Browse Source

fix issue

tags/v1.22.4.1^2
zhoupzh 3 years ago
parent
commit
ac735bbee5
10 changed files with 716 additions and 168 deletions
  1. +5
    -1
      modules/templates/helper.go
  2. +22
    -0
      templates/admin/cloudbrain/images.html
  3. +1
    -1
      templates/admin/cloudbrain/list.tmpl
  4. +1
    -1
      templates/admin/cloudbrain/search.tmpl
  5. +3
    -0
      templates/admin/navbar.tmpl
  6. +113
    -112
      templates/repo/cloudbrain/image/edit.tmpl
  7. +2
    -2
      templates/repo/cloudbrain/image/submit.tmpl
  8. +111
    -39
      web_src/js/components/Images.vue
  9. +408
    -0
      web_src/js/components/adminImages.vue
  10. +50
    -12
      web_src/js/features/images.js

+ 5
- 1
modules/templates/helper.go View File

@@ -92,6 +92,7 @@ func NewFuncMap() []template.FuncMap {
"Safe": Safe,
"SafeJS": SafeJS,
"Str2html": Str2html,
"subOne": subOne,
"TimeSince": timeutil.TimeSince,
"TimeSinceUnix": timeutil.TimeSinceUnix,
"TimeSinceUnix1": timeutil.TimeSinceUnix1,
@@ -443,7 +444,10 @@ func SafeJS(raw string) template.JS {
func Str2html(raw string) template.HTML {
return template.HTML(markup.Sanitize(raw))
}

//
func subOne(length int)int{
return length-1
}
// Escape escapes a HTML string
func Escape(raw string) string {
return html.EscapeString(raw)


+ 22
- 0
templates/admin/cloudbrain/images.html View File

@@ -0,0 +1,22 @@
{{template "base/head" .}}
<!-- 弹窗 -->
<div id="mask">
<div id="loadingPage">
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
</div>
<!-- 提示框 -->
<div class="alert"></div>
<div class="admin user">
{{template "admin/navbar" .}}
<div id="images-admin">

</div>
</div>
{{template "base/footer" .}}


+ 1
- 1
templates/admin/cloudbrain/list.tmpl View File

@@ -18,7 +18,7 @@
<div class="ui grid" >
<div class="row" style="border: 1px solid #d4d4d5;margin-top: 15px;padding-top: 0;">
{{template "admin/cloudbrain/search" .}}
<div class="ui ten wide column right aligned" style="margin: 1rem 0;">
<div class="ui six wide column right aligned" style="margin: 1rem 0;">
<a class="ui compact blue basic icon button" style="box-shadow: none !important; padding: 0.8em;" href="/admin/cloudbrains/download"><i class="ri-download-line middle aligned icon"></i>{{.i18n.Tr "admin.cloudbrain.download_report"}}</a>
</div>
<div class="ui sixteen wide column">


+ 1
- 1
templates/admin/cloudbrain/search.tmpl View File

@@ -6,7 +6,7 @@
</div>
</form>
</div>
<div class="ui six wide column" style="margin: 1rem 0;" id="adminCloud">
<div class="ui ten wide column" style="margin: 1rem 0;" id="adminCloud">
<div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;">
<div class="default text" style="color: rgba(0,0,0,.87);">{{.i18n.Tr "admin.cloudbrain.all_task_types"}}</div>
<i class="dropdown icon"></i>


+ 3
- 0
templates/admin/navbar.tmpl View File

@@ -17,6 +17,9 @@
<a class="{{if .PageIsAdminCloudBrains}}active{{end}} item" href="{{AppSubUrl}}/admin/cloudbrains">
云脑任务
</a>
<a class="{{if .PageIsAdminCloudBrains}}active{{end}} item" href="{{AppSubUrl}}/admin/images">
云脑镜像
</a>
<a class="{{if .PageIsAdminHooks}}active{{end}} item" href="{{AppSubUrl}}/admin/hooks">
{{.i18n.Tr "admin.hooks"}}
</a>


+ 113
- 112
templates/repo/cloudbrain/image/edit.tmpl View File

@@ -1,120 +1,121 @@
<style>
.label_color{
color:#505559 !important;
width: 6% !important;
text-align: center;
}
</style>
{{template "base/head" .}}
<div id="mask">
<div id="loadingPage">
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
.label_color{
color:#505559 !important;
width: 6% !important;
text-align: center;
}
</style>
{{template "base/head" .}}
<div id="mask">
<div id="loadingPage">
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
<div class="repository">
{{template "repo/header" .}}
<div class="alert"></div>
<div class="ui container">
<div>
<h4 class="ui top attached header">
{{.i18n.Tr "repo.submit_image"}}
</h4>
<div class="submit-image-tmplvalue" style="display: none;" data-link="/image/{{$.Image.ID}}"></div>
<div class="ui attached segment" style="padding: 2em 3em;padding-bottom: 7rem;">
<form class="ui form" id="form_image">
{{.CsrfTokenHtml}}
<input type="hidden" name="id" value="{{.Image.ID}}">
<div class="inline field">
<label class="label_color" for="">{{$.i18n.Tr "dataset.dataset_available_clusters"}}</label>
<div class="ui basic label" style="border: none !important;color:#3291f8;">
<svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="14" height="14"><path fill="none" d="M0 0h24v24H0z"></path><path d="M4 3h16a1 1 0 0 1 1 1v7H3V4a1 1 0 0 1 1-1zM3 13h18v7a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-7zm4 3v2h3v-2H7zM7 6v2h3V6H7z"></path></svg>
CPU/GPU
</div>
<input type="hidden" value="{{.Type}}" name="type">
</div>
<div class="inline required field">
<label class="label_color" for="">{{$.i18n.Tr "repo.images.name"}}</label>
<input type="hidden" name="tag" value="{{.Image.Tag}}" >
<input disabled value="{{.Image.Tag}}" style="width: 80%;">
<span class="tooltips" style="display: block;padding-left: 0.5rem;">{{.i18n.Tr "cloudbrain.job_name_rule"}}</span>
</div>
<div class="inline required field">
<label class="label_color" for="">{{$.i18n.Tr "dataset.description"}}</label>
<textarea style="width: 80%;" required id="description" value="{{.Image.Description}}" name="description" rows="3" maxlength="255" placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}} onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 255)">{{.Image.Description}}</textarea>
</div>
<div class="inline field" style="display: flex;align-items: center;">
{{$x := (len .Image.Topics) -1}}
<label class="label_color" for="">{{$.i18n.Tr "repo.model.manage.label"}}</label>&nbsp;{{$x}}
<div class="ui multiple search selection dropdown" id="dropdown_image" style="width: 80%;">
<input type="hidden" name="topics" value="{{range $k,$v := .Image.Topics}}{{$v}}{{if ne $k ((len $.Image.Topics))}},{{end}}{{end}}" required>
{{range .Image.Topics}}
<a class="ui label transition visible" data-value="{{.}}" style="display: inline-block !important;">{{.}}<i class="delete icon"></i></a>
{{end}}
<div class="default text" id="default_text">{{.i18n.Tr "repo.repo_label_helpe"}}</div>
<div class="menu" id="course_label_item"></div>
</div>
</div>
<span class="tooltips" style="display: block;padding-left: 0.5rem;margin-top: 0.5rem;margin-bottom: 1rem;">{{.i18n.Tr "repo.image.label_tooltips"}}</span>
<div class="inline fields">
<label class="label_color" for="" style="visibility: hidden;"></label>
<div class="field">
<div class="ui radio checkbox">
<input type="radio" name="isPrivate" checked="{{if not .Image.IsPrivate}} checked {{end}}" value="false">
<label>{{.i18n.Tr "org.settings.visibility.public"}}</label>
</div>
</div>
<div class="field" style="flex: 0.15;">
<div class="ui radio checkbox" >
<input type="radio" name="isPrivate" checked="{{if .Image.IsPrivate}} checked {{end}}" value="true">
<label>{{.i18n.Tr "home.show_private"}}</label>
</div>
</div>
<div class="field">
<span class="label_color">{{.i18n.Tr "repo.images.public_tooltips"}}</span>
</div>
</div>
<div class="repository">
{{template "repo/header" .}}
<div class="alert"></div>
<div class="ui container">
<div>
<h4 class="ui top attached header">
{{.i18n.Tr "repo.submit_image"}}
</h4>
<div class="submit-image-tmplvalue" style="display: none;" data-link="/image/{{$.Image.ID}}"></div>
<div class="ui attached segment" style="padding: 2em 3em;padding-bottom: 7rem;">
<div class="ui form" id="form_image">
{{.CsrfTokenHtml}}
<input type="hidden" name="id" value="{{.Image.ID}}">
<div class="inline field">
<label class="label_color" for="">{{$.i18n.Tr "dataset.dataset_available_clusters"}}</label>
<div class="ui basic label" style="border: none !important;color:#3291f8;">
<svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="14" height="14"><path fill="none" d="M0 0h24v24H0z"></path><path d="M4 3h16a1 1 0 0 1 1 1v7H3V4a1 1 0 0 1 1-1zM3 13h18v7a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-7zm4 3v2h3v-2H7zM7 6v2h3V6H7z"></path></svg>
CPU/GPU
</div>
<input type="hidden" value="{{.Type}}" name="type">
</div>
<div class="inline required field">
<label class="label_color" for="">{{$.i18n.Tr "repo.images.name"}}</label>
<input type="hidden" name="tag" value="{{.Image.Tag}}" >
<input disabled value="{{.Image.Tag}}" style="width: 80%;">
<span class="tooltips" style="display: block;padding-left: 0.5rem;">{{.i18n.Tr "cloudbrain.job_name_rule"}}</span>
</div>
<div class="inline required field">
<label class="label_color" for="">{{$.i18n.Tr "dataset.description"}}</label>
<textarea style="width: 80%;" required id="description" value="{{.Image.Description}}" name="description" rows="3" maxlength="255" placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}} onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 255)">{{.Image.Description}}</textarea>
</div>
<div class="inline field" style="display: flex;align-items: center;">
{{$lenTopics := len .Image.Topics}}
{{$subTopics := subOne $lenTopics}}
<label class="label_color" for="">{{$.i18n.Tr "repo.model.manage.label"}}</label>&nbsp;
<div class="ui multiple search selection dropdown" id="dropdown_image" style="width: 80%;">
<input type="hidden" name="topics" value="{{range $k,$v := .Image.Topics}}{{$v}}{{if ne $k $subTopics}},{{end}}{{end}}" required>
{{range .Image.Topics}}
<a class="ui label transition visible" data-value="{{.}}" style="display: inline-block !important;">{{.}}<i class="delete icon"></i></a>
{{end}}
<div class="default text" id="default_text">{{.i18n.Tr "repo.repo_label_helpe"}}</div>
<div class="menu" id="course_label_item"></div>
</div>
</div>
<span class="tooltips" style="display: block;padding-left: 0.5rem;margin-top: 0.5rem;margin-bottom: 1rem;">{{.i18n.Tr "repo.image.label_tooltips"}}</span>
<div class="inline fields">
<label class="label_color" for="" style="visibility: hidden;"></label>
<div class="field">
<div class="ui radio checkbox">
<input type="radio" name="isPrivate" {{if not .Image.IsPrivate}} checked {{end}} value="false">
<label>{{.i18n.Tr "org.settings.visibility.public"}}</label>
</div>
<div class="inline required field" style="padding-top: 2rem;">
<label class="label_color" for="" style="visibility: hidden;"></label>
<button class="ui create_image green button" type="button">
{{.i18n.Tr "repo.cloudbrain.commit_image"}}
</button>
<a class="ui button" id="cancel_submit_image">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a>
</div>
<div class="field" style="flex: 0.15;">
<div class="ui radio checkbox" >
<input type="radio" name="isPrivate" {{if .Image.IsPrivate}} checked {{end}} value="true">
<label>{{.i18n.Tr "home.show_private"}}</label>
</div>
</form>
</div>
<div class="field">
<span class="label_color">{{.i18n.Tr "repo.images.public_tooltips"}}</span>
</div>
</div>
<div class="inline required field" style="padding-top: 2rem;">
<label class="label_color" for="" style="visibility: hidden;"></label>
<button class="ui create_image green button" type="button">
{{.i18n.Tr "repo.cloudbrain.commit_image"}}
</button>
<a class="ui button" id="cancel_submit_image">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a>
</div>
</div>
</div>
</div>
{{template "base/footer" .}}
<script>
console.log({{$.Link}},{{$.PageFrom}},{{$.Image}})
console.log({{.Image.Description}})
let url_href = {{$.Link}}
function submitImage(){
console.log($('#form_image').serialize())
$.ajax({
url:url_href,
type:'POST',
data:$('#form_image').serialize(),
success:function(res){
console.log("res",res)
},
error: function(xhr){
// 隐藏 loading
// 只有请求不正常(状态码不为200)才会执行
// $('.ui.error.message').text(xhr.responseText)
// $('.ui.error.message').css('display','block')
},
complete:function(xhr){
// $("#mask").css({"display":"none","z-index":"1"})
}
})
}
</script>
</div>
</div>
{{template "base/footer" .}}
<script>
console.log({{$.Link}},{{$.PageFrom}},{{$.Image}})
console.log({{.Image.IsPrivate}})

