fix: 后端错误返回国际化处理

This commit is contained in:
ssongliu 2022-12-02 18:52:43 +08:00 committed by ssongliu
parent 6f425a6a0e
commit 71d90aca59
14 changed files with 203 additions and 161 deletions

View File

@ -47,6 +47,10 @@ func ErrorWithDetail(ctx *gin.Context, code int, msgKey string, err error) {
res.Msg = i18n.GetMsgWithMap("ErrStructTransform", map[string]interface{}{"detail": err})
case errors.Is(constant.ErrCaptchaCode, err):
res.Msg = i18n.GetMsgWithMap("ErrCaptchaCode", map[string]interface{}{"detail": err})
case errors.Is(constant.ErrAuth, err):
res.Msg = i18n.GetMsgWithMap("ErrAuth", map[string]interface{}{"detail": err})
case errors.Is(constant.ErrInitialPassword, err):
res.Msg = i18n.GetMsgWithMap("ErrInitialPassword", map[string]interface{}{"detail": err})
default:
res.Msg = i18n.GetMsgWithMap(msgKey, map[string]interface{}{"detail": err})
}

View File

@ -58,10 +58,10 @@ func (u *AuthService) Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo,
}
pass, err := encrypt.StringDecrypt(passwrodSetting.Value)
if err != nil {
return nil, err
return nil, constant.ErrAuth
}
if info.Password != pass && nameSetting.Value == info.Name {
return nil, errors.New("login failed")
return nil, constant.ErrAuth
}
mfa, err := settingRepo.Get(settingRepo.WithByKey("MFAStatus"))
if err != nil {
@ -89,10 +89,10 @@ func (u *AuthService) MFALogin(c *gin.Context, info dto.MFALogin) (*dto.UserLogi
}
pass, err := encrypt.StringDecrypt(passwrodSetting.Value)
if err != nil {
return nil, err
return nil, constant.ErrAuth
}
if info.Password != pass && nameSetting.Value == info.Name {
return nil, errors.New("login failed")
return nil, constant.ErrAuth
}
return u.generateSession(c, info.Name, info.AuthMethod)

View File

@ -124,15 +124,12 @@ func (u *ContainerService) CreateCompose(req dto.ComposeCreate) error {
write.Flush()
req.Path = path
}
go func() {
cmd := exec.Command("docker-compose", "-f", req.Path, "up", "-d")
stdout, err := cmd.CombinedOutput()
if err != nil {
global.LOG.Debugf("docker-compose up %s failed, err: %v", req.Name, err)
return
}
global.LOG.Debugf("docker-compose up %s successful, logs: %v", req.Name, string(stdout))
}()
cmd := exec.Command("docker-compose", "-f", req.Path, "up", "-d")
stdout, err := cmd.CombinedOutput()
if err != nil {
return err
}
global.LOG.Debugf("docker-compose up %s successful, logs: %v", req.Name, string(stdout))
return nil
}

View File

