= (props, ref) => {
const { children, __designMode, ...others } = props;
const otherProps: any = {};
if (__designMode === 'design') {
otherProps.onClick = (e: Event) => {
e.preventDefault();
};
}
return (
{children}
);
};
const RefLink = React.forwardRef(Link);
RefLink.defaultProps = {
href: 'https://fusion.design',
children: '这是一个超链接',
target: '_blank',
};
export default RefLink;
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/component/field/baseTableField.tsx
================================================
import React, { ReactNode } from "react";
import classnames from 'classnames';
import { Field } from "@alifd/next";
import { Rule } from "@alifd/next/types/field";
export interface IBaseTableFieldProps {
name: string;
value?: any;
onChange: (value: any) => void;
nextTablePrefix: string;
rules?: Rule;
}
class BaseTableField extends React.Component {
field: Field;
constructor(props: IBaseTableFieldProps & P) {
super(props);
this.field = new Field(this, {
onChange: (name, value) => {
this.dataChangeHandler(value);
},
});
}
componentWillMount() {
const { name } = this.props;
this.field.setValue(name, this.convertValueToSet(this.props.value));
}
componentWillReceiveProps(nextProps: IBaseTableFieldProps) {
const { name } = this.props;
this.field.setValue(name, this.convertValueToSet(nextProps.value));
}
validate() {
return new Promise((resolve) => {
const { name } = this.props;
this.field.validate([name], (errors) => {
resolve(errors);
});
});
}
convertValueToSet(value: any) {
return value;
}
dataChangeHandler(value: any) {
const { onChange } = this.props;
onChange && onChange(value);
}
renderField(): ReactNode {
return null;
}
render() {
const { nextTablePrefix, name } = this.props;
const field = this.field;
const errMsg = field.getError(name);
const fieldState = field.getState(name);
return (
{this.renderField()}
{errMsg ?
: null}
);
}
}
export default BaseTableField;
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/component/field/customField.tsx
================================================
import { InitResult, Rule } from "@alifd/next/types/field";
import { ReactNode } from "react";
import BaseTableField from "./baseTableField";
export interface ICustomFieldProps {
rowData: any;
renderField: (props: InitResult, value: any, rowData: any) => ReactNode;
}
export default class CustomField extends BaseTableField {
renderField() {
const field = this.field;
const { nextTablePrefix, value, onChange, rules, name, renderField, rowData, ...rest } = this.props;
const props = field.init(name, { rules }, rest);
delete props.value; // 外部默认为非受控模式
return renderField(props, value, rowData);
}
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/component/field/dateField.tsx
================================================
import React from "react";
import Moment, { MomentInput } from "moment";
import { DatePicker } from "@alifd/next";
import BaseTableField from "./baseTableField";
export default class DateField extends BaseTableField {
convertValueToSet(value: MomentInput) {
return value ? Moment(value) : value;
}
dataChangeHandler(value: any) {
const { onChange } = this.props;
onChange && onChange(value ? value.toDate().getTime() : value);
}
renderField() {
const field = this.field;
const { nextTablePrefix, value, onChange, rules, name, ...rest } = this.props;
return ();
}
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/component/field/dateRangeField.tsx
================================================
import React from "react";
import Moment, { MomentInput } from "moment";
import { DatePicker } from "@alifd/next";
import BaseTableField from "./baseTableField";
const { RangePicker } = DatePicker;
export default class DateRangeField extends BaseTableField {
convertValueToSet(value: { start?: MomentInput; end?: MomentInput }) {
const { start, end } = value;
return [
start ? Moment(start) : null,
end ? Moment(end) : null,
];
}
dataChangeHandler(value: any) {
const { onChange } = this.props;
if (onChange) {
const { 0: start, 1: end } = value;
onChange && onChange({
start: start ? start.toDate().getTime() : undefined,
end: end ? end.toDate().getTime() : undefined,
});
}
}
renderField() {
const field = this.field;
const { nextTablePrefix, value, onChange, rules, name, ...rest } = this.props;
return ();
}
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/component/field/inputField.tsx
================================================
import React from "react";
import { Input } from "@alifd/next";
import BaseTableField from "./baseTableField";
export default class InputField extends BaseTableField {
renderField() {
const field = this.field;
const { nextTablePrefix, value, onChange, rules, name, ...rest } = this.props;
return (
);
}
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/component/field/radioField.tsx
================================================
import React, { ReactNode } from "react";
import { Radio } from "@alifd/next";
import BaseTableField from "./baseTableField";
import { GroupProps } from "@alifd/next/types/radio";
const RadioGroup = Radio.Group;
interface IRadioFieldProps {
renderChildren?(): GroupProps['children'];
}
export default class RadioField extends BaseTableField {
renderField() {
const field = this.field;
const { nextTablePrefix, value, onChange, rules, name, renderChildren, ...rest } = this.props;
if (renderChildren) {
return (
{renderChildren()}
);
}
return null;
}
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/component/field/selectField.tsx
================================================
import React from "react";
import { Select } from "@alifd/next";
import BaseTableField from "./baseTableField";
import { SelectProps } from "@alifd/next/types/select";
interface ISelectFieldProps {
renderChildren?(): SelectProps['children'];
}
export default class SelectField extends BaseTableField {
renderField() {
const field = this.field;
const { nextTablePrefix, value, onChange, rules, name, renderChildren, ...rest } = this.props;
return ();
}
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/component/webCustomColumnDrawer.tsx
================================================
import React from "react";
import { Drawer, Button, Icon, Message, Checkbox, Switch } from '@alifd/next';
import cloneDeep from 'lodash/cloneDeep';
import isEqual from 'lodash/isEqual';
import { Table } from '@alifd/next';
function getSelectedRowKeys(columns: IWebCustomColumnDrawerProps['columns'] = []) {
const selectedRowKeys: string[] = [];
columns && columns.forEach((item) => {
const { hidden, dataKey } = item;
if (!hidden && dataKey) {
selectedRowKeys.push(dataKey);
}
});
return selectedRowKeys;
}
export interface IWebCustomColumnDrawerProps {
columns?: any[];
onOk?: (columns: IWebCustomColumnDrawerProps['columns']) => void;
onClose?: () => void;
locale?: {
[propKey: string]: string;
}
nextTablePrefix?: string;
visible: boolean;
}
interface IWebCustomColumnDrawerState {
defaultColumns: IWebCustomColumnDrawerProps['columns'];
currentColumns: IWebCustomColumnDrawerProps['columns'];
}
export default class WebCustomColumnDrawer extends React.Component {
static defaultProps = {
columns: [],
};
constructor(props: IWebCustomColumnDrawerProps) {
super(props);
const { columns } = this.props;
this.state = {
defaultColumns: cloneDeep(columns),
currentColumns: cloneDeep(columns),
};
}
componentWillReceiveProps(nextProps: IWebCustomColumnDrawerProps) {
const { defaultColumns } = this.state;
const { columns: nextColumns } = nextProps;
if (!isEqual(defaultColumns, nextColumns)) {
this.setState({
defaultColumns: cloneDeep(nextColumns),
currentColumns: cloneDeep(nextColumns),
});
}
}
isHidden(dataKey: string) {
const { currentColumns = [] } = this.state;
const column = currentColumns.find((item) => {
return item.dataKey === dataKey;
});
return column ? (!!column.hidden) : false;
}
isLocked(dataKey: string) {
const { currentColumns = [] } = this.state;
const column = currentColumns.find((item) => {
return item.dataKey === dataKey;
});
let lock = column && column.lock;
if (lock === "none") {
lock = undefined;
}
return !!lock;
}
isAllColumnsShown() {
const { currentColumns = [] } = this.state;
return !currentColumns.some((item) => {
return item.hidden;
});
}
handleCheck(checked: boolean, dataKey: string) {
const { currentColumns = [] } = this.state;
const column = currentColumns.find((item) => {
return item.dataKey === dataKey;
});
if (column) {
column.hidden = !checked;
column.lock = false;
this.forceUpdate();
}
}
handleLock(checked: boolean, dataKey: string) {
const { currentColumns = [] } = this.state;
const column = currentColumns.find((item) => {
return item.dataKey === dataKey;
});
if (column) {
column.lock = checked ? 'left' : undefined;
this.forceUpdate();
}
}
restoreDefault() {
const { defaultColumns } = this.state;
this.setState({
currentColumns: cloneDeep(defaultColumns),
});
}
handleOk() {
const { currentColumns = [] } = this.state;
const { onOk, locale = {} } = this.props;
let shownCount = 0;
let fixedCount = 0;
currentColumns.forEach((colums) => {
const { lock, hidden } = colums;
if (!hidden) {
shownCount++;
}
if (lock && lock != "none") {
fixedCount++;
}
});
if (currentColumns.length >= 2 && shownCount < 2) {
Message.error(locale.tipLeastColumns);
return;
}
onOk && onOk(currentColumns);
}
handleCheckAll(checked: boolean) {
const { currentColumns = [] } = this.state;
currentColumns.forEach((item) => {
return item.hidden = !checked;
});
this.forceUpdate();
}
renderColumnShown(value: any, record: any, hasCheckbox: boolean) {
const { nextTablePrefix } = this.props;
const { dataKey } = record;
return
{hasCheckbox ? {
this.handleCheck(checked, dataKey);
}} checked={!this.isHidden(dataKey)} /> : null}
{value}
;
}
renderColumnFixed(value: any, rowIndex: string, record: any) {
const { dataKey } = record;
return this.isHidden(dataKey) ? null : {
this.handleLock(checked, dataKey);
}} />;
}
render() {
const { nextTablePrefix, onClose, visible, locale = {} } = this.props;
const { currentColumns = [] } = this.state;
return (
{
return !item.isGroup
})}
hasBorder={false} primaryKey="dataKey"
rowSelection={{
selectedRowKeys: getSelectedRowKeys(currentColumns),
onSelectAll: (selected) => {
this.handleCheckAll(selected);
},
onSelect: (selected, records) => {
const { dataKey } = records;
this.handleCheck(selected, dataKey);
},
}}>
{
return this.renderColumnShown(value, record, false);
}} title={locale.showColumn} dataIndex="title"
width="60%" />
);
}
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/component/webLinkBar.tsx
================================================
import React from 'react';
import isFunction from "lodash/isFunction";
import type { IAction } from './webToolbar';
export interface IWebLinkBarProps {
nextTablePrefix?: string;
onActionClick?: (item: IAction, index: number) => void;
linkBar?: IAction[];
}
export default class WebLinkBar extends React.Component {
renderActionButton(item: IAction, index: number) {
const { nextTablePrefix, onActionClick } = this.props;
let content;
const itemProps = {
onClick: () => {
onActionClick && onActionClick(item, index);
},
};
if (item.render && isFunction(item.render)) {
content = (
{item.render(item.title)}
);
} else {
content = (
{item.title}
);
}
return (
{content}
{index === 0 ? null :
}
);
}
render() {
const { nextTablePrefix, linkBar = [] } = this.props;
return (
{linkBar.slice(0).reverse().map((link, index) => {
return link ? this.renderActionButton(link, index) : null;
})}
);
}
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/component/webNextTableActionCell.tsx
================================================
import React, { ReactNode } from "react";
import classnames from 'classnames';
import { Button, MenuButton } from '@alifd/next';
import actionTitleRender from "../utils/render/actionTitleRender";
import runColumnActionCallback from "../utils/runColumnActionCallback";
import filterActionColumn from "../utils/filterActionColumn";
import dispatchResizeEvent from "../utils/dispatchResizeEvent";
const { Item } = MenuButton;
export interface IActionColumnItem {
title: string;
callback?: (rowData: any, action: IActionColumnItem, index?: number) => void;
device?: string[];
mode?: string;
render?: (title: IActionColumnItem['title'], rowData: any) => ReactNode;
}
export interface IWebNextTableActionCellProps {
actionColumn?: IActionColumnItem[];
actionType?: string;
maxWebShownActionCount?: number;
nextTablePrefix?: string;
rowData?: any;
device?: string;
index?: number;
locale?: {
[prop: string]: string;
}
}
export default class WebNextTableActionCell extends React.Component {
refreshCellUI() {
this.forceUpdate(() => {
dispatchResizeEvent();
});
}
componentDidMount() {
setTimeout(() => {
dispatchResizeEvent()
}, 400)
}
render() {
const { actionColumn, actionType, maxWebShownActionCount = 3, nextTablePrefix, rowData, device, index, locale = {} } = this.props;
const currentActionColumn = filterActionColumn(actionColumn, rowData, device);
const showMoreAction = currentActionColumn.length > maxWebShownActionCount;
const actionColumnToRender = currentActionColumn.slice(0, (showMoreAction ? maxWebShownActionCount - 1 : undefined));
const remainActions = currentActionColumn.slice(maxWebShownActionCount - 1);
const isLink = actionType === 'link';
const menu = remainActions.map((action) => {
const render = actionTitleRender(action, rowData)
return render ? - {render}
: null;
}).filter(i => i !== null);
return (
{
actionColumnToRender.map((action) => {
const render = actionTitleRender(action, rowData)
return (
render ? : null
);
})
}
{showMoreAction && menu.length ?
{
const title = item.props.title;
const action = remainActions.find((item) => {
return item.title = title;
});
runColumnActionCallback({
index,
rowData,
action: action!,
}).finally(() => {
this.refreshCellUI();
});
}}
label={locale.more}
>{menu} : null}
);
}
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/component/webNextTableCell.tsx
================================================
import React from "react";
import isFunction from "lodash/isFunction";
import commonTableCellRender from "../utils/render/commonTableCellRender";
import { safeAccess, safeWrite } from "../utils/chainAccess";
import InputField from "./field/inputField";
import SelectField from "./field/selectField";
import RadioField from "./field/radioField";
import DateField from "./field/dateField";
import CustomField from "./field/customField";
import DateRangeField from "./field/dateRangeField";
import BaseTableField from "./field/baseTableField";
const fieldsMap = {
select: SelectField,
text: InputField,
radio: RadioField,
date: DateField,
dateRange: DateRangeField,
custom: CustomField,
};
function canEditCell(canEdit: boolean, rowData: IWebNextTableCellProps['rowData']) {
if (typeof canEdit === "undefined" || canEdit === null) {
return true;
}
if (isFunction(canEdit)) {
return canEdit(rowData);
}
return !!canEdit;
}
export interface IWebNextTableCellProps {
rowData: any;
column: {
editType?: keyof typeof fieldsMap;
dataKey: string;
[prop: string]: any;
};
isRenderEditMode?: boolean;
rowIndex: number;
nextTablePrefix?: string;
onCellDataChange?(options: {
dataKey: IWebNextTableCellProps['column']['dataKey'];
value: any,
rowData: IWebNextTableCellProps['rowData'];
rowIndex: IWebNextTableCellProps['rowIndex'];
}): void;
}
interface IWebNextTableCellState {
editable: boolean;
currentValue: any;
}
export default class WebNextTableCell extends React.Component {
fieldComponentRef: React.RefObject;
constructor(props: IWebNextTableCellProps) {
super(props);
this.state = {
editable: false,
currentValue: this.getRowValue(),
};
this.fieldComponentRef = React.createRef();
}
setEditable(v: boolean) {
const { rowData } = this.props;
rowData.__mode__ = v ? "EDIT" : "VIEW";
this.setState({ editable: !!v });
}
getRowValue() {
const { rowData, column } = this.props;
const { dataKey } = column;
return safeAccess(rowData, dataKey);
}
saveCell() {
const { currentValue } = this.state;
const { rowData, column } = this.props;
const { dataKey } = column;
safeWrite(rowData, dataKey, currentValue);
this.setEditable(false);
}
resetCell() {
this.setState({
currentValue: this.getRowValue(),
});
this.setEditable(false);
}
validateCell() {
const current = this.fieldComponentRef.current;
const validate = current && current.validate;
return validate && validate.call(current);
}
_fillFields(rowData: IWebNextTableCellProps['rowData'], dataKey: IWebNextTableCellProps['column']['dataKey']) {
rowData.__fields__ = rowData.__fields__ || {};
rowData.__fields__[dataKey] = this;
}
renderCellEditInner() {
const { currentValue } = this.state;
const { nextTablePrefix, column, rowData, rowIndex, onCellDataChange } = this.props;
const { editType, dataKey } = column;
const FieldComponent = fieldsMap[editType!];
let { editProps } = column;
if (isFunction(editProps)) {
editProps = editProps(rowData);
}
return ( {
// 兼容乐高 onChange 的返回格式 { value: value, ...rest }
let realValue = value;
if (value && (typeof value === 'object') && Object.hasOwnProperty.call(value, 'value')) {
realValue = value.value;
}
this.setState({ currentValue: realValue });
onCellDataChange && onCellDataChange({
dataKey,
value: realValue,
rowData,
rowIndex,
});
}}
rowData={rowData}
{...editProps}
/>);
}
render() {
const { editable } = this.state;
const { column, rowData, isRenderEditMode, rowIndex } = this.props;
const { editType, canEdit, dataKey } = column;
this._fillFields(rowData, dataKey);
if (isRenderEditMode && editable && editType && editType in fieldsMap && canEditCell(canEdit, rowData)) {
return ( {
e.stopPropagation();
}}>
{this.renderCellEditInner()}
);
}
return commonTableCellRender(safeAccess(rowData, dataKey), rowIndex, rowData, column);
}
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/component/webPagination.tsx
================================================
import React from "react";
import classnames from 'classnames';
import isString from "lodash/isString";
import { Pagination } from '@alifd/next';
import { paginationProps, fetchKey } from "../utils/tableProps";
import { PaginationProps } from "@alifd/next/types/pagination";
export interface IWebPaginationProps extends Pick {
nextTablePrefix?: string;
currentPage?: PaginationProps['current'];
totalCount?: PaginationProps['total'];
locale?: {
[prop: string]: string;
}
hideOnlyOnePage?: boolean;
noPadding?: boolean;
paginationPosition?: string;
}
export default class WebPagination extends React.Component {
render() {
const { nextTablePrefix, currentPage, pageSize, totalCount, locale, onChange, onPageSizeChange, hideOnlyOnePage, noPadding } = this.props;
const myProps = fetchKey(this.props, paginationProps as Array);
const { pageSizeList, paginationPosition = 'right', ...rest } = myProps;
if (hideOnlyOnePage && pageSize !== undefined && totalCount !== undefined && pageSize > totalCount) {
return null
}
return (
{
return (
{locale && locale.totalCount ? locale.totalCount : '总计'}:{' '}{total}{' '});
}}
{...
{
...rest,
pageSizeList: (pageSizeList && isString(pageSizeList)) ? (() => {
const pageSizeArray = pageSizeList.split(',');
if (pageSizeArray.length > 1) {
return pageSizeArray.map(i => parseInt(i, 10));
}
})() : pageSizeList,
current: currentPage,
pageSize,
total: totalCount,
onChange,
onPageSizeChange,
}
}
/>
);
}
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/component/webRowOrder.tsx
================================================
import React, { ReactNode } from 'react';
import { Select, Icon } from '@alifd/next';
import { SelectProps } from '@alifd/next/types/select';
const Option = Select.Option;
export interface IWebRowOrderProps {
items: {
value: string;
text: ReactNode;
}[];
nextTablePrefix: any;
defaultValue: any;
onChange: SelectProps['onChange'];
}
export default class WebRowOrder extends React.Component {
render() {
const { items, nextTablePrefix, defaultValue, onChange } = this.props;
return (
);
}
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/component/webToolbar.tsx
================================================
import React, { MouseEventHandler, ReactNode } from "react";
import classnames from "classnames";
import { Button, Search, Pagination, Icon } from '@alifd/next';
import WebRowOrder, { IWebRowOrderProps } from "./webRowOrder";
import WebLinkBar from "./webLinkBar";
import { SearchProps } from "@alifd/next/types/search";
import { PaginationProps } from "@alifd/next/types/pagination";
import { ButtonProps } from "@alifd/next/types/button";
export interface IAction {
render?: (title: IAction['title']) => ReactNode;
isDisabled?: () => boolean;
title?: ReactNode;
type: ButtonProps['type'];
disabled: boolean;
callback?: (action: IAction) => void;
}
export interface IWebToolbarProps {
nextTablePrefix?: string;
onSearch?: SearchProps['onSearch'];
onActionClick?: (action: IAction, index: number) => void;
locale?: { [prop: string]: string };
showActionBar?: boolean;
actionBar?: IAction[];
showLinkBar?: boolean;
linkBar?: any;
showSearch?: boolean;
searchBarPlaceholder?: string;
showCustomColumn?: boolean;
onClickCustomColumn?: MouseEventHandler;
rowOrder?: IWebRowOrderProps;
customBarItem?: {
render?: () => ReactNode;
rightRender?: () => ReactNode;
bottomRender?: () => ReactNode;
}
showMiniPager?: boolean;
paginationProps?: Pick & {
currentPage?: PaginationProps['current'];
totalCount?: PaginationProps['total'];
};
noPadding?: boolean;
}
export default class WebToolbar extends React.Component {
render() {
const {
nextTablePrefix, onSearch, onActionClick, locale = {},
showActionBar, actionBar, showLinkBar, linkBar, showSearch, searchBarPlaceholder, showCustomColumn,
onClickCustomColumn, rowOrder, customBarItem, showMiniPager, paginationProps, noPadding
} = this.props;
const { currentPage, pageSize, totalCount, onChange, onPageSizeChange } = paginationProps || {};
const renderCustomBarItem = !!(customBarItem && customBarItem.render);
const renderCustomBarItemRight = !!(customBarItem && customBarItem.rightRender);
const renderCustomBarItemBottom = !!(customBarItem && customBarItem.bottomRender);
const renderActionBar = !!(showActionBar && actionBar && actionBar.length);
const renderLeft = renderActionBar || renderCustomBarItem;
const renderLinkBar = !!(showLinkBar && linkBar && linkBar.length);
const renderRight = renderLinkBar || rowOrder || showCustomColumn || showMiniPager || showSearch || renderCustomBarItemRight;
const renderToolbar = renderLeft || renderRight;
if (!renderToolbar) {
return null;
}
return (
{renderLeft ?
{renderActionBar ? actionBar.map((action, index) => {
const { isDisabled, title, type, disabled, callback, ...rest } = action
const buttonType = type ? type : index === 0 ? 'secondary' : 'normal';
const disable = disabled !== undefined ? disabled : isDisabled ? !!(isDisabled()) : false;
return (
);
}) : null}
{renderCustomBarItem ?
{customBarItem.render!()}
: null}
: null}
{renderRight ?
{renderLinkBar ?
: null}
{rowOrder ?
: null}
{showCustomColumn ?
{locale.customColumn}
: null}
{showMiniPager ?
: null}
{
showSearch
?
: null
}
{
renderCustomBarItemRight ?
{customBarItem.rightRender!()}
: null
}
: null
}
{renderCustomBarItemBottom ?
{customBarItem.bottomRender!()}
: null}
);
}
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/index.scss
================================================
/* write style here */
@import "scss/variables";
$table-css-prefix: '#{$deep-css-prefix}table-' !default;
$red: #fb575f;
$blue: #33a4ff;
$orange: #ff8c33;
$green: #82cb78;
$grey: #c2c2c2;
$black: #2c2f33;
$yellow: #F9BD0F;
.#{$table-css-prefix}full-wrap,
.#{$table-css-prefix}detail-view-drawer {
.#{$table-css-prefix}detail-list {
background-color: #ffffff;
width: calc(100% - 18px);
.#{$table-css-prefix}detail-field-wrap {
line-height: 24px;
font-size: 14px;
display: flex;
.#{$table-css-prefix}detail-label {
color: $color-text1-3;
white-space: nowrap;
}
.#{$table-css-prefix}detail-value {
color: $color-text1-4;
.#{$css-prefix}btn {
font-size: 14px;
}
> span {
word-break: break-word;
font-size: 14px;
}
}
}
.#{$table-css-prefix}detail-field-highlight {
font-size: 16px;
padding-left: 0;
font-weight: bold;
padding-bottom: 8px;
}
}
.#{$css-prefix}table-sort {
outline: none;
line-height: 16px;
.#{$css-prefix}icon {
&.#{$css-prefix}icon-ascending, &.#{$css-prefix}icon-descending {
left: 0;
}
}
}
.#{$css-prefix}table-filter {
width: 16px;
}
.#{$css-prefix}table th {
background-color: $color-fill1-1;
.#{$css-prefix}table-cell-wrapper {
ul.#{$css-prefix}menu {
text-align: left;
}
}
}
.#{$css-prefix}table-cell{
.#{$css-prefix}btn-text.deep-table-link-button {
color:$color-link-2
}
.deep-table-badge {
display: inline-block;
padding: 2px 5px;
border-radius: 2px;
&.deep-table-badge-background-red {
color: white;
background-color: $red;
}
&.deep-table-badge-color-red {
color: $red
}
&.deep-table-badge-background-yellow {
color: white;
background-color: $yellow;
}
&.deep-table-badge-color-yellow {
color: $yellow
}
&.deep-table-badge-background-black {
color: white;
background-color: $black;
}
&.deep-table-badge-color-black {
color: $black
}
&.deep-table-badge-background-grey {
color: white;
background-color: $grey;
}
&.deep-table-badge-color-grey {
color: $grey
}
&.deep-table-badge-background-green {
color: white;
background-color: $green;
}
&.deep-table-badge-color-green {
color: $green
}
&.deep-table-badge-background-blue {
color: white;
background-color: $blue;
}
&.deep-table-badge-color-blue {
color: $blue
}
&.deep-table-badge-background-orange {
color: white;
background-color: $orange;
}
&.deep-table-badge-color-orange {
color: $orange
}
}
}
.#{$css-prefix}table-cell.#{$css-prefix}table-expanded {
.#{$css-prefix}icon-add:before, .#{$css-prefix}icon-minus:before {
color: $color-fill1-6;
font-size: 16px;
width: 16px;
}
.#{$css-prefix}icon-add:before {
content: "\e724";
}
.#{$css-prefix}icon-minus:before {
content: "\e725";
}
}
.#{$table-css-prefix}input {
width: 100%;
}
.#{$table-css-prefix}field-msg {
line-height: 24px;
text-align: left;
color: $color-error-3;
}
.#{$table-css-prefix}employee {
width: 100%;
.#{$css-prefix}select-trigger, .#{$css-prefix}select .#{$css-prefix}select-inner {
min-width: 50px;
}
}
}
.#{$table-css-prefix}full-wrap {
.#{$table-css-prefix}web-toolbar {
overflow: hidden;
padding: 16px 0;
&.#{$table-css-prefix}no-padding {
padding-top: 0;
}
.#{$table-css-prefix}left-wrap {
float: left;
}
.#{$table-css-prefix}right-wrap {
float: right;
}
.#{$table-css-prefix}button {
margin-right: 8px;
}
.#{$table-css-prefix}search {
width: 280px;
margin-left: 20px;
vertical-align: top;
.#{$css-prefix}search-icon {
outline: none;
}
}
.#{$table-css-prefix}custom-column, .#{$table-css-prefix}link-a, .#{$table-css-prefix}link-div {
color: $color-link-1;
font-size: 12px;
cursor: pointer;
i {
color: $color-text1-2;
margin-right: 3px;
}
.#{$table-css-prefix}text {
padding-left: 3px;
}
}
.#{$table-css-prefix}link-a {
text-decoration: none;
}
.#{$table-css-prefix}custom-column {
margin-left: 24px;
line-height: 32px;
display: inline-block;
vertical-align: top;
}
.#{$table-css-prefix}link-wrap {
margin-left: 24px;
display: inline-block;
white-space: nowrap;
line-height: 32px;
vertical-align: top;
.#{$table-css-prefix}link-item {
float: right;
}
.#{$table-css-prefix}link-sp {
width: 1px;
height: 12px;
margin: 10px 12px;
display: inline-block;
vertical-align: top;
background-color: $color-line1-2;
}
}
.#{$table-css-prefix}row-order {
display: inline-block;
vertical-align: top;
margin-left: 24px;
.#{$table-css-prefix}row-order-v {
color: $color-link-1;
i {
color: $color-text1-2;
margin-right: 3px;
}
}
.#{$css-prefix}input-control {
display: none;
}
.#{$css-prefix}input.#{$css-prefix}medium .#{$css-prefix}input-text-field {
padding-left: 3px;
padding-right: 0;
color: $color-link-1;
}
.#{$css-prefix}select-inner {
min-width: 50px;
}
.#{$css-prefix}select-trigger {
min-width: 50px;
}
.#{$css-prefix}input.#{$css-prefix}medium .#{$css-prefix}icon:before {
width: 16px;
font-size: 16px;
}
}
.#{$table-css-prefix}custom {
display: inline-block;
height: 32px;
line-height: 32px;
vertical-align: top;
margin: 0 5px;
}
.#{$table-css-prefix}custom-right {
display: inline-block;
height: 32px;
line-height: 32px;
vertical-align: top;
margin: 0 5px 0 10px;
}
.#{$table-css-prefix}pagination {
display: inline-block;
vertical-align: top;
margin: 2px 0 0 20px;
}
}
.#{$table-css-prefix}mobile-body {
.#{$css-prefix}radio-group {
width: 100%;
}
}
.#{$table-css-prefix}mobile-toolbar {
overflow: hidden;
border-bottom: 1px solid $color-line1-2;
.#{$table-css-prefix}right-wrap {
line-height: 44px;
display: flex;
&-selector {
width: 54px;
text-align: center;
}
&-content {
width: 100%;
text-align: right;
}
}
.#{$table-css-prefix}search-wrap {
padding: 8px 0;
.#{$table-css-prefix}search-inner {
overflow: hidden;
padding-left: 16px;
}
.#{$table-css-prefix}search-cancel-wrap {
float: right;
line-height: 28px;
padding: 0 16px;
}
}
.#{$table-css-prefix}search-cancel {
font-size: 14px;
color: $color-fill1-7;
}
.#{$table-css-prefix}i-wrap, .#{$table-css-prefix}row-order {
margin-right: 16px;
display: inline-block;
vertical-align: top;
color: $color-link-1;
font-size: 0;
position: relative;
&:active {
&:after {
position: absolute;
top: 6px;
left: -6px;
display: inline-block;
content: '';
width: 32px;
height: 32px;
background: $color-fill1-1;
z-index: -1;
border-radius: 16px;
}
}
}
.#{$table-css-prefix}search {
position: relative;
overflow: hidden;
.#{$css-prefix}icon-search {
vertical-align: top;
}
.input {
line-height: 28px;
width: 100%;
padding: 0;
border: none;
font-size: 12px;
outline: none;
background-color: transparent;
}
.i-wrap {
position: absolute;
right: 5px;
top: 4px;
padding: 0 10px;
color: $color-fill1-6;
}
.input-wrap {
border-radius: 20px;
padding: 0 0 0 18px;
background: #F1F3F5;
}
}
}
.#{$table-css-prefix}mobile-table {
.#{$css-prefix}table.#{$css-prefix}table-small td .#{$css-prefix}table-cell-wrapper {
padding: 8px;
}
.#{$css-prefix}table.#{$css-prefix}table-small .#{$css-prefix}table-prerow .#{$css-prefix}table-cell-wrapper {
padding-right: 8px;
}
.#{$css-prefix}table.#{$css-prefix}table-small {
td.first,
th.#{$css-prefix}table-selection {
.#{$css-prefix}table-cell-wrapper {
padding-left: 16px;
}
}
}
.#{$css-prefix}table.#{$css-prefix}table-small th.#{$css-prefix}table-selection .#{$css-prefix}table-cell-wrapper {
padding-left: 16px;
}
.#{$css-prefix}table-expanded-row {
background-color: $color-fill1-1;
}
.#{$css-prefix}table.#{$css-prefix}table-small td.#{$table-css-prefix}column-action .#{$css-prefix}table-cell-wrapper {
padding: 0;
}
.#{$table-css-prefix}column-action-i {
padding: 8px;
color: $color-fill1-6;
}
.#{$css-prefix}btn, .#{$css-prefix}table-expanded-ctrl {
cursor: default;
}
.#{$css-prefix}table-row.hovered {
background-color: #ffffff;
}
.#{$table-css-prefix}expand-wrap {
padding-left: 8px;
}
}
.#{$table-css-prefix}card-table {
.#{$table-css-prefix}item-wrap {
width: 100%;
padding: 16px;
border-bottom: 1px solid $color-line1-2;
position: relative;
font-size: 14px;
display: flex;
align-items: center;
justify-items: center;
.#{$table-css-prefix}item-wrap-selector {
margin-right: 12px;
}
.#{$table-css-prefix}item-wrap-content {
width: 100%;
display: flex;
justify-items: center;
align-items: center;
&.is-right {
flex-direction: row-reverse;
}
.#{$table-css-prefix}item-wrap-content-column {
width: 100%;
}
.#{$table-css-prefix}row-operate {
position: absolute;
right: 16px;
top: 10px;
line-height: 30px;
color: $color-fill1-6;
}
.#{$table-css-prefix}row-button-wrap {
margin-top: 16px;
text-align: right;
}
}
}
.#{$table-css-prefix}expand-wrap {
text-align: center;
margin-top: 16px;
}
.#{$table-css-prefix}more-wrap {
text-align: left;
}
.#{$table-css-prefix}expand-wrap, .#{$table-css-prefix}more-wrap {
line-height: 22px;
color: $color-fill1-6;
font-size: 14px;
.#{$table-css-prefix}text {
padding-right: 4px;
}
.#{$css-prefix}icon {
line-height: 20px;
}
}
.#{$table-css-prefix}expand-content-wrap {
background-color: $color-fill1-1;
border-radius: 4px;
margin-top: 16px;
}
.#{$css-prefix}btn {
cursor: default;
}
}
.#{$table-css-prefix}date-picker {
&.#{$css-prefix}date-picker, .#{$css-prefix}month-picker, .#{$css-prefix}year-picker {
width: 100%;
}
}
.#{$table-css-prefix}web-pagination-wrap {
.#{$table-css-prefix}web-pagination-left {
float: left;
}
.#{$table-css-prefix}web-pagination-right {
float: right;
.#{$css-prefix}select {
width: unset !important;
}
}
}
.#{$table-css-prefix}web-table {
.#{$css-prefix}table-expanded-row {
background-color: $color-fill1-1;
}
.#{$table-css-prefix}action-cell {
.#{$table-css-prefix}action-link {
&.#{$css-prefix}btn-text, &.#{$css-prefix}menu-btn.#{$css-prefix}btn-text.#{$css-prefix}btn-primary .#{$css-prefix}menu-btn-arrow {
color: $color-link-1;
}
}
.#{$table-css-prefix}action-button {
margin-right: 8px;
&:last-child {
margin-right: 0;
}
&.#{$table-css-prefix}action-more {
.#{$css-prefix}menu-btn-arrow {
vertical-align: middle;
}
}
}
.#{$table-css-prefix}action-link {
padding: 0 12px;
position: relative;
vertical-align: baseline;
&:first-child {
padding-left: 0;
&:before {
width: 0;
}
}
&:last-child {
padding-right: 0;
}
&.#{$table-css-prefix}action-more{
&:before {
top: 4px
}
}
&:before {
position: absolute;
content: '';
width: 1px;
height: 10px;
background: $color-line1-4;
vertical-align: middle;
top: 5px;
left: 1px;
}
}
.#{$table-css-prefix}action-more {
.#{$css-prefix}menu-btn-arrow {
vertical-align: top;
}
}
}
.#{$css-prefix}table-sort {
cursor: pointer;
}
}
.#{$table-css-prefix}web-pagination-wrap {
padding: 16px 10px;
&.#{$table-css-prefix}no-padding {
padding-bottom: 0;
}
}
}
.#{$table-css-prefix}mobile-drawer {
.#{$css-prefix}drawer-body {
padding: 0;
}
&.#{$css-prefix}drawer {
background-color: $color-fill1-2;
}
&.#{$css-prefix}drawer-right {
max-width: none;
width: 100%;
height: 100%;
}
.#{$css-prefix}switch, .#{$css-prefix}checkbox-wrapper input[type="checkbox"] {
cursor: default;
}
}
.#{$table-css-prefix}detail-view-drawer {
.#{$css-prefix}drawer-body {
position: absolute;
left: 0;
width: 100%;
top: 0;
height: 100%;
}
.#{$table-css-prefix}title {
line-height: 48px;
text-align: center;
background: #fff;
font-size: 16px;
position: absolute;
left: 0;
width: 100%;
top: 0;
border-bottom: 1px solid $color-line1-2;
color: $color-text1-4;
.#{$table-css-prefix}close {
position: absolute;
right: 16px;
top: 12px;
line-height: 20px;
}
}
.#{$table-css-prefix}detail-list-wrap {
background-color: #ffffff;
padding: 16px;
}
.#{$table-css-prefix}expand-content-wrap {
margin-top: 16px;
background-color: #ffffff;
}
.#{$table-css-prefix}center {
position: absolute;
left: 0;
width: 100%;
top: 49px;
bottom: 0;
overflow: auto;
}
.#{$table-css-prefix}center-action {
bottom: 51px;
}
.#{$table-css-prefix}bottom {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
z-index: 1002;
background-color: #ffffff;
.#{$table-css-prefix}action-wrap {
display: flex;
flex-direction: row;
border-top: 1px solid $color-fill1-2;
}
.#{$table-css-prefix}action-item {
flex: 1;
padding: 12px 0;
}
.#{$table-css-prefix}action-inner {
line-height: 24px;
color: $color-fill1-7;
border-left: 1px solid $color-line1-2;
text-align: center;
padding: 0 5px;
font-size: 16px;
}
.#{$table-css-prefix}action-disable {
color: $color-fill1-5;
}
.#{$table-css-prefix}action-item.first .#{$table-css-prefix}action-inner {
border-left: none;
}
}
}
.#{$table-css-prefix}operation-drawer {
.#{$table-css-prefix}item {
line-height: 47px;
font-size: 17px;
text-align: center;
background-color: #fff;
border-bottom: 1px solid $color-line1-2;
}
.#{$table-css-prefix}item-disable {
color: $color-fill1-5;
}
.#{$table-css-prefix}close {
line-height: 47px;
font-size: 17px;
text-align: center;
background-color: #fff;
margin-top: 10px;
}
.#{$table-css-prefix}action-list {
max-height: 384px;
overflow-x: hidden;
overflow-y: auto;
}
}
.#{$table-css-prefix}web-custom-column-drawer {
.#{$css-prefix}drawer-body {
position: absolute;
left: 0;
width: 100%;
top: 0;
height: 100%;
padding: 0;
}
.#{$table-css-prefix}title {
line-height: 48px;
text-align: left;
background: #fff;
font-size: 16px;
position: absolute;
left: 0;
width: 100%;
top: 0;
color: $color-text1-4;
border-bottom: 1px solid $color-line1-2;
.#{$table-css-prefix}title-txt {
padding: 0 16px;
font-weight: bold;
}
.#{$table-css-prefix}close {
line-height: 20px;
position: absolute;
right: 16px;
top: 12px;
cursor: pointer;
}
}
.#{$table-css-prefix}center {
position: absolute;
left: 0;
width: 100%;
top: 49px;
bottom: 53px;
overflow: auto;
}
.#{$table-css-prefix}cell-wrap {
line-height: 32px;
}
.#{$table-css-prefix}cell, .#{$table-css-prefix}select-all-content {
font-size: 12px;
color: $color-text1-4;
vertical-align: top;
}
.#{$css-prefix}table {
td, th {
.#{$css-prefix}table-cell-wrapper {
padding-left: 0;
padding-right: 0;
}
&.#{$css-prefix}table-selection {
.#{$css-prefix}table-cell-wrapper {
padding: 12px 16px;
}
}
}
}
.#{$table-css-prefix}cell-checkbox, .#{$table-css-prefix}select-all-checkbox {
vertical-align: top;
position: relative;
top: -2px;
}
.#{$table-css-prefix}bottom {
position: absolute;
bottom: 0;
width: 100%;
border-top: 1px solid $color-line1-2;
padding: 10px 16px;
text-align: right;
left: 0;
background: #fff;
border-radius: 0 0 4px 4px;
}
.#{$table-css-prefix}select-all {
float: left;
margin-left: 20px;
}
.#{$table-css-prefix}button {
margin-right: 6px;
}
}
.#{$table-css-prefix}mobile-custom-column-drawer {
.#{$css-prefix}drawer-body {
position: absolute;
left: 0;
width: 100%;
top: 0;
height: 100%;
}
.#{$table-css-prefix}title {
line-height: 48px;
text-align: center;
background: #fff;
font-size: 16px;
position: absolute;
left: 0;
width: 100%;
top: 0;
color: $color-text1-4;
.#{$table-css-prefix}close {
line-height: 20px;
position: absolute;
right: 16px;
top: 12px;
}
}
.#{$table-css-prefix}cell-wrap {
line-height: 32px;
}
.#{$table-css-prefix}cell, .#{$table-css-prefix}select-all-content {
margin-left: 12px;
font-size: 16px;
color: $color-text1-4;
vertical-align: top;
}
.#{$table-css-prefix}cell-checkbox, .#{$table-css-prefix}select-all-checkbox {
vertical-align: top;
position: relative;
top: -2px;
}
.#{$table-css-prefix}messge {
line-height: 30px;
}
.#{$table-css-prefix}center {
position: absolute;
left: 0;
width: 100%;
top: 49px;
bottom: 48px;
overflow: auto;
}
.#{$table-css-prefix}bottom {
position: absolute;
bottom: 0;
line-height: 48px;
background: #ffffff;
left: 0;
width: 100%;
}
.#{$table-css-prefix}select-all {
float: left;
margin-left: 20px;
}
.#{$table-css-prefix}button {
float: right;
margin-right: 16px;
}
.#{$css-prefix}checkbox-wrapper .#{$css-prefix}checkbox-inner {
border-radius: 50%;
}
}
.#{$table-css-prefix}full-wrap {
.#{$css-prefix}table-header {
overflow: hidden;
&::-webkit-scrollbar {
display: none;
}
}
}
.#{$table-css-prefix}column-title {
.#{$table-css-prefix}column-tooltip {
color: $color-notice-3;
line-height: 14px;
margin-left: 4px;
}
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/index.tsx
================================================
import classnames from 'classnames';
import React from 'react';
import { Table, Loading, ConfigProvider } from '@alifd/next'
import WebTable, { IWebTableProps } from './table/webTable';
import { fetchKey, tableProps } from "./utils/tableProps";
import buildNextTableMethod from "./utils/buildNextTableMethod";
import delegateFunctions from "./utils/delegateFunctions";
import getColumnsFromChildren from './utils/getColumnsFromChildern'
import zhCN from './locale/zh-cn'
import { LoadingProps } from '@alifd/next/types/loading';
import { IEditableMethods } from './mixin/editableMethods';
import { ICommonMethods } from './mixin/commonMethods';
import './index.scss';
const { GroupHeader, GroupFooter, Column, ColumnGroup } = Table
export interface ITableProps extends IWebTableProps {}
interface NextTable extends React.Component, Omit, Pick {}
class NextTable extends React.Component {
static Column = Column
static ColumnGroup = ColumnGroup
static GroupHeader = GroupHeader
static GroupFooter = GroupFooter
static defaultProps = {
columns: [],
clsPrefix: 'deep-',
locale: zhCN,
tablePrefix: 'table-',
primaryKey: 'id',
maxWebShownActionCount: 3,
expandedIndexSimulate: false,
loadingComponent: (props: LoadingProps) => {
return } {...props} />;
},
};
tableRef: React.RefObject;
constructor(props: ITableProps) {
super(props);
this.tableRef = React.createRef();
buildNextTableMethod(this);
}
renderTable() {
const { clsPrefix, tablePrefix } = this.props;
const myProps = fetchKey(this.props, tableProps);
const { children } = myProps;
if (children) {
myProps.columns = getColumnsFromChildren(children)
}
myProps.nextTablePrefix = `${clsPrefix}${tablePrefix}`;
myProps.actionColumn = delegateFunctions(myProps.actionColumn, 'callback', this, 2);
myProps.actionBar = delegateFunctions(myProps.actionBar, 'callback', this);
myProps.linkBar = delegateFunctions(myProps.linkBar, 'callback', this);
return ;
}
render() {
const { clsPrefix, tablePrefix, className } = this.props;
const nextTablePrefix = `${clsPrefix}${tablePrefix}`;
return (
{this.renderTable()}
);
}
}
export {
NextTable,
};
export default ConfigProvider.config(NextTable);
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/interface/index.ts
================================================
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/locale/en-us.ts
================================================
export default {
tipLeastNeededColumns: '2 shown columns is needed at least',
tipLeastColumns: '2 shown columns at least',
customColumn: 'Custom Columns',
showColumn: 'Show Column',
stickColumn: 'Stick Column',
showAll: 'Show All',
noData: 'No data',
restoreDefault: 'Reset',
notice: 'Notice',
ok: 'OK',
detail: 'Detail',
cancel: 'Cancel',
submit: 'Submit',
totalCount: 'Total',
collapse: 'Collapse',
expand: 'Expand',
more: 'More',
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/locale/zh-cn.ts
================================================
export default {
tipLeastNeededColumns: '最少需要展示2列',
tipLeastColumns: '最少展示2列',
customColumn: '自定义列',
showColumn: '展示此列',
stickColumn: '固定此列',
showAll: '全部展示',
noData: '没有数据',
restoreDefault: '恢复默认',
notice: '提示',
ok: '确定',
detail: '详情',
cancel: '取消',
submit: '提交',
totalCount: '总计',
collapse: '收起',
expand: '展开',
more: '更多',
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/mixin/columnMethods.tsx
================================================
import React, { ReactNode } from "react";
import assign from "lodash/assign";
import deepcopy from 'lodash/cloneDeep';
import WebCustomColumnDrawer from "../component/webCustomColumnDrawer";
import filterColumn from "../utils/filterColumn";
import type WebTable from "../table/webTable";
import { IWebTableProps } from "../table/webTable";
export interface IColumnMethods {
init(this: WebTable): void;
showCustomColumnDrawer(this: WebTable): void;
hideCustomColumnDrawer(this: WebTable): void;
setOriginalColumns(this: WebTable, columns: IWebTableProps['columns']): void;
changeCurrentColumns(this: WebTable, columns: IWebTableProps['columns']): void;
renderCustomColumnDrawer(this: WebTable): ReactNode;
}
const methods: IColumnMethods = {
init() {
const { columns = [] } = this.props;
const mergeState = {
isCustomColumnDrawerShown: false,
originalColumns: deepcopy(columns),
currentColumns: filterColumn(columns),
};
this.state = this.state || {};
assign(this.state, mergeState);
},
showCustomColumnDrawer() {
this.setState({
isCustomColumnDrawerShown: true,
});
},
hideCustomColumnDrawer() {
this.setState({
isCustomColumnDrawerShown: false,
});
},
setOriginalColumns(columns) {
this.setState({
originalColumns: deepcopy(columns),
});
},
changeCurrentColumns(columns) {
this.setState({
currentColumns: filterColumn(columns),
});
},
renderCustomColumnDrawer() {
const { isCustomColumnDrawerShown, originalColumns } = this.state;
const { nextTablePrefix, locale, onColumnsChange = () => { } } = this.props;
return (
{
this.changeCurrentColumns(columns);
onColumnsChange(columns)
this.hideCustomColumnDrawer();
}}
/>
);
},
};
export default methods;
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/mixin/commonMethods.ts
================================================
import assign from "lodash/assign";
import deepcopy from "lodash/cloneDeep";
import { isValidElement, ReactNode } from "react";
import WebTable from "../table/webTable";
import convertData from "../utils/convertData";
import getDataSource from "../utils/getDataSource";
export interface ICommonMethods {
init(this: WebTable): void;
loadData(this: WebTable, from: string): void;
getDataSource(this: WebTable): any;
getDataItem(this: WebTable, value: any): any;
onSort(this: WebTable, dataIndex: string, order: string): void;
onSearch(this: WebTable, searchKey: string): void;
renderEmptyContent(this: WebTable): ReactNode | null;
onPageSizeChange(this: WebTable, pageSize: number): void;
onPageNumChange(this: WebTable, current: number): void;
getPaginationProps(this: WebTable): any;
}
const methods: ICommonMethods = {
init() {
const { pagination = {} } = this.props;
const { pageSize } = pagination;
const result = convertData(getDataSource(this.props));
const mergeState = {
searchKey: '',
orderColumn: '',
orderType: '',
dataSource: result.dataSource || [],
totalCount: result.totalCount || 0,
pageSize,
currentPage: result.currentPage || 1,
};
this.state = this.state || {};
assign(this.state, mergeState);
},
loadData(this, from) {
const { onFetchData, onLoadData } = this.props;
const { currentPage, pageSize, searchKey, orderColumn, orderType } = this.state;
if (onLoadData) {
onLoadData(currentPage, pageSize, searchKey, orderColumn, orderType, from);
} else {
onFetchData && onFetchData({ currentPage, pageSize, searchKey, orderColumn, orderType, from });
}
},
getDataSource(this) {
const { dataSource } = this.state;
const list = deepcopy(dataSource);
list.forEach((item: any) => {
delete item.__mode__;
delete item.__fields__;
delete item.__expand__;
});
return list;
},
getDataItem(value) {
const { primaryKey } = this.props;
const { dataSource } = this.state;
return dataSource.find((item: any) => {
return item[primaryKey!] === value;
});
},
onSort(dataIndex, order) {
this.setState({
orderColumn: dataIndex,
orderType: order,
}, () => {
this.loadData('order');
});
},
onSearch(searchKey) {
this.setState({ searchKey }, () => {
this.loadData('search');
});
},
renderEmptyContent() {
const { setEmptyContent, emptyContent } = this.props;
if (!setEmptyContent) {
return null;
}
return typeof emptyContent === 'function' ? emptyContent() : isValidElement(emptyContent) ? emptyContent : null;
},
onPageSizeChange(pageSize) {
this.setState({ pageSize }, () => {
this.loadData('pagination');
});
},
onPageNumChange(current) {
this.setState({
currentPage: current,
}, () => {
this.loadData('pagination');
});
},
getPaginationProps() {
const { nextTablePrefix, pagination, locale, noPadding } = this.props;
const { currentPage, pageSize, totalCount } = this.state;
return {
nextTablePrefix, currentPage, totalCount,
...pagination,
noPadding,
pageSize,
locale,
onChange: this.onPageNumChange.bind(this),
onPageSizeChange: this.onPageSizeChange.bind(this),
};
},
};
export default methods;
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/mixin/editableMethods.ts
================================================
import assign from "lodash/assign";
import isObject from "lodash/isObject";
import isEmpty from "lodash/isEmpty";
import dispatchResizeEvent from "../utils/dispatchResizeEvent";
import getCleanRowData from "../utils/getCleanRowData";
import type WebTable from "../table/webTable";
function getDataItemByValue(rowData: any, instance: WebTable) {
const { primaryKey } = instance.props;
const primaryValue = isObject(rowData) ? (rowData as any)[primaryKey!] : rowData;
return instance.getDataItem(primaryValue);
}
function getAndCloneDataItem(rowData: any, instance: WebTable) {
return getCleanRowData(getDataItemByValue(rowData, instance));
}
function callTableCell(rowData: any, instance: WebTable, callback: (field: any) => any) {
const item = getDataItemByValue(rowData, instance) || {};
const { __fields__ } = item;
if (__fields__) {
const promiseList: Promise[] = [];
Object.keys(__fields__).forEach((name) => {
const field = __fields__[name];
if (field && callback) {
promiseList.push(Promise.resolve(callback(field)));
}
});
return Promise.all(promiseList);
}
return Promise.resolve();
}
// editRow(rowData): 使指定的行切换到编辑模式。
// saveRow(rowData): 保存行至数据
// resetRow(rowData): 重置行到数据(若保存过,则为保存过后的数据)。
export interface IEditableMethodsProps {
onEditRow?(rowItem: any): void;
onResetRow?(rowItem: any): void;
onSaveRow?(rowItem: any): void;
}
export interface IEditableMethods {
init(this: WebTable): void;
validateRow(this: WebTable, rowData: any): any;
editRow(this: WebTable, rowData: any): any;
saveRow(this: WebTable, rowData: any): any;
resetRow(this: WebTable, rowData: any): any;
}
const methods: IEditableMethods = {
init() {
const mergeState = {};
this.state = this.state || {};
assign(this.state, mergeState);
},
validateRow(rowData) {
return callTableCell(rowData, this, (field) => {
return field.validateCell();
}).then((dataList) => {
const result: any = {};
dataList && dataList.forEach((field) => {
field && Object.keys(field).forEach((name) => {
result[name] = field[name];
});
});
return isEmpty(result) ? undefined : result;
});
},
editRow(rowData) {
const { onEditRow } = this.props;
const promise = callTableCell(rowData, this, (field) => {
return field.setEditable(true);
}).then(() => {
const rowItem = getAndCloneDataItem(rowData, this);
rowItem && onEditRow && onEditRow(rowItem);
return rowItem;
});
promise.finally(() => {
dispatchResizeEvent();
});
return promise;
},
saveRow(rowData) {
const { onSaveRow } = this.props;
const promise = this.validateRow(rowData).then((error: Error) => {
if (error) {
return Promise.reject(error);
} else {
return callTableCell(rowData, this, (field) => {
return field.saveCell();
});
}
}).then(() => {
const rowItem = getAndCloneDataItem(rowData, this);
rowItem && onSaveRow && onSaveRow(rowItem);
return rowItem;
});
promise.finally(() => {
dispatchResizeEvent();
});
return promise;
},
resetRow(rowData) {
const { onResetRow } = this.props;
const promise = callTableCell(rowData, this, (field) => {
return field.resetCell();
}).then(() => {
const rowItem = getAndCloneDataItem(rowData, this);
rowItem && onResetRow && onResetRow(rowItem);
return rowItem;
});
promise.finally(() => {
dispatchResizeEvent();
});
return promise;
},
};
export default methods;
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/mixin/loadMethods.ts
================================================
import isPlainObject from "lodash/isPlainObject";
export default function loadMethods(target: {[propKey: string]: any}, source: {[propKey: string]: any}) {
if (!source || !isPlainObject(source)) {
return;
}
const { init, ...srcMethods } = source;
// eslint-disable-next-line guard-for-in,no-restricted-syntax
for (const methodName in srcMethods) {
target[methodName] = source[methodName];
}
if (typeof init === 'function') {
init.call(target);
}
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/scss/variables.scss
================================================
/* write style here */
@import '~@alifd/next/variables.scss';
// 必须设置,请严格遵循该包含default的写法。
$css-prefix: 'next-' !default;
$deep-css-prefix: 'deep-' !default;
// 使用到的主题扩展变量,内置默认值
$color-fill1-5: #BBC3CC !default;
$color-fill1-6: #A5AFBC !default;
$color-fill1-7: #79889B !default;
$color-fill1-8: #4C6079 !default;
$color-fill1-9: #1F3858 !default;
// default for theme-97
$color-brand1-2: #FFF0E5 !default;
$color-brand1-3: #FFF7F0 !default;
// default for theme-254
//$color-brand1-2: #E5F1FD !default;
//$color-brand1-3: #F0F7FF !default;
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/table/webTable.tsx
================================================
import React, { ReactNode } from 'react';
import { Table } from '@alifd/next';
import isEqual from 'lodash/isEqual';
import { ColumnProps, TableProps } from '@alifd/next/types/table';
import convertData from '../utils/convertData';
import loadMethods from "../mixin/loadMethods";
import commonMethods, { ICommonMethods } from "../mixin/commonMethods";
import columnMethods, { IColumnMethods } from "../mixin/columnMethods";
import WebToolbar, { IWebToolbarProps } from "../component/webToolbar";
import WebPagination from "../component/webPagination";
import hasRowAction from "../utils/hasRowAction";
import runToolbarActionCallback from "../utils/runToolbarActionCallback";
import buildTableProps from "../utils/buildTableProps";
import editableMethods, { IEditableMethods, IEditableMethodsProps } from "../mixin/editableMethods";
import WebNextTableActionCell, { IWebNextTableActionCellProps } from "../component/webNextTableActionCell";
import WebNextTableCell, { IWebNextTableCellProps } from "../component/webNextTableCell";
import getDataSource from "../utils/getDataSource";
import titleMessageRender from "../utils/render/titleMessageRender";
import { LoadingProps } from '@alifd/next/types/loading';
export interface IWebTableProps extends IWebToolbarProps, IEditableMethodsProps, Omit, Omit {
data?: any;
columns?: any[];
nextTablePrefix?: string;
isPagination?: boolean;
actionTitle?: string;
actionFixed?: string;
actionWidth?: number | string;
pagination?: any;
primaryKey?: string;
onFetchData?: (options: Pick & { from: string; }) => void;
onLoadData?: (...options: any[]) => void;
onColumnsChange?: (columns: IWebTableProps['columns']) => void;
setEmptyContent?: boolean;
emptyContent?: (() => ReactNode) | ReactNode;
noPadding?: boolean;
dataSource?: any;
device?: string;
actionHidden?: boolean;
theme?: string;
width?: string | number;
height?: string | number;
showRowSelector?: boolean;
onSelect?: NonNullable['onSelect'];
onSelectAll?: NonNullable['onSelectAll'];
isRowSelectorDisabled?: (rowData: any, index: number) => boolean;
rowSelector?: string;
onCellDataChange?: IWebNextTableCellProps['onCellDataChange'];
clsPrefix?: string;
tablePrefix?: string;
className?: string;
loadingComponent?: (props: LoadingProps) => ReactNode;
}
interface IWebTableState {
originalColumns?: any[];
currentColumns?: any[]
currentPage: number;
pageSize: number;
searchKey: string;
orderColumn: string;
orderType: string;
dataSource: any;
totalCount: number;
isCustomColumnDrawerShown: boolean;
}
interface WebTable extends React.Component, Omit, Omit, Omit {}
class WebTable extends React.Component {
static displayName = 'WebTable';
constructor(props: IWebTableProps) {
super(props);
loadMethods(this, commonMethods);
loadMethods(this, columnMethods);
loadMethods(this, editableMethods);
}
componentWillReceiveProps(nextProps: IWebTableProps) {
const { data } = this.props;
const nextData = getDataSource(nextProps);
if (!isEqual(nextData, data)) {
this.setState(convertData(nextData));
}
const {originalColumns} = this.state;
const {columns : nextColumns} = nextProps;
if (!isEqual(originalColumns, nextColumns)) {
this.setOriginalColumns(nextColumns);
this.changeCurrentColumns(nextColumns);
}
}
renderColumn(column: any) {
const { nextTablePrefix, onCellDataChange } = this.props;
const { lock, dataKey, width, title, titleRender, message, sortable, align, resizable, filters, filterMode } = column;
const props: ColumnProps = {
dataIndex: dataKey,
cell: (value, rowIndex, rowData) => {
return ();
},
title: titleMessageRender(title, message, nextTablePrefix),
width,
sortable,
align,
resizable,
filters,
filterMode,
};
if (lock && lock !== 'none') {
props.lock = lock;
}
if (titleRender) {
props.title = titleRender(column.title);
}
return ;
}
renderColumns(columns: IWebTableState['currentColumns']) {
return columns ? columns.map((column) => {
if (!column.isGroup) {
return this.renderColumn(column)
}
return (
column.children && column.children.length ?
{
this.renderColumns(column.children)
}
: null
)
}) : null;
}
renderActionColumns() {
const {
actionTitle, actionFixed, actionWidth, actionColumn, actionType,
maxWebShownActionCount, nextTablePrefix, device, primaryKey, locale
} = this.props;
if (!hasRowAction(this.props)) {
return null;
}
const actionColumnProps: ColumnProps = {
title: actionTitle,
lock: actionFixed !== 'none' ? actionFixed : false,
width: actionWidth,
cell: (value, index, rowData) => {
return ;
},
};
return ;
}
render() {
const { nextTablePrefix, isPagination, locale } = this.props;
const { dataSource, currentColumns } = this.state;
const paginationProps = this.getPaginationProps();
return (
{
runToolbarActionCallback({ action: item });
}}
onSearch={this.onSearch.bind(this)}
onClickCustomColumn={this.showCustomColumnDrawer.bind(this)}
paginationProps={paginationProps}
/>
{this.renderColumns(currentColumns)}
{this.renderActionColumns()}
{isPagination ? : null}
{this.renderCustomColumnDrawer()}
);
}
}
export default WebTable;
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/buildNextTableMethod.ts
================================================
import type { NextTable } from "..";
import { IEditableMethods } from "../mixin/editableMethods";
const methodList: (keyof Omit | 'getDataSource')[] = [
'editRow',
'saveRow',
'resetRow',
'validateRow',
'getDataSource',
];
export default function buildNextTableMethod(instance: NextTable) {
methodList.forEach((name) => {
instance[name] = function () {
const { tableRef } = instance;
const { current } = tableRef;
if (current) {
const method = current[name];
if (method) {
return method.apply(current, arguments as any);
}
}
};
});
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/buildTableProps.ts
================================================
import { IWebTableProps } from "../table/webTable";
import { TableProps } from '@alifd/next/types/table';
export default function buildTableProps(props: IWebTableProps) {
const {
loading, dataSource, onSort, emptyContent, onFilter, cellProps, rowProps,
primaryKey, theme, hasHeader, fixedHeader, maxBodyHeight, stickyHeader, isTree, indent,
onRowClick, onRowMouseEnter, onRowMouseLeave, onResizeChange, width, height, loadingComponent,
hasExpandedRowCtrl, expandedRowRender, onRowOpen, expandedRowIndent, useVirtual,offsetTop, sort, sortIcons,
showRowSelector, onSelect, onSelectAll, isRowSelectorDisabled, rowSelector, size, expandedIndexSimulate, rowSelection,
} = props;
let tableProps: TableProps = {
size,
primaryKey: primaryKey || 'id',
dataSource: dataSource || [],
hasBorder: theme === 'border',
hasHeader,
isZebra: theme === 'zebra',
loading,
emptyContent,
cellProps,
rowProps,
onFilter,
fixedHeader,
maxBodyHeight,
stickyHeader,
offsetTop,
isTree,
indent,
useVirtual,
onRowClick,
onRowMouseEnter,
onRowMouseLeave,
onResizeChange,
sort,
sortIcons,
onSort,
loadingComponent,
hasExpandedRowCtrl,
expandedRowRender,
onRowOpen,
expandedRowIndent,
style: { width, height },
expandedIndexSimulate,
};
if ('openRowKeys' in props) {
tableProps.openRowKeys = props.openRowKeys
}
if (showRowSelector) {
let selection: TableProps['rowSelection'];
if (rowSelection) {
selection = rowSelection;
} else {
selection = {};
if (onSelect) {
selection.onSelect = onSelect;
}
if (onSelectAll) {
selection.onSelectAll = onSelectAll;
}
selection.mode = rowSelector === 'checkboxSelector' ? 'multiple' : 'single';
if (isRowSelectorDisabled) {
const isRowSelectorDisabledFunc = isRowSelectorDisabled;
selection.getProps = (rowData, index) => ({
disabled: isRowSelectorDisabledFunc(rowData, index),
});
}
}
tableProps.rowSelection = selection;
}
return tableProps;
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/chainAccess.ts
================================================
export function safeAccess(obj: { [prop: string]: any }, str: string) {
return str.split('.').reduce((o, k) => (o ? o[k] : undefined), obj);
};
export function safeWrite(obj: { [prop: string]: any }, str: string, value: any) {
const segs = str.split('.');
const key = segs.pop();
const leaf = segs.reduce((o, k) => {
if (!o[k]) {
o[k] = {};
}
return o[k];
}, obj);
if (typeof key === 'string') {
leaf[key] = value;
}
};
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/convertData.ts
================================================
import deepcopy from 'lodash/cloneDeep';
import isPlainObject from "lodash/isPlainObject";
export default function convertData(data: Array | { data?: Array; currentPage?: string; totalCount?: string; }) {
let dataSource: Array | undefined = [];
let currentPage = 1;
let totalCount = 0;
if (Array.isArray(data)) {
dataSource = data;
} else if (isPlainObject(data)) {
dataSource = data.data;
currentPage = typeof data.currentPage !== "undefined" ? parseInt(data.currentPage, 10) : 1;
totalCount = typeof data.totalCount !== "undefined" ? parseInt(data.totalCount, 10) : 0;
}
return {dataSource : dataSource ? deepcopy(dataSource) : [], currentPage, totalCount};
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/delegateFunctions.ts
================================================
import deepcopy from "lodash/cloneDeep";
import isFunction from "lodash/isFunction";
export default function delegateFunctions(list: any[] | undefined, key: string, context: any, newArgPosition?: number) {
if (list && list.length) {
const result = deepcopy(list);
result.forEach((item) => {
const func = item && item[key];
if (func && isFunction(func)) {
item[key] = function () {
const ARGS = Array.prototype.slice.call(arguments);
if (newArgPosition === undefined) {
ARGS.push(context);
} else {
ARGS.splice(newArgPosition, 0, context);
}
return func.apply(context, ARGS);
};
}
});
return result;
}
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/dispatchResizeEvent.ts
================================================
let lastDelayId: number;
export default function dispatchResizeEvent() {
clearTimeout(lastDelayId);
lastDelayId = window.setTimeout(function () {
if (window.dispatchEvent) {
window.dispatchEvent(new Event('resize'));
}
}, 10);
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/filterActionColumn.ts
================================================
import type { IWebTableProps } from "../table/webTable";
import filterActionColumnByDevice from "./filterActionColumnByDevice";
export default function filterActionColumn(actionColumn: IWebTableProps['actionColumn'], rowData: any, device: IWebTableProps['device']) {
const filterByEditable = actionColumn.filter((action) => {
if (action.render && typeof action.render === 'function' && !action.render(action.title, rowData)) {
return false
}
if (rowData.__mode__ === "EDIT") {
return action.mode === "EDIT";
} else {
return action.mode !== "EDIT";
}
});
return filterActionColumnByDevice(filterByEditable, device);
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/filterActionColumnByDevice.ts
================================================
import type { IWebTableProps } from "../table/webTable";
export default function filterActionColumnByDevice(actionColumn: IWebTableProps['actionColumn'] = [], device: IWebTableProps['device']) {
return actionColumn.filter((action) => {
let actionDevice = action.device;
if (device && actionDevice) {
if (!Array.isArray(actionDevice)) {
actionDevice = [actionDevice];
}
return actionDevice.includes(device);
} else {
return true;
}
});
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/filterColumn.ts
================================================
import type { IWebCustomColumnDrawerProps } from "../component/webCustomColumnDrawer";
export default function filterColumn(columns: IWebCustomColumnDrawerProps['columns'] = []) {
return columns.filter((item) => {
return item.hidden !== true;
});
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/formatter.ts
================================================
import Big from 'big.js';
const Formatter = {
date: (str: string | false | null, pattern?: string) => {
// new Date(null,false) 会返回最初日期。
if (str === null || str === false || str === undefined || str === '') {
console.warn('Formatter: invalid date');
return '';
}
const date = new Date(str);
if (Object.prototype.toString.call(date) === '[object Date]') {
if (isNaN(date.getTime())) {
// invalid
console.warn('Formatter: invalid date');
return '';
}
let actualPattern = pattern || 'YYYY-MM-DD';
const o = {
'M+': date.getMonth() + 1, // 月份
'D+': date.getDate(), // 日
'd+': date.getDate(), // 日
'H+': date.getHours(), // 小时
'h+': date.getHours(), // 小时
'm+': date.getMinutes(), // 分
's+': date.getSeconds(), // 秒
'Q+': Math.floor((date.getMonth() + 3) / 3), // 季度
'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
S: date.getMilliseconds(), // 毫秒
};
if (/(y+)/i.test(actualPattern)) {
actualPattern = actualPattern.replace(
/(y+)/i,
(substr, $1) => {
return (`${date.getFullYear()}`).slice(4 - $1.length)
}
);
}
(Object.keys(o) as Array).forEach((k) => {
if (new RegExp(`(${k})`).test(actualPattern)) {
actualPattern = actualPattern.replace(new RegExp(`(${k})`), (substr, $1) => {
if ($1.length === 1) return `${o[k]}`;
return `00${o[k]}`.slice(`${o[k]}`.length)
})
}
});
return actualPattern;
}
return '';
},
money: (str: string, delimiter = ' ', fixedNum?: number | string) => {
const actualStr = fixedNum ? new Big(str).toFixed(parseInt(fixedNum.toString(), 10)).toString() : str;
if (actualStr.indexOf('.') !== -1) {
return actualStr.replace(/(\d)(?=(?:\d{3})+(\.))/g, (match, $1) => $1 + delimiter)
.replace(/(\d{3})(?![$|\.|\(|\s])/g, (match, $1) => $1);
}
return actualStr.replace(/(\d)(?=(?:\d{3})+$)/g, (match, $1) => $1 + delimiter);
},
};
export default Formatter;
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/getCleanRowData.ts
================================================
import isPlainObject from "lodash/isPlainObject";
import forOwn from "lodash/forOwn";
import isArray from "lodash/isArray";
function deepCopyExcept(data: any, callback: (value: any, key: string | number) => boolean) {
let dest: any, i, shouldExcept, newValue;
if (isPlainObject(data)) {
dest = {};
forOwn(data, (value, key) => {
newValue = deepCopyExcept(value, callback);
shouldExcept = callback(newValue, key);
if (!shouldExcept) {
dest[key] = newValue;
}
});
} else if (isArray(data)) {
dest = [];
for (i = 0; i < data.length; i++) {
newValue = deepCopyExcept(data[i], callback);
shouldExcept = callback(newValue, i);
if (!shouldExcept) {
dest.push(newValue);
}
}
} else {
return data;
}
return dest;
};
export default function getCleanRowData(rowData: any) {
if (rowData) {
const blackList = ['__mode__', '__fields__', '__expand__'];
return deepCopyExcept(rowData, (value, key) => {
return blackList.indexOf(key) !== -1
})
}
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/getColumnsFromChildern.tsx
================================================
import React, { ReactNode, ReactElement } from 'react'
export default (children: ReactNode) => {
const getColumns = (children: ReactNode) => {
let columns: any = []
const getCols = (children: ReactNode) => {
React.Children.map(children, item => {
const { props } = item as ReactElement;
if (props.children && props.children.length) {
columns.push({
isGroup: true,
title: props.align ? {props.title || ''}
: props.title || '',
children: getColumns(props.children)
})
} else {
columns.push({...props})
}
});
}
getCols(children)
return columns;
}
return getColumns(children)
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/getDataSource.ts
================================================
import type { IWebTableProps } from "../table/webTable";
export default function getDataSource(props: IWebTableProps) {
if (props) {
return props.dataSource || props.data;
}
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/hasRowAction.ts
================================================
import { IWebTableProps } from "../table/webTable";
import filterActionColumnByDevice from "./filterActionColumnByDevice";
export default function hasRowAction(props: IWebTableProps, withoutEdit?: boolean) {
const { actionHidden, actionColumn, device } = props;
if (actionHidden) {
return false;
}
if (actionColumn && actionColumn.length) {
let actionColumnFilter = filterActionColumnByDevice(actionColumn, device);
if (withoutEdit) {
actionColumnFilter = actionColumnFilter.filter((action) => {
return action.mode !== "EDIT";
});
}
return !!(actionColumnFilter && actionColumnFilter.length);
} else {
return false;
}
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/render/actionTitleRender.tsx
================================================
import type { IActionColumnItem } from "../../component/webNextTableActionCell";
export default function actionTitleRender(action: IActionColumnItem, rowData: any) {
const { title, render } = action;
if (render) {
try {
return render(title, rowData);
} catch (e) {
if (e instanceof Error) {
console.warn(e.stack);
}
return title;
}
} else {
return title;
}
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/render/cascadeTimestampRender.tsx
================================================
import errorRender from './errorRender';
import defaultRender from './defaultRender';
import Formatter from '../formatter';
export default function cascadeTimestampRender(cellData: any, item: { timeFormatter?: string }) {
if (!cellData) {
return '';
}
const { timeFormatter } = item;
if (Object.prototype.toString.call(cellData) === '[object Object]') {
if (!cellData.hasOwnProperty('start') && !cellData.hasOwnProperty('end')) {
return errorRender();
}
const start = Formatter.date(cellData.start, timeFormatter);
const end = Formatter.date(cellData.end, timeFormatter);
return defaultRender(`${start} ~ ${end}`);
}
return errorRender();
};
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/render/commonTableCellRender.tsx
================================================
import defaultRender from "./defaultRender";
import timestampRender from "./timestampRender";
import cascadeTimestampRender from "./cascadeTimestampRender";
import moneyRender from "./moneyRender";
import moneyRangeRender from "./moneyRangeRender";
import linkRender from './linkRender'
import fileRender from './fileRender'
import enumRender from './enumRender'
import imageRender from './imageRender'
export default function commonTableCellRender(value: any, index: number, rowData: any, column: any) {
const { dataType } = column;
if (dataType === 'text') {
return defaultRender(value);
}
if (dataType === 'link') {
return linkRender(value, column, rowData)
}
if (dataType === 'file') {
return fileRender(value)
}
if (dataType === 'image') {
return imageRender(value, column, rowData)
}
if (dataType === 'enum') {
return enumRender(value, column)
}
if (dataType === 'timestamp') {
return timestampRender(value, column);
}
if (dataType === 'cascadeTimestamp') {
return cascadeTimestampRender(value, column);
}
if (dataType === 'money') {
return moneyRender(value);
}
if (dataType === 'moneyRange') {
return moneyRangeRender(value);
}
const { render } = column;
if (render) {
try {
return render(value, index, rowData);
} catch (e) {
if (e instanceof Error) {
console.warn(e.stack);
}
return defaultRender(value);
}
} else {
return defaultRender(value);
}
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/render/defaultRender.tsx
================================================
import React from 'react';
import isObject from "lodash/isObject";
export default function defaultRender(value: any, className = '') {
if (value === undefined || value === null) {
return '';
}
if (isObject(value)) {
value = JSON.stringify(value);
}
return (
{value}
);
};
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/render/enumRender.tsx
================================================
import React, { ReactNode } from 'react';
export default function enumRender(cellData: any, column: {
enumData?: { value: any; text?: ReactNode; color?: string }[];
enumBadgeType?: string;
}) {
if (!cellData && cellData !== 0) {
return '';
}
const { enumData, enumBadgeType } = column;
if (!enumData || !Array.isArray(enumData) || enumData.length === 0) {
return cellData;
}
const found = enumData.find((item) => {
return item.value === cellData;
});
let color = 'black';
let theme = 'background';
if (!found) {
return cellData;
}
if (found.color) {
color = found.color;
if (enumBadgeType) {
theme = enumBadgeType;
}
let className = `deep-table-badge deep-table-badge-${theme}-${color}`;
return {found.text}
}
return found.text;
};
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/render/errorRender.tsx
================================================
import defaultRender from './defaultRender';
export default function errorRender() {
return defaultRender('数据格式不合法', 'error-cell');
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/render/fileRender.tsx
================================================
import React from 'react';
export default function fileRender(value: {name?: string; url?: string}[]) {
if (!value) {
return '';
}
if (!value.length || !value.splice) {
return 数据格式不合规,请返回数组形式!
}
return value.map(file => {
return (
{file.name}
)
})
};
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/render/imageRender.tsx
================================================
import React, { MouseEvent } from 'react';
interface IImageRenderColumn {
imageProps?: React.CSSProperties & { onClick?(e: MouseEvent, column: IImageRenderColumn, rowData: any): void };
imageWrapProps?: React.CSSProperties;
}
export default function ImageRender(value: string, column: IImageRenderColumn, rowData: any) {
if (!value || typeof value !== 'string') {
return 数据格式不合规,请返回字符串形式!
}
const imageProps = column.imageProps || {
width: 80,
height: 80,
borderRadius: 4
}
const imageWrapProps = column.imageWrapProps || {
display: 'inline-block',
padding: 4,
background: '#eee',
borderRadius: 4,
height: 88,
width: 88
}
const { onClick, width } = imageProps
const renderImageProps = {
src: value,
width: width,
style: { ...imageProps },
onClick: (e: MouseEvent) => {
if (onClick && typeof onClick === 'function') {
onClick(e, column, rowData)
e.stopPropagation()
}
}
};
return (
)
};
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/render/linkRender.tsx
================================================
import React from 'react';
import { Button } from '@alifd/next'
import { ButtonProps } from '@alifd/next/types/button';
export default function linkRender(value?: { title?: string; href?: string } | string, column?: any, rowData?: any, onClick?: () => void) {
if (value === undefined || value === null) {
return '';
}
let renderProps: ButtonProps = {
text: true,
type: 'primary',
className: `deep-table-link-button`,
title: typeof value == 'object' ? value.title : value,
style: { ...(rowData.style || {}) },
onClick: () => {
onClick && typeof onClick === 'function' && onClick();
if (typeof value === 'object' && value.href) {
location.href = value.href;
} else if (typeof value == 'string') {
location.href = value;
}
}
}
return (
);
};
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/render/moneyRangeRender.tsx
================================================
import errorRender from './errorRender';
import defaultRender from './defaultRender';
import Formatter from '../formatter';
export default function moneyRangeRender(cellData: {
lower?: string;
upper?: string;
currency?: string;
}) {
if (!cellData) {
return '';
}
if (Object.prototype.toString.call(cellData) === '[object Object]') {
if (!cellData.hasOwnProperty('lower') || !cellData.hasOwnProperty('upper')) {
return errorRender();
}
let lower;
let upper;
try {
lower = Formatter.money(cellData.lower || '0', ',', 2);
upper = Formatter.money(cellData.upper || '0', ',', 2);
} catch (e) {
return errorRender();
}
return defaultRender(`${lower} ${cellData.currency || ''} ~ ${upper} ${cellData.currency || ''}`);
}
return errorRender();
};
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/render/moneyRender.tsx
================================================
import errorRender from './errorRender';
import defaultRender from './defaultRender';
import Formatter from '../formatter';
export default function moneyRender(cellData: {
amount: string;
currency: string;
} | string) {
if (cellData === undefined || cellData === null) {
return '';
}
let money;
if (typeof cellData === 'object') {
if (!cellData.hasOwnProperty('amount') || !cellData.hasOwnProperty('currency')) {
return errorRender();
}
try {
money = Formatter.money(cellData.amount || '0', ',', 2);
} catch (e) {
return errorRender();
}
return defaultRender(`${money} ${cellData.currency}`);
}
try {
money = Formatter.money(cellData || '0', ',', 2);
} catch (e) {
return errorRender();
}
return defaultRender(money);
};
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/render/timestampRender.tsx
================================================
import errorRender from './errorRender';
import defaultRender from './defaultRender';
import Formatter from '../formatter';
export default function timestampRender(cellData: string, item: { timeFormatter?: string }) {
if (!cellData) {
return '';
}
if (isNaN(Number(cellData))) {
return errorRender();
}
const { timeFormatter } = item;
const result = Formatter.date(cellData, timeFormatter);
return defaultRender(result);
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/render/titleMessageRender.tsx
================================================
import { Balloon, Icon } from '@alifd/next';
import React, { ReactNode } from 'react';
export default function titleMessageRender(title: ReactNode, message: ReactNode, prefix?: string) {
if (!message) {
return title;
} else {
return
{title}
}
align="t"
>
{message}
}
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/runColumnActionCallback.ts
================================================
import { IActionColumnItem } from "../component/webNextTableActionCell";
import getCleanRowData from "./getCleanRowData";
export default function runColumnActionCallback(param: { action: IActionColumnItem; rowData: any; index?: number }) {
const { action, rowData, index } = param;
const { callback = () => { } } = action;
try {
if (rowData && callback) {
return Promise.resolve(callback(getCleanRowData(rowData), action, index));
}
} catch (e) {
if (e instanceof Error) {
console.warn(e.stack);
}
}
return Promise.reject();
};
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/runToolbarActionCallback.ts
================================================
import { IAction } from "../component/webToolbar";
export default function runToolbarActionCallback(param: { action: IAction }) {
const { action } = param;
const { callback } = action;
try {
return callback && callback(action);
} catch (e) {
if (e instanceof Error) {
console.warn(e.stack);
}
}
};
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-table/utils/tableProps.ts
================================================
import type { IWebTableProps } from "../table/webTable";
export function fetchKey(source: T, keyList: Array): Partial {
const result: Partial = {};
keyList.forEach((k) => {
const v = source[k];
if (typeof v !== "undefined") {
result[k] = v;
}
});
return result;
}
export const tableProps: Array = [
'clsPrefix',
'loading',
'device',
'locale',
'data',
'children',
'size',
'hasBorder',
'isZebra',
'noPadding',
'useVirtual',
'dataSource',
'onLoadData',
'onFetchData',
'columns',
'openRowKeys',
'onFilter',
'actionBar',
'isPagination',
'pagination',
'actionColumn',
'showMiniPager',
'sort',
'sortIcons',
'onColumnsChange',
'primaryKey', 'theme', 'hasHeader', 'fixedHeader', 'maxBodyHeight', 'stickyHeader', 'isTree', 'indent',
'onRowClick', 'onRowMouseEnter', 'onRowMouseLeave', 'onResizeChange', 'width', 'height', 'loadingComponent',
'hasExpandedRowCtrl', 'expandedRowRender', 'onRowOpen', 'expandedRowIndent',
'showRowSelector', 'onSelect', 'onSelectAll', 'isRowSelectorDisabled', 'rowSelector',
'actionHidden',
'actionColumn',
'actionTitle',
'actionType',
'actionFixed',
'actionWidth',
'maxWebShownActionCount',
'rowSelection',
'cellProps',
'rowProps',
'offsetTop',
'showActionBar',
'actionBar',
'showSearch',
'showCustomColumn',
'searchBarPlaceholder',
'showLinkBar',
'linkBar',
"rowOrder",
"customBarItem",
'onCellDataChange',
'expandedIndexSimulate',
'onEditRow',
'onSaveRow',
'onResetRow',
'setEmptyContent',
'emptyContent'
];
export const paginationProps = [
'size',
'type',
'shape',
'pageShowCount',
'pageSize',
'pageSizeSelector',
'pageSizeList',
'pageNumberRender',
'pageSizePosition',
'useFloatLayout',
'hideOnlyOnePage',
'showJump',
'link',
'popupProps',
'paginationPosition',
];
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-text/index.scss
================================================
$css-prefix: '.next-';
:root {
--s-base: 4px;
--s-compact: calc(var(--s-base) * 50);
--s-comfortable: calc(var(--s-base) * 80);
--s-luxury: calc(var(--s-base) * 160);
--s-1: 4px;
--s-2: 8px;
--s-3: 12px;
--s-4: 16px;
--s-5: 20px;
--s-6: 24px;
--s-7: 28px;
--s-8: 32px;
--s-9: 36px;
--s-10: 40px;
/* font */
--font-family: Roboto, 'Helvetica Neue', Helvetica, Tahoma, Arial, 'PingFang SC',
'Microsoft YaHei';
--p-h1-font-size: 56px;
--p-h1-icon-size: 56px;
--p-h1-font-weight: 900;
--p-h1-line-height: 64px;
--p-h1-margin-top: var(--s-9);
--p-h1-margin-bottom: var(--s-1);
--p-h2-font-size: 48px;
--p-h2-icon-size: 48px;
--p-h2-font-weight: 800;
--p-h2-line-height: 52px;
--p-h2-margin-top: var(--s-8);
--p-h2-margin-bottom: var(--s-1);
--p-h3-font-size: 36px;
--p-h3-icon-size: 36px;
--p-h3-font-weight: 700;
--p-h3-line-height: 44px;
--p-h3-margin-top: var(--s-7);
--p-h3-margin-bottom: var(--s-1);
--p-h4-font-size: 24px;
--p-h4-icon-size: 24px;
--p-h4-font-weight: 600;
--p-h4-line-height: 32px;
--p-h4-margin-top: var(--s-5);
--p-h4-margin-bottom: var(--s-2);
--p-h5-font-size: 20px;
--p-h5-icon-size: 20px;
--p-h5-font-weight: 500;
--p-h5-line-height: 28px;
--p-h5-margin-top: var(--s-4); // 上下不一定相等
--p-h5-margin-bottom: var(--s-1);
/* large */
--p-h6-font-size: 16px;
--p-h6-icon-size: 16px;
--p-h6-font-weight: 400;
--p-h6-line-height: 24px;
--p-h6-margin-top: var(--s-4);
--p-h6-margin-bottom: var(--s-1);
--p-body1-font-size: 16px;
--p-body1-icon-size: 16px;
--p-body1-font-weight: 400;
--p-body1-line-height: 24px;
--p-body1-margin-top: var(--s-3);
--p-body1-margin-bottom: var(--s-1);
--p-body1-indent-size: var(--s-2);
/* medium */
--p-body2-font-size: 14px;
--p-body2-icon-size: 14px;
--p-body2-font-weight: 400;
--p-body2-line-height: 22px;
--p-body2-margin-top: var(--s-2);
--p-body2-margin-bottom: var(--s-1);
--p-body2-indent-size: var(--s-2);
/* small */
--p-caption-font-size: 12px;
--p-caption-icon-size: 12px;
--p-caption-font-weight: 300;
--p-caption-line-height: 20px;
--p-caption-margin-top: var(--s-3);
--p-caption-margin-bottom: var(--s-1);
--p-caption-indent-size: var(--s-1);
--p-overline-font-size: 10px;
--p-overline-icon-size: 10px;
--p-overline-font-weight: 200;
--p-overline-line-height: 18px;
--p-overline-margin-top: var(--s-1);
--p-overline-margin-bottom: var(--s-1);
}
body {
--p-h1-margin-top: var(--s-1);
--p-h2-margin-top: var(--s-1);
--p-h3-margin-top: var(--s-1);
--p-h4-margin-top: var(--s-1);
--p-h5-margin-top: var(--s-1);
--p-h6-margin-top: var(--s-1);
--p-body1-margin-top: var(--s-1);
--p-body2-margin-top: var(--s-1);
--p-caption-margin-top: var(--s-1);
}
#{$css-prefix}text {
color: #1f2633;
text-align: justify;
// & + & {
// margin-left: 0;
// }
&-title {
font-weight: bold;
margin-bottom: 0.5em;
}
& + &-title {
margin-top: 1.2em;
}
&-paragraph {
color: #1f2633;
margin-bottom: 1em;
font-size: 14px;
line-height: 1.5;
}
mark {
padding: 0;
background: #fffbc7;
color: #1f2633;
}
strong {
font-weight: bold;
}
code {
background-color: #f4f6f9;
color: #1f2633;
border: 1px solid #e4e8ee;
margin: 0 0.2em;
padding: 0.2em 0.4em 0.1em;
font-size: 85%;
border-radius: 4px;
}
ul,
ol {
margin: 0 0 1em 0;
padding: 0;
}
li {
list-style-type: circle;
margin: 0 0 0 20px;
padding: 0 0 0 4px;
}
a {
text-decoration: none;
&:link {
color: rgba(3, 193, 253, 1);
}
&:visited {
color: rgba(0, 123, 176, 1);
}
&:hover {
color: rgba(0, 157, 214, 1);
}
&:active {
text-decoration: underline;
color: rgba(0, 157, 214, 1);
}
}
}
h1#{$css-prefix}text-title {
font-size: 24px;
}
h2#{$css-prefix}text-title {
font-size: 20px;
}
h3#{$css-prefix}text-title {
font-size: 16px;
}
h4#{$css-prefix}text-title {
font-size: 16px;
}
h5#{$css-prefix}text-title {
font-size: 14px;
}
h6#{$css-prefix}text-title {
font-size: 14px;
}
#{$css-prefix}text {
&-inherit {
font-family: inherit;
font-size: inherit;
font-weight: inherit;
line-height: inherit;
}
&-overline {
font-family: var(--p-overline-font-family);
font-size: var(--p-overline-font-size);
font-weight: var(--p-overline-font-weight);
line-height: var(--p-overline-line-height);
}
&-caption {
font-family: var(--p-caption-font-family);
font-size: var(--p-caption-font-size);
font-weight: var(--p-caption-font-weight);
line-height: var(--p-caption-line-height);
}
&-body2 {
font-family: var(--p-body2-font-family);
font-size: var(--p-body2-font-size);
font-weight: var(--p-body2-font-weight);
line-height: var(--p-body2-line-height);
}
&-body1 {
font-family: var(--p-body1-font-family);
font-size: var(--p-body1-font-size);
font-weight: var(--p-body1-font-weight);
line-height: var(--p-body1-line-height);
}
&-h6 {
font-family: var(--p-h6-font-family);
font-size: var(--p-h6-font-size);
font-weight: var(--p-h6-font-weight);
line-height: var(--p-h6-line-height);
}
&-h5 {
font-family: var(--p-h5-font-family);
font-size: var(--p-h5-font-size);
font-weight: var(--p-h5-font-weight);
line-height: var(--p-h5-line-height);
}
&-h4 {
font-family: var(--p-h4-font-family);
font-size: var(--p-h4-font-size);
font-weight: var(--p-h4-font-weight);
line-height: var(--p-h4-line-height);
}
&-h3 {
font-family: var(--p-h3-font-family);
font-size: var(--p-h3-font-size);
font-weight: var(--p-h3-font-weight);
line-height: var(--p-h3-line-height);
}
&-h2 {
font-family: var(--p-h2-font-family);
font-size: var(--p-h2-font-size);
font-weight: var(--p-h2-font-weight);
line-height: var(--p-h2-line-height);
}
&-h1 {
font-family: var(--p-h1-font-family);
font-size: var(--p-h1-font-size);
font-weight: var(--p-h1-font-weight);
line-height: var(--p-h1-line-height);
}
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/next-text/index.tsx
================================================
import * as React from 'react';
import classNames from 'classnames';
export const createTitle = (Tag) => {
/**
* Typography.Title
* @description 分为 H1, H2, H3, H4, H5, H6 不同的组件,表示不同层级,继承 Typography.Text API
* @order 1
*/
class Title extends React.Component {
static defaultProps = {
prefix: 'next-',
};
render() {
const { prefix, className, ...others } = this.props;
return (
);
}
}
Title.displayName = Tag.toUpperCase();
return Title;
};
/**
* 判断是否是生产环境
* @type {Boolean}
*/
export const isProduction = () => {
const PRODUCTION_ENV = 'production';
let result = false;
try {
if (process.env.NODE_ENV === PRODUCTION_ENV) {
result = true;
}
} catch (err) {
//
}
return result;
};
// 兼容老逻辑
export const textTypeMap = {
'body-1': 'body2',
'body-2': 'body1',
subhead: 'h6',
title: 'h5',
headline: 'h4',
'display-1': 'h3',
'display-2': 'h2',
'display-3': 'h1',
};
interface TextProps {
prefix?: string;
className?: string;
// type?: 'overline' | 'caption' | 'body-1' | 'body-2' | 'subhead' | 'title' | 'headline' | 'display-1' | 'display-2' | 'display-3';
// title === h5
// des === description
type?:
| 'h1'
| 'h2'
| 'h3'
| 'h4'
| 'h5'
| 'title'
| 'h6'
| 'body1'
| 'body2'
| 'caption'
| 'overline'
| 'inherit';
children?: React.ReactNode;
/**
* 添加删除线样式
*/
delete?: boolean;
/**
* 添加标记样式
*/
mark?: boolean;
/**
* 添加下划线样式
*/
underline?: boolean;
/**
* 是否加粗
*/
strong?: boolean;
/**
* 添加代码样式
*/
code?: boolean;
/**
* 设置标签类型
*/
component?: React.ElementType;
}
/**
* 文字 字体、大小、行高
* @param props
*/
const Text: React.FC = (props, ref) => {
const {
prefix,
className,
type,
component = 'span',
strong,
underline,
delete: deleteProp,
code,
mark,
...others
} = props;
let { children } = props;
const newType = textTypeMap[type] || type;
const cls = classNames(className, {
[`${prefix}text`]: true,
[`${prefix}text-${newType}`]: newType,
});
if (typeof children === 'string' && children.indexOf('\n') !== -1) {
const childrenList = children.split('\n');
const newChildren: any = [];
childrenList.forEach((child) => {
newChildren.push(child);
newChildren.push(
);
});
newChildren.pop();
children = newChildren;
}
const Tag = component;
if (strong) {
children = {children};
}
if (underline) {
children = {children};
}
if (deleteProp) {
children = {children};
}
if (code) {
children = {children};
}
if (mark) {
children = {children};
}
return (
{children}
);
};
const RefText = React.forwardRef(Text);
RefText.defaultProps = {
prefix: 'next-',
};
const Paragraph: React.FC = (props) => {
const { prefix, className, component, ...others } = props;
const cls = classNames(`${prefix}text-paragraph`, className);
if (!isProduction()) {
console.warn('Warning: Text.Paragraph is deprecated, use P instead');
}
return ;
};
// 为了保证兼容性,@alifd/next基础组件中 Typography 组件有的所有子组件、功能,Text也有,但是均不建议使用
RefText.H1 = createTitle('h1');
RefText.H2 = createTitle('h2');
RefText.H3 = createTitle('h3');
RefText.H4 = createTitle('h4');
RefText.H5 = createTitle('h5');
RefText.H6 = createTitle('h6');
RefText.Paragraph = Paragraph;
export default RefText;
================================================
FILE: packages/fusion-lowcode-materials/src/components/note-wrapper/index.scss
================================================
/* write style here */
.done-note-wrapper.render-wrapper-root {
// display: none !important;
display: block !important;
position: absolute !important;
z-index: 1 !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
line-height: 0 !important;
color: #000 !important;
border: 1px dashed rgba(9, 195, 182, 0.5) !important;
border-radius: 0 !important;
pointer-events: none !important;
text-align: left !important;
margin: 0;
padding: 0;
.render-wrapper-note {
display: inline-block;
width: 18px;
height: 18px;
margin: -1px 0 0 -1px;
line-height: 18px;
text-align: center;
font-size: 12px;
color: #fff;
background: #09c3b6;
border-radius: 0 0 60% 0;
opacity: 0.5;
pointer-events: auto;
cursor: pointer;
&:hover {
opacity: 1;
box-shadow: 1px 1px 4px rgba(68, 215, 182, 0.5);
}
}
&.hover {
border-color: #09c3b6 !important;
.render-wrapper-note {
opacity: 1;
background: #09c3b6;
}
}
}
.render-wrapper-target:hover > .render-wrapper-root,
.render-wrapper-root.hover {
display: block !important;
}
// 全局禁用批注
.preview-shell-note-0 {
.render-wrapper-root {
display: none !important;
}
.render-wrapper-target:hover > .render-wrapper-root,
.render-wrapper-root.hover {
display: none !important;
}
}
// 全局开启批注
.preview-shell-note-1 {
}
// 全局批注全部显示
.preview-shell-note-2 {
.render-wrapper-root {
display: block !important;
}
}
================================================
FILE: packages/fusion-lowcode-materials/src/components/note-wrapper/index.tsx
================================================
import React, { useEffect } from 'react';
import ReactDom from 'react-dom';
import { Balloon } from '@alifd/next';
const targetClass = 'render-wrapper-target';
const rootClass = 'render-wrapper-root done-note-wrapper';
// 获取DOM真实style的方法
const getStyle = (obj, attr) => {
if (obj.currentStyle) {
// 兼容IE
return obj.currentStyle[attr];
} else {
return window.getComputedStyle(obj, null)[attr];
}
};
interface NoteProps {
note?: string;
id?: string;
}
const NoteWrapper: React.ForwardRefRenderFunction = (props, ref) => {
const el = document.createElement('div');
let innerRef = null;
el.className = rootClass;
el.id = props.id;
el.ref = ref;
const _renderLayer = function() {
const { note } = props;
const defaultTrigger = N
;
const node = (
{note}
);
ReactDom.render(node, el);
};
useEffect(() => {
_renderLayer();
if (innerRef) {
const refDom = ReactDom.findDOMNode(innerRef);
if (refDom.className.indexOf(targetClass) === -1) {
if (getStyle(refDom, 'position') === 'static') {
refDom.style.position = 'relative'; // 当target目标组件的position为static时, 则使用relative, 方便内层元素定位
}
refDom.className += ` ${targetClass}`;
refDom.appendChild(el);
}
}
});
const { children } = props;
const _children = React.Children.map(children, (child) => {
let c = child;
if (typeof child === 'string') c = {child};
return React.cloneElement(c, { ref: (ref) => (innerRef = ref) });
});
return _children || <>>;
};
const RefNoteWrapper = React.forwardRef(NoteWrapper);
RefNoteWrapper.displayName = 'Wrapper';
export default RefNoteWrapper;
================================================
FILE: packages/fusion-lowcode-materials/src/components/rich-text/index.tsx
================================================
import * as React from 'react';
// 新结构
interface IContent {
aone?: {
// 可能未绑定
url: string;
priorityId: string;
project: { id: string; name: string };
creator: { empId: string; name: string };
assigner: { empId: string; name: string };
};
subject: string;
description: string;
hideTitle?: boolean;
id?: string;
}
interface IRichTextProps {
content?: IContent | string;
className?: string;
maxHeight?: string;
}
/**
* 文字 字体、大小、行高
* @param props
*/
const RichText: React.ForwardRefRenderFunction = (props, ref) => {
const {
content = { subject: '', description: '' },
maxHeight = 'auto',
...others
}: IRichTextProps = props;
const oldType = typeof content === 'string';
const desc = oldType ? content : content?.description || '';
const title = (!oldType && content?.subject) || '';
const hideTitle = oldType || content?.hideTitle;
return (
{!hideTitle && (
{title}
)}
);
};
const RefRichText = React.forwardRef(RichText);
RefRichText.defaultProps = {
content: {
subject: '需求标题',
hideTitle: false,
description:
'- 你可以在这里描述需求
- 或者粘贴需求截图
',
},
className: '',
};
export default RefRichText;
================================================
FILE: packages/fusion-lowcode-materials/src/components/video/index.tsx
================================================
import * as React from 'react';
export interface Props {
src?: string;
autoPlay?: boolean; //自动播放必须设置 muted=true
loop?: boolean;
muted?: boolean;
controls?: boolean;
poster?: string;
style?: object;
}
/**
* 视频
*/
const Video: React.ForwardRefRenderFunction = (props, ref) => {
return ;
};
const RefVideo = React.forwardRef(Video);
RefVideo.defaultProps = {
src: 'https://fusion.alicdn.com/fusion-site-2.0/fusion.mp4',
};
export default RefVideo;
================================================
FILE: packages/fusion-lowcode-materials/src/index.scss
================================================
@import './components/note-wrapper/index.scss';
@import './components/next-text/index.scss';
================================================
FILE: packages/fusion-lowcode-materials/src/index.tsx
================================================
import Link from './components/link';
import Image from './components/image';
import Video from './components/video';
import Balloon from './components/balloon';
import Calendar from './components/calendar';
import RichText from './components/rich-text';
import NextText from './components/next-text';
import NoteWrapper from './components/note-wrapper';
import NextTable from './components/next-table';
import Div from './components/div';
export {
Affix,
Animate,
Badge,
Breadcrumb,
Button,
Calendar2,
Card,
Cascader,
CascaderSelect,
Checkbox,
Collapse,
ConfigProvider,
DatePicker,
Dialog,
Drawer,
Dropdown,
Form,
Grid,
Icon,
Input,
Loading,
Menu,
MenuButton,
Message,
Nav,
Notification,
NumberPicker,
Overlay,
Pagination,
Paragraph,
Progress,
Radio,
Range,
Rating,
Search,
Select,
Slider,
SplitButton,
Step,
Switch,
Tab,
Table,
Tag,
TimePicker,
TimePicker2,
Timeline,
Transfer,
Tree,
TreeSelect,
Upload,
VirtualList,
Typography,
Field,
Divider,
Avatar,
ResponsiveGrid,
Box,
List,
DatePicker2,
} from '@alifd/next';
export { Link, Image, Video, RichText, NextText, NoteWrapper, Calendar, Balloon, NextTable, Div };
================================================
FILE: packages/fusion-lowcode-materials/src/utils.js
================================================
module.exports = {
replacer(key, value) {
if (typeof value === 'function') {
return {
type: 'JSFunction',
value: String(value),
};
}
return value;
},
isAsyncFunction: (fn) => {
return fn[Symbol.toStringTag] === 'AsyncFunction';
},
reviewer(key, value) {
if (!value) {
return value;
}
if (key === 'icon') {
if (typeof value === 'object') {
return {
type: 'smile',
size: 'small',
};
}
}
if (typeof value === 'object') {
if (value.type === 'JSFunction') {
let _value = value.value && value.value.trim();
let template = `
return function lowcode() {
const self = this;
try {
return (${_value}).apply(self, arguments);
} catch(e) {
console.log('call function which parsed by lowcode for key ${key} failed: ', e);
return e.message;
}
};`;
try {
return Function(template)();
} catch (e) {
if (e && e.message.includes("Unexpected token '{'")) {
console.log('method need add funtion prefix');
_value = 'function ' + _value;
template = `
return function lowcode() {
const self = this;
try {
return (${_value}).apply(self, arguments);
} catch(e) {
console.log('call function which parsed by lowcode for key ${key} failed: ', e);
return e.message;
}
};`;
return Function(template)();
}
console.error('parse lowcode function error: ', e);
console.error(value);
return value;
}
}
}
return value;
},
toJson(object, replacer) {
return JSON.stringify(object, replacer || this.replacer, 2);
},
parseJson(json) {
const input = typeof json === 'string' ? json : JSON.stringify(json);
return JSON.parse(input, this.reviewer);
},
calculateDependencies(schema, componentsMap) {
function findComps(schema, componentsMap, dependencies) {
dependencies = dependencies || {};
if (dependencies[schema.componentName]) {
dependencies[schema.componentName].count++;
} else {
dependencies[schema.componentName] = {
count: 1,
};
if (componentsMap && componentsMap[schema.componentName]) {
dependencies[schema.componentName].npm = componentsMap[schema.componentName].package;
dependencies[schema.componentName].version = componentsMap[schema.componentName].version;
}
}
if (schema.children && Array.isArray(schema.children)) {
schema.children.forEach((child) => {
dependencies = Object.assign(dependencies, findComps(child, componentsMap, dependencies));
});
}
return dependencies;
}
const comps = findComps(schema, componentsMap);
const deps = {};
Object.keys(comps).forEach((key) => {
const comp = comps[key];
if (!comp.npm) comp.npm = 'BuiltIn';
if (deps[`${comp.npm}${comp.version ? '@' + comp.version : ''}`]) {
deps[`${comp.npm}${comp.version ? '@' + comp.version : ''}`][key] = comp.count;
} else {
deps[`${comp.npm}${comp.version ? '@' + comp.version : ''}`] = {
[key]: comp.count,
};
}
});
return deps;
},
};
================================================
FILE: packages/fusion-ui/.editorconfig
================================================
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
quote_type = single
[*.md]
trim_trailing_whitespace = false
================================================
FILE: packages/fusion-ui/.eslintignore
================================================
node_modules/
build/
dist/
lib/
es/
docs/
plugins/
build*
**/*.min.js
**/*-min.js
**/*.bundle.js
================================================
FILE: packages/fusion-ui/.eslintrc.js
================================================
module.exports = {
extends: [
'eslint-config-ali/typescript/react',
'prettier',
'prettier/@typescript-eslint',
'prettier/react',
],
rules: {
'@typescript-eslint/ban-ts-comment': 'off',
},
};
================================================
FILE: packages/fusion-ui/.gitignore
================================================
lowcode_es/
lowcode_lib/
# See https://help.github.com/ignore-files/ for more about ignoring files.
# dependencies
node_modules/
# production
build/
dist/
tmp/
lib/
es/
# misc
.idea/
.happypack
.DS_Store
*.swp
*.dia~
.tmp
npm-debug.log*
yarn-debug.log*
yarn-error.log*
yarn.lock
storybook-static/
docs/src/.umi/
================================================
FILE: packages/fusion-ui/.markdownlint.json
================================================
{
"extends": "markdownlint-config-ali"
}
================================================
FILE: packages/fusion-ui/.markdownlintignore
================================================
node_modules/
build/
dist/
================================================
FILE: packages/fusion-ui/.prettierrc.js
================================================
module.exports = {
printWidth: 100,
tabWidth: 2,
semi: true,
singleQuote: true,
trailingComma: 'all',
arrowParens: 'always',
};
================================================
FILE: packages/fusion-ui/.stylelintignore
================================================
node_modules/
build/
dist/
es/
lib/
docs/
**/*.min.css
**/*-min.css
**/*.bundle.css
================================================
FILE: packages/fusion-ui/.stylelintrc.js
================================================
module.exports = {
extends: 'stylelint-config-ali',
};
================================================
FILE: packages/fusion-ui/README.md
================================================
# README
## 开发常用命令
- `cnpm start` 运行所有组件的开发调试环境
- `cnpm start page-header` 运行单个组件的开发调试环境
- `cnpm run lowcode:dev` 启动低代码开发调试环境
- `cnpm run lowcode:build` 构建低代码产物
- `cnpm run build` 打包生成 lib/ es/ dist/ build/文件
- `cnpm run materials` 生成物料中心需要的入库 JSON 文件
- `cnpm run lint` 进行代码检查
================================================
FILE: packages/fusion-ui/build.json
================================================
{
"library": "AlifdFusionUi",
"libraryTarget": "umd",
"sourceMap": false,
"alias": {
"@": "./src",
"@components": "./src/components"
},
"plugins": [
[
"build-plugin-component",
{
"themePackage": "@alifd/theme-2"
}
],
[
"build-plugin-fusion",
{
"uniteBaseComponent": "@alifd/next",
"cssVariable": true,
"importOptions": {
"libraryDirectory": "lib"
}
}
]
]
}
================================================
FILE: packages/fusion-ui/build.lowcode.js
================================================
const { library } = require('./build.json');
const { version, name } = require('./package.json');
module.exports = {
sourceMap: false,
alias: {
'@': './src',
'@alifd/fusion-ui': './src',
},
plugins: [
[
'@alifd/build-plugin-lowcode',
{
noParse: true,
renderUrls: [
`https://alifd.alicdn.com/npm/${name}@${version}/dist/${library}.js`,
`https://alifd.alicdn.com/npm/${name}@${version}/dist/${library}.css`,
],
baseUrl: {
prod: `https://alifd.alicdn.com/npm/${name}@${version}`,
daily: `https://alifd.alicdn.com/npm/${name}@${version}`,
},
engineScope: '@alilc',
},
],
[
'build-plugin-fusion',
{
uniteBaseComponent: '@alifd/next',
cssVariable: true,
importOptions: {
libraryDirectory: 'lib',
},
},
],
],
};
================================================
FILE: packages/fusion-ui/commitlint.config.js
================================================
module.exports = {
extends: ['ali'],
};
================================================
FILE: packages/fusion-ui/docs/.dumi/theme/builtins/API.tsx
================================================
import React, { useContext } from 'react';
import type { IApiComponentProps } from 'dumi/theme';
import { context, useApiData } from 'dumi/theme';
import './index.scss';
const LOCALE_TEXTS = {
'zh-CN': {
name: '参数',
description: '说明',
type: '类型',
default: '默认值',
required: '(必选)',
},
'en-US': {
name: 'Name',
description: 'Description',
type: 'Type',
default: 'Default',
required: '(required)',
},
};
export default ({ identifier, export: expt }: IApiComponentProps) => {
const data = useApiData(identifier);
const { locale = '' } = useContext(context);
const texts = /^zh|cn$/i.test(locale) ? LOCALE_TEXTS['zh-CN'] : LOCALE_TEXTS['en-US'];
const defaultComponentName = identifier
?.replace(/-([a-z])/g, function (all, i) {
return i.toUpperCase();
})
?.replace(/^\S/, (s) => s.toUpperCase());
return (
<>
{data && (
<>
{expt === 'default' ? defaultComponentName : expt}
| {texts.name} |
{texts.description} |
{texts.type} |
{texts.default} |
{data[expt]?.map((row) => (
| {row.identifier} |
{row.description || '--'} |
{row.type}
|
{row.default || (row.required && texts.required) || '--'}
|
))}
>
)}
>
);
};
================================================
FILE: packages/fusion-ui/docs/.dumi/theme/builtins/index.scss
================================================
.apiContainer {
border: none !important;
.apiTitle{
text-transform: capitalize;
}
thead tr {
th {
background: #fff;
border: none;
font-weight: 700;
text-align: left;
word-wrap: break-word;
letter-spacing: 0.2px;
padding: 4px 0 10px;
border-bottom: 2px solid #333;
font-size: 14px;
&:first-child {
padding-left: 8px;
}
}
}
tbody tr {
td {
border: none;
border-bottom: 1px solid #ccc;
text-align: left;
margin: 0;
padding: 18px 18px 18px 0;
color: #666;
word-wrap: break-word;
line-height: 24px;
letter-spacing: 0.2px;
font-size: 14px;
code {
color: #666;
word-wrap: break-word;
line-height: 24px;
letter-spacing: 0.2px;
font-size: 13px;
}
&:last-child {
min-width: 72px;
}
&:first-child{
color: #595959;
font-weight: 600;
white-space: nowrap;
padding-left: 8px;
font-size: 14px;
}
}
}
}
.__dumi-default-layout-footer-meta {
border: none;
}
================================================
FILE: packages/fusion-ui/docs/.dumi/theme/layout.tsx
================================================
import React from 'react';
import Layout from 'dumi-theme-default/es/layout';
import '@/index.scss';
import '@alifd/theme-2/dist/next.min.css';
export default ({ children, ...props }) => {
return {children};
};
================================================
FILE: packages/fusion-ui/docs/.fatherrc.ts
================================================
export default {
esm: 'rollup',
sassInRollupMode: {},
sass: {
// 默认值 Dart Sass,如果要改用 Node Sass,可安装 node-sass 依赖,然后使用该配置项
implementation: require('node-sass'),
// 传递给 Dart Sass 或 Node Sass 的配置项,可以是一个 Function
sassOptions: {
},
},
}
================================================
FILE: packages/fusion-ui/docs/.umirc.ts
================================================
import { defineConfig } from 'dumi';
import fs from 'fs';
import { join } from 'path';
const { version } = JSON.parse(fs.readFileSync(join(__dirname, '../package.json'), 'utf8'));
const productStyles =
'.__dumi-default-menu{display:none} .__dumi-default-layout{padding-left:58px!important}';
const productPath = `/@alifd/fusion-ui@${version}/build/docs/`;
export default defineConfig({
// other config entry
chainWebpack(memo) {
memo.module
.rule('js')
.include.add(join(__dirname, '../'))
.end()
.exclude.add(/node_modules/);
// 删除 dumi 内置插件
memo.plugins.delete('friendly-error');
memo.plugins.delete('copy');
// 配置文件import alias
memo.resolve.alias.set('@', join(__dirname, '../src'));
memo.resolve.alias.set('@components', join(__dirname, '../src/components'));
memo.resolve.alias.set('@alifd/fusion-ui', join(__dirname, '../src'));
},
logo: 'https://fusion.alicdn.com/images/jdSvK6gaqaWB.png',
exportStatic: process.env.NODE_ENV === 'production' ? { htmlSuffix: true } : {},
base: process.env.NODE_ENV === 'production' ? productPath : '/',
publicPath: process.env.NODE_ENV === 'production' ? productPath : '/',
styles: process.env.NODE_ENV === 'production' ? [productStyles] : [],
nodeModulesTransform: {
type: 'none',
exclude: [],
},
// md文件中使用@需配置alias
alias: {
'@': join(__dirname, '../src'),
'@components': join(__dirname, '../src/components'),
'@alifd/fusion-ui': join(__dirname, '../src'),
},
apiParser: {
propFilter: (prop) => {
if (prop.declarations !== undefined && prop.declarations.length > 0) {
const hasPropAdditionalDescription = prop.declarations.find((declaration) => {
if (declaration.fileName.includes('node_modules')) {
return (
declaration.fileName.includes('alifd/next') ||
declaration.fileName.includes('bizcharts')
);
}
return true;
});
return Boolean(hasPropAdditionalDescription);
}
return true;
},
},
mfsu: {},
locales: [
['zh-CN', '中文'],
['en-US', 'English'],
],
outputPath: '../build/docs',
});
================================================
FILE: packages/fusion-ui/docs/src/BarChart/index.md
================================================
## 何时使用
BarChart 的基础用法。
## 示例
```tsx
import React from 'react';
import { BarChart } from '@alifd/fusion-ui';
const props = {
data: [
{ year: '1991', value: 72345678 },
{ year: '1992', value: 4321132 },
{ year: '1993', value: 33121112.5 },
{ year: '1994', value: 45227221 },
{ year: '1995', value: 4321221.9 },
{ year: '1996', value: 6322121 },
{ year: '1997', value: 78312213 },
{ year: '1998', value: 4192312 },
{ year: '1999', value: 6212332 },
{ year: '2000', value: 3192312 },
],
xField: 'value',
yField: 'year',
color: '#0079f2',
label: {
visible: true,
position: 'middle',
},
};
export default () => {
return (
basic demo
);
};
```
## API
================================================
FILE: packages/fusion-ui/docs/src/ColumnChart/index.md
================================================
## 何时使用
ColumnChart 的基础用法。
## 示例
```tsx
import React from 'react';
import { ColumnChart } from '@alifd/fusion-ui';
const props = {
data: [
{ year: '1991', value: 72345678 },
{ year: '1992', value: 4321132 },
{ year: '1993', value: 33121112.5 },
{ year: '1994', value: 45227221 },
{ year: '1995', value: 4321221.9 },
{ year: '1996', value: 6322121 },
{ year: '1997', value: 78312213 },
{ year: '1998', value: 4192312 },
{ year: '1999', value: 6212332 },
{ year: '2000', value: 3192312 },
],
xField: 'year',
yField: 'value',
color: '#0079f2',
label: {
visible: true,
position: 'middle',
},
};
export default () => {
return (
basic demo
);
};
```
## API
================================================
FILE: packages/fusion-ui/docs/src/DonutChart/index.md
================================================
## 何时使用
DonutChart 的基础用法。
## 示例
### 基本用法
```tsx
import React from 'react';
import { DonutChart } from '@alifd/fusion-ui';
const props = {
legend: {
position: 'top-left',
},
data: [
{ year: '1991', value: 72345678 },
{ year: '1992', value: 4321132 },
{ year: '1993', value: 33121112.5 },
{ year: '1994', value: 45227221 },
{ year: '1995', value: 4321221.9 },
{ year: '1996', value: 6322121 },
{ year: '1997', value: 78312213 },
{ year: '1998', value: 2192312 },
{ year: '1999', value: 6212332 },
{ year: '2000', value: 1192312 },
],
angleField: 'value',
colorField: 'year',
label: {
visible: true,
type: 'spider',
},
color: ['#3BCBD1', '#47A4FE', '#EDBA42', '#F4704E', '#ED6899', '#7F62C3', '#6E7BC9'],
};
export default () => {
return (
);
};
```
### 显示百分比
```tsx
import React from 'react';
import { DonutChart } from '@alifd/fusion-ui';
const props = {
legend: {
position: 'top-left',
},
data: [
{ year: '1991', value: 72345678 },
{ year: '1992', value: 4321132 },
{ year: '1993', value: 33121112.5 },
{ year: '1994', value: 45227221 },
{ year: '1995', value: 4321221.9 },
{ year: '1996', value: 6322121 },
{ year: '1997', value: 78312213 },
{ year: '1998', value: 2192312 },
{ year: '1999', value: 6212332 },
{ year: '2000', value: 1192312 },
],
angleField: 'value',
colorField: 'year',
color: ['#3BCBD1', '#47A4FE', '#EDBA42', '#F4704E', '#ED6899', '#7F62C3', '#6E7BC9'],
};
export default () => {
return (
);
};
```
## API
================================================
FILE: packages/fusion-ui/docs/src/EditTable/index.md
================================================
## 何时使用
EditTable 的基础用法,演示自己控制数据的用法。code 试一下能不能用
## 示例
## API
================================================
FILE: packages/fusion-ui/docs/src/EditTable/index.tsx
================================================
import React from 'react';
import { EditTable } from '@alifd/fusion-ui';
const props = {
dataSource: [
{
id: 'id-2f5DdE2b-0',
date: '2013-06-12',
percent: 1.862,
documentAmount: 2022,
currency: 'CNY',
company: '支付宝科技有限公司',
childTableProps: {
dataSource: [],
columns: [
{
title: '公司',
dataIndex: 'company',
width: 160,
formatType: 'link',
searchable: true,
},
{
title: '单据金额',
dataIndex: 'documentAmount',
formatType: 'money',
},
{
title: '币种',
dataIndex: 'currency',
formatType: 'currency',
filters: [
{
label: 'CNY',
value: 'CNY',
},
{
label: 'USD',
value: 'USD',
},
{
label: 'JPY',
value: 'JPY',
},
{
label: 'HKD',
value: 'HKD',
},
],
filterMode: 'multiple',
explanation: '提示信息',
width: 110,
},
{
title: '完成进度',
dataIndex: 'percent',
formatType: 'progress',
},
{
title: '到账日期',
dataIndex: 'date',
formatType: 'date',
},
],
},
},
{
id: 'id-2f5DdE2b-1',
date: '2013-06-12',
percent: 1.862,
documentAmount: 2022,
currency: 'CNY',
company: '支付宝科技有限公司',
childTableProps: {
dataSource: [],
columns: [
{
title: '公司',
dataIndex: 'company',
width: 160,
formatType: 'link',
searchable: true,
},
{
title: '单据金额',
dataIndex: 'documentAmount',
formatType: 'money',
},
{
title: '币种',
dataIndex: 'currency',
formatType: 'currency',
filters: [
{
label: 'CNY',
value: 'CNY',
},
{
label: 'USD',
value: 'USD',
},
{
label: 'JPY',
value: 'JPY',
},
{
label: 'HKD',
value: 'HKD',
},
],
filterMode: 'multiple',
explanation: '提示信息',
width: 110,
},
{
title: '完成进度',
dataIndex: 'percent',
formatType: 'progress',
},
{
title: '到账日期',
dataIndex: 'date',
formatType: 'date',
},
],
},
},
{
id: 'id-2f5DdE2b-2',
date: '2013-06-12',
percent: 1.862,
documentAmount: 2022,
currency: 'CNY',
company: '支付宝科技有限公司',
childTableProps: {
dataSource: [],
columns: [
{
title: '公司',
dataIndex: 'company',
width: 160,
formatType: 'link',
searchable: true,
},
{
title: '单据金额',
dataIndex: 'documentAmount',
formatType: 'money',
},
{
title: '币种',
dataIndex: 'currency',
formatType: 'currency',
filters: [
{
label: 'CNY',
value: 'CNY',
},
{
label: 'USD',
value: 'USD',
},
{
label: 'JPY',
value: 'JPY',
},
{
label: 'HKD',
value: 'HKD',
},
],
filterMode: 'multiple',
explanation: '提示信息',
width: 110,
},
{
title: '完成进度',
dataIndex: 'percent',
formatType: 'progress',
},
{
title: '到账日期',
dataIndex: 'date',
formatType: 'date',
},
],
},
},
],
actionColumnButtons: {
dataSource: [
{
children: '查看',
type: 'primary',
},
{
children: '编辑',
type: 'primary',
disabled: true,
},
{
children: '删除',
type: 'primary',
},
],
text: true,
visibleButtonCount: 3,
},
actionBarButtons: {
dataSource: [
{
type: 'primary',
children: '操作一',
},
{
type: 'normal',
children: '操作二',
},
],
visibleButtonCount: 3,
},
paginationProps: {
pageSize: 20,
current: 1,
},
settingButtons: true,
columns: [
{
title: '公司',
dataIndex: 'company',
width: 160,
formatType: 'link',
searchable: true,
},
{
title: '单据金额',
dataIndex: 'documentAmount',
formatType: 'money',
},
{
title: '币种',
dataIndex: 'currency',
formatType: 'currency',
filters: [
{
label: 'CNY',
value: 'CNY',
},
{
label: 'USD',
value: 'USD',
},
{
label: 'JPY',
value: 'JPY',
},
{
label: 'HKD',
value: 'HKD',
},
],
filterMode: 'multiple',
explanation: '提示信息',
width: 110,
},
{
title: '完成进度',
dataIndex: 'percent',
formatType: 'progress',
},
{
title: '到账日期',
dataIndex: 'date',
formatType: 'date',
},
],
};
export default () => {
return (
);
};
================================================
FILE: packages/fusion-ui/docs/src/ExpandTable/index.md
================================================
## 何时使用
ExpandTable 的基础用法,演示自己控制数据的用法。code 试一下能不能用
## 示例
## API
================================================
FILE: packages/fusion-ui/docs/src/ExpandTable/index.tsx
================================================
import React from 'react';
import { ExpandTable } from '@alifd/fusion-ui';
const props = {
dataSource: [
{
id: 'id-2f5DdE2b-0',
date: '2013-06-12',
percent: 1.862,
documentAmount: 2022,
currency: 'CNY',
company: '支付宝科技有限公司',
childTableProps: {
dataSource: [],
columns: [
{
title: '公司',
dataIndex: 'company',
width: 160,
formatType: 'link',
searchable: true,
},
{
title: '单据金额',
dataIndex: 'documentAmount',
formatType: 'money',
},
{
title: '币种',
dataIndex: 'currency',
formatType: 'currency',
filters: [
{
label: 'CNY',
value: 'CNY',
},
{
label: 'USD',
value: 'USD',
},
{
label: 'JPY',
value: 'JPY',
},
{
label: 'HKD',
value: 'HKD',
},
],
filterMode: 'multiple',
explanation: '提示信息',
width: 110,
},
{
title: '完成进度',
dataIndex: 'percent',
formatType: 'progress',
},
{
title: '到账日期',
dataIndex: 'date',
formatType: 'date',
},
],
},
},
{
id: 'id-2f5DdE2b-1',
date: '2013-06-12',
percent: 1.862,
documentAmount: 2022,
currency: 'CNY',
company: '支付宝科技有限公司',
childTableProps: {
dataSource: [],
columns: [
{
title: '公司',
dataIndex: 'company',
width: 160,
formatType: 'link',
searchable: true,
},
{
title: '单据金额',
dataIndex: 'documentAmount',
formatType: 'money',
},
{
title: '币种',
dataIndex: 'currency',
formatType: 'currency',
filters: [
{
label: 'CNY',
value: 'CNY',
},
{
label: 'USD',
value: 'USD',
},
{
label: 'JPY',
value: 'JPY',
},
{
label: 'HKD',
value: 'HKD',
},
],
filterMode: 'multiple',
explanation: '提示信息',
width: 110,
},
{
title: '完成进度',
dataIndex: 'percent',
formatType: 'progress',
},
{
title: '到账日期',
dataIndex: 'date',
formatType: 'date',
},
],
},
},
{
id: 'id-2f5DdE2b-2',
date: '2013-06-12',
percent: 1.862,
documentAmount: 2022,
currency: 'CNY',
company: '支付宝科技有限公司',
childTableProps: {
dataSource: [],
columns: [
{
title: '公司',
dataIndex: 'company',
width: 160,
formatType: 'link',
searchable: true,
},
{
title: '单据金额',
dataIndex: 'documentAmount',
formatType: 'money',
},
{
title: '币种',
dataIndex: 'currency',
formatType: 'currency',
filters: [
{
label: 'CNY',
value: 'CNY',
},
{
label: 'USD',
value: 'USD',
},
{
label: 'JPY',
value: 'JPY',
},
{
label: 'HKD',
value: 'HKD',
},
],
filterMode: 'multiple',
explanation: '提示信息',
width: 110,
},
{
title: '完成进度',
dataIndex: 'percent',
formatType: 'progress',
},
{
title: '到账日期',
dataIndex: 'date',
formatType: 'date',
},
],
},
},
],
actionColumnButtons: {
dataSource: [
{
children: '查看',
type: 'primary',
},
{
children: '编辑',
type: 'primary',
disabled: true,
},
{
children: '删除',
type: 'primary',
},
],
text: true,
visibleButtonCount: 3,
},
actionBarButtons: {
dataSource: [
{
type: 'primary',
children: '操作一',
},
{
type: 'normal',
children: '操作二',
},
],
visibleButtonCount: 3,
},
paginationProps: {
pageSize: 20,
current: 1,
},
settingButtons: true,
columns: [
{
title: '公司',
dataIndex: 'company',
width: 160,
formatType: 'link',
searchable: true,
},
{
title: '单据金额',
dataIndex: 'documentAmount',
formatType: 'money',
},
{
title: '币种',
dataIndex: 'currency',
formatType: 'currency',
filters: [
{
label: 'CNY',
value: 'CNY',
},
{
label: 'USD',
value: 'USD',
},
{
label: 'JPY',
value: 'JPY',
},
{
label: 'HKD',
value: 'HKD',
},
],
filterMode: 'multiple',
explanation: '提示信息',
width: 110,
},
{
title: '完成进度',
dataIndex: 'percent',
formatType: 'progress',
},
{
title: '到账日期',
dataIndex: 'date',
formatType: 'date',
},
],
};
export default () => {
return (
);
};
================================================
FILE: packages/fusion-ui/docs/src/Filter/index.md
================================================
## 何时使用
Filter 的基础用法,演示自己控制数据的用法。code 试一下能不能用
## 示例
## API
================================================
FILE: packages/fusion-ui/docs/src/Filter/index.tsx
================================================
import React from 'react';
import { Input } from '@alifd/next';
import { Filter, ProForm } from '@alifd/fusion-ui';
const ProFormItem = ProForm.Item;
export default () => {
return (
);
};
================================================
FILE: packages/fusion-ui/docs/src/GroupTable/index.md
================================================
## 何时使用
GroupTable 的基础用法,演示自己控制数据的用法。code 试一下能不能用
## 示例
## API
================================================
FILE: packages/fusion-ui/docs/src/GroupTable/index.tsx
================================================
import React from 'react';
import { GroupTable } from '@alifd/fusion-ui';
const dataSource = [
{
header: '头部文字',
footer: '尾部文字',
children: [
{
company: '支付宝科技有限公司',
documentAmount: 2022,
currency: 'CNY',
percent: 1.862,
date: '2013-06-12',
id: 'id-2f5DdE2b-0',
},
{
company: '支付宝科技有限公司',
documentAmount: 2022,
currency: 'CNY',
percent: 1.862,
date: '2013-06-12',
id: 'id-2f5DdE2b-0',
},
],
},
{
header: '头部文字2',
footer: '尾部文字2',
children: [
{
company: '支付宝科技有限公司',
documentAmount: 2022,
currency: 'CNY',
percent: 1.862,
date: '2013-06-12',
id: 'id-2f5DdE2b-0',
},
{
company: '支付宝科技有限公司',
documentAmount: 2022,
currency: 'CNY',
percent: 1.862,
date: '2013-06-12',
id: 'id-2f5DdE2b-0',
},
{
company: '支付宝科技有限公司',
documentAmount: 2022,
currency: 'CNY',
percent: 1.862,
date: '2013-06-12',
id: 'id-2f5DdE2b-0',
},
{
company: '支付宝科技有限公司',
documentAmount: 2022,
currency: 'CNY',
percent: 1.862,
date: '2013-06-12',
id: 'id-2f5DdE2b-0',
},
],
},
];
const props = {
dataSource,
actionColumnButtons: {
dataSource: [
{
children: '查看',
type: 'primary',
},
{
children: '编辑',
type: 'primary',
disabled: true,
},
{
children: '删除',
type: 'primary',
},
],
text: true,
visibleButtonCount: 3,
},
actionBarButtons: {
dataSource: [
{
type: 'primary',
children: '操作一',
},
{
type: 'normal',
children: '操作二',
},
],
visibleButtonCount: 3,
},
paginationProps: {
pageSize: 20,
current: 1,
},
settingButtons: true,
columns: [
{
title: '公司',
dataIndex: 'company',
width: 160,
formatType: 'link',
searchable: true,
},
{
title: '单据金额',
dataIndex: 'documentAmount',
formatType: 'money',
},
{
title: '币种',
dataIndex: 'currency',
formatType: 'currency',
filters: [
{
label: 'CNY',
value: 'CNY',
},
{
label: 'USD',
value: 'USD',
},
{
label: 'JPY',
value: 'JPY',
},
{
label: 'HKD',
value: 'HKD',
},
],
filterMode: 'multiple',
explanation: '提示信息',
width: 110,
},
{
title: '完成进度',
dataIndex: 'percent',
formatType: 'progress',
},
{
title: '到账日期',
dataIndex: 'date',
formatType: 'date',
},
],
};
export default () => {
return (
);
};
================================================
FILE: packages/fusion-ui/docs/src/LineChart/basic.tsx
================================================
import React from 'react';
import { LineChart } from '@alifd/fusion-ui';
const props = {
data: [
{ year: '1991', value: 72345678 },
{ year: '1992', value: 4321132 },
{ year: '1993', value: 33121112.5 },
{ year: '1994', value: 45227221 },
{ year: '1995', value: 4321221.9 },
{ year: '1996', value: 6322121 },
{ year: '1997', value: 78312213 },
{ year: '1998', value: 4192312 },
{ year: '1999', value: 6212332 },
{ year: '2000', value: 3192312 },
],
xField: 'year',
yField: 'value',
color: '#0079f2',
label: {
visible: true,
},
};
export default () => {
return (
);
};
================================================
FILE: packages/fusion-ui/docs/src/LineChart/index.md
================================================
## 何时使用
LineChart 的基础用法。
## 示例
### 基础用法
### 缩略轴
## API
================================================
FILE: packages/fusion-ui/docs/src/LineChart/slider.tsx
================================================
import React from 'react';
import { LineChart } from '@alifd/fusion-ui';
const props = {
data: [
{ year: '1991', value: 72345678 },
{ year: '1992', value: 4321132 },
{ year: '1993', value: 33121112.5 },
{ year: '1994', value: 45227221 },
{ year: '1995', value: 4321221.9 },
{ year: '1996', value: 6322121 },
{ year: '1997', value: 78312213 },
{ year: '1998', value: 4192312 },
{ year: '1999', value: 6212332 },
{ year: '2000', value: 3192312 },
],
xField: 'year',
yField: 'value',
color: '#0079f2',
label: {
visible: true,
},
interactions: [
{
type: 'slider',
cfg: {
start: 0,
end: 1,
},
},
],
};
export default () => {
return (
);
};
================================================
FILE: packages/fusion-ui/docs/src/PageHeader/basic.tsx
================================================
import React from 'react';
import { PageHeader } from '@alifd/fusion-ui';
export default () => {
return (
);
};
================================================
FILE: packages/fusion-ui/docs/src/PageHeader/breadcrumb.tsx
================================================
import React from 'react';
import { PageHeader } from '@alifd/fusion-ui';
import { Breadcrumb } from '@alifd/next';
export default () => {
return (
1
2
3
}
subTitle="This is a subtitle"
/>
);
};
================================================
FILE: packages/fusion-ui/docs/src/PageHeader/index.md
================================================
## 何时使用
PageHeader 的基础用法,演示自己控制数据的用法。code 试一下能不能用
## 示例
### 基础用法
### 面包屑用法
## API
================================================
FILE: packages/fusion-ui/docs/src/PieChart/basic.tsx
================================================
import React from 'react';
import { PieChart } from '@alifd/fusion-ui';
const props = {
legend: {
position: 'top-left',
},
data: [
{ year: '1991', value: 72345678 },
{ year: '1992', value: 4321132 },
{ year: '1993', value: 33121112.5 },
{ year: '1994', value: 45227221 },
{ year: '1995', value: 4321221.9 },
{ year: '1996', value: 6322121 },
{ year: '1997', value: 78312213 },
{ year: '1998', value: 2192312 },
{ year: '1999', value: 6212332 },
{ year: '2000', value: 1192312 },
],
angleField: 'value',
colorField: 'year',
label: {
visible: true,
type: 'spider',
},
color: ['#3BCBD1', '#47A4FE', '#EDBA42', '#F4704E', '#ED6899', '#7F62C3', '#6E7BC9'],
};
export default () => {
return (
);
};
================================================
FILE: packages/fusion-ui/docs/src/PieChart/index.md
================================================
## 何时使用
PieChart 的基础用法。
## 示例
### 基础用法
### 标签显示百分比
## API
================================================
FILE: packages/fusion-ui/docs/src/PieChart/percent.tsx
================================================
import React from 'react';
import { PieChart } from '@alifd/fusion-ui';
const props = {
legend: {
position: 'top-left',
},
data: [
{ year: '1991', value: 72345678 },
{ year: '1992', value: 4321132 },
{ year: '1993', value: 33121112.5 },
{ year: '1994', value: 45227221 },
{ year: '1995', value: 4321221.9 },
{ year: '1996', value: 6322121 },
{ year: '1997', value: 78312213 },
{ year: '1998', value: 2192312 },
{ year: '1999', value: 6212332 },
{ year: '2000', value: 1192312 },
],
angleField: 'value',
colorField: 'year',
color: ['#3BCBD1', '#47A4FE', '#EDBA42', '#F4704E', '#ED6899', '#7F62C3', '#6E7BC9'],
};
export default () => {
return (
);
};
================================================
FILE: packages/fusion-ui/docs/src/ProDialog/basic.tsx
================================================
import React from 'react';
import { ProDialog } from '@alifd/fusion-ui';
import { Button } from '@alifd/next';
export default () => {
const dialogRef = React.useRef();
return (
{
console.log('ok');
}}
onCancel={() => {
console.log('cancel');
}}
onClose={() => {
console.log('close');
}}
>
Start your business here by searching a popular product
);
};
================================================
FILE: packages/fusion-ui/docs/src/ProDialog/index.md
================================================
## 何时使用
ProDialog 的基础用法,演示自己控制数据的用法。code 试一下能不能用
## 示例
### 基本用法
### 长文本
## API
================================================
FILE: packages/fusion-ui/docs/src/ProDialog/large-content.tsx
================================================
import React from 'react';
import { ProDialog } from '@alifd/fusion-ui';
import { Button, Typography } from '@alifd/next';
const { H4 } = Typography;
export default () => {
const dialogRef = React.useRef();
const largeContent = new Array(60)
.fill()
.map((_, index) => (
Start your business here by searching a popular product
));
return (
{
console.log('ok');
}}
onCancel={() => {
console.log('cancel');
}}
onClose={() => {
console.log('close');
}}
>
{largeContent}
);
};
================================================
FILE: packages/fusion-ui/docs/src/ProDrawer/basic.tsx
================================================
import React, { useRef } from 'react';
import { ProDrawer } from '@alifd/fusion-ui';
import { Button } from '@alifd/next';
export default () => {
const drawerRef = useRef();
const handleChangeVis = () => {
drawerRef?.current?.show();
};
return (
{
console.log('ok');
}}
onCancel={() => {
console.log('cancel');
}}
onClose={() => {
console.log('close');
}}
>
Start your business here by searching a popular product
);
};
================================================
FILE: packages/fusion-ui/docs/src/ProDrawer/index.md
================================================
## 何时使用
ProDrawer 的基础用法,演示自己控制数据的用法。code 试一下能不能用
## 示例
### 基本用法
## API
================================================
FILE: packages/fusion-ui/docs/src/ProForm/basic.tsx
================================================
import React from 'react';
import { Input, Field } from '@alifd/next';
import { ProForm, FormInput } from '@alifd/fusion-ui';
const ProFormItem = ProForm.Item;
export default () => {
const field = Field.useField([]);
const [values, setValues] = React.useState();
return (
);
};
================================================
FILE: packages/fusion-ui/docs/src/ProForm/index.md
================================================
## 何时使用
ProForm 的基础用法,演示自己控制数据的用法。code 试一下能不能用
## 示例
### 基本用法
### 操作按钮用法
## API
================================================
FILE: packages/fusion-ui/docs/src/ProForm/operations.tsx
================================================
import React from 'react';
import { Input, Button } from '@alifd/next';
import { ProForm } from '@alifd/fusion-ui';
export default () => {
return (
);
};
================================================
FILE: packages/fusion-ui/docs/src/ProTable/basic.tsx
================================================
import * as React from 'react';
import { ProTable, useProTable } from '@alifd/fusion-ui';
import { fetchPaginationList } from './service';
import { Dialog } from '@alifd/next';
const columns = [
{
title: '公司',
dataIndex: 'company',
width: 160,
},
{
title: '完成进度',
dataIndex: 'percent',
formatType: 'percent',
},
];
const actionColumnButtons = {
dataSource: [
{ children: '查看' },
{
children: '编辑',
disabled: (payload) => payload.rowRecord.percent > 0.5,
},
{
children: '删除',
onClick: (e, payload) => {
Dialog.confirm({
title: `是否删除${payload.rowRecord.company}`,
});
},
},
],
};
export default () => {
const { tableProps } = useProTable(fetchPaginationList);
return ;
};
================================================
FILE: packages/fusion-ui/docs/src/ProTable/index.md
================================================
## 何时使用
ProTable 的基础用法,演示自己控制数据的用法。code试一下能不能用
## 示例
### 基本用法
## API
================================================
FILE: packages/fusion-ui/docs/src/ProTable/service.ts
================================================
import qs from 'qs';
export const fetchPaginationList = async ({ current, pageSize }) => {
const size = +pageSize || 10;
return fetch(
`https://oneapi.alibaba-inc.com/mock/whalebase/pro-table/pagination-list?${qs.stringify({
current,
pageSize,
})}`,
)
.then((res) => res.json())
.then(({ content }) => ({
...content,
dataSource: content.dataSource
.slice(0, size)
.map((vo, index) => ({ ...vo, id: `id-${current * size + index}` })),
}));
};
================================================
FILE: packages/fusion-ui/docs/src/StepForm/basic.tsx
================================================
import React from 'react';
import { Input } from '@alifd/next';
import { StepForm, ProForm } from '@alifd/fusion-ui';
const ProFormItem = ProForm.Item;
const props = {
current: 0,
operations: [
{
content: '上一步',
action: 'previous',
type: 'secondary',
},
{
content: '下一步',
action: 'next',
type: 'primary',
},
],
};
export default () => {
return (
);
};
================================================
FILE: packages/fusion-ui/docs/src/StepForm/index.md
================================================
## 何时使用
StepForm 的基础用法,演示自己控制数据的用法。code 试一下能不能用
## 示例
### 基本用法
## API
================================================
FILE: packages/fusion-ui/docs/src/TabContainer/basic.tsx
================================================
import React from 'react';
import { TabContainer } from '@alifd/fusion-ui';
const props = {
shape: 'pure',
size: 'medium',
excessMode: 'slide',
};
export default () => {
return (
内容1
内容2
内容3
);
};
================================================
FILE: packages/fusion-ui/docs/src/TabContainer/index.md
================================================
## 何时使用
TabContainer 的基础用法,演示自己控制数据的用法。code试一下能不能用
## 示例
### 基本用法
## API
================================================
FILE: packages/fusion-ui/docs/src/anchorForm/index.md
================================================
## 何时使用
适合表单场景。
## 示例
```tsx
import React from 'react';
import { AnchorForm, ChildForm, FormInput, TabContainer } from '@alifd/fusion-ui';
const anchorFormProps = {
showAnchor: true,
enableRandomHtmlId: true,
anchorProps: {
direction: 'hoz',
hasAffix: true,
},
operationConfig: {
align: 'center',
},
operations: [
{
content: '提交',
action: 'submit',
type: 'secondary',
},
{
content: '重置',
action: 'reset',
type: 'secondary',
},
],
};
const childFormProps = [1, 2, 3, 4, 5, 6, 7, 8].map((item) => ({
columns: 2,
mode: 'independent',
anchorItemProps: {
label: `Tab-${item}`,
},
cardSectionProps: {
noBullet: true,
tagGroup: [
{
label: '操作',
color: 'orange',
},
{
label: '操作',
color: 'green',
},
{
label: '操作',
color: 'blue',
},
],
},
}));
const formInputProps = {
formItemProps: {
label: '表单项',
size: 'medium',
device: 'desktop',
fullWidth: true,
},
placeholder: '请输入',
};
export default () => {
return (
);
};
```
## API
================================================
FILE: packages/fusion-ui/docs/src/areaChart/index.md
================================================
## 何时使用
区域图表。
## 示例
```tsx
import React from 'react';
import { AreaChart } from '@alifd/fusion-ui';
const props = {
data: [
{ year: '1991', value: 72345678 },
{ year: '1992', value: 4321132 },
{ year: '1993', value: 33121112.5 },
{ year: '1994', value: 45227221 },
{ year: '1995', value: 4321221.9 },
{ year: '1996', value: 6322121 },
{ year: '1997', value: 78312213 },
{ year: '1998', value: 4192312 },
{ year: '1999', value: 6212332 },
{ year: '2000', value: 3192312 },
],
xField: 'year',
yField: 'value',
color: '#0079f2',
label: {
visible: true,
},
};
export default () => {
return ;
};
```
## API
================================================
FILE: packages/fusion-ui/docs/src/childForm/index.md
================================================
## 何时使用
适合表单场景。
## 示例
```tsx
import React from 'react';
import { Input } from '@alifd/next';
import { ChildForm, ProForm } from '@alifd/fusion-ui';
const ProFormItem = ProForm.Item;
export default () => {
return (
);
};
```
## API
================================================
FILE: packages/fusion-ui/f2elint.config.js
================================================
module.exports = {
enableStylelint: true,
enableMarkdownlint: true,
enablePrettier: true,
};
================================================
FILE: packages/fusion-ui/jest.config.js
================================================
module.exports = {
setupFilesAfterEnv: ['/test/setupTests.js'],
};
================================================
FILE: packages/fusion-ui/lowcode/anchor/meta.ts
================================================
import { hideProp } from '../utils';
const meta = {
components: [
{
componentName: 'Anchor',
group: '精选组件',
title: '电梯容器',
category: '布局容器类',
docUrl: '',
screenshot:
'https://img.alicdn.com/imgextra/i3/O1CN01aDpmze26zlTZVDhtR_!!6000000007733-2-tps-112-112.png',
devMode: 'proCode',
npm: {
package: '@alifd/fusion-ui',
version: '1.0.24-5',
exportName: 'Anchor',
main: 'lib/index.js',
destructuring: true,
subName: '',
},
configure: {
props: [
{
title: {
label: { type: 'i18n', 'en-US': 'dataSource', 'zh-CN': '锚点列表数据源' },
tip: 'dataSource | 锚点列表数据源',
},
name: 'dataSource',
description: '锚点列表数据源',
setter: {
componentName: 'ArraySetter',
props: {
itemSetter: {
componentName: 'ObjectSetter',
props: {
config: {
items: [
{
title: { label: { type: 'i18n', 'en-US': 'htmlId', 'zh-CN': 'htmlId' } },
name: 'htmlId',
setter: {
componentName: 'StringSetter',
isRequired: true,
initialValue: '',
},
},
{
title: { label: { type: 'i18n', 'en-US': 'label', 'zh-CN': 'label' } },
name: 'label',
setter: {
componentName: 'StringSetter',
isRequired: true,
initialValue: '',
},
},
{
title: {
label: { type: 'i18n', 'en-US': 'children', 'zh-CN': 'children' },
},
name: 'children',
setter: {
componentName: 'ArraySetter',
props: {
itemSetter: {
componentName: 'ObjectSetter',
props: {},
isRequired: false,
initialValue: {},
},
},
initialValue: [],
},
},
],
},
},
},
},
isRequired: true,
initialValue: [],
},
},
{
title: {
label: { type: 'i18n', 'en-US': 'container', 'zh-CN': '容器,默认是 win' },
tip: 'container | 容器,默认是 window',
},
condition: hideProp,
name: 'container',
setter: { componentName: 'FunctionSetter', isRequired: false },
},
{
title: {
label: { type: 'i18n', 'en-US': 'direction', 'zh-CN': '锚点方向' },
tip: 'direction | 锚点方向',
},
name: 'direction',
defaultValue: 'ver',
setter: {
componentName: 'RadioGroupSetter',
props: {
dataSource: [
{ label: 'ver', value: 'ver' },
{ label: 'hoz', value: 'hoz' },
],
options: [
{ label: 'ver', value: 'ver' },
{ label: 'hoz', value: 'hoz' },
],
},
initialValue: 'ver',
},
},
{
title: {
label: { type: 'i18n', 'en-US': 'hasAffix', 'zh-CN': '固定在顶部' },
tip: 'hasAffix | direction="hoz" 生效',
},
condition: (target) => {
return target.getProps().getPropValue('direction') === 'hoz';
},
name: 'hasAffix',
setter: { componentName: 'BoolSetter', isRequired: false, initialValue: false },
},
{
title: {
label: { type: 'i18n', 'en-US': 'affixProps', 'zh-CN': '固钉配置' },
tip: 'affixProps | hasAffix={true} 后使用',
},
condition: (target) => {
const hasAffix = target.getProps().getPropValue('hasAffix');
return typeof hasAffix === 'boolean' && hasAffix;
},
name: 'affixProps',
setter: {
componentName: 'ObjectSetter',
props: {
config: {
items: [
{
title: {
label: { type: 'i18n', 'en-US': 'container', 'zh-CN': 'container' },
},
name: 'container',
setter: { componentName: 'FunctionSetter', isRequired: false },
},
{
title: {
label: { type: 'i18n', 'en-US': 'offsetTop', 'zh-CN': 'offsetTop' },
},
name: 'offsetTop',
setter: { componentName: 'NumberSetter', isRequired: false, initialValue: 0 },
},
{
title: {
label: { type: 'i18n', 'en-US': 'offsetBottom', 'zh-CN': 'offsetBottom' },
},
name: 'offsetBottom',
setter: { componentName: 'NumberSetter', isRequired: false, initialValue: 0 },
},
{
title: { label: { type: 'i18n', 'en-US': 'onAffix', 'zh-CN': 'onAffix' } },
name: 'onAffix',
setter: { componentName: 'FunctionSetter' },
},
{
title: {
label: { type: 'i18n', 'en-US': 'useAbsolute', 'zh-CN': 'useAbsolute' },
},
name: 'useAbsolute',
setter: {
componentName: 'BoolSetter',
isRequired: false,
initialValue: false,
},
},
],
},
},
},
},
],
supports: { className: true, style: true },
component: {},
},
},
],
};
export default meta;
================================================
FILE: packages/fusion-ui/lowcode/anchor-form/meta.ts
================================================
import { IComponentDescription } from '../types';
import { hideProp, mockId } from '../utils';
import { operationProps } from '../common';
const AnchorFormMeta: IComponentDescription = {
componentName: 'AnchorForm',
title: '电梯表单',
category: '表单类',
group: '精选组件',
docUrl: '',
screenshot:
'https://img.alicdn.com/imgextra/i1/O1CN01jnfLpK1rFJ4nPj9Pt_!!6000000005601-55-tps-56-56.svg',
devMode: 'proCode',
npm: {
package: '@alifd/fusion-ui',
version: '0.1.6-beta.22',
exportName: 'AnchorForm',
main: 'lib/index.js',
destructuring: true,
subName: '',
},
configure: {
supports: { className: true, style: true, events: ['onChange'] },
component: {
isContainer: true,
isMinimalRenderUnit: true,
nestingRule: {
childWhitelist: ['ChildForm'],
},
},
props: [
{
name: 'anchorConfig',
title: '电梯设置',
type: 'group',
display: 'accordion',
items: [
{
name: 'showAnchor',
title: '电梯显示',
defaultValue: true,
setter: 'BoolSetter',
},
{
title: {
label: { type: 'i18n', 'en-US': 'direction', 'zh-CN': '锚点方向' },
tip: 'direction | 锚点方向',
},
name: 'anchorProps.direction',
condition: (target) => {
const showAnchor = target.getProps().getPropValue('showAnchor');
return typeof showAnchor === 'undefined' || showAnchor;
},
defaultValue: 'ver',
setter: {
componentName: 'RadioGroupSetter',
props: {
dataSource: [
{ label: '垂直', value: 'ver' },
{ label: '水平', value: 'hoz' },
],
options: [
{ label: '垂直', value: 'ver' },
{ label: '水平', value: 'hoz' },
],
},
initialValue: 'ver',
},
},
{
title: {
label: { type: 'i18n', 'en-US': 'hasAffix', 'zh-CN': '固定在顶部' },
tip: 'hasAffix | direction="hoz" 生效',
},
condition: (target) => {
const showAnchor = target.getProps().getPropValue('showAnchor');
return (
showAnchor && target.getProps().getPropValue('anchorProps.direction') === 'hoz'
);
},
name: 'anchorProps.hasAffix',
setter: { componentName: 'BoolSetter', isRequired: false, initialValue: false },
},
],
},
{
title: {
label: { type: 'i18n', 'en-US': 'container', 'zh-CN': '容器,默认是 win' },
tip: 'container | 容器,默认是 window',
},
condition: hideProp,
name: 'container',
setter: { componentName: 'FunctionSetter', isRequired: false },
},
{
title: {
label: { type: 'i18n', 'en-US': 'affixProps', 'zh-CN': '固钉配置' },
tip: 'affixProps | hasAffix={true} 后使用',
},
condition: (target) => {
const hasAffix = target.getProps().getPropValue('hasAffix');
return typeof hasAffix === 'boolean' && hasAffix;
},
name: 'affixProps',
setter: {
componentName: 'ObjectSetter',
props: {
config: {
items: [
{
title: { label: { type: 'i18n', 'en-US': 'container', 'zh-CN': 'container' } },
name: 'container',
setter: { componentName: 'FunctionSetter', isRequired: false },
},
{
title: { label: { type: 'i18n', 'en-US': 'offsetTop', 'zh-CN': 'offsetTop' } },
name: 'offsetTop',
setter: { componentName: 'NumberSetter', isRequired: false, initialValue: 0 },
},
{
title: {
label: { type: 'i18n', 'en-US': 'offsetBottom', 'zh-CN': 'offsetBottom' },
},
name: 'offsetBottom',
setter: { componentName: 'NumberSetter', isRequired: false, initialValue: 0 },
},
{
title: { label: { type: 'i18n', 'en-US': 'onAffix', 'zh-CN': 'onAffix' } },
name: 'onAffix',
setter: { componentName: 'FunctionSetter' },
},
{
title: {
label: { type: 'i18n', 'en-US': 'useAbsolute', 'zh-CN': 'useAbsolute' },
},
name: 'useAbsolute',
setter: { componentName: 'BoolSetter', isRequired: false, initialValue: false },
},
],
},
},
},
},
...operationProps,
{
title: {
label: { type: 'i18n', 'en-US': 'onChange', 'zh-CN': '点击不同锚点时的自定' },
tip: 'onChange | 点击不同锚点时的自定义触发函数',
},
condition: hideProp,
name: 'onChange',
setter: { componentName: 'FunctionSetter' },
},
{
title: {
label: { type: 'i18n', 'en-US': 'offsetY', 'zh-CN': '垂直跳转偏移量' },
tip: 'offsetY | 垂直跳转偏移量',
},
condition: hideProp,
name: 'offsetY',
defaultValue: 0,
setter: { componentName: 'NumberSetter', isRequired: false, initialValue: 0 },
},
{
title: {
label: { type: 'i18n', 'en-US': 'scrollTop', 'zh-CN': '自定义滚动到页首的方' },
tip: 'scrollTop | 自定义滚动到页首的方法',
},
condition: hideProp,
name: 'scrollTop',
setter: { componentName: 'FunctionSetter', isRequired: false },
},
],
},
};
const snippets: Snippet[] = [
{
title: '电梯表单',
screenshot:
'https://img.alicdn.com/imgextra/i1/O1CN01jnfLpK1rFJ4nPj9Pt_!!6000000005601-55-tps-56-56.svg',
schema: {
componentName: 'AnchorForm',
props: {
showAnchor: true,
anchorProps: {
direction: 'hoz',
},
},
children: [
{
componentName: 'ChildForm',
props: {
columns: 2,
mode: 'independent',
anchorItemProps: {
htmlId: mockId(),
label: 'Tab1',
},
cardSectionProps: {
noBullet: true,
},
operationConfig: {},
labelCol: {
fixedSpan: 4,
},
labelAlign: 'top',
},
children: [...new Array(4).keys()].map(() => ({
componentName: 'FormInput',
props: {
formItemProps: {
primaryKey: mockId(),
label: '表单项',
size: 'medium',
device: 'desktop',
fullWidth: true,
},
placeholder: '请输入',
},
})),
},
{
componentName: 'ChildForm',
props: {
mode: 'independent',
anchorItemProps: {
htmlId: mockId(),
label: 'Tab2',
},
cardSectionProps: {
noBullet: true,
},
columns: 2,
operationConfig: {},
labelCol: {
fixedSpan: 4,
},
labelAlign: 'top',
},
children: [...new Array(4).keys()].map(() => ({
componentName: 'FormInput',
props: {
formItemProps: {
primaryKey: mockId(),
label: '表单项',
size: 'medium',
device: 'desktop',
fullWidth: true,
},
placeholder: '请输入',
},
})),
},
{
componentName: 'ChildForm',
props: {
mode: 'independent',
anchorItemProps: {
htmlId: mockId(),
label: 'Tab3',
},
cardSectionProps: {
noBullet: true,
},
columns: 2,
operationConfig: {},
labelCol: {
fixedSpan: 4,
},
labelAlign: 'top',
},
children: [...new Array(4).keys()].map(() => ({
componentName: 'FormInput',
props: {
formItemProps: {
primaryKey: mockId(),
label: '表单项',
size: 'medium',
device: 'desktop',
fullWidth: true,
},
placeholder: '请输入',
},
})),
},
{
componentName: 'ChildForm',
props: {
mode: 'independent',
anchorItemProps: {
htmlId: mockId(),
label: 'Tab4',
},
cardSectionProps: {
noBullet: true,
},
columns: 2,
operationConfig: {},
labelCol: {
fixedSpan: 4,
},
labelAlign: 'top',
},
children: [...new Array(4).keys()].map(() => ({
componentName: 'FormInput',
props: {
formItemProps: {
primaryKey: mockId(),
label: '表单项',
size: 'medium',
device: 'desktop',
fullWidth: true,
},
placeholder: '请输入',
},
})),
},
],
},
},
];
export default {
...AnchorFormMeta,
snippets,
};
================================================
FILE: packages/fusion-ui/lowcode/area-chart/meta.ts
================================================
import { IPublicTypeComponentMetadata, IPublicTypeSnippet } from '@alilc/lowcode-types';
import { actionConfigure } from '../common/chart-action';
import { plotConfigure } from '../common/chart-plot';
const AreaChartMeta: IPublicTypeComponentMetadata = {
componentName: 'AreaChart',
title: '面积图',
category: '图表',
group: '精选组件',
docUrl: '',
screenshot: '',
devMode: 'proCode',
npm: {
package: '@alifd/fusion-ui',
version: '0.1.3-beta.3',
exportName: 'AreaChart',
main: 'lib/index.js',
destructuring: true,
subName: '',
},
configure: {
props: [
// 数据
{
name: 'data',
type: 'group',
display: 'accordion',
title: {
label: '数据',
},
items: [
{
name: 'data',
title: '图表数据',
setter: 'JsonSetter',
},
{
name: 'xField',
title: {
label: 'x轴字段名',
tip: 'x 方向映射对应的数据字段名',
},
setter: 'StringSetter',
},
{
name: 'yField',
title: {
label: 'y轴字段名',
tip: 'y 方向映射所对应的数据字段名',
},
setter: 'StringSetter',
},
],
},
// 图形属性
{
name: '',
type: 'group',
display: 'accordion',
title: {
label: '图形属性',
},
items: [
{
name: 'color',
title: '颜色',
setter: 'ColorSetter',
},
{
name: 'line.size',
title: '粗细',
setter: 'NumberSetter',
},
{
name: 'smooth',
title: '平滑',
setter: 'BoolSetter',
},
{
name: 'point.visible',
title: '显示点',
setter: 'BoolSetter',
},
{
name: 'label.visible',
title: '显示标签',
setter: 'BoolSetter',
},
],
},
...plotConfigure,
...actionConfigure,
],
},
};
const snippets: IPublicTypeSnippet[] = [
{
title: '面积图',
screenshot:
'https://img.alicdn.com/imgextra/i2/O1CN012P76ko1dqUbwwmuF8_!!6000000003787-55-tps-56-56.svg',
schema: {
componentName: 'AreaChart',
props: {
data: [
{ year: '1991', value: 72345678 },
{ year: '1992', value: 4321132 },
{ year: '1993', value: 33121112.5 },
{ year: '1994', value: 45227221 },
{ year: '1995', value: 4321221.9 },
{ year: '1996', value: 6322121 },
{ year: '1997', value: 78312213 },
{ year: '1998', value: 4192312 },
{ year: '1999', value: 6212332 },
{ year: '2000', value: 3192312 },
],
xField: 'year',
yField: 'value',
color: '#0079f2',
label: {
visible: true,
},
},
},
},
];
export default {
...AreaChartMeta,
snippets,
};
================================================
FILE: packages/fusion-ui/lowcode/bar-chart/meta.ts
================================================
import { IPublicTypeComponentMetadata, IPublicTypeSnippet } from '@alilc/lowcode-types';
import { actionConfigure } from '../common/chart-action';
import { plotConfigure } from '../common/chart-plot';
const BarChartMeta: IPublicTypeComponentMetadata = {
componentName: 'BarChart',
title: '条形图',
category: '图表',
group: '精选组件',
docUrl: '',
screenshot: '',
devMode: 'proCode',
npm: {
package: '@alifd/fusion-ui',
version: '0.1.3-beta.3',
exportName: 'BarChart',
main: 'lib/index.js',
destructuring: true,
subName: '',
},
configure: {
props: [
// 数据
{
name: 'data',
type: 'group',
display: 'accordion',
title: {
label: '数据',
},
items: [
{
name: 'data',
title: '图表数据',
setter: 'JsonSetter',
},
{
name: 'xField',
title: {
label: 'x轴字段名',
tip: 'x 方向映射对应的数据字段名',
},
setter: 'StringSetter',
},
{
name: 'yField',
title: {
label: 'y轴字段名',
tip: 'y 方向映射所对应的数据字段名',
},
setter: 'StringSetter',
},
],
},
// 图形属性
{
name: '',
type: 'group',
display: 'accordion',
title: {
label: '图形属性',
},
items: [
{
name: 'color',
title: '颜色',
setter: 'ColorSetter',
},
{
name: 'barSize',
title: '粗细',
setter: 'NumberSetter',
},
{
name: 'label',
type: 'group',
display: 'accordion',
title: {
label: '标签',
},
items: [
{
name: 'label.visible',
title: '显示',
setter: 'BoolSetter',
},
{
name: 'label.position',
title: '位置',
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{ title: '左', value: 'left' },
{ title: '中', value: 'middle' },
{ title: '右', value: 'right' },
],
},
},
condition: (target) => {
return !!target.getProps().getPropValue('label.visible');
},
},
],
},
],
},
...plotConfigure,
...actionConfigure,
],
},
};
const snippets: IPublicTypeSnippet[] = [
{
title: '条形图',
screenshot:
'https://img.alicdn.com/imgextra/i3/O1CN01cOF2841sYpZkxzCsv_!!6000000005779-55-tps-56-56.svg',
schema: {
componentName: 'BarChart',
props: {
data: [
{ year: '1991', value: 72345678 },
{ year: '1992', value: 4321132 },
{ year: '1993', value: 33121112.5 },
{ year: '1994', value: 45227221 },
{ year: '1995', value: 4321221.9 },
{ year: '1996', value: 6322121 },
{ year: '1997', value: 78312213 },
{ year: '1998', value: 4192312 },
{ year: '1999', value: 6212332 },
{ year: '2000', value: 3192312 },
],
xField: 'value',
yField: 'year',
color: '#0079f2',
label: {
visible: true,
position: 'middle',
},
},
},
},
];
export default {
...BarChartMeta,
snippets
};
================================================
FILE: packages/fusion-ui/lowcode/cascader-select/meta.js
================================================
import { wrapFormItemProps } from '../utils/form-utils';
export default {
componentName: 'FormCascaderSelect',
isFormItemComponent: true,
title: '级联选择器',
docUrl: '',
screenshot: '',
npm: {
package: '@alifd/fusion-ui',
version: '{{version}}',
exportName: 'FormCascaderSelect',
main: '',
destructuring: true,
subName: '',
},
props: [
{
name: 'prefix',
propType: 'string',
defaultValue: 'next-',
},
{
name: 'label',
title: {
label: 'label',
tip: '自定义内联 label',
},
propType: 'string',
description: '自定义内联 label',
},
{
name: 'className',
propType: 'string',
},
{
name: 'size',
propType: {
type: 'oneOf',
value: ['small', 'medium', 'large'],
},
description: '大小',
defaultValue: 'medium',
},
{
name: 'placeholder',
propType: 'string',
description: '占位符',
},
{
name: 'dataSource',
propType: {
type: 'arrayOf',
value: 'object',
},
},
{
name: 'disabled',
propType: 'bool',
description: '是否禁用',
defaultValue: false,
},
{
name: 'hasArrow',
propType: 'bool',
description: '下拉箭头',
defaultValue: true,
},
{
name: 'hasBorder',
propType: 'bool',
description: '边框',
defaultValue: true,
},
{
name: 'hasClear',
propType: 'bool',
description: '清除按钮',
defaultValue: false,
},
{
name: 'notFoundContent',
title: {
label: '无数据时显示内容',
tip: 'notFoundContent',
},
propType: {
type: 'oneOfType',
value: ['node', 'string'],
},
description: '无数据时显示内容',
defaultValue: 'Not Found',
},
{
name: 'loadData',
propType: 'func',
description: '异步加载数据函数\n@param {Object} data 当前点击异步加载的数据',
},
{
name: 'header',
propType: 'node',
description: '自定义下拉框头部',
},
{
name: 'footer',
propType: 'node',
description: '自定义下拉框底部',
},
{
name: 'defaultVisible',
title: {
label: '初始下拉框是否显示',
tip: 'defaultVisible',
},
propType: 'bool',
description: '初始下拉框是否显示',
defaultValue: false,
},
{
name: 'visible',
title: {
label: '当前下拉框是否显示',
tip: 'visible',
},
propType: 'bool',
description: '当前下拉框是否显示',
},
{
name: 'readOnly',
propType: 'bool',
description: '是否只读',
},
{
name: 'onChange',
propType: 'func',
description:
'选中值改变时触发的回调函数\n@param {String|Array} value 选中的值,单选时返回单个值,多选时返回数组\n@param {Object|Array} data 选中的数据,包括 value 和 label,单选时返回单个值,多选时返回数组,父子节点选中关联时,同时选中,只返回父节点\n@param {Object} extra 额外参数\n@param {Array} extra.selectedPath 单选时选中的数据的路径\n@param {Boolean} extra.checked 多选时当前的操作是选中还是取消选中\n@param {Object} extra.currentData 多选时当前操作的数据\n@param {Array} extra.checkedData 多选时所有被选中的数据\n@param {Array} extra.indeterminateData 多选时半选的数据',
},
{
name: 'expandTriggerType',
propType: {
type: 'oneOf',
value: ['click', 'hover'],
},
description: '展开触发方式',
defaultValue: 'click',
},
{
name: 'onExpand',
propType: 'func',
},
{
name: 'useVirtual',
propType: 'bool',
description: '虚拟滚动',
defaultValue: false,
},
{
name: 'multiple',
propType: 'bool',
description: '是否多选',
defaultValue: false,
},
{
name: 'changeOnSelect',
title: {
label: '选中即改变',
tip: 'changeOnSelect|是否选中即发生改变, 该属性仅在单选模式下有效',
},
propType: 'bool',
description: '是否选中即发生改变, 该属性仅在单选模式下有效',
defaultValue: false,
},
{
name: 'canOnlyCheckLeaf',
title: {
label: 'canOnlyCheckLeaf',
tip: '是否只能勾选叶子项的checkbox,该属性仅在多选模式下有效',
},
propType: 'bool',
description: '是否只能勾选叶子项的checkbox,该属性仅在多选模式下有效',
defaultValue: false,
},
{
name: 'checkStrictly',
title: {
label: 'checkStrictly',
tip: '父子节点是否选中不关联',
},
propType: 'bool',
description: '父子节点是否选中不关联',
defaultValue: false,
},
{
name: 'listStyle',
propType: 'object',
description: '每列列表样式对象',
},
{
name: 'resultAutoWidth',
title: {
label: 'resultAutoWidth',
tip: '搜索结果列表是否和选择框等宽',
},
propType: 'bool',
description: '搜索结果列表是否和选择框等宽',
defaultValue: true,
},
{
name: 'showSearch',
propType: 'bool',
description: '搜索框',
defaultValue: false,
},
{
name: 'filter',
propType: 'func',
description:
'自定义搜索函数\n@param {String} searchValue 搜索的关键字\n@param {Array} path 节点路径\n@return {Boolean} 是否匹配\n@default 根据路径所有节点的文本值模糊匹配',
},
{
name: 'onVisibleChange',
propType: 'func',
description:
'下拉框显示或关闭时触发事件的回调函数\n@param {Boolean} visible 是否显示\n@param {String} type 触发显示关闭的操作类型, fromTrigger 表示由trigger的点击触发; docClick 表示由document的点击触发',
},
{
name: 'popupStyle',
propType: 'object',
description: '下拉框自定义样式对象',
},
{
name: 'popupProps',
propType: 'object',
description: '透传到 Popup 的属性对象',
},
{
name: 'followTrigger',
title: {
label: '是否跟随滚动',
tip: 'followTrigger',
},
propType: 'bool',
description: '是否跟随滚动',
},
{
name: 'isPreview',
title: {
label: '是否为预览态',
tip: 'isPreview',
},
propType: 'bool',
description: '是否为预览态',
},
{
name: 'style',
propType: 'object',
},
{
name: 'popupContainer',
propType: 'any',
description: '弹层容器\n@param {Element} target 目标元素\n@return {Element} 弹层的容器元素',
},
],
configure: {
supports: {
style: true,
events: ['onChange', 'onExpand', 'onVisibleChange'],
},
props: wrapFormItemProps([
{
name: 'label',
title: {
label: '内联文案',
tip: '自定义内联 label',
},
setter: 'StringSetter',
},
{
name: 'size',
title: '尺寸',
setter: {
componentName: 'RadioGroupSetter',
props: { options: ['small', 'medium', 'large'] },
},
defaultValue: 'medium',
},
{
name: 'placeholder',
title: '占位提示',
setter: 'StringSetter',
},
{
name: 'dataSource',
title: '级联数据',
setter: 'JsonSetter',
},
{
name: 'disabled',
setter: 'BoolSetter',
title: '是否禁用',
defaultValue: false,
},
{
name: 'hasArrow',
setter: 'BoolSetter',
title: '下拉箭头',
defaultValue: true,
},
{
name: 'hasBorder',
setter: 'BoolSetter',
title: '边框',
defaultValue: true,
},
{
name: 'hasClear',
setter: 'BoolSetter',
title: '清除按钮',
defaultValue: false,
},
{
name: 'readOnly',
setter: 'BoolSetter',
title: '是否只读',
},
{
name: 'multiple',
setter: 'BoolSetter',
title: '是否多选',
defaultValue: false,
},
{
name: 'showSearch',
setter: 'BoolSetter',
title: '搜索框',
defaultValue: false,
},
{
name: 'followTrigger',
title: {
label: '跟随滚动',
tip: 'followTrigger',
},
setter: 'BoolSetter',
description: '是否跟随滚动',
},
{
name: 'isPreview',
title: {
label: '预览态',
tip: 'isPreview',
},
setter: 'BoolSetter',
description: '是否为预览态',
},
{
name: 'expandTriggerType',
display: 'block',
setter: {
componentName: 'RadioGroupSetter',
props: { options: ['click', 'hover'] },
},
title: '展开触发方式',
defaultValue: 'click',
},
{
name: 'notFoundContent',
display: 'block',
title: {
label: '无数据时显示内容',
tip: 'notFoundContent',
},
setter: {
componentName: 'MixedSetter',
props: {
setters: ['StringSetter', 'SlotSetter'],
},
},
defaultValue: 'Not Found',
},
{
type: 'group',
title: '高级',
display: 'block',
items: [
{
name: 'id',
title: {
label: {
type: 'i18n',
zh_CN: '唯一标识',
en_US: 'ID',
},
tip: {
type: 'i18n',
zh_CN: '属性: id | 说明: 唯一标识',
en_US: 'prop: id | description: switch id',
},
},
setter: 'StringSetter',
},
{
name: 'name',
title: {
label: {
type: 'i18n',
zh_CN: '表单标识',
en_US: 'Name',
},
tip: {
type: 'i18n',
zh_CN: '属性: name | 说明: 表单标识',
en_US: 'prop: name | description: switch name',
},
},
setter: 'StringSetter',
},
],
},
]),
},
icon: '',
category: '内容',
};
================================================
FILE: packages/fusion-ui/lowcode/cascader-select/snippets.js
================================================
module.exports = [
{
title: '收起模式',
screenshot:
'https://alifd.oss-cn-hangzhou.aliyuncs.com/fusion-cool/icons/icon-light/ic_light_cascader-select.png',
schema: {
componentName: 'CascaderSelect',
props: {
prefix: 'next-',
size: 'medium',
hasArrow: true,
hasBorder: true,
expandTriggerType: 'click',
resultAutoWidth: true,
notFoundContent: 'Not Found',
dataSource: [
{
value: '2974',
label: '西安',
children: [
{
value: '2975',
label: '西安市',
},
{
value: '2976',
label: '高陵县',
},
{
value: '2977',
label: '蓝田县',
},
],
},
],
},
},
},
{
title: '展开模式',
screenshot:
'https://alifd.oss-cn-hangzhou.aliyuncs.com/fusion-cool/icons/icon-light/ic_light_cascader.png',
schema: {
componentName: 'Cascader',
props: {
prefix: 'next-',
expandTriggerType: 'click',
dataSource: [
{
value: '2974',
label: '西安',
children: [
{
value: '2975',
label: '西安市',
},
{
value: '2976',
label: '高陵县',
},
{
value: '2977',
label: '蓝田县',
},
],
},
],
},
},
},
];
================================================
FILE: packages/fusion-ui/lowcode/checkbox-group/meta.js
================================================
import { wrapFormItemProps } from '../utils/form-utils';
export default {
componentName: 'FormCheckboxGroup',
isFormItemComponent: true,
title: '复选按钮组',
docUrl: '',
screenshot: '',
npm: {
package: '@alifd/fusion-ui',
version: '{{version}}',
exportName: 'FormCheckboxGroup',
main: '',
destructuring: true,
subName: '',
},
configure: {
props: wrapFormItemProps([
{
name: 'disabled',
title: '是否禁用',
setter: {
componentName: 'MixedSetter',
props: {
setters: ['BoolSetter', 'ExpressionSetter'],
},
},
},
{
name: 'itemDirection',
title: '排列方式',
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{ title: '水平排列', value: 'hoz' },
{ title: '垂直排列', value: 'ver' },
],
},
},
defaultValue: 'hoz',
},
{
name: 'isPreview',
title: '预览态',
setter: {
componentName: 'BoolSetter',
},
},
{
name: 'defaultValue',
title: '默认值',
defaultValue: '[]',
setter: {
componentName: 'MixedSetter',
props: {
setters: ['JsonSetter', 'ExpressionSetter'],
},
},
},
{
name: 'dataSource',
display: 'block',
title: '选项',
setter: {
componentName: 'MixedSetter',
props: {
setters: [
{
componentName: 'ArraySetter',
props: {
itemSetter: {
componentName: 'ObjectSetter',
props: {
config: {
items: [
{
name: 'label',
title: 'label',
setter: 'StringSetter',
},
{
name: 'value',
title: 'value',
setter: 'StringSetter',
},
],
},
},
initialValue: {
label: '选项一',
value: '1',
},
},
},
},
'ExpressionSetter',
],
},
},
},
{
type: 'group',
title: '高级',
display: 'block',
items: [
{
name: 'id',
title: {
label: {
type: 'i18n',
zh_CN: '唯一标识',
en_US: 'ID',
},
tip: {
type: 'i18n',
zh_CN: '属性: id | 说明: 唯一标识',
en_US: 'prop: id | description: switch id',
},
},
setter: 'StringSetter',
},
{
name: 'name',
title: {
label: {
type: 'i18n',
zh_CN: '表单标识',
en_US: 'Name',
},
tip: {
type: 'i18n',
zh_CN: '属性: name | 说明: 表单标识',
en_US: 'prop: name | description: switch name',
},
},
setter: 'StringSetter',
},
],
},
// {
// name: "renderPreview",
// title: "预览态模式下渲染的内容",
// display: "block",
// setter: {
// componentName: "FunctionSetter"
// },
// condition(target) {
// return target.getProps().getPropValue("isPreview") || false;
// }
// }
]),
supports: {
style: true,
events: ['onChange'],
},
advanced: {
initials: [
{
name: 'dataSource',
initial: () => {
return [
{
label: '选项一',
value: '1',
},
{
label: '选项二',
value: '2',
},
{
label: '选项三',
value: '3',
},
];
},
},
],
},
},
icon: '',
category: '内容',
};
================================================
FILE: packages/fusion-ui/lowcode/child-form/meta.ts
================================================
import { ComponentMetadata, Snippet } from '@ali/lowcode-types';
import { default as formBaseProps } from '../pro-form/common/form-base-props';
const ChildFormMeta: ComponentMetadata = {
componentName: 'ChildForm',
title: '子表单',
docUrl: '',
screenshot: '',
category: '表单类',
group: '精选组件',
devMode: 'proCode',
hidden: true,
npm: {
package: '@alifd/fusion-ui',
version: '0.1.6-beta.24',
exportName: 'ChildForm',
main: 'lib/index.js',
destructuring: true,
subName: '',
},
configure: {
props: formBaseProps,
supports: {
className: true,
style: true,
},
component: {
isContainer: true,
isMinimalRenderUnit: true,
nestingRule: {
childWhitelist: new RegExp('form.*', 'i'),
},
},
},
};
const snippets: Snippet[] = [
{
title: '子表单',
screenshot:
'https://img.alicdn.com/imgextra/i1/O1CN01MJT0lc1pXVaHIcoBy_!!6000000005370-55-tps-56-56.svg',
schema: {
componentName: 'ChildForm',
props: {
primaryKey: String(Math.floor(Math.random() * 10000)),
placeholder: '请在右侧面板添加表单项+',
placeholderStyle: {
height: '38px',
color: '#0088FF',
background: '#d8d8d836',
border: 0,
gridArea: 'span 4 / span 4',
},
columns: 3,
labelCol: {
fixedSpan: 4,
},
labelAlign: 'top',
emptyContent: '添加表单项',
},
children: [...new Array(3).keys()].map((item) => ({
componentName: 'FormInput',
props: {
formItemProps: {
primaryKey: String(Math.floor(Math.random() * 10000) + item),
label: '表单项',
size: 'medium',
device: 'desktop',
fullWidth: true,
},
placeholder: '请输入',
},
})),
},
},
];
export default {
...ChildFormMeta,
snippets,
};
================================================
FILE: packages/fusion-ui/lowcode/column-chart/meta.ts
================================================
import { IPublicTypeComponentMetadata, IPublicTypeSnippet } from '@alilc/lowcode-types';
import { actionConfigure } from '../common/chart-action';
import { plotConfigure } from '../common/chart-plot';
const ColumnChartMeta: IPublicTypeComponentMetadata = {
componentName: 'ColumnChart',
title: '柱状图',
category: '图表',
group: '精选组件',
docUrl: '',
screenshot: '',
devMode: 'proCode',
npm: {
package: '@alifd/fusion-ui',
version: '0.1.3-beta.3',
exportName: 'ColumnChart',
main: 'lib/index.js',
destructuring: true,
subName: '',
},
configure: {
props: [
// 数据
{
name: 'data',
type: 'group',
display: 'accordion',
title: {
label: '数据',
},
items: [
{
name: 'data',
title: '图表数据',
setter: 'JsonSetter',
},
{
name: 'xField',
title: {
label: 'x轴字段名',
tip: 'x 方向映射对应的数据字段名',
},
setter: 'StringSetter',
},
{
name: 'yField',
title: {
label: 'y轴字段名',
tip: 'y 方向映射所对应的数据字段名',
},
setter: 'StringSetter',
},
],
},
// 图形属性
{
name: '',
type: 'group',
display: 'accordion',
title: {
label: '图形属性',
},
items: [
{
name: 'color',
title: '颜色',
setter: 'ColorSetter',
},
{
name: 'columnSize',
title: '粗细',
setter: 'NumberSetter',
},
{
name: 'label',
type: 'group',
display: 'accordion',
title: {
label: '标签',
},
items: [
{
name: 'label.visible',
title: '显示',
setter: 'BoolSetter',
},
{
name: 'label.position',
title: '位置',
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{ title: '上', value: 'top' },
{ title: '中', value: 'middle' },
{ title: '下', value: 'bottom' },
],
},
},
condition: (target) => {
return !!target.getProps().getPropValue('label.visible');
},
},
],
},
],
},
...plotConfigure,
...actionConfigure,
],
},
};
const snippets: IPublicTypeSnippet[] = [
{
title: '柱状图',
screenshot:
'https://img.alicdn.com/imgextra/i1/O1CN01mz7siK1JIn9XZmCF6_!!6000000001006-55-tps-56-56.svg',
schema: {
componentName: 'ColumnChart',
props: {
data: [
{ year: '1991', value: 72345678 },
{ year: '1992', value: 4321132 },
{ year: '1993', value: 33121112.5 },
{ year: '1994', value: 45227221 },
{ year: '1995', value: 4321221.9 },
{ year: '1996', value: 6322121 },
{ year: '1997', value: 78312213 },
{ year: '1998', value: 4192312 },
{ year: '1999', value: 6212332 },
{ year: '2000', value: 3192312 },
],
xField: 'year',
yField: 'value',
color: '#0079f2',
label: {
visible: true,
position: 'middle',
},
// data: [
// {
// name: 'London',
// 月份: 'Jan.',
// 月均降雨量: 18.9,
// },
// {
// name: 'London',
// 月份: 'Feb.',
// 月均降雨量: 28.8,
// },
// {
// name: 'London',
// 月份: 'Mar.',
// 月均降雨量: 39.3,
// },
// {
// name: 'London',
// 月份: 'Apr.',
// 月均降雨量: 81.4,
// },
// {
// name: 'London',
// 月份: 'May',
// 月均降雨量: 47,
// },
// {
// name: 'London',
// 月份: 'Jun.',
// 月均降雨量: 20.3,
// },
// {
// name: 'London',
// 月份: 'Jul.',
// 月均降雨量: 24,
// },
// {
// name: 'London',
// 月份: 'Aug.',
// 月均降雨量: 35.6,
// },
// {
// name: 'Berlin',
// 月份: 'Jan.',
// 月均降雨量: 12.4,
// },
// {
// name: 'Berlin',
// 月份: 'Feb.',
// 月均降雨量: 23.2,
// },
// {
// name: 'Berlin',
// 月份: 'Mar.',
// 月均降雨量: 34.5,
// },
// {
// name: 'Berlin',
// 月份: 'Apr.',
// 月均降雨量: 99.7,
// },
// {
// name: 'Berlin',
// 月份: 'May',
// 月均降雨量: 52.6,
// },
// {
// name: 'Berlin',
// 月份: 'Jun.',
// 月均降雨量: 35.5,
// },
// {
// name: 'Berlin',
// 月份: 'Jul.',
// 月均降雨量: 37.4,
// },
// {
// name: 'Berlin',
// 月份: 'Aug.',
// 月均降雨量: 42.4,
// },
// ],
// xField: '月份',
// yField: '月均降雨量',
// seriesField: 'name',
// legend: {
// position: 'top-left',
// }
},
},
},
];
export default {
...ColumnChartMeta,
snippets,
};
================================================
FILE: packages/fusion-ui/lowcode/common/actions.ts
================================================
export const commonActions = [
{
name: 'actionType',
title: '操作类型',
display: 'inline',
editable: true,
initialValue: 'link',
setter: {
componentName: 'SelectSetter',
props: {
options: [
{
value: 'formDialog',
title: '打开表单弹窗',
},
{
value: 'link',
title: '链接',
},
],
},
},
},
{
name: 'text',
title: '标题',
editable: true,
initialValue: '详情',
display: 'inline',
setter: {
componentName: 'TextSetter',
},
},
{
name: 'key',
title: '标识',
display: 'none',
initialValue: (currentValue, defaultValue) => {
return currentValue || defaultValue || `data-${Math.random().toString(36).substr(-6)}`;
},
setter: {
componentName: 'TextSetter',
},
},
{
name: '_redirect_url',
title: '跳转页面',
display: 'inline',
accessor() {
const _redirect = this.parent.getParam('_redirect').getValue() || {};
return _redirect.url;
},
mutator(value) {
this.parent.getParam('_redirect').setValue({
externalLink: true,
openType: 'current',
url: value,
});
},
setter() {
const pages = this.node.getProp('_pages_').getValue();
const data = pages.map((item) => {
return {
title: item.title.zh_CN,
value: `/${item.navUuid}`,
};
});
return {
componentName: 'SelectSetter',
props: {
options: data,
},
};
},
hidden() {
return this.parent.getParam('actionType').getValue() !== 'link';
},
},
{
name: '_redirect',
title: '跳转页面',
display: 'none',
hidden: true,
},
{
title: '关联弹窗',
name: '_bindFormDialog',
display: 'inline',
hidden() {
const actionType = this.parent.getParam('actionType').toData();
return actionType !== 'formDialog';
},
setter() {
// 兼容Vision低版本
const nodeDocument = this.node.document || this.node.page;
const { nodeList } = nodeDocument.getRootNodeVisitor('NodeCache');
const options = nodeList
.filter((x) => x.componentName.includes('Dialog'))
.map((x) => ({
title:
x.propsData && x.propsData.title
? `${x.propsData.title}(${x.id})`
: `${x.id}(${x.componentName})`,
value: x.id,
}));
return {
componentName: 'SelectSetter',
props: {
options,
hasClear: true,
},
};
},
},
];
================================================
FILE: packages/fusion-ui/lowcode/common/button-groups.ts
================================================
import { IProps } from '../types/index';
import { hideProp } from '../utils';
export const buttonConfigureProps: IProps[] = [
{
name: 'children',
title: '名称',
display: 'inline',
initialValue: '操作',
isRequired: true,
setter: 'StringSetter',
},
{
name: 'type',
title: '按钮样式',
display: 'inline',
isRequired: true,
initialValue: 'primary',
setter: {
componentName: 'SelectSetter',
props: {
options: [
{
title: '普通按钮',
value: 'normal',
},
{
title: '主按钮',
value: 'primary',
},
{
title: '次按钮',
value: 'secondary',
},
],
},
},
},
{
name: 'key',
title: '标识',
condition: hideProp,
initialValue: (currentValue, defaultValue) =>
currentValue || defaultValue || `data-${Math.random().toString(36).substr(-6)}`,
setter: {
componentName: 'StringSetter',
},
},
{
name: 'disabled',
title: '是否禁用',
display: 'inline',
initialValue: false,
setter: 'BoolSetter',
},
{
name: 'hidden',
title: '是否隐藏',
display: 'inline',
initialValue: false,
setter: 'BoolSetter',
},
{
name: 'actionType',
title: '操作类型(TODO)',
condition: hideProp,
display: 'inline',
initialValue: 'batch',
setter: {
componentName: 'SelectSetter',
props: {
options: [
// {
// title: '批量',
// value: 'batch',
// },
{
title: '表单弹窗',
value: 'formDialog',
},
{
title: '链接',
value: 'link',
},
{
title: '导入',
value: 'import',
},
// {
// title: '同步',
// value: 'sync',
// },
{
title: '导出',
value: 'export',
},
// {
// title: '解析导出',
// value: 'analysisExport',
// },
],
},
},
},
{
name: 'onClick',
title: '点击事件',
setter: 'FunctionSetter',
},
];
export const buttonGroupConfigureProp: IProps = {
type: 'field',
name: 'buttonGroup',
title: '按钮组',
extraProps: {
display: 'accordion',
},
setter: {
componentName: 'ObjectSetter',
props: {
config: {
items: [
{
name: 'text',
title: {
label: '文字模式',
tip: '是否设定按钮为文字模式',
},
setter: 'BoolSetter',
},
{
name: 'visibleButtonCount',
title: {
label: '可见数量',
tip: '超过会收起到”更多“菜单中',
},
extraProps: {
defaultValue: 3,
},
setter: {
componentName: 'NumberSetter',
props: {
max: 6,
min: 1,
},
},
},
{
name: 'dataSource',
title: '按钮组',
extraProps: {
display: 'plain',
},
setter: {
componentName: 'ArraySetter',
props: {
hideDescription: true,
itemSetter: {
componentName: 'ObjectSetter',
props: {
config: {
items: buttonConfigureProps,
},
},
initialValue: () => ({
children: '操作',
type: 'normal',
}),
},
},
},
},
],
},
},
},
};
================================================
FILE: packages/fusion-ui/lowcode/common/chart-action.ts
================================================
import { IPublicTypeConfigure } from '@alilc/lowcode-types';
export const actionConfigure: NonNullable = [
{
type: 'field',
name: 'cardProps.actionButtons',
title: '操作配置',
extraProps: {
display: 'accordion',
},
setter: {
componentName: 'ArraySetter',
props: {
itemSetter: {
componentName: 'ObjectSetter',
props: {
config: {
items: [
{
name: 'children',
title: '名称',
display: 'inline',
initialValue: '操作',
important: true,
setter: 'StringSetter',
},
{
name: 'onClick',
title: '点击事件',
display: 'inline',
important: true,
setter: 'FunctionSetter',
},
],
},
},
initialValue: () => {
return {
children: '操作',
};
},
},
},
},
},
{
name: 'cardProps.text',
title: {
label: '文字模式',
tip: '是否设定按钮为文字模式',
},
setter: 'BoolSetter',
},
{
name: 'cardProps.visibleButtonCount',
title: {
label: '可见数量',
tip: '超过会收起到”更多“菜单中',
},
extraProps: {
defaultValue: 3,
},
setter: {
componentName: 'NumberSetter',
props: {
max: 6,
min: 1,
},
},
},
];
================================================
FILE: packages/fusion-ui/lowcode/common/chart-plot.ts
================================================
import { IPublicTypeConfigure } from '@alilc/lowcode-types';
export const plotConfigure: NonNullable = [
{
name: 'autoFit',
title: '自适应宽高',
display: 'block',
defaultValue: true,
setter: 'BoolSetter',
},
{
name: 'height',
title: '高度',
display: "block",
defaultValue: 300,
setter: {
componentName: 'NumberSetter',
},
}
];
================================================
FILE: packages/fusion-ui/lowcode/common/index.ts
================================================
export * from './actions';
export * from './chart-action';
export * from './operations';
================================================
FILE: packages/fusion-ui/lowcode/common/operations.ts
================================================
import { IProps } from '../types';
import { hideProp } from '../utils';
import { IPublicModelSettingField } from '@alilc/lowcode-types';
export const operationConfig: IProps = {
name: 'operationConfig',
display: 'accordion',
title: '底部操作',
setter: {
componentName: 'ObjectSetter',
props: {
config: {
items: [
{
name: 'visibleButtonCount',
title: {
label: '可见数量',
tip: '超过会收起到”更多“菜单中',
},
extraProps: {
defaultValue: 3,
},
setter: {
componentName: 'NumberSetter',
props: {
max: 6,
min: 1,
},
},
},
{
name: 'fixed',
title: '吸底',
setter: 'BoolSetter',
},
{
name: 'showSaveTime',
title: '显示时间',
setter: {
componentName: 'BoolSetter',
},
},
{
name: 'align',
title: '布局',
defaultValue: 'center',
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{
title: '居左',
value: 'left',
},
{
title: '居中',
value: 'center',
},
{
title: '居右',
value: 'right',
},
],
},
},
},
],
},
},
},
};
export const operations: IProps = {
name: 'operations',
display: 'block',
title: '操作项',
getValue: (target, value) => {
return value || [];
},
setter: {
componentName: 'MixedSetter',
props: {
setters: [
{
componentName: 'SlotSetter',
defaultValue: {
type: 'JSSlot',
value: [],
},
},
{
componentName: 'ArraySetter',
props: {
itemSetter: {
componentName: 'ObjectSetter',
props: {
config: {
items: [
{
name: 'id',
condition: hideProp,
setter: (target: IPublicModelSettingField) => {
if (!target.getValue()) {
target.setValue(`${target.id}`);
}
return 'StringSetter';
},
},
{
name: 'content',
display: 'inline',
title: '文本',
setter: 'StringSetter',
important: true,
},
{
name: 'action',
display: 'inline',
title: '操作',
important: true,
setValue: (target: IPublicModelSettingField, value: any) => {
const actionNameMap: any = {
submit: '提交',
reset: '重置',
custom: '自定义',
};
const actionName = actionNameMap[value] || '自定义';
target.parent.setPropValue('content', actionName);
},
setter: {
componentName: 'SelectSetter',
props: {
options: [
{
title: '提交',
value: 'submit',
},
{
title: '重置',
value: 'reset',
},
{
title: '自定义',
value: 'custom',
},
],
},
},
},
{
name: 'type',
display: 'inline',
title: '样式',
important: true,
setter: {
componentName: 'SelectSetter',
props: {
options: [
{
title: '主要',
value: 'primary',
},
{
title: '次要',
value: 'secondary',
},
{
title: '普通',
value: 'normal',
},
],
},
},
},
{
name: 'behavior',
title: '交互设置',
display: 'block',
condition: (target: IPublicModelSettingField) => {
const action = target.parent.getPropValue('action');
return !action || action === 'custom';
},
setter: {
componentName: 'BehaviorSetter',
props: (target: IPublicModelSettingField) => ({
actions: ['onClick'],
enableTooltipAction: true,
enableMessageAction: true,
extendedOptions: {
tooltip: {
id: target.parent.getPropValue('id'),
defaultTriggerType: 'click',
},
message: {
types: ['notice', 'success', 'loading', 'warning', 'error'],
defaultType: 'notice',
library: 'Next',
component: 'Message',
},
},
}),
},
},
{
name: 'onClick',
display: 'inline',
title: '点击事件',
condition: hideProp,
setter: 'FunctionSetter',
extraProps: {
supportVariable: true,
},
},
{
name: 'htmlType',
condition: hideProp,
},
{
name: '!autoSubmit',
display: 'inline',
virtual: true,
title: '自动提交',
setter: {
componentName: 'BoolSetter',
},
extraProps: {
setValue: (target: IPublicModelSettingField, value: any) => {
target.parent.setPropValue('htmlType', value ? 'submit' : '');
},
getValue: (target: IPublicModelSettingField, value: any) => {
return value === 'submit';
},
},
condition: (target: IPublicModelSettingField) => {
return target.parent.getPropValue('action') !== 'submit';
},
},
],
},
},
initialValue: () => {
return {
content: '提交',
action: 'submit',
type: 'normal',
};
},
},
},
},
],
},
},
};
export const operationProps = [operationConfig, operations];
================================================
FILE: packages/fusion-ui/lowcode/date-picker/meta.ts
================================================
import { hideProp } from '../utils';
import { wrapFormItemProps } from '../utils/form-utils';
import { IComponentDescription } from '../types';
const meta: IComponentDescription = {
componentName: 'FormDatePicker',
isFormItemComponent: true,
title: '日期选择框',
docUrl: '',
screenshot: '',
npm: {
package: '@alifd/fusion-ui',
version: '{{version}}',
exportName: 'FormDatePicker',
main: '',
destructuring: true,
subName: '',
},
configure: {
supports: {
events: ['onChange', 'onOk'],
},
props: wrapFormItemProps([
{
name: 'label',
title: {
label: '标签',
tip: 'label|表单项内置标签',
},
setter: 'StringSetter',
},
{
name: 'state',
title: {
label: '状态',
tip: 'state|表单项状态',
},
setter: {
componentName: 'RadioGroupSetter',
props: {
options: ['success', 'loading', 'error'],
},
},
},
{
name: 'placeholder',
title: {
label: '占位提示',
tip: 'placeholder|输入提示',
},
setter: 'StringSetter',
},
{
name: 'value',
title: {
label: 'value',
tip: 'value|日期值(受控)',
},
setter: 'DateSetter',
condition: hideProp,
},
{
name: 'format',
title: {
label: '格式',
tip: 'format|日期值的格式(用于限定用户输入和展示)',
},
setter: 'StringSetter',
defaultValue: 'YYYY-MM-DD',
},
{
name: 'size',
title: {
label: '尺寸',
tip: 'size|表单项尺寸',
},
setter: {
componentName: 'RadioGroupSetter',
props: {
options: ['small', 'medium', 'large'],
},
},
defaultValue: 'medium',
},
{
name: 'disabled',
title: {
label: '是否禁用',
tip: 'disabled|是否禁用',
},
setter: 'BoolSetter',
},
{
name: 'hasClear',
title: {
label: '清除按钮',
tip: 'hasClear|是否显示清空按钮',
},
setter: 'BoolSetter',
defaultValue: true,
},
{
name: 'followTrigger',
setter: 'BoolSetter',
title: '跟随滚动',
},
{
name: 'defaultValue',
title: {
label: '默认值',
tip: 'defaultValue|初始日期值,moment 对象',
},
setter: 'DateSetter',
},
{
name: 'form',
type: 'group',
title: '高级',
display: 'block',
items: [
{
name: 'id',
title: {
label: {
type: 'i18n',
zh_CN: '唯一标识',
en_US: 'ID',
},
tip: {
type: 'i18n',
zh_CN: '属性: id | 说明: 唯一标识',
en_US: 'prop: id | description: switch id',
},
},
setter: 'StringSetter',
},
{
name: 'name',
title: {
label: {
type: 'i18n',
zh_CN: '表单标识',
en_US: 'Name',
},
tip: {
type: 'i18n',
zh_CN: '属性: name | 说明: 表单标识',
en_US: 'prop: name | description: switch name',
},
},
setter: 'StringSetter',
},
],
},
]),
},
icon: '',
category: '内容',
};
export default meta;
================================================
FILE: packages/fusion-ui/lowcode/date-picker/snippets.js
================================================
module.exports = [
{
title: '日期选择框',
screenshot:
'https://alifd.oss-cn-hangzhou.aliyuncs.com/fusion-cool/icons/icon-light/ic_light_date-picker.png',
schema: {
componentName: 'DatePicker',
props: {
prefix: 'next-',
format: 'YYYY-MM-DD',
size: 'medium',
hasClear: false,
popupTriggerType: 'click',
popupAlign: 'tl tl',
followTrigger: true,
},
},
},
{
title: '日期区间',
screenshot:
'https://alifd.oss-cn-hangzhou.aliyuncs.com/fusion-cool/icons/icon-light/ic_light_date-picker.png',
schema: {
componentName: 'RangePicker',
props: {
prefix: 'next-',
format: 'YYYY-MM-DD',
size: 'medium',
type: 'date',
hasClear: false,
popupTriggerType: 'click',
popupAlign: 'tl tl',
followTrigger: true,
},
},
},
];
================================================
FILE: packages/fusion-ui/lowcode/donut-chart/meta.ts
================================================
import { IPublicTypeComponentMetadata, IPublicTypeSnippet } from '@alilc/lowcode-types';
import { actionConfigure } from '../common/chart-action';
import { plotConfigure } from '../common/chart-plot';
const DonutChartMeta: IPublicTypeComponentMetadata = {
componentName: 'DonutChart',
title: '环形图',
category: '图表',
group: '精选组件',
docUrl: '',
screenshot: '',
devMode: 'proCode',
npm: {
package: '@alifd/fusion-ui',
version: '0.1.3-beta.3',
exportName: 'DonutChart',
main: 'lib/index.js',
destructuring: true,
subName: '',
},
configure: {
props: [
// 图例
{
name: 'legend',
type: 'group',
display: 'accordion',
title: {
label: '图例',
},
items: [
{
name: 'legend.position',
title: '位置',
setter: {
componentName: 'SelectSetter',
props: {
options: [
{ title: '左', value: 'left' },
{ title: '左上', value: 'left-top' },
{ title: '左下', value: 'left-bottom' },
{ title: '右', value: 'right' },
{ title: '右上', value: 'right-top' },
{ title: '右下', value: 'right-bottom' },
{ title: '上', value: 'top' },
{ title: '上左', value: 'top-left' },
{ title: '上右', value: 'top-right' },
{ title: '下', value: 'bottom' },
{ title: '下左', value: 'bottom-left' },
{ title: '下右', value: 'bottom-right' },
],
},
},
},
],
},
// 数据
{
name: 'data',
type: 'group',
display: 'accordion',
title: {
label: '数据',
},
items: [
{
name: 'data',
title: '图表数据',
setter: 'JsonSetter',
},
{
name: 'angleField',
title: {
label: '值字段名',
tip: '扇形切片大小(弧度)所对应的数据字段名',
},
setter: 'StringSetter',
},
{
name: 'colorField',
title: {
label: '分类字段名',
tip: '扇形颜色映射对应的数据字段名',
},
setter: 'StringSetter',
},
],
},
// 图形属性
{
name: '',
type: 'group',
display: 'accordion',
title: {
label: '图形属性',
},
items: [
{
name: 'color',
title: '颜色',
setter: {
componentName: 'ArraySetter',
props: {
itemSetter: {
componentName: 'ColorSetter',
initialValue: '#0079f2',
},
},
},
},
{
name: 'label',
type: 'group',
display: 'accordion',
title: {
label: '标签',
},
items: [
{
name: 'label.visible',
title: '显示',
setter: 'BoolSetter',
},
{
name: 'label.type',
title: '位置',
setter: {
componentName: 'SelectSetter',
props: {
options: [
{ title: '内部', value: 'inner' },
{ title: '外部', value: 'outer' },
{ title: '外部圆形排布', value: 'outer-center' },
{ title: '蜘蛛布局', value: 'spider' },
],
},
},
},
],
},
],
},
...plotConfigure,
...actionConfigure,
],
},
};
const snippets: IPublicTypeSnippet[] = [
{
title: '环形图',
screenshot:
'https://img.alicdn.com/imgextra/i3/O1CN01pLbt7T1Mh0woqKEN1_!!6000000001465-55-tps-56-56.svg',
schema: {
componentName: 'DonutChart',
props: {
legend: {
position: 'top-left',
},
data: [
{ year: '1991', value: 72345678 },
{ year: '1992', value: 4321132 },
{ year: '1993', value: 33121112.5 },
{ year: '1994', value: 45227221 },
{ year: '1995', value: 4321221.9 },
{ year: '1996', value: 6322121 },
{ year: '1997', value: 78312213 },
{ year: '1998', value: 2192312 },
{ year: '1999', value: 6212332 },
{ year: '2000', value: 1192312 },
],
angleField: 'value',
colorField: 'year',
label: {
visible: true,
type: 'spider',
},
color: ['#3BCBD1', '#47A4FE', '#EDBA42', '#F4704E', '#ED6899', '#7F62C3', '#6E7BC9'],
},
},
},
];
export default {
...DonutChartMeta,
snippets,
};
================================================
FILE: packages/fusion-ui/lowcode/edit-table/meta.ts
================================================
import { IComponentDescription } from '../types/index';
import { ProTableProps } from '../pro-table/pro-table-meta';
function editTablePropsFilter(prop: any) {
const ignorePropNames: string[] = ['dataSource'];
return !ignorePropNames.includes(prop?.name);
}
const EditTableProps = ProTableProps.filter(editTablePropsFilter).map((item) => {
if (item.name === 'advanced') {
return {
type: 'group',
title: '高级',
name: 'other',
extraProps: {
display: 'accordion',
defaultCollapsed: true,
},
items: [
{
name: 'addPosition',
title: '新增行位置',
defaultValue: 'end',
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{
label: '上',
value: 'start',
},
{
label: '下',
value: 'end',
},
],
},
},
},
{
type: 'field',
name: '!选择模式',
title: '选择模式',
display: 'inline',
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{
title: '无',
value: 'none',
tip: 'none',
},
{
title: '多选',
value: 'multiple',
tip: 'multiple',
},
{
title: '单选',
value: 'single',
tip: 'single',
},
],
},
},
defaultValue: 'none',
getValue: (target) => {
const rowSelection = target.parent.getPropValue('rowSelection');
if (!rowSelection) {
return 'none';
}
return rowSelection.mode === 'single' ? 'single' : 'multiple';
},
setValue: (field, value) => {
const { node } = field;
if (['single', 'multiple'].includes(value)) {
node.setPropValue('rowSelection', {
...node.getPropValue('rowSelection'),
mode: value,
});
} else {
node.setPropValue('rowSelection', undefined);
}
},
},
{
type: 'field',
name: 'indexColumn',
title: '开启序号列',
extraProps: {
display: 'inline',
defaultValue: false,
},
setter: {
componentName: 'BoolSetter',
},
},
{
type: 'field',
name: 'settingButtons',
title: '开启设置按钮',
extraProps: {
display: 'inline',
defaultValue: false,
},
setter: {
componentName: 'BoolSetter',
},
},
{
type: 'field',
name: 'primaryKey',
title: {
label: '数据主键',
tip: '数据主键用于区分数据中不同的行,对行选择和行编辑功能非常重要,不同的行主键值不可重复,一般采用数据库中自增 ID 字段',
},
extraProps: {
display: 'inline',
defaultValue: 'id',
condition: () => false,
},
},
{
name: 'cellDefault',
title: {
label: '单元格缺省填充',
tip: '当单元格值为空时,显示内容',
},
setter: 'StringSetter',
},
],
};
}
return { ...item };
});
export const editTableMeta: IComponentDescription = {
componentName: 'EditTable',
title: '可编辑表格',
docUrl: '',
icon: 'https://img.alicdn.com/imgextra/i4/O1CN01dtjMvv1heoyqst9u5_!!6000000004303-55-tps-56-56.svg',
devMode: 'procode',
group: '精选组件',
category: '表格类',
tags: ['业务组件'],
npm: {
package: '@alifd/fusion-ui',
version: '1.0.24-21',
exportName: 'EditTable',
main: 'lib/index.js',
destructuring: true,
subName: '',
},
configure: {
props: EditTableProps,
component: {
isContainer: false,
nestingRule: {},
},
supports: {
events: ['onSave', 'onRemove'],
},
},
snippets: [
{
title: '可编辑表格',
screenshot:
'https://img.alicdn.com/imgextra/i4/O1CN01dtjMvv1heoyqst9u5_!!6000000004303-55-tps-56-56.svg',
schema: {
componentName: 'EditTable',
props: {
dataSource: [
{
id: 'id-2f5DdE2b-0',
date: '2013-06-12',
percent: 1.862,
documentAmount: 2022,
currency: 'CNY',
company: '支付宝科技有限公司',
},
{
id: 'id-2f5DdE2b-1',
date: '2013-06-12',
percent: 1.862,
documentAmount: 2022,
currency: 'CNY',
company: '支付宝科技有限公司',
},
{
id: 'id-2f5DdE2b-2',
date: '2013-06-12',
percent: 1.862,
documentAmount: 2022,
currency: 'CNY',
company: '支付宝科技有限公司',
},
{
id: 'id-2f5DdE2b-3',
date: '2013-06-12',
percent: 1.862,
documentAmount: 2022,
currency: 'CNY',
company: '支付宝科技有限公司',
},
{
id: 'id-2f5DdE2b-4',
date: '2013-06-12',
percent: 1.862,
documentAmount: 2022,
currency: 'CNY',
company: '支付宝科技有限公司',
},
],
actionColumnButtons: {
text: true,
visibleButtonCount: 3,
},
actionBarButtons: {
dataSource: [
{
type: 'primary',
children: '操作一',
},
{
type: 'normal',
children: '操作二',
},
],
visibleButtonCount: 3,
},
paginationProps: {
pageSize: 20,
current: 1,
},
settingButtons: true,
columns: [
{
title: '公司',
dataIndex: 'company',
width: 160,
formatType: 'link',
searchable: true,
},
{
title: '单据金额',
dataIndex: 'documentAmount',
formatType: 'money',
},
{
title: '币种',
dataIndex: 'currency',
formatType: 'currency',
filters: [
{
label: 'CNY',
value: 'CNY',
},
{
label: 'USD',
value: 'USD',
},
{
label: 'JPY',
value: 'JPY',
},
{
label: 'HKD',
value: 'HKD',
},
],
filterMode: 'multiple',
explanation: '提示信息',
width: 110,
},
{
title: '完成进度',
dataIndex: 'percent',
formatType: 'progress',
},
{
title: '到账日期',
dataIndex: 'date',
formatType: 'date',
},
],
},
},
},
],
};
export default editTableMeta;
================================================
FILE: packages/fusion-ui/lowcode/expand-table/meta.ts
================================================
import { ComponentMetadata, Snippet } from '@ali/lowcode-types';
import { proTableMeta } from '../pro-table/pro-table-meta';
import { mockProTableRow, mockId } from '../pro-table/utils';
import { isJSExpression } from '../utils';
const childProps = proTableMeta.configure.props.map((item) => {
if (item.name === 'dataSource') {
return {
type: 'field',
name: 'dataSource',
title: '表格数据源',
display: 'accordion',
setter: (target) => {
const dataSource = target.getProps().getPropValue('dataSource');
if (isJSExpression(dataSource)) {
return {
componentName: 'ExpressionSetter',
};
}
const current = dataSource[target.path[1]];
const columns = current?.childTableProps?.columns;
if (!columns || isJSExpression(columns)) {
return {
componentName: 'ExpressionSetter',
};
}
const mockRow = mockProTableRow(columns);
const primaryKey = target.getProps().getPropValue('primaryKey') || 'id';
return {
componentName: 'MixedSetter',
props: {
setters: [
{
componentName: 'ArraySetter',
props: {
itemSetter: {
componentName: 'ObjectSetter',
props: {
config: {
items: columns.map((column, index) => {
return {
title: {
label: {
type: 'i18n',
'en-US': column.dataIndex,
'zh-CN': column.title,
},
},
name: column.dataIndex,
setter: {
isRequired: index < 2,
componentName: 'StringSetter',
},
defaultValue: mockRow[column.dataIndex],
};
}),
},
},
initialValue: () => {
return {
...mockRow,
[primaryKey]: mockId(),
};
},
},
},
},
'ExpressionSetter',
],
},
};
},
};
}
return item;
});
const props = proTableMeta.configure.props.map((item) => {
if (item.name === 'dataSource') {
return {
type: 'field',
name: 'dataSource',
title: '表格数据源',
display: 'accordion',
setter: (target) => {
const columns = target.getProps().getPropValue('columns');
if (!columns || isJSExpression(columns)) {
return {
componentName: 'ExpressionSetter',
};
}
const mockRow = mockProTableRow(columns);
const primaryKey = target.getProps().getPropValue('primaryKey') || 'id';
return {
componentName: 'MixedSetter',
props: {
setters: [
{
componentName: 'ArraySetter',
props: {
itemSetter: {
componentName: 'ObjectSetter',
props: {
config: {
items: [
...columns.map((column, index) => {
return {
title: {
label: {
type: 'i18n',
'en-US': column.dataIndex,
'zh-CN': column.title,
},
},
name: column.dataIndex,
setter: {
isRequired: index < 2,
componentName: 'StringSetter',
},
defaultValue: mockRow[column.dataIndex],
};
}),
{
title: {
label: { type: 'i18n', 'en-US': 'ChildTable', 'zh-CN': '子表格配置' },
},
display: 'accordion',
name: 'childTableProps',
setter: {
componentName: 'ObjectSetter',
props: {
config: {
items: childProps,
},
},
},
},
],
},
},
initialValue: () => {
return {
...mockRow,
[primaryKey]: mockId(),
};
},
},
},
},
'ExpressionSetter',
],
},
};
},
};
}
return item;
});
const ExpandTableMeta: ComponentMetadata = {
componentName: 'ExpandTable',
title: '母子表格',
docUrl: '',
screenshot:
'https://img.alicdn.com/imgextra/i4/O1CN01N3gxxr1cjKnzi9iBU_!!6000000003636-55-tps-56-56.svg',
devMode: 'proCode',
group: '精选组件',
category: '表格类',
tags: ['业务组件'],
npm: {
package: '@alifd/fusion-ui',
version: '0.1.6-beta.8',
exportName: 'ExpandTable',
main: 'lib/index.js',
destructuring: true,
subName: '',
},
configure: {
props,
supports: {
className: true,
style: true,
events: [
{
name: 'onBodyScroll',
description: '在内容区域滚动的时候触发的函数',
},
],
},
component: {},
},
};
const snippets: Snippet[] = [
{
title: '母子表格',
screenshot:
'https://img.alicdn.com/imgextra/i4/O1CN01N3gxxr1cjKnzi9iBU_!!6000000003636-55-tps-56-56.svg',
schema: {
componentName: 'ExpandTable',
props: {
dataSource: [
{
id: 'id-2f5DdE2b-0',
date: '2013-06-12',
percent: 1.862,
documentAmount: 2022,
currency: 'CNY',
company: '支付宝科技有限公司',
childTableProps: {
dataSource: [],
columns: [
{
title: '公司',
dataIndex: 'company',
width: 160,
formatType: 'link',
searchable: true,
},
{
title: '单据金额',
dataIndex: 'documentAmount',
formatType: 'money',
},
{
title: '币种',
dataIndex: 'currency',
formatType: 'currency',
filters: [
{
label: 'CNY',
value: 'CNY',
},
{
label: 'USD',
value: 'USD',
},
{
label: 'JPY',
value: 'JPY',
},
{
label: 'HKD',
value: 'HKD',
},
],
filterMode: 'multiple',
explanation: '提示信息',
width: 110,
},
{
title: '完成进度',
dataIndex: 'percent',
formatType: 'progress',
},
{
title: '到账日期',
dataIndex: 'date',
formatType: 'date',
},
],
},
},
{
id: 'id-2f5DdE2b-1',
date: '2013-06-12',
percent: 1.862,
documentAmount: 2022,
currency: 'CNY',
company: '支付宝科技有限公司',
childTableProps: {
dataSource: [],
columns: [
{
title: '公司',
dataIndex: 'company',
width: 160,
formatType: 'link',
searchable: true,
},
{
title: '单据金额',
dataIndex: 'documentAmount',
formatType: 'money',
},
{
title: '币种',
dataIndex: 'currency',
formatType: 'currency',
filters: [
{
label: 'CNY',
value: 'CNY',
},
{
label: 'USD',
value: 'USD',
},
{
label: 'JPY',
value: 'JPY',
},
{
label: 'HKD',
value: 'HKD',
},
],
filterMode: 'multiple',
explanation: '提示信息',
width: 110,
},
{
title: '完成进度',
dataIndex: 'percent',
formatType: 'progress',
},
{
title: '到账日期',
dataIndex: 'date',
formatType: 'date',
},
],
},
},
{
id: 'id-2f5DdE2b-2',
date: '2013-06-12',
percent: 1.862,
documentAmount: 2022,
currency: 'CNY',
company: '支付宝科技有限公司',
childTableProps: {
dataSource: [],
columns: [
{
title: '公司',
dataIndex: 'company',
width: 160,
formatType: 'link',
searchable: true,
},
{
title: '单据金额',
dataIndex: 'documentAmount',
formatType: 'money',
},
{
title: '币种',
dataIndex: 'currency',
formatType: 'currency',
filters: [
{
label: 'CNY',
value: 'CNY',
},
{
label: 'USD',
value: 'USD',
},
{
label: 'JPY',
value: 'JPY',
},
{
label: 'HKD',
value: 'HKD',
},
],
filterMode: 'multiple',
explanation: '提示信息',
width: 110,
},
{
title: '完成进度',
dataIndex: 'percent',
formatType: 'progress',
},
{
title: '到账日期',
dataIndex: 'date',
formatType: 'date',
},
],
},
},
],
actionColumnButtons: {
dataSource: [
{
children: '查看',
type: 'primary',
},
{
children: '编辑',
type: 'primary',
disabled: true,
},
{
children: '删除',
type: 'primary',
},
],
text: true,
visibleButtonCount: 3,
},
actionBarButtons: {
dataSource: [
{
type: 'primary',
children: '操作一',
},
{
type: 'normal',
children: '操作二',
},
],
visibleButtonCount: 3,
},
paginationProps: {
pageSize: 20,
current: 1,
},
settingButtons: true,
columns: [
{
title: '公司',
dataIndex: 'company',
width: 160,
formatType: 'link',
searchable: true,
},
{
title: '单据金额',
dataIndex: 'documentAmount',
formatType: 'money',
},
{
title: '币种',
dataIndex: 'currency',
formatType: 'currency',
filters: [
{
label: 'CNY',
value: 'CNY',
},
{
label: 'USD',
value: 'USD',
},
{
label: 'JPY',
value: 'JPY',
},
{
label: 'HKD',
value: 'HKD',
},
],
filterMode: 'multiple',
explanation: '提示信息',
width: 110,
},
{
title: '完成进度',
dataIndex: 'percent',
formatType: 'progress',
},
{
title: '到账日期',
dataIndex: 'date',
formatType: 'date',
},
],
},
},
},
];
export default {
...ExpandTableMeta,
snippets,
};
================================================
FILE: packages/fusion-ui/lowcode/filter/meta.ts
================================================
import { ComponentMetadata, Snippet } from '@ali/lowcode-types';
import { formItemsProps } from '../pro-form/common/form-base-props';
import { showWithLabelAlign } from '../utils';
import { operations } from '../common';
const operationConfig = {
name: 'operationConfig',
display: 'accordion',
title: '底部操作',
setter: {
componentName: 'ObjectSetter',
props: {
config: {
items: [
{
name: 'visibleButtonCount',
title: {
label: '可见数量',
tip: '超过会收起到”更多“菜单中',
},
extraProps: {
defaultValue: 3,
},
setter: {
componentName: 'NumberSetter',
props: {
max: 6,
min: 1,
},
},
},
],
},
},
},
};
const FilterMeta: ComponentMetadata = {
componentName: 'Filter',
title: '查询筛选',
group: '精选组件',
category: '表格类',
tags: ['业务组件'],
docUrl: '',
icon: 'https://img.alicdn.com/imgextra/i1/O1CN01O4Oshp1RA6Z0sFZ6h_!!6000000002070-55-tps-56-56.svg',
devMode: 'proCode',
npm: {
package: '@alifd/fusion-ui',
version: '0.1.6-beta.8',
exportName: 'Filter',
main: 'lib/index.js',
destructuring: true,
subName: '',
},
configure: {
props: [
{
name: 'globalConfig',
title: '全局配置',
type: 'group',
display: 'accordion',
items: [
{
name: 'enableFilterConfiguration',
title: '开启筛选项',
setter: 'BoolSetter',
},
{
name: 'status',
title: '状态',
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{
title: '只读态',
value: 'readonly',
},
{
title: '编辑态',
value: 'editable',
},
],
},
},
getValue: (target) => {
const isPreview = target.getProps().getPropValue('isPreview');
return isPreview ? 'readonly' : 'editable';
},
setValue: (target, value) => {
target.getProps().setPropValue('isPreview', value === 'readonly');
},
defaultValue: 'editable',
},
{
name: 'isPreview',
condition: () => false,
title: {
label: {
type: 'i18n',
zh_CN: '预览态',
en_US: 'Preview Mode',
},
tip: {
type: 'i18n',
zh_CN: '属性: isPreview | 说明: 是否开启预览态',
en_US: 'prop: isPreview | description: preview mode',
},
},
setter: 'BoolSetter',
},
{
name: 'cols',
title: '布局',
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{
title: '一列',
value: 1,
},
{
title: '二列',
value: 2,
},
{
title: '三列',
value: 3,
},
{
title: '四列',
value: 4,
},
],
},
},
defaultValue: 4,
},
{
name: 'labelAlign',
title: {
label: {
type: 'i18n',
zh_CN: '标签位置',
en_US: 'Label Align',
},
tip: {
type: 'i18n',
zh_CN: '属性: labelAlign | 说明: 标签的位置\n@enum desc 上, 左, 内',
en_US: 'prop: labelAlign | description: label align',
},
},
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{
title: '上',
value: 'top',
},
{
title: '左',
value: 'left',
},
{
title: '内',
value: 'inset',
},
],
},
},
setValue: (target, value) => {
if (value === 'inset') {
target.getProps().setPropValue('labelCol', null);
target.getProps().setPropValue('wrapperCol', null);
} else if (value === 'left') {
target.getProps().setPropValue('labelCol', { fixedSpan: 4 });
target.getProps().setPropValue('wrapperCol', null);
}
return target.getProps().setPropValue('labelAlign', value);
},
defaultValue: 'top',
},
{
name: 'labelCol.fixedSpan',
title: '标题宽度',
condition: showWithLabelAlign,
setter: {
componentName: 'NumberSetter',
props: {
min: 0,
max: 24,
},
},
},
{
name: 'labelCol.offset',
title: '标题偏移',
condition: showWithLabelAlign,
setter: {
componentName: 'NumberSetter',
props: {
min: 0,
max: 24,
},
},
},
{
name: 'wrapperCol.span',
title: '内容宽度',
condition: showWithLabelAlign,
setter: {
componentName: 'NumberSetter',
props: {
min: 0,
max: 24,
},
},
},
{
name: 'wrapperCol.offset',
title: '内容偏移',
condition: showWithLabelAlign,
setter: {
componentName: 'NumberSetter',
props: {
min: 0,
max: 24,
},
},
},
{
name: 'labelTextAlign',
condition: showWithLabelAlign,
title: {
label: {
type: 'i18n',
zh_CN: '标签对齐',
en_US: 'Text Align',
},
tip: {
type: 'i18n',
zh_CN: '属性: labelTextAlign | 说明: 标签的左右对齐方式\n@enumdesc 左, 右',
en_US: 'prop: labelTextAlign | description: label text align',
},
},
setter: {
componentName: 'RadioGroupSetter',
props: {
options: ['left', 'right'],
},
},
defaultValue: 'right',
},
],
},
formItemsProps,
operationConfig,
operations,
],
supports: {
style: true,
className: true,
events: ['onExpand', 'onSearch', 'onReset'],
},
component: {
isMinimalRenderUnit: true,
},
},
};
const snippets: Snippet[] = [
{
title: '查询筛选',
screenshot:
'https://img.alicdn.com/imgextra/i1/O1CN01O4Oshp1RA6Z0sFZ6h_!!6000000002070-55-tps-56-56.svg',
schema: {
componentName: 'Filter',
id: 'node_ockt5mo4jj1',
props: {
labelAlign: 'top',
},
children: [...new Array(4).keys()].map((item) => ({
componentName: 'FormInput',
props: {
formItemProps: {
primaryKey: String(Math.floor(Math.random() * 10000) + item),
label: '表单项',
size: 'medium',
device: 'desktop',
fullWidth: true,
},
placeholder: '请输入',
},
})),
},
},
];
export default {
...FilterMeta,
snippets,
};
================================================
FILE: packages/fusion-ui/lowcode/filter-item/meta.ts
================================================
import { ComponentMetadata } from '@ali/lowcode-types';
const FilterItemMeta: ComponentMetadata = {
componentName: 'FilterItem',
title: 'FilterItem',
docUrl: '',
screenshot: '',
devMode: 'proCode',
npm: {
package: '@alifd/fusion-ui',
version: '0.1.6-beta.8',
exportName: 'FilterItem',
main: 'lib/index.js',
destructuring: true,
subName: '',
},
configure: {
props: [
{
title: {
label: {
type: 'i18n',
'en-US': 'prefix',
'zh-CN': '样式前缀',
},
tip: 'prefix | 样式前缀',
},
name: 'prefix',
description: '样式前缀',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'label',
'zh-CN': 'label 标签的文',
},
tip: 'label | label 标签的文本',
},
name: 'label',
description: 'label 标签的文本',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'labelCol',
'zh-CN': 'label 标签布局',
},
tip: 'labelCol | label 标签布局,通 `` 组件,设置 span offset 值,如 {span: 8, offset: 16},该项仅在垂直表单有效',
},
name: 'labelCol',
description:
'label 标签布局,通 `` 组件,设置 span offset 值,如 {span: 8, offset: 16},该项仅在垂直表单有效',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'wrapperCol',
'zh-CN': '需要为输入控件设置布',
},
tip: 'wrapperCol | 需要为输入控件设置布局样式时,使用该属性,用法同 labelCol',
},
name: 'wrapperCol',
description: '需要为输入控件设置布局样式时,使用该属性,用法同 labelCol',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'help',
'zh-CN': '自定义提示信息,如不',
},
tip: 'help | 自定义提示信息,如不设置,则会根据校验规则自动生成.',
},
name: 'help',
description: '自定义提示信息,如不设置,则会根据校验规则自动生成.',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'extra',
'zh-CN': '额外的提示信息,和 ',
},
tip: 'extra | 额外的提示信息,和 help 类似,当需要错误信息和提示文案同时出现时,可以使用这个。 位于错误信息后面',
},
name: 'extra',
description:
'额外的提示信息,和 help 类似,当需要错误信息和提示文案同时出现时,可以使用这个。 位于错误信息后面',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'validateState',
'zh-CN': '校验状态,如不设置,',
},
tip: 'validateState | 校验状态,如不设置,则会根据校验规则自动生成',
},
name: 'validateState',
description: '校验状态,如不设置,则会根据校验规则自动生成',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'hasFeedback',
'zh-CN': '配合 validat',
},
tip: 'hasFeedback | 配合 validateState 属性使用,是否展示 success/loading 的校验状态图标, 目前只有Input支持',
},
name: 'hasFeedback',
description:
'配合 validateState 属性使用,是否展示 success/loading 的校验状态图标, 目前只有Input支持',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'children',
'zh-CN': 'node 或者 fu',
},
tip: 'children | node 或者 function(values)',
},
name: 'children',
description: 'node 或者 function(values)',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'size',
'zh-CN': '单个 Item 的 ',
},
tip: 'size | 单个 Item 的 size 自定义,优先级高于 Form 的 size, 并且当组件与 Item 一起使用时,组件自身设置 size 属性无效。',
},
name: 'size',
description:
'单个 Item 的 size 自定义,优先级高于 Form 的 size, 并且当组件与 Item 一起使用时,组件自身设置 size 属性无效。',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'labelAlign',
'zh-CN': '标签的位置',
},
tip: 'labelAlign | 标签的位置',
},
name: 'labelAlign',
description: '标签的位置',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'labelTextAlign',
'zh-CN': '标签的左右对齐方式',
},
tip: 'labelTextAlign | 标签的左右对齐方式',
},
name: 'labelTextAlign',
defaultValue: 'right',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'required',
'zh-CN': '[表单校验] 不能为',
},
tip: 'required | [表单校验] 不能为空',
},
name: 'required',
description: '[表单校验] 不能为空',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'asterisk',
'zh-CN': 'required 的',
},
tip: 'asterisk | required 的星号是否显示',
},
name: 'asterisk',
description: 'required 的星号是否显示',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'requiredMessage',
'zh-CN': 'required 自',
},
tip: 'requiredMessage | required 自定义错误信息',
},
name: 'requiredMessage',
description: 'required 自定义错误信息',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'requiredTrigger',
'zh-CN': 'required 自',
},
tip: 'requiredTrigger | required 自定义触发方式',
},
name: 'requiredTrigger',
description: 'required 自定义触发方式',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'min',
'zh-CN': '[表单校验] 最小值',
},
tip: 'min | [表单校验] 最小值',
},
name: 'min',
description: '[表单校验] 最小值',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'max',
'zh-CN': '[表单校验] 最大值',
},
tip: 'max | [表单校验] 最大值',
},
name: 'max',
description: '[表单校验] 最大值',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'minmaxMessage',
'zh-CN': 'min/max 自定',
},
tip: 'minmaxMessage | min/max 自定义错误信息',
},
name: 'minmaxMessage',
description: 'min/max 自定义错误信息',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'minmaxTrigger',
'zh-CN': 'min/max 自定',
},
tip: 'minmaxTrigger | min/max 自定义触发方式',
},
name: 'minmaxTrigger',
description: 'min/max 自定义触发方式',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'minLength',
'zh-CN': '[表单校验] 字符串',
},
tip: 'minLength | [表单校验] 字符串最小长度 / 数组最小个数',
},
name: 'minLength',
description: '[表单校验] 字符串最小长度 / 数组最小个数',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'maxLength',
'zh-CN': '[表单校验] 字符串',
},
tip: 'maxLength | [表单校验] 字符串最大长度 / 数组最大个数',
},
name: 'maxLength',
description: '[表单校验] 字符串最大长度 / 数组最大个数',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'minmaxLengthMessage',
'zh-CN': 'minLength/',
},
tip: 'minmaxLengthMessage | minLength/maxLength 自定义错误信息',
},
name: 'minmaxLengthMessage',
description: 'minLength/maxLength 自定义错误信息',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'minmaxLengthTrigger',
'zh-CN': 'minLength/',
},
tip: 'minmaxLengthTrigger | minLength/maxLength 自定义触发方式',
},
name: 'minmaxLengthTrigger',
description: 'minLength/maxLength 自定义触发方式',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'length',
'zh-CN': '[表单校验] 字符串',
},
tip: 'length | [表单校验] 字符串精确长度 / 数组精确个数',
},
name: 'length',
description: '[表单校验] 字符串精确长度 / 数组精确个数',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'lengthMessage',
'zh-CN': 'length 自定义',
},
tip: 'lengthMessage | length 自定义错误信息',
},
name: 'lengthMessage',
description: 'length 自定义错误信息',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'lengthTrigger',
'zh-CN': 'length 自定义',
},
tip: 'lengthTrigger | length 自定义触发方式',
},
name: 'lengthTrigger',
description: 'length 自定义触发方式',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'pattern',
'zh-CN': '正则校验',
},
tip: 'pattern | 正则校验',
},
name: 'pattern',
description: '正则校验',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'patternMessage',
'zh-CN': 'pattern 自定',
},
tip: 'patternMessage | pattern 自定义错误信息',
},
name: 'patternMessage',
description: 'pattern 自定义错误信息',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'patternTrigger',
'zh-CN': 'pattern 自定',
},
tip: 'patternTrigger | pattern 自定义触发方式',
},
name: 'patternTrigger',
description: 'pattern 自定义触发方式',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'format',
'zh-CN': '[表单校验] 四种常',
},
tip: 'format | [表单校验] 四种常用的 pattern',
},
name: 'format',
description: '[表单校验] 四种常用的 pattern',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'formatMessage',
'zh-CN': 'format 自定义',
},
tip: 'formatMessage | format 自定义错误信息',
},
name: 'formatMessage',
description: 'format 自定义错误信息',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'formatTrigger',
'zh-CN': 'format 自定义',
},
tip: 'formatTrigger | format 自定义触发方式',
},
name: 'formatTrigger',
description: 'format 自定义触发方式',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'validator',
'zh-CN': '[表单校验] 自定义',
},
tip: 'validator | [表单校验] 自定义校验函数',
},
name: 'validator',
description: '[表单校验] 自定义校验函数',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'validatorTrigger',
'zh-CN': 'validator ',
},
tip: 'validatorTrigger | validator 自定义触发方式',
},
name: 'validatorTrigger',
description: 'validator 自定义触发方式',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'autoValidate',
'zh-CN': '是否修改数据时自动触',
},
tip: 'autoValidate | 是否修改数据时自动触发校验',
},
name: 'autoValidate',
description: '是否修改数据时自动触发校验',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'labelWidth',
'zh-CN': '在响应式布局下,且l',
},
tip: 'labelWidth | 在响应式布局下,且label在左边时,label的宽度是多少',
},
name: 'labelWidth',
description: '在响应式布局下,且label在左边时,label的宽度是多少',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'colSpan',
'zh-CN': '在响应式布局模式下,',
},
tip: 'colSpan | 在响应式布局模式下,表单项占多少列',
},
name: 'colSpan',
description: '在响应式布局模式下,表单项占多少列',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'isPreview',
'zh-CN': '是否开启预览态',
},
tip: 'isPreview | 是否开启预览态',
},
name: 'isPreview',
description: '是否开启预览态',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'renderPreview',
'zh-CN': '预览态模式下渲染的内',
},
tip: 'renderPreview | 预览态模式下渲染的内容',
},
name: 'renderPreview',
description: '预览态模式下渲染的内容',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'useLabelForErrorMessage',
'zh-CN': '是否使用 label',
},
tip: 'useLabelForErrorMessage | 是否使用 label 替换校验信息的 name 字段',
},
name: 'useLabelForErrorMessage',
description: '是否使用 label 替换校验信息的 name 字段',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'colon',
'zh-CN': '表示是否显示 lab',
},
tip: 'colon | 表示是否显示 label 后面的冒号',
},
name: 'colon',
description: '表示是否显示 label 后面的冒号',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'valueName',
'zh-CN': '子元素的 value',
},
tip: 'valueName | 子元素的 value 名称',
},
name: 'valueName',
description: '子元素的 value 名称',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'fullWidth',
'zh-CN': '单个 Item 中表',
},
tip: 'fullWidth | 单个 Item 中表单类组件宽度是否是 100%',
},
name: 'fullWidth',
description: '单个 Item 中表单类组件宽度是否是 100%',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'locale',
'zh-CN': '国际化文案对象,属性',
},
tip: 'locale | 国际化文案对象,属性为组件的 displayName',
},
name: 'locale',
description: '国际化文案对象,属性为组件的 displayName',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'pure',
'zh-CN': '是否开启 Pure ',
},
tip: 'pure | 是否开启 Pure Render 模式,会提高性能,但是也会带来副作用',
},
name: 'pure',
description: '是否开启 Pure Render 模式,会提高性能,但是也会带来副作用',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'warning',
'zh-CN': '是否在开发模式下显示',
},
tip: 'warning | 是否在开发模式下显示组件属性被废弃的 warning 提示',
},
name: 'warning',
description: '是否在开发模式下显示组件属性被废弃的 warning 提示',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'rtl',
'zh-CN': '是否开启 rtl 模',
},
tip: 'rtl | 是否开启 rtl 模式',
},
name: 'rtl',
description: '是否开启 rtl 模式',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
],
supports: {
style: true,
className: true,
},
component: {},
},
};
export default {
...FilterItemMeta,
};
================================================
FILE: packages/fusion-ui/lowcode/group-table/meta.ts
================================================
import { mockProTableRow } from '../pro-table/utils';
import { IComponentDescription } from '../types/index';
import { actionColumnButtonField, actionColumnField } from '../pro-table/actionColumnFields';
import { isJSExpression } from '../utils';
import { columnsField } from '../pro-table/columns-field';
import { buttonGroupConfigureProp } from '../common/button-groups';
const dataSource = [
{
header: '头部文字',
footer: '尾部文字',
children: [
{
company: '支付宝科技有限公司',
documentAmount: 2022,
currency: 'CNY',
percent: 1.862,
date: '2013-06-12',
id: 'id-2f5DdE2b-0',
},
{
company: '支付宝科技有限公司',
documentAmount: 2022,
currency: 'CNY',
percent: 1.862,
date: '2013-06-12',
id: 'id-2f5DdE2b-0',
},
],
},
{
header: '头部文字2',
footer: '尾部文字2',
children: [
{
company: '支付宝科技有限公司',
documentAmount: 2022,
currency: 'CNY',
percent: 1.862,
date: '2013-06-12',
id: 'id-2f5DdE2b-0',
},
{
company: '支付宝科技有限公司',
documentAmount: 2022,
currency: 'CNY',
percent: 1.862,
date: '2013-06-12',
id: 'id-2f5DdE2b-0',
},
{
company: '支付宝科技有限公司',
documentAmount: 2022,
currency: 'CNY',
percent: 1.862,
date: '2013-06-12',
id: 'id-2f5DdE2b-0',
},
{
company: '支付宝科技有限公司',
documentAmount: 2022,
currency: 'CNY',
percent: 1.862,
date: '2013-06-12',
id: 'id-2f5DdE2b-0',
},
],
},
];
const positiveIntegerSetter = {
componentName: 'NumberSetter',
props: {
max: 200,
min: 1,
},
};
const groupTableMeta: IComponentDescription = {
componentName: 'GroupTable',
title: '分组表格',
docUrl: '',
icon: 'https://img.alicdn.com/imgextra/i4/O1CN01idASGC1tGLCY6bAUC_!!6000000005874-55-tps-56-56.svg',
devMode: 'proCode',
group: '精选组件',
category: '表格类',
tags: ['业务组件'],
npm: {
package: '@alifd/fusion-ui',
version: '1.0.24-21',
exportName: 'GroupTable',
main: 'lib/index.js',
destructuring: true,
subName: '',
},
configure: {
props: [
columnsField,
{
type: 'field',
name: 'id',
title: '节点 ID',
condition: () => false,
extraProps: {},
setter: 'NodeSetter',
},
actionColumnButtonField,
{
...buttonGroupConfigureProp,
name: 'actionBarButtons',
title: '操作栏按钮',
},
actionColumnField,
{
name: 'dataSource',
title: '分组内容',
setter: {
componentName: 'ArraySetter',
props: {
itemSetter: {
componentName: 'ObjectSetter',
props: {
config: {
items: [
{
title: { label: { type: 'i18n', 'en-US': 'header', 'zh-CN': '头部文字' } },
name: 'header',
setter: {
componentName: 'StringSetter',
isRequired: true,
initialValue: '',
},
},
{
title: { label: { type: 'i18n', 'en-US': 'label', 'zh-CN': '尾部文字' } },
name: 'footer',
setter: {
componentName: 'StringSetter',
isRequired: true,
initialValue: '',
},
},
{
title: { label: { type: 'i18n', 'en-US': 'label', 'zh-CN': '数据源' } },
name: 'children',
setter: (target) => {
const columns = target.getProps().getPropValue('columns');
if (!columns || isJSExpression(columns)) {
return {
componentName: 'ExpressionSetter',
};
}
const mockRow = mockProTableRow(columns);
return {
componentName: 'ArraySetter',
props: {
itemSetter: {
componentName: 'ObjectSetter',
props: {
config: {
items: columns.map((column, index) => {
return {
title: {
label: {
type: 'i18n',
'en-US': column.dataIndex,
'zh-CN': column.title,
},
},
name: column.dataIndex,
setter: {
isRequired: index < 2,
componentName: 'StringSetter',
},
defaultValue: mockRow[column.dataIndex],
};
}),
},
},
initialValue: mockRow,
},
},
};
},
},
],
extraSetter: { componentName: 'MixedSetter', isRequired: false, props: {} },
},
},
initialValue: {
header: '标题',
footer: '尾部',
children: [],
},
},
},
isRequired: true,
initialValue: [],
},
},
{
type: 'field',
name: 'paginationProps',
title: '分页器',
extraProps: {
display: 'accordion',
defaultCollapsed: true,
},
setter: {
componentName: 'ObjectSetter',
display: 'inline',
props: {
config: {
items: [
{
type: 'field',
name: 'hidden',
title: '关闭分页',
extraProps: {
display: 'inline',
defaultValue: false,
},
setter: 'BoolSetter',
},
{
name: 'total',
title: '总行数',
setter: {
componentName: 'NumberSetter',
props: {
min: 0,
},
},
hidden() {
console.log(
'visiblevisiblevisiblevisible',
this.parent.getParam('hidden').getValue(),
);
return !this.parent.getParam('hidden').getValue();
},
},
{
name: 'current',
title: '当前页',
setter: positiveIntegerSetter,
},
{
name: 'pageSize',
title: '每页行数',
setter: [
{
componentName: 'SelectSetter',
initialValue: 10,
props: {
options: [
{
title: '5',
value: 5,
},
{
title: '10',
value: 10,
},
{
title: '20',
value: 20,
},
{
title: '50',
value: 50,
},
],
},
},
positiveIntegerSetter,
],
},
],
},
},
},
},
{
type: 'field',
name: 'rowSelection',
condition: () => false,
},
],
component: {
isContainer: false,
nestingRule: {},
},
supports: {},
},
snippets: [
{
title: '分组表格',
screenshot:
'https://img.alicdn.com/imgextra/i4/O1CN01idASGC1tGLCY6bAUC_!!6000000005874-55-tps-56-56.svg',
schema: {
componentName: 'GroupTable',
props: {
dataSource,
actionColumnButtons: {
dataSource: [
{
children: '查看',
type: 'primary',
},
{
children: '编辑',
type: 'primary',
disabled: true,
},
{
children: '删除',
type: 'primary',
},
],
text: true,
visibleButtonCount: 3,
},
actionBarButtons: {
dataSource: [
{
type: 'primary',
children: '操作一',
},
{
type: 'normal',
children: '操作二',
},
],
visibleButtonCount: 3,
},
paginationProps: {
pageSize: 20,
current: 1,
},
settingButtons: true,
columns: [
{
title: '公司',
dataIndex: 'company',
width: 160,
formatType: 'link',
searchable: true,
},
{
title: '单据金额',
dataIndex: 'documentAmount',
formatType: 'money',
},
{
title: '币种',
dataIndex: 'currency',
formatType: 'currency',
filters: [
{
label: 'CNY',
value: 'CNY',
},
{
label: 'USD',
value: 'USD',
},
{
label: 'JPY',
value: 'JPY',
},
{
label: 'HKD',
value: 'HKD',
},
],
filterMode: 'multiple',
explanation: '提示信息',
width: 110,
},
{
title: '完成进度',
dataIndex: 'percent',
formatType: 'progress',
},
{
title: '到账日期',
dataIndex: 'date',
formatType: 'date',
},
],
},
},
},
],
};
export default groupTableMeta;
================================================
FILE: packages/fusion-ui/lowcode/input/meta.ts
================================================
import { IProps } from '../types';
import { wrapFormItemProps } from '../utils/form-utils';
const props: IProps[] = wrapFormItemProps([
{
name: 'label',
setter: 'StringSetter',
title: {
label: {
type: 'i18n',
zh_CN: '标签文本',
en_US: 'Label',
},
tip: {
type: 'i18n',
zh_CN: '属性: label | 说明: 标签文本内容',
en_US: 'prop: label | description: label content',
},
},
},
{
name: 'defaultValue',
title: {
label: '默认值',
tip: 'defaultValue|初始值',
},
setter: 'StringSetter',
},
{
name: 'placeholder',
defaultValue: '请输入',
title: {
label: {
type: 'i18n',
zh_CN: '输入提示',
en_US: 'Placeholder',
},
tip: {
type: 'i18n',
zh_CN: '属性: placeholder | 说明: 输入提示',
en_US: 'prop: placeholder | description: placeholder',
},
},
setter: 'StringSetter',
},
{
name: 'state',
title: {
label: {
type: 'i18n',
zh_CN: '状态',
en_US: 'State',
},
tip: {
type: 'i18n',
zh_CN: '属性: state | 说明: 状态\n@enumdesc 错误, 校验中, 成功, 警告',
en_US: 'prop: state | description: input state',
},
},
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{
value: 'error',
title: 'error',
},
{
value: 'loading',
title: 'loading',
},
{
value: 'success',
title: 'success',
},
{
value: 'warning',
title: 'warning',
},
{
value: '',
title: '默认',
},
],
},
},
},
{
name: 'size',
title: {
label: {
type: 'i18n',
zh_CN: '尺寸',
en_US: 'Size',
},
tip: {
type: 'i18n',
zh_CN: '属性: size | 说明: 尺寸\n@enumdesc 小, 中, 大',
en_US: 'prop: size | description: size',
},
},
setter: {
componentName: 'RadioGroupSetter',
props: {
options: ['small', 'medium', 'large'],
},
},
defaultValue: 'medium',
},
{
name: 'maxLength',
title: {
label: {
type: 'i18n',
zh_CN: '最大长度',
en_US: 'MaxLength',
},
tip: {
type: 'i18n',
zh_CN: '属性: maxLength | 说明: 最大长度',
en_US: 'prop: maxLength | description: max length',
},
},
setter: 'NumberSetter',
description: '最大长度',
},
{
name: 'hasClear',
title: {
label: {
type: 'i18n',
zh_CN: '显示清除',
en_US: 'Show Clear',
},
tip: {
type: 'i18n',
zh_CN: '属性: hasClear | 说明: 是否出现清除按钮',
en_US: 'prop: hasClear | description: show clear icon',
},
},
setter: 'BoolSetter',
description: '是否出现清除按钮',
},
{
name: 'disabled',
title: {
label: {
type: 'i18n',
zh_CN: '是否禁用',
en_US: 'Disabled',
},
tip: {
type: 'i18n',
zh_CN: '属性: disabled | 说明: 是否被禁用',
en_US: 'prop: disabled | description: disabled',
},
},
setter: 'BoolSetter',
description: '是否禁用',
},
{
name: 'showLimitHint',
title: {
label: {
type: 'i18n',
zh_CN: '展示限制',
en_US: 'ShowLimit',
},
tip: {
type: 'i18n',
zh_CN: '属性: showLimitHint | 说明: 是否展现最大长度样式',
en_US: 'prop: showLimitHint | description: showLimitHint',
},
},
setter: 'BoolSetter',
description: '是否展现最大长度样式',
},
{
name: 'cutString',
title: {
label: {
type: 'i18n',
zh_CN: '是否截断',
en_US: 'Cut Off',
},
tip: {
type: 'i18n',
zh_CN: '属性: cutString | 说明: 是否截断超出字符串',
en_US: 'prop: cutString | description: whether cut off string',
},
},
setter: 'BoolSetter',
description: '是否截断超出字符串',
},
{
name: 'readOnly',
title: {
label: {
type: 'i18n',
zh_CN: '是否只读',
en_US: 'ReadOnly',
},
tip: {
type: 'i18n',
zh_CN: '属性: readOnly | 说明: 是否只读',
en_US: 'prop: readOnly | description: ReadOnly',
},
},
setter: 'BoolSetter',
description: '是否只读',
},
{
name: 'trim',
title: {
label: {
type: 'i18n',
zh_CN: '是否 Trim',
en_US: 'Trim',
},
tip: {
type: 'i18n',
zh_CN: '属性: trim | 说明: onChange返回会自动去除头尾空字符',
en_US: 'prop: trim | description: whether trim when onChange called',
},
},
setter: 'BoolSetter',
},
{
name: 'hasBorder',
title: {
label: {
type: 'i18n',
zh_CN: '显示边框',
en_US: 'ShowBorder',
},
tip: {
type: 'i18n',
zh_CN: '属性: hasBorder | 说明: 是否有边框',
en_US: 'prop: hasBorder | description: HasBorder',
},
},
setter: 'BoolSetter',
},
{
name: 'autoFocus',
title: {
label: {
type: 'i18n',
zh_CN: '自动聚焦',
en_US: 'Auto Focus',
},
tip: {
type: 'i18n',
zh_CN: '属性: autoFocus | 说明: 自动聚焦',
en_US: 'prop: autoFocus | description: autoFocus',
},
},
setter: 'BoolSetter',
description: '自动聚焦',
},
{
name: 'hint',
title: {
label: {
type: 'i18n',
zh_CN: 'Icon 水印',
en_US: 'IconHint',
},
tip: {
type: 'i18n',
zh_CN: '属性: hint | 说明: Icon 水印',
en_US: 'prop: hint | description: Icon hint',
},
},
setter: {
componentName: 'IconSetter',
},
},
{
name: 'innerBefore',
display: 'block',
title: {
label: {
type: 'i18n',
zh_CN: '文字前附加内容',
en_US: 'Inner Before',
},
tip: {
type: 'i18n',
zh_CN: '属性: innerBefore | 说明: 文字前附加内容',
en_US: 'prop: innerBefore | description: innerBefore',
},
},
setter: 'StringSetter',
},
{
name: 'innerAfter',
display: 'block',
title: {
label: {
type: 'i18n',
zh_CN: '文字后附加内容',
en_US: 'Inner After',
},
tip: {
type: 'i18n',
zh_CN: '属性: innerAfter | 说明: 文字后附加内容',
en_US: 'prop: innerAfter | description: innerAfter',
},
},
setter: 'StringSetter',
},
{
name: 'addonBefore',
display: 'block',
title: {
label: {
type: 'i18n',
zh_CN: '输入框前附加内容',
en_US: 'Addon Before',
},
tip: {
type: 'i18n',
zh_CN: '属性: addonBefore | 说明: 输入框前附加内容',
en_US: 'prop: addonBefore | description: addonBefore',
},
},
setter: 'StringSetter',
},
{
name: 'addonAfter',
display: 'block',
title: {
label: {
type: 'i18n',
zh_CN: '输入框后附加内容',
en_US: 'Addon After',
},
tip: {
type: 'i18n',
zh_CN: '属性: addonAfter | 说明: 输入框后附加内容',
en_US: 'prop: addonAfter | description: addonAfter',
},
},
setter: 'StringSetter',
},
{
name: 'addonTextBefore',
display: 'block',
title: {
label: {
type: 'i18n',
zh_CN: '输入框前附加文字',
en_US: 'Text Before',
},
tip: {
type: 'i18n',
zh_CN: '属性: addonTextBefore | 说明: 输入框前附加文字',
en_US: 'prop: addonTextBefore | description: addonTextBefore',
},
},
setter: 'StringSetter',
},
{
name: 'addonTextAfter',
display: 'block',
title: {
label: {
type: 'i18n',
zh_CN: '输入框后附加文字',
en_US: 'Text After',
},
tip: {
type: 'i18n',
zh_CN: '属性: addonTextAfter | 说明: 输入框后附加文字',
en_US: 'prop: addonTextAfter | description: addonTextAfter',
},
},
setter: 'StringSetter',
},
{
type: 'group',
title: '高级',
display: 'block',
items: [
{
name: 'id',
title: {
label: {
type: 'i18n',
zh_CN: '唯一标识',
en_US: 'ID',
},
tip: {
type: 'i18n',
zh_CN: '属性: id | 说明: 唯一标识',
en_US: 'prop: id | description: switch id',
},
},
setter: 'StringSetter',
},
{
name: 'name',
title: {
label: {
type: 'i18n',
zh_CN: '表单标识',
en_US: 'Name',
},
tip: {
type: 'i18n',
zh_CN: '属性: name | 说明: 表单标识',
en_US: 'prop: name | description: switch name',
},
},
setter: 'StringSetter',
},
],
},
]);
const meta = {
componentName: 'FormInput',
isFormItemComponent: true,
title: '输入框',
docUrl: '',
screenshot: '',
npm: {
package: '@alifd/fusion-ui',
version: '{{version}}',
exportName: 'FormInput',
main: '',
destructuring: true,
subName: '',
},
configure: {
props,
supports: {
style: true,
events: ['onPressEnter', 'onClear', 'onChange', 'onKeyDown', 'onFocus', 'onBlur'],
},
},
icon: '',
category: '内容',
};
export default meta;
================================================
FILE: packages/fusion-ui/lowcode/line-chart/meta.ts
================================================
import { IPublicTypeComponentMetadata, IPublicTypeSnippet } from '@alilc/lowcode-types';
import { actionConfigure } from '../common/chart-action';
import { plotConfigure } from '../common/chart-plot';
const LineChartMeta: IPublicTypeComponentMetadata = {
componentName: 'LineChart',
title: '折线图',
category: '图表',
group: '精选组件',
docUrl: '',
screenshot: '',
devMode: 'proCode',
npm: {
package: '@alifd/fusion-ui',
version: '0.1.3-beta.3',
exportName: 'LineChart',
main: 'lib/index.js',
destructuring: true,
subName: '',
},
configure: {
props: [
// 数据
{
name: 'data',
type: 'group',
display: 'accordion',
title: {
label: '数据',
},
items: [
{
name: 'data',
title: '图表数据',
setter: 'JsonSetter',
},
{
name: 'xField',
title: {
label: 'x轴字段名',
tip: 'x 方向映射对应的数据字段名',
},
setter: 'StringSetter',
},
{
name: 'yField',
title: {
label: 'y轴字段名',
tip: 'y 方向映射所对应的数据字段名',
},
setter: 'StringSetter',
},
],
},
// 图形属性
{
name: '',
type: 'group',
display: 'accordion',
title: {
label: '图形属性',
},
items: [
{
name: 'color',
title: '颜色',
setter: 'ColorSetter',
},
{
name: 'lineSize',
title: '粗细',
setter: 'NumberSetter',
},
{
name: 'smooth',
title: '平滑',
setter: 'BoolSetter',
},
{
name: 'point.visible',
title: '显示点',
setter: 'BoolSetter',
},
{
name: 'label.visible',
title: '显示标签',
setter: 'BoolSetter',
},
],
},
...plotConfigure,
...actionConfigure,
],
},
};
const snippets: IPublicTypeSnippet[] = [
{
title: '折线图',
screenshot:
'https://img.alicdn.com/imgextra/i2/O1CN01ChN5mm1txOQnh6kTh_!!6000000005968-55-tps-56-56.svg',
schema: {
componentName: 'LineChart',
props: {
data: [
{ year: '1991', value: 72345678 },
{ year: '1992', value: 4321132 },
{ year: '1993', value: 33121112.5 },
{ year: '1994', value: 45227221 },
{ year: '1995', value: 4321221.9 },
{ year: '1996', value: 6322121 },
{ year: '1997', value: 78312213 },
{ year: '1998', value: 4192312 },
{ year: '1999', value: 6212332 },
{ year: '2000', value: 3192312 },
],
xField: 'year',
yField: 'value',
color: '#0079f2',
label: {
visible: true,
},
},
},
},
];
export default {
...LineChartMeta,
snippets
};
================================================
FILE: packages/fusion-ui/lowcode/month-picker/meta.js
================================================
export default {
componentName: 'MonthPicker',
title: 'MonthPicker',
docUrl: '',
screenshot: '',
npm: {
package: '@alifd/next',
version: '{{version}}',
exportName: 'DatePicker',
main: '',
destructuring: true,
subName: 'MonthPicker',
},
props: [
{
name: 'prefix',
propType: 'string',
defaultValue: 'next-',
},
{
name: 'rtl',
propType: 'bool',
defaultValue: false,
},
{
name: 'label',
propType: {
type: 'instanceOf',
value: 'node',
},
description: '表单项内置标签',
},
{
name: 'state',
propType: {
type: 'oneOf',
value: ['success', 'loading', 'error'],
},
description: '表单项状态',
},
{
name: 'placeholder',
propType: 'string',
description: '输入提示',
},
{
name: 'defaultVisibleYear',
propType: 'func',
description: '默认展现的年\n@return {MomentObject} 返回包含指定年份的 moment 对象实例',
},
{
name: 'value',
propType: {
type: 'instanceOf',
value: 'custom',
},
description: '日期值(受控)moment 对象',
},
{
name: 'defaultValue',
propType: {
type: 'instanceOf',
value: 'custom',
},
description: '初始日期值,moment 对象',
},
{
name: 'format',
propType: 'string',
description: '日期值的格式(用于限定用户输入和展示)',
defaultValue: 'YYYY-MM',
},
{
name: 'disabledDate',
propType: 'func',
description:
'禁用日期函数\n@param {MomentObject} 日期值\n@param {String} view 当前视图类型,year: 年, month: 月, date: 日\n@return {Boolean} 是否禁用',
},
{
name: 'footerRender',
propType: 'func',
description: '自定义面板页脚\n@return {Node} 自定义的面板页脚组件',
},
{
name: 'onChange',
propType: 'func',
description: '日期值改变时的回调\n@param {MomentObject|String} value 日期值',
},
{
name: 'size',
propType: {
type: 'oneOf',
value: ['small', 'medium', 'large'],
},
description: '表单项尺寸',
defaultValue: 'medium',
},
{
name: 'disabled',
propType: 'bool',
description: '是否禁用',
},
{
name: 'hasClear',
propType: 'bool',
description: '是否显示清空按钮',
defaultValue: true,
},
{
name: 'visible',
propType: 'bool',
description: '弹层显示状态',
},
{
name: 'defaultVisible',
propType: 'bool',
description: '弹层默认是否显示',
},
{
name: 'onVisibleChange',
propType: 'func',
description:
'弹层展示状态变化时的回调\n@param {Boolean} visible 弹层是否显示\n@param {String} type 触发弹层显示和隐藏的来源 calendarSelect 表示由日期表盘的选择触发; fromTrigger 表示由trigger的点击触发; docClick 表示由document的点击触发',
},
{
name: 'popupTriggerType',
propType: {
type: 'oneOf',
value: ['click', 'hover'],
},
description: '弹层触发方式',
defaultValue: 'click',
},
{
name: 'popupAlign',
propType: 'string',
description: '弹层对齐方式, 具体含义见 OverLay文档',
defaultValue: 'tl tl',
},
{
name: 'popupContainer',
propType: 'any',
description: '弹层容器\n@param {Element} target 目标元素\n@return {Element} 弹层的容器元素',
},
{
name: 'popupStyle',
propType: 'object',
description: '弹层自定义样式',
},
{
name: 'popupClassName',
propType: 'string',
description: '弹层自定义样式类',
},
{
name: 'popupProps',
propType: 'object',
description: '弹层其他属性',
},
{
name: 'followTrigger',
propType: 'bool',
description: '是否跟随滚动',
},
{
name: 'inputProps',
propType: 'object',
description: '表单项其他属性',
},
{
name: 'monthCellRender',
propType: 'func',
description:
'自定义月份渲染函数\n@param {Object} calendarDate 对应 Calendar 返回的自定义日期对象\n@returns {ReactNode}',
},
{
name: 'yearCellRender',
propType: 'func',
},
{
name: 'dateInputAriaLabel',
propType: 'string',
description: '日期表单项的 aria-label 属性',
},
{
name: 'isPreview',
propType: 'bool',
description: '是否为预览态',
},
{
name: 'renderPreview',
propType: 'func',
description: '预览态模式下渲染的内容\n@param {MomentObject} value 月份',
},
{
name: 'locale',
propType: 'object',
},
{
name: 'className',
propType: 'string',
},
{
name: 'name',
propType: 'string',
},
{
name: 'popupComponent',
propType: {
type: 'instanceOf',
value: 'elementType',
},
},
{
name: 'popupContent',
propType: {
type: 'instanceOf',
value: 'node',
},
},
{
name: 'style',
propType: 'object',
},
],
configure: {
props: [],
},
category: '基础',
};
================================================
FILE: packages/fusion-ui/lowcode/number-picker/meta.ts
================================================
import { wrapFormItemProps } from '../utils/form-utils';
export default {
componentName: 'FormNumberPicker',
isFormItemComponent: true,
title: '数字表单项',
docUrl: '',
screenshot: '',
npm: {
package: '@alifd/fusion-ui',
version: '{{version}}',
exportName: 'FormNumberPicker',
main: '',
destructuring: true,
subName: '',
},
props: [
{
name: 'size',
propType: {
type: 'oneOf',
value: ['large', 'medium'],
},
description: '大小',
defaultValue: 'medium',
},
{
name: 'type',
propType: {
type: 'oneOf',
value: ['normal', 'inline'],
},
description: '设置类型',
defaultValue: 'normal',
},
{
name: 'value',
propType: 'number',
description: '当前值',
},
{
name: 'defaultValue',
propType: 'number',
description: '默认值',
},
{
name: 'disabled',
propType: 'bool',
description: '是否禁用',
},
{
name: 'step',
propType: 'number',
description: '步长',
defaultValue: 1,
},
{
name: 'precision',
propType: 'number',
description: '保留小数点后位数',
defaultValue: 0,
},
{
name: 'editable',
propType: 'bool',
description: '用户是否可以输入',
defaultValue: true,
},
{
name: 'autoFocus',
propType: 'bool',
description: '自动焦点',
},
{
name: 'max',
propType: 'number',
description: '最大值',
defaultValue: null,
},
{
name: 'min',
propType: 'number',
description: '最小值',
defaultValue: null,
},
{
name: 'format',
propType: 'func',
description: '格式化当前值',
},
{
name: 'upBtnProps',
propType: 'object',
description: '增加按钮的props',
},
{
name: 'downBtnProps',
propType: 'object',
description: '减少按钮的props',
},
{
name: 'label',
propType: 'string',
description: '内联 label',
},
{
name: 'innerAfter',
propType: {
type: 'oneOfType',
value: ['string', 'icon'],
},
description: 'inner after',
},
{
name: 'rtl',
propType: 'bool',
},
{
name: 'isPreview',
propType: 'bool',
description: '是否为预览态',
},
{
name: 'renderPreview',
propType: 'func',
description: '预览态模式下渲染的内容\n@param {number} value 评分值',
},
{
name: 'onChange',
propType: 'func',
description: '数值被改变的事件\n@param {Number} value 数据\n@param {Event} e DOM事件对象',
},
{
name: 'onKeyDown',
propType: 'func',
description: '键盘按下',
},
{
name: 'onFocus',
propType: 'func',
description: '焦点获得',
},
{
name: 'onBlur',
propType: 'func',
description: '焦点失去',
},
{
name: 'onCorrect',
propType: 'func',
description: '数值订正后的回调\n@param {Object} obj {currentValue,oldValue:String}',
},
{
name: 'onDisabled',
propType: 'func',
},
{
name: 'className',
propType: 'string',
description: '自定义class',
},
{
name: 'style',
propType: 'object',
description: '自定义内联样式',
},
],
configure: {
props: wrapFormItemProps([
{
name: 'alwaysShowTrigger',
title: '展示操作',
setter: 'BoolSetter',
defaultValue: true,
},
{
name: 'value',
title: '当前值',
setter: ['NumberSetter', 'ExpressionSetter'],
},
{
name: 'defaultValue',
title: '默认值',
setter: ['NumberSetter', 'ExpressionSetter'],
},
{
name: 'size',
title: {
label: {
type: 'i18n',
zh_CN: '尺寸',
en_US: 'Size',
},
tip: {
type: 'i18n',
zh_CN: '属性: size | 说明: 尺寸\n@enumdesc 小, 中, 大',
en_US: 'prop: size | description: size',
},
},
setter: {
componentName: 'RadioGroupSetter',
props: {
options: ['small', 'medium', 'large'],
},
},
defaultValue: 'medium',
},
{
name: 'type',
title: '类型',
defaultValue: 'normal',
setter: {
componentName: 'MixedSetter',
props: {
setters: [
{
componentName: 'RadioGroupSetter',
props: {
options: [
{ title: '普通', value: 'normal' },
{ title: '内联', value: 'inline' },
],
},
},
'ExpressionSetter',
],
},
},
},
{
name: 'innerAfter',
title: '单位',
setter: ['StringSetter', 'ExpressionSetter'],
},
{
name: 'step',
title: '步长',
defaultValue: 1,
setter: ['NumberSetter', 'ExpressionSetter'],
},
{
name: 'precision',
title: '小数位数',
defaultValue: 0,
setter: ['NumberSetter', 'ExpressionSetter'],
},
{
name: 'max',
title: '最大值',
setter: ['NumberSetter', 'ExpressionSetter'],
},
{
name: 'min',
title: '最小值',
setter: ['NumberSetter', 'ExpressionSetter'],
},
{
name: 'editable',
title: '可以输入',
defaultValue: true,
setter: ['BoolSetter', 'ExpressionSetter'],
},
{
name: 'format',
title: '格式化',
display: 'block',
setter: {
componentName: 'FunctionSetter',
// props: {
// defaultActionName="format",
// defaultCode=`function format(value) {
// return value;
// }`,
// }
},
},
{
type: 'group',
title: '高级',
display: 'block',
items: [
{
name: 'id',
title: {
label: {
type: 'i18n',
zh_CN: '唯一标识',
en_US: 'ID',
},
tip: {
type: 'i18n',
zh_CN: '属性: id | 说明: 唯一标识',
en_US: 'prop: id | description: switch id',
},
},
setter: 'StringSetter',
},
{
name: 'name',
title: {
label: {
type: 'i18n',
zh_CN: '表单标识',
en_US: 'Name',
},
tip: {
type: 'i18n',
zh_CN: '属性: name | 说明: 表单标识',
en_US: 'prop: name | description: switch name',
},
},
setter: 'StringSetter',
},
],
},
{
name: 'style',
setter: {
componentName: 'StyleSetter',
},
},
]),
supports: {
events: ['onChange', 'onKeyDown', 'onFocus', 'onBlur', 'onCorrect'],
},
},
icon: '',
category: '内容',
};
================================================
FILE: packages/fusion-ui/lowcode/page-header/common/props.ts
================================================
import { FieldConfig } from '@ali/lowcode-types';
const props: FieldConfig[] = [
{
name: 'title',
title: '标题',
setter: 'StringSetter',
},
{
name: 'subTitle',
title: '子标题',
setter: 'StringSetter',
},
{
name: 'backIcon',
title: '返回图标',
setter: {
componentName: 'IconSetter',
},
},
{
name: 'showAvatar',
title: '头像',
setValue: (target, value) => {
return target.getProps().setPropValue('avatar', value || null);
},
setter: {
componentName: 'BoolSetter',
},
},
{
name: 'showBreadcrumb',
title: '面包屑',
setValue: (target, value) => {
return target.getProps().setPropValue('breadcrumb', value ? ['首页', '列表'] : null);
},
defaultValue: true,
setter: {
componentName: 'BoolSetter',
},
},
{
name: 'showActions',
title: '操作区',
defaultValue: false,
setter: {
componentName: 'BoolSetter',
},
},
{
name: 'avatar',
type: 'group',
display: 'accordion',
condition: (target) => {
const _avatar = target.getProps().getPropValue('showAvatar');
return !!_avatar;
},
title: {
label: '头像',
},
items: [
{
name: 'avatar.icon',
title: {
label: {
type: 'i18n',
zh_CN: '图标',
en_US: 'Icon',
},
tip: {
type: 'i18n',
zh_CN: '属性: icon | 说明: 图标类型',
en_US: 'prop: icon | description: icon type',
},
},
setter: {
componentName: 'IconSetter',
},
},
{
name: 'avatar.children',
title: {
label: {
type: 'i18n',
zh_CN: '文本内容',
en_US: 'Content',
},
tip: {
type: 'i18n',
zh_CN: '属性: children | 说明: 文本内容',
en_US: 'prop: children | description: avatar content',
},
},
setter: 'StringSetter',
},
{
name: 'avatar.size',
title: {
label: {
type: 'i18n',
zh_CN: '头像尺寸',
en_US: 'Size',
},
tip: {
type: 'i18n',
zh_CN: '属性: size | 说明: 头像的大小',
en_US: 'prop: size | description: avatar size',
},
},
setter: {
componentName: 'RadioGroupSetter',
props: {
options: ['small', 'medium', 'large'],
},
},
defaultValue: 'medium',
},
{
name: 'avatar.shape',
title: {
label: {
type: 'i18n',
zh_CN: '头像形状',
en_US: 'Shape',
},
tip: {
type: 'i18n',
zh_CN: '属性: shape | 说明: 头像的形状',
en_US: 'prop: shape | description: avatar shape',
},
},
setter: {
componentName: 'RadioGroupSetter',
props: {
options: ['circle', 'square'],
},
},
defaultValue: 'circle',
},
{
name: 'avatar.src',
title: {
label: {
type: 'i18n',
zh_CN: '头像地址',
en_US: 'Src',
},
tip: {
type: 'i18n',
zh_CN: '属性: src | 说明: 图片类头像的资源地址',
en_US: 'prop: src | description: resource address',
},
},
setter: 'StringSetter',
},
],
},
{
name: 'breadcrumb',
title: '面包屑',
condition: (target) => {
const _breadcrumbTarget = target.getProps().get('showBreadcrumb');
const _breadcrumbValue = _breadcrumbTarget.getValue();
const _breadcrumbDefaultValue = _breadcrumbTarget.getDefaultValue();
if (_breadcrumbValue === undefined && _breadcrumbDefaultValue) {
return _breadcrumbDefaultValue;
} else {
return !!_breadcrumbValue;
}
},
setter: {
componentName: 'ArraySetter',
props: {
itemSetter: {
componentName: 'StringSetter',
initialValue: '首页',
},
},
},
},
];
export default props;
================================================
FILE: packages/fusion-ui/lowcode/page-header/meta.design.js
================================================
const props = require('./common/props');
module.exports = {
componentName: 'PageHeader',
title: '设计态 PageHeader',
docUrl: '',
screenshot: '',
devMode: 'proCode',
npm: {
package: '@alifd/fusion-ui',
version: '1.0.0',
exportName: 'PageHeader',
main: 'lib/index.js',
destructuring: true,
subName: '',
},
props: [
{
name: 'backIcon',
propType: 'node',
},
{
name: 'prefixCls',
propType: 'string',
},
{
name: 'title',
propType: 'node',
},
{
name: 'subTitle',
propType: 'node',
},
{
name: 'style',
propType: 'object',
},
{
name: 'breadcrumb',
propType: {
type: 'oneOfType',
value: ['object'],
},
},
{
name: 'breadcrumbRender',
propType: {
type: 'func',
params: [
{
name: 'props',
propType: {
type: 'shape',
value: [
{
name: 'backIcon',
propType: 'node',
},
{
name: 'prefixCls',
propType: 'string',
},
{
name: 'title',
propType: 'node',
},
{
name: 'subTitle',
propType: 'node',
},
{
name: 'style',
propType: 'object',
},
{
name: 'breadcrumb',
propType: {
type: 'oneOfType',
value: ['object'],
},
},
{
name: 'breadcrumbRender',
propType: 'object',
},
{
name: 'tags',
propType: {
type: 'oneOfType',
value: [
'object',
{
type: 'arrayOf',
value: 'object',
},
],
},
},
{
name: 'footer',
propType: 'node',
},
{
name: 'extra',
propType: 'node',
},
{
name: 'avatar',
propType: 'object',
},
{
name: 'onBack',
propType: {
type: 'func',
params: [
{
name: 'e',
propType: 'object',
},
],
raw: '(e?: MouseEvent) => void',
},
},
{
name: 'className',
propType: 'string',
},
{
name: 'ghost',
propType: 'bool',
},
],
},
},
{
name: 'defaultDom',
propType: 'node',
},
],
raw: '(props: PageHeaderProps, defaultDom: ReactNode) => ReactNode',
},
},
{
name: 'tags',
propType: {
type: 'oneOfType',
value: [
'object',
{
type: 'arrayOf',
value: 'object',
},
],
},
},
{
name: 'footer',
propType: 'node',
},
{
name: 'extra',
propType: 'node',
},
{
name: 'avatar',
propType: 'object',
},
{
name: 'onBack',
propType: {
type: 'func',
params: [
{
name: 'e',
propType: 'object',
},
],
raw: '(e?: MouseEvent) => void',
},
},
{
name: 'className',
propType: 'string',
},
{
name: 'ghost',
propType: 'bool',
},
],
configure: {
component: {
isContainer: true,
},
props,
},
snippets: [
{
title: 'PageHeader',
screenshot:
'https://alifd.oss-cn-hangzhou.aliyuncs.com/fusion-cool/icons/icon-light/ic_light_message.png',
schema: {
title: 'PageHeader',
componentName: 'PageHeader',
props: {
placeholderStyle: {
height: '38px',
color: '#0088FF',
background: '#d8d8d836',
border: 0,
},
placeholder: '',
title: 'This is a designer title',
subTitle: '',
breadcrumb: ['首页', '列表'],
},
},
},
],
};
================================================
FILE: packages/fusion-ui/lowcode/page-header/meta.ts
================================================
import { ComponentMetadata, Snippet } from '@ali/lowcode-types';
import { operations } from '../common';
import props from './common/props';
const PageHeaderMeta: ComponentMetadata = {
componentName: 'PageHeader',
category: '布局容器类',
group: '精选组件',
title: '页头',
docUrl: '',
icon: 'https://img.alicdn.com/imgextra/i2/O1CN01q3ZRHx24rrQ9ysyU8_!!6000000007445-55-tps-56-56.svg',
devMode: 'procode',
npm: {
package: '@alifd/fusion-ui',
version: '1.0.0',
exportName: 'PageHeader',
main: 'lib/index.js',
destructuring: true,
subName: '',
},
props: [
{
name: 'backIcon',
propType: 'node',
},
{
name: 'prefixCls',
propType: 'string',
},
{
name: 'title',
propType: 'node',
},
{
name: 'subTitle',
propType: 'node',
},
{
name: 'style',
propType: 'object',
},
{
name: 'breadcrumb',
propType: {
type: 'oneOfType',
value: ['object'],
},
},
{
name: 'breadcrumbRender',
propType: {
type: 'func',
params: [
{
name: 'props',
propType: {
type: 'shape',
value: [
{
name: 'backIcon',
propType: 'node',
},
{
name: 'prefixCls',
propType: 'string',
},
{
name: 'title',
propType: 'node',
},
{
name: 'subTitle',
propType: 'node',
},
{
name: 'style',
propType: 'object',
},
{
name: 'breadcrumb',
propType: {
type: 'oneOfType',
value: ['object'],
},
},
{
name: 'breadcrumbRender',
propType: 'object',
},
{
name: 'tags',
propType: {
type: 'oneOfType',
value: [
'object',
{
type: 'arrayOf',
value: 'object',
},
],
},
},
{
name: 'footer',
propType: 'node',
},
{
name: 'extra',
propType: 'node',
},
{
name: 'avatar',
propType: 'object',
},
{
name: 'onBack',
propType: {
type: 'func',
params: [
{
name: 'e',
propType: 'object',
},
],
raw: '(e?: MouseEvent) => void',
},
},
{
name: 'className',
propType: 'string',
},
{
name: 'ghost',
propType: 'bool',
},
],
},
},
{
name: 'defaultDom',
propType: 'node',
},
],
raw: '(props: PageHeaderProps, defaultDom: ReactNode) => ReactNode',
},
},
{
name: 'tags',
propType: {
type: 'oneOfType',
value: [
'object',
{
type: 'arrayOf',
value: 'object',
},
],
},
},
{
name: 'footer',
propType: 'node',
},
{
name: 'extra',
propType: 'node',
},
{
name: 'avatar',
propType: 'object',
},
{
name: 'onBack',
propType: {
type: 'func',
params: [
{
name: 'e',
propType: 'object',
},
],
raw: '(e?: MouseEvent) => void',
},
},
{
name: 'className',
propType: 'string',
},
{
name: 'ghost',
propType: 'bool',
},
],
configure: {
component: {
isContainer: false,
},
props: [
...props,
Object.assign({}, operations, {
condition: (target) => {
const showAction = target.getProps().getPropValue('showActions');
return !!showAction;
},
}),
],
},
};
const snippets: Snippet[] = [
{
title: '页头',
screenshot:
'https://img.alicdn.com/imgextra/i2/O1CN01q3ZRHx24rrQ9ysyU8_!!6000000007445-55-tps-56-56.svg',
schema: {
componentName: 'PageHeader',
title: '页头',
props: {
title: 'This is a designer title',
subTitle: '',
breadcrumb: ['首页', '列表'],
operations: [
{
content: '自定义',
action: 'custom',
type: 'secondary',
},
{
content: '自定义',
action: 'custom',
type: 'secondary',
},
],
},
},
},
];
export default {
...PageHeaderMeta,
snippets,
};
================================================
FILE: packages/fusion-ui/lowcode/pie-chart/meta.ts
================================================
import { IPublicTypeComponentMetadata, IPublicTypeConfigure } from '@alilc/lowcode-types';
import { actionConfigure } from '../common/chart-action';
import { plotConfigure } from '../common/chart-plot';
const pieChartMeta: IPublicTypeComponentMetadata = {
componentName: 'PieChart',
title: '饼图',
category: '图表',
group: '精选组件',
docUrl: '',
screenshot: '',
devMode: 'proCode',
npm: {
package: '@alifd/fusion-ui',
version: '0.1.3-beta.3',
exportName: 'PieChart',
main: 'lib/index.js',
destructuring: true,
subName: '',
},
configure: {
props: [
// 图例
{
name: 'legend',
type: 'group',
display: 'accordion',
title: {
label: '图例',
},
items: [
{
name: 'legend.position',
title: '位置',
setter: {
componentName: 'SelectSetter',
props: {
options: [
{ title: '左', value: 'left' },
{ title: '左上', value: 'left-top' },
{ title: '左下', value: 'left-bottom' },
{ title: '右', value: 'right' },
{ title: '右上', value: 'right-top' },
{ title: '右下', value: 'right-bottom' },
{ title: '上', value: 'top' },
{ title: '上左', value: 'top-left' },
{ title: '上右', value: 'top-right' },
{ title: '下', value: 'bottom' },
{ title: '下左', value: 'bottom-left' },
{ title: '下右', value: 'bottom-right' },
],
},
},
},
],
},
// 数据
{
name: 'data',
type: 'group',
display: 'accordion',
title: {
label: '数据',
},
items: [
{
name: 'data',
title: '图表数据',
setter: 'JsonSetter',
},
{
name: 'angleField',
title: {
label: '值字段名',
tip: '扇形切片大小(弧度)所对应的数据字段名',
},
setter: 'StringSetter',
},
{
name: 'colorField',
title: {
label: '分类字段名',
tip: '扇形颜色映射对应的数据字段名',
},
setter: 'StringSetter',
},
],
},
// 图形属性
{
name: '',
type: 'group',
display: 'accordion',
title: {
label: '图形属性',
},
items: [
{
name: 'color',
title: '颜色',
setter: {
componentName: 'ArraySetter',
props: {
itemSetter: {
componentName: 'ColorSetter',
initialValue: '#0079f2',
},
},
},
},
{
name: 'label',
type: 'group',
display: 'accordion',
title: {
label: '标签',
},
items: [
{
name: 'label.visible',
title: '显示',
setter: 'BoolSetter',
},
{
name: 'label.type',
title: '位置',
setter: {
componentName: 'SelectSetter',
props: {
options: [
{ title: '内部', value: 'inner' },
{ title: '外部', value: 'outer' },
{ title: '外部圆形排布', value: 'outer-center' },
{ title: '蜘蛛布局', value: 'spider' },
],
},
},
},
],
},
...plotConfigure,
...actionConfigure,
],
},
],
},
};
const snippets = [
{
title: '饼图',
name: 'PieChart',
screenshot:
'https://img.alicdn.com/imgextra/i4/O1CN018rBRGK24fx7hzkITN_!!6000000007419-55-tps-56-56.svg',
schema: {
componentName: 'PieChart',
title: '饼图',
props: {
legend: {
position: 'top-left',
},
data: [
{ year: '1991', value: 72345678 },
{ year: '1992', value: 4321132 },
{ year: '1993', value: 33121112.5 },
{ year: '1994', value: 45227221 },
{ year: '1995', value: 4321221.9 },
{ year: '1996', value: 6322121 },
{ year: '1997', value: 78312213 },
{ year: '1998', value: 2192312 },
{ year: '1999', value: 6212332 },
{ year: '2000', value: 1192312 },
],
angleField: 'value',
colorField: 'year',
label: {
visible: true,
type: 'spider',
},
color: ['#3BCBD1', '#47A4FE', '#EDBA42', '#F4704E', '#ED6899', '#7F62C3', '#6E7BC9'],
},
},
},
];
export default {
...pieChartMeta,
snippets
};
================================================
FILE: packages/fusion-ui/lowcode/pro-dialog/meta.ts
================================================
import { ComponentMetadata, Snippet } from '@ali/lowcode-types';
import { hideProp } from '../utils';
import { operationProps } from '../common';
const ProDialogMeta: ComponentMetadata = {
componentName: 'ProDialog',
title: '对话框',
group: '精选组件',
docUrl: '',
screenshot:
'https://img.alicdn.com/imgextra/i1/O1CN01n5JLZG1aBmYZlckSx_!!6000000003292-55-tps-56-56.svg',
devMode: 'proCode',
npm: {
package: '@alifd/fusion-ui',
version: '0.1.6-beta.23',
exportName: 'ProDialog',
main: 'lib/index.js',
destructuring: true,
subName: '',
},
configure: {
component: {
isContainer: true,
isModal: true,
rootSelector: 'div.next-dialog',
nestingRule: {
parentWhitelist: ['Page'],
},
},
props: [
{
name: 'ref',
condition: hideProp,
setter: (target) => {
if (!target?.getValue()) {
target?.setValue(`pro-dialog-${target?.id}`);
}
return 'StringSetter';
},
},
{
name: 'dialogType',
title: '弹窗类型',
defaultValue: 'normal',
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{
title: '提示弹窗',
value: 'notice',
},
{
title: '普通弹窗',
value: 'normal',
},
],
},
},
},
{
name: 'status',
title: '提示状态',
condition: (target) => {
return target.getProps().getPropValue('dialogType') === 'notice';
},
defaultValue: 'success',
setter: {
componentName: 'SelectSetter',
props: {
options: [
{
title: '提醒',
value: 'notice',
},
{
title: '警告',
value: 'warning',
},
{
title: '确认',
value: 'help',
},
{
title: '成功',
value: 'success',
},
{
title: '失败',
value: 'error',
},
{
title: '加载中',
value: 'loading',
},
],
},
},
},
{
name: 'title',
title: '标题',
setter: () => {
const hasTitleSetter = AliLowCodeEngine.setters.getSetter('TitleSetter');
return hasTitleSetter
? {
componentName: 'TitleSetter',
props: {
defaultChecked: true,
},
}
: 'StringSetter';
},
defaultValue: 'Title',
},
{
name: 'size',
title: '弹窗尺寸',
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{
title: '大',
value: 'large',
},
{
title: '中',
value: 'medium',
},
{
title: '小',
value: 'small',
},
],
},
},
},
{
name: 'visible',
title: '默认显示',
setter: 'BoolSetter',
defaultValue: false,
},
{
name: 'hasTips',
title: '提示信息',
setter: 'BoolSetter',
defaultValue: false,
},
{
name: 'iconType',
title: '提示图标',
setter: {
componentName: 'IconSetter',
},
condition: (target) => {
const showExplanation = target.getProps().getPropValue('hasTips');
return !!showExplanation;
},
},
{
name: 'explanation',
title: '解释文案',
setter: {
componentName: 'StringSetter',
},
condition: (target) => {
const showExplanation = target.getProps().getPropValue('hasTips');
return !!showExplanation;
},
},
{
name: 'hasMask',
title: '显示遮罩',
setter: 'BoolSetter',
defaultValue: true,
},
{
name: 'closeMode',
title: '关闭方式',
setter: {
componentName: 'SelectSetter',
props: {
mode: 'tag',
options: [
{
title: '点击按钮',
value: 'close',
},
{
title: '点击遮罩',
value: 'mask',
},
{
title: 'ESC',
value: 'esc',
},
],
},
},
defaultValue: ['close'],
},
{
name: 'autoFocus',
title: '自动聚焦',
setter: 'BoolSetter',
defaultValue: false,
},
...operationProps,
{
name: 'buttons',
title: '底部按钮配置',
type: 'group',
condition: hideProp,
extraProps: {
display: 'block',
},
items: [
{
name: 'footer',
title: '是否显示',
setter: 'BoolSetter',
initialValue: true,
},
{
name: 'footerAlign',
title: '对齐方式',
initialValue: 'right',
condition: (target) => {
return target.getProps().getPropValue('footer');
},
setter: {
componentName: 'RadioGroupSetter',
initialValue: 'right',
props: {
options: [
{
title: 'left',
value: 'left',
},
{
title: 'center',
value: 'center',
},
{
title: 'right',
value: 'right',
},
],
},
},
},
{
name: 'footerActions',
title: '排列方式',
initialValue: ['ok', 'cancel'],
condition: (target) => {
return target.getProps().getPropValue('footer');
},
setter: {
componentName: 'SelectSetter',
initialValue: ['ok', 'cancel'],
props: {
options: [
{
title: 'ok, cancel',
value: ['ok', 'cancel'],
},
{
title: 'cancel, ok',
value: ['cancel', 'ok'],
},
{
title: 'cancel',
value: ['cancel'],
},
{
title: 'ok',
value: ['ok'],
},
],
},
},
},
],
},
],
supports: {
events: ['onOk', 'onCancel', 'onClose'],
style: true,
},
advanced: {
callbacks: {
// 与 next-page 的 onNodeAdd 一模一样
onNodeAdd: (dragment, currentNode) => {
// 拖入的组件为 P、Block、Slot(把NextPage拖入到面板里时,NextPage的Slot也会触发onNodeAdd事件) 时,不进行包裹
// 拖入的组件 isModal为true时(例如drawer dialog 这类有单独组件树结构的),不进行包裹
if (
!dragment ||
['NextP', 'NextBlock', 'Slot'].includes(dragment.componentName) ||
(dragment.componentMeta.isModal && dragment.componentMeta.isModal())
) {
console.log(
`[${dragment.componentName}] doesn \\'n need to wrap with NextBlock > NextBlockCell`,
);
return;
}
const NextPProps = {
wrap: false,
type: 'body2',
verAlign: 'middle',
textSpacing: true,
align: 'left',
};
if (
[
'Form',
'ResponsiveGrid',
'Box',
'Card',
'List',
'Message',
'Slider',
'NextTable',
].includes(dragment.componentName) ||
dragment.getPropValue('isFillContainer')
) {
NextPProps.full = true;
}
const layoutPSchema = {
componentName: 'NextP',
title: '段落',
props: NextPProps,
children: [dragment.exportSchema()],
};
// 为目标元素包裹一层 Block
const layoutBlockNode = (len) =>
currentNode.document.createNode({
componentName: 'NextBlock',
title: '区块',
props: {
childTotalColumns: len || 12,
},
children: [
{
componentName: 'NextBlockCell',
title: '子区块',
props: {
isAutoContainer: true,
colSpan: 12,
rowSpan: 1,
},
children: [layoutPSchema],
},
],
});
const { dropLocation } = dragment.document.canvas;
if (!dropLocation) {
// 没有 dropLocation 一般是 slot, slot 元素不用特殊处理 不做任何包裹
return;
}
const dropTarget = dropLocation.target;
const dropTargetName = dropLocation.target.componentName || '';
// 找到要拖入进去的节点 ID
const targetId = (dropLocation && dropLocation.target.id) || '';
// 找到要拖入进去的节点
const slotTarget =
currentNode.slots.length > 0 && currentNode.slots.find((item) => item.id === targetId);
const layoutPNode = currentNode.document.createNode(layoutPSchema);
// 是否为 aside slot
const isAsideSlot = slotTarget && ['aside'].indexOf(slotTarget._slotFor.key) > -1;
// 是否为需要被 P 包裹的 Slot
const isNeedPSlot =
slotTarget && ['header', 'footer', 'nav'].indexOf(slotTarget._slotFor.key) > -1;
const wrapWithBlock = (curDragMent, node, curDropTargetName, blockLen) => {
setTimeout(() => {
console.log(
`[${curDragMent.componentName}] to [${curDropTargetName}] need to wrap with NextBlock > NextBlockCell > NextP [from NextPage2]`,
);
const newNode = node.document.createNode(layoutBlockNode(blockLen).exportSchema());
node.insertBefore(newNode, curDragMent, false);
curDragMent.remove(false);
newNode.children.get(0).children.get(0).children.get(0).select();
}, 1);
};
const wrapWithP = (curDragMent, node, curDropTargetName) => {
setTimeout(() => {
// const dragmentTarget = dropTarget;
// 要拖入的地方如果是 NextP 那就 不再自动包裹 P了
if (dropTargetName === 'NextP') {
console.log(
`[${curDragMent.componentName}] to [${curDropTargetName}] does't need to wrap with NextP. [from NextPage3]`,
);
return;
}
console.log(
`[${curDragMent.componentName}] to [${dropTargetName}] need to wrap with NextP [from NextPage3]`,
);
const newNode = node.document.createNode(Object.assign(layoutPNode.exportSchema()));
node.insertBefore(newNode, curDragMent, false);
curDragMent.remove(false);
newNode.children.get(0).select();
}, 1);
};
// 需要包裹 Block BlockCell P 的情况:
// 1. 组件拖入到 NextPage,的直接子元素下(不包括slot), 此时Block宽度为12
if (['NextPage'].includes(dropTargetName) && currentNode.children.has(dragment)) {
wrapWithBlock(dragment, currentNode, dropTargetName, 12);
// 需要包裹 Block BlockCell P 的情况:
// 2. 组件拖入到 NextPage 的 aside slot, 的直接子元素下 (不包括slot下的进一步内容),此时Block宽度为1
} else if (isAsideSlot && slotTarget && slotTarget.children.has(dragment)) {
wrapWithBlock(dragment, slotTarget, dropTargetName, 1);
// 需要包裹 P 的情况:
// 1. 如果是处于,开启了自然布局模式的容器组件中 (或者Tab里)
// 这里的Tab主要是给纪元epoch使用的,因为他们用到了 @ali/vc-deep 的TabLayout组件,没办法在这个组件上再增加属性 isAutoContainer
} else if (dropTarget.getPropValue('isAutoContainer') || dropTargetName === 'Tab.Item') {
wrapWithP(dragment, dropTarget, dropTargetName);
// 需要包裹 P 的情况:
// 2. 如果是处于,Page 的 nav header footer 中
} else if (isNeedPSlot && slotTarget) {
wrapWithP(dragment, slotTarget, dropTargetName);
}
// 其他维持原状,不进行其他设置
},
},
},
},
icon: 'https://img.alicdn.com/imgextra/i1/O1CN01n5JLZG1aBmYZlckSx_!!6000000003292-55-tps-56-56.svg',
category: '布局容器类',
};
const snippets: Snippet[] = [
{
title: '高级对话框',
screenshot:
'https://img.alicdn.com/imgextra/i1/O1CN01n5JLZG1aBmYZlckSx_!!6000000003292-55-tps-56-56.svg',
schema: {
componentName: 'ProDialog',
props: {
status: 'success',
size: 'medium',
prefix: 'next-',
footerAlign: 'right',
title: 'Title',
closeMode: ['esc', 'close'],
hasMask: true,
align: 'cc cc',
minMargin: 40,
isAutoContainer: true,
visible: true,
iconType: 'prompt',
explanation: '提示文案',
operationConfig: {
align: 'right',
},
operations: [
{
action: 'ok',
type: 'primary',
content: '确认',
},
{
action: 'cancel',
type: 'normal',
content: '取消',
},
],
},
},
},
];
export default {
...ProDialogMeta,
snippets,
};
================================================
FILE: packages/fusion-ui/lowcode/pro-drawer/meta.ts
================================================
import { hideProp } from '../utils';
import { operationProps } from '../common';
const wrapWithBlock = (dragment, node, dropTargetName, blockLen, layoutBlockNode) => {
setTimeout(() => {
console.log(
`[${dragment.componentName}] to [${dropTargetName}] need to wrap with NextBlock > NextBlockCell > NextP [from NextPage2]`,
);
const newNode = node.document.createNode(layoutBlockNode(blockLen).exportSchema());
node.insertBefore(newNode, dragment, false);
dragment.remove(false);
newNode.children.get(0).children.get(0).children.get(0).select();
}, 1);
};
const wrapWithP = (dragment, node, dropTargetName, layoutPNode) => {
setTimeout(() => {
// const dragmentTarget = dropTarget;
// 要拖入的地方如果是 NextP 那就 不再自动包裹 P了
if (dropTargetName === 'NextP') {
console.log(
`[${dragment.componentName}] to [${dropTargetName}] does't need to wrap with NextP. [from NextPage3]`,
);
return;
}
console.log(
`[${dragment.componentName}] to [${dropTargetName}] need to wrap with NextP [from NextPage3]`,
);
const newNode = node.document.createNode(Object.assign(layoutPNode.exportSchema()));
node.insertBefore(newNode, dragment, false);
dragment.remove(false);
newNode.children.get(0).select();
}, 1);
};
const meta = {
componentName: 'Drawer',
title: '抽屉',
group: '精选组件',
docUrl: '',
screenshot: '',
npm: {
package: '@alifd/fusion-ui',
version: '0.1.6-beta.23',
exportName: 'ProDrawer',
main: 'lib/index.js',
destructuring: true,
subName: '',
},
configure: {
component: {
isContainer: true,
isModal: true,
rootSelector: '.next-drawer',
nestingRule: {
parentWhitelist: (testNode) => {
return testNode.componentName === 'Page';
},
},
},
props: [
{
name: 'ref',
condition: hideProp,
setter: (target) => {
if (!target?.getValue()) {
target?.setValue(`pro-drawer-${target?.id}`);
}
return 'StringSetter';
},
},
{
name: 'title',
title: {
label: {
type: 'i18n',
zh_CN: '标题',
en_US: 'Title',
},
tip: {
type: 'i18n',
zh_CN: '属性: title | 说明: 标题',
en_US: 'prop: title | description: title',
},
},
setter: {
componentName: 'StringSetter',
},
description: '标题',
},
{
name: 'titleTip.enable',
title: '标题提示',
condition: (target) => {
console.log('title: ', target.getProps().getPropValue('title'));
return !!target.getProps().getPropValue('title');
},
setter: {
componentName: 'BoolSetter',
},
},
{
name: 'titleTip.content',
condition: (target) => {
return target.getProps().getPropValue('titleTip.enable') === true;
},
title: '提示内容',
setter: {
componentName: 'StringSetter',
},
},
{
name: 'titleTip.icon',
condition: (target) => {
return target.getProps().getPropValue('titleTip.enable') === true;
},
title: '提示图标',
setter: {
componentName: 'IconSetter',
},
},
{
name: 'width',
condition: hideProp,
title: {
label: {
type: 'i18n',
zh_CN: '宽度',
en_US: 'width',
},
tip: {
type: 'i18n',
zh_CN: '属性: width | 说明: 宽度',
en_US: 'prop: width | description: 仅在 placement是 left right 的时候生效',
},
},
setter: {
componentName: 'NumberSetter',
},
description: '宽度,仅在 placement是 left right 的时候生效',
},
{
name: 'height',
condition: hideProp,
title: {
label: {
type: 'i18n',
zh_CN: '高度',
en_US: 'height',
},
tip: {
type: 'i18n',
zh_CN: '属性: height | 说明: 高度',
en_US: 'prop: height | description: 仅在 placement是 top bottom 的时候生效',
},
},
setter: {
componentName: 'NumberSetter',
},
description: '高度,仅在 placement是 top bottom 的时候生效',
},
{
name: 'placement',
title: {
label: {
type: 'i18n',
zh_CN: '弹出位置',
en_US: 'height',
},
tip: {
type: 'i18n',
zh_CN: '属性: placement | 说明: 位于页面的位置',
en_US: 'prop: placement | description: drawer placement',
},
},
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{
title: '上',
value: 'top',
},
{
title: '右',
value: 'right',
},
{
title: '下',
value: 'bottom',
},
{
title: '左',
value: 'left',
},
],
},
},
description: '位于页面的位置',
defaultValue: 'right',
},
{
name: 'size',
title: '尺寸',
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{
title: '大',
value: 'large',
},
{
title: '中',
value: 'medium',
},
{
title: '小',
value: 'small',
},
],
},
},
},
{
name: 'visible',
title: {
label: {
type: 'i18n',
zh_CN: '默认显示',
en_US: 'visible',
},
tip: {
type: 'i18n',
zh_CN: '属性: visible | 说明: 默认显示',
en_US: 'prop: visible | description: drawer visible',
},
},
setter: 'BoolSetter',
},
{
name: 'hasMask',
title: {
label: {
type: 'i18n',
zh_CN: '显示遮罩',
en_US: 'hasMask',
},
tip: {
type: 'i18n',
zh_CN: '属性: hasMask | 说明: 是否显示遮罩',
en_US: 'prop: hasMask | description: drawer hasMask',
},
},
setter: {
componentName: 'BoolSetter',
},
description: '是否显示遮罩',
defaultValue: true,
},
{
name: 'closeMode',
title: '关闭方式',
setter: {
componentName: 'SelectSetter',
props: {
mode: 'multiple',
options: [
{
title: '点击按钮',
value: 'close',
},
{
title: '点击遮罩',
value: 'mask',
},
{
title: 'ESC',
value: 'esc',
},
],
},
},
defaultValue: ['close'],
},
...operationProps,
],
},
advanced: {
callbacks: {
// 与 next-page 的 onNodeAdd 一模一样
onNodeAdd: (dragment, currentNode) => {
// 拖入的组件为 P、Block、Slot(把NextPage拖入到面板里时,NextPage的Slot也会触发onNodeAdd事件) 时,不进行包裹
// 拖入的组件 isModal为true时(例如drawer dialog 这类有单独组件树结构的),不进行包裹
if (
!dragment ||
['NextP', 'NextBlock', 'Slot'].includes(dragment.componentName) ||
(dragment.componentMeta.isModal && dragment.componentMeta.isModal())
) {
console.log(
`[${dragment.componentName}] does not need to wrap with NextBlock > NextBlockCell`,
);
return;
}
const NextPProps = {
wrap: false,
type: 'body2',
verAlign: 'middle',
textSpacing: true,
align: 'left',
};
if (
[
'Form',
'ResponsiveGrid',
'Box',
'Card',
'List',
'Message',
'Slider',
'NextTable',
].includes(dragment.componentName) ||
dragment.getPropValue('isFillContainer')
) {
NextPProps.full = true;
}
const layoutPSchema = {
componentName: 'NextP',
title: '段落',
props: NextPProps,
children: [dragment.exportSchema()],
};
// 为目标元素包裹一层 Block
const layoutBlockNode = (len) =>
currentNode.document.createNode({
componentName: 'NextBlock',
title: '区块',
props: {
childTotalColumns: len || 12,
},
children: [
{
componentName: 'NextBlockCell',
title: '子区块',
props: {
isAutoContainer: true,
colSpan: 12,
rowSpan: 1,
},
children: [layoutPSchema],
},
],
});
const { dropLocation } = dragment.document.canvas;
if (!dropLocation) {
// 没有 dropLocation 一般是 slot, slot 元素不用特殊处理 不做任何包裹
return;
}
const dropTarget = dropLocation.target;
const dropTargetName = dropLocation.target.componentName || '';
// 找到要拖入进去的节点 ID
const targetId = (dropLocation && dropLocation.target.id) || '';
// 找到要拖入进去的节点
const slotTarget =
currentNode.slots.length > 0 && currentNode.slots.find((item) => item.id === targetId);
const layoutPNode = currentNode.document.createNode(layoutPSchema);
// 是否为 aside slot
const isAsideSlot = slotTarget && ['aside'].indexOf(slotTarget._slotFor.key) > -1;
// 是否为需要被 P 包裹的 Slot
const isNeedPSlot =
slotTarget && ['header', 'footer', 'nav'].indexOf(slotTarget._slotFor.key) > -1;
// 需要包裹 Block BlockCell P 的情况:
// 1. 组件拖入到 NextPage,的直接子元素下(不包括slot), 此时Block宽度为12
if (['NextPage'].includes(dropTargetName) && currentNode.children.has(dragment)) {
wrapWithBlock(dragment, currentNode, dropTargetName, 12, layoutBlockNode);
// 需要包裹 Block BlockCell P 的情况:
// 2. 组件拖入到 NextPage 的 aside slot, 的直接子元素下 (不包括slot下的进一步内容),此时Block宽度为1
} else if (isAsideSlot && slotTarget && slotTarget.children.has(dragment)) {
wrapWithBlock(dragment, slotTarget, dropTargetName, 1, layoutBlockNode);
// 需要包裹 P 的情况:
// 1. 如果是处于,开启了自然布局模式的容器组件中 (或者Tab里)
// 这里的Tab主要是给纪元epoch使用的,因为他们用到了 @ali/vc-deep 的TabLayout组件,没办法在这个组件上再增加属性 isAutoContainer
} else if (dropTarget.getPropValue('isAutoContainer') || dropTargetName === 'Tab.Item') {
wrapWithP(dragment, dropTarget, dropTargetName, layoutPNode);
// 需要包裹 P 的情况:
// 2. 如果是处于,Page 的 nav header footer 中
} else if (isNeedPSlot && slotTarget) {
wrapWithP(dragment, slotTarget, dropTargetName, layoutPNode);
}
// 其他维持原状,不进行其他设置
},
},
},
icon: '',
category: '布局容器类',
};
const snippets = [
{
title: '高级抽屉',
screenshot:
'https://img.alicdn.com/imgextra/i3/O1CN01PIbHBa1dxMY8m44cf_!!6000000003802-55-tps-56-56.svg',
schema: {
componentName: 'Drawer',
props: {
prefix: 'next-',
title: '高级抽屉',
triggerType: 'click',
closeable: true,
placement: 'right',
hasMask: true,
isAutoContainer: true,
visible: true,
size: 'medium',
operationConfig: {
align: 'right',
fixed: true,
},
operations: [
{
action: 'ok',
type: 'primary',
content: '确认',
},
{
action: 'cancel',
type: 'normal',
content: '取消',
},
],
},
},
},
];
export default { ...meta, snippets };
================================================
FILE: packages/fusion-ui/lowcode/pro-form/common/form-base-props.ts
================================================
import { isEqual, throttle } from 'lodash';
import { IPublicModelSettingField } from '@alilc/lowcode-types';
import { material } from '@alilc/lowcode-engine'
import { IProps } from '../../types';
import { formItemShortcutProps as baseFormItemProps } from './form-item-props';
import { hideProp, showWithLabelAlign } from '../../utils';
function getInitialPropsForFormItem(componentName, currentComponentProps) {
const component = material?.getAssets()?.components.filter((item) => item.componentName === componentName)[0];
const defaultProps = {};
const initials = component?.advanced?.initials;
if (initials && Array.isArray(initials) && initials.length) {
initials.forEach((initial) => {
if (initial && initial.name && initial.initial) {
defaultProps[initial.name] =
typeof initial.initial === 'function' ? initial.initial() : initial.initial;
}
});
}
const props = { ...currentComponentProps };
Object.keys(defaultProps).forEach((item) => {
const propValue = currentComponentProps[item];
if (!propValue && defaultProps[item]) {
props[item] = defaultProps[item];
}
});
return props;
}
const itemSetValue = throttle((target: IPublicModelSettingField, value) => {
const { node } = target;
const mergedValueMap = {};
const mergedValues: any = [];
const map = {};
if (!Array.isArray(value)) {
value = [];
}
value.forEach((item) => {
if (item.primaryKey === undefined) return;
if (!mergedValueMap[item.primaryKey]) {
mergedValueMap[item.primaryKey] = item;
mergedValues.push(item);
}
const FormItem = Object.assign({}, item);
if (!FormItem.componentName) {
// 新增表单项时初始化
FormItem.componentName = 'FormInput';
}
map[item.primaryKey] = FormItem;
});
const children = node?.children?.filter((child) => {
if (!mergedValueMap[child.propsData?.['primaryKey']]) {
mergedValueMap[child.propsData?.['primaryKey']] = child.propsData;
mergedValues.push(child.propsData);
}
return true;
});
const preValue = children.map((child) => {
return child.propsData;
});
if (isEqual(preValue, value)) {
return;
}
node?.children?.mergeChildren(
(child) => {
const primaryKey =
child.getPropValue('formItemProps')?.primaryKey || child.getPropValue('primaryKey');
if (Object.hasOwnProperty.call(map, primaryKey)) {
const { componentName, componentProps, ...otherProps } = map[primaryKey];
const newComponentProps = getInitialPropsForFormItem(componentName, componentProps);
let newProps;
if (child.componentName === 'ProFormItem') {
const formItemProps = { ...(child.propsData || {}), ...otherProps };
delete formItemProps.componentProps;
delete formItemProps.componentName;
newProps = {
formItemProps,
...newComponentProps,
};
delete newProps.componentName;
} else {
newProps = {
...(child.propsData || {}),
...newComponentProps,
formItemProps: otherProps,
};
}
node.replaceChild(child, {
componentName,
props: newProps,
});
delete map[primaryKey];
return false;
}
return true;
},
() => {
const items: any[] = [];
for (const primaryKey in map) {
if (Object.hasOwnProperty.call(map, primaryKey)) {
const { componentName, componentProps, ...otherProps } = map[primaryKey];
const newProps = {
formItemProps: otherProps,
...componentProps,
};
items.push({
componentName,
props: newProps,
});
}
}
return items;
},
(child1, child2) => {
const a = mergedValues.findIndex(
(item) =>
String(item.primaryKey) ===
String(
child1.getPropValue('formItemProps')?.primaryKey || child1.getPropValue('primaryKey'),
),
);
const b = mergedValues.findIndex(
(item) =>
String(item.primaryKey) ===
String(
child2.getPropValue('formItemProps')?.primaryKey || child2.getPropValue('primaryKey'),
),
);
return a - b;
},
);
});
export const formItemsProps = {
name: '!items',
title: '表单项',
display: 'accordion',
virtual: true,
setter: {
componentName: 'ArraySetter',
props: {
itemSetter: {
componentName: 'ObjectSetter',
props: {
config: {
items: [
{
name: 'componentName',
title: '表单项组件',
display: 'inline',
defaultValue: 'FormInput',
important: true,
setter: () => {
return {
componentName: 'SelectSetter',
props: {
options: AliLowCodeEngine.material
.getAssets()
.components.filter((item) => item.isFormItemComponent)
.map((item) => {
return {
title: item.title || item.componentName,
value: item.componentName,
};
}),
},
};
},
},
...baseFormItemProps,
],
},
},
initialValue: () => {
const mockProps = {};
baseFormItemProps.forEach((item) => {
if (item.defaultValue) {
if (typeof item.defaultValue === 'function') {
mockProps[item.name] = item.defaultValue();
} else {
mockProps[item.name] = item.defaultValue;
}
}
});
return {
componentName: 'FormInput',
...mockProps,
};
},
},
},
},
getValue: (target: IPublicModelSettingField) => {
const hotValue = target.node?.children?.map((child) => {
const { propsData } = child;
// 兼容 FroFromItem -> Input 的数据结构
if (child.componentName === 'ProFormItem') {
const { componentProps, ...formItemProps } = propsData || {};
return {
...formItemProps,
componentProps,
};
} else {
const { formItemProps, ...componentProps } = propsData || {};
return {
...formItemProps,
componentName: child.componentName,
componentProps,
};
}
});
return hotValue;
},
setValue: itemSetValue,
};
const props: IProps[] = [
{
name: 'ref',
condition: hideProp,
setter: (target) => {
if (!target?.getValue()) {
target?.setValue(`pro-form-${target?.id}`);
}
return 'StringSetter';
},
},
{
name: 'globalConfig',
title: '全局配置',
type: 'group',
display: 'accordion',
items: [
{
name: 'inline',
condition: hideProp,
title: {
label: {
type: 'i18n',
zh_CN: '内联表单',
en_US: 'Inline',
},
tip: {
type: 'i18n',
zh_CN: '属性: inline | 说明: 内联表单',
en_US: 'prop: inline | description: inline form',
},
},
setter: {
componentName: 'MixedSetter',
props: {
setters: ['BoolSetter', 'ExpressionSetter'],
},
},
setValue: (target, value) => {
if (value === true) {
target.getProps().setPropValue('labelCol', null);
target.getProps().setPropValue('wrapperCol', null);
} else {
target.getProps().setPropValue('labelCol', { fixedSpan: 4 });
target.getProps().setPropValue('wrapperCol', null);
}
return target.getProps().setPropValue('inline', value);
},
},
{
name: 'fullWidth',
condition: hideProp,
title: {
label: {
type: 'i18n',
zh_CN: '宽度占满',
en_US: 'FullWidth',
},
tip: {
type: 'i18n',
zh_CN: '属性: fullWidth | 说明: 单个 Item 中表单类组件宽度是否是100%',
en_US: 'prop: fullWidth | description: full width',
},
},
setter: 'BoolSetter',
},
{
name: 'status',
virtual: true,
title: '状态',
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{
title: '只读态',
value: 'readonly',
},
{
title: '编辑态',
value: 'editable',
},
],
},
},
getValue: (target) => {
const isPreview = target.getProps().getPropValue('isPreview');
return isPreview ? 'readonly' : 'editable';
},
setValue: (target, value) => {
target.getProps().setPropValue('isPreview', value === 'readonly');
},
defaultValue: 'editable',
},
{
name: 'isPreview',
condition: () => false,
title: {
label: {
type: 'i18n',
zh_CN: '预览态',
en_US: 'Preview Mode',
},
tip: {
type: 'i18n',
zh_CN: '属性: isPreview | 说明: 是否开启预览态',
en_US: 'prop: isPreview | description: preview mode',
},
},
setter: 'BoolSetter',
description: '是否开启预览态',
},
{
name: 'columns',
title: '布局',
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{
title: '一列',
value: 1,
},
{
title: '二列',
value: 2,
},
{
title: '三列',
value: 3,
},
{
title: '四列',
value: 4,
},
],
},
},
},
{
name: 'labelAlign',
title: {
label: {
type: 'i18n',
zh_CN: '标签位置',
en_US: 'Label Align',
},
tip: {
type: 'i18n',
zh_CN: '属性: labelAlign | 说明: 标签的位置\n@enumdesc 上, 左, 内',
en_US: 'prop: labelAlign | description: label align',
},
},
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{
title: '上',
value: 'top',
},
{
title: '左',
value: 'left',
},
{
title: '内',
value: 'inset',
},
],
},
},
extraProps: {
setValue: (target, value) => {
if (value === 'inset') {
target.getProps().setPropValue('labelCol.fixedSpan', 0);
target.getProps().setPropValue('wrapperCol', null);
} else if (value === 'left') {
target.getProps().setPropValue('labelCol.fixedSpan', 4);
target.getProps().setPropValue('wrapperCol', null);
}
return target.getProps().setPropValue('labelAlign', value);
},
},
defaultValue: 'top',
},
{
name: 'labelCol.fixedSpan',
title: '标题宽度',
condition: showWithLabelAlign,
setter: {
componentName: 'NumberSetter',
props: {
min: 0,
max: 24,
},
},
},
{
name: 'labelCol.offset',
title: '标题偏移',
condition: showWithLabelAlign,
setter: {
componentName: 'NumberSetter',
props: {
min: 0,
max: 24,
},
},
},
{
name: 'wrapperCol.span',
title: '内容宽度',
condition: showWithLabelAlign,
setter: {
componentName: 'NumberSetter',
props: {
min: 0,
max: 24,
},
},
},
{
name: 'wrapperCol.offset',
title: '内容偏移',
condition: showWithLabelAlign,
setter: {
componentName: 'NumberSetter',
props: {
min: 0,
max: 24,
},
},
},
{
name: 'labelTextAlign',
condition: showWithLabelAlign,
title: {
label: {
type: 'i18n',
zh_CN: '标签对齐',
en_US: 'Text Align',
},
tip: {
type: 'i18n',
zh_CN: '属性: labelTextAlign | 说明: 标签的左右对齐方式\n@enumdesc 左, 右',
en_US: 'prop: labelTextAlign | description: label text align',
},
},
setter: {
componentName: 'RadioGroupSetter',
props: {
options: ['left', 'right'],
},
},
defaultValue: 'right',
},
],
},
{
name: 'field',
condition: hideProp,
title: {
label: {
type: 'i18n',
zh_CN: 'Field 实例',
en_US: 'Field',
},
tip: {
type: 'i18n',
zh_CN: '属性: field | 说明: 传入 Field 实例',
en_US: 'prop: field | description: field instance',
},
docUrl:
'https://fusion.alibaba-inc.com/pc/component/basic/form#%E5%A4%8D%E6%9D%82%E5%8A%9F%E8%83%BD(Field)',
},
setter: {
componentName: 'ExpressionSetter',
},
},
{
name: 'value',
condition: hideProp,
title: {
label: {
type: 'i18n',
zh_CN: '表单值',
en_US: 'value',
},
tip: {
type: 'i18n',
zh_CN: '属性: value | 说明: 表单值',
en_US: 'prop: value | description: value instance',
},
},
setter: {
componentName: 'MixedSetter',
props: {
setters: ['JsonSetter', 'ExpressionSetter'],
},
},
},
{
name: 'size',
condition: hideProp,
title: {
label: {
type: 'i18n',
zh_CN: '尺寸',
en_US: 'Size',
},
tip: {
type: 'i18n',
zh_CN:
'属性: size | 说明: 单个 Item 的 size 自定义,优先级高于 Form 的 size, 并且当组件与 Item 一起使用时,组件自身设置 size 属性无效。\n@enumdesc 大, 中, 小',
en_US: 'prop: size | description: size',
},
},
setter: {
componentName: 'RadioGroupSetter',
props: {
options: ['large', 'medium', 'small'],
},
},
defaultValue: 'medium',
},
{
name: 'device',
condition: hideProp,
title: {
label: {
type: 'i18n',
zh_CN: '设备',
en_US: 'Device',
},
tip: {
type: 'i18n',
zh_CN: '属性: device | 说明: 预设屏幕宽度',
en_US: 'prop: device | description: device',
},
},
setter: {
componentName: 'RadioGroupSetter',
props: {
options: ['phone', 'tablet', 'desktop'],
},
},
defaultValue: 'desktop',
},
formItemsProps,
];
export default props;
================================================
FILE: packages/fusion-ui/lowcode/pro-form/common/form-item-props.ts
================================================
import React from 'react';
import { IProps } from '../../types';
import {
showWithLabelAlign,
showWithLabelAlignShortcut,
hideProp,
getParentValue,
mockId,
} from '../../utils';
const primaryKeyConfig = {
name: 'primaryKey',
title: '编号',
display: 'none',
condition: hideProp,
defaultValue: (val: any) => {
if (val) return val;
return mockId();
},
setter: 'StringSetter',
};
const columnSpanConfig = {
name: 'columnSpan',
title: '表单项宽度',
defaultValue: 1,
setter: (target) => {
const parentColumns = target.parent.getPropValue('columns');
const options = [
{
title: '一列',
value: 1,
},
{
title: '二列',
value: 2,
},
{
title: '三列',
value: 3,
},
{
title: '四列',
value: 4,
},
].slice(0, parentColumns);
return {
componentName: 'RadioGroupSetter',
props: {
options,
},
};
},
};
const labelConfig = {
name: 'label',
title: '标题',
display: 'inline',
defaultValue: '表单项',
setter: 'StringSetter',
important: true,
supportVariable: true,
};
const idConfig = {
name: 'id',
condition: hideProp,
title: {
label: {
type: 'i18n',
zh_CN: '唯一标识',
en_US: 'ID',
},
tip: {
type: 'i18n',
zh_CN: '属性: id | 说明: 唯一标识',
en_US: 'prop: id | description: switch id',
},
},
setter: 'StringSetter',
};
const nameConfig = {
name: 'name',
title: {
label: {
type: 'i18n',
zh_CN: '表单标识',
en_US: 'Name',
},
tip: {
type: 'i18n',
zh_CN: '属性: name | 说明: 表单标识,用于表单校验',
en_US: 'prop: name | description: form item name',
},
},
setter: 'StringSetter',
};
const helpConfig = {
name: 'help',
title: {
label: {
type: 'i18n',
zh_CN: '错误提示',
en_US: 'Help Info',
},
tip: {
type: 'i18n',
zh_CN: '属性: help | 说明: 自定义提示信息, 如不设置,则会根据校验规则自动生成.',
en_US: 'prop: help | description: help infomation',
},
},
setter: 'StringSetter',
};
const extraConfig = {
name: 'extra',
title: {
label: {
type: 'i18n',
zh_CN: '帮助提示',
en_US: 'Extra Info',
},
tip: {
type: 'i18n',
zh_CN:
'属性: extra | 说明: 额外的提示信息, 和 help 类似,当需要错误信息和提示文案同时出现时,可以使用这个。 位于错误信息后面',
en_US: 'prop: extra | description: extra infomation',
},
},
setter: 'StringSetter',
};
const validateStateConfig = {
name: 'validateState',
title: {
label: '校验状态',
tip: '如不设置,则会根据校验规则自动生成\n@enumdesc 失败, 成功, 校验中, 警告',
},
setter: {
componentName: 'RadioGroupSetter',
props: {
options: ['error', 'success', 'loading', 'warning'],
},
},
};
const sizeConfig = {
name: 'size',
title: {
label: '尺寸',
tip: '单个 Item 的 size 自定义,优先级高于 Form 的 size, 并且当组件与 Item 一起使用时,组件自身设置 size 属性无效。',
},
setter: {
componentName: 'RadioGroupSetter',
props: {
options: ['small', 'medium', 'large'],
},
},
defaultValue: 'medium',
};
const labelAlignConfig = {
name: 'labelAlign',
title: {
label: '标签位置',
tip: '上, 左, 内',
},
condition: hideProp,
getValue: getParentValue,
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{
title: '上',
value: 'top',
},
{
title: '左',
value: 'left',
},
{
title: '内',
value: 'inset',
},
{
title: '默认',
value: '',
},
],
},
},
};
const labelColFixedSpanConfig = {
name: 'labelCol.fixedSpan',
title: '标题宽度',
condition: showWithLabelAlign,
getValue: getParentValue,
setter: {
componentName: 'NumberSetter',
props: {
min: 0,
max: 24,
},
},
};
const labelColOffsetConfig = {
name: 'labelCol.offset',
title: '标题偏移',
condition: showWithLabelAlign,
getValue: getParentValue,
setter: {
componentName: 'NumberSetter',
props: {
min: 0,
max: 24,
},
},
};
const wrapperColSpanConfig = {
name: 'wrapperCol.span',
title: '内容宽度',
condition: showWithLabelAlign,
getValue: getParentValue,
setter: {
componentName: 'NumberSetter',
props: {
min: 0,
max: 24,
},
},
};
const wrapperColOffsetConfig = {
name: 'wrapperCol.offset',
title: '内容偏移',
condition: showWithLabelAlign,
getValue: getParentValue,
setter: {
componentName: 'NumberSetter',
props: {
min: 0,
max: 24,
},
},
};
const labelTipEnableConfig = {
name: 'labelTip.enable',
title: '标题提示',
condition: showWithLabelAlign,
setter: {
componentName: 'BoolSetter',
},
};
const labelTipContentConfig = {
name: 'labelTip.content',
title: '提示内容',
condition: showWithLabelAlign,
setter: {
componentName: 'StringSetter',
},
};
const labelTipIconConfig = {
name: 'labelTip.icon',
title: '提示图标',
condition: showWithLabelAlign,
setter: {
componentName: 'IconSetter',
},
};
const labelTextAlignConfig = {
name: 'labelTextAlign',
condition: showWithLabelAlign,
title: {
label: '标签对齐',
tip: '左, 右',
},
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{
title: '左',
value: 'left',
},
{
title: '右',
value: 'right',
},
{
title: '默认',
value: '',
},
],
},
},
defaultValue: 'right',
};
const deviceConfig = {
name: 'device',
title: {
label: '设备',
},
setter: {
componentName: 'RadioGroupSetter',
props: {
options: ['phone', 'tablet', 'desktop'],
},
},
defaultValue: 'desktop',
};
const requiredConfig = {
name: 'required',
defaultValue: false,
title: {
label: '是否必填',
tip: 'required | 是否必填',
},
setter: {
componentName: 'BoolSetter',
},
extraProps: {
setValue: (target, value) => {
if (value === true) {
const name = target.parent.getPropValue('name');
if (!name) {
target.parent.setPropValue('name', mockId());
}
}
target.parent.setValue(target.parent.getValue());
},
},
};
const fullWidthConfig = {
name: 'fullWidth',
defaultValue: true,
title: {
label: '宽度占满',
tip: '单个 Item 中表单类组件宽度是否是100%',
},
setter: {
componentName: 'BoolSetter',
},
};
const isPreviewConfig = {
name: 'isPreview',
title: {
label: '预览态',
tip: '是否开启预览态',
},
setter: 'BoolSetter',
};
const autoValidateConfig = {
name: 'autoValidate',
title: {
label: '自动校验',
tip: '是否修改数据时自动触发校验',
},
setter: 'BoolSetter',
};
const validationConfig = {
type: 'group',
name: 'validation',
display: 'accordion',
defaultCollapsed: true,
title: '校验',
items: [
{
type: 'group',
name: 'notNullValidation',
display: 'popup',
title: '非空校验',
items: [
{
name: 'required',
title: {
label: '不能为空',
tip: '[表单校验] 不能为空',
},
setter: 'BoolSetter',
},
{
name: 'requiredMessage',
title: {
label: '错误信息',
tip: '[表单校验]为空时自定义错误信息',
},
setter: 'StringSetter',
},
],
},
{
type: 'group',
name: 'maxValidation',
display: 'popup',
title: '最大/最小值校验',
items: [
{
name: 'min',
title: {
label: '最小值',
tip: '[表单校验] 最小值',
},
setter: 'NumberSetter',
},
{
name: 'max',
title: {
label: '最大值',
tip: '[表单校验] 最大值',
},
setter: 'NumberSetter',
},
{
name: 'minmaxMessage',
title: {
label: '错误信息',
tip: '[表单校验] min/max 自定义错误信息',
},
setter: 'StringSetter',
},
],
},
{
type: 'group',
name: 'maxLenValidation',
display: 'popup',
title: '最大/最小长度校验',
items: [
{
name: 'minLength',
title: {
label: '最小长度',
tip: '[表单校验] 字符串最小长度 / 数组最小个数',
},
setter: 'NumberSetter',
},
{
name: 'maxLength',
title: {
label: '最大长度',
tip: '[表单校验] 字符串最大长度 / 数组最大个数',
},
setter: 'NumberSetter',
},
{
name: 'minmaxLengthMessage',
title: {
label: '错误信息',
tip: '[表单校验] minLength/maxLength 自定义错误信息',
},
setter: 'StringSetter',
},
],
},
{
type: 'group',
name: 'lengthValidation',
display: 'popup',
title: '长度校验',
items: [
{
name: 'length',
title: {
label: '长度',
tip: '[表单校验] 字符串精确长度 / 数组精确个数',
},
setter: 'NumberSetter',
},
{
name: 'lengthMessage',
title: {
label: '错误信息',
tip: '[表单校验] minLength/maxLength 自定义错误信息',
},
setter: 'StringSetter',
},
],
},
{
type: 'group',
name: 'regValidation',
display: 'popup',
title: '正则校验',
items: [
{
name: 'pattern',
title: {
label: '正则',
tip: '[表单校验] 正则校验',
},
setter: 'StringSetter',
},
{
name: 'patternMessage',
title: {
label: '错误信息',
tip: '[表单校验] pattern 自定义错误信息',
},
setter: 'StringSetter',
},
],
},
{
type: 'group',
name: 'formatValidation',
display: 'popup',
title: '格式化校验',
items: [
{
name: 'format',
title: {
label: 'format',
tip: '[表单校验] 四种常用的 pattern',
},
setter: {
componentName: 'RadioGroupSetter',
props: {
options: ['number', 'email', 'url', 'tel'],
},
},
},
{
name: 'formatMessage',
title: {
label: '错误信息',
tip: '[表单校验] format 自定义错误信息',
},
setter: 'StringSetter',
},
],
},
{
name: 'validator',
display: 'popup',
title: {
label: '自定义校验函数',
},
setter: 'FunctionSetter',
},
],
};
const childFormConfig = {
name: 'childForm',
title: '开启子表单',
setter: {
componentName: 'SlotSetter',
initialValue: {
type: 'JSSlot',
visible: false,
value: [
{
componentName: 'ChildForm',
props: {
primaryKey: String(Math.floor(Math.random() * 10000)),
placeholder: '请在右侧面板添加表单项+',
placeholderStyle: {
height: '38px',
color: '#0088FF',
background: '#d8d8d836',
border: 0,
gridArea: 'span 4 / span 4',
},
columns: 3,
labelCol: {
fixedSpan: 4,
},
labelAlign: 'top',
emptyContent: '添加表单项',
},
children: [...new Array(3).keys()].map((item) => ({
componentName: 'FormInput',
props: {
formItemProps: {
primaryKey: String(Math.floor(Math.random() * 10000) + item),
label: '表单项',
size: 'medium',
device: 'desktop',
fullWidth: true,
},
placeholder: '请输入',
},
})),
},
],
},
},
};
export const formItemProps = [
primaryKeyConfig,
idConfig,
nameConfig,
columnSpanConfig,
labelConfig,
childFormConfig,
helpConfig,
extraConfig,
validateStateConfig,
sizeConfig,
labelAlignConfig,
labelColFixedSpanConfig,
labelColOffsetConfig,
wrapperColSpanConfig,
wrapperColOffsetConfig,
labelTipEnableConfig,
labelTipIconConfig,
labelTipContentConfig,
labelTextAlignConfig,
deviceConfig,
requiredConfig,
fullWidthConfig,
isPreviewConfig,
autoValidateConfig,
validationConfig,
];
export const formItemShortcutProps = [
primaryKeyConfig,
nameConfig,
labelConfig,
sizeConfig,
columnSpanConfig,
childFormConfig,
{
name: 'labelTip.enable',
title: '标题提示',
condition: showWithLabelAlignShortcut,
setter: {
componentName: 'BoolSetter',
},
},
{
name: 'labelTip.icon',
title: '提示图标',
condition: showWithLabelAlignShortcut,
setter: {
componentName: 'IconSetter',
},
},
{
name: 'labelTip.content',
title: '提示内容',
condition: showWithLabelAlignShortcut,
setter: {
componentName: 'StringSetter',
},
},
requiredConfig,
fullWidthConfig,
isPreviewConfig,
autoValidateConfig,
{
name: '!entry',
title: '组件详细配置',
display: 'block',
setter: (target) => {
return React.createElement(
Next.Button,
{
onClick: () => {
const { node } = target;
node.children.get(target.parent.key).select();
},
},
'点击配置',
);
},
},
];
const props: IProps[] = [
{
name: 'formItemProps',
title: '表单项配置',
extraProps: {
display: 'accordion',
defaultCollapsed: true,
},
setter: {
componentName: 'ObjectSetter',
props: {
config: {
items: formItemProps,
},
},
},
},
];
export default props;
================================================
FILE: packages/fusion-ui/lowcode/pro-form/common/props.ts
================================================
import { IProps } from '../../types';
import { operationProps } from '../../common';
import FormItemProps from './form-item-props';
import FormBaseProps from './form-base-props';
export { FormItemProps, FormBaseProps };
const props: IProps[] = [...FormBaseProps, ...operationProps];
export default props;
================================================
FILE: packages/fusion-ui/lowcode/pro-form/components/index.ts
================================================
import { default as PasswordMeta } from './password';
import { default as TextAreaMeta } from './text-area';
export default [PasswordMeta, TextAreaMeta];
================================================
FILE: packages/fusion-ui/lowcode/pro-form/components/password.ts
================================================
import { IProps } from '../../types';
import { wrapFormItemProps } from '../../utils/form-utils';
const props: IProps[] = wrapFormItemProps([
{
name: 'rows',
title: {
label: {
type: 'i18n',
zh_CN: '行数',
en_US: 'Rows',
},
tip: {
type: 'i18n',
zh_CN:
'属性: rows | 说明: 多行文本框高度
(不要直接用height设置多行文本框的高度, ie9 10会有兼容性问题)',
en_US: 'prop: rows | description: row numbers',
},
},
setter: 'NumberSetter',
supportVariable: true,
defaultValue: 4,
},
{
name: 'maxLength',
title: {
label: {
type: 'i18n',
zh_CN: '最大长度',
en_US: 'MaxLength',
},
tip: {
type: 'i18n',
zh_CN: '属性: maxLength | 说明: 最大长度',
en_US: 'prop: maxLength | description: max length',
},
},
setter: 'NumberSetter',
supportVariable: true,
description: '最大长度',
},
{
name: 'placeholder',
title: {
label: {
type: 'i18n',
zh_CN: '输入提示',
en_US: 'Placeholder',
},
tip: {
type: 'i18n',
zh_CN: '属性: placeholder | 说明: 输入提示',
en_US: 'prop: placeholder | description: placeholder',
},
},
setter: 'StringSetter',
supportVariable: true,
},
{
name: 'state',
title: {
label: {
type: 'i18n',
zh_CN: '状态',
en_US: 'State',
},
tip: {
type: 'i18n',
zh_CN: '属性: state | 说明: 状态\n@enumdesc 错误',
en_US: 'prop: state | description: input state',
},
},
setter: {
componentName: 'RadioGroupSetter',
props: {
options: ['error', 'warning'],
},
},
},
{
name: 'autoHeight',
title: {
label: {
type: 'i18n',
zh_CN: '自动高度',
en_US: 'Auto Height',
},
tip: {
type: 'i18n',
zh_CN: '属性: autoHeight | 说明: 自动高度 true / {minRows: 2, maxRows: 4}',
en_US: 'prop: autoHeight | description: auto height',
},
},
setter: 'BoolSetter',
supportVariable: true,
defaultValue: false,
},
{
name: 'isPreview',
title: {
label: {
type: 'i18n',
zh_CN: '预览态',
en_US: 'Preview',
},
tip: {
type: 'i18n',
zh_CN: '属性: isPreview | 说明: 是否为预览态',
en_US: 'prop: isPreview | description: preview',
},
},
setter: 'BoolSetter',
supportVariable: true,
defaultValue: false,
},
{
name: 'disabled',
title: {
label: {
type: 'i18n',
zh_CN: '是否禁用',
en_US: 'Disabled',
},
tip: {
type: 'i18n',
zh_CN: '属性: disabled | 说明: 是否被禁用',
en_US: 'prop: disabled | description: disabled',
},
},
setter: 'BoolSetter',
supportVariable: true,
description: '是否禁用',
},
{
name: 'hasLimitHint',
title: {
label: {
type: 'i18n',
zh_CN: '展示限制',
en_US: 'ShowLimit',
},
tip: {
type: 'i18n',
zh_CN: '属性: hasLimitHint | 说明: 是否展现最大长度样式',
en_US: 'prop: hasLimitHint | description: hasLimitHint',
},
},
setter: 'BoolSetter',
supportVariable: true,
description: '是否展现最大长度样式',
},
{
name: 'cutString',
title: {
label: {
type: 'i18n',
zh_CN: '是否截断',
en_US: 'Cut Off',
},
tip: {
type: 'i18n',
zh_CN: '属性: cutString | 说明: 是否截断超出字符串',
en_US: 'prop: cutString | description: whether cut off string',
},
},
setter: 'BoolSetter',
supportVariable: true,
description: '是否截断超出字符串',
},
{
name: 'readOnly',
title: {
label: {
type: 'i18n',
zh_CN: '是否只读',
en_US: 'ReadOnly',
},
tip: {
type: 'i18n',
zh_CN: '属性: readOnly | 说明: 是否只读',
en_US: 'prop: readOnly | description: ReadOnly',
},
},
setter: 'BoolSetter',
supportVariable: true,
description: '是否只读',
},
{
name: 'trim',
title: {
label: {
type: 'i18n',
zh_CN: '是否 Trim',
en_US: 'Trim',
},
tip: {
type: 'i18n',
zh_CN: '属性: trim | 说明: onChange返回会自动去除头尾空字符',
en_US: 'prop: trim | description: whether trim when onChange called',
},
},
setter: 'BoolSetter',
supportVariable: true,
},
{
name: 'hasBorder',
title: {
label: {
type: 'i18n',
zh_CN: '显示边框',
en_US: 'ShowBorder',
},
tip: {
type: 'i18n',
zh_CN: '属性: hasBorder | 说明: 是否有边框',
en_US: 'prop: hasBorder | description: HasBorder',
},
},
setter: 'BoolSetter',
supportVariable: true,
},
{
name: 'autoFocus',
title: {
label: {
type: 'i18n',
zh_CN: '自动聚焦',
en_US: 'Auto Focus',
},
tip: {
type: 'i18n',
zh_CN: '属性: autoFocus | 说明: 自动聚焦',
en_US: 'prop: autoFocus | description: autoFocus',
},
},
setter: 'BoolSetter',
supportVariable: true,
description: '自动聚焦',
},
{
type: 'group',
title: '高级',
display: 'block',
items: [
{
name: 'id',
title: {
label: {
type: 'i18n',
zh_CN: '唯一标识',
en_US: 'ID',
},
tip: {
type: 'i18n',
zh_CN: '属性: id | 说明: 唯一标识',
en_US: 'prop: id | description: switch id',
},
},
setter: 'StringSetter',
supportVariable: true,
},
{
name: 'name',
title: {
label: {
type: 'i18n',
zh_CN: '表单标识',
en_US: 'Name',
},
tip: {
type: 'i18n',
zh_CN: '属性: name | 说明: 表单标识',
en_US: 'prop: name | description: switch name',
},
},
setter: 'StringSetter',
supportVariable: true,
},
],
},
]);
const meta = {
componentName: 'FormPassword',
isFormItemComponent: true,
title: '密码框',
docUrl: '',
screenshot: '',
npm: {
package: '@alifd/fusion-ui',
version: '{{version}}',
exportName: 'FormPassword',
main: '',
destructuring: true,
subName: '',
},
configure: {
props,
supports: {
style: true,
events: ['onPressEnter', 'onClear', 'onChange', 'onKeyDown', 'onFocus', 'onBlur'],
},
},
icon: '',
category: '内容',
};
export default meta;
================================================
FILE: packages/fusion-ui/lowcode/pro-form/components/text-area.ts
================================================
import { IProps } from '../../types';
import { wrapFormItemProps } from '../../utils/form-utils';
const props: IProps[] = wrapFormItemProps([
{
name: 'rows',
title: {
label: {
type: 'i18n',
zh_CN: '行数',
en_US: 'Rows',
},
tip: {
type: 'i18n',
zh_CN:
'属性: rows | 说明: 多行文本框高度
(不要直接用height设置多行文本框的高度, ie9 10会有兼容性问题)',
en_US: 'prop: rows | description: row numbers',
},
},
setter: 'NumberSetter',
supportVariable: true,
defaultValue: 4,
},
{
name: 'maxLength',
title: {
label: {
type: 'i18n',
zh_CN: '最大长度',
en_US: 'MaxLength',
},
tip: {
type: 'i18n',
zh_CN: '属性: maxLength | 说明: 最大长度',
en_US: 'prop: maxLength | description: max length',
},
},
setter: 'NumberSetter',
supportVariable: true,
description: '最大长度',
},
{
name: 'placeholder',
title: {
label: {
type: 'i18n',
zh_CN: '输入提示',
en_US: 'Placeholder',
},
tip: {
type: 'i18n',
zh_CN: '属性: placeholder | 说明: 输入提示',
en_US: 'prop: placeholder | description: placeholder',
},
},
setter: 'StringSetter',
supportVariable: true,
},
{
name: 'state',
title: {
label: {
type: 'i18n',
zh_CN: '状态',
en_US: 'State',
},
tip: {
type: 'i18n',
zh_CN: '属性: state | 说明: 状态\n@enumdesc 错误',
en_US: 'prop: state | description: input state',
},
},
setter: {
componentName: 'RadioGroupSetter',
props: {
options: ['error', 'warning'],
},
},
},
{
name: 'autoHeight',
title: {
label: {
type: 'i18n',
zh_CN: '自动高度',
en_US: 'Auto Height',
},
tip: {
type: 'i18n',
zh_CN: '属性: autoHeight | 说明: 自动高度 true / {minRows: 2, maxRows: 4}',
en_US: 'prop: autoHeight | description: auto height',
},
},
setter: 'BoolSetter',
supportVariable: true,
defaultValue: false,
},
{
name: 'isPreview',
title: {
label: {
type: 'i18n',
zh_CN: '预览态',
en_US: 'Preview',
},
tip: {
type: 'i18n',
zh_CN: '属性: isPreview | 说明: 是否为预览态',
en_US: 'prop: isPreview | description: preview',
},
},
setter: 'BoolSetter',
supportVariable: true,
defaultValue: false,
},
{
name: 'disabled',
title: {
label: {
type: 'i18n',
zh_CN: '是否禁用',
en_US: 'Disabled',
},
tip: {
type: 'i18n',
zh_CN: '属性: disabled | 说明: 是否被禁用',
en_US: 'prop: disabled | description: disabled',
},
},
setter: 'BoolSetter',
supportVariable: true,
description: '是否禁用',
},
{
name: 'hasLimitHint',
title: {
label: {
type: 'i18n',
zh_CN: '展示限制',
en_US: 'ShowLimit',
},
tip: {
type: 'i18n',
zh_CN: '属性: hasLimitHint | 说明: 是否展现最大长度样式',
en_US: 'prop: hasLimitHint | description: hasLimitHint',
},
},
setter: 'BoolSetter',
supportVariable: true,
description: '是否展现最大长度样式',
},
{
name: 'cutString',
title: {
label: {
type: 'i18n',
zh_CN: '是否截断',
en_US: 'Cut Off',
},
tip: {
type: 'i18n',
zh_CN: '属性: cutString | 说明: 是否截断超出字符串',
en_US: 'prop: cutString | description: whether cut off string',
},
},
setter: 'BoolSetter',
supportVariable: true,
description: '是否截断超出字符串',
},
{
name: 'readOnly',
title: {
label: {
type: 'i18n',
zh_CN: '是否只读',
en_US: 'ReadOnly',
},
tip: {
type: 'i18n',
zh_CN: '属性: readOnly | 说明: 是否只读',
en_US: 'prop: readOnly | description: ReadOnly',
},
},
setter: 'BoolSetter',
supportVariable: true,
description: '是否只读',
},
{
name: 'trim',
title: {
label: {
type: 'i18n',
zh_CN: '是否 Trim',
en_US: 'Trim',
},
tip: {
type: 'i18n',
zh_CN: '属性: trim | 说明: onChange返回会自动去除头尾空字符',
en_US: 'prop: trim | description: whether trim when onChange called',
},
},
setter: 'BoolSetter',
supportVariable: true,
},
{
name: 'hasBorder',
title: {
label: {
type: 'i18n',
zh_CN: '显示边框',
en_US: 'ShowBorder',
},
tip: {
type: 'i18n',
zh_CN: '属性: hasBorder | 说明: 是否有边框',
en_US: 'prop: hasBorder | description: HasBorder',
},
},
setter: 'BoolSetter',
supportVariable: true,
},
{
name: 'autoFocus',
title: {
label: {
type: 'i18n',
zh_CN: '自动聚焦',
en_US: 'Auto Focus',
},
tip: {
type: 'i18n',
zh_CN: '属性: autoFocus | 说明: 自动聚焦',
en_US: 'prop: autoFocus | description: autoFocus',
},
},
setter: 'BoolSetter',
supportVariable: true,
description: '自动聚焦',
},
{
type: 'group',
title: '高级',
display: 'block',
items: [
{
name: 'id',
title: {
label: {
type: 'i18n',
zh_CN: '唯一标识',
en_US: 'ID',
},
tip: {
type: 'i18n',
zh_CN: '属性: id | 说明: 唯一标识',
en_US: 'prop: id | description: switch id',
},
},
setter: 'StringSetter',
supportVariable: true,
},
{
name: 'name',
title: {
label: {
type: 'i18n',
zh_CN: '表单标识',
en_US: 'Name',
},
tip: {
type: 'i18n',
zh_CN: '属性: name | 说明: 表单标识',
en_US: 'prop: name | description: switch name',
},
},
setter: 'StringSetter',
supportVariable: true,
},
],
},
]);
const meta = {
componentName: 'FormTextArea',
isFormItemComponent: true,
title: '多行文本框',
docUrl: '',
screenshot: '',
npm: {
package: '@alifd/fusion-ui',
version: '{{version}}',
exportName: 'FormTextArea',
main: '',
destructuring: true,
subName: '',
},
configure: {
props,
supports: {
style: true,
events: ['onPressEnter', 'onClear', 'onChange', 'onKeyDown', 'onFocus', 'onBlur'],
},
},
icon: '',
category: '内容',
};
export default meta;
================================================
FILE: packages/fusion-ui/lowcode/pro-form/meta.ts
================================================
import { IComponentDescription, ISnippet } from '../types';
import { default as props, FormItemProps } from './common/props';
import { default as ComponentsMeta } from './components';
const snippets: ISnippet[] = [
{
title: '高级表单',
screenshot:
'https://img.alicdn.com/imgextra/i2/O1CN016gn5DQ1FeXUNKdK22_!!6000000000512-55-tps-50-36.svg',
schema: {
componentName: 'ProForm',
title: '高级表单',
props: {
placeholder: '请在右侧面板添加表单项+',
placeholderStyle: {
height: '38px',
color: '#0088FF',
background: '#d8d8d836',
border: 0,
gridArea: 'span 4 / span 4',
},
columns: 4,
labelCol: {
fixedSpan: 4,
},
labelAlign: 'top',
emptyContent: '添加表单项',
},
children: [...new Array(8).keys()].map((item) => ({
componentName: 'FormInput',
props: {
formItemProps: {
primaryKey: String(Math.floor(Math.random() * 10000) + item),
label: '表单项',
size: 'medium',
device: 'desktop',
fullWidth: true,
},
placeholder: '请输入',
},
})),
},
},
];
const ProFormMeta: IComponentDescription[] = [
{
componentName: 'ProForm',
category: '表单类',
title: '高级表单',
group: '精选组件',
docUrl: '',
screenshot: '',
devMode: 'proCode',
npm: {
package: '@alifd/fusion-ui',
version: '0.1.4',
exportName: 'ProForm',
main: 'lib/index.js',
destructuring: true,
subName: '',
},
configure: {
component: {
isContainer: true,
isMinimalRenderUnit: true,
nestingRule: {
childWhitelist: new RegExp('form.*', 'i'),
},
},
supports: {
style: true,
events: ['saveField', 'onSubmit', 'onChange'],
},
props,
},
snippets,
},
{
componentName: 'ProFormItem',
title: '表单项',
docUrl: '',
screenshot:
'https://img.alicdn.com/imgextra/i2/O1CN016gn5DQ1FeXUNKdK22_!!6000000000512-55-tps-50-36.svg',
icon: 'https://img.alicdn.com/imgextra/i2/O1CN016gn5DQ1FeXUNKdK22_!!6000000000512-55-tps-50-36.svg',
devMode: 'proCode',
npm: {
package: '@alifd/fusion-ui',
version: '0.1.4',
exportName: 'ProForm',
main: 'lib/index.js',
destructuring: true,
subName: 'Item',
},
configure: {
component: {
disableBehaviors: ['copy'],
nestingRule: {
parentWhitelist: ['ProForm'],
},
},
props: FormItemProps,
supports: {
style: true,
events: ['onPressEnter', 'onClear', 'onChange', 'onKeyDown', 'onFocus', 'onBlur'],
},
advanced: {
initialChildren: [
{
componentName: 'FormInput',
props: {
hasBorder: true,
size: 'medium',
autoComplete: 'off',
},
},
],
callbacks: {
onNodeRemove: (removedNode, currentNode) => {
if (!removedNode || !currentNode) {
return;
}
const { children } = currentNode;
// 若无 children,则说明当前 P 组件内已为空,需要删除 FormItem 组件本身
if (children && children.isEmptyNode) {
currentNode.remove();
}
},
},
},
},
},
];
export default [...ProFormMeta, ...ComponentsMeta];
================================================
FILE: packages/fusion-ui/lowcode/pro-table/actionColumnFields.ts
================================================
import { IProps } from '../types/index';
import { buttonGroupConfigureProp } from '../common/button-groups';
export const actionColumnField: IProps = {
name: 'actionColumnProps',
title: '操作列',
extraProps: {
display: 'accordion',
defaultCollapsed: true,
},
setter: {
componentName: 'ObjectSetter',
props: {
display: 'drawer',
config: {
items: [
{
name: 'title',
title: '标题',
extraProps: {
display: 'inline',
defaultValue: '操作',
},
setter: {
componentName: 'StringSetter',
},
},
{
type: 'field',
name: 'width',
title: '宽度',
extraProps: {
display: 'inline',
defaultValue: 120,
},
setter: {
componentName: 'NumberSetter',
props: {
units: 'px',
},
},
},
{
name: 'lock',
title: '锁列',
display: 'inline',
initialValue: 'none',
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{
title: '左侧',
value: 'left',
tip: 'left',
},
{
title: '不锁',
value: 'none',
tip: 'none',
},
{
title: '右侧',
value: 'right',
tip: 'right',
},
],
compact: false,
},
},
},
],
},
},
},
};
export const actionColumnButtonField: IProps = {
...buttonGroupConfigureProp,
name: 'actionColumnButtons',
title: '操作列按钮',
};
================================================
FILE: packages/fusion-ui/lowcode/pro-table/columns-field.ts
================================================
import { uuid, mockProTableRow, mockId } from './utils';
import { IProps } from '../types/index';
import { hideProp, deepEqual, isJSExpression } from '../utils';
import debounce from 'lodash/debounce';
export const columnsField: IProps = {
type: 'field',
name: 'columns',
title: '数据列',
extraProps: {
display: 'accordion',
},
setValue: debounce((field, columns) => {
const _columns = isJSExpression(columns) ? columns.mock : columns;
if (!_columns || !Array.isArray(_columns) || !_columns.length) {
return;
}
const { node } = field;
const dataSource = node.getPropValue('dataSource') || [];
const _dataSource = isJSExpression(dataSource) ? dataSource.mock : dataSource;
if (!_dataSource || !Array.isArray(_dataSource) || !_dataSource.length) {
return;
}
const primaryKey = node.getPropValue('primaryKey') || 'id';
const mockRow = mockProTableRow(columns);
const newData = dataSource.map((item) => ({
[primaryKey]: mockId(),
...mockRow,
...item,
}));
if (!deepEqual(newData, dataSource)) {
node.setPropValue('dataSource', newData);
}
}),
setter: {
componentName: 'ArraySetter',
props: {
itemSetter: {
componentName: 'ObjectSetter',
props: {
config: {
items: [
{
name: 'title',
title: '标题',
display: 'inline',
initialValue: '姓名',
isRequired: true,
setter: 'StringSetter',
},
{
name: 'formatType',
title: '数据类型',
display: 'inline',
initialValue: 'text',
isRequired: true,
setter: {
componentName: 'SelectSetter',
props: {
options: [
{ value: 'text', title: '文本' },
{ value: 'number', title: '数字' },
{ value: 'money', title: '金额' },
{ value: 'date', title: '日期' },
{ value: 'phone', title: '手机号' },
// { value: 'currency', title: '币种' },
// { value: 'ou', title: 'OU编码' },
{ value: 'percent', title: '百分比' },
{ value: 'progress', title: '进度条' },
{ value: 'link', title: '链接' },
{ value: 'dialog', title: '弹窗' },
{ value: 'tag', title: '标签' },
// { value: 'textTag', title: '文字标签' },
// { value: 'files', title: '附件' },
// { value: 'bankCard', title: '银行卡号' },
// { value: 'employee', title: '员工' },
],
},
},
},
{
name: 'dataIndex',
title: '数据字段',
display: 'inline',
initialValue: (currentValue, defaultValue) =>
currentValue || defaultValue || `data-${uuid()}`,
setter: 'StringSetter',
},
{
name: 'align',
title: '对齐方式',
display: 'inline',
initialValue: 'left',
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{
value: 'left',
title: '居左',
},
{
value: 'center',
title: '居中',
},
{
value: 'right',
title: '居右',
},
],
},
},
},
{
name: 'lock',
title: '锁列',
display: 'inline',
initialValue: 'none',
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{
title: '左侧',
value: 'left',
tip: 'left',
},
{
title: '不锁',
value: 'none',
tip: 'none',
},
{
title: '右侧',
value: 'right',
tip: 'right',
},
],
compact: false,
},
},
},
// 格式化参数
{
name: 'formatOptions',
title: '格式化参数',
setter: 'ArraySetter',
condition: hideProp,
},
{
name: '_format_options_date',
title: '时间格式',
display: 'inline',
defaultValue: 'YYYY-MM-DD HH:mm:ss',
condition: (target) => {
return target.parent.getPropValue('formatType') === 'date';
},
getValue: (target) => {
const formatOptions = target.getProps().getPropValue('formatOptions') || [];
return formatOptions[0];
},
setValue: (target, value) => {
target.parent.setPropValue('formatOptions', [value]);
},
setter: {
componentName: 'SelectSetter',
props: {
options: [
{ value: 'YYYY-MM-DD HH:mm:ss', title: '年-月-日 时:分:秒' },
{ value: 'YYYY-MM-DD HH:mm', title: '年-月-日 时:分' },
{ value: 'YYYY-MM-DD', title: '年-月-日' },
{ value: 'YYYY-MM', title: '年-月' },
{ value: 'YYYY', title: '年' },
],
},
},
},
// 高级设置
{
name: 'explanation',
title: '表头说明',
display: 'inline',
initialValue: '',
setter: 'StringSetter',
},
{
name: 'width',
title: '宽度',
display: 'inline',
setter: {
componentName: 'NumberSetter',
props: {
units: [
{
type: 'px',
list: true,
},
{
type: '%',
list: true,
},
],
},
},
},
// {
// name: 'hidden',
// title: '是否隐藏',
// display: 'inline',
// initialValue: false,
// setter: 'BoolSetter',
// },
// {
// name: 'maxChars',
// title: '字数限定',
// display: 'inline',
// setter: 'NumberSetter',
// hidden() {
// return this.parent.getParam('formatType').toData() !== 'text';
// },
// },
{
name: 'sortable',
title: '列排序',
display: 'inline',
initialValue: false,
setter: 'BoolSetter',
},
{
name: 'searchable',
title: '列搜索',
display: 'inline',
initialValue: false,
setter: 'BoolSetter',
},
{
name: 'onCellClick',
condition: hideProp,
},
{
name: 'behavior',
title: '交互设置',
display: 'block',
condition: (target) => {
const formatType = target.parent.getPropValue('formatType');
return formatType && ['dialog', 'link'].includes(formatType);
},
setter: {
componentName: 'BehaviorSetter',
props: (target) => {
return {
actions: ['onCellClick'],
type: target.parent.getPropValue('formatType'),
};
},
},
},
],
},
},
initialValue: () => {
return {
title: '列标题',
formatType: 'text',
dataIndex: 'dataIndex',
};
},
},
},
},
};
================================================
FILE: packages/fusion-ui/lowcode/pro-table/global-style.ts
================================================
export const globalStyleField = {
type: 'group',
title: '全局样式',
name: 'globalStyle',
extraProps: {
display: 'accordion',
defaultCollapsed: true,
},
items: [
{
name: 'hasBorder',
title: '列分隔线',
display: 'inline',
defaultValue: false,
setter: 'BoolSetter',
},
{
name: 'isZebra',
title: '斑马线',
display: 'inline',
defaultValue: false,
setter: 'BoolSetter',
},
{
name: 'fixedHeader',
title: '固定表头',
display: 'inline',
defaultValue: false,
setter: 'BoolSetter',
},
{
name: 'size',
title: '密度',
display: 'inline',
defaultValue: 'medium',
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{
title: '紧凑',
value: 'small',
tip: 'small',
},
{
title: '正常',
value: 'medium',
tip: 'medium',
},
],
},
},
},
],
};
================================================
FILE: packages/fusion-ui/lowcode/pro-table/meta.ts
================================================
import { IAssets } from '../types/index';
import { proTableMeta } from './pro-table-meta';
const meta: IAssets = {
components: [
proTableMeta,
{
componentName: 'ProTableSlot',
title: '表格槽位',
docUrl: '',
screenshot: '',
devMode: 'proCode',
npm: {
package: '@alifd/fusion-ui',
version: '1.0.24-21',
exportName: 'ProTableSlot',
main: 'lib/index.js',
destructuring: true,
subName: '',
},
props: [
{
name: 'position',
propType: {
type: 'oneOf',
isRequired: true,
value: [
'actionBarLeft',
'actionBarRight',
'actionBarBefore',
'actionBarAfter',
'table',
],
},
description: '位置',
},
],
},
],
};
export default meta;
================================================
FILE: packages/fusion-ui/lowcode/pro-table/pro-table-meta.ts
================================================
import { mockProTableRow, mockId, getDataSourceItemSetter } from './utils';
import { IComponentDescription } from '../types/index';
import { actionColumnButtonField, actionColumnField } from './actionColumnFields';
import { isJSExpression } from '../utils';
import { columnsField } from './columns-field';
import { buttonGroupConfigureProp } from '../common/button-groups';
import { globalStyleField } from './global-style';
const positiveIntegerSetter = {
componentName: 'NumberSetter',
props: {
max: 200,
min: 1,
},
};
export const ProTableProps = [
columnsField,
{
type: 'field',
name: 'id',
title: '节点 ID',
condition: () => false,
extraProps: {},
setter: 'NodeSetter',
},
actionColumnField,
actionColumnButtonField,
{
...buttonGroupConfigureProp,
name: 'actionBarButtons',
title: '操作栏按钮',
},
{
type: 'field',
name: 'dataSource',
title: '表格数据源',
display: 'accordion',
setter: (target) => {
const columns = target.getProps().getPropValue('columns');
if (!columns || isJSExpression(columns)) {
return {
componentName: 'ExpressionSetter',
};
}
const mockRow = mockProTableRow(columns);
const primaryKey = target.getProps().getPropValue('primaryKey') || 'id';
const items = columns.map((column, index) => {
return {
title: {
label: {
type: 'i18n',
'en-US': column.dataIndex,
'zh-CN': column.title,
},
},
name: column.dataIndex,
important: index < 2,
setter: getDataSourceItemSetter(column.formatType),
defaultValue: mockRow[column.dataIndex],
};
});
return {
componentName: 'MixedSetter',
props: {
setters: [
{
componentName: 'ArraySetter',
props: {
itemSetter: {
componentName: 'ObjectSetter',
props: {
config: {
items,
},
},
initialValue: () => {
return {
...mockRow,
[primaryKey]: mockId(),
};
},
},
},
},
'ExpressionSetter',
],
},
};
},
},
{
type: 'field',
name: 'paginationProps',
title: '分页器',
extraProps: {
display: 'accordion',
defaultCollapsed: true,
},
setter: {
componentName: 'ObjectSetter',
display: 'inline',
props: {
config: {
items: [
{
type: 'field',
name: 'hidden',
title: '关闭分页',
extraProps: {
display: 'inline',
defaultValue: false,
},
setter: 'BoolSetter',
},
{
name: 'total',
title: '总行数',
setter: {
componentName: 'NumberSetter',
props: {
min: 0,
},
},
hidden() {
console.log(
'visiblevisiblevisiblevisible',
this.parent.getParam('hidden').getValue(),
);
return !this.parent.getParam('hidden').getValue();
},
},
{
name: 'current',
title: '当前页',
setter: positiveIntegerSetter,
},
{
name: 'pageSize',
title: '每页行数',
setter: [
{
componentName: 'SelectSetter',
initialValue: 10,
props: {
options: [
{
title: '5',
value: 5,
},
{
title: '10',
value: 10,
},
{
title: '20',
value: 20,
},
{
title: '50',
value: 50,
},
],
},
},
positiveIntegerSetter,
],
},
],
},
},
},
},
{
type: 'field',
name: 'rowSelection',
condition: () => false,
},
{
type: 'group',
title: '高级',
name: 'advanced',
extraProps: {
display: 'accordion',
defaultCollapsed: true,
},
items: [
{
type: 'field',
name: '!选择模式',
title: '选择模式',
display: 'inline',
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{
title: '无',
value: 'none',
tip: 'none',
},
{
title: '多选',
value: 'multiple',
tip: 'multiple',
},
{
title: '单选',
value: 'single',
tip: 'single',
},
],
},
},
defaultValue: 'none',
getValue: (target) => {
const rowSelection = target.parent.getPropValue('rowSelection');
if (!rowSelection) {
return 'none';
}
return rowSelection.mode === 'single' ? 'single' : 'multiple';
},
setValue: (field, value) => {
const { node } = field;
if (['single', 'multiple'].includes(value)) {
node.setPropValue('rowSelection', {
...node.getPropValue('rowSelection'),
mode: value,
});
} else {
node.setPropValue('rowSelection', undefined);
}
},
},
{
type: 'field',
name: 'indexColumn',
title: '开启序号列',
extraProps: {
display: 'inline',
defaultValue: false,
},
setter: {
componentName: 'BoolSetter',
},
},
{
type: 'field',
name: 'settingButtons',
title: '开启设置按钮',
extraProps: {
display: 'inline',
defaultValue: false,
},
setter: {
componentName: 'BoolSetter',
},
},
{
type: 'field',
name: 'primaryKey',
title: {
label: '数据主键',
tip: '数据主键用于区分数据中不同的行,对行选择和行编辑功能非常重要,不同的行主键值不可重复,一般采用数据库中自增 ID 字段',
},
extraProps: {
display: 'inline',
defaultValue: 'id',
condition: () => false,
},
},
{
name: 'cellDefault',
title: {
label: '单元格缺省填充',
tip: '当单元格值为空时,显示内容',
},
setter: 'StringSetter',
},
],
},
globalStyleField,
];
export const proTableMeta: IComponentDescription = {
componentName: 'ProTable',
title: '高级表格',
docUrl: '',
icon: 'https://img.alicdn.com/imgextra/i4/O1CN01z4HeA61OwhjktJNDW_!!6000000001770-55-tps-56-56.svg',
devMode: 'proCode',
group: '精选组件',
category: '表格类',
tags: ['业务组件'],
npm: {
package: '@alifd/fusion-ui',
version: '1.0.24-21',
exportName: 'ProTable',
main: 'lib/index.js',
destructuring: true,
subName: '',
},
configure: {
props: ProTableProps,
component: {
isContainer: false,
isMinimalRenderUnit: true,
nestingRule: {},
},
supports: {},
},
props: [],
snippets: [
{
title: '高级表格',
screenshot:
'https://img.alicdn.com/imgextra/i1/O1CN01R1OdLV1GgCXW0rjop_!!6000000000651-2-tps-112-112.png',
schema: {
componentName: 'ProTable',
props: {
dataSource: [
{
id: 'id-2f5DdE2b-0',
date: '2013-06-12',
percent: 1.862,
documentAmount: 2022,
currency: 'CNY',
company: '支付宝科技有限公司',
},
{
id: 'id-2f5DdE2b-1',
date: '2013-06-12',
percent: 1.862,
documentAmount: 2022,
currency: 'CNY',
company: '支付宝科技有限公司',
},
],
actionColumnButtons: {
dataSource: [
{
children: '查看',
type: 'primary',
},
{
children: '编辑',
type: 'primary',
disabled: true,
},
{
children: '删除',
type: 'primary',
},
],
text: true,
visibleButtonCount: 3,
},
actionBarButtons: {
dataSource: [
{
type: 'primary',
children: '操作一',
},
{
type: 'normal',
children: '操作二',
},
],
visibleButtonCount: 3,
},
paginationProps: {
pageSize: 20,
current: 1,
},
settingButtons: true,
columns: [
{
title: '公司',
dataIndex: 'company',
width: 160,
formatType: 'link',
searchable: true,
},
{
title: '单据金额',
dataIndex: 'documentAmount',
formatType: 'money',
},
{
title: '币种',
dataIndex: 'currency',
formatType: 'currency',
filters: [
{
label: 'CNY',
value: 'CNY',
},
{
label: 'USD',
value: 'USD',
},
{
label: 'JPY',
value: 'JPY',
},
{
label: 'HKD',
value: 'HKD',
},
],
filterMode: 'multiple',
explanation: '提示信息',
width: 110,
},
{
title: '完成进度',
dataIndex: 'percent',
formatType: 'progress',
},
{
title: '到账日期',
dataIndex: 'date',
formatType: 'date',
},
],
},
},
},
{
title: '树状表格',
screenshot:
'https://img.alicdn.com/imgextra/i1/O1CN01m4IZ481VKPwFFbDhP_!!6000000002634-2-tps-112-112.png',
schema: {
componentName: 'ProTable',
props: {
isTree: true,
dataSource: [
{
id: 'id-2f5DdE2b-0',
date: '2013-06-12',
percent: 1.862,
documentAmount: 2022,
currency: 'CNY',
company: '支付宝科技有限公司',
children: [
{
id: '2f5DdE2b-5Aee-c43c-e1db-0-0',
date: '2013-06-12',
percent: 1.862,
documentAmount: 2022,
currency: 'CNY',
company: '支付宝科技有限公司',
},
{
id: '2f5DdE2b-5Aee-c43c-e1db-0-1',
date: '2013-06-12',
percent: 1.862,
documentAmount: 2022,
currency: 'CNY',
company: '支付宝科技有限公司',
},
],
},
{
id: 'id-2f5DdE2b-1',
date: '2013-06-12',
percent: 1.862,
documentAmount: 2022,
currency: 'CNY',
company: '支付宝科技有限公司',
children: [
{
id: '2f5DdE2b-5Aee-c43c-e1db-1-0',
date: '2013-06-12',
percent: 1.862,
documentAmount: 2022,
currency: 'CNY',
company: '支付宝科技有限公司',
},
{
id: '2f5DdE2b-5Aee-c43c-e1db-1-1',
date: '2013-06-12',
percent: 1.862,
documentAmount: 2022,
currency: 'CNY',
company: '支付宝科技有限公司',
},
],
},
],
columns: [
{
title: '公司',
dataIndex: 'company',
width: 160,
formatType: 'link',
searchable: true,
},
{
title: '单据金额',
dataIndex: 'documentAmount',
formatType: 'money',
},
{
title: '币种',
dataIndex: 'currency',
formatType: 'currency',
filters: [
{
label: 'CNY',
value: 'CNY',
},
{
label: 'USD',
value: 'USD',
},
{
label: 'JPY',
value: 'JPY',
},
{
label: 'HKD',
value: 'HKD',
},
],
filterMode: 'multiple',
explanation: '提示信息',
width: 110,
},
{
title: '完成进度',
dataIndex: 'percent',
formatType: 'progress',
},
{
title: '到账日期',
dataIndex: 'date',
formatType: 'date',
},
],
},
},
},
],
};
================================================
FILE: packages/fusion-ui/lowcode/pro-table/utils.ts
================================================
import is from '@sindresorhus/is';
export const uuid = () => Math.random().toString(36).substr(-6);
export const PRO_TABLE_COLUMN_MOCK_VALUES = {
text: '这是一个文本',
number: 1234561.231,
money: 123213.1232,
date: '2021-08-18 20:52:33',
phone: '+86 13888888888',
currency: 'CNY',
ou: '34',
percent: 0.64,
progress: 0.64,
link: '这是链接',
tag: '成功',
textTag: '进行中',
files: [],
bankCard: '6226123412341234',
employee: {
img: 'https://work.alibaba-inc.com/photo/256512.40x40.jpg',
staff_id: '256512',
nickname: '乔勇',
realname: '石强',
},
};
export const mockProTableCell = (formatType) => PRO_TABLE_COLUMN_MOCK_VALUES[formatType];
export const mockId = () => `id-${uuid()}`;
export const columnMockValueKey = (formatType) => `_mock_value_${formatType}`;
export const mockProTableRow = (columns: any[]) => {
return columns
?.filter?.((vo) => vo.formatType && vo.dataIndex)
?.reduce?.((p, column) => {
const { formatType, dataIndex } = column;
const mockValue = column[columnMockValueKey(formatType)];
p[dataIndex] = is.nullOrUndefined(mockValue) ? mockProTableCell(formatType) : mockValue;
return p;
}, {});
};
export const getDataSourceItemSetter = (formatType) => {
// console.log('formatType: ', formatType);
let setter;
switch (formatType) {
case 'text':
case 'phone':
case 'link':
case 'dialog':
setter = 'StringSetter';
break;
case 'number':
case 'money':
case 'percent':
case 'currency':
case 'progress':
setter = 'NumberSetter';
break;
case 'date':
setter = 'DateSetter';
break;
default:
setter = 'StringSetter';
}
return setter;
};
================================================
FILE: packages/fusion-ui/lowcode/pro-table-slot/meta.ts
================================================
import { ComponentMetadata } from '@ali/lowcode-types';
const ProTableSlotMeta: ComponentMetadata = {
componentName: 'ProTableSlot',
title: 'ProTableSlot',
docUrl: '',
screenshot: '',
devMode: 'proCode',
npm: {
package: '@alifd/fusion-ui',
version: '0.1.6-beta.8',
exportName: 'ProTableSlot',
main: 'lib/index.js',
destructuring: true,
subName: '',
},
configure: {
props: [
{
title: {
label: {
type: 'i18n',
'en-US': 'position',
'zh-CN': '插入槽位',
},
tip: 'position | 插入槽位',
},
name: 'position',
description: '插入槽位',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
],
supports: {
style: true,
},
component: {},
},
};
export default {
...ProTableSlotMeta,
};
================================================
FILE: packages/fusion-ui/lowcode/radio-group/meta.js
================================================
import { wrapFormItemProps } from '../utils/form-utils';
export default {
componentName: 'FormRadioGroup',
isFormItemComponent: true,
title: '单选框组',
docUrl: '',
screenshot: '',
npm: {
package: '@alifd/fusion-ui',
version: '{{version}}',
exportName: 'FormRadioGroup',
main: '',
destructuring: true,
subName: '',
},
props: [
{
name: 'className',
propType: 'string',
description: '自定义类名',
},
{
name: 'style',
propType: 'object',
description: '自定义内敛样式',
},
{
name: 'name',
propType: 'string',
description: 'name',
},
{
name: 'size',
propType: {
type: 'oneOf',
value: ['large', 'medium', 'small'],
},
description: '尺寸',
defaultValue: 'medium',
},
{
name: 'shape',
propType: {
type: 'oneOf',
value: ['normal', 'button'],
},
description: '展示形态',
},
{
name: 'value',
propType: {
type: 'oneOfType',
value: ['string', 'number', 'bool'],
},
description: '选中项的值',
},
{
name: 'defaultValue',
propType: {
type: 'oneOfType',
value: ['string', 'number', 'bool'],
},
description: '默认值',
},
{
name: 'component',
propType: 'string',
description: '设置标签类型',
defaultValue: 'div',
},
{
name: 'disabled',
propType: 'bool',
description: '是否被禁用',
},
{
name: 'dataSource',
propType: 'object',
description: '可选项列表',
},
{
name: 'itemDirection',
propType: {
type: 'oneOf',
value: ['hoz', 'ver'],
},
description: '子项目的排列方式',
defaultValue: 'hoz',
},
{
name: 'isPreview',
propType: 'bool',
description: '是否为预览态',
defaultValue: false,
},
{
name: 'renderPreview',
propType: 'func',
description: '预览态模式下渲染的内容\n@param {number} value 评分值',
},
{
name: 'onChange',
propType: 'func',
description:
'选中值改变时的事件\n@param {String/Number} value 选中项的值\n@param {Event} e Dom 事件对象',
},
],
configure: {
props: wrapFormItemProps([
{
name: 'shape',
title: '展示形状',
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{ title: '默认', value: 'normal' },
{ title: '按钮', value: 'button' },
],
},
},
defaultValue: 'normal',
},
{
name: 'disabled',
title: '是否禁用',
setter: {
componentName: 'MixedSetter',
props: {
setters: ['BoolSetter', 'ExpressionSetter'],
},
},
},
{
name: 'itemDirection',
title: '排列方式',
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{ title: '水平排列', value: 'hoz' },
{ title: '垂直排列', value: 'ver' },
],
},
},
defaultValue: 'hoz',
},
{
name: 'isPreview',
title: '预览态',
setter: {
componentName: 'BoolSetter',
},
},
{
name: 'defaultValue',
title: '默认值',
defaultValue: '',
setter: {
componentName: 'MixedSetter',
props: {
setters: ['StringSetter', 'ExpressionSetter'],
},
},
},
{
name: 'dataSource',
display: 'block',
title: '选项',
setter: {
componentName: 'MixedSetter',
props: {
setters: [
{
componentName: 'ArraySetter',
props: {
itemSetter: {
componentName: 'ObjectSetter',
props: {
config: {
items: [
{
name: 'label',
title: 'label',
setter: 'StringSetter',
},
{
name: 'value',
title: 'value',
setter: 'StringSetter',
},
],
},
},
initialValue: {
label: '选项一',
value: '1',
},
},
},
},
'ExpressionSetter',
],
},
},
},
{
type: 'group',
title: '高级',
display: 'block',
items: [
{
name: 'id',
title: {
label: {
type: 'i18n',
zh_CN: '唯一标识',
en_US: 'ID',
},
tip: {
type: 'i18n',
zh_CN: '属性: id | 说明: 唯一标识',
en_US: 'prop: id | description: switch id',
},
},
setter: 'StringSetter',
},
{
name: 'name',
title: {
label: {
type: 'i18n',
zh_CN: '表单标识',
en_US: 'Name',
},
tip: {
type: 'i18n',
zh_CN: '属性: name | 说明: 表单标识',
en_US: 'prop: name | description: switch name',
},
},
setter: 'StringSetter',
},
],
},
]),
supports: {
style: true,
events: ['onChange'],
},
advanced: {
initials: [
{
name: 'dataSource',
initial: () => {
return [
{
label: '选项一',
value: '1',
},
{
label: '选项二',
value: '2',
},
{
label: '选项三',
value: '3',
},
];
},
},
],
},
},
icon: '',
category: '内容',
};
================================================
FILE: packages/fusion-ui/lowcode/range-picker/meta.js
================================================
import { wrapFormItemProps } from '../utils/form-utils';
export default {
componentName: 'FormRangePicker',
isFormItemComponent: true,
title: '日期区段选择',
docUrl: '',
screenshot: '',
npm: {
package: '@alifd/fusion-ui',
version: '{{version}}',
exportName: 'FormRangePicker',
main: '',
destructuring: true,
subName: '',
},
props: [
{
name: 'prefix',
propType: 'string',
defaultValue: 'next-',
},
{
name: 'rtl',
propType: 'bool',
defaultValue: false,
},
{
name: 'type',
propType: {
type: 'oneOf',
value: ['date', 'month', 'year'],
},
description: '日期范围类型',
defaultValue: 'date',
},
{
name: 'defaultVisibleMonth',
propType: 'func',
description: '默认展示的起始月份\n@return {MomentObject} 返回包含指定月份的 moment 对象实例',
},
{
name: 'onVisibleMonthChange',
propType: 'func',
},
{
name: 'value',
propType: 'array',
description: '日期范围值数组 [moment, moment]',
},
{
name: 'defaultValue',
propType: 'array',
description: '初始的日期范围值数组 [moment, moment]',
},
{
name: 'format',
propType: 'string',
description: '日期格式',
defaultValue: 'YYYY-MM-DD',
},
{
name: 'showTime',
propType: 'bool',
description: '是否使用时间控件,支持传入 TimePicker 的属性',
defaultValue: false,
},
{
name: 'resetTime',
propType: 'bool',
description: '每次选择是否重置时间(仅在 showTime 开启时有效)',
defaultValue: false,
},
{
name: 'disabledDate',
propType: 'func',
description:
'禁用日期函数\n@param {MomentObject} 日期值\n@param {String} view 当前视图类型,year: 年, month: 月, date: 日\n@return {Boolean} 是否禁用',
},
{
name: 'footerRender',
propType: 'func',
description: '自定义面板页脚\n@return {Node} 自定义的面板页脚组件',
},
{
name: 'onChange',
propType: 'func',
description:
'日期范围值改变时的回调 [ MomentObject|String, MomentObject|String ]\n@param {Array} value 日期值',
},
{
name: 'onOk',
propType: 'func',
description:
'点击确认按钮时的回调 返回开始时间和结束时间`[ MomentObject|String, MomentObject|String ]`\n@return {Array} 日期范围',
},
{
name: 'label',
propType: 'string',
description: '表单项内置标签',
},
{
name: 'state',
propType: {
type: 'oneOf',
value: ['error', 'loading', 'success'],
},
description: '表单项状态',
},
{
name: 'size',
propType: {
type: 'oneOf',
value: ['small', 'medium', 'large'],
},
description: '表单项尺寸',
defaultValue: 'medium',
},
{
name: 'disabled',
propType: 'bool',
description: '是否禁用',
},
{
name: 'hasClear',
propType: 'bool',
description: '是否显示清空按钮',
defaultValue: true,
},
{
name: 'visible',
propType: 'bool',
description: '弹层显示状态',
},
{
name: 'defaultVisible',
propType: 'bool',
description: '弹层默认是否显示',
defaultValue: false,
},
{
name: 'onVisibleChange',
propType: 'func',
description:
'弹层展示状态变化时的回调\n@param {Boolean} visible 弹层是否显示\n@param {String} type 触发弹层显示和隐藏的来源 okBtnClick 表示由确认按钮触发; fromTrigger 表示由trigger的点击触发; docClick 表示由document的点击触发',
},
{
name: 'popupTriggerType',
propType: {
type: 'oneOf',
value: ['click', 'hover'],
},
description: '弹层触发方式',
defaultValue: 'click',
},
{
name: 'popupAlign',
propType: 'string',
description: '弹层对齐方式, 具体含义见 OverLay文档',
defaultValue: 'tl tl',
},
{
name: 'popupContainer',
propType: 'node',
description: '弹层容器\n@param {Element} target 目标元素\n@return {Element} 弹层的容器元素',
},
{
name: 'popupClassName',
propType: 'string',
description: '弹层自定义样式类',
},
{
name: 'followTrigger',
propType: 'bool',
description: '是否跟随滚动',
},
{
name: 'startDateInputAriaLabel',
propType: 'string',
description: '开始日期表单项的 aria-label 属性',
},
{
name: 'startTimeInputAriaLabel',
propType: 'string',
description: '开始时间表单项的 aria-label 属性',
},
{
name: 'endDateInputAriaLabel',
propType: 'string',
description: '结束日期表单项的 aria-label 属性',
},
{
name: 'endTimeInputAriaLabel',
propType: 'string',
description: '结束时间表单项的 aria-label 属性',
},
{
name: 'isPreview',
propType: 'bool',
description: '是否为预览态',
},
{
name: 'locale',
propType: 'object',
},
{
name: 'className',
propType: 'string',
},
{
name: 'name',
propType: 'string',
},
{
name: 'popupComponent',
propType: 'string',
},
{
name: 'popupContent',
propType: 'node',
},
{
name: 'style',
propType: 'object',
},
],
configure: {
supports: {
style: true,
events: ['onVisibleMonthChange', 'onChange', 'onOk', 'onVisibleChange'],
},
props: wrapFormItemProps([
{
name: 'defaultValue',
title: {
label: '默认值',
tip: '初始的日期范围值数组 [moment, moment]',
},
setter: {
componentName: 'ObjectSetter',
props: {
config: {
items: [
{
name: 0,
title: '开始时间',
setter: 'DateSetter',
},
{
name: 1,
title: '结束时间',
setter: 'DateSetter',
},
],
},
},
},
},
{
name: 'type',
title: '日期类型',
setter: {
setter: 'RadioGroupSetter',
props: { options: ['date', 'month', 'year'] },
},
description: '日期范围类型',
defaultValue: 'date',
},
{
name: 'label',
title: '内置标签',
setter: 'StringSetter',
description: '表单项内置标签',
},
{
name: 'state',
title: '输入状态',
setter: {
setter: 'RadioGroupSetter',
props: { options: ['error', 'loading', 'success'] },
},
description: '表单项状态',
},
{
name: 'size',
title: '尺寸',
setter: {
setter: 'RadioGroupSetter',
props: { options: ['small', 'medium', 'large'] },
},
description: '表单项尺寸',
defaultValue: 'medium',
},
{
name: 'disabled',
setter: 'BoolSetter',
title: '是否禁用',
},
{
name: 'hasClear',
setter: 'BoolSetter',
title: '清空按钮',
defaultValue: true,
},
{
name: 'defaultVisible',
setter: 'BoolSetter',
title: '显示弹层',
defaultValue: false,
},
{
type: 'group',
title: '高级',
display: 'block',
items: [
{
name: 'id',
title: {
label: {
type: 'i18n',
zh_CN: '唯一标识',
en_US: 'ID',
},
tip: {
type: 'i18n',
zh_CN: '属性: id | 说明: 唯一标识',
en_US: 'prop: id | description: switch id',
},
},
setter: 'StringSetter',
},
{
name: 'name',
title: {
label: {
type: 'i18n',
zh_CN: '表单标识',
en_US: 'Name',
},
tip: {
type: 'i18n',
zh_CN: '属性: name | 说明: 表单标识',
en_US: 'prop: name | description: switch name',
},
},
setter: 'StringSetter',
},
],
},
]),
},
category: '内容',
icon: '',
};
================================================
FILE: packages/fusion-ui/lowcode/rating/meta.js
================================================
import { wrapFormItemProps } from '../utils/form-utils';
export default {
componentName: 'FormRating',
isFormItemComponent: true,
title: '评分',
docUrl: '',
screenshot: '',
npm: {
package: '@alifd/fusion-ui',
version: '{{version}}',
exportName: 'FormRating',
main: '',
destructuring: true,
subName: '',
},
props: [
{
name: 'id',
propType: 'string',
},
{
name: 'name',
propType: 'string',
description: 'name',
},
{
name: 'className',
propType: 'string',
},
{
name: 'style',
propType: 'object',
},
{
name: 'defaultValue',
propType: 'number',
description: '默认值',
defaultValue: 0,
},
{
name: 'value',
propType: 'number',
description: '值',
},
{
name: 'size',
propType: {
type: 'oneOf',
value: ['small', 'medium', 'large'],
},
description: '尺寸',
defaultValue: 'medium',
},
{
name: 'count',
propType: 'number',
description: '评分的总数',
defaultValue: 5,
},
{
name: 'showGrade',
propType: 'bool',
description: '是否显示 grade',
defaultValue: false,
},
{
name: 'allowHalf',
propType: 'bool',
description: '是否允许半星评分',
defaultValue: false,
},
{
name: 'disabled',
propType: 'bool',
description: '是否禁用',
defaultValue: false,
},
{
name: 'rtl',
propType: 'bool',
},
{
name: 'isPreview',
propType: 'bool',
description: '是否为预览态',
defaultValue: false,
},
{
name: 'renderPreview',
propType: 'func',
description: '预览态模式下渲染的内容',
},
{
name: 'readOnly',
propType: 'bool',
description: '是否为只读态,效果上同 disabeld',
defaultValue: false,
},
{
name: 'onChange',
propType: 'func',
description: '用户点击评分时触发的回调\n@param {String} value 评分值',
},
{
name: 'onHoverChange',
propType: 'func',
description: '用户hover评分时触发的回调\n@param {String} value 评分值',
},
],
configure: {
props: wrapFormItemProps([
{
name: 'value',
title: '当前值',
setter: ['NumberSetter', 'ExpressionSetter'],
},
{
name: 'defaultValue',
title: '默认值',
setter: ['NumberSetter', 'ExpressionSetter'],
},
{
name: 'size',
title: {
label: {
type: 'i18n',
zh_CN: '尺寸',
en_US: 'Size',
},
tip: {
type: 'i18n',
zh_CN: '属性: size | 说明: 尺寸\n@enumdesc 小, 中, 大',
en_US: 'prop: size | description: size',
},
},
setter: {
componentName: 'RadioGroupSetter',
props: {
options: ['small', 'medium', 'large'],
},
},
defaultValue: 'medium',
},
{
name: 'count',
title: '评分总数',
setter: ['NumberSetter', 'ExpressionSetter'],
},
{
name: 'allowHalf',
title: '半星评分',
setter: ['BoolSetter', 'ExpressionSetter'],
},
{
name: 'showGrade',
title: '显示分数',
setter: ['BoolSetter', 'ExpressionSetter'],
},
{
name: 'readAs',
title: '评分文案生成方法',
display: 'block',
setter: {
componentName: 'FunctionSetter',
// props: {
// defaultActionName="readAs",
// defaultCode=`function readAs(val) {
// return val + 'source';
// }`,
// }
},
},
{
type: 'group',
title: '高级',
display: 'block',
items: [
{
name: 'id',
title: {
label: {
type: 'i18n',
zh_CN: '唯一标识',
en_US: 'ID',
},
tip: {
type: 'i18n',
zh_CN: '属性: id | 说明: 唯一标识',
en_US: 'prop: id | description: switch id',
},
},
setter: 'StringSetter',
},
{
name: 'name',
title: {
label: {
type: 'i18n',
zh_CN: '表单标识',
en_US: 'Name',
},
tip: {
type: 'i18n',
zh_CN: '属性: name | 说明: 表单标识',
en_US: 'prop: name | description: switch name',
},
},
setter: 'StringSetter',
},
],
},
]),
supports: {
style: true,
events: ['onChange', 'onHoverChange'],
},
},
icon: '',
category: '内容',
};
================================================
FILE: packages/fusion-ui/lowcode/rating/snippets.js
================================================
module.exports = [
{
title: '评分',
screenshot:
'https://alifd.oss-cn-hangzhou.aliyuncs.com/fusion-cool/icons/icon-light/ic_light_rating.png',
schema: {
componentName: 'Rating',
props: {
prefix: 'next-',
count: 5,
size: 'medium',
},
},
},
];
================================================
FILE: packages/fusion-ui/lowcode/select/meta.js
================================================
import { wrapFormItemProps } from '../utils/form-utils';
export default {
componentName: 'FormSelect',
isFormItemComponent: true,
title: '选择器',
docUrl: '',
screenshot: '',
npm: {
package: '@alifd/fusion-ui',
version: '{{version}}',
exportName: 'FormSelect',
main: '',
destructuring: true,
subName: '',
},
configure: {
props: wrapFormItemProps([
{
name: 'placeholder',
title: {
label: '占位提示',
tip: '属性: placeholder',
},
defaultValue: '请选择', // 不生效
setter: 'StringSetter',
},
{
name: 'hasClear',
title: {
label: '清除按钮',
tip: '属性: hasClear',
},
setter: 'BoolSetter',
defaultValue: false,
},
{
name: 'showSearch',
title: {
label: '可搜索',
tip: '属性: showSearch',
},
setter: 'BoolSetter',
defaultValue: false,
},
{
name: 'dataSource',
display: 'block',
title: '选项',
tip: {
title: '数据格式',
url: '',
},
setter: {
componentName: 'MixedSetter',
props: {
setters: [
{
componentName: 'ArraySetter',
props: {
itemSetter: {
componentName: 'ObjectSetter',
props: {
config: {
items: [
{
name: 'label',
title: 'label',
setter: 'StringSetter',
},
{
name: 'value',
title: 'value',
setter: 'StringSetter',
},
],
},
},
initialValue: {
title: 'Title',
},
},
},
},
'ExpressionSetter',
],
},
},
},
{
name: 'mode',
title: {
label: '模式',
tip: '属性: mode',
},
setter: {
componentName: 'RadioGroupSetter',
props: {
defaultValue: 'single',
options: [
{ value: 'single', title: '单选' },
{ value: 'multiple', title: '多选' },
{ value: 'tag', title: '标签' },
],
},
},
},
{
type: 'group',
title: '其他配置',
display: 'block',
items: [
{
name: 'notFoundContent',
title: {
label: '空文案',
tip: 'notFoundContent|弹层内容为空的文案',
},
setter: 'StringSetter',
},
{
name: 'hasBorder',
title: {
label: '边框',
tip: '是否有边框',
},
setter: 'BoolSetter',
},
{
name: 'autoWidth',
title: '下拉等宽',
setter: 'BoolSetter',
},
{
name: 'hasArrow',
title: '下拉箭头',
setter: 'BoolSetter',
defaultValue: true,
},
],
},
{
type: 'group',
title: '高级',
display: 'block',
items: [
{
name: 'id',
title: {
label: {
type: 'i18n',
zh_CN: '唯一标识',
en_US: 'ID',
},
tip: {
type: 'i18n',
zh_CN: '属性: id | 说明: 唯一标识',
en_US: 'prop: id | description: switch id',
},
},
setter: 'StringSetter',
},
{
name: 'name',
title: {
label: {
type: 'i18n',
zh_CN: '表单标识',
en_US: 'Name',
},
tip: {
type: 'i18n',
zh_CN: '属性: name | 说明: 表单标识',
en_US: 'prop: name | description: switch name',
},
},
setter: 'StringSetter',
},
],
},
]),
supports: {
style: true,
events: [
{
name: 'onChange',
propType: 'func',
description: '值发生变化',
},
{
name: 'onVisibleChange',
propType: 'func',
description: '弹层显示隐藏变化',
},
{
name: 'onRemove',
propType: 'func',
description: 'Tag 被删除',
},
{
name: 'onSearch',
propType: 'func',
description: '搜索',
},
],
},
},
icon: '',
category: '内容',
};
================================================
FILE: packages/fusion-ui/lowcode/select/snippets.js
================================================
module.exports = [
{
title: '选择器',
screenshot:
'https://alifd.oss-cn-hangzhou.aliyuncs.com/fusion-cool/icons/icon-light/ic_light_select.png',
schema: {
componentName: 'Select',
props: {
mode: 'single',
hasArrow: true,
cacheValue: true,
dataSource: [
{
value: '1',
label: '选项1',
},
{
value: '2',
label: '选项2',
},
{
value: '3',
label: '选项3',
},
],
},
},
},
];
================================================
FILE: packages/fusion-ui/lowcode/step-form/meta.ts
================================================
import { operationConfig } from '../common';
import { IComponentDescription, ISnippet } from '../types';
import { hideProp } from '../utils';
import stepProps, { operations } from './step-props';
const snippets: ISnippet[] = [
{
title: '步骤表单',
screenshot:
'https://img.alicdn.com/imgextra/i4/O1CN01HFWZfM24k4gYve7im_!!6000000007428-55-tps-56-56.svg',
schema: {
componentName: 'StepForm',
props: {
current: 0,
operations: [
{
content: '上一步',
action: 'previous',
type: 'secondary',
},
{
content: '下一步',
action: 'next',
type: 'primary',
},
],
},
children: [
{
componentName: 'ProForm',
props: {
stepItemProps: {
title: 'StepItem',
},
},
children: [...new Array(3).keys()].map((item) => ({
componentName: 'FormInput',
props: {
formItemProps: {
primaryKey: String(Math.floor(Math.random() * 10000) + item),
label: '表单项',
size: 'medium',
device: 'desktop',
fullWidth: true,
},
placeholder: '请输入',
},
})),
},
{
componentName: 'ProForm',
props: {
stepItemProps: {
title: 'StepItem',
},
},
children: [
{
componentName: 'ProFormItem',
props: {
primaryKey: String(Math.floor(Math.random() * 10000)),
label: '表单项',
size: 'medium',
device: 'desktop',
},
},
{
componentName: 'ProFormItem',
props: {
primaryKey: String(Math.floor(Math.random() * 10000)),
label: '表单项',
size: 'medium',
device: 'desktop',
},
},
{
componentName: 'ProFormItem',
props: {
primaryKey: String(Math.floor(Math.random() * 10000)),
label: '表单项',
size: 'medium',
device: 'desktop',
},
},
],
},
],
},
},
];
const ProFormMeta: IComponentDescription[] = [
{
componentName: 'StepForm',
category: '表单类',
title: '步骤表单',
group: '精选组件',
docUrl: '',
screenshot: '',
devMode: 'procode',
npm: {
package: '@alifd/fusion-ui',
version: '0.1.4',
exportName: 'StepForm',
main: 'lib/index.js',
destructuring: true,
subName: '',
},
configure: {
component: {
isContainer: false,
},
supports: {
style: true,
events: ['saveField', 'onSubmit', 'onChange'],
},
props: [...stepProps, operationConfig, operations],
},
snippets,
},
{
componentName: 'Step.Item',
title: '步骤项',
docUrl: '',
screenshot: '',
npm: {
package: '@alifd/next',
version: '{{version}}',
exportName: 'Step',
main: '',
destructuring: true,
subName: 'Item',
},
props: [
{
name: 'icon',
propType: 'string',
description: '图标',
},
{
name: 'title',
propType: {
type: 'instanceOf',
value: 'node',
},
defaultValue: '步骤项',
description: '标题',
},
{
name: 'content',
title: {
label: '内容',
tip: 'content|内容填充, shape为 arrow 时无效',
},
propType: {
type: 'instanceOf',
value: 'node',
},
description: '内容填充, shape为 arrow 时无效',
},
{
name: 'status',
title: {
label: '状态',
tip: 'status|步骤的状态,如不传,会根据外层的 Step 的 current 属性生成,可选值为 `wait`, `process`, `finish`',
},
propType: {
type: 'oneOf',
value: ['wait', 'process', 'finish'],
},
description:
'步骤的状态,如不传,会根据外层的 Step 的 current 属性生成,可选值为 `wait`, `process`, `finish`',
},
{
name: 'percent',
propType: 'number',
description: '百分比',
},
{
name: 'disabled',
propType: 'bool',
description: '是否禁用',
},
{
name: 'onClick',
propType: 'func',
description: '点击步骤时的回调\n@param {Number} index 节点索引',
},
{
name: 'className',
propType: 'string',
description: '自定义样式',
},
{
name: 'style',
propType: 'object',
},
],
configure: {
props: {
isExtends: true,
override: [
{
name: 'icon',
title: {
label: '图标',
tip: 'icon|图标',
},
setter: {
componentName: 'IconSetter',
},
},
{
name: 'title',
setter: {
componentName: 'StringSetter',
},
defaultValue: '步骤项',
title: '标题',
},
{
name: 'content',
condition: hideProp,
title: {
label: '内容',
tip: 'content|内容',
},
setter: {
componentName: 'TextAreaSetter',
},
},
{
name: 'status',
title: {
label: '状态',
tip: 'status|状态',
},
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{
title: '等待',
value: 'wait',
},
{
title: '进行中',
value: 'process',
},
{
title: '结束',
value: 'finish',
},
{
title: '默认',
value: '',
},
],
},
},
},
],
},
},
category: 'null',
icon: '',
},
];
export default ProFormMeta;
================================================
FILE: packages/fusion-ui/lowcode/step-form/step-props.ts
================================================
import { hideProp } from '../utils';
export default [
{
name: '!items',
title: '步骤项',
setter: {
componentName: 'ArraySetter',
props: {
itemSetter: {
componentName: 'ObjectSetter',
props: {
config: {
items: [
{
name: 'icon',
title: '图标',
important: true,
setter: 'IconSetter',
},
{
name: 'title',
title: '标题',
important: true,
setter: 'StringSetter',
},
{
name: 'status',
title: {
label: '状态',
tip: '步骤的状态,如不传,会根据外层的 Step 的 current 属性生成,可选值为 `wait`, `process`, `finish`',
},
setter: {
componentName: 'RadioGroupSetter',
props: { options: ['wait', 'process', 'finish'] },
},
},
{
name: 'content',
title: {
label: '内容',
tip: 'content|内容填充, shape为 arrow 时无效',
},
condition: hideProp,
setter: 'TextAreaSetter',
description: '内容填充, shape为 arrow 时无效',
},
{
name: 'percent',
title: '百分比',
setter: 'NumberSetter',
description: '百分比',
},
{
name: 'disabled',
title: '是否禁用',
setter: 'BoolSetter',
description: '是否禁用',
},
],
},
},
initialValue: () => {
return {
primaryKey: String(Math.floor(Math.random() * 10000)),
title: 'StepItem',
};
},
},
},
},
getValue(target) {
// const node = target.node;
// const children = node.children;
const map = target.node.children.map((child) => {
const stepItemProps = child.getPropValue('stepItemProps') || {};
const primaryKey = stepItemProps.primaryKey ? stepItemProps.primaryKey : child.id;
return {
...stepItemProps,
primaryKey,
};
});
return map;
},
setValue(target, value) {
const { node } = target;
const map = {};
if (!Array.isArray(value)) {
value = [];
}
value.forEach((item) => {
const tabitem = Object.assign({}, item);
map[item.primaryKey] = tabitem;
});
node.children.mergeChildren(
(child) => {
const primaryKey = String(child.getPropValue('primaryKey'));
if (Object.hasOwnProperty.call(map, primaryKey)) {
child.setPropValue('stepItemProps', map[primaryKey]);
delete map[primaryKey];
return false;
}
return true;
},
() => {
const items = [];
for (const primaryKey in map) {
if (Object.hasOwnProperty.call(map, primaryKey)) {
items.push({
componentName: 'ProForm',
props: {
columns: 1,
primaryKey,
stepItemProps: map[primaryKey],
},
children: [...new Array(3).keys()].map((item) => ({
componentName: 'FormInput',
props: {
formItemProps: {
primaryKey: String(Math.floor(Math.random() * 10000) + item),
label: '表单项',
size: 'medium',
device: 'desktop',
fullWidth: true,
},
placeholder: '请输入',
},
})),
});
}
}
return items;
},
(child1, child2) => {
const a = value.findIndex(
(item) => String(item.primaryKey) === String(child1.getPropValue('primaryKey')),
);
const b = value.findIndex(
(item) => String(item.primaryKey) === String(child2.getPropValue('primaryKey')),
);
return a - b;
},
);
},
},
{
name: 'current',
setter: (target) => {
return {
componentName: 'MixedSetter',
props: {
setters: [
{
componentName: 'SelectSetter',
props: () => {
const items = target.getProps().getPropValue('!items') || [];
return {
options: items.map((item, index: number) => {
return {
title: `第 ${index + 1} 步: ${item.title}`,
value: `${index}`,
};
}),
};
},
},
'ExpressionSetter',
],
},
};
},
setValue: (target, value) => {
target.parent.setPropValue('current', +value);
},
title: '当前步骤',
defaultValue: 0,
},
{
name: 'shape',
title: '类型',
setter: (target) => {
const options =
target.getProps().getPropValue('direction') === 'ver'
? ['circle', 'dot']
: ['circle', 'arrow', 'dot'];
return {
componentName: 'RadioGroupSetter',
props: {
options,
},
};
},
defaultValue: 'circle',
},
{
name: 'direction',
condition: (target) => {
return target.getProps().getPropValue('shape') !== 'arrow';
},
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{ value: 'hoz', title: '横向' },
{ value: 'ver', title: '纵向' },
],
},
},
title: '展示方向',
defaultValue: 'hoz',
},
{
name: 'showAll',
condition: (target) => {
return target.getProps().getPropValue('direction') === 'ver';
},
title: '展示所有表单',
setter: {
componentName: 'BoolSetter',
},
},
{
name: 'labelPlacement',
condition: hideProp,
setter: {
componentName: 'RadioGroupSetter',
props: {
options: ['hoz', 'ver'],
},
},
title: '内容排列',
defaultValue: 'ver',
},
{
name: 'readOnly',
setter: 'BoolSetter',
title: '是否只读',
},
{
name: 'animation',
setter: 'BoolSetter',
title: '开启动效',
defaultValue: true,
},
];
export const operations = {
name: 'operations',
display: 'block',
title: '操作项',
getValue: (target, value) => {
return value || [];
},
setter: {
componentName: 'MixedSetter',
props: {
setters: [
{
componentName: 'SlotSetter',
defaultValue: {
type: 'JSSlot',
value: [],
},
},
{
componentName: 'ArraySetter',
props: {
itemSetter: {
componentName: 'ObjectSetter',
props: {
config: {
items: [
{
name: 'content',
display: 'inline',
title: '文本',
setter: 'StringSetter',
important: true,
extraProps: {
supportVariable: true,
},
},
{
name: 'action',
display: 'inline',
title: '操作',
important: true,
setValue: (target, value) => {
const actionNameMap = {
submit: '提交',
reset: '重置',
custom: '自定义',
};
const actionName = actionNameMap[value] || '自定义';
target.parent.setPropValue('content', actionName);
},
setter: {
componentName: 'SelectSetter',
props: {
options: [
{
title: '提交',
value: 'submit',
action: 'submit',
},
{
title: '重置',
value: 'reset',
action: 'reset',
},
{
title: '上一步',
value: 'previous',
action: 'previous',
},
{
title: '下一步',
value: 'next',
action: 'next',
},
{
title: '自定义',
value: 'custom',
},
],
},
},
},
{
name: 'type',
display: 'inline',
title: '样式',
important: true,
setter: {
componentName: 'SelectSetter',
props: {
options: [
{
title: '主要',
value: 'primary',
},
{
title: '次要',
value: 'secondary',
},
{
title: '普通',
value: 'normal',
},
],
},
},
},
{
name: 'behavior',
title: '交互设置',
display: 'block',
condition: (target) => {
const action = target.parent.getPropValue('action');
return !action || action === 'custom';
},
setter: {
componentName: 'BehaviorSetter',
props: {
actions: ['onClick'],
},
},
},
{
name: 'onClick',
display: 'inline',
title: '点击事件',
condition: hideProp,
setter: 'FunctionSetter',
extraProps: {
supportVariable: true,
},
},
{
name: 'htmlType',
condition: hideProp,
},
{
name: '!autoSubmit',
display: 'inline',
virtual: true,
title: '自动提交',
setter: {
componentName: 'BoolSetter',
},
extraProps: {
setValue: (target, value) => {
target.parent.setPropValue('htmlType', value ? 'submit' : '');
},
getValue: (target, value) => {
return value === 'submit';
},
},
condition: (target) => {
return target.parent.getPropValue('action') !== 'submit';
},
},
],
},
},
initialValue: () => {
return {
content: '提交',
action: 'submit',
type: 'secondary',
};
},
},
},
},
],
},
},
};
================================================
FILE: packages/fusion-ui/lowcode/story-placeholder/meta.ts
================================================
import { IPublicModelNode } from '@alilc/lowcode-types';
import { IComponentDescription, ISnippet } from '../types';
const snippets: ISnippet[] = [
{
title: '需求占位',
screenshot: 'https://img.alicdn.com/tfs/TB160cKkP39YK4jSZPcXXXrUFXa-112-64.png',
schema: {
title: '需求占位',
componentName: 'StoryPlaceholder',
props: {
title: '需求占位描述',
content: {
subject: '需求标题',
hideTitle: false,
description:
'- 你可以在这里描述需求
- 或者粘贴需求截图
',
},
},
},
},
];
interface INode extends IPublicModelNode {
startRect: any;
beforeSpan: number;
parentRect: any;
}
const meta: IComponentDescription = {
componentName: 'StoryPlaceholder',
title: '需求占位',
npm: {
package: '@alifd/fusion-ui',
version: 'latest',
exportName: 'StoryPlaceholder',
main: '',
destructuring: true,
subName: '',
},
configure: {
supports: {
style: true,
},
props: [
{
name: 'maxHeight',
title: '最大高度',
propType: 'number',
setter: 'NumberSetter',
description: '最大高度',
},
{
name: 'content',
title: '需求关联',
display: 'inline',
supportVariable: true,
setter: {
componentName: 'EditSetter',
props: {
title: '编辑内容',
},
},
},
],
},
advanced: {
getResizingHandlers: () => {
return ['e'];
},
callbacks: {
onResizeStart: (e, currentNode: INode) => {
const parent = currentNode.parent;
if (parent) {
const parentNode = parent.getDOMNode();
if (parentNode) {
currentNode.parentRect = parentNode.getBoundingClientRect();
}
}
currentNode.beforeSpan = currentNode.getPropValue('colSpan') || 12;
currentNode.startRect = currentNode.getRect();
},
onResize: (e, currentNode: INode) => {
const { deltaX } = e;
const startWidth = currentNode.startRect
? currentNode.startRect.width
: currentNode.beforeSpan * (currentNode.parentRect.width / 12);
let width = startWidth + deltaX;
if (!currentNode.startRect) {
currentNode.startRect = {
width,
};
}
width = Math.max(0, width); // 不能小于0
width = Math.min(width, currentNode.parentRect.width); // 不能大于父容器宽度
currentNode.getDOMNode().style.width = `${Math.round(width)}px`;
},
onResizeEnd: (e, currentNode) => {
currentNode.setPropValue('style.width', currentNode.getDOMNode().style.width);
},
},
},
icon: 'https://img.alicdn.com/imgextra/i3/O1CN01G7Lc8e1pZL7p4cdKc_!!6000000005374-2-tps-112-112.png',
category: '基础元素',
group: '精选组件',
hidden: true,
};
export default {
...meta,
snippets,
};
================================================
FILE: packages/fusion-ui/lowcode/tab-container/meta.ts
================================================
import { ComponentMetadata, Snippet } from '@ali/lowcode-types';
import props from './props';
const snippets: Snippet[] = [
{
title: '选项卡',
screenshot:
'https://img.alicdn.com/imgextra/i4/O1CN01mh9LPG268B90t8DaA_!!6000000007616-55-tps-56-56.svg',
schema: {
componentName: 'TabContainer',
props: {
shape: 'pure',
size: 'medium',
excessMode: 'slide',
},
children: [
{
componentName: 'TabContainer.Item',
props: {
title: '标签项1',
primaryKey: 'tab-item-1',
},
},
{
componentName: 'TabContainer.Item',
props: {
title: '标签项2',
primaryKey: 'tab-item-2',
},
},
],
},
},
];
const tabItemMeta = {
componentName: 'TabContainer.Item',
title: '选项卡',
docUrl: '',
screenshot: '',
devMode: 'proCode',
npm: {
package: '@alifd/fusion-ui',
version: '{{version}}',
exportName: 'TabContainer',
main: 'lib/index.js',
destructuring: true,
subName: 'Item',
},
configure: {
props: [
{
title: {
label: {
type: 'i18n',
'en-US': 'title',
'zh-CN': '选项卡标题',
},
tip: 'title | 选项卡标题',
},
name: 'title',
description: '选项卡标题',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'closeable',
'zh-CN': '单个选项卡是否可关闭',
},
tip: 'closeable | 单个选项卡是否可关闭',
},
name: 'closeable',
description: '单个选项卡是否可关闭',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'disabled',
'zh-CN': '选项卡是否被禁用',
},
tip: 'disabled | 选项卡是否被禁用',
},
name: 'disabled',
description: '选项卡是否被禁用',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'prefix',
'zh-CN': '样式类名的品牌前缀',
},
tip: 'prefix | 样式类名的品牌前缀',
},
name: 'prefix',
description: '样式类名的品牌前缀',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'locale',
'zh-CN': '国际化文案对象,属性',
},
tip: 'locale | 国际化文案对象,属性为组件的 displayName',
},
name: 'locale',
description: '国际化文案对象,属性为组件的 displayName',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'pure',
'zh-CN': '是否开启 Pure ',
},
tip: 'pure | 是否开启 Pure Render 模式,会提高性能,但是也会带来副作用',
},
name: 'pure',
description: '是否开启 Pure Render 模式,会提高性能,但是也会带来副作用',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'warning',
'zh-CN': '是否在开发模式下显示',
},
tip: 'warning | 是否在开发模式下显示组件属性被废弃的 warning 提示',
},
name: 'warning',
description: '是否在开发模式下显示组件属性被废弃的 warning 提示',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'rtl',
'zh-CN': '是否开启 rtl 模',
},
tip: 'rtl | 是否开启 rtl 模式',
},
name: 'rtl',
description: '是否开启 rtl 模式',
setter: {
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
},
],
supports: {
events: [
{
name: 'onClick',
},
{
name: 'onChange',
},
],
style: true,
},
component: {
isContainer: true,
disableBehaviors: '*',
},
advanced: {
hideSelectTools: true,
callbacks: {
onMouseDownHook: () => false,
onClickHook: () => false,
},
},
},
};
const TabContainerMeta: ComponentMetadata[] = [
{
componentName: 'TabContainer',
title: '选项卡',
category: '布局容器类',
group: '精选组件',
docUrl: '',
screenshot:
'https://img.alicdn.com/imgextra/i4/O1CN01mh9LPG268B90t8DaA_!!6000000007616-55-tps-56-56.svg',
devMode: 'proCode',
npm: {
package: '@alifd/fusion-ui',
version: '{{version}}',
exportName: 'TabContainer',
main: 'lib/index.js',
destructuring: true,
subName: '',
},
configure: {
component: {
isContainer: true,
nestingRule: {
childWhitelist: ['TabContainer.Item'],
},
},
props,
supports: {
style: true,
},
},
snippets,
},
tabItemMeta,
// compatible with the exsting json schema which has componentName: Tab.Item
{
...tabItemMeta,
componentName: 'Tab.Item',
}
];
export default TabContainerMeta;
================================================
FILE: packages/fusion-ui/lowcode/tab-container/props.ts
================================================
export default [
{
name: 'items',
title: '标签项',
setter: {
componentName: 'ArraySetter',
props: {
itemSetter: {
componentName: 'ObjectSetter',
props: {
config: {
items: [
{
name: 'title',
title: '名称',
defaultValue: '标签项',
important: true,
setter: 'StringSetter',
},
{
name: 'primaryKey',
title: '项目编号',
condition: () => false,
setter: 'StringSetter',
},
{
name: 'closeable',
title: '可关闭',
initialValue: false,
setter: 'BoolSetter',
},
{
name: 'disabled',
title: '是否禁用',
initialValue: false,
setter: 'BoolSetter',
},
],
},
},
initialValue: () => {
return {
primaryKey: String(Math.floor(Math.random() * 10000)),
title: '标签项',
closeable: false,
disabled: false,
};
},
},
},
},
extraProps: {
getValue(target) {
const map = target.node.children.map((child) => {
const primaryKey = child.getPropValue('primaryKey')
? String(child.getPropValue('primaryKey'))
: child.id;
return {
primaryKey,
title: child.getPropValue('title') || '标签项',
closeable: child.getPropValue('closeable'),
disabled: child.getPropValue('disabled'),
};
});
return map;
},
setValue(target, value) {
const { node } = target;
const map = {};
if (!Array.isArray(value)) {
value = [];
}
value.forEach((item) => {
const tabitem = Object.assign({}, item);
map[item.primaryKey] = tabitem;
});
node.children.mergeChildren(
(child) => {
const primaryKey = String(child.getPropValue('primaryKey'));
if (Object.hasOwnProperty.call(map, primaryKey)) {
child.setPropValue('title', map[primaryKey].title);
child.setPropValue('closeable', map[primaryKey].closeable);
child.setPropValue('disabled', map[primaryKey].disabled);
delete map[primaryKey];
return false;
}
return true;
},
() => {
const items = [];
for (const primaryKey in map) {
if (Object.hasOwnProperty.call(map, primaryKey)) {
items.push({
componentName: 'TabContainer.Item',
props: map[primaryKey],
});
}
}
return items;
},
(child1, child2) => {
const a = value.findIndex(
(item) => String(item.primaryKey) === String(child1.getPropValue('primaryKey')),
);
const b = value.findIndex(
(item) => String(item.primaryKey) === String(child2.getPropValue('primaryKey')),
);
return a - b;
},
);
},
},
},
{
name: 'shape',
title: '形态',
defaultValue: 'pure',
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{ title: '普通型', value: 'pure' },
{ title: '包裹型', value: 'wrapped' },
{ title: '文本型', value: 'text' },
{ title: '胶囊型', value: 'capsule' },
],
},
},
},
{
name: 'size',
title: '尺寸',
defaultValue: 'medium',
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{ title: '小', value: 'small' },
{ title: '中', value: 'medium' },
],
},
},
},
{
name: 'excessMode',
title: '选项卡过多时的滑动模式',
defaultValue: 'slide',
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{ title: '滑动', value: 'slide' },
{ title: '下拉', value: 'dropdown' },
],
},
},
},
{
name: 'tabPosition',
title: {
label: '导航选项卡的位置',
tip: '只适用于包裹型(wrapped)选项卡',
},
condition: (target) => {
const shape = target.getProps().getPropValue('shape');
return shape === 'wrapped';
},
defaultValue: 'top',
setter: {
componentName: 'RadioGroupSetter',
props: {
options: [
{
title: '顶部',
value: 'top',
},
{
title: '底部',
value: 'bottom',
},
{
title: '左边',
value: 'left',
},
{
title: '右边',
value: 'right',
},
],
},
},
},
];
================================================
FILE: packages/fusion-ui/lowcode/tree-select/meta.js
================================================
import { wrapFormItemProps } from '../utils/form-utils';
export default {
componentName: 'FormTreeSelect',
isFormItemComponent: true,
title: '树型选择控件',
docUrl: '',
screenshot: '',
npm: {
package: '@alifd/fusion-ui',
version: '{{version}}',
exportName: 'FormTreeSelect',
main: '',
destructuring: true,
subName: '',
},
configure: {
props: wrapFormItemProps([
{
name: 'placeholder',
title: {
label: '占位提示',
tip: '属性: placeholder',
},
defaultValue: '请选择', // 不生效
setter: 'StringSetter',
},
{
name: 'hasClear',
title: {
label: '清除按钮',
tip: '属性: hasClear',
},
setter: 'BoolSetter',
defaultValue: false,
},
{
name: 'showSearch',
title: {
label: '可搜索',
tip: '属性: showSearch',
},
setter: 'BoolSetter',
defaultValue: false,
},
{
name: 'label',
title: '内联文案',
setter: {
componentName: 'StringSetter',
},
},
{
name: 'dataSource',
title: {
label: '节点数据',
tip: '数据源',
},
setter: 'JsonSetter',
},
]),
},
icon: '',
category: '内容',
};
================================================
FILE: packages/fusion-ui/lowcode/tree-select/snippets.js
================================================
module.exports = [
{
title: '树型选择控件',
screenshot:
'https://alifd.oss-cn-hangzhou.aliyuncs.com/fusion-cool/icons/icon-light/ic_light_tree-select.png',
schema: {
componentName: 'TreeSelect',
props: {
prefix: 'next-',
size: 'medium',
hasArrow: true,
hasBorder: true,
autoWidth: true,
notFoundContent: 'Not Found',
treeCheckedStrategy: 'parent',
},
},
},
{
title: '树形控件',
screenshot:
'https://alifd.oss-cn-hangzhou.aliyuncs.com/fusion-cool/icons/icon-light/ic_light_tree.png',
schema: {
componentName: 'Tree',
props: {
prefix: 'next-',
selectable: true,
checkedStrategy: 'all',
autoExpandParent: true,
animation: true,
focusable: true,
},
},
},
];
================================================
FILE: packages/fusion-ui/lowcode/types/index.ts
================================================
import { IPublicTypeComponentMetadata, IPublicTypeSnippet, IPublicTypeFieldConfig, IPublicModelSettingField } from '@alilc/lowcode-types';
export interface ISnippet extends IPublicTypeSnippet {
label?: string;
title?: string;
}
export interface IComponentDescription extends IPublicTypeComponentMetadata {
snippets?: ISnippet[];
}
export interface IProps extends IPublicTypeFieldConfig {
showInListSetter?: boolean;
initialValue?: Function | any;
editable?: boolean;
items?: IProps[] | IPublicTypeFieldConfig[];
}
export interface SetterProps {
forceInline?: boolean;
key?: string;
prop?: IPublicModelSettingField;
selected?: any;
field?: IPublicModelSettingField;
value: any;
onChange: Function;
onInitial?: Function;
removeProp?: Function;
}
export interface IAssets {
components?: IComponentDescription[];
}
================================================
FILE: packages/fusion-ui/lowcode/upload/meta.js
================================================
import { wrapFormItemProps } from '../utils/form-utils';
export default {
componentName: 'FormUpload',
isFormItemComponent: true,
title: '上传',
docUrl: '',
screenshot: '',
npm: {
package: '@alifd/fusion-ui',
version: '{{version}}',
exportName: 'FormUpload',
main: '',
destructuring: true,
subName: '',
},
props: [
{
name: 'action',
propType: 'string',
description: '上传的地址',
},
{
name: 'value',
propType: {
type: 'Json',
},
description: '文件列表',
},
{
name: 'defaultValue',
propType: 'object',
description: '默认文件列表',
},
{
name: 'shape',
propType: {
type: 'oneOf',
value: ['card'],
},
description: '上传按钮形状',
},
{
name: 'listType',
propType: {
type: 'oneOf',
value: ['text', 'image', 'card'],
},
description: '上传列表的样式',
},
{
name: 'name',
propType: 'string',
description: '文件名字段',
},
{
name: 'data',
propType: {
type: 'oneOfType',
value: ['object', 'func'],
},
description: '上传额外传参',
},
{
name: 'formatter',
propType: 'func',
title: {
label: '数据格式化函数',
tip: '数据格式化函数,配合自定义 action 使用,参数为服务器的响应数据,详见 [formatter](#formater)\n@param {Object} response 返回\n@param {File} file 文件对象',
},
},
{
name: 'limit',
propType: 'number',
description: '最大文件上传个数',
defaultValue: null,
},
{
name: 'timeout',
propType: 'number',
description: '设置上传超时,单位ms',
},
{
name: 'dragable',
propType: 'bool',
description: '可选参数,是否支持拖拽上传,`ie10+` 支持。',
},
{
name: 'useDataURL',
propType: 'bool',
description: '可选参数,是否本地预览',
},
{
name: 'disabled',
propType: 'bool',
description: '可选参数,是否禁用上传功能',
},
{
name: 'onSelect',
propType: 'func',
description: '选择文件回调',
},
{
name: 'onProgress',
propType: 'func',
description: '上传中',
},
{
name: 'onChange',
propType: 'func',
description: '上传文件改变时的状态\n@param {Object} info 文件事件对象',
},
{
name: 'onSuccess',
propType: 'func',
description:
'可选参数,上传成功回调函数,参数为请求下响应信息以及文件\n@param {Object} file 文件\n@param {Array
);
}
}
================================================
FILE: packages/fusion-ui/src/components/menu-button/scss/variable.scss
================================================
////
/// @module menu-button: 菜单按钮
/// @tag MenuButton
/// @category component
/// @family general
/// @varPrefix $menu-btn-
/// @classPrefix {prefix}-menu-btn
////
// menu-button variables
// --------------------------------------------------
// prefix
$menu-btn-prefix: '.fusion-ui-menu-btn';
/// icon
/// @namespace statement/disabled
$menu-btn-disabled-icon-color: var(--color-text1-1, $color-text1-1) !default;
/// ghost icon
$menu-btn-ghost-light-disabled-icon-color: var(
--btn-ghost-light-color-disabled,
$btn-ghost-light-color-disabled
) !default;
/// ghost icon
$menu-btn-ghost-dark-disabled-icon-color: var(
--btn-ghost-dark-color-disabled,
$btn-ghost-dark-color-disabled
) !default;
/// icon
/// @namespace statement/normal
$menu-btn-pure-text-normal-icon-color: var(--color-text1-2, $color-text1-2) !default;
/// icon
/// @namespace statement/normal
$menu-btn-pure-text-primary-icon-color: var(--color-white, $color-white) !default;
/// icon
/// @namespace statement/normal
$menu-btn-pure-text-secondary-icon-color: var(--color-brand1-6, $color-brand1-6) !default;
/// icon
/// @namespace statement/normal
$menu-btn-text-text-normal-icon-color: var(--color-text1-4, $color-text1-4) !default;
/// icon
/// @namespace statement/primary
$menu-btn-text-text-primary-icon-color: var(--color-link-1, $color-link-1) !default;
/// icon
/// @namespace statement/light
$menu-btn-ghost-light-icon-color: var(--color-text1-4, $color-text1-4) !default;
/// icon
/// @namespace statement/dark
$menu-btn-ghost-dark-icon-color: var(--color-white, $color-white) !default;
/// fold icon
/// @namespace statement/normal
/// @type icon
$menu-btn-fold-icon-content: var(--icon-content-arrow-down, $icon-content-arrow-down) !default;
/// unfold icon
/// @namespace statement/normal
/// @type icon
$menu-btn-unfold-icon-content: var(--icon-reset, $icon-reset) !default;
================================================
FILE: packages/fusion-ui/src/components/page-header/index.scss
================================================
#{$biz-css-prefix}page-header {
position: relative;
padding: 0;
.next-breadcrumb .next-breadcrumb-text {
font-size: 14px;
}
&-ghost {
}
&.has-breadcrumb {
padding-top: 0;
}
&.has-footer {
padding-bottom: 0;
}
&-back {
margin-right: 16px;
font-size: 16px;
line-height: 1;
&-button {
border: none !important;
cursor: pointer;
}
}
.fusion-ui-divider-vertical {
height: 14px;
vertical-align: middle;
}
.fusion-ui-breadcrumb + &-heading {
box-sizing: border-box;
margin: 0;
padding: 0;
color: #000000d9;
font-variant: tabular-nums;
line-height: 1.5715;
list-style: none;
font-feature-settings: 'tnum';
color: #00000073;
font-size: 14px;
}
@mixin text-overflow-ellipsis() {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
&-heading {
display: flex;
justify-content: space-between;
margin-top: 8px;
&-left {
display: flex;
align-items: center;
overflow: hidden;
}
&-title {
margin-right: 12px;
margin-bottom: 0;
color: #000000d9;
font-weight: 600;
font-size: 20px;
line-height: 32px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
&-avatar {
margin-right: 12px;
}
&-sub-title {
margin-right: 12px;
color: #00000073;
font-size: 14px;
line-height: 1.5715;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
&-extra {
white-space: nowrap;
> * {
white-space: unset;
}
> *:first-child {
margin-left: 0;
}
}
}
&-content {
padding-top: 16px;
}
&-actions {
float: right;
}
&-footer {
.fusion-ui-tabs {
> .fusion-ui-tabs-nav {
margin: 0;
&::before {
border: none;
}
}
.fusion-ui-tabs-tab {
}
}
}
&-compact &-heading {
flex-wrap: wrap;
}
}
================================================
FILE: packages/fusion-ui/src/components/page-header/index.tsx
================================================
import * as React from 'react';
import classNames from 'classnames';
import ResizeObserver from 'rc-resize-observer';
import { Icon, Breadcrumb, Avatar, Button } from '@alifd/next';
import { bizCssPrefix } from '../../variables';
import Operations from '@/common/operations';
const TransButton = Button;
export interface PageHeaderProps {
backIcon?: string | React.ReactNode;
prefixCls?: string;
title?: React.ReactNode;
subTitle?: React.ReactNode;
style?: React.CSSProperties;
showBreadcrumb?: boolean;
breadcrumb?: any[] | React.ReactElement;
breadcrumbRender?: (props: PageHeaderProps, defaultDom: React.ReactNode) => React.ReactNode;
tags?: React.ReactElement | React.ReactElement[];
footer?: React.ReactNode;
extra?: React.ReactNode;
showAvatar?: boolean;
showActions?: boolean;
avatar?: object;
onBack?: (e?: React.MouseEvent) => void;
className?: string;
ghost?: boolean;
direction?: string;
pageHeader?: any;
operations?: any[];
operationConfig?: Record;
}
const renderBack = (
prefixCls: string,
backIcon?: string | React.ReactNode,
onBack?: (e?: React.MouseEvent) => void,
) => {
if (!backIcon) {
return null;
}
return (
) => {
onBack?.(e);
}}
className={`${prefixCls}-back-button`}
>
);
};
const renderBreadcrumb = (breadcrumb: any[]) => {
if (!breadcrumb) return null;
if (!Array.isArray(breadcrumb)) {
return breadcrumb;
}
if (!breadcrumb.length) {
return null;
}
return (
{breadcrumb.map((item) => {
return {item};
})}
);
};
const getBackIcon = (props: PageHeaderProps, direction = '') => {
if (props.backIcon !== undefined) {
return props.backIcon;
} else if (direction) {
return direction === 'rtl' ? 'arrow-right' : 'arrow-left';
} else {
return null;
}
};
const renderOperations = (
prefixCls: string,
operations: any[],
operationConfig = { align: 'right' },
) => {
const operationsProps = { operations, operationConfig };
let content;
if (!operations || !operations.length) {
content = null;
} else {
content = ;
}
return {content}
;
};
const renderTitle = (
prefixCls: string,
props: PageHeaderProps,
direction = '',
operations: any[],
operationConfig: { align: 'right' },
) => {
const { title, showAvatar, avatar, showActions, subTitle, tags, extra, onBack } = props;
const headingPrefixCls = `${prefixCls}-heading`;
const hasHeading = title || subTitle || tags || extra;
// If there is nothing, return a null
if (!hasHeading) {
return null;
}
const backIcon = getBackIcon(props, direction);
const backIconDom = renderBack(prefixCls, backIcon, onBack);
const hasTitle = backIconDom || avatar || hasHeading;
return (
{hasTitle && (
{backIconDom}
{showAvatar && avatar &&
}
{title && (
{title}
)}
{subTitle && (
{subTitle}
)}
{tags &&
{tags}}
)}
{extra &&
{extra}}
{showActions && operations && renderOperations(prefixCls, operations, operationConfig)}
);
};
const renderFooter = (prefixCls: string, footer: React.ReactNode) => {
if (footer) {
return {footer}
;
}
return null;
};
const renderChildren = (prefixCls: string, children: React.ReactNode) => (
{children}
);
const PageHeader: React.FC = (props: PageHeaderProps) => {
const [compact, updateCompact] = React.useState(false);
const onResize = ({ width }: { width: number }) => {
updateCompact(width < 768);
};
const {
prefixCls = `${bizCssPrefix}-page-header`,
style,
footer,
children,
breadcrumb,
breadcrumbRender,
showBreadcrumb,
className: customizeClassName,
direction,
pageHeader,
operations,
operationConfig,
} = props;
let ghost: undefined | boolean = true;
// Use `ghost` from `props` or from `ConfigProvider` instead.
if ('ghost' in props) {
ghost = props.ghost;
} else if (pageHeader && 'ghost' in pageHeader) {
ghost = pageHeader.ghost;
}
const getDefaultBreadcrumbDom = () => {
if (breadcrumb as any[]) {
return renderBreadcrumb(breadcrumb as any[]);
}
return null;
};
const defaultBreadcrumbDom = getDefaultBreadcrumbDom();
const isBreadcrumbComponent = breadcrumb && 'props' in breadcrumb;
// support breadcrumbRender function
const breadcrumbRenderDomFromProps =
breadcrumbRender?.(props, defaultBreadcrumbDom) || defaultBreadcrumbDom;
const breadcrumbDom = isBreadcrumbComponent ? breadcrumb : breadcrumbRenderDomFromProps;
const className = classNames(prefixCls, customizeClassName, {
'has-breadcrumb': !!breadcrumbDom && breadcrumbDom,
'has-footer': !!footer,
[`${prefixCls}-ghost`]: ghost,
[`${prefixCls}-rtl`]: direction === 'rtl',
[`${prefixCls}-compact`]: compact,
});
return (
{showBreadcrumb && breadcrumbDom}
{renderTitle(prefixCls, props, direction, operations, operationConfig)}
{children && renderChildren(prefixCls, children)}
{renderFooter(prefixCls, footer)}
);
};
PageHeader.defaultProps = {
showBreadcrumb: true,
showAvatar: false,
showOperation: true,
showActions: false,
};
export { PageHeader };
================================================
FILE: packages/fusion-ui/src/components/pie-chart/index.tsx
================================================
import React from 'react';
import { PieChart as MyPie } from 'bizcharts';
import numeral from 'numeral';
import DataSet from '@antv/data-set';
const { DataView } = DataSet;
const dv = new DataView();
type IProps = React.ComponentProps;
function PieChart(props: IProps) {
const { data, ...others } = props || {};
dv.source(data);
// 求百分比
dv.transform({
type: 'percent',
field: props?.angleField, // 统计字段
dimension: props?.colorField, // 该字段的占比
as: 'percent', // 结果存储在该字段
});
return (
{
const percent =
typeof angleField?.percent === 'number'
? numeral(angleField?.percent).format('0.00%')
: angleField?.percent;
return `${angleField?.[props?.colorField]} ${percent}`;
},
}}
interactions={[
{ type: 'element-selected' },
]}
{...others as IProps}
/>
);
}
export default PieChart;
================================================
FILE: packages/fusion-ui/src/components/pro-card/components/button-group/index.tsx
================================================
import * as React from 'react';
import { Button } from '@alifd/next';
export interface ButtonDataSource {
label?: string;
onClick?: (e: React.MouseEvent) => unknown;
}
export interface CardButtonGroupProps {
dataSource?: ButtonDataSource[];
text?: boolean;
}
export const CardButtonGroup: React.FC = ({ dataSource, text }) => {
return (
<>
{dataSource.map(({ label, onClick, ...rest }) => {
return (
);
})}
>
);
};
CardButtonGroup.defaultProps = {
dataSource: [],
};
export default CardButtonGroup;
================================================
FILE: packages/fusion-ui/src/components/pro-card/components/card/index.scss
================================================
@import '../../../../variables.scss';
$fusion-ui-card-padding: var(--s-5, $s-5);
$fusion-ui-card-padding-s: var(--s-3, $s-3);
.fusion-ui-card {
position: relative;
box-sizing: border-box;
width: 100%;
background-color: var(--color-white, $color-white);
// border-radius: 0;
display: flex;
flex-direction: column;
&-body {
flex: 1 1 auto;
&__panel {
padding: var(--fusion-ui-card-padding, $fusion-ui-card-padding);
padding-bottom: 0;
}
&__nopadding {
padding: 0;
}
// .fusion-ui-card-header + & {
// .fusion-ui-card-body__panel {
// padding-top: 0;
// }
// }
}
&--dialog {
padding: 0;
border-radius: 0;
box-shadow: none;
}
}
.fusion-ui-card-footer-actions {
padding-bottom: var(--fusion-ui-card-padding, $fusion-ui-card-padding);
}
.fusion-ui-pro-card-operation-container {
padding: var(
--fusion-ui-card-padding $fusion-ui-card-padding 0,
$fusion-ui-card-padding $fusion-ui-card-padding 0
);
}
.fusion-ui-pro-card-operation-fixed {
position: fixed;
width: 100%;
box-shadow: 0 -4px 10px 0 rgba(74, 91, 109, 0.1);
background-color: #fff;
bottom: 0;
left: 0;
padding-bottom: var(--fusion-ui-card-padding, $fusion-ui-card-padding);
}
================================================
FILE: packages/fusion-ui/src/components/pro-card/components/card/index.tsx
================================================
import * as React from 'react';
import { Loading } from '@alifd/next';
import classnames from 'classnames';
import { CardHeader, CardTagProps } from '../card-header';
import { CardButtonGroupProps } from '../button-group';
import { useFiledState } from '@/utils/hooks/useFiledState';
import { TooltipProps } from '@alifd/next/lib/balloon';
import Operations from '@/common/operations';
export interface IOperationConfig {
fixed?: boolean; // 是否固定
showSaveTime?: boolean;
align?: 'center' | 'flex-start' | 'flex-end';
}
export interface IOperationItem {
label?: string;
type?: 'primary' | 'secondary' | 'normal';
onClick?: () => void;
}
export interface CardProps extends Omit, 'title'> {
/**
* 卡片标题
*/
title?: React.ReactNode;
description?: React.ReactNode;
visibleButtonCount?: number;
/**
* 帮助信息,仅在 title 展示时生效
*/
explanation?: string;
bodyPadding?: boolean;
/**
* 帮助信息气泡配置
*/
explanationTooltipProps?: TooltipProps;
/**
* 卡片顶部操作区域自定义渲染
*/
actionBar?: React.ReactNode;
actionButtons?: CardButtonGroupProps;
tagGroup?: CardTagProps[];
/**
* 段落分割线; 如果为 true 时,默认最后一个段落没有分割线。
* @default false
*/
segmentLine?: boolean;
/**
* 是否 loading
*/
loading?: boolean;
/**
* 受控控制 Card 展开收起状态
*/
isCollapse?: boolean;
/**
* 是否开启 Card 显示展开收起
*/
hasCollapse?: boolean;
/**
* 默认收起
*/
defaultCollapse?: boolean;
/**
* 展开收起状态切换后的回调函数
*/
setCollapse?: (collapseState: boolean) => void;
/**
* 是否为弹窗卡片
*/
isDialogCard?: boolean;
hasDivider?: boolean;
operations?: IOperationItem[];
operationConfig?: IOperationConfig;
lastSaveTime?: number;
text?: boolean;
}
export const Card: React.FC = (props) => {
const {
title,
description,
visibleButtonCount,
className,
actionBar,
actionButtons,
loading,
tagGroup,
style,
hasCollapse,
isDialogCard,
explanation,
explanationTooltipProps,
children,
segmentLine,
defaultCollapse,
setCollapse,
isCollapse,
hasDivider,
operations,
operationConfig,
lastSaveTime,
bodyPadding,
text,
...otherProps
} = props;
const [collapsed, onCollapse] = useFiledState(
{
value: isCollapse,
defaultValue: defaultCollapse,
onChange: setCollapse,
},
'isCollapse' in props,
);
const cardBody = children;
const layout = 'flow';
const content = (
<>
{(title || hasCollapse || actionBar || actionButtons || tagGroup) && (
onCollapse(!collapsed)}
explanation={explanation}
explanationTooltipProps={explanationTooltipProps}
hasDivider={hasDivider}
/>
)}
{!collapsed && (
{cardBody}
)}
{!collapsed && (
)}
>
);
return (
{loading ? (
{content}
) : (
content
)}
);
};
Card.defaultProps = {
segmentLine: false,
loading: false,
isDialogCard: false,
hasCollapse: false,
defaultCollapse: false,
};
Card.displayName = 'Card';
================================================
FILE: packages/fusion-ui/src/components/pro-card/components/card-collapse/index.scss
================================================
.fusion-ui-card-collapse {
transition: height 0.3s;
overflow: hidden;
}
================================================
FILE: packages/fusion-ui/src/components/pro-card/components/card-collapse/index.tsx
================================================
import * as React from 'react';
import { useLayoutEffect } from 'react';
export const CardCollapse: React.FC<{
collapsed: boolean;
}> = ({ collapsed, children }) => {
const ref = React.useRef();
const contentRef = React.useRef();
useLayoutEffect(() => {
if (!ref.current) {
return () => {};
}
// 折叠
if (collapsed) {
// 解决折叠第一次也会进行动画问题
if (ref.current.style.height === 'auto') {
ref.current.style.height = `${contentRef.current.offsetHeight}px`;
}
const index = setTimeout(() => {
ref.current.style.height = '0px';
}, 0);
return () => clearTimeout(index);
}
// 当前已经展开,不进行动画
if (ref.current.style.height === 'auto') {
return () => {};
}
// 展开
ref.current.style.height = `${contentRef.current.offsetHeight}px`;
const index = setTimeout(() => {
ref.current.style.height = 'auto';
}, 400);
return () => clearTimeout(index);
}, [collapsed]);
return (
);
};
CardCollapse.displayName = 'CardCollapse';
================================================
FILE: packages/fusion-ui/src/components/pro-card/components/card-header/index.scss
================================================
@import '../../../../variables.scss';
$fusion-ui-card-header-padding: var(--s-4 $s-5, $s-4 $s-5);
.fusion-ui-card-header-padding {
padding-bottom: var(--s-4, $s-4);
}
.fusion-ui-card-header {
&__content {
box-sizing: border-box;
position: relative;
display: flex;
justify-content: space-between;
align-items: center;
overflow: hidden;
padding: var(--fusion-ui-card-header-padding, $fusion-ui-card-header-padding);
padding-bottom: 0;
// border-left: var(--s-1 transparent solid, $size-base transparent solid);
border-radius: var(--corner-2, $corner-2);
}
&--collapsed {
cursor: pointer;
border-color: var(--color-brand1-1, $color-brand1-1);
&:hover {
background-color: var(--color-fill1-2, $color-fill1-2);
}
.fusion-ui-card-header__action-bar {
display: none;
}
}
&__hd {
display: flex;
box-sizing: border-box;
align-items: center;
gap: var(--s-2, $s-2);
}
&__ft {
flex: 1;
display: flex;
gap: var(--s-2, $s-2);
justify-content: flex-end;
align-items: center;
}
&__desc {
padding: 0 $fusion-ui-card-header-padding $s-4 $fusion-ui-card-header-padding;
}
&__title {
display: flex;
box-sizing: border-box;
align-items: center;
font-size: var(--font-size-subhead, $font-size-subhead);
font-weight: var(--font-weight-semi-bold, $font-weight-semi-bold);
color: var(--color-text1-4, $color-text1-4);
}
&__tooltip {
color: var(--color-text1-1, $color-text1-1);
}
&__action-bar {
display: flex;
gap: var(--s-2, $s-2);
justify-content: flex-end;
}
&__collapse-btn {
user-select: none;
& > .fusion-ui-icon {
transition: transform 0.1s ease-in-out;
color: var(--color-line1-4 !important, $color-line1-4 !important);
}
&--collapsed {
& > .fusion-ui-icon {
color: var(--color-brand1-6 !important, $color-brand1-6 !important);
transform-origin: center;
transform: rotate(-180deg) !important;
}
}
&:hover {
& > .fusion-ui-icon {
color: var(--color-brand1-6 !important, $color-brand1-6 !important);
}
}
}
}
.fusion-ui-card-header__divider {
height: 1px;
border-bottom: 1px solid $color-line1-1;
margin-top: var(--s-4, $s-4);
}
================================================
FILE: packages/fusion-ui/src/components/pro-card/components/card-header/index.tsx
================================================
import * as React from 'react';
import { Button, Balloon, Tag } from '@alifd/next';
import { CustomIcon } from '@/components/toggle-icon';
import { ButtonGroup } from '@/components/button-group';
import { CardButtonGroupProps } from '../button-group';
import classnames from 'classnames';
import { TooltipProps } from '@alifd/next/lib/balloon';
const Tooltip = Balloon;
function formatActionButtons(actionButtons) {
if (actionButtons && Array.isArray(actionButtons)) {
return actionButtons.map((item) => {
if (item.label && !item.children) {
item.children = item.label;
}
return item;
});
}
return [];
}
export interface CardTagProps {
label?: string;
color?: string;
}
export interface CardHeaderProps {
/**
* 卡片标题
*/
title?: React.ReactNode;
description?: React.ReactNode;
/**
* 卡片顶部操作区域自定义渲染
*/
actionBar?: React.ReactNode;
actionButtons?: CardButtonGroupProps;
text?: boolean;
visibleButtonCount?: number;
tagGroup?: CardTagProps[];
/**
* 受控控制 Card 展开收起状态
*/
isCollapse?: boolean;
/**
* 是否开启 Card 显示展开收起
*/
hasCollapse?: boolean;
collapsed?: boolean;
onCollapse?: () => void;
/**
* 帮助信息,仅在 title 展示时生效
*/
explanation?: string;
/**
* 帮助信息气泡配置
*/
explanationTooltipProps?: TooltipProps;
hasDivider?: boolean;
}
export const CardHeader: React.FC = ({
title,
description,
hasCollapse,
actionBar,
collapsed,
onCollapse,
explanation,
explanationTooltipProps,
hasDivider,
tagGroup,
actionButtons,
text,
visibleButtonCount,
}) => {
return (
{title &&
{title}
}
{title && explanation && (
}
{...explanationTooltipProps}
>
{explanation}
)}
{tagGroup.map((item) => {
let label: any = item;
let color: any = 'blue';
if (typeof item === 'object') {
label = item.label;
if (item.color) {
color = item.color;
}
}
return (
{label}
);
})}
{actionBar &&
{actionBar}
}
{hasCollapse && (
)}
{description ?
{description}
: null}
{hasDivider && !collapsed &&
}
);
};
CardHeader.defaultProps = {
onCollapse: () => {},
hasDivider: true,
tagGroup: [],
};
CardHeader.displayName = 'CardHeader';
================================================
FILE: packages/fusion-ui/src/components/pro-card/components/card-section/index.scss
================================================
$fusion-ui-card-padding: var(--s-1 * 5, $size-base * 5);
$fusion-ui-card-header-padding: var(--fusion-ui-card-padding, $fusion-ui-card-padding);
$fusion-ui-card-section-padding: var(--fusion-ui-card-padding, $fusion-ui-card-padding);
.fusion-ui-card-section {
// padding-bottom: var(--fusion-ui-card-section-padding, $fusion-ui-card-section-padding);
box-sizing: border-box;
border: 0 solid $color-line1-1;
align-self: stretch;
}
.fusion-ui-card-section-header__divider {
height: 1px;
border-bottom: 1px solid $color-line1-1;
}
.fusion-ui-card-section-header + .fusion-ui-card-section-header__divider {
margin-top: var(--s-4, $s-4);
}
.fusion-ui-card-section-footer__divider {
height: 1px;
border-bottom: 1px solid $color-line1-1;
margin-top: var(--s-5, $s-5);
}
.fusion-ui-section-divider-indent {
margin-left: var(--s-5, $s-5);
margin-right: var(--s-5, $s-5);
}
.fusion-ui-card-section-header {
box-sizing: border-box;
position: relative;
display: flex;
justify-content: space-between;
align-items: center;
overflow: hidden;
padding: 5px 0;
padding-bottom: 0;
&__hd {
display: flex;
box-sizing: border-box;
align-items: center;
gap: var(--s-1 * 2, $size-base * 2);
}
&__ft {
flex: 1;
display: flex;
gap: var(--s-1 * 2, $size-base * 2);
justify-content: flex-end;
align-items: center;
}
&__title {
display: flex;
box-sizing: border-box;
align-items: center;
font-size: var(--font-size-body-2, $font-size-body-2);
font-weight: var(--font-weight-semi-bold, $font-weight-semi-bold);
color: var(--color-text1-3, $color-text1-3);
&::before {
content: '';
display: inline-block;
height: 13px;
width: 3px;
opacity: 0.8;
background: #034dfa;
border-radius: 2px;
margin-right: 8px;
}
&.fusion-ui-card-section-header-noBullet::before {
display: none;
}
}
&__tooltip {
color: var(--color-text1-1, $color-text1-1);
}
&__action-bar {
display: flex;
gap: var(--s-1 * 2, $size-base * 2);
justify-content: flex-end;
}
}
.fusion-ui-card-section-body {
padding: var(--fusion-ui-card-section-padding 0, $fusion-ui-card-section-padding 0);
}
.fusion-ui-card-body__panel--flow > .fusion-ui-card-section,
.fusion-ui-card-body__panel--flow
> .fusion-ui-row-col-container
> .fusion-ui-row
> .fusion-ui-col
> .fusion-ui-card-section {
// margin: 0 ($fusion-ui-card-padding * -1);
&--segment-line {
&:first-child {
border-top: none;
}
}
&:first-child {
padding-top: 0;
}
&:last-child {
padding-bottom: 0;
}
}
.fusion-ui-card-body__panel--grid > .fusion-ui-grid {
margin: 0 ($fusion-ui-card-padding * -1 - 1px) ($fusion-ui-card-padding * -1)
($fusion-ui-card-padding * -1);
& > .fusion-ui-card-section {
&--segment-line {
border-right-width: 1px;
}
.fusion-ui-card-section-header__title::before {
display: none;
}
}
}
================================================
FILE: packages/fusion-ui/src/components/pro-card/components/card-section/index.tsx
================================================
import * as React from 'react';
import { Loading, Balloon, Tag } from '@alifd/next';
import classnames from 'classnames';
import { CardTagProps } from '../card-header';
import { TooltipProps } from '@alifd/next/lib/balloon';
import { CustomIcon } from '@/components/toggle-icon';
const { Tooltip } = Balloon;
export interface CardSectionProps extends Omit, 'title'> {
/**
* 段落标题
*/
title?: React.ReactNode;
/**
* 帮助信息,仅在 title 展示时生效
*/
explanation?: string;
/**
* 帮助信息气泡配置
*/
explanationTooltipProps?: TooltipProps;
/**
* 子卡片顶部操作区域自定义渲染
*/
actionBar?: React.ReactNode;
/**
* 是否启用分割线
* @default false
*/
segmentLine?: boolean;
/**
* 是否 loading
* @default false
*/
loading?: boolean;
className?: string;
style?: React.CSSProperties;
tagGroup?: CardTagProps[];
headerDivider?: boolean;
footerDivider?: boolean;
hasDividerIndent?: boolean;
noBullet?: boolean;
}
/**
* 子卡片
*/
export const CardSection: React.FC = ({
children,
title,
className,
loading,
segmentLine,
actionBar,
explanation,
explanationTooltipProps,
tagGroup,
id,
headerDivider,
footerDivider,
hasDividerIndent,
noBullet,
style,
}) => {
// 获取 loading 状态
const loadingStatus = loading;
const content = (
<>
{(title || actionBar) && (
{title && (
{title}
{explanation && (
}
{...explanationTooltipProps}
>
{explanation}
)}
{tagGroup.map((item) => {
let label: any = item;
let color: any = 'blue';
if (typeof item === 'object') {
label = item.label;
if (item.color) {
color = item.color;
}
}
return (
{label}
);
})}
)}
{actionBar && (
{actionBar}
)}
)}
{headerDivider && (
)}
{children}
{footerDivider && (
)}
>
);
// 一般情况
return (
{loadingStatus ? (
{content}
) : (
content
)}
);
};
CardSection.displayName = 'CardSection';
CardSection.defaultProps = {
title: null,
segmentLine: false,
loading: false,
tagGroup: [],
noBullet: false,
headerDivider: true,
};
================================================
FILE: packages/fusion-ui/src/components/pro-card/index.scss
================================================
@import './theme-dark.scss';
@import './components/card/index.scss';
@import './components/card-collapse/index.scss';
@import './components/card-header/index.scss';
@import './components/card-section/index.scss';
================================================
FILE: packages/fusion-ui/src/components/pro-card/index.tsx
================================================
import { Card as ProCard, CardProps } from './components/card';
import { CardSection, CardSectionProps } from './components/card-section';
ProCard.CardSection = CardSection;
export { CardProps, CardSectionProps };
export default ProCard;
================================================
FILE: packages/fusion-ui/src/components/pro-card/theme-dark.scss
================================================
body.dark {
.fusion-ui-card {
background-color: var(--color-fill1-1, $color-fill1-1);
&-header {
&__title {
color: var(--color-text1-4, $color-text1-4);
}
}
&-body {
color: var(--color-text1-3, $color-text1-3);
}
&-header {
&--collapsed {
border-color: var(--color-brand1-6, $color-brand1-6);
&:hover {
background-color: var(--color-fill1-1, $color-fill1-1);
}
}
}
.fusion-ui-card-grid > .fusion-ui-card-section {
background-color: var(--color-fill1-1, $color-fill1-1);
}
.fusion-ui-card-section-header__title::before {
background: var(--color-brand1-6, $color-brand1-6);
}
}
}
================================================
FILE: packages/fusion-ui/src/components/pro-dialog/dialog.tsx
================================================
import * as React from 'react';
import cx from 'classnames';
import { Dialog as NextDialog, Message, Balloon, Icon } from '@alifd/next';
import { DialogProps as NextDialogProps } from '@alifd/next/types/dialog';
import Operations, { OperationProps } from '@/common/operations';
import { isEditorEnv } from '@/utils';
const { Tooltip } = Balloon;
const noop = () => {};
const isValidFunction = (func: any) => typeof func === 'function';
const ACTION_MAP: Record = {
ok: noop,
cancel: noop,
};
function getAction(action: string | number) {
return ACTION_MAP[action] || noop;
}
export interface DialogProps extends NextDialogProps {
/**
* 弹窗大小
*/
size?: 'small' | 'medium' | 'large' | 'autoLarge';
operations?: object[];
operationConfig?: object;
status?: string;
dialogType?: string;
explanation?: string;
iconType?: string;
hasTips?: boolean;
}
export interface DialogOperationsProps extends OperationProps {
onOk?: any;
onCancel?: any;
}
export interface DialogState {
visible?: boolean;
}
const DialogOperations = (props: DialogOperationsProps) => {
const { operations, operationConfig, onOk = noop, onCancel = noop, renderDefaultBtns } = props;
if (!operations || !operations.length) {
return null;
}
const baseOperations = operations.map((operation: any) => {
let onClick = getAction(operation.action).bind(this);
if (operation.action) {
if (operation.action === 'ok' && onOk && typeof onOk === 'function') {
onClick = onOk;
} else if (operation.action === 'cancel' && onCancel && typeof onCancel === 'function') {
onClick = onCancel;
}
}
return {
onClick,
...operation,
};
});
const operationProps = {
operations: baseOperations,
operationConfig,
renderDefaultBtns,
};
return ;
};
function Dialog(props: DialogProps) {
const {
size,
className,
onOk,
onCancel,
children,
operations,
footer,
operationConfig,
status,
messageProps,
dialogType,
explanationTooltipProps,
hasTips,
explanation,
iconType,
rtl,
title,
width,
...otherProps
} = props;
let footerElement = footer;
if (operations && operations.length) {
const operationsProps = {
operations,
operationConfig,
onOk,
onCancel,
renderDefaultBtns: () => footer || [],
};
footerElement = ;
}
if (typeof width !== 'undefined') {
otherProps.width = width;
}
// class 处理
const classes = cx({
'fusion-ui-dialog': true,
[`fusion-ui-dialog-${size}`]: typeof width === 'undefined',
[className]: !!className,
});
// 如果指定了 width ,则 size 不生效;
const titleElement =
dialogType === 'notice' && status ? (
) : (
{title}
{hasTips ? (
} {...explanationTooltipProps}>
{explanation}
) : (
''
)}
);
return (
{children}
);
}
export class InnerProDialog extends React.Component {
static displayName: 'ProDialog';
static propTypes: DialogProps;
constructor(props: DialogProps) {
super(props);
const { visible } = props;
this.state = {
visible: visible || false,
};
}
onOk = (event: Object) => {
const { onOk } = this.props;
if (isValidFunction(onOk)) {
onOk(event);
}
if (!('visible' in this.props)) {
this.setState({ visible: false });
}
};
onCancel = (event: Object) => {
const { onCancel } = this.props;
if (isValidFunction(onCancel)) {
onCancel(event);
}
this.setState({ visible: false });
};
onClose = (trigger: String, event: Object) => {
const { onClose } = this.props;
if (isValidFunction(onClose)) {
onClose(trigger, event);
}
this.setState({ visible: false });
};
show = () => {
this.setState({
visible: true,
});
};
open = () => {
this.setState({
visible: true,
});
};
hide = () => {
this.setState({
visible: false,
});
};
close = () => {
this.setState({
visible: false,
});
};
render() {
const { children, ...otherProps } = this.props;
const { visible } = this.state;
const realVisible = isEditorEnv(this.props) ? true : visible;
const dialogProps = {
...otherProps,
visible: realVisible,
onOk: this.onOk,
onCancel: this.onCancel,
onClose: this.onClose,
};
return ;
}
}
export const ProDialog = Object.assign(InnerProDialog, NextDialog);
================================================
FILE: packages/fusion-ui/src/components/pro-dialog/index.scss
================================================
.fusion-ui-dialog {
top: 50%;
left: 50%;
translate: -50% -50%;
&-small {
width: calc(var(--s-1, 4) * 100) !important;
}
&-medium {
width: calc(var(--s-1, 4) * 175) !important;
}
&-large {
width: calc(var(--s-1, 4) * 250) !important;
}
&-autoLarge {
width: 90vw !important;
min-width: 900px;
}
&__tooltip {
color: var(--color-text1-1, $color-text1-1);
display: inline-block;
margin-left: 8px;
}
}
================================================
FILE: packages/fusion-ui/src/components/pro-dialog/index.tsx
================================================
export * from './dialog';
================================================
FILE: packages/fusion-ui/src/components/pro-drawer/drawer.tsx
================================================
import * as React from 'react';
import { Drawer as NextDrawer, Balloon, Icon } from '@alifd/next';
import { DrawerProps as NextDrawerProps } from '@alifd/next/types/Drawer';
import { isEditorEnv } from '@/utils';
import { bizCssPrefix } from '@/variables';
import { Space } from '@/components/container';
import Operations, { OperationProps } from '@/common/operations';
const cssPrefix = `${bizCssPrefix}-pro-drawer`;
const noop = () => {};
const isValidFunction = (func: any) => typeof func === 'function';
const ACTION_MAP: Record = {
ok: noop,
cancel: noop,
};
function getAction(action: string | number) {
return ACTION_MAP[action] || noop;
}
export interface DrawerProps extends NextDrawerProps {
/**
* 弹窗大小
*/
size?: 'small' | 'medium' | 'large' | 'autoLarge';
operations?: object[];
operationConfig?: object;
onOk?: any;
onCancel?: any;
footer?: any;
titleTip?: any;
}
export interface DrawerOperationsProps extends OperationProps {
onOk?: any;
onCancel?: any;
}
const DrawerOperations = (props: DrawerOperationsProps) => {
const { operations, operationConfig, onOk = noop, onCancel = noop, renderDefaultBtns } = props;
if (!operations || !operations.length) {
return null;
}
const baseOperations = operations.map((operation: any) => {
let onClick = getAction(operation.action).bind(this);
if (operation.action) {
if (operation.action === 'ok' && onOk && typeof onOk === 'function') {
onClick = onOk;
} else if (operation.action === 'cancel' && onCancel && typeof onCancel === 'function') {
onClick = onCancel;
}
}
return {
onClick,
...operation,
};
});
const operationProps = {
operations: baseOperations,
operationConfig,
renderDefaultBtns,
};
return ;
};
const sizeMap: Record> = {
small: {
hoz: '20vw',
ver: '20vh',
},
medium: {
hoz: '40vw',
ver: '40vh',
},
large: {
hoz: '60vw',
ver: '60vh',
},
};
function Drawer(props: DrawerProps) {
const {
size,
children,
operations,
placement,
onOk,
onCancel,
footer,
operationConfig = {},
title,
titleTip,
className,
width,
height,
...otherProps
} = props;
let footerElement = footer;
if (operations && operations.length) {
const operationsProps = {
operations,
operationConfig,
onOk,
onCancel,
renderDefaultBtns: () => footer || [],
};
footerElement = ;
}
let _width = width;
let _height = height;
let align;
if (size) {
// ver
if (['top', 'bottom'].includes(placement)) {
align = 'ver';
if (!_height) {
_height = sizeMap[size].ver;
}
} else if (['left', 'right'].includes(placement)) {
align = 'hoz';
if (!_width) {
_width = sizeMap[size].hoz;
}
}
}
const _titleTip =
titleTip && titleTip.enable
? Object.assign(
{
content: title,
icon: 'help',
},
titleTip,
)
: null;
const titleElement = title ? (
{title}
{_titleTip ? (
}
alignEdge
closable={false}
>
{_titleTip.content || title}
) : null}
) : null;
return (
{children}
{footerElement}
);
}
export class InnerProDrawer extends React.Component {
static displayName: 'ProDrawer';
static propTypes: DrawerProps;
constructor(props: DrawerProps) {
super(props);
const { visible } = props;
this.state = {
visible: visible || false,
};
}
onOk = (event: Object) => {
const { onOk } = this.props;
if (isValidFunction(onOk)) {
onOk(event);
}
if (!('visible' in this.props)) {
this.setState({ visible: false });
}
};
onCancel = (event: Object) => {
const { onCancel } = this.props;
if (isValidFunction(onCancel)) {
onCancel(event);
}
this.setState({ visible: false });
};
onClose = (trigger: String, event: Object) => {
const { onClose } = this.props;
if (isValidFunction(onClose)) {
onClose(trigger, event);
}
this.setState({ visible: false });
};
show = () => {
this.setState({
visible: true,
});
};
open = () => {
this.setState({
visible: true,
});
};
hide = () => {
this.setState({
visible: false,
});
};
close = () => {
this.setState({
visible: false,
});
};
render() {
const { children, ...otherProps } = this.props;
const { visible } = this.state;
const realVisible = isEditorEnv(this.props) ? true : visible;
const DrawerProps = {
...otherProps,
visible: realVisible,
onOk: this.onOk,
onCancel: this.onCancel,
onClose: this.onClose,
};
return {children};
}
}
export const ProDrawer = Object.assign(InnerProDrawer, NextDrawer);
================================================
FILE: packages/fusion-ui/src/components/pro-drawer/index.scss
================================================
#{$biz-css-prefix}pro-drawer {
&-small {
width: calc(var(--s-1, 4) * 100);
}
&-medium {
width: calc(var(--s-1, 4) * 175);
}
&-large {
width: calc(var(--s-1, 4) * 250);
}
&-autoLarge {
width: 90vw;
min-width: 900px;
}
&-title {
font-size: var(--s-4, $s-4);
letter-spacing: 0;
line-height: var(--s-5, $s-5);
}
&.operation-container {
display: flex;
padding: 15px;
align-items: center;
& > * {
margin-left: 10px;
}
& > *:first-child {
margin-left: 0;
}
&-operation-item + &-operation-item {
margin-left: 10px;
}
&.operation-align-left {
justify-content: flex-start;
}
&.operation-align-center {
justify-content: center;
}
&.operation-align-right {
justify-content: flex-end;
}
&.operation-fixed {
width: 100%;
position: absolute;
background-color: #fff;
bottom: 0;
left: 0;
}
}
}
================================================
FILE: packages/fusion-ui/src/components/pro-drawer/index.tsx
================================================
export * from './drawer';
================================================
FILE: packages/fusion-ui/src/components/pro-form/components/Input.tsx
================================================
import * as React from 'react';
import { Input } from '@alifd/next';
import FormItem from './form-item';
const FormInput = (props: any) => {
const { formItemProps = {}, ...componentProps } = props;
return (
);
};
FormInput.displayName = 'FormInput';
export default FormInput;
================================================
FILE: packages/fusion-ui/src/components/pro-form/components/form-item/index.scss
================================================
#{$biz-css-prefix}form-item-bubble {
position: relative;
padding-top: 8px;
&::before {
content: '';
width: 0;
height: 0;
border-bottom: 7px solid #f4f5f8;
border-bottom: 7px solid var(--color-fill1-2, #f4f5f8);
border-right: 7px solid transparent;
border-left: 7px solid transparent;
position: absolute;
top: 1px;
left: 20px;
}
}
================================================
FILE: packages/fusion-ui/src/components/pro-form/components/form-item/index.tsx
================================================
import * as React from 'react';
import * as Next from '@alifd/next';
import { ItemProps } from '@alifd/next/types/form';
const { Balloon, Icon, Form } = Next;
const { Item } = Form;
export enum FormItemTypes {
Input = 'Input',
NumberPicker = 'NumberPicker',
DatePicker = 'DatePicker',
}
export interface ProFormItemProps extends ItemProps {
labelTip?: Record;
componentProps?: Record;
__designMode?: string;
childForm?: any;
}
const ProFormItem: React.ForwardRefRenderFunction = (
props: ProFormItemProps,
ref,
) => {
const {
labelTip,
label,
__designMode,
children,
labelAlign,
labelCol,
childForm,
...otherProps
} = props;
const _labelTip =
labelTip && labelTip.enable
? Object.assign(
{
content: label,
icon: 'help',
},
labelTip,
)
: null;
return (
-
{label}
{_labelTip ? (
}
alignEdge
closable={false}
>
{_labelTip.content || label}
) : null}
>
}
{...otherProps}
ref={ref}
>
{React.Children.map(children, (child) => {
if (!child) return null;
const _props = Object.assign({}, child.props || {});
const { defaultValue, value, ...otherComponentProps } = _props;
const finalValue =
(__designMode || otherComponentProps.__designMode) === 'design' ? defaultValue : value;
if (finalValue) {
otherComponentProps.value = finalValue;
}
otherComponentProps.renderPreview = (curValue) => {
if (otherProps.isPreview && !curValue) {
return '—';
}
if (!curValue) {
return curValue;
}
switch (typeof curValue) {
case 'boolean':
return curValue;
case 'object':
if (Array.isArray(curValue)) {
return curValue.length
? curValue.map((item, index) => (
{item?.label || '—'}
))
: null;
}
return curValue.label ? (
{curValue.label}
) : null;
default:
return curValue;
}
};
if (otherProps.name) {
_props.name = otherProps.name;
}
if (child) {
return React.cloneElement(child, Object.assign(_props, otherComponentProps));
}
return child;
})}
{childForm ? {childForm}
: null}
);
};
const RefProFormItem = React.forwardRef(ProFormItem);
RefProFormItem.displayName = 'ProFormItem';
RefProFormItem.defaultProps = {};
RefProFormItem.propTypes = {};
export default RefProFormItem;
================================================
FILE: packages/fusion-ui/src/components/pro-form/components/next-wrapper.tsx
================================================
import * as React from 'react';
import {
CascaderSelect,
Checkbox,
DatePicker,
Input,
NumberPicker,
Radio,
Rating,
Select,
TreeSelect,
Upload,
} from '@alifd/next';
import FormItem from './form-item';
const RadioGroup = Radio.Group;
const CheckboxGroup = Checkbox.Group;
const { RangePicker } = DatePicker;
const { TextArea, Password } = Input;
const FormCascaderSelect = wrapper(CascaderSelect, 'FormCascaderSelect');
const FormCheckboxGroup = wrapper(CheckboxGroup, 'FormCheckboxGroup');
const FormDatePicker = wrapper(DatePicker, 'FormDatePicker');
const FormInput = wrapper(Input, 'FormInput');
const FormNumberPicker = wrapper(NumberPicker, 'FormNumberPicker');
const FormRadioGroup = wrapper(RadioGroup, 'FormRadioGroup');
const FormRangePicker = wrapper(RangePicker, 'FormRangePicker');
const FormRating = wrapper(Rating, 'FormRating');
const FormSelect = wrapper(Select, 'FormSelect');
const FormTreeSelect = wrapper(TreeSelect, 'FormTreeSelect');
const FormUpload = wrapper(Upload, 'FormUpload');
const FormTextArea = wrapper(TextArea, 'FormTextArea');
const FormPassword = wrapper(Password, 'FormPassword');
function wrapper(NextFormComponent: any, displayName: string) {
const WrappedComponent = (props: any) => {
const { formItemProps = {}, ...componentProps } = props;
return (
);
};
WrappedComponent.displayName = displayName;
return WrappedComponent;
}
export {
FormCascaderSelect,
FormCheckboxGroup,
FormDatePicker,
FormInput,
FormNumberPicker,
FormRadioGroup,
FormRangePicker,
FormRating,
FormSelect,
FormTreeSelect,
FormUpload,
FormTextArea,
FormPassword,
};
================================================
FILE: packages/fusion-ui/src/components/pro-form/index.scss
================================================
@import './layouts/anchor-form/index.scss';
@import './layouts/child-form/index.scss';
@import './layouts/pro-form/index.scss';
@import './layouts/step-form/index.scss';
@import './components/form-item/index.scss';
================================================
FILE: packages/fusion-ui/src/components/pro-form/index.tsx
================================================
import ProForm from './layouts/pro-form';
import StepForm from './layouts/step-form';
import AnchorForm from './layouts/anchor-form';
import ChildForm from './layouts/child-form';
export * from './components/form-item';
export * from './components/next-wrapper';
export { StepForm, ProForm, AnchorForm, ChildForm };
================================================
FILE: packages/fusion-ui/src/components/pro-form/layouts/anchor-form/container.tsx
================================================
import React from 'react';
function AnchorContainer() {
return Container
;
}
export default AnchorContainer;
================================================
FILE: packages/fusion-ui/src/components/pro-form/layouts/anchor-form/index.scss
================================================
#{$biz-css-prefix}anchor-form {
&.forms {
margin-bottom: var(--s-5, $s-5);
background-color: var(--color-white, $color-white);
}
}
================================================
FILE: packages/fusion-ui/src/components/pro-form/layouts/anchor-form/index.tsx
================================================
import * as React from 'react';
import { useRef, useImperativeHandle, forwardRef } from 'react';
import { Form, Card } from '@alifd/next';
import { Space } from '@/components/container';
import { Anchor, AnchorProps, LinkItemData } from '@/components/anchor';
import Operations from '@/common/operations';
import { getId } from '@/utils';
export interface AnchorFormProps {
children?: React.ReactElement;
/**
* 可以这样写属性描述
* @description 是否展示锚点
* @description.zh-CN 还支持不同的 locale 后缀来实现多语言描述,使用 description 兜底
* @default false
*/
showAnchor?: boolean;
formMapRef?: any;
operations?: any;
operationConfig?: any;
lastSaveTime?: any;
anchorProps?: AnchorProps;
enableRandomHtmlId?: boolean;
}
export type AnchorFormItemProps = LinkItemData;
function renderAnchor(props: AnchorFormProps, formArray: Map) {
const dataSource: AnchorFormItemProps[] = Array.from(formArray.keys()).map((item) => {
const anchorItemProps = formArray.get(item);
const { label = '', htmlId = getId(), ...otherProps } = anchorItemProps || {};
return {
...otherProps,
label,
htmlId,
};
});
return <>{dataSource && }>;
}
function renderForm(
props: AnchorFormProps,
formArrayRef: React.MutableRefObject,
formArray: Map,
) {
const { children } = props;
return (
<>
{React.Children.map(children, (child, index) => {
const anchorItemProps = formArray.get(`${index}`);
const { mode = 'independent', cardProps = {}, ...otherProps } = child.props;
const { label = '', htmlId = getId() } = anchorItemProps;
return (
{React.cloneElement(child, {
ref: (node) => {
// Keep your own reference
formArrayRef.current[index] = node;
// Call the original ref, if any
const { ref } = child;
if (typeof ref === 'function') {
ref(node);
}
},
...otherProps,
mode,
})}
);
})}
>
);
}
function AnchorForm(props: AnchorFormProps, ref: any) {
const {
children,
formMapRef: propsFormMapRef,
operations,
operationConfig,
lastSaveTime,
anchorProps = {},
showAnchor = false,
enableRandomHtmlId,
...otherProps
} = props;
const formArrayRef = useRef>>([]);
useImperativeHandle(propsFormMapRef, () => formArrayRef.current);
if (!children) {
return (
内容为空
);
}
const formArray = new Map();
React.Children.map(children, (child, index) => {
const { anchorItemProps } = child.props;
const name = `${index}`;
const data = { ...anchorItemProps };
if (enableRandomHtmlId) {
data.htmlId = getId();
}
formArray.set(name, data);
});
const operationsProps = {
operations,
operationConfig,
lastSaveTime,
};
const formContent = renderForm(props, formArrayRef, formArray);
return (
{showAnchor ? renderAnchor(anchorProps, formArray) : null}
);
}
export default forwardRef(AnchorForm);
================================================
FILE: packages/fusion-ui/src/components/pro-form/layouts/child-form/index.scss
================================================
#{$biz-css-prefix}subForm-child-form {
&.one-column {
max-width: 600px;
margin: 0 auto;
}
background: #f5f5f5;
border-radius: 6px;
background-color: #f5f5f5;
padding: var(--s-4 $s-4 0 $s-4, $s-4 $s-4 0 $s-4);
margin-bottom: var(--s-4, $s-4);
&.empty-content {
display: flex;
justify-content: center;
align-content: center;
}
}
#{$biz-css-prefix}independent-child-form {
&.one-column {
max-width: 600px;
margin: 0 auto;
}
.next-number-picker {
.next-input-control {
padding-right: 0 !important;
}
}
.next-form-item-label label[required]:before {
margin-right: 0;
content: '';
}
.next-form-item-label label[required]:after {
margin-left: 4px;
content: '*';
color: #ff3000;
}
&.empty-content {
display: flex;
justify-content: center;
align-content: center;
}
}
================================================
FILE: packages/fusion-ui/src/components/pro-form/layouts/child-form/index.tsx
================================================
import * as React from 'react';
import { formatFormItems, ProFormProps } from '../pro-form';
import { ResponsiveGrid } from '@alifd/next';
import { bizCssPrefix } from '@/variables';
export interface ChildFormProps extends ProFormProps {
mode?: string;
}
const ChildForm = (props: ChildFormProps, ref) => {
const { children, columns, mode, spacing = 16, emptyContent, ...otherProps } = props;
const cssPrefix = `${bizCssPrefix}-${mode || 'subForm'}`;
return (
{children ? (
{formatFormItems(
children,
{
columns,
...otherProps,
},
true,
)}
) : (
{emptyContent}
)}
);
};
const RefChildForm = React.forwardRef(ChildForm);
RefChildForm.displayName = 'ChildForm';
export default RefChildForm;
================================================
FILE: packages/fusion-ui/src/components/pro-form/layouts/pro-form/index.scss
================================================
#{$biz-css-prefix}pro-form {
&.one-column {
max-width: 600px;
margin: 0 auto;
}
.next-number-picker {
.next-input-control {
padding-right: 0 !important;
}
}
.next-form-item-label label[required]:before {
margin-right: 0;
content: '';
}
.next-form-item-label label[required]:after {
margin-left: 4px;
content: '*';
color: #ff3000;
}
&.empty-content {
display: flex;
justify-content: center;
align-content: center;
}
}
.next-form-item-control > .next-input,
.next-form-item-control > .next-input-group,
.next-form-item-fullwidth .next-form-item-control > .next-date-picker,
.next-form-item-fullwidth
.next-form-item-control
> .next-date-picker
> .next-date-picker-trigger
> .next-input,
.next-form-item-fullwidth .next-form-item-control > .next-input,
.next-form-item-fullwidth .next-form-item-control > .next-input-group,
.next-form-item-fullwidth .next-form-item-control > .next-month-picker,
.next-form-item-fullwidth .next-form-item-control > .next-range-picker,
.next-form-item-fullwidth .next-form-item-control > .next-select,
.next-form-item-fullwidth .next-form-item-control > .next-time-picker,
.next-form-item-fullwidth .next-form-item-control > .next-year-picker,
.next-form-item-fullwidth .next-form-item-control > .next-number-picker {
width: 100%;
}
================================================
FILE: packages/fusion-ui/src/components/pro-form/layouts/pro-form/index.tsx
================================================
import moment from 'moment';
import * as React from 'react';
import classnames from 'classnames';
import { FormProps } from '@alifd/next/lib/form';
import { ResponsiveGrid, Form } from '@alifd/next';
import { ObjUtils } from '@/utils';
import { bizCssPrefix } from '@/variables';
import Operations from '@/common/operations';
import ProFormItem from '@/components/pro-form/components/form-item';
moment.locale('zh-cn');
const cssPrefix = `${bizCssPrefix}-pro-form`;
function getVisibleChildren(children: any[]) {
return children.filter((child: any) => {
return !child?.props?.invisible;
});
}
export interface ProFormProps extends FormProps {
columns: number;
children: React.ReactChild;
emptyContent: React.ReactNode | string;
spacing: number;
operations?: React.ReactNode | object[];
operationConfig?: object;
lastSaveTime?: number;
device?: string;
}
export const calculateLastRows: Function = (children: any[], gridColumns: number) => {
const rows: any[] = [];
const childrenLength = children.length;
for (let i = 0; i < childrenLength; ) {
const subRows = [];
let index = i;
let sum = 0;
let childColumnSpan =
children[index].props.columnSpan || children[index].props.formItemProps?.columnSpan || 1;
if (childColumnSpan >= gridColumns) {
subRows.push(children[index].key);
} else {
while (index < childrenLength) {
childColumnSpan =
children[index].props.columnSpan || children[index].props.formItemProps?.columnSpan || 1;
sum += childColumnSpan;
if (sum > gridColumns) {
index--;
break;
}
subRows.push(children[index++].key);
}
}
i = ++index;
rows.push(subRows);
}
return rows;
};
export const formatFormItems: Function = (
children: React.ReactChild,
props: ProFormProps,
isChildForm: boolean,
) => {
const {
columns: gridColumns,
size,
device,
labelAlign,
labelTextAlign,
labelCol,
wrapperCol,
colon,
isPreview,
} = props;
let _children;
if (!children) {
return null;
} else if (Array.isArray(children)) {
_children = children.filter(
(child: React.ReactElement) =>
child && ['function', 'object', 'string'].indexOf(typeof child.type) > -1,
);
} else {
_children = [children];
}
_children = getVisibleChildren(_children);
const rows: any = calculateLastRows(_children, gridColumns);
return React.Children.map(_children, (child: React.ReactElement) => {
if (ObjUtils.isReactFragment(child)) {
return formatFormItems(child.props.children, props);
}
if (child && ['function', 'object'].indexOf(typeof child.type) > -1) {
const _labelAlign = device === 'phone' ? 'top' : labelAlign;
const childrenProps: any = {
labelCol: child.props.labelCol ? child.props.labelCol : labelCol,
wrapperCol: child.props.wrapperCol ? child.props.wrapperCol : wrapperCol,
labelAlign: child.props.labelAlign ? child.props.labelAlign : _labelAlign,
labelTextAlign: child.props.labelTextAlign ? child.props.labelTextAlign : labelTextAlign,
colon: 'colon' in child.props ? child.props.colon : colon,
size: child.props.size ? child.props.size : size,
isPreview: child.props.isPreview ? child.props.isPreview : isPreview,
};
const { formItemProps = {}, ...componentProps } = child.props || {};
let { columnSpan = 1 } = formItemProps;
if (!isChildForm && rows[rows.length - 1]?.includes(child.key)) {
childrenProps.style = { marginBottom: '0px' };
}
if (
['ProFormItem', 'ChildForm'].includes(child.type.displayName) ||
child.type?.displayName?.startsWith('Form')
) {
if (child.type.displayName === 'ChildForm') {
columnSpan = gridColumns;
}
return (
{React.cloneElement(child, {
formItemProps: {
...ObjUtils.pickDefined(childrenProps),
...formItemProps,
},
})}
);
}
return (
{React.cloneElement(child, componentProps)}
);
}
return child;
});
};
const ProForm: React.ForwardRefRenderFunction = (props: ProFormProps, ref) => {
const {
children,
columns,
spacing = [0, 16, 16, 0],
operations,
operationConfig,
emptyContent,
lastSaveTime,
...otherProps
} = props;
const { isPreview } = otherProps || {};
const operationProps = { operations, operationConfig, lastSaveTime };
return (
<>
>
);
};
const RefProForm: React.ForwardRefExoticComponent & {
Item?: typeof ProFormItem;
} = React.forwardRef(ProForm);
RefProForm.displayName = 'ProForm';
RefProForm.defaultProps = {};
RefProForm.propTypes = {};
RefProForm.Item = ProFormItem;
export default RefProForm;
================================================
FILE: packages/fusion-ui/src/components/pro-form/layouts/step-form/index.scss
================================================
#{$biz-css-prefix}step-form {
&.steps {
margin-bottom: var(--s-5, $s-5);
}
&.forms {
margin-left: 0;
}
}
================================================
FILE: packages/fusion-ui/src/components/pro-form/layouts/step-form/index.tsx
================================================
import * as React from 'react';
import { useRef, useImperativeHandle, useEffect, useState, forwardRef } from 'react';
import { Step, Box } from '@alifd/next';
import { StepProps, ItemProps } from '@alifd/next/lib/step';
import Operations from '@/common/operations';
export interface StepFormProps extends StepProps {
children?: React.ReactElement;
onPrevious?: Function;
onNext?: Function;
formRef?: React.MutableRefObject;
formMapRef?: React.MutableRefObject;
operations?: any[];
operationConfig?: Record;
lastSaveTime?: Number;
}
export interface StepFormItemProps extends ItemProps {
stepItemProps?: React.ReactNode;
}
const ACTION_MAP = {
previous: (step, setStep) => {
setStep(Math.max(0, --step));
},
next: (step, setStep, stepLength) => {
setStep(Math.min(stepLength - 1, ++step));
},
};
const noop = () => {};
function getAction(action: string | number) {
return ACTION_MAP[action] || noop;
}
function renderStep(
props: StepFormProps,
formArray: Map,
step: number,
formArrayRef,
) {
const { direction = 'hoz', children, showAll, ...others } = props;
if (direction === 'hoz') {
return (
{formArray && (
{Array.from(formArray.keys()).map((item) => {
const { stepItemProps } = formArray.get(item);
return ;
})}
)}
);
}
return (
{React.Children.map(children, (child: React.ReactElement, index) => {
const { stepItemProps } = formArray.get(`${index}`);
const content = (
{React.cloneElement(child, {
ref: (node) => {
// Keep your own reference
formArrayRef.current[index] = node;
// Call the original ref, if any
const { ref } = child;
if (typeof ref === 'function') {
ref(node);
}
},
})}
);
return ;
})}
);
}
function renderForm(
props: StepFormProps,
step: number,
formArrayRef: React.MutableRefObject>>,
) {
const { children } = props;
return (
<>
{React.Children.map(children, (child: React.ReactElement, index) => {
return (
{React.cloneElement(child, {
ref: (node) => {
// Keep your own reference
formArrayRef.current[index] = node;
// Call the original ref, if any
const { ref } = child;
if (typeof ref === 'function') {
ref(node);
}
},
})}
);
})}
>
);
}
const renderOperations = ({
operations,
operationConfig = {},
lastSaveTime,
onPrevious,
onNext,
step,
setStep,
stepLength,
}) => {
if (!operations || !operations.length) {
return null;
}
const baseOperations = operations.map((operation: any) => {
let onClick = getAction(operation.action).bind(this, step, setStep, stepLength);
if (operation.action) {
if (operation.action === 'next') {
operation.disabled = step === stepLength - 1;
if (onNext && typeof onNext === 'function') {
onClick = onNext;
}
} else if (operation.action === 'previous') {
operation.disabled = step === 0;
if (onPrevious && typeof onPrevious === 'function') {
onClick = onPrevious;
}
}
}
return {
onClick,
...operation,
};
});
const operationsProps = {
operations: baseOperations,
operationConfig,
lastSaveTime,
};
return ;
};
function StepForm(props: StepFormProps, ref) {
const {
children,
onPrevious,
onNext,
formRef,
formMapRef: propsFormMapRef,
operations,
operationConfig,
lastSaveTime,
direction = 'hoz',
} = props;
const [step, setStep] = useState(props.current);
const formArrayRef = useRef>>([]);
useImperativeHandle(propsFormMapRef, () => formArrayRef.current);
const currentFormRef = formArrayRef.current[step || 0]?.current;
useImperativeHandle(formRef, () => currentFormRef);
const formArray = new Map();
React.Children.map(children, (child, index) => {
const itemProps = child.props as StepFormItemProps;
const name = `${index}`;
formArray.set(name, itemProps);
});
useEffect(() => {
setStep(props.current);
}, [props.current]);
if (!children) {
return (
内容为空
);
}
return (
<>{renderStep(props, formArray, step, formArrayRef)}>
<>{direction === 'hoz' ? renderForm(props, step, formArrayRef) : null}>
{renderOperations({
operations,
operationConfig,
lastSaveTime,
onPrevious,
onNext,
step,
setStep,
stepLength: formArray.size,
})}
);
}
export default forwardRef(StepForm);
================================================
FILE: packages/fusion-ui/src/components/pro-table/components/edit-table/index.scss
================================================
.fusion-ui-pro-table {
.row-add {
height: 37px;
background: #f6f8fb;
border: 1px dashed #c8d6fa;
background-color: #f6f8fb;
}
.next-table-cell-wrapper .next-select,
.next-table-cell-wrapper .next-input {
width: 100% !important;
min-width: 100% !important;
}
}
================================================
FILE: packages/fusion-ui/src/components/pro-table/components/edit-table/index.tsx
================================================
import * as React from 'react';
import { Button } from '@alifd/next';
import { ProTable, ProTableProps } from '../../index';
import { Space } from '@/components/container';
export interface EditTableProps extends ProTableProps {
addPosition?: 'end' | 'start';
onSave?: (rowIndex: number, record: Record, dataSource: any[]) => void;
onRemove?: (rowIndex: number, record: Record, dataSource: any[]) => void;
onCancel?: (rowIndex: number, record: Record, dataSource: any[]) => void;
}
export const EditTable = function (props: EditTableProps) {
const {
primaryKey = 'id',
dataSource: propDataSource,
actionColumnButtons: propActionColumnButtons = { dataSource: [] },
onSave,
onRemove,
onCancel,
addPosition = 'end',
...otherProps
} = props;
const [dataSource, setDataSource] = React.useState(propDataSource);
const dataSourceRef = React.useRef(dataSource);
const [actionColumnButtons, setActionColumnButtons] = React.useState(propActionColumnButtons);
function actionColumnButtonsHidden(showInEdit) {
return ({ rowRecord }) => {
return showInEdit ? !!rowRecord.editMode : !rowRecord.editMode;
};
}
const defaultActionColumnButtons = [
{
children: '编辑',
type: 'primary',
onClick(e, payload) {
const { rowKey, rowRecord } = payload;
const _data = dataSourceRef.current.map((item) => {
if (item[primaryKey] === rowKey) {
return Object.assign(item, rowRecord, { editMode: true });
}
return item;
});
setDataSource(_data);
},
hidden: actionColumnButtonsHidden(true),
},
{
children: '保存',
type: 'primary',
onClick(e, payload) {
const { rowIndex, rowKey, rowRecord } = payload;
const _data = dataSourceRef.current.map((item) => {
if (item[primaryKey] === rowKey) {
return Object.assign(item, rowRecord, { editMode: false });
}
return item;
});
onSave && onSave(rowIndex, rowRecord, _data);
setDataSource(_data);
},
hidden: actionColumnButtonsHidden(false),
},
{
children: '取消',
type: 'primary',
onClick(e, payload) {
const { rowIndex, rowKey, rowRecord } = payload;
const _data = dataSourceRef.current.map((item) => {
if (item[primaryKey] === rowKey) {
const keys = Object.keys(item);
const originKeys = keys.filter((key) => key.startsWith('origin-'));
originKeys.forEach((originKey) => {
item[originKey.replace('origin-', '')] = item[originKey];
});
return Object.assign(item, { editMode: false });
}
return item;
});
onCancel && onCancel(rowIndex, rowRecord, _data);
setDataSource(_data);
},
hidden: actionColumnButtonsHidden(false),
},
{
children: '删除',
type: 'primary',
onClick(e, payload) {
const { rowKey, rowIndex, rowRecord } = payload;
dataSourceRef.current = dataSourceRef.current.filter((item) => item[primaryKey] !== rowKey);
setDataSource(dataSourceRef.current);
onRemove && onRemove(rowIndex, rowRecord, dataSourceRef.current);
},
},
];
React.useEffect(() => {
const { dataSource: actionColumnDataSource = [] } = propActionColumnButtons;
const _actionColumnButtons = {
...actionColumnButtons,
dataSource: defaultActionColumnButtons.concat(actionColumnDataSource),
};
setActionColumnButtons(_actionColumnButtons);
}, [propActionColumnButtons, dataSource]);
const tableAfter = (
);
return (
<>
>
);
};
================================================
FILE: packages/fusion-ui/src/components/pro-table/components/group-table/index.tsx
================================================
import * as React from 'react';
import { ProTableProps } from '../../types';
import { ProTable } from '../pro-table';
export const GroupTable: React.FC = (props) => {
const { groupHeader: propGroupHeader, groupFooter: propGroupFooter, ...otherProps } = props;
const groupHeader = propGroupHeader || {
cell: (record) => record?.header,
};
const groupFooter = propGroupFooter || {
cell: (record) => record?.footer,
};
return ;
};
GroupTable.defaultProps = {
settingButtons: false,
defaultColumnsSetting: {},
columnKey: 'key',
primaryKey: 'id',
stickyLock: true,
resizable: true,
emptyContent: ,
hasBorder: false,
size: 'medium',
isZebra: false,
cellDefault: '',
cellTooltipMode: 'none',
};
================================================
FILE: packages/fusion-ui/src/components/pro-table/components/pro-table/index.scss
================================================
.fusion-ui-pro-table {
.fusion-ui-pagination {
padding: var(--s-4 0 0, $s-4 0 0);
display: flex;
justify-content: flex-end;
}
&.fullscreen {
padding: var(--s-5 $s-5 0, $s-5 $s-5 0);
background: var(--color-white, $color-white);
overflow-y: auto;
.fusion-ui-pagination {
box-sizing: border-box;
position: sticky;
bottom: 0;
background-color: var(--color-white, $color-white);
border-radius: var(--corner-2, $corner-2);
z-index: 9;
}
}
&-expanded-child {
padding: var(--s-5 $s-5 $s-2 $s-5, $s-5 $s-5 $s-2 $s-5);
background-color: var(--color-fill1-2, $color-fill1-2);
}
}
.fusion-ui-pro-table-body {
display: flex;
flex-direction: column;
gap: var(--s-4, $s-4);
.fusion-ui-pro-table-action-bar {
margin: 0;
}
}
.fusion-ui-pro-table-content {
position: relative;
.next-loading.next-open.next-loading-inline.next-table-loading-content{
position: absolute;
width: 100%;
height: 100%;
top: 0;
}
}
================================================
FILE: packages/fusion-ui/src/components/pro-table/components/pro-table/index.tsx
================================================
import * as React from 'react';
import { Space } from '@/components/container';
import { Box, Pagination } from '@alifd/next';
import { ProTableProps, ProTableSettingButtonType } from '../../types';
import { ProTableCompactButton } from '../pro-table-compact-button';
import { ProTableZebraButton } from '../pro-table-zebra-button';
import { ProTableFullscreenButton } from '../pro-table-fullscreen-button';
import { ProTableSettingButton } from '../pro-table-setting-button';
import { useProTableSlots } from '../pro-table-slot';
import {
ProTableContext,
useProTableValue,
} from '@/components/pro-table/contexts/pro-table-context';
import {
ProTableColumnsSettingContext,
useColumnsSettingValue,
} from '@/components/pro-table/contexts/pro-table-columns-setting-context';
import {
ProTableColumnsFilterContext,
useColumnsFilterValue,
} from '@/components/pro-table/contexts/pro-table-columns-filters-context';
import { ProTableBase } from '../pro-table-base/index';
// import { Result } from '@/result';
import {
ProTableSettingContext,
useProTableSettingValue,
} from '@/components/pro-table/contexts/pro-table-setting-context';
import is from '@sindresorhus/is';
import { ToggleIconGroup } from '@/components/toggle-icon';
import {
ProTableColumnsContext,
useProTableColumnsValue,
} from '@/components/pro-table/contexts/pro-table-columns-context';
import cns from 'classnames';
// import { Pagination } from '../../../pagination/index';
import { ProTableActionBarButtonGroup } from '../pro-table-action-bar-buttons';
import {
useProTableRowSelectionValue,
ProTableRowSelectionContext,
} from '../../contexts/pro-table-row-selection-context';
export const ProTable: React.FC = (props: ProTableProps) => {
const slots = useProTableSlots(props);
const columnsFiltersCtxValue = useColumnsFilterValue(props);
const columnsSettingCtxValue = useColumnsSettingValue(props);
const proTableSettingCtxValue = useProTableSettingValue(props);
const { paginationProps, settingButtons } = props;
const proTableContainer = React.useRef();
const tableBeforeContainer = React.useRef();
const proTableCtxValue = useProTableValue({
pageSize: paginationProps?.pageSize,
total: paginationProps?.total,
tableBeforeContainer,
proTableContainer,
});
const proTableColumnsCtxValue = useProTableColumnsValue(props);
const proTableRowSelectionCtxValue = useProTableRowSelectionValue(props);
const buttons = React.useMemo(() => {
if (settingButtons === false) {
return [];
}
if (is.array(settingButtons)) {
return settingButtons;
}
return ['compact', 'zebra', 'fullscreen', 'setting'];
}, [settingButtons]);
const loading = React.useMemo(
() => !columnsFiltersCtxValue.filterPanelVisible && props.loading,
[columnsFiltersCtxValue.filterPanelVisible, props.loading],
);
const hasActionBarButtons = props.actionBarButtons?.dataSource?.length > 0;
return (
{slots.actionBarBefore}
{(buttons.length > 0 ||
hasActionBarButtons ||
slots.actionBarLeft ||
slots.actionBarRight) && (
{hasActionBarButtons && (
)}
{slots.actionBarLeft}
{slots.actionBarRight}
{buttons.length > 0 && (
{buttons.includes('compact') && }
{buttons.includes('zebra') && }
{buttons.includes('fullscreen') && (
)}
{buttons.includes('setting') && }
)}
)}
{slots.actionBarAfter}
{slots.table}
{slots.tableAfter}
{paginationProps && !paginationProps.hidden && (
)}
);
};
ProTable.defaultProps = {
settingButtons: false,
defaultColumnsSetting: {},
columnKey: 'key',
primaryKey: 'id',
stickyLock: true,
resizable: true,
emptyContent: (
暂无内容
),
hasBorder: false,
size: 'medium',
isZebra: false,
cellDefault: '',
cellTooltipMode: 'none',
};
================================================
FILE: packages/fusion-ui/src/components/pro-table/components/pro-table-action-bar-buttons.tsx
================================================
import React, { useContext, useMemo } from 'react';
import { ProTableButtonGroup } from './pro-table-button-group/index';
import { ProTableActionBarButtons } from '../types';
import { ProTableRowSelectionContext } from '../contexts/pro-table-row-selection-context';
export const ProTableActionBarButtonGroup: React.FC = (props) => {
const rowSelection = useContext(ProTableRowSelectionContext);
const payload = useMemo(
() => ({
rowSelection,
}),
[rowSelection],
);
return ;
};
================================================
FILE: packages/fusion-ui/src/components/pro-table/components/pro-table-base/columns/useActionColumn.tsx
================================================
import { ColumnProps } from '@alifd/next/types/table';
import * as React from 'react';
import is from '@sindresorhus/is';
import {
ProTableBaseProps,
ProTableRowRecord,
ProTableProps,
ProTableActionColumnButtons,
ProTableRowPayload,
} from '../../../types';
import { useI18nBundle } from '@/provider';
import { emptyFn } from '@/utils/constants';
import { usePersistFn } from 'ahooks';
import get from 'lodash/get';
import { ProTableButtonGroup, ProTableButtonGroupProps } from '../../pro-table-button-group/index';
type ActionColumnProps = Pick<
ProTableBaseProps,
| 'actionColumn'
| 'actionButtonGroupProps'
| 'actionColumnButtons'
| 'actionColumnProps'
| 'actionColumnPredication'
| 'onActionColumnClick'
| 'primaryKey'
>;
const calcButtonWidth = (str: React.ReactNode) => {
if (is.string(str)) {
return str.length * 12 + 12;
}
return 50;
};
/**
* 操作列
*/
export const useActionColumn = ({
actionColumn,
actionColumnProps,
actionColumnPredication,
actionButtonGroupProps,
actionColumnButtons,
onActionColumnClick,
primaryKey,
}: ActionColumnProps): ColumnProps => {
const i18nBundle = useI18nBundle('ProTable');
const handleActionColumnClick = usePersistFn(onActionColumnClick || emptyFn);
const buttonGroupProps = {
dataSource: actionColumn,
...(actionColumnButtons || actionButtonGroupProps),
};
if (!is.array(buttonGroupProps.dataSource) || buttonGroupProps.dataSource.length === 0) {
return undefined;
}
const width =
actionColumnProps?.width ||
buttonGroupProps.dataSource
.slice(0, 3)
.map((vo) => calcButtonWidth(vo.children))
.reduce((p, vo) => p + vo, buttonGroupProps.dataSource.length > 3 ? 65 : 30);
return {
width,
lock: 'right',
title: i18nBundle.operation,
cell: (value, rowIndex, rowRecord) => (
),
...actionColumnProps,
};
};
interface ActionColumnButtonGroupProps {
rowIndex: number;
rowRecord: ProTableRowRecord;
actionColumnPredication?: ProTableProps['actionColumnPredication'];
onActionColumnClick?: ProTableProps['onActionColumnClick'];
primaryKey: ProTableProps['primaryKey'];
buttonGroupProps: ProTableActionColumnButtons;
}
const ActionColumnButtonGroup: React.FC = ({
rowIndex,
rowRecord,
actionColumnPredication,
onActionColumnClick,
primaryKey,
buttonGroupProps,
}) => {
const payload = React.useMemo(
() => ({
rowKey: rowRecord[primaryKey],
rowIndex,
rowRecord,
}),
[rowIndex, primaryKey, rowRecord],
);
const { dataSource, ...otherProps } = buttonGroupProps;
const realDataSource = React.useMemo(() => {
const buttons = is.function_(actionColumnPredication)
? actionColumnPredication({
actionColumn: dataSource,
index: payload.rowIndex,
record: payload.rowRecord,
})
: dataSource;
return is.array(buttons)
? buttons.map((vo) => ({
onClick: () => {
onActionColumnClick({
currentActionKey: vo.key,
selectedRowKey: payload.rowKey,
record: payload.rowRecord,
});
},
...vo,
hidden: is.string(vo.hidden)
? () => !!get(payload.rowRecord, vo.hidden as string)
: vo.hidden,
disabled: is.string(vo.disabled)
? () => !!get(payload.rowRecord, vo.disabled as string)
: vo.disabled,
}))
: [];
}, [actionColumnPredication, dataSource, onActionColumnClick, payload]);
return ;
};
ActionColumnButtonGroup.defaultProps = {
onActionColumnClick: emptyFn,
};
================================================
FILE: packages/fusion-ui/src/components/pro-table/components/pro-table-base/columns/useIndexColumn.tsx
================================================
import { useI18nBundle } from '@/provider';
import { ColumnProps } from '@alifd/next/types/table';
import * as React from 'react';
import { ProTableBaseProps } from '../../../types';
type IndexColumnProps = Pick;
/**
* 序号列
*/
export const useIndexColumn = ({
indexColumn,
indexColumnProps,
}: IndexColumnProps): ColumnProps => {
const i18nBundle = useI18nBundle('ProTable');
if (!indexColumn) {
return undefined;
}
return {
width: 70,
lock: 'left',
title: i18nBundle.indexColumnTitle,
cell: (value: any, index: number) => (
{index + 1}
),
align: 'center',
...indexColumnProps,
};
};
================================================
FILE: packages/fusion-ui/src/components/pro-table/components/pro-table-base/columns/useRowSelection.tsx
================================================
import * as React from 'react';
import { Checkbox } from '@alifd/next';
import { CustomIcon } from '@/components/toggle-icon';
import { MenuButton } from '@/components/menu-button';
import {
ProTableBaseProps,
ProTableRowKey,
ProTableRowRecord,
ProTableRowSelectionType,
} from '../../../types';
import numvert from 'numvert';
import is from '@sindresorhus/is';
import { emptyFn } from '@/utils/constants';
import { ProTableContext } from '../../../contexts/pro-table-context';
import ReactDOM from 'react-dom';
import { ProTableRowSelectionContext } from '../../../contexts/pro-table-row-selection-context';
export const isSelectedAllPages = (selectedRowKeys: ProTableRowKey[], reverseSelection: boolean) =>
reverseSelection && selectedRowKeys.length === 0;
export const hasSelectedRows = (selectedRowKeys: ProTableRowKey[], reverseSelection: boolean) =>
reverseSelection || selectedRowKeys.length > 0;
/**
* 行选择逻辑
* - 支持选择当前页所有行
* - 支持跨页选择
* - 支持选择所有页
*/
export const useRowSelection = (
originRowSelection: ProTableBaseProps['rowSelection'],
dataSource: any[] = [],
) => {
const hasRowSelection = !!originRowSelection;
const rowSelection = hasRowSelection ? originRowSelection : {};
const { tableBeforeContainer } = React.useContext(ProTableContext);
const instance = React.useContext(ProTableRowSelectionContext);
const tooltip = useProTableSelectionTooltip(
rowSelection.crossPageSelection === false
? instance.currentPageSelectedRowKeys.length
: instance.selectedRowKeys.length,
instance.reverseSelection,
);
if (!hasRowSelection) {
return undefined;
}
if (rowSelection.ref) {
rowSelection.ref.current = instance;
}
const {
selectAllPages,
selectCurrentPage,
currentPageSelectedRowKeys,
reverseSelection,
selectRows,
selectedRowKeys,
getRowKeyByRecord,
currentPageRowKeys,
} = instance;
const {
onSelect = emptyFn,
onSelectAll = emptyFn,
selections = ['SELECTION_ALL', 'SELECTION_NONE'],
titleProps,
} = rowSelection;
const isMultiple = rowSelection.mode !== 'single';
const hasMenu = isMultiple && is.array(selections) && selections.length > 0;
return {
mode: rowSelection.mode,
getProps: rowSelection.getProps,
selectedRowKeys: currentPageSelectedRowKeys,
onSelect: (selected: boolean, record: ProTableRowRecord, records: ProTableRowRecord[]) => {
selectRows(selected, [getRowKeyByRecord(record)]);
onSelect(selected, record, records);
},
columnProps: () => ({
align: 'left',
width: hasMenu ? 70 : 50,
}),
titleProps: () => ({
style: {
display: 'none',
},
}),
titleAddons: !isMultiple
? undefined
: () => {
const selectionTexts: Record = {
SELECTION_ALL: '全选所有',
SELECTION_NONE: '清空所有',
};
const globalChecked = currentPageSelectedRowKeys.length > 0;
const globalCheckedIndeterminate =
globalChecked &&
(reverseSelection
? selectedRowKeys.length > 0
: currentPageSelectedRowKeys.length < currentPageRowKeys.length);
const checkboxProps = titleProps ? titleProps() : {};
return (
<>
{!rowSelection.hideTooltip &&
tableBeforeContainer.current &&
tooltip &&
ReactDOM.createPortal(
{tooltip}
,
tableBeforeContainer.current,
)}
{
onSelectAll(selected, dataSource);
selectCurrentPage(selected);
}}
{...checkboxProps}
/>
{hasMenu && (
}
text
onItemClick={(key: ProTableRowSelectionType) => {
if (key === 'SELECTION_ALL') {
selectAllPages(true);
} else if (key === 'SELECTION_NONE') {
selectAllPages(false);
}
}}
popupTriggerType="hover"
autoWidth={false}
menuProps={{
isSelectIconRight: false,
}}
dataSource={selections.map((vo) => ({ key: vo, label: selectionTexts[vo] }))}
/>
)}
>
);
},
// ...rowSelection,
};
};
const renders = {
selected: (amount: number) => (
<>
已选中
{numvert(amount).format('0,0')}
条
>
),
selectedWithPageCount: (amount: number, pageCount: number) => (
<>
已选中{pageCount}页, 共
{numvert(amount).format('0,0')}
条
>
),
allPageUnselected: (amount: number) => (
<>
已选中所有页,反选
{numvert(amount).format('0,0')}
条
>
),
allPageSelectedAll: () => <>已选中所有项>,
};
const useProTableSelectionTooltip = (selecteAmount: number, reverseSelection: boolean) => {
const { total, pageSize } = React.useContext(ProTableContext);
return React.useMemo(() => {
if (reverseSelection) {
if (is.number(total)) {
if (total === 0) {
return undefined;
}
const pageCount =
is.number(pageSize) && is.number(total) && pageSize !== 0
? Math.ceil(total / pageSize)
: undefined;
return is.number(pageCount)
? renders.selectedWithPageCount(total - selecteAmount, pageCount)
: renders.selected(total - selecteAmount);
}
if (selecteAmount > 0) {
return renders.allPageUnselected(selecteAmount);
}
return renders.allPageSelectedAll();
}
if (selecteAmount > 0) {
return renders.selected(selecteAmount);
}
return undefined;
}, [reverseSelection, selecteAmount, total, pageSize]);
};
================================================
FILE: packages/fusion-ui/src/components/pro-table/components/pro-table-base/index.scss
================================================
.fusion-ui-pro-table-base {
position: relative;
.next-table-empty {
min-height: 224px;
}
.next-table-cell-wrapper:hover {
.next-table-resize-handler {
border-color: var(--color-line1-4, $color-line1-4);
}
}
.next-table-header-resizable .next-table-resize-handler {
width: var(--s-2, $s-2);
border-right: 2px solid transparent;
}
// 标题样式修改
.next-table-header .next-table-cell .next-table-cell-wrapper {
word-break: break-word;
}
// 内容样式修改
.next-table-body .next-table-cell .next-table-cell-wrapper {
word-break: break-word;
}
.only-bottom-border td {
border: 0;
}
.only-bottom-border .next-table-group .next-table-body table {
border-top: 0;
border-left: 0;
border-bottom: 0;
}
// 统计列相关样式修改
.fusion-ui-pro-table-total-row {
background: var(--color-fill1-1, $color-fill1-1);
font-family: Roboto-Medium;
font-size: var(--font-size-body-2, $font-size-body-2);
line-height: 16px;
font-weight: var(--font-weight-medium, $font-weight-medium);
}
.cell-money {
white-space: nowrap;
overflow: visible;
}
.cell-nowrap {
white-space: nowrap;
}
.fusion-ui-table-sort {
.fusion-ui-pro-table-sort-icon {
left: 0;
&.fusion-ui-icon-triangle-down {
top: 6px;
}
&.fusion-ui-icon-triangle-up {
top: -2px;
}
}
}
}
// 在 selectedRowKeys.length > 0 时展示 "已选择 x 项" 的容器
.fusion-ui-pro-table-selection {
position: absolute;
z-index: 50;
will-change: transform;
background-color: var(--color-white, $color-white);
border-radius: var(--s-1, $s-1);
padding: var(--s-1 $s-2, $s-1 $s-2);
text-align: center;
top: -16px;
left: var(--s-2, $s-2);
perspective: 800px;
box-shadow: var(--shadow-2, $shadow-2);
white-space: nowrap;
font-weight: normal;
font-size: var(--font-size-body-1, $font-size-body-1);
&-placeholder {
position: absolute;
width: 10px;
height: 10px;
background-color: red;
left: -8px;
top: 0;
}
&-number {
color: var(--color-brand1-6, $color-brand1-6);
font-weight: var(--font-weight-medium, $font-weight-medium);
margin: 0 $s-1;
}
}
.fusion-ui-tablex-serial-number {
color: var(--color-white, $color-white);
text-align: center;
font-size: var(--font-size-body-1, $font-size-body-1);
display: inline-flex;
justify-content: center;
align-items: center;
height: var(--s-5, $s-5);
width: var(--s-5, $s-5);
border-radius: var(--corner-2, $corner-2);
background-color: var(--color-line1-4, $color-line1-4);
}
.fusion-ui-pro-table-selection-checkbox {
display: inline-flex;
flex-direction: row;
align-items: center;
gap: var(--s-1, $s-1);
.fusion-ui-menu-btn {
color: var(--color-text1-2, $color-text1-2);
}
.fusion-ui-menu-btn-arrow {
display: none !important;
}
}
================================================
FILE: packages/fusion-ui/src/components/pro-table/components/pro-table-base/index.tsx
================================================
import * as React from 'react';
import cns from 'classnames';
import { Table } from '@alifd/next';
import { TableProps } from '@alifd/next/types/table';
import { getColumnKey, pickTableProps } from './utils';
import { useMemo } from 'react';
import { useActionColumn } from './columns/useActionColumn';
import { useIndexColumn } from './columns/useIndexColumn';
import { ProTableBaseProps } from '../../types';
import { renderColumns, useColumnsWithSetting } from '../pro-table-column';
import { useRowSelection } from './columns/useRowSelection';
import { ProTableColumnsSettingContext } from '../../contexts/pro-table-columns-setting-context';
import { ProTableSettingContext } from '@/components/pro-table/contexts/pro-table-setting-context';
import { registerColumnFormatters } from '../pro-table-column/pro-table-column-formatter';
import { defaultColumnFormatters } from '../pro-table-column/defaultColumnFormatters';
import { emptyFn } from '@/utils/constants';
import { ProTableCell } from '../pro-table-cell/pro-table-cell';
import { ProTableTreeCell } from '../pro-table-cell/pro-table-tree-cell';
// import { ProTableCell } from '../pro-table-cell';
registerColumnFormatters(defaultColumnFormatters);
const totalCell = () => 'Total';
const valueCell = (val) => val;
export const ProTableBase: React.FC = (props) => {
const { tableSetting } = React.useContext(ProTableSettingContext);
const {
columnKey,
resizable,
dataSource: originalDataSource,
rowSelection,
expandedRowRender,
groupHeader,
groupFooter,
totalDataSource,
} = props;
const actionColumnProps = useActionColumn(props);
const indexColumnProps = useIndexColumn(props);
const { updateColumnSetting, columnsSetting } = React.useContext(ProTableColumnsSettingContext);
const { flatColumns, columnsWithSetting } = useColumnsWithSetting({
columnKey,
columnsSetting,
columns: props.columns,
cellDefault: props.cellDefault,
cellTooltipMode: props.cellTooltipMode,
});
// table 属性
const externalProps: Partial = {
expandedIndexSimulate: expandedRowRender ? true : undefined,
};
if (resizable) {
externalProps.hasBorder = false;
externalProps.onResizeChange = (dataIndex, width) => {
const columnItem = flatColumns.find((vo) => vo.dataIndex === dataIndex);
if (!columnItem) {
console.warn(`未找到dataIndex=${dataIndex}的columnItem`);
return;
}
updateColumnSetting(
getColumnKey(columnItem, columnKey),
(oldSetting) => {
const oldWidth = +oldSetting.width || +columnItem.width || 200;
return {
width: Math.max(10, oldWidth + width),
};
},
'resize',
);
};
}
const dataSource = useMemo(
() => (totalDataSource ? [...(originalDataSource || []), totalDataSource] : originalDataSource),
[totalDataSource, originalDataSource],
);
if (totalDataSource) {
// 数据列第一列的下标,去掉表左侧功能列
const dataColumnsStartIndex = [expandedRowRender, rowSelection, indexColumnProps].filter(
(vo) => vo,
).length;
// 数据列最后一列的下标,去掉表右侧功能列
const dataColumnsEndIndex = dataColumnsStartIndex + flatColumns.length - 1;
// 统计行下标
const totalRowIndex = dataSource.length - 1;
externalProps.rowProps = (record, rowIndex) => {
if (rowIndex === totalRowIndex) {
return {
className: 'fusion-ui-pro-table-total-row',
};
}
return {};
};
externalProps.cellProps = (rowIndex, colIndex) => {
if (rowIndex === totalRowIndex) {
// 统计行的数据第一列显示 Total 文案
if (colIndex === 0) {
return {
cell: totalCell,
onCellClick: undefined,
formatValue: undefined,
};
}
// 不在数据列范围内的隐藏
if (colIndex < dataColumnsStartIndex || colIndex > dataColumnsEndIndex) {
return {
cell: emptyFn,
onCellClick: undefined,
formatValue: undefined,
};
}
return {
cell: valueCell,
onCellClick: undefined,
formatValue: undefined,
};
}
return {};
};
}
const NextTable = props.stickyLock ? Table.StickyLock : Table;
const nextTableProps = pickTableProps({
...externalProps,
...props,
...tableSetting,
rowSelection: useRowSelection(rowSelection, originalDataSource),
dataSource,
columns: undefined, // 剔除columns
className: cns('fusion-ui-pro-table-base', props.className),
});
const columns = renderColumns(columnsWithSetting, {
resizable,
});
return (
{groupHeader &&
(React.isValidElement(groupHeader) ? (
groupHeader
) : (
))}
{groupFooter &&
(React.isValidElement(groupFooter) ? (
groupFooter
) : (
))}
{indexColumnProps && }
{columns}
{actionColumnProps && }
{props.children}
);
};
ProTableBase.displayName = 'ProTableBase';
================================================
FILE: packages/fusion-ui/src/components/pro-table/components/pro-table-base/utils.tsx
================================================
import pick from 'lodash/pick';
import { TableProps } from '@alifd/next/types/table';
import { ProTableColumnProps, ProTableBaseProps } from '../../types';
export function getColumnKey(column: ProTableColumnProps, columnKey?: string) {
if (columnKey) {
if (column[columnKey]) {
return column[columnKey];
}
}
if (column.key) {
return column.key;
}
if (column.dataIndex) {
return column.dataIndex;
}
console.warn(
`[TableX] 自定义列需要每个 column 必须有 ${columnKey} | key | dataIndex 属性`,
column,
);
}
const nextTablePropsKeys: Array = [
// next table 所有属性
'affixProps',
'cellProps',
'className',
'columns',
'crossline',
'dataSource',
'emptyContent',
'expandedIndexSimulate',
'expandedRowIndent',
'expandedRowRender',
'filterParams',
'fixedHeader',
// 'getCellProps', // fusion 废弃
'getExpandedColProps',
// 'getRowProps', // fusion 废弃
'hasBorder',
'hasExpandedRowCtrl',
'hasHeader',
'indent',
'isTree',
'isZebra',
'loading',
'loadingComponent',
'locale',
'maxBodyHeight',
'offsetTop',
'onBodyScroll',
'onExpandedRowClick',
'onFilter',
'onResizeChange',
'onRowClick',
'onRowMouseEnter',
'onRowMouseLeave',
'onRowOpen',
'onSort',
'openRowKeys',
'prefix',
'primaryKey',
'pure',
'rowExpandable',
'rowHeight',
'rowProps',
'rowSelection',
'rtl',
'scrollToRow',
'size',
'sort',
'sortIcons',
'stickyHeader',
'style',
'tableLayout',
'tableWidth',
'useVirtual',
'warning',
];
export const pickTableProps = (whaleTableProps: ProTableBaseProps) => {
return pick(
whaleTableProps,
nextTablePropsKeys.filter((vo) => whaleTableProps[vo] !== undefined),
);
};
================================================
FILE: packages/fusion-ui/src/components/pro-table/components/pro-table-button-group/index.tsx
================================================
import * as React from 'react';
import { Button, ButtonProps } from '@/components/button';
import { MenuButton, MenuButtonProps } from '@/components/menu-button';
import { Space, SpaceProps } from '@/components/container';
import { PayloadButtonProps, usePayloadButtons } from './payload-button';
import { useI18nBundle } from '@/provider/contexts/locale-context/index';
import { omit } from 'lodash';
export interface ProTableButtonGroupProps extends SpaceProps {
/**
* 是否设定按钮为文字模式
*/
text?: boolean;
/**
* 可见按钮数量,超过会收起到”更多“菜单中
*/
maxCount?: number;
/**
* 按钮
*/
payload?: Payload;
/**
* 数据源驱动
*/
dataSource?: Array>;
/**
* "更多" 按钮的额外配置
*/
moreMenuButtonProps?: Partial;
}
export const ProTableButtonGroup: React.FC = ({
text,
maxCount,
payload,
dataSource,
moreMenuButtonProps,
...otherProps
}) => {
const i18nBundle = useI18nBundle('ButtonGroup');
const realDataSource = usePayloadButtons(dataSource, payload);
const splitIndex = getVisibleSplitIndex(realDataSource, maxCount);
const visibleButtons = realDataSource.slice(0, splitIndex);
const menuButtons = realDataSource.slice(splitIndex).map((vo) => omit(vo, ['type', 'text']));
return (
{text
? visibleButtons.map((dataSourceItem, idx) => (
))
: visibleButtons.map((dataSourceItem, idx) => )}
{menuButtons.length > 0 && (
)}
);
};
ProTableButtonGroup.defaultProps = {
maxCount: 4,
moreMenuButtonProps: {},
};
ProTableButtonGroup.displayName = 'ProTableButtonGroup';
const getVisibleSplitIndex = (dataSource: ButtonProps[], maxCount: number) => {
/**
* ButtonGroup:
* maxCount 2 时
* 包括更多按钮显示的数量
*
* 按钮 4 个, 显示 3 个按钮 + 1 个更多按钮
* 按钮 3 个, 显示 3 个按钮
* 按钮 2 个, 显示 2 个按钮
*
* 改进方案:
* maxCount 2 时
* 包括更多按钮显示的数量
*
* 按钮 4 个, 显示 1 个按钮 + 1 个更多按钮
* 按钮 3 个, 显示 1 个按钮 + 1 个更多按钮
* 按钮 2 个, 显示 2 个按钮
*
*/
if (dataSource.length <= maxCount) {
return dataSource.length;
}
return maxCount - 1;
};
================================================
FILE: packages/fusion-ui/src/components/pro-table/components/pro-table-button-group/payload-button.ts
================================================
import * as React from 'react';
import { ButtonProps } from '@/components/button';
import is from '@sindresorhus/is';
export interface PayloadButtonProps
extends Omit {
payload?: Payload;
/**
* 是否隐藏按钮
* @default false
*/
hidden?: boolean | ((payload?: Payload) => boolean);
/**
* 是否禁用按钮
* @default false
*/
disabled?: boolean | ((payload?: Payload) => boolean);
/**
* 按钮点击事件
*/
onClick?: (e: React.MouseEvent, payload?: Payload) => unknown;
}
function isPayloadButtonTruth(
cb: boolean | ((payload?: Payload) => boolean),
payload?: Payload,
): boolean {
return is.function_(cb) ? cb(payload) : cb;
}
export const usePayloadButtons = (
buttons: Array>,
payload: Payload,
) =>
React.useMemo(
() =>
buttons
.filter((vo) =>
is.nullOrUndefined(vo.hidden) ? true : !isPayloadButtonTruth(vo.hidden, payload),
)
.map((vo) => ({
...vo,
disabled: is.nullOrUndefined(vo.disabled)
? false
: isPayloadButtonTruth(vo.disabled, payload),
hidden: undefined,
onClick: vo.onClick && ((e) => vo.onClick(e, payload)),
})),
[buttons, payload],
);
================================================
FILE: packages/fusion-ui/src/components/pro-table/components/pro-table-cell/cell-label.tsx
================================================
import * as React from 'react';
// import { Ellipsis } from '@/ellipsis';
import { Balloon } from '@alifd/next';
// import { ColorType } from '@/types';
import classnames from 'classnames';
import { statusTypes } from '@/types/enum';
const { Tooltip } = Balloon;
export interface CellLabelProps extends React.HTMLProps {
toolTipMode?: 'always' | 'ellipsis' | 'none';
// color?: ColorType;
}
export const CellLabel: React.FC = ({
toolTipMode,
color,
children,
className,
style,
...props
}) => {
const isStatusColor = statusTypes.includes(color as any);
return (
{children}
);
};
CellLabel.defaultProps = {
toolTipMode: 'none',
};
export interface CellToolTipProps {
toolTipMode?: 'always' | 'ellipsis' | 'none';
onClick?: () => void;
}
const CellToolTip: React.FC = ({ toolTipMode, children }) => {
// if (toolTipMode === 'ellipsis') {
// return {children};
// }
if (toolTipMode === 'always') {
return (
<>{children}>
);
}
return <>{children}>;
};
================================================
FILE: packages/fusion-ui/src/components/pro-table/components/pro-table-cell/pro-table-cell.tsx
================================================
import * as React from 'react';
import classnames from 'classnames';
import { ProTableColumnProps, ProTableCellCommonProps } from '@/components/pro-table/types';
import { CellLabel } from './cell-label';
import { getColorWithFormat } from '../pro-table-cells/utils';
import { obj, pickAttrs } from '@/utils/util';
export interface ProTableCellProps extends ProTableCellCommonProps, ProTableColumnProps {
record: any;
value: any;
isIconLeft: boolean;
colIndex: number;
rowIndex: number;
__colIndex: number | string; // 经过锁列调整后的列索引,lock right的列会从非0开始
context: any;
component: 'td' | 'th' | 'div';
innerStyle: object;
type: 'header' | 'body';
rowSpan?: number;
getCellDomRef?: string;
primaryKey: string;
dataKey: string;
__normalized: any;
filterMenuProps: any;
filterProps: any;
expandedIndexSimulate: any;
wordBreak: any;
editCell: any;
}
export class ProTableCell extends React.Component {
static defaultProps = {
component: 'td',
type: 'body',
isIconLeft: false,
cell: (value: any) => value,
prefix: 'fusion-ui-',
};
shouldComponentUpdate(nextProps: ProTableCellProps) {
if (nextProps.pure) {
const isEqual = obj.shallowEqual(this.props, nextProps);
return !isEqual;
}
return true;
}
render() {
const {
prefix,
className,
cell,
value: originValue,
resizable,
asyncResizable,
colIndex,
rowIndex,
__colIndex,
record,
context,
align,
style = {},
formatValue,
component: Tag,
children,
title,
width,
innerStyle,
primaryKey,
__normalized,
filterMode,
filterMenuProps,
filterProps,
filters,
sortable,
sortDirections,
lock,
pure,
locale,
expandedIndexSimulate,
rtl,
isIconLeft,
type,
htmlTitle,
wordBreak,
editCell,
dataKey,
getCellDomRef,
onCellClick,
formatColor,
cellTooltipMode,
cellDefault,
...others
} = this.props;
const tagStyle = { ...style };
const isDataRow = rowIndex !== undefined;
const value =
formatValue && isDataRow ? formatValue(originValue, rowIndex, record) : originValue;
const cellProps = { value, index: rowIndex, record, context };
let content = cell;
const editContent = editCell;
if (record?.editMode && editContent) {
content = editContent(value, rowIndex, record, context, dataKey);
} else if (React.isValidElement(content)) {
content = React.cloneElement(content, cellProps);
} else if (typeof content === 'function') {
content = content(value, rowIndex, record, context);
}
if (align) {
tagStyle.textAlign = align;
if (rtl) {
if (align === 'left') {
tagStyle.textAlign = 'right';
} else if (align === 'right') {
tagStyle.textAlign = 'left';
}
}
}
const cls = classnames({
[`${prefix}table-cell`]: true,
[`${prefix}table-word-break-${wordBreak}`]: !!wordBreak,
[className]: className,
});
const contentWithTooltip = isDataRow ? (
onCellClick(value, rowIndex, record))}
color={formatColor && getColorWithFormat(value, formatColor)}
toolTipMode={cellTooltipMode}
>
{content || cellDefault}
) : (
content
);
return (
{isIconLeft ? children : contentWithTooltip}
{isIconLeft ? contentWithTooltip : children}
);
}
}
================================================
FILE: packages/fusion-ui/src/components/pro-table/components/pro-table-cell/pro-table-tree-cell.tsx
================================================
import React from 'react';
import PropTypes from 'prop-types';
import { Icon } from '@alifd/next';
import { ProTableCell, ProTableCellProps } from './pro-table-cell';
export interface ProTableTreeCellProps extends ProTableCellProps {
indent: number;
}
const KEYCODE = {
BACKSPACE: 8,
TAB: 9,
ENTER: 13,
SHIFT: 16,
CTRL: 17,
ALT: 18,
ESC: 27,
SPACE: 32,
END: 35,
HOME: 36,
LEFT: 37,
UP: 38,
RIGHT: 39,
DOWN: 40,
PAGE_UP: 33,
PAGE_DOWN: 34,
// version 0.x
ESCAPE: 27,
LEFT_ARROW: 37,
UP_ARROW: 38,
RIGHT_ARROW: 39,
DOWN_ARROW: 40,
// MacOS
CONTROL: 17,
OPTION: 18,
CMD: 91,
COMMAND: 91,
DELETE: 8,
};
export class ProTableTreeCell extends React.Component {
static defaultProps = {
component: 'td',
indent: 20,
};
static contextTypes = {
openTreeRowKeys: PropTypes.array,
indent: PropTypes.number,
onTreeNodeClick: PropTypes.func,
isTree: PropTypes.bool,
rowSelection: PropTypes.object,
};
onTreeNodeClick = (record, e) => {
e.stopPropagation();
this.context.onTreeNodeClick(record);
};
expandedKeydown = (record, e) => {
e.preventDefault();
e.stopPropagation();
if (e.keyCode === KEYCODE.ENTER) {
this.onTreeNodeClick(record, e);
}
};
render() {
const { colIndex, record, prefix, primaryKey, locale, rtl, children } = this.props;
const { openTreeRowKeys: openRowKeys, indent, isTree, rowSelection } = this.context;
const treeArrowNodeIndex = rowSelection ? 1 : 0;
let firstCellStyle;
let treeArrowNode;
if (colIndex === treeArrowNodeIndex) {
let treeArrowType;
if (isTree) {
const paddingType = rtl ? 'paddingRight' : 'paddingLeft';
firstCellStyle = {
[paddingType]: indent * (record.__level + 1),
};
treeArrowNode = ;
if (record.children && record.children.length) {
const hasExpanded = openRowKeys.indexOf(record[primaryKey]) > -1;
treeArrowType = hasExpanded ? 'arrow-down' : 'arrow-right';
treeArrowNode = (
this.onTreeNodeClick(record, e)}
onKeyDown={(e) => this.expandedKeydown(record, e)}
role="button"
tabIndex={0}
aria-expanded={hasExpanded}
aria-label={hasExpanded ? locale.expanded : locale.folded}
/>
);
}
}
}
return (
{children}
{treeArrowNode}
);
}
}
================================================
FILE: packages/fusion-ui/src/components/pro-table/components/pro-table-cells/utils.ts
================================================
import is from '@sindresorhus/is';
export type StatusColorType =
| 'success'
| 'error'
| 'warning'
| 'notice'
| 'help'
| 'normal'
| string;
/** 颜色转换回调 */
export type FormatColor =
| StatusColorType
| ((value: unknown) => StatusColorType)
| Record;
/**
*
* @param value 值
* @param formatColor 状态/颜色
* @returns 颜色
*/
export const getColorWithFormat = (value?: unknown, formatColor?: FormatColor): StatusColorType => {
if (is.object(formatColor)) {
return formatColor[value as string];
}
if (is.function_(formatColor)) {
return formatColor(value);
}
if (is.string(formatColor)) {
return formatColor;
}
return 'normal';
};
export const colorToStatus = (
value: StatusColorType,
allowStatus: Status[],
): Status | undefined => (allowStatus.includes(value as Status) ? (value as Status) : undefined);
================================================
FILE: packages/fusion-ui/src/components/pro-table/components/pro-table-column/defaultColumnFormatters.tsx
================================================
import * as React from 'react';
import { ProTableColumnProps } from '../../types';
import { ProTableColumnFormatter } from './pro-table-column-formatter';
import is from '@sindresorhus/is';
import {
formatBankCard,
formatDate,
formatMoney,
formatNumber,
formatPercent,
} from '@/utils/formatters';
// import { EmployeeInfo } from '@/employee-select';
// import { UploadList } from '@/upload/components/Upload/components/UploadList';
import { colorToStatus } from '../pro-table-cells/utils';
import {
Progress,
Tag,
Upload as UploadList,
Input,
NumberPicker,
DatePicker2,
Select,
} from '@alifd/next';
// import { Tag } from '@/tag';
const EditComponent = (props: any) => {
const { component, value, onChange, style = {}, ...otherProps } = props;
const [data, setData] = React.useState(value);
if (!style.width) {
style.width = '100%';
}
const Comp = component || Input;
return (
{
setData(changeValue);
onChange && onChange(changeValue);
}}
{...otherProps}
/>
);
};
const TextEditCell = (value, rowIndex, record, context, dataIndex) => {
return (
{
record[dataIndex] = data;
record[`origin-${dataIndex}`] = value;
}}
/>
);
};
const NumberEditCell = (value, rowIndex, record, context, dataIndex) => {
return (
{
record[dataIndex] = data;
record[`origin-${dataIndex}`] = value;
}}
/>
);
};
const DateEditCell = (value, rowIndex, record, context, dataIndex) => {
return (
{
record[dataIndex] = data;
record[`origin-${dataIndex}`] = value;
}}
/>
);
};
const SelectEditCell = (value, rowIndex, record, context, dataIndex) => {
return (
{
record[dataIndex] = data;
record[`origin-${dataIndex}`] = value;
}}
/>
);
};
/**
* 不同类型列的格式化方法a
*/
export const defaultColumnFormatters: Record<
ProTableColumnProps['formatType'],
ProTableColumnFormatter
> = {
text: (options) => {
return {
cellTooltipMode: 'ellipsis',
width: 100,
cell: options.cellFactory(({ value, getLabel }) => value && getLabel()),
editCell: TextEditCell,
};
},
number: (options) => ({
cellTooltipMode: 'ellipsis',
cell: options.formatterCellFactory(formatNumber),
editCell: NumberEditCell,
}),
// 金额渲染
money: (options) => ({
cellTooltipMode: 'ellipsis',
// 金额 + 币种,宽度设置为 120
// 金额展示,宽度设置为 90
width: options.formatTypeParser.rawOptions[0] ? 120 : 90,
align: 'right',
cell: options.formatterCellFactory(formatMoney),
editCell: NumberEditCell,
}),
// 日期渲染
date: (options) => ({
cellTooltipMode: 'ellipsis',
width: 158,
align: 'center',
cell: options.formatterCellFactory(formatDate),
editCell: DateEditCell,
}),
// 电话显示
phone: () => ({
cellTooltipMode: 'ellipsis',
width: 142,
editCell: TextEditCell,
}),
// 币种展示
currency: (options) => ({
cellTooltipMode: 'ellipsis',
width: 40,
cell: options.cellFactory(({ value, getLabel }) => value && getLabel()),
editCell: SelectEditCell,
}),
// OU 编码
ou: () => ({
cellTooltipMode: 'ellipsis',
width: 58,
align: 'center',
}),
// 百分比
percent: (options) => ({
cellTooltipMode: 'ellipsis',
width: 80,
cell: options.formatterCellFactory(formatPercent),
editCell: NumberEditCell,
}),
// 进度条
progress: (options) => ({
cellTooltipMode: 'ellipsis',
width: 180,
cell: options.cellFactory(({ value, getCellColor }) => {
if (is.number(value) || is.numericString(value)) {
const status = colorToStatus(getCellColor(), ['normal', 'success', 'error']) || 'normal';
return ;
}
return undefined;
}),
formatColor: undefined,
editCell: NumberEditCell,
}),
link: () => ({
cellTooltipMode: 'none',
cell: (value) => (
false}>
{value}
),
editCell: TextEditCell,
}),
tag: (options) => ({
cellTooltipMode: 'none',
width: 90,
cell: options.cellFactory(
({ value, getLabel, getCellColor }) =>
value && (
{getLabel()}
),
),
formatColor: undefined,
}),
textTag: (options) => ({
cellTooltipMode: 'none',
width: 90,
cell: options.cellFactory(
({ value, getLabel, getCellColor }) =>
value && (
{getLabel()}
),
),
formatColor: undefined,
}),
files: () => ({
cellTooltipMode: 'none',
width: 180,
cell: (value) =>
value && ,
formatColor: undefined,
}),
bankCard: () => ({
cellTooltipMode: 'ellipsis',
width: 183,
cell: formatBankCard,
}),
employee: () => ({
cellTooltipMode: 'none',
width: 160,
cell: (value) => value && ,
}),
};
================================================
FILE: packages/fusion-ui/src/components/pro-table/components/pro-table-column/index.tsx
================================================
import * as React from 'react';
import { ColumnProps } from '@alifd/next/types/table';
import { Table } from '@alifd/next';
import is from '@sindresorhus/is';
import omit from 'lodash/omit';
import { ProTableColumnTitle } from '../pro-table-column-title';
import { ProTableColumnProps, ProTableProps } from '../../types';
import { getColumnKey } from '../pro-table-base/utils';
import { formatColumnProps } from './pro-table-column-formatter';
interface ColumnWithSetting {
key: string;
column: ProTableColumnProps;
children: ColumnWithSetting[];
}
export const useColumnsWithSetting = ({
columns,
columnKey,
columnsSetting,
cellDefault,
cellTooltipMode,
}: Pick<
ProTableProps,
'columns' | 'columnKey' | 'columnsSetting' | 'cellDefault' | 'cellTooltipMode'
>) =>
React.useMemo(() => {
const fn = (items: ProTableColumnProps[]): ColumnWithSetting[] =>
is.array(items)
? items
.map((column, index) => {
const key = getColumnKey(column, columnKey);
// 列格式化
const typeColumnProps = formatColumnProps(column);
const col = {
// 设置优先级: 列配置 > 列类型提供值 > 表格
cellTooltipMode,
cellDefault,
...typeColumnProps,
...column,
};
const columnSetting = {
sortRank: index,
...columnsSetting[key],
};
// 列设置参数
col.width = is.number(columnSetting.width) ? columnSetting.width : col.width;
col.lock = is.nullOrUndefined(columnSetting.lock) ? col.lock : columnSetting.lock;
let lockRank = 0;
if (col.lock === 'right') {
lockRank = 100000;
} else if (col.lock) {
lockRank = -100000;
}
return {
key,
hidden: is.boolean(columnSetting.hidden) ? columnSetting.hidden : false,
columnSort: columnSetting.sortRank + lockRank,
column: col,
children: col.group ? fn(column.children) : [],
};
})
.sort((aItem, bItem) => aItem.columnSort - bItem.columnSort)
.filter((item) => !item.hidden)
: [];
const columnsWithSetting = fn(columns);
const flatColumns = [];
const reduceflatColumns = (items: ColumnWithSetting[]) => {
items.forEach((vo) => {
if (vo.children.length > 0) {
reduceflatColumns(vo.children);
} else {
flatColumns.push(vo.column);
}
});
};
reduceflatColumns(columnsWithSetting);
return {
columnsWithSetting,
flatColumns,
};
}, [columnKey, columns, columnsSetting, cellTooltipMode, cellDefault]);
export const renderColumns = (
items: ColumnWithSetting[],
options: {
resizable: boolean;
},
) =>
items.map(({ column, key, children }) => {
if (column.group) {
return (
{renderColumns(children, options)}
);
}
const _columnProps = pickColumnProps(column);
return (
{column.title}}
/>
);
});
/**
* 不传多余的参数下去以免组件报不识别 prop 的 warning
*/
export const pickColumnProps = (col: ProTableColumnProps): ColumnProps => {
return omit(col, [
'tableEl',
'groupHeader',
'groupFooter',
'group',
'children',
'type',
'formatType',
'formatConfig',
'tagCondition',
'i18nBundle',
// 剔除排序/筛选功能
'searchable',
'sortable',
'sortDirections',
'filters',
'filterMode',
]);
};
================================================
FILE: packages/fusion-ui/src/components/pro-table/components/pro-table-column/pro-table-column-formatter.tsx
================================================
import is from '@sindresorhus/is';
import * as React from 'react';
import qs from 'qs';
import { ProTableColumnProps } from '../../types';
import { getColorWithFormat } from '../pro-table-cells/utils';
import { DataSourceLabel, DataSourceLabelProps } from '@/utils/dataSource/data-source-label';
import { ReactNode } from 'react';
import { asyncDataSourceToPromiseDataSource } from '@/utils/dataSource/utils';
export interface CellFactoryCellOptions {
/** 单元格值 */
value: unknown;
/** 单元格label */
getLabel: (props?: DataSourceLabelProps) => ReactNode;
/** 行下标 */
rowIndex: number;
/** 行数据 */
record: unknown;
/** 获取配置 */
getCellOptions: () => any[];
/** 获取颜色 */
getCellColor: () => string;
}
export interface ProTableColumnFormatterOptions {
/** 列配置 */
column: ProTableColumnProps;
formatTypeParser: {
/** 类型原始值 */
raw: string;
/** 实际类型 */
type: string;
/** 参数 */
rawOptions: string[];
};
/** 获取真实参数 */
getCellOptions: (record: any) => any[];
/** 格式化 */
formatterCellFactory: (
cell: (value: Value, ...args: Args) => React.ReactNode,
) => React.ReactNode;
/** 高阶格式化 */
cellFactory: (cell: (options: CellFactoryCellOptions) => React.ReactNode) => React.ReactNode;
}
export type ProTableColumnFormatter = (
options: ProTableColumnFormatterOptions,
) => Partial;
class ProTableColumnFormatterManager {
columnFormatters: Record = {};
/** 注册列格式化类型 */
registerColumnFormatter = (name: string, columnFormatter: ProTableColumnFormatter) => {
if (is.function_(columnFormatter)) {
this.columnFormatters[name] = columnFormatter;
return;
}
console.warn(`registerColumnFormatter: ${name}, columnFormatter不是函数`);
};
/** 批量注册列格式化类型 */
registerColumnFormatters = (columnFormatters: Record) => {
Object.keys(columnFormatters).forEach((key) => {
this.registerColumnFormatter(key, columnFormatters[key]);
});
};
formatColumnProps = (col: ProTableColumnProps): ProTableColumnProps | undefined => {
if (is.string(col.formatType)) {
const formatterOptions = getFormatterOptions(col);
const { columnFormatters } = this;
if (formatterOptions.formatTypeParser.type in columnFormatters) {
return columnFormatters[formatterOptions.formatTypeParser.type](formatterOptions);
}
}
return undefined;
};
}
const proTableColumnFormatterManager = new ProTableColumnFormatterManager();
export const { registerColumnFormatter, registerColumnFormatters, formatColumnProps } =
proTableColumnFormatterManager;
const getFormatterOptions = (column: ProTableColumnProps): ProTableColumnFormatterOptions => {
const formatTypeParser = parseFormatType(column.formatType);
if (is.array(column.formatOptions)) {
formatTypeParser.rawOptions = [...formatTypeParser.rawOptions, ...column.formatOptions];
}
const getCellOptions = (record: any = {}) =>
formatTypeParser.rawOptions.map((vo) => (vo.startsWith('$') ? record[vo.slice(1)] : vo));
// 优化性能,列dataSource缓存
const dataSource = column.dataSource
? asyncDataSourceToPromiseDataSource(column.dataSource)
: undefined;
const cellFactory =
(cell: (options: CellFactoryCellOptions) => React.ReactNode) => (value, rowIndex, record) =>
cell({
getLabel: (props) =>
dataSource ? (
) : (
value
),
value,
rowIndex,
record,
getCellOptions: () => getCellOptions(record),
getCellColor: () => getColorWithFormat(value, column.formatColor),
});
const formatterCellFactory = (cell) => (value, rowIndex, record) =>
cell(value, ...(getCellOptions(record) as any));
return {
column,
formatTypeParser,
getCellOptions,
cellFactory,
formatterCellFactory,
};
};
/**
* 解析格式化字符串
* @param raw 格式化字符串
* @example
* - number
* - number:0,0.00%
* - number:$format
*/
const parseFormatType = (raw: string): ProTableColumnFormatterOptions['formatTypeParser'] => {
try {
const res = raw.trim().match(/^([a-zA-Z-_0-9]+)(?:\|(.*)?)?$/);
if (!res) {
throw new Error('不符合规则的formatType');
}
const [, type, optionStr = ''] = res;
return {
raw,
type,
rawOptions: Object.keys(qs.parse(optionStr)),
};
} catch (error) {
const err = new Error(`parseformatType: ${raw} 解析错误`);
err.stack = error?.stack;
throw err;
}
};
================================================
FILE: packages/fusion-ui/src/components/pro-table/components/pro-table-column-title/index.scss
================================================
@import '../../../../variables.scss';
.fusion-ui-pro-table-column-title-sortter {
display: inline-block;
position: relative;
height: 14px;
width: var(--s-2, $s-2);
cursor: pointer;
top: -3px;
.fusion-ui-icon {
position: absolute;
left: 0;
transform: scale(0.8);
}
.fusion-ui-icon-triangle-up {
top: 0;
}
.fusion-ui-icon-triangle-down {
top: 7px;
}
&--desc {
.fusion-ui-icon-triangle-down {
color: var(--color-brand1-6, $color-brand1-6);
}
}
&--asc {
.fusion-ui-icon-triangle-up {
color: var(--color-brand1-6, $color-brand1-6);
}
}
}
.fusion-ui-pro-table-column-title-icons {
display: inline-flex;
flex-direction: row;
gap: var(--s-2, $s-2);
margin-left: var(--s-2, $s-2);
color: var(--color-text1-2, $color-text1-2);
align-items: center;
}
.fusion-ui-pro-table-column-title-filter {
cursor: pointer;
color: var(--color-text1-2, $color-text1-2);
&--active {
color: var(--color-brand1-6, $color-brand1-6);
}
}
.fusion-ui-pro-table-column-title-filter-panel {
display: flex;
flex-direction: column;
background-color: var(--color-white, $color-white);
box-shadow: var(--shadow-2-down, $shadow-2-down);
border-radius: var(--corner-2, $corner-2);
width: calc(var(--s-1, 4) * 60);
&__bd {
display: flex;
flex-direction: column;
gap: var(--s-2, $s-2);
align-items: stretch;
padding: var(--s-3 $s-4, $s-3 $s-4);
}
&__ft {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
gap: var(--s-2, $s-2);
border-top: var(--line-1 solid $color-line1-1, $line-1 solid $color-line1-1);
padding: var(--s-2 $s-4, $s-2 $s-4);
}
&__segment {
// margin-bottom: var(--s-2, $s-2);
display: flex;
flex-direction: column;
align-items: stretch;
}
&__input {
// margin-bottom: var(--s-2, $s-2);
}
&__menu {
> .fusion-ui-menu.fusion-ui-ver {
padding: 0;
}
.fusion-ui-menu-header {
line-height: var(--s-7, $s-7);
}
> .fusion-ui-menu.fusion-ui-menu.fusion-ui-ver {
padding: 0 !important;
> .fusion-ui-menu-content {
margin: 0 -12px;
}
.fusion-ui-menu-item {
padding: 0 12px 0 12px;
}
}
}
}
.fusion-ui-pro-table-column-title {
display: inline-flex;
flex-direction: row;
align-items: center;
// white-space: nowrap;
&--wrap {
white-space: normal;
}
}
================================================
FILE: packages/fusion-ui/src/components/pro-table/components/pro-table-column-title/index.tsx
================================================
import * as React from 'react';
import { ProTableColumnProps } from '../../types';
import { ProTableColumnTitleFilter } from './pro-table-column-title-filter';
import { ProTableColumnTitleSortter } from './pro-table-column-title-sortter';
import { Balloon } from '@alifd/next';
import { CustomIcon } from '@/components/toggle-icon';
import { ProTableColumnsFilterContext } from '../../contexts/pro-table-columns-filters-context';
import { CellLabel } from '../pro-table-cell/cell-label';
const { Tooltip } = Balloon;
type ProTableColumnTitlePropsKey =
| 'sortable'
| 'sortDirections'
| 'filters'
| 'filterMode'
| 'lock'
| 'searchable'
| 'isImmediate'
| 'dataIndex'
| 'explanation'
| 'cellTooltipMode';
export type ProTableColumnTitleProps = Pick;
export const ProTableColumnTitle: React.FC = ({
dataIndex,
sortable,
sortDirections,
filters,
filterMode,
searchable,
explanation,
isImmediate,
cellTooltipMode,
lock,
children,
}) => {
const showFilter = searchable || !!filters;
const columnFilters = React.useContext(ProTableColumnsFilterContext);
return (
{children}
{(explanation || showFilter || sortable) && (
{explanation && (
} align="bl">
{explanation}
)}
{!showFilter && sortable && (
columnFilters.setColumnSort(dataIndex, val)}
value={columnFilters.getColumnSort(dataIndex)}
sortDirections={sortDirections}
/>
)}
{showFilter && (
)}
)}
);
};
ProTableColumnTitle.displayName = 'ProTableColumnTitle';
ProTableColumnTitle.defaultProps = {};
================================================
FILE: packages/fusion-ui/src/components/pro-table/components/pro-table-column-title/pro-table-column-title-filter-panel.tsx
================================================
import * as React from 'react';
import { Segment } from '@/components/segment';
import { Button, Input } from '@alifd/next';
import { Menu, MenuProps } from '@/components/menu';
import { CustomIcon } from '@/components/toggle-icon';
import { useMemo } from 'react';
import is from '@sindresorhus/is';
import { SortValue } from '../../types';
import { InputProps } from '@alifd/next/types/input';
import { useFiledState } from '@/utils/hooks/useFiledState';
import { useI18nBundle } from '@/provider';
import { ProTableColumnsFilterValue } from '../../contexts/pro-table-columns-filters-context';
import { useDataSource } from '@/utils/dataSource/hooks';
import { dataSourceToMenuDataSource } from '@/utils/dataSource';
import { AsyncDataSource } from '@/types';
export interface ProTableColumnFilterPanelProps {
sortable?: boolean;
sortDirections?: SortValue[];
searchable?: boolean;
filters?: FilterMenuProps['dataSource'];
filterMode?: FilterMenuProps['selectMode'];
filterMenuProps?: FilterMenuProps;
onClose?: () => void;
lock?: boolean | string;
dataIndex: string;
columnFilters: ProTableColumnsFilterValue;
/**
* 是否是即时生效
*/
isImmediate?: boolean;
rtl?: boolean;
}
export const ProTableColumnTitleFilterPanel: React.FC = ({
sortable,
searchable,
filters,
filterMode,
filterMenuProps,
onClose,
columnFilters,
isImmediate,
dataIndex,
// rtl,
}) => {
const i18nBundle = useI18nBundle('ProTable');
const showFooter = filters || sortable;
const [sort, setSort] = useFiledState(
{
value: columnFilters.getColumnSort(dataIndex),
onChange: (val) => {
if (isImmediate) {
columnFilters.setColumnSort(dataIndex, val);
}
},
},
isImmediate,
);
const [keywords, setKeywords] = useFiledState(
{
value: columnFilters.getColumnKeywords(dataIndex),
onChange: (val) => {
if (isImmediate) {
columnFilters.setColumnKeywords(dataIndex, val, true);
}
},
},
isImmediate,
);
const [selectedKeys, setSelectedKeys] = useFiledState(
{
value: columnFilters.getColumnSelectedKeys(dataIndex),
onChange: (val) => {
if (isImmediate) {
columnFilters.setColumnSelectedKeys(dataIndex, val, true);
}
},
},
isImmediate,
);
return (
{sortable && (
)}
{searchable && (
)}
{filters && (
)}
{showFooter && (
{!isImmediate && (
)}
)}
);
};
ProTableColumnTitleFilterPanel.defaultProps = {
onClose: () => {},
isImmediate: true,
};
interface FilterMenuProps extends Omit {
dataSource?: AsyncDataSource;
}
const FilterMenu: React.FC = ({ dataSource, ...otherProps }) => {
const [keywords, setKeywords] = React.useState();
const { data, loading, error } = useDataSource({ dataSource });
const menuDataSource = useMemo(
() => (is.array(data) ? dataSourceToMenuDataSource(data) : []),
[data],
);
const filterDataSource = React.useMemo(() => {
if (!keywords) {
return menuDataSource;
}
return menuDataSource.filter(
(vo) => is.string(vo.label) && vo.label.toLowerCase().indexOf(keywords) > -1,
);
}, [menuDataSource, keywords]);
const i18nBundle = useI18nBundle('ProTable');
return (