ry_app/pages/edit/edit.vue

1484 lines
41 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<view class="goods-edit-page">
<!-- 顶部导航栏 -->
<view class="navbar">
<view class="nav-left" @click="navBack">
<!-- <text class="icon"></text> -->
</view>
<view class="nav-title">编辑商品</view>
<view class="nav-right">
<text class="icon">···</text>
</view>
</view>
<!-- 商品图片展示区 -->
<view class="goods-img-box">
<image
class="goods-img"
:src="goodsInfo.imageUrl"
mode="widthFix"
@click="previewImage"
></image>
<view class="change-img-btn" @click="chooseImage"></view>
</view>
<!-- -->
<view class="form-container">
<!-- 商品名称 -->
<view class="form-item">
<view class="form-label">
<text class="required">*</text>名称
</view>
<input
class="item-input"
type="text"
placeholder="请输入商品名称"
v-model="goodsInfo.name"
/>
</view>
<!-- 商品单位 -->
<view class="form-item">
<view class="form-label">商品单位</view>
<input
class="item-input"
type="text"
placeholder="请输入商品单位"
v-model="goodsInfo.unit"
/>
</view>
<!-- 条码+扫码按钮 -->
<view class="form-item">
<view class="form-label">
<text class="required">*</text>条码
</view>
<view class="flex-row">
<input
class="item-input barcode-input"
type="text"
placeholder="请输入条码"
v-model="goodsInfo.barcode"
/>
<view class="scan-btn" @click="scanBarcode">扫码</view>
</view>
</view>
<!-- 售价核心区域(修正排版) -->
<view class="form-item">
<view class="form-label">
<text class="required">*</text>售价
</view>
<view class="flex-row">
<input
class="item-input price-input"
type="digit"
placeholder="请输入售价"
v-model="goodsInfo.salePrice"
/>
<text class="price-unit">元</text>
</view>
</view>
<!-- 推荐价格提示与选项 -->
<view class="price-recommend-section">
<view class="price-tips">
推荐价格(点击快速设置售价)<text class="tips-icon">i</text>
</view>
<view class="price-option-list">
<view
class="price-option"
:class="{active: activePrice == item.price}"
v-for="item in priceOptions"
:key="item.price"
@click="setSalePrice(item.price)"
>
<text class="option-text">{{ item.desc }}</text>
<text class="option-price">{{ item.price }}元</text>
</view>
</view>
</view>
<!-- 库存 -->
<view class="form-item">
<view class="form-label">库存</view>
<view class="flex-row">
<input
class="item-input"
type="number"
placeholder="请输入库存"
v-model="goodsInfo.stock"
/>
<text class="unit-text">件</text>
</view>
</view>
<!-- 最近进货价 -->
<view class="form-item">
<view class="form-label">最近进货价</view>
<view class="flex-row">
<input
class="item-input"
type="digit"
placeholder="请输入进货价"
v-model="goodsInfo.buyPrice"
/>
<text class="unit-text">元</text>
</view>
</view>
<!-- 货架码 -->
<view class="form-item">
<view class="form-label">货架码</view>
<input
class="item-input"
type="text"
placeholder="请输入货架码"
v-model="goodsInfo.shelfCode"
/>
</view>
<!-- 添加更多单位按钮 -->
<view class="add-unit-btn" @click="addUnit">+ 添加更多单位</view>
</view>
<!-- 其他设置区域 -->
<view class="settings-container">
<view class="settings-title">其他设置</view>
<!-- 保质期管理 -->
<view class="form-item">
<text class="item-label">保质期管理</text>
<switch
:checked="switchStatus.expire"
@change="toggleExpirationManagement"
color="#F53F3F"
/>
</view>
<!-- 保质期天数 -->
<view class="form-item" v-if="switchStatus.expire">
<text class="item-label">保质期天数</text>
<view class="expiration-options">
<view
class="expiration-item"
:class="{ active: expireSettings.days === 365 }"
@tap="setExpirationDays(365)"
>
<text class="expiration-text">1年</text>
<text class="expiration-days">365天</text>
</view>
<view
class="expiration-item"
:class="{ active: expireSettings.days === 270 }"
@tap="setExpirationDays(270)"
>
<text class="expiration-text">9个月</text>
<text class="expiration-days">270天</text>
</view>
<view
class="expiration-item"
:class="{ active: expireSettings.days === 180 }"
@tap="setExpirationDays(180)"
>
<text class="expiration-text">6个月</text>
<text class="expiration-days">180天</text>
</view>
<view
class="expiration-item"
:class="{ active: expireSettings.days === 240 }"
@tap="setExpirationDays(240)"
>
<text class="expiration-text">8个月</text>
<text class="expiration-days">240天</text>
</view>
<view
class="expiration-item"
:class="{ active: expireSettings.days === 300 }"
@tap="setExpirationDays(300)"
>
<text class="expiration-text">10个月</text>
<text class="expiration-days">300天</text>
</view>
</view>
</view>
<!-- 临期提醒天数 -->
<view class="form-item" v-if="switchStatus.expire">
<text class="item-label">临期提醒天数</text>
<view class="flex-row">
<input
class="item-input"
type="number"
placeholder="请输入临期提醒天数"
v-model="expireSettings.warnDays"
/>
<text class="unit-text">天</text>
</view>
</view>
<!-- 未成年人购买香烟提示 -->
<view class="setting-item flex-row-between">
<view class="setting-label flex-row">
<text>未成年人购买香烟提示</text>
<text class="tips-icon">i</text>
</view>
<view class="switch-box" @click="toggleSwitch('minor')">
<view class="switch-bg" :class="{open: switchStatus.minor}"></view>
<view class="switch-btn" :class="{open: switchStatus.minor}"></view>
</view>
</view>
<!-- 商品分类(点击触发弹窗) -->
<view class="setting-item flex-row-between" @click="showCategorySelector = true; getCategoryData()">
<view class="setting-label">商品分类</view>
<view class="flex-row">
<text class="selected-value">{{ goodsInfo.category || '请选择分类' }}</text>
<text class="right-arrow">></text>
</view>
</view>
<!-- 商品品牌(点击触发弹窗) -->
<view class="setting-item flex-row-between" @click="showBrandSelector = true; getBrandData()">
<view class="setting-label">商品品牌</view>
<view class="flex-row">
<text class="selected-value">{{ goodsInfo.brand || '请选择品牌' }}</text>
<text class="right-arrow">></text>
</view>
</view>
<!-- 品牌选择弹窗 -->
<view v-if="showBrandSelector" class="brand-selector-overlay" @click="closeBrandSelector">
<view class="brand-selector-container" @click.stop>
<!-- 头部 -->
<view class="selector-header">
<view class="header-left" @click="closeBrandSelector">
<text class="close-icon">×</text>
</view>
<view class="header-title">选择品牌</view>
<view class="header-right" @click="confirmSelectedBrand">
<text class="confirm-btn">完成</text>
</view>
</view>
<!-- 搜索框 -->
<view class="search-box" style="z-index: 10000; pointer-events: auto; display: flex; align-items: center; gap: 10rpx;">
<input
type="text"
placeholder="搜索品牌名称1"
:value="brandSearchKeyword"
@input="brandSearchKeyword = $event.detail.value"
style="
flex: 1;
padding: 20rpx;
background: #f5f5f5;
border-radius: 8rpx;
font-size: 28rpx;
border: 1rpx solid #ddd;
z-index: 10001;
pointer-events: auto;
user-select: text;
-webkit-user-select: text;
"
/>
<view
@click="performBrandSearch"
style="
padding: 15rpx 25rpx;
background-color: #E62429;
color: white;
border-radius: 8rpx;
font-size: 28rpx;
z-index: 10002;
pointer-events: auto;
"
>
搜索
</view>
</view>
<!-- 品牌列表(二级树状结构) -->
<view class="brand-list">
<!-- 普通品牌项 - 默认品牌 -->
<view
class="brand-item"
:class="{active: selectedBrand === '默认品牌'}"
@click="selectBrand('默认品牌')"
>
默认品牌
</view>
<!-- 动态生成品牌列表 -->
<template v-for="brand in brandData">
<!-- 父节点 -->
<view
class="brand-parent-item"
@click="toggleBrandExpand(brand.id)"
:key="brand.id"
>
<text
class="expand-icon"
:class="{expanded: expandedBrands[brand.id]}"
>▼</text>
<text class="parent-text">{{ brand.brandName }}</text>
</view>
<!-- 子节点(展开时显示) -->
<view v-if="expandedBrands[brand.id]" class="brand-child-item" :key="brand.id + '-children'">
<view
v-for="child in brand.children"
:key="child.id"
class="brand-item child"
:class="{active: selectedBrand === child.brandName}"
@click="selectBrand(child.brandName)"
>
{{ child.brandName }}
</view>
</view>
</template>
</view>
<!-- 品牌管理入口 -->
<view class="brand-management" @click="goToBrandManagement">
<text class="management-text">品牌管理</text>
</view>
</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" style="z-index: 10000; pointer-events: auto; display: flex; align-items: center; gap: 10rpx;">
<input
type="text"
placeholder="搜索分类名称"
:value="categorySearchKeyword"
@input="categorySearchKeyword = $event.detail.value"
style="
flex: 1;
padding: 20rpx;
background: #f5f5f5;
border-radius: 8rpx;
font-size: 28rpx;
border: 1rpx solid #ddd;
z-index: 10001;
pointer-events: auto;
user-select: text;
-webkit-user-select: text;
"
/>
<view
@click="performCategorySearch"
style="
padding: 15rpx 25rpx;
background-color: #E62429;
color: white;
border-radius: 8rpx;
font-size: 28rpx;
z-index: 10002;
pointer-events: auto;
"
>
搜索
</view>
</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>
<input
class="item-input"
type="text"
placeholder="请输入商品编码"
v-model="goodsInfo.code"
/>
</view>
</view>
<!-- 底部固定保存按钮 -->
<view class="bottom-submit">
<button class="save-btn" @click="saveGoods"></button>
</view>
</view>
</template>
<script>
import { getProductDetail, updateProduct, updateProductWithFile, getClassificationTree, getBrandTree } from '@/api/product'
import { getStoreId } from '@/utils/auth'
export default {
name: 'GoodsEdit',
data() {
return {
productId: null,
goodsInfo: {
imageUrl: 'https://p3-flow-imagex-sign.byteimg.com/tos-cn-i-a9rns2rl98/1b5ce0f17f5e4942a350d4c58f83dde9.png~tplv-a9rns2rl98-image.png?lk3s=8e244e95&rcl=202601151851433FA5618C22F61C91356F&rrcfp=dafada99&x-expires=2084698303&x-signature=mApXMrIjzYh%2B1B6IE2pHDPy9Z2U%3D',
name: '农夫山泉饮用天然水 550ML',
unit: '瓶',
barcode: '6921168509256',
salePrice: 5.5,
stock: 1,
buyPrice: 1.0,
category: '默认',
brand: '那',
code: '1',
shelfCode: '',
productionDate: ''
},
priceOptions: [
{ price: 2.0, desc: '92%商家卖' },
{ price: 1.5, desc: '2%商家卖' },
{ price: 1.8, desc: '1%商家卖' }
],
activePrice: 2.0,
switchStatus: {
expire: true,
minor: false
},
expireSettings: {
days: 240,
warnDays: 24,
activeOption: { label: '8个月', days: 240 }
},
expireOptionList: [
{ label: '1年', days: 365 },
{ label: '9个月', days: 270 },
{ label: '6个月', days: 180 },
{ label: '8个月', days: 240 },
{ label: '10个月', days: 300 }
],
// 品牌选择弹窗相关
showBrandSelector: false,
brandSearchKeyword: '',
selectedBrand: '那',
brandData: [],
expandedBrands: {},
// 分类选择弹窗相关
showCategorySelector: false,
categorySearchKeyword: '',
selectedCategory: 'default',
categoryData: [], // 分类数据
expandedCategories: {} // 记录展开状态的对象
}
},
onLoad(options) {
console.log('编辑页面参数:', options);
if (options.id) {
this.productId = options.id;
} else {
uni.showToast({
title: '缺少商品ID参数',
icon: 'none'
});
}
},
onShow() {
if (this.productId) {
this.loadProductDetail();
}
},
computed: {
warningDaysDisplay() {
if (!this.expireSettings.days) return '';
const days = parseInt(this.expireSettings.days);
return days.toString().substring(0, 2);
}
},
methods: {
navBack() {
uni.navigateBack({ delta: 1 });
},
previewImage() {
uni.previewImage({
urls: [this.goodsInfo.imageUrl],
current: this.goodsInfo.imageUrl
});
},
chooseImage() {
uni.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
this.goodsInfo.imageUrl = res.tempFilePaths[0];
}
});
},
scanBarcode() {
uni.scanCode({
onlyFromCamera: true,
scanType: ['barCode'],
success: (res) => {
this.goodsInfo.barcode = res.result;
uni.showToast({ title: '扫码成功', icon: 'success' });
},
fail: () => {
uni.showToast({ title: '扫码取消', icon: 'none' });
}
});
},
setSalePrice(price) {
this.activePrice = price;
this.goodsInfo.salePrice = price;
},
toggleSwitch(type) {
if (type === 'expire') {
this.switchStatus.expire = !this.switchStatus.expire;
} else if (type === 'minor') {
this.switchStatus.minor = !this.switchStatus.minor;
}
},
toggleExpirationManagement(e) {
this.switchStatus.expire = e.detail.value;
},
setExpirationDays(days) {
this.expireSettings.days = days;
const warningDays = days.toString().substring(0, 2);
this.expireSettings.warnDays = warningDays;
uni.showToast({ title: `已设置为${days}`, icon: 'success', duration: 1500 });
},
async loadProductDetail() {
if (!this.productId) {
uni.showToast({
title: '缺少商品ID',
icon: 'none'
});
return;
}
try {
console.log('正在获取商品详情ID:', this.productId);
const res = await getProductDetail(this.productId);
console.log('商品详情接口返回:', res);
if (res && res.code === 200 && res.data) {
const data = res.data;
this.goodsInfo = {
imageUrl: data.mainImage ? 'http://193.112.94.36:8081' + data.mainImage : this.goodsInfo.imageUrl,
name: data.productName || this.goodsInfo.name,
unit: this.goodsInfo.unit,
barcode: data.productBarCode || this.goodsInfo.barcode,
salePrice: data.storePrice || this.goodsInfo.salePrice,
stock: data.stockQuantity || this.goodsInfo.stock,
buyPrice: data.costPrice || this.goodsInfo.buyPrice,
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;
this.expireSettings.days = data.shelfLife;
this.expireSettings.warnDays = data.approaching || 24;
const days = data.shelfLife;
const option = this.expireOptionList.find(item => item.days === days);
if (option) {
this.expireSettings.activeOption = option;
}
} else {
this.switchStatus.expire = false;
}
console.log('商品详情数据:', this.goodsInfo);
} else {
uni.showToast({
title: res?.msg || '获取商品详情失败',
icon: 'none'
});
}
} catch (error) {
console.error('获取商品详情失败:', error);
uni.showToast({
title: '网络请求失败',
icon: 'none'
});
}
},
setExpireDays(item) {
this.expireSettings.days = item.days;
this.expireSettings.activeOption = item;
},
addUnit() {
uni.showModal({
title: '提示',
content: '是否添加商品多单位规格?',
success: (res) => {
if (res.confirm) uni.showToast({ title: '添加成功', icon: 'success' });
}
});
},
async saveGoods() {
if (!this.goodsInfo.name || !this.goodsInfo.name.trim()) {
uni.showToast({ title: '请输入商品名称', icon: 'none' });
return;
}
if (!this.goodsInfo.salePrice) {
uni.showToast({ title: '请输入售价', icon: 'none' });
return;
}
if (this.switchStatus.expire && !this.expireSettings.days) {
uni.showToast({ title: '请选择保质期天数', icon: 'none' });
return;
}
const storeId = getStoreId();
if (!storeId) {
uni.showToast({ title: '请先选择门店', icon: 'none' });
return;
}
uni.showLoading({ title: '保存中...' });
try {
const formData = {
id: this.productId,
productName: this.goodsInfo.name,
productBarCode: this.goodsInfo.barcode,
storePrice: this.goodsInfo.salePrice,
stockQuantity: this.goodsInfo.stock,
costPrice: this.goodsInfo.buyPrice,
productCode: this.goodsInfo.code,
shelfCode: this.goodsInfo.shelfCode || '',
expirationManagement: this.switchStatus.expire ? 1 : 0,
shelfLife: this.switchStatus.expire ? this.expireSettings.days : null,
approaching: this.switchStatus.expire ? this.expireSettings.warnDays : null,
productionDate: this.goodsInfo.productionDate || '',
storeId: storeId,
productBrand: this.goodsInfo.brand,
classification: this.goodsInfo.category
};
const res = await updateProductWithFile(this.goodsInfo.imageUrl || '', formData);
uni.hideLoading();
if (res.code === 200) {
uni.showToast({
title: '保存成功',
icon: 'success',
duration: 2000
});
setTimeout(() => {
this.navBack();
}, 2000);
} else {
uni.showToast({
title: res.msg || '保存失败',
icon: 'none'
});
}
} catch (error) {
uni.hideLoading();
console.error('保存商品失败:', error);
uni.showToast({
title: '网络请求失败',
icon: 'none'
});
}
},
// 获取品牌数据 - 简化版,只获取所有品牌
async getBrandData() {
try {
// 使用默认门店ID 2如果未找到门店ID
const storeId = getStoreId() || 2;
// 直接获取所有品牌
const res = await getBrandTree(storeId);
if (res.code === 200) {
this.brandData = res.data || [];
} else {
console.log('获取品牌数据失败:', res);
}
} catch (error) {
console.error('获取品牌数据失败:', error);
}
},
// 获取分类数据 - 简化版,只获取所有分类
async getCategoryData() {
try {
// 使用默认门店ID 2如果未找到门店ID
const storeId = getStoreId() || 2;
// 直接获取所有分类
const res = await getClassificationTree(storeId);
if (res.code === 200) {
this.categoryData = res.data || [];
} else {
console.log('获取分类数据失败:', res);
}
} catch (error) {
console.error('获取分类数据失败:', error);
}
},
// 执行分类搜索
async performCategorySearch() {
try {
// 使用默认门店ID 2如果未找到门店ID
const storeId = getStoreId() || 2;
// 调用分类搜索API
const res = await getClassificationTree(storeId, this.categorySearchKeyword);
if (res.code === 200) {
this.categoryData = res.data || [];
} else {
console.log('搜索分类失败:', res);
}
} catch (error) {
console.error('搜索分类失败:', error);
}
},
// 分类输入处理 - 仅更新数据不触发API
handleCategoryInput(e) {
// 直接更新数据让v-model正常工作
this.categorySearchKeyword = e.detail.value;
},
// 品牌输入处理 - 仅更新数据不触发API
handleBrandInput(e) {
// 直接更新数据让v-model正常工作
this.brandSearchKeyword = e.detail.value;
},
// 执行品牌搜索
async performBrandSearch() {
try {
// 使用默认门店ID 2如果未找到门店ID
const storeId = getStoreId() || 2;
// 调用品牌搜索API
const res = await getBrandTree(storeId, this.brandSearchKeyword);
if (res.code === 200) {
this.brandData = res.data || [];
} else {
console.log('搜索品牌失败:', res);
}
} catch (error) {
console.error('搜索品牌失败:', error);
}
},
// 品牌选择弹窗方法
selectBrand(brandName) {
this.selectedBrand = brandName;
},
confirmSelectedBrand() {
this.goodsInfo.brand = this.selectedBrand;
this.showBrandSelector = false;
this.brandSearchKeyword = '';
},
closeBrandSelector() {
this.showBrandSelector = false;
this.brandSearchKeyword = '';
},
toggleBrandExpand(brandId) {
this.$set(this.expandedBrands, brandId, !this.expandedBrands[brandId]);
},
goToBrandManagement() {
this.showBrandSelector = false;
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'
});
}
}
};
</script>
<style lang="scss" scoped>
// 全局样式
.goods-edit-page {
background-color: #f5f5f5;
min-height: 100vh;
box-sizing: border-box;
padding-bottom: 120rpx;
}
.flex-row {
display: flex;
align-items: center;
}
.flex-row-between {
display: flex;
align-items: center;
justify-content: space-between;
}
// 顶部导航栏
.navbar {
height: 88rpx;
background: #E62429;
color: #FFFFFF;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 30rpx;
position: sticky;
top: 0;
left: 0;
right: 0;
z-index: 99;
.nav-left, .nav-right {
width: 60rpx;
text-align: center;
.icon {
font-size: 32rpx;
}
}
.nav-title {
font-size: 36rpx;
font-weight: 500;
}
}
// 商品图片区域
.goods-img-box {
background: #FFFFFF;
padding: 40rpx 0;
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 20rpx;
.goods-img {
width: 220rpx;
height: 220rpx;
border-radius: 8rpx;
margin-bottom: 30rpx;
}
.change-img-btn {
font-size: 28rpx;
color: #666666;
padding: 12rpx 30rpx;
border: 1px solid #E5E5E5;
border-radius: 6rpx;
}
}
// 表单容器
.form-container {
background: #FFFFFF;
margin-bottom: 20rpx;
.form-item {
padding: 30rpx;
border-bottom: 1px solid #F0F0F0;
display: flex;
justify-content: space-between;
align-items: center;
.form-label {
font-size: 30rpx;
color: #333333;
.required {
color: #E62429;
margin-right: 4rpx;
}
}
.form-value {
font-size: 30rpx;
color: #333333;
}
.scan-btn {
margin-left: 20rpx;
padding: 8rpx 20rpx;
background: #F5F5F5;
border-radius: 4rpx;
font-size: 26rpx;
color: #666666;
}
}
// 推荐价格区域(修正后的排版)
.price-recommend-section {
padding: 0 30rpx 30rpx;
.price-tips {
width: 100%;
font-size: 24rpx;
color: #999999;
margin-bottom: 15rpx;
.tips-icon {
display: inline-block;
width: 20rpx;
height: 20rpx;
border: 1px solid #999;
border-radius: 50%;
text-align: center;
line-height: 20rpx;
font-size: 18rpx;
margin-left: 5rpx;
}
}
.price-option-list {
width: 100%;
display: flex;
gap: 20rpx;
.price-option {
flex: 1;
background: #F5F5F5;
border-radius: 8rpx;
padding: 20rpx 10rpx;
text-align: center;
.option-text {
font-size: 24rpx;
color: #666;
}
.option-price {
display: block;
font-size: 32rpx;
color: #E62429;
font-weight: bold;
margin-top: 8rpx;
}
&.active {
background: #E62429;
.option-text, .option-price {
color: #FFFFFF;
}
}
}
}
}
.form-placeholder {
font-size: 28rpx;
color: #CCCCCC;
}
.right-arrow {
font-size: 28rpx;
color: #CCCCCC;
margin-left: 10rpx;
}
.add-unit-btn {
margin: 30rpx;
padding: 20rpx;
text-align: center;
font-size: 28rpx;
color: #666666;
border: 1px dashed #CCCCCC;
border-radius: 8rpx;
background: #FFFFFF;
}
}
// 其他设置区域
.settings-container {
background: #FFFFFF;
.settings-title {
font-size: 32rpx;
font-weight: bold;
color: #333333;
padding: 30rpx;
border-bottom: 1px solid #F0F0F0;
}
.setting-item {
padding: 30rpx;
border-bottom: 1px solid #F0F0F0;
.setting-label {
font-size: 30rpx;
color: #333333;
.tips-icon {
display: inline-block;
width: 20rpx;
height: 20rpx;
border: 1px solid #999;
border-radius: 50%;
text-align: center;
line-height: 20rpx;
font-size: 18rpx;
margin-left: 5rpx;
}
}
.setting-left {
.setting-tips {
font-size: 24rpx;
color: #1677FF;
margin-top: 8rpx;
}
}
.setting-value {
font-size: 30rpx;
color: #333333;
}
.switch-box {
width: 70rpx;
height: 40rpx;
background: #E5E5E5;
border-radius: 20rpx;
position: relative;
display: flex;
align-items: center;
padding: 0 4rpx;
.switch-bg {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
border-radius: 20rpx;
background: #E5E5E5;
transition: all 0.3s ease;
&.open {
background: #E62429;
}
}
.switch-btn {
width: 32rpx;
height: 32rpx;
background: #FFFFFF;
border-radius: 50%;
position: relative;
z-index: 2;
transition: all 0.3s ease;
&.open {
transform: translateX(30rpx);
}
}
}
}
.expire-options {
display: flex;
padding: 0 30rpx 30rpx;
gap: 15rpx;
overflow-x: auto;
.expire-option {
flex-shrink: 0;
background: #F5F5F5;
border: 2px solid transparent;
border-radius: 8rpx;
padding: 15rpx 20rpx;
text-align: center;
position: relative;
.option-text {
font-size: 28rpx;
color: #333;
}
.option-days {
display: block;
font-size: 24rpx;
color: #E62429;
margin-top: 5rpx;
}
&.active {
border-color: #E62429;
background: #FFFFFF;
.checked-icon {
display: block;
position: absolute;
top: -10rpx;
right: -10rpx;
width: 30rpx;
height: 30rpx;
background: #E62429;
color: #FFFFFF;
border-radius: 50%;
font-size: 20rpx;
line-height: 30rpx;
text-align: center;
}
}
}
}
}
/* 保质期相关样式 */
.expiration-options { display:flex;flex-wrap:wrap;gap:20rpx;flex:1;justify-content:flex-end; }
.expiration-item { display:flex;flex-direction:column;align-items:center;padding:16rpx 20rpx;background:#f9f9f9;border-radius:8rpx;min-width:100rpx;border:2rpx solid transparent;transition:all 0.3s; }
.expiration-item.active { background:#F53F3F;border-color:#F53F3F; }
.expiration-item.active .expiration-text { color:#fff; }
.expiration-item.active .expiration-days { color:#fff; }
.expiration-text { font-size:28rpx;color:#333; }
.expiration-days { font-size:24rpx;color:#333;margin-top:4rpx; }
/* 临期提醒天数样式 */
.warning-days-display { display:flex;align-items:center;flex:1;justify-content:flex-end; }
.warning-days-value { font-size:36rpx;color:#333;font-weight:600;margin-right:8rpx; }
.warning-days-unit { font-size:28rpx;color:#333; }
/* 表单项样式 */
.form-item {
padding: 32rpx;
border-bottom: 1rpx solid #f0f0f0;
display: flex;
align-items: center;
justify-content: space-between;
}
.item-label { font-size: 32rpx;color: #333333;font-weight: 500;min-width: 160rpx; }
.item-input { flex:1;font-size:32rpx;color:#333;text-align:right;padding:0 20rpx; }
.item-input::placeholder { color: #999999; }
.barcode-input { flex: 1; }
.price-input { flex: 1; }
.price-unit { font-size: 32rpx;color: #333;margin-left: 10rpx; }
.unit-text { font-size: 32rpx;color: #333;margin-left: 10rpx; }
// 底部保存按钮
.bottom-submit {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: #FFFFFF;
padding: 20rpx 30rpx;
border-top: 1px solid #F0F0F0;
z-index: 90;
.save-btn {
width: 100%;
height: 90rpx;
line-height: 90rpx;
background: #E62429;
color: #FFFFFF;
font-size: 32rpx;
font-weight: 500;
border-radius: 8rpx;
padding: 0;
margin: 0;
&::after {
border: none;
}
}
}
// 商品品牌/分类选中值样式
.selected-value {
font-size: 30rpx;
color: #333;
margin-right: 10rpx;
}
// --------------------------
// 品牌选择弹窗样式
// --------------------------
.brand-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;
pointer-events: auto;
}
.brand-selector-container {
width: 100%;
background: #fff;
border-radius: 16rpx 16rpx 0 0;
max-height: 80vh;
display: flex;
flex-direction: column;
pointer-events: auto;
z-index: 1000;
}
.selector-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 30rpx;
border-bottom: 1rpx solid #f0f0f0;
.close-icon {
font-size: 36rpx;
color: #666;
}
.header-title {
font-size: 32rpx;
font-weight: 500;
color: #333;
}
.confirm-btn {
font-size: 30rpx;
color: #E62429;
}
}
.search-box {
padding: 20rpx 30rpx;
/* 确保搜索框容器可以被点击 */
pointer-events: auto;
z-index: 1000;
display: flex;
align-items: center;
gap: 10rpx;
.search-input {
flex: 1;
padding: 20rpx;
background: #f5f5f5;
border-radius: 8rpx;
font-size: 28rpx;
/* 确保输入框可以被点击和选中 */
pointer-events: auto;
z-index: 1001;
/* 确保输入框有焦点样式 */
border: 1rpx solid #ddd;
/* 确保可以选中文本 */
user-select: text;
/* 确保可以获得焦点 */
outline: none;
/* 确保触摸设备上可以正常使用 */
-webkit-user-select: text;
-webkit-tap-highlight-color: transparent;
&:focus {
border-color: #E62429;
box-shadow: 0 0 0 2rpx rgba(230, 36, 41, 0.1);
}
}
.search-button {
padding: 15rpx 25rpx;
background-color: #E62429;
color: white;
border-radius: 8rpx;
font-size: 28rpx;
/* 确保按钮可以被点击 */
pointer-events: auto;
z-index: 1002;
/* 添加点击反馈 */
&:active {
opacity: 0.8;
}
}
}
.brand-list {
flex: 1;
overflow-y: auto;
// 普通品牌项
.brand-item {
padding: 30rpx;
border-bottom: 1rpx solid #f0f0f0;
font-size: 30rpx;
color: #333;
position: relative;
&.active {
color: #E62429;
&::after {
content: "✓";
position: absolute;
right: 30rpx;
top: 50%;
transform: translateY(-50%);
font-size: 28rpx;
}
}
// 子节点样式
&.child {
padding-left: 60rpx;
background-color: #fafafa;
}
}
// 父节点样式
.brand-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;
}
}
}
.brand-management {
padding: 30rpx;
text-align: center;
color: #1677FF;
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;
pointer-events: auto;
}
.category-selector-container {
width: 100%;
background: #fff;
border-radius: 16rpx 16rpx 0 0;
max-height: 80vh;
display: flex;
flex-direction: column;
pointer-events: auto;
z-index: 1000;
}
.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>