mes-vue/src/views/production/myassigtask/index.vue
shaoleiliu-netizen123 f9e91c4216 提交代码
2026-08-25 15:20:24 +08:00

851 lines
20 KiB
Vue

<template>
<div class="page-container">
<!-- 用户列表 -->
<n-card class="user-list-card" size="small">
<!-- 搜索表单 -->
<div class="search-form">
<n-form
:model="searchForm"
label-placement="left"
>
<n-grid :cols="24" :x-gap="24">
<n-form-item-gi :span="4" label="派工编号">
<n-input v-model:value="searchForm.assingCode" placeholder="请输入派工编号" clearable />
</n-form-item-gi>
<n-form-item-gi :span="4" label="物料编码">
<n-input v-model:value="searchForm.materialCode" placeholder="请输入物料编码" clearable />
</n-form-item-gi>
<n-form-item-gi :span="4" label="物料名称">
<n-input v-model:value="searchForm.materialName" placeholder="请输入物料名称" clearable />
</n-form-item-gi>
<n-form-item-gi :span="4" label="工序名称">
<n-input v-model:value="searchForm.processName" placeholder="请输入工序名称" clearable />
</n-form-item-gi>
<n-form-item-gi :span="4" label="工单号">
<n-input v-model:value="searchForm.workOrderCode" placeholder="请输入工单号" clearable />
</n-form-item-gi>
<n-form-item-gi :span="4">
<n-space>
<n-button type="primary" @click="search">
<template #icon><n-icon><SearchOutline /></n-icon></template>
搜索
</n-button>
<n-button @click="reset">
<template #icon><n-icon><RefreshOutline /></n-icon></template>
重置
</n-button>
</n-space>
</n-form-item-gi>
</n-grid>
</n-form>
</div>
<AssingWorkTreeTable
ref="treeTableRef"
/>
<!-- 表格 -->
<!-- <n-data-table
:columns="columns"
size="small"
striped
:data="datalist"
:bordere="false"
:single-line="false"
:loading="loading"
remote
/>
<div class="pagination-container" style="display: flex; justify-content: flex-end; margin-top: 12px">
<n-pagination
v-model:page="pagination.page"
v-model:page-size="pagination.pageSize"
:item-count="pagination.itemCount"
:page-sizes="[10, 20, 50, 100]"
show-size-picker
show-quick-jumper
@update:page="handlePageChange"
@update:page-size="handlePageSizeChange"
>
<template #prefix>
{{ pagination.itemCount }}
</template>
</n-pagination>
</div> -->
</n-card>
<PlmModelDrawer ref="plmModelDrawerRef" />
<!--暂停恢复弹框-->
<n-modal
v-model:show="pausemodal"
title="报检"
preset="card"
style="width: 400px"
:mask-closable="false"
>
<AssingWorkVue
:id="gxobg.id"
:qcNumDisabled ="false"
@updateQcNum="handleUpdateQcNum"
/>
<SumbitDetailCard
:showOkTab="true"
:showScrapTab="true"
:showReworkTab = false
:showTraceCode="false"
:qcId="-1"
@updateSubmitDetail="handleSubmitDetail"
/>
<template #footer>
<n-space justify="end">
<n-button @click="pausemodal = false">取消</n-button>
<n-button
type="primary"
:loading="pauseLoading"
@click="pauseSubmit"
:disabled="pauseisedbtn"
>确认</n-button>
</n-space>
</template>
</n-modal>
<!-- 质检撤回弹框 -->
<n-modal
v-model:show="qcCancelModel"
title="提示"
preset="card"
style="width: 400px"
:mask-closable="false"
>
<n-card title="确定要撤回质检记录吗?">
<n-form ref="formRef" :model="qcCancelFormData" label-placement="left" label-width="100px">
<n-form-item label="备注" label-width="100">
<n-input
v-model:value="qcCancelFormData.remark"
type="textarea"
placeholder="输入撤回原因"
/>
</n-form-item>
</n-form>
<template #footer>
<n-space justify="end">
<n-button @click="qcCancelModel = false">取消</n-button>
<n-button
type="primary"
@click="cancelSubmit"
>确认</n-button>
</n-space>
</template>
</n-card>
</n-modal>
<!--改派弹框-->
<n-modal
v-model:show="reassignmodal"
title="改派"
preset="card"
style="width: 400px"
:mask-closable="false"
>
<n-form
ref="reassformRef"
:model="reassform"
:rules="reassrules"
label-placement="top"
label-width="80"
>
<n-form-item label="工序编号">
<n-input v-model:value="gxobg.id" disabled />
</n-form-item>
<n-form-item label="工序名称">
<n-input v-model:value="gxobg.name" disabled />
</n-form-item>
<n-form-item label="改派工人" path="">
<n-select
v-model:value="reassform.userId"
placeholder="请指定改派的员工"
clearable
style="width: 200px"
:options="reassignEmployees"
/>
</n-form-item>
<n-form-item label="改派原因" path="reason">
<n-input type="textarea" v-model:value="reassform.reason" placeholder="请输入改派原因" />
</n-form-item>
</n-form>
<template #footer>
<n-space justify="end">
<n-button @click="reassignmodal = false">取消</n-button>
<n-button
type="primary"
:loading="reassLoading"
@click="reassSubmit"
:disabled="reassdisedbtn"
>确定</n-button>
</n-space>
</template>
</n-modal>
</div>
</template>
<script setup lang="ts">
import {
ref,
reactive,
h,
onMounted,
watch, Component,
} from 'vue'
import {
NButton,
NDropdown,
NIcon,
NSpace,
NPagination,
NGrid,
// NGi,
NTag,
useMessage,
useDialog,
//type FormInst,
} from 'naive-ui'
import {
SearchOutline,
RefreshOutline,
SyncOutline,
EllipsisHorizontalOutline
} from '@vicons/ionicons5'
import { useUserStore } from '@/stores/user'
import { dictDataApi } from '@/api/org'
import {
mytasks,
inspectio
} from '@/api/production'
import PlmModelDrawer from '@/components/PlmModelDrawer.vue'
import AssingWorkVue from '@/views/biz/flowingAround/assingWork.vue'
import { qualityTestingApi, type QualityTesting } from '@/api/qualityTesting'
import SumbitDetailCard from '@/components/SumbitDetailCard.vue'
import { SubmitLog } from '@/api/submitLog'
import {
transfer
} from '@/api/production'
import { SysUser, userApi } from '@/api/system'
import AssingWorkTreeTable from '../componets/AssingWorkTreeTable.vue'
const treeTableRef = ref<InstanceType<typeof AssingWorkTreeTable>>()
const dialog = useDialog()
const message = useMessage()
const userStore = useUserStore()
// 权限检查
const hasPermission = (permission: string) => userStore.hasPermission(permission)
//派工状态字典
const qcAssingStatusOptions = ref<{ label: string; value: any;class:any }[]>([])
// ==================== 搜索表单 ====================
const searchForm = reactive({
page: 1,
pageSize: 20,
processId:'',
processName:'',
assingCode:'',
materialCode:'',
materialName:'',
workOrderCode:''
})
// ==================== 表格 ====================
const datalist = ref<any>([])
const loading = ref(false)
//分页
const pagination = reactive({
page: 1,
pageSize: 10,
itemCount: 0
})
const plmModelDrawerRef = ref<InstanceType<typeof PlmModelDrawer> | null>(null)
const columns = [
// {
// type: 'selection',
// minWidth:60
// },
{
align:"center",
title:"物料名称",
key:"materialName",
minWidth:150,
render(row:any) {
var opt = row.materialName
if(opt) return opt
return '-'
}
},
{
align:"center",
title:"物料编码",
key:"materialCode",
minWidth:150,
render(row:any) {
var opt = row.materialCode
if(opt) return opt
return '-'
}
},
{
align:"center",
title:"派工编号",
key:"assingCode",
minWidth:150
},
{
align:'center',
title: '工序名称',
key: 'processName',
minWidth: 200
},
{
align:'center',
title: '工序名称',
key: 'processCode',
minWidth: 200
},
{
align:'center',
title: '派工状态',
key: 'assingStatus',
minWidth: 150,
render(row:any) {
const val = row.assingStatus
const opt = qcAssingStatusOptions.value.find(o => o.value === val || String(o.value) === String(val))
if (!opt) return val ?? '-'
return h(NTag, { type: opt.class, size: 'small' }, { default: () => opt.label })
}
//派工状态0待执行 1执行中 2质检中+3已汇报一4已关闭
},
{
align:'center',
title: '车间名称',
key: 'workshopName',
minWidth: 200
},
{
align:'center',
title: '工段名称',
key: 'sectionName',
minWidth: 200
},
{
align:'center',
title: '工位名称',
key: 'deviceName',
minWidth: 200
},
{
align:'center',
title: '工人名称',
key: 'userName',
minWidth: 200
},
{
align:'center',
title: '数量',
minWidth: 100,
key: 'quantity'
},
{
align:'center',
title: '完成数量',
key: 'completedQuantity',
minWidth: 150
},
{
align:'center',
title: '完成时间',
key: 'completedTime',
minWidth: 180
},
{
align:'center',
title: '创建人',
key: 'createBy',
minWidth: 150
},
{
align:'center',
title: '工序状态',
key: 'status',
minWidth: 100,
render(row:any) {
if(row.status == 0){
return h(NTag, {
type:'success',
size: 'small'
},
{
default: () => '启用'
}
)
}
if(row.status == 1){
return h(NTag, {
type:'warning',
size: 'small'
},
{
default: () => '已暂停'
}
)
}
if(row.status == 2){
return h(NTag, {
type:'warning',
size: 'small'
},
{
default: () => '已改派'
}
)
}
return '-'
}
},
{
align:'center',
title: '操作',
key: 'actions',
width: 250,
fixed: 'right',
render(row:any) {
const buttons:any = []
if(hasPermission('biz:assingWork:edit')){
buttons.push(h(NButton, {
size: 'small',
type:'primary',
ghost:true,
onClick: () => { handlpause(row) } },
{ default: () => '完工汇报'}
))
}
buttons.push(h(NButton, {
size: 'small',
type: 'info',
ghost: true,
disabled: row.cancelBtnDisable,
onClick: ()=> cancelQuality(row)
}, { default: () => '质检撤回' }))
buttons.push(
h(NDropdown, {
trigger:'click',
options:[
{label:"改派",key:'transfer'},
{type: 'divider' }, // 分割线
],
onSelect:(key:string)=>{
switch(key) {
case "transfer":
handlreass(row)
break
}
}
},{
// 下拉触发按钮:三点图标 / 更多文字
default: () => h(NButton, { size: 'small', quaternary: true }, {
default: () => [h(NIcon, null, { default: () => h(EllipsisHorizontalOutline) })]
})
})
)
return buttons.length > 0 ? h(NSpace, {justify:'center'}, { default: () => buttons }) : '-'
}
}
]
//搜索数据
function search() {
treeTableRef.value?.loadTableData({
processName: searchForm.processName,
assingCode: searchForm.assingCode,
materialCode: searchForm.materialCode,
materialName: searchForm.materialName,
workOrderCode:searchForm.workOrderCode
})
}
//重置
function reset() {
searchForm.processId = ''
searchForm.processName = ''
searchForm.assingCode = ''
searchForm.materialCode = ''
searchForm.materialName = ''
searchForm.workOrderCode = ''
treeTableRef.value?.loadTableData({})
}
//获取列表数据
function getlist() {
treeTableRef.value?.loadTableData({
processName: searchForm.processName,
assingCode: searchForm.assingCode,
materialCode: searchForm.materialCode,
materialName: searchForm.materialName,
workOrderCode: searchForm.workOrderCode
})
}
function handlePageChange(page: number) {
pagination.page = page
getlist()
}
function handlePageSizeChange(pageSize: number) {
pagination.pageSize = pageSize
pagination.page = 1
getlist()
}
let gxobg = reactive<any>({})
//报检
let pausemodal = ref(false)
let pauseform = reactive<any>({
id:'',
qcNum:'',
okData:{
id:undefined,
qcId:undefined,
resultType:undefined,
qty:0,
traceCode:undefined,
defectCode:undefined,
handleAction:undefined,
actionStatus:undefined,
remark:undefined,
},
scrapData:{
id:undefined,
qcId:undefined,
resultType:undefined,
qty:0,
traceCode:undefined,
defectCode:undefined,
handleAction:undefined,
actionStatus:undefined,
remark:undefined,
}
})
const pauseformRef = ref()
const pauserules = {
qcNum: [
{ required: true, message: '请输报检数量', trigger: 'blur' },
{
validator(rule:any,value: any) {
if(value > pauseform.qcNum){
return new Error(`报检数量最大为${pauseform.qcNum}`)
}
return true
},
trigger: ['blur']
}
]
}
// watch(()=>pauseform.qcNum,v => {
// pauseform.qcNum = v.replace(/[^\d]/g,'')
// })
let pauseLoading = ref(false)
let pauseisedbtn = ref(false)
// 质检撤回
const qcCancelModel = ref<Boolean>(false)
const qcCancelFormData = ref<SubmitLog>({
assingWorkId:undefined,
remark:undefined
})
let qcCancelLoading = ref<Boolean>(false)
let qcDisabledBtn = ref<Boolean>(false)
function handlpause(n:any) {
gxobg.id = n.id
gxobg.name = n.name
pausemodal.value = true
pauseLoading.value = false
pauseisedbtn.value = false
pauseformRef.value?.restoreValidation()
pauseform.id = n.id
//pauseform.qcNum = `${n.quantity}`
// pauseform.qcNum = n.quantity-(n.completedQuantity ?? 0)
}
function checkPauseSumbit():boolean {
if(pauseform.id == null) {
message.error("参数id为空")
return false
}
if(pauseform.qcNum == null || pauseform.qcNum == '') {
message.error("质检数量不能为空")
return false
}
if(pauseform.okData == null || pauseform.okData == '' ) {
pauseform.okData={
id:undefined,
qcId:undefined,
resultType:undefined,
qty:0,
traceCode:undefined,
defectCode:undefined,
handleAction:undefined,
actionStatus:undefined,
remark:undefined,
}
}
if(pauseform.scrapData == null || pauseform.scrapData == '' ) {
pauseform.scrapData={
id:undefined,
qcId:undefined,
resultType:undefined,
qty:0,
traceCode:undefined,
defectCode:undefined,
handleAction:undefined,
actionStatus:undefined,
remark:undefined,
}
}
//检查合格数量和报废数量总和是不是等于提交总数
const okQty = pauseform.okData?.qty ?? 0
const scrapQty = pauseform.scrapData?.qty ?? 0
const checkNum = okQty + scrapQty
if(checkNum != pauseform.qcNum) {
message.error("汇报数量总和不等于提交数量")
return false
}
return true
}
function pauseSubmit() {
var pass = checkPauseSumbit();
console.log(pass);
if(!pass) return
pauseLoading.value = true
pauseisedbtn.value = true
inspectio(Object.assign({},pauseform,{qcNum:pauseform.qcNum*1})).then(() => {
message.success('操作成功!')
setTimeout(()=> {
pausemodal.value = false
pauseLoading.value = false
pauseisedbtn.value = false
getlist()
},1000)
}).catch(() => {
pauseLoading.value = false
pauseisedbtn.value = false
})
}
function handleUpdateQcNum(qcNum:number) {
pauseform.qcNum = qcNum
}
function handleSubmitDetail(submitDetail:any){
pauseform.okData = submitDetail.okData
pauseform.scrapData = submitDetail.scrapData
}
// 加载字典选项
async function loadDictOptions() {
qcCancelLoading = true
try {
const data = await dictDataApi.listByType('assing_status')
qcAssingStatusOptions.value = data.map(d => ({ label: d.dictLabel, value: (Number(d.dictValue) || d.dictValue),class:d.listClass }))
}catch {}
}
// function zantqy(row:any) {
// dialog.warning({
// title: '温馨提示',
// content: `确定要暂停"${row.processName}"吗?`,
// positiveText: '确定',
// negativeText: '取消',
// onPositiveClick: () => {
// pauseresume({}).then(() => {
// message.success('操作成功!')
// getlist()
// })
// }
// })
// }
function cancelQuality(row:any) {
qcCancelModel.value = true
qcCancelFormData.value.assingWorkId = row.id
qcCancelLoading.value = true
qcDisabledBtn.value = true
// dialog.warning({
// title: '提示',
// content: '确定要撤回质检记录吗?',
// positiveText: '确定',
// negativeText: '取消',
// onPositiveClick: async () => {
// try {
// await qualityTestingApi.cancel(row.id)
// message.success('撤回成功')
// getlist()
// } catch (error) {
// console.log("撤回失败"+error)
// }
// }
// })
}
async function cancelSubmit() {
try{
await qualityTestingApi.cancel({"assingId":qcCancelFormData.value.assingWorkId,"remark":qcCancelFormData.value.remark})
message.success('撤回成功')
qcCancelModel.value = false
getlist()
}catch(error) {
console.log("撤回失败"+error);
}
}
//改派
//改派员工列
const reassignEmployees = ref<Array<{value: number, username: string}>>([])
let reassLoading = ref(false)
let reassdisedbtn = ref(false)
let reassignmodal = ref(false)
const reassformRef = ref()
let reassform = reactive<any>({
id:null, //派工id
reason:null, //改派原因
userId:null //改派设备
})
const reassrules = {
userid: [{ required: true, message: '请选择员工', trigger: 'blur' }]
}
function handlreass(n:any) {
gxobg.name = n.processName
gxobg.id = n.processId
reassignmodal.value = true
reassLoading.value = false
reassdisedbtn.value = false
reassformRef.value?.restoreValidation()
reassform.id = n.id
reassform.reason = ''
reassform.userid = ''
}
function reassSubmit() {
reassformRef.value?.validate((v:any) => {
if(!v){
reassLoading.value = true
reassdisedbtn.value = true
transfer(reassform).then(() => {
message.success('操作成功!')
setTimeout(()=> {
reassignmodal.value = false
reassLoading.value = false
reassdisedbtn.value = false
getlist()
},1000)
}).catch(() => {
reassdisedbtn.value = false
reassLoading.value = false
})
}
})
}
//获取员工列
async function getUserList() {
const res = await userApi.getPathList();
reassignEmployees.value = res.map((user:SysUser)=>(
{
label: user.username,
value: user.id
}
))
}
onMounted(() => {
getlist()
getUserList()
loadDictOptions()
})
</script>
<style scoped>
</style>