From 520e69453048d2b1503bc4ba672fd82742ebb3d8 Mon Sep 17 00:00:00 2001 From: hisoka0728 <1399952343@qq.com> Date: Thu, 8 Aug 2024 08:39:33 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=8F=90=E4=BA=A4=E5=A4=A7=E5=B1=8F?= =?UTF-8?q?=E5=B1=9E=E6=80=A7,=E5=A4=A7=E5=B1=8F=E6=97=A5=E6=9C=9F?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E6=8F=92=E4=BB=B6,=E5=A4=A7=E5=B1=8F?= =?UTF-8?q?=E5=8D=95=E9=80=89=E5=BE=AA=E7=8E=AF=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.ts | 6 + src/screen-date-picker/index.ts | 17 + .../screen-date-picker-editor.controller.ts | 69 ++++ .../screen-date-picker-editor.provider.ts | 35 ++ .../screen-date-picker.scss | 115 +++++++ src/screen-date-picker/screen-date-picker.tsx | 228 +++++++++++++ src/screen-panel-attribute/index.ts | 17 + .../screen-panel-attribute.controller.ts | 70 ++++ .../screen-panel-attribute.provider.ts | 28 ++ .../screen-panel-attribute.scss | 312 ++++++++++++++++++ .../screen-panel-attribute.tsx | 94 ++++++ src/screen-radio-list/index.ts | 16 + .../screen-radio-list.controller.ts | 25 ++ .../screen-radio-list.provider.ts | 34 ++ src/screen-radio-list/screen-radio-list.scss | 116 +++++++ src/screen-radio-list/screen-radio-list.tsx | 211 ++++++++++++ 16 files changed, 1393 insertions(+) create mode 100644 src/screen-date-picker/index.ts create mode 100644 src/screen-date-picker/screen-date-picker-editor.controller.ts create mode 100644 src/screen-date-picker/screen-date-picker-editor.provider.ts create mode 100644 src/screen-date-picker/screen-date-picker.scss create mode 100644 src/screen-date-picker/screen-date-picker.tsx create mode 100644 src/screen-panel-attribute/index.ts create mode 100644 src/screen-panel-attribute/screen-panel-attribute.controller.ts create mode 100644 src/screen-panel-attribute/screen-panel-attribute.provider.ts create mode 100644 src/screen-panel-attribute/screen-panel-attribute.scss create mode 100644 src/screen-panel-attribute/screen-panel-attribute.tsx create mode 100644 src/screen-radio-list/index.ts create mode 100644 src/screen-radio-list/screen-radio-list.controller.ts create mode 100644 src/screen-radio-list/screen-radio-list.provider.ts create mode 100644 src/screen-radio-list/screen-radio-list.scss create mode 100644 src/screen-radio-list/screen-radio-list.tsx diff --git a/src/index.ts b/src/index.ts index bc553b6..4ef9be9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,6 +2,9 @@ import { App } from 'vue'; import { IBizDigitalFlop } from './digital-flop/index'; import { IBizScreenDashboard } from './screen-dashboard/index'; import { IBizScreenPortlet } from './screen-portlet/index'; +import { IBizScreenPanelAttribute } from './screen-panel-attribute/index'; +import { IBizScreenDatePicker } from './screen-date-picker/index'; +import { IBizScreenRadioList } from './screen-radio-list/index'; // 注入组件 export default { @@ -9,5 +12,8 @@ export default { _app.use(IBizDigitalFlop); _app.use(IBizScreenDashboard); _app.use(IBizScreenPortlet); + _app.use(IBizScreenPanelAttribute); + _app.use(IBizScreenDatePicker); + _app.use(IBizScreenRadioList); }, }; diff --git a/src/screen-date-picker/index.ts b/src/screen-date-picker/index.ts new file mode 100644 index 0000000..58ff305 --- /dev/null +++ b/src/screen-date-picker/index.ts @@ -0,0 +1,17 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import { registerEditorProvider } from '@ibiz-template/runtime'; +import { withInstall } from '@ibiz-template/vue3-util'; +import { App } from 'vue'; +import { ScreenDatePicker } from './screen-date-picker'; +import { ScreenDatePickerEditorProvider } from './screen-date-picker-editor.provider'; + +export const IBizScreenDatePicker = withInstall( + ScreenDatePicker, + function (v: App) { + v.component(ScreenDatePicker.name, ScreenDatePicker); + registerEditorProvider( + 'DATEPICKER_SCREEN_DATE_PICKER', + () => new ScreenDatePickerEditorProvider(), + ); + }, +); diff --git a/src/screen-date-picker/screen-date-picker-editor.controller.ts b/src/screen-date-picker/screen-date-picker-editor.controller.ts new file mode 100644 index 0000000..4375608 --- /dev/null +++ b/src/screen-date-picker/screen-date-picker-editor.controller.ts @@ -0,0 +1,69 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import { EditorController } from '@ibiz-template/runtime'; +import { IDatePicker } from '@ibiz/model-core'; + +/** + * 选项框列表编辑器控制器 + * @return {*} + * @author: zhujiamin + * @Date: 2022-08-25 10:57:58 + */ +export class ScreenDatePickerEditorController extends EditorController { + /** + * 根据编辑器类型获取格式化 + * + * @author lxm + * @date 2022-11-03 16:11:21 + * @protected + * @returns {*} {string} + */ + getFormatByType(editorType: string | undefined): string { + switch (editorType) { + // 时间选择器 + case 'DATEPICKER': + return 'YYYY-MM-DD HH:mm:ss'; + // 时间选择控件 + case 'DATEPICKEREX': + return 'YYYY-MM-DD HH:mm:ss'; + // 时间选择控件_无小时 + case 'DATEPICKEREX_NOTIME': + return 'YYYY-MM-DD'; + // 时间选择控件_小时 + case 'DATEPICKEREX_HOUR': + return 'YYYY-MM-DD HH'; + // 时间选择控件_分钟 + case 'DATEPICKEREX_MINUTE': + return 'YYYY-MM-DD HH:mm'; + // 时间选择控件_秒钟 + case 'DATEPICKEREX_SECOND': + return 'YYYY-MM-DD HH:mm:ss'; + // 时间选择控件_无日期 + case 'DATEPICKEREX_NODAY': + return 'HH:mm:ss'; + // 时间选择控件_无日期无秒钟 + case 'DATEPICKEREX_NODAY_NOSECOND': + return 'HH:mm'; + // 时间选择控件_无秒钟 + case 'DATEPICKEREX_NOSECOND': + return 'YYYY-MM-DD HH:mm'; + default: + return 'YYYY-MM-DD HH:mm:ss'; + } + } + + /** + * 值格式化 + * @return {*} + * @author: zhujiamin + * @Date: 2022-08-25 14:33:14 + */ + get valueFormat(): string | undefined { + if (this.model.dateTimeFormat) { + return this.model.dateTimeFormat; + } + if (super.valueFormat) { + return super.valueFormat; + } + return this.getFormatByType(this.model.editorType); + } +} diff --git a/src/screen-date-picker/screen-date-picker-editor.provider.ts b/src/screen-date-picker/screen-date-picker-editor.provider.ts new file mode 100644 index 0000000..8319243 --- /dev/null +++ b/src/screen-date-picker/screen-date-picker-editor.provider.ts @@ -0,0 +1,35 @@ +/* eslint-disable import/no-extraneous-dependencies */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { + IEditorContainerController, + IEditorProvider, +} from '@ibiz-template/runtime'; +import { IDatePicker } from '@ibiz/model-core'; +import { ScreenDatePickerEditorController } from './screen-date-picker-editor.controller'; + +/** + * 日期时间选择器编辑器适配器 + * + * @author lxm + * @date 2022-09-19 22:09:03 + * @export + * @class DatePickerEditorProvider + * @implements {EditorProvider} + */ +export class ScreenDatePickerEditorProvider implements IEditorProvider { + formEditor: string = 'ScreenDatePicker'; + + gridEditor: string = 'ScreenDatePicker'; + + async createController( + editorModel: IDatePicker, + parentController: IEditorContainerController, + ): Promise { + const c = new ScreenDatePickerEditorController( + editorModel, + parentController, + ); + await c.init(); + return c; + } +} diff --git a/src/screen-date-picker/screen-date-picker.scss b/src/screen-date-picker/screen-date-picker.scss new file mode 100644 index 0000000..10b675c --- /dev/null +++ b/src/screen-date-picker/screen-date-picker.scss @@ -0,0 +1,115 @@ +/* stylelint-disable selector-class-pattern */ +$screen-date-picker: ( + 'width': 121px, + 'background-repeat': no-repeat, + 'background-image': url('../../public/assets/img/time-container.png'), + 'icon-top': -2px, + 'icon-right': 8px, + 'icon-width': 32px, + 'icon-height': 32px, + 'icon-background-image': url('../../public/assets/img/time-down-arrow.png'), +); + +@include b('screen-date-picker') { + @include set-component-css-var('screen-date-picker', $screen-date-picker); + + position: relative; + width: getCssVar('screen-date-picker', 'width'); + background-color: transparent; + background-image: getCssVar('screen-date-picker', 'background-image'); + background-repeat: getCssVar('screen-date-picker', 'background-repeat'); + + .el-date-editor { + width: 100%; + } + + input { + font-size: getCssVar('form-item', 'font-size'); + color: getCssVar('form-item', 'text-color'); + border-color: getCssVar('form-item', 'border-color'); + } + + input::placeholder { + color: getCssVar('form-item', 'placeholder-color'); + } + + input[disabled] { + color: getCssVar('form-item', 'disabled-color'); + border-color: getCssVar('form-item', 'disabled-border-color'); + } + + @include m(readonly) { + font-size: getCssVar(form-item, font-size); + line-height: getCssVar(editor, default, line-height); + color: getCssVar(form-item, readonly-color); + } + + // 时间选择编辑器都不要输入框前面的图标(原因:模型默认给了宽度) + .el-input__wrapper { + .el-input__prefix { + display: none; + } + + &:hover { + box-shadow: unset; + } + } + + @include e(icon) { + position: absolute; + top: getCssVar('screen-date-picker', 'icon-top'); + right: getCssVar('screen-date-picker', 'icon-right'); + display: inline-block; + width: getCssVar('screen-date-picker', 'icon-width'); + height: getCssVar('screen-date-picker', 'icon-height'); + background-color: transparent; + background-image: getCssVar('screen-date-picker', 'icon-background-image'); + background-repeat: no-repeat; + } +} + +// 表单下的时间选择器默认显示,悬浮上去显示编辑器 +@include b(date-picker-form-default-content) { + display: none; +} + +@include b(form-item) { + @include b(date-picker) { + @include when(show-default) { + // 悬浮显示编辑器 + &:hover { + @include b(date-picker-form-default-content) { + display: none; + } + @include b(date-picker-input) { + display: block; + } + } + + // 不悬浮时显示信息态 + @include b(date-picker-form-default-content) { + display: flex; + align-items: center; + width: 100%; + padding: getCssVar(form-item, hover-edit-padding); + font-family: Arial, sans-serif; + font-size: getCssVar(form-item, font-size); + line-height: getCssVar(editor, default, line-height); + color: getCssVar(form-item, text-color); + } + @include b(date-picker-input) { + display: none; + } + + // 输入态 + @include when(editable) { + @include b(date-picker-form-default-content) { + display: none; + } + @include b(date-picker-input) { + display: block; + } + } + } + } +} diff --git a/src/screen-date-picker/screen-date-picker.tsx b/src/screen-date-picker/screen-date-picker.tsx new file mode 100644 index 0000000..36b4cfa --- /dev/null +++ b/src/screen-date-picker/screen-date-picker.tsx @@ -0,0 +1,228 @@ +/* eslint-disable import/no-extraneous-dependencies */ +/* eslint-disable no-nested-ternary */ +import { ref, watch, defineComponent, computed } from 'vue'; +import { + getDatePickerProps, + getEditorEmits, + useNamespace, +} from '@ibiz-template/vue3-util'; +import './screen-date-picker.scss'; +import dayjs from 'dayjs'; +import { ScreenDatePickerEditorController } from './screen-date-picker-editor.controller'; + +export const ScreenDatePicker = defineComponent({ + name: 'ScreenDatePicker', + props: getDatePickerProps(), + emits: getEditorEmits(), + setup(props, { emit }) { + const ns = useNamespace('screen-date-picker'); + const c = props.controller; + + const editorModel = c!.model; + + const type = ref('date'); + + const format = ref('YYYY-MM-DD'); + + const isTimePicker = ref(false); + + // 是否编辑态 + const isEditable = ref(false); + + // 编辑器Ref + const editorRef = ref(); + + // 是否显示表单默认内容 + const showFormDefaultContent = computed(() => { + if ( + props.controlParams && + props.controlParams.editmode === 'hover' && + !props.readonly + ) { + return true; + } + return false; + }); + + switch (editorModel.editorType) { + case 'DATEPICKEREX': + case 'DATEPICKEREX_NOTIME': + type.value = 'date'; + break; + case 'DATEPICKEREX_NODAY': + case 'DATEPICKEREX_NODAY_NOSECOND': + isTimePicker.value = true; + type.value = 'time'; + break; + case 'DATEPICKEREX_HOUR': + case 'DATEPICKEREX_MINUTE': + case 'DATEPICKEREX_SECOND': + case 'DATEPICKEREX_NOSECOND': + case 'DATEPICKER': + default: + type.value = 'datetime'; + } + // 值格式化 + const valueFormat = c!.valueFormat; + if (valueFormat) { + format.value = valueFormat; + } + + // 格式化后的值 + const formatValue = ref(); + watch( + () => props.value, + (newVal, oldVal) => { + // 空值不转换 + if (newVal && newVal !== oldVal) { + const formatVal = dayjs(newVal).format(valueFormat); + if (formatVal !== 'Invalid Date') { + formatValue.value = formatVal; + } else { + formatValue.value = newVal; + } + } else if (newVal == null) { + formatValue.value = newVal; + } + }, + { immediate: true }, + ); + + const setEditable = (flag: boolean) => { + if (flag) { + isEditable.value = flag; + } else { + setTimeout(() => { + isEditable.value = flag; + }, 100); + } + }; + + // 处理值变更 + const handleChange = (date: string, _dateType: IData) => { + emit('change', date); + setEditable(false); + }; + + watch(editorRef, newVal => { + if (props.autoFocus && newVal && newVal.focus) { + newVal.focus(); + } + }); + + // 聚焦 + const onFocus = (e: IData) => { + emit('focus', e); + setEditable(true); + }; + + // 失焦 + const onBlur = (e: IData) => { + emit('blur', e); + setEditable(false); + }; + + watch( + formatValue, + (newVal, oldVal) => { + if (newVal !== oldVal) { + emit('infoTextChange', newVal); + } + }, + { immediate: true }, + ); + + // 处理点击键盘 + const handleKeyUp = (e: KeyboardEvent) => { + if (e && e.code === 'Enter') { + emit('enter', e); + } + }; + + const renderIcon = () => { + return ; + }; + + return { + ns, + c, + editorModel, + type, + format, + formatValue, + handleChange, + editorRef, + isTimePicker, + onFocus, + onBlur, + isEditable, + setEditable, + showFormDefaultContent, + handleKeyUp, + renderIcon, + }; + }, + render() { + // 编辑态内容 + const editContent = this.isTimePicker ? ( + + ) : ( + + ); + + // 只读态内容 + const readonlyContent = this.formatValue; + + // 表单默认内容 + const formDefaultContent = ( +
+ {this.formatValue ? this.formatValue : '-'} +
+ ); + + return ( +
+ {this.showFormDefaultContent && formDefaultContent} + {this.readonly ? readonlyContent : editContent} + {this.readonly ? '' : this.renderIcon()} +
+ ); + }, +}); diff --git a/src/screen-panel-attribute/index.ts b/src/screen-panel-attribute/index.ts new file mode 100644 index 0000000..1660264 --- /dev/null +++ b/src/screen-panel-attribute/index.ts @@ -0,0 +1,17 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import { withInstall } from '@ibiz-template/vue3-util'; +import { App } from 'vue'; +import { registerEditorProvider } from '@ibiz-template/runtime'; +import { ScreenPanelAttribute } from './screen-panel-attribute'; +import { ScreenPanelAttributeControllerProvider } from './screen-panel-attribute.provider'; + +export const IBizScreenPanelAttribute = withInstall( + ScreenPanelAttribute, + function (v: App) { + v.component(ScreenPanelAttribute.name, ScreenPanelAttribute); + registerEditorProvider( + 'SPAN_SCREEN_PANEL_ATTRIBUTE', + () => new ScreenPanelAttributeControllerProvider(), + ); + }, +); diff --git a/src/screen-panel-attribute/screen-panel-attribute.controller.ts b/src/screen-panel-attribute/screen-panel-attribute.controller.ts new file mode 100644 index 0000000..0c73b96 --- /dev/null +++ b/src/screen-panel-attribute/screen-panel-attribute.controller.ts @@ -0,0 +1,70 @@ +import { ISpan } from '@ibiz/model-core'; + +// eslint-disable-next-line import/no-extraneous-dependencies +import { EditorController } from '@ibiz-template/runtime'; + +/** + * @description 大屏面板属性 + * @export + * @class DigitalFlopController + * @extends {EditorController} + */ +export class ScreenPanelAttributeController extends EditorController { + /** + * 展示模式 + * + * @author fangZhiHao + * @date 2024-08-07 15:08:14 + * @type {string} + */ + showModel: string = 'model1'; + + /** + * 单位 + * + * @author fangZhiHao + * @date 2024-08-07 14:08:14 + * @type {string} + */ + public unit: string = '个'; + + /** + * 标题位置 + * + * @author fangZhiHao + * @date 2024-08-07 14:08:38 + * @type {string} + */ + public labelPosition: string = 'bottom'; + + /** + * 标题 + * + * @author fangZhiHao + * @date 2024-08-07 20:08:45 + * @type {string} + */ + public caption: string = ''; + + /** + * 初始化 + */ + protected async onInit(): Promise { + if (this.model.editorParams) { + const { UNIT, LABELPOSITION, SHOWMODEL, CAPTION } = + this.model.editorParams; + if (UNIT) { + this.unit = UNIT; + } + if (LABELPOSITION) { + this.labelPosition = LABELPOSITION; + } + if (SHOWMODEL) { + this.showModel = SHOWMODEL; + } + if (CAPTION) { + this.caption = CAPTION; + } + } + } +} diff --git a/src/screen-panel-attribute/screen-panel-attribute.provider.ts b/src/screen-panel-attribute/screen-panel-attribute.provider.ts new file mode 100644 index 0000000..ca4dbca --- /dev/null +++ b/src/screen-panel-attribute/screen-panel-attribute.provider.ts @@ -0,0 +1,28 @@ +import { ISpan } from '@ibiz/model-core'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { + IEditorProvider, + IEditorContainerController, +} from '@ibiz-template/runtime'; +import { ScreenPanelAttributeController } from './screen-panel-attribute.controller'; + +/** + * @description 大屏面板属性 + * @export + * @class DigitalFlopControllerProvider + * @implements {IEditorProvider} + */ +export class ScreenPanelAttributeControllerProvider implements IEditorProvider { + formEditor: string = 'ScreenPanelAttribute'; + + gridEditor: string = 'ScreenPanelAttribute'; + + async createController( + editorModel: ISpan, + parentController: IEditorContainerController, + ): Promise { + const c = new ScreenPanelAttributeController(editorModel, parentController); + await c.init(); + return c; + } +} diff --git a/src/screen-panel-attribute/screen-panel-attribute.scss b/src/screen-panel-attribute/screen-panel-attribute.scss new file mode 100644 index 0000000..a7caed0 --- /dev/null +++ b/src/screen-panel-attribute/screen-panel-attribute.scss @@ -0,0 +1,312 @@ +$screen-panel-attribute: ( + 'min-height': 124px, + 'margin-top': 16px, + 'textvalue-top': 15%, + 'textvalue-left': 52%, + 'textvalue-transform': translateX(-50%), + 'textvalue-height': 100%, + 'textvalue-left-top': 0%, + 'textvalue-left-margin-top': 46%, + 'textvalue-right-top': 0%, + 'textvalue-right-margin-top': 46%, + 'textvalue-top-top': 0%, + 'hours-font-size': 36px, + 'hours-font-weight': bold, + 'hours-color': transparent, + 'hours-background-image': linear-gradient(white, #77c0f9), + 'hours-transform': skewX(-10deg), + 'unit-padding-top': 10px, + 'unit-font-size': 11px, + 'unit-font-weight': bold, + 'unit-color': transparent, + 'unit-background-image': linear-gradient(white, #77c0f9), + 'unit-transform': skewX(-10deg), + 'label-font-size': 14px, + 'label-color': #77c0f9, + 'backimg-margin': 0 auto, + 'backimg-height': 103px, + 'backimg-width': 173px, + 'backimg-background-image': + url('../../public/assets/img/year-month-target.png'), +); + +@include b(screen-panel-attribute) { + @include set-component-css-var( + 'screen-panel-attribute', + $screen-panel-attribute + ); + + @include e(backimg) { + width: getCssVar('screen-panel-attribute', 'backimg-width'); + height: getCssVar('screen-panel-attribute', 'backimg-height'); + margin: getCssVar('screen-panel-attribute', 'backimg-margin'); + background-image: getCssVar( + 'screen-panel-attribute', + 'backimg-background-image' + ); + } + + position: relative; + min-height: getCssVar('screen-panel-attribute', 'min-height'); + margin-top: getCssVar('screen-panel-attribute', 'margin-top'); + overflow: hidden; + text-align: center; + + @include e(textvalue) { + position: absolute; + top: getCssVar('screen-panel-attribute', 'textvalue-top'); + left: getCssVar('screen-panel-attribute', 'textvalue-left'); + display: flex; + flex-direction: column; + width: max-content; + height: getCssVar('screen-panel-attribute', 'textvalue-height'); + transform: getCssVar('screen-panel-attribute', 'textvalue-transform'); + + &.left { + top: getCssVar('screen-panel-attribute', 'textvalue-left-top'); + flex-direction: row-reverse; + .#{bem('screen-panel-attribute','label')} { + margin-top: getCssVar( + 'screen-panel-attribute', + 'textvalue-left-margin-top' + ); + } + } + + &.right { + top: getCssVar('screen-panel-attribute', 'textvalue-right-top'); + flex-direction: row; + .#{bem('screen-panel-attribute','label')} { + margin-top: getCssVar( + 'screen-panel-attribute', + 'textvalue-right-margin-top' + ); + } + } + + &.top { + top: getCssVar('screen-panel-attribute', 'textvalue-top-top'); + flex-direction: column-reverse; + } + } + + @include e(value) { + display: flex; + align-items: center; + justify-content: center; + vertical-align: bottom; + } + @include e(hours) { + font-size: getCssVar('screen-panel-attribute', 'hours-font-size'); + font-weight: getCssVar('screen-panel-attribute', 'hours-font-weight'); + color: getCssVar('screen-panel-attribute', 'hours-color'); + background-image: getCssVar( + 'screen-panel-attribute', + 'hours-background-image' + ); + background-clip: text; + transform: getCssVar('screen-panel-attribute', 'hours-transform'); + } + + @include e(unit) { + padding-top: getCssVar('screen-panel-attribute', 'unit-padding-top'); + font-size: getCssVar('screen-panel-attribute', 'unit-font-size'); + font-weight: getCssVar('screen-panel-attribute', 'unit-font-weight'); + color: getCssVar('screen-panel-attribute', 'unit-color'); + background-image: getCssVar( + 'screen-panel-attribute', + 'unit-background-image' + ); + background-clip: text; + transform: getCssVar('screen-panel-attribute', 'unit-transform'); + } + + @include e(label) { + font-size: getCssVar('screen-panel-attribute', 'label-font-size'); + color: getCssVar('screen-panel-attribute', 'label-color'); + } +} + +$screen-panel-attribute-model3: ( + 'padding-top': 40px, + 'margin-bottom': -20px, + 'value-height': 53px, + 'value-background-image': url('../../public/assets/img/year-total.png'), + 'total-padding-top': 2px, + 'total-font-size': 28px, + 'total-color': #fefefe, + 'total-text-shadow': 1px 0 4px rgb(39 116 245 / 50%) -1px 0 4px rgb( + 39 116 245 / 50% + ) 0 -1px 4px rgb(39 116 245 / 50%) 0 1px 4px rgb(39 116 245 / 50%), + 'total-letter-spacing': 5px, + 'total-webkit-text-stroke': 0.5px #3474c6, + 'label-margin-top': 5px, + 'label-font-size': 16px, + 'label-font-weight': 700, + 'label-color': #fff, + 'text-margin': 0 2px, +); + +@include b(screen-panel-attribute-model3) { + @include set-component-css-var( + 'screen-panel-attribute-model3', + $screen-panel-attribute-model3 + ); + + padding-top: getCssVar('screen-panel-attribute-model3', 'padding-top'); + margin-bottom: getCssVar('screen-panel-attribute-model3', 'margin-bottom'); + + @include e(value) { + height: getCssVar('screen-panel-attribute-model3', 'value-height'); + text-align: center; + background-image: getCssVar( + 'screen-panel-attribute-model3', + 'value-background-image' + ); + background-repeat: no-repeat; + background-position: center; + } + + @include e(total) { + padding-top: getCssVar( + 'screen-panel-attribute-model3', + 'total-padding-top' + ); + font-size: getCssVar('screen-panel-attribute-model3', 'total-font-size'); + color: getCssVar('screen-panel-attribute-model3', 'total-font-size'); + text-shadow: getCssVar( + 'screen-panel-attribute-model3', + 'total-text-shadow' + ); + letter-spacing: getCssVar( + 'screen-panel-attribute-model3', + 'total-letter-spacing' + ); + -webkit-text-stroke: getCssVar( + 'screen-panel-attribute-model3', + 'total-webkit-text-stroke' + ); + } + + @include e(label) { + display: block; + margin-top: getCssVar('screen-panel-attribute-model3', 'label-margin-top'); + font-size: getCssVar('screen-panel-attribute-model3', 'label-font-size'); + font-weight: getCssVar( + 'screen-panel-attribute-model3', + 'label-font-weight' + ); + color: getCssVar('screen-panel-attribute-model3', 'label-color'); + text-align: center; + } + @include e(text) { + margin: 0 2px; + } +} + +$screen-panel-attribute-model2: ( + 'min-width': 366px, + 'height': 90px, + 'textvalue-top': 0, + 'textvalue-left': 50%, + 'textvalue-width': 288px, + 'textvalue-height': 100%, + 'textvalue-background-image': + url('../../public/assets/img/today-new-student.png'), + 'textvalue-transform': translateX(-50%), + 'label-padding-top': 10px, + 'label-font-size': 18px, + 'label-font-weight': normal, + 'label-color': #409df1, + 'label-letter-spacing': 4px, + 'label-webkit-text-stroke': 0.3px, + 'value-padding-top': 6px, + 'value-font-size': 36px, + 'value-font-weight': bold, + 'value-color': transparent, + 'value-background': linear-gradient(to bottom, white, #3cbef1), + 'value-transform': skewX(-10deg), + 'unit-font-size': 18px, + 'unit-font-weight': 600, +); + +@include b(screen-panel-attribute-model2) { + @include set-component-css-var( + 'screen-panel-attribute-model2', + $screen-panel-attribute-model2 + ); + + position: relative; + min-width: getCssVar('screen-panel-attribute-model2', 'min-width'); + height: getCssVar('screen-panel-attribute-model2', 'height'); + overflow: hidden; + text-align: center; + + @include e(textvalue) { + position: absolute; + top: getCssVar('screen-panel-attribute-model2', 'textvalue-top'); + left: getCssVar('screen-panel-attribute-model2', 'textvalue-left'); + display: flex; + flex-direction: column; + width: getCssVar('screen-panel-attribute-model2', 'textvalue-width'); + height: getCssVar('screen-panel-attribute-model2', 'textvalue-height'); + background-image: getCssVar( + 'screen-panel-attribute-model2', + 'textvalue-background-image' + ); + transform: getCssVar( + 'screen-panel-attribute-model2', + 'textvalue-transform' + ); + } + @include e(label) { + display: flex; + flex: 0; + justify-content: center; + padding-top: getCssVar( + 'screen-panel-attribute-model2', + 'label-padding-top' + ); + font-size: getCssVar('screen-panel-attribute-model2', 'label-font-size'); + font-weight: getCssVar( + 'screen-panel-attribute-model2', + 'label-font-weight' + ); + color: getCssVar('screen-panel-attribute-model2', 'label-color'); + letter-spacing: getCssVar( + 'screen-panel-attribute-model2', + 'label-letter-spacing' + ); + -webkit-text-stroke: getCssVar( + 'screen-panel-attribute-model2', + 'label-webkit-text-stroke' + ); + } + + @include e(value) { + display: flex; + flex: 1; + align-items: baseline; + justify-content: center; + padding-top: getCssVar( + 'screen-panel-attribute-model2', + 'value-padding-top' + ); + font-size: getCssVar('screen-panel-attribute-model2', 'value-font-size'); + font-weight: getCssVar( + 'screen-panel-attribute-model2', + 'value-font-weight' + ); + color: getCssVar('screen-panel-attribute-model2', 'value-color'); + background: getCssVar('screen-panel-attribute-model2', 'value-background'); + background-clip: text; + transform: getCssVar('screen-panel-attribute-model2', 'value-transform'); + } + + @include e(unit) { + display: inline-flex; + align-items: end; + font-size: getCssVar('screen-panel-attribute-model2', 'unit-font-size'); + font-weight: getCssVar('screen-panel-attribute-model2', 'unit-font-weight'); + } +} diff --git a/src/screen-panel-attribute/screen-panel-attribute.tsx b/src/screen-panel-attribute/screen-panel-attribute.tsx new file mode 100644 index 0000000..25b9bfb --- /dev/null +++ b/src/screen-panel-attribute/screen-panel-attribute.tsx @@ -0,0 +1,94 @@ +import { defineComponent } from 'vue'; +import { getSpanProps, useNamespace } from '@ibiz-template/vue3-util'; +import { ScreenPanelAttributeController } from './screen-panel-attribute.controller'; +import './screen-panel-attribute.scss'; + +export const ScreenPanelAttribute = defineComponent({ + name: 'ScreenPanelAttribute', + props: getSpanProps(), + setup(props) { + const ns = useNamespace('screen-panel-attribute'); + + const c = props.controller; + + const renderModel1 = () => { + return ( +
+
+
+
+
{props.value || 0}
+
{c.unit}
+
+
{c.caption}
+
+
+ ); + }; + + const renderModel2 = () => { + return ( +
+
+
{c.caption}
+
+ {props.value || 0} +
{c.unit}
+
+
+
+ ); + }; + + const renderModel3 = () => { + return ( +
+
+
{props.value || 0}
+
+
+ + {c.caption} + +
+
+ ); + }; + + const renderModel4 = () => { + return ( +
+
{c.caption}
+
+ ); + }; + + const renderModel = () => { + if (c.showModel === 'model1') { + return renderModel1(); + } + if (c.showModel === 'model2') { + return renderModel2(); + } + if (c.showModel === 'model3') { + return renderModel3(); + } + if (c.showModel === 'model4') { + return renderModel4(); + } + }; + + return { + ns, + c, + renderModel1, + renderModel2, + renderModel3, + renderModel4, + renderModel, + }; + }, + render() { + return this.renderModel(); + }, +}); diff --git a/src/screen-radio-list/index.ts b/src/screen-radio-list/index.ts new file mode 100644 index 0000000..f73f9f0 --- /dev/null +++ b/src/screen-radio-list/index.ts @@ -0,0 +1,16 @@ +import { registerEditorProvider } from '@ibiz-template/runtime'; +import { withInstall } from '@ibiz-template/vue3-util'; +import { App } from 'vue'; +import { ScreenRadioList } from './screen-radio-list'; +import { ScreenRadioButtonListEditorProvider } from './screen-radio-list.provider'; + +export const IBizScreenRadioList = withInstall( + ScreenRadioList, + function (v: App) { + v.component(ScreenRadioList.name, ScreenRadioList); + registerEditorProvider( + 'RADIOBUTTONLIST_SCREEN_RADIO_LIST', + () => new ScreenRadioButtonListEditorProvider(), + ); + }, +); diff --git a/src/screen-radio-list/screen-radio-list.controller.ts b/src/screen-radio-list/screen-radio-list.controller.ts new file mode 100644 index 0000000..86db68c --- /dev/null +++ b/src/screen-radio-list/screen-radio-list.controller.ts @@ -0,0 +1,25 @@ +import { CodeListEditorController } from '@ibiz-template/runtime'; +import { IRadioButtonList } from '@ibiz/model-core'; + +/** + * 单选项列表编辑器控制器 + * @return {*} + * @author: zhujiamin + * @Date: 2022-08-25 10:57:58 + */ +export class ScreenRadioListEditorController extends CodeListEditorController { + /** + * 单选一行展示几个 + * @author fangZhiHao + * @date 2024-07-17 10:07:40 + * @type {(number | undefined)} + */ + rowNumber: number | undefined = undefined; + + protected async onInit(): Promise { + super.onInit(); + if (this.editorParams?.rowNumber) { + this.rowNumber = Number(this.editorParams.rowNumber); + } + } +} diff --git a/src/screen-radio-list/screen-radio-list.provider.ts b/src/screen-radio-list/screen-radio-list.provider.ts new file mode 100644 index 0000000..7ed4a74 --- /dev/null +++ b/src/screen-radio-list/screen-radio-list.provider.ts @@ -0,0 +1,34 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { + IEditorContainerController, + IEditorProvider, +} from '@ibiz-template/runtime'; +import { IRadioButtonList } from '@ibiz/model-core'; +import { ScreenRadioListEditorController } from './screen-radio-list.controller'; + +/** + * 单选框列表编辑器适配器 + * + * @author lxm + * @date 2022-09-19 22:09:03 + * @export + * @class RadioButtonListEditorProvider + * @implements {EditorProvider} + */ +export class ScreenRadioButtonListEditorProvider implements IEditorProvider { + formEditor: string = 'ScreenRadioList'; + + gridEditor: string = 'ScreenRadioList'; + + async createController( + editorModel: IRadioButtonList, + parentController: IEditorContainerController, + ): Promise { + const c = new ScreenRadioListEditorController( + editorModel, + parentController, + ); + await c.init(); + return c; + } +} diff --git a/src/screen-radio-list/screen-radio-list.scss b/src/screen-radio-list/screen-radio-list.scss new file mode 100644 index 0000000..c394891 --- /dev/null +++ b/src/screen-radio-list/screen-radio-list.scss @@ -0,0 +1,116 @@ +$screen-radio-list: ( + group-row-number: 0, + 'radio-input-display': none, + 'radio-padding': 0 5px, + 'radio-color': #17aaf0, + 'radio-background-image': + url('../../public/assets/img/month-train-default.png'), + 'radio-background-repeat': no-repeat, + 'radio-background-size': 100% 32px, + 'radio-checked-font-weight': 600, + 'radio-checked-color': white, + 'radio-checked-background-image': + url('../../public/assets/img/month-train-select.png'), + 'radio-label-padding-left': 0, +); +/* stylelint-disable no-descending-specificity */ +@include b(screen-radio-list) { + @include set-component-css-var(screen-radio-list, $screen-radio-list); + @include e(text) { + font-size: getCssVar(form-item, font-size); + color: getCssVar(form-item, text-color); + } + + .el-radio__input { + display: getCssVar(screen-radio-list, radio-input-display); + } + + .el-radio { + width: max-content; + padding: getCssVar(screen-radio-list, radio-padding); + color: getCssVar(screen-radio-list, radio-color); + text-align: center; + background-image: getCssVar(screen-radio-list, radio-background-image); + background-repeat: getCssVar(screen-radio-list, radio-background-repeat); + background-size: getCssVar(screen-radio-list, radio-background-size); + + &.is-checked { + font-weight: getCssVar(screen-radio-list, radio-checked-font-weight); + color: getCssVar(screen-radio-list, radio-checked-color); + background-image: getCssVar( + screen-radio-list, + radio-checked-background-image + ); + } + + .el-radio__label { + padding-left: getCssVar(screen-radio-list, radio-label-padding-left); + } + } + + @include m(readonly) { + font-size: getCssVar(form-item, font-size); + line-height: getCssVar(editor, default, line-height); + color: getCssVar(form-item, readonly-color); + } + + @include e(button) { + @include m(round-corner) { + margin-right: getCssVar(spacing, base-loose); + + &.el-radio-button.is-active { + .el-radio-button__inner { + color: getCssVar(color, primary); + background-color: getCssVar(color, secondary, light, default); + border-color: getCssVar(color, secondary, light, default); + } + + .el-radio-button__original-radio:checked + .el-radio-button__inner { + box-shadow: none; + } + } + + &.el-radio-button .el-radio-button__inner { + padding: getCssVar('spacing', 'tight') getCssVar('spacing', 'base'); + background-color: getCssVar(color, tertiary, light, hover); + border-color: getCssVar(color, tertiary, light, hover); + border-radius: getCssVar(height-control, default); + + &:nth-last-child(1) { + margin: 0; + } + } + + &.el-radio-button.is-disabled { + &.is-active .el-radio-button__inner { + border: getCssVar('border-thickness', 'control') solid + getCssVar(color, disabled, text); + } + + .el-radio-button__inner { + color: getCssVar(color, disabled, text); + background: getCssVar(color, disabled, bg); + border-color: getCssVar(color, disabled, border); + } + } + } + } + + @include when(grid-layout) { + .el-radio-group { + display: grid; + grid-template-columns: repeat( + getCssVar(screen-radio-list, group-row-number), + 1fr + ); + } + } +} + +@include b(form-item) { + @include b(screen-radio-list) { + @include when(show-default) { + padding: getCssVar(form-item, hover-edit-padding); + } + } +} diff --git a/src/screen-radio-list/screen-radio-list.tsx b/src/screen-radio-list/screen-radio-list.tsx new file mode 100644 index 0000000..2bdd85f --- /dev/null +++ b/src/screen-radio-list/screen-radio-list.tsx @@ -0,0 +1,211 @@ +import { + computed, + defineComponent, + onBeforeMount, + onMounted, + ref, + watch, +} from 'vue'; +import { + getEditorEmits, + getRadioProps, + useFocusAndBlur, + useNamespace, + useCodeListListen, + useAutoFocusBlur, +} from '@ibiz-template/vue3-util'; +import './screen-radio-list.scss'; +import { notNilEmpty } from 'qx-util'; +import { CodeListItem } from '@ibiz-template/runtime'; +import { ScreenRadioListEditorController } from './screen-radio-list.controller'; + +export const ScreenRadioList = defineComponent({ + name: 'ScreenRadioList', + props: getRadioProps(), + emits: getEditorEmits(), + setup(props, { emit }) { + const ns = useNamespace('screen-radio-list'); + + const c = props.controller; + + const editorModel = c.model; + + let timer: NodeJS.Timeout | null = null; + + // 绘制模式 + let renderMode = 'radio'; + // 按钮圆角显示 + let isBtnRoundCorner = false; + if (editorModel.editorParams) { + if (editorModel.editorParams.renderMode) { + renderMode = editorModel.editorParams.renderMode; + } + if (editorModel.editorParams.isBtnRoundCorner) { + isBtnRoundCorner = c.toBoolean( + editorModel.editorParams.isBtnRoundCorner, + ); + } + } + + const { useInFocusAndBlur, useInValueChange } = useAutoFocusBlur( + props, + emit, + ); + + const onSelectValueChange = (value: string | number) => { + emit('change', value); + useInValueChange(); + }; + + // 代码表 + const items = ref([]); + + const loopselect = () => { + const index = items.value.findIndex((item: IData) => { + return item.value === props.value; + }); + if (items.value && items.value.length > 0) { + if (index < items.value.length - 1) { + emit('change', items.value[index + 1].value); + } else { + emit('change', items.value[0].value); + } + } + }; + + onMounted(() => { + timer = setInterval(() => { + loopselect(); + }, 3000); + }); + + onBeforeMount(() => { + if (timer) { + clearInterval(timer); + } + }); + + watch( + () => props.data, + newVal => { + c.loadCodeList(newVal).then(_codeList => { + items.value = _codeList; + }); + }, + { + immediate: true, + deep: true, + }, + ); + + const fn = (data: CodeListItem[] | undefined) => { + if (data) { + items.value = data; + } + }; + + useCodeListListen(c.model.appCodeListId, c.context.srfappid, fn); + + const valueText = computed(() => { + // eslint-disable-next-line eqeqeq + return items.value.find(item => item.value == props.value)?.text || ''; + }); + + // 是否显示表单默认内容 + const showFormDefaultContent = computed(() => { + if ( + props.controlParams && + props.controlParams.editmode === 'hover' && + !props.readonly + ) { + return true; + } + return false; + }); + + watch( + valueText, + (newVal, oldVal) => { + if (newVal !== oldVal) { + emit('infoTextChange', newVal); + } + }, + { immediate: true }, + ); + + // 聚焦失焦事件 + const { componentRef: editorRef } = useFocusAndBlur( + () => emit('focus'), + () => useInFocusAndBlur(), + ); + + return { + timer, + ns, + editorModel, + items, + valueText, + onSelectValueChange, + editorRef, + renderMode, + isBtnRoundCorner, + showFormDefaultContent, + }; + }, + render() { + return ( +
+ {this.readonly ? ( + this.valueText + ) : ( + + {this.items.map((_item, index: number) => + this.renderMode === 'radio' ? ( + + {_item.text} + + ) : ( + + {_item.text} + + ), + )} + + )} +
+ ); + }, +}); -- Gitee