Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nuxt-backend-helper
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
王曜嵚 Wang Yaoqin
nuxt-backend-helper
Commits
596c911c
Commit
596c911c
authored
Apr 30, 2024
by
王曜嵚 Wang Yaoqin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
dev: websocket 后端传递
parent
b2ffb25e
Changes
31
Hide whitespace changes
Inline
Side-by-side
Showing
31 changed files
with
333 additions
and
371 deletions
+333
-371
main.css
assets/css/main.css
+0
-1
AppAlert.vue
components/AppAlert.vue
+0
-5
BottomLog.vue
components/BottomLog.vue
+9
-13
ProjectV1.vue
components/ProjectV1.vue
+67
-29
ProjectV2.vue
components/ProjectV2.vue
+85
-31
default.vue
layouts/default.vue
+2
-0
auth.global.ts
middleware/auth.global.ts
+5
-0
git.vue
pages/git.vue
+32
-91
home.vue
pages/home.vue
+0
-73
login.vue
pages/login.vue
+5
-7
prepare.vue
pages/prepare.vue
+0
-29
compile.post.ts
server/api/devops/v1/compile.post.ts
+4
-3
execute.post.ts
server/api/devops/v1/execute.post.ts
+10
-3
install.post.ts
server/api/devops/v1/install.post.ts
+4
-3
stop.post.ts
server/api/devops/v1/stop.post.ts
+2
-1
compile.post.ts
server/api/devops/v2/compile.post.ts
+4
-3
debug.post.ts
server/api/devops/v2/debug.post.ts
+5
-5
downloadWeApp.post.ts
server/api/devops/v2/downloadWeApp.post.ts
+13
-20
execute.post.ts
server/api/devops/v2/execute.post.ts
+4
-1
install.post.ts
server/api/devops/v2/install.post.ts
+6
-4
stop.post.ts
server/api/devops/v2/stop.post.ts
+2
-1
getProjectInfo.get.ts
server/api/user/getProjectInfo.get.ts
+0
-1
login.post.ts
server/api/user/login.post.ts
+14
-18
prepare_postgres.ts
server/plugins/prepare_postgres.ts
+5
-15
socket.io.ts
server/plugins/socket.io.ts
+0
-1
environment.d.ts
server/utils/environment.d.ts
+1
-1
index.ts
server/utils/index.ts
+1
-1
log.ts
server/utils/log.ts
+10
-0
postgres.ts
server/utils/postgres.ts
+12
-4
user.ts
store/user.ts
+14
-7
socket.ts
utils/socket.ts
+17
-0
No files found.
assets/css/main.css
View file @
596c911c
...
...
@@ -3,7 +3,6 @@
padding
:
0
;
}
.content
{
background-color
:
#EFEFEF
;
overflow
:
hidden
;
height
:
100%
;
padding
:
24px
;
...
...
components/AppAlert.vue
deleted
100644 → 0
View file @
b2ffb25e
<
template
>
<span>
<slot
/>
</span>
</
template
>
\ No newline at end of file
components/BottomLog.vue
View file @
596c911c
<
template
>
<div
class=
"bottom-log"
v-show=
"userStore.username"
>
<div
class=
"log__icon"
>
<svg
t=
"1713863250860"
fill=
"gray"
class=
"icon"
viewBox=
"0 0 1024 1024"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
p-id=
"5129"
width=
"1
6"
height=
"16
"
><path
d=
"M96 652.8c-19.2 0-38.4-19.2-38.4-38.4V409.6c0-19.2 19.2-38.4 38.4-38.4s38.4 19.2 38.4 38.4v204.8c0 25.6-12.8 38.4-38.4 38.4z"
p-id=
"5130"
></path><path
d=
"M1017.6 512c0-51.2-32-89.6-76.8-102.4V160c0-83.2-64-147.2-147.2-147.2H204.8C121.6 12.8 57.6 76.8 57.6 160v19.2c0 19.2 19.2 38.4 38.4 38.4s38.4-19.2 38.4-38.4v-19.2c0-38.4 32-70.4 70.4-70.4h595.2c38.4 0 70.4 32 70.4 70.4V409.6c-38.4 12.8-76.8 57.6-76.8 102.4 0 51.2 32 89.6 76.8 102.4v249.6c0 38.4-32 70.4-70.4 70.4H204.8c-38.4 0-70.4-32-70.4-70.4v-19.2c0-19.2-19.2-38.4-38.4-38.4s-38.4 19.2-38.4 38.4v19.2c0 83.2 64 147.2 147.2 147.2h595.2c83.2 0 147.2-64 147.2-147.2V620.8c44.8-19.2 70.4-57.6 70.4-108.8z m-108.8 51.2c-25.6 0-51.2-19.2-51.2-51.2 0-25.6 19.2-51.2 51.2-51.2s51.2 19.2 51.2 51.2c-6.4 25.6-25.6 51.2-51.2 51.2z"
p-id=
"5131"
></path><path
d=
"M659.2 332.8H345.6c-19.2 0-38.4-12.8-38.4-38.4 0-19.2 19.2-38.4 38.4-38.4h313.6c19.2 0 38.4 19.2 38.4 38.4 0 25.6-19.2 38.4-38.4 38.4zM659.2 550.4H345.6c-19.2 0-38.4-12.8-38.4-38.4 0-19.2 19.2-38.4 38.4-38.4h313.6c19.2 0 38.4 19.2 38.4 38.4 0 25.6-19.2 38.4-38.4 38.4zM659.2 768H345.6c-19.2 0-38.4-19.2-38.4-38.4s19.2-38.4 38.4-38.4h313.6c19.2 0 38.4 19.2 38.4 38.4 0 25.6-19.2 38.4-38.4 38.4z"
p-id=
"5132"
></path><path
d=
"M153.6 768H44.8c-19.2 0-38.4-19.2-38.4-38.4s19.2-38.4 38.4-38.4h108.8c19.2 0 38.4 19.2 38.4 38.4 0 25.6-19.2 38.4-38.4 38.4z"
p-id=
"5133"
></path><path
d=
"M153.6 332.8H44.8c-25.6 0-38.4-12.8-38.4-38.4 0-19.2 12.8-38.4 38.4-38.4h108.8c19.2 0 38.4 19.2 38.4 38.4 0 25.6-19.2 38.4-38.4 38.4z"
p-id=
"5134"
></path></svg>
<svg
t=
"1713863250860"
fill=
"gray"
class=
"icon"
viewBox=
"0 0 1024 1024"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
p-id=
"5129"
width=
"1
4"
height=
"14
"
><path
d=
"M96 652.8c-19.2 0-38.4-19.2-38.4-38.4V409.6c0-19.2 19.2-38.4 38.4-38.4s38.4 19.2 38.4 38.4v204.8c0 25.6-12.8 38.4-38.4 38.4z"
p-id=
"5130"
></path><path
d=
"M1017.6 512c0-51.2-32-89.6-76.8-102.4V160c0-83.2-64-147.2-147.2-147.2H204.8C121.6 12.8 57.6 76.8 57.6 160v19.2c0 19.2 19.2 38.4 38.4 38.4s38.4-19.2 38.4-38.4v-19.2c0-38.4 32-70.4 70.4-70.4h595.2c38.4 0 70.4 32 70.4 70.4V409.6c-38.4 12.8-76.8 57.6-76.8 102.4 0 51.2 32 89.6 76.8 102.4v249.6c0 38.4-32 70.4-70.4 70.4H204.8c-38.4 0-70.4-32-70.4-70.4v-19.2c0-19.2-19.2-38.4-38.4-38.4s-38.4 19.2-38.4 38.4v19.2c0 83.2 64 147.2 147.2 147.2h595.2c83.2 0 147.2-64 147.2-147.2V620.8c44.8-19.2 70.4-57.6 70.4-108.8z m-108.8 51.2c-25.6 0-51.2-19.2-51.2-51.2 0-25.6 19.2-51.2 51.2-51.2s51.2 19.2 51.2 51.2c-6.4 25.6-25.6 51.2-51.2 51.2z"
p-id=
"5131"
></path><path
d=
"M659.2 332.8H345.6c-19.2 0-38.4-12.8-38.4-38.4 0-19.2 19.2-38.4 38.4-38.4h313.6c19.2 0 38.4 19.2 38.4 38.4 0 25.6-19.2 38.4-38.4 38.4zM659.2 550.4H345.6c-19.2 0-38.4-12.8-38.4-38.4 0-19.2 19.2-38.4 38.4-38.4h313.6c19.2 0 38.4 19.2 38.4 38.4 0 25.6-19.2 38.4-38.4 38.4zM659.2 768H345.6c-19.2 0-38.4-19.2-38.4-38.4s19.2-38.4 38.4-38.4h313.6c19.2 0 38.4 19.2 38.4 38.4 0 25.6-19.2 38.4-38.4 38.4z"
p-id=
"5132"
></path><path
d=
"M153.6 768H44.8c-19.2 0-38.4-19.2-38.4-38.4s19.2-38.4 38.4-38.4h108.8c19.2 0 38.4 19.2 38.4 38.4 0 25.6-19.2 38.4-38.4 38.4z"
p-id=
"5133"
></path><path
d=
"M153.6 332.8H44.8c-25.6 0-38.4-12.8-38.4-38.4 0-19.2 12.8-38.4 38.4-38.4h108.8c19.2 0 38.4 19.2 38.4 38.4 0 25.6-19.2 38.4-38.4 38.4z"
p-id=
"5134"
></path></svg>
</div>
<div
class=
"log__info"
@
click=
"handleChangePanel"
>
<span
v-html=
"lastLog"
></span>
...
...
@@ -13,7 +13,7 @@
<svg
t=
"1713929532584"
class=
"icon"
viewBox=
"0 0 1024 1024"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
p-id=
"4248"
width=
"16"
height=
"16"
><path
d=
"M572.16 512l183.466667-183.04a42.666667 42.666667 0 1 0-60.586667-60.586667L512 451.84l-183.04-183.466667a42.666667 42.666667 0 0 0-60.586667 60.586667l183.466667 183.04-183.466667 183.04a42.666667 42.666667 0 0 0 0 60.586667 42.666667 42.666667 0 0 0 60.586667 0l183.04-183.466667 183.04 183.466667a42.666667 42.666667 0 0 0 60.586667 0 42.666667 42.666667 0 0 0 0-60.586667z"
p-id=
"4249"
></path></svg>
</div>
</div>
<div
class=
'logs-content'
>
<div
class=
'logs-content'
ref=
"logsContent"
>
<div
v-for=
'item in renderLogs'
:key=
'item'
>
<p
v-html=
'item'
></p>
</div>
...
...
@@ -23,7 +23,7 @@
</
template
>
<
script
setup
lang=
"ts"
>
import
{
io
}
from
'socket.io-client'
;
import
{
Socket
,
io
}
from
'socket.io-client'
;
import
{
useUserStore
}
from
"@/store/user"
const
userStore
=
useUserStore
()
...
...
@@ -41,10 +41,8 @@ const renderLogs = computed(() => {
})
userStore
.
$subscribe
(
function
(
mutation
,
state
)
{
if
(
state
.
username
)
{
initWebsocket
(
state
.
username
)
}
})
initWebsocket
(
state
.
username
)
},
{
once
:
true
})
function
addColorfulTag
(
log
:
string
)
{
let
value
=
log
...
...
@@ -55,12 +53,7 @@ function addColorfulTag(log: string) {
}
function
initWebsocket
(
username
:
string
)
{
const
socket
=
io
({
path
:
'/socket.io'
,
auth
:
{
username
}
});
let
socket
:
Socket
=
getWebSocket
()
// eslint-disable-next-line no-control-regex
const
removeLogPrefix
=
(
log
:
string
)
=>
log
.
replace
(
/^
\[
.*
?\]\s
/
,
''
).
replace
(
/
[\u
0000-
\u
0009
]
/g
,
''
).
replace
(
/
[\u
000B-
\u
001F
]
/g
,
''
)
...
...
@@ -74,6 +67,9 @@ function initWebsocket (username: string) {
}
}
})
socket
.
on
(
'ClearLog'
,
()
=>
{
logs
.
value
=
[]
})
}
function
handleChangePanel
()
{
...
...
components/ProjectV1.vue
View file @
596c911c
...
...
@@ -7,46 +7,70 @@
<span
title=
"状态"
class=
"secondary"
>
状态:
{{
getStatusLabel
(
info
?.
status
)
}}
</span>
<span
title=
"分支"
class=
"secondary branch"
@
click=
"handleChangeBranch"
>
分支:
{{
info
?.
branch
}}
</span>
<span
title=
"分支"
class=
"secondary branch"
>
分支:
{{
info
?.
branch
}}
</span>
<span
title=
"目录"
class=
"secondary"
>
目录:/var/logwire-platform
</span>
</div>
<div>
<button
v-if=
"info?.status === 'null'"
class=
"primary"
@
click=
"handleInstall"
>
初始化
</button>
<button
v-if=
"info?.status === 'created' || info?.status === 'compiled'"
@
click=
"handleCompile"
>
编译
</button>
<button
v-if=
"info?.status === 'compiled'"
@
click=
"handleExecute"
>
运行
</button>
<button
v-if=
"info?.status === 'running'"
@
click=
"handleStop"
>
停止
</button>
<div
v-else-if=
"info?.status?.endsWith('ing')"
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"
fill=
"#262626"
p-id=
"4292"
></path></svg>
<div
class=
"row"
style=
"margin-top: 50px;"
>
<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"
@
click=
"handleOpenVscode"
>
<svg
width=
"32"
height=
"32"
t=
"1713861440945"
class=
"icon"
viewBox=
"0 0 1024 1024"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
p-id=
"5245"
><path
d=
"M746.222933 102.239573l-359.799466 330.820267L185.347413 281.4976 102.2464 329.864533l198.20544 182.132054-198.20544 182.132053 83.101013 48.510293 201.076054-151.558826 359.799466 330.676906 175.527254-85.251413V187.4944z m0 217.57952v384.341334l-255.040853-192.177494z"
fill=
"#2196F3"
p-id=
"5246"
></path></svg>
<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"
>
<svg
width=
"32"
height=
"32"
t=
"1713861304749"
class=
"icon"
viewBox=
"0 0 1024 1024"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
p-id=
"4253"
><path
d=
"M439.264 208a16 16 0 0 0-16 16v67.968a239.744 239.744 0 0 0-46.496 26.896l-58.912-34a16 16 0 0 0-21.856 5.856l-80 138.56a16 16 0 0 0 5.856 21.856l58.896 34a242.624 242.624 0 0 0 0 53.728l-58.88 34a16 16 0 0 0-6.72 20.176l0.848 1.68 80 138.56a16 16 0 0 0 21.856 5.856l58.912-34a239.744 239.744 0 0 0 46.496 26.88V800a16 16 0 0 0 16 16h160a16 16 0 0 0 16-16v-67.968a239.744 239.744 0 0 0 46.512-26.896l58.912 34a16 16 0 0 0 21.856-5.856l80-138.56a16 16 0 0 0-4.288-20.832l-1.568-1.024-58.896-34a242.624 242.624 0 0 0 0-53.728l58.88-34a16 16 0 0 0 6.72-20.176l-0.848-1.68-80-138.56a16 16 0 0 0-21.856-5.856l-58.912 34a239.744 239.744 0 0 0-46.496-26.88V224a16 16 0 0 0-16-16h-160z m32 48h96v67.376l28.8 12.576c13.152 5.76 25.632 12.976 37.184 21.52l25.28 18.688 58.448-33.728 48 83.136-58.368 33.68 3.472 31.2a194.624 194.624 0 0 1 0 43.104l-3.472 31.2 58.368 33.68-48 83.136-58.432-33.728-25.296 18.688c-11.552 8.544-24.032 15.76-37.184 21.52l-28.8 12.576V768h-96v-67.376l-28.784-12.576c-13.152-5.76-25.632-12.976-37.184-21.52l-25.28-18.688-58.448 33.728-48-83.136 58.368-33.68-3.472-31.2a194.624 194.624 0 0 1 0-43.104l3.472-31.2-58.368-33.68 48-83.136 58.432 33.728 25.296-18.688a191.744 191.744 0 0 1 37.184-21.52l28.8-12.576V256z m47.28 144a112 112 0 1 0 0 224 112 112 0 0 0 0-224z m0 48a64 64 0 1 1 0 128 64 64 0 0 1 0-128z"
fill=
"#5A626A"
p-id=
"4254
"
></path></svg>
<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
style=
"display: none;"
>
<button>
切换分支
</button>
<button>
修改配置
</button>
<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
{
pending
,
data
:
info
}
=
useFetch
(
'/api/devops/v1/getProjectInfo'
)
let
{
pending
,
data
:
info
}
=
useLazyFetch
(
'/api/devops/v1/getProjectInfo'
)
watch
(
info
,
(
info
)
=>
{
useUserStore
().
setBranchV1
({
branchV1
:
info
?.
branch
||
''
})
})
function
handleChangeBranch
()
{
let
socket
:
Socket
=
getWebSocket
()
}
onMounted
(()
=>
{
socket
.
on
(
'ChangeV1Status'
,
(
e
:
any
)
=>
{
if
(
info
.
value
)
info
.
value
.
status
=
e
})
})
onUnmounted
(()
=>
{
socket
.
close
()
})
function
handleOpenVscode
()
{
window
.
open
(
window
.
location
.
protocol
+
'//'
+
window
.
location
.
hostname
+
':'
+
useUserStore
().
config
.
port
+
'/vscode?folder=/var/logwire-platform'
,
'_blank'
)
window
.
open
(
window
.
location
.
protocol
+
'//'
+
window
.
location
.
hostname
+
':'
+
useUserStore
().
port
+
'/vscode?folder=/var/logwire-platform'
,
'_blank'
)
}
function
getStatusLabel
(
status
?:
string
)
{
...
...
@@ -55,6 +79,7 @@ function getStatusLabel(status?: string) {
[
'creating'
,
'创建中'
],
[
'created'
,
"已创建"
],
[
'running'
,
'运行中'
],
[
'launched'
,
'正在运行'
],
[
'stopped'
,
'已停止'
],
[
'compiling'
,
'编译中'
],
[
'compiled'
,
'已编译'
]
...
...
@@ -63,24 +88,17 @@ function getStatusLabel(status?: string) {
}
async
function
handleStop
()
{
await
$fetch
(
'/api/devops/v1/stop'
,
{
method
:
'post'
})
if
(
info
.
value
)
info
.
value
.
status
=
'compiled'
}
async
function
handleExecute
()
{
await
$fetch
(
'/api/devops/v1/execute'
,
{
method
:
'post'
})
if
(
info
.
value
)
info
.
value
.
status
=
'running'
}
async
function
handleCompile
()
{
if
(
info
.
value
)
info
.
value
.
status
=
'compiling'
await
$fetch
(
'/api/devops/v1/compile'
,
{
method
:
'post'
})
if
(
info
.
value
)
info
.
value
.
status
=
'compiled'
}
async
function
handleInstall
()
{
if
(
info
.
value
)
info
.
value
.
status
=
'creating'
try
{
await
$fetch
(
'/api/devops/v1/install'
,
{
method
:
'post'
})
if
(
info
.
value
)
info
.
value
.
status
=
'created'
}
catch
(
err
)
{
info
.
value
!
.
status
=
'null'
await
$fetch
(
'/api/devops/v1/install'
,
{
method
:
'post'
})
if
(
info
.
value
)
{
info
.
value
.
branch
=
'master'
}
}
</
script
>
...
...
@@ -119,6 +137,21 @@ async function handleInstall() {
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
;
...
...
@@ -138,6 +171,11 @@ async function handleInstall() {
background-color
:
#eee
;
cursor
:
pointer
;
}
.setting-item
>
svg
{
width
:
20px
;
height
:
20px
;
fill
:
#999
;
}
@keyframes
rotate
{
from
{
...
...
components/ProjectV2.vue
View file @
596c911c
...
...
@@ -7,27 +7,57 @@
<span
title=
"状态"
class=
"secondary"
>
状态:
{{
getStatusLabel
(
info
?.
status
)
}}
</span>
<span
title=
"分支"
class=
"secondary branch"
@
click=
"handleChangeBranch"
>
分支:
{{
info
?.
branch
}}
</span>
<span
title=
"分支"
class=
"secondary branch"
>
分支:
{{
info
?.
branch
}}
</span>
<span
title=
"目录"
class=
"secondary"
>
目录:/var/logwire-backend
</span>
</div>
<div>
<button
v-if=
"info?.status === 'null'"
class=
"primary"
@
click=
"handleInstall"
>
初始化
</button>
<button
v-if=
"info?.status === 'created' || info?.status === 'compiled'"
@
click=
"handleCompile"
>
编译
</button>
<button
v-if=
"info?.status === 'compiled'"
@
click=
"handleExecute"
>
运行
</button>
<button
v-if=
"info?.status === 'running'"
@
click=
"handleStop"
>
停止
</button>
<div
v-else-if=
"info?.status?.endsWith('ing')"
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"
fill=
"#262626"
p-id=
"4292"
></path></svg>
<div
class=
"row"
style=
"margin-top: 50px;"
>
<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('/v2')"
>
<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
class=
"extra-operation"
@
click=
"handleDebug"
>
<svg
t=
"1714466907476"
class=
"icon"
viewBox=
"0 0 1024 1024"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
p-id=
"17233"
width=
"200"
height=
"200"
><path
d=
"M489.23 81.63A160 160 0 0 0 352 240v21.34h320V240A160 160 0 0 0 489.23 81.63z m383.76 143.64a32.004 32.004 0 0 0-31.1 7.56L750.62 320H273.38l-91.3-87.14a31.984 31.984 0 1 0-44.16 46.28l86.08 82.2v177.35H96a32 32 0 0 0 0 64h128V640c0 52.96 14.302 102.596 39.23 145.22L137.92 904.86a32.005 32.005 0 1 0 44.19 46.31L301.82 836.9a287.104 287.104 0 0 0 178.21 89.34V544a32 32 0 0 1 64 0v382.24a287.424 287.424 0 0 0 178.21-89.34l119.71 114.27a32.032 32.032 0 0 0 44.19-46.31L760.8 785.22A287.04 287.04 0 0 0 800 640v-37.34h128a32 32 0 0 0 0-64H800V361.31l86.08-82.17a32.004 32.004 0 0 0-13.09-53.87z"
p-id=
"17234"
></path></svg>
调试
</div>
<div
class=
"extra-operation"
@
click=
"handleZip"
>
<svg
t=
"1714466881817"
class=
"icon"
viewBox=
"0 0 1024 1024"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
p-id=
"16209"
width=
"200"
height=
"200"
><path
d=
"M966.208 246.752L534.144 21.408a47.968 47.968 0 0 0-44.128-0.128L58.08 243.136A47.968 47.968 0 0 0 32 285.824V744.64c0 18.208 10.304 34.848 26.592 42.976l432 215.36a48 48 0 0 0 42.816 0l432-215.36A48 48 0 0 0 992 744.672V289.344c0-17.92-9.952-34.304-25.792-42.592zM508.384 463.68l-162.176-79.808 367.36-196.704 158.4 82.624-363.584 193.888z m3.488-381.696l132.992 69.376-369.312 197.76-144.896-71.328 381.216-195.808zM96 332.096l153.216 75.392v168.256a32 32 0 0 0 64 0v-136.736L480 521.024v405.184L96 734.752V332.096z m448 594.112V517.184l384-204.736v422.304l-384 191.456z"
p-id=
"16210"
></path></svg>
打包微信压缩文件
</div>
</div>
</div>
</div>
<div
class=
"project-card__settings"
>
<div
class=
"setting-item"
@
click=
"handleOpenVscode
"
>
<svg
width=
"32"
height=
"32"
t=
"1713861440945"
class=
"icon"
viewBox=
"0 0 1024 1024"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
p-id=
"5245"
><path
d=
"M746.222933 102.239573l-359.799466 330.820267L185.347413 281.4976 102.2464 329.864533l198.20544 182.132054-198.20544 182.132053 83.101013 48.510293 201.076054-151.558826 359.799466 330.676906 175.527254-85.251413V187.4944z m0 217.57952v384.341334l-255.040853-192.177494z"
fill=
"#2196F3"
p-id=
"5246
"
></path></svg>
<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"
>
<svg
width=
"32"
height=
"32"
t=
"1713861304749"
class=
"icon"
viewBox=
"0 0 1024 1024"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
p-id=
"4253"
><path
d=
"M439.264 208a16 16 0 0 0-16 16v67.968a239.744 239.744 0 0 0-46.496 26.896l-58.912-34a16 16 0 0 0-21.856 5.856l-80 138.56a16 16 0 0 0 5.856 21.856l58.896 34a242.624 242.624 0 0 0 0 53.728l-58.88 34a16 16 0 0 0-6.72 20.176l0.848 1.68 80 138.56a16 16 0 0 0 21.856 5.856l58.912-34a239.744 239.744 0 0 0 46.496 26.88V800a16 16 0 0 0 16 16h160a16 16 0 0 0 16-16v-67.968a239.744 239.744 0 0 0 46.512-26.896l58.912 34a16 16 0 0 0 21.856-5.856l80-138.56a16 16 0 0 0-4.288-20.832l-1.568-1.024-58.896-34a242.624 242.624 0 0 0 0-53.728l58.88-34a16 16 0 0 0 6.72-20.176l-0.848-1.68-80-138.56a16 16 0 0 0-21.856-5.856l-58.912 34a239.744 239.744 0 0 0-46.496-26.88V224a16 16 0 0 0-16-16h-160z m32 48h96v67.376l28.8 12.576c13.152 5.76 25.632 12.976 37.184 21.52l25.28 18.688 58.448-33.728 48 83.136-58.368 33.68 3.472 31.2a194.624 194.624 0 0 1 0 43.104l-3.472 31.2 58.368 33.68-48 83.136-58.432-33.728-25.296 18.688c-11.552 8.544-24.032 15.76-37.184 21.52l-28.8 12.576V768h-96v-67.376l-28.784-12.576c-13.152-5.76-25.632-12.976-37.184-21.52l-25.28-18.688-58.448 33.728-48-83.136 58.368-33.68-3.472-31.2a194.624 194.624 0 0 1 0-43.104l3.472-31.2-58.368-33.68 48-83.136 58.432 33.728 25.296-18.688a191.744 191.744 0 0 1 37.184-21.52l28.8-12.576V256z m47.28 144a112 112 0 1 0 0 224 112 112 0 0 0 0-224z m0 48a64 64 0 1 1 0 128 64 64 0 0 1 0-128z"
fill=
"#5A626A"
p-id=
"4254"
></path></svg>
<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
class=
"setting-item"
@
click=
"handleOpenVscode"
>
<svg
width=
"32"
height=
"32"
t=
"1713861440945"
class=
"icon"
viewBox=
"0 0 1024 1024"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
p-id=
"5245"
><path
d=
"M746.222933 102.239573l-359.799466 330.820267L185.347413 281.4976 102.2464 329.864533l198.20544 182.132054-198.20544 182.132053 83.101013 48.510293 201.076054-151.558826 359.799466 330.676906 175.527254-85.251413V187.4944z m0 217.57952v384.341334l-255.040853-192.177494z"
p-id=
"5246"
></path></svg>
</div>
<div
class=
"setting-item"
>
<svg
width=
"32"
height=
"32"
t=
"1713861304749"
class=
"icon"
viewBox=
"0 0 1024 1024"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
p-id=
"4253"
><path
d=
"M439.264 208a16 16 0 0 0-16 16v67.968a239.744 239.744 0 0 0-46.496 26.896l-58.912-34a16 16 0 0 0-21.856 5.856l-80 138.56a16 16 0 0 0 5.856 21.856l58.896 34a242.624 242.624 0 0 0 0 53.728l-58.88 34a16 16 0 0 0-6.72 20.176l0.848 1.68 80 138.56a16 16 0 0 0 21.856 5.856l58.912-34a239.744 239.744 0 0 0 46.496 26.88V800a16 16 0 0 0 16 16h160a16 16 0 0 0 16-16v-67.968a239.744 239.744 0 0 0 46.512-26.896l58.912 34a16 16 0 0 0 21.856-5.856l80-138.56a16 16 0 0 0-4.288-20.832l-1.568-1.024-58.896-34a242.624 242.624 0 0 0 0-53.728l58.88-34a16 16 0 0 0 6.72-20.176l-0.848-1.68-80-138.56a16 16 0 0 0-21.856-5.856l-58.912 34a239.744 239.744 0 0 0-46.496-26.88V224a16 16 0 0 0-16-16h-160z m32 48h96v67.376l28.8 12.576c13.152 5.76 25.632 12.976 37.184 21.52l25.28 18.688 58.448-33.728 48 83.136-58.368 33.68 3.472 31.2a194.624 194.624 0 0 1 0 43.104l-3.472 31.2 58.368 33.68-48 83.136-58.432-33.728-25.296 18.688c-11.552 8.544-24.032 15.76-37.184 21.52l-28.8 12.576V768h-96v-67.376l-28.784-12.576c-13.152-5.76-25.632-12.976-37.184-21.52l-25.28-18.688-58.448 33.728-48-83.136 58.368-33.68-3.472-31.2a194.624 194.624 0 0 1 0-43.104l3.472-31.2-58.368-33.68 48-83.136 58.432 33.728 25.296-18.688a191.744 191.744 0 0 1 37.184-21.52l28.8-12.576V256z m47.28 144a112 112 0 1 0 0 224 112 112 0 0 0 0-224z m0 48a64 64 0 1 1 0 128 64 64 0 0 1 0-128z"
p-id=
"4254"
></path></svg>
</div>
-->
<div
style=
"display: none;"
>
<button>
切换分支
</button>
<button>
修改配置
</button>
...
...
@@ -40,16 +70,27 @@
</
template
>
<
script
setup
lang=
"ts"
>
import
{
Socket
,
io
}
from
'socket.io-client'
;
import
{
useUserStore
}
from
'~/store/user'
;
let
{
pending
,
data
:
info
}
=
useFetch
(
'/api/devops/v2/getProjectInfo'
)
let
{
pending
,
data
:
info
}
=
useLazyFetch
(
'/api/devops/v2/getProjectInfo'
)
watch
(
info
,
(
info
)
=>
{
useUserStore
().
setBranchV2
({
branchV2
:
info
?.
branch
||
''
})
})
function
handleChangeBranch
()
{
}
let
socket
:
Socket
=
getWebSocket
()
onMounted
(()
=>
{
socket
.
on
(
'ChangeV2Status'
,
(
e
:
any
)
=>
{
console
.
log
(
'info'
,
info
,
e
)
if
(
info
.
value
)
info
.
value
.
status
=
e
})
})
onUnmounted
(()
=>
{
socket
.
close
()
})
function
handleOpenVscode
()
{
window
.
open
(
window
.
location
.
protocol
+
'//'
+
window
.
location
.
hostname
+
':'
+
useUserStore
().
config
.
port
+
'/vscode?folder=/var/logwire-backend'
,
'_blank'
)
window
.
open
(
window
.
location
.
protocol
+
'//'
+
window
.
location
.
hostname
+
':'
+
useUserStore
().
port
+
'/vscode?folder=/var/logwire-backend'
,
'_blank'
)
}
function
getStatusLabel
(
status
?:
string
)
{
...
...
@@ -58,6 +99,7 @@ function getStatusLabel(status?: string) {
[
'creating'
,
'创建中'
],
[
'created'
,
"已创建"
],
[
'running'
,
'运行中'
],
[
'launched'
,
'正在运行'
],
[
'stopped'
,
'已停止'
],
[
'compiling'
,
'编译中'
],
[
'compiled'
,
'已编译'
]
...
...
@@ -66,32 +108,23 @@ function getStatusLabel(status?: string) {
}
async
function
handleDebug
()
{
await
$fetch
(
'/api/devops/v2/debug'
,
{
method
:
'post'
})
if
(
info
.
value
)
info
.
value
.
status
=
'running'
}
async
function
handleZip
()
{
await
$fetch
(
'/api/backend/downloadWeApp'
,
{
method
:
'post'
})
if
(
info
.
value
)
info
.
value
.
status
=
'running'
await
$fetch
(
'/api/devops/v2/downloadWeApp'
,
{
method
:
'post'
})
}
async
function
handleStop
()
{
await
$fetch
(
'/api/devops/v2/stop'
,
{
method
:
'post'
})
if
(
info
.
value
)
info
.
value
.
status
=
'compiled'
}
async
function
handleExecute
()
{
await
$fetch
(
'/api/devops/v2/execute'
,
{
method
:
'post'
})
if
(
info
.
value
)
info
.
value
.
status
=
'running'
}
async
function
handleCompile
()
{
if
(
info
.
value
)
info
.
value
.
status
=
'compiling'
await
$fetch
(
'/api/devops/v2/compile'
,
{
method
:
'post'
})
if
(
info
.
value
)
info
.
value
.
status
=
'compiled'
}
async
function
handleInstall
()
{
if
(
info
.
value
)
info
.
value
.
status
=
'creating'
try
{
await
$fetch
(
'/api/devops/v2/install'
,
{
method
:
'post'
})
if
(
info
.
value
)
info
.
value
.
status
=
'created'
}
catch
(
err
)
{
info
.
value
!
.
status
=
'null'
await
$fetch
(
'/api/devops/v2/install'
,
{
method
:
'post'
})
if
(
info
.
value
)
{
info
.
value
.
branch
=
'master'
}
}
</
script
>
...
...
@@ -104,7 +137,8 @@ async function handleInstall() {
border-radius
:
20px
;
height
:
120px
;
display
:
flex
;
overflow
:
hidden
overflow
:
hidden
;
margin-bottom
:
20px
;
}
.project-card__info
{
flex
:
1
;
...
...
@@ -130,6 +164,21 @@ async function handleInstall() {
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
;
...
...
@@ -145,6 +194,11 @@ async function handleInstall() {
color
:
#2e75e6
!important
;
cursor
:
pointer
;
}
.setting-item
>
svg
{
width
:
20px
;
height
:
20px
;
fill
:
#999
;
}
.setting-item
:hover
{
background-color
:
#eee
;
cursor
:
pointer
;
...
...
layouts/default.vue
View file @
596c911c
...
...
@@ -50,5 +50,7 @@
#app
.maintab
{
flex
:
1
;
overflow
:
hidden
;
margin
:
0
auto
;
max-width
:
800px
;
}
</
style
>
middleware/auth.global.ts
View file @
596c911c
import
{
useUserStore
}
from
"~/store/user"
export
default
defineNuxtRouteMiddleware
((
to
,
from
)
=>
{
if
(
to
.
path
===
'/'
)
{
return
navigateTo
(
'/login'
)
}
else
if
(
to
.
path
!==
'/login'
&&
!
useUserStore
().
username
)
{
// 检查是否登录
return
navigateTo
(
'/login'
)
}
})
\ No newline at end of file
pages/git.vue
View file @
596c911c
...
...
@@ -3,24 +3,6 @@
<div
class=
'content'
>
<div
class=
'container'
>
<form
class=
'form'
@
submit
.
prevent
>
<div
class=
'form-group'
>
<div
class=
'form-group__label'
>
<label>
Email
</label>
<p>
用户的 Gitlab 邮箱账号
</p>
</div>
<div
class=
'form-group__body'
>
<input
v-model=
'form.email'
/>
</div>
</div>
<div
class=
'form-group'
>
<div
class=
'form-group__label'
>
<label>
SSH Key
</label>
<p>
使用上述的 Email 邮箱生成 Ssh key,用于 Gitlab 中用户认证
</p>
</div>
<div
class=
'form-group__body'
>
<button
class=
'primary'
@
click=
'handleGenerate'
>
生成 ssh key
</button>
</div>
</div>
<div
class=
'form-group'
>
<div
class=
'form-group__label'
>
<label>
V2 分支管理
</label>
...
...
@@ -32,16 +14,13 @@
<span>
所有分支
</span>
<span>
<select
v-model=
'form.targetBranchV2'
>
<option
v-for=
'item in branchs'
:key=
'item'
>
{{
item
}}
</option>
<option
v-for=
'item in branchs
V2
'
:key=
'item'
>
{{
item
}}
</option>
</select>
</span>
<p>
<button
@
click=
'handleCheckout("v2")'
>
切换分支
</button>
</
p
>
</
span
>
</div>
<div
class=
'form-group__item'
>
<span>
刷新分支
</span>
<p>
刷新当前分支
</p>
<span><button
@
click=
'handleFetch("v2")'
>
刷新
</button></span>
</div>
</div>
...
...
@@ -59,14 +38,11 @@
<select
v-model=
'form.targetBranchV1'
>
<option
v-for=
'item in branchsV1'
:key=
'item'
>
{{
item
}}
</option>
</select>
</span>
<p>
<button
@
click=
'handleCheckout("v1")'
>
切换分支
</button>
</
p
>
</
span
>
</div>
<div
class=
'form-group__item'
>
<span>
刷新分支
</span>
<p>
刷新当前分支
</p>
<span><button
@
click=
'handleFetch("v1")'
>
刷新
</button></span>
</div>
</div>
...
...
@@ -78,6 +54,7 @@
</
template
>
<
script
lang=
"ts"
setup
>
import
{
useUserStore
}
from
'~/store/user'
;
const
form
=
ref
({
email
:
''
,
...
...
@@ -86,86 +63,46 @@ const form = ref({
targetBranchV2
:
''
,
targetBranchV1
:
''
})
const
branchs
=
ref
([])
const
branchs
V2
=
ref
([])
const
branchsV1
=
ref
([])
onMounted
(()
=>
{
onMounted
(
async
()
=>
{
getUserInfo
()
getCurrentBranchV2
()
getCurrentBranchV1
()
getAllBranchV2
()
getAllBranchV1
()
getAllBranch
(
'v1'
)
getAllBranch
(
'v2'
)
})
function
getUserInfo
()
{
$fetch
(
'/api/user/getProjectInfo'
).
then
((
res
:
any
)
=>
{
form
.
value
.
email
=
res
.
username
+
'@greaconsulting.com'
console
.
log
(
form
)
})
}
function
getAllBranchV2
()
{
return
$fetch
(
'/api/git/getAllBranchs'
,
{
query
:
{
platform
:
'v2'
}
}).
then
((
res
:
any
)
=>
{
branchs
.
value
=
res
.
split
(
'
\
n'
).
map
((
o
:
string
)
=>
o
.
trim
()).
filter
((
o
:
string
)
=>
!!
o
)
})
}
function
getAllBranchV1
()
{
return
$fetch
(
'/api/git/getAllBranchs'
,
{
query
:
{
platform
:
'v1'
}
}).
then
((
res
:
any
)
=>
{
branchsV1
.
value
=
res
.
split
(
'
\
n'
).
map
((
o
:
string
)
=>
o
.
trim
()).
filter
((
o
:
string
)
=>
!!
o
)
})
}
function
getCurrentBranchV2
()
{
return
$fetch
(
'/api/git/getCurrentBranch'
,
{
query
:
{
platform
:
'v2'
}
}).
then
((
res
:
any
)
=>
{
form
.
value
.
currentBranchV2
=
res
.
trim
()
form
.
value
.
targetBranchV2
=
form
.
value
.
currentBranchV2
})
form
.
value
.
email
=
useUserStore
().
username
+
'@greaconsulting.com'
form
.
value
.
currentBranchV1
=
useUserStore
().
branchV1
form
.
value
.
currentBranchV2
=
useUserStore
().
branchV2
form
.
value
.
targetBranchV1
=
form
.
value
.
currentBranchV1
form
.
value
.
targetBranchV2
=
form
.
value
.
currentBranchV2
}
function
getCurrentBranchV1
()
{
return
$fetch
(
'/api/git/getCurrentBranch'
,
{
query
:
{
platform
:
'v1'
}
}).
then
((
res
:
any
)
=>
{
form
.
value
.
currentBranchV1
=
res
.
trim
()
form
.
value
.
targetBranchV1
=
form
.
value
.
currentBranchV1
})
}
function
handleGenerate
()
{
$fetch
(
'/api/git/generateSsh'
,
{
method
:
'post'
,
body
:
{
email
:
form
.
value
.
email
}
}).
then
(
res
=>
{
if
(
res
)
{
const
input
=
document
.
createElement
(
'input'
)
input
.
value
=
res
document
.
body
.
appendChild
(
input
)
input
.
select
()
document
.
execCommand
(
'copy'
)
alert
(
'已拷贝 SSH Key, 请前往 Gitlab 更新个人 SSH Key 配置'
)
document
.
body
.
removeChild
(
input
)
function
getAllBranch
(
platform
:
'v1'
|
'v2'
)
{
return
$fetch
(
'/api/git/getAllBranchs'
,
{
query
:
{
platform
}
}).
then
((
res
:
any
)
=>
{
if
(
platform
===
'v1'
)
{
branchsV1
.
value
=
res
.
split
(
'
\
n'
).
map
((
o
:
string
)
=>
o
.
trim
()).
filter
((
o
:
string
)
=>
!!
o
)
}
else
{
branchsV2
.
value
=
res
.
split
(
'
\
n'
).
map
((
o
:
string
)
=>
o
.
trim
()).
filter
((
o
:
string
)
=>
!!
o
)
}
})
}
async
function
handleFetch
(
platform
:
'v1'
|
'v2'
)
{
const
branch
=
platform
===
'v2'
?
form
.
value
.
currentBranchV2
:
form
.
value
.
currentBranchV1
if
(
!
branch
)
return
await
$fetch
(
'/api/git/fetch'
,
{
method
:
'post'
,
body
:
{
branch
,
platform
}})
if
(
platform
===
'v1'
)
{
await
getCurrentBranchV1
()
await
getAllBranchV1
()
}
else
{
await
getCurrentBranchV2
()
await
getAllBranchV2
()
}
alert
(
'刷新分支完成,请重新编译运行'
)
await
getAllBranch
(
platform
)
}
async
function
handleCheckout
(
platform
:
'v1'
|
'v2'
)
{
try
{
const
branch
=
platform
===
'v1'
?
form
.
value
.
targetBranchV1
:
form
.
value
.
targetBranchV2
await
$fetch
(
'/api/git/checkout'
,
{
method
:
'post'
,
body
:
{
platform
,
branch
}
})
if
(
platform
===
'v1'
)
{
await
getCurrentBranchV1
()
form
.
value
.
currentBranchV1
=
form
.
value
.
targetBranchV1
}
else
{
await
getCurrentBranchV2
()
form
.
value
.
currentBranchV2
=
form
.
value
.
targetBranchV2
}
alert
(
'切换分支完成,请重新编译运行'
)
// 后端更新完毕
}
catch
(
err
)
{
console
.
log
(
err
)
const
branch
=
platform
===
'v1'
?
form
.
value
.
targetBranchV1
:
form
.
value
.
targetBranchV2
await
$fetch
(
'/api/git/checkout'
,
{
method
:
'post'
,
body
:
{
platform
,
branch
}
})
if
(
platform
===
'v1'
)
{
form
.
value
.
currentBranchV1
=
form
.
value
.
targetBranchV1
}
else
{
form
.
value
.
currentBranchV2
=
form
.
value
.
targetBranchV2
}
alert
(
'切换分支完成,请重新编译运行'
)
}
</
script
>
...
...
@@ -176,4 +113,8 @@ async function handleCheckout(platform: 'v1' | 'v2') {
height
:
100%
;
padding
:
24px
;
}
.content
select
{
width
:
200px
;
margin-right
:
10px
;
}
</
style
>
\ No newline at end of file
pages/home.vue
View file @
596c911c
...
...
@@ -8,79 +8,6 @@
</
template
>
<
script
lang=
"ts"
setup
>
import
{
useUserStore
}
from
'~/store/user'
;
const
username
=
ref
(
''
)
const
status
=
ref
(
'null'
)
// null | created | stopped | running | creating | compiling
const
statusV1
=
ref
(
'null'
)
const
loading
=
ref
(
false
)
const
logLevel
=
ref
(
'progress'
)
// info | progress
const
logs
=
ref
([]
as
string
[])
const
port
=
ref
(
0
)
onMounted
(
async
()
=>
{
await
getUserInfomation
()
})
async
function
getUserInfomation
()
{
const
res
=
await
$fetch
(
'/api/user/getProjectInfo'
)
if
(
res
)
{
useUserStore
().
setUserConfig
(
res
.
username
,
{
port
:
res
[
"port"
]
})
}
}
function
handleInstallV1
()
{
if
(
loading
.
value
)
return
logs
.
value
=
[]
loading
.
value
=
true
statusV1
.
value
=
'creating'
$fetch
(
'/api/devops/v1/install'
,
{
method
:
'post'
})
.
then
(
getUserInfomation
,
getUserInfomation
)
.
finally
(()
=>
{
loading
.
value
=
false
})
}
function
handleCompileV1
()
{
if
(
loading
.
value
)
return
loading
.
value
=
true
logs
.
value
=
[]
resetV2
()
$fetch
(
'/api/devops/v1/compile'
,
{
method
:
'post'
}).
then
(()
=>
{
return
getUserInfomation
()
}).
finally
(()
=>
{
loading
.
value
=
false
})
}
function
handleExecuteV1
()
{
if
(
loading
.
value
)
return
loading
.
value
=
true
logs
.
value
=
[]
resetV2
()
$fetch
(
'/api/devops/v1/execute'
,
{
method
:
'post'
}).
then
(()
=>
{
return
getUserInfomation
()
}).
finally
(()
=>
{
loading
.
value
=
false
})
}
function
handleStopV1
()
{
if
(
loading
.
value
)
return
logs
.
value
=
[]
loading
.
value
=
true
$fetch
(
'/api/devops/v1/stop'
,
{
method
:
'post'
}).
then
(()
=>
{
return
getUserInfomation
()
}).
finally
(()
=>
{
loading
.
value
=
false
})
}
function
handleOpenVscodeV1
()
{
window
.
open
(
window
.
location
.
protocol
+
'//'
+
window
.
location
.
hostname
+
':'
+
port
+
'/vscode?folder=/var/logwire-platform'
,
'_blank'
)
}
function
resetV1
()
{
statusV1
.
value
=
'created'
}
function
resetV2
()
{
status
.
value
=
'created'
}
</
script
>
<
style
scoped
>
...
...
pages/login.vue
View file @
596c911c
...
...
@@ -32,13 +32,11 @@ function handleLogin () {
$fetch
(
'/api/user/login'
,
{
method
:
'post'
,
body
:
{
username
:
username
.
value
}
}).
then
((
value
)
=>
{
if
(
value
)
{
userStore
.
setUserConfig
(
username
.
value
,
{
port
:
value
[
"port"
]
})
navigateTo
(
'/home'
)
}
else
{
navigateTo
(
'/prepare'
)
}
}).
then
(
value
=>
{
userStore
.
setUserName
({
username
:
value
!
.
username
})
userStore
.
setPort
({
port
:
value
!
.
port
})
setWebSocket
(
username
.
value
,
true
)
navigateTo
(
'/home'
)
})
}
</
script
>
...
...
pages/prepare.vue
deleted
100644 → 0
View file @
b2ffb25e
<
template
>
<div
class=
"prepare"
>
<span>
准备数据库服务中......
</span>
</div>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
useUserStore
}
from
'~/store/user'
;
const
{
data
}
=
useLazyFetch
(
'/api/user/prepare'
,
{
method
:
'post'
})
watch
(
data
,
function
(
value
)
{
if
(
value
)
{
useUserStore
().
setUserConfig
(
value
.
username
,
{
port
:
value
[
'port'
]
})
navigateTo
(
'/home'
)
}
})
</
script
>
<
style
scoped
>
.prepare
{
height
:
100vh
;
width
:
100vw
;
text-align
:
center
;
line-height
:
100vh
;
}
span
{
font-weight
:
bold
;
}
</
style
>
\ No newline at end of file
server/api/devops/v1/compile.post.ts
View file @
596c911c
...
...
@@ -5,8 +5,9 @@ export default defineEventHandler(async (event) => {
let
username
=
event
.
context
.
username
try
{
let
docker
=
createDockerFactory
(
username
)
LogUtil
.
clear
(
username
)
setPgTableData
(
'v1'
,
username
,
'status'
,
'compiling'
)
await
changeProjectStatus
(
'v1'
,
username
,
'status'
,
'compiling'
)
// 每次编译前把已有的 tenants_config 文件夹拷贝到一个地方,编译完成后,再拷贝回来
let
container
=
await
docker
.
checkContainer
(
username
+
'.node'
)
...
...
@@ -37,9 +38,9 @@ export default defineEventHandler(async (event) => {
await
docker
.
execContainerCommand
({
container
,
cmd
:
'rm ../tenants.tar.gz'
,
dir
:
'/var/logwire-platform/dist'
})
await
copyAndCreateServerPropertiesV1InDocker
(
username
)
LogUtil
.
printInfo
(
username
,
'编译完成'
)
await
setPgTableData
(
'v1'
,
username
,
'status'
,
'compiled'
)
await
changeProjectStatus
(
'v1'
,
username
,
'status'
,
'compiled'
)
}
catch
(
err
)
{
await
setPgTableData
(
'v1'
,
username
,
'status'
,
'created'
)
await
changeProjectStatus
(
'v1'
,
username
,
'status'
,
'created'
)
LogUtil
.
printError
(
username
,
err
instanceof
Error
?
err
.
message
:
JSON
.
stringify
(
err
))
setResponseStatus
(
event
,
500
)
return
err
...
...
server/api/devops/v1/execute.post.ts
View file @
596c911c
import
LogUtil
from
"~/server/utils/log"
export
default
defineEventHandler
(
async
(
event
)
=>
{
let
username
=
event
.
context
.
username
let
username
=
event
.
context
.
username
try
{
LogUtil
.
clear
(
username
)
let
docker
=
createDockerFactory
(
username
)
let
container
=
await
docker
.
checkContainer
(
username
+
'.node'
)
const
row
=
await
getPgTableData
(
'user'
,
username
)
const
port
=
row
?.[
"port"
]
LogUtil
.
printInfo
(
username
,
'程序启动中'
)
await
changeProjectStatus
(
'v1'
,
username
,
'status'
,
'running'
)
if
(
!
container
)
{
throw
new
Error
(
'没有创建容器,请先初始化容器'
)
}
...
...
@@ -22,6 +25,10 @@ export default defineEventHandler(async (event) => {
LogUtil
.
print
(
username
,
`[progress] [[1;34mInfo[m] 程序运行中...... \n`
)
LogUtil
.
print
(
username
,
`[progress] [[1;34mInfo[m] 请代理后端请求到 <strong>
${
HOST
}
:
${
port
}
</strong> 上 \n`
)
await
setPgTableData
(
'v1'
,
username
,
'status'
,
'running'
)
await
changeProjectStatus
(
'v1'
,
username
,
'status'
,
'launched'
)
}
catch
(
err
)
{
await
changeProjectStatus
(
'v2'
,
username
,
'status'
,
'compiled'
)
LogUtil
.
print
(
username
,
'[error] [[1;31mError[m]] '
+
(
err
instanceof
Error
?
err
.
message
:
JSON
.
stringify
(
err
)))
setResponseStatus
(
event
,
500
)
}
})
\ No newline at end of file
server/api/devops/v1/install.post.ts
View file @
596c911c
...
...
@@ -6,6 +6,7 @@ export default defineEventHandler(async (event) => {
let
username
=
event
.
context
.
username
let
pgClient
=
await
createPgClientFactory
(
username
)
try
{
LogUtil
.
clear
(
username
)
let
docker
=
createDockerFactory
(
username
)
const
rowV2
=
await
getPgTableData
(
'v2'
,
username
)
...
...
@@ -14,7 +15,7 @@ export default defineEventHandler(async (event) => {
}
let
rowV1
=
await
getPgTableData
(
'v1'
,
username
)
if
(
!
rowV1
)
await
insertPgTableData
(
'v1'
,
username
)
await
setPgTableData
(
'v1'
,
username
,
'status'
,
'creating'
)
await
changeProjectStatus
(
'v1'
,
username
,
'status'
,
'creating'
)
let
container
=
await
docker
.
checkContainer
(
username
+
'.node'
)
as
Dockerode
.
Container
if
(
!
container
)
{
throw
new
Error
(
'没有创建容器,请先初始化容器'
)
...
...
@@ -62,11 +63,11 @@ export default defineEventHandler(async (event) => {
await
docker
.
execContainerCommand
({
container
,
cmd
:
'tar -zvxf book.tar -C /var/logwire-platform/dist/projects/demo'
,
dir
:
'/var/logwire-demo'
})
})
await
setPgTableData
(
'v1'
,
username
,
'status'
,
'created'
)
await
changeProjectStatus
(
'v1'
,
username
,
'status'
,
'created'
)
await
stopPgClient
(
pgClient
)
LogUtil
.
printSuccess
(
username
,
'installed'
)
}
catch
(
err
:
any
)
{
await
setPgTableData
(
'v1'
,
username
,
'status'
,
'null'
)
await
changeProjectStatus
(
'v1'
,
username
,
'status'
,
'null'
)
await
stopPgClient
(
pgClient
)
LogUtil
.
printError
(
username
,
(
err
instanceof
Error
?
err
.
message
:
JSON
.
stringify
(
err
)))
setResponseStatus
(
event
,
500
)
...
...
server/api/devops/v1/stop.post.ts
View file @
596c911c
...
...
@@ -2,6 +2,7 @@ import LogUtil from "~/server/utils/log"
export
default
defineEventHandler
(
async
(
event
)
=>
{
let
username
=
event
.
context
.
username
LogUtil
.
clear
(
username
)
let
docker
=
createDockerFactory
(
username
)
let
container
=
await
docker
.
checkContainer
(
username
+
'.node'
)
if
(
!
container
)
{
...
...
@@ -10,5 +11,5 @@ export default defineEventHandler(async (event) => {
LogUtil
.
printInfo
(
username
,
`程序停止中......`
)
await
docker
.
execContainerCommand
({
container
,
cmd
:
'pm2 delete platform'
,
quiet
:
true
})
LogUtil
.
printInfo
(
username
,
`程序已停止`
)
await
setPgTableData
(
'v1'
,
username
,
'status'
,
'compiled'
)
await
changeProjectStatus
(
'v1'
,
username
,
'status'
,
'compiled'
)
})
\ No newline at end of file
server/api/devops/v2/compile.post.ts
View file @
596c911c
...
...
@@ -5,9 +5,10 @@ export default defineEventHandler(async (event) => {
let
username
=
event
.
context
.
username
try
{
let
username
=
event
.
context
.
username
LogUtil
.
clear
(
username
)
let
docker
=
createDockerFactory
(
username
)
await
setPgTableData
(
'v2'
,
username
,
'status'
,
'compiling'
)
await
changeProjectStatus
(
'v2'
,
username
,
'status'
,
'compiling'
)
// TODO: 在后端发送 websocket 通知前端状态变更
// 每次编译前把已有的 tenants_config 文件夹拷贝到一个地方,编译完成后,再拷贝回来
...
...
@@ -36,9 +37,9 @@ export default defineEventHandler(async (event) => {
copyAndCreateGatewayPropertiesV2InDocker
(
username
)
LogUtil
.
print
(
username
,
`[progress] [[1;34mInfo[m] 编译完成 \n`
)
await
setPgTableData
(
'v2'
,
username
,
'status'
,
'compiled'
)
await
changeProjectStatus
(
'v2'
,
username
,
'status'
,
'compiled'
)
}
catch
(
err
)
{
await
setPgTableData
(
'v2'
,
username
,
'status'
,
'created'
)
await
changeProjectStatus
(
'v2'
,
username
,
'status'
,
'created'
)
LogUtil
.
print
(
username
,
'[error] [[1;31mError[m]] '
+
(
err
instanceof
Error
?
err
.
message
:
JSON
.
stringify
(
err
)))
setResponseStatus
(
event
,
500
)
}
...
...
server/api/devops/v2/debug.post.ts
View file @
596c911c
...
...
@@ -3,17 +3,17 @@ import LogUtil from "~/server/utils/log"
export
default
defineEventHandler
(
async
(
event
)
=>
{
// 先判断服务是否启动,启动则关闭,然后调用新的命令启动 java 端
let
username
=
event
.
context
.
username
LogUtil
.
clear
(
username
)
let
docker
=
createDockerFactory
(
username
)
let
container
=
await
docker
.
checkContainer
(
username
+
'.node'
)
if
(
!
container
)
{
throw
new
Error
(
'没有创建容器,请先初始化容器'
)
}
const
rowV2
=
await
getPgTableData
(
'v2'
,
username
)
const
status
=
rowV2
?.
status
const
tenants
=
rowV2
?.
tenants
const
tenants
=
rowV2
!
.
tenants
const
rowUser
=
await
getPgTableData
(
'user'
,
username
)
const
port
=
rowUser
?.[
"port"
]
const
debug
=
rowV2
?
.
debug
const
port
=
rowUser
!
.
port
const
debug
=
rowV2
!
.
debug
// 有可能本身就关闭了
try
{
...
...
@@ -63,5 +63,5 @@ export default defineEventHandler(async (event) => {
LogUtil
.
print
(
username
,
`[progress] [[1;34mInfo[m] 请设置开发环境域名和端口号 <strong>
${
tenants
?.
host
}
<
/strong> 上
\n
`
)
LogUtil
.
print
(
username
,
`[progress] [[1;34mInfo[m] 调试程序已启动,请IP地址为 <strong>
${
debug
?.
host
}
<
/strong> 后端访问 <strong>${HOST}:${port}</
strong
>
进行调试\
n
`)
await
setPgTableData
( 'v2', username, 'status', 'running')
await
changeProjectStatus
( 'v2', username, 'status', 'running')
})
\ No newline at end of file
server/api/devops/v2/downloadWeApp.post.ts
View file @
596c911c
...
...
@@ -2,25 +2,18 @@ import LogUtil from "~/server/utils/log"
export
default
defineEventHandler
(
async
(
event
)
=>
{
let
username
=
event
.
context
.
username
let
pgClient
=
await
createPgClientFactory
(
username
)
try
{
let
username
=
event
.
context
.
username
let
docker
=
createDockerFactory
(
username
)
// 创建 node 容器
let
container
=
await
docker
.
checkContainer
(
username
+
'.node'
)
let
row
=
await
getPgTableData
(
'user'
,
username
)
let
port
=
row
?.[
"port"
]
if
(
container
)
{
LogUtil
.
print
(
username
,
`[progress] [[1;34mInfo[m] 打包微信小程序zip \n`
)
await
docker
.
execContainerCommand
({
container
,
cmd
:
'rm -f weapp.zip'
,
dir
:
'/var/logwire-backend/build-output/backend'
})
await
docker
.
execContainerCommand
({
container
,
cmd
:
`zip -q -r weapp.zip miniapp/main/dist miniapp/main/src/pages miniapp/main/src/app.config.ts`
,
dir
:
'/var/logwire-backend/build-output/backend'
})
LogUtil
.
print
(
username
,
`[progress] [[1;34mInfo[m] 打包结束,访问 <a target="_blank" href="http://192.168.0.4:
${
port
}
/download/backend/">http://192.168.0.4:
${
port
}
/download/backend/</a> 下载 webapp.zip 文件 \n`
)
}
else
{
throw
new
Error
(
'没有创建容器,请先初始化容器'
)
}
}
catch
(
err
)
{
await
stopPgClient
(
pgClient
)
setResponseStatus
(
event
,
500
)
return
err
LogUtil
.
clear
(
username
)
let
docker
=
createDockerFactory
(
username
)
// 创建 node 容器
let
container
=
await
docker
.
checkContainer
(
username
+
'.node'
)
let
row
=
await
getPgTableData
(
'user'
,
username
)
let
port
=
row
?.[
"port"
]
if
(
container
)
{
LogUtil
.
print
(
username
,
`[progress] [[1;34mInfo[m] 打包微信小程序zip \n`
)
await
docker
.
execContainerCommand
({
container
,
cmd
:
'rm -f weapp.zip'
,
dir
:
'/var/logwire-backend/build-output/backend'
})
await
docker
.
execContainerCommand
({
container
,
cmd
:
`zip -q -r weapp.zip miniapp/main/dist miniapp/main/src/pages miniapp/main/src/app.config.ts`
,
dir
:
'/var/logwire-backend/build-output/backend'
})
LogUtil
.
print
(
username
,
`[progress] [[1;34mInfo[m] 打包结束,访问 <a target="_blank" href="http://192.168.0.4:
${
port
}
/download/backend/">http://192.168.0.4:
${
port
}
/download/backend/</a> 下载 webapp.zip 文件 \n`
)
}
else
{
throw
new
Error
(
'没有创建容器,请先初始化容器'
)
}
})
\ No newline at end of file
server/api/devops/v2/execute.post.ts
View file @
596c911c
...
...
@@ -4,6 +4,7 @@ export default defineEventHandler(async (event) => {
let
username
=
event
.
context
.
username
try
{
let
username
=
event
.
context
.
username
LogUtil
.
clear
(
username
)
let
docker
=
createDockerFactory
(
username
)
let
container
=
await
docker
.
checkContainer
(
username
+
'.node'
)
let
rowUser
=
await
getPgTableData
(
'user'
,
username
)
...
...
@@ -12,6 +13,7 @@ export default defineEventHandler(async (event) => {
let
port
=
rowUser
?.[
"port"
]
LogUtil
.
printInfo
(
username
,
`程序初始化中......`
)
await
changeProjectStatus
(
'v2'
,
username
,
'status'
,
'running'
)
if
(
!
container
)
{
throw
new
Error
(
'没有创建容器,请先初始化容器'
)
}
...
...
@@ -32,8 +34,9 @@ export default defineEventHandler(async (event) => {
LogUtil
.
printInfo
(
username
,
`请代理后端请求到 <strong>
${
HOST
}
:
${
port
}
</strong> 上`
)
LogUtil
.
printInfo
(
username
,
`请设置开发环境域名和端口号 <strong>
${
tenants
?.
host
}
<
/strong> 上`
)
await
setPgTableData
(
'v2'
,
username
,
'status'
,
'running
'
)
await
changeProjectStatus
(
'v2'
,
username
,
'status'
,
'launched
'
)
}
catch
(
err
)
{
await
changeProjectStatus
(
'v2'
,
username
,
'status'
,
'compiled'
)
LogUtil
.
printError
(
username
,
(
err
instanceof
Error
?
err
.
message
:
JSON
.
stringify
(
err
)))
setResponseStatus
(
event
,
500
)
return
err
...
...
server/api/devops/v2/install.post.ts
View file @
596c911c
import
Dockerode
from
"dockerode"
import
LogUtil
from
"~/server/utils/log"
import
LogUtil
,
{
sendProjectStatus
}
from
"~/server/utils/log"
import
fs
from
'fs'
import
path
from
'path'
import
{
changeProjectStatus
}
from
"~/server/utils/postgres"
export
default
defineEventHandler
(
async
(
event
)
=>
{
let
username
=
event
.
context
.
username
let
pgClient
=
await
createPgClientFactory
(
'backend_helper'
)
try
{
LogUtil
.
clear
(
username
)
let
docker
=
createDockerFactory
(
username
)
let
host
=
docker
.
host
let
container
:
Dockerode
.
Container
=
{}
as
Dockerode
.
Container
const
port
=
(
await
getPgTableData
(
'user'
,
username
))?.
port
const
row
=
await
getPgTableData
(
'v2'
,
username
)
if
(
!
row
)
await
insertPgTableData
(
'v2'
,
username
)
await
setPgTableData
(
'v2'
,
username
,
'status'
,
'creating'
)
await
changeProjectStatus
(
'v2'
,
username
,
'status'
,
'creating'
)
// 必须要保证创建容器是首先执行
// node 容器根据 dev/prod 环境与否,决定在哪里创建,远程容器还是本机容器
await
LogUtil
.
run
(
username
,
'创建 node 容器'
,
async
()
=>
{
...
...
@@ -186,11 +188,11 @@ export default defineEventHandler(async (event) => {
}
await
setPgTableData
(
'v2'
,
username
,
'debug'
,
JSON
.
stringify
(
debug
))
})
await
setPgTableData
(
'v2'
,
username
,
'status'
,
'created'
)
await
changeProjectStatus
(
'v2'
,
username
,
'status'
,
'created'
)
await
stopPgClient
(
pgClient
)
LogUtil
.
printSuccess
(
username
,
'安装成功'
)
}
catch
(
err
:
any
)
{
await
setPgTableData
(
'v2'
,
username
,
'status'
,
'null'
)
await
changeProjectStatus
(
'v2'
,
username
,
'status'
,
'null'
)
await
stopPgClient
(
pgClient
)
LogUtil
.
printError
(
username
,
(
err
instanceof
Error
?
err
.
message
:
JSON
.
stringify
(
err
)))
setResponseStatus
(
event
,
500
)
...
...
server/api/devops/v2/stop.post.ts
View file @
596c911c
...
...
@@ -2,6 +2,7 @@ import LogUtil from "~/server/utils/log"
export
default
defineEventHandler
(
async
(
event
)
=>
{
let
username
=
event
.
context
.
username
LogUtil
.
clear
(
username
)
let
docker
=
createDockerFactory
(
username
)
let
container
=
await
docker
.
checkContainer
(
username
+
'.node'
)
if
(
!
container
)
{
...
...
@@ -12,5 +13,5 @@ export default defineEventHandler(async (event) => {
await
docker
.
execContainerCommand
({
container
,
cmd
:
'pm2 delete gateway'
,
quiet
:
true
})
LogUtil
.
print
(
username
,
`程序已停止`
)
await
setPgTableData
(
'v2'
,
username
,
'status'
,
'compiled'
)
await
changeProjectStatus
(
'v2'
,
username
,
'status'
,
'compiled'
)
})
\ No newline at end of file
server/api/user/getProjectInfo.get.ts
View file @
596c911c
export
default
defineEventHandler
(
async
(
event
)
=>
{
const
username
=
event
.
context
.
username
let
client
=
await
createPgClientFactory
(
'backend_helper'
)
let
result
=
await
getPgTableData
(
'user'
,
username
)
return
result
})
\ No newline at end of file
server/api/user/login.post.ts
View file @
596c911c
import
{
PgPort
}
from
"~/server/utils/postgres"
import
{
TableUser
}
from
"~/server/utils/postgres"
import
{
SESSION_PASSWORD
}
from
"../../utils"
export
default
defineEventHandler
(
async
(
event
)
=>
{
try
{
const
body
=
await
readBody
(
event
)
const
username
=
body
.
username
const
session
=
await
useSession
(
event
,
{
password
:
SESSION_PASSWORD
})
await
session
.
update
({
username
})
// 生产环境要求必须是先创建好服务器,再启动服务
if
(
process
.
env
.
NODE_ENV
===
'development'
)
{
return
false
}
else
{
let
result
=
await
getPgTableData
(
'user'
,
username
)
return
result
}
}
catch
(
err
)
{
throw
createError
({
statusCode
:
500
,
statusMessage
:
'登录失败'
})
const
body
=
await
readBody
(
event
)
const
username
=
body
.
username
const
session
=
await
useSession
(
event
,
{
password
:
SESSION_PASSWORD
})
await
session
.
update
({
username
})
let
user
=
await
getPgTableData
(
'user'
,
username
)
if
(
!
user
)
{
const
port
=
await
getAvailableNodePort
(
HOST
)
await
insertPgTableData
(
'user'
,
username
)
await
setPgTableData
(
'user'
,
username
,
'port'
,
port
)
user
=
await
getPgTableData
(
'user'
,
username
)
}
return
user
})
\ No newline at end of file
server/
api/user/prepare.post
.ts
→
server/
plugins/prepare_postgres
.ts
View file @
596c911c
import
fs
from
'fs'
import
path
from
'path'
export
default
defineEventHandler
(
async
(
event
)
=>
{
let
username
=
event
.
context
.
username
let
docker
=
createDockerFactory
(
username
)
export
default
defineNitroPlugin
(
async
(
nitroApp
)
=>
{
let
docker
=
createDockerFactory
(
'ADMIN'
)
let
postgres
=
await
docker
.
checkContainer
(
'postgres_12'
)
if
(
!
postgres
)
{
postgres
=
await
docker
.
checkAndCreateContainer
({
name
:
'postgres_12'
,
img
:
'postgres:12'
,
env
:
[
"POSTGRES_PASSWORD=postgres"
],
portBindings
:
{
'5432/tcp'
:
[{
HostPort
:
PgPort
.
toString
()
}]
}
})
...
...
@@ -13,25 +12,16 @@ export default defineEventHandler(async (event) => {
await
docker
.
startContainer
({
container
:
postgres
})
await
sleep
(
3000
)
}
let
client
=
await
createPgClientFactory
()
let
result
=
await
executePgQuery
({
client
,
query
:
"SELECT u.datname FROM pg_catalog.pg_database u where u.datname='backend_helper';"
})
if
(
result
.
rows
.
length
===
0
)
{
await
executePgQuery
({
client
,
query
:
'CREATE DATABASE backend_helper'
})
await
executePgQuery
({
client
,
query
:
fs
.
readFileSync
(
path
.
resolve
(
'./public/files/postgres/create_backend_helper.sql'
),
{
encoding
:
'utf-8'
})
})
await
client
.
end
()
client
=
await
createPgClientFactory
(
'backend_helper'
)
const
sqlCreateUser
=
fs
await
executePgQuery
({
client
,
query
:
fs
.
readFileSync
(
path
.
resolve
(
'./public/files/postgres/create_user.sql'
),
{
encoding
:
'utf-8'
})})
await
executePgQuery
({
client
,
query
:
fs
.
readFileSync
(
path
.
resolve
(
'./public/files/postgres/create_v2.sql'
),
{
encoding
:
'utf-8'
})})
await
executePgQuery
({
client
,
query
:
fs
.
readFileSync
(
path
.
resolve
(
'./public/files/postgres/create_v1.sql'
),
{
encoding
:
'utf-8'
})})
}
else
{
client
=
await
createPgClientFactory
(
'backend_helper'
)
}
let
user
=
await
getPgTableData
(
'user'
,
username
)
if
(
result
.
rowCount
===
0
)
{
const
port
=
await
getAvailableNodePort
(
HOST
)
await
executePgQuery
({
client
,
query
:
`INSERT INTO public."user"(username, port) VALUES ('
${
username
}
', '
${
port
}
');`
})
user
=
await
getPgTableData
(
'user'
,
username
)
await
client
.
end
()
}
return
user
})
\ No newline at end of file
server/plugins/socket.io.ts
View file @
596c911c
...
...
@@ -12,7 +12,6 @@ export default defineNitroPlugin((nitroApp: NitroApp) => {
io
.
on
(
"connection"
,
(
socket
:
any
)
=>
{
let
username
=
socket
.
handshake
.
auth
[
'username'
]
console
.
log
(
'connected success!'
,
username
)
setWebsocketIo
(
username
,
socket
)
});
...
...
server/utils/environment.d.ts
View file @
596c911c
declare
module
global
{
namespace
NodeJS
{
interface
ProcessEnv
{
HOST
:
string
DEV
HOST
:
string
NODE_ENV
:
string
PGUSER
:
string
postgres
:
string
...
...
server/utils/index.ts
View file @
596c911c
import
fs
from
'fs'
export
const
HOST
=
process
.
env
.
NODE_ENV
===
'production'
?
'192.168.0.4'
:
(
process
.
env
.
HOST
||
'192.168.0.190'
)
export
const
HOST
=
process
.
env
.
NODE_ENV
===
'production'
?
'192.168.0.4'
:
(
process
.
env
.
DEV
HOST
||
'192.168.0.190'
)
export
function
readJson
(
path
:
string
):
Record
<
string
,
any
>
{
try
{
...
...
server/utils/log.ts
View file @
596c911c
...
...
@@ -13,6 +13,12 @@ export function getWebsocketIo (username: string) {
return
websocket
.
get
(
username
)
as
Socket
}
export
function
sendProjectStatus
(
platform
:
'v1'
|
'v2'
,
username
:
string
,
status
:
string
)
{
const
eventName
=
platform
===
'v1'
?
'ChangeV1Status'
:
'ChangeV2Status'
const
socket
=
getWebsocketIo
(
username
)
socket
.
emit
(
eventName
,
status
)
}
export
default
class
LogUtil
{
// 根据 log 判断用户是否已经执行过
static
async
run
(
username
:
string
,
log
:
string
,
cb
:
()
=>
Promise
<
void
>
)
{
...
...
@@ -40,4 +46,8 @@ export default class LogUtil {
static
async
printWarning
(
username
:
string
,
log
:
string
)
{
}
static
clear
(
username
:
string
)
{
let
socket
=
getWebsocketIo
(
username
)
socket
.
emit
(
'ClearLog'
)
}
}
server/utils/postgres.ts
View file @
596c911c
import
pg
from
'pg'
import
{
sendProjectStatus
}
from
'./log'
export
const
PgPort
=
process
.
env
.
NODE_ENV
?.
trim
()
===
'production'
?
25556
:
30001
export
const
PgHost
=
process
.
env
.
NODE_ENV
?.
trim
()
===
'production'
?
'192.168.0.4'
:
process
.
env
.
HOST
export
const
PgHost
=
process
.
env
.
NODE_ENV
?.
trim
()
===
'production'
?
'192.168.0.4'
:
process
.
env
.
DEV
HOST
let
pool
:
pg
.
Pool
=
new
pg
.
Pool
({
host
:
PgHost
,
...
...
@@ -41,7 +42,7 @@ export type TableUser = { username: string, port: number }
export
type
TableV2
=
{
username
:
string
status
:
'null'
|
'created'
|
'stopped'
|
'running'
|
'creating'
|
'compiling'
|
'compiled'
status
:
'null'
|
'created'
|
'stopped'
|
'running'
|
'
launched'
|
'
creating'
|
'compiling'
|
'compiled'
tenants
:
Record
<
string
,
any
>
debug
:
Record
<
string
,
any
>
has_debugged
:
boolean
...
...
@@ -50,7 +51,7 @@ export type TableV2 = {
export
type
TableV1
=
{
username
:
string
status
:
'null'
|
'created'
|
'stopped'
|
'running'
|
'creating'
|
'compiling'
|
'compiled'
status
:
'null'
|
'created'
|
'stopped'
|
'running'
|
'
launched'
|
'
creating'
|
'compiling'
|
'compiled'
serverProperties
:
{
id
:
any
,
key
:
string
,
value
:
string
}[]
}
...
...
@@ -65,7 +66,7 @@ export async function getPgTableData (table: string, username: string) {
export
async
function
setPgTableData
(
table
:
'user'
,
username
:
string
,
key
:
keyof
TableUser
,
value
:
TableUser
[
keyof
TableUser
]):
Promise
<
void
>
;
export
async
function
setPgTableData
(
table
:
'v2'
,
username
:
string
,
key
:
keyof
TableV2
,
value
:
TableV2
[
keyof
TableV2
]):
Promise
<
void
>
;
export
async
function
setPgTableData
(
table
:
'v1'
,
username
:
string
,
key
:
keyof
TableV1
,
value
:
TableV1
[
keyof
TableV1
]):
Promise
<
void
>
;
export
async
function
setPgTableData
(
table
:
string
,
username
:
string
,
key
:
string
,
value
:
any
)
{
export
async
function
setPgTableData
(
table
:
'v1'
|
'v2'
|
'user'
,
username
:
string
,
key
:
string
,
value
:
any
)
{
await
pool
.
query
(
`UPDATE public.
${
table
}
SET "
${
key
}
"='
${
value
}
' WHERE username='
${
username
}
'`
)
}
...
...
@@ -76,3 +77,10 @@ export async function insertPgTableData (table: string, username: string) {
await
pool
.
query
(
`INSERT INTO public."
${
table
}
"(username) VALUES ('
${
username
}
');`
)
}
export
async
function
changeProjectStatus
(
table
:
'v2'
,
username
:
string
,
key
:
keyof
TableV2
,
value
:
TableV2
[
keyof
TableV2
]):
Promise
<
void
>
;
export
async
function
changeProjectStatus
(
table
:
'v1'
,
username
:
string
,
key
:
keyof
TableV1
,
value
:
TableV1
[
keyof
TableV1
]):
Promise
<
void
>
;
export
async
function
changeProjectStatus
(
table
:
string
,
username
:
string
,
key
:
string
,
value
:
any
)
{
await
setPgTableData
(
table
as
any
,
username
,
key
as
any
,
value
)
sendProjectStatus
(
table
as
any
,
username
,
value
)
}
store/user.ts
View file @
596c911c
...
...
@@ -2,15 +2,22 @@ import { defineStore } from 'pinia'
export
const
useUserStore
=
defineStore
(
'user'
,
()
=>
{
const
username
=
ref
(
''
)
const
config
=
ref
<
{
port
?:
string
}
>
({})
const
port
=
ref
(
0
)
const
branchV1
=
ref
(
''
)
const
branchV2
=
ref
(
''
)
function
setUserName
(
name
:
string
,
p
?:
string
)
{
username
.
value
=
name
function
setUserName
(
payload
:
{
username
:
string
}
)
{
username
.
value
=
payload
.
user
name
}
function
setUserConfig
(
name
:
string
,
obj
:
Object
)
{
config
.
value
=
obj
username
.
value
=
name
function
setPort
(
payload
:
{
port
:
number
})
{
port
.
value
=
payload
.
port
}
function
setBranchV1
(
payload
:
{
branchV1
:
string
})
{
branchV1
.
value
=
payload
.
branchV1
}
function
setBranchV2
(
payload
:
{
branchV2
:
string
})
{
branchV2
.
value
=
payload
.
branchV2
}
return
{
username
,
config
,
setUserName
,
setUserConfig
}
return
{
username
,
port
,
branchV1
,
branchV2
,
setUserName
,
setPort
,
setBranchV1
,
setBranchV2
}
})
\ No newline at end of file
utils/socket.ts
0 → 100644
View file @
596c911c
import
{
io
,
Socket
}
from
"socket.io-client"
;
let
socket
:
Socket
export
function
setWebSocket
(
username
:
string
,
force
?:
boolean
)
{
if
(
!
socket
||
force
)
{
socket
=
io
({
path
:
'/socket.io'
,
auth
:
{
username
}
});
}
}
export
function
getWebSocket
()
{
return
socket
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment