905 lines
24 KiB
Vue
905 lines
24 KiB
Vue
<template>
|
||
<div class="equipment-approval-container">
|
||
<!-- 页面头部 -->
|
||
<div class="page-header">
|
||
<div class="header-content">
|
||
<div class="header-left">
|
||
<div class="page-title">
|
||
<IconCheckCircle style="font-size: 24px; margin-right: 12px; color: var(--color-primary);" />
|
||
<h1>设备审批控制台</h1>
|
||
</div>
|
||
<div class="page-description">
|
||
管理设备采购申请的审批流程,包括待审批、已审批等状态管理
|
||
</div>
|
||
</div>
|
||
<div class="header-right">
|
||
<a-space>
|
||
<ApprovalSearch
|
||
:loading="loading"
|
||
@search="handleSearch"
|
||
@reset="handleReset"
|
||
/>
|
||
<a-button type="primary" size="large" @click="refreshData">
|
||
<template #icon>
|
||
<IconRefresh />
|
||
</template>
|
||
刷新
|
||
</a-button>
|
||
</a-space>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 统计卡片 -->
|
||
<div class="stats-container">
|
||
<a-row :gutter="16">
|
||
<a-col :span="6">
|
||
<a-card class="stat-card" :bordered="false">
|
||
<div class="stat-content">
|
||
<div class="stat-icon" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);">
|
||
<IconClockCircle />
|
||
</div>
|
||
<div class="stat-info">
|
||
<div class="stat-number">{{ getPendingCount() }}</div>
|
||
<div class="stat-label">待审批</div>
|
||
</div>
|
||
</div>
|
||
</a-card>
|
||
</a-col>
|
||
<a-col :span="6">
|
||
<a-card class="stat-card" :bordered="false">
|
||
<div class="stat-content">
|
||
<div class="stat-icon" style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);">
|
||
<IconCheckCircle />
|
||
</div>
|
||
<div class="stat-info">
|
||
<div class="stat-number">{{ getApprovedCount() }}</div>
|
||
<div class="stat-label">已通过</div>
|
||
</div>
|
||
</div>
|
||
</a-card>
|
||
</a-col>
|
||
<a-col :span="6">
|
||
<a-card class="stat-card" :bordered="false">
|
||
<div class="stat-content">
|
||
<div class="stat-icon" style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);">
|
||
<IconCloseCircle />
|
||
</div>
|
||
<div class="stat-info">
|
||
<div class="stat-number">{{ getRejectedCount() }}</div>
|
||
<div class="stat-label">已拒绝</div>
|
||
</div>
|
||
</div>
|
||
</a-card>
|
||
</a-col>
|
||
<a-col :span="6">
|
||
<a-card class="stat-card" :bordered="false">
|
||
<div class="stat-content">
|
||
<div class="stat-icon" style="background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);">
|
||
<IconApps />
|
||
</div>
|
||
<div class="stat-info">
|
||
<div class="stat-number">¥{{ getTotalAmount() }}</div>
|
||
<div class="stat-label">审批总额</div>
|
||
</div>
|
||
</div>
|
||
</a-card>
|
||
</a-col>
|
||
</a-row>
|
||
</div>
|
||
|
||
<!-- 标签页 -->
|
||
<a-card class="table-card" :bordered="false">
|
||
<template #title>
|
||
<div class="card-title">
|
||
<a-tabs v-model:active-key="activeTab" @change="handleTabChange">
|
||
<a-tab-pane key="pending" title="待审批">
|
||
<template #title>
|
||
<span>
|
||
<IconClockCircle style="margin-right: 4px;" />
|
||
待审批 ({{ getPendingCount() }})
|
||
</span>
|
||
</template>
|
||
</a-tab-pane>
|
||
<a-tab-pane key="approved" title="已审批">
|
||
<template #title>
|
||
<span>
|
||
<IconCheckCircle style="margin-right: 4px;" />
|
||
已审批 ({{ getApprovedCount() + getRejectedCount() }})
|
||
</span>
|
||
</template>
|
||
</a-tab-pane>
|
||
</a-tabs>
|
||
</div>
|
||
</template>
|
||
|
||
<a-table
|
||
:columns="columns"
|
||
:data="tableData"
|
||
:loading="loading"
|
||
:pagination="false"
|
||
row-key="approvalId"
|
||
:scroll="{ x: 'max-content', y: 400 }"
|
||
@change="handleTableChange"
|
||
>
|
||
<!-- 业务类型 -->
|
||
<template #businessType="{ record }">
|
||
<a-tag :color="getBusinessTypeColor(record.businessType)">
|
||
{{ getBusinessTypeText(record.businessType) }}
|
||
</a-tag>
|
||
</template>
|
||
|
||
<!-- 审批状态 -->
|
||
<template #approvalStatus="{ record }">
|
||
<a-tag :color="getApprovalStatusColor(record.approvalStatus)">
|
||
{{ getApprovalStatusText(record.approvalStatus) }}
|
||
</a-tag>
|
||
</template>
|
||
|
||
<!-- 采购价格 -->
|
||
<template #purchasePrice="{ record }">
|
||
<span v-if="record.purchasePrice" class="price-text">
|
||
¥{{ formatPrice(record.purchasePrice) }}
|
||
</span>
|
||
<span v-else class="no-data">-</span>
|
||
</template>
|
||
|
||
<!-- 总价 -->
|
||
<template #totalPrice="{ record }">
|
||
<span v-if="record.totalPrice" class="price-text">
|
||
¥{{ formatPrice(record.totalPrice) }}
|
||
</span>
|
||
<span v-else class="no-data">-</span>
|
||
</template>
|
||
|
||
<!-- 申请时间 -->
|
||
<template #applyTime="{ record }">
|
||
<span v-if="record.applyTime" class="time-text">
|
||
{{ formatDateTime(record.applyTime) }}
|
||
</span>
|
||
<span v-else class="no-data">-</span>
|
||
</template>
|
||
|
||
<!-- 审批时间 -->
|
||
<template #approvalTime="{ record }">
|
||
<span v-if="record.approvalTime" class="time-text">
|
||
{{ formatDateTime(record.approvalTime) }}
|
||
</span>
|
||
<span v-else class="no-data">-</span>
|
||
</template>
|
||
|
||
<!-- 操作 -->
|
||
<template #action="{ record }">
|
||
<a-space>
|
||
<a-button type="text" size="small" @click="handleView(record)">
|
||
查看详情
|
||
</a-button>
|
||
<a-button
|
||
v-if="record.approvalStatus === ApprovalStatus.PENDING"
|
||
type="primary"
|
||
size="small"
|
||
@click="handleApprove(record)"
|
||
>
|
||
审批通过
|
||
</a-button>
|
||
<a-button
|
||
v-if="record.approvalStatus === ApprovalStatus.PENDING"
|
||
type="text"
|
||
size="small"
|
||
status="danger"
|
||
@click="handleReject(record)"
|
||
>
|
||
审批拒绝
|
||
</a-button>
|
||
</a-space>
|
||
</template>
|
||
</a-table>
|
||
|
||
<!-- 分页器 - 固定在表格下方 -->
|
||
<div class="pagination-container">
|
||
<a-pagination
|
||
v-model:current="pagination.current"
|
||
v-model:page-size="pagination.pageSize"
|
||
:total="pagination.total"
|
||
:show-total="true"
|
||
:show-jumper="true"
|
||
:show-page-size="true"
|
||
:page-size-options="[10, 20, 50, 100]"
|
||
:hide-on-single-page="false"
|
||
size="default"
|
||
@change="handlePageChange"
|
||
@page-size-change="handlePageSizeChange"
|
||
/>
|
||
</div>
|
||
</a-card>
|
||
|
||
<!-- 审批详情弹窗 -->
|
||
<ApprovalDetailModal
|
||
v-model:visible="detailModalVisible"
|
||
:approval-data="currentApproval"
|
||
@success="handleModalSuccess"
|
||
@approve="handleApproveFromDetail"
|
||
@reject="handleRejectFromDetail"
|
||
/>
|
||
|
||
<!-- 审批操作弹窗 -->
|
||
<ApprovalActionModal
|
||
v-model:visible="actionModalVisible"
|
||
:approval-data="currentApproval"
|
||
:action-type="actionType"
|
||
@success="handleModalSuccess"
|
||
/>
|
||
</div>
|
||
</template>
|
||
|
||
<script lang="ts" setup>
|
||
import { onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue'
|
||
import { Modal } from '@arco-design/web-vue'
|
||
import {
|
||
IconApps,
|
||
IconCheckCircle,
|
||
IconClockCircle,
|
||
IconCloseCircle,
|
||
IconRefresh,
|
||
} from '@arco-design/web-vue/es/icon'
|
||
import message from '@arco-design/web-vue/es/message'
|
||
import ApprovalDetailModal from './components/ApprovalDetailModal.vue'
|
||
import ApprovalActionModal from './components/ApprovalActionModal.vue'
|
||
import ApprovalSearch from './components/ApprovalSearch.vue'
|
||
import { equipmentApprovalApi } from '@/apis/equipment/approval'
|
||
import type { EquipmentApprovalListReq, EquipmentApprovalResp } from '@/apis/equipment/type'
|
||
import { ApprovalStatus, BusinessType } from '@/apis/equipment/type'
|
||
|
||
defineOptions({ name: 'EquipmentApproval' })
|
||
|
||
// 当前搜索参数
|
||
const currentSearchParams = ref<EquipmentApprovalListReq>({})
|
||
|
||
// 表格数据
|
||
const tableData = ref<EquipmentApprovalResp[]>([])
|
||
const loading = ref(false)
|
||
|
||
// 分页配置
|
||
const pagination = reactive<any>({
|
||
current: 1,
|
||
pageSize: 10,
|
||
total: 0,
|
||
showPageSize: true,
|
||
showJumper: true,
|
||
showTotal: (total: number) => `共 ${total} 条记录`,
|
||
pageSizeOptions: [10, 20, 50, 100]
|
||
})
|
||
|
||
// 弹窗控制
|
||
const detailModalVisible = ref(false)
|
||
const actionModalVisible = ref(false)
|
||
const currentApproval = ref<EquipmentApprovalResp | null>(null)
|
||
const actionType = ref<'approve' | 'reject'>('approve')
|
||
|
||
// 当前标签页
|
||
const activeTab = ref('pending')
|
||
|
||
// 表格列配置
|
||
const columns = [
|
||
{
|
||
title: '设备名称',
|
||
dataIndex: 'equipmentName',
|
||
key: 'equipmentName',
|
||
width: 150,
|
||
},
|
||
{
|
||
title: '设备类型',
|
||
dataIndex: 'equipmentType',
|
||
key: 'equipmentType',
|
||
width: 120,
|
||
},
|
||
{
|
||
title: '业务类型',
|
||
dataIndex: 'businessType',
|
||
key: 'businessType',
|
||
slotName: 'businessType',
|
||
width: 100,
|
||
},
|
||
{
|
||
title: '设备型号',
|
||
dataIndex: 'equipmentModel',
|
||
key: 'equipmentModel',
|
||
width: 120,
|
||
},
|
||
{
|
||
title: '品牌',
|
||
dataIndex: 'brand',
|
||
key: 'brand',
|
||
width: 100,
|
||
},
|
||
{
|
||
title: '供应商',
|
||
dataIndex: 'supplierName',
|
||
key: 'supplierName',
|
||
width: 150,
|
||
},
|
||
{
|
||
title: '采购价格',
|
||
dataIndex: 'purchasePrice',
|
||
key: 'purchasePrice',
|
||
slotName: 'purchasePrice',
|
||
width: 120,
|
||
},
|
||
{
|
||
title: '总价',
|
||
dataIndex: 'totalPrice',
|
||
key: 'totalPrice',
|
||
slotName: 'totalPrice',
|
||
width: 120,
|
||
},
|
||
{
|
||
title: '数量',
|
||
dataIndex: 'quantity',
|
||
key: 'quantity',
|
||
width: 80,
|
||
},
|
||
{
|
||
title: '申请人',
|
||
dataIndex: 'applicantName',
|
||
key: 'applicantName',
|
||
width: 120,
|
||
},
|
||
{
|
||
title: '申请时间',
|
||
dataIndex: 'applyTime',
|
||
key: 'applyTime',
|
||
slotName: 'applyTime',
|
||
width: 160,
|
||
},
|
||
{
|
||
title: '审批状态',
|
||
dataIndex: 'approvalStatus',
|
||
key: 'approvalStatus',
|
||
slotName: 'approvalStatus',
|
||
width: 120,
|
||
},
|
||
{
|
||
title: '审批人',
|
||
dataIndex: 'approverName',
|
||
key: 'approverName',
|
||
width: 120,
|
||
},
|
||
{
|
||
title: '审批时间',
|
||
dataIndex: 'approvalTime',
|
||
key: 'approvalTime',
|
||
slotName: 'approvalTime',
|
||
width: 160,
|
||
},
|
||
{
|
||
title: '操作',
|
||
key: 'action',
|
||
slotName: 'action',
|
||
width: 200,
|
||
fixed: 'right',
|
||
},
|
||
]
|
||
|
||
// 获取审批状态颜色
|
||
const getApprovalStatusColor = (status: ApprovalStatus) => {
|
||
const colorMap: Record<string, string> = {
|
||
[ApprovalStatus.PENDING]: 'orange',
|
||
[ApprovalStatus.APPROVED]: 'green',
|
||
[ApprovalStatus.REJECTED]: 'red',
|
||
}
|
||
return colorMap[status] || 'blue'
|
||
}
|
||
|
||
// 获取业务类型颜色
|
||
const getBusinessTypeColor = (type: BusinessType) => {
|
||
const colorMap: Record<string, string> = {
|
||
[BusinessType.PROCUREMENT]: 'blue',
|
||
[BusinessType.BORROW]: 'green',
|
||
[BusinessType.RETURN]: 'orange',
|
||
}
|
||
return colorMap[type] || 'gray'
|
||
}
|
||
|
||
// 获取业务类型文本
|
||
const getBusinessTypeText = (type: BusinessType) => {
|
||
const textMap: Record<string, string> = {
|
||
[BusinessType.PROCUREMENT]: '采购',
|
||
[BusinessType.BORROW]: '借用',
|
||
[BusinessType.RETURN]: '归还',
|
||
}
|
||
return textMap[type] || '未知'
|
||
}
|
||
|
||
// 获取审批状态文本
|
||
const getApprovalStatusText = (status: ApprovalStatus) => {
|
||
const textMap: Record<string, string> = {
|
||
[ApprovalStatus.PENDING]: '待审批',
|
||
[ApprovalStatus.APPROVED]: '已通过',
|
||
[ApprovalStatus.REJECTED]: '已拒绝',
|
||
}
|
||
return textMap[status] || '未知'
|
||
}
|
||
|
||
// 格式化价格
|
||
const formatPrice = (price: number) => {
|
||
return price.toLocaleString('zh-CN', {
|
||
minimumFractionDigits: 2,
|
||
maximumFractionDigits: 2,
|
||
})
|
||
}
|
||
|
||
// 格式化日期时间
|
||
const formatDateTime = (dateTime: string) => {
|
||
if (!dateTime) return '-'
|
||
const date = new Date(dateTime)
|
||
return date.toLocaleString('zh-CN', {
|
||
year: 'numeric',
|
||
month: '2-digit',
|
||
day: '2-digit',
|
||
hour: '2-digit',
|
||
minute: '2-digit',
|
||
})
|
||
}
|
||
|
||
// 转换后端数据
|
||
const transformBackendData = (data: any[]): EquipmentApprovalResp[] => {
|
||
return data.map((item: any) => ({
|
||
approvalId: item.approvalId || item.id,
|
||
equipmentId: item.equipmentId,
|
||
equipmentName: item.equipmentName,
|
||
equipmentType: item.equipmentType,
|
||
equipmentModel: item.equipmentModel,
|
||
brand: item.brand,
|
||
supplierName: item.supplierName,
|
||
purchasePrice: item.purchasePrice,
|
||
totalPrice: item.totalPrice,
|
||
quantity: item.quantity,
|
||
applicantName: item.applicantName,
|
||
applicantId: item.applicantId,
|
||
applyTime: item.applyTime,
|
||
applyReason: item.applyReason,
|
||
businessType: item.businessType || BusinessType.PROCUREMENT,
|
||
approvalStatus: item.approvalStatus,
|
||
approverName: item.approverName,
|
||
approverId: item.approverId,
|
||
approvalTime: item.approvalTime,
|
||
approvalComment: item.approvalComment,
|
||
createTime: item.createTime,
|
||
updateTime: item.updateTime,
|
||
}))
|
||
}
|
||
|
||
// 加载数据
|
||
const loadData = async (searchParams?: EquipmentApprovalListReq) => {
|
||
console.log('📊 loadData - 开始加载数据')
|
||
console.log('📊 loadData - 接收到的搜索参数:', searchParams)
|
||
console.log('📊 loadData - 当前标签页:', activeTab.value)
|
||
|
||
loading.value = true
|
||
try {
|
||
// 构建完整的请求参数 - 参考设备采购功能的实现
|
||
const params: EquipmentApprovalListReq = {
|
||
pageNum: pagination.current, // 修改为 pageNum,与后端期望的参数名一致
|
||
pageSize: pagination.pageSize,
|
||
...(searchParams || {}),
|
||
}
|
||
|
||
console.log('📊 loadData - 构建的完整请求参数:', params)
|
||
|
||
let res: any
|
||
if (activeTab.value === 'pending') {
|
||
console.log('📊 loadData - 调用待审批API')
|
||
res = await equipmentApprovalApi.getPendingApprovals(params)
|
||
} else {
|
||
console.log('📊 loadData - 调用已审批API')
|
||
res = await equipmentApprovalApi.getApprovedApprovals(params)
|
||
}
|
||
|
||
console.log('API响应:', res)
|
||
|
||
if (res.code === 200 || res.success || res.status === 200) {
|
||
let dataList: any[] = []
|
||
let totalCount = 0
|
||
|
||
// 检查不同的数据字段 - 后端返回的是 PageResult 格式
|
||
if ((res as any).rows && Array.isArray((res as any).rows)) {
|
||
// 后端返回的是 PageResult 格式,数据在 rows 字段中
|
||
dataList = (res as any).rows
|
||
totalCount = (res as any).total || 0
|
||
console.log('从 rows 字段获取数据,总数:', totalCount)
|
||
} else if (Array.isArray(res.data)) {
|
||
dataList = res.data
|
||
totalCount = (res as any).total || dataList.length || 0
|
||
console.log('从 data 字段获取数据,总数:', totalCount)
|
||
} else if (res.data && Array.isArray((res.data as any).records)) {
|
||
dataList = (res.data as any).records
|
||
totalCount = (res.data as any).total || dataList.length || 0
|
||
console.log('从 records 字段获取数据,总数:', totalCount)
|
||
} else if (res.data && Array.isArray((res.data as any).list)) {
|
||
dataList = (res.data as any).list
|
||
totalCount = (res.data as any).total || dataList.length || 0
|
||
console.log('从 list 字段获取数据,总数:', totalCount)
|
||
} else {
|
||
console.warn('未找到有效的数据字段,响应结构:', res)
|
||
dataList = []
|
||
totalCount = 0
|
||
}
|
||
|
||
if (dataList.length > 0) {
|
||
const transformedData = transformBackendData(dataList)
|
||
tableData.value = transformedData
|
||
console.log('数据转换完成,设置到表格:', transformedData.length, '条')
|
||
} else {
|
||
tableData.value = []
|
||
console.log('没有数据,清空表格')
|
||
}
|
||
|
||
// 设置总数 - 优先使用后端返回的总数
|
||
pagination.total = totalCount
|
||
console.log('设置分页总数:', totalCount)
|
||
} else {
|
||
console.error('请求失败,响应:', res)
|
||
message.error(res.msg || (res as any).message || '加载数据失败')
|
||
tableData.value = []
|
||
pagination.total = 0
|
||
}
|
||
} catch (error: any) {
|
||
console.error('加载数据失败:', error)
|
||
message.error(error?.message || '加载数据失败')
|
||
tableData.value = []
|
||
pagination.total = 0
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
// 搜索
|
||
const handleSearch = (searchParams: EquipmentApprovalListReq) => {
|
||
console.log('🔍 主组件 - 接收到的搜索参数:', searchParams)
|
||
pagination.current = 1
|
||
currentSearchParams.value = { ...searchParams }
|
||
loadData(searchParams)
|
||
}
|
||
|
||
// 重置
|
||
const handleReset = () => {
|
||
console.log('🔄 主组件 - 重置操作')
|
||
pagination.current = 1
|
||
currentSearchParams.value = {}
|
||
loadData({}) // 传递空对象而不是 undefined
|
||
}
|
||
|
||
// 表格变化
|
||
const handleTableChange = (pag: any) => {
|
||
pagination.current = pag.current || 1
|
||
pagination.pageSize = pag.pageSize || 10
|
||
loadData(currentSearchParams.value || {})
|
||
}
|
||
|
||
// 分页变化处理
|
||
const handlePageChange = (page: number) => {
|
||
console.log('页码变化:', page)
|
||
pagination.current = page
|
||
loadData(currentSearchParams.value || {})
|
||
}
|
||
|
||
// 每页条数变化处理
|
||
const handlePageSizeChange = (pageSize: number) => {
|
||
console.log('每页条数变化:', pageSize)
|
||
pagination.pageSize = pageSize
|
||
pagination.current = 1 // 重置到第一页
|
||
loadData(currentSearchParams.value || {})
|
||
}
|
||
|
||
// 标签页变化
|
||
const handleTabChange = (key: string) => {
|
||
activeTab.value = key
|
||
pagination.current = 1
|
||
loadData(currentSearchParams.value || {})
|
||
}
|
||
|
||
// 查看详情
|
||
const handleView = (record: EquipmentApprovalResp) => {
|
||
currentApproval.value = { ...record }
|
||
detailModalVisible.value = true
|
||
}
|
||
|
||
// 审批通过
|
||
const handleApprove = (record: EquipmentApprovalResp) => {
|
||
currentApproval.value = { ...record }
|
||
actionType.value = 'approve'
|
||
actionModalVisible.value = true
|
||
}
|
||
|
||
// 审批拒绝
|
||
const handleReject = (record: EquipmentApprovalResp) => {
|
||
currentApproval.value = { ...record }
|
||
actionType.value = 'reject'
|
||
actionModalVisible.value = true
|
||
}
|
||
|
||
// 从详情弹窗审批通过
|
||
const handleApproveFromDetail = (record: EquipmentApprovalResp) => {
|
||
currentApproval.value = { ...record }
|
||
actionType.value = 'approve'
|
||
actionModalVisible.value = true
|
||
}
|
||
|
||
// 从详情弹窗审批拒绝
|
||
const handleRejectFromDetail = (record: EquipmentApprovalResp) => {
|
||
currentApproval.value = { ...record }
|
||
actionType.value = 'reject'
|
||
actionModalVisible.value = true
|
||
}
|
||
|
||
// 弹窗成功回调
|
||
const handleModalSuccess = () => {
|
||
detailModalVisible.value = false
|
||
actionModalVisible.value = false
|
||
loadData(currentSearchParams.value || {})
|
||
}
|
||
|
||
// 刷新数据
|
||
const refreshData = () => {
|
||
loadData(currentSearchParams.value || {})
|
||
}
|
||
|
||
// 统计函数
|
||
const getPendingCount = () => {
|
||
return tableData.value.filter(item =>
|
||
item.approvalStatus === ApprovalStatus.PENDING
|
||
).length
|
||
}
|
||
|
||
const getApprovedCount = () => {
|
||
return tableData.value.filter(item =>
|
||
item.approvalStatus === ApprovalStatus.APPROVED
|
||
).length
|
||
}
|
||
|
||
const getRejectedCount = () => {
|
||
return tableData.value.filter(item =>
|
||
item.approvalStatus === ApprovalStatus.REJECTED
|
||
).length
|
||
}
|
||
|
||
const getTotalAmount = () => {
|
||
const total = tableData.value.reduce((sum, item) => {
|
||
return sum + (item.totalPrice || 0)
|
||
}, 0)
|
||
return formatPrice(total)
|
||
}
|
||
|
||
onMounted(() => {
|
||
loadData({}) // 传递空对象而不是 undefined
|
||
})
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.equipment-approval-container {
|
||
.page-header {
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
border-radius: 12px;
|
||
padding: 24px;
|
||
margin-bottom: 24px;
|
||
|
||
.header-content {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
|
||
.header-left {
|
||
.page-title {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 8px;
|
||
|
||
h1 {
|
||
margin: 0;
|
||
color: white;
|
||
font-size: 28px;
|
||
font-weight: 600;
|
||
background: linear-gradient(135deg, #ffffff 0%, #f0f0f0 100%);
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
background-clip: text;
|
||
}
|
||
}
|
||
|
||
.page-description {
|
||
color: rgba(255, 255, 255, 0.8);
|
||
font-size: 14px;
|
||
}
|
||
}
|
||
|
||
.header-right {
|
||
.arco-btn {
|
||
border-radius: 8px;
|
||
font-weight: 500;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.stats-container {
|
||
margin-bottom: 24px;
|
||
|
||
.stat-card {
|
||
border-radius: 12px;
|
||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||
transition: all 0.3s ease;
|
||
|
||
&:hover {
|
||
transform: translateY(-4px);
|
||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
|
||
}
|
||
|
||
.stat-content {
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.stat-icon {
|
||
width: 60px;
|
||
height: 60px;
|
||
border-radius: 12px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-right: 16px;
|
||
|
||
.arco-icon {
|
||
font-size: 24px;
|
||
color: white;
|
||
}
|
||
}
|
||
|
||
.stat-info {
|
||
flex: 1;
|
||
|
||
.stat-number {
|
||
font-size: 24px;
|
||
font-weight: 600;
|
||
color: var(--color-text-1);
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.stat-label {
|
||
font-size: 14px;
|
||
color: var(--color-text-3);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.table-card {
|
||
border-radius: 12px;
|
||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||
|
||
.card-title {
|
||
.arco-tabs {
|
||
.arco-tabs-nav {
|
||
background: transparent;
|
||
|
||
.arco-tabs-tab {
|
||
border-radius: 8px;
|
||
margin-right: 8px;
|
||
|
||
&.arco-tabs-tab-active {
|
||
background: var(--color-primary-light-1);
|
||
color: var(--color-primary);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.arco-table {
|
||
.arco-table-th {
|
||
background-color: var(--color-fill-2);
|
||
font-weight: 600;
|
||
}
|
||
|
||
.arco-table-tr:hover {
|
||
background-color: var(--color-fill-1);
|
||
}
|
||
}
|
||
}
|
||
|
||
.price-text {
|
||
color: #f56c6c;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.time-text {
|
||
color: var(--color-text-2);
|
||
font-size: 12px;
|
||
}
|
||
|
||
.no-data {
|
||
color: var(--color-text-4);
|
||
font-style: italic;
|
||
}
|
||
|
||
// 分页器容器样式 - 固定在表格下方
|
||
.pagination-container {
|
||
position: sticky;
|
||
bottom: 0;
|
||
background: white;
|
||
padding: 16px 24px;
|
||
border-top: 1px solid var(--color-border);
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
align-items: center;
|
||
z-index: 10;
|
||
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.06);
|
||
|
||
.arco-pagination {
|
||
margin: 0;
|
||
|
||
.arco-pagination-item {
|
||
border-radius: 6px;
|
||
margin: 0 4px;
|
||
|
||
&.arco-pagination-item-active {
|
||
background: var(--color-primary);
|
||
border-color: var(--color-primary);
|
||
}
|
||
}
|
||
|
||
.arco-pagination-size-changer {
|
||
margin-left: 16px;
|
||
}
|
||
|
||
.arco-pagination-jumper {
|
||
margin-left: 16px;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 确保搜索区域有良好的对比度
|
||
.approval-search-container {
|
||
background: #ffffff;
|
||
padding: 16px;
|
||
border-radius: 8px;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||
margin-bottom: 16px;
|
||
|
||
.search-form {
|
||
.arco-form-item-label {
|
||
color: #333 !important;
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 响应式设计
|
||
@media (max-width: 768px) {
|
||
.equipment-approval-container {
|
||
.page-header {
|
||
.header-content {
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
|
||
.header-right {
|
||
margin-top: 16px;
|
||
width: 100%;
|
||
|
||
.arco-space {
|
||
width: 100%;
|
||
justify-content: space-between;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.stats-container {
|
||
.arco-col {
|
||
margin-bottom: 16px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</style>
|