mirror of
https://github.com/crawlab-team/crawlab.git
synced 2026-01-30 18:00:56 +01:00
added spider market
This commit is contained in:
@@ -13,6 +13,7 @@ export default {
|
||||
'Sites': '网站',
|
||||
'Setting': '设置',
|
||||
'Project': '项目',
|
||||
'Spider Market': '爬虫市场',
|
||||
|
||||
// 标签
|
||||
'Overview': '概览',
|
||||
@@ -518,6 +519,15 @@ export default {
|
||||
'Year': '年',
|
||||
'Years': '年',
|
||||
|
||||
// 爬虫市场
|
||||
'Search Keyword': '搜索关键词',
|
||||
'Sort': '排序',
|
||||
'Default Sort': '默认排序',
|
||||
'Most Stars': '最多 Stars',
|
||||
'Most Forks': '最多 Forks',
|
||||
'Latest Pushed': '最近提交',
|
||||
'Pushed At': '提交时间',
|
||||
|
||||
// 全局
|
||||
'Related Documentation': '相关文档',
|
||||
'Click to view related Documentation': '点击查看相关文档',
|
||||
@@ -647,6 +657,8 @@ export default {
|
||||
'Are you sure to add an API token?': '确认创建 API Token?',
|
||||
'Are you sure to delete this API token?': '确认删除该 API Token?',
|
||||
'Please enter Web Hook URL': '请输入 Web Hook URL',
|
||||
'Are you sure to download this spider?': '您确定要下载该爬虫?',
|
||||
'Downloaded successfully': '下载成功',
|
||||
|
||||
// 其他
|
||||
'Star crawlab-team/crawlab on GitHub': '在 GitHub 上为 Crawlab 加星吧'
|
||||
|
||||
@@ -181,6 +181,25 @@ export const constantRouterMap = [
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/repos',
|
||||
component: Layout,
|
||||
meta: {
|
||||
title: 'Spider Market',
|
||||
icon: 'fa fa-cloud'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'RepoList',
|
||||
component: () => import('../views/repo/RepoList'),
|
||||
meta: {
|
||||
title: 'Spider Market',
|
||||
icon: 'fa fa-cloud'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/disclaimer',
|
||||
component: Layout,
|
||||
@@ -243,8 +262,7 @@ export const constantRouterMap = [
|
||||
component: Layout,
|
||||
meta: {
|
||||
title: 'User',
|
||||
icon: 'fa fa-users',
|
||||
isNew: true
|
||||
icon: 'fa fa-users'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
|
||||
@@ -82,7 +82,7 @@ if (!CRAWLAB_API_ADDRESS.match('CRAWLAB_API_ADDRESS')) {
|
||||
const service = axios.create({
|
||||
baseURL: baseUrl, // url = base url + request url
|
||||
// withCredentials: true, // send cookies when cross-domain requests
|
||||
timeout: 5000 // request timeout
|
||||
timeout: 15000 // request timeout
|
||||
})
|
||||
// request interceptor
|
||||
service.interceptors.request.use(
|
||||
|
||||
257
frontend/src/views/repo/RepoList.vue
Normal file
257
frontend/src/views/repo/RepoList.vue
Normal file
@@ -0,0 +1,257 @@
|
||||
<template>
|
||||
<div class="app-container repo-list">
|
||||
<el-card>
|
||||
<div class="filter">
|
||||
<el-form inline>
|
||||
<el-form-item :label="$t('Search Keyword')">
|
||||
<el-input
|
||||
v-model="keyword"
|
||||
size="small"
|
||||
:placeholder="$t('Search Keyword')"
|
||||
@keyup.enter.native="getRepos"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('Sort')">
|
||||
<el-select
|
||||
v-model="sortKey"
|
||||
size="small"
|
||||
>
|
||||
<el-option :label="$t('Default Sort')" value=""/>
|
||||
<el-option :label="$t('Most Stars')" value="stars"/>
|
||||
<el-option :label="$t('Most Forks')" value="forks"/>
|
||||
<el-option :label="$t('Latest Pushed')" value="pushed_at"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="success" size="small" @click="getRepos">{{ $t('Search') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<el-table
|
||||
ref="table"
|
||||
:data="repos"
|
||||
:header-cell-style="{background:'rgb(48, 65, 86)',color:'white'}"
|
||||
:row-class-name="getRowClassName"
|
||||
row-key="id"
|
||||
border
|
||||
v-loading="isLoading"
|
||||
@expand-change="onRowExpand"
|
||||
>
|
||||
<el-table-column type="expand">
|
||||
<template slot-scope="scope">
|
||||
<ul class="sub-dir-list">
|
||||
<li
|
||||
v-for="sub in getSubDirList(scope.row)"
|
||||
:key="sub.full_name"
|
||||
class="sub-dir-item"
|
||||
>
|
||||
<div class="sub-dir-title">
|
||||
{{ sub.name }}
|
||||
</div>
|
||||
<div class="action">
|
||||
<el-tooltip :content="$t('Download')" placement="top">
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="fa fa-download"
|
||||
size="mini"
|
||||
@click="onDownload(scope.row, sub.full_name, $event)"
|
||||
v-loading="scope.row.loading"
|
||||
/>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
:label="$t('Name')"
|
||||
prop="full_name"
|
||||
width="300px"
|
||||
/>
|
||||
<el-table-column
|
||||
:label="$t('Description')"
|
||||
prop="description"
|
||||
min-width="500px"
|
||||
/>
|
||||
<el-table-column
|
||||
label="Stars"
|
||||
prop="stars"
|
||||
width="80px"
|
||||
align="right"
|
||||
/>
|
||||
<el-table-column
|
||||
label="Forks"
|
||||
prop="forks"
|
||||
width="80px"
|
||||
align="right"
|
||||
/>
|
||||
<el-table-column
|
||||
:label="$t('Pushed At')"
|
||||
prop="pushed_at"
|
||||
width="150px"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
{{ getTime(scope.row.pushed_at) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
:label="$t('Action')"
|
||||
width="120px"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<el-tooltip :content="$t('Download')" placement="top">
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="fa fa-download"
|
||||
size="mini"
|
||||
@click="onDownload(scope.row, null, $event)"
|
||||
v-loading="scope.row.loading"
|
||||
/>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pagination">
|
||||
<el-pagination
|
||||
:current-page.sync="pageNum"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size.sync="pageSize"
|
||||
layout="sizes, prev, pager, next"
|
||||
:total="total"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
export default {
|
||||
name: 'RepoList',
|
||||
data() {
|
||||
return {
|
||||
repos: [],
|
||||
total: 0,
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
keyword: '',
|
||||
sortKey: '',
|
||||
isLoading: false,
|
||||
subDirCache: {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
pageNum() {
|
||||
this.getRepos()
|
||||
},
|
||||
pageSize() {
|
||||
this.getRepos()
|
||||
},
|
||||
sortKey() {
|
||||
this.getRepos()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async getRepos() {
|
||||
this.isLoading = true
|
||||
try {
|
||||
const res = await this.$request.get('/repos', {
|
||||
page_num: this.pageNum,
|
||||
page_size: this.pageSize,
|
||||
keyword: this.keyword,
|
||||
sort_key: this.sortKey
|
||||
})
|
||||
this.repos = res.data.data
|
||||
this.total = res.data.total
|
||||
} finally {
|
||||
this.isLoading = false
|
||||
}
|
||||
},
|
||||
getTime(t) {
|
||||
return dayjs(t).format('YYYY-MM-DD HH:mm:ss')
|
||||
},
|
||||
onDownload(row, fullName, ev) {
|
||||
ev.stopPropagation()
|
||||
this.$confirm(this.$t('Are you sure to download this spider?'), this.$t('Notification'), {
|
||||
confirmButtonText: this.$t('Confirm'),
|
||||
cancelButtonText: this.$t('Cancel'),
|
||||
type: 'warning'
|
||||
}).then(async() => {
|
||||
this.$set(row, 'loading', true)
|
||||
try {
|
||||
await this.download(fullName || row.full_name)
|
||||
this.$message.success('Downloaded successfully')
|
||||
} finally {
|
||||
this.$set(row, 'loading', false)
|
||||
}
|
||||
})
|
||||
},
|
||||
async download(fullName) {
|
||||
this.$request.post('/repos/download', {
|
||||
full_name: fullName
|
||||
})
|
||||
},
|
||||
getRowClassName({ row }) {
|
||||
return row.is_sub_dir ? '' : 'non-expandable'
|
||||
},
|
||||
async onRowExpand(row, expandedRows) {
|
||||
if (!this.subDirCache[row.full_name]) {
|
||||
const res = await this.$request.get('/repos/sub-dir', {
|
||||
full_name: row.full_name
|
||||
})
|
||||
this.$set(this.subDirCache, row.full_name, res.data.data)
|
||||
}
|
||||
},
|
||||
getSubDirList(row) {
|
||||
if (!this.subDirCache[row.full_name]) return []
|
||||
return this.subDirCache[row.full_name].map(n => {
|
||||
return {
|
||||
name: n,
|
||||
full_name: `${row.full_name}/${n}`
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
await this.getRepos()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.el-table .el-button {
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
.el-table >>> .non-expandable .el-table__expand-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.el-table .sub-dir-list {
|
||||
list-style: none;
|
||||
font-size: 12px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.el-table .sub-dir-list .sub-dir-item {
|
||||
padding: 6px 0 6px 60px;
|
||||
border-bottom: 1px dashed #EBEEF5;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.el-table .sub-dir-list .sub-dir-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.el-table .sub-dir-list .sub-dir-item .sub-dir-title {
|
||||
line-height: 29px;
|
||||
}
|
||||
|
||||
.el-table .sub-dir-list .sub-dir-item .action {
|
||||
width: 120px;
|
||||
padding: 0 12px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user