wip: vite版重构中

This commit is contained in:
kailong321200875 2021-10-17 11:46:40 +08:00
parent a8163874dc
commit 0f5c55c36d
37 changed files with 2048 additions and 247 deletions

View File

@ -5,3 +5,4 @@
/*.d.ts
/test/unit/coverage/
/node_modules/*
/src/env.d.ts

View File

@ -2,3 +2,4 @@
/public/*
public/*
/dist*
/src/env.d.ts

6
components.d.ts vendored
View File

@ -5,9 +5,13 @@
declare module 'vue' {
export interface GlobalComponents {
404: typeof import('C:/Users/Saber/Documents/HBuilderProjects/vue-element-plus-admin/src/components/Error/404.vue')['default']
CountTo: typeof import('C:/Users/Saber/Documents/HBuilderProjects/vue-element-plus-admin/src/components/CountTo/index.vue')['default']
Echart: typeof import('C:/Users/Saber/Documents/HBuilderProjects/vue-element-plus-admin/src/components/Echart/index.vue')['default']
ElAlert: typeof import('element-plus/es')['ElAlert']
ElBacktop: typeof import('element-plus/es')['ElBacktop']
ElButton: typeof import('element-plus/es')['ElButton']
ElCard: typeof import('element-plus/es')['ElCard']
ElCol: typeof import('element-plus/es')['ElCol']
ElDrawer: typeof import('element-plus/es')['ElDrawer']
ElDropdown: typeof import('element-plus/es')['ElDropdown']
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
@ -17,6 +21,7 @@ declare module 'vue' {
ElInput: typeof import('element-plus/es')['ElInput']
ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElRow: typeof import('element-plus/es')['ElRow']
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
ElSwitch: typeof import('element-plus/es')['ElSwitch']
@ -25,6 +30,7 @@ declare module 'vue' {
ElTooltip: typeof import('element-plus/es')['ElTooltip']
HelloWorld: typeof import('C:/Users/Saber/Documents/HBuilderProjects/vue-element-plus-admin/src/components/HelloWorld.vue')['default']
ParentView: typeof import('C:/Users/Saber/Documents/HBuilderProjects/vue-element-plus-admin/src/components/ParentView/index.vue')['default']
Preview: typeof import('C:/Users/Saber/Documents/HBuilderProjects/vue-element-plus-admin/src/components/Preview/index.vue')['default']
Redirect: typeof import('C:/Users/Saber/Documents/HBuilderProjects/vue-element-plus-admin/src/components/Redirect/index.vue')['default']
SvgIcon: typeof import('C:/Users/Saber/Documents/HBuilderProjects/vue-element-plus-admin/src/components/SvgIcon/index.vue')['default']
}

View File

@ -26,7 +26,10 @@
"@element-plus/icons": "^0.0.11",
"@vueuse/core": "^6.5.3",
"axios": "^0.22.0",
"echarts": "^5.2.1",
"echarts-wordcloud": "^2.0.0",
"element-plus": "1.1.0-beta.20",
"intro.js": "^4.2.2",
"lodash-es": "^4.17.21",
"mockjs": "^1.1.0",
"nprogress": "^0.2.0",

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1595307154239" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7317" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48"><defs><style type="text/css"></style></defs><path d="M316 672h60c4.4 0 8-3.6 8-8V360c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v304c0 4.4 3.6 8 8 8zM512 622c22.1 0 40-17.9 40-39 0-23.1-17.9-41-40-41s-40 17.9-40 41c0 21.1 17.9 39 40 39zM512 482c22.1 0 40-17.9 40-39 0-23.1-17.9-41-40-41s-40 17.9-40 41c0 21.1 17.9 39 40 39z" p-id="7318"></path><path d="M880 112H144c-17.7 0-32 14.3-32 32v736c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V144c0-17.7-14.3-32-32-32z m-40 728H184V184h656v656z" p-id="7319"></path><path d="M648 672h60c4.4 0 8-3.6 8-8V360c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v304c0 4.4 3.6 8 8 8z" p-id="7320"></path></svg>

After

Width:  |  Height:  |  Size: 950 B

View File

@ -1 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1562375339339" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1991" width="32" height="32" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M490.965333 913.194667c-219.285333 0-397.034667-175.786667-397.034666-392.618667C93.930667 303.786667 271.68 128 490.965333 128c124.864 0 240.149333 57.365333 314.837334 153.301333 8.256 10.602667 6.250667 25.813333-4.48 33.984a24.682667 24.682667 0 0 1-34.346667-4.437333 348.757333 348.757333 0 0 0-276.010667-134.4c-192.213333 0-348.032 154.069333-348.032 344.128 0 190.08 155.818667 344.170667 348.032 344.170667 13.546667 0 24.512 10.837333 24.512 24.213333s-10.965333 24.234667-24.512 24.234667z" p-id="1992"></path><path d="M837.12 152.234667v175.018666c0 13.397333-10.986667 24.234667-24.512 24.234667a24.362667 24.362667 0 0 1-24.490667-24.234667V152.234667c0-13.397333 10.965333-24.234667 24.490667-24.234667 13.525333 0 24.490667 10.837333 24.490667 24.234667zM918.826667 547.733333a24.32 24.32 0 0 0-22.784-25.002666 24.362667 24.362667 0 0 0-26.133334 22.464 337.642667 337.642667 0 0 1-11.498666 66.773333c-3.584 12.864 4.053333 26.218667 17.109333 29.76a24.533333 24.533333 0 0 0 30.122667-16.917333c6.912-24.768 11.349333-50.432 13.141333-76.245334l0.042667-0.853333zM876.714667 685.013333a24.192 24.192 0 0 0-13.376-22.442666 24.597333 24.597333 0 0 0-32.938667 10.624 340.565333 340.565333 0 0 1-36.992 56.96 24.042667 24.042667 0 0 0 3.968 34.026666c10.602667 8.341333 26.005333 6.570667 34.410667-3.925333a386.901333 386.901333 0 0 0 42.261333-65.109333c1.706667-3.242667 2.56-6.698667 2.666667-10.112zM776.106667 805.12c0.213333-5.802667-1.706667-11.690667-5.76-16.448a24.682667 24.682667 0 0 0-34.56-2.901333 345.664 345.664 0 0 1-56.426667 38.357333 23.978667 23.978667 0 0 0-9.664 32.874667c6.506667 11.733333 21.418667 16 33.258667 9.578666a395.733333 395.733333 0 0 0 64.490666-43.754666c5.504-4.629333 8.426667-11.093333 8.661334-17.706667zM648.661333 873.770667a24.064 24.064 0 0 0-1.066666-8.042667 24.576 24.576 0 0 0-30.698667-15.936c-21.76 6.72-44.309333 11.242667-67.050667 13.482667a24.234667 24.234667 0 0 0-21.909333 26.538666c1.344 13.312 13.354667 23.04 26.794667 21.696a398.293333 398.293333 0 0 0 76.714666-15.424 24.32 24.32 0 0 0 17.216-22.314666z" p-id="1993"></path><path d="M639.061333 299.584h177.024c13.546667 0 24.512 10.858667 24.512 24.234667 0 13.376-10.965333 24.213333-24.512 24.213333h-177.024a24.362667 24.362667 0 0 1-24.490666-24.213333c0-13.376 10.965333-24.234667 24.490666-24.234667z" p-id="1994"></path></svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1595306944988" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1820" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48"><defs><style type="text/css"></style></defs><path d="M1464.3 279.7" p-id="1821"></path><path d="M512 960c-60.5 0-119.1-11.9-174.4-35.2-53.4-22.6-101.3-54.9-142.4-96s-73.4-89-96-142.4C75.9 631.1 64 572.5 64 512s11.9-119.1 35.2-174.4c22.6-53.4 54.9-101.3 96-142.4s89-73.4 142.4-96C392.9 75.9 451.5 64 512 64s119.1 11.9 174.4 35.2c53.4 22.6 101.3 54.9 142.4 96s73.4 89 96 142.4C948.1 392.9 960 451.5 960 512c0 19.1-15.5 34.6-34.6 34.6s-34.6-15.5-34.6-34.6c0-51.2-10-100.8-29.8-147.4-19.1-45.1-46.4-85.6-81.2-120.4C745 209.4 704.5 182 659.4 163c-46.7-19.7-96.3-29.8-147.4-29.8-51.2 0-100.8 10-147.4 29.8-45.1 19.1-85.6 46.4-120.4 81.2S182 319.5 163 364.6c-19.7 46.7-29.8 96.3-29.8 147.4 0 51.2 10 100.8 29.8 147.4 19.1 45.1 46.4 85.6 81.2 120.4C279 814.6 319.5 842 364.6 861c46.7 19.7 96.3 29.8 147.4 29.8 64.6 0 128.4-16.5 184.4-47.8 54.4-30.4 100.9-74.1 134.6-126.6 10.3-16.1 31.7-20.8 47.8-10.4 16.1 10.3 20.8 31.7 10.4 47.8-39.8 62-94.8 113.7-159.1 149.6-66.2 37-141.7 56.6-218.1 56.6z" p-id="1822"></path><path d="M924 552c-19.8 0-36-16.2-36-36V228c0-19.8 16.2-36 36-36s36 16.2 36 36v288c0 19.8-16.2 36-36 36zM275.4 575.5c9.5-2.5 19.1 2.9 22.3 12.2 3.5 10.2 9.9 17.7 19.1 22.6 7.1 3.9 15.1 5.8 24 5.8 16.6 0 30.8-6.9 42.5-20.8 11.7-13.8 20-32.7 24.9-75.1-7.7 12.2-17.3 20.8-28.7 25.8-11.4 5-23.7 7.4-36.8 7.4-26.7 0-47.7-8.3-63.3-24.9-15.5-16.6-23.3-37.9-23.3-64.1 0-25.1 7.7-47.1 23-66.2 15.3-19 37.9-28.6 67.8-28.6 40.3 0 68.1 18.1 83.4 54.4 8.5 19.9 12.7 44.9 12.7 74.9 0 33.8-5.1 63.8-15.3 89.9-16.9 43.5-45.5 65.2-85.8 65.2-27 0-47.6-7.1-61.6-21.2-10-10.1-16.4-22-19.3-35.8-2-9.6 4-19.1 13.5-21.6l0.9 0.1z m103-74.4c9.4-7.5 14.1-20.6 14.1-39.3 0-16.8-4.2-29.3-12.7-37.5S360.6 412 347.5 412c-14 0-25.2 4.7-33.4 14.1-8.2 9.4-12.4 22-12.4 37.7 0 14.9 3.6 26.7 10.9 35.5 7.2 8.8 18.8 13.1 34.6 13.1 11.4 0 21.8-3.8 31.2-11.3zM646.6 414.4c12.4 22.8 18.5 54 18.5 93.7 0 37.6-5.6 68.7-16.8 93.3-16.2 35.3-42.8 52.9-79.6 52.9-33.2 0-57.9-14.4-74.2-43.3-13.5-24.1-20.3-56.4-20.3-97 0-31.4 4.1-58.4 12.2-80.9 15.2-42 42.7-63 82.5-63 35.9 0 61.8 14.8 77.7 44.3z m-40.2 173.3c9.4-13.9 14-39.9 14-78 0-27.4-3.4-50-10.1-67.7-6.8-17.7-19.9-26.6-39.4-26.6-17.9 0-31 8.4-39.3 25.2-8.3 16.8-12.4 41.6-12.4 74.3 0 24.6 2.6 44.4 7.9 59.4 8.1 22.8 22 34.3 41.6 34.3 15.7 0 28.3-7 37.7-20.9zM803.3 387.2c11.2 11.3 16.8 25 16.8 41.2 0 16.7-5.8 30.7-17.5 41.8C791 481.4 777.4 487 762 487c-17.1 0-31.2-5.8-42.1-17.4-10.9-11.6-16.4-25.1-16.4-40.6 0-16.5 5.8-30.4 17.3-41.7 11.5-11.3 25.3-17 41.2-17 16.3 0 30.1 5.7 41.3 16.9zM739.5 451c6.2 6.2 13.7 9.3 22.5 9.3 8.4 0 15.8-3.1 22.1-9.3 6.3-6.2 9.4-13.7 9.4-22.6 0-8.5-3.1-15.9-9.3-22.1-6.2-6.2-13.6-9.3-22.2-9.3s-16.1 3.1-22.4 9.3c-6.3 6.2-9.4 13.7-9.4 22.6-0.1 8.4 3 15.8 9.3 22.1z" p-id="1823"></path></svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1595307195033" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8116" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48"><defs><style type="text/css"></style></defs><path d="M887.081 904.791a25.8 25.8 0 0 1-18.376-7.619L705.618 734.075l-4.163 3.369c-58.255 47.18-131.522 73.16-206.32 73.16-181.07 0-328.377-147.308-328.377-328.367 0-181.068 147.308-328.376 328.377-328.376 181.063 0 328.376 147.308 328.376 328.376 0 77.072-27.412 152.07-77.169 211.17l-3.522 4.173 162.719 162.744a25.846 25.846 0 0 1 7.639 18.432 26.081 26.081 0 0 1-26.051 26.045l-0.046-0.01zM495.13 205.957c-152.336 0-276.27 123.935-276.27 276.27 0 152.33 123.934 276.27 276.27 276.27 152.34 0 276.275-123.94 276.275-276.27 0-152.335-123.935-276.27-276.275-276.27z" p-id="8117"></path><path d="M626.545 508.355h-262.83a26.127 26.127 0 0 1 0-52.255h262.83a26.127 26.127 0 0 1 0 52.255z" p-id="8118"></path><path d="M495.13 639.77a26.127 26.127 0 0 1-26.128-26.128v-262.83a26.127 26.127 0 0 1 52.255 0v262.835a26.127 26.127 0 0 1-26.127 26.123z" p-id="8119"></path></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1595306911635" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1352" width="48" height="48" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M924.8 337.6c-22.6-53.4-54.9-101.3-96-142.4s-89-73.4-142.4-96C631.1 75.9 572.5 64 512 64S392.9 75.9 337.6 99.2c-53.4 22.6-101.3 54.9-142.4 96-22.4 22.4-42.2 46.8-59.2 73.1V228c0-19.8-16.2-36-36-36s-36 16.2-36 36v288c0 19.8 16.2 36 36 36s36-16.2 36-36v-50.2c4.2-34.8 13.2-68.7 27-101.2 19.1-45.1 46.4-85.6 81.2-120.4C279 209.4 319.5 182 364.6 163c46.7-19.7 96.3-29.8 147.4-29.8 51.2 0 100.8 10 147.4 29.8 45.1 19.1 85.6 46.4 120.4 81.2C814.6 279 842 319.5 861 364.6c19.7 46.7 29.8 96.3 29.8 147.4 0 51.2-10 100.8-29.8 147.4-19.1 45.1-46.4 85.6-81.2 120.4C745 814.6 704.5 842 659.4 861c-46.7 19.7-96.3 29.8-147.4 29.8-64.6 0-128.4-16.5-184.4-47.8-54.4-30.4-100.9-74.1-134.6-126.6-10.3-16.1-31.7-20.8-47.8-10.4-16.1 10.3-20.8 31.7-10.4 47.8 39.8 62 94.8 113.7 159.1 149.6 66.2 37 141.7 56.6 218.1 56.6 60.5 0 119.1-11.9 174.4-35.2 53.4-22.6 101.3-54.9 142.4-96 41.1-41.1 73.4-89 96-142.4C948.1 631.1 960 572.5 960 512s-11.9-119.1-35.2-174.4z" p-id="1353"></path><path d="M275.4 575.5c9.5-2.5 19.1 2.9 22.3 12.2 3.5 10.2 9.9 17.7 19.1 22.6 7.1 3.9 15.1 5.8 24 5.8 16.6 0 30.8-6.9 42.5-20.8 11.7-13.8 20-32.7 24.9-75.1-7.7 12.2-17.3 20.8-28.7 25.8-11.4 5-23.7 7.4-36.8 7.4-26.7 0-47.7-8.3-63.3-24.9-15.5-16.6-23.3-37.9-23.3-64.1 0-25.1 7.7-47.1 23-66.2 15.3-19 37.9-28.6 67.8-28.6 40.3 0 68.1 18.1 83.4 54.4 8.5 19.9 12.7 44.9 12.7 74.9 0 33.8-5.1 63.8-15.3 89.9-16.9 43.5-45.5 65.2-85.8 65.2-27 0-47.6-7.1-61.6-21.2-10-10.1-16.4-22-19.3-35.8-2-9.6 4-19.1 13.5-21.6l0.9 0.1z m103-74.4c9.4-7.5 14.1-20.6 14.1-39.3 0-16.8-4.2-29.3-12.7-37.5S360.6 412 347.5 412c-14 0-25.2 4.7-33.4 14.1-8.2 9.4-12.4 22-12.4 37.7 0 14.9 3.6 26.7 10.9 35.5 7.2 8.8 18.8 13.1 34.6 13.1 11.4 0 21.8-3.8 31.2-11.3zM646.6 414.4c12.4 22.8 18.5 54 18.5 93.7 0 37.6-5.6 68.7-16.8 93.3-16.2 35.3-42.8 52.9-79.6 52.9-33.2 0-57.9-14.4-74.2-43.3-13.5-24.1-20.3-56.4-20.3-97 0-31.4 4.1-58.4 12.2-80.9 15.2-42 42.7-63 82.5-63 35.9 0 61.8 14.8 77.7 44.3z m-40.2 173.3c9.4-13.9 14-39.9 14-78 0-27.4-3.4-50-10.1-67.7-6.8-17.7-19.9-26.6-39.4-26.6-17.9 0-31 8.4-39.3 25.2-8.3 16.8-12.4 41.6-12.4 74.3 0 24.6 2.6 44.4 7.9 59.4 8.1 22.8 22 34.3 41.6 34.3 15.7 0 28.3-7 37.7-20.9zM803.3 387.2c11.2 11.3 16.8 25 16.8 41.2 0 16.7-5.8 30.7-17.5 41.8C791 481.4 777.4 487 762 487c-17.1 0-31.2-5.8-42.1-17.4-10.9-11.6-16.4-25.1-16.4-40.6 0-16.5 5.8-30.4 17.3-41.7 11.5-11.3 25.3-17 41.2-17 16.3 0 30.1 5.7 41.3 16.9zM739.5 451c6.2 6.2 13.7 9.3 22.5 9.3 8.4 0 15.8-3.1 22.1-9.3 6.3-6.2 9.4-13.7 9.4-22.6 0-8.5-3.1-15.9-9.3-22.1-6.2-6.2-13.6-9.3-22.2-9.3s-16.1 3.1-22.4 9.3c-6.3 6.2-9.4 13.7-9.4 22.6-0.1 8.4 3 15.8 9.3 22.1z" p-id="1354"></path></svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1595308005241" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9878" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48"><defs><style type="text/css"></style></defs><path d="M750.3 198.7C598 46.4 351.1 46.4 198.7 198.7s-152.3 399.2 0 551.5C345.1 896.6 578.8 902.3 732 767.3l172.1 172.1 35.4-35.4-172.1-171.9c135-153.2 129.3-387-17.1-533.4z m39.3 403.8c-17.1 42.1-42.2 80-74.7 112.4-32.5 32.5-70.3 57.6-112.4 74.7-40.7 16.5-83.8 24.9-128 24.9s-87.2-8.4-128-24.9c-42.1-17.1-80-42.2-112.4-74.7s-57.6-70.3-74.7-112.4c-16.5-40.7-24.9-83.8-24.9-128s8.4-87.2 24.9-128c17.1-42.1 42.2-80 74.7-112.4s70.3-57.6 112.4-74.7c40.7-16.5 83.8-24.9 128-24.9s87.2 8.4 128 24.9c42.1 17.1 80 42.2 112.4 74.7 32.5 32.5 57.6 70.3 74.7 112.4 16.5 40.7 24.9 83.8 24.9 128s-8.4 87.3-24.9 128zM671 502H271v-50h400v50z" p-id="9879"></path></svg>

After

Width:  |  Height:  |  Size: 1018 B

View File

@ -0,0 +1,155 @@
<template>
<span>
{{ displayValue }}
</span>
</template>
<script setup lang="ts" name="CountTo">
import { reactive, computed, watch, onMounted, unref, toRef } from 'vue'
import { countToProps } from './props'
import { isNumber } from '@/utils/validate'
import { requestAnimationFrame, cancelAnimationFrame } from '@/utils/animation'
const props = defineProps(countToProps)
const emit = defineEmits(['mounted', 'callback'])
defineExpose({
pauseResume,
reset
})
const state = reactive<{
localStartVal: number
printVal: number | null
displayValue: string
paused: boolean
localDuration: number | null
startTime: number | null
timestamp: number | null
rAF: any
remaining: number | null
}>({
localStartVal: props.startVal,
displayValue: formatNumber(props.startVal),
printVal: null,
paused: false,
localDuration: props.duration,
startTime: null,
timestamp: null,
remaining: null,
rAF: null
})
const displayValue = toRef(state, 'displayValue')
onMounted(() => {
if (props.autoplay) {
start()
}
emit('mounted')
})
const getCountDown = computed(() => {
return props.startVal > props.endVal
})
watch([() => props.startVal, () => props.endVal], () => {
if (props.autoplay) {
start()
}
})
function start() {
const { startVal, duration } = props
state.localStartVal = startVal
state.startTime = null
state.localDuration = duration
state.paused = false
state.rAF = requestAnimationFrame(count)
}
function pauseResume() {
if (state.paused) {
resume()
state.paused = false
} else {
pause()
state.paused = true
}
}
function pause() {
cancelAnimationFrame(state.rAF)
}
function resume() {
state.startTime = null
state.localDuration = +(state.remaining as number)
state.localStartVal = +(state.printVal as number)
requestAnimationFrame(count)
}
function reset() {
state.startTime = null
cancelAnimationFrame(state.rAF)
state.displayValue = formatNumber(props.startVal)
}
function count(timestamp: number) {
const { useEasing, easingFn, endVal } = props
if (!state.startTime) state.startTime = timestamp
state.timestamp = timestamp
const progress = timestamp - state.startTime
state.remaining = (state.localDuration as number) - progress
if (useEasing) {
if (unref(getCountDown)) {
state.printVal =
state.localStartVal -
easingFn(progress, 0, state.localStartVal - endVal, state.localDuration as number)
} else {
state.printVal = easingFn(
progress,
state.localStartVal,
endVal - state.localStartVal,
state.localDuration as number
)
}
} else {
if (unref(getCountDown)) {
state.printVal =
state.localStartVal -
(state.localStartVal - endVal) * (progress / (state.localDuration as number))
} else {
state.printVal =
state.localStartVal +
(endVal - state.localStartVal) * (progress / (state.localDuration as number))
}
}
if (unref(getCountDown)) {
state.printVal = state.printVal < endVal ? endVal : state.printVal
} else {
state.printVal = state.printVal > endVal ? endVal : state.printVal
}
state.displayValue = formatNumber(state.printVal)
if (progress < (state.localDuration as number)) {
state.rAF = requestAnimationFrame(count)
} else {
emit('callback')
}
}
function formatNumber(num: number | string) {
const { decimals, decimal, separator, suffix, prefix } = props
num = Number(num).toFixed(decimals)
num += ''
const x = num.split('.')
let x1 = x[0]
const x2 = x.length > 1 ? decimal + x[1] : ''
const rgx = /(\d+)(\d{3})/
if (separator && !isNumber(separator)) {
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + separator + '$2')
}
}
return prefix + x1 + x2 + suffix
}
</script>

View File

@ -0,0 +1,62 @@
import { PropType } from 'vue'
export const countToProps = {
startVal: {
type: Number as PropType<number>,
required: false,
default: 0
},
endVal: {
type: Number as PropType<number>,
required: false,
default: 2017
},
duration: {
type: Number as PropType<number>,
required: false,
default: 3000
},
autoplay: {
type: Boolean as PropType<boolean>,
required: false,
default: true
},
decimals: {
type: Number as PropType<number>,
required: false,
default: 0,
validator(value: number) {
return value >= 0
}
},
decimal: {
type: String as PropType<string>,
required: false,
default: '.'
},
separator: {
type: String as PropType<string>,
required: false,
default: ','
},
prefix: {
type: String as PropType<string>,
required: false,
default: ''
},
suffix: {
type: String as PropType<string>,
required: false,
default: ''
},
useEasing: {
type: Boolean as PropType<boolean>,
required: false,
default: true
},
easingFn: {
type: Function as PropType<(t: number, b: number, c: number, d: number) => number>,
default(t: number, b: number, c: number, d: number) {
return (c * (-Math.pow(2, (-10 * t) / d) + 1) * 1024) / 1023 + b
}
}
}

View File

@ -0,0 +1,91 @@
<template>
<div ref="echartRef" :class="className" :style="{ height: height, width: width }"></div>
</template>
<script setup lang="ts" name="Echart">
import { PropType, onMounted, watch, computed, onBeforeUnmount, onActivated, ref, unref } from 'vue'
import type { EChartsOption } from 'echarts'
import echarts from '@/plugins/echarts'
import { debounce } from 'lodash-es'
import 'echarts-wordcloud'
type ThemeType = 'light' | 'dark' | 'default'
const props = defineProps({
options: {
type: Object as PropType<EChartsOption>,
required: true
},
className: {
type: String as PropType<string>,
default: ''
},
height: {
type: String as PropType<string>,
default: '500px'
},
width: {
type: String as PropType<string>,
default: ''
},
theme: {
type: String as PropType<ThemeType>,
default: 'default'
}
})
let chartRef: Nullable<echarts.ECharts> = null
let sidebarElm: Nullable<Element | any> = null
let __resizeHandler: Nullable<any> = null
const echartOptions = computed(() => props.options)
const echartRef = ref<Nullable<HTMLElement>>(null)
watch(
echartOptions,
(options: EChartsOption) => {
;(chartRef as echarts.ECharts).setOption(options)
},
{
deep: true
}
)
function initChart() {
chartRef = echarts.init(unref(echartRef) as HTMLElement, props.theme)
chartRef.setOption(props.options)
}
function sidebarResizeHandler(e: any): void {
if (e.propertyName === 'width') {
if (__resizeHandler) {
__resizeHandler()
}
}
}
onMounted(() => {
initChart()
__resizeHandler = debounce(() => {
if (chartRef) {
chartRef.resize()
}
}, 100)
window.addEventListener('resize', __resizeHandler)
sidebarElm = document.getElementsByClassName('sidebar__wrap')[0]
sidebarElm && sidebarElm.addEventListener('transitionend', sidebarResizeHandler)
})
onBeforeUnmount(() => {
window.removeEventListener('resize', __resizeHandler)
sidebarElm && sidebarElm.removeEventListener('transitionend', sidebarResizeHandler)
})
onActivated(() => {
// keep-alive
if (chartRef) {
chartRef.resize()
}
})
</script>

View File

@ -0,0 +1,33 @@
import ImgPreview from './index.vue'
import { isClient } from '@/utils/validate'
import type { Options, Props } from './types'
import { createVNode, render } from 'vue'
let instance: any = null
export function createImgPreview(options: Options) {
if (!isClient) return
const {
imageList,
show = true,
index = 0,
onSelect = null,
onClose = null,
zIndex = 500
} = options
const propsData: Partial<Props> = {}
const container = document.createElement('div')
propsData.imageList = imageList
propsData.show = show
propsData.index = index
propsData.zIndex = zIndex
propsData.onSelect = onSelect
propsData.onClose = onClose
document.body.appendChild(container)
instance = createVNode(ImgPreview, propsData)
render(instance, container)
}

View File

@ -0,0 +1,429 @@
<template>
<transition name="viewer-fade">
<div
v-show="show"
ref="wrapElRef"
tabindex="-1"
:style="{ 'z-index': zIndex }"
class="image-viewer__wrapper"
>
<div class="image-viewer__mask"></div>
<!-- CLOSE -->
<span class="image-viewer__btn image-viewer__close" @click="hide">
<i class="el-icon-circle-close iconfont"></i>
</span>
<!-- ARROW -->
<template v-if="!isSingle">
<span
class="image-viewer__btn image-viewer__prev"
:class="{ 'is-disabled': !infinite && isFirst }"
@click="prev"
>
<i class="el-icon-arrow-left iconfont"></i>
</span>
<span
class="image-viewer__btn image-viewer__next"
:class="{ 'is-disabled': !infinite && isLast }"
@click="next"
>
<i class="el-icon-arrow-right iconfont"></i>
</span>
</template>
<!-- ACTIONS -->
<div class="image-viewer__btn image-viewer__actions">
<div class="image-viewer__actions__inner">
<svg-icon class="iconfont" icon-class="unscale" @click="handleActions('zoomOut')" />
<svg-icon class="iconfont" icon-class="scale" @click="handleActions('zoomIn')" />
<svg-icon class="iconfont" icon-class="resume" @click="toggleMode" />
<svg-icon
class="iconfont"
icon-class="unrotate"
@click="handleActions('anticlocelise')"
/>
<svg-icon class="iconfont" icon-class="rotate" @click="handleActions('clocelise')" />
</div>
</div>
<!-- CANVAS -->
<div class="image-viewer__canvas">
<img
ref="imgRef"
:src="currentImg"
:style="imgStyle"
class="image-viewer__img"
@load="handleImgLoad"
@error="handleImgError"
@mousedown="handleMouseDown"
@click="select"
/>
</div>
</div>
</transition>
</template>
<script setup lang="ts" name="Preview">
import { ref, reactive, computed, watch, nextTick, unref } from 'vue'
import { previewProps } from './props'
import { isFirefox } from '@/utils/validate'
import { on, off } from '@/utils/dom-utils'
import throttle from 'lodash-es/throttle'
import SvgIcon from '_c/SvgIcon/index.vue'
const mousewheelEventName = isFirefox() ? 'DOMMouseScroll' : 'mousewheel'
const props = defineProps(previewProps)
const infinite = ref<boolean>(true)
const loading = ref<boolean>(false)
const show = ref<boolean>(props.show)
const index = ref<number>(props.index)
const transform = reactive({
scale: 1,
deg: 0,
offsetX: 0,
offsetY: 0,
enableTransition: false
})
const isSingle = computed((): boolean => props.imageList.length <= 1)
const isFirst = computed((): boolean => index.value === 0)
const isLast = computed((): boolean => index.value === props.imageList.length - 1)
const currentImg = computed((): string => props.imageList[index.value])
const imgStyle = computed(() => {
const { scale, deg, offsetX, offsetY, enableTransition } = transform
const style = {
transform: `scale(${scale}) rotate(${deg}deg)`,
transition: enableTransition ? 'transform .3s' : '',
'margin-left': `${offsetX}px`,
'margin-top': `${offsetY}px`
}
return style
})
const wrapElRef = ref<HTMLElement | null>(null)
const imgRef = ref<HTMLElement | null>(null)
let _keyDownHandler: Function | null = null
let _mouseWheelHandler: Function | null = null
let _dragHandler: Function | null = null
watch(
() => index.value,
() => {
reset()
}
)
watch(
() => currentImg.value,
() => {
nextTick(() => {
const $img = unref(imgRef) as any
if (!$img.complete) {
loading.value = true
}
})
}
)
watch(
() => show.value,
(show: boolean) => {
if (show) {
nextTick(() => {
;(unref(wrapElRef) as any).focus()
document.body.style.overflow = 'hidden'
deviceSupportInstall()
})
} else {
nextTick(() => {
document.body.style.overflow = 'auto'
deviceSupportUninstall()
})
}
},
{
immediate: true
}
)
function hide(): void {
show.value = false
if (typeof props.onClose === 'function') {
props.onClose(index.value)
}
}
function select(): void {
if (typeof props.onSelect === 'function') {
props.onSelect(index.value)
}
}
function deviceSupportInstall(): void {
_keyDownHandler = throttle((e: any) => {
const keyCode = e.keyCode
switch (keyCode) {
// ESC
case 27:
hide()
break
// SPACE
case 32:
toggleMode()
break
// LEFT_ARROW
case 37:
prev()
break
// UP_ARROW
case 38:
handleActions('zoomIn')
break
// RIGHT_ARROW
case 39:
next()
break
// DOWN_ARROW
case 40:
handleActions('zoomOut')
break
}
})
_mouseWheelHandler = throttle((e: any) => {
const delta = e.wheelDelta ? e.wheelDelta : -e.detail
if (delta > 0) {
handleActions('zoomIn', {
zoomRate: 0.015,
enableTransition: false
})
} else {
handleActions('zoomOut', {
zoomRate: 0.015,
enableTransition: false
})
}
})
on(document, 'keydown', _keyDownHandler as any)
on(document, mousewheelEventName, _mouseWheelHandler as any)
}
function deviceSupportUninstall(): void {
off(document, 'keydown', _keyDownHandler)
off(document, mousewheelEventName, _mouseWheelHandler)
_keyDownHandler = null
_mouseWheelHandler = null
}
function handleImgLoad(): void {
loading.value = false
}
function handleImgError(e: any): void {
loading.value = false
e.target.alt = '加载失败'
}
function handleMouseDown(e: any): void {
if (loading.value || e.button !== 0) return
const { offsetX, offsetY } = transform
const startX = e.pageX
const startY = e.pageY
_dragHandler = throttle((ev: any) => {
transform.offsetX = offsetX + ev.pageX - startX
transform.offsetY = offsetY + ev.pageY - startY
})
on(document, 'mousemove', _dragHandler as any)
on(document, 'mouseup', () => {
off(document, 'mousemove', _dragHandler as any)
})
e.preventDefault()
}
function reset(): void {
transform.scale = 1
transform.deg = 0
transform.offsetX = 0
transform.offsetY = 0
transform.enableTransition = false
}
function toggleMode(): void {
if (loading.value) return
reset()
}
function prev(): void {
if (isFirst.value && !infinite.value) return
const len = props.imageList.length
index.value = (index.value - 1 + len) % len
}
function next(): void {
if (isLast.value && !infinite.value) return
const len = props.imageList.length
index.value = (index.value + 1) % len
}
function handleActions(action: string, options: any = {}): void {
if (loading.value) return
const style = {
zoomRate: 0.2,
rotateDeg: 90,
enableTransition: true,
...options
}
const { zoomRate, rotateDeg, enableTransition } = style
switch (action) {
case 'zoomOut':
if (transform.scale > 0.2) {
transform.scale = parseFloat((transform.scale - zoomRate).toFixed(3))
}
break
case 'zoomIn':
transform.scale = parseFloat((transform.scale + zoomRate).toFixed(3))
break
case 'clocelise':
transform.deg += rotateDeg
break
case 'anticlocelise':
transform.deg -= rotateDeg
break
}
transform.enableTransition = enableTransition
}
</script>
<style lang="less" scoped>
.iconfont {
cursor: pointer;
}
.image-viewer__wrapper {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.image-viewer__btn {
position: absolute;
z-index: 1;
display: flex;
cursor: pointer;
border-radius: 50%;
opacity: 0.8;
box-sizing: border-box;
user-select: none;
align-items: center;
justify-content: center;
}
.image-viewer__close {
top: 40px;
right: 40px;
width: 40px;
height: 40px;
font-size: 40px;
color: #fff;
}
.image-viewer__canvas {
display: flex;
width: 100%;
height: 100%;
justify-content: center;
align-items: center;
}
.image-viewer__actions {
bottom: 30px;
left: 50%;
width: 282px;
height: 44px;
padding: 0 23px;
background-color: #606266;
border-color: #fff;
border-radius: 22px;
transform: translateX(-50%);
.image-viewer__actions__inner {
display: flex;
width: 100%;
height: 100%;
font-size: 23px;
color: #fff;
text-align: justify;
cursor: default;
align-items: center;
justify-content: space-around;
}
}
.image-viewer__prev {
top: 50%;
left: 40px;
width: 44px;
height: 44px;
font-size: 24px;
color: #fff;
background-color: #606266;
border-color: #fff;
transform: translateY(-50%);
}
.image-viewer__next {
top: 50%;
right: 40px;
width: 44px;
height: 44px;
font-size: 24px;
color: #fff;
text-indent: 2px;
background-color: #606266;
border-color: #fff;
transform: translateY(-50%);
}
.image-viewer__mask {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #000;
opacity: 0.5;
}
.viewer-fade-enter-active {
animation: viewer-fade-in 0.3s;
}
.viewer-fade-leave-active {
animation: viewer-fade-out 0.3s;
}
@keyframes viewer-fade-in {
0% {
opacity: 0;
transform: translate3d(0, -20px, 0);
}
100% {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
@keyframes viewer-fade-out {
0% {
opacity: 1;
transform: translate3d(0, 0, 0);
}
100% {
opacity: 0;
transform: translate3d(0, -20px, 0);
}
}
</style>

View File

@ -0,0 +1,28 @@
import { PropType } from 'vue'
export const previewProps = {
index: {
type: Number as PropType<number>,
default: 0
},
zIndex: {
type: Number as PropType<number>,
default: 100
},
show: {
type: Boolean as PropType<boolean>,
default: false
},
imageList: {
type: [Array] as PropType<string[]>,
default: []
},
onClose: {
type: Function as PropType<Function>,
default: null
},
onSelect: {
type: Function as PropType<Function>,
default: null
}
}

View File

@ -0,0 +1,18 @@
export interface Options {
show?: boolean
imageList: string[]
index?: number
zIndex?: number
onSelect?: Function | null
onClose?: Function | null
}
export interface Props {
show: boolean
instance: Props
imageList: string[]
index: number
zIndex: number
onSelect: Function | null
onClose: Function | null
}

2
src/env.d.ts vendored
View File

@ -1,4 +1,4 @@
// / <reference types="vite/client" />
/// <reference types="vite/client" />
declare module '*.vue' {
import { DefineComponent } from 'vue'

View File

@ -36,7 +36,7 @@
<template #title>
<item v-if="siderItem.meta" :icon="siderItem?.meta?.icon" :title="siderItem.meta.title" />
</template>
<sider-item
<sider-item-com
v-for="child in siderItem.children"
:key="child.path"
:is-nest="true"
@ -51,7 +51,6 @@
<script setup lang="ts" name="SiderItemCom">
import { PropType, ref, computed } from 'vue'
import type { RouteRecordRaw } from 'vue-router'
import path from 'path-browserify'
import { isExternal } from '@/utils/validate'
import Item from './Item.vue'
import { usePermissionStore } from '@/store/modules/permission'
@ -78,7 +77,6 @@ const props = defineProps({
default: 'Classic'
}
})
const onlyOneChild = ref<any>(null)
const activeTab = computed(() => permissionStore.getActiveTab)
@ -114,7 +112,10 @@ function resolvePath(routePath: string, otherPath?: string): string {
if (isExternal(routePath)) {
return routePath
}
return path.resolve(otherPath || props.basePath, routePath)
return (
((otherPath || props.basePath) === '/' ? '' : otherPath || props.basePath) +
(routePath ? '/' + routePath : '')
)
}
</script>

View File

@ -48,9 +48,7 @@ defineProps({
})
const { currentRoute, push } = useRouter()
const routers = computed(() => {
return permissionStore.getRouters
})
const routers = computed(() => permissionStore.getRouters)
const activeMenu = computed(() => {
const { meta, path } = currentRoute.value
// if set path, the sidebar will highlight the path you set

View File

@ -0,0 +1,33 @@
import * as echarts from 'echarts/core'
import { BarChart, LineChart, PieChart, MapChart, PictorialBarChart } from 'echarts/charts'
import {
TitleComponent,
TooltipComponent,
GridComponent,
PolarComponent,
AriaComponent,
ParallelComponent,
LegendComponent
} from 'echarts/components'
import { CanvasRenderer } from 'echarts/renderers'
echarts.use([
LegendComponent,
TitleComponent,
TooltipComponent,
GridComponent,
PolarComponent,
AriaComponent,
ParallelComponent,
BarChart,
LineChart,
PieChart,
MapChart,
CanvasRenderer,
PictorialBarChart
])
export default echarts

View File

@ -2,11 +2,13 @@ import { createRouter, createWebHashHistory } from 'vue-router'
import type { RouteRecordRaw } from 'vue-router'
import { AppRouteRecordRaw } from './types'
import type { App } from 'vue'
// import { getParentLayout } from './utils'
import { getParentLayout } from './utils'
/* Layout */
const Layout = () => import('../layout/index.vue')
// const ParentView = () => import('_c/ParentView/index.vue')
/**
* redirect: noredirect noredirect
* name:'router-name' 使<keep-alive>
@ -84,163 +86,163 @@ export const constantRouterMap: AppRouteRecordRaw[] = [
}
}
]
},
{
path: '/external-link',
component: Layout,
meta: {},
children: [
{
path: 'http://8.133.179.48:4000/dist-doc/',
meta: { title: '文档', icon: 'documentation' }
}
]
},
{
path: '/guide',
component: Layout,
name: 'Guide',
meta: {},
children: [
{
path: 'index',
component: () => import('_v/guide/index.vue'),
name: 'GuideDemo',
meta: {
title: '引导页',
icon: 'guide'
}
}
]
}
// {
// path: '/external-link',
// component: Layout,
// meta: {},
// children: [
// {
// path: 'http://8.133.179.48:4000/dist-doc/',
// meta: { title: '文档', icon: 'documentation' }
// }
// ]
// },
// {
// path: '/guide',
// component: Layout,
// name: 'Guide',
// meta: {},
// children: [
// {
// path: 'index',
// component: () => import('_v/guide/index.vue'),
// name: 'GuideDemo',
// meta: {
// title: '引导页',
// icon: 'guide'
// }
// }
// ]
// }
]
export const asyncRouterMap: AppRouteRecordRaw[] = [
// {
// path: '/components-demo',
// component: Layout,
// redirect: '/components-demo/echarts',
// name: 'ComponentsDemo',
// meta: {
// title: '功能组件',
// icon: 'component',
// alwaysShow: true
// },
// children: [
// {
// path: 'echarts',
// component: () => import('_v/components-demo/echarts/index.vue'),
// name: 'EchartsDemo',
// meta: {
// title: '图表'
// }
// },
// {
// path: 'preview',
// component: () => import('_v/components-demo/preview/index.vue'),
// name: 'PreviewDemo',
// meta: {
// title: '图片预览'
// }
// },
// {
// path: 'button',
// component: () => import('_v/components-demo/button/index.vue'),
// name: 'ButtonDemo',
// meta: {
// title: '按钮'
// }
// },
// {
// path: 'message',
// component: () => import('_v/components-demo/message/index.vue'),
// name: 'MessageDemo',
// meta: {
// title: '消息提示'
// }
// },
// {
// path: 'count-to',
// component: () => import('_v/components-demo/count-to/index.vue'),
// name: 'CountToDemo',
// meta: {
// title: '数字动画'
// }
// },
// {
// path: 'search',
// component: () => import('_v/components-demo/search/index.vue'),
// name: 'SearchDemo',
// meta: {
// title: '查询'
// }
// },
// {
// path: 'editor',
// component: () => import('_v/components-demo/editor/index.vue'),
// name: 'EditorDemo',
// meta: {
// title: '富文本编辑器'
// }
// },
// {
// path: 'markdown',
// component: () => import('_v/components-demo/markdown/index.vue'),
// name: 'MarkdownDemo',
// meta: {
// title: 'markdown编辑器'
// }
// },
// {
// path: 'dialog',
// component: () => import('_v/components-demo/dialog/index.vue'),
// name: 'DialogDemo',
// meta: {
// title: '弹窗'
// }
// },
// {
// path: 'more',
// component: () => import('_v/components-demo/more/index.vue'),
// name: 'MoreDemo',
// meta: {
// title: '显示更多'
// }
// },
// {
// path: 'detail',
// component: () => import('_v/components-demo/detail/index.vue'),
// name: 'DetailDemo',
// meta: {
// title: '详情组件'
// }
// },
// {
// path: 'qrcode',
// component: () => import('_v/components-demo/qrcode/index.vue'),
// name: 'QrcodeDemo',
// meta: {
// title: '二维码组件'
// }
// },
// {
// path: 'avatars',
// component: () => import('_v/components-demo/avatars/index.vue'),
// name: 'AvatarsDemo',
// meta: {
// title: '头像组'
// }
// },
// {
// path: 'highlight',
// component: () => import('_v/components-demo/highlight/index.vue'),
// name: 'HighlightDemo',
// meta: {
// title: '文字高亮'
// }
// }
// ]
// },
{
path: '/components-demo',
component: Layout,
redirect: '/components-demo/echarts',
name: 'ComponentsDemo',
meta: {
title: '功能组件',
icon: 'component',
alwaysShow: true
},
children: [
{
path: 'echarts',
component: () => import('_v/components-demo/echarts/index.vue'),
name: 'EchartsDemo',
meta: {
title: '图表'
}
},
{
path: 'preview',
component: () => import('_v/components-demo/preview/index.vue'),
name: 'PreviewDemo',
meta: {
title: '图片预览'
}
}
// {
// path: 'button',
// component: () => import('_v/components-demo/button/index.vue'),
// name: 'ButtonDemo',
// meta: {
// title: '按钮'
// }
// },
// {
// path: 'message',
// component: () => import('_v/components-demo/message/index.vue'),
// name: 'MessageDemo',
// meta: {
// title: '消息提示'
// }
// },
// {
// path: 'count-to',
// component: () => import('_v/components-demo/count-to/index.vue'),
// name: 'CountToDemo',
// meta: {
// title: '数字动画'
// }
// },
// {
// path: 'search',
// component: () => import('_v/components-demo/search/index.vue'),
// name: 'SearchDemo',
// meta: {
// title: '查询'
// }
// },
// {
// path: 'editor',
// component: () => import('_v/components-demo/editor/index.vue'),
// name: 'EditorDemo',
// meta: {
// title: '富文本编辑器'
// }
// },
// {
// path: 'markdown',
// component: () => import('_v/components-demo/markdown/index.vue'),
// name: 'MarkdownDemo',
// meta: {
// title: 'markdown编辑器'
// }
// },
// {
// path: 'dialog',
// component: () => import('_v/components-demo/dialog/index.vue'),
// name: 'DialogDemo',
// meta: {
// title: '弹窗'
// }
// },
// {
// path: 'more',
// component: () => import('_v/components-demo/more/index.vue'),
// name: 'MoreDemo',
// meta: {
// title: '显示更多'
// }
// },
// {
// path: 'detail',
// component: () => import('_v/components-demo/detail/index.vue'),
// name: 'DetailDemo',
// meta: {
// title: '详情组件'
// }
// },
// {
// path: 'qrcode',
// component: () => import('_v/components-demo/qrcode/index.vue'),
// name: 'QrcodeDemo',
// meta: {
// title: '二维码组件'
// }
// },
// {
// path: 'avatars',
// component: () => import('_v/components-demo/avatars/index.vue'),
// name: 'AvatarsDemo',
// meta: {
// title: '头像组'
// }
// },
// {
// path: 'highlight',
// component: () => import('_v/components-demo/highlight/index.vue'),
// name: 'HighlightDemo',
// meta: {
// title: '文字高亮'
// }
// }
]
},
// {
// path: '/table-demo',
// component: Layout,
@ -481,65 +483,65 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [
// }
// ]
// },
// {
// path: '/level',
// component: Layout,
// redirect: '/level/menu1/menu1-1/menu1-1-1',
// name: 'Level',
// meta: {
// title: '多级菜单缓存',
// icon: 'nested'
// },
// children: [
// {
// path: 'menu1',
// name: 'Menu1Demo',
// component: getParentLayout('Menu1Demo'),
// redirect: '/level/menu1/menu1-1/menu1-1-1',
// meta: {
// title: 'Menu1'
// },
// children: [
// {
// path: 'menu1-1',
// name: 'Menu11Demo',
// component: getParentLayout('Menu11Demo'),
// redirect: '/level/menu1/menu1-1/menu1-1-1',
// meta: {
// title: 'Menu1-1',
// alwaysShow: true
// },
// children: [
// {
// path: 'menu1-1-1',
// name: 'Menu111Demo',
// component: () => import('_v/level/Menu111.vue'),
// meta: {
// title: 'Menu1-1-1'
// }
// }
// ]
// },
// {
// path: 'menu1-2',
// name: 'Menu12Demo',
// component: () => import('_v/level/Menu12.vue'),
// meta: {
// title: 'Menu1-2'
// }
// }
// ]
// },
// {
// path: 'menu2',
// name: 'Menu2Demo',
// component: () => import('_v/level/Menu2.vue'),
// meta: {
// title: 'Menu2'
// }
// }
// ]
// },
{
path: '/level',
component: Layout,
redirect: '/level/menu1/menu1-1/menu1-1-1',
name: 'Level',
meta: {
title: '多级菜单缓存',
icon: 'nested'
},
children: [
{
path: 'menu1',
name: 'Menu1Demo',
component: getParentLayout('Menu1Demo'),
redirect: '/level/menu1/menu1-1/menu1-1-1',
meta: {
title: 'Menu1'
},
children: [
{
path: 'menu1-1',
name: 'Menu11Demo',
component: getParentLayout('Menu11Demo'),
redirect: '/level/menu1/menu1-1/menu1-1-1',
meta: {
title: 'Menu1-1',
alwaysShow: true
},
children: [
{
path: 'menu1-1-1',
name: 'Menu111Demo',
component: () => import('_v/level/Menu111.vue'),
meta: {
title: 'Menu1-1-1'
}
}
]
},
{
path: 'menu1-2',
name: 'Menu12Demo',
component: () => import('_v/level/Menu12.vue'),
meta: {
title: 'Menu1-2'
}
}
]
},
{
path: 'menu2',
name: 'Menu2Demo',
component: () => import('_v/level/Menu2.vue'),
meta: {
title: 'Menu2'
}
}
]
}
// {
// path: '/example-demo',
// component: Layout,

View File

@ -2,3 +2,4 @@
@import './variables.less';
@import './var.less';
@import './sidebar.less';
@import './transition.less';

View File

@ -11,7 +11,7 @@
background-color: var(--menu-background-color) !important;
.el-menu-item,
.el-submenu__title {
.el-sub-menu__title {
color: var(--menu-text-color) !important;
background-color: var(--menu-background-color) !important;
@ -20,9 +20,9 @@
}
}
.el-submenu {
.el-sub-menu {
.el-menu-item,
.el-submenu {
.el-sub-menu {
background-color: var(--sub-menu-background-color) !important;
}
@ -30,7 +30,7 @@
color: var(--menu-active-text-color) !important;
background-color: var(--sub-menu-hover-color) !important;
& > .el-submenu__title {
& > .el-sub-menu__title {
color: var(--menu-active-text-color) !important;
}
}
@ -39,14 +39,14 @@
.el-menu {
background-color: var(--sub-menu-background-color) !important;
.el-submenu__title {
.el-sub-menu__title {
background-color: var(--sub-menu-background-color) !important;
}
}
}
// menu hover
.submenu-title-noDropdown,
.el-submenu__title {
.el-sub-menu__title {
&:hover {
color: var(--sub-menu-active-text-color) !important;
background-color: var(--menu-background-color) !important;
@ -67,14 +67,14 @@
background-color: var(--sub-menu-hover-color) !important;
}
& > .el-submenu__title {
& > .el-sub-menu__title {
color: var(--menu-active-text-color) !important;
}
}
// .nest-menu {
// background-color: var(--sub-menu-background-color) !important;
// .el-submenu>.el-submenu__title {
// .el-sub-menu>.el-sub-menu__title {
// background-color: var(--sub-menu-background-color) !important;
// }
// .is-active {
@ -84,14 +84,14 @@
}
.el-menu--collapse {
& > div > .el-submenu {
& > div > .el-sub-menu {
i {
display: none;
}
}
.is-active {
& > .el-submenu__title {
& > .el-sub-menu__title {
background-color: var(--sub-menu-hover-color) !important;
}
}
@ -112,7 +112,7 @@
background-color: var(--menu-background-color) !important;
.el-menu-item,
.el-submenu__title {
.el-sub-menu__title {
color: var(--menu-text-color) !important;
background-color: var(--menu-background-color) !important;
@ -125,7 +125,7 @@
color: var(--menu-active-text-color) !important;
background-color: var(--sub-menu-hover-color) !important;
& > .el-submenu__title {
& > .el-sub-menu__title {
color: var(--menu-active-text-color) !important;
}
}
@ -137,7 +137,7 @@
// }
// menu hover
.submenu-title-noDropdown,
.el-submenu__title {
.el-sub-menu__title {
&:hover {
color: var(--sub-menu-active-text-color) !important;
background-color: var(--menu-background-color) !important;
@ -159,7 +159,7 @@
background-color: var(--top-menu-background-color) !important;
.el-menu-item,
.el-submenu__title {
.el-sub-menu__title {
height: var(--top-sider-height);
line-height: var(--top-sider-height);
color: var(--top-menu-text-color) !important;
@ -178,7 +178,7 @@
color: var(--top-menu-active-text-color) !important;
background: var(--top-menu-active-background-color) !important;
& > .el-submenu__title {
& > .el-sub-menu__title {
color: var(--top-menu-active-text-color) !important;
background: var(--top-menu-active-background-color) !important;
}
@ -192,7 +192,7 @@
// .nest-menu {
// background-color: var(--sub-menu-background-color) !important;
// .el-submenu>.el-submenu__title {
// .el-sub-menu>.el-sub-menu__title {
// background-color: var(--sub-menu-background-color) !important;
// }
// .is-active {
@ -201,7 +201,7 @@
// }
// menu hover
.submenu-title-noDropdown,
.el-submenu__title {
.el-sub-menu__title {
&:hover {
color: var(--top-sub-menu-active-text-color) !important;
background: var(--top-menu-active-background-color) !important;
@ -217,15 +217,15 @@
}
.top-popper-menu {
margin-top: 10px;
margin-left: 10px;
// margin-top: 10px;
// margin-left: 10px;
background: var(--top-menu-background-color);
.el-menu {
background-color: var(--top-menu-background-color) !important;
.el-menu-item,
.el-submenu__title {
.el-sub-menu__title {
color: var(--top-menu-text-color) !important;
background-color: var(--top-menu-background-color) !important;
@ -238,7 +238,7 @@
color: var(--top-menu-active-text-color) !important;
background-color: var(--top-menu-active-background-color) !important;
& > .el-submenu__title {
& > .el-sub-menu__title {
color: var(--top-menu-active-text-color) !important;
background-color: var(--top-menu-active-background-color) !important;
@ -255,7 +255,7 @@
// }
// menu hover
.submenu-title-noDropdown,
.el-submenu__title {
.el-sub-menu__title {
&:hover {
color: var(--top-sub-menu-hover-color) !important;
background-color: var(--top-menu-background-color) !important;

View File

@ -34,7 +34,7 @@ export function isTel(tel: any): boolean {
}
// 验证数字
export function isNum(num: any): boolean {
export function isNumber(num: any): boolean {
return /^[0-9]*$/.test(num)
}
@ -82,3 +82,25 @@ export const isFirefox = function () {
export function isString(val: unknown): val is string {
return is(val, 'String')
}
export const isWindow = (val: any): val is Window => {
return typeof window !== 'undefined' && is(val, 'Window')
}
export const isDef = <T = unknown>(val?: T): val is T => {
return typeof val !== 'undefined'
}
export const isUnDef = <T = unknown>(val?: T): val is T => {
return !isDef(val)
}
export const isFunction = (val: unknown): val is Function => typeof val === 'function'
export const isClient = () => {
return typeof window !== 'undefined'
}
export const isElement = (val: unknown): val is Element => {
return isObject(val) && !!val.tagName
}

View File

@ -0,0 +1,306 @@
import { EChartsOption } from 'echarts'
import { EChartsOption as EChartsWordOption } from 'echarts-wordcloud'
export const lineOptions: EChartsOption = {
xAxis: {
data: [
'一月',
'二月',
'三月',
'四月',
'五月',
'六月',
'七月',
'八月',
'九月',
'十月',
'十一月',
'十二月'
],
boundaryGap: false,
axisTick: {
show: false
}
},
grid: {
left: 20,
right: 20,
bottom: 20,
top: 30,
containLabel: true
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
},
padding: [5, 10]
},
yAxis: {
axisTick: {
show: false
}
},
legend: {
data: ['预期', '实际']
},
series: [
{
name: '预期',
smooth: true,
type: 'line',
data: [100, 120, 161, 134, 105, 160, 165, 114, 163, 185, 118, 123],
animationDuration: 2800,
animationEasing: 'cubicInOut'
},
{
name: '实际',
smooth: true,
type: 'line',
itemStyle: {},
data: [120, 82, 91, 154, 162, 140, 145, 250, 134, 56, 99, 123],
animationDuration: 2800,
animationEasing: 'quadraticOut'
}
]
}
export const pieOptions: EChartsOption = {
title: {
text: '用户访问来源',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b} : {c} ({d}%)'
},
legend: {
orient: 'vertical',
left: 'left',
data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎']
},
series: [
{
name: '用户访问来源',
type: 'pie',
radius: '55%',
center: ['50%', '60%'],
data: [
{ value: 335, name: '直接访问' },
{ value: 310, name: '邮件营销' },
{ value: 234, name: '联盟广告' },
{ value: 135, name: '视频广告' },
{ value: 1548, name: '搜索引擎' }
]
}
]
}
export const barOptions: EChartsOption = {
title: {
text: '每周用户活跃量',
left: 'center'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
xAxis: {
type: 'category',
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
axisTick: {
alignWithLabel: true
}
},
yAxis: {
type: 'value'
},
series: [
{
name: '活跃量',
data: [13253, 34235, 26321, 12340, 24643, 1322, 1324],
type: 'bar'
}
]
}
export const pieOptions2: EChartsOption = {
title: {
text: '用户访问来源',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b} : {c} ({d}%)'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [
{
name: '访问来源',
type: 'pie',
radius: '55%',
center: ['50%', '50%'],
data: [
{
value: 335,
name: '直接访问'
},
{
value: 310,
name: '邮件营销'
},
{
value: 274,
name: '联盟广告'
},
{
value: 235,
name: '视频广告'
},
{
value: 400,
name: '搜索引擎'
}
].sort(function (a, b) {
return a.value - b.value
}),
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
}
export const wordOptions: EChartsWordOption = {
tooltip: {},
series: [
{
type: 'wordCloud',
gridSize: 2,
sizeRange: [12, 50],
rotationRange: [-90, 90],
shape: 'pentagon',
width: 600,
height: 400,
drawOutOfBound: true,
textStyle: {
color: function () {
return (
'rgb(' +
[
Math.round(Math.random() * 160),
Math.round(Math.random() * 160),
Math.round(Math.random() * 160)
].join(',') +
')'
)
}
},
emphasis: {
textStyle: {
shadowBlur: 10,
shadowColor: '#333'
}
},
data: [
{
name: 'Sam S Club',
value: 10000,
textStyle: {
color: 'black'
},
emphasis: {
textStyle: {
color: 'red'
}
}
},
{
name: 'Macys',
value: 6181
},
{
name: 'Amy Schumer',
value: 4386
},
{
name: 'Jurassic World',
value: 4055
},
{
name: 'Charter Communications',
value: 2467
},
{
name: 'Chick Fil A',
value: 2244
},
{
name: 'Planet Fitness',
value: 1898
},
{
name: 'Pitch Perfect',
value: 1484
},
{
name: 'Express',
value: 1112
},
{
name: 'Home',
value: 965
},
{
name: 'Johnny Depp',
value: 847
},
{
name: 'Lena Dunham',
value: 582
},
{
name: 'Lewis Hamilton',
value: 555
},
{
name: 'KXAN',
value: 550
},
{
name: 'Mary Ellen Mark',
value: 462
},
{
name: 'Farrah Abraham',
value: 366
},
{
name: 'Rita Ora',
value: 360
},
{
name: 'Serena Williams',
value: 282
},
{
name: 'NCAA baseball tournament',
value: 273
},
{
name: 'Point Break',
value: 265
}
]
}
]
}

View File

@ -0,0 +1,53 @@
<template>
<div>
<el-alert
effect="dark"
:closable="false"
title="统一封装 Echart 组件,自适应宽度,只需传入 options 与 height 属性即可展示对应的图表。"
type="info"
style="margin-bottom: 20px"
/>
<el-row :gutter="20">
<el-col :span="10">
<div class="chart-wrap">
<echart :height="'300px'" :options="pieOptions" />
</div>
</el-col>
<el-col :span="14">
<div class="chart-wrap">
<echart :options="barOptions" :height="'300px'" />
</div>
</el-col>
<el-col :span="14">
<div class="chart-wrap">
<echart :options="lineOptions" :height="'300px'" />
</div>
</el-col>
<el-col :span="10">
<div class="chart-wrap">
<echart :options="pieOptions2" :height="'300px'" />
</div>
</el-col>
<el-col :span="24">
<div class="chart-wrap">
<echart :options="wordOptions" :height="'300px'" />
</div>
</el-col>
</el-row>
</div>
</template>
<script setup lang="ts" name="EchartsDemo">
import { lineOptions, pieOptions, barOptions, pieOptions2, wordOptions } from './echart-data'
import Echart from '_c/Echart/index.vue'
</script>
<style lang="less" scoped>
.chart-wrap {
padding: 10px;
margin-bottom: 20px;
background-color: #fff;
border-radius: 5px;
}
</style>

View File

@ -0,0 +1,113 @@
<template>
<div>
<el-alert
effect="dark"
:closable="false"
title="抽取于 Element 的图片预览组件进行改造,实现函数式调用组件,无需基于图片进行点击预览。"
type="info"
style="margin-bottom: 20px"
/>
<el-alert
effect="dark"
:closable="false"
title="有底图预览。"
type="info"
style="margin-bottom: 20px"
/>
<div class="img-wrap">
<div
v-for="(item, $index) in imgList"
:key="item"
class="img-item"
@click="showHasImg($index)"
>
<img :src="item" alt="" />
</div>
</div>
<el-alert
effect="dark"
:closable="false"
title="无底图预览。"
type="info"
style="margin-top: 20px; margin-bottom: 20px"
/>
<el-button type="primary" @click="showNoImg">点击预览</el-button>
<el-alert
effect="dark"
:closable="false"
title="点击事件,包含图片点击事件以及关闭事件。"
type="info"
style="margin-top: 20px; margin-bottom: 20px"
/>
<el-button type="primary" @click="showImg">点击预览</el-button>
</div>
</template>
<script setup lang="ts" name="PreviewDemo">
import { ref } from 'vue'
import { createImgPreview } from '_c/Preview'
import { Message } from '_c/Message'
const imgList = ref<string[]>([
'https://img1.baidu.com/it/u=657828739,1486746195&fm=26&fmt=auto&gp=0.jpg',
'https://img0.baidu.com/it/u=3114228356,677481409&fm=26&fmt=auto&gp=0.jpg',
'https://img1.baidu.com/it/u=508846955,3814747122&fm=26&fmt=auto&gp=0.jpg',
'https://img1.baidu.com/it/u=3536647690,3616605490&fm=26&fmt=auto&gp=0.jpg',
'https://img1.baidu.com/it/u=4087287201,1148061266&fm=26&fmt=auto&gp=0.jpg',
'https://img2.baidu.com/it/u=3429163260,2974496379&fm=26&fmt=auto&gp=0.jpg'
])
function showHasImg(i: number) {
createImgPreview({
index: i,
imageList: imgList.value
})
}
function showNoImg() {
createImgPreview({
index: 0,
imageList: imgList.value
})
}
function showImg() {
createImgPreview({
index: 0,
imageList: imgList.value,
onClose: (i: number) => {
Message.info('关闭的图片索引:' + i)
},
onSelect: (i: number) => {
Message.info('当前点击的图片索引:' + i)
}
})
}
</script>
<style lang="less" scoped>
.img-wrap {
display: flex;
justify-content: center;
.img-item {
position: relative;
width: 400px;
height: 300px;
margin: 0 10px;
overflow: hidden;
cursor: pointer;
img {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
}
</style>

View File

@ -0,0 +1,147 @@
<template>
<el-row :gutter="20" class="panel-group">
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('newVisitis')">
<div class="card-panel-icon-wrapper icon-people">
<svg-icon icon-class="peoples" class-name="card-panel-icon" />
</div>
<div class="card-panel-description">
<div class="card-panel-text">新增用户</div>
<count-to :start-val="0" :end-val="102400" :duration="2600" class="card-panel-num" />
</div>
</div>
</el-col>
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('messages')">
<div class="card-panel-icon-wrapper icon-message">
<svg-icon icon-class="message" class-name="card-panel-icon" />
</div>
<div class="card-panel-description">
<div class="card-panel-text">未读信息</div>
<count-to :start-val="0" :end-val="81212" :duration="3000" class="card-panel-num" />
</div>
</div>
</el-col>
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('purchases')">
<div class="card-panel-icon-wrapper icon-money">
<svg-icon icon-class="money" class-name="card-panel-icon" />
</div>
<div class="card-panel-description">
<div class="card-panel-text">成交金额</div>
<count-to :start-val="0" :end-val="9280" :duration="3200" class="card-panel-num" />
</div>
</div>
</el-col>
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('shoppings')">
<div class="card-panel-icon-wrapper icon-shopping">
<svg-icon icon-class="shopping" class-name="card-panel-icon" />
</div>
<div class="card-panel-description">
<div class="card-panel-text">购物总量</div>
<count-to :start-val="0" :end-val="13600" :duration="3600" class="card-panel-num" />
</div>
</div>
</el-col>
</el-row>
</template>
<script setup lang="ts" name="PanelGroup">
import CountTo from '_c/CountTo/index.vue'
const emit = defineEmits(['handleSetLineChartData'])
function handleSetLineChartData(type: string) {
emit('handleSetLineChartData', type)
}
</script>
<style lang="less" scoped>
.panel-group {
.card-panel-col {
margin-bottom: 20px;
}
.card-panel {
position: relative;
height: 108px;
overflow: hidden;
font-size: 12px;
color: #666;
cursor: pointer;
background: #fff;
border-color: rgba(0, 0, 0, 0.05);
box-shadow: 4px 4px 40px rgba(0, 0, 0, 0.05);
&:hover {
.card-panel-icon-wrapper {
color: #fff;
}
.icon-people {
background: #40c9c6;
}
.icon-message {
background: #36a3f7;
}
.icon-money {
background: #f4516c;
}
.icon-shopping {
background: #34bfa3;
}
}
.icon-people {
color: #40c9c6;
}
.icon-message {
color: #36a3f7;
}
.icon-money {
color: #f4516c;
}
.icon-shopping {
color: #34bfa3;
}
.card-panel-icon-wrapper {
float: left;
padding: 16px;
margin: 14px 0 0 14px;
border-radius: 6px;
transition: all 0.38s ease-out;
}
.card-panel-icon {
float: left;
font-size: 48px;
}
.card-panel-description {
float: right;
margin: 26px;
margin-left: 0;
font-weight: bold;
.card-panel-text {
margin-bottom: 12px;
font-size: 16px;
line-height: 18px;
color: rgba(0, 0, 0, 0.45);
}
.card-panel-num {
font-size: 20px;
}
}
}
}
</style>

View File

@ -0,0 +1,126 @@
import { EChartsOption } from 'echarts'
export const lineOptions: EChartsOption = {
xAxis: {
data: [
'一月',
'二月',
'三月',
'四月',
'五月',
'六月',
'七月',
'八月',
'九月',
'十月',
'十一月',
'十二月'
],
boundaryGap: false,
axisTick: {
show: false
}
},
grid: {
left: 20,
right: 20,
bottom: 20,
top: 30,
containLabel: true
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
},
padding: [5, 10]
},
yAxis: {
axisTick: {
show: false
}
},
legend: {
data: ['预期', '实际']
},
series: [
{
name: '预期',
smooth: true,
type: 'line',
data: [100, 120, 161, 134, 105, 160, 165, 114, 163, 185, 118, 123],
animationDuration: 2800,
animationEasing: 'cubicInOut'
},
{
name: '实际',
smooth: true,
type: 'line',
itemStyle: {},
data: [120, 82, 91, 154, 162, 140, 145, 250, 134, 56, 99, 123],
animationDuration: 2800,
animationEasing: 'quadraticOut'
}
]
}
export const pieOptions: EChartsOption = {
title: {
text: '用户访问来源',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b} : {c} ({d}%)'
},
legend: {
orient: 'vertical',
left: 'left',
data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎']
},
series: [
{
name: '用户访问来源',
type: 'pie',
radius: '55%',
center: ['50%', '60%'],
data: [
{ value: 335, name: '直接访问' },
{ value: 310, name: '邮件营销' },
{ value: 234, name: '联盟广告' },
{ value: 135, name: '视频广告' },
{ value: 1548, name: '搜索引擎' }
]
}
]
}
export const barOptions: EChartsOption = {
title: {
text: '每周用户活跃量',
left: 'center'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
xAxis: {
type: 'category',
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
axisTick: {
alignWithLabel: true
}
},
yAxis: {
type: 'value'
},
series: [
{
name: '活跃量',
data: [13253, 34235, 26321, 12340, 24643, 1322, 1324],
type: 'bar'
}
]
}

View File

@ -1,5 +1,35 @@
<template>
<div>2222</div>
<div>
<panel-group />
<el-row :gutter="20">
<el-col :span="10">
<div class="chart__wrap">
<echart :options="pieOptions" :height="'300px'" />
</div>
</el-col>
<el-col :span="14">
<div class="chart__wrap">
<echart :options="barOptions" :height="'300px'" />
</div>
</el-col>
</el-row>
<div class="chart__wrap">
<echart :options="lineOptions" :height="'300px'" />
</div>
</div>
</template>
<script setup lang="ts" name="Dashboard"></script>
<script setup lang="ts" name="Dashboard">
import { lineOptions, pieOptions, barOptions } from './echart-data'
import Echart from '_c/Echart/index.vue'
import PanelGroup from './components/PanelGroup.vue'
</script>
<style lang="less" scoped>
.chart__wrap {
padding: 10px;
margin-bottom: 20px;
background-color: #fff;
border-radius: 5px;
}
</style>

32
src/views/guide/index.vue Normal file
View File

@ -0,0 +1,32 @@
<template>
<div>
<el-alert
effect="dark"
:closable="false"
title=" 引导页对于一些第一次进入项目的人很有用,你可以简单介绍下项目的功能。引导页基于 intro.js"
type="info"
style="margin-bottom: 20px"
/>
<el-button type="primary" @click.prevent.stop="guide"> 开始引导 </el-button>
</div>
</template>
<script setup lang="ts" name="Guide">
import { onMounted } from 'vue'
import { useIntro } from '@/hooks/web/useIntro'
const { intro } = useIntro()
import steps from './steps'
function guide() {
intro.start()
}
onMounted(() => {
intro.addSteps(steps as any[]).setOptions({
prevLabel: '上一步',
nextLabel: '下一步',
skipLabel: '跳过',
doneLabel: '结束'
})
})
</script>

40
src/views/guide/steps.ts Normal file
View File

@ -0,0 +1,40 @@
const steps = [
{
element: '#sidebar__wrap',
title: '菜单栏',
intro: '以路由的结构渲染的菜单栏',
position: 'right'
},
{
element: '#hamburger-container',
title: '展开缩收',
intro: '用于展开和缩放菜单栏',
position: 'bottom'
},
{
element: '#breadcrumb-container',
title: '面包屑',
intro: '用于记录当前路由结构',
position: 'bottom'
},
{
element: '#screenfull-container',
title: '是否全屏',
intro: '用于设置是否全屏',
position: 'bottom'
},
{
element: '#user-container',
title: '用户信息',
intro: '用于展示用户',
position: 'bottom'
},
{
element: '#tag-container',
title: '标签页',
intro: '用于记录路由历史记录',
position: 'bottom'
}
]
export default steps

View File

@ -0,0 +1,12 @@
<template>
<div style="display: flex; padding: 20px; background: #fff; align-items: center">
<div style="min-width: 200px">多层级缓存-页面1-1-1</div>
<el-input v-model="value" />
</div>
</template>
<script setup lang="ts" name="Menu111Demo">
import { ref } from 'vue'
const value = ref<string>('')
</script>

View File

@ -0,0 +1,12 @@
<template>
<div style="display: flex; padding: 20px; background: #fff; align-items: center">
<div style="min-width: 200px">多层级缓存-页面1-2</div>
<el-input v-model="value" />
</div>
</template>
<script setup lang="ts" name="Menu12Demo">
import { ref } from 'vue'
const value = ref<string>('')
</script>

12
src/views/level/menu2.vue Normal file
View File

@ -0,0 +1,12 @@
<template>
<div style="display: flex; padding: 20px; background: #fff; align-items: center">
<div style="min-width: 200px">多层级缓存-页面2</div>
<el-input v-model="value" />
</div>
</template>
<script setup lang="ts" name="Menu2Demo">
import { ref } from 'vue'
const value = ref<string>('')
</script>

View File

@ -2478,6 +2478,19 @@ dot-prop@^5.1.0:
dependencies:
is-obj "^2.0.0"
echarts-wordcloud@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/echarts-wordcloud/-/echarts-wordcloud-2.0.0.tgz#52ef817895801ffe9e99dd1bacab7686b2dec04a"
integrity sha512-K7l6pTklqdW7ZWzT/1CS0KhBSINr/cd7c5N1fVMzZMwLQHEwT7x+nivK7g5hkVh7WNcAv4Dn6/ZS5zMKRozC1g==
echarts@^5.2.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/echarts/-/echarts-5.2.1.tgz#bd58ec011cd82def4a714e4038ef4b73b8417bc3"
integrity sha512-OJ79b22eqRfbSV8vYmDKmA+XWfNbr0Uk/OafWcFNIGDWti2Uw9A6eVCiJLmqPa9Sk+EWL+t5v26aak0z3gxiZw==
dependencies:
tslib "2.3.0"
zrender "5.2.1"
electron-to-chromium@^1.3.857:
version "1.3.864"
resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.864.tgz#6a993bcc196a2b8b3df84d28d5d4dd912393885f"
@ -3661,6 +3674,11 @@ inquirer@6.5.2:
strip-ansi "^5.1.0"
through "^2.3.6"
intro.js@^4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/intro.js/-/intro.js-4.2.2.tgz#9077549cc6ef697e78d18d1c05003b7471281e1a"
integrity sha512-Zgz2e8syCuttJ2vJlDOWCSWPUJBr7AOJkU5Ti3zcvXho+y//q0ixwoT+PkPLJWI7AX35IdgRcxAEWUrOAJYiNQ==
is-accessor-descriptor@^0.1.6:
version "0.1.6"
resolved "https://registry.nlark.com/is-accessor-descriptor/download/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
@ -6774,6 +6792,11 @@ ts-node@^9:
source-map-support "^0.5.17"
yn "3.1.1"
tslib@2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e"
integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
tslib@^1.8.1, tslib@^1.9.0:
version "1.14.1"
resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
@ -7459,6 +7482,13 @@ yocto-queue@^0.1.0:
resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
zrender@5.2.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/zrender/-/zrender-5.2.1.tgz#5f4bbda915ba6d412b0b19dc2431beaad05417bb"
integrity sha512-M3bPGZuyLTNBC6LiNKXJwSCtglMp8XUEqEBG+2MdICDI3d1s500Y4P0CzldQGsqpRVB7fkvf3BKQQRxsEaTlsw==
dependencies:
tslib "2.3.0"
zwitch@^1.0.0:
version "1.0.5"
resolved "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920"