增加批量导入资产功能
This commit is contained in:
		@ -1,3 +1,4 @@
 | 
			
		||||
debug: true
 | 
			
		||||
db: mysql
 | 
			
		||||
mysql:
 | 
			
		||||
  hostname: 172.16.101.32
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										40
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								main.go
									
									
									
									
									
								
							@ -11,6 +11,7 @@ import (
 | 
			
		||||
	"gorm.io/driver/mysql"
 | 
			
		||||
	"gorm.io/driver/sqlite"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
	"gorm.io/gorm/logger"
 | 
			
		||||
	"io"
 | 
			
		||||
	"next-terminal/pkg/api"
 | 
			
		||||
	"next-terminal/pkg/config"
 | 
			
		||||
@ -24,7 +25,7 @@ import (
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const Version = "v0.3.2"
 | 
			
		||||
const Version = "v0.3.3"
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	err := Run()
 | 
			
		||||
@ -65,6 +66,13 @@ func Run() error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var logMode logger.Interface
 | 
			
		||||
	if global.Config.Debug {
 | 
			
		||||
		logMode = logger.Default.LogMode(logger.Info)
 | 
			
		||||
	} else {
 | 
			
		||||
		logMode = logger.Default.LogMode(logger.Silent)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Printf("当前数据库模式为:%v\n", global.Config.DB)
 | 
			
		||||
	if global.Config.DB == "mysql" {
 | 
			
		||||
		dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
 | 
			
		||||
@ -75,11 +83,11 @@ func Run() error {
 | 
			
		||||
			global.Config.Mysql.Database,
 | 
			
		||||
		)
 | 
			
		||||
		global.DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
 | 
			
		||||
			//Logger: logger.Default.LogMode(logger.Info),
 | 
			
		||||
			Logger: logMode,
 | 
			
		||||
		})
 | 
			
		||||
	} else {
 | 
			
		||||
		global.DB, err = gorm.Open(sqlite.Open(global.Config.Sqlite.File), &gorm.Config{
 | 
			
		||||
			//Logger: logger.Default.LogMode(logger.Info),
 | 
			
		||||
			Logger: logMode,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -196,9 +204,12 @@ func Run() error {
 | 
			
		||||
	global.Cache = cache.New(5*time.Minute, 10*time.Minute)
 | 
			
		||||
	global.Cache.OnEvicted(func(key string, value interface{}) {
 | 
			
		||||
		if strings.HasPrefix(key, api.Token) {
 | 
			
		||||
			token := strings.Split(key, ":")[1]
 | 
			
		||||
			token := api.GetTokenFormCacheKey(key)
 | 
			
		||||
			logrus.Debugf("用户Token「%v」过期", token)
 | 
			
		||||
			model.Logout(token)
 | 
			
		||||
			err := model.Logout(token)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				logrus.Errorf("退出登录失败 %v", err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	global.Store = global.NewStore()
 | 
			
		||||
@ -256,7 +267,7 @@ func Run() error {
 | 
			
		||||
			User:     user,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		cacheKey := strings.Join([]string{api.Token, token}, ":")
 | 
			
		||||
		cacheKey := api.BuildCacheKeyByToken(token)
 | 
			
		||||
 | 
			
		||||
		if authorization.Remember {
 | 
			
		||||
			// 记住登录有效期两周
 | 
			
		||||
@ -267,6 +278,23 @@ func Run() error {
 | 
			
		||||
		logrus.Debugf("重新加载用户「%v」授权Token「%v」到缓存", user.Nickname, token)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 修正用户登录状态
 | 
			
		||||
	onlineUsers, err := model.FindOnlineUsers()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	for i := range onlineUsers {
 | 
			
		||||
		logs, err := model.FindAliveLoginLogsByUserId(onlineUsers[i].ID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if len(logs) == 0 {
 | 
			
		||||
			if err := model.UpdateUserOnline(false, onlineUsers[i].ID); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	e := api.SetupRoutes()
 | 
			
		||||
	if err := handle.InitProperties(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
 | 
			
		||||
@ -91,7 +91,7 @@ func LoginSuccess(c echo.Context, loginAccount LoginAccount, user model.User) (t
 | 
			
		||||
		User:     user,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cacheKey := strings.Join([]string{Token, token}, ":")
 | 
			
		||||
	cacheKey := BuildCacheKeyByToken(token)
 | 
			
		||||
 | 
			
		||||
	if authorization.Remember {
 | 
			
		||||
		// 记住登录有效期两周
 | 
			
		||||
@ -119,6 +119,16 @@ func LoginSuccess(c echo.Context, loginAccount LoginAccount, user model.User) (t
 | 
			
		||||
	return token, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func BuildCacheKeyByToken(token string) string {
 | 
			
		||||
	cacheKey := strings.Join([]string{Token, token}, ":")
 | 
			
		||||
	return cacheKey
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetTokenFormCacheKey(cacheKey string) string {
 | 
			
		||||
	token := strings.Split(cacheKey, ":")[1]
 | 
			
		||||
	return token
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func loginWithTotpEndpoint(c echo.Context) error {
 | 
			
		||||
	var loginAccount LoginAccount
 | 
			
		||||
	if err := c.Bind(&loginAccount); err != nil {
 | 
			
		||||
@ -165,7 +175,7 @@ func loginWithTotpEndpoint(c echo.Context) error {
 | 
			
		||||
 | 
			
		||||
func LogoutEndpoint(c echo.Context) error {
 | 
			
		||||
	token := GetToken(c)
 | 
			
		||||
	cacheKey := strings.Join([]string{Token, token}, ":")
 | 
			
		||||
	cacheKey := BuildCacheKeyByToken(token)
 | 
			
		||||
	global.Cache.Delete(cacheKey)
 | 
			
		||||
	model.Logout(token)
 | 
			
		||||
	return Success(c, nil)
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,8 @@
 | 
			
		||||
package api
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"encoding/csv"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"github.com/labstack/echo/v4"
 | 
			
		||||
@ -44,6 +46,77 @@ func AssetCreateEndpoint(c echo.Context) error {
 | 
			
		||||
	return Success(c, item)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func AssetImportEndpoint(c echo.Context) error {
 | 
			
		||||
	account, _ := GetCurrentAccount(c)
 | 
			
		||||
 | 
			
		||||
	file, err := c.FormFile("file")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	src, err := file.Open()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defer src.Close()
 | 
			
		||||
	reader := csv.NewReader(bufio.NewReader(src))
 | 
			
		||||
	records, err := reader.ReadAll()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	total := len(records)
 | 
			
		||||
	if total == 0 {
 | 
			
		||||
		return errors.New("csv数据为空")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var successCount = 0
 | 
			
		||||
	var errorCount = 0
 | 
			
		||||
	m := echo.Map{}
 | 
			
		||||
 | 
			
		||||
	for i := 0; i < total; i++ {
 | 
			
		||||
		record := records[i]
 | 
			
		||||
		if len(record) >= 9 {
 | 
			
		||||
			port, _ := strconv.Atoi(record[3])
 | 
			
		||||
			asset := model.Asset{
 | 
			
		||||
				ID:          utils.UUID(),
 | 
			
		||||
				Name:        record[0],
 | 
			
		||||
				Protocol:    record[1],
 | 
			
		||||
				IP:          record[2],
 | 
			
		||||
				Port:        port,
 | 
			
		||||
				AccountType: model.Custom,
 | 
			
		||||
				Username:    record[4],
 | 
			
		||||
				Password:    record[5],
 | 
			
		||||
				PrivateKey:  record[6],
 | 
			
		||||
				Passphrase:  record[7],
 | 
			
		||||
				Description: record[8],
 | 
			
		||||
				Created:     utils.NowJsonTime(),
 | 
			
		||||
				Owner:       account.ID,
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			err := model.CreateNewAsset(&asset)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				errorCount++
 | 
			
		||||
				m[strconv.Itoa(i)] = err.Error()
 | 
			
		||||
			} else {
 | 
			
		||||
				successCount++
 | 
			
		||||
				// 创建后自动检测资产是否存活
 | 
			
		||||
				go func() {
 | 
			
		||||
					active := utils.Tcping(asset.IP, asset.Port)
 | 
			
		||||
					model.UpdateAssetActiveById(active, asset.ID)
 | 
			
		||||
				}()
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Success(c, echo.Map{
 | 
			
		||||
		"successCount": successCount,
 | 
			
		||||
		"errorCount":   errorCount,
 | 
			
		||||
		"data":         m,
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func AssetPagingEndpoint(c echo.Context) error {
 | 
			
		||||
	pageIndex, _ := strconv.Atoi(c.QueryParam("pageIndex"))
 | 
			
		||||
	pageSize, _ := strconv.Atoi(c.QueryParam("pageSize"))
 | 
			
		||||
@ -134,6 +207,10 @@ func AssetUpdateEndpoint(c echo.Context) error {
 | 
			
		||||
func AssetGetAttributeEndpoint(c echo.Context) error {
 | 
			
		||||
 | 
			
		||||
	assetId := c.Param("id")
 | 
			
		||||
	if err := PreCheckAssetPermission(c, assetId); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	attributeMap, err := model.FindAssetAttrMapByAssetId(assetId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
@ -177,6 +254,9 @@ func AssetDeleteEndpoint(c echo.Context) error {
 | 
			
		||||
 | 
			
		||||
func AssetGetEndpoint(c echo.Context) (err error) {
 | 
			
		||||
	id := c.Param("id")
 | 
			
		||||
	if err := PreCheckAssetPermission(c, id); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var item model.Asset
 | 
			
		||||
	if item, err = model.FindAssetById(id); err != nil {
 | 
			
		||||
 | 
			
		||||
@ -84,6 +84,11 @@ func CommandDeleteEndpoint(c echo.Context) error {
 | 
			
		||||
 | 
			
		||||
func CommandGetEndpoint(c echo.Context) (err error) {
 | 
			
		||||
	id := c.Param("id")
 | 
			
		||||
 | 
			
		||||
	if err := PreCheckCommandPermission(c, id); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var item model.Command
 | 
			
		||||
	if item, err = model.FindCommandById(id); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
 | 
			
		||||
@ -140,6 +140,9 @@ func CredentialDeleteEndpoint(c echo.Context) error {
 | 
			
		||||
 | 
			
		||||
func CredentialGetEndpoint(c echo.Context) error {
 | 
			
		||||
	id := c.Param("id")
 | 
			
		||||
	if err := PreCheckCredentialPermission(c, id); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	item, err := model.FindCredentialById(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
 | 
			
		||||
@ -55,7 +55,7 @@ func Auth(next echo.HandlerFunc) echo.HandlerFunc {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		token := GetToken(c)
 | 
			
		||||
		cacheKey := strings.Join([]string{Token, token}, ":")
 | 
			
		||||
		cacheKey := BuildCacheKeyByToken(token)
 | 
			
		||||
		authorization, found := global.Cache.Get(cacheKey)
 | 
			
		||||
		if !found {
 | 
			
		||||
			return Fail(c, 401, "您的登录信息已失效,请重新登录后再试。")
 | 
			
		||||
@ -63,9 +63,9 @@ func Auth(next echo.HandlerFunc) echo.HandlerFunc {
 | 
			
		||||
 | 
			
		||||
		if authorization.(Authorization).Remember {
 | 
			
		||||
			// 记住登录有效期两周
 | 
			
		||||
			global.Cache.Set(token, authorization, time.Hour*time.Duration(24*14))
 | 
			
		||||
			global.Cache.Set(cacheKey, authorization, time.Hour*time.Duration(24*14))
 | 
			
		||||
		} else {
 | 
			
		||||
			global.Cache.Set(token, authorization, time.Hour*time.Duration(2))
 | 
			
		||||
			global.Cache.Set(cacheKey, authorization, time.Hour*time.Duration(2))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return next(c)
 | 
			
		||||
 | 
			
		||||
@ -71,10 +71,11 @@ func SetupRoutes() *echo.Echo {
 | 
			
		||||
		//userGroups.DELETE("/:id/members/:memberId", UserGroupDelMembersEndpoint)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	assets := e.Group("/assets", Auth)
 | 
			
		||||
	assets := e.Group("/assets")
 | 
			
		||||
	{
 | 
			
		||||
		assets.GET("", AssetAllEndpoint)
 | 
			
		||||
		assets.POST("", AssetCreateEndpoint)
 | 
			
		||||
		assets.POST("/import", Admin(AssetImportEndpoint))
 | 
			
		||||
		assets.GET("/paging", AssetPagingEndpoint)
 | 
			
		||||
		assets.POST("/:id/tcping", AssetTcpingEndpoint)
 | 
			
		||||
		assets.PUT("/:id", AssetUpdateEndpoint)
 | 
			
		||||
@ -110,7 +111,7 @@ func SetupRoutes() *echo.Echo {
 | 
			
		||||
	sessions := e.Group("/sessions")
 | 
			
		||||
	{
 | 
			
		||||
		sessions.POST("", SessionCreateEndpoint)
 | 
			
		||||
		sessions.GET("/paging", SessionPagingEndpoint)
 | 
			
		||||
		sessions.GET("/paging", Admin(SessionPagingEndpoint))
 | 
			
		||||
		sessions.POST("/:id/connect", SessionConnectEndpoint)
 | 
			
		||||
		sessions.POST("/:id/disconnect", Admin(SessionDisconnectEndpoint))
 | 
			
		||||
		sessions.POST("/:id/resize", SessionResizeEndpoint)
 | 
			
		||||
@ -138,7 +139,7 @@ func SetupRoutes() *echo.Echo {
 | 
			
		||||
		loginLogs.DELETE("/:id", LoginLogDeleteEndpoint)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	e.GET("/properties", PropertyGetEndpoint)
 | 
			
		||||
	e.GET("/properties", Admin(PropertyGetEndpoint))
 | 
			
		||||
	e.PUT("/properties", Admin(PropertyUpdateEndpoint))
 | 
			
		||||
 | 
			
		||||
	e.GET("/overview/counter", OverviewCounterEndPoint)
 | 
			
		||||
@ -202,7 +203,8 @@ func GetToken(c echo.Context) string {
 | 
			
		||||
 | 
			
		||||
func GetCurrentAccount(c echo.Context) (model.User, bool) {
 | 
			
		||||
	token := GetToken(c)
 | 
			
		||||
	get, b := global.Cache.Get(token)
 | 
			
		||||
	cacheKey := BuildCacheKeyByToken(token)
 | 
			
		||||
	get, b := global.Cache.Get(cacheKey)
 | 
			
		||||
	if b {
 | 
			
		||||
		return get.(Authorization).User, true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -8,6 +8,7 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Config struct {
 | 
			
		||||
	Debug         bool
 | 
			
		||||
	DB            string
 | 
			
		||||
	Server        *Server
 | 
			
		||||
	Mysql         *Mysql
 | 
			
		||||
@ -78,6 +79,7 @@ func SetupConfig() (*Config, error) {
 | 
			
		||||
			Key:  viper.GetString("server.key"),
 | 
			
		||||
		},
 | 
			
		||||
		ResetPassword: viper.GetString("reset-password"),
 | 
			
		||||
		Debug:         viper.GetBool("debug"),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return config, nil
 | 
			
		||||
 | 
			
		||||
@ -9,8 +9,8 @@ import (
 | 
			
		||||
type Asset struct {
 | 
			
		||||
	ID           string         `gorm:"primary_key " json:"id"`
 | 
			
		||||
	Name         string         `json:"name"`
 | 
			
		||||
	IP           string         `json:"ip"`
 | 
			
		||||
	Protocol     string         `json:"protocol"`
 | 
			
		||||
	IP           string         `json:"ip"`
 | 
			
		||||
	Port         int            `json:"port"`
 | 
			
		||||
	AccountType  string         `json:"accountType"`
 | 
			
		||||
	Username     string         `json:"username"`
 | 
			
		||||
 | 
			
		||||
@ -81,7 +81,7 @@ func FindLoginLogById(id string) (o LoginLog, err error) {
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Logout(token string) {
 | 
			
		||||
func Logout(token string) (err error) {
 | 
			
		||||
 | 
			
		||||
	loginLog, err := FindLoginLogById(token)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@ -89,7 +89,10 @@ func Logout(token string) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	global.DB.Table("login_logs").Where("id = ?", token).Update("logout_time", utils.NowJsonTime())
 | 
			
		||||
	err = global.DB.Updates(&LoginLog{LogoutTime: utils.NowJsonTime(), ID: token}).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	loginLogs, err := FindAliveLoginLogsByUserId(loginLog.UserId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@ -97,6 +100,7 @@ func Logout(token string) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(loginLogs) == 0 {
 | 
			
		||||
		UpdateUserById(&User{Online: false}, loginLog.UserId)
 | 
			
		||||
		err = UpdateUserOnline(false, loginLog.UserId)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -129,6 +129,17 @@ func UpdateUserById(o *User, id string) {
 | 
			
		||||
	global.DB.Updates(o)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func UpdateUserOnline(online bool, id string) (err error) {
 | 
			
		||||
	sql := "update users set online = ? where id = ?"
 | 
			
		||||
	err = global.DB.Exec(sql, online, id).Error
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func FindOnlineUsers() (o []User, err error) {
 | 
			
		||||
	err = global.DB.Where("online = ?", true).Find(&o).Error
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func DeleteUserById(id string) {
 | 
			
		||||
	global.DB.Where("id = ?", id).Delete(&User{})
 | 
			
		||||
	// 删除用户组中的用户关系
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								sample.csv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								sample.csv
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
测试阿里云,ssh,10.1.1.2,22,username,password,privateKey,passphrase,description
 | 
			
		||||
		
		
			
  | 
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "next-terminal",
 | 
			
		||||
  "version": "0.3.2",
 | 
			
		||||
  "version": "0.3.3-beta",
 | 
			
		||||
  "private": true,
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@ant-design/icons": "^4.3.0",
 | 
			
		||||
 | 
			
		||||
@ -2,5 +2,6 @@ export const PROTOCOL_COLORS = {
 | 
			
		||||
    'rdp': 'cyan',
 | 
			
		||||
    'ssh': 'blue',
 | 
			
		||||
    'telnet': 'geekblue',
 | 
			
		||||
    'vnc': 'purple'
 | 
			
		||||
    'vnc': 'purple',
 | 
			
		||||
    'kubernetes': 'volcano'
 | 
			
		||||
}
 | 
			
		||||
@ -12,6 +12,7 @@ import {
 | 
			
		||||
    Layout,
 | 
			
		||||
    Menu,
 | 
			
		||||
    Modal,
 | 
			
		||||
    notification,
 | 
			
		||||
    PageHeader,
 | 
			
		||||
    Row,
 | 
			
		||||
    Select,
 | 
			
		||||
@ -26,19 +27,24 @@ import qs from "qs";
 | 
			
		||||
import AssetModal from "./AssetModal";
 | 
			
		||||
import request from "../../common/request";
 | 
			
		||||
import {message} from "antd/es";
 | 
			
		||||
import {isEmpty, itemRender} from "../../utils/utils";
 | 
			
		||||
import {getHeaders, isEmpty, itemRender} from "../../utils/utils";
 | 
			
		||||
import dayjs from 'dayjs';
 | 
			
		||||
import {
 | 
			
		||||
    DeleteOutlined,
 | 
			
		||||
    DownOutlined,
 | 
			
		||||
    ExclamationCircleOutlined,
 | 
			
		||||
    ImportOutlined,
 | 
			
		||||
    PlusOutlined,
 | 
			
		||||
    SyncOutlined,
 | 
			
		||||
    UndoOutlined
 | 
			
		||||
    UndoOutlined,
 | 
			
		||||
    UploadOutlined
 | 
			
		||||
} from '@ant-design/icons';
 | 
			
		||||
import {PROTOCOL_COLORS} from "../../common/constants";
 | 
			
		||||
import Logout from "../user/Logout";
 | 
			
		||||
import {hasPermission, isAdmin} from "../../service/permission";
 | 
			
		||||
import Upload from "antd/es/upload";
 | 
			
		||||
import axios from "axios";
 | 
			
		||||
import {server} from "../../common/env";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const confirm = Modal.confirm;
 | 
			
		||||
@ -88,6 +94,9 @@ class Asset extends Component {
 | 
			
		||||
        users: [],
 | 
			
		||||
        selected: {},
 | 
			
		||||
        selectedSharers: [],
 | 
			
		||||
        importModalVisible: false,
 | 
			
		||||
        fileList: [],
 | 
			
		||||
        uploading: false,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    async componentDidMount() {
 | 
			
		||||
@ -726,6 +735,20 @@ class Asset extends Component {
 | 
			
		||||
 | 
			
		||||
                                    <Divider type="vertical"/>
 | 
			
		||||
 | 
			
		||||
                                    {isAdmin() ?
 | 
			
		||||
                                        <Tooltip title="批量导入">
 | 
			
		||||
                                            <Button type="dashed" icon={<ImportOutlined/>}
 | 
			
		||||
                                                    onClick={() => {
 | 
			
		||||
                                                        this.setState({
 | 
			
		||||
                                                            importModalVisible: true
 | 
			
		||||
                                                        })
 | 
			
		||||
                                                    }}>
 | 
			
		||||
 | 
			
		||||
                                            </Button>
 | 
			
		||||
                                        </Tooltip> : undefined
 | 
			
		||||
                                    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                                    <Tooltip title="新增">
 | 
			
		||||
                                        <Button type="dashed" icon={<PlusOutlined/>}
 | 
			
		||||
                                                onClick={() => this.showModal('新增资产', {})}>
 | 
			
		||||
@ -803,6 +826,85 @@ class Asset extends Component {
 | 
			
		||||
                            : null
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    {
 | 
			
		||||
                        this.state.importModalVisible ?
 | 
			
		||||
                            <Modal title="资产导入" visible={true}
 | 
			
		||||
                                   onOk={() => {
 | 
			
		||||
                                       const formData = new FormData();
 | 
			
		||||
                                       formData.append("file", this.state.fileList[0]);
 | 
			
		||||
 | 
			
		||||
                                       let headers = getHeaders();
 | 
			
		||||
                                       headers['Content-Type'] = 'multipart/form-data';
 | 
			
		||||
 | 
			
		||||
                                       axios
 | 
			
		||||
                                           .post(server + "/assets/import", formData, {
 | 
			
		||||
                                               headers: headers
 | 
			
		||||
                                           })
 | 
			
		||||
                                           .then((resp) => {
 | 
			
		||||
                                               console.log("上传成功", resp);
 | 
			
		||||
                                               this.setState({
 | 
			
		||||
                                                   importModalVisible: false
 | 
			
		||||
                                               })
 | 
			
		||||
                                               let result = resp.data;
 | 
			
		||||
                                               if (result['code'] === 1) {
 | 
			
		||||
                                                   let data = result['data'];
 | 
			
		||||
                                                   let successCount = data['successCount'];
 | 
			
		||||
                                                   let errorCount = data['errorCount'];
 | 
			
		||||
                                                   if (errorCount === 0) {
 | 
			
		||||
                                                       notification['success']({
 | 
			
		||||
                                                           message: '导入资产成功',
 | 
			
		||||
                                                           description: '共导入成功' + successCount + '条资产。',
 | 
			
		||||
                                                       });
 | 
			
		||||
                                                   } else {
 | 
			
		||||
                                                       notification['info']({
 | 
			
		||||
                                                           message: '导入资产完成',
 | 
			
		||||
                                                           description: `共导入成功${successCount}条资产,失败${errorCount}条资产。`,
 | 
			
		||||
                                                       });
 | 
			
		||||
                                                   }
 | 
			
		||||
                                               } else {
 | 
			
		||||
                                                   notification['error']({
 | 
			
		||||
                                                       message: '导入资产失败',
 | 
			
		||||
                                                       description: result['message'],
 | 
			
		||||
                                                   });
 | 
			
		||||
                                               }
 | 
			
		||||
                                               this.loadTableData();
 | 
			
		||||
                                           });
 | 
			
		||||
                                   }}
 | 
			
		||||
                                   onCancel={() => {
 | 
			
		||||
                                       this.setState({
 | 
			
		||||
                                           importModalVisible: false
 | 
			
		||||
                                       })
 | 
			
		||||
                                   }}
 | 
			
		||||
                                   okButtonProps={{
 | 
			
		||||
                                       disabled: this.state.fileList.length === 0
 | 
			
		||||
                                   }}
 | 
			
		||||
                            >
 | 
			
		||||
                                <Upload
 | 
			
		||||
                                    maxCount={1}
 | 
			
		||||
                                    onRemove={file => {
 | 
			
		||||
                                        this.setState(state => {
 | 
			
		||||
                                            const index = state.fileList.indexOf(file);
 | 
			
		||||
                                            const newFileList = state.fileList.slice();
 | 
			
		||||
                                            newFileList.splice(index, 1);
 | 
			
		||||
                                            return {
 | 
			
		||||
                                                fileList: newFileList,
 | 
			
		||||
                                            };
 | 
			
		||||
                                        });
 | 
			
		||||
                                    }}
 | 
			
		||||
                                    beforeUpload={(file) => {
 | 
			
		||||
                                        this.setState(state => ({
 | 
			
		||||
                                            fileList: [file],
 | 
			
		||||
                                        }));
 | 
			
		||||
                                        return false;
 | 
			
		||||
                                    }}
 | 
			
		||||
                                    fileList={this.state.fileList}
 | 
			
		||||
                                >
 | 
			
		||||
                                    <Button icon={<UploadOutlined/>}>选择csv文件</Button>
 | 
			
		||||
                                </Upload>
 | 
			
		||||
                            </Modal>
 | 
			
		||||
                            : undefined
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    <Modal title={<Text>更换资源「<strong style={{color: '#1890ff'}}>{this.state.selected['name']}</strong>」的所有者
 | 
			
		||||
                    </Text>}
 | 
			
		||||
                           visible={this.state.changeOwnerModalVisible}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user