feat: 租户配额、家长重置密码及重置密码弹窗优化

- 租户配额: 实现 PUT /admin/tenants/:id/quota 更新逻辑,修复回显老值问题
- 家长重置密码: 改为后端生成临时密码并返回,与教师/租户接口一致
- 重置密码弹窗: 确认按钮文案改为「重置」,新密码区域字体改为白色

Made-with: Cursor
This commit is contained in:
zhonghua 2026-03-23 16:55:01 +08:00
parent 354071b6a3
commit cb737a43e5
8 changed files with 84 additions and 9 deletions

View File

@ -308,7 +308,7 @@
</a-drawer>
<!-- 重置密码确认模态框 -->
<a-modal v-model:open="resetPasswordVisible" @ok="confirmResetPassword" :confirm-loading="resetting" :width="400">
<a-modal v-model:open="resetPasswordVisible" @ok="confirmResetPassword" :confirm-loading="resetting" :width="400" okText="重置">
<template #title>
<span class="modal-title">
<KeyOutlined class="modal-title-icon" />
@ -871,6 +871,15 @@ onMounted(() => {
color: white;
}
.password-display :deep(.ant-typography),
.password-display :deep(.ant-typography-copy) {
color: white !important;
}
.password-display :deep(.ant-typography-copy-icon) {
color: rgba(255, 255, 255, 0.85);
}
/* Modal title styling */
.modal-title {
display: flex;

View File

@ -275,7 +275,7 @@
</a-modal>
<!-- 重置密码确认模态框 -->
<a-modal v-model:open="resetPasswordVisible" @ok="confirmResetPassword" :confirm-loading="resetting" :width="400">
<a-modal v-model:open="resetPasswordVisible" @ok="confirmResetPassword" :confirm-loading="resetting" :width="400" okText="重置">
<template #title>
<span class="modal-title">
<KeyOutlined class="modal-title-icon" />
@ -1027,6 +1027,15 @@ onMounted(() => {
color: white;
}
.password-display :deep(.ant-typography),
.password-display :deep(.ant-typography-copy) {
color: white !important;
}
.password-display :deep(.ant-typography-copy-icon) {
color: rgba(255, 255, 255, 0.85);
}
/* Modal title styling */
.modal-title {
display: flex;

View File

@ -176,7 +176,7 @@
</a-modal>
<!-- 重置密码确认模态框 -->
<a-modal v-model:open="resetPasswordVisible" @ok="confirmResetPassword" :confirm-loading="resetting" :width="400">
<a-modal v-model:open="resetPasswordVisible" @ok="confirmResetPassword" :confirm-loading="resetting" :width="400" okText="重置">
<template #title>
<span class="modal-title">
<KeyOutlined class="modal-title-icon" />
@ -778,6 +778,15 @@ onMounted(() => {
color: white;
}
.password-display :deep(.ant-typography),
.password-display :deep(.ant-typography-copy) {
color: white !important;
}
.password-display :deep(.ant-typography-copy-icon) {
color: rgba(255, 255, 255, 0.85);
}
/* Modal title styling */
.modal-title {
display: flex;

View File

@ -7,6 +7,7 @@ import com.reading.platform.common.response.PageResult;
import com.reading.platform.common.response.Result;
import com.reading.platform.dto.request.TenantCreateRequest;
import com.reading.platform.dto.request.TenantUpdateRequest;
import com.reading.platform.dto.request.UpdateTenantQuotaRequest;
import com.reading.platform.dto.response.TenantResponse;
import com.reading.platform.entity.Tenant;
import com.reading.platform.entity.TenantPackage;
@ -105,9 +106,14 @@ public class AdminTenantController {
@Operation(summary = "更新租户配额")
@PutMapping("/{id}/quota")
public Result<TenantResponse> updateTenantQuota(@PathVariable Long id, @RequestBody Map<String, Object> quota) {
// TODO: 实现更新租户配额逻辑
Tenant tenant = tenantService.getTenantById(id);
public Result<TenantResponse> updateTenantQuota(
@PathVariable Long id,
@RequestBody UpdateTenantQuotaRequest request) {
TenantUpdateRequest updateRequest = new TenantUpdateRequest();
updateRequest.setCollectionIds(request.getCollectionIds());
updateRequest.setTeacherQuota(request.getTeacherQuota());
updateRequest.setStudentQuota(request.getStudentQuota());
Tenant tenant = tenantService.updateTenant(id, updateRequest);
return Result.success(toResponse(tenant));
}

View File

@ -88,10 +88,10 @@ public class SchoolParentController {
@Operation(summary = "Reset parent password")
@PostMapping("/{id}/reset-password")
public Result<Void> resetPassword(@PathVariable Long id, @RequestParam String newPassword) {
public Result<java.util.Map<String, String>> resetPassword(@PathVariable Long id) {
Long tenantId = SecurityUtils.getCurrentTenantId();
parentService.resetPasswordWithTenantCheck(id, tenantId, newPassword);
return Result.success();
String tempPassword = parentService.resetPasswordAndReturnTemp(id, tenantId);
return Result.success(java.util.Map.of("tempPassword", tempPassword));
}
@Operation(summary = "Bind student to parent")

View File

@ -0,0 +1,23 @@
package com.reading.platform.dto.request;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
/**
* 更新租户配额请求
*/
@Data
@Schema(description = "更新租户配额请求")
public class UpdateTenantQuotaRequest {
@Schema(description = "课程套餐 ID 列表collectionIds")
private List<Long> collectionIds;
@Schema(description = "教师配额")
private Integer teacherQuota;
@Schema(description = "学生配额")
private Integer studentQuota;
}

View File

@ -62,6 +62,11 @@ public interface ParentService extends com.baomidou.mybatisplus.extension.servic
*/
void resetPasswordWithTenantCheck(Long id, Long tenantId, String newPassword);
/**
* 重置密码并返回临时密码带租户验证
*/
String resetPasswordAndReturnTemp(Long id, Long tenantId);
/**
* 绑定学生
*/

View File

@ -19,6 +19,8 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import java.util.UUID;
/**
* 家长服务实现类
*/
@ -190,6 +192,18 @@ public class ParentServiceImpl extends com.baomidou.mybatisplus.extension.servic
resetPassword(id, newPassword);
}
@Override
@Transactional
public String resetPasswordAndReturnTemp(Long id, Long tenantId) {
log.info("开始重置密码并返回临时密码ID: {}, tenantId: {}", id, tenantId);
Parent parent = getParentByIdWithTenantCheck(id, tenantId);
String tempPassword = UUID.randomUUID().toString().replace("-", "").substring(0, 8);
parent.setPassword(passwordEncoder.encode(tempPassword));
parentMapper.updateById(parent);
log.info("家长密码重置成功ID: {}", id);
return tempPassword;
}
@Override
@Transactional
public void bindStudentWithTenantCheck(Long parentId, Long studentId, Long tenantId, String relationship, Boolean isPrimary) {