diff --git a/pkg/api/asset.go b/pkg/api/asset.go index 8c90f1b..5b2de68 100644 --- a/pkg/api/asset.go +++ b/pkg/api/asset.go @@ -1,6 +1,7 @@ package api import ( + "encoding/json" "errors" "github.com/labstack/echo/v4" "next-terminal/pkg/model" @@ -68,10 +69,17 @@ func AssetUpdateEndpoint(c echo.Context) error { return err } - var item model.Asset - if err := c.Bind(&item); err != nil { + m := echo.Map{} + if err := c.Bind(&m); err != nil { return err } + + data, _ := json.Marshal(m) + var item model.Asset + if err := json.Unmarshal(data, &item); err != nil { + return err + } + switch item.AccountType { case "credential": item.Username = "-" @@ -102,6 +110,9 @@ func AssetUpdateEndpoint(c echo.Context) error { } model.UpdateAssetById(&item, id) + if err := model.UpdateAssetAttributes(id, item.Protocol, m); err != nil { + return err + } return Success(c, nil) } @@ -151,8 +162,16 @@ func AssetGetEndpoint(c echo.Context) (err error) { if item, err = model.FindAssetById(id); err != nil { return err } + attributeMap, err := model.FindAssetAttrMapByAssetId(id) + if err != nil { + return err + } + itemMap := utils.StructToMap(item) + for key := range attributeMap { + itemMap[key] = attributeMap[key] + } - return Success(c, item) + return Success(c, itemMap) } func AssetTcpingEndpoint(c echo.Context) (err error) { diff --git a/pkg/api/property.go b/pkg/api/property.go index 4a0916f..a7bfaba 100644 --- a/pkg/api/property.go +++ b/pkg/api/property.go @@ -1,8 +1,10 @@ package api import ( + "errors" "fmt" "github.com/labstack/echo/v4" + "gorm.io/gorm" "next-terminal/pkg/model" ) @@ -19,11 +21,23 @@ func PropertyUpdateEndpoint(c echo.Context) error { for key := range item { value := fmt.Sprintf("%v", item[key]) + if value == "" { + value = "-" + } + property := model.Property{ Name: key, Value: value, } - model.UpdatePropertyByName(&property, key) + + _, err := model.FindPropertyByName(key) + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + if err := model.CreateNewProperty(&property); err != nil { + return err + } + } else { + model.UpdatePropertyByName(&property, key) + } } return Success(c, nil) } diff --git a/pkg/api/routes.go b/pkg/api/routes.go index 7a6f54d..1936864 100644 --- a/pkg/api/routes.go +++ b/pkg/api/routes.go @@ -74,8 +74,6 @@ func SetupRoutes() *echo.Echo { assets.GET("/paging", AssetPagingEndpoint) assets.POST("/:id/tcping", AssetTcpingEndpoint) assets.PUT("/:id", AssetUpdateEndpoint) - assets.GET("/:id/attributes", AssetGetAttributeEndpoint) - assets.PUT("/:id/attributes", AssetUpdateAttributeEndpoint) assets.DELETE("/:id", AssetDeleteEndpoint) assets.GET("/:id", AssetGetEndpoint) assets.POST("/:id/change-owner", Admin(AssetChangeOwnerEndpoint)) diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 930b842..22fb258 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -11,6 +11,7 @@ import ( "net" "os" "path/filepath" + "reflect" "sort" "strconv" "strings" @@ -157,3 +158,27 @@ func Contains(s []string, str string) bool { } return false } + +func StructToMap(obj interface{}) map[string]interface{} { + t := reflect.TypeOf(obj) + v := reflect.ValueOf(obj) + if t.Kind() == reflect.Ptr { + // 如果是指针,则获取其所指向的元素 + t = t.Elem() + v = v.Elem() + } + + var data = make(map[string]interface{}) + if t.Kind() == reflect.Struct { + // 只有结构体可以获取其字段信息 + for i := 0; i < t.NumField(); i++ { + jsonName := t.Field(i).Tag.Get("json") + if jsonName != "" { + data[jsonName] = v.Field(i).Interface() + } else { + data[t.Field(i).Name] = v.Field(i).Interface() + } + } + } + return data +} diff --git a/web/src/components/asset/Asset.js b/web/src/components/asset/Asset.js index 707db36..0735a20 100644 --- a/web/src/components/asset/Asset.js +++ b/web/src/components/asset/Asset.js @@ -40,10 +40,6 @@ import { import {PROTOCOL_COLORS} from "../../common/constants"; import Logout from "../user/Logout"; import {hasPermission, isAdmin} from "../../service/permission"; -import AssetSSHAttributeModal from "./AssetSSHAttributeModal"; -import AssetRDPAttributeModal from "./AssetRDPAttributeModal"; -import AssetVNCAttributeModal from "./AssetVNCAttributeModal"; -import AssetTelnetAttributeModal from "./AssetTelnetAttributeModal"; const confirm = Modal.confirm; const {Search} = Input; @@ -89,8 +85,6 @@ class Asset extends Component { users: [], selected: {}, selectedSharers: [], - attrVisible: false, - attributes: {} }; async componentDidMount() { @@ -230,34 +224,6 @@ class Asset extends Component { await this.showModal('复制资产', result.data); } - async attr(record) { - let result = await request.get(`/assets/${record['id']}/attributes`); - if (result.code !== 1) { - message.error(result.message, 10); - return; - } - - // eslint-disable-next-line no-extend-native - String.prototype.bool = function () { - return (/^true$/i).test(this); - }; - - let attributes = result['data']; - for (const key in attributes) { - if (!attributes.hasOwnProperty(key)) { - continue; - } - if (key === 'swap-red-blue') { - attributes[key] = attributes[key].bool(); - } - } - this.setState({ - selected: record, - attrVisible: true, - attributes: attributes - }); - } - async showModal(title, asset = {}) { // 并行请求 let getCredentials = request.get('/credentials'); @@ -447,30 +413,6 @@ class Asset extends Component { }) } - handleUpdateAttr = async (formData) => { - // 弹窗 form 传来的数据 - this.setState({ - modalConfirmLoading: true - }); - - try { - let selected = this.state.selected; - let result = await request.put(`/assets/${selected['id']}/attributes?protocol=${selected['protocol']}`, formData); - if (result['code'] !== 1) { - message.error(result['message'], 10); - } else { - message.success('操作成功'); - this.setState({ - attrVisible: false - }) - } - } finally { - this.setState({ - modalConfirmLoading: false - }); - } - } - handleCancelUpdateAttr = () => { this.setState({ attrVisible: false, @@ -550,12 +492,6 @@ class Asset extends Component { onClick={() => this.copy(record.id)}>复制 - - - - {isAdmin() ?