Compare commits
10 Commits
3f21d7f8dd
...
1d700ad5b6
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1d700ad5b6 | ||
![]() |
3648df9522 | ||
![]() |
eb2925829f | ||
![]() |
1e3c968277 | ||
![]() |
339db778c3 | ||
![]() |
8b8ae7b692 | ||
![]() |
52be26eb43 | ||
![]() |
9f958addc8 | ||
![]() |
7a69b88885 | ||
![]() |
76fe71a8dd |
@@ -22,7 +22,8 @@
|
|||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td width="200">
|
<td width="250">
|
||||||
|
<p>⭐️ <a href="https://www.bilibili.com/video/BV1B3htzqEf1/?spm_id_from=333.1387.homepage.video_card.click" target="__blank"> 高度适配AI编辑器的MCP </a></p>
|
||||||
<p>📄 创建基础模板</p>
|
<p>📄 创建基础模板</p>
|
||||||
<p>🤖 AI生成结构</p>
|
<p>🤖 AI生成结构</p>
|
||||||
<p>⏰ 生成代码</p>
|
<p>⏰ 生成代码</p>
|
||||||
|
@@ -2,107 +2,103 @@
|
|||||||
|
|
||||||
# jwt configuration
|
# jwt configuration
|
||||||
jwt:
|
jwt:
|
||||||
signing-key: qmPlus
|
signing-key: qmPlus
|
||||||
expires-time: 7d
|
expires-time: 7d
|
||||||
buffer-time: 1d
|
buffer-time: 1d
|
||||||
issuer: qmPlus
|
issuer: qmPlus
|
||||||
# zap logger configuration
|
# zap logger configuration
|
||||||
zap:
|
zap:
|
||||||
level: info
|
level: info
|
||||||
format: console
|
format: console
|
||||||
prefix: "[github.com/flipped-aurora/gin-vue-admin/server]"
|
prefix: "[github.com/flipped-aurora/gin-vue-admin/server]"
|
||||||
director: log
|
director: log
|
||||||
show-line: true
|
show-line: true
|
||||||
encode-level: LowercaseColorLevelEncoder
|
encode-level: LowercaseColorLevelEncoder
|
||||||
stacktrace-key: stacktrace
|
stacktrace-key: stacktrace
|
||||||
log-in-console: true
|
log-in-console: true
|
||||||
|
retention-day: -1
|
||||||
|
|
||||||
# redis configuration
|
# redis configuration
|
||||||
redis:
|
redis:
|
||||||
db: 0
|
#是否使用redis集群模式
|
||||||
addr: 177.7.0.14:6379
|
useCluster: false
|
||||||
password: ""
|
#使用集群模式addr和db默认无效
|
||||||
|
addr: 177.7.0.14:6379
|
||||||
|
password: ""
|
||||||
|
db: 0
|
||||||
|
clusterAddrs:
|
||||||
|
- "177.7.0.14:7000"
|
||||||
|
- "177.7.0.15:7001"
|
||||||
|
- "177.7.0.13:7002"
|
||||||
|
|
||||||
|
# redis-list configuration
|
||||||
|
redis-list:
|
||||||
|
- name: cache # 数据库的名称,注意: name 需要在 redis-list 中唯一
|
||||||
|
useCluster: false # 是否使用redis集群模式
|
||||||
|
addr: 177.7.0.14:6379 # 使用集群模式addr和db默认无效
|
||||||
|
password: ""
|
||||||
|
db: 0
|
||||||
|
clusterAddrs:
|
||||||
|
- "177.7.0.14:7000"
|
||||||
|
- "177.7.0.15:7001"
|
||||||
|
- "177.7.0.13:7002"
|
||||||
|
|
||||||
# mongo configuration
|
# mongo configuration
|
||||||
mongo:
|
mongo:
|
||||||
coll: ''
|
coll: ''
|
||||||
options: ''
|
options: ''
|
||||||
database: ''
|
database: ''
|
||||||
username: ''
|
username: ''
|
||||||
password: ''
|
password: ''
|
||||||
min-pool-size: 0
|
auth-source: ''
|
||||||
max-pool-size: 100
|
min-pool-size: 0
|
||||||
socket-timeout-ms: 0
|
max-pool-size: 100
|
||||||
connect-timeout-ms: 0
|
socket-timeout-ms: 0
|
||||||
is-zap: false
|
connect-timeout-ms: 0
|
||||||
hosts:
|
is-zap: false
|
||||||
- host: ''
|
hosts:
|
||||||
port: ''
|
- host: ''
|
||||||
|
port: ''
|
||||||
|
|
||||||
# email configuration
|
# email configuration
|
||||||
email:
|
email:
|
||||||
to: xxx@qq.com
|
to: xxx@qq.com
|
||||||
port: 465
|
port: 465
|
||||||
from: xxx@163.com
|
from: xxx@163.com
|
||||||
host: smtp.163.com
|
host: smtp.163.com
|
||||||
is-ssl: true
|
is-ssl: true
|
||||||
secret: xxx
|
secret: xxx
|
||||||
nickname: test
|
nickname: test
|
||||||
|
|
||||||
# system configuration
|
# system configuration
|
||||||
system:
|
system:
|
||||||
env: public # Change to "develop" to skip authentication for development mode
|
env: local # 修改为public可以关闭路由日志输出
|
||||||
addr: 8888
|
addr: 8888
|
||||||
db-type: mysql
|
db-type: mysql
|
||||||
oss-type: local # 控制oss选择走本地还是 七牛等其他仓 自行增加其他oss仓可以在 server/utils/upload/upload.go 中 NewOss函数配置
|
oss-type: local # 控制oss选择走本地还是 七牛等其他仓 自行增加其他oss仓可以在 server/utils/upload/upload.go 中 NewOss函数配置
|
||||||
use-redis: false # 使用redis
|
use-redis: false # 使用redis
|
||||||
use-mongo: false # 使用mongo
|
use-mongo: false # 使用mongo
|
||||||
use-multipoint: false
|
use-multipoint: false
|
||||||
# IP限制次数 一个小时15000次
|
# IP限制次数 一个小时15000次
|
||||||
iplimit-count: 15000
|
iplimit-count: 15000
|
||||||
# IP限制一个小时
|
# IP限制一个小时
|
||||||
iplimit-time: 3600
|
iplimit-time: 3600
|
||||||
|
# 路由全局前缀
|
||||||
|
router-prefix: ""
|
||||||
|
# 严格角色模式 打开后权限将会存在上下级关系
|
||||||
|
use-strict-auth: false
|
||||||
|
|
||||||
# captcha configuration
|
# captcha configuration
|
||||||
captcha:
|
captcha:
|
||||||
key-long: 6
|
key-long: 6
|
||||||
img-width: 240
|
img-width: 240
|
||||||
img-height: 80
|
img-height: 80
|
||||||
open-captcha: 0 # 0代表一直开启,大于0代表限制次数
|
open-captcha: 0 # 0代表一直开启,大于0代表限制次数
|
||||||
open-captcha-timeout: 3600 # open-captcha大于0时才生效
|
open-captcha-timeout: 3600 # open-captcha大于0时才生效
|
||||||
|
|
||||||
# mysql connect configuration
|
# mysql connect configuration
|
||||||
# 未初始化之前请勿手动修改数据库信息!!!如果一定要手动初始化请看(https://gin-vue-admin.com/docs/first_master)
|
# 未初始化之前请勿手动修改数据库信息!!!如果一定要手动初始化请看(https://gin-vue-admin.com/docs/first_master)
|
||||||
mysql:
|
mysql:
|
||||||
path: ""
|
|
||||||
port: ""
|
|
||||||
config: ""
|
|
||||||
db-name: ""
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
max-idle-conns: 10
|
|
||||||
max-open-conns: 100
|
|
||||||
log-mode: ""
|
|
||||||
log-zap: false
|
|
||||||
|
|
||||||
# pgsql connect configuration
|
|
||||||
# 未初始化之前请勿手动修改数据库信息!!!如果一定要手动初始化请看(https://gin-vue-admin.com/docs/first_master)
|
|
||||||
pgsql:
|
|
||||||
path: ""
|
|
||||||
port: ""
|
|
||||||
config: ""
|
|
||||||
db-name: ""
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
max-idle-conns: 10
|
|
||||||
max-open-conns: 100
|
|
||||||
log-mode: ""
|
|
||||||
log-zap: false
|
|
||||||
|
|
||||||
db-list:
|
|
||||||
- disable: true # 是否禁用
|
|
||||||
type: "" # 数据库的类型,目前支持mysql、pgsql
|
|
||||||
alias-name: "" # 数据库的名称,注意: alias-name 需要在db-list中唯一
|
|
||||||
path: ""
|
path: ""
|
||||||
port: ""
|
port: ""
|
||||||
config: ""
|
config: ""
|
||||||
@@ -114,107 +110,174 @@ db-list:
|
|||||||
log-mode: ""
|
log-mode: ""
|
||||||
log-zap: false
|
log-zap: false
|
||||||
|
|
||||||
|
# pgsql connect configuration
|
||||||
|
# 未初始化之前请勿手动修改数据库信息!!!如果一定要手动初始化请看(https://gin-vue-admin.com/docs/first_master)
|
||||||
|
pgsql:
|
||||||
|
path: ""
|
||||||
|
port: ""
|
||||||
|
config: ""
|
||||||
|
db-name: ""
|
||||||
|
username: ""
|
||||||
|
password: ""
|
||||||
|
max-idle-conns: 10
|
||||||
|
max-open-conns: 100
|
||||||
|
log-mode: ""
|
||||||
|
log-zap: false
|
||||||
|
oracle:
|
||||||
|
path: ""
|
||||||
|
port: ""
|
||||||
|
config: ""
|
||||||
|
db-name: ""
|
||||||
|
username: ""
|
||||||
|
password: ""
|
||||||
|
max-idle-conns: 10
|
||||||
|
max-open-conns: 100
|
||||||
|
log-mode: ""
|
||||||
|
log-zap: false
|
||||||
|
mssql:
|
||||||
|
path: ""
|
||||||
|
port: ""
|
||||||
|
config: ""
|
||||||
|
db-name: ""
|
||||||
|
username: ""
|
||||||
|
password: ""
|
||||||
|
max-idle-conns: 10
|
||||||
|
max-open-conns: 100
|
||||||
|
log-mode: ""
|
||||||
|
log-zap: false
|
||||||
|
sqlite:
|
||||||
|
path: ""
|
||||||
|
port: ""
|
||||||
|
config: ""
|
||||||
|
db-name: ""
|
||||||
|
username: ""
|
||||||
|
password: ""
|
||||||
|
max-idle-conns: 10
|
||||||
|
max-open-conns: 100
|
||||||
|
log-mode: ""
|
||||||
|
log-zap: false
|
||||||
|
db-list:
|
||||||
|
- disable: true # 是否禁用
|
||||||
|
type: "" # 数据库的类型,目前支持mysql、pgsql、mssql、oracle
|
||||||
|
alias-name: "" # 数据库的名称,注意: alias-name 需要在db-list中唯一
|
||||||
|
path: ""
|
||||||
|
port: ""
|
||||||
|
config: ""
|
||||||
|
db-name: ""
|
||||||
|
username: ""
|
||||||
|
password: ""
|
||||||
|
max-idle-conns: 10
|
||||||
|
max-open-conns: 100
|
||||||
|
log-mode: ""
|
||||||
|
log-zap: false
|
||||||
|
|
||||||
# local configuration
|
# local configuration
|
||||||
local:
|
local:
|
||||||
path: uploads/file
|
path: uploads/file
|
||||||
store-path: uploads/file
|
store-path: uploads/file
|
||||||
|
|
||||||
# autocode configuration
|
# autocode configuration
|
||||||
autocode:
|
autocode:
|
||||||
transfer-restart: true
|
web: web/src
|
||||||
# root 自动适配项目根目录
|
root: "" # root 自动适配项目根目录, 请不要手动配置,他会在项目加载的时候识别出根路径
|
||||||
# 请不要手动配置,他会在项目加载的时候识别出根路径
|
server: server
|
||||||
root: ""
|
module: 'github.com/flipped-aurora/gin-vue-admin/server'
|
||||||
server: /server
|
ai-path: "" # AI服务路径
|
||||||
server-plug: /plugin/%s
|
|
||||||
server-api: /api/v1/%s
|
|
||||||
server-initialize: /initialize
|
|
||||||
server-model: /model/%s
|
|
||||||
server-request: /model/%s/request/
|
|
||||||
server-router: /router/%s
|
|
||||||
server-service: /service/%s
|
|
||||||
web: /web/src
|
|
||||||
web-api: /api
|
|
||||||
web-form: /view
|
|
||||||
web-table: /view
|
|
||||||
|
|
||||||
# qiniu configuration (请自行七牛申请对应的 公钥 私钥 bucket 和 域名地址)
|
# qiniu configuration (请自行七牛申请对应的 公钥 私钥 bucket 和 域名地址)
|
||||||
qiniu:
|
qiniu:
|
||||||
zone: ZoneHuaDong
|
zone: ZoneHuaDong
|
||||||
bucket: ""
|
bucket: ""
|
||||||
img-path: ""
|
img-path: ""
|
||||||
use-https: false
|
use-https: false
|
||||||
access-key: ""
|
access-key: ""
|
||||||
secret-key: ""
|
secret-key: ""
|
||||||
use-cdn-domains: false
|
use-cdn-domains: false
|
||||||
|
|
||||||
|
# minio oss configuration
|
||||||
|
minio:
|
||||||
|
endpoint: yourEndpoint
|
||||||
|
access-key-id: yourAccessKeyId
|
||||||
|
access-key-secret: yourAccessKeySecret
|
||||||
|
bucket-name: yourBucketName
|
||||||
|
use-ssl: false
|
||||||
|
base-path: ""
|
||||||
|
bucket-url: "http://host:9000/yourBucketName"
|
||||||
|
|
||||||
# aliyun oss configuration
|
# aliyun oss configuration
|
||||||
aliyun-oss:
|
aliyun-oss:
|
||||||
endpoint: yourEndpoint
|
endpoint: yourEndpoint
|
||||||
access-key-id: yourAccessKeyId
|
access-key-id: yourAccessKeyId
|
||||||
access-key-secret: yourAccessKeySecret
|
access-key-secret: yourAccessKeySecret
|
||||||
bucket-name: yourBucketName
|
bucket-name: yourBucketName
|
||||||
bucket-url: yourBucketUrl
|
bucket-url: yourBucketUrl
|
||||||
base-path: yourBasePath
|
base-path: yourBasePath
|
||||||
|
|
||||||
# tencent cos configuration
|
# tencent cos configuration
|
||||||
tencent-cos:
|
tencent-cos:
|
||||||
bucket: xxxxx-10005608
|
bucket: xxxxx-10005608
|
||||||
region: ap-shanghai
|
region: ap-shanghai
|
||||||
secret-id: your-secret-id
|
secret-id: your-secret-id
|
||||||
secret-key: your-secret-key
|
secret-key: your-secret-key
|
||||||
base-url: https://gin.vue.admin
|
base-url: https://gin.vue.admin
|
||||||
path-prefix: github.com/flipped-aurora/gin-vue-admin/server
|
path-prefix: github.com/flipped-aurora/gin-vue-admin/server
|
||||||
|
|
||||||
# aws s3 configuration (minio compatible)
|
# aws s3 configuration (minio compatible)
|
||||||
aws-s3:
|
aws-s3:
|
||||||
bucket: xxxxx-10005608
|
bucket: xxxxx-10005608
|
||||||
region: ap-shanghai
|
region: ap-shanghai
|
||||||
endpoint: ""
|
endpoint: ""
|
||||||
s3-force-path-style: false
|
s3-force-path-style: false
|
||||||
disable-ssl: false
|
disable-ssl: false
|
||||||
secret-id: your-secret-id
|
secret-id: your-secret-id
|
||||||
secret-key: your-secret-key
|
secret-key: your-secret-key
|
||||||
base-url: https://gin.vue.admin
|
base-url: https://gin.vue.admin
|
||||||
path-prefix: github.com/flipped-aurora/gin-vue-admin/server
|
path-prefix: github.com/flipped-aurora/gin-vue-admin/server
|
||||||
|
|
||||||
|
# cloudflare r2 configuration
|
||||||
|
cloudflare-r2:
|
||||||
|
bucket: xxxx0bucket
|
||||||
|
base-url: https://gin.vue.admin.com
|
||||||
|
path: uploads
|
||||||
|
account-id: xxx_account_id
|
||||||
|
access-key-id: xxx_key_id
|
||||||
|
secret-access-key: xxx_secret_key
|
||||||
|
|
||||||
# huawei obs configuration
|
# huawei obs configuration
|
||||||
hua-wei-obs:
|
hua-wei-obs:
|
||||||
path: you-path
|
path: you-path
|
||||||
bucket: you-bucket
|
bucket: you-bucket
|
||||||
endpoint: you-endpoint
|
endpoint: you-endpoint
|
||||||
access-key: you-access-key
|
access-key: you-access-key
|
||||||
secret-key: you-secret-key
|
secret-key: you-secret-key
|
||||||
|
|
||||||
# excel configuration
|
# excel configuration
|
||||||
excel:
|
excel:
|
||||||
dir: ./resource/excel/
|
dir: ./resource/excel/
|
||||||
|
|
||||||
# timer task db clear table
|
# disk usage configuration
|
||||||
Timer:
|
disk-list:
|
||||||
start: true
|
- mount-point: "/"
|
||||||
spec: "@daily" # 定时任务详细配置参考 https://pkg.go.dev/github.com/robfig/cron/v3
|
|
||||||
detail:
|
|
||||||
- tableName: sys_operation_records
|
|
||||||
compareField: created_at
|
|
||||||
interval: 2160h
|
|
||||||
- tableName: jwt_blacklists
|
|
||||||
compareField: created_at
|
|
||||||
interval: 168h
|
|
||||||
|
|
||||||
# 跨域配置
|
# 跨域配置
|
||||||
# 需要配合 server/initialize/router.go -> `Router.Use(middleware.CorsByRules())` 使用
|
# 需要配合 server/initialize/router.go -> `Router.Use(middleware.CorsByRules())` 使用
|
||||||
cors:
|
cors:
|
||||||
mode: whitelist # 放行模式: allow-all, 放行全部; whitelist, 白名单模式, 来自白名单内域名的请求添加 cors 头; strict-whitelist 严格白名单模式, 白名单外的请求一律拒绝
|
mode: strict-whitelist # 放行模式: allow-all, 放行全部; whitelist, 白名单模式, 来自白名单内域名的请求添加 cors 头; strict-whitelist 严格白名单模式, 白名单外的请求一律拒绝
|
||||||
whitelist:
|
whitelist:
|
||||||
- allow-origin: example1.com
|
- allow-origin: example1.com
|
||||||
allow-headers: content-type
|
allow-headers: Content-Type,AccessToken,X-CSRF-Token, Authorization, Token,X-Token,X-User-Id
|
||||||
allow-methods: GET, POST
|
allow-methods: POST, GET
|
||||||
expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type
|
expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type
|
||||||
allow-credentials: true # 布尔值
|
|
||||||
- allow-origin: example2.com
|
allow-credentials: true # 布尔值
|
||||||
allow-headers: content-type
|
- allow-origin: example2.com
|
||||||
allow-methods: GET, POST
|
allow-headers: content-type
|
||||||
expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type
|
allow-methods: GET, POST
|
||||||
allow-credentials: true # 布尔值
|
expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type
|
||||||
|
allow-credentials: true # 布尔值
|
||||||
|
mcp:
|
||||||
|
name: GVA_MCP
|
||||||
|
version: v1.0.0
|
||||||
|
sse_path: /sse
|
||||||
|
message_path: /message
|
||||||
|
url_prefix: ''
|
@@ -1,10 +1,18 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
type Oracle struct {
|
type Oracle struct {
|
||||||
GeneralDB `yaml:",inline" mapstructure:",squash"`
|
GeneralDB `yaml:",inline" mapstructure:",squash"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Oracle) Dsn() string {
|
func (m *Oracle) Dsn() string {
|
||||||
return "oracle://" + m.Username + ":" + m.Password + "@" + m.Path + ":" + m.Port + "/" + m.Dbname + "?" + m.Config
|
dsn := fmt.Sprintf("oracle://%s:%s@%s/%s?%s", url.PathEscape(m.Username), url.PathEscape(m.Password),
|
||||||
|
net.JoinHostPort(m.Path, m.Port), url.PathEscape(m.Dbname), m.Config)
|
||||||
|
return dsn
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,18 +1,14 @@
|
|||||||
package initialize
|
package initialize
|
||||||
|
|
||||||
import (
|
import (
|
||||||
//"github.com/dzwvip/oracle"
|
oracle "github.com/dzwvip/gorm-oracle"
|
||||||
"github.com/flipped-aurora/gin-vue-admin/server/config"
|
"github.com/flipped-aurora/gin-vue-admin/server/config"
|
||||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||||
"github.com/flipped-aurora/gin-vue-admin/server/initialize/internal"
|
"github.com/flipped-aurora/gin-vue-admin/server/initialize/internal"
|
||||||
|
|
||||||
//_ "github.com/godror/godror"
|
|
||||||
"gorm.io/driver/mysql"
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GormOracle 初始化oracle数据库
|
// GormOracle 初始化oracle数据库
|
||||||
// 如果需要Oracle库 放开import里的注释 把下方 mysql.Config 改为 oracle.Config ; mysql.New 改为 oracle.New
|
|
||||||
func GormOracle() *gorm.DB {
|
func GormOracle() *gorm.DB {
|
||||||
m := global.GVA_CONFIG.Oracle
|
m := global.GVA_CONFIG.Oracle
|
||||||
return initOracleDatabase(m)
|
return initOracleDatabase(m)
|
||||||
@@ -28,13 +24,7 @@ func initOracleDatabase(m config.Oracle) *gorm.DB {
|
|||||||
if m.Dbname == "" {
|
if m.Dbname == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
if db, err := gorm.Open(oracle.Open(m.Dsn()), internal.Gorm.Config(m.Prefix, m.Singular)); err != nil {
|
||||||
oracleConfig := mysql.Config{
|
|
||||||
DSN: m.Dsn(), // DSN data source name
|
|
||||||
DefaultStringSize: 191, // string 类型字段的默认长度
|
|
||||||
}
|
|
||||||
|
|
||||||
if db, err := gorm.Open(mysql.New(oracleConfig), internal.Gorm.Config(m.Prefix, m.Singular)); err != nil {
|
|
||||||
panic(err)
|
panic(err)
|
||||||
} else {
|
} else {
|
||||||
sqlDB, _ := db.DB()
|
sqlDB, _ := db.DB()
|
||||||
|
@@ -41,7 +41,11 @@ type ApiCreator struct{}
|
|||||||
// New 创建API创建工具
|
// New 创建API创建工具
|
||||||
func (a *ApiCreator) New() mcp.Tool {
|
func (a *ApiCreator) New() mcp.Tool {
|
||||||
return mcp.NewTool("create_api",
|
return mcp.NewTool("create_api",
|
||||||
mcp.WithDescription("创建后端API记录,用于AI编辑器自动添加API接口时自动创建对应的API权限记录。注意:使用gva_auto_generate创建的包和模块会自动创建API权限,无需调用此工具。仅在AI编辑器自动添加API或router下的文件产生路径变化时使用。"),
|
mcp.WithDescription(`创建后端API记录,用于AI编辑器自动添加API接口时自动创建对应的API权限记录。
|
||||||
|
|
||||||
|
**重要限制:**
|
||||||
|
- 当使用gva_auto_generate工具且needCreatedModules=true时,模块创建会自动生成API权限,不应调用此工具
|
||||||
|
- 仅在以下情况使用:1) 单独创建API(不涉及模块创建);2) AI编辑器自动添加API;3) router下的文件产生路径变化时`),
|
||||||
mcp.WithString("path",
|
mcp.WithString("path",
|
||||||
mcp.Required(),
|
mcp.Required(),
|
||||||
mcp.Description("API路径,如:/user/create"),
|
mcp.Description("API路径,如:/user/create"),
|
||||||
|
@@ -1,81 +0,0 @@
|
|||||||
package mcpTool
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"github.com/mark3labs/mcp-go/mcp"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
RegisterTool(&CurrentTime{})
|
|
||||||
}
|
|
||||||
|
|
||||||
type CurrentTime struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取当前系统时间
|
|
||||||
func (t *CurrentTime) Handle(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
||||||
// 获取当前系统时间
|
|
||||||
|
|
||||||
timezone, ok := request.GetArguments()["timezone"].(string)
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("参数错误:timezone 必须是字符串类型")
|
|
||||||
}
|
|
||||||
// 根据timezone参数加载对应时区
|
|
||||||
loc, err := loadTimeZone(timezone)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取当前时间并转换为指定时区
|
|
||||||
currentTime := time.Now().In(loc).Format("2006-01-02 15:04:05")
|
|
||||||
//返回
|
|
||||||
return &mcp.CallToolResult{
|
|
||||||
Content: []mcp.Content{
|
|
||||||
mcp.TextContent{
|
|
||||||
Type: "text",
|
|
||||||
Text: fmt.Sprintf("%s 时区的当前时间是:%s", timezone, currentTime),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *CurrentTime) New() mcp.Tool {
|
|
||||||
return mcp.NewTool("currentTime",
|
|
||||||
mcp.WithDescription("获取当前系统时间"),
|
|
||||||
mcp.WithString("timezone",
|
|
||||||
mcp.Required(),
|
|
||||||
mcp.Description("时区"),
|
|
||||||
mcp.Enum("UTC", "CST", "PST", "EST", "GMT", "CET", "JST", "MST", "IST", "AST", "HST"),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将简写时区转换为IANA标准时区
|
|
||||||
func loadTimeZone(timezone string) (*time.Location, error) {
|
|
||||||
// 时区映射表
|
|
||||||
timezoneMap := map[string]string{
|
|
||||||
"UTC": "UTC",
|
|
||||||
"CST": "Asia/Shanghai", // 中国标准时间
|
|
||||||
"PST": "America/Los_Angeles",
|
|
||||||
"EST": "America/New_York",
|
|
||||||
"GMT": "GMT",
|
|
||||||
"CET": "Europe/Paris",
|
|
||||||
"JST": "Asia/Tokyo",
|
|
||||||
"MST": "America/Denver",
|
|
||||||
"IST": "Asia/Kolkata",
|
|
||||||
"AST": "Asia/Riyadh", // 阿拉伯标准时间
|
|
||||||
"HST": "Pacific/Honolulu",
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取标准时区名称
|
|
||||||
tzName, exists := timezoneMap[timezone]
|
|
||||||
if !exists {
|
|
||||||
return nil, errors.New("不支持的时区: " + timezone)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 加载时区
|
|
||||||
return time.LoadLocation(tzName)
|
|
||||||
}
|
|
@@ -1,79 +0,0 @@
|
|||||||
package mcpTool
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
|
||||||
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
|
|
||||||
"github.com/mark3labs/mcp-go/mcp"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
RegisterTool(&GetNickname{})
|
|
||||||
}
|
|
||||||
|
|
||||||
type GetNickname struct{}
|
|
||||||
|
|
||||||
// 根据用户username获取nickname
|
|
||||||
func (t *GetNickname) New() mcp.Tool {
|
|
||||||
return mcp.NewTool("getNickname",
|
|
||||||
mcp.WithDescription("根据用户username获取nickname"),
|
|
||||||
mcp.WithString("username",
|
|
||||||
mcp.Required(),
|
|
||||||
mcp.Description("用户的username"),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle 处理获取昵称的请求
|
|
||||||
func (t *GetNickname) Handle(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
||||||
// 1. 参数验证
|
|
||||||
username, ok := request.GetArguments()["username"].(string)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("参数错误:username 必须是字符串类型")
|
|
||||||
}
|
|
||||||
|
|
||||||
if username == "" {
|
|
||||||
return nil, errors.New("参数错误:username 不能为空")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 记录操作日志
|
|
||||||
global.GVA_LOG.Info("getNickname 工具被调用")
|
|
||||||
|
|
||||||
// 3. 优化查询,只选择需要的字段
|
|
||||||
var user struct {
|
|
||||||
NickName string
|
|
||||||
}
|
|
||||||
|
|
||||||
err := global.GVA_DB.Model(&system.SysUser{}).
|
|
||||||
Select("nick_name").
|
|
||||||
Where("username = ?", username).
|
|
||||||
First(&user).Error
|
|
||||||
|
|
||||||
// 4. 优化错误处理
|
|
||||||
if err != nil {
|
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
||||||
return &mcp.CallToolResult{
|
|
||||||
Content: []mcp.Content{
|
|
||||||
mcp.TextContent{
|
|
||||||
Type: "text",
|
|
||||||
Text: fmt.Sprintf("用户 %s 不存在", username),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
global.GVA_LOG.Error("数据库查询错误")
|
|
||||||
return nil, errors.New("系统错误,请稍后再试")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 构造回复信息
|
|
||||||
return &mcp.CallToolResult{
|
|
||||||
Content: []mcp.Content{
|
|
||||||
mcp.TextContent{
|
|
||||||
Type: "text",
|
|
||||||
Text: fmt.Sprintf("用户 %s 的昵称是 %s", username, user.NickName),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
|
@@ -135,6 +135,10 @@ func (t *AutomationModuleAnalyzer) New() mcp.Tool {
|
|||||||
2. AI分析需求为1xxx2xxx格式 → gva_auto_generate(执行创建)
|
2. AI分析需求为1xxx2xxx格式 → gva_auto_generate(执行创建)
|
||||||
3. 创建完成后,根据需要使用其他辅助工具
|
3. 创建完成后,根据需要使用其他辅助工具
|
||||||
|
|
||||||
|
**重要限制:**
|
||||||
|
- 当needCreatedModules=true时,模块创建会自动生成API和菜单,因此不应再调用api_creator和menu_creator工具
|
||||||
|
- 只有在单独创建API或菜单(不涉及模块创建)时才使用api_creator和menu_creator工具
|
||||||
|
|
||||||
重要:ExecutionPlan结构体格式要求(支持批量创建):
|
重要:ExecutionPlan结构体格式要求(支持批量创建):
|
||||||
{
|
{
|
||||||
"packageName": "包名(string)",
|
"packageName": "包名(string)",
|
||||||
@@ -169,7 +173,7 @@ func (t *AutomationModuleAnalyzer) New() mcp.Tool {
|
|||||||
"generateWeb": "是否生成前端(bool)",
|
"generateWeb": "是否生成前端(bool)",
|
||||||
"generateServer": "是否生成后端(bool)",
|
"generateServer": "是否生成后端(bool)",
|
||||||
"fields": [{
|
"fields": [{
|
||||||
"fieldName": "字段名(string)",
|
"fieldName": "字段名(string)必须大写开头",
|
||||||
"fieldDesc": "字段描述(string)",
|
"fieldDesc": "字段描述(string)",
|
||||||
"fieldType": "字段类型支持:string(字符串),richtext(富文本),int(整型),bool(布尔值),float64(浮点型),time.Time(时间),enum(枚举),picture(单图片,字符串),pictures(多图片,json字符串),video(视频,字符串),file(文件,json字符串),json(JSON),array(数组)",
|
"fieldType": "字段类型支持:string(字符串),richtext(富文本),int(整型),bool(布尔值),float64(浮点型),time.Time(时间),enum(枚举),picture(单图片,字符串),pictures(多图片,json字符串),video(视频,字符串),file(文件,json字符串),json(JSON),array(数组)",
|
||||||
"fieldJson": "JSON标签(string)",
|
"fieldJson": "JSON标签(string)",
|
||||||
@@ -184,7 +188,7 @@ func (t *AutomationModuleAnalyzer) New() mcp.Tool {
|
|||||||
"desc": "详情显示(bool)",
|
"desc": "详情显示(bool)",
|
||||||
"excel": "导入导出(bool)",
|
"excel": "导入导出(bool)",
|
||||||
"require": "是否必填(bool)",
|
"require": "是否必填(bool)",
|
||||||
"defaultValue": "默认值(string)",
|
"defaultValue": "默认值(string),JSON类型(array,json,file,pictures)请保持为空他们不可以设置默认值",
|
||||||
"errorText": "错误提示(string)",
|
"errorText": "错误提示(string)",
|
||||||
"clearable": "是否可清空(bool)",
|
"clearable": "是否可清空(bool)",
|
||||||
"sort": "是否排序(bool)",
|
"sort": "是否排序(bool)",
|
||||||
@@ -1239,6 +1243,14 @@ func (t *AutomationModuleAnalyzer) validateExecutionPlan(plan *ExecutionPlan) er
|
|||||||
if field.FieldName == "" {
|
if field.FieldName == "" {
|
||||||
return fmt.Errorf("模块 %d 字段 %d 的 fieldName 不能为空", moduleIndex+1, i+1)
|
return fmt.Errorf("模块 %d 字段 %d 的 fieldName 不能为空", moduleIndex+1, i+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 确保字段名首字母大写
|
||||||
|
if len(field.FieldName) > 0 {
|
||||||
|
firstChar := string(field.FieldName[0])
|
||||||
|
if firstChar >= "a" && firstChar <= "z" {
|
||||||
|
moduleInfo.Fields[i].FieldName = strings.ToUpper(firstChar) + field.FieldName[1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
if field.FieldDesc == "" {
|
if field.FieldDesc == "" {
|
||||||
return fmt.Errorf("模块 %d 字段 %d 的 fieldDesc 不能为空", moduleIndex+1, i+1)
|
return fmt.Errorf("模块 %d 字段 %d 的 fieldDesc 不能为空", moduleIndex+1, i+1)
|
||||||
}
|
}
|
||||||
@@ -1365,6 +1377,13 @@ func (t *AutomationModuleAnalyzer) executeCreation(ctx context.Context, plan *Ex
|
|||||||
}
|
}
|
||||||
|
|
||||||
result.Message += fmt.Sprintf("批量创建完成,共处理 %d 个模块; ", len(plan.ModulesInfo))
|
result.Message += fmt.Sprintf("批量创建完成,共处理 %d 个模块; ", len(plan.ModulesInfo))
|
||||||
|
|
||||||
|
// 添加重要提醒:不要使用其他MCP工具
|
||||||
|
result.Message += "\n\n⚠️ 重要提醒:\n"
|
||||||
|
result.Message += "模块创建已完成,API和菜单已自动生成。请不要再调用以下MCP工具:\n"
|
||||||
|
result.Message += "- api_creator:API权限已在模块创建时自动生成\n"
|
||||||
|
result.Message += "- menu_creator:前端菜单已在模块创建时自动生成\n"
|
||||||
|
result.Message += "如需修改API或菜单,请直接在系统管理界面中进行配置。\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Message += "已构建目录结构信息; "
|
result.Message += "已构建目录结构信息; "
|
||||||
|
@@ -64,7 +64,11 @@ type MenuCreator struct{}
|
|||||||
// New 创建菜单创建工具
|
// New 创建菜单创建工具
|
||||||
func (m *MenuCreator) New() mcp.Tool {
|
func (m *MenuCreator) New() mcp.Tool {
|
||||||
return mcp.NewTool("create_menu",
|
return mcp.NewTool("create_menu",
|
||||||
mcp.WithDescription("创建前端菜单记录,用于AI编辑器自动添加前端页面时自动创建对应的菜单项。注意:使用gva_auto_generate创建的包和模块会自动创建菜单项,无需调用此工具。仅在AI编辑器自动添加前端页面时使用。"),
|
mcp.WithDescription(`创建前端菜单记录,用于AI编辑器自动添加前端页面时自动创建对应的菜单项。
|
||||||
|
|
||||||
|
**重要限制:**
|
||||||
|
- 当使用gva_auto_generate工具且needCreatedModules=true时,模块创建会自动生成菜单项,不应调用此工具
|
||||||
|
- 仅在以下情况使用:1) 单独创建菜单(不涉及模块创建);2) AI编辑器自动添加前端页面时`),
|
||||||
mcp.WithNumber("parentId",
|
mcp.WithNumber("parentId",
|
||||||
mcp.Description("父菜单ID,0表示根菜单"),
|
mcp.Description("父菜单ID,0表示根菜单"),
|
||||||
mcp.DefaultNumber(0),
|
mcp.DefaultNumber(0),
|
||||||
|
@@ -64,7 +64,7 @@ WHERE
|
|||||||
lower(a.table_name) = ?
|
lower(a.table_name) = ?
|
||||||
AND lower(a.OWNER) = ?
|
AND lower(a.OWNER) = ?
|
||||||
ORDER BY
|
ORDER BY
|
||||||
a.COLUMN_ID;
|
a.COLUMN_ID
|
||||||
`
|
`
|
||||||
|
|
||||||
err = global.GVA_DBList[businessDB].Raw(sql, tableName, dbName).Scan(&entities).Error
|
err = global.GVA_DBList[businessDB].Raw(sql, tableName, dbName).Scan(&entities).Error
|
||||||
|
@@ -5,7 +5,7 @@ var (
|
|||||||
ApiVerify = Rules{"Path": {NotEmpty()}, "Description": {NotEmpty()}, "ApiGroup": {NotEmpty()}, "Method": {NotEmpty()}}
|
ApiVerify = Rules{"Path": {NotEmpty()}, "Description": {NotEmpty()}, "ApiGroup": {NotEmpty()}, "Method": {NotEmpty()}}
|
||||||
MenuVerify = Rules{"Path": {NotEmpty()}, "Name": {NotEmpty()}, "Component": {NotEmpty()}, "Sort": {Ge("0")}}
|
MenuVerify = Rules{"Path": {NotEmpty()}, "Name": {NotEmpty()}, "Component": {NotEmpty()}, "Sort": {Ge("0")}}
|
||||||
MenuMetaVerify = Rules{"Title": {NotEmpty()}}
|
MenuMetaVerify = Rules{"Title": {NotEmpty()}}
|
||||||
LoginVerify = Rules{"CaptchaId": {NotEmpty()}, "Captcha": {NotEmpty()}, "Username": {NotEmpty()}, "Password": {NotEmpty()}}
|
LoginVerify = Rules{"Username": {NotEmpty()}, "Password": {NotEmpty()}}
|
||||||
RegisterVerify = Rules{"Username": {NotEmpty()}, "NickName": {NotEmpty()}, "Password": {NotEmpty()}, "AuthorityId": {NotEmpty()}}
|
RegisterVerify = Rules{"Username": {NotEmpty()}, "NickName": {NotEmpty()}, "Password": {NotEmpty()}, "AuthorityId": {NotEmpty()}}
|
||||||
PageInfoVerify = Rules{"Page": {NotEmpty()}, "PageSize": {NotEmpty()}}
|
PageInfoVerify = Rules{"Page": {NotEmpty()}, "PageSize": {NotEmpty()}}
|
||||||
CustomerVerify = Rules{"CustomerName": {NotEmpty()}, "CustomerPhoneData": {NotEmpty()}}
|
CustomerVerify = Rules{"CustomerName": {NotEmpty()}, "CustomerPhoneData": {NotEmpty()}}
|
||||||
|
@@ -42,7 +42,7 @@
|
|||||||
"tailwindcss": "^3.4.10",
|
"tailwindcss": "^3.4.10",
|
||||||
"universal-cookie": "^7",
|
"universal-cookie": "^7",
|
||||||
"vform3-builds": "^3.0.10",
|
"vform3-builds": "^3.0.10",
|
||||||
"vite-auto-import-svg": "^1.6.0",
|
"vite-auto-import-svg": "^1.7.0",
|
||||||
"vue": "^3.5.7",
|
"vue": "^3.5.7",
|
||||||
"vue-cropper": "^1.1.4",
|
"vue-cropper": "^1.1.4",
|
||||||
"vue-echarts": "^7.0.3",
|
"vue-echarts": "^7.0.3",
|
||||||
|
@@ -7,22 +7,7 @@ export default {
|
|||||||
// 当被绑定的元素插入到 DOM 中时……
|
// 当被绑定的元素插入到 DOM 中时……
|
||||||
mounted: function (el, binding) {
|
mounted: function (el, binding) {
|
||||||
const userInfo = userStore.userInfo
|
const userInfo = userStore.userInfo
|
||||||
let type = ''
|
if (!binding.value){
|
||||||
switch (Object.prototype.toString.call(binding.value)) {
|
|
||||||
case '[object Array]':
|
|
||||||
type = 'Array'
|
|
||||||
break
|
|
||||||
case '[object String]':
|
|
||||||
type = 'String'
|
|
||||||
break
|
|
||||||
case '[object Number]':
|
|
||||||
type = 'Number'
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
type = ''
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if (type === '') {
|
|
||||||
el.parentNode.removeChild(el)
|
el.parentNode.removeChild(el)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@@ -93,7 +93,7 @@ export const useUserStore = defineStore('user', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!router.hasRoute(userInfo.value.authority.defaultRouter)) {
|
if (!router.hasRoute(userInfo.value.authority.defaultRouter)) {
|
||||||
ElMessage.error('请联系管理员进行授权')
|
ElMessage.error('不存在可以登陆的首页,请联系管理员进行配置')
|
||||||
} else {
|
} else {
|
||||||
await router.replace({ name: userInfo.value.authority.defaultRouter })
|
await router.replace({ name: userInfo.value.authority.defaultRouter })
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user