|
@@ -4,23 +4,61 @@
|
|
|
<!-- 搜索栏 -->
|
|
<!-- 搜索栏 -->
|
|
|
<div class="search-bar">
|
|
<div class="search-bar">
|
|
|
<el-input v-model="queryParams.keyword" placeholder="搜索订单号" style="width: 200px" clearable @keyup.enter="handleQuery">
|
|
<el-input v-model="queryParams.keyword" placeholder="搜索订单号" style="width: 200px" clearable @keyup.enter="handleQuery">
|
|
|
- <template #prefix><el-icon><Search /></el-icon></template>
|
|
|
|
|
|
|
+ <template #prefix
|
|
|
|
|
+ ><el-icon><Search /></el-icon
|
|
|
|
|
+ ></template>
|
|
|
</el-input>
|
|
</el-input>
|
|
|
- <el-date-picker v-model="queryParams.dateRange" type="daterange" range-separator="—" start-placeholder="开始日期" end-placeholder="结束日期" style="width: 240px" />
|
|
|
|
|
|
|
+ <el-date-picker
|
|
|
|
|
+ v-model="queryParams.dateRange"
|
|
|
|
|
+ type="daterange"
|
|
|
|
|
+ range-separator="—"
|
|
|
|
|
+ start-placeholder="开始日期"
|
|
|
|
|
+ end-placeholder="结束日期"
|
|
|
|
|
+ style="width: 240px"
|
|
|
|
|
+ />
|
|
|
<el-button type="primary" @click="handleQuery">搜索</el-button>
|
|
<el-button type="primary" @click="handleQuery">搜索</el-button>
|
|
|
<el-button @click="handleReset">重置</el-button>
|
|
<el-button @click="handleReset">重置</el-button>
|
|
|
</div>
|
|
</div>
|
|
|
<!-- 筛选栏 -->
|
|
<!-- 筛选栏 -->
|
|
|
<div class="filter-bar">
|
|
<div class="filter-bar">
|
|
|
<span class="filter-label">下单部门</span>
|
|
<span class="filter-label">下单部门</span>
|
|
|
- <el-select v-model="queryParams.department" placeholder="请选择" style="width: 100px" clearable><el-option label="某某部门" value="某某部门" /></el-select>
|
|
|
|
|
|
|
+ <el-tree-select
|
|
|
|
|
+ v-model="queryParams.department"
|
|
|
|
|
+ style="width: 100px"
|
|
|
|
|
+ :data="deptList"
|
|
|
|
|
+ :props="{ value: 'deptId', label: 'deptName', children: 'children' }"
|
|
|
|
|
+ value-key="deptId"
|
|
|
|
|
+ placeholder="请选择"
|
|
|
|
|
+ check-strictly
|
|
|
|
|
+ :render-after-expand="false"
|
|
|
|
|
+ clearable
|
|
|
|
|
+ >
|
|
|
|
|
+ </el-tree-select>
|
|
|
<span class="filter-label">状态</span>
|
|
<span class="filter-label">状态</span>
|
|
|
- <el-select v-model="queryParams.status" placeholder="请选择" style="width: 100px" clearable><el-option label="已完成" value="completed" /><el-option label="待收货" value="pending" /><el-option label="已取消" value="cancelled" /></el-select>
|
|
|
|
|
|
|
+ <el-select v-model="queryParams.status" placeholder="请选择" style="width: 100px" clearable>
|
|
|
|
|
+ <el-option v-for="dict in order_status" :key="dict.value" :label="dict.label" :value="dict.value" />
|
|
|
|
|
+ </el-select>
|
|
|
<span class="filter-label">支付方式</span>
|
|
<span class="filter-label">支付方式</span>
|
|
|
- <el-select v-model="queryParams.payType" placeholder="请选择" style="width: 100px" clearable><el-option label="在线支付" value="online" /><el-option label="账期支付" value="credit" /></el-select>
|
|
|
|
|
|
|
+ <el-select v-model="queryParams.payType" placeholder="请选择" style="width: 100px" clearable
|
|
|
|
|
+ ><el-option v-for="dict in pay_method" :key="dict.value" :label="dict.label" :value="dict.value"
|
|
|
|
|
+ /></el-select>
|
|
|
<div class="filter-right">
|
|
<div class="filter-right">
|
|
|
- <el-dropdown><el-button>订单导出 <el-icon><ArrowDown /></el-icon></el-button><template #dropdown><el-dropdown-menu><el-dropdown-item>导出Excel</el-dropdown-item><el-dropdown-item>导出PDF</el-dropdown-item></el-dropdown-menu></template></el-dropdown>
|
|
|
|
|
- <el-dropdown><el-button>订单打印 <el-icon><ArrowDown /></el-icon></el-button><template #dropdown><el-dropdown-menu><el-dropdown-item>打印订单</el-dropdown-item><el-dropdown-item>打印发货单</el-dropdown-item></el-dropdown-menu></template></el-dropdown>
|
|
|
|
|
|
|
+ <el-dropdown
|
|
|
|
|
+ ><el-button
|
|
|
|
|
+ >订单导出 <el-icon><ArrowDown /></el-icon></el-button
|
|
|
|
|
+ ><template #dropdown
|
|
|
|
|
+ ><el-dropdown-menu><el-dropdown-item>导出Excel</el-dropdown-item><el-dropdown-item>导出PDF</el-dropdown-item></el-dropdown-menu></template
|
|
|
|
|
+ ></el-dropdown
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-dropdown
|
|
|
|
|
+ ><el-button
|
|
|
|
|
+ >订单打印 <el-icon><ArrowDown /></el-icon></el-button
|
|
|
|
|
+ ><template #dropdown
|
|
|
|
|
+ ><el-dropdown-menu
|
|
|
|
|
+ ><el-dropdown-item>打印订单</el-dropdown-item><el-dropdown-item>打印发货单</el-dropdown-item></el-dropdown-menu
|
|
|
|
|
+ ></template
|
|
|
|
|
+ ></el-dropdown
|
|
|
|
|
+ >
|
|
|
<el-button>下载电子签单</el-button>
|
|
<el-button>下载电子签单</el-button>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
@@ -31,24 +69,34 @@
|
|
|
<el-icon><component :is="tab.icon" /></el-icon><span>{{ tab.label }}</span>
|
|
<el-icon><component :is="tab.icon" /></el-icon><span>{{ tab.label }}</span>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
- <el-button type="danger" link><el-icon><Delete /></el-icon>订单回收站</el-button>
|
|
|
|
|
|
|
+ <el-button type="danger" link
|
|
|
|
|
+ ><el-icon><Delete /></el-icon>订单回收站</el-button
|
|
|
|
|
+ >
|
|
|
</div>
|
|
</div>
|
|
|
<!-- 订单列表 -->
|
|
<!-- 订单列表 -->
|
|
|
<div class="order-list">
|
|
<div class="order-list">
|
|
|
- <div v-for="(order, orderIndex) in orderList" :key="order.id" class="order-card">
|
|
|
|
|
|
|
+ <div v-for="order in orderList" :key="order.id" class="order-card">
|
|
|
<div class="order-header">
|
|
<div class="order-header">
|
|
|
<el-checkbox v-model="order.checked" @change="handleOrderCheck" />
|
|
<el-checkbox v-model="order.checked" @change="handleOrderCheck" />
|
|
|
<span class="order-time">{{ order.orderTime }}</span>
|
|
<span class="order-time">{{ order.orderTime }}</span>
|
|
|
<span class="order-info">订单号:{{ order.orderNo }}</span>
|
|
<span class="order-info">订单号:{{ order.orderNo }}</span>
|
|
|
<span class="order-info">下单人:{{ order.orderPerson }}</span>
|
|
<span class="order-info">下单人:{{ order.orderPerson }}</span>
|
|
|
<span class="order-info">部门:{{ order.department }}</span>
|
|
<span class="order-info">部门:{{ order.department }}</span>
|
|
|
- <el-button type="primary" link class="expand-btn" @click="handleExpand(order)">{{ order.expanded ? '收起' : '展开' }} <el-icon><ArrowDown /></el-icon></el-button>
|
|
|
|
|
|
|
+ <el-button type="primary" link class="expand-btn" @click="handleExpand(order)"
|
|
|
|
|
+ >{{ order.expanded ? '收起' : '展开' }} <el-icon><ArrowDown /></el-icon
|
|
|
|
|
+ ></el-button>
|
|
|
</div>
|
|
</div>
|
|
|
<div v-if="order.countdown" class="countdown-bar">订单锁定剩余时间:{{ order.countdown }}</div>
|
|
<div v-if="order.countdown" class="countdown-bar">订单锁定剩余时间:{{ order.countdown }}</div>
|
|
|
<div class="product-list">
|
|
<div class="product-list">
|
|
|
- <div v-for="(item, itemIndex) in (order.expanded ? order.products : order.products.slice(0, 1))" :key="itemIndex" class="product-row">
|
|
|
|
|
|
|
+ <div v-for="(item, itemIndex) in order.expanded ? order.products : order.products.slice(0, 1)" :key="itemIndex" class="product-row">
|
|
|
<div class="product-cell product-info-cell">
|
|
<div class="product-cell product-info-cell">
|
|
|
- <div class="product-image"><el-image :src="item.image" fit="contain"><template #error><div class="image-placeholder"><el-icon :size="30" color="#ccc"><Picture /></el-icon></div></template></el-image></div>
|
|
|
|
|
|
|
+ <div class="product-image">
|
|
|
|
|
+ <el-image :src="item.image" fit="contain"
|
|
|
|
|
+ ><template #error
|
|
|
|
|
+ ><div class="image-placeholder">
|
|
|
|
|
+ <el-icon :size="30" color="#ccc"><Picture /></el-icon></div></template
|
|
|
|
|
+ ></el-image>
|
|
|
|
|
+ </div>
|
|
|
<div class="product-detail">
|
|
<div class="product-detail">
|
|
|
<div class="product-name">{{ item.name }}</div>
|
|
<div class="product-name">{{ item.name }}</div>
|
|
|
<div class="product-spec">{{ item.spec1 }} {{ item.spec2 }}</div>
|
|
<div class="product-spec">{{ item.spec1 }} {{ item.spec2 }}</div>
|
|
@@ -57,17 +105,32 @@
|
|
|
<div class="product-quantity">x{{ item.quantity }}</div>
|
|
<div class="product-quantity">x{{ item.quantity }}</div>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="product-cell amount-cell" v-if="itemIndex === 0">
|
|
<div class="product-cell amount-cell" v-if="itemIndex === 0">
|
|
|
- <div class="amount-info"><span class="label">支付款</span><span class="value highlight">¥{{ order.payAmount }}</span></div>
|
|
|
|
|
- <div class="amount-info"><span class="label">含运费:</span><span class="value">¥{{ order.freight }}</span></div>
|
|
|
|
|
|
|
+ <div class="amount-info">
|
|
|
|
|
+ <span class="label">支付款</span><span class="value highlight">¥{{ order.payAmount }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="amount-info">
|
|
|
|
|
+ <span class="label">含运费:</span><span class="value">¥{{ order.freight }}</span>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="product-cell status-cell" v-if="itemIndex === 0">
|
|
<div class="product-cell status-cell" v-if="itemIndex === 0">
|
|
|
<span class="status-text" :style="{ color: getStatusColor(order.status) }">{{ order.statusText }}</span>
|
|
<span class="status-text" :style="{ color: getStatusColor(order.status) }">{{ order.statusText }}</span>
|
|
|
<el-button type="primary" link size="small" @click="handleViewDetail(order)">查看订单轨迹</el-button>
|
|
<el-button type="primary" link size="small" @click="handleViewDetail(order)">查看订单轨迹</el-button>
|
|
|
- <template v-if="order.auditStatus"><span :class="['audit-status', getAuditStatusClass(order.auditStatus)]">{{ order.auditStatus }}</span><el-button type="primary" link size="small">查看审批流</el-button></template>
|
|
|
|
|
|
|
+ <template v-if="order.auditStatus"
|
|
|
|
|
+ ><span :class="['audit-status', getAuditStatusClass(order.auditStatus)]">{{ order.auditStatus }}</span
|
|
|
|
|
+ ><el-button type="primary" link size="small">查看审批流</el-button></template
|
|
|
|
|
+ >
|
|
|
<el-button v-if="order.fileCount" type="primary" link size="small">审核文件({{ order.fileCount }})</el-button>
|
|
<el-button v-if="order.fileCount" type="primary" link size="small">审核文件({{ order.fileCount }})</el-button>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="product-cell action-cell" v-if="itemIndex === 0">
|
|
<div class="product-cell action-cell" v-if="itemIndex === 0">
|
|
|
- <el-button v-for="action in getOrderActions(order)" :key="action" type="primary" link size="small" @click="handleAction(action, order)">{{ action }}</el-button>
|
|
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ v-for="action in getOrderActions(order)"
|
|
|
|
|
+ :key="action"
|
|
|
|
|
+ type="primary"
|
|
|
|
|
+ link
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ @click="handleAction(action, order)"
|
|
|
|
|
+ >{{ action }}</el-button
|
|
|
|
|
+ >
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
@@ -78,9 +141,20 @@
|
|
|
<div class="bottom-bar">
|
|
<div class="bottom-bar">
|
|
|
<div class="bottom-left"><el-checkbox v-model="selectAll" @change="handleSelectAll">全选</el-checkbox></div>
|
|
<div class="bottom-left"><el-checkbox v-model="selectAll" @change="handleSelectAll">全选</el-checkbox></div>
|
|
|
<div class="bottom-right">
|
|
<div class="bottom-right">
|
|
|
- <span class="selected-info">已勾选 <em>{{ selectedCount }}</em>/{{ totalOrders }}个订单 共计<em>¥{{ selectedAmount }}</em></span>
|
|
|
|
|
|
|
+ <span class="selected-info"
|
|
|
|
|
+ >已勾选 <em>{{ selectedCount }}</em
|
|
|
|
|
+ >/{{ totalOrders }}个订单 共计<em>¥{{ selectedAmount }}</em></span
|
|
|
|
|
+ >
|
|
|
<el-button>复制订单号</el-button>
|
|
<el-button>复制订单号</el-button>
|
|
|
- <el-dropdown><el-button>批量订单打印 <el-icon><ArrowDown /></el-icon></el-button><template #dropdown><el-dropdown-menu><el-dropdown-item>打印订单</el-dropdown-item><el-dropdown-item>打印发货单</el-dropdown-item></el-dropdown-menu></template></el-dropdown>
|
|
|
|
|
|
|
+ <el-dropdown
|
|
|
|
|
+ ><el-button
|
|
|
|
|
+ >批量订单打印 <el-icon><ArrowDown /></el-icon></el-button
|
|
|
|
|
+ ><template #dropdown
|
|
|
|
|
+ ><el-dropdown-menu
|
|
|
|
|
+ ><el-dropdown-item>打印订单</el-dropdown-item><el-dropdown-item>打印发货单</el-dropdown-item></el-dropdown-menu
|
|
|
|
|
+ ></template
|
|
|
|
|
+ ></el-dropdown
|
|
|
|
|
+ >
|
|
|
<el-button type="danger">批量确认收货</el-button>
|
|
<el-button type="danger">批量确认收货</el-button>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
@@ -90,19 +164,25 @@
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
|
-import { ref, reactive, computed, onMounted, watch } from 'vue'
|
|
|
|
|
-import { useRouter } from 'vue-router'
|
|
|
|
|
-import { Search, ArrowDown, Delete, Document, Clock, Box, CircleCheck, CircleClose, Picture } from '@element-plus/icons-vue'
|
|
|
|
|
-import type { CheckboxValueType } from 'element-plus'
|
|
|
|
|
-import { TablePagination } from '@/components'
|
|
|
|
|
-import { getOrderList, getOrderStatusStats, getOrderProducts, cancelOrder, deleteOrder } from '@/api/pc/enterprise/order'
|
|
|
|
|
-import type { OrderMain, OrderStatusStats } from '@/api/pc/enterprise/orderTypes'
|
|
|
|
|
-import { ElMessage, ElMessageBox } from 'element-plus'
|
|
|
|
|
|
|
+import { ref, reactive, computed, onMounted, watch } from 'vue';
|
|
|
|
|
+import { useRouter } from 'vue-router';
|
|
|
|
|
+import { Search, ArrowDown, Delete, Document, Clock, Box, CircleCheck, CircleClose, Picture } from '@element-plus/icons-vue';
|
|
|
|
|
+import type { CheckboxValueType } from 'element-plus';
|
|
|
|
|
+import { TablePagination } from '@/components';
|
|
|
|
|
+import { getOrderList, getOrderStatusStats, getOrderProducts, cancelOrder, deleteOrder } from '@/api/pc/enterprise/order';
|
|
|
|
|
+import type { OrderMain, OrderStatusStats } from '@/api/pc/enterprise/orderTypes';
|
|
|
|
|
+import { ElMessage, ElMessageBox } from 'element-plus';
|
|
|
|
|
+import { getDeptTree } from '@/api/pc/organization';
|
|
|
|
|
+import { DeptInfo } from '@/api/pc/organization/types';
|
|
|
|
|
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
|
|
|
+const { order_status, pay_method } = toRefs<any>(proxy?.useDict('order_status', 'pay_method'));
|
|
|
|
|
+
|
|
|
|
|
+const router = useRouter();
|
|
|
|
|
+const activeTab = ref('all');
|
|
|
|
|
+const selectAll = ref(false);
|
|
|
|
|
+const loading = ref(false);
|
|
|
|
|
|
|
|
-const router = useRouter()
|
|
|
|
|
-const activeTab = ref('all')
|
|
|
|
|
-const selectAll = ref(false)
|
|
|
|
|
-const loading = ref(false)
|
|
|
|
|
|
|
+const deptList = ref([]);
|
|
|
|
|
|
|
|
const statusTabs = [
|
|
const statusTabs = [
|
|
|
{ key: 'all', label: '全部订单', icon: Document },
|
|
{ key: 'all', label: '全部订单', icon: Document },
|
|
@@ -110,45 +190,45 @@ const statusTabs = [
|
|
|
{ key: 'shipping', label: '待收货', icon: Box },
|
|
{ key: 'shipping', label: '待收货', icon: Box },
|
|
|
{ key: 'completed', label: '已完成', icon: CircleCheck },
|
|
{ key: 'completed', label: '已完成', icon: CircleCheck },
|
|
|
{ key: 'cancelled', label: '已取消', icon: CircleClose }
|
|
{ key: 'cancelled', label: '已取消', icon: CircleClose }
|
|
|
-]
|
|
|
|
|
|
|
+];
|
|
|
|
|
|
|
|
// 监听标签页切换,重置页码并重新获取数据
|
|
// 监听标签页切换,重置页码并重新获取数据
|
|
|
watch(activeTab, (newTab) => {
|
|
watch(activeTab, (newTab) => {
|
|
|
- queryParams.pageNum = 1
|
|
|
|
|
|
|
+ queryParams.pageNum = 1;
|
|
|
// 根据标签页设置后端查询的状态参数
|
|
// 根据标签页设置后端查询的状态参数
|
|
|
if (newTab === 'all') {
|
|
if (newTab === 'all') {
|
|
|
- queryParams.status = ''
|
|
|
|
|
|
|
+ queryParams.status = '';
|
|
|
} else {
|
|
} else {
|
|
|
// 将前端标签页key映射回后端状态值
|
|
// 将前端标签页key映射回后端状态值
|
|
|
const tabToStatusMap: Record<string, string> = {
|
|
const tabToStatusMap: Record<string, string> = {
|
|
|
- 'preOrder': '0,1', // 待支付,待确认
|
|
|
|
|
- 'shipping': '2,3,4', // 待发货,部分发货,发货完成
|
|
|
|
|
- 'completed': '5', // 已完成
|
|
|
|
|
- 'cancelled': '6,7' // 已关闭,已取消
|
|
|
|
|
- }
|
|
|
|
|
- queryParams.status = tabToStatusMap[newTab] || ''
|
|
|
|
|
|
|
+ 'preOrder': '1', // 待支付,待确认
|
|
|
|
|
+ 'shipping': '2,3,4', // 待发货,部分发货,发货完成
|
|
|
|
|
+ 'completed': '5', // 已完成
|
|
|
|
|
+ 'cancelled': '7' // 已关闭,已取消
|
|
|
|
|
+ };
|
|
|
|
|
+ queryParams.status = tabToStatusMap[newTab] || '';
|
|
|
}
|
|
}
|
|
|
- fetchOrderList()
|
|
|
|
|
-})
|
|
|
|
|
|
|
+ fetchOrderList();
|
|
|
|
|
+});
|
|
|
|
|
|
|
|
-const queryParams = reactive({ keyword: '', dateRange: null, department: '', status: '', payType: '', pageNum: 1, pageSize: 5 })
|
|
|
|
|
-const total = ref(0)
|
|
|
|
|
-const allOrders = ref<any[]>([])
|
|
|
|
|
|
|
+const queryParams = reactive({ keyword: '', dateRange: null, department: '', status: '', payType: '', pageNum: 1, pageSize: 5 });
|
|
|
|
|
+const total = ref(0);
|
|
|
|
|
+const allOrders = ref<any[]>([]);
|
|
|
|
|
|
|
|
// 将后端状态映射为前端标签页key
|
|
// 将后端状态映射为前端标签页key
|
|
|
const mapBackendStatusToTabKey = (backendStatus: string) => {
|
|
const mapBackendStatusToTabKey = (backendStatus: string) => {
|
|
|
const statusMap: Record<string, string> = {
|
|
const statusMap: Record<string, string> = {
|
|
|
- '0': 'preOrder', // 待支付
|
|
|
|
|
- '1': 'preOrder', // 待确认
|
|
|
|
|
- '2': 'shipping', // 待发货
|
|
|
|
|
- '3': 'shipping', // 部分发货
|
|
|
|
|
- '4': 'shipping', // 发货完成
|
|
|
|
|
- '5': 'completed', // 已完成
|
|
|
|
|
- '6': 'cancelled', // 已关闭
|
|
|
|
|
- '7': 'cancelled' // 已取消
|
|
|
|
|
- }
|
|
|
|
|
- return statusMap[backendStatus] || backendStatus
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ '0': 'preOrder', // 待支付
|
|
|
|
|
+ '1': 'preOrder', // 待确认
|
|
|
|
|
+ '2': 'shipping', // 待发货
|
|
|
|
|
+ '3': 'shipping', // 部分发货
|
|
|
|
|
+ '4': 'shipping', // 发货完成
|
|
|
|
|
+ '5': 'completed', // 已完成
|
|
|
|
|
+ '6': 'cancelled', // 已关闭
|
|
|
|
|
+ '7': 'cancelled' // 已取消
|
|
|
|
|
+ };
|
|
|
|
|
+ return statusMap[backendStatus] || backendStatus;
|
|
|
|
|
+};
|
|
|
|
|
|
|
|
// 根据订单状态获取状态文本
|
|
// 根据订单状态获取状态文本
|
|
|
const getStatusText = (status: string) => {
|
|
const getStatusText = (status: string) => {
|
|
@@ -161,37 +241,57 @@ const getStatusText = (status: string) => {
|
|
|
'5': '已完成',
|
|
'5': '已完成',
|
|
|
'6': '已关闭',
|
|
'6': '已关闭',
|
|
|
'7': '已取消'
|
|
'7': '已取消'
|
|
|
|
|
+ };
|
|
|
|
|
+ return statusMap[status] || status;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 加载部门树
|
|
|
|
|
+const loadDeptTree = async () => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await getDeptTree();
|
|
|
|
|
+ if (res.code === 200 && res.data) {
|
|
|
|
|
+ deptList.value = res.data;
|
|
|
|
|
+
|
|
|
|
|
+ if (Array.isArray(res.data)) {
|
|
|
|
|
+ const treeData = proxy?.handleTree<DeptInfo>(res.data, 'deptId', 'parentId');
|
|
|
|
|
+ deptList.value = treeData || res.data;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ deptList.value = [];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('获取部门树失败:', error);
|
|
|
|
|
+ ElMessage.error('获取部门树失败');
|
|
|
}
|
|
}
|
|
|
- return statusMap[status] || status
|
|
|
|
|
-}
|
|
|
|
|
|
|
+};
|
|
|
|
|
|
|
|
// 获取订单列表
|
|
// 获取订单列表
|
|
|
const fetchOrderList = async () => {
|
|
const fetchOrderList = async () => {
|
|
|
- loading.value = true
|
|
|
|
|
|
|
+ loading.value = true;
|
|
|
try {
|
|
try {
|
|
|
const params: any = {
|
|
const params: any = {
|
|
|
pageNum: queryParams.pageNum,
|
|
pageNum: queryParams.pageNum,
|
|
|
pageSize: queryParams.pageSize
|
|
pageSize: queryParams.pageSize
|
|
|
- }
|
|
|
|
|
|
|
+ };
|
|
|
|
|
|
|
|
// 添加筛选条件
|
|
// 添加筛选条件
|
|
|
- if (queryParams.keyword) params.orderNo = queryParams.keyword
|
|
|
|
|
- if (queryParams.department) params.department = queryParams.department
|
|
|
|
|
- if (queryParams.status) params.orderStatuses = queryParams.status // 使用orderStatuses支持多状态查询
|
|
|
|
|
- if (queryParams.payType) params.payType = queryParams.payType
|
|
|
|
|
|
|
+ if (queryParams.keyword) params.orderNo = queryParams.keyword;
|
|
|
|
|
+ if (queryParams.department) params.department = queryParams.department;
|
|
|
|
|
+ if (queryParams.status) params.orderStatuses = queryParams.status; // 使用orderStatuses支持多状态查询
|
|
|
|
|
+ if (queryParams.payType) params.payType = queryParams.payType;
|
|
|
if (queryParams.dateRange && queryParams.dateRange.length === 2) {
|
|
if (queryParams.dateRange && queryParams.dateRange.length === 2) {
|
|
|
- params.beginTime = queryParams.dateRange[0]
|
|
|
|
|
- params.endTime = queryParams.dateRange[1]
|
|
|
|
|
|
|
+ params.beginTime = queryParams.dateRange[0];
|
|
|
|
|
+ params.endTime = queryParams.dateRange[1];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- console.log('发送到后端的参数:', params)
|
|
|
|
|
- const res = await getOrderList(params)
|
|
|
|
|
- console.log('后端返回的数据:', res)
|
|
|
|
|
|
|
+ console.log('发送到后端的参数:', params);
|
|
|
|
|
+ const res = await getOrderList(params);
|
|
|
|
|
+ console.log('后端返回的数据:', res);
|
|
|
if (res.code === 200) {
|
|
if (res.code === 200) {
|
|
|
// 调试:打印后端返回的第一条订单数据
|
|
// 调试:打印后端返回的第一条订单数据
|
|
|
if (res.rows && res.rows.length > 0) {
|
|
if (res.rows && res.rows.length > 0) {
|
|
|
- console.log('后端���回的订单状态值:', res.rows[0].orderStatus)
|
|
|
|
|
- console.log('完整的订单数据:', res.rows[0])
|
|
|
|
|
|
|
+ console.log('后端���回的订单状态值:', res.rows[0].orderStatus);
|
|
|
|
|
+ console.log('完整的订单数据:', res.rows[0]);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 将后端数据转换为前端需要的格式
|
|
// 将后端数据转换为前端需要的格式
|
|
@@ -211,52 +311,69 @@ const fetchOrderList = async () => {
|
|
|
checked: false,
|
|
checked: false,
|
|
|
expanded: false,
|
|
expanded: false,
|
|
|
products: [] // 商品信息需要单独加载
|
|
products: [] // 商品信息需要单独加载
|
|
|
- }))
|
|
|
|
|
|
|
+ }));
|
|
|
|
|
|
|
|
// 调试:打印转换后的订单状态
|
|
// 调试:打印转换后的订单状态
|
|
|
- console.log('转换后的订单状态分布:', allOrders.value.map(o => o.status))
|
|
|
|
|
|
|
+ console.log(
|
|
|
|
|
+ '转换后的订单状态分布:',
|
|
|
|
|
+ allOrders.value.map((o) => o.status)
|
|
|
|
|
+ );
|
|
|
|
|
|
|
|
- total.value = res.total || 0
|
|
|
|
|
|
|
+ total.value = res.total || 0;
|
|
|
}
|
|
}
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
- console.error('获取订单列表失败:', error)
|
|
|
|
|
|
|
+ console.error('获取订单列表失败:', error);
|
|
|
} finally {
|
|
} finally {
|
|
|
- loading.value = false
|
|
|
|
|
|
|
+ loading.value = false;
|
|
|
}
|
|
}
|
|
|
-}
|
|
|
|
|
|
|
+};
|
|
|
|
|
|
|
|
-const orderList = computed(() => allOrders.value)
|
|
|
|
|
-const totalOrders = computed(() => total.value)
|
|
|
|
|
-const selectedCount = computed(() => orderList.value.filter(o => o.checked).length)
|
|
|
|
|
-const selectedAmount = computed(() => orderList.value.filter(o => o.checked).reduce((sum, o) => sum + parseFloat(o.payAmount), 0).toFixed(2))
|
|
|
|
|
|
|
+const orderList = computed(() => allOrders.value);
|
|
|
|
|
+const totalOrders = computed(() => total.value);
|
|
|
|
|
+const selectedCount = computed(() => orderList.value.filter((o) => o.checked).length);
|
|
|
|
|
+const selectedAmount = computed(() =>
|
|
|
|
|
+ orderList.value
|
|
|
|
|
+ .filter((o) => o.checked)
|
|
|
|
|
+ .reduce((sum, o) => sum + parseFloat(o.payAmount), 0)
|
|
|
|
|
+ .toFixed(2)
|
|
|
|
|
+);
|
|
|
|
|
|
|
|
-const getStatusColor = (status: string) => ({ completed: '#67c23a', preOrder: '#e6a23c', shipping: '#409eff', cancelled: '#909399' }[status] || '#909399')
|
|
|
|
|
-const getAuditStatusClass = (auditStatus: string) => auditStatus === '审批通过' ? 'success' : auditStatus === '审批驳回' ? 'danger' : 'warning'
|
|
|
|
|
|
|
+const getStatusColor = (status: string) =>
|
|
|
|
|
+ ({ completed: '#67c23a', preOrder: '#e6a23c', shipping: '#409eff', cancelled: '#909399' })[status] || '#909399';
|
|
|
|
|
+const getAuditStatusClass = (auditStatus: string) => (auditStatus === '审批通过' ? 'success' : auditStatus === '审批驳回' ? 'danger' : 'warning');
|
|
|
const getOrderActions = (order: any) => {
|
|
const getOrderActions = (order: any) => {
|
|
|
- const actions: string[] = []
|
|
|
|
|
|
|
+ const actions: string[] = [];
|
|
|
switch (order.status) {
|
|
switch (order.status) {
|
|
|
- case 'preOrder': actions.push('再次购买', '加入采购单', '取消订单'); break
|
|
|
|
|
- case 'shipping': actions.push('再次购买', '加入采购单', '取消订单'); break
|
|
|
|
|
- case 'completed': actions.push('评价', '再次购买', '加入采购单', '申请售后', '删除订单', '查看发票'); break
|
|
|
|
|
- case 'cancelled': actions.push('再次购买', '加入采购单', '删除订单'); break
|
|
|
|
|
|
|
+ case 'preOrder':
|
|
|
|
|
+ actions.push('再次购买', '加入采购单', '取消订单');
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 'shipping':
|
|
|
|
|
+ actions.push('再次购买', '加入采购单', '取消订单');
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 'completed':
|
|
|
|
|
+ actions.push('评价', '再次购买', '加入采购单', '申请售后', '删除订单', '查看发票');
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 'cancelled':
|
|
|
|
|
+ actions.push('再次购买', '加入采购单', '删除订单');
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
- return actions
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ return actions;
|
|
|
|
|
+};
|
|
|
const handleExpand = async (order: any) => {
|
|
const handleExpand = async (order: any) => {
|
|
|
- console.log('handleExpand 被调用, order.id:', order.id, 'order.expanded:', order.expanded)
|
|
|
|
|
|
|
+ console.log('handleExpand 被调用, order.id:', order.id, 'order.expanded:', order.expanded);
|
|
|
|
|
|
|
|
- const orderIndex = allOrders.value.findIndex(o => o.id === order.id)
|
|
|
|
|
- if (orderIndex === -1) return
|
|
|
|
|
|
|
+ const orderIndex = allOrders.value.findIndex((o) => o.id === order.id);
|
|
|
|
|
+ if (orderIndex === -1) return;
|
|
|
|
|
|
|
|
- const currentOrder = allOrders.value[orderIndex]
|
|
|
|
|
- console.log('找到订单, currentOrder.expanded:', currentOrder.expanded)
|
|
|
|
|
|
|
+ const currentOrder = allOrders.value[orderIndex];
|
|
|
|
|
+ console.log('找到订单, currentOrder.expanded:', currentOrder.expanded);
|
|
|
|
|
|
|
|
if (!currentOrder.expanded && currentOrder.products.length === 0) {
|
|
if (!currentOrder.expanded && currentOrder.products.length === 0) {
|
|
|
- console.log('需要加载商品')
|
|
|
|
|
|
|
+ console.log('需要加载商品');
|
|
|
try {
|
|
try {
|
|
|
- const res = await getOrderProducts([order.id])
|
|
|
|
|
|
|
+ const res = await getOrderProducts([order.id]);
|
|
|
if (res.code === 200 && res.rows) {
|
|
if (res.code === 200 && res.rows) {
|
|
|
- console.log('后端返回的商品数据:', res.rows)
|
|
|
|
|
|
|
+ console.log('后端返回的商品数据:', res.rows);
|
|
|
const products = res.rows.map((p: any) => ({
|
|
const products = res.rows.map((p: any) => ({
|
|
|
image: p.productImage || '',
|
|
image: p.productImage || '',
|
|
|
name: p.productName || '',
|
|
name: p.productName || '',
|
|
@@ -264,104 +381,109 @@ const handleExpand = async (order: any) => {
|
|
|
spec2: p.productNo || '',
|
|
spec2: p.productNo || '',
|
|
|
price: p.orderPrice || 0,
|
|
price: p.orderPrice || 0,
|
|
|
quantity: p.orderQuantity || 0
|
|
quantity: p.orderQuantity || 0
|
|
|
- }))
|
|
|
|
|
- console.log('商品加载完成, products.length:', products.length)
|
|
|
|
|
|
|
+ }));
|
|
|
|
|
+ console.log('商品加载完成, products.length:', products.length);
|
|
|
|
|
|
|
|
// 替换整个数组以触发响应式更新
|
|
// 替换整个数组以触发响应式更新
|
|
|
- allOrders.value = allOrders.value.map((o, i) =>
|
|
|
|
|
- i === orderIndex ? { ...o, expanded: true, products } : o
|
|
|
|
|
- )
|
|
|
|
|
- console.log('已更新数组,expanded 设置为 true')
|
|
|
|
|
- return
|
|
|
|
|
|
|
+ allOrders.value = allOrders.value.map((o, i) => (i === orderIndex ? { ...o, expanded: true, products } : o));
|
|
|
|
|
+ console.log('已更新数组,expanded 设置为 true');
|
|
|
|
|
+ return;
|
|
|
}
|
|
}
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
- console.error('加载商品失败:', error)
|
|
|
|
|
- return
|
|
|
|
|
|
|
+ console.error('加载商品失败:', error);
|
|
|
|
|
+ return;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- console.log('切换 expanded 状态, 从', currentOrder.expanded, '到', !currentOrder.expanded)
|
|
|
|
|
|
|
+ console.log('切换 expanded 状态, 从', currentOrder.expanded, '到', !currentOrder.expanded);
|
|
|
// 替换整个数组以触发响应式更新
|
|
// 替换整个数组以触发响应式更新
|
|
|
- allOrders.value = allOrders.value.map((o, i) =>
|
|
|
|
|
- i === orderIndex ? { ...o, expanded: !o.expanded } : o
|
|
|
|
|
- )
|
|
|
|
|
- console.log('已更新数组,expanded 已切换')
|
|
|
|
|
-}
|
|
|
|
|
-const handleSelectAll = (val: CheckboxValueType) => { orderList.value.forEach(order => { order.checked = !!val }) }
|
|
|
|
|
-const handleOrderCheck = () => { selectAll.value = orderList.value.every(order => order.checked) }
|
|
|
|
|
-const handleViewDetail = (order: any) => { router.push(`/order/orderManage/detail/${order.orderNo}`) }
|
|
|
|
|
|
|
+ allOrders.value = allOrders.value.map((o, i) => (i === orderIndex ? { ...o, expanded: !o.expanded } : o));
|
|
|
|
|
+ console.log('已更新数组,expanded 已切换');
|
|
|
|
|
+};
|
|
|
|
|
+const handleSelectAll = (val: CheckboxValueType) => {
|
|
|
|
|
+ orderList.value.forEach((order) => {
|
|
|
|
|
+ order.checked = !!val;
|
|
|
|
|
+ });
|
|
|
|
|
+};
|
|
|
|
|
+const handleOrderCheck = () => {
|
|
|
|
|
+ selectAll.value = orderList.value.every((order) => order.checked);
|
|
|
|
|
+};
|
|
|
|
|
+const handleViewDetail = (order: any) => {
|
|
|
|
|
+ router.push(`/order/orderManage/detail/${order.orderNo}`);
|
|
|
|
|
+};
|
|
|
const handleQuery = () => {
|
|
const handleQuery = () => {
|
|
|
- queryParams.pageNum = 1
|
|
|
|
|
- fetchOrderList()
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ queryParams.pageNum = 1;
|
|
|
|
|
+ fetchOrderList();
|
|
|
|
|
+};
|
|
|
const handleReset = () => {
|
|
const handleReset = () => {
|
|
|
- queryParams.keyword = ''
|
|
|
|
|
- queryParams.dateRange = null
|
|
|
|
|
- queryParams.department = ''
|
|
|
|
|
- queryParams.payType = ''
|
|
|
|
|
- queryParams.pageNum = 1
|
|
|
|
|
- fetchOrderList()
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ queryParams.keyword = '';
|
|
|
|
|
+ queryParams.dateRange = null;
|
|
|
|
|
+ queryParams.department = '';
|
|
|
|
|
+ queryParams.payType = '';
|
|
|
|
|
+ queryParams.pageNum = 1;
|
|
|
|
|
+ fetchOrderList();
|
|
|
|
|
+};
|
|
|
const handleAction = (action: string, order: any) => {
|
|
const handleAction = (action: string, order: any) => {
|
|
|
switch (action) {
|
|
switch (action) {
|
|
|
case '取消订单':
|
|
case '取消订单':
|
|
|
- handleCancelOrder(order)
|
|
|
|
|
- break
|
|
|
|
|
|
|
+ handleCancelOrder(order);
|
|
|
|
|
+ break;
|
|
|
case '删除订单':
|
|
case '删除订单':
|
|
|
- handleDeleteOrder(order)
|
|
|
|
|
- break
|
|
|
|
|
|
|
+ handleDeleteOrder(order);
|
|
|
|
|
+ break;
|
|
|
case '查看详情':
|
|
case '查看详情':
|
|
|
- handleViewDetail(order)
|
|
|
|
|
- break
|
|
|
|
|
|
|
+ handleViewDetail(order);
|
|
|
|
|
+ break;
|
|
|
default:
|
|
default:
|
|
|
- ElMessage.info(`${action}功能开发中`)
|
|
|
|
|
|
|
+ ElMessage.info(`${action}功能开发中`);
|
|
|
}
|
|
}
|
|
|
-}
|
|
|
|
|
|
|
+};
|
|
|
const handleCancelOrder = async (order: any) => {
|
|
const handleCancelOrder = async (order: any) => {
|
|
|
try {
|
|
try {
|
|
|
await ElMessageBox.confirm('确定要取消该订单吗?', '提示', {
|
|
await ElMessageBox.confirm('确定要取消该订单吗?', '提示', {
|
|
|
confirmButtonText: '确定',
|
|
confirmButtonText: '确定',
|
|
|
cancelButtonText: '取消',
|
|
cancelButtonText: '取消',
|
|
|
type: 'warning'
|
|
type: 'warning'
|
|
|
- })
|
|
|
|
|
- const res = await cancelOrder({ id: order.id, orderStatus: '7' })
|
|
|
|
|
|
|
+ });
|
|
|
|
|
+ const res = await cancelOrder({ id: order.id, orderStatus: '7' });
|
|
|
if (res.code === 200) {
|
|
if (res.code === 200) {
|
|
|
- ElMessage.success('订单已取消')
|
|
|
|
|
- fetchOrderList()
|
|
|
|
|
|
|
+ ElMessage.success('订单已取消');
|
|
|
|
|
+ fetchOrderList();
|
|
|
} else {
|
|
} else {
|
|
|
- ElMessage.error(res.msg || '取消订单失败')
|
|
|
|
|
|
|
+ ElMessage.error(res.msg || '取消订单失败');
|
|
|
}
|
|
}
|
|
|
} catch (error: any) {
|
|
} catch (error: any) {
|
|
|
if (error !== 'cancel') {
|
|
if (error !== 'cancel') {
|
|
|
- ElMessage.error('取消订单失败')
|
|
|
|
|
|
|
+ ElMessage.error('取消订单失败');
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-}
|
|
|
|
|
|
|
+};
|
|
|
const handleDeleteOrder = async (order: any) => {
|
|
const handleDeleteOrder = async (order: any) => {
|
|
|
try {
|
|
try {
|
|
|
await ElMessageBox.confirm('确定要删除该订单吗?删除后无法恢复。', '提示', {
|
|
await ElMessageBox.confirm('确定要删除该订单吗?删除后无法恢复。', '提示', {
|
|
|
confirmButtonText: '确定',
|
|
confirmButtonText: '确定',
|
|
|
cancelButtonText: '取消',
|
|
cancelButtonText: '取消',
|
|
|
type: 'warning'
|
|
type: 'warning'
|
|
|
- })
|
|
|
|
|
- const res = await deleteOrder([order.id])
|
|
|
|
|
|
|
+ });
|
|
|
|
|
+ const res = await deleteOrder([order.id]);
|
|
|
if (res.code === 200) {
|
|
if (res.code === 200) {
|
|
|
- ElMessage.success('订单已删除')
|
|
|
|
|
- fetchOrderList()
|
|
|
|
|
|
|
+ ElMessage.success('订单已删除');
|
|
|
|
|
+ fetchOrderList();
|
|
|
} else {
|
|
} else {
|
|
|
- ElMessage.error(res.msg || '删除订单失败')
|
|
|
|
|
|
|
+ ElMessage.error(res.msg || '删除订单失败');
|
|
|
}
|
|
}
|
|
|
} catch (error: any) {
|
|
} catch (error: any) {
|
|
|
if (error !== 'cancel') {
|
|
if (error !== 'cancel') {
|
|
|
- ElMessage.error('删除订单失败')
|
|
|
|
|
|
|
+ ElMessage.error('删除订单失败');
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-}
|
|
|
|
|
|
|
+};
|
|
|
|
|
|
|
|
// 页面加载时获取订单列表
|
|
// 页面加载时获取订单列表
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
|
- fetchOrderList()
|
|
|
|
|
-})
|
|
|
|
|
|
|
+ loadDeptTree();
|
|
|
|
|
+ fetchOrderList();
|
|
|
|
|
+});
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
<style scoped lang="scss">
|
|
@@ -373,16 +495,217 @@ onMounted(() => {
|
|
|
flex-direction: column;
|
|
flex-direction: column;
|
|
|
max-height: calc(100vh - 120px); // 减去顶部导航栏和其他元素高度
|
|
max-height: calc(100vh - 120px); // 减去顶部导航栏和其他元素高度
|
|
|
}
|
|
}
|
|
|
-.page-title { font-size: 16px; font-weight: bold; display: flex; align-items: center; gap: 8px; margin-bottom: 20px; }
|
|
|
|
|
-.title-bar { display: inline-block; width: 3px; height: 16px; background: #e60012; border-radius: 2px; }
|
|
|
|
|
-.search-bar { display: flex; align-items: center; gap: 15px; margin-bottom: 15px; }
|
|
|
|
|
-.filter-bar { display: flex; align-items: center; gap: 10px; margin-bottom: 15px; .filter-label { font-size: 14px; color: #666; } .filter-right { flex: 1; display: flex; justify-content: flex-end; gap: 10px; } }
|
|
|
|
|
-.tab-bar { display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #eee; margin-bottom: 15px; .tab-left { display: flex; gap: 25px; } .tab-item { display: flex; align-items: center; gap: 5px; padding: 12px 0; cursor: pointer; color: #666; font-size: 14px; border-bottom: 2px solid transparent; margin-bottom: -1px; &:hover, &.active { color: #333; } &.active { border-bottom-color: #e60012; } } }
|
|
|
|
|
|
|
+.page-title {
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 8px;
|
|
|
|
|
+ margin-bottom: 20px;
|
|
|
|
|
+}
|
|
|
|
|
+.title-bar {
|
|
|
|
|
+ display: inline-block;
|
|
|
|
|
+ width: 3px;
|
|
|
|
|
+ height: 16px;
|
|
|
|
|
+ background: #e60012;
|
|
|
|
|
+ border-radius: 2px;
|
|
|
|
|
+}
|
|
|
|
|
+.search-bar {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 15px;
|
|
|
|
|
+ margin-bottom: 15px;
|
|
|
|
|
+}
|
|
|
|
|
+.filter-bar {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 10px;
|
|
|
|
|
+ margin-bottom: 15px;
|
|
|
|
|
+ .filter-label {
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ color: #666;
|
|
|
|
|
+ }
|
|
|
|
|
+ .filter-right {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: flex-end;
|
|
|
|
|
+ gap: 10px;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+.tab-bar {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ border-bottom: 1px solid #eee;
|
|
|
|
|
+ margin-bottom: 15px;
|
|
|
|
|
+ .tab-left {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 25px;
|
|
|
|
|
+ }
|
|
|
|
|
+ .tab-item {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 5px;
|
|
|
|
|
+ padding: 12px 0;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ color: #666;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ border-bottom: 2px solid transparent;
|
|
|
|
|
+ margin-bottom: -1px;
|
|
|
|
|
+ &:hover,
|
|
|
|
|
+ &.active {
|
|
|
|
|
+ color: #333;
|
|
|
|
|
+ }
|
|
|
|
|
+ &.active {
|
|
|
|
|
+ border-bottom-color: #e60012;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
.order-list {
|
|
.order-list {
|
|
|
flex: 1;
|
|
flex: 1;
|
|
|
overflow-y: auto;
|
|
overflow-y: auto;
|
|
|
margin-bottom: 15px;
|
|
margin-bottom: 15px;
|
|
|
- .order-card { border: 1px solid #eee; border-radius: 4px; margin-bottom: 15px; overflow: hidden; .order-header { display: flex; align-items: center; gap: 15px; padding: 12px 15px; background: #f9f9f9; border-bottom: 1px solid #eee; font-size: 13px; color: #666; .order-time { color: #333; } .expand-btn { margin-left: auto; } } .countdown-bar { background: #fff5e6; color: #e6a23c; padding: 8px 15px; font-size: 13px; border-bottom: 1px solid #eee; } .product-list { .product-row { display: flex; border-bottom: 1px solid #f5f5f5; &:last-child { border-bottom: none; } } .product-cell { padding: 15px; display: flex; flex-direction: column; justify-content: center; } .product-info-cell { flex: 1; flex-direction: row; align-items: center; gap: 15px; .product-image { width: 80px; height: 80px; background: #f5f5f5; border-radius: 4px; overflow: hidden; flex-shrink: 0; .el-image { width: 100%; height: 100%; } .image-placeholder { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; } } .product-detail { flex: 1; .product-name { font-size: 14px; color: #333; margin-bottom: 5px; line-height: 1.4; } .product-spec { font-size: 12px; color: #999; margin-bottom: 5px; } .product-price { font-size: 16px; font-weight: bold; color: #e60012; } } .product-quantity { font-size: 13px; color: #666; } } .amount-cell { width: 120px; border-left: 1px solid #f5f5f5; .amount-info { margin-bottom: 5px; .label { font-size: 12px; color: #999; } .value { font-size: 14px; color: #333; &.highlight { font-size: 16px; font-weight: bold; color: #e60012; } } } } .status-cell { width: 120px; border-left: 1px solid #f5f5f5; align-items: flex-start; gap: 5px; .status-text { font-size: 14px; font-weight: 500; } .audit-status { font-size: 12px; &.success { color: #e60012; } &.warning { color: #e6a23c; } &.danger { color: #e60012; } } } .action-cell { width: 100px; border-left: 1px solid #f5f5f5; align-items: flex-start; gap: 3px; } } } }
|
|
|
|
|
|
|
+ .order-card {
|
|
|
|
|
+ border: 1px solid #eee;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+ margin-bottom: 15px;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ .order-header {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 15px;
|
|
|
|
|
+ padding: 12px 15px;
|
|
|
|
|
+ background: #f9f9f9;
|
|
|
|
|
+ border-bottom: 1px solid #eee;
|
|
|
|
|
+ font-size: 13px;
|
|
|
|
|
+ color: #666;
|
|
|
|
|
+ .order-time {
|
|
|
|
|
+ color: #333;
|
|
|
|
|
+ }
|
|
|
|
|
+ .expand-btn {
|
|
|
|
|
+ margin-left: auto;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .countdown-bar {
|
|
|
|
|
+ background: #fff5e6;
|
|
|
|
|
+ color: #e6a23c;
|
|
|
|
|
+ padding: 8px 15px;
|
|
|
|
|
+ font-size: 13px;
|
|
|
|
|
+ border-bottom: 1px solid #eee;
|
|
|
|
|
+ }
|
|
|
|
|
+ .product-list {
|
|
|
|
|
+ .product-row {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ border-bottom: 1px solid #f5f5f5;
|
|
|
|
|
+ &:last-child {
|
|
|
|
|
+ border-bottom: none;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .product-cell {
|
|
|
|
|
+ padding: 15px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ }
|
|
|
|
|
+ .product-info-cell {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ flex-direction: row;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 15px;
|
|
|
|
|
+ .product-image {
|
|
|
|
|
+ width: 80px;
|
|
|
|
|
+ height: 80px;
|
|
|
|
|
+ background: #f5f5f5;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ .el-image {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ }
|
|
|
|
|
+ .image-placeholder {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .product-detail {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ .product-name {
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ color: #333;
|
|
|
|
|
+ margin-bottom: 5px;
|
|
|
|
|
+ line-height: 1.4;
|
|
|
|
|
+ }
|
|
|
|
|
+ .product-spec {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: #999;
|
|
|
|
|
+ margin-bottom: 5px;
|
|
|
|
|
+ }
|
|
|
|
|
+ .product-price {
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ color: #e60012;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .product-quantity {
|
|
|
|
|
+ font-size: 13px;
|
|
|
|
|
+ color: #666;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .amount-cell {
|
|
|
|
|
+ width: 120px;
|
|
|
|
|
+ border-left: 1px solid #f5f5f5;
|
|
|
|
|
+ .amount-info {
|
|
|
|
|
+ margin-bottom: 5px;
|
|
|
|
|
+ .label {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: #999;
|
|
|
|
|
+ }
|
|
|
|
|
+ .value {
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ color: #333;
|
|
|
|
|
+ &.highlight {
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ color: #e60012;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .status-cell {
|
|
|
|
|
+ width: 120px;
|
|
|
|
|
+ border-left: 1px solid #f5f5f5;
|
|
|
|
|
+ align-items: flex-start;
|
|
|
|
|
+ gap: 5px;
|
|
|
|
|
+ .status-text {
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ }
|
|
|
|
|
+ .audit-status {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ &.success {
|
|
|
|
|
+ color: #e60012;
|
|
|
|
|
+ }
|
|
|
|
|
+ &.warning {
|
|
|
|
|
+ color: #e6a23c;
|
|
|
|
|
+ }
|
|
|
|
|
+ &.danger {
|
|
|
|
|
+ color: #e60012;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .action-cell {
|
|
|
|
|
+ width: 100px;
|
|
|
|
|
+ border-left: 1px solid #f5f5f5;
|
|
|
|
|
+ align-items: flex-start;
|
|
|
|
|
+ gap: 3px;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
.bottom-bar {
|
|
.bottom-bar {
|
|
|
background: #fafafa;
|
|
background: #fafafa;
|
|
|
border: 1px solid #eee;
|
|
border: 1px solid #eee;
|
|
@@ -392,7 +715,20 @@ onMounted(() => {
|
|
|
justify-content: space-between;
|
|
justify-content: space-between;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
flex-shrink: 0;
|
|
flex-shrink: 0;
|
|
|
- .bottom-right { display: flex; align-items: center; gap: 15px; .selected-info { font-size: 14px; color: #666; em { color: #e60012; font-style: normal; font-weight: bold; } } }
|
|
|
|
|
|
|
+ .bottom-right {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 15px;
|
|
|
|
|
+ .selected-info {
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ color: #666;
|
|
|
|
|
+ em {
|
|
|
|
|
+ color: #e60012;
|
|
|
|
|
+ font-style: normal;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
:deep(.table-pagination) {
|
|
:deep(.table-pagination) {
|
|
|
flex-shrink: 0;
|
|
flex-shrink: 0;
|