diff --git a/app/system/api/plugins_manage.go b/app/system/api/plugins_manage.go
new file mode 100644
index 0000000..3be6970
--- /dev/null
+++ b/app/system/api/plugins_manage.go
@@ -0,0 +1,142 @@
+// ==========================================================================
+// GFast自动生成控制器相关代码,只生成一次,按需修改,再次生成不会覆盖.
+// 生成日期:2021-08-31 17:58:43
+// 生成路径: gfast/app/system/api/plugins_manage.go
+// 生成人:gfast
+// ==========================================================================
+
+package api
+
+import (
+ "gfast/app/system/dao"
+ "gfast/app/system/service"
+ "github.com/gogf/gf/frame/g"
+ "github.com/gogf/gf/net/ghttp"
+ "github.com/gogf/gf/text/gstr"
+ "github.com/gogf/gf/util/gvalid"
+)
+
+type pluginsManage struct {
+ SystemBase
+}
+
+var PluginsManage = new(pluginsManage)
+
+// List 列表
+func (c *pluginsManage) List(r *ghttp.Request) {
+ var req *dao.PluginsManageSearchReq
+ //获取参数
+ if err := r.Parse(&req); err != nil {
+ c.FailJsonExit(r, err.(gvalid.Error).FirstString())
+ }
+ req.Ctx = r.GetCtx()
+ total, page, list, err := service.PluginsManage.GetList(req)
+ if err != nil {
+ c.FailJsonExit(r, err.Error())
+ }
+ result := g.Map{
+ "currentPage": page,
+ "total": total,
+ "list": list,
+ }
+ c.SusJsonExit(r, result)
+}
+
+// Get 获取
+func (c *pluginsManage) Get(r *ghttp.Request) {
+ id := r.GetInt64("id")
+ info, err := service.PluginsManage.GetInfoById(r.GetCtx(), id)
+ if err != nil {
+ c.FailJsonExit(r, err.Error())
+ }
+ c.SusJsonExit(r, info)
+}
+
+// ChangeStatus 修改状态
+func (c *pluginsManage) ChangeStatus(r *ghttp.Request) {
+ var req *dao.PluginsManageStatusReq
+ //获取参数
+ if err := r.Parse(&req); err != nil {
+ c.FailJsonExit(r, err.(gvalid.Error).FirstString())
+ }
+ if err := service.PluginsManage.ChangeStatus(r.GetCtx(), req); err != nil {
+ c.FailJsonExit(r, err.Error())
+ } else {
+ c.SusJsonExit(r, "状态设置成功")
+ }
+}
+
+// Install 插件安装
+func (c *pluginsManage) Install(r *ghttp.Request) {
+ var req *dao.PluginsManageInstallReq
+ //获取参数
+ if err := r.Parse(&req); err != nil {
+ c.FailJsonExit(r, err.(gvalid.Error).FirstString())
+ }
+ if req.RToken == "" {
+ c.SusJsonExit(r, g.Map{
+ "code": -401,
+ "msg": "请登录",
+ })
+ }
+ err := service.PluginsManage.Install(r.GetCtx(), req)
+ if err != nil {
+ c.FailJsonExit(r, err.Error())
+ }
+ c.SusJsonExit(r, "安装成功")
+}
+
+// Captcha 获取验证码
+func (c *pluginsManage) Captcha(r *ghttp.Request) {
+ idKeyC, base64stringC, err := service.PluginsManage.GetCaptcha(r.GetCtx())
+ if err != nil {
+ c.FailJsonExit(r, err.Error())
+ }
+ c.SusJsonExit(r, g.Map{
+ "base64stringC": base64stringC,
+ "idKeyC": idKeyC,
+ })
+}
+
+// LoginR 登录插件服务
+func (c *pluginsManage) LoginR(r *ghttp.Request) {
+ var req *dao.PluginRLoginFormReq
+ // 通过Parse方法解析获取参数
+ err := r.Parse(&req)
+ if err != nil {
+ c.FailJsonExit(r, err.(gvalid.Error).FirstString())
+ }
+ var userInfo g.Map
+ userInfo, err = service.PluginsManage.LoginR(r.GetCtx(), req)
+ if err != nil {
+ c.FailJsonExit(r, err.Error())
+ }
+ c.SusJsonExit(r, userInfo)
+}
+
+// InstallOffLine 离线安装
+func (c *pluginsManage) InstallOffLine(r *ghttp.Request) {
+ upFile := r.GetUploadFile("file")
+ f, err := upFile.Open()
+ if err != nil {
+ c.FailJsonExit(r, err.Error())
+ }
+ defer f.Close()
+ d := make([]byte, upFile.Size)
+ _, err = f.Read(d)
+ if err != nil {
+ c.FailJsonExit(r, err.Error())
+ }
+ fileName := upFile.Filename
+ fileName = gstr.SubStr(fileName, gstr.PosR(fileName, "=")+1,
+ gstr.PosR(fileName, ".")-gstr.PosR(fileName, "=")-1)
+ err = service.PluginsManage.PluginIsExists(r.GetCtx(), fileName)
+ if err != nil {
+ c.FailJsonExit(r, err.Error())
+ }
+ err = service.PluginsManage.InstallFile(r.GetCtx(), d, fileName)
+ if err != nil {
+ c.FailJsonExit(r, err.Error())
+ }
+ c.SusJsonExit(r)
+}
diff --git a/app/system/dao/internal/plugins_manage.go b/app/system/dao/internal/plugins_manage.go
new file mode 100644
index 0000000..577fe97
--- /dev/null
+++ b/app/system/dao/internal/plugins_manage.go
@@ -0,0 +1,81 @@
+// ==========================================================================
+// GFast自动生成dao internal操作代码,无需手动修改,重新生成会自动覆盖.
+// 生成日期:2021-08-31 17:58:43
+// 生成路径: gfast/app/system/dao/internal/plugins_manage.go
+// 生成人:gfast
+// ==========================================================================
+
+package internal
+
+import (
+ "context"
+ "github.com/gogf/gf/database/gdb"
+ "github.com/gogf/gf/frame/g"
+)
+
+// PluginsManageDao is the manager for logic model data accessing and custom defined data operations functions management.
+type PluginsManageDao struct {
+ Table string // Table is the underlying table name of the DAO.
+ Group string // Group is the database configuration group name of current DAO.
+ Columns PluginsManageColumns // Columns is the short type for Columns, which contains all the column names of Table for convenient usage.
+}
+
+// PluginsManageColumns defines and stores column names for table plugins_manage.
+type PluginsManageColumns struct {
+ Id string // ID
+ StoreId string // 插件在商城中的id
+ PName string // 插件名称英文
+ PTitle string // 插件名称
+ PDescription string // 插件介绍
+ PAuth string // 作者
+ IsInstall string // 是否安装
+ Status string // 状态
+ Version string // 当前版本
+ Price string // 价格
+ DownloadTimes string // 下载次数
+ InstallPath string // 安装路径
+}
+
+var pluginsManageColumns = PluginsManageColumns{
+ Id: "id",
+ StoreId: "store_id",
+ PName: "p_name",
+ PTitle: "p_title",
+ PDescription: "p_description",
+ PAuth: "p_auth",
+ IsInstall: "is_install",
+ Status: "status",
+ Version: "version",
+ Price: "price",
+ DownloadTimes: "download_times",
+ InstallPath: "install_path",
+}
+
+// NewPluginsManageDao creates and returns a new DAO object for table data access.
+func NewPluginsManageDao() *PluginsManageDao {
+ return &PluginsManageDao{
+ Group: "default",
+ Table: "plugins_manage",
+ Columns: pluginsManageColumns,
+ }
+}
+
+// DB retrieves and returns the underlying raw database management object of current DAO.
+func (dao *PluginsManageDao) DB() gdb.DB {
+ return g.DB(dao.Group)
+}
+
+// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
+func (dao *PluginsManageDao) Ctx(ctx context.Context) *gdb.Model {
+ return dao.DB().Model(dao.Table).Safe().Ctx(ctx)
+}
+
+// Transaction wraps the transaction logic using function f.
+// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
+// It commits the transaction and returns nil if function f returns nil.
+//
+// Note that, you should not Commit or Rollback the transaction in function f
+// as it is automatically handled by this function.
+func (dao *PluginsManageDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) {
+ return dao.Ctx(ctx).Transaction(ctx, f)
+}
diff --git a/app/system/dao/plugins_manage.go b/app/system/dao/plugins_manage.go
new file mode 100644
index 0000000..389fe3c
--- /dev/null
+++ b/app/system/dao/plugins_manage.go
@@ -0,0 +1,146 @@
+// ==========================================================================
+// GFast自动生成dao操作代码,无需手动修改,重新生成不会自动覆盖.
+// 生成日期:2021-08-31 17:58:43
+// 生成路径: gfast/app/system/dao/plugins_manage.go
+// 生成人:gfast
+// ==========================================================================
+
+package dao
+
+import (
+ comModel "gfast/app/common/model"
+ "gfast/app/system/dao/internal"
+ "github.com/gogf/gf/os/gtime"
+)
+
+// pluginsManageDao is the manager for logic model data accessing and custom defined data operations functions management.
+// You can define custom methods on it to extend its functionality as you wish.
+type pluginsManageDao struct {
+ *internal.PluginsManageDao
+}
+
+var (
+ // PluginsManage is globally public accessible object for table tools_gen_table operations.
+ PluginsManage = pluginsManageDao{
+ internal.NewPluginsManageDao(),
+ }
+)
+
+// Fill with you ideas below.
+
+// PluginsManageSearchReq 分页请求参数
+type PluginsManageSearchReq struct {
+ PName string `p:"pName"` //插件名称英文
+ PTitle string `p:"pTitle"` //插件名称
+ PAuth string `p:"pAuth"` //作者
+ Status string `p:"status"` //状态
+ comModel.PageReq
+}
+
+// PluginsManageAddReq 添加操作请求参数
+type PluginsManageAddReq struct {
+ StoreId int `p:"storeId" `
+ PName string `p:"pName" v:"required#插件名称英文不能为空"`
+ PTitle string `p:"pTitle" `
+ PDescription string `p:"pDescription" `
+ PAuth string `p:"pAuth" `
+ Status int `p:"status" v:"required#状态不能为空"`
+ Version string `p:"version" `
+ Price uint `p:"price" v:"required#价格不能为空"`
+ DownloadTimes uint `p:"downloadTimes" v:"required#下载次数不能为空"`
+ IsInstall int `p:"isInstall" v:"required#是否安装不能为空"`
+}
+
+// PluginsManageEditReq 修改操作请求参数
+type PluginsManageEditReq struct {
+ Id uint `p:"id" v:"required#主键ID不能为空"`
+ StoreId int `p:"storeId" `
+ PName string `p:"pName" v:"required#插件名称英文不能为空"`
+ PTitle string `p:"pTitle" `
+ PDescription string `p:"pDescription" `
+ PAuth string `p:"pAuth" `
+ Status int `p:"status" v:"required#状态不能为空"`
+ Version string `p:"version" `
+ Price uint `p:"price" v:"required#价格不能为空"`
+ DownloadTimes uint `p:"downloadTimes" v:"required#下载次数不能为空"`
+ IsInstall int `p:"isInstall" v:"required#是否安装不能为空"`
+}
+
+// PluginsManageStatusReq 设置状态参数
+type PluginsManageStatusReq struct {
+ PluginId uint `p:"pluginId" v:"required#pluginId不能为空"`
+ Status int `p:"status" v:"required#状态不能为空"`
+}
+
+// PluginsManageListRes 列表返回结果
+type PluginsManageListRes struct {
+ Id uint `json:"id" `
+ PName string `json:"pName" v:"required#插件名称英文不能为空"`
+ PTitle string `json:"pTitle" `
+ PDescription string `json:"pDescription" `
+ PAuth string `json:"pAuth" `
+ Status int `json:"status" v:"required#状态不能为空"`
+ Version string `json:"version" `
+ Price uint `json:"price" v:"required#价格不能为空"`
+ DownloadTimes uint `json:"downloadTimes" v:"required#下载次数不能为空"`
+}
+
+// PluginsManageInfoRes 数据返回结果
+type PluginsManageInfoRes struct {
+ Id uint `json:"id" `
+ StoreId int `json:"storeId" `
+ PName string `json:"pName" v:"required#插件名称英文不能为空"`
+ PTitle string `json:"pTitle" `
+ PDescription string `json:"pDescription" `
+ PAuth string `json:"pAuth" `
+ IsInstall int `json:"isInstall" v:"required#是否安装不能为空"`
+ Status int `json:"status" v:"required#状态不能为空"`
+ Version string `json:"version" `
+ Price uint `json:"price" v:"required#价格不能为空"`
+ DownloadTimes uint `json:"downloadTimes" v:"required#下载次数不能为空"`
+}
+
+// CsPluginListRes 插件商城获取的插件数据
+type CsPluginListRes struct {
+ PluginId uint `orm:"plugin_id,primary" json:"pluginId"` // ID
+ PluginCateId uint `orm:"plugin_cate_id" json:"pluginCateId"` // 分类ID
+ PluginName string `orm:"plugin_name" json:"pluginName"` // 插件名称
+ CodeName string `orm:"code_name" json:"CodeName"` // 代码名称
+ PluginPrice uint `orm:"plugin_price" json:"pluginPrice"` // 售价
+ PluginPriceStr string `json:"pluginPriceStr"` // 售价decimal
+ PluginDiscount uint `orm:"plugin_discount" json:"pluginDiscount"` // 折扣
+ PluginCreater uint `orm:"plugin_creater" json:"pluginCreater"` // 开发人员ID
+ PublishDate *gtime.Time `orm:"publish_date" json:"publishDate"` // 发布日期
+ PluginThumb string `orm:"plugin_thumb" json:"pluginThumb"` // 插件封面
+ PluginImgs string `orm:"plugin_imgs" json:"pluginImgs"` // 插件预览图
+ CreatedBy uint64 `orm:"created_by" json:"createdBy"` // 创建人
+ CreatedAt *gtime.Time `orm:"created_at" json:"createdAt"` // 创建日期
+ UpdatedAt *gtime.Time `orm:"updated_at" json:"updatedAt"` // 修改日期
+ DeletedAt *gtime.Time `orm:"deleted_at" json:"deletedAt"` // 删除日期
+ DownloadTimes uint64 `orm:"download_times" json:"downloadTimes"` //下载次数
+ Description string `orm:"description" json:"description"` //插件描述
+ PluginInfo []*struct {
+ InfoId uint `json:"infoId"` // ID
+ PluginId uint `json:"pluginId"` // 插件ID
+ InfoVersion string `json:"infoVersion"` // 版本号
+ } `json:"pluginInfo"`
+ MemName string `json:"memName" orm:"mem_name"`
+ Status int `json:"status"`
+ Version string `json:"version" `
+ IsInstall int `json:"isInstall"`
+}
+
+// PluginsManageInstallReq 插件安装操作参数
+type PluginsManageInstallReq struct {
+ PluginId uint `p:"pluginId" v:"required#插件ID不能为空"`
+ Version string `p:"version"`
+ RToken string `p:"rToken"`
+}
+
+// PluginRLoginFormReq 远端登录请求参数
+type PluginRLoginFormReq struct {
+ Username string `p:"username" v:"required#账号必须" json:"username"`
+ Password string `p:"password" v:"required#密码不能为空" json:"password"`
+ VerifyCode string `p:"verifyCode" v:"required#验证码不能为空" json:"verifyCode"`
+ VerifyKey string `p:"verifyKey" json:"verifyKey"`
+}
diff --git a/app/system/model/plugins_manage.go b/app/system/model/plugins_manage.go
new file mode 100644
index 0000000..84998af
--- /dev/null
+++ b/app/system/model/plugins_manage.go
@@ -0,0 +1,24 @@
+// ==========================================================================
+// GFast自动生成model代码,无需手动修改,重新生成会自动覆盖.
+// 生成日期:2021-08-31 17:58:43
+// 生成路径: gfast/app/system/model/plugins_manage.go
+// 生成人:gfast
+// ==========================================================================
+
+package model
+
+// PluginsManage is the golang structure for table plugins_manage.
+type PluginsManage struct {
+ Id uint `orm:"id,primary" json:"id"` // ID
+ StoreId int `orm:"store_id" json:"storeId"` // 插件在商城中的id
+ PName string `orm:"p_name" json:"pName"` // 插件名称英文
+ PTitle string `orm:"p_title" json:"pTitle"` // 插件名称
+ PDescription string `orm:"p_description" json:"pDescription"` // 插件介绍
+ PAuth string `orm:"p_auth" json:"pAuth"` // 作者
+ IsInstall int `orm:"is_install" json:"isInstall"` // 是否安装
+ Status int `orm:"status" json:"status"` // 状态
+ Version string `orm:"version" json:"version"` // 当前版本
+ Price uint `orm:"price" json:"price"` // 价格
+ DownloadTimes uint `orm:"download_times" json:"downloadTimes"` // 下载次数
+ InstallPath string `orm:"install_oath" json:"installPath"` // 安装路径
+}
diff --git a/app/system/router/plugins_manage.go b/app/system/router/plugins_manage.go
new file mode 100644
index 0000000..a370b52
--- /dev/null
+++ b/app/system/router/plugins_manage.go
@@ -0,0 +1,37 @@
+// ==========================================================================
+// GFast自动生成路由代码,只生成一次,按需修改,再次生成不会覆盖.
+// 生成日期:2021-08-31 17:58:43
+// 生成路径: gfast/app/system/router/plugins_manage.go
+// 生成人:gfast
+// ==========================================================================
+
+package router
+
+import (
+ "gfast/app/system/api"
+ "gfast/middleware"
+ "github.com/gogf/gf/frame/g"
+ "github.com/gogf/gf/net/ghttp"
+)
+
+//加载路由
+func init() {
+ s := g.Server()
+ s.Group("/", func(group *ghttp.RouterGroup) {
+ group.Group("/system", func(group *ghttp.RouterGroup) {
+ group.Group("/pluginsManage", func(group *ghttp.RouterGroup) {
+ //gToken拦截器
+ api.GfToken.AuthMiddleware(group)
+ //context拦截器
+ group.Middleware(middleware.Ctx, middleware.Auth)
+ group.GET("list", api.PluginsManage.List)
+ group.GET("get", api.PluginsManage.Get)
+ group.PUT("changeStatus", api.PluginsManage.ChangeStatus)
+ group.POST("install", api.PluginsManage.Install)
+ group.GET("captcha", api.PluginsManage.Captcha)
+ group.POST("loginR", api.PluginsManage.LoginR)
+ group.POST("installOffLine", api.PluginsManage.InstallOffLine)
+ })
+ })
+ })
+}
diff --git a/app/system/service/plugins_manage.go b/app/system/service/plugins_manage.go
new file mode 100644
index 0000000..efaad7d
--- /dev/null
+++ b/app/system/service/plugins_manage.go
@@ -0,0 +1,450 @@
+// ==========================================================================
+// GFast自动生成业务逻辑层相关代码,只生成一次,按需修改,再次生成不会覆盖.
+// 生成日期:2021-08-31 17:58:43
+// 生成路径: gfast/app/system/service/plugins_manage.go
+// 生成人:gfast
+// ==========================================================================
+
+package service
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "gfast/app/common/global"
+ "gfast/app/system/dao"
+ "gfast/app/system/model"
+ "gfast/library"
+ "github.com/gogf/gf/container/garray"
+ "github.com/gogf/gf/container/gmap"
+ "github.com/gogf/gf/encoding/gcompress"
+ "github.com/gogf/gf/encoding/gjson"
+ "github.com/gogf/gf/encoding/gurl"
+ "github.com/gogf/gf/errors/gerror"
+ "github.com/gogf/gf/frame/g"
+ "github.com/gogf/gf/net/ghttp"
+ "github.com/gogf/gf/os/gfile"
+ "github.com/gogf/gf/text/gstr"
+ "github.com/gogf/gf/util/gconv"
+)
+
+type pluginsManage struct {
+}
+
+var PluginsManage = new(pluginsManage)
+
+// GetList 获取列表
+func (s *pluginsManage) GetList(req *dao.PluginsManageSearchReq) (total, page int, list []*dao.CsPluginListRes, err error) {
+ //同步服务端插件商城
+ total, page, list, err = s.syncFromStore(req)
+ return
+}
+
+// GetInfoById 通过id获取
+func (s *pluginsManage) GetInfoById(ctx context.Context, id int64) (info *dao.PluginsManageInfoRes, err error) {
+ if id == 0 {
+ err = gerror.New("参数错误")
+ return
+ }
+ var data *model.PluginsManage
+ err = dao.PluginsManage.Ctx(ctx).Where(dao.PluginsManage.Columns.Id, id).Scan(&data)
+ if err != nil {
+ g.Log().Error(err)
+ }
+ if data == nil || err != nil {
+ err = gerror.New("获取信息失败")
+ }
+ info = &dao.PluginsManageInfoRes{
+ Id: data.Id,
+ StoreId: data.StoreId,
+ PName: data.PName,
+ PTitle: data.PTitle,
+ PDescription: data.PDescription,
+ PAuth: data.PAuth,
+ IsInstall: data.IsInstall,
+ Status: data.Status,
+ Version: data.Version,
+ Price: data.Price,
+ DownloadTimes: data.DownloadTimes,
+ }
+ return
+}
+
+// Add 添加
+func (s *pluginsManage) Add(ctx context.Context, req *dao.PluginsManageAddReq) (err error) {
+ _, err = dao.PluginsManage.Ctx(ctx).Insert(req)
+ return
+}
+
+// Edit 修改
+func (s *pluginsManage) Edit(ctx context.Context, req *dao.PluginsManageEditReq) error {
+ _, err := dao.PluginsManage.Ctx(ctx).FieldsEx(dao.PluginsManage.Columns.Id).Where(dao.PluginsManage.Columns.Id, req.Id).
+ Update(req)
+ return err
+}
+
+// DeleteByIds 删除
+func (s *pluginsManage) DeleteByIds(ctx context.Context, ids []int) (err error) {
+ if len(ids) == 0 {
+ err = gerror.New("参数错误")
+ return
+ }
+ _, err = dao.PluginsManage.Ctx(ctx).Delete(dao.PluginsManage.Columns.Id+" in (?)", ids)
+ if err != nil {
+ g.Log().Error(err)
+ err = gerror.New("删除失败")
+ }
+ return
+}
+
+// ChangeStatus 修改状态
+func (s *pluginsManage) ChangeStatus(ctx context.Context, req *dao.PluginsManageStatusReq) error {
+ _, err := dao.PluginsManage.Ctx(ctx).Where(dao.PluginsManage.Columns.StoreId, req.PluginId).Update(g.Map{
+ dao.PluginsManage.Columns.Status: req.Status,
+ })
+ return err
+}
+
+//同步插件商城中的插件
+func (s *pluginsManage) syncFromStore(req *dao.PluginsManageSearchReq) (total, page int, csPluginList []*dao.CsPluginListRes, err error) {
+ storeUrl := g.Cfg().GetString("plugin.serverUrl") + "/codeStore/pluginList"
+ res := (*ghttp.ClientResponse)(nil)
+ if req.PageNum == 0 {
+ req.PageNum = 1
+ }
+ page = req.PageNum
+ res, err = g.Client().Ctx(req.Ctx).Get(storeUrl, g.MapStrAny{
+ "pageNum": req.PageNum,
+ "PageSize": req.PageSize,
+ "pluginName": req.PTitle,
+ })
+ if err != nil {
+ g.Log().Error(err)
+ err = gerror.New("获取插件数据失败")
+ return
+ }
+ defer res.Close()
+ var data map[string]interface{}
+ b := res.ReadAll()
+ err = json.Unmarshal(b, &data)
+ if err != nil {
+ g.Log().Error(err)
+ err = gerror.New("获取插件数据失败")
+ return
+ }
+ if gconv.Int(data["code"]) == 0 {
+ err = gconv.Structs((data["data"].(g.Map))["list"], &csPluginList)
+ if err != nil {
+ return
+ }
+ csPluginList, err = s.updatePlugins(req.Ctx, csPluginList)
+ if err != nil {
+ return
+ }
+ total = gconv.Int((data["data"].(g.Map))["total"])
+ } else {
+ err = gerror.New(data["msg"].(string))
+ return
+ }
+ return
+}
+
+// 更新插件数据
+func (s *pluginsManage) updatePlugins(ctx context.Context, csList []*dao.CsPluginListRes) (newList []*dao.CsPluginListRes, err error) {
+ ids := make([]uint, len(csList))
+ for k, v := range csList {
+ ids[k] = v.PluginId
+ }
+ //查询插件信息
+ var pluginList []*model.PluginsManage
+ err = dao.PluginsManage.Ctx(ctx).Where(dao.PluginsManage.Columns.StoreId+" in(?)", ids).Scan(&pluginList)
+ if err != nil {
+ return
+ }
+ hasIds := garray.NewArraySize(len(pluginList), 100)
+ gmp := gmap.New()
+ for k, v := range pluginList {
+ hasIds.Set(k, v.StoreId)
+ gmp.Set(v.StoreId, v)
+ }
+ for _, v := range csList {
+ pluginId := gconv.Int(v.PluginId)
+ if hasIds.Len() > 0 && hasIds.Contains(pluginId) {
+ plugin := gmp.Get(pluginId).(*model.PluginsManage)
+ //修改
+ version := plugin.Version
+ if plugin.IsInstall == 0 && len(v.PluginInfo) > 0 {
+ version = v.PluginInfo[0].InfoVersion
+ }
+ err = s.Edit(ctx, &dao.PluginsManageEditReq{
+ Id: plugin.Id,
+ StoreId: pluginId,
+ PName: v.CodeName,
+ PTitle: v.PluginName,
+ PDescription: v.Description,
+ PAuth: v.MemName,
+ Status: plugin.Status,
+ Version: version,
+ Price: v.PluginPrice,
+ DownloadTimes: gconv.Uint(v.DownloadTimes),
+ IsInstall: plugin.IsInstall,
+ })
+ v.Status = plugin.Status
+ v.Version = version
+ v.IsInstall = plugin.IsInstall
+ v.PluginPriceStr = s.Int64ToDecimal(gconv.Int64(v.PluginPrice))
+ } else {
+ //新增
+ version := ""
+ if len(v.PluginInfo) > 0 {
+ version = v.PluginInfo[0].InfoVersion
+ }
+ err = s.Add(ctx, &dao.PluginsManageAddReq{
+ StoreId: pluginId,
+ PName: v.CodeName,
+ PTitle: v.PluginName,
+ PDescription: v.Description,
+ PAuth: v.MemName,
+ Status: 0,
+ Version: version,
+ Price: v.PluginPrice,
+ DownloadTimes: gconv.Uint(v.DownloadTimes),
+ IsInstall: 0,
+ })
+ v.Status = 0
+ v.Version = version
+ v.IsInstall = 0
+ v.PluginPriceStr = s.Int64ToDecimal(gconv.Int64(v.PluginPrice))
+ }
+ if err != nil {
+ return
+ }
+ }
+ newList = csList
+ return
+}
+
+// DecimalToInt64 元转分
+func (s *pluginsManage) DecimalToInt64(decimal string) (i int64) {
+ pos := gstr.PosR(decimal, ".")
+ integer := gconv.Int64(gstr.SubStr(decimal, 0, pos)) * 100
+ dec := int64(0)
+ if pos > -1 {
+ dec = gconv.Int64(gstr.SubStr(decimal, pos+1, 2))
+ }
+ i = integer + dec
+ return
+}
+
+// Int64ToDecimal 分转元
+func (s *pluginsManage) Int64ToDecimal(i int64) (decimal string) {
+ b := []byte(gconv.String(i))
+ for {
+ if len(b) >= 2 {
+ break
+ }
+ b = append([]byte{'0'}, b...)
+ }
+ integer := b[:len(b)-2]
+ if len(integer) == 0 {
+ integer = []byte{'0'}
+ }
+ dec := b[len(b)-2:]
+ decimal = fmt.Sprintf("%s.%s", integer, dec)
+ return
+}
+
+// Install 插件安装
+func (s *pluginsManage) Install(ctx context.Context, req *dao.PluginsManageInstallReq) (err error) {
+ //生成下载链接
+ storeUrl := g.Cfg().GetString("plugin.serverUrl") + "/codeStoreFrontAdmin/getDownloadInfo"
+ res := (*ghttp.ClientResponse)(nil)
+ res, err = g.Client().Ctx(ctx).Get(fmt.Sprintf("%s?pluginId=%d&version=%s&token=%s", storeUrl, req.PluginId, req.Version,
+ gurl.RawEncode(req.RToken)))
+ if err != nil {
+ return
+ }
+ defer res.Close()
+ var data map[string]interface{}
+ b := res.ReadAll()
+ err = json.Unmarshal(b, &data)
+ if err != nil {
+ return
+ }
+ if gconv.Int(data["code"]) == 0 {
+ url := fmt.Sprintf("%s/%s&token=%s", g.Cfg().GetString("plugin.serverUrl"),
+ (data["data"]).(string), gurl.RawEncode(req.RToken))
+ //下载插件并安装
+ err = s.downloadAndInstall(ctx, url)
+ } else {
+ err = gerror.New(data["msg"].(string))
+ }
+ return
+}
+
+// GetCaptcha 获取验证码
+func (s *pluginsManage) GetCaptcha(ctx context.Context) (idKeyC, base64stringC string, err error) {
+ storeUrl := g.Cfg().GetString("plugin.serverUrl") + "/captcha/get"
+ res := (*ghttp.ClientResponse)(nil)
+ res, err = g.Client().Ctx(ctx).Get(storeUrl)
+ if err != nil {
+ g.Log().Error(err)
+ err = gerror.New("获取验证码失败")
+ return
+ }
+ defer res.Close()
+ var data map[string]interface{}
+ b := res.ReadAll()
+ err = json.Unmarshal(b, &data)
+ if err != nil {
+ g.Log().Error(err)
+ err = gerror.New("获取插件数据失败")
+ return
+ }
+ if gconv.Int(data["code"]) == 0 {
+ data = (data["data"]).(g.Map)
+ idKeyC = gconv.String(data["idKeyC"])
+ base64stringC = gconv.String(data["base64stringC"])
+ } else {
+ err = gerror.New(data["msg"].(string))
+ }
+ return
+}
+
+// LoginR 登录
+func (s *pluginsManage) LoginR(ctx context.Context, loginReq *dao.PluginRLoginFormReq) (userInfo g.Map, err error) {
+ storeUrl := g.Cfg().GetString("plugin.serverUrl") + "/codeStoreFrontAdmin/login"
+ res := (*ghttp.ClientResponse)(nil)
+ res, err = g.Client().Ctx(ctx).Post(storeUrl, loginReq)
+ if err != nil {
+ g.Log().Error(err)
+ err = gerror.New("获取验证码失败")
+ return
+ }
+ defer res.Close()
+ var data map[string]interface{}
+ b := res.ReadAll()
+ err = json.Unmarshal(b, &data)
+ if err != nil {
+ g.Log().Error(err)
+ err = gerror.New("登录失败")
+ return
+ }
+ if gconv.Int(data["code"]) == 0 {
+ userInfo = (data["data"]).(g.Map)
+ } else {
+ err = gerror.New(data["msg"].(string))
+ }
+ return
+}
+
+// 下载并安装插件
+func (s *pluginsManage) downloadAndInstall(ctx context.Context, url string) error {
+ res, err := g.Client().Ctx(ctx).Get(url)
+ if err != nil {
+ return err
+ }
+ defer res.Close()
+ ct := res.Header.Get("Content-Type")
+ if gstr.ContainsI(ct, "json") {
+ var data map[string]interface{}
+ b := res.ReadAll()
+ err = json.Unmarshal(b, &data)
+ if err != nil {
+ return err
+ }
+ if gconv.Int(data["code"]) != 0 {
+ err = gerror.New(data["msg"].(string))
+ }
+ return err
+ } else {
+ //安装
+ //获取插件名称
+ fileName := res.Header.Get("content-disposition")
+ fileName = gstr.SubStr(fileName, gstr.PosR(fileName, "=")+1,
+ gstr.PosR(fileName, ".")-gstr.PosR(fileName, "=")-1)
+ err = s.InstallFile(ctx, res.ReadAll(), fileName)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// InstallFile 安装插件文件
+func (s *pluginsManage) InstallFile(ctx context.Context, data []byte, fileName string) (err error) {
+ //获取插件下载路径
+ downloadPath := library.GetExcPath() + "/data/installPlugins"
+ if !gfile.IsDir(downloadPath) {
+ err = gfile.Mkdir(downloadPath)
+ if err != nil {
+ return
+ }
+ }
+ g.Log().Debug(downloadPath, fileName)
+ // 删除安装临时文件
+ defer gfile.Remove(downloadPath + "/" + fileName)
+ err = gcompress.UnZipContent(data, downloadPath)
+ if err != nil {
+ return
+ }
+ //获取插件配置信息
+ var installCfg *gjson.Json
+ installCfg, err = gjson.Load(downloadPath + "/" + fileName + "/install.json")
+ if err != nil {
+ return
+ }
+ mustGfastVersion := installCfg.GetString("minGfastVersion")
+ if gstr.CompareVersion(mustGfastVersion, global.Version) > 0 {
+ err = gerror.New(fmt.Sprintf("您的gfast版本过低,此插件要求gfast版本为:%s", mustGfastVersion))
+ return
+ }
+ //获取本项目安装情况
+ var plugin *model.PluginsManage
+ err = dao.PluginsManage.Ctx(ctx).Where(dao.PluginsManage.Columns.PName, fileName).Limit(1).Scan(&plugin)
+ if err != nil {
+ return
+ }
+ if plugin == nil {
+ err = gerror.New("插件信息不存在,请刷新页面后再安装。")
+ return
+ }
+ //复制插件文件到对应目录
+ //1.后端
+ err = gfile.Copy(downloadPath+"/"+fileName+"/go/", library.GetExcPath())
+ if err != nil {
+ return
+ }
+ //2.前端
+ fontRoot := g.Cfg().GetString("gen.frontDir")
+ if !gfile.IsDir(fontRoot) {
+ err = gerror.New("前端路径不存在,请配置gen.frontDir")
+ return
+ }
+ err = gfile.Copy(downloadPath+"/"+fileName+"/vue/", fontRoot+"/src")
+ if err != nil {
+ return
+ }
+ // 安装成功后修改插件安装状态及安装路径
+ _, err = dao.PluginsManage.Ctx(ctx).WherePri(plugin.Id).Update(g.Map{
+ dao.PluginsManage.Columns.IsInstall: 1,
+ dao.PluginsManage.Columns.Status: 1,
+ dao.PluginsManage.Columns.InstallPath: installCfg.GetString("installPath"),
+ dao.PluginsManage.Columns.Version: installCfg.GetString("version"),
+ })
+ return
+}
+
+// PluginIsExists 判断插件是否存在
+func (s *pluginsManage) PluginIsExists(ctx context.Context, name string) error {
+ info := (*model.PluginsManage)(nil)
+ err := dao.PluginsManage.Ctx(ctx).Where(dao.PluginsManage.Columns.PName, name).Limit(1).
+ Fields(dao.PluginsManage.Columns.Id).Scan(&info)
+ if err != nil {
+ return err
+ }
+ if info == nil {
+ return gerror.New("不属于官方插件,无法安装。")
+ }
+ return nil
+}
diff --git a/config/config.toml b/config/config.toml
index 48e74a5..5a10d1d 100644
--- a/config/config.toml
+++ b/config/config.toml
@@ -46,7 +46,7 @@
# Redis数据库配置
[redis]
open = true #是否开启 redis 缓存 若不开启使用gchache缓存方式
- default = "127.0.0.1:6379,9?idleTimeout=20&maxActive=100"
+ default = "127.0.0.1:6379,2?idleTimeout=20&maxActive=100"
#jwt配置
[gToken]
@@ -87,4 +87,9 @@
SecretID = "填写您的SecretID"
SecretKey = "填写您的SecretKey"
[upload.local] #本地上传配置
- UpPath = "/pub_upload/" #上传路径
\ No newline at end of file
+ UpPath = "/pub_upload/" #上传路径
+
+
+# 插件管理
+[plugin]
+ serverUrl = "http://localhost:8199" #获取插件商城插件列表
\ No newline at end of file
diff --git a/library/response.go b/library/response.go
index 160a8af..3535bd1 100644
--- a/library/response.go
+++ b/library/response.go
@@ -1,11 +1,10 @@
package library
import (
- "github.com/gogf/gf/frame/g"
+ "fmt"
+ "github.com/gogf/gf/encoding/gurl"
"github.com/gogf/gf/net/ghttp"
"github.com/gogf/gf/os/gview"
- "github.com/gogf/gf/text/gstr"
- "github.com/gogf/gf/util/gconv"
)
const (
@@ -87,35 +86,16 @@ func (res *Response) FailJson(isExit bool, r *ghttp.Request, msg string, data ..
//模板输出
func (res *Response) WriteTpl(r *ghttp.Request, tpl string, view *gview.View, params ...gview.Params) error {
- //绑定模板中需要用到的方法
- view.BindFuncMap(g.Map{
- // 根据长度i来切割字符串
- "subStr": func(str interface{}, i int) (s string) {
- s1 := gconv.String(str)
- if gstr.LenRune(s1) > i {
- s = gstr.SubStrRune(s1, 0, i) + "..."
- return s
- }
- return s1
- },
- // 格式化时间戳 年月日
- "timeFormatYear": func(time interface{}) string {
- return TimeStampToDate(gconv.Int64(time))
- },
- // 格式化时间戳 年月日时分秒
- "timeFormatDateTime": func(time interface{}) string {
- return TimeStampToDateTime(gconv.Int64(time))
- },
- "add": func(a, b interface{}) int {
- return gconv.Int(a) + gconv.Int(b)
- },
- })
//设置全局变量
- domain, _ := GetDomain(r)
- view.Assigns(g.Map{
- "domain": domain,
- })
- return r.Response.WriteTpl(tpl, params...)
+ urlInfo, _ := gurl.ParseURL(r.GetUrl(), -1)
+ view.Assign("urlInfo", urlInfo)
+ r.SetView(view)
+ err := r.Response.WriteTpl(tpl, params...)
+ if err != nil {
+ fmt.Println(err.Error())
+ r.Response.WriteExit(err.Error())
+ }
+ return nil
}
func (res *Response) Redirect(r *ghttp.Request, location string, code ...int) {
diff --git a/library/utils.go b/library/utils.go
index 4f6f87a..ea6cbc8 100644
--- a/library/utils.go
+++ b/library/utils.go
@@ -14,6 +14,9 @@ import (
"github.com/gogf/gf/text/gstr"
"github.com/gogf/gf/util/gconv"
"net"
+ "os"
+ "os/exec"
+ "path/filepath"
"strings"
)
@@ -247,3 +250,13 @@ func CurrencyLong(currency interface{}) int64 {
}
return 0
}
+
+func GetExcPath() string {
+ file, _ := exec.LookPath(os.Args[0])
+ // 获取包含可执行文件名称的路径
+ path, _ := filepath.Abs(file)
+ // 获取可执行文件所在目录
+ index := strings.LastIndex(path, string(os.PathSeparator))
+ ret := path[:index]
+ return strings.Replace(ret, "\\", "/", -1)
+}
diff --git a/template/vm/vue/list-vue.template b/template/vm/vue/list-vue.template
index 4ccc0df..8c58b52 100644
--- a/template/vm/vue/list-vue.template
+++ b/template/vm/vue/list-vue.template
@@ -277,11 +277,11 @@
{{else if eq $column.HtmlType "file"}}
-
+
{{else if eq $column.HtmlType "files"}}
-
+
{{end}}
{{end}}
diff --git a/template/vm/vue/tree-vue.template b/template/vm/vue/tree-vue.template
index ade41ac..435bc78 100644
--- a/template/vm/vue/tree-vue.template
+++ b/template/vm/vue/tree-vue.template
@@ -281,11 +281,11 @@
{{else if eq $column.HtmlType "file"}}
-
+
{{else if eq $column.HtmlType "files"}}
-
+
{{end}}
{{end}}