Forráskód Böngészése

feat: 自定义指令新增
1. 全局复制命令
2. 点击水波扩散效果新增
3. 不依赖第三方ui库的message提示组件
refactor: 管理界面布局ui更新
1. svg文件移除背景色
2. 侧边栏样式优化

kindring 1 éve
szülő
commit
94714e429c

+ 1 - 1
assets/icons/svg/all.svg

@@ -1 +1 @@
-<svg t="1681465373129" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2628" width="200" height="200"><path d="M384 896c-17.664 0-32-14.304-32-32L352 160c0-17.664 14.336-32 32-32s32 14.336 32 32l0 704C416 881.696 401.664 896 384 896z" fill="#5D656E" p-id="2629"></path><path d="M641.056 896.128c-17.696 0-32-14.304-32-32l0-704c0-17.664 14.304-32 32-32s32 14.336 32 32l0 704C673.056 881.824 658.752 896.128 641.056 896.128z" fill="#5D656E" p-id="2630"></path><path d="M864 736c-17.696 0-32-14.304-32-32L832 320c0-17.664 14.304-32 32-32s32 14.336 32 32l0 384C896 721.696 881.696 736 864 736z" fill="#5D656E" p-id="2631"></path><path d="M160 736c-17.664 0-32-14.304-32-32L128 320c0-17.664 14.336-32 32-32s32 14.336 32 32l0 384C192 721.696 177.664 736 160 736z" fill="#5D656E" p-id="2632"></path></svg>
+<svg t="1681465373129" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2628" width="200" height="200"><path d="M384 896c-17.664 0-32-14.304-32-32L352 160c0-17.664 14.336-32 32-32s32 14.336 32 32l0 704C416 881.696 401.664 896 384 896z"  p-id="2629"></path><path d="M641.056 896.128c-17.696 0-32-14.304-32-32l0-704c0-17.664 14.304-32 32-32s32 14.336 32 32l0 704C673.056 881.824 658.752 896.128 641.056 896.128z"  p-id="2630"></path><path d="M864 736c-17.696 0-32-14.304-32-32L832 320c0-17.664 14.304-32 32-32s32 14.336 32 32l0 384C896 721.696 881.696 736 864 736z"  p-id="2631"></path><path d="M160 736c-17.664 0-32-14.304-32-32L128 320c0-17.664 14.336-32 32-32s32 14.336 32 32l0 384C192 721.696 177.664 736 160 736z"  p-id="2632"></path></svg>

+ 1 - 1
assets/icons/svg/arrow-down.svg

@@ -1 +1 @@
-<svg t="1688635660812" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5400" width="200" height="200"><path d="M888.2 286.1L512 662.3 135.8 286.1c-16.4-16.4-43.1-16.4-59.5 0s-16.4 43.1 0 59.5l382.6 382.6c14.2 14.2 33 22 53.1 22s38.9-7.8 53.1-22l382.6-382.6c16.4-16.4 16.4-43.1 0-59.5-16.5-16.4-43.1-16.4-59.5 0z" fill="#272636" p-id="5401"></path></svg>
+<svg t="1688635660812" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5400" width="200" height="200"><path d="M888.2 286.1L512 662.3 135.8 286.1c-16.4-16.4-43.1-16.4-59.5 0s-16.4 43.1 0 59.5l382.6 382.6c14.2 14.2 33 22 53.1 22s38.9-7.8 53.1-22l382.6-382.6c16.4-16.4 16.4-43.1 0-59.5-16.5-16.4-43.1-16.4-59.5 0z"  p-id="5401"></path></svg>

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
assets/icons/svg/camera.svg


+ 1 - 1
assets/icons/svg/close.svg

@@ -1 +1 @@
-<svg t="1682101832270" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9026" width="200" height="200"><path d="M504.224 470.288l207.84-207.84a16 16 0 0 1 22.608 0l11.328 11.328a16 16 0 0 1 0 22.624l-207.84 207.824 207.84 207.84a16 16 0 0 1 0 22.608l-11.328 11.328a16 16 0 0 1-22.624 0l-207.824-207.84-207.84 207.84a16 16 0 0 1-22.608 0l-11.328-11.328a16 16 0 0 1 0-22.624l207.84-207.824-207.84-207.84a16 16 0 0 1 0-22.608l11.328-11.328a16 16 0 0 1 22.624 0l207.824 207.84z" fill="#000000" p-id="9027"></path></svg>
+<svg t="1682101832270" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9026" width="200" height="200"><path d="M504.224 470.288l207.84-207.84a16 16 0 0 1 22.608 0l11.328 11.328a16 16 0 0 1 0 22.624l-207.84 207.824 207.84 207.84a16 16 0 0 1 0 22.608l-11.328 11.328a16 16 0 0 1-22.624 0l-207.824-207.84-207.84 207.84a16 16 0 0 1-22.608 0l-11.328-11.328a16 16 0 0 1 0-22.624l207.84-207.824-207.84-207.84a16 16 0 0 1 0-22.608l11.328-11.328a16 16 0 0 1 22.624 0l207.824 207.84z"  p-id="9027"></path></svg>

+ 1 - 1
assets/icons/svg/ePower.svg

@@ -1 +1 @@
-<svg t="1681810336929" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4459" width="200" height="200"><path d="M579.456 128c31.008 0 58.016 22.08 65.504 53.568L677.984 320H800v64h-106.72l30.528 128H832v64l-96.128 0.032-0.256 3.264 61.76 226.56c10.24 37.568-10.496 76.704-46.368 87.424a64.8 64.8 0 0 1-50.048-5.44l-4.992-3.072L512 760.992l-183.968 123.776a64.96 64.96 0 0 1-55.04 8.512c-35.84-10.72-56.64-49.856-46.4-87.392l61.792-226.592L288.192 576H192v-64h108.16l30.528-128H224v-64h121.984l33.056-138.432c7.072-29.76 31.584-51.072 60.384-53.376l5.12-0.192h134.912z m103.968 517.632l-108.992 73.312 158.048 106.368-49.056-179.68z m-342.88 0L291.52 825.312l158.016-106.368-108.992-73.312zM661.984 576H361.92L512 676.928 661.984 576z m-49.952-192h-200.128l-34.944 128h269.984l-34.912-128z m-50.56-185.28h-98.976L429.376 320h165.184l-33.056-121.28z" fill="#686C78" p-id="4460"></path></svg>
+<svg t="1681810336929" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4459" width="200" height="200"><path d="M579.456 128c31.008 0 58.016 22.08 65.504 53.568L677.984 320H800v64h-106.72l30.528 128H832v64l-96.128 0.032-0.256 3.264 61.76 226.56c10.24 37.568-10.496 76.704-46.368 87.424a64.8 64.8 0 0 1-50.048-5.44l-4.992-3.072L512 760.992l-183.968 123.776a64.96 64.96 0 0 1-55.04 8.512c-35.84-10.72-56.64-49.856-46.4-87.392l61.792-226.592L288.192 576H192v-64h108.16l30.528-128H224v-64h121.984l33.056-138.432c7.072-29.76 31.584-51.072 60.384-53.376l5.12-0.192h134.912z m103.968 517.632l-108.992 73.312 158.048 106.368-49.056-179.68z m-342.88 0L291.52 825.312l158.016-106.368-108.992-73.312zM661.984 576H361.92L512 676.928 661.984 576z m-49.952-192h-200.128l-34.944 128h269.984l-34.912-128z m-50.56-185.28h-98.976L429.376 320h165.184l-33.056-121.28z"  p-id="4460"></path></svg>

+ 1 - 1
assets/icons/svg/index-setting.svg

@@ -1 +1 @@
-<svg t="1688641537753" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1609" width="200" height="200"><path d="M932 754h-46.1c-9.7 23.9-23.6 45.6-40.3 64.8l24.9 43.2c7.5 13.1 3.1 29.8-10 37.3L765.9 954c-13.1 7.5-29.8 3.1-37.4-10l-27.2-47.1c-10.1 1.3-20.3 2.4-30.7 2.4-10.4 0-20.6-1-30.8-2.4L612.6 944c-7.6 13.1-24.2 17.6-37.4 10l-94.7-54.7c-13.1-7.6-17.5-24.3-10.1-37.3l25-43.2c-16.7-19.2-30.5-40.8-40.2-64.8h-46.1c-16.1 0-29.1-13-29.1-29.1V608.8c0-16 13-29 29.1-29h46.1c9.7-23.9 23.5-45.6 40.2-64.8l-25-43.2c-7.4-13.1-3-29.8 10.1-37.3l94.7-54.7c13.2-7.5 29.8-3.1 37.4 10l27.2 47.1c10.2-1.3 20.4-2.4 30.8-2.4 10.4 0 20.6 1 30.7 2.4l27.2-47.1c7.6-13.1 24.3-17.6 37.4-10l94.7 54.7c13.1 7.5 17.5 24.3 10 37.3l-25 43.2c16.7 19.2 30.5 40.8 40.3 64.8H932c16.1 0 29.1 13 29.1 29V725c0 16-13.1 29-29.1 29zM670.5 551c-64 0-115.9 51.9-115.9 115.9s51.8 115.9 115.9 115.9 115.9-51.9 115.9-115.9S734.6 551 670.5 551zM544.4 308.9l-74.9-66.6L67.3 599.9V376.4L469.5 63.6l306.9 238.7c-33.6-9.7-69-15.2-105.8-15.2-44.4-0.1-86.7 7.9-126.2 21.8z m-253.7 358c0 93.2 33.7 178.4 89.4 244.5v46H156.6V644.5l176.2-151c-26.7 52-42.1 110.9-42.1 173.4z" fill="#070102" p-id="1610"></path></svg>
+<svg t="1688641537753" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1609" width="200" height="200"><path d="M932 754h-46.1c-9.7 23.9-23.6 45.6-40.3 64.8l24.9 43.2c7.5 13.1 3.1 29.8-10 37.3L765.9 954c-13.1 7.5-29.8 3.1-37.4-10l-27.2-47.1c-10.1 1.3-20.3 2.4-30.7 2.4-10.4 0-20.6-1-30.8-2.4L612.6 944c-7.6 13.1-24.2 17.6-37.4 10l-94.7-54.7c-13.1-7.6-17.5-24.3-10.1-37.3l25-43.2c-16.7-19.2-30.5-40.8-40.2-64.8h-46.1c-16.1 0-29.1-13-29.1-29.1V608.8c0-16 13-29 29.1-29h46.1c9.7-23.9 23.5-45.6 40.2-64.8l-25-43.2c-7.4-13.1-3-29.8 10.1-37.3l94.7-54.7c13.2-7.5 29.8-3.1 37.4 10l27.2 47.1c10.2-1.3 20.4-2.4 30.8-2.4 10.4 0 20.6 1 30.7 2.4l27.2-47.1c7.6-13.1 24.3-17.6 37.4-10l94.7 54.7c13.1 7.5 17.5 24.3 10 37.3l-25 43.2c16.7 19.2 30.5 40.8 40.3 64.8H932c16.1 0 29.1 13 29.1 29V725c0 16-13.1 29-29.1 29zM670.5 551c-64 0-115.9 51.9-115.9 115.9s51.8 115.9 115.9 115.9 115.9-51.9 115.9-115.9S734.6 551 670.5 551zM544.4 308.9l-74.9-66.6L67.3 599.9V376.4L469.5 63.6l306.9 238.7c-33.6-9.7-69-15.2-105.8-15.2-44.4-0.1-86.7 7.9-126.2 21.8z m-253.7 358c0 93.2 33.7 178.4 89.4 244.5v46H156.6V644.5l176.2-151c-26.7 52-42.1 110.9-42.1 173.4z"  p-id="1610"></path></svg>

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
assets/icons/svg/lowPower.svg


+ 1 - 1
assets/icons/svg/more.svg

@@ -1 +1 @@
-<svg t="1650133442635" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8461" width="200" height="200"><path d="M341.333333 533.333333a128 128 0 0 1 128 128v149.333334a128 128 0 0 1-128 128H192a128 128 0 0 1-128-128v-149.333334a128 128 0 0 1 128-128h149.333333z m469.333334 0a128 128 0 0 1 128 128v149.333334a128 128 0 0 1-128 128h-149.333334a128 128 0 0 1-128-128v-149.333334a128 128 0 0 1 128-128h149.333334z m-469.333334 64H192a64 64 0 0 0-63.893333 60.245334L128 661.333333v149.333334a64 64 0 0 0 60.245333 63.893333L192 874.666667h149.333333a64 64 0 0 0 63.893334-60.245334L405.333333 810.666667v-149.333334a64 64 0 0 0-60.245333-63.893333L341.333333 597.333333z m469.333334 0h-149.333334a64 64 0 0 0-63.893333 60.245334L597.333333 661.333333v149.333334a64 64 0 0 0 60.245334 63.893333L661.333333 874.666667h149.333334a64 64 0 0 0 63.893333-60.245334L874.666667 810.666667v-149.333334a64 64 0 0 0-60.245334-63.893333L810.666667 597.333333zM341.333333 64a128 128 0 0 1 128 128v149.333333a128 128 0 0 1-128 128H192a128 128 0 0 1-128-128V192a128 128 0 0 1 128-128h149.333333z m469.333334 0a128 128 0 0 1 128 128v149.333333a128 128 0 0 1-128 128h-149.333334a128 128 0 0 1-128-128V192a128 128 0 0 1 128-128h149.333334zM341.333333 128H192a64 64 0 0 0-63.893333 60.245333L128 192v149.333333a64 64 0 0 0 60.245333 63.893334L192 405.333333h149.333333a64 64 0 0 0 63.893334-60.245333L405.333333 341.333333V192a64 64 0 0 0-60.245333-63.893333L341.333333 128z m469.333334 0h-149.333334a64 64 0 0 0-63.893333 60.245333L597.333333 192v149.333333a64 64 0 0 0 60.245334 63.893334L661.333333 405.333333h149.333334a64 64 0 0 0 63.893333-60.245333L874.666667 341.333333V192a64 64 0 0 0-60.245334-63.893333L810.666667 128z" fill="#333333" p-id="8462"></path></svg>
+<svg t="1650133442635" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8461" width="200" height="200"><path d="M341.333333 533.333333a128 128 0 0 1 128 128v149.333334a128 128 0 0 1-128 128H192a128 128 0 0 1-128-128v-149.333334a128 128 0 0 1 128-128h149.333333z m469.333334 0a128 128 0 0 1 128 128v149.333334a128 128 0 0 1-128 128h-149.333334a128 128 0 0 1-128-128v-149.333334a128 128 0 0 1 128-128h149.333334z m-469.333334 64H192a64 64 0 0 0-63.893333 60.245334L128 661.333333v149.333334a64 64 0 0 0 60.245333 63.893333L192 874.666667h149.333333a64 64 0 0 0 63.893334-60.245334L405.333333 810.666667v-149.333334a64 64 0 0 0-60.245333-63.893333L341.333333 597.333333z m469.333334 0h-149.333334a64 64 0 0 0-63.893333 60.245334L597.333333 661.333333v149.333334a64 64 0 0 0 60.245334 63.893333L661.333333 874.666667h149.333334a64 64 0 0 0 63.893333-60.245334L874.666667 810.666667v-149.333334a64 64 0 0 0-60.245334-63.893333L810.666667 597.333333zM341.333333 64a128 128 0 0 1 128 128v149.333333a128 128 0 0 1-128 128H192a128 128 0 0 1-128-128V192a128 128 0 0 1 128-128h149.333333z m469.333334 0a128 128 0 0 1 128 128v149.333333a128 128 0 0 1-128 128h-149.333334a128 128 0 0 1-128-128V192a128 128 0 0 1 128-128h149.333334zM341.333333 128H192a64 64 0 0 0-63.893333 60.245333L128 192v149.333333a64 64 0 0 0 60.245333 63.893334L192 405.333333h149.333333a64 64 0 0 0 63.893334-60.245333L405.333333 341.333333V192a64 64 0 0 0-60.245333-63.893333L341.333333 128z m469.333334 0h-149.333334a64 64 0 0 0-63.893333 60.245333L597.333333 192v149.333333a64 64 0 0 0 60.245334 63.893334L661.333333 405.333333h149.333334a64 64 0 0 0 63.893333-60.245333L874.666667 341.333333V192a64 64 0 0 0-60.245334-63.893333L810.666667 128z"  p-id="8462"></path></svg>

+ 1 - 1
assets/icons/svg/news.svg

@@ -1 +1 @@
-<svg t="1692069803365" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4041" width="200" height="200"><path d="M928 0l-704 0c-53.024 0-96 42.944-96 96l0 64-32 0c-53.024 0-96 42.944-96 96l0 640c0 70.688 57.312 128 128 128l768 0c70.688 0 128-57.312 128-128l0-800c0-53.056-43.008-96-96-96zM960 896c0 35.264-28.736 64-64 64l-768 0c-35.296 0-64-28.736-64-64l0-640c0-17.664 14.336-32 32-32l32 0 0 640c0 17.696 14.304 32 32 32s32-14.304 32-32l0-768c0-17.664 14.336-32 32-32l704 0c17.632 0 32 14.336 32 32l0 800zM623.936 416.16c-8.8 0-16-7.168-16-16s7.2-16 16-16l256 0c8.864 0 16 7.168 16 16s-7.136 16-16 16l-256 0zM623.936 320.16c-8.8 0-16-7.168-16-16s7.2-16 16-16l256 0c8.864 0 16 7.168 16 16s-7.136 16-16 16l-256 0zM623.936 224.16c-8.8 0-16-7.168-16-16s7.2-16 16-16l256 0c8.864 0 16 7.168 16 16s-7.136 16-16 16l-256 0zM528 864.128c8.832 0 16 7.2 16 16 0 8.864-7.2 16-16 16l-256 0c-8.832 0-16-7.136-16-16 0-8.8 7.168-16 16-16l256 0zM528 768.128c8.832 0 16 7.2 16 16 0 8.864-7.2 16-16 16l-256 0c-8.832 0-16-7.136-16-16 0-8.8 7.168-16 16-16l256 0zM528 672.128c8.832 0 16 7.2 16 16 0 8.864-7.2 16-16 16l-256 0c-8.832 0-16-7.136-16-16 0-8.8 7.168-16 16-16l256 0zM880 864.128c8.8 0 16 7.2 16 16 0 8.864-7.2 16-16 16l-256 0c-8.864 0-16-7.136-16-16 0-8.8 7.136-16 16-16l256 0zM880 768.128c8.8 0 16 7.2 16 16 0 8.864-7.2 16-16 16l-256 0c-8.864 0-16-7.136-16-16 0-8.8 7.136-16 16-16l256 0zM880 672.128c8.8 0 16 7.2 16 16 0 8.864-7.2 16-16 16l-256 0c-8.864 0-16-7.136-16-16 0-8.8 7.136-16 16-16l256 0zM880 480.128c8.8 0 16 7.168 16 16s-7.2 16-16 16l-608 0c-8.832 0-16-7.168-16-16s7.168-16 16-16l608 0zM880 576.128c8.8 0 16 7.2 16 16 0 8.864-7.2 16-16 16l-608 0c-8.832 0-16-7.136-16-16 0-8.8 7.168-16 16-16l608 0zM288 416l224 0c17.696 0 32-14.304 32-32l0-223.872c0-17.696-14.304-32-32-32l-224 0c-17.696 0-32 14.304-32 32l0 223.872c0 17.664 14.304 32 32 32zM320 192l160 0 0 160-160 0 0-160z" fill="#444444" p-id="4042"></path></svg>
+<svg t="1692069803365" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4041" width="200" height="200"><path d="M928 0l-704 0c-53.024 0-96 42.944-96 96l0 64-32 0c-53.024 0-96 42.944-96 96l0 640c0 70.688 57.312 128 128 128l768 0c70.688 0 128-57.312 128-128l0-800c0-53.056-43.008-96-96-96zM960 896c0 35.264-28.736 64-64 64l-768 0c-35.296 0-64-28.736-64-64l0-640c0-17.664 14.336-32 32-32l32 0 0 640c0 17.696 14.304 32 32 32s32-14.304 32-32l0-768c0-17.664 14.336-32 32-32l704 0c17.632 0 32 14.336 32 32l0 800zM623.936 416.16c-8.8 0-16-7.168-16-16s7.2-16 16-16l256 0c8.864 0 16 7.168 16 16s-7.136 16-16 16l-256 0zM623.936 320.16c-8.8 0-16-7.168-16-16s7.2-16 16-16l256 0c8.864 0 16 7.168 16 16s-7.136 16-16 16l-256 0zM623.936 224.16c-8.8 0-16-7.168-16-16s7.2-16 16-16l256 0c8.864 0 16 7.168 16 16s-7.136 16-16 16l-256 0zM528 864.128c8.832 0 16 7.2 16 16 0 8.864-7.2 16-16 16l-256 0c-8.832 0-16-7.136-16-16 0-8.8 7.168-16 16-16l256 0zM528 768.128c8.832 0 16 7.2 16 16 0 8.864-7.2 16-16 16l-256 0c-8.832 0-16-7.136-16-16 0-8.8 7.168-16 16-16l256 0zM528 672.128c8.832 0 16 7.2 16 16 0 8.864-7.2 16-16 16l-256 0c-8.832 0-16-7.136-16-16 0-8.8 7.168-16 16-16l256 0zM880 864.128c8.8 0 16 7.2 16 16 0 8.864-7.2 16-16 16l-256 0c-8.864 0-16-7.136-16-16 0-8.8 7.136-16 16-16l256 0zM880 768.128c8.8 0 16 7.2 16 16 0 8.864-7.2 16-16 16l-256 0c-8.864 0-16-7.136-16-16 0-8.8 7.136-16 16-16l256 0zM880 672.128c8.8 0 16 7.2 16 16 0 8.864-7.2 16-16 16l-256 0c-8.864 0-16-7.136-16-16 0-8.8 7.136-16 16-16l256 0zM880 480.128c8.8 0 16 7.168 16 16s-7.2 16-16 16l-608 0c-8.832 0-16-7.168-16-16s7.168-16 16-16l608 0zM880 576.128c8.8 0 16 7.2 16 16 0 8.864-7.2 16-16 16l-608 0c-8.832 0-16-7.136-16-16 0-8.8 7.168-16 16-16l608 0zM288 416l224 0c17.696 0 32-14.304 32-32l0-223.872c0-17.696-14.304-32-32-32l-224 0c-17.696 0-32 14.304-32 32l0 223.872c0 17.664 14.304 32 32 32zM320 192l160 0 0 160-160 0 0-160z"  p-id="4042"></path></svg>

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
assets/icons/svg/pdf.svg


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
assets/icons/svg/product.svg


+ 1 - 1
assets/icons/svg/search.svg

@@ -1 +1 @@
-<svg t="1683197709921" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2605" width="200" height="200"><path d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6c3.2 3.2 8.4 3.2 11.6 0l43.6-43.5c3.2-3.2 3.2-8.4 0-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z" fill="#333333" p-id="2606"></path></svg>
+<svg t="1683197709921" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2605" width="200" height="200"><path d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6c3.2 3.2 8.4 3.2 11.6 0l43.6-43.5c3.2-3.2 3.2-8.4 0-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"  p-id="2606"></path></svg>

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
assets/icons/svg/wechat.svg


BIN
assets/images/page-404.png


+ 18 - 7
components/layout/adminLayout.vue

@@ -16,8 +16,11 @@ export default {
       default: '35px'
     },
     bgColor: {default: '#fff'},
-    sideBarColor: {default: '#bebebe'},
-    headerBgColor: {default: '#086fb6'},
+    contentBgColor: {default: '#eeeeee'},
+    sideBarColor: {default: '#001529'},
+    sideTextColor: {default: '#fff'},
+    sideTextActiveColor: {default: '#ffffffa6'},
+    headerBgColor: {default: '#014175'},
     // 文本颜色, 主要文本颜色 次要文本颜色
     textColor: {default: '#333'},
     mainTextColor: {default: '#333'},
@@ -106,7 +109,10 @@ export default {
       --baseSideBarWidth: ${this.sideBarWidth};
       --sideBarHeight: ${this.sideBarHeight};
       --bg-color: ${this.bgColor};
+      --content-bg-color: ${this.contentBgColor};
       --sideBarBgColor: ${this.sideBarColor};
+      --sideTextColor: ${this.sideTextColor};
+      --sideTextActiveColor: ${this.sideTextActiveColor};
       --header-color: ${this.headerBgColor};
       --text-color: ${this.textColor};
       --main-text-color: ${this.mainTextColor};
@@ -206,7 +212,10 @@ export default {
   --sideBarHeight: v-bind(sideBarHeight);
   --baseSideBarWidth: v-bind(sideBarWidth);
   --bg-color: v-bind(bgColor);
+  --content-bg-color: v-bind(contentBgColor);
   --sideBarBgColor: v-bind(sideBarColor);
+  --side-text-color: v-bind(sideTextColor);
+  --side-text-active-color: v-bind(sideTextActiveColor);
   --header-color: v-bind(headerBgColor);
   --text-color: v-bind(textColor);
   --main-text-color: v-bind(mainTextColor);
@@ -269,12 +278,13 @@ export default {
 }
 .lay-sideBar{
   width: var(--sideBarWidth);
+  color: var(--side-text-color);
 }
 .lay-content{
   width: calc(100% - var(--sideBarWidth));
   height: 100%;
   overflow: auto;
-  background-color: #d5d5d5;
+  background-color: var(--content-bg-color);
 }
 .lay-sideBar-control{
   position: relative;
@@ -296,7 +306,7 @@ export default {
 .lay-sideBar-control:hover{
   border-color: #f0ad4e;
   background-color: #f0ad4e;
-  color: #fff;
+  color: var(--side-text-active-color);
 }
 
 .bar-menu-item{
@@ -326,7 +336,7 @@ export default {
   display: flex;
   justify-content: center;
   align-items: center;
-  color: var(--text-color);
+  color: var(--side-text-color);
   flex-shrink: 0;
 }
 .bar-menu-item .menu-title .icon *{
@@ -334,10 +344,11 @@ export default {
 }
 .bar-menu-item .menu-title .option{
   cursor: pointer;
-  color: var(--text-color);
+  color: var(--side-text-color);
+  font-size: 1.5rem;
 }
 .bar-menu-item .menu-title .option:hover{
-  color: var(--btn-text-color-hover);
+  color: var(--side-text-active-color);
 }
 .bar-menu-item .menu-title .text{
   width: calc(100% - var(--sideBarHeight) - var(--sideBarHeight));

+ 1 - 1
nuxt.config.js

@@ -188,7 +188,7 @@ export default {
     plugins: [
       "@plugins/svg-icon.js",
       { src: "@plugins/ckeditor.js", mode: "client" ,ssr: false},
-
+      { src: "@plugins/vue-directive.js", mode: "client" ,ssr: false},
       // {src: '~/plugins/vue-pdf.js', ssr: false}
     ],
     // api中间件

+ 38 - 0
pages/errorPage/page-404.vue

@@ -0,0 +1,38 @@
+<template>
+  <div class="page-404 fvc">
+    <div>
+      <h4 class="title">当前页面不存在</h4>
+      <router-link class="goback" to="/">返回首页</router-link>
+    </div>
+  </div>
+</template>
+<script lang="ts">
+import { defineComponent } from "vue";
+
+export default defineComponent({
+  name: "page-404",
+})
+</script>
+<style >
+.page-404 {
+  width: 100%;
+  height: 100%;
+  background-image: url("../../assets/images/page-404.png");
+  background-size: cover;
+  background-position: center center;
+  text-align: center;
+  color: #fff;
+
+}
+.title {
+  font-size: 48px;
+  font-weight: normal;
+  margin-bottom: 16px;
+  letter-spacing: 4px;
+  line-height: 1;
+}
+.goback {
+  font-size: 16px;
+  text-decoration: underline;
+}
+</style>

+ 17 - 6
pages/manger/news/index.vue

@@ -9,22 +9,23 @@ import {isEmpty} from "../../../until/typeTool";
 import TableSelect from "../../../components/public/tableSelect.vue";
 import dbField_esm from "../../../map/dbField_esm";
 import ImageViewer from "../../../components/public/imageViewer.vue";
+import {timestampToTime} from "../../../until/time";
 
 const newsColumns = [
   {
     title: "ID",
     dataIndex: 'id',
-    width: '5%',
+    width: '3%',
   },
   {
     title: "文章标题",
     dataIndex: 'title',
-    width: '20%',
+    width: '15%',
   },
   {
     title: "文章类型",
     dataIndex: 'type_key',
-    width: '20%',
+    width: '5%',
     scopedSlots: {customRender: 'newsType'},
   },
   {
@@ -38,9 +39,15 @@ const newsColumns = [
     dataIndex: 'source',
     width: '10%',
   },
+  {
+    title: "阅读量",
+    dataIndex: 'hits',
+    width: '5%',
+  },
   {
     title: "创建时间",
-    dataIndex: 'source',
+    dataIndex: 'date_time',
+    scopedSlots: {customRender: 'time'},
     width: '10%',
   },
   {
@@ -144,6 +151,7 @@ export default {
     this.form.type.init = this.form.type.val;
   },
   methods: {
+    timestampToTime,
     copy(str){
       copy(str).then(()=>{
         this.$message.success('已经将内容复制到剪切板')
@@ -317,13 +325,16 @@ export default {
               <svg-icon :name="'copy'" :icon-class="'copy'" class="text-2xl cursor-pointer mx-2" title="点击复制" @click.native="copy(text)" />
             </div>
           </template>
+          <template slot="time" slot-scope="text">
+            <span>{{timestampToTime(text)}}</span>
+          </template>
           <template class="flex justify-center" slot="operation" slot-scope="text,record">
             <a-button  type="primary">
-              <a :href="`/manger/product/info?id=${record.id}`">文章详情</a>
+              <a :href="`/manger/news/info?id=${record.id}`">文章详情</a>
             </a-button>
 
             <a-button class="mx-3" type="primary">
-              <a :href="`/manger/product/edit?id=${record.id}`">编辑文章</a>
+              <a :href="`/manger/news/edit?id=${record.id}`">编辑文章</a>
             </a-button>
 
           </template>

+ 90 - 2
pages/manger/news/info.vue

@@ -1,18 +1,106 @@
 <script>
+import RoundedTitle from "@/components/public/roundedTitle.vue";
+import {getQueryString} from "@/until/domTool";
+import {apiMap} from "@/map/apiMap";
+import {rCode} from "@/map/rcodeMap_esm";
+import {handle} from "@/until/handle";
+import {unescapeHtml} from "@/until/unescapeHtml";
+import {timestampToTime} from "@/until/time";
+
 export default {
   name: "newsInfo",
+  components: {RoundedTitle},
+
   data(){
-    return {}
+    return {
+      loading: false,
+      newsInfo: {},
+
+    }
+  },
+  beforeMount() {
+    // 获取路径中的id值
+    this.newsId = getQueryString('id');
+    if( !this.newsId ){
+      this.$message.error('未获取到文章id');
+      window.location.href = "/manger/news";
+      return ;
+    }
+    console.log(this.newsId);
+    this.loadNewsInfo();
+
+  },
+  methods: {
+    async loadNewsInfo(){
+        let newsId = this.newsId;
+        if( !newsId ){
+          this.$message.error('未获取到文章id');
+          return;
+        }
+        this.loading = true;
+        let [err,res] = await handle(this.$axios.get(`${apiMap.newsInfo.path}/${newsId}`));
+        this.loading = false;
+        if(err){
+          this.$message.error('获取文章信息失败');
+          return console.log(err);
+        }
+      let  result = res.data;
+      if (result.code === rCode.OK){
+        this.$message.success('');
+        let pageData = result.data;
+        pageData.htmlContent = unescapeHtml(pageData.content);
+        pageData.createTime = timestampToTime(pageData.date_time);
+        //
+        this.newsInfo = result.data;
+        console.log(this.newsInfo);
+      }else{
+        this.$message.error(`获取文章信息失败,${result.msg}`);
+      }
+    }
   }
 }
 </script>
 
 <template>
-  <div class="w-full">
+  <div class="w-full p-2">
+    <rounded-title class="text-xl">
+      <span>文章详情</span>
+      <a href="/manger/news"
+         class="px-10 h-full ml-5 rounded bg-blue-400 text-white cursor-pointer
+        hover:text-orange-500 ">文章中心</a>
+    </rounded-title>
+    <div class="page-content-box w-full mt-2 p-0.5  rounded bg-white">
+      <div class="page-title">{{newsInfo.title}}</div>
+      <div class="w-full mt-2">
+        <div class="w-full">
+          <div class="w-full flex justify-between">
+            <div class="w-1/2">
+              <span>作者:</span>
+              <span>{{newsInfo.author}}</span>
+
+            </div>
+            <div class="w-1/2">
+              <span>发布时间:</span>
+              <span>{{newsInfo.createTime}}</span>
+            </div>
+          </div>
+        </div>
 
+      </div>
+      <div class="w-full mt-2">
+        <div class="w-full">
+          <div class="w-full mt-2 border border-gray-400 rounded p-0.5" v-html="newsInfo.htmlContent">
+          </div>
+        </div>
+      </div>
+    </div>
   </div>
 </template>
 
 <style scoped>
+.page-title{
+  font-size: 1.5rem;
+  font-weight: bold;
 
+}
 </style>

+ 6 - 6
pages/manger/product/index.vue

@@ -25,7 +25,7 @@ const productColumns = [
     title: '产品类型',
     dataIndex: 'type_key',
     width: '20%',
-    scopedSlots: {customRender: 'peoType'},
+    scopedSlots: {customRender: 'proType'},
   },
   {
     title: '产品图片',
@@ -217,8 +217,7 @@ export default {
                           @search="onSearchHandle"
                           :loading="loading" v-model="form.key.val" />
         </div>
-
-
+        <span v-copy="'text'">测试</span>
         <div class="flex">
           <a-button class="ml-2" type="primary" @click="refreshHandel" :loading="loading">刷新</a-button>
         </div>
@@ -232,18 +231,19 @@ export default {
           :pagination="false"
           :data-source="productionList"
         >
+
           <template slot="proType" slot-scope="text">
-            <span>{{getProTypeText(text)}}</span>
+            <span  v-copy="getProTypeText(text)">{{getProTypeText(text)}}</span>
           </template>
 
           <template slot="image" slot-scope="text,record">
-            <image-viewer :src="text" :alt="record.name" />
+            <image-viewer :src="text?text.charAt(0) == '/'? text : '/public/'+text : '' " :alt="record.name" />
           </template>
 
           <template slot="keyLight" class="flex" slot-scope="text">
             <div class="w-full flex items-center">
               <div  v-html="keyLight(text)"></div>
-              <svg-icon :name="'copy'" :icon-class="'copy'" class="text-2xl cursor-pointer mx-2" title="点击复制" @click.native="copy(text)" />
+              <svg-icon :name="'copy'" :icon-class="'copy'" class="text-2xl cursor-pointer mx-2" v-copy="text" title="点击复制" />
             </div>
           </template>
           <template class="flex justify-center" slot="operation" slot-scope="text,record">

+ 31 - 0
plugins/vue-directive.js

@@ -0,0 +1,31 @@
+
+"use strict";
+import Vue from 'vue'
+import ripple from '../until/ripple.js'
+import {message} from '../until/message.js'
+import {copyText, isMobile} from "../until";
+
+function copyBind(el, binding) {
+  el.addEventListener("click", function () {
+    copyText(binding.value, () => message.success("复制成功"), tip => message.success(tip));
+  });
+}
+// 添加一个自定义指令`v-copy`点击复制内容
+Vue.directive("copy", {
+  inserted: copyBind,
+});
+
+Vue.directive("ripple", {
+  inserted(el) {
+    /** 添加事件类型 */
+    const eventType = isMobile() ? "touchstart" : "mousedown";
+    el.setAttribute("ripple", "");
+    el.addEventListener(eventType, function (e) {
+      ripple(e, el);
+    });
+  }
+});
+
+
+
+

+ 1 - 1
server/control/c_solution.js

@@ -80,7 +80,7 @@ async function searchSolution(type, key, p, l)
     });
 }
 
-async function searchNews(type, key, sortKey, sortType, p, l)
+async function searchNews(type, key, sortKey = '', sortType = '', p, l)
 {
   p = p || 1;
   l = l || 10;

+ 2 - 2
server/router/r_news.js

@@ -11,12 +11,12 @@ router.get(
   async (req, res) => {
     try{
       let err, result;
-      let {key, l, p, type} = req.query;
+      let {key, l, p, type, s,st } = req.query;
       type = type || 'all';
       l = typeTool.toNumber(l);
       p = typeTool.toNumber(p);
       log.info(`page=${p},limit=${l}`);
-      [err, result] = await c_solution.searchNews(type, key, p, l);
+      [err, result] = await c_solution.searchNews(type, key, s, st, p, l);
       if(err){
         return controlError(res, err, null);}
       log.info(`result len=${result.arr.length}`)

+ 21 - 1
until/domTool.js

@@ -78,4 +78,24 @@ function comDomStyle(el,lineNum,gap){
     }
 }
 
-export default {comDomHeight,launchIntoFullscreen,exitFullscreen,isFullscreenEnabled,comDomStyle}
+/**
+ * 获取url参数
+ * @param name
+ * @returns {string}
+ */
+export function getQueryString(name) {
+    let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
+    // console.log(window.location.search);
+    let r = window.location.search.substr(1).match(reg);
+    if (r != null) return decodeURI(r[2]);
+    return '';
+}
+
+export default {
+  comDomHeight,
+  launchIntoFullscreen,
+  exitFullscreen,
+  isFullscreenEnabled,
+  comDomStyle,
+  getQueryString
+}

+ 213 - 0
until/index.js

@@ -0,0 +1,213 @@
+/**
+ * 检测类型
+ * @param target 检测的目标
+ */
+export function checkType(target) {
+  const value = Object.prototype.toString.call(target);
+  const result = value.match(/\[object (\S*)\]/)[1];
+  return result.toLocaleLowerCase();
+}
+/**
+ * 判断任意值的类型,作用与`checkType`一致,外加一个辅助功能:当函数返回值为`true`时,可以传入泛型来确定`target`的类型(类型收窄)
+ * @param target 判断目标
+ * @param type 判断的类型
+ */
+export function isType(target, type) {
+  return checkType(target) === type;
+}
+/**
+ * 修改属性值-只修改之前存在的值
+ * @param target 修改的目标
+ * @param value 修改的内容
+ */
+export function modifyData(target, value) {
+  for (const key in value) {
+    if (Object.prototype.hasOwnProperty.call(target, key)) {
+      const item = value[key];
+      const _target = target[key];
+      // 深层逐个赋值
+      if (isType(_target, "object")) {
+        modifyData(_target, item);
+      }
+      else {
+        target[key] = item;
+      }
+    }
+  }
+}
+/**
+ * 设置属性值-之前不存在的值也根据传入的`value`值去设置
+ * @param target 设置的目标
+ * @param value 设置的内容
+ */
+export function setData(target, value) {
+  for (const key in value) {
+    target[key] = value[key];
+  }
+}
+/**
+ * 格式化日期
+ * @param value 指定日期
+ * @param format 格式化的规则
+ * @example
+ * ```js
+ * formatDate();
+ * formatDate(1603264465956);
+ * formatDate(1603264465956, "h:m:s");
+ * formatDate(1603264465956, "Y年M月D日");
+ * ```
+ */
+export function formatDate(value = Date.now(), format = "Y-M-D h:m:s") {
+  if (["null", null, "undefined", undefined, ""].includes(value))
+    return "";
+  // ios 和 mac 系统中,带横杆的字符串日期是格式不了的,这里做一下判断处理
+  if (typeof value === "string" && new Date(value).toString() === "Invalid Date") {
+    value = value.replace(/-/g, "/");
+  }
+  const formatNumber = (n) => `0${n}`.slice(-2);
+  const date = new Date(value);
+  const formatList = ["Y", "M", "D", "h", "m", "s"];
+  const resultList = [];
+  resultList.push(date.getFullYear().toString());
+  resultList.push(formatNumber(date.getMonth() + 1));
+  resultList.push(formatNumber(date.getDate()));
+  resultList.push(formatNumber(date.getHours()));
+  resultList.push(formatNumber(date.getMinutes()));
+  resultList.push(formatNumber(date.getSeconds()));
+  for (let i = 0; i < resultList.length; i++) {
+    format = format.replace(formatList[i], resultList[i]);
+  }
+  return format;
+}
+/**
+ * 点击复制
+ * @param text 复制的内容
+ * @param success 成功回调
+ * @param fail 出错回调
+ */
+export function copyText(text, success, fail) {
+  text = text.replace(/(^\s*)|(\s*$)/g, "");
+  if (!text) {
+    fail && fail("复制的内容不能为空!");
+    return;
+  }
+  const id = "the-clipboard";
+  let clipboard = document.getElementById(id);
+  if (!clipboard) {
+    clipboard = document.createElement("textarea");
+    clipboard.id = id;
+    clipboard.readOnly = true;
+    clipboard.style.cssText = "font-size: 15px; position: fixed; top: -1000%; left: -1000%;";
+    document.body.appendChild(clipboard);
+  }
+  clipboard.value = text;
+  clipboard.select();
+  clipboard.setSelectionRange(0, clipboard.value.length);
+  const state = document.execCommand("copy");
+  if (state) {
+    success && success();
+  }
+  else {
+    fail && fail("复制失败");
+  }
+}
+/**
+ * 输入只能是数字
+ * @param value
+ * @param decimal 是否要保留小数
+ * @param negative 是否可以为负数
+ */
+export function inputOnlyNumber(value, decimal, negative) {
+  let result = value.toString().trim();
+  if (result.length === 0)
+    return "";
+  const minus = (negative && result[0] == "-") ? "-" : "";
+  if (decimal) {
+    result = result.replace(/[^0-9.]+/ig, "");
+    let array = result.split(".");
+    if (array.length > 1) {
+      result = array[0] + "." + array[1];
+    }
+  }
+  else {
+    result = result.replace(/[^0-9]+/ig, "");
+  }
+  return minus + result;
+}
+/**
+ * ES5 兼容 ES6 `Array.findIndex`
+ * @param array
+ * @param compare 对比函数
+ */
+export function findIndex(array, compare) {
+  var result = -1;
+  for (var i = 0; i < array.length; i++) {
+    if (compare(array[i], i)) {
+      result = i;
+      break;
+    }
+  }
+  return result;
+}
+/**
+ * 自定义对象数组去重
+ * @param array
+ * @param compare 对比函数
+ * @example
+ * ```js
+ * const list = [{ id: 10, code: "abc" }, {id: 12, code: "abc"}, {id: 12, code: "abc"}];
+ * filterRepeat(list, (a, b) => a.id == b.id)
+ * ```
+ */
+export function filterRepeat(array, compare) {
+  return array.filter((element, index, self) => {
+    return findIndex(self, el => compare(el, element)) === index;
+  });
+}
+/**
+ * 判断是否外部链接
+ * @param path 路径
+ */
+export function isExternal(path) {
+  return /^(https?:|mailto:|tel:)/.test(path);
+}
+/**
+ * `JSON`转`FormData`
+ * @param params `JSON`对象
+ * @example
+ * ```js
+ * const info = { name: "hjs", id: 123 };
+ * const val = jsonToFormData(info);
+ * console.log(val); // "name=hjs&id=123"
+ * ```
+ */
+export function jsonToFormData(params) {
+  let result = "";
+  for (const key in params) {
+    result += `&${key}=${params[key]}`;
+  }
+  return result.slice(1);
+}
+/**
+ * `JSON`格式化对象,内置错误捕捉处理,错误时返回默认值
+ * - 默认返回空对象: `{}`
+ * @param target 要格式化的目标对象
+ * @param defaultValue 默认返回值
+ */
+export function jsonParse(target, defaultValue = {}) {
+  let result = defaultValue;
+  if (isType(target, "string")) {
+    try {
+      result = JSON.parse(target);
+    }
+    catch (error) {
+      console.warn("JSON格式化对象错误 >>", error);
+    }
+  }
+  return result;
+}
+/** 检查是否移动端 */
+export function isMobile() {
+  const pattern = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|OperaMini/i;
+  return pattern.test(navigator.userAgent);
+}

+ 387 - 0
until/message.js

@@ -0,0 +1,387 @@
+import { usezIndex } from "./vue/hooks";
+/**
+ * 消息提醒功能
+ * @param params
+ */
+function useMessage(params = {}) {
+  const doc = document;
+  const cssModule = `__${Math.random().toString(36).slice(2, 7)}`;
+  const className = {
+    box: `msg-box${cssModule}`,
+    hide: `hide${cssModule}`,
+    text: `msg-text${cssModule}`,
+    icon: `msg-icon${cssModule}`
+  };
+  const style = doc.createElement("style");
+  style.textContent = `
+  .${className.box}, .${className.icon}, .${className.text} {
+    padding: 0;
+    margin: 0;
+    box-sizing: border-box;
+  }
+  .${className.box} {
+    position: fixed;
+    top: 0;
+    left: 50%;
+    display: flex;
+    padding: 12px 16px;
+    border-radius: 2px;
+    background-color: #fff;
+    box-shadow: 0 3px 3px -2px rgba(0,0,0,.2),0 3px 4px 0 rgba(0,0,0,.14),0 1px 8px 0 rgba(0,0,0,.12);
+    white-space: nowrap;
+    animation: ${className.box}-move .4s;
+    transition: .4s all;
+    transform: translate3d(-50%, 0%, 0);
+    opacity: 1;
+    overflow: hidden;
+  }
+  .${className.box}::after {
+    content: "";
+    position: absolute;
+    left: 0;
+    top: 0;
+    height: 100%;
+    width: 4px;
+  }
+  @keyframes ${className.box}-move {
+    0% {
+      opacity: 0;
+      transform: translate3d(-50%, -100%, 0);
+    }
+    100% {
+      opacity: 1;
+      transform: translate3d(-50%, 0%, 0);
+    }
+  }
+  .${className.box}.${className.hide} {
+    opacity: 0;
+    /* transform: translate3d(-50%, -100%, 0); */
+    transform: translate3d(-50%, -100%, 0) scale(0);
+  }
+  .${className.icon} {
+    display: inline-block;
+    width: 18px;
+    height: 18px;
+    border-radius: 50%;
+    overflow: hidden;
+    margin-right: 6px;
+    position: relative;
+  }
+  .${className.text} {
+    font-size: 14px;
+    line-height: 18px;
+    color: #555;
+  }
+  .${className.icon}::after,
+  .${className.icon}::before {
+    position: absolute;
+    content: "";
+    background-color: #fff;
+  }
+  .${className.box}.info .${className.icon}, .${className.box}.info::after {
+    background-color: #1890ff;
+  }
+  .${className.box}.success .${className.icon}, .${className.box}.success::after {
+    background-color: #52c41a;
+  }
+  .${className.box}.warning .${className.icon}, .${className.box}.warning::after {
+    background-color: #faad14;
+  }
+  .${className.box}.error .${className.icon}, .${className.box}.error::after {
+    background-color: #ff4d4f;
+  }
+  .${className.box}.info .${className.icon}::after,
+  .${className.box}.warning .${className.icon}::after {
+    top: 15%;
+    left: 50%;
+    margin-left: -1px;
+    width: 2px;
+    height: 2px;
+    border-radius: 50%;
+  }
+  .${className.box}.info .${className.icon}::before,
+  .${className.box}.warning .${className.icon}::before {
+    top: calc(15% + 4px);
+    left: 50%;
+    margin-left: -1px;
+    width: 2px;
+    height: 40%;
+  }
+  .${className.box}.error .${className.icon}::after,
+  .${className.box}.error .${className.icon}::before {
+    top: 20%;
+    left: 50%;
+    width: 2px;
+    height: 60%;
+    margin-left: -1px;
+    border-radius: 1px;
+  }
+  .${className.box}.error .${className.icon}::after {
+    transform: rotate(-45deg);
+  }
+  .${className.box}.error .${className.icon}::before {
+    transform: rotate(45deg);
+  }
+  .${className.box}.success .${className.icon}::after {
+    box-sizing: content-box;
+    background-color: transparent;
+    border: 2px solid #fff;
+    border-left: 0;
+    border-top: 0;
+    height: 50%;
+    left: 35%;
+    top: 13%;
+    transform: rotate(45deg);
+    width: 20%;
+    transform-origin: center;
+  }
+  `.replace(/(\n|\t|\s)*/ig, "$1").replace(/\n|\t|\s(\{|\}|\,|\:|\;)/ig, "$1").replace(/(\{|\}|\,|\:|\;)\s/ig, "$1");
+  doc.head.appendChild(style);
+  /** 消息队列 */
+  const messageList = [];
+  /**
+   * 获取指定`item`的定位`top`
+   * @param el
+   */
+  function getItemTop(el) {
+    let top = 10;
+    for (let i = 0; i < messageList.length; i++) {
+      const item = messageList[i];
+      if (el && el === item) {
+        break;
+      }
+      top += item.clientHeight + 20;
+    }
+    return top;
+  }
+  /**
+   * 删除指定列表项
+   * @param el
+   */
+  function removeItem(el) {
+    for (let i = 0; i < messageList.length; i++) {
+      const item = messageList[i];
+      if (item === el) {
+        messageList.splice(i, 1);
+        break;
+      }
+    }
+    el.classList.add(className.hide);
+    messageList.forEach(function (item) {
+      item.style.top = `${getItemTop(item)}px`;
+    });
+  }
+  /**
+   * 显示一条消息
+   * @param content 内容
+   * @param type 消息类型
+   * @param duration 持续时间,优先级比默认值高
+   */
+  function show(content, type = "info", duration) {
+    const el = doc.createElement("div");
+    el.className = `${className.box} ${type}`;
+    el.style.top = `${getItemTop()}px`;
+    el.style.zIndex = zIndex.message;
+    el.innerHTML = `
+    <span class="${className.icon}"></span>
+    <span class="${className.text}">${content}</span>
+    `;
+    messageList.push(el);
+    doc.body.appendChild(el);
+    // 添加动画监听事件
+    function animationEnd() {
+      el.removeEventListener("animationend", animationEnd);
+      setTimeout(removeItem, duration || params.duration || 3000, el);
+    }
+    el.addEventListener("animationend", animationEnd);
+    function transitionEnd() {
+      if (getComputedStyle(el).opacity !== "0")
+        return;
+      el.removeEventListener("transitionend", transitionEnd);
+      el.remove();
+    }
+    el.addEventListener("transitionend", transitionEnd);
+  }
+  return {
+    show,
+    /** 普通描述提示 */
+    info(msg) {
+      show(msg, "info");
+    },
+    /** 成功提示 */
+    success(msg) {
+      show(msg, "success");
+    },
+    /** 警告提示 */
+    warning(msg) {
+      show(msg, "warning");
+    },
+    /** 错误提示 */
+    error(msg) {
+      show(msg, "error");
+    }
+  };
+}
+/** 对话框控件 */
+function useDialog() {
+  const doc = document;
+  const cssModule = `__${Math.random().toString(36).slice(2, 7)}`;
+  const className = {
+    mask: `dialog-mask${cssModule}`,
+    popup: `dialog-popup${cssModule}`,
+    title: `dialog-title${cssModule}`,
+    content: `dialog-content${cssModule}`,
+    footer: `dialog-footer${cssModule}`,
+    confirm: `confirm${cssModule}`,
+    fade: `fade${cssModule}`,
+    show: `show${cssModule}`,
+    hide: `hide${cssModule}`
+  };
+  const cssText = `
+  .${className.mask} {
+    --time: .3s;
+    --transition: .3s all;
+    --black: #333;
+    --text-color: #555;
+    --confirm-bg: #2ec1cb;
+    position: fixed;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    background-color: rgba(0,0,0,0.45);
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    transition: var(--transition);
+    animation: ${className.fade} var(--time);
+  }
+  .${className.mask} * {
+    margin: 0;
+    padding: 0;
+    box-sizing: border-box;
+  }
+  .${className.popup} {
+    width: 74%;
+    max-width: 375px;
+    border-radius: var(--border-radius);
+    box-shadow: 0px 1px 5px 0px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 3px 1px -2px rgba(0, 0, 0, 0.12);
+    background-color: #fff;
+    transition: var(--transition);
+    animation: ${className.show} var(--time);
+  }
+  .${className.title} {
+    font-size: 18px;
+    padding: 12px 15px;
+    border-bottom: solid 1px #eee;
+    font-weight: normal;
+    color: var(--black);
+    text-align: left;
+  }
+  .${className.content} {
+    padding: 16px 15px;
+    font-size: 15px;
+    color: var(--text-color);
+    text-align: left;
+  }
+  .${className.footer} {
+    width: 100%;
+    text-align: right;
+    border-top: solid 1px #eee;
+    padding: 12px 15px;
+  }
+  @keyframes ${className.fade} {
+    0% { opacity: 0; }
+    100% { opacity: 1; }
+  }
+  @keyframes ${className.show} {
+    0% { transform: translate3d(var(--x), var(--y), 0) scale(0); }
+    100% { transform: translate3d(0, 0, 0) scale(1); }
+  }
+  .${className.mask}.${className.hide} {
+    opacity: 0;
+  }
+  .${className.mask}.${className.hide} .${className.popup} {
+    transform: translate3d(var(--x), var(--y), 0) scale(0);
+  }
+  `;
+  const style = doc.createElement("style");
+  style.textContent = cssText.replace(/(\n|\t|\s)*/ig, "$1").replace(/\n|\t|\s(\{|\}|\,|\:|\;)/ig, "$1").replace(/(\{|\}|\,|\:|\;)\s/ig, "$1");
+  doc.head.appendChild(style);
+  /** 点击记录坐标 */
+  const clickSize = {
+    x: "0vw",
+    y: "0vh"
+  };
+  // 添加点击事件,并记录每次点击坐标
+  doc.addEventListener("click", function (e) {
+    const { innerWidth, innerHeight } = window;
+    const centerX = innerWidth / 2;
+    const centerY = innerHeight / 2;
+    const pageY = e.clientY - centerY;
+    const pageX = e.clientX - centerX;
+    clickSize.x = `${pageX / innerWidth * 100}vw`;
+    clickSize.y = `${pageY / innerHeight * 100}vh`;
+  }, true);
+  /**
+   * 输出节点
+   * @param option
+   */
+  function show(option) {
+    const el = doc.createElement("section");
+    el.className = className.mask;
+    el.style.zIndex = zIndex.dialog;
+    // 设置起始偏移位置
+    el.style.setProperty("--x", clickSize.x);
+    el.style.setProperty("--y", clickSize.y);
+    // 设置完之后还原坐标位置
+    clickSize.x = "0vw";
+    clickSize.y = "0vh";
+    const cancelBtn = option.cancelText ? `<button class="the-btn">${option.cancelText}</button>` : "";
+    el.innerHTML = `
+    <div class="${className.popup}">
+      <h2 class="${className.title}">${typeof option.title === "string" ? option.title : "提示"}</h2>
+      <div class="${className.content}">${option.content}</div>
+      <div class="${className.footer}">
+        ${cancelBtn}
+        <button class="${className.confirm} the-btn blue">${option.confirmText || "确认"}</button>
+      </div>
+    </div>
+    `;
+    doc.body.appendChild(el);
+    el.addEventListener("transitionend", function (e) {
+      e.target === el && el.classList.contains(className.hide) && el.remove();
+    });
+    function hide() {
+      el.classList.add(className.hide);
+    }
+    if (option.cancelText) {
+      el.querySelector(`.${className.footer} button`).onclick = function () {
+        hide();
+        option.cancel && option.cancel();
+      };
+    }
+    el.querySelector(`.${className.confirm}`).onclick = function () {
+      hide();
+      option.confirm && option.confirm();
+    };
+  }
+  return {
+    show
+  };
+}
+const zIndex = {
+  get message() {
+    return (usezIndex() + 20).toString();
+  },
+  get dialog() {
+    return (usezIndex() + 10).toString();
+  }
+};
+/** 顶部消息提醒控件 */
+export const message = useMessage({
+  duration: 3600
+});
+const dialog = useDialog();
+/** 对话弹框控件 */
+export const messageBox = dialog.show;

+ 54 - 0
until/ripple.js

@@ -0,0 +1,54 @@
+/**
+ * 水波纹节点对象池
+ */
+const ripplePool = [];
+/**
+ * 点击水波纹
+ * [参考](https://juejin.cn/post/7047782205002612773)
+ * @param event 点击事件
+ * @param target 点击目标
+ */
+export default function ripple(event, target) {
+  /**
+   * 水波纹动画节点
+   */
+  let node;
+  // 从对象池里面拿取节点
+  if (ripplePool.length > 1) {
+    node = ripplePool.shift();
+  }
+  else {
+    node = document.createElement("div");
+    node.className = "ripple";
+  }
+  /** 点击目标矩阵尺寸 */
+  const rect = target.getBoundingClientRect();
+  /** 当前自定义颜色值 */
+  const color = target.getAttribute("color");
+  /** 波纹大小 */
+  let size = Math.max(rect.width, rect.height);
+  // 设置最大范围
+  if (size > 200)
+    size = 200;
+  // 设置大小
+  node.style.height = node.style.width = size + "px";
+  // 默认是白色透明
+  node.style.backgroundColor = color || "rgba(255, 255, 255, .45)";
+  // 这里必须输出节点后再设置位置,不然会有问题
+  target.appendChild(node);
+  const touches = event.touches;
+  const y = touches ? touches[0].clientY : event.clientY;
+  const x = touches ? touches[0].clientX : event.clientX;
+  const top = y - rect.top - (node.offsetHeight / 2);
+  const left = x - rect.left - (node.offsetWidth / 2);
+  // console.log(top, left);
+  node.style.top = top + "px";
+  node.style.left = left + "px";
+  function end() {
+    node.removeEventListener("animationend", end);
+    // console.log("动画结束", node);
+    target.removeChild(node);
+    ripplePool.push(node);
+  }
+  node.addEventListener("animationend", end);
+}

+ 52 - 0
until/vue/hooks.js

@@ -0,0 +1,52 @@
+
+let zIndex = 1000;
+
+
+/**
+ * 各个弹层组件应用的定位层级
+ * - 该方法调用一次之后,就会累加一次层级
+ * - 保证所有弹层按照书写顺序去排列定位层级
+ */
+export function usezIndex() {
+  const val = zIndex;
+  zIndex++;
+  return val;
+}
+
+// 声明
+// data 为数据
+// delay 为时间。delay = null 则直接不使用 防抖 方案
+function debounceRef (data, delay = 300) {
+  // 定时器
+  let timer = null
+  // 数据
+  const value = {value: data}
+  // 创建 proxy 实例
+  const proxy = new Proxy(value, {
+    get(target, property) {
+      // 返回当前值
+      return target[property]
+    },
+    // set 参数说明
+    // target:目标, property:属性, newValue 值, receiver:接收者
+    set(target, property, newValue, receiver) {
+      // 定时器判断,如果存在则清除当前定时器
+      if(timer != null){
+        // 清除定时器
+        clearTimeout(timer)
+        // 将 timer 恢复默认值
+        timer = null
+      }
+      // 赋值并创建定时器
+      timer = setTimeout(() => {
+        // 修改值
+        target[property] = newValue
+      }, delay)
+      // 让 set 一直返回 true
+      // 不返回 true,则会报下列错误: 'set' on proxy: trap returned falsish for property 'value'
+      return true;
+    }
+  })
+  // 判断 delay === null,等于则返回未代理的对象,反之
+  return delay === null ?value : proxy
+}

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott