| New file |
| | |
| | | <template> |
| | | <view class="container"> |
| | | |
| | | <!-- 搜索筛选卡片 --> |
| | | <view class="filter-card"> |
| | | <!-- 订单选择 --> |
| | | <view class="filter-item"> |
| | | <view class="filter-label"> |
| | | <uni-icons type="document" size="18" color="#409EFF"></uni-icons> |
| | | <text>订单号</text> |
| | | </view> |
| | | <view class="filter-input"> |
| | | <uni-combox :candidates="orderNoList" placeholder="请选择订单" v-model="orderNo" @input="getOrderDet"></uni-combox> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 物料编号过滤 --> |
| | | <view class="filter-item"> |
| | | <view class="filter-label"> |
| | | <uni-icons type="scan" size="18" color="#409EFF"></uni-icons> |
| | | <text>物料编号</text> |
| | | </view> |
| | | <view class="filter-input"> |
| | | <input |
| | | type="text" |
| | | v-model="filterMatnr" |
| | | placeholder="输入物料编号过滤" |
| | | @input="onFilterInput" |
| | | class="filter-input-field" |
| | | placeholder-class="placeholder-style" |
| | | /> |
| | | </view> |
| | | <view v-if="filterMatnr" class="filter-clear" @click="clearFilter"> |
| | | <uni-icons type="close" size="18" color="#909399"></uni-icons> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 统计和全选栏 --> |
| | | <view class="filter-footer"> |
| | | <view class="stat-info"> |
| | | <uni-icons type="list" size="16" color="#909399"></uni-icons> |
| | | <text>{{filterMatnr ? '过滤结果' : '全部物料'}}:{{filteredList.length}} 条</text> |
| | | </view> |
| | | <view class="select-all-btn" @click="allSelect"> |
| | | <text class="select-all-text">{{seltitle}}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 物料列表 --> |
| | | <scroll-view class="scroll-area" scroll-y :show-scrollbar="false"> |
| | | <view class="material-list"> |
| | | <view class="material-card" v-for="(orderDetl,index) in filteredList" :key="index" @click="toggleSelect(orderDetl)"> |
| | | <view class="card-content"> |
| | | <view class="card-info"> |
| | | <view class="info-row"> |
| | | <view class="info-label">序号:</view> |
| | | <view class="info-value"> |
| | | <text class="serial-number">{{index + 1}}</text> |
| | | </view> |
| | | </view> |
| | | <view class="info-row"> |
| | | <view class="info-label">出库口:</view> |
| | | <view class="info-value"> |
| | | <uni-combox :candidates="orderDetl.staNos || []" placeholder="请选择出库口" v-model="orderDetl.selectedStaNo" @click.stop></uni-combox> |
| | | </view> |
| | | </view> |
| | | <view class="info-row"> |
| | | <view class="info-label">订单号:</view> |
| | | <view class="info-value"> |
| | | <text class="tag tag-info">{{orderDetl.orderNo || '-'}}</text> |
| | | </view> |
| | | </view> |
| | | <view class="info-row"> |
| | | <view class="info-label">料号:</view> |
| | | <view class="info-value"> |
| | | <text class="tag tag-primary">{{orderDetl.matnr || '-'}}</text> |
| | | </view> |
| | | </view> |
| | | <view class="info-row"> |
| | | <view class="info-label">批号:</view> |
| | | <view class="info-value"> |
| | | <text class="tag tag-warning">{{orderDetl.batch || '-'}}</text> |
| | | </view> |
| | | </view> |
| | | <view class="info-row"> |
| | | <view class="info-label">库位号:</view> |
| | | <view class="info-value"> |
| | | <text class="tag tag-warning">{{orderDetl.locNo || '-'}}</text> |
| | | </view> |
| | | </view> |
| | | <view class="info-row"> |
| | | <view class="info-label">可用数量:</view> |
| | | <view class="info-value"> |
| | | <text class="quantity-text">{{orderDetl.anfme || 0}}</text> |
| | | <text class="unit-text">个</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view v-if="orderDetl.frozen === 0" class="card-checkbox" @click.stop> |
| | | <view class="checkbox-wrapper" :class="{ 'checked': orderDetl.checked }"> |
| | | <uni-icons v-if="orderDetl.checked" type="checkmarkempty" size="20" color="#ffffff"></uni-icons> |
| | | </view> |
| | | </view> |
| | | <view v-else class="disabled-wrapper" @click.stop> |
| | | <view class="disabled-tag"> |
| | | <text>库存不足</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 空状态 --> |
| | | <view v-if="filteredList.length === 0 && dataList.length > 0" class="empty-state"> |
| | | <uni-icons type="search" size="80" color="#e4e7ed"></uni-icons> |
| | | <text class="empty-text">没有匹配 "{{filterMatnr}}" 的物料</text> |
| | | </view> |
| | | <view v-else-if="dataList.length === 0 && !loading" class="empty-state"> |
| | | <uni-icons type="document" size="80" color="#e4e7ed"></uni-icons> |
| | | <text class="empty-text">请先选择订单</text> |
| | | </view> |
| | | |
| | | <!-- 加载状态 --> |
| | | <view v-if="loading" class="loading-state"> |
| | | <uni-load-more status="loading"></uni-load-more> |
| | | </view> |
| | | |
| | | <!-- 底部提示 --> |
| | | <view class="bottom-tip" v-if="filteredList.length > 0 && !loading"> |
| | | <text>- 已经到底了 -</text> |
| | | </view> |
| | | </view> |
| | | </scroll-view> |
| | | |
| | | <!-- 底部操作按钮 --> |
| | | <view class="bottom-bar"> |
| | | <button class="btn-submit" size="default" type="primary" @click="reset()"> |
| | | <text>重置</text> |
| | | </button> |
| | | <button class="btn-submit" size="default" type="primary" @click="addItems()"> |
| | | <uni-icons type="checkmarkempty" size="18" color="#ffffff"></uni-icons> |
| | | <text>出库选中物料</text> |
| | | </button> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | data() { |
| | | return { |
| | | baseUrl: '', |
| | | token: '', |
| | | storeId: 0, |
| | | store: '', |
| | | total: 0, |
| | | searchType: '订单', |
| | | searchValue: '', |
| | | dataList: [], |
| | | filteredList: [], |
| | | selectedList: [], |
| | | matnr: '', |
| | | orderNo: '', |
| | | orderNoList: [], |
| | | seltitle: '全选', |
| | | filterMatnr: '', |
| | | idList: [], |
| | | loading: false, |
| | | } |
| | | }, |
| | | computed: { |
| | | selectedCount() { |
| | | return this.dataList.filter(item => item.checked).length |
| | | } |
| | | }, |
| | | onShow() { |
| | | let _this = this |
| | | this.baseUrl = uni.getStorageSync('baseUrl'); |
| | | this.token = uni.getStorageSync('token'); |
| | | this.storeId = uni.getStorageSync('store') |
| | | if (this.storeId == 1) { |
| | | this.store = '宁波仓' |
| | | } |
| | | if (this.storeId == 2) { |
| | | this.store = '新昌仓' |
| | | } |
| | | const eventChannel = this.getOpenerEventChannel(); |
| | | eventChannel.on('item', function(data) { |
| | | _this.matnr = data.item.matnr |
| | | _this.getMatList() |
| | | }) |
| | | this.getOrderNoList() |
| | | }, |
| | | methods: { |
| | | // 重置选中状态 |
| | | reset() { |
| | | for (let k of this.dataList) { |
| | | this.$set(k, 'checked', false) |
| | | } |
| | | this.orderNo = '' |
| | | this.updateSelectAllTitle() |
| | | }, |
| | | onFilterInput() { |
| | | this.applyFilter() |
| | | }, |
| | | |
| | | applyFilter() { |
| | | if (!this.filterMatnr || this.filterMatnr.trim() === '') { |
| | | this.filteredList = [...this.dataList] |
| | | } else { |
| | | const keyword = this.filterMatnr.trim().toLowerCase() |
| | | this.filteredList = this.dataList.filter(item => { |
| | | return item.matnr && item.matnr.toLowerCase().includes(keyword) |
| | | }) |
| | | } |
| | | this.updateSelectAllTitle() |
| | | }, |
| | | |
| | | clearFilter() { |
| | | this.filterMatnr = '' |
| | | this.applyFilter() |
| | | }, |
| | | |
| | | updateSelectAllTitle() { |
| | | if (this.filteredList.length === 0) { |
| | | this.seltitle = '全选' |
| | | return |
| | | } |
| | | const allChecked = this.filteredList.every(item => item.checked === true) |
| | | this.seltitle = allChecked ? '取消全选' : '全选' |
| | | }, |
| | | |
| | | toggleSelect(item) { |
| | | if (item.frozen !== 0) return |
| | | this.checkboxChange(item) |
| | | }, |
| | | |
| | | addItems() { |
| | | // 收集所有选中的物料 |
| | | let pickList = [] |
| | | for (let k of this.dataList) { |
| | | if (k.checked) { |
| | | pickList.push(k) |
| | | } |
| | | } |
| | | |
| | | if (pickList.length === 0) { |
| | | uni.showToast({ |
| | | title: '请至少选择一个物料', |
| | | icon: "none", |
| | | position: 'center' |
| | | }) |
| | | return |
| | | } |
| | | |
| | | // 检查是否所有选中的物料都选择了出库口 |
| | | const missingStaNo = pickList.filter(item => { |
| | | return item.staNos && item.staNos.length > 0 && !item.selectedStaNo |
| | | }) |
| | | |
| | | if (missingStaNo.length > 0) { |
| | | uni.showModal({ |
| | | title: '提示', |
| | | content: `有 ${missingStaNo.length} 个物料未选择出库口,是否继续?`, |
| | | confirmText: '继续', |
| | | cancelText: '取消', |
| | | success: (res) => { |
| | | if (res.confirm) { |
| | | this.submitPickList(pickList) |
| | | } |
| | | } |
| | | }) |
| | | return |
| | | } |
| | | |
| | | this.submitPickList(pickList) |
| | | }, |
| | | // 提交选中的物料列表 |
| | | submitPickList(pickList) { |
| | | // 准备提交的数据格式 |
| | | const submitData = pickList.map(item => { |
| | | return { |
| | | frozen: item.frozen, |
| | | matnr: item.matnr, // 物料编号 |
| | | maktx: item.maktx, |
| | | batch: item.batch, // 批号 |
| | | locNo: item.locNo, // 库位号 |
| | | anfme: item.anfme, // 可用数量 |
| | | orderNo: item.orderNo, // 订单号 |
| | | staNo: item.selectedStaNo, // 选中的出库口 |
| | | // 添加其他需要的字段 |
| | | } |
| | | }) |
| | | |
| | | console.log('准备出库的物料:', submitData) |
| | | |
| | | this.outboundRequest(submitData) |
| | | |
| | | }, |
| | | // 直接调用出库接口的方法 |
| | | outboundRequest(submitData) { |
| | | uni.showLoading({ title: '出库中...', mask: true }) |
| | | |
| | | uni.request({ |
| | | url: this.baseUrl + '/out/pakout/auth', // 替换成你的出库接口地址 |
| | | method: 'POST', |
| | | header: { |
| | | 'Content-Type': 'application/json', |
| | | 'token': this.token |
| | | }, |
| | | data: { |
| | | list: submitData // 选中的物料列表 |
| | | }, |
| | | success(res) { |
| | | let result = res.data |
| | | if (typeof result === 'string') { |
| | | try { |
| | | result = JSON.parse(result) |
| | | } catch(e) { |
| | | console.error('JSON解析失败:', e) |
| | | } |
| | | } |
| | | |
| | | if (result.code === 200) { |
| | | uni.showToast({ |
| | | title: `成功出库 ${submitData.length} 个物料`, |
| | | icon: "success" |
| | | }) |
| | | |
| | | // 出库成功后,刷新列表或返回上一页 |
| | | setTimeout(() => { |
| | | // 刷新当前列表 |
| | | this.getOrderDet() |
| | | // 或者返回上一页 |
| | | // uni.navigateBack({}) |
| | | }, 1500) |
| | | } else if (result.code === 403) { |
| | | uni.showToast({ title: result.msg || '登录已过期', icon: "error" }) |
| | | setTimeout(() => { uni.reLaunch({ url: '../login/login' }); }, 1500); |
| | | } else { |
| | | uni.showToast({ title: result.msg || '出库失败', icon: "error" }) |
| | | } |
| | | }, |
| | | fail(err) { |
| | | console.error('出库请求失败:', err) |
| | | uni.showToast({ title: '网络请求失败', icon: "error" }) |
| | | }, |
| | | complete() { |
| | | uni.hideLoading() |
| | | } |
| | | }) |
| | | }, |
| | | checkboxChange(e) { |
| | | if (e.checked) { |
| | | this.$set(e, 'checked', false) |
| | | } else { |
| | | this.$set(e, 'checked', true) |
| | | } |
| | | this.updateSelectAllTitle() |
| | | }, |
| | | |
| | | allSelect() { |
| | | const targetList = this.filteredList |
| | | if (this.seltitle == '全选') { |
| | | for (let k of targetList) { |
| | | if (k.frozen === 0) { |
| | | k.checked = true |
| | | } |
| | | } |
| | | this.seltitle = '取消全选' |
| | | } else { |
| | | for (let k of targetList) { |
| | | k.checked = false |
| | | } |
| | | this.seltitle = '全选' |
| | | } |
| | | }, |
| | | |
| | | getOrderDet() { |
| | | if (!this.orderNo) { |
| | | uni.showToast({ |
| | | title: '请选择订单号', |
| | | icon: "none" |
| | | }) |
| | | return |
| | | } |
| | | |
| | | let that = this |
| | | that.idList = [] |
| | | that.loading = true |
| | | uni.showLoading({ title: '加载中...', mask: true }) |
| | | |
| | | uni.request({ |
| | | url: that.baseUrl + '/orderDetlPakout/list/auth', |
| | | data: {orderNo: that.orderNo}, |
| | | method: 'GET', |
| | | success(res) { |
| | | res = res.data; |
| | | if (res.code === 200) { |
| | | for (var i = 0; i < res.data.length; i++) { |
| | | if (res.data[i].id) { |
| | | that.idList.push(res.data[i].id) |
| | | } |
| | | } |
| | | that.previewPakout() |
| | | } else { |
| | | uni.hideLoading() |
| | | that.loading = false |
| | | uni.showToast({ |
| | | title: res.msg || '加载失败', |
| | | icon: "error" |
| | | }) |
| | | } |
| | | }, |
| | | fail() { |
| | | uni.hideLoading() |
| | | that.loading = false |
| | | uni.showToast({ |
| | | title: '网络请求失败', |
| | | icon: "error" |
| | | }) |
| | | } |
| | | }) |
| | | }, |
| | | |
| | | previewPakout() { |
| | | let that = this |
| | | uni.request({ |
| | | url: that.baseUrl + '/out/pakout/preview/auth', |
| | | data: that.idList, |
| | | method: 'POST', |
| | | header: { |
| | | 'Content-Type': 'application/json', |
| | | 'token': that.token |
| | | }, |
| | | success(res) { |
| | | let result = res.data |
| | | if (typeof result === 'string') { |
| | | try { |
| | | result = JSON.parse(result) |
| | | } catch(e) { |
| | | console.error('JSON解析失败:', e) |
| | | } |
| | | } |
| | | |
| | | if (result.code === 200) { |
| | | that.dataList = result.data || [] |
| | | if (that.dataList.length > 0) { |
| | | for (var i = 0; i < that.dataList.length; i++) { |
| | | that.$set(that.dataList[i], 'checked', false) |
| | | that.$set(that.dataList[i], 'selectedStaNo', '') |
| | | if (!that.dataList[i].staNos) { |
| | | that.$set(that.dataList[i], 'staNos', []) |
| | | } |
| | | } |
| | | that.applyFilter() |
| | | } |
| | | uni.showToast({ |
| | | title: `加载成功,共${that.dataList.length}个物料`, |
| | | icon: "success", |
| | | duration: 1500 |
| | | }) |
| | | } else if (result.code == 403) { |
| | | uni.showToast({ title: result.msg || '登录已过期', icon: "error" }) |
| | | setTimeout(() => { uni.reLaunch({ url: '../login/login' }); }, 1500); |
| | | } else { |
| | | uni.showToast({ title: result.msg || '预览失败', icon: "error" }) |
| | | } |
| | | }, |
| | | fail(err) { |
| | | console.error('预览请求失败:', err) |
| | | uni.showToast({ title: '网络请求失败', icon: "error" }) |
| | | }, |
| | | complete() { |
| | | uni.hideLoading() |
| | | that.loading = false |
| | | } |
| | | }) |
| | | }, |
| | | |
| | | getOrderNoList() { |
| | | let that = this |
| | | uni.request({ |
| | | url: this.baseUrl + '/order/pakout/order/nav/list/auth', |
| | | header: { |
| | | 'token': uni.getStorageSync('token') |
| | | }, |
| | | method: 'POST', |
| | | success(res) { |
| | | res = res.data |
| | | if (res.code == 403) { |
| | | uni.showToast({ title: res.msg, icon: "error", position: 'center' }) |
| | | setTimeout(() => { uni.reLaunch({ url: '../login/login' }); }, 1000); |
| | | } |
| | | if (res.data && res.data.length) { |
| | | for (var i = 0; i < res.data.length; i++) { |
| | | that.orderNoList.push(res.data[i].orderNo) |
| | | } |
| | | } |
| | | } |
| | | }) |
| | | }, |
| | | |
| | | clear() { |
| | | this.searchValue = '' |
| | | this.getOrderNoList(this.locNo) |
| | | }, |
| | | |
| | | back() { |
| | | uni.navigateBack({}) |
| | | }, |
| | | |
| | | set(e) { |
| | | var ck = this.dataList[e].checked |
| | | this.dataList[e].checked = ck ? false : true |
| | | this.updateSelectAllTitle() |
| | | }, |
| | | |
| | | getMatList() { |
| | | let that = this |
| | | let searchParam = { |
| | | orderNo: that.searchValue, |
| | | matnr: that.matnr, |
| | | } |
| | | that.loading = true |
| | | uni.showLoading({ title: '加载中...', mask: true }) |
| | | |
| | | uni.request({ |
| | | url: that.baseUrl + '/mobile/outBound/mat/list', |
| | | header: { |
| | | 'token': uni.getStorageSync('token') |
| | | }, |
| | | data: searchParam, |
| | | method: 'GET', |
| | | success(res) { |
| | | res = res.data; |
| | | if (res.code === 200) { |
| | | that.total = res.data.length |
| | | const result1 = res.data.filter(obj1 => |
| | | !that.selectedList.some(obj2 => obj1.matnr === obj2.matnr && obj1.orderNo === obj2.orderNo) |
| | | ); |
| | | that.dataList = result1 |
| | | that.total = result1.length |
| | | that.applyFilter() |
| | | } else if (res.code == 403) { |
| | | uni.showToast({ title: res.msg, icon: "error", position: 'center' }) |
| | | setTimeout(() => { uni.reLaunch({ url: '../login/login' }); }, 1000); |
| | | } else { |
| | | uni.showToast({ title: res.msg, icon: "error", position: 'center' }) |
| | | } |
| | | }, |
| | | fail() { |
| | | uni.showToast({ title: '网络请求失败', icon: "error" }) |
| | | }, |
| | | complete() { |
| | | uni.hideLoading() |
| | | that.loading = false |
| | | } |
| | | }) |
| | | }, |
| | | |
| | | addItem(mat) { |
| | | this.getOpenerEventChannel().emit('sMat', {data: mat}); |
| | | uni.navigateBack({}) |
| | | } |
| | | }, |
| | | |
| | | watch: { |
| | | filterMatnr() { |
| | | this.applyFilter() |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | /* 全局样式 */ |
| | | .container { |
| | | min-height: 100vh; |
| | | background-color: #f5f7fa; |
| | | } |
| | | |
| | | .status_bar { |
| | | height: var(--status-bar-height); |
| | | width: 100%; |
| | | background-color: #ffffff; |
| | | } |
| | | |
| | | /* 筛选卡片 */ |
| | | .filter-card { |
| | | background: #ffffff; |
| | | margin: 24rpx; |
| | | border-radius: 24rpx; |
| | | overflow: hidden; |
| | | box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | .filter-item { |
| | | display: flex; |
| | | align-items: center; |
| | | padding: 24rpx 32rpx; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | } |
| | | |
| | | .filter-item:last-child { |
| | | border-bottom: none; |
| | | } |
| | | |
| | | .filter-label { |
| | | width: 140rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 12rpx; |
| | | font-size: 28rpx; |
| | | color: #303133; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .filter-input { |
| | | flex: 1; |
| | | } |
| | | |
| | | .filter-input-field { |
| | | background: #f5f7fa; |
| | | padding: 16rpx 20rpx; |
| | | border-radius: 12rpx; |
| | | font-size: 28rpx; |
| | | color: #303133; |
| | | width: 100%; |
| | | } |
| | | |
| | | .filter-input-field:focus { |
| | | background: #ffffff; |
| | | box-shadow: 0 0 0 2rpx #409EFF; |
| | | } |
| | | |
| | | .filter-clear { |
| | | padding: 0 16rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .placeholder-style { |
| | | color: #c0c4cc; |
| | | font-size: 26rpx; |
| | | } |
| | | |
| | | .filter-footer { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 20rpx 32rpx; |
| | | background: #f8f9fa; |
| | | border-top: 1px solid #f0f0f0; |
| | | } |
| | | |
| | | .stat-info { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8rpx; |
| | | font-size: 26rpx; |
| | | color: #606266; |
| | | } |
| | | |
| | | .select-all-btn { |
| | | padding: 8rpx 24rpx; |
| | | background: #ecf5ff; |
| | | border-radius: 32rpx; |
| | | } |
| | | |
| | | .select-all-text { |
| | | font-size: 26rpx; |
| | | color: #409EFF; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | /* 滚动区域 */ |
| | | .scroll-area { |
| | | height: calc(100vh - 420rpx); |
| | | padding: 0 24rpx; |
| | | } |
| | | |
| | | /* 物料列表 */ |
| | | .material-list { |
| | | padding-bottom: 40rpx; |
| | | } |
| | | |
| | | .material-card { |
| | | background: #ffffff; |
| | | border-radius: 24rpx; |
| | | margin-bottom: 20rpx; |
| | | overflow: hidden; |
| | | box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.04); |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .material-card:active { |
| | | transform: scale(0.98); |
| | | } |
| | | |
| | | .card-content { |
| | | display: flex; |
| | | padding: 24rpx; |
| | | } |
| | | |
| | | .card-info { |
| | | flex: 1; |
| | | } |
| | | |
| | | .info-row { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-bottom: 16rpx; |
| | | font-size: 28rpx; |
| | | } |
| | | |
| | | .info-row:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .info-label { |
| | | width: 140rpx; |
| | | color: #909399; |
| | | font-size: 26rpx; |
| | | } |
| | | |
| | | .info-value { |
| | | flex: 1; |
| | | color: #606266; |
| | | font-size: 28rpx; |
| | | word-break: break-all; |
| | | } |
| | | |
| | | .serial-number { |
| | | color: #409EFF; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | /* 标签样式 */ |
| | | .tag { |
| | | display: inline-block; |
| | | padding: 6rpx 16rpx; |
| | | border-radius: 8rpx; |
| | | font-size: 24rpx; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .tag-primary { |
| | | background: #ecf5ff; |
| | | color: #409EFF; |
| | | } |
| | | |
| | | .tag-info { |
| | | background: #f0f9ff; |
| | | color: #67C23A; |
| | | } |
| | | |
| | | .tag-warning { |
| | | background: #fdf6ec; |
| | | color: #E6A23C; |
| | | } |
| | | |
| | | .quantity-text { |
| | | font-size: 32rpx; |
| | | font-weight: 600; |
| | | color: #F56C6C; |
| | | } |
| | | |
| | | .unit-text { |
| | | font-size: 24rpx; |
| | | color: #909399; |
| | | margin-left: 8rpx; |
| | | } |
| | | |
| | | /* 复选框样式 */ |
| | | .card-checkbox { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | padding-left: 20rpx; |
| | | margin-left: 20rpx; |
| | | border-left: 2rpx solid #f0f0f0; |
| | | } |
| | | |
| | | .checkbox-wrapper { |
| | | width: 44rpx; |
| | | height: 44rpx; |
| | | border-radius: 50%; |
| | | border: 2rpx solid #dcdfe6; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | transition: all 0.2s ease; |
| | | background: #ffffff; |
| | | } |
| | | |
| | | .checkbox-wrapper.checked { |
| | | background: #409EFF; |
| | | border-color: #409EFF; |
| | | } |
| | | |
| | | /* 库存不足样式 */ |
| | | .disabled-wrapper { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | padding-left: 20rpx; |
| | | margin-left: 20rpx; |
| | | border-left: 2rpx solid #f0f0f0; |
| | | } |
| | | |
| | | .disabled-tag { |
| | | padding: 8rpx 16rpx; |
| | | background: #fef0f0; |
| | | border-radius: 8rpx; |
| | | } |
| | | |
| | | .disabled-tag text { |
| | | font-size: 24rpx; |
| | | color: #F56C6C; |
| | | } |
| | | |
| | | /* 空状态 */ |
| | | .empty-state { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | padding: 120rpx 0; |
| | | } |
| | | |
| | | .empty-text { |
| | | font-size: 28rpx; |
| | | color: #c0c4cc; |
| | | margin-top: 24rpx; |
| | | } |
| | | |
| | | /* 加载状态 */ |
| | | .loading-state { |
| | | padding: 60rpx 0; |
| | | } |
| | | |
| | | /* 底部提示 */ |
| | | .bottom-tip { |
| | | text-align: center; |
| | | padding: 40rpx 0; |
| | | color: #c0c4cc; |
| | | font-size: 24rpx; |
| | | } |
| | | |
| | | /* 底部按钮栏 */ |
| | | .bottom-bar { |
| | | position: fixed; |
| | | bottom: 0; |
| | | left: 0; |
| | | right: 0; |
| | | padding: 20rpx 32rpx; |
| | | display: flex; |
| | | flex-direction: row; |
| | | padding-bottom: calc(20rpx + env(safe-area-inset-bottom)); |
| | | background: #ffffff; |
| | | box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.05); |
| | | z-index: 20; |
| | | } |
| | | |
| | | .btn-submit { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 12rpx; |
| | | height: 88rpx; |
| | | border-radius: 48rpx; |
| | | font-size: 30rpx; |
| | | font-weight: 500; |
| | | background: linear-gradient(135deg, #409EFF 0%, #66b1ff 100%); |
| | | color: #ffffff; |
| | | border: none; |
| | | box-shadow: 0 8rpx 20rpx rgba(64, 158, 255, 0.3); |
| | | transition: all 0.3s ease; |
| | | position: relative; |
| | | } |
| | | |
| | | .btn-submit:active { |
| | | transform: scale(0.98); |
| | | box-shadow: 0 4rpx 12rpx rgba(64, 158, 255, 0.3); |
| | | } |
| | | |
| | | .selected-badge { |
| | | position: absolute; |
| | | top: -12rpx; |
| | | right: -12rpx; |
| | | background: #F56C6C; |
| | | color: #ffffff; |
| | | font-size: 22rpx; |
| | | padding: 4rpx 12rpx; |
| | | border-radius: 32rpx; |
| | | min-width: 40rpx; |
| | | text-align: center; |
| | | } |
| | | </style> |