diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fa77846596d56f6dff436a6dcf0c7b26fbb0131..0d5d4caf4cf190797cea77ae41057e4fce68a046 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,16 @@ ## [Unreleased] +### Added + +- 泳道看板新增分组隐藏功能 +- 看板识别enableFullScreen(启用全屏)和 enableGroupHidden(启用分组隐藏)参数 +- 新增卡片新建功能 + +### Fixed + +- 修复泳道看板快速操作栏和批操作栏异常 + ## [0.7.41-alpha.15] - 2025-07-27 ### Added diff --git a/src/common/index.ts b/src/common/index.ts index aa80cec417dfd5ee80cc014b8e7f75d25c57a9b4..7abd94e9bb089c37d258510730297e55af873f98 100644 --- a/src/common/index.ts +++ b/src/common/index.ts @@ -41,6 +41,7 @@ import { IBizGanttSetting } from './gantt-setting/gantt-setting'; import { IBizNavSplit } from './nav-split/nav-split'; import { IBizCropping } from './cropping/cropping'; import { IBizEditorEmptyText } from './editor-empty-text/editor-empty-text'; +import { IBizKanbanSetting } from './kanben-setting/kanben-setting'; export * from './col/col'; export * from './row/row'; @@ -54,6 +55,7 @@ export { DoingNotice } from './doing-notice/doing-notice'; export const IBizCommonComponents = { install: (v: App): void => { + v.component(IBizKanbanSetting.name, IBizKanbanSetting); v.component(IBizEditorEmptyText.name, IBizEditorEmptyText); v.component(IBizCropping.name, IBizCropping); v.component(IBizControlBase.name, IBizControlBase); diff --git a/src/common/kanben-setting/kanben-setting.scss b/src/common/kanben-setting/kanben-setting.scss new file mode 100644 index 0000000000000000000000000000000000000000..98e6290c310ca2354156598f013326c0fca1bf5e --- /dev/null +++ b/src/common/kanben-setting/kanben-setting.scss @@ -0,0 +1,12 @@ +@include b('kanban-setting') { + + @include e('popover') { + @include m('content') { + display: flex; + flex-direction: column; + width: 100%; + max-height: 500px; + overflow-y: auto; + } + } +} diff --git a/src/common/kanben-setting/kanben-setting.tsx b/src/common/kanben-setting/kanben-setting.tsx new file mode 100644 index 0000000000000000000000000000000000000000..f88c6924aefb5a63ce7f73b04238ca21eb5775ed --- /dev/null +++ b/src/common/kanben-setting/kanben-setting.tsx @@ -0,0 +1,73 @@ +/* eslint-disable no-nested-ternary */ +import { PropType, computed, defineComponent } from 'vue'; +import { useNamespace } from '@ibiz-template/vue3-util'; +import { KanbanController } from '@ibiz-template/runtime'; +import './kanben-setting.scss'; + +export const IBizKanbanSetting = defineComponent({ + name: 'IBizKanbanSetting', + props: { + controller: { + type: Object as PropType, + required: true, + }, + buttonStyle: { + type: Object as PropType<{ circle: boolean; type: string }>, + default: () => ({ circle: false, type: 'info' }), + }, + }, + setup(props) { + const ns = useNamespace('kanban-setting'); + + const groups = computed(() => { + return props.controller.state.groups; + }); + + return { + ns, + groups, + }; + }, + render() { + return ( +
+ + {{ + reference: () => { + return ( + + + + ); + }, + default: () => { + return ( +
+ {this.groups.map(group => { + return ( + { + group.hidden = !val; + }} + /> + ); + })} +
+ ); + }, + }} +
+
+ ); + }, +}); diff --git a/src/control/data-view/data-view.scss b/src/control/data-view/data-view.scss index 32dfcd7600ca66c044805b6edc273a075126ef19..409d19a32d4a101d6c146958efa90b0395db1c91 100644 --- a/src/control/data-view/data-view.scss +++ b/src/control/data-view/data-view.scss @@ -124,6 +124,17 @@ $control-dataview-group-item-content: ( background-color: getCssVar(control-dataview, hover-bg-color); } + @include e(new) { + color: getCssVar(color, text, 3); + border: 2px dashed getCssVar(color, border); + + .el-card__body { + display: flex; + align-items: center; + justify-content: center; + } + } + @include e(content) { display: flex; align-items: center; diff --git a/src/control/data-view/data-view.tsx b/src/control/data-view/data-view.tsx index 866fb6a5153b15511acad1a99313b5446f530ee9..00eb9bb559a29938572aa48e55e89cabe33c0bb8 100644 --- a/src/control/data-view/data-view.tsx +++ b/src/control/data-view/data-view.tsx @@ -220,6 +220,30 @@ export const DataViewControl = defineComponent({ return c.onDbRowClick(item); }; + /** + * @description 绘制新建卡片项 + * @param {IMDControlGroupState} [group] + * @returns {*} + */ + const renderNewCard = (group?: IMDControlGroupState) => { + return ( + { + c.onClickNew(event, group?.key); + }} + > + + + ); + }; + // 绘制项布局面板 const renderPanelItem = (item: IData, modelData: ILayoutPanel): VNode => { const { context, params } = c; @@ -238,6 +262,7 @@ export const DataViewControl = defineComponent({ > ); }; + // 绘制项行为 const renderItemAction = (item: IData): VNode => { return ( @@ -323,7 +348,7 @@ export const DataViewControl = defineComponent({ * @param {IData[]} items * @return {*} */ - const renderCardLayout = (items: IData[]) => { + const renderCardLayout = (items: IData[], group?: IMDControlGroupState) => { const { cardColXS, cardColSM, cardColMD, cardColLG } = c.model; if (cardColXS || cardColSM || cardColMD || cardColLG) return ( @@ -341,6 +366,17 @@ export const DataViewControl = defineComponent({ ); })} + {c.enableNew && !c.state.readonly && ( + +
{renderNewCard(group)}
+
+ )} ); return ( @@ -348,6 +384,9 @@ export const DataViewControl = defineComponent({ {items.map(item => { return
{renderCard(item)}
; })} + {c.enableNew && !c.state.readonly && ( +
{renderNewCard(group)}
+ )} ); }; @@ -389,7 +428,7 @@ export const DataViewControl = defineComponent({ {group.children.length > 0 ? ( - renderCardLayout(group.children) + renderCardLayout(group.children, group) ) : (
{ibiz.i18n.t('app.noData')} diff --git a/src/control/kanban/kanban.scss b/src/control/kanban/kanban.scss index ab137a6bfa65fdd33563feaee105929f31a5fc9a..08cf95fb20255fe4db32639b5b10f57d7db99113 100644 --- a/src/control/kanban/kanban.scss +++ b/src/control/kanban/kanban.scss @@ -10,13 +10,10 @@ $control-kanban: ( @include b(control-kanban) { @include set-component-css-var(control-kanban, $control-kanban); + display: flex; width: 100%; height: 100%; - @include when('swimlane') { - padding-right: 0 !important; - } - @include m(row) { @include b(control-kanban-group-container) { @include flex(row); @@ -24,7 +21,7 @@ $control-kanban: ( padding-bottom: getCssVar(spacing, tight); overflow: auto; - & > * + *{ + & > * + * { margin-left: getCssVar(spacing, base); } } @@ -36,7 +33,7 @@ $control-kanban: ( flex-direction: column; align-items: start; height: 100%; - padding: getCssVar('spacing','none'); + padding: getCssVar('spacing', 'none'); ion-icon { position: absolute; @@ -47,7 +44,8 @@ $control-kanban: ( } @include e(header-caption) { align-self: center; - transform: rotate(90deg) translate(calc(100% / 2 - var(--ibiz-spacing-tight)), 0); + transform: rotate(90deg) + translate(calc(100% / 2 - var(--ibiz-spacing-tight)), 0); } } } @@ -59,7 +57,7 @@ $control-kanban: ( flex-direction: column; - & > * + *{ + & > * + * { margin-top: getCssVar(spacing, base); } } @@ -77,8 +75,7 @@ $control-kanban: ( } @include b(control-kanban-group-container) { - width: 100%; - height: 100%; + flex: 1; } @include b(control-kanban-group) { @@ -91,7 +88,7 @@ $control-kanban: ( @include e(header) { position: relative; height: getCssVar(control-kanban, group-header-height); - padding: getCssVar('spacing','none') getCssVar(spacing, base); + padding: getCssVar('spacing', 'none') getCssVar(spacing, base); font-size: getCssVar(control-kanban, font-size); font-weight: getCssVar(control-kanban, font-weight); cursor: pointer; @@ -129,8 +126,15 @@ $control-kanban: ( flex: auto; width: 100%; height: calc(100% - 48px); - padding: getCssVar('spacing','none') getCssVar(spacing, tight); + padding: getCssVar('spacing', 'none') getCssVar(spacing, tight); overflow: auto; + + &:hover { + .#{bem(control-kanban, quicktoolbar)} { + visibility: visible; + } + } + @include e(draggable) { min-height: 100%; padding: getCssVar(spacing, base) 0; @@ -142,12 +146,12 @@ $control-kanban: ( flex-shrink: 0; min-height: 0; } - .#{bem(control-kanban, quicktoolbar)}{ + .#{bem(control-kanban, quicktoolbar)} { flex-grow: 1; width: calc(100% - getCssVar(spacing, base)); } - .#{bem(control-toolbar, item)}{ + .#{bem(control-toolbar, item)} { justify-content: center; } } @@ -158,11 +162,11 @@ $control-kanban: ( width: 32px; height: 32px; padding: getCssVar(spacing, tight); - margin-left: getCssVar('spacing','extra-tight'); + margin-left: getCssVar('spacing', 'extra-tight'); font-size: getCssVar(control-kanban, font-size); color: getCssVar(color, primary); cursor: pointer; - border-radius: getCssVar('border','radius','circle'); + border-radius: getCssVar('border', 'radius', 'circle'); &:hover { background-color: getCssVar(color, fill, 0); @@ -170,10 +174,10 @@ $control-kanban: ( } @include e(actions-dropdown) { &:has(.el-button) { - padding: getCssVar(spacing, extra, tight) getCssVar('spacing','none'); + padding: getCssVar(spacing, extra, tight) getCssVar('spacing', 'none'); } .#{bem(action-toolbar)} { - @include flex(column) + @include flex(column); } .el-button { @@ -182,7 +186,7 @@ $control-kanban: ( justify-content: flex-start; width: 100%; padding: getCssVar(spacing, tight) getCssVar(spacing, base); - margin: getCssVar('spacing','none'); + margin: getCssVar('spacing', 'none'); font-size: getCssVar('font-size', 'regular'); color: getCssVar(color, primary, text); @@ -230,7 +234,7 @@ $control-kanban: ( &.is-has-caption { margin: 0; } - } + } } } } @@ -241,40 +245,30 @@ $control-kanban: ( @include b(control-kanban) { position: relative; - padding-right: calc(getCssVar(control-kanban, group-header-height) + getCssVar(spacing, base)); - @include e(quicktoolbar) { - @include flex(column); + @include e(quicktoolbar) { margin-bottom: getCssVar(spacing, base); + visibility: hidden; + @include flex(column); - & > * + *{ + & > * + * { margin-top: getCssVar(spacing, tight); } } - @include e(full-btn) { - @include flex(row, center, center); - - position: absolute; - top: 0; - right: 0; - width: getCssVar(control-kanban, group-header-height); - height: getCssVar(control-kanban, group-header-height); - font-size: getCssVar(font-size, header, 4); - font-weight: getCssVar('font-weight', 'regular'); - color: getCssVar(color, primary); - background-color: getCssVar(color, bg, 2); - border: 1px solid getCssVar(color, border); - } - @include when(full) { padding: getCssVar(spacing, base); - padding-right: calc(getCssVar(control-kanban, group-header-height) + getCssVar(spacing, extra, loose)); background-color: getCssVar(color, bg, 2); - @include e(full-btn) { - top: getCssVar(spacing, base); - right: getCssVar(spacing, base); - } + } +} + +@include b(control-kanban-toolbar) { + display: flex; + flex-shrink: 0; + gap: getCssVar(spacing, tight); + + .el-button { + border: 1px solid getCssVar(color, border); } } @@ -283,7 +277,7 @@ $control-kanban: ( border-bottom: 1px solid getCssVar(color, border); @include e(toolbar) { - .#{bem(control-toolbar)}{ + .#{bem(control-toolbar)} { flex-wrap: wrap; row-gap: getCssVar(spacing, tight); } @@ -298,7 +292,7 @@ $control-kanban: ( @include e(info) { span { - margin: getCssVar('spacing','none') getCssVar(spacing, extra, tight); + margin: getCssVar('spacing', 'none') getCssVar(spacing, extra, tight); color: getCssVar(color, primary); } } diff --git a/src/control/kanban/kanban.tsx b/src/control/kanban/kanban.tsx index ccf8089a179fa3d605a453fea5de178619237ff2..39947e8cba940482584eb26af3f8a13c5c35ff78 100644 --- a/src/control/kanban/kanban.tsx +++ b/src/control/kanban/kanban.tsx @@ -30,7 +30,7 @@ import { KanbanController, IKanbanGroupState, } from '@ibiz-template/runtime'; -import { NOOP, listenJSEvent, showTitle } from '@ibiz-template/core'; +import { NOOP, listenJSEvent } from '@ibiz-template/core'; import { SwimlaneKanban } from './swimlane-kanban/swimlane-kanban'; import './kanban.scss'; @@ -462,7 +462,7 @@ export const KanbanControl = defineComponent({ > )} @@ -636,15 +636,29 @@ export const KanbanControl = defineComponent({
{groups.length > 0 && groups.map(group => { - return this.renderGroup(group as IKanbanGroupState); + if (group.hidden) return null; + return this.renderGroup(group); })}
, groups.length > 0 && ( -
- {this.isFull ? ( - - ) : ( - +
+ {this.c.enableGroupHidden && ( + + )} + {this.c.enableFullScreen && ( + + + )}
), diff --git a/src/control/kanban/swimlane-kanban/swimlane-kanban.scss b/src/control/kanban/swimlane-kanban/swimlane-kanban.scss index 74180d790fc2554e0e8029a8fc46335b46e53027..a18cb279c82fff17f6b10d427d3c2dfb6cb8ec6b 100644 --- a/src/control/kanban/swimlane-kanban/swimlane-kanban.scss +++ b/src/control/kanban/swimlane-kanban/swimlane-kanban.scss @@ -32,6 +32,7 @@ $swimlane-kanban: ( box-sizing: border-box; width: 100%; min-width: fit-content; + padding-right: 4px; border-top: 1px solid getCssVar('color', 'border'); @include m('action') { visibility: hidden; @@ -118,12 +119,12 @@ $swimlane-kanban: ( } .el-button { - color: getCssVar('color', 'text', 3); + color: getCssVar('color', 'text', 2); --el-button-bg-color: #{getCssVar('color', 'white')}; --el-button-hover-bg-color: #{getCssVar('color', 'fill', 0)}; --el-button-active-bg-color: #{getCssVar('color', 'fill', 0)}; - --el-button-text-color: #{getCssVar('color', 'text', 3)}; + --el-button-text-color: #{getCssVar('color', 'text', 2)}; --el-button-hover-text-color: #{getCssVar('color', 'primary')}; --el-button-active-text-color: #{getCssVar('color', 'primary')}; @@ -293,4 +294,11 @@ $swimlane-kanban: ( width: 100%; } } + + @include e('quicktoolbar') { + flex-flow: column nowrap; + gap: getCssVar(spacing, tight); + align-items: center; + justify-content: center; + } } diff --git a/src/control/kanban/swimlane-kanban/swimlane-kanban.tsx b/src/control/kanban/swimlane-kanban/swimlane-kanban.tsx index 93ee1d777f2eded0d1a9fb581693606270b2438e..09a2378d7d44d5c89f3e85875668e5bf80f28c65 100644 --- a/src/control/kanban/swimlane-kanban/swimlane-kanban.tsx +++ b/src/control/kanban/swimlane-kanban/swimlane-kanban.tsx @@ -21,9 +21,6 @@ export const SwimlaneKanban = defineComponent({ draggable, }, props: { - /** - * @description 面板直接内容控制器 - */ controller: { type: Object as PropType, required: true, @@ -36,7 +33,7 @@ export const SwimlaneKanban = defineComponent({ /** * popper样式 */ - const popperStyle = { zIndex: zIndex.increment(), position: 'unset' }; + const popperStyle = { zIndex: zIndex.increment() }; /** * 展开所有 @@ -242,7 +239,6 @@ export const SwimlaneKanban = defineComponent({ {showActionBar && ( (
- { - c.onGroupToolbarClick(detail, event, group); - }} - > + {c.model.groupUIActionGroup && ( + { + c.onGroupToolbarClick(detail, event, group); + }} + > + )} {batchToolbarModel && (
+ {c.enableGroupHidden && ( +
+ +
+ )}
{c.state.groups.map(group => { + if (group.hidden) return undefined; return renderHeaderCell(group); })} @@ -442,6 +449,10 @@ export const SwimlaneKanban = defineComponent({ lane: IKanbanSwimlane, group: IKanbanGroupState, ) => { + const { swimlaneAppDEFieldId } = c.model; + const items = group.children.filter( + item => item[swimlaneAppDEFieldId!] === lane.key, + ); return (
{c.enableNew && !c.state.readonly && ( @@ -456,7 +467,7 @@ export const SwimlaneKanban = defineComponent({ {ibiz.i18n.t('app.newlyBuild')} )} - {quickToolbarModel && ( + {quickToolbarModel && items.length === 0 && (
{c.state.groups.map(group => { + if (group.hidden) return undefined; return renderBodyCell(index, lane, group); })} diff --git a/src/locale/en/index.ts b/src/locale/en/index.ts index 5fd49a8a2bdabc7a94aef8a0f3f876d2daf45338..9b2e2fdc768feb33361f89f4fcec8a2b193571ac 100644 --- a/src/locale/en/index.ts +++ b/src/locale/en/index.ts @@ -31,6 +31,8 @@ export default { pleaseEnterAccount: 'Please enter account number', pleaseEnterPassword: 'Please enter password', aiError: 'System encountered an exception, please try again later', + fullscreen: 'Fullscreen', + cancelFullscreen: 'Cancel fullscreen', }, // 视图 view: { @@ -592,6 +594,9 @@ export default { gridSetting: { hideControl: 'Column selection', }, + kanbanSetting: { + hideGroup: 'Group selection', + }, ganttSetting: { resultDefault: 'Restore defaults', headerCaption: 'Header display attributes', diff --git a/src/locale/zh-CN/index.ts b/src/locale/zh-CN/index.ts index 77af981446b89c092f77846445bccee1305ee7c8..99b9107a2511719190cc22377c3de7d97494dc78 100644 --- a/src/locale/zh-CN/index.ts +++ b/src/locale/zh-CN/index.ts @@ -31,6 +31,8 @@ export default { pleaseEnterAccount: '请输入账号', pleaseEnterPassword: '请输入密码', aiError: '系统发生异常,请稍后重试', + fullscreen: '全屏', + cancelFullscreen: '取消全屏', }, // 视图 view: { @@ -549,6 +551,9 @@ export default { gridSetting: { hideControl: '列选择', }, + kanbanSetting: { + hideGroup: '分组选择', + }, ganttSetting: { resultDefault: '恢复默认值', headerCaption: '表头显示属性',