- 修复无法查看原生会话录屏的bug
- 优化列表显示的时间 - 优化获取开发环境的方式
This commit is contained in:
parent
b977b85cdf
commit
11d3dc167b
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,3 +4,4 @@ web/build
|
||||
*.db
|
||||
.DS_Store
|
||||
.eslintcache
|
||||
.env
|
@ -53,9 +53,10 @@ func AssetPagingEndpoint(c echo.Context) error {
|
||||
owner := c.QueryParam("owner")
|
||||
sharer := c.QueryParam("sharer")
|
||||
userGroupId := c.QueryParam("userGroupId")
|
||||
ip := c.QueryParam("ip")
|
||||
|
||||
account, _ := GetCurrentAccount(c)
|
||||
items, total, err := model.FindPageAsset(pageIndex, pageSize, name, protocol, tags, account, owner, sharer, userGroupId)
|
||||
items, total, err := model.FindPageAsset(pageIndex, pageSize, name, protocol, tags, account, owner, sharer, userGroupId, ip)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ func ErrorHandler(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
|
||||
func Auth(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
|
||||
urls := []string{"download", "recording", "login", "static", "favicon", "logo"}
|
||||
urls := []string{"download", "recording", "login", "static", "favicon", "logo", "asciinema"}
|
||||
|
||||
return func(c echo.Context) error {
|
||||
// 路由拦截 - 登录身份、资源权限判断等
|
||||
|
@ -22,12 +22,12 @@ func OverviewCounterEndPoint(c echo.Context) error {
|
||||
asset int64
|
||||
)
|
||||
if model.TypeUser == account.Type {
|
||||
countUser, _ = model.CountUser()
|
||||
countUser, _ = model.CountOnlineUser()
|
||||
countOnlineSession, _ = model.CountOnlineSession()
|
||||
credential, _ = model.CountCredentialByUserId(account.ID)
|
||||
asset, _ = model.CountAssetByUserId(account.ID)
|
||||
} else {
|
||||
countUser, _ = model.CountUser()
|
||||
countUser, _ = model.CountOnlineUser()
|
||||
countOnlineSession, _ = model.CountOnlineSession()
|
||||
credential, _ = model.CountCredential()
|
||||
asset, _ = model.CountAsset()
|
||||
|
@ -63,8 +63,8 @@ func FindAssetByConditions(protocol string, account User) (o []Asset, err error)
|
||||
return
|
||||
}
|
||||
|
||||
func FindPageAsset(pageIndex, pageSize int, name, protocol, tags string, account User, owner, sharer, userGroupId 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(resource_sharers.user_id) as sharer_count").Joins("left join users on assets.owner = users.id").Joins("left join resource_sharers on assets.id = resource_sharers.resource_id").Group("assets.id")
|
||||
func FindPageAsset(pageIndex, pageSize int, name, protocol, tags string, account User, owner, sharer, userGroupId, ip 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,assets.tags, users.nickname as owner_name,COUNT(resource_sharers.user_id) as sharer_count").Joins("left join users on assets.owner = users.id").Joins("left join resource_sharers on assets.id = resource_sharers.resource_id").Group("assets.id")
|
||||
dbCounter := global.DB.Table("assets").Select("DISTINCT assets.id").Joins("left join resource_sharers on assets.id = resource_sharers.resource_id").Group("assets.id")
|
||||
|
||||
if TypeUser == account.Type {
|
||||
@ -103,6 +103,11 @@ func FindPageAsset(pageIndex, pageSize int, name, protocol, tags string, account
|
||||
dbCounter = dbCounter.Where("assets.name like ?", "%"+name+"%")
|
||||
}
|
||||
|
||||
if len(ip) > 0 {
|
||||
db = db.Where("assets.ip like ?", "%"+ip+"%")
|
||||
dbCounter = dbCounter.Where("assets.ip like ?", "%"+ip+"%")
|
||||
}
|
||||
|
||||
if len(protocol) > 0 {
|
||||
db = db.Where("assets.protocol = ?", protocol)
|
||||
dbCounter = dbCounter.Where("assets.protocol = ?", protocol)
|
||||
|
@ -107,7 +107,7 @@ func DeleteUserById(id string) {
|
||||
global.DB.Where("user_id = ?", id).Delete(&ResourceSharer{})
|
||||
}
|
||||
|
||||
func CountUser() (total int64, err error) {
|
||||
err = global.DB.Find(&User{}).Count(&total).Error
|
||||
func CountOnlineUser() (total int64, err error) {
|
||||
err = global.DB.Where("online = ?", true).Find(&User{}).Count(&total).Error
|
||||
return
|
||||
}
|
||||
|
8
web/package-lock.json
generated
8
web/package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "next-terminal",
|
||||
"version": "0.1.1",
|
||||
"version": "0.2.4",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@ -5363,9 +5363,9 @@
|
||||
"integrity": "sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ=="
|
||||
},
|
||||
"dayjs": {
|
||||
"version": "1.9.6",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.9.6.tgz",
|
||||
"integrity": "sha512-HngNLtPEBWRo8EFVmHFmSXAjtCX8rGNqeXQI0Gh7wCTSqwaKgPIDqu9m07wABVopNwzvOeCb+2711vQhDlcIXw=="
|
||||
"version": "1.10.4",
|
||||
"resolved": "https://registry.npm.taobao.org/dayjs/download/dayjs-1.10.4.tgz?cache=0&sync_timestamp=1611309982734&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdayjs%2Fdownload%2Fdayjs-1.10.4.tgz",
|
||||
"integrity": "sha1-jlRKm4aD9heD9XCYCoqA6vVKseI="
|
||||
},
|
||||
"debug": {
|
||||
"version": "3.1.0",
|
||||
|
@ -6,6 +6,7 @@
|
||||
"@ant-design/icons": "^4.3.0",
|
||||
"antd": "^4.8.4",
|
||||
"axios": "^0.21.1",
|
||||
"dayjs": "^1.10.4",
|
||||
"guacamole-common-js": "^1.2.0",
|
||||
"qs": "^6.9.4",
|
||||
"react": "^16.14.0",
|
||||
|
@ -1,22 +1,5 @@
|
||||
// prod
|
||||
let wsPrefix;
|
||||
if (window.location.protocol === 'https:') {
|
||||
wsPrefix = 'wss:'
|
||||
} else {
|
||||
wsPrefix = 'ws:'
|
||||
}
|
||||
|
||||
export const server = '';
|
||||
export const wsServer = wsPrefix + window.location.host;
|
||||
export const prefix = window.location.protocol + '//' + window.location.host;
|
||||
|
||||
// dev
|
||||
// export const server = '//127.0.0.1:8088';
|
||||
// export const wsServer = 'ws://127.0.0.1:8088';
|
||||
// export const prefix = '';
|
||||
|
||||
export const PROTOCOL_COLORS = {
|
||||
'rdp': 'red',
|
||||
'rdp': 'cyan',
|
||||
'ssh': 'blue',
|
||||
'telnet': 'geekblue',
|
||||
'vnc': 'purple'
|
||||
|
28
web/src/common/env.js
Normal file
28
web/src/common/env.js
Normal file
@ -0,0 +1,28 @@
|
||||
function env() {
|
||||
if (process.env.REACT_APP_ENV === 'development') {
|
||||
// 本地开发环境
|
||||
return {
|
||||
server: '//127.0.0.1:8088',
|
||||
wsServer: 'ws://127.0.0.1:8088',
|
||||
prefix: '',
|
||||
}
|
||||
} else {
|
||||
// 生产环境
|
||||
let wsPrefix;
|
||||
if (window.location.protocol === 'https:') {
|
||||
wsPrefix = 'wss:'
|
||||
} else {
|
||||
wsPrefix = 'ws:'
|
||||
}
|
||||
return {
|
||||
server: '',
|
||||
wsServer: wsPrefix + window.location.host,
|
||||
prefix: window.location.protocol + '//' + window.location.host,
|
||||
}
|
||||
}
|
||||
}
|
||||
export default env();
|
||||
|
||||
export const server = env().server;
|
||||
export const wsServer = env().wsServer;
|
||||
export const prefix = env().prefix;
|
@ -1,5 +1,5 @@
|
||||
import axios from 'axios'
|
||||
import {server} from "./constants";
|
||||
import {server} from "./env";
|
||||
import {message} from 'antd';
|
||||
import {getHeaders} from "../utils/utils";
|
||||
|
||||
|
@ -3,7 +3,7 @@ import Guacamole from 'guacamole-common-js';
|
||||
import {Affix, Button, Col, Drawer, Dropdown, Form, Input, Menu, message, Modal, Row} from 'antd'
|
||||
import qs from "qs";
|
||||
import request from "../../common/request";
|
||||
import {wsServer} from "../../common/constants";
|
||||
import {wsServer} from "../../common/env";
|
||||
import {
|
||||
AppstoreTwoTone,
|
||||
CopyTwoTone,
|
||||
|
@ -2,7 +2,7 @@ import React, {Component} from 'react';
|
||||
import "xterm/css/xterm.css"
|
||||
import {Terminal} from "xterm";
|
||||
import qs from "qs";
|
||||
import {wsServer} from "../../common/constants";
|
||||
import {wsServer} from "../../common/env";
|
||||
import "./Console.css"
|
||||
import {getToken, isEmpty} from "../../utils/utils";
|
||||
import {FitAddon} from 'xterm-addon-fit'
|
||||
|
@ -22,7 +22,7 @@ import {
|
||||
} from "@ant-design/icons";
|
||||
import qs from "qs";
|
||||
import request from "../../common/request";
|
||||
import {server} from "../../common/constants";
|
||||
import {server} from "../../common/env";
|
||||
import Upload from "antd/es/upload";
|
||||
import {download, getFileName, getToken, isEmpty, renderSize} from "../../utils/utils";
|
||||
import './FileSystem.css'
|
||||
@ -107,7 +107,7 @@ class FileSystem extends Component {
|
||||
if (isEmpty(key)) {
|
||||
key = '/';
|
||||
}
|
||||
let result = await request.get(`${server}/sessions/${this.state.sessionId}/ls?dir=${key}`);
|
||||
let result = await request.get(`/sessions/${this.state.sessionId}/ls?dir=${key}`);
|
||||
if (result['code'] !== 1) {
|
||||
message.error(result['message']);
|
||||
return;
|
||||
|
@ -2,7 +2,7 @@ import React, {Component} from 'react';
|
||||
import Guacamole from 'guacamole-common-js';
|
||||
import {Modal, Result, Spin} from 'antd'
|
||||
import qs from "qs";
|
||||
import {wsServer} from "../../common/constants";
|
||||
import {wsServer} from "../../common/env";
|
||||
import {getToken} from "../../utils/utils";
|
||||
import './Access.css'
|
||||
|
||||
|
@ -2,7 +2,7 @@ import React, {Component} from 'react';
|
||||
import "xterm/css/xterm.css"
|
||||
import {Terminal} from "xterm";
|
||||
import qs from "qs";
|
||||
import {wsServer} from "../../common/constants";
|
||||
import {wsServer} from "../../common/env";
|
||||
import {getToken, isEmpty} from "../../utils/utils";
|
||||
import {FitAddon} from 'xterm-addon-fit';
|
||||
import "./Access.css"
|
||||
|
@ -26,9 +26,8 @@ import qs from "qs";
|
||||
import AssetModal from "./AssetModal";
|
||||
import request from "../../common/request";
|
||||
import {message} from "antd/es";
|
||||
import {itemRender} from "../../utils/utils";
|
||||
|
||||
|
||||
import {isEmpty, itemRender} from "../../utils/utils";
|
||||
import dayjs from 'dayjs';
|
||||
import {
|
||||
DeleteOutlined,
|
||||
DownOutlined,
|
||||
@ -41,6 +40,7 @@ import {PROTOCOL_COLORS} from "../../common/constants";
|
||||
import Logout from "../user/Logout";
|
||||
import {hasPermission, isAdmin} from "../../service/permission";
|
||||
|
||||
|
||||
const confirm = Modal.confirm;
|
||||
const {Search} = Input;
|
||||
const {Content} = Layout;
|
||||
@ -59,6 +59,7 @@ const routes = [
|
||||
class Asset extends Component {
|
||||
|
||||
inputRefOfName = React.createRef();
|
||||
inputRefOfIp = React.createRef();
|
||||
changeOwnerFormRef = React.createRef();
|
||||
|
||||
state = {
|
||||
@ -172,6 +173,17 @@ class Asset extends Component {
|
||||
this.loadTableData(query);
|
||||
};
|
||||
|
||||
handleSearchByIp = ip => {
|
||||
let query = {
|
||||
...this.state.queryParams,
|
||||
'pageIndex': 1,
|
||||
'pageSize': this.state.queryParams.pageSize,
|
||||
'ip': ip,
|
||||
}
|
||||
|
||||
this.loadTableData(query);
|
||||
};
|
||||
|
||||
handleTagsChange = tags => {
|
||||
this.setState({
|
||||
selectedTags: tags
|
||||
@ -459,18 +471,48 @@ class Asset extends Component {
|
||||
dataIndex: 'protocol',
|
||||
key: 'protocol',
|
||||
render: (text, record) => {
|
||||
|
||||
return (<Tag color={PROTOCOL_COLORS[text]}>{text}</Tag>);
|
||||
const title = `${record['ip'] + ':' + record['port']}`
|
||||
return (
|
||||
<Tooltip title={title}>
|
||||
<Tag color={PROTOCOL_COLORS[text]}>{text}</Tag>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
}, {
|
||||
title: '标签',
|
||||
dataIndex: 'tags',
|
||||
key: 'tags',
|
||||
render: tags => {
|
||||
if (!isEmpty(tags)) {
|
||||
let tagDocuments = []
|
||||
let tagArr = tags.split(',');
|
||||
for (let i = 0; i < tagArr.length; i++) {
|
||||
if (tags[i] === '-') {
|
||||
continue;
|
||||
}
|
||||
tagDocuments.push(<Tag>{tagArr[i]}</Tag>)
|
||||
}
|
||||
return tagDocuments;
|
||||
}
|
||||
}
|
||||
}, {
|
||||
title: '状态',
|
||||
dataIndex: 'active',
|
||||
key: 'active',
|
||||
render: text => {
|
||||
|
||||
if (text) {
|
||||
return (<Badge status="processing" text="运行中"/>);
|
||||
return (
|
||||
<Tooltip title='运行中'>
|
||||
<Badge status="processing"/>
|
||||
</Tooltip>
|
||||
)
|
||||
} else {
|
||||
return (<Badge status="error" text="不可用"/>);
|
||||
return (
|
||||
<Tooltip title='不可用'>
|
||||
<Badge status="error"/>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
}
|
||||
}, {
|
||||
@ -480,7 +522,14 @@ class Asset extends Component {
|
||||
}, {
|
||||
title: '创建日期',
|
||||
dataIndex: 'created',
|
||||
key: 'created'
|
||||
key: 'created',
|
||||
render: (text, record) => {
|
||||
return (
|
||||
<Tooltip title={text}>
|
||||
{dayjs(text).fromNow()}
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
@ -598,10 +647,10 @@ class Asset extends Component {
|
||||
<Content key='page-content' className="site-layout-background page-content">
|
||||
<div style={{marginBottom: 20}}>
|
||||
<Row justify="space-around" align="middle" gutter={24}>
|
||||
<Col span={8} key={1}>
|
||||
<Col span={4} key={1}>
|
||||
<Title level={3}>资产列表</Title>
|
||||
</Col>
|
||||
<Col span={16} key={2} style={{textAlign: 'right'}}>
|
||||
<Col span={20} key={2} style={{textAlign: 'right'}}>
|
||||
<Space>
|
||||
|
||||
<Search
|
||||
@ -609,6 +658,15 @@ class Asset extends Component {
|
||||
placeholder="资产名称"
|
||||
allowClear
|
||||
onSearch={this.handleSearchByName}
|
||||
style={{width: 200}}
|
||||
/>
|
||||
|
||||
<Search
|
||||
ref={this.inputRefOfIp}
|
||||
placeholder="资产IP"
|
||||
allowClear
|
||||
onSearch={this.handleSearchByIp}
|
||||
style={{width: 200}}
|
||||
/>
|
||||
|
||||
<Select mode="multiple"
|
||||
@ -638,6 +696,7 @@ class Asset extends Component {
|
||||
|
||||
<Button icon={<UndoOutlined/>} onClick={() => {
|
||||
this.inputRefOfName.current.setValue('');
|
||||
this.inputRefOfIp.current.setValue('');
|
||||
this.setState({
|
||||
selectedTags: []
|
||||
})
|
||||
|
@ -36,6 +36,7 @@ import {
|
||||
import {compare, itemRender} from "../../utils/utils";
|
||||
import Logout from "../user/Logout";
|
||||
import {hasPermission, isAdmin} from "../../service/permission";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
const confirm = Modal.confirm;
|
||||
const {Content} = Layout;
|
||||
@ -403,7 +404,14 @@ class DynamicCommand extends Component {
|
||||
}, {
|
||||
title: '创建日期',
|
||||
dataIndex: 'created',
|
||||
key: 'created'
|
||||
key: 'created',
|
||||
render: (text, record) => {
|
||||
return (
|
||||
<Tooltip title={text}>
|
||||
{dayjs(text).fromNow()}
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
}, {
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
|
@ -35,6 +35,7 @@ import {
|
||||
import {itemRender} from "../../utils/utils";
|
||||
import Logout from "../user/Logout";
|
||||
import {hasPermission, isAdmin} from "../../service/permission";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
const confirm = Modal.confirm;
|
||||
const {Search} = Input;
|
||||
@ -375,6 +376,13 @@ class Credential extends Component {
|
||||
title: '创建时间',
|
||||
dataIndex: 'created',
|
||||
key: 'created',
|
||||
render: (text, record) => {
|
||||
return (
|
||||
<Tooltip title={text}>
|
||||
{dayjs(text).fromNow()}
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
|
@ -18,12 +18,13 @@ import {
|
||||
} from "antd";
|
||||
import qs from "qs";
|
||||
import request from "../../common/request";
|
||||
import {differTime, formatDate, itemRender} from "../../utils/utils";
|
||||
import {differTime, itemRender} from "../../utils/utils";
|
||||
import Playback from "./Playback";
|
||||
import {message} from "antd/es";
|
||||
import {DeleteOutlined, ExclamationCircleOutlined, SyncOutlined, UndoOutlined} from "@ant-design/icons";
|
||||
import {PROTOCOL_COLORS} from "../../common/constants";
|
||||
import Logout from "../user/Logout";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
const confirm = Modal.confirm;
|
||||
const {Content} = Layout;
|
||||
@ -244,29 +245,28 @@ class OfflineSession extends Component {
|
||||
title: '资产名称',
|
||||
dataIndex: 'assetName',
|
||||
key: 'assetName'
|
||||
}, {
|
||||
title: '远程连接',
|
||||
dataIndex: 'access',
|
||||
key: 'access',
|
||||
render: (text, record) => {
|
||||
|
||||
return `${record.username}@${record.ip}:${record.port}`;
|
||||
}
|
||||
}, {
|
||||
title: '连接协议',
|
||||
dataIndex: 'protocol',
|
||||
key: 'protocol',
|
||||
render: (text, record) => {
|
||||
|
||||
return (<Tag color={PROTOCOL_COLORS[text]}>{text}</Tag>);
|
||||
const title = `${record.username}@${record.ip}:${record.port}`;
|
||||
return (
|
||||
<Tooltip title={title}>
|
||||
<Tag color={PROTOCOL_COLORS[text]}>{text}</Tag>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
}, {
|
||||
title: '接入时间',
|
||||
dataIndex: 'connectedTime',
|
||||
key: 'connectedTime',
|
||||
render: (text, record) => {
|
||||
|
||||
return formatDate(text, 'yyyy-MM-dd hh:mm:ss');
|
||||
return (
|
||||
<Tooltip title={text}>
|
||||
{dayjs(text).fromNow()}
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
}, {
|
||||
title: '接入时长',
|
||||
|
@ -19,12 +19,13 @@ import {
|
||||
} from "antd";
|
||||
import qs from "qs";
|
||||
import request from "../../common/request";
|
||||
import {differTime, formatDate, itemRender} from "../../utils/utils";
|
||||
import {differTime, itemRender} from "../../utils/utils";
|
||||
import {message} from "antd/es";
|
||||
import {PROTOCOL_COLORS} from "../../common/constants";
|
||||
import {DisconnectOutlined, ExclamationCircleOutlined, SyncOutlined, UndoOutlined} from "@ant-design/icons";
|
||||
import Monitor from "../access/Monitor";
|
||||
import Logout from "../user/Logout";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
const confirm = Modal.confirm;
|
||||
const {Content} = Layout;
|
||||
@ -241,29 +242,28 @@ class OnlineSession extends Component {
|
||||
title: '资产名称',
|
||||
dataIndex: 'assetName',
|
||||
key: 'assetName'
|
||||
}, {
|
||||
title: '远程连接',
|
||||
dataIndex: 'access',
|
||||
key: 'access',
|
||||
render: (text, record) => {
|
||||
|
||||
return `${record.username}@${record.ip}:${record.port}`;
|
||||
}
|
||||
}, {
|
||||
title: '连接协议',
|
||||
dataIndex: 'protocol',
|
||||
key: 'protocol',
|
||||
render: (text, record) => {
|
||||
|
||||
return (<Tag color={PROTOCOL_COLORS[text]}>{text}</Tag>);
|
||||
const title = `${record.username}@${record.ip}:${record.port}`;
|
||||
return (
|
||||
<Tooltip title={title}>
|
||||
<Tag color={PROTOCOL_COLORS[text]}>{text}</Tag>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
}, {
|
||||
title: '接入时间',
|
||||
dataIndex: 'connectedTime',
|
||||
key: 'connectedTime',
|
||||
render: (text, record) => {
|
||||
|
||||
return formatDate(text, 'yyyy-MM-dd hh:mm:ss');
|
||||
return (
|
||||
<Tooltip title={text}>
|
||||
{dayjs(text).fromNow()}
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
}, {
|
||||
title: '接入时长',
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, {Component} from 'react';
|
||||
import Guacamole from "guacamole-common-js";
|
||||
import {server} from "../../common/constants";
|
||||
import server from "../../common/env";
|
||||
import {Button, Col, Row, Slider, Typography} from "antd";
|
||||
import {PauseCircleOutlined, PlayCircleOutlined} from '@ant-design/icons';
|
||||
import {Tooltip} from "antd/lib/index";
|
||||
|
@ -36,6 +36,7 @@ import {
|
||||
import Logout from "./Logout";
|
||||
import UserShareAsset from "./UserShareAsset";
|
||||
import {hasPermission} from "../../service/permission";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
const confirm = Modal.confirm;
|
||||
const {Search} = Input;
|
||||
@ -342,7 +343,14 @@ class User extends Component {
|
||||
}, {
|
||||
title: '创建日期',
|
||||
dataIndex: 'created',
|
||||
key: 'created'
|
||||
key: 'created',
|
||||
render: (text, record) => {
|
||||
return (
|
||||
<Tooltip title={text}>
|
||||
{dayjs(text).fromNow()}
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
|
@ -9,6 +9,7 @@ import {DeleteOutlined, ExclamationCircleOutlined, PlusOutlined, SyncOutlined, U
|
||||
import Logout from "./Logout";
|
||||
import UserGroupModal from "./UserGroupModal";
|
||||
import UserShareAsset from "./UserShareAsset";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
const confirm = Modal.confirm;
|
||||
const {Search} = Input;
|
||||
@ -285,7 +286,14 @@ class UserGroup extends Component {
|
||||
}, {
|
||||
title: '创建日期',
|
||||
dataIndex: 'created',
|
||||
key: 'created'
|
||||
key: 'created',
|
||||
render: (text, record) => {
|
||||
return (
|
||||
<Tooltip title={text}>
|
||||
{dayjs(text).fromNow()}
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
|
@ -6,6 +6,12 @@ import * as serviceWorker from './serviceWorker';
|
||||
import zhCN from 'antd/es/locale-provider/zh_CN';
|
||||
import {ConfigProvider} from 'antd';
|
||||
import {HashRouter as Router} from "react-router-dom";
|
||||
import dayjs from "dayjs";
|
||||
import relativeTime from "dayjs/plugin/relativeTime";
|
||||
import 'dayjs/locale/zh-cn'
|
||||
|
||||
dayjs.extend(relativeTime);
|
||||
dayjs.locale('zh-cn');
|
||||
|
||||
ReactDOM.render(
|
||||
<ConfigProvider locale={zhCN}>
|
||||
|
Loading…
Reference in New Issue
Block a user