Newer
Older
xc-business-system / src / views / resource / person / trainSign / detail.vue
dutingting on 29 Nov 20 KB bug修复
<!-- 培训签到表详情 -->
<script name="TrainSignDetail" lang="ts" setup>
import { ElLoading, ElMessage, ElMessageBox, dayjs } from 'element-plus'
import type { IStaffBasicInfo } from '../register/person-regitster'
import type { IParticipantInfo, IRegistrationForm } from './train-interface'
import FilterRegistedStaff from '@/views/resource/common/filterRegistedStaff.vue'
import { addTrainSignInfo, confirmSign, detailTrainSignInfo, getStream, updateTrainSignInfo, workbenchReminder } from '@/api/resource/train'
import type { TableColumn } from '@/components/NormalTable/table_interface'
import type { IDictType } from '@/commonInterface/resource-interface'
import { getDictByCode } from '@/api/system/dict'
import { getStaffList } from '@/api/resource/register'
import useUserStore from '@/store/modules/user'
import { printPdf } from '@/utils/printUtils'
import type { dictType } from '@/global'
import filterGrantNotice from '@/views/resource/common/filterGrantNotice.vue'
import { exportFile } from '@/utils/exportUtils'
import { getBase64 } from '@/utils/download'

const type = ref<string>('')
const id = ref<string>('')

const route = useRoute()
const router = useRouter()

const loading = ref<boolean>(false)

// 字典值
const labCodeDict = ref<Array<IDictType>>([]) // 实验室代码
const groupCodeDict = ref<Array<IDictType>>([]) // 部门代码

const trainInfo = ref<IRegistrationForm>({
  id: '',
  fileCode: '', // 文件编号
  fileName: '培训签到表', // 文件名称
  labCode: '',
  labCodeName: '',
  groupCode: '',
  groupCodeName: '',
  trainingTime: '',
  position: '',
  host: '',
  fileNoteCode: '',
  content: '',
  createTime: '',
  noveltyId: '',
  participantsList: [],
})

const basicFormRef = ref()
const staffFormRef = ref()
const refFilterStaff = ref()

const trainBasicRules = ref({
  labCode: [{ required: true, message: '实验室不能为空,请选择', trigger: ['change', 'blur'] }],
  groupCode: [{ required: true, message: '部门不能为空,请选择', trigger: ['change', 'blur'] }],
  trainingTime: [{ required: true, message: '培训时间不能为空,请选择', trigger: ['change', 'blur'] }],
  position: [{ required: true, message: '培训地点不能为空', trigger: 'blur' }],
  host: [{ required: true, message: '培训会主持人不能为空', trigger: 'blur' }],
  content: [{ required: true, message: '训练内容不能为空', trigger: 'blur' }],
}) // 表单验证规则

const staffColumns = ref<Array<TableColumn>>([
  { text: '姓名', value: 'staffName', align: 'center', width: '150' },
  { text: '军官/文职证号', value: 'officerNo', align: 'center', width: '160' },
  { text: '工作部门', value: 'deptName', align: 'center' },
  { text: '岗位', value: 'station', align: 'center' },
  { text: '人员类别', value: 'staffTypeName', align: 'center', width: '120' },
  { text: '是否已发送通知', value: 'isNoticedName', align: 'center', width: '100' },
  { text: '是否进行确认', value: 'isConformName', align: 'center', width: '100' },
  { text: '签到结果', value: 'isSignName', align: 'center', width: '100' },
  { text: '确认时间', value: 'confirmTime', align: 'center', width: '180' },
]) // 表头

// 表格被选中的行
const staffSelected = ref<IParticipantInfo[]>([])

const userInfo = useUserStore()

// ----------------------------------------------------------------------------------------------
const staffUserList = ref<dictType[]>([]) // 计量人员
// 获取计量人员
const fetchStaffList = async () => {
  // 计量人员
  const res = await getStaffList({
    staffNo: '', // 人员编号
    name: '', // 姓名
    deptId: '', // 所在部门
    limit: 999999,
    offset: 1,
  })
  staffUserList.value = res.data.rows
}
// ----------------------------------------------------------------------------------------------
// 关闭
const resetForm = () => {
  sessionStorage.removeItem('trainSignInfo')
  router.go(-1)
}

