修复:1.添加素材API配置项到数据库 2.RestTemplate支持信任所有HTTPS证书

This commit is contained in:
Your Name 2026-01-07 14:23:31 +08:00
parent beeedcc800
commit 7936451d61
6 changed files with 205 additions and 164 deletions

View File

@ -5,17 +5,58 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import javax.net.ssl.*;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
/**
* RestTemplate配置类
* 支持调用HTTPS接口(信任所有证书)
*/
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
public RestTemplate restTemplate() throws NoSuchAlgorithmException, KeyManagementException {
// 创建信任所有证书的 TrustManager
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() { return null; }
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
}
};
// 安装信任所有证书的 TrustManager
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
// 设置 HostnameVerifier 为信任所有主机名
HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
// 创建自定义的 RequestFactory
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory() {
@Override
protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
if (connection instanceof HttpsURLConnection) {
((HttpsURLConnection) connection).setHostnameVerifier((hostname, session) -> true);
try {
((HttpsURLConnection) connection).setSSLSocketFactory(sslContext.getSocketFactory());
} catch (Exception e) {
// ignore
}
}
super.prepareConnection(connection, httpMethod);
}
};
factory.setConnectTimeout(10000); // 连接超时10秒
factory.setReadTimeout(30000); // 读取超时30秒
return new RestTemplate(factory);
}
}

View File

