fix: 登录界面错误信息提示显示优化

This commit is contained in:
ssongliu 2022-12-05 11:12:07 +08:00 committed by ssongliu
parent 89b96a5b75
commit 1cad44c33d
17 changed files with 225 additions and 180 deletions

View file

@ -2,16 +2,15 @@ package helper
import ( import (
"fmt" "fmt"
"github.com/1Panel-dev/1Panel/backend/buserr"
"net/http" "net/http"
"strconv" "strconv"
"github.com/pkg/errors"
"github.com/1Panel-dev/1Panel/backend/app/dto" "github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant" "github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/i18n" "github.com/1Panel-dev/1Panel/backend/i18n"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/pkg/errors"
) )
func GeneratePaginationFromReq(c *gin.Context) (*dto.PageInfo, bool) { func GeneratePaginationFromReq(c *gin.Context) (*dto.PageInfo, bool) {
@ -35,30 +34,32 @@ func GeneratePaginationFromReq(c *gin.Context) (*dto.PageInfo, bool) {
func ErrorWithDetail(ctx *gin.Context, code int, msgKey string, err error) { func ErrorWithDetail(ctx *gin.Context, code int, msgKey string, err error) {
res := dto.Response{ res := dto.Response{
Code: code, Code: code,
Msg: "", Message: "",
} }
if msgKey == constant.ErrTypeInternalServer { if msgKey == constant.ErrTypeInternalServer {
switch { switch {
case errors.Is(err, constant.ErrRecordExist): case errors.Is(err, constant.ErrRecordExist):
res.Msg = i18n.GetMsgWithMap("ErrRecordExist", map[string]interface{}{"detail": err}) res.Message = i18n.GetMsgWithMap("ErrRecordExist", map[string]interface{}{"detail": err})
case errors.Is(constant.ErrRecordNotFound, err): case errors.Is(constant.ErrRecordNotFound, err):
res.Msg = i18n.GetMsgWithMap("ErrRecordNotFound", map[string]interface{}{"detail": err}) res.Message = i18n.GetMsgWithMap("ErrRecordNotFound", map[string]interface{}{"detail": err})
case errors.Is(constant.ErrStructTransform, err): case errors.Is(constant.ErrStructTransform, err):
res.Msg = i18n.GetMsgWithMap("ErrStructTransform", map[string]interface{}{"detail": err}) res.Message = i18n.GetMsgWithMap("ErrStructTransform", map[string]interface{}{"detail": err})
case errors.Is(constant.ErrCaptchaCode, err): case errors.Is(constant.ErrCaptchaCode, err):
res.Msg = i18n.GetMsgWithMap("ErrCaptchaCode", map[string]interface{}{"detail": err}) res.Code = constant.CodeAuth
res.Message = "ErrCaptchaCode"
case errors.Is(constant.ErrAuth, err): case errors.Is(constant.ErrAuth, err):
res.Msg = i18n.GetMsgWithMap("ErrAuth", map[string]interface{}{"detail": err}) res.Code = constant.CodeAuth
res.Message = "ErrAuth"
case errors.Is(constant.ErrInitialPassword, err): case errors.Is(constant.ErrInitialPassword, err):
res.Msg = i18n.GetMsgWithMap("ErrInitialPassword", map[string]interface{}{"detail": err}) res.Message = i18n.GetMsgWithMap("ErrInitialPassword", map[string]interface{}{"detail": err})
case errors.As(err, &buserr.BusinessError{}): case errors.As(err, &buserr.BusinessError{}):
res.Msg = err.Error() res.Message = err.Error()
default: default:
res.Msg = i18n.GetMsgWithMap(msgKey, map[string]interface{}{"detail": err}) res.Message = i18n.GetMsgWithMap(msgKey, map[string]interface{}{"detail": err})
} }
} else { } else {
res.Msg = i18n.GetMsgWithMap(msgKey, map[string]interface{}{"detail": err}) res.Message = i18n.GetMsgWithMap(msgKey, map[string]interface{}{"detail": err})
} }
ctx.JSON(http.StatusOK, res) ctx.JSON(http.StatusOK, res)
ctx.Abort() ctx.Abort()
@ -78,8 +79,8 @@ func SuccessWithData(ctx *gin.Context, data interface{}) {
func SuccessWithMsg(ctx *gin.Context, msg string) { func SuccessWithMsg(ctx *gin.Context, msg string) {
res := dto.Response{ res := dto.Response{
Code: constant.CodeSuccess, Code: constant.CodeSuccess,
Msg: msg, Message: msg,
} }
ctx.JSON(http.StatusOK, res) ctx.JSON(http.StatusOK, res)
ctx.Abort() ctx.Abort()

View file

@ -6,9 +6,9 @@ type PageResult struct {
} }
type Response struct { type Response struct {
Code int `json:"code"` Code int `json:"code"`
Msg string `json:"msg"` Message string `json:"message"`
Data interface{} `json:"data"` Data interface{} `json:"data"`
} }
type Options struct { type Options struct {

View file

@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"os/exec" "os/exec"
"strings"
"time" "time"
"github.com/1Panel-dev/1Panel/backend/app/dto" "github.com/1Panel-dev/1Panel/backend/app/dto"
@ -43,10 +44,10 @@ func (u *DashboardService) LoadBaseInfo(ioOption string, netOption string) (*dto
cmd := exec.Command("uptime", "-s") cmd := exec.Command("uptime", "-s")
stdout, err := cmd.CombinedOutput() stdout, err := cmd.CombinedOutput()
if err != nil { if err == nil {
baseInfo.Uptime = string(stdout) baseInfo.Uptime = string(stdout)
uptime, err := time.Parse("2006-01-02 15:04:05", string(stdout)) uptime, err := time.Parse("2006-01-02 15:04:05", strings.ReplaceAll(string(stdout), "\n", ""))
if err != nil { if err == nil {
hours := int(time.Since(uptime).Hours()) hours := int(time.Since(uptime).Hours())
minutes := int(time.Since(uptime).Minutes()) minutes := int(time.Since(uptime).Minutes())
baseInfo.TimeSinceUptime = fmt.Sprintf("%ddays %dhours %dmimutes", hours/24, hours%24, minutes-hours*60) baseInfo.TimeSinceUptime = fmt.Sprintf("%ddays %dhours %dmimutes", hours/24, hours%24, minutes-hours*60)

View file

@ -65,7 +65,7 @@ func (u *LogService) PageOperationLog(search dto.PageInfo) (int64, interface{},
} }
item.Status = res.Code item.Status = res.Code
if item.Status != 200 { if item.Status != 200 {
item.ErrorMessage = res.Msg item.ErrorMessage = res.Message
} }
dtoOps = append(dtoOps, item) dtoOps = append(dtoOps, item)
} }

View file

@ -12,6 +12,7 @@ const (
CodeErrForbidden = 403 CodeErrForbidden = 403
CodeErrNotFound = 404 CodeErrNotFound = 404
CodePasswordExpired = 405 CodePasswordExpired = 405
CodeAuth = 406
CodeErrInternalServer = 500 CodeErrInternalServer = 500
CodeErrHeader = 406 CodeErrHeader = 406
) )

View file

@ -2,8 +2,6 @@ ErrInvalidParams: "Request parameter error: {{ .detail }}"
ErrToken: "Token information is incorrect.: {{ .detail }}" ErrToken: "Token information is incorrect.: {{ .detail }}"
ErrTokenParse: "Token generation error: {{ .detail }}" ErrTokenParse: "Token generation error: {{ .detail }}"
ErrTokenTimeOut: "Login information is out of date: {{ .detail }}" ErrTokenTimeOut: "Login information is out of date: {{ .detail }}"
ErrAuth: "Login information is incorrect."
ErrCaptchaCode: "The verification code information is incorrect"
ErrInitialPassword: "Initial password error" ErrInitialPassword: "Initial password error"
ErrInternalServer: "Service internal error: {{ .detail }}" ErrInternalServer: "Service internal error: {{ .detail }}"
ErrRecordExist: "Record already exists: {{ .detail }}" ErrRecordExist: "Record already exists: {{ .detail }}"

View file

@ -2,8 +2,6 @@ ErrInvalidParams: "请求参数错误: {{ .detail }}"
ErrToken: "Token 信息错误: {{ .detail }}" ErrToken: "Token 信息错误: {{ .detail }}"
ErrTokenParse: "Token 生成错误: {{ .detail }}" ErrTokenParse: "Token 生成错误: {{ .detail }}"
ErrTokenTimeOut: "登陆信息已过期: {{ .detail }}" ErrTokenTimeOut: "登陆信息已过期: {{ .detail }}"
ErrAuth: "登录信息错误"
ErrCaptchaCode: "错误的验证码信息"
ErrInitialPassword: "原密码错误" ErrInitialPassword: "原密码错误"
ErrInternalServer: "服务内部错误: {{ .detail }}" ErrInternalServer: "服务内部错误: {{ .detail }}"
ErrRecordExist: "记录已存在: {{ .detail }}" ErrRecordExist: "记录已存在: {{ .detail }}"

View file

@ -59,6 +59,9 @@ class RequestHttp {
router.push({ name: 'Expired' }); router.push({ name: 'Expired' });
return data; return data;
} }
if (data.code == ResultEnum.ERRAUTH) {
return data;
}
if (data.code && data.code !== ResultEnum.SUCCESS) { if (data.code && data.code !== ResultEnum.SUCCESS) {
ElMessage.error(data.msg); ElMessage.error(data.msg);
return Promise.reject(data); return Promise.reject(data);

View file

@ -5,6 +5,7 @@ export enum ResultEnum {
UNSAFETY = 402, UNSAFETY = 402,
FORBIDDEN = 403, FORBIDDEN = 403,
EXPIRED = 405, EXPIRED = 405,
ERRAUTH = 406,
TIMEOUT = 100000, TIMEOUT = 100000,
TYPE = 'success', TYPE = 'success',
} }

View file

@ -80,7 +80,9 @@ export default {
password: 'Password', password: 'Password',
rePassword: 'Confirm Password', rePassword: 'Confirm Password',
welcome: 'Welcome back, please enter your username and password to log in!', welcome: 'Welcome back, please enter your username and password to log in!',
errorAuthInfo: 'The user name or password you entered is incorrect, please re-enter!',
captchaHelper: 'Please enter the verification code', captchaHelper: 'Please enter the verification code',
errorCaptcha: 'Incorrect verification code information!',
safeEntrance: 'Please use the correct entry to log in to the panel', safeEntrance: 'Please use the correct entry to log in to the panel',
reason: 'Cause of error:', reason: 'Cause of error:',
reasonHelper: reasonHelper:
@ -165,6 +167,9 @@ export default {
time: 'Times', time: 'Times',
uptime: 'Up Time', uptime: 'Up Time',
runningTime: 'Running Time', runningTime: 'Running Time',
Day: 'Days',
Hour: 'Hours',
Minute: 'Minutes',
runSmoothly: 'Run smoothly', runSmoothly: 'Run smoothly',
runNormal: 'Run normal', runNormal: 'Run normal',

View file

@ -82,7 +82,9 @@ export default {
password: '密码', password: '密码',
rePassword: '确认密码', rePassword: '确认密码',
welcome: '欢迎回来请输入用户名和密码登录', welcome: '欢迎回来请输入用户名和密码登录',
errorAuthInfo: '您输入的用户名或密码不正确请重新输入',
captchaHelper: '请输入验证码', captchaHelper: '请输入验证码',
errorCaptcha: '错误的验证码信息',
safeEntrance: '请使用正确的入口登录面板', safeEntrance: '请使用正确的入口登录面板',
reason: '错误原因', reason: '错误原因',
reasonHelper: reasonHelper:
@ -171,6 +173,9 @@ export default {
time: '次', time: '次',
uptime: '启动时间', uptime: '启动时间',
runningTime: '运行时间', runningTime: '运行时间',
Day: '天',
Hour: '小时',
Minute: '分钟',
runSmoothly: '运行流畅', runSmoothly: '运行流畅',
runNormal: '运行正常', runNormal: '运行正常',

View file

@ -125,6 +125,16 @@
display: inline-block; display: inline-block;
} }
.input-error {
font-size: 12px;
word-break: break-all;
color: red;
transform: scale(0.9);
transform-origin: left;
width: 110%;
display: inline-block;
}
.myTable { .myTable {
border-collapse: collapse; border-collapse: collapse;
font-size: 12px; font-size: 12px;

View file

@ -5,6 +5,14 @@
<el-radio-button class="topButton" size="large" @click="routerTo('/containers')" label="container"> <el-radio-button class="topButton" size="large" @click="routerTo('/containers')" label="container">
{{ $t('container.container') }} {{ $t('container.container') }}
</el-radio-button> </el-radio-button>
<el-radio-button
class="topButton"
size="large"
@click="routerTo('/containers/compose')"
label="compose"
>
{{ $t('container.compose') }}
</el-radio-button>
<el-radio-button class="topButton" size="large" @click="routerTo('/containers/image')" label="image"> <el-radio-button class="topButton" size="large" @click="routerTo('/containers/image')" label="image">
{{ $t('container.image') }} {{ $t('container.image') }}
</el-radio-button> </el-radio-button>
@ -22,14 +30,6 @@
<el-radio-button class="topButton" size="large" @click="routerTo('/containers/repo')" label="repo"> <el-radio-button class="topButton" size="large" @click="routerTo('/containers/repo')" label="repo">
{{ $t('container.repo') }} {{ $t('container.repo') }}
</el-radio-button> </el-radio-button>
<el-radio-button
class="topButton"
size="large"
@click="routerTo('/containers/compose')"
label="compose"
>
{{ $t('container.compose') }}
</el-radio-button>
<el-radio-button <el-radio-button
class="topButton" class="topButton"
size="large" size="large"

View file

@ -8,8 +8,8 @@
</template> </template>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<div @click="goInstall(baseInfo.haloID)"> <div @click="goInstall()" style="cursor: pointer">
<el-card style="height: 110px" @click="goInstall(baseInfo.haloID)"> <el-card style="height: 110px">
<el-row> <el-row>
<el-col :span="4"> <el-col :span="4">
<img style="width: 40px; height: 40px" src="../images/halo.jpg" alt="" /> <img style="width: 40px; height: 40px" src="../images/halo.jpg" alt="" />
@ -26,8 +26,8 @@
</div> </div>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<div @click="goInstall(baseInfo.dateeaseID)"> <div @click="goInstall()" style="cursor: pointer">
<el-card style="height: 110px" @click="goInstall(baseInfo.dateeaseID)"> <el-card style="height: 110px">
<el-row> <el-row>
<el-col :span="4"> <el-col :span="4">
<img style="width: 40px; height: 40px" src="../images/de.jpg" alt="" /> <img style="width: 40px; height: 40px" src="../images/de.jpg" alt="" />
@ -46,8 +46,8 @@
</el-row> </el-row>
<el-row :gutter="20" style="margin-top: 20px"> <el-row :gutter="20" style="margin-top: 20px">
<el-col :span="12"> <el-col :span="12">
<div @click="goInstall(baseInfo.jumpserverID)"> <div @click="goInstall()" style="cursor: pointer">
<el-card style="height: 110px" @click="goInstall(baseInfo.jumpserverID)"> <el-card style="height: 110px">
<el-row> <el-row>
<el-col :span="4"> <el-col :span="4">
<img style="width: 40px; height: 40px" src="../images/js.jpg" alt="" /> <img style="width: 40px; height: 40px" src="../images/js.jpg" alt="" />
@ -64,8 +64,8 @@
</div> </div>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<div @click="goInstall(baseInfo.metersphereID)"> <div @click="goInstall()" style="cursor: pointer">
<el-card style="height: 110px" @click="goInstall(baseInfo.metersphereID)"> <el-card style="height: 110px">
<el-row> <el-row>
<el-col :span="4"> <el-col :span="4">
<img style="width: 40px; height: 40px" src="../images/ms.jpg" alt="" /> <img style="width: 40px; height: 40px" src="../images/ms.jpg" alt="" />
@ -84,8 +84,8 @@
</el-row> </el-row>
<el-row :gutter="20" style="margin-top: 20px"> <el-row :gutter="20" style="margin-top: 20px">
<el-col :span="12"> <el-col :span="12">
<div @click="goInstall(baseInfo.kubeoperatorID)"> <div @click="goInstall()" style="cursor: pointer">
<el-card style="height: 110px" @click="goInstall(baseInfo.kubeoperatorID)"> <el-card style="height: 110px">
<el-row> <el-row>
<el-col :span="4"> <el-col :span="4">
<img style="width: 40px; height: 40px" src="../images/ko.jpg" alt="" /> <img style="width: 40px; height: 40px" src="../images/ko.jpg" alt="" />
@ -102,8 +102,8 @@
</div> </div>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<div @click="goInstall(baseInfo.kubepiID)"> <div @click="goInstall()" style="cursor: pointer">
<el-card style="height: 110px" @click="goInstall(baseInfo.kubepiID)"> <el-card style="height: 110px">
<el-row> <el-row>
<el-col :span="4"> <el-col :span="4">
<img style="width: 40px; height: 40px" src="../images/kubepi.jpg" alt="" /> <img style="width: 40px; height: 40px" src="../images/kubepi.jpg" alt="" />
@ -148,11 +148,8 @@ const acceptParams = (base: Dashboard.BaseInfo): void => {
baseInfo.value.kubepiID = base.kubepiID; baseInfo.value.kubepiID = base.kubepiID;
}; };
const goInstall = (id: number) => { const goInstall = () => {
let params: { [key: string]: any } = { router.push({ name: 'App' });
id: id,
};
router.push({ name: 'AppDetail', params });
}; };
defineExpose({ defineExpose({

View file

@ -75,7 +75,14 @@
</el-card> </el-card>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<Status ref="statuRef" /> <el-card class="el-card">
<template #header>
<div class="card-header">
<span>{{ $t('commons.table.status') }}</span>
</div>
</template>
<Status ref="statuRef" />
</el-card>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-card class="el-card"> <el-card class="el-card">
@ -309,6 +316,11 @@ const onLoadBaseInfo = async (isInit: boolean, range: string) => {
const res = await loadBaseInfo(searchInfo.ioOption, searchInfo.netOption); const res = await loadBaseInfo(searchInfo.ioOption, searchInfo.netOption);
baseInfo.value = res.data; baseInfo.value = res.data;
currentInfo.value = baseInfo.value.currentInfo; currentInfo.value = baseInfo.value.currentInfo;
if (baseInfo.value.timeSinceUptime) {
baseInfo.value.timeSinceUptime.replaceAll('days', i18n.global.t('home.Day'));
baseInfo.value.timeSinceUptime.replaceAll('hours', i18n.global.t('home.Hour'));
baseInfo.value.timeSinceUptime.replaceAll('minutes', i18n.global.t('home.Minute'));
}
onLoadCurrentInfo(); onLoadCurrentInfo();
statuRef.value.acceptParams(currentInfo.value, baseInfo.value); statuRef.value.acceptParams(currentInfo.value, baseInfo.value);
appRef.value.acceptParams(baseInfo.value); appRef.value.acceptParams(baseInfo.value);
@ -393,7 +405,7 @@ const loadData = async () => {
[i18n.global.t('monitor.read'), i18n.global.t('monitor.write')], [i18n.global.t('monitor.read'), i18n.global.t('monitor.write')],
timeIODatas.value, timeIODatas.value,
[ioReadYDatas, ioWriteYDatas], [ioReadYDatas, ioWriteYDatas],
'流量', i18n.global.t('monitor.network'),
'MB', 'MB',
); );
} else { } else {

View file

@ -1,134 +1,123 @@
<template> <template>
<div> <div>
<el-card class="el-card"> <el-row :gutter="10">
<template #header> <el-col :span="12" align="center">
<div class="card-header"> <el-popover placement="bottom" :width="300" trigger="hover">
<span>{{ $t('commons.table.status') }}</span> <div style="margin-bottom: 10px">
</div> <el-tag>{{ baseInfo.cpuModelName }}</el-tag>
</template> </div>
<el-row :gutter="10"> <el-tag>
<el-col :span="12" align="center"> {{ $t('home.core') }} *{{ baseInfo.cpuCores }} {{ $t('home.logicCore') }} *{{
<el-popover placement="bottom" :width="300" trigger="hover"> baseInfo.cpuLogicalCores
<div style="margin-bottom: 10px"> }}
<el-tag>{{ baseInfo.cpuModelName }}</el-tag> </el-tag>
</div>
<el-tag>
{{ $t('home.core') }} *{{ baseInfo.cpuCores }} {{ $t('home.logicCore') }} *{{
baseInfo.cpuLogicalCores
}}
</el-tag>
<br />
<el-tag style="margin-top: 5px" v-for="(item, index) of currentInfo.cpuPercent" :key="index">
CPU-{{ index }}: {{ formatNumber(item) }}%
</el-tag>
<template #reference>
<el-progress
type="dashboard"
:width="80"
:percentage="formatNumber(currentInfo.cpuUsedPercent)"
>
<template #default="{ percentage }">
<span class="percentage-value">{{ percentage }}%</span>
<span class="percentage-label">CPU</span>
</template>
</el-progress>
</template>
</el-popover>
<br /> <br />
<span class="input-help"> <el-tag style="margin-top: 5px" v-for="(item, index) of currentInfo.cpuPercent" :key="index">
( {{ formatNumber(currentInfo.cpuUsed) }} / {{ currentInfo.cpuTotal }} ) Core CPU-{{ index }}: {{ formatNumber(item) }}%
</span> </el-tag>
</el-col> <template #reference>
<el-col :span="12" align="center"> <el-progress
<el-progress type="dashboard" :width="80" :percentage="formatNumber(currentInfo.MemoryUsedPercent)"> type="dashboard"
<template #default="{ percentage }"> :width="80"
<span class="percentage-value">{{ percentage }}%</span> :percentage="formatNumber(currentInfo.cpuUsedPercent)"
<span class="percentage-label">{{ $t('monitor.memory') }}</span> >
</template> <template #default="{ percentage }">
</el-progress> <span class="percentage-value">{{ percentage }}%</span>
<br /> <span class="percentage-label">CPU</span>
<span class="input-help"> </template>
( {{ formatNumber(currentInfo.memoryUsed / 1024 / 1024) }} / </el-progress>
{{ formatNumber(currentInfo.memoryTotal / 1024 / 1024) }} ) MB </template>
</span> </el-popover>
</el-col> <br />
</el-row> <span class="input-help">
<el-row :gutter="10" style="margin-top: 30px"> ( {{ formatNumber(currentInfo.cpuUsed) }} / {{ currentInfo.cpuTotal }} ) Core
<el-col :span="12" align="center"> </span>
<el-popover placement="bottom" :width="200" trigger="hover"> </el-col>
<el-tag style="margin-top: 5px"> <el-col :span="12" align="center">
{{ $t('home.loadAverage', [1]) }}: {{ formatNumber(currentInfo.load1) }} <el-progress type="dashboard" :width="80" :percentage="formatNumber(currentInfo.MemoryUsedPercent)">
</el-tag> <template #default="{ percentage }">
<el-tag style="margin-top: 5px"> <span class="percentage-value">{{ percentage }}%</span>
{{ $t('home.loadAverage', [5]) }}: {{ formatNumber(currentInfo.load5) }} <span class="percentage-label">{{ $t('monitor.memory') }}</span>
</el-tag> </template>
<el-tag style="margin-top: 5px"> </el-progress>
{{ $t('home.loadAverage', [15]) }}: {{ formatNumber(currentInfo.load15) }} <br />
</el-tag> <span class="input-help">
<template #reference> ( {{ formatNumber(currentInfo.memoryUsed / 1024 / 1024) }} /
<el-progress {{ formatNumber(currentInfo.memoryTotal / 1024 / 1024) }} ) MB
type="dashboard" </span>
:width="80" </el-col>
:percentage="formatNumber(currentInfo.loadUsagePercent)" </el-row>
> <el-row :gutter="10" style="margin-top: 30px">
<template #default="{ percentage }"> <el-col :span="12" align="center">
<span class="percentage-value">{{ percentage }}%</span> <el-popover placement="bottom" :width="200" trigger="hover">
<span class="percentage-label">{{ $t('home.load') }}</span> <el-tag style="margin-top: 5px">
</template> {{ $t('home.loadAverage', [1]) }}: {{ formatNumber(currentInfo.load1) }}
</el-progress> </el-tag>
</template> <el-tag style="margin-top: 5px">
</el-popover> {{ $t('home.loadAverage', [5]) }}: {{ formatNumber(currentInfo.load5) }}
<br /> </el-tag>
<span class="input-help">{{ loadStatus(currentInfo.loadUsagePercent) }}</span> <el-tag style="margin-top: 5px">
</el-col> {{ $t('home.loadAverage', [15]) }}: {{ formatNumber(currentInfo.load15) }}
<el-col :span="12" align="center"> </el-tag>
<el-popover placement="bottom" :width="160" trigger="hover"> <template #reference>
<el-tag>{{ $t('home.mount') }}: /</el-tag> <el-progress
<div><el-tag style="margin-top: 10px">iNode</el-tag></div> type="dashboard"
<el-tag style="margin-top: 5px">{{ $t('home.total') }}: {{ currentInfo.inodesTotal }}</el-tag> :width="80"
<el-tag style="margin-top: 3px">{{ $t('home.used') }}: {{ currentInfo.inodesUsed }}</el-tag> :percentage="formatNumber(currentInfo.loadUsagePercent)"
<el-tag style="margin-top: 3px">{{ $t('home.free') }}: {{ currentInfo.inodesFree }}</el-tag> >
<el-tag style="margin-top: 3px"> <template #default="{ percentage }">
{{ $t('home.percent') }}: {{ formatNumber(currentInfo.inodesUsedPercent) }}% <span class="percentage-value">{{ percentage }}%</span>
</el-tag> <span class="percentage-label">{{ $t('home.load') }}</span>
</template>
</el-progress>
</template>
</el-popover>
<br />
<span class="input-help">{{ loadStatus(currentInfo.loadUsagePercent) }}</span>
</el-col>
<el-col :span="12" align="center">
<el-popover placement="bottom" :width="160" trigger="hover">
<el-tag>{{ $t('home.mount') }}: /</el-tag>
<div><el-tag style="margin-top: 10px">iNode</el-tag></div>
<el-tag style="margin-top: 5px">{{ $t('home.total') }}: {{ currentInfo.inodesTotal }}</el-tag>
<el-tag style="margin-top: 3px">{{ $t('home.used') }}: {{ currentInfo.inodesUsed }}</el-tag>
<el-tag style="margin-top: 3px">{{ $t('home.free') }}: {{ currentInfo.inodesFree }}</el-tag>
<el-tag style="margin-top: 3px">
{{ $t('home.percent') }}: {{ formatNumber(currentInfo.inodesUsedPercent) }}%
</el-tag>
<div> <div>
<el-tag style="margin-top: 10px">{{ $t('monitor.disk') }}</el-tag> <el-tag style="margin-top: 10px">{{ $t('monitor.disk') }}</el-tag>
</div> </div>
<el-tag style="margin-top: 5px"> <el-tag style="margin-top: 5px">
{{ $t('home.total') }}: {{ formatNumber(currentInfo.total / 1024 / 1024 / 1024) }} GB {{ $t('home.total') }}: {{ formatNumber(currentInfo.total / 1024 / 1024 / 1024) }} GB
</el-tag> </el-tag>
<el-tag style="margin-top: 3px"> <el-tag style="margin-top: 3px">
{{ $t('home.used') }}: {{ formatNumber(currentInfo.used / 1024 / 1024 / 1024) }} GB {{ $t('home.used') }}: {{ formatNumber(currentInfo.used / 1024 / 1024 / 1024) }} GB
</el-tag> </el-tag>
<el-tag style="margin-top: 3px"> <el-tag style="margin-top: 3px">
{{ $t('home.free') }}: {{ formatNumber(currentInfo.free / 1024 / 1024 / 1024) }} GB {{ $t('home.free') }}: {{ formatNumber(currentInfo.free / 1024 / 1024 / 1024) }} GB
</el-tag> </el-tag>
<el-tag style="margin-top: 3px"> <el-tag style="margin-top: 3px">
{{ $t('home.percent') }}: {{ formatNumber(currentInfo.usedPercent) }}% {{ $t('home.percent') }}: {{ formatNumber(currentInfo.usedPercent) }}%
</el-tag> </el-tag>
<template #reference> <template #reference>
<el-progress <el-progress type="dashboard" :width="80" :percentage="formatNumber(currentInfo.usedPercent)">
type="dashboard" <template #default="{ percentage }">
:width="80" <span class="percentage-value">{{ percentage }}%</span>
:percentage="formatNumber(currentInfo.usedPercent)" <span class="percentage-label">{{ $t('monitor.disk') }}</span>
> </template>
<template #default="{ percentage }"> </el-progress>
<span class="percentage-value">{{ percentage }}%</span> </template>
<span class="percentage-label">{{ $t('monitor.disk') }}</span> </el-popover>
</template>
</el-progress>
</template>
</el-popover>
<br /> <br />
<span class="input-help"> <span class="input-help">
( {{ formatNumber(currentInfo.used / 1024 / 1024 / 1024) }} / ( {{ formatNumber(currentInfo.used / 1024 / 1024 / 1024) }} /
{{ formatNumber(currentInfo.total / 1024 / 1024 / 1024) }} ) GB {{ formatNumber(currentInfo.total / 1024 / 1024 / 1024) }} ) GB
</span> </span>
</el-col> </el-col>
</el-row> </el-row>
</el-card>
</div> </div>
</template> </template>
@ -149,6 +138,8 @@ const baseInfo = ref<Dashboard.BaseInfo>({
databaseNumber: 0, databaseNumber: 0,
cronjobNumber: 0, cronjobNumber: 0,
appInstalldNumber: 0, appInstalldNumber: 0,
uptime: '',
timeSinceUptime: '',
hostname: '', hostname: '',
os: '', os: '',

View file

@ -123,6 +123,9 @@
</el-icon> </el-icon>
</template> </template>
</el-input> </el-input>
<span v-if="errAuthInfo" class="input-error" style="line-height: 14px">
{{ $t('commons.login.errorAuthInfo') }}
</span>
</el-form-item> </el-form-item>
<el-form-item prop="captcha"> <el-form-item prop="captcha">
<el-input <el-input
@ -137,6 +140,9 @@
:alt="$t('commons.login.captchaHelper')" :alt="$t('commons.login.captchaHelper')"
@click="loginVerify()" @click="loginVerify()"
/> />
<span v-if="errCaptcha" class="input-error" style="line-height: 14px">
{{ $t('commons.login.errorCaptcha') }}
</span>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button <el-button
@ -170,6 +176,9 @@ import { Rules } from '@/global/form-rules';
const globalStore = GlobalStore(); const globalStore = GlobalStore();
const menuStore = MenuStore(); const menuStore = MenuStore();
const errAuthInfo = ref(false);
const errCaptcha = ref(false);
const isFirst = ref(); const isFirst = ref();
type FormInstance = InstanceType<typeof ElForm>; type FormInstance = InstanceType<typeof ElForm>;
@ -241,6 +250,19 @@ const login = (formEl: FormInstance | undefined) => {
authMethod: '', authMethod: '',
}; };
const res = await loginApi(requestLoginForm); const res = await loginApi(requestLoginForm);
if (res.code === 406) {
if (res.message === 'ErrCaptchaCode') {
errCaptcha.value = true;
errAuthInfo.value = false;
loginVerify();
}
if (res.message === 'ErrAuth') {
errCaptcha.value = false;
errAuthInfo.value = true;
loginVerify();
}
return;
}
if (res.data.mfaStatus === 'enable') { if (res.data.mfaStatus === 'enable') {
mfaShow.value = true; mfaShow.value = true;
mfaLoginForm.secret = res.data.mfaSecret; mfaLoginForm.secret = res.data.mfaSecret;