Merge remote-tracking branch 'origin/master'

# Conflicts:
#	ruoyi-modules/hwmom-wms/src/main/java/org/dromara/wms/domain/WmsInventory.java
hwmom-htk
wanghao 5 months ago
commit cf2ed1ceaa

@ -0,0 +1,15 @@
package org.dromara.common.constant;
/**
* MES
*
* @author xins
*/
public interface HwMomAiConstants {
/**
* rediskey
*/
public static final String AI_DATABASE_SCHEMA_KEY_PREFIX = "ai:database:schema:";
}

@ -190,6 +190,15 @@
<version>0.18.0</version>
</dependency>
<!--阿里云百炼SDK,通义千问-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dashscope-sdk-java</artifactId>
<!-- 请将 'the-latest-version' 替换为最新版本号https://mvnrepository.com/artifact/com.alibaba/dashscope-sdk-java -->
<version>2.18.2</version>
</dependency>
<!-- 本地模型依赖以sentence-transformers为例 -->
<dependency>
<groupId>org.tensorflow</groupId>
@ -300,6 +309,17 @@
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.anyline</groupId>
<artifactId>anyline-data-jdbc-mssql</artifactId>
<version>${anyline.version}</version>
</dependency>
<dependency>
<groupId>org.anyline</groupId>
<artifactId>anyline-environment-spring-data-jdbc</artifactId>
<version>${anyline.version}</version>
</dependency>
</dependencies>
<build>

@ -131,6 +131,16 @@ public class AiAssistantController extends BaseController {
}
/**
* sqlAIModelID, AIPLATFORMID
* @param request
* @return
*/
@PostMapping(value = "/generateSql")
public String generateSql(AIRequest request) {
return aiAssistantService.generateSQL(request);
}

@ -142,7 +142,7 @@ public class AiModelController extends BaseController {
/**
*
* AIapikeyapisecret
*/
@PostMapping("/testAIModel")
public R<Void> testAIModel(@RequestParam("provider") String provider, @RequestBody AIRequest request) {

@ -0,0 +1,181 @@
package org.dromara.ai.controller;
import java.util.List;
import cn.hutool.core.convert.Convert;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.dromara.ai.domain.AiSqlTable;
import org.dromara.ai.domain.dto.AiSqlTableDelete;
import org.dromara.common.mybatis.helper.DataBaseHelper;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.ai.domain.vo.AiSqlTableVo;
import org.dromara.ai.domain.bo.AiSqlTableBo;
import org.dromara.ai.service.IAiSqlTableService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
/**
* AIsql
* 访:/ai/aiSqlTable
*
* @author xins
* @date 2025-09-04
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/aiSqlTable")
public class AiSqlTableController extends BaseController {
private final IAiSqlTableService aiSqlTableService;
/**
* AIsql
*/
@SaCheckPermission("ai:aiSqlTable:list")
@GetMapping("/list")
public TableDataInfo<AiSqlTableVo> list(AiSqlTableBo bo, PageQuery pageQuery) {
return aiSqlTableService.queryPageList(bo, pageQuery);
}
/**
* AIsql
*/
@SaCheckPermission("ai:aiSqlTable:export")
@Log(title = "AI生成sql信息", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(AiSqlTableBo bo, HttpServletResponse response) {
List<AiSqlTableVo> list = aiSqlTableService.queryList(bo);
ExcelUtil.exportExcel(list, "AI生成sql信息", AiSqlTableVo.class, response);
}
/**
* AIsql
*
* @param tableId
*/
@SaCheckPermission("ai:aiSqlTable:query")
@GetMapping("/{tableId}")
public R<AiSqlTableVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long tableId) {
return R.ok(aiSqlTableService.queryById(tableId));
}
/**
* AIsql
*/
@SaCheckPermission("ai:aiSqlTable:add")
@Log(title = "AI生成sql信息", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody AiSqlTableBo bo) {
return toAjax(aiSqlTableService.insertByBo(bo));
}
/**
* AIsql
*/
@SaCheckPermission("ai:aiSqlTable:edit")
@Log(title = "AI生成sql信息", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody AiSqlTableBo bo) {
return toAjax(aiSqlTableService.updateByBo(bo));
}
/**
* AIsql
*
* @param tableIds
*/
@SaCheckPermission("ai:aiSqlTable:remove")
@Log(title = "AI生成sql信息", businessType = BusinessType.DELETE)
@DeleteMapping("/{tableIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] tableIds) {
return toAjax(aiSqlTableService.deleteWithValidByIds(List.of(tableIds), true));
}
/**
* AIsql
*/
@GetMapping("/getAiSqlTableList")
public R<List<AiSqlTableVo>> getAiSqlTableList(AiSqlTableBo bo) {
List<AiSqlTableVo> list = aiSqlTableService.queryList(bo);
return R.ok(list);
}
/**
*
*/
@SaCheckPermission("ai:aiSqlTable:list")
@GetMapping(value = "/getDataNames")
public R<Object> getCurrentDataSourceNameList() {
return R.ok(DataBaseHelper.getDataSourceNameList());
}
/**
*
*/
@SaCheckPermission("ai:aiSqlTable:list")
@GetMapping("/db/list")
public TableDataInfo<AiSqlTable> dbTableList(AiSqlTableBo aiSqlTableBo, PageQuery pageQuery) {
return aiSqlTableService.selectPageDbTableList(aiSqlTableBo, pageQuery);
}
/**
*
*
* @param alSqlTableList
*/
@SaCheckPermission("ai:aiSqlTable:add")
@Log(title = "导入表结构", businessType = BusinessType.IMPORT)
@PostMapping("/importTable")
public R<Void> importTableSave(@RequestBody
List<AiSqlTable> alSqlTableList) {
System.out.println(alSqlTableList);
return toAjax(aiSqlTableService.importAiSqlTable(alSqlTableList));
}
/**
* AIsql
*
* @param aiSqlTableDeleteList
*/
@SaCheckPermission("ai:aiSqlTable:remove")
@Log(title = "AI生成sql信息", businessType = BusinessType.DELETE)
@DeleteMapping("/deleteAiSqlTable")
public R<Void> deleteAiSqlTable(@Validated(EditGroup.class) @RequestBody List<AiSqlTableDelete> aiSqlTableDeleteList) {
aiSqlTableService.deleteAiSqlTable(aiSqlTableDeleteList);
return R.ok();
}
/**
*
*
*/
@SaCheckPermission("ai:aiSqlTable:refresh")
@PostMapping("/refreshCache")
public R<Void> refreshCache() {
aiSqlTableService.refreshCache();
return R.ok();
}
}

@ -0,0 +1,62 @@
package org.dromara.ai.domain;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
/**
* AIsql ai_sql_table
*
* @author xins
* @date 2025-09-04
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("ai_sql_table")
public class AiSqlTable extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
*
*/
@TableId(value = "table_id", type = IdType.AUTO)
private Long tableId;
/**
*
*/
private String dataName;
/**
*
*/
private String tableName;
/**
*
*/
private String tableComment;
/**
*
*/
private String subTableName;
/**
*
*/
private String subTableFkName;
/**
* 0 2
*/
@TableLogic
private String delFlag;
}

