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.
1749 lines
48 KiB
1749 lines
48 KiB
<template>
|
|
<div class="mod-config exp-apply-page">
|
|
<!-- 查询条件表单 -->
|
|
<el-form :inline="true" label-position="top" class="query-form">
|
|
<el-form-item label="申请单号">
|
|
<el-input v-model="queryHeaderData.applyNo" placeholder="请输入申请单号" clearable style="width: 150px"></el-input>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="事业部">
|
|
<el-select v-model="queryHeaderData.buNo" placeholder="请选择" clearable style="width: 120px">
|
|
<el-option label="全部" value=""></el-option>
|
|
<el-option
|
|
v-for="i in buList"
|
|
:key="i.buNo"
|
|
:label="i.buDesc"
|
|
:value="i.buNo">
|
|
</el-option>
|
|
</el-select>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="试验类型">
|
|
<el-select v-model="queryHeaderData.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="queryHeaderData.title" placeholder="支持模糊查询" clearable style="width: 150px"></el-input>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="项目编号">
|
|
<el-input v-model="queryHeaderData.projectNo" placeholder="支持模糊查询" clearable style="width: 150px"></el-input>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="产品型号">
|
|
<el-input v-model="queryHeaderData.productType" placeholder="支持模糊查询" clearable style="width: 150px"></el-input>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="状态">
|
|
<el-select v-model="queryHeaderData.status" placeholder="请选择" clearable style="width: 120px">
|
|
<el-option label="全部" value=""></el-option>
|
|
<el-option label="草稿" value="草稿"></el-option>
|
|
<el-option label="已下达" value="已下达"></el-option>
|
|
<el-option label="已批准" value="已批准"></el-option>
|
|
<el-option label="生产中" value="生产中"></el-option>
|
|
<el-option label="样品确认" value="样品确认"></el-option>
|
|
<el-option label="已完成" value="已完成"></el-option>
|
|
</el-select>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="创建日期">
|
|
<el-date-picker
|
|
v-model="queryHeaderData.createStartDate"
|
|
type="date"
|
|
format="yyyy-MM-dd"
|
|
value-format="yyyy-MM-dd"
|
|
placeholder="开始日期"
|
|
style="width: 140px">
|
|
</el-date-picker>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="至">
|
|
<el-date-picker
|
|
v-model="queryHeaderData.createEndDate"
|
|
type="date"
|
|
format="yyyy-MM-dd"
|
|
value-format="yyyy-MM-dd"
|
|
placeholder="结束日期"
|
|
style="width: 140px">
|
|
</el-date-picker>
|
|
</el-form-item>
|
|
|
|
<el-form-item label=" " style="margin-top: -11px">
|
|
<el-button @click="getDataList('Y')" type="primary" plain class="search-btn">查询</el-button>
|
|
<el-button @click="resetQuery()" plain class="reset-btn">重置</el-button>
|
|
<el-button @click="openCreateDialog()" type="success" plain class="add-btn">新增申请单</el-button>
|
|
</el-form-item>
|
|
</el-form>
|
|
|
|
<!-- 数据表格 -->
|
|
<el-table
|
|
ref="dataTable"
|
|
@row-click="handleRowClick"
|
|
highlight-current-row
|
|
:data="dataList"
|
|
v-loading="dataListLoading"
|
|
border
|
|
class="data-table"
|
|
style="width: 100%;"
|
|
:height="tableHeight">
|
|
|
|
<el-table-column
|
|
label="操作"
|
|
width="150"
|
|
align="center"
|
|
header-align="center">
|
|
<template slot-scope="scope">
|
|
<a
|
|
@click="editApply(scope.row)">修改</a>
|
|
<a
|
|
v-if="scope.row.status === '草稿' || scope.row.status === '已驳回'"
|
|
@click="submitApply(scope.row)">{{ scope.row.status === '已驳回' ? '重新下达' : '下达' }}</a>
|
|
<a
|
|
v-if="scope.row.status === '草稿'"
|
|
@click="deleteApply(scope.row)">删除</a>
|
|
<a
|
|
v-if="scope.row.status !== '草稿' && scope.row.status !== '已完成' && scope.row.status !== '已驳回'"
|
|
@click="withdrawApply(scope.row)">撤回</a>
|
|
<a
|
|
v-if="showSampleConfirmBtn(scope.row)"
|
|
@click="openSampleConfirm(scope.row)">样品确认</a>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column
|
|
prop="buDesc"
|
|
label="事业部"
|
|
width="70"
|
|
align="center"
|
|
header-align="center">
|
|
</el-table-column>
|
|
|
|
<el-table-column
|
|
prop="applyNo"
|
|
label="申请单号"
|
|
width="100"
|
|
align="center"
|
|
header-align="center"
|
|
show-overflow-tooltip>
|
|
</el-table-column>
|
|
<el-table-column
|
|
prop="status"
|
|
label="状态"
|
|
width="80"
|
|
align="center"
|
|
header-align="center">
|
|
</el-table-column>
|
|
<!-- <el-table-column
|
|
prop="currentStep"
|
|
label="当前步骤"
|
|
width="90"
|
|
align="center"
|
|
header-align="center">
|
|
</el-table-column>-->
|
|
<el-table-column
|
|
prop="experimentType"
|
|
label="试验类型"
|
|
width="100"
|
|
align="center" show-overflow-tooltip
|
|
header-align="center">
|
|
</el-table-column>
|
|
|
|
<el-table-column
|
|
prop="title"
|
|
label="试验名称"
|
|
min-width="120"
|
|
align="left"
|
|
header-align="center"
|
|
show-overflow-tooltip>
|
|
</el-table-column>
|
|
|
|
<el-table-column
|
|
prop="projectNo"
|
|
label="项目编号"
|
|
width="100"
|
|
align="center"
|
|
header-align="center"
|
|
show-overflow-tooltip>
|
|
</el-table-column>
|
|
|
|
<el-table-column
|
|
prop="productType"
|
|
label="产品型号"
|
|
min-width="220"
|
|
align="center"
|
|
header-align="center"
|
|
show-overflow-tooltip>
|
|
</el-table-column>
|
|
|
|
<el-table-column
|
|
prop="expectedFinishDate"
|
|
label="期望完成日期"
|
|
width="120"
|
|
align="center"
|
|
header-align="center">
|
|
</el-table-column>
|
|
|
|
<el-table-column
|
|
prop="actualFinishDate"
|
|
label="最终完成日期"
|
|
width="120"
|
|
align="center"
|
|
header-align="center">
|
|
</el-table-column>
|
|
<el-table-column
|
|
prop="finalQuantity"
|
|
label="入库数量"
|
|
width="80"
|
|
align="center"
|
|
header-align="center">
|
|
</el-table-column>
|
|
<el-table-column
|
|
prop="creatorName"
|
|
label="创建人"
|
|
width="80"
|
|
align="center"
|
|
header-align="center">
|
|
</el-table-column>
|
|
|
|
<el-table-column
|
|
prop="createTime"
|
|
label="创建时间"
|
|
min-width="100"
|
|
align="center" show-overflow-tooltip
|
|
header-align="center">
|
|
</el-table-column>
|
|
</el-table>
|
|
|
|
<!-- 分页组件 -->
|
|
<el-pagination
|
|
@size-change="sizeChangeHandle"
|
|
@current-change="currentChangeHandle"
|
|
:current-page="pageIndex"
|
|
:page-sizes="[20, 50, 100]"
|
|
:page-size="pageSize"
|
|
:total="totalPage"
|
|
layout="total, sizes, prev, pager, next, jumper"
|
|
style="margin-top: 10px; text-align: right;">
|
|
</el-pagination>
|
|
|
|
<!-- 下方Tab区域 -->
|
|
<el-tabs class="customer-tab"
|
|
v-model="activeName"
|
|
type="border-card"
|
|
style="margin-top: 10px; min-height: 280px;"
|
|
@tab-click="handleTabClick">
|
|
|
|
<!-- Tab 1: 项目详情 -->
|
|
<!-- <el-tab-pane :label="getProjectDetailLabel()" name="projectDetail">
|
|
<exp-project-detail
|
|
v-if="currentRow.applyNo"
|
|
ref="projectDetail"
|
|
:apply-no="currentRow.applyNo"
|
|
:status="currentRow.status"
|
|
:height="detailHeight"
|
|
@refresh="handleDetailRefresh">
|
|
</exp-project-detail>
|
|
<div v-else class="empty-tip">
|
|
请在上方表格中选择一条申请单记录
|
|
</div>
|
|
</el-tab-pane>-->
|
|
<el-tab-pane label="附件上传" name="attachment">
|
|
<erf-attachment-manager
|
|
v-if="currentRow.applyNo"
|
|
ref="attachmentManager"
|
|
:apply-no="currentRow.applyNo"
|
|
:disabled="false"
|
|
:height="detailHeight">
|
|
</erf-attachment-manager>
|
|
<div v-else class="empty-tip">
|
|
请在上方表格中选择一条申请单记录
|
|
</div>
|
|
</el-tab-pane>
|
|
<!-- Tab 2: 三方确认 -->
|
|
<el-tab-pane label="三方确认" v-if="currentRow.experimentType==='High Risk'" name="triConfirm">
|
|
<exp-tri-confirm
|
|
v-if="currentRow.applyNo&¤tRow.experimentType==='High Risk'"
|
|
ref="triConfirm"
|
|
:apply-no="currentRow.applyNo"
|
|
:experiment-type="currentRow.experimentType"
|
|
:height="detailHeight">
|
|
</exp-tri-confirm>
|
|
<div v-else class="empty-tip">
|
|
请在上方表格中选择一条申请单记录
|
|
</div>
|
|
</el-tab-pane>
|
|
|
|
<!-- Tab 3: 附件上传 -->
|
|
|
|
|
|
<!-- Tab 4: 审批状态和日志 -->
|
|
<el-tab-pane label="审批状态和日志" name="approvalStatus">
|
|
<div v-if="currentRow.applyNo" :style="{height: detailHeight + 'px', overflowY: 'auto', padding: '0px 10px'}">
|
|
|
|
<!-- 两栏布局:审批流程 | 审批日志 -->
|
|
<div class="two-column-layout">
|
|
|
|
<!-- 左栏:审批流程 -->
|
|
<div class="stages-column">
|
|
<div class="column-header">
|
|
<i class="el-icon-s-order"></i>
|
|
<span>审批流程</span>
|
|
<span class="progress-badge">{{ flowStatus.progressPercent || 0 }}%</span>
|
|
</div>
|
|
<div class="stages-list">
|
|
<div
|
|
v-for="(stage, index) in flowStatus.stages"
|
|
:key="index"
|
|
class="stage-item"
|
|
:class="'stage-' + stage.status">
|
|
<div class="stage-icon">
|
|
<i :class="getStageIcon(stage.status)"></i>
|
|
</div>
|
|
<div class="stage-content">
|
|
<div class="stage-name">{{ stage.nodeName }}</div>
|
|
<div class="stage-meta">
|
|
<el-tag :type="getStageTagType(stage.status)" size="mini" effect="plain">
|
|
{{ getStageStatusText(stage.status) }}
|
|
</el-tag>
|
|
<span v-if="stage.completeTime" class="stage-time">{{ stage.completeTime }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 右栏:审批日志(表格) -->
|
|
<div class="logs-column">
|
|
<div class="column-header">
|
|
<i class="el-icon-tickets"></i>
|
|
<span>审批日志</span>
|
|
<span class="logs-count">{{ flowStatus.approvalLogs ? flowStatus.approvalLogs.length : 0 }}条</span>
|
|
</div>
|
|
<div class="logs-table-wrapper">
|
|
<el-table
|
|
:data="flowStatus.approvalLogs"
|
|
size="small"
|
|
class="approval-logs-table"
|
|
style="width: 100%"
|
|
height="34vh">
|
|
|
|
<el-table-column prop="logTime" label="时间" width="150" align="center">
|
|
<template slot-scope="scope">
|
|
<span style="font-size: 12px">{{ formatDateTime(scope.row.logTime) }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
|
|
<el-table-column prop="action" label="操作" width="90" align="center">
|
|
<template slot-scope="scope">
|
|
<el-tag :type="getActionTagType(scope.row.action)" size="mini">
|
|
{{ scope.row.action }}
|
|
</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
|
|
<el-table-column prop="nodeCode" label="节点" width="150" align="center">
|
|
<template slot-scope="scope">
|
|
<span style="font-size: 12px">{{ scope.row.nodeCode }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
|
|
<el-table-column prop="operatorName" label="操作人" width="100" align="center">
|
|
<template slot-scope="scope">
|
|
<span style="font-size: 12px">{{ scope.row.operatorName }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
|
|
<el-table-column prop="comment" label="备注" min-width="180" show-overflow-tooltip>
|
|
<template slot-scope="scope">
|
|
<span style="font-size: 12px; color: #606266">{{ scope.row.comment || '-' }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
<div v-else class="empty-tip">
|
|
<i class="el-icon-document" style="font-size: 40px; color: #C0C4CC; margin-bottom: 10px"></i>
|
|
<p style="font-size: 13px">请选择申请单查看审批状态</p>
|
|
</div>
|
|
</el-tab-pane>
|
|
</el-tabs>
|
|
|
|
<!-- 新增/编辑弹窗 -->
|
|
<el-dialog
|
|
:title="dialogTitle"
|
|
:visible.sync="dialogVisible"
|
|
width="950px"
|
|
:close-on-click-modal="false"
|
|
v-drag>
|
|
|
|
<exp-apply-form
|
|
v-if="dialogVisible"
|
|
ref="applyForm"
|
|
:apply-data="currentApply"
|
|
:readonly="dialogReadonly">
|
|
</exp-apply-form>
|
|
|
|
<el-footer style="height: 40px; margin-top: 40px; text-align: center">
|
|
<el-button type="primary" @click="saveApply" v-if="!dialogReadonly" :loading="saveLoading">
|
|
{{ saveLoading ? '保存中...' : '保存' }}
|
|
</el-button>
|
|
<el-button type="primary" @click="dialogVisible = false">关闭</el-button>
|
|
</el-footer>
|
|
</el-dialog>
|
|
|
|
<!-- 样品确认弹窗 -->
|
|
<el-dialog
|
|
title="样品确认"
|
|
:visible.sync="sampleConfirmVisible"
|
|
width="320px"
|
|
:close-on-click-modal="false">
|
|
<div style="margin-top: 1px;margin-left: 10px; color: #909399; font-size: 12px">
|
|
不输入或输入0表示样品报废,大于0表示正常入库
|
|
</div>
|
|
<el-form :model="sampleConfirmData" label-width="100px" size="small">
|
|
<el-form-item label="申请单号">
|
|
<el-tag type="primary">{{ sampleConfirmData.applyNo }}</el-tag>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="样品数量" required>
|
|
<el-input
|
|
v-model="sampleConfirmData.sampleQuantity"
|
|
:min="0"
|
|
:precision="0"
|
|
placeholder="请输入样品数量"
|
|
style="width: 80%">
|
|
</el-input>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="完成日期" required>
|
|
<el-date-picker
|
|
v-model="sampleConfirmData.finalFinishDate"
|
|
type="date"
|
|
format="yyyy-MM-dd"
|
|
value-format="yyyy-MM-dd"
|
|
placeholder="请选择最终完成日期"
|
|
style="width: 80%">
|
|
</el-date-picker>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="样品状态">
|
|
<el-tag :type="getSampleStatusTagType()">
|
|
{{ getSampleStatusText() }}
|
|
</el-tag>
|
|
</el-form-item>
|
|
</el-form>
|
|
|
|
<div slot="footer" class="dialog-footer">
|
|
<el-button type="primary" @click="confirmSampleSubmit" :loading="sampleConfirmLoading">
|
|
{{ sampleConfirmLoading ? '确认中...' : '确认' }}
|
|
</el-button>
|
|
<el-button @click="sampleConfirmVisible = false">关闭</el-button>
|
|
</div>
|
|
</el-dialog>
|
|
|
|
<!-- 下达确认弹窗 - 选择审批人 -->
|
|
<el-dialog
|
|
title="确认审批人信息"
|
|
:visible.sync="submitDialogVisible"
|
|
width="500px"
|
|
:close-on-click-modal="false">
|
|
|
|
<el-form :model="submitData" label-width="80px" size="small">
|
|
<!-- 技术经理 -->
|
|
<el-form-item label="技术经理">
|
|
<el-tag type="success" size="medium">
|
|
{{ submitData.techManagerName }}
|
|
</el-tag>
|
|
<span style="margin-left: 10px; color: #909399; font-size: 12px">
|
|
(根据发起人角色自动分配)
|
|
</span>
|
|
</el-form-item>
|
|
|
|
<!-- 生产经理 -->
|
|
<el-form-item label="生产经理" required>
|
|
<el-select class="manager-select"
|
|
v-model="submitData.prodManagerIds"
|
|
multiple
|
|
placeholder="请选择生产经理"
|
|
style="width: 100%">
|
|
<el-option
|
|
v-for="manager in prodManagerList"
|
|
:key="manager.userId"
|
|
:label="manager.userDisplay || manager.username"
|
|
:value="manager.userId">
|
|
</el-option>
|
|
</el-select>
|
|
<div style="margin-top: 1px; color: #909399; font-size: 12px">
|
|
可多选,所有选中的生产经理都必须审批通过后才会流转到计划员排产
|
|
</div>
|
|
</el-form-item>
|
|
|
|
<!-- 质量经理 -->
|
|
<el-form-item label="质量经理" required>
|
|
<el-select class="manager-select"
|
|
v-model="submitData.qualityManagerIds"
|
|
multiple
|
|
placeholder="请选择质量经理"
|
|
style="width: 100%">
|
|
<el-option
|
|
v-for="manager in qualityManagerList"
|
|
:key="manager.userId"
|
|
:label="manager.userDisplay || manager.username"
|
|
:value="manager.userId">
|
|
</el-option>
|
|
</el-select>
|
|
<div style="margin-top: 1px; color: #909399; font-size: 12px">
|
|
可多选,所有选中的质量经理都必须审批通过后才会流转到计划员排产
|
|
</div>
|
|
</el-form-item>
|
|
</el-form>
|
|
|
|
<div slot="footer" class="dialog-footer">
|
|
<el-button @click="submitDialogVisible = false">取消</el-button>
|
|
<el-button type="primary" @click="confirmSubmit" :loading="submitLoading">
|
|
{{ submitLoading ? '下达中...' : '确认下达' }}
|
|
</el-button>
|
|
</div>
|
|
</el-dialog>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { searchExpApplyList, submitExpApply, deleteExpApply, withdrawExpApply, getSubmitApprovers, getFlowStatus, getTriConfirmList, confirmSample } from '@/api/erf/erf'
|
|
import { getBuList } from '@/api/factory/site'
|
|
import ExpApplyForm from './components/expApplyForm.vue'
|
|
import ExpProjectDetail from './components/expProjectDetail.vue'
|
|
import ExpTriConfirm from './components/expTriConfirm.vue'
|
|
import ErfAttachmentManager from './components/erfAttachmentManager.vue'
|
|
|
|
export default {
|
|
name: 'ExpApplyList',
|
|
|
|
components: {
|
|
ExpApplyForm,
|
|
ExpProjectDetail,
|
|
ExpTriConfirm,
|
|
ErfAttachmentManager
|
|
},
|
|
|
|
data() {
|
|
return {
|
|
buList: [],
|
|
// 查询条件
|
|
queryHeaderData: {
|
|
applyNo: '',
|
|
buNo: '',
|
|
experimentType: '',
|
|
status: '',
|
|
createStartDate: '',
|
|
createEndDate: '',
|
|
page: 1,
|
|
limit: 20
|
|
},
|
|
|
|
// 数据列表
|
|
dataList: [],
|
|
|
|
// 分页参数
|
|
pageIndex: 1,
|
|
pageSize: 20,
|
|
totalPage: 0,
|
|
dataListLoading: false,
|
|
|
|
// 弹窗相关
|
|
dialogVisible: false,
|
|
dialogTitle: '新增申请单',
|
|
dialogReadonly: false,
|
|
currentApply: {},
|
|
saveLoading: false,
|
|
|
|
// 当前选中行
|
|
currentRow: {},
|
|
|
|
// Tab页签
|
|
activeName: 'attachment',
|
|
|
|
// 表格高度
|
|
tableHeight: (window.innerHeight - 260)/2,
|
|
detailHeight: '35vh',
|
|
|
|
// 下达确认弹窗
|
|
submitDialogVisible: false,
|
|
submitLoading: false,
|
|
submitData: {
|
|
applyNo: '',
|
|
buNo: '',
|
|
techManagerId: null,
|
|
techManagerName: '',
|
|
prodManagerIds: [],
|
|
qualityManagerIds: []
|
|
},
|
|
prodManagerList: [], // 生产经理候选列表
|
|
qualityManagerList: [], // 质量经理候选列表
|
|
|
|
// 流程状态数据
|
|
flowStatus: {
|
|
applyNo: '',
|
|
currentStatus: '',
|
|
currentStep: '',
|
|
progressPercent: 0,
|
|
stages: [],
|
|
approvalLogs: []
|
|
},
|
|
|
|
// 样品确认弹窗
|
|
sampleConfirmVisible: false,
|
|
sampleConfirmLoading: false,
|
|
sampleConfirmData: {
|
|
applyNo: '',
|
|
sampleQuantity: null,
|
|
finalFinishDate: ''
|
|
}
|
|
}
|
|
},
|
|
|
|
activated() {
|
|
this.loadBuList()
|
|
this.getDataList()
|
|
},
|
|
|
|
methods: {
|
|
/**
|
|
* 加载事业部列表
|
|
*/
|
|
loadBuList() {
|
|
const tempData = { site: this.$store.state.user.site }
|
|
getBuList(tempData).then(({data}) => {
|
|
if (data.code === 0) {
|
|
this.buList = data.row1
|
|
}
|
|
})
|
|
},
|
|
|
|
/**
|
|
* 获取申请单列表
|
|
*/
|
|
getDataList(flag) {
|
|
if (flag === 'Y') {
|
|
this.pageIndex = 1
|
|
}
|
|
|
|
this.queryHeaderData.page = this.pageIndex
|
|
this.queryHeaderData.limit = this.pageSize
|
|
|
|
this.dataListLoading = true
|
|
|
|
searchExpApplyList(this.queryHeaderData).then(({data}) => {
|
|
this.dataListLoading = false
|
|
if (data && data.code === 0) {
|
|
this.dataList = data.page.list || []
|
|
this.totalPage = data.page.totalCount || 0
|
|
|
|
// 如果有数据,处理行选中
|
|
if (this.dataList.length > 0) {
|
|
// 尝试找到之前选中的行
|
|
if (this.currentRow.applyNo) {
|
|
const selectedRow = this.dataList.find(item => item.applyNo === this.currentRow.applyNo)
|
|
if (selectedRow) {
|
|
// 如果找到之前选中的行,重新高亮
|
|
this.$nextTick(() => {
|
|
this.handleRowClick(selectedRow)
|
|
})
|
|
} else {
|
|
// 如果没找到,选中第一行
|
|
this.handleRowClick(this.dataList[0])
|
|
}
|
|
} else {
|
|
// 如果之前没有选中任何行,默认选中第一行
|
|
this.handleRowClick(this.dataList[0])
|
|
}
|
|
} else {
|
|
// 没有数据,清空当前行
|
|
this.currentRow = {}
|
|
}
|
|
} else {
|
|
this.dataList = []
|
|
this.totalPage = 0
|
|
this.currentRow = {}
|
|
this.$message.error(data.msg || '查询失败')
|
|
}
|
|
}).catch(error => {
|
|
this.dataListLoading = false
|
|
this.$message.error('查询异常')
|
|
})
|
|
},
|
|
|
|
/**
|
|
* 重置查询条件
|
|
*/
|
|
resetQuery() {
|
|
this.queryHeaderData = {
|
|
applyNo: '',
|
|
buNo: '',
|
|
experimentType: '',
|
|
status: '',
|
|
createStartDate: '',
|
|
createEndDate: '',
|
|
page: 1,
|
|
limit: 20
|
|
}
|
|
this.getDataList('Y')
|
|
},
|
|
|
|
/**
|
|
* 打开新增对话框
|
|
*/
|
|
openCreateDialog() {
|
|
this.dialogTitle = '新增申请单'
|
|
this.dialogReadonly = false
|
|
this.currentApply = {}
|
|
this.dialogVisible = true
|
|
},
|
|
|
|
/**
|
|
* 查看详情
|
|
*/
|
|
viewDetail(row) {
|
|
this.dialogTitle = '查看申请单'
|
|
this.dialogReadonly = true
|
|
this.currentApply = { ...row }
|
|
this.dialogVisible = true
|
|
},
|
|
|
|
/**
|
|
* 编辑申请单
|
|
*/
|
|
editApply(row) {
|
|
this.dialogTitle = '修改申请单'
|
|
this.dialogReadonly = false
|
|
this.currentApply = { ...row }
|
|
this.dialogVisible = true
|
|
},
|
|
|
|
/**
|
|
* 保存申请单
|
|
*/
|
|
saveApply() {
|
|
const formData = this.$refs.applyForm.getFormData()
|
|
if (!formData) {
|
|
return
|
|
}
|
|
|
|
this.saveLoading = true
|
|
this.$refs.applyForm.save().then(() => {
|
|
this.saveLoading = false
|
|
this.$message.success('保存成功')
|
|
this.dialogVisible = false
|
|
this.getDataList()
|
|
}).catch(error => {
|
|
this.saveLoading = false
|
|
})
|
|
},
|
|
|
|
/**
|
|
* 下达申请单 - 打开审批人确认弹窗
|
|
*/
|
|
submitApply(row) {
|
|
// ✅ 如果是High Risk,先验证工序
|
|
if (row.experimentType === 'High Risk') {
|
|
console.log('🔍 检测到High Risk申请单,开始验证工序...')
|
|
|
|
// 通过API查询工序列表进行验证(不依赖子组件是否已加载)
|
|
this.validateHighRiskProcessByApi(row.applyNo).then(isValid => {
|
|
if (!isValid) {
|
|
console.log('❌ High Risk验证失败,终止下达')
|
|
this.$alert('High Risk申请单必须至少有一条完整的工序(包含车间、质量、技术三个负责人)才能下达', '操作提示', {
|
|
confirmButtonText: '确定',
|
|
type: 'warning'
|
|
})
|
|
return
|
|
}
|
|
|
|
console.log('✅ High Risk验证通过,继续下达流程')
|
|
// 验证通过后继续下达流程
|
|
this.proceedSubmit(row)
|
|
}).catch(error => {
|
|
console.error('❌ 验证工序异常:', error)
|
|
this.$message.error('验证工序失败,请重试')
|
|
})
|
|
} else {
|
|
// 非High Risk直接下达
|
|
console.log('📝 Low Risk申请单,直接下达')
|
|
this.proceedSubmit(row)
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 通过API验证High Risk工序
|
|
*
|
|
* @param {String} applyNo 申请单号
|
|
* @return {Promise<Boolean>} 验证结果
|
|
*/
|
|
validateHighRiskProcessByApi(applyNo) {
|
|
return new Promise((resolve, reject) => {
|
|
// 调用API查询工序列表
|
|
getTriConfirmList({ applyNo: applyNo }).then(({data}) => {
|
|
if (data && data.code === 0) {
|
|
const processList = data.list || []
|
|
console.log('📊 查询到工序数量:', processList.length)
|
|
|
|
// 检查是否至少有一条完整的工序
|
|
const completeProcesses = processList.filter(process => {
|
|
const isComplete = process.prodApproverName &&
|
|
process.qaApproverName &&
|
|
process.techApproverName
|
|
|
|
if (isComplete) {
|
|
console.log('✅ 完整工序:', process.processStep, {
|
|
车间: process.prodApproverName,
|
|
质量: process.qaApproverName,
|
|
技术: process.techApproverName
|
|
})
|
|
}
|
|
|
|
return isComplete
|
|
})
|
|
|
|
console.log(`📈 完整工序数量: ${completeProcesses.length}/${processList.length}`)
|
|
|
|
// 至少需要一条完整的工序
|
|
resolve(completeProcesses.length > 0)
|
|
} else {
|
|
reject(new Error(data.msg || '查询工序列表失败'))
|
|
}
|
|
}).catch(error => {
|
|
reject(error)
|
|
})
|
|
})
|
|
},
|
|
|
|
/**
|
|
* 执行下达流程
|
|
*/
|
|
proceedSubmit(row) {
|
|
// 一次性获取所有审批人信息
|
|
getSubmitApprovers({
|
|
userId: this.$store.state.user.id,
|
|
buNo: row.buNo
|
|
}).then(({data}) => {
|
|
if (data && data.code === 0) {
|
|
// 设置生产经理和质量经理列表
|
|
this.prodManagerList = data.prodManagers || []
|
|
this.qualityManagerList = data.qualityManagers || []
|
|
// 根据事业部设置默认生产经理(使用user_display模糊匹配)
|
|
const defaultProdManagerIds = []
|
|
if (row.buDesc === 'RFID') {
|
|
// RFID默认Tony
|
|
const tony = this.prodManagerList.find(m =>
|
|
m.userDisplay && m.userDisplay.toLowerCase().includes('tony')
|
|
)
|
|
if (tony) defaultProdManagerIds.push(tony.userId)
|
|
} else if (row.buDesc === 'RF') {
|
|
// RF默认Charles
|
|
const charles = this.prodManagerList.find(m =>
|
|
m.userDisplay && m.userDisplay.toLowerCase().includes('charles')
|
|
)
|
|
if (charles) defaultProdManagerIds.push(charles.userId)
|
|
}
|
|
|
|
// 根据事业部设置默认质量经理(使用user_display模糊匹配)
|
|
const defaultQualityManagerIds = []
|
|
if (row.buDesc === 'RFID') {
|
|
// RFID默认Victor
|
|
const victor = this.qualityManagerList.find(m =>
|
|
m.userDisplay && m.userDisplay.toLowerCase().includes('victor')
|
|
)
|
|
if (victor) defaultQualityManagerIds.push(victor.userId)
|
|
} else if (row.buDesc === 'RF') {
|
|
// RF默认尹君
|
|
const yin = this.qualityManagerList.find(m =>
|
|
m.userDisplay && (m.userDisplay.includes('尹君') || m.userDisplay.toLowerCase().includes('yin'))
|
|
)
|
|
if (yin) defaultQualityManagerIds.push(yin.userId)
|
|
}
|
|
|
|
// 设置表单数据
|
|
this.submitData = {
|
|
applyNo: row.applyNo,
|
|
buNo: row.buNo,
|
|
techManagerId: data.techManager.managerId,
|
|
techManagerName: data.techManager.managerName,
|
|
prodManagerIds: defaultProdManagerIds,
|
|
qualityManagerIds: defaultQualityManagerIds
|
|
}
|
|
|
|
// 显示弹窗
|
|
this.submitDialogVisible = true
|
|
} else {
|
|
this.$message.error(data.msg || '获取审批人信息失败')
|
|
}
|
|
}).catch(() => {
|
|
this.$message.error('获取审批人信息异常')
|
|
})
|
|
},
|
|
|
|
/**
|
|
* 确认下达
|
|
*/
|
|
confirmSubmit() {
|
|
// 验证必填项
|
|
if (!this.submitData.techManagerId) {
|
|
this.$message.warning('技术经理未分配')
|
|
return
|
|
}
|
|
if (!this.submitData.prodManagerIds || this.submitData.prodManagerIds.length === 0) {
|
|
this.$message.warning('请至少选择一位生产经理')
|
|
return
|
|
}
|
|
if (!this.submitData.qualityManagerIds || this.submitData.qualityManagerIds.length === 0) {
|
|
this.$message.warning('请至少选择一位质量经理')
|
|
return
|
|
}
|
|
|
|
this.submitLoading = true
|
|
|
|
// 调用下达API
|
|
submitExpApply({
|
|
applyNo: this.submitData.applyNo,
|
|
techManagerId: this.submitData.techManagerId,
|
|
prodManagerIds: this.submitData.prodManagerIds,
|
|
qualityManagerIds: this.submitData.qualityManagerIds
|
|
}).then(({data}) => {
|
|
this.submitLoading = false
|
|
if (data && data.code === 0) {
|
|
this.$message.success('下达成功,已通知相关审批人')
|
|
this.submitDialogVisible = false
|
|
this.getDataList()
|
|
|
|
// 触发全局审批通知检查(通知审批人)
|
|
this.triggerApprovalNotification()
|
|
} else {
|
|
this.$message.error(data.msg || '下达失败')
|
|
}
|
|
}).catch(() => {
|
|
this.submitLoading = false
|
|
})
|
|
},
|
|
|
|
/**
|
|
* 触发全局审批通知检查
|
|
* 在申请单下达成功后调用,立即通知审批人
|
|
*/
|
|
triggerApprovalNotification() {
|
|
try {
|
|
// 通过 $root 访问 App.vue 的方法
|
|
if (this.$root && this.$root.$children && this.$root.$children[0]) {
|
|
const app = this.$root.$children[0]
|
|
if (app.checkApprovalNotifications) {
|
|
// 延迟1秒后检查,确保后端数据已更新
|
|
setTimeout(() => {
|
|
//app.checkApprovalNotifications()
|
|
console.log('[审批通知] 已触发手动检查')
|
|
}, 1000)
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.log('[审批通知] 触发通知检查失败:', error.message)
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 删除申请单
|
|
*/
|
|
deleteApply(row) {
|
|
this.$confirm('确定删除该申请单?', '操作提示', {
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning'
|
|
}).then(() => {
|
|
deleteExpApply({ applyNo: row.applyNo }).then(({data}) => {
|
|
if (data && data.code === 0) {
|
|
this.$message.success('删除成功')
|
|
this.getDataList()
|
|
} else {
|
|
this.$message.error(data.msg || '删除失败')
|
|
}
|
|
})
|
|
})
|
|
},
|
|
|
|
/**
|
|
* 撤回申请单
|
|
*/
|
|
withdrawApply(row) {
|
|
this.$confirm('确定撤回该申请单?撤回后将变为草稿状态', '操作提示', {
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning'
|
|
}).then(() => {
|
|
withdrawExpApply({
|
|
applyNo: row.applyNo,
|
|
currentUserId: this.$store.state.user.id
|
|
}).then(({data}) => {
|
|
if (data && data.code === 0) {
|
|
this.$message.success('撤回成功')
|
|
this.getDataList()
|
|
} else {
|
|
this.$message.error(data.msg || '撤回失败')
|
|
}
|
|
})
|
|
})
|
|
},
|
|
|
|
/**
|
|
* 获取状态类型
|
|
*/
|
|
getStatusType(status) {
|
|
const types = {
|
|
'草稿': 'info',
|
|
'已下达': 'warning',
|
|
'已批准': 'success',
|
|
'生产中': '',
|
|
'已完成': 'success',
|
|
'已取消': 'danger',
|
|
'已驳回': 'danger'
|
|
}
|
|
return types[status] || 'info'
|
|
},
|
|
|
|
/**
|
|
* 获取状态文本(直接返回中文状态)
|
|
*/
|
|
getStatusText(status) {
|
|
return status || ''
|
|
},
|
|
|
|
/**
|
|
* 分页大小改变
|
|
*/
|
|
sizeChangeHandle(val) {
|
|
this.pageSize = val
|
|
this.pageIndex = 1
|
|
this.getDataList()
|
|
},
|
|
|
|
/**
|
|
* 当前页改变
|
|
*/
|
|
currentChangeHandle(val) {
|
|
this.pageIndex = val
|
|
this.getDataList()
|
|
},
|
|
|
|
/**
|
|
* 行点击事件
|
|
*/
|
|
handleRowClick(row) {
|
|
this.currentRow = JSON.parse(JSON.stringify(row))
|
|
// 设置表格当前行高亮
|
|
this.$nextTick(() => {
|
|
this.$refs.dataTable.setCurrentRow(row)
|
|
})
|
|
|
|
// 根据当前tab刷新对应的数据
|
|
if (this.activeName === 'approvalStatus') {
|
|
// 刷新审批状态和日志
|
|
this.loadFlowStatus()
|
|
} else if (this.activeName === 'triConfirm') {
|
|
// 刷新三方确认数据
|
|
this.$nextTick(() => {
|
|
if (this.$refs.triConfirm && this.$refs.triConfirm.loadProcessList) {
|
|
console.log('🔄 行切换,刷新三方确认数据')
|
|
this.$refs.triConfirm.loadProcessList()
|
|
}
|
|
})
|
|
} else {
|
|
// 否则自动切换到项目详情tab
|
|
this.activeName = 'attachment'
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Tab切换事件
|
|
*/
|
|
handleTabClick(tab) {
|
|
// Tab切换时可以做一些特殊处理
|
|
console.log('当前Tab:', tab.name)
|
|
|
|
// 切换到审批状态tab时加载流程状态
|
|
if (tab.name === 'approvalStatus' && this.currentRow.applyNo) {
|
|
this.loadFlowStatus()
|
|
}
|
|
|
|
// 切换到三方确认tab时刷新数据
|
|
if (tab.name === 'triConfirm' && this.currentRow.applyNo) {
|
|
this.$nextTick(() => {
|
|
if (this.$refs.triConfirm && this.$refs.triConfirm.loadProcessList) {
|
|
console.log('🔄 Tab切换,刷新三方确认数据')
|
|
this.$refs.triConfirm.loadProcessList()
|
|
}
|
|
})
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 项目详情刷新事件
|
|
*/
|
|
handleDetailRefresh() {
|
|
// 刷新当前行数据
|
|
this.getDataList()
|
|
},
|
|
|
|
/**
|
|
* 获取项目详情Tab标签
|
|
*/
|
|
getProjectDetailLabel() {
|
|
if (this.currentRow.applyNo) {
|
|
return `项目详情 [${this.currentRow.applyNo}]`
|
|
}
|
|
return '项目详情'
|
|
},
|
|
|
|
/**
|
|
* 加载流程状态
|
|
*/
|
|
loadFlowStatus() {
|
|
if (!this.currentRow.applyNo) {
|
|
return
|
|
}
|
|
|
|
getFlowStatus({ applyNo: this.currentRow.applyNo }).then(({data}) => {
|
|
if (data && data.code === 0) {
|
|
this.flowStatus = data.data || {
|
|
stages: [],
|
|
approvalLogs: []
|
|
}
|
|
}
|
|
})
|
|
},
|
|
|
|
/**
|
|
* 获取阶段颜色
|
|
*/
|
|
getStageColor(status) {
|
|
const colors = {
|
|
'pending': '#C0C4CC',
|
|
'current': '#409EFF',
|
|
'completed': '#67C23A',
|
|
'rejected': '#F56C6C'
|
|
}
|
|
return colors[status] || '#C0C4CC'
|
|
},
|
|
|
|
/**
|
|
* 获取阶段图标
|
|
*/
|
|
getStageIcon(status) {
|
|
const icons = {
|
|
'pending': 'el-icon-time',
|
|
'current': 'el-icon-loading',
|
|
'completed': 'el-icon-success',
|
|
'rejected': 'el-icon-error'
|
|
}
|
|
return icons[status] || 'el-icon-time'
|
|
},
|
|
|
|
/**
|
|
* 获取阶段标签类型
|
|
*/
|
|
getStageTagType(status) {
|
|
const types = {
|
|
'pending': 'info',
|
|
'current': '',
|
|
'completed': 'success',
|
|
'rejected': 'danger'
|
|
}
|
|
return types[status] || 'info'
|
|
},
|
|
|
|
/**
|
|
* 获取阶段状态文本
|
|
*/
|
|
getStageStatusText(status) {
|
|
const texts = {
|
|
'pending': '未开始',
|
|
'current': '进行中',
|
|
'completed': '已完成',
|
|
'rejected': '已驳回'
|
|
}
|
|
return texts[status] || '未知'
|
|
},
|
|
|
|
/**
|
|
* 获取操作类型标签
|
|
*/
|
|
getActionTagType(action) {
|
|
const types = {
|
|
'下达': 'primary',
|
|
'批准': 'success',
|
|
'确认': 'success',
|
|
'驳回': 'danger',
|
|
'撤回': 'warning',
|
|
'提醒': 'info',
|
|
'已排产': 'success',
|
|
'录入最终结果': 'success'
|
|
}
|
|
return types[action] || 'info'
|
|
},
|
|
|
|
|
|
/**
|
|
* 格式化日期时间
|
|
*/
|
|
formatDateTime(dateTime) {
|
|
if (!dateTime) {
|
|
return ''
|
|
}
|
|
|
|
if (typeof dateTime === 'string') {
|
|
return dateTime
|
|
}
|
|
|
|
const date = new Date(dateTime)
|
|
const year = date.getFullYear()
|
|
const month = String(date.getMonth() + 1).padStart(2, '0')
|
|
const day = String(date.getDate()).padStart(2, '0')
|
|
const hours = String(date.getHours()).padStart(2, '0')
|
|
const minutes = String(date.getMinutes()).padStart(2, '0')
|
|
const seconds = String(date.getSeconds()).padStart(2, '0')
|
|
|
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
|
},
|
|
|
|
/**
|
|
* 判断是否显示样品确认按钮
|
|
* Low Risk: 计划员排产完成后(currentStep="已完成"且status="生产中")显示
|
|
* High Risk: 三方确认阶段(currentStep="三方确认"且status="生产中")显示
|
|
*/
|
|
showSampleConfirmBtn(row) {
|
|
if (row.experimentType === 'Low Risk') {
|
|
return row.currentStep === '样品确认'
|
|
} else if (row.experimentType === 'High Risk') {
|
|
return row.currentStep === '样品确认'
|
|
}
|
|
return false
|
|
},
|
|
|
|
/**
|
|
* 打开样品确认对话框
|
|
*/
|
|
openSampleConfirm(row) {
|
|
this.sampleConfirmData = {
|
|
applyNo: row.applyNo,
|
|
sampleQuantity: null,
|
|
finalFinishDate: ''
|
|
}
|
|
this.sampleConfirmVisible = true
|
|
},
|
|
|
|
/**
|
|
* 获取样品状态标签类型
|
|
*/
|
|
getSampleStatusTagType() {
|
|
if (!this.sampleConfirmData.sampleQuantity || this.sampleConfirmData.sampleQuantity === 0) {
|
|
return 'danger'
|
|
}
|
|
return 'success'
|
|
},
|
|
|
|
/**
|
|
* 获取样品状态文本
|
|
*/
|
|
getSampleStatusText() {
|
|
if (!this.sampleConfirmData.sampleQuantity || this.sampleConfirmData.sampleQuantity === 0) {
|
|
return '报废'
|
|
}
|
|
return '正常入库'
|
|
},
|
|
|
|
/**
|
|
* 提交样品确认
|
|
*/
|
|
confirmSampleSubmit() {
|
|
// 验证最终完成日期必填
|
|
if (!this.sampleConfirmData.finalFinishDate) {
|
|
this.$message.warning('请选择最终完成日期')
|
|
return
|
|
}
|
|
// 确定样品状态
|
|
const finalStatus = (!this.sampleConfirmData.sampleQuantity || this.sampleConfirmData.sampleQuantity === 0)
|
|
? '报废'
|
|
: '正常入库'
|
|
|
|
const finalQuantity = this.sampleConfirmData.sampleQuantity || 0
|
|
this.sampleConfirmLoading = true
|
|
confirmSample({
|
|
applyNo: this.sampleConfirmData.applyNo,
|
|
finalQuantity: finalQuantity,
|
|
finalStatus: finalStatus,
|
|
actualFinishDate: this.sampleConfirmData.finalFinishDate
|
|
}).then(({data}) => {
|
|
this.sampleConfirmLoading = false
|
|
if (data && data.code === 0) {
|
|
this.$message.success('样品确认成功')
|
|
this.sampleConfirmVisible = false
|
|
this.getDataList()
|
|
} else {
|
|
this.$message.error(data.msg || '样品确认失败')
|
|
}
|
|
}).catch(() => {
|
|
this.sampleConfirmLoading = false
|
|
this.$message.error('样品确认异常')
|
|
})
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.mod-config {
|
|
|
|
}
|
|
|
|
.el-form {
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.dialog-footer {
|
|
text-align: center;
|
|
}
|
|
|
|
.empty-tip {
|
|
padding: 40px;
|
|
text-align: center;
|
|
color: #999;
|
|
font-size: 14px;
|
|
}
|
|
|
|
/* ==================== 页面专属样式 - 不影响全局 ==================== */
|
|
|
|
/* 查询表单样式 */
|
|
.exp-apply-page .query-form {
|
|
background-color: #FFFFFF;
|
|
padding: 15px 15px 5px 15px;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.exp-apply-page .query-form >>> .el-form-item__label {
|
|
color: #333333;
|
|
font-size: 13px;
|
|
padding-bottom: 5px;
|
|
}
|
|
|
|
.exp-apply-page .query-form >>> .el-input__inner {
|
|
height: 32px;
|
|
line-height: 32px;
|
|
border-radius: 4px;
|
|
border: 1px solid #DCDFE6;
|
|
font-size: 13px;
|
|
}
|
|
|
|
.exp-apply-page .query-form >>> .el-input__inner::placeholder {
|
|
color: #C0C4CC;
|
|
font-size: 13px;
|
|
}
|
|
|
|
.exp-apply-page .query-form >>> .el-select .el-input__inner {
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.exp-apply-page .query-form >>> .el-date-editor .el-input__inner {
|
|
border-radius: 4px;
|
|
}
|
|
|
|
/* 按钮样式 - 扁平化风格 */
|
|
.exp-apply-page >>> .el-button {
|
|
height: 32px;
|
|
padding: 0 15px;
|
|
font-size: 13px;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
/* 查询按钮 - 蓝色扁平 */
|
|
.exp-apply-page .search-btn {
|
|
background-color: #ECF5FF;
|
|
border-color: #B3D8FF;
|
|
color: #409EFF;
|
|
}
|
|
|
|
.exp-apply-page .search-btn:hover {
|
|
background-color: #409EFF;
|
|
border-color: #409EFF;
|
|
color: #FFFFFF;
|
|
}
|
|
|
|
/* 重置按钮 - 灰色扁平 */
|
|
.exp-apply-page .reset-btn {
|
|
background-color: #F5F7FA;
|
|
border-color: #D3D4D6;
|
|
color: #606266;
|
|
}
|
|
|
|
.exp-apply-page .reset-btn:hover {
|
|
background-color: #909399;
|
|
border-color: #909399;
|
|
color: #FFFFFF;
|
|
}
|
|
|
|
/* 新增按钮 - 绿色扁平 */
|
|
.exp-apply-page .add-btn {
|
|
background-color: #F0F9FF;
|
|
border-color: #C0E6C7;
|
|
color: #67C23A;
|
|
}
|
|
|
|
.exp-apply-page .add-btn:hover {
|
|
background-color: #67C23A;
|
|
border-color: #67C23A;
|
|
color: #FFFFFF;
|
|
}
|
|
|
|
/* 数据表格样式 */
|
|
.exp-apply-page .data-table {
|
|
background-color: #FFFFFF;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.exp-apply-page .data-table >>> .el-table__header-wrapper th {
|
|
background-color: #F5F7FA !important;
|
|
color: #333333;
|
|
font-weight: 600;
|
|
font-size: 16px;
|
|
border-color: #EBEEF5;
|
|
padding: 10px 0;
|
|
height: auto;
|
|
}
|
|
|
|
/* 固定列表头也使用相同背景色 */
|
|
.exp-apply-page .data-table >>> .el-table__fixed-header-wrapper th {
|
|
background-color: #F5F7FA !important;
|
|
color: #333333;
|
|
font-weight: 600;
|
|
font-size: 16px;
|
|
border-color: #EBEEF5;
|
|
padding: 12px 0;
|
|
height: auto;
|
|
}
|
|
|
|
.exp-apply-page .data-table >>> .el-table__header-wrapper .cell {
|
|
text-align: center;
|
|
padding: 0 10px;
|
|
//line-height: 2;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
font-size: 13px !important;
|
|
}
|
|
|
|
.exp-apply-page .data-table >>> .el-table__fixed-header-wrapper .cell {
|
|
text-align: center;
|
|
padding: 0 10px;
|
|
//line-height: 2;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.exp-apply-page .data-table >>> .el-table__body-wrapper td {
|
|
border-color: #EBEEF5;
|
|
padding: 12px 0;
|
|
font-size: 16px;
|
|
color: #606266;
|
|
height: auto;
|
|
}
|
|
|
|
/* 固定列数据行也使用相同样式 */
|
|
.exp-apply-page .data-table >>> .el-table__fixed-body-wrapper td {
|
|
border-color: #EBEEF5;
|
|
padding: 12px 0;
|
|
font-size: 16px;
|
|
color: #606266;
|
|
height: auto;
|
|
}
|
|
|
|
.exp-apply-page .data-table >>> .el-table__body-wrapper .cell {
|
|
padding: 0 10px;
|
|
//line-height: 2;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
font-size: 13px !important;
|
|
}
|
|
|
|
.exp-apply-page .data-table >>> .el-table__fixed-body-wrapper .cell {
|
|
padding: 0 10px;
|
|
//line-height: 2;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* 操作列链接样式 - 统一蓝色样式 */
|
|
.exp-apply-page .data-table >>> .el-table__body-wrapper a {
|
|
text-decoration: none;
|
|
cursor: pointer;
|
|
font-size: 13px;
|
|
color: #409EFF !important;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.exp-apply-page .data-table >>> .el-table__body-wrapper a:hover {
|
|
color: #66B1FF !important;
|
|
text-decoration: underline;
|
|
}
|
|
|
|
.exp-apply-page .data-table >>> .el-table__body tr:hover > td {
|
|
background-color: #F5F7FA !important;
|
|
}
|
|
|
|
.exp-apply-page .data-table >>> .el-table__body tr.current-row > td {
|
|
background-color: #ECF5FF !important;
|
|
}
|
|
|
|
/* Tab样式优化 - 两栏布局 */
|
|
|
|
/* 两栏布局容器 */
|
|
.two-column-layout {
|
|
display: flex;
|
|
gap: 10px;
|
|
height: 100%;
|
|
}
|
|
|
|
/* 统一的列头样式 */
|
|
.column-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
color: #606266;
|
|
padding: 8px 12px;
|
|
background: #f5f7fa;
|
|
border-bottom: 2px solid #409EFF;
|
|
}
|
|
|
|
.column-header i {
|
|
color: #409EFF;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.progress-badge {
|
|
margin-left: auto;
|
|
font-size: 14px;
|
|
color: #409EFF;
|
|
font-weight: bold;
|
|
}
|
|
|
|
/* ==================== 左栏:审批流程 ==================== */
|
|
.stages-column {
|
|
flex: 0 0 380px;
|
|
background: white;
|
|
border: 1px solid #e4e7ed;
|
|
border-radius: 6px;
|
|
overflow: hidden;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.stages-list {
|
|
padding: 8px;
|
|
overflow-y: auto;
|
|
flex: 1;
|
|
}
|
|
|
|
.stage-item {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 8px;
|
|
padding: 8px;
|
|
margin-bottom: 6px;
|
|
border-radius: 6px;
|
|
background: #fafafa;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.stage-item:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.stage-item:hover {
|
|
background: #f0f2f5;
|
|
transform: translateX(2px);
|
|
}
|
|
|
|
.stage-icon {
|
|
width: 28px;
|
|
height: 28px;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 14px;
|
|
flex-shrink: 0;
|
|
margin-top: 2px;
|
|
}
|
|
|
|
.stage-pending .stage-icon {
|
|
background: #e8e8e8;
|
|
color: #909399;
|
|
}
|
|
|
|
.stage-current .stage-icon {
|
|
background: #409EFF;
|
|
color: white;
|
|
animation: pulse-stage 2s infinite;
|
|
}
|
|
|
|
@keyframes pulse-stage {
|
|
0%, 100% {
|
|
box-shadow: 0 0 0 3px rgba(64, 158, 255, 0.3);
|
|
}
|
|
50% {
|
|
box-shadow: 0 0 0 5px rgba(64, 158, 255, 0.1);
|
|
}
|
|
}
|
|
|
|
.stage-completed .stage-icon {
|
|
background: #67C23A;
|
|
color: white;
|
|
}
|
|
|
|
.stage-rejected .stage-icon {
|
|
background: #F56C6C;
|
|
color: white;
|
|
}
|
|
|
|
.stage-content {
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
|
|
.stage-name {
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
color: #303133;
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.stage-meta {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
}
|
|
|
|
.stage-time {
|
|
font-size: 11px;
|
|
color: #909399;
|
|
}
|
|
|
|
.stage-current {
|
|
background: #ecf5ff !important;
|
|
border: 1px solid #b3d8ff;
|
|
}
|
|
|
|
.stage-completed {
|
|
background: #f0f9ff !important;
|
|
}
|
|
|
|
.stage-rejected {
|
|
background: #fef0f0 !important;
|
|
border: 1px solid #fbc4c4;
|
|
}
|
|
|
|
/* ==================== 右栏:审批日志(表格) ==================== */
|
|
.logs-column {
|
|
flex: 1;
|
|
background: white;
|
|
border: 1px solid #e4e7ed;
|
|
border-radius: 6px;
|
|
overflow: hidden;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.logs-column .column-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.logs-count {
|
|
font-size: 11px;
|
|
color: #909399;
|
|
font-weight: normal;
|
|
margin-left: auto;
|
|
}
|
|
|
|
.logs-table-wrapper {
|
|
flex: 1;
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* ==================== 审批日志表格专用样式 ==================== */
|
|
|
|
/* 表头样式 - 深灰色背景,白色文字 */
|
|
.approval-logs-table >>> .el-table__header-wrapper th,
|
|
.approval-logs-table >>> .el-table__header-wrapper .el-table__cell {
|
|
background-color: #F5F7FA !important;
|
|
color: #606266 !important;
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* 数据行样式 - 更高的行高防止遮挡 */
|
|
.approval-logs-table >>> .el-table__body-wrapper .el-table__row {
|
|
height: 40px !important;
|
|
}
|
|
|
|
.approval-logs-table >>> .el-table__body-wrapper td,
|
|
.approval-logs-table >>> .el-table__body-wrapper .el-table__cell {
|
|
height: 40px !important;
|
|
padding: 0 !important;
|
|
}
|
|
|
|
/* 关键修复:cell容器要有足够的padding和overflow可见 */
|
|
.approval-logs-table >>> .el-table__body-wrapper .cell {
|
|
padding: 1px 12px !important;
|
|
line-height: 24px !important;
|
|
overflow: visible !important;
|
|
height: auto !important;
|
|
}
|
|
|
|
/* 标签样式 - 确保不被遮挡 */
|
|
.approval-logs-table >>> .el-tag {
|
|
vertical-align: middle !important;
|
|
display: inline-block !important;
|
|
margin: 2px 0 !important;
|
|
}
|
|
|
|
/* 悬停效果 */
|
|
.approval-logs-table >>> .el-table__body tr:hover > td {
|
|
background-color: #f5f7fa !important;
|
|
}
|
|
|
|
/* 空状态 */
|
|
.empty-tip {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 50px 20px;
|
|
color: #909399;
|
|
}
|
|
|
|
.empty-tip p {
|
|
margin: 0;
|
|
}
|
|
/deep/ .manager-select .el-input__inner {
|
|
height: 30px !important;
|
|
line-height: 30px !important;
|
|
}
|
|
|
|
</style>
|