商品详情加分类

master
fy 2026-01-23 15:36:51 +08:00
parent eccbae3b69
commit 721e425b72
2 changed files with 239 additions and 22 deletions

View File

@ -2,9 +2,7 @@
<view class="container">
<!-- 顶部导航栏 -->
<view class="navbar">
<view class="nav-back" @click="goBack">
<text class="iconfont"></text>
</view>
<view class="nav-title">分类管理</view>
<view class="nav-more">
<text class="iconfont">···</text>

View File

@ -229,15 +229,13 @@
</view>
</view>
<!-- 商品分类 -->
<view class="setting-item flex-row-between">
<!-- 商品分类点击触发弹窗 -->
<view class="setting-item flex-row-between" @click="showCategorySelector = true; getCategoryData()">
<view class="setting-label">商品分类</view>
<input
class="item-input"
type="text"
placeholder="请输入商品分类"
v-model="goodsInfo.category"
/>
<view class="flex-row">
<text class="selected-value">{{ goodsInfo.category || '请选择分类' }}</text>
<text class="right-arrow">></text>
</view>
</view>
<!-- 商品品牌点击触发弹窗 -->
@ -249,7 +247,7 @@
</view>
</view>
<!-- 品牌选择弹窗完全匹配参考代码+图片 -->
<!-- 品牌选择弹窗 -->
<view v-if="showBrandSelector" class="brand-selector-overlay" @click="closeBrandSelector">
<view class="brand-selector-container" @click.stop>
<!-- 头部 -->
@ -321,6 +319,69 @@
</view>
</view>
<!-- 商品分类选择弹窗 -->
<view v-if="showCategorySelector" class="category-selector-overlay" @click="closeCategorySelector">
<view class="category-selector-container" @click.stop>
<!-- 头部 -->
<view class="selector-header">
<view class="header-left" @click="closeCategorySelector">
<text class="close-icon">×</text>
</view>
<view class="header-title">选择分类</view>
<view class="header-right" @click="confirmSelectedCategory">
<text class="confirm-btn">完成</text>
</view>
</view>
<!-- 搜索框 -->
<view class="search-box">
<input
class="search-input"
type="text"
placeholder="搜索分类名称"
v-model="categorySearchKeyword"
/>
</view>
<!-- 分类列表二级树状结构 -->
<view class="category-list">
<!-- 动态生成分类列表 -->
<template v-for="category in categoryData">
<!-- 父节点 -->
<view
class="category-parent-item"
@click="toggleCategoryExpand(category.id)"
:key="category.id"
>
<text
class="expand-icon"
:class="{expanded: expandedCategories[category.id]}"
></text>
<text class="parent-text">{{ category.classificationName }}</text>
</view>
<!-- 子节点展开时显示 -->
<view v-if="expandedCategories[category.id]" class="category-child-item" :key="category.id + '-children'">
<view
v-for="child in category.children"
:key="child.id"
class="category-item child"
:class="{active: selectedCategory === child.classificationName}"
@click="selectCategory(child.classificationName)"
>
{{ child.classificationName }}
</view>
</view>
</template>
</view>
<!-- 分类管理入口 -->
<view class="category-management" @click="goToCategoryManagement">
<text class="management-text">分类管理</text>
</view>
</view>
</view>
<!-- 商品编码 -->
<view class="setting-item flex-row-between">
<view class="setting-label">商品编码</view>
@ -357,7 +418,7 @@ export default {
stock: 1,
buyPrice: 1.0,
category: '默认',
brand: '那', //
brand: '那',
code: '1',
shelfCode: '',
productionDate: ''
@ -387,9 +448,15 @@ export default {
//
showBrandSelector: false,
brandSearchKeyword: '',
selectedBrand: '那', //
brandData: [], //
expandedBrands: {} //
selectedBrand: '那',
brandData: [],
expandedBrands: {},
//
showCategorySelector: false,
categorySearchKeyword: '',
selectedCategory: 'default',
categoryData: [], //
expandedCategories: {} //
}
},
onLoad(options) {
@ -494,13 +561,14 @@ export default {
salePrice: data.storePrice || this.goodsInfo.salePrice,
stock: data.stockQuantity || this.goodsInfo.stock,
buyPrice: data.costPrice || this.goodsInfo.buyPrice,
category: this.goodsInfo.category,
category: data.classifcation || this.goodsInfo.category,
brand: data.productBrand || this.goodsInfo.brand,
code: data.productCode || this.goodsInfo.code
};
this.activePrice = data.storePrice || this.goodsInfo.salePrice;
this.selectedBrand = data.productBrand || this.goodsInfo.brand;
this.selectedCategory = data.classifcation || this.goodsInfo.category;
if (data.shelfLife) {
this.switchStatus.expire = true;
@ -583,7 +651,8 @@ export default {
approaching: this.switchStatus.expire ? this.expireSettings.warnDays : null,
productionDate: this.goodsInfo.productionDate || '',
storeId: storeId,
productBrand: this.goodsInfo.brand
productBrand: this.goodsInfo.brand,
classification: this.goodsInfo.category
};
const res = await updateProductWithFile(this.goodsInfo.imageUrl || '', formData);
@ -638,6 +707,40 @@ export default {
}
},
//
async getCategoryData() {
try {
const storeId = getStoreId();
if (!storeId) {
uni.showToast({
title: '请先选择门店',
icon: 'none'
});
return;
}
const res = await uni.request({
url: `http://193.112.94.36:8081/mall/classification/getTree/${storeId}`,
method: 'GET'
});
if (res[1] && res[1].data && res[1].data.code === 200) {
this.categoryData = res[1].data.data;
} else {
uni.showToast({
title: '获取分类数据失败',
icon: 'none'
});
}
} catch (error) {
console.error('获取分类数据失败:', error);
uni.showToast({
title: '网络请求失败',
icon: 'none'
});
}
},
//
selectBrand(brandName) {
this.selectedBrand = brandName;
@ -659,7 +762,37 @@ export default {
uni.navigateTo({
url: '/pages/addBrand/addBrand'
});
},
//
selectCategory(categoryName) {
this.selectedCategory = categoryName;
},
confirmSelectedCategory() {
//
const categoryMap = {
'rx': '处方药(RX)',
'vet-otc': '兽用非处方药',
'vet-rx': '兽用处方药',
'default': '默认',
'otc-child': 'OTC子分类示例',
'go-child': '子分类示例'
};
this.goodsInfo.category = categoryMap[this.selectedCategory] || this.selectedCategory;
this.showCategorySelector = false;
this.categorySearchKeyword = '';
},
closeCategorySelector() {
this.showCategorySelector = false;
this.categorySearchKeyword = '';
},
toggleCategoryExpand(key) {
this.$set(this.expandedCategories, key, !this.expandedCategories[key]);
},
goToCategoryManagement() {
this.showCategorySelector = false;
uni.navigateTo({
url: '/pages/category/category'
});
}
}
};
@ -1015,7 +1148,7 @@ export default {
}
}
//
// /
.selected-value {
font-size: 30rpx;
color: #333;
@ -1023,7 +1156,7 @@ export default {
}
// --------------------------
//
//
// --------------------------
.brand-selector-overlay {
position: fixed;
@ -1120,7 +1253,7 @@ export default {
color: #999;
transition: transform 0.2s ease;
&.expanded {
transform: rotate(180deg);
transform: rotate(90deg);
}
}
.parent-text {
@ -1136,4 +1269,90 @@ export default {
font-size: 28rpx;
border-top: 1rpx solid #f0f0f0;
}
// --------------------------
//
// --------------------------
.category-selector-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: flex-end;
z-index: 999;
}
.category-selector-container {
width: 100%;
background: #fff;
border-radius: 16rpx 16rpx 0 0;
max-height: 80vh;
display: flex;
flex-direction: column;
}
.category-list {
flex: 1;
overflow-y: auto;
//
.category-item {
padding: 30rpx;
border-bottom: 1rpx solid #f0f0f0;
font-size: 30rpx;
color: #333;
position: relative;
&.active {
border: 1rpx solid #E62429;
border-radius: 8rpx;
margin: 0 16rpx;
&::after {
content: "✓";
position: absolute;
right: 30rpx;
top: 50%;
transform: translateY(-50%);
font-size: 28rpx;
color: #E62429;
}
}
//
&.child {
padding-left: 60rpx;
background-color: #fafafa;
}
}
//
.category-parent-item {
padding: 30rpx;
border-bottom: 1rpx solid #f0f0f0;
font-size: 30rpx;
color: #333;
display: flex;
align-items: center;
.expand-icon {
font-size: 24rpx;
margin-right: 10rpx;
color: #999;
transition: transform 0.2s ease;
&.expanded {
transform: rotate(90deg);
}
}
.parent-text {
flex: 1;
}
}
}
.category-management {
padding: 30rpx;
text-align: center;
color: #1677FF;
font-size: 28rpx;
border-top: 1rpx solid #f0f0f0;
}
</style>