diff --git a/README.md b/README.md index 07a007d716c9f5463829294bd61b7b03a4284114..4d324b3735bd185dc02bc71312c9a9105adbe2ac 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,7 @@ continew-admin # 全局通用项目配置及依赖版本管理 │ │ ├─ mapper # 系统管理相关 Mapper │ │ ├─ model # 系统管理相关模型 │ │ │ ├─ entity # 系统管理相关实体对象 + │ │ │ ├─ request # 系统管理相关请求对象 │ │ │ └─ vo # 系统管理相关 VO(View Object) │ │ └─ service # 系统管理相关业务接口及实现类 │ │ └─ impl # 系统管理相关业务实现类 diff --git a/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/config/jackson/BigNumberSerializer.java b/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/config/jackson/BigNumberSerializer.java index fc91c6b42aea363ca1a055e1ebfdec867a4a78b8..b8579d1694b229bdee85016f3fa05bf61976b6f9 100644 --- a/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/config/jackson/BigNumberSerializer.java +++ b/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/config/jackson/BigNumberSerializer.java @@ -44,12 +44,12 @@ public class BigNumberSerializer extends NumberSerializer { } @Override - public void serialize(Number value, JsonGenerator gen, SerializerProvider provider) throws IOException { + public void serialize(Number value, JsonGenerator generator, SerializerProvider provider) throws IOException { // 序列化为字符串 if (value.longValue() > MIN_SAFE_INTEGER && value.longValue() < MAX_SAFE_INTEGER) { - super.serialize(value, gen, provider); + super.serialize(value, generator, provider); } else { - gen.writeString(value.toString()); + generator.writeString(value.toString()); } } } diff --git a/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/config/jackson/IEnumDeserializer.java b/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/config/jackson/IEnumDeserializer.java new file mode 100644 index 0000000000000000000000000000000000000000..46b86949d51726086169ba22ab7ad873c3c44e22 --- /dev/null +++ b/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/config/jackson/IEnumDeserializer.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.charles7c.cnadmin.common.config.jackson; + +import java.io.IOException; +import java.lang.reflect.Field; + +import com.baomidou.mybatisplus.annotation.IEnum; +import com.fasterxml.jackson.core.*; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.annotation.JacksonStdImpl; + +import cn.hutool.core.util.ClassUtil; +import cn.hutool.core.util.ReflectUtil; + +/** + * 通用枚举接口 IEnum 反序列化器 + * + * @author Charles7c + * @since 2023/1/8 13:56 + */ +@JacksonStdImpl +public class IEnumDeserializer extends JsonDeserializer { + + /** 静态实例 */ + public static final IEnumDeserializer SERIALIZER_INSTANCE = new IEnumDeserializer(); + + @Override + public IEnum deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { + Class targetClass = jsonParser.getCurrentValue().getClass(); + String fieldName = jsonParser.getCurrentName(); + String value = jsonParser.getText(); + return this.getEnum(targetClass, value, fieldName); + } + + /** + * 通过某字段对应值获取枚举,获取不到时为 {@code null} + * + * @param targetClass + * 目标类型 + * @param value + * 字段值 + * @param fieldName + * 字段名 + * @return 对应枚举 ,获取不到时为 {@code null} + */ + public IEnum getEnum(Class targetClass, String value, String fieldName) { + Field field = ReflectUtil.getField(targetClass, fieldName); + Class fieldTypeClass = field.getType(); + Object[] enumConstants = fieldTypeClass.getEnumConstants(); + for (Object enumConstant : enumConstants) { + if (ClassUtil.isAssignable(IEnum.class, fieldTypeClass)) { + IEnum iEnum = (IEnum)enumConstant; + if (iEnum.getValue().equals(Integer.valueOf(value))) { + return iEnum; + } + } + } + return null; + } +} diff --git a/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/config/jackson/IEnumSerializer.java b/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/config/jackson/IEnumSerializer.java new file mode 100644 index 0000000000000000000000000000000000000000..1681ff6925de0aea78a580e9cc06c1d97e341e8b --- /dev/null +++ b/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/config/jackson/IEnumSerializer.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.charles7c.cnadmin.common.config.jackson; + +import java.io.IOException; + +import com.baomidou.mybatisplus.annotation.IEnum; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.annotation.JacksonStdImpl; + +/** + * 通用枚举接口 IEnum 序列化器 + * + * @author Charles7c + * @since 2023/1/8 13:56 + */ +@JacksonStdImpl +public class IEnumSerializer extends JsonSerializer { + + /** 静态实例 */ + public static final IEnumSerializer SERIALIZER_INSTANCE = new IEnumSerializer(); + + @Override + public void serialize(IEnum value, JsonGenerator generator, SerializerProvider serializers) throws IOException { + generator.writeObject(value.getValue()); + } +} diff --git a/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/config/jackson/JacksonConfiguration.java b/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/config/jackson/JacksonConfiguration.java index 20d9735edd3a8d69a8def441d371a7a84f58f5df..c95502f18e03658a5e1ec252c48415fd97b3ee2e 100644 --- a/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/config/jackson/JacksonConfiguration.java +++ b/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/config/jackson/JacksonConfiguration.java @@ -16,7 +16,6 @@ package top.charles7c.cnadmin.common.config.jackson; -import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import java.time.LocalDate; @@ -30,11 +29,11 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import com.baomidou.mybatisplus.annotation.IEnum; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; @@ -55,7 +54,7 @@ import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; public class JacksonConfiguration { /** - * 全局配置序列化返回 JSON 处理 + * 针对数值类型:Long、BigInteger、BigDecimal,时间类型:LocalDateTime、LocalDate、LocalTime 的序列化和反序列化 */ @Bean public Jackson2ObjectMapperBuilderCustomizer customizer() { @@ -64,23 +63,14 @@ public class JacksonConfiguration { String timeFormatPattern = "HH:mm:ss"; return builder -> { - // 针对通用枚举 IEnum 的转换 - builder.serializerByType(IEnum.class, new JsonSerializer>() { - @Override - public void serialize(IEnum value, JsonGenerator gen, SerializerProvider serializers) - throws IOException { - gen.writeNumber(value.getValue()); - } - }); - - // 针对 Long、BigInteger、BigDecimal 的转换 + // 针对数值类型:Long、BigInteger、BigDecimal 的序列化和反序列化 JavaTimeModule javaTimeModule = new JavaTimeModule(); javaTimeModule.addSerializer(Long.class, BigNumberSerializer.SERIALIZER_INSTANCE); javaTimeModule.addSerializer(Long.TYPE, BigNumberSerializer.SERIALIZER_INSTANCE); javaTimeModule.addSerializer(BigInteger.class, BigNumberSerializer.SERIALIZER_INSTANCE); javaTimeModule.addSerializer(BigDecimal.class, ToStringSerializer.instance); - // 针对 LocalDateTime、LocalDate、LocalTime 的转换 + // 针对时间类型:LocalDateTime、LocalDate、LocalTime 的序列化和反序列化 DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(dateTimeFormatPattern); javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(dateTimeFormatter)); javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(dateTimeFormatter)); @@ -97,4 +87,21 @@ public class JacksonConfiguration { log.info(">>>初始化 Jackson 配置<<<"); }; } + + /** + * 针对通用枚举接口 IEnum 的序列化和反序列化 + */ + @Bean + public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) { + SimpleModule simpleModule = new SimpleModule(); + simpleModule.addSerializer(IEnum.class, IEnumSerializer.SERIALIZER_INSTANCE); + + SimpleDeserializersWrapper deserializers = new SimpleDeserializersWrapper(); + deserializers.addDeserializer(IEnum.class, IEnumDeserializer.SERIALIZER_INSTANCE); + simpleModule.setDeserializers(deserializers); + + ObjectMapper objectMapper = builder.createXmlMapper(false).build(); + objectMapper.registerModule(simpleModule); + return objectMapper; + } } diff --git a/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/config/jackson/SimpleDeserializersWrapper.java b/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/config/jackson/SimpleDeserializersWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..aa9629dd1f66a762e87cb8fd6f0fdfba97eac014 --- /dev/null +++ b/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/config/jackson/SimpleDeserializersWrapper.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.charles7c.cnadmin.common.config.jackson; + +import lombok.extern.slf4j.Slf4j; + +import com.fasterxml.jackson.databind.BeanDescription; +import com.fasterxml.jackson.databind.DeserializationConfig; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.module.SimpleDeserializers; +import com.fasterxml.jackson.databind.type.ClassKey; + +/** + * 反序列化器包装类(重写 Jackson 反序列化枚举方法,参阅:FasterXML/jackson-databind#2842) + * + *

