Compare commits
52 Commits
8e0122b08f
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
646f69bb56 | ||
|
|
756444ef2b | ||
|
|
6dfc201c66 | ||
|
|
870e1c612d | ||
|
|
fbcd930887 | ||
|
|
a1bcc2e478 | ||
|
|
a84cd57fad | ||
|
|
c49a6d8288 | ||
|
|
796d083823 | ||
|
|
817f6e3436 | ||
|
|
3e32aa6313 | ||
|
|
255a0be7f2 | ||
|
|
1c422f5436 | ||
|
|
46894e04fe | ||
|
|
1ea0fc04bf | ||
|
|
7a9c31ca27 | ||
|
|
7b24ea86f5 | ||
|
|
b789a4af92 | ||
|
|
c6f93aaa44 | ||
|
|
3fe8c80696 | ||
|
|
3860c9583b | ||
|
|
82bebc0dd8 | ||
|
|
2c68fe898a | ||
|
|
e8259fbf91 | ||
|
|
84b0d15a0c | ||
|
|
d932d26830 | ||
|
|
b62c62c6e0 | ||
|
|
10b421d682 | ||
|
|
1899ebf226 | ||
|
|
02f151307d | ||
|
|
c0adc172c1 | ||
|
|
b90847a0f1 | ||
|
|
e25d288fae | ||
|
|
0500d3e688 | ||
|
|
45d6cc53ca | ||
|
|
d9881a50c1 | ||
|
|
6df829cf90 | ||
|
|
5dc15bb2a9 | ||
|
|
08f440f7c8 | ||
|
|
826973f42a | ||
|
|
e040f6d93b | ||
|
|
a38039f4aa | ||
|
|
5af9b7c0ff | ||
|
|
10ebbd6b6f | ||
|
|
0772a91c26 | ||
|
|
3d827c0033 | ||
|
|
f388a0c5b1 | ||
|
|
324bd1166f | ||
|
|
64767e9ca0 | ||
|
|
a4f548b847 | ||
|
|
82efb8c251 | ||
|
|
d7995d8cc5 |
@@ -15,7 +15,7 @@ export default {
|
|||||||
* 新增分类
|
* 新增分类
|
||||||
*/
|
*/
|
||||||
createCategory(data) {
|
createCategory(data) {
|
||||||
return api.request('/products/categories', 'POST', data)
|
return api.request('/products/categories', 'POST', {}, data)
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -33,12 +33,19 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取商品列表
|
* 获取商品列表(只显示上架)
|
||||||
*/
|
*/
|
||||||
getProducts(params) {
|
getProducts(params) {
|
||||||
return api.request('/products', 'GET', params)
|
return api.request('/products', 'GET', params)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有商品(包括下架,用于管理)
|
||||||
|
*/
|
||||||
|
getAllProducts(params) {
|
||||||
|
return api.request('/products/all', 'GET', params)
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取商品详情
|
* 获取商品详情
|
||||||
*/
|
*/
|
||||||
@@ -50,14 +57,14 @@ export default {
|
|||||||
* 新增商品
|
* 新增商品
|
||||||
*/
|
*/
|
||||||
createProduct(data) {
|
createProduct(data) {
|
||||||
return api.request('/products', 'POST', data)
|
return api.request('/products', 'POST', {}, data)
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改商品
|
* 修改商品
|
||||||
*/
|
*/
|
||||||
updateProduct(id, data) {
|
updateProduct(id, data) {
|
||||||
return api.request(`/products/${id}`, 'PUT', data)
|
return api.request(`/products/${id}`, 'PUT', {}, data)
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -127,7 +127,7 @@
|
|||||||
"text": "首页"
|
"text": "首页"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pagePath": "pages/product/list",
|
"pagePath": "pages/product/manage",
|
||||||
"text": "商品"
|
"text": "商品"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -74,10 +74,6 @@
|
|||||||
<view class="menu-icon-box pink"><text class="icon-text">类</text></view>
|
<view class="menu-icon-box pink"><text class="icon-text">类</text></view>
|
||||||
<text class="menu-text">种类管理</text>
|
<text class="menu-text">种类管理</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="menu-item" @click="goStock()">
|
|
||||||
<view class="menu-icon-box cyan"><text class="icon-text">库</text></view>
|
|
||||||
<text class="menu-text">库存管理</text>
|
|
||||||
</view>
|
|
||||||
<view class="menu-item" @click="goTo('/pages/stock/in')">
|
<view class="menu-item" @click="goTo('/pages/stock/in')">
|
||||||
<view class="menu-icon-box orange"><text class="icon-text">入</text></view>
|
<view class="menu-icon-box orange"><text class="icon-text">入</text></view>
|
||||||
<text class="menu-text">入库</text>
|
<text class="menu-text">入库</text>
|
||||||
@@ -145,14 +141,16 @@ export default {
|
|||||||
else this.greeting = '晚上好'
|
else this.greeting = '晚上好'
|
||||||
},
|
},
|
||||||
goTo(url) {
|
goTo(url) {
|
||||||
|
// tabBar 页面需要用 switchTab
|
||||||
|
if (url.startsWith('/pages/product/manage') || url.startsWith('/pages/order/list') || url.startsWith('/pages/index/index')) {
|
||||||
|
uni.switchTab({ url })
|
||||||
|
} else {
|
||||||
uni.navigateTo({ url })
|
uni.navigateTo({ url })
|
||||||
|
}
|
||||||
},
|
},
|
||||||
goToTab(url) {
|
goToTab(url) {
|
||||||
uni.switchTab({ url })
|
uni.switchTab({ url })
|
||||||
},
|
},
|
||||||
goStock() {
|
|
||||||
uni.navigateTo({ url: '/pages/stock/list' })
|
|
||||||
},
|
|
||||||
logout() {
|
logout() {
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: '退出登录',
|
title: '退出登录',
|
||||||
|
|||||||
@@ -46,18 +46,24 @@
|
|||||||
|
|
||||||
<view v-for="(item, index) in orderItems" :key="index" class="order-item">
|
<view v-for="(item, index) in orderItems" :key="index" class="order-item">
|
||||||
<view class="item-info">
|
<view class="item-info">
|
||||||
<text class="item-name">{{ item.productName }}</text>
|
<text class="item-name-box">{{ item.productName }}</text>
|
||||||
<text class="item-spec">{{ item.spec || '-' }}</text>
|
<text class="item-spec">{{ item.spec ? ' ' + item.spec : '' }}</text>
|
||||||
|
<text class="item-dims" v-if="item.length && item.width">{{ item.length }}x{{ item.width }}</text>
|
||||||
|
<text class="item-stock">库存: {{ stocks[item.productId] || 0 }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="item-edit">
|
<view class="item-edit">
|
||||||
<view class="quantity-edit">
|
<view class="quantity-edit">
|
||||||
<text class="qty-label">数量</text>
|
<text class="qty-label">数量</text>
|
||||||
|
<view class="qty-wrapper">
|
||||||
|
<text class="qty-btn" @click="qtyMinus(index)">-</text>
|
||||||
<input
|
<input
|
||||||
class="qty-input"
|
class="qty-input"
|
||||||
type="number"
|
type="number"
|
||||||
v-model="item.quantity"
|
v-model="item.quantity"
|
||||||
@change="calcAmount"
|
@change="onQuantityChange(index)"
|
||||||
/>
|
/>
|
||||||
|
<text class="qty-btn" @click="qtyPlus(index)">+</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="price-edit">
|
<view class="price-edit">
|
||||||
<text class="qty-label">单价</text>
|
<text class="qty-label">单价</text>
|
||||||
@@ -174,6 +180,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import orderApi from '@/api/order'
|
import orderApi from '@/api/order'
|
||||||
|
import stockApi from '@/api/stock'
|
||||||
import productApi from '@/api/product'
|
import productApi from '@/api/product'
|
||||||
import customerApi from '@/api/customer'
|
import customerApi from '@/api/customer'
|
||||||
|
|
||||||
@@ -197,6 +204,7 @@ export default {
|
|||||||
orderItems: [],
|
orderItems: [],
|
||||||
productList: [],
|
productList: [],
|
||||||
searchKeyword: '',
|
searchKeyword: '',
|
||||||
|
stocks: {}, // 商品库存
|
||||||
|
|
||||||
// 金额相关
|
// 金额相关
|
||||||
discountRate: 100, // 折扣率(保留逻辑,默认100%不打折)
|
discountRate: 100, // 折扣率(保留逻辑,默认100%不打折)
|
||||||
@@ -218,6 +226,7 @@ export default {
|
|||||||
onLoad(options) {
|
onLoad(options) {
|
||||||
this.loadCustomersByType()
|
this.loadCustomersByType()
|
||||||
this.loadProducts()
|
this.loadProducts()
|
||||||
|
this.loadStocks()
|
||||||
if (options.orderId) {
|
if (options.orderId) {
|
||||||
this.editingOrderId = options.orderId
|
this.editingOrderId = options.orderId
|
||||||
// 编辑模式
|
// 编辑模式
|
||||||
@@ -249,7 +258,10 @@ export default {
|
|||||||
spec: item.productSpec,
|
spec: item.productSpec,
|
||||||
unit: item.unit,
|
unit: item.unit,
|
||||||
price: item.price,
|
price: item.price,
|
||||||
quantity: item.quantity
|
quantity: item.quantity,
|
||||||
|
length: item.length || '',
|
||||||
|
width: item.width || '',
|
||||||
|
area: item.area || ''
|
||||||
}))
|
}))
|
||||||
|
|
||||||
this.discountRate = order.discountRate
|
this.discountRate = order.discountRate
|
||||||
@@ -295,6 +307,20 @@ export default {
|
|||||||
console.error(e)
|
console.error(e)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async loadStocks() {
|
||||||
|
try {
|
||||||
|
const res = await stockApi.getStockList({ page: 1, pageSize: 500 })
|
||||||
|
const stockMap = {}
|
||||||
|
if (res.records) {
|
||||||
|
res.records.forEach(s => {
|
||||||
|
stockMap[s.productId] = s.quantity || 0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.stocks = stockMap
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
},
|
||||||
selectCustomer(e) {
|
selectCustomer(e) {
|
||||||
this.selectedCustomer = this.filteredCustomers[e.detail.value]
|
this.selectedCustomer = this.filteredCustomers[e.detail.value]
|
||||||
},
|
},
|
||||||
@@ -335,6 +361,9 @@ export default {
|
|||||||
spec: product.spec,
|
spec: product.spec,
|
||||||
unit: product.unit,
|
unit: product.unit,
|
||||||
price: product.price,
|
price: product.price,
|
||||||
|
length: product.length || '',
|
||||||
|
width: product.width || '',
|
||||||
|
area: product.area || '',
|
||||||
quantity: 1
|
quantity: 1
|
||||||
})
|
})
|
||||||
this.calcAmount()
|
this.calcAmount()
|
||||||
@@ -343,6 +372,38 @@ export default {
|
|||||||
this.orderItems.splice(index, 1)
|
this.orderItems.splice(index, 1)
|
||||||
this.calcAmount()
|
this.calcAmount()
|
||||||
},
|
},
|
||||||
|
qtyMinus(index) {
|
||||||
|
const item = this.orderItems[index]
|
||||||
|
const stock = this.stocks[item.productId] || 0
|
||||||
|
if (item.quantity > 1) {
|
||||||
|
item.quantity--
|
||||||
|
this.calcAmount()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
qtyPlus(index) {
|
||||||
|
const item = this.orderItems[index]
|
||||||
|
const stock = this.stocks[item.productId] || 0
|
||||||
|
if (item.quantity < stock) {
|
||||||
|
item.quantity++
|
||||||
|
this.calcAmount()
|
||||||
|
} else {
|
||||||
|
uni.showToast({ title: '库存不足', icon: 'none' })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onQuantityChange(index) {
|
||||||
|
const item = this.orderItems[index]
|
||||||
|
const stock = this.stocks[item.productId] || 0
|
||||||
|
let qty = parseInt(item.quantity)
|
||||||
|
if (isNaN(qty) || qty < 1) {
|
||||||
|
qty = 1
|
||||||
|
}
|
||||||
|
if (qty > stock) {
|
||||||
|
qty = stock
|
||||||
|
uni.showToast({ title: '库存不足,已调整为最大库存', icon: 'none' })
|
||||||
|
}
|
||||||
|
item.quantity = qty
|
||||||
|
this.calcAmount()
|
||||||
|
},
|
||||||
// 核心金额计算逻辑
|
// 核心金额计算逻辑
|
||||||
calcAmount() {
|
calcAmount() {
|
||||||
// 1. 计算原价 = Σ(单价 × 数量)
|
// 1. 计算原价 = Σ(单价 × 数量)
|
||||||
@@ -390,7 +451,10 @@ export default {
|
|||||||
items: this.orderItems.map(item => ({
|
items: this.orderItems.map(item => ({
|
||||||
productId: item.productId,
|
productId: item.productId,
|
||||||
quantity: item.quantity,
|
quantity: item.quantity,
|
||||||
price: item.price
|
price: item.price,
|
||||||
|
length: item.length || null,
|
||||||
|
width: item.width || null,
|
||||||
|
area: item.area || null
|
||||||
})),
|
})),
|
||||||
discountRate: 100, // 保留折扣率逻辑,默认100%
|
discountRate: 100, // 保留折扣率逻辑,默认100%
|
||||||
discountMoney: parseFloat(this.discountMoney) || 0,
|
discountMoney: parseFloat(this.discountMoney) || 0,
|
||||||
@@ -514,13 +578,19 @@ export default {
|
|||||||
|
|
||||||
.item-info {
|
.item-info {
|
||||||
margin-bottom: 16rpx;
|
margin-bottom: 16rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-name {
|
.item-name-box {
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
display: block;
|
|
||||||
color: #333;
|
color: #333;
|
||||||
|
width: 170rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-spec {
|
.item-spec {
|
||||||
@@ -528,6 +598,21 @@ export default {
|
|||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item-dims {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #667eea;
|
||||||
|
background: #f0f0ff;
|
||||||
|
padding: 2rpx 8rpx;
|
||||||
|
border-radius: 4rpx;
|
||||||
|
margin-left: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-stock {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #999;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.item-edit {
|
.item-edit {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -536,23 +621,69 @@ export default {
|
|||||||
.quantity-edit, .price-edit {
|
.quantity-edit, .price-edit {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-right: 20rpx;
|
margin-right: 24rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.qty-label {
|
.qty-label {
|
||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
color: #666;
|
color: #666;
|
||||||
margin-right: 8rpx;
|
margin-right: 8rpx;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.qty-input, .price-input {
|
.qty-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background: #f5f5f5;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qty-btn {
|
||||||
|
width: 48rpx;
|
||||||
|
height: 48rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: #667eea;
|
||||||
|
background: #fff;
|
||||||
|
border: 1rpx solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qty-btn:first-child {
|
||||||
|
border-radius: 8rpx 0 0 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qty-btn:last-child {
|
||||||
|
border-radius: 0 8rpx 8rpx 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qty-input {
|
||||||
width: 100rpx;
|
width: 100rpx;
|
||||||
height: 56rpx;
|
height: 48rpx;
|
||||||
|
background: #fff;
|
||||||
|
border: 1rpx solid #ddd;
|
||||||
|
border-left: none;
|
||||||
|
border-right: none;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.price-input {
|
||||||
|
width: 120rpx;
|
||||||
|
height: 48rpx;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border: 1rpx solid #ddd;
|
border: 1rpx solid #ddd;
|
||||||
border-radius: 8rpx;
|
border-radius: 8rpx;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
|
margin-left: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-info {
|
||||||
|
font-size: 20rpx;
|
||||||
|
color: #999;
|
||||||
|
margin-left: 12rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-subtotal {
|
.item-subtotal {
|
||||||
|
|||||||
@@ -36,7 +36,8 @@
|
|||||||
<view class="section-title">商品明细</view>
|
<view class="section-title">商品明细</view>
|
||||||
<view class="items-list">
|
<view class="items-list">
|
||||||
<view class="item-row header">
|
<view class="item-row header">
|
||||||
<text class="item-name">商品名称</text>
|
<text class="item-info">商品信息</text>
|
||||||
|
<text class="item-area">总面积(m²)</text>
|
||||||
<text class="item-qty">数量</text>
|
<text class="item-qty">数量</text>
|
||||||
<text class="item-price">单价</text>
|
<text class="item-price">单价</text>
|
||||||
<text class="item-subtotal">小计</text>
|
<text class="item-subtotal">小计</text>
|
||||||
@@ -46,10 +47,11 @@
|
|||||||
:key="index"
|
:key="index"
|
||||||
class="item-row"
|
class="item-row"
|
||||||
>
|
>
|
||||||
<text class="item-name">{{ item.productName }}</text>
|
<text class="item-info"><text class="item-name-text">{{ item.productName }}</text><text class="item-spec-text">{{ item.productSpec ? ' ' + item.productSpec : '' }}</text><text class="item-dims-text">{{ item.length || '-' }}x{{ item.width || '-' }}</text></text>
|
||||||
|
<text class="item-area">{{ calcArea(item) }}</text>
|
||||||
<text class="item-qty">{{ item.quantity }}</text>
|
<text class="item-qty">{{ item.quantity }}</text>
|
||||||
<text class="item-price">¥{{ item.price }}</text>
|
<text class="item-price">¥{{ item.price }}</text>
|
||||||
<text class="item-subtotal">¥{{ (item.price * item.quantity).toFixed(2) }}</text>
|
<text class="item-subtotal">¥{{ (item.price * item.quantity).toFixed(0) }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -170,6 +172,12 @@ export default {
|
|||||||
if (!time) return ''
|
if (!time) return ''
|
||||||
return time.substring(0, 16).replace('T', ' ')
|
return time.substring(0, 16).replace('T', ' ')
|
||||||
},
|
},
|
||||||
|
calcArea(item) {
|
||||||
|
if (item.length && item.width && item.quantity) {
|
||||||
|
return (item.length * item.width * item.quantity / 1000000).toFixed(4)
|
||||||
|
}
|
||||||
|
return '-'
|
||||||
|
},
|
||||||
getPaymentMethod(method) {
|
getPaymentMethod(method) {
|
||||||
const map = {
|
const map = {
|
||||||
'cash': '现金',
|
'cash': '现金',
|
||||||
@@ -345,7 +353,8 @@ export default {
|
|||||||
display: flex;
|
display: flex;
|
||||||
padding: 20rpx 0;
|
padding: 20rpx 0;
|
||||||
border-bottom: 1rpx solid #f8f8f8;
|
border-bottom: 1rpx solid #f8f8f8;
|
||||||
font-size: 26rpx;
|
font-size: 24rpx;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-row.header {
|
.item-row.header {
|
||||||
@@ -355,12 +364,36 @@ export default {
|
|||||||
padding: 16rpx 0;
|
padding: 16rpx 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-name {
|
.item-info {
|
||||||
flex: 2;
|
flex: 3;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #333;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-name-text {
|
||||||
|
color: #333;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-spec-text {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-dims-text {
|
||||||
|
color: #666;
|
||||||
|
margin-left: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-area {
|
||||||
|
flex: 1.5;
|
||||||
|
text-align: center;
|
||||||
|
color: #667eea;
|
||||||
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-qty {
|
.item-qty {
|
||||||
flex: 1;
|
flex: 0.8;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -158,14 +158,9 @@ export default {
|
|||||||
|
|
||||||
const list = res.records || []
|
const list = res.records || []
|
||||||
|
|
||||||
// 加载每个订单的明细
|
// 直接使用订单中的items,不再单独请求
|
||||||
for (const order of list) {
|
for (const order of list) {
|
||||||
try {
|
this.$set(this.orderItemsMap, order.orderId, order.items || [])
|
||||||
const detail = await orderApi.getOrderDetail(order.orderId)
|
|
||||||
this.$set(this.orderItemsMap, order.orderId, detail.items || [])
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.page === 1) {
|
if (this.page === 1) {
|
||||||
|
|||||||
@@ -219,15 +219,21 @@ export default {
|
|||||||
this.returnQty++
|
this.returnQty++
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
confirmReturn() {
|
async confirmReturn() {
|
||||||
if (this.returnQty <= 0 || this.returnQty > this.currentItem.returnableQty) {
|
if (this.returnQty <= 0 || this.returnQty > this.currentItem.returnableQty) {
|
||||||
uni.showToast({ title: '退货数量无效', icon: 'none' })
|
uni.showToast({ title: '退货数量无效', icon: 'none' })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await orderApi.refundOrder(this.currentItem.orderId)
|
||||||
uni.showToast({ title: '退货成功', icon: 'success' })
|
uni.showToast({ title: '退货成功', icon: 'success' })
|
||||||
// TODO: 调用后端创建退货订单
|
|
||||||
this.closePopup()
|
this.closePopup()
|
||||||
this.loadReturnableGoods()
|
this.loadReturnableGoods()
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
uni.showToast({ title: e.message || '退货失败', icon: 'none' })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -159,8 +159,9 @@ export default {
|
|||||||
this.loadProducts()
|
this.loadProducts()
|
||||||
},
|
},
|
||||||
viewDetail(item) {
|
viewDetail(item) {
|
||||||
|
// 跳转到商品管理页面进行编辑
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: `/pages/product/detail?productId=${item.productId}`
|
url: `/pages/product/manage?productId=${item.productId}`
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
getStock(productId) {
|
getStock(productId) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="page">
|
<view class="page">
|
||||||
<!-- 搜索栏 -->
|
<!-- 搜索栏 -->
|
||||||
|
<view class="search-section">
|
||||||
<view class="search-bar">
|
<view class="search-bar">
|
||||||
<input
|
<input
|
||||||
class="search-input"
|
class="search-input"
|
||||||
@@ -8,31 +9,53 @@
|
|||||||
placeholder="搜索商品名称"
|
placeholder="搜索商品名称"
|
||||||
@confirm="search"
|
@confirm="search"
|
||||||
/>
|
/>
|
||||||
<button class="search-btn" @click="search">搜索</button>
|
|
||||||
<button class="add-btn" @click="addProduct">+</button>
|
<button class="add-btn" @click="addProduct">+</button>
|
||||||
</view>
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 商品列表 -->
|
<!-- 分类侧栏 + 商品列表 -->
|
||||||
|
<view class="content-wrapper">
|
||||||
|
<!-- 左侧分类 -->
|
||||||
|
<scroll-view scroll-y class="category-sidebar">
|
||||||
|
<view class="category-item" :class="{ active: !categoryId }" @click="selectCategory('')">
|
||||||
|
全部
|
||||||
|
</view>
|
||||||
|
<view v-for="cat in categories" :key="cat.categoryId" class="category-item" :class="{ active: categoryId === cat.categoryId }" @click="selectCategory(cat.categoryId)">
|
||||||
|
{{ cat.name }}
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<!-- 右侧商品列表 -->
|
||||||
|
<scroll-view scroll-y class="product-scroll">
|
||||||
<view class="product-list">
|
<view class="product-list">
|
||||||
<view
|
<view
|
||||||
v-for="item in products"
|
v-for="item in productList"
|
||||||
:key="item.productId"
|
:key="item.productId"
|
||||||
class="product-item"
|
class="product-item"
|
||||||
>
|
>
|
||||||
<view class="product-info" @click="editProduct(item)">
|
<view class="product-info">
|
||||||
|
<view class="product-header">
|
||||||
<text class="product-name">{{ item.name }}</text>
|
<text class="product-name">{{ item.name }}</text>
|
||||||
|
<text class="product-category" v-if="item.categoryName">{{ item.categoryName }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="product-row">
|
||||||
<text class="product-spec">{{ item.spec || '-' }}</text>
|
<text class="product-spec">{{ item.spec || '-' }}</text>
|
||||||
<view class="product-price">
|
<text class="product-unit">/{{ item.unit }}</text>
|
||||||
<text class="price">¥{{ item.price }}</text>
|
<text class="product-price-text">¥{{ item.price }}</text>
|
||||||
<text class="unit">/{{ item.unit }}</text>
|
</view>
|
||||||
|
<view class="product-spec-row" v-if="item.length && item.width">
|
||||||
|
<text class="spec-text">规格:{{ item.length }} x {{ item.width }} = {{ item.area }} m²</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="product-status">
|
<view class="product-status">
|
||||||
<text :class="['status', item.status === 1 ? 'on' : 'off']">
|
<text :class="['status', item.status === 1 ? 'on' : 'off']">
|
||||||
{{ item.status === 1 ? '上架' : '下架' }}
|
{{ item.status === 1 ? '已上架' : '已下架' }}
|
||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="product-actions">
|
<view class="product-actions">
|
||||||
|
<view class="action-btn edit" @click="editProduct(item)" v-if="item.status === 1">
|
||||||
|
编辑
|
||||||
|
</view>
|
||||||
<view class="action-btn" @click="toggleStatus(item)">
|
<view class="action-btn" @click="toggleStatus(item)">
|
||||||
{{ item.status === 1 ? '下架' : '上架' }}
|
{{ item.status === 1 ? '下架' : '上架' }}
|
||||||
</view>
|
</view>
|
||||||
@@ -43,10 +66,12 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 空状态 -->
|
<!-- 空状态 -->
|
||||||
<view v-if="products.length === 0" class="empty">
|
<view v-if="productList.length === 0" class="empty">
|
||||||
<text>暂无商品</text>
|
<text>暂无商品</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 商品表单弹窗 -->
|
<!-- 商品表单弹窗 -->
|
||||||
<view class="modal" v-if="showModal">
|
<view class="modal" v-if="showModal">
|
||||||
@@ -58,32 +83,48 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="modal-body">
|
<view class="modal-body">
|
||||||
<view class="form-item">
|
<view class="form-item">
|
||||||
<text class="label">商品名称*</text>
|
<text class="label"><text class="required">*</text>分类</text>
|
||||||
<input class="input" v-model="form.name" placeholder="请输入商品名称" />
|
|
||||||
</view>
|
|
||||||
<view class="form-item">
|
|
||||||
<text class="label">规格</text>
|
|
||||||
<input class="input" v-model="form.spec" placeholder="请输入规格" />
|
|
||||||
</view>
|
|
||||||
<view class="form-item">
|
|
||||||
<text class="label">单位*</text>
|
|
||||||
<input class="input" v-model="form.unit" placeholder="如:个、箱、米" />
|
|
||||||
</view>
|
|
||||||
<view class="form-item">
|
|
||||||
<text class="label">价格*</text>
|
|
||||||
<input class="input" type="digit" v-model="form.price" placeholder="请输入价格" />
|
|
||||||
</view>
|
|
||||||
<view class="form-item">
|
|
||||||
<text class="label">分类</text>
|
|
||||||
<picker :range="categories" range-key="name" @change="onCategoryChange">
|
<picker :range="categories" range-key="name" @change="onCategoryChange">
|
||||||
<view class="picker">
|
<view class="picker">
|
||||||
{{ form.categoryId ? getCategoryName(form.categoryId) : '请选择分类' }}
|
{{ form.categoryId ? getCategoryName(form.categoryId) : '请选择分类' }}
|
||||||
</view>
|
</view>
|
||||||
</picker>
|
</picker>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="form-item">
|
||||||
|
<text class="label"><text class="required">*</text>商品名称</text>
|
||||||
|
<input class="input" v-model="form.name" placeholder="请输入商品名称" />
|
||||||
|
</view>
|
||||||
|
<view class="form-row size-row">
|
||||||
|
<view class="form-item half">
|
||||||
|
<text class="label">长度(mm)</text>
|
||||||
|
<input class="input" type="digit" v-model="form.length" maxlength="5" />
|
||||||
|
</view>
|
||||||
|
<view class="form-item half">
|
||||||
|
<text class="label">宽度(mm)</text>
|
||||||
|
<input class="input" type="digit" v-model="form.width" maxlength="5" />
|
||||||
|
</view>
|
||||||
|
<view class="form-item half">
|
||||||
|
<text class="label">面积(m²)</text>
|
||||||
|
<input class="input" type="digit" v-model="form.area" disabled />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="form-row">
|
||||||
|
<view class="form-item half">
|
||||||
|
<text class="label">颜色</text>
|
||||||
|
<input class="input" v-model="form.spec" />
|
||||||
|
</view>
|
||||||
|
<view class="form-item half">
|
||||||
|
<text class="label"><text class="required">*</text>单位</text>
|
||||||
|
<input class="input" v-model="form.unit" placeholder="如:个、箱、米" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="form-item">
|
||||||
|
<text class="label"><text class="required">*</text>价格</text>
|
||||||
|
<input class="input" type="digit" v-model="form.price" placeholder="请输入价格" />
|
||||||
|
</view>
|
||||||
<view class="form-item">
|
<view class="form-item">
|
||||||
<text class="label">备注</text>
|
<text class="label">备注</text>
|
||||||
<textarea class="textarea" v-model="form.remark" placeholder="请输入备注" />
|
<textarea class="textarea" v-model="form.remark" />
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="modal-footer">
|
<view class="modal-footer">
|
||||||
@@ -103,30 +144,55 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
keyword: '',
|
keyword: '',
|
||||||
products: [],
|
categoryId: '',
|
||||||
|
productList: [],
|
||||||
categories: [],
|
categories: [],
|
||||||
showModal: false,
|
showModal: false,
|
||||||
isEdit: false,
|
isEdit: false,
|
||||||
form: {
|
form: {
|
||||||
productId: '',
|
productId: '',
|
||||||
|
categoryId: '',
|
||||||
name: '',
|
name: '',
|
||||||
spec: '',
|
spec: '',
|
||||||
unit: '',
|
unit: '',
|
||||||
price: '',
|
price: '',
|
||||||
categoryId: '',
|
length: '',
|
||||||
|
width: '',
|
||||||
|
area: '',
|
||||||
remark: '',
|
remark: '',
|
||||||
status: 1
|
status: 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onLoad() {
|
onLoad(options) {
|
||||||
if (!canManageProduct()) {
|
// 移除权限检查,允许所有用户访问
|
||||||
uni.showToast({ title: '无权限', icon: 'none' })
|
|
||||||
uni.navigateBack()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.loadCategories()
|
this.loadCategories()
|
||||||
this.loadProducts()
|
this.loadProducts()
|
||||||
|
// 如果传入了 productId,则打开编辑弹窗
|
||||||
|
if (options.productId) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const item = this.productList.find(p => p.productId === options.productId)
|
||||||
|
if (item) {
|
||||||
|
this.editProduct(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
computedArea() {
|
||||||
|
const l = parseFloat(this.form.length)
|
||||||
|
const w = parseFloat(this.form.width)
|
||||||
|
// 长度(mm) × 宽度(mm) ÷ 1000000 = 面积(m²)
|
||||||
|
if (!isNaN(l) && !isNaN(w) && l > 0 && w > 0) {
|
||||||
|
return (l * w / 1000000).toFixed(4)
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
computedArea(val) {
|
||||||
|
this.form.area = val
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async loadCategories() {
|
async loadCategories() {
|
||||||
@@ -139,16 +205,21 @@ export default {
|
|||||||
},
|
},
|
||||||
async loadProducts() {
|
async loadProducts() {
|
||||||
try {
|
try {
|
||||||
const res = await productApi.getProducts({
|
const res = await productApi.getAllProducts({
|
||||||
keyword: this.keyword,
|
keyword: this.keyword,
|
||||||
|
categoryId: this.categoryId,
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 100
|
pageSize: 100
|
||||||
})
|
})
|
||||||
this.products = res.records || []
|
this.productList = res.records || []
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
selectCategory(id) {
|
||||||
|
this.categoryId = id
|
||||||
|
this.loadProducts()
|
||||||
|
},
|
||||||
search() {
|
search() {
|
||||||
this.loadProducts()
|
this.loadProducts()
|
||||||
},
|
},
|
||||||
@@ -161,6 +232,9 @@ export default {
|
|||||||
unit: '',
|
unit: '',
|
||||||
price: '',
|
price: '',
|
||||||
categoryId: '',
|
categoryId: '',
|
||||||
|
length: '',
|
||||||
|
width: '',
|
||||||
|
area: '',
|
||||||
remark: '',
|
remark: '',
|
||||||
status: 1
|
status: 1
|
||||||
}
|
}
|
||||||
@@ -183,6 +257,10 @@ export default {
|
|||||||
return cat ? cat.name : ''
|
return cat ? cat.name : ''
|
||||||
},
|
},
|
||||||
async saveProduct() {
|
async saveProduct() {
|
||||||
|
if (!this.form.categoryId) {
|
||||||
|
uni.showToast({ title: '请选择分类', icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
if (!this.form.name) {
|
if (!this.form.name) {
|
||||||
uni.showToast({ title: '请输入商品名称', icon: 'none' })
|
uni.showToast({ title: '请输入商品名称', icon: 'none' })
|
||||||
return
|
return
|
||||||
@@ -197,11 +275,12 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const formData = JSON.parse(JSON.stringify(this.form))
|
||||||
if (this.isEdit) {
|
if (this.isEdit) {
|
||||||
await productApi.updateProduct(this.form)
|
await productApi.updateProduct(formData.productId, formData)
|
||||||
uni.showToast({ title: '更新成功', icon: 'success' })
|
uni.showToast({ title: '更新成功', icon: 'success' })
|
||||||
} else {
|
} else {
|
||||||
await productApi.createProduct(this.form)
|
await productApi.createProduct(formData)
|
||||||
uni.showToast({ title: '创建成功', icon: 'success' })
|
uni.showToast({ title: '创建成功', icon: 'success' })
|
||||||
}
|
}
|
||||||
this.closeModal()
|
this.closeModal()
|
||||||
@@ -214,8 +293,7 @@ export default {
|
|||||||
async toggleStatus(item) {
|
async toggleStatus(item) {
|
||||||
const newStatus = item.status === 1 ? 0 : 1
|
const newStatus = item.status === 1 ? 0 : 1
|
||||||
try {
|
try {
|
||||||
await productApi.updateProduct({
|
await productApi.updateProduct(item.productId, {
|
||||||
productId: item.productId,
|
|
||||||
status: newStatus
|
status: newStatus
|
||||||
})
|
})
|
||||||
uni.showToast({ title: newStatus === 1 ? '已上架' : '已下架', icon: 'success' })
|
uni.showToast({ title: newStatus === 1 ? '已上架' : '已下架', icon: 'success' })
|
||||||
@@ -249,6 +327,81 @@ export default {
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
.page {
|
.page {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 搜索区域 */
|
||||||
|
.search-section {
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
padding: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background: rgba(255, 255, 255, 0.95);
|
||||||
|
border-radius: 50rpx;
|
||||||
|
padding: 0 20rpx;
|
||||||
|
height: 70rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-btn {
|
||||||
|
width: 60rpx;
|
||||||
|
height: 60rpx;
|
||||||
|
line-height: 60rpx;
|
||||||
|
background: #3cc51f;
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border-radius: 50%;
|
||||||
|
font-size: 36rpx;
|
||||||
|
margin-left: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 内容区域:侧栏+列表 */
|
||||||
|
.content-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 分类侧栏 */
|
||||||
|
.category-sidebar {
|
||||||
|
width: 160rpx;
|
||||||
|
background: #fff;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border-right: 1rpx solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-item {
|
||||||
|
padding: 28rpx 16rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #666;
|
||||||
|
text-align: center;
|
||||||
|
border-left: 6rpx solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-item.active {
|
||||||
|
background: #f8f9fa;
|
||||||
|
color: #667eea;
|
||||||
|
font-weight: bold;
|
||||||
|
border-left-color: #667eea;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 商品列表 */
|
||||||
|
.product-scroll {
|
||||||
|
flex: 1;
|
||||||
|
background: #f8f9fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-list {
|
||||||
padding: 20rpx;
|
padding: 20rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,13 +465,57 @@ export default {
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.product-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-category {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #667eea;
|
||||||
|
background: #f0f0ff;
|
||||||
|
padding: 4rpx 12rpx;
|
||||||
|
border-radius: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
.product-spec {
|
.product-spec {
|
||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
color: #999;
|
color: #999;
|
||||||
margin-top: 8rpx;
|
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.product-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-unit {
|
||||||
|
color: #999;
|
||||||
|
font-size: 24rpx;
|
||||||
|
margin-left: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-price-text {
|
||||||
|
color: #ff4d4f;
|
||||||
|
font-size: 24rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-left: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-spec-row {
|
||||||
|
margin-top: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spec-text {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #666;
|
||||||
|
background: #f5f5f5;
|
||||||
|
padding: 4rpx 12rpx;
|
||||||
|
border-radius: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
.product-price {
|
.product-price {
|
||||||
margin-top: 12rpx;
|
margin-top: 12rpx;
|
||||||
}
|
}
|
||||||
@@ -369,6 +566,11 @@ export default {
|
|||||||
margin-bottom: 10rpx;
|
margin-bottom: 10rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.action-btn.edit {
|
||||||
|
background: #f0f5ff;
|
||||||
|
color: #667eea;
|
||||||
|
}
|
||||||
|
|
||||||
.action-btn.delete {
|
.action-btn.delete {
|
||||||
background: #fff1f0;
|
background: #fff1f0;
|
||||||
color: #ff4d4f;
|
color: #ff4d4f;
|
||||||
@@ -434,6 +636,28 @@ export default {
|
|||||||
margin-bottom: 24rpx;
|
margin-bottom: 24rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row .half {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.size-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.size-row .half {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row.three .half {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 26rpx;
|
font-size: 26rpx;
|
||||||
@@ -441,13 +665,25 @@ export default {
|
|||||||
margin-bottom: 10rpx;
|
margin-bottom: 10rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.required {
|
||||||
|
color: #ff4d4f;
|
||||||
|
margin-right: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input[disabled] {
|
||||||
|
background: #f5f5f5;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
.input {
|
.input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 70rpx;
|
height: 70rpx;
|
||||||
padding: 0 20rpx;
|
padding: 0 20rpx;
|
||||||
background: #f5f5f5;
|
background: #fff;
|
||||||
|
border: 2rpx solid #e5e5e5;
|
||||||
border-radius: 8rpx;
|
border-radius: 8rpx;
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.picker {
|
.picker {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 分类 + 商品列表 -->
|
<!-- 分类侧栏 + 商品列表 -->
|
||||||
<view class="content-wrapper">
|
<view class="content-wrapper">
|
||||||
<!-- 左侧分类 -->
|
<!-- 左侧分类 -->
|
||||||
<scroll-view scroll-y class="category-sidebar">
|
<scroll-view scroll-y class="category-sidebar">
|
||||||
@@ -29,10 +29,17 @@
|
|||||||
<!-- 右侧商品列表 -->
|
<!-- 右侧商品列表 -->
|
||||||
<scroll-view scroll-y class="product-scroll">
|
<scroll-view scroll-y class="product-scroll">
|
||||||
<view class="product-list">
|
<view class="product-list">
|
||||||
<view v-for="item in productList" :key="item.productId" class="product-item" @click="selectProduct(item)">
|
<view v-for="item in productList" :key="item.productId" class="product-item" :class="{ disabled: stocks[item.productId] === 0 }" @click="selectProduct(item)">
|
||||||
<view class="product-info">
|
<view class="product-info">
|
||||||
<text class="product-name">{{ item.name }}</text>
|
<text class="product-name">{{ item.name }}</text>
|
||||||
|
<view class="product-row">
|
||||||
<text class="product-spec">{{ item.spec || '-' }}</text>
|
<text class="product-spec">{{ item.spec || '-' }}</text>
|
||||||
|
<text class="product-size" v-if="item.length && item.width">{{ item.length }} x {{ item.width }} = {{ item.area }} m²</text>
|
||||||
|
</view>
|
||||||
|
<view class="product-stock">
|
||||||
|
<text class="stock-label">库存:</text>
|
||||||
|
<text class="stock-value" :class="{ 'stock-zero': stocks[item.productId] === 0 }">{{ stocks[item.productId] || 0 }}</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="product-price">
|
<view class="product-price">
|
||||||
<text class="price">¥{{ item.price }}</text>
|
<text class="price">¥{{ item.price }}</text>
|
||||||
@@ -47,11 +54,42 @@
|
|||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 商品详情/选择弹窗 -->
|
||||||
|
<view class="modal-mask" v-if="showModal" @click="closeModal">
|
||||||
|
<view class="modal-content" @click.stop>
|
||||||
|
<view class="modal-header">
|
||||||
|
<text class="modal-title">{{ selectedProduct.name }}</text>
|
||||||
|
<text class="modal-close" @click="closeModal">×</text>
|
||||||
|
</view>
|
||||||
|
<view class="modal-body">
|
||||||
|
<view class="size-row">
|
||||||
|
<view class="size-item">
|
||||||
|
<text class="size-label">长度(cm)</text>
|
||||||
|
<input class="size-input" type="digit" v-model="selectedProduct.length" placeholder="非必填" />
|
||||||
|
</view>
|
||||||
|
<view class="size-item">
|
||||||
|
<text class="size-label">宽度(cm)</text>
|
||||||
|
<input class="size-input" type="digit" v-model="selectedProduct.width" placeholder="非必填" />
|
||||||
|
</view>
|
||||||
|
<view class="size-item">
|
||||||
|
<text class="size-label">面积(m²)</text>
|
||||||
|
<input class="size-input" type="digit" v-model="selectedProduct.area" disabled />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="modal-footer">
|
||||||
|
<button class="cancel-btn" @click="closeModal">取消</button>
|
||||||
|
<button class="confirm-btn" @click="confirmProduct">确认</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import productApi from '@/api/product'
|
import productApi from '@/api/product'
|
||||||
|
import stockApi from '@/api/stock'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
@@ -60,9 +98,29 @@ export default {
|
|||||||
categoryId: '',
|
categoryId: '',
|
||||||
categories: [],
|
categories: [],
|
||||||
productList: [],
|
productList: [],
|
||||||
|
stocks: {}, // 商品库存
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 50,
|
pageSize: 50,
|
||||||
loading: false
|
loading: false,
|
||||||
|
showModal: false,
|
||||||
|
selectedProduct: {
|
||||||
|
productId: '',
|
||||||
|
name: '',
|
||||||
|
spec: '',
|
||||||
|
unit: '',
|
||||||
|
price: 0,
|
||||||
|
length: '',
|
||||||
|
width: '',
|
||||||
|
area: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
'selectedProduct.length'(val) {
|
||||||
|
this.calcArea()
|
||||||
|
},
|
||||||
|
'selectedProduct.width'(val) {
|
||||||
|
this.calcArea()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onLoad() {
|
onLoad() {
|
||||||
@@ -70,6 +128,23 @@ export default {
|
|||||||
this.getProducts()
|
this.getProducts()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
selectProduct(item) {
|
||||||
|
// 库存为0不可选中
|
||||||
|
if (this.stocks[item.productId] === 0) {
|
||||||
|
uni.showToast({ title: '库存不足', icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const pages = getCurrentPages()
|
||||||
|
const prevPage = pages[pages.length - 2]
|
||||||
|
prevPage.$vm.addProduct(item)
|
||||||
|
uni.navigateBack()
|
||||||
|
},
|
||||||
|
calcArea() {
|
||||||
|
const length = parseFloat(this.selectedProduct.length) || 0
|
||||||
|
const width = parseFloat(this.selectedProduct.width) || 0
|
||||||
|
// 长度(cm) * 宽度(cm) / 10000 = 面积(m²)
|
||||||
|
this.selectedProduct.area = length && width ? (length * width / 10000).toFixed(2) : ''
|
||||||
|
},
|
||||||
async loadCategories() {
|
async loadCategories() {
|
||||||
try {
|
try {
|
||||||
const categories = await productApi.getCategories()
|
const categories = await productApi.getCategories()
|
||||||
@@ -88,6 +163,16 @@ export default {
|
|||||||
pageSize: this.pageSize
|
pageSize: this.pageSize
|
||||||
})
|
})
|
||||||
this.productList = res.records || []
|
this.productList = res.records || []
|
||||||
|
|
||||||
|
// 获取每个商品的库存
|
||||||
|
const stockRes = await stockApi.getStockList({ page: 1, pageSize: 500 })
|
||||||
|
const stockMap = {}
|
||||||
|
if (stockRes.records) {
|
||||||
|
stockRes.records.forEach(s => {
|
||||||
|
stockMap[s.productId] = s.quantity || 0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.stocks = stockMap
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
uni.showToast({ title: '加载失败', icon: 'none' })
|
uni.showToast({ title: '加载失败', icon: 'none' })
|
||||||
} finally {
|
} finally {
|
||||||
@@ -103,10 +188,31 @@ export default {
|
|||||||
this.page = 1
|
this.page = 1
|
||||||
this.getProducts()
|
this.getProducts()
|
||||||
},
|
},
|
||||||
selectProduct(item) {
|
openProductDetail(item) {
|
||||||
|
this.selectedProduct = {
|
||||||
|
productId: item.productId,
|
||||||
|
name: item.name,
|
||||||
|
spec: item.spec,
|
||||||
|
unit: item.unit,
|
||||||
|
price: item.price,
|
||||||
|
length: '',
|
||||||
|
width: '',
|
||||||
|
area: ''
|
||||||
|
}
|
||||||
|
this.showModal = true
|
||||||
|
},
|
||||||
|
closeModal() {
|
||||||
|
this.showModal = false
|
||||||
|
},
|
||||||
|
confirmProduct() {
|
||||||
const pages = getCurrentPages()
|
const pages = getCurrentPages()
|
||||||
const prevPage = pages[pages.length - 2]
|
const prevPage = pages[pages.length - 2]
|
||||||
prevPage.$vm.addProduct(item)
|
prevPage.$vm.addProduct({
|
||||||
|
...this.selectedProduct,
|
||||||
|
length: this.selectedProduct.length,
|
||||||
|
width: this.selectedProduct.width,
|
||||||
|
area: this.selectedProduct.area
|
||||||
|
})
|
||||||
uni.navigateBack()
|
uni.navigateBack()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -144,26 +250,29 @@ export default {
|
|||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 内容区域:侧栏+列表 */
|
||||||
.content-wrapper {
|
.content-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: calc(100vh - 130rpx);
|
height: calc(100vh - 130rpx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 分类侧栏 */
|
||||||
.category-sidebar {
|
.category-sidebar {
|
||||||
width: 140rpx;
|
width: 160rpx;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
border-right: 1rpx solid #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
.category-item {
|
.category-sidebar .category-item {
|
||||||
padding: 28rpx 20rpx;
|
padding: 28rpx 16rpx;
|
||||||
font-size: 26rpx;
|
font-size: 26rpx;
|
||||||
color: #666;
|
color: #666;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-left: 6rpx solid transparent;
|
border-left: 6rpx solid transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.category-item.active {
|
.category-sidebar .category-item.active {
|
||||||
background: #f8f9fa;
|
background: #f8f9fa;
|
||||||
color: #667eea;
|
color: #667eea;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@@ -190,6 +299,11 @@ export default {
|
|||||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.06);
|
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.product-item.disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
.product-info {
|
.product-info {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
@@ -207,6 +321,42 @@ export default {
|
|||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.product-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-size {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #667eea;
|
||||||
|
background: #f0f0ff;
|
||||||
|
padding: 2rpx 8rpx;
|
||||||
|
border-radius: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-stock {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-label {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-value {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #333;
|
||||||
|
margin-left: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-value.stock-zero {
|
||||||
|
color: #ff4d4f;
|
||||||
|
}
|
||||||
|
|
||||||
.product-price {
|
.product-price {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
@@ -235,4 +385,97 @@ export default {
|
|||||||
color: #999;
|
color: #999;
|
||||||
margin-top: 20rpx;
|
margin-top: 20rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 弹窗 */
|
||||||
|
.modal-mask {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
width: 80%;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 30rpx;
|
||||||
|
border-bottom: 1rpx solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-title {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-close {
|
||||||
|
font-size: 48rpx;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
padding: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.size-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.size-item {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.size-label {
|
||||||
|
display: block;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #666;
|
||||||
|
margin-bottom: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.size-input {
|
||||||
|
width: 100%;
|
||||||
|
height: 70rpx;
|
||||||
|
background: #f5f5f5;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
padding: 0 20rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
display: flex;
|
||||||
|
gap: 20rpx;
|
||||||
|
padding: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-btn, .confirm-btn {
|
||||||
|
flex: 1;
|
||||||
|
height: 80rpx;
|
||||||
|
line-height: 80rpx;
|
||||||
|
border-radius: 40rpx;
|
||||||
|
font-size: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-btn {
|
||||||
|
background: #f5f5f5;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-btn {
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -50,7 +50,8 @@
|
|||||||
<view class="section-title">商品明细</view>
|
<view class="section-title">商品明细</view>
|
||||||
<view class="items-list">
|
<view class="items-list">
|
||||||
<view class="item-row header">
|
<view class="item-row header">
|
||||||
<text class="item-name">商品</text>
|
<text class="item-info">商品信息</text>
|
||||||
|
<text class="item-area">总面积(m²)</text>
|
||||||
<text class="item-qty">数量</text>
|
<text class="item-qty">数量</text>
|
||||||
<text class="item-price">单价</text>
|
<text class="item-price">单价</text>
|
||||||
<text class="item-subtotal">小计</text>
|
<text class="item-subtotal">小计</text>
|
||||||
@@ -60,10 +61,11 @@
|
|||||||
:key="index"
|
:key="index"
|
||||||
class="item-row"
|
class="item-row"
|
||||||
>
|
>
|
||||||
<text class="item-name">{{ item.productName }}</text>
|
<text class="item-info"><text class="item-name-text">{{ item.productName }}</text><text class="item-spec-text">{{ item.productSpec ? ' ' + item.productSpec : '' }}</text><text class="item-dims-text">{{ item.length || '-' }}x{{ item.width || '-' }}</text></text>
|
||||||
|
<text class="item-area">{{ calcArea(item) }}</text>
|
||||||
<text class="item-qty">{{ item.quantity }}</text>
|
<text class="item-qty">{{ item.quantity }}</text>
|
||||||
<text class="item-price">¥{{ item.price }}</text>
|
<text class="item-price">¥{{ item.price }}</text>
|
||||||
<text class="item-subtotal">¥{{ (item.price * item.quantity).toFixed(2) }}</text>
|
<text class="item-subtotal">¥{{ (item.price * item.quantity).toFixed(0) }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -153,6 +155,12 @@ export default {
|
|||||||
formatTime(time) {
|
formatTime(time) {
|
||||||
if (!time) return ''
|
if (!time) return ''
|
||||||
return time.substring(0, 16).replace('T', ' ')
|
return time.substring(0, 16).replace('T', ' ')
|
||||||
|
},
|
||||||
|
calcArea(item) {
|
||||||
|
if (item.length && item.width && item.quantity) {
|
||||||
|
return (item.length * item.width * item.quantity / 1000000).toFixed(4)
|
||||||
|
}
|
||||||
|
return '-'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -284,9 +292,10 @@ export default {
|
|||||||
|
|
||||||
.item-row {
|
.item-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 20rpx 0;
|
padding: 16rpx 0;
|
||||||
border-bottom: 1rpx solid #f8f8f8;
|
border-bottom: 1rpx solid #f8f8f8;
|
||||||
font-size: 26rpx;
|
font-size: 24rpx;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-row.header {
|
.item-row.header {
|
||||||
@@ -295,12 +304,36 @@ export default {
|
|||||||
color: #666;
|
color: #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-name {
|
.item-info {
|
||||||
flex: 2;
|
flex: 3;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #333;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-name-text {
|
||||||
|
color: #333;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-spec-text {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-dims-text {
|
||||||
|
color: #666;
|
||||||
|
margin-left: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-area {
|
||||||
|
flex: 1.5;
|
||||||
|
text-align: center;
|
||||||
|
color: #667eea;
|
||||||
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-qty {
|
.item-qty {
|
||||||
flex: 1;
|
flex: 0.8;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,8 +32,18 @@
|
|||||||
@click="openQuantityPopup(item)"
|
@click="openQuantityPopup(item)"
|
||||||
>
|
>
|
||||||
<view class="product-info">
|
<view class="product-info">
|
||||||
|
<view class="product-header">
|
||||||
<text class="product-name">{{ item.name }}</text>
|
<text class="product-name">{{ item.name }}</text>
|
||||||
|
<text class="product-category" v-if="item.categoryName">{{ item.categoryName }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="product-row">
|
||||||
<text class="product-spec">{{ item.spec || '-' }}</text>
|
<text class="product-spec">{{ item.spec || '-' }}</text>
|
||||||
|
<text class="product-unit">/{{ item.unit }}</text>
|
||||||
|
<text class="product-price-text">¥{{ item.price }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="product-spec-row" v-if="item.length && item.width">
|
||||||
|
<text class="spec-text">{{ item.length }} x {{ item.width }} = {{ item.area }} m²</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="product-add">
|
<view class="product-add">
|
||||||
<text class="add-icon">+</text>
|
<text class="add-icon">+</text>
|
||||||
@@ -320,11 +330,30 @@ export default {
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.product-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
.product-name {
|
.product-name {
|
||||||
display: block;
|
|
||||||
font-size: 30rpx;
|
font-size: 30rpx;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: #333;
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-category {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #667eea;
|
||||||
|
background: #f0f4ff;
|
||||||
|
padding: 4rpx 12rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
margin-left: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
margin-bottom: 8rpx;
|
margin-bottom: 8rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,6 +362,28 @@ export default {
|
|||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.product-unit {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-price-text {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #ff4d4f;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-left: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-spec-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spec-text {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
.product-add {
|
.product-add {
|
||||||
width: 60rpx;
|
width: 60rpx;
|
||||||
height: 60rpx;
|
height: 60rpx;
|
||||||
|
|||||||
Reference in New Issue
Block a user