|
|
@@ -0,0 +1,475 @@
|
|
|
+<template>
|
|
|
+ <div>
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col style="display:flex" :span="20" :xs="24">
|
|
|
+ <el-form :model="searchCondition" :inline="true">
|
|
|
+ <el-form-item label="审核状态" prop="auditStatus">
|
|
|
+ <el-select :clearable="true" @change="list" v-model="searchCondition.auditStatus" placeholder="请选择审核状态" style="width: 155px">
|
|
|
+ <el-option label="未审核" value="0" />
|
|
|
+ <el-option label="已通过" value="1" />
|
|
|
+ <el-option label="已驳回" value="2" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="业务类型" prop="tableName">
|
|
|
+ <el-input
|
|
|
+ @change="list"
|
|
|
+ v-model="searchCondition.tableName"
|
|
|
+ style="max-width: 600px"
|
|
|
+ placeholder="请输入业务名称"
|
|
|
+ class="input-with-select"
|
|
|
+ :clearable="true"
|
|
|
+ >
|
|
|
+ </el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="业务行为" prop="tableName">
|
|
|
+ <el-select :clearable="true" @change="list" v-model="searchCondition.businessType" placeholder="选择业务行为" style="width: 155px">
|
|
|
+ <el-option label="删除" value="删除" />
|
|
|
+ <el-option label="删除全表" value="删除全表" />
|
|
|
+ <el-option label="导入" value="导入" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="创建时间" prop="createTime">
|
|
|
+ <el-date-picker
|
|
|
+ v-model="searchCondition.createTime"
|
|
|
+ @change="list"
|
|
|
+ type="datetimerange"
|
|
|
+ :shortcuts="shortcuts"
|
|
|
+ range-separator="到"
|
|
|
+ start-placeholder="开始时间"
|
|
|
+ end-placeholder="结束时间"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" icon="Search" @click="handleSearch">搜索</el-button>
|
|
|
+ <el-button icon="Refresh" @click="handleReset">重置</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ <el-table :data="tableData" style="width: 100%;" max-height="700">
|
|
|
+ <el-table-column prop="createBy" label="操作员" width="200px"></el-table-column>
|
|
|
+ <el-table-column prop="tableName" label="表名" width="100px" />
|
|
|
+ <el-table-column prop="businessType" label="业务类型" width="100px" />
|
|
|
+ <el-table-column prop="auditStatus" label="审核状态" width="130px">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-tag :type="getTagType(row.auditStatus)">
|
|
|
+ {{ getAuditStatus(row.auditStatus) }}
|
|
|
+ </el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="createTime" label="创建时间">
|
|
|
+ <template #default="{ row }">
|
|
|
+ {{ formatDateTime(row.createTime) }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="updateBy" label="审批员" width="100px"></el-table-column>
|
|
|
+ <el-table-column prop="updateTime" label="更新时间">
|
|
|
+ <template #default="{ row }">
|
|
|
+ {{ formatDateTime(row.updateTime) }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-button v-if="row.auditStatus == 0 && row.businessType != '删除全表'" plain @click="checkDetail(row)" type="warning">
|
|
|
+ 查看详情内容
|
|
|
+ </el-button>
|
|
|
+ <el-button v-if="row.auditStatus == 0" type="primary" size="mini" @click="approve(row)">批准</el-button>
|
|
|
+ <el-button v-if="row.auditStatus == 0" type="danger" size="mini" @click="reject(row.id)">驳回</el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ <div style="float: right">
|
|
|
+ <el-pagination
|
|
|
+ size="small"
|
|
|
+ v-model:current-page="currentPage"
|
|
|
+ v-model:page-size="pageSize"
|
|
|
+ :page-sizes="[10, 20, 30, 50]"
|
|
|
+ :total="total"
|
|
|
+ @current-change="list"
|
|
|
+ @size-change="list"
|
|
|
+ background
|
|
|
+ layout="total, sizes, prev, pager, next, jumper"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <el-dialog
|
|
|
+ v-model="dialogVisible"
|
|
|
+ title="详情页面"
|
|
|
+ >
|
|
|
+ <div>
|
|
|
+ <el-table :data="dialogData" width="100%">
|
|
|
+ <el-table-column
|
|
|
+ v-for="(key, index) in keys"
|
|
|
+ :key="index"
|
|
|
+ :prop="key"
|
|
|
+ :label="vKeys[index]"
|
|
|
+ width="100px"
|
|
|
+ show-overflow-tooltip="true"
|
|
|
+ >
|
|
|
+ <template #default="{ row }">
|
|
|
+ {{ row[key] }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+ <template #footer>
|
|
|
+ <div class="dialog-footer">
|
|
|
+ <el-button type="primary" @click="dialogVisible = false">
|
|
|
+ 确认
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+ <el-dialog
|
|
|
+ v-model="RejectDialogVisible"
|
|
|
+ title="驳回理由"
|
|
|
+ >
|
|
|
+ <el-input
|
|
|
+ v-model="rejectTextarea"
|
|
|
+ style="width: 100%"
|
|
|
+ :autosize="{ minRows: 5, maxRows: 10 }"
|
|
|
+ type="textarea"
|
|
|
+ placeholder="请输入驳回理由"
|
|
|
+ />
|
|
|
+ <template #footer>
|
|
|
+ <span class="dialog-footer">
|
|
|
+ <el-button type="danger" @click="confirmReject">驳回</el-button>
|
|
|
+ <el-button type="primary" @click="cancelReject">取消</el-button>
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <el-dialog
|
|
|
+ v-model="excelDialogVisible"
|
|
|
+ title="导入的详情内容"
|
|
|
+ align-center
|
|
|
+ width="100%"
|
|
|
+ @close="excelDialogClose"
|
|
|
+ >
|
|
|
+ <div style="display: flex; flex-direction: column; align-items: center;">
|
|
|
+ <div>
|
|
|
+ <span>显示行数:</span>
|
|
|
+ <el-input-number v-model="maxRowsToShow" :min="1" :max="500" :step="10" />
|
|
|
+ <span>(默认展示{{maxRowsToShow}}条可以点击+号往下看,最多展示500行)</span>
|
|
|
+ <span> </span>
|
|
|
+ <el-button plain icon="Download" type="success" @click="downLoadOriginFile">下载源文件</el-button>
|
|
|
+ </div>
|
|
|
+ <table v-if="data" border="1" style="width: 100%; border-collapse: collapse;">
|
|
|
+ <tbody>
|
|
|
+ <tr v-for="(row, rowIndex) in displayedData" :key="rowIndex" style="border-bottom: 1px solid #ddd;">
|
|
|
+ <td v-for="(cell, cellIndex) in row" :key="cellIndex" style="width: 100px;padding: 8px; border: 1px solid #ddd;">{{ cell }}</td>
|
|
|
+ </tr>
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+ </div>
|
|
|
+ <template #footer>
|
|
|
+ <div class="dialog-footer">
|
|
|
+ <el-button @click="excelDialogVisible = false">关闭</el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import {ref, toRaw} from 'vue';
|
|
|
+import {ElTable, ElTableColumn, ElTag, ElMessage} from 'element-plus';
|
|
|
+import {
|
|
|
+ approveRequest,
|
|
|
+ approveRequestByImportWithFile,
|
|
|
+ checkContent,
|
|
|
+ getListByPage,
|
|
|
+ rejectRequest
|
|
|
+} from "@/api/rkpz/rkpzxx";
|
|
|
+import {fieldMap} from "@/views/CEEnterprise/companydetail/map";
|
|
|
+import * as XLSX from 'xlsx';
|
|
|
+import request from "@/utils/request";
|
|
|
+
|
|
|
+const tableData = ref();
|
|
|
+const dialogVisible = ref(false);
|
|
|
+const dialogData = ref();
|
|
|
+const RejectDialogVisible = ref(false);
|
|
|
+const keys = ref();
|
|
|
+const vKeys = ref();
|
|
|
+const rejectTextarea = ref('')
|
|
|
+const rejectId = ref();
|
|
|
+const currentPage = ref(1);
|
|
|
+const pageSize = ref(20);
|
|
|
+const total = ref(0);
|
|
|
+const excelDialogVisible = ref(false);
|
|
|
+const data = ref(null);
|
|
|
+const maxRowsToShow = ref(50);
|
|
|
+const originFile = ref('');
|
|
|
+const searchCondition = ref({
|
|
|
+ auditStatus:"",
|
|
|
+ tableName:"",
|
|
|
+ businessType:"",
|
|
|
+ createTime:[]
|
|
|
+})
|
|
|
+
|
|
|
+const shortcuts = [
|
|
|
+ {
|
|
|
+ text: '上一周',
|
|
|
+ value: () => {
|
|
|
+ const end = new Date()
|
|
|
+ const start = new Date()
|
|
|
+ start.setDate(start.getDate() - 7)
|
|
|
+ return [start, end]
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: '上一月',
|
|
|
+ value: () => {
|
|
|
+ const end = new Date()
|
|
|
+ const start = new Date()
|
|
|
+ start.setMonth(start.getMonth() - 1)
|
|
|
+ return [start, end]
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: '上三个月',
|
|
|
+ value: () => {
|
|
|
+ const end = new Date()
|
|
|
+ const start = new Date()
|
|
|
+ start.setMonth(start.getMonth() - 3)
|
|
|
+ return [start, end]
|
|
|
+ },
|
|
|
+ },
|
|
|
+]
|
|
|
+const handleSearch = ()=>{
|
|
|
+ list();
|
|
|
+}
|
|
|
+const handleReset = ()=>{
|
|
|
+ searchCondition.value = {
|
|
|
+ auditStatus:"",
|
|
|
+ tableName:"",
|
|
|
+ businessType:"",
|
|
|
+ createTime:[]
|
|
|
+ }
|
|
|
+ list();
|
|
|
+}
|
|
|
+
|
|
|
+// 获取审核状态文本
|
|
|
+function getAuditStatus(status) {
|
|
|
+ const statuses = ['待审核', '审核通过', '审核不通过'];
|
|
|
+ return statuses[status] || '未知';
|
|
|
+}
|
|
|
+
|
|
|
+// 获取标签类型
|
|
|
+function getTagType(status) {
|
|
|
+ switch (status) {
|
|
|
+ case 0:
|
|
|
+ return 'warning';
|
|
|
+ case 1:
|
|
|
+ return 'success';
|
|
|
+ case 2:
|
|
|
+ return 'danger';
|
|
|
+ case 3:
|
|
|
+ return 'info';
|
|
|
+ default:
|
|
|
+ return 'default';
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 格式化日期时间
|
|
|
+function formatDateTime(dateTime) {
|
|
|
+ if (!dateTime) return '';
|
|
|
+ const date = new Date(dateTime);
|
|
|
+ return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} ${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}:${String(date.getSeconds()).padStart(2, '0')}`;
|
|
|
+}
|
|
|
+
|
|
|
+const list = async () => {
|
|
|
+ const conditionJsonArr = [];
|
|
|
+ conditionJsonArr.push(
|
|
|
+ {
|
|
|
+ column:"audit_status",
|
|
|
+ type:'like',
|
|
|
+ value:searchCondition.value.auditStatus?searchCondition.value.auditStatus:"",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ column:"table_name",
|
|
|
+ type:'like',
|
|
|
+ value:searchCondition.value.tableName?searchCondition.value.tableName:"",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ column:"create_time",
|
|
|
+ type:'orderByDesc'
|
|
|
+ }
|
|
|
+ )
|
|
|
+ !!searchCondition.value.businessType && conditionJsonArr.push(
|
|
|
+ {
|
|
|
+ column:"business_type",
|
|
|
+ type:'eq',
|
|
|
+ value:searchCondition.value.businessType,
|
|
|
+ }
|
|
|
+ )
|
|
|
+ searchCondition.value.createTime.length > 0 && conditionJsonArr.push(
|
|
|
+ {
|
|
|
+ column:"create_time",
|
|
|
+ type:'between',
|
|
|
+ value:handleTimeToString(searchCondition.value.createTime),
|
|
|
+ }
|
|
|
+ )
|
|
|
+ const res = await getListByPage(currentPage.value,pageSize.value,conditionJsonArr);
|
|
|
+ if (res.code == 200) {
|
|
|
+ tableData.value = res.data.records;
|
|
|
+ total.value = res.data.total;
|
|
|
+ }
|
|
|
+}
|
|
|
+const handleTimeToString = (time)=>{
|
|
|
+ return formatDateTime(time[0])+","+formatDateTime(time[1]);
|
|
|
+}
|
|
|
+
|
|
|
+const approve = async (row) => {
|
|
|
+ if(row.businessType == '导入'){
|
|
|
+ const res = await approveRequestByImportWithFile(row);
|
|
|
+ if(res.code == 200){
|
|
|
+ ElMessage({
|
|
|
+ type: 'success',
|
|
|
+ message: res.msg
|
|
|
+ })
|
|
|
+ }else {
|
|
|
+ ElMessage({
|
|
|
+ type: 'error',
|
|
|
+ message: res.msg
|
|
|
+ })
|
|
|
+ }
|
|
|
+ list();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const res = await approveRequest(row.id);
|
|
|
+ if (res.code == 200) {
|
|
|
+ ElMessage({
|
|
|
+ type: 'success',
|
|
|
+ message: res.msg
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ ElMessage({
|
|
|
+ type: 'error',
|
|
|
+ message: res.msg
|
|
|
+ })
|
|
|
+ }
|
|
|
+ list()
|
|
|
+}
|
|
|
+
|
|
|
+const reject = async (id) => {
|
|
|
+ rejectId.value = id;
|
|
|
+ RejectDialogVisible.value = true;
|
|
|
+}
|
|
|
+
|
|
|
+const confirmReject = async () => {
|
|
|
+ if (rejectTextarea.value.length == 0) {
|
|
|
+ rejectId.value = '';
|
|
|
+ rejectTextarea.value = '';
|
|
|
+ ElMessage.error('请输入驳回理由');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const res = await rejectRequest(rejectId.value, rejectTextarea.value);
|
|
|
+ if (res.code == 200) {
|
|
|
+ ElMessage({
|
|
|
+ type: 'success',
|
|
|
+ message: res.msg
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ ElMessage({
|
|
|
+ type: 'error',
|
|
|
+ message: res.msg
|
|
|
+ })
|
|
|
+ }
|
|
|
+ rejectId.value = '';
|
|
|
+ rejectTextarea.value = '';
|
|
|
+ RejectDialogVisible.value = false;
|
|
|
+ list()
|
|
|
+}
|
|
|
+
|
|
|
+const cancelReject = ()=>{
|
|
|
+ rejectId.value = '';
|
|
|
+ rejectTextarea.value = '';
|
|
|
+ RejectDialogVisible.value = false;
|
|
|
+}
|
|
|
+
|
|
|
+const checkDetail = async (row) => {
|
|
|
+ if(row.businessType == '导入'){
|
|
|
+ if(!row.operationContent){
|
|
|
+ ElMessage({
|
|
|
+ type: 'error',
|
|
|
+ message: "数据异常请联系管理员"
|
|
|
+ })
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ excelDialogVisible.value = true;
|
|
|
+ try {
|
|
|
+ const response = await fetch(import.meta.env.VITE_APP_BASE_URL+row.operationContent);
|
|
|
+ if (!response.ok) {
|
|
|
+ ElMessage({
|
|
|
+ type: 'error',
|
|
|
+ message: "网络异常请联系管理员"
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ originFile.value = row.operationContent;
|
|
|
+ const blob = await response.blob();
|
|
|
+ const arrayBuffer = await blob.arrayBuffer();
|
|
|
+ const workbook = XLSX.read(arrayBuffer, { type: 'buffer' });
|
|
|
+ const sheetName = workbook.SheetNames[0];
|
|
|
+ const worksheet = workbook.Sheets[sheetName];
|
|
|
+ const jsonData = XLSX.utils.sheet_to_json(worksheet);
|
|
|
+ data.value = jsonData;
|
|
|
+ } catch (error) {
|
|
|
+ ElMessage({
|
|
|
+ type: 'error',
|
|
|
+ message: error.message
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const res = await checkContent(row.id);
|
|
|
+ if (res.code == 200) {
|
|
|
+ dialogData.value = res.data
|
|
|
+ keys.value = Object.keys(dialogData.value[0]);
|
|
|
+ keys.value.shift();
|
|
|
+ vKeys.value = keys.value.map(camelToUnderscore).map(q => {
|
|
|
+ return fieldMap[q];
|
|
|
+ })
|
|
|
+ dialogVisible.value = true
|
|
|
+ } else {
|
|
|
+ ElMessage({
|
|
|
+ type: 'error',
|
|
|
+ message: res.msg
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const displayedData = computed(() => {
|
|
|
+ return data.value ? data.value.slice(0, maxRowsToShow.value) : [];
|
|
|
+});
|
|
|
+
|
|
|
+const excelDialogClose = ()=>{
|
|
|
+ excelDialogVisible.value = false;
|
|
|
+ data.value = [];
|
|
|
+ maxRowsToShow.value = 50;
|
|
|
+ originFile.value = '';
|
|
|
+}
|
|
|
+
|
|
|
+const downLoadOriginFile = ()=>{
|
|
|
+ const link = document.createElement('a');
|
|
|
+ link.href = import.meta.env.VITE_APP_BASE_URL+originFile.value;
|
|
|
+ document.body.appendChild(link);
|
|
|
+ link.click();
|
|
|
+ document.body.removeChild(link);
|
|
|
+}
|
|
|
+
|
|
|
+const camelToUnderscore = (camelStr) => {
|
|
|
+ return camelStr
|
|
|
+ .replace(/([A-Z])/g, function (match) {
|
|
|
+ return '_' + match.toLowerCase();
|
|
|
+ })
|
|
|
+ .replace(/^_/, '');
|
|
|
+}
|
|
|
+
|
|
|
+const init = () => {
|
|
|
+ list()
|
|
|
+}
|
|
|
+init()
|
|
|
+</script>
|
|
|
+
|