@ -19,6 +19,7 @@ const (
// internal
var (
ErrCaptchaCode = errors.New("ErrCaptchaCode")
ErrAuth = errors.New("ErrAuth")
ErrRecordExist = errors.New("ErrRecordExist")
ErrRecordNotFound = errors.New("ErrRecordNotFound")
ErrStructTransform = errors.New("ErrStructTransform")

View File

@ -2,8 +2,9 @@ ErrInvalidParams: "Request parameter error: {{ .detail }}"
ErrToken: "Token information is incorrect.: {{ .detail }}"
ErrTokenParse: "Token generation error: {{ .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: {{ .detail }}"
ErrInitialPassword: "Initial password error"
ErrInternalServer: "Service internal error: {{ .detail }}"
ErrRecordExist: "Record already exists: {{ .detail }}"
ErrRecordNotFound: "Records not found: {{ .detail }}"

View File

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

View File

@ -26,7 +26,7 @@ func VerifyCode(codeID string, code string) error {
func CreateCaptcha() (*dto.CaptchaResponse, error) {
var driverString base64Captcha.DriverString
driverString.Source = "1234567890QWERTYUPLKJHGFDSAZXCVBNMqwertyuplkjhgfdsazxcvbnm"
driverString.Source = "1234567890QWERTYUPLKJHGFDSAZXCVBNMqwertyupkjhgfdsazxcvbnm"
driverString.Width = 120
driverString.Height = 50
driverString.NoiseCount = 0

View File

@ -89,6 +89,7 @@ const onDownload = async () => {
};
interface DialogProps {
container: string;
containerID: string;
}
@ -96,6 +97,7 @@ const acceptParams = (props: DialogProps): void => {
logSearch.containerID = props.containerID;
logSearch.mode = 'all';
logSearch.isWatch = false;
logSearch.container = props.container;
searchLogs();
timer = setInterval(() => {
if (logSearch.isWatch) {

View File

@ -1,5 +1,5 @@
<template>
<div>
<div v-loading="loading">
<Submenu activeName="compose" />
<el-card style="margin-top: 20px">
<ComplexTable :pagination-config="paginationConfig" v-model:selects="selects" :data="data" @search="search">
@ -77,6 +77,7 @@ import router from '@/routers';
const data = ref();
const selects = ref<any>([]);
const loading = ref(false);
const paginationConfig = reactive({
page: 1,
@ -89,12 +90,16 @@ const search = async () => {
page: paginationConfig.page,
pageSize: paginationConfig.pageSize,
};
await searchCompose(params).then((res) => {
if (res.data) {
data.value = res.data.items;
loading.value = true;
await searchCompose(params)
.then((res) => {
loading.value = false;
data.value = res.data.items || [];
paginationConfig.total = res.data.total;
}
});
})
.finally(() => {
loading.value = false;
});
};
const goContainer = async (name: string) => {

View File

@ -5,50 +5,52 @@
<span>{{ $t('container.compose') }}</span>
</div>
</template>
<el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
<el-form-item :label="$t('container.name')" prop="name">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item :label="$t('container.from')">
<el-radio-group v-model="form.from">
<el-radio label="edit">{{ $t('container.edit') }}</el-radio>
<el-radio label="path">{{ $t('container.pathSelect') }}</el-radio>
<el-radio label="template">{{ $t('container.composeTemplate') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="form.from === 'path'" prop="path">
<el-input
clearable
:placeholder="$t('commons.example') + '/tmp/docker-compose.yml'"
v-model="form.path"
>
<template #append>
<FileList @choose="loadDir" :dir="false"></FileList>
</template>
</el-input>
</el-form-item>
<el-form-item v-if="form.from === 'template'" prop="template">
<el-select v-model="form.template">
<el-option v-for="item in templateOptions" :key="item.id" :value="item.id" :label="item.name" />
</el-select>
</el-form-item>
<el-form-item v-if="form.from === 'edit'">
<codemirror
:autofocus="true"
placeholder="None data"
:indent-with-tab="true"
:tabSize="4"
style="max-height: 500px; width: 100%"
:lineWrapping="true"
:matchBrackets="true"
theme="cobalt"
:styleActiveLine="true"
:extensions="extensions"
v-model="form.file"
:readOnly="true"
/>
</el-form-item>
</el-form>
<div v-loading="loading">
<el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
<el-form-item :label="$t('container.name')" prop="name">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item :label="$t('container.from')">
<el-radio-group v-model="form.from">
<el-radio label="edit">{{ $t('container.edit') }}</el-radio>
<el-radio label="path">{{ $t('container.pathSelect') }}</el-radio>
<el-radio label="template">{{ $t('container.composeTemplate') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="form.from === 'path'" prop="path">
<el-input
clearable
:placeholder="$t('commons.example') + '/tmp/docker-compose.yml'"
v-model="form.path"
>
<template #append>
<FileList @choose="loadDir" :dir="false"></FileList>
</template>
</el-input>
</el-form-item>
<el-form-item v-if="form.from === 'template'" prop="template">
<el-select v-model="form.template">
<el-option v-for="item in templateOptions" :key="item.id" :value="item.id" :label="item.name" />
</el-select>
</el-form-item>
<el-form-item v-if="form.from === 'edit'">
<codemirror
:autofocus="true"
placeholder="None data"
:indent-with-tab="true"
:tabSize="4"
style="max-height: 500px; width: 100%"
:lineWrapping="true"
:matchBrackets="true"
theme="cobalt"
:styleActiveLine="true"
:extensions="extensions"
v-model="form.file"
:readOnly="true"
/>
</el-form-item>
</el-form>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="composeVisiable = false">{{ $t('commons.button.cancel') }}</el-button>
@ -75,6 +77,8 @@ const extensions = [javascript(), oneDark];
const composeVisiable = ref(false);
const templateOptions = ref();
const loading = ref(false);
const varifyPath = (rule: any, value: any, callback: any) => {
if (value.indexOf('docker-compose.yml') === -1) {
callback(new Error(i18n.global.t('commons.rule.selectHelper', ['docker-compose.yml'])));
@ -118,10 +122,17 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(async (valid) => {
if (!valid) return;
await upCompose(form);
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
emit('search');
composeVisiable.value = false;
loading.value = true;
upCompose(form)
.then(() => {
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
loading.value = false;
emit('search');
composeVisiable.value = false;
})
.finally(() => {
loading.value = false;
});
});
};

View File

@ -25,9 +25,6 @@
v-model="row.status"
inline-prompt
size="default"
style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
active-text="Y"
inactive-text="N"
active-value="Enable"
inactive-value="Disable"
/>

View File

@ -194,7 +194,7 @@ const onSaveFile = async () => {
};
const loadContainerLog = async (containerID: string) => {
dialogContainerLogRef.value!.acceptParams({ containerID: containerID });
dialogContainerLogRef.value!.acceptParams({ containerID: containerID, container: mysqlName.value });
};
const loadBaseInfo = async () => {

View File

@ -60,96 +60,103 @@
:title="$t('setting.backupAccount')"
width="30%"
>
<el-form ref="formRef" label-position="left" :model="form" label-width="160px">
<el-form-item :label="$t('commons.table.type')" prop="type" :rules="Rules.requiredSelect">
<el-select style="width: 100%" v-model="form.type" :disabled="operation === 'edit'">
<el-option
v-for="item in typeOptions"
:key="item.label"
:value="item.value"
:label="item.label"
/>
</el-select>
</el-form-item>
<el-form-item
v-if="form.type === 'LOCAL'"
:label="$t('setting.currentPath')"
prop="varsJson['dir']"
:rules="Rules.requiredInput"
>
<el-input v-model="form.varsJson['dir']">
<template #append>
<FileList @choose="loadDir" :dir="true"></FileList>
</template>
</el-input>
</el-form-item>
<el-form-item
v-if="hasBucket(form.type) && operation !== 'edit'"
label="Access Key ID"
prop="varsJson.accessKey"
:rules="Rules.requiredInput"
>
<el-input v-model="form.varsJson['accessKey']" />
</el-form-item>
<el-form-item
v-if="hasBucket(form.type)"
label="Access Key Secret"
prop="credential"
:rules="Rules.requiredInput"
>
<el-input show-password v-model="form.credential" />
</el-form-item>
<el-form-item
v-if="form.type === 'S3'"
label="Region"
prop="varsJson.region"
:rules="Rules.requiredInput"
>
<el-input v-model="form.varsJson['region']" />
</el-form-item>
<el-form-item
v-if="hasBucket(form.type)"
label="Endpoint"
prop="varsJson.endpoint"
:rules="Rules.requiredInput"
>
<el-input v-model="form.varsJson['endpoint']" />
</el-form-item>
<el-form-item
v-if="form.type !== '' && hasBucket(form.type)"
label="Bucket"
prop="bucket"
:rules="Rules.requiredSelect"
>
<el-select style="width: 80%" v-model="form.bucket">
<el-option v-for="item in buckets" :key="item" :value="item" />
</el-select>
<el-button style="width: 20%" plain @click="getBuckets">
{{ $t('setting.loadBucket') }}
</el-button>
</el-form-item>
<div v-if="form.type === 'SFTP'">
<el-form-item :label="$t('setting.address')" prop="varsJson.address" :rules="Rules.requiredInput">
<el-input v-model="form.varsJson['address']" />
</el-form-item>
<el-form-item :label="$t('setting.port')" prop="varsJson.port" :rules="[Rules.number]">
<el-input-number :min="0" :max="65535" v-model.number="form.varsJson['port']" />
<div v-loading="loading">
<el-form ref="formRef" label-position="left" :model="form" label-width="160px">
<el-form-item :label="$t('commons.table.type')" prop="type" :rules="Rules.requiredSelect">
<el-select style="width: 100%" v-model="form.type" :disabled="operation === 'edit'">
<el-option
v-for="item in typeOptions"
:key="item.label"
:value="item.value"
:label="item.label"
/>
</el-select>
</el-form-item>
<el-form-item
:label="$t('setting.username')"
prop="varsJson.username"
:rules="[Rules.requiredInput]"
v-if="form.type === 'LOCAL'"
:label="$t('setting.currentPath')"
prop="varsJson['dir']"
:rules="Rules.requiredInput"
>
<el-input v-model="form.varsJson['username']" />
<el-input v-model="form.varsJson['dir']">
<template #append>
<FileList @choose="loadDir" :dir="true"></FileList>
</template>
</el-input>
</el-form-item>
<el-form-item :label="$t('setting.password')" prop="credential" :rules="[Rules.requiredInput]">
<el-input type="password" show-password v-model="form.credential" />
<el-form-item
v-if="hasBucket(form.type) && operation !== 'edit'"
label="Access Key ID"
prop="varsJson.accessKey"
:rules="Rules.requiredInput"
>
<el-input v-model="form.varsJson['accessKey']" />
</el-form-item>
<el-form-item :label="$t('setting.path')" prop="bucket">
<el-input v-model="form.bucket" />
<el-form-item
v-if="hasBucket(form.type)"
label="Access Key Secret"
prop="credential"
:rules="Rules.requiredInput"
>
<el-input show-password v-model="form.credential" />
</el-form-item>
</div>
</el-form>
<el-form-item
v-if="form.type === 'S3'"
label="Region"
prop="varsJson.region"
:rules="Rules.requiredInput"
>
<el-input v-model="form.varsJson['region']" />
</el-form-item>
<el-form-item
v-if="hasBucket(form.type)"
label="Endpoint"
prop="varsJson.endpoint"
:rules="Rules.requiredInput"
>
<el-input v-model="form.varsJson['endpoint']" />
</el-form-item>
<el-form-item
v-if="form.type !== '' && hasBucket(form.type)"
label="Bucket"
prop="bucket"
:rules="Rules.requiredSelect"
>
<el-select style="width: 80%" v-model="form.bucket">
<el-option v-for="item in buckets" :key="item" :value="item" />
</el-select>
<el-button style="width: 20%" plain @click="getBuckets">
{{ $t('setting.loadBucket') }}
</el-button>
</el-form-item>
<div v-if="form.type === 'SFTP'">
<el-form-item
:label="$t('setting.address')"
prop="varsJson.address"
:rules="Rules.requiredInput"
>
<el-input v-model="form.varsJson['address']" />
</el-form-item>
<el-form-item :label="$t('setting.port')" prop="varsJson.port" :rules="[Rules.number]">
<el-input-number :min="0" :max="65535" v-model.number="form.varsJson['port']" />
</el-form-item>
<el-form-item
:label="$t('setting.username')"
prop="varsJson.username"
:rules="[Rules.requiredInput]"
>
<el-input v-model="form.varsJson['username']" />
</el-form-item>
<el-form-item :label="$t('setting.password')" prop="credential" :rules="[Rules.requiredInput]">
<el-input type="password" show-password v-model="form.credential" />
</el-form-item>
<el-form-item :label="$t('setting.path')" prop="bucket">
<el-input v-model="form.bucket" />
</el-form-item>
</div>
</el-form>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="backupVisiable = false">{{ $t('commons.button.cancel') }}</el-button>
@ -177,6 +184,7 @@ const data = ref();
const selects = ref<any>([]);
const backupVisiable = ref<boolean>(false);
const operation = ref<string>('create');
const loading = ref(false);
const form = reactive({
id: 0,
@ -275,8 +283,20 @@ function restForm() {
}
const getBuckets = async () => {
const res = await listBucket({ type: form.type, vars: JSON.stringify(form.varsJson), credential: form.credential });
buckets.value = res.data;
loading.value = true;
listBucket({
type: form.type,
vars: JSON.stringify(form.varsJson),
credential: form.credential,
})
.then((res) => {
loading.value = true;
buckets.value = res.data;
})
.finally(() => {
buckets.value = [];
loading.value = false;
});
};
const loadDir = async (path: string) => {
form.varsJson['dir'] = path;

View File

@ -39,7 +39,10 @@ watch(
activeName,
(newvalue) => {
if (newvalue === '2') {
dialogContainerLogRef.value!.acceptParams({ containerID: props.containerName });
dialogContainerLogRef.value!.acceptParams({
containerID: props.containerName,
container: props.containerName,
});
}
},
{ immediate: true },