Feat: add icon btn

This commit is contained in:
unitwk 2023-08-31 11:10:46 +08:00
parent b8ca8d1701
commit d977350123
4 changed files with 95 additions and 41 deletions

View File

@ -42,7 +42,9 @@ declare module 'vue' {
BetweenMenus: typeof import('./src/components/BetweenMenus.vue')['default'] BetweenMenus: typeof import('./src/components/BetweenMenus.vue')['default']
CardOperator: typeof import('./src/components/CardOperator.vue')['default'] CardOperator: typeof import('./src/components/CardOperator.vue')['default']
CardPanel: typeof import('./src/components/CardPanel.vue')['default'] CardPanel: typeof import('./src/components/CardPanel.vue')['default']
copy: typeof import('./src/components/ActionButton copy.vue')['default']
DataStatistic: typeof import('./src/components/DataStatistic.vue')['default'] DataStatistic: typeof import('./src/components/DataStatistic.vue')['default']
IconBtn: typeof import('./src/components/IconBtn.vue')['default']
InnerCard: typeof import('./src/components/InnerCard.vue')['default'] InnerCard: typeof import('./src/components/InnerCard.vue')['default']
InputDialogProvider: typeof import('./src/components/InputDialogProvider.vue')['default'] InputDialogProvider: typeof import('./src/components/InputDialogProvider.vue')['default']
LayoutCard: typeof import('./src/components/LayoutCard.vue')['default'] LayoutCard: typeof import('./src/components/LayoutCard.vue')['default']

View File

@ -0,0 +1,38 @@
<script setup lang="ts">
import type { FunctionalComponent } from "vue";
defineProps<{
icon: FunctionalComponent;
title: string;
placement?: string;
}>();
</script>
<template>
<span class="btn">
<a-tooltip :placement="placement ? placement : 'top'">
<template #title>
<span>{{ title }}</span>
</template>
<component :is="icon"></component>
</a-tooltip>
</span>
</template>
<style scoped lang="scss">
.btn {
padding: 6px 8px;
border: 1px solid rgb(0, 0, 0, 0);
cursor: pointer;
user-select: none;
transition: all 0.4s;
border-radius: 4px;
&:hover {
background-color: var(--color-gray-2);
border: 1px solid var(--color-gray-8);
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.16);
}
}
</style>

View File

@ -116,17 +116,19 @@ export function useTerminal() {
disableStdin: false, disableStdin: false,
cursorStyle: "underline", cursorStyle: "underline",
cursorBlink: true, cursorBlink: true,
fontSize: isPhone.value ? 10 : 13, fontSize: 14,
theme: { theme: {
background: "#1e1e1e" background: "#1e1e1e"
}, },
allowProposedApi: true, allowProposedApi: true,
rendererType: "canvas" rendererType: "canvas",
rows: 40,
cols: 160
}); });
const fitAddon = new FitAddon(); const fitAddon = new FitAddon();
term.loadAddon(fitAddon); // term.loadAddon(fitAddon);
term.open(element); term.open(element);
fitAddon.fit(); // fitAddon.fit();
termFitAddon.value = fitAddon; termFitAddon.value = fitAddon;
term.onData((data) => { term.onData((data) => {
@ -145,21 +147,20 @@ export function useTerminal() {
}; };
events.on("stdout", (v: StdoutData) => { events.on("stdout", (v: StdoutData) => {
// console.debug("stdout:", v.text);
terminal.value?.write(v.text); terminal.value?.write(v.text);
}); });
const handleTerminalSizeChange = () => { // const handleTerminalSizeChange = () => {
termFitAddon.value?.fit(); // termFitAddon.value?.fit();
}; // };
onMounted(() => { onMounted(() => {
window.addEventListener("resize", handleTerminalSizeChange); // window.addEventListener("resize", handleTerminalSizeChange);
}); });
onUnmounted(() => { onUnmounted(() => {
events.removeAllListeners(); events.removeAllListeners();
window.removeEventListener("resize", handleTerminalSizeChange); // window.removeEventListener("resize", handleTerminalSizeChange);
socket.close(); socket.close();
}); });

View File

@ -2,14 +2,15 @@
import CardPanel from "@/components/CardPanel.vue"; import CardPanel from "@/components/CardPanel.vue";
import { t } from "@/lang/i18n"; import { t } from "@/lang/i18n";
import type { LayoutCard } from "@/types"; import type { LayoutCard } from "@/types";
import { DownOutlined, PlaySquareOutlined } from "@ant-design/icons-vue"; import { CodeOutlined, DownOutlined, PlaySquareOutlined } from "@ant-design/icons-vue";
import { arrayFilter } from "../../tools/array"; import { arrayFilter } from "../../tools/array";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { useTerminal } from "../../hooks/useTerminal"; import { useTerminal } from "../../hooks/useTerminal";
import { onMounted, computed } from "vue"; import { onMounted, computed, ref } from "vue";
import type { InstanceDetail } from "../../types/index"; import type { InstanceDetail } from "../../types/index";
import { useLayoutCardTools } from "@/hooks/useCardTools"; import { useLayoutCardTools } from "@/hooks/useCardTools";
import { getRandomId } from "../../tools/randId"; import { getRandomId } from "../../tools/randId";
import IconBtn from "@/components/IconBtn.vue";
const props = defineProps<{ const props = defineProps<{
card: LayoutCard; card: LayoutCard;
@ -20,6 +21,7 @@ const { getMetaOrRouteValue } = useLayoutCardTools(props.card);
const instanceId = getMetaOrRouteValue<string>("instanceId"); const instanceId = getMetaOrRouteValue<string>("instanceId");
const daemonId = getMetaOrRouteValue<string>("daemonId"); const daemonId = getMetaOrRouteValue<string>("daemonId");
const terminalDomId = computed(() => `terminal-window-${getRandomId()}`); const terminalDomId = computed(() => `terminal-window-${getRandomId()}`);
const commandInputValue = ref("");
const quickOperations = arrayFilter([ const quickOperations = arrayFilter([
// { // {
@ -84,15 +86,15 @@ onMounted(async () => {
<CardPanel class="containerWrapper" style="height: 100%"> <CardPanel class="containerWrapper" style="height: 100%">
<template #title>{{ card.title }}</template> <template #title>{{ card.title }}</template>
<template #operator> <template #operator>
<a-button <span
v-for="item in quickOperations" v-for="item in quickOperations"
:key="item.title" :key="item.title"
size="default" size="default"
class="mr-8" class="mr-8"
v-bind="item.props" v-bind="item.props"
> >
{{ item.title }} <IconBtn :icon="item.icon" :title="item.title"></IconBtn>
</a-button> </span>
<a-dropdown> <a-dropdown>
<template #overlay> <template #overlay>
<a-menu> <a-menu>
@ -102,26 +104,26 @@ onMounted(async () => {
</a-menu-item> </a-menu-item>
</a-menu> </a-menu>
</template> </template>
<a-button size="default" type="primary"> <span size="default" type="primary">
操作 <IconBtn :icon="DownOutlined" :title="t('操作')"></IconBtn>
<DownOutlined /> </span>
</a-button>
</a-dropdown> </a-dropdown>
</template> </template>
<template #body> <template #body>
<div class="terminal-wrapper"> <div class="console-wrapper">
<div class="terminal-container"> <div class="terminal-wrapper">
<div :id="terminalDomId"></div> <div class="terminal-container">
<div :id="terminalDomId"></div>
</div>
</div>
<div class="command-input">
<a-input v-model:value="commandInputValue" :placeholder="t('在这里输入命令按回车键发送')">
<template #prefix>
<CodeOutlined style="font-size: 18px" />
</template>
</a-input>
</div> </div>
</div> </div>
<!-- <p>控制台区域TODO</p>
<p>实例ID: {{ instanceId }}</p>
<p>守护进程ID: {{ daemonId }}</p>
<p>
{{ state }}
</p> -->
</template> </template>
</CardPanel> </CardPanel>
</template> </template>
@ -129,17 +131,28 @@ onMounted(async () => {
<style lang="scss"> <style lang="scss">
@import "../../assets/xterm.scss"; @import "../../assets/xterm.scss";
.terminal-wrapper { .console-wrapper {
position: relative; .terminal-wrapper {
overflow: hidden; position: relative;
height: 100%; overflow: hidden;
background-color: #1e1e1e; height: 100%;
padding: 4px; background-color: #1e1e1e;
border-radius: 4px; padding: 4px;
overflow-x: auto !important; border-radius: 6px;
overflow-y: hidden; overflow-x: auto !important;
.terminal-container { overflow-y: hidden;
min-width: 680px; display: flex;
flex-direction: column;
.terminal-container {
min-width: 680px;
height: 100%;
}
margin-bottom: 12px;
}
.command-input {
position: relative;
} }
} }
</style> </style>