#
zhou zhou
19 小时以前 eff43fd0ea0d3051d56c2aa9827cc3081e46d865
#
1个文件已添加
3个文件已修改
1103 ■■■■■ 已修改文件
pages.json 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/outbound/orderOut/orderDetlList.vue 498 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/outbound/orderOut/orderList.vue 170 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
static/css/common.scss 426 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages.json
@@ -21,7 +21,14 @@
        {
            "path": "pages/outbound/orderOut/orderList",
            "style": {
                "navigationBarTitleText": "单据列表"
                "navigationBarTitleText": "单据列表",
                "enablePullDownRefresh": true
            }
        },
        {
            "path": "pages/outbound/orderOut/orderDetlList",
            "style": {
                "navigationBarTitleText": "单据明细列表"
            }
        },
        {
pages/outbound/orderOut/orderDetlList.vue
New file
@@ -0,0 +1,498 @@
<template>
    <view class="page-container">
        <!-- 订单信息头部 -->
        <view class="order-header" v-if="order">
            <view class="header-content">
                <view class="header-row">
                    <text class="header-label">单据号</text>
                    <text class="header-value">{{order.code}}</text>
                </view>
                <view class="header-row">
                    <text class="header-label">单据类型</text>
                    <text class="header-value">{{order.wkType$ || '-'}}</text>
                </view>
            </view>
        </view>
        <!-- 搜索框 -->
        <view class="search-bar">
            <uni-search-bar v-model="condition" placeholder=" 扫码 / 输入物料" bgColor="#F5F5F5" @confirm="search" @cancel="onCancelSearch" />
        </view>
        <!-- 明细列表 -->
        <view class="detl-list">
            <view class="detl-card" v-for="(item, index) in filterList" :key="index" @click="chose(item)">
                <!-- 卡片头部 -->
                <view class="card-header">
                    <view class="mat-info">
                        <text class="mat-code">{{item.matnrCode}}</text>
                        <text class="mat-name">{{item.maktx || '-'}}</text>
                    </view>
                    <view class="qty-badge" :class="item.enableQty > 0 ? 'badge-active' : 'badge-done'">
                        <text class="qty-text">剩余 {{item.enableQty}}</text>
                    </view>
                </view>
                <!-- 卡片内容 -->
                <view class="card-body">
                    <view class="info-grid">
                        <view class="info-item">
                            <text class="info-label">规格</text>
                            <text class="info-value">{{item.specs || '-'}}</text>
                        </view>
                        <view class="info-item">
                            <text class="info-label">批次</text>
                            <text class="info-value">{{item.batch || '-'}}</text>
                        </view>
                        <view class="info-item">
                            <text class="info-label">订单数量</text>
                            <text class="info-value highlight">{{item.anfme}}</text>
                        </view>
                        <view class="info-item">
                            <text class="info-label">已完成</text>
                            <text class="info-value">{{item.anfme - item.enableQty}}</text>
                        </view>
                    </view>
                    <!-- 进度条 -->
                    <view class="progress-wrap">
                        <view class="progress-bar">
                            <view class="progress-fill" :style="{width: getProgress(item) + '%'}"></view>
                        </view>
                        <text class="progress-text">{{getProgress(item)}}%</text>
                    </view>
                </view>
                <!-- 卡片底部 -->
                <view class="card-footer" v-if="item.enableQty > 0">
                    <text class="action-text">点击组托入库</text>
                    <uni-icons type="right" size="14" color="#0081ff"></uni-icons>
                </view>
                <view class="card-footer card-footer-done" v-else>
                    <text class="done-text">已完成</text>
                    <uni-icons type="checkmarkempty" size="14" color="#28a745"></uni-icons>
                </view>
            </view>
        </view>
        <!-- 空状态 -->
        <view class="empty-state" v-if="filterList.length === 0 && !loading">
            <uni-icons type="info" size="60" color="#CCCCCC"></uni-icons>
            <text class="empty-text">暂无明细数据</text>
        </view>
        <!-- 统计信息 -->
        <view class="stats-bar" v-if="menuList.length > 0">
            <view class="stats-item">
                <text class="stats-value">{{menuList.length}}</text>
                <text class="stats-label">总明细</text>
            </view>
            <view class="stats-divider"></view>
            <view class="stats-item">
                <text class="stats-value">{{pendingCount}}</text>
                <text class="stats-label">待处理</text>
            </view>
            <view class="stats-divider"></view>
            <view class="stats-item">
                <text class="stats-value">{{completedCount}}</text>
                <text class="stats-label">已完成</text>
            </view>
        </view>
    </view>
</template>
<script>
    import { request } from '@/common/request.js'
    export default {
        data() {
            return {
                data: '',
                condition: '',
                menuList: [],
                order: '',
                loading: false,
            }
        },
        computed: {
            // 过滤后的列表(优先显示有剩余数量的)
            filterList() {
                if (!this.condition.trim()) {
                    // 排序:有剩余数量的排前面
                    return [...this.menuList].sort((a, b) => {
                        if (a.enableQty > 0 && b.enableQty <= 0) return -1;
                        if (a.enableQty <= 0 && b.enableQty > 0) return 1;
                        return 0;
                    });
                }
                const keyword = this.condition.toLowerCase();
                return this.menuList.filter(item => {
                    return (item.matnr && item.matnr.toLowerCase().includes(keyword)) ||
                           (item.maktx && item.maktx.toLowerCase().includes(keyword)) ||
                           (item.batch && item.batch.toLowerCase().includes(keyword));
                });
            },
            // 待处理数量
            pendingCount() {
                return this.menuList.filter(item => item.enableQty > 0).length;
            },
            // 已完成数量
            completedCount() {
                return this.menuList.filter(item => item.enableQty <= 0).length;
            }
        },
        onLoad() {
            let that = this;
            const eventChannel = this.getOpenerEventChannel();
            if (eventChannel) {
                eventChannel.on('data', function(data) {
                    that.order = data.data;
                    that.getOrderNoList(that.order);
                });
            }
        },
        onShow() {
            if (this.order) {
                this.getOrderNoList(this.order);
            }
        },
        methods: {
            // 计算进度
            getProgress(item) {
                if (!item.anfme || item.anfme === 0) return 0;
                const progress = ((item.anfme - item.enableQty) / item.anfme * 100).toFixed(0);
                return Math.min(100, Math.max(0, progress));
            },
            // 搜索
            async search() {
                if (!this.condition.trim()) {
                    this.getOrderNoList(this.order);
                    return;
                }
                this.loading = true;
                try {
                    const res = await request('/orderDetl/search/pda/auth', {
                        condition: this.condition,
                        order: this.order.code
                    }, 'POST', true);
                    if (res.code === 200) {
                        this.menuList = res.data || [];
                    } else if (res.code === 403) {
                        uni.showToast({ title: res.msg, icon: "none", position: 'top' });
                        setTimeout(() => {
                            uni.reLaunch({ url: '../login/login' });
                        }, 1000);
                    } else {
                        uni.showToast({ title: res.msg, icon: "none", position: 'top' });
                    }
                } catch (err) {
                    // request.js 已经处理了错误提示
                } finally {
                    this.loading = false;
                }
            },
            // 取消搜索
            onCancelSearch() {
                this.condition = '';
                this.getOrderNoList(this.order);
            },
            // 获取订单明细列表
            async getOrderNoList(order) {
                if (!order || !order.code) return;
                this.loading = true;
                try {
                    const res = await request('/orderOut/detlList', {
                        orderNo: order.code
                    }, 'GET', true);
                    if (res.code === 200) {
                        this.menuList = res.data || [];
                    } else {
                        this.menuList = res.data || [];
                    }
                } catch (err) {
                    // request.js 已经处理了错误提示
                } finally {
                    this.loading = false;
                }
            },
            // 选择明细进行组托
            chose(item) {
                if (item.enableQty <= 0) {
                    uni.showToast({ title: '该明细已完成', icon: "none", position: 'top' });
                    return;
                }
                let that = this;
                uni.navigateTo({
                    url: "../order/orderPakin2",
                    success: function(res) {
                        res.eventChannel.emit('orderItem', {
                            item: item
                        });
                    },
                    events: {
                        acceptDataFromOpenedPage: function(data) {
                            // 返回后刷新数据
                        },
                    },
                });
            }
        }
    }
</script>
<style>
    /* 引入公共样式 */
    @import url('@/static/css/common.scss');
    .page-container {
        padding-bottom: 120rpx;
    }
    /* 订单头部 */
    .order-header {
        background: linear-gradient(135deg, #0081ff 0%, #1890ff 100%);
        padding: 16rpx 20rpx;
    }
    .header-content {
        background: rgba(255, 255, 255, 0.15);
        border-radius: 10rpx;
        padding: 12rpx 16rpx;
    }
    .header-row {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 4rpx 0;
    }
    .header-label {
        font-size: 24rpx;
        color: rgba(255, 255, 255, 0.7);
    }
    .header-value {
        font-size: 26rpx;
        color: #ffffff;
        font-weight: 500;
    }
    /* 搜索栏 */
    .search-bar {
        padding: 0rpx 8rpx;
        background: #ffffff;
        box-shadow: 0 2rpx 8rpx rgba(0, 129, 255, 0.08);
    }
    /* 明细列表 */
    .detl-list {
        padding: 0 20rpx;
    }
    .detl-card {
        background: #ffffff;
        border-radius: 12rpx;
        margin-top: 12rpx;
        box-shadow: 0 2rpx 12rpx rgba(0, 129, 255, 0.08);
        overflow: hidden;
        transition: transform 0.2s ease;
        border: 1rpx solid #e4e7ed;
    }
    .detl-card:active {
        transform: scale(0.98);
    }
    /* 卡片头部 */
    .card-header {
        display: flex;
        justify-content: space-between;
        align-items: flex-start;
        padding: 14rpx 16rpx;
        border-bottom: 1rpx solid #f0f0f0;
    }
    .mat-info {
        flex: 1;
        padding-right: 12rpx;
    }
    .mat-code {
        font-size: 26rpx;
        color: #303133;
        font-weight: 600;
        display: block;
    }
    .mat-name {
        font-size: 22rpx;
        color: #909399;
        margin-top: 4rpx;
        display: block;
    }
    .qty-badge {
        padding: 4rpx 12rpx;
        border-radius: 16rpx;
        flex-shrink: 0;
    }
    .badge-active {
        background: linear-gradient(135deg, #0081ff 0%, #1890ff 100%);
    }
    .badge-done {
        background: #e8f5e9;
    }
    .qty-text {
        font-size: 20rpx;
        font-weight: 500;
        color: #ffffff;
    }
    .badge-done .qty-text {
        color: #28a745;
    }
    /* 卡片内容 */
    .card-body {
        padding: 12rpx 16rpx;
    }
    .info-grid {
        display: flex;
        flex-wrap: wrap;
    }
    .info-item {
        width: 50%;
        margin-bottom: 8rpx;
    }
    .info-label {
        font-size: 20rpx;
        color: #909399;
        display: block;
    }
    .info-value {
        font-size: 24rpx;
        color: #303133;
        font-weight: 500;
        display: block;
        margin-top: 2rpx;
    }
    .info-value.highlight {
        color: #0081ff;
        font-weight: 600;
    }
    /* 进度条 */
    .progress-wrap {
        display: flex;
        align-items: center;
        margin-top: 8rpx;
    }
    .progress-bar {
        flex: 1;
        height: 8rpx;
        background: #e8e8e8;
        border-radius: 4rpx;
        overflow: hidden;
    }
    .progress-fill {
        height: 100%;
        background: linear-gradient(90deg, #0081ff 0%, #1890ff 100%);
        border-radius: 4rpx;
        transition: width 0.3s ease;
    }
    .progress-text {
        font-size: 20rpx;
        color: #909399;
        margin-left: 12rpx;
        min-width: 50rpx;
        text-align: right;
    }
    /* 卡片底部 */
    .card-footer {
        display: flex;
        align-items: center;
        justify-content: flex-end;
        padding: 12rpx 16rpx;
        border-top: 1rpx solid #f0f0f0;
        background: #fafafa;
    }
    .card-footer-done {
        background: #f0fff4;
    }
    .action-text {
        font-size: 24rpx;
        color: #0081ff;
        margin-right: 6rpx;
        font-weight: 500;
    }
    .done-text {
        font-size: 24rpx;
        color: #28a745;
        margin-right: 6rpx;
    }
    /* 空状态 */
    .empty-state {
        padding: 60rpx 0;
    }
    .empty-text {
        margin-top: 20rpx;
    }
    /* 统计栏 */
    .stats-bar {
        position: fixed;
        bottom: 0;
        left: 0;
        right: 0;
        display: flex;
        align-items: center;
        justify-content: space-around;
        background: #ffffff;
        padding: 16rpx 0;
        box-shadow: 0 -2rpx 12rpx rgba(0, 0, 0, 0.06);
    }
    .stats-item {
        display: flex;
        flex-direction: column;
        align-items: center;
        flex: 1;
    }
    .stats-value {
        font-size: 32rpx;
        color: #303133;
        font-weight: 600;
    }
    .stats-label {
        font-size: 20rpx;
        color: #909399;
        margin-top: 4rpx;
    }
    .stats-divider {
        width: 1rpx;
        height: 50rpx;
        background: #e8e8e8;
    }
</style>
pages/outbound/orderOut/orderList.vue
@@ -10,12 +10,12 @@
            <view class="order-card" v-for="(item,i) in matList" :key="i" @click="toPrint(item)">
                <!-- 卡片头部 -->
                <view class="card-header">
                    <view class="order-badge" :class="getSettleClass(item.settle)">
                        <text class="badge-text">{{item.settle$ || '未知'}}</text>
                    <view class="order-badge" :class="getSettleClass(item.exceStatus)">
                        <text class="badge-text">{{item.exceStatus$ || '未知'}}</text>
                    </view>
                    <view class="order-no">
                        <text class="order-no-label">单据号</text>
                        <text class="order-no-value">{{item.orderNo}}</text>
                        <text class="order-no-value">{{item.code}}</text>
                    </view>
                </view>
                
@@ -24,14 +24,25 @@
                    <view class="info-row">
                        <view class="info-item">
                            <text class="info-label">单据类型</text>
                            <text class="info-value">{{item.docType$ || '-'}}</text>
                            <text class="info-value">{{item.wkType$ || '-'}}</text>
                        </view>
                        <!-- <view class="info-item">
                            <text class="info-label">应出数量</text>
                            <text class="info-value">{{item.anfme || '-'}}</text>
                        </view> -->
                    </view>
                    <view class="info-row">
                        <view class="info-item">
                            <text class="info-label">应出数量</text>
                            <text class="info-value">{{item.anfme || '-'}}</text>
                        </view>
                        <view class="info-item">
                            <text class="info-label">仓库</text>
                            <text class="info-value">{{item.itemName || '-'}}</text>
                            <text class="info-label">完成数量</text>
                            <text class="info-value">{{item.qty || '-'}}</text>
                        </view>
                    </view>
                </view>
                
                <!-- 卡片底部 -->
                <view class="card-footer">
@@ -54,6 +65,7 @@
</template>
<script>
    import { request } from '@/common/request.js'
    export default {
        data() {
            return {
@@ -62,8 +74,7 @@
                condition: '',
                loading: false,
                curr: 1,
                baseUrl: '',
                token: '',
                limit:5,
                status: 'more',
                contentText: {
                    contentdown: '上拉加载更多',
@@ -96,8 +107,6 @@
            }
        },
        onShow() {
            this.baseUrl = uni.getStorageSync('baseUrl');
            this.token = uni.getStorageSync('token');
            // 每次进入页面重新加载
            this.refreshData();
        },
@@ -115,90 +124,72 @@
                this.fetchOrderList(false);
            },
            // 获取订单列表
            fetchOrderList(isRefresh) {
                let that = this;
                uni.request({
                    url: that.baseUrl + '/order/pakin/order/list/pda/page/auth',
                    data: {
                        curr: that.curr,
                        limit: 20,
                        tagId: that.tagIdNow
                    },
                    method: "GET",
                    header: {
                        'token': uni.getStorageSync('token'),
                    },
                    success(result) {
                        var res = result.data;
                        if (res.code === 200) {
                            let records = res.data.records || [];
                            if (records.length > 0) {
                                if (isRefresh) {
                                    that.matList = records;
                                } else {
                                    that.matList = that.matList.concat(records);
                                }
                                that.curr = that.curr + 1;
                                that.status = 'more';
            async fetchOrderList(isRefresh) {
                try {
                    const res = await request('/orderOut/list', {
                        curr: this.curr,
                        limit: this.limit,
                        orderNo: this.condition
                    }, 'GET', true);
                    if (res.code === 200) {
                        let records = res.data.records || [];
                        if (records.length > 0) {
                            if (isRefresh) {
                                this.matList = records;
                            } else {
                                that.status = 'noMore';
                                this.matList = this.matList.concat(records);
                            }
                        } else if (res.code === 403) {
                            uni.showToast({ title: res.msg, icon: "none", position: 'top' });
                            setTimeout(() => {
                                uni.reLaunch({ url: '../login/login' });
                            }, 1000);
                            this.curr = this.curr + 1;
                            this.status = 'more';
                        } else {
                            uni.showToast({ title: res.msg, icon: "none", position: 'top' });
                            this.status = 'noMore';
                        }
                    },
                    fail(err) {
                        uni.showToast({ title: '网络请求失败', icon: "none", position: 'top' });
                    },
                    complete() {
                        that.loading = false;
                        uni.stopPullDownRefresh();
                    } else if (res.code === 403) {
                        uni.showToast({ title: res.msg, icon: "none", position: 'top' });
                        setTimeout(() => {
                            uni.reLaunch({ url: '../login/login' });
                        }, 1000);
                    } else {
                        uni.showToast({ title: res.msg, icon: "none", position: 'top' });
                    }
                });
                } catch (err) {
                    // request.js 已经处理了错误提示
                } finally {
                    this.loading = false;
                    uni.stopPullDownRefresh();
                }
            },
            // 搜索
            search() {
            async search() {
                if (!this.condition.trim()) {
                    this.refreshData();
                    return;
                }
                let that = this;
                that.loading = true;
                uni.request({
                    url: that.baseUrl + '/order/search/pda/auth',
                    data: {
                        condition: that.condition
                    },
                    method: "GET",
                    header: {
                        'token': uni.getStorageSync('token'),
                    },
                    success(result) {
                        var res = result.data;
                        if (res.code === 200) {
                            that.matList = res.data || [];
                            that.status = 'noMore';
                        } else if (res.code === 403) {
                            uni.showToast({ title: res.msg, icon: "none", position: 'top' });
                            setTimeout(() => {
                                uni.reLaunch({ url: '../login/login' });
                            }, 1000);
                        } else {
                            uni.showToast({ title: res.msg, icon: "none", position: 'top' });
                        }
                    },
                    fail() {
                        uni.showToast({ title: '搜索请求失败', icon: "none", position: 'top' });
                    },
                    complete() {
                        that.loading = false;
                this.loading = true;
                try {
                    const res = await request('/orderOut/list', {
                        curr: this.curr,
                        limit: this.limit,
                        orderNo: this.condition
                    }, 'GET', true);
                    if (res.code === 200) {
                        this.matList = res.data || [];
                        this.status = 'noMore';
                    } else if (res.code === 403) {
                        uni.showToast({ title: res.msg, icon: "none", position: 'top' });
                        setTimeout(() => {
                            uni.reLaunch({ url: '../login/login' });
                        }, 1000);
                    } else {
                        uni.showToast({ title: res.msg, icon: "none", position: 'top' });
                    }
                });
                } catch (err) {
                    // request.js 已经处理了错误提示
                } finally {
                    this.loading = false;
                }
            },
            // 取消搜索
            onCancelSearch() {
@@ -220,7 +211,7 @@
            toPrint(item) {
                let that = this;
                uni.navigateTo({
                    url: "../order/orderDetlList",
                    url: "./orderDetlList",
                    success: function(res) {
                        res.eventChannel.emit('data', {
                            data: item
@@ -243,14 +234,14 @@
    
    .page-container {
        min-height: 100vh;
        background: linear-gradient(135deg, #f5f7fa 0%, #e4e8eb 100%);
        background: #f5f7fa;
        padding-bottom: 20rpx;
    }
    
    .search-bar {
        padding: 0rpx 14rpx;
        padding: 0rpx 8rpx;
        background: #ffffff;
        box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
        box-shadow: 0 2rpx 12rpx rgba(0, 129, 255, 0.08);
    }
    
    .order-list {
@@ -261,21 +252,22 @@
        background: #ffffff;
        border-radius: 16rpx;
        margin-top: 20rpx;
        box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
        box-shadow: 0 4rpx 20rpx rgba(0, 129, 255, 0.1);
        overflow: hidden;
        transition: transform 0.2s ease, box-shadow 0.2s ease;
        border: 1rpx solid #e4e7ed;
    }
    
    .order-card:active {
        transform: scale(0.98);
        box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.12);
        box-shadow: 0 2rpx 10rpx rgba(0, 129, 255, 0.15);
    }
    
    .card-header {
        display: flex;
        align-items: center;
        padding: 24rpx 28rpx;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        background: linear-gradient(135deg, #0081ff 0%, #1890ff 100%);
    }
    
    .order-badge {
static/css/common.scss
@@ -26,4 +26,428 @@
            margin-bottom: 20upx;
        }
    }
}
}
/**
 * 公共样式 - 基于 agv_start.vue 抽离
 * 适用于:agv_start.vue, orderPakin2.vue, orderDetlList.vue 等页面
 */
/* ==================== 页面基础样式 ==================== */
page {
    height: 100%;
    background: #f5f7fa;
}
.page-container {
    min-height: 100vh;
    background: linear-gradient(135deg, #f5f7fa 0%, #e4e8eb 100%);
    padding-bottom: 110rpx;
    box-sizing: border-box;
}
/* ==================== 表单区域样式 ==================== */
.form-section {
    background: #ffffff;
    padding: 12rpx 20rpx;
    box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
}
.form-item {
    display: flex;
    align-items: center;
    padding: 12rpx 0;
    border-bottom: 1rpx solid #f0f0f0;
}
.form-item:last-child {
    border-bottom: none;
}
.form-label {
    display: flex;
    align-items: center;
    flex-shrink: 0;
    white-space: nowrap;
    margin-right: 16rpx;
}
.label-text {
    font-size: 26rpx;
    color: #303133;
    margin-left: 6rpx;
}
.form-input-wrap {
    flex: 1;
    display: flex;
    align-items: center;
    background: #f5f7fa;
    border-radius: 6rpx;
    padding: 0 16rpx;
    height: 60rpx;
}
.form-input {
    flex: 1;
    height: 60rpx;
    font-size: 26rpx;
    color: #303133;
}
/* Picker 样式 */
.picker-full {
    flex: 1;
    width: 100%;
}
.picker-value {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 60rpx;
    font-size: 26rpx;
    color: #303133;
}
.picker-value text {
    flex: 1;
}
/* ==================== 列表头部样式 ==================== */
.list-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 16rpx 20rpx;
    background: #ffffff;
    margin-top: 12rpx;
    box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
}
.header-left {
    display: flex;
    align-items: center;
}
.header-title {
    font-size: 28rpx;
    color: #303133;
    font-weight: 600;
}
.count-badge {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    border-radius: 16rpx;
    padding: 2rpx 12rpx;
    margin-left: 12rpx;
}
.count-text {
    font-size: 20rpx;
    color: #ffffff;
    font-weight: 500;
}
/* ==================== 商品卡片样式 ==================== */
.list-container {
    padding: 0 20rpx;
}
.mat-card {
    background: #ffffff;
    border-radius: 12rpx;
    margin-top: 12rpx;
    box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
    overflow: hidden;
}
.card-top {
    display: flex;
    align-items: center;
    padding: 14rpx 16rpx;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.card-index {
    width: 36rpx;
    height: 36rpx;
    background: rgba(255, 255, 255, 0.25);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 22rpx;
    color: #ffffff;
    font-weight: 600;
    margin-right: 12rpx;
}
.mat-code-wrap {
    flex: 1;
}
.mat-code {
    font-size: 26rpx;
    color: #ffffff;
    font-weight: 600;
}
.qty-badge {
    background: rgba(255, 255, 255, 0.3);
    padding: 4rpx 14rpx;
    border-radius: 16rpx;
}
.qty-text {
    font-size: 24rpx;
    color: #ffffff;
    font-weight: 600;
}
/* ==================== 卡片内容样式 ==================== */
.card-content {
    padding: 12rpx 16rpx;
}
.info-row {
    display: flex;
    margin-bottom: 8rpx;
}
.info-row:last-child {
    margin-bottom: 0;
}
.info-col {
    flex: 1;
}
.info-col.half {
    width: 50%;
    flex: none;
}
.info-label {
    font-size: 20rpx;
    color: #909399;
    display: block;
}
.info-value {
    font-size: 24rpx;
    color: #303133;
    display: block;
    margin-top: 2rpx;
}
.info-value.highlight {
    color: #667eea;
    font-weight: 500;
}
.info-value.qty {
    font-size: 28rpx;
    color: #303133;
    font-weight: 600;
}
/* ==================== 卡片操作按钮样式 ==================== */
.card-actions {
    display: flex;
    border-top: 1rpx solid #f0f0f0;
}
.action-btn {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 14rpx 0;
}
.edit-btn {
    border-right: 1rpx solid #f0f0f0;
}
.action-text {
    font-size: 24rpx;
    color: #667eea;
    margin-left: 6rpx;
}
.delete-text {
    color: #f56c6c;
}
/* ==================== 空状态样式 ==================== */
.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 80rpx 0;
}
.empty-text {
    font-size: 26rpx;
    color: #909399;
    margin-top: 16rpx;
}
.empty-hint {
    font-size: 22rpx;
    color: #c0c4cc;
    margin-top: 8rpx;
}
.bottom-placeholder {
    height: 20rpx;
}
/* ==================== 底部操作栏样式 ==================== */
.bottom-bar {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    display: flex;
    padding: 16rpx 20rpx;
    background: #ffffff;
    box-shadow: 0 -2rpx 12rpx rgba(0, 0, 0, 0.06);
}
.btn-reset {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 160rpx;
    height: 72rpx;
    background: #f5f7fa;
    border-radius: 36rpx;
    margin-right: 16rpx;
}
.btn-reset .btn-text {
    font-size: 26rpx;
    color: #909399;
    margin-left: 6rpx;
}
.btn-submit {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    height: 72rpx;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    border-radius: 36rpx;
}
.btn-submit .btn-text {
    font-size: 28rpx;
    color: #ffffff;
    font-weight: 500;
    margin-left: 6rpx;
}
.btn-disabled {
    background: #c0c4cc;
    opacity: 0.6;
}
/* ==================== 弹窗样式 ==================== */
.popup-card {
    width: 600rpx;
    background: #ffffff;
    border-radius: 16rpx;
    overflow: hidden;
}
.popup-header {
    padding: 24rpx;
    text-align: center;
    border-bottom: 1rpx solid #f0f0f0;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.popup-title {
    font-size: 30rpx;
    color: #ffffff;
    font-weight: 600;
}
.popup-body {
    padding: 24rpx;
}
.popup-row {
    display: flex;
    align-items: center;
    margin-bottom: 20rpx;
    height: 70rpx;
}
.popup-row:last-child {
    margin-bottom: 0;
}
.popup-label {
    width: 80rpx;
    font-size: 26rpx;
    color: #606266;
    flex-shrink: 0;
}
.popup-value {
    flex: 1;
    height: 70rpx;
    background: #f5f7fa;
    border-radius: 8rpx;
    padding: 0 16rpx;
    font-size: 26rpx;
    color: #303133;
    display: flex;
    align-items: center;
    box-sizing: border-box;
}
.popup-value.disabled {
    color: #909399;
    background: #f0f0f0;
}
.popup-value.input {
    padding: 0 16rpx;
}
.popup-value.number {
    justify-content: center;
    background: transparent;
    padding: 0;
}
.popup-footer {
    display: flex;
    border-top: 1rpx solid #f0f0f0;
}
.popup-btn {
    flex: 1;
    height: 90rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 28rpx;
}
.popup-btn.cancel {
    color: #909399;
    border-right: 1rpx solid #f0f0f0;
}
.popup-btn.confirm {
    color: #667eea;
    font-weight: 600;
}