| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599 |
- <template>
- <div class="order-audit-container">
- <PageTitle title="审核订单" />
- <!-- 主Tab切换 -->
- <StatusTabs v-model="activeMainTab" :tabs="mainTabs" type="line" @change="handleMainTabChange" />
- <!-- 状态Tab切换 -->
- <StatusTabs v-model="activeStatusTab" :tabs="currentStatusTabs" type="pill" @change="handleStatusTabChange" />
- <!-- 搜索栏 -->
- <div class="search-bar">
- <el-input v-model="queryParams.keyword" placeholder="搜索" style="width: 240px" clearable>
- <template #prefix>
- <el-icon><Search /></el-icon>
- </template>
- </el-input>
- <div style="width: 240px">
- <el-date-picker
- v-model="queryParams.dateRange"
- type="daterange"
- range-separator="—"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- style="width: 240px"
- />
- </div>
- <el-tree-select
- v-model="queryParams.department"
- style="width: 240px"
- :data="deptList"
- :props="{ value: 'deptId', label: 'deptName', children: 'children' }"
- value-key="deptId"
- placeholder="下单部门"
- check-strictly
- :render-after-expand="false"
- clearable
- >
- </el-tree-select>
- </div>
- <!-- 订单列表 -->
- <div class="order-list">
- <div v-for="(order, orderIndex) in orderList" :key="orderIndex" class="order-card">
- <div class="order-header">
- <el-checkbox v-model="order.checked" />
- <span class="order-time">{{ order.orderTime }}</span>
- <span class="order-info">订单号:{{ order.orderNo }}</span>
- <el-button type="primary" link class="detail-btn" @click="handleViewDetail(order)">
- 订单详情 <el-icon><ArrowRight /></el-icon>
- </el-button>
- </div>
- <div class="product-list">
- <div class="product-row">
- <div class="product-cell product-info-cell">
- <template v-if="order.products && order.products.length > 0">
- <div class="product-image">
- <el-image :src="order.products[0].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-name">{{ order.products[0].name }}</div>
- <div class="product-spec">{{ order.products[0].spec1 }} {{ order.products[0].spec2 }}</div>
- <div class="product-price">¥{{ order.products[0].price }}</div>
- </div>
- <div class="product-quantity">x{{ order.products[0].quantity }}</div>
- </template>
- <template v-else>
- <div class="product-image">
- <div class="image-placeholder">
- <el-icon :size="30" color="#ccc"><Picture /></el-icon>
- </div>
- </div>
- <div class="product-detail">
- <div class="product-name">暂无商品信息</div>
- </div>
- </template>
- </div>
- <div class="product-cell amount-cell">
- <div class="amount-info">
- <span class="label">支付款:</span>
- <span class="value highlight">¥{{ order.payableAmount }}</span>
- </div>
- <div class="amount-info">
- <span class="label">{{ order.payMethod }}</span>
- </div>
- </div>
- <div class="product-cell status-cell">
- <span :class="['status-text', getStatusClass(order.checkStatus)]">{{ getStatusText(order.checkStatus) }}</span>
- <!-- <el-button type="primary" link size="small">查看订单轨迹</el-button> -->
- <template v-if="order.checkStatus !== '0' && activeMainTab === 'myAudit'">
- <!-- <el-button type="primary" link size="small">查看审批流</el-button> -->
- </template>
- <template v-if="activeMainTab === 'myApply'">
- <span v-if="order.checkStatus === '1'" class="result-text success">审批通过</span>
- <span v-else-if="order.checkStatus === '2'" class="result-text danger">审批驳回</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>
- </div>
- <div class="product-cell action-cell">
- <template v-if="activeMainTab === 'myAudit' && order.checkStatus === '0'">
- <el-button type="success" link size="small" @click="handleApprove(order)">同意</el-button>
- <el-button type="danger" link size="small" @click="handleReject(order)">拒绝</el-button>
- </template>
- <template v-if="activeMainTab === 'myApply' && order.checkStatus === '0'">
- <el-button type="primary" link size="small" @click="handleCancelApply(order)">取消申请</el-button>
- </template>
- </div>
- </div>
- </div>
- </div>
- <el-empty v-if="orderList.length === 0" description="暂无审核订单" />
- </div>
- <!-- 分页 -->
- <div class="pagination-container">
- <el-pagination
- v-model:current-page="pageNum"
- v-model:page-size="pageSize"
- :total="displayTotal"
- :page-sizes="[10, 20, 50, 100]"
- layout="total, sizes, prev, pager, next, jumper"
- @size-change="handleSizeChange"
- @current-change="handlePageChange"
- />
- </div>
- <!-- 审批弹窗 -->
- <el-dialog v-model="auditDialogVisible" :title="auditDialogTitle" width="450px">
- <el-form ref="auditFormRef" :model="auditForm" :rules="auditRules" label-width="80px">
- <el-form-item label="审批意见" prop="opinion">
- <el-input v-model="auditForm.opinion" type="textarea" :rows="4" placeholder="请输入审批意见" />
- </el-form-item>
- </el-form>
- <template #footer>
- <el-button @click="auditDialogVisible = false">取消</el-button>
- <el-button type="danger" @click="handleSubmitAudit">确定</el-button>
- </template>
- </el-dialog>
- </div>
- </template>
- <script setup lang="ts">
- import { ref, reactive, computed, onMounted } from 'vue';
- import { useRouter } from 'vue-router';
- import { Search, Document, User, ArrowRight, Picture } from '@element-plus/icons-vue';
- import { ElMessage, ElMessageBox } from 'element-plus';
- import { PageTitle, StatusTabs } from '@/components';
- import { getDeptTree } from '@/api/pc/organization';
- import { DeptInfo } from '@/api/pc/organization/types';
- import { getOrderList, getOrderProducts, checkOrderStatus } from '@/api/pc/enterprise/order';
- const { proxy } = getCurrentInstance() as ComponentInternalInstance;
- const { complaints_suggestion_type } = toRefs<any>(proxy?.useDict('complaints_suggestion_type'));
- const router = useRouter();
- const activeMainTab = ref('myAudit');
- const activeStatusTab = ref('all');
- const auditDialogVisible = ref(false);
- const auditDialogTitle = ref('审批');
- const auditFormRef = ref();
- const currentAuditOrder = ref<any>(null);
- const currentAuditAction = ref('');
- const loading = ref(false);
- const allOrders = ref<any[]>([]);
- const pageNum = ref(1);
- const pageSize = ref(5);
- const total = ref(0);
- const deptList = ref([]);
- const mainTabs = [
- { key: 'myAudit', label: '我审批的', icon: Document }
- // { key: 'myApply', label: '我申请的', icon: User }
- // { key: 'myAudit', label: '待审批', icon: Document },
- // { key: 'myApply', label: '已审批', icon: User }
- ];
- const auditStatusTabs = [
- { key: 'all', label: '全部订单' },
- { key: 'pending', label: '待审批' },
- { key: 'approved', label: '已通过' },
- { key: 'rejected', label: '已驳回' }
- ];
- const applyStatusTabs = [
- { key: 'all', label: '全部订单' },
- { key: 'pending', label: '审批中' },
- { key: 'approved', label: '审批通过' },
- { key: 'rejected', label: '审批驳回' },
- { key: 'cancelled', label: '审批取消' }
- ];
- const currentStatusTabs = computed(() => {
- return activeMainTab.value === 'myAudit' ? auditStatusTabs : applyStatusTabs;
- });
- const queryParams = reactive({
- keyword: '',
- dateRange: null,
- department: '',
- filter1: ''
- });
- const checkOrderData = reactive({
- orderId: undefined,
- checkStatus: '',
- checkRemark: ''
- });
- const auditForm = reactive({ opinion: '' });
- const auditRules = { opinion: [{ required: true, message: '请输入审批意见', trigger: 'blur' }] };
- // 加载订单列表数据
- const loadOrderList = async () => {
- try {
- loading.value = true;
- // 根据状态tab设置checkStatus参数
- const params: any = {
- pageNum: pageNum.value,
- pageSize: pageSize.value
- };
- // 根据不同状态设置checkStatus参数
- if (activeStatusTab.value === 'pending') {
- params.checkStatus = '0';
- } else if (activeStatusTab.value === 'approved') {
- params.checkStatus = '1';
- } else if (activeStatusTab.value === 'rejected') {
- params.checkStatus = '2';
- }
- const res = await getOrderList(params);
- if (res.code === 200 && res.rows) {
- allOrders.value = res.rows.map((item: any) => ({
- id: item.id,
- orderTime: item.createTime,
- orderNo: item.orderNo,
- payableAmount: item.payableAmount,
- payMethod: item.payMethod,
- checkStatus: item.checkStatus,
- fileCount: 0,
- checked: false,
- products: []
- }));
- total.value = res.total || 0;
- // 获取所有订单的商品信息
- if (allOrders.value.length > 0) {
- const orderIds = allOrders.value.map((order) => order.id);
- const productsRes = await getOrderProducts(orderIds);
- if (productsRes.code === 200 && productsRes.rows) {
- // 将商品信息按订单ID分组
- const productsByOrderId = new Map();
- productsRes.rows.forEach((p: any) => {
- if (!productsByOrderId.has(p.orderId)) {
- productsByOrderId.set(p.orderId, []);
- }
- productsByOrderId.get(p.orderId).push({
- image: p.productImage || '',
- name: p.productName || '',
- spec1: p.productUnit || '',
- spec2: p.productNo || '',
- price: p.orderPrice || 0,
- quantity: p.orderQuantity || 0
- });
- });
- // 将商品信息赋值给对应的订单
- allOrders.value.forEach((order) => {
- order.products = productsByOrderId.get(order.id) || [];
- });
- }
- }
- }
- } catch (error) {
- console.error('加载订单列表失败:', error);
- ElMessage.error('加载订单列表失败');
- } finally {
- loading.value = false;
- }
- };
- // 加载部门树
- 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('获取部门树失败');
- }
- };
- // 每页条数变化
- const handleSizeChange = () => {
- pageNum.value = 1;
- loadOrderList();
- };
- // 页码变化
- const handlePageChange = () => {
- loadOrderList();
- };
- const orderList = computed(() => {
- // 所有状态都由后端过滤,前端直接返回数据
- return allOrders.value;
- });
- // 使用后端返回的总数
- const displayTotal = computed(() => {
- return total.value;
- });
- const handleMainTabChange = () => {
- activeStatusTab.value = 'all';
- pageNum.value = 1;
- loadOrderList();
- };
- // 状态 tab 切换
- const handleStatusTabChange = () => {
- pageNum.value = 1;
- loadOrderList();
- };
- onMounted(() => {
- loadDeptTree();
- loadOrderList();
- });
- const getStatusText = (checkStatus: string) => {
- const map: Record<string, string> = {
- '0': '待审批',
- '1': '审批通过',
- '2': '审批驳回'
- };
- return map[checkStatus] || checkStatus;
- };
- const getStatusClass = (checkStatus: string) => {
- if (checkStatus === '1') return 'success';
- return 'warning';
- };
- const handleViewDetail = (order: any) => {
- router.push(`/order/orderManage/detail?orderId=${order.id}`);
- };
- const handleApprove = (order: any) => {
- currentAuditOrder.value = order;
- checkOrderData.orderId = order.id;
- currentAuditAction.value = 'approve';
- auditDialogTitle.value = '审批通过';
- auditForm.opinion = '';
- auditDialogVisible.value = true;
- };
- const handleReject = (order: any) => {
- currentAuditOrder.value = order;
- checkOrderData.orderId = order.id;
- currentAuditAction.value = 'reject';
- auditDialogTitle.value = '审批拒绝';
- auditForm.opinion = '';
- auditDialogVisible.value = true;
- };
- const handleCancelApply = (order: any) => {
- ElMessageBox.confirm('确定要取消该申请吗?', '提示', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning'
- })
- .then(() => {
- order.auditStatus = 'cancelled';
- ElMessage.success('已取消申请');
- })
- .catch(() => {});
- };
- const handleSubmitAudit = async () => {
- const valid = await auditFormRef.value?.validate();
- if (!valid) return;
- try {
- const checkStatus = currentAuditAction.value === 'approve' ? '1' : '2';
- checkOrderData.checkStatus = checkStatus;
- checkOrderData.checkRemark = auditForm.opinion;
- await checkOrderStatus(checkOrderData);
- ElMessage.success(currentAuditAction.value === 'approve' ? '审批通过' : '已拒绝');
- auditDialogVisible.value = false;
- loadOrderList();
- } catch (error) {
- console.error('审批失败:', error);
- ElMessage.error('审批失败,请重试');
- }
- };
- </script>
- <style scoped lang="scss">
- .order-audit-container {
- padding: 20px;
- background: #fff;
- min-height: 100%;
- width: 100%;
- }
- .search-bar {
- display: flex;
- align-items: center;
- gap: 15px;
- margin-bottom: 15px;
- }
- .filter-bar {
- display: flex;
- align-items: center;
- gap: 10px;
- margin-bottom: 20px;
- .filter-label {
- font-size: 14px;
- color: #666;
- }
- }
- .order-list {
- .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;
- }
- .detail-btn {
- margin-left: auto;
- }
- }
- .product-list {
- .product-row {
- display: flex;
- }
- .product-cell {
- padding: 15px;
- display: flex;
- align-items: center;
- // 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: 150px;
- border-left: 1px solid #f5f5f5;
- .amount-info {
- margin-bottom: 5px;
- .label {
- font-size: 12px;
- color: #999;
- margin-right: 5px;
- }
- .value {
- font-size: 14px;
- color: #333;
- &.highlight {
- font-size: 16px;
- font-weight: bold;
- color: #e60012;
- }
- }
- }
- }
- .status-cell {
- width: 140px;
- border-left: 1px solid #f5f5f5;
- // align-items: flex-start;
- gap: 5px;
- .status-text {
- font-size: 13px;
- font-weight: 500;
- &.success {
- color: #67c23a;
- }
- &.warning {
- color: #e6a23c;
- }
- }
- .result-text {
- font-size: 13px;
- font-weight: 500;
- &.success {
- color: #e60012;
- }
- &.danger {
- color: #e60012;
- }
- }
- }
- .action-cell {
- width: 100px;
- border-left: 1px solid #f5f5f5;
- // align-items: flex-start;
- // gap: 5px;
- }
- }
- }
- }
- </style>
|