集成钉钉
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package com.rj;
|
package com.rj;
|
||||||
|
|
||||||
import com.rj.config.AmapProperties;
|
import com.rj.config.AmapProperties;
|
||||||
|
import com.rj.config.LbAssessmentDingTalkProperties;
|
||||||
import com.rj.config.YihangyiVllmAsrProperties;
|
import com.rj.config.YihangyiVllmAsrProperties;
|
||||||
import org.mybatis.spring.annotation.MapperScan;
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
@@ -40,7 +41,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
|
|||||||
@MapperScan("com.rj.mapper")
|
@MapperScan("com.rj.mapper")
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@EnableScheduling
|
@EnableScheduling
|
||||||
@EnableConfigurationProperties({YihangyiVllmAsrProperties.class, AmapProperties.class})
|
@EnableConfigurationProperties({YihangyiVllmAsrProperties.class, AmapProperties.class, LbAssessmentDingTalkProperties.class})
|
||||||
public class AISmartCard20251230Application {
|
public class AISmartCard20251230Application {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.rj.config;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 申请评估 - 钉钉群机器人 Webhook 配置。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ConfigurationProperties(prefix = "lb.assessment-apply.dingtalk")
|
||||||
|
public class LbAssessmentDingTalkProperties {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否启用钉钉发送。
|
||||||
|
*/
|
||||||
|
private boolean enabled = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义机器人 Webhook 中的 access_token。
|
||||||
|
*/
|
||||||
|
private String accessToken = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加签密钥(SEC 开头);未配置则不加签。
|
||||||
|
*/
|
||||||
|
private String secret = "";
|
||||||
|
}
|
||||||
@@ -110,7 +110,7 @@ public class LbAssessmentApplyController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/notificationText")
|
@GetMapping("/notificationText")
|
||||||
@Operation(summary = "生成评估会议通知文案", description = "根据租户ID与记录ID查询申请评估记录,拼接并返回格式化通知文本")
|
@Operation(summary = "生成评估会议通知文案", description = "根据租户ID与记录ID查询申请评估记录,拼接通知文本并写入 notification_text 字段后返回")
|
||||||
public ResponseEntity<Map<String, Object>> getNotificationText(
|
public ResponseEntity<Map<String, Object>> getNotificationText(
|
||||||
@Parameter(description = "租户ID", required = true) @RequestParam String tenantId,
|
@Parameter(description = "租户ID", required = true) @RequestParam String tenantId,
|
||||||
@Parameter(description = "申请评估记录ID(UUID)", required = true) @RequestParam String id) {
|
@Parameter(description = "申请评估记录ID(UUID)", required = true) @RequestParam String id) {
|
||||||
@@ -122,6 +122,19 @@ public class LbAssessmentApplyController {
|
|||||||
return ResponseEntity.badRequest().body(result);
|
return ResponseEntity.badRequest().body(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/sendNotificationToDingTalk")
|
||||||
|
@Operation(summary = "发送评估会议通知到钉钉群", description = "根据租户ID与记录ID查询申请评估记录,将 notification_text 发送至配置的钉钉群机器人")
|
||||||
|
public ResponseEntity<Map<String, Object>> sendNotificationToDingTalk(
|
||||||
|
@Parameter(description = "租户ID", required = true) @RequestParam String tenantId,
|
||||||
|
@Parameter(description = "申请评估记录ID(UUID)", required = true) @RequestParam String id) {
|
||||||
|
Map<String, Object> result = lbAssessmentApplyService.sendNotificationTextToDingTalk(tenantId, id);
|
||||||
|
Boolean success = (Boolean) result.get("success");
|
||||||
|
if (success != null && success) {
|
||||||
|
return ResponseEntity.ok(result);
|
||||||
|
}
|
||||||
|
return ResponseEntity.badRequest().body(result);
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/export")
|
@GetMapping("/export")
|
||||||
@Operation(summary = "导出申请评估Excel", description = "按租户ID与申请日期时间范围导出申请评估列表")
|
@Operation(summary = "导出申请评估Excel", description = "按租户ID与申请日期时间范围导出申请评估列表")
|
||||||
public void export(
|
public void export(
|
||||||
|
|||||||
@@ -70,6 +70,10 @@ public class LbAssessmentApply implements Serializable {
|
|||||||
@Schema(description = "会议号")
|
@Schema(description = "会议号")
|
||||||
private String meetingNumber;
|
private String meetingNumber;
|
||||||
|
|
||||||
|
@TableField("notification_text")
|
||||||
|
@Schema(description = "评估会议通知文案")
|
||||||
|
private String notificationText;
|
||||||
|
|
||||||
@TableField("application_datetime")
|
@TableField("application_datetime")
|
||||||
@Schema(description = "申请日期时间")
|
@Schema(description = "申请日期时间")
|
||||||
private LocalDateTime applicationDatetime;
|
private LocalDateTime applicationDatetime;
|
||||||
|
|||||||
14
src/main/java/com/rj/service/DingTalkRobotService.java
Normal file
14
src/main/java/com/rj/service/DingTalkRobotService.java
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package com.rj.service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 钉钉自定义机器人(群消息)发送。
|
||||||
|
*/
|
||||||
|
public interface DingTalkRobotService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向配置的钉钉群发送文本消息。
|
||||||
|
*
|
||||||
|
* @param content 消息正文
|
||||||
|
*/
|
||||||
|
void sendText(String content);
|
||||||
|
}
|
||||||
@@ -41,4 +41,9 @@ public interface ILbAssessmentApplyService extends IService<LbAssessmentApply> {
|
|||||||
*/
|
*/
|
||||||
Map<String, Object> buildAssessmentNotificationText(String tenantId, String id);
|
Map<String, Object> buildAssessmentNotificationText(String tenantId, String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据租户ID与记录ID查询申请评估记录,将 notification_text 发送至钉钉群。
|
||||||
|
*/
|
||||||
|
Map<String, Object> sendNotificationTextToDingTalk(String tenantId, String id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
110
src/main/java/com/rj/service/impl/DingTalkRobotServiceImpl.java
Normal file
110
src/main/java/com/rj/service/impl/DingTalkRobotServiceImpl.java
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
package com.rj.service.impl;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.rj.config.LbAssessmentDingTalkProperties;
|
||||||
|
import com.rj.service.DingTalkRobotService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.HttpEntity;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import javax.crypto.Mac;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class DingTalkRobotServiceImpl implements DingTalkRobotService {
|
||||||
|
|
||||||
|
private static final String SEND_URL = "https://oapi.dingtalk.com/robot/send";
|
||||||
|
|
||||||
|
private final RestTemplate restTemplate;
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
private final LbAssessmentDingTalkProperties properties;
|
||||||
|
|
||||||
|
public DingTalkRobotServiceImpl(RestTemplate restTemplate,
|
||||||
|
ObjectMapper objectMapper,
|
||||||
|
LbAssessmentDingTalkProperties properties) {
|
||||||
|
this.restTemplate = restTemplate;
|
||||||
|
this.objectMapper = objectMapper;
|
||||||
|
this.properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendText(String content) {
|
||||||
|
if (!properties.isEnabled()) {
|
||||||
|
throw new IllegalStateException("钉钉机器人发送未启用,请在配置中设置 lb.assessment-apply.dingtalk.enabled=true");
|
||||||
|
}
|
||||||
|
if (!StringUtils.hasText(properties.getAccessToken())) {
|
||||||
|
throw new IllegalStateException("未配置钉钉机器人 access-token(lb.assessment-apply.dingtalk.access-token)");
|
||||||
|
}
|
||||||
|
if (!StringUtils.hasText(content)) {
|
||||||
|
throw new IllegalArgumentException("发送内容不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
String url = buildWebhookUrl();
|
||||||
|
Map<String, Object> body = new HashMap<>();
|
||||||
|
body.put("msgtype", "text");
|
||||||
|
Map<String, String> text = new HashMap<>();
|
||||||
|
text.put("content", content);
|
||||||
|
body.put("text", text);
|
||||||
|
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
HttpEntity<Map<String, Object>> entity = new HttpEntity<>(body, headers);
|
||||||
|
|
||||||
|
ResponseEntity<String> response = restTemplate.postForEntity(url, entity, String.class);
|
||||||
|
parseResponse(response.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildWebhookUrl() {
|
||||||
|
StringBuilder url = new StringBuilder(SEND_URL)
|
||||||
|
.append("?access_token=")
|
||||||
|
.append(properties.getAccessToken().trim());
|
||||||
|
if (StringUtils.hasText(properties.getSecret())) {
|
||||||
|
long timestamp = System.currentTimeMillis();
|
||||||
|
String sign = sign(timestamp, properties.getSecret().trim());
|
||||||
|
url.append("×tamp=").append(timestamp).append("&sign=").append(sign);
|
||||||
|
}
|
||||||
|
return url.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String sign(long timestamp, String secret) {
|
||||||
|
try {
|
||||||
|
String stringToSign = timestamp + "\n" + secret;
|
||||||
|
Mac mac = Mac.getInstance("HmacSHA256");
|
||||||
|
mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
|
||||||
|
byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
|
||||||
|
return URLEncoder.encode(Base64.getEncoder().encodeToString(signData), StandardCharsets.UTF_8);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IllegalStateException("钉钉加签失败:" + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseResponse(String body) {
|
||||||
|
if (!StringUtils.hasText(body)) {
|
||||||
|
throw new IllegalStateException("钉钉接口返回为空");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
JsonNode root = objectMapper.readTree(body);
|
||||||
|
int errcode = root.path("errcode").asInt(-1);
|
||||||
|
if (errcode != 0) {
|
||||||
|
String errmsg = root.path("errmsg").asText("未知错误");
|
||||||
|
throw new IllegalStateException("钉钉发送失败:" + errmsg + "(errcode=" + errcode + ")");
|
||||||
|
}
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IllegalStateException("解析钉钉响应失败:" + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.rj.entity.LbAssessmentApply;
|
import com.rj.entity.LbAssessmentApply;
|
||||||
import com.rj.mapper.LbAssessmentApplyMapper;
|
import com.rj.mapper.LbAssessmentApplyMapper;
|
||||||
|
import com.rj.service.DingTalkRobotService;
|
||||||
import com.rj.service.ILbAssessmentApplyService;
|
import com.rj.service.ILbAssessmentApplyService;
|
||||||
import jakarta.servlet.ServletOutputStream;
|
import jakarta.servlet.ServletOutputStream;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
@@ -47,6 +48,9 @@ public class LbAssessmentApplyServiceImpl
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ObjectMapper objectMapper;
|
private ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DingTalkRobotService dingTalkRobotService;
|
||||||
|
|
||||||
@Value("${langchain4j.open-ai.chat-model.model-name:qwen-plus}")
|
@Value("${langchain4j.open-ai.chat-model.model-name:qwen-plus}")
|
||||||
private String dashScopeChatModel;
|
private String dashScopeChatModel;
|
||||||
|
|
||||||
@@ -67,7 +71,7 @@ public class LbAssessmentApplyServiceImpl
|
|||||||
moderatorName 主持人姓名;
|
moderatorName 主持人姓名;
|
||||||
meetingNumber 会议号;
|
meetingNumber 会议号;
|
||||||
applicationDatetime 申请日期时间,优先 ISO-8601(如 2026-05-15T14:30:00),也可 yyyy-MM-dd HH:mm:ss;若仅有日期可设为当天 00:00:00。
|
applicationDatetime 申请日期时间,优先 ISO-8601(如 2026-05-15T14:30:00),也可 yyyy-MM-dd HH:mm:ss;若仅有日期可设为当天 00:00:00。
|
||||||
不要输出 id、tenantId、createdAt、updatedAt。
|
不要输出 id、tenantId、createdAt、updatedAt、notificationText。
|
||||||
""";
|
""";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -190,6 +194,7 @@ public class LbAssessmentApplyServiceImpl
|
|||||||
entity.setCreatedAt(now);
|
entity.setCreatedAt(now);
|
||||||
}
|
}
|
||||||
entity.setUpdatedAt(now);
|
entity.setUpdatedAt(now);
|
||||||
|
refreshNotificationText(entity);
|
||||||
|
|
||||||
boolean ok = this.save(entity);
|
boolean ok = this.save(entity);
|
||||||
result.put("success", ok);
|
result.put("success", ok);
|
||||||
@@ -216,6 +221,9 @@ public class LbAssessmentApplyServiceImpl
|
|||||||
}
|
}
|
||||||
entity.setUpdatedAt(LocalDateTime.now());
|
entity.setUpdatedAt(LocalDateTime.now());
|
||||||
boolean ok = this.updateById(entity);
|
boolean ok = this.updateById(entity);
|
||||||
|
if (ok) {
|
||||||
|
persistNotificationText(entity.getId());
|
||||||
|
}
|
||||||
result.put("success", ok);
|
result.put("success", ok);
|
||||||
result.put("message", ok ? "编辑成功" : "编辑失败");
|
result.put("message", ok ? "编辑成功" : "编辑失败");
|
||||||
if (ok) {
|
if (ok) {
|
||||||
@@ -308,17 +316,14 @@ public class LbAssessmentApplyServiceImpl
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
LambdaQueryWrapper<LbAssessmentApply> queryWrapper = new LambdaQueryWrapper<>();
|
LbAssessmentApply record = getByTenantIdAndId(tenantId, id);
|
||||||
queryWrapper.eq(LbAssessmentApply::getTenantId, tenantId.trim())
|
|
||||||
.eq(LbAssessmentApply::getId, id.trim());
|
|
||||||
LbAssessmentApply record = this.getOne(queryWrapper);
|
|
||||||
if (record == null) {
|
if (record == null) {
|
||||||
result.put("success", false);
|
result.put("success", false);
|
||||||
result.put("message", "未找到对应的申请评估记录");
|
result.put("message", "未找到对应的申请评估记录");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
String text = formatAssessmentNotificationText(record);
|
String text = ensureAndSaveNotificationText(record);
|
||||||
result.put("success", true);
|
result.put("success", true);
|
||||||
result.put("message", "生成成功");
|
result.put("message", "生成成功");
|
||||||
result.put("data", text);
|
result.put("data", text);
|
||||||
@@ -331,6 +336,91 @@ public class LbAssessmentApplyServiceImpl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> sendNotificationTextToDingTalk(String tenantId, String id) {
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
try {
|
||||||
|
if (tenantId == null || tenantId.trim().isEmpty()) {
|
||||||
|
result.put("success", false);
|
||||||
|
result.put("message", "tenantId不能为空");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (id == null || id.trim().isEmpty()) {
|
||||||
|
result.put("success", false);
|
||||||
|
result.put("message", "id不能为空");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
LbAssessmentApply record = getByTenantIdAndId(tenantId, id);
|
||||||
|
if (record == null) {
|
||||||
|
result.put("success", false);
|
||||||
|
result.put("message", "未找到对应的申请评估记录");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String text = ensureAndSaveNotificationText(record);
|
||||||
|
dingTalkRobotService.sendText(text);
|
||||||
|
|
||||||
|
result.put("success", true);
|
||||||
|
result.put("message", "发送成功");
|
||||||
|
result.put("data", text);
|
||||||
|
return result;
|
||||||
|
} catch (IllegalArgumentException | IllegalStateException e) {
|
||||||
|
log.warn("发送评估会议通知到钉钉失败, tenantId={}, id={}, reason={}", tenantId, id, e.getMessage());
|
||||||
|
result.put("success", false);
|
||||||
|
result.put("message", e.getMessage());
|
||||||
|
return result;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("发送评估会议通知到钉钉异常, tenantId={}, id={}", tenantId, id, e);
|
||||||
|
result.put("success", false);
|
||||||
|
result.put("message", "发送失败:" + e.getMessage());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private LbAssessmentApply getByTenantIdAndId(String tenantId, String id) {
|
||||||
|
LambdaQueryWrapper<LbAssessmentApply> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper.eq(LbAssessmentApply::getTenantId, tenantId.trim())
|
||||||
|
.eq(LbAssessmentApply::getId, id.trim());
|
||||||
|
return this.getOne(queryWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回可用的通知文案:库中已有则直接返回,否则生成并落库。
|
||||||
|
*/
|
||||||
|
private String ensureAndSaveNotificationText(LbAssessmentApply record) {
|
||||||
|
String text = record.getNotificationText();
|
||||||
|
if (text != null && !text.trim().isEmpty()) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
text = formatAssessmentNotificationText(record);
|
||||||
|
LbAssessmentApply update = new LbAssessmentApply();
|
||||||
|
update.setId(record.getId());
|
||||||
|
update.setNotificationText(text);
|
||||||
|
update.setUpdatedAt(LocalDateTime.now());
|
||||||
|
if (!this.updateById(update)) {
|
||||||
|
throw new IllegalStateException("通知文案保存失败");
|
||||||
|
}
|
||||||
|
record.setNotificationText(text);
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshNotificationText(LbAssessmentApply entity) {
|
||||||
|
entity.setNotificationText(formatAssessmentNotificationText(entity));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void persistNotificationText(String id) {
|
||||||
|
LbAssessmentApply record = this.getById(id);
|
||||||
|
if (record == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LbAssessmentApply update = new LbAssessmentApply();
|
||||||
|
update.setId(id);
|
||||||
|
update.setNotificationText(formatAssessmentNotificationText(record));
|
||||||
|
update.setUpdatedAt(LocalDateTime.now());
|
||||||
|
this.updateById(update);
|
||||||
|
}
|
||||||
|
|
||||||
private static String formatAssessmentNotificationText(LbAssessmentApply record) {
|
private static String formatAssessmentNotificationText(LbAssessmentApply record) {
|
||||||
String teacherName = nullToEmpty(record.getAssessmentTeacherName());
|
String teacherName = nullToEmpty(record.getAssessmentTeacherName());
|
||||||
String applicantName = nullToEmpty(record.getApplicantName());
|
String applicantName = nullToEmpty(record.getApplicantName());
|
||||||
|
|||||||
@@ -276,6 +276,14 @@ dify:
|
|||||||
amap:
|
amap:
|
||||||
web-service-key: ${AMAP_WEB_SERVICE_KEY:34eaa47387aa9e8c1a8ca0d4c8abaa1d}
|
web-service-key: ${AMAP_WEB_SERVICE_KEY:34eaa47387aa9e8c1a8ca0d4c8abaa1d}
|
||||||
|
|
||||||
|
# 申请评估 - 钉钉群机器人(自定义机器人 Webhook)
|
||||||
|
lb:
|
||||||
|
assessment-apply:
|
||||||
|
dingtalk:
|
||||||
|
enabled: ${LB_ASSESSMENT_DINGTALK_ENABLED:true}
|
||||||
|
access-token: ${LB_ASSESSMENT_DINGTALK_ACCESS_TOKEN:}
|
||||||
|
secret: ${LB_ASSESSMENT_DINGTALK_SECRET:}
|
||||||
|
|
||||||
# MinIO 对象存储配置
|
# MinIO 对象存储配置
|
||||||
minio:
|
minio:
|
||||||
# MinIO服务器地址
|
# MinIO服务器地址
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
-- =============================================================================
|
||||||
|
-- 升级脚本:为 lb_assessment_apply 表增加 notification_text 列
|
||||||
|
-- =============================================================================
|
||||||
|
|
||||||
|
SET NAMES utf8mb4;
|
||||||
|
|
||||||
|
ALTER TABLE `lb_assessment_apply`
|
||||||
|
ADD COLUMN `notification_text` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '评估会议通知文案' AFTER `meeting_number`;
|
||||||
Reference in New Issue
Block a user