feat: update mobile first template (#1697)

This commit is contained in:
ajaxzheng 2024-06-26 11:08:46 +08:00 committed by GitHub
parent 5e02624fd9
commit 640c1a2aab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
848 changed files with 27230 additions and 3009 deletions

View File

@ -25,6 +25,7 @@ module.exports = {
'vue/no-unused-refs': 'off', 'vue/no-unused-refs': 'off',
'vue/require-component-is': 'off', 'vue/require-component-is': 'off',
'vue/singleline-html-element-content-newline': 'off', 'vue/singleline-html-element-content-newline': 'off',
'vue/no-v-for-template-key-on-child': 'off',
'curly': 'off', 'curly': 'off',
'sort-imports': 'off', 'sort-imports': 'off',
'prefer-template': 'off', 'prefer-template': 'off',
@ -48,6 +49,7 @@ module.exports = {
'@typescript-eslint/restrict-plus-operands': 'off', '@typescript-eslint/restrict-plus-operands': 'off',
'@typescript-eslint/no-use-before-define': 'off', '@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/restrict-template-expressions': 'off', '@typescript-eslint/restrict-template-expressions': 'off',
'@typescript-eslint/no-invalid-this': 'off' '@typescript-eslint/no-invalid-this': 'off',
'vue/no-deprecated-dollar-scopedslots-api': 'off'
} }
} }

View File