let url_href = {{$.Link}}
function submitImage(){
console.log($('#form_image').serialize())
$.ajax({
url:url_href,
type:'POST',
data:$('#form_image').serialize(),
success:function(res){
console.log("res",res)
},
error: function(xhr){
// 隐藏 loading
// 只有请求不正常(状态码不为200)才会执行
// $('.ui.error.message').text(xhr.responseText)
// $('.ui.error.message').css('display','block')
},
complete:function(xhr){
// $("#mask").css({"display":"none","z-index":"1"})
}
})
}


</script>

+ 2
- 2
templates/repo/cloudbrain/image/submit.tmpl View File

@@ -25,7 +25,7 @@
</h4>
<div class="submit-image-tmplvalue" style="display: none;" data-link="{{$.Link}}"></div>
<div class="ui attached segment" style="padding: 2em 3em;padding-bottom: 7rem;">
<form class="ui form" id="form_image">
<div class="ui form" id="form_image">
{{.CsrfTokenHtml}}
<div class="inline field">
<label class="label_color" for="">{{$.i18n.Tr "dataset.dataset_available_clusters"}}</label>
@@ -78,7 +78,7 @@
</button>
<a class="ui button" id="cancel_submit_image">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a>
</div>
</form>
</div>
</div>
</div>
</div>


