* feat(mcp): 新增gva_review工具并优化字典和代码生成逻辑 * fix: 调整mcp整体逻辑 * chore: 更新.gitignore,添加对本地配置文件的忽略 * feat(logo): 新增Logo组件并在多个页面中替换原有logo实现 * fix: 修复菜单 Logo 部分删除文本后显示异常的问题 * fix:添加字典列表搜索,支持中英文搜索.添加字典详情搜索 * style: 优化部分视觉样式 * feat: 增强错误预览组件的暗黑模式支持 * feat: 优化请求错误消息获取逻辑,增加状态文本优先级 * feat: 添加前端登录验证码静态验证逻辑 * feat: 添加开发环境启动脚本 * feat: 更新 SvgIcon 组件,支持本地图标和 Iconify 图标、移除未使用的 unocss 依赖 * fix:字典支持 tree 结构 * feat: 优化动态路由注册方式 * feat: 添加配置控制标签页keep-alive功能 * feat: 添加全局错误处理机制,捕获 Vue 和 JS 错误 * refactor: 移除API和菜单创建结果中的权限分配提醒,优化输出信息 * feat: 更新 reset.scss,优化全局样式重置,增强兼容性和可读性 * refactor(字典详情): 优化字典详情查询逻辑,移除预加载改为按需加载 * refactor(路由管理): 优化路由添加逻辑,增强路径处理和顶级路由注册 * refactor(系统配置): 将auto-migrate修改为disable-auto-migrate,保证用户升级的兼容性 * feat(utils): 优化字典数据递归查找功能并替换select为tree-select * fix(deps): 修复在字段类型为file生成搜索条件无法运行的bug * fix: 修复header的tools中icon不展示的问题 --------- Co-authored-by: piexlMax(奇淼 <qimiaojiangjizhao@gmail.com> Co-authored-by: Azir-11 <2075125282@qq.com> Co-authored-by: bypanghu <bypanghu@163.com> Co-authored-by: feitianbubu <feitianbubu@qq.com> Co-authored-by: 青菜白玉汤 <79054161+Azir-11@users.noreply.github.com> Co-authored-by: krank <emosick@qq.com>
240 lines
6.6 KiB
Go
240 lines
6.6 KiB
Go
package mcpTool
|
||
|
||
import (
|
||
"context"
|
||
"encoding/json"
|
||
"fmt"
|
||
|
||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
|
||
"github.com/flipped-aurora/gin-vue-admin/server/service"
|
||
"github.com/mark3labs/mcp-go/mcp"
|
||
"go.uber.org/zap"
|
||
"gorm.io/gorm"
|
||
)
|
||
|
||
// 注册工具
|
||
func init() {
|
||
RegisterTool(&DictionaryQuery{})
|
||
}
|
||
|
||
type DictionaryPre struct {
|
||
Type string `json:"type"` // 字典名(英)
|
||
Desc string `json:"desc"` // 描述
|
||
}
|
||
|
||
// DictionaryInfo 字典信息结构
|
||
type DictionaryInfo struct {
|
||
ID uint `json:"id"`
|
||
Name string `json:"name"` // 字典名(中)
|
||
Type string `json:"type"` // 字典名(英)
|
||
Status *bool `json:"status"` // 状态
|
||
Desc string `json:"desc"` // 描述
|
||
Details []DictionaryDetailInfo `json:"details"` // 字典详情
|
||
}
|
||
|
||
// DictionaryDetailInfo 字典详情信息结构
|
||
type DictionaryDetailInfo struct {
|
||
ID uint `json:"id"`
|
||
Label string `json:"label"` // 展示值
|
||
Value string `json:"value"` // 字典值
|
||
Extend string `json:"extend"` // 扩展值
|
||
Status *bool `json:"status"` // 启用状态
|
||
Sort int `json:"sort"` // 排序标记
|
||
}
|
||
|
||
// DictionaryQueryResponse 字典查询响应结构
|
||
type DictionaryQueryResponse struct {
|
||
Success bool `json:"success"`
|
||
Message string `json:"message"`
|
||
Total int `json:"total"`
|
||
Dictionaries []DictionaryInfo `json:"dictionaries"`
|
||
}
|
||
|
||
// DictionaryQuery 字典查询工具
|
||
type DictionaryQuery struct{}
|
||
|
||
// New 创建字典查询工具
|
||
func (d *DictionaryQuery) New() mcp.Tool {
|
||
return mcp.NewTool("query_dictionaries",
|
||
mcp.WithDescription("查询系统中所有的字典和字典属性,用于AI生成逻辑时了解可用的字典选项"),
|
||
mcp.WithString("dictType",
|
||
mcp.Description("可选:指定字典类型进行精确查询,如果不提供则返回所有字典"),
|
||
),
|
||
mcp.WithBoolean("includeDisabled",
|
||
mcp.Description("是否包含已禁用的字典和字典项,默认为false(只返回启用的)"),
|
||
),
|
||
mcp.WithBoolean("detailsOnly",
|
||
mcp.Description("是否只返回字典详情信息(不包含字典基本信息),默认为false"),
|
||
),
|
||
)
|
||
}
|
||
|
||
// Handle 处理字典查询请求
|
||
func (d *DictionaryQuery) Handle(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||
args := request.GetArguments()
|
||
|
||
// 获取参数
|
||
dictType := ""
|
||
if val, ok := args["dictType"].(string); ok {
|
||
dictType = val
|
||
}
|
||
|
||
includeDisabled := false
|
||
if val, ok := args["includeDisabled"].(bool); ok {
|
||
includeDisabled = val
|
||
}
|
||
|
||
detailsOnly := false
|
||
if val, ok := args["detailsOnly"].(bool); ok {
|
||
detailsOnly = val
|
||
}
|
||
|
||
// 获取字典服务
|
||
dictionaryService := service.ServiceGroupApp.SystemServiceGroup.DictionaryService
|
||
|
||
var dictionaries []DictionaryInfo
|
||
var err error
|
||
|
||
if dictType != "" {
|
||
// 查询指定类型的字典
|
||
var status *bool
|
||
if !includeDisabled {
|
||
status = &[]bool{true}[0]
|
||
}
|
||
|
||
sysDictionary, err := dictionaryService.GetSysDictionary(dictType, 0, status)
|
||
if err != nil {
|
||
global.GVA_LOG.Error("查询字典失败", zap.Error(err))
|
||
return &mcp.CallToolResult{
|
||
Content: []mcp.Content{
|
||
mcp.NewTextContent(fmt.Sprintf(`{"success": false, "message": "查询字典失败: %v", "total": 0, "dictionaries": []}`, err.Error())),
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// 转换为响应格式
|
||
dictInfo := DictionaryInfo{
|
||
ID: sysDictionary.ID,
|
||
Name: sysDictionary.Name,
|
||
Type: sysDictionary.Type,
|
||
Status: sysDictionary.Status,
|
||
Desc: sysDictionary.Desc,
|
||
}
|
||
|
||
// 获取字典详情
|
||
for _, detail := range sysDictionary.SysDictionaryDetails {
|
||
if includeDisabled || (detail.Status != nil && *detail.Status) {
|
||
dictInfo.Details = append(dictInfo.Details, DictionaryDetailInfo{
|
||
ID: detail.ID,
|
||
Label: detail.Label,
|
||
Value: detail.Value,
|
||
Extend: detail.Extend,
|
||
Status: detail.Status,
|
||
Sort: detail.Sort,
|
||
})
|
||
}
|
||
}
|
||
|
||
dictionaries = append(dictionaries, dictInfo)
|
||
} else {
|
||
// 查询所有字典
|
||
var sysDictionaries []system.SysDictionary
|
||
db := global.GVA_DB.Model(&system.SysDictionary{})
|
||
|
||
if !includeDisabled {
|
||
db = db.Where("status = ?", true)
|
||
}
|
||
|
||
err = db.Preload("SysDictionaryDetails", func(db *gorm.DB) *gorm.DB {
|
||
if includeDisabled {
|
||
return db.Order("sort")
|
||
} else {
|
||
return db.Where("status = ?", true).Order("sort")
|
||
}
|
||
}).Find(&sysDictionaries).Error
|
||
|
||
if err != nil {
|
||
global.GVA_LOG.Error("查询字典列表失败", zap.Error(err))
|
||
return &mcp.CallToolResult{
|
||
Content: []mcp.Content{
|
||
mcp.NewTextContent(fmt.Sprintf(`{"success": false, "message": "查询字典列表失败: %v", "total": 0, "dictionaries": []}`, err.Error())),
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// 转换为响应格式
|
||
for _, dict := range sysDictionaries {
|
||
dictInfo := DictionaryInfo{
|
||
ID: dict.ID,
|
||
Name: dict.Name,
|
||
Type: dict.Type,
|
||
Status: dict.Status,
|
||
Desc: dict.Desc,
|
||
}
|
||
|
||
// 获取字典详情
|
||
for _, detail := range dict.SysDictionaryDetails {
|
||
if includeDisabled || (detail.Status != nil && *detail.Status) {
|
||
dictInfo.Details = append(dictInfo.Details, DictionaryDetailInfo{
|
||
ID: detail.ID,
|
||
Label: detail.Label,
|
||
Value: detail.Value,
|
||
Extend: detail.Extend,
|
||
Status: detail.Status,
|
||
Sort: detail.Sort,
|
||
})
|
||
}
|
||
}
|
||
|
||
dictionaries = append(dictionaries, dictInfo)
|
||
}
|
||
}
|
||
|
||
// 如果只需要详情信息,则提取所有详情
|
||
if detailsOnly {
|
||
var allDetails []DictionaryDetailInfo
|
||
for _, dict := range dictionaries {
|
||
allDetails = append(allDetails, dict.Details...)
|
||
}
|
||
|
||
response := map[string]interface{}{
|
||
"success": true,
|
||
"message": "查询字典详情成功",
|
||
"total": len(allDetails),
|
||
"details": allDetails,
|
||
}
|
||
|
||
responseJSON, _ := json.Marshal(response)
|
||
return &mcp.CallToolResult{
|
||
Content: []mcp.Content{
|
||
mcp.NewTextContent(string(responseJSON)),
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// 构建响应
|
||
response := DictionaryQueryResponse{
|
||
Success: true,
|
||
Message: "查询字典成功",
|
||
Total: len(dictionaries),
|
||
Dictionaries: dictionaries,
|
||
}
|
||
|
||
responseJSON, err := json.Marshal(response)
|
||
if err != nil {
|
||
global.GVA_LOG.Error("序列化响应失败", zap.Error(err))
|
||
return &mcp.CallToolResult{
|
||
Content: []mcp.Content{
|
||
mcp.NewTextContent(fmt.Sprintf(`{"success": false, "message": "序列化响应失败: %v", "total": 0, "dictionaries": []}`, err.Error())),
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
return &mcp.CallToolResult{
|
||
Content: []mcp.Content{
|
||
mcp.NewTextContent(string(responseJSON)),
|
||
},
|
||
}, nil
|
||
}
|