fix: 修复Admin暗色主题与环境总览布局

This commit is contained in:
sunlei 2026-06-19 13:29:37 +08:00
parent 2fde3c4e74
commit d038501228
11 changed files with 204 additions and 108 deletions

View File

@ -48,10 +48,16 @@ function getStatusColor(status: EnvironmentHealthStatus) {
<style scoped>
.environment-event-stream {
padding: 16px;
border: 1px solid hsl(214deg 18% 86%);
display: flex;
flex-direction: column;
min-width: 0;
min-height: 0;
padding: 12px;
overflow: hidden;
color: hsl(var(--card-foreground));
background: hsl(var(--card));
border: 1px solid hsl(var(--border));
border-radius: 8px;
background: hsl(0deg 0% 100%);
}
.environment-event-stream__header {
@ -60,26 +66,29 @@ function getStatusColor(status: EnvironmentHealthStatus) {
gap: 8px;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
margin-bottom: 8px;
}
.environment-event-stream__header h2 {
margin: 0;
color: hsl(219deg 22% 18%);
font-size: 16px;
color: hsl(var(--foreground));
}
.environment-event-stream__header span,
.environment-event-stream__time {
color: hsl(215deg 12% 38%);
font-size: 12px;
color: hsl(var(--muted-foreground));
}
.environment-event-stream__list {
display: grid;
gap: 8px;
flex: 1 1 0;
gap: 6px;
min-height: 0;
padding: 0;
margin: 0;
overflow: hidden;
list-style: none;
}
@ -89,17 +98,18 @@ function getStatusColor(status: EnvironmentHealthStatus) {
gap: 10px;
align-items: center;
min-height: 44px;
padding: 8px 10px;
border: 1px solid hsl(210deg 18% 91%);
padding: 7px 10px;
overflow: hidden;
background: hsl(var(--accent));
border: 1px solid hsl(var(--border));
border-radius: 8px;
background: hsl(210deg 25% 98%);
}
.environment-event-stream__list strong {
min-width: 0;
overflow-wrap: anywhere;
color: hsl(219deg 22% 18%);
font-size: 13px;
color: hsl(var(--foreground));
overflow-wrap: anywhere;
}
.environment-event-stream__tags {

View File

@ -108,18 +108,24 @@ function getEvidenceTitle(evidence: EnvironmentEvidence) {
<style scoped>
.environment-evidence-panel {
display: flex;
flex-direction: column;
gap: 12px;
display: grid;
grid-template-rows: auto minmax(0, 1fr) auto;
gap: 10px;
min-width: 0;
padding: 16px;
border: 1px solid hsl(214deg 18% 86%);
height: 100%;
min-height: 0;
padding: 14px;
overflow: hidden;
color: hsl(var(--card-foreground));
background: hsl(var(--card));
border: 1px solid hsl(var(--border));
border-radius: 8px;
background: hsl(0deg 0% 100%);
}
.environment-evidence-panel__section {
min-width: 0;
min-height: 0;
overflow: hidden;
}
.environment-evidence-panel__section h2,
@ -130,28 +136,30 @@ function getEvidenceTitle(evidence: EnvironmentEvidence) {
}
.environment-evidence-panel__section h2 {
color: hsl(219deg 22% 18%);
font-size: 18px;
color: hsl(var(--foreground));
}
.environment-evidence-panel__section h3 {
margin-bottom: 10px;
color: hsl(219deg 22% 18%);
font-size: 14px;
color: hsl(var(--foreground));
}
.environment-evidence-panel__eyebrow,
.environment-evidence-panel__summary,
.environment-evidence-panel__action span {
color: hsl(215deg 12% 38%);
font-size: 12px;
color: hsl(var(--muted-foreground));
}
.environment-evidence-panel__evidence-list {
display: grid;
gap: 10px;
gap: 8px;
min-height: 0;
padding: 0;
margin: 0;
overflow: hidden;
list-style: none;
}
@ -161,10 +169,11 @@ function getEvidenceTitle(evidence: EnvironmentEvidence) {
flex-direction: column;
gap: 4px;
min-width: 0;
padding: 10px;
border: 1px solid hsl(210deg 18% 91%);
padding: 8px;
overflow: hidden;
background: hsl(var(--accent));
border: 1px solid hsl(var(--border));
border-radius: 8px;
background: hsl(210deg 25% 98%);
}
.environment-evidence-panel__evidence-list strong,
@ -175,6 +184,8 @@ function getEvidenceTitle(evidence: EnvironmentEvidence) {
.environment-evidence-panel__actions {
display: grid;
gap: 10px;
gap: 8px;
min-height: 0;
overflow: hidden;
}
</style>

View File

@ -94,27 +94,33 @@ function getBadgeStatus(site: EnvironmentSite) {
.environment-site-rail {
display: flex;
flex-direction: column;
gap: 10px;
gap: 8px;
min-width: 0;
height: 100%;
min-height: 0;
overflow: hidden;
}
.environment-site-rail__item {
display: flex;
flex-direction: column;
gap: 8px;
gap: 6px;
width: 100%;
padding: 14px;
color: hsl(219deg 22% 18%);
min-width: 0;
padding: 12px;
overflow: hidden;
color: hsl(var(--card-foreground));
text-align: left;
border: 1px solid hsl(214deg 18% 86%);
border-radius: 8px;
background: hsl(0deg 0% 100%);
cursor: pointer;
background: hsl(var(--card));
border: 1px solid hsl(var(--border));
border-radius: 8px;
}
.environment-site-rail__item.is-selected {
border-color: hsl(198deg 82% 42%);
box-shadow: inset 3px 0 0 hsl(198deg 82% 42%);
background: hsl(var(--primary) / 8%);
border-color: hsl(var(--primary));
box-shadow: inset 3px 0 0 hsl(var(--primary));
}
.environment-site-rail__topline,
@ -127,8 +133,12 @@ function getBadgeStatus(site: EnvironmentSite) {
}
.environment-site-rail__summary {
color: hsl(215deg 12% 38%);
display: -webkit-box;
overflow: hidden;
-webkit-line-clamp: 2;
font-size: 12px;
line-height: 1.45;
color: hsl(var(--muted-foreground));
-webkit-box-orient: vertical;
}
</style>

View File

@ -97,12 +97,14 @@ function getStatusColor(status: EnvironmentHealthStatus) {
.environment-status-bar {
display: grid;
grid-template-columns: minmax(260px, 1fr) minmax(260px, auto) auto;
gap: 16px;
gap: 12px;
align-items: center;
padding: 18px;
border: 1px solid hsl(214deg 18% 86%);
min-width: 0;
padding: 14px;
color: hsl(var(--card-foreground));
background: hsl(var(--card));
border: 1px solid hsl(var(--border));
border-radius: 8px;
background: hsl(0deg 0% 100%);
}
.environment-status-bar__summary {
@ -118,16 +120,16 @@ function getStatusColor(status: EnvironmentHealthStatus) {
.environment-status-bar__heading h1 {
margin: 0;
color: hsl(219deg 22% 18%);
font-size: 22px;
font-weight: 700;
line-height: 1.2;
color: hsl(var(--foreground));
}
.environment-status-bar__eyebrow {
margin: 0 0 4px;
color: hsl(215deg 12% 45%);
font-size: 12px;
color: hsl(var(--muted-foreground));
}
.environment-status-bar__meta,
@ -135,8 +137,8 @@ function getStatusColor(status: EnvironmentHealthStatus) {
display: flex;
flex-wrap: wrap;
gap: 8px 14px;
color: hsl(215deg 12% 38%);
font-size: 12px;
color: hsl(var(--muted-foreground));
}
.environment-status-bar__counts span {
@ -154,6 +156,8 @@ function getStatusColor(status: EnvironmentHealthStatus) {
@media (width <= 900px) {
.environment-status-bar {
grid-template-columns: 1fr;
gap: 8px;
padding: 12px;
}
.environment-status-bar__actions {

View File

@ -97,11 +97,17 @@ function countUnwiredSignals(service: EnvironmentService) {
<style scoped>
.environment-topology {
display: flex;
flex-direction: column;
min-width: 0;
padding: 16px;
border: 1px solid hsl(214deg 18% 86%);
height: 100%;
min-height: 0;
padding: 14px;
overflow: hidden;
color: hsl(var(--card-foreground));
background: hsl(var(--card));
border: 1px solid hsl(var(--border));
border-radius: 8px;
background: hsl(0deg 0% 100%);
}
.environment-topology__header,
@ -116,52 +122,61 @@ function countUnwiredSignals(service: EnvironmentService) {
.environment-topology__header p {
margin: 0 0 4px;
color: hsl(215deg 12% 45%);
font-size: 12px;
color: hsl(var(--muted-foreground));
}
.environment-topology__header h2 {
margin: 0;
color: hsl(219deg 22% 18%);
font-size: 18px;
color: hsl(var(--foreground));
}
.environment-topology__nodes {
display: grid;
gap: 14px;
margin-top: 16px;
flex: 1 1 0;
gap: 10px;
min-height: 0;
margin-top: 12px;
overflow: hidden;
}
.environment-topology__node {
padding: 12px;
border: 1px solid hsl(210deg 18% 91%);
min-width: 0;
padding: 10px;
overflow: hidden;
background: hsl(var(--background));
border: 1px solid hsl(var(--border));
border-radius: 8px;
}
.environment-topology__services {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
gap: 10px;
margin-top: 12px;
grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
gap: 8px;
margin-top: 10px;
overflow: hidden;
}
.environment-topology__service {
display: flex;
flex-direction: column;
gap: 8px;
min-height: 124px;
padding: 12px;
color: hsl(219deg 22% 18%);
gap: 6px;
min-width: 0;
min-height: 104px;
padding: 10px;
overflow: hidden;
color: hsl(var(--foreground));
text-align: left;
border: 1px solid hsl(214deg 18% 86%);
border-radius: 8px;
background: hsl(210deg 25% 98%);
cursor: pointer;
background: hsl(var(--accent));
border: 1px solid hsl(var(--border));
border-radius: 8px;
}
.environment-topology__service.is-selected {
border-color: hsl(198deg 82% 42%);
background: hsl(198deg 42% 96%);
background: hsl(var(--primary) / 10%);
border-color: hsl(var(--primary));
}
.environment-topology__service-name {
@ -169,9 +184,13 @@ function countUnwiredSignals(service: EnvironmentService) {
}
.environment-topology__service-summary {
display: -webkit-box;
flex: 1;
color: hsl(215deg 12% 38%);
overflow: hidden;
-webkit-line-clamp: 2;
font-size: 12px;
line-height: 1.45;
color: hsl(var(--muted-foreground));
-webkit-box-orient: vertical;
}
</style>

View File

@ -493,27 +493,41 @@ function getErrorMessage(error: unknown) {
<style scoped>
.environment-dashboard-page {
display: flex;
flex-direction: column;
gap: 16px;
min-height: 100%;
padding: 16px;
background: hsl(210deg 25% 96%);
box-sizing: border-box;
display: grid;
grid-template-rows: auto minmax(0, 1fr) minmax(108px, 0.26fr);
gap: 12px;
width: 100%;
height: var(--vben-content-height, 100%);
min-height: 0;
max-height: var(--vben-content-height, 100%);
padding: 12px;
overflow: hidden;
color: hsl(var(--foreground));
background: hsl(var(--background-deep));
}
.environment-dashboard-page__main {
display: grid;
grid-template-columns: minmax(210px, 260px) minmax(360px, 1fr) minmax(
280px,
340px
grid-template-columns: minmax(196px, 0.72fr) minmax(0, 1.9fr) minmax(
248px,
0.92fr
);
gap: 16px;
align-items: start;
gap: 12px;
align-items: stretch;
min-width: 0;
min-height: 0;
overflow: hidden;
}
@media (width <= 1180px) {
.environment-dashboard-page {
grid-template-rows: auto minmax(0, 1fr) minmax(96px, 0.22fr);
}
.environment-dashboard-page__main {
grid-template-columns: minmax(190px, 240px) 1fr;
grid-template-rows: minmax(0, 1fr) minmax(120px, 0.42fr);
grid-template-columns: minmax(180px, 220px) minmax(0, 1fr);
}
.environment-dashboard-page__main > :last-child {
@ -523,11 +537,15 @@ function getErrorMessage(error: unknown) {
@media (width <= 760px) {
.environment-dashboard-page {
padding: 10px;
grid-template-rows: auto minmax(0, 1fr) minmax(88px, 0.18fr);
gap: 8px;
padding: 8px;
}
.environment-dashboard-page__main {
grid-template-rows: minmax(0, 0.62fr) minmax(0, 1.3fr) minmax(0, 0.9fr);
grid-template-columns: 1fr;
gap: 8px;
}
.environment-dashboard-page__main > :last-child {

View File

@ -180,8 +180,10 @@ export default defineComponent({
<div
style={{
alignItems: 'center',
border: '1px dashed var(--border-color)',
background: 'hsl(var(--muted))',
border: '1px dashed hsl(var(--border))',
borderRadius: '8px',
color: 'hsl(var(--muted-foreground))',
display: 'flex',
height: '240px',
justifyContent: 'center',

View File

@ -67,9 +67,9 @@ export default defineComponent({
*/
const renderField = (label: string, value: unknown) => {
return (
<div class="grid grid-cols-[120px_1fr] gap-3 border-b border-solid border-gray-100 py-2 text-sm">
<span class="text-gray-500">{label}</span>
<span class="break-all">{formatValue(value)}</span>
<div class="grid grid-cols-[120px_1fr] gap-3 border-b border-solid border-border py-2 text-sm">
<span class="text-muted-foreground">{label}</span>
<span class="break-all text-foreground">{formatValue(value)}</span>
</div>
);
};
@ -84,7 +84,7 @@ export default defineComponent({
return (
<section class="mt-4">
<h3 class="mb-2 text-sm font-medium">{title}</h3>
<pre class="max-h-72 overflow-auto rounded bg-gray-50 p-3 text-xs">
<pre class="max-h-72 overflow-auto rounded border border-border bg-muted p-3 text-xs text-foreground">
{JSON.stringify(value, null, 2)}
</pre>
</section>

View File

@ -42,6 +42,9 @@ export default defineComponent({
{ immediate: true },
);
/**
* Loads the latest task run records for the selected plugin task drawer.
*/
async function loadRuns() {
if (!props.task?.id) return;
loading.value = true;
@ -56,25 +59,32 @@ export default defineComponent({
}
}
/**
* Renders one scheduled-task execution record with themed evidence blocks.
*
* @param item - Task run row returned by the plugin task API.
*/
const renderRun = (item: QqbotPluginTaskApi.TaskRun) => (
<div class="border-b border-solid border-gray-100 py-3" key={item.id}>
<div class="border-b border-solid border-border py-3" key={item.id}>
<div class="mb-2 flex flex-wrap items-center gap-2">
<Tag color={runStatusColor[item.status]}>{item.status}</Tag>
<Tag>{item.triggerType}</Tag>
<span>{item.startedAt || item.createTime || '-'}</span>
<span>
<span class="text-muted-foreground">
{item.startedAt || item.createTime || '-'}
</span>
<span class="text-muted-foreground">
{item.durationMs === null || item.durationMs === undefined
? '-'
: `${item.durationMs} ms`}
</span>
</div>
{item.safeSummary ? (
<pre class="whitespace-pre-wrap rounded bg-gray-50 p-2 text-xs">
<pre class="whitespace-pre-wrap rounded border border-border bg-muted p-2 text-xs text-foreground">
{JSON.stringify(item.safeSummary, null, 2)}
</pre>
) : null}
{item.errorMessage ? (
<div class="mt-2 text-sm text-red-500">{item.errorMessage}</div>
<div class="mt-2 text-sm text-destructive">{item.errorMessage}</div>
) : null}
</div>
);

View File

@ -58,7 +58,7 @@ export default defineComponent({
>
{props.mode === 'validate' ? (
<textarea
class="w-full resize-y rounded border border-solid border-gray-200 p-3 font-mono text-sm outline-none"
class="w-full resize-y rounded border border-solid border-border bg-background p-3 font-mono text-sm text-foreground outline-none placeholder:text-muted-foreground focus:border-primary"
onInput={(event) => {
emit('update:value', (event.target as HTMLTextAreaElement).value);
}}
@ -68,7 +68,9 @@ export default defineComponent({
) : (
<div class="space-y-3">
<label class="block">
<span class="mb-1 block text-sm text-gray-600"></span>
<span class="mb-1 block text-sm text-muted-foreground">
</span>
<AInput
onUpdate:value={(value: string) => {
emit('update:packagePath', value);
@ -78,7 +80,9 @@ export default defineComponent({
/>
</label>
<label class="block">
<span class="mb-1 block text-sm text-gray-600"> Hash</span>
<span class="mb-1 block text-sm text-muted-foreground">
Hash
</span>
<AInput
onUpdate:value={(value: string) => {
emit('update:packageHash', value);

View File

@ -43,6 +43,11 @@ export default defineComponent({
},
emits: ['close', 'installationAction'],
setup(props, { emit }) {
/**
* Maps plugin platform status values to readable themed status tags.
*
* @param status - Runtime, binding, or installation status from the API.
*/
const renderStatusTag = (status?: string) => {
if (!status) return <Tag color="default">-</Tag>;
const color =
@ -50,21 +55,21 @@ export default defineComponent({
return <Tag color={color}>{getQqbotStatusLabel(status)}</Tag>;
};
/**
* Renders recent runtime events with safe summaries for diagnosis.
*/
const renderEvents = () =>
props.runtimeEvents.length > 0 ? (
<div class="space-y-3">
{props.runtimeEvents.map((item) => (
<div
class="border-b border-solid border-gray-100 pb-3"
key={item.id}
>
<div>
<div class="border-b border-solid border-border pb-3" key={item.id}>
<div class="flex flex-wrap items-center gap-2">
<Tag color={item.level === 'error' ? 'error' : 'processing'}>
{item.level}
</Tag>
<span>{item.eventType}</span>
<span class="text-foreground">{item.eventType}</span>
</div>
<pre class="mt-2 whitespace-pre-wrap text-xs">
<pre class="mt-2 whitespace-pre-wrap rounded border border-border bg-muted p-2 text-xs text-foreground">
{JSON.stringify(item.safeSummary || {}, null, 2)}
</pre>
</div>
@ -74,16 +79,16 @@ export default defineComponent({
<span></span>
);
/**
* Renders account-to-plugin binding rows for the selected platform state.
*/
const renderBindings = () =>
props.accountBindings.length > 0 ? (
<div class="space-y-3">
{props.accountBindings.map((item) => (
<div
class="border-b border-solid border-gray-100 pb-3"
key={item.id}
>
<div class="border-b border-solid border-border pb-3" key={item.id}>
{renderStatusTag(item.enabled ? 'enabled' : 'disabled')}
<span>
<span class="text-foreground">
{item.pluginId} / {item.accountId}
</span>
</div>
@ -93,18 +98,18 @@ export default defineComponent({
<span></span>
);
/**
* Renders installed plugin rows and exposes safe lifecycle actions.
*/
const renderInstallations = () =>
props.installations.length > 0 ? (
<div class="space-y-3">
{props.installations.map((item) => (
<div
class="border-b border-solid border-gray-100 pb-3"
key={item.id}
>
<div class="border-b border-solid border-border pb-3" key={item.id}>
<div class="mb-2 flex items-center gap-2">
{renderStatusTag(item.status)}
<Tag>{item.runtimeStatus || '-'}</Tag>
<span>
<span class="text-foreground">
{item.pluginId} / {item.versionId}
</span>
</div>
@ -135,6 +140,9 @@ export default defineComponent({
<span></span>
);
/**
* Selects the drawer body according to the active platform state tab.
*/
const renderContent = () => {
if (props.mode === 'events') return renderEvents();
if (props.mode === 'bindings') return renderBindings();