@ -466,7 +466,7 @@ public class TaskApprovalService {
} else {
// 没有子任务时显示总积分和工时
content.append("**任务积分**:").append(task.getScore()).append(" 分 \n");
if (task.getEstimatedHours() != null) {
if (task.getEstimatedHours() != null) {
content.append("**预估工时**:").append(formatEstimatedHours(task.getEstimatedHours())).append(" \n");
}
}

View File

@ -432,7 +432,7 @@ public class TaskService {
java.util.List<java.util.Map<String, Object>> typeDetailsList = new java.util.ArrayList<>();
for (com.designhub.dto.PipelineTaskDTO.TaskItemDTO itemDto : groupItems) {
var demandType = configService.getDemandTypeById(itemDto.getTaskTypeId());
var demandType = configService.getDemandTypeById(itemDto.getTaskTypeId());
int itemScore = demandType.getUnitScore().multiply(BigDecimal.valueOf(itemDto.getQuantity())).intValue();
BigDecimal itemHours = demandType.getEstimatedHours() != null
? demandType.getEstimatedHours().multiply(BigDecimal.valueOf(itemDto.getQuantity()))
@ -491,7 +491,7 @@ public class TaskService {
}
} else {
// 并行流水线:全部待接单
item.setStatus("pending");
item.setStatus("pending");
item.setIsLocked(0);
}

View File

@ -1338,10 +1338,10 @@ public class UserService {
int diffB = Math.abs(b.getDeptName().length() - dingDeptName.length());
return Integer.compare(diffA, diffB);
})
.findFirst()
.orElse(null);
.findFirst()
.orElse(null);
if (matched != null) {
if (matched != null) {
log.info("通过部门名称模糊匹配: {} -> {} (候选数: {})",
dingDeptName, matched.getDeptName(), fuzzyMatched.size());
}

View File

@ -600,21 +600,21 @@
</template>
<!-- 二级部门或无子部门的一级部门:正常显示 -->
<template v-else>
<div class="score-main">
<span class="score-value">{{ record.scoreBalance ?? 0 }}</span>
<span class="score-unit">分</span>
</div>
<div class="score-details">
<span class="score-detail-item">
<span class="detail-label">充值</span>
<span class="detail-value">{{ record.totalRecharge ?? 0 }}</span>
</span>
<span class="detail-separator">|</span>
<span class="score-detail-item">
<span class="detail-label">消耗</span>
<span class="detail-value">{{ record.totalConsume ?? 0 }}</span>
</span>
</div>
<div class="score-main">
<span class="score-value">{{ record.scoreBalance ?? 0 }}</span>
<span class="score-unit">分</span>
</div>
<div class="score-details">
<span class="score-detail-item">
<span class="detail-label">充值</span>
<span class="detail-value">{{ record.totalRecharge ?? 0 }}</span>
</span>
<span class="detail-separator">|</span>
<span class="score-detail-item">
<span class="detail-label">消耗</span>
<span class="detail-value">{{ record.totalConsume ?? 0 }}</span>
</span>
</div>
</template>
</div>
</template>
@ -1787,13 +1787,13 @@
<a-select v-model:value="departmentParentId" placeholder="请选择上级部门" allow-clear>
<a-select-option :value="0">顶级部门(一级)</a-select-option>
<a-select-opt-group label="一级部门(选择后成为二级)">
<a-select-option
<a-select-option
v-for="dept in parentDepartmentOptions.level1"
:key="dept.id"
:value="dept.id"
>
{{ dept.deptName }}
</a-select-option>
:key="dept.id"
:value="dept.id"
>
{{ dept.deptName }}
</a-select-option>
</a-select-opt-group>
<a-select-opt-group label="二级部门(选择后成为三级)">
<a-select-option
@ -1900,46 +1900,46 @@
<!-- 消耗限制设置:只对可管理积分的部门显示 -->
<template v-if="canManageScore">
<a-divider>消耗限制设置</a-divider>
<a-descriptions :column="2" bordered>
<a-descriptions-item label="限制状态">
<a-tag :color="currentScorePool.limitEnabled ? 'green' : 'default'">
{{ currentScorePool.limitEnabled ? '已启用' : '未启用' }}
</a-tag>
</a-descriptions-item>
<a-descriptions-item label="限制周期" v-if="currentScorePool.limitEnabled">
{{ currentScorePool.limitPeriod === 'DAILY' ? '每日' :
currentScorePool.limitPeriod === 'WEEKLY' ? '每周' :
currentScorePool.limitPeriod === 'MONTHLY' ? '每月' : '未知' }}
</a-descriptions-item>
<a-descriptions-item label="周期限额" v-if="currentScorePool.limitEnabled">
{{ currentScorePool.periodLimit || 0 }} 分
</a-descriptions-item>
<a-descriptions-item label="已使用" v-if="currentScorePool.limitEnabled">
{{ currentScorePool.periodUsed || 0 }} 分
<span v-if="currentScorePool.periodLimit">
({{ Math.round((currentScorePool.periodUsed || 0) / currentScorePool.periodLimit * 100) }}%)
</span>
</a-descriptions-item>
</a-descriptions>
<a-divider>消耗限制设置</a-divider>
<a-descriptions :column="2" bordered>
<a-descriptions-item label="限制状态">
<a-tag :color="currentScorePool.limitEnabled ? 'green' : 'default'">
{{ currentScorePool.limitEnabled ? '已启用' : '未启用' }}
</a-tag>
</a-descriptions-item>
<a-descriptions-item label="限制周期" v-if="currentScorePool.limitEnabled">
{{ currentScorePool.limitPeriod === 'DAILY' ? '每日' :
currentScorePool.limitPeriod === 'WEEKLY' ? '每周' :
currentScorePool.limitPeriod === 'MONTHLY' ? '每月' : '未知' }}
</a-descriptions-item>
<a-descriptions-item label="周期限额" v-if="currentScorePool.limitEnabled">
{{ currentScorePool.periodLimit || 0 }} 分
</a-descriptions-item>
<a-descriptions-item label="已使用" v-if="currentScorePool.limitEnabled">
{{ currentScorePool.periodUsed || 0 }} 分
<span v-if="currentScorePool.periodLimit">
({{ Math.round((currentScorePool.periodUsed || 0) / currentScorePool.periodLimit * 100) }}%)
</span>
</a-descriptions-item>
</a-descriptions>
<a-divider>充值积分</a-divider>
<a-form layout="inline">
<a-form-item label="充值金额">
<a-input-number
v-model:value="rechargeAmount"
:min="1"
:precision="0"
style="width: 200px"
placeholder="请输入充值金额"
/>
</a-form-item>
<a-form-item>
<a-button type="primary" @click="handleRecharge">确认充值</a-button>
</a-form-item>
</a-form>
<a-divider>充值积分</a-divider>
<a-form layout="inline">
<a-form-item label="充值金额">
<a-input-number
v-model:value="rechargeAmount"
:min="1"
:precision="0"
style="width: 200px"
placeholder="请输入充值金额"
/>
</a-form-item>
<a-form-item>
<a-button type="primary" @click="handleRecharge">确认充值</a-button>
</a-form-item>
</a-form>
</template>
</div>
<a-empty v-else description="加载中..." />

View File

@ -200,10 +200,10 @@
class="task-card chart-card"
@click="handleTaskClick(task)"
>
<!-- 任务标题 -->
<div class="task-header">
<h3 class="task-title">{{ task.title }}</h3>
<div class="task-badges">
<!-- 任务标题 -->
<div class="task-header">
<h3 class="task-title">{{ task.title }}</h3>
<div class="task-badges">
<span v-if="task.isSubTask" class="badge badge-subtask">
<Icon name="layers" size="sm" color="#1890ff" style="margin-right: 4px; vertical-align: middle;" />
子任务
@ -216,12 +216,12 @@
<Icon name="star" size="sm" color="#31f08b" style="margin-right: 4px; vertical-align: middle;" />
高分
</span>
<span v-if="task.isUrgent" class="badge badge-urgent">
<Icon name="fire" size="sm" color="#31f08b" style="margin-right: 4px; vertical-align: middle;" />
紧急
</span>
</div>
</div>
<span v-if="task.isUrgent" class="badge badge-urgent">
<Icon name="fire" size="sm" color="#31f08b" style="margin-right: 4px; vertical-align: middle;" />
紧急
</span>
</div>
</div>
<!-- 流程阶段 -->
<div v-if="getProcessStage(task)" class="process-stage">
@ -233,17 +233,17 @@
<!-- 任务信息 -->
<div class="task-info-wrapper">
<div class="task-info">
<div class="info-item">
<span class="label">任务类型</span>
<div class="task-info">
<div class="info-item">
<span class="label">任务类型</span>
<span class="value">{{ getTaskTypeName(task.taskTypeId, task.taskTypeName, task.taskSubType) }}</span>
</div>
<div class="info-item">
<span class="label">预估积分</span>
</div>
<div class="info-item">
<span class="label">预估积分</span>
<span class="value text-brand">{{ task.totalScore || task.score || '--' }} 分</span>
</div>
<div class="info-item">
<span class="label">数量</span>
</div>
<div class="info-item">
<span class="label">数量</span>
<span class="value">{{ task.quantity || 1 }} 个</span>
</div>
</div>
@ -550,17 +550,17 @@
<!-- 任务信息 -->
<div class="task-info-wrapper">
<div class="task-info task-info-3col">
<div class="info-item">
<span class="label">任务类型</span>
<div class="info-item">
<span class="label">任务类型</span>
<span class="value">{{ getTaskTypeName(task.taskTypeId, task.taskTypeName, task.taskSubType) }}</span>
</div>
<div class="info-item">
<span class="label">预估积分</span>
</div>
<div class="info-item">
<span class="label">预估积分</span>
<span class="value text-brand">{{ task.totalScore || task.score }} 分</span>
</div>
<div class="info-item">
<span class="label">数量</span>
<span class="value">{{ task.quantity || '--' }} 个</span>
</div>
<div class="info-item">
<span class="label">数量</span>
<span class="value">{{ task.quantity || '--' }} 个</span>
</div>
</div>
<!-- 预览图 -->
@ -866,17 +866,17 @@
<!-- 任务信息 -->
<div class="task-info-wrapper">
<div class="task-info task-info-3col">
<div class="info-item">
<span class="label">任务类型</span>
<div class="info-item">
<span class="label">任务类型</span>
<span class="value">{{ getTaskTypeName(task.taskTypeId, task.taskTypeName, task.taskSubType) }}</span>
</div>
<div class="info-item">
<span class="label">预估积分</span>
</div>
<div class="info-item">
<span class="label">预估积分</span>
<span class="value text-brand">{{ task.totalScore || task.score }} 分</span>
</div>
<div class="info-item">
<span class="label">数量</span>
<span class="value">{{ task.quantity || '--' }} 个</span>
</div>
<div class="info-item">
<span class="label">数量</span>
<span class="value">{{ task.quantity || '--' }} 个</span>
</div>
</div>
<!-- 预览图 -->
@ -1215,17 +1215,17 @@
<!-- 任务信息 -->
<div class="task-info-wrapper">
<div class="task-info task-info-3col">
<div class="info-item">
<span class="label">任务类型</span>
<div class="info-item">
<span class="label">任务类型</span>
<span class="value">{{ getTaskTypeName(task.taskTypeId, task.taskTypeName, task.taskSubType) }}</span>
</div>
<div class="info-item">
<span class="label">获得积分</span>
<span class="value text-brand">{{ task.score }} 分</span>
</div>
<div class="info-item">
<span class="label">数量</span>
<span class="value">{{ task.quantity || '--' }} 个</span>
</div>
<div class="info-item">
<span class="label">获得积分</span>
<span class="value text-brand">{{ task.score }} 分</span>
</div>
<div class="info-item">
<span class="label">数量</span>
<span class="value">{{ task.quantity || '--' }} 个</span>
</div>
</div>
<!-- 预览图 -->
@ -1554,17 +1554,17 @@
<!-- 任务信息 -->
<div class="task-info-wrapper">
<div class="task-info task-info-3col">
<div class="info-item">
<span class="label">任务类型</span>
<div class="info-item">
<span class="label">任务类型</span>
<span class="value">{{ getTaskTypeName(task.taskTypeId, task.taskTypeName, task.taskSubType) }}</span>
</div>
<div class="info-item">
<span class="label">积分</span>
<span class="value text-brand">{{ task.score }} 分</span>
</div>
<div class="info-item">
<span class="label">数量</span>
<span class="value">{{ task.quantity || '--' }} 个</span>
</div>
<div class="info-item">
<span class="label">积分</span>
<span class="value text-brand">{{ task.score }} 分</span>
</div>
<div class="info-item">
<span class="label">数量</span>
<span class="value">{{ task.quantity || '--' }} 个</span>
</div>
</div>
<!-- 预览图 -->
@ -1791,22 +1791,22 @@
<!-- 任务信息 -->
<div class="task-info-wrapper">
<div class="task-info">
<div v-if="item.type === 'task'" class="info-item">
<span class="label">任务类型</span>
<span class="value">{{ getTaskTypeName(item.data.taskTypeId) }}</span>
</div>
<div v-if="item.type === 'taskGroup'" class="info-item">
<span class="label">子任务数量</span>
<span class="value">{{ item.data.items?.length || 0 }} 个</span>
</div>
<div class="info-item">
<span class="label">预估积分</span>
<span class="value text-brand">{{ item.score }} 分</span>
</div>
<div v-if="item.type === 'task'" class="info-item">
<span class="label">数量</span>
<span class="value">{{ item.data.quantity || '--' }} 个</span>
<div class="task-info">
<div v-if="item.type === 'task'" class="info-item">
<span class="label">任务类型</span>
<span class="value">{{ getTaskTypeName(item.data.taskTypeId) }}</span>
</div>
<div v-if="item.type === 'taskGroup'" class="info-item">
<span class="label">子任务数量</span>
<span class="value">{{ item.data.items?.length || 0 }} 个</span>
</div>
<div class="info-item">
<span class="label">预估积分</span>
<span class="value text-brand">{{ item.score }} 分</span>
</div>
<div v-if="item.type === 'task'" class="info-item">
<span class="label">数量</span>
<span class="value">{{ item.data.quantity || '--' }} 个</span>
</div>
</div>
<!-- 预览图 -->
@ -2920,7 +2920,7 @@ const loadCompletedTasks = async () => {
}
} else if (userDeptType === 'demand') {
// 需求部门用户:看到自己发起的已完成的母任务
const response = await taskApi.getCompletedTasks(params)
const response = await taskApi.getCompletedTasks(params)
if (response.data && response.data.records) {
allTasks = response.data.records.map((task: any) => ({
...task,
@ -3207,12 +3207,12 @@ const showAssignDesignerModal = async (task: Task) => {
}))
} else {
// 兼容旧数据:从 taskTypeIds 获取
const taskTypeIdsStr = task.taskTypeIds || task.taskTypeId?.toString() || ''
const taskTypeIdArray = taskTypeIdsStr.split(',').filter(id => id.trim())
approveTaskTypes.value = taskTypeIdArray.map(id => ({
typeId: parseInt(id.trim()),
quantity: task.quantity || 1
}))
const taskTypeIdsStr = task.taskTypeIds || task.taskTypeId?.toString() || ''
const taskTypeIdArray = taskTypeIdsStr.split(',').filter(id => id.trim())
approveTaskTypes.value = taskTypeIdArray.map(id => ({
typeId: parseInt(id.trim()),
quantity: task.quantity || 1
}))
}
approveModalVisible.value = true
@ -3657,26 +3657,26 @@ const loadInProgressTasks = async () => {
// 根据部门类型决定加载哪些任务
if (isAdmin) {
// 管理员:看到所有任务(母任务和子任务)
const [taskResponse, itemResponse] = await Promise.all([
taskApi.getTasks(params),
taskApi.getInProgressTaskItems(params)
])
const [taskResponse, itemResponse] = await Promise.all([
taskApi.getTasks(params),
taskApi.getInProgressTaskItems(params)
])
// 处理普通任务
if (taskResponse.data && taskResponse.data.records) {
const tasks = taskResponse.data.records.map((task: any) => ({
...task,
// 处理普通任务
if (taskResponse.data && taskResponse.data.records) {
const tasks = taskResponse.data.records.map((task: any) => ({
...task,
isSubTask: false
}))
allTasks = [...allTasks, ...tasks]
totalCount += taskResponse.data.total || 0
}
}))
allTasks = [...allTasks, ...tasks]
totalCount += taskResponse.data.total || 0
}
// 处理子任务
if (itemResponse.data && itemResponse.data.records) {
// 处理子任务
if (itemResponse.data && itemResponse.data.records) {
const items = itemResponse.data.records.map((item: any) => mapTaskItemToTask(item))
allTasks = [...allTasks, ...items]
totalCount += itemResponse.data.total || 0
allTasks = [...allTasks, ...items]
totalCount += itemResponse.data.total || 0
}
} else if (userDeptType === 'demand') {
// 需求部门用户:只看母任务卡片(自己发起的任务)