Compare commits
36 Commits
d968ce2a3e
...
dev-web
Author | SHA1 | Date | |
---|---|---|---|
![]() |
6d0239fe60 | ||
![]() |
09ae980ab5 | ||
![]() |
c52f7e2097 | ||
![]() |
1844a843eb | ||
![]() |
593185a431 | ||
![]() |
ab7ef546ea | ||
![]() |
8fd70be906 | ||
![]() |
d342a5bae9 | ||
![]() |
6b5231d169 | ||
![]() |
c7cc2e36fd | ||
![]() |
2fabbf5c0f | ||
![]() |
e37da632df | ||
![]() |
219dcdc372 | ||
![]() |
ca849de37f | ||
![]() |
e14df1fd99 | ||
![]() |
2e37eae3ca | ||
![]() |
9f7f0c9dd7 | ||
![]() |
1102a60425 | ||
![]() |
8a29bf610c | ||
![]() |
056caf5d06 | ||
![]() |
d550942cd2 | ||
![]() |
c22384fbc0 | ||
![]() |
d42b89cc8b | ||
![]() |
c32db8c8f6 | ||
![]() |
f723c12d42 | ||
![]() |
da54e71c27 | ||
![]() |
0d46bb7d07 | ||
![]() |
cffb1ee0f4 | ||
![]() |
143cf61a57 | ||
![]() |
1dc2d77e82 | ||
![]() |
37748ecb7f | ||
![]() |
5de8b45b2f | ||
![]() |
3fb8cd4dad | ||
![]() |
274a4d93df | ||
![]() |
c383e1737f | ||
![]() |
2a40d560d4 |
@@ -9,7 +9,7 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/lzh-1625/go_process_manager/config"
|
"github.com/lzh-1625/go_process_manager/config"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/constants"
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/logic"
|
"github.com/lzh-1625/go_process_manager/internal/app/logic"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/middle"
|
"github.com/lzh-1625/go_process_manager/internal/app/middle"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/repository"
|
"github.com/lzh-1625/go_process_manager/internal/app/repository"
|
||||||
@@ -86,12 +86,12 @@ func initProcess() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func initJwtSecret() {
|
func initJwtSecret() {
|
||||||
if secret, err := repository.ConfigRepository.GetConfigValue(constants.SECRET_KEY); err == nil {
|
if secret, err := repository.ConfigRepository.GetConfigValue(eum.SecretKey); err == nil {
|
||||||
utils.SetSecret([]byte(secret))
|
utils.SetSecret([]byte(secret))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
secret := utils.RandString(32)
|
secret := utils.RandString(32)
|
||||||
repository.ConfigRepository.SetConfigValue(constants.SECRET_KEY, secret)
|
repository.ConfigRepository.SetConfigValue(eum.SecretKey, secret)
|
||||||
utils.SetSecret([]byte(secret))
|
utils.SetSecret([]byte(secret))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,6 +123,7 @@ func initListenKillSignal() {
|
|||||||
sigs := make(chan os.Signal, 1)
|
sigs := make(chan os.Signal, 1)
|
||||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||||
<-sigs
|
<-sigs
|
||||||
|
logger.Logger.Info("进程正在退出,等待全部进程停止")
|
||||||
logic.ProcessCtlLogic.KillAllProcess()
|
logic.ProcessCtlLogic.KillAllProcess()
|
||||||
log.Print("已停止所有进程")
|
log.Print("已停止所有进程")
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
|
@@ -7,7 +7,34 @@ import (
|
|||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var startTitle = `
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
_____ _____ _____
|
||||||
|
/\ \ /\ \ /\ \
|
||||||
|
/::\ \ /::\ \ /::\____\
|
||||||
|
/::::\ \ /::::\ \ /::::| |
|
||||||
|
/::::::\ \ /::::::\ \ /:::::| |
|
||||||
|
/:::/\:::\ \ /:::/\:::\ \ /::::::| |
|
||||||
|
/:::/ \:::\ \ /:::/__\:::\ \ /:::/|::| |
|
||||||
|
/:::/ \:::\ \ /::::\ \:::\ \ /:::/ |::| |
|
||||||
|
/:::/ / \:::\ \ /::::::\ \:::\ \ /:::/ |::|___|______
|
||||||
|
/:::/ / \:::\ ___\ /:::/\:::\ \:::\____\ /:::/ |::::::::\ \
|
||||||
|
/:::/____/ ___\:::| |/:::/ \:::\ \:::| |/:::/ |:::::::::\____\
|
||||||
|
\:::\ \ /\ /:::|____|\::/ \:::\ /:::|____|\::/ / ~~~~~/:::/ /
|
||||||
|
\:::\ /::\ \::/ / \/_____/\:::\/:::/ / \/____/ /:::/ /
|
||||||
|
\:::\ \:::\ \/____/ \::::::/ / /:::/ /
|
||||||
|
\:::\ \:::\____\ \::::/ / /:::/ /
|
||||||
|
\:::\ /:::/ / \::/____/ /:::/ /
|
||||||
|
\:::\/:::/ / ~~ /:::/ /
|
||||||
|
\::::::/ / /:::/ /
|
||||||
|
\::::/ / /:::/ /
|
||||||
|
\::/____/ \::/ /
|
||||||
|
\/____/
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
`
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
print(startTitle)
|
||||||
gin.SetMode(gin.ReleaseMode)
|
gin.SetMode(gin.ReleaseMode)
|
||||||
route.Route()
|
route.Route()
|
||||||
}
|
}
|
||||||
|
@@ -32,6 +32,5 @@ type configuration struct {
|
|||||||
CgroupPeriod int64 `default:"100000" describe:"CgroupPeriod"`
|
CgroupPeriod int64 `default:"100000" describe:"CgroupPeriod"`
|
||||||
CgroupSwapLimit bool `default:"false" describe:"cgroup swap限制"`
|
CgroupSwapLimit bool `default:"false" describe:"cgroup swap限制"`
|
||||||
CondWaitTime int `default:"30" describe:"长轮询等待时间(秒)"`
|
CondWaitTime int `default:"30" describe:"长轮询等待时间(秒)"`
|
||||||
PerformanceCapacityDisplay bool `default:"false" describe:"性能资源容量显示"`
|
|
||||||
Tui bool `default:"-"`
|
Tui bool `default:"-"`
|
||||||
}
|
}
|
||||||
|
@@ -3,28 +3,28 @@ package api
|
|||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/constants"
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/repository"
|
"github.com/lzh-1625/go_process_manager/internal/app/repository"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getRole(ctx *gin.Context) constants.Role {
|
func getRole(ctx *gin.Context) eum.Role {
|
||||||
if v, ok := ctx.Get(constants.CTXFLG_ROLE); ok {
|
if v, ok := ctx.Get(eum.CtxRole); ok {
|
||||||
return v.(constants.Role)
|
return v.(eum.Role)
|
||||||
}
|
}
|
||||||
return constants.ROLE_GUEST
|
return eum.RoleGuest
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUserName(ctx *gin.Context) string {
|
func getUserName(ctx *gin.Context) string {
|
||||||
return ctx.GetString(constants.CTXFLG_USER_NAME)
|
return ctx.GetString(eum.CtxUserName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isAdmin(ctx *gin.Context) bool {
|
func isAdmin(ctx *gin.Context) bool {
|
||||||
return getRole(ctx) <= constants.ROLE_ADMIN
|
return getRole(ctx) <= eum.RoleAdmin
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasOprPermission(ctx *gin.Context, uuid int, op constants.OprPermission) bool {
|
func hasOprPermission(ctx *gin.Context, uuid int, op eum.OprPermission) bool {
|
||||||
return isAdmin(ctx) || reflect.ValueOf(repository.PermissionRepository.GetPermission(getUserName(ctx), uuid)).FieldByName(string(op)).Bool()
|
return isAdmin(ctx) || reflect.ValueOf(repository.PermissionRepository.GetPermission(getUserName(ctx), uuid)).FieldByName(string(op)).Bool()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -4,7 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/constants"
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/logic"
|
"github.com/lzh-1625/go_process_manager/internal/app/logic"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/repository"
|
"github.com/lzh-1625/go_process_manager/internal/app/repository"
|
||||||
@@ -20,7 +20,7 @@ func (a *logApi) GetLog(ctx *gin.Context, req model.GetLogReq) any {
|
|||||||
if isAdmin(ctx) {
|
if isAdmin(ctx) {
|
||||||
return logic.LogLogicImpl.Search(req, req.FilterName...)
|
return logic.LogLogicImpl.Search(req, req.FilterName...)
|
||||||
} else {
|
} else {
|
||||||
processNameList := repository.PermissionRepository.GetProcessNameByPermission(getUserName(ctx), constants.OPERATION_LOG)
|
processNameList := repository.PermissionRepository.GetProcessNameByPermission(getUserName(ctx), eum.OperationLog)
|
||||||
filterName := slices.DeleteFunc(req.FilterName, func(s string) bool {
|
filterName := slices.DeleteFunc(req.FilterName, func(s string) bool {
|
||||||
return !slices.Contains(processNameList, s)
|
return !slices.Contains(processNameList, s)
|
||||||
})
|
})
|
||||||
|
@@ -5,6 +5,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/logic"
|
"github.com/lzh-1625/go_process_manager/internal/app/logic"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/repository"
|
"github.com/lzh-1625/go_process_manager/internal/app/repository"
|
||||||
@@ -44,12 +45,18 @@ func (p *procApi) DeleteNewProcess(ctx *gin.Context, req struct {
|
|||||||
func (p *procApi) KillProcess(ctx *gin.Context, req struct {
|
func (p *procApi) KillProcess(ctx *gin.Context, req struct {
|
||||||
Uuid int `form:"uuid" binding:"required"`
|
Uuid int `form:"uuid" binding:"required"`
|
||||||
}) (err error) {
|
}) (err error) {
|
||||||
|
if !hasOprPermission(ctx, req.Uuid, eum.OperationStop) {
|
||||||
|
return errors.New("not permission")
|
||||||
|
}
|
||||||
return logic.ProcessCtlLogic.KillProcess(req.Uuid)
|
return logic.ProcessCtlLogic.KillProcess(req.Uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *procApi) StartProcess(ctx *gin.Context, req struct {
|
func (p *procApi) StartProcess(ctx *gin.Context, req struct {
|
||||||
Uuid int `form:"uuid" binding:"required"`
|
Uuid int `json:"uuid" binding:"required"`
|
||||||
}) (err error) {
|
}) (err error) {
|
||||||
|
if !hasOprPermission(ctx, req.Uuid, eum.OperationStart) {
|
||||||
|
return errors.New("not permission")
|
||||||
|
}
|
||||||
prod, err := logic.ProcessCtlLogic.GetProcess(req.Uuid)
|
prod, err := logic.ProcessCtlLogic.GetProcess(req.Uuid)
|
||||||
if err != nil { // 进程不存在则创建
|
if err != nil { // 进程不存在则创建
|
||||||
proConfig, err := repository.ProcessRepository.GetProcessConfigById(req.Uuid)
|
proConfig, err := repository.ProcessRepository.GetProcessConfigById(req.Uuid)
|
||||||
@@ -63,7 +70,7 @@ func (p *procApi) StartProcess(ctx *gin.Context, req struct {
|
|||||||
logic.ProcessCtlLogic.AddProcess(req.Uuid, proc)
|
logic.ProcessCtlLogic.AddProcess(req.Uuid, proc)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if prod.State.State == 1 {
|
if prod.State.State == eum.ProcessStateStart || prod.State.State == eum.ProcessStateRunning {
|
||||||
return errors.New("process is currently running")
|
return errors.New("process is currently running")
|
||||||
}
|
}
|
||||||
prod.ResetRestartTimes()
|
prod.ResetRestartTimes()
|
||||||
|
@@ -4,7 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/lzh-1625/go_process_manager/config"
|
"github.com/lzh-1625/go_process_manager/config"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/constants"
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/repository"
|
"github.com/lzh-1625/go_process_manager/internal/app/repository"
|
||||||
"github.com/lzh-1625/go_process_manager/utils"
|
"github.com/lzh-1625/go_process_manager/utils"
|
||||||
@@ -27,7 +27,6 @@ func (u *userApi) LoginHandler(ctx *gin.Context, req model.LoginHandlerReq) any
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return gin.H{
|
return gin.H{
|
||||||
"code": 0,
|
|
||||||
"token": token,
|
"token": token,
|
||||||
"username": req.Account,
|
"username": req.Account,
|
||||||
"role": repository.UserRepository.GetUserByName(req.Account).Role,
|
"role": repository.UserRepository.GetUserByName(req.Account).Role,
|
||||||
@@ -35,10 +34,10 @@ func (u *userApi) LoginHandler(ctx *gin.Context, req model.LoginHandlerReq) any
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *userApi) CreateUser(ctx *gin.Context, req model.User) (err error) {
|
func (u *userApi) CreateUser(ctx *gin.Context, req model.User) (err error) {
|
||||||
if req.Role == constants.ROLE_ROOT {
|
if req.Role == eum.RoleRoot {
|
||||||
return errors.New("creation of root accounts is forbidden")
|
return errors.New("creation of root accounts is forbidden")
|
||||||
}
|
}
|
||||||
if req.Account == constants.CONSOLE {
|
if req.Account == eum.Console {
|
||||||
return errors.New("operation failed")
|
return errors.New("operation failed")
|
||||||
}
|
}
|
||||||
if len(req.Password) < config.CF.UserPassWordMinLength {
|
if len(req.Password) < config.CF.UserPassWordMinLength {
|
||||||
@@ -50,7 +49,7 @@ func (u *userApi) CreateUser(ctx *gin.Context, req model.User) (err error) {
|
|||||||
|
|
||||||
func (u *userApi) ChangePassword(ctx *gin.Context, req model.User) (err error) {
|
func (u *userApi) ChangePassword(ctx *gin.Context, req model.User) (err error) {
|
||||||
reqUser := getUserName(ctx)
|
reqUser := getUserName(ctx)
|
||||||
if getRole(ctx) != constants.ROLE_ROOT && req.Account != "" {
|
if getRole(ctx) != eum.RoleRoot && req.Account != "" {
|
||||||
return errors.New("invalid parameters")
|
return errors.New("invalid parameters")
|
||||||
}
|
}
|
||||||
var userName string
|
var userName string
|
||||||
@@ -84,7 +83,7 @@ func (u *userApi) checkLoginInfo(account, password string) bool {
|
|||||||
repository.UserRepository.CreateUser(model.User{
|
repository.UserRepository.CreateUser(model.User{
|
||||||
Account: "root",
|
Account: "root",
|
||||||
Password: DEFAULT_ROOT_PASSWORD,
|
Password: DEFAULT_ROOT_PASSWORD,
|
||||||
Role: constants.ROLE_ROOT,
|
Role: eum.RoleRoot,
|
||||||
})
|
})
|
||||||
return password == DEFAULT_ROOT_PASSWORD
|
return password == DEFAULT_ROOT_PASSWORD
|
||||||
}
|
}
|
||||||
|
@@ -3,12 +3,13 @@ package api
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/lzh-1625/go_process_manager/config"
|
"github.com/lzh-1625/go_process_manager/config"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/constants"
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/logic"
|
"github.com/lzh-1625/go_process_manager/internal/app/logic"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/repository"
|
"github.com/lzh-1625/go_process_manager/internal/app/repository"
|
||||||
@@ -46,9 +47,15 @@ func (w *WsConnetInstance) Cancel() {
|
|||||||
var upgrader = websocket.Upgrader{
|
var upgrader = websocket.Upgrader{
|
||||||
ReadBufferSize: 1024,
|
ReadBufferSize: 1024,
|
||||||
WriteBufferSize: 1024,
|
WriteBufferSize: 1024,
|
||||||
|
CheckOrigin: func(r *http.Request) bool {
|
||||||
|
return true // 允许所有跨域请求
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *wsApi) WebsocketHandle(ctx *gin.Context, req model.WebsocketHandleReq) (err error) {
|
func (w *wsApi) WebsocketHandle(ctx *gin.Context, req model.WebsocketHandleReq) (err error) {
|
||||||
|
if !hasOprPermission(ctx, req.Uuid, eum.OperationTerminal) {
|
||||||
|
return errors.New("not permission")
|
||||||
|
}
|
||||||
reqUser := getUserName(ctx)
|
reqUser := getUserName(ctx)
|
||||||
proc, err := logic.ProcessCtlLogic.GetProcess(req.Uuid)
|
proc, err := logic.ProcessCtlLogic.GetProcess(req.Uuid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -64,7 +71,7 @@ func (w *wsApi) WebsocketHandle(ctx *gin.Context, req model.WebsocketHandleReq)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer conn.Close()
|
||||||
log.Logger.Infow("ws连接成功")
|
log.Logger.Infow("ws连接成功")
|
||||||
|
|
||||||
wsCtx, cancel := context.WithCancel(context.Background())
|
wsCtx, cancel := context.WithCancel(context.Background())
|
||||||
@@ -73,10 +80,12 @@ func (w *wsApi) WebsocketHandle(ctx *gin.Context, req model.WebsocketHandleReq)
|
|||||||
CancelFunc: cancel,
|
CancelFunc: cancel,
|
||||||
wsLock: sync.Mutex{},
|
wsLock: sync.Mutex{},
|
||||||
}
|
}
|
||||||
proc.ReadCache(wci)
|
if err := proc.ReadCache(wci); err != nil {
|
||||||
if proc.State.State == 1 {
|
return nil
|
||||||
|
}
|
||||||
|
if proc.State.State == eum.ProcessStateRunning {
|
||||||
proc.SetTerminalSize(req.Cols, req.Rows)
|
proc.SetTerminalSize(req.Cols, req.Rows)
|
||||||
w.startWsConnect(wci, cancel, proc, hasOprPermission(ctx, req.Uuid, constants.OPERATION_TERMINAL_WRITE))
|
w.startWsConnect(wci, cancel, proc, hasOprPermission(ctx, req.Uuid, eum.OperationTerminalWrite))
|
||||||
proc.AddConn(reqUser, wci)
|
proc.AddConn(reqUser, wci)
|
||||||
defer proc.DeleteConn(reqUser)
|
defer proc.DeleteConn(reqUser)
|
||||||
}
|
}
|
||||||
@@ -92,7 +101,6 @@ func (w *wsApi) WebsocketHandle(ctx *gin.Context, req model.WebsocketHandleReq)
|
|||||||
case <-wsCtx.Done():
|
case <-wsCtx.Done():
|
||||||
log.Logger.Infow("ws连接断开", "操作类型", "tcp连接建立已被关闭")
|
log.Logger.Infow("ws连接断开", "操作类型", "tcp连接建立已被关闭")
|
||||||
}
|
}
|
||||||
conn.Close()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +120,7 @@ func (w *wsApi) WebsocketShareHandle(ctx *gin.Context, req model.WebsocketHandle
|
|||||||
if proc.HasWsConn(guestName) {
|
if proc.HasWsConn(guestName) {
|
||||||
return errors.New("connection already exists")
|
return errors.New("connection already exists")
|
||||||
}
|
}
|
||||||
if proc.State.State != 1 {
|
if proc.State.State != eum.ProcessStateRunning {
|
||||||
return errors.New("process not is running")
|
return errors.New("process not is running")
|
||||||
}
|
}
|
||||||
if !proc.VerifyControl() {
|
if !proc.VerifyControl() {
|
||||||
@@ -122,7 +130,7 @@ func (w *wsApi) WebsocketShareHandle(ctx *gin.Context, req model.WebsocketHandle
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer conn.Close()
|
||||||
log.Logger.Infow("ws连接成功")
|
log.Logger.Infow("ws连接成功")
|
||||||
data.UpdatedAt = time.Now()
|
data.UpdatedAt = time.Now()
|
||||||
repository.WsShare.Edit(data)
|
repository.WsShare.Edit(data)
|
||||||
@@ -134,7 +142,9 @@ func (w *wsApi) WebsocketShareHandle(ctx *gin.Context, req model.WebsocketHandle
|
|||||||
CancelFunc: cancel,
|
CancelFunc: cancel,
|
||||||
wsLock: sync.Mutex{},
|
wsLock: sync.Mutex{},
|
||||||
}
|
}
|
||||||
proc.ReadCache(wci)
|
if err := proc.ReadCache(wci); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
w.startWsConnect(wci, cancel, proc, data.Write)
|
w.startWsConnect(wci, cancel, proc, data.Write)
|
||||||
proc.AddConn(guestName, wci)
|
proc.AddConn(guestName, wci)
|
||||||
defer proc.DeleteConn(guestName)
|
defer proc.DeleteConn(guestName)
|
||||||
@@ -152,7 +162,6 @@ func (w *wsApi) WebsocketShareHandle(ctx *gin.Context, req model.WebsocketHandle
|
|||||||
case <-time.After(time.Until(data.ExpireTime)):
|
case <-time.After(time.Until(data.ExpireTime)):
|
||||||
log.Logger.Infow("ws连接断开", "操作类型", "分享时间已结束")
|
log.Logger.Infow("ws连接断开", "操作类型", "分享时间已结束")
|
||||||
}
|
}
|
||||||
conn.Close()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,6 +0,0 @@
|
|||||||
package constants
|
|
||||||
|
|
||||||
const (
|
|
||||||
SECRET_KEY = "secret"
|
|
||||||
CONSOLE = "console"
|
|
||||||
)
|
|
@@ -1,7 +0,0 @@
|
|||||||
package constants
|
|
||||||
|
|
||||||
const (
|
|
||||||
CTXFLG_USER_NAME = "user"
|
|
||||||
CTXFLG_ROLE = "role"
|
|
||||||
CTXFLG_ERR = "err"
|
|
||||||
)
|
|
@@ -1,11 +0,0 @@
|
|||||||
package constants
|
|
||||||
|
|
||||||
type OprPermission string
|
|
||||||
|
|
||||||
const (
|
|
||||||
OPERATION_START OprPermission = "Start"
|
|
||||||
OPERATION_STOP OprPermission = "Stop"
|
|
||||||
OPERATION_TERMINAL OprPermission = "Terminal"
|
|
||||||
OPERATION_TERMINAL_WRITE OprPermission = "Write"
|
|
||||||
OPERATION_LOG OprPermission = "Log"
|
|
||||||
)
|
|
@@ -1,16 +0,0 @@
|
|||||||
package constants
|
|
||||||
|
|
||||||
type TerminalType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
TERMINAL_PTY TerminalType = "pty"
|
|
||||||
TERMINAL_STD TerminalType = "std"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ProcessState int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
PROCESS_STOP ProcessState = iota
|
|
||||||
PROCESS_START
|
|
||||||
PROCESS_WARNNING
|
|
||||||
)
|
|
@@ -1,10 +0,0 @@
|
|||||||
package constants
|
|
||||||
|
|
||||||
type Role int
|
|
||||||
|
|
||||||
const (
|
|
||||||
ROLE_ROOT Role = iota
|
|
||||||
ROLE_ADMIN
|
|
||||||
ROLE_USER
|
|
||||||
ROLE_GUEST
|
|
||||||
)
|
|
@@ -1,19 +0,0 @@
|
|||||||
package constants
|
|
||||||
|
|
||||||
type Condition int
|
|
||||||
|
|
||||||
const (
|
|
||||||
RUNNING Condition = iota
|
|
||||||
NOT_RUNNING
|
|
||||||
EXCEPTION
|
|
||||||
PASS
|
|
||||||
)
|
|
||||||
|
|
||||||
type TaskOperation int
|
|
||||||
|
|
||||||
const (
|
|
||||||
TASK_START TaskOperation = iota
|
|
||||||
TASK_STOP
|
|
||||||
TASK_START_WAIT_DONE
|
|
||||||
TASK_STOP_WAIT_DONE
|
|
||||||
)
|
|
6
internal/app/eum/consts.go
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package eum
|
||||||
|
|
||||||
|
const (
|
||||||
|
SecretKey = "secret"
|
||||||
|
Console = "console"
|
||||||
|
)
|
11
internal/app/eum/event.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package eum
|
||||||
|
|
||||||
|
type EventType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
EventProcessStart EventType = "ProcessStart"
|
||||||
|
EventProcessStop EventType = "ProcessStop"
|
||||||
|
EventProcessWarning EventType = "ProcessWarning"
|
||||||
|
EventTaskStart EventType = "TaskStart"
|
||||||
|
EventTaskStop EventType = "TaskStop"
|
||||||
|
)
|
6
internal/app/eum/gin.go
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package eum
|
||||||
|
|
||||||
|
const (
|
||||||
|
CtxUserName = "user"
|
||||||
|
CtxRole = "role"
|
||||||
|
)
|
11
internal/app/eum/permission.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package eum
|
||||||
|
|
||||||
|
type OprPermission string
|
||||||
|
|
||||||
|
const (
|
||||||
|
OperationStart OprPermission = "Start"
|
||||||
|
OperationStop OprPermission = "Stop"
|
||||||
|
OperationTerminal OprPermission = "Terminal"
|
||||||
|
OperationTerminalWrite OprPermission = "Write"
|
||||||
|
OperationLog OprPermission = "Log"
|
||||||
|
)
|
17
internal/app/eum/process.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package eum
|
||||||
|
|
||||||
|
type TerminalType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
TerminalPty TerminalType = "pty"
|
||||||
|
TerminalStd TerminalType = "std"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProcessState int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
ProcessStateStop ProcessState = iota
|
||||||
|
ProcessStateStart
|
||||||
|
ProcessStateWarnning
|
||||||
|
ProcessStateRunning
|
||||||
|
)
|
10
internal/app/eum/role.go
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package eum
|
||||||
|
|
||||||
|
type Role int
|
||||||
|
|
||||||
|
const (
|
||||||
|
RoleRoot Role = iota
|
||||||
|
RoleAdmin
|
||||||
|
RoleUser
|
||||||
|
RoleGuest
|
||||||
|
)
|
21
internal/app/eum/task.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package eum
|
||||||
|
|
||||||
|
type Condition int
|
||||||
|
|
||||||
|
const (
|
||||||
|
TaskCondRunning Condition = iota
|
||||||
|
TaskCondNotRunning
|
||||||
|
TaskCondException
|
||||||
|
TaskCondPass
|
||||||
|
)
|
||||||
|
|
||||||
|
type TaskOperation int
|
||||||
|
|
||||||
|
const (
|
||||||
|
TaskStart TaskOperation = iota
|
||||||
|
TaskStop
|
||||||
|
TaskStartWaitDone
|
||||||
|
TaskStopWaitDone
|
||||||
|
)
|
||||||
|
|
||||||
|
type CtxTaskTraceId struct{}
|
35
internal/app/logic/event.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package logic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
|
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
||||||
|
"github.com/lzh-1625/go_process_manager/internal/app/repository"
|
||||||
|
"github.com/lzh-1625/go_process_manager/log"
|
||||||
|
"github.com/lzh-1625/go_process_manager/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type eventLogic struct{}
|
||||||
|
|
||||||
|
var EventLogic = new(eventLogic)
|
||||||
|
|
||||||
|
func (e *eventLogic) Create(name string, eventType eum.EventType, additionalKv ...string) {
|
||||||
|
if len(additionalKv)%2 != 0 {
|
||||||
|
log.Logger.Errorw("参数长度错误", "args", additionalKv)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data := model.Event{
|
||||||
|
Name: name,
|
||||||
|
CreatedTime: time.Now(),
|
||||||
|
Type: eventType,
|
||||||
|
}
|
||||||
|
m := map[string]string{}
|
||||||
|
for i := range len(additionalKv) / 2 {
|
||||||
|
m[additionalKv[2*i]] = additionalKv[2*i+1]
|
||||||
|
}
|
||||||
|
data.Additional = utils.StructToJsonStr(m)
|
||||||
|
if err := repository.EventRepository.Create(data); err != nil {
|
||||||
|
log.Logger.Errorw("事件创建失败", "err", err)
|
||||||
|
}
|
||||||
|
}
|
@@ -1,6 +1,7 @@
|
|||||||
package logic
|
package logic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -10,7 +11,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/lzh-1625/go_process_manager/config"
|
"github.com/lzh-1625/go_process_manager/config"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/constants"
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/middle"
|
"github.com/lzh-1625/go_process_manager/internal/app/middle"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
||||||
"github.com/lzh-1625/go_process_manager/log"
|
"github.com/lzh-1625/go_process_manager/log"
|
||||||
@@ -20,14 +21,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Process interface {
|
type Process interface {
|
||||||
ReadCache(ConnectInstance)
|
ReadCache(ConnectInstance) error
|
||||||
Write(string) error
|
Write(string) error
|
||||||
WriteBytes([]byte) error
|
WriteBytes([]byte) error
|
||||||
readInit()
|
readInit()
|
||||||
doOnInit()
|
doOnInit()
|
||||||
doOnKilled()
|
doOnKilled()
|
||||||
Start() error
|
Start() error
|
||||||
Type() constants.TerminalType
|
Type() eum.TerminalType
|
||||||
SetTerminalSize(int, int)
|
SetTerminalSize(int, int)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,7 +59,7 @@ type ProcessBase struct {
|
|||||||
State struct {
|
State struct {
|
||||||
startTime time.Time
|
startTime time.Time
|
||||||
Info string
|
Info string
|
||||||
State constants.ProcessState //0 为未运行,1为运作中,2为异常状态
|
State eum.ProcessState //0 为未运行,1为运作中,2为异常状态
|
||||||
stateLock sync.Mutex
|
stateLock sync.Mutex
|
||||||
restartTimes int
|
restartTimes int
|
||||||
manualStopFlag bool
|
manualStopFlag bool
|
||||||
@@ -93,7 +94,7 @@ func (p *ProcessBase) watchDog() {
|
|||||||
}
|
}
|
||||||
close(p.StopChan)
|
close(p.StopChan)
|
||||||
p.doOnKilled()
|
p.doOnKilled()
|
||||||
p.SetState(constants.PROCESS_STOP)
|
p.SetState(eum.ProcessStateStop)
|
||||||
if state.ExitCode() != 0 {
|
if state.ExitCode() != 0 {
|
||||||
log.Logger.Infow("进程停止", "进程名称", p.Name, "exitCode", state.ExitCode(), "进程类型", p.Type())
|
log.Logger.Infow("进程停止", "进程名称", p.Name, "exitCode", state.ExitCode(), "进程类型", p.Type())
|
||||||
p.push(fmt.Sprintf("进程停止,退出码 %d", state.ExitCode()))
|
p.push(fmt.Sprintf("进程停止,退出码 %d", state.ExitCode()))
|
||||||
@@ -117,7 +118,7 @@ func (p *ProcessBase) watchDog() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Logger.Warnw("重启次数达到上限", "name", p.Name, "limit", config.CF.ProcessRestartsLimit)
|
log.Logger.Warnw("重启次数达到上限", "name", p.Name, "limit", config.CF.ProcessRestartsLimit)
|
||||||
p.SetState(constants.PROCESS_WARNNING)
|
p.SetState(eum.ProcessStateWarnning)
|
||||||
p.State.Info = "重启次数异常"
|
p.State.Info = "重启次数异常"
|
||||||
p.push("进程重启次数达到上限")
|
p.push("进程重启次数达到上限")
|
||||||
}
|
}
|
||||||
@@ -139,7 +140,7 @@ func (p *ProcessBase) pInit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// fn 函数执行成功的情况下对state赋值
|
// fn 函数执行成功的情况下对state赋值
|
||||||
func (p *ProcessBase) SetState(state constants.ProcessState, fn ...func() bool) bool {
|
func (p *ProcessBase) SetState(state eum.ProcessState, fn ...func() bool) bool {
|
||||||
p.State.stateLock.Lock()
|
p.State.stateLock.Lock()
|
||||||
defer p.State.stateLock.Unlock()
|
defer p.State.stateLock.Unlock()
|
||||||
for _, v := range fn {
|
for _, v := range fn {
|
||||||
@@ -149,10 +150,26 @@ func (p *ProcessBase) SetState(state constants.ProcessState, fn ...func() bool)
|
|||||||
}
|
}
|
||||||
p.State.State = state
|
p.State.State = state
|
||||||
middle.ProcessWaitCond.Trigger()
|
middle.ProcessWaitCond.Trigger()
|
||||||
|
p.createEvent(state)
|
||||||
go TaskLogic.RunTaskByTriggerEvent(p.Name, state)
|
go TaskLogic.RunTaskByTriggerEvent(p.Name, state)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *ProcessBase) createEvent(state eum.ProcessState) {
|
||||||
|
var eventType eum.EventType
|
||||||
|
switch state {
|
||||||
|
case eum.ProcessStateRunning:
|
||||||
|
eventType = eum.EventProcessStart
|
||||||
|
case eum.ProcessStateStop:
|
||||||
|
eventType = eum.EventProcessStop
|
||||||
|
case eum.ProcessStateWarnning:
|
||||||
|
eventType = eum.EventProcessWarning
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
EventLogic.Create(p.Name, eventType)
|
||||||
|
}
|
||||||
|
|
||||||
func (p *ProcessBase) GetUserString() string {
|
func (p *ProcessBase) GetUserString() string {
|
||||||
return strings.Join(p.GetUserList(), ";")
|
return strings.Join(p.GetUserList(), ";")
|
||||||
}
|
}
|
||||||
@@ -267,7 +284,7 @@ func (p *ProcessBase) monitorHanler() {
|
|||||||
ticker := time.NewTicker(time.Second * time.Duration(config.CF.PerformanceInfoInterval))
|
ticker := time.NewTicker(time.Second * time.Duration(config.CF.PerformanceInfoInterval))
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
for {
|
for {
|
||||||
if p.State.State != 1 {
|
if p.State.State != eum.ProcessStateRunning {
|
||||||
log.Logger.Debugw("进程未在运行", "state", p.State.State)
|
log.Logger.Debugw("进程未在运行", "state", p.State.State)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -306,6 +323,10 @@ func (p *ProcessBase) initPsutil() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProcessBase) Kill() error {
|
func (p *ProcessBase) Kill() error {
|
||||||
|
if p.State.State != eum.ProcessStateRunning {
|
||||||
|
return errors.New("can't kill not running process")
|
||||||
|
}
|
||||||
|
p.State.manualStopFlag = true
|
||||||
p.op.Signal(syscall.SIGINT)
|
p.op.Signal(syscall.SIGINT)
|
||||||
select {
|
select {
|
||||||
case <-p.StopChan:
|
case <-p.StopChan:
|
||||||
|
@@ -4,11 +4,10 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"runtime"
|
"runtime"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/lzh-1625/go_process_manager/config"
|
"github.com/google/shlex"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/constants"
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/repository"
|
"github.com/lzh-1625/go_process_manager/internal/app/repository"
|
||||||
"github.com/lzh-1625/go_process_manager/log"
|
"github.com/lzh-1625/go_process_manager/log"
|
||||||
@@ -37,10 +36,6 @@ func (p *processCtlLogic) KillProcess(uuid int) error {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("进程类型错误")
|
return errors.New("进程类型错误")
|
||||||
}
|
}
|
||||||
if result.State.State != 1 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
result.State.manualStopFlag = true
|
|
||||||
return result.Kill()
|
return result.Kill()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,13 +56,9 @@ func (p *processCtlLogic) KillAllProcess() {
|
|||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
p.processMap.Range(func(key, value any) bool {
|
p.processMap.Range(func(key, value any) bool {
|
||||||
process := value.(*ProcessBase)
|
process := value.(*ProcessBase)
|
||||||
if process.State.State != 1 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
process.State.manualStopFlag = true
|
|
||||||
process.Kill()
|
process.Kill()
|
||||||
}()
|
}()
|
||||||
return true
|
return true
|
||||||
@@ -76,7 +67,7 @@ func (p *processCtlLogic) KillAllProcess() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *processCtlLogic) KillAllProcessByUserName(userName string) {
|
func (p *processCtlLogic) KillAllProcessByUserName(userName string) {
|
||||||
stopPermissionProcess := repository.PermissionRepository.GetProcessNameByPermission(userName, constants.OPERATION_STOP)
|
stopPermissionProcess := repository.PermissionRepository.GetProcessNameByPermission(userName, eum.OperationStop)
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
p.processMap.Range(func(key, value any) bool {
|
p.processMap.Range(func(key, value any) bool {
|
||||||
process := value.(*ProcessBase)
|
process := value.(*ProcessBase)
|
||||||
@@ -124,10 +115,8 @@ func (p *processCtlLogic) getProcessInfoList(processConfiglist []model.Process)
|
|||||||
pi.User = process.GetUserString()
|
pi.User = process.GetUserString()
|
||||||
pi.Usage.Cpu = process.performanceStatus.cpu
|
pi.Usage.Cpu = process.performanceStatus.cpu
|
||||||
pi.Usage.Mem = process.performanceStatus.mem
|
pi.Usage.Mem = process.performanceStatus.mem
|
||||||
if config.CF.PerformanceCapacityDisplay {
|
|
||||||
pi.Usage.CpuCapacity = float64(runtime.NumCPU()) * 100.0
|
pi.Usage.CpuCapacity = float64(runtime.NumCPU()) * 100.0
|
||||||
pi.Usage.MemCapacity = float64(utils.UnwarpIgnore(mem.VirtualMemory()).Total >> 10)
|
pi.Usage.MemCapacity = float64(utils.UnwarpIgnore(mem.VirtualMemory()).Total >> 10)
|
||||||
}
|
|
||||||
pi.Usage.Time = process.performanceStatus.time
|
pi.Usage.Time = process.performanceStatus.time
|
||||||
pi.TermType = process.Type()
|
pi.TermType = process.Type()
|
||||||
pi.CgroupEnable = process.Config.cgroupEnable
|
pi.CgroupEnable = process.Config.cgroupEnable
|
||||||
@@ -183,7 +172,7 @@ func (p *processCtlLogic) ProcessInit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *processCtlLogic) ProcesStartAllByUsername(userName string) {
|
func (p *processCtlLogic) ProcesStartAllByUsername(userName string) {
|
||||||
startPermissionProcess := repository.PermissionRepository.GetProcessNameByPermission(userName, constants.OPERATION_START)
|
startPermissionProcess := repository.PermissionRepository.GetProcessNameByPermission(userName, eum.OperationStart)
|
||||||
p.processMap.Range(func(key, value any) bool {
|
p.processMap.Range(func(key, value any) bool {
|
||||||
process := value.(*ProcessBase)
|
process := value.(*ProcessBase)
|
||||||
if !slices.Contains(startPermissionProcess, process.Name) {
|
if !slices.Contains(startPermissionProcess, process.Name) {
|
||||||
@@ -217,7 +206,7 @@ func (p *processCtlLogic) UpdateProcessConfig(config model.Process) error {
|
|||||||
result.Config.cpuLimit = config.CpuLimit
|
result.Config.cpuLimit = config.CpuLimit
|
||||||
result.Config.AutoRestart = config.AutoRestart
|
result.Config.AutoRestart = config.AutoRestart
|
||||||
result.Config.compulsoryRestart = config.CompulsoryRestart
|
result.Config.compulsoryRestart = config.CompulsoryRestart
|
||||||
result.StartCommand = strings.Fields(config.Cmd)
|
result.StartCommand = utils.UnwarpIgnore(shlex.Split(config.Cmd))
|
||||||
result.WorkDir = config.Cwd
|
result.WorkDir = config.Cwd
|
||||||
result.Name = config.Name
|
result.Name = config.Name
|
||||||
return nil
|
return nil
|
||||||
@@ -225,9 +214,9 @@ func (p *processCtlLogic) UpdateProcessConfig(config model.Process) error {
|
|||||||
|
|
||||||
func (p *processCtlLogic) NewProcess(config model.Process) (proc *ProcessBase, err error) {
|
func (p *processCtlLogic) NewProcess(config model.Process) (proc *ProcessBase, err error) {
|
||||||
switch config.TermType {
|
switch config.TermType {
|
||||||
case constants.TERMINAL_STD:
|
case eum.TerminalStd:
|
||||||
proc = NewProcessStd(config)
|
proc = NewProcessStd(config)
|
||||||
case constants.TERMINAL_PTY:
|
case eum.TerminalPty:
|
||||||
proc = NewProcessPty(config)
|
proc = NewProcessPty(config)
|
||||||
default:
|
default:
|
||||||
err = errors.New("终端类型错误")
|
err = errors.New("终端类型错误")
|
||||||
|
@@ -2,13 +2,14 @@ package logic
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/google/shlex"
|
"github.com/google/shlex"
|
||||||
"github.com/lzh-1625/go_process_manager/config"
|
"github.com/lzh-1625/go_process_manager/config"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/constants"
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
||||||
"github.com/lzh-1625/go_process_manager/log"
|
"github.com/lzh-1625/go_process_manager/log"
|
||||||
"github.com/lzh-1625/go_process_manager/utils"
|
"github.com/lzh-1625/go_process_manager/utils"
|
||||||
@@ -26,20 +27,20 @@ func (p *ProcessPty) doOnKilled() {
|
|||||||
p.pty.Close()
|
p.pty.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProcessPty) Type() constants.TerminalType {
|
func (p *ProcessPty) Type() eum.TerminalType {
|
||||||
return constants.TERMINAL_PTY
|
return eum.TerminalPty
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProcessPty) Start() (err error) {
|
func (p *ProcessPty) Start() (err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.Config.AutoRestart = false
|
p.Config.AutoRestart = false
|
||||||
p.SetState(constants.PROCESS_WARNNING)
|
p.SetState(eum.ProcessStateWarnning)
|
||||||
p.State.Info = "进程启动失败:" + err.Error()
|
p.State.Info = "进程启动失败:" + err.Error()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
if ok := p.SetState(constants.PROCESS_START, func() bool {
|
if ok := p.SetState(eum.ProcessStateStart, func() bool {
|
||||||
return p.State.State != 1
|
return p.State.State != eum.ProcessStateStart
|
||||||
}); !ok {
|
}); !ok {
|
||||||
log.Logger.Warnw("进程已在运行,跳过启动")
|
log.Logger.Warnw("进程已在运行,跳过启动")
|
||||||
return nil
|
return nil
|
||||||
@@ -113,10 +114,12 @@ func (p *ProcessPty) readInit() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProcessPty) ReadCache(ws ConnectInstance) {
|
func (p *ProcessPty) ReadCache(ws ConnectInstance) error {
|
||||||
if p.cacheBytesBuf != nil {
|
if p.cacheBytesBuf == nil {
|
||||||
ws.Write(p.cacheBytesBuf.Bytes())
|
return errors.New("cache is null")
|
||||||
}
|
}
|
||||||
|
ws.Write(p.cacheBytesBuf.Bytes())
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProcessPty) bufHanle(b []byte) {
|
func (p *ProcessPty) bufHanle(b []byte) {
|
||||||
@@ -139,10 +142,7 @@ func NewProcessPty(pconfig model.Process) *ProcessBase {
|
|||||||
StartCommand: utils.UnwarpIgnore(shlex.Split(pconfig.Cmd)),
|
StartCommand: utils.UnwarpIgnore(shlex.Split(pconfig.Cmd)),
|
||||||
WorkDir: pconfig.Cwd,
|
WorkDir: pconfig.Cwd,
|
||||||
}
|
}
|
||||||
processPty := ProcessPty{
|
p.Process = &ProcessPty{ProcessBase: &p}
|
||||||
ProcessBase: &p,
|
p.setProcessConfig(pconfig)
|
||||||
}
|
|
||||||
p.Process = &processPty
|
|
||||||
processPty.setProcessConfig(pconfig)
|
|
||||||
return &p
|
return &p
|
||||||
}
|
}
|
||||||
|
@@ -2,11 +2,13 @@ package logic
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/google/shlex"
|
||||||
"github.com/lzh-1625/go_process_manager/config"
|
"github.com/lzh-1625/go_process_manager/config"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/constants"
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
||||||
"github.com/lzh-1625/go_process_manager/log"
|
"github.com/lzh-1625/go_process_manager/log"
|
||||||
"github.com/lzh-1625/go_process_manager/utils"
|
"github.com/lzh-1625/go_process_manager/utils"
|
||||||
@@ -24,20 +26,20 @@ func (p *ProcessPty) doOnKilled() {
|
|||||||
p.pty.Close()
|
p.pty.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProcessPty) Type() constants.TerminalType {
|
func (p *ProcessPty) Type() eum.TerminalType {
|
||||||
return constants.TERMINAL_PTY
|
return eum.TerminalPty
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProcessPty) Start() (err error) {
|
func (p *ProcessPty) Start() (err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.Config.AutoRestart = false
|
p.Config.AutoRestart = false
|
||||||
p.SetState(constants.PROCESS_WARNNING)
|
p.SetState(eum.ProcessStateWarnning)
|
||||||
p.State.Info = "进程启动失败:" + err.Error()
|
p.State.Info = "进程启动失败:" + err.Error()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
if ok := p.SetState(constants.PROCESS_START, func() bool {
|
if ok := p.SetState(eum.ProcessStateStart, func() bool {
|
||||||
return p.State.State != 1
|
return p.State.State != eum.ProcessStateRunning && p.State.State != eum.ProcessStateStart
|
||||||
}); !ok {
|
}); !ok {
|
||||||
log.Logger.Warnw("进程已在运行,跳过启动")
|
log.Logger.Warnw("进程已在运行,跳过启动")
|
||||||
return nil
|
return nil
|
||||||
@@ -66,6 +68,11 @@ func (p *ProcessPty) Start() (err error) {
|
|||||||
}
|
}
|
||||||
log.Logger.Infow("进程启动成功", "进程名称", p.Name, "重启次数", p.State.restartTimes)
|
log.Logger.Infow("进程启动成功", "进程名称", p.Name, "重启次数", p.State.restartTimes)
|
||||||
p.pInit()
|
p.pInit()
|
||||||
|
if !p.SetState(eum.ProcessStateRunning, func() bool {
|
||||||
|
return p.State.State == eum.ProcessStateStart
|
||||||
|
}) {
|
||||||
|
return errors.New("状态异常启动失败")
|
||||||
|
}
|
||||||
p.push("进程启动成功")
|
p.push("进程启动成功")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -115,8 +122,12 @@ func (p *ProcessPty) readInit() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProcessPty) ReadCache(ws ConnectInstance) {
|
func (p *ProcessPty) ReadCache(ws ConnectInstance) error {
|
||||||
|
if p.cacheBytesBuf == nil {
|
||||||
|
return errors.New("cache is null")
|
||||||
|
}
|
||||||
ws.Write(p.cacheBytesBuf.Bytes())
|
ws.Write(p.cacheBytesBuf.Bytes())
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProcessPty) bufHanle(b []byte) {
|
func (p *ProcessPty) bufHanle(b []byte) {
|
||||||
@@ -135,13 +146,10 @@ func (p *ProcessPty) doOnInit() {
|
|||||||
func NewProcessPty(pconfig model.Process) *ProcessBase {
|
func NewProcessPty(pconfig model.Process) *ProcessBase {
|
||||||
p := ProcessBase{
|
p := ProcessBase{
|
||||||
Name: pconfig.Name,
|
Name: pconfig.Name,
|
||||||
StartCommand: strings.Split(pconfig.Cmd, " "),
|
StartCommand: utils.UnwarpIgnore(shlex.Split(pconfig.Cmd)),
|
||||||
WorkDir: pconfig.Cwd,
|
WorkDir: pconfig.Cwd,
|
||||||
}
|
}
|
||||||
processPty := ProcessPty{
|
p.Process = &ProcessPty{ProcessBase: &p}
|
||||||
ProcessBase: &p,
|
p.setProcessConfig(pconfig)
|
||||||
}
|
|
||||||
p.Process = &processPty
|
|
||||||
processPty.setProcessConfig(pconfig)
|
|
||||||
return &p
|
return &p
|
||||||
}
|
}
|
||||||
|
@@ -2,13 +2,14 @@ package logic
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
|
||||||
"github.com/google/shlex"
|
"github.com/google/shlex"
|
||||||
|
|
||||||
"github.com/lzh-1625/go_process_manager/config"
|
"github.com/lzh-1625/go_process_manager/config"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/constants"
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
||||||
"github.com/lzh-1625/go_process_manager/log"
|
"github.com/lzh-1625/go_process_manager/log"
|
||||||
"github.com/lzh-1625/go_process_manager/utils"
|
"github.com/lzh-1625/go_process_manager/utils"
|
||||||
@@ -21,8 +22,8 @@ type ProcessStd struct {
|
|||||||
stdout *bufio.Scanner
|
stdout *bufio.Scanner
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProcessStd) Type() constants.TerminalType {
|
func (p *ProcessStd) Type() eum.TerminalType {
|
||||||
return constants.TERMINAL_STD
|
return eum.TerminalStd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProcessStd) WriteBytes(input []byte) (err error) {
|
func (p *ProcessStd) WriteBytes(input []byte) (err error) {
|
||||||
@@ -41,12 +42,12 @@ func (p *ProcessStd) Start() (err error) {
|
|||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.Config.AutoRestart = false
|
p.Config.AutoRestart = false
|
||||||
p.SetState(constants.PROCESS_WARNNING)
|
p.SetState(eum.ProcessStateWarnning)
|
||||||
p.State.Info = "进程启动失败:" + err.Error()
|
p.State.Info = "进程启动失败:" + err.Error()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
if ok := p.SetState(constants.PROCESS_START, func() bool {
|
if ok := p.SetState(eum.ProcessStateStart, func() bool {
|
||||||
return p.State.State != 1
|
return p.State.State != eum.ProcessStateRunning && p.State.State != eum.ProcessStateStart
|
||||||
}); !ok {
|
}); !ok {
|
||||||
log.Logger.Warnw("进程已在运行,跳过启动")
|
log.Logger.Warnw("进程已在运行,跳过启动")
|
||||||
return nil
|
return nil
|
||||||
@@ -73,6 +74,11 @@ func (p *ProcessStd) Start() (err error) {
|
|||||||
log.Logger.Infow("进程启动成功", "重启次数", p.State.restartTimes)
|
log.Logger.Infow("进程启动成功", "重启次数", p.State.restartTimes)
|
||||||
p.op = cmd.Process
|
p.op = cmd.Process
|
||||||
p.pInit()
|
p.pInit()
|
||||||
|
if !p.SetState(eum.ProcessStateRunning, func() bool {
|
||||||
|
return p.State.State == eum.ProcessStateStart
|
||||||
|
}) {
|
||||||
|
return errors.New("状态异常启动失败")
|
||||||
|
}
|
||||||
p.push("进程启动成功")
|
p.push("进程启动成功")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -81,10 +87,14 @@ func (p *ProcessStd) doOnInit() {
|
|||||||
p.cacheLine = make([]string, config.CF.ProcessMsgCacheLinesLimit)
|
p.cacheLine = make([]string, config.CF.ProcessMsgCacheLinesLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProcessStd) ReadCache(ws ConnectInstance) {
|
func (p *ProcessStd) ReadCache(ws ConnectInstance) error {
|
||||||
|
if len(p.cacheLine) == 0 {
|
||||||
|
return errors.New("cache is null")
|
||||||
|
}
|
||||||
for _, line := range p.cacheLine {
|
for _, line := range p.cacheLine {
|
||||||
ws.WriteString(line)
|
ws.WriteString(line)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProcessStd) doOnKilled() {
|
func (p *ProcessStd) doOnKilled() {
|
||||||
@@ -137,10 +147,7 @@ func NewProcessStd(pconfig model.Process) *ProcessBase {
|
|||||||
StartCommand: utils.UnwarpIgnore(shlex.Split(pconfig.Cmd)),
|
StartCommand: utils.UnwarpIgnore(shlex.Split(pconfig.Cmd)),
|
||||||
WorkDir: pconfig.Cwd,
|
WorkDir: pconfig.Cwd,
|
||||||
}
|
}
|
||||||
processStd := ProcessStd{
|
p.Process = &ProcessStd{ProcessBase: &p}
|
||||||
ProcessBase: &p,
|
p.setProcessConfig(pconfig)
|
||||||
}
|
|
||||||
p.Process = &processStd
|
|
||||||
processStd.setProcessConfig(pconfig)
|
|
||||||
return &p
|
return &p
|
||||||
}
|
}
|
||||||
|
@@ -4,7 +4,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/constants"
|
"github.com/google/uuid"
|
||||||
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/middle"
|
"github.com/lzh-1625/go_process_manager/internal/app/middle"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
||||||
"github.com/lzh-1625/go_process_manager/log"
|
"github.com/lzh-1625/go_process_manager/log"
|
||||||
@@ -25,7 +26,7 @@ func NewTaskJob(data model.Task) (*TaskJob, error) {
|
|||||||
TaskConfig: &data,
|
TaskConfig: &data,
|
||||||
StartTime: time.Now(),
|
StartTime: time.Now(),
|
||||||
}
|
}
|
||||||
if data.CronExpression != "" {
|
if data.Enable && data.CronExpression != "" {
|
||||||
err := tj.InitCronHandle()
|
err := tj.InitCronHandle()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Logger.Warnw("定时任务启动失败", "err", err, "task", data.Id)
|
log.Logger.Warnw("定时任务启动失败", "err", err, "task", data.Id)
|
||||||
@@ -35,6 +36,11 @@ func NewTaskJob(data model.Task) (*TaskJob, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *TaskJob) Run(ctx context.Context) {
|
func (t *TaskJob) Run(ctx context.Context) {
|
||||||
|
if ctx.Value(eum.CtxTaskTraceId{}) == nil {
|
||||||
|
ctx = context.WithValue(ctx, eum.CtxTaskTraceId{}, uuid.NewString())
|
||||||
|
}
|
||||||
|
EventLogic.Create(t.TaskConfig.Name, eum.EventTaskStart, "traceId", ctx.Value(eum.CtxTaskTraceId{}).(string))
|
||||||
|
defer EventLogic.Create(t.TaskConfig.Name, eum.EventTaskStop, "traceId", ctx.Value(eum.CtxTaskTraceId{}).(string))
|
||||||
t.Running = true
|
t.Running = true
|
||||||
middle.TaskWaitCond.Trigger()
|
middle.TaskWaitCond.Trigger()
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -43,7 +49,7 @@ func (t *TaskJob) Run(ctx context.Context) {
|
|||||||
}()
|
}()
|
||||||
var ok bool
|
var ok bool
|
||||||
// 判断条件是否满足
|
// 判断条件是否满足
|
||||||
if t.TaskConfig.Condition == constants.PASS {
|
if t.TaskConfig.Condition == eum.TaskCondPass {
|
||||||
ok = true
|
ok = true
|
||||||
} else {
|
} else {
|
||||||
proc, err := ProcessCtlLogic.GetProcess(t.TaskConfig.OperationTarget)
|
proc, err := ProcessCtlLogic.GetProcess(t.TaskConfig.OperationTarget)
|
||||||
@@ -66,7 +72,7 @@ func (t *TaskJob) Run(ctx context.Context) {
|
|||||||
// 执行操作
|
// 执行操作
|
||||||
log.Logger.Infow("任务开始执行")
|
log.Logger.Infow("任务开始执行")
|
||||||
if !OperationHandle[t.TaskConfig.Operation](t.TaskConfig, proc) {
|
if !OperationHandle[t.TaskConfig.Operation](t.TaskConfig, proc) {
|
||||||
log.Logger.Errorw("任务执行失败")
|
log.Logger.Warnw("任务执行失败")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Logger.Infow("任务执行成功", "target", t.TaskConfig.OperationTarget)
|
log.Logger.Infow("任务执行成功", "target", t.TaskConfig.OperationTarget)
|
||||||
@@ -114,6 +120,7 @@ func (t *TaskJob) InitCronHandle() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
c.Start()
|
||||||
t.Cron = c
|
t.Cron = c
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@@ -4,50 +4,50 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/lzh-1625/go_process_manager/config"
|
"github.com/lzh-1625/go_process_manager/config"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/constants"
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
||||||
"github.com/lzh-1625/go_process_manager/log"
|
"github.com/lzh-1625/go_process_manager/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
type conditionFunc func(data *model.Task, proc *ProcessBase) bool
|
type conditionFunc func(data *model.Task, proc *ProcessBase) bool
|
||||||
|
|
||||||
var conditionHandle = map[constants.Condition]conditionFunc{
|
var conditionHandle = map[eum.Condition]conditionFunc{
|
||||||
constants.RUNNING: func(data *model.Task, proc *ProcessBase) bool {
|
eum.TaskCondRunning: func(data *model.Task, proc *ProcessBase) bool {
|
||||||
return proc.State.State == 1
|
return proc.State.State == eum.ProcessStateRunning
|
||||||
},
|
},
|
||||||
constants.NOT_RUNNING: func(data *model.Task, proc *ProcessBase) bool {
|
eum.TaskCondNotRunning: func(data *model.Task, proc *ProcessBase) bool {
|
||||||
return proc.State.State != 1
|
return proc.State.State != eum.ProcessStateRunning && proc.State.State != eum.ProcessStateStart
|
||||||
},
|
},
|
||||||
constants.EXCEPTION: func(data *model.Task, proc *ProcessBase) bool {
|
eum.TaskCondException: func(data *model.Task, proc *ProcessBase) bool {
|
||||||
return proc.State.State == 2
|
return proc.State.State == eum.ProcessStateWarnning
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// 执行操作,返回结果是否成功
|
// 执行操作,返回结果是否成功
|
||||||
type operationFunc func(data *model.Task, proc *ProcessBase) bool
|
type operationFunc func(data *model.Task, proc *ProcessBase) bool
|
||||||
|
|
||||||
var OperationHandle = map[constants.TaskOperation]operationFunc{
|
var OperationHandle = map[eum.TaskOperation]operationFunc{
|
||||||
constants.TASK_START: func(data *model.Task, proc *ProcessBase) bool {
|
eum.TaskStart: func(data *model.Task, proc *ProcessBase) bool {
|
||||||
if proc.State.State == 1 {
|
if proc.State.State == eum.ProcessStateRunning || proc.State.State == eum.ProcessStateStart {
|
||||||
log.Logger.Debugw("进程已在运行")
|
log.Logger.Debugw("进程已在运行", "proc", proc.Name)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
go proc.Start()
|
proc.Start()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
|
|
||||||
constants.TASK_START_WAIT_DONE: func(data *model.Task, proc *ProcessBase) bool {
|
eum.TaskStartWaitDone: func(data *model.Task, proc *ProcessBase) bool {
|
||||||
if proc.State.State == 1 {
|
if proc.State.State == eum.ProcessStateRunning || proc.State.State == eum.ProcessStateStart {
|
||||||
log.Logger.Debugw("进程已在运行")
|
log.Logger.Debugw("进程已在运行", "proc", proc.Name)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if err := proc.Start(); err != nil {
|
if err := proc.Start(); err != nil {
|
||||||
log.Logger.Debugw("进程启动失败")
|
log.Logger.Debugw("进程启动失败", "proc", proc.Name)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case <-proc.StopChan:
|
case <-proc.StopChan:
|
||||||
log.Logger.Debugw("进程停止,任务完成")
|
log.Logger.Debugw("进程停止,任务完成", "proc", proc.Name)
|
||||||
return true
|
return true
|
||||||
case <-time.After(time.Second * time.Duration(config.CF.TaskTimeout)):
|
case <-time.After(time.Second * time.Duration(config.CF.TaskTimeout)):
|
||||||
log.Logger.Errorw("任务超时")
|
log.Logger.Errorw("任务超时")
|
||||||
@@ -55,24 +55,22 @@ var OperationHandle = map[constants.TaskOperation]operationFunc{
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
constants.TASK_STOP: func(data *model.Task, proc *ProcessBase) bool {
|
eum.TaskStop: func(data *model.Task, proc *ProcessBase) bool {
|
||||||
if proc.State.State != 1 {
|
if proc.State.State != eum.ProcessStateRunning {
|
||||||
log.Logger.Debugw("进程未在运行")
|
log.Logger.Debugw("进程未在运行", "proc", proc.Name)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
log.Logger.Debugw("异步停止任务")
|
log.Logger.Debugw("异步停止任务", "proc", proc.Name)
|
||||||
proc.State.manualStopFlag = true
|
|
||||||
go proc.Kill()
|
go proc.Kill()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
|
|
||||||
constants.TASK_STOP_WAIT_DONE: func(data *model.Task, proc *ProcessBase) bool {
|
eum.TaskStopWaitDone: func(data *model.Task, proc *ProcessBase) bool {
|
||||||
if proc.State.State != 1 {
|
if proc.State.State != eum.ProcessStateRunning {
|
||||||
log.Logger.Debugw("进程未在运行")
|
log.Logger.Debugw("进程未在运行", "proc", proc.Name)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
log.Logger.Debugw("停止任务并等待结束")
|
log.Logger.Debugw("停止任务并等待结束", "proc", proc.Name)
|
||||||
proc.State.manualStopFlag = true
|
|
||||||
return proc.Kill() == nil
|
return proc.Kill() == nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@@ -5,7 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/constants"
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/repository"
|
"github.com/lzh-1625/go_process_manager/internal/app/repository"
|
||||||
"github.com/lzh-1625/go_process_manager/log"
|
"github.com/lzh-1625/go_process_manager/log"
|
||||||
@@ -154,7 +154,7 @@ func (t *taskLogic) RunTaskByKey(key string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *taskLogic) RunTaskByTriggerEvent(processName string, event constants.ProcessState) {
|
func (t *taskLogic) RunTaskByTriggerEvent(processName string, event eum.ProcessState) {
|
||||||
taskList := repository.TaskRepository.GetTriggerTask(processName, event)
|
taskList := repository.TaskRepository.GetTriggerTask(processName, event)
|
||||||
if len(taskList) == 0 {
|
if len(taskList) == 0 {
|
||||||
return
|
return
|
||||||
|
@@ -6,7 +6,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/constants"
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
"github.com/lzh-1625/go_process_manager/log"
|
"github.com/lzh-1625/go_process_manager/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ func Logger() gin.HandlerFunc {
|
|||||||
logKv = append(logKv, "Status", ctx.Writer.Status())
|
logKv = append(logKv, "Status", ctx.Writer.Status())
|
||||||
logKv = append(logKv, "Path", path)
|
logKv = append(logKv, "Path", path)
|
||||||
logKv = append(logKv, "耗时", fmt.Sprintf("%dms", time.Now().UnixMilli()-start.UnixMilli()))
|
logKv = append(logKv, "耗时", fmt.Sprintf("%dms", time.Now().UnixMilli()-start.UnixMilli()))
|
||||||
if user, ok := ctx.Get(constants.CTXFLG_USER_NAME); ok {
|
if user, ok := ctx.Get(eum.CtxUserName); ok {
|
||||||
logKv = append(logKv, "user", user)
|
logKv = append(logKv, "user", user)
|
||||||
}
|
}
|
||||||
switch {
|
switch {
|
||||||
|
@@ -1,39 +1,14 @@
|
|||||||
package middle
|
package middle
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/constants"
|
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/repository"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func RolePermission(needPermission constants.Role) func(ctx *gin.Context) {
|
func RolePermission(needPermission eum.Role) func(ctx *gin.Context) {
|
||||||
return func(ctx *gin.Context) {
|
return func(ctx *gin.Context) {
|
||||||
if v, ok := ctx.Get(constants.CTXFLG_ROLE); !ok || v.(constants.Role) > needPermission {
|
if v, ok := ctx.Get(eum.CtxRole); !ok || v.(eum.Role) > needPermission {
|
||||||
rErr(ctx, -1, "Insufficient permissions; please check your access rights!", nil)
|
|
||||||
ctx.Abort()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.Next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func OprPermission(op constants.OprPermission) func(ctx *gin.Context) {
|
|
||||||
return func(ctx *gin.Context) {
|
|
||||||
uuid, err := strconv.Atoi(ctx.Query("uuid"))
|
|
||||||
if err != nil {
|
|
||||||
rErr(ctx, -1, "Invalid parameters!", nil)
|
|
||||||
ctx.Abort()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if v, ok := ctx.Get(constants.CTXFLG_ROLE); !ok || v.(constants.Role) <= constants.ROLE_ADMIN {
|
|
||||||
ctx.Next()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !reflect.ValueOf(repository.PermissionRepository.GetPermission(ctx.GetString(constants.CTXFLG_USER_NAME), uuid)).FieldByName(string(op)).Bool() {
|
|
||||||
rErr(ctx, -1, "Insufficient permissions; please check your access rights!", nil)
|
rErr(ctx, -1, "Insufficient permissions; please check your access rights!", nil)
|
||||||
ctx.Abort()
|
ctx.Abort()
|
||||||
return
|
return
|
||||||
|
@@ -1,11 +1,10 @@
|
|||||||
package middle
|
package middle
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/constants"
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/repository"
|
"github.com/lzh-1625/go_process_manager/internal/app/repository"
|
||||||
"github.com/lzh-1625/go_process_manager/log"
|
"github.com/lzh-1625/go_process_manager/log"
|
||||||
"github.com/lzh-1625/go_process_manager/utils"
|
"github.com/lzh-1625/go_process_manager/utils"
|
||||||
@@ -46,36 +45,19 @@ func CheckToken() gin.HandlerFunc {
|
|||||||
return strings.HasPrefix(c.Request.URL.Path, s)
|
return strings.HasPrefix(c.Request.URL.Path, s)
|
||||||
}) {
|
}) {
|
||||||
var token string
|
var token string
|
||||||
if c.Request.Header.Get("token") != "" {
|
if c.Request.Header.Get("Authorization") != "" {
|
||||||
token = c.Request.Header.Get("token")
|
token = strings.TrimPrefix(c.Request.Header.Get("Authorization"), "bearer ")
|
||||||
} else {
|
} else {
|
||||||
token = c.Query("token")
|
token = c.Query("token")
|
||||||
}
|
}
|
||||||
if _, err := utils.VerifyToken(token); err != nil {
|
if mc, err := utils.VerifyToken(token); err != nil {
|
||||||
rErr(c, -2, "token校验失败", err)
|
rErr(c, -2, "token校验失败", err)
|
||||||
return
|
return
|
||||||
}
|
|
||||||
if username, err := getUser(c); err != nil {
|
|
||||||
rErr(c, -1, "无法获取user信息", err)
|
|
||||||
} else {
|
} else {
|
||||||
c.Set(constants.CTXFLG_USER_NAME, username)
|
c.Set(eum.CtxUserName, mc.Username)
|
||||||
c.Set(constants.CTXFLG_ROLE, repository.UserRepository.GetUserByName(username).Role)
|
c.Set(eum.CtxRole, repository.UserRepository.GetUserByName(mc.Username).Role)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.Next()
|
c.Next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUser(ctx *gin.Context) (string, error) {
|
|
||||||
var token string
|
|
||||||
if ctx.Request.Header.Get("token") != "" {
|
|
||||||
token = ctx.Request.Header.Get("token")
|
|
||||||
} else {
|
|
||||||
token = ctx.Query("token")
|
|
||||||
}
|
|
||||||
if mc, err := utils.VerifyToken(token); err == nil && mc != nil {
|
|
||||||
return mc.Username, nil
|
|
||||||
} else {
|
|
||||||
return "", errors.Join(errors.New("用户信息获取失败"), err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -43,7 +43,7 @@ func (p *waitCond) Trigger() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *waitCond) WaitGetMiddel(c *gin.Context) {
|
func (p *waitCond) WaitGetMiddel(c *gin.Context) {
|
||||||
reqUser := c.GetHeader("token")
|
reqUser := c.GetHeader("Uuid")
|
||||||
defer p.timeMap.Store(reqUser, p.ts)
|
defer p.timeMap.Store(reqUser, p.ts)
|
||||||
if ts, ok := p.timeMap.Load(reqUser); !ok || ts.(int64) > p.ts {
|
if ts, ok := p.timeMap.Load(reqUser); !ok || ts.(int64) > p.ts {
|
||||||
c.Next()
|
c.Next()
|
||||||
|
19
internal/app/model/event.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Event struct {
|
||||||
|
Id uint64 `gorm:"primaryKey;autoIncrement;column:id" json:"id"`
|
||||||
|
Name string `gorm:"column:name" json:"name"`
|
||||||
|
Type eum.EventType `gorm:"column:type" json:"type"`
|
||||||
|
Additional string `gorm:"column:additional" json:"additional"`
|
||||||
|
CreatedTime time.Time `gorm:"column:created_time" json:"createdTime"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Event) TableName() string {
|
||||||
|
return "event"
|
||||||
|
}
|
@@ -1,6 +1,6 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import "github.com/lzh-1625/go_process_manager/internal/app/constants"
|
import "github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
|
|
||||||
type ProcessInfo struct {
|
type ProcessInfo struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
@@ -9,7 +9,7 @@ type ProcessInfo struct {
|
|||||||
User string `json:"user"`
|
User string `json:"user"`
|
||||||
Usage Usage `json:"usage"`
|
Usage Usage `json:"usage"`
|
||||||
State State `json:"state"`
|
State State `json:"state"`
|
||||||
TermType constants.TerminalType `json:"termType"`
|
TermType eum.TerminalType `json:"termType"`
|
||||||
CgroupEnable bool `json:"cgroupEnable"`
|
CgroupEnable bool `json:"cgroupEnable"`
|
||||||
MemoryLimit *float32 `json:"memoryLimit"`
|
MemoryLimit *float32 `json:"memoryLimit"`
|
||||||
CpuLimit *float32 `json:"cpuLimit"`
|
CpuLimit *float32 `json:"cpuLimit"`
|
||||||
@@ -24,6 +24,6 @@ type Usage struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type State struct {
|
type State struct {
|
||||||
State constants.ProcessState `json:"state"`
|
State eum.ProcessState `json:"state"`
|
||||||
Info string `json:"info"`
|
Info string `json:"info"`
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import "github.com/lzh-1625/go_process_manager/internal/app/constants"
|
import "github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
|
|
||||||
type Process struct {
|
type Process struct {
|
||||||
Uuid int `gorm:"primaryKey;autoIncrement;column:uuid" json:"uuid"`
|
Uuid int `gorm:"primaryKey;autoIncrement;column:uuid" json:"uuid"`
|
||||||
@@ -9,9 +9,9 @@ type Process struct {
|
|||||||
Cwd string `gorm:"column:cwd" json:"cwd"`
|
Cwd string `gorm:"column:cwd" json:"cwd"`
|
||||||
AutoRestart bool `gorm:"column:auto_restart" json:"autoRestart"`
|
AutoRestart bool `gorm:"column:auto_restart" json:"autoRestart"`
|
||||||
CompulsoryRestart bool `gorm:"column:compulsory_restart" json:"compulsoryRestart"`
|
CompulsoryRestart bool `gorm:"column:compulsory_restart" json:"compulsoryRestart"`
|
||||||
PushIds string `gorm:"column:push_ids" json:"pushIds"`
|
PushIds string `gorm:"column:push_ids;type:json" json:"pushIds"`
|
||||||
LogReport bool `gorm:"column:log_report" json:"logReport"`
|
LogReport bool `gorm:"column:log_report" json:"logReport"`
|
||||||
TermType constants.TerminalType `gorm:"column:term_type" json:"termType"`
|
TermType eum.TerminalType `gorm:"column:term_type" json:"termType"`
|
||||||
CgroupEnable bool `gorm:"column:cgroup_enable" json:"cgroupEnable"`
|
CgroupEnable bool `gorm:"column:cgroup_enable" json:"cgroupEnable"`
|
||||||
MemoryLimit *float32 `gorm:"column:memory_limit" json:"memoryLimit"`
|
MemoryLimit *float32 `gorm:"column:memory_limit" json:"memoryLimit"`
|
||||||
CpuLimit *float32 `gorm:"column:cpu_limit" json:"cpuLimit"`
|
CpuLimit *float32 `gorm:"column:cpu_limit" json:"cpuLimit"`
|
||||||
|
@@ -3,16 +3,17 @@ package model
|
|||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/constants"
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Task struct {
|
type Task struct {
|
||||||
Id int `gorm:"column:id;NOT NULL;primaryKey;autoIncrement;" json:"id" `
|
Id int `gorm:"column:id;NOT NULL;primaryKey;autoIncrement;" json:"id" `
|
||||||
|
Name string `gorm:"column:name" json:"name" `
|
||||||
ProcessId int `gorm:"column:process_id;NOT NULL" json:"processId" `
|
ProcessId int `gorm:"column:process_id;NOT NULL" json:"processId" `
|
||||||
Condition constants.Condition `gorm:"column:condition;NOT NULL" json:"condition" `
|
Condition eum.Condition `gorm:"column:condition;NOT NULL" json:"condition" `
|
||||||
NextId *int `gorm:"column:next_id;" json:"nextId" `
|
NextId *int `gorm:"column:next_id;" json:"nextId" `
|
||||||
Operation constants.TaskOperation `gorm:"column:operation;NOT NULL" json:"operation" `
|
Operation eum.TaskOperation `gorm:"column:operation;NOT NULL" json:"operation" `
|
||||||
TriggerEvent *constants.ProcessState `gorm:"column:trigger_event;" json:"triggerEvent" `
|
TriggerEvent *eum.ProcessState `gorm:"column:trigger_event;" json:"triggerEvent" `
|
||||||
TriggerTarget *int `gorm:"column:trigger_target;" json:"triggerTarget" `
|
TriggerTarget *int `gorm:"column:trigger_target;" json:"triggerTarget" `
|
||||||
OperationTarget int `gorm:"column:operation_target;NOT NULL" json:"operationTarget" `
|
OperationTarget int `gorm:"column:operation_target;NOT NULL" json:"operationTarget" `
|
||||||
CronExpression string `gorm:"column:cron;" json:"cron" `
|
CronExpression string `gorm:"column:cron;" json:"cron" `
|
||||||
|
@@ -3,13 +3,13 @@ package model
|
|||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/constants"
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
)
|
)
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
Account string `json:"account" gorm:"primaryKey;column:account" `
|
Account string `json:"account" gorm:"primaryKey;column:account" `
|
||||||
Password string `json:"password" gorm:"column:password" `
|
Password string `json:"password" gorm:"column:password" `
|
||||||
Role constants.Role `json:"role" gorm:"column:role" `
|
Role eum.Role `json:"role" gorm:"column:role" `
|
||||||
CreateTime time.Time `json:"createTime" gorm:"column:create_time" `
|
CreateTime time.Time `json:"createTime" gorm:"column:create_time" `
|
||||||
Remark string `json:"remark" gorm:"column:remark" `
|
Remark string `json:"remark" gorm:"column:remark" `
|
||||||
}
|
}
|
||||||
|
@@ -41,15 +41,18 @@ func InitDb() {
|
|||||||
}
|
}
|
||||||
sqlDB.SetConnMaxLifetime(time.Hour)
|
sqlDB.SetConnMaxLifetime(time.Hour)
|
||||||
db = gdb.Session(&defaultConfig)
|
db = gdb.Session(&defaultConfig)
|
||||||
// db = db.Debug()
|
db = db.Debug()
|
||||||
db.AutoMigrate(&model.Process{}, &model.User{}, &model.Permission{}, &model.Push{}, &model.Config{}, &model.ProcessLog{}, &model.Task{}, &model.WsShare{})
|
db.AutoMigrate(
|
||||||
|
&model.Process{},
|
||||||
// g := gen.NewGenerator(gen.Config{
|
&model.User{},
|
||||||
// OutPath: "internal/app/repository/query",
|
&model.Permission{},
|
||||||
// Mode: gen.WithoutContext | gen.WithDefaultQuery | gen.WithQueryInterface, // generate mode
|
&model.Push{},
|
||||||
// })
|
&model.Config{},
|
||||||
// g.UseDB(db)
|
&model.ProcessLog{},
|
||||||
// g.ApplyBasic(&model.Process{}, &model.User{}, &model.Permission{}, &model.Push{}, &model.Config{}, &model.ProcessLog{}, &model.Task{}, &model.WsShare{})
|
&model.Task{},
|
||||||
// g.Execute()
|
&model.WsShare{},
|
||||||
|
&model.Event{},
|
||||||
|
)
|
||||||
|
gormGen(db)
|
||||||
query.SetDefault(db)
|
query.SetDefault(db)
|
||||||
}
|
}
|
||||||
|
14
internal/app/repository/event.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
||||||
|
"github.com/lzh-1625/go_process_manager/internal/app/repository/query"
|
||||||
|
)
|
||||||
|
|
||||||
|
type eventRepository struct{}
|
||||||
|
|
||||||
|
var EventRepository = new(eventRepository)
|
||||||
|
|
||||||
|
func (e *eventRepository) Create(event model.Event) error {
|
||||||
|
return query.Event.Create(&event)
|
||||||
|
}
|
33
internal/app/repository/gen.go
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
//go:build gen
|
||||||
|
// +build gen
|
||||||
|
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
||||||
|
"gorm.io/gen"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func gormGen(db *gorm.DB) {
|
||||||
|
g := gen.NewGenerator(gen.Config{
|
||||||
|
OutPath: "internal/app/repository/query",
|
||||||
|
Mode: gen.WithoutContext | gen.WithDefaultQuery | gen.WithQueryInterface, // generate mode
|
||||||
|
})
|
||||||
|
g.UseDB(db)
|
||||||
|
g.ApplyBasic(
|
||||||
|
&model.Process{},
|
||||||
|
&model.User{},
|
||||||
|
&model.Permission{},
|
||||||
|
&model.Push{},
|
||||||
|
&model.Config{},
|
||||||
|
&model.ProcessLog{},
|
||||||
|
&model.Task{},
|
||||||
|
&model.WsShare{},
|
||||||
|
&model.Event{},
|
||||||
|
)
|
||||||
|
g.Execute()
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
10
internal/app/repository/gen_ignore.go
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
//go:build !gen
|
||||||
|
// +build !gen
|
||||||
|
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import "gorm.io/gorm"
|
||||||
|
|
||||||
|
func gormGen(*gorm.DB) {
|
||||||
|
|
||||||
|
}
|
@@ -3,7 +3,7 @@ package repository
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/constants"
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/repository/query"
|
"github.com/lzh-1625/go_process_manager/internal/app/repository/query"
|
||||||
"github.com/lzh-1625/go_process_manager/log"
|
"github.com/lzh-1625/go_process_manager/log"
|
||||||
@@ -64,18 +64,18 @@ func (p *permissionRepository) GetPermission(user string, pid int) (result model
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *permissionRepository) GetProcessNameByPermission(user string, op constants.OprPermission) (result []string) {
|
func (p *permissionRepository) GetProcessNameByPermission(user string, op eum.OprPermission) (result []string) {
|
||||||
tx := query.Permission.Select(query.Process.Name).RightJoin(query.Process, query.Process.Uuid.EqCol(query.Permission.Pid)).Where(query.Permission.Account.Eq(user)).Where(query.Permission.Owned.Is(true))
|
tx := query.Permission.Select(query.Process.Name).RightJoin(query.Process, query.Process.Uuid.EqCol(query.Permission.Pid)).Where(query.Permission.Account.Eq(user)).Where(query.Permission.Owned.Is(true))
|
||||||
switch op {
|
switch op {
|
||||||
case constants.OPERATION_LOG:
|
case eum.OperationLog:
|
||||||
tx = tx.Where(query.Permission.Log.Is(true))
|
tx = tx.Where(query.Permission.Log.Is(true))
|
||||||
case constants.OPERATION_START:
|
case eum.OperationStart:
|
||||||
tx = tx.Where(query.Permission.Start.Is(true))
|
tx = tx.Where(query.Permission.Start.Is(true))
|
||||||
case constants.OPERATION_STOP:
|
case eum.OperationStop:
|
||||||
tx = tx.Where(query.Permission.Stop.Is(true))
|
tx = tx.Where(query.Permission.Stop.Is(true))
|
||||||
case constants.OPERATION_TERMINAL:
|
case eum.OperationTerminal:
|
||||||
tx = tx.Where(query.Permission.Terminal.Is(true))
|
tx = tx.Where(query.Permission.Terminal.Is(true))
|
||||||
case constants.OPERATION_TERMINAL_WRITE:
|
case eum.OperationTerminalWrite:
|
||||||
tx = tx.Where(query.Permission.Write.Is(true))
|
tx = tx.Where(query.Permission.Write.Is(true))
|
||||||
}
|
}
|
||||||
tx.Scan(&result)
|
tx.Scan(&result)
|
||||||
|
@@ -15,7 +15,7 @@ func (p *processRepository) GetAllProcessConfig() []model.Process {
|
|||||||
tx := db.Find(&result)
|
tx := db.Find(&result)
|
||||||
if tx.Error != nil {
|
if tx.Error != nil {
|
||||||
log.Logger.Error(tx.Error)
|
log.Logger.Error(tx.Error)
|
||||||
return []model.Process{}
|
return nil
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -28,7 +28,7 @@ func (p *processRepository) GetProcessConfigByUser(username string) []model.Proc
|
|||||||
Scan(&result)
|
Scan(&result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Logger.Error(err)
|
log.Logger.Error(err)
|
||||||
return []model.Process{}
|
return nil
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -44,9 +44,8 @@ func (p *processRepository) AddProcessConfig(process model.Process) (id int, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *processRepository) DeleteProcessConfig(uuid int) error {
|
func (p *processRepository) DeleteProcessConfig(uuid int) error {
|
||||||
return db.Delete(&model.Process{
|
_, err := query.Process.Where(query.Process.Uuid.Eq(uuid)).Delete()
|
||||||
Uuid: uuid,
|
return err
|
||||||
}).Error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *processRepository) GetProcessConfigById(uuid int) (data model.Process, err error) {
|
func (p *processRepository) GetProcessConfigById(uuid int) (data model.Process, err error) {
|
||||||
|
398
internal/app/repository/query/event.gen.go
Normal file
@@ -0,0 +1,398 @@
|
|||||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package query
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
|
||||||
|
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"gorm.io/gorm/clause"
|
||||||
|
"gorm.io/gorm/schema"
|
||||||
|
|
||||||
|
"gorm.io/gen"
|
||||||
|
"gorm.io/gen/field"
|
||||||
|
|
||||||
|
"gorm.io/plugin/dbresolver"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newEvent(db *gorm.DB, opts ...gen.DOOption) event {
|
||||||
|
_event := event{}
|
||||||
|
|
||||||
|
_event.eventDo.UseDB(db, opts...)
|
||||||
|
_event.eventDo.UseModel(&model.Event{})
|
||||||
|
|
||||||
|
tableName := _event.eventDo.TableName()
|
||||||
|
_event.ALL = field.NewAsterisk(tableName)
|
||||||
|
_event.Id = field.NewUint64(tableName, "id")
|
||||||
|
_event.Name = field.NewString(tableName, "name")
|
||||||
|
_event.Type = field.NewString(tableName, "type")
|
||||||
|
_event.Additional = field.NewString(tableName, "additional")
|
||||||
|
_event.CreatedTime = field.NewTime(tableName, "created_time")
|
||||||
|
|
||||||
|
_event.fillFieldMap()
|
||||||
|
|
||||||
|
return _event
|
||||||
|
}
|
||||||
|
|
||||||
|
type event struct {
|
||||||
|
eventDo
|
||||||
|
|
||||||
|
ALL field.Asterisk
|
||||||
|
Id field.Uint64
|
||||||
|
Name field.String
|
||||||
|
Type field.String
|
||||||
|
Additional field.String
|
||||||
|
CreatedTime field.Time
|
||||||
|
|
||||||
|
fieldMap map[string]field.Expr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e event) Table(newTableName string) *event {
|
||||||
|
e.eventDo.UseTable(newTableName)
|
||||||
|
return e.updateTableName(newTableName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e event) As(alias string) *event {
|
||||||
|
e.eventDo.DO = *(e.eventDo.As(alias).(*gen.DO))
|
||||||
|
return e.updateTableName(alias)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *event) updateTableName(table string) *event {
|
||||||
|
e.ALL = field.NewAsterisk(table)
|
||||||
|
e.Id = field.NewUint64(table, "id")
|
||||||
|
e.Name = field.NewString(table, "name")
|
||||||
|
e.Type = field.NewString(table, "type")
|
||||||
|
e.Additional = field.NewString(table, "additional")
|
||||||
|
e.CreatedTime = field.NewTime(table, "created_time")
|
||||||
|
|
||||||
|
e.fillFieldMap()
|
||||||
|
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *event) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
|
||||||
|
_f, ok := e.fieldMap[fieldName]
|
||||||
|
if !ok || _f == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
_oe, ok := _f.(field.OrderExpr)
|
||||||
|
return _oe, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *event) fillFieldMap() {
|
||||||
|
e.fieldMap = make(map[string]field.Expr, 5)
|
||||||
|
e.fieldMap["id"] = e.Id
|
||||||
|
e.fieldMap["name"] = e.Name
|
||||||
|
e.fieldMap["type"] = e.Type
|
||||||
|
e.fieldMap["additional"] = e.Additional
|
||||||
|
e.fieldMap["created_time"] = e.CreatedTime
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e event) clone(db *gorm.DB) event {
|
||||||
|
e.eventDo.ReplaceConnPool(db.Statement.ConnPool)
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e event) replaceDB(db *gorm.DB) event {
|
||||||
|
e.eventDo.ReplaceDB(db)
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
type eventDo struct{ gen.DO }
|
||||||
|
|
||||||
|
type IEventDo interface {
|
||||||
|
gen.SubQuery
|
||||||
|
Debug() IEventDo
|
||||||
|
WithContext(ctx context.Context) IEventDo
|
||||||
|
WithResult(fc func(tx gen.Dao)) gen.ResultInfo
|
||||||
|
ReplaceDB(db *gorm.DB)
|
||||||
|
ReadDB() IEventDo
|
||||||
|
WriteDB() IEventDo
|
||||||
|
As(alias string) gen.Dao
|
||||||
|
Session(config *gorm.Session) IEventDo
|
||||||
|
Columns(cols ...field.Expr) gen.Columns
|
||||||
|
Clauses(conds ...clause.Expression) IEventDo
|
||||||
|
Not(conds ...gen.Condition) IEventDo
|
||||||
|
Or(conds ...gen.Condition) IEventDo
|
||||||
|
Select(conds ...field.Expr) IEventDo
|
||||||
|
Where(conds ...gen.Condition) IEventDo
|
||||||
|
Order(conds ...field.Expr) IEventDo
|
||||||
|
Distinct(cols ...field.Expr) IEventDo
|
||||||
|
Omit(cols ...field.Expr) IEventDo
|
||||||
|
Join(table schema.Tabler, on ...field.Expr) IEventDo
|
||||||
|
LeftJoin(table schema.Tabler, on ...field.Expr) IEventDo
|
||||||
|
RightJoin(table schema.Tabler, on ...field.Expr) IEventDo
|
||||||
|
Group(cols ...field.Expr) IEventDo
|
||||||
|
Having(conds ...gen.Condition) IEventDo
|
||||||
|
Limit(limit int) IEventDo
|
||||||
|
Offset(offset int) IEventDo
|
||||||
|
Count() (count int64, err error)
|
||||||
|
Scopes(funcs ...func(gen.Dao) gen.Dao) IEventDo
|
||||||
|
Unscoped() IEventDo
|
||||||
|
Create(values ...*model.Event) error
|
||||||
|
CreateInBatches(values []*model.Event, batchSize int) error
|
||||||
|
Save(values ...*model.Event) error
|
||||||
|
First() (*model.Event, error)
|
||||||
|
Take() (*model.Event, error)
|
||||||
|
Last() (*model.Event, error)
|
||||||
|
Find() ([]*model.Event, error)
|
||||||
|
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.Event, err error)
|
||||||
|
FindInBatches(result *[]*model.Event, batchSize int, fc func(tx gen.Dao, batch int) error) error
|
||||||
|
Pluck(column field.Expr, dest interface{}) error
|
||||||
|
Delete(...*model.Event) (info gen.ResultInfo, err error)
|
||||||
|
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
|
||||||
|
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
|
||||||
|
Updates(value interface{}) (info gen.ResultInfo, err error)
|
||||||
|
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
|
||||||
|
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
|
||||||
|
UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
|
||||||
|
UpdateFrom(q gen.SubQuery) gen.Dao
|
||||||
|
Attrs(attrs ...field.AssignExpr) IEventDo
|
||||||
|
Assign(attrs ...field.AssignExpr) IEventDo
|
||||||
|
Joins(fields ...field.RelationField) IEventDo
|
||||||
|
Preload(fields ...field.RelationField) IEventDo
|
||||||
|
FirstOrInit() (*model.Event, error)
|
||||||
|
FirstOrCreate() (*model.Event, error)
|
||||||
|
FindByPage(offset int, limit int) (result []*model.Event, count int64, err error)
|
||||||
|
ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
|
||||||
|
Rows() (*sql.Rows, error)
|
||||||
|
Row() *sql.Row
|
||||||
|
Scan(result interface{}) (err error)
|
||||||
|
Returning(value interface{}, columns ...string) IEventDo
|
||||||
|
UnderlyingDB() *gorm.DB
|
||||||
|
schema.Tabler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Debug() IEventDo {
|
||||||
|
return e.withDO(e.DO.Debug())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) WithContext(ctx context.Context) IEventDo {
|
||||||
|
return e.withDO(e.DO.WithContext(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) ReadDB() IEventDo {
|
||||||
|
return e.Clauses(dbresolver.Read)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) WriteDB() IEventDo {
|
||||||
|
return e.Clauses(dbresolver.Write)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Session(config *gorm.Session) IEventDo {
|
||||||
|
return e.withDO(e.DO.Session(config))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Clauses(conds ...clause.Expression) IEventDo {
|
||||||
|
return e.withDO(e.DO.Clauses(conds...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Returning(value interface{}, columns ...string) IEventDo {
|
||||||
|
return e.withDO(e.DO.Returning(value, columns...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Not(conds ...gen.Condition) IEventDo {
|
||||||
|
return e.withDO(e.DO.Not(conds...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Or(conds ...gen.Condition) IEventDo {
|
||||||
|
return e.withDO(e.DO.Or(conds...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Select(conds ...field.Expr) IEventDo {
|
||||||
|
return e.withDO(e.DO.Select(conds...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Where(conds ...gen.Condition) IEventDo {
|
||||||
|
return e.withDO(e.DO.Where(conds...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Order(conds ...field.Expr) IEventDo {
|
||||||
|
return e.withDO(e.DO.Order(conds...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Distinct(cols ...field.Expr) IEventDo {
|
||||||
|
return e.withDO(e.DO.Distinct(cols...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Omit(cols ...field.Expr) IEventDo {
|
||||||
|
return e.withDO(e.DO.Omit(cols...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Join(table schema.Tabler, on ...field.Expr) IEventDo {
|
||||||
|
return e.withDO(e.DO.Join(table, on...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) LeftJoin(table schema.Tabler, on ...field.Expr) IEventDo {
|
||||||
|
return e.withDO(e.DO.LeftJoin(table, on...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) RightJoin(table schema.Tabler, on ...field.Expr) IEventDo {
|
||||||
|
return e.withDO(e.DO.RightJoin(table, on...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Group(cols ...field.Expr) IEventDo {
|
||||||
|
return e.withDO(e.DO.Group(cols...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Having(conds ...gen.Condition) IEventDo {
|
||||||
|
return e.withDO(e.DO.Having(conds...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Limit(limit int) IEventDo {
|
||||||
|
return e.withDO(e.DO.Limit(limit))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Offset(offset int) IEventDo {
|
||||||
|
return e.withDO(e.DO.Offset(offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IEventDo {
|
||||||
|
return e.withDO(e.DO.Scopes(funcs...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Unscoped() IEventDo {
|
||||||
|
return e.withDO(e.DO.Unscoped())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Create(values ...*model.Event) error {
|
||||||
|
if len(values) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return e.DO.Create(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) CreateInBatches(values []*model.Event, batchSize int) error {
|
||||||
|
return e.DO.CreateInBatches(values, batchSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save : !!! underlying implementation is different with GORM
|
||||||
|
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
|
||||||
|
func (e eventDo) Save(values ...*model.Event) error {
|
||||||
|
if len(values) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return e.DO.Save(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) First() (*model.Event, error) {
|
||||||
|
if result, err := e.DO.First(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return result.(*model.Event), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Take() (*model.Event, error) {
|
||||||
|
if result, err := e.DO.Take(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return result.(*model.Event), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Last() (*model.Event, error) {
|
||||||
|
if result, err := e.DO.Last(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return result.(*model.Event), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Find() ([]*model.Event, error) {
|
||||||
|
result, err := e.DO.Find()
|
||||||
|
return result.([]*model.Event), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.Event, err error) {
|
||||||
|
buf := make([]*model.Event, 0, batchSize)
|
||||||
|
err = e.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
|
||||||
|
defer func() { results = append(results, buf...) }()
|
||||||
|
return fc(tx, batch)
|
||||||
|
})
|
||||||
|
return results, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) FindInBatches(result *[]*model.Event, batchSize int, fc func(tx gen.Dao, batch int) error) error {
|
||||||
|
return e.DO.FindInBatches(result, batchSize, fc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Attrs(attrs ...field.AssignExpr) IEventDo {
|
||||||
|
return e.withDO(e.DO.Attrs(attrs...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Assign(attrs ...field.AssignExpr) IEventDo {
|
||||||
|
return e.withDO(e.DO.Assign(attrs...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Joins(fields ...field.RelationField) IEventDo {
|
||||||
|
for _, _f := range fields {
|
||||||
|
e = *e.withDO(e.DO.Joins(_f))
|
||||||
|
}
|
||||||
|
return &e
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Preload(fields ...field.RelationField) IEventDo {
|
||||||
|
for _, _f := range fields {
|
||||||
|
e = *e.withDO(e.DO.Preload(_f))
|
||||||
|
}
|
||||||
|
return &e
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) FirstOrInit() (*model.Event, error) {
|
||||||
|
if result, err := e.DO.FirstOrInit(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return result.(*model.Event), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) FirstOrCreate() (*model.Event, error) {
|
||||||
|
if result, err := e.DO.FirstOrCreate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return result.(*model.Event), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) FindByPage(offset int, limit int) (result []*model.Event, count int64, err error) {
|
||||||
|
result, err = e.Offset(offset).Limit(limit).Find()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if size := len(result); 0 < limit && 0 < size && size < limit {
|
||||||
|
count = int64(size + offset)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
count, err = e.Offset(-1).Limit(-1).Count()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
|
||||||
|
count, err = e.Count()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = e.Offset(offset).Limit(limit).Scan(result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Scan(result interface{}) (err error) {
|
||||||
|
return e.DO.Scan(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventDo) Delete(models ...*model.Event) (result gen.ResultInfo, err error) {
|
||||||
|
return e.DO.Delete(models)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *eventDo) withDO(do gen.Dao) *eventDo {
|
||||||
|
e.DO = *do.(*gen.DO)
|
||||||
|
return e
|
||||||
|
}
|
@@ -18,6 +18,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
Q = new(Query)
|
Q = new(Query)
|
||||||
Config *config
|
Config *config
|
||||||
|
Event *event
|
||||||
Permission *permission
|
Permission *permission
|
||||||
Process *process
|
Process *process
|
||||||
ProcessLog *processLog
|
ProcessLog *processLog
|
||||||
@@ -30,6 +31,7 @@ var (
|
|||||||
func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
|
func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
|
||||||
*Q = *Use(db, opts...)
|
*Q = *Use(db, opts...)
|
||||||
Config = &Q.Config
|
Config = &Q.Config
|
||||||
|
Event = &Q.Event
|
||||||
Permission = &Q.Permission
|
Permission = &Q.Permission
|
||||||
Process = &Q.Process
|
Process = &Q.Process
|
||||||
ProcessLog = &Q.ProcessLog
|
ProcessLog = &Q.ProcessLog
|
||||||
@@ -43,6 +45,7 @@ func Use(db *gorm.DB, opts ...gen.DOOption) *Query {
|
|||||||
return &Query{
|
return &Query{
|
||||||
db: db,
|
db: db,
|
||||||
Config: newConfig(db, opts...),
|
Config: newConfig(db, opts...),
|
||||||
|
Event: newEvent(db, opts...),
|
||||||
Permission: newPermission(db, opts...),
|
Permission: newPermission(db, opts...),
|
||||||
Process: newProcess(db, opts...),
|
Process: newProcess(db, opts...),
|
||||||
ProcessLog: newProcessLog(db, opts...),
|
ProcessLog: newProcessLog(db, opts...),
|
||||||
@@ -57,6 +60,7 @@ type Query struct {
|
|||||||
db *gorm.DB
|
db *gorm.DB
|
||||||
|
|
||||||
Config config
|
Config config
|
||||||
|
Event event
|
||||||
Permission permission
|
Permission permission
|
||||||
Process process
|
Process process
|
||||||
ProcessLog processLog
|
ProcessLog processLog
|
||||||
@@ -72,6 +76,7 @@ func (q *Query) clone(db *gorm.DB) *Query {
|
|||||||
return &Query{
|
return &Query{
|
||||||
db: db,
|
db: db,
|
||||||
Config: q.Config.clone(db),
|
Config: q.Config.clone(db),
|
||||||
|
Event: q.Event.clone(db),
|
||||||
Permission: q.Permission.clone(db),
|
Permission: q.Permission.clone(db),
|
||||||
Process: q.Process.clone(db),
|
Process: q.Process.clone(db),
|
||||||
ProcessLog: q.ProcessLog.clone(db),
|
ProcessLog: q.ProcessLog.clone(db),
|
||||||
@@ -94,6 +99,7 @@ func (q *Query) ReplaceDB(db *gorm.DB) *Query {
|
|||||||
return &Query{
|
return &Query{
|
||||||
db: db,
|
db: db,
|
||||||
Config: q.Config.replaceDB(db),
|
Config: q.Config.replaceDB(db),
|
||||||
|
Event: q.Event.replaceDB(db),
|
||||||
Permission: q.Permission.replaceDB(db),
|
Permission: q.Permission.replaceDB(db),
|
||||||
Process: q.Process.replaceDB(db),
|
Process: q.Process.replaceDB(db),
|
||||||
ProcessLog: q.ProcessLog.replaceDB(db),
|
ProcessLog: q.ProcessLog.replaceDB(db),
|
||||||
@@ -106,6 +112,7 @@ func (q *Query) ReplaceDB(db *gorm.DB) *Query {
|
|||||||
|
|
||||||
type queryCtx struct {
|
type queryCtx struct {
|
||||||
Config IConfigDo
|
Config IConfigDo
|
||||||
|
Event IEventDo
|
||||||
Permission IPermissionDo
|
Permission IPermissionDo
|
||||||
Process IProcessDo
|
Process IProcessDo
|
||||||
ProcessLog IProcessLogDo
|
ProcessLog IProcessLogDo
|
||||||
@@ -118,6 +125,7 @@ type queryCtx struct {
|
|||||||
func (q *Query) WithContext(ctx context.Context) *queryCtx {
|
func (q *Query) WithContext(ctx context.Context) *queryCtx {
|
||||||
return &queryCtx{
|
return &queryCtx{
|
||||||
Config: q.Config.WithContext(ctx),
|
Config: q.Config.WithContext(ctx),
|
||||||
|
Event: q.Event.WithContext(ctx),
|
||||||
Permission: q.Permission.WithContext(ctx),
|
Permission: q.Permission.WithContext(ctx),
|
||||||
Process: q.Process.WithContext(ctx),
|
Process: q.Process.WithContext(ctx),
|
||||||
ProcessLog: q.ProcessLog.WithContext(ctx),
|
ProcessLog: q.ProcessLog.WithContext(ctx),
|
||||||
|
@@ -28,6 +28,7 @@ func newTask(db *gorm.DB, opts ...gen.DOOption) task {
|
|||||||
tableName := _task.taskDo.TableName()
|
tableName := _task.taskDo.TableName()
|
||||||
_task.ALL = field.NewAsterisk(tableName)
|
_task.ALL = field.NewAsterisk(tableName)
|
||||||
_task.Id = field.NewInt(tableName, "id")
|
_task.Id = field.NewInt(tableName, "id")
|
||||||
|
_task.Name = field.NewString(tableName, "name")
|
||||||
_task.ProcessId = field.NewInt(tableName, "process_id")
|
_task.ProcessId = field.NewInt(tableName, "process_id")
|
||||||
_task.Condition = field.NewInt(tableName, "condition")
|
_task.Condition = field.NewInt(tableName, "condition")
|
||||||
_task.NextId = field.NewInt(tableName, "next_id")
|
_task.NextId = field.NewInt(tableName, "next_id")
|
||||||
@@ -35,7 +36,7 @@ func newTask(db *gorm.DB, opts ...gen.DOOption) task {
|
|||||||
_task.TriggerEvent = field.NewInt32(tableName, "trigger_event")
|
_task.TriggerEvent = field.NewInt32(tableName, "trigger_event")
|
||||||
_task.TriggerTarget = field.NewInt(tableName, "trigger_target")
|
_task.TriggerTarget = field.NewInt(tableName, "trigger_target")
|
||||||
_task.OperationTarget = field.NewInt(tableName, "operation_target")
|
_task.OperationTarget = field.NewInt(tableName, "operation_target")
|
||||||
_task.Cron = field.NewString(tableName, "cron")
|
_task.CronExpression = field.NewString(tableName, "cron")
|
||||||
_task.Enable = field.NewBool(tableName, "enable")
|
_task.Enable = field.NewBool(tableName, "enable")
|
||||||
_task.ApiEnable = field.NewBool(tableName, "api_enable")
|
_task.ApiEnable = field.NewBool(tableName, "api_enable")
|
||||||
_task.Key = field.NewString(tableName, "key")
|
_task.Key = field.NewString(tableName, "key")
|
||||||
@@ -50,6 +51,7 @@ type task struct {
|
|||||||
|
|
||||||
ALL field.Asterisk
|
ALL field.Asterisk
|
||||||
Id field.Int
|
Id field.Int
|
||||||
|
Name field.String
|
||||||
ProcessId field.Int
|
ProcessId field.Int
|
||||||
Condition field.Int
|
Condition field.Int
|
||||||
NextId field.Int
|
NextId field.Int
|
||||||
@@ -57,7 +59,7 @@ type task struct {
|
|||||||
TriggerEvent field.Int32
|
TriggerEvent field.Int32
|
||||||
TriggerTarget field.Int
|
TriggerTarget field.Int
|
||||||
OperationTarget field.Int
|
OperationTarget field.Int
|
||||||
Cron field.String
|
CronExpression field.String
|
||||||
Enable field.Bool
|
Enable field.Bool
|
||||||
ApiEnable field.Bool
|
ApiEnable field.Bool
|
||||||
Key field.String
|
Key field.String
|
||||||
@@ -78,6 +80,7 @@ func (t task) As(alias string) *task {
|
|||||||
func (t *task) updateTableName(table string) *task {
|
func (t *task) updateTableName(table string) *task {
|
||||||
t.ALL = field.NewAsterisk(table)
|
t.ALL = field.NewAsterisk(table)
|
||||||
t.Id = field.NewInt(table, "id")
|
t.Id = field.NewInt(table, "id")
|
||||||
|
t.Name = field.NewString(table, "name")
|
||||||
t.ProcessId = field.NewInt(table, "process_id")
|
t.ProcessId = field.NewInt(table, "process_id")
|
||||||
t.Condition = field.NewInt(table, "condition")
|
t.Condition = field.NewInt(table, "condition")
|
||||||
t.NextId = field.NewInt(table, "next_id")
|
t.NextId = field.NewInt(table, "next_id")
|
||||||
@@ -85,7 +88,7 @@ func (t *task) updateTableName(table string) *task {
|
|||||||
t.TriggerEvent = field.NewInt32(table, "trigger_event")
|
t.TriggerEvent = field.NewInt32(table, "trigger_event")
|
||||||
t.TriggerTarget = field.NewInt(table, "trigger_target")
|
t.TriggerTarget = field.NewInt(table, "trigger_target")
|
||||||
t.OperationTarget = field.NewInt(table, "operation_target")
|
t.OperationTarget = field.NewInt(table, "operation_target")
|
||||||
t.Cron = field.NewString(table, "cron")
|
t.CronExpression = field.NewString(table, "cron")
|
||||||
t.Enable = field.NewBool(table, "enable")
|
t.Enable = field.NewBool(table, "enable")
|
||||||
t.ApiEnable = field.NewBool(table, "api_enable")
|
t.ApiEnable = field.NewBool(table, "api_enable")
|
||||||
t.Key = field.NewString(table, "key")
|
t.Key = field.NewString(table, "key")
|
||||||
@@ -105,8 +108,9 @@ func (t *task) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *task) fillFieldMap() {
|
func (t *task) fillFieldMap() {
|
||||||
t.fieldMap = make(map[string]field.Expr, 12)
|
t.fieldMap = make(map[string]field.Expr, 13)
|
||||||
t.fieldMap["id"] = t.Id
|
t.fieldMap["id"] = t.Id
|
||||||
|
t.fieldMap["name"] = t.Name
|
||||||
t.fieldMap["process_id"] = t.ProcessId
|
t.fieldMap["process_id"] = t.ProcessId
|
||||||
t.fieldMap["condition"] = t.Condition
|
t.fieldMap["condition"] = t.Condition
|
||||||
t.fieldMap["next_id"] = t.NextId
|
t.fieldMap["next_id"] = t.NextId
|
||||||
@@ -114,7 +118,7 @@ func (t *task) fillFieldMap() {
|
|||||||
t.fieldMap["trigger_event"] = t.TriggerEvent
|
t.fieldMap["trigger_event"] = t.TriggerEvent
|
||||||
t.fieldMap["trigger_target"] = t.TriggerTarget
|
t.fieldMap["trigger_target"] = t.TriggerTarget
|
||||||
t.fieldMap["operation_target"] = t.OperationTarget
|
t.fieldMap["operation_target"] = t.OperationTarget
|
||||||
t.fieldMap["cron"] = t.Cron
|
t.fieldMap["cron"] = t.CronExpression
|
||||||
t.fieldMap["enable"] = t.Enable
|
t.fieldMap["enable"] = t.Enable
|
||||||
t.fieldMap["api_enable"] = t.ApiEnable
|
t.fieldMap["api_enable"] = t.ApiEnable
|
||||||
t.fieldMap["key"] = t.Key
|
t.fieldMap["key"] = t.Key
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
package repository
|
package repository
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/constants"
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/repository/query"
|
"github.com/lzh-1625/go_process_manager/internal/app/repository/query"
|
||||||
)
|
)
|
||||||
@@ -26,7 +26,7 @@ func (t *taskRepository) GetTaskByKey(key string) (result model.Task, err error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *taskRepository) AddTask(data model.Task) (taskId int, err error) {
|
func (t *taskRepository) AddTask(data model.Task) (taskId int, err error) {
|
||||||
err = db.Create(&data).Error
|
err = query.Task.Create(&data)
|
||||||
taskId = data.Id
|
taskId = data.Id
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -64,7 +64,7 @@ func (t *taskRepository) GetAllTaskWithProcessName() (result []model.TaskVo) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *taskRepository) GetTriggerTask(processName string, event constants.ProcessState) []model.Task {
|
func (t *taskRepository) GetTriggerTask(processName string, event eum.ProcessState) []model.Task {
|
||||||
result := []model.Task{}
|
result := []model.Task{}
|
||||||
query.Task.Select(query.Task.ALL).
|
query.Task.Select(query.Task.ALL).
|
||||||
LeftJoin(query.Process, query.Process.Uuid.EqCol(query.Task.TriggerTarget)).
|
LeftJoin(query.Process, query.Process.Uuid.EqCol(query.Task.TriggerTarget)).
|
||||||
|
@@ -6,7 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/lzh-1625/go_process_manager/config"
|
"github.com/lzh-1625/go_process_manager/config"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/api"
|
"github.com/lzh-1625/go_process_manager/internal/app/api"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/constants"
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/middle"
|
"github.com/lzh-1625/go_process_manager/internal/app/middle"
|
||||||
"github.com/lzh-1625/go_process_manager/log"
|
"github.com/lzh-1625/go_process_manager/log"
|
||||||
"github.com/lzh-1625/go_process_manager/resources"
|
"github.com/lzh-1625/go_process_manager/resources"
|
||||||
@@ -58,55 +58,55 @@ func routePathInit(r *gin.Engine) {
|
|||||||
{
|
{
|
||||||
wsGroup := apiGroup.Group("/ws")
|
wsGroup := apiGroup.Group("/ws")
|
||||||
{
|
{
|
||||||
wsGroup.GET("", middle.OprPermission(constants.OPERATION_TERMINAL), bind(api.WsApi.WebsocketHandle, Query))
|
wsGroup.GET("", bind(api.WsApi.WebsocketHandle, Query))
|
||||||
wsGroup.GET("/share", bind(api.WsApi.WebsocketShareHandle, Query))
|
wsGroup.GET("/share", bind(api.WsApi.WebsocketShareHandle, Query))
|
||||||
}
|
}
|
||||||
|
|
||||||
processGroup := apiGroup.Group("/process")
|
processGroup := apiGroup.Group("/process")
|
||||||
{
|
{
|
||||||
processGroup.DELETE("", middle.OprPermission(constants.OPERATION_STOP), bind(api.ProcApi.KillProcess, Query))
|
processGroup.DELETE("", bind(api.ProcApi.KillProcess, Query))
|
||||||
processGroup.GET("", bind(api.ProcApi.GetProcessList, None))
|
processGroup.GET("", bind(api.ProcApi.GetProcessList, None))
|
||||||
processGroup.GET("/wait", middle.ProcessWaitCond.WaitGetMiddel, bind(api.ProcApi.GetProcessList, None))
|
processGroup.GET("/wait", middle.ProcessWaitCond.WaitGetMiddel, bind(api.ProcApi.GetProcessList, None))
|
||||||
processGroup.PUT("", middle.OprPermission(constants.OPERATION_START), bind(api.ProcApi.StartProcess, Query))
|
processGroup.PUT("", bind(api.ProcApi.StartProcess, Body))
|
||||||
processGroup.PUT("/all", bind(api.ProcApi.StartAllProcess, None))
|
processGroup.PUT("/all", bind(api.ProcApi.StartAllProcess, None))
|
||||||
processGroup.DELETE("/all", bind(api.ProcApi.KillAllProcess, None))
|
processGroup.DELETE("/all", bind(api.ProcApi.KillAllProcess, None))
|
||||||
processGroup.POST("/share", middle.RolePermission(constants.ROLE_ADMIN), bind(api.ProcApi.ProcessCreateShare, Body))
|
processGroup.POST("/share", middle.RolePermission(eum.RoleAdmin), bind(api.ProcApi.ProcessCreateShare, Body))
|
||||||
processGroup.GET("/control", middle.RolePermission(constants.ROLE_ROOT), middle.ProcessWaitCond.WaitTriggerMiddel, bind(api.ProcApi.ProcessControl, Query))
|
processGroup.GET("/control", middle.RolePermission(eum.RoleRoot), middle.ProcessWaitCond.WaitTriggerMiddel, bind(api.ProcApi.ProcessControl, Query))
|
||||||
|
|
||||||
proConfigGroup := processGroup.Group("/config")
|
proConfigGroup := processGroup.Group("/config")
|
||||||
{
|
{
|
||||||
proConfigGroup.POST("", middle.RolePermission(constants.ROLE_ROOT), middle.ProcessWaitCond.WaitTriggerMiddel, bind(api.ProcApi.CreateNewProcess, Body))
|
proConfigGroup.POST("", middle.RolePermission(eum.RoleRoot), middle.ProcessWaitCond.WaitTriggerMiddel, bind(api.ProcApi.CreateNewProcess, Body))
|
||||||
proConfigGroup.DELETE("", middle.RolePermission(constants.ROLE_ROOT), middle.ProcessWaitCond.WaitTriggerMiddel, bind(api.ProcApi.DeleteNewProcess, Query))
|
proConfigGroup.DELETE("", middle.RolePermission(eum.RoleRoot), middle.ProcessWaitCond.WaitTriggerMiddel, bind(api.ProcApi.DeleteNewProcess, Query))
|
||||||
proConfigGroup.PUT("", middle.RolePermission(constants.ROLE_ROOT), bind(api.ProcApi.UpdateProcessConfig, Body))
|
proConfigGroup.PUT("", middle.RolePermission(eum.RoleRoot), bind(api.ProcApi.UpdateProcessConfig, Body))
|
||||||
proConfigGroup.GET("", middle.RolePermission(constants.ROLE_ADMIN), bind(api.ProcApi.GetProcessConfig, Query))
|
proConfigGroup.GET("", middle.RolePermission(eum.RoleAdmin), bind(api.ProcApi.GetProcessConfig, Query))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
taskGroup := apiGroup.Group("/task")
|
taskGroup := apiGroup.Group("/task")
|
||||||
{
|
{
|
||||||
taskGroup.GET("", middle.RolePermission(constants.ROLE_ADMIN), bind(api.TaskApi.GetTaskById, Query))
|
taskGroup.GET("", middle.RolePermission(eum.RoleAdmin), bind(api.TaskApi.GetTaskById, Query))
|
||||||
taskGroup.GET("/all", middle.RolePermission(constants.ROLE_ADMIN), bind(api.TaskApi.GetTaskList, None))
|
taskGroup.GET("/all", middle.RolePermission(eum.RoleAdmin), bind(api.TaskApi.GetTaskList, None))
|
||||||
taskGroup.GET("/all/wait", middle.RolePermission(constants.ROLE_ADMIN), middle.TaskWaitCond.WaitGetMiddel, bind(api.TaskApi.GetTaskList, None))
|
taskGroup.GET("/all/wait", middle.RolePermission(eum.RoleAdmin), middle.TaskWaitCond.WaitGetMiddel, bind(api.TaskApi.GetTaskList, None))
|
||||||
taskGroup.POST("", middle.RolePermission(constants.ROLE_ADMIN), middle.TaskWaitCond.WaitTriggerMiddel, bind(api.TaskApi.CreateTask, Body))
|
taskGroup.POST("", middle.RolePermission(eum.RoleAdmin), middle.TaskWaitCond.WaitTriggerMiddel, bind(api.TaskApi.CreateTask, Body))
|
||||||
taskGroup.DELETE("", middle.RolePermission(constants.ROLE_ADMIN), middle.TaskWaitCond.WaitTriggerMiddel, bind(api.TaskApi.DeleteTaskById, Query))
|
taskGroup.DELETE("", middle.RolePermission(eum.RoleAdmin), middle.TaskWaitCond.WaitTriggerMiddel, bind(api.TaskApi.DeleteTaskById, Query))
|
||||||
taskGroup.PUT("", middle.RolePermission(constants.ROLE_ADMIN), middle.TaskWaitCond.WaitTriggerMiddel, bind(api.TaskApi.EditTask, Body))
|
taskGroup.PUT("", middle.RolePermission(eum.RoleAdmin), middle.TaskWaitCond.WaitTriggerMiddel, bind(api.TaskApi.EditTask, Body))
|
||||||
taskGroup.PUT("/enable", middle.RolePermission(constants.ROLE_ADMIN), middle.TaskWaitCond.WaitTriggerMiddel, bind(api.TaskApi.EditTaskEnable, Body))
|
taskGroup.PUT("/enable", middle.RolePermission(eum.RoleAdmin), middle.TaskWaitCond.WaitTriggerMiddel, bind(api.TaskApi.EditTaskEnable, Body))
|
||||||
taskGroup.GET("/start", middle.RolePermission(constants.ROLE_ADMIN), bind(api.TaskApi.StartTask, Query))
|
taskGroup.GET("/start", middle.RolePermission(eum.RoleAdmin), bind(api.TaskApi.StartTask, Query))
|
||||||
taskGroup.GET("/stop", middle.RolePermission(constants.ROLE_ADMIN), bind(api.TaskApi.StopTask, Query))
|
taskGroup.GET("/stop", middle.RolePermission(eum.RoleAdmin), bind(api.TaskApi.StopTask, Query))
|
||||||
taskGroup.POST("/key", middle.RolePermission(constants.ROLE_ADMIN), bind(api.TaskApi.CreateTaskApiKey, Body))
|
taskGroup.POST("/key", middle.RolePermission(eum.RoleAdmin), bind(api.TaskApi.CreateTaskApiKey, Body))
|
||||||
taskGroup.GET("/api-key/:key", bind(api.TaskApi.RunTaskByKey, None))
|
taskGroup.GET("/api-key/:key", bind(api.TaskApi.RunTaskByKey, None))
|
||||||
}
|
}
|
||||||
|
|
||||||
userGroup := apiGroup.Group("/user")
|
userGroup := apiGroup.Group("/user")
|
||||||
{
|
{
|
||||||
userGroup.POST("/login", bind(api.UserApi.LoginHandler, Body))
|
userGroup.POST("/login", bind(api.UserApi.LoginHandler, Body))
|
||||||
userGroup.POST("", middle.RolePermission(constants.ROLE_ROOT), bind(api.UserApi.CreateUser, Body))
|
userGroup.POST("", middle.RolePermission(eum.RoleRoot), bind(api.UserApi.CreateUser, Body))
|
||||||
userGroup.PUT("/password", middle.RolePermission(constants.ROLE_USER), bind(api.UserApi.ChangePassword, Body))
|
userGroup.PUT("/password", middle.RolePermission(eum.RoleUser), bind(api.UserApi.ChangePassword, Body))
|
||||||
userGroup.DELETE("", middle.RolePermission(constants.ROLE_ROOT), bind(api.UserApi.DeleteUser, Query))
|
userGroup.DELETE("", middle.RolePermission(eum.RoleRoot), bind(api.UserApi.DeleteUser, Query))
|
||||||
userGroup.GET("", middle.RolePermission(constants.ROLE_ROOT), bind(api.UserApi.GetUserList, None))
|
userGroup.GET("", middle.RolePermission(eum.RoleRoot), bind(api.UserApi.GetUserList, None))
|
||||||
}
|
}
|
||||||
|
|
||||||
pushGroup := apiGroup.Group("/push").Use(middle.RolePermission(constants.ROLE_ADMIN))
|
pushGroup := apiGroup.Group("/push").Use(middle.RolePermission(eum.RoleAdmin))
|
||||||
{
|
{
|
||||||
pushGroup.GET("/list", bind(api.PushApi.GetPushList, None))
|
pushGroup.GET("/list", bind(api.PushApi.GetPushList, None))
|
||||||
pushGroup.GET("", bind(api.PushApi.GetPushById, Query))
|
pushGroup.GET("", bind(api.PushApi.GetPushById, Query))
|
||||||
@@ -115,30 +115,30 @@ func routePathInit(r *gin.Engine) {
|
|||||||
pushGroup.DELETE("", bind(api.PushApi.DeletePushConfig, Query))
|
pushGroup.DELETE("", bind(api.PushApi.DeletePushConfig, Query))
|
||||||
}
|
}
|
||||||
|
|
||||||
fileGroup := apiGroup.Group("/file").Use(middle.RolePermission(constants.ROLE_ADMIN))
|
fileGroup := apiGroup.Group("/file").Use(middle.RolePermission(eum.RoleAdmin))
|
||||||
{
|
{
|
||||||
fileGroup.GET("/list", bind(api.FileApi.FilePathHandler, Query))
|
fileGroup.GET("/list", bind(api.FileApi.FilePathHandler, Query))
|
||||||
fileGroup.PUT("", bind(api.FileApi.FileWriteHandler, None))
|
fileGroup.PUT("", bind(api.FileApi.FileWriteHandler, None))
|
||||||
fileGroup.GET("", bind(api.FileApi.FileReadHandler, Query))
|
fileGroup.GET("", bind(api.FileApi.FileReadHandler, Query))
|
||||||
}
|
}
|
||||||
|
|
||||||
permissionGroup := apiGroup.Group("/permission").Use(middle.RolePermission(constants.ROLE_ROOT))
|
permissionGroup := apiGroup.Group("/permission").Use(middle.RolePermission(eum.RoleRoot))
|
||||||
{
|
{
|
||||||
permissionGroup.GET("/list", bind(api.PermissionApi.GetPermissionList, Query))
|
permissionGroup.GET("/list", bind(api.PermissionApi.GetPermissionList, Query))
|
||||||
permissionGroup.PUT("", middle.ProcessWaitCond.WaitTriggerMiddel, bind(api.PermissionApi.EditPermssion, Body))
|
permissionGroup.PUT("", middle.ProcessWaitCond.WaitTriggerMiddel, bind(api.PermissionApi.EditPermssion, Body))
|
||||||
}
|
}
|
||||||
|
|
||||||
logGroup := apiGroup.Group("/log").Use(middle.RolePermission(constants.ROLE_USER))
|
logGroup := apiGroup.Group("/log").Use(middle.RolePermission(eum.RoleUser))
|
||||||
{
|
{
|
||||||
logGroup.POST("", bind(api.LogApi.GetLog, Body))
|
logGroup.POST("", bind(api.LogApi.GetLog, Body))
|
||||||
logGroup.GET("/running", bind(api.LogApi.GetRunningLog, None))
|
logGroup.GET("/running", bind(api.LogApi.GetRunningLog, None))
|
||||||
}
|
}
|
||||||
|
|
||||||
configGroup := apiGroup.Group("/config").Use(middle.RolePermission(constants.ROLE_ROOT))
|
configGroup := apiGroup.Group("/config").Use(middle.RolePermission(eum.RoleRoot))
|
||||||
{
|
{
|
||||||
configGroup.GET("", bind(api.ConfigApi.GetSystemConfiguration, None))
|
configGroup.GET("", bind(api.ConfigApi.GetSystemConfiguration, None))
|
||||||
configGroup.PUT("", bind(api.ConfigApi.SetSystemConfiguration, None))
|
configGroup.PUT("", bind(api.ConfigApi.SetSystemConfiguration, None))
|
||||||
configGroup.PUT("/log", bind(api.ConfigApi.LogConfigReload, None))
|
configGroup.GET("/reload", bind(api.ConfigApi.LogConfigReload, None))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -184,7 +184,7 @@ func bind[T any, R any](fn func(*gin.Context, T) R, bindOption int) func(*gin.Co
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case api.Response:
|
case *api.Response:
|
||||||
ctx.JSON(v.StatusCode, gin.H{
|
ctx.JSON(v.StatusCode, gin.H{
|
||||||
"data": v.Data,
|
"data": v.Data,
|
||||||
"msg": v.Msg,
|
"msg": v.Msg,
|
||||||
|
@@ -4,7 +4,6 @@
|
|||||||
package bleve
|
package bleve
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/blevesearch/bleve/v2"
|
"github.com/blevesearch/bleve/v2"
|
||||||
@@ -74,7 +73,6 @@ func (b *bleveSearch) Insert(logContent string, processName string, using string
|
|||||||
}); err != nil {
|
}); err != nil {
|
||||||
logger.Logger.Warnw("bleve log insert failed", "err", err)
|
logger.Logger.Warnw("bleve log insert failed", "err", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("using: %v\n", using)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bleveSearch) Search(req model.GetLogReq, filterProcessName ...string) (result model.LogResp) {
|
func (b *bleveSearch) Search(req model.GetLogReq, filterProcessName ...string) (result model.LogResp) {
|
||||||
|
@@ -3,7 +3,6 @@ package es
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -84,16 +83,15 @@ func (e *esSearch) Search(req model.GetLogReq, filterProcessName ...string) mode
|
|||||||
for _, v := range sr.QueryStringAnalysis(req.Match.Log) {
|
for _, v := range sr.QueryStringAnalysis(req.Match.Log) {
|
||||||
switch v.Cond {
|
switch v.Cond {
|
||||||
case sr.Match:
|
case sr.Match:
|
||||||
queryList = append(queryList, elastic.NewMatchQuery("log", v.Content))
|
queryList = append(queryList, elastic.NewMatchQuery("log", v.Content).Boost(2))
|
||||||
|
queryList = append(queryList, elastic.NewMatchPhraseQuery("log", v.Content))
|
||||||
case sr.NotMatch:
|
case sr.NotMatch:
|
||||||
notQuery = append(notQuery, elastic.NewMatchQuery("log", v.Content))
|
notQuery = append(notQuery, elastic.NewMatchPhraseQuery("log", v.Content))
|
||||||
case sr.WildCard:
|
case sr.WildCard:
|
||||||
queryList = append(queryList, elastic.NewWildcardQuery("log.keyword", "*"+v.Content+"*"))
|
queryList = append(queryList, elastic.NewWildcardQuery("log.keyword", "*"+v.Content+"*"))
|
||||||
case sr.NotWildCard:
|
case sr.NotWildCard:
|
||||||
notQuery = append(notQuery, elastic.NewWildcardQuery("log.keyword", "*"+v.Content+"*"))
|
notQuery = append(notQuery, elastic.NewWildcardQuery("log.keyword", "*"+v.Content+"*"))
|
||||||
}
|
}
|
||||||
fmt.Printf("v.Cond: %v\n", v.Cond)
|
|
||||||
fmt.Printf("v.Content: %v\n", v.Content)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.Match.Name != "" {
|
if req.Match.Name != "" {
|
||||||
|
@@ -1,11 +1,12 @@
|
|||||||
package search
|
package search
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/google/shlex"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
||||||
"github.com/lzh-1625/go_process_manager/log"
|
"github.com/lzh-1625/go_process_manager/log"
|
||||||
|
"github.com/lzh-1625/go_process_manager/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LogLogic interface {
|
type LogLogic interface {
|
||||||
@@ -47,7 +48,7 @@ func QueryStringAnalysis(s string) (query []Query) {
|
|||||||
if strings.TrimSpace(s) == "" {
|
if strings.TrimSpace(s) == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
strList := strings.Split(s, " ")
|
strList := utils.UnwarpIgnore(shlex.Split(s))
|
||||||
for _, v := range strList {
|
for _, v := range strList {
|
||||||
switch {
|
switch {
|
||||||
case strings.HasPrefix(v, "!^"):
|
case strings.HasPrefix(v, "!^"):
|
||||||
@@ -64,6 +65,5 @@ func QueryStringAnalysis(s string) (query []Query) {
|
|||||||
query = append(query, Query{Match, v})
|
query = append(query, Query{Match, v})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Printf("query: %v\n", query)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@@ -6,7 +6,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/lzh-1625/go_process_manager/config"
|
"github.com/lzh-1625/go_process_manager/config"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/constants"
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/logic"
|
"github.com/lzh-1625/go_process_manager/internal/app/logic"
|
||||||
"github.com/lzh-1625/go_process_manager/log"
|
"github.com/lzh-1625/go_process_manager/log"
|
||||||
"github.com/lzh-1625/go_process_manager/utils"
|
"github.com/lzh-1625/go_process_manager/utils"
|
||||||
@@ -49,7 +49,7 @@ func (t *tui) drawProcessList() {
|
|||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
list.AddItem(v.Name, utils.NewKVStr().Add("user_name", v.User).Add("start_time", v.StartTime).Add("state", v.State.State).Build(), 'a'+rune(i), func() {
|
list.AddItem(v.Name, utils.NewKVStr().Add("user_name", v.User).Add("start_time", v.StartTime).Add("state", v.State.State).Build(), 'a'+rune(i), func() {
|
||||||
if v.State.State != 1 || v.TermType != constants.TERMINAL_PTY {
|
if v.State.State != 1 || v.TermType != eum.TerminalPty {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t.teminal(v.Uuid)
|
t.teminal(v.Uuid)
|
||||||
@@ -75,8 +75,8 @@ func (t *tui) teminal(uuid int) {
|
|||||||
tci := &TermConnectInstance{
|
tci := &TermConnectInstance{
|
||||||
CancelFunc: cancel,
|
CancelFunc: cancel,
|
||||||
}
|
}
|
||||||
p.AddConn(constants.CONSOLE, tci)
|
p.AddConn(eum.Console, tci)
|
||||||
defer p.DeleteConn(constants.CONSOLE)
|
defer p.DeleteConn(eum.Console)
|
||||||
os.Stdin.Write([]byte("\033[H\033[2J")) // 清空屏幕
|
os.Stdin.Write([]byte("\033[H\033[2J")) // 清空屏幕
|
||||||
p.ReadCache(tci)
|
p.ReadCache(tci)
|
||||||
go t.startConnect(p, ctx, cancel)
|
go t.startConnect(p, ctx, cancel)
|
||||||
@@ -91,11 +91,11 @@ func (t *tui) teminal(uuid int) {
|
|||||||
|
|
||||||
func (t *tui) startConnect(p logic.Process, ctx context.Context, cancel context.CancelFunc) {
|
func (t *tui) startConnect(p logic.Process, ctx context.Context, cancel context.CancelFunc) {
|
||||||
switch p.Type() {
|
switch p.Type() {
|
||||||
case constants.TERMINAL_PTY:
|
case eum.TerminalPty:
|
||||||
{
|
{
|
||||||
t.ptyConnect(p, ctx, cancel)
|
t.ptyConnect(p, ctx, cancel)
|
||||||
}
|
}
|
||||||
case constants.TERMINAL_STD:
|
case eum.TerminalStd:
|
||||||
{
|
{
|
||||||
t.stdConnect(p, ctx, cancel)
|
t.stdConnect(p, ctx, cancel)
|
||||||
}
|
}
|
||||||
|
@@ -5,7 +5,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
_ "github.com/lzh-1625/go_process_manager/boot"
|
_ "github.com/lzh-1625/go_process_manager/boot"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/constants"
|
"github.com/lzh-1625/go_process_manager/internal/app/eum"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/logic"
|
"github.com/lzh-1625/go_process_manager/internal/app/logic"
|
||||||
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
"github.com/lzh-1625/go_process_manager/internal/app/model"
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ func TestCgroup(t *testing.T) {
|
|||||||
Name: "test",
|
Name: "test",
|
||||||
Cmd: "bash",
|
Cmd: "bash",
|
||||||
Cwd: `/root`,
|
Cwd: `/root`,
|
||||||
TermType: constants.TERMINAL_PTY,
|
TermType: eum.TerminalPty,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
|
4
resources/.browserslistrc
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
> 1%
|
||||||
|
last 2 versions
|
||||||
|
not dead
|
||||||
|
not ie 11
|
2
resources/.dockerignore
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
node_modules
|
||||||
|
npm-debug.log
|
5
resources/.editorconfig
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
[*.{js,jsx,ts,tsx,vue}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
10
resources/.env.dev
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
# Firebase 🔥
|
||||||
|
VITE_FIREBASE_API_KEY=
|
||||||
|
VITE_FIREBASE_AUTH_DOMAIN=
|
||||||
|
VITE_FIREBASE_PROJECT_ID=
|
||||||
|
VITE_FIREBASE_STORAGE_BUCKET=
|
||||||
|
VITE_FIREBASE_MESSAGING_SENDER_ID=
|
||||||
|
VITE_FIREBASE_APP_ID=
|
||||||
|
VITE_FIREBASE_MEASUREMENT_ID=
|
1
resources/.env.pro
Normal file
@@ -0,0 +1 @@
|
|||||||
|
VITE_API_BASE_URL=https://api.example.com
|
7
resources/.env.template
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
VITE_OPENAI_API_KEY = XXXXXXXXXXXX
|
||||||
|
VITE_UNSPLASH_ACCESS_KEY = XXXXXXXXXXXX
|
||||||
|
VITE_GITHUB_CLIENT_ID = XXXXXXXXXXXX
|
||||||
|
# Aruze TextToSpeech Key (required for tts)
|
||||||
|
VITE_TTS_KEY=XXXXXXXXXXXX
|
||||||
|
# Aruze TextToSpeech Region
|
||||||
|
VITE_TTS_REGION = XXXXXXXXXXXX
|
2
resources/.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
* text=auto
|
32
resources/.gitignore
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
/dist
|
||||||
|
/.vite_cache
|
||||||
|
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
|
|
||||||
|
# Local Netlify folder
|
||||||
|
.netlify
|
||||||
|
.env
|
||||||
|
|
||||||
|
# yarn.lock
|
||||||
|
yarn.lock
|
3
resources/.vite/deps_temp_61bc278e/package.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"type": "module"
|
||||||
|
}
|
13
resources/Dockerfile
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# 构建阶段
|
||||||
|
FROM node:lts-alpine as build-stage
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm install
|
||||||
|
COPY . .
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# 生产阶段
|
||||||
|
FROM nginx:stable-alpine as production-stage
|
||||||
|
COPY --from=build-stage /app/dist /usr/share/nginx/html
|
||||||
|
EXPOSE 80
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
6
resources/Dockerfile.dev
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
FROM node:lts-alpine
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm install
|
||||||
|
EXPOSE 8080
|
||||||
|
CMD ["npm", "run", "dev"]
|
21
resources/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 jk.yang
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
169
resources/README.jp.md
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
<br><br>
|
||||||
|
|
||||||
|
<p align='center' >
|
||||||
|
<img src='/src/assets/logo.png' alt='Vuetify3' width='300'/>
|
||||||
|
</p>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://vuejs.org/">
|
||||||
|
<img src="https://img.shields.io/badge/vue-v3.2.47-brightgreen.svg" alt="vue">
|
||||||
|
</a>
|
||||||
|
<a href="https://vuetifyjs.com/">
|
||||||
|
<img src="https://img.shields.io/badge/vuetify-v3.1.13-blue.svg" alt="element-ui">
|
||||||
|
</a>
|
||||||
|
<a href="https://vitejs.dev/">
|
||||||
|
<img src="https://img.shields.io/badge/vite-v4.2.1-blueviolet.svg" alt="element-ui">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="https://github.com/yangjiakai/lux-admin-vuetify3/blob/main/LICENSE">
|
||||||
|
<img src="https://img.shields.io/github/license/mashape/apistatus.svg" alt="license">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h4 align='center'>
|
||||||
|
<a href="https://lux.vuetify3.com/">ライブ・デモ</a>
|
||||||
|
</h4>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<p align='center'>
|
||||||
|
<a href="https://github.com/yangjiakai/jk-vuetify3-lux-admin/blob/main/README.md">English</a> | <a href="https://github.com/yangjiakai/jk-vuetify3-lux-admin/blob/main/README.zh-CN.md">简体中文</a>| <b >日本語</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## 📖 序文
|
||||||
|
|
||||||
|
> 目標は、最も優れた Vuetify 3 の Admin オープンソーステンプレートを作成することです。
|
||||||
|
|
||||||
|
Vuetify の洗練されたテーマを基盤に、明確で効率的なプロジェクト構造を構築し、最新の技術フレームワークを統合しています。このプロジェクトは、さまざまな一般的な技術要件や機能に対応することを目指し、AI アシスタントを組み込むことで、よりインテリジェントな体験を提供します。さらに、すべてのページが複数のデバイスで適応的に表示されるようにし、シームレスなクロスプラットフォーム互換性を実現しています。
|
||||||
|
|
||||||
|
## 📖Other Versions
|
||||||
|
|
||||||
|
SPA Full Version: [lux-ui](https://github.com/yangjiakai/lux-nuxt3)
|
||||||
|
|
||||||
|
SPA Simplified i18n Version[lux-ui-i18n](https://github.com/yangjiakai/vuetify3-lux-admin-template-i18n)
|
||||||
|
|
||||||
|
SPA Simplified chinese Version[lux-ui-zh](https://github.com/yangjiakai/vuetify3-lux-admin-template-zh)
|
||||||
|
|
||||||
|
Nuxt3 version:
|
||||||
|
|
||||||
|
Nuxt3 Full Version [lux-nuxt3](https://github.com/yangjiakai/lux-nuxt3)
|
||||||
|
|
||||||
|
Nuxt3 Simplified Version [lux-nuxt3-template](https://github.com/yangjiakai/lux-nuxt3-template)
|
||||||
|
|
||||||
|
## 📖Documents
|
||||||
|
|
||||||
|
- 📖 [Document 1.0 Chinese](https://www.craft.me/s/tAMVv4hUxZIH6G)
|
||||||
|
|
||||||
|
## 📚 特徴
|
||||||
|
|
||||||
|
- 📖 [Vue 3.2](https://github.com/vuejs/core)
|
||||||
|
- 📖 [Vite 4.x](https://github.com/vitejs/vite)
|
||||||
|
- 📖 UI Framework [Vuetify 3](https://next.vuetifyjs.com/en/)
|
||||||
|
- 📖 TypeScript
|
||||||
|
- 📦 Component Auto Importing
|
||||||
|
- 🍍 [Pinia](https://pinia.vuejs.org/)
|
||||||
|
- 📔 `<script setup>`
|
||||||
|
- 📚 Use icons from any icon sets in [Iconify](https://icon-sets.iconify.design/)
|
||||||
|
- ☁️ Deploy on Netlify, zero-config
|
||||||
|
- 🔑 Firebase auth
|
||||||
|
- 📈 Echarts, ApexChart
|
||||||
|
- 🧭 Openai, Chatgpt
|
||||||
|
- 🌍 vue-i18n
|
||||||
|
- 📚 virtual-scroller , vuedraggable , perfect-scrollbar
|
||||||
|
- 📝 Rich Text Editor
|
||||||
|
- 📇 Responsive multi-platform adaptive
|
||||||
|
|
||||||
|
## 📈 Project Activity
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 💬 連絡
|
||||||
|
|
||||||
|
- Email <a href="mailto:yjkbako@gmail.com">yjkbako@gmail.com</a>
|
||||||
|
- Twitter https://twitter.com/baibaixiang
|
||||||
|
- Wechat <img src='/src/assets/wechat-qrcode.png' alt='DashBoard' width='300' />
|
||||||
|
|
||||||
|
## 💌 プレビュー
|
||||||
|
|
||||||
|
<img src='/src/assets/previews/DashBoard.png' alt='DashBoard' />
|
||||||
|
<img src='/src/assets/previews/TaskBoard.png' alt='ChatGPT' />
|
||||||
|
<img src='/src/assets/previews/DataTable.png' alt='DataTable' />
|
||||||
|
<img src='/src/assets/previews/Todo.png' alt='ChatGPT' />
|
||||||
|
<img src='/src/assets/previews/ChatGPT.png' alt='ChatGPT' />
|
||||||
|
<img src='/src/assets/previews/Card.png' alt='Card' />
|
||||||
|
<img src='/src/assets/previews/Color.png' alt='Color' />
|
||||||
|
<img src='/src/assets/previews/Gradient.png' alt='Gradient' />
|
||||||
|
<img src='/src/assets/previews/Login.png' alt='ChatGPT' />
|
||||||
|
<img src='/src/assets/previews/Unsplash.png' alt='ChatGPT' />
|
||||||
|
<img src='/src/assets/previews/Unsplash2.png' alt='ChatGPT' />
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## 📦 プリパック
|
||||||
|
|
||||||
|
### 🏷️UI Frameworks
|
||||||
|
|
||||||
|
- [Vuetify3](https://next.vuetifyjs.com/en/) - Vuetify は、美しく手作りされた Vue コンポーネントで構成された、デザインスキル不要の UI フレームワークです。
|
||||||
|
|
||||||
|
### 🏷️Icons
|
||||||
|
|
||||||
|
- [Iconify](https://iconify.design) - 任意のアイコンセットを使用 [🔍Icônes](https://icones.netlify.app/)
|
||||||
|
- [Pure CSS Icons via UnoCSS](https://github.com/antfu/unocss/tree/main/packages/preset-icons)
|
||||||
|
|
||||||
|
### 🏷️ プラグイン
|
||||||
|
|
||||||
|
- [Vue Router4](https://router.vuejs.org/)
|
||||||
|
- [VueUse](https://github.com/antfu/vueuse) - 便利なコンポジション API 集
|
||||||
|
- [VuedDaggable](https://github.com/SortableJS/Vue.Draggable) - 配列モデルと同期したドラッグ&ドロップによる配置操作が可能
|
||||||
|
- [Vue-Masonry-Wall](https://github.com/DerYeger/yeger/tree/main/packages/vue-masonry-wall) -Vue 3 のレスポンシブな Masonry レイアウト SSR をサポートしています
|
||||||
|
- [Vue-Virtual-Scroller](https://github.com/Akryum/vue-virtual-scroller) - 超高速の任意のデータ量のスクロール
|
||||||
|
|
||||||
|
## 👻 今すぐ試す!
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone https://github.com/yangjiakai/lux-admin-vuetify3.git
|
||||||
|
|
||||||
|
cd lux-admin-vuetify3
|
||||||
|
|
||||||
|
yarn install
|
||||||
|
|
||||||
|
yarn dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## 👻Docker it!
|
||||||
|
|
||||||
|
1. 开发环境构建镜像:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker-compose build dev
|
||||||
|
```
|
||||||
|
|
||||||
|
2. 启动开发环境:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker-compose up dev
|
||||||
|
```
|
||||||
|
|
||||||
|
3. 生产环境构建镜像:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker-compose build app
|
||||||
|
```
|
||||||
|
|
||||||
|
4. 启动生产环境:
|
||||||
|
```
|
||||||
|
docker-compose up app
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🔑Set ApiKey
|
||||||
|
|
||||||
|
Find the `.env.template` file in the root directory, remove the `.template` suffix, and replace` VITE_OPENAI_API_KEY`, `VITE_UNSPLASH_ACCESS_KEY`, and `VITE_GITHUB_CLIENT_ID`, and `VITE_TTS_KEY` and `VITE_TTS_REGION` with your own keys.
|
||||||
|
|
||||||
|
> openai apikey: https://platform.openai.com/account/api-keys
|
||||||
|
|
||||||
|
> unsplash apikey: https://unsplash.com/oauth/applications
|
||||||
|
|
||||||
|
> github apikey: https://github.com/settings/tokens
|
||||||
|
|
||||||
|
> azure textToSpeech : https://speech.microsoft.com/
|
171
resources/README.md
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
<br><br>
|
||||||
|
|
||||||
|
<p align='center' >
|
||||||
|
<img src='/src/assets/logo.png' alt='Vuetify3' width='300'/>
|
||||||
|
</p>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://vuejs.org/">
|
||||||
|
<img src="https://img.shields.io/badge/vue-v3.2.47-brightgreen.svg" alt="vue">
|
||||||
|
</a>
|
||||||
|
<a href="https://vuetifyjs.com/">
|
||||||
|
<img src="https://img.shields.io/badge/vuetify-v3.1.13-blue.svg" alt="element-ui">
|
||||||
|
</a>
|
||||||
|
<a href="https://vitejs.dev/">
|
||||||
|
<img src="https://img.shields.io/badge/vite-v4.2.1-blueviolet.svg" alt="element-ui">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="https://github.com/yangjiakai/lux-admin-vuetify3/blob/main/LICENSE">
|
||||||
|
<img src="https://img.shields.io/github/license/mashape/apistatus.svg" alt="license">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h4 align='center'>
|
||||||
|
<a href="https://lux.vuetify3.com/">Live Demo</a>
|
||||||
|
</h4>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<p align='center'>
|
||||||
|
<b>English</b> | <a href="https://github.com/yangjiakai/jk-vuetify3-lux-admin/blob/main/README.zh-CN.md">简体中文</a>| <a href="https://github.com/yangjiakai/jk-vuetify3-lux-admin/blob/main/README.jp.md">日本語</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## 📖Introduction
|
||||||
|
|
||||||
|
> Goal: Creating the best Vuetify 3 Admin open-source template.
|
||||||
|
|
||||||
|
Built upon the elegant themes of Vuetify, we have established a clear and efficient project structure, integrating the latest technology frameworks. This project aims to address a wide range of common technical requirements and features, while incorporating an AI assistant for a more intelligent experience. Additionally, we ensure that all pages are adaptive across multiple devices, achieving a seamless cross-platform compatibility.
|
||||||
|
|
||||||
|
## 📖Other Versions
|
||||||
|
|
||||||
|
SPA Full Version: [lux-vuetify3](https://github.com/yangjiakai/lux-nuxt3)
|
||||||
|
|
||||||
|
SPA Simplified i18n Version[lux-vuetify3-i18n](https://github.com/yangjiakai/vuetify3-lux-admin-template-i18n)
|
||||||
|
|
||||||
|
SPA Simplified chinese Version[lux-vuetify3-zh](https://github.com/yangjiakai/vuetify3-lux-admin-template-zh)
|
||||||
|
|
||||||
|
Nuxt3 version:
|
||||||
|
|
||||||
|
Nuxt3 Full Version [lux-nuxt3](https://github.com/yangjiakai/lux-nuxt3)
|
||||||
|
|
||||||
|
Nuxt3 Simplified Version [lux-nuxt3-template](https://github.com/yangjiakai/lux-nuxt3-template)
|
||||||
|
|
||||||
|
## 📖Documents
|
||||||
|
|
||||||
|
- 📖 [Document 1.0 Chinese](https://www.craft.me/s/tAMVv4hUxZIH6G)
|
||||||
|
|
||||||
|
## 📚Features
|
||||||
|
|
||||||
|
- 📖 [Vue 3.2](https://github.com/vuejs/core)
|
||||||
|
- 📖 [Vite 4.x](https://github.com/vitejs/vite)
|
||||||
|
- 📖 UI Framework [Vuetify 3](https://next.vuetifyjs.com/en/)
|
||||||
|
- 📖 TypeScript
|
||||||
|
- 📦 Component Auto Importing
|
||||||
|
- 🍍 [Pinia](https://pinia.vuejs.org/)
|
||||||
|
- 📔 `<script setup>`
|
||||||
|
- 📚 Use icons from any icon sets in [Iconify](https://icon-sets.iconify.design/)
|
||||||
|
- ☁️ Deploy on Netlify, zero-config
|
||||||
|
- 🔑 Firebase auth
|
||||||
|
- 📈 Echarts, ApexChart
|
||||||
|
- 🧭 Openai, Chatgpt
|
||||||
|
- 🌍 vue-i18n
|
||||||
|
- 📚 virtual-scroller , vuedraggable , perfect-scrollbar
|
||||||
|
- 📝 Rich Text Editor
|
||||||
|
- 📇 Responsive multi-platform adaptive
|
||||||
|
|
||||||
|
## 📈 Project Activity
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 💬Contact Me
|
||||||
|
|
||||||
|
- Email <a href="mailto:yjkbako@gmail.com">yjkbako@gmail.com</a>
|
||||||
|
- Twitter https://twitter.com/baibaixiang
|
||||||
|
- Wechat <img src='/src/assets/wechat-qrcode.png' alt='DashBoard' width='300' />
|
||||||
|
|
||||||
|
## 💌Preview
|
||||||
|
|
||||||
|
<img src='/src/assets/previews/DashBoard.png' alt='DashBoard' />
|
||||||
|
<img src='/src/assets/previews/TaskBoard.png' alt='ChatGPT' />
|
||||||
|
<img src='/src/assets/previews/DataTable.png' alt='DataTable' />
|
||||||
|
<img src='/src/assets/previews/Todo.png' alt='ChatGPT' />
|
||||||
|
<img src='/src/assets/previews/ChatGPT.png' alt='ChatGPT' />
|
||||||
|
<img src='/src/assets/previews/Card.png' alt='Card' />
|
||||||
|
<img src='/src/assets/previews/Color.png' alt='Color' />
|
||||||
|
<img src='/src/assets/previews/Gradient.png' alt='Gradient' />
|
||||||
|
<img src='/src/assets/previews/Login.png' alt='ChatGPT' />
|
||||||
|
<img src='/src/assets/previews/Unsplash.png' alt='ChatGPT' />
|
||||||
|
<img src='/src/assets/previews/Unsplash2.png' alt='ChatGPT' />
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## 📦Pre-packed
|
||||||
|
|
||||||
|
### 🏷️ UI Frameworks
|
||||||
|
|
||||||
|
- [Vuetify3](https://next.vuetifyjs.com/en/) - Vuetify is a no design skills required UI Framework with beautifully handcrafted Vue Components.
|
||||||
|
|
||||||
|
### 🏷️ Icons
|
||||||
|
|
||||||
|
- [Iconify](https://iconify.design) - use icons from any icon sets [🔍Icônes](https://icones.netlify.app/)
|
||||||
|
- [Pure CSS Icons via UnoCSS](https://github.com/antfu/unocss/tree/main/packages/preset-icons)
|
||||||
|
|
||||||
|
### 🏷️ Plugins
|
||||||
|
|
||||||
|
- [Vue Router4](https://router.vuejs.org/)
|
||||||
|
- [VueUse](https://github.com/antfu/vueuse) - collection of useful composition APIs
|
||||||
|
- [VuedDaggable](https://github.com/SortableJS/Vue.Draggable) - allowing drag-and-drop and synchronization with view model array.
|
||||||
|
- [Vue-Masonry-Wall](https://github.com/DerYeger/yeger/tree/main/packages/vue-masonry-wall) - Responsive masonry layout with SSR support and zero dependencies for Vue 3.
|
||||||
|
- [Vue-Virtual-Scroller](https://github.com/Akryum/vue-virtual-scroller) - Blazing fast scrolling of any amount of data
|
||||||
|
|
||||||
|
## 👻Try it now!
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone https://github.com/yangjiakai/lux-admin-vuetify3.git
|
||||||
|
|
||||||
|
cd lux-admin-vuetify3
|
||||||
|
|
||||||
|
yarn install
|
||||||
|
|
||||||
|
yarn dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## 👻Docker it!
|
||||||
|
|
||||||
|
1. Build the development environment image:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker-compose build dev
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Start the development environment:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker-compose up dev
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Build the production environment image:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker-compose build app
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Start the production environment:
|
||||||
|
```
|
||||||
|
docker-compose up app
|
||||||
|
```
|
||||||
|
|
||||||
|
这应该能解决实时更新的问题。如果您还有任何疑问或遇到其他问题,请随时告诉我。
|
||||||
|
|
||||||
|
### 🔑Set ApiKey
|
||||||
|
|
||||||
|
Find the `.env.template` file in the root directory, remove the `.template` suffix, and replace` VITE_OPENAI_API_KEY`, `VITE_UNSPLASH_ACCESS_KEY`, and `VITE_GITHUB_CLIENT_ID`, and `VITE_TTS_KEY` and `VITE_TTS_REGION` with your own keys.
|
||||||
|
|
||||||
|
> openai apikey: https://platform.openai.com/account/api-keys
|
||||||
|
|
||||||
|
> unsplash apikey: https://unsplash.com/oauth/applications
|
||||||
|
|
||||||
|
> github apikey: https://github.com/settings/tokens
|
||||||
|
|
||||||
|
> azure textToSpeech : https://speech.microsoft.com/
|
210
resources/README.zh-CN.md
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
<br><br>
|
||||||
|
|
||||||
|
<p align='center' >
|
||||||
|
<img src='/src/assets/logo.png' alt='Vuetify3' width='300'/>
|
||||||
|
</p>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://vuejs.org/">
|
||||||
|
<img src="https://img.shields.io/badge/vue-v3.2.47-brightgreen.svg" alt="vue">
|
||||||
|
</a>
|
||||||
|
<a href="https://vuetifyjs.com/">
|
||||||
|
<img src="https://img.shields.io/badge/vuetify-v3.1.13-blue.svg" alt="element-ui">
|
||||||
|
</a>
|
||||||
|
<a href="https://vitejs.dev/">
|
||||||
|
<img src="https://img.shields.io/badge/vite-v4.2.1-blueviolet.svg" alt="element-ui">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="https://github.com/yangjiakai/lux-admin-vuetify3/blob/main/LICENSE">
|
||||||
|
<img src="https://img.shields.io/github/license/mashape/apistatus.svg" alt="license">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h4 align='center'>
|
||||||
|
<a href="https://lux.vuetify3.com/">在线 Demo</a>
|
||||||
|
</h4>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<p align='center'>
|
||||||
|
<a href="https://github.com/yangjiakai/jk-vuetify3-lux-admin/blob/main/README.md">English</a> | <b>简体中文</b>| <a href="https://github.com/yangjiakai/jk-vuetify3-lux-admin/blob/main/README.jp.md">日本語</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## 📖 序文
|
||||||
|
|
||||||
|
> 目标创造最优秀的 vuetify3 的 Admin 开源模板
|
||||||
|
|
||||||
|
在 Vuetify 精美的主题基础上,我们构建了一个清晰且高效的项目逻辑架构,整合了最新的技术框架。本项目旨在实现各种常见的技术需求和功能,同时融合了 AI 助手,以提供更智能化的体验。此外,我们确保所有页面在多种设备上均能自适应展示,实现优雅的跨平台兼容性。
|
||||||
|
|
||||||
|
## 📖 其他版本
|
||||||
|
|
||||||
|
### SPA Version
|
||||||
|
|
||||||
|
SPA 完整版: [lux-vuetify3](https://github.com/yangjiakai/lux-nuxt3)
|
||||||
|
|
||||||
|
SPA 简化国际化模板 [lux-vuetify3-i18n](https://github.com/yangjiakai/vuetify3-lux-admin-template-i18n)
|
||||||
|
|
||||||
|
SPA 简化中文模板 [lux-vuetify3-zh](https://github.com/yangjiakai/vuetify3-lux-admin-template-zh)
|
||||||
|
|
||||||
|
### Nuxt3 Version
|
||||||
|
|
||||||
|
Nuxt3 完整版 [lux-nuxt3](https://github.com/yangjiakai/lux-nuxt3)
|
||||||
|
|
||||||
|
Nuxt3 简化版 [lux-nuxt3-template](https://github.com/yangjiakai/lux-nuxt3-template)
|
||||||
|
|
||||||
|
## 文档
|
||||||
|
|
||||||
|
- 📖 [中文版文档 1.0 ](https://www.craft.me/s/tAMVv4hUxZIH6G)
|
||||||
|
|
||||||
|
## 📚 特性
|
||||||
|
|
||||||
|
- 📖 [Vue 3.2](https://github.com/vuejs/core)
|
||||||
|
- 📖 [Vite 4.x](https://github.com/vitejs/vite)
|
||||||
|
- 📖 UI Framework [Vuetify 3](https://next.vuetifyjs.com/en/)
|
||||||
|
- 📖 TypeScript
|
||||||
|
- 📦 组件自动导入
|
||||||
|
- 🍍 通过 [Pinia](https://pinia.vuejs.org/)进行状态管理
|
||||||
|
- 📔 使用新的 `<script setup>` 语法
|
||||||
|
- 📚 使用任意的图标集 [Iconify](https://icon-sets.iconify.design/)
|
||||||
|
- ☁️ 零配置部署在 Netlify
|
||||||
|
- 🔑 Firebase 授权
|
||||||
|
- 📈 Echarts, ApexChart
|
||||||
|
- 🧭 Openai, Chatgpt 支持
|
||||||
|
- 🌍 vue-i18n 多语言支持
|
||||||
|
- 📚 virtual-scroller , vuedraggable , perfect-scrollbar
|
||||||
|
- 📝 富文本编辑器
|
||||||
|
- 📇 响应式多平台自适应
|
||||||
|
|
||||||
|
## 📈 项目活跃度
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 💬 联络我
|
||||||
|
|
||||||
|
- 邮箱 <a href="mailto:yjkbako@gmail.com">yjkbako@gmail.com</a>
|
||||||
|
- 推特 https://twitter.com/baibaixiang
|
||||||
|
- 微信 <img src='/src/assets/wechat-qrcode.png' alt='DashBoard' width='300' />
|
||||||
|
|
||||||
|
## 💌 预览
|
||||||
|
|
||||||
|
<img src='/src/assets/previews/DashBoard.png' alt='DashBoard' />
|
||||||
|
<img src='/src/assets/previews/TaskBoard.png' alt='ChatGPT' />
|
||||||
|
<img src='/src/assets/previews/DataTable.png' alt='DataTable' />
|
||||||
|
<img src='/src/assets/previews/Todo.png' alt='ChatGPT' />
|
||||||
|
<img src='/src/assets/previews/ChatGPT.png' alt='ChatGPT' />
|
||||||
|
<img src='/src/assets/previews/Card.png' alt='Card' />
|
||||||
|
<img src='/src/assets/previews/Color.png' alt='Color' />
|
||||||
|
<img src='/src/assets/previews/Gradient.png' alt='Gradient' />
|
||||||
|
<img src='/src/assets/previews/Login.png' alt='ChatGPT' />
|
||||||
|
<img src='/src/assets/previews/Unsplash.png' alt='ChatGPT' />
|
||||||
|
<img src='/src/assets/previews/Unsplash2.png' alt='ChatGPT' />
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## 📦Pre-packed
|
||||||
|
|
||||||
|
### 🏷️UI 框架
|
||||||
|
|
||||||
|
- [Vuetify3](https://next.vuetifyjs.com/en/) - Vuetify 是一个不要求设计能力的 Vue 界面组件框架,自带了许多自行设计实现的 Vue 组件。
|
||||||
|
|
||||||
|
### 🏷️Icons
|
||||||
|
|
||||||
|
- [Iconify](https://iconify.design) - 使用任意的图标集 [🔍Icônes](https://icones.netlify.app/)
|
||||||
|
- [Pure CSS Icons via UnoCSS](https://github.com/antfu/unocss/tree/main/packages/preset-icons)
|
||||||
|
|
||||||
|
## 目标功能
|
||||||
|
|
||||||
|
- [x] 明暗主题切换 -- 完成
|
||||||
|
- [x] 主题色切换 -- 完成
|
||||||
|
- [x] 中日英三语言切换-- 完成
|
||||||
|
- [x] 整合 ChatGpt-- 完成
|
||||||
|
|
||||||
|
## 目标页面
|
||||||
|
|
||||||
|
### 认证相关
|
||||||
|
|
||||||
|
- [x] 登录 -- 完成
|
||||||
|
- [x] 注册 -- 完成
|
||||||
|
- [x] 验证邮件 -- 完成
|
||||||
|
- [ ] 密码重置 -- 施工中
|
||||||
|
|
||||||
|
### 公共页面
|
||||||
|
|
||||||
|
- [x] 404 -- 完成
|
||||||
|
- [x] 500 -- 施工中
|
||||||
|
- [x] 系统维护 -- 施工中
|
||||||
|
- [x] 常见问题 -- 施工中
|
||||||
|
|
||||||
|
### UI 相关
|
||||||
|
|
||||||
|
- [x] 瀑布流布局 -- 完成
|
||||||
|
- [x] 大数据虚拟列表 -- 完成
|
||||||
|
- [ ] 骨架屏 -- 施工中
|
||||||
|
|
||||||
|
### 功能页面
|
||||||
|
|
||||||
|
- [x] 任务版(拖拽功能) -- 完成
|
||||||
|
- [x] 任务列表() -- 施工中
|
||||||
|
|
||||||
|
### 站点仿写
|
||||||
|
|
||||||
|
- [ ] ......
|
||||||
|
|
||||||
|
### 🏷️ 插件
|
||||||
|
|
||||||
|
- [Vue Router4](https://router.vuejs.org/)
|
||||||
|
- [VueUse](https://github.com/antfu/vueuse) - 非常有用的组合式 API 合集
|
||||||
|
- [VuedDaggable](https://github.com/SortableJS/Vue.Draggable) - 允许进行与数组模型同步的拖拽放置操作
|
||||||
|
- [Vue-Masonry-Wall](https://github.com/DerYeger/yeger/tree/main/packages/vue-masonry-wall) - 是一种 Vue3 响应式,支持 SSR,且零依的的瀑布流布局方案
|
||||||
|
- [Vue-Virtual-Scroller](https://github.com/Akryum/vue-virtual-scroller) - 大数据快速虚拟滚动插件
|
||||||
|
|
||||||
|
## 👻 现在可以试试!
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone https://github.com/yangjiakai/lux-admin-vuetify3.git
|
||||||
|
|
||||||
|
cd lux-admin-vuetify3
|
||||||
|
|
||||||
|
yarn install
|
||||||
|
|
||||||
|
yarn dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## 👻Docker it!
|
||||||
|
|
||||||
|
1. 开发环境构建镜像:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker-compose build dev
|
||||||
|
```
|
||||||
|
|
||||||
|
2. 启动开发环境:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker-compose up dev
|
||||||
|
```
|
||||||
|
|
||||||
|
3. 生产环境构建镜像:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker-compose build app
|
||||||
|
```
|
||||||
|
|
||||||
|
4. 启动生产环境:
|
||||||
|
```
|
||||||
|
docker-compose up app
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🔑 配置 ApiKey
|
||||||
|
|
||||||
|
找到根目录下的`.env.template`文件,去掉`.template`后缀
|
||||||
|
把`VITE_OPENAI_API_KEY`,`VITE_UNSPLASH_ACCESS_KEY`,`VITE_GITHUB_CLIENT_ID`,`VITE_TTS_KEY` , `VITE_TTS_REGION`分别替换成你自己的
|
||||||
|
|
||||||
|
> openai apikey: https://platform.openai.com/account/api-keys
|
||||||
|
|
||||||
|
> unsplash apikey: https://unsplash.com/oauth/applications
|
||||||
|
|
||||||
|
> github apikey: https://github.com/settings/tokens
|
||||||
|
|
||||||
|
> azure textToSpeech : https://speech.microsoft.com/
|
73
resources/auto-imports.d.ts
vendored
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
// Generated by 'unplugin-auto-import'
|
||||||
|
export {};
|
||||||
|
declare global {
|
||||||
|
const EffectScope: typeof import("vue")["EffectScope"];
|
||||||
|
const acceptHMRUpdate: typeof import("pinia")["acceptHMRUpdate"];
|
||||||
|
const computed: typeof import("vue")["computed"];
|
||||||
|
const createApp: typeof import("vue")["createApp"];
|
||||||
|
const createPinia: typeof import("pinia")["createPinia"];
|
||||||
|
const customRef: typeof import("vue")["customRef"];
|
||||||
|
const defineAsyncComponent: typeof import("vue")["defineAsyncComponent"];
|
||||||
|
const defineComponent: typeof import("vue")["defineComponent"];
|
||||||
|
const defineStore: typeof import("pinia")["defineStore"];
|
||||||
|
const effectScope: typeof import("vue")["effectScope"];
|
||||||
|
const getActivePinia: typeof import("pinia")["getActivePinia"];
|
||||||
|
const getCurrentInstance: typeof import("vue")["getCurrentInstance"];
|
||||||
|
const getCurrentScope: typeof import("vue")["getCurrentScope"];
|
||||||
|
const h: typeof import("vue")["h"];
|
||||||
|
const inject: typeof import("vue")["inject"];
|
||||||
|
const isProxy: typeof import("vue")["isProxy"];
|
||||||
|
const isReactive: typeof import("vue")["isReactive"];
|
||||||
|
const isReadonly: typeof import("vue")["isReadonly"];
|
||||||
|
const isRef: typeof import("vue")["isRef"];
|
||||||
|
const mapActions: typeof import("pinia")["mapActions"];
|
||||||
|
const mapGetters: typeof import("pinia")["mapGetters"];
|
||||||
|
const mapState: typeof import("pinia")["mapState"];
|
||||||
|
const mapStores: typeof import("pinia")["mapStores"];
|
||||||
|
const mapWritableState: typeof import("pinia")["mapWritableState"];
|
||||||
|
const markRaw: typeof import("vue")["markRaw"];
|
||||||
|
const nextTick: typeof import("vue")["nextTick"];
|
||||||
|
const onActivated: typeof import("vue")["onActivated"];
|
||||||
|
const onBeforeMount: typeof import("vue")["onBeforeMount"];
|
||||||
|
const onBeforeRouteLeave: typeof import("vue-router")["onBeforeRouteLeave"];
|
||||||
|
const onBeforeRouteUpdate: typeof import("vue-router")["onBeforeRouteUpdate"];
|
||||||
|
const onBeforeUnmount: typeof import("vue")["onBeforeUnmount"];
|
||||||
|
const onBeforeUpdate: typeof import("vue")["onBeforeUpdate"];
|
||||||
|
const onDeactivated: typeof import("vue")["onDeactivated"];
|
||||||
|
const onErrorCaptured: typeof import("vue")["onErrorCaptured"];
|
||||||
|
const onMounted: typeof import("vue")["onMounted"];
|
||||||
|
const onRenderTracked: typeof import("vue")["onRenderTracked"];
|
||||||
|
const onRenderTriggered: typeof import("vue")["onRenderTriggered"];
|
||||||
|
const onScopeDispose: typeof import("vue")["onScopeDispose"];
|
||||||
|
const onServerPrefetch: typeof import("vue")["onServerPrefetch"];
|
||||||
|
const onUnmounted: typeof import("vue")["onUnmounted"];
|
||||||
|
const onUpdated: typeof import("vue")["onUpdated"];
|
||||||
|
const provide: typeof import("vue")["provide"];
|
||||||
|
const reactive: typeof import("vue")["reactive"];
|
||||||
|
const readonly: typeof import("vue")["readonly"];
|
||||||
|
const ref: typeof import("vue")["ref"];
|
||||||
|
const resolveComponent: typeof import("vue")["resolveComponent"];
|
||||||
|
const resolveDirective: typeof import("vue")["resolveDirective"];
|
||||||
|
const setActivePinia: typeof import("pinia")["setActivePinia"];
|
||||||
|
const setMapStoreSuffix: typeof import("pinia")["setMapStoreSuffix"];
|
||||||
|
const shallowReactive: typeof import("vue")["shallowReactive"];
|
||||||
|
const shallowReadonly: typeof import("vue")["shallowReadonly"];
|
||||||
|
const shallowRef: typeof import("vue")["shallowRef"];
|
||||||
|
const storeToRefs: typeof import("pinia")["storeToRefs"];
|
||||||
|
const toRaw: typeof import("vue")["toRaw"];
|
||||||
|
const toRef: typeof import("vue")["toRef"];
|
||||||
|
const toRefs: typeof import("vue")["toRefs"];
|
||||||
|
const triggerRef: typeof import("vue")["triggerRef"];
|
||||||
|
const unref: typeof import("vue")["unref"];
|
||||||
|
const useAttrs: typeof import("vue")["useAttrs"];
|
||||||
|
const useCssModule: typeof import("vue")["useCssModule"];
|
||||||
|
const useCssVars: typeof import("vue")["useCssVars"];
|
||||||
|
const useLink: typeof import("vue-router")["useLink"];
|
||||||
|
const useRoute: typeof import("vue-router")["useRoute"];
|
||||||
|
const useRouter: typeof import("vue-router")["useRouter"];
|
||||||
|
const useSlots: typeof import("vue")["useSlots"];
|
||||||
|
const watch: typeof import("vue")["watch"];
|
||||||
|
const watchEffect: typeof import("vue")["watchEffect"];
|
||||||
|
const watchPostEffect: typeof import("vue")["watchPostEffect"];
|
||||||
|
const watchSyncEffect: typeof import("vue")["watchSyncEffect"];
|
||||||
|
}
|
25
resources/docker-compose.yml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
|
||||||
|
dev:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile.dev
|
||||||
|
volumes:
|
||||||
|
- .:/app
|
||||||
|
- /app/node_modules
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=development
|
||||||
|
command: npm run dev
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
node_modules:
|
32
resources/index.html
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" href="/favicon.png" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Vuetify-Lux</title>
|
||||||
|
<!-- Google tag (gtag.js) -->
|
||||||
|
<script
|
||||||
|
async
|
||||||
|
src="https://www.googletagmanager.com/gtag/js?id=G-WVWG4VLCL2"
|
||||||
|
></script>
|
||||||
|
<script>
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
|
function gtag() {
|
||||||
|
dataLayer.push(arguments);
|
||||||
|
}
|
||||||
|
gtag("js", new Date());
|
||||||
|
|
||||||
|
gtag("config", "G-WVWG4VLCL2");
|
||||||
|
</script>
|
||||||
|
<link
|
||||||
|
href="https://fonts.loli.net/css2?family=Quicksand:wght@300;400;500;600;700&display=swap"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.ts"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
2
resources/netlify.toml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[build.environment]
|
||||||
|
NODE_VERSION = "21.1.0"
|
7444
resources/package-lock.json
generated
Normal file
72
resources/package.json
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
{
|
||||||
|
"name": "vuetify3-design",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite --mode dev",
|
||||||
|
"build": "vite build --base=/ --mode pro",
|
||||||
|
"preview": "vite preview",
|
||||||
|
"test": "vitest",
|
||||||
|
"test:ui": "vitest --ui",
|
||||||
|
"coverage": "vitest run --coverage"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@formkit/auto-animate": "^0.8.2",
|
||||||
|
"@mdi/font": "7.4.47",
|
||||||
|
"@tiptap/pm": "^2.5.9",
|
||||||
|
"@tiptap/starter-kit": "^2.5.9",
|
||||||
|
"@tiptap/vue-3": "^2.5.9",
|
||||||
|
"@vueup/vue-quill": "^1.2.0",
|
||||||
|
"@vueuse/core": "^10.11.0",
|
||||||
|
"@vueuse/integrations": "^10.11.0",
|
||||||
|
"@xterm/addon-canvas": "^0.7.0",
|
||||||
|
"@yeger/vue-masonry-wall": "^5.0.14",
|
||||||
|
"apexcharts": "^3.52.0",
|
||||||
|
"axios": "^1.7.5",
|
||||||
|
"clipboard": "^2.0.11",
|
||||||
|
"echarts": "^5.5.1",
|
||||||
|
"flag-icons": "^7.2.3",
|
||||||
|
"focus-trap": "^7.5.4",
|
||||||
|
"happy-dom": "^14.12.3",
|
||||||
|
"md-editor-v3": "^4.18.0",
|
||||||
|
"microsoft-cognitiveservices-speech-sdk": "^1.38.0",
|
||||||
|
"moment": "^2.30.1",
|
||||||
|
"openai": "^4.55.1",
|
||||||
|
"pinia": "^2.2.1",
|
||||||
|
"pinia-plugin-persist": "^1.0.0",
|
||||||
|
"plantuml-encoder": "^1.4.0",
|
||||||
|
"roboto-fontface": "*",
|
||||||
|
"unsplash-js": "^7.0.19",
|
||||||
|
"vue": "^3.4.36",
|
||||||
|
"vue-echarts": "^7.0.1",
|
||||||
|
"vue-i18n": "^9.13.1",
|
||||||
|
"vue-router": "^4.4.3",
|
||||||
|
"vue-virtual-scroller": "^2.0.0-beta.8",
|
||||||
|
"vue-waterfall-plugin-next": "^2.4.3",
|
||||||
|
"vue3-apexcharts": "^1.5.3",
|
||||||
|
"vue3-lottie": "^3.3.0",
|
||||||
|
"vue3-perfect-scrollbar": "^2.0.0",
|
||||||
|
"vuedraggable": "^4.1.0",
|
||||||
|
"vuetify": "^3.6.14",
|
||||||
|
"webfontloader": "^1.6.28",
|
||||||
|
"xterm": "^5.3.0",
|
||||||
|
"xterm-addon-attach": "^0.9.0",
|
||||||
|
"xterm-addon-fit": "^0.8.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@faker-js/faker": "^8.4.1",
|
||||||
|
"@fortawesome/fontawesome-free": "^6.6.0",
|
||||||
|
"@iconify/vue": "^4.1.2",
|
||||||
|
"@types/node": "^22.1.0",
|
||||||
|
"@vitejs/plugin-vue": "^5.1.2",
|
||||||
|
"@vitest/ui": "^2.0.5",
|
||||||
|
"@vue/test-utils": "^2.4.6",
|
||||||
|
"autoprefixer": "^10.4.20",
|
||||||
|
"postcss": "^8.4.41",
|
||||||
|
"sass": "^1.77.8",
|
||||||
|
"tailwindcss": "^3.4.8",
|
||||||
|
"unplugin-auto-import": "^0.18.2",
|
||||||
|
"vite": "^5.4.0",
|
||||||
|
"vite-plugin-vuetify": "^2.0.4",
|
||||||
|
"vitest": "^2.0.5"
|
||||||
|
}
|
||||||
|
}
|
6
resources/postcss.config.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
1
resources/public/_redirects
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/* /index.html 200
|
BIN
resources/public/favicon.ico
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
resources/public/favicon.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
51
resources/src/App.vue
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import UILayout from "@/layouts/UILayout.vue";
|
||||||
|
import LandingLayout from "@/layouts/LandingLayout.vue";
|
||||||
|
import DefaultLayout from "@/layouts/DefaultLayout.vue";
|
||||||
|
import AuthLayout from "@/layouts/AuthLayout.vue";
|
||||||
|
|
||||||
|
import Snackbar from "@/components/common/Snackbar.vue";
|
||||||
|
import { useAppStore } from "@/stores/appStore";
|
||||||
|
import { useTheme } from "vuetify";
|
||||||
|
const appStore = useAppStore();
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
|
const isRouterLoaded = computed(() => {
|
||||||
|
if (route.name !== null) return true;
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
const layouts = {
|
||||||
|
default: DefaultLayout,
|
||||||
|
ui: UILayout,
|
||||||
|
landing: LandingLayout,
|
||||||
|
auth: AuthLayout,
|
||||||
|
};
|
||||||
|
|
||||||
|
type LayoutName = "default" | "ui" | "landing" | "auth" | "error";
|
||||||
|
|
||||||
|
const currentLayout = computed(() => {
|
||||||
|
const layoutName = route.meta.layout as LayoutName;
|
||||||
|
if (!layoutName) {
|
||||||
|
return DefaultLayout;
|
||||||
|
}
|
||||||
|
return layouts[layoutName];
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
theme.global.name.value = appStore.theme;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<v-app>
|
||||||
|
<component :is="currentLayout" v-if="isRouterLoaded">
|
||||||
|
<router-view> </router-view>
|
||||||
|
</component>
|
||||||
|
<Snackbar />
|
||||||
|
</v-app>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
67
resources/src/api/aiApi.ts
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
import { useSnackbarStore } from "@/stores/snackbarStore";
|
||||||
|
import { useChatGPTStore } from "@/stores/chatGPTStore";
|
||||||
|
|
||||||
|
const gptInstance = axios.create({
|
||||||
|
timeout: 100000,
|
||||||
|
});
|
||||||
|
|
||||||
|
gptInstance.interceptors.request.use((config) => {
|
||||||
|
const chatGPTStore = useChatGPTStore();
|
||||||
|
config.baseURL = chatGPTStore.proxyUrl;
|
||||||
|
return config;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
gptInstance.interceptors.response.use(
|
||||||
|
(response) => {
|
||||||
|
return response;
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
const snackbarStore = useSnackbarStore();
|
||||||
|
if (error.response) {
|
||||||
|
const status = error.response.status;
|
||||||
|
const data = error.response.data;
|
||||||
|
snackbarStore.showErrorMessage(data.error);
|
||||||
|
} else {
|
||||||
|
snackbarStore.showErrorMessage("Network Error");
|
||||||
|
}
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get all models.
|
||||||
|
export const getModelsApi = (apiKey: string) => {
|
||||||
|
return gptInstance.get("/v1/models", {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer " + apiKey,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get account balance information.
|
||||||
|
export const getBalanceApi = (apiKey: string) => {
|
||||||
|
return gptInstance.get("/dashboard/billing/credit_grants", {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer " + apiKey,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// speech-to-text
|
||||||
|
export const createTranscriptionApi = (formData: any, apiKey: string) => {
|
||||||
|
return gptInstance.post("/v1/audio/transcriptions", formData, {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer " + apiKey,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// completions(Stream UnUsed)
|
||||||
|
export const createCompletionApi = (data: any, apiKey: string) => {
|
||||||
|
return gptInstance.post("/v1/chat/completions", data, {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer " + apiKey,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
102
resources/src/api/api.ts
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
import axios, {
|
||||||
|
AxiosInstance,
|
||||||
|
AxiosError,
|
||||||
|
AxiosRequestConfig,
|
||||||
|
AxiosResponse,
|
||||||
|
} from "axios";
|
||||||
|
import { useSnackbarStore } from "@/stores/snackbarStore";
|
||||||
|
import router from "../router";
|
||||||
|
|
||||||
|
const snackbarStore = useSnackbarStore();
|
||||||
|
|
||||||
|
interface Result {
|
||||||
|
code: number;
|
||||||
|
msg: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 请求响应参数,包含data
|
||||||
|
interface ResultData<T = any> extends Result {
|
||||||
|
data?: T;
|
||||||
|
}
|
||||||
|
const URL: string = "";
|
||||||
|
enum RequestEnums {
|
||||||
|
TIMEOUT = 20000,
|
||||||
|
}
|
||||||
|
const config = {
|
||||||
|
// 默认地址
|
||||||
|
baseURL: URL as string,
|
||||||
|
// 设置超时时间
|
||||||
|
timeout: RequestEnums.TIMEOUT as number,
|
||||||
|
// 跨域时候允许携带凭证
|
||||||
|
withCredentials: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
class RequestHttp {
|
||||||
|
service: AxiosInstance;
|
||||||
|
public constructor(config: AxiosRequestConfig) {
|
||||||
|
// 实例化axios
|
||||||
|
this.service = axios.create(config);
|
||||||
|
|
||||||
|
this.service.interceptors.request.use(
|
||||||
|
(config) => {
|
||||||
|
const token = localStorage.getItem("token") || "";
|
||||||
|
config.headers.Authorization = "bearer " + token;
|
||||||
|
config.url = "/api" + config.url;
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
(error: AxiosError) => {
|
||||||
|
snackbarStore.showErrorMessage(error);
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 响应拦截器
|
||||||
|
* 服务器换返回信息 -> [拦截统一处理] -> 客户端JS获取到信息
|
||||||
|
*/
|
||||||
|
this.service.interceptors.response.use(
|
||||||
|
(response: AxiosResponse) => {
|
||||||
|
const { data } = response; // 解构
|
||||||
|
if (data.code !== 0) {
|
||||||
|
snackbarStore.showErrorMessage(data.message);
|
||||||
|
return Promise.reject(data);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
(error: AxiosError) => {
|
||||||
|
const { response } = error;
|
||||||
|
if (response) {
|
||||||
|
this.handleCode(response.status);
|
||||||
|
}
|
||||||
|
//@ts-ignore
|
||||||
|
snackbarStore.showErrorMessage(response.data.message);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
handleCode(code: number): void {
|
||||||
|
switch (code) {
|
||||||
|
case 401:
|
||||||
|
router.replace("/login");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 常用方法封装
|
||||||
|
get<T>(url: string, params?: object): Promise<ResultData<T>> {
|
||||||
|
return this.service.get(url, { params });
|
||||||
|
}
|
||||||
|
post<T>(url: string, params?: object): Promise<ResultData<T>> {
|
||||||
|
return this.service.post(url, params);
|
||||||
|
}
|
||||||
|
put<T>(url: string, params?: object): Promise<ResultData<T>> {
|
||||||
|
return this.service.put(url, params);
|
||||||
|
}
|
||||||
|
delete<T>(url: string, params?: object): Promise<ResultData<T>> {
|
||||||
|
return this.service.delete(url, { params });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出一个实例对象
|
||||||
|
export default new RequestHttp(config);
|
13
resources/src/api/config.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import api from "./api";
|
||||||
|
|
||||||
|
export function getConfig() {
|
||||||
|
return api.get("/config", undefined).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setConfig(data) {
|
||||||
|
return api.put("/config", data).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function esReload() {
|
||||||
|
return api.put("/config/reload").then((res) => res);
|
||||||
|
}
|
39
resources/src/api/githubApi.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
import { useSnackbarStore } from "@/stores/snackbarStore";
|
||||||
|
const snackbarStore = useSnackbarStore();
|
||||||
|
// change the access key to your own
|
||||||
|
const ACCESS_KEY = import.meta.env.VITE_GITHUB_CLIENT_ID;
|
||||||
|
|
||||||
|
const instance = axios.create({
|
||||||
|
baseURL: "https://api.github.com",
|
||||||
|
timeout: 20000,
|
||||||
|
headers: { Authorization: "Bearer" + " " + ACCESS_KEY },
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.interceptors.response.use(
|
||||||
|
(response) => {
|
||||||
|
return response;
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
if (error.response) {
|
||||||
|
const status = error.response.status;
|
||||||
|
const data = error.response.data;
|
||||||
|
snackbarStore.showErrorMessage(data.message);
|
||||||
|
} else {
|
||||||
|
snackbarStore.showErrorMessage("Network Error");
|
||||||
|
}
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// https://api.github.com/users/yangjiakai/events/public
|
||||||
|
|
||||||
|
// Get public events for a user
|
||||||
|
export const getPublicEventsApi = (username: string) => {
|
||||||
|
return instance.get("/users/" + username + "/events/public");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get public events for a network of repositories
|
||||||
|
export const getPublicEventsForNetworkApi = (username: string) => {
|
||||||
|
return instance.get("/networks/" + username + "/events");
|
||||||
|
};
|
33
resources/src/api/googleApi.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export const textToSpeech = async () => {
|
||||||
|
const googleInstance = axios.create({
|
||||||
|
baseURL: "https://us-central1-texttospeech.googleapis.com",
|
||||||
|
timeout: 100000,
|
||||||
|
});
|
||||||
|
|
||||||
|
const res = await googleInstance.post(
|
||||||
|
"/v1/chat/completions/text:synthesize",
|
||||||
|
{
|
||||||
|
audioConfig: {
|
||||||
|
audioEncoding: "LINEAR16",
|
||||||
|
effectsProfileId: ["small-bluetooth-speaker-class-device"],
|
||||||
|
pitch: 0,
|
||||||
|
speakingRate: 1,
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
text: "Google Cloud Text-to-Speech enables developers to synthesize natural-sounding speech with 100+ voices, available in multiple languages and variants. It applies DeepMind’s groundbreaking research in WaveNet and Google’s powerful neural networks to deliver the highest fidelity possible. As an easy-to-use API, you can create lifelike interactions with your users, across many applications and devices.",
|
||||||
|
},
|
||||||
|
voice: {
|
||||||
|
languageCode: "en-US",
|
||||||
|
name: "en-US-Neural2-J",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"x-goog-api-key": "AIzaSyBSXdkeyAvIZX5n_bj4KsqSjJf1W-_TfCntvk",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
5
resources/src/api/log.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import api from "./api";
|
||||||
|
|
||||||
|
export function getLog(data: any) {
|
||||||
|
return api.post("/log", data).then((res) => res);
|
||||||
|
}
|
12
resources/src/api/login.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import api from "./api";
|
||||||
|
|
||||||
|
interface LoginRes {
|
||||||
|
code: number;
|
||||||
|
token: string;
|
||||||
|
username: string;
|
||||||
|
role: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const login = (query: any) => {
|
||||||
|
return api.post<LoginRes>("/user/login", query).then((res) => res);
|
||||||
|
};
|
50
resources/src/api/process.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { ProcessConfig, ProcessItem } from "../types/process/process";
|
||||||
|
import api from "./api";
|
||||||
|
|
||||||
|
export function getProcessList() {
|
||||||
|
return api.get<ProcessItem[]>("/process", undefined).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getProcessListWait() {
|
||||||
|
return api.get<ProcessItem[]>("/process/wait", undefined).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function killProcessAll() {
|
||||||
|
return api.delete("/process/all", { }).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function startProcessAll() {
|
||||||
|
return api.put("/process/all", { }).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function killProcess(uuid) {
|
||||||
|
return api.delete("/process", { uuid }).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function startProcess(uuid) {
|
||||||
|
return api.put("/process", { uuid }).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getContorl(uuid) {
|
||||||
|
return api.get("/process/control", { uuid }).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getProcessConfig(uuid) {
|
||||||
|
return api.get<ProcessConfig>("/process/config", { uuid }).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteProcessConfig(uuid) {
|
||||||
|
return api.delete("/process/config", { uuid }).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function putProcessConfig(data) {
|
||||||
|
return api.put("/process/config", data).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function postProcessConfig(data) {
|
||||||
|
return api.post("/process/config", data).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createProcessShare(data) {
|
||||||
|
return api.post("/process/share", data).then((res) => res);
|
||||||
|
}
|
22
resources/src/api/push.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { PushItem } from "../types/push/push";
|
||||||
|
import api from "./api";
|
||||||
|
|
||||||
|
export function createPush(data) {
|
||||||
|
return api.post("/push", data).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPushList() {
|
||||||
|
return api.get<PushItem[]>("/push/list", undefined).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deletePush(id) {
|
||||||
|
return api.delete("/push", { id }).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPush(id) {
|
||||||
|
return api.get("/push", { id }).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function editPush(data) {
|
||||||
|
return api.put("/push", data).then((res) => res);
|
||||||
|
}
|
39
resources/src/api/stableDiffusionApi.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// import Axios library
|
||||||
|
import axios from "axios";
|
||||||
|
// Set default validation status for Axios
|
||||||
|
axios.defaults.validateStatus = function (status) {
|
||||||
|
// Return true if status is between 200 and 300 inclusive
|
||||||
|
return status >= 200 && status < 300;
|
||||||
|
};
|
||||||
|
// Create a new Axios instance with base URL and timeout
|
||||||
|
const diffusion = axios.create({
|
||||||
|
baseURL: "/sdApi",
|
||||||
|
// baseURL: 'http://127.0.0.1:7861',
|
||||||
|
timeout: 100000,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加请求拦截器
|
||||||
|
diffusion.interceptors.request.use();
|
||||||
|
|
||||||
|
// 添加响应拦截器
|
||||||
|
diffusion.interceptors.response.use();
|
||||||
|
|
||||||
|
//getmodels
|
||||||
|
|
||||||
|
//txt2img
|
||||||
|
export const txt2imgApi = (data: any) => {
|
||||||
|
return diffusion.post("/sdapi/v1/txt2img", data);
|
||||||
|
};
|
||||||
|
//img2img
|
||||||
|
export const img2imgApi = (data: any) => {
|
||||||
|
return diffusion.post("/sdapi/v1/img2img", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
//getProgeress
|
||||||
|
export const getProgressApi = (data: any) => {
|
||||||
|
return diffusion.get("/sdapi/v1/progress");
|
||||||
|
};
|
||||||
|
//getSamplers
|
||||||
|
export const getSamplersApi = () => {
|
||||||
|
return diffusion.get("/sdapi/v1/samplers");
|
||||||
|
};
|
42
resources/src/api/task.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import { TaskItem } from "../types/tassk/task";
|
||||||
|
import api from "./api";
|
||||||
|
|
||||||
|
export function getTaskAll() {
|
||||||
|
return api.get<TaskItem[]>("/task/all", undefined).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTaskAllWait() {
|
||||||
|
return api.get("/task/all/wait", undefined).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTaskById(id) {
|
||||||
|
return api.get<TaskItem>("/task", { id }).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function startTaskById(id) {
|
||||||
|
return api.get("/task/start", { id }).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function stopTaskById(id) {
|
||||||
|
return api.get("/task/stop", { id }).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function editTaskEnable(body) {
|
||||||
|
return api.put("/task/enable", body).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function editTask(body) {
|
||||||
|
return api.put("/task", body).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addTask(body) {
|
||||||
|
return api.post("/task", body).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteTaskById(id) {
|
||||||
|
return api.delete("/task", { id }).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function changeTaskKey(id) {
|
||||||
|
return api.post("/task/key", { id }).then((res) => res);
|
||||||
|
}
|
160
resources/src/api/unsplashApi.ts
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
import { useSnackbarStore } from "@/stores/snackbarStore";
|
||||||
|
const snackbarStore = useSnackbarStore();
|
||||||
|
// change the access key to your own
|
||||||
|
const ACCESS_KEY = import.meta.env.VITE_UNSPLASH_ACCESS_KEY;
|
||||||
|
|
||||||
|
const instance = axios.create({
|
||||||
|
baseURL: "https://api.unsplash.com",
|
||||||
|
timeout: 20000,
|
||||||
|
headers: { Authorization: "Client-ID" + " " + ACCESS_KEY },
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.interceptors.response.use(
|
||||||
|
(response) => {
|
||||||
|
return response;
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
if (error.response) {
|
||||||
|
const status = error.response.status;
|
||||||
|
const data = error.response.data;
|
||||||
|
snackbarStore.showErrorMessage(data.errors[0]);
|
||||||
|
} else {
|
||||||
|
snackbarStore.showErrorMessage("Network Error");
|
||||||
|
}
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
interface Query {
|
||||||
|
page?: number;
|
||||||
|
per_page?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// List photos 图片一览
|
||||||
|
export const getPhotosApi = (query?: Query) => {
|
||||||
|
return instance.get("/photos/", { params: query });
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get a photo 获取图片信息
|
||||||
|
export const getPhotoApi = (id: string) => {
|
||||||
|
return instance.get("/photos/" + id);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get a random photo 获取一张随机图片
|
||||||
|
export const getRandomPhotoApi = () => {
|
||||||
|
return instance.get("/photos/random");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get a photo’s statistics 获取照片的统计数据
|
||||||
|
export const getPhotoStatisticsApi = (id: string) => {
|
||||||
|
return instance.get("/photos/" + id + "/statistics");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get a photo’s related 获取照片的相关照片
|
||||||
|
export const getPhotoRelatedApi = (id: string) => {
|
||||||
|
return instance.get("/photos/" + id + "/related");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Track a photo download
|
||||||
|
// Update a photo
|
||||||
|
// Like a photo
|
||||||
|
// Unlike a photo
|
||||||
|
|
||||||
|
// Topic
|
||||||
|
// List topics
|
||||||
|
export const getTopicsApi = (query?: Query) => {
|
||||||
|
return instance.get("/topics", { params: query });
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get a topic
|
||||||
|
export const getTopicApi = (id_or_slug: string | string[]) => {
|
||||||
|
return instance.get("/topics/" + id_or_slug);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get a topic’s photos
|
||||||
|
export const getTopicPhotosApi = (
|
||||||
|
id_or_slug: string | string[],
|
||||||
|
query?: Query
|
||||||
|
) => {
|
||||||
|
return instance.get("/topics/" + id_or_slug + "/photos", { params: query });
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get a user
|
||||||
|
export const getUserApi = (username: string | string[]) => {
|
||||||
|
return instance.get("/users/" + username);
|
||||||
|
};
|
||||||
|
// Get a user’s portfolio
|
||||||
|
export const getUserPortfolioApi = (username: string | string[]) => {
|
||||||
|
return instance.get("/users/" + username + "/portfolio");
|
||||||
|
};
|
||||||
|
// List a user’s photos
|
||||||
|
export const getUserPhotosApi = (
|
||||||
|
username: string | string[],
|
||||||
|
query?: Query
|
||||||
|
) => {
|
||||||
|
return instance.get("/users/" + username + "/photos", { params: query });
|
||||||
|
};
|
||||||
|
// List a user’s liked photos
|
||||||
|
export const getUserLikesApi = (username: string | string[], query?: Query) => {
|
||||||
|
return instance.get("/users/" + username + "/likes", { params: query });
|
||||||
|
};
|
||||||
|
// List a user’s collections
|
||||||
|
export const getUserCollectionsApi = (
|
||||||
|
username: string | string[],
|
||||||
|
query?: Query
|
||||||
|
) => {
|
||||||
|
return instance.get("/users/" + username + "/collections", { params: query });
|
||||||
|
};
|
||||||
|
// Get a user’s statistics
|
||||||
|
export const getUserStatisticsApi = (username: string | string[]) => {
|
||||||
|
return instance.get("/users/" + username + "/statistics");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Collections 图集
|
||||||
|
// List collections 图集一览
|
||||||
|
export const getCollectionsApi = (query?: Query) => {
|
||||||
|
return instance.get("/collections", { params: query });
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get a collection 获取图集信息
|
||||||
|
export const getCollectionApi = (id: string | string[]) => {
|
||||||
|
return instance.get("/collections/" + id);
|
||||||
|
};
|
||||||
|
// Get a collection’s photos 获取该图集下所有图片
|
||||||
|
export const getCollectionPhotosApi = (
|
||||||
|
id: string | string[],
|
||||||
|
query?: Query
|
||||||
|
) => {
|
||||||
|
return instance.get("/collections/" + id + "/photos", { params: query });
|
||||||
|
};
|
||||||
|
// List a collection’s related collections 获取该图集相关联图集
|
||||||
|
export const getCollectionRelatedApi = (id: string | string[]) => {
|
||||||
|
return instance.get("/collections/" + id + "/related");
|
||||||
|
};
|
||||||
|
// Create a new collection 新增图集
|
||||||
|
// Update an existing collection 更新现存图集
|
||||||
|
// Delete a collection 删除某个图集
|
||||||
|
// Add a photo to a collection 添加图片到图集
|
||||||
|
// Remove a photo from a collection 从图集删除图片
|
||||||
|
|
||||||
|
// Search
|
||||||
|
// Search All
|
||||||
|
export const searchAllApi = (query?: Query) => {
|
||||||
|
return instance.get("/search", { params: query });
|
||||||
|
};
|
||||||
|
|
||||||
|
// Search photos
|
||||||
|
export const searchPhotosApi = (query?: Query) => {
|
||||||
|
return instance.get("/search/photos", { params: query });
|
||||||
|
};
|
||||||
|
|
||||||
|
// Search collections
|
||||||
|
export const searchCollectionsApi = (query?: Query) => {
|
||||||
|
return instance.get("/search/collections", { params: query });
|
||||||
|
};
|
||||||
|
|
||||||
|
// Search users
|
||||||
|
export const searchUsersApi = (query?: Query) => {
|
||||||
|
return instance.get("/search/users", { params: query });
|
||||||
|
};
|
39
resources/src/api/user.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import api from "./api";
|
||||||
|
|
||||||
|
// 登录方法
|
||||||
|
export function login(data) {
|
||||||
|
return api.post("/user/login", {
|
||||||
|
account: data.account,
|
||||||
|
password: data.password,
|
||||||
|
}).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createUser(data) {
|
||||||
|
return api.post("/user", data).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteUser(account) {
|
||||||
|
return api.delete("/user", { account }).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function changePassword(data) {
|
||||||
|
return api.put("/user/password", data).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function registerAdmin(password) {
|
||||||
|
return api.get("/user/register/admin", { password }).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getUserList() {
|
||||||
|
return api.get("/user", undefined).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPermission(account, pid) {
|
||||||
|
return api.get("/permission/list", { account, pid }).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export function editPermission(data) {
|
||||||
|
return api.put("/permission", data).then((res) => res);
|
||||||
|
}
|
1
resources/src/assets/images/404.svg
Normal file
After Width: | Height: | Size: 17 KiB |
1
resources/src/assets/images/500.svg
Normal file
After Width: | Height: | Size: 41 KiB |
BIN
resources/src/assets/images/avatars/avatar_assistant.jpg
Normal file
After Width: | Height: | Size: 7.5 KiB |
BIN
resources/src/assets/images/avatars/avatar_user.jpg
Normal file
After Width: | Height: | Size: 77 KiB |
BIN
resources/src/assets/images/card2/yoimiya.png
Normal file
After Width: | Height: | Size: 248 KiB |