完成分类页

dev
truthhun 1 year ago
parent ad017f44b5
commit e0d4039c9d

@ -231,6 +231,8 @@ func (m *DBModel) GetDocumentList(opt *OptionGetDocumentList) (documentList []Do
opt.SelectFields = m.FilterValidFields(tableDocument, opt.SelectFields...)
if len(opt.SelectFields) > 0 {
db = db.Select(opt.SelectFields)
} else {
db = db.Select(m.GetTableFields(tableDocument))
}
if len(opt.Sort) > 0 {

@ -9,8 +9,8 @@ import (
type DocumentCategory struct {
Id int64 `form:"id" json:"id,omitempty" gorm:"primaryKey;autoIncrement;column:id;comment:;"`
DocumentId int64 `form:"document_id" json:"document_id,omitempty" gorm:"column:document_id;type:bigint(20);size:20;default:0;index:document_id;comment:文档ID;"`
CategoryId int64 `form:"category_id" json:"category_id,omitempty" gorm:"column:category_id;type:bigint(20);size:20;default:0;index:category_id;comment:分类ID;"`
DocumentId int64 `form:"document_id" json:"document_id,omitempty" gorm:"column:document_id;type:bigint(20);size:20;default:0;index:document_id;index:idx_doc_cate,unique;comment:文档ID;"`
CategoryId int64 `form:"category_id" json:"category_id,omitempty" gorm:"column:category_id;type:bigint(20);size:20;default:0;index:category_id;index:idx_doc_cate,unique;comment:分类ID;"`
CreatedAt *time.Time `form:"created_at" json:"created_at,omitempty" gorm:"column:created_at;type:datetime;comment:创建时间;"`
UpdatedAt *time.Time `form:"updated_at" json:"updated_at,omitempty" gorm:"column:updated_at;type:datetime;comment:更新时间;"`
}

@ -215,10 +215,16 @@ func (m *DBModel) FilterValidFields(tableName string, fields ...string) (validFi
// GetTableFields 查询指定表的所有字段
func (m *DBModel) GetTableFields(tableName string) (fields []string) {
slice := strings.Split(tableName, " ")
alias := ""
if len(slice) == 2 {
tableName = slice[0]
alias = slice[1] + "."
}
fieldsMap, ok := m.tableFieldsMap[tableName]
if ok {
for field := range fieldsMap {
fields = append(fields, field)
fields = append(fields, fmt.Sprintf("%s`%s`", alias, field))
}
}
return

@ -0,0 +1,46 @@
<template>
<el-image
:src="
document.attachment && document.attachment.hash
? `/view/cover/${document.attachment.hash}`
: ''
"
:alt="document.title"
:style="{ height: height }"
>
<div slot="error" class="image-slot">
<img src="/static/images/default-cover.png" />
</div>
</el-image>
</template>
<script>
export default {
name: 'DocumentCover',
props: {
document: {
type: Object,
default: () => ({}),
},
height: {
type: String,
default: '',
},
},
data() {
return {}
},
}
</script>
<style lang="scss" scoped>
.el-image {
border: 2px solid #efefef;
border-radius: 5px;
}
img {
width: 100%;
transition: transform 0.3s ease 0s;
&:hover {
transform: scale(1.2);
}
}
</style>

@ -0,0 +1,132 @@
<template>
<div class="com-document-list">
<ul>
<li v-for="doc in documents" :key="'doc-' + doc.id">
<el-row :gutter="20">
<el-col :span="4" class="doc-cover">
<nuxt-link :to="`/document/${doc.id}`">
<document-cover :document="doc" />
</nuxt-link>
</el-col>
<el-col :span="20">
<h3>
<nuxt-link
:to="`/document/${doc.id}`"
class="el-link el-link--primary"
><img
:src="`/static/images/${doc.ext}_24.png`"
:alt="`${doc.ext} 文档`"
/>
{{ doc.title }}</nuxt-link
>
</h3>
<div class="doc-info">
<el-rate
v-model="doc.score"
disabled
show-score
text-color="#ff9900"
score-template="{value}"
>
</el-rate>
<span class="float-right">
{{ doc.price || 0 }} 魔豆 <span class="line">|</span>
{{ doc.pages || '-' }} <span class="line">|</span>
{{ formatBytes(doc.size) || '-' }}
<span class="hidden-xs-only"
><span class="line">|</span>
{{ formatDatetime(doc.created_at) }}</span
></span
>
</div>
<div class="doc-desc">
{{ doc.description }}
</div>
</el-col>
</el-row>
</li>
</ul>
</div>
</template>
<script>
import DocumentCover from './DocumentCover.vue'
import { formatBytes, formatDatetime } from '~/utils/utils'
export default {
name: 'DocumentList',
components: { DocumentCover },
props: {
documents: {
type: Array,
default: () => [],
},
},
data() {
return {}
},
methods: {
formatBytes,
formatDatetime,
},
}
</script>
<style lang="scss" scoped>
.com-document-list {
ul,
li {
list-style: none;
padding: 0;
margin: 0;
}
li {
margin-bottom: 20px;
padding-bottom: 18px;
border-bottom: 1px dashed #ddd;
}
h3 {
margin: 0;
a {
font-size: 18px;
font-weight: 400;
display: inline-block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
img {
height: 18px;
position: relative;
top: 3px;
}
}
}
.doc-cover {
.el-image {
width: 100%;
border: 3px solid #efefef;
border-radius: 5px;
&:hover img {
transform: scale(1.2);
}
}
}
.doc-info {
margin: 10px 0;
font-size: 13px;
color: #888;
.line {
color: #ddd;
margin: 0 5px;
}
}
.doc-desc {
font-size: 15px;
color: #888;
line-height: 180%;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 3;
max-height: 81px;
-webkit-box-orient: vertical;
}
}
</style>

@ -25,14 +25,16 @@
<el-tab-pane name="latest">
<span slot="label"><i class="el-icon-date"></i> 最新</span>
</el-tab-pane>
<el-tab-pane name="hot">
<el-tab-pane name="view">
<span slot="label"><i class="el-icon-view"></i> 浏览</span>
</el-tab-pane>
<el-tab-pane name="recommend">
<span slot="label"><i class="el-icon-date"></i> 推荐</span>
<span slot="label"
><i class="el-icon-coordinate"></i> 推荐</span
>
</el-tab-pane>
<el-tab-pane name="favorite">
<span slot="label"><i class="el-icon-date"></i> 收藏</span>
<span slot="label"><i class="el-icon-star-off"></i> 收藏</span>
</el-tab-pane>
<el-tab-pane name="download">
<span slot="label"><i class="el-icon-download"></i> 下载</span>
@ -42,69 +44,13 @@
</el-tab-pane>
</el-tabs>
</div>
<div class="doc-list-data">
<ul>
<li v-for="x in 10" :key="'x-' + x">
<el-row :gutter="20">
<el-col :span="4" class="doc-cover">
<nuxt-link to="/document/">
<img
v-if="x % 3 == 0"
src="https://static.wenkuzhijia.cn/fe5642195d3060c51d12fccaa46f4c61.jpg"
alt=""
style="width: 100%"
/>
<img
v-if="x % 3 == 1"
src="https://static.sitestack.cn/projects/entgo-0.11-zh/uploads/202210/171f825ac77e9e82.png/cover"
alt=""
style="width: 100%"
/>
<img
v-if="x % 3 == 2"
src="https://static.sitestack.cn/projects/learn-go-with-tests-14.0-en/uploads/202210/171edb9f6a91aa73.png/cover"
alt=""
style="width: 100%"
/>
</nuxt-link>
</el-col>
<el-col :span="20">
<h3>
<nuxt-link
to="/document/"
class="el-link el-link--primary"
><img src="/static/images/pdf_24.png" alt="" />
啊实打实大</nuxt-link
>
</h3>
<div class="doc-info">
<el-rate
v-model="score"
disabled
show-score
text-color="#ff9900"
score-template="{value}"
>
</el-rate>
<span class="float-right"
>5 金币 | 141 | 786.00 KB
<span class="hidden-xs-only"
>| 2019-06-10 10:17</span
></span
>
</div>
<div class="doc-desc">
GoFrame是一款模块化高性能企业级的Go基础开发框架GoFrame不是一款WEBGoFrame是一款模块化高性能企业级的Go基础开发框架GoFrame不是一款WEBGoFrame是一款模块化高性能企业级的Go基础开发框架GoFrame不是一款WEBGoFrame是一款模块化高性能企业级的Go基础开发框架GoFrame不是一款WEBGoFrame是一款模块化高性能企业级的Go基础开发框架GoFrame不是一款WEBGoFrame是一款模块化高性能企业级的Go基础开发框架GoFrame不是一款WEB/RPC框架而是一款通用性的基础开发框架是Golang标准库的一个增强扩展级包含通用核心的基础开发组件优点是实战化模块化文档全面模块丰富易用性高通用性强面向团队
</div>
</el-col>
</el-row>
</li>
</ul>
<div v-loading="loading" class="doc-list-data">
<document-list :documents="documents" />
</div>
<el-pagination
v-if="total > 0"
:current-page="query.page"
:page-size="10"
:page-size="size"
layout="total, prev, pager, next, jumper"
:total="total"
@current-change="pageChange"
@ -117,10 +63,10 @@
<el-card shadow="never" class="categories">
<div slot="header">
<el-row>
<el-col :span="8" class="header-title">
<el-col :span="12" class="header-title">
{{ breadcrumbs[0].title }}
</el-col>
<el-col :span="16">
<el-col :span="12">
<el-input v-model="filterText" placeholder="分类过滤">
</el-input>
</el-col>
@ -144,14 +90,15 @@
<el-col :span="8" class="header-title">关键词</el-col>
</el-row>
</div>
<nuxt-link
v-for="(keyword, index) in keywords"
:key="'kw' + keyword"
:to="{ path: '/search', query: { wd: keyword } }"
:class="['tag-' + (index % 5)]"
>
<el-tag effect="plain"> {{ keyword }}</el-tag>
</nuxt-link>
<div v-loading="loading">
<nuxt-link
v-for="keyword in keywords"
:key="'kw' + keyword"
:to="{ path: '/search', query: { wd: keyword } }"
>
<el-tag effect="plain"> {{ keyword }}</el-tag>
</nuxt-link>
</div>
</el-card>
</el-col>
</el-row>
@ -160,12 +107,14 @@
<script>
import { mapGetters } from 'vuex'
import DocumentList from '~/components/DocumentList.vue'
import { listDocument } from '~/api/document'
export default {
name: 'PageCategory',
components: { DocumentList },
data() {
return {
filterText: '',
score: 4.5,
defaultExpandedKeys: [],
defaultProps: {
children: 'children',
@ -176,11 +125,14 @@ export default {
sort: 'latest',
page: 1,
},
size: 10,
breadcrumbs: [], //
trees: [],
documents: [],
categoryId: parseInt(this.$route.params.id) || 0,
total: 0,
keywords: ['Java', '书栈网', 'PHP教程', 'MySQL'],
keywords: [],
loading: false,
}
},
head() {
@ -273,9 +225,75 @@ export default {
},
})
},
loadData() {
// TODO:
console.log('loadData')
async loadData() {
this.loading = true
let order = 'id desc'
switch (this.query.sort) {
case 'latest':
order = 'id desc'
break
case 'view':
order = 'view_count desc'
break
case 'favorite':
order = 'favorite_count desc'
break
case 'comment':
order = 'comment_count desc'
break
case 'pages':
order = 'pages desc'
break
case 'recommend':
order = 'recommend_at desc'
break
case 'download':
order = 'download_count desc'
break
default:
break
}
const res = await listDocument({
order,
page: this.query.page,
size: this.size,
category_id: this.categoryId,
field: [
'id',
'title',
'keywords',
'description',
'view_count',
'favorite_count',
'comment_count',
'created_at',
'size',
'price',
'pages',
'ext',
'score',
],
})
if (res.status === 200) {
this.total = res.data.total
const documents = res.data.document || []
const keywords = []
this.documents = documents.map((x) => {
x.ext = x.ext.replace(/\./, '')
if (x.keywords) {
x.keywords.split(',').forEach((keyword) => {
keyword = keyword.trim()
if (keyword && !keywords.includes(keyword)) {
keywords.push(keyword)
}
})
}
x.score = parseFloat(x.score) / 100 || 4.0
return x
})
this.keywords = keywords
}
this.loading = false
},
},
}
@ -336,57 +354,5 @@ export default {
}
}
}
.doc-list-data {
ul,
li {
list-style: none;
padding: 0;
margin: 0;
}
li {
margin-bottom: 20px;
padding-bottom: 18px;
border-bottom: 1px dashed #ddd;
}
h3 {
margin: 0;
a {
font-size: 18px;
font-weight: 400;
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
img {
height: 18px;
position: relative;
top: 3px;
}
}
}
.doc-cover {
img {
width: 100%;
border: 1px solid #efefef;
border-radius: 3px;
}
}
.doc-info {
margin: 10px 0;
font-size: 13px;
color: #bbb;
}
.doc-desc {
font-size: 15px;
color: #888;
line-height: 180%;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 3;
max-height: 81px;
-webkit-box-orient: vertical;
}
}
}
</style>

Loading…
Cancel
Save