🎨 粘贴安全策略提示.
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
mv ../../orion-ops-launch/target/orion-ops-launch.jar ./
|
||||
mv ../../orion-ops-ui/dist ./dist
|
||||
docker build -t orion-ops-pro:1.0.2 .
|
||||
docker build -t orion-ops-pro:1.0.3 .
|
||||
|
||||
@@ -2,18 +2,20 @@
|
||||
|
||||
## v1.0.3
|
||||
|
||||
`2024-03-2` `release`
|
||||
`2024-03-24` `release`
|
||||
|
||||
* 🚀 升级 `arco design` 到 `2.55.0`
|
||||
* 🐞 修复 新创建的用户登录会跳转到 **404**
|
||||
* 🐞 修复 分配菜单模态框没有子菜单不显示的问题
|
||||
* 🐞 修复 终端无法粘贴
|
||||
* 🐞 修复 `工作台` `快捷操作` 会展示隐藏的菜单
|
||||
* 🐞 修复 工作台页面快捷操作面板会展示隐藏的菜单
|
||||
* 🐞 修复 主机终端无法粘贴
|
||||
* 🐞 修复 卡片列表组件控制台 warn 提示
|
||||
* 🐞 修复 关闭终端时控制台提示 handleResize 错误信息
|
||||
* 🔨 修改 系统菜单渲染逻辑 (移除 JSX 构建时不会提示 JSX.IntrinsicElements)
|
||||
|
||||
[如何升级](/about/update.md?id=_v103)
|
||||
|
||||
## v1.0.2
|
||||
## v1.0.3
|
||||
|
||||
`2024-03-22` `release`
|
||||
|
||||
|
||||
@@ -12,3 +12,7 @@
|
||||
* 资产授权 UI 改版
|
||||
* RDP 远程桌面
|
||||
* 接入 config 后端动态配置
|
||||
|
||||
## 已知问题 🐞
|
||||
|
||||
* 顶部菜单折叠宽度计算有问题 (arco 框架内问题)
|
||||
|
||||
@@ -26,6 +26,8 @@ import java.util.List;
|
||||
@Component
|
||||
public class SftpListHandler extends AbstractTerminalHandler<SftpListRequest> {
|
||||
|
||||
private static final String HOME_PATH = "~";
|
||||
|
||||
@Override
|
||||
public void handle(WebSocketSession channel, SftpListRequest payload) {
|
||||
// 获取会话
|
||||
@@ -37,7 +39,7 @@ public class SftpListHandler extends AbstractTerminalHandler<SftpListRequest> {
|
||||
List<SftpFileVO> list = Lists.empty();
|
||||
try {
|
||||
// 空目录则直接获取 home 目录
|
||||
if (Strings.isBlank(path)) {
|
||||
if (HOME_PATH.equals(path)) {
|
||||
path = session.getHome();
|
||||
}
|
||||
// 文件列表
|
||||
|
||||
@@ -272,7 +272,9 @@ export default class LogAppender implements ILogAppender {
|
||||
.filter(Boolean)
|
||||
.forEach(s => s.dispose());
|
||||
// 卸载终端
|
||||
s.terminal?.dispose();
|
||||
setTimeout(() => {
|
||||
s.terminal?.dispose();
|
||||
}, 300);
|
||||
} catch (e) {
|
||||
// 卸载可能会报错
|
||||
}
|
||||
|
||||
@@ -49,7 +49,10 @@
|
||||
'field-value',
|
||||
field.ellipsis ? 'field-value-ellipsis' : ''
|
||||
]">
|
||||
<slot :name="field.slotName" :record="item" :index="index" :key="item[key as string]">
|
||||
<slot :name="field.slotName"
|
||||
:record="item"
|
||||
:index="index"
|
||||
:rowKey="item[rowKey as string]">
|
||||
<a-tooltip v-if="field.tooltip" :content="item[field.dataIndex]">
|
||||
<span v-if="field.render" v-html="field.render({ record: item, index })" />
|
||||
<span v-else>{{ item[field.dataIndex] }}</span>
|
||||
@@ -87,7 +90,7 @@
|
||||
|
||||
const props = defineProps<CardProps & {
|
||||
index: number,
|
||||
item: CardRecord
|
||||
item: CardRecord,
|
||||
}>();
|
||||
const emits = defineEmits(['emitter']);
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
</a-col>
|
||||
<!-- 数据卡片 -->
|
||||
<a-col v-for="(item, index) in list"
|
||||
:key="item[key]"
|
||||
:key="item[rowKey]"
|
||||
v-bind="cardLayoutCols"
|
||||
:class="{ 'disabled-col': item.disabled === true }">
|
||||
<!-- 右键菜单 -->
|
||||
@@ -41,12 +41,18 @@
|
||||
@emitter="dispatchEmitter">
|
||||
<!-- 自定义插槽 -->
|
||||
<template v-for="slot in Object.keys($slots)" :key="slot" #[slot]>
|
||||
<slot :name="slot" :record="item" :index="index" :key="item[key]" />
|
||||
<slot :name="slot"
|
||||
:record="item"
|
||||
:index="index"
|
||||
:rowKey="item[rowKey]" />
|
||||
</template>
|
||||
</card-item>
|
||||
<!-- 右键菜单 -->
|
||||
<template v-if="contextMenu" #content>
|
||||
<slot name="contextMenu" :record="item" :index="index" :key="item[key]" />
|
||||
<slot name="contextMenu"
|
||||
:record="item"
|
||||
:index="index"
|
||||
:rowKey="item[rowKey]" />
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</a-col>
|
||||
@@ -82,7 +88,7 @@
|
||||
import useEmitter from '@/hooks/emitter';
|
||||
|
||||
const props = withDefaults(defineProps<CardProps>(), {
|
||||
key: 'id',
|
||||
rowKey: 'id',
|
||||
pagination: false,
|
||||
loading: false,
|
||||
cardHeight: '100%',
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { CardFieldConfig, CardPosition, CardRecord, ColResponsiveValue, Han
|
||||
|
||||
// 卡片属性
|
||||
export interface CardProps {
|
||||
key?: string;
|
||||
rowKey?: string;
|
||||
pagination?: PaginationProps | boolean;
|
||||
loading?: boolean;
|
||||
fieldConfig?: CardFieldConfig;
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
</a-watermark>
|
||||
</a-layout-content>
|
||||
<!-- 页脚 -->
|
||||
<footer v-if="visibleFooter" />
|
||||
<app-footer v-if="visibleFooter" />
|
||||
</a-layout>
|
||||
</a-layout>
|
||||
</a-layout>
|
||||
@@ -61,8 +61,8 @@
|
||||
import { toggleDrawerMenuKey } from '@/types/symbol';
|
||||
import PageLayout from './page-layout.vue';
|
||||
import NavBar from '@/components/app/navbar/index.vue';
|
||||
import Footer from '@/components/app/footer/index.vue';
|
||||
import TabBar from '@/components/app/tab-bar/index.vue';
|
||||
import AppFooter from '@/components/app/app-footer/index.vue';
|
||||
import SystemMenuTree from '@/components/system/menu/tree/index.vue';
|
||||
|
||||
const appStore = useAppStore();
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
const debug = import.meta.env.MODE !== 'production';
|
||||
|
||||
// 当前环境是否为安全环境
|
||||
export const isSecureEnvironment = (() => {
|
||||
return window.location.protocol === 'https:' || window.location.hostname === 'localhost';
|
||||
})();
|
||||
|
||||
// http base url
|
||||
export const httpBaseUrl = (() => {
|
||||
const configBase = import.meta.env.VITE_API_BASE_URL;
|
||||
|
||||
@@ -8,16 +8,16 @@
|
||||
<div class="logo-text">Orion Ops Pro</div>
|
||||
</div>
|
||||
<!-- 左侧 banner -->
|
||||
<LoginBanner />
|
||||
<login-banner />
|
||||
<!-- 主体部分 -->
|
||||
<div class="content">
|
||||
<div class="content-inner">
|
||||
<!-- 登录表单 -->
|
||||
<LoginForm />
|
||||
<login-form />
|
||||
</div>
|
||||
<!-- 页脚 -->
|
||||
<div class="footer">
|
||||
<Footer />
|
||||
<app-footer />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -26,9 +26,9 @@
|
||||
<script lang="ts" setup>
|
||||
import { Notification } from '@arco-design/web-vue';
|
||||
import { reLoginTipsKey } from '@/types/symbol';
|
||||
import Footer from '@/components/app/footer/index.vue';
|
||||
import LoginBanner from './components/banner.vue';
|
||||
import LoginForm from './components/login-form.vue';
|
||||
import AppFooter from '@/components/app/app-footer/index.vue';
|
||||
|
||||
// 登录提示
|
||||
const tips = window.sessionStorage.getItem(reLoginTipsKey);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="top-side">
|
||||
<!-- 提示 -->
|
||||
<div class="panel">
|
||||
<Banner />
|
||||
<banner />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-wrapper">
|
||||
|
||||
@@ -13,7 +13,12 @@
|
||||
</div>
|
||||
<!-- 描述 -->
|
||||
<div class="block-form-item-desc">
|
||||
{{ desc }}
|
||||
<template v-if="desc">
|
||||
{{ desc }}
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot name="desc" />
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</a-col>
|
||||
@@ -29,13 +34,14 @@
|
||||
|
||||
defineProps<{
|
||||
label: string,
|
||||
desc: string,
|
||||
desc?: string,
|
||||
}>();
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.block-form-item-wrapper {
|
||||
width: 458px;
|
||||
height: 100%;
|
||||
min-height: 64px;
|
||||
border-radius: 4px;
|
||||
|
||||
@@ -8,6 +8,12 @@
|
||||
</div>
|
||||
<!-- 提示 -->
|
||||
<a-alert class="mb16">修改后会立刻保存, 立即生效 (无需刷新页面)</a-alert>
|
||||
<!-- 非安全环境提示 -->
|
||||
<a-alert v-if="!isSecureEnvironment"
|
||||
type="warning"
|
||||
class="mb16">
|
||||
当前环境非 HTTPS 环境, 因浏览器安全策略限制, '粘贴' 功能无法使用
|
||||
</a-alert>
|
||||
<!-- 内容区域 -->
|
||||
<div class="terminal-setting-body block-body setting-body">
|
||||
<a-form class="terminal-setting-form"
|
||||
@@ -52,6 +58,7 @@
|
||||
import { useTerminalStore } from '@/store';
|
||||
import { TerminalPreferenceItem } from '@/store/modules/terminal';
|
||||
import { ActionBarItems } from '../../../types/terminal.const';
|
||||
import { isSecureEnvironment } from '@/utils/env';
|
||||
import IconActions from '../../layout/icon-actions.vue';
|
||||
|
||||
const { preference, updateTerminalPreference } = useTerminalStore();
|
||||
|
||||
@@ -8,6 +8,12 @@
|
||||
</div>
|
||||
<!-- 提示 -->
|
||||
<a-alert class="mb16">修改后会立刻保存, 重新打开终端后生效 (无需刷新页面)</a-alert>
|
||||
<!-- 非安全环境提示 -->
|
||||
<a-alert v-if="!isSecureEnvironment"
|
||||
type="warning"
|
||||
class="mb16">
|
||||
当前环境非 HTTPS 环境, 因浏览器安全策略限制, '粘贴' 功能无法使用
|
||||
</a-alert>
|
||||
<!-- 内容区域 -->
|
||||
<div class="terminal-setting-body block-body setting-body">
|
||||
<!-- 功能项 -->
|
||||
@@ -84,6 +90,7 @@
|
||||
import { useTerminalStore } from '@/store';
|
||||
import { TerminalPreferenceItem } from '@/store/modules/terminal';
|
||||
import { ActionBarItems } from '../../../types/terminal.const';
|
||||
import { isSecureEnvironment } from '@/utils/env';
|
||||
|
||||
const { preference, updateTerminalPreference } = useTerminalStore();
|
||||
|
||||
|
||||
@@ -8,6 +8,12 @@
|
||||
</div>
|
||||
<!-- 提示 -->
|
||||
<a-alert class="mb16">修改后会立刻保存, 刷新页面后生效</a-alert>
|
||||
<!-- 非安全环境提示 -->
|
||||
<a-alert v-if="!isSecureEnvironment"
|
||||
type="warning"
|
||||
class="mb16">
|
||||
当前环境非 HTTPS 环境, 因浏览器安全策略限制, '粘贴' 功能无法使用
|
||||
</a-alert>
|
||||
<!-- 内容区域 -->
|
||||
<div class="terminal-setting-body setting-body">
|
||||
<a-row class="mb16" align="stretch" :gutter="16">
|
||||
@@ -40,23 +46,29 @@
|
||||
<a-switch type="round"
|
||||
v-model="formModel.copyAutoTrim" />
|
||||
</block-setting-item>
|
||||
<!-- 粘贴去除空格 -->
|
||||
<block-setting-item label="粘贴去除空格" desc="粘贴文本前自动删除尾部空格 如: 命令输入框, 命令编辑器, 右键粘贴, 粘贴按钮, 右键菜单粘贴, 自定义粘贴快捷键 (内置粘贴快捷键因浏览器限制不会去除)">
|
||||
<a-switch type="round"
|
||||
v-model="formModel.pasteAutoTrim" />
|
||||
</block-setting-item>
|
||||
</a-row>
|
||||
<a-row class="mb16" align="stretch" :gutter="16">
|
||||
<!-- 右键粘贴 -->
|
||||
<block-setting-item label="右键粘贴" desc="右键自动粘贴, 启用后需要关闭右键菜单 (若开启了右键选中词条, 有选中的文本时, 右键粘贴无效)">
|
||||
<a-switch type="round"
|
||||
v-model="formModel.rightClickPaste" />
|
||||
</block-setting-item>
|
||||
<!-- 启用右键菜单 -->
|
||||
<block-setting-item label="启用右键菜单" desc="右键终端将打开自定义菜单, 启用后需要关闭右键粘贴">
|
||||
<a-switch type="round"
|
||||
v-model="formModel.enableRightClickMenu" />
|
||||
</block-setting-item>
|
||||
|
||||
</a-row>
|
||||
<a-row class="mb16" align="stretch" :gutter="16">
|
||||
<!-- 右键粘贴 -->
|
||||
<block-setting-item label="右键粘贴"
|
||||
desc="启用右键自动粘贴需要关闭右键菜单. 如果启用右键选中词条且选中有文本时, 右键粘贴无效. 因浏览器安全策略限制, 此功能需要在 HTTPS 环境下使用">
|
||||
<a-switch type="round"
|
||||
v-model="formModel.rightClickPaste" />
|
||||
</block-setting-item>
|
||||
<!-- 粘贴去除空格 -->
|
||||
<block-setting-item label="粘贴去除空格"
|
||||
desc="粘贴文本前自动删除尾部空格 如: 命令输入框, 命令编辑器, 右键粘贴, 粘贴按钮, 右键菜单粘贴, 自定义粘贴快捷键. 默认粘贴快捷键无法去除空格">
|
||||
<a-switch type="round"
|
||||
v-model="formModel.pasteAutoTrim" />
|
||||
<template #desc>
|
||||
|
||||
</template>
|
||||
</block-setting-item>
|
||||
</a-row>
|
||||
<a-row class="mb16" align="stretch" :gutter="16">
|
||||
<!-- 启用响铃 -->
|
||||
@@ -87,6 +99,7 @@
|
||||
import { ref, watch } from 'vue';
|
||||
import { useTerminalStore } from '@/store';
|
||||
import { TerminalPreferenceItem } from '@/store/modules/terminal';
|
||||
import { isSecureEnvironment } from '@/utils/env';
|
||||
import BlockSettingItem from '../block-setting-item.vue';
|
||||
|
||||
const { preference, updateTerminalPreference } = useTerminalStore();
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
<div class="terminal-setting-body setting-body">
|
||||
<!-- 提示 -->
|
||||
<a-alert class="mb16">点击保存按钮后需要刷新页面生效 (恢复默认配置后也需要点击保存按钮) (设置时需要避免与浏览器内置快捷键冲突)</a-alert>
|
||||
<!-- 非安全环境提示 -->
|
||||
<a-alert v-if="!isSecureEnvironment"
|
||||
type="warning"
|
||||
class="mb16">
|
||||
当前环境非 HTTPS 环境, 因浏览器安全策略限制, '粘贴' 功能无法使用
|
||||
</a-alert>
|
||||
<a-space class="action-container" size="mini">
|
||||
<!-- 是否启用 -->
|
||||
<a-switch v-model="value"
|
||||
@@ -39,6 +45,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { isSecureEnvironment } from '@/utils/env';
|
||||
|
||||
const props = defineProps<{
|
||||
enabled: boolean
|
||||
|
||||
@@ -170,11 +170,11 @@
|
||||
|
||||
// 连接成功回调
|
||||
const connectCallback = () => {
|
||||
loadFiles(undefined);
|
||||
loadFiles('~');
|
||||
};
|
||||
|
||||
// 加载文件列表
|
||||
const loadFiles = (path: string | undefined) => {
|
||||
const loadFiles = (path: string) => {
|
||||
setTableLoading(true);
|
||||
session.value?.list(path);
|
||||
};
|
||||
|
||||
@@ -46,7 +46,7 @@ export default class SftpSession implements ISftpSession {
|
||||
}
|
||||
|
||||
// 查询文件列表
|
||||
list(path: string | undefined) {
|
||||
list(path: string) {
|
||||
this.channel.send(InputProtocol.SFTP_LIST, {
|
||||
sessionId: this.sessionId,
|
||||
showHiddenFile: ~~this.showHiddenFile,
|
||||
|
||||
@@ -248,7 +248,9 @@ export default class SshSession implements ISshSession {
|
||||
.filter(Boolean)
|
||||
.forEach(s => s.dispose());
|
||||
// 卸载终端
|
||||
this.inst.dispose();
|
||||
setTimeout(() => {
|
||||
this.inst.dispose();
|
||||
}, 300);
|
||||
} catch (e) {
|
||||
// 卸载可能会报错
|
||||
}
|
||||
|
||||
@@ -324,7 +324,7 @@ export interface ISftpSession extends ITerminalSession {
|
||||
// 设置显示隐藏文件
|
||||
setShowHiddenFile: (show: boolean) => void;
|
||||
// 查询文件列表
|
||||
list: (path: string | undefined) => void;
|
||||
list: (path: string) => void;
|
||||
// 创建文件夹
|
||||
mkdir: (path: string) => void;
|
||||
// 创建文件
|
||||
|
||||
Reference in New Issue
Block a user