5 天以前 22229c67d87f0fae4c4bc90db106b8a1e2c49b53
src/views/collaborativeApproval/sealManagement/index.vue
@@ -7,7 +7,6 @@
        </div>
      </template>
   <!-- 用印申请管理 -->
        <div class="tab-content">
            <el-row :gutter="20" class="mb-20 ">
@@ -75,22 +74,39 @@
        <el-form-item label="申请原因" prop="reason">
          <el-input v-model="sealForm.reason" type="textarea" :rows="4" placeholder="请详细说明用印原因" />
        </el-form-item>
        <el-form-item label="审批人" prop="approveUserId">
          <el-select v-model="sealForm.approveUserId" placeholder="请选择审批人" style="width: 100%" filterable>
            <el-option
                v-for="user in userList"
                :key="user.userId"
                :label="user.nickName"
                :value="user.userId"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="紧急程度" prop="urgency">
          <el-radio-group v-model="sealForm.urgency">
            <el-radio label="normal">普通</el-radio>
            <el-radio label="urgent">紧急</el-radio>
            <el-radio label="very-urgent">特急</el-radio>
            <el-radio value="normal">普通</el-radio>
            <el-radio value="urgent">紧急</el-radio>
            <el-radio value="very-urgent">特急</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="附件上传">
          <el-upload
            multiple
            :show-file-list="false"
            :action="sealUploadUrl"
            name="files"
            :headers="uploadHeaders"
            :limit="10"
            :before-upload="handleBeforeUpload"
            :on-success="handleUploadSuccess"
            :on-error="handleUploadError"
            :on-exceed="handleUploadExceed"
          >
            <el-button type="primary">点击上传附件</el-button>
          </el-upload>
          <el-table v-if="sealForm.attachmentList.length" :data="sealForm.attachmentList" border class="attachment-table">
            <el-table-column label="附件名称" show-overflow-tooltip>
              <template #default="scope">{{ scope.row.name }}</template>
            </el-table-column>
            <el-table-column label="操作" width="140" align="center">
              <template #default="scope">
                <el-button link type="primary" size="small" @click="previewFile(scope.row)">预览</el-button>
                <el-button link type="danger" size="small" @click="removeAttachment(scope.$index)">删除</el-button>
              </template>
            </el-table-column>
          </el-table>
        </el-form-item>
      </el-form>
    </FormDialog>
@@ -119,21 +135,41 @@
          </el-descriptions-item>
          <el-descriptions-item label="申请原因" :span="2">{{ currentSealDetail.reason }}</el-descriptions-item>
        </el-descriptions>
        <!-- 附件列表 -->
        <div v-if="currentSealDetail.commonFileList?.length" class="attachment-section">
          <div class="attachment-title">附件列表:</div>
          <el-table :data="currentSealDetail.commonFileList" border class="attachment-table">
            <el-table-column label="附件名称" show-overflow-tooltip>
              <template #default="scope">
                {{ scope.row.originalFilename || scope.row.name || scope.row.fileName || '未命名文件' }}
              </template>
            </el-table-column>
            <el-table-column fixed="right" label="操作" width="150" align="center">
              <template #default="scope">
                <el-button link type="primary" size="small" @click="previewFile(scope.row)">预览</el-button>
                <el-button link type="primary" size="small" @click="downloadFile(scope.row)">下载</el-button>
              </template>
            </el-table-column>
          </el-table>
        </div>
      </div>
    </FormDialog>
    <!-- 文件预览组件 -->
    <FilePreview ref="filePreviewRef" />
  </div>
</template>
<script setup>
import { ref, reactive, onMounted, getCurrentInstance, watch } from 'vue'
import { ref, reactive, onMounted, getCurrentInstance } from 'vue'
import { useRoute } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { listSealApplication, addSealApplication, updateSealApplication } from '@/api/collaborativeApproval/sealManagement.js'
import { userListNoPageByTenantId } from '@/api/system/user.js'
import { ElMessage } from 'element-plus'
import { listSealApplication, addSealApplication } from '@/api/collaborativeApproval/sealManagement.js'
import useUserStore from '@/store/modules/user'
import { getToken } from '@/utils/auth'
import FormDialog from '@/components/Dialog/FormDialog.vue'
import PIMTable from '@/components/PIMTable/PIMTable.vue'
import FilePreview from '@/components/filePreview/index.vue'
// 响应式数据
// 用印申请相关
@@ -143,24 +179,27 @@
const tableLoading = ref(false)
const showSealDetailDialog = ref(false)
const currentSealDetail = ref(null)
const filePreviewRef = ref(null)
const sealFormRef = ref()
const userList = ref([])
// 附件上传(本地上传,非 minio,返回 [{ name, url }])
const sealUploadUrl = import.meta.env.VITE_APP_BASE_API + '/common/uploadsList'
const uploadHeaders = ref({ Authorization: 'Bearer ' + getToken() })
const sealForm = reactive({
  id: null,
  applicationNum: '',
  title: '',
  sealType: '',
  reason: '',
  approveUserId: '',
  urgency: 'normal',
  status: 'pending'
  status: 'pending',
  attachmentList: []
})
const sealRules = {
  applicationNum: [{ required: true, message: '请输入申请编号', trigger: 'blur' }],
  title: [{ required: true, message: '请输入申请标题', trigger: 'blur' }],
  sealType: [{ required: true, message: '请选择用印类型', trigger: 'change' }],
  reason: [{ required: true, message: '请输入申请原因', trigger: 'blur' }],
  approveUserId: [{ required: true, message: '请选择审批人', trigger: 'change' }]
  reason: [{ required: true, message: '请输入申请原因', trigger: 'blur' }]
}
const sealSearchForm = reactive({
@@ -209,9 +248,9 @@
// 用印申请表格列配置(需在 getStatusText/getSealTypeText 等之后定义)
const sealTableColumn = ref([
  { label: '申请编号', prop: 'applicationNum',},
  { label: '申请编号', prop: 'applicationNum' },
  { label: '申请标题', prop: 'title', showOverflowTooltip: true },
  { label: '申请人', prop: 'createUserName', },
  { label: '申请人', prop: 'createUserName' },
  { label: '所属部门', prop: 'department', width: 150 },
  {
    label: '用印类型',
@@ -229,40 +268,27 @@
    formatData: (v) => getStatusText(v),
    formatType: (v) => getStatusType(v)
  },
  { label: '审批人', prop: 'approveUserName', width: 120 },
  {
    dataType: 'action',
    label: '操作',
    width: 250,
    width: 150,
    fixed: 'right',
    align: 'center',
    operation: [
      { name: '查看', clickFun: (row) => viewSealDetail(row) },
      {
        name: '审批',
        clickFun: (row) => approveSeal(row),
        showHide: (row) => row.status === 'pending' && row.approveUserId === userStore.id
      },
      {
        name: '拒绝',
        clickFun: (row) => rejectSeal(row),
        showHide: (row) => row.status === 'pending' && row.approveUserId === userStore.id
      },
      {
        name: '重新申请',
        clickFun: (row) => reapplySeal(row),
        showHide: (row) => row.status === 'rejected' && row.createUser === userStore.id
      }
        showHide: (row) => row.status === 'rejected' && Number(userStore.id) === row.createUser
      },
      { name: '详情', clickFun: (row) => viewSealDetail(row) }
    ]
  }
])
// 搜索印章申请
const searchSealApplications = () => {
  page.current=1
  page.current = 1
  getSealApplicationList()
  // ElMessage.success('搜索完成')
}
// 重置印章申请搜索
const resetSealSearch = () => {
@@ -271,43 +297,52 @@
  sealSearchForm.applicationNum = ''
  searchSealApplications()
}
// 提交用印申请
// 重新申请用印
const reapplySeal = (row) => {
  // 预填表单数据
  Object.assign(sealForm, {
    id: row.id,
    applicationNum: row.applicationNum,
    title: row.title,
    sealType: row.sealType,
    reason: row.reason,
    urgency: row.urgency || 'normal',
    status: 'pending',
    attachmentList: row.commonFileList || []
  })
  showSealApplyDialog.value = true
}
// 提交用印申请(新增与重新申请均走 add 接口:重新申请会重新发起协同审批流程)
const submitSealApplication = async () => {
  try {
    await sealFormRef.value.validate()
    addSealApplication(sealForm).then(res => {
      if(res.code == 200){
        ElMessage.success('申请提交成功')
      if (res.code == 200) {
        ElMessage.success(sealForm.id ? '重新申请成功' : '申请提交成功')
        closeSealApplyDialog()
        getSealApplicationList()
        Object.assign(sealForm, {
        applicationNum: '',
        title: '',
        sealType: '',
        reason: '',
        approveUserId: '',
        urgency: 'normal',
        status: 'pending'
      })
      }
    }).catch(err => {
      console.log(err.msg)
    })
  } catch (error) {
  }
}
// 关闭用印申请对话框
const closeSealApplyDialog = () => {
  // 清空表单数据
  Object.assign(sealForm, {
    id: null,
    applicationNum: '',
    title: '',
    sealType: '',
    reason: '',
    approveUserId: '',
    urgency: 'normal',
    status: 'pending'
    status: 'pending',
    attachmentList: []
  })
  // 清除表单验证状态
  if (sealFormRef.value) {
@@ -325,55 +360,64 @@
  currentSealDetail.value = row
  showSealDetailDialog.value = true
}
// 审批用印申请
const approveSeal = (row) => {
  ElMessageBox.confirm('确认通过该用印申请?', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(() => {
    row.status = 'approved'
    updateSealApplication(row).then(res => {
      if(res.code == 200){
        ElMessage.success('审批通过')
        getSealApplicationList()
      }
    })
  })
// 附件上传前校验(单个文件不超过 50MB)
const handleBeforeUpload = (file) => {
  if (file.size / 1024 / 1024 > 50) {
    ElMessage.error('文件大小不能超过 50MB')
    return false
  }
  return true
}
// 拒绝用印申请
const rejectSeal = (row) => {
  ElMessageBox.prompt('请输入拒绝原因', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    inputPattern: /\S+/,
    inputErrorMessage: '拒绝原因不能为空'
  }).then(({ value }) => {
    row.status = 'rejected'
    updateSealApplication(row).then(res => {
      if(res.code == 200){
        ElMessage.success('已拒绝申请')
        getSealApplicationList()
      }
    })
  })
// 附件上传成功回调
const handleUploadSuccess = (res) => {
  if (res.code === 200) {
    const list = res.data || []
    list.forEach(item => sealForm.attachmentList.push({ name: item.name, url: item.url }))
    ElMessage.success('上传成功')
  } else {
    ElMessage.error(res.msg || '上传失败')
  }
}
// 附件上传失败回调
const handleUploadError = () => {
  ElMessage.error('附件上传失败')
}
// 附件数量超出
const handleUploadExceed = () => {
  ElMessage.warning('最多上传 10 个附件')
}
// 删除待提交附件
const removeAttachment = (index) => {
  sealForm.attachmentList.splice(index, 1)
}
// 预览文件(完整可访问 URL,直接打开,不拼 host)
const previewFile = (row) => {
  const url = row.previewURL || row.previewUrl || row.url
  if (url && filePreviewRef.value) {
    filePreviewRef.value.openUrl(url)
  } else {
    ElMessage.warning('文件地址无效,无法预览')
  }
}
// 重新申请用印
const reapplySeal = (row) => {
  // 预填表单数据
  Object.assign(sealForm, {
    applicationNum: row.applicationNum,
    title: row.title,
    sealType: row.sealType,
    reason: row.reason,
    approveUserId: row.approveUserId,
    urgency: row.urgency || 'normal',
    status: 'pending'
  })
  showSealApplyDialog.value = true
// 下载文件
const downloadFile = (row) => {
  const url = row.downloadURL || row.downloadUrl || row.url
  if (url) {
    const filename = row.originalFilename || row.name || row.fileName || 'download'
    const a = document.createElement('a')
    a.href = url
    a.download = filename
    a.target = '_blank'
    a.rel = 'noopener noreferrer'
    document.body.appendChild(a)
    a.click()
    document.body.removeChild(a)
  } else {
    ElMessage.warning('文件地址无效,无法下载')
  }
}
// 导出用印申请
const { proxy } = getCurrentInstance()
const handleExport = () => {
@@ -384,13 +428,13 @@
const getSealApplicationList = async () => {
  tableLoading.value = true
  listSealApplication(page, sealSearchForm)
  .then(res => {
    sealApplications.value = res.data.records
    page.total = res.data.total
    tableLoading.value = false
  }).catch(err => {
    tableLoading.value = false
  })
    .then(res => {
      sealApplications.value = res.data.records
      page.total = res.data.total
      tableLoading.value = false
    }).catch(err => {
      tableLoading.value = false
    })
}
// 分页变化处理
const paginationChange = (obj) => {
@@ -398,15 +442,6 @@
  page.size = obj.limit;
  getSealApplicationList();
};
// 监听对话框打开,获取用户列表
watch(showSealApplyDialog, (newVal) => {
  if (newVal) {
    userListNoPageByTenantId().then((res) => {
      userList.value = res.data;
    });
  }
});
onMounted(() => {
  // 路由携带 applicationNum 时,预填并查询
@@ -442,4 +477,19 @@
.ml-10 {
  margin-left: 10px;
}
</style>
.attachment-section {
  margin-top: 20px;
}
.attachment-title {
  font-size: 14px;
  color: #606266;
  margin-bottom: 10px;
  font-weight: 500;
}
.attachment-table {
  border-radius: 4px;
}
</style>