From b93657ca98a9f1ced3aacc255c3fa09b7d39cca4 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期二, 20 十月 2026 18:01:45 +0800
Subject: [PATCH] feat: 质量监控/人员培训/体系文件控制功能与界面调整
---
src/components/Table/lims-table.vue | 5
src/views/CNAS/process/ensureResults/ensureResultsValidity/index.vue | 12 +-
src/views/CNAS/personnel/personnelInfo/tabs/personnelTraining.vue | 36 +++---
src/views/CNAS/process/ensureResults/ensureResultsValidity/components/evaluateDialog.vue | 4
src/views/CNAS/systemManagement/documentControl/components/DistributionCollectionRecord.vue | 2
public/import-templates/质量监控计划导入模板.xlsx | 0
src/views/CNAS/systemManagement/documentControl/components/FileList.vue | 7 +
src/views/CNAS/personnel/personnelInfo/components/Edit.vue | 80 +++++++++------
src/views/CNAS/personnel/personnelInfo/components/AddInDetail.vue | 47 ++++++++-
src/views/CNAS/systemManagement/documentControl/components/ControlledFileApplication.vue | 19 ++-
src/components/ImportDialog/index.vue | 12 ++
src/components/UpPdfStamp/index.vue | 31 +++++
src/views/CNAS/process/ensureResults/qualityControlPlan/index.vue | 6
src/views/CNAS/systemManagement/documentControl/components/FileChangeRequest.vue | 14 ++
public/import-templates/人员培训年度计划导入模板.xlsx | 0
src/views/CNAS/process/ensureResults/ensureResultsValidity/components/detailFormDialog.vue | 25 ++++
16 files changed, 214 insertions(+), 86 deletions(-)
diff --git "a/public/import-templates/\344\272\272\345\221\230\345\237\271\350\256\255\345\271\264\345\272\246\350\256\241\345\210\222\345\257\274\345\205\245\346\250\241\346\235\277.xlsx" "b/public/import-templates/\344\272\272\345\221\230\345\237\271\350\256\255\345\271\264\345\272\246\350\256\241\345\210\222\345\257\274\345\205\245\346\250\241\346\235\277.xlsx"
index 269954c..7a0ed12 100644
--- "a/public/import-templates/\344\272\272\345\221\230\345\237\271\350\256\255\345\271\264\345\272\246\350\256\241\345\210\222\345\257\274\345\205\245\346\250\241\346\235\277.xlsx"
+++ "b/public/import-templates/\344\272\272\345\221\230\345\237\271\350\256\255\345\271\264\345\272\246\350\256\241\345\210\222\345\257\274\345\205\245\346\250\241\346\235\277.xlsx"
Binary files differ
diff --git "a/public/import-templates/\350\264\250\351\207\217\347\233\221\346\216\247\350\256\241\345\210\222\345\257\274\345\205\245\346\250\241\346\235\277.xlsx" "b/public/import-templates/\350\264\250\351\207\217\347\233\221\346\216\247\350\256\241\345\210\222\345\257\274\345\205\245\346\250\241\346\235\277.xlsx"
index 5e42a1b..9b48a50 100644
--- "a/public/import-templates/\350\264\250\351\207\217\347\233\221\346\216\247\350\256\241\345\210\222\345\257\274\345\205\245\346\250\241\346\235\277.xlsx"
+++ "b/public/import-templates/\350\264\250\351\207\217\347\233\221\346\216\247\350\256\241\345\210\222\345\257\274\345\205\245\346\250\241\346\235\277.xlsx"
Binary files differ
diff --git a/src/components/ImportDialog/index.vue b/src/components/ImportDialog/index.vue
index 51b5ede..cfb3c87 100644
--- a/src/components/ImportDialog/index.vue
+++ b/src/components/ImportDialog/index.vue
@@ -186,7 +186,8 @@
.template-tip {
display: flex;
align-items: center;
- gap: 6px;
+ flex-wrap: nowrap;
+ gap: 4px;
margin-bottom: 12px;
padding: 8px 12px;
border-radius: 4px;
@@ -195,6 +196,15 @@
font-size: 13px;
}
+.template-tip > span {
+ white-space: nowrap;
+}
+
+.template-tip .el-button {
+ flex-shrink: 0;
+ margin-left: 0;
+}
+
.upload-tips {
margin-top: 10px;
color: var(--el-text-color-secondary);
diff --git a/src/components/Table/lims-table.vue b/src/components/Table/lims-table.vue
index 70539e5..946cca8 100644
--- a/src/components/Table/lims-table.vue
+++ b/src/components/Table/lims-table.vue
@@ -231,7 +231,10 @@
}
function indexMethod(index) {
- return (props.page.current - 1) * props.page.size + index + 1
+ // 鏈紶 page 鏃堕粯璁� current 涓� 0锛屼細绠楀嚭 -9銆�-8 杩欑被璐熷簭鍙凤紱杩欓噷鍏滃簳涓虹涓�椤�
+ const current = props.page && props.page.current > 0 ? props.page.current : 1
+ const size = props.page && props.page.size > 0 ? props.page.size : 10
+ return (current - 1) * size + index + 1
}
function onPagination({ page, limit }) {
diff --git a/src/components/UpPdfStamp/index.vue b/src/components/UpPdfStamp/index.vue
index 0c6088e..fd92a4e 100644
--- a/src/components/UpPdfStamp/index.vue
+++ b/src/components/UpPdfStamp/index.vue
@@ -1,7 +1,10 @@
<template>
<div class="up-pdf-stamp">
<div v-if="isUpFile" class="work" style="display: flex;justify-content: space-between;align-items: center;margin-bottom: 10px;">
- <input ref="fileInput" type="file" accept="application/pdf" @change="handleFileUpload" />
+ <input ref="fileInput" type="file" accept=".pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.wps,.et,.dps,.txt,.jpg,.jpeg,.png" @change="handleFileUpload" />
+ <span v-if="fileName !== '鏂囦欢鍚�'" style="margin-left: 10px;font-size: 12px;color: var(--el-text-color-secondary);">
+ 宸查�夋嫨锛歿{ fileName }}<template v-if="!isPdfFile">锛堥潪 PDF 鏂囦欢鎸夊師鏂囦欢涓婁紶锛屼笉鏀寔鐩栫珷锛�</template>
+ </span>
</div>
<div v-if="canvasNumPages > 0" style="color: red;font-size: 12px;margin: 16px 0;">鎻愮ず锛氬湪鏂囦欢鑼冨洿鍐咃紝鍗曞嚮榧犳爣鐩栫珷锛屽弻鍑婚紶鏍囧凡鐩栧ソ绔犲鍙垹闄ゅ綋鍓嶇珷</div>
<canvas
@@ -35,7 +38,9 @@
stampHeight: 80, // 鐩栫珷楂樺害
stampsName: '',
stampsList: ['涓讳换', '璐ㄩ噺璐熻矗浜�', '鎶�鏈礋璐d汉'],
- fileName: '鏂囦欢鍚�'
+ fileName: '鏂囦欢鍚�',
+ selectedFile: null, // 闈� PDF 鏂囦欢锛氫繚鐣欏師濮� File锛岀洿鎺ヤ笂浼�
+ isPdfFile: false
}
},
methods: {
@@ -49,6 +54,9 @@
const file = event.target.files[0]
if (file.size > 20 * 1024 * 1024) {
this.$refs.fileInput.value = '' // 娓呯┖鏂囦欢杈撳叆妗嗗唴瀹�
+ this.selectedFile = null
+ this.isPdfFile = false
+ this.fileName = '鏂囦欢鍚�'
return this.$message.error('鏂囦欢澶у皬涓嶈兘瓒呰繃20M')
}
this.lookFile(file)
@@ -67,14 +75,25 @@
this.stampsName = '缁煎悎瀹�'
}
}
- if (file && file.type === 'application/pdf') {
+ this.isPdfFile = !!file && (file.type === 'application/pdf' || /\.pdf$/i.test(file.name || ''))
+ if (this.isPdfFile) {
+ this.selectedFile = file
const reader = new FileReader()
reader.onload = e => {
const typedArray = new Uint8Array(e.target.result)
this.loadPDF(typedArray)
}
reader.readAsArrayBuffer(file)
+ } else if (this.isUpFile) {
+ // 鏂囦欢娓呭崟涓婁紶鏀寔 Word/Excel/鍥剧墖绛夋牸寮忥紝涓嶅仛鐩栫珷锛岄�変腑鍚庢寜鍘熸枃浠朵笂浼�
+ this.selectedFile = file
+ this.pdfDoc = null
+ this.canvasNumPages = 0
+ this.stamps = []
+ this.contextList = []
} else {
+ // 鍏朵粬娴佺▼锛堟枃浠剁敵璇枫�佸彉鏇寸敵璇风瓑锛変粛鍙鐞� PDF
+ this.selectedFile = null
this.$message.error('璇烽�夋嫨 PDF 鏂囦欢')
}
},
@@ -167,8 +186,12 @@
},
// 鐢熸垚 PDF 鐨勫嚱鏁�
async generatePDF() {
+ // 闈� PDF锛氫笉鐩栫珷锛屽師鏂囦欢鐩存帴涓婁紶
+ if (this.selectedFile && !this.isPdfFile) {
+ return this.$emit('uploadPDF', this.selectedFile, this.fileName)
+ }
if (this.contextList.length === 0) {
- this.$message({ message: '璇峰厛涓婁紶PDF鏂囦欢', type: 'error' })
+ this.$message({ message: '璇峰厛閫夋嫨鏂囦欢', type: 'error' })
this.$emit('uploadPDFErr')
return false
}
diff --git a/src/views/CNAS/personnel/personnelInfo/components/AddInDetail.vue b/src/views/CNAS/personnel/personnelInfo/components/AddInDetail.vue
index de32220..1b2291b 100644
--- a/src/views/CNAS/personnel/personnelInfo/components/AddInDetail.vue
+++ b/src/views/CNAS/personnel/personnelInfo/components/AddInDetail.vue
@@ -33,12 +33,20 @@
</el-col>
<el-col :span="12">
<el-form-item label="鍩硅璁插笀:" prop="trainingLecturerId">
- <el-select v-model="trainingPlan.trainingLecturerId"
- clearable filterable
- placeholder="璇烽�夋嫨" size="small" style="width: 100%;">
- <el-option v-for="item in responsibleOptions" :key="item.id" :label="item.name" :value="item.id">
- </el-option>
- </el-select>
+ <div style="display: flex; align-items: center; gap: 8px; width: 100%;">
+ <el-radio-group v-model="lecturerType" size="small" @change="handleLecturerTypeChange">
+ <el-radio-button label="internal">鍐呴儴浜哄憳</el-radio-button>
+ <el-radio-button label="external">澶栬仒璁插笀</el-radio-button>
+ </el-radio-group>
+ <el-select v-if="lecturerType === 'internal'" v-model="trainingPlan.trainingLecturerId"
+ clearable filterable
+ placeholder="璇烽�夋嫨" size="small" style="flex: 1;">
+ <el-option v-for="item in responsibleOptions" :key="item.id" :label="item.name" :value="item.id">
+ </el-option>
+ </el-select>
+ <el-input v-else v-model="trainingPlan.trainingLecturerName" clearable
+ placeholder="璇疯緭鍏ュ鑱樿甯堝鍚�" size="small" style="flex: 1;"></el-input>
+ </div>
</el-form-item>
</el-col>
<el-col :span="12">
@@ -88,6 +96,7 @@
return {
addTrainingPlanDia: false,
submitAddLoading: false,
+ lecturerType: 'internal',
trainingPlan: {
planId: '',
id: '',
@@ -97,6 +106,7 @@
participants: '',
trainingContent: '',
trainingLecturerId: '',
+ trainingLecturerName: '',
trainingMode: '',
holdingDepartment: '',
remarks: '',
@@ -104,7 +114,6 @@
trainingPlanRules: {
trainingDate: [{ required: true, message: '璇烽�夋嫨鍩硅鏃ユ湡', trigger: 'change' }],
trainingContent: [{ required: true, message: '璇疯緭鍏ュ煿璁唴瀹�', trigger: 'blur' }],
- trainingLecturerId: [{ required: true, message: '璇烽�夋嫨鍩硅璁插笀', trigger: 'blur' }],
},
responsibleOptions: [],
operationType: ''
@@ -117,7 +126,9 @@
this.operationType = type
if (this.operationType === 'edit') {
this.trainingPlan = this.HaveJson(row)
+ this.lecturerType = row.trainingLecturerId ? 'internal' : (row.trainingLecturerName ? 'external' : 'internal')
} else {
+ this.lecturerType = 'internal'
this.trainingPlan = {
id: '',
trainingDate: '',
@@ -134,10 +145,32 @@
this.trainingPlan.planId = id
this.getUserList()
},
+ handleLecturerTypeChange(type) {
+ if (type === 'internal') {
+ this.trainingPlan.trainingLecturerName = ''
+ } else {
+ this.trainingPlan.trainingLecturerId = null
+ }
+ },
// 鎻愪氦鏂板
submitAdd() {
this.$refs.trainingPlanForm.validate((valid) => {
if (valid) {
+ if (this.lecturerType === 'internal' && !this.trainingPlan.trainingLecturerId) {
+ this.$message.warning('璇烽�夋嫨鍩硅璁插笀')
+ return
+ }
+ if (this.lecturerType === 'external') {
+ const lecturerName = (this.trainingPlan.trainingLecturerName || '').trim()
+ if (!lecturerName) {
+ this.$message.warning('璇疯緭鍏ュ鑱樿甯堝鍚�')
+ return
+ }
+ this.trainingPlan.trainingLecturerId = null
+ this.trainingPlan.trainingLecturerName = lecturerName
+ } else {
+ this.trainingPlan.trainingLecturerName = null
+ }
this.submitAddLoading = true
this.trainingPlan.planId = this.currentChangeRow.id
const personTrainingDetailed = this.trainingPlan
diff --git a/src/views/CNAS/personnel/personnelInfo/components/Edit.vue b/src/views/CNAS/personnel/personnelInfo/components/Edit.vue
index 1dc611e..95d521d 100644
--- a/src/views/CNAS/personnel/personnelInfo/components/Edit.vue
+++ b/src/views/CNAS/personnel/personnelInfo/components/Edit.vue
@@ -10,40 +10,44 @@
</div>
<div class="form_title">
<el-row>
- <el-col :span="7">
+ <el-col :span="8">
<span class="form_label">鍩硅鍐呭锛�</span>
<span> {{ trainingForm.trainingContent }} </span>
</el-col>
- <el-col :span="5">
+ <el-col :span="4">
<span class="form_label">鐘舵�侊細</span>
<el-tag v-if="trainingForm.state === 1" type="success">宸插畬鎴�</el-tag>
<el-tag v-if="trainingForm.state === 2" type="warning">寰呰瘎浠�</el-tag>
<el-tag v-if="trainingForm.state === 3" type="primary">鏈紑濮�</el-tag>
</el-col>
- <el-col :span="4">
+ <el-col :span="5">
<span class="form_label">鍩硅璁插笀锛�</span>
<span> {{ trainingForm.trainingLecturerName }} </span>
</el-col>
+ <el-col :span="7">
+ <span class="form_label">鍩硅鏃ユ湡锛�</span>
+ <span> {{ trainingForm.trainingDate || '-' }} </span>
+ </el-col>
</el-row>
<el-row style="margin: 15px 0">
- <el-form>
+ <el-form label-width="130px">
<el-row>
<el-col :span="6">
- <el-form-item label="鍩硅鏃ユ湡:">
+ <el-form-item label="寮�濮嬫椂闂�:">
<el-date-picker v-model="trainingForm.openingTime" format="YYYY-MM-DD" :disabled="currentRow.state !== 3"
- placeholder="閫夋嫨鏃ユ湡" size="small" value-format="YYYY-MM-DD"
- type="date" style="width: 60%"></el-date-picker>
+ placeholder="閫夋嫨瀹為檯寮�濮嬫棩鏈�" size="small" value-format="YYYY-MM-DD"
+ type="date" style="width: 100%"></el-date-picker>
</el-form-item>
</el-col>
- <el-col :span="7">
+ <el-col :span="9">
<el-form-item label="鍩硅鍦扮偣">
<el-input v-model="trainingForm.placeTraining" :disabled="currentRow.state !== 3" :rows="2" placeholder="璇疯緭鍏�"
- size="small" style="width: 60%" type="text"></el-input>
+ size="small" style="width: 100%" type="text"></el-input>
</el-form-item>
</el-col>
- <el-col :span="6">
+ <el-col :span="9">
<el-form-item label="璇勪环浜�">
- <el-select v-model="trainingForm.assessmentUserId" :disabled="currentRow.state !== 3" placeholder="璇烽�夋嫨" size="small" style="width: 50%">
+ <el-select v-model="trainingForm.assessmentUserId" :disabled="currentRow.state !== 3" placeholder="璇烽�夋嫨" size="small" style="width: 100%">
<el-option v-for="item in userList" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
@@ -51,7 +55,7 @@
<el-col :span="12">
<el-form-item label="鑰冩牳鏂瑰紡">
<el-input v-model="trainingForm.assessmentMethod" :disabled="currentRow.state !== 3" :rows="2" placeholder="璇疯緭鍏�"
- size="small" style="width: 79%" type="textarea"></el-input>
+ size="small" style="width: 100%" type="textarea"></el-input>
</el-form-item>
</el-col>
</el-row>
@@ -60,14 +64,14 @@
<el-form-item label="璇勪环鏃堕棿">
<el-date-picker v-model="trainingForm.assessmentDate" :disabled="currentRow.state !== 2 || isDisabled"
type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD" size="small"
- placeholder="閫夋嫨鏃ユ湡">
+ placeholder="閫夋嫨鏃ユ湡" style="width: 100%">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="鏈鍩硅缁煎悎璇勪环">
<el-input v-model="trainingForm.comprehensiveAssessment" :disabled="currentRow.state !== 2 || isDisabled" :rows="2" placeholder="璇疯緭鍏�"
- size="small" style="width: 68%" type="textarea"></el-input>
+ size="small" style="width: 100%" type="textarea"></el-input>
</el-form-item>
</el-col>
</el-row>
@@ -76,15 +80,17 @@
</div>
<el-divider>浜哄憳璇︽儏</el-divider>
<div>
- <div class="items_center">
- <span>濮撳悕</span>
- <el-input v-model="userName" class="search" placeholder="璇疯緭鍏�"
- size="small"></el-input>
- <el-button size="small" type="primary" @click="getInfo">鏌ヨ</el-button>
- </div>
- <div class="items_btn">
- <el-button :disabled="currentRow.state === 1" size="small" type="primary" @click="addPerson">鏂板浜哄憳</el-button>
- <el-button :disabled="currentRow.state === 1" size="small" @click="batchDelete">鎵归噺鍒犻櫎</el-button>
+ <div class="items_header">
+ <div class="items_center">
+ <span>濮撳悕</span>
+ <el-input v-model="userName" class="person-search-input" placeholder="璇疯緭鍏�"
+ size="small" clearable @keyup.enter="getInfo"></el-input>
+ <el-button size="small" type="primary" @click="getInfo">鏌ヨ</el-button>
+ </div>
+ <div class="items_btn">
+ <el-button :disabled="currentRow.state === 1" size="small" type="primary" @click="addPerson">鏂板浜哄憳</el-button>
+ <el-button :disabled="currentRow.state === 1" size="small" @click="batchDelete">鎵归噺鍒犻櫎</el-button>
+ </div>
</div>
<el-table :data="trainingTableData" height="calc(100vh - 30em)" stripe style="width: 100%"
border
@@ -117,7 +123,7 @@
</el-form>
</div>
<div v-if="selectUserDia" class="body" style="height: 60vh;">
- <lims-table :tableData="tableData1" :column="column1"
+ <lims-table :tableData="tableData1" :column="column1" :page="page1"
:isSelection="true" :handleSelectionChange="selectMethod"
height="500" :tableLoading="tableLoading1"></lims-table>
</div>
@@ -402,15 +408,27 @@
}
+.items_header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 10px;
+}
.items_center {
- float: left;
- width: 50%;
- text-align: left;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+.items_center > span {
+ line-height: 24px;
+ white-space: nowrap;
+}
+.items_center .person-search-input {
+ width: 200px;
}
.items_btn {
- text-align: right;
- width: 50%;
- float: right;
- margin-bottom: 1em;
+ display: flex;
+ align-items: center;
+ gap: 8px;
}
</style>
diff --git a/src/views/CNAS/personnel/personnelInfo/tabs/personnelTraining.vue b/src/views/CNAS/personnel/personnelInfo/tabs/personnelTraining.vue
index 71c311b..5d58279 100644
--- a/src/views/CNAS/personnel/personnelInfo/tabs/personnelTraining.vue
+++ b/src/views/CNAS/personnel/personnelInfo/tabs/personnelTraining.vue
@@ -95,9 +95,9 @@
</el-option>
</el-select>
</div>
- <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 style="display: flex; align-items: center; flex-wrap: nowrap; gap: 4px; margin-bottom: 10px; padding: 8px 12px; border-radius: 4px; background: var(--el-color-primary-light-9); font-size: 13px;">
+ <span style="white-space: nowrap;">绗竴娆″鍏ヨ鍏堜笅杞芥ā鏉匡紝鎸夋ā鏉挎牸寮忓~鍐欏悗鍐嶄笂浼犮��</span>
+ <el-button link type="primary" style="flex-shrink: 0; margin-left: 0;" @click="downloadTemplate">涓嬭浇瀵煎叆妯℃澘</el-button>
</div>
<div style="margin: 0 auto;">
<el-upload ref="upload"
@@ -110,7 +110,7 @@
</div>
<div style="margin-top: 10px; color: var(--el-text-color-secondary); font-size: 12px; line-height: 20px;">
<div>鏀寔鏍煎紡锛�.xls銆�.xlsx锛涘崟涓枃浠朵笉瓒呰繃10MB銆�</div>
- <div>鍩硅璁插笀蹇呴』濉啓绯荤粺涓凡瀛樺湪鐨勪汉鍛樺鍚嶏紝鍚﹀垯鏁存壒瀵煎叆澶辫触銆�</div>
+ <div>鍩硅璁插笀濉啓绯荤粺鍐呬汉鍛樺鍚嶆椂鑷姩鍏宠仈锛涘鑱樿甯堢洿鎺ュ~鍐欏鍚嶏紝鎸夋枃鏈繚瀛樸��</div>
<div>鍩硅鏃堕棿寤鸿濉啓 YYYY-MM-DD锛岃鏃跺~鍐欐暣鏁般��</div>
<div>瀵煎叆鍙鍙栨ā鏉跨殑绗竴涓伐浣滆〃銆�</div>
</div>
@@ -325,23 +325,23 @@
{
label: '鍩硅澶х被',
prop: 'trainingCategory',
- width: '100px',
+ minWidth: '100px',
},{
label: '鍩硅鐩爣',
prop: 'trainingObjectives',
- width: '100px',
+ minWidth: '100px',
}, {
label: '鍩硅鍐呭',
prop: 'trainingContent',
- width: '100px',
+ minWidth: '100px',
}, {
label: '鍩硅鏂瑰紡',
prop: 'trainingMode',
- width: '100px',
+ minWidth: '100px',
}, {
dataType: 'tag',
label: '璇剧▼鐘舵��',
- width: '100px',
+ minWidth: '100px',
prop: 'state',
formatData: (params) => {
if (params == 1) {
@@ -370,34 +370,34 @@
}, {
label: '鍙傚姞瀵硅薄',
prop: 'participants',
- width: '100px',
+ minWidth: '100px',
}, {
label: '涓惧姙閮ㄩ棬',
prop: 'holdingDepartment',
- width: '100px',
+ minWidth: '100px',
}, {
label: '鍩硅璁插笀',
prop: 'trainingLecturerName',
- width: '100px',
+ minWidth: '100px',
}, {
label: '鍩硅鏃ユ湡',
prop: 'trainingDate',
- width: '100px',
+ minWidth: '100px',
}, {
label: '寮�濮嬫椂闂�',
prop: 'openingTime',
- width: '100px',
+ minWidth: '100px',
}, {
label: '璇炬椂',
prop: 'classHour',
- width: '100px',
+ minWidth: '100px',
}, {
label: '澶囨敞',
prop: 'remarks',
- width: '100px',
+ minWidth: '100px',
}, {
dataType: 'action',
- width: '200',
+ minWidth: '200px',
label: '鎿嶄綔',
fixed: 'right',
operation: [
@@ -645,7 +645,7 @@
// 涓嬭浇骞村害璁″垝瀵煎叆妯℃澘
downloadTemplate() {
const link = document.createElement('a')
- link.href = '/import-templates/浜哄憳鍩硅骞村害璁″垝瀵煎叆妯℃澘.xlsx?v=2'
+ link.href = '/import-templates/浜哄憳鍩硅骞村害璁″垝瀵煎叆妯℃澘.xlsx?v=3'
link.download = '浜哄憳鍩硅骞村害璁″垝瀵煎叆妯℃澘.xlsx'
document.body.appendChild(link)
link.click()
diff --git a/src/views/CNAS/process/ensureResults/ensureResultsValidity/components/detailFormDialog.vue b/src/views/CNAS/process/ensureResults/ensureResultsValidity/components/detailFormDialog.vue
index 88318c1..073dca1 100644
--- a/src/views/CNAS/process/ensureResults/ensureResultsValidity/components/detailFormDialog.vue
+++ b/src/views/CNAS/process/ensureResults/ensureResultsValidity/components/detailFormDialog.vue
@@ -21,8 +21,11 @@
</el-form-item>
</el-col>
<el-col :span="12">
- <el-form-item label="璐ㄦ帶鏂瑰紡" prop="monitorWay">
- <el-input v-model="form.monitorWay" size="small" clearable placeholder="濡傜洸鏍锋娴嬨�佷汉鍛樻瘮瀵广�佺洃鐫f鏌�" />
+ <el-form-item label="璐ㄦ帶鏂瑰紡" prop="monitorWayList">
+ <el-select v-model="form.monitorWayList" multiple filterable allow-create default-first-option
+ size="small" style="width: 100%" placeholder="鍙閫夛紝涔熷彲杈撳叆鍏朵粬鏂瑰紡">
+ <el-option v-for="item in monitorWayOptions" :key="item" :label="item" :value="item" />
+ </el-select>
</el-form-item>
</el-col>
<el-col :span="12">
@@ -103,6 +106,11 @@
// 杩欓噷瀛樻斁鏁版嵁
return {
formDia: false,
+ // LMSY-CX30-2024銆婅川閲忔帶鍒剁▼搴忋��4.1 瑙勫畾鐨勫父鐢ㄨ川閲忔帶鍒舵墜娈碉紝鍙閫�
+ monitorWayOptions: [
+ '浜哄憳姣斿', '璁惧姣斿', '鏂规硶姣斿', '鐩叉牱妫�娴�',
+ '鐣欐牱鍐嶆祴', '鏍囧噯鐗╄川鐩戞帶', '瀹為獙瀹ら棿姣斿', '鑳藉姏楠岃瘉',
+ ],
form: {
qualityMonitorDetailsId: '',
sortNo: null,
@@ -116,6 +124,7 @@
budget: '',
organization: '',
monitorWay: '',
+ monitorWayList: [],
itemKind: 'OTHER',
standardMethodId: null,
templateId: null,
@@ -134,7 +143,7 @@
rules: {
monitorProject: [{ required: true, message: '璇疯緭鍏ヨ川鎺ч」鐩�', trigger: 'blur' }],
technicalStandardText: [{ required: true, message: '璇疯緭鍏ユ妧鏈爣鍑�', trigger: 'blur' }],
- monitorWay: [{ required: true, message: '璇疯緭鍏ヨ川鎺ф柟寮�', trigger: 'blur' }],
+ monitorWayList: [{ required: true, type: 'array', min: 1, message: '璇烽�夋嫨璐ㄦ帶鏂瑰紡', trigger: 'change' }],
completionMonth: [{ required: true, message: '璇烽�夋嫨瀹屾垚鏃堕檺', trigger: 'change' }],
responsibleUserId: [{ required: true, message: '璇烽�夋嫨璐熻矗浜�', trigger: 'change' }],
templateIds: [{ required: true, type: 'array', min: 1, message: '璇疯嚦灏戦�夋嫨涓�涓師濮嬭褰曟ā鏉�', trigger: 'change' }],
@@ -148,6 +157,7 @@
openDia(type, row) {
this.formDia = true
this.operationType = type
+ this.form.monitorWayList = []
this.templateOptions = []
this.allTemplateOptions = []
this.templateBindingLoading = false
@@ -165,7 +175,12 @@
const templateIds = row.templateIds
? String(row.templateIds).split(',').filter(Boolean).map(id => Number(id))
: (row.templateId ? [Number(row.templateId)] : [])
- this.form = {...row, itemKind: row.itemKind || 'OTHER', templateIds}
+ this.form = {
+ ...row,
+ itemKind: row.itemKind || 'OTHER',
+ templateIds,
+ monitorWayList: row.monitorWay ? String(row.monitorWay).split(/[銆�,锛�;锛沒/).map(item => item.trim()).filter(Boolean) : [],
+ }
},
handleStandardChange(id) {
const standard = this.standardOptions.find(item => Number(item.id) === Number(id))
@@ -211,6 +226,8 @@
: []
entity.templateIds = templateIds.join(',') || null
entity.templateId = templateIds.length ? templateIds[0] : null
+ entity.monitorWay = (this.form.monitorWayList || []).map(item => item.trim()).filter(Boolean).join('銆�')
+ delete entity.monitorWayList
entity.reviewerUserId = null
return entity
},
diff --git a/src/views/CNAS/process/ensureResults/ensureResultsValidity/components/evaluateDialog.vue b/src/views/CNAS/process/ensureResults/ensureResultsValidity/components/evaluateDialog.vue
index 40d28e6..1571068 100644
--- a/src/views/CNAS/process/ensureResults/ensureResultsValidity/components/evaluateDialog.vue
+++ b/src/views/CNAS/process/ensureResults/ensureResultsValidity/components/evaluateDialog.vue
@@ -2,8 +2,10 @@
<div>
<el-dialog :close-on-click-modal="false" :close-on-press-escape="false"
v-model="formDia"
- title="璐ㄩ噺鐩戞帶璇勪环"
+ title="璐ㄩ噺鎺у埗璇勪环璁板綍"
width="60%" @close="closeEvaDia">
+ <el-alert type="info" :closable="false" show-icon style="margin-bottom: 12px"
+ title="妫�娴嬪涓讳换缁勭粐璇勪环骞跺~鍐欐湰璁板綍锛屾妧鏈礋璐d汉瀹℃牳锛涜瘎瀹$粨璁哄闇�閲囧彇鎺柦锛屾寜銆婄籂姝f帾鏂界▼搴忋�嬫墽琛屽苟鐣欏瓨璁板綍銆�" />
<el-steps :active="currentStep" align-center finish-status="success">
<el-step title="鐩戞帶璁″垝瀹炴柦鎯呭喌" @click="setStep(0)"></el-step>
<el-step title="鐩戞帶缁撴灉璇勪环" @click="setStep(1)"></el-step>
diff --git a/src/views/CNAS/process/ensureResults/ensureResultsValidity/index.vue b/src/views/CNAS/process/ensureResults/ensureResultsValidity/index.vue
index f6346ed..e6288e8 100644
--- a/src/views/CNAS/process/ensureResults/ensureResultsValidity/index.vue
+++ b/src/views/CNAS/process/ensureResults/ensureResultsValidity/index.vue
@@ -227,9 +227,9 @@
</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 style="display: flex; align-items: center; flex-wrap: nowrap; gap: 4px; margin-bottom: 10px; padding: 8px 12px; border-radius: 4px; background: var(--el-color-primary-light-9); font-size: 13px;">
+ <span style="white-space: nowrap;">绗竴娆″鍏ヨ鍏堜笅杞芥ā鏉匡紝鎸夋ā鏉挎牸寮忓~鍐欏悗鍐嶄笂浼犮��</span>
+ <el-button link type="primary" style="flex-shrink: 0; margin-left: 0;" @click="downloadTemplate">涓嬭浇瀵煎叆妯℃澘</el-button>
</div>
<div style="margin: 0 auto;">
<el-upload ref="upload" :action="action" :auto-upload="false" v-model:file-list="fileList" :headers="uploadHeader"
@@ -594,7 +594,7 @@
downloadTemplate() {
const link = document.createElement('a')
// 甯︾増鏈弬鏁伴伩鍏嶆祻瑙堝櫒缁х画浣跨敤缂撳瓨閲岀殑鏃фā鏉�
- link.href = '/import-templates/璐ㄩ噺鐩戞帶璁″垝瀵煎叆妯℃澘.xlsx?v=2'
+ link.href = '/import-templates/璐ㄩ噺鐩戞帶璁″垝瀵煎叆妯℃澘.xlsx?v=3'
link.download = '璐ㄩ噺鐩戞帶璁″垝瀵煎叆妯℃澘.xlsx'
document.body.appendChild(link)
link.click()
@@ -956,7 +956,7 @@
exportQualityMonitorRatify({ qualityMonitorDetailsId: this.download.qualityMonitorDetailsId }).then(res => {
this.outLoading = false
const blob = new Blob([res], { type: 'application/msword' });
- this.$download.saveAs(blob, '璐ㄩ噺鐩戞帶瀹炴柦璁″垝.docx')
+ this.$download.saveAs(blob, '璐ㄩ噺鎺у埗鎺柦.docx')
})
},
// 瀹屾垚鎶ュ憡瀵煎嚭
@@ -973,7 +973,7 @@
exportQualityMonitorEvaluate({ qualityMonitorDetailsId: this.download.qualityMonitorDetailsId }).then(res => {
this.outLoading = false
const blob = new Blob([res], { type: 'application/msword' });
- this.$download.saveAs(blob, '璐ㄩ噺鐩戞帶璇勪环.docx')
+ this.$download.saveAs(blob, '璐ㄩ噺鎺у埗璇勪环璁板綍.docx')
})
},
delYearPlanDetail(row) {
diff --git a/src/views/CNAS/process/ensureResults/qualityControlPlan/index.vue b/src/views/CNAS/process/ensureResults/qualityControlPlan/index.vue
index fe29f64..730ad01 100644
--- a/src/views/CNAS/process/ensureResults/qualityControlPlan/index.vue
+++ b/src/views/CNAS/process/ensureResults/qualityControlPlan/index.vue
@@ -131,9 +131,9 @@
</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 style="display: flex; align-items: center; flex-wrap: nowrap; gap: 4px; margin-bottom: 10px; padding: 8px 12px; border-radius: 4px; background: var(--el-color-primary-light-9); font-size: 13px;">
+ <span style="white-space: nowrap;">绗竴娆″鍏ヨ鍏堜笅杞芥ā鏉匡紝鎸夋ā鏉挎牸寮忓~鍐欏悗鍐嶄笂浼犮��</span>
+ <el-button link type="primary" style="flex-shrink: 0; margin-left: 0;" @click="downloadTemplate">涓嬭浇瀵煎叆妯℃澘</el-button>
</div>
<div style="margin: 0 auto;">
<el-upload ref="upload1" :action="action" :auto-upload="false" :file-list="fileList" :headers="uploadHeader"
diff --git a/src/views/CNAS/systemManagement/documentControl/components/ControlledFileApplication.vue b/src/views/CNAS/systemManagement/documentControl/components/ControlledFileApplication.vue
index dae8fc0..9f02bb5 100644
--- a/src/views/CNAS/systemManagement/documentControl/components/ControlledFileApplication.vue
+++ b/src/views/CNAS/systemManagement/documentControl/components/ControlledFileApplication.vue
@@ -71,7 +71,7 @@
<div class="search_thing">
<div class="search_label">涓婁紶闄勪欢锛�</div>
<div class="search_input"><el-upload style="margin: 8px 0 0px 50px;" action="#" :auto-upload="false"
- :multiple="false" accept='.pdf' :on-change="handleChangeUpload" v-if="addDialogVisible">
+ :multiple="false" accept='.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.wps,.et,.dps,.txt,.jpg,.jpeg,.png' :on-change="handleChangeUpload" v-if="addDialogVisible">
<el-button size="small" type="primary">涓婁紶闄勪欢</el-button>
</el-upload></div>
</div>
@@ -437,21 +437,30 @@
handleCheck0(row) {
this.checkStampDialogVisible = false
this.checkDialogVisible = true
- checkManageDocumentControlledPdf({ id: row.id }).then(res => {
- const blob = new Blob([res]);
+ checkManageDocumentControlledPdf({ id: row.id }).then(async res => {
+ // 鍚庣杞� PDF 澶辫触鏃朵細杩斿洖 JSON 閿欒锛宐lob 閲屽氨涓嶆槸 PDF
+ if (res.type && res.type.includes('json')) {
+ const data = JSON.parse(await res.text())
+ this.$message.error(data.msg || '闄勪欢杞崲棰勮澶辫触')
+ this.checkDialogVisible = false
+ return
+ }
+ const blob = new Blob([res], { type: 'application/pdf' });
const file = new File([blob], row.name, { type: 'application/pdf' })
this.$refs.UpPdfStamp.lookFile(file, this.currentStamp)
}).catch(err => {
+ this.checkDialogVisible = false
console.log(err)
})
},
handleDown(row) {
if (!row.url) return this.$message.warning('鏂囦欢鏈笂浼�')
- this.$download.saveAs(row.url, row.url);
+ const fileName = row.url.replace(/^[0-9a-fA-F-]{36}_/, '')
+ this.$download.saveAs(this.javaApi + '/word/' + row.url, fileName);
},
async uploadPDF(pdfBlob) {
const formData = new FormData();
- formData.append('file', pdfBlob, this.fileName + '.pdf'); // 鏂囦欢瀛楁
+ formData.append('file', pdfBlob, (this.currentInfo.name || 'controlled') + '.pdf'); // 鏂囦欢瀛楁
formData.append('id', this.currentInfo.id); // 鏂囦欢鍚嶅瓧娈�
formData.append('state', this.type); // 鏂囦欢鍚嶅瓧娈�
formData.append('writer', this.currentInfo.writer); // 鏂囦欢鍚嶅瓧娈�
diff --git a/src/views/CNAS/systemManagement/documentControl/components/DistributionCollectionRecord.vue b/src/views/CNAS/systemManagement/documentControl/components/DistributionCollectionRecord.vue
index cbff184..9e0ec33 100644
--- a/src/views/CNAS/systemManagement/documentControl/components/DistributionCollectionRecord.vue
+++ b/src/views/CNAS/systemManagement/documentControl/components/DistributionCollectionRecord.vue
@@ -154,7 +154,7 @@
<div class="search_thing">
<div class="search_label">涓婁紶闄勪欢锛�</div>
<div class="search_input"><el-upload :auto-upload="false" :multiple="false" :on-change="handleChangeUpload"
- accept='.pdf,.doc,.docx,.xls,.xlsx' action="#" style="margin: 8px 0 0px 50px;">
+ accept='.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.wps,.et,.dps,.txt,.jpg,.jpeg,.png' action="#" style="margin: 8px 0 0px 50px;">
<el-button size="small" type="primary">涓婁紶闄勪欢</el-button>
</el-upload></div>
</div>
diff --git a/src/views/CNAS/systemManagement/documentControl/components/FileChangeRequest.vue b/src/views/CNAS/systemManagement/documentControl/components/FileChangeRequest.vue
index fcf241d..d65c19d 100644
--- a/src/views/CNAS/systemManagement/documentControl/components/FileChangeRequest.vue
+++ b/src/views/CNAS/systemManagement/documentControl/components/FileChangeRequest.vue
@@ -184,7 +184,7 @@
<div class="search_thing" style="width: 100%;">
<div class="search_label">鐩稿叧闄勪欢锛�</div>
<div class="search_input"><el-upload v-if="addDialogVisible" :auto-upload="false" :multiple="false"
- :on-change="handleChangeUpload" accept='.pdf' action="#" style="margin: 8px 0 0px 50px;">
+ :on-change="handleChangeUpload" accept='.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.wps,.et,.dps,.txt,.jpg,.jpeg,.png' action="#" style="margin: 8px 0 0px 50px;">
<el-button size="small" type="primary">涓婁紶闄勪欢</el-button>
</el-upload></div>
</div>
@@ -536,15 +536,23 @@
this.getCurrentFile(alterBeforeCode)
this.addDialogVisible = true
this.diaLoading = true
- checkManageDocumentAlterPdf({ id: row.id }).then(res => {
+ checkManageDocumentAlterPdf({ id: row.id }).then(async res => {
//
this.diaLoading = false
- const blob = new Blob([res]);
+ // 鍚庣杞� PDF 澶辫触鏃朵細杩斿洖 JSON 閿欒锛宐lob 閲屽氨涓嶆槸 PDF
+ if (res.type && res.type.includes('json')) {
+ const data = JSON.parse(await res.text())
+ this.$message.error(data.msg || '闄勪欢杞崲棰勮澶辫触')
+ this.addDialogVisible = false
+ return
+ }
+ const blob = new Blob([res], { type: 'application/pdf' });
const file = new File([blob], row.name, { type: 'application/pdf' })
this.$refs.UpPdfStamp.lookFile(file)
this.currentInfo = row
}).catch(err => {
this.diaLoading = false
+ this.addDialogVisible = false
console.log(err)
})
},
diff --git a/src/views/CNAS/systemManagement/documentControl/components/FileList.vue b/src/views/CNAS/systemManagement/documentControl/components/FileList.vue
index 256bc60..96cea97 100644
--- a/src/views/CNAS/systemManagement/documentControl/components/FileList.vue
+++ b/src/views/CNAS/systemManagement/documentControl/components/FileList.vue
@@ -29,6 +29,9 @@
:height="'calc(100vh - 290px)'" @pagination="pagination"></lims-table>
</div>
<el-dialog title="涓婁紶" v-model="addDialogVisible" width="1000px" top="3vh">
+ <div style="margin-bottom: 10px; padding: 8px 12px; border-radius: 4px; background: var(--el-color-primary-light-9); font-size: 13px; color: var(--el-text-color-regular);">
+ 鏀寔 PDF銆乄ord锛�.doc/.docx锛夈�丒xcel锛�.xls/.xlsx锛夈�丳PT銆佸浘鐗囩瓑甯歌鏍煎紡锛屽崟涓枃浠朵笉瓒呰繃 20MB銆侾DF 鍙瑙堝苟鐩栫珷锛涘叾浠栨牸寮忔寜鍘熸枃浠朵笂浼狅紝涓嶇洊绔犮��
+ </div>
<UpPdfStamp ref="UpPdfStamp" v-if="addDialogVisible" @uploadPDF="uploadPDF" :isUpFile="true"
@uploadPDFErr="uploadPDFErr"></UpPdfStamp>
<template #footer><span class="dialog-footer">
@@ -277,7 +280,9 @@
// 涓嬭浇鏂囦欢
handleDown(row) {
if (!row.url) return this.$message.warning('鏂囦欢鏈笂浼�')
- this.$download.saveAs(row.url, row.url);
+ // 鍚庣淇濆瓨鐨勬槸 word 鐩綍涓嬬殑 uuid_鍘熸枃浠跺悕锛屼笅杞芥椂璧伴潤鎬佽祫婧愬湴鍧�骞跺幓鎺� uuid 鍓嶇紑
+ const fileName = row.url.replace(/^[0-9a-fA-F-]{36}_/, '')
+ this.$download.saveAs(this.javaApi + '/word/' + row.url, fileName);
},
// 鏌ョ湅鏂囦欢
handleLook(row) {
--
Gitblit v1.9.3