Browse Source

工序另存为模版

master
han\hanst 1 month ago
parent
commit
a7c91d83e0
  1. 20
      src/api/erf/erf.js
  2. 32
      src/components/ApprovalNotificationManager.vue
  3. 417
      src/views/modules/erf/components/expTriConfirm.vue
  4. 1
      src/views/modules/erf/expApplyApproval.vue
  5. 31
      src/views/modules/erf/expApplyList.vue
  6. 1
      src/views/modules/erf/plannerSchedule.vue

20
src/api/erf/erf.js

@ -111,3 +111,23 @@ export const deleteTriConfirmProcess = data => createAPI(`/erf/triConfirm/delete
* 批量更新工序顺序用于拖拽排序
*/
export const updateProcessSequence = data => createAPI(`/erf/triConfirm/updateProcessSequence`, 'post', data)
/**
* 查询工序模版列表
*/
export const getProcessTemplateList = data => createAPI(`/erf/triConfirm/getProcessTemplateList`, 'post', data)
/**
* 保存工序模版
*/
export const saveProcessTemplate = data => createAPI(`/erf/triConfirm/saveProcessTemplate`, 'post', data)
/**
* 删除工序模版
*/
export const deleteProcessTemplate = data => createAPI(`/erf/triConfirm/deleteProcessTemplate`, 'post', data)
/**
* 根据角色查询负责人列表
*/
export const getUserListByRole = data => createAPI(`/erf/triConfirm/getUserListByRole`, 'post', data)

32
src/components/ApprovalNotificationManager.vue

@ -72,13 +72,13 @@ export default {
*/
isLoggedIn(newVal, oldVal) {
console.log(`[审批通知] 登录状态变化: ${oldVal} -> ${newVal}, 已初始化: ${this.isInitialized}`)
//
if (oldVal === newVal) {
console.log('[审批通知] 登录状态未变化,跳过')
return
}
if (newVal && !this.isInitialized) {
console.log('[审批通知] 用户已登录(watch触发),初始化通知系统')
// mounted
@ -124,14 +124,14 @@ export default {
}
console.log('[审批通知] 开始初始化通知系统...')
//
this.isInitialized = true
//
this.stopPolling()
this.closeAllNotifications()
//
if (this.firstCheckTimeout) {
clearTimeout(this.firstCheckTimeout)
@ -148,7 +148,7 @@ export default {
//
this.startPolling()
console.log('[审批通知] 通知系统初始化完成')
},
@ -157,13 +157,13 @@ export default {
*/
stopNotificationSystem() {
console.log('[审批通知] 停止通知系统...')
//
this.closeAllNotifications()
//
this.stopPolling()
//
if (this.firstCheckTimeout) {
clearTimeout(this.firstCheckTimeout)
@ -178,13 +178,13 @@ export default {
console.log('[审批通知] 通知系统已停止')
},
/**
* 关闭所有活动的通知窗口
*/
closeAllNotifications() {
console.log(`[审批通知] 关闭所有通知窗口,当前数量: ${this.activeNotifications.length}`)
//
this.activeNotifications.forEach(notification => {
try {
@ -195,11 +195,11 @@ export default {
console.error('[审批通知] 关闭通知失败:', error)
}
})
//
this.activeNotifications = []
},
/**
* 从活动列表中移除指定的通知实例
* @param {Object} notification - 要移除的通知实例
@ -264,6 +264,8 @@ export default {
site: this.currentSite,
currentUserId: this.currentUserId,
userName: this.currentUserName,
pageType : 'MANAGER', //
pendingStatus: '已下达', //
page :1,
limit :20
}
@ -336,7 +338,7 @@ export default {
this.removeNotification(notificationInstance)
}
})
//
this.activeNotifications.push(notificationInstance)
console.log(`[审批通知] 已创建汇总通知,当前活动通知数: ${this.activeNotifications.length}`)
@ -431,7 +433,7 @@ export default {
this.removeNotification(notificationInstance)
}
})
//
this.activeNotifications.push(notificationInstance)
console.log(`[审批通知] 已创建单个通知 (${applyNo}),当前活动通知数: ${this.activeNotifications.length}`)

417
src/views/modules/erf/components/expTriConfirm.vue

@ -156,32 +156,61 @@
ref="processForm"
label-width="100px">
<el-form-item label="工序" required>
<el-form-item required>
<template #label>
<span slot="label" style="" class="big-label">
<a href="#" @click="openTemplateDialog()">工序</a>
</span>
</template>
<el-input
v-model="processForm.processStep"
:readonly="isEditMode"
placeholder="请输入工序名称">
placeholder="请输入工序名称或点击标题选择模版">
<el-button
slot="append"
type="success"
@click="saveAsTemplate">
另存为
</el-button>
</el-input>
</el-form-item>
<el-form-item label="车间负责人">
<el-form-item required>
<template #label>
<span slot="label" style="" class="big-label">
<a href="#" @click="openUserDialog('PROD')">车间负责人</a>
</span>
</template>
<el-input
v-model="processForm.prodApproverName"
placeholder="请输入车间负责人">
readonly
placeholder="请选择车间负责人">
</el-input>
</el-form-item>
<el-form-item label="质量负责人">
<el-form-item required>
<template #label>
<span slot="label" style="" class="big-label">
<a href="#" @click="openUserDialog('QA')">质量负责人</a>
</span>
</template>
<el-input
v-model="processForm.qaApproverName"
placeholder="请输入质量负责人">
readonly
placeholder="请选择质量负责人">
</el-input>
</el-form-item>
<el-form-item label="技术负责人">
<el-form-item required>
<template #label>
<span slot="label" style="" class="big-label">
<a href="#" @click="openUserDialog('TECH')">技术负责人</a>
</span>
</template>
<el-input
v-model="processForm.techApproverName"
placeholder="请输入技术负责人">
readonly
placeholder="请选择技术负责人">
</el-input>
</el-form-item>
@ -206,6 +235,111 @@
</div>
</el-dialog>
<!-- 工序模版选择弹框 -->
<el-dialog
title="选择工序模版"
:visible.sync="templateDialogVisible"
width="600px"
:close-on-click-modal="false">
<el-table
:data="templateList"
v-loading="templateLoading"
border
max-height="400px"
@row-click="selectTemplate"
style="width: 100%; cursor: pointer;">
<el-table-column
prop="templateName"
label="工序名称"
width="150"
align="center"
header-align="center">
</el-table-column>
<el-table-column
prop="prodApproverName"
label="车间负责人"
width="120"
align="center"
header-align="center">
</el-table-column>
<el-table-column
prop="qaApproverName"
label="质量负责人"
width="120"
align="center"
header-align="center">
</el-table-column>
<el-table-column
prop="techApproverName"
label="技术负责人"
width="120"
align="center"
header-align="center">
</el-table-column>
<el-table-column
label="操作"
width="80"
align="center"
header-align="center">
<template slot-scope="scope">
<a
type="text"
size="small"
style="color: #F56C6C"
@click.stop="deleteTemplate(scope.row)">
删除
</a>
</template>
</el-table-column>
</el-table>
<div slot="footer">
<el-button @click="templateDialogVisible = false">关闭</el-button>
</div>
</el-dialog>
<!-- 人员选择弹框 -->
<el-dialog
:title="userDialogTitle"
:visible.sync="userDialogVisible"
width="500px"
:close-on-click-modal="false">
<el-table
:data="userList"
v-loading="userLoading"
border
max-height="400px"
@row-click="selectUser"
style="width: 100%; cursor: pointer;">
<el-table-column
prop="userName"
label="姓名"
align="center"
header-align="center">
</el-table-column>
<el-table-column
prop="userId"
label="用户ID"
width="100"
align="center"
header-align="center">
</el-table-column>
</el-table>
<div slot="footer">
<el-button @click="userDialogVisible = false">关闭</el-button>
</div>
</el-dialog>
<!-- 确认对话框 -->
<el-dialog
:title="confirmDialogTitle"
@ -266,7 +400,17 @@
</template>
<script>
import { getTriConfirmList, saveTriConfirmProcess, deleteTriConfirmProcess, confirmTriApproval, updateProcessSequence } from '@/api/erf/erf'
import {
getTriConfirmList,
saveTriConfirmProcess,
deleteTriConfirmProcess,
confirmTriApproval,
updateProcessSequence,
getProcessTemplateList,
saveProcessTemplate,
deleteProcessTemplate,
getUserListByRole
} from '@/api/erf/erf'
import Sortable from 'sortablejs'
export default {
@ -280,6 +424,10 @@ export default {
height: {
type: String,
default: '35vh'
},
experimentType: {
type: String,
default: ''
}
},
@ -297,11 +445,26 @@ export default {
processForm: {
processStep: '',
prodApproverName: '',
prodApproverUserId: null,
qaApproverName: '',
qaApproverUserId: null,
techApproverName: '',
techApproverUserId: null,
remark: ''
},
//
templateDialogVisible: false,
templateList: [],
templateLoading: false,
//
userDialogVisible: false,
userDialogTitle: '',
userList: [],
userLoading: false,
currentRoleTypeForUser: '', //
//
confirmDialogVisible: false,
confirmDialogTitle: '',
@ -442,8 +605,11 @@ export default {
this.processForm = {
processStep: '',
prodApproverName: '',
prodApproverUserId: null,
qaApproverName: '',
qaApproverUserId: null,
techApproverName: '',
techApproverUserId: null,
remark: ''
}
this.processDialogVisible = true
@ -458,13 +624,186 @@ export default {
this.processForm = {
processStep: row.processStep,
prodApproverName: row.prodApproverName || '',
prodApproverUserId: row.prodApproverUserId || null,
qaApproverName: row.qaApproverName || '',
qaApproverUserId: row.qaApproverUserId || null,
techApproverName: row.techApproverName || '',
techApproverUserId: row.techApproverUserId || null,
remark: row.remark || ''
}
this.processDialogVisible = true
},
/**
* 打开工序模版选择弹框
*/
openTemplateDialog() {
this.templateDialogVisible = true
this.loadTemplateList()
},
/**
* 加载工序模版列表
*/
loadTemplateList() {
this.templateLoading = true
getProcessTemplateList({
site: this.$store.state.user.site
}).then(({data}) => {
this.templateLoading = false
if (data && data.code === 0) {
this.templateList = data.list || []
} else {
this.templateList = []
this.$message.error(data.msg || '加载模版列表失败')
}
}).catch(error => {
this.templateLoading = false
this.$message.error('加载模版列表异常')
})
},
/**
* 选择模版
*/
selectTemplate(row) {
this.processForm.processStep = row.templateName
this.processForm.prodApproverName = row.prodApproverName || ''
this.processForm.prodApproverUserId = row.prodApproverUserId || null
this.processForm.qaApproverName = row.qaApproverName || ''
this.processForm.qaApproverUserId = row.qaApproverUserId || null
this.processForm.techApproverName = row.techApproverName || ''
this.processForm.techApproverUserId = row.techApproverUserId || null
this.processForm.remark = row.remark || ''
this.templateDialogVisible = false
this.$message.success('已应用模版')
},
/**
* 删除模版
*/
deleteTemplate(row) {
this.$confirm('确定删除该模版?', '操作提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
deleteProcessTemplate({ id: row.id }).then(({data}) => {
if (data && data.code === 0) {
this.$message.success('删除模版成功')
this.loadTemplateList()
} else {
this.$message.error(data.msg || '删除模版失败')
}
}).catch(error => {
this.$message.error('删除模版异常')
})
})
},
/**
* 另存为模版
*/
saveAsTemplate() {
//
if (!this.processForm.processStep || !this.processForm.processStep.trim()) {
this.$message.warning('请输入工序名称')
return
}
if (!this.processForm.prodApproverName || !this.processForm.qaApproverName || !this.processForm.techApproverName) {
this.$message.warning('请先选择所有负责人')
return
}
this.$confirm('确定将当前工序保存为模版?', '操作提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'info'
}).then(() => {
saveProcessTemplate({
site: this.$store.state.user.site,
templateName: this.processForm.processStep.trim(),
prodApproverName: this.processForm.prodApproverName,
prodApproverUserId: this.processForm.prodApproverUserId,
qaApproverName: this.processForm.qaApproverName,
qaApproverUserId: this.processForm.qaApproverUserId,
techApproverName: this.processForm.techApproverName,
techApproverUserId: this.processForm.techApproverUserId,
remark: this.processForm.remark || ''
}).then(({data}) => {
if (data && data.code === 0) {
this.$message.success('保存模版成功')
} else {
this.$message.error(data.msg || '保存模版失败')
}
}).catch(error => {
this.$message.error('保存模版异常')
})
})
},
/**
* 打开人员选择弹框
*/
openUserDialog(roleType) {
this.currentRoleTypeForUser = roleType
const roleNames = {
'PROD': '车间负责人',
'QA': '质量负责人',
'TECH': '技术负责人'
}
this.userDialogTitle = `选择${roleNames[roleType]}`
this.userDialogVisible = true
this.loadUserList(roleType)
},
/**
* 加载人员列表
*/
loadUserList(roleType) {
this.userLoading = true
getUserListByRole({
roleType: roleType,
site: this.$store.state.user.site
}).then(({data}) => {
this.userLoading = false
if (data && data.code === 0) {
this.userList = data.list || []
} else {
this.userList = []
this.$message.error(data.msg || '加载人员列表失败')
}
}).catch(error => {
this.userLoading = false
this.$message.error('加载人员列表异常')
})
},
/**
* 选择人员
*/
selectUser(row) {
const roleType = this.currentRoleTypeForUser
if (roleType === 'PROD') {
this.processForm.prodApproverName = row.userName
this.processForm.prodApproverUserId = row.userId
} else if (roleType === 'QA') {
this.processForm.qaApproverName = row.userName
this.processForm.qaApproverUserId = row.userId
} else if (roleType === 'TECH') {
this.processForm.techApproverName = row.userName
this.processForm.techApproverUserId = row.userId
}
this.userDialogVisible = false
this.$message.success('已选择负责人')
},
/**
* 保存工序
*/
@ -475,14 +814,33 @@ export default {
return
}
//
if (!this.processForm.prodApproverName) {
this.$message.warning('请选择车间负责人')
return
}
if (!this.processForm.qaApproverName) {
this.$message.warning('请选择质量负责人')
return
}
if (!this.processForm.techApproverName) {
this.$message.warning('请选择技术负责人')
return
}
this.processSaving = true
saveTriConfirmProcess({
applyNo: this.applyNo,
processStep: this.processForm.processStep.trim(),
prodApproverName: this.processForm.prodApproverName || '',
qaApproverName: this.processForm.qaApproverName || '',
techApproverName: this.processForm.techApproverName || '',
prodApproverName: this.processForm.prodApproverName,
prodApproverUserId: this.processForm.prodApproverUserId,
qaApproverName: this.processForm.qaApproverName,
qaApproverUserId: this.processForm.qaApproverUserId,
techApproverName: this.processForm.techApproverName,
techApproverUserId: this.processForm.techApproverUserId,
remark: this.processForm.remark || ''
}).then(({data}) => {
this.processSaving = false
@ -499,6 +857,41 @@ export default {
})
},
/**
* 验证High Risk是否有完整工序
* 供父组件调用
* @return {Boolean} true=验证通过, false=验证失败
*/
validateHighRiskProcess() {
console.log('🔍 验证High Risk工序,experimentType:', this.experimentType)
// High Risk
if (this.experimentType !== 'High Risk') {
console.log('✅ 非High Risk,验证通过')
return true
}
//
const completeProcesses = this.processList.filter(process => {
return process.prodApproverName &&
process.qaApproverName &&
process.techApproverName
})
console.log('📊 完整工序数量:', completeProcesses.length, '/', this.processList.length)
if (completeProcesses.length === 0) {
this.$alert('High Risk申请单必须至少有一条完整的工序(包含车间、质量、技术三个负责人)', '操作提示', {
confirmButtonText: '确定',
type: 'warning'
})
return false
}
console.log('✅ High Risk验证通过')
return true
},
/**
* 删除工序行
*/

1
src/views/modules/erf/expApplyApproval.vue

@ -554,6 +554,7 @@ export default {
this.queryHeaderData.page = this.pageIndex
this.queryHeaderData.limit = this.pageSize
this.queryHeaderData.currentUserId = this.$store.state.user.id
this.queryHeaderData.pageType = 'MANAGER' //
this.dataListLoading = true

31
src/views/modules/erf/expApplyList.vue

@ -244,6 +244,7 @@
v-if="currentRow.applyNo&&currentRow.experimentType==='High Risk'"
ref="triConfirm"
:apply-no="currentRow.applyNo"
:experiment-type="currentRow.experimentType"
:height="detailHeight">
</exp-tri-confirm>
<div v-else class="empty-tip">
@ -666,6 +667,36 @@ export default {
* 下达申请单 - 打开审批人确认弹窗
*/
submitApply(row) {
// High Risk
if (row.experimentType === 'High Risk') {
//
this.currentRow = row
// DOM
this.$nextTick(() => {
if (this.$refs.triConfirm && this.$refs.triConfirm.validateHighRiskProcess) {
const isValid = this.$refs.triConfirm.validateHighRiskProcess()
if (!isValid) {
console.log('❌ High Risk验证失败,终止下达')
return
}
} else {
console.warn('⚠️ 未找到triConfirm组件或validateHighRiskProcess方法')
}
//
this.proceedSubmit(row)
})
} else {
// High Risk
this.proceedSubmit(row)
}
},
/**
* 执行下达流程
*/
proceedSubmit(row) {
//
getSubmitApprovers({
userId: this.$store.state.user.id,

1
src/views/modules/erf/plannerSchedule.vue

@ -245,6 +245,7 @@ export default {
applyNo: '',
buNo: '',
currentUserId: this.$store.state.user.id,
pageType: 'PLANNER', //
pendingStatus: '已批准', //
page: 1,
limit: 20

Loading…
Cancel
Save