You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1016 lines
23 KiB
1016 lines
23 KiB
<template>
|
|
<div class="tri-confirm-container">
|
|
<!-- 页面标题和统计 -->
|
|
<div class="page-header">
|
|
<div class="header-left">
|
|
<h2 class="page-title">
|
|
<i class="el-icon-s-check"></i> 三方确认
|
|
</h2>
|
|
<p class="page-subtitle">High Risk 生产质量技术三方确认管理</p>
|
|
</div>
|
|
<div class="header-right">
|
|
<div class="stat-cards">
|
|
<div class="stat-card stat-total">
|
|
<div class="stat-icon"><i class="el-icon-document"></i></div>
|
|
<div class="stat-content">
|
|
<div class="stat-value">{{ dataList.length }}</div>
|
|
<div class="stat-label">待确认工序</div>
|
|
</div>
|
|
</div>
|
|
<div class="stat-card stat-can-confirm">
|
|
<div class="stat-icon"><i class="el-icon-success"></i></div>
|
|
<div class="stat-content">
|
|
<div class="stat-value">{{ canConfirmCount }}</div>
|
|
<div class="stat-label">可立即确认</div>
|
|
</div>
|
|
</div>
|
|
<div class="stat-card stat-waiting">
|
|
<div class="stat-icon"><i class="el-icon-time"></i></div>
|
|
<div class="stat-content">
|
|
<div class="stat-value">{{ waitingCount }}</div>
|
|
<div class="stat-label">等待上道工序</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 查询条件表单 -->
|
|
<div class="search-section">
|
|
<el-collapse class="no-arrow" v-model="searchExpanded">
|
|
<el-collapse-item name="1">
|
|
<template slot="title">
|
|
<i class="el-icon-search"></i>
|
|
<span style="margin-left: 8px; font-weight: 500;">筛选条件</span>
|
|
</template>
|
|
<el-form :inline="true" label-position="top" class="search-form">
|
|
<el-form-item label="申请单号">
|
|
<el-input v-model="queryData.applyNo" placeholder="支持模糊查询" clearable style="width: 150px"></el-input>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="试验类型">
|
|
<el-select v-model="queryData.experimentType" placeholder="请选择" clearable style="width: 120px">
|
|
<el-option label="全部" value=""></el-option>
|
|
<el-option label="High Risk" value="High Risk"></el-option>
|
|
<el-option label="Low Risk" value="Low Risk"></el-option>
|
|
</el-select>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="试验名称">
|
|
<el-input v-model="queryData.title" placeholder="支持模糊查询" clearable style="width: 150px"></el-input>
|
|
</el-form-item>
|
|
|
|
<el-form-item label=" ">
|
|
<el-button @click="handleQuery" type="primary" icon="el-icon-search">查询</el-button>
|
|
<el-button @click="resetQuery" type="default" icon="el-icon-refresh-left">重置</el-button>
|
|
</el-form-item>
|
|
</el-form>
|
|
</el-collapse-item>
|
|
</el-collapse>
|
|
</div>
|
|
|
|
<!-- 卡片列表 -->
|
|
<div class="cards-container" v-loading="dataListLoading">
|
|
<transition-group name="card-list" tag="div" class="cards-grid">
|
|
<div
|
|
v-for="item in filteredDataList"
|
|
:key="item.applyNo + '-' + item.processStep"
|
|
class="confirm-card"
|
|
:class="{'high-risk': item.experimentType === 'High Risk', 'disabled': !item.canConfirm}">
|
|
|
|
<!-- 卡片头部 -->
|
|
<div class="card-header">
|
|
<div class="card-title-area">
|
|
<el-tag
|
|
:type="item.experimentType === 'High Risk' ? 'danger' : 'success'"
|
|
size="middle"
|
|
effect="dark"
|
|
class="risk-tag">
|
|
<i :class="item.experimentType === 'High Risk' ? 'el-icon-warning' : 'el-icon-success'"></i>
|
|
{{ item.experimentType }}
|
|
</el-tag>
|
|
<span class="apply-no">{{ item.applyNo }}</span>
|
|
</div>
|
|
<el-tag
|
|
:type="getRoleTagType(item.currentRole)"
|
|
size="middle"
|
|
effect="plain"
|
|
class="role-tag">
|
|
{{ getRoleName(item.currentRole) }}
|
|
</el-tag>
|
|
</div>
|
|
|
|
<!-- 卡片主体内容 -->
|
|
<div class="card-body">
|
|
<h3 class="experiment-title">
|
|
<i class="el-icon-document"></i>
|
|
{{ item.title }}
|
|
</h3>
|
|
|
|
<div class="process-info">
|
|
<div class="process-badge">
|
|
<i class="el-icon-s-operation"></i>
|
|
<span class="process-label">工序 {{ item.processSeq }}</span>
|
|
</div>
|
|
<div class="process-name">{{ item.processStep }}</div>
|
|
</div>
|
|
|
|
<div class="card-details">
|
|
<div class="detail-row">
|
|
<span class="detail-label">
|
|
<i class="el-icon-box"></i>
|
|
项目编号
|
|
</span>
|
|
<span class="detail-value">{{ item.projectNo || '-' }}</span>
|
|
</div>
|
|
|
|
<div class="detail-row">
|
|
<span class="detail-label">
|
|
<i class="el-icon-goods"></i>
|
|
产品型号
|
|
</span>
|
|
<span class="detail-value" :title="item.productType">{{ item.productType || '-' }}</span>
|
|
</div>
|
|
|
|
<div class="detail-row">
|
|
<span class="detail-label">
|
|
<i class="el-icon-user"></i>
|
|
申请人
|
|
</span>
|
|
<span class="detail-value">{{ item.creatorName }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 三方确认状态 -->
|
|
<div class="tri-status">
|
|
<div class="status-item" :class="{'confirmed': item.prodConfirmed}">
|
|
<i :class="item.prodConfirmed ? 'el-icon-circle-check' : 'el-icon-remove-outline'"></i>
|
|
<span>生产</span>
|
|
</div>
|
|
<div class="status-item" :class="{'confirmed': item.qaConfirmed}">
|
|
<i :class="item.qaConfirmed ? 'el-icon-circle-check' : 'el-icon-remove-outline'"></i>
|
|
<span>质量</span>
|
|
</div>
|
|
<div class="status-item" :class="{'confirmed': item.techConfirmed}">
|
|
<i :class="item.techConfirmed ? 'el-icon-circle-check' : 'el-icon-remove-outline'"></i>
|
|
<span>技术</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 卡片底部 -->
|
|
<div class="card-footer">
|
|
<div class="status-tip" v-if="!item.canConfirm">
|
|
<i class="el-icon-time"></i>
|
|
等待第{{ item.processSeq - 1 }}道工序完成
|
|
</div>
|
|
<div class="status-tip ready" v-else>
|
|
<i class="el-icon-success"></i>
|
|
可以确认
|
|
</div>
|
|
<div class="action-buttons">
|
|
<el-button
|
|
type="success"
|
|
size="small"
|
|
plain
|
|
icon="el-icon-check"
|
|
class="confirm-btn"
|
|
:disabled="!item.canConfirm"
|
|
@click="openConfirmDialog(item)">
|
|
确认
|
|
</el-button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</transition-group>
|
|
|
|
<!-- 空状态 -->
|
|
<div v-if="!dataListLoading && filteredDataList.length === 0" class="empty-state">
|
|
<i class="el-icon-document-checked empty-icon"></i>
|
|
<p class="empty-text">暂无待确认工序</p>
|
|
<p class="empty-subtext">您已完成所有三方确认任务</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 确认弹窗 -->
|
|
<el-dialog
|
|
:title="'三方确认 - ' + getRoleName(confirmData.roleType)"
|
|
:visible.sync="confirmDialogVisible"
|
|
width="700px"
|
|
:close-on-click-modal="false"
|
|
v-drag>
|
|
|
|
<!-- 申请单和工序信息 -->
|
|
<div class="confirm-info">
|
|
<el-descriptions :column="2" border size="small">
|
|
<el-descriptions-item label="申请单号">{{ confirmData.applyNo }}</el-descriptions-item>
|
|
<el-descriptions-item label="试验类型">
|
|
<el-tag :type="confirmData.experimentType === 'High Risk' ? 'danger' : 'success'" size="small">
|
|
{{ confirmData.experimentType }}
|
|
</el-tag>
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="试验名称" :span="2">{{ confirmData.title }}</el-descriptions-item>
|
|
<el-descriptions-item label="工序顺序">第 {{ confirmData.processSeq }} 道</el-descriptions-item>
|
|
<el-descriptions-item label="工序名称">{{ confirmData.processStep }}</el-descriptions-item>
|
|
</el-descriptions>
|
|
</div>
|
|
|
|
<!-- 确认表单 -->
|
|
<el-divider content-position="left">确认信息</el-divider>
|
|
<el-form :model="confirmData" label-position="top" style="margin-left: 5px; margin-top: -5px;">
|
|
<el-row :gutter="20">
|
|
<el-col :span="12">
|
|
<el-form-item label="确认角色">
|
|
<el-tag :type="getRoleTagType(confirmData.roleType)" size="medium">
|
|
{{ getRoleName(confirmData.roleType) }}
|
|
</el-tag>
|
|
</el-form-item>
|
|
</el-col>
|
|
|
|
<el-col :span="12">
|
|
<el-form-item label="样品是否OK" required>
|
|
<el-radio-group v-model="confirmData.sampleOk">
|
|
<el-radio :label="true">OK</el-radio>
|
|
<el-radio :label="false">NG</el-radio>
|
|
</el-radio-group>
|
|
</el-form-item>
|
|
</el-col>
|
|
</el-row>
|
|
|
|
<el-row :gutter="20">
|
|
<el-col :span="24">
|
|
<el-form-item label="确认意见" required>
|
|
<el-input
|
|
v-model="confirmData.comment"
|
|
type="textarea"
|
|
:rows="3"
|
|
placeholder="请输入确认意见"
|
|
maxlength="500"
|
|
show-word-limit>
|
|
</el-input>
|
|
</el-form-item>
|
|
</el-col>
|
|
</el-row>
|
|
</el-form>
|
|
|
|
<el-footer style="height: 40px; margin-top: 60px; text-align: center">
|
|
<el-button type="success" @click="doConfirm" :loading="confirmLoading" icon="el-icon-check">
|
|
{{ confirmLoading ? '确认中...' : '确认提交' }}
|
|
</el-button>
|
|
<el-button type="primary" @click="confirmDialogVisible = false" :disabled="confirmLoading">关闭</el-button>
|
|
</el-footer>
|
|
</el-dialog>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { getPendingTriConfirmList, confirmTriApproval } from '@/api/erf/erf'
|
|
|
|
export default {
|
|
name: 'TriConfirm',
|
|
|
|
data() {
|
|
return {
|
|
searchExpanded: ['0'], // 搜索条件默认展开
|
|
|
|
// 查询条件
|
|
queryData: {
|
|
applyNo: '',
|
|
experimentType: '',
|
|
title: ''
|
|
},
|
|
|
|
// 数据列表
|
|
dataList: [],
|
|
filteredDataList: [],
|
|
dataListLoading: false,
|
|
|
|
// 确认弹窗
|
|
confirmDialogVisible: false,
|
|
confirmData: {
|
|
applyNo: '',
|
|
processStep: '',
|
|
processSeq: null,
|
|
roleType: '',
|
|
sampleOk: true,
|
|
comment: '',
|
|
approverUserId: this.$store.state.user.id,
|
|
approverName: this.$store.state.user.name,
|
|
// 用于展示的信息
|
|
experimentType: '',
|
|
title: ''
|
|
},
|
|
confirmLoading: false
|
|
}
|
|
},
|
|
|
|
computed: {
|
|
/**
|
|
* 计算可立即确认的数量
|
|
*/
|
|
canConfirmCount() {
|
|
return this.filteredDataList.filter(item => item.canConfirm).length
|
|
},
|
|
|
|
/**
|
|
* 计算等待上道工序的数量
|
|
*/
|
|
waitingCount() {
|
|
return this.filteredDataList.filter(item => !item.canConfirm).length
|
|
}
|
|
},
|
|
|
|
activated() {
|
|
this.getDataList()
|
|
},
|
|
|
|
methods: {
|
|
/**
|
|
* 获取待确认列表
|
|
*/
|
|
getDataList() {
|
|
this.dataListLoading = true
|
|
|
|
const params = {
|
|
currentUserId: this.$store.state.user.id,
|
|
site: this.$store.state.user.site
|
|
}
|
|
|
|
getPendingTriConfirmList(params).then(({data}) => {
|
|
this.dataListLoading = false
|
|
if (data && data.code === 0) {
|
|
this.dataList = data.list || []
|
|
this.filterData() // 应用筛选条件
|
|
} else {
|
|
this.dataList = []
|
|
this.filteredDataList = []
|
|
this.$message.error(data.msg || '查询失败')
|
|
}
|
|
}).catch(error => {
|
|
this.dataListLoading = false
|
|
this.$message.error('查询异常')
|
|
})
|
|
},
|
|
|
|
/**
|
|
* 处理查询按钮点击(重新从后端获取数据)
|
|
*/
|
|
handleQuery() {
|
|
this.getDataList()
|
|
},
|
|
|
|
/**
|
|
* 筛选数据(前端筛选)
|
|
*/
|
|
filterData() {
|
|
let result = [...this.dataList]
|
|
|
|
// 申请单号筛选
|
|
if (this.queryData.applyNo) {
|
|
const keyword = this.queryData.applyNo.toLowerCase()
|
|
result = result.filter(item =>
|
|
item.applyNo && item.applyNo.toLowerCase().includes(keyword)
|
|
)
|
|
}
|
|
|
|
// 试验类型筛选
|
|
if (this.queryData.experimentType) {
|
|
result = result.filter(item => item.experimentType === this.queryData.experimentType)
|
|
}
|
|
|
|
// 试验名称筛选
|
|
if (this.queryData.title) {
|
|
const keyword = this.queryData.title.toLowerCase()
|
|
result = result.filter(item =>
|
|
item.title && item.title.toLowerCase().includes(keyword)
|
|
)
|
|
}
|
|
|
|
this.filteredDataList = result
|
|
},
|
|
|
|
/**
|
|
* 重置查询条件
|
|
*/
|
|
resetQuery() {
|
|
this.queryData.applyNo = ''
|
|
this.queryData.experimentType = ''
|
|
this.queryData.title = ''
|
|
this.getDataList()
|
|
},
|
|
|
|
/**
|
|
* 打开确认对话框
|
|
*/
|
|
openConfirmDialog(item) {
|
|
if (!item.canConfirm) {
|
|
this.$message.warning(`请等待第${item.processSeq - 1}道工序完成三方确认后再操作`)
|
|
return
|
|
}
|
|
|
|
this.confirmData = {
|
|
applyNo: item.applyNo,
|
|
processStep: item.processStep,
|
|
processSeq: item.processSeq,
|
|
roleType: item.currentRole,
|
|
sampleOk: true,
|
|
comment: '',
|
|
approverUserId: this.$store.state.user.id,
|
|
approverName: this.$store.state.user.name,
|
|
// 用于展示的信息
|
|
experimentType: item.experimentType,
|
|
title: item.title
|
|
}
|
|
this.confirmDialogVisible = true
|
|
},
|
|
|
|
/**
|
|
* 执行确认
|
|
*/
|
|
doConfirm() {
|
|
if ((!this.confirmData.comment || this.confirmData.comment.trim() === '') && !this.confirmData.sampleOk) {
|
|
this.$message.warning('请输入确认意见')
|
|
return
|
|
}
|
|
|
|
this.confirmLoading = true
|
|
|
|
confirmTriApproval(this.confirmData).then(({data}) => {
|
|
this.confirmLoading = false
|
|
if (data && data.code === 0) {
|
|
this.$message.success('确认成功')
|
|
this.confirmDialogVisible = false
|
|
this.getDataList() // 重新加载列表
|
|
} else {
|
|
this.$message.error(data.msg || '确认失败')
|
|
}
|
|
}).catch(error => {
|
|
this.confirmLoading = false
|
|
this.$message.error('确认异常')
|
|
})
|
|
},
|
|
|
|
/**
|
|
* 获取角色名称
|
|
*/
|
|
getRoleName(roleType) {
|
|
const names = {
|
|
'PROD': '生产负责人',
|
|
'QA': '质量负责人',
|
|
'TECH': '技术负责人'
|
|
}
|
|
return names[roleType] || roleType
|
|
},
|
|
|
|
/**
|
|
* 获取角色标签类型
|
|
*/
|
|
getRoleTagType(roleType) {
|
|
const types = {
|
|
'PROD': 'warning',
|
|
'QA': 'success',
|
|
'TECH': 'primary'
|
|
}
|
|
return types[roleType] || 'info'
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
/* 整体容器 */
|
|
.tri-confirm-container {
|
|
padding: 15px;
|
|
background: #f5f7fa;
|
|
min-height: calc(100vh - 80px);
|
|
}
|
|
|
|
/* ===== 页面头部 ===== */
|
|
.page-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 15px;
|
|
padding: 5px 20px;
|
|
background: #FFFFFF;
|
|
border-radius: 4px;
|
|
border: 1px solid #EBEEF5;
|
|
}
|
|
|
|
.header-left {
|
|
color: #303133;
|
|
}
|
|
|
|
.page-title {
|
|
margin: 0;
|
|
font-size: 20px;
|
|
font-weight: 600;
|
|
color: #303133;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
|
|
.page-title i {
|
|
font-size: 22px;
|
|
color: #409EFF;
|
|
}
|
|
|
|
.page-subtitle {
|
|
margin: 6px 0 0 0;
|
|
font-size: 13px;
|
|
color: #909399;
|
|
}
|
|
|
|
.header-right {
|
|
display: flex;
|
|
gap: 12px;
|
|
}
|
|
|
|
/* ===== 统计卡片 ===== */
|
|
.stat-cards {
|
|
display: flex;
|
|
gap: 12px;
|
|
}
|
|
|
|
.stat-card {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
padding: 12px 20px;
|
|
background: #FFFFFF;
|
|
border-radius: 4px;
|
|
border: 1px solid #EBEEF5;
|
|
transition: all 0.3s ease;
|
|
cursor: pointer;
|
|
min-width: 140px;
|
|
}
|
|
|
|
.stat-card:hover {
|
|
border-color: #409EFF;
|
|
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.15);
|
|
}
|
|
|
|
.stat-icon {
|
|
width: 40px;
|
|
height: 40px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border-radius: 4px;
|
|
font-size: 20px;
|
|
color: white;
|
|
}
|
|
|
|
.stat-total .stat-icon {
|
|
background: #409EFF;
|
|
}
|
|
|
|
.stat-can-confirm .stat-icon {
|
|
background: #67C23A;
|
|
}
|
|
|
|
.stat-waiting .stat-icon {
|
|
background: #E6A23C;
|
|
}
|
|
|
|
.stat-content {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.stat-value {
|
|
font-size: 24px;
|
|
font-weight: 600;
|
|
color: #303133;
|
|
line-height: 1;
|
|
}
|
|
|
|
.stat-label {
|
|
font-size: 12px;
|
|
color: #909399;
|
|
margin-top: 4px;
|
|
}
|
|
|
|
/* ===== 搜索区域 ===== */
|
|
.search-section {
|
|
margin-bottom: 15px;
|
|
background: white;
|
|
border-radius: 4px;
|
|
border: 1px solid #EBEEF5;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.search-section >>> .el-collapse-item__header {
|
|
padding: 0 15px;
|
|
height: 45px;
|
|
line-height: 45px;
|
|
background: white;
|
|
border-bottom: 1px solid #ebeef5;
|
|
font-size: 13px;
|
|
color: #303133;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.search-section >>> .el-collapse-item__content {
|
|
padding: 15px;
|
|
background: #FFFFFF;
|
|
}
|
|
|
|
.search-form {
|
|
margin: 0;
|
|
}
|
|
|
|
.search-form >>> .el-form-item {
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
/* ===== 卡片容器 ===== */
|
|
.cards-container {
|
|
min-height: 400px;
|
|
position: relative;
|
|
}
|
|
|
|
.cards-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(380px, 1fr));
|
|
gap: 15px;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
/* ===== 确认卡片 ===== */
|
|
.confirm-card {
|
|
background: white;
|
|
border-radius: 4px;
|
|
padding: 12px;
|
|
border: 1px solid #EBEEF5;
|
|
transition: all 0.3s ease;
|
|
cursor: pointer;
|
|
position: relative;
|
|
}
|
|
|
|
.confirm-card::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 1px;
|
|
height: 100%;
|
|
background: #67C23A;
|
|
transition: all 0.3s ease;
|
|
border-radius: 4px 0 0 4px;
|
|
}
|
|
|
|
.confirm-card.high-risk::before {
|
|
background: #F56C6C;
|
|
}
|
|
|
|
.confirm-card.disabled {
|
|
opacity: 0.7;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.confirm-card.disabled::before {
|
|
background: #909399;
|
|
}
|
|
|
|
.confirm-card:hover:not(.disabled) {
|
|
border-color: #409EFF;
|
|
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.15);
|
|
}
|
|
|
|
/* 卡片头部 */
|
|
.card-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 4px;
|
|
padding-bottom: 6px;
|
|
border-bottom: 1px solid #EBEEF5;
|
|
}
|
|
|
|
.card-title-area {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
|
|
.risk-tag {
|
|
font-weight: 500;
|
|
padding: 0px 12px;
|
|
font-size: 13px;
|
|
}
|
|
|
|
.risk-tag i {
|
|
margin-right: 4px;
|
|
}
|
|
|
|
.apply-no {
|
|
font-size: 13px;
|
|
color: #606266;
|
|
font-family: 'Courier New', monospace;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.role-tag {
|
|
font-weight: 500;
|
|
padding: 0px 12px;
|
|
font-size: 13px;
|
|
}
|
|
|
|
/* 卡片主体 */
|
|
.card-body {
|
|
margin-bottom: 4px;
|
|
}
|
|
|
|
.experiment-title {
|
|
font-size: 15px;
|
|
font-weight: 600;
|
|
color: #303133;
|
|
margin: 0 0 4px 0;
|
|
line-height: 1.5;
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 6px;
|
|
}
|
|
|
|
.experiment-title i {
|
|
color: #409EFF;
|
|
margin-top: 2px;
|
|
font-size: 16px;
|
|
}
|
|
|
|
.process-info {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
margin-bottom: 6px;
|
|
padding: 10px;
|
|
border-radius: 4px;
|
|
background: #F5F7FA;
|
|
//border-radius: 3px;
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
.process-badge {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.process-badge i {
|
|
font-size: 16px;
|
|
}
|
|
|
|
.process-name {
|
|
flex: 1;
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.card-details {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
margin-bottom: 6px;
|
|
}
|
|
|
|
.detail-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
font-size: 13px;
|
|
padding: 6px 10px;
|
|
background: #F5F7FA;
|
|
border-radius: 3px;
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
.detail-row:hover {
|
|
background: #ECF5FF;
|
|
}
|
|
|
|
.detail-label {
|
|
color: #909399;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 5px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.detail-label i {
|
|
color: #409EFF;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.detail-value {
|
|
color: #606266;
|
|
font-weight: 500;
|
|
text-align: right;
|
|
max-width: 200px;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* 三方确认状态 */
|
|
.tri-status {
|
|
display: flex;
|
|
justify-content: space-around;
|
|
padding: 5px;
|
|
background: #F5F7FA;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.status-item {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 6px;
|
|
color: #909399;
|
|
font-size: 13px;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.status-item i {
|
|
font-size: 24px;
|
|
}
|
|
|
|
.status-item.confirmed {
|
|
color: #67C23A;
|
|
}
|
|
|
|
.status-item.confirmed i {
|
|
animation: checkBounce 0.6s ease;
|
|
}
|
|
|
|
@keyframes checkBounce {
|
|
0%, 100% { transform: scale(1); }
|
|
50% { transform: scale(1.2); }
|
|
}
|
|
|
|
/* 卡片底部 */
|
|
.card-footer {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding-top: 6px;
|
|
border-top: 1px solid #EBEEF5;
|
|
}
|
|
|
|
.status-tip {
|
|
font-size: 12px;
|
|
color: #E6A23C;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 5px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.status-tip i {
|
|
font-size: 14px;
|
|
}
|
|
|
|
.status-tip.ready {
|
|
color: #67C23A;
|
|
}
|
|
|
|
.action-buttons {
|
|
display: flex;
|
|
gap: 8px;
|
|
}
|
|
|
|
.confirm-btn {
|
|
background: #f0f9ff;
|
|
border-color: #b3e19d;
|
|
color: #67C23A;
|
|
font-weight: 500;
|
|
padding: 7px 20px;
|
|
font-size: 13px;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.confirm-btn:hover:not(:disabled) {
|
|
background: #67C23A;
|
|
border-color: #67C23A;
|
|
color: #FFFFFF;
|
|
}
|
|
|
|
.confirm-btn:disabled {
|
|
opacity: 0.5;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
/* ===== 空状态 ===== */
|
|
.empty-state {
|
|
text-align: center;
|
|
padding: 80px 20px;
|
|
background: white;
|
|
border-radius: 4px;
|
|
border: 1px solid #EBEEF5;
|
|
}
|
|
|
|
.empty-icon {
|
|
font-size: 64px;
|
|
color: #c0c4cc;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.empty-text {
|
|
font-size: 15px;
|
|
color: #606266;
|
|
margin: 0 0 6px 0;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.empty-subtext {
|
|
font-size: 13px;
|
|
color: #909399;
|
|
margin: 0;
|
|
}
|
|
|
|
/* ===== 卡片动画 ===== */
|
|
.card-list-enter-active {
|
|
animation: cardFadeIn 0.4s ease;
|
|
}
|
|
|
|
.card-list-leave-active {
|
|
animation: cardFadeOut 0.3s ease;
|
|
}
|
|
|
|
@keyframes cardFadeIn {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(15px);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
|
|
@keyframes cardFadeOut {
|
|
from {
|
|
opacity: 1;
|
|
transform: scale(1);
|
|
}
|
|
to {
|
|
opacity: 0;
|
|
transform: scale(0.95);
|
|
}
|
|
}
|
|
|
|
/* ===== 弹窗样式 ===== */
|
|
.confirm-info {
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.confirm-info >>> .el-descriptions {
|
|
font-size: 13px;
|
|
}
|
|
|
|
/* ===== 响应式设计 ===== */
|
|
@media screen and (max-width: 1600px) {
|
|
.cards-grid {
|
|
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
|
|
}
|
|
}
|
|
|
|
@media screen and (max-width: 1200px) {
|
|
.cards-grid {
|
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
|
}
|
|
|
|
.page-header {
|
|
flex-direction: column;
|
|
gap: 15px;
|
|
align-items: flex-start;
|
|
}
|
|
|
|
.stat-cards {
|
|
width: 100%;
|
|
overflow-x: auto;
|
|
}
|
|
}
|
|
|
|
@media screen and (max-width: 768px) {
|
|
.cards-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.stat-cards {
|
|
flex-direction: column;
|
|
}
|
|
|
|
.stat-card {
|
|
width: 100%;
|
|
}
|
|
}
|
|
|
|
/deep/ .no-arrow .el-collapse-item__header .el-collapse-item__arrow {
|
|
display: none !important;
|
|
}
|
|
|
|
</style>
|