提交 cd1a5c5f 编写于 作者: B break60 提交者: qiaozhanwei

Modification date format and page signature (#1048)

* Delete third party import license

* Resource authorization add file resource and UDF resource tab

* Solve the problem that the initial value of timing is not assigned and the period cannot be selected if the second is selected.

* revert

* Modification date format and page signature

* Upgrade ANSY UI to version 0.1.46
上级 8eceb685
......@@ -63,9 +63,15 @@
</span>
</m-tooltips-JSON>
</td>
<td><span class="ellipsis">{{item.note}}</span></td>
<td><span>{{item.createTime | formatDate}}</span></td>
<td><span>{{item.updateTime | formatDate}}</span></td>
<td><span class="ellipsis" v-tooltip="item.note">{{item.note || '-'}}</span></td>
<td>
<span v-if="item.createTime">{{item.createTime | formatDate}}</span>
<span v-else>-</span>
</td>
<td>
<span v-if="item.updateTime">{{item.updateTime | formatDate}}</span>
<span v-else>-</span>
</td>
<td>
<x-button
type="info"
......
......@@ -92,7 +92,8 @@
<span>{{item.nodeCount}}</span>
</td>
<td>
<span>{{item.date | formatDate}}</span>
<span v-if="item.date">{{item.date | formatDate}}</span>
<span v-else>-</span>
</td>
<td>
<span class="state">
......
......@@ -62,12 +62,15 @@
<td><span>{{_rtPublishStatus(item.releaseState)}}</span></td>
<td>
<span v-if="item.createTime">{{item.createTime | formatDate}}</span>
<span v-if="!item.createTime">-</span>
<span v-else>-</span>
</td>
<td>
<span>{{item.updateTime | formatDate}}</span>
<span v-if="item.updateTime">{{item.updateTime | formatDate}}</span>
<span v-else>-</span>
</td>
<td>
<span class="ellipsis" v-tooltip="item.desc">{{item.desc || '-'}}</span>
</td>
<td><span class="ellipsis">{{item.desc}}</span></td>
<td>
<span v-if="item.scheduleReleaseState === 'OFFLINE'">{{$t('offline')}}</span>
<span v-if="item.scheduleReleaseState === 'ONLINE'">{{$t('online')}}</span>
......
......@@ -69,19 +69,22 @@
</td>
<td><span>{{_rtRunningType(item.commandType)}}</span></td>
<td>
<span v-if="!item.scheduleTime"></span>
<span v-else>{{item.scheduleTime | formatDate}}</span>
<span v-if="item.scheduleTime">{{item.scheduleTime | formatDate}}</span>
<span v-else>-</span>
</td>
<td>
<span v-if="item.startTime">{{item.startTime | formatDate}}</span>
<span v-else>-</span>
</td>
<td><span>{{item.startTime | formatDate}}</span></td>
<td>
<span v-if="item.endTime">{{item.endTime | formatDate}}</span>
<span v-if="!item.endTime">-</span>
<span v-else>-</span>
</td>
<td width="70"><span>{{item.duration || '-'}}</span></td>
<td width="70"><span>{{item.runTimes}}</span></td>
<td>
<span v-if="item.host">{{item.host}}</span>
<span v-if="!item.host">-</span>
<span v-else>-</span>
</td>
<td><span>{{item.recovery}}</span></td>
......
......@@ -66,11 +66,16 @@
<span>{{item.instRunningCount}}</span>
</td>
<td>
<span>{{item.desc}}</span>
<span class="ellipsis" v-tooltip="item.desc">{{item.desc || '-'}}</span>
</td>
<td>
<span v-if="item.createTime">{{item.createTime | formatDate}}</span>
<span v-else>-</span>
</td>
<td>
<span v-if="item.updateTime">{{item.updateTime | formatDate}}</span>
<span v-else>-</span>
</td>
<td><span>{{item.createTime | formatDate}}</span></td>
<td><span>{{item.updateTime | formatDate}}</span></td>
<td>
<x-button
type="info"
......
......@@ -66,11 +66,17 @@
<td><a href="javascript:" class="links" @click="_go(item)"><span class="ellipsis">{{item.processInstanceName}}</span></a></td>
<td><span>{{item.taskType}}</span></td>
<td><span v-html="_rtState(item.state)" style="cursor: pointer;"></span></td>
<td><span>{{item.submitTime | formatDate}}</span></td>
<td><span>{{item.startTime | formatDate}}</span></td>
<td>
<span v-if="item.submitTime">{{item.submitTime | formatDate}}</span>
<span v-else>-</span>
</td>
<td>
<span v-if="item.startTime">{{item.startTime | formatDate}}</span>
<span v-else>-</span>
</td>
<td>
<span v-if="item.endTime">{{item.endTime | formatDate}}</span>
<span v-if="!item.endTime">-</span>
<span v-else>-</span>
</td>
<td><span>{{item.host || '-'}}</span></td>
<td><span>{{item.duration}}</span></td>
......
......@@ -51,12 +51,15 @@
</span>
</td>
<td><span class="ellipsis">{{item.fileName}}</span></td>
<td><span class="ellipsis">{{item.desc}}</span></td>
<td>
<span class="ellipsis" v-tooltip="item.desc">{{item.desc || '-'}}</span>
</td>
<td>
<span>{{_rtSize(item.size)}}</span>
</td>
<td>
<span>{{item.updateTime | formatDate}}</span>
<span v-if="item.updateTime">{{item.updateTime | formatDate}}</span>
<span v-else>-</span>
</td>
<td>
<x-button
......
......@@ -67,7 +67,7 @@ v-ps<template>
<span>{{item.type}}</span>
</td>
<td>
<span class="ellipsis">{{item.desc || '-'}}</span>
<span class="ellipsis" v-tooltip="item.desc">{{item.desc || '-'}}</span>
</td>
<td>
<span>{{item.resourceName}}</span>
......@@ -76,7 +76,8 @@ v-ps<template>
<span>{{item.database || '-'}}</span>
</td>
<td>
<span>{{item.updateTime | formatDate}}</span>
<span v-if="item.updateTime">{{item.updateTime | formatDate}}</span>
<span v-else>-</span>
</td>
<td>
<x-button
......
......@@ -58,13 +58,15 @@
<span>{{_rtSize(item.size)}}</span>
</td>
<td>
<span class="ellipsis">{{item.desc || '-'}}</span>
<span class="ellipsis" v-tooltip="item.desc">{{item.desc || '-'}}</span>
</td>
<td>
<span>{{item.createTime | formatDate}}</span>
<span v-if="item.createTime">{{item.createTime | formatDate}}</span>
<span v-else>-</span>
</td>
<td>
<span>{{item.updateTime | formatDate}}</span>
<span v-if="item.updateTime">{{item.updateTime | formatDate}}</span>
<span v-else>-</span>
</td>
<td>
<x-button
......
......@@ -59,13 +59,19 @@
</span>
</td>
<td>
<span>{{item.desc}}</span>
<span class="ellipsis" v-tooltip="item.desc">{{item.desc || '-'}}</span>
</td>
<td>
<span>{{item.queueName}}</span>
</td>
<td><span>{{item.createTime | formatDate}}</span></td>
<td><span>{{item.updateTime | formatDate}}</span></td>
<td>
<span v-if="item.createTime">{{item.createTime | formatDate}}</span>
<span v-else>-</span>
</td>
<td>
<span v-if="item.updateTime">{{item.updateTime | formatDate}}</span>
<span v-else>-</span>
</td>
<td>
<x-button
type="info"
......
......@@ -71,8 +71,14 @@
<td>
<span>{{item.phone || '-'}}</span>
</td>
<td><span>{{item.createTime | formatDate}}</span></td>
<td><span>{{item.updateTime | formatDate}}</span></td>
<td>
<span v-if="item.createTime">{{item.createTime | formatDate}}</span>
<span v-else>-</span>
</td>
<td>
<span v-if="item.updateTime">{{item.updateTime | formatDate}}</span>
<span v-else>-</span>
</td>
<td>
<x-poptip
:ref="'poptip-auth-' + $index"
......
......@@ -52,12 +52,16 @@
</td>
<td><span>{{item.groupType === 'EMAIL' ? `${$t('Email')}` : `${$t('SMS')}`}}</span></td>
<td>
<span>{{item.desc}}</span>
<span class="ellipsis" v-tooltip="item.desc">{{item.desc || '-'}}</span>
</td>
<td>
<span>{{item.createTime | formatDate}}</span>
<span v-if="item.createTime">{{item.createTime | formatDate}}</span>
<span v-else>-</span>
</td>
<td>
<span v-if="item.updateTime">{{item.updateTime | formatDate}}</span>
<span v-else>-</span>
</td>
<td><span>{{item.updateTime | formatDate}}</span></td>
<td>
<x-button type="info" shape="circle" size="xsmall" data-toggle="tooltip" icon="iconfont icon-yonghu1" :title="$t('Managing Users')" @click="_mangeUser(item)">
</x-button>
......
......@@ -51,9 +51,13 @@
<span>{{item.ipList}}</span>
</td>
<td>
<span>{{item.createTime | formatDate}}</span>
<span v-if="item.createTime">{{item.createTime | formatDate}}</span>
<span v-else>-</span>
</td>
<td>
<span v-if="item.updateTime">{{item.updateTime | formatDate}}</span>
<span v-else>-</span>
</td>
<td><span>{{item.updateTime | formatDate}}</span></td>
<td>
<x-button type="info" shape="circle" size="xsmall" data-toggle="tooltip" icon="iconfont icon-bianjixiugai" :title="$t('Edit')" @click="_edit(item)">
</x-button>
......
......@@ -52,10 +52,17 @@
</td>
<td><span>{{item.token}}</span></td>
<td>
<span>{{item.expireTime | formatDate}}</span>
<span v-if="item.expireTime">{{item.expireTime | formatDate}}</span>
<span v-else>-</span>
</td>
<td>
<span v-if="item.createTime">{{item.createTime | formatDate}}</span>
<span v-else>-</span>
</td>
<td>
<span v-if="item.updateTime">{{item.updateTime | formatDate}}</span>
<span v-else>-</span>
</td>
<td><span>{{item.createTime | formatDate}}</span></td>
<td><span>{{item.updateTime | formatDate}}</span></td>
<td>
<x-button type="info" shape="circle" size="xsmall" data-toggle="tooltip" icon="iconfont icon-bianjixiugai" :title="$t('Edit')" @click="_edit(item)">
</x-button>
......
......@@ -453,7 +453,7 @@ export default {
'Avg latency': '平均延时',
'Max latency': '最大延时',
'Node count': '节点数',
'Query time': '当前查询时间',
'Query time': '当前查询时间',
'Node self-test status': '节点自检状态',
'Health status': '健康状态',
'Max connections': '最大连接数',
......
因为 它太大了无法显示 source diff 。你可以改为 查看blob
......@@ -26,10 +26,10 @@ Created by iconfont
<glyph glyph-name="filter" unicode="&#58936;" d="M440.6096818342152-61.1951791181657c-7.411231604938271 0-14.823619047619045 3.7056158024691355-18.528079012345678 3.7056158024691355-11.118003245149911 7.411231604938271-18.53039068783069 22.234850652557316-18.53039068783069 33.351698059964725V298.27035880070537L77.4373722751323 768.9113058201058c-7.411231604938271 11.116847407407407-11.116847407407407 25.940466455026453-3.7056158024691355 40.7640855026455 7.412387442680775 11.116847407407407 18.529234850088184 18.528079012345678 33.352853897707234 18.528079012345678H922.3686320987654c14.823619047619045 0 25.940466455026453-7.4100757671957656 33.351698059964725-18.528079012345678 7.412387442680775-11.116847407407407 3.7056158024691355-25.940466455026453-3.7056158024691355-37.05846970017637L625.9020303350969 298.27035880070537v-248.29128465608463c0-14.823619047619045-7.412387442680775-25.940466455026453-22.234850652557316-33.352853897707234L455.4333008818342-57.489563315696614c-3.7056158024691355-3.7056158024691355-7.411231604938271-3.7056158024691355-14.823619047619045-3.7056158024691355z" horiz-adv-x="1024" />
<glyph glyph-name="check" unicode="&#58953;" d="M400.22 76.49400000000003l569.83 679.097c11.005 13.115 30.558 14.826 43.674 3.82 13.115-11.004 14.826-30.558 3.82-43.673L425.7 10.404999999999973c-11.005-13.115-30.559-14.826-43.674-3.82a31.285 31.285 0 0 0-2.999 2.874l-0.303 0.27L10.78 341.02700000000004c-13.134 11.825-14.194 32.059-2.369 45.192 11.826 13.134 32.06 14.194 45.193 2.369L400.22 76.49400000000003z" horiz-adv-x="1024" />
<glyph glyph-name="search" unicode="&#59449;" d="M949.248-2.048000000000002c7.168-8.192 10.752-16.896 10.752-26.112 0-9.216-3.584-17.408-10.752-25.088-7.168-7.168-15.872-10.752-25.088-10.752-9.216 0-17.92 3.584-25.088 10.752l-205.824 204.8c-33.28-27.136-70.656-48.64-112.64-64.512-41.472-15.872-86.016-23.552-132.608-23.552-108.544 2.56-199.168 39.936-271.36 112.64-72.192 72.192-110.08 162.816-112.64 271.36 2.56 108.544 39.936 199.168 112.64 271.36 72.192 72.192 162.816 110.08 271.36 112.64 108.544-2.56 199.168-39.936 271.36-112.64 72.192-72.192 110.08-162.816 112.64-271.36 0-46.592-7.68-90.624-23.552-132.608-15.872-41.472-37.376-79.36-64.512-112.64l205.824-204.8h-0.512z m-280.576 229.376c29.184 29.184 51.712 62.464 67.584 99.84 15.872 37.888 24.064 77.824 24.064 120.32s-8.192 82.944-24.064 120.32c-15.872 37.888-38.4 71.168-67.584 99.84S606.208 719.8720000000001 568.32 736.256c-37.888 15.872-77.824 24.064-120.32 24.064S365.056 752.1279999999999 327.68 736.256c-37.888-15.872-71.168-38.4-99.84-67.584S176.128 606.2080000000001 160.256 568.3199999999999c-15.872-37.888-24.064-77.824-24.064-120.32s8.192-82.944 24.064-120.32c15.872-37.888 38.4-71.168 67.584-99.84s62.464-51.712 99.84-67.584c37.888-15.872 77.824-24.064 120.32-24.064s82.944 8.192 120.832 25.088c37.376 14.848 70.656 37.376 99.84 66.048z" horiz-adv-x="1024" />
<glyph glyph-name="search" unicode="&#58956;" d="M700.109 148.63300000000004l-69.093 69.093c-66.65-55.615-152.486-89.088-246.155-89.088-212.078 0-384 171.588-384 383.252C0.86 723.553 172.783 895.14 384.86 895.14c212.077 0 384-171.588 384-383.251 0-95.204-34.782-182.3-92.355-249.322l67.22-67.218c21.836 6.634 46.525 1.318 63.79-15.947l197.667-197.666c24.945-24.945 24.945-65.389 0-90.334-24.945-24.945-65.388-24.945-90.333 0L717.183 89.07000000000005c-16.159 16.16-21.85 38.822-17.074 59.563zM384.861 192.53999999999996c176.716 0 319.972 142.978 319.972 319.35 0 176.371-143.256 319.349-319.972 319.349-176.716 0-319.973-142.978-319.973-319.35 0-176.371 143.257-319.349 319.973-319.349z" horiz-adv-x="1024" />
<glyph glyph-name="check" unicode="&#58953;" d="M400.22 76.49400000000003l569.83 679.097c11.005 13.115 30.558 14.826 43.674 3.82 13.115-11.004 14.826-30.558 3.82-43.673L425.7 10.404999999999973c-11.005-13.115-30.559-14.826-43.674-3.82a31.285 31.285 0 0 0-2.999 2.874l-0.303 0.27L10.78 341.02700000000004c-13.134 11.825-14.194 32.059-2.369 45.192 11.826 13.134 32.06 14.194 45.193 2.369L400.22 76.49400000000003z" horiz-adv-x="1024" />
<glyph glyph-name="off" unicode="&#58957;" d="M272.341 802.669c15.316 8.817 34.88 3.55 43.698-11.767 8.818-15.317 3.55-34.88-11.766-43.699C175.827 673.2570000000001 95 536.463 95 385.54c0-230.303 186.697-417 417-417s417 186.697 417 417c0 150.966-80.872 287.793-209.376 361.724-15.318 8.813-20.592 28.376-11.78 43.695 8.814 15.319 28.377 20.592 43.696 11.78C899.696 717.5 993 559.6379999999999 993 385.537c0-265.648-215.351-481-481-481s-481 215.352-481 481c0 174.052 93.252 331.876 241.341 417.13zM512 896c17.673 0 32-14.327 32-32v-512c0-17.673-14.327-32-32-32-17.673 0-32 14.327-32 32V864c0 17.673 14.327 32 32 32z" horiz-adv-x="1024" />
......@@ -98,6 +98,15 @@ Created by iconfont
<glyph glyph-name="increase" unicode="&#58988;" d="M164 700v-632c0-17.673 14.327-32 32-32h632c17.673 0 32 14.327 32 32V700c0 17.673-14.327 32-32 32H196c-17.673 0-32-14.327-32-32z m0 96h696c35.346 0 64-28.654 64-64v-696c0-35.346-28.654-64-64-64H164c-35.346 0-64 28.654-64 64V732c0 35.346 28.654 64 64 64zM528 588v-376c0-17.673-14.327-32-32-32-17.673 0-32 14.327-32 32V588c0 17.673 14.327 32 32 32 17.673 0 32-14.327 32-32zM716 400c0-17.673-14.327-32-32-32H308c-17.673 0-32 14.327-32 32 0 17.673 14.327 32 32 32h376c17.673 0 32-14.327 32-32z" horiz-adv-x="1024" />
<glyph glyph-name="eye" unicode="&#59586;" d="M1012.736 349.696c-104.96-173.056-297.472-289.792-500.736-289.792s-395.264 117.248-500.736 289.792C4.608 361.472 0 374.784 0 389.12s4.608 27.648 11.264 39.424C116.736 601.088 309.248 718.336 512 718.336s395.264-117.248 500.736-289.792c6.656-11.776 11.264-25.088 11.264-39.424s-4.608-27.648-11.264-39.424z m-279.552 241.152c23.04-38.912 34.816-83.456 34.816-128.512 0-141.312-114.688-256-256-256s-256 114.688-256 256c0 45.056 11.776 89.6 34.816 128.512-89.088-45.568-163.328-117.76-217.6-201.728 97.792-151.04 255.488-256 438.784-256s340.992 104.96 438.784 256c-54.272 83.968-128.512 156.16-217.6 201.728zM512 635.904c-95.232 0-173.568-78.336-173.568-173.568 0-14.848 12.8-27.648 27.648-27.648s27.648 12.8 27.648 27.648C393.216 527.36 446.976 581.12 512 581.12c14.848 0 27.648 12.8 27.648 27.648s-12.8 27.136-27.648 27.136z" horiz-adv-x="1029" />
<glyph glyph-name="amount-desc" unicode="&#59587;" d="M406.543284 63.554228999999964L225.178109-117.81094499999995c-4.075622-3.566169-8.660697-5.094527-13.245771-5.094528s-9.170149 1.528358-13.245771 5.094528L16.81194 64.06368199999997c-5.094527 5.60398-6.622886 13.245771-4.075622 19.868656 3.056716 6.622886 9.679602 11.20796 16.811941 11.207961h109.022885V877.659701c0 10.189055 8.151244 18.340299 18.340299 18.340299h109.022885c10.189055 0 18.340299-8.151244 18.340299-18.340299v-782.519402h109.022885c10.189055 0 18.340299-8.151244 18.340299-18.340299 0.509453-4.585075-2.037811-9.170149-5.094527-13.245771zM685.21393 768.636816c0-10.189055-8.151244-18.340299-18.340298-18.340299h-145.703483c-10.189055 0-18.340299 8.151244-18.340298 18.340299V877.659701c0 10.189055 8.151244 18.340299 18.340298 18.340299h145.703483c10.189055 0 18.340299-8.151244 18.340298-18.340299V768.636816z m109.022886-290.897513c0-10.189055-8.151244-18.340299-18.340299-18.340298h-254.726368c-10.189055 0-18.340299 8.151244-18.340298 18.340298V586.762189c0 10.189055 8.151244 18.340299 18.340298 18.340299h254.726368c10.189055 0 18.340299-8.151244 18.340299-18.340299v-109.022886z m109.022885-291.406965c0-10.189055-8.151244-18.340299-18.340298-18.340298h-363.749254c-10.189055 0-18.340299 8.151244-18.340298 18.340298v109.022886c0 10.189055 8.151244 18.340299 18.340298 18.340298h363.749254c10.189055 0 18.340299-8.151244 18.340298-18.340298v-109.022886z m109.022886-290.897512c0-10.189055-8.151244-18.340299-18.340298-18.340299h-473.281592c-10.189055 0-18.340299 8.151244-18.340299 18.340299V4.4577110000000175c0 10.189055 8.151244 18.340299 18.340299 18.340299h473.281592c10.189055 0 18.340299-8.151244 18.340298-18.340299v-109.022885z" horiz-adv-x="1024" />
<glyph glyph-name="amount-asc" unicode="&#59589;" d="M406.543284 63.554228999999964L225.178109-117.81094499999995c-4.075622-3.566169-8.660697-5.094527-13.245771-5.094528s-9.170149 1.528358-13.245771 5.094528L16.81194 64.06368199999997c-5.094527 5.60398-6.622886 13.245771-4.075622 19.868656 3.056716 6.622886 9.679602 11.20796 16.811941 11.207961h109.022885V877.659701c0 10.189055 8.151244 18.340299 18.340299 18.340299h109.022885c10.189055 0 18.340299-8.151244 18.340299-18.340299v-782.519402h109.022885c10.189055 0 18.340299-8.151244 18.340299-18.340299 0.509453-4.585075-2.037811-9.170149-5.094527-13.245771zM1012.282587 768.636816c0-10.189055-8.151244-18.340299-18.340298-18.340299h-473.281592c-10.189055 0-18.340299 8.151244-18.340299 18.340299V877.659701c0 10.189055 8.151244 18.340299 18.340299 18.340299h473.281592c10.189055 0 18.340299-8.151244 18.340298-18.340299V768.636816z m-109.022886-290.897513c0-10.189055-8.151244-18.340299-18.340298-18.340298h-363.749254c-10.189055 0-18.340299 8.151244-18.340298 18.340298V586.762189c0 10.189055 8.151244 18.340299 18.340298 18.340299h363.749254c10.189055 0 18.340299-8.151244 18.340298-18.340299v-109.022886z m-109.022885-291.406965c0-10.189055-8.151244-18.340299-18.340299-18.340298h-254.726368c-10.189055 0-18.340299 8.151244-18.340298 18.340298v109.022886c0 10.189055 8.151244 18.340299 18.340298 18.340298h254.726368c10.189055 0 18.340299-8.151244 18.340299-18.340298v-109.022886zM685.21393-104.56517399999996c0-10.189055-8.151244-18.340299-18.340298-18.340299h-145.703483c-10.189055 0-18.340299 8.151244-18.340298 18.340299V4.4577110000000175c0 10.189055 8.151244 18.340299 18.340298 18.340299h145.703483c10.189055 0 18.340299-8.151244 18.340298-18.340299v-109.022885z" horiz-adv-x="1024" />
</font>
......
{
"name": "@analysys/ans-ui",
"version": "0.0.22",
"description": "vue components for analysys",
"keywords": [
"analysys",
"UI"
],
"main": "lib/ans-ui.min.js",
"style": "lib/ans-ui.min.css",
"files": [
"lib",
"src",
"packages"
],
"license": "MIT",
"scripts": {
"build": "npm run clean && cross-env NODE_ENV=production webpack --config ./build/webpack.config.prod.js && webpack --config ./build/webpack.config.locale.js",
"dev": "npm run clean && parcel ./example/index.html -p 4000",
"build:c": "node build/component/buildComponent.js",
"dev:c": "npm run clean && rimraf .cache && node build/component/devComponent.js",
"clean": "rimraf dist",
"lint": "standard \"**/*.{js,vue}\"",
"lint:fix": "standard \"**/*.{js,vue}\" --fix",
"theme": "node-sass --output-style compressed ./src/style/index.scss > ./theme/ans.min.css && cp -rf ./src/style/font/. ./theme/font",
"prepublishOnly": "npm run build",
"start": "npm run dev",
"test": "npm run lint"
"_from": "@analysys/ans-ui",
"_id": "@analysys/ans-ui@0.1.46",
"_inBundle": false,
"_integrity": "sha1-2wM8Ul7F+u4ZrTSwyiEIHEiGd5k=",
"_location": "/@analysys/ans-ui",
"_phantomChildren": {},
"_requested": {
"type": "tag",
"registry": true,
"raw": "@analysys/ans-ui",
"name": "@analysys/ans-ui",
"escapedName": "@analysys%2fans-ui",
"scope": "@analysys",
"rawSpec": "",
"saveSpec": null,
"fetchSpec": "latest"
},
"peerDependencies": {
"vue": ">=2"
"_requiredBy": [
"#USER",
"/"
],
"_resolved": "http://registry.npm.analysys.cn/@analysys/ans-ui/download/@analysys/ans-ui-0.1.46.tgz",
"_shasum": "db033c525ec5faee19ad34b0ca21081c48867799",
"_spec": "@analysys/ans-ui",
"_where": "/Users/xiangcaibiao/Downloads/escheduler/dolphinscheduler-ui",
"bundleDependencies": false,
"config": {
"ghooks": {}
},
"dependencies": {
"async-validator": "^1.10.0",
"dayjs": "^1.7.7",
"deepmerge": "^3.2.0",
"normalize-wheel": "^1.0.1",
"popper.js": "^1.14.4"
"popper.js": "^1.14.4",
"throttle-debounce": "^2.1.0"
},
"deprecated": false,
"description": "vue components for analysys",
"devDependencies": {
"@fedor/progress-webpack-plugin": "^1.0.0",
"@fedor/standard": "^1.0.3",
......@@ -53,6 +54,7 @@
"babel-plugin-transform-runtime": "^6.23.0",
"babel-plugin-transform-vue-jsx": "^3.7.0",
"babel-preset-env": "^1.5.2",
"babel-runtime": "^6.26.0",
"cross-env": "^5.2.0",
"css-loader": "0.28.8",
"cssnano": "^4.0.3",
......@@ -76,12 +78,40 @@
"webpack": "^3",
"webpack-merge": "^4.1.3"
},
"files": [
"lib",
"src",
"packages"
],
"keywords": [
"analysys",
"UI"
],
"license": "MIT",
"main": "lib/ans-ui.min.js",
"maintainers": [
{
"name": "liuxin",
"email": "liuxin@analysys.com.cn"
}
],
"name": "@analysys/ans-ui",
"peerDependencies": {
"vue": ">=2"
},
"scripts": {
"build": "npm run clean && cross-env NODE_ENV=production webpack --config ./build/webpack.config.prod.js && webpack --config ./build/webpack.config.locale.js",
"build:c": "node build/component/buildComponent.js",
"clean": "rimraf dist",
"dev": "npm run clean && parcel ./example/index.html -p 4000",
"dev:c": "npm run clean && rimraf .cache && node build/component/devComponent.js",
"lint": "standard \"**/*.{js,vue}\"",
"lint:fix": "standard \"**/*.{js,vue}\" --fix",
"prepublishOnly": "npm run build",
"start": "npm run dev",
"test": "npm run lint",
"theme": "node-sass --output-style compressed ./src/style/index.scss > ./theme/ans.min.css && cp -rf ./src/style/font/. ./theme/font"
},
"standard": {
"parser": "babel-eslint",
"ignore": [
......@@ -89,7 +119,6 @@
"packages/*"
]
},
"config": {
"ghooks": {}
}
"style": "lib/ans-ui.min.css",
"version": "0.1.46"
}
......@@ -17,6 +17,7 @@ cancel | 点击取消的回调 | Object | {show [Boolean] ,text [String], handle
render | 自定义内容 | Function | 使用时 content, title ,ok , cancel 失效 | -
showMask | 是否显示遮罩 | Boolean | - | false
maskClosable | 点击遮罩是否关闭 | Boolean | - | false
i18n | 国际化对象 | VueI18n | - | -
#### Modal 实例方法
......@@ -34,6 +35,7 @@ content | 内容 | String | - | -
duration | 自动关闭的延时,单位秒,不关闭可以写 0 | Number | - | 1.5
onClose | 关闭时的回调 | Function | - | -
closable | 是否显示关闭图标 | Boolean | - | false
i18n | 国际化对象 | VueI18n | - | -
#### Message 全局相关
......@@ -57,6 +59,7 @@ content | 内容 | String | - | -
duration | 自动关闭的延时,单位秒,不关闭可以写 0 | Number | - | 1.5
onClose | 关闭时的回调 | Function | - | -
closable | 是否显示关闭图标 | Boolean | - | false
i18n | 国际化对象 | VueI18n | - | -
#### Notice 全局相关
......
......@@ -9,6 +9,7 @@ BoxManager.newInstance = properties => {
const Instance = new Vue({
data: _props,
i18n: _props.i18n,
render (h) {
return h(BoxManager, {
props: _props
......
......@@ -13,7 +13,8 @@ let defaultConfig = {
// 设置出现的位置在浏览器顶部的距离
top: 60,
transitionName: `${ANIMATION_PREFIX}move-in`,
fixed: true
fixed: true,
i18n: null
}
let iconTypes = {
......@@ -24,20 +25,28 @@ let iconTypes = {
'loading': 'ans-icon-spinner'
}
function getMessageInstance () {
function getMessageInstance (i18n) {
messageInstance = messageInstance || BoxManager.newInstance({
prefixCls: prefixCls,
styles: {
top: defaultConfig.top + 'px',
left: '50%'
},
className: defaultConfig.fixed ? `${prefixCls}-fixed` : ''
className: defaultConfig.fixed ? `${prefixCls}-fixed` : '',
i18n
})
return messageInstance
}
function notice (content = '', duration = defaultConfig.duration, type, onClose = function () {}, closable = false) {
let instance = getMessageInstance()
function notice (
content = '',
duration = defaultConfig.duration,
type,
onClose = function () {},
closable = false,
i18n = defaultConfig.i18n
) {
let instance = getMessageInstance(i18n)
instance.notice({
name: `${prefixKey}${name}`,
......@@ -70,23 +79,23 @@ export default {
name: 'Message',
info (options) {
options = formatOptions(options)
return notice(options.content, options.duration, 'info', options.onClose, options.closable)
return notice(options.content, options.duration, 'info', options.onClose, options.closable, options.i18n)
},
success (options) {
options = formatOptions(options)
return notice(options.content, options.duration, 'success', options.onClose, options.closable)
return notice(options.content, options.duration, 'success', options.onClose, options.closable, options.i18n)
},
warning (options) {
options = formatOptions(options)
return notice(options.content, options.duration, 'warning', options.onClose, options.closable)
return notice(options.content, options.duration, 'warning', options.onClose, options.closable, options.i18n)
},
error (options) {
options = formatOptions(options)
return notice(options.content, options.duration, 'error', options.onClose, options.closable)
return notice(options.content, options.duration, 'error', options.onClose, options.closable, options.i18n)
},
loading (options) {
options = formatOptions(options)
return notice(options.content, options.duration, 'loading', options.onClose, options.closable)
return notice(options.content, options.duration, 'loading', options.onClose, options.closable, options.i18n)
},
config (cfg = {}) {
defaultConfig = Object.assign(defaultConfig, cfg)
......
......@@ -17,13 +17,15 @@ let customModal
let defaultConfig = {
// 设置全局的自动关闭时间,为0时不自动消失
duration: 0,
transitionName: `${ANIMATION_PREFIX}modal-down`
transitionName: `${ANIMATION_PREFIX}modal-down`,
i18n: null
}
function getMessageInstance () {
function getMessageInstance (i18n) {
messageInstance = messageInstance || BoxManager.newInstance({
prefixCls: prefixCls,
styles: {}
styles: {},
i18n
})
return messageInstance
}
......@@ -45,7 +47,8 @@ function getMessageInstance () {
* maskClosable
*/
function notice (options) {
let instance = getMessageInstance()
const i18n = options.i18n || defaultConfig.i18n
let instance = getMessageInstance(i18n)
let keyName = `${prefixKey}${name}`
......@@ -56,6 +59,7 @@ function notice (options) {
let comp = instance.component.$children.find(o => o.name === keyName)
if (options.render) {
customModal = new Vue({
i18n,
name: 'customModal',
render: options.render,
mounted () {
......@@ -74,6 +78,7 @@ function notice (options) {
}).$mount(comp.$refs.content)
} else {
customModal = new Vue({
i18n,
name: 'defaultModal',
data: {
width: options.width ? options.width : '520',
......
......@@ -14,7 +14,8 @@ let defaultConfig = {
top: 60,
right: 20,
transitionName: `${ANIMATION_PREFIX}move-right`,
list: true
list: true,
i18n: null
}
let iconTypes = {
......@@ -25,20 +26,29 @@ let iconTypes = {
'loading': 'ans-icon-spinner'
}
function getMessageInstance () {
function getMessageInstance (i18n) {
messageInstance = messageInstance || BoxManager.newInstance({
prefixCls: prefixCls,
styles: {
top: defaultConfig.top + 'px',
right: defaultConfig.right + 'px'
},
className: defaultConfig.list ? `${prefixCls}-list` : ''
className: defaultConfig.list ? `${prefixCls}-list` : '',
i18n
})
return messageInstance
}
function notice (title = '', content = '', duration = defaultConfig.duration, type, onClose = function () {}, closable = false) {
let instance = getMessageInstance()
function notice (
title = '',
content = '',
duration = defaultConfig.duration,
type,
onClose = function () {},
closable = false,
i18n = defaultConfig.i18n
) {
let instance = getMessageInstance(i18n)
instance.notice({
name: `${prefixKey}${name}`,
......@@ -75,23 +85,23 @@ export default {
name: 'Notice',
info (options) {
options = formatOptions(options)
return notice(options.title, options.content, options.duration, 'info', options.onClose, options.closable)
return notice(options.title, options.content, options.duration, 'info', options.onClose, options.closable, options.i18n)
},
success (options) {
options = formatOptions(options)
return notice(options.title, options.content, options.duration, 'success', options.onClose, options.closable)
return notice(options.title, options.content, options.duration, 'success', options.onClose, options.closable, options.i18n)
},
warning (options) {
options = formatOptions(options)
return notice(options.title, options.content, options.duration, 'warning', options.onClose, options.closable)
return notice(options.title, options.content, options.duration, 'warning', options.onClose, options.closable, options.i18n)
},
error (options) {
options = formatOptions(options)
return notice(options.title, options.content, options.duration, 'error', options.onClose, options.closable)
return notice(options.title, options.content, options.duration, 'error', options.onClose, options.closable, options.i18n)
},
loading (options) {
options = formatOptions(options)
return notice(options.title, options.content, options.duration, 'loading', options.onClose, options.closable)
return notice(options.title, options.content, options.duration, 'loading', options.onClose, options.closable, options.i18n)
},
config (cfg = {}) {
defaultConfig = Object.assign(defaultConfig, cfg)
......
......@@ -11,6 +11,7 @@ label | 组合使用时有效,指定当前选项value值 | String / Number / B
disabled | 是否禁用 | Boolean | - | false
true-value | 自定义选中时的值 | String / Number / Boolean | - | true
false-value | 自定义未选中时的值 | String / Number / Boolean | - | false
indeterminate | 设置 indeterminate 状态,只负责样式控制 | Boolean | - | false
### Checkbox events
......
......@@ -10,10 +10,17 @@
<section class="demo-section">
<h4>组合</h4>
<div>
<x-checkbox-group v-model="md" @on-change="onChange">
<x-checkbox :label="'香蕉'" disabled>香蕉</x-checkbox>
<x-checkbox :label="'苹果'">苹果</x-checkbox>
<x-checkbox :label="'橘子'">橘子</x-checkbox>
<x-checkbox-group v-model="favorites" @on-change="onChange">
<x-checkbox v-for="(f, i) in fruits" :label="f" :key="f" :disabled="!i">{{f}}</x-checkbox>
</x-checkbox-group>
</div>
</section>
<section class="demo-section">
<h4>indeterminate 状态</h4>
<div>
<x-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @on-change="handleCheckAll">全选</x-checkbox>
<x-checkbox-group v-model="favorites" @on-change="handleCheck">
<x-checkbox v-for="f in fruits" :label="f" :key="f">{{f}}</x-checkbox>
</x-checkbox-group>
</div>
</section>
......@@ -27,8 +34,11 @@ export default {
name: 'app',
data () {
return {
md: ['香蕉', '苹果', '橘子'],
ck: ''
ck: '',
fruits: ['香蕉', '苹果', '橘子'],
favorites: ['苹果', '橘子'],
checkAll: false,
isIndeterminate: true
}
},
components: { xCheckboxGroup, xCheckbox },
......@@ -38,6 +48,15 @@ export default {
},
clickMe (d) {
console.log(d)
},
handleCheckAll (val) {
this.favorites = val ? this.fruits : []
this.isIndeterminate = false
},
handleCheck (value) {
let checkedCount = value.length
this.checkAll = checkedCount === this.fruits.length
this.isIndeterminate = checkedCount > 0 && checkedCount < this.fruits.length
}
}
}
......
......@@ -60,6 +60,11 @@ export default {
falseValue: {
type: [Boolean, String, Number],
default: false
},
// 不确定状态
indeterminate: {
type: Boolean,
default: false
}
},
computed: {
......@@ -73,6 +78,7 @@ export default {
checkedClass () {
return [{
[`${prefixCls}`]: true,
['is-indeterminate']: this.indeterminate,
[`${prefixCls}-checked`]: !!this.currentValue
}]
}
......
......@@ -23,7 +23,7 @@ export default {
data () {
return {
currentValue: this.value,
childrens: []
children: []
}
},
computed: {
......@@ -37,9 +37,9 @@ export default {
methods: {
updateModel (update) {
const value = this.value
this.childrens = findComponentsDownward(this, 'xCheckbox')
if (this.childrens) {
this.childrens.forEach(child => {
this.children = findComponentsDownward(this, 'xCheckbox')
if (this.children) {
this.children.forEach(child => {
child.model = value
if (update) {
child.currentValue = value.indexOf(child.label) >= 0
......
......@@ -38,13 +38,12 @@ for (let i = 10; i < 100; i++) {
}
const WEEKS = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']
const daysInWeek = WEEKS.map(w => t(`ans.datepicker.weeks.${w}`))
export default {
components: { ym },
data () {
return {
week: daysInWeek,
week: WEEKS.map(w => t(`ans.datepicker.weeks.${w}`)),
// 本月一号星期几
weeks: 0,
......
......@@ -2,37 +2,49 @@
<div class="x-date-packer-time" :style="{width: type==='daterange' ? '305px' : 'auto'}">
<div class="packer-time-body" :class="[getType()]">
<div class="hd-text" v-if="type==='daterange'">{{t('ans.datepicker.startTime')}}</div>
<div class="picker-time-div time-hours" ref="hours">
<ul>
<li v-for="(item,index) in 24" :class="{'time-act': index == hours}" @click="change(index, 'hours')">{{numLen(index)}}</li>
<div class="picker-time-div time-hours" ref="hours" >
<ul @mouseover="hoverBlock('start', 0)">
<li v-for="(item,index) in setStep(24, step[0])" :key="index"
:class="{'time-act': item == hours}"
@click="change(item, 'hours')">{{numLen(item)}}</li>
</ul>
</div>
<div class="picker-time-div time-minute" ref="minute">
<ul>
<li v-for="(item,index) in 60" :class="{'time-act': index == minute}" @click="change(index, 'minute')">{{numLen(index)}}</li>
<ul @mouseover="hoverBlock('start', 1)">
<li v-for="(item,index) in setStep(60, step[1])" :key="index"
:class="{'time-act': item == minute}"
@click="change(item, 'minute')">{{numLen(item)}}</li>
</ul>
</div>
<div class="picker-time-div time-second" ref="second">
<ul>
<li v-for="(item,index) in 60" :class="{'time-act': index == second}" @click="change(index, 'second')">{{numLen(index)}}</li>
<ul @mouseover="hoverBlock('start', 2)">
<li v-for="(item,index) in setStep(60, step[2])" :key="index"
:class="{'time-act': item == second}"
@click="change(item, 'second')">{{numLen(item)}}</li>
</ul>
</div>
</div>
<div class="packer-time-body" :class="[getType()]" v-if="type==='daterange'" style="float:right">
<div class="hd-text" v-if="type==='daterange'">{{t('ans.datepicker.endTime')}}</div>
<div class="picker-time-div time-hours bd-left" ref="hours1">
<ul>
<li v-for="(item,index) in 24" :class="{'time-act': index == hours1}" @click="changeLast(index, 'hours1')">{{numLen(index)}}</li>
<ul @mouseover="hoverBlock('end', 0)">
<li v-for="(item,index) in setStep(24, step[0])" :key="index"
:class="{'time-act': item == hours1}"
@click="changeLast(item, 'hours1')">{{numLen(item)}}</li>
</ul>
</div>
<div class="picker-time-div time-minute" ref="minute1">
<ul>
<li v-for="(item,index) in 60" :class="{'time-act': index == minute1}" @click="changeLast(index, 'minute1')">{{numLen(index)}}</li>
<ul @mouseover="hoverBlock('end', 1)">
<li v-for="(item,index) in setStep(60, step[1])" :key="index"
:class="{'time-act': item == minute1}"
@click="changeLast(item, 'minute1')">{{numLen(item)}}</li>
</ul>
</div>
<div class="picker-time-div time-second" ref="second1">
<ul>
<li v-for="(item,index) in 60" :class="{'time-act': index == second1}" @click="changeLast(index, 'second1')">{{numLen(index)}}</li>
<ul @mouseover="hoverBlock('end', 2)">
<li v-for="(item,index) in setStep(60, step[2])" :key="index"
:class="{'time-act': item == second1}"
@click="changeLast(item, 'second1')">{{numLen(item)}}</li>
</ul>
</div>
</div>
......@@ -58,7 +70,13 @@ export default {
},
props: {
format: String,
type: String
type: String,
step: {
type: Array,
default() {
return [1, 1, 1]
}
}
},
mixins: [Locale],
methods: {
......@@ -84,15 +102,47 @@ export default {
this.second1 = null
}
},
setStep (num, step) {
if(!step) {
step = 1
}
if (num === 1 || !num) {
return num
}
let n = []
for (let i = 0; i < num; i++) {
if(i % step === 0) {
n.push(i)
}
}
return n
},
getStepScrollTop (num, index) {
let selfStep = this.step[index]
if(selfStep && selfStep > 1) {
return num % selfStep === 0 ? (num / selfStep) * 25 : 0
}
return num * 25
},
setScrollTop () {
// let step = (num, index) => {
// let selfStep = this.step[index]
// if(selfStep && selfStep > 1) {
// return num % selfStep === 0 ? num / selfStep : 0
// }
// return num
// }
setTimeout(() => {
this.$refs.hours.scrollTop = this.hours * 25
this.$refs.minute.scrollTop = this.minute * 25
this.$refs.second.scrollTop = this.second * 25
if (this.$refs.hours1) this.$refs.hours1.scrollTop = this.hours1 * 25
if (this.$refs.minute1) this.$refs.minute1.scrollTop = this.minute1 * 25
if (this.$refs.second1) this.$refs.second1.scrollTop = this.second1 * 25
this.$refs.hours.scrollTop = this.getStepScrollTop(this.hours, 0)
this.$refs.minute.scrollTop = this.getStepScrollTop(this.minute, 1)
this.$refs.second.scrollTop = this.getStepScrollTop(this.second, 2)
if (this.$refs.hours1) this.$refs.hours1.scrollTop = this.getStepScrollTop(this.hours1, 0)
if (this.$refs.minute1) this.$refs.minute1.scrollTop = this.getStepScrollTop(this.minute1, 1)
if (this.$refs.second1) this.$refs.second1.scrollTop = this.getStepScrollTop(this.second1, 2)
}, 10)
},
......@@ -111,7 +161,18 @@ export default {
setHms (value, type) {
this[type] = value
this.$refs[type].scrollTop = value * 25
let index = 0
if(/minute/.test(type)) {
index = 1
}
if(/second/.test(type)) {
index = 2
}
this.$refs[type].scrollTop = this.getStepScrollTop(value, index)
let key = ['hours', 'minute', 'second', 'hours1', 'minute1', 'second1']
key.forEach(item => {
......@@ -121,25 +182,25 @@ export default {
change (value, type) {
this.setHms(value, type)
if (this.year === this.year1 && this.month === this.month1 && this.day === this.day1) {
if (type === 'hours') {
if (this.hours1 <= value && this.minute > this.minute1) {
this.minute1 = this.minute
this.$refs.minute1.scrollTop = this.minute * 25
this.$refs.minute1.scrollTop = this.getStepScrollTop(this.minute, 1)
}
if (this.hours1 < value) {
this.hours1 = value
if (this.$refs.hours1) this.$refs.hours1.scrollTop = value * 25
if (this.$refs.hours1) this.$refs.hours1.scrollTop = this.getStepScrollTop(value, 0)
}
}
if (type === 'minute' && this.hours1 === this.hours && this.minute1 < value) {
this.minute1 = value
if (this.$refs.minute1) this.$refs.minute1.scrollTop = value * 25
if (this.$refs.minute1) this.$refs.minute1.scrollTop = this.getStepScrollTop(value, 1)
}
if (type === 'second' && this.hours1 === this.hours && this.minute1 === this.minute && this.second1 < value) {
this.second1 = value
if (this.$refs.second1) this.$refs.second1.scrollTop = value * 25
if (this.$refs.second1) this.$refs.second1.scrollTop = this.getStepScrollTop(value, 2)
}
}
......@@ -173,6 +234,10 @@ export default {
if (/H|h/.test(fmt) && /m/.test(fmt) && /s/.test(fmt)) return 'hms'
if (/H|h/.test(fmt) && /m/.test(fmt)) return 'hm'
if (/H|h/.test(fmt)) return 'h'
},
hoverBlock (type, index) {
this.$emit('_hoverBlock', type, index)
}
}
}
......
......@@ -3,7 +3,6 @@
popper-class="date-poptip"
class="x-datepicker"
:placement="placement"
transition="datepicker-animation"
:append-to-body="appendToBody"
:position-fixed="positionFixed"
:viewport="viewport"
......@@ -276,7 +275,7 @@ export default {
dateChange (data, optItem) {
this.dateValueChange = data
this.optItem = optItem ? JSON.parse(JSON.stringify(optItem)) : null
this.optItem = optItem ? { ...optItem } : null
let fmtDate = this.fmtDate(data)
......@@ -285,7 +284,6 @@ export default {
if (optItem && this.multiple === 1) {
this.doClose()
}
!this.isConfirm() ? this.doClose() : this.$emit('on-text-change', fmtDate, optItem)
},
......
<template>
<div class="x-date-panel">
<div class="x-date-panel-day">
<!-- <template v-if="isTimes()">
<times v-show="isTimesShow" ref="times" @change="timeChange"></times>
</template> -->
<day :selected-date="selectedDate" @change="dayChange" :format="format" :disabled-date="disabledDate" ref="vDate"></day>
</div>
<confirm v-if="isConfirm()"
:format="format"
@confirm-btn="$emit('confirm')"
@cancel="$emit('cancel')"
type="date"
ref="confirm"
@time-change="timeChange"
></confirm>
</div>
</template>
<script>
import day from '../base/day.vue'
import confirm from '../base/confirm.vue'
import ishms from '../util/ishms.js'
import isValid from '../util/isValid.js'
export default {
name: 'panelDate',
components: { day, confirm },
data () {
return {
selectedDate: null,
// 是否展示times
isTimesShow: false
}
},
props: {
// 初始值
value: {
type: [Array],
default () {
return null
}
},
// 展示的日期格式
format: String,
// 不可选日期
disabledDate: {
type: Function,
default: null
},
// confirm
confirm: {
type: [Number, Boolean],
default: 0
},
// 选项
options: {
type: [Array, Object],
default: null
}
},
mounted () {
this.init()
},
methods: {
init (date) {
let dateValue = date || this.value
if (dateValue && dateValue.length) {
this.selectedDate = dateValue
if (isValid(dateValue[0])) this.$refs.vDate.toDate = dateValue[0]
} else {
this.selectedDate = []
}
this.$refs.vDate.init(this.selectedDate)
this.timeInit()
},
timeInit () {
if (this.isTimes()) {
this.$refs.confirm.timsInit(this.selectedDate[this.selectedDate.length - 1])
}
},
dayChange (date) {
this.selectedDate = [date]
this.timeInit()
this.$emit('change', this.selectedDate)
},
timeChange (date) {
this.selectedDate = [date]
this.$emit('change', this.selectedDate)
},
isTimes () {
return ishms(this.format)
},
isConfirm () {
if (this.confirm || this.isTimes()) return true
return false
}
}
}
<template>
<div class="x-date-panel" @click.stop>
<div class="x-date-panel-day">
<!-- <template v-if="isTimes()">
<times v-show="isTimesShow" ref="times" @change="timeChange"></times>
</template> -->
<day :selected-date="selectedDate" @change="dayChange" :format="format" :disabled-date="disabledDate" ref="vDate"></day>
</div>
<confirm v-if="isConfirm()"
:format="format"
@confirm-btn="$emit('confirm')"
@cancel="$emit('cancel')"
type="date"
ref="confirm"
@time-change="timeChange"
></confirm>
</div>
</template>
<script>
import day from '../base/day.vue'
import confirm from '../base/confirm.vue'
import ishms from '../util/ishms.js'
import isValid from '../util/isValid.js'
export default {
name: 'panelDate',
components: { day, confirm },
data () {
return {
selectedDate: null,
// 是否展示times
isTimesShow: false
}
},
props: {
// 初始值
value: {
type: [Array],
default () {
return null
}
},
// 展示的日期格式
format: String,
// 不可选日期
disabledDate: {
type: Function,
default: null
},
// confirm
confirm: {
type: [Number, Boolean],
default: 0
},
// 选项
options: {
type: [Array, Object],
default: null
}
},
mounted () {
this.init()
},
methods: {
init (date) {
let dateValue = date || this.value
if (dateValue && dateValue.length) {
this.selectedDate = dateValue
if (isValid(dateValue[0])) this.$refs.vDate.toDate = dateValue[0]
} else {
this.selectedDate = []
}
this.$refs.vDate.init(this.selectedDate)
this.timeInit()
},
timeInit () {
if (this.isTimes()) {
this.$refs.confirm.timsInit(this.selectedDate[this.selectedDate.length - 1])
}
},
dayChange (date) {
this.selectedDate = [date]
this.timeInit()
this.$emit('change', this.selectedDate)
},
timeChange (date) {
this.selectedDate = [date]
this.$emit('change', this.selectedDate)
},
isTimes () {
return ishms(this.format)
},
isConfirm () {
if (this.confirm || this.isTimes()) return true
return false
}
}
}
</script>
\ No newline at end of file
<template>
<div class="x-date-packer-panel">
<years :types="type" ref="years" style="position:inherit;" @change="change"></years>
</div>
</template>
<script>
import years from '../base/years.vue'
export default {
components: { years },
data () {
return {
}
},
props: {
type: {
type: String,
default: 'year'
},
value: Array
},
mounted () {
let t = this.type === 'year' ? 'y' : 'm'
let d = this.value && this.value.length ? this.value[0] : new Date()
this.$refs.years.init(d, t)
},
methods: {
change (date) {
this.$emit('change', [date])
}
}
}
<template>
<div class="x-date-packer-panel" @click.stop>
<years :types="type" ref="years" style="position:inherit;" @change="change"></years>
</div>
</template>
<script>
import years from '../base/years.vue'
export default {
components: { years },
data () {
return {
}
},
props: {
type: {
type: String,
default: 'year'
},
value: Array
},
mounted () {
let t = this.type === 'year' ? 'y' : 'm'
let d = this.value && this.value.length ? this.value[0] : new Date()
this.$refs.years.init(d, t)
},
methods: {
change (date) {
this.$emit('change', [date])
}
}
}
</script>
\ No newline at end of file
/**
* https://github.com/taylorhakes/fecha
* Parse or format dates
* @class fecha
*/
var fecha = {}
var token = /d{1,4}|M{1,4}|YY(?:YY)?|S{1,3}|Do|ZZ|([HhMsDm])\1?|[aA]|"[^"]*"|'[^']*'/g
var twoDigits = /\d\d?/
var threeDigits = /\d{3}/
var fourDigits = /\d{4}/
var word = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i
var literal = /\[([^]*?)\]/gm
var noop = function () {
}
function shorten (arr, sLen) {
var newArr = []
for (var i = 0, len = arr.length; i < len; i++) {
newArr.push(arr[i].substr(0, sLen))
}
return newArr
}
function monthUpdate (arrName) {
return function (d, v, i18n) {
var index = i18n[arrName].indexOf(v.charAt(0).toUpperCase() + v.substr(1).toLowerCase())
if (~index) {
d.month = index
}
}
}
function pad (val, len) {
val = String(val)
len = len || 2
while (val.length < len) {
val = '0' + val
}
return val
}
var dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
var monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
var monthNamesShort = shorten(monthNames, 3)
var dayNamesShort = shorten(dayNames, 3)
fecha.i18n = {
dayNamesShort: dayNamesShort,
dayNames: dayNames,
monthNamesShort: monthNamesShort,
monthNames: monthNames,
amPm: ['am', 'pm'],
DoFn: function DoFn (D) {
return D + ['th', 'st', 'nd', 'rd'][D % 10 > 3 ? 0 : (D - D % 10 !== 10) * D % 10]
}
}
var formatFlags = {
D: function (dateObj) {
return dateObj.getDate()
},
DD: function (dateObj) {
return pad(dateObj.getDate())
},
Do: function (dateObj, i18n) {
return i18n.DoFn(dateObj.getDate())
},
d: function (dateObj) {
return dateObj.getDay()
},
dd: function (dateObj) {
return pad(dateObj.getDay())
},
ddd: function (dateObj, i18n) {
return i18n.dayNamesShort[dateObj.getDay()]
},
dddd: function (dateObj, i18n) {
return i18n.dayNames[dateObj.getDay()]
},
M: function (dateObj) {
return dateObj.getMonth() + 1
},
MM: function (dateObj) {
return pad(dateObj.getMonth() + 1)
},
MMM: function (dateObj, i18n) {
return i18n.monthNamesShort[dateObj.getMonth()]
},
MMMM: function (dateObj, i18n) {
return i18n.monthNames[dateObj.getMonth()]
},
YY: function (dateObj) {
return String(dateObj.getFullYear()).substr(2)
},
YYYY: function (dateObj) {
return pad(dateObj.getFullYear(), 4)
},
h: function (dateObj) {
return dateObj.getHours() % 12 || 12
},
hh: function (dateObj) {
return pad(dateObj.getHours() % 12 || 12)
},
H: function (dateObj) {
return dateObj.getHours()
},
HH: function (dateObj) {
return pad(dateObj.getHours())
},
m: function (dateObj) {
return dateObj.getMinutes()
},
mm: function (dateObj) {
return pad(dateObj.getMinutes())
},
s: function (dateObj) {
return dateObj.getSeconds()
},
ss: function (dateObj) {
return pad(dateObj.getSeconds())
},
S: function (dateObj) {
return Math.round(dateObj.getMilliseconds() / 100)
},
SS: function (dateObj) {
return pad(Math.round(dateObj.getMilliseconds() / 10), 2)
},
SSS: function (dateObj) {
return pad(dateObj.getMilliseconds(), 3)
},
a: function (dateObj, i18n) {
return dateObj.getHours() < 12 ? i18n.amPm[0] : i18n.amPm[1]
},
A: function (dateObj, i18n) {
return dateObj.getHours() < 12 ? i18n.amPm[0].toUpperCase() : i18n.amPm[1].toUpperCase()
},
ZZ: function (dateObj) {
var o = dateObj.getTimezoneOffset()
return (o > 0 ? '-' : '+') + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4)
}
}
var parseFlags = {
D: [twoDigits, function (d, v) {
d.day = v
}],
Do: [new RegExp(twoDigits.source + word.source), function (d, v) {
d.day = parseInt(v, 10)
}],
M: [twoDigits, function (d, v) {
d.month = v - 1
}],
YY: [twoDigits, function (d, v) {
var da = new Date(), cent = +('' + da.getFullYear()).substr(0, 2)
d.year = '' + (v > 68 ? cent - 1 : cent) + v
}],
h: [twoDigits, function (d, v) {
d.hour = v
}],
m: [twoDigits, function (d, v) {
d.minute = v
}],
s: [twoDigits, function (d, v) {
d.second = v
}],
YYYY: [fourDigits, function (d, v) {
d.year = v
}],
S: [/\d/, function (d, v) {
d.millisecond = v * 100
}],
SS: [/\d{2}/, function (d, v) {
d.millisecond = v * 10
}],
SSS: [threeDigits, function (d, v) {
d.millisecond = v
}],
d: [twoDigits, noop],
ddd: [word, noop],
MMM: [word, monthUpdate('monthNamesShort')],
MMMM: [word, monthUpdate('monthNames')],
a: [word, function (d, v, i18n) {
var val = v.toLowerCase()
if (val === i18n.amPm[0]) {
d.isPm = false
} else if (val === i18n.amPm[1]) {
d.isPm = true
}
}],
ZZ: [/([\+\-]\d\d:?\d\d|Z)/, function (d, v) {
if (v === 'Z') v = '+00:00'
var parts = (v + '').match(/([\+\-]|\d\d)/gi), minutes
if (parts) {
minutes = +(parts[1] * 60) + parseInt(parts[2], 10)
d.timezoneOffset = parts[0] === '+' ? minutes : -minutes
}
}]
}
parseFlags.dd = parseFlags.d
parseFlags.dddd = parseFlags.ddd
parseFlags.DD = parseFlags.D
parseFlags.mm = parseFlags.m
parseFlags.hh = parseFlags.H = parseFlags.HH = parseFlags.h
parseFlags.MM = parseFlags.M
parseFlags.ss = parseFlags.s
parseFlags.A = parseFlags.a
// Some common format strings
fecha.masks = {
default: 'ddd MMM DD YYYY HH:mm:ss',
shortDate: 'M/D/YY',
mediumDate: 'MMM D, YYYY',
longDate: 'MMMM D, YYYY',
fullDate: 'dddd, MMMM D, YYYY',
shortTime: 'HH:mm',
mediumTime: 'HH:mm:ss',
longTime: 'HH:mm:ss.SSS'
}
/***
* Format a date
* @method format
* @param {Date|number} dateObj
* @param {string} mask Format of the date, i.e. 'mm-dd-yy' or 'shortDate'
*/
fecha.format = function (dateObj, mask, i18nSettings) {
var i18n = i18nSettings || fecha.i18n
if (typeof dateObj === 'number') {
dateObj = new Date(dateObj)
}
if (Object.prototype.toString.call(dateObj) !== '[object Date]' || isNaN(dateObj.getTime())) {
throw new Error('Invalid Date in fecha.format')
}
mask = fecha.masks[mask] || mask || fecha.masks['default']
var literals = []
// Make literals inactive by replacing them with ??
mask = mask.replace(literal, function ($0, $1) {
literals.push($1)
return '??'
})
// Apply formatting rules
mask = mask.replace(token, function ($0) {
return $0 in formatFlags ? formatFlags[$0](dateObj, i18n) : $0.slice(1, $0.length - 1)
})
// Inline literal values back into the formatted value
return mask.replace(/\?\?/g, function () {
return literals.shift()
})
}
/**
* Parse a date string into an object, changes - into /
* @method parse
* @param {string} dateStr Date string
* @param {string} format Date parse format
* @returns {Date|boolean}
*/
fecha.parse = function (dateStr, format, i18nSettings) {
var i18n = i18nSettings || fecha.i18n
if (typeof format !== 'string') {
throw new Error('Invalid format in fecha.parse')
}
format = fecha.masks[format] || format
// Avoid regular expression denial of service, fail early for really long strings
// https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS
if (dateStr.length > 1000) {
return false
}
var isValid = true
var dateInfo = {}
format.replace(token, function ($0) {
if (parseFlags[$0]) {
var info = parseFlags[$0]
var index = dateStr.search(info[0])
if (!~index) {
isValid = false
} else {
dateStr.replace(info[0], function (result) {
info[1](dateInfo, result, i18n)
dateStr = dateStr.substr(index + result.length)
return result
})
}
}
return parseFlags[$0] ? '' : $0.slice(1, $0.length - 1)
})
if (!isValid) {
return false
}
var today = new Date()
if (dateInfo.isPm === true && dateInfo.hour != null && +dateInfo.hour !== 12) {
dateInfo.hour = +dateInfo.hour + 12
} else if (dateInfo.isPm === false && +dateInfo.hour === 12) {
dateInfo.hour = 0
}
var date
if (dateInfo.timezoneOffset != null) {
dateInfo.minute = +(dateInfo.minute || 0) - +dateInfo.timezoneOffset
date = new Date(Date.UTC(dateInfo.year || today.getFullYear(), dateInfo.month || 0, dateInfo.day || 1,
dateInfo.hour || 0, dateInfo.minute || 0, dateInfo.second || 0, dateInfo.millisecond || 0))
} else {
date = new Date(dateInfo.year || today.getFullYear(), dateInfo.month || 0, dateInfo.day || 1,
dateInfo.hour || 0, dateInfo.minute || 0, dateInfo.second || 0, dateInfo.millisecond || 0)
}
return date
}
/**
* https://github.com/taylorhakes/fecha
* Parse or format dates
* @class fecha
*/
var fecha = {}
var token = /d{1,4}|M{1,4}|YY(?:YY)?|S{1,3}|Do|ZZ|([HhMsDm])\1?|[aA]|"[^"]*"|'[^']*'/g
var twoDigits = /\d\d?/
var threeDigits = /\d{3}/
var fourDigits = /\d{4}/
var word = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i
var literal = /\[([^]*?)\]/gm
var noop = function () {
}
function shorten (arr, sLen) {
var newArr = []
for (var i = 0, len = arr.length; i < len; i++) {
newArr.push(arr[i].substr(0, sLen))
}
return newArr
}
function monthUpdate (arrName) {
return function (d, v, i18n) {
var index = i18n[arrName].indexOf(v.charAt(0).toUpperCase() + v.substr(1).toLowerCase())
if (~index) {
d.month = index
}
}
}
function pad (val, len) {
val = String(val)
len = len || 2
while (val.length < len) {
val = '0' + val
}
return val
}
var dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
var monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
var monthNamesShort = shorten(monthNames, 3)
var dayNamesShort = shorten(dayNames, 3)
fecha.i18n = {
dayNamesShort: dayNamesShort,
dayNames: dayNames,
monthNamesShort: monthNamesShort,
monthNames: monthNames,
amPm: ['am', 'pm'],
DoFn: function DoFn (D) {
return D + ['th', 'st', 'nd', 'rd'][D % 10 > 3 ? 0 : (D - D % 10 !== 10) * D % 10]
}
}
var formatFlags = {
D: function (dateObj) {
return dateObj.getDate()
},
DD: function (dateObj) {
return pad(dateObj.getDate())
},
Do: function (dateObj, i18n) {
return i18n.DoFn(dateObj.getDate())
},
d: function (dateObj) {
return dateObj.getDay()
},
dd: function (dateObj) {
return pad(dateObj.getDay())
},
ddd: function (dateObj, i18n) {
return i18n.dayNamesShort[dateObj.getDay()]
},
dddd: function (dateObj, i18n) {
return i18n.dayNames[dateObj.getDay()]
},
M: function (dateObj) {
return dateObj.getMonth() + 1
},
MM: function (dateObj) {
return pad(dateObj.getMonth() + 1)
},
MMM: function (dateObj, i18n) {
return i18n.monthNamesShort[dateObj.getMonth()]
},
MMMM: function (dateObj, i18n) {
return i18n.monthNames[dateObj.getMonth()]
},
YY: function (dateObj) {
return String(dateObj.getFullYear()).substr(2)
},
YYYY: function (dateObj) {
return pad(dateObj.getFullYear(), 4)
},
h: function (dateObj) {
return dateObj.getHours() % 12 || 12
},
hh: function (dateObj) {
return pad(dateObj.getHours() % 12 || 12)
},
H: function (dateObj) {
return dateObj.getHours()
},
HH: function (dateObj) {
return pad(dateObj.getHours())
},
m: function (dateObj) {
return dateObj.getMinutes()
},
mm: function (dateObj) {
return pad(dateObj.getMinutes())
},
s: function (dateObj) {
return dateObj.getSeconds()
},
ss: function (dateObj) {
return pad(dateObj.getSeconds())
},
S: function (dateObj) {
return Math.round(dateObj.getMilliseconds() / 100)
},
SS: function (dateObj) {
return pad(Math.round(dateObj.getMilliseconds() / 10), 2)
},
SSS: function (dateObj) {
return pad(dateObj.getMilliseconds(), 3)
},
a: function (dateObj, i18n) {
return dateObj.getHours() < 12 ? i18n.amPm[0] : i18n.amPm[1]
},
A: function (dateObj, i18n) {
return dateObj.getHours() < 12 ? i18n.amPm[0].toUpperCase() : i18n.amPm[1].toUpperCase()
},
ZZ: function (dateObj) {
var o = dateObj.getTimezoneOffset()
return (o > 0 ? '-' : '+') + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4)
}
}
var parseFlags = {
D: [twoDigits, function (d, v) {
d.day = v
}],
Do: [new RegExp(twoDigits.source + word.source), function (d, v) {
d.day = parseInt(v, 10)
}],
M: [twoDigits, function (d, v) {
d.month = v - 1
}],
YY: [twoDigits, function (d, v) {
var da = new Date(), cent = +('' + da.getFullYear()).substr(0, 2)
d.year = '' + (v > 68 ? cent - 1 : cent) + v
}],
h: [twoDigits, function (d, v) {
d.hour = v
}],
m: [twoDigits, function (d, v) {
d.minute = v
}],
s: [twoDigits, function (d, v) {
d.second = v
}],
YYYY: [fourDigits, function (d, v) {
d.year = v
}],
S: [/\d/, function (d, v) {
d.millisecond = v * 100
}],
SS: [/\d{2}/, function (d, v) {
d.millisecond = v * 10
}],
SSS: [threeDigits, function (d, v) {
d.millisecond = v
}],
d: [twoDigits, noop],
ddd: [word, noop],
MMM: [word, monthUpdate('monthNamesShort')],
MMMM: [word, monthUpdate('monthNames')],
a: [word, function (d, v, i18n) {
var val = v.toLowerCase()
if (val === i18n.amPm[0]) {
d.isPm = false
} else if (val === i18n.amPm[1]) {
d.isPm = true
}
}],
ZZ: [/([\+\-]\d\d:?\d\d|Z)/, function (d, v) {
if (v === 'Z') v = '+00:00'
var parts = (v + '').match(/([\+\-]|\d\d)/gi), minutes
if (parts) {
minutes = +(parts[1] * 60) + parseInt(parts[2], 10)
d.timezoneOffset = parts[0] === '+' ? minutes : -minutes
}
}]
}
parseFlags.dd = parseFlags.d
parseFlags.dddd = parseFlags.ddd
parseFlags.DD = parseFlags.D
parseFlags.mm = parseFlags.m
parseFlags.hh = parseFlags.H = parseFlags.HH = parseFlags.h
parseFlags.MM = parseFlags.M
parseFlags.ss = parseFlags.s
parseFlags.A = parseFlags.a
// Some common format strings
fecha.masks = {
default: 'ddd MMM DD YYYY HH:mm:ss',
shortDate: 'M/D/YY',
mediumDate: 'MMM D, YYYY',
longDate: 'MMMM D, YYYY',
fullDate: 'dddd, MMMM D, YYYY',
shortTime: 'HH:mm',
mediumTime: 'HH:mm:ss',
longTime: 'HH:mm:ss.SSS'
}
/***
* Format a date
* @method format
* @param {Date|number} dateObj
* @param {string} mask Format of the date, i.e. 'mm-dd-yy' or 'shortDate'
*/
fecha.format = function (dateObj, mask, i18nSettings) {
var i18n = i18nSettings || fecha.i18n
if (typeof dateObj === 'number') {
dateObj = new Date(dateObj)
}
if (Object.prototype.toString.call(dateObj) !== '[object Date]' || isNaN(dateObj.getTime())) {
throw new Error('Invalid Date in fecha.format')
}
mask = fecha.masks[mask] || mask || fecha.masks['default']
var literals = []
// Make literals inactive by replacing them with ??
mask = mask.replace(literal, function ($0, $1) {
literals.push($1)
return '??'
})
// Apply formatting rules
mask = mask.replace(token, function ($0) {
return $0 in formatFlags ? formatFlags[$0](dateObj, i18n) : $0.slice(1, $0.length - 1)
})
// Inline literal values back into the formatted value
return mask.replace(/\?\?/g, function () {
return literals.shift()
})
}
/**
* Parse a date string into an object, changes - into /
* @method parse
* @param {string} dateStr Date string
* @param {string} format Date parse format
* @returns {Date|boolean}
*/
fecha.parse = function (dateStr, format, i18nSettings) {
var i18n = i18nSettings || fecha.i18n
if (typeof format !== 'string') {
throw new Error('Invalid format in fecha.parse')
}
format = fecha.masks[format] || format
// Avoid regular expression denial of service, fail early for really long strings
// https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS
if (dateStr.length > 1000) {
return false
}
var isValid = true
var dateInfo = {}
format.replace(token, function ($0) {
if (parseFlags[$0]) {
var info = parseFlags[$0]
var index = dateStr.search(info[0])
if (!~index) {
isValid = false
} else {
dateStr.replace(info[0], function (result) {
info[1](dateInfo, result, i18n)
dateStr = dateStr.substr(index + result.length)
return result
})
}
}
return parseFlags[$0] ? '' : $0.slice(1, $0.length - 1)
})
if (!isValid) {
return false
}
var today = new Date()
if (dateInfo.isPm === true && dateInfo.hour != null && +dateInfo.hour !== 12) {
dateInfo.hour = +dateInfo.hour + 12
} else if (dateInfo.isPm === false && +dateInfo.hour === 12) {
dateInfo.hour = 0
}
var date
if (dateInfo.timezoneOffset != null) {
dateInfo.minute = +(dateInfo.minute || 0) - +dateInfo.timezoneOffset
date = new Date(Date.UTC(dateInfo.year || today.getFullYear(), dateInfo.month || 0, dateInfo.day || 1,
dateInfo.hour || 0, dateInfo.minute || 0, dateInfo.second || 0, dateInfo.millisecond || 0))
} else {
date = new Date(dateInfo.year || today.getFullYear(), dateInfo.month || 0, dateInfo.day || 1,
dateInfo.hour || 0, dateInfo.minute || 0, dateInfo.second || 0, dateInfo.millisecond || 0)
}
return date
}
export default fecha
/*
*
* 判断数据类型
*
*/
function isType (value) {
let type = Object.prototype.toString.call(value)
return type.match(/\[object (.*?)\]/)[1].toLowerCase()
}
/*
*
* 判断数据类型
*
*/
function isType (value) {
let type = Object.prototype.toString.call(value)
return type.match(/\[object (.*?)\]/)[1].toLowerCase()
}
export default isType
/*
*
* 验证日期是否合法
*
*/
import moment from 'dayjs'
export default (date) => {
// return Date.parse(date) > 0
return moment(date).isValid()
}
/*
*
* 验证日期是否合法
*
*/
import moment from 'dayjs'
export default (date) => {
// return Date.parse(date) > 0
return moment(date).isValid()
}
export default (fmt) => {
if (/[HhmsS]/.test(fmt)) {
return 'second'
}
if (/[Hhm]/.test(fmt)) {
return 'minute'
}
if (/[Hh]/.test(fmt)) {
return 'hour'
}
return false
export default (fmt) => {
if (/[HhmsS]/.test(fmt)) {
return 'second'
}
if (/[Hhm]/.test(fmt)) {
return 'minute'
}
if (/[Hh]/.test(fmt)) {
return 'hour'
}
return false
}
export default () => {
let date = new Date()
return {
year: date.getFullYear(),
month: date.getMonth() + 1,
today: date.getDate()
}
export default () => {
let date = new Date()
return {
year: date.getFullYear(),
month: date.getMonth() + 1,
today: date.getDate()
}
}
......@@ -12,4 +12,5 @@ closable | 是否显示关闭 | Boolean | - | false
escClose | 是否按 esc 键关闭 | Boolean | - | true
transitionName | 动画类名 | String | - | -
showMask | 是否显示遮罩 | Boolean | - | true
maskClosable | 是否关闭遮罩 | Boolean | - | true
\ No newline at end of file
maskClosable | 是否关闭遮罩 | Boolean | - | true
i18n | 国际化对象 | VueI18n | - | -
\ No newline at end of file
......@@ -67,7 +67,6 @@
<div ref="append" class="append-area" v-if="$slots.append">
<slot name="append"></slot>
</div>
<div class="no-border-shadow" v-if="noBorder" v-show="focused"></div>
</template>
<textarea
v-else
......@@ -300,6 +299,7 @@ export default {
clear () {
this.setCurrentValue('')
this.focus()
this.$emit('input', '')
},
/**
* 文本域自适应
......
<template>
<span>
<transition name="x-ani-fade" @after-leave="destroyPopper">
<transition :name="transition" @after-leave="destroyPopper">
<div
:class="wrapperClass"
ref="popper"
......@@ -45,7 +45,7 @@ export default {
prefixCls: prefixCls,
delayTime: 0,
timer: null,
arrowClass: `${LIB_NAME}-popper-arrow`
arrowClass: `${LIB_NAME}-popper-arrow large`
}
},
props: {
......@@ -97,6 +97,10 @@ export default {
type: Number,
default: 5
},
transition: {
type: String,
default: 'x-ani-fade'
},
popperClass: String
},
computed: {
......
......@@ -23,12 +23,8 @@ bar-offset-bottom | 垂直滚动条距离视图底部的偏移 | Number | — |
事件名称 | 说明 | 回调参数
--- | --- | ---
on-x-start | 水平滚动到达最左侧时触发 | —
on-scroll-x | 水平滚动改变时触发 | 当前的 left 值
on-x-end | 水平滚动到达最右侧时触发 | —
on-y-start | 垂直滚动到达顶部时触发 | —
on-scroll-y | 垂直滚动改变时触发 | 当前的 top 值
on-y-end | 垂直滚动到达底部时触发 | —
on-scroll-x | 水平滚动改变时触发 | 当前的 left 值,是否达到最左侧,是否达到最右侧
on-scroll-y | 垂直滚动改变时触发 | 当前的 top 值,是否达到最顶部,是否达到最底部
on-start-drag-bar | 开始拖动滚动条时触发 | 是否垂直滚动条
on-end-drag-bar | 结束拖动滚动条时触发 | 是否垂直滚动条
......
......@@ -60,7 +60,7 @@ export default {
},
width () {
return this.viewWidth * this.wrapperWidth / this.contentWidth
return Math.max(40, this.viewWidth * this.wrapperWidth / this.contentWidth)
},
maxLeft () {
......@@ -69,9 +69,13 @@ export default {
},
methods: {
setLeft (left) {
_getValidLeft (left) {
return Math.min(this.maxLeft, Math.max(left, 0))
},
setLeft (percentage) {
if (this.contentWidth) {
this.left = -left * this.wrapperWidth / this.contentWidth
this.left = this._getValidLeft(percentage * this.maxLeft)
}
},
......@@ -97,9 +101,8 @@ export default {
const delta = event.clientX - this.startClientX
let left = this.startLeft + delta
left = Math.min(this.maxLeft, Math.max(left, 0))
this.left = left
this.$emit('on-horizontal-drag', left / this.wrapperWidth)
this.left = this._getValidLeft(left)
this.$emit('on-horizontal-drag', left / this.maxLeft)
}
},
......@@ -122,7 +125,7 @@ export default {
let left = this.left + delta
left = Math.min(this.maxLeft, Math.max(left, 0))
this.left = left
this.$emit('on-horizontal-drag', left / this.wrapperWidth)
this.$emit('on-horizontal-drag', left / this.maxLeft)
}
}
},
......
......@@ -4,6 +4,7 @@
ref="content"
class="scroll-area-wrapper"
:class="{'scroll-transition':!dragging}"
:style="innerStyles"
@touchstart="startDrag"
@touchmove="onDrag"
@touchend="endDrag">
......@@ -18,7 +19,7 @@
:offset-left="barOffsetLeft"
:offset-right="barOffsetRight"
:dragging="dragging"
:disabled="disabled"
:disabled="disableModel.disableX"
:active="activeBar"
@on-start-drag="handleStartDragBar"
@on-horizontal-drag="handleHorizontalDrag"
......@@ -35,7 +36,7 @@
:offset-top="barOffsetTop"
:offset-bottom="barOffsetBottom"
:dragging="dragging"
:disabled="disabled"
:disabled="disableModel.disableY"
:active="activeBar"
@on-start-drag="handleStartDragBar"
@on-vertical-drag="handleVerticalDrag"
......@@ -51,6 +52,8 @@ import { LIB_NAME, mousewheel, limitedLoop, formatSize } from '../../../../src/u
import xVerticalScrollbar from './VerticalScrollbar'
import xHorizontalScrollbar from './HorizontalScrollbar'
const maxScrollDistance = 500
export default {
name: 'xScroller',
......@@ -67,6 +70,10 @@ export default {
maxHeight: [String, Number],
innerWidth: [String, Number],
innerHeight: [String, Number],
scrollbarClass: String,
// 是否反转 Y 轴滚轮,当该值为 true 时,滚动 Y 轴将控制水平方向的滚动
......@@ -87,7 +94,7 @@ export default {
},
disabled: {
type: Boolean,
type: [Boolean, String],
default: false
},
......@@ -130,12 +137,28 @@ export default {
startTop: null,
startLeft: null,
moving: false,
hoveringBar: false,
resetMovingTimer: null
hoveringBar: false
}
},
computed: {
disableModel () {
if (typeof this.disabled === 'boolean' && this.disabled) {
return {
disableX: true,
disableY: true
}
} else if (typeof this.disabled === 'string' && ['x', 'y'].includes(this.disabled)) {
return this.disabled === 'x'
? { disableX: true, disableY: false }
: { disableX: false, disableY: true }
}
return {
disableX: false,
disableY: false
}
},
wrapperStyles () {
return {
width: formatSize(this.width),
......@@ -145,12 +168,19 @@ export default {
}
},
innerStyles () {
return {
width: formatSize(this.innerWidth),
height: formatSize(this.innerHeight)
}
},
minLeft () {
return this.wrapperWidth - this.contentWidth
return Math.min(0, this.wrapperWidth - this.contentWidth)
},
minTop () {
return this.wrapperHeight - this.contentHeight
return Math.min(0, this.wrapperHeight - this.contentHeight)
},
dragging () {
......@@ -183,6 +213,22 @@ export default {
maxHeight () {
this.checkScrollable()
},
innerWidth () {
this.checkScrollable()
},
innerHeight () {
this.checkScrollable()
},
scrollX (v) {
if (!v) this.setContentLeft(0, false)
},
scrollY (v) {
if (!v) this.setContentTop(0, false)
}
},
......@@ -201,10 +247,12 @@ export default {
}
this.scrollX = this.contentWidth - this.wrapperWidth > 1
this.scrollY = this.contentHeight - this.wrapperHeight > 1
this.checkBoundary()
},
handleMouseWheel (event, data) {
if (this.disabled) {
const { disableX, disableY } = this.disableModel
if (disableX && disableY) {
event.preventDefault()
return
}
......@@ -213,26 +261,34 @@ export default {
const content = this.$refs.content
let deltaLeft = this.reverseScrollY || shift ? -data.pixelY : -data.pixelX
let deltaTop = shift ? -data.pixelX : -data.pixelY
if (this.scrollX && deltaLeft) {
// mac
if (~navigator.userAgent.indexOf('Mac OS X')) {
deltaLeft = Math.min(maxScrollDistance, Math.max(-maxScrollDistance, deltaLeft))
deltaTop = Math.min(maxScrollDistance, Math.max(-maxScrollDistance, deltaTop))
}
const moveVertical = Math.abs(deltaLeft) < Math.abs(deltaTop)
if (!disableX && this.scrollX && deltaLeft && !moveVertical) {
let lastLeft = this.currentLeft
let left = this.getValidNumber(lastLeft + deltaLeft, this.minLeft, 0)
if (left !== lastLeft) {
this.currentLeft = left
content.style.left = left + 'px'
if (this.$refs.horizontal) {
this.$refs.horizontal.setLeft(left)
this.$refs.horizontal.setLeft(left / this.minLeft)
}
this.emitEvent(left, false)
event.preventDefault()
}
} else if (this.scrollY && deltaTop) {
} else if (!disableY && this.scrollY && deltaTop && moveVertical) {
let lastTop = this.currentTop
let top = this.getValidNumber(lastTop + deltaTop, this.minTop, 0)
if (top !== lastTop) {
this.currentTop = top
content.style.top = top + 'px'
if (this.$refs.vertical) {
this.$refs.vertical.setTop(top)
this.$refs.vertical.setTop(top / this.minTop)
}
this.emitEvent(top, true)
event.preventDefault()
......@@ -258,7 +314,7 @@ export default {
handleVerticalDrag (barTopPercentage) {
const content = this.$refs.content
let top = this.getValidNumber(-barTopPercentage * this.contentHeight, this.minTop, 0)
let top = this.getValidNumber(barTopPercentage * this.minTop, this.minTop, 0)
if (top !== this.currentTop) {
this.currentTop = top
content.style.top = top + 'px'
......@@ -270,7 +326,7 @@ export default {
handleHorizontalDrag (barLeftPercentage) {
const content = this.$refs.content
let left = this.getValidNumber(-barLeftPercentage * this.contentWidth, this.minLeft, 0)
let left = this.getValidNumber(barLeftPercentage * this.minLeft, this.minLeft, 0)
if (left !== this.currentLeft) {
this.currentLeft = left
content.style.left = left + 'px'
......@@ -281,7 +337,10 @@ export default {
startDrag (event) {
event.preventDefault()
if (this.disabled) return
const { disableX, disableY } = this.disableModel
this.$emit('start-drag')
if (disableX && disableY) return
event = event.changedTouches[0]
this.startTop = this.currentTop
......@@ -293,28 +352,31 @@ export default {
onDrag (e) {
if (!this.bodyDragging) return
this.$emit('dragging')
const { disableX, disableY } = this.disableModel
const content = this.$refs.content
const event = e.changedTouches[0]
if (this.scrollX) {
if (!disableX && this.scrollX) {
let left = this.getValidNumber(this.startLeft + event.clientX - this.startClientX, this.minLeft, 0)
if (left !== this.currentLeft) {
this.currentLeft = left
content.style.left = left + 'px'
if (this.$refs.horizontal) {
this.$refs.horizontal.setLeft(left)
this.$refs.horizontal.setLeft(left / this.minLeft)
}
this.emitEvent(left, false)
e.preventDefault()
}
}
if (this.scrollY) {
if (!disableY && this.scrollY) {
let top = this.getValidNumber(this.startTop + event.clientY - this.startClientY, this.minTop, 0)
if (top !== this.currentTop) {
this.currentTop = top
content.style.top = top + 'px'
if (this.$refs.vertical) {
this.$refs.vertical.setTop(top)
this.$refs.vertical.setTop(top / this.minTop)
}
this.emitEvent(top, true)
e.preventDefault()
......@@ -327,23 +389,14 @@ export default {
if (this.bodyDragging) {
this.bodyDragging = false
}
this.$emit('end-drag')
},
emitEvent (amount, vertical) {
if (vertical) {
if (amount === 0) {
this.$nextTick(() => this.$emit('on-y-start'))
} else if (amount === this.minTop) {
this.$nextTick(() => this.$emit('on-y-end'))
}
this.$emit('on-scroll-y', amount)
this.$emit('on-scroll-y', amount, amount === 0, amount === this.minTop)
} else {
if (amount === 0) {
this.$nextTick(() => this.$emit('on-x-start'))
} else if (amount === this.minLeft) {
this.$nextTick(() => this.$emit('on-x-end'))
}
this.$emit('on-scroll-x', amount)
this.$emit('on-scroll-x', amount, amount === 0, amount === this.minLeft)
}
},
......@@ -352,6 +405,21 @@ export default {
if (!this.contentWidth || !this.contentHeight) {
limitedLoop.nextTick(this.forceCheck, this)
}
// reset
this.forceCheck.startTime = null
},
checkBoundary () {
if (this.currentLeft > 0) {
this.setContentLeft(0, false)
} else if (this.currentLeft < this.minLeft) {
this.setContentLeft(this.minLeft, false)
}
if (this.currentTop > 0) {
this.setContentTop(0, false)
} else if (this.currentTop < this.minTop) {
this.setContentTop(this.minTop, false)
}
},
setContentLeft (left, transition = true) {
......@@ -360,13 +428,13 @@ export default {
this.currentLeft = left
if (!transition) {
this.bodyDragging = true
setTimeout(() => {
this.timer1 = setTimeout(() => {
this.bodyDragging = false
}, 500)
}
this.$refs.content.style.left = left + 'px'
if (this.$refs.horizontal) {
this.$refs.horizontal.setLeft(left)
this.$refs.horizontal.setLeft(left / this.minLeft)
}
this.handleAction()
},
......@@ -377,13 +445,13 @@ export default {
this.currentTop = top
if (!transition) {
this.bodyDragging = true
setTimeout(() => {
this.timer2 = setTimeout(() => {
this.bodyDragging = false
}, 500)
}
this.$refs.content.style.top = top + 'px'
if (this.$refs.vertical) {
this.$refs.vertical.setTop(top)
this.$refs.vertical.setTop(top / this.minTop)
}
this.handleAction()
},
......@@ -393,22 +461,26 @@ export default {
const content = this.$refs.content
if (!transition) {
this.bodyDragging = true
setTimeout(() => {
this.timer3 = setTimeout(() => {
this.bodyDragging = false
}, 500)
}
if (vertical) {
this.currentTop = start ? 0 : this.minTop
content.style.top = start ? 0 : this.minTop + 'px'
if (this.$refs.vertical) {
this.$refs.vertical.setTop(this.currentTop)
}
this.$nextTick(() => {
if (this.$refs.vertical) {
this.$refs.vertical.setTop(this.currentTop / this.minTop)
}
})
} else {
this.currentLeft = start ? 0 : this.minLeft
content.style.left = start ? 0 : this.minLeft + 'px'
if (this.$refs.horizontal) {
this.$refs.horizontal.setLeft(this.currentLeft)
}
this.$nextTick(() => {
if (this.$refs.horizontal) {
this.$refs.horizontal.setLeft(this.currentLeft / this.minLeft)
}
})
}
this.handleAction()
},
......@@ -454,6 +526,13 @@ export default {
this.forceCheck()
})
}
},
beforeDestroy () {
clearTimeout(this.timer1)
clearTimeout(this.timer2)
clearTimeout(this.timer3)
clearTimeout(this.resetMovingTimer)
}
}
</script>
......@@ -60,18 +60,22 @@ export default {
},
height () {
return this.viewHeight * this.wrapperHeight / this.contentHeight
return Math.max(40, this.viewHeight * this.wrapperHeight / this.contentHeight)
},
maxTop () {
return this.viewHeight - this.height
return this.wrapperHeight - this.height
}
},
methods: {
setTop (top) {
_getValidTop (top) {
return Math.min(this.maxTop, Math.max(top, 0))
},
setTop (percentage) {
if (this.contentHeight) {
this.top = -top * this.wrapperHeight / this.contentHeight
this.top = this._getValidTop(percentage * this.maxTop)
}
},
......@@ -97,9 +101,8 @@ export default {
const delta = event.clientY - this.startClientY
let top = this.startTop + delta
top = Math.min(this.maxTop, Math.max(top, 0))
this.top = top
this.$emit('on-vertical-drag', top / this.wrapperHeight)
this.top = this._getValidTop(top)
this.$emit('on-vertical-drag', top / this.maxTop)
}
},
......@@ -122,7 +125,7 @@ export default {
let top = this.top + delta
top = Math.min(this.maxTop, Math.max(top, 0))
this.top = top
this.$emit('on-vertical-drag', top / this.wrapperHeight)
this.$emit('on-vertical-drag', top / this.maxTop)
}
}
},
......
......@@ -21,13 +21,17 @@ multiple | 是否开启多选 | Boolean | — | false
filterable | 是否开启搜索功能 | Boolean | — | false
filter-props | 当 option 的绑定值为对象时,搜索查找的对应属性列表 | Array | — | —
no-data-text | 选项为空时显示的文字 | String | — | 暂无数据
highlight-matched-text | 搜索时是否高亮选项中匹配的文字,(仅当未设置 filter-props 时可用) | Boolean | — | false
no-data-icon | 选项为空时显示的图标类名 | String | — | ans-icon-no-data
highlight-matched-text | 搜索时是否高亮选项中匹配的文字 | Boolean | — | false
ignore-case | 搜索时是否忽略大小写,可以和 filter-props 以及 highlight-matched-text 配合使用 | Boolean | — | false
no-match-text | 搜索没有任何匹配项时显示的文字 | String | — | 搜索无结果
no-match-icon | 搜索没有任何匹配项时显示的图标类名 | String | — | ans-icon-search-no-data
has-arrow | 下拉框是否显示指示箭头 | Boolean | — | false
append-to-body | 下拉框是否插入 body | Boolean | — | false
position-fixed | 下拉框是否 fixed 定位 | Boolean | — | false
viewport | 下拉框是否基于 viewport 定位 | Boolean | — | false
popper-options | Popper.js 的可选项 | Object | — | —
dropdown-class | 下拉框样式 | String | — | —
scrollbar-class | 滚动条样式 | String | — | —
drop-animation | 下拉框动画 | String | — | —
......@@ -37,6 +41,7 @@ drop-animation | 下拉框动画 | String | — | —
--- | --- | ---
on-change | 选中值发生变化时触发 | 目前的选中值,{ value: value, label: label }
on-visible-change | 下拉框状态改变时触发 | 出现则为 true,隐藏则为 false
on-keyword-change | 搜索关键字改变时触发 | keyword
### Select methods
......@@ -47,6 +52,7 @@ blur | 使 input 失去焦点并且隐藏下拉框 | —
search | 搜索 | keyword
updateScrollbar | 更新下拉框内的滚动条 | —
resetScrollbar | 将滚动条移回到顶部 | —
setDropdownReference | 手动指定下拉框的触发元素 | dom 元素
### Select slots
......@@ -56,7 +62,6 @@ trigger | Select 组件触发元素的插槽 | selectedModel
multiple | 开启多选时,控制 input 内如何显示的插槽 | selectedList
header | 下拉框头部插槽,必须使用作用域插槽 | —
footer | 下拉框底部插槽,必须使用作用域插槽 | —
empty | 数据为空时可使用该插槽 | —
### OptionGroup props
......
......@@ -3,7 +3,7 @@
<section class="demo-section">
<h4>动态 Option</h4>
<div>
<x-select>
<x-select height="500">
<div style="padding:10px 20px;" slot="header" slot-scope="header">
<x-input v-model="keyword"/>
</div>
......
import Vue from 'vue'
import App from './dynamic.vue'
import App from './navigation.vue'
new Vue({
el: '#app',
......
<template>
<div class="select-demo-wrapper">
<section class="demo-section">
<h4>手动触发</h4>
<div>
<x-select ref="select" v-model="value" valueKey="id" multiple :popperOptions="{placement:'bottom-start'}">
<x-option
v-for="city in cities"
:key="city.value"
:value="city"
:label="city.label"
>
</x-option>
<div slot="trigger">
<x-button @click="handle">第一个</x-button>
<x-button @click="handle">第二个</x-button>
<x-button @click="handle">第三个</x-button>
</div>
</x-select>
</div>
</section>
</div>
</template>
<script>
import { xButton } from '../../vue-button/src'
import { xSelect, xOption, xOptionGroup } from '../src'
export default {
name: 'app',
components: { xSelect, xOption, xOptionGroup, xButton },
data () {
return {
value: 1,
cities: [{
id: 1,
value: 'Beijing',
label: '北京'
}, {
id: 2,
value: 'Shanghai',
label: '上海'
}, {
id: 3,
value: 'Nanjing',
label: '南京'
}, {
id: 4,
value: 'Chengdu',
label: '成都'
}, {
id: 5,
value: 'Shenzhen',
label: '深圳'
}, {
id: 6,
value: 'Guangzhou',
label: '广州'
}]
}
},
methods: {
handle (e) {
this.value = 1
this.$refs.select.setDropdownReference(e.currentTarget)
this.$nextTick(() => this.$refs.select.focus())
}
}
}
</script>
<style lang="scss">
.demo-wrapper {
.cate {
height: 40px;
margin-left: 20px;
font-size: 16px;
font-weight: bold;
line-height: 40px;
}
.row {
display: flex;
margin: 20px 0;
padding: 0 50px;
& > div {
margin-right: 50px;
}
}
.custom {
display: flex;
justify-content: space-between;
padding: 5px 10px;
&:hover {
background: #8492a6;
.left,
.right {
color: #fff;
}
}
.left {
font-size: 12px;
}
.right {
color: #8492a6;
font-size: 12px;
transform: scale(0.8);
}
}
.selected .custom {
color: #598cd4;
background: #dfd8e4;
}
.custom-group {
height: 40px;
line-height: 40px;
font-size: 14px;
color: #303030;
font-weight: bolder;
background: #b7d1f0;
i {
margin: 0 10px;
}
}
}
</style>
......@@ -3,7 +3,14 @@
<section class="demo-section">
<h4>键盘导航</h4>
<div>
<x-select multiple filterable height="150" highlight-matched-text>
<x-select
multiple
filterable
height="150"
highlight-matched-text
ignore-case
:filter-props="['label', 'value']"
>
<x-option
v-for="city in cities"
:key="city.value"
......@@ -28,27 +35,27 @@ export default {
cities: [{
id: 1,
value: 'Beijing',
label: '北京'
label: '北京-Beijing'
}, {
id: 2,
value: 'Shanghai',
label: '上海'
label: '上海-Shanghai'
}, {
id: 3,
value: 'Nanjing',
label: '南京'
label: '南京-Nanjing'
}, {
id: 4,
value: 'Chengdu',
label: '成都'
label: '成都-Chengdu'
}, {
id: 5,
value: 'Shenzhen',
label: '深圳'
label: '深圳-Shenzhen'
}, {
id: 6,
value: 'Guangzhou',
label: '广州'
label: '广州-Guangzhou'
}]
}
}
......
<template>
<li
v-show="visible"
:class="[wrapperClass, {selected, disabled, multiple}]"
:class="[wrapperClass, {selected, disabled, multiple, 'invisible-option': !visible}]"
@mouseenter="hoverItem"
@touchend="handleTouch"
@click="handleClick">
<slot :option="this">
<span
class="default-option-class"
:class="{focused, 'invisible-option': !visible}"
:class="{focused}"
v-html="displayText"
></span>
<i v-if="multiple && selected" class="selected-mark"></i>
......@@ -49,17 +50,31 @@ export default {
return this.select && this.select.multiple
},
displayText () {
return (this.visible && this.select && this.select.filterable && this.select.highlightMatchedText && this.select.keyword)
? this.label.replace(this.select.keyword, `<span class="highlight">${this.select.keyword}</span>`)
: this.label
if (this.visible && this.select && this.select.filterable && this.select.highlightMatchedText && this.select.keyword) {
if (this.select.ignoreCase) {
const ll = this.label.toLowerCase()
const lk = this.select.keyword.toLowerCase()
const index = ll.indexOf(lk)
if (~index) {
const length = lk.length
return this.label.substr(0, index) + `<span class="highlight">${this.label.substr(index, length)}</span>` + this.label.substr(index + length)
}
} else {
return this.label.replace(this.select.keyword, `<span class="highlight">${this.select.keyword}</span>`)
}
}
return this.label
}
},
methods: {
hoverItem () {
if (!this.disabled) {
this.select.focusIndex = this.select.options.indexOf(this)
this.select.focusIndex = this.select.visibleOptions.indexOf(this)
}
},
handleTouch () {
!this.select.dragging && this.handleClick()
},
handleClick () {
if (this.clickHandler && typeof this.clickHandler === 'function') {
this.clickHandler(this.value, this.label)
......@@ -85,14 +100,21 @@ export default {
const value = this.value
let matchKeyword = false
for (const prop of props) {
if (value && value[prop] && value[prop].toString().includes(keyword)) {
if (value && value[prop] && this.isPropIncludeKeyword(value[prop].toString(), keyword)) {
matchKeyword = true
break
}
}
return matchKeyword
} else {
return this.label.toString().includes(keyword)
return this.isPropIncludeKeyword(this.label.toString(), keyword)
}
},
isPropIncludeKeyword (prop, keyword) {
if (this.select.ignoreCase) {
return prop.toLowerCase().includes(keyword.toLowerCase())
} else {
return prop.includes(keyword)
}
}
},
......
<template>
<div :class="wrapperClass" v-click-outside="blur">
<div :class="wrapperClass" v-click-outside="clickWrapperOutside">
<div
class="tag-container"
:class="{'tag-container-disabled':disabled}"
ref="multiple"
v-if="multiple"
v-if="multiple && !customTrigger"
:style="tagContainerStyles"
@click="toggleDropdown"
@mouseenter="inputHovering = true"
......@@ -52,8 +52,10 @@
</slot>
</div>
<x-select-dropdown
v-click-outside="clickDropdownOutside"
ref="dropdown"
:scrollbar-class="scrollbarClass"
:custom-class="dropdownClass"
:custom-header="panelHeader"
:custom-footer="panelFooter"
:width="width"
......@@ -66,7 +68,7 @@
:viewport="viewport"
:popper-options="mergedOptions"
@on-update-width="handleUpdateWidth"
@click.native="_refocus"
@click.native="clickDropdown"
@keydown.native.esc.stop.prevent="_refocusTrigger"
@keydown.native.down.stop.prevent="navigateOptions('next')"
@keydown.native.up.stop.prevent="navigateOptions('prev')"
......@@ -84,15 +86,12 @@
<ul class="dropdown-container" :style="panelStyles">
<slot></slot>
</ul>
<div v-if="hasEmptySlot" class="empty-hint-erea">
<slot name="empty"></slot>
</div>
<div v-if="!hasEmptySlot && options.length === 0" class="empty-text">
<i class="ans-icon-no-data"></i>
<div v-if="options.length === 0" class="empty-text">
<i :class="noDataIcon"></i>
<span>{{noDataText}}</span>
</div>
<div v-if="!hasEmptySlot && showNoMatchText" class="empty-text">
<i class="ans-icon-search-no-data"></i>
<div v-else-if="visibleOptions.length === 0" class="empty-text">
<i :class="noMatchIcon"></i>
<span>{{noMatchText}}</span>
</div>
</x-select-dropdown>
......@@ -100,7 +99,8 @@
</template>
<script>
import { LIB_NAME, clickOutside, emitter, getValueByPath, hasClass } from '../../../../src/util'
import { debounce } from 'throttle-debounce'
import { LIB_NAME, clickOutside, emitter, hasClass } from '../../../../src/util'
import { xInput } from '../../../vue-input/src'
import xSelectDropdown from './SelectDropdown.vue'
import { t } from '../../../../src/locale'
......@@ -133,6 +133,8 @@ export default {
visible: false,
// 当前 select 组件中的所有 option 子组件
options: [],
// 已按照 dom 排序的可见 option 子组件
visibleOptions: [],
// 多选时当前已选项对应的 option 子组件
selectedOptions: [],
// 单选时上一次点击选项对应的 option 子组件
......@@ -147,8 +149,9 @@ export default {
panelHeader: null,
panelFooter: null,
panelStyles: {},
hasEmptySlot: false,
focusIndex: -1
focusIndex: -1,
dragging: false,
customTrigger: false
}
},
......@@ -215,12 +218,23 @@ export default {
}
},
noDataIcon: {
type: String,
default: 'ans-icon-no-data'
},
// 搜索时是否高亮选项中匹配的文字,(仅当未设置 filter-props 时可用)
highlightMatchedText: {
type: Boolean,
default: false
},
// 搜索时是否忽略大小写
ignoreCase: {
type: Boolean,
default: false
},
// 搜索没有任何匹配项时显示的文字
noMatchText: {
type: String,
......@@ -229,6 +243,11 @@ export default {
}
},
noMatchIcon: {
type: String,
default: 'ans-icon-search-no-data'
},
hasArrow: {
type: Boolean,
default: false
......@@ -252,6 +271,8 @@ export default {
}
},
dropdownClass: String,
scrollbarClass: String,
dropAnimation: String
......@@ -296,7 +317,11 @@ export default {
selectedModel () {
return this.multiple
? this.selectedList
: this.lastOption ? { label: this.lastOption.label, value: this.lastOption.value } : null
: this.lastOption ? {
label: this.lastOption.label,
value: this.lastOption.value,
notFound: this.lastOption.notFound
} : null
},
// 是否显示清空图标
......@@ -308,10 +333,6 @@ export default {
return this.clearable && !this.disabled && this.inputHovering && hasValue
},
showNoMatchText () {
return this.options.length !== 0 && this.options.every(o => !o.visible)
},
navigatable () {
return this.options.some(o => !o.disabled && o.visible)
}
......@@ -334,7 +355,7 @@ export default {
},
focusIndex (val) {
if (val > -1 && val < this.options.length) {
if (val > -1 && val < this.visibleOptions.length) {
const target = this._getOptionByElIndex(val)
this.options.forEach(o => {
o.focused = target === o
......@@ -348,6 +369,14 @@ export default {
},
methods: {
/**
* 设置下拉框的 reference 属性
*/
setDropdownReference (reference) {
this.hideDropdown()
this.$refs.dropdown.setReference(reference)
},
/**
* 更新下拉框内的滚动条
*/
......@@ -371,8 +400,10 @@ export default {
this.broadcast('xOption', 'keywordChange', keyword)
this.broadcast('xOptionGroup', 'keywordChange', keyword)
this.$nextTick(() => {
this.updateScrollbar()
this._filterVisible()
this.$nextTick(() => this.updateScrollbar())
})
this.$emit('on-keyword-change', keyword)
},
/**
......@@ -381,6 +412,8 @@ export default {
focus () {
if (!this.visible) {
this.toggleDropdown()
} else {
this.$refs.dropdown.updateLayout()
}
},
......@@ -508,10 +541,10 @@ export default {
resetHoverIndex () {
if (!this.multiple) {
this.focusIndex = this.options.indexOf(this.lastOption)
this.focusIndex = this.visibleOptions.indexOf(this.lastOption)
} else {
if (this.selectedOptions.length > 0) {
this.focusIndex = Math.min.apply(null, this.selectedOptions.map(o => this.options.indexOf(o)))
this.focusIndex = Math.min.apply(null, this.selectedOptions.map(o => this.visibleOptions.indexOf(o)))
} else {
this.focusIndex = -1
}
......@@ -528,13 +561,13 @@ export default {
}
if (direction === 'next') {
this.focusIndex++
if (this.focusIndex >= this.options.length) {
if (this.focusIndex >= this.visibleOptions.length) {
this.focusIndex = 0
}
} else if (direction === 'prev') {
this.focusIndex--
if (this.focusIndex < 0) {
this.focusIndex = this.options.length - 1
this.focusIndex = this.visibleOptions.length - 1
}
}
const option = this._getOptionByElIndex(this.focusIndex)
......@@ -544,12 +577,35 @@ export default {
this.$nextTick(() => this.$refs.dropdown.scrollToTarget(option))
},
_filterVisible () {
if (this.options.length) {
const parent = this.options[0].$el.parentNode
let els
if (hasClass(parent, 'dropdown-container')) {
els = Array.from(parent.children)
} else {
els = []
const groups = Array.from(parent.parentNode.parentNode.parentNode.children)
for (const group of groups) {
els = els.concat(Array.from(group.children[1].children[0].children))
}
}
const visibleEls = els.filter(e => !hasClass(e, 'invisible-option'))
const result = []
visibleEls.forEach(e => {
const c = this.options.find(o => o.$el === e)
c && result.push(c)
})
this.visibleOptions = result
} else {
this.visibleOptions = []
}
},
_getOptionByElIndex (index) {
if (this.options.length) {
const els = Array.from(this.options[0].$el.parentNode.children)
.filter(e => !hasClass('invisible-option'))
if (els.length < index + 1) return null
return this.options.find(o => o.$el === els[index])
if (this.visibleOptions.length < index + 1) return null
return this.visibleOptions[index]
} else {
return null
}
......@@ -609,6 +665,7 @@ export default {
} else {
this.lastOption = this.getOption(value)
}
this.resetHoverIndex()
}
},
......@@ -618,14 +675,14 @@ export default {
getOption (value) {
const checkByProp = this.valueKey || typeof value === 'object'
for (const option of this.options) {
if ((checkByProp && getValueByPath(option.value, this.valueKey) === value) ||
if ((checkByProp && option.value[this.valueKey] === value[this.valueKey]) ||
option.value === value) {
option.selected = true
return option
}
}
const label = typeof value === 'object' ? '' : value
return { value, label }
return { value, label, notFound: true }
},
/**
......@@ -635,7 +692,7 @@ export default {
if (index > -1) {
this.options.splice(index, 1)
}
this.focusIndex = -1
this.debouncedUpdate()
},
/**
......@@ -651,22 +708,52 @@ export default {
registerOption (option) {
this.options.push(option)
this.focusIndex = -1
this.setSelected(this.value)
this.$refs.dropdown && this.$refs.dropdown.checkScrollable()
this.debouncedUpdate()
},
handleUpdateWidth (width) {
this.panelStyles = { width }
},
clickWrapperOutside () {
if (this.appendToBody) {
setTimeout(() => {
if (!this.dropdownClicked) {
this.blur()
}
}, 0)
} else {
this.blur()
}
},
clickDropdownOutside () {
if (this.appendToBody) {
this.dropdownClicked = false
}
},
clickDropdown () {
if (this.appendToBody) {
this.dropdownClicked = true
} else {
this._refocus()
}
}
},
created () {
this.$on('click-option', this.handleSelect)
this.debouncedUpdate = debounce(50, () => {
this.focusIndex = -1
this.setSelected(this.value)
this._filterVisible()
this.$refs.dropdown && this.$refs.dropdown.checkScrollable()
})
},
mounted () {
this.hasEmptySlot = this.$slots.empty !== undefined
this.customTrigger = !!(this.$slots.trigger || this.$scopedSlots.trigger)
this.setSelected(this.value)
if (this.$refs.input) {
this.inputWidth = this.$refs.input.$el.clientWidth
......
......@@ -5,7 +5,14 @@
<x-cuctom-render v-if="customHeader" :render="customHeader"></x-cuctom-render>
<slot name="search"></slot>
<div ref="wrapper" class="inner-wrapper" :style="innerStyles">
<x-scroller ref="scroller" :scrollbar-class="scrollbarClass" :style="innerStyles" width="100%">
<x-scroller
ref="scroller"
:scrollbar-class="scrollbarClass"
:style="innerStyles"
width="100%"
@start-drag="handleStartDrag"
@dragging="handleDragging"
>
<slot></slot>
</x-scroller>
</div>
......@@ -28,11 +35,12 @@ export default {
hasArrow: Boolean,
customHeader: Function,
customFooter: Function,
customClass: String,
scrollbarClass: String
},
data () {
return {
arrowClass: `${LIB_NAME}-popper-arrow`,
arrowClass: `${LIB_NAME}-popper-arrow large`,
wrapperStyles: {},
innerStyles: {}
}
......@@ -45,11 +53,18 @@ export default {
return [
`${LIB_NAME}-select-dropdown`,
{ light: this.hasArrow },
{ 'no-box-shadow': this.noBoxShadow }
{ 'no-box-shadow': this.noBoxShadow },
this.customClass
]
}
},
methods: {
handleStartDrag () {
this.$parent.dragging = false
},
handleDragging () {
this.$parent.dragging = true
},
toggle () {
if (this.visible) {
this.hide()
......@@ -86,14 +101,14 @@ export default {
if (option && option.$el) {
this.$refs.scroller.scrollToTarget(option.$el)
}
},
setReference (reference) {
this.destroyPopper()
this.referenceEl = reference
}
},
mounted () {
this.$refs.reference = this.$parent.$el
},
beforeDestroy () {
// 调用 Popper 方法
this.destroyPopper()
}
}
</script>
......@@ -10,7 +10,7 @@
<section class="demo-section">
<h4>禁用状态</h4>
<div>
<x-switch disabled></x-switch>
<x-switch v-model="checked" disabled></x-switch>
</div>
</section>
<section class="demo-section">
......
......@@ -20,16 +20,19 @@ default-sort-orders | 点击表头文字,排序规则轮转顺序,数组元
default-expand-all | 是否默认展开所有行 | Boolean | — | false
expand-row-keys | 可以通过该属性设置 Table 目前的展开行,需要设置 row-key 属性才能使用,该属性为展开行的 keys 数组 | Array | —
cell-span-method | 合并行或列的计算方法 | Function({ row, column, rowIndex, columnIndex }) | — | —
row-key | 表格行的 key 值,用于优化渲染。当 reserve-states / internal-paging 为 true 时,必须设置该属性 | String | — | —
row-key | 表格行的 key 值,当 reserve-states 为 true 时,必须设置该属性 | String | — | —
current-row-key | 用于指定当前行,可以通过设置 .highlight-row 的样式来控制高亮 | String / Number | — | —
reserve-states | 数据实例改变后是否保存多选、展开等状态,需要设置 row-key | Boolean | — | false
children-prop | 数据结构为树结构时,叶子节点数组的对应属性名称,注意树结构的数据只能使用自定义排序 | String | — | children
tree-title | 树结构的第一列是否需要加上 title 属性 | Boolean | — | false
default-unfold-children | 数据结构为树结构时,是否默认展开所有的叶子节点 | Boolean | — | false
show-header | 是否显示表头 | String | — | true
internal-paging | 是否启用内部分页模式:实际显示的表格行数不会超过 row-limit,建议数据量过多时开启以提升性能,需要设置 row-key | Boolean | — | false
row-limit | 最大行数限制 | Number | — | 100
paging-active-distance | 未设置 table 高度时,激活上一页/下一页时的边界距离 | Number | — | 300
virtual-scroll | 是否启用虚拟滚动 | Boolean | — | false
row-height | 行高,启动虚拟滚动时需要设置 | Number | — | 38
max-tree-row | 当表格为树结构时,开启虚拟滚动后,最大渲染的行数 | Number | — | 15
reverse-scroll-y | 是否反转 Y 轴滚轮,当该值为 true 时,滚动 Y 轴将控制水平方向的滚动 | Boolean | — | true
scroll-bar-class | 自定义滚动条样式名称 | String | — | —
frozen-data | 是否冻结 data,节省内存开销 | Boolean | — | true
### Table events
......@@ -42,6 +45,8 @@ on-expand-change | 当用户对某一行展开或者关闭的时候会触发该
on-unfolded-change | 当用户展开或者关闭树节点表格时会触发该事件 | row, unfoldedRows
on-sort-change | 当表格的排序条件发生变化时触发的事件 | column, prop, order
on-hit | 当表格内容滚动到边界时触发该事件,参数为边界位置信息 | 'left' / 'right' / 'top' / 'bottom'
on-scroll | 当表格内容滚动时触发(需要设置 height 或者 restrict 为 true) | isVertical, amount
on-slice | 当虚拟滚动做数据切割时触发 |
### Table methods
......@@ -65,6 +70,7 @@ type | 列的类型 | String | selection / expand | —
label | 表头内容 | String | — | —
prop | 表格内容对应的属性,支持多层访问:如 'user.address[0].city' | String | — | —
width | 列宽,单位为 px(只支持数值型的格式,如 400) | Number / String | — | —
min-width | 最小列宽,单位为 px(只支持数值型的格式,如 400) | Number / String | — | —
fixed | 是否固定列,true 等价于 left | Boolean / String | true / left / right | false
sortable | 对应列是否可以排序,如果设置为 'custom',则代表用户希望自定义排序,需要监听 Table 的 on-sort-change 事件 | Boolean / String | true / false / 'custom' | false
sort-method | 对数据进行排序的时候使用的方法,仅当 sortable 设置为 true 的时候有效,需返回一个数字,和 Array.sort 表现一致 | Function(cellA, cellB, rowA, rowB) | — | —
......@@ -84,3 +90,4 @@ expand | 展开行的内容,参数为 { row, $index }
prepend | 表头前置插槽,可以在不破坏原有表头功能的基础上进行额外扩展,参数为 { column, $index }
append | 表头后置插槽,可以在不破坏原有表头功能的基础上进行额外扩展,参数为 { column, $index }
headerText | 表头文本插槽,可以在不破坏原有表头功能的基础上进行额外扩展,参数为 { column, $index }
treeText | 树结构第一列文本的插槽,参数为 { row, column, content, $rowIndex, $columnIndex }
......@@ -57,12 +57,13 @@
</section>
<section class="demo-section">
<h4>固定列</h4>
<x-table stripe :data="tableData">
<x-table affix stripe :data="tableData">
<x-table-column
v-for="(header, index) in detailTableHeaders"
:fixed="index === 3 ? 'right' : index === 1 ? 'left' : false"
:key="index"
width="300"
:min-width="index > 2 ? 400 : undefined"
:width="index <= 2 ? 200 : undefined"
:label="header.label"
:prop="header.prop">
</x-table-column>
......
import Vue from 'vue'
import App from './dynamic.vue'
import App from './app.vue'
new Vue({
el: '#app',
......
<template>
<div style="margin-bottom: 20px;">
<div style="line-height: 40px;">性能演示</div>
<x-table affix internal-paging border height="400" :default-column-width="200" row-key="rowId" :data="tableData">
<x-table affix border virtual-scroll height="300" :default-column-width="200" row-key="rowId" :data="tableData" :cellSpanMethod="cellSpanMethod">
<x-table-column type="selection"></x-table-column>
<x-table-column
v-for="(header, i) in headers"
......@@ -12,7 +12,18 @@
:label="header.label"
sortable
:sort-method="sortMethod"
></x-table-column>
>
<template slot="prepend" slot-scope="scope">
<div :style="{margin:i === 2 ? '0 0 0 10px' : '0 10px 0 0'}">这是前置插槽{{scope.$index}}</div>
</template>
<template slot="append" slot-scope="scope">
<div>这是后置插槽{{scope.$index}}</div>
</template>
<template slot="headerText" slot-scope="scope">
<div>这是表头文本插槽</div>
<div>{{scope.column.label}}</div>
</template>
</x-table-column>
</x-table>
</div>
</template>
......@@ -48,6 +59,24 @@ export default {
},
sortMethod (a, b) {
return a - b
},
cellSpanMethod ({ row, column, rowIndex, columnIndex }) {
// console.log('span')
if (rowIndex % 2 === 0) {
if (columnIndex === 1) {
return [1, 2]
} else if (columnIndex === 2) {
return [0, 0]
}
}
if (columnIndex === 3) {
if (rowIndex === 10) {
return [5, 1]
} else if ([11, 12, 13, 14].includes(rowIndex)) {
return [0, 0]
}
}
return [1, 1]
}
}
}
......
......@@ -3,7 +3,7 @@
<div style="line-height: 40px;">restrict 属性</div>
<button @click="changeHeight">改变高度</button>
<div style="width:800px;overflow:hidden;" :style="{height:height + 'px'}">
<x-table :data="tableData" ref="table" restrict>
<x-table :data="tableData" border ref="table" restrict>
<x-table-column
v-for="header in tableHeaders"
:fixed="header.id === 1 ? 'left' : header.id === 2 ? 'right' : false"
......@@ -38,8 +38,17 @@ export default {
components: { xTable, xTableColumn },
computed: {
tableData () {
const list = this.getListData().slice(0, 1)
list[0].children = this.getListData()
list[0].children[2].children = this.getListData()
list[0].children[2].children[2].children = this.getListData()
return list
}
},
methods: {
getListData () {
const list = []
for (let i = 0; i < 6; i++) {
for (let i = 0; i < 5; i++) {
list.push({
id: i + 1,
name: '易小宝',
......@@ -55,9 +64,7 @@ export default {
})
}
return list
}
},
methods: {
},
changeHeight () {
this.height = this.height > 240 ? 200 : 400
setTimeout(() => this.$refs.table.doLayout(), 200)
......
<template>
<div style="margin: 20px;">
<div style="margin: 20px;height:200px;">
<div style="line-height: 40px;">table tree</div>
<x-table :data="tableData">
<x-table :data="tableData" restrict ref="table" tree-title>
<x-table-column
v-for="(header, index) in tableHeaders"
:key="index"
:label="header.label"
:prop="header.prop">
<template slot="treeText" slot-scope="{content}">
<div>{{content}} + 'abc'</div>
</template>
</x-table-column>
</x-table>
</div>
......@@ -43,7 +46,7 @@ export default {
for (let i = 0; i < this.rowCount; i++) {
list.push({
id: i + 1,
name: '易小宝',
name: '易小宝易小宝易小宝易小宝易小宝易小宝易小宝易小宝易小宝易小宝易小宝易小宝易小宝',
city: '长沙',
lastUsedTime: `2018-09-${i + 1 < 10 ? '0' + (i + 1) : (i + 1)} 12:30:33`,
province: '湖南',
......@@ -57,6 +60,11 @@ export default {
}
return list
}
},
mounted () {
setTimeout(() => {
this.$refs.table.toggleRowUnfolding(this.tableData[0], true)
}, 100)
}
}
</script>
<script>
export default {
name: 'CellRenderer',
functional: true,
props: {
expand: {
type: Boolean,
......@@ -10,34 +10,42 @@ export default {
type: Boolean,
default: false
},
render: Function,
customRender: Function,
row: Object,
column: Object,
content: [String, Number, Object],
rIndex: Number,
cIndex: Number
},
render: (h, ctx) => {
render: function (h) {
let params
if (ctx.props.expand) {
if (this.expand) {
params = {
row: ctx.props.row,
$index: ctx.props.rIndex
row: this.row,
$index: this.rIndex
}
} else if (ctx.props.header) {
} else if (this.header) {
params = {
column: ctx.props.column,
$index: ctx.props.cIndex
column: this.column,
$index: this.cIndex
}
} else {
params = {
row: ctx.props.row,
column: ctx.props.column,
content: ctx.props.content,
$rowIndex: ctx.props.rIndex,
$columnIndex: ctx.props.cIndex
row: this.row,
column: this.column,
content: this.content,
$rowIndex: this.rIndex,
$columnIndex: this.cIndex
}
}
return ctx.props.render(h, params)
const result = this.customRender(h, params)
if (!result) {
return null
}
if (Array.isArray(result)) {
return result.length === 1 ? result[0] : h('div', result)
}
return result
}
}
</script>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册