+ * 默认处理:
+ * 1. Jackson 会先查找指定枚举类型对应的反序列化器(例如:GenderEnum 枚举类型,则是找 GenderEnum 枚举类型的对应反序列化器);
+ * 2. 如果找不到则开始查找 Enum 类型(所有枚举父类)的反序列化器;
+ * 3. 如果都找不到则会采用默认的枚举反序列化器(它仅能根据枚举类型的 name、ordinal 来进行反序列化)。 + *

+ *

+ * 重写增强后:
+ * 1. 同默认 1;
+ * 2. 同默认 2;
+ * 3. 如果也找不到 Enum 类型(所有枚举父类)的反序列化器,开始查找指定枚举类型的接口的反序列化器(例如:GenderEnum 枚举类型,则是找它的接口 IEnum 的反序列化器);
+ * 4. 同默认 3。 + *

+ * + * @author Charles7c + * @since 2023/1/8 13:28 + */ +@Slf4j +public class SimpleDeserializersWrapper extends SimpleDeserializers { + + @Override + public JsonDeserializer findEnumDeserializer(Class type, DeserializationConfig config, + BeanDescription beanDesc) throws JsonMappingException { + JsonDeserializer deser = super.findEnumDeserializer(type, config, beanDesc); + if (deser != null) { + return deser; + } + + // 重写增强:开始查找指定枚举类型的接口的反序列化器(例如:GenderEnum 枚举类型,则是找它的接口 IEnum 的反序列化器) + for (Class typeInterface : type.getInterfaces()) { + deser = this._classMappings.get(new ClassKey(typeInterface)); + if (deser != null) { + return deser; + } + } + return null; + } +} diff --git a/continew-admin-system/src/main/java/top/charles7c/cnadmin/auth/model/vo/UserInfoVO.java b/continew-admin-system/src/main/java/top/charles7c/cnadmin/auth/model/vo/UserInfoVO.java index 4322b58b3bb7cab9e65028111384c6355baddea3..ebd3c384344591c2946731c5ebb6b3f0cfd5167f 100644 --- a/continew-admin-system/src/main/java/top/charles7c/cnadmin/auth/model/vo/UserInfoVO.java +++ b/continew-admin-system/src/main/java/top/charles7c/cnadmin/auth/model/vo/UserInfoVO.java @@ -65,7 +65,7 @@ public class UserInfoVO implements Serializable { /** * 性别(0未知 1男 2女) */ - @Schema(description = "性别(0未知 1男 2女)") + @Schema(description = "性别(0未知 1男 2女)", type = "Integer", allowableValues = {"0", "1", "2"}) private GenderEnum gender; /** diff --git a/continew-admin-system/src/main/java/top/charles7c/cnadmin/system/model/request/UpdateBasicInfoRequest.java b/continew-admin-system/src/main/java/top/charles7c/cnadmin/system/model/request/UpdateBasicInfoRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..9bb5569edb2e7ba67c0ea932155701a17336508d --- /dev/null +++ b/continew-admin-system/src/main/java/top/charles7c/cnadmin/system/model/request/UpdateBasicInfoRequest.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.charles7c.cnadmin.system.model.request; + +import java.io.Serializable; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import lombok.Data; + +import io.swagger.v3.oas.annotations.media.Schema; + +import top.charles7c.cnadmin.common.enums.GenderEnum; + +/** + * 修改基础信息 + * + * @author Charles7c + * @since 2023/1/7 23:08 + */ +@Data +@Schema(description = "修改基础信息") +public class UpdateBasicInfoRequest implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 昵称 + */ + @Schema(description = "昵称") + @NotBlank(message = "昵称不能为空") + @Size(max = 32, message = "昵称长度不能超过 32 个字符") + private String nickname; + + /** + * 性别(0未知 1男 2女) + */ + @Schema(description = "性别(0未知 1男 2女)", type = "Integer", allowableValues = {"0", "1", "2"}) + @NotNull(message = "非法性别") + private GenderEnum gender; +} diff --git a/continew-admin-system/src/main/java/top/charles7c/cnadmin/system/service/UserService.java b/continew-admin-system/src/main/java/top/charles7c/cnadmin/system/service/UserService.java index 9ed6ffdc04a215b2db5c62a4836295a12d42d503..a95289e91345201d0c57482a878965c7ea37b986 100644 --- a/continew-admin-system/src/main/java/top/charles7c/cnadmin/system/service/UserService.java +++ b/continew-admin-system/src/main/java/top/charles7c/cnadmin/system/service/UserService.java @@ -16,6 +16,8 @@ package top.charles7c.cnadmin.system.service; +import org.springframework.web.multipart.MultipartFile; + import top.charles7c.cnadmin.system.model.entity.SysUser; /** @@ -36,12 +38,21 @@ public interface UserService { SysUser getByUsername(String username); /** - * 修改头像 + * 上传头像 * * @param avatar - * 头像路径 + * 头像文件 * @param userId - * 用户ID + * 用户 ID + * @return 新头像路径 + */ + String uploadAvatar(MultipartFile avatar, Long userId); + + /** + * 修改信息 + * + * @param user + * 用户信息 */ - void updateAvatar(String avatar, Long userId); + void update(SysUser user); } diff --git a/continew-admin-system/src/main/java/top/charles7c/cnadmin/system/service/impl/UserServiceImpl.java b/continew-admin-system/src/main/java/top/charles7c/cnadmin/system/service/impl/UserServiceImpl.java index baaaa339bc97c633d8f942bffd484e2bbfd5c692..70fc5265d2a007d57683a99fd6e89ab074b331e3 100644 --- a/continew-admin-system/src/main/java/top/charles7c/cnadmin/system/service/impl/UserServiceImpl.java +++ b/continew-admin-system/src/main/java/top/charles7c/cnadmin/system/service/impl/UserServiceImpl.java @@ -16,13 +16,26 @@ package top.charles7c.cnadmin.system.service.impl; +import java.io.File; + import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.StrUtil; + +import top.charles7c.cnadmin.common.config.properties.LocalStorageProperties; +import top.charles7c.cnadmin.common.model.dto.LoginUser; +import top.charles7c.cnadmin.common.util.FileUtils; +import top.charles7c.cnadmin.common.util.helper.LoginHelper; +import top.charles7c.cnadmin.common.util.validate.CheckUtils; import top.charles7c.cnadmin.system.mapper.UserMapper; import top.charles7c.cnadmin.system.model.entity.SysUser; import top.charles7c.cnadmin.system.service.UserService; @@ -38,6 +51,7 @@ import top.charles7c.cnadmin.system.service.UserService; public class UserServiceImpl implements UserService { private final UserMapper userMapper; + private final LocalStorageProperties localStorageProperties; @Override public SysUser getByUsername(String username) { @@ -45,8 +59,41 @@ public class UserServiceImpl implements UserService { } @Override - public void updateAvatar(String avatar, Long userId) { + @Transactional(rollbackFor = Exception.class) + public String uploadAvatar(MultipartFile avatarFile, Long userId) { + // 上传新头像 + String avatarPath = localStorageProperties.getPath().getAvatar(); + File newAvatarFile = FileUtils.upload(avatarFile, avatarPath, false); + CheckUtils.exIfNull(newAvatarFile, "上传头像失败"); + assert newAvatarFile != null; + + // 更新用户头像 + String newAvatar = newAvatarFile.getName(); userMapper.update(null, - new LambdaUpdateWrapper().set(SysUser::getAvatar, avatar).eq(SysUser::getUserId, userId)); + new LambdaUpdateWrapper().set(SysUser::getAvatar, newAvatar).eq(SysUser::getUserId, userId)); + + // 删除原头像 + LoginUser loginUser = LoginHelper.getLoginUser(); + String oldAvatar = loginUser.getAvatar(); + if (StrUtil.isNotBlank(loginUser.getAvatar())) { + FileUtil.del(avatarPath + oldAvatar); + } + + // 更新登录用户信息 + loginUser.setAvatar(newAvatar); + LoginHelper.updateLoginUser(loginUser); + return newAvatar; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(SysUser user) { + userMapper.updateById(user); + + // 更新登录用户信息 + SysUser sysUser = userMapper.selectById(user.getUserId()); + LoginUser loginUser = LoginHelper.getLoginUser(); + BeanUtil.copyProperties(sysUser, loginUser); + LoginHelper.updateLoginUser(loginUser); } } diff --git a/continew-admin-ui/src/api/interceptor.ts b/continew-admin-ui/src/api/interceptor.ts index 9fdfbe5f230add51693364591fc43dd1fa56e2b2..c573419b7b0345d4cee26dfa2de0b7d3b71b65b2 100644 --- a/continew-admin-ui/src/api/interceptor.ts +++ b/continew-admin-ui/src/api/interceptor.ts @@ -38,7 +38,11 @@ axios.interceptors.request.use( // add response interceptors axios.interceptors.response.use( (response: AxiosResponse) => { - return response.data; + const res = response.data; + if (!res.success) { + Message.error(res.msg); + } + return res; }, (error) => { const res = error.response.data; diff --git a/continew-admin-ui/src/api/system/user-center.ts b/continew-admin-ui/src/api/system/user-center.ts index 1a798fc1634abb74c90f9ef1c67ae816b4827d00..5bb6987176547ed1b6fe894b2ddcc1a002b14eb3 100644 --- a/continew-admin-ui/src/api/system/user-center.ts +++ b/continew-admin-ui/src/api/system/user-center.ts @@ -13,6 +13,10 @@ export function uploadAvatar(data: FormData) { return axios.post('/system/user/center/avatar', data); } -export function saveUserInfo() { - return axios.get('/api/user/save-info'); +export interface UpdateBasicInfoReq { + nickname: string; + gender: number; +} +export function updateBasicInfo(req: UpdateBasicInfoReq) { + return axios.patch('/system/user/center/basic/info', req); } \ No newline at end of file diff --git a/continew-admin-ui/src/views/login/components/login-form.vue b/continew-admin-ui/src/views/login/components/login-form.vue index 1c3a364326b07971444261ebfe8682782e97a823..0776572108d28445559ba01044963e8b40575619 100644 --- a/continew-admin-ui/src/views/login/components/login-form.vue +++ b/continew-admin-ui/src/views/login/components/login-form.vue @@ -19,6 +19,8 @@