diff --git a/pkg/api/asset.go b/pkg/api/asset.go
index 8a9b139..e56e9e9 100644
--- a/pkg/api/asset.go
+++ b/pkg/api/asset.go
@@ -33,9 +33,11 @@ func AssetPagingEndpoint(c echo.Context) error {
name := c.QueryParam("name")
protocol := c.QueryParam("protocol")
tags := c.QueryParam("tags")
+ owner := c.QueryParam("owner")
+ sharer := c.QueryParam("sharer")
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{
"total": total,
diff --git a/pkg/api/resource.go b/pkg/api/resource.go
index e4d523a..e06415e 100644
--- a/pkg/api/resource.go
+++ b/pkg/api/resource.go
@@ -6,6 +6,12 @@ import (
"strings"
)
+type RU struct {
+ UserId string `json:"userId"`
+ ResourceType string `json:"resourceType"`
+ ResourceIds []string `json:"resourceIds"`
+}
+
func ResourceGetAssignEndPoint(c echo.Context) error {
resourceId := c.Param("id")
userIds, err := model.FindUserIdsByResourceId(resourceId)
@@ -25,3 +31,29 @@ func ResourceOverwriteAssignEndPoint(c echo.Context) error {
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, "")
+}
diff --git a/pkg/api/routes.go b/pkg/api/routes.go
index b8fd34d..dfc8a35 100644
--- a/pkg/api/routes.go
+++ b/pkg/api/routes.go
@@ -58,8 +58,8 @@ func SetupRoutes() *echo.Echo {
userGroups.PUT("/:id", UserGroupUpdateEndpoint)
userGroups.DELETE("/:id", UserGroupDeleteEndpoint)
userGroups.GET("/:id", UserGroupGetEndpoint)
- userGroups.POST("/:id/members", UserGroupAddMembersEndpoint)
- userGroups.DELETE("/:id/members/:memberId", UserGroupDelMembersEndpoint)
+ //userGroups.POST("/:id/members", UserGroupAddMembersEndpoint)
+ //userGroups.DELETE("/:id/members/:memberId", UserGroupDelMembersEndpoint)
}
assets := e.Group("/assets", Auth)
@@ -119,6 +119,8 @@ func SetupRoutes() *echo.Echo {
{
resources.GET("/:id/assign", ResourceGetAssignEndPoint)
resources.POST("/:id/assign", ResourceOverwriteAssignEndPoint)
+ resources.POST("/remove", ResourceRemoveByUserIdAssignEndPoint)
+ resources.POST("/add", ResourceAddByUserIdAssignEndPoint)
}
e.GET("/properties", PropertyGetEndpoint)
diff --git a/pkg/api/user-group.go b/pkg/api/user-group.go
index 24831af..4d3686c 100644
--- a/pkg/api/user-group.go
+++ b/pkg/api/user-group.go
@@ -10,6 +10,7 @@ import (
)
type UserGroup struct {
+ Id string `json:"id"`
Name string `json:"name"`
Members []string `json:"members"`
}
@@ -52,12 +53,17 @@ func UserGroupPagingEndpoint(c echo.Context) error {
func UserGroupUpdateEndpoint(c echo.Context) error {
id := c.Param("id")
- var item model.UserGroup
+ var item UserGroup
if err := c.Bind(&item); err != nil {
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)
}
@@ -81,7 +87,18 @@ func UserGroupGetEndpoint(c echo.Context) error {
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 {
diff --git a/pkg/model/asset.go b/pkg/model/asset.go
index 7eaeafc..5be697d 100644
--- a/pkg/model/asset.go
+++ b/pkg/model/asset.go
@@ -58,7 +58,7 @@ func FindAssetByConditions(protocol string, account User) (o []Asset, err error)
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")
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
db = db.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 {
diff --git a/pkg/model/resource.go b/pkg/model/resource.go
index 4dc596b..a3fa9dc 100644
--- a/pkg/model/resource.go
+++ b/pkg/model/resource.go
@@ -1,6 +1,7 @@
package model
import (
+ "gorm.io/gorm"
"next-terminal/pkg/global"
"next-terminal/pkg/utils"
)
@@ -45,3 +46,28 @@ func OverwriteUserIdsByResourceId(resourceId, resourceType string, userIds []str
}
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
+ })
+}
diff --git a/pkg/model/user-group-member.go b/pkg/model/user-group-member.go
index 2d2f4d2..ca05e08 100644
--- a/pkg/model/user-group-member.go
+++ b/pkg/model/user-group-member.go
@@ -1,5 +1,7 @@
package model
+import "next-terminal/pkg/global"
+
type UserGroupMember struct {
ID string `gorm:"primary_key" json:"name"`
UserId string `json:"userId"`
@@ -9,3 +11,8 @@ type UserGroupMember struct {
func (r *UserGroupMember) TableName() string {
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
+}
diff --git a/pkg/model/user-group.go b/pkg/model/user-group.go
index be55e90..21a77fa 100644
--- a/pkg/model/user-group.go
+++ b/pkg/model/user-group.go
@@ -86,9 +86,28 @@ func FindUserGroupById(id string) (o UserGroup, err error) {
return
}
-func UpdateUserGroupById(o *UserGroup, id string) {
- o.ID = id
- global.DB.Updates(o)
+func UpdateUserGroupById(o *UserGroup, members []string, id string) error {
+ return global.DB.Transaction(func(tx *gorm.DB) error {
+ 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) {
diff --git a/pkg/model/user.go b/pkg/model/user.go
index a1c338f..51caec7 100644
--- a/pkg/model/user.go
+++ b/pkg/model/user.go
@@ -23,6 +23,18 @@ type User struct {
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 {
return "users"
}
@@ -38,19 +50,27 @@ func FindAllUser() (o []User) {
return
}
-func FindPageUser(pageIndex, pageSize int, username, nickname string) (o []User, total int64, err error) {
- db := global.DB
+func FindPageUser(pageIndex, pageSize int, username, nickname string) (o []UserVo, total int64, err error) {
+ 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 {
- db = db.Where("username like ?", "%"+username+"%")
+ db = db.Where("users.username like ?", "%"+username+"%")
+ dbCounter = dbCounter.Where("username like ?", "%"+username+"%")
}
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 {
- o = make([]User, 0)
+ o = make([]UserVo, 0)
}
return
}
diff --git a/web/src/components/asset/Asset.js b/web/src/components/asset/Asset.js
index 5eb8395..113aa64 100644
--- a/web/src/components/asset/Asset.js
+++ b/web/src/components/asset/Asset.js
@@ -88,6 +88,7 @@ class Asset extends Component {
};
async componentDidMount() {
+
this.loadTableData();
let result = await request.get('/tags');
diff --git a/web/src/components/user/User.js b/web/src/components/user/User.js
index 1c05470..6848e68 100644
--- a/web/src/components/user/User.js
+++ b/web/src/components/user/User.js
@@ -21,17 +21,9 @@ import qs from "qs";
import UserModal from "./UserModal";
import request from "../../common/request";
import {message} from "antd/es";
-import {
- DeleteOutlined,
- DownOutlined,
- ExclamationCircleOutlined,
- IssuesCloseOutlined,
- PlusOutlined,
- StopOutlined,
- SyncOutlined,
- UndoOutlined
-} from '@ant-design/icons';
+import {DeleteOutlined, ExclamationCircleOutlined, PlusOutlined, SyncOutlined, UndoOutlined} from '@ant-design/icons';
import Logout from "./Logout";
+import UserShareAsset from "./UserShareAsset";
const confirm = Modal.confirm;
const {Search} = Input;
@@ -68,6 +60,7 @@ class User extends Component {
model: null,
selectedRowKeys: [],
delBtnLoading: false,
+ assetVisible: false
};
componentDidMount() {
@@ -230,14 +223,14 @@ class User extends Component {
})
try {
let result = await request.delete('/users/' + this.state.selectedRowKeys.join(','));
- if (result.code === 1) {
+ if (result['code'] === 1) {
message.success('操作成功', 3);
this.setState({
selectedRowKeys: []
})
await this.loadTableData(this.state.queryParams);
} else {
- message.error('删除失败 :( ' + result.message, 10);
+ message.error(result['message'], 10);
}
} finally {
this.setState({
@@ -246,6 +239,13 @@ class User extends Component {
}
}
+ handleAssetCancel = () => {
+ this.loadTableData()
+ this.setState({
+ assetVisible: false
+ })
+ }
+
render() {
const columns = [{
@@ -293,6 +293,18 @@ class User extends Component {
return ();
}
}
+ }, {
+ title: '共享资产',
+ dataIndex: 'sharerAssetCount',
+ key: 'sharerAssetCount',
+ render: (text, record, index) => {
+ return
+ }
}, {
title: '创建日期',
dataIndex: 'created',
@@ -483,15 +495,39 @@ class User extends Component {
loading={this.state.loading}
/>
-
+ : undefined
+ }
+
+ {
+
+ }}
+ onCancel={this.handleAssetCancel}
+ okText='确定'
+ cancelText='取消'
+ footer={null}
>
-
+
+
>
);
diff --git a/web/src/components/user/UserGroup.js b/web/src/components/user/UserGroup.js
index e8358b0..d6e8a79 100644
--- a/web/src/components/user/UserGroup.js
+++ b/web/src/components/user/UserGroup.js
@@ -40,11 +40,10 @@ class UserGroup extends Component {
modalVisible: false,
modalTitle: '',
modalConfirmLoading: false,
- model: null,
+ model: undefined,
selectedRowKeys: [],
delBtnLoading: false,
users: [],
- members: []
};
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({
- model: user,
+ model: model,
modalVisible: true,
modalTitle: title
});
@@ -138,7 +161,8 @@ class UserGroup extends Component {
handleCancelModal = e => {
this.setState({
modalVisible: false,
- modalTitle: ''
+ modalTitle: '',
+ model: undefined
});
};
@@ -243,9 +267,7 @@ class UserGroup extends Component {
dataIndex: 'memberCount',
key: 'memberCount',
render: (text, record, index) => {
- return
+ return
}
}, {
title: '创建日期',
@@ -255,13 +277,12 @@ class UserGroup extends Component {
{
title: '操作',
key: 'action',
- render: (text, record) => {
-
-
+ render: (text, record, index) => {
return (
+ loading={this.state.items[index].updateBtnLoading}
+ onClick={() => this.showModal('更新用户组', record['id'], index)}>编辑
@@ -325,7 +346,7 @@ class UserGroup extends Component {
@@ -382,17 +403,20 @@ class UserGroup extends Component {
loading={this.state.loading}
/>
-
-
+ {/* 为了屏蔽ant modal 关闭后数据仍然遗留的问题*/}
+ {this.state.modalVisible ?
+
+ : undefined
+ }
+
>
diff --git a/web/src/components/user/UserGroupModal.js b/web/src/components/user/UserGroupModal.js
index f22cdbd..008d79e 100644
--- a/web/src/components/user/UserGroupModal.js
+++ b/web/src/components/user/UserGroupModal.js
@@ -1,4 +1,4 @@
-import React, {useState} from 'react';
+import React from 'react';
import {Form, Input, Modal, Select} from "antd/lib/index";
const UserGroupModal = ({
@@ -9,7 +9,6 @@ const UserGroupModal = ({
confirmLoading,
model,
users,
- members,
}) => {
const [form] = Form.useForm();
@@ -24,6 +23,7 @@ const UserGroupModal = ({
title={title}
visible={visible}
maskClosable={false}
+ destroyOnClose={true}
onOk={() => {
form
.validateFields()
diff --git a/web/src/components/user/UserShareAsset.js b/web/src/components/user/UserShareAsset.js
new file mode 100644
index 0000000..a61bc1f
--- /dev/null
+++ b/web/src/components/user/UserShareAsset.js
@@ -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 (
+
+ {short}
+
+ );
+ }
+ }, {
+ title: '网络',
+ dataIndex: 'ip',
+ key: 'ip',
+ render: (text, record) => {
+
+ return record['ip'] + ':' + record['port'];
+ }
+ }, {
+ title: '连接协议',
+ dataIndex: 'protocol',
+ key: 'protocol',
+ render: (text, record) => {
+
+ return ({text});
+ }
+ }, {
+ title: '状态',
+ dataIndex: 'active',
+ key: 'active',
+ render: text => {
+ if (text) {
+ return ();
+ } else {
+ return ();
+ }
+ }
+ }, {
+ 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 (
+ <>
+
+
+
+
+ 共享资产列表
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `总计 ${total} 条`
+ }}
+ loading={this.state.loading}
+ />
+
+ {this.state.chooseAssetVisible ?
+ {
+ this.loadTableData()
+ this.setState({
+ chooseAssetVisible: false
+ })
+ }}
+ visible={this.state.chooseAssetVisible}
+ width={window.innerWidth * 0.8}
+ >
+
+
+
+ : undefined
+ }
+
+
+ >
+ );
+ }
+}
+
+export default UserShareAsset;
diff --git a/web/src/components/user/UserShareSelectAsset.js b/web/src/components/user/UserShareSelectAsset.js
new file mode 100644
index 0000000..36d2130
--- /dev/null
+++ b/web/src/components/user/UserShareSelectAsset.js
@@ -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 (
+
+ {short}
+
+ );
+ }
+ }, {
+ title: '网络',
+ dataIndex: 'ip',
+ key: 'ip',
+ render: (text, record) => {
+
+ return record['ip'] + ':' + record['port'];
+ }
+ }, {
+ title: '连接协议',
+ dataIndex: 'protocol',
+ key: 'protocol',
+ render: (text, record) => {
+
+ return ({text});
+ }
+ }, {
+ title: '状态',
+ dataIndex: 'active',
+ key: 'active',
+ render: text => {
+ if (text) {
+ return ();
+ } else {
+ return ();
+ }
+ }
+ }, {
+ 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 (
+ <>
+ 共享资产列表
+
+ {
+ this.state.totalSelectedRows.map(item => {
+ return this.unSelectRow(item['id'])}
+ key={item['id']}>{item['name']}
+ })
+ }
+
+
+
+
+
+
+
+ 全部资产列表
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `总计 ${total} 条`
+ }}
+ loading={this.state.loading}
+ />
+
+ >
+ );
+ }
+}
+
+export default UserShareAsset;
diff --git a/web/src/utils/utils.js b/web/src/utils/utils.js
index 4a650f9..f56f8d4 100644
--- a/web/src/utils/utils.js
+++ b/web/src/utils/utils.js
@@ -170,4 +170,10 @@ export function compare(p) {
}
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))))
}
\ No newline at end of file