<template> <div class="project-card project-v2"> <div class="project-card__info"> <div class="project-card__desc"> <div class="row"> <span title="项目" class="primary">logwire-v1</span> <span title="状态" class="secondary"> 状态:{{ getStatusLabel(info?.status) }} </span> <span title="分支" class="secondary branch">分支:{{ info?.branch }}</span> <span title="目录" class="secondary">目录:/var/logwire-platform</span> </div> <div v-if="tip" class="row" style="color: #ffa15b;word-break: break-all;"> <span>Tip: {{ tip }}</span> </div> <div class="row" style="position: absolute;bottom: 0px;"> <div class="extra-operation" @click="navigateTo('/git')"> <svg t="1714466723924" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13200" width="200" height="200"><path d="M738.986667 868.693333c0 47.786667 37.546667 85.333333 85.333333 85.333334s85.333333-37.546667 85.333333-85.333334-37.546667-85.333333-85.333333-85.333333-85.333333 39.253333-85.333333 85.333333z" p-id="13201"></path><path d="M824.32 979.626667c-61.44 0-110.933333-49.493333-110.933333-110.933334s49.493333-110.933333 110.933333-110.933333 110.933333 49.493333 110.933333 110.933333-49.493333 110.933333-110.933333 110.933334z m0-170.666667c-32.426667 0-59.733333 27.306667-59.733333 59.733333s27.306667 59.733333 59.733333 59.733334 59.733333-27.306667 59.733333-59.733334-27.306667-59.733333-59.733333-59.733333z" p-id="13202"></path><path d="M269.653333 868.693333c0 47.786667 37.546667 85.333333 85.333334 85.333334s85.333333-37.546667 85.333333-85.333334-37.546667-85.333333-85.333333-85.333333-85.333333 39.253333-85.333334 85.333333z" p-id="13203"></path><path d="M354.986667 979.626667c-61.44 0-110.933333-49.493333-110.933334-110.933334s49.493333-110.933333 110.933334-110.933333 110.933333 49.493333 110.933333 110.933333-49.493333 110.933333-110.933333 110.933334z m0-170.666667c-32.426667 0-59.733333 27.306667-59.733334 59.733333s27.306667 59.733333 59.733334 59.733334 59.733333-27.306667 59.733333-59.733334-27.306667-59.733333-59.733333-59.733333z" p-id="13204"></path><path d="M269.653333 186.026667c0 47.786667 37.546667 85.333333 85.333334 85.333333s85.333333-37.546667 85.333333-85.333333-37.546667-85.333333-85.333333-85.333334-85.333333 39.253333-85.333334 85.333334z" p-id="13205"></path><path d="M354.986667 296.96c-61.44 0-110.933333-49.493333-110.933334-110.933333s49.493333-110.933333 110.933334-110.933334 110.933333 49.493333 110.933333 110.933334-49.493333 110.933333-110.933333 110.933333z m0-170.666667c-32.426667 0-59.733333 27.306667-59.733334 59.733334s27.306667 59.733333 59.733334 59.733333 59.733333-27.306667 59.733333-59.733333-27.306667-59.733333-59.733333-59.733334z" p-id="13206"></path><path d="M824.32 808.96c-13.653333 0-25.6-11.946667-25.6-25.6v-85.333333c0-68.266667-110.933333-114.346667-218.453333-157.013334-75.093333-30.72-150.186667-61.44-199.68-104.106666V785.066667c0 13.653333-11.946667 25.6-25.6 25.6s-25.6-11.946667-25.6-25.6V273.066667c0-13.653333 11.946667-25.6 25.6-25.6s25.6 11.946667 25.6 25.6v63.146666c0 68.266667 110.933333 114.346667 218.453333 157.013334 122.88 51.2 250.88 102.4 250.88 204.8v85.333333c0 13.653333-11.946667 25.6-25.6 25.6z" p-id="13207"></path></svg> 切换分支 </div> <div class="extra-operation" @click="navigateTo('/v1')"> <svg t="1714466827612" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="14201" width="200" height="200"><path d="M544.033302 516.000776V96.000564c0-17.672051-14.478655-31.998984-32.150706-31.998984s-32.150706 14.326933-32.150707 31.998984v420.061624c-54.909072 14.251072-95.809105 64.333925-95.809105 123.935554 0 59.691941 40.82056 109.836206 96.090876 124.000579a32.298816 32.298816 0 0 0-0.281771 4.006195v159.99492c0 17.672051 14.478655 31.998984 32.150707 31.998984s32.150706-14.326933 32.150706-31.998984V768.004516a32.280754 32.280754 0 0 0-0.317894-3.941171c55.389526-14.088512 96.397933-64.301413 96.397932-124.058378 0.010837-59.691941-40.809723-109.832593-96.080038-124.004191z m13.221527 169.249989a64.00158 64.00158 0 1 1 18.744945-45.256635 63.578925 63.578925 0 0 1-18.744945 45.260247zM223.678606 196.003711a32.287979 32.287979 0 0 0 0.292607-4.002582V96.000564a31.970084 31.970084 0 1 0-63.940169 0V192.001129a32.371065 32.371065 0 0 0 0.180622 4.060381c-55.270316 14.160761-96.173962 64.301413-96.173961 124.000579s40.910871 109.818143 96.181186 123.996966a32.360228 32.360228 0 0 0-0.184234 3.937558V927.999436a31.970084 31.970084 0 1 0 63.940169 0V448.000226a32.287979 32.287979 0 0 0-0.278158-3.883372c55.385914-14.088512 96.350971-64.301413 96.350971-124.054765S279.071744 210.084998 223.678606 196.003711z m13.575545 169.315013A64.00158 64.00158 0 1 1 255.999097 320.062089a63.578925 63.578925 0 0 1-18.744946 45.256635zM959.99842 320.062089c0-59.775027-41.048144-109.977091-96.45212-124.058378a32.360228 32.360228 0 0 0 0.173397-4.002582V96.000564a31.970084 31.970084 0 1 0-63.940169 0V192.001129a32.291592 32.291592 0 0 0 0.299833 4.060381c-55.270316 14.160761-96.116162 64.301413-96.116163 124.000579s40.82056 109.836206 96.090876 124.000578a32.298816 32.298816 0 0 0-0.281771 3.99897V927.999436a31.970084 31.970084 0 1 0 63.940169 0V448.061637a32.381903 32.381903 0 0 0-0.166172-3.941171c55.407588-14.084899 96.452119-64.286963 96.45212-124.058377z m-82.746526 45.253022a63.997968 63.997968 0 1 1 18.748558-45.253022 63.578925 63.578925 0 0 1-18.748558 45.253022z" p-id="14202"></path></svg> 修改配置 </div> <div class="extra-operation" @click="handleOpenVscode"> <svg t="1714466933895" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="18229" width="200" height="200"><path d="M753.664 28.672V860.16L28.672 751.616l726.016 244.736 241.664-100.352V129.024L753.664 28.672zM499.712 169.984L277.504 389.12 143.36 288.768 89.088 307.2 225.28 441.344 89.088 576.512l55.296 18.432 134.144-100.352 222.208 220.16 133.12-56.32V226.304l-134.144-56.32z m0 156.672v230.4L347.136 441.344l152.576-114.688z" p-id="18230"></path></svg> 打开 Vscode </div> </div> </div> </div> <div class="project-card__settings"> <div class="setting-item" v-if="info?.status === 'null'" title="初始化" @click="handleInstall"> <svg t="1714465823398" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2319" width="200" height="200"><path d="M56.888889 284.444444h853.333333v682.666667H56.888889V284.444444z m56.888889 56.888889v568.888889h739.555555V341.333333H113.777778zM199.111111 170.666667L125.155556 284.444444H56.888889l113.777778-170.666666h625.777777l113.777778 170.666666h-68.266666l-73.955556-113.777777h-568.888889zM125.155556 284.444444H56.888889l113.777778-170.666666h625.777777l113.777778 170.666666h-68.266666l-73.955556-113.777777h-568.888889L125.155556 284.444444z" p-id="2320"></path><path d="M227.555556 603.022222l39.822222-34.133333 221.866666 193.422222 216.177778-193.422222 39.822222 34.133333-256 227.555556z" p-id="2321"></path><path d="M455.111111 398.222222h56.888889v369.777778H455.111111z" p-id="2322"></path></svg> </div> <div class="setting-item" v-if="info?.status === 'created' || info?.status === 'compiled'" title="编译" @click="handleCompile"> <svg t="1714466022297" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7952" width="200" height="200"><path d="M353.536 32l531.008 1.152 6.016 0.512a36.928 36.928 0 0 1 30.912 36.48v232.832l-0.448 6.016a36.928 36.928 0 0 1-36.48 30.912h-232.896l-9.6 9.664v605.504l-0.512 6.016a36.928 36.928 0 0 1-36.48 30.912h-186.24l-6.016-0.512a36.928 36.928 0 0 1-30.912-36.416V349.568l-9.664-9.664h-232.96l-5.76-0.448a36.928 36.928 0 0 1-31.104-36.48v-112l0.448-5.76a36.928 36.928 0 0 1 18.752-26.688L353.536 32z m484.48 75.008H372.672l-191.36 103.04-5.12 8.512v37.824l9.728 9.664H455.68v642.432l9.664 9.728h93.184l9.6-9.728V266.048h269.888l9.6-9.6V116.608l-9.6-9.664z" p-id="7953"></path></svg> </div> <div class="setting-item" v-if="info?.status === 'compiled'" title="运行" @click="handleExecute"> <svg t="1714466279198" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1111" width="200" height="200"><path d="M512 193.536c175.616 0 318.464 142.848 318.464 318.464s-142.848 318.464-318.464 318.464S193.536 687.616 193.536 512 336.384 193.536 512 193.536M512 102.4c-226.304 0-409.6 183.296-409.6 409.6s183.296 409.6 409.6 409.6 409.6-183.296 409.6-409.6-183.296-409.6-409.6-409.6z" p-id="1112"></path><path d="M670.208 483.328L456.192 360.96a26.0096 26.0096 0 0 0-38.912 22.528v244.736c0 19.968 21.504 32.256 38.912 22.528l214.016-122.368c17.408-10.24 17.408-35.328 0-45.056z" p-id="1113"></path></svg> </div> <div class="setting-item" v-if="info?.status === 'launched'" title="停止" @click="handleStop"> <svg t="1714466309184" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1264" width="200" height="200"><path d="M611.328 638.464H412.672c-14.848 0-27.136-12.288-27.136-27.136V412.672c0-14.848 12.288-27.136 27.136-27.136h198.144c14.848 0 27.136 12.288 27.136 27.136v198.144c0.512 15.36-11.776 27.648-26.624 27.648z" p-id="1265"></path><path d="M512 193.536c175.616 0 318.464 142.848 318.464 318.464s-142.848 318.464-318.464 318.464S193.536 687.616 193.536 512 336.384 193.536 512 193.536M512 102.4c-226.304 0-409.6 183.296-409.6 409.6s183.296 409.6 409.6 409.6 409.6-183.296 409.6-409.6-183.296-409.6-409.6-409.6z" p-id="1266"></path></svg> </div> <div v-if="info?.status?.endsWith('ing')" class="setting-item"> <div class="loading-icon"> <svg t="1714012359955" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4291" width="16" height="16"><path d="M876.864 782.592c3.264 0 6.272-3.2 6.272-6.656 0-3.456-3.008-6.592-6.272-6.592-3.264 0-6.272 3.2-6.272 6.592 0 3.456 3.008 6.656 6.272 6.656z m-140.544 153.344c2.304 2.432 5.568 3.84 8.768 3.84a12.16 12.16 0 0 0 8.832-3.84 13.76 13.76 0 0 0 0-18.56 12.224 12.224 0 0 0-8.832-3.84 12.16 12.16 0 0 0-8.768 3.84 13.696 13.696 0 0 0 0 18.56zM552.32 1018.24c3.456 3.648 8.32 5.76 13.184 5.76a18.368 18.368 0 0 0 13.184-5.76 20.608 20.608 0 0 0 0-27.968 18.368 18.368 0 0 0-13.184-5.824 18.368 18.368 0 0 0-13.184 5.76 20.608 20.608 0 0 0 0 28.032z m-198.336-5.76c4.608 4.8 11.072 7.68 17.6 7.68a24.448 24.448 0 0 0 17.536-7.68 27.456 27.456 0 0 0 0-37.248 24.448 24.448 0 0 0-17.536-7.68 24.448 24.448 0 0 0-17.6 7.68 27.52 27.52 0 0 0 0 37.184z m-175.68-91.84c5.76 6.08 13.824 9.6 21.952 9.6a30.592 30.592 0 0 0 22.016-9.6 34.368 34.368 0 0 0 0-46.592 30.592 30.592 0 0 0-22.016-9.6 30.592 30.592 0 0 0-21.952 9.6 34.368 34.368 0 0 0 0 46.592z m-121.152-159.36c6.912 7.36 16.64 11.648 26.368 11.648a36.736 36.736 0 0 0 26.432-11.584 41.28 41.28 0 0 0 0-55.936 36.736 36.736 0 0 0-26.432-11.584 36.8 36.8 0 0 0-26.368 11.52 41.28 41.28 0 0 0 0 56zM12.736 564.672a42.88 42.88 0 0 0 30.784 13.44 42.88 42.88 0 0 0 30.784-13.44 48.128 48.128 0 0 0 0-65.216 42.88 42.88 0 0 0-30.72-13.44 42.88 42.88 0 0 0-30.848 13.44 48.128 48.128 0 0 0 0 65.216z m39.808-195.392a48.96 48.96 0 0 0 35.2 15.36 48.96 48.96 0 0 0 35.2-15.36 54.976 54.976 0 0 0 0-74.56 48.96 48.96 0 0 0-35.2-15.424 48.96 48.96 0 0 0-35.2 15.424 54.976 54.976 0 0 0 0 74.56zM168.32 212.48c10.368 11.008 24.96 17.408 39.68 17.408 14.592 0 29.184-6.4 39.552-17.408a61.888 61.888 0 0 0 0-83.84 55.104 55.104 0 0 0-39.616-17.408c-14.656 0-29.248 6.4-39.616 17.408a61.888 61.888 0 0 0 0 83.84zM337.344 124.8c11.52 12.16 27.712 19.264 43.968 19.264 16.256 0 32.448-7.04 43.968-19.264a68.672 68.672 0 0 0 0-93.184 61.248 61.248 0 0 0-43.968-19.264 61.248 61.248 0 0 0-43.968 19.264 68.736 68.736 0 0 0 0 93.184z m189.632-1.088c12.672 13.44 30.528 21.248 48.448 21.248s35.712-7.808 48.384-21.248a75.584 75.584 0 0 0 0-102.464A67.392 67.392 0 0 0 575.36 0c-17.92 0-35.776 7.808-48.448 21.248a75.584 75.584 0 0 0 0 102.464z m173.824 86.592c13.824 14.592 33.28 23.104 52.736 23.104 19.584 0 39.04-8.512 52.8-23.104a82.432 82.432 0 0 0 0-111.744 73.472 73.472 0 0 0-52.8-23.168c-19.52 0-38.912 8.512-52.736 23.168a82.432 82.432 0 0 0 0 111.744z m124.032 158.528c14.976 15.872 36.032 25.088 57.216 25.088 21.12 0 42.24-9.216 57.152-25.088a89.344 89.344 0 0 0 0-121.088 79.616 79.616 0 0 0-57.152-25.088c-21.184 0-42.24 9.216-57.216 25.088a89.344 89.344 0 0 0 0 121.088z m50.432 204.032c16.128 17.088 38.784 27.008 61.632 27.008 22.784 0 45.44-9.92 61.568-27.008a96.256 96.256 0 0 0 0-130.432 85.76 85.76 0 0 0-61.568-27.072c-22.848 0-45.44 9.984-61.632 27.072a96.192 96.192 0 0 0 0 130.432z" p-id="4292"></path></svg> </div> </div> </div> </div> </template> <script setup lang="ts"> import { Socket, io } from 'socket.io-client'; import { useUserStore } from '~/store/user'; let tip = ref('') let { pending, data: info, execute } = useLazyFetch('/api/devops/v1/getProjectInfo') watch(info, (info) => { useUserStore().setBranchV1({ branchV1: info?.branch || '' }) if (info && info.status) { tip.value = getTip(info.status) || '' } }) let socket: Socket = getWebSocket() onMounted(() => { socket.on('v1', (e: string) => { const data = JSON.parse(e) as { type: string , message: string } if (data.type === 'Tip') { tip.value = data.message } else if (data.type === 'Status') { info.value!.status = data.message as any tip.value = getTip(data.message) || '' } }) }) onUnmounted(() => { socket.removeListener('v1') }) function handleOpenVscode() { window.open(window.location.protocol + '//' + window.location.hostname + ':' + useUserStore().port + '/vscode?folder=/var/logwire-platform', '_blank') } function getStatusLabel(status?: string) { const map = new Map([ ['null', "未初始化"], ['creating', '创建中'], ['created', "已创建"], ['running', '运行中'], ['launched', '正在运行'], ['compiling', '编译中'], ['compiled', '已编译'] ]) return status ? map.get(status) : '' } async function handleStop() { await $fetch('/api/devops/v1/stop', { method: 'post' }) } async function handleExecute() { await $fetch('/api/devops/v1/execute', { method: 'post' }) } async function handleCompile() { await $fetch('/api/devops/v1/compile', { method: 'post'}) } async function handleInstall() { await $fetch('/api/devops/v1/install', { method: 'post' }) execute() } function getTip (status: string) { const HOST = useRuntimeConfig().public.dockerHost const port = useUserStore().port const map = new Map([ ['null', '请点击右侧按钮完成项目初始化'], ['launched', `请代理后端请求到 ${HOST}:${port}`] ]) return map.get(status) } </script> <style scoped> .project-card{ border: 1px solid #fff; background-color: #fff; border: 1px solid #ccc; border-radius: 20px; height: 120px; display: flex; overflow: hidden } .project-card__info{ flex: 1; overflow: hidden; padding: 20px; position: relative; } .project-card__settings{ width: 60px; border-left: 1px solid #ddd; display: flex; flex-direction: column; } .project-card__settings > div{ flex: 1; display: flex; justify-content: center; align-items: center; } .project-card__settings > div:nth-child(n+1) { border-top: 1px solid #ddd; } .project-card__desc > .row{ margin-bottom: 10px; font-size: 14px; } .project-card__desc > .row > .extra-operation { font-size: 12px; color: #999; margin-right: 15px; line-height: 16px; display: inline-block; } .project-card__desc > .row > .extra-operation:hover{ color: #2e75e6 !important; cursor: pointer; } .project-card__desc > .row > .extra-operation > svg{ width: 12px; height: 12px; } .project-card__desc > .row > .primary { font-size: 14px; color: #000; margin-right: 15px; } .project-card__desc > .row > .secondary { font-size: 12px; color: #999; margin-right: 15px; } .branch:hover{ color: #2e75e6 !important; cursor: pointer; } .setting-item:hover{ background-color: #eee; cursor: pointer; } .setting-item > svg { width: 20px; height: 20px; fill: #999; } @keyframes rotate { from { transform: rotate(0); } to { transform: rotate(360deg); } } .loading-icon svg{ animation: rotate infinite 3s linear; } </style>