feat: 创建数据列表页面(sjlbc)

- 添加数据列表页面,包含顶部导航、左侧筛选栏、右侧数据表格
- 实现价格区间和有效期筛选功能
- 实现表格排序功能(按数据类型、发布时间、数据条数、浏览量、下载量)
- 添加数据类型标签(公共数据-绿色、社会性数据-蓝色)
- 添加奇偶行颜色区分和分页组件

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
liulujian 2026-04-03 16:31:10 +08:00
parent 25f6982fd2
commit b286a17ed4

View File

@ -0,0 +1,628 @@
<template>
<div class="sjlbc-page">
<!-- 顶部导航 -->
<NewNav />
<div class="main-content">
<!-- 当前位置 -->
<div class="current-position">
<span>当前位置</span>
<span class="position-item" @click="goHome">首页</span>
<span class="separator">/</span>
<span class="position-item" @click="goService">服务中心</span>
<span class="separator">/</span>
<span class="position-item" @click="goDataMarket">碳数据市场</span>
<span class="separator">/</span>
<span class="position-current">数据列表</span>
</div>
<!-- 主内容区 -->
<div class="content-wrapper">
<!-- 左侧筛选栏 -->
<div class="filter-sidebar">
<div class="filter-box">
<!-- 价格区间 -->
<div class="filter-section">
<div class="filter-title">价格区间</div>
<div class="price-range">
<input type="text" v-model="filterParams.priceMin" placeholder="最低" class="price-input" />
<span class="price-separator">-</span>
<input type="text" v-model="filterParams.priceMax" placeholder="最高" class="price-input" />
</div>
</div>
<!-- 有效期 -->
<div class="filter-section">
<div class="filter-title">有效期</div>
<div class="date-picker-box">
<input type="date" v-model="filterParams.validDate" class="date-input" />
</div>
</div>
<!-- 筛选按钮 -->
<div class="filter-buttons">
<button class="btn-reset" @click="resetFilter">重置</button>
<button class="btn-confirm" @click="confirmFilter">确定</button>
</div>
</div>
</div>
<!-- 右侧数据列表 -->
<div class="data-list">
<!-- 表头 -->
<div class="table-header">
<div class="th th-type" @click="sortBy('type')">
数据类型
<span class="sort-icon">
<span class="sort-up" :class="{ active: sortField === 'type' && sortOrder === 'asc' }"></span>
<span class="sort-down" :class="{ active: sortField === 'type' && sortOrder === 'desc' }"></span>
</span>
</div>
<div class="th th-name">名称</div>
<div class="th th-time" @click="sortBy('time')">
发布时间/更新时间
<span class="sort-icon">
<span class="sort-up" :class="{ active: sortField === 'time' && sortOrder === 'asc' }"></span>
<span class="sort-down" :class="{ active: sortField === 'time' && sortOrder === 'desc' }"></span>
</span>
</div>
<div class="th th-count" @click="sortBy('count')">
数据条数
<span class="sort-icon">
<span class="sort-up" :class="{ active: sortField === 'count' && sortOrder === 'asc' }"></span>
<span class="sort-down" :class="{ active: sortField === 'count' && sortOrder === 'desc' }"></span>
</span>
</div>
<div class="th th-views" @click="sortBy('views')">
浏览量
<span class="sort-icon">
<span class="sort-up" :class="{ active: sortField === 'views' && sortOrder === 'asc' }"></span>
<span class="sort-down" :class="{ active: sortField === 'views' && sortOrder === 'desc' }"></span>
</span>
</div>
<div class="th th-downloads" @click="sortBy('downloads')">
下载量
<span class="sort-icon">
<span class="sort-up" :class="{ active: sortField === 'downloads' && sortOrder === 'asc' }"></span>
<span class="sort-down" :class="{ active: sortField === 'downloads' && sortOrder === 'desc' }"></span>
</span>
</div>
</div>
<!-- 表格数据 -->
<div class="table-body">
<div
v-for="(item, index) in sortedDataList"
:key="index"
class="table-row"
:class="{ 'row-even': index % 2 === 1 }"
>
<div class="td td-type">
<span class="type-tag" :class="item.type === '公共数据' ? 'tag-green' : 'tag-blue'">
{{ item.type }}
</span>
</div>
<div class="td td-name" :title="item.name">{{ item.name }}</div>
<div class="td td-time">
<div class="time-info">
<span>发布时间{{ item.publishTime }}</span>
<span v-if="item.updateTime">更新时间{{ item.updateTime }}</span>
</div>
</div>
<div class="td td-count">{{ item.dataCount }}</div>
<div class="td td-views">{{ item.views }}次浏览</div>
<div class="td td-downloads">{{ item.downloads }}次下载</div>
</div>
</div>
</div>
</div>
<!-- 分页 -->
<div class="pagination">
<span class="page-btn">上一页</span>
<span class="page-btn active">1</span>
<span class="page-btn">2</span>
<span class="page-btn">3</span>
<span class="page-btn">4</span>
<span class="page-btn">5</span>
<span class="page-btn">下一页</span>
</div>
</div>
<!-- 底部 -->
<Footer />
</div>
</template>
<script>
import NewNav from '@/pages/index/components/new-nav/index.vue';
import Footer from '@/pages/index/components/footer/index.vue';
export default {
name: 'SjlbcPage',
components: {
NewNav,
Footer,
},
data() {
return {
filterParams: {
priceMin: '',
priceMax: '',
validDate: '',
},
sortField: '',
sortOrder: '',
dataList: [
{
name: '全球多源高分辨温室气体及大气污染物排放清单',
type: '社会性数据',
publishTime: '2026-03-30 10:00',
updateTime: '2026-03-30 10:00',
dataCount: '45,000',
views: '475',
downloads: '18',
},
{
name: '国家温室气体排放因子数据库',
type: '公共数据',
publishTime: '2026-03-30 10:00',
updateTime: '',
dataCount: '45,000',
views: '475',
downloads: '18',
},
{
name: '碳排放数据库',
type: '公共数据',
publishTime: '2026-03-30 10:00',
updateTime: '',
dataCount: '45,000',
views: '475',
downloads: '18',
},
{
name: '全球多源高分辨温室气体及大气污染物排放清单',
type: '社会性数据',
publishTime: '2026-03-30 10:00',
updateTime: '2026-03-30 10:00',
dataCount: '45,000',
views: '475',
downloads: '18',
},
{
name: '国家温室气体排放因子数据库',
type: '公共数据',
publishTime: '2026-03-30 10:00',
updateTime: '',
dataCount: '45,000',
views: '475',
downloads: '18',
},
{
name: '碳排放数据库',
type: '公共数据',
publishTime: '2026-03-30 10:00',
updateTime: '',
dataCount: '45,000',
views: '475',
downloads: '18',
},
{
name: '全球多源高分辨温室气体及大气污染物排放清单',
type: '社会性数据',
publishTime: '2026-03-30 10:00',
updateTime: '2026-03-30 10:00',
dataCount: '45,000',
views: '475',
downloads: '18',
},
{
name: '国家温室气体排放因子数据库',
type: '公共数据',
publishTime: '2026-03-30 10:00',
updateTime: '',
dataCount: '45,000',
views: '475',
downloads: '18',
},
],
};
},
computed: {
sortedDataList() {
if (!this.sortField) {
return this.dataList;
}
return [...this.dataList].sort((a, b) => {
let valA = a[this.sortField];
let valB = b[this.sortField];
//
if (this.sortField === 'time') {
valA = a.updateTime || a.publishTime;
valB = b.updateTime || b.publishTime;
}
//
if (this.sortField === 'count' || this.sortField === 'views' || this.sortField === 'downloads') {
valA = parseInt(valA.replace(/,/g, ''));
valB = parseInt(valB.replace(/,/g, ''));
}
if (valA < valB) {
return this.sortOrder === 'asc' ? -1 : 1;
}
if (valA > valB) {
return this.sortOrder === 'asc' ? 1 : -1;
}
return 0;
});
},
},
methods: {
sortBy(field) {
if (this.sortField === field) {
this.sortOrder = this.sortOrder === 'asc' ? 'desc' : 'asc';
} else {
this.sortField = field;
this.sortOrder = 'desc';
}
},
resetFilter() {
this.filterParams = {
priceMin: '',
priceMax: '',
validDate: '',
};
},
confirmFilter() {
console.log('筛选条件:', this.filterParams);
},
goHome() {
window.location.href = '/view/mhzc/home';
},
goService() {
window.location.href = '/view/mhzc/fwsc/fwsc';
},
goDataMarket() {
window.location.href = '/view/mhzc/fwsc/sjsc';
},
},
};
</script>
<style lang="less" scoped>
.sjlbc-page {
min-height: 100vh;
background: #f5f5f5;
}
.main-content {
width: 1920px;
padding-top: 64px;
margin: 0 auto;
}
//
.current-position {
width: 100%;
height: 48px;
padding: 0 60px;
line-height: 48px;
background: #fff;
box-sizing: border-box;
.position-item {
cursor: pointer;
&:hover {
color: #009a29;
}
}
.separator {
margin: 0 8px;
color: #ccc;
}
.position-current {
color: #009a29;
}
}
//
.content-wrapper {
display: flex;
padding: 20px 60px;
gap: 20px;
}
//
.filter-sidebar {
width: 220px;
flex-shrink: 0;
}
.filter-box {
position: sticky;
top: 84px;
padding: 20px;
background: #fff;
border-radius: 8px;
}
.filter-section {
margin-bottom: 24px;
}
.filter-title {
margin-bottom: 12px;
font-size: 16px;
font-weight: 600;
color: #333;
}
.price-range {
display: flex;
align-items: center;
gap: 8px;
}
.price-input {
flex: 1;
height: 36px;
padding: 0 12px;
border: 1px solid #ddd;
border-radius: 4px;
outline: none;
box-sizing: border-box;
&:focus {
border-color: #009a29;
}
}
.price-separator {
color: #999;
}
.date-picker-box {
.date-input {
width: 100%;
height: 36px;
padding: 0 12px;
border: 1px solid #ddd;
border-radius: 4px;
outline: none;
box-sizing: border-box;
&:focus {
border-color: #009a29;
}
}
}
.filter-buttons {
display: flex;
gap: 12px;
.btn-reset,
.btn-confirm {
height: 36px;
font-size: 14px;
cursor: pointer;
border: none;
border-radius: 4px;
flex: 1;
}
.btn-reset {
color: #666;
background: #f5f5f5;
border: 1px solid #ddd;
&:hover {
background: #eee;
}
}
.btn-confirm {
color: #fff;
background: #009a29;
&:hover {
background: #008f26;
}
}
}
//
.data-list {
overflow: hidden;
background: #fff;
border-radius: 8px;
flex: 1;
}
//
.table-header {
display: flex;
height: 48px;
background: #f5f5f5;
border-bottom: 1px solid #eee;
}
.th {
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
padding: 0 12px;
font-size: 14px;
font-weight: 600;
color: #333;
cursor: pointer;
&:hover {
background: #eee;
}
}
.th-type {
width: 120px;
}
.th-name {
flex: 1;
justify-content: flex-start;
}
.th-time {
width: 180px;
}
.th-count {
width: 100px;
}
.th-views {
width: 100px;
}
.th-downloads {
width: 100px;
}
.sort-icon {
display: flex;
flex-direction: column;
gap: 1px;
font-size: 8px;
color: #ccc;
.sort-up,
.sort-down {
&.active {
color: #009a29;
}
}
.sort-down {
transform: rotate(180deg);
}
}
//
.table-body {
.table-row {
display: flex;
min-height: 72px;
border-bottom: 1px solid #eee;
&:hover {
background: #f9f9f9;
}
&.row-even {
background: #fafafa;
}
}
}
.td {
display: flex;
align-items: center;
justify-content: center;
padding: 0 12px;
font-size: 14px;
color: #666;
}
.td-type {
width: 120px;
}
.td-name {
flex: 1;
justify-content: flex-start;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.td-time {
width: 180px;
flex-direction: column;
justify-content: center;
gap: 4px;
.time-info {
display: flex;
flex-direction: column;
font-size: 12px;
color: #999;
}
}
.td-count {
width: 100px;
}
.td-views {
width: 100px;
}
.td-downloads {
width: 100px;
}
//
.type-tag {
padding: 4px 8px;
font-size: 12px;
border-radius: 4px;
&.tag-green {
color: #2e7d32;
background: #e8f5e9;
}
&.tag-blue {
color: #1565c0;
background: #e3f2fd;
}
}
//
.pagination {
display: flex;
justify-content: center;
align-items: center;
padding: 24px 0;
gap: 8px;
.page-btn {
height: 36px;
min-width: 40px;
padding: 0 12px;
line-height: 36px;
color: #666;
text-align: center;
cursor: pointer;
background: #fff;
border: 1px solid #ddd;
border-radius: 4px;
&:hover {
color: #009a29;
border-color: #009a29;
}
&.active {
color: #fff;
background: #009a29;
border-color: #009a29;
}
}
}
</style>