From 29be8639dc16b5d82bddc6099b1fa5cdca75f77a Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期二, 20 十月 2026 16:28:22 +0800
Subject: [PATCH] feat(import): 统一导入弹框与模板,修复模板日期格式及上传报错
---
src/views/CNAS/process/ensureResults/ensureResultsValidity/index.vue | 894 +++++++++++++++++++++++++++++++++++++----------------------
1 files changed, 559 insertions(+), 335 deletions(-)
diff --git a/src/views/CNAS/process/ensureResults/ensureResultsValidity/index.vue b/src/views/CNAS/process/ensureResults/ensureResultsValidity/index.vue
index c0708a5..f6346ed 100644
--- a/src/views/CNAS/process/ensureResults/ensureResultsValidity/index.vue
+++ b/src/views/CNAS/process/ensureResults/ensureResultsValidity/index.vue
@@ -1,38 +1,82 @@
<template>
<!-- 7.7璐ㄩ噺鐩戞帶璁″垝-->
<div class="app-container">
- <div class="table-card">
- <div style="display: flex;justify-content: space-between">
- <div style="display: flex;">
- <div style="margin-bottom: 18px;margin-right: 10px;display: flex;align-items: center;line-height: 32px;">
- <span style="width: 88px;font-size: 14px;font-weight: 700;color: #606266;">璁″垝鍚嶇О</span>
- <el-input size="small" placeholder="璇疯緭鍏�" clearable v-model="yearForm.monitorName"
- @keyup.enter="getYearPlanList"></el-input>
- </div>
- <div style="line-height: 30px;">
- <el-button type="primary" size="small" @click="getYearPlanList">鏌ヨ</el-button>
- <el-button size="small" @click="clearYear">閲嶇疆</el-button>
- </div>
+ <section v-if="pageMode === 'list'" class="plan-list-card">
+ <div class="plan-list-toolbar">
+ <div class="plan-list-filters">
+ <span class="annual-plan-label">璁″垝骞村害</span>
+ <el-date-picker v-model="selectedYear" type="year" value-format="YYYY" format="YYYY骞�" :clearable="false"
+ size="small" style="width: 130px" @change="handleYearChange" />
+ <span class="filter-label">璁″垝鍚嶇О</span>
+ <el-input v-model="yearForm.monitorName" clearable placeholder="璇疯緭鍏�" size="small" style="width: 220px"
+ @keyup.enter="getYearPlanList" />
+ <el-button type="primary" size="small" @click="getYearPlanList">鏌ヨ</el-button>
+ <el-button size="small" @click="clearYear">閲嶇疆</el-button>
</div>
- <div style="line-height: 30px;">
- <el-button size="small" type="primary" @click="leadInto">瀵煎叆</el-button>
+ <div class="plan-list-actions">
+ <el-button size="small" @click="leadInto">瀵煎叆</el-button>
+ <el-button type="primary" size="small" @click="openCreatePlan">鏂板缓骞村害璁″垝</el-button>
</div>
</div>
- <lims-table :tableData="yearTableData" :column="yearColumnData" :page="yearPage" :tableLoading="yearLoading"
- :height="'calc(100vh - 34em)'" @pagination="pagination" :rowClick="rowClick" key="yearTableData"></lims-table>
+ <lims-table :tableData="yearTableData" :column="yearColumnData" :page="yearPage"
+ :tableLoading="yearLoading" :height="'calc(100vh - 11em)'" @pagination="pagination" key="yearTableData">
+ <template #planActions="{ row }">
+ <div class="detail-actions">
+ <el-button link type="primary" size="small" @click="openPlan(row)">鏌ョ湅璁″垝</el-button>
+ <el-button v-if="canReviewRow(row)" link type="primary" size="small" @click="examinePlan(row)">瀹℃牳</el-button>
+ <el-button v-if="canApproveRow(row)" link type="primary" size="small" @click="approvalPlan(row)">鎵瑰噯</el-button>
+ <el-dropdown trigger="click" @command="command => handlePlanCommand(command, row)">
+ <el-button link type="primary" size="small">鏇村鈱�</el-button>
+ <template #dropdown>
+ <el-dropdown-menu>
+ <el-dropdown-item command="export" :disabled="row.ratifyStatus !== 1">瀵煎嚭骞村害璁″垝</el-dropdown-item>
+ <el-dropdown-item command="delete" divided :disabled="!canDeleteRow(row)">鍒犻櫎</el-dropdown-item>
+ </el-dropdown-menu>
+ </template>
+ </el-dropdown>
+ </div>
+ </template>
+ </lims-table>
+ </section>
+
+ <template v-else>
+ <div class="annual-plan-header">
+ <div class="annual-plan-main">
+ <el-button link type="primary" size="small" @click="backToPlanList">鈫� 杩斿洖骞村害璁″垝</el-button>
+ <span class="annual-plan-label">{{ selectedYear }}骞村害</span>
+ <template v-if="currentPlan">
+ <strong>{{ currentPlan.monitorName }}</strong>
+ <el-tag :type="planStatusType">{{ planStatusText }}</el-tag>
+ <span>缂栧埗锛歿{ currentPlan.writeName || '-' }} {{ formatDate(currentPlan.writeTime) }}</span>
+ <span>瀹℃牳锛歿{ currentPlan.examineName || '-' }}</span>
+ <span>鎵瑰噯锛歿{ currentPlan.ratifyName || '-' }}</span>
+ </template>
+ <el-tag v-else type="info">璇ュ勾搴﹀皻鏈缓绔嬭鍒�</el-tag>
+ </div>
+ <div class="annual-plan-actions">
+ <el-button v-if="canEditPlan" type="primary" size="small" @click="submitPlan">鎻愪氦瀹℃牳</el-button>
+ <el-button v-if="canReviewPlan" type="primary" size="small" @click="examinePlan(currentPlan)">瀹℃牳</el-button>
+ <el-button v-if="canApprovePlan" type="primary" size="small" @click="approvalPlan(currentPlan)">鎵瑰噯</el-button>
+ <el-button size="small" @click="leadInto">瀵煎叆</el-button>
+ <el-button v-if="currentPlan" size="small" :disabled="currentPlan.ratifyStatus !== 1" @click="handleDown(currentPlan)">瀵煎嚭骞村害璁″垝</el-button>
+ </div>
</div>
- <div style="margin-top: 20px">
- <div style="display: flex;justify-content: space-between">
+ <div class="plan-detail-card">
+ <el-alert v-if="currentPlan && currentPlan.ratifyStatus !== 1" type="info" :closable="false" show-icon
+ style="margin-bottom: 12px"
+ title="妫�娴嬬被璐ㄦ帶椤圭洰闇�鍦ㄥ勾搴﹁鍒掑鏍搞�佹壒鍑嗛�氳繃鍚庯紝鐐瑰嚮瀵瑰簲琛岀殑鈥滀笅鍙戜换鍔♀�濊繘琛屼笅鍙戯紱闈炴娴嬬被椤圭洰鏃犻渶涓嬪彂銆�" />
+ <div class="plan-detail-toolbar">
<div style="display: flex;">
<div style="margin-bottom: 18px;margin-right: 10px;display: flex;align-items: center;line-height: 32px;">
- <span style="width: 88px;font-size: 14px;font-weight: 700;color: #606266;">鐩戞帶鐩殑</span>
- <el-input v-model="yearDetailForm.monitorPurpose" placeholder="璇疯緭鍏�" size="small"
+ <span style="width: 88px;font-size: 14px;font-weight: 700;color: var(--lims-text-2);">璐ㄦ帶椤圭洰</span>
+ <el-input v-model="yearDetailForm.monitorProject" placeholder="璇疯緭鍏�" size="small"
@keyup.enter="getYearDetailPlanList"></el-input>
</div>
<div style="margin-bottom: 18px;margin-right: 10px;display: flex;align-items: center;line-height: 32px;">
- <span style="width: 88px;font-size: 14px;font-weight: 700;color: #606266;">鐩戞帶椤圭洰</span>
- <el-input v-model="yearDetailForm.monitorProject" placeholder="璇疯緭鍏�" size="small"
- @keyup.enter="getYearDetailPlanList"></el-input>
+ <span style="width: 70px;font-size: 14px;font-weight: 700;color: var(--lims-text-2);">璐熻矗浜�</span>
+ <el-select v-model="yearDetailForm.responsibleUserId" clearable filterable size="small" style="width: 160px">
+ <el-option v-for="item in responsibleOptions" :key="item.id" :label="item.name" :value="item.id" />
+ </el-select>
</div>
<div style="line-height: 30px;">
<el-button type="primary" size="small" @click="getYearDetailPlanList">鏌ヨ</el-button>
@@ -40,14 +84,65 @@
</div>
</div>
<div style="line-height: 30px;">
- <el-button size="small" type="primary" @click="exportSignatureTemplate">瀵煎嚭绛惧悕妯℃澘</el-button>
- <el-button size="small" type="primary" @click="showDialog('add')">鏂板</el-button>
+<!-- <el-button size="small" type="primary" @click="exportSignatureTemplate">瀵煎嚭绛惧悕妯℃澘</el-button>-->
+ <el-button size="small" type="primary" :disabled="!canEditPlan" @click="showDialog('add')">鏂板璐ㄦ帶椤圭洰</el-button>
</div>
</div>
<lims-table :tableData="yearDetailTableData" :column="yearDetailColumnData" :page="yearDetailPage"
- :tableLoading="yearDetailLoading" :height="'calc(100vh - 34em)'" @pagination="pagination1" ref="yearDetailTableData"
- key="yearDetailTableData"></lims-table>
+ :tableLoading="yearDetailLoading" :height="'calc(100vh - 15em)'" @pagination="pagination1" ref="yearDetailTableData"
+ key="yearDetailTableData">
+ <template #detailActions="{ row }">
+ <div class="detail-actions">
+ <el-button link type="primary" size="small" :disabled="!canEditPlan || !!row.inspectionTaskId"
+ @click="showDialog('edit', row)">缂栬緫</el-button>
+
+ <el-button v-if="row.itemKind !== 'INSPECTION'" link type="primary" size="small"
+ @click="carryOut(row)">瀹炴柦</el-button>
+ <el-button v-else-if="!row.inspectionTaskId" link type="primary" size="small"
+ :disabled="row.planRatifyStatus !== 1" @click="dispatchTask(row)">涓嬪彂浠诲姟</el-button>
+ <el-button v-else link type="primary" size="small" @click="evaluate(row)">
+ {{ row.inspectionTaskState === 5 ? '璇勪环璁板綍' : '璇勪环瑕佹眰' }}
+ </el-button>
+
+ <el-dropdown trigger="click" @command="command => handleDetailCommand(command, row)">
+ <el-button link type="primary" size="small">鏇村鈱�</el-button>
+ <template #dropdown>
+ <el-dropdown-menu>
+ <el-dropdown-item v-if="row.itemKind !== 'INSPECTION'" command="complete">瀹屾垚鎶ュ憡</el-dropdown-item>
+ <el-dropdown-item v-if="row.itemKind !== 'INSPECTION'" command="evaluate">璇勪环</el-dropdown-item>
+ <el-dropdown-item v-if="row.itemKind === 'INSPECTION' && !row.inspectionTaskId" command="requirement">璇勪环瑕佹眰</el-dropdown-item>
+ <el-dropdown-item v-if="row.itemKind === 'INSPECTION' && row.inspectionTaskId" command="cancel"
+ :disabled="row.inspectionTaskOrderState !== 1 || row.inspectionTaskState !== 0">鍙栨秷浠诲姟</el-dropdown-item>
+ <el-dropdown-item command="attachment">闄勪欢涓婁紶</el-dropdown-item>
+ <el-dropdown-item command="export">瀵煎嚭</el-dropdown-item>
+ <el-dropdown-item command="delete" divided
+ :disabled="!canEditPlan || !!row.inspectionTaskId">鍒犻櫎</el-dropdown-item>
+ </el-dropdown-menu>
+ </template>
+ </el-dropdown>
+ </div>
+ </template>
+ </lims-table>
</div>
+ </template>
+ <el-dialog v-model="createPlanDialog" title="鏂板缓骞村害璐ㄩ噺鎺у埗璁″垝" width="520px">
+ <el-form :model="planForm" label-width="90px">
+ <el-form-item label="骞村害">
+ <el-date-picker v-model="planForm.monitorYear" type="year" value-format="YYYY" format="YYYY骞�"
+ :clearable="false" style="width: 100%" placeholder="璇烽�夋嫨骞村害" />
+ </el-form-item>
+ <el-form-item label="璁″垝鍚嶇О"><el-input v-model="planForm.monitorName" /></el-form-item>
+ <el-form-item label="瀹℃牳浜�">
+ <el-select v-model="planForm.examineUserId" filterable style="width:100%">
+ <el-option v-for="item in responsibleOptions" :key="item.id" :label="item.name" :value="item.id" />
+ </el-select>
+ </el-form-item>
+ </el-form>
+ <template #footer>
+ <el-button @click="createPlanDialog=false">鍙栨秷</el-button>
+ <el-button type="primary" :loading="createPlanLoading" @click="createPlan">纭畾</el-button>
+ </template>
+ </el-dialog>
<!--鏂板淇敼寮规-->
<detail-form-dialog v-if="formDia" ref="formDia" :qualityMonitorId="qualityMonitorId"
@closeDia="closeDia"></detail-form-dialog>
@@ -56,6 +151,8 @@
@closeCarryOutDia="closeCarryOutDia"></carry-out-dialog>
<!--璇勪环娴佺▼寮规-->
<evaluate-dialog v-if="evaluateDialog" ref="evaluateDialog" @closeEvaDia="closeEvaDia"></evaluate-dialog>
+ <inspection-evaluation-dialog v-if="inspectionEvaluateDialog" ref="inspectionEvaluateDialog"
+ @close="closeInspectionEvaluateDialog" />
<el-dialog v-model="examineDialog" title="瀹℃牳" width="30%" @close="closeExamineDia">
<span>
瀹℃牳澶囨敞锛�
@@ -117,27 +214,38 @@
<!--瀵煎叆璁″垝-->
<el-dialog v-model="uploadDia" title="鏁版嵁瀵煎叆" width="500px" :close-on-click-modal="false"
:close-on-press-escape="false">
- <div style="display: flex; align-items: center;">
- <span style="width: 60px">骞翠唤锛�</span>
- <el-date-picker v-model="planYear" type="year" value-format="YYYY" clearable size="small" format="YYYY"
- placeholder="閫夋嫨骞�">
- </el-date-picker>
- </div>
- <div style="display: flex;align-items: center;margin: 10px 0">
- <div style="width: 60px">瀹℃牳浜猴細</div>
- <el-select v-model="examineUserId" clearable filterable size="small" style="width: 50%;">
- <el-option v-for="item in responsibleOptions" :key="item.id" :label="item.name" :value="item.id">
- </el-option>
- </el-select>
+ <el-form label-width="70px" size="small">
+ <el-form-item label="骞翠唤">
+ <el-date-picker v-model="planYear" type="year" value-format="YYYY" clearable format="YYYY"
+ placeholder="閫夋嫨骞�" style="width: 100%">
+ </el-date-picker>
+ </el-form-item>
+ <el-form-item label="瀹℃牳浜�">
+ <el-select v-model="examineUserId" clearable filterable style="width: 100%">
+ <el-option v-for="item in responsibleOptions" :key="item.id" :label="item.name" :value="item.id">
+ </el-option>
+ </el-select>
+ </el-form-item>
+ </el-form>
+ <div style="display: flex; align-items: center; gap: 8px; margin-bottom: 10px; padding: 8px 12px; border-radius: 4px; background: var(--el-color-primary-light-9); font-size: 13px;">
+ <span>绗竴娆″鍏ヨ鍏堜笅杞芥ā鏉匡紝鎸夋ā鏉挎牸寮忓~鍐欏悗鍐嶄笂浼犮��</span>
+ <el-button link type="primary" @click="downloadTemplate">涓嬭浇瀵煎叆妯℃澘</el-button>
</div>
<div style="margin: 0 auto;">
- <el-upload ref="upload" :action="action" :auto-upload="false" :file-list="fileList" :headers="uploadHeader"
- :limit="1" accept='.jpg,.jpeg,.png,.gif,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.zip,.rar'
+ <el-upload ref="upload" :action="action" :auto-upload="false" v-model:file-list="fileList" :headers="uploadHeader"
+ :limit="1" accept=".xls,.xlsx"
:on-change="beforeUpload" :on-error="onError" :on-success="handleSuccessUp" drag
- :data="{ planYear: planYear, examineUserId: examineUserId }" name="file">
+ :data="{ monitorYear: planYear, examineUserId: examineUserId }" name="file">
<lims-icon name="el-icon-upload"></lims-icon>
<div class="el-upload__text">灏嗘枃浠舵嫋鍒版澶勶紝鎴�<em>鐐瑰嚮涓婁紶</em></div>
</el-upload>
+ </div>
+ <div style="margin-top: 10px; color: var(--el-text-color-secondary); font-size: 12px; line-height: 20px;">
+ <div>鏀寔鏍煎紡锛�.xls銆�.xlsx锛涘崟涓枃浠朵笉瓒呰繃10MB銆�</div>
+ <div>璐ㄦ帶椤圭洰銆佹妧鏈爣鍑嗐�佽川鎺ф柟寮忋�佸畬鎴愭椂闄愩�佽礋璐d汉涓哄繀濉」銆�</div>
+ <div>瀹屾垚鏃堕檺鏍煎紡蹇呴』涓� YYYY-MM锛堟ā鏉夸腑璇ュ垪涓烘枃鏈牸寮忥紝鐩存帴杈撳叆 2026-12 鍗冲彲锛夛紱璐熻矗浜哄繀椤诲~鍐欑郴缁熶腑宸插瓨鍦ㄧ殑浜哄憳濮撳悕銆�</div>
+ <div>瀵煎叆鍚庤鍒掍繚瀛樹负鑽夌銆傝鍦ㄨ鍒掕鎯呬腑缂栬緫璐ㄦ帶椤圭洰骞堕�夋嫨浜嬮」绫诲埆锛涙娴嬬被杩橀渶閫夋嫨妫�娴嬫爣鍑嗐�佸師濮嬭褰曟ā鏉裤�佹娴嬪憳銆佽瘎浠蜂汉骞跺~鍐欎换鍔℃埅姝㈡棩锛岀‘璁ゅ悗鍐嶆彁浜ゅ鏍搞��</div>
+ <div>瀵煎叆鍙鍙栨ā鏉跨殑绗竴涓伐浣滆〃銆�</div>
</div>
<template #footer><span class="dialog-footer">
<el-button @click="uploadDia = false">鍙� 娑�</el-button>
@@ -152,7 +260,7 @@
</div>
<div style="margin: 0 auto;">
<el-upload ref="upload1" :action="action1" :auto-upload="false"
- :data="{ qualityMonitorDetailsId: qualityMonitorDetailsId }" :file-list="fileList1" :headers="uploadHeader"
+ :data="{ qualityMonitorDetailsId: qualityMonitorDetailsId }" v-model:file-list="fileList1" :headers="uploadHeader"
:limit="1" :on-change="beforeUpload1" :on-error="onError1" :on-success="onSuccess1" accept='.doc,.docx,application/pdf,' drag
name="file">
<lims-icon name="el-icon-upload"></lims-icon>
@@ -170,17 +278,20 @@
<script>
import DetailFormDialog from './components/detailFormDialog.vue';
+import InspectionEvaluationDialog from './components/inspectionEvaluationDialog.vue';
import CarryOutDialog from './components/carryOutDialog.vue';
import EvaluateDialog from './components/evaluateDialog.vue';
import filePreview from "@/components/Preview/filePreview.vue";
import limsTable from "@/components/Table/lims-table.vue";
import {
+ createAnnualPlan, getAnnualPlan, submitAnnualPlan,
delQualityMonitorDetail,
delQualitySupervise,
examineQualityMonitor, exportQualityMonitorDetail, exportQualityMonitorEvaluate, exportQualityMonitorRatify,
pageQualityMonitor, pageQualityMonitorDetail, ratifyFinishReport,
ratifyQualityMonitor
} from "@/api/cnas/process/ensureResults/qualityMonitor";
+import { dispatchInspectionTask, cancelInspectionTask } from "@/api/cnas/process/ensureResults/qualityMonitor";
import { selectUserCondition } from "@/api/performance/class";
import { mapGetters } from "@/utils/store-compat";
import ViewRecord from "./components/ViewRecord.vue";
@@ -188,11 +299,19 @@
export default {
name: 'EnsureResultsValidity',
// import 寮曞叆鐨勭粍浠堕渶瑕佹敞鍏ュ埌瀵硅薄涓墠鑳戒娇鐢�
- components: {ViewRecord, limsTable, filePreview, EvaluateDialog, CarryOutDialog, DetailFormDialog },
+ components: {ViewRecord, limsTable, filePreview, EvaluateDialog, CarryOutDialog, DetailFormDialog, InspectionEvaluationDialog },
data() {
// 杩欓噷瀛樻斁鏁版嵁
return {
ViewRecord: false,
+ inspectionEvaluateDialog: false,
+ pageMode: 'list',
+ selectedYear: String(new Date().getFullYear()),
+ currentPlan: null,
+ selectedPlanId: null,
+ createPlanDialog: false,
+ createPlanLoading: false,
+ planForm: { monitorYear: String(new Date().getFullYear()), monitorName: '', examineUserId: null },
examineUserId: '',
responsibleOptions: [],
yearForm: {
@@ -207,247 +326,91 @@
{
label: '璁″垝鍚嶇О',
prop: 'monitorName',
- width: '150px'
+ minWidth: '220px'
+ }, {
+ label: '璁″垝骞村害',
+ prop: 'monitorYear',
+ width: '100px'
+ }, {
+ dataType: 'tag',
+ label: '璁″垝鐘舵��',
+ prop: 'workflowStatus',
+ width: '110px',
+ formatData: (value, row) => this.planWorkflowText(value),
+ formatType: value => this.planWorkflowType(value)
}, {
label: '缂栧埗浜�',
prop: 'writeName',
- width: '100'
+ minWidth: '100px'
}, {
label: '缂栧埗鏃ユ湡',
prop: 'writeTime',
- width: '160'
- }, {
- dataType: 'tag',
- label: '瀹℃牳鐘舵��',
- prop: 'examineStatus',
- width: '100',
- formatData: (params) => {
- if (params === 0) {
- return '涓嶉�氳繃';
- } else if (params === 1) {
- return '閫氳繃';
- } else {
- return null;
- }
- },
- formatType: (params) => {
- if (params === 0) {
- return 'danger';
- } else if (params === 1) {
- return 'success';
- } else {
- return null;
- }
- }
- }, {
- label: '瀹℃牳鍐呭',
- prop: 'examineRemark',
- width: '100'
+ minWidth: '150px',
+ formatData: value => this.formatDate(value)
}, {
label: '瀹℃牳浜�',
prop: 'examineName',
- width: '100'
+ minWidth: '100px'
}, {
label: '瀹℃牳鏃ユ湡',
prop: 'examineTime',
- width: '160'
- }, {
- dataType: 'tag',
- label: '鎵瑰噯鐘舵��',
- prop: 'ratifyStatus',
- width: '100',
- formatData: (params) => {
- if (params === 0) {
- return '涓嶆壒鍑�';
- } else if (params === 1) {
- return '鎵瑰噯';
- } else {
- return null;
- }
- },
- formatType: (params) => {
- if (params === 0) {
- return 'danger';
- } else if (params === 1) {
- return 'success';
- } else {
- return null;
- }
- }
- }, {
- label: '鎵瑰噯鍐呭',
- prop: 'ratifyRemark',
- width: '100'
+ minWidth: '150px',
+ formatData: value => this.formatDate(value)
}, {
label: '鎵瑰噯浜�',
prop: 'ratifyName',
- width: '100'
+ minWidth: '100px'
}, {
label: '鎵瑰噯鏃ユ湡',
prop: 'ratifyTime',
- width: '160'
+ minWidth: '150px',
+ formatData: value => this.formatDate(value)
}, {
- dataType: 'action',
+ dataType: 'slot',
+ slot: 'planActions',
label: '鎿嶄綔',
fixed: 'right',
- operation: [
- {
- name: '瀹℃牳',
- type: 'text',
- disabled: (row) => {
- if (row.examineStatus === 1 || this.userId != row.examineUserId) {
- return true
- } else {
- return false
- }
- },
- clickFun: (row) => {
- this.examinePlan(row)
- }
- },
- {
- name: '鎵瑰噯',
- type: 'text',
- disabled: (row) => {
- if (row.ratifyStatus === 1 || row.examineStatus !== 1 || this.userId != row.ratifyUserId) {
- return true
- } else {
- return false
- }
- },
- clickFun: (row) => {
- this.approvalPlan(row)
- }
- },
- {
- name: '瀵煎嚭',
- type: 'text',
- clickFun: (row) => {
- this.handleDown(row)
- },
- disabled: (row) => {
- if (row.ratifyStatus !== 1) {
- return true
- } else {
- return false
- }
- },
- },
- {
- name: '鍒犻櫎',
- type: 'text',
- color: 'var(--el-color-danger)',
- clickFun: (row) => {
- this.delPlan(row)
- },
- disabled: (row) => {
- if (row.examineStatus === 1) {
- return true;
- } else {
- return false;
- }
- },
- }
- ]
+ width: '220px'
}],
yearTableData: [], // 骞磋〃
yearLoading: false,
yearDetailForm: {
- monitorPurpose: '',
monitorProject: '',
+ responsibleUserId: null,
},
yearDetailColumnData: [
{
- label: '鐩戞帶鐩殑',
- prop: 'monitorPurpose',
- width: '150px',
- showOverflowTooltip: true,
- }, {
- label: '璁″垝寮�灞曟椂闂�',
- prop: 'plannedTime',
- width: '150px'
- }, {
- label: '鐩戞帶椤圭洰',
+ label: '璐ㄦ帶椤圭洰',
prop: 'monitorProject',
- width: '150px'
+ minWidth: '140px'
}, {
- label: '鍙傚姞鍗曚綅锛堜汉鍛橈級',
- prop: 'participant',
- width: '190px'
+ label: '鎶�鏈爣鍑�',
+ prop: 'technicalStandardText',
+ minWidth: '220px'
}, {
- label: '棰勭畻锛堝厓锛�',
- prop: 'budget',
- width: '150px'
- }, {
- label: '缁勭粐浜哄憳',
- prop: 'organization',
- width: '150px'
- }, {
- label: '鐩戞帶鏂瑰紡',
+ label: '璐ㄦ帶鏂瑰紡',
prop: 'monitorWay',
- width: '150px'
- },{
- dataType: 'tag',
- label: '瀹炴柦鐘舵��',
- prop: 'detailsRatifyStatus',
- width: '100',
- formatData: (params) => {
- if (params === 0) {
- return '鏈紑濮�';
- } else if (params === 1) {
- return '寰呰瘎浠�';
- } else if (params === 2) {
- return '涓嶆壒鍑�';
- } else if (params === 3) {
- return '宸叉壒鍑�';
- } else {
- return null;
- }
- },
- formatType: (params) => {
- if (params === 0) {
- return '';
- } else if (params === 1) {
- return 'warning';
- } else if (params === 2) {
- return 'danger';
- } else if (params === 3) {
- return 'success';
- } else {
- return null;
- }
- }
- },{
- dataType: 'tag',
- label: '鎶ュ憡鐘舵��',
- prop: 'reportStatus',
- width: '100',
- formatData: (params) => {
- if (params === 0) {
- return '鏈紑濮�';
- } else if (params === 1) {
- return '寰呰瘎浠�';
- } else if (params === 2) {
- return '涓嶆壒鍑�';
- } else if (params === 3) {
- return '宸叉壒鍑�';
- } else {
- return null;
- }
- },
- formatType: (params) => {
- if (params === 0) {
- return '';
- } else if (params === 1) {
- return 'warning';
- } else if (params === 2) {
- return 'danger';
- } else if (params === 3) {
- return 'success';
- } else {
- return null;
- }
- }
+ minWidth: '120px'
+ }, {
+ label: '瀹屾垚鏃堕檺',
+ prop: 'completionMonth',
+ width: '110px',
+ formatData: value => value ? value.replace('-', '.') : ''
+ }, {
+ label: '璐熻矗浜�',
+ prop: 'responsibleName',
+ minWidth: '100px'
+ }, {
+ label: '璇勪环浜�',
+ prop: 'evaluatorName',
+ minWidth: '100px'
+ }, {
+ label: '浜嬮」绫诲埆', prop: 'itemKind', width: '100px',
+ formatData: value => value === 'INSPECTION' ? '妫�娴嬬被' : '闈炴娴嬬被'
+ }, {
+ label: '鐩戞帶浠诲姟缂栧彿', prop: 'inspectionTaskCode', minWidth: '150px'
+ }, {
+ label: '浠诲姟鐘舵��', prop: 'taskStatusText', width: '110px'
},{
dataType: 'tag',
label: '璇勪环鐘舵��',
@@ -480,61 +443,11 @@
}
}
}, {
- dataType: 'action',
+ dataType: 'slot',
+ slot: 'detailActions',
label: '鎿嶄綔',
fixed: 'right',
- operation: [
- {
- name: '缂栬緫',
- type: 'text',
- clickFun: (row) => {
- this.showDialog('edit', row)
- }
- },
- {
- name: '瀹炴柦',
- type: 'text',
- clickFun: (row) => {
- this.carryOut(row)
- }
- },
- {
- name: '瀹屾垚鎶ュ憡',
- type: 'text',
- clickFun: (row) => {
- this.record(row)
- },
- },
- {
- name: '璇勪环',
- type: 'text',
- clickFun: (row) => {
- this.evaluate(row)
- }
- },
- {
- name: '闄勪欢涓婁紶',
- type: 'text',
- clickFun: (row) => {
- this.viewTestRecord(row)
- }
- },
- {
- name: '瀵煎嚭',
- type: 'text',
- clickFun: (row) => {
- this.downLoadPost(row);
- },
- },
- {
- name: '鍒犻櫎',
- type: 'text',
- color: 'var(--el-color-danger)',
- clickFun: (row) => {
- this.delYearPlanDetail(row)
- }
- }
- ]
+ width: '220px'
}
],
yearDetailTableData: [], // 骞存槑缁嗚〃
@@ -574,31 +487,91 @@
};
},
mounted() {
+ this.getUserList()
this.getYearPlanList()
},
// 鏂规硶闆嗗悎
methods: {
// 鏌ヨ骞村害璁″垝琛�
getYearPlanList() {
- const entity = {
- monitorName: this.yearForm.monitorName,
- }
- const page = this.yearPage
this.yearLoading = true
- pageQualityMonitor({ ...entity, ...page }).then(res => {
- this.yearLoading = false
- this.yearTableData = res.data.records
- this.yearPage.total = res.data.total
- if (this.yearTableData.length > 0) {
- this.rowClick(this.yearTableData[0])
- }
- }).catch(err => {
- console.log('err---', err);
+ const entity = {
+ monitorYear: this.selectedYear,
+ monitorName: this.yearForm.monitorName
+ }
+ return pageQualityMonitor({ ...entity, ...this.yearPage }).then(res => {
+ this.yearTableData = res.data?.records || []
+ this.yearPage.total = res.data?.total || 0
+ }).finally(() => {
this.yearLoading = false
})
},
+ loadAnnualPlan() {
+ if (!this.selectedPlanId) return Promise.resolve()
+ return this.loadPlanVersion()
+ },
+ loadPlanVersion() {
+ if (!this.selectedPlanId) return Promise.resolve()
+ return getAnnualPlan({ monitorYear: this.selectedYear, qualityMonitorId: this.selectedPlanId }).then(res => {
+ this.currentPlan = res.data || null
+ this.qualityMonitorId = this.currentPlan?.qualityMonitorId || ''
+ this.yearDetailPage.current = 1
+ return this.getYearDetailPlanList()
+ })
+ },
+ openPlan(row, addFirstDetail = false) {
+ this.selectedYear = String(row.monitorYear || this.selectedYear)
+ this.selectedPlanId = row.qualityMonitorId
+ this.pageMode = 'detail'
+ return this.loadPlanVersion().then(() => {
+ if (addFirstDetail) this.showDialog('add')
+ })
+ },
+ backToPlanList() {
+ this.pageMode = 'list'
+ this.currentPlan = null
+ this.qualityMonitorId = ''
+ this.yearDetailForm = { monitorProject: '', responsibleUserId: null }
+ this.getYearPlanList()
+ },
+ handleYearChange() {
+ this.yearPage.current = 1
+ this.getYearPlanList()
+ },
+ openCreatePlan() {
+ this.planForm = {
+ monitorYear: String(new Date().getFullYear()),
+ monitorName: '',
+ examineUserId: null
+ }
+ this.createPlanDialog = true
+ },
+ createPlan() {
+ if (!this.planForm.monitorYear || !this.planForm.monitorName || !this.planForm.examineUserId) {
+ this.$message.warning('璇烽�夋嫨骞村害銆佸~鍐欒鍒掑悕绉板苟閫夋嫨瀹℃牳浜�')
+ return
+ }
+ this.createPlanLoading = true
+ createAnnualPlan({ ...this.planForm }).then(res => {
+ this.createPlanDialog = false
+ this.selectedYear = String(res.data.monitorYear)
+ this.yearPage.current = 1
+ this.$message.success('骞村害璁″垝宸插垱寤猴紝璇峰~鍐欑涓�涓川鎺ч」鐩�')
+ return this.getYearPlanList().then(() => this.openPlan(res.data, true))
+ }).finally(() => { this.createPlanLoading = false })
+ },
+ submitPlan() {
+ this.$confirm('鎻愪氦鍚庤川鎺ч」鐩皢閿佸畾锛岀‘璁ゆ彁浜ゅ鏍革紵', '鎻愪氦瀹℃牳').then(() => {
+ submitAnnualPlan(this.qualityMonitorId).then(() => {
+ this.$message.success('宸叉彁浜ゅ鏍�')
+ this.loadPlanVersion()
+ this.getYearPlanList()
+ })
+ }).catch(() => {})
+ },
clearYear() {
this.yearForm.monitorName = ''
+ this.yearPage.current = 1
this.getYearPlanList()
},
pagination({ page, limit }) {
@@ -609,14 +582,31 @@
pagination1({ page, limit }) {
this.yearDetailPage.current = page;
this.yearDetailPage.size = limit;
- this.getYearPlanList();
+ this.getYearDetailPlanList();
},
leadInto() {
this.uploadDia = true
+ this.planYear = this.selectedYear
+ this.fileList = []
this.getUserList()
+ },
+ // 涓嬭浇瀵煎叆妯℃澘
+ downloadTemplate() {
+ const link = document.createElement('a')
+ // 甯︾増鏈弬鏁伴伩鍏嶆祻瑙堝櫒缁х画浣跨敤缂撳瓨閲岀殑鏃фā鏉�
+ link.href = '/import-templates/璐ㄩ噺鐩戞帶璁″垝瀵煎叆妯℃澘.xlsx?v=2'
+ link.download = '璐ㄩ噺鐩戞帶璁″垝瀵煎叆妯℃澘.xlsx'
+ document.body.appendChild(link)
+ link.click()
+ document.body.removeChild(link)
},
// 瀵煎叆娴佺▼
beforeUpload(file) {
+ if (!/\.(xls|xlsx)$/i.test(file.name || '')) {
+ this.$message.error('璇烽�夋嫨 .xls 鎴� .xlsx 鏍煎紡鐨勬枃浠�');
+ this.$refs.upload.clearFiles()
+ return false;
+ }
if (file.size > 1024 * 1024 * 10) {
this.$message.error('涓婁紶鏂囦欢涓嶈秴杩�10M');
this.$refs.upload.clearFiles()
@@ -626,23 +616,40 @@
}
},
onError(err, file, fileList) {
- this.$message.error('涓婁紶澶辫触')
- this.$refs.upload.clearFiles()
+ this.uploading = false
+ this.fileList = []
+ this.$message.error('涓婁紶澶辫触锛岃閲嶆柊閫夋嫨鏂囦欢')
},
handleSuccessUp(response) {
this.uploading = false;
if (response.code == 200) {
- this.$message.success('涓婁紶鎴愬姛');
+ this.$message.success('瀵煎叆鎴愬姛锛岃鍒掑凡淇濆瓨涓鸿崏绋匡紝璇疯ˉ鍏ㄨ川鎺ч」鐩悗鎻愪氦瀹℃牳');
+ const importedPlan = response.data || null
this.timer = setTimeout(() => {
this.uploadDia = false
this.fileList = []
- this.planYear = ''
this.examineUserId = ''
- this.getYearPlanList()
+ // 瀵煎叆瀹屾垚鍚庣洿鎺ヨ繘鍏ヨ鍒掕鎯咃紝鏂逛究缁х画缂栬緫璐ㄦ帶椤圭洰銆侀�夋嫨妫�娴嬫爣鍑嗙瓑
+ if (importedPlan && importedPlan.qualityMonitorId) {
+ this.openPlan(importedPlan)
+ } else {
+ this.getYearPlanList()
+ }
}, 1000)
} else {
- this.$message.error(response.msg)
+ this.$message.error(response.msg || '涓婁紶澶辫触')
+ // 鍚庣杩斿洖涓氬姟閿欒鏃� HTTP 鐘舵�佷粛鏄� 200锛宔l-upload 浼氭妸鏂囦欢鏍囪涓� success锛�
+ // 鐩存帴鍐嶆璋冪敤 submit() 涓嶄細閲嶆柊涓婁紶锛岃繖閲屾妸鏂囦欢鎭㈠涓哄緟涓婁紶鐘舵�併��
+ this.resetUploadFiles()
}
+ },
+ resetUploadFiles() {
+ const files = this.$refs.upload?.uploadFiles || this.fileList || []
+ files.forEach(file => {
+ file.status = 'ready'
+ file.response = undefined
+ file.percentage = 0
+ })
},
submitUpload() {
if (!this.planYear) {
@@ -650,9 +657,15 @@
return;
}
if (!this.examineUserId) {
- this.$message.warning('璇烽�夋嫨鎵瑰噯浜�')
+ this.$message.warning('璇烽�夋嫨瀹℃牳浜�')
return;
}
+ const files = this.$refs.upload?.uploadFiles || this.fileList || []
+ if (!files.length) {
+ this.$message.warning('璇烽�夋嫨瑕佸鍏ョ殑鏂囦欢')
+ return;
+ }
+ this.uploading = true
this.$refs.upload.submit();
},
// end
@@ -678,7 +691,7 @@
closeExamineDia() {
this.examineDialog = false
this.examineInfo.examineRemark = ''
- this.getYearPlanList()
+ this.refreshPlanData()
},
// 鎵瑰噯
approvalPlan(row) {
@@ -701,7 +714,14 @@
closeRatifyDia() {
this.ratifyDialog = false
this.ratifyInfo.ratifyRemark = ''
- this.getYearPlanList()
+ this.refreshPlanData()
+ },
+ refreshPlanData() {
+ return this.getYearPlanList().then(() => {
+ if (this.pageMode === 'detail' && this.selectedPlanId) {
+ return this.loadPlanVersion()
+ }
+ })
},
// 鎵瑰噯鎶ュ憡
handleApproval(status) {
@@ -762,16 +782,19 @@
getYearDetailPlanList() {
const entity = {
qualityMonitorId: this.qualityMonitorId,
- monitorPurpose: this.yearDetailForm.monitorPurpose,
monitorProject: this.yearDetailForm.monitorProject,
+ responsibleUserId: this.yearDetailForm.responsibleUserId,
}
const page = this.yearDetailPage
this.yearDetailLoading = true
pageQualityMonitorDetail({ ...entity, ...page }).then(res => {
this.yearDetailLoading = false
- this.yearDetailTableData = res.data.records
+ this.yearDetailTableData = res.data.records.map(item => ({
+ ...item,
+ taskStatusText: this.inspectionTaskStatus(item)
+ }))
this.yearDetailPage.total = res.data.total
- this.$refs.yearDetailTableData.$refs.multipleTable.doLayout()
+ this.$nextTick(() => this.$refs.yearDetailTableData?.$refs?.multipleTable?.doLayout())
}).catch(err => {
console.log('err---', err);
this.yearDetailLoading = false
@@ -780,8 +803,8 @@
// 閲嶇疆鏄庣粏琛�
clearDetail() {
this.yearDetailForm = {
- monitorPurpose: '',
- monitorProject: ''
+ monitorProject: '',
+ responsibleUserId: null
}
this.getYearDetailPlanList()
},
@@ -822,6 +845,7 @@
}
this.lookDialogVisible = true
} else {
+ this.fileList1 = []
this.uploadDia1 = true
}
},
@@ -851,7 +875,7 @@
this.uploading1 = false
},
submitUpload1() {
- if (this.$refs.upload1.uploadFiles.length === 0) {
+ if (!this.fileList1 || this.fileList1.length === 0) {
this.$message.error('鏈�夋嫨鏂囦欢')
return
}
@@ -862,6 +886,11 @@
// end
// 鎵撳紑璇勪环寮规
evaluate(row) {
+ if (row.itemKind === 'INSPECTION') {
+ this.inspectionEvaluateDialog = true
+ this.$nextTick(() => this.$refs.inspectionEvaluateDialog.open(row))
+ return
+ }
this.evaluateDialog = true
this.$nextTick(() => {
this.$refs.evaluateDialog.openDia(row)
@@ -870,6 +899,26 @@
closeEvaDia() {
this.evaluateDialog = false
this.getYearDetailPlanList()
+ },
+ closeInspectionEvaluateDialog() {
+ this.inspectionEvaluateDialog = false
+ this.getYearDetailPlanList()
+ },
+ dispatchTask(row) {
+ this.$confirm(`纭涓嬪彂鈥�${row.monitorProject}鈥濈殑璐ㄩ噺鐩戞帶妫�楠屼换鍔★紵`, '涓嬪彂浠诲姟').then(() => {
+ dispatchInspectionTask(row.qualityMonitorDetailsId).then(res => {
+ this.$message.success(`宸蹭笅鍙戠洃鎺т换鍔★細${res.data.entrustCode}`)
+ this.getYearDetailPlanList()
+ })
+ }).catch(() => {})
+ },
+ cancelTask(row) {
+ this.$confirm(`纭鍙栨秷鐩戞帶浠诲姟鈥�${row.inspectionTaskCode}鈥濓紵宸插彇娑堜换鍔′細淇濈暀鍘嗗彶璁板綍銆俙, '鍙栨秷浠诲姟').then(() => {
+ cancelInspectionTask(row.qualityMonitorDetailsId).then(() => {
+ this.$message.success('浠诲姟宸插彇娑�')
+ this.getYearDetailPlanList()
+ })
+ }).catch(() => {})
},
// 闄勪欢涓婁紶
viewTestRecord (row) {
@@ -885,6 +934,14 @@
},
// 鎵撳紑骞村害鏄庣粏鏂板銆佷慨鏀瑰脊妗�
showDialog(type, row) {
+ if (!this.qualityMonitorId) {
+ this.$message.warning('璇峰厛鏂板缓骞村害璐ㄩ噺鎺у埗璁″垝')
+ return
+ }
+ if (!this.canEditPlan) {
+ this.$message.warning('褰撳墠璁″垝鐘舵�佷笉鑳界淮鎶よ川鎺ч」鐩�')
+ return
+ }
this.formDia = true
this.$nextTick(() => {
this.$refs.formDia.openDia(type, row)
@@ -949,11 +1006,98 @@
link.target = '_blank';
document.body.appendChild(link);
link.click();
+ },
+ formatDate(value) {
+ return value ? String(value).slice(0, 10) : '-'
+ },
+ planWorkflowText(value) {
+ return ({
+ DRAFT: '鑽夌',
+ PENDING_REVIEW: '寰呭鏍�',
+ REVIEW_REJECTED: '瀹℃牳閫�鍥�',
+ PENDING_APPROVAL: '寰呮壒鍑�',
+ APPROVAL_REJECTED: '鎵瑰噯閫�鍥�',
+ APPROVED: '宸叉壒鍑�'
+ })[value] || '鍘嗗彶璁″垝'
+ },
+ planWorkflowType(value) {
+ return ({
+ DRAFT: 'info',
+ PENDING_REVIEW: 'warning',
+ REVIEW_REJECTED: 'danger',
+ PENDING_APPROVAL: 'warning',
+ APPROVAL_REJECTED: 'danger',
+ APPROVED: 'success'
+ })[value] || 'info'
+ },
+ canReviewRow(row) {
+ return row.workflowStatus === 'PENDING_REVIEW'
+ && Number(this.userId) === Number(row.examineUserId)
+ },
+ canApproveRow(row) {
+ return row.workflowStatus === 'PENDING_APPROVAL'
+ && Number(this.userId) === Number(row.ratifyUserId)
+ },
+ canDeleteRow(row) {
+ return Number(this.userId) === Number(row.writeUserId)
+ && ['DRAFT', 'REVIEW_REJECTED', 'APPROVAL_REJECTED'].includes(row.workflowStatus || 'DRAFT')
+ },
+ handlePlanCommand(command, row) {
+ if (command === 'export') this.handleDown(row)
+ if (command === 'delete') this.delPlan(row)
+ },
+ inspectionTaskStatus(row) {
+ if (row.itemKind !== 'INSPECTION') return '鏃犻渶涓嬪彂'
+ const value = row.inspectionTaskState
+ if (value === null || value === undefined) {
+ return Number(row.planRatifyStatus) === 1 ? '鏈笅鍙�' : '寰呰鍒掓壒鍑�'
+ }
+ const map = { 0: '寰呮娴�', 1: '妫�娴嬩腑', 2: '妫�娴嬩腑', 3: '寰呭鏍�', 4: '澶嶆牳閫�鍥�', 5: '寰呰瘎浠�' }
+ return map[value] || '澶勭悊涓�'
+ },
+ handleDetailCommand(command, row) {
+ const handlers = {
+ complete: () => this.record(row),
+ evaluate: () => this.evaluate(row),
+ requirement: () => this.evaluate(row),
+ cancel: () => this.cancelTask(row),
+ attachment: () => this.viewTestRecord(row),
+ export: () => this.downLoadPost(row),
+ delete: () => this.delYearPlanDetail(row)
+ }
+ handlers[command]?.()
}
},
// 鐢ㄤ簬涓婁紶鏂囦欢鐨勪俊鎭�
computed: {
...mapGetters(["userId", "nickName"]),
+ effectivePlanStatus() {
+ if (!this.currentPlan) return ''
+ if (this.currentPlan.workflowStatus) return this.currentPlan.workflowStatus
+ if (this.currentPlan.ratifyStatus === 1) return 'APPROVED'
+ if (this.currentPlan.ratifyStatus === 0) return 'APPROVAL_REJECTED'
+ if (this.currentPlan.examineStatus === 1) return 'PENDING_APPROVAL'
+ if (this.currentPlan.examineStatus === 0) return 'REVIEW_REJECTED'
+ return 'DRAFT'
+ },
+ planStatusText() {
+ return ({DRAFT:'鑽夌',PENDING_REVIEW:'寰呭鏍�',REVIEW_REJECTED:'瀹℃牳閫�鍥�',PENDING_APPROVAL:'寰呮壒鍑�',APPROVAL_REJECTED:'鎵瑰噯閫�鍥�',APPROVED:'宸叉壒鍑�'})[this.effectivePlanStatus] || '鍘嗗彶璁″垝'
+ },
+ planStatusType() {
+ return ({DRAFT:'info',PENDING_REVIEW:'warning',REVIEW_REJECTED:'danger',PENDING_APPROVAL:'warning',APPROVAL_REJECTED:'danger',APPROVED:'success'})[this.effectivePlanStatus] || 'info'
+ },
+ canEditPlan() {
+ return !!this.currentPlan && Number(this.userId) === Number(this.currentPlan.writeUserId)
+ && ['DRAFT','REVIEW_REJECTED','APPROVAL_REJECTED'].includes(this.effectivePlanStatus)
+ },
+ canReviewPlan() {
+ return !!this.currentPlan && this.effectivePlanStatus === 'PENDING_REVIEW'
+ && Number(this.userId) === Number(this.currentPlan.examineUserId)
+ },
+ canApprovePlan() {
+ return !!this.currentPlan && this.effectivePlanStatus === 'PENDING_APPROVAL'
+ && Number(this.userId) === Number(this.currentPlan.ratifyUserId)
+ },
action() {
return this.javaApi + '/qualityMonitor/importQualityMonitor'
},
@@ -967,4 +1111,84 @@
};
</script>
-<style scoped></style>
+<style scoped>
+.plan-list-card {
+ min-width: 0;
+ padding: 14px 16px;
+ background: var(--lims-card-bg, var(--el-bg-color));
+ border: 1px solid var(--el-border-color-light);
+ border-radius: 4px;
+}
+.plan-list-toolbar,
+.plan-list-filters,
+.plan-list-actions {
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: 10px;
+}
+.plan-list-toolbar {
+ justify-content: space-between;
+ margin-bottom: 14px;
+}
+.filter-label {
+ margin-left: 8px;
+ font-size: 14px;
+ font-weight: 700;
+ color: var(--lims-text-2);
+ white-space: nowrap;
+}
+.annual-plan-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 16px;
+ padding: 14px 16px;
+ margin-bottom: 16px;
+ background: var(--lims-card-bg, var(--el-bg-color));
+ border: 1px solid var(--el-border-color-light);
+ border-radius: 4px;
+}
+.annual-plan-main, .annual-plan-actions {
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: 10px;
+}
+.annual-plan-label { font-weight: 700; color: var(--lims-text-2); }
+.plan-detail-card {
+ min-width: 0;
+ background: var(--lims-card-bg, var(--el-bg-color));
+}
+.plan-detail-toolbar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ flex-wrap: wrap;
+ gap: 10px;
+}
+.section-title {
+ display: inline-flex;
+ align-items: center;
+ margin-right: 18px;
+ font-size: 15px;
+ font-weight: 700;
+ color: var(--lims-text-1, var(--el-text-color-primary));
+ white-space: nowrap;
+}
+.detail-actions {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ white-space: nowrap;
+}
+@media (max-width: 1200px) {
+ .annual-plan-header {
+ align-items: flex-start;
+ flex-direction: column;
+ }
+ .annual-plan-actions {
+ width: 100%;
+ }
+}
+</style>
--
Gitblit v1.9.3