wip: vite版重构中
This commit is contained in:
parent
a8163874dc
commit
0f5c55c36d
|
@ -5,3 +5,4 @@
|
|||
/*.d.ts
|
||||
/test/unit/coverage/
|
||||
/node_modules/*
|
||||
/src/env.d.ts
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
/public/*
|
||||
public/*
|
||||
/dist*
|
||||
/src/env.d.ts
|
||||
|
|
|
@ -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']
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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>
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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)
|
||||
}
|
|
@ -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>
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// / <reference types="vite/client" />
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
declare module '*.vue' {
|
||||
import { DefineComponent } from 'vue'
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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,
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
@import './variables.less';
|
||||
@import './var.less';
|
||||
@import './sidebar.less';
|
||||
@import './transition.less';
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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'
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
30
yarn.lock
30
yarn.lock
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue