调整部分前端布局和后端增删改逻辑
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询首页扫码异常
|
||||
export function listScanExceptions() {
|
||||
return request({
|
||||
url: '/business/dashboard/scan-exceptions',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="_图层_2" data-name="图层 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 516.1 194.52">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: #008596;
|
||||
}
|
||||
|
||||
.cls-2 {
|
||||
fill: #1a2736;
|
||||
}
|
||||
|
||||
.cls-sub {
|
||||
fill: #008596;
|
||||
}
|
||||
|
||||
.cls-3 {
|
||||
fill: #91cdb9;
|
||||
}
|
||||
|
||||
.cls-4 {
|
||||
fill: #43b69e;
|
||||
}
|
||||
|
||||
.cls-5 {
|
||||
fill: #554d8a;
|
||||
}
|
||||
|
||||
.cls-6 {
|
||||
fill: #50bcba;
|
||||
}
|
||||
|
||||
.cls-7, .cls-8, .cls-9 {
|
||||
fill: #28225c;
|
||||
}
|
||||
|
||||
.cls-10 {
|
||||
fill: #009a91;
|
||||
opacity: .8;
|
||||
}
|
||||
|
||||
.cls-10, .cls-11 {
|
||||
fill-rule: evenodd;
|
||||
}
|
||||
|
||||
.cls-11 {
|
||||
fill: #a5d7d7;
|
||||
}
|
||||
|
||||
.cls-8 {
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.cls-9 {
|
||||
opacity: .25;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<g id="tekening">
|
||||
<g>
|
||||
<g>
|
||||
<path class="cls-2" d="M302.33,61.89l-18.13,63.56c-3.35,11.65-7.77,17.59-23.63,17.59-3.99,0-10.36-.86-13.06-1.73-1.19-.43-2.27-.76-2.27-1.94v-8.74c0-1.19,.97-2.05,2.16-2.05h.22c3.56,.21,9.93,.86,13.49,.86,3.88,0,5.83-1.29,7.12-5.61l.97-3.35h-1.62c-3.99,0-7.34-.65-10.04-10.04l-14.24-48.56c-.11-.32-.11-.54-.11-.76,0-1.08,.65-1.73,2.16-1.73h14.35c1.08,0,1.83,.97,2.05,2.05l9.71,40.58c.32,1.51,.65,2.05,1.29,2.05h.97l10.04-42.63c.21-1.08,1.08-2.05,2.27-2.05h14.35c1.08,0,2.05,.86,2.05,1.94,0,.22-.11,.33-.11,.54Z"/>
|
||||
<path class="cls-2" d="M326.72,121.44h-13.17c-1.19,0-2.27-1.08-2.27-2.27V40.83c0-1.19,1.08-2.16,2.27-2.16h13.17c1.19,0,2.05,.97,2.05,2.16V119.17c0,1.19-.86,2.27-2.05,2.27Z"/>
|
||||
<path class="cls-2" d="M396,61.89l-13.6,48.99c-2.7,9.6-9.28,11.33-15.65,11.33s-12.84-1.73-15.54-11.33l-13.49-48.99c-.11-.21-.11-.43-.11-.65,0-1.08,.76-1.84,1.73-1.84h14.24c1.08,0,1.94,.97,2.27,2.27l9.28,42.3c.33,1.62,.86,2.27,1.62,2.27s1.4-.65,1.73-2.27l9.28-42.3c.32-1.3,1.19-2.27,2.27-2.27h14.24c.97,0,1.84,.76,1.84,1.84,0,.21,0,.43-.11,.65Z"/>
|
||||
<path class="cls-2" d="M418.66,121.3c-9.39,0-18.45-4.53-18.45-18.56v-.97c0-12.63,8.09-18.24,26.55-18.24h5.83v-3.89c0-6.15-6.78-7.47-11.85-7.47,0,0-17.96,1.95-17.96-12.69,0,0,16.18-.15,23.3-.15,15.54,0,23.99,4.55,23.99,20.31v39.49c0,1.19-.97,2.16-2.16,2.16h-29.24Zm13.89-27.41h-6.15c-7.56,0-9.5,2.59-9.5,7.88v.97c0,4.53,2.27,5.39,6.8,5.39,3.24,0,8.68,0,8.68,0l.17-14.25Z"/>
|
||||
<path class="cls-2" d="M497.01,58.61c15.65,0,19.1,10.9,19.1,24.5v35.93c0,1.19-1.08,2.27-2.27,2.27h-13.06c-1.19,0-2.16-1.08-2.16-2.27v-35.93c-.1-6.03,.45-8.65-6.13-8.65-3.22,0-8.33,.12-11.99,2.06v42.52c0,1.19-.97,2.27-2.16,2.27h-13.06c-1.19,0-2.27-1.08-2.27-2.27V61.63c0-1.19,.97-2.16,2.16-2.16l31.83-.86Z"/>
|
||||
<path class="cls-2" d="M184.25,121.47c0-17.9,16.39-18.14,16.39-18.14,8.24,0,17.54-.5,17.98-6.18,.24-3.16-.41-4.44-6.02-7.82l-15.23-8.96c-10.04-6.01-12.73-12.89-12.73-20.87,0-12.02,6.69-21.3,27.63-21.3,1.66,0,23.24,.05,23.26,.07-.13,.14,.12,2.04,.12,3.24,0,14.93-20.16,13.71-20.16,13.71-6.15,0-9.85,2.38-9.85,6.31,0,3.06,1.26,4.7,7.09,7.87l13.81,6.38c11.22,6.12,12.5,12.79,12.5,21.64,0,11.58-6.73,24.27-24.96,24.11l-29.81-.05Z"/>
|
||||
<g>
|
||||
<path class="cls-sub" d="M365.04,163.65h-1.67c-.32,0-.58-.29-.58-.64v-22.95c0-.32,.23-.61,.58-.61h1.67c.32,0,.58,.26,.58,.61v22.95c0,.32-.23,.64-.58,.64Z"/>
|
||||
<path class="cls-sub" d="M373.88,143.11h-1.64c-.35,0-.64-.29-.64-.64v-2.57c0-.35,.29-.64,.64-.64h1.64c.35,0,.64,.29,.64,.64v2.57c0,.35-.29,.64-.64,.64Zm-.06,20.53h-1.54c-.35,0-.64-.29-.64-.64v-16.42c0-.35,.29-.64,.64-.64h1.54c.35,0,.64,.29,.64,.64v16.42c0,.35-.29,.64-.64,.64Z"/>
|
||||
<path class="cls-sub" d="M393.77,146.72l-4.35,15.32c-.42,1.45-1.51,1.84-2.9,1.84s-2.48-.39-2.9-1.84l-4.34-15.32c-.03-.1-.03-.16-.03-.23,0-.32,.19-.55,.51-.55h1.77c.26,0,.48,.19,.61,.61l3.7,14.03c.19,.77,.35,.93,.68,.93,.29,0,.48-.16,.68-.93l3.7-14.03c.13-.42,.35-.61,.61-.61h1.77c.32,0,.51,.23,.51,.55,0,.06,0,.13-.03,.23Z"/>
|
||||
<path class="cls-sub" d="M400.81,143.11h-1.64c-.35,0-.64-.29-.64-.64v-2.57c0-.35,.29-.64,.64-.64h1.64c.35,0,.64,.29,.64,.64v2.57c0,.35-.29,.64-.64,.64Zm-.06,20.53h-1.54c-.35,0-.64-.29-.64-.64v-16.42c0-.35,.29-.64,.64-.64h1.54c.35,0,.64,.29,.64,.64v16.42c0,.35-.29,.64-.64,.64Z"/>
|
||||
<path class="cls-sub" d="M420.03,163.65h-1.54c-.35,0-.64-.29-.64-.64v-10.59c0-3.25-1.09-4.25-3.54-4.25-1.35,0-2.86,.51-4.34,1.26v13.58c0,.32-.29,.64-.64,.64h-1.58c-.32,0-.61-.29-.61-.64v-16.42c0-.35,.26-.64,.61-.64h1.61c.35,0,.61,.29,.61,.64v.61c1.77-1,3.22-1.48,5.12-1.48,3.86,0,5.6,2.41,5.6,6.69v10.59c0,.35-.29,.64-.64,.64Z"/>
|
||||
<path class="cls-sub" d="M440.07,148.1l-1.16,.22c.58,.61,1.09,1.58,1.09,3.32v.26c0,3.54-2.19,5.5-7.15,5.5-1.71,0-2.8-.26-3.73-.64-.55,.26-.8,.61-.8,1.09,0,.55,.26,.84,1,1.03l4.8,1.22c3.15,.8,6.18,1.71,6.18,4.73v.26c0,3.09-2.06,4.99-7.34,4.99s-7.4-1.96-7.4-5.12v-.29c0-1.8,.97-3.28,2.03-4.09l-.23-.1c-1.03-.45-1.48-1.51-1.48-2.51v-.03c0-.87,.42-1.8,1.32-2.32-1-.93-1.48-2.09-1.48-3.73v-.26c0-2.86,1.61-5.7,7.14-5.7h7.05c.39,0,.74,.32,.74,.71v.84c0,.42-.23,.55-.58,.61Zm-2.61,16.74c0-1.26-1.03-1.77-3.93-2.51l-3.64-.93c-.93,.8-1.58,1.61-1.58,3.28v.29c0,1.8,1.06,2.93,4.63,2.93s4.51-1.03,4.51-2.8v-.26Zm-.26-13.2c0-1.93-.87-3.44-4.35-3.44s-4.34,1.64-4.34,3.44v.26c0,1.42,.64,3.28,4.34,3.28,3.48,0,4.35-1.35,4.35-3.28v-.26Z"/>
|
||||
<path class="cls-sub" d="M365.07,173.76h-1.64c-.35,0-.64-.29-.64-.64v-2.57c0-.35,.29-.64,.64-.64h1.64c.35,0,.64,.29,.64,.64v2.57c0,.35-.29,.64-.64,.64Zm-.06,20.53h-1.54c-.35,0-.64-.29-.64-.64v-16.42c0-.35,.29-.64,.64-.64h1.54c.35,0,.64,.29,.64,.64v16.42c0,.35-.29,.64-.64,.64Z"/>
|
||||
<path class="cls-sub" d="M384.28,194.29h-1.54c-.35,0-.64-.29-.64-.64v-10.59c0-3.25-1.09-4.25-3.54-4.25-1.35,0-2.86,.51-4.34,1.26v13.58c0,.32-.29,.64-.64,.64h-1.58c-.32,0-.61-.29-.61-.64v-16.42c0-.35,.26-.64,.61-.64h1.61c.35,0,.61,.29,.61,.64v.61c1.77-1,3.22-1.48,5.12-1.48,3.86,0,5.6,2.41,5.6,6.69v10.59c0,.35-.29,.64-.64,.64Z"/>
|
||||
<path class="cls-sub" d="M403.17,194.29h-1.54c-.35,0-.64-.29-.64-.64v-10.59c0-3.25-1.09-4.25-3.54-4.25-1.35,0-2.86,.51-4.34,1.26v13.58c0,.32-.29,.64-.64,.64h-1.58c-.32,0-.61-.29-.61-.64v-16.42c0-.35,.26-.64,.61-.64h1.61c.35,0,.61,.29,.61,.64v.61c1.77-1,3.22-1.48,5.12-1.48,3.86,0,5.6,2.41,5.6,6.69v10.59c0,.35-.29,.64-.64,.64Z"/>
|
||||
<path class="cls-sub" d="M415.71,194.52c-4.73,0-7.14-3.12-7.14-7.85v-2.45c0-4.73,2.41-7.85,7.14-7.85s7.18,3.12,7.18,7.85v2.45c0,4.73-2.45,7.85-7.18,7.85Zm4.35-10.3c0-3.28-1.32-5.38-4.35-5.38s-4.31,2.06-4.31,5.38v2.45c0,3.28,1.29,5.38,4.31,5.38s4.35-2.06,4.35-5.38v-2.45Z"/>
|
||||
<path class="cls-sub" d="M440.52,177.36l-4.35,15.32c-.42,1.45-1.51,1.84-2.9,1.84s-2.48-.39-2.9-1.84l-4.35-15.32c-.03-.1-.03-.16-.03-.23,0-.32,.19-.55,.51-.55h1.77c.26,0,.48,.19,.61,.61l3.7,14.03c.19,.77,.35,.93,.68,.93,.29,0,.48-.16,.68-.93l3.7-14.03c.13-.42,.35-.61,.61-.61h1.77c.32,0,.51,.23,.51,.55,0,.06,0,.13-.03,.23Z"/>
|
||||
<path class="cls-sub" d="M455.97,194.29h-1.48c-.35,0-.64-.29-.64-.64v-.71c-1.54,.9-3.15,1.58-4.96,1.58-2.74,0-5.25-1.19-5.25-5.21v-.39c0-3.48,2.03-5.21,7.76-5.21h2.38v-1.29c0-2.7-.93-3.64-3.44-3.64-2.09,0-3.64,.13-4.92,.26h-.16c-.29,0-.58-.1-.58-.51v-1.13c0-.35,.23-.55,.68-.61,1.32-.23,2.8-.42,4.99-.42,4.47,0,6.28,2.25,6.28,6.05v11.23c0,.35-.29,.64-.64,.64Zm-2.19-8.56h-2.38c-3.9,0-4.93,.87-4.93,3.15v.39c0,2.32,1.09,2.93,2.96,2.93,1.48,0,2.8-.45,4.35-1.29v-5.18Z"/>
|
||||
<path class="cls-sub" d="M469.99,194.36c-.64,.1-1.48,.16-2.09,.16-2.96,0-4.38-.77-4.38-4.31v-11.23l-3.12-.35c-.35-.03-.61-.22-.61-.58v-.87c0-.35,.26-.58,.61-.58h3.12v-3.15c0-.32,.22-.58,.58-.64l1.67-.26h.1c.26,0,.48,.22,.48,.55v3.51h3.48c.35,0,.64,.29,.64,.64v1.09c0,.35-.29,.64-.64,.64h-3.48v11.23c0,1.77,.45,2.03,1.74,2.03h1.8c.45,0,.68,.13,.68,.45v1.13c0,.29-.16,.48-.58,.55Z"/>
|
||||
<path class="cls-sub" d="M477.14,173.76h-1.64c-.35,0-.64-.29-.64-.64v-2.57c0-.35,.29-.64,.64-.64h1.64c.35,0,.64,.29,.64,.64v2.57c0,.35-.29,.64-.64,.64Zm-.06,20.53h-1.54c-.35,0-.64-.29-.64-.64v-16.42c0-.35,.29-.64,.64-.64h1.54c.35,0,.64,.29,.64,.64v16.42c0,.35-.29,.64-.64,.64Z"/>
|
||||
<path class="cls-sub" d="M490.01,194.52c-4.73,0-7.14-3.12-7.14-7.85v-2.45c0-4.73,2.41-7.85,7.14-7.85s7.18,3.12,7.18,7.85v2.45c0,4.73-2.45,7.85-7.18,7.85Zm4.35-10.3c0-3.28-1.32-5.38-4.35-5.38s-4.31,2.06-4.31,5.38v2.45c0,3.28,1.29,5.38,4.31,5.38s4.35-2.06,4.35-5.38v-2.45Z"/>
|
||||
<path class="cls-sub" d="M514.85,194.29h-1.54c-.35,0-.64-.29-.64-.64v-10.59c0-3.25-1.09-4.25-3.54-4.25-1.35,0-2.86,.51-4.34,1.26v13.58c0,.32-.29,.64-.64,.64h-1.58c-.32,0-.61-.29-.61-.64v-16.42c0-.35,.26-.64,.61-.64h1.61c.35,0,.61,.29,.61,.64v.61c1.77-1,3.22-1.48,5.12-1.48,3.86,0,5.6,2.41,5.6,6.69v10.59c0,.35-.29,.64-.64,.64Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path class="cls-11" d="M57.78,67.44c-.03,5.02-.86,9.86-2.35,14.39,0,0,.01,.01,.02,.02,0,0,0,0,.01,0,10.82-31.09,38.25-54.41,71.67-59.3C130.83,15.86,132.95,8.18,132.95,0h0s-46.67,0-46.67,0H46.67C30.78,0,16.76,7.94,8.33,20.07c.88-.04,1.76-.07,2.65-.06,26.02,.17,46.98,21.41,46.8,47.43Z"/>
|
||||
<path class="cls-10" d="M0,46.67c0,5.62,1,11,2.82,15.99,5.22-.78,10.62-.87,16.11-.17,14.7,1.88,27.41,9.05,36.5,19.35,1.49-4.53,2.31-9.36,2.35-14.39,.17-26.02-20.78-47.26-46.8-47.43-.89,0-1.77,.02-2.65,.06C3.08,27.61,0,36.78,0,46.67H0Z"/>
|
||||
<path class="cls-6" d="M0,46.67c0,5.62,1,11,2.82,15.99,5.22-.78,10.62-.87,16.11-.17,14.7,1.88,27.41,9.05,36.5,19.35,1.49-4.53,2.31-9.36,2.35-14.39,.17-26.02-20.78-47.26-46.8-47.43-.89,0-1.77,.02-2.65,.06C3.08,27.61,0,36.78,0,46.67H0Z"/>
|
||||
<path class="cls-7" d="M55.46,81.85s-.01-.01-.02-.02c0,0,0,0,0,.01,0,0,.02,0,.02,0Z"/>
|
||||
<path class="cls-10" d="M55.47,81.85s0,0-.01,0c0,0,0,0,.01,.01,0,0,0,0,0,0Z"/>
|
||||
<path class="cls-8" d="M55.47,81.85s0,0-.01,0c0,0,0,0,.01,.01,0,0,0,0,0,0Z"/>
|
||||
<path class="cls-7" d="M55.42,81.88s.03,0,.05-.01c0,0,0,0,0,0,0,0,0,0-.01-.01,0,0-.02,0-.02,0,0,.01,0,.02-.01,.03Z"/>
|
||||
<path class="cls-8" d="M55.42,81.88s.03,0,.05-.01c0,0,0,0,0,0,0,0,0,0-.01-.01,0,0-.02,0-.02,0,0,.01,0,.02-.01,.03Z"/>
|
||||
<path class="cls-10" d="M55.47,81.85s0,0,.01,0c5.58-1.58,11.47-2.44,17.56-2.44,24,0,44.92,13.13,56.01,32.6,2.5-5.72,3.9-12.04,3.9-18.68h0c0-24.43-18.78-44.48-42.69-46.5-.22-.02-.22-.31,0-.33,15.91-1.34,29.53-10.67,36.88-23.95-33.42,4.9-60.85,28.21-71.67,59.3Z"/>
|
||||
<path class="cls-3" d="M55.47,81.85s0,0,.01,0c5.58-1.58,11.47-2.44,17.56-2.44,24,0,44.92,13.13,56.01,32.6,2.5-5.72,3.9-12.04,3.9-18.68h0c0-24.43-18.78-44.48-42.69-46.5-.22-.02-.22-.31,0-.33,15.91-1.34,29.53-10.67,36.88-23.95-33.42,4.9-60.85,28.21-71.67,59.3Z"/>
|
||||
<path class="cls-10" d="M55.47,81.86s.01,0,.02,0c0,0,0,0-.01,0,0,0,0,0,0,0,0,0,0,0,0,0Z"/>
|
||||
<path class="cls-8" d="M55.47,81.86s.01,0,.02,0c0,0,0,0-.01,0,0,0,0,0,0,0,0,0,0,0,0,0Z"/>
|
||||
<path class="cls-9" d="M55.47,81.86s.01,0,.02,0c0,0,0,0-.01,0,0,0,0,0,0,0,0,0,0,0,0,0Z"/>
|
||||
<polygon class="cls-7" points="55.47 81.86 55.47 81.86 55.47 81.86 55.47 81.86"/>
|
||||
<polygon class="cls-8" points="55.47 81.86 55.47 81.86 55.47 81.86 55.47 81.86"/>
|
||||
<polygon class="cls-9" points="55.47 81.86 55.47 81.86 55.47 81.86 55.47 81.86"/>
|
||||
<path class="cls-10" d="M73.04,79.42c-6.09,0-11.97,.86-17.56,2.44,24.27,7.47,41.91,30.06,41.91,56.78,0,0,0,.01,0,.02,14.23-3.48,25.89-13.47,31.65-26.64-11.08-19.46-32-32.6-56.01-32.6Z"/>
|
||||
<path class="cls-9" d="M73.04,79.42c-6.09,0-11.97,.86-17.56,2.44,24.27,7.47,41.91,30.06,41.91,56.78,0,0,0,.01,0,.02,14.23-3.48,25.89-13.47,31.65-26.64-11.08-19.46-32-32.6-56.01-32.6Z"/>
|
||||
<path class="cls-4" d="M73.04,79.42c-6.09,0-11.97,.86-17.56,2.44,24.27,7.47,41.91,30.06,41.91,56.78,0,0,0,.01,0,.02,14.23-3.48,25.89-13.47,31.65-26.64-11.08-19.46-32-32.6-56.01-32.6Z"/>
|
||||
<path class="cls-10" d="M55.48,81.86s-.01,0-.02,0c10.78,12.22,16.46,28.84,14.23,46.28-.53,4.12-1.59,8.08-3.11,11.86h19.69c3.83,0,7.55-.47,11.11-1.34,0,0,0-.01,0-.02,0-26.72-17.64-49.31-41.91-56.78Z"/>
|
||||
<path class="cls-8" d="M55.48,81.86s-.01,0-.02,0c10.78,12.22,16.46,28.84,14.23,46.28-.53,4.12-1.59,8.08-3.11,11.86h19.69c3.83,0,7.55-.47,11.11-1.34,0,0,0-.01,0-.02,0-26.72-17.64-49.31-41.91-56.78Z"/>
|
||||
<path class="cls-9" d="M55.48,81.86s-.01,0-.02,0c10.78,12.22,16.46,28.84,14.23,46.28-.53,4.12-1.59,8.08-3.11,11.86h19.69c3.83,0,7.55-.47,11.11-1.34,0,0,0-.01,0-.02,0-26.72-17.64-49.31-41.91-56.78Z"/>
|
||||
<path class="cls-1" d="M55.48,81.86s-.01,0-.02,0c10.78,12.22,16.46,28.84,14.23,46.28-.53,4.12-1.59,8.08-3.11,11.86h19.69c3.83,0,7.55-.47,11.11-1.34,0,0,0-.01,0-.02,0-26.72-17.64-49.31-41.91-56.78Z"/>
|
||||
<path class="cls-5" d="M55.47,81.86s0,0,0,0c-.02,0-.03,0-.05,.01,0-.01,0-.02,.01-.03,0,0,0,0,0-.01-9.09-10.29-21.81-17.47-36.5-19.35-5.49-.7-10.89-.6-16.11,.17,2.93,8.02,7.98,15.01,14.5,20.29,5.11,4.14,11.12,7.22,17.69,8.91,2.45,.63,4.96,1.08,7.55,1.3,.24,.02,.24,.34,0,.36-4.74,.41-9.26,1.54-13.49,3.27-8.71,3.55-16.1,9.65-21.25,17.38-4.93,7.4-7.82,16.28-7.82,25.84H0s8.74,0,8.74,0h57.85c1.51-3.77,2.58-7.74,3.11-11.86,2.23-17.44-3.45-34.06-14.23-46.28Z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 13 KiB |
@@ -86,15 +86,16 @@
|
||||
.el-table__header-wrapper, .el-table__fixed-header-wrapper {
|
||||
th {
|
||||
word-break: break-word;
|
||||
background-color: #f8f8f9 !important;
|
||||
color: #515a6e;
|
||||
height: 40px !important;
|
||||
background-color: var(--el-fill-color-light, #f5f7fa) !important;
|
||||
color: var(--el-text-color-regular, #606266);
|
||||
height: 46px !important;
|
||||
font-size: 13px;
|
||||
font-weight: 650;
|
||||
}
|
||||
}
|
||||
.el-table__body-wrapper {
|
||||
.el-button [class*="el-icon-"] + span {
|
||||
margin-left: 1px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -306,3 +307,177 @@
|
||||
.splitpanes.default-theme .splitpanes__pane {
|
||||
background-color: var(--splitpanes-default-bg) !important;
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 全局工作区与现代化容器体系
|
||||
// ==========================================
|
||||
.app-container {
|
||||
min-height: 100%;
|
||||
padding: 18px 20px 24px;
|
||||
background: var(--el-bg-color-page, #f5f7fb);
|
||||
color: var(--el-text-color-primary, #303133);
|
||||
box-sizing: border-box;
|
||||
|
||||
// 顶部内联检索卡片 (排除弹窗内部表单)
|
||||
& > .el-form--inline,
|
||||
.splitpanes .el-form--inline {
|
||||
margin: 0 0 14px;
|
||||
padding: 14px 16px 2px;
|
||||
border: 1px solid var(--el-border-color-lighter, #e4e7ed);
|
||||
border-radius: 12px;
|
||||
background: var(--el-bg-color, #fff);
|
||||
box-shadow: var(--el-box-shadow-lighter, 0 3px 14px rgba(31, 55, 88, 0.04));
|
||||
transition: box-shadow 0.25s ease, border-color 0.25s ease;
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 12px;
|
||||
margin-right: 14px;
|
||||
}
|
||||
|
||||
.el-input,
|
||||
.el-select,
|
||||
.el-input-number,
|
||||
.el-date-editor {
|
||||
min-width: 190px;
|
||||
}
|
||||
}
|
||||
|
||||
// 统一操作工具栏
|
||||
& > .el-row.mb8,
|
||||
.splitpanes .el-row.mb8 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
min-height: 38px;
|
||||
margin: 0 0 12px !important;
|
||||
|
||||
.el-col {
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
|
||||
.top-right-btn {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
// 统一现代化数据表格卡片容器
|
||||
& > .el-table,
|
||||
.splitpanes .el-table {
|
||||
width: 100%;
|
||||
border: 1px solid var(--el-border-color-lighter, #e4e7ed);
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
background: var(--el-bg-color, #fff);
|
||||
box-shadow: var(--el-box-shadow-lighter, 0 3px 14px rgba(31, 55, 88, 0.04));
|
||||
|
||||
.el-table__header th {
|
||||
height: 46px !important;
|
||||
background: var(--el-fill-color-light, #f5f7fa) !important;
|
||||
color: var(--el-text-color-regular, #606266) !important;
|
||||
font-weight: 650;
|
||||
border-bottom: 1px solid var(--el-border-color-lighter, #e4e7ed);
|
||||
}
|
||||
|
||||
.el-table__body td {
|
||||
height: 50px;
|
||||
border-bottom: 1px solid var(--el-border-color-lighter, #f0f2f5);
|
||||
}
|
||||
|
||||
.el-table__body tr:nth-child(even) > td {
|
||||
background: var(--el-fill-color-lighter, #fafafa);
|
||||
}
|
||||
|
||||
.el-table__body tr:hover > td {
|
||||
background-color: var(--el-fill-color-light, #f5f7fa) !important;
|
||||
}
|
||||
|
||||
.el-table__inner-wrapper::before {
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
margin-top: 14px;
|
||||
padding: 0 2px;
|
||||
}
|
||||
}
|
||||
|
||||
// 弹窗现代化规范
|
||||
.el-dialog {
|
||||
border-radius: 14px !important;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--el-border-color-lighter, #e4e7ed);
|
||||
box-shadow: 0 20px 60px rgba(15, 34, 58, 0.16) !important;
|
||||
|
||||
.el-dialog__header {
|
||||
padding: 16px 22px 14px;
|
||||
margin-right: 0;
|
||||
border-bottom: 1px solid var(--el-border-color-lighter, #e4e7ed);
|
||||
|
||||
.el-dialog__title {
|
||||
font-size: 16px;
|
||||
font-weight: 650;
|
||||
color: var(--el-text-color-primary, #303133);
|
||||
}
|
||||
}
|
||||
|
||||
.el-dialog__body {
|
||||
padding: 20px 22px;
|
||||
}
|
||||
|
||||
.el-dialog__footer {
|
||||
padding: 12px 22px 16px;
|
||||
border-top: 1px solid var(--el-border-color-lighter, #e4e7ed);
|
||||
}
|
||||
}
|
||||
|
||||
// 卡片现代化规范
|
||||
.el-card {
|
||||
border-radius: 14px !important;
|
||||
border: 1px solid var(--el-border-color-lighter, #e4e7ed) !important;
|
||||
box-shadow: var(--el-box-shadow-lighter, 0 3px 14px rgba(31, 55, 88, 0.04)) !important;
|
||||
|
||||
.el-card__header {
|
||||
padding: 16px 20px !important;
|
||||
border-bottom: 1px solid var(--el-border-color-lighter, #e4e7ed) !important;
|
||||
font-weight: 650;
|
||||
}
|
||||
|
||||
.el-card__body {
|
||||
padding: 18px 20px !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 分割面板与树结构卡片化
|
||||
.splitpanes.default-theme {
|
||||
.splitpanes__pane {
|
||||
background-color: var(--el-bg-color, #fff) !important;
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--el-border-color-lighter, #e4e7ed);
|
||||
padding: 16px;
|
||||
box-shadow: var(--el-box-shadow-lighter, 0 3px 14px rgba(31, 55, 88, 0.04));
|
||||
}
|
||||
|
||||
.splitpanes__splitter {
|
||||
background-color: transparent !important;
|
||||
border: none !important;
|
||||
width: 12px !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 输入框与按钮微调
|
||||
.el-input__wrapper,
|
||||
.el-select__wrapper {
|
||||
border-radius: 8px !important;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.el-button {
|
||||
border-radius: 8px;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&.is-circle {
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
left: 0;
|
||||
z-index: 1001;
|
||||
overflow: hidden;
|
||||
-webkit-box-shadow: 2px 0 6px rgba(0,21,41,.35);
|
||||
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
|
||||
border-right: 1px solid var(--el-border-color-lighter, #e4e7ed);
|
||||
box-shadow: 2px 0 10px 0 rgba(15, 34, 58, 0.05);
|
||||
|
||||
// reset element-ui css
|
||||
.horizontal-collapse-transition {
|
||||
@@ -68,6 +68,24 @@
|
||||
border: none;
|
||||
height: 100%;
|
||||
width: 100% !important;
|
||||
|
||||
&:not(.el-menu--collapse) {
|
||||
.el-menu-item,
|
||||
.el-sub-menu__title {
|
||||
height: 46px;
|
||||
line-height: 46px;
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
transition: background-color 0.2s ease, color 0.2s ease;
|
||||
}
|
||||
|
||||
.el-menu-item.is-active {
|
||||
font-weight: 600;
|
||||
background-color: rgba(0, 133, 150, 0.12) !important;
|
||||
color: var(--current-color, #008596) !important;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-menu-item, .menu-title {
|
||||
@@ -92,9 +110,18 @@
|
||||
color: vars.$base-menu-color-active !important;
|
||||
}
|
||||
|
||||
& .theme-dark .el-menu:not(.el-menu--collapse) .el-menu-item.is-active {
|
||||
background-color: rgba(0, 133, 150, 0.26) !important;
|
||||
color: #38bdf8 !important;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
& .nest-menu .el-sub-menu>.el-sub-menu__title,
|
||||
& .el-sub-menu .el-menu-item {
|
||||
min-width: vars.$base-sidebar-width !important;
|
||||
width: 100% !important;
|
||||
margin: 0 !important;
|
||||
border-radius: 0 !important;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 0.06) !important;
|
||||
@@ -108,6 +135,11 @@
|
||||
&:hover {
|
||||
background-color: vars.$base-sub-menu-hover !important;
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
background-color: rgba(0, 133, 150, 0.28) !important;
|
||||
color: #38bdf8 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -88,10 +88,21 @@ getBreadcrumb()
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
line-height: 50px;
|
||||
margin-left: 8px;
|
||||
|
||||
.no-redirect {
|
||||
color: #97a8be;
|
||||
color: var(--el-text-color-regular, #606266);
|
||||
cursor: text;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--el-text-color-secondary, #909399);
|
||||
transition: color 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
color: var(--el-color-primary, #008596);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -96,9 +96,12 @@ function handleCurrentChange(val) {
|
||||
|
||||
<style scoped>
|
||||
.pagination-container {
|
||||
background: #fff;
|
||||
background: transparent;
|
||||
padding: 12px 2px 0;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.pagination-container.hidden {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -52,6 +52,7 @@ async function syncTestBatchScope() {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background-color: var(--el-bg-color-page, #f5f7fb);
|
||||
}
|
||||
|
||||
.fixed-header + .app-main {
|
||||
@@ -123,11 +124,15 @@ async function syncTestBatchScope() {
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background-color: #f1f1f1;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: #c0c0c0;
|
||||
background-color: var(--el-border-color-darker, #c0c4cc);
|
||||
border-radius: 3px;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--el-text-color-secondary, #909399);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -156,7 +156,8 @@ async function toggleTheme(event) {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
background: var(--navbar-bg);
|
||||
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
|
||||
border-bottom: 1px solid var(--el-border-color-lighter, #e4e7ed);
|
||||
box-shadow: 0 1px 4px rgba(15, 34, 58, 0.04);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
// padding: 0 8px;
|
||||
@@ -216,19 +217,22 @@ async function toggleTheme(event) {
|
||||
}
|
||||
|
||||
.right-menu-item {
|
||||
display: inline-block;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 8px;
|
||||
height: 100%;
|
||||
font-size: 18px;
|
||||
color: #5a5e66;
|
||||
vertical-align: text-bottom;
|
||||
color: var(--el-text-color-regular, #5a5e66);
|
||||
vertical-align: middle;
|
||||
|
||||
&.hover-effect {
|
||||
cursor: pointer;
|
||||
transition: background 0.3s;
|
||||
transition: background 0.3s, color 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.025);
|
||||
background: rgba(0, 0, 0, 0.035);
|
||||
color: var(--el-color-primary, #008596);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,30 +251,36 @@ async function toggleTheme(event) {
|
||||
}
|
||||
|
||||
.avatar-container {
|
||||
margin-right: 0px;
|
||||
padding-right: 0px;
|
||||
margin-right: 4px;
|
||||
padding: 0 4px;
|
||||
|
||||
.avatar-wrapper {
|
||||
margin-top: 10px;
|
||||
right: 8px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 4px 8px;
|
||||
border-radius: 20px;
|
||||
transition: background 0.25s ease;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
cursor: pointer;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin-right: 8px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
vertical-align: middle;
|
||||
border-style: none;
|
||||
object-fit: cover;
|
||||
border: 1.5px solid var(--el-color-primary-light-7, #b2e0e6);
|
||||
box-shadow: 0 2px 6px rgba(0, 133, 150, 0.12);
|
||||
}
|
||||
|
||||
.user-nickname{
|
||||
position: relative;
|
||||
left: 0px;
|
||||
// bottom: 10px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
.user-nickname {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--el-text-color-primary, #303133);
|
||||
}
|
||||
|
||||
i {
|
||||
|
||||
@@ -44,6 +44,7 @@ const logoBackground = variables.menuBg;
|
||||
background: v-bind(logoBackground);
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
||||
|
||||
& .sidebar-logo-link {
|
||||
display: flex;
|
||||
|
||||
@@ -87,8 +87,8 @@ function isActive(r) {
|
||||
function activeStyle(tag) {
|
||||
if (!isActive(tag)) return {};
|
||||
return {
|
||||
"background-color": theme.value,
|
||||
"border-color": theme.value
|
||||
"background-color": theme.value || '#008596',
|
||||
"border-color": theme.value || '#008596'
|
||||
};
|
||||
}
|
||||
function isAffix(tag) {
|
||||
@@ -244,8 +244,8 @@ function handleScroll() {
|
||||
height: 34px;
|
||||
width: 100%;
|
||||
background: var(--tags-bg, #fff);
|
||||
border-bottom: 1px solid var(--tags-item-border, #d8dce5);
|
||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04);
|
||||
border-bottom: 1px solid var(--el-border-color-lighter, #e4e7ed);
|
||||
box-shadow: 0 1px 4px 0 rgba(15, 34, 58, 0.04);
|
||||
.tags-view-wrapper {
|
||||
.tags-view-item {
|
||||
display: inline-block;
|
||||
@@ -254,12 +254,14 @@ function handleScroll() {
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
border: 1px solid var(--tags-item-border, #d8dce5);
|
||||
border-radius: 6px;
|
||||
color: var(--tags-item-text, #495060);
|
||||
background: var(--tags-item-bg, #fff);
|
||||
padding: 0 8px;
|
||||
padding: 0 10px;
|
||||
font-size: 12px;
|
||||
margin-left: 5px;
|
||||
margin-top: 4px;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:first-of-type {
|
||||
margin-left: 15px;
|
||||
@@ -269,20 +271,27 @@ function handleScroll() {
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
&:not(.active):hover {
|
||||
background-color: var(--el-fill-color-light, #f5f7fa);
|
||||
border-color: var(--el-color-primary-light-7, #b2e0e6);
|
||||
color: var(--el-color-primary, #008596);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #42b983;
|
||||
background-color: #008596;
|
||||
color: #fff;
|
||||
border-color: #42b983;
|
||||
border-color: #008596;
|
||||
box-shadow: 0 2px 6px rgba(0, 133, 150, 0.22);
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
background: #fff;
|
||||
display: inline-block;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
margin-right: 5px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -298,21 +307,26 @@ function handleScroll() {
|
||||
z-index: 3000;
|
||||
position: absolute;
|
||||
list-style-type: none;
|
||||
padding: 5px 0;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: var(--tags-item-text, #333);
|
||||
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
|
||||
border: 1px solid var(--el-border-color-light, #e4e7ed);
|
||||
padding: 6px 0;
|
||||
border-radius: 8px;
|
||||
font-size: 13px;
|
||||
font-weight: 450;
|
||||
color: var(--el-text-color-primary, #333);
|
||||
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
|
||||
border: 1px solid var(--el-border-color-lighter, #e4e7ed);
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin: 0;
|
||||
padding: 7px 16px;
|
||||
padding: 8px 16px;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s ease, color 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
background: var(--tags-item-hover, #eee);
|
||||
background: var(--el-fill-color-light, #f5f7fa);
|
||||
color: var(--el-color-primary, #008596);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -347,4 +361,4 @@ function handleScroll() {
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -14,7 +14,7 @@ const useSettingsStore = defineStore(
|
||||
{
|
||||
state: () => ({
|
||||
title: '',
|
||||
theme: storageSetting.theme || '#409EFF',
|
||||
theme: storageSetting.theme || '#008596',
|
||||
sideTheme: storageSetting.sideTheme || sideTheme,
|
||||
showSettings: showSettings,
|
||||
navType: storageSetting.navType === undefined ? navType : storageSetting.navType,
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
<template>
|
||||
<div class="dashboard-page">
|
||||
<div class="dashboard-header">
|
||||
<div class="header-left">
|
||||
<h1 class="page-title">仓储运营总览</h1>
|
||||
<p class="page-desc">实时监控托盘流转、出入库动态与仓储核心 KPI</p>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<el-tag type="info" effect="plain" class="range-tag">数据范围:全部仓库</el-tag>
|
||||
<el-button type="primary" plain :icon="Refresh" :loading="state.loading" @click="loadDashboardData">刷新数据</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="state.partialError" class="dashboard-alert">
|
||||
<el-icon><Warning /></el-icon>
|
||||
<span>部分运营数据暂时无法加载,已保留可用模块。</span>
|
||||
@@ -36,7 +47,7 @@
|
||||
<div class="card-heading">
|
||||
<div>
|
||||
<h2>{{ trendRangeLabel }}入库 / 出库趋势</h2>
|
||||
<span>入库以单据数统计,出库以确认包数统计</span>
|
||||
<span>入库以单据数统计,出库以确认包数统计(默认近 7 天入库 / 出库趋势)</span>
|
||||
</div>
|
||||
<el-select
|
||||
v-model="selectedTrendDays"
|
||||
@@ -155,12 +166,31 @@
|
||||
|
||||
<el-card class="dashboard-card activity-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-heading"><div><h2>扫码异常</h2><span>扫码过程中的异常记录</span></div><el-tag type="success" effect="light">正常</el-tag></div>
|
||||
<div class="card-heading"><div><h2>扫码异常</h2><span>扫码过程中的异常记录</span></div><el-tag :type="scanExceptionTag.type" effect="light">{{ scanExceptionTag.label }}</el-tag></div>
|
||||
</template>
|
||||
<div class="exception-empty">
|
||||
<div v-if="state.loading || state.scanExceptionAvailable === null" class="exception-list">
|
||||
<el-skeleton :rows="4" animated />
|
||||
</div>
|
||||
<div v-else-if="state.scanExceptionAvailable === false" class="exception-empty">
|
||||
<div class="exception-icon exception-icon--warning"><el-icon><WarningFilled /></el-icon></div>
|
||||
<strong>扫码异常暂时无法加载</strong>
|
||||
<span>请稍后点击“重新加载”再试。</span>
|
||||
</div>
|
||||
<div v-else-if="scanExceptions.length" class="exception-list">
|
||||
<div v-for="item in scanExceptions" :key="item.operId" class="exception-item">
|
||||
<span class="exception-icon exception-icon--danger"><el-icon><WarningFilled /></el-icon></span>
|
||||
<span class="exception-copy">
|
||||
<strong>{{ item.source }}</strong>
|
||||
<small>{{ item.operatorName || '未知用户' }} · {{ formatTime(item.occurredAt) }}</small>
|
||||
<span class="exception-message" :title="item.errorMessage">{{ item.errorMessage }}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="scanExceptionTotal > scanExceptions.length" class="exception-more">仅展示最近 {{ scanExceptions.length }} 条异常记录</div>
|
||||
</div>
|
||||
<div v-else class="exception-empty">
|
||||
<div class="exception-icon"><el-icon><CircleCheck /></el-icon></div>
|
||||
<strong>暂无扫码异常记录</strong>
|
||||
<span>当前系统没有提供独立异常日志接口,后续接入后将在此展示。</span>
|
||||
<span>最近没有失败的扫码请求。</span>
|
||||
</div>
|
||||
</el-card>
|
||||
</section>
|
||||
@@ -169,7 +199,8 @@
|
||||
|
||||
<script setup name="DashBoard">
|
||||
import * as echarts from 'echarts'
|
||||
import { ArrowRight, Box, CircleCheck, Coin, Download, DocumentAdd, Operation, Upload, Van, Warning, WarningFilled } from '@element-plus/icons-vue'
|
||||
import { ArrowRight, Box, CircleCheck, Coin, Download, DocumentAdd, Operation, Refresh, Upload, Van, Warning, WarningFilled } from '@element-plus/icons-vue'
|
||||
import { listScanExceptions } from '@/api/business/dashboard'
|
||||
import { listInbound } from '@/api/business/inbound'
|
||||
import { listReturn } from '@/api/business/return'
|
||||
import { listShipment } from '@/api/business/shipment'
|
||||
@@ -198,6 +229,9 @@ const state = reactive({
|
||||
pendingItems: [],
|
||||
recentInbound: [],
|
||||
recentShipments: [],
|
||||
scanExceptionAvailable: null,
|
||||
scanExceptionTotal: 0,
|
||||
scanExceptions: [],
|
||||
trendInboundRows: [],
|
||||
trendShipmentRows: []
|
||||
})
|
||||
@@ -223,6 +257,14 @@ const pendingItems = computed(() => state.pendingItems)
|
||||
const pendingTotal = computed(() => state.pendingTotal)
|
||||
const recentInbound = computed(() => state.recentInbound)
|
||||
const recentShipments = computed(() => state.recentShipments)
|
||||
const scanExceptions = computed(() => state.scanExceptions)
|
||||
const scanExceptionTotal = computed(() => state.scanExceptionTotal)
|
||||
const scanExceptionTag = computed(() => {
|
||||
if (state.scanExceptionAvailable === null) return { type: 'info', label: '加载中' }
|
||||
if (state.scanExceptionAvailable === false) return { type: 'warning', label: '暂不可用' }
|
||||
if (scanExceptionTotal.value > 0) return { type: 'danger', label: `${scanExceptionTotal.value} 条` }
|
||||
return { type: 'success', label: '正常' }
|
||||
})
|
||||
const inventoryHasData = computed(() => state.inventoryRows.length > 0)
|
||||
const trendHasData = computed(() => state.trendInboundRows.length > 0 || state.trendShipmentRows.length > 0)
|
||||
const trendRangeLabel = computed(() => TREND_RANGE_OPTIONS.find((option) => option.value === selectedTrendDays.value)?.label || '近 7 天')
|
||||
@@ -352,9 +394,10 @@ async function handleTrendRangeChange() {
|
||||
async function loadDashboardData() {
|
||||
state.loading = true
|
||||
state.partialError = false
|
||||
state.scanExceptionAvailable = null
|
||||
const today = todayQuery()
|
||||
try {
|
||||
const [inventory, todayInbound, todayShipment, recentInboundResponse, recentShipmentResponse, trend, pendingInbound, pendingShipment, pendingReturn] = await Promise.all([
|
||||
const [inventory, todayInbound, todayShipment, recentInboundResponse, recentShipmentResponse, trend, pendingInbound, pendingShipment, pendingReturn, scanExceptionsResponse] = await Promise.all([
|
||||
requestSafely('托盘库存', () => loadAllPages(listPalletInventory), { rows: [], total: 0 }),
|
||||
requestSafely('今日入库', () => listInbound({ ...today, pageNum: 1, pageSize: 1 }), {}),
|
||||
requestSafely('今日出库', () => listShipment({ ...today, pageNum: 1, pageSize: 1 }), {}),
|
||||
@@ -363,7 +406,8 @@ async function loadDashboardData() {
|
||||
fetchTrendData(),
|
||||
requestSafely('待确认入库', () => listInbound({ status: 'DRAFT', pageNum: 1, pageSize: 5 }), {}),
|
||||
requestSafely('待确认出库', () => listShipment({ status: 'DRAFT', pageNum: 1, pageSize: 5 }), {}),
|
||||
requestSafely('待确认退回', () => listReturn({ status: 'REQUESTED', pageNum: 1, pageSize: 5 }), {})
|
||||
requestSafely('待确认退回', () => listReturn({ status: 'REQUESTED', pageNum: 1, pageSize: 5 }), {}),
|
||||
requestSafely('扫码异常', () => listScanExceptions(), null)
|
||||
])
|
||||
|
||||
state.inventoryRows = inventory.rows
|
||||
@@ -381,6 +425,9 @@ async function loadDashboardData() {
|
||||
...getRows(pendingReturn).map((row) => ({ key: `return-${row.returnId}`, title: row.returnNo, type: '退回申请', status: row.status, time: row.requestedAt, path: '/businessOperation/return', tone: 'green' }))
|
||||
].slice(0, 6)
|
||||
state.pendingTotal = getTotal(pendingInbound) + getTotal(pendingShipment) + getTotal(pendingReturn)
|
||||
state.scanExceptionAvailable = Boolean(scanExceptionsResponse)
|
||||
state.scanExceptions = getRows(scanExceptionsResponse)
|
||||
state.scanExceptionTotal = getTotal(scanExceptionsResponse)
|
||||
} finally {
|
||||
state.loading = false
|
||||
await nextTick()
|
||||
@@ -416,15 +463,50 @@ function renderCharts() {
|
||||
chart.clear()
|
||||
if (trendHasData.value) {
|
||||
chart.setOption({
|
||||
color: ['#1677ff', '#16a085'],
|
||||
tooltip: { trigger: 'axis' },
|
||||
color: ['#008596', '#0284c7'],
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
backgroundColor: settingsStore.isDark ? 'rgba(23, 27, 34, 0.95)' : 'rgba(255, 255, 255, 0.96)',
|
||||
borderColor: settingsStore.isDark ? '#374151' : '#e2e8f0',
|
||||
textStyle: { color: settingsStore.isDark ? '#f1f5f9' : '#1e293b' }
|
||||
},
|
||||
legend: { bottom: 0, textStyle: { color: chartTextColor() } },
|
||||
grid: { top: 18, right: 20, bottom: 42, left: 42 },
|
||||
xAxis: { type: 'category', boundaryGap: false, data: trendData.value.labels, axisLine: { lineStyle: { color: chartGridColor() } }, axisLabel: { color: chartTextColor(), interval: selectedTrendDays.value > 14 ? 4 : 0, hideOverlap: true } },
|
||||
yAxis: { type: 'value', minInterval: 1, splitLine: { lineStyle: { color: chartGridColor() } }, axisLabel: { color: chartTextColor() } },
|
||||
series: [
|
||||
{ name: '入库单', type: 'line', smooth: true, symbol: 'circle', symbolSize: 7, data: trendData.value.inbound, areaStyle: { opacity: 0.08 } },
|
||||
{ name: '出库包数', type: 'line', smooth: true, symbol: 'circle', symbolSize: 7, data: trendData.value.outbound, areaStyle: { opacity: 0.06 } }
|
||||
{
|
||||
name: '入库单',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
symbol: 'circle',
|
||||
symbolSize: 7,
|
||||
itemStyle: { color: '#008596' },
|
||||
lineStyle: { width: 2.5, color: '#008596' },
|
||||
areaStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: 'rgba(0, 133, 150, 0.25)' },
|
||||
{ offset: 1, color: 'rgba(0, 133, 150, 0.01)' }
|
||||
])
|
||||
},
|
||||
data: trendData.value.inbound
|
||||
},
|
||||
{
|
||||
name: '出库包数',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
symbol: 'circle',
|
||||
symbolSize: 7,
|
||||
itemStyle: { color: '#0284c7' },
|
||||
lineStyle: { width: 2.5, color: '#0284c7' },
|
||||
areaStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: 'rgba(2, 132, 199, 0.2)' },
|
||||
{ offset: 1, color: 'rgba(2, 132, 199, 0.01)' }
|
||||
])
|
||||
},
|
||||
data: trendData.value.outbound
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
@@ -434,8 +516,14 @@ function renderCharts() {
|
||||
chart.clear()
|
||||
if (inventoryHasData.value) {
|
||||
chart.setOption({
|
||||
color: ['#1677ff', '#16a085', '#f59e0b', '#7c5cff', '#ef6a6a', '#8c9bab'],
|
||||
tooltip: { trigger: 'item', formatter: '{b}<br/>{c} 个托盘({d}%)' },
|
||||
color: ['#008596', '#0284c7', '#10b981', '#f59e0b', '#8b5cf6', '#64748b'],
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{b}<br/>{c} 个托盘({d}%)',
|
||||
backgroundColor: settingsStore.isDark ? 'rgba(23, 27, 34, 0.95)' : 'rgba(255, 255, 255, 0.96)',
|
||||
borderColor: settingsStore.isDark ? '#374151' : '#e2e8f0',
|
||||
textStyle: { color: settingsStore.isDark ? '#f1f5f9' : '#1e293b' }
|
||||
},
|
||||
legend: { bottom: 0, type: 'scroll', textStyle: { color: chartTextColor() } },
|
||||
series: [{ type: 'pie', radius: ['46%', '72%'], center: ['50%', '44%'], avoidLabelOverlap: true, itemStyle: { borderColor: settingsStore.isDark ? '#141414' : '#fff', borderWidth: 3 }, label: { color: chartTextColor(), formatter: '{b}\n{c}' }, data: inventoryStateSummary.value }]
|
||||
})
|
||||
@@ -481,26 +569,63 @@ onBeforeUnmount(() => {
|
||||
|
||||
.card-heading h2 { margin: 0; color: var(--el-text-color-primary); font-weight: 700; }
|
||||
.card-heading span { margin: 8px 0 0; color: var(--el-text-color-secondary); font-size: 13px; }
|
||||
.dashboard-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 20px;
|
||||
padding: 4px 2px;
|
||||
|
||||
.header-left {
|
||||
.page-title {
|
||||
margin: 0;
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.5px;
|
||||
color: var(--el-text-color-primary, #1e293b);
|
||||
}
|
||||
|
||||
.page-desc {
|
||||
margin: 6px 0 0;
|
||||
font-size: 13px;
|
||||
color: var(--el-text-color-secondary, #64748b);
|
||||
}
|
||||
}
|
||||
|
||||
.header-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
}
|
||||
.dashboard-alert { display: flex; align-items: center; gap: 8px; margin-bottom: 16px; padding: 10px 14px; border: 1px solid var(--el-color-warning-light-5); border-radius: 10px; background: var(--el-color-warning-light-9); color: var(--el-color-warning-dark-2); font-size: 13px; }
|
||||
.dashboard-alert .el-button { margin-left: auto; }
|
||||
|
||||
.kpi-grid { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 14px; margin-bottom: 20px; }
|
||||
.kpi-card { display: flex; align-items: flex-start; gap: 14px; min-height: 124px; padding: 20px; border: 1px solid var(--el-border-color-lighter); border-radius: 14px; background: var(--el-bg-color, #fff); box-shadow: 0 5px 18px rgba(31, 55, 88, .05); }
|
||||
.kpi-card { display: flex; align-items: flex-start; gap: 14px; min-height: 124px; padding: 20px; border: 1px solid var(--el-border-color-lighter); border-radius: 14px; background: var(--el-bg-color, #fff); box-shadow: 0 4px 16px rgba(15, 34, 58, 0.04); transition: transform 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease; }
|
||||
.kpi-card:hover { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(15, 34, 58, 0.08); border-color: var(--el-color-primary-light-7, #b2e0e6); }
|
||||
.kpi-icon, .quick-action-icon, .activity-icon, .exception-icon { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; border-radius: 12px; }
|
||||
.kpi-icon { width: 42px; height: 42px; font-size: 21px; }
|
||||
.kpi-card--blue .kpi-icon { background: #e9f2ff; color: #1677ff; }.kpi-card--green .kpi-icon { background: #e8f8f2; color: #16a085; }.kpi-card--cyan .kpi-icon { background: #e7f8fb; color: #0891b2; }.kpi-card--orange .kpi-icon { background: #fff2df; color: #d97706; }.kpi-card--red .kpi-icon { background: #ffeded; color: #e25555; }
|
||||
.kpi-content { min-width: 0; }.kpi-label { display: block; color: var(--el-text-color-secondary); font-size: 13px; }.kpi-content strong { display: block; margin: 7px 0 2px; font-size: 28px; line-height: 1; }.kpi-caption { color: var(--el-text-color-placeholder); font-size: 12px; }
|
||||
.kpi-card--blue .kpi-icon { background: linear-gradient(135deg, #e0f2fe 0%, #bae6fd 100%); color: #0284c7; }.kpi-card--green .kpi-icon { background: linear-gradient(135deg, #dcfce7 0%, #bbf7d0 100%); color: #16a34a; }.kpi-card--cyan .kpi-icon { background: linear-gradient(135deg, #e0f7fa 0%, #b2ebf2 100%); color: #008596; }.kpi-card--orange .kpi-icon { background: linear-gradient(135deg, #ffedd5 0%, #fed7aa 100%); color: #ea580c; }.kpi-card--red .kpi-icon { background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%); color: #dc2626; }
|
||||
html.dark {
|
||||
.kpi-card--blue .kpi-icon { background: rgba(2, 132, 199, 0.2); color: #38bdf8; }
|
||||
.kpi-card--green .kpi-icon { background: rgba(22, 163, 74, 0.2); color: #4ade80; }
|
||||
.kpi-card--cyan .kpi-icon { background: rgba(0, 133, 150, 0.2); color: #22d3ee; }
|
||||
.kpi-card--orange .kpi-icon { background: rgba(234, 88, 12, 0.2); color: #fb923c; }
|
||||
.kpi-card--red .kpi-icon { background: rgba(220, 38, 38, 0.2); color: #f87171; }
|
||||
}
|
||||
.kpi-content { min-width: 0; }.kpi-label { display: block; color: var(--el-text-color-secondary); font-size: 13px; }.kpi-content strong { display: block; margin: 7px 0 2px; font-size: 28px; line-height: 1; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; font-variant-numeric: tabular-nums; font-weight: 700; color: var(--el-text-color-primary); }.kpi-caption { color: var(--el-text-color-placeholder); font-size: 12px; }
|
||||
|
||||
.dashboard-section, .dashboard-card { border: 1px solid var(--el-border-color-lighter); border-radius: 14px; background: var(--el-bg-color, #fff); box-shadow: 0 5px 18px rgba(31, 55, 88, .04); }
|
||||
.quick-section { margin-bottom: 20px; padding: 20px; }.card-heading h2 { font-size: 17px; }
|
||||
.quick-action-grid { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 10px; }.quick-action { display: flex; align-items: center; gap: 10px; min-width: 0; padding: 12px; border: 1px solid var(--el-border-color-lighter); border-radius: 10px; background: transparent; color: inherit; text-align: left; cursor: pointer; transition: border-color .2s ease, background-color .2s ease, transform .2s ease; }.quick-action:hover { border-color: var(--el-color-primary-light-5); background: var(--el-color-primary-light-9); transform: translateY(-1px); }.quick-action-icon { width: 34px; height: 34px; background: var(--el-color-primary-light-9); color: var(--el-color-primary); font-size: 18px; }.quick-action-copy { display: flex; flex-direction: column; min-width: 0; gap: 3px; }.quick-action-copy strong { font-size: 13px; white-space: nowrap; }.quick-action-copy small { overflow: hidden; color: var(--el-text-color-secondary); font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }.quick-action-arrow { margin-left: auto; color: var(--el-text-color-placeholder); }
|
||||
.quick-action-grid { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 10px; }.quick-action { display: flex; align-items: center; gap: 10px; min-width: 0; padding: 12px 14px; border: 1px solid var(--el-border-color-lighter); border-radius: 12px; background: var(--el-bg-color, #fff); color: inherit; text-align: left; cursor: pointer; transition: all 0.2s ease; }.quick-action:hover { border-color: var(--el-color-primary-light-5); background: var(--el-color-primary-light-9); transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0, 133, 150, 0.08); }.quick-action:hover .quick-action-arrow { transform: translateX(3px); color: var(--el-color-primary); }.quick-action-icon { width: 34px; height: 34px; background: var(--el-color-primary-light-9); color: var(--el-color-primary); font-size: 18px; }.quick-action-copy { display: flex; flex-direction: column; min-width: 0; gap: 3px; }.quick-action-copy strong { font-size: 13px; white-space: nowrap; }.quick-action-copy small { overflow: hidden; color: var(--el-text-color-secondary); font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }.quick-action-arrow { margin-left: auto; color: var(--el-text-color-placeholder); transition: transform 0.2s ease, color 0.2s ease; }
|
||||
|
||||
.dashboard-grid { display: grid; gap: 20px; margin-bottom: 20px; }.chart-grid { grid-template-columns: minmax(0, 1.55fr) minmax(340px, 1fr); }.operational-grid { grid-template-columns: minmax(0, 1.1fr) minmax(360px, .9fr); }.activity-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); margin-bottom: 0; }.dashboard-card :deep(.el-card__header) { padding: 18px 20px; border-bottom-color: var(--el-border-color-lighter); }.dashboard-card :deep(.el-card__body) { padding: 18px 20px; }.dashboard-card { overflow: hidden; }.card-heading { justify-content: space-between; gap: 12px; }.card-heading > div { min-width: 0; }.card-heading span { display: block; margin-top: 5px; font-size: 12px; }
|
||||
.trend-range-select { width: 112px; flex: 0 0 auto; }.chart-wrapper { position: relative; min-height: 290px; }.chart-wrapper--distribution { min-height: 290px; }.chart-canvas { width: 100%; height: 290px; }.chart-loading, .chart-empty { position: absolute; inset: 20px; }
|
||||
|
||||
.warehouse-ranking, .pending-list, .activity-list { min-height: 250px; }.warehouse-row { display: flex; align-items: center; gap: 12px; padding: 12px 0; }.warehouse-row + .warehouse-row { border-top: 1px solid var(--el-border-color-lighter); }.warehouse-rank { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; border-radius: 7px; background: var(--el-fill-color-light); color: var(--el-text-color-secondary); font-size: 12px; font-weight: 700; }.warehouse-rank--top { background: var(--el-color-primary-light-9); color: var(--el-color-primary); }.warehouse-main { flex: 1; min-width: 0; }.warehouse-title { justify-content: space-between; gap: 10px; margin-bottom: 8px; font-size: 13px; }.warehouse-title span { color: var(--el-text-color-placeholder); font-size: 12px; }.warehouse-value { flex: 0 0 84px; color: var(--el-text-color-primary); font-size: 13px; text-align: right; }
|
||||
.pending-item, .activity-item { display: flex; align-items: center; width: 100%; gap: 10px; padding: 12px 0; border: 0; border-bottom: 1px solid var(--el-border-color-lighter); background: transparent; color: inherit; text-align: left; cursor: pointer; }.pending-item:last-child, .activity-item:last-child { border-bottom: 0; }.pending-item:hover .pending-copy strong, .activity-item:hover .activity-copy strong { color: var(--el-color-primary); }.pending-dot { width: 8px; height: 8px; border-radius: 50%; }.pending-dot--orange { background: #f59e0b; }.pending-dot--blue { background: #1677ff; }.pending-dot--green { background: #16a085; }.pending-copy, .activity-copy { display: flex; flex: 1; flex-direction: column; min-width: 0; gap: 4px; }.pending-copy strong, .activity-copy strong { overflow: hidden; font-size: 13px; text-overflow: ellipsis; white-space: nowrap; }.pending-copy small, .activity-copy small { color: var(--el-text-color-secondary); font-size: 12px; }.activity-icon { width: 34px; height: 34px; font-size: 16px; }.activity-icon--inbound { background: #eaf3ff; color: #1677ff; }.activity-icon--outbound { background: #fff1e8; color: #d97706; }.activity-quantity { color: var(--el-color-primary); font-size: 12px; font-weight: 700; white-space: nowrap; }
|
||||
.exception-empty { display: flex; min-height: 250px; flex-direction: column; align-items: center; justify-content: center; gap: 8px; color: var(--el-text-color-secondary); text-align: center; }.exception-icon { width: 52px; height: 52px; margin-bottom: 5px; background: var(--el-color-success-light-9); color: var(--el-color-success); font-size: 26px; }.exception-empty strong { color: var(--el-text-color-primary); font-size: 14px; }.exception-empty span { max-width: 230px; font-size: 12px; line-height: 1.6; }
|
||||
.pending-item, .activity-item { display: flex; align-items: center; width: 100%; gap: 10px; padding: 12px 8px; border: 0; border-bottom: 1px solid var(--el-border-color-lighter); background: transparent; color: inherit; text-align: left; cursor: pointer; transition: all 0.2s ease; border-radius: 8px; }.pending-item:last-child, .activity-item:last-child { border-bottom: 0; }.pending-item:hover, .activity-item:hover { background: var(--el-fill-color-light, #f8fafc); }.pending-item:hover .pending-copy strong, .activity-item:hover .activity-copy strong { color: var(--el-color-primary); }.pending-dot { width: 8px; height: 8px; border-radius: 50%; }.pending-dot--orange { background: #f59e0b; }.pending-dot--blue { background: #1677ff; }.pending-dot--green { background: #16a085; }.pending-copy, .activity-copy { display: flex; flex: 1; flex-direction: column; min-width: 0; gap: 4px; }.pending-copy strong, .activity-copy strong { overflow: hidden; font-size: 13px; text-overflow: ellipsis; white-space: nowrap; }.pending-copy small, .activity-copy small { color: var(--el-text-color-secondary); font-size: 12px; }.activity-icon { width: 34px; height: 34px; font-size: 16px; }.activity-icon--inbound { background: #eaf3ff; color: #1677ff; }.activity-icon--outbound { background: #fff1e8; color: #d97706; }.activity-quantity { color: var(--el-color-primary); font-size: 12px; font-weight: 700; white-space: nowrap; }
|
||||
.exception-list { min-height: 250px; }.exception-item { display: flex; align-items: flex-start; gap: 10px; padding: 12px 0; border-bottom: 1px solid var(--el-border-color-lighter); }.exception-item:last-child { border-bottom: 0; }.exception-copy { display: flex; flex: 1; min-width: 0; flex-direction: column; gap: 4px; }.exception-copy strong { overflow: hidden; font-size: 13px; text-overflow: ellipsis; white-space: nowrap; }.exception-copy small { color: var(--el-text-color-secondary); font-size: 12px; }.exception-message { overflow: hidden; color: var(--el-text-color-secondary); font-size: 12px; line-height: 1.5; text-overflow: ellipsis; white-space: nowrap; }.exception-more { padding-top: 10px; color: var(--el-text-color-placeholder); font-size: 12px; text-align: center; }.exception-empty { display: flex; min-height: 250px; flex-direction: column; align-items: center; justify-content: center; gap: 8px; color: var(--el-text-color-secondary); text-align: center; }.exception-icon { width: 52px; height: 52px; margin-bottom: 5px; background: var(--el-color-success-light-9); color: var(--el-color-success); font-size: 26px; }.exception-icon--danger { width: 34px; height: 34px; margin: 0; border-radius: 10px; background: var(--el-color-danger-light-9); color: var(--el-color-danger); font-size: 17px; }.exception-icon--warning { background: var(--el-color-warning-light-9); color: var(--el-color-warning); }.exception-empty strong { color: var(--el-text-color-primary); font-size: 14px; }.exception-empty span { max-width: 230px; font-size: 12px; line-height: 1.6; }
|
||||
|
||||
@media (max-width: 1280px) { .kpi-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }.quick-action-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }.activity-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }.activity-card:last-child { grid-column: span 2; } }
|
||||
@media (max-width: 900px) { .dashboard-page { padding: 16px; }.chart-grid, .operational-grid { grid-template-columns: 1fr; } }
|
||||
|
||||
@@ -1,68 +1,101 @@
|
||||
<template>
|
||||
<div class="login">
|
||||
<el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
|
||||
<h3 class="title">{{ title }}</h3>
|
||||
<el-form-item prop="username">
|
||||
<el-input
|
||||
v-model="loginForm.username"
|
||||
type="text"
|
||||
size="large"
|
||||
auto-complete="off"
|
||||
placeholder="账号"
|
||||
>
|
||||
<template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password">
|
||||
<el-input
|
||||
v-model="loginForm.password"
|
||||
type="password"
|
||||
size="large"
|
||||
auto-complete="off"
|
||||
placeholder="密码"
|
||||
@keyup.enter="handleLogin"
|
||||
>
|
||||
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="code" v-if="captchaEnabled">
|
||||
<el-input
|
||||
v-model="loginForm.code"
|
||||
size="large"
|
||||
auto-complete="off"
|
||||
placeholder="验证码"
|
||||
style="width: 63%"
|
||||
@keyup.enter="handleLogin"
|
||||
>
|
||||
<template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
|
||||
</el-input>
|
||||
<div class="login-code">
|
||||
<img :src="codeUrl" @click="getCode" class="login-code-img"/>
|
||||
<div class="login login-wrapper">
|
||||
<canvas ref="canvasRef" class="bg-canvas"></canvas>
|
||||
<div class="noise-overlay"></div>
|
||||
<div class="login-box">
|
||||
<div class="login-card">
|
||||
<div class="brand-header">
|
||||
<div class="brand-logo-wrap">
|
||||
<img :src="brandLogoLight" :alt="title" class="brand-logo brand-logo-light" />
|
||||
<img :src="brandLogoDark" :alt="title" class="brand-logo brand-logo-dark" />
|
||||
</div>
|
||||
<h3 class="system-title title">{{ title }}</h3>
|
||||
<div class="feature-badges">
|
||||
<span class="badge-item">托盘全流程追溯</span>
|
||||
<span class="badge-divider">·</span>
|
||||
<span class="badge-item">智能防错防漏</span>
|
||||
<span class="badge-divider">·</span>
|
||||
<span class="badge-item">动态精益运营</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
|
||||
<el-form-item style="width:100%;">
|
||||
<el-button
|
||||
:loading="loading"
|
||||
size="large"
|
||||
type="primary"
|
||||
style="width:100%;"
|
||||
@click.prevent="handleLogin"
|
||||
>
|
||||
<span v-if="!loading">登 录</span>
|
||||
<span v-else>登 录 中...</span>
|
||||
</el-button>
|
||||
<div style="float: right;" v-if="register">
|
||||
<router-link class="link-type" :to="'/register'">立即注册</router-link>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
|
||||
<el-form-item prop="username" class="custom-field">
|
||||
<el-input
|
||||
v-model="loginForm.username"
|
||||
type="text"
|
||||
size="large"
|
||||
auto-complete="off"
|
||||
placeholder="账号"
|
||||
>
|
||||
<template #prefix>
|
||||
<svg-icon icon-class="user" class="input-icon" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="password" class="custom-field">
|
||||
<el-input
|
||||
v-model="loginForm.password"
|
||||
type="password"
|
||||
size="large"
|
||||
auto-complete="off"
|
||||
placeholder="密码"
|
||||
show-password
|
||||
@keyup.enter="handleLogin"
|
||||
>
|
||||
<template #prefix>
|
||||
<svg-icon icon-class="password" class="input-icon" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="code" v-if="captchaEnabled" class="custom-field captcha-form-item">
|
||||
<div class="captcha-flex-row">
|
||||
<el-input
|
||||
v-model="loginForm.code"
|
||||
size="large"
|
||||
auto-complete="off"
|
||||
placeholder="验证码"
|
||||
class="captcha-input"
|
||||
@keyup.enter="handleLogin"
|
||||
>
|
||||
<template #prefix>
|
||||
<svg-icon icon-class="validCode" class="input-icon" />
|
||||
</template>
|
||||
</el-input>
|
||||
<div class="login-code" @click="getCode" title="点击刷新验证码">
|
||||
<img :src="codeUrl" alt="验证码" class="login-code-img" />
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<div class="login-options-row">
|
||||
<el-checkbox v-model="loginForm.rememberMe">记住密码</el-checkbox>
|
||||
<router-link v-if="register" class="register-link" :to="'/register'">立即注册</router-link>
|
||||
</div>
|
||||
|
||||
<el-form-item class="submit-form-item">
|
||||
<el-button
|
||||
:loading="loading"
|
||||
size="large"
|
||||
type="primary"
|
||||
class="login-submit-btn"
|
||||
@click.prevent="handleLogin"
|
||||
>
|
||||
<span v-if="!loading">登 录</span>
|
||||
<span v-else>登 录 中...</span>
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 底部 -->
|
||||
<div class="el-login-footer">
|
||||
<span>{{ footerContent }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { getCodeImg } from "@/api/login";
|
||||
@@ -70,6 +103,8 @@ import Cookies from "js-cookie";
|
||||
import { encrypt, decrypt } from "@/utils/jsencrypt";
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import defaultSettings from '@/settings'
|
||||
import brandLogoDark from '@/assets/logo/sylvan-logo.svg'
|
||||
import brandLogoLight from '@/assets/logo/sylvan-logo-light.svg'
|
||||
|
||||
const title = import.meta.env.VITE_APP_TITLE;
|
||||
const footerContent = defaultSettings.footerContent
|
||||
@@ -162,83 +197,532 @@ function getCookie() {
|
||||
};
|
||||
}
|
||||
|
||||
const canvasRef = ref(null);
|
||||
let cleanupBackground = null;
|
||||
|
||||
class GeometricShape {
|
||||
constructor(anchorXRatio, anchorYRatio, radiusRatio, color, style = 'fill', ringCount = 1) {
|
||||
this.anchorXRatio = anchorXRatio;
|
||||
this.anchorYRatio = anchorYRatio;
|
||||
this.radiusRatio = radiusRatio;
|
||||
this.color = color;
|
||||
this.style = style;
|
||||
this.ringCount = ringCount;
|
||||
this.phaseX = Math.random() * Math.PI * 2;
|
||||
this.phaseY = Math.random() * Math.PI * 2;
|
||||
this.phaseR = Math.random() * Math.PI * 2;
|
||||
this.speed = 0.0003 + Math.random() * 0.0002;
|
||||
}
|
||||
|
||||
draw(ctx, w, h, t) {
|
||||
const baseX = w * this.anchorXRatio;
|
||||
const baseY = h * this.anchorYRatio;
|
||||
const maxDim = Math.max(w, h);
|
||||
const baseRadius = maxDim * this.radiusRatio;
|
||||
|
||||
const x = baseX + Math.sin(t * this.speed + this.phaseX) * (maxDim * 0.015);
|
||||
const y = baseY + Math.cos(t * this.speed * 0.8 + this.phaseY) * (maxDim * 0.015);
|
||||
const r = baseRadius + Math.sin(t * this.speed * 1.2 + this.phaseR) * (baseRadius * 0.03);
|
||||
|
||||
if (this.style === 'fill') {
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, r, 0, Math.PI * 2);
|
||||
ctx.fillStyle = this.color;
|
||||
ctx.fill();
|
||||
} else if (this.style === 'stroke') {
|
||||
for (let i = 0; i < this.ringCount; i++) {
|
||||
ctx.beginPath();
|
||||
const ringR = r + i * (maxDim * 0.025);
|
||||
ctx.arc(x, y, ringR, 0, Math.PI * 2);
|
||||
ctx.strokeStyle = this.color;
|
||||
ctx.lineWidth = 1.5;
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AmbientGlow {
|
||||
constructor(xRatio, yRatio, radiusRatio, r, g, b, maxOpacity, speedX, speedY) {
|
||||
this.xRatio = xRatio;
|
||||
this.yRatio = yRatio;
|
||||
this.radiusRatio = radiusRatio;
|
||||
this.color = `${r}, ${g}, ${b}`;
|
||||
this.maxOpacity = maxOpacity;
|
||||
this.speedX = speedX;
|
||||
this.speedY = speedY;
|
||||
this.phaseX = Math.random() * Math.PI * 2;
|
||||
this.phaseY = Math.random() * Math.PI * 2;
|
||||
}
|
||||
|
||||
draw(ctx, w, h, t) {
|
||||
const maxDim = Math.max(w, h);
|
||||
const radius = maxDim * this.radiusRatio;
|
||||
const x = w * this.xRatio + Math.sin(t * this.speedX + this.phaseX) * (w * 0.2);
|
||||
const y = h * this.yRatio + Math.cos(t * this.speedY + this.phaseY) * (h * 0.2);
|
||||
|
||||
const gradient = ctx.createRadialGradient(x, y, 0, x, y, radius);
|
||||
gradient.addColorStop(0, `rgba(${this.color}, ${this.maxOpacity})`);
|
||||
gradient.addColorStop(1, `rgba(${this.color}, 0)`);
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, radius, 0, Math.PI * 2);
|
||||
ctx.fillStyle = gradient;
|
||||
ctx.fill();
|
||||
}
|
||||
}
|
||||
|
||||
function initDynamicBackground() {
|
||||
const canvas = canvasRef.value;
|
||||
if (!canvas) return null;
|
||||
|
||||
const ctx = canvas.getContext('2d', { alpha: false });
|
||||
if (!ctx) return null;
|
||||
|
||||
let width = 0;
|
||||
let height = 0;
|
||||
let time = 0;
|
||||
let animationFrameId = null;
|
||||
|
||||
function resizeCanvas() {
|
||||
if (!canvas) return;
|
||||
width = window.innerWidth;
|
||||
height = window.innerHeight;
|
||||
const dpr = window.devicePixelRatio || 1;
|
||||
canvas.width = width * dpr;
|
||||
canvas.height = height * dpr;
|
||||
ctx.scale(dpr, dpr);
|
||||
}
|
||||
|
||||
window.addEventListener('resize', resizeCanvas);
|
||||
resizeCanvas();
|
||||
|
||||
const isDark = document.documentElement.classList.contains('dark');
|
||||
|
||||
const shapes = isDark ? [
|
||||
new GeometricShape(-0.02, 0.15, 0.35, '#162238', 'fill'),
|
||||
new GeometricShape(0.08, -0.05, 0.22, '#008596', 'fill'),
|
||||
new GeometricShape(-0.1, -0.1, 0.25, 'rgba(56, 189, 248, 0.08)', 'stroke', 6),
|
||||
new GeometricShape(0.85, 0.95, 0.25, '#162238', 'fill'),
|
||||
new GeometricShape(0.98, 0.88, 0.15, '#008596', 'fill'),
|
||||
new GeometricShape(1.05, 1.05, 0.15, 'rgba(56, 189, 248, 0.12)', 'stroke', 4),
|
||||
new GeometricShape(0.05, 1.0, 0.18, '#0e4e5e', 'fill'),
|
||||
new GeometricShape(0.95, -0.05, 0.2, '#008596', 'fill')
|
||||
] : [
|
||||
new GeometricShape(-0.02, 0.15, 0.35, '#262464', 'fill'),
|
||||
new GeometricShape(0.08, -0.05, 0.22, '#00A89D', 'fill'),
|
||||
new GeometricShape(-0.1, -0.1, 0.25, 'rgba(255, 255, 255, 0.08)', 'stroke', 6),
|
||||
new GeometricShape(0.85, 0.95, 0.25, '#262464', 'fill'),
|
||||
new GeometricShape(0.98, 0.88, 0.15, '#00A89D', 'fill'),
|
||||
new GeometricShape(1.05, 1.05, 0.15, 'rgba(0, 168, 157, 0.15)', 'stroke', 4),
|
||||
new GeometricShape(0.05, 1.0, 0.18, '#6ec6c2', 'fill'),
|
||||
new GeometricShape(0.95, -0.05, 0.2, '#00A89D', 'fill')
|
||||
];
|
||||
|
||||
const glows = isDark ? [
|
||||
new AmbientGlow(0.3, 0.7, 0.5, 0, 133, 150, 0.12, 0.0001, 0.00015),
|
||||
new AmbientGlow(0.7, 0.3, 0.6, 22, 34, 56, 0.18, 0.00012, 0.00008),
|
||||
new AmbientGlow(0.5, 0.5, 0.7, 14, 78, 94, 0.10, -0.00008, 0.00011)
|
||||
] : [
|
||||
new AmbientGlow(0.3, 0.7, 0.5, 0, 168, 157, 0.08, 0.0001, 0.00015),
|
||||
new AmbientGlow(0.7, 0.3, 0.6, 70, 80, 150, 0.06, 0.00012, 0.00008),
|
||||
new AmbientGlow(0.5, 0.5, 0.7, 110, 198, 194, 0.07, -0.00008, 0.00011)
|
||||
];
|
||||
|
||||
function drawBackground() {
|
||||
const isNowDark = document.documentElement.classList.contains('dark');
|
||||
ctx.fillStyle = isNowDark ? '#0b1420' : '#f0f6f7';
|
||||
ctx.fillRect(0, 0, width, height);
|
||||
}
|
||||
|
||||
function animate() {
|
||||
drawBackground();
|
||||
|
||||
glows.forEach(glow => {
|
||||
glow.draw(ctx, width, height, time);
|
||||
});
|
||||
|
||||
ctx.lineCap = 'round';
|
||||
ctx.lineJoin = 'round';
|
||||
|
||||
shapes.forEach(shape => {
|
||||
shape.draw(ctx, width, height, time);
|
||||
});
|
||||
|
||||
time += 16;
|
||||
animationFrameId = requestAnimationFrame(animate);
|
||||
}
|
||||
|
||||
animationFrameId = requestAnimationFrame(animate);
|
||||
|
||||
return () => {
|
||||
if (animationFrameId) {
|
||||
cancelAnimationFrame(animationFrameId);
|
||||
animationFrameId = null;
|
||||
}
|
||||
window.removeEventListener('resize', resizeCanvas);
|
||||
};
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
cleanupBackground = initDynamicBackground();
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (cleanupBackground) {
|
||||
cleanupBackground();
|
||||
cleanupBackground = null;
|
||||
}
|
||||
});
|
||||
|
||||
getCode();
|
||||
getCookie();
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
.login {
|
||||
.login-wrapper {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
width: 100vw;
|
||||
overflow: hidden;
|
||||
background-color: #f0f6f7;
|
||||
}
|
||||
|
||||
html.dark .login-wrapper {
|
||||
background-color: #0b1420;
|
||||
}
|
||||
|
||||
.bg-canvas {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.noise-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
opacity: 0.04;
|
||||
background: url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.login-box {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
width: 100%;
|
||||
max-width: 440px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.login-card {
|
||||
background: rgba(255, 255, 255, 0.90);
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.85);
|
||||
border-radius: 20px;
|
||||
padding: 38px 36px 30px;
|
||||
box-shadow: 0 20px 60px rgba(15, 34, 58, 0.12), 0 4px 16px rgba(15, 34, 58, 0.05);
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
html.dark .login-card {
|
||||
background: rgba(23, 27, 34, 0.92);
|
||||
border-color: rgba(255, 255, 255, 0.08);
|
||||
box-shadow: 0 24px 70px rgba(0, 0, 0, 0.55), 0 4px 16px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.brand-header {
|
||||
text-align: center;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.brand-logo-wrap {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
background-image: url("../assets/images/login-background.jpg");
|
||||
background-size: cover;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
html.dark .login {
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url("../assets/images/login-background.jpg");
|
||||
}
|
||||
.title {
|
||||
margin: 0px auto 30px auto;
|
||||
text-align: center;
|
||||
color: #707070;
|
||||
.brand-logo {
|
||||
height: 56px;
|
||||
max-width: 240px;
|
||||
object-fit: contain;
|
||||
filter: drop-shadow(0 4px 10px rgba(15, 34, 58, 0.08));
|
||||
transition: transform 0.25s ease, filter 0.25s ease;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-1px);
|
||||
filter: drop-shadow(0 6px 14px rgba(15, 34, 58, 0.12));
|
||||
}
|
||||
}
|
||||
|
||||
html.dark .title {
|
||||
color: var(--el-text-color-primary);
|
||||
.brand-logo-light {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.brand-logo-dark {
|
||||
display: none;
|
||||
}
|
||||
|
||||
html.dark {
|
||||
.brand-logo-light {
|
||||
display: none;
|
||||
}
|
||||
.brand-logo-dark {
|
||||
display: block;
|
||||
filter: drop-shadow(0 4px 12px rgba(56, 189, 248, 0.16));
|
||||
|
||||
&:hover {
|
||||
filter: drop-shadow(0 6px 16px rgba(56, 189, 248, 0.22));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.system-title {
|
||||
margin: 0;
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.5px;
|
||||
color: #1a2736;
|
||||
}
|
||||
|
||||
html.dark .system-title {
|
||||
color: #f1f5f9;
|
||||
}
|
||||
|
||||
.feature-badges {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
margin-top: 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.badge-item {
|
||||
font-size: 12px;
|
||||
color: #008596;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.2px;
|
||||
}
|
||||
|
||||
html.dark .badge-item {
|
||||
color: #38bdf8;
|
||||
}
|
||||
|
||||
.badge-divider {
|
||||
color: #cbd5e1;
|
||||
font-size: 12px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
html.dark .badge-divider {
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
.login-form {
|
||||
border-radius: 6px;
|
||||
background: #ffffff;
|
||||
width: 400px;
|
||||
padding: 25px 25px 5px 25px;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
.el-input {
|
||||
height: 40px;
|
||||
input {
|
||||
height: 40px;
|
||||
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
:deep(.el-input__wrapper) {
|
||||
border-radius: 10px;
|
||||
padding: 2px 14px;
|
||||
height: 44px;
|
||||
box-shadow: 0 0 0 1px #dcdfe6 inset;
|
||||
transition: box-shadow 0.2s ease, border-color 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 0 0 1px #b0b8c4 inset;
|
||||
}
|
||||
|
||||
&.is-focus {
|
||||
box-shadow: 0 0 0 2px #008596 inset !important;
|
||||
}
|
||||
}
|
||||
|
||||
.input-icon {
|
||||
height: 39px;
|
||||
width: 14px;
|
||||
margin-left: 0px;
|
||||
font-size: 16px;
|
||||
color: #008596;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
:deep(.el-input__password) {
|
||||
color: #94a3b8;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
color: #008596;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
html.dark .login-form {
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
.login-tip {
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
color: #bfbfbf;
|
||||
}
|
||||
.login-code {
|
||||
width: 33%;
|
||||
height: 40px;
|
||||
float: right;
|
||||
img {
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
:deep(.el-input__wrapper) {
|
||||
background-color: #1a202c;
|
||||
box-shadow: 0 0 0 1px #374151 inset;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 0 0 1px #4b5563 inset;
|
||||
}
|
||||
|
||||
&.is-focus {
|
||||
box-shadow: 0 0 0 2px #38bdf8 inset !important;
|
||||
}
|
||||
}
|
||||
|
||||
.input-icon {
|
||||
color: #38bdf8;
|
||||
}
|
||||
|
||||
:deep(.el-input__password) {
|
||||
color: #64748b;
|
||||
|
||||
&:hover {
|
||||
color: #38bdf8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.captcha-flex-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.captcha-input {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.login-code {
|
||||
width: 120px;
|
||||
height: 44px;
|
||||
flex: 0 0 120px;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
border: 1px solid #dcdfe6;
|
||||
background: #f8fafc;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: opacity 0.2s ease, border-color 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.9;
|
||||
border-color: #008596;
|
||||
}
|
||||
|
||||
.login-code-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
html.dark .login-code {
|
||||
background: #1a202c;
|
||||
border-color: #374151;
|
||||
}
|
||||
|
||||
.login-options-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: -4px 0 18px;
|
||||
padding: 0 2px;
|
||||
}
|
||||
|
||||
.register-link {
|
||||
color: #008596;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
transition: color 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
color: #0ea5e9;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
html.dark .register-link {
|
||||
color: #38bdf8;
|
||||
}
|
||||
|
||||
.submit-form-item {
|
||||
margin-bottom: 6px !important;
|
||||
}
|
||||
|
||||
.login-submit-btn {
|
||||
width: 100%;
|
||||
height: 46px;
|
||||
border-radius: 10px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 2px;
|
||||
border: none;
|
||||
background: linear-gradient(135deg, #008596 0%, #0284c7 100%);
|
||||
box-shadow: 0 8px 22px rgba(0, 133, 150, 0.32);
|
||||
transition: all 0.25s ease;
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(135deg, #009cb0 0%, #0396dc 100%);
|
||||
box-shadow: 0 10px 26px rgba(0, 133, 150, 0.42);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: translateY(1px);
|
||||
box-shadow: 0 4px 12px rgba(0, 133, 150, 0.28);
|
||||
}
|
||||
}
|
||||
|
||||
.el-login-footer {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
position: absolute;
|
||||
bottom: 16px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
font-family: Arial;
|
||||
color: #64748b;
|
||||
font-family: inherit;
|
||||
font-size: 12px;
|
||||
letter-spacing: 1px;
|
||||
letter-spacing: 0.5px;
|
||||
z-index: 2;
|
||||
}
|
||||
.login-code-img {
|
||||
height: 40px;
|
||||
padding-left: 12px;
|
||||
|
||||
html.dark .el-login-footer {
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.login-box {
|
||||
padding: 14px;
|
||||
}
|
||||
.login-card {
|
||||
padding: 28px 20px 22px;
|
||||
border-radius: 16px;
|
||||
}
|
||||
.system-title {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user