app #1 simpleasm: 从 oci 迁过来,asm.famzheng.me 已上线
- 后端 FastAPI 重写为 axum + rusqlite (musl static, 2.8MB) - 前端原样搬运 (Vue3 + Vite + Pinia + vue-router + vite-plugin-yaml) - k8s: cube-simpleasm ns + 1Gi PVC (k3s local-path) + Recreate strategy - CI: 复刻 deploy-cube.yml,按 apps/simpleasm/** 触发 - cube 门户里 simpleasm 状态从 pending 改成 live - 数据冷启 (Fam 拍板不带历史进度)
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
<template>
|
||||
<div class="output-console">
|
||||
<div class="console-header">
|
||||
<span>Output</span>
|
||||
<button v-if="messages.length" @click="$emit('clear')" class="clear-btn">Clear</button>
|
||||
</div>
|
||||
<div class="console-body" ref="bodyEl">
|
||||
<div v-for="(m, i) in messages" :key="i" class="console-line" :class="m.type">
|
||||
<span class="pfx">{{ m.pfx }}</span>
|
||||
<span>{{ m.text }}</span>
|
||||
</div>
|
||||
<div v-if="!messages.length" class="empty">Waiting to run...</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref, watch, nextTick } from 'vue'
|
||||
|
||||
const props = defineProps({ output: Array, error: String, status: String })
|
||||
defineEmits(['clear'])
|
||||
const bodyEl = ref(null)
|
||||
|
||||
const messages = computed(() => {
|
||||
const msgs = []
|
||||
if (props.status) msgs.push({ type: 'info', pfx: '>', text: props.status })
|
||||
for (const v of (props.output || [])) msgs.push({ type: 'output', pfx: 'OUT', text: String(v) })
|
||||
if (props.error) msgs.push({ type: 'error', pfx: '!', text: props.error })
|
||||
return msgs
|
||||
})
|
||||
|
||||
watch(messages, async () => {
|
||||
await nextTick()
|
||||
if (bodyEl.value) bodyEl.value.scrollTop = bodyEl.value.scrollHeight
|
||||
}, { deep: true })
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.output-console {
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-lg);
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.console-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 5px 14px;
|
||||
background: var(--bg-surface);
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.clear-btn { padding: 2px 8px; font-size: 11px; background: transparent; color: var(--text-muted); border: 1px solid var(--border); }
|
||||
.console-body {
|
||||
padding: 8px 14px;
|
||||
min-height: 40px;
|
||||
max-height: 100px;
|
||||
overflow-y: auto;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 13px;
|
||||
background: var(--bg-dark);
|
||||
}
|
||||
.console-line { padding: 1px 0; display: flex; gap: 8px; }
|
||||
.pfx { color: var(--text-muted); flex-shrink: 0; min-width: 28px; }
|
||||
.console-line.output { color: var(--accent-green); }
|
||||
.console-line.error { color: var(--accent-red); }
|
||||
.console-line.info { color: var(--accent-cyan); }
|
||||
.empty { color: var(--text-muted); font-style: italic; font-size: 12px; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user