Merge branch 'master' of https://gitee.com/xiao12feng/xinli
This commit is contained in:
commit
2e550daa71
|
|
@ -1,6 +1,7 @@
|
|||
package com.ddnai.web.controller.psychology;
|
||||
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
|
@ -12,6 +13,8 @@ import org.springframework.web.bind.annotation.PutMapping;
|
|||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import com.ddnai.common.annotation.Anonymous;
|
||||
import com.ddnai.common.annotation.Log;
|
||||
import com.ddnai.common.core.controller.BaseController;
|
||||
import com.ddnai.common.core.domain.AjaxResult;
|
||||
|
|
@ -20,6 +23,7 @@ import com.ddnai.common.core.page.TableDataInfo;
|
|||
import com.ddnai.common.enums.BusinessType;
|
||||
import com.ddnai.common.utils.SecurityUtils;
|
||||
import com.ddnai.common.utils.StringUtils;
|
||||
import com.ddnai.common.utils.poi.ExcelUtil;
|
||||
import com.ddnai.system.domain.psychology.PsyUserProfile;
|
||||
import com.ddnai.system.service.ISysDeptService;
|
||||
import com.ddnai.system.service.ISysPostService;
|
||||
|
|
@ -235,4 +239,45 @@ public class PsyUserProfileController extends BaseController
|
|||
{
|
||||
return toAjax(profileService.deleteProfileByIds(profileIds));
|
||||
}
|
||||
|
||||
// ==================== 导入导出功能 ====================
|
||||
|
||||
/**
|
||||
* 导出用户档案列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('psychology:profile:export')")
|
||||
@Log(title = "用户档案", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, PsyUserProfile profile)
|
||||
{
|
||||
List<PsyUserProfile> list = profileService.selectProfileList(profile);
|
||||
ExcelUtil<PsyUserProfile> util = new ExcelUtil<PsyUserProfile>(PsyUserProfile.class);
|
||||
util.exportExcel(response, list, "用户档案数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载用户档案导入模板
|
||||
*/
|
||||
@Anonymous
|
||||
@GetMapping("/importTemplate")
|
||||
public void importTemplate(HttpServletResponse response)
|
||||
{
|
||||
ExcelUtil<PsyUserProfile> util = new ExcelUtil<PsyUserProfile>(PsyUserProfile.class);
|
||||
util.importTemplateExcel(response, "用户档案数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入用户档案数据
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('psychology:profile:import')")
|
||||
@Log(title = "用户档案", businessType = BusinessType.IMPORT)
|
||||
@PostMapping("/importData")
|
||||
public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
|
||||
{
|
||||
ExcelUtil<PsyUserProfile> util = new ExcelUtil<PsyUserProfile>(PsyUserProfile.class);
|
||||
List<PsyUserProfile> profileList = util.importExcel(file.getInputStream());
|
||||
String operName = getUsername();
|
||||
String message = profileService.importProfile(profileList, updateSupport, operName);
|
||||
return success(message);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -178,33 +178,22 @@ public class SysLoginController
|
|||
String infoNumberTrimmed = infoNumber.trim();
|
||||
SysUser user = null;
|
||||
|
||||
// 优先通过信息编号查找用户档案,然后通过userId查找用户
|
||||
// 严格模式:必须通过信息编号在用户档案中查找
|
||||
// 只有在用户档案中存在的信息编号才能登录
|
||||
com.ddnai.system.domain.psychology.PsyUserProfile profile = userProfileService.selectProfileByInfoNumber(infoNumberTrimmed);
|
||||
if (profile != null && profile.getUserId() != null)
|
||||
|
||||
if (profile == null)
|
||||
{
|
||||
return AjaxResult.error("信息编号不存在,请先创建用户档案");
|
||||
}
|
||||
|
||||
if (profile.getUserId() == null)
|
||||
{
|
||||
return AjaxResult.error("用户档案异常,未关联系统用户");
|
||||
}
|
||||
|
||||
// 通过档案中的userId查找用户
|
||||
user = userService.selectUserById(profile.getUserId());
|
||||
}
|
||||
|
||||
// 如果通过信息编号找不到,则使用原来的逻辑(兼容旧版本)
|
||||
if (user == null)
|
||||
{
|
||||
// 支持两种方式:1. 通过user_name查找 2. 如果是数字,通过user_id查找
|
||||
user = userService.selectUserByUserName(infoNumberTrimmed);
|
||||
|
||||
// 如果通过user_name找不到,且输入的是数字,尝试通过user_id查找
|
||||
if (user == null && StringUtils.isNumeric(infoNumberTrimmed))
|
||||
{
|
||||
try
|
||||
{
|
||||
Long userId = Long.parseLong(infoNumberTrimmed);
|
||||
user = userService.selectUserById(userId);
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
// 数字格式错误,忽略
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查系统有效时间(系统管理员不受限制)
|
||||
try
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import org.springframework.web.bind.annotation.RequestBody;
|
|||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import com.ddnai.common.annotation.Anonymous;
|
||||
import com.ddnai.common.annotation.Log;
|
||||
import com.ddnai.common.core.controller.BaseController;
|
||||
import com.ddnai.common.core.domain.AjaxResult;
|
||||
|
|
@ -87,7 +88,8 @@ public class SysUserController extends BaseController
|
|||
return success(message);
|
||||
}
|
||||
|
||||
@PostMapping("/importTemplate")
|
||||
@Anonymous
|
||||
@GetMapping("/importTemplate")
|
||||
public void importTemplate(HttpServletResponse response)
|
||||
{
|
||||
ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ public class SysUser extends BaseEntity
|
|||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 用户ID */
|
||||
/** 用户ID - 只在导出时显示,导入时不需要,通过信息编号自动设置 */
|
||||
@Excel(name = "用户序号", type = Type.EXPORT, cellType = ColumnType.NUMERIC, prompt = "用户编号")
|
||||
private Long userId;
|
||||
|
||||
|
|
@ -92,6 +92,44 @@ public class SysUser extends BaseEntity
|
|||
/** 角色ID */
|
||||
private Long roleId;
|
||||
|
||||
// ==================== 心理档案相关字段 ====================
|
||||
|
||||
/** 信息编号 */
|
||||
@Excel(name = "信息编号")
|
||||
private String infoNumber;
|
||||
|
||||
/** 档案类型 */
|
||||
@Excel(name = "档案类型", readConverterExp = "standard=标准,child=儿童,adult=成人,senior=老年")
|
||||
private String profileType;
|
||||
|
||||
/** 身份证号 */
|
||||
@Excel(name = "身份证号")
|
||||
private String idCard;
|
||||
|
||||
/** 生日 */
|
||||
@Excel(name = "生日", width = 30, dateFormat = "yyyy-MM-dd")
|
||||
private Date birthday;
|
||||
|
||||
/** 学历 */
|
||||
@Excel(name = "学历")
|
||||
private String education;
|
||||
|
||||
/** 职业 */
|
||||
@Excel(name = "职业")
|
||||
private String occupation;
|
||||
|
||||
/** 地址 */
|
||||
@Excel(name = "地址")
|
||||
private String address;
|
||||
|
||||
/** 紧急联系人 */
|
||||
@Excel(name = "紧急联系人")
|
||||
private String emergencyContact;
|
||||
|
||||
/** 紧急联系电话 */
|
||||
@Excel(name = "紧急联系电话")
|
||||
private String emergencyPhone;
|
||||
|
||||
public SysUser()
|
||||
{
|
||||
|
||||
|
|
@ -310,6 +348,98 @@ public class SysUser extends BaseEntity
|
|||
this.roleId = roleId;
|
||||
}
|
||||
|
||||
// ==================== 心理档案字段的 Getter/Setter ====================
|
||||
|
||||
public String getInfoNumber()
|
||||
{
|
||||
return infoNumber;
|
||||
}
|
||||
|
||||
public void setInfoNumber(String infoNumber)
|
||||
{
|
||||
this.infoNumber = infoNumber;
|
||||
}
|
||||
|
||||
public String getProfileType()
|
||||
{
|
||||
return profileType;
|
||||
}
|
||||
|
||||
public void setProfileType(String profileType)
|
||||
{
|
||||
this.profileType = profileType;
|
||||
}
|
||||
|
||||
public String getIdCard()
|
||||
{
|
||||
return idCard;
|
||||
}
|
||||
|
||||
public void setIdCard(String idCard)
|
||||
{
|
||||
this.idCard = idCard;
|
||||
}
|
||||
|
||||
public Date getBirthday()
|
||||
{
|
||||
return birthday;
|
||||
}
|
||||
|
||||
public void setBirthday(Date birthday)
|
||||
{
|
||||
this.birthday = birthday;
|
||||
}
|
||||
|
||||
public String getEducation()
|
||||
{
|
||||
return education;
|
||||
}
|
||||
|
||||
public void setEducation(String education)
|
||||
{
|
||||
this.education = education;
|
||||
}
|
||||
|
||||
public String getOccupation()
|
||||
{
|
||||
return occupation;
|
||||
}
|
||||
|
||||
public void setOccupation(String occupation)
|
||||
{
|
||||
this.occupation = occupation;
|
||||
}
|
||||
|
||||
public String getAddress()
|
||||
{
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String address)
|
||||
{
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public String getEmergencyContact()
|
||||
{
|
||||
return emergencyContact;
|
||||
}
|
||||
|
||||
public void setEmergencyContact(String emergencyContact)
|
||||
{
|
||||
this.emergencyContact = emergencyContact;
|
||||
}
|
||||
|
||||
public String getEmergencyPhone()
|
||||
{
|
||||
return emergencyPhone;
|
||||
}
|
||||
|
||||
public void setEmergencyPhone(String emergencyPhone)
|
||||
{
|
||||
this.emergencyPhone = emergencyPhone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||
|
|
|
|||
|
|
@ -29,8 +29,10 @@ import com.ddnai.framework.manager.AsyncManager;
|
|||
import com.ddnai.framework.manager.factory.AsyncFactory;
|
||||
import com.ddnai.framework.security.context.AuthenticationContextHolder;
|
||||
import com.ddnai.common.core.domain.entity.SysUser;
|
||||
import com.ddnai.common.core.domain.entity.SysRole;
|
||||
import com.ddnai.system.service.ISysConfigService;
|
||||
import com.ddnai.system.service.ISysUserService;
|
||||
import com.ddnai.system.service.psychology.IPsyUserProfileService;
|
||||
|
||||
/**
|
||||
* 登录校验方法
|
||||
|
|
@ -42,6 +44,9 @@ public class SysLoginService
|
|||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(SysLoginService.class);
|
||||
|
||||
@Autowired
|
||||
private IPsyUserProfileService userProfileService;
|
||||
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
|
||||
|
|
@ -100,6 +105,36 @@ public class SysLoginService
|
|||
}
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
|
||||
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
|
||||
|
||||
// 检查学员用户是否有档案
|
||||
SysUser user = loginUser.getUser();
|
||||
if (user != null && user.getRoles() != null)
|
||||
{
|
||||
boolean isStudent = false;
|
||||
for (SysRole role : user.getRoles())
|
||||
{
|
||||
if (role != null && ("student".equalsIgnoreCase(role.getRoleKey()) ||
|
||||
(role.getRoleName() != null && role.getRoleName().contains("学员"))))
|
||||
{
|
||||
isStudent = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是学员角色,必须有档案才能登录
|
||||
if (isStudent)
|
||||
{
|
||||
com.ddnai.system.domain.psychology.PsyUserProfile profile =
|
||||
userProfileService.selectProfileByUserId(user.getUserId());
|
||||
if (profile == null || StringUtils.isEmpty(profile.getInfoNumber()))
|
||||
{
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, "学员账号必须有用户档案才能登录"));
|
||||
throw new ServiceException("该账号未创建用户档案,请联系管理员创建档案后再登录");
|
||||
}
|
||||
log.info("学员登录验证通过,用户: {}, 信息编号: {}", username, profile.getInfoNumber());
|
||||
}
|
||||
}
|
||||
|
||||
recordLoginInfo(loginUser.getUserId());
|
||||
// 生成token
|
||||
return tokenService.createToken(loginUser);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.ddnai.system.domain.psychology;
|
||||
|
||||
import com.ddnai.common.annotation.Excel;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
|
@ -17,44 +18,54 @@ public class PsyUserProfile extends BaseEntity
|
|||
/** 档案ID */
|
||||
private Long profileId;
|
||||
|
||||
/** 用户ID(关联sys_user) */
|
||||
/** 用户ID(关联sys_user) - 不在Excel模板中显示,通过信息编号自动设置 */
|
||||
private Long userId;
|
||||
|
||||
/** 档案类型(如:standard标准 child儿童 adult成人 senior老年) */
|
||||
@Excel(name = "档案类型", readConverterExp = "standard=标准,child=儿童,adult=成人,senior=老年")
|
||||
private String profileType;
|
||||
|
||||
/** 头像 */
|
||||
private String avatar;
|
||||
|
||||
/** 身份证号 */
|
||||
@Excel(name = "身份证号")
|
||||
private String idCard;
|
||||
|
||||
/** 档案数据(JSON格式) */
|
||||
private String profileData;
|
||||
|
||||
/** 姓名 */
|
||||
@Excel(name = "姓名")
|
||||
private String userName;
|
||||
|
||||
/** 电话 */
|
||||
@Excel(name = "电话")
|
||||
private String phone;
|
||||
|
||||
/** 生日 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
@Excel(name = "生日", width = 30, dateFormat = "yyyy-MM-dd")
|
||||
private java.util.Date birthday;
|
||||
|
||||
/** 学历 */
|
||||
@Excel(name = "学历")
|
||||
private String education;
|
||||
|
||||
/** 职业 */
|
||||
@Excel(name = "职业")
|
||||
private String occupation;
|
||||
|
||||
/** 地址 */
|
||||
@Excel(name = "地址")
|
||||
private String address;
|
||||
|
||||
/** 紧急联系人 */
|
||||
@Excel(name = "紧急联系人")
|
||||
private String emergencyContact;
|
||||
|
||||
/** 紧急联系电话 */
|
||||
@Excel(name = "紧急联系电话")
|
||||
private String emergencyPhone;
|
||||
|
||||
/** 病史 */
|
||||
|
|
@ -70,6 +81,7 @@ public class PsyUserProfile extends BaseEntity
|
|||
private String deptName;
|
||||
|
||||
/** 信息编号 */
|
||||
@Excel(name = "信息编号")
|
||||
private String infoNumber;
|
||||
|
||||
public Long getProfileId()
|
||||
|
|
|
|||
|
|
@ -517,6 +517,20 @@ public class SysUserServiceImpl implements ISysUserService
|
|||
{
|
||||
try
|
||||
{
|
||||
// 如果有信息编号,使用信息编号作为登录账号
|
||||
if (StringUtils.isNotEmpty(user.getInfoNumber()))
|
||||
{
|
||||
user.setUserName(user.getInfoNumber()); // 登录账号 = 信息编号
|
||||
}
|
||||
|
||||
// 如果没有用户名,跳过
|
||||
if (StringUtils.isEmpty(user.getUserName()))
|
||||
{
|
||||
failureNum++;
|
||||
failureMsg.append("<br/>").append(failureNum).append("、用户名或信息编号不能为空");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 验证是否存在这个用户
|
||||
SysUser u = userMapper.selectUserByUserName(user.getUserName());
|
||||
if (StringUtils.isNull(u))
|
||||
|
|
|
|||
|
|
@ -314,7 +314,37 @@ public class PsyUserProfileServiceImpl implements IPsyUserProfileService
|
|||
@Override
|
||||
public int deleteProfileByIds(Long[] profileIds)
|
||||
{
|
||||
return profileMapper.deleteProfileByIds(profileIds);
|
||||
// 先获取所有要删除的档案,记录对应的用户ID
|
||||
java.util.List<Long> userIdsToDelete = new java.util.ArrayList<>();
|
||||
for (Long profileId : profileIds)
|
||||
{
|
||||
PsyUserProfile profile = profileMapper.selectProfileById(profileId);
|
||||
if (profile != null && profile.getUserId() != null)
|
||||
{
|
||||
userIdsToDelete.add(profile.getUserId());
|
||||
}
|
||||
}
|
||||
|
||||
// 删除档案
|
||||
int result = profileMapper.deleteProfileByIds(profileIds);
|
||||
|
||||
// 删除对应的用户
|
||||
if (!userIdsToDelete.isEmpty())
|
||||
{
|
||||
Long[] userIds = userIdsToDelete.toArray(new Long[0]);
|
||||
try
|
||||
{
|
||||
userService.deleteUserByIds(userIds);
|
||||
log.info("删除档案同时删除了对应的用户,用户ID: {}", userIdsToDelete);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.error("删除用户失败,用户ID: {}", userIdsToDelete, e);
|
||||
// 即使删除用户失败,档案已经删除,也返回成功
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void validateInfoNumberUnique(String infoNumber, Long profileId)
|
||||
|
|
@ -336,16 +366,22 @@ public class PsyUserProfileServiceImpl implements IPsyUserProfileService
|
|||
{
|
||||
throw new ServiceException("信息编号不能为空");
|
||||
}
|
||||
|
||||
SysUser user = new SysUser();
|
||||
// 使用信息编号作为登录账号(用户名)
|
||||
String loginAccount = profile.getInfoNumber();
|
||||
user.setUserName(loginAccount);
|
||||
|
||||
// 不设置userId,让数据库自动生成
|
||||
// userId和信息编号不需要保持一致,信息编号用于登录
|
||||
user.setUserName(loginAccount); // 登录账号 = 信息编号
|
||||
user.setNickName(StringUtils.isNotEmpty(profile.getUserName()) ? profile.getUserName() : loginAccount);
|
||||
user.setPhonenumber(profile.getPhone());
|
||||
user.setDeptId(profile.getDeptId());
|
||||
user.setStatus("0");
|
||||
user.setPassword(SecurityUtils.encryptPassword(resolveInitPassword()));
|
||||
user.setCreateBy(SecurityUtils.getUsername());
|
||||
user.setRemark("由用户档案自动创建");
|
||||
user.setRemark("由用户档案自动创建(登录账号:" + loginAccount + ")");
|
||||
|
||||
Long studentRoleId = resolveStudentRoleId();
|
||||
if (studentRoleId != null)
|
||||
{
|
||||
|
|
@ -355,11 +391,16 @@ public class PsyUserProfileServiceImpl implements IPsyUserProfileService
|
|||
{
|
||||
log.warn("未找到学生角色,自动创建的用户将没有角色,请检查角色配置");
|
||||
}
|
||||
|
||||
if (!userService.checkUserNameUnique(user))
|
||||
{
|
||||
throw new ServiceException("登录账号 '" + loginAccount + "' 已存在,请更换信息编号");
|
||||
}
|
||||
|
||||
log.info("自动创建用户,登录账号: {}", loginAccount);
|
||||
userService.insertUser(user);
|
||||
log.info("用户创建成功,用户ID: {}, 登录账号: {}", user.getUserId(), user.getUserName());
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
|
|
@ -418,5 +459,86 @@ public class PsyUserProfileServiceImpl implements IPsyUserProfileService
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入用户档案数据
|
||||
*
|
||||
* @param profileList 用户档案数据列表
|
||||
* @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据
|
||||
* @param operName 操作用户
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public String importProfile(List<PsyUserProfile> profileList, Boolean isUpdateSupport, String operName)
|
||||
{
|
||||
if (StringUtils.isNull(profileList) || profileList.size() == 0)
|
||||
{
|
||||
throw new ServiceException("导入用户档案数据不能为空!");
|
||||
}
|
||||
int successNum = 0;
|
||||
int failureNum = 0;
|
||||
StringBuilder successMsg = new StringBuilder();
|
||||
StringBuilder failureMsg = new StringBuilder();
|
||||
|
||||
for (PsyUserProfile profile : profileList)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 设置创建者
|
||||
profile.setCreateBy(operName);
|
||||
|
||||
// 验证信息编号
|
||||
if (StringUtils.isEmpty(profile.getInfoNumber()))
|
||||
{
|
||||
failureNum++;
|
||||
failureMsg.append("<br/>").append(failureNum).append("、档案信息编号为空");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 根据信息编号查询是否存在
|
||||
PsyUserProfile existProfile = profileMapper.selectProfileByInfoNumber(profile.getInfoNumber());
|
||||
if (StringUtils.isNull(existProfile))
|
||||
{
|
||||
// 新增档案
|
||||
this.insertProfile(profile);
|
||||
successNum++;
|
||||
successMsg.append("<br/>").append(successNum).append("、信息编号 ").append(profile.getInfoNumber()).append(" 导入成功");
|
||||
}
|
||||
else if (isUpdateSupport)
|
||||
{
|
||||
// 更新档案
|
||||
profile.setProfileId(existProfile.getProfileId());
|
||||
profile.setUserId(existProfile.getUserId());
|
||||
profile.setUpdateBy(operName);
|
||||
this.updateProfile(profile);
|
||||
successNum++;
|
||||
successMsg.append("<br/>").append(successNum).append("、信息编号 ").append(profile.getInfoNumber()).append(" 更新成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
failureNum++;
|
||||
failureMsg.append("<br/>").append(failureNum).append("、信息编号 ").append(profile.getInfoNumber()).append(" 已存在");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
failureNum++;
|
||||
String msg = "<br/>" + failureNum + "、信息编号 " + profile.getInfoNumber() + " 导入失败:";
|
||||
failureMsg.append(msg).append(e.getMessage());
|
||||
log.error(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
if (failureNum > 0)
|
||||
{
|
||||
failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
|
||||
throw new ServiceException(failureMsg.toString());
|
||||
}
|
||||
else
|
||||
{
|
||||
successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
|
||||
}
|
||||
return successMsg.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,5 +65,15 @@ public interface IPsyUserProfileService
|
|||
* @return 结果
|
||||
*/
|
||||
public int deleteProfileByIds(Long[] profileIds);
|
||||
|
||||
/**
|
||||
* 导入用户档案数据
|
||||
*
|
||||
* @param profileList 用户档案数据列表
|
||||
* @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据
|
||||
* @param operName 操作用户
|
||||
* @return 结果
|
||||
*/
|
||||
public String importProfile(List<PsyUserProfile> profileList, Boolean isUpdateSupport, String operName);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
|
|
@ -152,7 +152,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
|
||||
<insert id="insertUser" parameterType="SysUser" useGeneratedKeys="true" keyProperty="userId">
|
||||
insert into sys_user(
|
||||
<if test="userId != null and userId != 0">user_id,</if>
|
||||
<if test="deptId != null and deptId != 0">dept_id,</if>
|
||||
<if test="userName != null and userName != ''">user_name,</if>
|
||||
<if test="nickName != null and nickName != ''">nick_name,</if>
|
||||
|
|
@ -167,7 +166,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
<if test="remark != null and remark != ''">remark,</if>
|
||||
create_time
|
||||
)values(
|
||||
<if test="userId != null and userId != ''">#{userId},</if>
|
||||
<if test="deptId != null and deptId != ''">#{deptId},</if>
|
||||
<if test="userName != null and userName != ''">#{userName},</if>
|
||||
<if test="nickName != null and nickName != ''">#{nickName},</if>
|
||||
|
|
|
|||
|
|
@ -21,8 +21,10 @@ router.beforeEach((to, from, next) => {
|
|||
to.meta.title && store.dispatch('settings/setTitle', to.meta.title)
|
||||
/* has token*/
|
||||
if (to.path === '/login' || to.path === '/admin-login') {
|
||||
// 已登录,统一跳回首页
|
||||
next({ path: '/' })
|
||||
// 已登录,根据角色跳转到相应页面
|
||||
const userRoles = store.getters.roles || []
|
||||
const isStudentRole = userRoles.some(role => role === 'student' || role.includes('学员'))
|
||||
next({ path: isStudentRole ? '/student/tests' : '/' })
|
||||
NProgress.done()
|
||||
} else if (isWhiteList(to.path)) {
|
||||
next()
|
||||
|
|
@ -39,21 +41,22 @@ router.beforeEach((to, from, next) => {
|
|||
const isStudentRole = userRoles.some(role => role === 'student' || role.includes('学员'))
|
||||
|
||||
if (isStudentRole) {
|
||||
const allowPaths = [
|
||||
'/',
|
||||
'/index'
|
||||
]
|
||||
// 学员访问首页时重定向到测试题列表
|
||||
if (to.path === '/' || to.path === '/index') {
|
||||
next({ path: '/student/tests', replace: true })
|
||||
return
|
||||
}
|
||||
const allowPrefixes = [
|
||||
'/student',
|
||||
'/psychology/assessment/taking',
|
||||
'/psychology/questionnaire',
|
||||
'/psychology/assessment/report'
|
||||
]
|
||||
const isAllowed = allowPaths.includes(to.path) || allowPrefixes.some(prefix => to.path.startsWith(prefix))
|
||||
const isAllowed = allowPrefixes.some(prefix => to.path.startsWith(prefix))
|
||||
if (isAllowed) {
|
||||
next()
|
||||
} else {
|
||||
next({ path: '/' })
|
||||
next({ path: '/student/tests' })
|
||||
}
|
||||
} else {
|
||||
// 管理员角色,生成路由
|
||||
|
|
@ -77,21 +80,22 @@ router.beforeEach((to, from, next) => {
|
|||
const isStudentRole = userRoles.some(role => role === 'student' || role.includes('学员'))
|
||||
|
||||
if (isStudentRole) {
|
||||
const allowPaths = [
|
||||
'/',
|
||||
'/index'
|
||||
]
|
||||
// 学员访问首页时重定向到测试题列表
|
||||
if (to.path === '/' || to.path === '/index') {
|
||||
next({ path: '/student/tests', replace: true })
|
||||
return
|
||||
}
|
||||
const allowPrefixes = [
|
||||
'/student',
|
||||
'/psychology/assessment/taking',
|
||||
'/psychology/questionnaire',
|
||||
'/psychology/assessment/report'
|
||||
]
|
||||
const isAllowed = allowPaths.includes(to.path) || allowPrefixes.some(prefix => to.path.startsWith(prefix))
|
||||
const isAllowed = allowPrefixes.some(prefix => to.path.startsWith(prefix))
|
||||
if (isAllowed) {
|
||||
next()
|
||||
} else {
|
||||
next({ path: '/' })
|
||||
next({ path: '/student/tests' })
|
||||
}
|
||||
} else {
|
||||
next()
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ export const constantRoutes = [
|
|||
{
|
||||
path: '/student/tests',
|
||||
component: () => import('@/views/student/tests'),
|
||||
name: 'StudentTests',
|
||||
hidden: true,
|
||||
meta: { title: '心理测试题' }
|
||||
},
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ const getters = {
|
|||
permission_routes: state => state.permission.routes,
|
||||
topbarRouters: state => state.permission.topbarRouters,
|
||||
defaultRoutes: state => state.permission.defaultRoutes,
|
||||
sidebarRouters: state => state.permission.sidebarRouters
|
||||
sidebarRouters: state => state.permission.sidebarRouters,
|
||||
infoNumber: state => state.user.infoNumber
|
||||
}
|
||||
export default getters
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import router from '@/router'
|
||||
import { MessageBox, } from 'element-ui'
|
||||
import { login, logout, getInfo, studentLogin } from '@/api/login'
|
||||
import { getToken, setToken, removeToken, getRole, setRole } from '@/utils/auth'
|
||||
import { getToken, setToken, removeToken, getRole, setRole, getInfoNumber, setInfoNumber } from '@/utils/auth'
|
||||
import { isHttp, isEmpty } from "@/utils/validate"
|
||||
import defAva from '@/assets/images/profile.jpg'
|
||||
|
||||
|
|
@ -22,7 +22,8 @@ const user = {
|
|||
nickName: '',
|
||||
avatar: '',
|
||||
roles: initRoles(),
|
||||
permissions: []
|
||||
permissions: [],
|
||||
infoNumber: getInfoNumber() || '' // 学员信息编号,从 Cookie 中恢复
|
||||
},
|
||||
|
||||
mutations: {
|
||||
|
|
@ -58,6 +59,11 @@ const user = {
|
|||
},
|
||||
SET_PERMISSIONS: (state, permissions) => {
|
||||
state.permissions = permissions
|
||||
},
|
||||
SET_INFO_NUMBER: (state, infoNumber) => {
|
||||
state.infoNumber = infoNumber
|
||||
// 持久化到 Cookie
|
||||
setInfoNumber(infoNumber)
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -132,6 +138,7 @@ const user = {
|
|||
commit('SET_TOKEN', '')
|
||||
commit('SET_ROLES', [])
|
||||
commit('SET_PERMISSIONS', [])
|
||||
commit('SET_INFO_NUMBER', '')
|
||||
removeToken()
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
|
|
@ -145,6 +152,7 @@ const user = {
|
|||
return new Promise(resolve => {
|
||||
commit('SET_TOKEN', '')
|
||||
commit('SET_ROLES', [])
|
||||
commit('SET_INFO_NUMBER', '')
|
||||
removeToken()
|
||||
resolve()
|
||||
})
|
||||
|
|
@ -165,6 +173,8 @@ const user = {
|
|||
// 设置学员token
|
||||
setToken(res.token)
|
||||
commit('SET_TOKEN', res.token)
|
||||
// 保存信息编号到 store
|
||||
commit('SET_INFO_NUMBER', infoNumber)
|
||||
// 学员登录成功后,需要调用GetInfo获取用户信息(因为学员也是系统用户,只是角色不同)
|
||||
// 这里不设置角色,等GetInfo获取后再设置
|
||||
resolve()
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import Cookies from 'js-cookie'
|
|||
|
||||
const TokenKey = 'Admin-Token'
|
||||
const RoleKey = 'User-Role'
|
||||
const InfoNumberKey = 'Info-Number'
|
||||
|
||||
export function getToken() {
|
||||
return Cookies.get(TokenKey)
|
||||
|
|
@ -14,6 +15,7 @@ export function setToken(token) {
|
|||
export function removeToken() {
|
||||
Cookies.remove(TokenKey)
|
||||
Cookies.remove(RoleKey)
|
||||
Cookies.remove(InfoNumberKey)
|
||||
}
|
||||
|
||||
// 获取用户角色
|
||||
|
|
@ -29,3 +31,17 @@ export function setRole(role) {
|
|||
return Cookies.remove(RoleKey)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取信息编号
|
||||
export function getInfoNumber() {
|
||||
return Cookies.get(InfoNumberKey)
|
||||
}
|
||||
|
||||
// 设置信息编号
|
||||
export function setInfoNumber(infoNumber) {
|
||||
if (infoNumber) {
|
||||
return Cookies.set(InfoNumberKey, infoNumber)
|
||||
} else {
|
||||
return Cookies.remove(InfoNumberKey)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,9 +74,6 @@
|
|||
<span v-if="!loading">登 录</span>
|
||||
<span v-else>登 录 中...</span>
|
||||
</el-button>
|
||||
<div style="float: right;" v-if="register">
|
||||
<router-link class="link-type" :to="'/register'">立即注册</router-link>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item style="width:100%; text-align: center; margin-top: 10px;">
|
||||
<a class="student-login-link" @click="switchToStudent">
|
||||
|
|
@ -250,7 +247,8 @@ export default {
|
|||
this.$store.dispatch("StudentLogin", loginData).then(() => {
|
||||
// 学员登录成功后,需要调用GetInfo获取用户信息
|
||||
this.$store.dispatch("GetInfo").then(() => {
|
||||
const targetPath = this.resolveRedirect("/")
|
||||
// 学员登录后跳转到测试题页面,如果有redirect参数则跳转到指定页面
|
||||
const targetPath = this.resolveRedirect("/student/tests")
|
||||
this.$router.push(targetPath).catch(()=>{})
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
|
|
|
|||
|
|
@ -145,7 +145,10 @@ export default {
|
|||
this.assessmentId = this.$route.query.assessmentId;
|
||||
if (!this.assessmentId) {
|
||||
this.$modal.msgError("测评ID不能为空");
|
||||
this.$router.push('/psychology/assessment');
|
||||
// 根据用户角色跳转到相应页面
|
||||
const roles = this.$store.getters.roles || [];
|
||||
const isStudent = roles.some(role => role === 'student' || role.includes('学员'));
|
||||
this.$router.push(isStudent ? '/student/tests' : '/psychology/assessment');
|
||||
return;
|
||||
}
|
||||
this.loadAssessment();
|
||||
|
|
@ -162,7 +165,10 @@ export default {
|
|||
const assessment = assessmentRes.data;
|
||||
if (!assessment) {
|
||||
this.$modal.msgError("测评不存在");
|
||||
this.$router.push('/psychology/assessment');
|
||||
// 根据用户角色跳转到相应页面
|
||||
const roles = this.$store.getters.roles || [];
|
||||
const isStudent = roles.some(role => role === 'student' || role.includes('学员'));
|
||||
this.$router.push(isStudent ? '/student/tests' : '/psychology/assessment');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -172,7 +178,10 @@ export default {
|
|||
// 检查题目列表是否为空
|
||||
if (this.itemList.length === 0) {
|
||||
this.$modal.msgWarning("该量表暂无题目,请联系管理员添加题目");
|
||||
this.$router.push('/psychology/assessment');
|
||||
// 根据用户角色跳转到相应页面
|
||||
const roles = this.$store.getters.roles || [];
|
||||
const isStudent = roles.some(role => role === 'student' || role.includes('学员'));
|
||||
this.$router.push(isStudent ? '/student/tests' : '/psychology/assessment');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -309,14 +318,20 @@ export default {
|
|||
this.$modal.confirm('确定要暂停测评吗?您可以稍后继续完成。').then(() => {
|
||||
pauseAssessment(this.assessmentId).then(() => {
|
||||
this.$modal.msgSuccess("测评已暂停");
|
||||
this.$router.push('/psychology/assessment');
|
||||
// 根据用户角色跳转到相应页面
|
||||
const roles = this.$store.getters.roles || [];
|
||||
const isStudent = roles.some(role => role === 'student' || role.includes('学员'));
|
||||
this.$router.push(isStudent ? '/student/tests' : '/psychology/assessment');
|
||||
});
|
||||
});
|
||||
},
|
||||
/** 退出 */
|
||||
handleExit() {
|
||||
this.$modal.confirm('确定要退出测评吗?已答题目将会保存。').then(() => {
|
||||
this.$router.push('/psychology/assessment');
|
||||
// 根据用户角色跳转到相应页面
|
||||
const roles = this.$store.getters.roles || [];
|
||||
const isStudent = roles.some(role => role === 'student' || role.includes('学员'));
|
||||
this.$router.push(isStudent ? '/student/tests' : '/psychology/assessment');
|
||||
});
|
||||
},
|
||||
/** 提交测评 */
|
||||
|
|
@ -331,7 +346,10 @@ export default {
|
|||
this.$modal.confirm('确定要提交测评吗?提交后将不能修改。').then(() => {
|
||||
submitAssessment(this.assessmentId).then(response => {
|
||||
this.$modal.msgSuccess(response.msg || "测评已提交,报告已生成");
|
||||
this.$router.push('/psychology/assessment');
|
||||
// 根据用户角色跳转到相应页面
|
||||
const roles = this.$store.getters.roles || [];
|
||||
const isStudent = roles.some(role => role === 'student' || role.includes('学员'));
|
||||
this.$router.push(isStudent ? '/student/tests' : '/psychology/assessment');
|
||||
}).catch(error => {
|
||||
this.$modal.msgError(error.msg || "提交失败,请重试");
|
||||
});
|
||||
|
|
@ -461,7 +479,10 @@ export default {
|
|||
submitAssessment(this.assessmentId).then(response => {
|
||||
this.loading = false;
|
||||
this.$modal.msgSuccess(response.msg || "测评已提交,报告已生成");
|
||||
this.$router.push('/psychology/assessment');
|
||||
// 根据用户角色跳转到相应页面
|
||||
const roles = this.$store.getters.roles || [];
|
||||
const isStudent = roles.some(role => role === 'student' || role.includes('学员'));
|
||||
this.$router.push(isStudent ? '/student/tests' : '/psychology/assessment');
|
||||
}).catch(error => {
|
||||
this.loading = false;
|
||||
this.$modal.msgError(error.msg || "提交失败,请重试");
|
||||
|
|
|
|||
|
|
@ -9,14 +9,7 @@
|
|||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户ID" prop="userId">
|
||||
<el-input
|
||||
v-model="queryParams.userId"
|
||||
placeholder="请输入用户ID"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<!-- 用户ID已隐藏,只使用信息编号 -->
|
||||
<el-form-item label="手机号码" prop="phone">
|
||||
<el-input
|
||||
v-model="queryParams.phone"
|
||||
|
|
@ -39,14 +32,6 @@
|
|||
<el-option label="老年" value="senior" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="身份证号" prop="idCard">
|
||||
<el-input
|
||||
v-model="queryParams.idCard"
|
||||
placeholder="请输入身份证号"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="信息编号" prop="infoNumber">
|
||||
<el-input
|
||||
v-model="queryParams.infoNumber"
|
||||
|
|
@ -57,7 +42,6 @@
|
|||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
|
|
@ -72,16 +56,6 @@
|
|||
v-hasPermi="['psychology:profile:add']"
|
||||
>新增档案</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.8">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-user"
|
||||
size="mini"
|
||||
@click="handleAddUser"
|
||||
v-hasPermi="['psychology:profile:add']"
|
||||
>创建用户</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="success"
|
||||
|
|
@ -104,13 +78,33 @@
|
|||
v-hasPermi="['psychology:profile:remove']"
|
||||
>删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="info"
|
||||
plain
|
||||
icon="el-icon-upload2"
|
||||
size="mini"
|
||||
@click="handleImport"
|
||||
v-hasPermi="['psychology:profile:import']"
|
||||
>导入</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="el-icon-download"
|
||||
size="mini"
|
||||
@click="handleExport"
|
||||
v-hasPermi="['psychology:profile:export']"
|
||||
>导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table ref="profileTable" v-loading="loading" :data="profileList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="序号" align="center" prop="profileId" width="80" />
|
||||
<el-table-column label="用户ID" align="center" prop="userId" width="100" />
|
||||
<!-- 用户ID列已隐藏,只显示信息编号 -->
|
||||
<el-table-column label="信息编号" align="center" prop="infoNumber" width="120" />
|
||||
<el-table-column label="档案类型" align="center" prop="profileType" width="120">
|
||||
<template slot-scope="scope">
|
||||
|
|
@ -123,7 +117,6 @@
|
|||
</el-table-column>
|
||||
<el-table-column label="姓名" align="center" prop="userName" width="100" />
|
||||
<el-table-column label="电话" align="center" prop="phone" width="120" />
|
||||
<el-table-column label="身份证号" align="center" prop="idCard" width="180" />
|
||||
<el-table-column label="生日" align="center" prop="birthday" width="120">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.birthday, '{y}-{m}-{d}') }}</span>
|
||||
|
|
@ -147,13 +140,6 @@
|
|||
@click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['psychology:profile:edit']"
|
||||
>档案</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-user"
|
||||
@click="handleEditUser(scope.row)"
|
||||
v-hasPermi="['psychology:profile:edit']"
|
||||
>用户</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
|
|
@ -177,21 +163,6 @@
|
|||
<el-dialog :title="title" :visible.sync="open" width="900px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="120px">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="userId">
|
||||
<template slot="label">
|
||||
用户ID
|
||||
<span style="color:#909399;font-size:12px;">(留空自动创建)</span>
|
||||
</template>
|
||||
<el-input-number
|
||||
v-model="form.userId"
|
||||
:min="1"
|
||||
:disabled="form.profileId != undefined"
|
||||
:controls="false"
|
||||
placeholder="不填将自动创建用户"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="档案类型" prop="profileType">
|
||||
<el-select v-model="form.profileType" placeholder="请选择档案类型">
|
||||
|
|
@ -202,6 +173,9 @@
|
|||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<!-- 用户ID已隐藏,会通过信息编号自动填充 -->
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
|
|
@ -374,12 +348,32 @@
|
|||
<el-button @click="cancelUser">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 用户档案导入对话框 -->
|
||||
<el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
|
||||
<el-upload ref="upload" :limit="1" accept=".xlsx, .xls" :headers="upload.headers" :action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading" :on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag>
|
||||
<i class="el-icon-upload"></i>
|
||||
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
||||
<div class="el-upload__tip text-center" slot="tip">
|
||||
<div class="el-upload__tip" slot="tip">
|
||||
<el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户档案数据
|
||||
</div>
|
||||
<span>仅允许导入xls、xlsx格式文件。</span>
|
||||
<el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">下载模板</el-link>
|
||||
</div>
|
||||
</el-upload>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitFileForm">确 定</el-button>
|
||||
<el-button @click="upload.open = false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listProfile, getProfile, getProfileByUserId, delProfile, addProfile, updateProfile, getUserInfo, addUserInProfile, getUserInfoById, updateUserInProfile, delUserInProfile } from "@/api/psychology/profile"
|
||||
import { deptTreeSelect } from "@/api/system/user"
|
||||
import { getToken } from "@/utils/auth"
|
||||
import Treeselect from "@riophae/vue-treeselect"
|
||||
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
|
||||
|
||||
|
|
@ -484,6 +478,21 @@ export default {
|
|||
trigger: "blur"
|
||||
}
|
||||
]
|
||||
},
|
||||
// 用户导入参数
|
||||
upload: {
|
||||
// 是否显示弹出层(用户导入)
|
||||
open: false,
|
||||
// 弹出层标题(用户导入)
|
||||
title: "",
|
||||
// 是否禁用上传
|
||||
isUploading: false,
|
||||
// 是否更新已经存在的用户档案数据
|
||||
updateSupport: 0,
|
||||
// 设置上传的请求头部
|
||||
headers: { Authorization: "Bearer " + getToken() },
|
||||
// 上传的地址
|
||||
url: process.env.VUE_APP_BASE_API + "/psychology/profile/importData"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -545,7 +554,8 @@ export default {
|
|||
// 处理信息编号输入,只允许数字
|
||||
handleInfoNumberInput(value) {
|
||||
// 移除所有非数字字符
|
||||
this.form.infoNumber = value.replace(/\D/g, '')
|
||||
const numericValue = value.replace(/\D/g, '')
|
||||
this.form.infoNumber = numericValue
|
||||
},
|
||||
// 处理姓名输入,只允许汉字
|
||||
handleUserNameInput(value) {
|
||||
|
|
@ -852,6 +862,42 @@ export default {
|
|||
this.getList()
|
||||
this.$modal.msgSuccess("删除成功")
|
||||
}).catch(() => {})
|
||||
},
|
||||
/** 导出按钮操作 */
|
||||
handleExport() {
|
||||
this.download('psychology/profile/export', {
|
||||
...this.queryParams
|
||||
}, `profile_${new Date().getTime()}.xlsx`)
|
||||
},
|
||||
/** 导入按钮操作 */
|
||||
handleImport() {
|
||||
this.upload.title = "用户档案导入"
|
||||
this.upload.open = true
|
||||
},
|
||||
/** 下载模板操作 */
|
||||
importTemplate() {
|
||||
window.location.href = process.env.VUE_APP_BASE_API + '/psychology/profile/importTemplate'
|
||||
},
|
||||
// 文件上传中处理
|
||||
handleFileUploadProgress(event, file, fileList) {
|
||||
this.upload.isUploading = true
|
||||
},
|
||||
// 文件上传成功处理
|
||||
handleFileSuccess(response, file, fileList) {
|
||||
this.upload.open = false
|
||||
this.upload.isUploading = false
|
||||
this.$refs.upload.clearFiles()
|
||||
this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true })
|
||||
this.getList()
|
||||
},
|
||||
// 提交上传文件
|
||||
submitFileForm() {
|
||||
const file = this.$refs.upload.uploadFiles
|
||||
if (!file || file.length === 0 || !file[0].name.toLowerCase().endsWith('.xls') && !file[0].name.toLowerCase().endsWith('.xlsx')) {
|
||||
this.$modal.msgError('请选择后缀为 "xls"或"xlsx"的文件。')
|
||||
return
|
||||
}
|
||||
this.$refs.upload.submit()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,7 +106,10 @@ export default {
|
|||
startAnswerDirectly() {
|
||||
if (!this.form.questionnaireId) {
|
||||
this.$modal.msgError("问卷ID不能为空");
|
||||
this.$router.push('/psychology/scale');
|
||||
// 根据用户角色跳转到相应页面
|
||||
const roles = this.$store.getters.roles || [];
|
||||
const isStudent = roles.some(role => role === 'student' || role.includes('学员'));
|
||||
this.$router.push(isStudent ? '/student/tests' : '/psychology/scale');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -131,7 +134,10 @@ export default {
|
|||
},
|
||||
/** 返回 */
|
||||
handleBack() {
|
||||
this.$router.push('/psychology/scale');
|
||||
// 根据用户角色跳转到相应页面
|
||||
const roles = this.$store.getters.roles || [];
|
||||
const isStudent = roles.some(role => role === 'student' || role.includes('学员'));
|
||||
this.$router.push(isStudent ? '/student/tests' : '/psychology/scale');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -216,7 +216,10 @@ export default {
|
|||
this.answerId = this.$route.query.answerId;
|
||||
if (!this.answerId) {
|
||||
this.$modal.msgError("答题ID不能为空");
|
||||
this.$router.push('/psychology/scale');
|
||||
// 根据用户角色跳转到相应页面
|
||||
const roles = this.$store.getters.roles || [];
|
||||
const isStudent = roles.some(role => role === 'student' || role.includes('学员'));
|
||||
this.$router.push(isStudent ? '/student/tests' : '/psychology/scale');
|
||||
return;
|
||||
}
|
||||
this.loadAnswer();
|
||||
|
|
@ -232,7 +235,10 @@ export default {
|
|||
const answer = answerRes.data;
|
||||
if (!answer) {
|
||||
this.$modal.msgError("答题记录不存在");
|
||||
this.$router.push('/psychology/scale');
|
||||
// 根据用户角色跳转到相应页面
|
||||
const roles = this.$store.getters.roles || [];
|
||||
const isStudent = roles.some(role => role === 'student' || role.includes('学员'));
|
||||
this.$router.push(isStudent ? '/student/tests' : '/psychology/scale');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -256,7 +262,10 @@ export default {
|
|||
|
||||
if (this.itemList.length === 0) {
|
||||
this.$modal.msgWarning("该问卷暂无题目,请联系管理员添加题目");
|
||||
this.$router.push('/psychology/scale');
|
||||
// 根据用户角色跳转到相应页面
|
||||
const roles = this.$store.getters.roles || [];
|
||||
const isStudent = roles.some(role => role === 'student' || role.includes('学员'));
|
||||
this.$router.push(isStudent ? '/student/tests' : '/psychology/scale');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -449,7 +458,10 @@ export default {
|
|||
/** 退出 */
|
||||
handleExit() {
|
||||
this.$modal.confirm('确定要退出答题吗?已答题目将会保存。').then(() => {
|
||||
this.$router.push('/psychology/scale');
|
||||
// 根据用户角色跳转到相应页面
|
||||
const roles = this.$store.getters.roles || [];
|
||||
const isStudent = roles.some(role => role === 'student' || role.includes('学员'));
|
||||
this.$router.push(isStudent ? '/student/tests' : '/psychology/scale');
|
||||
});
|
||||
},
|
||||
/** 提交问卷 */
|
||||
|
|
@ -480,7 +492,10 @@ export default {
|
|||
submitQuestionnaireAnswer(this.answerId).then(response => {
|
||||
this.loading = false;
|
||||
this.$modal.msgSuccess(response.msg || "问卷已提交");
|
||||
this.$router.push('/psychology/scale');
|
||||
// 根据用户角色跳转到相应页面
|
||||
const roles = this.$store.getters.roles || [];
|
||||
const isStudent = roles.some(role => role === 'student' || role.includes('学员'));
|
||||
this.$router.push(isStudent ? '/student/tests' : '/psychology/scale');
|
||||
}).catch(error => {
|
||||
this.loading = false;
|
||||
this.$modal.msgError(error.msg || "提交失败,请重试");
|
||||
|
|
|
|||
|
|
@ -72,6 +72,34 @@
|
|||
<div v-if="reportForm.pdfPath">
|
||||
<el-button type="primary" icon="el-icon-download" @click="handleDownloadPDF">下载PDF报告</el-button>
|
||||
</div>
|
||||
|
||||
<!-- AI分析 -->
|
||||
<el-divider content-position="left">AI智能分析</el-divider>
|
||||
<div class="ai-analysis-section">
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-magic-stick"
|
||||
@click="handleAIAnalysis"
|
||||
:loading="aiLoading"
|
||||
:disabled="!reportForm.reportContent"
|
||||
>
|
||||
{{ aiLoading ? '分析中...' : 'AI分析' }}
|
||||
</el-button>
|
||||
<div v-if="aiError" class="ai-error">
|
||||
<el-alert
|
||||
:title="aiError"
|
||||
type="error"
|
||||
:closable="false"
|
||||
show-icon>
|
||||
</el-alert>
|
||||
</div>
|
||||
<div v-if="aiResult" class="ai-result">
|
||||
<h3 class="ai-result-title">
|
||||
<i class="el-icon-magic-stick"></i> AI分析结果
|
||||
</h3>
|
||||
<div class="ai-result-content" v-html="aiResult"></div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 报告编辑对话框 -->
|
||||
|
|
@ -88,23 +116,10 @@
|
|||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="报告摘要" prop="summary">
|
||||
<el-input
|
||||
v-model="editForm.summary"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
placeholder="请输入报告摘要"
|
||||
/>
|
||||
<Editor v-model="editForm.summary" :min-height="150" />
|
||||
</el-form-item>
|
||||
<el-form-item label="报告内容" prop="reportContent">
|
||||
<el-input
|
||||
v-model="editForm.reportContent"
|
||||
type="textarea"
|
||||
:rows="15"
|
||||
placeholder="请输入报告内容(支持HTML格式)"
|
||||
/>
|
||||
<div style="margin-top: 10px; color: #909399; font-size: 12px;">
|
||||
<i class="el-icon-info"></i> 提示:报告内容支持HTML格式,可以包含标题、段落、列表等格式
|
||||
</div>
|
||||
<Editor v-model="editForm.reportContent" :min-height="400" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
|
|
@ -119,9 +134,12 @@
|
|||
import { getReport, getReportByAssessmentId, updateReportWithType } from "@/api/psychology/report";
|
||||
import { getQuestionnaireRankList } from "@/api/psychology/questionnaireAnswer";
|
||||
import request from '@/utils/request';
|
||||
import axios from 'axios';
|
||||
import Editor from "@/components/Editor";
|
||||
|
||||
export default {
|
||||
name: "ReportDetail",
|
||||
components: { Editor },
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
|
|
@ -129,6 +147,10 @@ export default {
|
|||
sourceType: null,
|
||||
rankList: [],
|
||||
rankLoading: false,
|
||||
// AI分析
|
||||
aiLoading: false,
|
||||
aiResult: '',
|
||||
aiError: '',
|
||||
// 编辑对话框
|
||||
editOpen: false,
|
||||
editForm: {},
|
||||
|
|
@ -291,6 +313,129 @@ export default {
|
|||
if (this.$refs["editForm"]) {
|
||||
this.$refs["editForm"].resetFields();
|
||||
}
|
||||
},
|
||||
/** AI分析 */
|
||||
async handleAIAnalysis() {
|
||||
if (!this.reportForm.reportContent) {
|
||||
this.$modal.msgWarning("报告内容为空,无法进行分析");
|
||||
return;
|
||||
}
|
||||
|
||||
this.aiLoading = true;
|
||||
this.aiError = '';
|
||||
this.aiResult = '';
|
||||
|
||||
// Ollama API配置
|
||||
const OLLAMA_URL = 'http://192.168.0.106:11434/api/generate';
|
||||
const MODEL = 'deepseek-r1:32b';
|
||||
|
||||
// 构建系统提示词
|
||||
const SYSTEM_PROMPT = [
|
||||
'你是专业心理测评报告分析师,请根据用户提供的报告内容进行深度分析。要求:',
|
||||
'1. 提取报告的核心信息和关键指标;',
|
||||
'2. 分析测评结果的含义和可能的影响;',
|
||||
'3. 提供专业、客观、易懂的分析解读(500-800字);',
|
||||
'4. 使用结构化的格式输出,包含:核心结论、详细分析、建议、总体结论四个部分;',
|
||||
'5. 仅输出分析结果,不添加额外建议、问候语或思考过程;',
|
||||
'6. 使用HTML格式输出,使用<h3>标签作为小标题,<p>标签作为段落。'
|
||||
].join('\n');
|
||||
|
||||
// 构建完整的提示词
|
||||
const reportContent = this.reportForm.reportContent || '';
|
||||
const reportTitle = this.reportForm.reportTitle || '心理测评报告';
|
||||
const reportType = this.reportForm.reportType || '标准报告';
|
||||
|
||||
// 提取纯文本内容(去除HTML标签)
|
||||
const textContent = reportContent.replace(/<[^>]*>/g, '').substring(0, 3000);
|
||||
|
||||
const prompt = `${SYSTEM_PROMPT}\n\n重要:请直接输出结果,不要包含任何思考过程、<think>标签或<think>标签。\n\n报告标题:${reportTitle}\n报告类型:${reportType}\n报告内容:${textContent}`;
|
||||
|
||||
try {
|
||||
const { data } = await axios.post(OLLAMA_URL, {
|
||||
model: MODEL,
|
||||
prompt: prompt,
|
||||
temperature: 0.2,
|
||||
num_predict: 1000,
|
||||
stream: false
|
||||
}, {
|
||||
timeout: 60000 // 60秒超时
|
||||
});
|
||||
|
||||
let rawResponse = data?.response ?? '无法解析模型输出';
|
||||
|
||||
// 过滤掉思考过程标签
|
||||
rawResponse = rawResponse
|
||||
.replace(/<think>[\s\S]*?<\/think>/gi, '')
|
||||
.replace(/<think>[\s\S]*?<\/redacted_reasoning>/gi, '')
|
||||
.replace(/<think[\s\S]*?>/gi, '')
|
||||
.replace(/<redacted_reasoning[\s\S]*?>/gi, '')
|
||||
// 移除Markdown代码块标记
|
||||
.replace(/```html\s*/gi, '')
|
||||
.replace(/```\s*/g, '')
|
||||
.replace(/```[a-z]*\s*/gi, '')
|
||||
.trim();
|
||||
|
||||
if (!rawResponse || rawResponse === '无法解析模型输出') {
|
||||
this.aiError = '模型返回结果为空,请稍后重试';
|
||||
return;
|
||||
}
|
||||
|
||||
// 格式化结果,确保HTML格式正确
|
||||
this.aiResult = this.formatAIResult(rawResponse);
|
||||
|
||||
} catch (err) {
|
||||
console.error('AI分析失败:', err);
|
||||
if (err.code === 'ECONNABORTED' || err.message.includes('timeout')) {
|
||||
this.aiError = '请求超时,请检查Ollama服务是否正常运行';
|
||||
} else if (err.response) {
|
||||
this.aiError = err.response.data?.error || err.message || 'AI分析失败,请稍后重试';
|
||||
} else if (err.request) {
|
||||
this.aiError = '无法连接到Ollama服务,请检查服务地址是否正确(当前:' + OLLAMA_URL + ')';
|
||||
} else {
|
||||
this.aiError = err.message || 'AI分析失败,请稍后重试';
|
||||
}
|
||||
} finally {
|
||||
this.aiLoading = false;
|
||||
}
|
||||
},
|
||||
/** 格式化AI分析结果 */
|
||||
formatAIResult(text) {
|
||||
// 移除Markdown代码块标记(```html、```等)
|
||||
let html = text
|
||||
.replace(/```html\s*/gi, '')
|
||||
.replace(/```\s*/g, '')
|
||||
.replace(/```[a-z]*\s*/gi, '')
|
||||
.trim();
|
||||
|
||||
// 如果已经是HTML格式,清理后返回
|
||||
if (html.includes('<h3>') || html.includes('<p>') || html.includes('<div>')) {
|
||||
// 移除可能残留的代码块标记
|
||||
html = html.replace(/```html\s*/gi, '').replace(/```\s*/g, '');
|
||||
return html;
|
||||
}
|
||||
|
||||
// 处理标题(以数字开头或包含"结论"、"分析"、"建议"等关键词的行)
|
||||
html = html.replace(/^(\d+[\.、]?\s*[^\n]+)$/gm, '<h3>$1</h3>');
|
||||
html = html.replace(/^([^\n]*(?:结论|分析|建议|总结|概述)[^\n]*)$/gm, '<h3>$1</h3>');
|
||||
|
||||
// 将段落分隔符转换为<p>标签
|
||||
html = html.split('\n\n').map(para => {
|
||||
para = para.trim();
|
||||
if (!para) return '';
|
||||
if (para.startsWith('<h3>')) return para;
|
||||
return '<p>' + para.replace(/\n/g, '<br>') + '</p>';
|
||||
}).join('');
|
||||
|
||||
// 确保每个段落都有正确的格式
|
||||
html = html.replace(/(<p>.*?<\/p>)/g, (match) => {
|
||||
if (match.includes('<h3>')) return match.replace(/<p>|<\/p>/g, '');
|
||||
return match;
|
||||
});
|
||||
|
||||
// 最后再次清理可能残留的代码块标记
|
||||
html = html.replace(/```html\s*/gi, '').replace(/```\s*/g, '');
|
||||
|
||||
return html;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -345,5 +490,69 @@ export default {
|
|||
font-weight: bold;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
/* AI分析区域样式 */
|
||||
.ai-analysis-section {
|
||||
margin-top: 20px;
|
||||
padding: 20px;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.ai-error {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.ai-result {
|
||||
margin-top: 20px;
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.ai-result-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #409eff;
|
||||
margin: 0 0 15px 0;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 2px solid #e4e7ed;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.ai-result-title i {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.ai-result-content {
|
||||
line-height: 1.8;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.ai-result-content >>> h3 {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #409eff;
|
||||
margin: 20px 0 10px 0;
|
||||
padding-left: 10px;
|
||||
border-left: 3px solid #409eff;
|
||||
}
|
||||
|
||||
.ai-result-content >>> p {
|
||||
margin: 12px 0;
|
||||
text-align: justify;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.ai-result-content >>> p:first-of-type {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.ai-result-content >>> br {
|
||||
line-height: 1.8;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
|
|||
|
|
@ -147,23 +147,10 @@
|
|||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="报告摘要" prop="summary">
|
||||
<el-input
|
||||
v-model="editForm.summary"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
placeholder="请输入报告摘要"
|
||||
/>
|
||||
<Editor v-model="editForm.summary" :min-height="150" />
|
||||
</el-form-item>
|
||||
<el-form-item label="报告内容" prop="reportContent">
|
||||
<el-input
|
||||
v-model="editForm.reportContent"
|
||||
type="textarea"
|
||||
:rows="15"
|
||||
placeholder="请输入报告内容(支持HTML格式)"
|
||||
/>
|
||||
<div style="margin-top: 10px; color: #909399; font-size: 12px;">
|
||||
<i class="el-icon-info"></i> 提示:报告内容支持HTML格式,可以包含标题、段落、列表等格式
|
||||
</div>
|
||||
<Editor v-model="editForm.reportContent" :min-height="400" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
|
|
@ -197,9 +184,11 @@
|
|||
import { listReport, getReport, delReport, exportReport, updateReportWithType } from "@/api/psychology/report";
|
||||
import { loadSasReportData } from "@/services/report/ReportDataMapper";
|
||||
import SASReportGenerator from "@/services/report/SASReportGenerator";
|
||||
import Editor from "@/components/Editor";
|
||||
|
||||
export default {
|
||||
name: "Report",
|
||||
components: { Editor },
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
|
|
|
|||
|
|
@ -72,11 +72,14 @@ export default {
|
|||
return {
|
||||
loading: false,
|
||||
testList: [],
|
||||
searchText: "",
|
||||
studentNo: ""
|
||||
searchText: ""
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 学员编号 - 从 store 实时获取,优先使用 infoNumber
|
||||
studentNo() {
|
||||
return this.$store.getters.infoNumber || this.$store.getters.name || "未知"
|
||||
},
|
||||
// 过滤后的测试题列表
|
||||
filteredTestList() {
|
||||
if (!this.searchText) {
|
||||
|
|
@ -88,12 +91,23 @@ export default {
|
|||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// 监听路由变化,从其他页面返回时刷新列表
|
||||
'$route'(to, from) {
|
||||
// 当路由变为当前页面时,刷新列表
|
||||
if (to.path === '/student/tests') {
|
||||
this.loadTestList()
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 获取学员编号
|
||||
this.studentNo = this.$store.getters.name || "未知"
|
||||
// 加载测试题列表
|
||||
this.loadTestList()
|
||||
},
|
||||
// 页面激活时刷新列表(从测试页面返回时)
|
||||
activated() {
|
||||
this.loadTestList()
|
||||
},
|
||||
methods: {
|
||||
// 加载测试题列表
|
||||
loadTestList() {
|
||||
|
|
@ -104,9 +118,19 @@ export default {
|
|||
includeQuestionnaire: true // 包含问卷
|
||||
}).then(response => {
|
||||
// 过滤出有题目的测试题
|
||||
this.testList = (response.rows || []).filter(scale => {
|
||||
let filteredList = (response.rows || []).filter(scale => {
|
||||
return scale.itemCount && scale.itemCount > 0
|
||||
})
|
||||
|
||||
// 按时间倒序排列(最新的在前面)
|
||||
this.testList = filteredList.sort((a, b) => {
|
||||
// 优先使用 updateTime,如果没有则使用 createTime
|
||||
const timeA = a.updateTime || a.createTime || ''
|
||||
const timeB = b.updateTime || b.createTime || ''
|
||||
// 倒序排列(新的在前)
|
||||
return timeB.localeCompare(timeA)
|
||||
})
|
||||
|
||||
this.loading = false
|
||||
}).catch(error => {
|
||||
console.error("loadTestList, 加载测试题列表失败:", error)
|
||||
|
|
|
|||
|
|
@ -96,32 +96,10 @@
|
|||
</el-row>
|
||||
|
||||
<!-- 添加或修改用户配置对话框 -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="用户昵称" prop="nickName">
|
||||
<el-input v-model="form.nickName" placeholder="请输入用户昵称" maxlength="30" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="归属部门" prop="deptId">
|
||||
<treeselect v-model="form.deptId" :options="enabledDeptOptions" :show-count="true" placeholder="请选择归属部门" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12" v-if="false">
|
||||
<el-form-item label="手机号码" prop="phonenumber">
|
||||
<el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="邮箱" prop="email">
|
||||
<el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-dialog :title="title" :visible.sync="open" width="900px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="120px">
|
||||
<!-- 基本信息 -->
|
||||
<el-divider content-position="left">基本信息</el-divider>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
|
||||
|
|
@ -136,7 +114,31 @@
|
|||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="用户性别">
|
||||
<el-form-item label="用户昵称" prop="nickName">
|
||||
<el-input v-model="form.nickName" placeholder="请输入用户昵称/姓名" maxlength="30" @input="handleNickNameInput" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="信息编号" prop="infoNumber">
|
||||
<el-input v-model="form.infoNumber" placeholder="请输入信息编号(仅数字)" @input="handleInfoNumberInput" maxlength="20" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="手机号码" prop="phonenumber">
|
||||
<el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="邮箱" prop="email">
|
||||
<el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="性别" prop="sex">
|
||||
<el-select v-model="form.sex" placeholder="请选择性别">
|
||||
<el-option v-for="dict in dict.type.sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
|
||||
</el-select>
|
||||
|
|
@ -150,6 +152,78 @@
|
|||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 心理档案信息 -->
|
||||
<el-divider content-position="left">心理档案信息</el-divider>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="档案类型" prop="profileType">
|
||||
<el-select v-model="form.profileType" placeholder="请选择档案类型">
|
||||
<el-option label="标准" value="standard" />
|
||||
<el-option label="儿童" value="child" />
|
||||
<el-option label="成人" value="adult" />
|
||||
<el-option label="老年" value="senior" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="身份证号" prop="idCard">
|
||||
<el-input v-model="form.idCard" placeholder="请输入身份证号" maxlength="18" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="生日" prop="birthday">
|
||||
<el-date-picker
|
||||
v-model="form.birthday"
|
||||
type="date"
|
||||
placeholder="选择生日"
|
||||
value-format="yyyy-MM-dd"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="学历" prop="education">
|
||||
<el-input v-model="form.education" placeholder="请输入学历" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="职业" prop="occupation">
|
||||
<el-input v-model="form.occupation" placeholder="请输入职业" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="归属部门" prop="deptId">
|
||||
<treeselect v-model="form.deptId" :options="enabledDeptOptions" :show-count="true" placeholder="请选择归属部门" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="地址" prop="address">
|
||||
<el-input v-model="form.address" type="textarea" :rows="2" placeholder="请输入地址" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="紧急联系人" prop="emergencyContact">
|
||||
<el-input v-model="form.emergencyContact" placeholder="请输入紧急联系人" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="紧急联系电话" prop="emergencyPhone">
|
||||
<el-input v-model="form.emergencyPhone" placeholder="请输入紧急联系电话" maxlength="11" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 系统权限 -->
|
||||
<el-divider content-position="left">系统权限</el-divider>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="岗位">
|
||||
|
|
@ -401,10 +475,29 @@ export default {
|
|||
status: "0",
|
||||
remark: undefined,
|
||||
postIds: [],
|
||||
roleIds: []
|
||||
roleIds: [],
|
||||
// 心理档案字段
|
||||
infoNumber: undefined,
|
||||
profileType: 'standard',
|
||||
idCard: undefined,
|
||||
birthday: undefined,
|
||||
education: undefined,
|
||||
occupation: undefined,
|
||||
address: undefined,
|
||||
emergencyContact: undefined,
|
||||
emergencyPhone: undefined
|
||||
}
|
||||
this.resetForm("form")
|
||||
},
|
||||
// 处理信息编号输入,只允许数字
|
||||
handleInfoNumberInput(value) {
|
||||
const numericValue = value.replace(/\D/g, '')
|
||||
this.form.infoNumber = numericValue
|
||||
},
|
||||
// 处理昵称输入,只允许汉字
|
||||
handleNickNameInput(value) {
|
||||
this.form.nickName = value.replace(/[^\u4e00-\u9fa5]/g, '')
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1
|
||||
|
|
|
|||
229
使用指南-总览.md
Normal file
229
使用指南-总览.md
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
# 心理健康测评系统 - 使用指南总览
|
||||
|
||||
## 📚 文档导航
|
||||
|
||||
本系统为不同身份的用户提供了详细的使用指南,请根据您的身份选择对应的指南文档。
|
||||
|
||||
---
|
||||
|
||||
## 👥 用户身份说明
|
||||
|
||||
### 1. 系统管理员
|
||||
|
||||
**适用对象**:
|
||||
- 系统管理员
|
||||
- 拥有完整系统管理权限的用户
|
||||
|
||||
**主要职责**:
|
||||
- 管理量表、用户、权限
|
||||
- 配置预警规则
|
||||
- 查看和管理测评报告
|
||||
- 管理二维码
|
||||
- 系统设置和维护
|
||||
|
||||
**对应指南**:👉 [系统管理员使用指南](./使用指南-系统管理员.md)
|
||||
|
||||
---
|
||||
|
||||
### 2. 普通用户/测评者
|
||||
|
||||
**适用对象**:
|
||||
- 已获得量表权限的注册用户
|
||||
- 需要进行心理测评的用户
|
||||
- 查看测评报告的用户
|
||||
|
||||
**主要功能**:
|
||||
- 进行心理量表测评
|
||||
- 查看测评报告
|
||||
- 查看历史记录
|
||||
- 使用二维码扫描
|
||||
- 管理个人档案
|
||||
|
||||
**对应指南**:👉 [普通用户使用指南](./使用指南-普通用户.md)
|
||||
|
||||
---
|
||||
|
||||
### 3. 注册用户
|
||||
|
||||
**适用对象**:
|
||||
- 新注册的用户
|
||||
- 等待权限分配的用户
|
||||
|
||||
**主要流程**:
|
||||
- 注册账号
|
||||
- 首次登录
|
||||
- 等待权限分配
|
||||
- 开始使用系统
|
||||
|
||||
**对应指南**:👉 [注册用户使用指南](./使用指南-注册用户.md)
|
||||
|
||||
---
|
||||
|
||||
## 📖 快速开始
|
||||
|
||||
### 我是系统管理员
|
||||
|
||||
1. 使用默认账号登录(用户名:`admin`,密码:`admin123`)
|
||||
2. 阅读 [系统管理员使用指南](./使用指南-系统管理员.md)
|
||||
3. 开始配置系统和管理用户
|
||||
|
||||
### 我是新用户
|
||||
|
||||
1. 在登录页面点击"注册"
|
||||
2. 填写注册信息完成注册
|
||||
3. 阅读 [注册用户使用指南](./使用指南-注册用户.md)
|
||||
4. 等待管理员分配权限
|
||||
5. 获得权限后,阅读 [普通用户使用指南](./使用指南-普通用户.md)
|
||||
6. 开始进行测评
|
||||
|
||||
### 我是已有权限的用户
|
||||
|
||||
1. 使用账号登录系统
|
||||
2. 阅读 [普通用户使用指南](./使用指南-普通用户.md)
|
||||
3. 开始进行测评
|
||||
|
||||
---
|
||||
|
||||
## 🎯 功能模块说明
|
||||
|
||||
### 量表管理
|
||||
- **管理员**:创建、导入、配置量表
|
||||
- **普通用户**:选择量表进行测评
|
||||
|
||||
### 测评管理
|
||||
- **管理员**:查看和管理所有测评记录
|
||||
- **普通用户**:查看自己的测评记录
|
||||
|
||||
### 报告管理
|
||||
- **管理员**:查看、编辑、导出所有报告
|
||||
- **普通用户**:查看自己的测评报告
|
||||
|
||||
### 权限管理
|
||||
- **管理员**:为用户分配量表权限
|
||||
- **普通用户**:查看自己的权限范围
|
||||
|
||||
### 问卷管理
|
||||
- **管理员**:创建自定义问卷、主观题评分
|
||||
- **普通用户**:参与问卷答题
|
||||
|
||||
### 预警管理
|
||||
- **管理员**:配置预警规则、查看预警信息
|
||||
- **普通用户**:不涉及
|
||||
|
||||
### 二维码管理
|
||||
- **管理员**:生成和管理二维码
|
||||
- **普通用户**:扫描二维码进行测评或查看报告
|
||||
|
||||
---
|
||||
|
||||
## 📋 文档结构
|
||||
|
||||
```
|
||||
使用指南总览.md ← 您当前所在的位置
|
||||
├── 使用指南-系统管理员.md ← 管理员完整使用指南
|
||||
├── 使用指南-普通用户.md ← 普通用户完整使用指南
|
||||
└── 使用指南-注册用户.md ← 注册用户指南
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 常见问题快速查找
|
||||
|
||||
### 关于注册
|
||||
- 如何注册账号? → [注册用户使用指南](./使用指南-注册用户.md#注册流程)
|
||||
- 注册后无法登录? → [注册用户使用指南](./使用指南-注册用户.md#常见问题)
|
||||
|
||||
### 关于测评
|
||||
- 如何开始测评? → [普通用户使用指南](./使用指南-普通用户.md#开始测评)
|
||||
- 如何答题? → [普通用户使用指南](./使用指南-普通用户.md#答题操作)
|
||||
- 可以暂停测评吗? → [普通用户使用指南](./使用指南-普通用户.md#暂停和继续)
|
||||
|
||||
### 关于报告
|
||||
- 如何查看报告? → [普通用户使用指南](./使用指南-普通用户.md#查看报告)
|
||||
- 报告什么时候生成? → [普通用户使用指南](./使用指南-普通用户.md#常见问题)
|
||||
|
||||
### 关于权限
|
||||
- 看不到量表怎么办? → [普通用户使用指南](./使用指南-普通用户.md#常见问题)
|
||||
- 如何分配权限? → [系统管理员使用指南](./使用指南-系统管理员.md#权限管理)
|
||||
|
||||
### 关于量表
|
||||
- 如何导入新量表? → [系统管理员使用指南](./使用指南-系统管理员.md#量表管理)
|
||||
- 如何配置量表? → [系统管理员使用指南](./使用指南-系统管理员.md#配置量表)
|
||||
|
||||
---
|
||||
|
||||
## 📞 获取帮助
|
||||
|
||||
### 技术支持
|
||||
|
||||
如遇到问题,可以:
|
||||
|
||||
1. **查看文档**:阅读对应的使用指南
|
||||
2. **查看常见问题**:每个指南都包含常见问题部分
|
||||
3. **联系管理员**:联系系统管理员获取帮助
|
||||
4. **查看系统日志**:管理员可以查看系统日志排查问题
|
||||
|
||||
### 文档更新
|
||||
|
||||
- 文档会随着系统更新而更新
|
||||
- 建议定期查看最新版本
|
||||
- 如有疑问,请联系技术支持
|
||||
|
||||
---
|
||||
|
||||
## ✅ 使用检查清单
|
||||
|
||||
### 新用户检查清单
|
||||
|
||||
- [ ] 已完成账号注册
|
||||
- [ ] 已成功登录系统
|
||||
- [ ] 已阅读注册用户使用指南
|
||||
- [ ] 已联系管理员申请权限
|
||||
- [ ] 已获得量表权限
|
||||
- [ ] 已阅读普通用户使用指南
|
||||
- [ ] 已准备好进行首次测评
|
||||
|
||||
### 管理员检查清单
|
||||
|
||||
- [ ] 已修改默认密码
|
||||
- [ ] 已阅读系统管理员使用指南
|
||||
- [ ] 已配置系统基础设置
|
||||
- [ ] 已导入或创建量表
|
||||
- [ ] 已为用户分配权限
|
||||
- [ ] 已配置预警规则(如需要)
|
||||
- [ ] 已测试系统功能
|
||||
|
||||
---
|
||||
|
||||
## 🎓 学习路径建议
|
||||
|
||||
### 对于新用户
|
||||
|
||||
1. **第一步**:注册账号 → [注册用户使用指南](./使用指南-注册用户.md)
|
||||
2. **第二步**:等待权限分配
|
||||
3. **第三步**:学习使用系统 → [普通用户使用指南](./使用指南-普通用户.md)
|
||||
4. **第四步**:进行首次测评
|
||||
5. **第五步**:查看测评报告
|
||||
|
||||
### 对于管理员
|
||||
|
||||
1. **第一步**:登录系统并修改密码
|
||||
2. **第二步**:阅读管理员指南 → [系统管理员使用指南](./使用指南-系统管理员.md)
|
||||
3. **第三步**:配置系统基础设置
|
||||
4. **第四步**:导入或创建量表
|
||||
5. **第五步**:为用户分配权限
|
||||
6. **第六步**:测试系统功能
|
||||
7. **第七步**:开始日常管理
|
||||
|
||||
---
|
||||
|
||||
## 📝 文档说明
|
||||
|
||||
- **最后更新**:2025-01-XX
|
||||
- **文档版本**:v1.0
|
||||
- **适用系统版本**:心理健康测评系统 v1.0
|
||||
|
||||
---
|
||||
|
||||
**祝您使用愉快!** 🎉
|
||||
|
||||
375
使用指南-普通用户.md
Normal file
375
使用指南-普通用户.md
Normal file
|
|
@ -0,0 +1,375 @@
|
|||
# 心理健康测评系统 - 普通用户使用指南
|
||||
|
||||
## 📋 目录
|
||||
|
||||
1. [系统概述](#系统概述)
|
||||
2. [注册账号](#注册账号)
|
||||
3. [登录系统](#登录系统)
|
||||
4. [开始测评](#开始测评)
|
||||
5. [答题操作](#答题操作)
|
||||
6. [查看报告](#查看报告)
|
||||
7. [查看历史记录](#查看历史记录)
|
||||
8. [使用二维码](#使用二维码)
|
||||
9. [用户档案](#用户档案)
|
||||
10. [常见问题](#常见问题)
|
||||
|
||||
---
|
||||
|
||||
## 系统概述
|
||||
|
||||
心理健康测评系统是一个专业的心理测评平台,您可以通过该系统进行各种心理量表测评,查看测评报告,了解自己的心理健康状况。
|
||||
|
||||
### 主要功能
|
||||
|
||||
- **心理测评**:进行各种心理量表测评
|
||||
- **查看报告**:查看详细的测评报告和结果解释
|
||||
- **历史记录**:查看历史测评记录
|
||||
- **二维码扫描**:通过扫码快速开始测评
|
||||
- **用户档案**:管理个人档案信息
|
||||
|
||||
---
|
||||
|
||||
## 注册账号
|
||||
|
||||
### 注册步骤
|
||||
|
||||
1. 打开浏览器,访问系统地址(如:`http://localhost:80`)
|
||||
2. 在登录页面,点击 **"注册"** 链接
|
||||
3. 填写注册信息:
|
||||
- **用户名**:用于登录的用户名(必填,唯一)
|
||||
- **密码**:登录密码(必填,建议8位以上)
|
||||
- **确认密码**:再次输入密码(必填)
|
||||
- **手机号**:手机号码(可选)
|
||||
- **邮箱**:邮箱地址(可选)
|
||||
4. 输入验证码(如显示)
|
||||
5. 点击 **"注册"** 按钮
|
||||
6. 注册成功后,系统会提示注册成功
|
||||
|
||||
### 注册注意事项
|
||||
|
||||
- 用户名不能重复,如果提示用户名已存在,请更换用户名
|
||||
- 密码建议包含字母和数字,提高安全性
|
||||
- 注册后需要等待管理员分配量表权限才能进行测评
|
||||
- 如果忘记密码,请联系管理员重置
|
||||
|
||||
---
|
||||
|
||||
## 登录系统
|
||||
|
||||
### 登录步骤
|
||||
|
||||
1. 打开浏览器,访问系统地址
|
||||
2. 在登录页面输入:
|
||||
- **用户名**:您的用户名
|
||||
- **密码**:您的密码
|
||||
- **验证码**:输入显示的验证码(如显示)
|
||||
3. 点击 **"登录"** 按钮
|
||||
4. 登录成功后进入系统首页
|
||||
|
||||
### 登录问题
|
||||
|
||||
- **忘记密码**:请联系管理员重置密码
|
||||
- **账号被锁定**:联系管理员解锁账号
|
||||
- **验证码看不清**:点击验证码图片刷新
|
||||
|
||||
---
|
||||
|
||||
## 开始测评
|
||||
|
||||
### 方式一:通过菜单开始
|
||||
|
||||
1. 登录系统后,点击左侧菜单 **"心理测评管理"** → **"测评管理"**
|
||||
2. 点击 **"开始测评"** 按钮
|
||||
3. 在量表选择页面,选择要进行的量表
|
||||
4. 填写被测评人信息:
|
||||
- **姓名**:被测评人姓名
|
||||
- **性别**:男/女
|
||||
- **年龄**:年龄
|
||||
- **其他信息**:根据需要填写
|
||||
5. 点击 **"开始测评"** 按钮
|
||||
6. 进入答题页面
|
||||
|
||||
### 方式二:通过二维码扫描
|
||||
|
||||
1. 使用手机扫描管理员提供的测评二维码
|
||||
2. 如果未登录,系统会提示先登录
|
||||
3. 登录后自动跳转到测评开始页面
|
||||
4. 填写被测评人信息
|
||||
5. 开始答题
|
||||
|
||||
### 量表选择说明
|
||||
|
||||
- **权限限制**:您只能看到管理员为您分配权限的量表
|
||||
- **量表信息**:每个量表显示名称、类型、题目数量、预计时间
|
||||
- **无权限提示**:如果没有可用的量表,系统会提示联系管理员
|
||||
|
||||
---
|
||||
|
||||
## 答题操作
|
||||
|
||||
### 答题界面
|
||||
|
||||
答题页面包含以下元素:
|
||||
- **量表信息**:显示量表名称和进度
|
||||
- **题目区域**:显示当前题目和选项
|
||||
- **进度条**:显示答题进度
|
||||
- **导航按钮**:上一题、下一题、提交
|
||||
|
||||
### 答题步骤
|
||||
|
||||
1. **阅读题目**:仔细阅读题目内容
|
||||
2. **选择答案**:
|
||||
- **单选题**:选择一个选项
|
||||
- **多选题**:可以选择多个选项
|
||||
3. **保存答案**:选择答案后,系统自动保存
|
||||
4. **继续答题**:
|
||||
- 点击 **"下一题"** 继续
|
||||
- 或点击 **"上一题"** 返回修改
|
||||
5. **完成答题**:
|
||||
- 答完所有题目后,点击 **"提交"** 按钮
|
||||
- 确认提交后,系统生成测评报告
|
||||
|
||||
### 答题技巧
|
||||
|
||||
- **认真阅读**:仔细阅读每个题目,理解题意
|
||||
- **如实回答**:根据自己的真实情况回答,不要猜测
|
||||
- **不要跳过**:尽量回答所有题目,确保结果准确
|
||||
- **可以修改**:在提交前可以随时返回修改答案
|
||||
- **注意时间**:某些量表有时间限制,注意答题时间
|
||||
|
||||
### 暂停和继续
|
||||
|
||||
如果无法一次性完成测评:
|
||||
|
||||
1. **暂停测评**:
|
||||
- 点击 **"暂停"** 按钮
|
||||
- 系统保存当前进度
|
||||
2. **继续测评**:
|
||||
- 下次登录后,进入 **"测评管理"**
|
||||
- 找到状态为"进行中"的测评
|
||||
- 点击 **"继续测评"** 按钮
|
||||
- 系统自动跳转到上次的答题位置
|
||||
|
||||
---
|
||||
|
||||
## 查看报告
|
||||
|
||||
### 查看方式
|
||||
|
||||
#### 方式一:通过菜单查看
|
||||
|
||||
1. 登录系统后,点击 **"心理测评管理"** → **"测评报告"**
|
||||
2. 在报告列表中,找到要查看的报告
|
||||
3. 点击 **"查看"** 按钮
|
||||
4. 查看报告详细内容
|
||||
|
||||
#### 方式二:通过测评记录查看
|
||||
|
||||
1. 进入 **"测评管理"**
|
||||
2. 找到已完成的测评记录
|
||||
3. 点击 **"查看报告"** 按钮
|
||||
4. 查看报告
|
||||
|
||||
#### 方式三:通过二维码扫描
|
||||
|
||||
1. 扫描管理员提供的报告查看二维码
|
||||
2. 如果未登录,系统会提示先登录
|
||||
3. 登录后自动跳转到报告详情页面
|
||||
|
||||
### 报告内容
|
||||
|
||||
测评报告通常包含以下内容:
|
||||
|
||||
- **基本信息**:
|
||||
- 被测评人信息
|
||||
- 测评时间
|
||||
- 量表名称
|
||||
- **测评结果**:
|
||||
- 总分
|
||||
- 各因子得分(如有)
|
||||
- 分数解释
|
||||
- **结果分析**:
|
||||
- 结果等级(如:正常、轻度、中度、重度)
|
||||
- 详细解释
|
||||
- 因子分析(如有)
|
||||
- **建议指导**:
|
||||
- 针对性的建议
|
||||
- 改善方法
|
||||
- 注意事项
|
||||
|
||||
### 报告说明
|
||||
|
||||
- **报告生成**:提交测评后,系统自动生成报告
|
||||
- **报告准确性**:报告结果基于您的答题情况,请如实回答
|
||||
- **仅供参考**:报告结果仅供参考,不能替代专业诊断
|
||||
- **隐私保护**:您的测评数据受到隐私保护
|
||||
|
||||
---
|
||||
|
||||
## 查看历史记录
|
||||
|
||||
### 查看测评记录
|
||||
|
||||
1. 进入 **"心理测评管理"** → **"测评管理"**
|
||||
2. 查看所有测评记录:
|
||||
- **进行中**:尚未完成的测评
|
||||
- **已完成**:已完成的测评
|
||||
- **已暂停**:暂停的测评
|
||||
3. 可以按条件搜索:
|
||||
- 量表名称
|
||||
- 被测评人
|
||||
- 测评状态
|
||||
- 创建时间
|
||||
|
||||
### 查看报告记录
|
||||
|
||||
1. 进入 **"心理测评管理"** → **"测评报告"**
|
||||
2. 查看所有报告记录
|
||||
3. 可以按条件搜索:
|
||||
- 报告标题
|
||||
- 量表名称
|
||||
- 创建时间
|
||||
|
||||
### 对比分析
|
||||
|
||||
- 可以查看同一被测评人的多次测评记录
|
||||
- 对比不同时间的测评结果
|
||||
- 了解心理变化趋势
|
||||
|
||||
---
|
||||
|
||||
## 使用二维码
|
||||
|
||||
### 扫描测评二维码
|
||||
|
||||
1. 使用手机扫描管理员提供的测评二维码
|
||||
2. 如果未登录,系统会提示先登录
|
||||
3. 登录后自动跳转到测评开始页面
|
||||
4. 填写被测评人信息
|
||||
5. 开始答题
|
||||
|
||||
### 扫描报告二维码
|
||||
|
||||
1. 使用手机扫描管理员提供的报告查看二维码
|
||||
2. 如果未登录,系统会提示先登录
|
||||
3. 登录后自动跳转到报告详情页面
|
||||
4. 查看报告内容
|
||||
|
||||
### 二维码使用说明
|
||||
|
||||
- **扫码工具**:可以使用微信、支付宝等应用的扫一扫功能
|
||||
- **网络要求**:需要网络连接才能访问
|
||||
- **权限要求**:需要登录并有相应权限
|
||||
- **有效期**:二维码可能有过期时间,过期后无法使用
|
||||
|
||||
---
|
||||
|
||||
## 用户档案
|
||||
|
||||
### 查看个人档案
|
||||
|
||||
1. 进入 **"心理测评管理"** → **"用户档案"**
|
||||
2. 查看个人档案信息
|
||||
3. 可以查看:
|
||||
- 基本信息
|
||||
- 测评记录
|
||||
- 档案历史
|
||||
|
||||
### 编辑个人档案
|
||||
|
||||
1. 在档案页面,点击 **"编辑"** 按钮
|
||||
2. 修改档案信息(如允许)
|
||||
3. 点击 **"确定"** 保存
|
||||
|
||||
### 档案说明
|
||||
|
||||
- **档案内容**:由管理员配置,可能包含自定义字段
|
||||
- **隐私保护**:档案信息受到隐私保护
|
||||
- **权限限制**:某些字段可能无法自行修改
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q1: 注册后无法看到量表?
|
||||
|
||||
**A**: 注册后需要等待管理员为您分配量表权限。请联系管理员分配权限。
|
||||
|
||||
### Q2: 忘记密码怎么办?
|
||||
|
||||
**A**: 请联系管理员重置密码。管理员可以在用户管理中重置您的密码。
|
||||
|
||||
### Q3: 答题过程中可以暂停吗?
|
||||
|
||||
**A**: 可以。点击"暂停"按钮,系统会保存当前进度。下次登录后可以继续完成测评。
|
||||
|
||||
### Q4: 可以修改已提交的答案吗?
|
||||
|
||||
**A**: 不可以。提交后无法修改答案。请在提交前仔细检查。
|
||||
|
||||
### Q5: 报告什么时候生成?
|
||||
|
||||
**A**: 提交测评后,系统会自动生成报告。通常几秒钟内完成。
|
||||
|
||||
### Q6: 可以查看历史测评记录吗?
|
||||
|
||||
**A**: 可以。在"测评管理"中可以查看所有历史测评记录。
|
||||
|
||||
### Q7: 报告结果准确吗?
|
||||
|
||||
**A**: 报告结果基于您的答题情况。请如实回答题目,确保结果准确。但报告结果仅供参考,不能替代专业诊断。
|
||||
|
||||
### Q8: 可以导出报告吗?
|
||||
|
||||
**A**: 普通用户无法导出报告。如需导出,请联系管理员。
|
||||
|
||||
### Q9: 二维码扫描后无法访问?
|
||||
|
||||
**A**: 检查以下几点:
|
||||
- 是否已登录
|
||||
- 是否有相应权限
|
||||
- 二维码是否过期
|
||||
- 网络连接是否正常
|
||||
|
||||
### Q10: 如何联系管理员?
|
||||
|
||||
**A**: 请联系系统管理员或技术支持人员。
|
||||
|
||||
---
|
||||
|
||||
## 使用提示
|
||||
|
||||
### 测评前
|
||||
|
||||
- ✅ 确保网络连接正常
|
||||
- ✅ 选择一个安静的环境
|
||||
- ✅ 预留足够的答题时间
|
||||
- ✅ 准备好被测评人的基本信息
|
||||
|
||||
### 测评中
|
||||
|
||||
- ✅ 认真阅读每个题目
|
||||
- ✅ 根据自己的真实情况回答
|
||||
- ✅ 不要猜测或随意选择
|
||||
- ✅ 注意答题时间
|
||||
|
||||
### 测评后
|
||||
|
||||
- ✅ 查看生成的报告
|
||||
- ✅ 理解报告内容
|
||||
- ✅ 如有疑问,咨询专业人员
|
||||
- ✅ 保存报告信息(如需要)
|
||||
|
||||
---
|
||||
|
||||
## 隐私说明
|
||||
|
||||
- 您的测评数据受到严格保护
|
||||
- 只有管理员和您本人可以查看您的测评记录
|
||||
- 系统不会向第三方泄露您的个人信息
|
||||
- 请妥善保管您的账号密码
|
||||
|
||||
---
|
||||
|
||||
**最后更新**:2025-01-XX
|
||||
|
||||
264
使用指南-注册用户.md
Normal file
264
使用指南-注册用户.md
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
# 心理健康测评系统 - 注册用户使用指南
|
||||
|
||||
## 📋 目录
|
||||
|
||||
1. [注册流程](#注册流程)
|
||||
2. [首次登录](#首次登录)
|
||||
3. [等待权限分配](#等待权限分配)
|
||||
4. [开始使用](#开始使用)
|
||||
5. [常见问题](#常见问题)
|
||||
|
||||
---
|
||||
|
||||
## 注册流程
|
||||
|
||||
### 访问注册页面
|
||||
|
||||
1. 打开浏览器,访问系统地址(如:`http://localhost:80`)
|
||||
2. 在登录页面,点击 **"注册"** 链接或按钮
|
||||
3. 进入注册页面
|
||||
|
||||
### 填写注册信息
|
||||
|
||||
在注册页面填写以下信息:
|
||||
|
||||
#### 必填信息
|
||||
|
||||
- **用户名**:
|
||||
- 用于登录的用户名
|
||||
- 必须唯一,不能与其他用户重复
|
||||
- 建议使用字母、数字组合
|
||||
- 长度建议:3-20个字符
|
||||
|
||||
- **密码**:
|
||||
- 登录密码
|
||||
- 建议8位以上
|
||||
- 建议包含字母和数字
|
||||
- 不要使用过于简单的密码(如:123456)
|
||||
|
||||
- **确认密码**:
|
||||
- 再次输入密码
|
||||
- 必须与密码一致
|
||||
|
||||
#### 可选信息
|
||||
|
||||
- **手机号**:手机号码(用于找回密码等)
|
||||
- **邮箱**:邮箱地址(用于接收通知等)
|
||||
|
||||
### 完成注册
|
||||
|
||||
1. 输入验证码(如显示)
|
||||
2. 阅读并同意用户协议(如有)
|
||||
3. 点击 **"注册"** 按钮
|
||||
4. 系统验证信息:
|
||||
- 如果用户名已存在,会提示"用户名已存在"
|
||||
- 如果密码不一致,会提示"两次密码不一致"
|
||||
- 如果验证码错误,会提示"验证码错误"
|
||||
5. 注册成功后,系统会显示"注册成功"提示
|
||||
|
||||
---
|
||||
|
||||
## 首次登录
|
||||
|
||||
### 登录步骤
|
||||
|
||||
1. 注册成功后,返回登录页面
|
||||
2. 使用注册的用户名和密码登录
|
||||
3. 首次登录后,您可能会看到:
|
||||
- 欢迎页面
|
||||
- 系统提示(如:等待管理员分配权限)
|
||||
- 空白的量表列表(如果还没有权限)
|
||||
|
||||
### 登录后状态
|
||||
|
||||
注册用户首次登录后,通常处于以下状态:
|
||||
|
||||
- ✅ **账号已激活**:可以正常登录系统
|
||||
- ⏳ **等待权限**:需要等待管理员分配量表权限
|
||||
- 📋 **功能受限**:可能无法看到量表或进行测评
|
||||
|
||||
---
|
||||
|
||||
## 等待权限分配
|
||||
|
||||
### 为什么需要等待?
|
||||
|
||||
注册用户需要管理员分配量表访问权限后才能进行测评。这是为了:
|
||||
|
||||
- **权限控制**:确保用户只能访问被授权的量表
|
||||
- **数据安全**:保护测评数据的安全
|
||||
- **管理规范**:便于管理员统一管理
|
||||
|
||||
### 如何知道权限已分配?
|
||||
|
||||
权限分配后,您可以通过以下方式确认:
|
||||
|
||||
1. **刷新页面**:登录后刷新浏览器页面
|
||||
2. **查看量表列表**:进入"测评管理",如果能看到量表列表,说明已有权限
|
||||
3. **联系管理员**:如果长时间没有权限,可以联系管理员确认
|
||||
|
||||
### 权限说明
|
||||
|
||||
管理员可以为您分配:
|
||||
|
||||
- **量表权限**:指定您可以访问哪些量表
|
||||
- **时间范围**:权限的有效期(开始时间和结束时间)
|
||||
- **权限类型**:按用户、角色或部门分配
|
||||
|
||||
---
|
||||
|
||||
## 开始使用
|
||||
|
||||
### 获得权限后
|
||||
|
||||
当管理员为您分配权限后,您可以:
|
||||
|
||||
1. **查看可用量表**:
|
||||
- 进入"心理测评管理" → "测评管理"
|
||||
- 点击"开始测评"
|
||||
- 查看可用的量表列表
|
||||
|
||||
2. **开始测评**:
|
||||
- 选择要进行的量表
|
||||
- 填写被测评人信息
|
||||
- 开始答题
|
||||
|
||||
3. **查看报告**:
|
||||
- 完成测评后查看报告
|
||||
- 查看历史测评记录
|
||||
|
||||
### 使用流程
|
||||
|
||||
完整的测评流程:
|
||||
|
||||
```
|
||||
注册账号
|
||||
↓
|
||||
登录系统
|
||||
↓
|
||||
等待权限分配
|
||||
↓
|
||||
选择量表
|
||||
↓
|
||||
填写被测评人信息
|
||||
↓
|
||||
开始答题
|
||||
↓
|
||||
提交测评
|
||||
↓
|
||||
查看报告
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q1: 注册时提示"用户名已存在"?
|
||||
|
||||
**A**: 该用户名已被其他用户使用。请更换一个不同的用户名。
|
||||
|
||||
**建议**:
|
||||
- 使用字母+数字组合
|
||||
- 添加下划线或连字符
|
||||
- 使用邮箱前缀作为用户名
|
||||
|
||||
### Q2: 注册时提示"密码不一致"?
|
||||
|
||||
**A**: "密码"和"确认密码"输入不一致。请重新输入,确保两次输入的密码完全相同。
|
||||
|
||||
### Q3: 注册后无法登录?
|
||||
|
||||
**A**: 检查以下几点:
|
||||
- 用户名和密码是否正确
|
||||
- 是否输入了正确的验证码
|
||||
- 账号是否被管理员停用
|
||||
- 联系管理员确认账号状态
|
||||
|
||||
### Q4: 登录后看不到量表?
|
||||
|
||||
**A**: 这是正常情况。注册用户需要等待管理员分配量表权限。请:
|
||||
- 等待管理员分配权限
|
||||
- 或联系管理员申请权限
|
||||
|
||||
### Q5: 如何联系管理员?
|
||||
|
||||
**A**: 请联系系统管理员或技术支持人员,告知您的用户名和需求。
|
||||
|
||||
### Q6: 忘记密码怎么办?
|
||||
|
||||
**A**: 请联系管理员重置密码。管理员可以在用户管理中重置您的密码。
|
||||
|
||||
### Q7: 可以修改注册信息吗?
|
||||
|
||||
**A**: 部分信息可以修改:
|
||||
- 登录后进入"个人中心"(如有)
|
||||
- 或联系管理员修改
|
||||
|
||||
### Q8: 注册后多久可以获得权限?
|
||||
|
||||
**A**: 这取决于管理员的工作安排。通常:
|
||||
- 管理员会定期审核新注册用户
|
||||
- 或根据申请及时分配权限
|
||||
- 建议主动联系管理员申请
|
||||
|
||||
### Q9: 可以注册多个账号吗?
|
||||
|
||||
**A**: 可以,但需要:
|
||||
- 使用不同的用户名
|
||||
- 每个账号独立管理
|
||||
- 遵守系统使用规范
|
||||
|
||||
### Q10: 注册信息会被泄露吗?
|
||||
|
||||
**A**: 不会。系统严格保护用户隐私:
|
||||
- 注册信息受到加密保护
|
||||
- 不会向第三方泄露
|
||||
- 只有管理员可以查看(用于权限管理)
|
||||
|
||||
---
|
||||
|
||||
## 注册注意事项
|
||||
|
||||
### 用户名选择
|
||||
|
||||
- ✅ 使用易记的用户名
|
||||
- ✅ 避免使用特殊字符
|
||||
- ✅ 不要使用真实姓名(保护隐私)
|
||||
- ❌ 不要使用过于简单的用户名(如:abc、123)
|
||||
|
||||
### 密码设置
|
||||
|
||||
- ✅ 使用8位以上的密码
|
||||
- ✅ 包含字母和数字
|
||||
- ✅ 定期更换密码
|
||||
- ❌ 不要使用过于简单的密码
|
||||
- ❌ 不要使用个人信息作为密码
|
||||
|
||||
### 信息填写
|
||||
|
||||
- ✅ 如实填写信息(如手机号、邮箱)
|
||||
- ✅ 信息用于账号管理和找回密码
|
||||
- ⚠️ 注意保护个人隐私
|
||||
|
||||
---
|
||||
|
||||
## 下一步
|
||||
|
||||
注册成功后,建议您:
|
||||
|
||||
1. **保存账号信息**:记录用户名和密码,妥善保管
|
||||
2. **联系管理员**:主动联系管理员申请量表权限
|
||||
3. **了解系统**:阅读《普通用户使用指南》,了解系统功能
|
||||
4. **准备测评**:获得权限后,准备好进行测评
|
||||
|
||||
---
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [普通用户使用指南](./使用指南-普通用户.md) - 详细的使用说明
|
||||
- [系统管理员使用指南](./使用指南-系统管理员.md) - 管理员功能说明
|
||||
|
||||
---
|
||||
|
||||
**最后更新**:2025-01-XX
|
||||
|
||||
650
使用指南-系统管理员.md
Normal file
650
使用指南-系统管理员.md
Normal file
|
|
@ -0,0 +1,650 @@
|
|||
# 心理健康测评系统 - 系统管理员使用指南
|
||||
|
||||
## 📋 目录
|
||||
|
||||
1. [系统概述](#系统概述)
|
||||
2. [登录系统](#登录系统)
|
||||
3. [量表管理](#量表管理)
|
||||
4. [用户管理](#用户管理)
|
||||
5. [权限管理](#权限管理)
|
||||
6. [测评管理](#测评管理)
|
||||
7. [报告管理](#报告管理)
|
||||
8. [问卷管理](#问卷管理)
|
||||
9. [预警管理](#预警管理)
|
||||
10. [二维码管理](#二维码管理)
|
||||
11. [用户档案管理](#用户档案管理)
|
||||
12. [心理网站管理](#心理网站管理)
|
||||
13. [系统设置](#系统设置)
|
||||
14. [数据导出](#数据导出)
|
||||
15. [常见问题](#常见问题)
|
||||
|
||||
---
|
||||
|
||||
## 系统概述
|
||||
|
||||
心理健康测评系统是一个基于Web的心理测评管理平台,支持量表测评、自定义问卷、用户档案管理、预警管理等功能。
|
||||
|
||||
### 主要功能模块
|
||||
|
||||
- **量表管理**:创建、导入、配置心理量表
|
||||
- **用户管理**:管理用户账号、分配权限
|
||||
- **测评管理**:查看和管理测评记录
|
||||
- **报告管理**:查看、编辑、导出测评报告
|
||||
- **问卷管理**:创建自定义问卷、主观题评分
|
||||
- **预警管理**:配置预警规则、查看预警信息
|
||||
- **二维码管理**:生成和管理测评二维码
|
||||
- **用户档案**:管理用户档案信息
|
||||
- **心理网站**:管理心理教育网站内容
|
||||
|
||||
---
|
||||
|
||||
## 登录系统
|
||||
|
||||
### 访问系统
|
||||
|
||||
1. 打开浏览器,访问系统地址(如:`http://localhost:80`)
|
||||
2. 进入登录页面
|
||||
|
||||
### 默认管理员账号
|
||||
|
||||
- **用户名**:`admin`
|
||||
- **密码**:`admin123`
|
||||
|
||||
> ⚠️ **安全提示**:首次登录后请立即修改密码!
|
||||
|
||||
### 登录步骤
|
||||
|
||||
1. 输入用户名和密码
|
||||
2. 输入验证码(如显示)
|
||||
3. 点击"登录"按钮
|
||||
4. 登录成功后进入系统首页
|
||||
|
||||
---
|
||||
|
||||
## 量表管理
|
||||
|
||||
### 功能说明
|
||||
|
||||
量表管理是系统的核心功能,管理员可以创建、导入、配置和管理心理量表。
|
||||
|
||||
### 创建新量表
|
||||
|
||||
#### 方式一:手动创建
|
||||
|
||||
1. 进入 **心理测评管理** → **量表管理**
|
||||
2. 点击 **"新增"** 按钮
|
||||
3. 填写量表基本信息:
|
||||
- **量表编码**:唯一标识(如:`SCL_90`)
|
||||
- **量表名称**:量表完整名称
|
||||
- **量表类型**:选择类型(情绪、人格、行为等)
|
||||
- **量表简介**:简短介绍
|
||||
- **量表描述**:详细描述
|
||||
- **题目数量**:预计题目数
|
||||
- **预计完成时间**:分钟数
|
||||
- **适用人群**:如"一般人群"、"青少年"等
|
||||
- **作者**:量表作者
|
||||
- **来源**:量表来源
|
||||
- **状态**:选择"正常"(启用)
|
||||
4. 点击 **"确定"** 保存
|
||||
|
||||
#### 方式二:JSON格式导入
|
||||
|
||||
1. 进入 **量表管理** 页面
|
||||
2. 点击 **"导入"** 按钮
|
||||
3. 选择JSON格式的量表文件
|
||||
4. 系统自动解析并导入量表数据
|
||||
5. 检查导入结果,确认无误
|
||||
|
||||
> 📖 **详细说明**:参考《新量表导入完整操作指南.md》
|
||||
|
||||
### 配置量表
|
||||
|
||||
创建量表后,需要完成以下配置:
|
||||
|
||||
#### 1. 添加题目
|
||||
|
||||
1. 在量表列表中,点击 **"题目管理"** 按钮
|
||||
2. 点击 **"新增"** 添加题目
|
||||
3. 填写题目信息:
|
||||
- **题目序号**:如 1、2、3...
|
||||
- **题目内容**:题目的完整文字
|
||||
- **题目类型**:单选题/多选题
|
||||
- **是否必答**:是/否
|
||||
4. 保存题目
|
||||
|
||||
#### 2. 配置选项
|
||||
|
||||
1. 在题目列表中,点击 **"选项管理"** 按钮
|
||||
2. 为每个题目添加选项:
|
||||
- **选项编码**:如 A、B、C、D
|
||||
- **选项内容**:选项文字
|
||||
- **选项分数**:该选项对应的分数
|
||||
3. 保存选项
|
||||
|
||||
#### 3. 添加因子(如需要)
|
||||
|
||||
1. 在量表列表中,点击 **"因子管理"** 按钮
|
||||
2. 点击 **"新增"** 添加因子
|
||||
3. 填写因子信息:
|
||||
- **因子编码**:如 F1、F2
|
||||
- **因子名称**:如"躯体化因子"
|
||||
- **因子描述**:详细说明
|
||||
4. 保存因子
|
||||
|
||||
#### 4. 配置计分规则(如需要)
|
||||
|
||||
1. 在因子列表中,点击 **"计分规则"** 按钮
|
||||
2. 为每个因子配置计分规则:
|
||||
- 选择题目
|
||||
- 选择选项(可选)
|
||||
- 设置权重
|
||||
- 选择计算方式(求和/平均/最大/最小)
|
||||
3. 保存规则
|
||||
|
||||
#### 5. 配置结果解释
|
||||
|
||||
1. 进入 **心理测评管理** → **解释配置**
|
||||
2. 点击 **"新增"** 添加解释
|
||||
3. 填写解释信息:
|
||||
- **量表**:选择量表
|
||||
- **因子**:选择因子(可选)
|
||||
- **分数下限/上限**:分数范围
|
||||
- **等级**:如"低"、"中"、"高"
|
||||
- **解释标题**:解释标题
|
||||
- **解释内容**:详细解释
|
||||
- **建议指导**:建议和指导
|
||||
4. 保存解释
|
||||
|
||||
### 管理量表
|
||||
|
||||
- **编辑量表**:点击 **"修改"** 按钮
|
||||
- **删除量表**:点击 **"删除"** 按钮(需谨慎)
|
||||
- **查看详情**:点击量表名称
|
||||
- **导出量表**:勾选量表后点击 **"导出"** 按钮
|
||||
|
||||
---
|
||||
|
||||
## 用户管理
|
||||
|
||||
### 功能说明
|
||||
|
||||
用户管理用于管理系统用户账号,包括创建用户、分配角色、设置权限等。
|
||||
|
||||
### 查看用户列表
|
||||
|
||||
1. 进入 **系统管理** → **用户管理**
|
||||
2. 查看用户列表,可以按条件搜索:
|
||||
- 用户名
|
||||
- 手机号
|
||||
- 状态
|
||||
- 创建时间
|
||||
|
||||
### 创建新用户
|
||||
|
||||
1. 在用户管理页面,点击 **"新增"** 按钮
|
||||
2. 填写用户信息:
|
||||
- **用户名**:登录用户名
|
||||
- **昵称**:显示名称
|
||||
- **邮箱**:邮箱地址
|
||||
- **手机号**:手机号码
|
||||
- **性别**:男/女
|
||||
- **密码**:初始密码
|
||||
- **部门**:所属部门
|
||||
- **角色**:选择角色
|
||||
- **状态**:正常/停用
|
||||
3. 点击 **"确定"** 保存
|
||||
|
||||
### 管理用户
|
||||
|
||||
- **编辑用户**:点击 **"修改"** 按钮
|
||||
- **删除用户**:点击 **"删除"** 按钮
|
||||
- **重置密码**:点击 **"重置密码"** 按钮
|
||||
- **分配角色**:点击 **"更多"** → **"分配角色"**
|
||||
- **分配量表权限**:点击 **"更多"** → **"分配量表权限"**
|
||||
|
||||
### 批量操作
|
||||
|
||||
1. 勾选多个用户
|
||||
2. 点击 **"批量删除"** 或 **"批量导出"**
|
||||
|
||||
---
|
||||
|
||||
## 权限管理
|
||||
|
||||
### 功能说明
|
||||
|
||||
权限管理用于控制用户对量表的访问权限,支持按用户、角色、部门分配权限。
|
||||
|
||||
### 量表权限管理
|
||||
|
||||
1. 进入 **心理测评管理** → **量表权限管理**
|
||||
2. 查看权限列表,可以按条件筛选:
|
||||
- 量表名称
|
||||
- 用户名称
|
||||
- 部门
|
||||
- 状态
|
||||
|
||||
### 分配权限
|
||||
|
||||
#### 方式一:通过权限管理页面
|
||||
|
||||
1. 在权限管理页面,点击 **"新增"** 按钮
|
||||
2. 填写权限信息:
|
||||
- **量表**:选择量表
|
||||
- **用户**:选择用户(可选)
|
||||
- **角色**:选择角色(可选)
|
||||
- **部门**:选择部门(可选)
|
||||
- **开始时间**:权限生效时间
|
||||
- **结束时间**:权限失效时间
|
||||
- **状态**:有效/无效
|
||||
3. 点击 **"确定"** 保存
|
||||
|
||||
#### 方式二:通过用户管理页面
|
||||
|
||||
1. 进入 **系统管理** → **用户管理**
|
||||
2. 找到要分配权限的用户
|
||||
3. 点击 **"更多"** → **"分配量表权限"**
|
||||
4. 在权限分配页面,选择量表并设置时间范围
|
||||
5. 点击 **"确定"** 保存
|
||||
|
||||
### 权限规则
|
||||
|
||||
- **管理员**(userId = 1)自动拥有所有量表的访问权限
|
||||
- **用户直接权限**:优先级最高
|
||||
- **角色权限**:次优先级
|
||||
- **部门权限**:再次优先级
|
||||
- **全局权限**:最低优先级(所有用户)
|
||||
|
||||
---
|
||||
|
||||
## 测评管理
|
||||
|
||||
### 功能说明
|
||||
|
||||
测评管理用于查看和管理所有测评记录,包括进行中的测评和已完成的测评。
|
||||
|
||||
### 查看测评列表
|
||||
|
||||
1. 进入 **心理测评管理** → **测评管理**
|
||||
2. 查看测评列表,可以按条件搜索:
|
||||
- 量表名称
|
||||
- 被测评人
|
||||
- 测评状态
|
||||
- 创建时间
|
||||
|
||||
### 测评状态
|
||||
|
||||
- **进行中**:测评尚未完成
|
||||
- **已完成**:测评已完成并生成报告
|
||||
- **已暂停**:测评被暂停(支持继续测评)
|
||||
|
||||
### 管理测评
|
||||
|
||||
- **查看详情**:点击测评记录
|
||||
- **查看报告**:点击 **"查看报告"** 按钮
|
||||
- **删除测评**:点击 **"删除"** 按钮
|
||||
- **继续测评**:对于暂停的测评,可以继续完成
|
||||
|
||||
### 管理员快速填充(测试功能)
|
||||
|
||||
> ⚠️ **注意**:此功能仅用于测试,不建议用于真实测评数据。
|
||||
|
||||
1. 进入测评页面
|
||||
2. 点击 **"快速填充"** 下拉按钮
|
||||
3. 选择填充策略:
|
||||
- 填充第一个选项并提交
|
||||
- 填充中间选项并提交
|
||||
- 填充最后一个选项并提交
|
||||
- 随机填充并提交
|
||||
4. 确认后系统自动填充并提交测评
|
||||
|
||||
---
|
||||
|
||||
## 报告管理
|
||||
|
||||
### 功能说明
|
||||
|
||||
报告管理用于查看、编辑、导出测评报告。
|
||||
|
||||
### 查看报告列表
|
||||
|
||||
1. 进入 **心理测评管理** → **测评报告**
|
||||
2. 查看报告列表,可以按条件搜索:
|
||||
- 报告标题
|
||||
- 被测评人
|
||||
- 量表名称
|
||||
- 生成状态
|
||||
- 创建时间
|
||||
|
||||
### 查看报告详情
|
||||
|
||||
1. 在报告列表中,点击 **"查看"** 按钮
|
||||
2. 查看报告详细内容:
|
||||
- 基本信息
|
||||
- 测评结果
|
||||
- 因子分析
|
||||
- 结果解释
|
||||
- 建议指导
|
||||
|
||||
### 编辑报告
|
||||
|
||||
1. 在报告列表中,点击 **"编辑"** 按钮
|
||||
2. 修改报告内容:
|
||||
- 解释标题
|
||||
- 解释内容
|
||||
- 建议指导
|
||||
3. 点击 **"确定"** 保存
|
||||
|
||||
### 导出报告
|
||||
|
||||
1. 勾选需要导出的报告(可多选)
|
||||
2. 点击 **"导出"** 按钮
|
||||
3. 系统生成Excel文件并下载
|
||||
|
||||
---
|
||||
|
||||
## 问卷管理
|
||||
|
||||
### 功能说明
|
||||
|
||||
问卷管理用于创建自定义问卷,支持多种题型,适合在线考试、练习等场景。
|
||||
|
||||
### 创建问卷
|
||||
|
||||
1. 进入 **心理测评管理** → **问卷管理**
|
||||
2. 点击 **"新增"** 按钮
|
||||
3. 填写问卷信息:
|
||||
- **问卷名称**:问卷标题
|
||||
- **问卷描述**:问卷说明
|
||||
- **问卷类型**:选择类型
|
||||
- **状态**:正常/停用
|
||||
4. 点击 **"确定"** 保存
|
||||
|
||||
### 添加题目
|
||||
|
||||
1. 在问卷列表中,点击 **"题目管理"** 按钮
|
||||
2. 点击 **"新增"** 添加题目
|
||||
3. 选择题目类型:
|
||||
- **单选题**:只有一个正确答案
|
||||
- **多选题**:可以有多个正确答案
|
||||
- **判断题**:对/错
|
||||
- **填空题**:文本输入
|
||||
- **简答题**:短文本回答
|
||||
- **问答题**:长文本回答
|
||||
- **作文题**:长文本回答
|
||||
4. 填写题目信息:
|
||||
- **题目内容**:题目文字
|
||||
- **题目分值**:该题分数
|
||||
- **是否必答**:是/否
|
||||
- **正确答案**:客观题的正确答案
|
||||
5. 保存题目
|
||||
|
||||
### 主观题评分
|
||||
|
||||
1. 进入 **心理测评管理** → **主观题评分**
|
||||
2. 查看待评分题目列表
|
||||
3. 点击 **"评分"** 按钮
|
||||
4. 输入得分和评语(可选)
|
||||
5. 点击 **"确定"** 保存
|
||||
|
||||
### 批量评分
|
||||
|
||||
1. 勾选多个待评分题目
|
||||
2. 点击 **"批量评分"** 按钮
|
||||
3. 为每个题目输入得分和评语
|
||||
4. 点击 **"确定"** 批量保存
|
||||
|
||||
---
|
||||
|
||||
## 预警管理
|
||||
|
||||
### 功能说明
|
||||
|
||||
预警管理用于配置预警规则,当测评结果异常时自动向管理员发出警告。
|
||||
|
||||
### 配置预警规则
|
||||
|
||||
1. 进入 **心理测评管理** → **预警规则配置**
|
||||
2. 点击 **"新增"** 按钮
|
||||
3. 填写预警规则信息:
|
||||
- **量表**:选择量表
|
||||
- **因子**:选择因子(可选)
|
||||
- **规则名称**:如"重度抑郁预警"
|
||||
- **预警等级**:低/中/高/紧急
|
||||
- **分数下限/上限**:触发预警的分数范围
|
||||
- **百分位下限/上限**:触发预警的百分位范围
|
||||
- **自动解除**:是否自动解除预警
|
||||
- **解除条件**:自动解除的条件
|
||||
- **状态**:正常/停用
|
||||
4. 点击 **"确定"** 保存
|
||||
|
||||
### 查看预警信息
|
||||
|
||||
1. 进入 **心理测评管理** → **预警管理**
|
||||
2. 查看预警列表,可以按条件筛选:
|
||||
- 预警等级
|
||||
- 量表名称
|
||||
- 被测评人
|
||||
- 预警状态
|
||||
- 创建时间
|
||||
|
||||
### 处理预警
|
||||
|
||||
- **查看详情**:点击预警记录查看详细信息
|
||||
- **解除预警**:手动解除预警
|
||||
- **导出预警**:导出预警数据
|
||||
|
||||
---
|
||||
|
||||
## 二维码管理
|
||||
|
||||
### 功能说明
|
||||
|
||||
二维码管理用于生成和管理测评二维码,方便用户通过扫码快速访问测评和查看报告。
|
||||
|
||||
### 生成量表测评二维码
|
||||
|
||||
1. 进入 **心理测评管理** → **量表管理**
|
||||
2. 找到目标量表
|
||||
3. 点击 **"二维码"** 按钮
|
||||
4. 系统生成二维码并显示
|
||||
5. 可以下载二维码图片或直接打印
|
||||
|
||||
### 生成报告查看二维码
|
||||
|
||||
1. 进入 **心理测评管理** → **测评报告**
|
||||
2. 找到目标报告
|
||||
3. 点击 **"二维码"** 按钮
|
||||
4. 系统生成二维码
|
||||
|
||||
### 管理二维码
|
||||
|
||||
1. 进入 **心理测评管理** → **二维码管理**
|
||||
2. 查看所有二维码:
|
||||
- 二维码类型
|
||||
- 目标信息
|
||||
- 扫码次数
|
||||
- 状态
|
||||
- 过期时间
|
||||
3. 可以重新生成或删除二维码
|
||||
|
||||
---
|
||||
|
||||
## 用户档案管理
|
||||
|
||||
### 功能说明
|
||||
|
||||
用户档案管理用于管理用户的档案信息,支持自定义档案项目。
|
||||
|
||||
### 查看用户档案
|
||||
|
||||
1. 进入 **心理测评管理** → **用户档案**
|
||||
2. 查看用户档案列表
|
||||
3. 可以按条件搜索用户
|
||||
|
||||
### 编辑用户档案
|
||||
|
||||
1. 在档案列表中,点击 **"编辑"** 按钮
|
||||
2. 修改档案信息:
|
||||
- 基本信息
|
||||
- 自定义字段
|
||||
3. 点击 **"确定"** 保存
|
||||
|
||||
### 自定义档案项目
|
||||
|
||||
1. 进入 **系统管理** → **参数设置**(如支持)
|
||||
2. 配置自定义档案字段
|
||||
3. 保存配置
|
||||
|
||||
---
|
||||
|
||||
## 心理网站管理
|
||||
|
||||
### 功能说明
|
||||
|
||||
心理网站管理用于管理心理教育网站的内容,包括文章、分类、评论等。
|
||||
|
||||
### 管理文章
|
||||
|
||||
1. 进入 **心理测评管理** → **心理网站** → **内容管理**
|
||||
2. 查看文章列表
|
||||
3. 可以新增、编辑、删除文章
|
||||
|
||||
### 管理分类
|
||||
|
||||
1. 进入 **心理测评管理** → **心理网站** → **分类管理**
|
||||
2. 管理文章分类
|
||||
|
||||
### 管理评论
|
||||
|
||||
1. 进入 **心理测评管理** → **心理网站** → **评论管理**
|
||||
2. 查看和管理用户评论
|
||||
|
||||
---
|
||||
|
||||
## 系统设置
|
||||
|
||||
### 角色管理
|
||||
|
||||
1. 进入 **系统管理** → **角色管理**
|
||||
2. 查看和管理系统角色
|
||||
3. 为角色分配菜单权限和按钮权限
|
||||
|
||||
### 菜单管理
|
||||
|
||||
1. 进入 **系统管理** → **菜单管理**
|
||||
2. 查看和管理系统菜单
|
||||
3. 可以新增、编辑、删除菜单
|
||||
|
||||
### 参数设置
|
||||
|
||||
1. 进入 **系统管理** → **参数设置**
|
||||
2. 配置系统参数
|
||||
|
||||
### 字典管理
|
||||
|
||||
1. 进入 **系统管理** → **字典管理**
|
||||
2. 管理系统字典数据
|
||||
|
||||
---
|
||||
|
||||
## 数据导出
|
||||
|
||||
### 量表导出
|
||||
|
||||
1. 进入 **心理测评管理** → **量表管理**
|
||||
2. 勾选需要导出的量表(可多选)
|
||||
3. 点击 **"导出"** 按钮
|
||||
4. 系统生成JSON格式文件并下载
|
||||
|
||||
### 报告导出
|
||||
|
||||
1. 进入 **心理测评管理** → **测评报告**
|
||||
2. 勾选需要导出的报告(可多选)
|
||||
3. 点击 **"导出"** 按钮
|
||||
4. 系统生成Excel格式文件并下载
|
||||
|
||||
### 数据备份
|
||||
|
||||
1. 进入 **系统管理** → **数据备份**(如支持)
|
||||
2. 执行数据备份操作
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q1: 如何导入新量表?
|
||||
|
||||
**A**: 有两种方式:
|
||||
1. **手动创建**:在量表管理中逐个添加题目和选项
|
||||
2. **JSON导入**:准备符合格式的JSON文件,使用导入功能
|
||||
|
||||
详细说明请参考《新量表导入完整操作指南.md》
|
||||
|
||||
### Q2: 用户看不到量表怎么办?
|
||||
|
||||
**A**: 检查以下几点:
|
||||
1. 量表状态是否为"正常"
|
||||
2. 用户是否有量表访问权限
|
||||
3. 权限是否在有效期内
|
||||
4. 刷新浏览器页面
|
||||
|
||||
### Q3: 如何配置预警规则?
|
||||
|
||||
**A**:
|
||||
1. 进入"预警规则配置"
|
||||
2. 选择量表和因子
|
||||
3. 设置分数范围或百分位范围
|
||||
4. 选择预警等级
|
||||
5. 保存规则
|
||||
|
||||
### Q4: 二维码无法访问怎么办?
|
||||
|
||||
**A**: 检查以下几点:
|
||||
1. 二维码是否过期
|
||||
2. 二维码状态是否为"有效"
|
||||
3. 网络连接是否正常
|
||||
4. 系统URL配置是否正确
|
||||
|
||||
### Q5: 如何批量分配用户权限?
|
||||
|
||||
**A**:
|
||||
1. 进入"量表权限管理"
|
||||
2. 点击"新增"
|
||||
3. 选择量表
|
||||
4. 选择角色或部门(不选择用户表示批量分配)
|
||||
5. 设置时间范围
|
||||
6. 保存
|
||||
|
||||
### Q6: 报告生成失败怎么办?
|
||||
|
||||
**A**: 检查以下几点:
|
||||
1. 量表是否配置了结果解释
|
||||
2. 因子计分规则是否正确
|
||||
3. 测评是否已完成
|
||||
4. 查看系统日志错误信息
|
||||
|
||||
### Q7: 如何修改报告内容?
|
||||
|
||||
**A**:
|
||||
1. 进入"测评报告"
|
||||
2. 找到目标报告
|
||||
3. 点击"编辑"按钮
|
||||
4. 修改解释内容或建议指导
|
||||
5. 保存
|
||||
|
||||
---
|
||||
|
||||
## 技术支持
|
||||
|
||||
如遇到问题,请:
|
||||
|
||||
1. 查看系统日志
|
||||
2. 检查浏览器控制台错误
|
||||
3. 参考相关文档
|
||||
4. 联系技术支持
|
||||
|
||||
---
|
||||
|
||||
**最后更新**:2025-01-XX
|
||||
|
||||
Loading…
Reference in New Issue
Block a user