1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-01-31 22:18:07 +08:00

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}) res.Msg = 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.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: default:
res.Msg = i18n.GetMsgWithMap(msgKey, map[string]interface{}{"detail": err}) 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) pass, err := encrypt.StringDecrypt(passwrodSetting.Value)
if err != nil { if err != nil {
return nil, err return nil, constant.ErrAuth
} }
if info.Password != pass && nameSetting.Value == info.Name { 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")) mfa, err := settingRepo.Get(settingRepo.WithByKey("MFAStatus"))
if err != nil { 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) pass, err := encrypt.StringDecrypt(passwrodSetting.Value)
if err != nil { if err != nil {
return nil, err return nil, constant.ErrAuth
} }
if info.Password != pass && nameSetting.Value == info.Name { 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) return u.generateSession(c, info.Name, info.AuthMethod)

View File

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

View File

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

View File

@ -2,8 +2,9 @@ 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" ErrCaptchaCode: "The verification code information is incorrect"
ErrInitialPassword: "Initial password error: {{ .detail }}" ErrInitialPassword: "Initial password error"
ErrInternalServer: "Service internal error: {{ .detail }}" ErrInternalServer: "Service internal error: {{ .detail }}"
ErrRecordExist: "Record already exists: {{ .detail }}" ErrRecordExist: "Record already exists: {{ .detail }}"
ErrRecordNotFound: "Records not found: {{ .detail }}" ErrRecordNotFound: "Records not found: {{ .detail }}"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -60,96 +60,103 @@
:title="$t('setting.backupAccount')" :title="$t('setting.backupAccount')"
width="30%" width="30%"
> >
<el-form ref="formRef" label-position="left" :model="form" label-width="160px"> <div v-loading="loading">
<el-form-item :label="$t('commons.table.type')" prop="type" :rules="Rules.requiredSelect"> <el-form ref="formRef" label-position="left" :model="form" label-width="160px">
<el-select style="width: 100%" v-model="form.type" :disabled="operation === 'edit'"> <el-form-item :label="$t('commons.table.type')" prop="type" :rules="Rules.requiredSelect">
<el-option <el-select style="width: 100%" v-model="form.type" :disabled="operation === 'edit'">
v-for="item in typeOptions" <el-option
:key="item.label" v-for="item in typeOptions"
:value="item.value" :key="item.label"
:label="item.label" :value="item.value"
/> :label="item.label"
</el-select> />
</el-form-item> </el-select>
<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']" />
</el-form-item> </el-form-item>
<el-form-item <el-form-item
:label="$t('setting.username')" v-if="form.type === 'LOCAL'"
prop="varsJson.username" :label="$t('setting.currentPath')"
:rules="[Rules.requiredInput]" 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>
<el-form-item :label="$t('setting.password')" prop="credential" :rules="[Rules.requiredInput]"> <el-form-item
<el-input type="password" show-password v-model="form.credential" /> 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>
<el-form-item :label="$t('setting.path')" prop="bucket"> <el-form-item
<el-input v-model="form.bucket" /> 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>
</div> <el-form-item
</el-form> 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> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click="backupVisiable = false">{{ $t('commons.button.cancel') }}</el-button> <el-button @click="backupVisiable = false">{{ $t('commons.button.cancel') }}</el-button>
@ -177,6 +184,7 @@ const data = ref();
const selects = ref<any>([]); const selects = ref<any>([]);
const backupVisiable = ref<boolean>(false); const backupVisiable = ref<boolean>(false);
const operation = ref<string>('create'); const operation = ref<string>('create');
const loading = ref(false);
const form = reactive({ const form = reactive({
id: 0, id: 0,
@ -275,8 +283,20 @@ function restForm() {
} }
const getBuckets = async () => { const getBuckets = async () => {
const res = await listBucket({ type: form.type, vars: JSON.stringify(form.varsJson), credential: form.credential }); loading.value = true;
buckets.value = res.data; 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) => { const loadDir = async (path: string) => {
form.varsJson['dir'] = path; form.varsJson['dir'] = path;

View File

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