Newer
Older
smart-metering-front / src / views / business / subpackage / apply / edit.vue
<!-- 分包申请详情 -->
<script lang="ts" setup>
import { ElLoading, ElMessage, ElMessageBox } from 'element-plus'
import type { FormInstance, FormRules } from 'element-plus'
import { ref } from 'vue'
import type { IApplyDetail, ISampleList } from '../subpackage-interface'
import selectProjectApprove from '../apply/components/selectProjectApprove.vue'
import selectSample from './components/selectSample.vue'
import type { dictType } from './apply-interface'
import { UploadFile } from '@/api/measure/file'
import ApprovalDialog from '@/components/Approval/ApprovalDialog.vue'
import type { TableColumn } from '@/components/NormalTable/table_interface'
import { addApply, detail, failUpdateApply, submit, updateApply } from '@/api/business/subpackage/apply'
import { cancelApproval, fetchApproval, submitApproval } from '@/api/approval'
import showPhoto from '@/views/system/tool/showPhoto.vue'
import { getDictByCode } from '@/api/system/dict'
import useUserStore from '@/store/modules/user'

const user = useUserStore() // 用户信息
const textMap: { [key: string]: string } = {
  edit: '编辑',
  add: '新建',
  detail: '详情',
}// 字典
const { proxy } = getCurrentInstance() as any
const $router = useRouter() // 关闭页面使用
const $route = useRoute()
const query = $route.query
const approvalDialog = ref() // 审批对话ref
const pageType = ref('add') // 页面类型: add, edit, detail
const infoId = ref('') // 列表id
const submitId = ref('') // 新建提交时所用的id
const outsourceReasonMap = ref<dictType[]>([]) // 分包原因
const ruleFormRef = ref<FormInstance>() as any
const detailForm = ref<IApplyDetail>({
  projectNo: '', // 分包项目编号
  formId: query.formId as string,
  applicantTime: '', // 申请时间
  applyMinioFileName: '', // 申请文件名称
  applyProcessId: '', // 流程实例id
  applyRemark: '', // 申请备注
  createUser: '', // 申请人
  createUserName: '', // 申请人名称
  orderSampleList: [] as any, // 订单列表
  outsourceReason: '', // 分包原因
  outsourceReasonName: '', // 原因名称
  outsourcerId: '', // 分包方id
  outsourcerNo: '', // 分包方编号
  outsourcerName: '', // 公司名称
  preCost: '', // 预计费用
  preEndTime: '', // 预计结束时间
  preStartTime: '', // 预计开始时间
  projectName: '', // 分包项目名称
  sampleList: [] as any, // 样品列表
  rejectRemark: '', // 历次原因
})

// 自定义校验规则--要求预计结束时间大于预计开始时间
const requireOverTimeValid = (rule: any, value: any, callback: any) => {
  if (!value) {
    return callback(new Error('预计结束时间必填'))
  }
  if (new Date(detailForm.value.preEndTime).getTime() <= new Date(detailForm.value.preStartTime).getTime()) {
    return callback(new Error('不能小于预计开始时间'))
  }
  callback()
}
// 校验规则
const formRules = ref<FormRules>({
  projectName: [{ required: true, message: '分包项目名称必填', trigger: ['blur', 'change'] }],
  outsourcerNo: [{ required: true, message: '分包方编号必填', trigger: ['blur', 'change'] }],
  // outsourcerName: [{ required: true, message: '要求公司名称必填', trigger: ['blur', 'change'] }],
  outsourceReason: [{ required: true, message: '分包原因必填', trigger: ['blur', 'change'] }],
  // preCost: [{ required: true, message: '预计费用必填', trigger: ['blur', 'change'] },
  //   { pattern: /(^-?\d\d*\.\d*$)|(^-?\d\d*$)|(^-?\.\d\d*$)/, message: '预计费用只能为数字', trigger: ['blur', 'change'] }],
  preStartTime: [{ required: true, message: '预计开始时间必填', trigger: ['blur', 'change'] }],
  // preEndTime: [{ required: true, message: '预计结束时间必填', trigger: ['blur', 'change'] }],
  preEndTime: [{ required: true, type: 'date', validator: requireOverTimeValid, trigger: 'change' }],
})

