🐛 终端无法粘贴.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "orion-ops-pro-ui",
|
||||
"description": "Orion Ops Pro for Vue",
|
||||
"version": "1.0.2",
|
||||
"version": "1.0.3",
|
||||
"private": true,
|
||||
"author": "Jiahang Li",
|
||||
"license": "Apache 2.0",
|
||||
|
||||
3328
orion-ops-ui/pnpm-lock.yaml
generated
3328
orion-ops-ui/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,189 +1,189 @@
|
||||
<script lang="tsx">
|
||||
import type { RouteMeta, RouteRecordRaw } from 'vue-router';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { compile, computed, defineComponent, h, ref } from 'vue';
|
||||
import { useAppStore } from '@/store';
|
||||
import { listenerRouteChange } from '@/utils/route-listener';
|
||||
import { openWindow, regexUrl } from '@/utils';
|
||||
import { openNewRoute } from '@/router';
|
||||
import useMenuTree from './use-menu-tree';
|
||||
<!--<script lang="tsx">-->
|
||||
<!-- import type { RouteMeta, RouteRecordRaw } from 'vue-router';-->
|
||||
<!-- import { useRoute, useRouter } from 'vue-router';-->
|
||||
<!-- import { compile, computed, defineComponent, h, ref } from 'vue';-->
|
||||
<!-- import { useAppStore } from '@/store';-->
|
||||
<!-- import { listenerRouteChange } from '@/utils/route-listener';-->
|
||||
<!-- import { openWindow, regexUrl } from '@/utils';-->
|
||||
<!-- import { openNewRoute } from '@/router';-->
|
||||
<!-- import useMenuTree from './use-menu-tree';-->
|
||||
|
||||
export default defineComponent({
|
||||
name: 'menuTree',
|
||||
emit: ['collapse'],
|
||||
setup() {
|
||||
const appStore = useAppStore();
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const { menuTree } = useMenuTree();
|
||||
const collapsed = computed({
|
||||
get() {
|
||||
if (appStore.device === 'desktop') return appStore.menuCollapse;
|
||||
return false;
|
||||
},
|
||||
set(value: boolean) {
|
||||
appStore.updateSettings({ menuCollapse: value });
|
||||
},
|
||||
});
|
||||
<!-- export default defineComponent({-->
|
||||
<!-- name: 'menuTree',-->
|
||||
<!-- emit: ['collapse'],-->
|
||||
<!-- setup() {-->
|
||||
<!-- const appStore = useAppStore();-->
|
||||
<!-- const router = useRouter();-->
|
||||
<!-- const route = useRoute();-->
|
||||
<!-- const { menuTree } = useMenuTree();-->
|
||||
<!-- const collapsed = computed({-->
|
||||
<!-- get() {-->
|
||||
<!-- if (appStore.device === 'desktop') return appStore.menuCollapse;-->
|
||||
<!-- return false;-->
|
||||
<!-- },-->
|
||||
<!-- set(value: boolean) {-->
|
||||
<!-- appStore.updateSettings({ menuCollapse: value });-->
|
||||
<!-- },-->
|
||||
<!-- });-->
|
||||
|
||||
const topMenu = computed(() => appStore.topMenu);
|
||||
const openKeys = ref<string[]>([]);
|
||||
const selectedKey = ref<string[]>([]);
|
||||
<!-- const topMenu = computed(() => appStore.topMenu);-->
|
||||
<!-- const openKeys = ref<string[]>([]);-->
|
||||
<!-- const selectedKey = ref<string[]>([]);-->
|
||||
|
||||
// 跳转路由
|
||||
const goto = (e: any, item: RouteRecordRaw) => {
|
||||
// 打开外链
|
||||
if (regexUrl.test(item.path)) {
|
||||
openWindow(item.path);
|
||||
return;
|
||||
}
|
||||
const { hideInMenu, activeMenu, newWindow } = item.meta as RouteMeta;
|
||||
// 新页面打开
|
||||
if (newWindow || e.ctrlKey) {
|
||||
openNewRoute({
|
||||
name: item.name,
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 设置 selectedKey
|
||||
if (route.name === item.name && !hideInMenu && !activeMenu) {
|
||||
selectedKey.value = [item.name as string];
|
||||
return;
|
||||
}
|
||||
// 触发跳转
|
||||
router.push({
|
||||
name: item.name,
|
||||
});
|
||||
};
|
||||
<!-- // 跳转路由-->
|
||||
<!-- const goto = (e: any, item: RouteRecordRaw) => {-->
|
||||
<!-- // 打开外链-->
|
||||
<!-- if (regexUrl.test(item.path)) {-->
|
||||
<!-- openWindow(item.path);-->
|
||||
<!-- return;-->
|
||||
<!-- }-->
|
||||
<!-- const { hideInMenu, activeMenu, newWindow } = item.meta as RouteMeta;-->
|
||||
<!-- // 新页面打开-->
|
||||
<!-- if (newWindow || e.ctrlKey) {-->
|
||||
<!-- openNewRoute({-->
|
||||
<!-- name: item.name,-->
|
||||
<!-- });-->
|
||||
<!-- return;-->
|
||||
<!-- }-->
|
||||
<!-- // 设置 selectedKey-->
|
||||
<!-- if (route.name === item.name && !hideInMenu && !activeMenu) {-->
|
||||
<!-- selectedKey.value = [item.name as string];-->
|
||||
<!-- return;-->
|
||||
<!-- }-->
|
||||
<!-- // 触发跳转-->
|
||||
<!-- router.push({-->
|
||||
<!-- name: item.name,-->
|
||||
<!-- });-->
|
||||
<!-- };-->
|
||||
|
||||
const findMenuOpenKeys = (target: string) => {
|
||||
const result: string[] = [];
|
||||
let isFind = false;
|
||||
const backtrack = (item: RouteRecordRaw, keys: string[]) => {
|
||||
if (item.name === target) {
|
||||
isFind = true;
|
||||
result.push(...keys);
|
||||
return;
|
||||
}
|
||||
if (item.children?.length) {
|
||||
item.children.forEach((el) => {
|
||||
backtrack(el, [...keys, el.name as string]);
|
||||
});
|
||||
}
|
||||
};
|
||||
menuTree.value.forEach((el: RouteRecordRaw) => {
|
||||
if (isFind) return;
|
||||
backtrack(el, [el.name as string]);
|
||||
});
|
||||
return result;
|
||||
};
|
||||
<!-- const findMenuOpenKeys = (target: string) => {-->
|
||||
<!-- const result: string[] = [];-->
|
||||
<!-- let isFind = false;-->
|
||||
<!-- const backtrack = (item: RouteRecordRaw, keys: string[]) => {-->
|
||||
<!-- if (item.name === target) {-->
|
||||
<!-- isFind = true;-->
|
||||
<!-- result.push(...keys);-->
|
||||
<!-- return;-->
|
||||
<!-- }-->
|
||||
<!-- if (item.children?.length) {-->
|
||||
<!-- item.children.forEach((el) => {-->
|
||||
<!-- backtrack(el, [...keys, el.name as string]);-->
|
||||
<!-- });-->
|
||||
<!-- }-->
|
||||
<!-- };-->
|
||||
<!-- menuTree.value.forEach((el: RouteRecordRaw) => {-->
|
||||
<!-- if (isFind) return;-->
|
||||
<!-- backtrack(el, [el.name as string]);-->
|
||||
<!-- });-->
|
||||
<!-- return result;-->
|
||||
<!-- };-->
|
||||
|
||||
// 监听路由 设置打开的 key
|
||||
listenerRouteChange((newRoute) => {
|
||||
const { activeMenu, hideInMenu } = newRoute.meta;
|
||||
if (!hideInMenu || activeMenu) {
|
||||
const menuOpenKeys = findMenuOpenKeys(
|
||||
(activeMenu || newRoute.name) as string
|
||||
);
|
||||
<!-- // 监听路由 设置打开的 key-->
|
||||
<!-- listenerRouteChange((newRoute) => {-->
|
||||
<!-- const { activeMenu, hideInMenu } = newRoute.meta;-->
|
||||
<!-- if (!hideInMenu || activeMenu) {-->
|
||||
<!-- const menuOpenKeys = findMenuOpenKeys(-->
|
||||
<!-- (activeMenu || newRoute.name) as string-->
|
||||
<!-- );-->
|
||||
|
||||
const keySet = new Set([...menuOpenKeys, ...openKeys.value]);
|
||||
openKeys.value = [...keySet];
|
||||
<!-- const keySet = new Set([...menuOpenKeys, ...openKeys.value]);-->
|
||||
<!-- openKeys.value = [...keySet];-->
|
||||
|
||||
selectedKey.value = [
|
||||
activeMenu || menuOpenKeys[menuOpenKeys.length - 1],
|
||||
];
|
||||
}
|
||||
}, true);
|
||||
<!-- selectedKey.value = [-->
|
||||
<!-- activeMenu || menuOpenKeys[menuOpenKeys.length - 1],-->
|
||||
<!-- ];-->
|
||||
<!-- }-->
|
||||
<!-- }, true);-->
|
||||
|
||||
// 展开菜单
|
||||
const setCollapse = (val: boolean) => {
|
||||
if (appStore.device === 'desktop')
|
||||
appStore.updateSettings({ menuCollapse: val });
|
||||
};
|
||||
<!-- // 展开菜单-->
|
||||
<!-- const setCollapse = (val: boolean) => {-->
|
||||
<!-- if (appStore.device === 'desktop')-->
|
||||
<!-- appStore.updateSettings({ menuCollapse: val });-->
|
||||
<!-- };-->
|
||||
|
||||
// 渲染菜单
|
||||
const renderSubMenu = () => {
|
||||
function travel(_route: RouteRecordRaw[], nodes = []) {
|
||||
if (_route) {
|
||||
_route.forEach((element) => {
|
||||
// This is demo, modify nodes as needed
|
||||
const icon = element?.meta?.icon
|
||||
? () => h(compile(`<${element?.meta?.icon}/>`))
|
||||
: null;
|
||||
const node =
|
||||
element?.children && element?.children.length !== 0 ? (
|
||||
<a-sub-menu
|
||||
key={element?.name}
|
||||
v-slots={{
|
||||
icon,
|
||||
// 去除国际化 title: () => h(compile(t(element?.meta?.locale || ''))),
|
||||
title: () => h(compile(element?.meta?.locale || '')),
|
||||
}}
|
||||
>
|
||||
{travel(element?.children)}
|
||||
</a-sub-menu>
|
||||
) : (
|
||||
<a-menu-item
|
||||
key={element?.name}
|
||||
v-slots={{ icon }}
|
||||
onClick={($event: any) => goto($event, element)}
|
||||
>
|
||||
{element?.meta?.locale || ''}
|
||||
</a-menu-item>
|
||||
);
|
||||
nodes.push(node as never);
|
||||
});
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
<!-- // 渲染菜单-->
|
||||
<!-- const renderSubMenu = () => {-->
|
||||
<!-- function travel(_route: RouteRecordRaw[], nodes = []) {-->
|
||||
<!-- if (_route) {-->
|
||||
<!-- _route.forEach((element) => {-->
|
||||
<!-- // This is demo, modify nodes as needed-->
|
||||
<!-- const icon = element?.meta?.icon-->
|
||||
<!-- ? () => h(compile(`<${element?.meta?.icon}/>`))-->
|
||||
<!-- : null;-->
|
||||
<!-- const node =-->
|
||||
<!-- element?.children && element?.children.length !== 0 ? (-->
|
||||
<!-- <a-sub-menu-->
|
||||
<!-- key={element?.name}-->
|
||||
<!-- v-slots={{-->
|
||||
<!-- icon,-->
|
||||
<!-- // 去除国际化 title: () => h(compile(t(element?.meta?.locale || ''))),-->
|
||||
<!-- title: () => h(compile(element?.meta?.locale || '')),-->
|
||||
<!-- }}-->
|
||||
<!-- >-->
|
||||
<!-- {travel(element?.children)}-->
|
||||
<!-- </a-sub-menu>-->
|
||||
<!-- ) : (-->
|
||||
<!-- <a-menu-item-->
|
||||
<!-- key={element?.name}-->
|
||||
<!-- v-slots={{ icon }}-->
|
||||
<!-- onClick={($event: any) => goto($event, element)}-->
|
||||
<!-- >-->
|
||||
<!-- {element?.meta?.locale || ''}-->
|
||||
<!-- </a-menu-item>-->
|
||||
<!-- );-->
|
||||
<!-- nodes.push(node as never);-->
|
||||
<!-- });-->
|
||||
<!-- }-->
|
||||
<!-- return nodes;-->
|
||||
<!-- }-->
|
||||
|
||||
return travel(menuTree.value);
|
||||
};
|
||||
<!-- return travel(menuTree.value);-->
|
||||
<!-- };-->
|
||||
|
||||
return () => (
|
||||
<a-menu
|
||||
mode={topMenu.value ? 'horizontal' : 'vertical'}
|
||||
v-model:collapsed={collapsed.value}
|
||||
v-model:open-keys={openKeys.value}
|
||||
show-collapse-button={appStore.device !== 'mobile'}
|
||||
auto-open={false}
|
||||
selected-keys={selectedKey.value}
|
||||
auto-open-selected={true}
|
||||
level-indent={34}
|
||||
style="height: 100%; width:100%;"
|
||||
onCollapse={setCollapse}
|
||||
>
|
||||
{renderSubMenu()}
|
||||
</a-menu>
|
||||
);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<!-- return () => (-->
|
||||
<!-- <a-menu-->
|
||||
<!-- mode={topMenu.value ? 'horizontal' : 'vertical'}-->
|
||||
<!-- v-model:collapsed={collapsed.value}-->
|
||||
<!-- v-model:open-keys={openKeys.value}-->
|
||||
<!-- show-collapse-button={appStore.device !== 'mobile'}-->
|
||||
<!-- auto-open={false}-->
|
||||
<!-- selected-keys={selectedKey.value}-->
|
||||
<!-- auto-open-selected={true}-->
|
||||
<!-- level-indent={34}-->
|
||||
<!-- style="height: 100%; width:100%;"-->
|
||||
<!-- onCollapse={setCollapse}-->
|
||||
<!-- >-->
|
||||
<!-- {renderSubMenu()}-->
|
||||
<!-- </a-menu>-->
|
||||
<!-- );-->
|
||||
<!-- },-->
|
||||
<!-- });-->
|
||||
<!--</script>-->
|
||||
|
||||
<style lang="less" scoped>
|
||||
:deep(.arco-menu-inner) {
|
||||
.arco-menu-inline-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
<!--<style lang="less" scoped>-->
|
||||
<!-- :deep(.arco-menu-inner) {-->
|
||||
<!-- .arco-menu-inline-header {-->
|
||||
<!-- display: flex;-->
|
||||
<!-- align-items: center;-->
|
||||
<!-- }-->
|
||||
|
||||
.arco-icon {
|
||||
&:not(.arco-icon-down) {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
<!-- .arco-icon {-->
|
||||
<!-- &:not(.arco-icon-down) {-->
|
||||
<!-- font-size: 18px;-->
|
||||
<!-- }-->
|
||||
<!-- }-->
|
||||
|
||||
.arco-menu-icon {
|
||||
margin-right: 10px !important;
|
||||
}
|
||||
<!-- .arco-menu-icon {-->
|
||||
<!-- margin-right: 10px !important;-->
|
||||
<!-- }-->
|
||||
|
||||
.arco-menu-indent-list {
|
||||
width: 28px;
|
||||
display: inline-block;
|
||||
}
|
||||
<!-- .arco-menu-indent-list {-->
|
||||
<!-- width: 28px;-->
|
||||
<!-- display: inline-block;-->
|
||||
<!-- }-->
|
||||
|
||||
.arco-menu-title {
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- .arco-menu-title {-->
|
||||
<!-- user-select: none;-->
|
||||
<!-- }-->
|
||||
<!-- }-->
|
||||
<!--</style>-->
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import { useClipboard } from '@vueuse/core';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
const { copy: c } = useClipboard();
|
||||
|
||||
// 复制
|
||||
export const copy = async (value: string | undefined, tips: string | boolean = `${value} 已复制`) => {
|
||||
try {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
await c(value);
|
||||
await copyToClipboard(value);
|
||||
if (tips) {
|
||||
Message.success(tips as string);
|
||||
}
|
||||
@@ -20,7 +17,49 @@ export const copy = async (value: string | undefined, tips: string | boolean = `
|
||||
|
||||
// 获取剪切板内容
|
||||
export const readText = () => {
|
||||
return navigator.clipboard.readText();
|
||||
if (navigator.clipboard) {
|
||||
return navigator.clipboard.readText();
|
||||
} else {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.style.position = 'absolute';
|
||||
textarea.style.left = '-9999px';
|
||||
document.body.appendChild(textarea);
|
||||
textarea.select();
|
||||
try {
|
||||
const success = document.execCommand('paste');
|
||||
if (!success) {
|
||||
Message.error('当前浏览器无法读取剪切板内容');
|
||||
}
|
||||
resolve(textarea.value);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
} finally {
|
||||
document.body.removeChild(textarea);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 复制到剪切板
|
||||
export const copyToClipboard = async (value: string) => {
|
||||
if (navigator.clipboard) {
|
||||
await navigator.clipboard.writeText(value);
|
||||
} else {
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.textContent = value;
|
||||
textarea.style.position = 'absolute';
|
||||
textarea.style.left = '-9999px';
|
||||
document.body.appendChild(textarea);
|
||||
textarea.select();
|
||||
try {
|
||||
document.execCommand('copy');
|
||||
} catch (error) {
|
||||
throw error;
|
||||
} finally {
|
||||
document.body.removeChild(textarea);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default function useCopy() {
|
||||
|
||||
@@ -16,17 +16,18 @@ const preventKeys: Array<ShortcutKey> = [
|
||||
altKey: false,
|
||||
shiftKey: true,
|
||||
code: 'KeyC'
|
||||
}, {
|
||||
ctrlKey: true,
|
||||
altKey: false,
|
||||
shiftKey: true,
|
||||
code: 'KeyV'
|
||||
}, {
|
||||
ctrlKey: false,
|
||||
altKey: false,
|
||||
shiftKey: true,
|
||||
code: 'Insert'
|
||||
},
|
||||
}
|
||||
// , {
|
||||
// ctrlKey: true,
|
||||
// altKey: false,
|
||||
// shiftKey: true,
|
||||
// code: 'KeyV'
|
||||
// }, {
|
||||
// ctrlKey: false,
|
||||
// altKey: false,
|
||||
// shiftKey: true,
|
||||
// code: 'Insert'
|
||||
// },
|
||||
];
|
||||
|
||||
const { copy: copyValue, readText } = useCopy();
|
||||
|
||||
Reference in New Issue
Block a user