@ -185,6 +185,7 @@ interface IButtonGroupData {
text: string // 显示文本 text: string // 显示文本
value: number | number // 选中的值 value: number | number // 选中的值
disabled?: boolean // 是否禁用 disabled?: boolean // 是否禁用
tip?: string // 按钮悬浮提示 v3.17.0版本增加此功能
// 配置选块角标 // 配置选块角标
sup?: { sup?: {
text: string // 角标文本 text: string // 角标文本

View File

@ -7,7 +7,7 @@ export default {
props: [ props: [
{ {
name: 'auto-width', name: 'auto-width',
type: 'Boolean', type: 'boolean',
defaultValue: '', defaultValue: '',
desc: { desc: {
'zh-CN': '卡片的宽度是否自动撑开,设置后将不再给卡片设置固定宽度', 'zh-CN': '卡片的宽度是否自动撑开,设置后将不再给卡片设置固定宽度',
@ -20,7 +20,7 @@ export default {
}, },
{ {
name: 'check-type', name: 'check-type',
type: 'String', type: 'string',
defaultValue: '', defaultValue: '',
desc: { desc: {
'zh-CN': '设置卡片单选、多选,单选/radio多选/checkbox需同时设置 label。', 'zh-CN': '设置卡片单选、多选,单选/radio多选/checkbox需同时设置 label。',
@ -33,7 +33,7 @@ export default {
}, },
{ {
name: 'custom-class', name: 'custom-class',
type: 'String', type: 'string',
defaultValue: '', defaultValue: '',
desc: { desc: {
'zh-CN': '卡片的class', 'zh-CN': '卡片的class',
@ -45,8 +45,8 @@ export default {
}, },
{ {
name: 'disabled', name: 'disabled',
type: 'Boolean', type: 'boolean',
defaultValue: '', defaultValue: 'false',
desc: { desc: {
'zh-CN': '卡片禁用', 'zh-CN': '卡片禁用',
'en-US': 'Card disabled' 'en-US': 'Card disabled'
@ -57,7 +57,7 @@ export default {
}, },
{ {
name: 'height', name: 'height',
type: 'String', type: 'string',
defaultValue: '', defaultValue: '',
desc: { desc: {
'zh-CN': '卡片内容区域的高度', 'zh-CN': '卡片内容区域的高度',
@ -69,7 +69,7 @@ export default {
}, },
{ {
name: 'icon-more', name: 'icon-more',
type: 'Object', type: "'iconxxx' | Component",
defaultValue: '', defaultValue: '',
desc: { desc: {
'zh-CN': '更多按钮图标可传入一个svg图标对象进行替换', 'zh-CN': '更多按钮图标可传入一个svg图标对象进行替换',
@ -81,7 +81,7 @@ export default {
}, },
{ {
name: 'label', name: 'label',
type: 'String / Number', type: 'string / number',
defaultValue: '', defaultValue: '',
desc: { desc: {
'zh-CN': 'checkbox或radio的label', 'zh-CN': 'checkbox或radio的label',
@ -93,7 +93,8 @@ export default {
}, },
{ {
name: 'options', name: 'options',
type: 'Array', typeAnchorName: 'IOptions',
type: 'IOptions',
defaultValue: '', defaultValue: '',
desc: { desc: {
'zh-CN': '操作按钮配置', 'zh-CN': '操作按钮配置',
@ -105,8 +106,8 @@ export default {
}, },
{ {
name: 'size', name: 'size',
type: 'String', type: 'string',
defaultValue: '', defaultValue: 'medium',
desc: { desc: {
'zh-CN': '尺寸支持large、medium、small、mini 4个尺寸默认值为medium', 'zh-CN': '尺寸支持large、medium、small、mini 4个尺寸默认值为medium',
'en-US': 'Size. The options are large, medium, small, and mini. The default value is medium.' 'en-US': 'Size. The options are large, medium, small, and mini. The default value is medium.'
@ -117,7 +118,7 @@ export default {
}, },
{ {
name: 'src', name: 'src',
type: 'String', type: 'string',
defaultValue: '', defaultValue: '',
desc: { desc: {
'zh-CN': '图片或者视频的地址', 'zh-CN': '图片或者视频的地址',
@ -129,8 +130,8 @@ export default {
}, },
{ {
name: 'status', name: 'status',
type: 'String', type: 'string',
defaultValue: '', defaultValue: 'default',
desc: { desc: {
'zh-CN': '卡片状态,支持 success、warning、alerting、danger 4 种状态', 'zh-CN': '卡片状态,支持 success、warning、alerting、danger 4 种状态',
'en-US': 'Card status. The value can be success, warning, alerting, or dangerous.' 'en-US': 'Card status. The value can be success, warning, alerting, or dangerous.'
@ -141,7 +142,7 @@ export default {
}, },
{ {
name: 'title', name: 'title',
type: 'String', type: 'string',
defaultValue: '', defaultValue: '',
desc: { desc: {
'zh-CN': '卡片的标题', 'zh-CN': '卡片的标题',
@ -153,10 +154,10 @@ export default {
}, },
{ {
name: 'type', name: 'type',
type: 'String', type: 'string',
defaultValue: '', defaultValue: 'text',
desc: { desc: {
'zh-CN': '设置卡片类型,支持 text、image、video、logo 4 种类型', 'zh-CN': '设置卡片类型,支持 text、image、video、logo 4 种类型',
'en-US': 'Set the card type. The options are text, image, video, and logo.' 'en-US': 'Set the card type. The options are text, image, video, and logo.'
}, },
mode: ['pc', 'mobile-first'], mode: ['pc', 'mobile-first'],
@ -165,7 +166,7 @@ export default {
}, },
{ {
name: 'v-model', name: 'v-model',
type: 'String', type: 'string',
defaultValue: '', defaultValue: '',
desc: { desc: {
'zh-CN': '绑定值,默认为空', 'zh-CN': '绑定值,默认为空',
@ -174,12 +175,24 @@ export default {
mode: ['pc', 'mobile-first'], mode: ['pc', 'mobile-first'],
pcDemo: 'check-type-checkbox', pcDemo: 'check-type-checkbox',
mfDemo: '' mfDemo: ''
},
{
name: 'check-mode',
type: 'string',
defaultValue: 'normal',
desc: {
'zh-CN': '卡片被选中后的呈现模式可选值为normal | simple | badge',
'en-US': 'Display mode of a selected card. The options are as follows: normal | simple | badge'
},
mode: ['pc', 'mobile-first'],
pcDemo: 'check-mode',
mfDemo: ''
} }
], ],
events: [ events: [
{ {
name: 'change', name: 'change',
type: 'Function()', type: '() => {}',
defaultValue: '', defaultValue: '',
desc: { desc: {
'zh-CN': '组件选中/取消选中事件', 'zh-CN': '组件选中/取消选中事件',
@ -191,7 +204,7 @@ export default {
}, },
{ {
name: 'icon-click', name: 'icon-click',
type: 'Function()', type: '() => {}',
defaultValue: '', defaultValue: '',
desc: { desc: {
'zh-CN': '操作栏按钮点击事件', 'zh-CN': '操作栏按钮点击事件',
@ -203,7 +216,7 @@ export default {
}, },
{ {
name: 'click', name: 'click',
type: 'Function()', type: '() => {}',
defaultValue: '', defaultValue: '',
desc: { desc: {
'zh-CN': '点击卡片事件', 'zh-CN': '点击卡片事件',
@ -278,5 +291,33 @@ export default {
} }
] ]
} }
],
types: [
{
name: 'IOptions',
type: 'interface',
code: `
interface IOptions [
{
text: '删除列表',
icon: IconDel()
},
{
text: '编辑',
icon: IconWriting(),
disabled: true
},
{
text: '排序',
icon: IconAscending()
},
{
text: '分享',
icon: IconShare(),
disabled: true
}
]
`
}
] ]
} }

View File

@ -146,6 +146,44 @@ export default {
mode: ['pc', 'mobile-first'], mode: ['pc', 'mobile-first'],
pcDemo: 'card-mode', pcDemo: 'card-mode',
mfDemo: '' mfDemo: ''
},
{
name: 'swipeable',
type: 'boolean',
defaultValue: 'false',
desc: {
'zh-CN': '是否支持触屏轮播',
'en-US': 'Support Touchscreen Carousel'
},
mode: ['mobile-first'],
pcDemo: '',
mfDemo: ''
},
{
name: 'lite',
type: 'boolean',
defaultValue: 'false',
desc: {
'zh-CN': '是否打开精简模式,不显示切换按钮和指示器',
'en-US':
'Indicates whether to enable the simplified mode. The switch button and indicator are not displayed.'
},
mode: ['pc', 'mobile-first'],
pcDemo: 'swipeable',
mfDemo: ''
},
{
name: 'beforeSwipe',
type: '(newIndex,oldIndex) => boolean',
defaultValue: '',
desc: {
'zh-CN': '触摸轮播前,通过返回值控制某个图是否可轮播显示',
'en-US':
'Controls whether a graph can be displayed in rotation based on the return value before the rotation is touched.'
},
mode: ['pc', 'mobile-first'],
pcDemo: 'swipeable',
mfDemo: ''
} }
], ],
events: [ events: [

View File

@ -142,6 +142,17 @@ export default {
}, },
mode: ['pc'], mode: ['pc'],
pcDemo: 'title' pcDemo: 'title'
},
{
name: 'expand-icon',
type: 'Component',
defaultValue: '',
desc: {
'zh-CN': '自定义icon 图标',
'en-US': 'Customized icon'
},
mode: ['pc'],
pcDemo: 'icon'
} }
], ],
events: [], events: [],

View File

@ -10,8 +10,8 @@ export default {
type: 'boolean', type: 'boolean',
defaultValue: '该属性的默认值为 true', defaultValue: '该属性的默认值为 true',
desc: { desc: {
'zh-CN': '是否显示清除按钮;是否可清空', 'zh-CN': '是否显示清除按钮',
'en-US': 'Whether to display the Clear button; Clearable' 'en-US': 'Whether to display the Clear button'
}, },
mode: ['pc', 'mobile-first'], mode: ['pc', 'mobile-first'],
pcDemo: 'custom-service', pcDemo: 'custom-service',
@ -19,7 +19,7 @@ export default {
}, },
{ {
name: 'disabled', name: 'disabled',
type: 'Boolen', type: 'boolean',
defaultValue: '该属性的默认值为 false', defaultValue: '该属性的默认值为 false',
desc: { desc: {
'zh-CN': '禁用', 'zh-CN': '禁用',
@ -116,14 +116,88 @@ export default {
mfDemo: '' mfDemo: ''
}, },
{ {
name: 'v-model', name: 'set-default',
type: 'String / Number', type: 'boolean',
defaultValue: 'false',
desc: {
'zh-CN': '是否开启设置默认币种,默认值为 false',
'en-US':
'Indicates whether to enable the function of setting the default currency. The default value is false.'
},
mode: ['pc', 'mobile-first'],
pcDemo: 'set-default',
mfDemo: ''
},
{
name: 'set-default-currency',
type: 'function',
defaultValue: '', defaultValue: '',
desc: { desc: {
'zh-CN': '设置下拉框的值', 'zh-CN': '设置默认币种的自定义方法',
'en-US': '' 'en-US': 'Custom Method for Setting Default Currency'
}, },
mode: ['mobile-first'], mode: ['pc', 'mobile-first'],
pcDemo: 'set-default-custom-service',
mfDemo: ''
},
{
name: 'fetch-default-currency',
type: 'function',
defaultValue: '',
desc: {
'zh-CN': '设置默认币种的服务',
'en-US': 'Services that set the default currency'
},
mode: ['pc', 'mobile-first'],
pcDemo: 'set-default-custom-service',
mfDemo: ''
},
{
name: 'label',
type: 'string',
defaultValue: '',
desc: {
'zh-CN': `显示标题,设置 shape='filter' 属性切换至过滤器模式时有效,可参考 FilterBox 组件属性`,
'en-US': `Display title. This parameter is valid when shape='filter' is set to switch to the filter mode. For details, see the attributes of the FilterBox component.`
},
mode: ['pc', 'mobile-first'],
pcDemo: 'filter',
mfDemo: ''
},
{
name: 'drop-style',
type: 'object',
defaultValue: '{}',
desc: {
'zh-CN': '自定义下拉选项样式',
'en-US': 'Custom drop-down options style'
},
mode: ['pc', 'mobile-first'],
pcDemo: 'filter',
mfDemo: ''
},
{
name: 'shape',
type: 'string',
defaultValue: '',
desc: {
'zh-CN': `通过 shape='filter' 属性切换至过滤器模式`,
'en-US': `Switch to the filter mode by using the shape='filter' attribute.`
},
mode: ['pc', 'mobile-first'],
pcDemo: 'filter',
mfDemo: ''
},
{
name: 'tip',
type: 'string',
defaultValue: '',
desc: {
'zh-CN': `显示提示信息,设置 shape='filter' 属性切换至过滤器模式时有效,可参考 FilterBox 组件属性`,
'en-US': `Displays a message. This parameter is valid when shape='filter' is set to switch to the filter mode. For details, see the attributes of the FilterBox component.`
},
mode: ['pc', 'mobile-first'],
pcDemo: 'filter',
mfDemo: '' mfDemo: ''
} }
], ],
@ -131,13 +205,19 @@ export default {
{ {
name: 'change', name: 'change',
type: '', type: '',
defaultValue: '', defaultValue: '(arg1,arg2) => void',
desc: { desc: {
'zh-CN': 'zh-CN': `
'arg1:{Any|Array 单选并且未指定渲染类型时是选中项的值字段此时没有arg2参数多选并且未指定渲染类型时是选中项值字段组成的数组此时没有arg2参数单选并且渲染类型为树或者表格时是选中项对象此时没有arg2参数多选并且渲染类型为树或者表格时是选中项对象值字段组成的数组此时有arg2参数}arg2:{Array 多选并且渲染类型为树或者表格时,是选中项对象组成的数组}', arg1:{Any|Array 单选并且未指定渲染类型时是选中项的值字段此时没有arg2参数多选并且未指定渲染类型时是选中项值字段组成的数组此时没有arg2参数单选并且渲染类型为树或者表格时是选中项对象此时没有arg2参数多选并且渲染类型为树或者表格时是选中项对象值字段组成的数组此时有arg2参数}<br>
'en-US': '' arg2:{Array 多选并且渲染类型为树或者表格时是选中项对象组成的数组}
`,
'en-US': `
When arg1:{Any|Array is selected and the rendering type is not specified, this is the value field of the selected item. In this case, the arg2 parameter is not provided. If multiple options are selected and the rendering type is not specified, the value field of the selected items is an array. In this case, the arg2 parameter is not provided. If you select a single item and the rendering type is tree or table, the object is selected. In this case, the arg2 parameter is not provided. When multiple selections are selected and the rendering type is tree or table, the array is composed of the selected object value fields. In this case, the arg2 parameter is available.},<br>
arg2:{An array consisting of selected items when multiple Arrays are selected and the rendering type is tree or table}
`
}, },
mode: ['mobile-first'], mode: ['pc', 'mobile-first'],
pcDemo: '',
mfDemo: '' mfDemo: ''
} }
], ],

View File

@ -182,28 +182,16 @@ export default {
} }
], ],
events: [ events: [
{
name: 'open',
type: '() => void',
defaultValue: '',
desc: {
'zh-CN': '打开抽屉事件',
'en-US': ''
},
mode: ['pc', 'mobile-first'],
pcDemo: 'open-event',
mfDemo: ''
},
{ {
name: 'close', name: 'close',
type: '() => void', type: '(force: boolean) => void',
defaultValue: '', defaultValue: '',
desc: { desc: {
'zh-CN': '关闭抽屉事件', 'zh-CN': '关闭抽屉事件,参数 force 指定是否强制关闭',
'en-US': 'Close drawer event' 'en-US': 'Close drawer event, and parameter force decides force close'
}, },
mode: ['pc', 'mobile-first'], mode: ['pc', 'mobile-first'],
pcDemo: 'close-event', pcDemo: 'events',
mfDemo: '' mfDemo: ''
}, },
{ {
@ -215,7 +203,19 @@ export default {
'en-US': 'Confirm event. This event is emit only when show-footer="true" is set' 'en-US': 'Confirm event. This event is emit only when show-footer="true" is set'
}, },
mode: ['pc', 'mobile-first'], mode: ['pc', 'mobile-first'],
pcDemo: 'confirm-event', pcDemo: 'events',
mfDemo: ''
},
{
name: 'show',
type: '(instance: Component) => void',
defaultValue: '',
desc: {
'zh-CN': '抽屉显示事件',
'en-US': ''
},
mode: ['pc'],
pcDemo: 'events',
mfDemo: '' mfDemo: ''
}, },
{ {
@ -252,6 +252,18 @@ export default {
}, },
mode: ['mobile-first'], mode: ['mobile-first'],
mfDemo: '' mfDemo: ''
},
{
name: 'service',
type: '(configs: IDrawerConfigs) => Component',
typeAnchorName: 'IDrawerConfigs',
defaultValue: '',
desc: {
'zh-CN': '配置并打开抽屉',
'en-US': ''
},
mode: ['pc'],
pcDemo: 'use-through-method'
} }
], ],
slots: [ slots: [
@ -297,5 +309,28 @@ export default {
} }
] ]
} }
],
types: [
{
name: 'IDrawerConfigs',
type: 'interface',
code: `
interface IDrawerConfigs extends IDrawerProps {
// 方法调用的配置参数
events: {
// 监听事件
close: () => void
confirm: () => void
show: (instance: Component) => void
},
customSlots: {
// 插槽
default: string | VNode | (h) => VNode,
header: string | VNode | (h) => VNode,
headerRight: string | VNode | (h) => VNode,
footer: string | VNode | (h) => VNode
}
`
}
] ]
} }

View File

@ -143,6 +143,30 @@ export default {
pcDemo: 'grid-context-menu#context-menu-footer-menu', pcDemo: 'grid-context-menu#context-menu-footer-menu',
mfDemo: '' mfDemo: ''
}, },
{
name: 'custom-column-names',
type: 'string[]',
defaultValue: "['TinyGridColumn']",
metaData: {
experimental: {
version: '3.17.0'
}
},
versionTipOption: {
extendTip: {
'zh-CN': '该属性于3.17版本新增,封装 grid-column 时需要配置此字段,提供给表格收集配置',
'en-US':
'This field needs to be configured when encapsulating grid-column and is provided for table collection configuration'
}
},
desc: {
'zh-CN': '封装 grid-column 时需要配置此字段,提供给表格收集配置',
'en-US':
'This field needs to be configured when encapsulating grid-column and is provided for table collection configuration'
},
mode: ['pc'],
pcDemo: 'grid-faq#custom-column'
},
{ {
name: 'data', name: 'data',
typeAnchorName: 'IRow', typeAnchorName: 'IRow',
@ -1436,6 +1460,28 @@ export default {
pcDemo: 'grid-event#event-toggle-expand-change-event', pcDemo: 'grid-event#event-toggle-expand-change-event',
mfDemo: '' mfDemo: ''
}, },
{
name: 'toggle-group-change',
typeAnchorName: 'IToggleGroupChangeArgs',
type: '(row: IRow)=> void',
defaultValue: '',
metaData: {
experimental: '3.17.0'
},
versionTipOption: {
extendTip: {
'zh-CN': '该特性于3.17版本新增',
'en-US': 'This feature was added in version 3.17'
}
},
desc: {
'zh-CN': '当分组的展开和收起时会触发该事件',
'en-US': 'This event is triggered when the group is expanded and collapsed.'
},
mode: ['pc', 'mobile-first'],
pcDemo: 'grid-row-grouping#row-grouping-row-group-render',
mfDemo: ''
},
{ {
name: 'toggle-tree-change', name: 'toggle-tree-change',
typeAnchorName: 'IToggleTreeChangeArgs', typeAnchorName: 'IToggleTreeChangeArgs',
@ -4016,8 +4062,16 @@ interface IDataHandler {
type: 'type', type: 'type',
code: ` code: `
interface IRowGroup { interface IRowGroup {
// 自定义渲染内容
render: () => Vnode
// 列标识符,行分组会将具有相同值的列进行分组展示 // 列标识符,行分组会将具有相同值的列进行分组展示
field: string field: string
// 3.17版本新增,配置分组行的列合并数量
colspan: number
// 3.17版本新增,控制分组行是否可以手动折叠
closeable: boolean
// 3.17版本新增,控制分组生成时是否默认收起
activeMethod: (row: IRow) => boolean
} }
` `
}, },

View File

@ -528,6 +528,20 @@ export default {
}, },
mode: ['mobile'], mode: ['mobile'],
mobileDemo: '' mobileDemo: ''
},
{
name: 'popup-more',
type: 'Boolean',
defaultValue: '',
desc: {
'zh-CN':
'在只读的基础上增加 <code>popup-more</code> 属性,可使文本域超出显示更多按钮,点击更多按钮可以查看详细信息。',
'en-US':
'The <code>popup-more</code> attribute is added to enable the text field to exceed the display of more buttons. You can click more buttons to view details.'
},
mode: ['pc', 'mobile-first'],
pcDemo: 'display-only-popup-more',
mfDemo: 'display-only-popup-more'
} }
], ],
events: [ events: [

View File

@ -376,6 +376,8 @@ interface IPopperOption {
removeOnDestroy: boolean // 弹出层消失后是否移除弹出层的DOM元素布尔false removeOnDestroy: boolean // 弹出层消失后是否移除弹出层的DOM元素布尔false
updateHiddenPopperOnScroll: boolean // 滚动过程中是否更新隐藏的弹出层位置 updateHiddenPopperOnScroll: boolean // 滚动过程中是否更新隐藏的弹出层位置
boundariesElement: 'viewport' | 'body' | HTMLElement // 滚动过程中,弹出层的碰撞边界。 默认值为: 'viewport' boundariesElement: 'viewport' | 'body' | HTMLElement // 滚动过程中,弹出层的碰撞边界。 默认值为: 'viewport'
ignoreBoundaries: boolean // 忽略边界判断,弹出的位置始终是设置的 placement 值
scrollParent: HTMLElement // 指定滚动的父节点,优化级最高。 默认为null
} }
` `
}, },

View File

@ -18,6 +18,19 @@ export default {
pcDemo: 'all-text', pcDemo: 'all-text',
mfDemo: 'all-text' mfDemo: 'all-text'
}, },
{
name: 'show-all-text-tag',
type: 'boolean',
defaultValue: 'false',
desc: {
'zh-CN':
'指定多选模式全选后,在输入框中,是否只显示 all-text 指定的Tag。 默认值为 <code>false</code>,所有选项循环显示在输入框。',
'en-US':
'Specifies whether only the tag specified by all-text is displayed in the text box after the multi-select mode is specified. The default value is <code>false</code>. All options are displayed in the text box cyclically.'
},
mode: ['pc'],
pcDemo: 'all-text'
},
{ {
name: 'allow-copy', name: 'allow-copy',
type: 'boolean', type: 'boolean',
@ -625,12 +638,25 @@ export default {
defaultValue: 'false', defaultValue: 'false',
desc: { desc: {
'zh-CN': 'zh-CN':
'是否展示多选框开启多选限制选择数量时,选中条数和限制总条数的占比的文字提示。 该属性的优先级大于<code>show-proportion</code> 属性,同时设置只', '是否展示多选框开启多选限制选择数量时,选中条数和限制总条数的占比的文字提示。 该属性的优先级大于<code>show-proportion</code> 属性',
'en-US': 'en-US':
'Display the proportion of the number of selected items and the total number of items in the multiple-choice box' 'Display the proportion of the number of selected items and the total number of items in the multiple-choice box'
}, },
mode: ['pc'], mode: ['pc'],
pcDemo: 'multiple' pcDemo: 'multiple'
},
{
name: 'init-label',
type: 'string',
defaultValue: '',
desc: {
'zh-CN':
'通过 <code>init-label</code> 属性设置远程搜索或者嵌套树懒加载数据未获取到时显示的初始化 <code>label </code>值。',
'en-US':
'Use the <code>init-label</code> attribute to set the initial <code>label </code> value displayed when remote search or nested sloth loading data is not obtained.'
},
mode: ['pc'],
pcDemo: 'init-label'
} }
], ],
events: [ events: [

View File

@ -87,7 +87,28 @@ export default {
pcDemo: 'split-threshold' pcDemo: 'split-threshold'
}, },
{ {
mode: [] name: 'border',
type: 'boolean',
defaultValue: 'true',
desc: {
'zh-CN': '是否显示边框',
'en-US': 'Indicates whether to display the border.'
},
mode: ['pc'],
pcDemo: ''
},
{
name: 'right-bottom-value',
type: 'boolean',
defaultValue: 'false',
desc: {
'zh-CN':
'默认情况下v-model的值为左/上面板的位置。 当设置right-bottom-value 为true时指明 v-model的值为 右/下面板的位置。 ',
'en-US':
'By default, the value of v-model is the position of the left/top panel. When right-bottom-value is set to true, the value of v-model is the position of the right/lower panel.'
},
mode: ['pc'],
pcDemo: ''
} }
], ],
events: [ events: [

View File

@ -146,8 +146,9 @@ export default {
type: 'boolean', type: 'boolean',
defaultValue: 'false', defaultValue: 'false',
desc: { desc: {
'zh-CN': '是否显示底部分割线,适用于横向时间线', 'zh-CN': '是否显示底部指标三角,适用于横向时间线',
'en-US': 'Whether to display the bottom separator line of horizontal timeline' 'en-US':
'Indicates whether to display the bottom indicator triangle, which is applicable to the horizontal timeline.'
}, },
mode: ['pc'], mode: ['pc'],
pcDemo: 'show-divider' pcDemo: 'show-divider'

View File

@ -321,6 +321,8 @@ interface IPopperOption {
removeOnDestroy: boolean // 弹出层消失后是否移除弹出层的DOM元素布尔false removeOnDestroy: boolean // 弹出层消失后是否移除弹出层的DOM元素布尔false
updateHiddenPopperOnScroll: boolean // 滚动过程中是否更新隐藏的弹出层位置 updateHiddenPopperOnScroll: boolean // 滚动过程中是否更新隐藏的弹出层位置
boundariesElement: 'viewport' | 'body' | HTMLElement // 滚动过程中,弹出层的碰撞边界。 默认值为: 'viewport' boundariesElement: 'viewport' | 'body' | HTMLElement // 滚动过程中,弹出层的碰撞边界。 默认值为: 'viewport'
ignoreBoundaries: boolean // 忽略边界判断,弹出的位置始终是设置的 placement 值
scrollParent: HTMLElement // 指定滚动的父节点,优化级最高。 默认为null
} }
` `
}, },

View File

@ -478,6 +478,19 @@ export default {
}, },
mode: ['pc'], mode: ['pc'],
pcDemo: 'filter-view' pcDemo: 'filter-view'
},
{
name: 'edit-config',
typeAnchorName: 'ITreeEditConfig',
type: 'ITreeEditConfig',
defaultValue: '{}',
desc: {
'zh-CN': '用于编辑模式下参数配置,指示新增节点的 id ,是否显示 id 重复的警告等',
'en-US':
'Used for parameter configuration in editing mode, indicating the ID of a new node and whether to display a warning indicating duplicate IDs.'
},
mode: ['pc'],
pcDemo: 'edit'
} }
], ],
events: [ events: [
@ -1193,5 +1206,19 @@ export default {
} }
] ]
} }
],
types: [
{
name: 'ITreeEditConfig',
type: 'type',
code: `
interface ITreeEditConfig{
// 生成新节点的id
initNodeIdMethod: (node) => string;
// 新节点id与其它id重复时是否在控制台显示告警。
noWarning: boolean;
}
`
}
] ]
} }

View File

@ -0,0 +1,25 @@
<template>
<div>
<p>默认可清除</p>
<tiny-date-picker v-model="value1"></tiny-date-picker>
<br />
<p>不可清除</p>
<tiny-date-picker v-model="value2" :clearable="false"></tiny-date-picker>
</div>
</template>
<script>
import { DatePicker } from '@opentiny/vue'
export default {
components: {
TinyDatePicker: DatePicker
},
data() {
return {
value1: new Date(),
value2: new Date()
}
}
}
</script>

View File

@ -0,0 +1,20 @@
<template>
<div style="width: 270px">
<tiny-date-picker v-model="value" type="date" title="日期选择"></tiny-date-picker>
</div>
</template>
<script>
import { DatePicker } from '@opentiny/vue'
export default {
components: {
TinyDatePicker: DatePicker
},
data() {
return {
value: new Date()
}
}
}
</script>

View File

@ -0,0 +1,35 @@
<template>
<div>
<p>日期值{{ value }}</p>
<tiny-date-picker v-model="value" type="daterange" :picker-options="onPickOptions"></tiny-date-picker>
</div>
</template>
<script>
import { DatePicker, Modal } from '@opentiny/vue'
export default {
components: {
TinyDatePicker: DatePicker
},
data() {
return {
value: [new Date(2022, 10, 12), new Date(2022, 11, 25)],
onPickOptions: {
onPick: (val) => {
if (val.maxDate) {
Modal.message({
message: '当前获取的值 maxDate' + val.maxDate,
status: 'info'
})
Modal.message({
message: '当前获取的值 minDate' + val.minDate,
status: 'info'
})
}
}
}
}
}
}
</script>

View File

@ -0,0 +1,21 @@
<template>
<div style="width: 270px">
<p>{{ value }}</p>
<tiny-date-picker v-model="value" type="datetimerange"></tiny-date-picker>
</div>
</template>
<script>
import { DatePicker } from '@opentiny/vue'
export default {
components: {
TinyDatePicker: DatePicker
},
data() {
return {
value: ['2023-11-21T01:11:11.000Z', '2023-12-07T23:08:24.000Z']
}
}
}
</script>

View File

@ -0,0 +1,20 @@
<template>
<div style="width: 270px">
<tiny-date-picker v-model="value" type="datetime"></tiny-date-picker>
</div>
</template>
<script>
import { DatePicker } from '@opentiny/vue'
export default {
components: {
TinyDatePicker: DatePicker
},
data() {
return {
value: ''
}
}
}
</script>

View File

@ -0,0 +1,32 @@
<template>
<div>
<tiny-button @click="disabled = !disabled">改为{{ disabled ? '启用' : '禁用' }}</tiny-button>
<br /><br />
<tiny-date-picker v-model="value" :disabled="disabled"></tiny-date-picker>
<br /><br />
<tiny-button @click="displayOnly = !displayOnly">改为{{ displayOnly ? '可操作' : '仅显示' }}模式</tiny-button>
<br /><br />
<tiny-date-picker v-model="value" :display-only="displayOnly"></tiny-date-picker>
</div>
</template>
<script>
import { DatePicker, Button } from '@opentiny/vue'
export default {
components: {
TinyDatePicker: DatePicker,
TinyButton: Button
},
data() {
return {
value: new Date(),
disabled: false,
displayOnly: false
}
}
}
</script>

View File

@ -0,0 +1,32 @@
<template>
<div>
<p>日期组件</p>
<tiny-date-picker v-model="value1" type="date" placeholder="请选择日期 placeholder"></tiny-date-picker>
<br />
<p>日期范围选择组件</p>
<tiny-date-picker
v-model="value2"
type="daterange"
range-separator="至"
start-placeholder="开始日期 start"
end-placeholder="结束日期 end"
></tiny-date-picker>
</div>
</template>
<script>
import { DatePicker } from '@opentiny/vue'
export default {
components: {
TinyDatePicker: DatePicker
},
data() {
return {
value1: '',
value2: []
}
}
}
</script>

View File

@ -0,0 +1,25 @@
<template>
<div>
<p>日期值{{ value }}</p>
<tiny-date-picker :step="step" v-model="value" type="datetimerange"></tiny-date-picker>
</div>
</template>
<script>
import { DatePicker } from '@opentiny/vue'
export default {
components: {
TinyDatePicker: DatePicker
},
data() {
return {
step: {
hour: 2,
minute: 5
},
value: []
}
}
}
</script>

View File

@ -0,0 +1,9 @@
---
title: DatePicker 日期选择器组件
---
# DatePicker 日期选择器组件
<div>
</div>

View File

@ -0,0 +1,9 @@
---
title: DatePicker 日期选择器组件
---
# DatePicker 日期选择器组件
<div>
</div>

View File

@ -0,0 +1,120 @@
export default {
column: '2',
owner: '',
demos: [
{
demoId: 'basic-usage',
name: {
'zh-CN': '基本用法',
'en-US': 'basic usage'
},
desc: {
'zh-CN': '<p>设置 `type` 属性默认值为 `date`,以日期的形式进行选择。</p>',
'en-US': '<p>button type</p>'
},
codeFiles: ['basic-usage.vue']
},
{
demoId: 'datetime',
name: {
'zh-CN': '选择日期时间',
'en-US': 'events'
},
desc: {
'zh-CN': '<p>设置 `type` 属性为 `datetime`,以日期时间的形式进行选择。<p>',
'en-US': '<p>bbutton click</p>'
},
codeFiles: ['datetime.vue']
},
{
demoId: 'date-range',
name: {
'zh-CN': '选择日期范围',
'en-US': 'events'
},
desc: {
'zh-CN': '<p>设置 `type` 属性为 `daterange`,以日期范围的形式进行选择。<p>',
'en-US': '<p>bbutton click</p>'
},
codeFiles: ['date-range.vue']
},
{
demoId: 'datetime-range',
name: {
'zh-CN': '选择日期时间范围',
'en-US': 'events'
},
desc: {
'zh-CN': '<p>设置 `type` 属性为 `datetimerange`,以日期时间范围的形式进行选择。<p>',
'en-US': '<p>bbutton click</p>'
},
codeFiles: ['datetime-range.vue']
},
{
demoId: 'year',
name: {
'zh-CN': '年份选择',
'en-US': 'Year and month selector'
},
desc: {
'zh-CN':
'<p>设置 `type` 属性为 `year`,进行年份单选;设置 `type` 属性为 `years`,进行年份多选;设置 `type` 属性为 `yearrange`,进行年份范围选择。<p>',
'en-US': '<p>Set the `type` attribute to `year-month` to select a year-month selector.</p>'
},
codeFiles: ['year.vue']
},
{
demoId: 'placeholder',
name: {
'zh-CN': '占位符',
'en-US': 'Year Month Range Selector'
},
desc: {
'zh-CN':
'<p>单选可通过 `placeholder` 设置占位符。范围选择时,`start-placeholder` 和 `end-placeholder` 属性可分别指定开始日期和结束日期输入框的占位符。`range-separator` 属性指定开始日期和结束日期输入框之间的分隔符。<p>',
'en-US':
'<p>Single choice: You can use `placeholder` to set a placeholder. When a range is selected, the `start-placeholder` and `end-placeholder` attributes specify placeholders for the start and end date input boxes, respectively. The `range-separator` property specifies the separator between the start date and end date input boxes.<p>'
},
codeFiles: ['placeholder.vue']
},
{
demoId: 'disabled',
name: {
'zh-CN': '禁用',
'en-US': 'Disabled'
},
desc: {
'zh-CN': '<p>配置 `disabled` 属性设置时间选择器禁用。<p>',
'en-US': '<p>Configure the `disabled` property to disable the time selector.<p>'
},
codeFiles: ['disabled.vue']
},
{
demoId: 'step',
name: {
'zh-CN': '步长',
'en-US': 'Year Month Range Selector Limit Range'
},
desc: {
'zh-CN': '<p>通过 `step` 设置时间选择的步长,默认值为 `{ hour: 1, minute: 1, second: 1 }`。<p>',
'en-US':
'<p>Use `step` to set the time selection step. The default value is `{hour: 1, minute: 1, second: 1}`.<p>'
},
codeFiles: ['step.vue']
},
{
demoId: 'about-clear',
name: {
'zh-CN': '清除输入',
'en-US': 'Clear input'
},
desc: {
'zh-CN':
'<p>选择日期后,鼠标悬停在输入框时,默认会显示清除图标,单击图标可以清除输入框内容。设置 `clearable` 属性为 `false` 后,则不显示清除图标,不可清除。<p>',
'en-US':
'<p>After you select a date, the clear icon is displayed by default when you hover the cursor over the text box. You can click the icon to clear the text box. After the `clearable` attribute is set to `false`, the clear icon is not displayed and cannot be cleared.<p>'
},
codeFiles: ['about-clear.vue']
}
]
}

View File

@ -0,0 +1,63 @@
<template>
<tiny-layout>
<tiny-row>
<tiny-col :span="6">
<div class="w-96">
<span>年份单选</span>
<tiny-date-picker v-model="value1" type="year" placeholder="选择年份单选"></tiny-date-picker>
{{ value1 }}
</div>
</tiny-col>
<tiny-col :span="6">
<div class="w-96">
<span>年份多选</span>
<tiny-date-picker v-model="value2" type="years" placeholder="选择年份多选"></tiny-date-picker>
{{ value2 }}
</div>
</tiny-col>
</tiny-row>
<br />
<tiny-row>
<tiny-col :span="6">
<div class="w-96">
<span>年份范围选择</span>
<tiny-date-picker v-model="value3" type="yearrange" placeholder="选择年份范围"></tiny-date-picker>
{{ value3 }}
</div>
</tiny-col>
<tiny-col :span="6">
<div class="w-96">
年份禁用
<tiny-date-picker v-model="value4" type="year" :picker-options="pickerOptions"></tiny-date-picker>
{{ value4 }}
</div>
</tiny-col>
</tiny-row>
</tiny-layout>
</template>
<script>
import { Layout, Row, Col, DatePicker } from '@opentiny/vue'
export default {
components: {
TinyLayout: Layout,
TinyRow: Row,
TinyCol: Col,
TinyDatePicker: DatePicker
},
data() {
return {
value1: '',
value2: ['2021-01-01T16:00:00.000Z', '2000-01-01T16:00:00.000Z'],
value3: '',
value4: '',
pickerOptions: {
disabledDate(time) {
return time.getTime() > Date.now()
}
}
}
}
}
</script>

View File

@ -1,18 +1,44 @@
<template> <template>
<div class="demo-input"> <div class="demo-input">
<tiny-input type="textarea" v-model="input" placeholder="resize 为默认"></tiny-input> <p>resize</p>
<br /> <tiny-input type="textarea" v-model="input" placeholder="default"></tiny-input>
<br /> <tiny-input type="textarea" v-model="input" resize="none" placeholder="resize = none"></tiny-input>
<tiny-input type="textarea" v-model="input" resize="none" placeholder="resize 为 none"></tiny-input> <tiny-input type="textarea" v-model="input" resize="both" placeholder="resize = both"></tiny-input>
<br /> <tiny-input type="textarea" v-model="input" resize="horizontal" placeholder="resize = horizontal"></tiny-input>
<br /> <tiny-input type="textarea" v-model="input" resize="vertical" placeholder="resize = vertical"></tiny-input>
<tiny-input type="textarea" v-model="input" resize="both" placeholder="resize 为 both"></tiny-input>
<br /> <p>autosize</p>
<br /> <tiny-input
<tiny-input type="textarea" v-model="input" resize="horizontal" placeholder="resize 为 horizontal"></tiny-input> type="textarea"
<br /> v-model="textarea"
<br /> placeholder="autosize = { minRows: 2, maxRows: 3 }"
<tiny-input type="textarea" v-model="input" resize="vertical" placeholder="resize 为 vertical"></tiny-input> :autosize="{ minRows: 2, maxRows: 3 }"
></tiny-input>
<tiny-input type="textarea" v-model="textarea" placeholder="autosize" autosize></tiny-input>
<p>hover-expand</p>
<tiny-input
type="textarea"
v-model="hoverText"
placeholder="hover-expand autosize = { minRows: 6, maxRows: 10 }"
:autosize="{ minRows: 6, maxRows: 10 }"
hover-expand
></tiny-input>
<tiny-input
type="textarea"
v-model="hoverText"
placeholder="autosize hover-expand"
autosize
hover-expand
></tiny-input>
<tiny-input
type="textarea"
v-model="displayOnlyText"
placeholder="autosize hover-expand display-only"
autosize
hover-expand
display-only
></tiny-input>
</div> </div>
</template> </template>
@ -25,14 +51,19 @@ export default {
}, },
data() { data() {
return { return {
input: '' input: '',
textarea: '',
hoverText: '',
displayOnlyText: 'value 的内容'
} }
} }
} }
</script> </script>
<style scoped> <style lang="less" scoped>
.demo-input .tiny-textarea { .demo-input div[data-tag='tiny-input'] {
width: 400px; width: 200px;
margin: 5px;
display: inline-block;
} }
</style> </style>

View File

@ -133,8 +133,14 @@ export default {
}, },
desc: { desc: {
'zh-CN': 'zh-CN':
'<p>可通过 `resize` 属性设置文本域的缩放。可选值:`none / both / horizontal / vertical`。注意:只在 `type="textarea"` 时有效。<p>', '<p>可通过 <code>resize</code> 属性设置文本域的缩放。可选值:<code>none / both / horizontal / vertical</code>。注意:只在 <code>type="textarea"</code> 时有效。</p>\n ' +
'en-US': '<p>bbutton click</p>' '<p>可通过 <code>autosize</code> 属性设置文本域自适应内容高度。可传入对象,如<code>{ minRows: 2, maxRows: 6 }</code>。</p> \n<p></p>' +
'<p>可通过 <code>hover-expand</code> 属性设置文本域鼠标悬浮展开/收起,只对 <code>type=textarea</code> 有效,最好搭配 <code>autosize</code> 一起使用<p>',
'en-US':
'<p>You can use the <code>resize</code> property to set the scaling of the text field. The value can be <code>none / both / horizontal / vertical</code>. Note: This parameter is valid only when <code>type="textarea"</code>.</p>' +
'<p>The <code>autosize</code> property allows you to set the text field to adapt to the content height. You can transfer an object, for example, <code>{minRows: 2, maxRows: 6}</code>.</p>' +
'<p>You can use the <code>hover-expand</code> attribute to set the text field to be expanded or collapsed by hovering the mouse. This parameter is valid only for <code>type=textarea</code>. It is recommended that you use it together with <code>autosize</code></p>'
}, },
codeFiles: ['resize.vue'] codeFiles: ['resize.vue']
}, },

View File

@ -24,6 +24,9 @@ export default {
}, },
methods: { methods: {
beforeLeave() { beforeLeave() {
//
// return Promise.resolve(false)
// return Promise.reject()
return false return false
} }
} }

View File

@ -49,6 +49,7 @@ export const cmpMenus = [
key: 'cmp_form_components', key: 'cmp_form_components',
children: [ children: [
{ name: 'DatePickerMobile', nameCn: '日期选择器', key: 'date-picker-mobile' }, { name: 'DatePickerMobile', nameCn: '日期选择器', key: 'date-picker-mobile' },
{ name: 'DatePicker', nameCn: '日期选择器多端', key: 'date-picker' },
{ name: 'TimePickerMobile', nameCn: '时间选择器', key: 'time-picker-mobile' }, { name: 'TimePickerMobile', nameCn: '时间选择器', key: 'time-picker-mobile' },
{ name: 'Button', nameCn: '按钮', key: 'button' }, { name: 'Button', nameCn: '按钮', key: 'button' },
{ name: 'Checkbox', nameCn: '复选框', key: 'checkbox' }, { name: 'Checkbox', nameCn: '复选框', key: 'checkbox' },

View File

@ -3,7 +3,8 @@ import { test, expect } from '@playwright/test'
test('自定义服务', async ({ page }) => { test('自定义服务', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull()) page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('amount#custom-service') await page.goto('amount#custom-service')
await page.getByRole('img').filter({ hasText: '>' }).locator('path').click() const demo = page.locator('#custom-service')
await demo.locator('.tiny-amount-input-icon').click()
await page await page
.locator('div') .locator('div')
.filter({ hasText: /^币种MZNCNY$/ }) .filter({ hasText: /^币种MZNCNY$/ })

View File

@ -3,8 +3,7 @@ import { test, expect } from '@playwright/test'
test('debounce', async ({ page }) => { test('debounce', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull()) page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('autocomplete#debounce') await page.goto('autocomplete#debounce')
await page.getByText('去抖延时').nth(3).click()
await page.getByRole('textbox', { name: '请输入内容', exact: true }).click() await page.getByRole('textbox', { name: '请输入内容', exact: true }).click()
await expect(page.getByRole('option', { name: 'WWWW科技YX公司' })).not.toBeVisible() await expect(page.getByRole('option', { name: 'WWWW科技YX公司' })).not.toBeVisible()
await page.waitForTimeout(1000) await page.waitForTimeout(1000)

View File

@ -3,7 +3,6 @@ import { test, expect } from '@playwright/test'
test('size', async ({ page }) => { test('size', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull()) page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('autocomplete#size') await page.goto('autocomplete#size')
await page.getByText('输入框大小').nth(1).click()
await page.getByRole('textbox', { name: '请输入内容', exact: true }).click() await page.getByRole('textbox', { name: '请输入内容', exact: true }).click()
await page.getByRole('option', { name: 'WWWW科技YX公司' }).click() await page.getByRole('option', { name: 'WWWW科技YX公司' }).click()
await expect(page.locator('//div[@class="tiny-input tiny-input-medium"]')).toHaveClass(/tiny-input-medium/) await expect(page.locator('//div[@class="tiny-input tiny-input-medium"]')).toHaveClass(/tiny-input-medium/)

View File

@ -25,7 +25,7 @@ const groupData = ref([
const disabledGroup = ref([ const disabledGroup = ref([
{ text: 'Button1', value: 1 }, { text: 'Button1', value: 1 },
{ text: 'Button2', value: 2, disabled: true }, { text: 'Button2', value: 2, disabled: true, tip: '因为xxx原因被禁用' },
{ text: 'Button3', value: 3 } { text: 'Button3', value: 3 }
]) ])
</script> </script>

View File

@ -38,4 +38,8 @@ test('测试按钮是否禁用', async ({ page }) => {
await expect(buttonGroup3.locator('button').nth(1)).toHaveCSS('background-color', 'rgb(245, 245, 246)') await expect(buttonGroup3.locator('button').nth(1)).toHaveCSS('background-color', 'rgb(245, 245, 246)')
await expect(buttonGroup3.locator('button').nth(1)).toHaveCSS('border-bottom-color', 'rgb(173, 176, 184)') await expect(buttonGroup3.locator('button').nth(1)).toHaveCSS('border-bottom-color', 'rgb(173, 176, 184)')
await expect(buttonGroup3.locator('button').nth(1)).toHaveCSS('color', 'rgb(173, 176, 184)') await expect(buttonGroup3.locator('button').nth(1)).toHaveCSS('color', 'rgb(173, 176, 184)')
// 按钮悬浮提示
await buttonGroup3.locator('button').nth(1).hover()
await expect(page.getByText('因为xxx原因被禁用')).toBeVisible()
}) })

View File

@ -29,7 +29,7 @@ export default {
], ],
disabledGroup: [ disabledGroup: [
{ text: 'Button1', value: 1 }, { text: 'Button1', value: 1 },
{ text: 'Button2', value: 2, disabled: true }, { text: 'Button2', value: 2, disabled: true, tip: '因为xxx原因被禁用' },
{ text: 'Button3', value: 3 } { text: 'Button3', value: 3 }
] ]
} }

View File

@ -37,9 +37,9 @@ export default {
}, },
desc: { desc: {
'zh-CN': 'zh-CN':
'<p>通过 <code>disabled</code> 设置按钮组是否禁用,数据项设置 <code>disabled</code> 属性可以禁用单个按钮。</p>', '<p>通过 <code>disabled</code> 设置按钮组是否禁用,数据项设置 <code>disabled</code> 属性可以禁用单个按钮,数据项设置 <code>tip</code> 属性(v3.17.0版本增加此功能)增加按钮悬浮提示功能。</p>',
'en-US': 'en-US':
'<p>By setting whether the button group is disabled through <code>disabled</code> , and setting the <code>disabled</code> property of the data item, individual buttons can be disabled.</p>' '<p>You can set whether to disable the button group through <code>disabled</code>. You can set the <code>disabled</code> attribute to disable a single button. You can set the <code>tip</code> attribute to add the reason for disabling the button. </p></p>'
}, },
codeFiles: ['disabled.vue'] codeFiles: ['disabled.vue']
}, },

View File

@ -39,10 +39,30 @@ const setDays = (type) => {
return return
} }
map[type].value.push(...selectedDate.value) map[type].value.push(...selectedDate.value)
selectedDate.value.forEach((date) => {
if (type === 'workingDays') {
removeFromArray(offDays.value, date)
removeFromArray(holidays.value, date)
} else if (type === 'offDays') {
removeFromArray(holidays.value, date)
removeFromArray(workingDays.value, date)
} else {
removeFromArray(offDays.value, date)
removeFromArray(workingDays.value, date)
}
})
selectedDates.value = [] selectedDates.value = []
selectedDate.value = [] selectedDate.value = []
} }
const removeFromArray = (array, item) => {
const index = array.indexOf(item)
if (index !== -1) {
array.splice(index, 1)
}
}
const setDayBgColor = (date) => { const setDayBgColor = (date) => {
if (workingDays.value.includes(date)) { if (workingDays.value.includes(date)) {
return 'blue' return 'blue'

View File

@ -41,9 +41,29 @@ export default {
return return
} }
this[type].push(...this.selectedDate) this[type].push(...this.selectedDate)
this.selectedDate.forEach((date) => {
if (type === 'workingDays') {
this.removeFromArray(this.offDays, date)
this.removeFromArray(this.holidays, date)
} else if (type === 'offDays') {
this.removeFromArray(this.holidays, date)
this.removeFromArray(this.workingDays, date)
} else {
this.removeFromArray(this.offDays, date)
this.removeFromArray(this.workingDays, date)
}
})
this.selectedDates = [] this.selectedDates = []
this.selectedDate = [] this.selectedDate = []
}, },
removeFromArray(array, item) {
const index = array.indexOf(item)
if (index !== -1) {
array.splice(index, 1)
}
},
setDayBgColor(date) { setDayBgColor(date) {
if (this.workingDays.includes(date)) { if (this.workingDays.includes(date)) {
return 'blue' return 'blue'

View File

@ -3,24 +3,11 @@ import { test, expect } from '@playwright/test'
test('添加日程事件', async ({ page }) => { test('添加日程事件', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull()) page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('calendar#dynamic-add-schedule') await page.goto('calendar#dynamic-add-schedule')
const selectedDay4 = page.getByText('通知事项通知事项A', { exact: true }) const selectedDay4 = page.getByText('通知事项通知事项A', { exact: true })
const dayFun4 = page.locator('.tiny-calendar__tip-content').filter({ hasText: '请注意该通知事项A' }) const dayFun4 = page.locator('.tiny-calendar__tip-content').filter({ hasText: '请注意该通知事项A' })
const selectedDay13 = page.getByRole('listitem').filter({ hasText: '这是一条警告' })
const dayFun13 = page.locator('.tiny-calendar__tip-content').filter({ hasText: '这是一条警告消息这是一条警告' })
const selectedDay14 = page.getByRole('listitem').filter({ hasText: '这是一条错误' })
const datFun14 = page.locator('.tiny-calendar__tip-content').filter({ hasText: '这是一条错误,还有错误' })
await selectedDay4.hover() await selectedDay4.hover()
await page.waitForTimeout(200) await page.waitForTimeout(200)
await expect(dayFun4).toBeVisible() await expect(dayFun4).toBeVisible()
await selectedDay13.hover()
await page.waitForTimeout(200)
await expect(dayFun13).toBeVisible()
await selectedDay14.hover()
await page.waitForTimeout(200)
await expect(datFun14).toBeVisible()
}) })

View File

@ -0,0 +1,165 @@
<template>
<div class="card-wrap">
<!-- 单选demo -->
<tiny-card-group v-model="radioValue" check-type="radio">
<tiny-card
id="smb-card"
v-for="item in dataArr"
:key="item.title"
:label="item.title"
check-mode="simple"
custom-class="smb-card"
>
<div class="card-content">
<img class="card-image" :src="item.imageSrc" :alt="item.imageAlt || ''" />
<div class="card-text">
<div class="card-title">{{ item.title }}</div>
<div class="card-descript">
{{ item.content }}
</div>
</div>
</div>
<div v-if="item.options" class="card-stlecting">
<tiny-select v-model="item.selectVal" :options="item.options"> </tiny-select>
</div>
</tiny-card>
</tiny-card-group>
<!-- 多选demo -->
<tiny-card-group v-model="checkboxValue" check-type="checkbox">
<tiny-card
id="smb-card"
v-for="item in dataArr"
:key="item.title"
:label="item.title"
check-mode="badge"
custom-class="smb-card"
>
<div class="card-content">
<img class="card-image" :src="item.imageSrc" :alt="item.imageAlt || ''" />
<div class="card-text">
<div class="card-title">{{ item.title }}</div>
<div class="card-descript">
{{ item.content }}
</div>
</div>
</div>
<div v-if="item.options" class="card-stlecting">
<tiny-select v-model="item.selectVal" :options="item.options"> </tiny-select>
</div>
</tiny-card>
</tiny-card-group>
</div>
</template>
<script setup>
import { Card as TinyCard, CardGroup as TinyCardGroup, Select as TinySelect } from '@opentiny/vue'
import { ref } from 'vue'
const radioValue = ref('TinyVue')
const checkboxValue = ref(['TinyVue', 'TinyNG'])
const dataArr = ref([
{
title: 'TinyVue',
content: '^15.0.01',
imageSrc: ''
},
{
title: 'TinyNG',
content: '^16.0.01',
imageSrc: ''
},
{
title: 'TinyEngine',
content: '^14.0.01',
imageSrc: '',
selectVal: 'TinyVue',
options: [
{ value: 'TinyVue', label: 'TinyVue' },
{ value: 'TinyNG', label: 'TinyNG' },
{ value: 'TinyEngine', label: 'TinyEngine' }
]
}
])
</script>
<style scoped>
.card-wrap {
width: 100%;
background: #f5f5f5;
padding: 16px;
display: flex;
justify-content: space-between;
}
.my-card {
width: 80%;
cursor: pointer;
padding: 20px;
}
.content {
display: flex;
}
.content img {
width: 80px;
height: 80px;
margin-right: 20px;
}
/* 业务功能demo */
.smb-card {
display: inline-block;
position: relative;
width: 220px;
margin: 25px;
border-radius: 8px;
cursor: pointer;
background-color: #fafafa;
}
.smb-card:hover {
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.1);
}
.card-content {
width: 100%;
display: flex;
align-items: center;
padding: 24px;
}
.card-image {
display: block;
width: 40px;
height: 40px;
}
.card-text {
margin-left: 16px;
}
.card-title {
font-size: 14px;
text-align: left;
line-height: 22px;
color: #252b3a;
white-space: nowrap;
text-overflow: ellipsis;
max-width: 136px;
overflow: hidden;
}
.card-descript {
font-size: 12px;
text-align: left;
line-height: 20px;
color: #575d6c;
white-space: nowrap;
text-overflow: ellipsis;
max-width: 136px;
overflow: hidden;
}
.card-stlecting {
border-top: 1px solid rgba(0, 0, 0, 0.05);
}
</style>
<style>
#smb-card .tiny-card--small-padding {
padding: 0;
}
</style>

View File

@ -0,0 +1,175 @@
<template>
<div class="card-wrap">
<!-- 单选demo -->
<tiny-card-group v-model="radioValue" check-type="radio">
<tiny-card
id="smb-card"
v-for="item in dataArr"
:key="item.title"
:label="item.title"
check-mode="simple"
custom-class="smb-card"
>
<div class="card-content">
<img class="card-image" :src="item.imageSrc" :alt="item.imageAlt || ''" />
<div class="card-text">
<div class="card-title">{{ item.title }}</div>
<div class="card-descript">
{{ item.content }}
</div>
</div>
</div>
<div v-if="item.options" class="card-stlecting">
<tiny-select v-model="item.selectVal" :options="item.options"> </tiny-select>
</div>
</tiny-card>
</tiny-card-group>
<!-- 多选demo -->
<tiny-card-group v-model="checkboxValue" check-type="checkbox">
<tiny-card
id="smb-card"
v-for="item in dataArr"
:key="item.title"
:label="item.title"
check-mode="badge"
custom-class="smb-card"
>
<div class="card-content">
<img class="card-image" :src="item.imageSrc" :alt="item.imageAlt || ''" />
<div class="card-text">
<div class="card-title">{{ item.title }}</div>
<div class="card-descript">
{{ item.content }}
</div>
</div>
</div>
<div v-if="item.options" class="card-stlecting">
<tiny-select v-model="item.selectVal" :options="item.options"> </tiny-select>
</div>
</tiny-card>
</tiny-card-group>
</div>
</template>
<script>
import { Card, CardGroup, Select } from '@opentiny/vue'
export default {
components: {
TinyCard: Card,
TinyCardGroup: CardGroup,
TinySelect: Select
},
data() {
return {
radioValue: 'TinyVue',
checkboxValue: ['TinyVue', 'TinyNG'],
dataArr: [
{
title: 'TinyVue',
content: '^15.0.01',
imageSrc: ''
},
{
title: 'TinyNG',
content: '^16.0.01',
imageSrc: ''
},
{
title: 'TinyEngine',
content: '^14.0.01',
imageSrc: '',
selectVal: 'TinyVue',
options: [
{ value: 'TinyVue', label: 'TinyVue' },
{ value: 'TinyNG', label: 'TinyNG' },
{ value: 'TinyEngine', label: 'TinyEngine' }
]
}
]
}
}
}
</script>
<style scoped>
.card-wrap {
width: 100%;
background: #f5f5f5;
padding: 16px;
display: flex;
justify-content: space-between;
}
.my-card {
width: 80%;
cursor: pointer;
padding: 10px;
}
.content {
display: flex;
}
.content img {
width: 80px;
height: 80px;
margin-right: 20px;
}
/* 业务功能demo */
.smb-card {
display: inline-block;
position: relative;
width: 220px;
margin: 25px;
border-radius: 8px;
cursor: pointer;
background-color: #fafafa;
}
.smb-card:hover {
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.1);
}
.card-content {
width: 100%;
display: flex;
align-items: center;
padding: 24px;
}
.card-image {
display: block;
width: 40px;
height: 40px;
}
.card-text {
margin-left: 16px;
}
.card-title {
font-size: 14px;
text-align: left;
line-height: 22px;
color: #252b3a;
white-space: nowrap;
text-overflow: ellipsis;
max-width: 136px;
overflow: hidden;
}
.card-descript {
font-size: 12px;
text-align: left;
line-height: 20px;
color: #575d6c;
white-space: nowrap;
text-overflow: ellipsis;
max-width: 136px;
overflow: hidden;
}
.card-stlecting {
border-top: 1px solid rgba(0, 0, 0, 0.05);
}
</style>
<style>
#smb-card .tiny-card--small-padding {
padding: 0;
}
</style>

View File

@ -0,0 +1,102 @@
<template>
<div class="card-wrap">
<!-- 单选normaldemo -->
<tiny-card-group v-model="radioValue" check-type="radio">
<tiny-card
v-for="item in dataArr"
:key="item.title"
:label="item.title"
check-mode="normal"
custom-class="my-card"
>
check-mode="normal" 的示例
</tiny-card>
</tiny-card-group>
<!-- 单选simpledemo -->
<tiny-card-group v-model="radioValue" check-type="radio">
<tiny-card
v-for="item in dataArr"
:key="item.title"
:label="item.title"
check-mode="simple"
custom-class="my-card"
>
<div class="content">
<img :src="item.imageSrc" alt="" />
<div>
<p>simple</p>
<p>check-mode="simple" 的示例</p>
</div>
</div>
</tiny-card>
</tiny-card-group>
<!-- 多选badgedemo -->
<tiny-card-group v-model="checkboxValue" check-type="checkbox">
<tiny-card
v-for="item in dataArr"
:key="item.title"
:label="item.title"
check-mode="badge"
custom-class="my-card"
>
<div class="content">
<img :src="item.imageSrc" alt="" />
<div>
<p>badge</p>
<p>check-mode="badge" 的示例</p>
</div>
</div>
</tiny-card>
</tiny-card-group>
</div>
</template>
<script setup>
import { Card as TinyCard, CardGroup as TinyCardGroup } from '@opentiny/vue'
import { ref } from 'vue'
const radioValue = ref('TinyVue')
const checkboxValue = ref(['TinyVue', 'TinyNG'])
const dataArr = ref([
{
title: 'TinyVue',
content: '^15.0.01',
imageSrc: ''
},
{
title: 'TinyNG',
content: '^16.0.01',
imageSrc: ''
},
{
title: 'TinyEngine',
content: '^14.0.01',
imageSrc: ''
}
])
</script>
<style scoped>
.card-wrap {
width: 100%;
background: #f5f5f5;
padding: 16px;
display: flex;
justify-content: space-between;
}
.my-card {
width: 80%;
cursor: pointer;
padding: 20px;
}
.content {
display: flex;
}
.content img {
width: 80px;
height: 80px;
margin-right: 20px;
}
</style>

View File

@ -0,0 +1,111 @@
<template>
<div class="card-wrap">
<!-- 单选normaldemo -->
<tiny-card-group v-model="radioValue" check-type="radio">
<tiny-card
v-for="item in dataArr"
:key="item.title"
:label="item.title"
check-mode="normal"
custom-class="my-card"
>
check-mode="normal" 的示例
</tiny-card>
</tiny-card-group>
<!-- 单选simpledemo -->
<tiny-card-group v-model="radioValue" check-type="radio">
<tiny-card
v-for="item in dataArr"
:key="item.title"
:label="item.title"
check-mode="simple"
custom-class="my-card"
>
<div class="content">
<img :src="item.imageSrc" alt="" />
<div>
<p>simple</p>
<p>check-mode="simple" 的示例</p>
</div>
</div>
</tiny-card>
</tiny-card-group>
<!-- 多选badgedemo -->
<tiny-card-group v-model="checkboxValue" check-type="checkbox">
<tiny-card
v-for="item in dataArr"
:key="item.title"
:label="item.title"
check-mode="badge"
custom-class="my-card"
>
<div class="content">
<img :src="item.imageSrc" alt="" />
<div>
<p>badge</p>
<p>check-mode="badge" 的示例</p>
</div>
</div>
</tiny-card>
</tiny-card-group>
</div>
</template>
<script>
import { Card, CardGroup } from '@opentiny/vue'
export default {
components: {
TinyCard: Card,
TinyCardGroup: CardGroup
},
data() {
return {
radioValue: 'TinyVue',
checkboxValue: ['TinyVue', 'TinyNG'],
dataArr: [
{
title: 'TinyVue',
content: '^15.0.01',
imageSrc: ''
},
{
title: 'TinyNG',
content: '^16.0.01',
imageSrc: ''
},
{
title: 'TinyEngine',
content: '^14.0.01',
imageSrc: ''
}
]
}
}
}
</script>
<style scoped>
.card-wrap {
width: 100%;
background: #f5f5f5;
padding: 16px;
display: flex;
justify-content: space-between;
}
.my-card {
width: 80%;
cursor: pointer;
padding: 10px;
}
.content {
display: flex;
}
.content img {
width: 80px;
height: 80px;
margin-right: 20px;
}
</style>

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="card-wrap"> <div class="card-wrap">
<tiny-card title="这是卡片标题" card-class="my-card"> <tiny-card title="这是卡片标题" custom-class="my-card">
<p> <p>
这是一段长文本内容这是一段长文本内容这是一段长文本内容这是一段长文本内容 这是一段长文本内容这是一段长文本内容这是一段长文本内容这是一段长文本内容
这是一段长文本内容这是一段长文本内容这是一段长文本内容这是一段长文本内容 这是一段长文本内容这是一段长文本内容这是一段长文本内容这是一段长文本内容
@ -48,4 +48,7 @@ const options = ref([
background: #f5f5f5; background: #f5f5f5;
padding: 16px; padding: 16px;
} }
.my-card {
background-color: rgba(0, 0, 0, 0.3);
}
</style> </style>

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="card-wrap"> <div class="card-wrap">
<tiny-card title="这是卡片标题" card-class="my-card"> <tiny-card title="这是卡片标题" custom-class="my-card">
<p> <p>
这是一段长文本内容这是一段长文本内容这是一段长文本内容这是一段长文本内容 这是一段长文本内容这是一段长文本内容这是一段长文本内容这是一段长文本内容
这是一段长文本内容这是一段长文本内容这是一段长文本内容这是一段长文本内容 这是一段长文本内容这是一段长文本内容这是一段长文本内容这是一段长文本内容
@ -56,4 +56,7 @@ export default {
background: #f5f5f5; background: #f5f5f5;
padding: 16px; padding: 16px;
} }
.my-card {
background-color: rgba(0, 0, 0, 0.3);
}
</style> </style>

