feat: function add for admin page is ready

This commit is contained in:
RockYang 2023-12-23 22:30:27 +08:00
parent 3ab930a107
commit 8addba8203
7 changed files with 103 additions and 48 deletions

View File

@ -32,46 +32,21 @@ const (
var InnerFunctions = []Function{ var InnerFunctions = []Function{
{ {
Name: FuncZaoBao, Name: FuncZaoBao,
Description: "每日早报,获取当天全球的热门新闻事件列表", Description: "每日早报,获取当天新闻事件列表",
Parameters: Parameters{ Parameters: Parameters{
Type: "object", Type: "object",
Properties: map[string]Property{ Properties: map[string]Property{},
"text": { Required: []string{},
Type: "string",
Description: "",
},
},
Required: []string{},
}, },
}, },
{ {
Name: FuncWeibo, Name: FuncWeibo,
Description: "新浪微博热搜榜,微博当日热搜榜单", Description: "新浪微博热搜榜,微博当日热搜榜单",
Parameters: Parameters{ Parameters: Parameters{
Type: "object", Type: "object",
Properties: map[string]Property{ Properties: map[string]Property{},
"text": { Required: []string{},
Type: "string",
Description: "",
},
},
Required: []string{},
},
},
{
Name: FuncHeadLine,
Description: "今日头条,给用户推荐当天的头条新闻,周榜热文",
Parameters: Parameters{
Type: "object",
Properties: map[string]Property{
"text": {
Type: "string",
Description: "",
},
},
Required: []string{},
}, },
}, },

View File

@ -8,6 +8,7 @@ import (
"chatplus/store/vo" "chatplus/store/vo"
"chatplus/utils" "chatplus/utils"
"chatplus/utils/resp" "chatplus/utils/resp"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gorm.io/gorm" "gorm.io/gorm"
) )
@ -33,22 +34,64 @@ func (h *FunctionHandler) Save(c *gin.Context) {
var f = model.Function{ var f = model.Function{
Id: data.Id, Id: data.Id,
Name: data.Name, Name: data.Name,
Label: data.Label,
Description: data.Description, Description: data.Description,
Parameters: utils.JsonEncode(data.Parameters), Parameters: utils.JsonEncode(data.Parameters),
Required: utils.JsonEncode(data.Required), Required: utils.JsonEncode(data.Required),
Action: data.Action, Action: data.Action,
Enabled: false, Token: data.Token,
Enabled: data.Enabled,
} }
logger.Info(f) res := h.db.Save(&f)
if res.Error != nil {
resp.ERROR(c, "error with save data:"+res.Error.Error())
return
}
data.Id = f.Id
resp.SUCCESS(c, data) resp.SUCCESS(c, data)
} }
func (h *FunctionHandler) List(c *gin.Context) { func (h *FunctionHandler) Set(c *gin.Context) {
var data struct {
Id uint `json:"id"`
Filed string `json:"filed"`
Value interface{} `json:"value"`
}
if err := c.ShouldBindJSON(&data); err != nil {
resp.ERROR(c, types.InvalidArgs)
return
}
res := h.db.Model(&model.Function{}).Where("id = ?", data.Id).Update(data.Filed, data.Value)
if res.Error != nil {
resp.ERROR(c, "更新数据库失败!")
return
}
resp.SUCCESS(c) resp.SUCCESS(c)
} }
func (h *FunctionHandler) List(c *gin.Context) {
var items []model.Function
res := h.db.Find(&items)
if res.Error != nil {
resp.ERROR(c, "No data found")
return
}
functions := make([]vo.Function, 0)
for _, v := range items {
var f vo.Function
err := utils.CopyObject(v, &f)
if err != nil {
continue
}
functions = append(functions, f)
}
resp.SUCCESS(c, functions)
}
func (h *FunctionHandler) Remove(c *gin.Context) { func (h *FunctionHandler) Remove(c *gin.Context) {
id := h.GetInt(c, "id", 0) id := h.GetInt(c, "id", 0)

View File

@ -17,7 +17,6 @@ import (
"chatplus/store" "chatplus/store"
"context" "context"
"embed" "embed"
"github.com/go-redis/redis/v8"
"io" "io"
"log" "log"
"os" "os"
@ -26,6 +25,8 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/go-redis/redis/v8"
"github.com/lionsoul2014/ip2region/binding/golang/xdb" "github.com/lionsoul2014/ip2region/binding/golang/xdb"
"go.uber.org/fx" "go.uber.org/fx"
"gorm.io/gorm" "gorm.io/gorm"
@ -351,6 +352,7 @@ func main() {
fx.Invoke(func(s *core.AppServer, h *admin.FunctionHandler) { fx.Invoke(func(s *core.AppServer, h *admin.FunctionHandler) {
group := s.Engine.Group("/api/admin/function/") group := s.Engine.Group("/api/admin/function/")
group.POST("save", h.Save) group.POST("save", h.Save)
group.POST("set", h.Set)
group.GET("list", h.List) group.GET("list", h.List)
group.GET("remove", h.Remove) group.GET("remove", h.Remove)
}), }),

View File

@ -8,5 +8,6 @@ type Function struct {
Parameters string Parameters string
Required string Required string
Action string Action string
Token string
Enabled bool Enabled bool
} }

View File

@ -14,9 +14,11 @@ type Property struct {
type Function struct { type Function struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Label string `json:"label"`
Description string `json:"description"` Description string `json:"description"`
Parameters Parameters `json:"parameters"` Parameters Parameters `json:"parameters"`
Required []string `json:"required"` Required []string `json:"required"`
Action string `json:"action"` Action string `json:"action"`
Token string `json:"token"`
Enabled bool `json:"enabled"` Enabled bool `json:"enabled"`
} }

View File

@ -21,4 +21,6 @@ ALTER TABLE `chatgpt_functions` ADD `enabled` TINYINT(1) NOT NULL DEFAULT '0' CO
ALTER TABLE `chatgpt_functions` ADD `label` VARCHAR(30) NULL COMMENT '函数标签' AFTER `name`; ALTER TABLE `chatgpt_functions` ADD `label` VARCHAR(30) NULL COMMENT '函数标签' AFTER `name`;
ALTER TABLE `chatgpt_mj_jobs` ADD `use_proxy` TINYINT(1) NOT NULL DEFAULT '0' COMMENT '是否使用反代' AFTER `progress`; ALTER TABLE `chatgpt_mj_jobs` ADD `use_proxy` TINYINT(1) NOT NULL DEFAULT '0' COMMENT '是否使用反代' AFTER `progress`;
ALTER TABLE `chatgpt_mj_jobs` CHANGE `img_url` `img_url` VARCHAR(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '图片URL'; ALTER TABLE `chatgpt_mj_jobs` CHANGE `img_url` `img_url` VARCHAR(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '图片URL';
ALTER TABLE `chatgpt_functions` ADD `token` VARCHAR(255) NULL COMMENT 'API授权token' AFTER `action`;

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="container role-list" v-loading="loading"> <div class="container role-list" v-loading="loading">
<div class="handle-box"> <div class="handle-box">
<el-button type="primary" :icon="Plus" @click="addRole">新增</el-button> <el-button type="primary" :icon="Plus" @click="addRow">新增</el-button>
</div> </div>
<el-row> <el-row>
<el-table :data="tableData" :border="parentBorder" style="width: 100%"> <el-table :data="tableData" :border="parentBorder" style="width: 100%">
@ -10,10 +10,11 @@
<span class="sort" :data-id="scope.row.id">{{ scope.row.name }}</span> <span class="sort" :data-id="scope.row.id">{{ scope.row.name }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="函数别名" prop="label"/>
<el-table-column label="功能描述" prop="description"/> <el-table-column label="功能描述" prop="description"/>
<el-table-column label="启用状态"> <el-table-column label="启用状态">
<template #default="scope"> <template #default="scope">
<el-switch v-model="scope.row.enabled" @change="functionSet(scope.row)"/> <el-switch v-model="scope.row.enabled" @change="functionSet('enabled',scope.row)"/>
</template> </template>
</el-table-column> </el-table-column>
@ -39,6 +40,7 @@
<el-form-item label="函数名称:" prop="name"> <el-form-item label="函数名称:" prop="name">
<el-input <el-input
v-model="item.name" v-model="item.name"
placeholder="函数名称最好为英文"
autocomplete="off" autocomplete="off"
/> />
</el-form-item> </el-form-item>
@ -113,6 +115,19 @@
</template> </template>
</el-form-item> </el-form-item>
<el-form-item label="API 地址:" prop="action">
<el-input
v-model="item.action"
autocomplete="off"
/>
</el-form-item>
<el-form-item label="API Token" prop="token">
<el-input
v-model="item.token"
autocomplete="off"
/>
</el-form-item>
<el-form-item label="启用状态"> <el-form-item label="启用状态">
<el-switch v-model="item.enabled"/> <el-switch v-model="item.enabled"/>
</el-form-item> </el-form-item>
@ -130,21 +145,19 @@
<script setup> <script setup>
import {Delete, Plus, RemoveFilled} from "@element-plus/icons-vue"; import {Delete, Plus} from "@element-plus/icons-vue";
import {onMounted, reactive, ref} from "vue"; import {onMounted, reactive, ref} from "vue";
import {httpGet, httpPost} from "@/utils/http"; import {httpGet, httpPost} from "@/utils/http";
import {ElMessage} from "element-plus"; import {ElMessage} from "element-plus";
import {copyObj, removeArrayItem} from "@/utils/libs"; import {arrayContains, copyObj} from "@/utils/libs";
import {Sortable} from "sortablejs"
const showDialog = ref(false) const showDialog = ref(false)
const parentBorder = ref(true) const parentBorder = ref(true)
const childBorder = ref(true) const childBorder = ref(true)
const tableData = ref([]) const tableData = ref([])
const item = ref({parameters: []}) const item = ref({})
const params = ref([]) const params = ref([])
const formRef = ref(null) const formRef = ref(null)
const editRow = ref({})
const loading = ref(true) const loading = ref(true)
const title = ref("新增函数") const title = ref("新增函数")
@ -176,11 +189,24 @@ const curIndex = ref(0)
const rowEdit = function (index, row) { const rowEdit = function (index, row) {
curIndex.value = index curIndex.value = index
item.value = copyObj(row) item.value = copyObj(row)
// initialize parameters
const props = item.value?.parameters?.properties
const required = item.value?.parameters?.required
const _params = []
for (let key in props) {
_params.push({
name: key,
type: props[key].type,
desc: props[key].description,
required: arrayContains(required, key)
})
}
params.value = _params
showDialog.value = true showDialog.value = true
} }
const addRole = function () { const addRow = function () {
item.value = {parameters: []} item.value = {enabled:true}
showDialog.value = true showDialog.value = true
} }
@ -233,8 +259,12 @@ const removeParam = function (index) {
params.value.splice(index, 1); params.value.splice(index, 1);
} }
const functionSet = (row) => { const functionSet = (filed,row) => {
httpPost('/api/admin/function/set', {id: row.id, filed: filed, value: row[filed]}).then(() => {
ElMessage.success("操作成功!")
}).catch(e => {
ElMessage.error("操作失败:" + e.message)
})
} }
</script> </script>