const list = ref<ISampleList[]>([])// 表格数据
// 表头
const columns = ref<TableColumn[]>([
  { text: '样品编号', value: 'sampleNo', align: 'center', width: '230' },
  { text: '样品名称', value: 'sampleName', align: 'center' },
  { text: '型号', value: 'sampleModel', align: 'center' },
  { text: '出厂编号', value: 'manufacturingNo', align: 'center' },
  { text: '委托单编号', value: 'orderCode', align: 'center' },
  { text: '委托单位', value: 'customerName', align: 'center' },
])

// 从路由中获取页面类型参数
if ($route.params && $route.params.type) {
  pageType.value = $route.params.type as string
  console.log(pageType.value)

  if ($route.params.id) {
    infoId.value = $route.params.id as string
  }
}

// 获取字典值
function getDict() {
  // 分包原因
  getDictByCode('outsourceReason').then((response) => {
    outsourceReasonMap.value = response.data
  })
}

// 获取详情信息
const getDetail = () => {
  const loading = ElLoading.service({
    lock: true,
    background: 'rgba(255, 255, 255, 0.8)',
  })
  detail({ id: $route.params.id as string }).then((res) => {
    loading.close()
    detailForm.value = res.data
    detailForm.value.createUserName = res.data.applicantName || user.name
    list.value = res.data.sampleList.filter((item: ISampleList) => {
      return item !== null
    })
  }).catch(() => {
    loading.close()
  })
}

// 关闭新增页面的回调
const close = () => {
  $router.back()
}

// 保存
const handleSave = () => {
  const tempList = list.value.filter(item => item.sampleNo)
  if (!tempList.length) {
    ElMessage.warning('样品信息不能为空')
    return
  }
  ruleFormRef.value.validate((valid: boolean) => {
    if (valid) {
      const loading = ElLoading.service({
        lock: true,
        background: 'rgba(255, 255, 255, 0.8)',
      })
      // 样品&委托单列表(保存/编辑草稿接口入参使用)
      const temList = [] as any // 临时数组
      console.log('保存中的数组', list.value)

      list.value.forEach((item: any) => {
        if ((item.orderId && item.id) || (item.orderId && item.sampleId)) {
          temList.push({
            orderId: item.orderId,
            sampleId: item.id || item.sampleId,
          })
        }
      })
      detailForm.value.orderSampleList = temList
      if (pageType.value === 'add') { // 新建
        addApply(detailForm.value).then((res) => {
          submitId.value = res.data.id
          detailForm.value.projectNo = res.data.projectNo // 分包项目编号
          ElMessage.success('保存成功')
          loading.close()
        }).catch(() => {
          loading.close()
        })
      }
      else if (pageType.value === 'edit') { // 编辑
        if (query.approvalStatusName === '未通过-驳回') { // 未通过-驳回
          failUpdateApply(detailForm.value).then((res) => {
            ElMessage.success('保存成功')
            loading.close()
            close()
          }).catch(() => {
            loading.close()
          })
        }
        else { // 草稿箱和已取消
          updateApply(detailForm.value).then((res) => {
            ElMessage.success('保存成功')
            loading.close()
            close()
          }).catch(() => {
            loading.close()
          })
        }
      }
    }
  })
}

// 提交
const handleSubmit = () => {
  if (submitId.value) {
    const loading = ElLoading.service({
      lock: true,
      background: 'rgba(255, 255, 255, 0.8)',
    })
    const params = {
      id: submitId.value,
      formId: query.formId, // 表单id
    }
    submit(params).then(() => {
      ElMessage.success('提交成功')
      loading.close()
      close()
    }).catch(() => {
      loading.close()
    })
  }
  else {
    ElMessage.warning('请先保存!')
  }
}

// 增加行
const addRow = () => {
  const index = list.value.findIndex(item => !item.sampleNo)
  if (index !== -1) {
    ElMessage.warning('请完善上一条样品信息')
    return
  }
  list.value.push({
    orderCode: '',	// 原始记录单编号
    sampleName: '',	// 样品名称
    sampleNo: '',	// 样品编号
    customerNo: '', // 委托方id
    customerName: '', // 委托方名称
    startTime: '',
    endTime: '',
  })
}
const sampleVisible = ref(false)
const projectVisible = ref(false)
const isMulti = ref(false)
const selectIndex = ref(0)
// 点击选择
const handleSelect = (index: number, row: ISampleList) => {
  sampleVisible.value = true // 选择设备对话框显隐
  isMulti.value = false // 是否单选, false单选、true表格多选
  selectIndex.value = index
}