View File

@ -83,12 +83,40 @@ export default {
}, },
desc: { desc: {
'zh-CN': 'zh-CN':
'<p>通过属性<code>check-type="checkbox"</code>设置卡片多选,通过属性<code>check-type="radio"</code>设置卡片单选,需同时设置 label。注意目前仅支持在 text 类型开启多选</p>', '<p>通过属性<code>check-type="checkbox"</code>设置卡片多选通过属性<code>check-type="radio"</code>设置卡片单选,需同时设置 label。注意目前仅支持在 text 类型开启多选</p>',
'en-US': 'en-US':
'<p>Use the <code>check-type="checkbox"</code> attribute to set multiple card selections, and use the <code>check-type="radio"</code> attribute to set single card selections. You need to set labels at the same time. Note: Currently, multiple selections can be enabled only for the text type.</p>' '<p>Use the <code>check-type="checkbox"</code> attribute to set multiple card selections, and use the <code>check-type="radio"</code> attribute to set single card selections. You need to set labels at the same time. Note: Currently, multiple selections can be enabled only for the text type.</p>'
}, },
codeFiles: ['check-type-checkbox.vue'] codeFiles: ['check-type-checkbox.vue']
}, },
{
demoId: 'check-mode',
name: {
'zh-CN': '单选&多选(选择模式)',
'en-US': 'Single-choice & multiple-choice(check-mode)'
},
desc: {
'zh-CN':
'<p>通过属性<code>check-mode</code>配置卡片的选中效果,搭配属性<code>check-type="checkbox"</code>设置卡片多选,通过属性<code>check-type="radio"</code>设置卡片单选,需同时设置 label。注意目前仅支持在 text 类型开启多选</p>',
'en-US':
'<p>Use the <code>check-mode</code> configuring the Selection Effect of a Card, and use the <code>check-type="checkbox"</code> attribute to set multiple card selections, and use the <code>check-type="radio"</code> attribute to set single card selections. You need to set labels at the same time. Note: Currently, multiple selections can be enabled only for the text type.</p>'
},
codeFiles: ['check-mode.vue']
},
{
demoId: 'card-select',
name: {
'zh-CN': '卡片选择(业务功能)',
'en-US': 'Card Selection (Business Function)'
},
desc: {
'zh-CN':
'<p>通过属性<code>check-mode</code>配置卡片的选中效果,搭配属性<code>check-type="checkbox"</code>设置卡片多选,通过属性<code>check-type="radio"</code>设置卡片单选,需同时设置 label。注意目前仅支持在 text 类型开启多选</p>',
'en-US':
'<p>Use the <code>check-mode</code> configuring the Selection Effect of a Card, and use the <code>check-type="checkbox"</code> attribute to set multiple card selections, and use the <code>check-type="radio"</code> attribute to set single card selections. You need to set labels at the same time. Note: Currently, multiple selections can be enabled only for the text type.</p>'
},
codeFiles: ['card-select.vue']
},
{ {
demoId: 'custom-class', demoId: 'custom-class',
name: { name: {

View File

@ -0,0 +1,30 @@
<template>
<tiny-carousel height="150px" lite>
<tiny-carousel-item class="carousel-item-demo" v-for="item in 2" :key="item">
<h3>{{ item }}</h3>
</tiny-carousel-item>
</tiny-carousel>
</template>
<script setup>
import { Carousel as TinyCarousel, CarouselItem as TinyCarouselItem } from '@opentiny/vue'
</script>
<style scoped>
.tiny-carousel__item h3 {
color: #475669;
opacity: 0.75;
line-height: 150px;
margin: 0;
text-align: center;
font-size: 25px;
}
.carousel-item-demo:nth-child(2n) {
background-color: #fafafa;
}
.carousel-item-demo:nth-child(2n + 1) {
background-color: #edf0f3;
}
</style>

View File

@ -0,0 +1,37 @@
<template>
<tiny-carousel height="150px" lite>
<tiny-carousel-item class="carousel-item-demo" v-for="item in 2" :key="item">
<h3>{{ item }}</h3>
</tiny-carousel-item>
</tiny-carousel>
</template>
<script>
import { Carousel, CarouselItem } from '@opentiny/vue'
export default {
components: {
TinyCarousel: Carousel,
TinyCarouselItem: CarouselItem
}
}
</script>
<style scoped>
.tiny-carousel__item h3 {
color: #475669;
opacity: 0.75;
line-height: 150px;
margin: 0;
text-align: center;
font-size: 25px;
}
.carousel-item-demo:nth-child(2n) {
background-color: #fafafa;
}
.carousel-item-demo:nth-child(2n + 1) {
background-color: #edf0f3;
}
</style>

View File

@ -155,7 +155,7 @@ export default {
desc: { desc: {
'zh-CN': '<p>通过配置 <code>type</code> 属性为<code>card</code>后,走马灯将以卡片形式进行展示。</p>\n', 'zh-CN': '<p>通过配置 <code>type</code> 属性为<code>card</code>后,走马灯将以卡片形式进行展示。</p>\n',
'en-US': 'en-US':
'<p>After the <code>type</code> attribute is set to <code>card</code>, the lantern is displayed as a card. </p>\n' '<p>After the <code>type</code> attribute is set to <code>card</code>, the carousel is displayed as a card. </p>\n'
}, },
codeFiles: ['card-mode.vue'] codeFiles: ['card-mode.vue']
}, },
@ -163,7 +163,7 @@ export default {
demoId: 'carousel-events', demoId: 'carousel-events',
name: { name: {
'zh-CN': '走马灯事件', 'zh-CN': '走马灯事件',
'en-US': 'The Ma Deng incident' 'en-US': 'Carousel Events'
}, },
desc: { desc: {
'zh-CN': 'zh-CN':
@ -172,6 +172,24 @@ export default {
}, },
codeFiles: ['carousel-events.vue'] codeFiles: ['carousel-events.vue']
}, },
{
demoId: 'swipeable',
name: {
'zh-CN': '触屏轮播',
'en-US': 'Touchscreen Carousel'
},
desc: {
'zh-CN': `
通过<code>swipeable</code> ,<br>
通过 <code>lite</code>
`,
'en-US': `
The <code>swipeable</code> attribute is used to support touchscreen carousel.<br>
Enable the compact mode with the <code>lite</code> attribute. The toggle button and indicator are not displayed.
`
},
codeFiles: ['swipeable.vue']
},
{ {
demoId: 'card-show', demoId: 'card-show',
name: { name: {

View File

@ -21,7 +21,7 @@
</template> </template>
<script> <script>
import { Collapse, CollapseItem, Modal } from '@opentiny/vue' import { Collapse, CollapseItem } from '@opentiny/vue'
export default { export default {
components: { components: {
@ -32,7 +32,7 @@ export default {
return { return {
activeName: '1' activeName: '1'
} }
}, }
} }
</script> </script>

View File

@ -7,7 +7,7 @@
<div>与现实生活一致与现实生活的流程逻辑保持一致遵循用户习惯的语言和概念</div> <div>与现实生活一致与现实生活的流程逻辑保持一致遵循用户习惯的语言和概念</div>
<div>在界面中一致所有的元素和结构需保持一致比如设计样式图标和文本元素的位置等</div> <div>在界面中一致所有的元素和结构需保持一致比如设计样式图标和文本元素的位置等</div>
</tiny-collapse-item> </tiny-collapse-item>
<tiny-collapse-item title="反馈 Feedback" name="2"> <tiny-collapse-item title="使用expandIcon参数自定义icon" name="2" :expand-icon="IconDeltaRightO">
<div>控制反馈通过界面样式和交互动效让用户可以清晰的感知自己的操作</div> <div>控制反馈通过界面样式和交互动效让用户可以清晰的感知自己的操作</div>
<div>页面反馈操作后通过页面元素的变化清晰地展现当前状态</div> <div>页面反馈操作后通过页面元素的变化清晰地展现当前状态</div>
</tiny-collapse-item> </tiny-collapse-item>
@ -26,11 +26,13 @@
<script setup> <script setup>
import { ref } from 'vue' import { ref } from 'vue'
import { Collapse as TinyCollapse, CollapseItem as TinyCollapseItem } from '@opentiny/vue' import { Collapse as TinyCollapse, CollapseItem as TinyCollapseItem } from '@opentiny/vue'
import { iconDeltaRight } from '@opentiny/vue-icon' import { iconDeltaRight, iconDeltaRightO } from '@opentiny/vue-icon'
const activeNames = ref(['1']) const activeNames = ref(['1', '2'])
const TinyIconDeltaRight = iconDeltaRight() const TinyIconDeltaRight = iconDeltaRight()
const IconDeltaRightO = iconDeltaRightO()
</script> </script>
<style scoped lang="less"> <style scoped lang="less">

View File

@ -1,6 +1,6 @@
<template> <template>
<tiny-collapse class="demo-collapse-wrap" v-model="activeNames"> <tiny-collapse class="demo-collapse-wrap" v-model="activeNames">
<tiny-collapse-item title="一致性 Consistency" name="1"> <tiny-collapse-item title="使用icon插槽自定义icon" name="1">
<template #icon> <template #icon>
<span> <span>
<icon-delta-right class="icon-delta-right"></icon-delta-right> <icon-delta-right class="icon-delta-right"></icon-delta-right>
@ -9,7 +9,7 @@
<div>与现实生活一致与现实生活的流程逻辑保持一致遵循用户习惯的语言和概念</div> <div>与现实生活一致与现实生活的流程逻辑保持一致遵循用户习惯的语言和概念</div>
<div>在界面中一致所有的元素和结构需保持一致比如设计样式图标和文本元素的位置等</div> <div>在界面中一致所有的元素和结构需保持一致比如设计样式图标和文本元素的位置等</div>
</tiny-collapse-item> </tiny-collapse-item>
<tiny-collapse-item title="反馈 Feedback" name="2"> <tiny-collapse-item title="使用expandIcon参数自定义icon" name="2" :expand-icon="IconDeltaRightO">
<div>控制反馈通过界面样式和交互动效让用户可以清晰的感知自己的操作</div> <div>控制反馈通过界面样式和交互动效让用户可以清晰的感知自己的操作</div>
<div>页面反馈操作后通过页面元素的变化清晰地展现当前状态</div> <div>页面反馈操作后通过页面元素的变化清晰地展现当前状态</div>
</tiny-collapse-item> </tiny-collapse-item>
@ -27,7 +27,7 @@
<script> <script>
import { Collapse, CollapseItem } from '@opentiny/vue' import { Collapse, CollapseItem } from '@opentiny/vue'
import { IconDeltaRight } from '@opentiny/vue-icon' import { IconDeltaRight, IconDeltaRightO } from '@opentiny/vue-icon'
export default { export default {
components: { components: {
@ -37,7 +37,8 @@ export default {
}, },
data() { data() {
return { return {
activeNames: ['1'] activeNames: ['1', '2'],
IconDeltaRightO: IconDeltaRightO()
} }
} }
} }

View File

@ -66,9 +66,9 @@ export default {
}, },
desc: { desc: {
'zh-CN': 'zh-CN':
'<p>在 <code>collapse-item</code> 元素上可以通过 <code>icon</code> 插槽的方式自定义展开折叠 icon 图标。</p>', '<p>在 <code>collapse-item</code> 元素上可以通过 <code>icon</code> 插槽的方式自定义展开折叠 icon 图标。 也可以通过 <code>expand-icon</code> 参数传入一个框架自带的 <code>icon</code> 图标,此种方式不需要自己写样式</p>',
'en-US': 'en-US':
'<p>On the <code>collapse-item</code> element, you can customize the folding icon icon by using the <code>icon</code> slot. </p>' '<p>On the <code>collapse-item</code> element, the <code>icon</code> slot can be used to customize the expand/collapse icon. The <code>expand-icon</code> parameter can also be used to pass in an <code>icon</code> that comes with the framework. In this way, you do not need to write your own style. </p>'
}, },
codeFiles: ['icon.vue'] codeFiles: ['icon.vue']
}, },

View File

@ -1,14 +1,8 @@
import { test, expect } from '@playwright/test' import { test, expect } from '@playwright/test'
test('test', async ({ page }) => { test('辅助色', async ({ page }) => {
await page.goto('color#neutral-color') await page.goto('color#auxiliary-color')
await page.getByText('主色彩').click() await expect(page.getByText('bg-success-normal')).toHaveClass(/bg-success-normal/)
await page.getByText('bg-primary-normal').click() await expect(page.getByText('bg-warning-normal')).toHaveClass(/bg-warning-normal/)
await expect(page.getByText('bg-primary-normal')).toHaveClass(/bg-primary-normal/) await expect(page.getByText('bg-error-normal')).toHaveClass(/bg-error-normal/)
await page.getByText('bg-primary-hover').click()
await expect(page.getByText('bg-primary-hover')).toHaveClass(/bg-primary-hover/)
await page.getByText('bg-primary-active').click()
await expect(page.getByText('bg-primary-active')).toHaveClass(/bg-primary-active/)
await page.getByText('bg-btn-active').click()
await expect(page.getByText('bg-btn-active')).toHaveClass(/bg-btn-active/)
}) })

View File

@ -1,12 +1,9 @@
import { test, expect } from '@playwright/test' import { test, expect } from '@playwright/test'
test('test', async ({ page }) => { test('主色彩', async ({ page }) => {
await page.goto('color#main-color') await page.goto('color#main-color')
await page.getByText('辅助色').click() await expect(page.getByText('bg-primary-normal')).toHaveClass(/bg-primary-normal/)
await page.getByText('bg-success-normal').click() await expect(page.getByText('bg-primary-hover')).toHaveClass(/bg-primary-hover/)
await expect(page.getByText('bg-success-normal')).toHaveClass(/bg-success-normal/) await expect(page.getByText('bg-primary-active')).toHaveClass(/bg-primary-active/)
await page.getByText('bg-warning-normal').click() await expect(page.getByText('bg-btn-active')).toHaveClass(/bg-btn-active/)
await expect(page.getByText('bg-warning-normal')).toHaveClass(/bg-warning-normal/)
await page.getByText('bg-error-normal').click()
await expect(page.getByText('bg-error-normal')).toHaveClass(/bg-error-normal/)
}) })

View File

@ -1,14 +1,9 @@
import { test, expect } from '@playwright/test' import { test, expect } from '@playwright/test'
test('test', async ({ page }) => { test('中性色', async ({ page }) => {
await page.goto('color#auxiliary-color') await page.goto('color#neutral-color')
await page.getByText('中性色').click()
await page.getByText('bg-gray-navigation').click()
await expect(page.getByText('bg-gray-navigation')).toHaveClass(/bg-gray-navigation/) await expect(page.getByText('bg-gray-navigation')).toHaveClass(/bg-gray-navigation/)
await page.getByText('bg-gray-darker').click()
await expect(page.getByText('bg-gray-darker')).toHaveClass(/bg-gray-darker/) await expect(page.getByText('bg-gray-darker')).toHaveClass(/bg-gray-darker/)
await page.getByText('bg-gray-dark').nth(1).click()
await expect(page.getByText('bg-gray-dark').nth(1)).toHaveClass(/bg-gray-dark/) await expect(page.getByText('bg-gray-dark').nth(1)).toHaveClass(/bg-gray-dark/)
await page.getByText('bg-gray-normal').click()
await expect(page.getByText('bg-gray-normal')).toHaveClass(/bg-gray-normal/) await expect(page.getByText('bg-gray-normal')).toHaveClass(/bg-gray-normal/)
}) })

View File

@ -3,9 +3,7 @@ import { test, expect } from '@playwright/test'
test('测试改变文字方向', async ({ page }) => { test('测试改变文字方向', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull()) page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('config-provider#text-direct') await page.goto('config-provider#text-direct')
await page.getByRole('link', { name: '改变文字方向' }).click()
await page.getByRole('button', { name: 'RTL' }).click() await page.getByRole('button', { name: 'RTL' }).click()
await page.waitForTimeout(300) await page.waitForTimeout(300)
await page.getByRole('button', { name: 'LTR' }).click() await page.getByRole('button', { name: 'LTR' }).click()
await page.waitForTimeout(300)
}) })

View File

@ -3,15 +3,9 @@ import { test, expect } from '@playwright/test'
test('裁剪框方法', async ({ page }) => { test('裁剪框方法', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull()) page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('crop#crop-meth') await page.goto('crop#crop-meth')
await page.getByRole('link', { name: '裁剪框方法 事件' }).click()
await page.getByRole('button', { name: '启用裁剪框' }).click() await page.getByRole('button', { name: '启用裁剪框' }).click()
await page.getByRole('button', { name: '图片裁剪' }).click() await page.getByRole('button', { name: '图片裁剪' }).click()
await page.locator('div:nth-child(5) > .tiny-svg').click() await page.locator('div:nth-child(5) > .tiny-svg').click()
await page.locator('div:nth-child(5) > .tiny-svg').click()
await page.locator('div:nth-child(5) > .tiny-svg').click()
await page.locator('div:nth-child(5) > .tiny-svg').click()
await page.locator('div:nth-child(5) > .tiny-svg').click()
await page.locator('div:nth-child(5) > .tiny-svg').click()
await page.locator('.tiny-crop__dialog-content__handle__button > div:nth-child(2)').click() await page.locator('.tiny-crop__dialog-content__handle__button > div:nth-child(2)').click()
await page.locator('div:nth-child(8) > .tiny-svg').click() await page.locator('div:nth-child(8) > .tiny-svg').click()
}) })

View File

@ -0,0 +1,10 @@
<template>
<tiny-currency v-model="value" placeholder="请选择" set-default></tiny-currency>
</template>
<script setup>
import { ref } from 'vue'
import { Currency as TinyCurrency } from '@opentiny/vue'
const value = ref('CNY')
</script>

View File

@ -0,0 +1,43 @@
<template>
<tiny-currency
v-model="value"
placeholder="请选择"
set-default
:fetch-default-currency="fetchDefaultCurrency"
:set-default-currency="setDefaultCurrency"
@change="change"
></tiny-currency>
</template>
<script setup>
import { ref, getCurrentInstance } from 'vue'
import { Currency as TinyCurrency, Modal } from '@opentiny/vue'
const value = ref('')
const defaultCurrency = ref('VUV')
const change = (value) => {
Modal.message({ message: `当前值为 ${value}`, status: 'info' })
}
const fetchDefaultCurrency = () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(defaultCurrency.value)
}, 500)
})
}
const setDefaultCurrency = (value) => {
return new Promise((resolve) => {
setTimeout(() => {
defaultCurrency.value = value
Modal.message({ message: `设置默认值成功,值为${value} `, status: 'success' })
resolve(value)
}, 500)
})
}
const instance = getCurrentInstance()
const { $service } = instance.appContext.config.globalProperties
console.log($service?.base.getEnvInfo())
</script>

