用户信息变更
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
-- 修复字符编码问题
|
||||
-- 删除现有数据库(如果存在)
|
||||
-- DROP DATABASE IF EXISTS `school_news`;
|
||||
DROP DATABASE IF EXISTS `school_news`;
|
||||
|
||||
-- 创建数据库,使用utf8mb4字符集
|
||||
CREATE DATABASE IF NOT EXISTS `school_news` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
@@ -32,6 +32,7 @@ CREATE TABLE `tb_sys_user_info` (
|
||||
`given_name` VARCHAR(50) DEFAULT NULL COMMENT '名',
|
||||
`full_name` VARCHAR(100) DEFAULT NULL COMMENT '全名',
|
||||
`level` INT(4) DEFAULT 1 COMMENT '等级',
|
||||
`student_id` VARCHAR(50) DEFAULT NULL COMMENT '学号',
|
||||
`id_card` VARCHAR(50) DEFAULT NULL COMMENT '身份证号',
|
||||
`address` VARCHAR(255) DEFAULT NULL COMMENT '地址',
|
||||
`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
|
||||
@@ -62,6 +62,13 @@ public class TbSysUserInfo extends BaseDTO {
|
||||
*/
|
||||
private Float level;
|
||||
|
||||
/**
|
||||
* @description 学号
|
||||
* @author yslg
|
||||
* @since 2025-11-26
|
||||
*/
|
||||
private String studentId;
|
||||
|
||||
/**
|
||||
* @description 身份证号
|
||||
* @author yslg
|
||||
@@ -132,6 +139,14 @@ public class TbSysUserInfo extends BaseDTO {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public String getStudentId() {
|
||||
return studentId;
|
||||
}
|
||||
|
||||
public void setStudentId(String studentId) {
|
||||
this.studentId = studentId;
|
||||
}
|
||||
|
||||
public String getIdCard() {
|
||||
return idCard;
|
||||
}
|
||||
@@ -160,6 +175,7 @@ public class TbSysUserInfo extends BaseDTO {
|
||||
", givenName='" + givenName + '\'' +
|
||||
", fullName='" + fullName + '\'' +
|
||||
", level=" + level +
|
||||
", studentId='" + studentId + '\'' +
|
||||
", idCard='" + idCard + '\'' +
|
||||
", address='" + address + '\'' +
|
||||
", createTime=" + getCreateTime() +
|
||||
|
||||
@@ -16,6 +16,7 @@ public class UserVO {
|
||||
private String givenName;
|
||||
private String fullName;
|
||||
private Float level;
|
||||
private String studentId;
|
||||
private String idCard;
|
||||
private String address;
|
||||
private String deptID;
|
||||
@@ -138,6 +139,12 @@ public class UserVO {
|
||||
public void setLevel(Float level) {
|
||||
this.level = level;
|
||||
}
|
||||
public String getStudentId() {
|
||||
return studentId;
|
||||
}
|
||||
public void setStudentId(String studentId) {
|
||||
this.studentId = studentId;
|
||||
}
|
||||
public Date getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
@@ -611,12 +611,12 @@ public class SysUserServiceImpl implements SysUserService {
|
||||
filter.setEmail(email);
|
||||
filter.setDeleted(false);
|
||||
|
||||
if (StringUtils.hasText(excludeId)) {
|
||||
filter.setID(excludeId);
|
||||
}
|
||||
// if (StringUtils.hasText(excludeId)) {
|
||||
// filter.setID(excludeId);
|
||||
// }
|
||||
|
||||
long count = userMapper.selectByFilter(filter, userDeptRoles).size();
|
||||
boolean exists = count > 0;
|
||||
List<TbSysUser> userList = userMapper.selectByFilter(filter, userDeptRoles);
|
||||
boolean exists = userList.size() >1 && (userList.size() == 1 && !userList.get(0).getID().equals(excludeId));
|
||||
|
||||
logger.info("邮箱存在性检查完成:{},存在:{}", email, exists);
|
||||
resultDomain.success("检查完成", exists);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
<result column="given_name" property="givenName" />
|
||||
<result column="full_name" property="fullName" />
|
||||
<result column="level" property="level" />
|
||||
<result column="student_id" property="studentId" />
|
||||
<result column="id_card" property="idCard" />
|
||||
<result column="address" property="address" />
|
||||
<result column="create_time" property="createTime" />
|
||||
@@ -19,7 +20,7 @@
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
id, user_id, avatar, gender, family_name, given_name, full_name, level, id_card, address, create_time, update_time, delete_time, deleted
|
||||
id, user_id, avatar, gender, student_id, family_name, given_name, full_name, level, id_card, address, create_time, update_time, delete_time, deleted
|
||||
</sql>
|
||||
<!-- insertUserInfo -->
|
||||
|
||||
@@ -39,6 +40,7 @@
|
||||
<if test="userInfo.givenName != null">given_name = #{userInfo.givenName},</if>
|
||||
<if test="userInfo.fullName != null">full_name = #{userInfo.fullName},</if>
|
||||
<if test="userInfo.level != null">level = #{userInfo.level},</if>
|
||||
<if test="userInfo.studentId != null">student_id = #{userInfo.studentId},</if>
|
||||
<if test="userInfo.idCard != null">id_card = #{userInfo.idCard},</if>
|
||||
<if test="userInfo.address != null">address = #{userInfo.address},</if>
|
||||
<if test="userInfo.updater != null">updater = #{userInfo.updater},</if>
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
<result column="dept_name" property="deptName" jdbcType="VARCHAR"/>
|
||||
<result column="role_name" property="roleName" jdbcType="VARCHAR"/>
|
||||
<result column="level" property="level" jdbcType="INTEGER"/>
|
||||
<result column="student_id" property="studentId" jdbcType="VARCHAR"/>
|
||||
<result column="id_card" property="idCard" jdbcType="VARCHAR"/>
|
||||
<result column="address" property="address" jdbcType="VARCHAR"/>
|
||||
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
|
||||
@@ -64,13 +65,13 @@
|
||||
</sql>
|
||||
|
||||
<sql id="FullUser_Column_List">
|
||||
id, user_id, avatar, gender, family_name, given_name, full_name, id_card, address,
|
||||
id, user_id, avatar, gender, family_name, given_name, full_name, student_id,id_card, address,
|
||||
create_time, update_time, delete_time, deleted, status
|
||||
</sql>
|
||||
|
||||
<!-- 用户信息字段 -->
|
||||
<sql id="UserInfo_Column_List">
|
||||
id, user_id, avatar, gender, family_name, given_name, full_name, id_card, address,
|
||||
id, user_id, avatar, gender, family_name, given_name, full_name, student_id,id_card, address,
|
||||
create_time, update_time, delete_time, deleted
|
||||
</sql>
|
||||
|
||||
@@ -230,6 +231,7 @@
|
||||
ui.given_name,
|
||||
ui.full_name,
|
||||
ui.level,
|
||||
ui.student_id,
|
||||
ui.id_card,
|
||||
ui.address,
|
||||
udr.dept_id,
|
||||
@@ -349,6 +351,7 @@
|
||||
ui.given_name,
|
||||
ui.full_name,
|
||||
ui.level,
|
||||
ui.student_id,
|
||||
ui.id_card,
|
||||
ui.address,
|
||||
udr.dept_id,
|
||||
@@ -491,6 +494,8 @@
|
||||
<if test="userInfo.familyName != null">family_name = #{userInfo.familyName},</if>
|
||||
<if test="userInfo.givenName != null">given_name = #{userInfo.givenName},</if>
|
||||
<if test="userInfo.fullName != null">full_name = #{userInfo.fullName},</if>
|
||||
<if test="userInfo.level != null">level = #{userInfo.level},</if>
|
||||
<if test="userInfo.studentId != null">student_id = #{userInfo.studentId},</if>
|
||||
<if test="userInfo.idCard != null">id_card = #{userInfo.idCard},</if>
|
||||
<if test="userInfo.address != null">address = #{userInfo.address},</if>
|
||||
<if test="userInfo.updateTime != null">update_time = #{userInfo.updateTime}</if>
|
||||
@@ -562,6 +567,7 @@
|
||||
tus.email,
|
||||
tsui.avatar,
|
||||
tsui.gender,
|
||||
tsui.student_id,
|
||||
(SELECT dept_path FROM dept_hierarchy WHERE parent_id IS NULL LIMIT 1) as dept_name,
|
||||
tsr.name as role_name,
|
||||
tsui.level,
|
||||
|
||||
@@ -56,15 +56,34 @@ public class UserProfileController {
|
||||
* 更新个人信息
|
||||
*/
|
||||
@PutMapping("/info/update")
|
||||
public ResultDomain<TbSysUserInfo> updateUserProfile(@HttpLogin LoginDomain loginDomain, @RequestBody TbSysUserInfo userInfo) {
|
||||
// TODO: 实现更新个人信息(姓名、部门、联系方式等)
|
||||
ResultDomain<TbSysUserInfo> result = userService.updateUserInfo(userInfo);
|
||||
if (result.isSuccess()) {
|
||||
public ResultDomain<UserVO> updateUserProfile(@HttpLogin LoginDomain loginDomain, @RequestBody UserVO userVO) {
|
||||
ResultDomain<UserVO> result = new ResultDomain<>();
|
||||
// 更新tb_sys_user
|
||||
TbSysUser user = new TbSysUser();
|
||||
user.setID(userVO.getUserID());
|
||||
user.setUsername(userVO.getUsername());
|
||||
user.setEmail(userVO.getEmail());
|
||||
user.setPhone(userVO.getPhone());
|
||||
ResultDomain<TbSysUser> re = userService.updateUser(user);
|
||||
if (!re.isSuccess()) {
|
||||
result.fail(re.getMessage());
|
||||
return result;
|
||||
}
|
||||
|
||||
// 更新tb_sys_user_info
|
||||
TbSysUserInfo userInfo = new TbSysUserInfo();
|
||||
userInfo.setUserID(userVO.getUserID());
|
||||
userInfo.setAvatar(userVO.getAvatar());
|
||||
userInfo.setGender(userVO.getGender());
|
||||
userInfo.setStudentId(userVO.getStudentId());
|
||||
|
||||
ResultDomain<TbSysUserInfo> result1 = userService.updateUserInfo(userInfo);
|
||||
if (result1.isSuccess()) {
|
||||
result.success("个人信息更新成功", userVO);
|
||||
return result;
|
||||
} else {
|
||||
ResultDomain<TbSysUserInfo> result2 = new ResultDomain<>();
|
||||
result2.fail(result.getCode(), result.getMessage());
|
||||
return result2;
|
||||
result.fail(result1.getCode(), result1.getMessage());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -184,7 +184,7 @@ request.interceptors.response.use(
|
||||
case 401:
|
||||
ElMessage.error('认证失败,请重新登录');
|
||||
TokenManager.removeToken();
|
||||
window.location.href = '/login';
|
||||
window.location.href = '/schoolNewsWeb/login';
|
||||
break;
|
||||
case 403:
|
||||
ElMessage.error('没有权限访问该资源');
|
||||
|
||||
@@ -31,7 +31,7 @@ export const userProfileApi = {
|
||||
* @param userInfo 用户信息
|
||||
* @returns Promise<ResultDomain<any>>
|
||||
*/
|
||||
async updateUserProfile(userInfo: any): Promise<ResultDomain<any>> {
|
||||
async updateUserProfile(userInfo: UserVO): Promise<ResultDomain<any>> {
|
||||
const response = await api.put<any>('/usercenter/profile/info/update', userInfo);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -89,6 +89,7 @@ import type { UserVO, SysMenu } from '@/types';
|
||||
import { ChangeHome } from '@/components/base';
|
||||
import userIcon from '@/assets/imgs/user.svg';
|
||||
import settingsIcon from '@/assets/imgs/settings.svg';
|
||||
import { FILE_DOWNLOAD_URL } from '@/config';
|
||||
// Props
|
||||
interface Props {
|
||||
user?: UserVO | null;
|
||||
@@ -118,7 +119,7 @@ const isLoggedIn = computed(() => {
|
||||
});
|
||||
|
||||
const userAvatar = computed(() => {
|
||||
return props.user?.avatar || '';
|
||||
return props.user?.avatar ? FILE_DOWNLOAD_URL + props.user?.avatar : '';
|
||||
});
|
||||
|
||||
const avatarText = computed(() => {
|
||||
|
||||
@@ -29,6 +29,9 @@ export interface SysUser extends BaseDTO {
|
||||
export interface SysUserInfo extends BaseDTO {
|
||||
/** 用户ID */
|
||||
userID?: string;
|
||||
/** 用户名(迁移到userInfo中,便于统一展示) */
|
||||
username?: string;
|
||||
studentId?: string;
|
||||
/** 真实姓名 */
|
||||
realName?: string;
|
||||
/** 昵称 */
|
||||
@@ -51,6 +54,7 @@ export interface SysUserInfo extends BaseDTO {
|
||||
export interface UserVO extends BaseDTO {
|
||||
/** 用户ID(兼容字段) */
|
||||
userID?: string;
|
||||
studentId?: string;
|
||||
/** 用户名 */
|
||||
username?: string;
|
||||
/** 邮箱 */
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<!-- 头像 -->
|
||||
<div class="avatar-wrapper">
|
||||
<img
|
||||
:src="userInfo?.avatar && userInfo.avatar!='default' ? userInfo.avatar : defaultAvatar"
|
||||
:src="userInfo?.avatar && userInfo.avatar!='default' ? FILE_DOWNLOAD_URL + userInfo.avatar : defaultAvatar"
|
||||
:alt="userInfo?.username"
|
||||
class="avatar"
|
||||
/>
|
||||
@@ -57,6 +57,7 @@ import femaleIcon from '@/assets/imgs/female.svg';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { getLevelWordIconUrl } from '@/utils/iconUtils';
|
||||
import { FILE_DOWNLOAD_URL } from '@/config';
|
||||
|
||||
const router = useRouter();
|
||||
const userInfo = ref<UserVO>();
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
<template>
|
||||
|
||||
<div class="personal-info">
|
||||
<el-form :model="userForm" label-width="120px" class="info-form">
|
||||
<el-form-item label="头像">
|
||||
<div class="avatar-upload">
|
||||
<img :src="userForm.avatar || defaultAvatar" alt="头像" class="avatar-preview" />
|
||||
<el-button size="small" @click="handleAvatarUpload">更换头像</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<div class="personal-info">
|
||||
<el-form :model="userForm" label-width="120px" class="info-form" v-loading="loading">
|
||||
<el-form-item label="头像">
|
||||
<FileUpload
|
||||
:as-dialog="false"
|
||||
list-type="cover"
|
||||
v-model:cover-url="userForm.avatar"
|
||||
accept="image/*"
|
||||
:max-size="5"
|
||||
tip="点击上传头像"
|
||||
module="avatar"
|
||||
@success="handleAvatarSuccess"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="用户名">
|
||||
<el-input v-model="userForm.username" disabled />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="姓名">
|
||||
<el-input v-model="userForm.realName" />
|
||||
<el-input v-model="userForm.username" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="性别">
|
||||
@@ -36,71 +37,142 @@
|
||||
<el-input v-model="userForm.deptName" disabled />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="个人简介">
|
||||
<el-input v-model="userForm.bio" type="textarea" :rows="4" placeholder="介绍一下自己吧..." />
|
||||
<el-form-item label="学号">
|
||||
<el-input v-model="userForm.studentId" placeholder="请输入学号" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSave">保存</el-button>
|
||||
<el-button @click="handleCancel">取消</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSave" :loading="saving">保存</el-button>
|
||||
<el-button @click="handleCancel">取消</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { ElForm, ElFormItem, ElInput, ElButton, ElRadio, ElRadioGroup, ElMessage } from 'element-plus';
|
||||
import { UserCenterLayout } from '@/views/user/user-center';
|
||||
// 默认头像
|
||||
const defaultAvatar = new URL('@/assets/imgs/default-avatar.png', import.meta.url).href;
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { userProfileApi } from '@/apis/usercenter';
|
||||
import { FILE_DOWNLOAD_URL } from '@/config';
|
||||
import { FileUpload } from '@/components/file';
|
||||
import type { SysFile, UserVO } from '@/types';
|
||||
|
||||
const loading = ref(false);
|
||||
const saving = ref(false);
|
||||
const originalUserInfo = ref<any>(null);
|
||||
|
||||
const userForm = ref({
|
||||
avatar: '',
|
||||
username: '',
|
||||
realName: '',
|
||||
gender: 1,
|
||||
phone: '',
|
||||
email: '',
|
||||
deptName: '',
|
||||
bio: ''
|
||||
studentId: ''
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
// TODO: 加载用户信息
|
||||
loadUserInfo();
|
||||
});
|
||||
// 接口返回的用户ID,用于提交更新
|
||||
const profileUserId = ref<string | undefined>(undefined);
|
||||
|
||||
function loadUserInfo() {
|
||||
// 模拟数据
|
||||
userForm.value = {
|
||||
avatar: '',
|
||||
username: '平台用户bc7a1b',
|
||||
realName: '张三',
|
||||
gender: 1,
|
||||
phone: '15268425987',
|
||||
email: 'zhangsan@example.com',
|
||||
deptName: '机械学院',
|
||||
bio: ''
|
||||
};
|
||||
// 加载用户信息
|
||||
async function loadUserInfo() {
|
||||
loading.value = true;
|
||||
try {
|
||||
const result = await userProfileApi.getUserProfile();
|
||||
if (result.code === 200 && result.data) {
|
||||
const info: UserVO = result.data;
|
||||
profileUserId.value = info.userID;
|
||||
|
||||
// 保存原始数据用于取消操作
|
||||
let avatarVal = info.avatar || '';
|
||||
if (avatarVal === 'default') {
|
||||
avatarVal = '';
|
||||
} else if (avatarVal && FILE_DOWNLOAD_URL && avatarVal.startsWith(FILE_DOWNLOAD_URL)) {
|
||||
avatarVal = avatarVal.substring(FILE_DOWNLOAD_URL.length);
|
||||
}
|
||||
|
||||
originalUserInfo.value = {
|
||||
avatar: avatarVal,
|
||||
username: info.username || '',
|
||||
gender: info.gender ?? 1,
|
||||
phone: info.phone || '',
|
||||
email: info.email || '',
|
||||
deptName: info.deptName || '',
|
||||
studentId: info.studentId || ''
|
||||
};
|
||||
|
||||
// 填充表单
|
||||
userForm.value = { ...originalUserInfo.value };
|
||||
} else {
|
||||
ElMessage.error(result.message || '获取个人信息失败');
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('加载用户信息失败:', error);
|
||||
ElMessage.error('加载用户信息失败: ' + (error.message || '未知错误'));
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleAvatarUpload() {
|
||||
// TODO: 上传头像
|
||||
ElMessage.info('上传头像功能开发中');
|
||||
/**
|
||||
* 头像上传成功回调
|
||||
*/
|
||||
function handleAvatarSuccess(files: SysFile[]) {
|
||||
if (files && files.length > 0) {
|
||||
ElMessage.success('头像上传成功');
|
||||
}
|
||||
}
|
||||
|
||||
function handleSave() {
|
||||
// TODO: 保存用户信息
|
||||
ElMessage.success('保存成功');
|
||||
/**
|
||||
* 保存用户信息
|
||||
*/
|
||||
async function handleSave() {
|
||||
if (!profileUserId.value) {
|
||||
ElMessage.warning('未获取到用户ID');
|
||||
}
|
||||
|
||||
saving.value = true;
|
||||
try {
|
||||
const userInfo: UserVO = {
|
||||
userID: profileUserId.value,
|
||||
avatar: userForm.value.avatar,
|
||||
gender: userForm.value.gender,
|
||||
studentId: userForm.value.studentId,
|
||||
username: userForm.value.username,
|
||||
phone: userForm.value.phone,
|
||||
email: userForm.value.email,
|
||||
};
|
||||
|
||||
const result = await userProfileApi.updateUserProfile(userInfo);
|
||||
|
||||
if (result.code === 200) {
|
||||
ElMessage.success('保存成功');
|
||||
await loadUserInfo();
|
||||
originalUserInfo.value = { ...userForm.value };
|
||||
} else {
|
||||
ElMessage.error(result.message || '保存失败');
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('保存用户信息失败:', error);
|
||||
ElMessage.error('保存失败: ' + (error.message || '未知错误'));
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消编辑
|
||||
*/
|
||||
function handleCancel() {
|
||||
// 重置表单
|
||||
loadUserInfo();
|
||||
if (originalUserInfo.value) {
|
||||
userForm.value = { ...originalUserInfo.value };
|
||||
ElMessage.info('已取消修改');
|
||||
}
|
||||
}
|
||||
onMounted(() => {
|
||||
loadUserInfo();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -111,18 +183,4 @@ function handleCancel() {
|
||||
.info-form {
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.avatar-upload {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.avatar-preview {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
border: 2px solid #e0e0e0;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user