// 点击批量添加
const multiAdd = () => {
  sampleVisible.value = true // 打开选择样品的对话框
  isMulti.value = true
}

const checkoutList = ref([]) // 选中的行

// 修改委托方对话框显隐
const changeSampleVisible = (val: boolean) => {
  sampleVisible.value = val
}
// 修改项目选择对话框显隐
const changeProjectVisible = (val: boolean) => {
  projectVisible.value = val
}

// 选好样品
const clickConfirmSample = (val: any) => {
  if (val && val.length) {
    if (isMulti.value) {
      val.forEach((item: ISampleList) => {
        // 只添加列表里不存在的
        const index = list.value.findIndex((i: ISampleList) => item.sampleNo === i.sampleNo)
        if (index === -1) {
          list.value.push(item)
        }
      })
    }
    else {
      const index = list.value.findIndex((i: ISampleList) => val[0].sampleNo === i.sampleNo)
      if (index !== -1) {
        ElMessage.warning('此样品已添加过')
        return
      }
      list.value.splice(selectIndex.value, 1, val[0])
    }
  }
}

// 选择分包方
const clickConfirmProject = (val: any) => {
  detailForm.value.outsourcerId = val[0].id // 分包方id
  detailForm.value.outsourcerNo = val[0].outsourcerNo // 分包方编号
  detailForm.value.outsourcerName = val[0].outsourcerName // 公司名称
  // detailForm.value.applyProcessId = val[0].processId // 流程实例id
}

// 选中行
const handleSelectionChange = (e: any) => {
  checkoutList.value = e
}

// 删除行
const delRow = () => {
  checkoutList.value.forEach((item: ISampleList) => {
    list.value.forEach((element, index) => {
      if (element.sampleNo === item.sampleNo) {
        list.value.splice(index, 1)
      }
    })
  })
}

// ---------------------------------文件上传-------------------------------------------
const fileRef = ref()
const onFileChange = (event: any) => {
  // 原生上传
  if (event.target.files?.length !== 0) {
    // 创建formdata对象
    const fd = new FormData()
    fd.append('multipartFile', event.target.files[0])
    const loading = ElLoading.service({
      lock: true,
      background: 'rgba(255, 255, 255, 0.8)',
    })
    UploadFile(fd).then((res) => {
      if (res.code === 200) {
        detailForm.value.applyMinioFileName = res.data[0]
        // 重置当前验证
        ElMessage.success('文件上传成功')
        loading.close()
      }
      else {
        ElMessage.error(res.message)
        loading.close()
      }
    })
  }
}
const upload = () => {
  fileRef.value.click()
}
// ------------------------------------------审批-----------------------------------------

const approvalRecordData = ref([]) // 审批流程数据
// 查询审批记录
function getApprovalRecord(processId: string) {
  if (pageType.value !== 'add') {
    if (processId) {
      fetchApproval(processId).then((res) => {
        approvalRecordData.value = res.data
      })
    }
    else {
      ElMessage.warning('流程实例id为空')
    }
  }
}
// 审批结束回调
const approvalSuccess = () => {
  close() // 返回上一页
}
// 审批
const handleApprove = (val: string, title = '') => {
  if (val === '取消') {
    const params = {
      processInstanceId: detailForm.value.applyProcessId!,
      comments: '',
    }
    ElMessageBox.confirm(
      '确认取消该审批吗?',
      '提示',
      {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning',
      },
    )
      .then(() => {
        cancelApproval(params).then((res) => {
          ElMessage({
            type: 'success',
            message: '取消成功',
          })
          close()
        })
      })
  }
  else if (val === '同意') {
    approvalDialog.value.initDialog('agree', query.taskId)
  }
  else if (val === '驳回') {
    approvalDialog.value.initDialog('reject', query.taskId)
  }
  else if (val === '拒绝') {
    approvalDialog.value.initDialog('refuse', query.taskId)
  }
}
// -------------------------------------------------------------------------------------
onMounted(async () => {
  await getDict()
  detailForm.value.applyProcessId = query.applyProcessId as string // 流程实例
  if (pageType.value !== 'add') { // 编辑、详情
    getDetail()
    if (query.approvalStatusName !== '草稿箱') {
      getApprovalRecord(detailForm.value.applyProcessId) // 获取审批流程
    }
  }
  else { // 新建
    detailForm.value.createUser = user.id // 申请人id
    detailForm.value.createUserName = user.name // 申请人名字
    detailForm.value.applicantTime = proxy.dayjs().format('YYYY-MM-DD HH:mm:ss') // 申请时间
  }
})