View File

@ -0,0 +1,50 @@
<template>
<tiny-currency
v-model="value"
placeholder="请选择"
set-default
:fetch-default-currency="fetchDefaultCurrency"
:set-default-currency="setDefaultCurrency"
@change="change"
></tiny-currency>
</template>
<script>
import { Currency, Modal } from '@opentiny/vue'
export default {
components: {
TinyCurrency: Currency
},
data() {
return {
value: '',
defaultCurrency: 'VUV'
}
},
methods: {
change(value) {
Modal.message({ message: `当前值为 ${value}`, status: 'info' })
},
fetchDefaultCurrency() {
return new Promise((resolve) => {
setTimeout(() => {
resolve(this.defaultCurrency)
}, 500)
})
},
setDefaultCurrency(value) {
return new Promise((resolve) => {
setTimeout(() => {
this.defaultCurrency = value
Modal.message({ message: `设置默认值成功,值为${value} `, status: 'success' })
resolve(value)
}, 500)
})
}
},
created() {
console.log(this.$service?.base.getEnvInfo())
}
}
</script>

View File

@ -0,0 +1,18 @@
<template>
<tiny-currency v-model="value" placeholder="请选择" set-default></tiny-currency>
</template>
<script>
import { Currency } from '@opentiny/vue'
export default {
components: {
TinyCurrency: Currency
},
data() {
return {
value: ''
}
}
}
</script>