+ 111
- 39
web_src/js/components/Images.vue View File

@@ -11,7 +11,7 @@
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="公开镜像" name="first" v-loading="loadingPublic">
<template v-if="tableDataPublic.length!==0">
<div class="ui sixteen wide column">
<!-- <div class="ui two column stackable grid">
<div class="column">

@@ -22,16 +22,21 @@
</el-input>
</div>
</div> -->
<div class="ui eight wide column">

</div>
<div class="ui three wide column">

</div>
<div class="ui five wide column">

</div>
</div>
<el-row style="align-items: center;display: flex;">
<el-col :span="12">
<div>
<el-checkbox v-model="checked">仅显示平台推荐</el-checkbox>
</div>
</el-col>
<el-col :span="4"><div style="visibility: hidden;">TODO</div></el-col>
<el-col :span="8">
<div>
<el-input placeholder="搜镜像名称/描述/标签..." v-model="search" class="input-with-select" @keyup.enter.native="searchName()">
<el-button id="success" slot="append" icon="el-icon-search" @click="searchName()">搜索</el-button>
</el-input>
</div>
</el-col>
</el-row>
<el-row style="margin-top:15px;">

<el-table
@@ -67,13 +72,13 @@
</template>
</el-table-column>
<el-table-column
prop="type"
prop="cloudbrainType"
label="可用集群"
min-width="10%"
align="center"
>
<template slot-scope="scope">
{{scope.row.type | transformType}}
{{scope.row.cloudbrainType | transformType}}
</template>
</el-table-column>
<el-table-column
@@ -128,20 +133,43 @@
</el-pagination>
</div>
</template>
<el-empty v-else :image-size="200"></el-empty>
<template v-else>
<el-row style="align-items: center;display: flex;">
<el-col :span="12">
<div>
<el-checkbox v-model="checked">备选项</el-checkbox>
</div>
</el-col>
<el-col :span="4"><div style="visibility: hidden;">TODO</div></el-col>
<el-col :span="8">
<div>
<el-input placeholder="搜镜像名称/描述/标签..." v-model="search" class="input-with-select" @keyup.enter.native="searchName()">
<el-button id="success" slot="append" icon="el-icon-search" @click="searchName()">搜索</el-button>
</el-input>
</div>
</el-col>
</el-row>
<el-empty :image-size="200"></el-empty>
</template>
</el-tab-pane>
<el-tab-pane label="我的镜像" name="second" v-loading="loadingCustom">
<template v-if="tableDataCustom.length!==0">
<div class="ui sixteen wide column">
<div class="ui two column stackable grid">
<div class="column">
<el-input placeholder="请输入镜像名称关健词" v-model="search" class="input-with-select" @keyup.enter.native="searchName()">
<el-button slot="append" id="success" icon="el-icon-search" @click="searchName()">搜索</el-button>
<el-row style="align-items: center;display: flex;">
<el-col :span="12">
<div style="visibility: hidden;">
TODO
</div>
</el-col>
<el-col :span="4"><div style="visibility: hidden;">TODO</div></el-col>
<el-col :span="8">
<div>
<el-input placeholder="搜镜像名称/描述/标签..." v-model="search" class="input-with-select" @keyup.enter.native="searchName()">
<el-button id="success" slot="append" icon="el-icon-search" @click="searchName()">搜索</el-button>
</el-input>
</div>
</div>
</div>
</div>
</el-col>
</el-row>
<el-row style="margin-top:15px;">
<el-table
:data="tableDataCustom"
@@ -176,13 +204,13 @@
</template>
</el-table-column>
<el-table-column
prop="type"
prop="cloudbrainType"
label="可用集群"
min-width="10%"
align="center"
>
<template slot-scope="scope">
{{scope.row.type | transformType}}
{{scope.row.cloudbrainType | transformType}}
</template>
</el-table-column>
<el-table-column
@@ -246,19 +274,43 @@
</el-pagination>
</div>
</template>
<el-empty v-else :image-size="200"></el-empty>
<template v-else>
<el-row style="align-items: center;display: flex;">
<el-col :span="12">
<div style="visibility: hidden;">
TODO
</div>
</el-col>
<el-col :span="4"><div style="visibility: hidden;">TODO</div></el-col>
<el-col :span="8">
<div>
<el-input placeholder="搜镜像名称/描述/标签..." v-model="search" class="input-with-select" @keyup.enter.native="searchName()">
<el-button id="success" slot="append" icon="el-icon-search" @click="searchName()">搜索</el-button>
</el-input>
</div>
</el-col>
</el-row>
<el-empty :image-size="200"></el-empty>
</template>
</el-tab-pane>
<el-tab-pane label="我收藏的镜像" name="third">
<template v-if="tableDataStar.length!==0">
<div class="ui sixteen wide column">
<div class="ui two column stackable grid">
<div class="column">
<el-input placeholder="请输入镜像名称关健词" v-model="search" class="input-with-select">
<el-button slot="append" id="success" icon="el-icon-search">搜索</el-button>
<el-row style="align-items: center;display: flex;">
<el-col :span="12">
<div style="visibility: hidden;">
TODO
</div>
</el-col>
<el-col :span="4"><div style="visibility: hidden;">TODO</div></el-col>
<el-col :span="8">
<div>
<el-input placeholder="搜镜像名称/描述/标签..." v-model="search" class="input-with-select" @keyup.enter.native="searchName()">
<el-button id="success" slot="append" icon="el-icon-search" @click="searchName()">搜索</el-button>
</el-input>
</div>
</div>
</div>
</el-col>
</el-row>
<el-row style="margin-top:15px;">

