合并merchant文件

This commit is contained in:
2026-03-20 15:43:33 +08:00
parent 29f588a2b2
commit 620ae742df
12 changed files with 3477 additions and 0 deletions

View File

@@ -57,14 +57,36 @@
<text class="label">当前库存</text>
<text class="value">{{ currentProduct?.total_stock }}</text>
</view>
<<<<<<< HEAD
<view class="form-item">
<text class="label">新库存</text>
<input class="input" type="number" v-model="newStock" placeholder="请输入新库存"/>
=======
<view class="adjust-type">
<view class="type-btn" :class="{ active: adjustType === 'set' }" @click="adjustType = 'set'">直接设为</view>
<view class="type-btn" :class="{ active: adjustType === 'add' }" @click="adjustType = 'add'">增加</view>
<view class="type-btn" :class="{ active: adjustType === 'sub' }" @click="adjustType = 'sub'">减少</view>
</view>
<view class="form-item">
<text class="label">{{ adjustType === 'set' ? '新库存数量' : '调整数值' }}</text>
<input class="input" type="number" v-model="newStock" :placeholder="adjustType === 'set' ? '请输入新库存' : '请输入数值'"/>
</view>
<view class="form-item">
<text class="label">备注 (可选)</text>
<input class="input" v-model="stockRemark" placeholder="如:入库、损耗等"/>
>>>>>>> local-backup-root-cyj
</view>
</view>
<view class="modal-footer">
<view class="modal-btn cancel" @click="closeStockModal">取消</view>
<<<<<<< HEAD
<view class="modal-btn confirm" @click="saveStock">保存</view>
=======
<view class="modal-btn confirm" @click="saveStock">确认提交</view>
>>>>>>> local-backup-root-cyj
</view>
</view>
</view>
@@ -96,7 +118,13 @@
stats: { totalProducts: 0, lowStock: 0, outOfStock: 0 },
showStockModal: false,
currentProduct: null as ProductType | null,
<<<<<<< HEAD
newStock: ''
=======
newStock: '',
adjustType: 'set', // 'set', 'add', 'sub'
stockRemark: ''
>>>>>>> local-backup-root-cyj
}
},
@@ -105,6 +133,10 @@
},
onShow() {
<<<<<<< HEAD
=======
this.page = 1
>>>>>>> local-backup-root-cyj
this.loadProducts()
this.loadStats()
},
@@ -113,11 +145,21 @@
async initMerchantId() {
try {
const session = supa.getSession()
<<<<<<< HEAD
this.merchantId = session?.user?.getString('id') || uni.getStorageSync('user_id') || ''
=======
if (session != null && session.user != null) {
this.merchantId = session.user.getString('id') || ''
}
if (!this.merchantId) {
this.merchantId = uni.getStorageSync('user_id') || ''
}
>>>>>>> local-backup-root-cyj
} catch (e) {}
},
async loadProducts() {
<<<<<<< HEAD
this.loading = true
try {
@@ -127,10 +169,34 @@
if (response.error != null || !response.data) {
this.products = []
=======
if (this.loading && this.page === 1) return
this.loading = true
try {
let query = supa.from('ml_products')
.select('id, name, main_image_url, total_stock, warning_stock')
.eq('merchant_id', this.merchantId)
.order('total_stock', { ascending: true })
.page(this.page)
.limit(this.limit)
if (this.currentFilter === 'low') {
query = query.lte('total_stock', 10) // 简化处理,实际应关联 warning_stock
} else if (this.currentFilter === 'out') {
query = query.eq('total_stock', 0)
}
const response = await query.execute()
if (response.error != null) {
console.error('加载商品失败:', response.error)
>>>>>>> local-backup-root-cyj
return
}
const rawData = response.data as any[]
<<<<<<< HEAD
let productsData: ProductType[] = []
for (let i = 0; i < rawData.length; i++) {
@@ -141,16 +207,38 @@
if (this.currentFilter === 'low' && stock > warning) continue
if (this.currentFilter === 'out' && stock > 0) continue
=======
if (!rawData) return
const productsData: ProductType[] = []
for (let i = 0; i < rawData.length; i++) {
const item = rawData[i] as UTSJSONObject
>>>>>>> local-backup-root-cyj
productsData.push({
id: item.getString('id') || '',
name: item.getString('name') || '',
main_image_url: item.getString('main_image_url') || '',
<<<<<<< HEAD
total_stock: stock,
warning_stock: warning
})
}
this.products = productsData
=======
total_stock: item.getNumber('total_stock') || 0,
warning_stock: item.getNumber('warning_stock') || 10
} as ProductType)
}
if (this.page === 1) {
this.products = productsData
} else {
this.products = [...this.products, ...productsData]
}
this.hasMore = rawData.length === this.limit
>>>>>>> local-backup-root-cyj
} catch (e) {
console.error('加载失败:', e)
} finally {
@@ -200,7 +288,13 @@
editStock(product: ProductType) {
this.currentProduct = product
<<<<<<< HEAD
this.newStock = String(product.total_stock)
=======
this.newStock = ''
this.adjustType = 'set'
this.stockRemark = ''
>>>>>>> local-backup-root-cyj
this.showStockModal = true
},
@@ -211,6 +305,7 @@
},
async saveStock() {
<<<<<<< HEAD
if (!this.newStock || isNaN(parseInt(this.newStock))) {
uni.showToast({ title: '请输入有效库存', icon: 'none' })
return
@@ -218,18 +313,63 @@
try {
const response = await supa.from('ml_products').update({ total_stock: parseInt(this.newStock), updated_at: new Date().toISOString() }).eq('id', this.currentProduct!.id).execute()
=======
const val = parseInt(this.newStock)
if (isNaN(val)) {
uni.showToast({ title: '请输入有效数值', icon: 'none' })
return
}
let finalStock = 0
if (this.adjustType === 'set') {
finalStock = val
} else if (this.adjustType === 'add') {
finalStock = (this.currentProduct?.total_stock || 0) + val
} else if (this.adjustType === 'sub') {
finalStock = (this.currentProduct?.total_stock || 0) - val
}
if (finalStock < 0) {
uni.showToast({ title: '最终库存不能小于0', icon: 'none' })
return
}
uni.showLoading({ title: '更新中...' })
try {
const response = await supa.from('ml_products')
.update({
total_stock: finalStock,
available_stock: finalStock,
updated_at: new Date().toISOString()
})
.eq('id', this.currentProduct!.id)
.execute()
>>>>>>> local-backup-root-cyj
if (response.error != null) {
uni.showToast({ title: '保存失败', icon: 'none' })
return
}
<<<<<<< HEAD
uni.showToast({ title: '保存成功', icon: 'success' })
this.closeStockModal()
this.loadProducts()
this.loadStats()
} catch (e) {
uni.showToast({ title: '保存失败', icon: 'none' })
=======
uni.showToast({ title: '更新成功', icon: 'success' })
this.closeStockModal()
this.page = 1
this.loadProducts()
this.loadStats()
} catch (e) {
uni.showToast({ title: '操作异常', icon: 'none' })
} finally {
uni.hideLoading()
>>>>>>> local-backup-root-cyj
}
},
@@ -273,10 +413,17 @@
.action-btn { padding: 12rpx 24rpx; font-size: 24rpx; background-color: #E3F2FD; color: #1976D2; border-radius: 24rpx; }
.modal-mask { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; z-index: 1000; }
.modal-content { width: 80%; background-color: #fff; border-radius: 16rpx; }
<<<<<<< HEAD
.modal-header { display: flex; justify-content: space-between; align-items: center; padding: 30rpx; border-bottom: 1rpx solid #f5f5f5; }
.modal-title { font-size: 32rpx; font-weight: bold; color: #333; }
.modal-close { font-size: 44rpx; color: #999; }
.modal-body { padding: 30rpx; }
=======
.modal-body { padding: 30rpx; }
.adjust-type { display: flex; justify-content: space-between; margin-bottom: 30rpx; }
.type-btn { flex: 1; height: 64rpx; line-height: 64rpx; text-align: center; font-size: 24rpx; background-color: #f5f5f5; color: #666; margin: 0 10rpx; border-radius: 32rpx; border: 1rpx solid #eee; }
.type-btn.active { background-color: #E3F2FD; color: #007AFF; border-color: #007AFF; }
>>>>>>> local-backup-root-cyj
.form-item { margin-bottom: 20rpx; }
.form-item .label { font-size: 26rpx; color: #999; display: block; margin-bottom: 10rpx; }
.form-item .value { font-size: 28rpx; color: #333; }