View File

@ -66,6 +66,33 @@ export default {
'<p>Use the filter attribute to switch to filter mode. In filter mode, you can pass the label to display the title, tip to display the prompt information, and clearable to display the clear button.</p>\n' '<p>Use the filter attribute to switch to filter mode. In filter mode, you can pass the label to display the title, tip to display the prompt information, and clearable to display the clear button.</p>\n'
}, },
codeFiles: ['filter.vue'] codeFiles: ['filter.vue']
},
{
demoId: 'set-default',
name: {
'zh-CN': '设置默认币种',
'en-US': 'Set Default Currency'
},
desc: {
'zh-CN': `通过 <code>set-default</code> 属性设置组件是否使用设置默认币种功能。<code>v-model</code>和默认币种值同时存在,以默认币种值优先`,
'en-US':
'Set the <code>set-default</code> attribute to determine whether the component uses the function of setting the default currency. <code>v-model</code> and the default currency value coexist. The default currency value is preferred.'
},
codeFiles: ['set-default.vue']
},
{
demoId: 'set-default-custom-service',
name: {
'zh-CN': '自定义默认币种服务',
'en-US': 'Custom Default Currency Service'
},
desc: {
'zh-CN':
'通过 <code>fetch-default-currency</code> 和 <code>set-default-currency</code> 自定义默认币种查询和保存服务',
'en-US':
'Use <code>fetch-default-currency</code> and <code>set-default-currency</code> to customize the default currency query and saving service.'
},
codeFiles: ['set-default-custom-service.vue']
} }
] ]
} }

