|
|
@@ -3,6 +3,12 @@
|
|
|
<view class="header-info">
|
|
|
进货总金额:{{jxsInfo.total_purchase}}
|
|
|
</view>
|
|
|
+ <view class="ship-entry" @click="openShip">
|
|
|
+ 发货供应商
|
|
|
+ </view>
|
|
|
+ <view class="ship-entry" @click="openShipRecord">
|
|
|
+ 发货记录
|
|
|
+ </view>
|
|
|
<view class="stock-list">
|
|
|
<view class="stock-card" v-for="item in jxsInfo.stock_list" @click="goItem(item)">
|
|
|
<view class="product-image-wrapper">
|
|
|
@@ -29,12 +35,94 @@
|
|
|
<view class="code-close" @click="closeCode">关闭</view>
|
|
|
</view>
|
|
|
</uni-popup>
|
|
|
+ <uni-popup type="center" ref="ship">
|
|
|
+ <view class="ship-popup">
|
|
|
+ <view class="ship-title">发货供应商</view>
|
|
|
+ <view class="ship-form">
|
|
|
+ <view class="ship-item">
|
|
|
+ <view class="ship-label">供应商 UID</view>
|
|
|
+ <input class="ship-input" type="number" v-model="shipForm.to_uid" placeholder="请输入收货方 UID" />
|
|
|
+ </view>
|
|
|
+ <view class="ship-item">
|
|
|
+ <view class="ship-label">商品</view>
|
|
|
+ <picker mode="selector" :range="productNames" :value="productIndex" @change="onProductChange">
|
|
|
+ <view class="ship-picker" :class="{ placeholder: productIndex < 0 }">
|
|
|
+ {{ productIndex >= 0 ? productNames[productIndex] : '请选择商品' }}
|
|
|
+ </view>
|
|
|
+ </picker>
|
|
|
+ </view>
|
|
|
+ <view class="ship-item">
|
|
|
+ <view class="ship-label">规格</view>
|
|
|
+ <picker mode="selector" :range="skuNames" :value="skuIndex" :disabled="productIndex < 0" @change="onSkuChange">
|
|
|
+ <view class="ship-picker" :class="{ placeholder: skuIndex < 0 }">
|
|
|
+ {{ skuIndex >= 0 ? skuNames[skuIndex] : '请选择规格' }}
|
|
|
+ </view>
|
|
|
+ </picker>
|
|
|
+ <view class="ship-tip" v-if="selectedProduct">剩余库存(基础单位):{{ selectedProduct.remaining_quantity }}</view>
|
|
|
+ </view>
|
|
|
+ <view class="ship-item">
|
|
|
+ <view class="ship-label">发货数量</view>
|
|
|
+ <input class="ship-input" type="number" v-model="shipForm.quantity" placeholder="请输入发货数量" />
|
|
|
+ </view>
|
|
|
+ <view class="ship-item">
|
|
|
+ <view class="ship-label">备注(选填)</view>
|
|
|
+ <input class="ship-input" type="text" v-model="shipForm.mark" placeholder="请输入备注" />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="ship-actions">
|
|
|
+ <view class="ship-cancel" @click="closeShip">取消</view>
|
|
|
+ <view class="ship-submit" @click="submitShip">确认发货</view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </uni-popup>
|
|
|
+ <uni-popup type="bottom" ref="shipRecord">
|
|
|
+ <view class="record-popup">
|
|
|
+ <view class="record-header">
|
|
|
+ <view class="ship-title">发货记录</view>
|
|
|
+ <view class="record-close" @click="closeShipRecord">关闭</view>
|
|
|
+ </view>
|
|
|
+ <view class="record-tabs">
|
|
|
+ <view
|
|
|
+ class="record-tab"
|
|
|
+ :class="{ active: recordType === item.value }"
|
|
|
+ v-for="item in recordTabs"
|
|
|
+ :key="item.value"
|
|
|
+ @click="changeRecordType(item.value)"
|
|
|
+ >{{ item.label }}</view>
|
|
|
+ </view>
|
|
|
+ <scroll-view
|
|
|
+ class="record-list"
|
|
|
+ scroll-y
|
|
|
+ @scrolltolower="loadMoreRecords"
|
|
|
+ >
|
|
|
+ <view class="record-empty" v-if="!recordList.length && !recordLoading">暂无发货记录</view>
|
|
|
+ <view class="record-card" v-for="item in recordList" :key="item.id">
|
|
|
+ <view class="record-card-top">
|
|
|
+ <view class="record-name">{{ item.product_name }}</view>
|
|
|
+ <view class="record-direction" :class="item.direction === '发出' ? 'out' : 'in'">{{ item.direction }}</view>
|
|
|
+ </view>
|
|
|
+ <view class="record-row">发货方:{{ item.from_nickname || '平台' }}</view>
|
|
|
+ <view class="record-row">收货方:{{ item.to_nickname }}</view>
|
|
|
+ <view class="record-row">数量:{{ item.quantity }}(基础单位 {{ item.base_quantity }})</view>
|
|
|
+ <view class="record-row" v-if="item.diff_amount && Number(item.diff_amount) > 0">差价佣金:¥{{ item.diff_amount }}</view>
|
|
|
+ <view class="record-row" v-if="item.mark">备注:{{ item.mark }}</view>
|
|
|
+ <view class="record-time">{{ item.add_time }}</view>
|
|
|
+ </view>
|
|
|
+ <view class="record-status" v-if="recordList.length">
|
|
|
+ {{ recordFinished ? '没有更多了' : (recordLoading ? '加载中...' : '上拉加载更多') }}
|
|
|
+ </view>
|
|
|
+ </scroll-view>
|
|
|
+ </view>
|
|
|
+ </uni-popup>
|
|
|
</view>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
import {
|
|
|
- getJxsInfo
|
|
|
+ getJxsInfo,
|
|
|
+ getShipmentProducts,
|
|
|
+ submitShipment,
|
|
|
+ getShipmentRecords
|
|
|
} from '@/api/user.js'
|
|
|
import {
|
|
|
mapState
|
|
|
@@ -49,12 +137,48 @@
|
|
|
dealer_name: '',
|
|
|
stock_list: [],
|
|
|
total_purchase: ''
|
|
|
- }
|
|
|
+ },
|
|
|
+ productList: [],
|
|
|
+ productIndex: -1,
|
|
|
+ skuIndex: -1,
|
|
|
+ shipForm: {
|
|
|
+ to_uid: '',
|
|
|
+ quantity: '',
|
|
|
+ mark: ''
|
|
|
+ },
|
|
|
+ submitting: false,
|
|
|
+ recordTabs: [
|
|
|
+ { label: '全部', value: 0 },
|
|
|
+ { label: '我发出的', value: 1 },
|
|
|
+ { label: '我收到的', value: 2 }
|
|
|
+ ],
|
|
|
+ recordType: 0,
|
|
|
+ recordList: [],
|
|
|
+ recordPage: 1,
|
|
|
+ recordLimit: 10,
|
|
|
+ recordCount: 0,
|
|
|
+ recordLoading: false,
|
|
|
+ recordFinished: false
|
|
|
}
|
|
|
},
|
|
|
computed: {
|
|
|
...mapState(['baseURL']),
|
|
|
- ...mapState('user', ['userInfo'])
|
|
|
+ ...mapState('user', ['userInfo']),
|
|
|
+ productNames() {
|
|
|
+ return this.productList.map(item => item.product_name)
|
|
|
+ },
|
|
|
+ selectedProduct() {
|
|
|
+ return this.productIndex >= 0 ? this.productList[this.productIndex] : null
|
|
|
+ },
|
|
|
+ skuList() {
|
|
|
+ return this.selectedProduct ? (this.selectedProduct.skus || []) : []
|
|
|
+ },
|
|
|
+ skuNames() {
|
|
|
+ return this.skuList.map(item => `${item.suk}(×${item.unit_quantity})`)
|
|
|
+ },
|
|
|
+ selectedSku() {
|
|
|
+ return this.skuIndex >= 0 ? this.skuList[this.skuIndex] : null
|
|
|
+ }
|
|
|
},
|
|
|
methods: {
|
|
|
goItem(item) {
|
|
|
@@ -74,6 +198,124 @@
|
|
|
},
|
|
|
closeCode() {
|
|
|
this.$refs.code.close()
|
|
|
+ },
|
|
|
+ resetShipForm() {
|
|
|
+ this.productIndex = -1
|
|
|
+ this.skuIndex = -1
|
|
|
+ this.shipForm = {
|
|
|
+ to_uid: '',
|
|
|
+ quantity: '',
|
|
|
+ mark: ''
|
|
|
+ }
|
|
|
+ },
|
|
|
+ openShip() {
|
|
|
+ this.resetShipForm()
|
|
|
+ getShipmentProducts().then(res => {
|
|
|
+ this.productList = res.data || []
|
|
|
+ if (!this.productList.length) {
|
|
|
+ uni.showToast({
|
|
|
+ title: '暂无可发货商品',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.$refs.ship.open()
|
|
|
+ })
|
|
|
+ },
|
|
|
+ closeShip() {
|
|
|
+ this.$refs.ship.close()
|
|
|
+ },
|
|
|
+ onProductChange(e) {
|
|
|
+ this.productIndex = Number(e.detail.value)
|
|
|
+ this.skuIndex = -1
|
|
|
+ },
|
|
|
+ onSkuChange(e) {
|
|
|
+ this.skuIndex = Number(e.detail.value)
|
|
|
+ },
|
|
|
+ submitShip() {
|
|
|
+ const toUid = String(this.shipForm.to_uid || '').trim()
|
|
|
+ const quantity = Number(this.shipForm.quantity)
|
|
|
+ if (!toUid) {
|
|
|
+ uni.showToast({ title: '请输入供应商 UID', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (!this.selectedProduct) {
|
|
|
+ uni.showToast({ title: '请选择商品', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (!this.selectedSku) {
|
|
|
+ uni.showToast({ title: '请选择规格', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (!quantity || quantity <= 0) {
|
|
|
+ uni.showToast({ title: '发货数量必须大于0', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (this.submitting) return
|
|
|
+ this.submitting = true
|
|
|
+ const data = {
|
|
|
+ to_uid: Number(toUid),
|
|
|
+ product_id: this.selectedProduct.product_id,
|
|
|
+ attr_unique: this.selectedSku.unique,
|
|
|
+ quantity: quantity
|
|
|
+ }
|
|
|
+ const mark = String(this.shipForm.mark || '').trim()
|
|
|
+ if (mark) data.mark = mark
|
|
|
+ submitShipment(data).then(res => {
|
|
|
+ uni.showToast({
|
|
|
+ title: res.msg || '发货成功',
|
|
|
+ icon: 'success'
|
|
|
+ })
|
|
|
+ this.closeShip()
|
|
|
+ this.getJxsInfo()
|
|
|
+ }).finally(() => {
|
|
|
+ this.submitting = false
|
|
|
+ })
|
|
|
+ },
|
|
|
+ openShipRecord() {
|
|
|
+ this.recordType = 0
|
|
|
+ this.resetRecordList()
|
|
|
+ this.$refs.shipRecord.open()
|
|
|
+ this.getShipRecords()
|
|
|
+ },
|
|
|
+ closeShipRecord() {
|
|
|
+ this.$refs.shipRecord.close()
|
|
|
+ },
|
|
|
+ resetRecordList() {
|
|
|
+ this.recordPage = 1
|
|
|
+ this.recordList = []
|
|
|
+ this.recordCount = 0
|
|
|
+ this.recordFinished = false
|
|
|
+ },
|
|
|
+ changeRecordType(type) {
|
|
|
+ if (this.recordType === type) return
|
|
|
+ this.recordType = type
|
|
|
+ this.resetRecordList()
|
|
|
+ this.getShipRecords()
|
|
|
+ },
|
|
|
+ loadMoreRecords() {
|
|
|
+ if (this.recordLoading || this.recordFinished) return
|
|
|
+ this.recordPage += 1
|
|
|
+ this.getShipRecords()
|
|
|
+ },
|
|
|
+ getShipRecords() {
|
|
|
+ if (this.recordLoading) return
|
|
|
+ this.recordLoading = true
|
|
|
+ getShipmentRecords({
|
|
|
+ type: this.recordType,
|
|
|
+ page: this.recordPage,
|
|
|
+ limit: this.recordLimit
|
|
|
+ }).then(res => {
|
|
|
+ const data = res.data || {}
|
|
|
+ const list = data.list || []
|
|
|
+ this.recordCount = data.count || 0
|
|
|
+ this.recordList = this.recordPage === 1 ? list : this.recordList.concat(list)
|
|
|
+ this.recordFinished = this.recordList.length >= this.recordCount || list.length < this.recordLimit
|
|
|
+ }).catch(() => {
|
|
|
+ if (this.recordPage > 1) this.recordPage -= 1
|
|
|
+ }).finally(() => {
|
|
|
+ this.recordLoading = false
|
|
|
+ })
|
|
|
}
|
|
|
},
|
|
|
onLoad() {
|
|
|
@@ -98,6 +340,17 @@
|
|
|
margin-bottom: 20rpx;
|
|
|
}
|
|
|
|
|
|
+ .ship-entry {
|
|
|
+ background-color: #fff;
|
|
|
+ padding: 28rpx 30rpx;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ font-size: 30rpx;
|
|
|
+ color: #FF6B6B;
|
|
|
+ font-weight: 500;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+
|
|
|
.stock-list {
|
|
|
display: flex;
|
|
|
flex-wrap: wrap;
|
|
|
@@ -194,4 +447,201 @@
|
|
|
border: 1rpx solid #e5e5e5;
|
|
|
border-radius: 40rpx;
|
|
|
}
|
|
|
-</style>
|
|
|
+
|
|
|
+ .ship-popup {
|
|
|
+ background-color: #ffffff;
|
|
|
+ border-radius: 24rpx;
|
|
|
+ padding: 40rpx 36rpx;
|
|
|
+ width: 620rpx;
|
|
|
+ box-sizing: border-box;
|
|
|
+ box-shadow: 0 10rpx 40rpx rgba(0, 0, 0, 0.15);
|
|
|
+ }
|
|
|
+
|
|
|
+ .ship-title {
|
|
|
+ font-size: 34rpx;
|
|
|
+ color: #333;
|
|
|
+ font-weight: 600;
|
|
|
+ text-align: center;
|
|
|
+ margin-bottom: 30rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .ship-form {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 24rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .ship-item {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 12rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .ship-label {
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #666;
|
|
|
+ }
|
|
|
+
|
|
|
+ .ship-input,
|
|
|
+ .ship-picker {
|
|
|
+ height: 76rpx;
|
|
|
+ line-height: 76rpx;
|
|
|
+ padding: 0 24rpx;
|
|
|
+ background-color: #f7f7f7;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #333;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+
|
|
|
+ .ship-picker.placeholder {
|
|
|
+ color: #999;
|
|
|
+ }
|
|
|
+
|
|
|
+ .ship-tip {
|
|
|
+ font-size: 22rpx;
|
|
|
+ color: #999;
|
|
|
+ }
|
|
|
+
|
|
|
+ .ship-actions {
|
|
|
+ display: flex;
|
|
|
+ gap: 20rpx;
|
|
|
+ margin-top: 40rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .ship-cancel,
|
|
|
+ .ship-submit {
|
|
|
+ flex: 1;
|
|
|
+ height: 80rpx;
|
|
|
+ line-height: 80rpx;
|
|
|
+ text-align: center;
|
|
|
+ border-radius: 40rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .ship-cancel {
|
|
|
+ color: #999;
|
|
|
+ border: 1rpx solid #e5e5e5;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+
|
|
|
+ .ship-submit {
|
|
|
+ color: #fff;
|
|
|
+ background-color: #FF6B6B;
|
|
|
+ font-weight: 500;
|
|
|
+ }
|
|
|
+
|
|
|
+ .record-popup {
|
|
|
+ background-color: #fff;
|
|
|
+ border-radius: 24rpx 24rpx 0 0;
|
|
|
+ padding: 30rpx 24rpx calc(30rpx + env(safe-area-inset-bottom));
|
|
|
+ height: 75vh;
|
|
|
+ box-sizing: border-box;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ }
|
|
|
+
|
|
|
+ .record-header {
|
|
|
+ position: relative;
|
|
|
+ margin-bottom: 10rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .record-header .ship-title {
|
|
|
+ margin-bottom: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .record-close {
|
|
|
+ position: absolute;
|
|
|
+ right: 0;
|
|
|
+ top: 0;
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #999;
|
|
|
+ padding: 8rpx 0 8rpx 20rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .record-tabs {
|
|
|
+ display: flex;
|
|
|
+ gap: 16rpx;
|
|
|
+ margin: 24rpx 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .record-tab {
|
|
|
+ flex: 1;
|
|
|
+ height: 64rpx;
|
|
|
+ line-height: 64rpx;
|
|
|
+ text-align: center;
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #666;
|
|
|
+ background-color: #f7f7f7;
|
|
|
+ border-radius: 32rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .record-tab.active {
|
|
|
+ color: #fff;
|
|
|
+ background-color: #FF6B6B;
|
|
|
+ }
|
|
|
+
|
|
|
+ .record-list {
|
|
|
+ flex: 1;
|
|
|
+ height: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .record-empty,
|
|
|
+ .record-status {
|
|
|
+ text-align: center;
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #999;
|
|
|
+ padding: 40rpx 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .record-card {
|
|
|
+ background-color: #f7f7f7;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ padding: 24rpx;
|
|
|
+ margin-bottom: 16rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .record-card-top {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ gap: 16rpx;
|
|
|
+ margin-bottom: 12rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .record-name {
|
|
|
+ flex: 1;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #333;
|
|
|
+ font-weight: 500;
|
|
|
+ }
|
|
|
+
|
|
|
+ .record-direction {
|
|
|
+ font-size: 22rpx;
|
|
|
+ padding: 4rpx 14rpx;
|
|
|
+ border-radius: 20rpx;
|
|
|
+ flex-shrink: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .record-direction.out {
|
|
|
+ color: #FF6B6B;
|
|
|
+ background-color: rgba(255, 107, 107, 0.12);
|
|
|
+ }
|
|
|
+
|
|
|
+ .record-direction.in {
|
|
|
+ color: #2ecc71;
|
|
|
+ background-color: rgba(46, 204, 113, 0.12);
|
|
|
+ }
|
|
|
+
|
|
|
+ .record-row {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #666;
|
|
|
+ line-height: 1.7;
|
|
|
+ }
|
|
|
+
|
|
|
+ .record-time {
|
|
|
+ font-size: 22rpx;
|
|
|
+ color: #999;
|
|
|
+ margin-top: 10rpx;
|
|
|
+ }
|
|
|
+</style>
|