// 监听到驳回原因
const giveRejectRemark = (reason: string) => {
  if (detailForm.value.rejectRemark) {
    const lastIndex = detailForm.value.rejectRemark.lastIndexOf(reason)
    if (lastIndex === -1) { // 本次原因和上次最后一次原因不同才去拼接
      detailForm.value.rejectRemark = `${detailForm.value.rejectRemark};${reason}`
    }
  }
  else {
    detailForm.value.rejectRemark = reason
  }
}
</script>

<template>
  <app-container style="overflow: hidden;">
    <detail-page :title="`分包项目申请-${textMap[pageType]}`">
      <template #btns>
        <el-button v-if="pageType === 'detail' && query.approvalStatusName === '待审批'" type="primary" @click="handleApprove('同意')">
          同意
        </el-button>
        <el-button v-if="pageType === 'detail' && query.approvalStatusName === '待审批' && query.decisionItem !== '3'" type="primary" @click="handleApprove('驳回')">
          驳回
        </el-button>
        <el-button v-if="pageType === 'detail' && query.approvalStatusName === '待审批' && query.decisionItem !== '2'" type="danger" @click="handleApprove('拒绝')">
          拒绝
        </el-button>
        <el-button v-if="pageType === 'add'" type="primary" @click="handleSubmit">
          提交
        </el-button>
        <el-button v-if="pageType !== 'detail'" type="primary" @click="handleSave">
          保存
        </el-button>
        <!-- <el-button v-if="pageType === 'detail'" type="primary">
          打印
        </el-button> -->
        <el-button v-if="pageType === 'detail' && query.approvalStatusName === '审批中'" type="info" @click="handleApprove('取消')">
          取消
        </el-button>
        <el-button type="info" @click="close">
          关闭
        </el-button>
      </template>
      <el-form
        ref="ruleFormRef"
        :model="detailForm"
        label-width="140"
        label-position="right"
        :rules="formRules"
      >
        <el-row :gutter="24">
          <el-col :span="6">
            <el-form-item label="分包项目编号:" prop="id">
              <el-input v-model="detailForm.projectNo" disabled placeholder="系统自动生成" />
            </el-form-item>
          </el-col>
          <el-col :span="6">
            <el-form-item label="分包项目名称:" prop="projectName">
              <el-input
                v-model="detailForm.projectName"
                :placeholder="pageType === 'detail' ? '' : '请输入分包项目名称'"
                :disabled="pageType === 'detail'"
              />
            </el-form-item>
          </el-col>
          <el-col :span="6">
            <el-form-item label="申请人:">
              <el-input
                v-model="detailForm.createUserName" disabled
              />
            </el-form-item>
          </el-col>
          <el-col :span="6">
            <el-form-item label="申请时间:" prop="applicantTime">
              <el-input
                v-model="detailForm.applicantTime" disabled
              />
            </el-form-item>
          </el-col>
          <el-col :span="6">
            <el-form-item label="分包方编号:" prop="outsourcerNo">
              <el-input
                v-model="detailForm.outsourcerNo"
                disabled
                :placeholder="pageType === 'detail' ? '' : '请选择分包方编号'"
              >
                <template v-if="pageType !== 'detail'" #append>
                  <el-button
                    size="small"
                    @click="changeProjectVisible(true)"
                  >
                    选择
                  </el-button>
                </template>
              </el-input>
            </el-form-item>
          </el-col>
          <el-col :span="6">
            <el-form-item label="公司名称:" prop="outsourcerName">
              <el-input
                v-model="detailForm.outsourcerName"
                :placeholder="pageType === 'detail' ? '' : '请输入公司名称'"
                disabled
              />
            </el-form-item>
          </el-col>
          <el-col :span="6">
            <el-form-item label="分包原因:" prop="outsourceReason">
              <el-select v-model="detailForm.outsourceReason" :placeholder="pageType === 'detail' ? '' : '请选择分包原因'" :disabled="pageType === 'detail'" class="full-width-input">
                <el-option
                  v-for="i in outsourceReasonMap"
                  :key="i.value"
                  :label="i.name"
                  :value="i.value"
                />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="6">
            <el-form-item label="预计费用(元):" prop="preCost">
              <el-input
                v-model="detailForm.preCost"
                placeholder="请输入预计费用"
                :disabled="pageType === 'detail'"
              />
            </el-form-item>
          </el-col>
          <el-col :span="6">
            <el-form-item label="预计开始时间:" prop="preStartTime">
              <el-date-picker
                v-model="detailForm.preStartTime"
                type="datetime"
                placeholder="请选择"
                format="YYYY-MM-DD HH:mm:ss"
                value-format="YYYY-MM-DD HH:mm:ss"
                :disabled="pageType === 'detail'"
              />
            </el-form-item>
          </el-col>
          <el-col :span="6">
            <el-form-item label="预计结束时间:" prop="preEndTime">
              <el-date-picker
                v-model="detailForm.preEndTime"
                type="datetime"
                placeholder="请选择"
                format="YYYY-MM-DD HH:mm:ss"
                value-format="YYYY-MM-DD HH:mm:ss"
                :disabled="pageType === 'detail'"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="备注:" prop="applyRemark">
              <el-input
                v-model="detailForm.applyRemark"
                :disabled="pageType === 'detail'"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="24">
          <el-col :span="24">
            <el-form-item label="附件:" prop="applyMinioFileName">
              <input v-show="pageType === ''" ref="fileRef" multiple type="file" @change="onFileChange">
              <span v-if="pageType === 'detail' && !detailForm.applyMinioFileName">无</span>
              <div v-else style="display: flex;">
                <show-photo :minio-file-name="detailForm.applyMinioFileName || ''" style="display: inline-block;" />
              </div>
              <el-button v-if="pageType !== 'detail'" type="primary" :disabled="pageType === 'detail'" @click="upload">
                {{ detailForm.applyMinioFileName ? '更换' : '上传' }}
              </el-button>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row v-if="query.approvalStatusName === '未通过-驳回'" :gutter="20">
          <el-col :span="24">
            <el-form-item label="历次驳回原因:">
              <el-input
                v-model.trim="detailForm.rejectRemark"
                :placeholder="pageType === 'detail' ? '' : '历次驳回原因'"
                class="full-width-input"
                clearable
                type="textarea"
                autosize
                disabled
              />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
    </detail-page>
    <detail-block title="样品信息">
      <template v-if="pageType !== 'detail'" #btns>
        <el-button type="primary" @click="multiAdd">
          批量添加
        </el-button>
        <el-button type="primary" @click="addRow">
          增加行
        </el-button>
        <el-button type="info" @click="delRow">
          删除行
        </el-button>
      </template>
      <el-table
        :data="list"
        border
        style="width: 100%;"
        max-height="600"
        @selection-change="handleSelectionChange"
      >
        <el-table-column v-if="pageType !== 'detail'" type="selection" width="38" />
        <el-table-column align="center" label="序号" width="80" type="index" />
        <el-table-column
          v-for="item in columns"
          :key="item.value"
          :prop="item.value"
          :label="item.text"
          :width="item.width"
          show-overflow-tooltip
          align="center"
        >
          <template v-if="item.value === 'sampleNo' && (pageType === 'add' || pageType === 'edit')" #default="scope">
            <el-input v-model="scope.row.sampleNo" placeholder="请选择设备" class="input" disabled>
              <template #append>
                <el-button size="small" @click="handleSelect(scope.$index, scope.row)">
                  选择
                </el-button>
              </template>
            </el-input>
          </template>
        </el-table-column>
      </el-table>
    </detail-block>
    <detail-block v-if="query.approvalStatusName !== '草稿箱' && pageType !== 'add'" title="审批流程">
      <!-- 审批流程 -->
      <approval-record ref="approvalRecord" :approval-record-data="approvalRecordData" @give-reject-remark="giveRejectRemark" />
    </detail-block>
    <!-- 样品增加弹窗 -->
    <select-sample v-model:visible="sampleVisible" :is-use-customer-no="false" :is-multi="isMulti" @click-confirm-sample="clickConfirmSample" @change-visible="changeSampleVisible" />
    <!-- 项目选择 -->
    <select-project-approve
      v-model:visible="projectVisible" :form-id="detailForm.formId" @click-confirm-project="clickConfirmProject"
      @change-visible="changeProjectVisible(false)"
    />
    <!-- 审批弹窗 -->
    <approval-dialog ref="approvalDialog" @on-success="approvalSuccess" />
  </app-container>
</template>

<style lang="scss" scoped>
// 样式
</style>