const staffMultiSelect = (e: any) => {
  staffSelected.value = e
}

const detail = () => {
  detailTrainSignInfo({ id: id.value }).then((res) => {
    if (res.code === 200) {
      trainInfo.value = res.data
      trainInfo.value.participantsList = trainInfo.value.participantsList.map((staff) => {
        return {
          ...staff,
          isConformName: staff.isConform === '1' ? '已确认' : '未确认',
          isSignName: staff.isSign === '1' ? '已签到' : '未签到',
          isNoticedName: staff.isNoticed === '1' ? '已通知' : '未通知',
        }
      })
      loading.value = false
    }
  }).catch(() => {
    loading.value = false
  })
}

// 新增培训签到表
const addTrainAndStaffList = () => {
  trainInfo.value.createTime = dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss')
  addTrainSignInfo(trainInfo.value).then((res) => {
    if (res.code === 200) {
      // 提示保存成功
      ElMessage.success('保存成功')
      id.value = res.data
      trainInfo.value.id = res.data // id
      type.value = 'detail'
      trainInfo.value.fileCode = res.data
    }
    else {
      // 提示失败信息
      ElMessage.error(`保存失败:${res.message}`)
    }
  })
}
// 编辑登记表
const updateTrainAndStaffList = () => {
  updateTrainSignInfo(trainInfo.value).then((res) => {
    if (res.code === 200) {
      // 提示保存成功
      ElMessage.success('保存成功')

      type.value = 'detail'
      trainInfo.value.participantsList = trainInfo.value.participantsList.map((staff) => {
        return {
          ...staff,
          isConformName: staff.isConform === '1' ? '已确认' : '未确认',
          isSignName: staff.isSign === '1' ? '已签到' : '未签到',
          isNoitcedName: staff.isNoticed === '1' ? '已通知' : '未通知',
        }
      })
    }
    else {
      // 提示失败信息
      ElMessage.error(`保存失败:${res.message}`)
    }
  })
}

// 保存基本信息
const saveTrainForm = async () => {
  if (!basicFormRef) { return }

  await basicFormRef.value.validate((valid: boolean, fields: any) => {
    if (valid === true) {
      if (trainInfo.value.participantsList !== undefined && trainInfo.value.participantsList.length > 0) {
        ElMessageBox.confirm(
          '确认保存吗?',
          '提示',
          {
            confirmButtonText: '确认',
            cancelButtonText: '取消',
            type: 'warning',
          },
        ).then(() => {
          if (type.value === 'create') {
            addTrainAndStaffList()
          }
          else if (type.value === 'update') {
            updateTrainAndStaffList()
          }
        })
      }
      else {
        ElMessage.warning('实训人员不能为空')
      }
    }
  })
}

// 点击编辑按钮
const editButtHandler = () => {
  type.value = 'update'
}

// 点击增加行按钮 选择人员
const addEditableRow = () => {
  refFilterStaff.value.showOrHideFilterDialog(true)
}

// 选定人员
const recordSelectedHandler = (rows: Array<IStaffBasicInfo>) => {
  refFilterStaff.value.showOrHideFilterDialog(false)

  rows.forEach((staff) => {
    const exist = trainInfo.value.participantsList.filter(part => staff.id === part.participantId)
    // 表中没有重复的人员 则添加
    if (exist.length === 0) {
      trainInfo.value.participantsList.push({
        formId: id.value,
        participantId: staff.id!,
        isConform: '0',
        isSign: '0',
        isNoticed: '0',
        staffName: staff.staffName,
        officerNo: staff.officerNo,
        deptName: staff.deptName,
        station: staff.station,
        staffTypeName: staff.staffTypeName,
      })
    }
  })
}

