consumer模块完成度95%,能编译在安卓端运行,在解决数据获取和页面布局问题

This commit is contained in:
cyh666666
2026-02-26 17:27:15 +08:00
parent e606c597ca
commit b34f960624
1412 changed files with 3304 additions and 804 deletions

View File

@@ -83,21 +83,44 @@
<text class="section-desc">快速定位</text>
</view>
<view class="category-grid" v-if="categoryTab === 'category'">
<!-- 一级分类 -->
<view
v-for="category in categories"
v-for="category in parentCategories"
:key="category.id"
class="category-card"
@click="switchCategory(category)"
@click="onParentCategoryClick(category)"
:style="{ '--card-color': category.color }"
>
<view class="card-icon">
<text class="card-icon-text">{{ category.icon }}</text>
</view>
<text class="card-name">{{ category.name }}</text>
<text class="card-desc">{{ category.description }}</text>
</view>
</view>
<view class="category-grid" v-else>
<!-- 二级分类 -->
<view v-if="categoryTab === 'category' && showSubCategories && subCategories.length > 0" class="sub-category-grid">
<view class="sub-category-header">
<text class="sub-category-title">{{ selectedParentCategory?.name }}分类</text>
<text class="sub-category-close" @click="showSubCategories = false">✕</text>
</view>
<view class="sub-category-wrapper">
<view
v-for="subCat in subCategories"
:key="subCat.id"
class="sub-category-card"
@click="onSubCategoryClick(subCat)"
>
<view class="card-icon">
<text class="card-icon-text">{{ subCat.icon }}</text>
</view>
<text class="card-name">{{ subCat.name }}</text>
</view>
</view>
</view>
<!-- 品牌列表 -->
<view class="category-grid" v-if="categoryTab === 'brand'">
<view
v-for="brand in brands"
:key="brand.id"
@@ -304,6 +327,12 @@ const categoryTab = ref<string>('category')
const categories = ref<Category[]>([])
const brands = ref<Brand[]>([])
// 一级分类和二级分类
const parentCategories = ref<Category[]>([])
const subCategories = ref<Category[]>([])
const selectedParentCategory = ref<Category | null>(null)
const showSubCategories = ref(false)
// 排序标签类型
type SortTab = {
id: string
@@ -342,38 +371,60 @@ const healthNews = [
}
]
// 获取分类数据
// 获取一级分类数据
const loadCategories = async (): Promise<void> => {
try {
const categoriesData = await supabaseService.getCategories()
// 映射字段根据ml_categories表结构映射
const mappedCategories: Category[] = []
const rawList = categoriesData as any[]
for (let i = 0; i < rawList.length; i++) {
const raw = rawList[i]
const catObj = (raw instanceof UTSJSONObject) ? (raw as UTSJSONObject) : (JSON.parse(JSON.stringify(raw)) as UTSJSONObject)
const name = catObj.getString('name') ?? ''
// 过滤掉医药健康相关分类
if (name.includes('医药') || name.includes('健康')) {
continue
}
const id = catObj.getString('id') ?? ''
const description = catObj.getString('description') ?? ''
const icon = catObj.getString('icon') ?? catObj.getString('icon_url') ?? '📦'
const color = catObj.getString('color') ?? '#4CAF50'
// 使用 JSON.parse 创建对象,避免接口实例化问题
const categoryItem = JSON.parse(`{"id":"${id}","name":"${name}","icon":"${icon}","description":"${description}","color":"${color}"}`) as Category
mappedCategories.push(categoryItem)
}
// 保持原始顺序或按ID排序移除随机打乱
categories.value = mappedCategories
const categoriesData = await supabaseService.getParentCategories()
parentCategories.value = categoriesData
// 兼容其他使用 categories 的地方
categories.value = categoriesData
} catch (error) {
console.error('加载分类数据失败:', error)
// 如果加载失败,使用默认分类作为后备
parentCategories.value = []
categories.value = []
}
}
// 获取二级分类数据
const loadSubCategories = async (parentId: string): Promise<void> => {
try {
const subData = await supabaseService.getSubCategories(parentId)
subCategories.value = subData
} catch (error) {
console.error('加载子分类数据失败:', error)
subCategories.value = []
}
}
// 点击一级分类
const onParentCategoryClick = async (category: Category): Promise<void> => {
// 如果已经选中,则切换显示/隐藏二级分类
if (selectedParentCategory.value != null && selectedParentCategory.value.id === category.id) {
showSubCategories.value = !showSubCategories.value
return
}
// 选中新的分类
selectedParentCategory.value = category
showSubCategories.value = true
// 加载二级分类
await loadSubCategories(category.id)
}
// 点击二级分类
const onSubCategoryClick = (category: Category): void => {
// 跳转到分类页面
uni.setStorageSync('selectedCategory', category.id)
const timestamp = Date.now()
const randomParam = Math.random().toString(36).substring(2, 8)
const url = `/pages/mall/consumer/category?categoryId=${category.id}&name=${encodeURIComponent(category.name)}&timestamp=${timestamp}&random=${randomParam}`
uni.switchTab({
url: '/pages/mall/consumer/category'
})
}
// 获取品牌数据
const loadBrands = async () => {
try {
@@ -1138,7 +1189,7 @@ const navigateToReminders = () => uni.navigateTo({ url: '/pages/user/reminders'
}
.category-card {
width: 47%; /* 50 - 3 */
width: 23%; /* 一行4个 */
margin: 0 1.5% 16px 1.5%;
display: flex;
flex-direction: column;
@@ -1187,6 +1238,78 @@ const navigateToReminders = () => uni.navigateTo({ url: '/pages/user/reminders'
text-align: center;
}
/* 二级分类样式 */
.sub-category-grid {
background: #f8f9fa;
border-radius: 12px;
padding: 16px;
margin-top: 16px;
}
.sub-category-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 1px solid #e0e0e0;
}
.sub-category-title {
font-size: 14px;
font-weight: bold;
color: #333;
}
.sub-category-close {
font-size: 16px;
color: #999;
padding: 4px 8px;
}
.sub-category-wrapper {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-start;
}
.sub-category-card {
width: 23%;
background: white;
border-radius: 8px;
padding: 10px 4px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border: 1px solid #eee;
margin-right: 2%;
margin-bottom: 10px;
}
.sub-category-card .card-icon {
width: 36px;
height: 36px;
border-radius: 18px;
margin-bottom: 6px;
display: flex;
align-items: center;
justify-content: center;
}
.sub-category-card .card-icon-text {
font-size: 18px;
}
.sub-category-card .card-name {
font-size: 11px;
color: #333;
text-align: center;
lines: 1;
text-overflow: ellipsis;
}
/* 健康资讯 */
.health-news {
background: white;