View File

@ -1,17 +1,17 @@
<template> <template>
<div> <div>
<tiny-button @click="box1 = true" type="info">允许滚动背景</tiny-button> <tiny-button @click="openDlg(true)" type="info">允许滚动背景</tiny-button>
<tiny-button @click="box2 = true">不允许滚动背景</tiny-button> <tiny-button @click="openDlg(false)">不允许滚动背景</tiny-button>
<tiny-dialog-box :lock-scroll="false" v-model:visible="box1" title="消息" width="30%"> <tiny-dialog-box :lock-scroll="false" v-model:visible="visible1" title="消息" width="30%">
<span>不锁定被遮罩内容的滚动</span> <span>允许被遮罩内容的滚动</span>
<template #footer> <template #footer>
<tiny-button type="primary" @click="box1 = false"> </tiny-button> <tiny-button type="primary" @click="closeDlg(true)"> </tiny-button>
</template> </template>
</tiny-dialog-box> </tiny-dialog-box>
<tiny-dialog-box :lock-scroll="true" v-model:visible="box2" title="消息" width="30%"> <tiny-dialog-box :lock-scroll="true" v-model:visible="visible2" title="消息" width="30%">
<span>锁定被遮罩内容的滚动</span> <span>不允许被遮罩内容的滚动</span>
<template #footer> <template #footer>
<tiny-button type="primary" @click="box2 = false"> </tiny-button> <tiny-button type="primary" @click="closeDlg(false)"> </tiny-button>
</template> </template>
</tiny-dialog-box> </tiny-dialog-box>
</div> </div>
@ -21,6 +21,28 @@
import { ref } from 'vue' import { ref } from 'vue'
import { Button as TinyButton, DialogBox as TinyDialogBox } from '@opentiny/vue' import { Button as TinyButton, DialogBox as TinyDialogBox } from '@opentiny/vue'
const box1 = ref(false) const visible1 = ref(false)
const box2 = ref(false) const visible2 = ref(false)
function openDlg(isScroll) {
if (isScroll) {
document.body.style.overflow = 'auto'
document.body.style.height = '200vh'
visible1.value = true
} else {
document.body.style.height = '200vh'
visible2.value = true
}
}
function closeDlg(isScroll) {
if (isScroll) {
document.body.style.overflow = 'hidden'
document.body.style.height = '100vh'
visible1.value = false
} else {
document.body.style.height = '100vh'
visible2.value = false
}
}
</script> </script>

View File

@ -1,18 +1,17 @@
<template> <template>
<div> <div>
<tiny-button @click="box1 = true" type="info">允许滚动背景</tiny-button> <tiny-button @click="openDlg(true)" type="info">允许滚动背景</tiny-button>
<tiny-button @click="box2 = true">不允许滚动背景</tiny-button> <tiny-button @click="openDlg(false)">不允许滚动背景</tiny-button>
<tiny-dialog-box :lock-scroll="false" v-model:visible="box1" title="消息" width="30%"> <tiny-dialog-box :lock-scroll="false" v-model:visible="visible1" title="消息" width="30%">
<span>不锁定被遮罩内容的滚动</span> <span>允许被遮罩内容的滚动</span>
<template #footer> <template #footer>
<tiny-button type="primary" @click="box1 = false"> </tiny-button> <tiny-button type="primary" @click="closeDlg(true)"> </tiny-button>
</template> </template>
</tiny-dialog-box> </tiny-dialog-box>
<tiny-dialog-box :lock-scroll="true" v-model:visible="visible2" title="消息" width="30%">
<tiny-dialog-box :lock-scroll="true" v-model:visible="box2" title="消息" width="30%"> <span>不允许被遮罩内容的滚动</span>
<span>锁定被遮罩内容的滚动</span>
<template #footer> <template #footer>
<tiny-button type="primary" @click="box2 = false"> </tiny-button> <tiny-button type="primary" @click="closeDlg(false)"> </tiny-button>
</template> </template>
</tiny-dialog-box> </tiny-dialog-box>
</div> </div>
@ -28,8 +27,30 @@ export default {
}, },
data() { data() {
return { return {
box1: false, visible1: false,
box2: false visible2: false
}
},
methods: {
openDlg(isScroll) {
if (isScroll) {
document.body.style.overflow = 'auto'
document.body.style.height = '200vh'
this.visible1 = true
} else {
document.body.style.height = '200vh'
this.visible2 = true
}
},
closeDlg(isScroll) {
if (isScroll) {
document.body.style.overflow = 'hidden'
document.body.style.height = '100vh'
this.visible1 = false
} else {
document.body.style.height = '100vh'
this.visible2 = false
}
} }
} }
} }

View File

@ -1,14 +1,15 @@
<template> <template>
<div class="demo-drawer"> <div class="demo-drawer">
<tiny-button @click="toggleDrawer(true)" type="primary"> 点击展开 Drawer </tiny-button> <tiny-button type="primary" @click="showDrawer"> 点击展开 Drawer </tiny-button>
<tiny-drawer <tiny-drawer
ref="drawer"
title="抽屉关闭将会被拦截" title="抽屉关闭将会被拦截"
v-model:visible="visible"
:before-close="onBeforeClose"
show-footer show-footer
@confirm="confirm" :visible="visible"
:before-close="onBeforeClose"
@update:visible="visible = $event"
> >
<tiny-button @click="toggleDrawer(false)" type="primary"> 关闭 Drawer </tiny-button> <tiny-button type="primary" @click="forceClose"> 强制关闭 Drawer </tiny-button>
</tiny-drawer> </tiny-drawer>
</div> </div>
</template> </template>
@ -18,17 +19,17 @@ import { ref } from 'vue'
import { Drawer as TinyDrawer, Button as TinyButton, Modal } from '@opentiny/vue' import { Drawer as TinyDrawer, Button as TinyButton, Modal } from '@opentiny/vue'
const visible = ref(false) const visible = ref(false)
const drawer = ref()
const showDrawer = () => {
visible.value = true
}
const toggleDrawer = (value) => { const forceClose = () => {
visible.value = value drawer.value.close(true)
} }
const onBeforeClose = (type) => { const onBeforeClose = (type) => {
Modal.message({ message: `beforeClose 回调参数 type = ${type}`, status: 'info', duration: 5000 }) Modal.message({ message: `beforeClose 回调参数 type = ${type}`, status: 'info', duration: 5000 })
return false return false
} }
const confirm = () => {
visible.value = false
}
</script> </script>

View File

@ -12,14 +12,14 @@ test('拦截弹窗关闭', async ({ page }) => {
// 点击关闭按钮 // 点击关闭按钮
await page.getByRole('button', { name: 'Close' }).click() await page.getByRole('button', { name: 'Close' }).click()
await expect(message).toContainText('close') await expect(message.nth(1)).toContainText('close')
await expect(drawer).toBeVisible() await expect(drawer).toBeVisible()
// 点击遮罩层 // 点击遮罩层
await page.locator('.tiny-drawer__mask').click() await page.locator('.tiny-drawer__mask').click()
await expect(drawer).toBeVisible() await expect(drawer).toBeVisible()
// 点击底部确按钮 // 点击底部确按钮
await page.locator('#before-close').getByRole('button', { name: '确定' }).click() await page.locator('#before-close').getByRole('button', { name: '确定' }).click()
await expect(drawer).toBeVisible() await expect(drawer).toBeVisible()

View File

@ -1,15 +1,15 @@
<template> <template>
<div class="demo-drawer"> <div class="demo-drawer">
<tiny-button @click="toggleDrawer(true)" type="primary"> 点击展开 Drawer </tiny-button> <tiny-button type="primary" @click="showDrawer"> 点击展开 Drawer </tiny-button>
<tiny-drawer <tiny-drawer
ref="drawer"
title="抽屉关闭将会被拦截" title="抽屉关闭将会被拦截"
:visible="visible"
@update:visible="visible = $event"
@confirm="confirm"
show-footer show-footer
:visible="visible"
:before-close="onBeforeClose" :before-close="onBeforeClose"
@update:visible="visible = $event"
> >
<tiny-button @click="toggleDrawer(false)" type="primary"> 关闭 Drawer </tiny-button> <tiny-button type="primary" @click="forceClose"> 强制关闭 Drawer </tiny-button>
</tiny-drawer> </tiny-drawer>
</div> </div>
</template> </template>
@ -28,15 +28,15 @@ export default {
} }
}, },
methods: { methods: {
toggleDrawer(value) { showDrawer() {
this.visible = value this.visible = true
},
forceClose() {
this.$refs.drawer.close(true)
}, },
onBeforeClose(type) { onBeforeClose(type) {
Modal.message({ message: `beforeClose 回调参数 type = ${type}`, status: 'info', duration: 5000 }) Modal.message({ message: `beforeClose 回调参数 type = ${type}`, status: 'info', duration: 5000 })
return false return false
},
confirm() {
this.visible = false
} }
} }
} }

View File

@ -1,35 +0,0 @@
<template>
<div>
<tiny-button @click="openDrawer" type="primary"> 关闭事件示例 </tiny-button>
<tiny-drawer
title="标题"
:show-footer="true"
:visible="visible"
@update:visible="visible = $event"
@close="close"
@confirm="confirm"
>
<div style="padding: 32px">内容区域</div>
</tiny-drawer>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { Drawer as TinyDrawer, Button as TinyButton, Modal } from '@opentiny/vue'
const visible = ref(false)
function openDrawer() {
visible.value = true
}
function close() {
Modal.message('关闭事件')
}
function confirm() {
Modal.message({ message: '确认事件', status: 'success' })
visible.value = false
}
</script>

View File

@ -1,18 +0,0 @@
import { test, expect } from '@playwright/test'
test('关闭事件', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('drawer#close-event')
const message = page.locator('.tiny-modal.type__message').filter({ hasText: '关闭事件' }).first()
// 右上角关闭按钮
await page.getByRole('button', { name: '关闭事件示例' }).click()
await page.getByRole('button', { name: 'Close' }).click()
await expect(message).toBeVisible()
// 底部按钮关闭
await page.getByRole('button', { name: '关闭事件示例' }).click()
await page.getByRole('button', { name: '取消' }).click()
await expect(message).toBeVisible()
})

View File

@ -1,43 +0,0 @@
<template>
<div>
<tiny-button @click="openDrawer" type="primary"> 关闭事件示例 </tiny-button>
<tiny-drawer
title="标题"
:show-footer="true"
:visible="visible"
@update:visible="visible = $event"
@close="close"
@confirm="confirm"
>
<div style="padding: 32px">内容区域</div>
</tiny-drawer>
</div>
</template>
<script>
import { Drawer, Button, Modal } from '@opentiny/vue'
export default {
components: {
TinyDrawer: Drawer,
TinyButton: Button
},
data() {
return {
visible: false
}
},
methods: {
openDrawer() {
this.visible = true
},
close() {
Modal.message('关闭事件')
},
confirm() {
Modal.message({ message: '确认事件', status: 'success' })
this.visible = false
}
}
}
</script>

View File

@ -1,29 +0,0 @@
<template>
<div>
<tiny-button @click="openDrawer" type="primary"> 确认事件示例 </tiny-button>
<tiny-drawer
title="标题"
:show-footer="true"
:visible="visible"
@update:visible="visible = $event"
@confirm="confirm"
>
<div style="padding: 32px">内容区域</div>
</tiny-drawer>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { Drawer as TinyDrawer, Button as TinyButton, Modal } from '@opentiny/vue'
const visible = ref(false)
function openDrawer() {
visible.value = true
}
function confirm() {
Modal.message({ message: '确认事件', status: 'success' })
}
</script>

View File

@ -1,11 +0,0 @@
import { test, expect } from '@playwright/test'
test('确认事件', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('drawer#confirm-event')
const message = page.locator('.tiny-modal.type__message').filter({ hasText: '确认事件' }).first()
await page.getByRole('button', { name: '确认事件示例' }).click()
await page.getByRole('button', { name: '确定' }).click()
await expect(message).toBeVisible()
})

View File

@ -0,0 +1,45 @@
<template>
<div class="demo-drawer">
<tiny-button type="primary" @click="showDrawer"> 点击打开抽屉 </tiny-button>
<tiny-drawer
title="事件示例"
:show-footer="true"
:visible="visible"
@update:visible="visible = $event"
@open="onOpen"
@close="onClose"
@confirm="onConfirm"
>
<div class="content">
<span>内容区域</span>
</div>
</tiny-drawer>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { Drawer as TinyDrawer, Button as TinyButton, Modal } from '@opentiny/vue'
const visible = ref(false)
const showDrawer = () => {
visible.value = true
}
const onOpen = () => {
Modal.message({ message: '打开事件', status: 'info' })
}
const onClose = () => {
Modal.message({ message: '关闭事件', status: 'info' })
}
const onConfirm = () => {
Modal.message({ message: '确定事件', status: 'info' })
}
</script>
<style scoped>
.content {
padding: 20px 0;
}
</style>

View File

@ -0,0 +1,35 @@
import { test, expect } from '@playwright/test'
test('事件', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('drawer#events')
const drawer = page.locator('.tiny-drawer__main')
// 显示事件
const showMsg = page.locator('.tiny-modal.type__message').filter({ hasText: '打开事件' }).first()
await page.getByRole('button', { name: '点击打开抽屉' }).click()
await expect(showMsg).toBeVisible()
await expect(drawer).toBeVisible()
// 确定事件
const confirmMsg = page.locator('.tiny-modal.type__message').filter({ hasText: '确定事件' }).first()
await page.getByRole('button', { name: '确定' }).click()
await expect(confirmMsg).toBeVisible()
await expect(drawer).not.toBeVisible()
// 关闭事件
const closeMsg = page.locator('.tiny-modal.type__message').filter({ hasText: '关闭事件' }).first()
await page.getByRole('button', { name: '点击打开抽屉' }).click()
// 右上角关闭按钮
await drawer.locator('.tiny-drawer__headerbtn').click()
await expect(closeMsg).toBeVisible()
// 底部按钮关闭
await page.getByRole('button', { name: '点击打开抽屉' }).click()
await page.getByRole('button', { name: '取消' }).click()
await expect(closeMsg).toBeVisible()
// 点击蒙层关闭
await page.getByRole('button', { name: '点击打开抽屉' }).click()
await page.locator('.tiny-drawer__mask').click()
await expect(closeMsg).toBeVisible()
})