// 删除实训人员
const delTrainStaffRec = async () => {
  if (staffSelected.value.length === 0) {
    ElMessage.warning('请至少选择一行')
    return
  }

  // 校验已发送通知的不能删除
  const isNoticedIndex = staffSelected.value.findIndex(item => item.isNoticed === '1')
  if (isNoticedIndex !== -1) {
    ElMessage.warning(`${staffSelected.value[isNoticedIndex].staffName}已经发送通知,不允许删除`)
    return
  }

  // 校验已确认的不能删除
  const index = staffSelected.value.findIndex(item => item.isConform === '1')
  if (index !== -1) {
    ElMessage.warning(`${staffSelected.value[index].staffName}已经确认过,不允许删除`)
    return
  }

  // 前端界面删除
  trainInfo.value.participantsList = trainInfo.value.participantsList.filter(item => staffSelected.value.includes(item) === false)
}

// ----------------------------文件发放通知单-------------------------------------------
const selectFileInformComRef = ref() // 选择文件发放通知单
// 点击选择文件发放通知单
const selectFileInform = () => {
  selectFileInformComRef.value.showOrHideFilterDialog(true)
}

// 选好文件
const confirmSelectFile = (value: any) => {
  const distributor = value.distributor.split(',') // 发放人员id
  const distributorNames = value.distributorNames // 发放人员名称
  const tempStaffUserList = [] as any
  if (distributor && distributor.length) {
    distributor.forEach((item: any) => {
      const index = staffUserList.value.findIndex(i => i.id === item)
      if (index !== -1) {
        const staff = staffUserList.value[index] as any
        tempStaffUserList.push({
          formId: id.value,
          participantId: staff.id!,
          isConform: '0',
          isSign: '0',
          isNoticed: '0',
          staffName: staff.staffName,
          officerNo: staff.officerNo,
          deptName: staff.deptName,
          station: staff.station,
          staffTypeName: staff.staffTypeName,
        })
      }
    })
  }
  console.log('发放人员', tempStaffUserList)

  trainInfo.value.fileNoteCode = value.formNo // 文件发放编号
  // 发放人员列表
  trainInfo.value.participantsList = tempStaffUserList
}
// --------------------------------导出word、pdf、打印----------------------------------------------------
const stream = ref()
const streamNormal = ref(true) // 流是否正常
// 获取流
const fetchStream = async (isPdf = true) => {
  const loading = ElLoading.service({
    lock: true,
    text: '加载中...',
    background: 'rgba(255, 255, 255, 0.6)',
  })
  const res = await getStream({ id: id.value, pdf: isPdf })
  stream.value = res.data
  loading.close()
}

// 打印Word
const printToWord = () => {
  fetchStream(false).then(() => {
    if (streamNormal.value) {
      exportFile(stream.value, '培训签到表.doc')
    }
  })
}

// 导出PDF
const printToPDF = () => {
  fetchStream().then(() => {
    if (streamNormal.value) {
      exportFile(new Blob([stream.value]), '培训签到表.pdf')
    }
  })
}

// 打印
const printClickedHandler = () => {
  fetchStream().then(() => {
    if (streamNormal.value) {
      const blobUrl = URL.createObjectURL(stream.value)
      printPdf(blobUrl)
    }
  })
}
// ------------------------------------------------------------------------------------

// 向参训人员发送通知
const sendToParticipant = () => {
  const participantNameSend = trainInfo.value.participantsList.map((item) => {
    if (item.isNoticed !== '1') {
      return item.staffName
    }
    else {
      return ''
    }
  }).filter(item => item !== '')

  if (participantNameSend.length === 0) {
    ElMessage.warning('所有的用户都已经通知过了,请勿重复发送通知')
  }
  else {
    loading.value = true
    workbenchReminder({ id: id.value }).then((res) => {
      loading.value = false
      if (res.code === 200) {
        ElMessage.success(`向以下用户发送通知成功:\n${participantNameSend.join(',')}`)

        trainInfo.value.participantsList.forEach((item) => {
          if (item.isNoticed !== '1') {
            item.isNoticed = '1'
            item.isNoticedName = '已通知'
          }
        })
      }
    }).catch(() => {
      loading.value = false
    })
  }
}
const title = ref('')
const initDialog = (params: any) => {
  type.value = params.type
  id.value = params.id

  switch (params.type) {
    case 'create' :
      trainInfo.value.createTime = dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss')
      trainInfo.value.host = userInfo.name
      trainInfo.value.labCode = userInfo.bizLabCode // 实验室代码
      trainInfo.value.groupCode = userInfo.groupNo // 部门代码
      trainInfo.value.labCodeName = userInfo.labCodeName // 实验室名称
      trainInfo.value.groupCodeName = userInfo.groupName // 部门名称
      if (route.query.noveltyId) {
        trainInfo.value.noveltyId = route.query.noveltyId as string
      }
      title.value = '培训签到表(新增)'
      break
    case 'update':
      loading.value = true
      detail()
      title.value = '培训签到表(编辑)'
      break
    case 'detail':
      loading.value = true
      detail()
      title.value = '培训签到表(详情)'

      break
    default:
      title.value = ''
      break
  }
}

