chore: release v0.8.4 — 移除龙虾军团入口,精简前端

This commit is contained in:
晴天
2026-03-13 15:24:12 +08:00
parent 5e2abeadc5
commit 0dd202d50d
15 changed files with 24 additions and 3431 deletions

View File

@@ -1,44 +0,0 @@
export const DOCKER_TASK_TIMEOUT_MS = 10 * 60 * 1000
export function buildDockerDispatchTargets(targets = []) {
if (!Array.isArray(targets)) return []
return targets.map(target => ({
containerId: target.id,
containerName: target.name,
nodeId: target.nodeId || null,
}))
}
export function buildDockerInstanceSwitchContext({ containerId, name, port, gatewayPort, nodeId }) {
if (!containerId) throw new Error('缺少容器 ID')
if (!name) throw new Error('缺少容器名称')
const panelPort = parseRequiredPort(port, '面板端口')
const parsedGatewayPort = parseOptionalPort(gatewayPort, 18789)
return {
instanceId: `docker-${containerId.slice(0, 12)}`,
reloadRoute: true,
registration: {
name,
type: 'docker',
endpoint: `http://127.0.0.1:${panelPort}`,
gatewayPort: parsedGatewayPort,
containerId,
nodeId: nodeId || null,
note: 'Added from Docker page',
},
}
}
function parseRequiredPort(value, label) {
const port = Number.parseInt(value, 10)
if (Number.isInteger(port) && port > 0) return port
throw new Error(`${label}无效`)
}
function parseOptionalPort(value, fallback) {
const port = Number.parseInt(value, 10)
if (Number.isInteger(port) && port > 0) return port
return fallback
}

View File

