|
|
|
@ -1,13 +1,55 @@ |
|
|
|
<template> |
|
|
|
<div class="mod-config"> |
|
|
|
<!-- 查询条件 --> |
|
|
|
<el-form :inline="true" label-position="top"> |
|
|
|
<div class="schedule-container"> |
|
|
|
<!-- 页面标题和统计 --> |
|
|
|
<div class="page-header"> |
|
|
|
<div class="header-left"> |
|
|
|
<h2 class="page-title"> |
|
|
|
<i class="el-icon-s-order"></i> 计划员排产 |
|
|
|
</h2> |
|
|
|
<p class="page-subtitle">试验申请排产管理</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">{{ totalPage }}</div> |
|
|
|
<div class="stat-label">待排产总数</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="stat-card stat-high-risk"> |
|
|
|
<div class="stat-icon"><i class="el-icon-warning"></i></div> |
|
|
|
<div class="stat-content"> |
|
|
|
<div class="stat-value">{{ highRiskCount }}</div> |
|
|
|
<div class="stat-label">高风险试验</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="stat-card stat-low-risk"> |
|
|
|
<div class="stat-icon"><i class="el-icon-success"></i></div> |
|
|
|
<div class="stat-content"> |
|
|
|
<div class="stat-value">{{ lowRiskCount }}</div> |
|
|
|
<div class="stat-label">低风险试验</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 查询条件表单 --> |
|
|
|
<div class="search-section"> |
|
|
|
<el-collapse 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="searchData.applyNo" placeholder="请输入申请单号" clearable style="width: 150px"></el-input> |
|
|
|
<el-input v-model="searchData.applyNo" placeholder="支持模糊查询" clearable style="width: 150px"></el-input> |
|
|
|
</el-form-item> |
|
|
|
|
|
|
|
<el-form-item label="事业部"> |
|
|
|
<el-select v-model="searchData.buNo" clearable style="width: 120px"> |
|
|
|
<el-select v-model="searchData.buNo" placeholder="请选择" clearable style="width: 120px"> |
|
|
|
<el-option label="全部" value=""></el-option> |
|
|
|
<el-option |
|
|
|
v-for="i in buList" |
|
|
|
@ -42,26 +84,6 @@ |
|
|
|
<el-input v-model="searchData.creatorName" placeholder="支持模糊查询" clearable style="width: 120px"></el-input> |
|
|
|
</el-form-item> |
|
|
|
|
|
|
|
<!-- <el-form-item label="申请开始日期"> |
|
|
|
<el-date-picker |
|
|
|
v-model="searchData.createStartDate" |
|
|
|
type="date" |
|
|
|
placeholder="选择日期" |
|
|
|
value-format="yyyy-MM-dd" |
|
|
|
style="width: 150px"> |
|
|
|
</el-date-picker> |
|
|
|
</el-form-item> |
|
|
|
|
|
|
|
<el-form-item label="申请结束日期"> |
|
|
|
<el-date-picker |
|
|
|
v-model="searchData.createEndDate" |
|
|
|
type="date" |
|
|
|
placeholder="选择日期" |
|
|
|
value-format="yyyy-MM-dd" |
|
|
|
style="width: 150px"> |
|
|
|
</el-date-picker> |
|
|
|
</el-form-item>--> |
|
|
|
|
|
|
|
<el-form-item label="期望完成开始日期"> |
|
|
|
<el-date-picker |
|
|
|
v-model="searchData.expectedFinishStartDate" |
|
|
|
@ -83,69 +105,121 @@ |
|
|
|
</el-form-item> |
|
|
|
|
|
|
|
<el-form-item label=" "> |
|
|
|
<el-button @click="getDataList('Y')" type="primary">查询</el-button> |
|
|
|
<el-button @click="getDataList('Y')" 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> |
|
|
|
|
|
|
|
<!-- 待排产申请单列表 --> |
|
|
|
<el-table |
|
|
|
:data="dataList" |
|
|
|
v-loading="dataListLoading" |
|
|
|
border |
|
|
|
stripe |
|
|
|
style="width: 100%;" |
|
|
|
:height="height"> |
|
|
|
|
|
|
|
<el-table-column |
|
|
|
label="操作" |
|
|
|
width="100" |
|
|
|
align="center" |
|
|
|
fixed="left"> |
|
|
|
<template slot-scope="scope"> |
|
|
|
<a type="text" size="small" @click="openScheduleDialog(scope.row)">排产</a> |
|
|
|
</template> |
|
|
|
</el-table-column> |
|
|
|
|
|
|
|
<el-table-column prop="applyNo" label="申请单号" width="140" align="center"></el-table-column> |
|
|
|
<el-table-column prop="buNo" label="事业部" width="80" align="center"></el-table-column> |
|
|
|
<el-table-column prop="experimentType" label="试验类型" min-width="100" align="center"></el-table-column> |
|
|
|
<el-table-column prop="title" label="试验名称" min-width="200" align="left" show-overflow-tooltip></el-table-column> |
|
|
|
<el-table-column |
|
|
|
prop="projectNo" |
|
|
|
label="项目编号" |
|
|
|
min-width="120" |
|
|
|
align="center" |
|
|
|
header-align="center" |
|
|
|
show-overflow-tooltip> |
|
|
|
</el-table-column> |
|
|
|
|
|
|
|
<el-table-column |
|
|
|
prop="productType" |
|
|
|
label="产品型号" |
|
|
|
min-width="200" |
|
|
|
align="center" |
|
|
|
header-align="center" |
|
|
|
show-overflow-tooltip> |
|
|
|
</el-table-column> |
|
|
|
<el-table-column prop="expectedFinishDate" label="期望完成日期" width="120" align="center"></el-table-column> |
|
|
|
<el-table-column |
|
|
|
prop="creatorName" |
|
|
|
label="申请人" |
|
|
|
width="100" |
|
|
|
align="center" |
|
|
|
header-align="center"> |
|
|
|
</el-table-column> |
|
|
|
|
|
|
|
<el-table-column |
|
|
|
prop="createTime" |
|
|
|
label="申请时间" |
|
|
|
width="160" |
|
|
|
align="center" |
|
|
|
header-align="center"> |
|
|
|
</el-table-column> |
|
|
|
</el-table> |
|
|
|
|
|
|
|
<!-- 分页 --> |
|
|
|
<!-- 卡片列表 --> |
|
|
|
<div class="cards-container" v-loading="dataListLoading"> |
|
|
|
<transition-group name="card-list" tag="div" class="cards-grid"> |
|
|
|
<div |
|
|
|
v-for="item in dataList" |
|
|
|
:key="item.applyNo" |
|
|
|
class="schedule-card" |
|
|
|
:class="{'high-risk': item.experimentType === 'High Risk'}" |
|
|
|
@click="openScheduleDialog(item)"> |
|
|
|
|
|
|
|
<!-- 卡片头部 --> |
|
|
|
<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="info" size="small" effect="plain">{{ item.buNo }}</el-tag> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 卡片主体内容 --> |
|
|
|
<div class="card-body"> |
|
|
|
<h3 class="experiment-title"> |
|
|
|
<i class="el-icon-document"></i> |
|
|
|
{{ item.title }} |
|
|
|
</h3> |
|
|
|
|
|
|
|
<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-date"></i> |
|
|
|
期望完成日期 |
|
|
|
</span> |
|
|
|
<span class="detail-value">{{ item.expectedFinishDate || '-' }}</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 class="detail-row"> |
|
|
|
<span class="detail-label"> |
|
|
|
<i class="el-icon-time"></i> |
|
|
|
申请时间 |
|
|
|
</span> |
|
|
|
<span class="detail-value">{{ item.createTime }}</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 卡片底部 --> |
|
|
|
<div class="card-footer"> |
|
|
|
<div class="current-step"> |
|
|
|
<i class="el-icon-position"></i> |
|
|
|
{{ item.currentStep || '待排产' }} |
|
|
|
</div> |
|
|
|
<div class="action-buttons"> |
|
|
|
<el-button |
|
|
|
type="primary" |
|
|
|
size="small" |
|
|
|
plain |
|
|
|
icon="el-icon-s-order" |
|
|
|
class="schedule-btn" |
|
|
|
@click.stop="openScheduleDialog(item)"> |
|
|
|
立即排产 |
|
|
|
</el-button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</transition-group> |
|
|
|
|
|
|
|
<!-- 空状态 --> |
|
|
|
<div v-if="!dataListLoading && dataList.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> |
|
|
|
|
|
|
|
<!-- 分页组件 --> |
|
|
|
<div class="pagination-wrapper" v-if="dataList.length > 0"> |
|
|
|
<el-pagination |
|
|
|
@size-change="sizeChangeHandle" |
|
|
|
@current-change="currentChangeHandle" |
|
|
|
@ -154,54 +228,58 @@ |
|
|
|
:page-size="pageSize" |
|
|
|
:total="totalPage" |
|
|
|
layout="total, sizes, prev, pager, next, jumper" |
|
|
|
style="margin-top: 20px; text-align: right;"> |
|
|
|
background> |
|
|
|
</el-pagination> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 排产弹窗 --> |
|
|
|
<el-dialog |
|
|
|
title="计划员排产" |
|
|
|
:visible.sync="scheduleDialogVisible" |
|
|
|
width="600px" |
|
|
|
:close-on-click-modal="false" |
|
|
|
v-drag> |
|
|
|
<div slot="title" class="dialog-header"> |
|
|
|
<i class="el-icon-s-order"></i> |
|
|
|
<span>计划员排产</span> |
|
|
|
</div> |
|
|
|
|
|
|
|
<el-form :model="scheduleData" label-position="top" style="margin-left: 5px; margin-top: -5px;"> |
|
|
|
<el-row :gutter="20"> |
|
|
|
<el-col :span="8"> |
|
|
|
<el-form-item label="申请单号"> |
|
|
|
<span>{{ scheduleData.applyNo }}</span> |
|
|
|
</el-form-item> |
|
|
|
</el-col> |
|
|
|
|
|
|
|
<el-col :span="8"> |
|
|
|
<el-form-item label="试验类型"> |
|
|
|
<el-tag :type="currentApply.experimentType === 'High Risk' ? 'danger' : 'success'"> |
|
|
|
<!-- 申请单基本信息 --> |
|
|
|
<div class="schedule-info-section"> |
|
|
|
<div class="info-title"> |
|
|
|
<i class="el-icon-info"></i> |
|
|
|
申请单信息 |
|
|
|
</div> |
|
|
|
<el-descriptions :column="2" border size="small" class="apply-descriptions"> |
|
|
|
<el-descriptions-item label="申请单号">{{ scheduleData.applyNo }}</el-descriptions-item> |
|
|
|
<el-descriptions-item label="试验类型"> |
|
|
|
<el-tag :type="currentApply.experimentType === 'High Risk' ? 'danger' : 'success'" effect="dark"> |
|
|
|
<i :class="currentApply.experimentType === 'High Risk' ? 'el-icon-warning' : 'el-icon-success'"></i> |
|
|
|
{{ currentApply.experimentType }} |
|
|
|
</el-tag> |
|
|
|
</el-form-item> |
|
|
|
</el-col> |
|
|
|
|
|
|
|
<el-col :span="8"> |
|
|
|
<el-form-item label="申请人"> |
|
|
|
<span>{{ currentApply.creatorName }}</span> |
|
|
|
</el-form-item> |
|
|
|
</el-col> |
|
|
|
</el-row> |
|
|
|
|
|
|
|
<el-row :gutter="20"> |
|
|
|
<el-col :span="24"> |
|
|
|
<el-form-item label="试验名称"> |
|
|
|
<span>{{ currentApply.title }}</span> |
|
|
|
</el-form-item> |
|
|
|
</el-col> |
|
|
|
</el-row> |
|
|
|
</el-descriptions-item> |
|
|
|
<el-descriptions-item label="试验名称" :span="2">{{ currentApply.title }}</el-descriptions-item> |
|
|
|
<el-descriptions-item label="项目编号">{{ currentApply.projectNo || '-' }}</el-descriptions-item> |
|
|
|
<el-descriptions-item label="产品型号">{{ currentApply.productType || '-' }}</el-descriptions-item> |
|
|
|
<el-descriptions-item label="期望完成日期">{{ currentApply.expectedFinishDate || '-' }}</el-descriptions-item> |
|
|
|
<el-descriptions-item label="申请人">{{ currentApply.creatorName }}</el-descriptions-item> |
|
|
|
</el-descriptions> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 排产信息录入 --> |
|
|
|
<div class="schedule-input-section"> |
|
|
|
<div class="info-title"> |
|
|
|
<i class="el-icon-edit"></i> |
|
|
|
排产信息 |
|
|
|
</div> |
|
|
|
<el-form :model="scheduleData" label-position="top" class="schedule-form"> |
|
|
|
<el-row :gutter="20"> |
|
|
|
<el-col :span="12"> |
|
|
|
<el-form-item label="实验工单号" required> |
|
|
|
<el-input |
|
|
|
v-model="scheduleData.workOrderNo" |
|
|
|
placeholder="请输入实验工单号"> |
|
|
|
placeholder="请输入实验工单号" |
|
|
|
clearable> |
|
|
|
<i slot="prefix" class="el-input__icon el-icon-document"></i> |
|
|
|
</el-input> |
|
|
|
</el-form-item> |
|
|
|
</el-col> |
|
|
|
@ -214,18 +292,20 @@ |
|
|
|
format="yyyy-MM-dd" |
|
|
|
value-format="yyyy-MM-dd" |
|
|
|
placeholder="选择排产日期" |
|
|
|
prefix-icon="el-icon-date" |
|
|
|
style="width: 100%"> |
|
|
|
</el-date-picker> |
|
|
|
</el-form-item> |
|
|
|
</el-col> |
|
|
|
</el-row> |
|
|
|
</el-form> |
|
|
|
</div> |
|
|
|
|
|
|
|
<el-footer style="height: 40px; margin-top: 10px; text-align: center"> |
|
|
|
<el-button type="primary" @click="doSchedule" :loading="scheduleLoading" > |
|
|
|
{{ scheduleLoading ? '排产中...' : '确定排产' }} |
|
|
|
</el-button> |
|
|
|
<el-button type="primary" @click="scheduleDialogVisible = false" :disabled="scheduleLoading">关闭</el-button> |
|
|
|
<el-button @click="scheduleDialogVisible = false" :disabled="scheduleLoading">关闭</el-button> |
|
|
|
</el-footer> |
|
|
|
</el-dialog> |
|
|
|
</div> |
|
|
|
@ -241,9 +321,17 @@ export default { |
|
|
|
data() { |
|
|
|
return { |
|
|
|
buList: [], |
|
|
|
searchExpanded: ['0'], // 搜索条件默认展开 |
|
|
|
searchData: { |
|
|
|
applyNo: '', |
|
|
|
buNo: '', |
|
|
|
experimentType: '', |
|
|
|
title: '', |
|
|
|
projectNo: '', |
|
|
|
productType: '', |
|
|
|
creatorName: '', |
|
|
|
expectedFinishStartDate: '', |
|
|
|
expectedFinishEndDate: '', |
|
|
|
currentUserId: this.$store.state.user.id, |
|
|
|
pageType: 'PLANNER', // 计划员排产页面,只查询计划员排产节点 |
|
|
|
pendingStatus: '已批准', // 计划员排产只查询已批准状态 |
|
|
|
@ -264,9 +352,23 @@ export default { |
|
|
|
workOrderNo: '', |
|
|
|
scheduledDate: '' |
|
|
|
}, |
|
|
|
scheduleLoading: false, |
|
|
|
scheduleLoading: false |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
computed: { |
|
|
|
/** |
|
|
|
* 计算高风险试验数量 |
|
|
|
*/ |
|
|
|
highRiskCount() { |
|
|
|
return this.dataList.filter(item => item.experimentType === 'High Risk').length |
|
|
|
}, |
|
|
|
|
|
|
|
height: window.innerHeight - 260 |
|
|
|
/** |
|
|
|
* 计算低风险试验数量 |
|
|
|
*/ |
|
|
|
lowRiskCount() { |
|
|
|
return this.dataList.filter(item => item.experimentType === 'Low Risk').length |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
@ -288,6 +390,9 @@ export default { |
|
|
|
}) |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
|
* 获取待排产列表 |
|
|
|
*/ |
|
|
|
getDataList(flag) { |
|
|
|
if (flag === 'Y') { |
|
|
|
this.pageIndex = 1 |
|
|
|
@ -295,6 +400,7 @@ export default { |
|
|
|
|
|
|
|
this.searchData.page = this.pageIndex |
|
|
|
this.searchData.limit = this.pageSize |
|
|
|
this.searchData.currentUserId = this.$store.state.user.id |
|
|
|
|
|
|
|
this.dataListLoading = true |
|
|
|
|
|
|
|
@ -306,12 +412,30 @@ export default { |
|
|
|
} else { |
|
|
|
this.dataList = [] |
|
|
|
this.totalPage = 0 |
|
|
|
this.$message.error(data.msg || '查询失败') |
|
|
|
} |
|
|
|
}).catch(error => { |
|
|
|
this.dataListLoading = false |
|
|
|
this.$message.error('查询异常') |
|
|
|
}) |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
|
* 重置查询条件 |
|
|
|
*/ |
|
|
|
resetQuery() { |
|
|
|
this.searchData.applyNo = '' |
|
|
|
this.searchData.buNo = '' |
|
|
|
this.searchData.experimentType = '' |
|
|
|
this.searchData.title = '' |
|
|
|
this.searchData.projectNo = '' |
|
|
|
this.searchData.productType = '' |
|
|
|
this.searchData.creatorName = '' |
|
|
|
this.searchData.expectedFinishStartDate = '' |
|
|
|
this.searchData.expectedFinishEndDate = '' |
|
|
|
this.getDataList('Y') |
|
|
|
}, |
|
|
|
|
|
|
|
openScheduleDialog(row) { |
|
|
|
this.currentApply = { ...row } |
|
|
|
this.scheduleData = { |
|
|
|
@ -367,7 +491,512 @@ export default { |
|
|
|
</script> |
|
|
|
|
|
|
|
<style scoped> |
|
|
|
.mod-config { |
|
|
|
/* 整体容器 */ |
|
|
|
.schedule-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-high-risk .stat-icon { |
|
|
|
background: #F56C6C; |
|
|
|
} |
|
|
|
|
|
|
|
.stat-low-risk .stat-icon { |
|
|
|
background: #67C23A; |
|
|
|
} |
|
|
|
|
|
|
|
.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; |
|
|
|
} |
|
|
|
|
|
|
|
/* ===== 排产卡片 ===== */ |
|
|
|
.schedule-card { |
|
|
|
background: white; |
|
|
|
border-radius: 4px; |
|
|
|
padding: 18px; |
|
|
|
border: 1px solid #EBEEF5; |
|
|
|
transition: all 0.3s ease; |
|
|
|
cursor: pointer; |
|
|
|
position: relative; |
|
|
|
} |
|
|
|
|
|
|
|
.schedule-card::before { |
|
|
|
content: ''; |
|
|
|
position: absolute; |
|
|
|
top: 0; |
|
|
|
left: 0; |
|
|
|
width: 1px; |
|
|
|
height: 100%; |
|
|
|
background: #67C23A; |
|
|
|
transition: all 0.3s ease; |
|
|
|
} |
|
|
|
|
|
|
|
.schedule-card.high-risk::before { |
|
|
|
background: #F56C6C; |
|
|
|
} |
|
|
|
|
|
|
|
.schedule-card:hover { |
|
|
|
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: 14px; |
|
|
|
padding-bottom: 10px; |
|
|
|
border-bottom: 1px solid #EBEEF5; |
|
|
|
} |
|
|
|
|
|
|
|
.card-title-area { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
gap: 10px; |
|
|
|
} |
|
|
|
|
|
|
|
.risk-tag { |
|
|
|
font-weight: 500; |
|
|
|
padding: 0px 10px; |
|
|
|
font-size: 14px; |
|
|
|
} |
|
|
|
|
|
|
|
.risk-tag i { |
|
|
|
margin-right: 4px; |
|
|
|
} |
|
|
|
|
|
|
|
.apply-no { |
|
|
|
font-size: 13px; |
|
|
|
color: #606266; |
|
|
|
font-family: 'Courier New', monospace; |
|
|
|
font-weight: 500; |
|
|
|
} |
|
|
|
|
|
|
|
/* 卡片主体 */ |
|
|
|
.card-body { |
|
|
|
//margin-bottom: 14px; |
|
|
|
} |
|
|
|
|
|
|
|
.experiment-title { |
|
|
|
font-size: 15px; |
|
|
|
font-weight: 600; |
|
|
|
color: #303133; |
|
|
|
margin: 0 0 14px 0; |
|
|
|
line-height: 1.5; |
|
|
|
display: flex; |
|
|
|
align-items: flex-start; |
|
|
|
gap: 6px; |
|
|
|
} |
|
|
|
|
|
|
|
.experiment-title i { |
|
|
|
color: #409EFF; |
|
|
|
margin-top: 2px; |
|
|
|
font-size: 16px; |
|
|
|
} |
|
|
|
|
|
|
|
.card-details { |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
gap: 8px; |
|
|
|
} |
|
|
|
|
|
|
|
.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: 250px; |
|
|
|
overflow: hidden; |
|
|
|
text-overflow: ellipsis; |
|
|
|
white-space: nowrap; |
|
|
|
} |
|
|
|
|
|
|
|
/* 卡片底部 */ |
|
|
|
.card-footer { |
|
|
|
display: flex; |
|
|
|
justify-content: space-between; |
|
|
|
align-items: center; |
|
|
|
padding-top: 10px; |
|
|
|
border-top: 1px solid #EBEEF5; |
|
|
|
} |
|
|
|
|
|
|
|
.current-step { |
|
|
|
font-size: 12px; |
|
|
|
color: #909399; |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
gap: 5px; |
|
|
|
} |
|
|
|
|
|
|
|
.current-step i { |
|
|
|
color: #409EFF; |
|
|
|
} |
|
|
|
|
|
|
|
.action-buttons { |
|
|
|
display: flex; |
|
|
|
gap: 8px; |
|
|
|
} |
|
|
|
|
|
|
|
.schedule-btn { |
|
|
|
background: #ecf5ff; |
|
|
|
border-color: #b3d8ff; |
|
|
|
color: #409EFF; |
|
|
|
font-weight: 500; |
|
|
|
padding: 7px 16px; |
|
|
|
font-size: 13px; |
|
|
|
transition: all 0.3s ease; |
|
|
|
} |
|
|
|
|
|
|
|
.schedule-btn:hover { |
|
|
|
background: #409EFF; |
|
|
|
border-color: #409EFF; |
|
|
|
color: #FFFFFF; |
|
|
|
} |
|
|
|
|
|
|
|
/* ===== 空状态 ===== */ |
|
|
|
.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; |
|
|
|
} |
|
|
|
|
|
|
|
/* ===== 分页 ===== */ |
|
|
|
.pagination-wrapper { |
|
|
|
display: flex; |
|
|
|
justify-content: center; |
|
|
|
padding: 15px; |
|
|
|
background: white; |
|
|
|
border-radius: 4px; |
|
|
|
border: 1px solid #EBEEF5; |
|
|
|
} |
|
|
|
|
|
|
|
/* ===== 卡片动画 ===== */ |
|
|
|
.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); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* ===== 响应式设计 ===== */ |
|
|
|
@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%; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* ===== 弹窗样式 ===== */ |
|
|
|
.dialog-header { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
gap: 8px; |
|
|
|
font-size: 16px; |
|
|
|
font-weight: 600; |
|
|
|
color: #303133; |
|
|
|
} |
|
|
|
|
|
|
|
.dialog-header i { |
|
|
|
color: #409EFF; |
|
|
|
font-size: 18px; |
|
|
|
} |
|
|
|
|
|
|
|
.schedule-info-section { |
|
|
|
margin-bottom: 20px; |
|
|
|
} |
|
|
|
|
|
|
|
.schedule-input-section { |
|
|
|
margin-top: 20px; |
|
|
|
} |
|
|
|
|
|
|
|
.info-title { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
gap: 6px; |
|
|
|
font-size: 14px; |
|
|
|
font-weight: 600; |
|
|
|
color: #303133; |
|
|
|
margin-bottom: 12px; |
|
|
|
padding-bottom: 8px; |
|
|
|
border-bottom: 1px solid #409EFF; |
|
|
|
} |
|
|
|
|
|
|
|
.info-title i { |
|
|
|
color: #409EFF; |
|
|
|
font-size: 16px; |
|
|
|
} |
|
|
|
|
|
|
|
.apply-descriptions { |
|
|
|
font-size: 13px; |
|
|
|
} |
|
|
|
|
|
|
|
.apply-descriptions >>> .el-descriptions-item__label { |
|
|
|
background: #F5F7FA; |
|
|
|
font-weight: 600; |
|
|
|
color: #606266; |
|
|
|
width: 120px; |
|
|
|
} |
|
|
|
|
|
|
|
.apply-descriptions >>> .el-descriptions-item__content { |
|
|
|
color: #303133; |
|
|
|
} |
|
|
|
|
|
|
|
.schedule-form { |
|
|
|
margin-top: 10px; |
|
|
|
} |
|
|
|
|
|
|
|
.schedule-form >>> .el-form-item__label { |
|
|
|
font-weight: 600; |
|
|
|
color: #606266; |
|
|
|
} |
|
|
|
|
|
|
|
.dialog-footer { |
|
|
|
text-align: right; |
|
|
|
padding-top: 20px; |
|
|
|
border-top: 1px solid #EBEEF5; |
|
|
|
} |
|
|
|
</style> |