2 changed files with 490 additions and 0 deletions
@ -0,0 +1,70 @@ |
|||||||
|
import request from "@/api/request"; |
||||||
|
import { BASE_PATH } from "@/api/request"; |
||||||
|
import feedback from "@/utils/feedback"; |
||||||
|
|
||||||
|
export function getPage(data) { |
||||||
|
return request.post({ |
||||||
|
url: "/data/dataAudit/getPage", |
||||||
|
body: data |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
export function add(data) { |
||||||
|
return request.post({ |
||||||
|
url: "/data/dataAudit/add", |
||||||
|
body: data |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
export function update(data) { |
||||||
|
return request.post({ |
||||||
|
url: "/data/dataAudit/update", |
||||||
|
body: data |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
export function del(data) { |
||||||
|
return request.post({ |
||||||
|
url: "/data/dataAudit/delete", |
||||||
|
body: data |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
export function importExcel(file) { |
||||||
|
const formData = new FormData(); |
||||||
|
formData.append("file", file); |
||||||
|
return request.post({ |
||||||
|
url: "/data/dataAudit/import", |
||||||
|
body: formData |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
export async function downloadTemplate() { |
||||||
|
const response = await fetch(`${BASE_PATH}/data/dataAudit/downloadTemplate`, { |
||||||
|
method: 'GET', |
||||||
|
headers: { |
||||||
|
"Authorization": localStorage.getItem('token') || '' |
||||||
|
} |
||||||
|
}); |
||||||
|
if (!response.ok) { |
||||||
|
feedback.msgError('下载模板失败'); |
||||||
|
return; |
||||||
|
} |
||||||
|
const blob = await response.blob(); |
||||||
|
let filename = '审计数据导入模板.xlsx'; |
||||||
|
const disposition = response.headers.get('content-disposition'); |
||||||
|
if (disposition) { |
||||||
|
const match = disposition.match(/filename\*=UTF-8''(.+)/); |
||||||
|
if (match) { |
||||||
|
filename = decodeURIComponent(match[1]); |
||||||
|
} |
||||||
|
} |
||||||
|
const url = window.URL.createObjectURL(blob); |
||||||
|
const a = document.createElement('a'); |
||||||
|
a.href = url; |
||||||
|
a.download = filename; |
||||||
|
document.body.appendChild(a); |
||||||
|
a.click(); |
||||||
|
document.body.removeChild(a); |
||||||
|
window.URL.revokeObjectURL(url); |
||||||
|
} |
||||||
@ -0,0 +1,420 @@ |
|||||||
|
<template> |
||||||
|
<div class="container"> |
||||||
|
<header> |
||||||
|
<el-form :label-width="100"> |
||||||
|
<el-row> |
||||||
|
<el-col :span="6"> |
||||||
|
<el-form-item label="审计类型"> |
||||||
|
<el-select v-model="query.auditType" placeholder="请选择" clearable style="width: 100%"> |
||||||
|
<el-option label="执法活动财物审计" value="28"/> |
||||||
|
<el-option label="经济责任审计" value="29"/> |
||||||
|
<el-option label="专项审计" value="30"/> |
||||||
|
</el-select> |
||||||
|
</el-form-item> |
||||||
|
</el-col> |
||||||
|
<el-col :span="6"> |
||||||
|
<el-form-item label="项目名称"> |
||||||
|
<el-input v-model="query.projectName" placeholder="请输入项目名称" clearable/> |
||||||
|
</el-form-item> |
||||||
|
</el-col> |
||||||
|
<el-col :span="6"> |
||||||
|
<el-form-item label="涉及二级单位"> |
||||||
|
<depart-tree-select |
||||||
|
v-model="query.secondLevelDeptId" |
||||||
|
:check-strictly="true" |
||||||
|
/> |
||||||
|
</el-form-item> |
||||||
|
</el-col> |
||||||
|
<el-col :span="6"> |
||||||
|
<el-form-item label="涉及三级单位"> |
||||||
|
<depart-tree-select |
||||||
|
v-model="query.thirdLevelDeptId" |
||||||
|
:check-strictly="true" |
||||||
|
/> |
||||||
|
</el-form-item> |
||||||
|
</el-col> |
||||||
|
<el-col :span="6"> |
||||||
|
<el-form-item label="审计时间"> |
||||||
|
<date-time-range-picker-ext v-model="query.auditTimeList"/> |
||||||
|
</el-form-item> |
||||||
|
</el-col> |
||||||
|
</el-row> |
||||||
|
</el-form> |
||||||
|
<div class="mb-25 flex between"> |
||||||
|
<div> |
||||||
|
<el-button type="primary" @click="handleAdd">添加</el-button> |
||||||
|
<el-button type="primary" @click="handleImport">数据导入</el-button> |
||||||
|
</div> |
||||||
|
<div> |
||||||
|
<el-button type="primary" @click="getList"> |
||||||
|
<template #icon> |
||||||
|
<icon name="el-icon-Search"/> |
||||||
|
</template> |
||||||
|
查询 |
||||||
|
</el-button> |
||||||
|
<el-button @click="reset">重置</el-button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</header> |
||||||
|
<div class="table-container" v-loading="loading"> |
||||||
|
<el-table :data="list"> |
||||||
|
<el-table-column label="审计类型" width="140" prop="auditType"> |
||||||
|
<template #default="{ row }"> |
||||||
|
{{ getAuditTypeLabel(row.auditType) }} |
||||||
|
</template> |
||||||
|
</el-table-column> |
||||||
|
<el-table-column label="项目名称" min-width="200" prop="projectName" show-overflow-tooltip/> |
||||||
|
<el-table-column label="涉及二级单位" width="150" prop="secondLevelDeptName" show-overflow-tooltip/> |
||||||
|
<el-table-column label="涉及三级单位" width="150" prop="thirdLevelDeptName" show-overflow-tooltip/> |
||||||
|
<el-table-column label="审计时间" width="170" prop="auditTime" |
||||||
|
:formatter="(_, __, v) => v ? timeFormat(v, 'yyyy-mm-dd hh:MM:ss') : '/'"/> |
||||||
|
<el-table-column label="审计涉及金额(万元)" width="140" prop="auditAmount" align="right"> |
||||||
|
<template #default="{ row }"> |
||||||
|
{{ formatMoney(row.auditAmount) }} |
||||||
|
</template> |
||||||
|
</el-table-column> |
||||||
|
<el-table-column label="问题金额(万元)" width="130" prop="issueAmount" align="right"> |
||||||
|
<template #default="{ row }"> |
||||||
|
{{ formatMoney(row.issueAmount) }} |
||||||
|
</template> |
||||||
|
</el-table-column> |
||||||
|
<el-table-column label="创建人" width="100" prop="createBy"/> |
||||||
|
<el-table-column label="创建时间" width="170" prop="createTime" |
||||||
|
:formatter="(_, __, v) => v ? timeFormat(v, 'yyyy-mm-dd hh:MM:ss') : '/'"/> |
||||||
|
<el-table-column label="操作" width="150"> |
||||||
|
<template #default="{ row }"> |
||||||
|
<el-button type="primary" link @click="handleEdit(row)">修改</el-button> |
||||||
|
<el-button type="danger" link @click="handleDel(row)">删除</el-button> |
||||||
|
</template> |
||||||
|
</el-table-column> |
||||||
|
</el-table> |
||||||
|
</div> |
||||||
|
<div class="flex end mt-8"> |
||||||
|
<el-pagination |
||||||
|
@size-change="getList" |
||||||
|
@current-change="getList" |
||||||
|
:page-sizes="[10, 20, 50]" |
||||||
|
v-model:page-size="query.size" |
||||||
|
v-model:current-page="query.current" |
||||||
|
layout="total, sizes, prev, pager, next" |
||||||
|
:total="total" |
||||||
|
/> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="600px" destroy-on-close> |
||||||
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px"> |
||||||
|
<el-form-item label="审计类型" prop="auditType"> |
||||||
|
<el-select v-model="form.auditType" placeholder="请选择审计类型" style="width: 100%"> |
||||||
|
<el-option label="执法活动财物审计" value="28"/> |
||||||
|
<el-option label="经济责任审计" value="29"/> |
||||||
|
<el-option label="专项审计" value="30"/> |
||||||
|
</el-select> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="项目名称" prop="projectName"> |
||||||
|
<el-input v-model="form.projectName" placeholder="请输入项目名称"/> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="涉及二级单位"> |
||||||
|
<depart-tree-select |
||||||
|
v-model="form.secondLevelDeptId" |
||||||
|
:check-strictly="true" |
||||||
|
@node-click="(row) => (form.secondLevelDeptName = row.shortName)" |
||||||
|
/> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="涉及三级单位"> |
||||||
|
<depart-tree-select |
||||||
|
v-model="form.thirdLevelDeptId" |
||||||
|
:check-strictly="true" |
||||||
|
@node-click="(row) => (form.thirdLevelDeptName = row.shortName)" |
||||||
|
/> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="审计时间" prop="auditTime"> |
||||||
|
<el-date-picker |
||||||
|
v-model="form.auditTime" |
||||||
|
type="datetime" |
||||||
|
placeholder="请选择审计时间" |
||||||
|
style="width: 100%" |
||||||
|
value-format="YYYY-MM-DD HH:mm:ss" |
||||||
|
/> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="审计涉及金额" prop="auditAmount"> |
||||||
|
<el-input-number v-model="form.auditAmount" :precision="4" :min="0" style="width: calc(100% - 40px)"/> |
||||||
|
<span class="unit-label">万元</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="问题金额"> |
||||||
|
<el-input-number v-model="form.issueAmount" :precision="4" :min="0" style="width: calc(100% - 40px)"/> |
||||||
|
<span class="unit-label">万元</span> |
||||||
|
</el-form-item> |
||||||
|
</el-form> |
||||||
|
<template #footer> |
||||||
|
<div class="dialog-footer"> |
||||||
|
<el-button @click="dialogVisible = false">取消</el-button> |
||||||
|
<el-button type="primary" @click="submitForm" :loading="submitLoading">确定</el-button> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
</el-dialog> |
||||||
|
|
||||||
|
<el-dialog title="审计数据导入" v-model="importDialogVisible" width="60vw" :lock-scroll="false"> |
||||||
|
<div v-loading="importLoading"> |
||||||
|
<el-upload |
||||||
|
drag |
||||||
|
:multiple="false" |
||||||
|
:auto-upload="false" |
||||||
|
:show-file-list="false" |
||||||
|
v-model:file-list="importFileList" |
||||||
|
accept="application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" |
||||||
|
class="mt-20" |
||||||
|
> |
||||||
|
<template v-if="importFileList.length === 0"> |
||||||
|
<el-icon class="el-icon--upload"> |
||||||
|
<upload-filled/> |
||||||
|
</el-icon> |
||||||
|
<div class="el-upload__text"> |
||||||
|
<p>点击或拖拽文件到此区域上传</p> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<template v-else> |
||||||
|
<el-icon class="el-icon--upload"> |
||||||
|
<Select/> |
||||||
|
</el-icon> |
||||||
|
<div class="el-upload__text"> |
||||||
|
已选择文件:{{ importFileList[importFileList.length - 1].name }} |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
</el-upload> |
||||||
|
<div class="mt-20"> |
||||||
|
<span>文件模板:</span> |
||||||
|
<el-button type="primary" link @click="handleDownloadTemplate">审计数据导入模板.xlsx 下载</el-button> |
||||||
|
</div> |
||||||
|
<footer class="flex end mt-20"> |
||||||
|
<el-button @click="importDialogVisible = false">取消</el-button> |
||||||
|
<el-button type="primary" @click="handleConfirmImport" :loading="importLoading" :disabled="importFileList.length === 0"> |
||||||
|
确认导入 |
||||||
|
</el-button> |
||||||
|
</footer> |
||||||
|
</div> |
||||||
|
</el-dialog> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup> |
||||||
|
import {timeFormat} from "@/utils/util"; |
||||||
|
import feedback from "@/utils/feedback"; |
||||||
|
import {getPage, add, update, del, importExcel, downloadTemplate} from "@/api/data/dataAudit.ts"; |
||||||
|
|
||||||
|
const query = ref({ |
||||||
|
size: 10, |
||||||
|
current: 1, |
||||||
|
auditType: '', |
||||||
|
projectName: '', |
||||||
|
secondLevelDeptId: null, |
||||||
|
thirdLevelDeptId: null, |
||||||
|
auditTimeList: [] |
||||||
|
}); |
||||||
|
|
||||||
|
const list = ref([]); |
||||||
|
const total = ref(0); |
||||||
|
const loading = ref(false); |
||||||
|
|
||||||
|
const getList = async () => { |
||||||
|
loading.value = true; |
||||||
|
try { |
||||||
|
const res = await getPage(query.value); |
||||||
|
list.value = res.records || []; |
||||||
|
total.value = res.total || 0; |
||||||
|
} catch (e) { |
||||||
|
console.error(e); |
||||||
|
} finally { |
||||||
|
loading.value = false; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
const reset = () => { |
||||||
|
query.value = { |
||||||
|
size: 10, |
||||||
|
current: 1, |
||||||
|
auditType: '', |
||||||
|
projectName: '', |
||||||
|
secondLevelDeptId: null, |
||||||
|
thirdLevelDeptId: null, |
||||||
|
auditTimeList: [] |
||||||
|
}; |
||||||
|
getList(); |
||||||
|
}; |
||||||
|
|
||||||
|
onMounted(() => { |
||||||
|
getList(); |
||||||
|
}); |
||||||
|
|
||||||
|
const dialogVisible = ref(false); |
||||||
|
const dialogTitle = ref('添加'); |
||||||
|
const formRef = ref(); |
||||||
|
const submitLoading = ref(false); |
||||||
|
|
||||||
|
const createEmptyForm = () => ({ |
||||||
|
id: null, |
||||||
|
auditType: '', |
||||||
|
projectName: '', |
||||||
|
secondLevelDeptId: null, |
||||||
|
secondLevelDeptName: '', |
||||||
|
thirdLevelDeptId: null, |
||||||
|
thirdLevelDeptName: '', |
||||||
|
auditTime: '', |
||||||
|
auditAmount: null, |
||||||
|
issueAmount: 0 |
||||||
|
}); |
||||||
|
|
||||||
|
const form = ref(createEmptyForm()); |
||||||
|
|
||||||
|
const rules = { |
||||||
|
auditType: [{required: true, message: '请选择审计类型', trigger: 'change'}], |
||||||
|
projectName: [{required: true, message: '请输入项目名称', trigger: 'blur'}], |
||||||
|
auditTime: [{required: true, message: '请选择审计时间', trigger: 'change'}], |
||||||
|
auditAmount: [{required: true, message: '请输入审计涉及金额', trigger: 'blur'}] |
||||||
|
}; |
||||||
|
|
||||||
|
const handleAdd = () => { |
||||||
|
form.value = createEmptyForm(); |
||||||
|
dialogTitle.value = '添加'; |
||||||
|
dialogVisible.value = true; |
||||||
|
}; |
||||||
|
|
||||||
|
const handleEdit = (row) => { |
||||||
|
form.value = { |
||||||
|
id: row.id, |
||||||
|
auditType: String(row.auditType), |
||||||
|
projectName: row.projectName, |
||||||
|
secondLevelDeptId: row.secondLevelDeptId ? String(row.secondLevelDeptId) : null, |
||||||
|
secondLevelDeptName: row.secondLevelDeptName || '', |
||||||
|
thirdLevelDeptId: row.thirdLevelDeptId ? String(row.thirdLevelDeptId) : null, |
||||||
|
thirdLevelDeptName: row.thirdLevelDeptName || '', |
||||||
|
auditTime: row.auditTime, |
||||||
|
auditAmount: row.auditAmount, |
||||||
|
issueAmount: row.issueAmount || 0 |
||||||
|
}; |
||||||
|
dialogTitle.value = '修改'; |
||||||
|
dialogVisible.value = true; |
||||||
|
}; |
||||||
|
|
||||||
|
const handleDel = async (row) => { |
||||||
|
await feedback.confirm(`确定删除该数据?`); |
||||||
|
await del({id: row.id}); |
||||||
|
feedback.msgSuccess("操作成功"); |
||||||
|
getList(); |
||||||
|
}; |
||||||
|
|
||||||
|
const submitForm = async () => { |
||||||
|
await formRef.value.validate(); |
||||||
|
submitLoading.value = true; |
||||||
|
try { |
||||||
|
if (form.value.id) { |
||||||
|
await update(form.value); |
||||||
|
} else { |
||||||
|
await add(form.value); |
||||||
|
} |
||||||
|
feedback.msgSuccess("操作成功"); |
||||||
|
dialogVisible.value = false; |
||||||
|
getList(); |
||||||
|
} catch (e) { |
||||||
|
console.error(e); |
||||||
|
feedback.notifyError("操作失败"); |
||||||
|
} finally { |
||||||
|
submitLoading.value = false; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
const formatMoney = (value) => { |
||||||
|
if (value === null || value === undefined) return '/'; |
||||||
|
return Number(value).toLocaleString('zh-CN', {minimumFractionDigits: 4, maximumFractionDigits: 4}); |
||||||
|
}; |
||||||
|
|
||||||
|
const auditTypeMap = { |
||||||
|
'28': '执法活动财物审计', |
||||||
|
'29': '经济责任审计', |
||||||
|
'30': '专项审计' |
||||||
|
}; |
||||||
|
|
||||||
|
const getAuditTypeLabel = (value) => { |
||||||
|
return auditTypeMap[value] || '/'; |
||||||
|
}; |
||||||
|
|
||||||
|
const importDialogVisible = ref(false); |
||||||
|
const importLoading = ref(false); |
||||||
|
const importFileList = ref([]); |
||||||
|
|
||||||
|
const handleImport = () => { |
||||||
|
importFileList.value = []; |
||||||
|
importDialogVisible.value = true; |
||||||
|
}; |
||||||
|
|
||||||
|
const handleConfirmImport = async () => { |
||||||
|
if (importFileList.value.length === 0) { |
||||||
|
feedback.msgWarning("请选择要导入的文件"); |
||||||
|
return; |
||||||
|
} |
||||||
|
importLoading.value = true; |
||||||
|
try { |
||||||
|
const file = importFileList.value[importFileList.value.length - 1].raw; |
||||||
|
const count = await importExcel(file); |
||||||
|
feedback.msgSuccess(`导入成功,共导入 ${count} 条数据`); |
||||||
|
importDialogVisible.value = false; |
||||||
|
getList(); |
||||||
|
} catch (e) { |
||||||
|
console.error(e); |
||||||
|
feedback.notifyError("导入失败"); |
||||||
|
} finally { |
||||||
|
importLoading.value = false; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
const handleDownloadTemplate = async () => { |
||||||
|
await downloadTemplate(); |
||||||
|
}; |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" scoped> |
||||||
|
.container { |
||||||
|
padding: 20px; |
||||||
|
background: #fff; |
||||||
|
border-radius: 4px; |
||||||
|
} |
||||||
|
|
||||||
|
header { |
||||||
|
margin-bottom: 20px; |
||||||
|
} |
||||||
|
|
||||||
|
.mb-25 { |
||||||
|
margin-bottom: 25px; |
||||||
|
} |
||||||
|
|
||||||
|
.flex { |
||||||
|
display: flex; |
||||||
|
} |
||||||
|
|
||||||
|
.between { |
||||||
|
justify-content: space-between; |
||||||
|
} |
||||||
|
|
||||||
|
.end { |
||||||
|
justify-content: flex-end; |
||||||
|
} |
||||||
|
|
||||||
|
.mt-8 { |
||||||
|
margin-top: 8px; |
||||||
|
} |
||||||
|
|
||||||
|
.mt-20 { |
||||||
|
margin-top: 20px; |
||||||
|
} |
||||||
|
|
||||||
|
.unit-label { |
||||||
|
margin-left: 8px; |
||||||
|
color: #606266; |
||||||
|
} |
||||||
|
|
||||||
|
.dialog-footer { |
||||||
|
display: flex; |
||||||
|
justify-content: flex-end; |
||||||
|
padding: 0 20px 10px; |
||||||
|
gap: 10px; |
||||||
|
} |
||||||
|
</style> |
||||||
Loading…
Reference in new issue