use vue
This commit is contained in:
parent
fe433600ae
commit
70a97be750
24
main.go
24
main.go
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"embed"
|
"embed"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"html/template"
|
|
||||||
"io/fs"
|
"io/fs"
|
||||||
m "k8s-manager/src"
|
m "k8s-manager/src"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
@ -18,17 +17,17 @@ func main() {
|
||||||
|
|
||||||
r := gin.Default()
|
r := gin.Default()
|
||||||
|
|
||||||
r.SetFuncMap(template.FuncMap{
|
//r.SetFuncMap(template.FuncMap{
|
||||||
"inc": m.Inc,
|
// "inc": m.Inc,
|
||||||
})
|
//})
|
||||||
|
//
|
||||||
tmp := template.Must(template.New("").
|
//tmp := template.Must(template.New("").
|
||||||
Funcs(template.FuncMap{
|
// Funcs(template.FuncMap{
|
||||||
"inc": m.Inc,
|
// "inc": m.Inc,
|
||||||
}).
|
// }).
|
||||||
ParseFS(f, "template/*"))
|
// ParseFS(f, "template/*"))
|
||||||
|
//
|
||||||
r.SetHTMLTemplate(tmp)
|
//r.SetHTMLTemplate(tmp)
|
||||||
fp, _ := fs.Sub(f, "static")
|
fp, _ := fs.Sub(f, "static")
|
||||||
r.StaticFS("/static", http.FS(fp))
|
r.StaticFS("/static", http.FS(fp))
|
||||||
|
|
||||||
|
|
@ -42,6 +41,7 @@ func main() {
|
||||||
r.DELETE("/dep", m.JWTAuthMiddleware, m.CreateDeleteDeployment)
|
r.DELETE("/dep", m.JWTAuthMiddleware, m.CreateDeleteDeployment)
|
||||||
|
|
||||||
r.GET("/login/:username", Test)
|
r.GET("/login/:username", Test)
|
||||||
|
r.GET("/username", m.JWTAuthMiddleware, m.GetUsername)
|
||||||
err := r.Run(":8000")
|
err := r.Run(":8000")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/thoas/go-funk"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
@ -49,18 +48,20 @@ func statusString(a *AppViewModel) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func AppPage(c *gin.Context) {
|
func AppPage(c *gin.Context) {
|
||||||
username := c.MustGet("username").(string)
|
//username := c.MustGet("username").(string)
|
||||||
appsvm := funk.Map(GetApps(username), func(a AppModel) AppViewModel { return AppViewModel{AppModel: &a} }).([]AppViewModel)
|
//appsvm := funk.Map(GetApps(username), func(a AppModel) AppViewModel { return AppViewModel{AppModel: &a} }).([]AppViewModel)
|
||||||
for i := range appsvm {
|
//for i := range appsvm {
|
||||||
a := &appsvm[i]
|
// a := &appsvm[i]
|
||||||
a.Status = statusString(a)
|
// a.Status = statusString(a)
|
||||||
a.ServiceDisplayName = a.ServiceName()
|
// a.ServiceDisplayName = a.ServiceName()
|
||||||
}
|
//}
|
||||||
vm := &AppsViewModel{
|
//vm := &AppsViewModel{
|
||||||
Username: username,
|
// Username: username,
|
||||||
Apps: appsvm,
|
// Apps: appsvm,
|
||||||
}
|
//}
|
||||||
c.HTML(http.StatusOK, "app_view.html", vm)
|
|
||||||
|
c.File("template/app_view.html")
|
||||||
|
// c.HTML(http.StatusOK, "app_view.html", vm)
|
||||||
}
|
}
|
||||||
|
|
||||||
func AppMiddleware(c *gin.Context) {
|
func AppMiddleware(c *gin.Context) {
|
||||||
|
|
@ -109,3 +110,8 @@ func GetAppsController(c *gin.Context) {
|
||||||
apps := GetApps(username)
|
apps := GetApps(username)
|
||||||
c.JSON(http.StatusOK, apps)
|
c.JSON(http.StatusOK, apps)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetUsername(c *gin.Context) {
|
||||||
|
username := c.MustGet("username").(string)
|
||||||
|
c.JSON(http.StatusOK, gin.H{"username": username})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,21 +4,22 @@
|
||||||
<link href="static/css/bootstrap.min.css" rel="stylesheet">
|
<link href="static/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<script src="static/js/bootstrap.bundle.min.js"></script>
|
<script src="static/js/bootstrap.bundle.min.js"></script>
|
||||||
<script src="static/js/axios.min.js"></script>
|
<script src="static/js/axios.min.js"></script>
|
||||||
|
<script src="static/js/vue.global.js"></script>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>应用管理</title>
|
<title>应用管理</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container" id="app">
|
||||||
|
|
||||||
<h1>应用管理页面</h1>
|
<h1>应用管理页面</h1>
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<div class="align-self-start">用户名:{{ .Username }}</div>
|
<!-- <div class="align-self-start">用户名:{{ .Username }}</div>-->
|
||||||
<div class="ms-auto align-self-end">
|
<div class="ms-auto align-self-end">
|
||||||
<button class="btn btn-success" onclick="showModal('')">添加应用</button>
|
<button class="btn btn-success" @click="showModal(null)">添加应用</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -40,32 +41,29 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{{ range $i, $v := .Apps }}
|
<tr v-for="(item, index) in apps">
|
||||||
<tr id="app-list-{{ $v.Id }}">
|
<td> {{ index + 1 }}</td>
|
||||||
<td> {{ inc $i }}</td>
|
<td> {{ item.AppName }}</td>
|
||||||
<td class="app-field-id" style="display: none;"> {{ $v.Id }}</td>
|
<td> {{ item.Comment }}</td>
|
||||||
<td class="app-field-name"> {{ $v.AppName }}</td>
|
<td> {{ item.Image }}</td>
|
||||||
<td class="app-field-comment"> {{ $v.Comment }}</td>
|
<td> {{ item.Command }}</td>
|
||||||
<td class="app-field-image"> {{ $v.Image }}</td>
|
<td> {{ item.Env }}</td>
|
||||||
<td class="app-field-cmd"> {{ $v.Command }}</td>
|
<td> {{ item.Status }}</td>
|
||||||
<td class="app-field-env"> {{ $v.Env }}</td>
|
<td> {{ item.ServiceDisplayName }}</td>
|
||||||
<td class="app-field-status" id="app-status-{{ $v.Id }}"> {{ $v.Status }}</td>
|
<td> {{ item.Ports }}</td>
|
||||||
<td class="app-field-svc"> {{ $v.ServiceDisplayName }}</td>
|
|
||||||
<td class="app-field-ports"> {{ $v.Ports }}</td>
|
|
||||||
<td>
|
<td>
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<button class="btn btn-success" onclick="startApp('{{$v.Id}}')">启动</button>
|
<button class="btn btn-success" @click="startApp(item)">启动</button>
|
||||||
<button class="btn btn-dark" onclick="stopApp('{{$v.Id}}')">停止</button>
|
<button class="btn btn-dark" @click="stopApp(item)">停止</button>
|
||||||
<button class="btn btn-primary" onclick="showModal('app-list-{{ $v.Id }}')">修改</button>
|
<button class="btn btn-primary" @click="showModal(item)">修改</button>
|
||||||
<button class="btn btn-danger" onclick="deleteApp('{{ $v.Id }}')">删除</button>
|
<button class="btn btn-danger" @click="deleteApp(item)">删除</button>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{ else }}
|
|
||||||
<tr>
|
<tr v-if="apps.length == 0">
|
||||||
<td colspan="7" style="text-align: center;">点击+按钮添加应用</td>
|
<td colspan="7" style="text-align: center;">点击+按钮添加应用</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{ end }}
|
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
|
|
@ -80,51 +78,53 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
|
|
||||||
<input type="text" id="app-id" class="form-control" style="display: none;" disabled/>
|
|
||||||
<input type="text" id="app-username" class="form-control" style="display: none;" disabled
|
|
||||||
value="{{ .Username }}"/>
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label for="app-name" class="form-label">应用名</label>
|
<label for="app-name" class="form-label">应用名</label>
|
||||||
<input type="text" id="app-name" class="form-control"
|
<input type="text" id="app-name" class="form-control" v-model="selectApp.AppName"
|
||||||
placeholder="只能为字母、数字和下划线"/>
|
placeholder="只能为字母、数字和下划线"/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label for="app-image" class="form-label">镜像</label>
|
<label for="app-image" class="form-label">镜像</label>
|
||||||
<input type="text" id="app-image" class="form-control" placeholder="Docker镜像名"/>
|
<input type="text" id="app-image" class="form-control" v-model="selectApp.Image"
|
||||||
|
placeholder="Docker镜像名"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label for="app-cmd" class="form-label">启动命令</label>
|
<label for="app-cmd" class="form-label">启动命令</label>
|
||||||
<input type="text" id="app-cmd" class="form-control" placeholder="启动命令,可选"/>
|
<input type="text" id="app-cmd" class="form-control" v-model="selectApp.Command"
|
||||||
|
placeholder="启动命令,可选"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label for="app-env" class="form-label">环境变量</label>
|
<label for="app-env" class="form-label">环境变量</label>
|
||||||
<input type="text" id="app-env" class="form-control" placeholder="环境变量,可选"/>
|
<input type="text" id="app-env" class="form-control" v-model="selectApp.Env"
|
||||||
|
placeholder="环境变量,可选"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label for="app-svc" class="form-label">服务名</label>
|
<label for="app-svc" class="form-label">服务名</label>
|
||||||
<input type="text" id="app-svc" class="form-control" placeholder="服务名,可选"/>
|
<input type="text" id="app-svc" class="form-control" v-model="selectApp.SvcName"
|
||||||
|
placeholder="服务名,可选"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label for="app-ports" class="form-label">端口号</label>
|
<label for="app-ports" class="form-label">端口号</label>
|
||||||
<input type="text" id="app-ports" class="form-control" placeholder="端口号,多个端口以逗号分隔"/>
|
<input type="text" id="app-ports" class="form-control" v-model="selectApp.Ports"
|
||||||
|
placeholder="端口号,多个端口以逗号分隔"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label for="app-comment" class="form-label">描述</label>
|
<label for="app-comment" class="form-label">描述</label>
|
||||||
<textarea type="text" id="app-comment" class="form-control" placeholder="应用描述"></textarea>
|
<textarea type="text" id="app-comment" class="form-control" v-model="selectApp.Comment"
|
||||||
|
placeholder="应用描述"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
|
||||||
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" onclick="updateApp()">保存
|
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" @click="updateApp()">保存
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -142,94 +142,78 @@
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function updateModalField(classString, value) {
|
|
||||||
const classArray = classString.split(' ')
|
|
||||||
for (let c of classArray) {
|
|
||||||
if (c.startsWith("app-field-")) {
|
|
||||||
const k = c.replace("app-field-", "app-")
|
|
||||||
const ele = document.getElementById(k)
|
|
||||||
if (!ele) {
|
|
||||||
console.log("Cannot fine element ", k)
|
|
||||||
} else {
|
|
||||||
ele.value = value
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearModalField() {
|
const {createApp} = Vue
|
||||||
const id_list = ["app-id", "app-name", "app-image", "app-cmd", "app-env", "app-comment", "app-svc", "app-ports"]
|
createApp({
|
||||||
for (const k of id_list) {
|
data() {
|
||||||
document.getElementById(k).value = ""
|
return {
|
||||||
|
username: "",
|
||||||
|
apps: [],
|
||||||
|
blankApp: {},
|
||||||
|
selectApp: {
|
||||||
|
Id: "",
|
||||||
|
AppName: "",
|
||||||
|
UserName: "",
|
||||||
|
Image: "",
|
||||||
|
Command: "",
|
||||||
|
Comment: "",
|
||||||
|
Env: "",
|
||||||
|
SvcName: "",
|
||||||
|
Ports: "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
function showModal(id) {
|
methods: {
|
||||||
if (id) {
|
showModal(a) {
|
||||||
const list_tr = document.getElementById(id)
|
if (!a) {
|
||||||
const values = list_tr.children
|
a = JSON.parse(JSON.stringify(this.blankApp))
|
||||||
for (let a of values) {
|
|
||||||
updateModalField(a.className, a.innerHTML.trim())
|
|
||||||
}
|
}
|
||||||
} else {
|
this.selectApp = a;
|
||||||
clearModalField()
|
|
||||||
}
|
|
||||||
|
|
||||||
(new bootstrap.Modal("#edit-modal")).show()
|
(new bootstrap.Modal("#edit-modal")).show()
|
||||||
}
|
},
|
||||||
|
startApp(item) {
|
||||||
function showToast(e) {
|
axios.post("dep?id=" + item.Id).then(e => {
|
||||||
// document.getElementById("toast-content").innerHTML = e.msg
|
console.log(e.data)
|
||||||
// t = new bootstrap.Toast(document.getElementById("success-toast"))
|
})
|
||||||
// console.log(t)
|
},
|
||||||
// t.show()
|
deleteApp(app) {
|
||||||
}
|
axios.delete("app", {
|
||||||
|
data: app
|
||||||
function updateApp() {
|
}).then(e => {
|
||||||
const id_list = ["app-id", "app-name", "app-username", "app-image", "app-cmd", "app-env", "app-comment", "app-svc", "app-ports"]
|
console.log(e.data)
|
||||||
const json_key_list = ["Id", "AppName", "UserName", "Image", "Command", "Env", "Comment", "SvcName", "Ports"]
|
})
|
||||||
let appData = {}
|
},
|
||||||
for (let k in id_list) {
|
stopApp(app) {
|
||||||
appData[json_key_list[k]] = document.getElementById(id_list[k]).value
|
axios.delete("dep?id=" + app.Id).then(e => {
|
||||||
}
|
console.log(e.data)
|
||||||
if (appData['Id']) {
|
})
|
||||||
appData['Id'] = parseInt(appData['Id'])
|
},
|
||||||
axios.put("app", appData).then(e => {
|
updateApp() {
|
||||||
showToast(e.data)
|
let app = this.selectApp
|
||||||
|
if (app.Id) {
|
||||||
|
axios.put("app", app).then(e => {
|
||||||
|
console.log(e)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
appData['Id'] = null
|
app.Id = null
|
||||||
axios.post("app", appData).then(e => {
|
app.UserName = this.username
|
||||||
|
axios.post("app", app).then(e => {
|
||||||
console.log(e)
|
console.log(e)
|
||||||
showToast(e.data)
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
function deleteApp(id) {
|
mounted() {
|
||||||
axios.delete("app", {
|
this.blankApp = JSON.parse(JSON.stringify(this.selectApp))
|
||||||
"data": {
|
axios.get("username").then(r => {
|
||||||
Id: parseInt(id),
|
this.username = r.data.username
|
||||||
Username: document.getElementById("app-username").value
|
|
||||||
}
|
|
||||||
}).then(e => {
|
|
||||||
console.log(e.data)
|
|
||||||
showToast(e.data)
|
|
||||||
})
|
})
|
||||||
}
|
axios.get("apps").then(response => {
|
||||||
|
this.apps = response.data
|
||||||
function startApp(id) {
|
|
||||||
axios.post("dep?id=" + id).then(e => {
|
|
||||||
console.log(e.data)
|
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
function stopApp(id) {
|
|
||||||
axios.delete("dep?id=" + id).then(e => {
|
|
||||||
console.log(e.data)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
}).mount("#app")
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</html>
|
</html>
|
||||||
Loading…
Reference in New Issue