@ -0,0 +1,59 @@
package org.dromara.ai.domain.bo;
import org.dromara.ai.domain.AiSqlTable;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
/**
* AIsql ai_sql_table
*
* @author xins
* @date 2025-09-04
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = AiSqlTable.class, reverseConvertGenerate = false)
public class AiSqlTableBo extends BaseEntity {
/**
*
*/
@NotNull(message = "编号不能为空", groups = { AddGroup.class, EditGroup.class })
private Long tableId;
/**
*
*/
private String dataName;
/**
*
*/
@NotBlank(message = "表名称不能为空", groups = { AddGroup.class, EditGroup.class })
private String tableName;
/**
*
*/
@NotBlank(message = "表描述不能为空", groups = { AddGroup.class, EditGroup.class })
private String tableComment;
/**
*
*/
@NotBlank(message = "关联子表的表名不能为空", groups = { AddGroup.class, EditGroup.class })
private String subTableName;
/**
*
*/
@NotBlank(message = "子表关联的外键名不能为空", groups = { AddGroup.class, EditGroup.class })
private String subTableFkName;
}

@ -0,0 +1,35 @@
package org.dromara.ai.domain.dto;
/**
* @description AiSqlTable Delete dto
* @author xins
* @date 2025/9/5 14:50
*/
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.dromara.common.core.validate.EditGroup;
@Data
public class AiSqlTableDelete {
/**
* ID
*/
@NotNull(message = "表ID不能为空", groups = { EditGroup.class })
private Long tableId;
/**
*
*/
@NotBlank(message = "表名不能为空", groups = { EditGroup.class })
private String tableName;
/**
*
*/
@NotBlank(message = "数据源名称不能为空", groups = { EditGroup.class })
private String dataName;
}

@ -0,0 +1,67 @@
package org.dromara.ai.domain.vo;
import org.dromara.ai.domain.AiSqlTable;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* AIsql ai_sql_table
*
* @author xins
* @date 2025-09-04
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = AiSqlTable.class)
public class AiSqlTableVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
*
*/
@ExcelProperty(value = "编号")
private Long tableId;
/**
*
*/
private String dataName;
/**
*
*/
@ExcelProperty(value = "表名称")
private String tableName;
/**
*
*/
@ExcelProperty(value = "表描述")
private String tableComment;
/**
*
*/
@ExcelProperty(value = "关联子表的表名")
private String subTableName;
/**
*
*/
@ExcelProperty(value = "子表关联的外键名")
private String subTableFkName;
}

@ -0,0 +1,28 @@
package org.dromara.ai.mapper;
import com.baomidou.dynamic.datasource.annotation.DS;
import org.dromara.ai.domain.AiSqlTable;
import org.dromara.ai.domain.vo.AiSqlTableVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import java.util.List;
/**
* AIsqlMapper
*
* @author xins
* @date 2025-09-04
*/
public interface AiSqlTableMapper extends BaseMapperPlus<AiSqlTable, AiSqlTableVo> {
/**
*
*
* @param dataName
* @return
*
* @DS("") 使
*/
@DS("")
List<String> selectTableNameList(String dataName);
}