View File

@ -0,0 +1,55 @@
<template>
<div class="demo-drawer">
<tiny-button type="primary" @click="showDrawer"> 点击打开抽屉 </tiny-button>
<p>{{ visible }}</p>
<tiny-drawer
title="事件示例"
:show-footer="true"
:visible="visible"
@update:visible="visible = $event"
@open="onOpen"
@close="onClose"
@confirm="onConfirm"
>
<div class="content">
<span>内容区域</span>
</div>
</tiny-drawer>
</div>
</template>
<script>
import { Drawer, Button, Modal } from '@opentiny/vue'
export default {
components: {
TinyDrawer: Drawer,
TinyButton: Button
},
data() {
return {
visible: false
}
},
methods: {
showDrawer() {
this.visible = true
},
onOpen() {
Modal.message({ message: '打开事件', status: 'info' })
},
onClose() {
Modal.message({ message: '关闭事件', status: 'info' })
},
onConfirm() {
Modal.message({ message: '确定事件', status: 'info' })
}
}
}
</script>
<style scoped>
.content {
padding: 20px 0;
}
</style>

View File

@ -1,27 +0,0 @@
<template>
<div>
<tiny-button @click="fn" type="primary"> 打开事件示例 </tiny-button>
<tiny-drawer title="标题" :show-footer="true" :visible="visible" @update:visible="visible = $event" @open="open">
<div style="height: 200px; text-align: center">
<br />
<br />
<span>内容区域</span>
</div>
</tiny-drawer>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { Drawer as TinyDrawer, Button as TinyButton, Modal } from '@opentiny/vue'
const visible = ref(false)
function fn() {
visible.value = true
}
function open() {
Modal.message('打开事件')
}
</script>

View File

@ -1,11 +0,0 @@
import { test, expect } from '@playwright/test'
test('打开事件', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('drawer#open-event')
const message = page.locator('.tiny-modal.type__message').filter({ hasText: '打开事件' }).first()
await page.getByRole('button', { name: '打开事件示例' }).click()
await expect(message).toBeVisible()
})

View File

@ -1,36 +0,0 @@
<template>
<div>
<tiny-button @click="fn" type="primary"> 打开事件示例 </tiny-button>
<tiny-drawer title="标题" :show-footer="true" :visible="visible" @update:visible="visible = $event" @open="open">
<div style="height: 200px; text-align: center">
<br />
<br />
<span>内容区域</span>
</div>
</tiny-drawer>
</div>
</template>
<script>
import { Drawer, Button, Modal } from '@opentiny/vue'
export default {
components: {
TinyDrawer: Drawer,
TinyButton: Button
},
data() {
return {
visible: false
}
},
methods: {
fn() {
this.visible = true
},
open() {
Modal.message('打开事件')
}
}
}
</script>

View File

@ -0,0 +1,53 @@
<template>
<div class="tiny-demo-drawer">
<tiny-button @click="showDrawer" type="primary"> 点击打开抽屉 </tiny-button>
</div>
</template>
<script lang="tsx" setup>
import { ref } from 'vue'
import { Drawer, Button as TinyButton } from '@opentiny/vue'
import { iconHelp } from '@opentiny/vue-icon'
let drawerInstance = null
const closeDrawer = () => {
if (drawerInstance) {
drawerInstance.close()
}
}
const IconHelp = iconHelp()
const config = ref({
// props
title: '这是一个通过方法打开的抽屉',
showClose: false,
showFooter: true,
// events
events: {
open: (instance) => console.log('open 事件', instance),
close: () => console.log('close 事件')
},
// customSlots , string | VNode | ({h, $drawer}) => VNode
customSlots: {
// 使 h
default: (h) => h('p', { class: 'drawer-content' }, '抽屉主体内容。'),
// VNode , $drawer 访
headerRight: () => <IconHelp></IconHelp>,
// VNode
footer: (
<TinyButton type="primary" onClick={closeDrawer}>
点击关闭
</TinyButton>
)
}
})
const showDrawer = () => {
drawerInstance = Drawer.service(config.value)
}
</script>
<style scope>
.drawer-content {
padding: 20px 0;
}
</style>

View File

@ -0,0 +1,14 @@
import { test, expect } from '@playwright/test'
test('通过方法调用', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('drawer#use-through-method')
const drawer = page.locator('.tiny-drawer__main')
await page.getByRole('button', { name: '点击打开抽屉' }).click()
await expect(drawer).toBeVisible()
await expect(drawer.locator('.tiny-drawer__header')).toHaveText('这是一个通过方法打开的抽屉')
await expect(drawer.locator('.tiny-drawer__body')).toHaveText('抽屉主体内容。')
await drawer.getByRole('button', { name: '点击关闭' }).click()
await expect(page.locator('.tiny-drawer__main')).not.toBeVisible()
})

View File

@ -0,0 +1,60 @@
<template>
<div class="tiny-demo-drawer">
<tiny-button @click="showDrawer" type="primary"> 点击打开抽屉 </tiny-button>
</div>
</template>
<script lang="tsx">
import { Drawer, Button } from '@opentiny/vue'
import { iconHelp } from '@opentiny/vue-icon'
export default {
components: {
TinyButton: Button
},
data() {
return {
drawerInstance: null
}
},
methods: {
showDrawer() {
const IconHelp = iconHelp()
const config = {
// props
title: '这是一个通过方法打开的抽屉',
showClose: false,
showFooter: true,
// events
events: {
open: (instance) => console.log('open 事件', instance),
close: () => console.log('close 事件')
},
// customSlots , string | VNode | ({h, $drawer}) => VNode
customSlots: {
// 使 h
default: (h) => h('p', { class: 'drawer-content' }, '抽屉主体内容。'),
// VNode , $drawer 访
headerRight: () => <IconHelp></IconHelp>,
// VNode
footer: (
<Button type="primary" onClick={this.closeDrawer}>
点击关闭
</Button>
)
}
}
this.drawerInstance = Drawer.service(config)
},
closeDrawer() {
this.drawerInstance.close()
}
}
}
</script>
<style scope>
.drawer-content {
padding: 20px 0;
}
</style>

View File

@ -14,6 +14,16 @@ export default {
}, },
codeFiles: ['basic-usage.vue'] codeFiles: ['basic-usage.vue']
}, },
{
demoId: 'use-through-method',
name: { 'zh-CN': '通过方法调用', 'en-US': 'Use through method' },
desc: {
'zh-CN':
'<p>通过 <code>Drawer.service</code> 方法可配置并打开抽屉,方法返回组件实例,可调用其 <code>close</code> 方法关闭组件。</p>',
'en-US': ''
},
codeFiles: ['use-through-method.vue']
},
{ {
demoId: 'placement', demoId: 'placement',
name: { name: {
@ -81,8 +91,14 @@ export default {
'en-US': 'Block Drawer Close' 'en-US': 'Block Drawer Close'
}, },
desc: { desc: {
'zh-CN': 'zh-CN': `<p>通过 <code>before-close</code> 属性可以配置一个拦截弹窗关闭的方法。如果方法返回 <code>false</code> 值,则拦截弹窗关闭;否则不拦截。</p>
'\n <p>通过 <code>before-close</code> 属性可以配置一个拦截弹窗关闭的方法。如果方法返回 <code>false</code> 值,则拦截弹窗关闭;否则不拦截。</p>\n <p>可以通过该拦截方法传入的参数获取关闭的操作类型 <code>type</code> 弹窗有以下关闭类型:</p>\n <ul>\n <li>confirm点击确认时关闭</li>\n <li>cancel点击取消时关闭</li>\n <li>close点击关闭按钮时关闭</li>\n <li>mask点击遮罩层时关闭</li>\n </ul>\n ', <p>可以通过该拦截方法传入的参数获取关闭的操作类型 <code>type</code> </p>
<ul>
<li>confirm点击确定按钮时关闭</li>
<li>cancel点击取消时关闭</li>
<li>close点击关闭按钮时关闭</li>
<li>mask点击遮罩层时关闭</li>
</ul>`,
'en-US': 'en-US':
'<p>The <code>before-close</code> attribute can be used to configure a method that intercepts closing of the pop-up window. If the method returns a value of <code>false</code>, then the pop-up window is prevented from closing; otherwise it is not intercepted.</p>\n <p>The parameter passed through this interception method can be used to obtain the type of closing operation <code>type</code> for the pop-up window. The following are the types of closing operations:</p>\n <ul>\n <li>confirm: click confirm button</li>\n <li>cancel: click cancel button</li>\n <li>close: click close button</li>\n <li>mask: click mask</li>\n </ul>\n ' '<p>The <code>before-close</code> attribute can be used to configure a method that intercepts closing of the pop-up window. If the method returns a value of <code>false</code>, then the pop-up window is prevented from closing; otherwise it is not intercepted.</p>\n <p>The parameter passed through this interception method can be used to obtain the type of closing operation <code>type</code> for the pop-up window. The following are the types of closing operations:</p>\n <ul>\n <li>confirm: click confirm button</li>\n <li>cancel: click cancel button</li>\n <li>close: click close button</li>\n <li>mask: click mask</li>\n </ul>\n '
}, },
@ -187,41 +203,25 @@ export default {
codeFiles: ['footer-slot.vue'] codeFiles: ['footer-slot.vue']
}, },
{ {
demoId: 'open-event', demoId: 'events',
name: { name: {
'zh-CN': '打开事件', 'zh-CN': '事件',
'en-US': '' 'en-US': ''
}, },
desc: { desc: {
'zh-CN': '<p>打开抽屉事件。</p>', 'zh-CN': `
<p><code>open</code></p>
<p><code>confirm</code> <code>show-footer</code> true </p>
<p><code>close</code></p>
<ul>
<li>点击右上角关闭按钮</li>
<li>点击遮罩层仅当 <code>mask-closable</code> true </li>
<li>点击底部取消按钮该按钮仅当设置 <code>show-footer</code> true </li>
<li>通过组件实例的 <code>close</code> </li>
</ul>`,
'en-US': '' 'en-US': ''
}, },
codeFiles: ['open-event.vue'] codeFiles: ['events.vue']
},
{
demoId: 'close-event',
name: {
'zh-CN': '关闭事件',
'en-US': ''
},
desc: {
'zh-CN': '<p>关闭抽屉事件,抽屉关闭时触发。</p>',
'en-US': ''
},
codeFiles: ['close-event.vue']
},
{
demoId: 'confirm-event',
name: {
'zh-CN': '确认事件',
'en-US': ''
},
desc: {
'zh-CN':
'<p>确认事件,点击确认按钮时触发,设置 <code>:show-footer="true"</code> 且不使用底部插槽 <code>footer</code> 时有效。</p>',
'en-US': ''
},
codeFiles: ['confirm-event.vue']
} }
] ]
} }

View File

