shinnosuke
2026-08-06 3d92993d0877197371f57869e84763dcba39a716
fix(admin): 自动记录政策发布人 (bug #24051)
6个文件已修改
26 ■■■■■ 已修改文件
talent-card-admin/src/views/TalentPolicyEditView.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
talent-card-admin/src/views/TalentPolicyPublishView.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
talent-card-server/src/main/java/com/talentcard/server/business/admin/AdminBusinessController.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
talent-card-server/src/main/java/com/talentcard/server/business/admin/AdminBusinessService.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
talent-card-server/src/main/java/com/talentcard/server/business/admin/auth/AdminAuthInterceptor.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
talent-card-server/src/main/java/com/talentcard/server/business/admin/auth/AdminAuthService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
talent-card-admin/src/views/TalentPolicyEditView.vue
@@ -14,6 +14,6 @@
</script>
<template>
  <div class="policy-edit-page" v-loading="loading"><section class="news-meta-panel"><h3>发布信息</h3><div class="news-meta-grid"><div><span>发布时间</span><strong>{{ createdAt }}</strong></div><div><span>修改时间</span><strong>{{ updatedAt }}</strong></div></div></section><section class="policy-publish-panel"><h3>政策内容</h3><el-form class="policy-publish-form" :model="form" label-width="88px">
    <el-form-item label="政策标题"><el-input v-model="form.title" /></el-form-item><el-form-item label="政策摘要"><el-input v-model="form.subtitle" /></el-form-item><el-form-item label="发布人"><el-input v-model="form.author" /></el-form-item><el-form-item label="发布来源"><el-input v-model="form.source" /></el-form-item><el-form-item label="政策详情"><el-input v-model="form.content" type="textarea" :rows="10" /></el-form-item><el-form-item label="封面图 URL"><el-input v-model="form.coverUrl" /></el-form-item><el-form-item label="排序值"><el-input-number v-model="form.sortNo" :min="0" :max="9999" /></el-form-item><el-form-item><el-button type="primary" @click="save">保存</el-button></el-form-item>
    <el-form-item label="政策标题"><el-input v-model="form.title" /></el-form-item><el-form-item label="政策摘要"><el-input v-model="form.subtitle" /></el-form-item><el-form-item label="政策详情"><el-input v-model="form.content" type="textarea" :rows="10" /></el-form-item><el-form-item label="封面图 URL"><el-input v-model="form.coverUrl" /></el-form-item><el-form-item label="排序值"><el-input-number v-model="form.sortNo" :min="0" :max="9999" /></el-form-item><el-form-item><el-button type="primary" @click="save">保存</el-button></el-form-item>
  </el-form></section></div>
</template>
talent-card-admin/src/views/TalentPolicyPublishView.vue
@@ -17,8 +17,6 @@
  <div class="policy-publish-page"><section class="policy-publish-panel"><h3>政策内容</h3><el-form class="policy-publish-form" :model="form" label-width="88px">
    <el-form-item label="政策标题"><el-input v-model="form.title" placeholder="请输入政策标题" /></el-form-item>
    <el-form-item label="政策摘要"><el-input v-model="form.subtitle" placeholder="用于小程序列表展示" /></el-form-item>
    <el-form-item label="发布人"><el-input v-model="form.author" /></el-form-item>
    <el-form-item label="发布来源"><el-input v-model="form.source" /></el-form-item>
    <el-form-item label="政策详情"><el-input v-model="form.content" type="textarea" :rows="10" /></el-form-item>
    <el-form-item label="封面图 URL"><el-input v-model="form.coverUrl" placeholder="https://..." /></el-form-item>
    <el-form-item label="排序值"><el-input-number v-model="form.sortNo" :min="0" :max="9999" /></el-form-item>
talent-card-server/src/main/java/com/talentcard/server/business/admin/AdminBusinessController.java
@@ -3,6 +3,7 @@
import java.util.Map;
import com.talentcard.server.business.PageResult;
import com.talentcard.server.business.admin.auth.AdminAuthInterceptor;
import com.talentcard.server.common.ApiResponse;
import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
@@ -17,6 +18,8 @@
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import jakarta.servlet.http.HttpServletRequest;
@RestController
@RequestMapping("/api/admin/business")
@@ -93,8 +96,9 @@
    @PostMapping("/policies")
    @ResponseStatus(HttpStatus.CREATED)
    public ApiResponse<Map<String, Object>> createPolicy(@Valid @RequestBody PolicyArticleRequest request) {
        return ApiResponse.success(adminBusinessService.createPolicy(request));
    public ApiResponse<Map<String, Object>> createPolicy(@Valid @RequestBody PolicyArticleRequest request, HttpServletRequest servletRequest) {
        String operatorName = String.valueOf(servletRequest.getAttribute(AdminAuthInterceptor.OPERATOR_NAME_ATTRIBUTE));
        return ApiResponse.success(adminBusinessService.createPolicy(request, operatorName));
    }
    @PutMapping("/policies/{id}")
talent-card-server/src/main/java/com/talentcard/server/business/admin/AdminBusinessService.java
@@ -181,10 +181,10 @@
    }
    @Transactional
    public Map<String, Object> createPolicy(PolicyArticleRequest request) {
    public Map<String, Object> createPolicy(PolicyArticleRequest request, String operatorName) {
        int status = defaultNewsStatus(request.status());
        jdbcTemplate.update("insert into policy_article(policy_no, title, subtitle, cover_url, author, source, content, is_top, sort_no, publish_time, status) values (?, ?, ?, ?, ?, ?, ?, ?, ?, case when ? = 1 then now() else null end, ?)",
                BusinessIdGenerator.next("POLICY"), request.title().trim(), blankToNull(request.subtitle()), blankToNull(request.coverUrl()), blankToNull(request.author()), blankToNull(request.source()), sanitizeNewsContent(request.content()), Boolean.TRUE.equals(request.isTop()) ? 1 : 0, request.sortNo() == null ? 0 : request.sortNo(), status, status);
                BusinessIdGenerator.next("POLICY"), request.title().trim(), blankToNull(request.subtitle()), blankToNull(request.coverUrl()), blankToNull(operatorName), blankToNull(request.source()), sanitizeNewsContent(request.content()), Boolean.TRUE.equals(request.isTop()) ? 1 : 0, request.sortNo() == null ? 0 : request.sortNo(), status, status);
        return policyDetail(jdbcTemplate.queryForObject("select last_insert_id()", Long.class));
    }
talent-card-server/src/main/java/com/talentcard/server/business/admin/auth/AdminAuthInterceptor.java
@@ -9,6 +9,7 @@
@Component
public class AdminAuthInterceptor implements HandlerInterceptor {
    public static final String OPERATOR_ID_ATTRIBUTE = "authenticatedAdminOperatorId";
    public static final String OPERATOR_NAME_ATTRIBUTE = "authenticatedAdminOperatorName";
    private final AdminAuthService service;
@@ -20,6 +21,7 @@
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        Long operatorId = service.authenticate(request.getHeader(HttpHeaders.AUTHORIZATION));
        request.setAttribute(OPERATOR_ID_ATTRIBUTE, operatorId);
        request.setAttribute(OPERATOR_NAME_ATTRIBUTE, service.operatorName(operatorId));
        return true;
    }
}
talent-card-server/src/main/java/com/talentcard/server/business/admin/auth/AdminAuthService.java
@@ -98,6 +98,14 @@
        return number(rows.get(0).get("operatorId"));
    }
    @Transactional(readOnly = true)
    public String operatorName(Long operatorId) {
        List<Map<String, Object>> rows = rows("select display_name from admin_operator where id = ? and deleted = 0 limit 1", operatorId);
        if (rows.isEmpty()) throw new BusinessException(ErrorCode.UNAUTHORIZED, "请先登录管理后台");
        String displayName = String.valueOf(rows.get(0).get("displayName")).trim();
        return displayName.isBlank() ? "管理员" : displayName;
    }
    private Map<String, Object> issueSession(Map<String, Object> operator) {
        String accessToken = token();
        LocalDateTime now = LocalDateTime.now();