+
{item.title}
+
{item.content}
+
+ {item.timestamp} {item.extraTime}
+
+
+ {(item.icon &&
{item.icon}
) || (
+
)}
-
- {((layout === 'cross' && type === 'default') || type === 'cross') &&
}
-
-
{item.title}
- {/* TODO: description 废弃,使用 content */}
-
{item.content || item.description}
- {((layout === 'right' && type === 'default') || type === 'right') && (
-
{item.timestamp}
- )}
-
+
+
+ )
+ }
+ renderCollapse = (subItems) => {
+ return (
+
+ {this.state.expanded === true &&
+ subItems.map((c, idx) => {
+ return this.renderSub(c, idx)
+ })}
+
{
+ this.setState({ expanded: !this.state.expanded })
+ }}
+ >
+ {this.state.expanded === true ? '收起' : '展开'}
+
+
-
- {dotEl}
-
+
)
}
- /**
- * 渲染列表,被递归调用
- * @param {Array} datas 数据
- * @param {String | React.ReactNode} groupTitle 分组标题
- * @param {Number} originIndex 原始索引,用于判断是否为第一个分组标题
- */
- renderItems (data, groupTitle, isSub) {
- const { layout, localeDatas, type } = this.props
- return data.map((item, index) => {
- const { groupTitle: gt } = item
- if (gt) {
- // 渲染分组
- return this.renderItems(item.children, gt)
- }
- if (item.children && layout !== 'cross' && type !== 'cross') {
- // 子项 含 收起按钮
- const foldingEl = (
-
- )
- // 如果含有子项,需先渲染当前项
- let el = this.renderItem(item, index, groupTitle)
- return [el, foldingEl]
- }
- return this.renderItem(item, index, groupTitle, isSub)
- })
+ renderSub = (item, index, isLast, isFirst) => {
+ return (
+
+
+
{item.timestamp}
+
{item.extraTime}
+
+ {item.icon ||
}
+
+
+
{item.title}
+
{item.content}
+
+
+ )
+ }
+ renderCross = (item, index, isLast, isFirst) => {
+ return (
+
+
+
{item.timestamp}
+
{item.extraTime}
+
+ {(item.icon &&
{item.icon}
) || (
+
+ )}
+
+
+
{item.title}
+
{item.content}
+
+
+ )
}
+ renderDefault = (item, index, isLast, isFirst) => {
+ return [
+
+
+
{item.timestamp}
+
{item.extraTime}
+
+ {(item.icon &&
{item.icon}
) || (
+
+ )}
+
+
+
{item.title}
+
{item.content}
+
+
,
+ item.children && this.renderCollapse(item.children)
+ ]
+ }
render () {
const { layout, type, list, data, theme } = this.props
const _layout = type === 'default' ? layout : type
- const rootCls = classNames('hi-timeline', `theme__${theme}`, `hi-timeline--${_layout}`)
+ const rootCls = classNames(
+ 'hi-timeline',
+ `theme__${theme}`,
+ `hi-timeline--${['normal', 'default'].includes(_layout) ? 'default' : _layout}`
+ )
return (
-
{this.renderItems(data || list)}
+
+ {(data || list).map((item, index) => {
+ if (item.groupTitle) {
+ const isLast = index === (data || list).length - 1
+ return this.renderGroup(item, index, isLast)
+ } else {
+ const isLast = index === (data || list).length - 1
+ const isFirst = index === 0
+ return this.renderItem(item, index, isLast, isFirst)
+ }
+ })}
+
)
}
diff --git a/components/timeline/style/index.scss b/components/timeline/style/index.scss
index 96171ee57..fb3a8ca29 100755
--- a/components/timeline/style/index.scss
+++ b/components/timeline/style/index.scss
@@ -2,248 +2,411 @@
.hi-timeline {
position: relative;
- padding: 8px;
+ padding: 4px;
ul {
margin: 0 !important;
padding: 0 !important;
}
- &__item {
- margin: 0;
- padding: 0;
- list-style: none;
- display: flex;
- position: relative;
- padding-bottom: 10px;
+ &--cross {
+ .timeline__item {
+ position: relative;
+ margin-bottom: 20px;
+ display: flex;
+
+ &--last {
+ margin-bottom: 0;
- &:last-child {
- .hi-timeline__line {
- display: none;
+ .item__line {
+ height: 7px !important;
+ }
}
- }
- &--folding {
- position: relative;
- padding-bottom: 20px;
- display: block;
- margin-top: 0 !important;
+ &--first {
+ .item__line {
+ top: 7px;
+ height: calc(100% + 20px - 7px) !important;
+ }
+ }
- .hi-timeline__line {
- z-index: 1;
+ &--left {
+ width: calc(50% - 20px);
+ margin-right: calc(50% + 20px);
+ flex-direction: row-reverse;
+
+ .item__dot {
+ width: 8px;
+ height: 8px;
+ border: 2px solid #4284f5;
+ background: #fff;
+ border-radius: 50%;
+ box-sizing: border-box;
+ position: absolute;
+ top: 7px;
+ right: -20px;
+ transform: translateX(50%);
+ z-index: 2;
+ }
+
+ .item__icon {
+ position: absolute;
+ background: #fff;
+ top: 7px;
+ right: -20px;
+ transform: translateX(50%);
+ z-index: 2;
+ }
+
+ .item__line {
+ position: absolute;
+ right: -20px;
+ width: 2px;
+ background: rgb(242, 242, 242);
+ height: calc(100% + 20px);
+ transform: translateX(50%);
+ }
+
+ .item--left {
+ text-align: right;
+ width: calc(30% - 20px);
+ margin-left: 20px;
+
+ .item__time {
+ color: rgb(51, 51, 51);
+ font-size: 14px;
+ line-height: 22px;
+ margin-bottom: 2px;
+ }
+
+ .item__extra {
+ color: rgb(158, 158, 158);
+ font-size: 12px;
+ line-height: 20px;
+ }
+ }
+
+ .item--right {
+ text-align: right;
+ width: 70%;
+
+ .item__title {
+ color: rgb(51, 51, 51);
+ font-size: 14px;
+ line-height: 22px;
+ margin-bottom: 2px;
+ }
+
+ .item__content {
+ color: rgb(158, 158, 158);
+ font-size: 12px;
+ line-height: 20px;
+ }
+ }
}
- }
- &--sub {
- &:last-child {
- padding-bottom: 40px;
+ &--right {
+ width: calc(50% - 20px);
+ margin-left: calc(50% + 20px);
+
+ .item__dot {
+ width: 8px;
+ height: 8px;
+ border: 2px solid #4284f5;
+ background: #fff;
+ border-radius: 50%;
+ box-sizing: border-box;
+ position: absolute;
+ top: 7px;
+ left: -20px;
+ transform: translateX(-50%);
+ z-index: 2;
+ }
+
+ .item__line {
+ position: absolute;
+ left: -20px;
+ width: 2px;
+ background: rgb(242, 242, 242);
+ height: calc(100% + 20px);
+ transform: translateX(-50%);
+ }
- .hi-timeline__line {
- display: block;
+ .item--left {
+ width: calc(30% - 20px);
+ margin-right: 20px;
+
+ .item__time {
+ color: rgb(51, 51, 51);
+ font-size: 14px;
+ line-height: 22px;
+ margin-bottom: 2px;
+ }
+
+ .item__extra {
+ color: rgb(158, 158, 158);
+ font-size: 12px;
+ line-height: 20px;
+ }
+ }
+
+ .item--right {
+ width: 70%;
+
+ .item__title {
+ color: rgb(51, 51, 51);
+ font-size: 14px;
+ line-height: 22px;
+ margin-bottom: 2px;
+ }
+
+ .item__content {
+ color: rgb(158, 158, 158);
+ font-size: 12px;
+ line-height: 20px;
+ }
}
}
}
}
- &__arrow {
- position: absolute;
- left: 74px;
- bottom: 8px;
- cursor: pointer;
- }
+ &--right {
+ .timeline__item {
+ position: relative;
+ margin-bottom: 20px;
+ margin-left: 24px;
- &__row {
- margin-left: 40px;
- display: flex;
- }
+ .item__title {
+ color: rgb(51, 51, 51);
+ font-size: 14px;
+ line-height: 22px;
+ margin-bottom: 2px;
+ }
- &__content-container {
- display: inline-block;
- }
+ .item__content {
+ color: #666;
+ font-size: 12px;
+ line-height: 20px;
+ margin-bottom: 6px;
+ }
- &__time {
- flex: 0 0 36px;
- text-align: right;
- display: inline-block;
- vertical-align: top;
-
- &--extra {
- width: auto;
- text-align: left;
- font-size: 12px;
- color: #999;
- margin-top: 6px;
- }
- }
+ .item__time {
+ color: #999;
+ font-size: 12px;
+ line-height: 20px;
+ }
- &__extra-time {
- font-size: 12px;
- color: #666;
- margin-top: 2px;
- }
+ &--last {
+ &.timeline__item {
+ margin-bottom: 0;
- &__title {
- font-size: 14px;
- color: #333;
- text-align: left;
- }
+ .item__line {
+ height: 7px;
+ }
+ }
+ }
- &__desc {
- margin-top: 8px;
- font-size: 12px;
- color: #666;
- }
+ &--first {
+ &.timeline__item {
+ .item__line {
+ top: 7px;
+ height: calc(100% + 20px - 7px);
+ }
+ }
+ }
- &__line {
- position: absolute;
- top: 0.75em;
- height: 100%;
- width: 2px;
- background: rgba(242, 242, 242, 1);
- left: 55px;
- // border-left: 2px solid #e8e8e8;
- }
+ .item__dot {
+ width: 8px;
+ height: 8px;
+ border: 2px solid #4284f5;
+ background: #fff;
+ border-radius: 50%;
+ box-sizing: border-box;
+ position: absolute;
+ top: 7px;
+ left: -20px;
+ transform: translateX(-50%);
+ z-index: 2;
+ }
- &__dot {
- width: 8px;
- height: 8px;
- border: 2px solid #4284f5;
- border-radius: 50%;
- box-sizing: border-box;
- position: absolute;
- top: 0.5em;
- left: 52px;
- z-index: 2;
-
- &--sub {
- width: 6px;
- height: 6px;
- border: 0;
- background: #4284f5;
- left: 53px;
- }
+ .item__icon {
+ position: absolute;
+ background: #fff;
+ top: 7px;
+ left: -20px;
+ transform: translateX(-50%);
+ z-index: 2;
+ }
- &--custom {
- border: none;
- border-radius: 0;
- font-size: 12px;
- width: auto;
- height: auto;
- // left: 4px;
- background: #fff;
- transform: translate(-50%, -30%);
+ .item__line {
+ position: absolute;
+ left: -22px;
+ top: 0;
+ width: 2px;
+ background: rgb(242, 242, 242);
+ height: calc(100% + 20px);
+ transform: translateX(50%);
+ }
}
}
- &--right {
- .hi-timeline__line {
- left: 3px;
- }
+ &--default {
+ .timeline__collapse {
+ margin-bottom: 24px;
- .hi-timeline__row {
- margin-left: 24px;
- }
-
- .hi-timeline__dot {
- left: 0;
+ .collapse-opt {
+ font-size: 12px;
+ margin-left: calc(30% + 20px);
+ cursor: pointer;
+ position: relative;
+ }
- &--custom {
- left: 4px;
+ .item__line {
+ position: absolute;
+ top: 0;
+ left: -20px;
+ width: 2px;
+ background: #f2f2f2;
+ height: calc(100% + 24px);
+ transform: translateX(-50%);
}
- &--sub {
- left: 1px;
+ .item__dot {
+ width: 4px !important;
+ height: 4px !important;
+ background: #4284f5 !important;
+ border-radius: 50%;
+ top: 9px !important;
}
}
- .hi-timeline__arrow {
- left: 40px;
- }
- }
+ .timeline__group-title {
+ text-align: right;
+ width: calc(30% - 20px);
+ margin-right: 20px;
+ margin-bottom: 10px;
+ color: rgb(0, 0, 0);
+ font-weight: bolder;
+ position: relative;
- &--normal {
- .hi-timeline__dot {
- &--custom {
- left: 56px;
+ .item__line {
+ position: absolute;
+ top: 0;
+ left: calc(100% + 20px);
+ right: 0;
+ width: 2px;
+ background: #f2f2f2;
+ height: calc(100% + 10px);
+ transform: translateX(-50%);
}
}
- }
- &--cross {
- .hi-timeline__row {
- width: 50%;
- }
+ .timeline__item {
+ display: flex;
+ position: relative;
+ margin-bottom: 20px;
- .hi-timeline__item:nth-child(even) {
- .hi-timeline__row {
- margin-left: -19px;
+ .item--left {
text-align: right;
- display: inline-block;
+ width: calc(30% - 20px);
+ margin-right: 20px;
- .hi-timeline__time {
- float: right;
+ .item__time {
+ color: rgb(51, 51, 51);
+ font-size: 14px;
+ line-height: 22px;
+ margin-bottom: 2px;
}
- }
- .hi-timeline__content-container {
- margin-right: 20px;
+ .item__extra {
+ color: rgb(158, 158, 158);
+ font-size: 12px;
+ line-height: 20px;
+ }
}
- .hi-timeline__title {
- text-align: right;
+ .item__dot {
+ width: 8px;
+ height: 8px;
+ border: 2px solid #4284f5;
+ background: #fff;
+ border-radius: 50%;
+ box-sizing: border-box;
+ position: absolute;
+ top: 7px;
+ left: 30%;
+ transform: translateX(-50%);
+ z-index: 2;
}
- }
- .hi-timeline__item:nth-child(odd) {
- .hi-timeline__row {
- margin-left: 50%;
- padding-left: 19px;
- text-align: left;
-
- .hi-timeline__time {
- text-align: left;
- }
+ .item__icon {
+ position: absolute;
+ background: #fff;
+ top: 7px;
+ left: 30%;
+ transform: translateX(-50%);
+ z-index: 2;
}
- .hi-timeline__content-container {
- margin-left: 20px;
+ .item__line {
+ position: absolute;
+ left: 30%;
+ width: 2px;
+ background: rgb(242, 242, 242);
+ height: calc(100% + 20px);
+ transform: translateX(-50%);
}
- }
- .hi-timeline__line {
- left: 50%;
- transform: translateX(-1px);
- }
+ .item--right {
+ width: calc(70% - 20px);
+ margin-left: 20px;
- .hi-timeline__dot {
- left: 50%;
- transform: translateX(-4px);
+ .item__title {
+ color: rgb(51, 51, 51);
+ font-size: 14px;
+ line-height: 22px;
+ margin-bottom: 2px;
+ }
- &--custom {
- transform: translate(-50%, -30%);
+ .item__content {
+ color: rgb(158, 158, 158);
+ font-size: 12px;
+ line-height: 20px;
+ }
}
- }
- }
-
- &__group-title {
- font-size: 12px;
- color: #666;
- margin-bottom: 4px;
- }
-}
-@each $key, $value in $theme-colors {
- .theme__#{$key}.hi-timeline {
- .hi-timeline__dot {
- border: 2px solid $value;
+ &--last {
+ .item--right {
+ margin-bottom: 0;
+ }
- &.hi-timeline__dot--custom {
- border: none;
+ .item__line {
+ height: 7px;
+ }
}
- &--sub {
- background: $value;
+ &--first {
+ .item__line {
+ top: 7px;
+ height: calc(100% + 20px - 7px);
+ }
}
}
}
}
+
+// @each $key, $value in $theme-colors {
+// .theme__#{$key}.hi-timeline {
+// .hi-timeline__dot {
+// border: 2px solid $value;
+
+// &.hi-timeline__dot--custom {
+// border: none;
+// }
+
+// &--sub {
+// background: $value;
+// }
+// }
+// }
+// }
diff --git a/components/tree/Tree.js b/components/tree/Tree.js
index 7314a88dd..48ed60313 100644
--- a/components/tree/Tree.js
+++ b/components/tree/Tree.js
@@ -181,7 +181,9 @@ export class Tree extends Component {
onDrop,
onDropEnd,
onDelete,
+ onBeforeDelete,
onSave,
+ onBeforeSave,
onClick,
apperance,
contextMenu,
@@ -222,7 +224,9 @@ export class Tree extends Component {
onDrop={onDrop}
onDropEnd={onDropEnd}
onDelete={onDelete}
+ onBeforeDelete={onBeforeDelete}
onSave={onSave}
+ onBeforeSave={onBeforeSave}
contextMenu={contextMenu}
/>
diff --git a/components/tree/TreeItem.js b/components/tree/TreeItem.js
index fa6af872c..151cc557c 100644
--- a/components/tree/TreeItem.js
+++ b/components/tree/TreeItem.js
@@ -18,9 +18,10 @@ class TreeItem extends Component {
}
render () {
const {
+ level,
editable,
draggable,
- dropDividerPosition,
+ direction,
checked,
expanded,
highlight,
@@ -31,7 +32,6 @@ class TreeItem extends Component {
onClick,
highlightable,
item,
- draggingNode,
checkable,
itemStyle,
onExpanded,
@@ -47,7 +47,7 @@ class TreeItem extends Component {
connectDragSource,
connectDropTarget,
isOver,
- targetNode,
+ isDragging,
saveEditNode,
origin,
loadChildren,
@@ -79,7 +79,7 @@ class TreeItem extends Component {
}
)}
>
- {targetNode === item.id && dropDividerPosition === 'up' && isOver && (
+ { direction === 'up' && isOver && (
{(!item.children || (item.children && !expanded)) &&
- targetNode === item.id &&
- dropDividerPosition === 'down' &&
+ direction === 'down' &&
isOver && }
{
node.id === item.id) || {}).title === '' ? { marginRight: 12, color: '#999', cursor: 'not-allowed' } : { cursor: 'pointer', marginRight: 12, color: themeColor[theme] }}
onClick={() => {
if ((editingNodes.find(node => node.id === item.id) || {}).title !== '') {
- saveEditNode(item.id)
+ saveEditNode(item.id, level)
}
}}
>
@@ -169,14 +168,14 @@ class TreeItem extends Component {
style={item.style}
className={`${prefixCls}_item-text ${itemStyle} ${
highlight === item.id ? 'highlight' : ''
- } ${draggingNode === item.id ? 'dragging' : ''} ${item.disabled ? prefixCls + '_item-text--disabled' : ''}`}
+ } ${isDragging ? 'dragging' : ''} ${item.disabled ? prefixCls + '_item-text--disabled' : ''}`}
onContextMenu={e => {
if (item.disabled) {
return false
}
if (editable) {
e.preventDefault()
- showRightClickMenu(item, e)
+ showRightClickMenu(item, e, level)
}
}}
onClick={e => {
@@ -191,7 +190,7 @@ class TreeItem extends Component {
>
{item.title}
{/* {renderRightClickMenu(item)} */}
- {targetNode === item.id && dropDividerPosition === 'sub' && isOver && (
+ { direction === 'sub' && isOver && (
)}
@@ -201,14 +200,14 @@ class TreeItem extends Component {
style={item.style}
className={`${prefixCls}_item-text ${itemStyle} ${
highlight === item.id ? 'highlight' : ''
- } ${draggingNode === item.id ? 'dragging' : ''} ${item.disabled ? prefixCls + '_item-text--disabled' : ''}`}
+ } ${isDragging ? 'dragging' : ''} ${item.disabled ? prefixCls + '_item-text--disabled' : ''}`}
onContextMenu={e => {
if (item.disabled) {
return false
}
if (this.props.editable) {
e.preventDefault()
- showRightClickMenu(item, e)
+ showRightClickMenu(item, e, level)
}
}}
onClick={e => {
@@ -226,11 +225,11 @@ class TreeItem extends Component {
)}
- {item.children && item.children.length > 0 && expanded ? renderTree(item.children) : null}
+ {item.children && item.children.length > 0 && expanded ? renderTree(item.children, [], level + 1) : null}
{item.children &&
expanded &&
- targetNode === item.id &&
- dropDividerPosition === 'down' &&
+
+ direction === 'down' &&
isOver &&