@ -32,8 +32,8 @@ test('配置式:使用 menu-options 和 title', async ({ page }) => {
const dropDownMenuItem = dropDownMenu.locator('.tiny-dropdown-item') const dropDownMenuItem = dropDownMenu.locator('.tiny-dropdown-item')
await expect(dropDown).toContainText('点击下拉') await expect(dropDown).toContainText('点击下拉')
await page.waitForTimeout(200)
await dropDown.hover() await dropDown.hover()
await page.waitForTimeout(300)
await expect(dropDownMenu.first()).toBeVisible() await expect(dropDownMenu.first()).toBeVisible()
await expect(dropDownMenuItem.first()).toContainText('老友粉') await expect(dropDownMenuItem.first()).toContainText('老友粉')
await expect(dropDownMenuItem.first()).toHaveClass(/is-disabled/) await expect(dropDownMenuItem.first()).toHaveClass(/is-disabled/)

View File

@ -20,7 +20,6 @@
import { ref } from 'vue' import { ref } from 'vue'
import { Modal, Popover } from '@opentiny/vue' import { Modal, Popover } from '@opentiny/vue'
import Flowchart from '@opentiny/vue-flowchart' import Flowchart from '@opentiny/vue-flowchart'
import { hooks } from '@opentiny/vue-common'
import { iconYes, iconPanelMini, iconChevronDown, iconChevronUp } from '@opentiny/vue-icon' import { iconYes, iconPanelMini, iconChevronDown, iconChevronUp } from '@opentiny/vue-icon'
const { createNode, createLink, createItem, createConfig } = Flowchart const { createNode, createLink, createItem, createConfig } = Flowchart
@ -138,7 +137,7 @@ const HandlerList = {
const imgStyle = `width:${headSize}px;height:${headSize}px` const imgStyle = `width:${headSize}px;height:${headSize}px`
const res = [] const res = []
items.map(({ key }, i) => { items.forEach(({ key }, i) => {
let left let left
if (items.length > 1) { if (items.length > 1) {
@ -229,15 +228,15 @@ function toggleStatus() {
chartRef.value.refresh() chartRef.value.refresh()
} }
function onClickNode(afterNode, e) { function onClickNode(_afterNode, _e) {
Modal.message('click-node') Modal.message('click-node')
} }
function onClickLink(afterLink, e) { function onClickLink(_afterLink, _e) {
Modal.message('click-link') Modal.message('click-link')
} }
function onClickBlank(param, e) { function onClickBlank(_param, _e) {
Modal.message('click-blank') Modal.message('click-blank')
} }
</script> </script>

View File

@ -137,7 +137,7 @@ const HandlerList = {
const imgStyle = `width:${headSize}px;height:${headSize}px` const imgStyle = `width:${headSize}px;height:${headSize}px`
const res = [] const res = []
items.map(({ key }, i) => { items.forEach(({ key }, i) => {
let left let left
if (items.length > 1) { if (items.length > 1) {
@ -236,13 +236,13 @@ export default {
// 2. // 2.
this.$refs.chart.refresh() this.$refs.chart.refresh()
}, },
onClickNode(afterNode, e) { onClickNode(_afterNode, _e) {
Modal.message('click-node') Modal.message('click-node')
}, },
onClickLink(afterLink, e) { onClickLink(_afterLink, _e) {
Modal.message('click-link') Modal.message('click-link')
}, },
onClickBlank(param, e) { onClickBlank(_param, _e) {
Modal.message('click-blank') Modal.message('click-blank')
} }
} }

View File

@ -5,9 +5,9 @@ test('简化版列设置测试', async ({ page }) => {
await page.goto('grid-custom#custom-column-simple') await page.goto('grid-custom#custom-column-simple')
await page.locator('.tiny-select > div').click() await page.locator('.tiny-select > div').click()
await page.getByRole('listitem').filter({ hasText: '员工数' }).click() await page.getByRole('listitem').filter({ hasText: '员工数' }).click()
const thHeader = page.locator('th.tiny-grid-header__column').nth(1) const thHeader = page.locator('th.tiny-grid-header__column').nth(3)
await expect(thHeader).toContainText('名称') await expect(thHeader).toContainText('地址')
await page.getByRole('listitem').filter({ hasText: '名称' }).locator('span').nth(2).click() await page.getByRole('listitem').filter({ hasText: '名称' }).click()
const thHeader2 = page.locator('th.tiny-grid-header__column').nth(1) const thHeader2 = page.locator('th.tiny-grid-header__column').nth(1)
await expect(thHeader2).toContainText('员工数') await expect(thHeader2).toContainText('员工数')

View File

@ -0,0 +1,156 @@
<template>
<tiny-grid
:data="tableData"
column-key
:drop-config="dropConfig"
@column-drag-start="columnDragStart"
@column-drop="columnDrop"
column-min-width="180"
:optimization="{ scrollX: { gt: 10, rSize: 15 } }"
show-header-overflow
>
<tiny-grid-column title="group">
<tiny-grid-column type="index" width="60" fixed="left"></tiny-grid-column>
<tiny-grid-column field="name" title="公司名称" fixed="left"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group1">
<tiny-grid-column field="employees" title="员工数1"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期1"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group2">
<tiny-grid-column field="employees" title="员工数2"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期2"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group3">
<tiny-grid-column field="employees" title="员工数3"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期3"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group4">
<tiny-grid-column field="employees" title="员工数4"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期4"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group5">
<tiny-grid-column field="employees" title="员工数5"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期5"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group6">
<tiny-grid-column field="employees" title="员工数6"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期6"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group7">
<tiny-grid-column field="employees" title="员工数7"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期7"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group8">
<tiny-grid-column field="employees" title="员工数8"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期8"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group9">
<tiny-grid-column field="employees" title="员工数9"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期9"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group10">
<tiny-grid-column field="employees" title="员工数10"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期10"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group11">
<tiny-grid-column field="employees" title="员工数11"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期11"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group12">
<tiny-grid-column field="employees" title="员工数12"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期12"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group13">
<tiny-grid-column field="employees" title="员工数13"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期13"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group14">
<tiny-grid-column field="employees" title="员工数14"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期14"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group15">
<tiny-grid-column field="employees" title="员工数15"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期15"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group16">
<tiny-grid-column field="employees" title="员工数16"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期16"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group17">
<tiny-grid-column field="employees" title="员工数17"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期17"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group18">
<tiny-grid-column field="employees" title="员工数18"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期18"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group19">
<tiny-grid-column field="employees" title="员工数19"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期19"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group20">
<tiny-grid-column field="employees" title="员工数20"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期20"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column field="city" title="城市" fixed="right"></tiny-grid-column>
</tiny-grid>
</template>
<script setup>
import { ref } from 'vue'
import { Grid as TinyGrid, GridColumn as TinyGridColumn, Modal } from '@opentiny/vue'
const dropConfig = ref({
// scheme v2 使使 sortablejs
scheme: 'v2',
//
column: true,
// level nested level
columnGroup: 'level',
// false
columnBeforeDrop: ({ dragColumn, dropColumn }) => {
console.log('columnBeforeDrop', dragColumn, dropColumn)
return true
},
//
columnDropClass: 'in-drop'
})
const tableData = ref([
{
id: '1',
name: 'GFD科技有限公司',
city: '福州',
employees: 800,
created_date: '2014-04-30 00:56:00'
},
{
id: '2',
name: 'WWW科技有限公司',
city: '深圳',
employees: 300,
created_date: '2016-07-08 12:36:22'
},
{
id: '3',
name: 'RFV有限责任公司',
city: '中山',
employees: 1300,
created_date: '2014-02-14 14:14:14'
}
])
function columnDragStart() {
Modal.message({ message: '列拖拽开始', status: 'info' })
}
function columnDrop() {
Modal.message({ message: '列拖拽结束', status: 'info' })
}
</script>
<style>
.in-drop {
outline: 1px dashed rgba(170, 50, 220, 0.6);
outline-offset: -2px;
}
</style>

View File

@ -0,0 +1,40 @@
import { test, expect } from '@playwright/test'
test('多级表头拖拽', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('grid-drag#multi-header-drag')
await page.setViewportSize({
width: 2000,
height: 1000
})
const draggerDom = page.getByRole('cell', { name: '创建日期1' })
// 获取拖拽元素位置
const { x, y } = await draggerDom.boundingBox()
// 验证不可拖拽
await page.mouse.move(x + 2, y + 3)
await page.waitForTimeout(200)
await page.mouse.down()
await page.waitForTimeout(200)
await page.mouse.move(x + 200, y)
await page.waitForTimeout(200)
await page.mouse.up()
await page.waitForTimeout(200)
await expect(page.locator('.tiny-grid-header__row').nth(1).locator('.tiny-grid-header__column').nth(3)).toContainText(
'创建日期1'
)
// 获取拖拽元素位置
const { x: left, y: top } = await draggerDom.boundingBox()
// 验证可拖拽
await page.mouse.move(left + 2, top + 3)
await page.waitForTimeout(200)
await page.mouse.down()
await page.waitForTimeout(200)
await page.mouse.move(left - 50, top)
await page.waitForTimeout(200)
await page.mouse.up()
await page.waitForTimeout(200)
await expect(page.locator('.tiny-grid-header__row').nth(1).locator('.tiny-grid-header__column').nth(2)).toContainText(
'创建日期1'
)
})

View File

@ -0,0 +1,166 @@
<template>
<tiny-grid
:data="tableData"
column-key
:drop-config="dropConfig"
@column-drag-start="columnDragStart"
@column-drop="columnDrop"
column-min-width="180"
:optimization="{ scrollX: { gt: 10, rSize: 15 } }"
show-header-overflow
>
<tiny-grid-column title="group">
<tiny-grid-column type="index" width="60" fixed="left"></tiny-grid-column>
<tiny-grid-column field="name" title="公司名称"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group1">
<tiny-grid-column field="employees" title="员工数1"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期1"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group2">
<tiny-grid-column field="employees" title="员工数2"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期2"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group3">
<tiny-grid-column field="employees" title="员工数3"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期3"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group4">
<tiny-grid-column field="employees" title="员工数4"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期4"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group5">
<tiny-grid-column field="employees" title="员工数5"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期5"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group6">
<tiny-grid-column field="employees" title="员工数6"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期6"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group7">
<tiny-grid-column field="employees" title="员工数7"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期7"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group8">
<tiny-grid-column field="employees" title="员工数8"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期8"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group9">
<tiny-grid-column field="employees" title="员工数9"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期9"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group10">
<tiny-grid-column field="employees" title="员工数10"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期10"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group11">
<tiny-grid-column field="employees" title="员工数11"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期11"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group12">
<tiny-grid-column field="employees" title="员工数12"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期12"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group13">
<tiny-grid-column field="employees" title="员工数13"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期13"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group14">
<tiny-grid-column field="employees" title="员工数14"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期14"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group15">
<tiny-grid-column field="employees" title="员工数15"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期15"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group16">
<tiny-grid-column field="employees" title="员工数16"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期16"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group17">
<tiny-grid-column field="employees" title="员工数17"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期17"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group18">
<tiny-grid-column field="employees" title="员工数18"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期18"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group19">
<tiny-grid-column field="employees" title="员工数19"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期19"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column title="group20">
<tiny-grid-column field="employees" title="员工数20"></tiny-grid-column>
<tiny-grid-column field="created_date" title="创建日期20"></tiny-grid-column>
</tiny-grid-column>
<tiny-grid-column field="city" title="城市" fixed="right"></tiny-grid-column>
</tiny-grid>
</template>
<script>
import { Grid, GridColumn, Modal } from '@opentiny/vue'
export default {
components: {
TinyGrid: Grid,
TinyGridColumn: GridColumn
},
data() {
return {
dropConfig: {
// scheme v2 使使 sortablejs
scheme: 'v2',
//
column: true,
// level nested level
columnGroup: 'level',
// false
columnBeforeDrop: ({ dragColumn, dropColumn }) => {
console.log('columnBeforeDrop', dragColumn, dropColumn)
return true
},
//
columnDropClass: 'in-drop'
},
tableData: [
{
id: '1',
name: 'GFD科技有限公司',
city: '福州',
employees: 800,
created_date: '2014-04-30 00:56:00'
},
{
id: '2',
name: 'WWW科技有限公司',
city: '深圳',
employees: 300,
created_date: '2016-07-08 12:36:22'
},
{
id: '3',
name: 'RFV有限责任公司',
city: '中山',
employees: 1300,
created_date: '2014-02-14 14:14:14'
}
]
}
},
methods: {
columnDragStart() {
Modal.message({ message: '列拖拽开始', status: 'info' })
},
columnDrop() {
Modal.message({ message: '列拖拽结束', status: 'info' })
}
}
}
</script>
<style>
.in-drop {
outline: 1px dashed rgba(170, 50, 220, 0.6);
outline-offset: -2px;
}
</style>

View File

@ -6,8 +6,9 @@
@row-drop-end="rowDropEnd" @row-drop-end="rowDropEnd"
@row-drop-start="rowDropStart" @row-drop-start="rowDropStart"
@row-drop-move="rowDropMove" @row-drop-move="rowDropMove"
column-min-width="300px"
> >
<tiny-grid-column type="index" width="60"></tiny-grid-column> <tiny-grid-column type="index" width="60" fixed="left"></tiny-grid-column>
<tiny-grid-column field="name" title="公司名称"></tiny-grid-column> <tiny-grid-column field="name" title="公司名称"></tiny-grid-column>
<tiny-grid-column field="employees" title="员工数"></tiny-grid-column> <tiny-grid-column field="employees" title="员工数"></tiny-grid-column>
<tiny-grid-column field="createdDate" title="创建日期"></tiny-grid-column> <tiny-grid-column field="createdDate" title="创建日期"></tiny-grid-column>
@ -23,6 +24,7 @@ import Sortable from 'sortablejs'
const dropConfig = ref({ const dropConfig = ref({
plugin: Sortable, plugin: Sortable,
row: true, row: true,
rowHandle: 'index',
column: false // column: false //
}) })
const tableData = ref([ const tableData = ref([

View File

@ -3,7 +3,7 @@ import { test, expect } from '@playwright/test'
test('行拖拽', async ({ page }) => { test('行拖拽', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull()) page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('grid-drag#drag-row-drag') await page.goto('grid-drag#drag-row-drag')
const draggerDom = page.getByRole('cell', { name: 'RFV有限责任公司' }) const draggerDom = page.locator('.row__drop-handle').first()
// 获取拖拽元素位置 // 获取拖拽元素位置
const { x, y } = await draggerDom.boundingBox() const { x, y } = await draggerDom.boundingBox()
// 开始拖拽 // 开始拖拽
@ -15,5 +15,5 @@ test('行拖拽', async ({ page }) => {
await page.waitForTimeout(200) await page.waitForTimeout(200)
await page.mouse.up() await page.mouse.up()
await page.waitForTimeout(200) await page.waitForTimeout(200)
await expect(page.locator('.tiny-grid-body__row').nth(5)).toContainText('RFV有限责任公司') await expect(page.locator('.tiny-grid-body__row').nth(5)).toContainText('WSX科技YX公司')
}) })

View File

@ -6,8 +6,9 @@
@row-drop-end="rowDropEnd" @row-drop-end="rowDropEnd"
@row-drop-start="rowDropStart" @row-drop-start="rowDropStart"
@row-drop-move="rowDropMove" @row-drop-move="rowDropMove"
column-min-width="300px"
> >
<tiny-grid-column type="index" width="60"></tiny-grid-column> <tiny-grid-column type="index" width="60" fixed="left"></tiny-grid-column>
<tiny-grid-column field="name" title="公司名称"></tiny-grid-column> <tiny-grid-column field="name" title="公司名称"></tiny-grid-column>
<tiny-grid-column field="employees" title="员工数"></tiny-grid-column> <tiny-grid-column field="employees" title="员工数"></tiny-grid-column>
<tiny-grid-column field="createdDate" title="创建日期"></tiny-grid-column> <tiny-grid-column field="createdDate" title="创建日期"></tiny-grid-column>
@ -29,6 +30,7 @@ export default {
dropConfig: { dropConfig: {
plugin: Sortable, plugin: Sortable,
row: true, row: true,
rowHandle: 'index',
column: false // column: false //
}, },
tableData: [ tableData: [

View File

@ -0,0 +1,88 @@
<template>
<div>
<div class="button-box">
<tiny-button @click="change">改变列插槽</tiny-button>
</div>
<tiny-grid :data="tableData">
<tiny-grid-column type="index" width="60"></tiny-grid-column>
<tiny-grid-column v-for="col in cols" :key="col.field" :field="col.field" :title="col.title">
<template v-if="col.header" #header>
<div>{{ col.header.value }}</div>
</template>
<template v-if="col.default" #default>
<div>{{ col.default.value }}</div>
</template>
</tiny-grid-column>
<tiny-grid-column field="address" title="地址"></tiny-grid-column>
<tiny-grid-column field="introduction" title="公司简介" show-overflow></tiny-grid-column>
</tiny-grid>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { Grid as TinyGrid, GridColumn as TinyGridColumn, Button as TinyButton } from '@opentiny/vue'
let times = 1
const createNewCols = () => [
{
field: 'name',
title: '名称',
header: {
value: `header-${++times}`
}
},
{
field: 'area',
title: '所属区域',
default: {
value: `col-${times}`
}
}
]
const cols = ref([
{
field: 'name',
title: '名称',
header: {
value: `header-${times}`
}
},
{
field: 'area',
title: '所属区域',
default: {
value: `col-${times}`
}
}
])
const tableData = ref([
{
id: '1',
name: 'GFD科技YX公司',
area: '华东区',
address: '福州',
introduction: '公司技术和研发实力雄厚是国家863项目的参与者并被政府认定为“高新技术企业”。'
},
{
id: '2',
name: 'WWWW科技YX公司',
area: '华南区',
address: '深圳福田区',
introduction: '公司技术和研发实力雄厚是国家863项目的参与者并被政府认定为“高新技术企业”。'
}
])
const change = () => {
cols.value = createNewCols()
}
</script>
<style scoped>
.button-box {
margin-bottom: 20px;
}
</style>

View File

@ -0,0 +1,14 @@
import { test, expect } from '@playwright/test'
test('动态修改列插槽', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('grid-dynamically-columns#dynamic-slot')
await expect(page.getByRole('cell', { name: 'header-1' })).toBeVisible()
await expect(page.getByRole('cell', { name: 'col-1' }).first()).toBeVisible()
await page.getByRole('button', { name: '改变列插槽' }).click()
await expect(page.getByRole('cell', { name: 'header-2' })).toBeVisible()
await expect(page.getByRole('cell', { name: 'col-2' }).first()).toBeVisible()
await page.getByRole('button', { name: '改变列插槽' }).click()
await expect(page.getByRole('cell', { name: 'header-3' })).toBeVisible()
await expect(page.getByRole('cell', { name: 'col-3' }).first()).toBeVisible()
})

View File

@ -0,0 +1,97 @@
<template>
<div>
<div class="button-box">
<tiny-button @click="change">改变列插槽</tiny-button>
</div>
<tiny-grid :data="tableData">
<tiny-grid-column type="index" width="60"></tiny-grid-column>
<tiny-grid-column v-for="col in cols" :key="col.field" :field="col.field" :title="col.title">
<template v-if="col.header" #header>
<div>{{ col.header.value }}</div>
</template>
<template v-if="col.default" #default>
<div>{{ col.default.value }}</div>
</template>
</tiny-grid-column>
<tiny-grid-column field="address" title="地址"></tiny-grid-column>
<tiny-grid-column field="introduction" title="公司简介" show-overflow></tiny-grid-column>
</tiny-grid>
</div>
</template>
<script>
import { Grid, GridColumn, Button } from '@opentiny/vue'
let times = 1
const createNewCols = () => [
{
field: 'name',
title: '名称',
header: {
value: `header-${++times}`
}
},
{
field: 'area',
title: '所属区域',
default: {
value: `col-${times}`
}
}
]
export default {
components: {
TinyGrid: Grid,
TinyGridColumn: GridColumn,
TinyButton: Button
},
methods: {
change() {
this.cols = createNewCols()
}
},
data() {
return {
cols: [
{
field: 'name',
title: '名称',
header: {
value: `header-${times}`
}
},
{
field: 'area',
title: '所属区域',
default: {
value: `col-${times}`
}
}
],
tableData: [
{
id: '1',
name: 'GFD科技YX公司',
area: '华东区',
address: '福州',
introduction: '公司技术和研发实力雄厚是国家863项目的参与者并被政府认定为“高新技术企业”。'
},
{
id: '2',
name: 'WWWW科技YX公司',
area: '华南区',
address: '深圳福田区',
introduction: '公司技术和研发实力雄厚是国家863项目的参与者并被政府认定为“高新技术企业”。'
}
]
}
}
}
</script>
<style scoped>
.button-box {
margin-bottom: 20px;
}
</style>

View File

@ -0,0 +1,58 @@
<template>
<div>
<tiny-button @click="change" type="primary" class="mb-16"> 反转列顺序 </tiny-button>
<tiny-grid :data="tableData">
<tiny-grid-column v-for="col in cols" :key="col.field" v-bind="col"></tiny-grid-column>
</tiny-grid>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { Grid as TinyGrid, GridColumn as TinyGridColumn, Button as TinyButton } from '@opentiny/vue'
const cols = ref([
{
field: 'introduction',
title: '公司简介'
},
{
field: 'address',
title: '地址'
}
])
const tableData = ref([
{
id: '1',
name: 'GFD科技有限公司',
area: '华东区',
address: '福州',
introduction: '公司技术和研发实力雄厚是国家863项目的参与者并被政府认定为“高新技术企业”。'
},
{
id: '2',
name: 'WWWW科技有限公司',
area: '华南区',
address: '深圳福田区',
introduction: '公司技术和研发实力雄厚是国家863项目的参与者并被政府认定为“高新技术企业”。'
},
{
id: '3',
name: 'RFV有限责任公司',
area: '华南区',
address: '中山市',
introduction: '公司技术和研发实力雄厚是国家863项目的参与者并被政府认定为“高新技术企业”。'
}
])
function change() {
cols.value.reverse()
}
</script>
<style scoped>
.mb-16 {
margin-bottom: 16px;
}
</style>

View File

@ -0,0 +1,16 @@
import { test, expect } from '@playwright/test'
test('表格反转测试', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('grid-dynamically-columns#dynamically-columns-reverse-columns')
const firstHeader = page.locator(
'#dynamically-columns-reverse-columns .tiny-grid-header__column .tiny-grid-cell-text'
)
const firstCell = page.locator('#dynamically-columns-reverse-columns .tiny-grid-body__column .tiny-grid-cell')
await expect(firstHeader.first()).toHaveText(/公司简介/)
await expect(firstCell.first()).toHaveText(/公司技术和研发实力雄厚/)
await page.getByRole('button', { name: '反转列顺序' }).click()
await expect(firstHeader.first()).toHaveText(/地址/)
await expect(firstCell.first()).toHaveText(/福州/)
})

Some files were not shown because too many files have changed in this diff Show More