const getLabCodeDict = async () => {
  if (sessionStorage.getItem('bizLabCode') !== null && sessionStorage.getItem('bizLabCode') !== '') {
    labCodeDict.value = JSON.parse(sessionStorage.getItem('bizLabCode')!)
  }
  else {
    await getDictByCode('bizLabCode').then((res) => {
      if (res.code === 200) {
        labCodeDict.value = res.data
        sessionStorage.setItem('bizLabCode', JSON.stringify(res.data))
      }
    })
  }
}

const getGroupCodeDict = async () => {
  if (sessionStorage.getItem('bizGroupCode') !== null && sessionStorage.getItem('bizGroupCode') !== '') {
    groupCodeDict.value = JSON.parse(sessionStorage.getItem('bizGroupCode')!)
  }
  else {
    await getDictByCode('bizGroupCode').then((res) => {
      if (res.code === 200) {
        groupCodeDict.value = res.data
        sessionStorage.setItem('bizGroupCode', JSON.stringify(res.data))
      }
    })
  }
}

// 参训人员确认
const confirm = () => {
  const params = {
    formId: id.value,
    isSign: '1',
    userId: userInfo.id,
  }
  confirmSign(params).then(() => {
    // ElMessage.success('确认成功')
  })
}

const initDict = () => {
  getLabCodeDict()
  getGroupCodeDict()
}

onMounted(async () => {
  await fetchStaffList() // 获取计量人员
  initDict()
  initDialog(route.query)

  // 从工作台跳转过来需要调签到接口
  const lastPage = `${router.options.history.state.back}` // 上一页的路径
  if (lastPage.includes('workbench') && route.query.fromWorkBench === 'work') { // 从工作台来跳转过来显示编辑标准库按钮
    confirm()
  }
})
</script>

