first commit
This commit is contained in:
1336
src/pages/products/detail.vue
Normal file
1336
src/pages/products/detail.vue
Normal file
File diff suppressed because it is too large
Load Diff
207
src/pages/products/index.vue
Normal file
207
src/pages/products/index.vue
Normal file
@@ -0,0 +1,207 @@
|
||||
<template>
|
||||
<ListPageLayout title="数据大厅" subtitle="发现并订阅您需要的数据产品">
|
||||
<template #filters>
|
||||
<FilterSection>
|
||||
<FilterItem label="产品分类">
|
||||
<el-select v-model="filters.category_id" placeholder="选择分类" clearable @change="handleFilterChange"
|
||||
class="w-full">
|
||||
<el-option v-for="category in categories" :key="category.id" :label="category.name" :value="category.id" />
|
||||
</el-select>
|
||||
</FilterItem>
|
||||
|
||||
<FilterItem label="产品类型">
|
||||
<el-select v-model="filters.is_package" placeholder="选择类型" clearable @change="handleFilterChange"
|
||||
class="w-full">
|
||||
<el-option label="单品" value="false" />
|
||||
<el-option label="组合包" value="true" />
|
||||
</el-select>
|
||||
</FilterItem>
|
||||
|
||||
<FilterItem label="订阅状态">
|
||||
<el-select v-model="filters.is_subscribed" placeholder="选择订阅状态" clearable @change="handleFilterChange"
|
||||
class="w-full">
|
||||
<el-option label="已订阅" value="true" />
|
||||
<el-option label="未订阅" value="false" />
|
||||
</el-select>
|
||||
</FilterItem>
|
||||
|
||||
<FilterItem label="搜索产品">
|
||||
<el-input v-model="filters.keyword" placeholder="输入产品名称或编号" clearable @input="handleSearch" class="w-full" />
|
||||
</FilterItem>
|
||||
|
||||
<template #stats>
|
||||
共找到 {{ total }} 个产品
|
||||
</template>
|
||||
|
||||
<template #buttons>
|
||||
<el-button @click="resetFilters">重置筛选</el-button>
|
||||
<el-button type="primary" @click="loadProducts">应用筛选</el-button>
|
||||
</template>
|
||||
</FilterSection>
|
||||
</template>
|
||||
|
||||
<template #table>
|
||||
<div v-if="loading" class="flex justify-center items-center py-12">
|
||||
<el-loading size="large" />
|
||||
</div>
|
||||
|
||||
<div v-else-if="products.length === 0" class="text-center py-12">
|
||||
<el-empty description="暂无产品数据" />
|
||||
</div>
|
||||
|
||||
<div v-else class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6 p-4">
|
||||
<ProductCard v-for="product in products" :key="product.id" :product="product"
|
||||
:is-subscribed="product.is_subscribed" @view-detail="handleViewDetail"
|
||||
@subscribe="handleSubscribe" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #pagination>
|
||||
<el-pagination v-if="total > 0" v-model:current-page="currentPage" v-model:page-size="pageSize"
|
||||
:page-sizes="[12, 24, 48, 96]" :total="total" layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleSizeChange" @current-change="handleCurrentChange" />
|
||||
</template>
|
||||
</ListPageLayout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { categoryApi, productApi } from '@/api'
|
||||
import FilterItem from '@/components/common/FilterItem.vue'
|
||||
import FilterSection from '@/components/common/FilterSection.vue'
|
||||
import ListPageLayout from '@/components/common/ListPageLayout.vue'
|
||||
import ProductCard from '@/components/product/ProductCard.vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
// 响应式数据
|
||||
const loading = ref(false)
|
||||
const products = ref([])
|
||||
const categories = ref([])
|
||||
const total = ref(0)
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(12)
|
||||
|
||||
// 筛选条件
|
||||
const filters = reactive({
|
||||
category_id: '',
|
||||
is_package: null,
|
||||
is_subscribed: null,
|
||||
keyword: ''
|
||||
})
|
||||
|
||||
// 搜索防抖
|
||||
let searchTimer = null
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
loadCategories()
|
||||
loadProducts()
|
||||
})
|
||||
|
||||
// 加载产品分类
|
||||
const loadCategories = async () => {
|
||||
try {
|
||||
const response = await categoryApi.getCategories({ page: 1, page_size: 100 })
|
||||
categories.value = response.data?.items || []
|
||||
} catch (error) {
|
||||
console.error('加载分类失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 加载产品列表
|
||||
const loadProducts = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const params = {
|
||||
page: currentPage.value,
|
||||
page_size: pageSize.value,
|
||||
...filters
|
||||
}
|
||||
|
||||
const response = await productApi.getProducts(params)
|
||||
products.value = response.data?.items || []
|
||||
total.value = response.data?.total || 0
|
||||
} catch (error) {
|
||||
console.error('加载产品失败:', error)
|
||||
ElMessage.error('加载产品失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 处理筛选变化
|
||||
const handleFilterChange = () => {
|
||||
currentPage.value = 1
|
||||
loadProducts()
|
||||
}
|
||||
|
||||
// 处理搜索
|
||||
const handleSearch = () => {
|
||||
if (searchTimer) {
|
||||
clearTimeout(searchTimer)
|
||||
}
|
||||
searchTimer = setTimeout(() => {
|
||||
currentPage.value = 1
|
||||
loadProducts()
|
||||
}, 500)
|
||||
}
|
||||
|
||||
// 重置筛选
|
||||
const resetFilters = () => {
|
||||
filters.category_id = ''
|
||||
filters.is_package = null
|
||||
filters.is_subscribed = null
|
||||
filters.keyword = ''
|
||||
currentPage.value = 1
|
||||
loadProducts()
|
||||
}
|
||||
|
||||
// 处理分页大小变化
|
||||
const handleSizeChange = (size) => {
|
||||
pageSize.value = size
|
||||
currentPage.value = 1
|
||||
loadProducts()
|
||||
}
|
||||
|
||||
// 处理当前页变化
|
||||
const handleCurrentChange = (page) => {
|
||||
currentPage.value = page
|
||||
loadProducts()
|
||||
}
|
||||
|
||||
// 查看产品详情
|
||||
const handleViewDetail = (product) => {
|
||||
router.push(`/products/${product.id}`)
|
||||
}
|
||||
|
||||
// 订阅产品
|
||||
const handleSubscribe = async (product) => {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`确定要订阅产品"${product.name}"吗?`,
|
||||
'确认订阅',
|
||||
{
|
||||
confirmButtonText: '确定订阅',
|
||||
cancelButtonText: '取消',
|
||||
type: 'info'
|
||||
}
|
||||
)
|
||||
|
||||
await productApi.subscribeProduct(product.id)
|
||||
ElMessage.success('订阅成功')
|
||||
|
||||
// 重新加载产品列表以更新订阅状态
|
||||
await loadProducts()
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
console.error('订阅失败:', error)
|
||||
ElMessage.error('订阅失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 页面特定样式可以在这里添加 */
|
||||
</style>
|
||||
Reference in New Issue
Block a user