@@ -1,204 +0,0 @@
// 像素风格龙虾兵角色图
// 每个角色是一个 16x16 像素画,用 SVG rects 渲染
// 调色板0=制服主色 1=制服亮色 2=制服暗色 3=虾红(头/钳) 4=深色(眼) 5=白 6=装备色 .=透明
// 制服用兵种色 → 每个角色外观差异明显
const PIXEL_CHARS = {
// 步兵 — 灰蓝制服 + 钢盔
general: {
palette: ['#64748b', '#94a3b8', '#475569', '#e74c3c', '#1e293b', '#ffffff', '#cbd5e1'],
pixels: [
'................',
'......0022......',
'.....006622.....',
'....00000000....',
'..3..044440..3..',
'..3..055550..3..',
'.33..044440..33.',
'.....000000.....',
'....00011000....',
'....00000000....',
'.....000000.....',
'.....000000.....',
'......0000......',
'.....00..00.....',
'.....00..00.....',
'.....22..22.....',
],
},
// 突击兵(coder) — 金黄制服 + 护目镜 + 闪电
coder: {
palette: ['#f59e0b', '#fbbf24', '#b45309', '#e74c3c', '#1e293b', '#ffffff', '#fef3c7'],
pixels: [
'.......66.......',
'......6666......',
'.....666666.....',
'....00066000....',
'..3..044440..3..',
'..3..055550..3..',
'.33..044440..33.',
'.....000000.....',
'....00011000....',
'....00000000....',
'.....000000.....',
'.6...000000...6.',
'.66...0000...66.',
'.....00..00.....',
'.....00..00.....',
'.....22..22.....',
],
},
// 翻译官 — 青色制服 + 贝雷帽 + 卷轴
translator: {
palette: ['#06b6d4', '#22d3ee', '#0e7490', '#e74c3c', '#1e293b', '#ffffff', '#ecfeff'],
pixels: [
'....1100........',
'...011000.......',
'...0000000......',
'....000000......',
'..3..044440..3..',
'..3..055550..3..',
'.33..044440..33.',
'.....000000.....',
'....00011000....',
'....00000000..66',
'.....000000..646',
'.....000000..646',
'......0000...66.',
'.....00..00.....',
'.....00..00.....',
'.....22..22.....',
],
},
// 文书官 — 紫色制服 + 文人帽 + 羽毛笔
writer: {
palette: ['#8b5cf6', '#a78bfa', '#6d28d9', '#e74c3c', '#1e293b', '#ffffff', '#ede9fe'],
pixels: [
'..............6.',
'.....0011....6..',
'....001100..6...',
'....000000.6....',
'..3..044440..3..',
'..3..055550..3..',
'.33..044440..33.',
'.....000000.....',
'....00011000....',
'....00000000....',
'.....000000.....',
'.....000000.....',
'......0000......',
'.....00..00.....',
'.....00..00.....',
'.....22..22.....',
],
},
// 参谋(analyst) — 绿色制服 + 眼镜 + 图表板
analyst: {
palette: ['#22c55e', '#4ade80', '#15803d', '#e74c3c', '#1e293b', '#ffffff', '#dcfce7'],
pixels: [
'................',
'......4444......',
'.....444444.....',
'....44444444....',
'..3.066.660.3...',
'..3..055550..3..',
'.33..044440..33.',
'.....000000.....',
'....00011000....',
'....00000000.66.',
'.....000000.626.',
'.....000000.626.',
'......0000..66..',
'.....00..00.....',
'.....00..00.....',
'.....22..22.....',
],
},
// 特种兵(custom) — 深红制服 + 战术面罩 + 扳手
custom: {
palette: ['#ef4444', '#f87171', '#b91c1c', '#dc2626', '#1e293b', '#ffffff', '#fee2e2'],
pixels: [
'......0022......',
'.....020020.....',
'....00000000....',
'....04444400....',
'..3..044440..3..',
'..3..055550..3..',
'.33..044440..33.',
'.....000000.....',
'....00011000....',
'....00000000....',
'.....000000.....',
'.4...000000...4.',
'.44...0000...44.',
'.....00..00.....',
'.....00..00.....',
'.....22..22.....',
],
},
}
// 军营Docker 节点)像素图
const PIXEL_BARRACKS = {
palette: ['#92400e', '#b45309', '#fbbf24', '#d97706', '#78350f', '#ffffff', '#f59e0b'],
pixels: [
'......6666......',
'.....666666.....',
'....33333333....',
'...3333333333...',
'..333333333333..',
'..300053005300..',
'..300053005300..',
'..300053005300..',
'..333333333333..',
'..300053005300..',
'..300053005300..',
'..300053005300..',
'..333333333333..',
'..333300003333..',
'..333300003333..',
'..444444444444..',
],
}
/**
* 生成像素角色 SVG
* @param {string} role - 兵种 key
* @param {number} size - 显示尺寸 (px)
* @returns {string} SVG HTML string
*/
function _renderPixelSvg(data, size) {
const { palette, pixels } = data
const grid = 16
let rects = ''
for (let y = 0; y < pixels.length; y++) {
const row = pixels[y]
for (let x = 0; x < row.length; x++) {
const ch = row[x]
if (ch === '.') continue
const colorIdx = parseInt(ch)
if (isNaN(colorIdx) || !palette[colorIdx]) continue
rects += `<rect x="${x}" y="${y}" width="1" height="1" fill="${palette[colorIdx]}"/>`
}
}
return `<svg viewBox="0 0 ${grid} ${grid}" width="${size}" height="${size}" xmlns="http://www.w3.org/2000/svg" style="image-rendering:pixelated">${rects}</svg>`
}
/**
* 生成像素角色 SVG
* @param {string} role - 兵种 key
* @param {number} size - 显示尺寸 (px)
* @returns {string} SVG HTML string
*/
export function pixelRole(role, size = 32) {
return _renderPixelSvg(PIXEL_CHARS[role] || PIXEL_CHARS.general, size)
}
/**
* 生成军营像素 SVG
* @param {number} size - 显示尺寸 (px)
* @returns {string} SVG HTML string
*/
export function pixelBarracks(size = 32) {
return _renderPixelSvg(PIXEL_BARRACKS, size)
}

View File