<el-table
@@ -294,13 +346,13 @@
</template>
</el-table-column>
<el-table-column
prop="type"
prop="cloudbrainType"
label="可用集群"
min-width="10%"
align="center"
>
<template slot-scope="scope">
{{scope.row.type | transformType}}
{{scope.row.cloudbrainType | transformType}}
</template>
</el-table-column>
<el-table-column
@@ -356,7 +408,24 @@
</div>
</template>
<el-empty v-else :image-size="200"></el-empty>
<template v-else>
<el-row style="align-items: center;display: flex;">
<el-col :span="12">
<div style="visibility: hidden;">
TODO
</div>
</el-col>
<el-col :span="4"><div style="visibility: hidden;">TODO</div></el-col>
<el-col :span="8">
<div>
<el-input placeholder="搜镜像名称/描述/标签..." v-model="search" class="input-with-select" @keyup.enter.native="searchName()">
<el-button id="success" slot="append" icon="el-icon-search" @click="searchName()">搜索</el-button>
</el-input>
</div>
</el-col>
</el-row>
<el-empty :image-size="200"></el-empty>
</template>
</el-tab-pane>
</el-tabs>
</div>
@@ -380,6 +449,7 @@ export default {
return {
activeName: 'first',
search:'',
checked:false,
currentPagePublic:1,
pageSizePublic:15,
totalNumPublic:0,
@@ -405,7 +475,9 @@ export default {
},
methods: {
handleClick(tab, event) {
this.search = ''
if(tab.name=="first"){
this.paramsPublic.q = ''
this.getImageListPublic()
}
if(tab.name=="second"){
@@ -584,15 +656,15 @@ export default {
},
watch:{
search(val){
if(!val && this.activeName=='first'){
if(this.activeName=='first'){
this.paramsPublic.q = val
this.getImageListPublic()
}
if(!val && this.activeName=='second'){
if(this.activeName=='second'){
this.paramsCustom.q = val
this.getImageListCustom()
}
if(!val && this.activeName=='third'){
if(this.activeName=='third'){
this.paramsStar.q = val
this.getImageListStar()
}


+ 408
- 0
web_src/js/components/adminImages.vue View File

@@ -0,0 +1,408 @@
<template>
<div>
<div class="ui container" style="width: 80%;">
<div class="row" style="border: 1px solid #d4d4d5;margin-top: 15px;padding-top: 0;">
<div class="ui attached segment">
<div class="ui form ignore-dirty">
<div class="ui fluid action input">
<input type="text" v-model="search" @keyup.enter="searchName()">
<button class="ui blue button" @click="searchName()">搜索</button>
</div>
</div>
</div>
<div class="ui ten wide column" style="padding-top: 1rem;padding-left: 1rem">
<el-checkbox v-model="checked">仅显示平台推荐</el-checkbox>
</div>
<el-row style="margin-top:15px;">
<el-table
:data="tableDataCustom"
style="width: 100%"
:header-cell-style="tableHeaderStyle"
>
<el-table-column
label="镜像名称"
min-width="19%"
align="left"
prop="tag"
>
<template slot-scope="scope">
<div style="display: flex;align-items: center;">
<a class="text-over image_title" :title="scope.row.tag">{{ scope.row.tag }}</a>
<i class="ri-lock-2-line" style="color: #fa8c16;padding: 0 1rem;" v-if="scope.row.isPrivate"></i>
</div>
</template>
</el-table-column>
<el-table-column
label="镜像描述"
min-width="28%"
align="left"
prop="description"
>
<template slot-scope="scope">
<div class="image_desc" :title="scope.row.description">{{ scope.row.description}}</div>
<div v-if="!!scope.row.topics">
<span v-for="(topic,index) in scope.row.topics" class="ui repo-topic label topic">{{topic}}</span>
</div>
</template>
</el-table-column>
<el-table-column
prop="cloudbrainType"
label="可用集群"
min-width="10%"
align="center"
>
<template slot-scope="scope">
{{scope.row.cloudbrainType | transformType}}
</template>
</el-table-column>
<el-table-column
prop="isPrivate"
label="状态"
min-width="8%"
align="center"
>
<template slot-scope="scope">
{{scope.row.isPrivate | transformPravite}}
</template>
</el-table-column>
<el-table-column
prop="creator"
label="创建者"
min-width="8%"
align="center"
>
<template slot-scope="scope">
<a :href="'/' + scope.row.userName" :title="scope.row.userName">
<img :src="scope.row.relAvatarLink" class="ui avatar image">
</a>
</template>
</el-table-column>
<el-table-column
prop="createdUnix"
label="创建时间"
align="center"
min-width="14%"
>
<template slot-scope="scope">
{{scope.row.createdUnix | transformTimestamp}}
</template>
</el-table-column>
<el-table-column
align="center"
min-width="21%"
label="操作"
>
<template slot-scope="scope">
<div style="display: flex;justify-content: flex-end;align-items: center;">
<div style="display: flex;align-items: center;cursor: default;;padding: 0 1rem;">
<svg width="1.4em" height="1.4em" viewBox="0 0 32 32" class="heart-stroke"><path d="M4.4 6.54c-1.761 1.643-2.6 3.793-2.36 6.056.24 2.263 1.507 4.521 3.663 6.534a29110.9 29110.9 0 0010.296 9.633l10.297-9.633c2.157-2.013 3.424-4.273 3.664-6.536.24-2.264-.599-4.412-2.36-6.056-1.73-1.613-3.84-2.29-6.097-1.955-1.689.25-3.454 1.078-5.105 2.394l-.4.319-.398-.319c-1.649-1.316-3.414-2.143-5.105-2.394a7.612 7.612 0 00-1.113-.081c-1.838 0-3.541.694-4.983 2.038z"></path></svg>
<span style="line-height: 2;margin-left:0.3rem;">{{scope.row.numStars}}</span>
</div>
<span style="padding: 0 1rem;color:#0366d6;cursor:pointer;" v-if="scope.row.type==5" @click="unSetRecommend(scope.$index,scope.row.id)">取消推荐</span>
<span style="padding: 0 1rem;color:#0366d6;cursor:pointer;" v-else @click="setRecommend(scope.$index,scope.row.id)">设为推荐</span>
<span style="padding: 0 1rem;color:#0366d6;cursor:pointer;" @click="copyUrl(scope.row.place)">复制地址</span>
<div style="padding-left:1rem;cursor:pointer;">
<el-dropdown size="medium">
<span class="el-dropdown-link">
更多<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native="eidtImage(scope.row.id)">编辑</el-dropdown-item>
<el-dropdown-item style="color: red;" @click.native="deleteImage(scope.row.id)">删除</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</template>
</el-table-column>
</el-table>
</el-row>
<div class="ui container" style="padding:2rem 0;text-align:center">
<el-pagination
background
@size-change="handleSizeChangeCustom"
@current-change="handleCurrentChangeCustom"
:current-page="currentPageCustom"
:page-size="pageSizeCustom"
:page-sizes="[5,15,20]"
layout="total, sizes, prev, pager, next, jumper"
:total="totalNumCustom">
</el-pagination>
</div>
</div>
</div>
</div>

</template>

<script>

const {_AppSubUrl, _StaticUrlPrefix, csrf} = window.config;




export default {
components: {
},
data() {
return {
search:'',
checked:false,

currentPageCustom:1,
pageSizeCustom:15,
totalNumCustom:0,
paramsCustom:{page:1,pageSize:15,q:''},
tableDataCustom: [],
starCustom:[],
loadingCustom:false,


};
},
methods: {
tableHeaderStyle({row,column,rowIndex,columnIndex}){
if(rowIndex===0){
return 'background:#f5f5f6;color:#606266'
}
},

handleSizeChangeCustom(val){
this.paramsCustom.pageSize = val
this.getImageListCustom()


},
handleCurrentChangeCustom(val){
this.paramsCustom.page = val
this.getImageListCustom()

},

getImageListCustom(){
this.loadingCustom = true
this.$axios.get('/admin/images/data',{
params:this.paramsCustom
}).then((res)=>{
console.log("res",res)
this.totalNumCustom = res.data.count
this.tableDataCustom = res.data.images
this.tableDataCustom.forEach(element => {
this.starCustom.push({id:element.id,})
});
this.loadingCustom = false
})
},
deleteImage(id){
this.$axios.delete('/image/'+id).then((res)=>{
console.log(res)
this.getImageListCustom()
})
},
eidtImage(id){
location.href = `/image/${id}/imageSquare`
},
imageStar(index,id,isStar){
if(isStar){
this.$axios.put(`/image/${id}/action/unstar`).then((res)=>{
console.log(res)
this.tableDataPublic[index].numStars = this.tableDataPublic[index].numStars - 1
this.tableDataPublic[index].isStar = false
})
}else{
this.$axios.put(`/image/${id}/action/star`).then((res)=>{
console.log(res)
this.tableDataPublic[index].numStars = this.tableDataPublic[index].numStars + 1
this.tableDataPublic[index].isStar = true
})
}
},
copyUrl(url){
const cInput = document.createElement('input')
cInput.value = url
document.body.appendChild(cInput)
cInput.select()
document.execCommand('Copy')
cInput.remove()
},
searchName(){
this.paramsCustom.q = this.search
this.paramsCustom.page = 1
this.getImageListCustom()
},
setRecommend(index,id){
this.$axios.put(`/admin/images/${id}/action/recommend`).then((res)=>{
console.log(res)
this.tableDataCustom[index].type = 5

})
},
unSetRecommend(index,id){
this.$axios.put(`/admin/images/${id}/action/unrecommend`).then((res)=>{
console.log(res)
this.tableDataCustom[index].type = 0
})
}

},
filters:{
clearP(value){
if(!value) return ''
const reg = /\<\/?p\>/g;
value = value.replace(reg,'')
return value
},
transformType(val){
if(val==0){
return "GPU"
}
},
transformPravite(val){
if(val){
return "私有"
}else{
return "公开"
}
},
transformTimestamp(timestamp){
// let a = new Date(timestamp).getTime();
const date = new Date(parseInt(timestamp) * 1000);
const Y = date.getFullYear() + '-';
const M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';
const D = (date.getDate() < 10 ? '0'+date.getDate() : date.getDate()) + ' ';
const h = (date.getHours() < 10 ? '0'+date.getHours() : date.getHours()) + ':';
const m = (date.getMinutes() <10 ? '0'+date.getMinutes() : date.getMinutes()) + ':' ;
const s = (date.getSeconds() <10 ? '0'+date.getSeconds() : date.getSeconds()) ; // 秒
const dateString = Y + M + D + h + m + s;
// console.log('dateString', dateString); // > dateString 2021-07-06 14:23
return dateString;
},
},
watch:{
search(val){
this.paramsCustom.q = val
this.getImageListCustom()
}

},
mounted() {
this.getImageListCustom()
},
created() {
}

};
</script>

<style scoped>
.header-wrapper {
background-color: #f5f5f6;
padding-top: 15px;
}
.image_text{
padding:25px 0 55px 0 ;
}
#header{
position: relative;
top:-40px;
}
.el-dropdown-menu__item--divided{
border-top: 1px solid blue;
}
.el-table thead{
background-color: #f5f5f6;
}
/deep/ .el-tabs__item:hover{
color: #000;
font-weight: 500;
}
/deep/ .el-tabs__item.is-active {
color: #000;
font-weight: 500;
}
/deep/ .el-tabs__active-bar{
background-color:#000
}

/deep/ .el-pagination.is-background .el-pager li:not(.disabled).active {
background-color: #5bb973;
color: #FFF;
}
/deep/ .el-pagination.is-background .el-pager li.active {
color: #fff;
cursor: default;
}
/deep/ .el-pagination.is-background .el-pager li:hover {
color: #5bb973;
}
/deep/ .el-pagination.is-background .el-pager li:not(.disabled):hover {
color: #5bb973;
}
/deep/ .el-pagination.is-background .el-pager li:not(.disabled).active:hover {
background-color: #5bb973;
color: #FFF;
}

/deep/ .el-pager li.active {
color: #08C0B9;
cursor: default;
}
/deep/ .el-pagination .el-pager li:hover {
color: #08C0B9;
}
/deep/ .el-pagination .el-pager li:not(.disabled):hover {
color: #08C0B9;
}
/* /deep/ .el-pagination.is-background .el-pager li:not(.disabled).active{
background-color: #5bb973;
color: #000;
} */
/* /deep/ .el-pager li:hover{
color: #000;
} */
#success{
background-color: #5bb973;
color: white;
}
.text-over{
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
white-space: nowrap;
}
.image_title{
display: inline-block;
cursor: default;
color: rgb(66, 98, 144);
}
.image_desc{
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
display: -webkit-box;
text-overflow: ellipsis;
overflow: hidden;
}
.heart-stroke{
stroke: #666;
stroke-width: 2;
fill: #fff
}
.stars_active{
fill: #FA8C16 !important;
stroke:#FA8C16 !important
}
</style>

+ 50
- 12
web_src/js/features/images.js View File

@@ -1,4 +1,5 @@
import Images from '../components/Images.vue';
import adminImages from '../components/adminImages.vue';
import Vue from 'vue';
export default async function initImage(){
function validate() {
@@ -27,16 +28,14 @@ export default async function initImage(){
}
})
}
function $params(obj) {
var str = [];
for (var p in obj) {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
}
return str.join("&");
}
function initDropdown(){
// const editLable = []
// $('#dropdown_image').find('.ui.label.transition.visible').each((index,item)=>{
// console.log(index,item)
// console.log(item.getAttribute("data-value"))
// editLable.push(item.getAttribute("data-value"))
// console.log(editLable.join(','))
// $("input[name='topics']").val(editLable.join(','))
// })
$('#dropdown_image')
.dropdown({
allowAdditions: true,
@@ -50,7 +49,7 @@ export default async function initImage(){
if(!query){
$('#course_label_item').empty()
}else{
$.get(`/api/v1/topics/search?q=${query}`,(data)=>{
$.get(`/api/v1/image/topics/search?q=${query}`,(data)=>{
if(data.topics.length!==0){
let html=''
$('#course_label_item').empty()
@@ -68,15 +67,40 @@ export default async function initImage(){
initDropdown()
let link = $('.submit-image-tmplvalue').data('link')
$('.ui.create_image.green.button').click(()=>{
console.log($('#form_image').serialize())
let pattenTag = new RegExp(/^[A-Za-z0-9_.-]{1,100}[A-Za-z0-9_.]$/)
if(!pattenTag.test($("input[name='tag']").val())){
$("input[name='tag']").parent().addClass('error')
return false
}
if(!$("textarea[name='description']").val()){
$("textarea[name='description']").parent().addClass('error')
return false
}
$("#mask").css({"display":"block","z-index":"999"})
const postData = {
_csrf:$("input[name='_csrf']").val(),
tag:$("input[name='tag']").val(),
description:$("textarea[name='description']").val(),
type:$("input[name='type']").val(),
isPrivate:$("input[name='isPrivate']").val(),
topics:$("input[name='topics']").val(),
id:$("input[name='id']").val()
}
console.log(postData)
let formData = $params(postData)
console.log(formData)
$.ajax({
url:link,
type:'POST',
data:$('#form_image').serialize(),
data:formData,
success:function(res){
console.log("res",res)
if(res.Code===1){
$('.alert').html(res.Message).removeClass('alert-success').addClass('alert-danger').show().delay(1500).fadeOut();
}else if(res.Code==0){
location.href = `${window.config.AppSubUrl}/explore/images`
}
},
error: function(xhr){
@@ -112,5 +136,19 @@ export default async function initImage(){
render: h => h(Images)
});
}
function initVueAdminImages() {
const el = document.getElementById('images-admin');
console.log(el)
if (!el) {
return;
}
new Vue({
el:el,
render: h => h(adminImages)
});
}
initVueImages()
initVueAdminImages()
}

Loading…
Cancel
Save