|
|
@@ -0,0 +1,790 @@
|
|
|
+<template>
|
|
|
+ <div class="revoke-application-approval">
|
|
|
+ <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
|
|
+ <div v-show="showSearch" class="mb-[10px]">
|
|
|
+ <el-card shadow="hover">
|
|
|
+ <el-form ref="queryFormRef" :model="queryParams">
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="学号" prop="studentNo">
|
|
|
+ <el-input v-model="queryParams.studentNo" placeholder="请输入学号" clearable @keyup.enter="handleQuery" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="学生姓名" prop="studentName">
|
|
|
+ <el-input v-model="queryParams.studentName" placeholder="请输入学生姓名" clearable @keyup.enter="handleQuery" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8" v-if="activeTab === 'reviewed'">
|
|
|
+ <el-form-item label="审核结果" prop="status">
|
|
|
+ <el-select v-model="queryParams.status" placeholder="请选择审核结果" clearable>
|
|
|
+ <el-option label="审核通过" value="3" />
|
|
|
+ <el-option label="审核拒绝" value="5" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8" v-else>
|
|
|
+ <el-form-item label="状态" prop="status">
|
|
|
+ <el-select v-model="queryParams.status" placeholder="请选择状态" clearable>
|
|
|
+ <el-option v-for="dict in student_revoke_status" :key="dict.value" :label="dict.label" :value="dict.value" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ <el-row>
|
|
|
+ <el-col :span="24" class="search-btn-container">
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
|
|
+ <el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </el-form>
|
|
|
+ </el-card>
|
|
|
+ </div>
|
|
|
+ </transition>
|
|
|
+
|
|
|
+ <el-card shadow="never">
|
|
|
+ <template #header>
|
|
|
+ <el-row :gutter="10" class="mb8">
|
|
|
+ <el-col :span="1.5">
|
|
|
+ <span class="text-lg font-medium">学工处违纪撤销申请审核管理</span>
|
|
|
+ </el-col>
|
|
|
+ <right-toolbar :showSearch="showSearch" @update:showSearch="showSearch = $event" @queryTable="getList"></right-toolbar>
|
|
|
+ </el-row>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <el-tabs v-model="activeTab" @tab-change="handleTabChange" class="tab-container">
|
|
|
+ <!-- 待审核申请 Tab -->
|
|
|
+ <el-tab-pane label="待审核申请" name="pending">
|
|
|
+ <el-table v-loading="loading" border :data="revokeApplicationList" class="full-width-table">
|
|
|
+ <el-table-column label="学号" align="center" prop="studentNo" min-width="120" />
|
|
|
+ <el-table-column label="学生姓名" align="center" prop="studentName" min-width="100" />
|
|
|
+ <el-table-column label="违纪类型" align="center" prop="disciplineTypeName" min-width="140" show-overflow-tooltip />
|
|
|
+ <el-table-column label="违纪日期" align="center" prop="disciplineDate" min-width="130" />
|
|
|
+ <el-table-column label="撤销原因" align="center" prop="revokeReason" min-width="200" show-overflow-tooltip />
|
|
|
+ <el-table-column label="申请时间" align="center" prop="applyTime" min-width="160" />
|
|
|
+ <el-table-column label="班主任审核" align="center" min-width="120">
|
|
|
+ <template #default="scope">
|
|
|
+ <div v-if="scope.row.teacherApprovalTime">
|
|
|
+ <div>{{ scope.row.teacherApprovalByName }}</div>
|
|
|
+ <div class="text-xs text-gray-500">{{ scope.row.teacherApprovalTime }}</div>
|
|
|
+ </div>
|
|
|
+ <span v-else class="text-gray-400">-</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="状态" align="center" prop="status" min-width="100">
|
|
|
+ <template #default="scope">
|
|
|
+ <dict-tag :options="student_revoke_status" :value="scope.row.status" />
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="200">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-tooltip content="查看" placement="top">
|
|
|
+ <el-button
|
|
|
+ link
|
|
|
+ type="primary"
|
|
|
+ icon="View"
|
|
|
+ @click="handleView(scope.row)"
|
|
|
+ v-hasPermi="['disciplineRevoke:studentAffairs:query']"
|
|
|
+ ></el-button>
|
|
|
+ </el-tooltip>
|
|
|
+ <el-tooltip content="审核通过" placement="top" v-if="scope.row.status === '2'">
|
|
|
+ <el-button
|
|
|
+ link
|
|
|
+ type="success"
|
|
|
+ icon="CircleCheck"
|
|
|
+ @click="handleApprove(scope.row, '3')"
|
|
|
+ v-hasPermi="['disciplineRevoke:studentAffairs:approve']"
|
|
|
+ ></el-button>
|
|
|
+ </el-tooltip>
|
|
|
+ <el-tooltip content="审核驳回" placement="top" v-if="scope.row.status === '2'">
|
|
|
+ <el-button
|
|
|
+ link
|
|
|
+ type="danger"
|
|
|
+ icon="CircleClose"
|
|
|
+ @click="handleApprove(scope.row, '5')"
|
|
|
+ v-hasPermi="['disciplineRevoke:studentAffairs:approve']"
|
|
|
+ ></el-button>
|
|
|
+ </el-tooltip>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <pagination v-show="total > 0" :total="total" :page="queryParams.pageNum" :limit="queryParams.pageSize" @pagination="getList" />
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+ <!-- 已审核记录 Tab -->
|
|
|
+ <el-tab-pane label="已审核记录" name="reviewed">
|
|
|
+ <el-table v-loading="loading" border :data="reviewedApplicationList" class="full-width-table">
|
|
|
+ <el-table-column label="学号" align="center" prop="studentNo" min-width="120" />
|
|
|
+ <el-table-column label="学生姓名" align="center" prop="studentName" min-width="100" />
|
|
|
+ <el-table-column label="违纪类型" align="center" prop="disciplineTypeName" min-width="140" show-overflow-tooltip />
|
|
|
+ <el-table-column label="违纪日期" align="center" prop="disciplineDate" min-width="130" />
|
|
|
+ <el-table-column label="撤销原因" align="center" prop="revokeReason" min-width="200" show-overflow-tooltip />
|
|
|
+ <el-table-column label="申请时间" align="center" prop="applyTime" min-width="160" />
|
|
|
+ <el-table-column label="班主任审核" align="center" min-width="120">
|
|
|
+ <template #default="scope">
|
|
|
+ <div v-if="scope.row.teacherApprovalTime">
|
|
|
+ <div>{{ scope.row.teacherApprovalByName }}</div>
|
|
|
+ <div class="text-xs text-gray-500">{{ scope.row.teacherApprovalTime }}</div>
|
|
|
+ </div>
|
|
|
+ <span v-else class="text-gray-400">-</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="学工处审核" align="center" min-width="150">
|
|
|
+ <template #default="scope">
|
|
|
+ <div v-if="scope.row.approvalTime">
|
|
|
+ <div>{{ scope.row.approvalByName || '学工处' }}</div>
|
|
|
+ <div class="text-xs text-gray-500">{{ scope.row.approvalTime }}</div>
|
|
|
+ </div>
|
|
|
+ <span v-else class="text-gray-400">-</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="审核结果" align="center" prop="status" min-width="100">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-tag :type="scope.row.status === '3' ? 'success' : 'danger'">
|
|
|
+ {{ scope.row.status === '3' ? '审核通过' : '审核拒绝' }}
|
|
|
+ </el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="审核备注" align="center" prop="approvalRemark" min-width="200" show-overflow-tooltip />
|
|
|
+ <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="120">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-tooltip content="查看" placement="top">
|
|
|
+ <el-button
|
|
|
+ link
|
|
|
+ type="primary"
|
|
|
+ icon="View"
|
|
|
+ @click="handleView(scope.row)"
|
|
|
+ v-hasPermi="['disciplineRevoke:studentAffairs:query']"
|
|
|
+ ></el-button>
|
|
|
+ </el-tooltip>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <pagination
|
|
|
+ v-show="reviewedTotal > 0"
|
|
|
+ :total="reviewedTotal"
|
|
|
+ :page="queryParams.pageNum"
|
|
|
+ :limit="queryParams.pageSize"
|
|
|
+ @pagination="getList"
|
|
|
+ />
|
|
|
+ </el-tab-pane>
|
|
|
+ </el-tabs>
|
|
|
+ </el-card>
|
|
|
+
|
|
|
+ <!-- 查看撤销申请对话框 -->
|
|
|
+ <RevokeApplicationView ref="revokeApplicationViewRef" />
|
|
|
+
|
|
|
+ <!-- 审核对话框 -->
|
|
|
+ <el-dialog :title="approvalDialog.title" v-model="approvalDialog.visible" width="600px" append-to-body destroy-on-close>
|
|
|
+ <el-form ref="approvalFormRef" :model="approvalForm" :rules="approvalRules" label-width="120px">
|
|
|
+ <el-form-item label="学生姓名">
|
|
|
+ <el-input v-model="approvalForm.studentName" disabled />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="审核结果">
|
|
|
+ <el-input v-model="approvalForm.statusText" disabled />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="审核时间">
|
|
|
+ <el-input v-model="approvalForm.approvalTime" disabled />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="撤销申请原因">
|
|
|
+ <el-input v-model="approvalForm.revokeReason" type="textarea" :rows="3" disabled />
|
|
|
+ </el-form-item>
|
|
|
+ <!-- 撤销证明材料展示(只读) -->
|
|
|
+ <el-form-item label="撤销证明材料" v-if="revokeAttachmentList && revokeAttachmentList.length > 0">
|
|
|
+ <div class="attachment-view-container">
|
|
|
+ <div class="attachment-view-grid">
|
|
|
+ <div v-for="file in revokeAttachmentList" :key="file.uid" class="upload-file-card">
|
|
|
+ <div class="upload-file-thumb">
|
|
|
+ <image-preview v-if="isImageFile(file) && file.url" :src="getFileOssId(file)" class="upload-thumb-image" :isOssId="true" />
|
|
|
+ <div v-else class="upload-file-placeholder">
|
|
|
+ <el-icon><Document /></el-icon>
|
|
|
+ <span class="file-ext">{{ getFileExt(file.name) }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="upload-file-name" :title="file.name">
|
|
|
+ {{ getShortFileName(file.name) }}
|
|
|
+ </div>
|
|
|
+ <div class="upload-file-card-actions">
|
|
|
+ <el-button type="success" size="small" @click.stop="handleDownloadAttachment(file)" title="下载">
|
|
|
+ <el-icon><Download /></el-icon>
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="班主任审核意见" v-if="approvalForm.teacherApprovalRemark">
|
|
|
+ <el-input v-model="approvalForm.teacherApprovalRemark" type="textarea" :rows="2" disabled />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="学工处审核备注" prop="approvalRemark">
|
|
|
+ <el-input v-model="approvalForm.approvalRemark" type="textarea" placeholder="请输入学工处审核备注" :rows="4" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <template #footer>
|
|
|
+ <div class="dialog-footer">
|
|
|
+ <el-button :loading="buttonLoading" type="primary" @click="submitApproval">确 定</el-button>
|
|
|
+ <el-button @click="cancelApproval">取 消</el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup name="StudentAffairsRevokeApproval" lang="ts">
|
|
|
+import { ref, reactive, toRefs, onMounted, getCurrentInstance } from 'vue';
|
|
|
+import { Document, Download } from '@element-plus/icons-vue';
|
|
|
+import { ElMessage, ElLoading } from 'element-plus';
|
|
|
+import ImagePreview from '@/components/ImagePreview/index.vue';
|
|
|
+import request from '@/utils/request';
|
|
|
+import RevokeApplicationView from '../xsDisciplineRecord/RevokeApplicationView.vue';
|
|
|
+
|
|
|
+const { proxy } = getCurrentInstance();
|
|
|
+const { student_revoke_status } = toRefs<any>(proxy?.useDict('student_revoke_status'));
|
|
|
+
|
|
|
+const revokeApplicationList = ref<any[]>([]);
|
|
|
+const reviewedApplicationList = ref<any[]>([]);
|
|
|
+const loading = ref(true);
|
|
|
+const showSearch = ref(true);
|
|
|
+const total = ref(0);
|
|
|
+const reviewedTotal = ref(0);
|
|
|
+const buttonLoading = ref(false);
|
|
|
+const activeTab = ref('pending');
|
|
|
+
|
|
|
+// 撤销申请附件数据
|
|
|
+const revokeAttachmentList = ref<any[]>([]);
|
|
|
+
|
|
|
+const queryFormRef = ref();
|
|
|
+const revokeApplicationViewRef = ref();
|
|
|
+const approvalFormRef = ref();
|
|
|
+
|
|
|
+interface QueryParams {
|
|
|
+ pageNum: number;
|
|
|
+ pageSize: number;
|
|
|
+ studentNo?: string;
|
|
|
+ studentName?: string;
|
|
|
+ status?: string;
|
|
|
+ params: Record<string, any>;
|
|
|
+}
|
|
|
+
|
|
|
+const data = reactive<{
|
|
|
+ form: Record<string, any>;
|
|
|
+ queryParams: QueryParams;
|
|
|
+}>({
|
|
|
+ form: {},
|
|
|
+ queryParams: {
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ studentNo: undefined,
|
|
|
+ studentName: undefined,
|
|
|
+ status: undefined,
|
|
|
+ params: {}
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+const { queryParams } = toRefs(data);
|
|
|
+
|
|
|
+// 审核对话框
|
|
|
+const approvalDialog = reactive({
|
|
|
+ visible: false,
|
|
|
+ title: ''
|
|
|
+});
|
|
|
+
|
|
|
+const approvalForm = ref({
|
|
|
+ id: undefined,
|
|
|
+ disciplineRecordId: undefined,
|
|
|
+ studentName: '',
|
|
|
+ status: '',
|
|
|
+ statusText: '',
|
|
|
+ approvalTime: '',
|
|
|
+ revokeReason: '',
|
|
|
+ teacherApprovalRemark: '',
|
|
|
+ approvalRemark: ''
|
|
|
+});
|
|
|
+
|
|
|
+const approvalRules = reactive({
|
|
|
+ approvalRemark: [{ required: true, message: '审核备注不能为空', trigger: 'blur' }]
|
|
|
+});
|
|
|
+
|
|
|
+/** 查询学工处待审核的撤销申请列表 */
|
|
|
+const getList = async () => {
|
|
|
+ if (activeTab.value === 'pending') {
|
|
|
+ await getPendingList();
|
|
|
+ } else {
|
|
|
+ await getReviewedList();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取待审核申请列表 */
|
|
|
+const getPendingList = async () => {
|
|
|
+ loading.value = true;
|
|
|
+ try {
|
|
|
+ // 待审核状态,只查询班主任已审核通过的记录(状态为2)
|
|
|
+ const params = { ...queryParams.value };
|
|
|
+ if (!params.status) {
|
|
|
+ params.status = '2'; // 默认查询待学工处审核的记录
|
|
|
+ }
|
|
|
+
|
|
|
+ const res = await request({
|
|
|
+ url: '/disciplineRevoke/disciplineRevoke/studentAffairsList',
|
|
|
+ method: 'get',
|
|
|
+ params: params
|
|
|
+ });
|
|
|
+ revokeApplicationList.value = res.rows || [];
|
|
|
+ total.value = res.total || 0;
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取学工处待审核撤销申请列表失败:', error);
|
|
|
+ revokeApplicationList.value = [];
|
|
|
+ total.value = 0;
|
|
|
+ } finally {
|
|
|
+ loading.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取已审核记录列表 */
|
|
|
+const getReviewedList = async () => {
|
|
|
+ loading.value = true;
|
|
|
+ try {
|
|
|
+ // 已审核状态,查询状态为3(通过)或5(拒绝)的记录
|
|
|
+ const params = { ...queryParams.value };
|
|
|
+ if (!params.status) {
|
|
|
+ // 如果没有指定状态,查询所有已审核的记录
|
|
|
+ params.params.statusList = '3,5';
|
|
|
+ }
|
|
|
+
|
|
|
+ const res = await request({
|
|
|
+ url: '/disciplineRevoke/disciplineRevoke/studentAffairsReviewedList',
|
|
|
+ method: 'get',
|
|
|
+ params: params
|
|
|
+ });
|
|
|
+ reviewedApplicationList.value = res.rows || [];
|
|
|
+ reviewedTotal.value = res.total || 0;
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取学工处已审核撤销申请列表失败:', error);
|
|
|
+ reviewedApplicationList.value = [];
|
|
|
+ reviewedTotal.value = 0;
|
|
|
+ } finally {
|
|
|
+ loading.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 搜索按钮操作 */
|
|
|
+const handleQuery = () => {
|
|
|
+ queryParams.value.pageNum = 1;
|
|
|
+ getList();
|
|
|
+};
|
|
|
+
|
|
|
+/** 重置按钮操作 */
|
|
|
+const resetQuery = () => {
|
|
|
+ queryFormRef.value?.resetFields();
|
|
|
+ handleQuery();
|
|
|
+};
|
|
|
+
|
|
|
+/** Tab切换处理 */
|
|
|
+const handleTabChange = (tabName: string) => {
|
|
|
+ activeTab.value = tabName;
|
|
|
+ // 重置查询参数
|
|
|
+ queryParams.value.pageNum = 1;
|
|
|
+ queryParams.value.status = undefined;
|
|
|
+ // 重新加载数据
|
|
|
+ getList();
|
|
|
+};
|
|
|
+
|
|
|
+/** 查看按钮操作 */
|
|
|
+const handleView = (row: any) => {
|
|
|
+ revokeApplicationViewRef.value?.openDialog(row.disciplineRecordId, '查看');
|
|
|
+};
|
|
|
+
|
|
|
+/** 审核按钮操作 */
|
|
|
+const handleApprove = async (row: any, status: string) => {
|
|
|
+ approvalForm.value = {
|
|
|
+ id: row.id,
|
|
|
+ disciplineRecordId: row.disciplineRecordId,
|
|
|
+ studentName: row.studentName,
|
|
|
+ status: status,
|
|
|
+ statusText: status === '3' ? '学工处审核通过' : '学工处审核拒绝',
|
|
|
+ approvalTime: new Date().toLocaleString(),
|
|
|
+ revokeReason: row.revokeReason || '',
|
|
|
+ teacherApprovalRemark: row.teacherApprovalRemark || '',
|
|
|
+ approvalRemark: ''
|
|
|
+ };
|
|
|
+
|
|
|
+ // 加载撤销申请的证明材料
|
|
|
+ if (row.revokeEvidence) {
|
|
|
+ await handleRevokeAttachmentData(row.revokeEvidence);
|
|
|
+ } else {
|
|
|
+ revokeAttachmentList.value = [];
|
|
|
+ }
|
|
|
+
|
|
|
+ approvalDialog.title = status === '3' ? '学工处审核通过' : '学工处审核拒绝';
|
|
|
+ approvalDialog.visible = true;
|
|
|
+};
|
|
|
+
|
|
|
+/** 提交审核 */
|
|
|
+const submitApproval = () => {
|
|
|
+ approvalFormRef.value?.validate(async (valid: boolean) => {
|
|
|
+ if (valid) {
|
|
|
+ buttonLoading.value = true;
|
|
|
+ try {
|
|
|
+ await request({
|
|
|
+ url: '/disciplineRevoke/disciplineRevoke/studentAffairsApprove',
|
|
|
+ method: 'put',
|
|
|
+ data: {
|
|
|
+ id: approvalForm.value.id,
|
|
|
+ disciplineRecordId: approvalForm.value.disciplineRecordId,
|
|
|
+ status: approvalForm.value.status,
|
|
|
+ revokeReason: approvalForm.value.revokeReason,
|
|
|
+ approvalRemark: approvalForm.value.approvalRemark
|
|
|
+ }
|
|
|
+ });
|
|
|
+ proxy?.$modal.msgSuccess('审核成功');
|
|
|
+ approvalDialog.visible = false;
|
|
|
+ getList();
|
|
|
+ } catch (error) {
|
|
|
+ console.error('审核失败:', error);
|
|
|
+ proxy?.$modal.msgError('审核失败');
|
|
|
+ } finally {
|
|
|
+ buttonLoading.value = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+/** 取消审核 */
|
|
|
+const cancelApproval = () => {
|
|
|
+ approvalDialog.visible = false;
|
|
|
+ approvalForm.value = {
|
|
|
+ id: undefined,
|
|
|
+ disciplineRecordId: undefined,
|
|
|
+ studentName: '',
|
|
|
+ status: '',
|
|
|
+ statusText: '',
|
|
|
+ approvalTime: '',
|
|
|
+ revokeReason: '',
|
|
|
+ teacherApprovalRemark: '',
|
|
|
+ approvalRemark: ''
|
|
|
+ };
|
|
|
+ // 重置附件数据
|
|
|
+ revokeAttachmentList.value = [];
|
|
|
+};
|
|
|
+
|
|
|
+// 文件处理方法
|
|
|
+const isImageFile = (file: any) => {
|
|
|
+ const imageTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/bmp', 'image/webp'];
|
|
|
+ return imageTypes.includes(file.raw?.type) || (file.url && /\.(jpg|jpeg|png|gif|bmp|webp)$/i.test(file.name));
|
|
|
+};
|
|
|
+
|
|
|
+const getFileOssId = (file: any) => {
|
|
|
+ return file.ossId || '';
|
|
|
+};
|
|
|
+
|
|
|
+const getFileExt = (fileName: string) => {
|
|
|
+ const ext = fileName.split('.').pop()?.toUpperCase();
|
|
|
+ return ext || 'FILE';
|
|
|
+};
|
|
|
+
|
|
|
+const getShortFileName = (fileName: string) => {
|
|
|
+ if (!fileName) return '';
|
|
|
+ const lastDotIndex = fileName.lastIndexOf('.');
|
|
|
+ if (lastDotIndex === -1) {
|
|
|
+ return fileName.length > 12 ? fileName.substring(0, 12) + '...' : fileName;
|
|
|
+ }
|
|
|
+ const name = fileName.substring(0, lastDotIndex);
|
|
|
+ const ext = fileName.substring(lastDotIndex);
|
|
|
+ if (name.length <= 8) {
|
|
|
+ return fileName;
|
|
|
+ }
|
|
|
+ return name.substring(0, 8) + '...' + ext;
|
|
|
+};
|
|
|
+
|
|
|
+const handleDownloadAttachment = async (file: any) => {
|
|
|
+ let downloadUrl = '';
|
|
|
+ let fileName = file.name || 'attachment';
|
|
|
+
|
|
|
+ if (file.response && file.response.data && file.response.data.filePath) {
|
|
|
+ downloadUrl = file.response.data.filePath;
|
|
|
+ fileName = file.response.data.fileName || fileName;
|
|
|
+ } else if (file.ossId) {
|
|
|
+ downloadUrl = file.ossId;
|
|
|
+ } else if (file.raw) {
|
|
|
+ const link = document.createElement('a');
|
|
|
+ link.href = URL.createObjectURL(file.raw);
|
|
|
+ link.download = fileName;
|
|
|
+ link.style.display = 'none';
|
|
|
+ document.body.appendChild(link);
|
|
|
+ link.click();
|
|
|
+ document.body.removeChild(link);
|
|
|
+ URL.revokeObjectURL(link.href);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!downloadUrl) {
|
|
|
+ ElMessage.error('无法获取文件下载地址');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ const loading = ElLoading.service({
|
|
|
+ text: '正在下载文件...',
|
|
|
+ target: document.body
|
|
|
+ });
|
|
|
+
|
|
|
+ const response = await request({
|
|
|
+ url: '/resource/oss/download/' + downloadUrl,
|
|
|
+ method: 'get',
|
|
|
+ responseType: 'blob',
|
|
|
+ timeout: 300000
|
|
|
+ });
|
|
|
+
|
|
|
+ if (!response) {
|
|
|
+ throw new Error('响应数据为空');
|
|
|
+ }
|
|
|
+
|
|
|
+ let blobData: Blob;
|
|
|
+ if (response instanceof Blob) {
|
|
|
+ blobData = response;
|
|
|
+ } else if (response.data instanceof Blob) {
|
|
|
+ blobData = response.data;
|
|
|
+ } else {
|
|
|
+ throw new Error('无效的响应数据格式');
|
|
|
+ }
|
|
|
+
|
|
|
+ const url = window.URL.createObjectURL(blobData);
|
|
|
+ const link = document.createElement('a');
|
|
|
+ link.href = url;
|
|
|
+ link.download = fileName;
|
|
|
+ link.style.display = 'none';
|
|
|
+ document.body.appendChild(link);
|
|
|
+ link.click();
|
|
|
+ document.body.removeChild(link);
|
|
|
+ window.URL.revokeObjectURL(url);
|
|
|
+ loading?.close();
|
|
|
+ } catch (error) {
|
|
|
+ console.error('下载文件失败:', error);
|
|
|
+ ElMessage.error('下载文件失败,请稍后重试');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const handleRevokeAttachmentData = async (revokeEvidence: string) => {
|
|
|
+ try {
|
|
|
+ if (!revokeEvidence || !revokeEvidence.toString().trim()) {
|
|
|
+ revokeAttachmentList.value = [];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const ossIdsArray = revokeEvidence
|
|
|
+ .toString()
|
|
|
+ .split(',')
|
|
|
+ .map((id: string) => id.trim())
|
|
|
+ .filter((id: string) => id);
|
|
|
+
|
|
|
+ if (ossIdsArray.length === 0) {
|
|
|
+ revokeAttachmentList.value = [];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const response = await request({
|
|
|
+ url: `/resource/oss/listByIds/${ossIdsArray.join(',')}`,
|
|
|
+ method: 'get'
|
|
|
+ });
|
|
|
+
|
|
|
+ if (response.code === 200 && response.data) {
|
|
|
+ const attachmentFiles = response.data.map((item: any, index: number) => ({
|
|
|
+ uid: `revoke_${index}_${Date.now()}`,
|
|
|
+ name: item.originalName || `撤销证明${index + 1}`,
|
|
|
+ url: item.url,
|
|
|
+ ossId: item.ossId,
|
|
|
+ status: 'success'
|
|
|
+ }));
|
|
|
+
|
|
|
+ revokeAttachmentList.value = attachmentFiles;
|
|
|
+ } else {
|
|
|
+ revokeAttachmentList.value = [];
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('处理撤销申请附件数据失败:', error);
|
|
|
+ revokeAttachmentList.value = [];
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ getList();
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+/* 搜索按钮容器样式 */
|
|
|
+.search-btn-container {
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ margin-top: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.search-btn-container .el-form-item {
|
|
|
+ margin-bottom: 0 !important;
|
|
|
+}
|
|
|
+
|
|
|
+/* 表格全宽样式 */
|
|
|
+.full-width-table {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+/* 确保表格容器充满宽度 */
|
|
|
+:deep(.el-table) {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+/* 表格内容区域充满宽度 */
|
|
|
+:deep(.el-table__body-wrapper) {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+/* 文件卡片样式 */
|
|
|
+.upload-file-card {
|
|
|
+ position: relative;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ border-radius: 6px;
|
|
|
+ overflow: hidden;
|
|
|
+ background: #fff;
|
|
|
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
|
+ transition: all 0.3s;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-file-card:hover {
|
|
|
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
|
|
+}
|
|
|
+
|
|
|
+.upload-file-thumb {
|
|
|
+ position: relative;
|
|
|
+ width: 100%;
|
|
|
+ height: 110px;
|
|
|
+ background: #f5f5f5;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-thumb-image {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ object-fit: cover;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-file-placeholder {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ color: #909399;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-file-placeholder .el-icon {
|
|
|
+ font-size: 28px;
|
|
|
+ margin-bottom: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.file-ext {
|
|
|
+ font-size: 12px;
|
|
|
+ text-transform: uppercase;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-file-name {
|
|
|
+ padding: 6px 8px;
|
|
|
+ font-size: 11px;
|
|
|
+ color: #303133;
|
|
|
+ text-align: center;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+ background: #fafafa;
|
|
|
+ border-top: 1px solid #f0f0f0;
|
|
|
+ line-height: 1.2;
|
|
|
+ height: 32px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ word-break: break-all;
|
|
|
+ max-width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-file-card-actions {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ padding: 6px 8px;
|
|
|
+ background: #fafafa;
|
|
|
+ border-top: 1px solid #f0f0f0;
|
|
|
+ transition: all 0.3s;
|
|
|
+ height: 38px;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-file-card-actions .el-button {
|
|
|
+ padding: 4px 8px;
|
|
|
+ border: 1px solid #e0e0e0;
|
|
|
+ background: #fff;
|
|
|
+ font-size: 12px;
|
|
|
+ border-radius: 3px;
|
|
|
+ transition: all 0.3s;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-file-card-actions .el-button:hover {
|
|
|
+ background: #f5f5f5;
|
|
|
+ border-color: #409eff;
|
|
|
+}
|
|
|
+
|
|
|
+/* 查看模式下的附件网格展示 */
|
|
|
+.attachment-view-container {
|
|
|
+ width: 100%;
|
|
|
+ max-height: 300px;
|
|
|
+ min-height: 150px;
|
|
|
+ overflow-y: auto;
|
|
|
+ padding-right: 8px;
|
|
|
+ border: 1px solid #e4e7ed;
|
|
|
+ border-radius: 6px;
|
|
|
+ background: #fafafa;
|
|
|
+}
|
|
|
+
|
|
|
+.attachment-view-grid {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(4, 1fr);
|
|
|
+ gap: 9px;
|
|
|
+ margin: 12px;
|
|
|
+ padding-bottom: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+/* Tab 容器样式 */
|
|
|
+.tab-container {
|
|
|
+ margin-top: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.tab-container :deep(.el-tabs__header) {
|
|
|
+ margin-bottom: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.tab-container :deep(.el-tabs__nav-wrap) {
|
|
|
+ padding-left: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.tab-container :deep(.el-tabs__item) {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 500;
|
|
|
+ padding: 0 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.tab-container :deep(.el-tabs__item.is-active) {
|
|
|
+ /* color: #409eff; */
|
|
|
+}
|
|
|
+
|
|
|
+.tab-container :deep(.el-tabs__content) {
|
|
|
+ padding-top: 0;
|
|
|
+}
|
|
|
+</style>
|