feat: update vue-docs (#1810)
|
@ -434,6 +434,20 @@ export default {
|
|||
mode: ['pc'],
|
||||
pcDemo: ''
|
||||
},
|
||||
{
|
||||
name: 'footer-buttons',
|
||||
type: 'Slot',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '自定义弹窗底部按钮',
|
||||
'en-US': 'Custom Pop Up Bottom buttons'
|
||||
},
|
||||
metaData: {
|
||||
new: '3.18.0'
|
||||
},
|
||||
mode: ['pc'],
|
||||
pcDemo: ''
|
||||
},
|
||||
{
|
||||
name: 'option',
|
||||
type: 'Slot',
|
||||
|
|
|
@ -228,6 +228,22 @@ export default {
|
|||
},
|
||||
mode: ['pc'],
|
||||
pcDemo: 'visible-arrow'
|
||||
},
|
||||
{
|
||||
name: 'lazy-show-popper',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN': '是否懒加载下拉菜单及内部的项,以优化性能,默认初始全加载菜单及内部项。',
|
||||
'en-US':
|
||||
'Indicates whether to lazily load the drop-down menu and internal items to optimize performance. The default value is false. The menu and internal items are loaded initially.'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'lazy-show-popper',
|
||||
mfDemo: '',
|
||||
metaData: {
|
||||
experimental: '3.18.0'
|
||||
}
|
||||
}
|
||||
],
|
||||
events: [
|
||||
|
|
|
@ -262,7 +262,8 @@ export default {
|
|||
'zh-CN': '限制文件大小,单位为 KB;当为 Number 类型时,小于该值停止上传;为数组时[min,max] 设置上传范围',
|
||||
'en-US': ''
|
||||
},
|
||||
mode: ['mobile-first'],
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'file-size',
|
||||
mfDemo: ''
|
||||
},
|
||||
{
|
||||
|
|
|
@ -1073,6 +1073,19 @@ export default {
|
|||
}
|
||||
],
|
||||
events: [
|
||||
{
|
||||
name: 'after-refresh-column',
|
||||
type: '()=> void',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '在新增或者删除列后,列配置是异步更新的,列配置刷新后触发的回调',
|
||||
'en-US':
|
||||
'After adding or deleting a column, the column configuration is updated asynchronously, and the callback is triggered after the column configuration is refreshed.'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'grid-dynamically-columns#column-switching-scroll',
|
||||
mfDemo: ''
|
||||
},
|
||||
{
|
||||
name: 'before-page-change',
|
||||
typeAnchorName: 'IBeforePageChangeArgs',
|
||||
|
|
|
@ -175,7 +175,7 @@ interface IDomData {
|
|||
//销毁的回调函数
|
||||
destroy: () => void
|
||||
// 完成的回调函数
|
||||
completey: () => void
|
||||
complete: () => void
|
||||
|
||||
// 需要设置的按钮组
|
||||
button: {
|
||||
|
|
|
@ -396,6 +396,21 @@ export default {
|
|||
mobileDemo: 'counter',
|
||||
mfDemo: ''
|
||||
},
|
||||
{
|
||||
name: 'show-tooltip',
|
||||
type: 'boolean',
|
||||
defaultValue: 'true',
|
||||
metaData: {
|
||||
new: '3.18.0'
|
||||
},
|
||||
desc: {
|
||||
'zh-CN': '只读状态下,文本超出是否悬浮提示',
|
||||
'en-US': 'In the read-only state, whether the text exceeds the floating prompt'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'size',
|
||||
mfDemo: ''
|
||||
},
|
||||
{
|
||||
name: 'size',
|
||||
type: "'medium' | 'small' | 'mini'",
|
||||
|
|
|
@ -491,6 +491,17 @@ export default {
|
|||
},
|
||||
mode: ['pc'],
|
||||
pcDemo: 'edit'
|
||||
},
|
||||
{
|
||||
name: 'highlight-query',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN': '通过 <code> highlightQuery </code> 属性,是否在匹配的节点中,高亮搜索文字。<br>',
|
||||
'en-US': 'Indicates whether to highlight the search text in the matched node.'
|
||||
},
|
||||
mode: ['pc'],
|
||||
pcDemo: 'filter-view'
|
||||
}
|
||||
],
|
||||
events: [
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
<template>
|
||||
<tiny-file-upload ref="upload" :action="action" accept=".doc,.docx" :file-list="fileList" :file-size="[100, 200]" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { FileUpload } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyFileUpload: FileUpload
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
action: 'http://localhost:3000/api/upload',
|
||||
fileList: []
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,76 @@
|
|||
<template>
|
||||
<tiny-file-upload ref="upload" :action="action" list-type="text" :file-list="fileList" :file-size="100" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { FileUpload } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyFileUpload: FileUpload
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
action: 'http://localhost:3000/api/upload',
|
||||
fileList: [
|
||||
{
|
||||
docId: 'M1T2A1N548572512085860351',
|
||||
path: 'edm/one/',
|
||||
docVersion: 'V1',
|
||||
name: 'test1.png',
|
||||
docSize: 100 * 1024,
|
||||
size: 100 * 1024,
|
||||
serverName: 'ShenZhen'
|
||||
},
|
||||
{
|
||||
docId: 'M1T2A1N548572512085860352',
|
||||
path: 'edm/one/',
|
||||
docVersion: 'V1',
|
||||
name: 'test2.doc',
|
||||
docSize: 17252 * 1024,
|
||||
size: 17252 * 1024,
|
||||
serverName: 'ShenZhen'
|
||||
},
|
||||
{
|
||||
docId: 'M1T2A1N548572512085860353',
|
||||
path: 'edm/one/',
|
||||
docVersion: 'V1',
|
||||
name: 'test3.png',
|
||||
docSize: 200 * 1024,
|
||||
size: 200 * 1024,
|
||||
serverName: 'ShenZhen',
|
||||
status: 'uploading',
|
||||
percentage: 30
|
||||
},
|
||||
{
|
||||
docId: 'M1T2A1N548572512085860353',
|
||||
path: 'edm/one/',
|
||||
docVersion: 'V1',
|
||||
name: 'test4.doc',
|
||||
docSize: 17252 * 1024,
|
||||
size: 17252 * 1024,
|
||||
serverName: 'ShenZhen',
|
||||
status: 'fail',
|
||||
percentage: 30
|
||||
},
|
||||
{
|
||||
docId: 'M1T2A1N548572512085860353',
|
||||
path: 'edm/one/',
|
||||
docVersion: 'V1',
|
||||
name: 'test5超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长.doc',
|
||||
docSize: 17252 * 1024,
|
||||
size: 17252 * 1024,
|
||||
serverName: 'ShenZhen'
|
||||
},
|
||||
{
|
||||
docId: 'M1T2A1N548572512085860353',
|
||||
path: 'edm/one/',
|
||||
docVersion: 'V1',
|
||||
name: '没有文件大小.doc',
|
||||
serverName: 'ShenZhen'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -38,6 +38,30 @@ export default {
|
|||
},
|
||||
codeFiles: ['file-list.vue']
|
||||
},
|
||||
{
|
||||
demoId: 'file-size',
|
||||
name: {
|
||||
'zh-CN': '上传的文件大小限制',
|
||||
'en-US': 'Uploaded file size limit'
|
||||
},
|
||||
desc: {
|
||||
'zh-CN': '<p>通过 <code>file-size</code> 配置上传文件的大小。<p>',
|
||||
'en-US': '<p>Use <code>file-size</code> to configure the size of the uploaded file.</p>'
|
||||
},
|
||||
codeFiles: ['file-size.vue']
|
||||
},
|
||||
{
|
||||
demoId: 'file-size-array',
|
||||
name: {
|
||||
'zh-CN': '上传的文件大小范围',
|
||||
'en-US': 'Uploaded file size range'
|
||||
},
|
||||
desc: {
|
||||
'zh-CN': '<p>通过 <code>file-size</code> 配置为数组类型限制上传文件的大小范围。<p>',
|
||||
'en-US': '<p>Set <code>file-size</code> to an array to limit the size of the file to be uploaded.</p>'
|
||||
},
|
||||
codeFiles: ['file-size-array.vue']
|
||||
},
|
||||
{
|
||||
demoId: 'show-title',
|
||||
name: {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
<tiny-radio v-model="viewType" label="card">卡片视图</tiny-radio>
|
||||
<tiny-radio v-model="viewType" label="list">列表视图</tiny-radio>
|
||||
<tiny-radio v-model="viewType" label="gantt">甘特视图</tiny-radio>
|
||||
<tiny-radio v-model="viewType" label="custom">custom视图</tiny-radio>
|
||||
</div>
|
||||
<tiny-grid
|
||||
highlight-current-row
|
||||
|
@ -68,7 +69,10 @@
|
|||
</div>
|
||||
</template>
|
||||
<template #gantt="{ rows }">
|
||||
<div class="gantt-container">{{ rows.length }}</div>
|
||||
<div class="gantt-container">gantt视图,表格行数{{ rows.length }}</div>
|
||||
</template>
|
||||
<template #custom="{ rows }">
|
||||
<div class="custom-container">custom视图,表格行数{{ rows.length }}</div>
|
||||
</template>
|
||||
</tiny-grid>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,226 @@
|
|||
<template>
|
||||
<div class="cascader-panel-demo-props">
|
||||
<div>
|
||||
选中值:<span>{{ value }}</span>
|
||||
</div>
|
||||
<tiny-cascader-panel
|
||||
v-model="value"
|
||||
:options="optionsCascader"
|
||||
:props="{
|
||||
multiple: true
|
||||
}"
|
||||
></tiny-cascader-panel>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { CascaderPanel as TinyCascaderPanel } from '@opentiny/vue'
|
||||
|
||||
const value = ref([
|
||||
['zhinan', 'anzhuang', 'xiangmudengji'],
|
||||
['zhinan', 'anzhuang', 'huanjingzhunbei'],
|
||||
['zhinan', 'anzhuang', 'anzhuangcli'],
|
||||
['zhinan', 'kaifa', 'monishuju']
|
||||
])
|
||||
const optionsCascader = ref([
|
||||
{
|
||||
value: 'zhinan',
|
||||
label: '指南',
|
||||
children: [
|
||||
{
|
||||
value: 'anzhuang',
|
||||
label: '安装',
|
||||
children: [
|
||||
{
|
||||
value: 'xiangmudengji',
|
||||
label: '项目登记'
|
||||
},
|
||||
{
|
||||
value: 'huanjingzhunbei',
|
||||
label: '环境准备'
|
||||
},
|
||||
{
|
||||
value: 'anzhuangcli',
|
||||
label: '安装 CLI'
|
||||
},
|
||||
{
|
||||
value: 'chuangjianxiangmu',
|
||||
label: '创建项目'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
value: 'kaifa',
|
||||
label: '开发',
|
||||
children: [
|
||||
{
|
||||
value: 'yinruzujian',
|
||||
label: '引入组件'
|
||||
},
|
||||
{
|
||||
value: 'monishuju',
|
||||
label: '模拟数据'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
value: 'zujian',
|
||||
label: '组件',
|
||||
children: [
|
||||
{
|
||||
value: 'basic',
|
||||
label: '框架风格',
|
||||
children: [
|
||||
{
|
||||
value: 'layout',
|
||||
label: 'Layout 布局'
|
||||
},
|
||||
{
|
||||
value: 'color',
|
||||
label: 'Color 色彩'
|
||||
},
|
||||
{
|
||||
value: 'font',
|
||||
label: 'Font 字体'
|
||||
},
|
||||
{
|
||||
value: 'icon',
|
||||
label: 'Icon 图标'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
value: 'form',
|
||||
label: '表单组件',
|
||||
children: [
|
||||
{
|
||||
value: 'radio',
|
||||
label: 'Radio 单选框'
|
||||
},
|
||||
{
|
||||
value: 'checkbox',
|
||||
label: 'Checkbox 多选框'
|
||||
},
|
||||
{
|
||||
value: 'input',
|
||||
label: 'Input 输入框'
|
||||
},
|
||||
{
|
||||
value: 'number',
|
||||
label: 'Numeric 计数器'
|
||||
},
|
||||
{
|
||||
value: 'select',
|
||||
label: 'Select 选择器'
|
||||
},
|
||||
{
|
||||
value: 'cascader',
|
||||
label: 'Cascader 级联选择器'
|
||||
},
|
||||
{
|
||||
value: 'switch',
|
||||
label: 'Switch 开关'
|
||||
},
|
||||
{
|
||||
value: 'slider',
|
||||
label: 'Slider 滑块'
|
||||
},
|
||||
{
|
||||
value: 'time-picker',
|
||||
label: 'TimePicker 时间选择器'
|
||||
},
|
||||
{
|
||||
value: 'date-picker',
|
||||
label: 'DatePicker 日期选择器'
|
||||
},
|
||||
{
|
||||
value: 'form',
|
||||
label: 'Form 表单'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
value: 'data',
|
||||
label: '数据组件',
|
||||
children: [
|
||||
{
|
||||
value: 'tree',
|
||||
label: 'Tree 树形控件'
|
||||
},
|
||||
{
|
||||
value: 'pager',
|
||||
label: 'Pager 分页'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
value: 'notice',
|
||||
label: '提示组件',
|
||||
children: [
|
||||
{
|
||||
value: 'alert',
|
||||
label: 'Alert 警告'
|
||||
},
|
||||
{
|
||||
value: 'loading',
|
||||
label: 'Loading 加载'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
value: 'navigation',
|
||||
label: '导航组件',
|
||||
children: [
|
||||
{
|
||||
value: 'menu',
|
||||
label: 'NavMenu 导航菜单'
|
||||
},
|
||||
{
|
||||
value: 'tabs',
|
||||
label: 'Tabs 标签页'
|
||||
},
|
||||
{
|
||||
value: 'breadcrumb',
|
||||
label: 'Breadcrumb 面包屑'
|
||||
},
|
||||
{
|
||||
value: 'steps',
|
||||
label: 'Steps 步骤条'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
value: 'others',
|
||||
label: '其他组件',
|
||||
children: [
|
||||
{
|
||||
value: 'rate',
|
||||
label: 'Rate 评分'
|
||||
},
|
||||
{
|
||||
value: 'tag',
|
||||
label: 'Tag 标签'
|
||||
},
|
||||
{
|
||||
value: 'usercontact',
|
||||
label: 'UserContact 联系人'
|
||||
},
|
||||
{
|
||||
value: 'slidebar',
|
||||
label: 'SlideBar 滚动块'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.cascader-panel-demo-props > :not(:last-child) {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,15 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('多选', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('cascader-panel#multiple')
|
||||
const multipleText1 = page.getByText(
|
||||
'选中值:[ [ "zhinan", "anzhuang", "xiangmudengji" ], [ "zhinan", "anzhuang", "huanjingzhunbei" ], [ "zhinan", "anzhuang", "anzhuangcli" ], [ "zhinan", "kaifa", "monishuju" ] ]'
|
||||
)
|
||||
await expect(multipleText1).toBeVisible()
|
||||
await page.getByRole('menuitem', { name: '创建项目' }).locator('span').nth(1).click()
|
||||
const multipleText2 = page.getByText(
|
||||
'选中值:[ [ "zhinan", "anzhuang", "xiangmudengji" ], [ "zhinan", "anzhuang", "huanjingzhunbei" ], [ "zhinan", "anzhuang", "anzhuangcli" ], [ "zhinan", "anzhuang", "chuangjianxiangmu" ], [ "zhinan", "kaifa", "monishuju" ] ]'
|
||||
)
|
||||
await expect(multipleText2).toBeVisible()
|
||||
})
|
|
@ -0,0 +1,234 @@
|
|||
<template>
|
||||
<div class="cascader-panel-demo-props">
|
||||
<div>
|
||||
选中值:<span>{{ value }}</span>
|
||||
</div>
|
||||
<tiny-cascader-panel
|
||||
v-model="value"
|
||||
:options="optionsCascader"
|
||||
:props="{
|
||||
multiple: true
|
||||
}"
|
||||
></tiny-cascader-panel>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { CascaderPanel } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyCascaderPanel: CascaderPanel
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value: [
|
||||
['zhinan', 'anzhuang', 'xiangmudengji'],
|
||||
['zhinan', 'anzhuang', 'huanjingzhunbei'],
|
||||
['zhinan', 'anzhuang', 'anzhuangcli'],
|
||||
['zhinan', 'kaifa', 'monishuju']
|
||||
],
|
||||
optionsCascader: [
|
||||
{
|
||||
value: 'zhinan',
|
||||
label: '指南',
|
||||
children: [
|
||||
{
|
||||
value: 'anzhuang',
|
||||
label: '安装',
|
||||
children: [
|
||||
{
|
||||
value: 'xiangmudengji',
|
||||
label: '项目登记'
|
||||
},
|
||||
{
|
||||
value: 'huanjingzhunbei',
|
||||
label: '环境准备'
|
||||
},
|
||||
{
|
||||
value: 'anzhuangcli',
|
||||
label: '安装 CLI'
|
||||
},
|
||||
{
|
||||
value: 'chuangjianxiangmu',
|
||||
label: '创建项目'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
value: 'kaifa',
|
||||
label: '开发',
|
||||
children: [
|
||||
{
|
||||
value: 'yinruzujian',
|
||||
label: '引入组件'
|
||||
},
|
||||
{
|
||||
value: 'monishuju',
|
||||
label: '模拟数据'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
value: 'zujian',
|
||||
label: '组件',
|
||||
children: [
|
||||
{
|
||||
value: 'basic',
|
||||
label: '框架风格',
|
||||
children: [
|
||||
{
|
||||
value: 'layout',
|
||||
label: 'Layout 布局'
|
||||
},
|
||||
{
|
||||
value: 'color',
|
||||
label: 'Color 色彩'
|
||||
},
|
||||
{
|
||||
value: 'font',
|
||||
label: 'Font 字体'
|
||||
},
|
||||
{
|
||||
value: 'icon',
|
||||
label: 'Icon 图标'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
value: 'form',
|
||||
label: '表单组件',
|
||||
children: [
|
||||
{
|
||||
value: 'radio',
|
||||
label: 'Radio 单选框'
|
||||
},
|
||||
{
|
||||
value: 'checkbox',
|
||||
label: 'Checkbox 多选框'
|
||||
},
|
||||
{
|
||||
value: 'input',
|
||||
label: 'Input 输入框'
|
||||
},
|
||||
{
|
||||
value: 'number',
|
||||
label: 'Numeric 计数器'
|
||||
},
|
||||
{
|
||||
value: 'select',
|
||||
label: 'Select 选择器'
|
||||
},
|
||||
{
|
||||
value: 'cascader',
|
||||
label: 'Cascader 级联选择器'
|
||||
},
|
||||
{
|
||||
value: 'switch',
|
||||
label: 'Switch 开关'
|
||||
},
|
||||
{
|
||||
value: 'slider',
|
||||
label: 'Slider 滑块'
|
||||
},
|
||||
{
|
||||
value: 'time-picker',
|
||||
label: 'TimePicker 时间选择器'
|
||||
},
|
||||
{
|
||||
value: 'date-picker',
|
||||
label: 'DatePicker 日期选择器'
|
||||
},
|
||||
{
|
||||
value: 'form',
|
||||
label: 'Form 表单'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
value: 'data',
|
||||
label: '数据组件',
|
||||
children: [
|
||||
{
|
||||
value: 'tree',
|
||||
label: 'Tree 树形控件'
|
||||
},
|
||||
{
|
||||
value: 'pager',
|
||||
label: 'Pager 分页'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
value: 'notice',
|
||||
label: '提示组件',
|
||||
children: [
|
||||
{
|
||||
value: 'alert',
|
||||
label: 'Alert 警告'
|
||||
},
|
||||
{
|
||||
value: 'loading',
|
||||
label: 'Loading 加载'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
value: 'navigation',
|
||||
label: '导航组件',
|
||||
children: [
|
||||
{
|
||||
value: 'menu',
|
||||
label: 'NavMenu 导航菜单'
|
||||
},
|
||||
{
|
||||
value: 'tabs',
|
||||
label: 'Tabs 标签页'
|
||||
},
|
||||
{
|
||||
value: 'breadcrumb',
|
||||
label: 'Breadcrumb 面包屑'
|
||||
},
|
||||
{
|
||||
value: 'steps',
|
||||
label: 'Steps 步骤条'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
value: 'others',
|
||||
label: '其他组件',
|
||||
children: [
|
||||
{
|
||||
value: 'rate',
|
||||
label: 'Rate 评分'
|
||||
},
|
||||
{
|
||||
value: 'tag',
|
||||
label: 'Tag 标签'
|
||||
},
|
||||
{
|
||||
value: 'usercontact',
|
||||
label: 'UserContact 联系人'
|
||||
},
|
||||
{
|
||||
value: 'slidebar',
|
||||
label: 'SlideBar 滚动块'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.cascader-panel-demo-props > :not(:last-child) {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
</style>
|
|
@ -30,6 +30,18 @@ export default {
|
|||
},
|
||||
codeFiles: ['custom-option-content.vue']
|
||||
},
|
||||
{
|
||||
demoId: 'multiple',
|
||||
name: {
|
||||
'zh-CN': '多选',
|
||||
'en-US': 'Multiple Choices'
|
||||
},
|
||||
desc: {
|
||||
'zh-CN': '<p>通过 <code>props.multiple = true</code> 来开启多选模式。</p>\n',
|
||||
'en-US': '<p>Use <code>props.multiple = true</code> to enable the multi-selection mode. </p>\n'
|
||||
},
|
||||
codeFiles: ['multiple.vue']
|
||||
},
|
||||
{
|
||||
demoId: 'cascader-panel-props',
|
||||
name: {
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>
|
||||
关键字:<tiny-input v-model="query" placeholder="输入关键字,观察下面的高亮"></tiny-input>
|
||||
<tiny-button @click="changeList">修改内容</tiny-button>
|
||||
</div>
|
||||
|
||||
<div>避免场景1: 直接包含文字节点</div>
|
||||
<div v-highlight-query="query">
|
||||
{{ list.join(',') }}
|
||||
</div>
|
||||
<br />
|
||||
<div>避免场景2:文字节点与其它组件混合</div>
|
||||
<div v-highlight-query="query">
|
||||
{{ list.join(',') }}
|
||||
<tiny-input></tiny-input>
|
||||
</div>
|
||||
<br />
|
||||
<div>正确的场景1</div>
|
||||
<div v-highlight-query="query">
|
||||
<span> {{ list.join(',') }}</span>
|
||||
</div>
|
||||
<br />
|
||||
<div>正确的场景2</div>
|
||||
<div v-highlight-query="query">
|
||||
<span> {{ list.join(',') }}</span>
|
||||
<tiny-input></tiny-input>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { Input as TinyInput, Button as TinyButton } from '@opentiny/vue'
|
||||
import { HighlightQuery as vHighlightQuery } from '@opentiny/vue-directive'
|
||||
|
||||
const query = ref('一片')
|
||||
const list = ref(['一片一片又一片', '两片三片四五片', '六片七片八九片', '飞入芦花都不见'])
|
||||
|
||||
const changeList = () => (list.value = ['江上一笼统', '井上黑窟窿', '黄狗身上白', '白狗身上肿'])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-input {
|
||||
width: 280px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
div {
|
||||
line-height: 2;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,15 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('避免用法', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('directives-highlight-query#avoid')
|
||||
|
||||
const input = page.locator('.pc-demo-container .tiny-input-inner').first()
|
||||
const hlNode = page.locator('.pc-demo-container .tiny-hl-query-node')
|
||||
const button = page.locator('.pc-demo-container .tiny-button')
|
||||
|
||||
await expect(hlNode).toHaveCount(12)
|
||||
|
||||
await button.click()
|
||||
await expect(hlNode).toHaveCount(6)
|
||||
})
|
|
@ -0,0 +1,65 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>
|
||||
关键字:<tiny-input v-model="query" placeholder="输入关键字,观察下面的高亮"></tiny-input>
|
||||
<tiny-button @click="changeList">修改内容</tiny-button>
|
||||
</div>
|
||||
|
||||
<div>避免场景1: 直接包含文字节点</div>
|
||||
<div v-highlight-query="query">
|
||||
{{ list.join(',') }}
|
||||
</div>
|
||||
<br />
|
||||
<div>避免场景2:文字节点与其它组件混合</div>
|
||||
<div v-highlight-query="query">
|
||||
{{ list.join(',') }}
|
||||
<tiny-input></tiny-input>
|
||||
</div>
|
||||
<br />
|
||||
<div>正确的场景1</div>
|
||||
<div v-highlight-query="query">
|
||||
<span> {{ list.join(',') }}</span>
|
||||
</div>
|
||||
<br />
|
||||
<div>正确的场景2</div>
|
||||
<div v-highlight-query="query">
|
||||
<span> {{ list.join(',') }}</span>
|
||||
<tiny-input></tiny-input>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { HighlightQuery } from '@opentiny/vue-directive'
|
||||
import { Input, Button } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
directives: { HighlightQuery },
|
||||
components: {
|
||||
TinyInput: Input,
|
||||
TinyButton: Button
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
query: '一片',
|
||||
list: ['一片一片又一片', '两片三片四五片', '六片七片八九片', '飞入芦花都不见']
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeList() {
|
||||
this.list = ['江上一笼统', '井上黑窟窿', '黄狗身上白', '白狗身上肿']
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-input {
|
||||
width: 280px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
div {
|
||||
line-height: 2;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,31 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>关键字:<tiny-input v-model="query" placeholder="输入关键字,观察下面的高亮"></tiny-input></div>
|
||||
<div v-highlight-query="query">
|
||||
<ul>
|
||||
<li v-for="line in list" :key="line">
|
||||
{{ line }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { Input as TinyInput } from '@opentiny/vue'
|
||||
import { HighlightQuery as vHighlightQuery } from '@opentiny/vue-directive'
|
||||
|
||||
const query = ref('')
|
||||
const list = ref(['一片一片又一片', '两片三片四五片', '六片七片八九片', '飞入芦花都不见'])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-input {
|
||||
width: 280px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
li {
|
||||
line-height: 2;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,12 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('基本用法', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('directives-highlight-query#basic-usage')
|
||||
|
||||
const input = page.locator('.pc-demo-container .tiny-input__inner')
|
||||
const hlNode = page.locator('.pc-demo-container .tiny-hl-query-node')
|
||||
|
||||
await input.fill('一片')
|
||||
await expect(hlNode).toHaveCount(3)
|
||||
})
|
|
@ -0,0 +1,40 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>关键字:<tiny-input v-model="query" placeholder="输入关键字,观察下面的高亮"></tiny-input></div>
|
||||
<div v-highlight-query="query">
|
||||
<ul>
|
||||
<li v-for="line in list" :key="line">
|
||||
{{ line }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { HighlightQuery } from '@opentiny/vue-directive'
|
||||
import { Input } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
directives: { HighlightQuery },
|
||||
components: {
|
||||
TinyInput: Input
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
query: '',
|
||||
list: ['一片一片又一片', '两片三片四五片', '六片七片八九片', '飞入芦花都不见']
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-input {
|
||||
width: 280px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
li {
|
||||
line-height: 2;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
title: HighlightQuery 高亮搜索字
|
||||
---
|
||||
|
||||
# HighlightQuery 高亮搜索字
|
||||
|
||||
<div>HighlightQuery 高亮搜索字指令,用于高亮区个区域的匹配字符。</div>
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
title: HighlightQuery Highlight search word
|
||||
---
|
||||
|
||||
# HighlightQuery Highlight search word
|
||||
|
||||
<div>HighlightQuery Highlight search word command, which is used to match characters in each area of the highlight area. </div>
|
|
@ -0,0 +1,39 @@
|
|||
export default {
|
||||
column: '2',
|
||||
owner: '',
|
||||
metaData: {
|
||||
stable: '3.18.0'
|
||||
},
|
||||
versionTipOption: {
|
||||
stages: ['stable']
|
||||
},
|
||||
demos: [
|
||||
{
|
||||
demoId: 'basic-usage',
|
||||
name: {
|
||||
'zh-CN': '基本用法',
|
||||
'en-US': 'Basic Usage'
|
||||
},
|
||||
desc: {
|
||||
'zh-CN': '通过自动高亮搜索字指令,可以自动高亮某个节点下,所有匹配的字符。',
|
||||
'en-US':
|
||||
'You can use the automatic highlight search word command to automatically highlight all matched characters under a node.'
|
||||
},
|
||||
codeFiles: ['highlight-query/basic-usage.vue']
|
||||
},
|
||||
{
|
||||
demoId: 'avoid',
|
||||
name: {
|
||||
'zh-CN': '避免场景',
|
||||
'en-US': 'Basic Usage'
|
||||
},
|
||||
desc: {
|
||||
'zh-CN':
|
||||
'纯文字节点在<code>Vue</code> 编译时有特殊处理。自动高亮搜索字的指令是直接处理<code>Dom</code>节点的内容,所以要避免纯文本节点。以下2个场景会造成<code>Vue</code> 更新机制失败。',
|
||||
'en-US':
|
||||
'Plain text nodes are specially processed during <code>Vue</code> compilation. The instruction for automatically highlighting search words is to directly process the contents of the <code>Dom</code> node, so avoid plain text nodes. The <code>Vue</code> update mechanism fails in the following scenarios:'
|
||||
},
|
||||
codeFiles: ['highlight-query/avoid.vue']
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>场景1:初始全加载</div>
|
||||
<br />
|
||||
<tiny-dropdown>
|
||||
<span>下拉菜单</span>
|
||||
<template #dropdown>
|
||||
<tiny-dropdown-menu>
|
||||
<tiny-dropdown-item>黄金糕</tiny-dropdown-item>
|
||||
<tiny-dropdown-item>狮子头</tiny-dropdown-item>
|
||||
<tiny-dropdown-item>螺蛳粉</tiny-dropdown-item>
|
||||
<tiny-dropdown-item disabled>双皮奶</tiny-dropdown-item>
|
||||
<tiny-dropdown-item divided>蚵仔煎</tiny-dropdown-item>
|
||||
</tiny-dropdown-menu>
|
||||
</template>
|
||||
</tiny-dropdown>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景2:初始不加载菜单及子项,适合表格等大数量的场景</div>
|
||||
<br />
|
||||
<tiny-dropdown lazy-show-popper>
|
||||
<span>下拉菜单</span>
|
||||
<template #dropdown>
|
||||
<tiny-dropdown-menu>
|
||||
<tiny-dropdown-item>黄金糕</tiny-dropdown-item>
|
||||
<tiny-dropdown-item>狮子头</tiny-dropdown-item>
|
||||
<tiny-dropdown-item>螺蛳粉</tiny-dropdown-item>
|
||||
<tiny-dropdown-item disabled>双皮奶</tiny-dropdown-item>
|
||||
<tiny-dropdown-item divided>蚵仔煎</tiny-dropdown-item>
|
||||
</tiny-dropdown-menu>
|
||||
</template>
|
||||
</tiny-dropdown>
|
||||
<br />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
Dropdown as TinyDropdown,
|
||||
DropdownMenu as TinyDropdownMenu,
|
||||
DropdownItem as TinyDropdownItem
|
||||
} from '@opentiny/vue'
|
||||
</script>
|
|
@ -0,0 +1,20 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('基本用法', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('dropdown#lazy-show-popper')
|
||||
|
||||
const wrap = page.locator('#lazy-show-popper')
|
||||
const dropDownLi = wrap.locator('.tiny-dropdown li')
|
||||
const dropDownOnBody = page.locator('body .tiny-dropdown-menu li')
|
||||
|
||||
const dropDown2 = wrap.locator('.tiny-dropdown').nth(1)
|
||||
|
||||
// 2个示例应该是10个菜单项, 懒加载成功的话,应该只加载5个。
|
||||
await expect(dropDownLi).toHaveCount(5)
|
||||
|
||||
// 点击后,应该加载10个, 但展开的5项是 appendToBody的。
|
||||
await dropDown2.click()
|
||||
await expect(dropDownLi).toHaveCount(5)
|
||||
await expect(dropDownOnBody).toHaveCount(5)
|
||||
})
|
|
@ -0,0 +1,47 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>场景1:初始全加载</div>
|
||||
<br />
|
||||
<tiny-dropdown>
|
||||
<span>下拉菜单</span>
|
||||
<template #dropdown>
|
||||
<tiny-dropdown-menu>
|
||||
<tiny-dropdown-item>黄金糕</tiny-dropdown-item>
|
||||
<tiny-dropdown-item>狮子头</tiny-dropdown-item>
|
||||
<tiny-dropdown-item>螺蛳粉</tiny-dropdown-item>
|
||||
<tiny-dropdown-item disabled>双皮奶</tiny-dropdown-item>
|
||||
<tiny-dropdown-item divided>蚵仔煎</tiny-dropdown-item>
|
||||
</tiny-dropdown-menu>
|
||||
</template>
|
||||
</tiny-dropdown>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景2:初始不加载菜单及子项,适合表格等大数量的场景</div>
|
||||
<br />
|
||||
<tiny-dropdown lazy-show-popper>
|
||||
<span>下拉菜单</span>
|
||||
<template #dropdown>
|
||||
<tiny-dropdown-menu>
|
||||
<tiny-dropdown-item>黄金糕</tiny-dropdown-item>
|
||||
<tiny-dropdown-item>狮子头</tiny-dropdown-item>
|
||||
<tiny-dropdown-item>螺蛳粉</tiny-dropdown-item>
|
||||
<tiny-dropdown-item disabled>双皮奶</tiny-dropdown-item>
|
||||
<tiny-dropdown-item divided>蚵仔煎</tiny-dropdown-item>
|
||||
</tiny-dropdown-menu>
|
||||
</template>
|
||||
</tiny-dropdown>
|
||||
<br />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Dropdown, DropdownMenu, DropdownItem } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyDropdown: Dropdown,
|
||||
TinyDropdownMenu: DropdownMenu,
|
||||
TinyDropdownItem: DropdownItem
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -231,6 +231,19 @@ export default {
|
|||
'<p><code>button-click</code>: When the button type is selected, listen for the left button click event.</p>\n<p><code>item-click</code>: Listens for menu item click events</p>\n<p><code>visible-change</code>: Listens for changes in the display and hiding of dropdown pop ups.</p>\n'
|
||||
},
|
||||
codeFiles: ['events.vue']
|
||||
},
|
||||
{
|
||||
demoId: 'lazy-show-popper',
|
||||
name: {
|
||||
'zh-CN': '懒加载菜单和子项',
|
||||
'en-US': 'Lazy Load Menus and Subitems'
|
||||
},
|
||||
desc: {
|
||||
'zh-CN': '通过 <code>lazy-show-popper </code>属性,指定是否懒加载下拉菜单及内部的项',
|
||||
'en-US':
|
||||
'The <code>lazy-show-popper </code> property specifies whether to lazy load the drop-down menu and internal items.'
|
||||
},
|
||||
codeFiles: ['lazy-show-popper.vue']
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
<template>
|
||||
<div style="height: 540px">
|
||||
<tiny-file-upload
|
||||
ref="upload"
|
||||
:action="action"
|
||||
accept=".doc,.docx"
|
||||
:file-list="fileList"
|
||||
list-type="saas"
|
||||
:file-size="[100, 200]"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { FileUpload } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyFileUpload: FileUpload
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
action: 'http://localhost:3000/api/upload',
|
||||
fileList: [
|
||||
{
|
||||
docId: 'M1T2A1N548572512085860351',
|
||||
path: 'edm/one/',
|
||||
docVersion: 'V1',
|
||||
name: 'test1.png',
|
||||
docSize: 100 * 1024,
|
||||
size: 100 * 1024,
|
||||
serverName: 'ShenZhen'
|
||||
},
|
||||
{
|
||||
docId: 'M1T2A1N548572512085860352',
|
||||
path: 'edm/one/',
|
||||
docVersion: 'V1',
|
||||
name: 'test2.doc',
|
||||
docSize: 17252 * 1024,
|
||||
size: 17252 * 1024,
|
||||
serverName: 'ShenZhen'
|
||||
},
|
||||
{
|
||||
docId: 'M1T2A1N548572512085860353',
|
||||
path: 'edm/one/',
|
||||
docVersion: 'V1',
|
||||
name: 'test3.png',
|
||||
docSize: 200 * 1024,
|
||||
size: 200 * 1024,
|
||||
serverName: 'ShenZhen',
|
||||
status: 'uploading',
|
||||
percentage: 30
|
||||
},
|
||||
{
|
||||
docId: 'M1T2A1N548572512085860353',
|
||||
path: 'edm/one/',
|
||||
docVersion: 'V1',
|
||||
name: 'test4.doc',
|
||||
docSize: 17252 * 1024,
|
||||
size: 17252 * 1024,
|
||||
serverName: 'ShenZhen',
|
||||
status: 'fail',
|
||||
percentage: 30
|
||||
},
|
||||
{
|
||||
docId: 'M1T2A1N548572512085860353',
|
||||
path: 'edm/one/',
|
||||
docVersion: 'V1',
|
||||
name: 'test5超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长.doc',
|
||||
docSize: 17252 * 1024,
|
||||
size: 17252 * 1024,
|
||||
serverName: 'ShenZhen'
|
||||
},
|
||||
{
|
||||
docId: 'M1T2A1N548572512085860353',
|
||||
path: 'edm/one/',
|
||||
docVersion: 'V1',
|
||||
name: '没有文件大小.doc',
|
||||
serverName: 'ShenZhen'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,78 @@
|
|||
<template>
|
||||
<div style="height: 540px">
|
||||
<tiny-file-upload ref="upload" :action="action" :file-list="fileList" list-type="saas" :file-size="100" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { FileUpload } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyFileUpload: FileUpload
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
action: 'http://localhost:3000/api/upload',
|
||||
fileList: [
|
||||
{
|
||||
docId: 'M1T2A1N548572512085860351',
|
||||
path: 'edm/one/',
|
||||
docVersion: 'V1',
|
||||
name: 'test1.png',
|
||||
docSize: 100 * 1024,
|
||||
size: 100 * 1024,
|
||||
serverName: 'ShenZhen'
|
||||
},
|
||||
{
|
||||
docId: 'M1T2A1N548572512085860352',
|
||||
path: 'edm/one/',
|
||||
docVersion: 'V1',
|
||||
name: 'test2.doc',
|
||||
docSize: 17252 * 1024,
|
||||
size: 17252 * 1024,
|
||||
serverName: 'ShenZhen'
|
||||
},
|
||||
{
|
||||
docId: 'M1T2A1N548572512085860353',
|
||||
path: 'edm/one/',
|
||||
docVersion: 'V1',
|
||||
name: 'test3.png',
|
||||
docSize: 200 * 1024,
|
||||
size: 200 * 1024,
|
||||
serverName: 'ShenZhen',
|
||||
status: 'uploading',
|
||||
percentage: 30
|
||||
},
|
||||
{
|
||||
docId: 'M1T2A1N548572512085860353',
|
||||
path: 'edm/one/',
|
||||
docVersion: 'V1',
|
||||
name: 'test4.doc',
|
||||
docSize: 17252 * 1024,
|
||||
size: 17252 * 1024,
|
||||
serverName: 'ShenZhen',
|
||||
status: 'fail',
|
||||
percentage: 30
|
||||
},
|
||||
{
|
||||
docId: 'M1T2A1N548572512085860353',
|
||||
path: 'edm/one/',
|
||||
docVersion: 'V1',
|
||||
name: 'test5超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长.doc',
|
||||
docSize: 17252 * 1024,
|
||||
size: 17252 * 1024,
|
||||
serverName: 'ShenZhen'
|
||||
},
|
||||
{
|
||||
docId: 'M1T2A1N548572512085860353',
|
||||
path: 'edm/one/',
|
||||
docVersion: 'V1',
|
||||
name: '没有文件大小.doc',
|
||||
serverName: 'ShenZhen'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -189,6 +189,30 @@ export default {
|
|||
},
|
||||
codeFiles: ['upload-file-list.vue']
|
||||
},
|
||||
{
|
||||
demoId: 'file-size',
|
||||
name: {
|
||||
'zh-CN': '文件大小限制',
|
||||
'en-US': 'Uploaded file size limit'
|
||||
},
|
||||
desc: {
|
||||
'zh-CN': '<p>通过 <code>file-size</code> 配置上传文件的大小。<p>',
|
||||
'en-US': '<p>Use <code>file-size</code> to configure the size of the uploaded file.</p>'
|
||||
},
|
||||
codeFiles: ['file-size.vue']
|
||||
},
|
||||
{
|
||||
demoId: 'file-size-array',
|
||||
name: {
|
||||
'zh-CN': '文件大小范围',
|
||||
'en-US': 'Uploaded file size range'
|
||||
},
|
||||
desc: {
|
||||
'zh-CN': '<p>通过 <code>file-size</code> 配置为数组类型限制上传文件的大小范围。<p>',
|
||||
'en-US': '<p>Set <code>file-size</code> to an array to limit the size of the file to be uploaded.</p>'
|
||||
},
|
||||
codeFiles: ['file-size-array.vue']
|
||||
},
|
||||
{
|
||||
demoId: 'upload-file-list-slot',
|
||||
name: {
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
<template>
|
||||
<div>
|
||||
<tiny-button @click="changeFlag">{{ flag ? '隐藏' : '显示' }}最后一列</tiny-button>
|
||||
<tiny-grid
|
||||
ref="grid"
|
||||
column-width="200"
|
||||
:data="tableData"
|
||||
:resizable="true"
|
||||
:optimization="{ scrollX: { gt: 15, rSize: 20 } }"
|
||||
@after-refresh-column="handleAfterRefresh"
|
||||
>
|
||||
<tiny-grid-column field="name" :title="(h) => h('div', '名称')"></tiny-grid-column>
|
||||
<tiny-grid-column field="englishName" title="英文名"></tiny-grid-column>
|
||||
<tiny-grid-column field="established" title="成立时间" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="listed" title="是否上市"></tiny-grid-column>
|
||||
<tiny-grid-column field="ranking" title="国内排名" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="registeredCapital" title="注册资本" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="businessScope" title="业务范围"></tiny-grid-column>
|
||||
<tiny-grid-column field="employees" title="员工数" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="address" title="地址"></tiny-grid-column>
|
||||
<tiny-grid-column field="englishName" title="英文名"></tiny-grid-column>
|
||||
<tiny-grid-column field="established" title="成立时间" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="listed" title="是否上市"></tiny-grid-column>
|
||||
<tiny-grid-column field="ranking" title="国内排名" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="registeredCapital" title="注册资本" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="businessScope" title="业务范围"></tiny-grid-column>
|
||||
<tiny-grid-column field="employees" title="员工数" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="address" title="地址"></tiny-grid-column>
|
||||
<tiny-grid-column field="englishName" title="英文名"></tiny-grid-column>
|
||||
<tiny-grid-column field="established" title="成立时间" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="listed" title="是否上市1"></tiny-grid-column>
|
||||
<tiny-grid-column field="ranking" title="国内排名1" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="registeredCapital" title="注册资本1" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="businessScope" title="业务范围1"></tiny-grid-column>
|
||||
<tiny-grid-column field="employees" title="员工数1" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="address" title="地址1"></tiny-grid-column>
|
||||
<tiny-grid-column field="englishName" title="英文名2"></tiny-grid-column>
|
||||
<tiny-grid-column field="established" title="成立时间2" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="listed" title="是否上市2"></tiny-grid-column>
|
||||
<tiny-grid-column field="ranking" title="国内排名2" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="registeredCapital" title="注册资本2" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="businessScope" title="业务范围2"></tiny-grid-column>
|
||||
<tiny-grid-column field="employees" title="员工数2" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="address" title="地址2"></tiny-grid-column>
|
||||
<tiny-grid-column v-if="flag" field="introduction" title="公司简介(最后一列)" show-overflow></tiny-grid-column>
|
||||
</tiny-grid>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Grid as TinyGrid, GridColumn as TinyGridColumn, Button as TinyButton } from '@opentiny/vue'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const flag = ref(false)
|
||||
|
||||
const tableData = ref([
|
||||
{
|
||||
id: '1',
|
||||
name: 'GFD科技有限公司',
|
||||
address: '福州',
|
||||
introduction: '公司技术和研发实力雄厚,是国家863项目的参与者,并被政府认定为“高新技术企业”。',
|
||||
employees: 800,
|
||||
englishName: 'GFD',
|
||||
established: '2005',
|
||||
listed: '是',
|
||||
ranking: '23',
|
||||
registeredCapital: '2000万',
|
||||
businessScope: '食品'
|
||||
}
|
||||
])
|
||||
|
||||
const grid = ref()
|
||||
|
||||
function changeFlag() {
|
||||
flag.value = !flag.value
|
||||
}
|
||||
function handleAfterRefresh() {
|
||||
const fullColumn = grid.value.getTableColumn().fullColumn
|
||||
console.log(fullColumn[fullColumn.length - 1])
|
||||
}
|
||||
</script>
|
|
@ -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#column-switching-scroll')
|
||||
const demo = page.locator('#column-switching-scroll')
|
||||
|
||||
await demo.locator('.tiny-grid__body-wrapper.body__wrapper').click()
|
||||
await page.mouse.wheel(10000, 0)
|
||||
|
||||
await expect(demo.getByText('地址2')).toBeVisible()
|
||||
await demo.getByText('显示最后一列').click()
|
||||
await expect(demo.getByText('地址2')).toBeVisible()
|
||||
})
|
|
@ -0,0 +1,89 @@
|
|||
<template>
|
||||
<div>
|
||||
<tiny-button @click="changeFlag">{{ flag ? '隐藏' : '显示' }}最后一列</tiny-button>
|
||||
<tiny-grid
|
||||
ref="grid"
|
||||
column-width="200"
|
||||
:data="tableData"
|
||||
:resizable="true"
|
||||
:optimization="{ scrollX: { gt: 15, rSize: 20 } }"
|
||||
@after-refresh-column="handleAfterRefresh"
|
||||
>
|
||||
<tiny-grid-column field="name" :title="(h) => h('div', '名称')"></tiny-grid-column>
|
||||
<tiny-grid-column field="englishName" title="英文名"></tiny-grid-column>
|
||||
<tiny-grid-column field="established" title="成立时间" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="listed" title="是否上市"></tiny-grid-column>
|
||||
<tiny-grid-column field="ranking" title="国内排名" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="registeredCapital" title="注册资本" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="businessScope" title="业务范围"></tiny-grid-column>
|
||||
<tiny-grid-column field="employees" title="员工数" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="address" title="地址"></tiny-grid-column>
|
||||
<tiny-grid-column field="englishName" title="英文名"></tiny-grid-column>
|
||||
<tiny-grid-column field="established" title="成立时间" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="listed" title="是否上市"></tiny-grid-column>
|
||||
<tiny-grid-column field="ranking" title="国内排名" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="registeredCapital" title="注册资本" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="businessScope" title="业务范围"></tiny-grid-column>
|
||||
<tiny-grid-column field="employees" title="员工数" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="address" title="地址"></tiny-grid-column>
|
||||
<tiny-grid-column field="englishName" title="英文名"></tiny-grid-column>
|
||||
<tiny-grid-column field="established" title="成立时间" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="listed" title="是否上市1"></tiny-grid-column>
|
||||
<tiny-grid-column field="ranking" title="国内排名1" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="registeredCapital" title="注册资本1" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="businessScope" title="业务范围1"></tiny-grid-column>
|
||||
<tiny-grid-column field="employees" title="员工数1" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="address" title="地址1"></tiny-grid-column>
|
||||
<tiny-grid-column field="englishName" title="英文名2"></tiny-grid-column>
|
||||
<tiny-grid-column field="established" title="成立时间2" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="listed" title="是否上市2"></tiny-grid-column>
|
||||
<tiny-grid-column field="ranking" title="国内排名2" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="registeredCapital" title="注册资本2" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="businessScope" title="业务范围2"></tiny-grid-column>
|
||||
<tiny-grid-column field="employees" title="员工数2" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="address" title="地址2"></tiny-grid-column>
|
||||
<tiny-grid-column v-if="flag" field="introduction" title="公司简介(最后一列)" show-overflow></tiny-grid-column>
|
||||
</tiny-grid>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Grid, GridColumn, Button } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyButton: Button,
|
||||
TinyGrid: Grid,
|
||||
TinyGridColumn: GridColumn
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
flag: false,
|
||||
tableData: [
|
||||
{
|
||||
id: '1',
|
||||
name: 'GFD科技有限公司',
|
||||
address: '福州',
|
||||
introduction: '公司技术和研发实力雄厚,是国家863项目的参与者,并被政府认定为“高新技术企业”。',
|
||||
employees: 800,
|
||||
englishName: 'GFD',
|
||||
established: '2005',
|
||||
listed: '是',
|
||||
ranking: '23',
|
||||
registeredCapital: '2000万',
|
||||
businessScope: '食品'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeFlag() {
|
||||
this.flag = !this.flag
|
||||
},
|
||||
handleAfterRefresh() {
|
||||
const fullColumn = this.$refs.grid.getTableColumn().fullColumn
|
||||
console.log(fullColumn[fullColumn.length - 1])
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -14,6 +14,18 @@ export default {
|
|||
},
|
||||
'codeFiles': ['dynamically-columns/dynamically-columns.vue']
|
||||
},
|
||||
{
|
||||
'demoId': 'column-switching-scroll',
|
||||
'name': {
|
||||
'zh-CN': '新增列滚动位置',
|
||||
'en-US': 'New columns scroll positon'
|
||||
},
|
||||
'desc': {
|
||||
'zh-CN': '根据日期范围选择框的日期范围动态的生成表格列。',
|
||||
'en-US': 'For details, see the following example.'
|
||||
},
|
||||
'codeFiles': ['dynamically-columns/column-switching-scroll.vue']
|
||||
},
|
||||
{
|
||||
'demoId': 'column-columns-dynamic',
|
||||
'name': { 'zh-CN': '动态列数据', 'en-US': '' },
|
||||
|
|
|
@ -1,42 +1,249 @@
|
|||
export const iconGroups = {
|
||||
Arrow: [
|
||||
'IconArrowDown',
|
||||
Left: [
|
||||
'IconAngleLeft',
|
||||
'IconArrowLeft',
|
||||
'IconArrowRight',
|
||||
'IconArrowUp',
|
||||
'IconAscending',
|
||||
'IconChevronDown',
|
||||
'IconChevronLeft',
|
||||
'IconChevronRight',
|
||||
'IconChevronUp',
|
||||
'IconDefault',
|
||||
'IconDeltaDownO',
|
||||
'IconDeltaDown',
|
||||
'IconDeltaLeftO',
|
||||
'IconDeltaLeft',
|
||||
'IconDeltaRightO',
|
||||
'IconDeltaRight',
|
||||
'IconDeltaUpO',
|
||||
'IconDeltaUp',
|
||||
'IconDoubleLeft',
|
||||
'IconDoubleRight',
|
||||
'IconDownO',
|
||||
'IconDown',
|
||||
'IconDownWard',
|
||||
'IconEnd',
|
||||
'IconLeft',
|
||||
'IconLeftO',
|
||||
'IconLeftWard',
|
||||
'IconLeftWardArrow',
|
||||
'IconLeft',
|
||||
'IconPopup',
|
||||
'IconRightO',
|
||||
'IconDeltaLeft',
|
||||
'IconPagerFirst',
|
||||
'IconPagerPrev',
|
||||
'IconRichTextAlignLeft',
|
||||
'IconSplitLeft',
|
||||
'IconUndo'
|
||||
],
|
||||
Right: [
|
||||
'IconArrowRight',
|
||||
'IconAngleRight',
|
||||
'IconChevronRight',
|
||||
'IconDeltaRight',
|
||||
'IconDeltaRightO',
|
||||
'IconDoubleRight',
|
||||
'IconEnd',
|
||||
'IconPagerLast',
|
||||
'IconPagerNext',
|
||||
'IconRedo',
|
||||
'IconRight',
|
||||
'IconRightO',
|
||||
'IconRichTextRedo',
|
||||
'IconRichTextAlignRight',
|
||||
'IconRightward',
|
||||
'IconTriangleDown',
|
||||
'IconUpO',
|
||||
'IconSplitRight',
|
||||
'IconStart',
|
||||
'IconTransform'
|
||||
],
|
||||
TextAlign: [
|
||||
'IconAlignCenter',
|
||||
'IconAlignLeft',
|
||||
'IconAlignJustify',
|
||||
'IconAlignRight',
|
||||
'IconAlignStretch',
|
||||
'IconStreamSolid',
|
||||
'IconRichTextAddColumnAfter',
|
||||
'IconRichTextAddColumnBefore',
|
||||
'IconRichTextAddRowAfter',
|
||||
'IconRichTextAddRowBefore',
|
||||
'IconRichTextAlignCenter',
|
||||
'IconRichTextDeleteColumn',
|
||||
'IconRichTextDeleteRow',
|
||||
'IconRichTextLineHeight',
|
||||
'IconRichTextListOrdered',
|
||||
'IconRichTextListUnordered',
|
||||
'IconRichTextMergeCells',
|
||||
'IconRichTextMergeCellsVertical',
|
||||
'IconRichTextSplitCellsHorizontal',
|
||||
'IconRichTextSplitCellsVertical',
|
||||
'IconRichTextTable',
|
||||
'IconRichTextTaskList',
|
||||
'IconSplit'
|
||||
],
|
||||
Upward: [
|
||||
'IconArrowUp',
|
||||
'IconChevronUp',
|
||||
'IconDeltaUp',
|
||||
'IconDeltaUpO',
|
||||
'IconFreeze',
|
||||
'IconUp',
|
||||
'IconUpO',
|
||||
'IconUpWard'
|
||||
],
|
||||
Downward: [
|
||||
'IconArrowBottom',
|
||||
'IconArrowDown',
|
||||
'IconChevronDown',
|
||||
'IconDeltaDown',
|
||||
'IconDeltaDownO',
|
||||
'IconDown',
|
||||
'IconDownO',
|
||||
'IconDownWard',
|
||||
'IconTriangleDown'
|
||||
],
|
||||
Back: ['IconEditorUndo', 'IconGoBack', 'IconImport', 'IconRichTextUndo'],
|
||||
Cycle: [
|
||||
'IconConmentRefresh',
|
||||
'IconDownload',
|
||||
'IconGenerating',
|
||||
'IconGroupTransfer',
|
||||
'IconReplace',
|
||||
'IconRefres',
|
||||
'IconRefresh',
|
||||
'IconRepeat',
|
||||
'IconUpload'
|
||||
],
|
||||
Sort: [
|
||||
'IconAscending',
|
||||
'IconDescending',
|
||||
'IconSort',
|
||||
'IconSortDefault',
|
||||
'IconSortO',
|
||||
'IconSortTriangle',
|
||||
'IconSortTriangleAscending',
|
||||
'IconSortTriangleDescending'
|
||||
],
|
||||
Filter: ['IconBefilter', 'IconClearFilter', 'IconDefinedFiltration', 'IconFilter', 'IconFiltered', 'IconUnfilter'],
|
||||
Reduce: [
|
||||
'IconExpand',
|
||||
'IconMinus',
|
||||
'IconMinusCircle',
|
||||
'IconMinusSquare',
|
||||
'IconNodeOpen',
|
||||
'IconPanelMini',
|
||||
'IconStop',
|
||||
'IconZoomOut'
|
||||
],
|
||||
Add: [
|
||||
'IconAdd',
|
||||
'IconAddCircle',
|
||||
'IconNew',
|
||||
'IconNode',
|
||||
'IconPlus',
|
||||
'IconPlusSquare',
|
||||
'IconPlusCircle',
|
||||
'IconPutAway',
|
||||
'IconView',
|
||||
'IconZoomIn'
|
||||
],
|
||||
Check: [
|
||||
'IconCheck',
|
||||
'IconHalfchecked',
|
||||
'IconHalfselect',
|
||||
'IconMobileCheckbox',
|
||||
'IconMobileCheckboxHalf',
|
||||
'IconPreChecked'
|
||||
],
|
||||
Success: [
|
||||
'IconCheckedLinear',
|
||||
'IconCheckedSur',
|
||||
'IconDone',
|
||||
'IconFinish',
|
||||
'IconMobileCheckboxSelected',
|
||||
'IconSubScript',
|
||||
'IconSuccess',
|
||||
'IconSuccessful',
|
||||
'IconYes'
|
||||
],
|
||||
Fail: [
|
||||
'IconClose',
|
||||
'IconCloseCircle',
|
||||
'IconCloseSquare',
|
||||
'IconDelete',
|
||||
'IconError',
|
||||
'IconOperationfaild',
|
||||
'IconOperationfaildL',
|
||||
'IconStepsError'
|
||||
],
|
||||
Warn: [
|
||||
'IconCueL',
|
||||
'IconCueLO',
|
||||
'IconExceptionO',
|
||||
'IconExclamation',
|
||||
'IconWarn',
|
||||
'IconWarning',
|
||||
'IconWarningO',
|
||||
'IconWarningTriangle'
|
||||
],
|
||||
Question: ['IconHelpCircle', 'IconHelpQuery', 'IconUnknow', 'IconUnknown'],
|
||||
Prompt: [
|
||||
'IconInfo',
|
||||
'IconInfoCircle',
|
||||
'IconInfoSolid',
|
||||
'IconHelp',
|
||||
'IconHelpSolid',
|
||||
'IconPrompt',
|
||||
'IconPromptExclamation'
|
||||
],
|
||||
Stretchable: [
|
||||
'IconFullscreenLeft',
|
||||
'IconMinscreenLeft',
|
||||
'IconMinscreenRight',
|
||||
'IconStretch',
|
||||
'IconStretchCrosswise',
|
||||
'IconStretchUpright'
|
||||
],
|
||||
More: ['IconEllipsis', 'IconMore', 'IconPopup'],
|
||||
Dot: [
|
||||
'IconDotIpv4',
|
||||
'IconLeave',
|
||||
'IconOffLine',
|
||||
'IconOnLine',
|
||||
'IconBusy',
|
||||
'IconDoneMini',
|
||||
'IconOnGoing',
|
||||
'IconOnGoingMini',
|
||||
'IconMobileRadio',
|
||||
'IconExceptionMiniO',
|
||||
'IconMobileRadioSelected',
|
||||
'IconOperation',
|
||||
'IconRadio',
|
||||
'IconRadioselected'
|
||||
],
|
||||
Location: ['IconLocation', 'IconLocationNumber', 'IconMarkOn'],
|
||||
Letter: [
|
||||
'IconEditorBold',
|
||||
'IconEditorDeleteline',
|
||||
'IconEditorItalic',
|
||||
'IconEditorSub',
|
||||
'IconEditorSubtitle',
|
||||
'IconEditorSuper',
|
||||
'IconEditorTitle',
|
||||
'IconEditorUnderline',
|
||||
'IconFontColor',
|
||||
'IconFontSize',
|
||||
'IconFontStyle',
|
||||
'IconFontWeight',
|
||||
'IconRichTextBold',
|
||||
'IconRichTextFontSize',
|
||||
'IconRichTextFormatClear',
|
||||
'IconRichTextH1',
|
||||
'IconRichTextH2',
|
||||
'IconRichTextH3',
|
||||
'IconRichTextH4',
|
||||
'IconRichTextH5',
|
||||
'IconRichTextH6',
|
||||
'IconRichTextHeading',
|
||||
'IconRichTextItalic',
|
||||
'IconRichTextStrikeThrough',
|
||||
'IconRichTextSubscript',
|
||||
'IconRichTextSuperscript',
|
||||
'IconRichTextUnderline',
|
||||
'IconTextDecoration',
|
||||
'IconUnderline'
|
||||
],
|
||||
Mall: [
|
||||
'IconPurchasePlannedOrder',
|
||||
'IconShipped',
|
||||
'IconShoppingCard',
|
||||
'IconSoldOut',
|
||||
'IconSurchargeSettled',
|
||||
'IconSurchargeSettled',
|
||||
'IconWaitForDeliveryO',
|
||||
'IconWaitingToPick'
|
||||
],
|
||||
Brands: ['IconAngularjs', 'IconEspaceAuto', 'IconEspace', 'IconNodejs', 'IconReactjs', 'IconVuejs'],
|
||||
Charts: ['IconAreaChart', 'IconDotChart', 'IconLineChart', 'IconPieChart', 'IconStatistics'],
|
||||
Editor: [
|
||||
|
@ -44,11 +251,8 @@ export const iconGroups = {
|
|||
'IconEditorAlignLeft',
|
||||
'IconEditorAlignRight',
|
||||
'IconEditorBackground',
|
||||
'IconEditorBold',
|
||||
'IconEditorCode',
|
||||
'IconEditorDeleteline',
|
||||
'IconEditorEraser',
|
||||
'IconEditorItalic',
|
||||
'IconEditorLeftBorder',
|
||||
'IconEditorList',
|
||||
'IconEditorListDot',
|
||||
|
@ -58,51 +262,64 @@ export const iconGroups = {
|
|||
'IconEditorQuote',
|
||||
'IconEditorRedo',
|
||||
'IconEditorRightBorder',
|
||||
'IconEditorSub',
|
||||
'IconEditorSubtitle',
|
||||
'IconEditorSuper',
|
||||
'IconEditorTable',
|
||||
'IconEditorTextcolor',
|
||||
'IconEditorTitle',
|
||||
'IconEditorUnderline',
|
||||
'IconEditorUndo',
|
||||
'IconExport',
|
||||
'IconEditorVideo',
|
||||
'IconOperationfaildL',
|
||||
'IconFilletExternalLink',
|
||||
'IconOuterLink',
|
||||
'IconTextDecoration',
|
||||
'IconUnderline',
|
||||
'IconWriting'
|
||||
],
|
||||
IT: [
|
||||
'IconAdministrator',
|
||||
'IconDataSource',
|
||||
'IconDesktopView',
|
||||
'IconEmailAdd',
|
||||
'IconEmailCircle',
|
||||
'IconExcel',
|
||||
'IconException',
|
||||
'IconExclamation',
|
||||
'IconLanguage',
|
||||
'IconMailContent',
|
||||
'IconMail',
|
||||
'IconMarkOn',
|
||||
'IconMobileView',
|
||||
'IconMobile',
|
||||
'IconPrintPreview',
|
||||
'IconReplies',
|
||||
'IconSent',
|
||||
'IconShare',
|
||||
'IconShareArrow',
|
||||
'IconShoppingCard',
|
||||
'IconTabletView',
|
||||
'IconUnlock',
|
||||
'IconUnsent',
|
||||
'IconUser',
|
||||
'IconVersiontree',
|
||||
'IconWebPlus',
|
||||
'IconJs'
|
||||
],
|
||||
Clock: ['IconClockWork', 'IconProcessing', 'IconTime'],
|
||||
Email: ['IconEmailAdd', 'IconEmailCircle', 'IconMailContent', 'IconMail', 'IconReplies', 'IconSent', 'IconUnsent'],
|
||||
Folder: ['IconFileCloudupload', 'IconFolder', 'IconFolderClosed', 'IconFolderOpened'],
|
||||
File: [
|
||||
'IconCloudUpload',
|
||||
'IconDocument',
|
||||
'IconExcel',
|
||||
'IconExcelType',
|
||||
'IconFileExcel',
|
||||
'IconFile',
|
||||
'IconFilesCircle',
|
||||
'IconFiles',
|
||||
'IconFiletext',
|
||||
'IconFileType',
|
||||
'IconFileupload',
|
||||
'IconFinishO',
|
||||
'IconHistoryRecord',
|
||||
'IconOtherType',
|
||||
'IconPdfType',
|
||||
'IconPptType',
|
||||
'IconTextType',
|
||||
'IconText',
|
||||
'IconTextAlign',
|
||||
'IconTextTab',
|
||||
'IconVideoType',
|
||||
'IconWordType',
|
||||
'IconXml',
|
||||
'IconZipType'
|
||||
],
|
||||
Image: ['IconAddPicture', 'IconImageAdd', 'IconPicture', 'IconPictureType', 'IconRichTextImage'],
|
||||
Media: [
|
||||
'IconAudio',
|
||||
'IconCourse',
|
||||
'IconCustom',
|
||||
'IconCustomerService',
|
||||
|
@ -110,161 +327,89 @@ export const iconGroups = {
|
|||
'IconDialog2',
|
||||
'IconInformation',
|
||||
'IconMessageCircle',
|
||||
'IconPagerFirst',
|
||||
'IconPagerLast',
|
||||
'IconPagerNext',
|
||||
'IconPagerPrev',
|
||||
'IconMic',
|
||||
'IconPauseCircle',
|
||||
'IconPause',
|
||||
'IconPicture',
|
||||
'IconStartCircle',
|
||||
'IconStart',
|
||||
'IconTime'
|
||||
'IconStartO',
|
||||
'IconTurnOn'
|
||||
],
|
||||
Objects: [
|
||||
Object: [
|
||||
'IconBoat',
|
||||
'IconCalculator',
|
||||
'IconCalendar',
|
||||
'IconClockWork',
|
||||
'IconCloudDownload',
|
||||
'IconCloudUpload',
|
||||
'IconCoin',
|
||||
'IconTaskCooperation',
|
||||
'IconTelephoneCircle',
|
||||
'IconTelephone'
|
||||
],
|
||||
Symbols: [
|
||||
'IconBusy',
|
||||
'IconCheck',
|
||||
'IconCheckedLinear',
|
||||
'IconCheckedSur',
|
||||
'IconCloseCircle',
|
||||
'IconCloseSquare',
|
||||
Symbol: [
|
||||
'IconCode',
|
||||
'IconCommission',
|
||||
'IconCueL',
|
||||
'IconCrop',
|
||||
'IconDotIpv4',
|
||||
'IconEllipsis',
|
||||
'IconError',
|
||||
'IconEyeclose',
|
||||
'IconEyeopen',
|
||||
'IconFrownO',
|
||||
'IconFrown',
|
||||
'IconGroup',
|
||||
'IconHeartempty',
|
||||
'IconHelpCircle',
|
||||
'IconHelpQuery',
|
||||
'IconHelpSolid',
|
||||
'IconHelp',
|
||||
'IconHelpful',
|
||||
'IconLeave',
|
||||
'IconLoading',
|
||||
'IconLock',
|
||||
'IconMale',
|
||||
'IconMeh',
|
||||
'IconMore',
|
||||
'IconPlus',
|
||||
'IconNodeOpen',
|
||||
'IconNode',
|
||||
'IconNone',
|
||||
'IconOffLine',
|
||||
'IconOnLine',
|
||||
'IconPanelMax',
|
||||
'IconPanelMini',
|
||||
'IconPanelNormal',
|
||||
'IconRadio',
|
||||
'IconRadioselected',
|
||||
'IconSmileO',
|
||||
'IconSmile',
|
||||
'IconStarActive',
|
||||
'IconStarDisable',
|
||||
'IconStarO',
|
||||
'IconStop',
|
||||
'IconSuccess',
|
||||
'IconSuccessful',
|
||||
'IconInfoSolid',
|
||||
'IconInfoCircle',
|
||||
'IconInfo',
|
||||
'IconOperationfaild',
|
||||
'IconUnknow',
|
||||
'IconUnknown',
|
||||
'IconWarning',
|
||||
'IconWarningTriangle',
|
||||
'IconClose',
|
||||
'IconYes'
|
||||
'IconStarO'
|
||||
],
|
||||
Tools: [
|
||||
'IconAdd',
|
||||
'IconAddPicture',
|
||||
Tool: [
|
||||
'IconConfig',
|
||||
'IconSetting',
|
||||
'IconAlignBaseline',
|
||||
'IconAlignCenter',
|
||||
'IconAlignFlexCenter',
|
||||
'IconAlignFlexEnd',
|
||||
'IconAlignFlexStart',
|
||||
'IconAlignJustify',
|
||||
'IconAlignLeft',
|
||||
'IconAlignRight',
|
||||
'IconAlignStretch',
|
||||
'IconApp',
|
||||
'IconApplication',
|
||||
'IconAssociation',
|
||||
'IconAttachment',
|
||||
'IconBarChart',
|
||||
'IconBefilter',
|
||||
'IconBoxSolid',
|
||||
'IconCheckOut',
|
||||
'IconCheckedTrue',
|
||||
'IconClearFilter',
|
||||
'IconConmentRefresh',
|
||||
'IconCopySolid',
|
||||
'IconCopy',
|
||||
'IconDefinedFiltration',
|
||||
'IconDel',
|
||||
'IconDeleteL',
|
||||
'IconDeleted',
|
||||
'IconDerive',
|
||||
'IconDeletePage',
|
||||
'IconDescending',
|
||||
'IconColReverse',
|
||||
'IconDirectionCol',
|
||||
'IconDirectionRow',
|
||||
'IconRowReverse',
|
||||
'IconDownloadCloud',
|
||||
'IconDownloadLink',
|
||||
'IconDownload',
|
||||
'IconDraft',
|
||||
'IconEdit',
|
||||
'IconEditor',
|
||||
'IconEditorTab',
|
||||
'IconExport',
|
||||
'IconExpressSearch',
|
||||
'IconFileCloudupload',
|
||||
'IconFileExcel',
|
||||
'IconFile',
|
||||
'IconFilesCircle',
|
||||
'IconFiles',
|
||||
'IconFiletext',
|
||||
'IconFileupload',
|
||||
'IconFiltered',
|
||||
'IconFlag',
|
||||
'IconFolderClosed',
|
||||
'IconFolderOpened',
|
||||
'IconFontColor',
|
||||
'IconFontFamily',
|
||||
'IconFontSize',
|
||||
'IconFontStyle',
|
||||
'IconFontWeight',
|
||||
'IconFreezeLeft',
|
||||
'IconFreezeRight',
|
||||
'IconFullscreen',
|
||||
'IconFullscreenLeft',
|
||||
'IconGrade',
|
||||
'IconGroupTransfer',
|
||||
'IconHalfchecked',
|
||||
'IconHalfselect',
|
||||
'IconHideLeft',
|
||||
'IconHideRight',
|
||||
'IconHideTopleft',
|
||||
'IconImport',
|
||||
'IconJusitfyCenter',
|
||||
'IconJusitfyFlexEnd',
|
||||
'IconJusitfySpaceAround',
|
||||
|
@ -274,24 +419,13 @@ export const iconGroups = {
|
|||
'IconLineHeight',
|
||||
'IconLineThrought',
|
||||
'IconLink',
|
||||
'IconMinscreenLeft',
|
||||
'IconMinscreen',
|
||||
'IconMinusCircle',
|
||||
'IconMinusSquare',
|
||||
'IconMinus',
|
||||
'IconNew',
|
||||
'IconNoPremission',
|
||||
'IconPagelink',
|
||||
'IconPlusCircle',
|
||||
'IconPlusSquare',
|
||||
'IconPreChecked',
|
||||
'IconPushpin',
|
||||
'IconRedo',
|
||||
'IconRefres',
|
||||
'IconRenew',
|
||||
'IconRepeat',
|
||||
'IconReplace',
|
||||
'IconRightFrozen',
|
||||
'IconRichTextNodeDelete',
|
||||
'IconSandwichCollapse',
|
||||
'IconSandwichExpand',
|
||||
'IconSave',
|
||||
|
@ -299,21 +433,8 @@ export const iconGroups = {
|
|||
'IconSearch',
|
||||
'IconSelect',
|
||||
'IconSeparate',
|
||||
'IconSetting',
|
||||
'IconSortDefault',
|
||||
'IconSort',
|
||||
'IconStreamSolid',
|
||||
'IconTextAlign',
|
||||
'IconTextTab',
|
||||
'IconText',
|
||||
'IconTotal',
|
||||
'IconUndelete',
|
||||
'IconUndo',
|
||||
'IconUnfilter',
|
||||
'IconUnfreeze',
|
||||
'IconUpload',
|
||||
'IconView',
|
||||
'IconZoomIn',
|
||||
'IconZoomOut'
|
||||
'IconUnfreeze'
|
||||
]
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import { test, expect } from '@playwright/test'
|
|||
test('[Input]basic-usage: placeholder, focus-style, v-model', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('input#basic-usage')
|
||||
const input = await page.locator('.demo-input > .tiny-input > .tiny-input-display-only > input')
|
||||
const input = page.locator('.demo-input > .tiny-input > .tiny-input-display-only > input')
|
||||
|
||||
await expect(input).toBeVisible()
|
||||
await expect(input).toHaveAttribute('placeholder', 'Please input')
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
<template>
|
||||
<div class="demo-input">
|
||||
是否悬浮提示:<tiny-switch v-model="showTooltip"></tiny-switch>
|
||||
<tiny-input v-model="input" display-only :show-tooltip="showTooltip"></tiny-input>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Input as TinyInput, Switch as TinySwitch } from '@opentiny/vue'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const showTooltip = ref(false)
|
||||
|
||||
const input = ref(
|
||||
'内容很多内容很多内容很多内容很多内容很多内容很多内容很多内容很多内容很多内容很多内容很多内容很多内容很多内容很多内容很多内容很多内容很多内容很多内容很多'
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.demo-input {
|
||||
width: 200px;
|
||||
display: inline-block;
|
||||
}
|
||||
.tiny-input {
|
||||
margin-top: 12px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,10 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('只读态悬浮提示', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('input#show-tooltip')
|
||||
|
||||
const demo = page.locator('#show-tooltip')
|
||||
await demo.locator('.tiny-input .tiny-input-display-only__content').hover()
|
||||
await expect(page.locator('.tiny-tooltip.tiny-tooltip__popper')).not.toBeVisible()
|
||||
})
|
|
@ -0,0 +1,34 @@
|
|||
<template>
|
||||
<div class="demo-input">
|
||||
是否悬浮提示:<tiny-switch v-model="showTooltip"></tiny-switch>
|
||||
<tiny-input v-model="input" display-only :show-tooltip="showTooltip"></tiny-input>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Input, Switch } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyInput: Input,
|
||||
TinySwitch: Switch
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showTooltip: false,
|
||||
input:
|
||||
'内容很多内容很多内容很多内容很多内容很多内容很多内容很多内容很多内容很多内容很多内容很多内容很多内容很多内容很多内容很多内容很多内容很多内容很多内容很多'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.demo-input {
|
||||
width: 200px;
|
||||
display: inline-block;
|
||||
}
|
||||
.tiny-input {
|
||||
margin-top: 12px;
|
||||
}
|
||||
</style>
|
|
@ -41,6 +41,19 @@ export default {
|
|||
},
|
||||
codeFiles: ['show-password.vue']
|
||||
},
|
||||
{
|
||||
demoId: 'show-tooltip',
|
||||
name: {
|
||||
'zh-CN': '只读态悬浮提示',
|
||||
'en-US': 'Show Tooltip'
|
||||
},
|
||||
desc: {
|
||||
'zh-CN': '<p>通过 <code>show-tooltip</code> 配置当文本超长时,是否显示悬浮提示。</p>\n',
|
||||
'en-US':
|
||||
'<p>Use <code>show-tooltip</code> to configure whether to display a floating tip when the text is too long. </p>\n'
|
||||
},
|
||||
codeFiles: ['show-tooltip.vue']
|
||||
},
|
||||
{
|
||||
demoId: 'size',
|
||||
name: {
|
||||
|
|
|
@ -12,8 +12,7 @@ const options = reactive([
|
|||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
{ value: '选项4', label: '重庆' }
|
||||
])
|
||||
const value = ref('')
|
||||
</script>
|
||||
|
|
|
@ -18,8 +18,7 @@ export default {
|
|||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
{ value: '选项4', label: '重庆' }
|
||||
],
|
||||
value: ''
|
||||
}
|
||||
|
|
|
@ -8,3 +8,9 @@ import { Slider as TinySlider } from '@opentiny/vue'
|
|||
|
||||
const value = ref(20)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -16,3 +16,9 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -15,3 +15,9 @@ function setValue() {
|
|||
value.value = 50
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 32px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -25,3 +25,9 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 32px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -8,3 +8,9 @@ import { Slider as TinySlider } from '@opentiny/vue'
|
|||
|
||||
const value = ref(40)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -16,3 +16,9 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -12,3 +12,9 @@ function format(value) {
|
|||
return '当前值为:' + value
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -21,3 +21,9 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>
|
||||
<tiny-slider v-model="value" :marks="marks"></tiny-slider>
|
||||
</div>
|
||||
</div>
|
||||
<tiny-slider v-model="value" :marks="marks"></tiny-slider>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
@ -18,3 +14,9 @@ const marks = ref({
|
|||
|
||||
const value = ref(20)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>
|
||||
<tiny-slider v-model="value" :marks="marks"></tiny-slider>
|
||||
</div>
|
||||
</div>
|
||||
<tiny-slider v-model="value" :marks="marks"></tiny-slider>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -25,3 +21,9 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -8,3 +8,9 @@ import { Slider as TinySlider } from '@opentiny/vue'
|
|||
|
||||
const value = ref(30)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -16,3 +16,9 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -8,3 +8,9 @@ import { Slider as TinySlider } from '@opentiny/vue'
|
|||
|
||||
const value = ref([20, 40])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -16,3 +16,9 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -8,3 +8,9 @@ import { Slider as TinySlider } from '@opentiny/vue'
|
|||
|
||||
const value = ref(40)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -16,3 +16,9 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -10,3 +10,9 @@ import { Slider as TinySlider } from '@opentiny/vue'
|
|||
const value = ref(40)
|
||||
const value2 = ref([40, 60])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -18,3 +18,9 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -12,3 +12,9 @@ function format(value) {
|
|||
return '当前值为:' + value
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -21,3 +21,9 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -32,3 +32,9 @@ function stop(val) {
|
|||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -39,3 +39,9 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -12,3 +12,9 @@ import { Slider as TinySlider } from '@opentiny/vue'
|
|||
|
||||
const value = ref(40)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -20,3 +20,9 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -8,3 +8,9 @@ import { Slider as TinySlider } from '@opentiny/vue'
|
|||
|
||||
const value = ref(30)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -16,3 +16,9 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-slider-container {
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -9,7 +9,7 @@ test('选择器打开时默认时间设置', async ({ page }) => {
|
|||
const minute = page.getByRole('listitem').filter({ hasText: '40' }).first()
|
||||
const second = page.getByRole('listitem').filter({ hasText: '00' }).nth(2)
|
||||
|
||||
await page.locator('#default-value input[type="text"]').click()
|
||||
await page.locator('#default-value input[type="text"]').nth(0).click()
|
||||
await expect(hour).toHaveClass(/active/)
|
||||
await expect(minute).toHaveClass(/active/)
|
||||
await expect(second).toHaveClass(/active/)
|
||||
|
|
|
@ -5,6 +5,7 @@ test('固定时间范围', async ({ page }) => {
|
|||
await page.goto('time-picker#picker-options')
|
||||
|
||||
const selectTime = page.getByRole('textbox', { name: '18:40:00' })
|
||||
const selectTime1 = page.getByRole('textbox', { name: '19:40:00' })
|
||||
// 点击17点,点击确定,关闭选择框后,查看input 时间是否仍是18:40:00
|
||||
await selectTime.click()
|
||||
await page.waitForTimeout(100)
|
||||
|
@ -12,11 +13,11 @@ test('固定时间范围', async ({ page }) => {
|
|||
await page.getByRole('button', { name: '确定' }).click()
|
||||
await page.waitForTimeout(100)
|
||||
await expect(selectTime).toBeVisible()
|
||||
// 点击21点,点击确定,关闭选择框后,查看input 时间是否仍是18:40:00
|
||||
// 点击19点,点击确定,关闭选择框后,查看input 时间是19:40:00
|
||||
await selectTime.click()
|
||||
await page.waitForTimeout(100)
|
||||
await page.getByRole('listitem').filter({ hasText: '21' }).first().click()
|
||||
await page.getByRole('listitem').filter({ hasText: '19' }).first().click()
|
||||
await page.getByRole('button', { name: '确定' }).click()
|
||||
await page.waitForTimeout(100)
|
||||
await expect(selectTime).toBeVisible()
|
||||
await expect(selectTime1).toBeVisible()
|
||||
})
|
||||
|
|
|
@ -14,6 +14,13 @@
|
|||
<tiny-radio label="hide"> 隐藏 </tiny-radio>
|
||||
</tiny-radio-group>
|
||||
</div>
|
||||
<div class="option-row">
|
||||
<span> 搜索后是否高亮关键字:</span>
|
||||
<tiny-radio-group v-model="highlightQuery">
|
||||
<tiny-radio label="show"> 高亮 </tiny-radio>
|
||||
<tiny-radio label="hide"> 默认不变 </tiny-radio>
|
||||
</tiny-radio-group>
|
||||
</div>
|
||||
<div class="option-row">
|
||||
<span> 搜索值:</span>
|
||||
<tiny-input v-model="filterText" @input="inputChange"></tiny-input>
|
||||
|
@ -23,6 +30,7 @@
|
|||
ref="treeRef"
|
||||
:data="data"
|
||||
:view-type="viewType"
|
||||
:highlight-query="highlightQuery === 'show'"
|
||||
:filter-node-method="filterNodeMethod"
|
||||
:show-auxi="showAuxi === 'show'"
|
||||
default-expand-all
|
||||
|
@ -41,6 +49,7 @@ import { Tree as TinyTree, RadioGroup as TinyRadioGroup, Radio as TinyRadio, Inp
|
|||
|
||||
const treeRef = ref()
|
||||
const viewType = ref('tree')
|
||||
const highlightQuery = ref('hide')
|
||||
const showAuxi = ref('hide')
|
||||
const filterText = ref('')
|
||||
const data = ref([
|
||||
|
|
|
@ -7,15 +7,23 @@ test('测试过滤视图', async ({ page }) => {
|
|||
const preview = page.locator('.pc-demo-container')
|
||||
const tree = preview.locator('.tiny-tree').nth(0)
|
||||
const btnPlain = preview.getByText('平铺视图 plain')
|
||||
const btnHighlight = preview.getByRole('radio', { name: '高亮' })
|
||||
const checkboxs = tree.locator('.tiny-tree__plain-node .tiny-checkbox')
|
||||
const highlightNodes = tree.locator('.tiny-tree__plain-node .tiny-hl-query-node')
|
||||
const input = preview.locator('.tiny-input input')
|
||||
|
||||
await expect(tree.getByText('数据 1-1-1')).toHaveCount(1)
|
||||
|
||||
// 测试平铺视图
|
||||
await btnPlain.click()
|
||||
await expect(checkboxs).toHaveCount(9)
|
||||
await page.waitForTimeout(20)
|
||||
|
||||
// 测试过滤
|
||||
await input.fill('1-1')
|
||||
await expect(checkboxs).toHaveCount(3)
|
||||
|
||||
// 测试高亮
|
||||
await btnHighlight.click()
|
||||
await expect(highlightNodes).toHaveCount(2)
|
||||
})
|
||||
|
|
|
@ -14,6 +14,13 @@
|
|||
<tiny-radio label="hide"> 隐藏 </tiny-radio>
|
||||
</tiny-radio-group>
|
||||
</div>
|
||||
<div class="option-row">
|
||||
<span> 搜索后是否高亮关键字:</span>
|
||||
<tiny-radio-group v-model="highlightQuery">
|
||||
<tiny-radio label="show"> 高亮 </tiny-radio>
|
||||
<tiny-radio label="hide"> 默认不变 </tiny-radio>
|
||||
</tiny-radio-group>
|
||||
</div>
|
||||
<div class="option-row">
|
||||
<span> 搜索值:</span>
|
||||
<tiny-input v-model="filterText" @input="inputChange"></tiny-input>
|
||||
|
@ -23,6 +30,7 @@
|
|||
ref="treeRef"
|
||||
:data="data"
|
||||
:view-type="viewType"
|
||||
:highlight-query="highlightQuery === 'show'"
|
||||
:filter-node-method="filterNodeMethod"
|
||||
:show-auxi="showAuxi === 'show'"
|
||||
default-expand-all
|
||||
|
@ -49,6 +57,7 @@ export default {
|
|||
return {
|
||||
viewType: 'tree',
|
||||
showAuxi: 'hide',
|
||||
highlightQuery: 'hide',
|
||||
filterText: '',
|
||||
data: [
|
||||
{
|
||||
|
|
|
@ -312,6 +312,7 @@ export default {
|
|||
'zh-CN': `
|
||||
通过 <code> filter-node-method </code> 属性, 指定过滤节点时的函数,函数返回<code>true</code>时节点显示,否则节点隐藏。<br>
|
||||
通过 <code> filter </code> 组件方法,触发组件进行过滤。<br>
|
||||
通过 <code> highlightQuery </code> 属性,是否在匹配的节点中,高亮搜索文字。<br>
|
||||
通过 <code> view-type </code> 属性,设置组件的视图模式,可选值为<code> tree </code> 和 <code> plain </code>,默认为<code> tree </code>。<br>
|
||||
通过 <code> show-auxi </code> 属性,设置在平铺视图时,是否显示节点的辅助信息,默认为<code>true</code>。<br>
|
||||
<div class="tip custom-block">
|
||||
|
@ -321,6 +322,7 @@ export default {
|
|||
`,
|
||||
'en-US': `The <code> filter-node-method </code> property is used to specify the function for filtering nodes. The function returns <code>true</code> to display the nodes. <br>
|
||||
Run the <code> filter </code> component method to trigger the component to filter. <br>
|
||||
Use the <code>highlightQuery </code> attribute to determine whether to highlight the search text in the matched node.<br>
|
||||
Use the <code> view-type </code> property to set the component view mode. The optional values are <code> tree </code> and <code> plain </code>. The default value is <code> tree </code>. <br>
|
||||
The <code> show-auxi </code> property is used to set whether to display auxiliary node information in tiled view. The default is <code>true</code>. <br>
|
||||
<div class="tip custom-block">
|
||||
|
|
|
@ -320,7 +320,10 @@ export const cmpMenus = [
|
|||
'label': '自定义指令',
|
||||
'labelEn': 'Custom Instruction',
|
||||
'key': 'directives-custom-instruction',
|
||||
'children': [{ 'nameCn': '超出隐藏', 'name': 'AutoTip', 'key': 'directives-auto-tip' }]
|
||||
'children': [
|
||||
{ 'nameCn': '超出隐藏', 'name': 'AutoTip', 'key': 'directives-auto-tip' },
|
||||
{ 'nameCn': '高亮搜索字', 'name': 'HighlightQuery', 'key': 'directives-highlight-query' }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
|
|
After Width: | Height: | Size: 492 B |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 246 B |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 245 B |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 20 KiB |
|
@ -1,5 +1,7 @@
|
|||
{
|
||||
"language": "EN",
|
||||
"zh-cn": "Chinese",
|
||||
"en-us": "English",
|
||||
"localeType": "Language Selection",
|
||||
"dark": "Dark",
|
||||
"light": "Light",
|
||||
"searchPlaceholder": "Search",
|
||||
|
@ -39,4 +41,4 @@
|
|||
"demoModeMultiple": "Multiple",
|
||||
"contributor": "Contributors",
|
||||
"noData": "No Data"
|
||||
}
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
{
|
||||
"language": "中",
|
||||
"zh-cn": "中文",
|
||||
"en-us": "英文",
|
||||
"localeType": "语言选择",
|
||||
"dark": "深色",
|
||||
"light": "浅色",
|
||||
"searchPlaceholder": "搜索",
|
||||
|
@ -39,4 +41,4 @@
|
|||
"demoModeMultiple": "多示例",
|
||||
"contributor": "贡献者",
|
||||
"noData": "暂无数据"
|
||||
}
|
||||
}
|
|
@ -11,17 +11,14 @@ const appData = reactive({
|
|||
bpState: useMediaQuery([640, 1024, 1280]).matches // 3点4区间, bp0,bp1,bp2,bp3
|
||||
})
|
||||
const isZhCn = computed(() => appData.lang === ZH_CN_LANG)
|
||||
let appFn = {
|
||||
toggleLang() {
|
||||
let url = location.href
|
||||
if (appData.lang === ZH_CN_LANG) {
|
||||
url = location.href.replace(zhPath, enPath)
|
||||
} else {
|
||||
url = location.href.replace(enPath, zhPath)
|
||||
const appFn = {
|
||||
toggleLang(name) {
|
||||
if (name !== appData.lang) {
|
||||
let url = location.href
|
||||
url = location.href.replace(LANG_PATH_MAP[appData.lang], LANG_PATH_MAP[name])
|
||||
appData.lang = name
|
||||
location.replace(url)
|
||||
}
|
||||
appData.lang = appData.lang === ZH_CN_LANG ? EN_US_LANG : ZH_CN_LANG
|
||||
// router.push(url)
|
||||
location.replace(url)
|
||||
},
|
||||
toggleTheme() {
|
||||
appData.theme = appData.theme === 'light' ? 'dark' : 'light'
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import { reactive } from 'vue'
|
||||
import { $local } from './storage'
|
||||
import { appFn } from './appData'
|
||||
|
||||
const _modeKey = 'tiny-vue-api-mode'
|
||||
const _demoModeKey = 'tiny-vue-demo-mode'
|
||||
const apiModeState = reactive({
|
||||
localeMode: location.href.includes('en-US') ? 'enUS' : 'zhCN',
|
||||
apiMode: $local[_modeKey] || 'Composition', // 示例风格: Options: 组合式; Composition: 选项式
|
||||
demoMode: $local[_demoModeKey] || 'default' // 示例展示: default:多示例, single:单示例
|
||||
})
|
||||
|
@ -12,6 +14,9 @@ const apiModeFn = {
|
|||
getDemoName: (name) => {
|
||||
return name.replace(/\.vue$/, `${apiModeState.apiMode === 'Options' ? '' : '-composition-api'}.vue`)
|
||||
},
|
||||
changeLocaleMode: (name) => {
|
||||
appFn.toggleLang(name)
|
||||
},
|
||||
changeApiMode: (name) => {
|
||||
$local[_modeKey] = name
|
||||
},
|
||||
|
|
|
@ -1,6 +1,22 @@
|
|||
/** 文档显示风格设置 */
|
||||
const getStyleSettings = (i18nByKey) => {
|
||||
const styleSettings = [
|
||||
{
|
||||
// 语言选择
|
||||
name: 'localeMode',
|
||||
defaultValue: 'zhCN',
|
||||
title: i18nByKey('localeType'),
|
||||
options: [
|
||||
{
|
||||
value: 'zhCN',
|
||||
text: i18nByKey('zh-cn')
|
||||
},
|
||||
{
|
||||
value: 'enUS',
|
||||
text: i18nByKey('en-us')
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
// 示例代码风格
|
||||
name: 'apiMode',
|
||||
|
|
|
@ -16,6 +16,17 @@ import {
|
|||
INFINITY_THEME,
|
||||
getKeyByValue
|
||||
} from '../const'
|
||||
import glaciers from '@/assets/images/glaciers.png'
|
||||
import glaciersIcon from '@/assets/images/glaciers-icon.png'
|
||||
|
||||
import infinitely from '@/assets/images/Infinitely.png'
|
||||
import infinitelyIcon from '@/assets/images/Infinitely-icon.png'
|
||||
|
||||
import oceanic from '@/assets/images/oceanic.png'
|
||||
import oceanicIcon from '@/assets/images/oceanic-icon.png'
|
||||
|
||||
import starrySky from '@/assets/images/starry-sky.png'
|
||||
import starrySkyIcon from '@/assets/images/starry-sky-icon.png'
|
||||
|
||||
const themeMap = {
|
||||
[DEFAULT_THEME]: null,
|
||||
|
@ -27,10 +38,34 @@ const themeMap = {
|
|||
const isEn = appData.lang === 'enUS'
|
||||
|
||||
const themeData = [
|
||||
{ value: [DEFAULT_THEME], label: isEn ? 'Default Theme' : '默认主题' },
|
||||
{ value: [INFINITY_THEME], label: isEn ? 'Infinity Theme' : '无限主题' },
|
||||
{ value: [AURORA_THEME], label: isEn ? 'Aurora Theme' : 'Aurora 主题' },
|
||||
{ value: [SMB_THEME], label: isEn ? 'SMB Theme' : 'SMB 主题' }
|
||||
{
|
||||
value: [DEFAULT_THEME],
|
||||
label: isEn ? 'Default Theme' : '冰川主题',
|
||||
tips: isEn ? 'Accurate, Efficient, Distinct' : '精准、高效、清晰',
|
||||
icon: glaciersIcon,
|
||||
bgImage: glaciers
|
||||
},
|
||||
{
|
||||
value: [SMB_THEME],
|
||||
label: isEn ? 'Star Theme' : '星空主题',
|
||||
tips: isEn ? 'Leading, Innovative, Reliable' : '领先、创新、信赖',
|
||||
icon: starrySkyIcon,
|
||||
bgImage: starrySky
|
||||
},
|
||||
{
|
||||
value: [AURORA_THEME],
|
||||
label: isEn ? 'Ocean Theme' : '海洋主题',
|
||||
tips: isEn ? 'Simple, Agile, Delightful' : '简约、敏捷、愉悦',
|
||||
icon: oceanicIcon,
|
||||
bgImage: oceanic
|
||||
},
|
||||
{
|
||||
value: [INFINITY_THEME],
|
||||
label: isEn ? 'Infinity Theme' : '无限主题',
|
||||
tips: isEn ? 'Creative, Scientific, Efficient' : '创造、科学、高效',
|
||||
icon: infinitelyIcon,
|
||||
bgImage: infinitely
|
||||
}
|
||||
]
|
||||
|
||||
const designConfigMap = {
|
||||
|
|
|
@ -5,69 +5,70 @@
|
|||
:style="settingsStyle"
|
||||
>
|
||||
<!-- 切换主题样式 -->
|
||||
<tiny-dropdown trigger="click" :show-icon="false" @visible-change="(visible) => toggleMenuShow(visible, 'theme')">
|
||||
<tiny-tooltip
|
||||
:content="i18nByKey('changeTheme')"
|
||||
:placement="isSettingsAside ? 'left' : 'right'"
|
||||
popper-class="docs-tooltip"
|
||||
effect="light"
|
||||
>
|
||||
<div class="settings-btn theme-change-button">
|
||||
<theme-settings-icon
|
||||
:class="['settings-icon theme-settings-icon', { 'is-active': showThemeMenu }]"
|
||||
></theme-settings-icon>
|
||||
</div>
|
||||
</tiny-tooltip>
|
||||
<template #dropdown>
|
||||
<tiny-dropdown-menu popper-class="opt-menu theme-settings-menu">
|
||||
<div v-for="(item, index) in themeData" :key="index" class="theme-option-list">
|
||||
<tiny-button
|
||||
ghost
|
||||
:class="['theme-option', { 'is-active': item.value === currentThemeKey }]"
|
||||
@click="themeItemClick(item)"
|
||||
>{{ item.text }}</tiny-button
|
||||
>
|
||||
<tiny-popover
|
||||
width="404"
|
||||
placement="left-end"
|
||||
trigger="click"
|
||||
:visible-arrow="false"
|
||||
popper-class="theme-settings-popover"
|
||||
>
|
||||
<div class="theme-settings-menu">
|
||||
<div class="theme-settings-title">{{ i18nByKey('changeTheme') }}</div>
|
||||
<div
|
||||
v-for="(item, index) in themeData"
|
||||
:key="item.text + index"
|
||||
:class="['theme-option-list', { 'is-active-popover': item.value === currentThemeKey }]"
|
||||
:style="{ backgroundImage: 'url(' + item.bgImage + ')' }"
|
||||
@click="themeItemClick(item)"
|
||||
>
|
||||
<div class="theme-option-list-icon" :style="{ backgroundImage: 'url(' + item.icon + ')' }"></div>
|
||||
<div>
|
||||
<div class="theme-option-list-text">
|
||||
{{ item.text }}
|
||||
</div>
|
||||
<div class="theme-option-list-tips">
|
||||
{{ item.tips }}
|
||||
</div>
|
||||
</div>
|
||||
</tiny-dropdown-menu>
|
||||
</div>
|
||||
</div>
|
||||
<template #reference>
|
||||
<div class="settings-btn theme-change-button">
|
||||
<theme-settings-icon class="settings-icon theme-settings-icon"></theme-settings-icon>
|
||||
</div>
|
||||
</template>
|
||||
</tiny-dropdown>
|
||||
</tiny-popover>
|
||||
|
||||
<!-- demo风格设置 -->
|
||||
<tiny-dropdown
|
||||
<tiny-popover
|
||||
v-if="!templateModeState.isSaas"
|
||||
trigger="click"
|
||||
:show-icon="false"
|
||||
@visible-change="(visible) => toggleMenuShow(visible, 'style')"
|
||||
width="180"
|
||||
placement="left-end"
|
||||
trigger="manual"
|
||||
:visible-arrow="false"
|
||||
v-model="demoStyleVisible"
|
||||
popper-class="opt-menu style-settings-menu theme-settings-popover"
|
||||
>
|
||||
<tiny-tooltip
|
||||
:content="i18nByKey('changeApiType')"
|
||||
:placement="isSettingsAside ? 'left' : 'right'"
|
||||
popper-class="docs-tooltip"
|
||||
effect="light"
|
||||
>
|
||||
<div class="settings-btn style-settings-btn">
|
||||
<style-settings-icon
|
||||
:class="['settings-icon style-settings-icon', { 'is-active': showStyleMenu }]"
|
||||
></style-settings-icon>
|
||||
<div v-for="(item, index) in styleSettings" :key="index" class="style-settings-item">
|
||||
<p class="style-settings-title">{{ item.title }}</p>
|
||||
<tiny-radio-group
|
||||
v-model="apiModeState[item.name]"
|
||||
class="style-settings-options-group"
|
||||
@change="onSettingsChange(item.name)"
|
||||
>
|
||||
<tiny-radio v-for="option in item.options" :key="option" :label="option.value">{{ option.text }}</tiny-radio>
|
||||
</tiny-radio-group>
|
||||
</div>
|
||||
<template #reference>
|
||||
<div
|
||||
class="settings-btn style-settings-btn"
|
||||
@click="demoStyleVisible = !demoStyleVisible"
|
||||
@blur="demoStyleVisible = false"
|
||||
>
|
||||
<style-settings-icon class="settings-icon style-settings-icon"></style-settings-icon>
|
||||
</div>
|
||||
</tiny-tooltip>
|
||||
<template #dropdown>
|
||||
<tiny-dropdown-menu popper-class="opt-menu style-settings-menu">
|
||||
<div v-for="(item, index) in styleSettings" :key="index" class="style-settings-item">
|
||||
<p class="style-settings-title">{{ item.title }}</p>
|
||||
<tiny-radio-group
|
||||
v-model="apiModeState[item.name]"
|
||||
class="style-settings-options-group"
|
||||
@change="onSettingsChange(item.name)"
|
||||
>
|
||||
<tiny-radio v-for="option in item.options" :key="option" :label="option.value">{{
|
||||
option.text
|
||||
}}</tiny-radio>
|
||||
</tiny-radio-group>
|
||||
</div>
|
||||
</tiny-dropdown-menu>
|
||||
</template>
|
||||
</tiny-dropdown>
|
||||
</tiny-popover>
|
||||
|
||||
<!-- 返回顶部 -->
|
||||
<div v-show="showBackTop" @click="onBackTop">
|
||||
|
@ -87,7 +88,7 @@
|
|||
|
||||
<script>
|
||||
import { defineComponent, reactive, toRefs, onMounted, onUnmounted, watch, nextTick, ref } from 'vue'
|
||||
import { Dropdown, DropdownMenu, Tooltip, Radio, RadioGroup, Button } from '@opentiny/vue'
|
||||
import { Tooltip, Radio, RadioGroup, Popover } from '@opentiny/vue'
|
||||
import { iconUpWard } from '@opentiny/vue-icon'
|
||||
import debounce from '@opentiny/vue-renderless/common/deps/debounce'
|
||||
import { i18nByKey, useApiMode, useTemplateMode } from '@/tools'
|
||||
|
@ -100,13 +101,11 @@ import StyleSettingsIcon from '@/assets/images/style-settings.svg'
|
|||
export default defineComponent({
|
||||
name: 'FloatSettings',
|
||||
components: {
|
||||
TinyDropdown: Dropdown,
|
||||
TinyDropdownMenu: DropdownMenu,
|
||||
TinyTooltip: Tooltip,
|
||||
TinyRadio: Radio,
|
||||
TinyRadioGroup: RadioGroup,
|
||||
TinyButton: Button,
|
||||
IconUpWard: iconUpWard(),
|
||||
TinyPopover: Popover,
|
||||
ThemeSettingsIcon,
|
||||
StyleSettingsIcon
|
||||
},
|
||||
|
@ -120,9 +119,8 @@ export default defineComponent({
|
|||
const isPlus = import.meta.env.VITE_APP_MODE === 'plus'
|
||||
|
||||
const state = reactive({
|
||||
demoStyleVisible: false,
|
||||
themeData: [],
|
||||
showThemeMenu: false,
|
||||
showStyleMenu: false,
|
||||
styleSettings: getStyleSettings(i18nByKey),
|
||||
settingsStyle: {
|
||||
bottom: DEFAULT_BOTTOM_VAL
|
||||
|
@ -133,7 +131,7 @@ export default defineComponent({
|
|||
})
|
||||
|
||||
if (isPlus) {
|
||||
state.styleSettings = state.styleSettings.filter((item) => item.defaultValue === 'default')
|
||||
state.styleSettings = state.styleSettings.filter((item) => item.name !== 'apiMode')
|
||||
apiModeState.apiMode = 'Options'
|
||||
}
|
||||
|
||||
|
@ -147,6 +145,10 @@ export default defineComponent({
|
|||
},
|
||||
onSettingsChange(modeType) {
|
||||
switch (modeType) {
|
||||
case 'localeMode': {
|
||||
apiModeFn.changeLocaleMode(apiModeState[modeType])
|
||||
break
|
||||
}
|
||||
case 'apiMode': {
|
||||
apiModeFn.changeApiMode(apiModeState[modeType])
|
||||
break
|
||||
|
@ -162,21 +164,16 @@ export default defineComponent({
|
|||
themeItemClick(node) {
|
||||
const val = node?.value || 'tiny-smb-theme'
|
||||
changeTheme(val)
|
||||
},
|
||||
|
||||
toggleMenuShow(visible, type) {
|
||||
if (type === 'theme') {
|
||||
state.showThemeMenu = visible
|
||||
} else if (type === 'style') {
|
||||
state.showStyleMenu = visible
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const getThemeOptions = () => {
|
||||
const themeData = getThemeData().map((item) => ({
|
||||
value: item.value[0],
|
||||
text: item.label
|
||||
text: item.label,
|
||||
tips: item.tips,
|
||||
icon: item.icon,
|
||||
bgImage: item.bgImage
|
||||
}))
|
||||
state.themeData = themeData
|
||||
}
|
||||
|
@ -306,10 +303,6 @@ export default defineComponent({
|
|||
width: var(--ti-common-size-4x);
|
||||
height: var(--ti-common-size-4x);
|
||||
color: #595959;
|
||||
|
||||
&.is-active {
|
||||
color: var(--ti-common-color-primary-normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -320,13 +313,6 @@ export default defineComponent({
|
|||
border-radius: var(--ti-common-space-3x);
|
||||
box-shadow: 0px 4px 20px 0px rgba(0, 0, 0, 0.15);
|
||||
|
||||
&.theme-settings-menu {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&.style-settings-menu {
|
||||
padding: 14px;
|
||||
|
||||
|
@ -338,6 +324,7 @@ export default defineComponent({
|
|||
font-size: var(--ti-common-font-size-base);
|
||||
line-height: var(--ti-common-line-height-6);
|
||||
font-weight: 600;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.style-settings-options-group {
|
||||
|
@ -357,25 +344,64 @@ export default defineComponent({
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.tiny-popover.tiny-popper.theme-settings-popover {
|
||||
border-radius: 12px;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.theme-option-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 154px;
|
||||
|
||||
.theme-option {
|
||||
display: inline-block;
|
||||
width: 126px;
|
||||
border: none;
|
||||
border-radius: var(--ti-common-space-2x);
|
||||
|
||||
&.is-active {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
}
|
||||
.theme-settings-menu {
|
||||
width: 404px;
|
||||
display: flex;
|
||||
padding: 15px 32px;
|
||||
flex-direction: column;
|
||||
margin: 0;
|
||||
.theme-settings-title {
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
color: #000000;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
.theme-option-list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
background-color: aliceblue;
|
||||
cursor: pointer;
|
||||
margin-top: 20px;
|
||||
width: 308px;
|
||||
height: 64px;
|
||||
border: 1px solid #ffffff;
|
||||
border-radius: 8px;
|
||||
background-repeat: no-repeat;
|
||||
.theme-option-list-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin: 16px 24px;
|
||||
}
|
||||
.theme-option-list-text {
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
font-size: 14px;
|
||||
color: #202e54;
|
||||
font-weight: 700;
|
||||
}
|
||||
.theme-option-list-tips {
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
font-size: 14px;
|
||||
color: #808080;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
.theme-option-list:hover {
|
||||
border-color: rgba(0, 0, 0, 0.05);
|
||||
box-shadow: 0px 4px 20px 0px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
.is-active-popover {
|
||||
border-color: #1476ff;
|
||||
}
|
||||
|
||||
@media (max-width: 1279px) {
|
||||
.float-settings {
|
||||
|
|
|
@ -10,6 +10,8 @@ import Guide from './src/guide'
|
|||
import Pager from './src/pager'
|
||||
import Select from './src/select'
|
||||
import TreeNode from './src/tree-node'
|
||||
import TimeSpinner from './src/time-spinner'
|
||||
import Time from './src/time-spinner'
|
||||
import UploadList from './src/upload-list'
|
||||
import BreadcrumbItem from './src/breadcrumb-item'
|
||||
import { version } from './package.json'
|
||||
|
@ -30,6 +32,8 @@ export default {
|
|||
Pager,
|
||||
Select,
|
||||
TreeNode,
|
||||
TimeSpinner,
|
||||
Time,
|
||||
BreadcrumbItem,
|
||||
UploadList
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
export default {
|
||||
// 控制time-picker组件button显示和样式
|
||||
showTimePickerButton: true,
|
||||
// smb规范下,时间选择器单个item的margin为12px.
|
||||
itemMarginSpace: 12
|
||||
}
|
|
@ -3024,11 +3024,6 @@
|
|||
"pc"
|
||||
]
|
||||
},
|
||||
"TreeSelectPc": {
|
||||
"path": "vue/src/tree-select/src/pc.vue",
|
||||
"type": "template",
|
||||
"exclude": false
|
||||
},
|
||||
"Upload": {
|
||||
"path": "vue/src/upload/index.ts",
|
||||
"type": "component",
|
||||
|
|
|
@ -29,7 +29,7 @@ if (!isServer) {
|
|||
on(document, 'mouseup', (event) => {
|
||||
nodeList
|
||||
.filter((node) => !node[nameSpace].mousedownTrigger)
|
||||
.forEach((node) => node[nameSpace].documentHandler(event, startClick))
|
||||
.forEach((node) => node[nameSpace].documentHandler(event, node[nameSpace]?.mouseupTrigger ? event : startClick))
|
||||
startClick = null
|
||||
})
|
||||
}
|
||||
|
@ -60,8 +60,12 @@ const createDocumentHandler = (el, binding, vnode) =>
|
|||
* v-clickoutside
|
||||
* @desc 点击元素外面才会触发的事件
|
||||
* @example
|
||||
* 两个修饰符,mousedown、mouseup
|
||||
* 当没有修饰符时,需要同时满足在目标元素外同步按下和释放鼠标才会触发回调。
|
||||
* ```html
|
||||
* <div v-clickoutside="handleClose">
|
||||
* <div v-clickoutside="handleClose"> // 在元素外部点击时触发
|
||||
* <div v-clickoutside.mousedown="handleClose"> // 在元素外部按下鼠标时触发
|
||||
* <div v-clickoutside.mouseup="handleClose"> // 在元素外部松开鼠标时触发
|
||||
* ```
|
||||
*/
|
||||
export default {
|
||||
|
@ -69,22 +73,25 @@ export default {
|
|||
nodeList.push(el)
|
||||
const id = seed++
|
||||
const { modifiers, expression, value } = binding
|
||||
|
||||
const { mousedown = false, mouseup = false } = modifiers || {}
|
||||
el[nameSpace] = {
|
||||
id,
|
||||
documentHandler: createDocumentHandler(el, binding, vnode),
|
||||
methodName: expression,
|
||||
bindingFn: value,
|
||||
mousedownTrigger: modifiers.mousedown
|
||||
mousedownTrigger: mousedown,
|
||||
mouseupTrigger: mouseup
|
||||
}
|
||||
},
|
||||
|
||||
update: (el, binding, vnode) => {
|
||||
const { modifiers, expression, value } = binding
|
||||
const { mousedown = false, mouseup = false } = modifiers || {}
|
||||
el[nameSpace].documentHandler = createDocumentHandler(el, binding, vnode)
|
||||
el[nameSpace].methodName = expression
|
||||
el[nameSpace].bindingFn = value
|
||||
el[nameSpace].mousedownTrigger = modifiers.mousedown
|
||||
el[nameSpace].mousedownTrigger = mousedown
|
||||
el[nameSpace].mouseupTrigger = mouseup
|
||||
},
|
||||
|
||||
unbind: (el) => {
|
||||
|
|
|
@ -7,27 +7,41 @@ import { onMountedOrActivated as createHook } from './useEventListener'
|
|||
* relationContainer 子组件顺序由关系容器确定,由根组件提供,可以不使用,子组件顺序就是组件创建顺序
|
||||
* onChange 子组件顺序改变后的回调处理,由根组件提供,可以不使用
|
||||
* childrenKey 在组件关系树上的所有实例中定义的子组件引用名称,默认是 instanceChildren
|
||||
* delivery 根组件向下分发的内容
|
||||
*/
|
||||
export const useRelation =
|
||||
({ getCurrentInstance, inject, markRaw, nextTick, onMounted, onActivated, onUnmounted, provide, reactive, toRef }) =>
|
||||
({ relationKey, relationContainer, onChange, childrenKey } = {}) => {
|
||||
({
|
||||
computed,
|
||||
getCurrentInstance,
|
||||
inject,
|
||||
markRaw,
|
||||
nextTick,
|
||||
onMounted,
|
||||
onActivated,
|
||||
onUnmounted,
|
||||
provide,
|
||||
reactive,
|
||||
toRef
|
||||
}) =>
|
||||
({ relationKey, relationContainer, onChange, childrenKey, delivery } = {}) => {
|
||||
if (!relationKey) {
|
||||
throw new Error('[TINY Error]<relationKey> must exist.')
|
||||
}
|
||||
|
||||
const instance = getCurrentInstance()
|
||||
const state = reactive({ children: [] })
|
||||
const state = reactive({ children: [], indexInParent: -1 })
|
||||
const injectValue = inject(relationKey, null)
|
||||
// 收集所有的子组件刷新回调
|
||||
let callbacks = []
|
||||
|
||||
if (injectValue) {
|
||||
const { link, unlink, callbacks: injectCbs, childrenKey: injectKey } = injectValue
|
||||
const { link, unlink, callbacks: injectCbs, childrenKey: injectKey, delivery: injectDelivery } = injectValue
|
||||
|
||||
callbacks = injectCbs
|
||||
childrenKey = childrenKey || injectKey || 'instanceChildren'
|
||||
delivery = injectDelivery
|
||||
|
||||
link(instance)
|
||||
state.indexInParent = link(instance)
|
||||
|
||||
onUnmounted(() => unlink(instance))
|
||||
} else {
|
||||
|
@ -69,7 +83,13 @@ export const useRelation =
|
|||
})
|
||||
}
|
||||
|
||||
const link = (child) => state.children.push(markRaw(child.proxy))
|
||||
const link = (child) => {
|
||||
const childPublic = child.proxy
|
||||
|
||||
state.children.push(markRaw(childPublic))
|
||||
|
||||
return computed(() => state.children.indexOf(childPublic))
|
||||
}
|
||||
|
||||
const unlink = (child) => {
|
||||
const index = state.children.indexOf(child.proxy)
|
||||
|
@ -82,15 +102,15 @@ export const useRelation =
|
|||
// 刷新子组件顺序
|
||||
callbacks.push((flattenNodes) => sortPublicInstances(state.children, flattenNodes))
|
||||
|
||||
provide(relationKey, { link, unlink, callbacks, childrenKey })
|
||||
provide(relationKey, { link, unlink, callbacks, childrenKey, delivery })
|
||||
|
||||
// 在 Public Instance 上定义子组件数组,并且在组件卸载时移除
|
||||
Object.defineProperty(instance.proxy, childrenKey, { configurable: true, get: () => state.children })
|
||||
|
||||
onUnmounted(() => delete instance.proxy[childrenKey])
|
||||
|
||||
// 返回子组件数组 ref
|
||||
return { children: toRef(state, 'children') }
|
||||
// 返回子组件数组 ref、在父级中的位置索引 ref 和接收到的分发内容
|
||||
return { children: toRef(state, 'children'), index: toRef(state, 'indexInParent'), delivery }
|
||||
}
|
||||
|
||||
const flattenChildNodes = (childNodes, result) => {
|
||||
|
|
|
@ -348,8 +348,8 @@ export const handleDrag =
|
|||
document.onmouseup = () => {
|
||||
document.onmousemove = demMousemove
|
||||
document.onmouseup = demMouseup
|
||||
props.draggable && state.move && emit('drag-end', event)
|
||||
state.move = false
|
||||
props.draggable && emit('drag-end', event)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -73,8 +73,16 @@ export const multiGridSelectAll =
|
|||
}
|
||||
})
|
||||
} else {
|
||||
state.selectedValues = []
|
||||
state.selectedDatas = []
|
||||
// 同步勿删,跨页取消全选时,仅删除当前页数据
|
||||
const { data = [] } = props.gridOp || {}
|
||||
data.forEach((item) => {
|
||||
const selectedItem = state.selectedValues.find((i) => i === item[props.valueField])
|
||||
if (selectedItem) {
|
||||
const index = state.selectedValues.indexOf(selectedItem)
|
||||
state.selectedValues.splice(index, 1)
|
||||
state.selectedDatas.splice(index, 1)
|
||||
}
|
||||
})
|
||||
state.selectedChanged = true
|
||||
}
|
||||
|
||||
|
@ -82,20 +90,41 @@ export const multiGridSelectAll =
|
|||
}
|
||||
|
||||
export const multiGridSelectChange =
|
||||
({ api, props, state }) =>
|
||||
({ api, props, state, vm }) =>
|
||||
({ row, checked }) => {
|
||||
const index = findIndexOf(state.selectedValues, (val) => val === row[props.valueField])
|
||||
const property = props.valueField
|
||||
const grid = vm.$refs?.multiGrid
|
||||
const selectedRows = grid.getSelectRecords()
|
||||
|
||||
if (checked) {
|
||||
if (!~index) {
|
||||
state.selectedValues = [...state.selectedValues, row[props.valueField]]
|
||||
state.selectedDatas = [...state.selectedDatas, row]
|
||||
// 获取新勾选的行
|
||||
const addSelectedRows = selectedRows.filter((row) => !state.selectedValues.includes(row[property]))
|
||||
if (addSelectedRows.length > 0) {
|
||||
state.selectedValues = [...state.selectedValues, ...addSelectedRows.map((row) => row[property])]
|
||||
state.selectedDatas = [...state.selectedDatas, ...addSelectedRows]
|
||||
state.selectedChanged = true
|
||||
}
|
||||
} else {
|
||||
if (~index) {
|
||||
state.selectedValues = [...state.selectedValues.slice(0, index), ...state.selectedValues.slice(index + 1)]
|
||||
state.selectedDatas = [...state.selectedDatas.slice(0, index), ...state.selectedDatas.slice(index + 1)]
|
||||
const childrenKey = props.gridOp?.treeConfig?.children
|
||||
const checkStrictly = props.gridOp?.selectConfig?.checkStrictly
|
||||
|
||||
const getCancelRows = (row, arr) => {
|
||||
arr.push(row)
|
||||
if (row[childrenKey]?.length > 0) {
|
||||
row[childrenKey].forEach((childRow) => getCancelRows(childRow, arr))
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// 获取取消勾选的列
|
||||
let cancelRows = checkStrictly ? [row] : getCancelRows(row, [])
|
||||
cancelRows = cancelRows.filter((row) => state.selectedValues.includes(row[property]))
|
||||
if (cancelRows.length > 0) {
|
||||
cancelRows.forEach((row) => {
|
||||
const index = state.selectedValues.indexOf(row[property])
|
||||
state.selectedValues.splice(index, 1)
|
||||
state.selectedDatas.splice(index, 1)
|
||||
})
|
||||
state.selectedChanged = true
|
||||
}
|
||||
}
|
||||
|
@ -385,16 +414,18 @@ export const setChecked =
|
|||
|
||||
export const computedConfig =
|
||||
({ props, state }) =>
|
||||
() => {
|
||||
(type) => {
|
||||
const { multi, popseletor, gridOp } = props
|
||||
const { selectConfig = {}, radioConfig = {} } = gridOp || {}
|
||||
const { selectedValues } = state
|
||||
let config = {}
|
||||
|
||||
if (popseletor === 'grid') {
|
||||
if (multi) {
|
||||
// 单选和多选同时使用computedConfig来获取配置,因此需要加type区分,否则单选和多选返回的是一模一样的配置
|
||||
if (multi && type === 'select') {
|
||||
config = Object.assign(config, selectConfig, { checkRowKeys: selectedValues })
|
||||
} else {
|
||||
}
|
||||
if (!multi && type === 'radio') {
|
||||
config = Object.assign(config, radioConfig, { checkRowKey: selectedValues[0] })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,8 +56,8 @@ export const renderless = (props, { reactive, computed, watch }, { vm, nextTick,
|
|||
selectedDatas: [],
|
||||
selectedValues: [],
|
||||
multiGridStore: {
|
||||
selectConfig: computed(() => api.computedConfig()),
|
||||
radioConfig: computed(() => api.computedConfig()),
|
||||
selectConfig: computed(() => api.computedConfig('select')),
|
||||
radioConfig: computed(() => api.computedConfig('radio')),
|
||||
inited: false,
|
||||
loading: false
|
||||
},
|
||||
|
@ -96,7 +96,7 @@ export const renderless = (props, { reactive, computed, watch }, { vm, nextTick,
|
|||
|
||||
Object.assign(api, {
|
||||
multiGridSelectAll: multiGridSelectAll({ api, props, state }),
|
||||
multiGridSelectChange: multiGridSelectChange({ api, props, state }),
|
||||
multiGridSelectChange: multiGridSelectChange({ api, props, state, vm }),
|
||||
multiTreeAfterLoad: multiTreeAfterLoad({ api, props, state, vm }),
|
||||
multiTreeCheck: multiTreeCheck({ api, props, state, vm, nextTick }),
|
||||
multiTreeFilterPlain: multiTreeFilterPlain({ api, props, state }),
|
||||
|
|