优化
This commit is contained in:
@@ -62,6 +62,11 @@
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
<version>5.2.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.belerweb</groupId>
|
||||
<artifactId>pinyin4j</artifactId>
|
||||
<version>2.5.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-api</artifactId>
|
||||
|
||||
@@ -12,6 +12,11 @@ import com.writeoff.module.expert.model.ExpertBankCardInfo;
|
||||
import com.writeoff.module.expert.model.ExpertInfo;
|
||||
import com.writeoff.module.system.service.DataPermissionService;
|
||||
import com.writeoff.security.AuthContext;
|
||||
import net.sourceforge.pinyin4j.PinyinHelper;
|
||||
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
|
||||
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
|
||||
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
|
||||
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -114,12 +119,31 @@ public class ExpertService {
|
||||
StringBuilder whereClause = new StringBuilder(
|
||||
"WHERE e.tenant_id=" + PLATFORM_TENANT_ID + " AND e.is_deleted=0"
|
||||
);
|
||||
List<Object> countArgs = new ArrayList<>();
|
||||
if (keyword != null && !keyword.trim().isEmpty()) {
|
||||
String kw = keyword.trim().replace("'", "''");
|
||||
whereClause.append(" AND (e.expert_name LIKE '%").append(kw).append("%' OR e.id_no LIKE '%").append(kw).append("%')");
|
||||
}
|
||||
|
||||
com.writeoff.module.system.service.DataPermissionService.DataScope scope = dataPermissionService.resolveCurrentUserScope();
|
||||
if (!scope.isExpertAll()) {
|
||||
boolean hasIdScope = !scope.getExpertIds().isEmpty();
|
||||
boolean hasOwnerScope = scope.isExpertOwnerOnly();
|
||||
if (!hasIdScope && !hasOwnerScope) {
|
||||
return new PageResult<ExpertInfo>(new ArrayList<>(), 0, safePage, safeSize);
|
||||
}
|
||||
whereClause.append(" AND (1=0");
|
||||
if (hasIdScope) {
|
||||
whereClause.append(" OR e.id IN (").append(scope.getExpertIds().stream().map(String::valueOf).collect(Collectors.joining(","))).append(")");
|
||||
}
|
||||
if (hasOwnerScope) {
|
||||
Long userId = AuthContext.userId();
|
||||
if (userId != null) {
|
||||
whereClause.append(" OR e.created_by=").append(userId);
|
||||
}
|
||||
}
|
||||
whereClause.append(")");
|
||||
}
|
||||
|
||||
Integer total = jdbcTemplate.queryForObject(
|
||||
"SELECT COUNT(1) FROM expert e " + whereClause,
|
||||
Integer.class
|
||||
@@ -138,7 +162,6 @@ public class ExpertService {
|
||||
sql.append(whereClause);
|
||||
sql.append(" ORDER BY e.id DESC LIMIT ").append(safeSize).append(" OFFSET ").append(offset);
|
||||
List<ExpertInfo> list = jdbcTemplate.query(sql.toString(), EXPERT_ROW_MAPPER);
|
||||
list = filterByExpertScope(list);
|
||||
List<ExpertInfo> maskedList = new java.util.ArrayList<ExpertInfo>(list.size());
|
||||
for (ExpertInfo item : list) {
|
||||
maskedList.add(maskSensitiveFields(item));
|
||||
@@ -195,11 +218,13 @@ public class ExpertService {
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ExpertInfo create(CreateExpertRequest request) {
|
||||
String idNo = request.getIdNo() == null ? "" : request.getIdNo().trim().toUpperCase();
|
||||
request.setIdNo(idNo);
|
||||
Integer count = jdbcTemplate.queryForObject(
|
||||
"SELECT COUNT(1) FROM expert WHERE tenant_id=? AND id_no=? AND is_deleted=0",
|
||||
Integer.class,
|
||||
PLATFORM_TENANT_ID,
|
||||
request.getIdNo()
|
||||
idNo
|
||||
);
|
||||
if (count != null && count > 0) {
|
||||
throw new BusinessException(10001, "身份证号已存在");
|
||||
@@ -617,11 +642,76 @@ public class ExpertService {
|
||||
name
|
||||
);
|
||||
if (byName.isEmpty()) {
|
||||
throw new BusinessException(10001, label + "不在平台字典内,请先在平台字典中维护");
|
||||
String pinyinCode = getPinyin(name);
|
||||
if (pinyinCode.length() > 40) {
|
||||
pinyinCode = pinyinCode.substring(0, 40);
|
||||
}
|
||||
Integer count = jdbcTemplate.queryForObject(
|
||||
"SELECT COUNT(1) FROM platform_dictionary_item WHERE dict_type=? AND dict_code=?",
|
||||
Integer.class,
|
||||
dictType,
|
||||
pinyinCode
|
||||
);
|
||||
if (count != null && count > 0) {
|
||||
int i = 1;
|
||||
while(true) {
|
||||
String newCode = pinyinCode + "_" + i;
|
||||
if (newCode.length() > 50) {
|
||||
newCode = newCode.substring(newCode.length() - 50);
|
||||
}
|
||||
Integer c = jdbcTemplate.queryForObject(
|
||||
"SELECT COUNT(1) FROM platform_dictionary_item WHERE dict_type=? AND dict_code=?",
|
||||
Integer.class, dictType, newCode
|
||||
);
|
||||
if (c == null || c == 0) {
|
||||
pinyinCode = newCode;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
Integer maxSort = jdbcTemplate.queryForObject(
|
||||
"SELECT MAX(sort_no) FROM platform_dictionary_item WHERE dict_type=?",
|
||||
Integer.class,
|
||||
dictType
|
||||
);
|
||||
int nextSort = (maxSort == null ? 0 : maxSort) + 10;
|
||||
jdbcTemplate.update(
|
||||
"INSERT INTO platform_dictionary_item (dict_type, dict_code, dict_name, sort_no, status, remark, created_by, updated_by) " +
|
||||
"VALUES (?, ?, ?, ?, 'ENABLED', 'Auto-imported', ?, ?)",
|
||||
dictType, pinyinCode, name, nextSort, safeUserId(), safeUserId()
|
||||
);
|
||||
return new DictionaryItem(pinyinCode, name);
|
||||
}
|
||||
return byName.get(0);
|
||||
}
|
||||
|
||||
private String getPinyin(String src) {
|
||||
if (src == null || src.trim().isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
StringBuilder result = new StringBuilder();
|
||||
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
|
||||
format.setCaseType(HanyuPinyinCaseType.UPPERCASE);
|
||||
format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
|
||||
format.setVCharType(HanyuPinyinVCharType.WITH_V);
|
||||
for (char c : src.trim().toCharArray()) {
|
||||
if (Character.toString(c).matches("[\\u4E00-\\u9FA5]+")) {
|
||||
try {
|
||||
String[] pinyins = PinyinHelper.toHanyuPinyinStringArray(c, format);
|
||||
if (pinyins != null && pinyins.length > 0) {
|
||||
result.append(pinyins[0]);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
result.append(c);
|
||||
}
|
||||
} else {
|
||||
result.append(Character.toUpperCase(c));
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private void validateImportExpert(CreateExpertRequest request, Set<String> batchIdNos, Set<String> batchPhones) {
|
||||
if (request == null) {
|
||||
throw new BusinessException(10001, "导入行不能为空");
|
||||
|
||||
+74
-2
@@ -11,6 +11,11 @@ import com.writeoff.module.file.service.OssService;
|
||||
import com.writeoff.module.expert.model.ExpertBankCardInfo;
|
||||
import com.writeoff.module.expert.model.ExpertInfo;
|
||||
import com.writeoff.security.AuthContext;
|
||||
import net.sourceforge.pinyin4j.PinyinHelper;
|
||||
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
|
||||
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
|
||||
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
|
||||
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -188,11 +193,13 @@ public class PlatformExpertService {
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ExpertInfo create(CreateExpertRequest request) {
|
||||
String idNo = request.getIdNo() == null ? "" : request.getIdNo().trim().toUpperCase();
|
||||
request.setIdNo(idNo);
|
||||
Integer count = jdbcTemplate.queryForObject(
|
||||
"SELECT COUNT(1) FROM expert WHERE tenant_id=? AND id_no=? AND is_deleted=0",
|
||||
Integer.class,
|
||||
PLATFORM_TENANT_ID,
|
||||
request.getIdNo()
|
||||
idNo
|
||||
);
|
||||
if (count != null && count > 0) {
|
||||
throw new BusinessException(10001, "身份证号已存在");
|
||||
@@ -614,11 +621,76 @@ public class PlatformExpertService {
|
||||
name
|
||||
);
|
||||
if (byName.isEmpty()) {
|
||||
throw new BusinessException(10001, label + "不在平台字典内,请先在平台字典中维护");
|
||||
String pinyinCode = getPinyin(name);
|
||||
if (pinyinCode.length() > 40) {
|
||||
pinyinCode = pinyinCode.substring(0, 40);
|
||||
}
|
||||
Integer count = jdbcTemplate.queryForObject(
|
||||
"SELECT COUNT(1) FROM platform_dictionary_item WHERE dict_type=? AND dict_code=?",
|
||||
Integer.class,
|
||||
dictType,
|
||||
pinyinCode
|
||||
);
|
||||
if (count != null && count > 0) {
|
||||
int i = 1;
|
||||
while(true) {
|
||||
String newCode = pinyinCode + "_" + i;
|
||||
if (newCode.length() > 50) {
|
||||
newCode = newCode.substring(newCode.length() - 50);
|
||||
}
|
||||
Integer c = jdbcTemplate.queryForObject(
|
||||
"SELECT COUNT(1) FROM platform_dictionary_item WHERE dict_type=? AND dict_code=?",
|
||||
Integer.class, dictType, newCode
|
||||
);
|
||||
if (c == null || c == 0) {
|
||||
pinyinCode = newCode;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
Integer maxSort = jdbcTemplate.queryForObject(
|
||||
"SELECT MAX(sort_no) FROM platform_dictionary_item WHERE dict_type=?",
|
||||
Integer.class,
|
||||
dictType
|
||||
);
|
||||
int nextSort = (maxSort == null ? 0 : maxSort) + 10;
|
||||
jdbcTemplate.update(
|
||||
"INSERT INTO platform_dictionary_item (dict_type, dict_code, dict_name, sort_no, status, remark, created_by, updated_by) " +
|
||||
"VALUES (?, ?, ?, ?, 'ENABLED', 'Auto-imported', ?, ?)",
|
||||
dictType, pinyinCode, name, nextSort, safeUserId(), safeUserId()
|
||||
);
|
||||
return new DictionaryItem(pinyinCode, name);
|
||||
}
|
||||
return byName.get(0);
|
||||
}
|
||||
|
||||
private String getPinyin(String src) {
|
||||
if (src == null || src.trim().isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
StringBuilder result = new StringBuilder();
|
||||
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
|
||||
format.setCaseType(HanyuPinyinCaseType.UPPERCASE);
|
||||
format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
|
||||
format.setVCharType(HanyuPinyinVCharType.WITH_V);
|
||||
for (char c : src.trim().toCharArray()) {
|
||||
if (Character.toString(c).matches("[\\u4E00-\\u9FA5]+")) {
|
||||
try {
|
||||
String[] pinyins = PinyinHelper.toHanyuPinyinStringArray(c, format);
|
||||
if (pinyins != null && pinyins.length > 0) {
|
||||
result.append(pinyins[0]);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
result.append(c);
|
||||
}
|
||||
} else {
|
||||
result.append(Character.toUpperCase(c));
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private DictionaryItem resolveOptionalDictionaryItem(String dictType, String dictCode, String dictName, String label) {
|
||||
boolean hasCode = dictCode != null && !dictCode.trim().isEmpty();
|
||||
boolean hasName = dictName != null && !dictName.trim().isEmpty();
|
||||
|
||||
@@ -172,7 +172,7 @@ public class MeetingController {
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
@RequirePermission(value = "meeting.create", dataScope = DataScopeType.MEETING, auditAction = "MEETING_UPDATE")
|
||||
@RequirePermission(value = "meeting.update", dataScope = DataScopeType.MEETING, auditAction = "MEETING_UPDATE")
|
||||
public ApiResponse<Meeting> update(@PathVariable("id") Long id,
|
||||
@RequestBody @Valid CreateMeetingRequest request) {
|
||||
return ApiResponse.success(meetingService.update(id, request));
|
||||
|
||||
+3
-1
@@ -2050,6 +2050,8 @@ public class MeetingMaterialService {
|
||||
requireMeetingInvoiceAttachmentList(map.get("attachments"));
|
||||
}
|
||||
}
|
||||
} catch (BusinessException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new BusinessException(10001, "资料内容格式错误或缺少必填字段");
|
||||
}
|
||||
@@ -3170,7 +3172,7 @@ public class MeetingMaterialService {
|
||||
}
|
||||
Collection<?> list = (Collection<?>) value;
|
||||
if (list.isEmpty()) {
|
||||
throw new BusinessException(10001, "提交失败,缺少必填字段: invoices");
|
||||
return;
|
||||
}
|
||||
for (Object item : list) {
|
||||
if (!(item instanceof Map)) {
|
||||
|
||||
@@ -230,8 +230,12 @@ public class MeetingService {
|
||||
double cateringRatio = request.getCateringRatio() == null ? project.getCateringFeeRatio() : normalizeRatio(request.getCateringRatio(), "餐费占比");
|
||||
assertMeetingRatiosWithinProject(project, laborRatio, cateringRatio);
|
||||
long defaultBudgetCent = calculateDefaultMeetingBudgetCent(project);
|
||||
if (defaultBudgetCent <= 0L) {
|
||||
throw new BusinessException(ErrorCodes.VALIDATION_ERROR, "默认会议预算必须大于 0");
|
||||
long initialBudgetCent = request.getBudgetCent() != null ? request.getBudgetCent() : defaultBudgetCent;
|
||||
if (!project.isAllowMeetingOverBudget() && initialBudgetCent > defaultBudgetCent) {
|
||||
throw new BusinessException(ErrorCodes.VALIDATION_ERROR, "当前项目不允许会议预算超出默认分配额度");
|
||||
}
|
||||
if (initialBudgetCent <= 0L) {
|
||||
throw new BusinessException(ErrorCodes.VALIDATION_ERROR, "会议预算必须大于 0");
|
||||
}
|
||||
String now = nowIsoSeconds();
|
||||
Meeting meeting = new Meeting(
|
||||
@@ -243,7 +247,7 @@ public class MeetingService {
|
||||
request.getLocation(),
|
||||
request.getStartTime(),
|
||||
request.getEndTime(),
|
||||
defaultBudgetCent,
|
||||
initialBudgetCent,
|
||||
laborRatio,
|
||||
cateringRatio,
|
||||
MeetingStatus.NOT_STARTED,
|
||||
@@ -401,6 +405,15 @@ public class MeetingService {
|
||||
double laborRatio = request.getLaborRatio() == null ? existing.getLaborRatio() : normalizeRatio(request.getLaborRatio(), "劳务占比");
|
||||
double cateringRatio = request.getCateringRatio() == null ? existing.getCateringRatio() : normalizeRatio(request.getCateringRatio(), "餐费占比");
|
||||
assertMeetingRatiosWithinProject(project, laborRatio, cateringRatio);
|
||||
|
||||
long newBudgetCent = request.getBudgetCent() != null ? request.getBudgetCent() : existing.getBudgetCent();
|
||||
if (!project.isAllowMeetingOverBudget() && newBudgetCent > existing.getBudgetCent()) {
|
||||
throw new BusinessException(ErrorCodes.VALIDATION_ERROR, "当前项目不允许调高会议预算");
|
||||
}
|
||||
if (newBudgetCent <= 0L) {
|
||||
throw new BusinessException(ErrorCodes.VALIDATION_ERROR, "会议预算必须大于 0");
|
||||
}
|
||||
|
||||
Meeting updated = new Meeting(
|
||||
existing.getId(),
|
||||
existing.getProjectId(),
|
||||
@@ -410,7 +423,7 @@ public class MeetingService {
|
||||
request.getLocation(),
|
||||
request.getStartTime(),
|
||||
request.getEndTime(),
|
||||
request.getBudgetCent(),
|
||||
newBudgetCent,
|
||||
laborRatio,
|
||||
cateringRatio,
|
||||
existing.getStatus(),
|
||||
|
||||
+22
-2
@@ -144,8 +144,8 @@ public class MeetingSummaryExportService {
|
||||
projectName,
|
||||
queryTenantName(tenantId)
|
||||
);
|
||||
String meetingCategory = stringValue(meeting.get("meeting_category"));
|
||||
String location = stringValue(meeting.get("location"));
|
||||
String meetingCategory = resolveDictName("MEETING_CATEGORY", stringValue(meeting.get("meeting_category")));
|
||||
String location = resolveDictName("MEETING_LOCATION", stringValue(meeting.get("location")));
|
||||
String startTime = stringValue(meeting.get("start_time"));
|
||||
String endTime = stringValue(meeting.get("end_time"));
|
||||
String guestCountText = formatNumber(basicInfo.get("guestCount"));
|
||||
@@ -240,6 +240,26 @@ public class MeetingSummaryExportService {
|
||||
}
|
||||
}
|
||||
|
||||
private String resolveDictName(String dictType, String dictCode) {
|
||||
if (dictCode == null || dictCode.trim().isEmpty()) {
|
||||
return dictCode;
|
||||
}
|
||||
try {
|
||||
List<String> names = jdbcTemplate.queryForList(
|
||||
"SELECT dict_name FROM platform_dictionary_item WHERE dict_type=? AND dict_code=? AND is_deleted=0 LIMIT 1",
|
||||
String.class,
|
||||
dictType,
|
||||
dictCode
|
||||
);
|
||||
if (!names.isEmpty() && names.get(0) != null) {
|
||||
return names.get(0);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// ignore
|
||||
}
|
||||
return dictCode;
|
||||
}
|
||||
|
||||
private List<Long> parseIdList(Object value) {
|
||||
if (!(value instanceof List)) {
|
||||
return Collections.emptyList();
|
||||
|
||||
@@ -93,9 +93,9 @@ public class UserController {
|
||||
|
||||
@PostMapping("/{id}/reset-password")
|
||||
@RequirePermission(value = "user.password.reset", dataScope = DataScopeType.TENANT, auditAction = "USER_RESET_PASSWORD")
|
||||
public ApiResponse<String> resetPassword(@PathVariable("id") Long id, @RequestBody @Valid ResetPasswordRequest request) {
|
||||
systemUserService.resetPassword(id, request);
|
||||
return ApiResponse.success("OK");
|
||||
public ApiResponse<String> resetPassword(@PathVariable("id") Long id) {
|
||||
systemUserService.resetPassword(id);
|
||||
return ApiResponse.success("密码已重置");
|
||||
}
|
||||
|
||||
@GetMapping("/{id}/role-history")
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.writeoff.module.system.model.UserRoleHistory;
|
||||
import com.writeoff.security.AuthContext;
|
||||
import com.writeoff.security.PasswordCodecService;
|
||||
import com.writeoff.security.PasswordPolicyService;
|
||||
import com.writeoff.security.PasswordSetupService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
@@ -55,7 +56,9 @@ public class SystemUserService {
|
||||
private final PasswordPolicyService passwordPolicyService;
|
||||
private final PasswordCodecService passwordCodecService;
|
||||
private final TransactionTemplate transactionTemplate;
|
||||
private final PasswordSetupService passwordSetupService;
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
private final String frontendBaseUrl;
|
||||
|
||||
private static final RowMapper<SystemUser> USER_ROW_MAPPER = (rs, n) -> new SystemUser(
|
||||
rs.getLong("id"),
|
||||
@@ -97,13 +100,17 @@ public class SystemUserService {
|
||||
NotificationDispatchService notificationDispatchService,
|
||||
PasswordPolicyService passwordPolicyService,
|
||||
PasswordCodecService passwordCodecService,
|
||||
PlatformTransactionManager transactionManager) {
|
||||
PlatformTransactionManager transactionManager,
|
||||
PasswordSetupService passwordSetupService,
|
||||
@org.springframework.beans.factory.annotation.Value("${app.frontend-base-url:http://localhost:5173}") String frontendBaseUrl) {
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
this.dataPermissionService = dataPermissionService;
|
||||
this.notificationDispatchService = notificationDispatchService;
|
||||
this.passwordPolicyService = passwordPolicyService;
|
||||
this.passwordCodecService = passwordCodecService;
|
||||
this.transactionTemplate = new TransactionTemplate(transactionManager);
|
||||
this.passwordSetupService = passwordSetupService;
|
||||
this.frontendBaseUrl = frontendBaseUrl;
|
||||
}
|
||||
|
||||
public PageResult<SystemUser> listUsers(int pageNo, int pageSize, Boolean includeDeleted) {
|
||||
@@ -179,10 +186,8 @@ public class SystemUserService {
|
||||
final String phone = request.getPhone() == null ? "" : request.getPhone().trim();
|
||||
final String email = request.getEmail() == null ? "" : request.getEmail().trim();
|
||||
final String rawPassword = request.getPassword() == null ? "" : request.getPassword().trim();
|
||||
if (rawPassword.isEmpty()) {
|
||||
throw new BusinessException(10001, "\u5bc6\u7801\u4e0d\u80fd\u4e3a\u7a7a");
|
||||
}
|
||||
passwordPolicyService.validate(rawPassword);
|
||||
final String finalPassword = rawPassword.isEmpty() ? ("Tmp@" + java.util.UUID.randomUUID().toString().replace("-", "").substring(0, 8) + "aA1") : rawPassword;
|
||||
passwordPolicyService.validate(finalPassword);
|
||||
final String validFrom = request.getValidFrom() == null || request.getValidFrom().trim().isEmpty()
|
||||
? LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
|
||||
: normalizeDateTimeString(request.getValidFrom());
|
||||
@@ -191,7 +196,7 @@ public class SystemUserService {
|
||||
: normalizeDateTimeString(request.getValidTo());
|
||||
return transactionTemplate.execute(status -> {
|
||||
assertPhoneAvailable(phone, null);
|
||||
String passwordHash = passwordCodecService.encode(rawPassword);
|
||||
String passwordHash = passwordCodecService.encode(finalPassword);
|
||||
String tenantSwitchAccountKey = resolveTenantSwitchAccountKeyByPhone(phone, null);
|
||||
KeyHolder keyHolder = new GeneratedKeyHolder();
|
||||
jdbcTemplate.update(connection -> {
|
||||
@@ -217,7 +222,8 @@ public class SystemUserService {
|
||||
}, keyHolder);
|
||||
Long id = keyHolder.getKey() == null ? null : keyHolder.getKey().longValue();
|
||||
autoAssignExecutorRoleWhenCreatorIsProjectExecutor(id);
|
||||
sendUserCreatedMail(id, userName, phone, email, validFrom, validTo);
|
||||
String setupLink = passwordSetupService.issueUserSetupLink(tenantId(), id, safeUserId());
|
||||
sendUserCreatedMail(id, userName, phone, email, finalPassword, validFrom, validTo, setupLink);
|
||||
return new SystemUser(id, userName, phone, email, "ENABLED", validFrom, validTo, "", "");
|
||||
});
|
||||
}
|
||||
@@ -248,8 +254,8 @@ public class SystemUserService {
|
||||
ps.setTimestamp(idx++, validTo == null ? Timestamp.valueOf(LocalDateTime.of(2099, 12, 31, 23, 59, 59)) : validTo);
|
||||
ps.setLong(idx++, operator);
|
||||
if (request.getPassword() != null && !request.getPassword().trim().isEmpty()) {
|
||||
passwordPolicyService.validate(request.getPassword());
|
||||
ps.setString(idx++, passwordCodecService.encode(request.getPassword()));
|
||||
passwordPolicyService.validate(request.getPassword().trim());
|
||||
ps.setString(idx++, passwordCodecService.encode(request.getPassword().trim()));
|
||||
}
|
||||
ps.setLong(idx++, tenantId());
|
||||
ps.setLong(idx, userId);
|
||||
@@ -413,14 +419,54 @@ public class SystemUserService {
|
||||
);
|
||||
}
|
||||
|
||||
public void resetPassword(Long userId, ResetPasswordRequest request) {
|
||||
public void resetPassword(Long userId) {
|
||||
assertUserExists(userId);
|
||||
passwordPolicyService.validate(request.getNewPassword());
|
||||
jdbcTemplate.update(
|
||||
"UPDATE sys_user SET password_hash=?, updated_at=CURRENT_TIMESTAMP WHERE id=?",
|
||||
passwordCodecService.encode(request.getNewPassword()),
|
||||
|
||||
SystemUser user = jdbcTemplate.queryForObject(
|
||||
"SELECT id, user_name, phone, email, status, valid_from, valid_to FROM sys_user WHERE tenant_id=? AND id=? AND is_deleted=0 LIMIT 1",
|
||||
(rs, rowNum) -> new SystemUser(
|
||||
rs.getLong("id"),
|
||||
rs.getString("user_name"),
|
||||
rs.getString("phone"),
|
||||
rs.getString("email"),
|
||||
rs.getString("status"),
|
||||
rs.getString("valid_from"),
|
||||
rs.getString("valid_to")
|
||||
),
|
||||
tenantId(),
|
||||
userId
|
||||
);
|
||||
|
||||
String setupLink = passwordSetupService.issueUserSetupLink(tenantId(), userId, safeUserId());
|
||||
|
||||
List<Map<String, Object>> tenants = jdbcTemplate.queryForList(
|
||||
"SELECT tenant_code, tenant_name FROM tenant WHERE id=? LIMIT 1",
|
||||
tenantId()
|
||||
);
|
||||
String tenantCode = tenants.isEmpty() ? "" : String.valueOf(tenants.get(0).get("tenant_code"));
|
||||
String tenantName = tenants.isEmpty() ? "" : String.valueOf(tenants.get(0).get("tenant_name"));
|
||||
|
||||
Map<String, Object> variables = new LinkedHashMap<String, Object>();
|
||||
variables.put("userId", userId);
|
||||
variables.put("targetUserId", userId);
|
||||
variables.put("userName", user.getUserName());
|
||||
variables.put("phone", user.getPhone());
|
||||
variables.put("email", user.getEmail());
|
||||
variables.put("tenantCode", tenantCode);
|
||||
variables.put("tenantName", tenantName);
|
||||
variables.put("setupLink", setupLink);
|
||||
|
||||
DispatchNotificationRequest dispatchRequest = new DispatchNotificationRequest();
|
||||
dispatchRequest.setIdempotencyKey("user-password-reset-" + tenantId() + "-" + userId + "-" + System.currentTimeMillis());
|
||||
dispatchRequest.setEventCode("USER_PASSWORD_RESET");
|
||||
dispatchRequest.setBizType("USER");
|
||||
dispatchRequest.setBizId("user-" + userId);
|
||||
try {
|
||||
dispatchRequest.setVariablesJson(objectMapper.writeValueAsString(variables));
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to write variables json", e);
|
||||
}
|
||||
notificationDispatchService.dispatch(dispatchRequest);
|
||||
}
|
||||
|
||||
public void changeMyPassword(Long userId, String oldPassword, String newPassword) {
|
||||
@@ -707,8 +753,8 @@ public class SystemUserService {
|
||||
if (item.getUserName() == null || item.getUserName().trim().isEmpty()) {
|
||||
throw new BusinessException(10001, "用户名不能为空");
|
||||
}
|
||||
if (item.getPassword() == null || item.getPassword().trim().isEmpty()) {
|
||||
throw new BusinessException(10001, "密码不能为空");
|
||||
if (item.getPassword() != null && !item.getPassword().trim().isEmpty()) {
|
||||
passwordPolicyService.validate(item.getPassword().trim());
|
||||
}
|
||||
ImportValidationUtils.validatePhone(item.getPhone());
|
||||
ImportValidationUtils.validateRequiredEmail(item.getEmail());
|
||||
@@ -717,7 +763,6 @@ public class SystemUserService {
|
||||
if (!batchPhones.add(phone)) {
|
||||
throw new BusinessException(10001, "批次内手机号重复");
|
||||
}
|
||||
passwordPolicyService.validate(item.getPassword().trim());
|
||||
String roleCode = ImportValidationUtils.trim(item.getRoleCode());
|
||||
if (roleCode.isEmpty()) {
|
||||
return null;
|
||||
@@ -750,7 +795,7 @@ public class SystemUserService {
|
||||
: ex.getMessage();
|
||||
}
|
||||
|
||||
private void sendUserCreatedMail(Long userId, String userName, String phone, String email, String validFrom, String validTo) {
|
||||
private void sendUserCreatedMail(Long userId, String userName, String phone, String email, String rawPassword, String validFrom, String validTo, String setupLink) {
|
||||
if (userId == null || userId <= 0) {
|
||||
return;
|
||||
}
|
||||
@@ -761,18 +806,26 @@ public class SystemUserService {
|
||||
);
|
||||
String tenantCode = tenants.isEmpty() ? "" : String.valueOf(tenants.get(0).get("tenant_code"));
|
||||
String tenantName = tenants.isEmpty() ? "" : String.valueOf(tenants.get(0).get("tenant_name"));
|
||||
String loginPath = "/" + tenantCode + "/login";
|
||||
String baseUrl = frontendBaseUrl == null ? "" : frontendBaseUrl;
|
||||
while (baseUrl.endsWith("/")) {
|
||||
baseUrl = baseUrl.substring(0, baseUrl.length() - 1);
|
||||
}
|
||||
String loginPath = baseUrl.isEmpty() ? "/" + tenantCode + "/login" : baseUrl + "/" + tenantCode + "/login";
|
||||
String displayValidTo = (validTo != null && validTo.contains("2099-12-31")) ? "长期有效" : validTo;
|
||||
|
||||
Map<String, Object> variables = new LinkedHashMap<String, Object>();
|
||||
variables.put("userId", userId);
|
||||
variables.put("targetUserId", userId);
|
||||
variables.put("userName", userName);
|
||||
variables.put("phone", phone);
|
||||
variables.put("email", email);
|
||||
variables.put("password", rawPassword);
|
||||
variables.put("validFrom", validFrom);
|
||||
variables.put("validTo", validTo);
|
||||
variables.put("validTo", displayValidTo);
|
||||
variables.put("tenantCode", tenantCode);
|
||||
variables.put("tenantName", tenantName);
|
||||
variables.put("loginPath", loginPath);
|
||||
variables.put("loginPath", setupLink != null ? setupLink : loginPath);
|
||||
variables.put("setupLink", setupLink != null ? setupLink : "");
|
||||
DispatchNotificationRequest request = new DispatchNotificationRequest();
|
||||
request.setIdempotencyKey("user-created-" + tenantId() + "-" + userId);
|
||||
request.setEventCode("USER_CREATED");
|
||||
|
||||
@@ -270,7 +270,8 @@ public class TenantService {
|
||||
);
|
||||
|
||||
String setupLink = passwordSetupService.issueTenantAdminSetupLink(tenantId, uid, safeUserId());
|
||||
sendTenantAdminMail(tenantId, request, action, setupLink);
|
||||
// 移除了发送邮件功能
|
||||
// sendTenantAdminMail(tenantId, request, action, setupLink);
|
||||
|
||||
java.util.Map<String, Object> data = new java.util.LinkedHashMap<String, Object>();
|
||||
data.put("tenantId", tenantId);
|
||||
@@ -278,6 +279,7 @@ public class TenantService {
|
||||
data.put("roleId", roleId);
|
||||
data.put("roleCode", roleCode);
|
||||
data.put("action", action);
|
||||
data.put("setupLink", setupLink);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
+23
-13
@@ -39,11 +39,23 @@ public class TemplateController {
|
||||
@RequestParam(value = "status", required = false) String status,
|
||||
@RequestParam(value = "scopeType", required = false) String scopeType,
|
||||
@RequestParam(value = "bizScene", required = false) String bizScene,
|
||||
@RequestParam(value = "watermarkEnabled", required = false) Boolean watermarkEnabled,
|
||||
@RequestParam(value = "effectiveStatus", required = false) String effectiveStatus,
|
||||
@RequestParam(value = "pageNo", defaultValue = "1") int pageNo,
|
||||
@RequestParam(value = "pageSize", defaultValue = "20") int pageSize) {
|
||||
return ApiResponse.success(templateService.list(templateName, templateType, status, scopeType, bizScene, watermarkEnabled, effectiveStatus, pageNo, pageSize));
|
||||
return ApiResponse.success(templateService.list(templateName, templateType, status, scopeType, bizScene, effectiveStatus, pageNo, pageSize));
|
||||
}
|
||||
|
||||
@GetMapping("/view-list")
|
||||
@RequirePermission(value = "template.read", dataScope = DataScopeType.TENANT, auditAction = "TEMPLATE_VIEW_LIST")
|
||||
public ApiResponse<PageResult<TemplateInfo>> viewList(
|
||||
@RequestParam(value = "templateName", required = false) String templateName,
|
||||
@RequestParam(value = "templateType", required = false) String templateType,
|
||||
@RequestParam(value = "scopeType", required = false) String scopeType,
|
||||
@RequestParam(value = "bizScene", required = false) String bizScene,
|
||||
@RequestParam(value = "effectiveStatus", required = false) String effectiveStatus,
|
||||
@RequestParam(value = "pageNo", defaultValue = "1") int pageNo,
|
||||
@RequestParam(value = "pageSize", defaultValue = "20") int pageSize) {
|
||||
return ApiResponse.success(templateService.listView(templateName, templateType, scopeType, bizScene, effectiveStatus, pageNo, pageSize));
|
||||
}
|
||||
|
||||
@GetMapping("/published-options")
|
||||
@@ -98,6 +110,12 @@ public class TemplateController {
|
||||
return ApiResponse.success(templateService.create(request));
|
||||
}
|
||||
|
||||
@PostMapping("/{id}/update")
|
||||
@RequirePermission(value = "template.update", dataScope = DataScopeType.TENANT, auditAction = "TEMPLATE_UPDATE")
|
||||
public ApiResponse<TemplateInfo> update(@PathVariable("id") Long id, @RequestBody @Valid com.writeoff.module.template.dto.UpdateTemplateRequest request) {
|
||||
return ApiResponse.success(templateService.update(id, request));
|
||||
}
|
||||
|
||||
@PostMapping("/upload-sign")
|
||||
@RequirePermission(value = "template.create", dataScope = DataScopeType.TENANT, auditAction = "TEMPLATE_UPLOAD_SIGN")
|
||||
public ApiResponse<Map<String, Object>> uploadSign(@RequestBody @Valid TemplateUploadSignRequest request) {
|
||||
@@ -105,7 +123,7 @@ public class TemplateController {
|
||||
}
|
||||
|
||||
@GetMapping("/{id}/versions")
|
||||
@RequirePermission(value = "template.read", dataScope = DataScopeType.TENANT, auditAction = "TEMPLATE_VERSIONS")
|
||||
@RequirePermission(value = "template.detail.read", dataScope = DataScopeType.TENANT, auditAction = "TEMPLATE_VERSIONS")
|
||||
public ApiResponse<List<TemplateVersionInfo>> versions(@PathVariable("id") Long id) {
|
||||
return ApiResponse.success(templateService.versions(id));
|
||||
}
|
||||
@@ -148,16 +166,10 @@ public class TemplateController {
|
||||
return ApiResponse.success(templateService.download(id, request.getRemoteAddr(), request.getHeader("User-Agent")));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}/download-watermark")
|
||||
@RequirePermission(value = "template.download", dataScope = DataScopeType.TENANT, auditAction = "TEMPLATE_DOWNLOAD_WATERMARK")
|
||||
public ApiResponse<Map<String, Object>> downloadWatermark(@PathVariable("id") Long id,
|
||||
@RequestParam(value = "watermarkText", required = false) String watermarkText,
|
||||
HttpServletRequest request) {
|
||||
return ApiResponse.success(templateService.downloadWatermark(id, watermarkText, request.getRemoteAddr(), request.getHeader("User-Agent")));
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/{id}/versions/diff")
|
||||
@RequirePermission(value = "template.read", dataScope = DataScopeType.TENANT, auditAction = "TEMPLATE_VERSION_DIFF")
|
||||
@RequirePermission(value = "template.detail.read", dataScope = DataScopeType.TENANT, auditAction = "TEMPLATE_VERSION_DIFF")
|
||||
public ApiResponse<Map<String, Object>> versionDiff(@PathVariable("id") Long id,
|
||||
@RequestParam(value = "leftVersionNo", required = false) Integer leftVersionNo,
|
||||
@RequestParam(value = "rightVersionNo", required = false) Integer rightVersionNo) {
|
||||
@@ -172,7 +184,6 @@ public class TemplateController {
|
||||
@RequestParam(value = "userId", required = false) Long userId,
|
||||
@RequestParam(value = "userKeyword", required = false) String userKeyword,
|
||||
@RequestParam(value = "versionNo", required = false) Integer versionNo,
|
||||
@RequestParam(value = "downloadType", required = false) String downloadType,
|
||||
@RequestParam(value = "ip", required = false) String ip,
|
||||
@RequestParam(value = "downloadedFrom", required = false) String downloadedFrom,
|
||||
@RequestParam(value = "downloadedTo", required = false) String downloadedTo,
|
||||
@@ -184,7 +195,6 @@ public class TemplateController {
|
||||
userId,
|
||||
userKeyword,
|
||||
versionNo,
|
||||
downloadType,
|
||||
ip,
|
||||
downloadedFrom,
|
||||
downloadedTo,
|
||||
|
||||
@@ -18,7 +18,6 @@ public class CreateTemplateRequest {
|
||||
private String changeLog;
|
||||
private String effectiveFrom;
|
||||
private String effectiveTo;
|
||||
private Boolean watermarkEnabled;
|
||||
private Integer downloadRateLimitPerHour;
|
||||
|
||||
public String getTemplateName() {
|
||||
@@ -109,13 +108,6 @@ public class CreateTemplateRequest {
|
||||
this.effectiveTo = effectiveTo;
|
||||
}
|
||||
|
||||
public Boolean getWatermarkEnabled() {
|
||||
return watermarkEnabled;
|
||||
}
|
||||
|
||||
public void setWatermarkEnabled(Boolean watermarkEnabled) {
|
||||
this.watermarkEnabled = watermarkEnabled;
|
||||
}
|
||||
|
||||
public Integer getDownloadRateLimitPerHour() {
|
||||
return downloadRateLimitPerHour;
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
package com.writeoff.module.template.dto;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
public class UpdateTemplateRequest {
|
||||
@NotBlank(message = "模板名称不能为空")
|
||||
private String templateName;
|
||||
@NotBlank(message = "模板类型不能为空")
|
||||
private String templateType;
|
||||
@NotBlank(message = "适用范围不能为空")
|
||||
private String scopeType;
|
||||
private Long projectId;
|
||||
private Long meetingId;
|
||||
private Long scopeId;
|
||||
private String bizScene;
|
||||
private String effectiveFrom;
|
||||
private String effectiveTo;
|
||||
private Integer downloadRateLimitPerHour;
|
||||
|
||||
public String getTemplateName() {
|
||||
return templateName;
|
||||
}
|
||||
|
||||
public void setTemplateName(String templateName) {
|
||||
this.templateName = templateName;
|
||||
}
|
||||
|
||||
public String getTemplateType() {
|
||||
return templateType;
|
||||
}
|
||||
|
||||
public void setTemplateType(String templateType) {
|
||||
this.templateType = templateType;
|
||||
}
|
||||
|
||||
public String getScopeType() {
|
||||
return scopeType;
|
||||
}
|
||||
|
||||
public void setScopeType(String scopeType) {
|
||||
this.scopeType = scopeType;
|
||||
}
|
||||
|
||||
public Long getProjectId() {
|
||||
return projectId;
|
||||
}
|
||||
|
||||
public void setProjectId(Long projectId) {
|
||||
this.projectId = projectId;
|
||||
}
|
||||
|
||||
public Long getMeetingId() {
|
||||
return meetingId;
|
||||
}
|
||||
|
||||
public void setMeetingId(Long meetingId) {
|
||||
this.meetingId = meetingId;
|
||||
}
|
||||
|
||||
public Long getScopeId() {
|
||||
return scopeId;
|
||||
}
|
||||
|
||||
public void setScopeId(Long scopeId) {
|
||||
this.scopeId = scopeId;
|
||||
}
|
||||
|
||||
public String getBizScene() {
|
||||
return bizScene;
|
||||
}
|
||||
|
||||
public void setBizScene(String bizScene) {
|
||||
this.bizScene = bizScene;
|
||||
}
|
||||
|
||||
public String getEffectiveFrom() {
|
||||
return effectiveFrom;
|
||||
}
|
||||
|
||||
public void setEffectiveFrom(String effectiveFrom) {
|
||||
this.effectiveFrom = effectiveFrom;
|
||||
}
|
||||
|
||||
public String getEffectiveTo() {
|
||||
return effectiveTo;
|
||||
}
|
||||
|
||||
public void setEffectiveTo(String effectiveTo) {
|
||||
this.effectiveTo = effectiveTo;
|
||||
}
|
||||
|
||||
|
||||
public Integer getDownloadRateLimitPerHour() {
|
||||
return downloadRateLimitPerHour;
|
||||
}
|
||||
|
||||
public void setDownloadRateLimitPerHour(Integer downloadRateLimitPerHour) {
|
||||
this.downloadRateLimitPerHour = downloadRateLimitPerHour;
|
||||
}
|
||||
}
|
||||
+2
-6
@@ -10,7 +10,6 @@ public class TemplateDownloadLogInfo {
|
||||
private String userPhone;
|
||||
private String objectKey;
|
||||
private String downloadType;
|
||||
private String watermarkText;
|
||||
private Long projectId;
|
||||
private Long meetingId;
|
||||
private String ip;
|
||||
@@ -18,7 +17,7 @@ public class TemplateDownloadLogInfo {
|
||||
private String downloadedAt;
|
||||
|
||||
public TemplateDownloadLogInfo(Long id, Long templateId, String templateName, Integer versionNo, Long userId, String userName, String userPhone,
|
||||
String objectKey, String downloadType, String watermarkText, Long projectId, Long meetingId,
|
||||
String objectKey, String downloadType, Long projectId, Long meetingId,
|
||||
String ip, String userAgent, String downloadedAt) {
|
||||
this.id = id;
|
||||
this.templateId = templateId;
|
||||
@@ -29,7 +28,6 @@ public class TemplateDownloadLogInfo {
|
||||
this.userPhone = userPhone;
|
||||
this.objectKey = objectKey;
|
||||
this.downloadType = downloadType;
|
||||
this.watermarkText = watermarkText;
|
||||
this.projectId = projectId;
|
||||
this.meetingId = meetingId;
|
||||
this.ip = ip;
|
||||
@@ -73,9 +71,7 @@ public class TemplateDownloadLogInfo {
|
||||
return downloadType;
|
||||
}
|
||||
|
||||
public String getWatermarkText() {
|
||||
return watermarkText;
|
||||
}
|
||||
|
||||
|
||||
public Long getProjectId() {
|
||||
return projectId;
|
||||
|
||||
@@ -14,13 +14,12 @@ public class TemplateInfo {
|
||||
private String currentObjectKey;
|
||||
private String effectiveFrom;
|
||||
private String effectiveTo;
|
||||
private Boolean watermarkEnabled;
|
||||
private Integer downloadRateLimitPerHour;
|
||||
private String createdAt;
|
||||
private String updatedAt;
|
||||
|
||||
public TemplateInfo(Long id, String templateName, String templateType, String scopeType, Long projectId, Long meetingId, Long scopeId, String bizScene,
|
||||
String status, Integer currentVersionNo, String currentObjectKey, String effectiveFrom, String effectiveTo, Boolean watermarkEnabled, Integer downloadRateLimitPerHour,
|
||||
String status, Integer currentVersionNo, String currentObjectKey, String effectiveFrom, String effectiveTo, Integer downloadRateLimitPerHour,
|
||||
String createdAt, String updatedAt) {
|
||||
this.id = id;
|
||||
this.templateName = templateName;
|
||||
@@ -35,7 +34,6 @@ public class TemplateInfo {
|
||||
this.currentObjectKey = currentObjectKey;
|
||||
this.effectiveFrom = effectiveFrom;
|
||||
this.effectiveTo = effectiveTo;
|
||||
this.watermarkEnabled = watermarkEnabled;
|
||||
this.downloadRateLimitPerHour = downloadRateLimitPerHour;
|
||||
this.createdAt = createdAt;
|
||||
this.updatedAt = updatedAt;
|
||||
@@ -93,9 +91,6 @@ public class TemplateInfo {
|
||||
return effectiveTo;
|
||||
}
|
||||
|
||||
public Boolean getWatermarkEnabled() {
|
||||
return watermarkEnabled;
|
||||
}
|
||||
|
||||
public Integer getDownloadRateLimitPerHour() {
|
||||
return downloadRateLimitPerHour;
|
||||
|
||||
@@ -59,7 +59,6 @@ public class TemplateService {
|
||||
rs.getString("current_object_key"),
|
||||
rs.getString("effective_from"),
|
||||
rs.getString("effective_to"),
|
||||
rs.getInt("watermark_enabled") == 1,
|
||||
rs.getInt("download_rate_limit_per_hour"),
|
||||
rs.getString("created_at"),
|
||||
rs.getString("updated_at")
|
||||
@@ -86,7 +85,6 @@ public class TemplateService {
|
||||
rs.getString("user_phone"),
|
||||
rs.getString("object_key"),
|
||||
rs.getString("download_type"),
|
||||
rs.getString("watermark_text"),
|
||||
rs.getObject("project_id") == null ? null : rs.getLong("project_id"),
|
||||
rs.getObject("meeting_id") == null ? null : rs.getLong("meeting_id"),
|
||||
rs.getString("ip"),
|
||||
@@ -114,7 +112,6 @@ public class TemplateService {
|
||||
String status,
|
||||
String scopeType,
|
||||
String bizScene,
|
||||
Boolean watermarkEnabled,
|
||||
String effectiveStatus,
|
||||
int pageNo,
|
||||
int pageSize) {
|
||||
@@ -150,10 +147,7 @@ public class TemplateService {
|
||||
whereSql.append(" AND t.biz_scene=?");
|
||||
whereArgs.add(normalizedBizScene);
|
||||
}
|
||||
if (watermarkEnabled != null) {
|
||||
whereSql.append(" AND t.watermark_enabled=?");
|
||||
whereArgs.add(Boolean.TRUE.equals(watermarkEnabled) ? 1 : 0);
|
||||
}
|
||||
|
||||
appendEffectiveStatusFilter(whereSql, normalizedEffectiveStatus);
|
||||
|
||||
Integer total = jdbcTemplate.queryForObject(
|
||||
@@ -176,6 +170,16 @@ public class TemplateService {
|
||||
return new PageResult<>(list, totalCount, safePage, safeSize);
|
||||
}
|
||||
|
||||
public PageResult<TemplateInfo> listView(String templateName,
|
||||
String templateType,
|
||||
String scopeType,
|
||||
String bizScene,
|
||||
String effectiveStatus,
|
||||
int pageNo,
|
||||
int pageSize) {
|
||||
return list(templateName, templateType, "PUBLISHED", scopeType, bizScene, effectiveStatus, pageNo, pageSize);
|
||||
}
|
||||
|
||||
public List<TemplateInfo> listPublishedOptions(String bizScene) {
|
||||
String normalizedBizScene = normalizeOptionalBizScene(bizScene);
|
||||
StringBuilder sql = new StringBuilder(templateSelectSql())
|
||||
@@ -248,8 +252,8 @@ public class TemplateService {
|
||||
KeyHolder keyHolder = new GeneratedKeyHolder();
|
||||
jdbcTemplate.update(connection -> {
|
||||
PreparedStatement ps = connection.prepareStatement(
|
||||
"INSERT INTO template (tenant_id, template_name, template_type, scope_type, project_id, meeting_id, scope_id, biz_scene, status, current_version_no, effective_from, effective_to, watermark_enabled, download_rate_limit_per_hour, created_by, updated_by) " +
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'DRAFT', 1, STR_TO_DATE(?, '%Y-%m-%d %H:%i:%s'), STR_TO_DATE(?, '%Y-%m-%d %H:%i:%s'), ?, ?, ?, ?)",
|
||||
"INSERT INTO template (tenant_id, template_name, template_type, scope_type, project_id, meeting_id, scope_id, biz_scene, status, current_version_no, effective_from, effective_to, download_rate_limit_per_hour, created_by, updated_by) " +
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'DRAFT', 1, STR_TO_DATE(?, '%Y-%m-%d %H:%i:%s'), STR_TO_DATE(?, '%Y-%m-%d %H:%i:%s'), ?, ?, ?)",
|
||||
Statement.RETURN_GENERATED_KEYS
|
||||
);
|
||||
ps.setLong(1, tenantId());
|
||||
@@ -262,10 +266,9 @@ public class TemplateService {
|
||||
ps.setString(8, normalizeBizScene(request.getBizScene()));
|
||||
ps.setString(9, effectiveFrom);
|
||||
ps.setString(10, effectiveTo);
|
||||
ps.setInt(11, Boolean.TRUE.equals(request.getWatermarkEnabled()) ? 1 : 0);
|
||||
ps.setInt(12, downloadRateLimitPerHour);
|
||||
ps.setInt(11, downloadRateLimitPerHour);
|
||||
ps.setLong(12, userId);
|
||||
ps.setLong(13, userId);
|
||||
ps.setLong(14, userId);
|
||||
return ps;
|
||||
}, keyHolder);
|
||||
Long templateId = keyHolder.getKey() == null ? null : keyHolder.getKey().longValue();
|
||||
@@ -282,6 +285,36 @@ public class TemplateService {
|
||||
return findById(validTemplateId);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public TemplateInfo update(Long templateId, com.writeoff.module.template.dto.UpdateTemplateRequest request) {
|
||||
TemplateInfo template = findById(templateId);
|
||||
assertTemplateEditable(template);
|
||||
String scopeType = normalizeScope(request.getScopeType());
|
||||
String templateType = normalizeTemplateType(request.getTemplateType());
|
||||
String effectiveFrom = normalizeOptionalDateTime(request.getEffectiveFrom(), "effectiveFrom");
|
||||
String effectiveTo = normalizeOptionalDateTime(request.getEffectiveTo(), "effectiveTo");
|
||||
Integer downloadRateLimitPerHour = normalizeDownloadRateLimit(request.getDownloadRateLimitPerHour());
|
||||
assertEffectiveRangeValid(effectiveFrom, effectiveTo);
|
||||
assertTypeOptionEnabled(templateType);
|
||||
jdbcTemplate.update(
|
||||
"UPDATE template SET template_name=?, template_type=?, scope_type=?, project_id=?, meeting_id=?, scope_id=?, biz_scene=?, effective_from=STR_TO_DATE(?, '%Y-%m-%d %H:%i:%s'), effective_to=STR_TO_DATE(?, '%Y-%m-%d %H:%i:%s'), download_rate_limit_per_hour=?, updated_by=?, updated_at=CURRENT_TIMESTAMP WHERE tenant_id=? AND id=?",
|
||||
request.getTemplateName(),
|
||||
templateType,
|
||||
scopeType,
|
||||
request.getProjectId(),
|
||||
request.getMeetingId(),
|
||||
request.getScopeId(),
|
||||
normalizeBizScene(request.getBizScene()),
|
||||
effectiveFrom,
|
||||
effectiveTo,
|
||||
downloadRateLimitPerHour,
|
||||
safeUserId(),
|
||||
tenantId(),
|
||||
templateId
|
||||
);
|
||||
return findById(templateId);
|
||||
}
|
||||
|
||||
public List<TemplateVersionInfo> versions(Long templateId) {
|
||||
assertTemplateExists(templateId);
|
||||
return jdbcTemplate.query(
|
||||
@@ -451,15 +484,14 @@ public class TemplateService {
|
||||
assertTemplateEffectiveNow(template, "下载");
|
||||
assertDownloadRateLimit(template, userId);
|
||||
jdbcTemplate.update(
|
||||
"INSERT INTO template_download_log (tenant_id, template_id, version_no, user_id, object_key, download_type, watermark_text, project_id, meeting_id, ip, user_agent) " +
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
"INSERT INTO template_download_log (tenant_id, template_id, version_no, user_id, object_key, download_type, project_id, meeting_id, ip, user_agent) " +
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
tenantId(),
|
||||
template.getId(),
|
||||
template.getCurrentVersionNo(),
|
||||
userId,
|
||||
template.getCurrentObjectKey(),
|
||||
"NORMAL",
|
||||
null,
|
||||
template.getProjectId(),
|
||||
template.getMeetingId(),
|
||||
ip,
|
||||
@@ -473,46 +505,6 @@ public class TemplateService {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Map<String, Object> downloadWatermark(Long templateId, String watermarkText, String ip, String userAgent) {
|
||||
TemplateInfo template = findById(templateId);
|
||||
if ("DISABLED".equalsIgnoreCase(template.getStatus()) || "ARCHIVED".equalsIgnoreCase(template.getStatus())) {
|
||||
throw new BusinessException(10003, "模板已停用,无法下载");
|
||||
}
|
||||
if (template.getCurrentObjectKey() == null || template.getCurrentObjectKey().trim().isEmpty()) {
|
||||
throw new BusinessException(10003, "模板当前版本文件不存在");
|
||||
}
|
||||
String signedUrl = ossService.generateDownloadUrl(template.getCurrentObjectKey());
|
||||
Long userId = safeUserId();
|
||||
assertTemplateDownloadAllowed(template);
|
||||
if (!template.getWatermarkEnabled()) {
|
||||
throw new BusinessException(10003, "模板未启用水印下载");
|
||||
}
|
||||
assertTemplateEffectiveNow(template, "水印下载");
|
||||
assertDownloadRateLimit(template, userId);
|
||||
jdbcTemplate.update(
|
||||
"INSERT INTO template_download_log (tenant_id, template_id, version_no, user_id, object_key, download_type, watermark_text, project_id, meeting_id, ip, user_agent) " +
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
tenantId(),
|
||||
template.getId(),
|
||||
template.getCurrentVersionNo(),
|
||||
userId,
|
||||
template.getCurrentObjectKey(),
|
||||
"WATERMARK",
|
||||
watermarkText == null ? null : watermarkText.trim(),
|
||||
template.getProjectId(),
|
||||
template.getMeetingId(),
|
||||
ip,
|
||||
userAgent
|
||||
);
|
||||
Map<String, Object> result = new LinkedHashMap<String, Object>();
|
||||
result.put("templateId", template.getId());
|
||||
result.put("versionNo", template.getCurrentVersionNo());
|
||||
result.put("objectKey", template.getCurrentObjectKey());
|
||||
result.put("signedUrl", signedUrl);
|
||||
result.put("watermarkText", watermarkText == null ? "" : watermarkText.trim());
|
||||
return result;
|
||||
}
|
||||
|
||||
public Map<String, Object> versionDiff(Long templateId, Integer leftVersionNo, Integer rightVersionNo) {
|
||||
assertTemplateExists(templateId);
|
||||
@@ -548,7 +540,6 @@ public class TemplateService {
|
||||
Long userId,
|
||||
String userKeyword,
|
||||
Integer versionNo,
|
||||
String downloadType,
|
||||
String ip,
|
||||
String downloadedFrom,
|
||||
String downloadedTo,
|
||||
@@ -559,7 +550,6 @@ public class TemplateService {
|
||||
int offset = (safePage - 1) * safeSize;
|
||||
String normalizedTemplateName = trimToNull(templateName);
|
||||
String normalizedUserKeyword = trimToNull(userKeyword);
|
||||
String normalizedDownloadType = normalizeOptionalDownloadType(downloadType);
|
||||
String normalizedIp = trimToNull(ip);
|
||||
String normalizedDownloadedFrom = trimToNull(downloadedFrom);
|
||||
String normalizedDownloadedTo = trimToNull(downloadedTo);
|
||||
@@ -598,10 +588,7 @@ public class TemplateService {
|
||||
whereSql.append(" AND l.version_no=?");
|
||||
whereArgs.add(versionNo);
|
||||
}
|
||||
if (normalizedDownloadType != null) {
|
||||
whereSql.append(" AND l.download_type=?");
|
||||
whereArgs.add(normalizedDownloadType);
|
||||
}
|
||||
|
||||
if (normalizedIp != null) {
|
||||
whereSql.append(" AND l.ip LIKE ?");
|
||||
whereArgs.add("%" + normalizedIp + "%");
|
||||
@@ -628,7 +615,7 @@ public class TemplateService {
|
||||
List<TemplateDownloadLogInfo> list = jdbcTemplate.query(
|
||||
"SELECT l.id, l.template_id, COALESCE(t.template_name, '') AS template_name, " +
|
||||
"l.version_no, l.user_id, COALESCE(u.user_name, '') AS user_name, COALESCE(u.phone, '') AS user_phone, " +
|
||||
"l.object_key, l.download_type, COALESCE(l.watermark_text, '') AS watermark_text, " +
|
||||
"l.object_key, l.download_type, " +
|
||||
"l.project_id, l.meeting_id, l.ip, l.user_agent, DATE_FORMAT(l.downloaded_at, '%Y-%m-%d %H:%i:%s') AS downloaded_at" +
|
||||
whereSql +
|
||||
" ORDER BY l.downloaded_at DESC, l.id DESC LIMIT ? OFFSET ?",
|
||||
@@ -709,7 +696,7 @@ public class TemplateService {
|
||||
"t.current_version_no, tv.object_key AS current_object_key, " +
|
||||
"DATE_FORMAT(t.effective_from, '%Y-%m-%d %H:%i:%s') AS effective_from, " +
|
||||
"DATE_FORMAT(t.effective_to, '%Y-%m-%d %H:%i:%s') AS effective_to, " +
|
||||
"t.watermark_enabled, t.download_rate_limit_per_hour, " +
|
||||
"t.download_rate_limit_per_hour, " +
|
||||
"DATE_FORMAT(t.created_at, '%Y-%m-%d %H:%i:%s') AS created_at, " +
|
||||
"DATE_FORMAT(t.updated_at, '%Y-%m-%d %H:%i:%s') AS updated_at " +
|
||||
"FROM template t " +
|
||||
@@ -806,17 +793,7 @@ public class TemplateService {
|
||||
return normalized;
|
||||
}
|
||||
|
||||
private String normalizeOptionalDownloadType(String downloadType) {
|
||||
String value = trimToNull(downloadType);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
String normalized = value.toUpperCase();
|
||||
if (!"NORMAL".equals(normalized) && !"WATERMARK".equals(normalized)) {
|
||||
throw new BusinessException(10003, "downloadType仅支持NORMAL/WATERMARK");
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
|
||||
private String normalizeContentType(String contentType) {
|
||||
if (contentType == null || contentType.trim().isEmpty()) {
|
||||
@@ -936,7 +913,7 @@ public class TemplateService {
|
||||
|
||||
private void assertTemplateEditable(TemplateInfo template) {
|
||||
if ("ARCHIVED".equalsIgnoreCase(template.getStatus())) {
|
||||
throw new BusinessException(10003, "已归档模板不允许新增版本");
|
||||
throw new BusinessException(10003, "已归档模板不允许编辑或新增版本");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.util.Map;
|
||||
@Service
|
||||
public class PasswordSetupService {
|
||||
private static final String SCENARIO_TENANT_ADMIN_SETUP = "TENANT_ADMIN_SETUP";
|
||||
private static final String SCENARIO_USER_SETUP = "USER_SETUP";
|
||||
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
@@ -71,6 +72,36 @@ public class PasswordSetupService {
|
||||
return buildSetupLink(tenantCode, rawToken);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public String issueUserSetupLink(Long tenantId, Long userId, Long operatorUserId) {
|
||||
Map<String, Object> user = loadSystemUser(tenantId, userId);
|
||||
String tenantCode = String.valueOf(user.get("tenant_code"));
|
||||
jdbcTemplate.update(
|
||||
"UPDATE auth_password_setup_token " +
|
||||
"SET is_deleted=1, updated_by=?, updated_at=CURRENT_TIMESTAMP " +
|
||||
"WHERE tenant_id=? AND user_id=? AND scenario=? AND is_deleted=0 AND used_at IS NULL",
|
||||
safeOperator(operatorUserId),
|
||||
tenantId,
|
||||
userId,
|
||||
SCENARIO_USER_SETUP
|
||||
);
|
||||
|
||||
String rawToken = generateToken();
|
||||
LocalDateTime expiresAt = LocalDateTime.now().plusMinutes(Math.max(passwordSetupExpireMinutes, 10L));
|
||||
jdbcTemplate.update(
|
||||
"INSERT INTO auth_password_setup_token (tenant_id, user_id, scenario, token_hash, expires_at, created_by, updated_by) " +
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||
tenantId,
|
||||
userId,
|
||||
SCENARIO_USER_SETUP,
|
||||
hashToken(rawToken),
|
||||
Timestamp.valueOf(expiresAt),
|
||||
safeOperator(operatorUserId),
|
||||
safeOperator(operatorUserId)
|
||||
);
|
||||
return buildSetupLink(tenantCode, rawToken);
|
||||
}
|
||||
|
||||
public Map<String, Object> verifyTenantPasswordSetupToken(String tenantCode, String rawToken) {
|
||||
Map<String, Object> tokenRecord = loadAvailableTokenRecord(tenantCode, rawToken);
|
||||
Map<String, Object> data = new LinkedHashMap<String, Object>();
|
||||
@@ -112,11 +143,12 @@ public class PasswordSetupService {
|
||||
jdbcTemplate.update(
|
||||
"UPDATE auth_password_setup_token " +
|
||||
"SET is_deleted=1, updated_by=?, updated_at=CURRENT_TIMESTAMP " +
|
||||
"WHERE tenant_id=? AND user_id=? AND scenario=? AND id<>? AND is_deleted=0 AND used_at IS NULL",
|
||||
"WHERE tenant_id=? AND user_id=? AND scenario IN (?, ?) AND id<>? AND is_deleted=0 AND used_at IS NULL",
|
||||
userId,
|
||||
tenantId,
|
||||
userId,
|
||||
SCENARIO_TENANT_ADMIN_SETUP,
|
||||
SCENARIO_USER_SETUP,
|
||||
tokenId
|
||||
);
|
||||
|
||||
@@ -139,11 +171,12 @@ public class PasswordSetupService {
|
||||
"FROM auth_password_setup_token tkn " +
|
||||
"JOIN tenant t ON tkn.tenant_id=t.id " +
|
||||
"JOIN sys_user u ON tkn.user_id=u.id AND tkn.tenant_id=u.tenant_id " +
|
||||
"WHERE tkn.token_hash=? AND tkn.scenario=? AND tkn.is_deleted=0 " +
|
||||
"WHERE tkn.token_hash=? AND tkn.scenario IN (?, ?) AND tkn.is_deleted=0 " +
|
||||
"AND t.is_deleted=0 AND u.is_deleted=0 " +
|
||||
"LIMIT 1",
|
||||
hashToken(normalizedToken),
|
||||
SCENARIO_TENANT_ADMIN_SETUP
|
||||
SCENARIO_TENANT_ADMIN_SETUP,
|
||||
SCENARIO_USER_SETUP
|
||||
);
|
||||
if (rows.isEmpty()) {
|
||||
throw new BusinessException(10001, "设置链接无效或已过期");
|
||||
@@ -181,6 +214,22 @@ public class PasswordSetupService {
|
||||
return rows.get(0);
|
||||
}
|
||||
|
||||
private Map<String, Object> loadSystemUser(Long tenantId, Long userId) {
|
||||
List<Map<String, Object>> rows = jdbcTemplate.queryForList(
|
||||
"SELECT u.id, u.tenant_id, t.tenant_code " +
|
||||
"FROM sys_user u " +
|
||||
"JOIN tenant t ON u.tenant_id=t.id " +
|
||||
"WHERE u.tenant_id=? AND u.id=? AND u.is_deleted=0 AND t.is_deleted=0 " +
|
||||
"LIMIT 1",
|
||||
tenantId,
|
||||
userId
|
||||
);
|
||||
if (rows.isEmpty()) {
|
||||
throw new BusinessException(10003, "用户不存在");
|
||||
}
|
||||
return rows.get(0);
|
||||
}
|
||||
|
||||
private String buildSetupLink(String tenantCode, String rawToken) {
|
||||
String baseUrl = normalizeBaseUrl(frontendBaseUrl);
|
||||
String path = "/" + tenantCode + "/setup-password?token=" + urlEncode(rawToken);
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
-- 添加模板编辑权限
|
||||
INSERT INTO permission (id, permission_code, permission_name, module)
|
||||
SELECT t.next_id, 'template.update', '编辑模板', 'template'
|
||||
FROM (SELECT IFNULL(MAX(id), 0) + 1 AS next_id FROM permission) t
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM permission WHERE permission_code = 'template.update'
|
||||
);
|
||||
|
||||
-- 授予角色编辑模板权限(通常跟随 template.create 一起授权)
|
||||
-- 找出所有拥有 template.create 权限的角色,给他们也加上 template.update 权限
|
||||
SET @next_rp_id = (SELECT IFNULL(MAX(id), 0) FROM role_permission);
|
||||
|
||||
INSERT INTO role_permission (id, tenant_id, role_id, permission_id)
|
||||
SELECT
|
||||
(@next_rp_id := @next_rp_id + 1) AS id,
|
||||
rp.tenant_id,
|
||||
rp.role_id,
|
||||
p.id
|
||||
FROM role_permission rp
|
||||
JOIN permission source_p ON source_p.id = rp.permission_id AND source_p.permission_code = 'template.create'
|
||||
JOIN permission p ON p.permission_code = 'template.update'
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM role_permission existing_rp
|
||||
WHERE existing_rp.tenant_id = rp.tenant_id
|
||||
AND existing_rp.role_id = rp.role_id
|
||||
AND existing_rp.permission_id = p.id
|
||||
);
|
||||
@@ -0,0 +1,51 @@
|
||||
-- 添加查看详情和水印下载权限
|
||||
INSERT INTO permission (id, permission_code, permission_name, module)
|
||||
SELECT t.next_id, 'template.detail.read', '查看模板详情', 'template'
|
||||
FROM (SELECT IFNULL(MAX(id), 0) + 1 AS next_id FROM permission) t
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM permission WHERE permission_code = 'template.detail.read'
|
||||
);
|
||||
|
||||
INSERT INTO permission (id, permission_code, permission_name, module)
|
||||
SELECT t.next_id, 'template.watermark.download', '水印下载模板', 'template'
|
||||
FROM (SELECT IFNULL(MAX(id), 0) + 1 AS next_id FROM permission) t
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM permission WHERE permission_code = 'template.watermark.download'
|
||||
);
|
||||
|
||||
-- 授予角色新权限(继承现有权限)
|
||||
SET @next_rp_id = (SELECT IFNULL(MAX(id), 0) FROM role_permission);
|
||||
|
||||
-- 给有 template.read 的加上 template.detail.read
|
||||
INSERT INTO role_permission (id, tenant_id, role_id, permission_id)
|
||||
SELECT
|
||||
(@next_rp_id := @next_rp_id + 1) AS id,
|
||||
rp.tenant_id,
|
||||
rp.role_id,
|
||||
p.id
|
||||
FROM role_permission rp
|
||||
JOIN permission source_p ON source_p.id = rp.permission_id AND source_p.permission_code = 'template.read'
|
||||
JOIN permission p ON p.permission_code = 'template.detail.read'
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM role_permission existing_rp
|
||||
WHERE existing_rp.tenant_id = rp.tenant_id
|
||||
AND existing_rp.role_id = rp.role_id
|
||||
AND existing_rp.permission_id = p.id
|
||||
);
|
||||
|
||||
-- 给有 template.download 的加上 template.watermark.download
|
||||
INSERT INTO role_permission (id, tenant_id, role_id, permission_id)
|
||||
SELECT
|
||||
(@next_rp_id := @next_rp_id + 1) AS id,
|
||||
rp.tenant_id,
|
||||
rp.role_id,
|
||||
p.id
|
||||
FROM role_permission rp
|
||||
JOIN permission source_p ON source_p.id = rp.permission_id AND source_p.permission_code = 'template.download'
|
||||
JOIN permission p ON p.permission_code = 'template.watermark.download'
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM role_permission existing_rp
|
||||
WHERE existing_rp.tenant_id = rp.tenant_id
|
||||
AND existing_rp.role_id = rp.role_id
|
||||
AND existing_rp.permission_id = p.id
|
||||
);
|
||||
@@ -0,0 +1,7 @@
|
||||
-- 移除水印相关字段
|
||||
ALTER TABLE template DROP COLUMN watermark_enabled;
|
||||
ALTER TABLE template_download_log DROP COLUMN watermark_text;
|
||||
|
||||
-- 删除之前新增的 template.watermark.download 权限
|
||||
DELETE FROM role_permission WHERE permission_id IN (SELECT id FROM permission WHERE permission_code = 'template.watermark.download');
|
||||
DELETE FROM permission WHERE permission_code = 'template.watermark.download';
|
||||
@@ -0,0 +1,27 @@
|
||||
SET @next_permission_id := (SELECT IFNULL(MAX(id), 0) + 1 FROM permission);
|
||||
INSERT INTO permission (id, permission_code, permission_name, module)
|
||||
SELECT @next_permission_id, 'meeting.update', '编辑会议', 'meeting'
|
||||
FROM dual
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM permission
|
||||
WHERE permission_code = 'meeting.update'
|
||||
);
|
||||
|
||||
SET @next_role_permission_id := (SELECT IFNULL(MAX(id), 0) FROM role_permission);
|
||||
INSERT INTO role_permission (id, tenant_id, role_id, permission_id)
|
||||
SELECT
|
||||
(@next_role_permission_id := @next_role_permission_id + 1) AS id,
|
||||
rp.tenant_id,
|
||||
rp.role_id,
|
||||
p.id AS permission_id
|
||||
FROM role_permission rp
|
||||
JOIN permission source_p ON source_p.id = rp.permission_id AND source_p.permission_code = 'meeting.create'
|
||||
JOIN permission p ON p.permission_code = 'meeting.update'
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM role_permission exist_rp
|
||||
WHERE exist_rp.tenant_id = rp.tenant_id
|
||||
AND exist_rp.role_id = rp.role_id
|
||||
AND exist_rp.permission_id = p.id
|
||||
);
|
||||
Binary file not shown.
Reference in New Issue
Block a user