@@ -2,18 +2,11 @@
* Tauri API 封装层
* Tauri 环境用 invokeWeb 模式走 dev-api 后端
*/
import { DOCKER_TASK_TIMEOUT_MS } from './docker-tasking.js'
const isTauri = !!window.__TAURI_INTERNALS__
// 仅在 Node.js 后端实现的命令Tauri Rust 不处理),强制走 webInvoke
const WEB_ONLY_CMDS = new Set([
'docker_test_endpoint',
'docker_info', 'docker_list_containers', 'docker_create_container',
'docker_start_container', 'docker_stop_container', 'docker_restart_container',
'docker_remove_container', 'docker_rebuild_container', 'docker_container_logs', 'docker_container_exec', 'docker_init_worker', 'docker_gateway_chat', 'docker_agent', 'docker_agent_broadcast', 'docker_dispatch_task', 'docker_dispatch_broadcast', 'docker_task_status', 'docker_task_list', 'docker_pull_image', 'docker_pull_status',
'docker_list_images', 'docker_list_nodes', 'docker_add_node', 'docker_remove_node',
'docker_cluster_overview',
'instance_list', 'instance_add', 'instance_remove', 'instance_set_active',
'instance_health_check', 'instance_health_all',
'get_deploy_mode',
@@ -270,34 +263,6 @@ export const api = {
instanceHealthCheck: (id) => invoke('instance_health_check', { id }),
instanceHealthAll: () => invoke('instance_health_all'),
// Docker 集群管理
getDeployMode: () => cachedInvoke('get_deploy_mode', {}, 60000),
dockerClusterOverview: () => invoke('docker_cluster_overview'),
dockerTestEndpoint: (endpoint) => invoke('docker_test_endpoint', { endpoint }),
dockerInfo: (nodeId) => invoke('docker_info', { nodeId }),
dockerListContainers: (nodeId, all = true) => invoke('docker_list_containers', { nodeId, all }),
dockerCreateContainer: (opts) => invoke('docker_create_container', opts),
dockerStartContainer: (nodeId, containerId) => { invalidate('docker_cluster_overview', 'docker_list_containers'); return invoke('docker_start_container', { nodeId, containerId }) },
dockerStopContainer: (nodeId, containerId) => { invalidate('docker_cluster_overview', 'docker_list_containers'); return invoke('docker_stop_container', { nodeId, containerId }) },
dockerRestartContainer: (nodeId, containerId) => { invalidate('docker_cluster_overview', 'docker_list_containers'); return invoke('docker_restart_container', { nodeId, containerId }) },
dockerRemoveContainer: (nodeId, containerId, force = false) => { invalidate('docker_cluster_overview', 'docker_list_containers'); return invoke('docker_remove_container', { nodeId, containerId, force }) },
dockerContainerLogs: (nodeId, containerId, tail = 200) => invoke('docker_container_logs', { nodeId, containerId, tail }),
dockerContainerExec: (nodeId, containerId, cmd) => invoke('docker_container_exec', { nodeId, containerId, cmd }),
dockerInitWorker: (nodeId, containerId, role) => invoke('docker_init_worker', { nodeId, containerId, role }),
dockerGatewayChat: (nodeId, containerId, message, timeout = DOCKER_TASK_TIMEOUT_MS) => invoke('docker_gateway_chat', { nodeId, containerId, message, timeout }),
dockerAgent: (nodeId, containerId, cmd) => invoke('docker_agent', { nodeId, containerId, cmd }),
dockerAgentBroadcast: (nodeId, containerIds, message, timeout = DOCKER_TASK_TIMEOUT_MS) => invoke('docker_agent_broadcast', { nodeId, containerIds, message, timeout }),
dockerDispatchTask: (nodeId, containerId, containerName, message, timeout = DOCKER_TASK_TIMEOUT_MS) => invoke('docker_dispatch_task', { nodeId, containerId, containerName, message, timeout }),
dockerDispatchBroadcast: (nodeId, targets, message, timeout = DOCKER_TASK_TIMEOUT_MS) => invoke('docker_dispatch_broadcast', { nodeId, targets, message, timeout }),
dockerTaskStatus: (taskId) => invoke('docker_task_status', { taskId }),
dockerTaskList: (containerId, status) => invoke('docker_task_list', { containerId, status }),
dockerRebuildContainer: (nodeId, containerId, pullLatest = true) => invoke('docker_rebuild_container', { nodeId, containerId, pullLatest }),
dockerPullImage: (nodeId, image, tag, requestId) => invoke('docker_pull_image', { nodeId, image, tag, requestId }),
dockerPullStatus: (requestId) => invoke('docker_pull_status', { requestId }),
dockerListImages: (nodeId) => invoke('docker_list_images', { nodeId }),
dockerListNodes: () => cachedInvoke('docker_list_nodes', {}, 30000),
dockerAddNode: (name, endpoint) => { invalidate('docker_list_nodes', 'docker_cluster_overview'); return invoke('docker_add_node', { name, endpoint }) },
dockerRemoveNode: (nodeId) => { invalidate('docker_list_nodes', 'docker_cluster_overview'); return invoke('docker_remove_node', { nodeId }) },
// 前端热更新
checkFrontendUpdate: () => invoke('check_frontend_update'),