完成资产隔离
This commit is contained in:
parent
a0610b8ce0
commit
28d17accd2
@ -33,9 +33,11 @@ func AssetPagingEndpoint(c echo.Context) error {
|
|||||||
name := c.QueryParam("name")
|
name := c.QueryParam("name")
|
||||||
protocol := c.QueryParam("protocol")
|
protocol := c.QueryParam("protocol")
|
||||||
tags := c.QueryParam("tags")
|
tags := c.QueryParam("tags")
|
||||||
|
owner := c.QueryParam("owner")
|
||||||
|
sharer := c.QueryParam("sharer")
|
||||||
|
|
||||||
account, _ := GetCurrentAccount(c)
|
account, _ := GetCurrentAccount(c)
|
||||||
items, total, _ := model.FindPageAsset(pageIndex, pageSize, name, protocol, tags, account)
|
items, total, _ := model.FindPageAsset(pageIndex, pageSize, name, protocol, tags, account, owner, sharer)
|
||||||
|
|
||||||
return Success(c, H{
|
return Success(c, H{
|
||||||
"total": total,
|
"total": total,
|
||||||
|
@ -6,6 +6,12 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type RU struct {
|
||||||
|
UserId string `json:"userId"`
|
||||||
|
ResourceType string `json:"resourceType"`
|
||||||
|
ResourceIds []string `json:"resourceIds"`
|
||||||
|
}
|
||||||
|
|
||||||
func ResourceGetAssignEndPoint(c echo.Context) error {
|
func ResourceGetAssignEndPoint(c echo.Context) error {
|
||||||
resourceId := c.Param("id")
|
resourceId := c.Param("id")
|
||||||
userIds, err := model.FindUserIdsByResourceId(resourceId)
|
userIds, err := model.FindUserIdsByResourceId(resourceId)
|
||||||
@ -25,3 +31,29 @@ func ResourceOverwriteAssignEndPoint(c echo.Context) error {
|
|||||||
|
|
||||||
return Success(c, "")
|
return Success(c, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ResourceRemoveByUserIdAssignEndPoint(c echo.Context) error {
|
||||||
|
var ru RU
|
||||||
|
if err := c.Bind(&ru); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := model.DeleteByUserIdAndResourceTypeAndResourceIdIn(ru.UserId, ru.ResourceType, ru.ResourceIds); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return Success(c, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ResourceAddByUserIdAssignEndPoint(c echo.Context) error {
|
||||||
|
var ru RU
|
||||||
|
if err := c.Bind(&ru); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := model.AddSharerResources(ru.UserId, ru.ResourceType, ru.ResourceIds); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return Success(c, "")
|
||||||
|
}
|
||||||
|
@ -58,8 +58,8 @@ func SetupRoutes() *echo.Echo {
|
|||||||
userGroups.PUT("/:id", UserGroupUpdateEndpoint)
|
userGroups.PUT("/:id", UserGroupUpdateEndpoint)
|
||||||
userGroups.DELETE("/:id", UserGroupDeleteEndpoint)
|
userGroups.DELETE("/:id", UserGroupDeleteEndpoint)
|
||||||
userGroups.GET("/:id", UserGroupGetEndpoint)
|
userGroups.GET("/:id", UserGroupGetEndpoint)
|
||||||
userGroups.POST("/:id/members", UserGroupAddMembersEndpoint)
|
//userGroups.POST("/:id/members", UserGroupAddMembersEndpoint)
|
||||||
userGroups.DELETE("/:id/members/:memberId", UserGroupDelMembersEndpoint)
|
//userGroups.DELETE("/:id/members/:memberId", UserGroupDelMembersEndpoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
assets := e.Group("/assets", Auth)
|
assets := e.Group("/assets", Auth)
|
||||||
@ -119,6 +119,8 @@ func SetupRoutes() *echo.Echo {
|
|||||||
{
|
{
|
||||||
resources.GET("/:id/assign", ResourceGetAssignEndPoint)
|
resources.GET("/:id/assign", ResourceGetAssignEndPoint)
|
||||||
resources.POST("/:id/assign", ResourceOverwriteAssignEndPoint)
|
resources.POST("/:id/assign", ResourceOverwriteAssignEndPoint)
|
||||||
|
resources.POST("/remove", ResourceRemoveByUserIdAssignEndPoint)
|
||||||
|
resources.POST("/add", ResourceAddByUserIdAssignEndPoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
e.GET("/properties", PropertyGetEndpoint)
|
e.GET("/properties", PropertyGetEndpoint)
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type UserGroup struct {
|
type UserGroup struct {
|
||||||
|
Id string `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Members []string `json:"members"`
|
Members []string `json:"members"`
|
||||||
}
|
}
|
||||||
@ -52,12 +53,17 @@ func UserGroupPagingEndpoint(c echo.Context) error {
|
|||||||
func UserGroupUpdateEndpoint(c echo.Context) error {
|
func UserGroupUpdateEndpoint(c echo.Context) error {
|
||||||
id := c.Param("id")
|
id := c.Param("id")
|
||||||
|
|
||||||
var item model.UserGroup
|
var item UserGroup
|
||||||
if err := c.Bind(&item); err != nil {
|
if err := c.Bind(&item); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
userGroup := model.UserGroup{
|
||||||
|
Name: item.Name,
|
||||||
|
}
|
||||||
|
|
||||||
model.UpdateUserGroupById(&item, id)
|
if err := model.UpdateUserGroupById(&userGroup, item.Members, id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return Success(c, nil)
|
return Success(c, nil)
|
||||||
}
|
}
|
||||||
@ -81,7 +87,18 @@ func UserGroupGetEndpoint(c echo.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return Success(c, item)
|
members, err := model.FindUserGroupMembersByUserGroupId(id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
userGroup := UserGroup{
|
||||||
|
Id: item.ID,
|
||||||
|
Name: item.Name,
|
||||||
|
Members: members,
|
||||||
|
}
|
||||||
|
|
||||||
|
return Success(c, userGroup)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UserGroupAddMembersEndpoint(c echo.Context) error {
|
func UserGroupAddMembersEndpoint(c echo.Context) error {
|
||||||
|
@ -58,7 +58,7 @@ func FindAssetByConditions(protocol string, account User) (o []Asset, err error)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func FindPageAsset(pageIndex, pageSize int, name, protocol, tags string, account User) (o []AssetVo, total int64, err error) {
|
func FindPageAsset(pageIndex, pageSize int, name, protocol, tags string, account User, owner, sharer string) (o []AssetVo, total int64, err error) {
|
||||||
db := global.DB.Table("assets").Select("assets.id,assets.name,assets.ip,assets.port,assets.protocol,assets.active,assets.owner,assets.created, users.nickname as owner_name,COUNT(resources.user_id) as sharer_count").Joins("left join users on assets.owner = users.id").Joins("left join resources on assets.id = resources.resource_id").Group("assets.id")
|
db := global.DB.Table("assets").Select("assets.id,assets.name,assets.ip,assets.port,assets.protocol,assets.active,assets.owner,assets.created, users.nickname as owner_name,COUNT(resources.user_id) as sharer_count").Joins("left join users on assets.owner = users.id").Joins("left join resources on assets.id = resources.resource_id").Group("assets.id")
|
||||||
dbCounter := global.DB.Table("assets").Select("DISTINCT assets.id").Joins("left join resources on assets.id = resources.resource_id")
|
dbCounter := global.DB.Table("assets").Select("DISTINCT assets.id").Joins("left join resources on assets.id = resources.resource_id")
|
||||||
|
|
||||||
@ -66,6 +66,15 @@ func FindPageAsset(pageIndex, pageSize int, name, protocol, tags string, account
|
|||||||
owner := account.ID
|
owner := account.ID
|
||||||
db = db.Where("assets.owner = ? or resources.user_id = ?", owner, owner)
|
db = db.Where("assets.owner = ? or resources.user_id = ?", owner, owner)
|
||||||
dbCounter = dbCounter.Where("assets.owner = ? or resources.user_id = ?", owner, owner)
|
dbCounter = dbCounter.Where("assets.owner = ? or resources.user_id = ?", owner, owner)
|
||||||
|
} else {
|
||||||
|
if len(owner) > 0 {
|
||||||
|
db = db.Where("assets.owner = ?", owner)
|
||||||
|
dbCounter = dbCounter.Where("assets.owner = ?", owner)
|
||||||
|
}
|
||||||
|
if len(sharer) > 0 {
|
||||||
|
db = db.Where("resources.user_id = ?", sharer)
|
||||||
|
dbCounter = dbCounter.Where("resources.user_id = ?", sharer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(name) > 0 {
|
if len(name) > 0 {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"gorm.io/gorm"
|
||||||
"next-terminal/pkg/global"
|
"next-terminal/pkg/global"
|
||||||
"next-terminal/pkg/utils"
|
"next-terminal/pkg/utils"
|
||||||
)
|
)
|
||||||
@ -45,3 +46,28 @@ func OverwriteUserIdsByResourceId(resourceId, resourceType string, userIds []str
|
|||||||
}
|
}
|
||||||
db.Commit()
|
db.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DeleteByUserIdAndResourceTypeAndResourceIdIn(userId, resourceType string, resourceIds []string) error {
|
||||||
|
return global.DB.Where("user_id = ? and resource_type = ? and resource_id in ?", userId, resourceType, resourceIds).Delete(&Resource{}).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddSharerResources(userId, resourceType string, resourceIds []string) error {
|
||||||
|
return global.DB.Transaction(func(tx *gorm.DB) (err error) {
|
||||||
|
|
||||||
|
for i := range resourceIds {
|
||||||
|
resourceId := resourceIds[i]
|
||||||
|
id := utils.Sign([]string{resourceId, resourceType, userId})
|
||||||
|
resource := &Resource{
|
||||||
|
ID: id,
|
||||||
|
ResourceId: resourceId,
|
||||||
|
ResourceType: resourceType,
|
||||||
|
UserId: userId,
|
||||||
|
}
|
||||||
|
err = tx.Create(resource).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
|
import "next-terminal/pkg/global"
|
||||||
|
|
||||||
type UserGroupMember struct {
|
type UserGroupMember struct {
|
||||||
ID string `gorm:"primary_key" json:"name"`
|
ID string `gorm:"primary_key" json:"name"`
|
||||||
UserId string `json:"userId"`
|
UserId string `json:"userId"`
|
||||||
@ -9,3 +11,8 @@ type UserGroupMember struct {
|
|||||||
func (r *UserGroupMember) TableName() string {
|
func (r *UserGroupMember) TableName() string {
|
||||||
return "user_group_members"
|
return "user_group_members"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func FindUserGroupMembersByUserGroupId(id string) (o []string, err error) {
|
||||||
|
err = global.DB.Table("user_group_members").Select("user_id").Where("user_group_id = ?", id).Find(&o).Error
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -86,9 +86,28 @@ func FindUserGroupById(id string) (o UserGroup, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateUserGroupById(o *UserGroup, id string) {
|
func UpdateUserGroupById(o *UserGroup, members []string, id string) error {
|
||||||
o.ID = id
|
return global.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
global.DB.Updates(o)
|
o.ID = id
|
||||||
|
err := tx.Updates(o).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tx.Where("user_group_id = ?", id).Delete(&UserGroupMember{}).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if members != nil {
|
||||||
|
userGroupId := o.ID
|
||||||
|
err = AddUserGroupMembers(tx, members, userGroupId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteUserGroupById(id string) {
|
func DeleteUserGroupById(id string) {
|
||||||
|
@ -23,6 +23,18 @@ type User struct {
|
|||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UserVo struct {
|
||||||
|
ID string `gorm:"primary_key" json:"id"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Nickname string `json:"nickname"`
|
||||||
|
Online bool `json:"online"`
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
Created utils.JsonTime `json:"created"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
//OwnerAssetCount int64 `json:"ownerAssetCount"`
|
||||||
|
SharerAssetCount int64 `json:"sharerAssetCount"`
|
||||||
|
}
|
||||||
|
|
||||||
func (r *User) TableName() string {
|
func (r *User) TableName() string {
|
||||||
return "users"
|
return "users"
|
||||||
}
|
}
|
||||||
@ -38,19 +50,27 @@ func FindAllUser() (o []User) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func FindPageUser(pageIndex, pageSize int, username, nickname string) (o []User, total int64, err error) {
|
func FindPageUser(pageIndex, pageSize int, username, nickname string) (o []UserVo, total int64, err error) {
|
||||||
db := global.DB
|
db := global.DB.Table("users").Select("users.id,users.username,users.nickname,users.online,users.enabled,users.created,users.type, count(resources.user_id) as sharer_asset_count").Joins("left join resources on users.id = resources.user_id and resources.resource_type = 'asset'").Group("users.id")
|
||||||
|
dbCounter := global.DB.Table("users")
|
||||||
if len(username) > 0 {
|
if len(username) > 0 {
|
||||||
db = db.Where("username like ?", "%"+username+"%")
|
db = db.Where("users.username like ?", "%"+username+"%")
|
||||||
|
dbCounter = dbCounter.Where("username like ?", "%"+username+"%")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(nickname) > 0 {
|
if len(nickname) > 0 {
|
||||||
db = db.Where("nickname like ?", "%"+nickname+"%")
|
db = db.Where("users.nickname like ?", "%"+nickname+"%")
|
||||||
|
dbCounter = dbCounter.Where("nickname like ?", "%"+nickname+"%")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = db.Order("created desc").Find(&o).Offset((pageIndex - 1) * pageSize).Limit(pageSize).Count(&total).Error
|
err = dbCounter.Count(&total).Error
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = db.Order("users.created desc").Find(&o).Offset((pageIndex - 1) * pageSize).Limit(pageSize).Error
|
||||||
if o == nil {
|
if o == nil {
|
||||||
o = make([]User, 0)
|
o = make([]UserVo, 0)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -88,6 +88,7 @@ class Asset extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
|
|
||||||
this.loadTableData();
|
this.loadTableData();
|
||||||
|
|
||||||
let result = await request.get('/tags');
|
let result = await request.get('/tags');
|
||||||
|
@ -21,17 +21,9 @@ import qs from "qs";
|
|||||||
import UserModal from "./UserModal";
|
import UserModal from "./UserModal";
|
||||||
import request from "../../common/request";
|
import request from "../../common/request";
|
||||||
import {message} from "antd/es";
|
import {message} from "antd/es";
|
||||||
import {
|
import {DeleteOutlined, ExclamationCircleOutlined, PlusOutlined, SyncOutlined, UndoOutlined} from '@ant-design/icons';
|
||||||
DeleteOutlined,
|
|
||||||
DownOutlined,
|
|
||||||
ExclamationCircleOutlined,
|
|
||||||
IssuesCloseOutlined,
|
|
||||||
PlusOutlined,
|
|
||||||
StopOutlined,
|
|
||||||
SyncOutlined,
|
|
||||||
UndoOutlined
|
|
||||||
} from '@ant-design/icons';
|
|
||||||
import Logout from "./Logout";
|
import Logout from "./Logout";
|
||||||
|
import UserShareAsset from "./UserShareAsset";
|
||||||
|
|
||||||
const confirm = Modal.confirm;
|
const confirm = Modal.confirm;
|
||||||
const {Search} = Input;
|
const {Search} = Input;
|
||||||
@ -68,6 +60,7 @@ class User extends Component {
|
|||||||
model: null,
|
model: null,
|
||||||
selectedRowKeys: [],
|
selectedRowKeys: [],
|
||||||
delBtnLoading: false,
|
delBtnLoading: false,
|
||||||
|
assetVisible: false
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@ -230,14 +223,14 @@ class User extends Component {
|
|||||||
})
|
})
|
||||||
try {
|
try {
|
||||||
let result = await request.delete('/users/' + this.state.selectedRowKeys.join(','));
|
let result = await request.delete('/users/' + this.state.selectedRowKeys.join(','));
|
||||||
if (result.code === 1) {
|
if (result['code'] === 1) {
|
||||||
message.success('操作成功', 3);
|
message.success('操作成功', 3);
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedRowKeys: []
|
selectedRowKeys: []
|
||||||
})
|
})
|
||||||
await this.loadTableData(this.state.queryParams);
|
await this.loadTableData(this.state.queryParams);
|
||||||
} else {
|
} else {
|
||||||
message.error('删除失败 :( ' + result.message, 10);
|
message.error(result['message'], 10);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -246,6 +239,13 @@ class User extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleAssetCancel = () => {
|
||||||
|
this.loadTableData()
|
||||||
|
this.setState({
|
||||||
|
assetVisible: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
||||||
const columns = [{
|
const columns = [{
|
||||||
@ -293,6 +293,18 @@ class User extends Component {
|
|||||||
return (<Badge status="default" text="离线"/>);
|
return (<Badge status="default" text="离线"/>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
title: '共享资产',
|
||||||
|
dataIndex: 'sharerAssetCount',
|
||||||
|
key: 'sharerAssetCount',
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return <Button type='link' onClick={async () => {
|
||||||
|
this.setState({
|
||||||
|
assetVisible: true,
|
||||||
|
sharer: record['id']
|
||||||
|
})
|
||||||
|
}}>{text}</Button>
|
||||||
|
}
|
||||||
}, {
|
}, {
|
||||||
title: '创建日期',
|
title: '创建日期',
|
||||||
dataIndex: 'created',
|
dataIndex: 'created',
|
||||||
@ -483,15 +495,39 @@ class User extends Component {
|
|||||||
loading={this.state.loading}
|
loading={this.state.loading}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<UserModal
|
{/* 为了屏蔽ant modal 关闭后数据仍然遗留的问题*/}
|
||||||
visible={this.state.modalVisible}
|
{
|
||||||
title={this.state.modalTitle}
|
this.state.modalVisible ?
|
||||||
handleOk={this.handleOk}
|
<UserModal
|
||||||
handleCancel={this.handleCancelModal}
|
visible={this.state.modalVisible}
|
||||||
confirmLoading={this.state.modalConfirmLoading}
|
title={this.state.modalTitle}
|
||||||
model={this.state.model}
|
handleOk={this.handleOk}
|
||||||
|
handleCancel={this.handleCancelModal}
|
||||||
|
confirmLoading={this.state.modalConfirmLoading}
|
||||||
|
model={this.state.model}
|
||||||
|
>
|
||||||
|
</UserModal> : undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
width={window.innerWidth * 0.8}
|
||||||
|
title='已共享资产'
|
||||||
|
visible={this.state.assetVisible}
|
||||||
|
maskClosable={false}
|
||||||
|
destroyOnClose={true}
|
||||||
|
onOk={() => {
|
||||||
|
|
||||||
|
}}
|
||||||
|
onCancel={this.handleAssetCancel}
|
||||||
|
okText='确定'
|
||||||
|
cancelText='取消'
|
||||||
|
footer={null}
|
||||||
>
|
>
|
||||||
</UserModal>
|
<UserShareAsset
|
||||||
|
sharer={this.state.sharer}
|
||||||
|
owner={this.state.owner}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
</Content>
|
</Content>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -40,11 +40,10 @@ class UserGroup extends Component {
|
|||||||
modalVisible: false,
|
modalVisible: false,
|
||||||
modalTitle: '',
|
modalTitle: '',
|
||||||
modalConfirmLoading: false,
|
modalConfirmLoading: false,
|
||||||
model: null,
|
model: undefined,
|
||||||
selectedRowKeys: [],
|
selectedRowKeys: [],
|
||||||
delBtnLoading: false,
|
delBtnLoading: false,
|
||||||
users: [],
|
users: [],
|
||||||
members: []
|
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@ -125,11 +124,35 @@ class UserGroup extends Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
showModal(title, user = {}) {
|
showModal = async (title, id, index) => {
|
||||||
|
|
||||||
this.handleSearchByNickname('');
|
let items = this.state.items;
|
||||||
|
|
||||||
|
let model = {}
|
||||||
|
if (id) {
|
||||||
|
items[index].updateBtnLoading = true;
|
||||||
|
this.setState({
|
||||||
|
items: items
|
||||||
|
});
|
||||||
|
|
||||||
|
let result = await request.get('/user-groups/' + id);
|
||||||
|
if (result['code'] !== 1) {
|
||||||
|
message.error(result['message']);
|
||||||
|
items[index].updateBtnLoading = false;
|
||||||
|
this.setState({
|
||||||
|
items: items
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
items[index].updateBtnLoading = false;
|
||||||
|
model = result['data']
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.handleSearchByNickname('');
|
||||||
|
console.log(model)
|
||||||
this.setState({
|
this.setState({
|
||||||
model: user,
|
model: model,
|
||||||
modalVisible: true,
|
modalVisible: true,
|
||||||
modalTitle: title
|
modalTitle: title
|
||||||
});
|
});
|
||||||
@ -138,7 +161,8 @@ class UserGroup extends Component {
|
|||||||
handleCancelModal = e => {
|
handleCancelModal = e => {
|
||||||
this.setState({
|
this.setState({
|
||||||
modalVisible: false,
|
modalVisible: false,
|
||||||
modalTitle: ''
|
modalTitle: '',
|
||||||
|
model: undefined
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -243,9 +267,7 @@ class UserGroup extends Component {
|
|||||||
dataIndex: 'memberCount',
|
dataIndex: 'memberCount',
|
||||||
key: 'memberCount',
|
key: 'memberCount',
|
||||||
render: (text, record, index) => {
|
render: (text, record, index) => {
|
||||||
return <Button type='link' onClick={async () => {
|
return <Button type='link' onClick={() => this.showModal('更新用户组', record['id'], index)}>{text}</Button>
|
||||||
await this.handleShowSharer(record, true);
|
|
||||||
}}>{text}</Button>
|
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
title: '创建日期',
|
title: '创建日期',
|
||||||
@ -255,13 +277,12 @@ class UserGroup extends Component {
|
|||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
key: 'action',
|
key: 'action',
|
||||||
render: (text, record) => {
|
render: (text, record, index) => {
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Button type="link" size='small'
|
<Button type="link" size='small'
|
||||||
onClick={() => this.showModal('更新用户组', record)}>编辑</Button>
|
loading={this.state.items[index].updateBtnLoading}
|
||||||
|
onClick={() => this.showModal('更新用户组', record['id'], index)}>编辑</Button>
|
||||||
<Button type="link" size='small'
|
<Button type="link" size='small'
|
||||||
onClick={() => this.showDeleteConfirm(record.id, record.name)}>删除</Button>
|
onClick={() => this.showDeleteConfirm(record.id, record.name)}>删除</Button>
|
||||||
</div>
|
</div>
|
||||||
@ -325,7 +346,7 @@ class UserGroup extends Component {
|
|||||||
|
|
||||||
<Tooltip title="新增">
|
<Tooltip title="新增">
|
||||||
<Button type="dashed" icon={<PlusOutlined/>}
|
<Button type="dashed" icon={<PlusOutlined/>}
|
||||||
onClick={() => this.showModal('新增用户组', {})}>
|
onClick={() => this.showModal('新增用户组')}>
|
||||||
|
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@ -382,17 +403,20 @@ class UserGroup extends Component {
|
|||||||
loading={this.state.loading}
|
loading={this.state.loading}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<UserGroupModal
|
{/* 为了屏蔽ant modal 关闭后数据仍然遗留的问题*/}
|
||||||
visible={this.state.modalVisible}
|
{this.state.modalVisible ?
|
||||||
title={this.state.modalTitle}
|
<UserGroupModal
|
||||||
handleOk={this.handleOk}
|
visible={this.state.modalVisible}
|
||||||
handleCancel={this.handleCancelModal}
|
title={this.state.modalTitle}
|
||||||
confirmLoading={this.state.modalConfirmLoading}
|
handleOk={this.handleOk}
|
||||||
model={this.state.model}
|
handleCancel={this.handleCancelModal}
|
||||||
users={this.state.users}
|
confirmLoading={this.state.modalConfirmLoading}
|
||||||
members={this.state.members}
|
model={this.state.model}
|
||||||
>
|
users={this.state.users}
|
||||||
</UserGroupModal>
|
>
|
||||||
|
</UserGroupModal> : undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
</Content>
|
</Content>
|
||||||
</>
|
</>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, {useState} from 'react';
|
import React from 'react';
|
||||||
import {Form, Input, Modal, Select} from "antd/lib/index";
|
import {Form, Input, Modal, Select} from "antd/lib/index";
|
||||||
|
|
||||||
const UserGroupModal = ({
|
const UserGroupModal = ({
|
||||||
@ -9,7 +9,6 @@ const UserGroupModal = ({
|
|||||||
confirmLoading,
|
confirmLoading,
|
||||||
model,
|
model,
|
||||||
users,
|
users,
|
||||||
members,
|
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
@ -24,6 +23,7 @@ const UserGroupModal = ({
|
|||||||
title={title}
|
title={title}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
maskClosable={false}
|
maskClosable={false}
|
||||||
|
destroyOnClose={true}
|
||||||
onOk={() => {
|
onOk={() => {
|
||||||
form
|
form
|
||||||
.validateFields()
|
.validateFields()
|
||||||
|
392
web/src/components/user/UserShareAsset.js
Normal file
392
web/src/components/user/UserShareAsset.js
Normal file
@ -0,0 +1,392 @@
|
|||||||
|
import React, {Component} from 'react';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Badge,
|
||||||
|
Button,
|
||||||
|
Col,
|
||||||
|
Divider,
|
||||||
|
Drawer,
|
||||||
|
Input,
|
||||||
|
Layout,
|
||||||
|
Modal,
|
||||||
|
Row,
|
||||||
|
Select,
|
||||||
|
Space,
|
||||||
|
Table,
|
||||||
|
Tag,
|
||||||
|
Tooltip,
|
||||||
|
Typography
|
||||||
|
} from "antd";
|
||||||
|
import qs from "qs";
|
||||||
|
import request from "../../common/request";
|
||||||
|
import {message} from "antd/es";
|
||||||
|
|
||||||
|
|
||||||
|
import {DeleteOutlined, ExclamationCircleOutlined, PlusOutlined, SyncOutlined, UndoOutlined} from '@ant-design/icons';
|
||||||
|
import {PROTOCOL_COLORS} from "../../common/constants";
|
||||||
|
import UserShareChooseAsset from "./UserShareSelectAsset";
|
||||||
|
|
||||||
|
const confirm = Modal.confirm;
|
||||||
|
const {Search} = Input;
|
||||||
|
const {Content} = Layout;
|
||||||
|
const {Title, Text} = Typography;
|
||||||
|
|
||||||
|
class UserShareAsset extends Component {
|
||||||
|
|
||||||
|
inputRefOfName = React.createRef();
|
||||||
|
changeOwnerFormRef = React.createRef();
|
||||||
|
|
||||||
|
state = {
|
||||||
|
items: [],
|
||||||
|
total: 0,
|
||||||
|
queryParams: {
|
||||||
|
pageIndex: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
protocol: ''
|
||||||
|
},
|
||||||
|
loading: false,
|
||||||
|
tags: [],
|
||||||
|
model: {},
|
||||||
|
selectedRowKeys: [],
|
||||||
|
delBtnLoading: false,
|
||||||
|
changeOwnerModalVisible: false,
|
||||||
|
changeSharerModalVisible: false,
|
||||||
|
changeOwnerConfirmLoading: false,
|
||||||
|
changeSharerConfirmLoading: false,
|
||||||
|
users: [],
|
||||||
|
selected: {},
|
||||||
|
selectedSharers: [],
|
||||||
|
chooseAssetVisible: false
|
||||||
|
};
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
let sharer = this.props.sharer;
|
||||||
|
this.loadTableData({sharer: sharer});
|
||||||
|
|
||||||
|
let result = await request.get('/tags');
|
||||||
|
if (result['code'] === 1) {
|
||||||
|
this.setState({
|
||||||
|
tags: result['data']
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadTableData(queryParams) {
|
||||||
|
this.setState({
|
||||||
|
loading: true
|
||||||
|
});
|
||||||
|
|
||||||
|
queryParams = queryParams || this.state.queryParams;
|
||||||
|
|
||||||
|
// queryParams
|
||||||
|
let paramsStr = qs.stringify(queryParams);
|
||||||
|
|
||||||
|
let data = {
|
||||||
|
items: [],
|
||||||
|
total: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
let result = await request.get('/assets/paging?' + paramsStr);
|
||||||
|
if (result['code'] === 1) {
|
||||||
|
data = result['data'];
|
||||||
|
} else {
|
||||||
|
message.error(result['message']);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
const items = data.items.map(item => {
|
||||||
|
return {'key': item['id'], ...item}
|
||||||
|
})
|
||||||
|
this.setState({
|
||||||
|
items: items,
|
||||||
|
total: data.total,
|
||||||
|
queryParams: queryParams,
|
||||||
|
loading: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChangPage = async (pageIndex, pageSize) => {
|
||||||
|
let queryParams = this.state.queryParams;
|
||||||
|
queryParams.pageIndex = pageIndex;
|
||||||
|
queryParams.pageSize = pageSize;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
queryParams: queryParams
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.loadTableData(queryParams)
|
||||||
|
};
|
||||||
|
|
||||||
|
handleSearchByName = name => {
|
||||||
|
let query = {
|
||||||
|
...this.state.queryParams,
|
||||||
|
'pageIndex': 1,
|
||||||
|
'pageSize': this.state.queryParams.pageSize,
|
||||||
|
'name': name,
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loadTableData(query);
|
||||||
|
};
|
||||||
|
|
||||||
|
handleTagsChange = tags => {
|
||||||
|
console.log(tags)
|
||||||
|
// this.setState({
|
||||||
|
// tags: tags
|
||||||
|
// })
|
||||||
|
let query = {
|
||||||
|
...this.state.queryParams,
|
||||||
|
'pageIndex': 1,
|
||||||
|
'pageSize': this.state.queryParams.pageSize,
|
||||||
|
'tags': tags.join(','),
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loadTableData(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSearchByProtocol = protocol => {
|
||||||
|
let query = {
|
||||||
|
...this.state.queryParams,
|
||||||
|
'pageIndex': 1,
|
||||||
|
'pageSize': this.state.queryParams.pageSize,
|
||||||
|
'protocol': protocol,
|
||||||
|
}
|
||||||
|
this.loadTableData(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
title: '序号',
|
||||||
|
dataIndex: 'id',
|
||||||
|
key: 'id',
|
||||||
|
render: (id, record, index) => {
|
||||||
|
return index + 1;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
title: '资产名称',
|
||||||
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
|
render: (name, record) => {
|
||||||
|
let short = name;
|
||||||
|
if (short && short.length > 20) {
|
||||||
|
short = short.substring(0, 20) + " ...";
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Tooltip placement="topLeft" title={name}>
|
||||||
|
{short}
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
title: '网络',
|
||||||
|
dataIndex: 'ip',
|
||||||
|
key: 'ip',
|
||||||
|
render: (text, record) => {
|
||||||
|
|
||||||
|
return record['ip'] + ':' + record['port'];
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
title: '连接协议',
|
||||||
|
dataIndex: 'protocol',
|
||||||
|
key: 'protocol',
|
||||||
|
render: (text, record) => {
|
||||||
|
|
||||||
|
return (<Tag color={PROTOCOL_COLORS[text]}>{text}</Tag>);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
title: '状态',
|
||||||
|
dataIndex: 'active',
|
||||||
|
key: 'active',
|
||||||
|
render: text => {
|
||||||
|
if (text) {
|
||||||
|
return (<Badge status="processing" text="运行中"/>);
|
||||||
|
} else {
|
||||||
|
return (<Badge status="error" text="不可用"/>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
title: '所有者',
|
||||||
|
dataIndex: 'ownerName',
|
||||||
|
key: 'ownerName'
|
||||||
|
}, {
|
||||||
|
title: '创建日期',
|
||||||
|
dataIndex: 'created',
|
||||||
|
key: 'created'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const selectedRowKeys = this.state.selectedRowKeys;
|
||||||
|
const rowSelection = {
|
||||||
|
selectedRowKeys: this.state.selectedRowKeys,
|
||||||
|
onChange: (selectedRowKeys, selectedRows) => {
|
||||||
|
this.setState({selectedRowKeys});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const hasSelected = selectedRowKeys.length > 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Content key='page-content' className="site-layout-background">
|
||||||
|
<div style={{marginBottom: 20}}>
|
||||||
|
<Row justify="space-around" align="middle" gutter={24}>
|
||||||
|
<Col span={8} key={1}>
|
||||||
|
<Title level={3}>共享资产列表</Title>
|
||||||
|
</Col>
|
||||||
|
<Col span={16} key={2} style={{textAlign: 'right'}}>
|
||||||
|
<Space>
|
||||||
|
|
||||||
|
<Search
|
||||||
|
ref={this.inputRefOfName}
|
||||||
|
placeholder="资产名称"
|
||||||
|
allowClear
|
||||||
|
onSearch={this.handleSearchByName}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Select mode="multiple"
|
||||||
|
allowClear
|
||||||
|
placeholder="资产标签" onChange={this.handleTagsChange}
|
||||||
|
style={{minWidth: 150}}>
|
||||||
|
{this.state.tags.map(tag => {
|
||||||
|
if (tag === '-') {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return (<Select.Option key={tag}>{tag}</Select.Option>)
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
|
||||||
|
<Select onChange={this.handleSearchByProtocol}
|
||||||
|
value={this.state.queryParams.protocol ? this.state.queryParams.protocol : ''}
|
||||||
|
style={{width: 100}}>
|
||||||
|
<Select.Option value="">全部协议</Select.Option>
|
||||||
|
<Select.Option value="rdp">rdp</Select.Option>
|
||||||
|
<Select.Option value="ssh">ssh</Select.Option>
|
||||||
|
<Select.Option value="vnc">vnc</Select.Option>
|
||||||
|
<Select.Option value="telnet">telnet</Select.Option>
|
||||||
|
</Select>
|
||||||
|
|
||||||
|
<Tooltip title='重置查询'>
|
||||||
|
|
||||||
|
<Button icon={<UndoOutlined/>} onClick={() => {
|
||||||
|
this.inputRefOfName.current.setValue('');
|
||||||
|
this.loadTableData({
|
||||||
|
...this.state.queryParams,
|
||||||
|
pageIndex: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
protocol: ''
|
||||||
|
})
|
||||||
|
}}>
|
||||||
|
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<Divider type="vertical"/>
|
||||||
|
|
||||||
|
<Tooltip title="新增">
|
||||||
|
<Button type="dashed" icon={<PlusOutlined/>}
|
||||||
|
onClick={() => {
|
||||||
|
this.setState({
|
||||||
|
chooseAssetVisible: true
|
||||||
|
})
|
||||||
|
}}>
|
||||||
|
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<Tooltip title="刷新列表">
|
||||||
|
<Button icon={<SyncOutlined/>} onClick={() => {
|
||||||
|
this.loadTableData(this.state.queryParams)
|
||||||
|
}}>
|
||||||
|
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<Tooltip title="移除共享">
|
||||||
|
<Button type="dashed" danger disabled={!hasSelected} icon={<DeleteOutlined/>}
|
||||||
|
loading={this.state.delBtnLoading}
|
||||||
|
onClick={() => {
|
||||||
|
const content = <div>
|
||||||
|
您确定要移除选中的<Text style={{color: '#1890FF'}}
|
||||||
|
strong>{this.state.selectedRowKeys.length}</Text>条共享记录吗?
|
||||||
|
</div>;
|
||||||
|
confirm({
|
||||||
|
icon: <ExclamationCircleOutlined/>,
|
||||||
|
content: content,
|
||||||
|
onOk: async () => {
|
||||||
|
let userId = this.state.queryParams.sharer;
|
||||||
|
let result = await request.post(`/resources/remove`, {
|
||||||
|
userId: userId,
|
||||||
|
resourceType: 'asset',
|
||||||
|
resourceIds: this.state.selectedRowKeys
|
||||||
|
});
|
||||||
|
if (result['code'] === 1) {
|
||||||
|
message.success('操作成功', 3);
|
||||||
|
this.setState({
|
||||||
|
selectedRowKeys: []
|
||||||
|
})
|
||||||
|
await this.loadTableData();
|
||||||
|
} else {
|
||||||
|
message.error(result['message'], 10);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onCancel() {
|
||||||
|
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}>
|
||||||
|
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</Space>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Table key='assets-table'
|
||||||
|
rowSelection={rowSelection}
|
||||||
|
dataSource={this.state.items}
|
||||||
|
columns={columns}
|
||||||
|
position={'both'}
|
||||||
|
pagination={{
|
||||||
|
showSizeChanger: true,
|
||||||
|
current: this.state.queryParams.pageIndex,
|
||||||
|
pageSize: this.state.queryParams.pageSize,
|
||||||
|
onChange: this.handleChangPage,
|
||||||
|
onShowSizeChange: this.handleChangPage,
|
||||||
|
total: this.state.total,
|
||||||
|
showTotal: total => `总计 ${total} 条`
|
||||||
|
}}
|
||||||
|
loading={this.state.loading}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{this.state.chooseAssetVisible ?
|
||||||
|
<Drawer
|
||||||
|
title="添加资产"
|
||||||
|
placement="right"
|
||||||
|
closable={true}
|
||||||
|
onClose={() => {
|
||||||
|
this.loadTableData()
|
||||||
|
this.setState({
|
||||||
|
chooseAssetVisible: false
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
visible={this.state.chooseAssetVisible}
|
||||||
|
width={window.innerWidth * 0.8}
|
||||||
|
>
|
||||||
|
<UserShareChooseAsset
|
||||||
|
sharer={this.state.queryParams.sharer}
|
||||||
|
>
|
||||||
|
|
||||||
|
</UserShareChooseAsset>
|
||||||
|
</Drawer> : undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
</Content>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserShareAsset;
|
416
web/src/components/user/UserShareSelectAsset.js
Normal file
416
web/src/components/user/UserShareSelectAsset.js
Normal file
@ -0,0 +1,416 @@
|
|||||||
|
import React, {Component} from 'react';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Badge,
|
||||||
|
Button,
|
||||||
|
Col,
|
||||||
|
Divider,
|
||||||
|
Input,
|
||||||
|
Layout,
|
||||||
|
Modal,
|
||||||
|
Row,
|
||||||
|
Select,
|
||||||
|
Space,
|
||||||
|
Table,
|
||||||
|
Tag,
|
||||||
|
Tooltip,
|
||||||
|
Typography
|
||||||
|
} from "antd";
|
||||||
|
import qs from "qs";
|
||||||
|
import request from "../../common/request";
|
||||||
|
import {message} from "antd/es";
|
||||||
|
|
||||||
|
|
||||||
|
import {PlusOutlined, SyncOutlined, UndoOutlined} from '@ant-design/icons';
|
||||||
|
import {PROTOCOL_COLORS} from "../../common/constants";
|
||||||
|
|
||||||
|
const confirm = Modal.confirm;
|
||||||
|
const {Search} = Input;
|
||||||
|
const {Content} = Layout;
|
||||||
|
const {Title, Text} = Typography;
|
||||||
|
|
||||||
|
class UserShareAsset extends Component {
|
||||||
|
|
||||||
|
inputRefOfName = React.createRef();
|
||||||
|
changeOwnerFormRef = React.createRef();
|
||||||
|
|
||||||
|
state = {
|
||||||
|
items: [],
|
||||||
|
total: 0,
|
||||||
|
queryParams: {
|
||||||
|
pageIndex: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
protocol: ''
|
||||||
|
},
|
||||||
|
loading: false,
|
||||||
|
tags: [],
|
||||||
|
model: {},
|
||||||
|
selectedRowKeys: [],
|
||||||
|
selectedRows: [],
|
||||||
|
delBtnLoading: false,
|
||||||
|
changeOwnerModalVisible: false,
|
||||||
|
changeSharerModalVisible: false,
|
||||||
|
changeOwnerConfirmLoading: false,
|
||||||
|
changeSharerConfirmLoading: false,
|
||||||
|
users: [],
|
||||||
|
selected: {},
|
||||||
|
totalSelectedRows: [],
|
||||||
|
sharer: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
sharer: this.props.sharer
|
||||||
|
})
|
||||||
|
let r2 = await request.get('/assets/paging?pageIndex=1&pageSize=1000&sharer=' + this.props.sharer);
|
||||||
|
if (r2['code'] === 1) {
|
||||||
|
let items = r2['data']['items'];
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
totalSelectedRows: items
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loadTableData();
|
||||||
|
|
||||||
|
let result = await request.get('/tags');
|
||||||
|
if (result['code'] === 1) {
|
||||||
|
this.setState({
|
||||||
|
tags: result['data']
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadTableData(queryParams) {
|
||||||
|
this.setState({
|
||||||
|
loading: true
|
||||||
|
});
|
||||||
|
|
||||||
|
queryParams = queryParams || this.state.queryParams;
|
||||||
|
|
||||||
|
// queryParams
|
||||||
|
let paramsStr = qs.stringify(queryParams);
|
||||||
|
|
||||||
|
let data = {
|
||||||
|
items: [],
|
||||||
|
total: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
let result = await request.get('/assets/paging?' + paramsStr);
|
||||||
|
if (result['code'] === 1) {
|
||||||
|
data = result['data'];
|
||||||
|
} else {
|
||||||
|
message.error(result['message']);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
const items = data.items.map(item => {
|
||||||
|
return {'key': item['id'], ...item}
|
||||||
|
})
|
||||||
|
let totalSelectedRows = this.state.totalSelectedRows;
|
||||||
|
let selectedRowKeys = totalSelectedRows.map(item => item['id']);
|
||||||
|
this.setState({
|
||||||
|
items: items,
|
||||||
|
total: data.total,
|
||||||
|
queryParams: queryParams,
|
||||||
|
loading: false,
|
||||||
|
selectedRowKeys: selectedRowKeys
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChangPage = async (pageIndex, pageSize) => {
|
||||||
|
let queryParams = this.state.queryParams;
|
||||||
|
queryParams.pageIndex = pageIndex;
|
||||||
|
queryParams.pageSize = pageSize;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
queryParams: queryParams
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.loadTableData(queryParams)
|
||||||
|
};
|
||||||
|
|
||||||
|
handleSearchByName = name => {
|
||||||
|
let query = {
|
||||||
|
...this.state.queryParams,
|
||||||
|
'pageIndex': 1,
|
||||||
|
'pageSize': this.state.queryParams.pageSize,
|
||||||
|
'name': name,
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loadTableData(query);
|
||||||
|
};
|
||||||
|
|
||||||
|
handleTagsChange = tags => {
|
||||||
|
console.log(tags)
|
||||||
|
// this.setState({
|
||||||
|
// tags: tags
|
||||||
|
// })
|
||||||
|
let query = {
|
||||||
|
...this.state.queryParams,
|
||||||
|
'pageIndex': 1,
|
||||||
|
'pageSize': this.state.queryParams.pageSize,
|
||||||
|
'tags': tags.join(','),
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loadTableData(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSearchByProtocol = protocol => {
|
||||||
|
let query = {
|
||||||
|
...this.state.queryParams,
|
||||||
|
'pageIndex': 1,
|
||||||
|
'pageSize': this.state.queryParams.pageSize,
|
||||||
|
'protocol': protocol,
|
||||||
|
}
|
||||||
|
this.loadTableData(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
unSelectRow = async (assetId) => {
|
||||||
|
let userId = this.state.sharer;
|
||||||
|
let result = await request.post(`/resources/remove`, {
|
||||||
|
userId: userId,
|
||||||
|
resourceType: 'asset',
|
||||||
|
resourceIds: [assetId]
|
||||||
|
});
|
||||||
|
if (result['code'] === 1) {
|
||||||
|
message.success('操作成功', 3);
|
||||||
|
} else {
|
||||||
|
message.error(result['message'], 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedRowKeys = this.state.selectedRowKeys.filter(key => key !== assetId);
|
||||||
|
const totalSelectedRows = this.state.totalSelectedRows.filter(item => item['id'] !== assetId);
|
||||||
|
this.setState({
|
||||||
|
selectedRowKeys: selectedRowKeys,
|
||||||
|
totalSelectedRows: totalSelectedRows
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
title: '序号',
|
||||||
|
dataIndex: 'id',
|
||||||
|
key: 'id',
|
||||||
|
render: (id, record, index) => {
|
||||||
|
return index + 1;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
title: '资产名称',
|
||||||
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
|
render: (name, record) => {
|
||||||
|
let short = name;
|
||||||
|
if (short && short.length > 20) {
|
||||||
|
short = short.substring(0, 20) + " ...";
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Tooltip placement="topLeft" title={name}>
|
||||||
|
{short}
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
title: '网络',
|
||||||
|
dataIndex: 'ip',
|
||||||
|
key: 'ip',
|
||||||
|
render: (text, record) => {
|
||||||
|
|
||||||
|
return record['ip'] + ':' + record['port'];
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
title: '连接协议',
|
||||||
|
dataIndex: 'protocol',
|
||||||
|
key: 'protocol',
|
||||||
|
render: (text, record) => {
|
||||||
|
|
||||||
|
return (<Tag color={PROTOCOL_COLORS[text]}>{text}</Tag>);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
title: '状态',
|
||||||
|
dataIndex: 'active',
|
||||||
|
key: 'active',
|
||||||
|
render: text => {
|
||||||
|
if (text) {
|
||||||
|
return (<Badge status="processing" text="运行中"/>);
|
||||||
|
} else {
|
||||||
|
return (<Badge status="error" text="不可用"/>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
title: '所有者',
|
||||||
|
dataIndex: 'ownerName',
|
||||||
|
key: 'ownerName'
|
||||||
|
}, {
|
||||||
|
title: '创建日期',
|
||||||
|
dataIndex: 'created',
|
||||||
|
key: 'created'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const selectedRowKeys = this.state.selectedRowKeys;
|
||||||
|
const rowSelection = {
|
||||||
|
selectedRowKeys: this.state.selectedRowKeys,
|
||||||
|
onChange: (selectedRowKeys, selectedRows) => {
|
||||||
|
this.setState({selectedRowKeys, selectedRows});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let hasSelected = false;
|
||||||
|
if (selectedRowKeys.length > 0) {
|
||||||
|
let totalSelectedRows = this.state.totalSelectedRows;
|
||||||
|
let allSelectedRowKeys = totalSelectedRows.map(item => item['id']);
|
||||||
|
for (let i = 0; i < selectedRowKeys.length; i++) {
|
||||||
|
let selectedRowKey = selectedRowKeys[i];
|
||||||
|
if (!allSelectedRowKeys.includes(selectedRowKey)) {
|
||||||
|
hasSelected = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Title level={3}>共享资产列表</Title>
|
||||||
|
<div>
|
||||||
|
{
|
||||||
|
this.state.totalSelectedRows.map(item => {
|
||||||
|
return <Tag color={PROTOCOL_COLORS[item['protocol']]} closable
|
||||||
|
onClose={() => this.unSelectRow(item['id'])}
|
||||||
|
key={item['id']}>{item['name']}</Tag>
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Divider/>
|
||||||
|
<Content key='page-content' className="site-layout-background">
|
||||||
|
<div style={{marginBottom: 20}}>
|
||||||
|
<Row justify="space-around" align="middle" gutter={24}>
|
||||||
|
<Col span={8} key={1}>
|
||||||
|
<Title level={3}>全部资产列表</Title>
|
||||||
|
</Col>
|
||||||
|
<Col span={16} key={2} style={{textAlign: 'right'}}>
|
||||||
|
<Space>
|
||||||
|
|
||||||
|
<Search
|
||||||
|
ref={this.inputRefOfName}
|
||||||
|
placeholder="资产名称"
|
||||||
|
allowClear
|
||||||
|
onSearch={this.handleSearchByName}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Select mode="multiple"
|
||||||
|
allowClear
|
||||||
|
placeholder="资产标签" onChange={this.handleTagsChange}
|
||||||
|
style={{minWidth: 150}}>
|
||||||
|
{this.state.tags.map(tag => {
|
||||||
|
if (tag === '-') {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return (<Select.Option key={tag}>{tag}</Select.Option>)
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
|
||||||
|
<Select onChange={this.handleSearchByProtocol}
|
||||||
|
value={this.state.queryParams.protocol ? this.state.queryParams.protocol : ''}
|
||||||
|
style={{width: 100}}>
|
||||||
|
<Select.Option value="">全部协议</Select.Option>
|
||||||
|
<Select.Option value="rdp">rdp</Select.Option>
|
||||||
|
<Select.Option value="ssh">ssh</Select.Option>
|
||||||
|
<Select.Option value="vnc">vnc</Select.Option>
|
||||||
|
<Select.Option value="telnet">telnet</Select.Option>
|
||||||
|
</Select>
|
||||||
|
|
||||||
|
<Tooltip title='重置查询'>
|
||||||
|
|
||||||
|
<Button icon={<UndoOutlined/>} onClick={() => {
|
||||||
|
this.inputRefOfName.current.setValue('');
|
||||||
|
this.loadTableData({
|
||||||
|
...this.state.queryParams,
|
||||||
|
pageIndex: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
protocol: ''
|
||||||
|
})
|
||||||
|
}}>
|
||||||
|
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<Divider type="vertical"/>
|
||||||
|
|
||||||
|
<Tooltip title="刷新列表">
|
||||||
|
<Button icon={<SyncOutlined/>} onClick={() => {
|
||||||
|
this.loadTableData(this.state.queryParams)
|
||||||
|
}}>
|
||||||
|
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<Tooltip title="添加共享">
|
||||||
|
<Button type="primary" disabled={!hasSelected} icon={<PlusOutlined/>}
|
||||||
|
onClick={async () => {
|
||||||
|
console.log(this.state.selectedRows)
|
||||||
|
let totalSelectedRows = this.state.totalSelectedRows;
|
||||||
|
let totalSelectedRowKeys = totalSelectedRows.map(item => item['id']);
|
||||||
|
|
||||||
|
let selectedRows = this.state.selectedRows;
|
||||||
|
let newRowKeys = []
|
||||||
|
for (let i = 0; i < selectedRows.length; i++) {
|
||||||
|
let selectedRow = selectedRows[i];
|
||||||
|
if (totalSelectedRowKeys.includes(selectedRow['id'])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
totalSelectedRows.push(selectedRow);
|
||||||
|
newRowKeys.push(selectedRow['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
let userId = this.state.sharer;
|
||||||
|
let result = await request.post(`/resources/add`, {
|
||||||
|
userId: userId,
|
||||||
|
resourceType: 'asset',
|
||||||
|
resourceIds: newRowKeys
|
||||||
|
});
|
||||||
|
if (result['code'] === 1) {
|
||||||
|
message.success('操作成功', 3);
|
||||||
|
this.setState({
|
||||||
|
totalSelectedRows: totalSelectedRows
|
||||||
|
})
|
||||||
|
await this.loadTableData();
|
||||||
|
} else {
|
||||||
|
message.error(result['message'], 10);
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</Space>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Table key='assets-table'
|
||||||
|
rowSelection={rowSelection}
|
||||||
|
dataSource={this.state.items}
|
||||||
|
columns={columns}
|
||||||
|
position={'both'}
|
||||||
|
pagination={{
|
||||||
|
showSizeChanger: true,
|
||||||
|
current: this.state.queryParams.pageIndex,
|
||||||
|
pageSize: this.state.queryParams.pageSize,
|
||||||
|
onChange: this.handleChangPage,
|
||||||
|
onShowSizeChange: this.handleChangPage,
|
||||||
|
total: this.state.total,
|
||||||
|
showTotal: total => `总计 ${total} 条`
|
||||||
|
}}
|
||||||
|
loading={this.state.loading}
|
||||||
|
/>
|
||||||
|
</Content>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserShareAsset;
|
@ -171,3 +171,9 @@ export function compare(p) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function difference(a, b) {
|
||||||
|
let aSet = new Set(a)
|
||||||
|
let bSet = new Set(b)
|
||||||
|
return Array.from(new Set(a.concat(b).filter(v => !aSet.has(v) || !bSet.has(v))))
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user