<template>
  <app-container>
    <detail-page :title="title">
      <template #btns>
        <el-button v-if="type === 'detail'" type="primary" @click="sendToParticipant()">
          向参训人员发送通知
        </el-button>

        <template v-if="type === 'detail'">
          <el-button type="primary" @click="printToWord">
            导出Word
          </el-button>
          <el-button type="primary" @click="printToPDF">
            导出PDF
          </el-button>
          <el-button type="primary" @click="printClickedHandler">
            打印
          </el-button>
          <el-button type="primary" @click="editButtHandler()">
            编辑
          </el-button>
        </template>

        <el-button v-if="type !== 'detail'" type="primary" @click="saveTrainForm()">
          保存
        </el-button>
        <el-button type="info" @click="resetForm()">
          关闭
        </el-button>
      </template>

      <el-form ref="basicFormRef" :model="trainInfo" :rules="trainBasicRules" label-position="right" :class="[type === 'detail' ? 'isDetail' : '']" label-width="110" border stripe>
        <el-row :gutter="24">
          <!-- 第一行 第一列 -->
          <el-col :span="6">
            <el-form-item label="实验室" prop="labCode">
              <el-select v-model="trainInfo.labCode" style="width: 100%;" placeholder="请选择实验室" :disabled="type !== 'create'">
                <el-option v-for="site in labCodeDict" :key="site.id" :value="site.value" :label="site.name" />
              </el-select>
            </el-form-item>

            <el-form-item label="时间" prop="trainingTime">
              <el-date-picker
                v-model="trainInfo.trainingTime" type="datetime"
                format="YYYY-MM-DD HH:mm" value-format="YYYY-MM-DD HH:mm:ss"
                placeholder="请选择培训时间" :disabled="type === 'detail'" :clearable="true" style="width: 100%;"
              />
            </el-form-item>
          </el-col>

          <!-- 第一行 第二列 -->
          <el-col :span="6">
            <el-form-item label="部门" prop="groupCode">
              <el-select v-model="trainInfo.groupCode" style="width: 100%;" placeholder="请选择部门" :disabled="type !== 'create'">
                <el-option v-for="dict in groupCodeDict" :key="dict.id" :value="dict.value" :label="dict.name" />
              </el-select>
            </el-form-item>

            <el-form-item label="地点" prop="position">
              <el-input v-model="trainInfo.position" placeholder="地点" :show-word-limit="true" :maxlength="50" :disabled="type === 'detail'" />
            </el-form-item>
          </el-col>

          <!-- 第一行 第三列 -->
          <el-col :span="6">
            <el-form-item label="文件编号">
              <el-input v-model="trainInfo.fileCode" placeholder="系统自动生成" disabled />
            </el-form-item>
            <el-form-item label="主持" prop="host">
              <el-input v-model="trainInfo.host" :clearable="true" placeholder="请输入培训会主持人" :disabled="type === 'detail'" />
            </el-form-item>
          </el-col>

          <!-- 第一行 第四列 -->
          <el-col :span="6">
            <el-form-item label="文件名称">
              <el-input v-model="trainInfo.fileName" disabled />
            </el-form-item>
            <el-form-item label="文件发放通知单">
              <el-input v-model="trainInfo.fileNoteCode" placeholder="文件发放通知单" disabled>
                <template v-if="type !== 'detail'" #append>
                  <el-button @click="selectFileInform">
                    选择
                  </el-button>
                </template>
              </el-input>
            </el-form-item>
          </el-col>
        </el-row>

        <!-- 第二行 -->
        <el-row :gutter="24">
          <el-col :span="24">
            <el-form-item label="内容" prop="content">
              <el-input v-model="trainInfo.content" placeholder="请输入培训内容" type="textarea" :show-word-limit="true" :maxlength="500" :rows="5" :clearable="true" :disabled="type === 'detail'" />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
    </detail-page>

    <el-form ref="staffFormRef" label-position="right" label-width="110px" border stripe>
      <table-container v-loading="loading" title="参加人员" style="margin-top: 20px;">
        <template v-if="type !== 'detail' && !trainInfo.fileNoteCode" #btns-right>
          <el-button type="primary" @click="addEditableRow">
            批量增加
          </el-button>
          <el-button type="info" @click="delTrainStaffRec">
            删除行
          </el-button>
        </template>

        <!-- 表格区域 -->
        <el-table :data="trainInfo.participantsList" :columns="staffColumns" border @selection-change="staffMultiSelect">
          <el-table-column v-if="type !== 'detail'" type="selection" align="center" width="40" />
          <el-table-column align="center" label="序号" width="55" type="index" />
          <el-table-column
            v-for="item in staffColumns"
            :key="item.value"
            :prop="item.value"
            :label="item.text"
            :width="item.width"
            align="center"
          >
            <template #header>
              <span>{{ item.text }}</span>
            </template>
          </el-table-column>
          <el-table-column align="center" label="电子签名" width="240">
            <template #default="scope">
              <el-image v-if="scope.row.signFileUrl" :src="scope.row.signFileUrl" />/>
            </template>
          </el-table-column>
        </el-table>
      </table-container>
    </el-form>
    <filter-grant-notice ref="selectFileInformComRef" @confirm-select="confirmSelectFile" />
    <filter-registed-staff ref="refFilterStaff" @record-selected="recordSelectedHandler" />
  </app-container>
</template>

<style lang="scss" scoped>
.isDetail {
  ::v-deep {
    .el-form-item.is-required:not(.is-no-asterisk) .el-form-item__label-wrap > .el-form-item__label::before,
    .el-form-item.is-required:not(.is-no-asterisk) > .el-form-item__label::before {
      content: "";
      display: none;
    }
  }
}
</style>