@ -11,11 +11,11 @@ import java.util.Map;
/**
* @Author xins
* @Date 2025/7/8 9:22
* @Description:
* @Description: SQLServersql mapper
*/
@InterceptorIgnore(dataPermission = "true", tenantLine = "true")
@Mapper
public interface DatabaseMetaMapper {
public interface SQLServerDatabaseMetaMapper {
/**
*
@ -41,4 +41,7 @@ public interface DatabaseMetaMapper {
"INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id " +
"WHERE i.is_primary_key = 1 AND OBJECT_NAME(ic.object_id) = #{tableName}")
List<String> getPrimaryKeys(@Param("tableName") String tableName);
List<Map<String,Object>> getTablesStructureByTableNames(@Param("tableNames") String[] tableNames);
}

@ -19,7 +19,7 @@ public class AIRequest {
private AIProviderEnum aiModelEnum;
/**
* /ID(deepseek-chattongyi-qianwentencent-lkewenxin-yiyan)
* (deepseek-chattongyi-qianwen)
*/
private String model;
@ -28,6 +28,12 @@ public class AIRequest {
*/
private Long modelId;
/**
* AIID
*/
private Long platformId;
/**
* ID
*/
@ -80,7 +86,7 @@ public class AIRequest {
private String apiSecretEncryptFlag;
/**
*
* (prompt)
*/
private String text;
@ -98,6 +104,23 @@ public class AIRequest {
private String messageTopic;
private String questionContent;
/**
* IDai_model
*/
private Long embeddingModelId;
/**
*
*/
private Integer retrieveLimit;
/**
*
*/
private String dataName;
/**
*
*/

@ -7,7 +7,7 @@ public enum AIProviderEnum {
private final String name;
private final Long code;//等于ai_base_model表的base_model_id
private final Long code;//等于ai_platform表的platform_id
AIProviderEnum(String name, Long code) {
this.name = name;

@ -40,10 +40,10 @@ public class AIProviderProcessorFactory {
}
/**
* base_model_idAPI
* platformIdAI
*/
public IUnifiedAIProviderProcessor getProcessor(Long baseModelId) {
AIProviderEnum provider = AIProviderEnum.fromCode(baseModelId);
public IUnifiedAIProviderProcessor getProcessorByPlatformId(Long platformId) {
AIProviderEnum provider = AIProviderEnum.fromCode(platformId);
return getProcessor(provider);
}
}

@ -91,6 +91,9 @@ public class DeepSeekProcessor extends BaseAIProviderProcessor {
}
String requestBody = objectMapper.writeValueAsString(rootNode);
configureApiKey(request);
return standardRequest(API_URL, requestBody, request.getApiKey());
} catch (IOException e) {
return buildErrorResponse("构建请求失败: " + e.getMessage());
@ -114,7 +117,7 @@ public class DeepSeekProcessor extends BaseAIProviderProcessor {
StringBuilder fullResponseBuilder = new StringBuilder();
String requestBody = objectMapper.writeValueAsString(rootNode);
setApiKey(request);
configureApiKey(request);
return executeStreamRequest(API_URL, requestBody, request.getApiKey()).doOnNext(chunk -> {
// 收集每个chunk
@ -220,7 +223,7 @@ public class DeepSeekProcessor extends BaseAIProviderProcessor {
return "";
}
private void setApiKey(AIRequest request) {
private void configureApiKey(AIRequest request) {
AiModelVo aiModelVo = aiModelMapper.selectVoById(request.getModelId());
if (aiModelVo != null) {
if (aiModelVo.getApiKey() == null) {

@ -1,7 +1,9 @@
package org.dromara.ai.service;
import org.dromara.ai.process.dto.AIRequest;
import org.dromara.ai.process.dto.AIResponse;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public interface IAIAssistantService {
@ -13,6 +15,13 @@ public interface IAIAssistantService {
*/
Flux<String> chatStream(String provider, AIRequest aiRequest);
/**
* sql
* @param aiRequest
* @return String
*/
public String generateSQL(AIRequest aiRequest);
public boolean testAIModel(String provider, AIRequest aiRequest);
// public boolean testAIModel(String provider, AIRequest aiRequest);
}

@ -0,0 +1,101 @@
package org.dromara.ai.service;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import org.dromara.ai.domain.AiSqlTable;
import org.dromara.ai.domain.dto.AiSqlTableDelete;
import org.dromara.ai.domain.vo.AiSqlTableVo;
import org.dromara.ai.domain.bo.AiSqlTableBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* AIsqlService
*
* @author xins
* @date 2025-09-04
*/
public interface IAiSqlTableService {
/**
* AIsql
*
* @param tableId
* @return AIsql
*/
AiSqlTableVo queryById(Long tableId);
/**
* AIsql
*
* @param bo
* @param pageQuery
* @return AIsql
*/
TableDataInfo<AiSqlTableVo> queryPageList(AiSqlTableBo bo, PageQuery pageQuery);
/**
* AIsql
*
* @param bo
* @return AIsql
*/
List<AiSqlTableVo> queryList(AiSqlTableBo bo);
/**
* AIsql
*
* @param bo AIsql
* @return
*/
Boolean insertByBo(AiSqlTableBo bo);
/**
* AIsql
*
* @param bo AIsql
* @return
*/
Boolean updateByBo(AiSqlTableBo bo);
/**
* AIsql
*
* @param ids
* @param isValid
* @return
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
*
*
* @param aiSqlTableBo AiSqlTableBo
* @param pageQuery PageQuery
* @return TableDataInfo
*/
public TableDataInfo<AiSqlTable> selectPageDbTableList(AiSqlTableBo aiSqlTableBo, PageQuery pageQuery);
/**
*
*
* @param aiSqlTableList
*/
public boolean importAiSqlTable(List<AiSqlTable> aiSqlTableList);
/**
*
*/
public void refreshCache();
/**
* AIsql
* @param aiSqlTableDeleteList
*/
public void deleteAiSqlTable(List<AiSqlTableDelete> aiSqlTableDeleteList);
}

@ -1,27 +1,33 @@
package org.dromara.ai.service.impl;
import com.alibaba.excel.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.dromara.ai.domain.AiModel;
import org.dromara.ai.domain.vo.AiModelVo;
import org.dromara.ai.mapper.AiModelMapper;
import org.dromara.ai.test.vectorization.process.IEmbeddingProcessor;
import org.dromara.ai.process.dto.AIResponse;
import org.dromara.ai.test.ChatRequest;
import org.dromara.ai.mapper.SQLServerDatabaseMetaMapper;
import org.dromara.ai.process.dto.AIMessage;
import org.dromara.ai.process.dto.AIRequest;
import org.dromara.ai.process.dto.AIResponse;
import org.dromara.ai.process.provider.processor.AIProviderProcessorFactory;
import org.dromara.ai.process.provider.processor.IUnifiedAIProviderProcessor;
import org.dromara.ai.service.IAIAssistantService;
import org.dromara.ai.vectordb.service.IVectorDBService;
import org.dromara.common.constant.HwMomAiConstants;
import org.dromara.common.encrypt.utils.EncryptUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.api.model.LoginUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import com.fasterxml.jackson.databind.ObjectMapper;
import reactor.core.publisher.Mono;
import java.time.Duration;
import java.util.*;
import java.util.stream.Collectors;
/**
* @Author xins
@ -40,9 +46,6 @@ public class AIAssistantServiceImpl implements IAIAssistantService {
@Autowired
private Map<String, IUnifiedAIProviderProcessor> aiProviderProcessorMap;
@Autowired
private Map<String, IEmbeddingProcessor> embeddingProcessorMap;
@Autowired
private AIProviderProcessorFactory aiProviderProcessorFactory;
@ -52,6 +55,9 @@ public class AIAssistantServiceImpl implements IAIAssistantService {
@Autowired
private ObjectMapper objectMapper;
@Autowired
private StringRedisTemplate redisTemplate;
/**
*
*
@ -129,7 +135,7 @@ public class AIAssistantServiceImpl implements IAIAssistantService {
//todo:后续从redis中获取
aiRequest.setApiKey(EncryptUtils.decryptByBase64(aiModel.getApiKey()));
aiRequest.setApiSecret(EncryptUtils.decryptByBase64(aiModel.getApiSecret()));
IUnifiedAIProviderProcessor tencentLkeProcessor = aiProviderProcessorFactory.getProcessor(aiModel.getBaseModelId());
IUnifiedAIProviderProcessor tencentLkeProcessor = aiProviderProcessorFactory.getProcessorByPlatformId(aiModel.getPlatformId());
List<Double> queryEmbedding = tencentLkeProcessor.getEmbedding(aiRequest);
int topK = aiRequest.getRetrieveLimit() == null || aiRequest.getRetrieveLimit() <= 0 ?
@ -188,30 +194,206 @@ public class AIAssistantServiceImpl implements IAIAssistantService {
}
}
/**
* sql
*
* @param aiRequest
* @return String
*/
@Override
public boolean testAIModel(String provider, AIRequest aiRequest) {
IUnifiedAIProviderProcessor processor = aiProviderProcessorMap.get(provider);
if (processor == null) {
throw new IllegalArgumentException("Unsupported processor type");
public String generateSQL(AIRequest aiRequest) {
String naturalLanguageQuery = aiRequest.getText();
// 1. 获取数据库结构
String dataName = StringUtils.isNotBlank(aiRequest.getDataName()) ? aiRequest.getDataName() : "master";
String schemaDescription = redisTemplate.opsForValue().get(HwMomAiConstants.AI_DATABASE_SCHEMA_KEY_PREFIX + dataName);
if (schemaDescription == null) {
throw new RuntimeException("请先设置AI生成SQL表信息或刷新缓存后在生成");
}
aiRequest.setModel("deepseek-chat");
String decryptApiKey = EncryptUtils.decryptByBase64(aiRequest.getApiKey());
aiRequest.setApiKey(decryptApiKey);
JSONObject schemaJson = JSONObject.parseObject(schemaDescription);
StringBuilder sb = new StringBuilder("SQL Server 数据库结构:\n\n");
schemaJson.entrySet().forEach(entry -> {
// sb.append(entry.getKey()).append("\n");
sb.append(entry.getValue()).append("\n\n");
});
// sb.append(schemaDescription);
// 2. 构建 AI 提示
String prompt = String.format(
"你是一个专业的 SQL Server 数据库专家。仅根据以下数据库结构(如果以下数据库结构中没有则返回select * from):\n\n%s\n\n" +
"请将以下自然语言查询转换为优化的 SQL Server T-SQL 语句:\n" +
"---\n%s\n---\n\n" +
"要求:\n" +
"1. 只返回 SQL 语句,不要包含解释\n" +
"2. 使用 SQL Server 特有的语法(如 TOP 而不是 LIMIT\n" +
"3. 考虑性能优化\n" +
"4. 使用合适的索引提示(如果需要)\n" +
"5. 包含必要的 WITH(NOLOCK) 提示(适用于高并发环境)\n" +
"6. 使用 ANSI 标准的 JOIN 语法 \n",
sb.toString(), naturalLanguageQuery
);
IUnifiedAIProviderProcessor processor = aiProviderProcessorFactory.getProcessorByPlatformId(aiRequest.getPlatformId());
AIMessage aiMessage = new AIMessage();
aiMessage.setRole("user");
aiMessage.setContent("这是一个测试请求,请回复'测试成功'");
aiRequest.setMessages(Collections.singletonList(
aiMessage
));
AIResponse aiResponse = processor.chat(aiRequest).block(Duration.ofSeconds(10));
if (aiResponse != null && aiResponse.isSuccess()) {
System.out.println(aiResponse.getContent());
System.out.println(aiResponse.getUsage());
aiMessage.setContent(prompt);
aiRequest.setMessages(Collections.singletonList(aiMessage));
Mono<AIResponse> response = processor.chat(aiRequest);
if (Objects.requireNonNull(response.block()).isSuccess()) {
String content = response.block().getContent().toString();
//content内容需要转换通过deepseek返回的如
// ```sql
// SELECT
// dept_id,
// tenant_id,
// parent_id,
// ancestors,
// dept_name,
// dept_category,
// order_num,
// leader,
// phone,
// email,
// status,
// del_flag,
// create_dept,
// create_by,
// create_time,
// update_by,
// update_time
// FROM sys_dept WITH(NOLOCK)
// WHERE del_flag = '0'
// ORDER BY order_num, dept_id;
//```
return extractSqlFromContent(content);
} else {
throw new RuntimeException("生成sql语句失败" + response.block().getErrorMessage());
}
return true;
}
/**
*
*/
private String getFormattedSchema() {
List<Map<String, Object>> allColumns = databaseMetaMapper.getAllTablesStructure();
Map<String, List<Map<String, Object>>> tables = allColumns.stream()
.collect(Collectors.groupingBy(
col -> (String) col.get("tableName"),
LinkedHashMap::new,
Collectors.toList()
));
StringBuilder sb = new StringBuilder("SQL Server 数据库结构:\n\n");
for (Map.Entry<String, List<Map<String, Object>>> entry : tables.entrySet()) {
String tableName = entry.getKey();
List<String> primaryKeys = databaseMetaMapper.getPrimaryKeys(tableName);
sb.append("- 表名: ").append(tableName).append("\n");
sb.append(" 主键: ").append(String.join(", ", primaryKeys)).append("\n");
sb.append(" 字段:\n");
for (Map<String, Object> column : entry.getValue()) {
sb.append(" * ")
.append(column.get("columnName"))
.append(" (").append(column.get("dataType"));
if (column.get("maxLength") != null && (short) column.get("maxLength") > 0) {
sb.append(", 长度: ").append(column.get("maxLength"));
}
if (column.get("precision") != null && (short) column.get("precision") > 0) {
sb.append(", 精度: ").append(column.get("precision"));
}
if (column.get("scale") != null && (short) column.get("scale") > 0) {
sb.append(", 小数位: ").append(column.get("scale"));
}
sb.append(column.get("nullable").equals(1) ? ", 可空" : ", 非空");
if (!((String) column.get("defaultValue")).isEmpty()) {
sb.append(", 默认值: ").append(column.get("defaultValue"));
}
if (!((String) column.get("description")).isEmpty()) {
sb.append(", 描述: ").append(column.get("description"));
}
sb.append(")\n");
}
sb.append("\n");
}
return sb.toString();
}
// 专门处理 Markdown SQL 代码块
private static String extractSqlFromContent(String content) {
// 情况1如果包含 ```sql ... ``` 格式
if (content.contains("```sql")) {
int start = content.indexOf("```sql") + 6; // 跳过 ```sql
int end = content.lastIndexOf("```");
if (end > start) {
content = content.substring(start, end).trim();
}
}
// 情况2如果只有 ``` ... ```(没有 sql 标注)
if (content.contains("```")) {
int start = content.indexOf("```") + 3;
int end = content.lastIndexOf("```");
if (end > start) {
content = content.substring(start, end).trim();
}
}
// content = extractSqlFromText(content);
content = content.replace("\\n", "\n") // 处理转义的换行符
.replace("\n", " ");
content = content.trim();
if ((content.startsWith("\"") && content.endsWith("\"")) ||
(content.startsWith("'") && content.endsWith("'"))) {
content = content.substring(1, content.length() - 1);
}
return content.trim();
}
// /**
// * 在新建AI模型或修改AI模型时测试AI模型是否可用验证apikey和apisecret等信息
// * @param provider
// * @param aiRequest
// * @return
// */
// @Override
// public boolean testAIModel(String provider, AIRequest aiRequest) {
// IUnifiedAIProviderProcessor processor = aiProviderProcessorMap.get(provider);
// if (processor == null) {
// throw new IllegalArgumentException("Unsupported processor type");
// }
// aiRequest.setModel("deepseek-chat");
// String decryptApiKey = EncryptUtils.decryptByBase64(aiRequest.getApiKey());
// aiRequest.setApiKey(decryptApiKey);
// AIMessage aiMessage = new AIMessage();
// aiMessage.setRole("user");
// aiMessage.setContent("这是一个测试请求,请仅回复'测试成功'");
// aiRequest.setMessages(Collections.singletonList(
// aiMessage
// ));
// AIResponse aiResponse = processor.chat(aiRequest).block(Duration.ofSeconds(10));
// if (aiResponse != null && aiResponse.isSuccess()) {
// System.out.println(aiResponse.getContent());
// System.out.println(aiResponse.getUsage());
// }
//
// return true;
// }
public String aiFillForm() {
@ -225,5 +407,4 @@ public class AIAssistantServiceImpl implements IAIAssistantService {
}
}

@ -0,0 +1,333 @@
package org.dromara.ai.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.dromara.ai.domain.dto.AiSqlTableDelete;
import org.dromara.ai.mapper.SQLServerDatabaseMetaMapper;
import org.dromara.ai.utils.DbSchemaUtils;
import org.dromara.common.constant.HwMomAiConstants;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.dromara.ai.domain.bo.AiSqlTableBo;
import org.dromara.ai.domain.vo.AiSqlTableVo;
import org.dromara.ai.domain.AiSqlTable;
import org.dromara.ai.mapper.AiSqlTableMapper;
import org.dromara.ai.service.IAiSqlTableService;
import java.util.*;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.anyline.metadata.Column;
import org.anyline.metadata.Table;
import org.anyline.proxy.ServiceProxy;
import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.file.FileUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* AIsqlService
*
* @author xins
* @date 2025-09-04
*/
@RequiredArgsConstructor
@Service
public class AiSqlTableServiceImpl implements IAiSqlTableService {
private static final String[] TABLE_IGNORE = new String[]{"sj_", "act_", "flw_", "gen_"};
private final AiSqlTableMapper baseMapper;
private final SQLServerDatabaseMetaMapper sqlServerDatabaseMetaMapper;
private final StringRedisTemplate redisTemplate;
/**
* AIsql
*
* @param tableId
* @return AIsql
*/
@Override
public AiSqlTableVo queryById(Long tableId) {
return baseMapper.selectVoById(tableId);
}
/**
* AIsql
*
* @param bo
* @param pageQuery
* @return AIsql
*/
@Override
public TableDataInfo<AiSqlTableVo> queryPageList(AiSqlTableBo bo, PageQuery pageQuery) {
MPJLambdaWrapper<AiSqlTable> lqw = buildQueryWrapper(bo);
Page<AiSqlTableVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* AIsql
*
* @param bo
* @return AIsql
*/
@Override
public List<AiSqlTableVo> queryList(AiSqlTableBo bo) {
MPJLambdaWrapper<AiSqlTable> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private MPJLambdaWrapper<AiSqlTable> buildQueryWrapper(AiSqlTableBo bo) {
Map<String, Object> params = bo.getParams();
MPJLambdaWrapper<AiSqlTable> lqw = JoinWrappers.lambda(AiSqlTable.class)
.selectAll(AiSqlTable.class)
.eq(bo.getTableId() != null, AiSqlTable::getTableId, bo.getTableId())
.like(StringUtils.isNotBlank(bo.getTableName()), AiSqlTable::getTableName, bo.getTableName())
.like(StringUtils.isNotBlank(bo.getTableComment()), AiSqlTable::getTableComment, bo.getTableComment())
.like(StringUtils.isNotBlank(bo.getSubTableName()), AiSqlTable::getSubTableName, bo.getSubTableName())
.like(StringUtils.isNotBlank(bo.getSubTableFkName()), AiSqlTable::getSubTableFkName, bo.getSubTableFkName())
.orderByDesc(AiSqlTable::getCreateTime);
return lqw;
}
/**
* AIsql
*
* @param bo AIsql
* @return
*/
@Override
public Boolean insertByBo(AiSqlTableBo bo) {
AiSqlTable add = MapstructUtils.convert(bo, AiSqlTable.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setTableId(add.getTableId());
}
return flag;
}
/**
* AIsql
*
* @param bo AIsql
* @return
*/
@Override
public Boolean updateByBo(AiSqlTableBo bo) {
AiSqlTable update = MapstructUtils.convert(bo, AiSqlTable.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
*
*/
private void validEntityBeforeSave(AiSqlTable entity) {
//TODO 做一些数据校验,如唯一约束
}
/**
* AIsql
*
* @param ids
* @param isValid
* @return
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
/**
*
*
* @param aiSqlTableBo AiSqlTableBo
* @param pageQuery PageQuery
* @return TableDataInfo
*/
@DS("#aiSqlTableBo.dataName")
@Override
public TableDataInfo<AiSqlTable> selectPageDbTableList(AiSqlTableBo aiSqlTableBo, PageQuery pageQuery) {
// 获取查询条件
String tableName = aiSqlTableBo.getTableName();
String tableComment = aiSqlTableBo.getTableComment();
LinkedHashMap<String, Table<?>> tablesMap = ServiceProxy.metadata().tables();
if (CollUtil.isEmpty(tablesMap)) {
return TableDataInfo.build();
}
List<String> tableNames = baseMapper.selectTableNameList(aiSqlTableBo.getDataName());
String[] tableArrays;
if (CollUtil.isNotEmpty(tableNames)) {
tableArrays = tableNames.toArray(new String[0]);
} else {
tableArrays = new String[0];
}
// 过滤并转换表格数据
List<AiSqlTable> tables = tablesMap.values().stream()
.filter(x -> !startWithAnyIgnoreCase(x.getName(), TABLE_IGNORE))
.filter(x -> {
if (CollUtil.isEmpty(tableNames)) {
return true;
}
return !StringUtils.equalsAnyIgnoreCase(x.getName(), tableArrays);
})
.filter(x -> {
boolean nameMatches = true;
boolean commentMatches = true;
// 进行表名称的模糊查询
if (StringUtils.isNotBlank(tableName)) {
nameMatches = StringUtils.containsIgnoreCase(x.getName(), tableName);
}
// 进行表描述的模糊查询
if (StringUtils.isNotBlank(tableComment)) {
commentMatches = StringUtils.containsIgnoreCase(x.getComment(), tableComment);
}
// 同时匹配名称和描述
return nameMatches && commentMatches;
})
.map(x -> {
AiSqlTable gen = new AiSqlTable();
gen.setTableName(x.getName());
gen.setTableComment(x.getComment());
gen.setCreateTime(x.getCreateTime());
gen.setUpdateTime(x.getUpdateTime());
return gen;
}).toList();
IPage<AiSqlTable> page = pageQuery.build();
page.setTotal(tables.size());
// 手动分页 set数据
page.setRecords(CollUtil.page((int) page.getCurrent() - 1, (int) page.getSize(), tables));
return TableDataInfo.build(page);
}
public static boolean startWithAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) {
// 判断是否是以指定字符串开头
for (CharSequence searchCharSequence : searchCharSequences) {
if (StringUtils.startsWithIgnoreCase(cs, searchCharSequence)) {
return true;
}
}
return false;
}
/**
*
*
* @param aiSqlTableList
*/
@DSTransactional
@Override
public boolean importAiSqlTable(List<AiSqlTable> aiSqlTableList) {
AiSqlTable aiSqlTable = aiSqlTableList.get(0);
String dbSchema = redisTemplate.opsForValue().get(HwMomAiConstants.AI_DATABASE_SCHEMA_KEY_PREFIX + aiSqlTable.getDataName());
JSONObject dbSchemaJson;
if (dbSchema == null) {
dbSchemaJson = new JSONObject();
} else {
dbSchemaJson = JSON.parseObject(dbSchema);
}
getTableSchema(dbSchemaJson, aiSqlTableList);
return baseMapper.insertBatch(aiSqlTableList);
}
/**
*
*/
@Override
public void refreshCache() {
JSONObject dbSchemaJson = new JSONObject();
List<AiSqlTable> aiSqlTableList = baseMapper.selectList();
getTableSchema(dbSchemaJson, aiSqlTableList);
}
/**
* AIsql
* @param aiSqlTableDeleteList
*/
@Override
public void deleteAiSqlTable(List<AiSqlTableDelete> aiSqlTableDeleteList) {
List<Long> tableIds = aiSqlTableDeleteList.stream().map(AiSqlTableDelete::getTableId).collect(Collectors.toList());
baseMapper.deleteByIds(tableIds);
String dataName = aiSqlTableDeleteList.get(0).getDataName();
String dbSchema = redisTemplate.opsForValue().get(HwMomAiConstants.AI_DATABASE_SCHEMA_KEY_PREFIX + dataName);
if (StringUtils.isNotBlank(dbSchema)) {
JSONObject dbSchemaJson = JSON.parseObject(dbSchema);
for (AiSqlTableDelete aiSqlTableDelete : aiSqlTableDeleteList) {
String tableName = aiSqlTableDelete.getTableName();
dbSchemaJson.remove(tableName);
}
redisTemplate.opsForValue().set(HwMomAiConstants.AI_DATABASE_SCHEMA_KEY_PREFIX + dataName,dbSchemaJson.toJSONString());
}
}
private void getTableSchema(JSONObject dbSchemaJson, List<AiSqlTable> aiSqlTableList) {
String dataName = aiSqlTableList.get(0).getDataName();
for (AiSqlTable aiSqlTable : aiSqlTableList) {
String tableName = aiSqlTable.getTableName();
List<Map<String, Object>> tableStructures = sqlServerDatabaseMetaMapper.getTableStructure(tableName);
List<String> primaryKeys = sqlServerDatabaseMetaMapper.getPrimaryKeys(tableName);
String schema = DbSchemaUtils.getFormatSchema(tableName, aiSqlTable.getTableComment(), tableStructures, primaryKeys);
dbSchemaJson.put(tableName, schema);
}
redisTemplate.opsForValue().set(HwMomAiConstants.AI_DATABASE_SCHEMA_KEY_PREFIX + dataName, dbSchemaJson.toJSONString());
}
}

@ -1,7 +1,6 @@
package org.dromara.ai.service.impl;
import org.dromara.ai.mapper.DatabaseMetaMapper;
import org.dromara.ai.process.provider.processor.impl.DeepSeekProcessor;
import org.dromara.ai.mapper.SQLServerDatabaseMetaMapper;
import org.dromara.ai.test.ChatRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -20,10 +19,7 @@ import java.util.stream.Collectors;
public class DatabaseMetaServiceImpl {
@Autowired
private DatabaseMetaMapper databaseMetaMapper;
@Autowired
private DeepSeekProcessor deepSeekService;
private SQLServerDatabaseMetaMapper databaseMetaMapper;
/**
*
@ -81,20 +77,6 @@ public class DatabaseMetaServiceImpl {
return sb.toString();
}
/**
*
*/
public Map<String, Object> getTableDetail(String tableName) {
Map<String, Object> result = new LinkedHashMap<>();
result.put("tableName", tableName);
result.put("primaryKeys", databaseMetaMapper.getPrimaryKeys(tableName));
result.put("columns", databaseMetaMapper.getTableStructure(tableName));
return result;
}
public String generateSQL(String naturalLanguageQuery) {
// 1. 获取数据库结构
@ -118,52 +100,25 @@ public class DatabaseMetaServiceImpl {
ChatRequest chatRequest = new ChatRequest();
chatRequest.setPrompt(prompt);
// Mono<String> dd = deepSeekService.getStandardResponse(chatRequest);
// dd.subscribe(System.out::println);
// dd.subscribe(
// response -> {
// System.out.println("\n=== 完整响应 ===");
// if (response.getChoices() != null && !response.getChoices().isEmpty()) {
// System.out.println(response.getChoices().get(0).getText());
// }
// System.out.println("=== 响应结束 ===");
// },
// error -> System.err.println("调用失败: " + error.getMessage())
// );
// System.out.println(d);
// d.subscribe(
// data -> System.out.println("Received: " + data),
// error -> System.err.println("Error: " + error),
// () -> System.out.println("Stream completed")
// );
return prompt;
// // 3. 调用 DeepSeek API
// HttpHeaders headers = new HttpHeaders();
// headers.setContentType(MediaType.APPLICATION_JSON);
// headers.set("Authorization", "Bearer " + apiKey);
//
// Map<String, Object> request = new HashMap<>();
// request.put("model", "deepseek-chat");
// request.put("messages", List.of(Map.of("role", "user", "content", prompt)));
// request.put("temperature", 0.3); // 降低随机性以获得更确定的 SQL
//
// HttpEntity<Map<String, Object>> entity = new HttpEntity<>(request, headers);
//
// try {
// ResponseEntity<Map> response = restTemplate.exchange(
// apiUrl, HttpMethod.POST, entity, Map.class);
//
// if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
// return extractSqlFromResponse(response.getBody());
// }
// throw new RuntimeException("API 调用失败,状态码: " + response.getStatusCode());
// } catch (Exception e) {
// throw new RuntimeException("生成 SQL 失败: " + e.getMessage(), e);
// }
}
/**
*
*/
public Map<String, Object> getTableDetail(String tableName) {
Map<String, Object> result = new LinkedHashMap<>();
result.put("tableName", tableName);
result.put("primaryKeys", databaseMetaMapper.getPrimaryKeys(tableName));
result.put("columns", databaseMetaMapper.getTableStructure(tableName));
return result;
}
public String generateSQL1(String naturalLanguageQuery) {
// 1. 获取数据库结构

@ -0,0 +1,54 @@
package org.dromara.ai.utils;
import java.util.List;
import java.util.Map;
/**
* @Author xins
* @Date 2025/9/5 13:30
* @Description:
*/
public class DbSchemaUtils {
public static String getFormatSchema(String tableName, String tableComment,List<Map<String, Object>> columns, List<String> primaryKeys) {
StringBuilder sb = new StringBuilder();
sb.append("- 表名: ").append(tableName).append("\n");
sb.append(" 主键: ").append(String.join(", ", primaryKeys)).append("\n");
sb.append(" 表描述: ").append(tableComment).append("\n");
sb.append(" 字段:\n");
for (Map<String, Object> column : columns) {
sb.append(" * ")
.append(column.get("columnName"))
.append(" (").append(column.get("dataType"));
if (column.get("maxLength") != null && (short) column.get("maxLength") > 0) {
sb.append(", 长度: ").append(column.get("maxLength"));
}
if (column.get("precision") != null && (short) column.get("precision") > 0) {
sb.append(", 精度: ").append(column.get("precision"));
}
if (column.get("scale") != null && (short) column.get("scale") > 0) {
sb.append(", 小数位: ").append(column.get("scale"));
}
sb.append(column.get("nullable").equals(1) ? ", 可空" : ", 非空");
if (!((String) column.get("defaultValue")).isEmpty()) {
sb.append(", 默认值: ").append(column.get("defaultValue"));
}
if (!((String) column.get("description")).isEmpty()) {
sb.append(", 描述: ").append(column.get("description"));
}
sb.append(")\n");
}
sb.append("\n");
return sb.toString();
}
}

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.ai.mapper.AiSqlTableMapper">
<select id="selectTableNameList" resultType="java.lang.String">
select table_name from ai_sql_table where data_name = #{dataName,jdbcType=VARCHAR}
</select>
</mapper>

@ -2,11 +2,12 @@
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.ai.mapper.DatabaseMetaMapper">
<mapper namespace="org.dromara.ai.mapper.SQLServerDatabaseMetaMapper">
<!-- 获取指定表的结构信息 -->
<select id="getTableStructure" resultType="map">
SELECT
OBJECT_NAME(c.object_id) AS tableName,
c.name AS columnName,
t.name AS dataType,
c.max_length AS maxLength,
@ -14,7 +15,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
c.scale,
c.is_nullable AS nullable,
ISNULL(OBJECT_DEFINITION(c.default_object_id), '') AS defaultValue,
ep.value AS description
ISNULL(ep.value, '') AS description
FROM sys.columns c
JOIN sys.types t ON c.user_type_id = t.user_type_id
LEFT JOIN sys.extended_properties ep ON
@ -43,8 +44,35 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
ep.major_id = c.object_id AND
ep.minor_id = c.column_id AND
ep.name = 'MS_Description'
WHERE OBJECT_NAME(c.object_id) IN (SELECT name FROM hwmom.sys.tables where name='sys_user')
WHERE OBJECT_NAME(c.object_id) IN (SELECT name FROM hwmom.sys.tables where name like 'sys%' or name like 'prod%' or name like 'base%' or name like 'wms%' or name like 'dms%')
ORDER BY tableName, c.column_id
</select>
<select id="getTablesStructureByTableNames" resultType="map">
SELECT
OBJECT_NAME(c.object_id) AS tableName,
c.name AS columnName,
t.name AS dataType,
c.max_length AS maxLength,
c.precision,
c.scale,
c.is_nullable AS nullable,
ISNULL(OBJECT_DEFINITION(c.default_object_id), '') AS defaultValue,
ISNULL(ep.value, '') AS description
FROM sys.columns c
JOIN sys.types t ON c.user_type_id = t.user_type_id
LEFT JOIN sys.extended_properties ep ON
ep.major_id = c.object_id AND
ep.minor_id = c.column_id AND
ep.name = 'MS_Description'
WHERE OBJECT_NAME(c.object_id) IN
<foreach item="tableName" collection="array" open="(" separator="," close=")">
#{tableName}
</foreach>
ORDER BY tableName, c.column_id
</select>
</mapper>

@ -123,4 +123,12 @@ public class WmsInventory {
*/
@TableField(exist = false)
private Long aoDId;//字段映射
/**
* wms
*/
@TableField(exist = false)
private Long maxParkingTime;
}

@ -135,4 +135,9 @@ public class WmsInventoryVo implements Serializable {
*
*/
private String warehouseName;
/**
* wms
*/
private Long maxParkingTime;
}

@ -85,7 +85,7 @@ public class WmsInventoryServiceImpl implements IWmsInventoryService {
.selectAll(WmsInventory.class)
// 关联表查询物料
.select(BaseMaterialInfo::getMaterialCode, BaseMaterialInfo::getMaterialName)
.select(BaseMaterialInfo::getMaterialCode, BaseMaterialInfo::getMaterialName, BaseMaterialInfo::getMaxParkingTime)
.leftJoin(BaseMaterialInfo.class, BaseMaterialInfo::getMaterialId, WmsInventory::getMaterialId)
// 关联表查询物料大类名称
.select(BaseMaterialCategory::getMaterialCategoryName)
@ -113,7 +113,7 @@ public class WmsInventoryServiceImpl implements IWmsInventoryService {
.selectAll(WmsInventory.class)
// 关联表查询物料
.select(BaseMaterialInfo::getMaterialCode, BaseMaterialInfo::getMaterialName)
.select(BaseMaterialInfo::getMaterialCode, BaseMaterialInfo::getMaterialName, BaseMaterialInfo::getMaxParkingTime)
.leftJoin(BaseMaterialInfo.class, BaseMaterialInfo::getMaterialId, WmsInventory::getMaterialId)
// 关联表查询物料大类名称
.select(BaseMaterialCategory::getMaterialCategoryName)

@ -29,6 +29,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
MAX(c.warehouse_name) warehouse_name,
MAX(b.material_code) material_code,
MAX(b.material_name) material_name,
MAX(b.max_parking_time) max_parking_time,
MAX(x.lock_state) lock_state,
MAX(x.material_categories) material_categories,
MAX(x.location_code) locationCode,
@ -70,6 +71,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
MAX(b.max_stock_amount) max_stock_amount,
MAX(b.material_code) material_code,
MAX(b.material_name) material_name,
MAX(b.max_parking_time) max_parking_time,
-- MAX(x.material_categories) material_categories,
-- MAX(bmc.material_category_name) material_category_name,
MAX(x.lock_state) lock_state
@ -158,6 +160,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
bmi.material_name,
bmi.material_spec,
bmi.material_unit,
bmi.max_parking_time,
wbw.warehouse_code,
wbw.warehouse_name,
wbw.warehouse_id,
@ -212,6 +215,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
bmi.material_name,
bmi.material_spec,
bmi.material_unit,
bmi.max_parking_time,
wbw.warehouse_code,
wbw.warehouse_name,
woo.warehouse_id,
@ -270,6 +274,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
icr.material_name,
bmi.material_spec,
bmi.material_unit,
bmi.max_parking_time,
'' as warehouse_code,
'' as warehouse_name,
NULL as warehouse_id
@ -321,6 +326,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
bmi.material_name,
bmi.material_spec,
bmi.material_unit,
bmi.max_parking_time,
wbw.warehouse_code,
wbw.warehouse_name,
ro.warehouse_id,
@ -376,6 +382,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
bmi.material_name,
bmi.material_spec,
bmi.material_unit,
bmi.max_parking_time,
'' as warehouse_code,
'' as warehouse_name,
NULL as warehouse_id

Loading…
Cancel
Save