提交 1.3.0-beta4
This commit is contained in:
parent
f87d44d38b
commit
b6150c77f8
@ -46,6 +46,14 @@ https://next.typesafe.cn/ 账号:test 密码:test
|
|||||||
|
|
||||||
默认账号密码为 admin/admin 。
|
默认账号密码为 admin/admin 。
|
||||||
|
|
||||||
|
## 手动编译
|
||||||
|
|
||||||
|
1. 找一台Linux 机器或者Mac
|
||||||
|
2. 安装 go 1.18 或以上版本
|
||||||
|
3. 安装 nodejs 16,安装 npm 或 yarn
|
||||||
|
4. 进入 web 目录 执行 yarn install 或 npm install
|
||||||
|
5. 返回上级目录,也就是项目根目录,执行 sh build.sh
|
||||||
|
|
||||||
## 问题反馈
|
## 问题反馈
|
||||||
|
|
||||||
- Issues
|
- Issues
|
||||||
|
@ -5,12 +5,11 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/csv"
|
"encoding/csv"
|
||||||
"errors"
|
"errors"
|
||||||
"next-terminal/server/common"
|
|
||||||
"next-terminal/server/common/maps"
|
|
||||||
"next-terminal/server/common/nt"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"next-terminal/server/common/maps"
|
||||||
|
"next-terminal/server/common/nt"
|
||||||
"next-terminal/server/model"
|
"next-terminal/server/model"
|
||||||
"next-terminal/server/repository"
|
"next-terminal/server/repository"
|
||||||
"next-terminal/server/service"
|
"next-terminal/server/service"
|
||||||
@ -22,7 +21,7 @@ import (
|
|||||||
type AssetApi struct{}
|
type AssetApi struct{}
|
||||||
|
|
||||||
func (assetApi AssetApi) AssetCreateEndpoint(c echo.Context) error {
|
func (assetApi AssetApi) AssetCreateEndpoint(c echo.Context) error {
|
||||||
m := echo.Map{}
|
m := maps.Map{}
|
||||||
if err := c.Bind(&m); err != nil {
|
if err := c.Bind(&m); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -71,29 +70,31 @@ func (assetApi AssetApi) AssetImportEndpoint(c echo.Context) error {
|
|||||||
record := records[i]
|
record := records[i]
|
||||||
if len(record) >= 9 {
|
if len(record) >= 9 {
|
||||||
port, _ := strconv.Atoi(record[3])
|
port, _ := strconv.Atoi(record[3])
|
||||||
asset := model.Asset{
|
asset := maps.Map{
|
||||||
ID: utils.UUID(),
|
"id": utils.UUID(),
|
||||||
Name: record[0],
|
"name": record[0],
|
||||||
Protocol: record[1],
|
"protocol": record[1],
|
||||||
IP: record[2],
|
"ip": record[2],
|
||||||
Port: port,
|
"port": port,
|
||||||
AccountType: nt.Custom,
|
"accountType": nt.Custom,
|
||||||
Username: record[4],
|
"username": record[4],
|
||||||
Password: record[5],
|
"password": record[5],
|
||||||
PrivateKey: record[6],
|
"privateKey": record[6],
|
||||||
Passphrase: record[7],
|
"passphrase": record[7],
|
||||||
Description: record[8],
|
"Description": record[8],
|
||||||
Created: common.NowJsonTime(),
|
"owner": account.ID,
|
||||||
Owner: account.ID,
|
}
|
||||||
Active: true,
|
|
||||||
|
if record[6] != "" {
|
||||||
|
asset["accountType"] = nt.PrivateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(record) >= 10 {
|
if len(record) >= 10 {
|
||||||
tags := strings.ReplaceAll(record[9], "|", ",")
|
tags := strings.ReplaceAll(record[9], "|", ",")
|
||||||
asset.Tags = tags
|
asset["tags"] = tags
|
||||||
}
|
}
|
||||||
|
|
||||||
err := repository.AssetRepository.Create(context.TODO(), &asset)
|
_, err := service.AssetService.Create(context.Background(), asset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorCount++
|
errorCount++
|
||||||
m[strconv.Itoa(i)] = err.Error()
|
m[strconv.Itoa(i)] = err.Error()
|
||||||
@ -151,7 +152,7 @@ func (assetApi AssetApi) AssetAllEndpoint(c echo.Context) error {
|
|||||||
|
|
||||||
func (assetApi AssetApi) AssetUpdateEndpoint(c echo.Context) error {
|
func (assetApi AssetApi) AssetUpdateEndpoint(c echo.Context) error {
|
||||||
id := c.Param("id")
|
id := c.Param("id")
|
||||||
m := echo.Map{}
|
m := maps.Map{}
|
||||||
if err := c.Bind(&m); err != nil {
|
if err := c.Bind(&m); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ func (api WebTerminalApi) SshEndpoint(c echo.Context) error {
|
|||||||
|
|
||||||
s, err := service.SessionService.FindByIdAndDecrypt(ctx, sessionId)
|
s, err := service.SessionService.FindByIdAndDecrypt(ctx, sessionId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return WriteMessage(ws, dto.NewMessage(Closed, "获取会话失败"))
|
return WriteMessage(ws, dto.NewMessage(Closed, "获取会话或解密数据失败"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := api.permissionCheck(c, s.AssetId); err != nil {
|
if err := api.permissionCheck(c, s.AssetId); err != nil {
|
||||||
|
@ -9,5 +9,5 @@ var Banner = ` ___ ___
|
|||||||
\/|::/ / /:/\/__/
|
\/|::/ / /:/\/__/
|
||||||
|:/ / \/__/
|
|:/ / \/__/
|
||||||
\/__/ `
|
\/__/ `
|
||||||
var Version = `v1.3.0-beta2`
|
var Version = `v1.3.0-beta4`
|
||||||
var Hi = Banner + Version
|
var Hi = Banner + Version
|
||||||
|
@ -3,15 +3,14 @@ package repository
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"next-terminal/server/common/nt"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"next-terminal/server/common/maps"
|
||||||
|
"next-terminal/server/common/nt"
|
||||||
"next-terminal/server/config"
|
"next-terminal/server/config"
|
||||||
"next-terminal/server/model"
|
"next-terminal/server/model"
|
||||||
"next-terminal/server/utils"
|
"next-terminal/server/utils"
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var AssetRepository = new(assetRepository)
|
var AssetRepository = new(assetRepository)
|
||||||
@ -172,7 +171,7 @@ func (r assetRepository) FindTags(c context.Context) (o []string, err error) {
|
|||||||
return utils.Distinct(o), nil
|
return utils.Distinct(o), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r assetRepository) UpdateAttributes(c context.Context, assetId, protocol string, m echo.Map) error {
|
func (r assetRepository) UpdateAttributes(c context.Context, assetId, protocol string, m maps.Map) error {
|
||||||
var data []model.AssetAttribute
|
var data []model.AssetAttribute
|
||||||
var parameterNames []string
|
var parameterNames []string
|
||||||
switch protocol {
|
switch protocol {
|
||||||
@ -202,7 +201,7 @@ func (r assetRepository) UpdateAttributes(c context.Context, assetId, protocol s
|
|||||||
return r.GetDB(c).CreateInBatches(&data, len(data)).Error
|
return r.GetDB(c).CreateInBatches(&data, len(data)).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func genAttribute(assetId, name string, m echo.Map) model.AssetAttribute {
|
func genAttribute(assetId, name string, m maps.Map) model.AssetAttribute {
|
||||||
value := fmt.Sprintf("%v", m[name])
|
value := fmt.Sprintf("%v", m[name])
|
||||||
attribute := model.AssetAttribute{
|
attribute := model.AssetAttribute{
|
||||||
Id: utils.Sign([]string{assetId, name}),
|
Id: utils.Sign([]string{assetId, name}),
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"golang.org/x/net/proxy"
|
"golang.org/x/net/proxy"
|
||||||
"net"
|
"net"
|
||||||
|
"next-terminal/server/common/maps"
|
||||||
"next-terminal/server/common/nt"
|
"next-terminal/server/common/nt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
@ -18,7 +19,6 @@ import (
|
|||||||
"next-terminal/server/repository"
|
"next-terminal/server/repository"
|
||||||
"next-terminal/server/utils"
|
"next-terminal/server/utils"
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -173,22 +173,22 @@ func (s assetService) CheckStatus(asset *model.Asset, ip string, port int) (bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s assetService) Create(ctx context.Context, m echo.Map) (model.Asset, error) {
|
func (s assetService) Create(ctx context.Context, m maps.Map) (*model.Asset, error) {
|
||||||
|
|
||||||
data, err := json.Marshal(m)
|
data, err := json.Marshal(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return model.Asset{}, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var item model.Asset
|
var item model.Asset
|
||||||
if err := json.Unmarshal(data, &item); err != nil {
|
if err := json.Unmarshal(data, &item); err != nil {
|
||||||
return model.Asset{}, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
item.ID = utils.UUID()
|
item.ID = utils.UUID()
|
||||||
item.Created = common.NowJsonTime()
|
item.Created = common.NowJsonTime()
|
||||||
item.Active = true
|
item.Active = true
|
||||||
|
|
||||||
return item, s.Transaction(ctx, func(ctx context.Context) error {
|
return &item, s.Transaction(ctx, func(ctx context.Context) error {
|
||||||
if err := s.Encrypt(&item, config.GlobalCfg.EncryptionPassword); err != nil {
|
if err := s.Encrypt(&item, config.GlobalCfg.EncryptionPassword); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -222,7 +222,7 @@ func (s assetService) DeleteById(id string) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s assetService) UpdateById(id string, m echo.Map) error {
|
func (s assetService) UpdateById(id string, m maps.Map) error {
|
||||||
data, err := json.Marshal(m)
|
data, err := json.Marshal(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"next-terminal/server/common/maps"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"next-terminal/server/common"
|
"next-terminal/server/common"
|
||||||
@ -15,7 +16,6 @@ import (
|
|||||||
"next-terminal/server/repository"
|
"next-terminal/server/repository"
|
||||||
"next-terminal/server/utils"
|
"next-terminal/server/utils"
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -265,7 +265,7 @@ func (service backupService) Import(backup *dto.Backup) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
m := echo.Map{}
|
m := maps.Map{}
|
||||||
if err := json.Unmarshal(data, &m); err != nil {
|
if err := json.Unmarshal(data, &m); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1,54 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto"
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/rsa"
|
|
||||||
"crypto/sha512"
|
|
||||||
"crypto/x509"
|
|
||||||
"encoding/pem"
|
|
||||||
|
|
||||||
"github.com/denisbrodbeck/machineid"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SignatureRSA rsa私钥签名
|
|
||||||
func SignatureRSA(plainText []byte, rsaPrivateKey string) (signed []byte, err error) {
|
|
||||||
// 使用pem对读取的内容解码得到block
|
|
||||||
block, _ := pem.Decode([]byte(rsaPrivateKey))
|
|
||||||
//x509将数据解析得到私钥结构体
|
|
||||||
privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// 创建一个hash对象
|
|
||||||
h := sha512.New()
|
|
||||||
_, _ = h.Write(plainText)
|
|
||||||
// 计算hash值
|
|
||||||
hashText := h.Sum(nil)
|
|
||||||
// 使用rsa函数对散列值签名
|
|
||||||
signed, err = rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA512, hashText)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return signed, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// VerifyRSA rsa签名认证
|
|
||||||
func VerifyRSA(plainText, signText []byte, rsaPublicKey string) bool {
|
|
||||||
// pem解码得到block
|
|
||||||
block, _ := pem.Decode([]byte(rsaPublicKey))
|
|
||||||
// x509解析得到接口
|
|
||||||
publicKey, err := x509.ParsePKCS1PublicKey(block.Bytes)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// 对原始明文进行hash运算得到散列值
|
|
||||||
hashText := sha512.Sum512(plainText)
|
|
||||||
// 签名认证
|
|
||||||
err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA512, hashText[:], signText)
|
|
||||||
return err == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetMachineId() (string, error) {
|
|
||||||
return machineid.ID()
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "next-terminal",
|
"name": "next-terminal",
|
||||||
"version": "1.3.0-beta3",
|
"version": "1.3.0-beta4",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/charts": "^1.4.2",
|
"@ant-design/charts": "^1.4.2",
|
||||||
|
3
web/src/components/access/Guacd.css
Normal file
3
web/src/components/access/Guacd.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#display > div {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
@ -19,6 +19,7 @@ import Draggable from "react-draggable";
|
|||||||
import FileSystem from "../devops/FileSystem";
|
import FileSystem from "../devops/FileSystem";
|
||||||
import GuacdClipboard from "./GuacdClipboard";
|
import GuacdClipboard from "./GuacdClipboard";
|
||||||
import {debounce} from "../../utils/fun";
|
import {debounce} from "../../utils/fun";
|
||||||
|
import './Guacd.css';
|
||||||
|
|
||||||
let fixedSize = false;
|
let fixedSize = false;
|
||||||
|
|
||||||
@ -74,17 +75,15 @@ const Guacd = () => {
|
|||||||
tunnel.onerror = onError;
|
tunnel.onerror = onError;
|
||||||
|
|
||||||
// Get display div from document
|
// Get display div from document
|
||||||
const display = document.getElementById("display");
|
const displayEle = document.getElementById("display");
|
||||||
|
|
||||||
// Add client to display div
|
// Add client to display div
|
||||||
const element = client.getDisplay().getElement();
|
const element = client.getDisplay().getElement();
|
||||||
display.appendChild(element);
|
displayEle.appendChild(element);
|
||||||
|
|
||||||
let scale = 1;
|
|
||||||
let dpi = 96;
|
let dpi = 96;
|
||||||
if (protocol === 'telnet') {
|
if (protocol === 'telnet') {
|
||||||
dpi = dpi * 2;
|
dpi = dpi * 2;
|
||||||
scale = 0.5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let token = getToken();
|
let token = getToken();
|
||||||
@ -99,21 +98,31 @@ const Guacd = () => {
|
|||||||
let paramStr = qs.stringify(params);
|
let paramStr = qs.stringify(params);
|
||||||
|
|
||||||
client.connect(paramStr);
|
client.connect(paramStr);
|
||||||
|
let display = client.getDisplay();
|
||||||
|
display.onresize = function (width, height) {
|
||||||
|
display.scale(Math.min(
|
||||||
|
window.innerHeight / display.getHeight(),
|
||||||
|
window.innerWidth / display.getHeight()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
const mouse = new Guacamole.Mouse(element);
|
const mouse = new Guacamole.Mouse(element);
|
||||||
|
|
||||||
mouse.onmousedown = mouse.onmouseup = function (mouseState) {
|
mouse.onmousedown = mouse.onmouseup = mouse.onmousemove = function (mouseState) {
|
||||||
|
client.getDisplay().showCursor(false);
|
||||||
|
mouseState.x = mouseState.x / display.getScale();
|
||||||
|
mouseState.y = mouseState.y / display.getScale();
|
||||||
client.sendMouseState(mouseState);
|
client.sendMouseState(mouseState);
|
||||||
};
|
};
|
||||||
|
|
||||||
mouse.onmousemove = function (mouseState) {
|
const touch = new Guacamole.Mouse.Touchpad(element); // or Guacamole.Touchscreen
|
||||||
mouseState.x = mouseState.x / scale;
|
|
||||||
mouseState.y = mouseState.y / scale;
|
touch.onmousedown = touch.onmousemove = touch.onmouseup = function (state) {
|
||||||
client.sendMouseState(mouseState);
|
client.sendMouseState(state);
|
||||||
};
|
};
|
||||||
|
|
||||||
const sink = new Guacamole.InputSink();
|
const sink = new Guacamole.InputSink();
|
||||||
display.appendChild(sink.getElement());
|
displayEle.appendChild(sink.getElement());
|
||||||
sink.focus();
|
sink.focus();
|
||||||
|
|
||||||
const keyboard = new Guacamole.Keyboard(sink.getElement());
|
const keyboard = new Guacamole.Keyboard(sink.getElement());
|
||||||
@ -130,7 +139,6 @@ const Guacd = () => {
|
|||||||
|
|
||||||
setGuacd({
|
setGuacd({
|
||||||
client,
|
client,
|
||||||
scale,
|
|
||||||
sink,
|
sink,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -162,17 +170,12 @@ const Guacd = () => {
|
|||||||
}, [guacd])
|
}, [guacd])
|
||||||
|
|
||||||
const onWindowResize = () => {
|
const onWindowResize = () => {
|
||||||
console.log(guacd, fixedSize);
|
|
||||||
if (guacd.client && !fixedSize) {
|
if (guacd.client && !fixedSize) {
|
||||||
const display = guacd.client.getDisplay();
|
const display = guacd.client.getDisplay();
|
||||||
let scale = guacd.scale;
|
display.scale(Math.min(
|
||||||
display.scale(scale);
|
window.innerHeight / display.getHeight(),
|
||||||
let width = window.innerWidth;
|
window.innerWidth / display.getHeight()
|
||||||
let height = window.innerHeight;
|
));
|
||||||
|
|
||||||
guacd.client.sendSize(width / scale, height / scale);
|
|
||||||
|
|
||||||
setBox({width, height})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,7 +441,6 @@ const Guacd = () => {
|
|||||||
<div>
|
<div>
|
||||||
|
|
||||||
<div className="container" style={{
|
<div className="container" style={{
|
||||||
overflow: 'hidden',
|
|
||||||
width: box.width,
|
width: box.width,
|
||||||
height: box.height,
|
height: box.height,
|
||||||
margin: '0 auto'
|
margin: '0 auto'
|
||||||
|
@ -88,19 +88,6 @@ const Term = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (term && websocket && fitAddon && websocket.readyState === WebSocket.OPEN) {
|
|
||||||
fit();
|
|
||||||
focus();
|
|
||||||
let terminalSize = {
|
|
||||||
cols: term.cols,
|
|
||||||
rows: term.rows
|
|
||||||
}
|
|
||||||
websocket.send(new Message(Message.Resize, window.btoa(JSON.stringify(terminalSize))).toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
}, [box.width, box.height]);
|
|
||||||
|
|
||||||
const onWindowResize = () => {
|
const onWindowResize = () => {
|
||||||
setBox({width: window.innerWidth, height: window.innerHeight});
|
setBox({width: window.innerWidth, height: window.innerHeight});
|
||||||
};
|
};
|
||||||
@ -225,9 +212,20 @@ const Term = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = assetName;
|
document.title = assetName;
|
||||||
window.addEventListener('beforeunload', handleUnload);
|
|
||||||
|
|
||||||
init(assetId);
|
init(assetId);
|
||||||
|
}, [assetId]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (term && websocket && fitAddon && websocket.readyState === WebSocket.OPEN) {
|
||||||
|
fit();
|
||||||
|
focus();
|
||||||
|
let terminalSize = {
|
||||||
|
cols: term.cols,
|
||||||
|
rows: term.rows
|
||||||
|
}
|
||||||
|
websocket.send(new Message(Message.Resize, window.btoa(JSON.stringify(terminalSize))).toString());
|
||||||
|
}
|
||||||
|
window.addEventListener('beforeunload', handleUnload);
|
||||||
|
|
||||||
let resize = debounce(() => {
|
let resize = debounce(() => {
|
||||||
onWindowResize();
|
onWindowResize();
|
||||||
@ -242,7 +240,7 @@ const Term = () => {
|
|||||||
window.removeEventListener('resize', resize);
|
window.removeEventListener('resize', resize);
|
||||||
window.removeEventListener('beforeunload', handleUnload);
|
window.removeEventListener('beforeunload', handleUnload);
|
||||||
}
|
}
|
||||||
}, [assetId]);
|
}, [box.width, box.height]);
|
||||||
|
|
||||||
const cmdMenuItems = commands.map(item => {
|
const cmdMenuItems = commands.map(item => {
|
||||||
return {
|
return {
|
||||||
|
@ -44,6 +44,7 @@ function downloadImportExampleCsv() {
|
|||||||
|
|
||||||
const importExampleContent = <>
|
const importExampleContent = <>
|
||||||
<a onClick={downloadImportExampleCsv}>下载示例</a>
|
<a onClick={downloadImportExampleCsv}>下载示例</a>
|
||||||
|
<div>导入资产时,账号、密码和密钥、密码属于二选一,都填写时优先选择私钥和密码。</div>
|
||||||
</>
|
</>
|
||||||
|
|
||||||
const Asset = () => {
|
const Asset = () => {
|
||||||
@ -295,9 +296,9 @@ const Asset = () => {
|
|||||||
setSelectedRowKeys([]);
|
setSelectedRowKeys([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleImportAsset = (file) => {
|
const handleImportAsset = async (file) => {
|
||||||
|
|
||||||
let [success, data] = api.importAsset(file);
|
let [success, data] = await api.importAsset(file);
|
||||||
if (success === false) {
|
if (success === false) {
|
||||||
notification['error']({
|
notification['error']({
|
||||||
message: '导入资产失败',
|
message: '导入资产失败',
|
||||||
@ -320,7 +321,7 @@ const Asset = () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
actionRef.current.reload();
|
actionRef.current.reload();
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleChangeOwner = (row) => {
|
const handleChangeOwner = (row) => {
|
||||||
@ -397,6 +398,7 @@ const Asset = () => {
|
|||||||
<Upload
|
<Upload
|
||||||
maxCount={1}
|
maxCount={1}
|
||||||
beforeUpload={handleImportAsset}
|
beforeUpload={handleImportAsset}
|
||||||
|
showUploadList={false}
|
||||||
>
|
>
|
||||||
<Button key='import'>导入</Button>
|
<Button key='import'>导入</Button>
|
||||||
</Upload>
|
</Upload>
|
||||||
@ -461,6 +463,8 @@ const Asset = () => {
|
|||||||
actionRef.current.reload();
|
actionRef.current.reload();
|
||||||
} finally {
|
} finally {
|
||||||
setConfirmLoading(false);
|
setConfirmLoading(false);
|
||||||
|
setSelectedRowKey(undefined);
|
||||||
|
setCopied(false);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -116,7 +116,10 @@ const ManagerLayout = () => {
|
|||||||
<Popconfirm
|
<Popconfirm
|
||||||
key='login-btn-pop'
|
key='login-btn-pop'
|
||||||
title="您确定要退出登录吗?"
|
title="您确定要退出登录吗?"
|
||||||
onConfirm={accountApi.logout}
|
onConfirm={async ()=>{
|
||||||
|
await accountApi.logout();
|
||||||
|
navigate('/login');
|
||||||
|
}}
|
||||||
okText="确定"
|
okText="确定"
|
||||||
cancelText="取消"
|
cancelText="取消"
|
||||||
placement="left"
|
placement="left"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, {Suspense, useEffect} from 'react';
|
import React, {Suspense, useEffect} from 'react';
|
||||||
import {Link, Outlet, useLocation} from "react-router-dom";
|
import {Link, Outlet, useLocation, useNavigate} from "react-router-dom";
|
||||||
import {Breadcrumb, Button, Dropdown, Layout, Menu, Popconfirm} from "antd";
|
import {Breadcrumb, Button, Dropdown, Layout, Menu, Popconfirm} from "antd";
|
||||||
import {
|
import {
|
||||||
CodeOutlined,
|
CodeOutlined,
|
||||||
@ -27,6 +27,8 @@ const breadcrumbNameMap = {
|
|||||||
const UserLayout = () => {
|
const UserLayout = () => {
|
||||||
|
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
let _current = location.pathname.split('/')[1];
|
let _current = location.pathname.split('/')[1];
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -63,7 +65,10 @@ const UserLayout = () => {
|
|||||||
<Popconfirm
|
<Popconfirm
|
||||||
key='login-btn-pop'
|
key='login-btn-pop'
|
||||||
title="您确定要退出登录吗?"
|
title="您确定要退出登录吗?"
|
||||||
onConfirm={accountApi.logout}
|
onConfirm={async ()=>{
|
||||||
|
await accountApi.logout();
|
||||||
|
navigate('/login');
|
||||||
|
}}
|
||||||
okText="确定"
|
okText="确定"
|
||||||
cancelText="取消"
|
cancelText="取消"
|
||||||
placement="left"
|
placement="left"
|
||||||
|
Loading…
Reference in New Issue
Block a user