Compare commits

...

8 Commits

  1. 16
      src/api/request.ts
  2. 24
      src/api/warning/business.ts
  3. 107
      src/components/file/upload.vue
  4. 55
      src/components/reportAudit/finishDistrbute.vue
  5. 17
      src/views/report/edit/controlPrice.vue
  6. 9
      src/views/warning/business.vue
  7. 75
      src/views/warning/index.vue

16
src/api/request.ts

@ -13,7 +13,7 @@ type Options = {
params?: Record<string, any>,
body?: string | FormData | Record<string, any>,
config?:Object
showErrorMsg: bool
showErrorMsg?: boolean
};
function get(options: Options) {
@ -90,7 +90,7 @@ function ajax(url: string, options: Options) {
headers: { ...headers, ...options.headers }
}).then(response => {
if (response.status === 413) {
return;
throw new Error('请求内容过大,请缩小文件后重试');
}
if( isBlob){
return response.blob();
@ -127,10 +127,20 @@ function ajax(url: string, options: Options) {
// }else{
// feedback.msgError("请联系开发人员,数据存在问题")
// }
console.log(message)
if (options.showErrorMsg) {
feedback.msgError(message || '操作失败,请稍后重试')
}
reject(res)
}
}
}).catch(error => {
if (options.showErrorMsg) {
const message = error?.message === '请求内容过大,请缩小文件后重试'
? error.message
: '网络异常,请检查网络后重试'
feedback.msgError(message)
}
reject(error)
})
})
}

24
src/api/warning/business.ts

@ -7,7 +7,8 @@ import request from "@/api/request";
*/
export function getWarningBusiness(reportId: string) {
return request.get({
url: `/warning/business/${reportId}`
url: `/warning/business/${reportId}`,
showErrorMsg: true
});
}
@ -17,7 +18,8 @@ export function getWarningBusiness(reportId: string) {
export function saveWarningBusiness(data: any) {
return request.post({
url: '/warning/business/save',
body: data
body: data,
showErrorMsg: true
});
}
@ -27,7 +29,8 @@ export function saveWarningBusiness(data: any) {
export function submitWarningBusiness(data: any) {
return request.post({
url: '/warning/business/submit',
body: data
body: data,
showErrorMsg: true
});
}
@ -37,7 +40,8 @@ export function submitWarningBusiness(data: any) {
export function endWarningBusiness(data: any) {
return request.post({
url: '/warning/business/end',
body: data
body: data,
showErrorMsg: true
});
}
@ -47,7 +51,8 @@ export function endWarningBusiness(data: any) {
export function auditPassWarningDistribute(data: any) {
return request.post({
url: '/warning/business/audit/pass/distribute',
body: data
body: data,
showErrorMsg: true
});
}
@ -57,7 +62,8 @@ export function auditPassWarningDistribute(data: any) {
export function auditRejectWarning(data: any) {
return request.post({
url: '/warning/business/audit/reject',
body: data
body: data,
showErrorMsg: true
});
}
@ -66,7 +72,8 @@ export function auditRejectWarning(data: any) {
*/
export function getWarningFlowList(reportId: string) {
return request.get({
url: `/warning/business/flow/${reportId}`
url: `/warning/business/flow/${reportId}`,
showErrorMsg: true
});
}
@ -74,6 +81,7 @@ export function getWarningFlowList(reportId: string) {
export const getCompilePage=(body)=>{
return request.post({
url:`/warning/business/compile/page`,
body
body,
showErrorMsg: true
})
}

107
src/components/file/upload.vue

@ -1,6 +1,7 @@
<template>
<div>
<el-upload
ref="uploadRef"
:action="`${BASE_PATH}/file/upload`"
:headers="{ Authorization: getToken() }"
multiple
@ -55,7 +56,52 @@ const props = defineProps({
const emit = defineEmits(["update:files"]);
const uploadRef = ref();
const files = ref(props.files);
const allowArchiveFallback = ref(false);
const fallbackArchiveExts = ['zip', 'rar', '7z'];
const archiveExts = [...fallbackArchiveExts, 'tar', 'gz', 'bz2', 'xz', 'iso', 'dmg'];
const uploadResponseTimeout = 15000;
const responseTimers = new Map();
function getFileExt(file) {
const name = (file?.name || file?.raw?.name || '').toLowerCase();
return name.includes('.') ? name.split('.').pop() : '';
}
function enableArchiveFallback(file) {
if (archiveExts.includes(getFileExt(file))) {
return false;
}
allowArchiveFallback.value = true;
feedback.msgError('文件上传失败,已临时允许上传一个 ZIP、RAR 或 7Z 压缩包');
return true;
}
function clearResponseTimer(file) {
const timer = responseTimers.get(file?.uid);
if (timer) {
window.clearTimeout(timer);
}
responseTimers.delete(file?.uid);
}
function startUploadResponseTimer(file) {
if (archiveExts.includes(getFileExt(file)) || responseTimers.has(file?.uid)) {
return;
}
const timer = window.setTimeout(() => {
responseTimers.delete(file.uid);
uploadRef.value?.abort(file);
handleError(new Error('文件保存响应超时'), file);
}, uploadResponseTimeout);
responseTimers.set(file.uid, timer);
}
onBeforeUnmount(() => {
responseTimers.forEach((timer) => window.clearTimeout(timer));
responseTimers.clear();
});
watch(
() => props.files,
@ -73,13 +119,10 @@ watch(files, () => {
},{immediate:true});
function beforeUpload(file) {
const name = (file?.name || '').toLowerCase()
const ext = name.includes('.') ? name.split('.').pop() : ''
const ext = getFileExt(file)
//
const imageExts = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg', 'tiff', 'tif', 'ico', 'heic', 'heif']
//
const archiveExts = ['zip', 'rar', '7z', 'tar', 'gz', 'bz2', 'xz', 'iso', 'dmg']
// PDF
if (imageExts.includes(ext)) {
@ -87,10 +130,15 @@ function beforeUpload(file) {
return false
}
//
if (archiveExts.includes(ext)) {
feedback.msgWarning('暂不支持压缩包上传')
return false
if (!allowArchiveFallback.value) {
feedback.msgWarning('压缩包仅在文件上传失败后允许上传')
return false
}
if (!fallbackArchiveExts.includes(ext)) {
feedback.msgWarning('文件上传失败后仅支持 ZIP、RAR 或 7Z 压缩包')
return false
}
}
// 100MB
@ -98,6 +146,12 @@ function beforeUpload(file) {
feedback.msgError('文件大小不能超过100MB');
return false;
}
if (fallbackArchiveExts.includes(ext)) {
allowArchiveFallback.value = false;
}
if (!archiveExts.includes(ext)) {
allowArchiveFallback.value = false;
}
files.value.push({
uid: file.uid,
percent: 0,
@ -109,29 +163,54 @@ function uploadProgress(progressEvent, file) {
const filterFiles = files.value.filter((item) => file.uid === item.uid);
if (filterFiles.length) {
filterFiles[0].percent = parseInt(progressEvent.percent);
const percent = parseInt(progressEvent.percent);
filterFiles[0].percent = Math.min(99, percent);
if (percent >= 100) {
startUploadResponseTimer(file);
}
}
}
function handleSuccess(data, file) {
clearResponseTimer(file);
const filterFiles = files.value.filter((item) => file.uid === item.uid);
if (data.code !== 200) {
feedback.msgError(data.message);
files.value.splice(files.value.indexOf(filterFiles[0]), 1);
if (!enableArchiveFallback(file)) {
feedback.msgError(data.message);
}
if (filterFiles.length) {
files.value.splice(files.value.indexOf(filterFiles[0]), 1);
emit("update:files", files.value);
}
return;
}
if (!archiveExts.includes(getFileExt(file))) {
allowArchiveFallback.value = false;
}
if (filterFiles.length) {
filterFiles[0].percent = 100;
filterFiles[0].fileName = data.data.fileName;
filterFiles[0].filePath = data.data.filePath;
filterFiles[0].loading = false;
window.setTimeout(() => {
filterFiles[0].loading = false;
emit("update:files", files.value);
}, 300);
}
console.log("file", files.value);
emit("update:files", files.value);
}
function handleError(e, file) {
clearResponseTimer(file);
console.log(e, file);
feedback.msgError("上传失败!");
const fileIndex = files.value.findIndex((item) => file.uid === item.uid);
if (fileIndex > -1) {
files.value.splice(fileIndex, 1);
emit("update:files", files.value);
}
if (enableArchiveFallback(file)) {
return;
}
feedback.msgError("上传失败,请重试!");
}
</script>

55
src/components/reportAudit/finishDistrbute.vue

@ -8,7 +8,7 @@ import {getList,save,delCommon} from '@/api/commonOpinions';
import useCatchStore from "@/stores/modules/catch";
import useUserStore from "@/stores/modules/user";
const userStore = useUserStore();
const props = defineProps(['dialog','reportId','nextNode','message',"isWarning","flowId"])
const props = defineProps(['dialog','reportId','nextNode','message',"isWarning","flowId","batchItems"])
const emits = defineEmits(['submitFeedback',"closeFun"])
const catchStore = useCatchStore();
@ -19,6 +19,7 @@ const formData = ref({
data:{}
})
const auditForm= ref()
const submitLoading = ref(false)
const dict = catchStore.getDicts([
"businessType",
"suspectProblem",
@ -99,23 +100,43 @@ const closeAdd=()=>{
}
const submitFun = async ()=>{
await auditForm.value.validate();
await feedback.confirm("是否确认通过?");
formData.value.reportId = props.reportId;
formData.value.flowId = props.flowId;
//nextNode
if(props.nextNode){
formData.value.nextNode = props.nextNode;
}
if(props.isWarning){
const res = await auditPassWarningDistribute(formData.value);
// const res = await auditWarning(formData.value);
}else{
const res = await auditReport(formData.value);
const isBatch = Array.isArray(props.batchItems) && props.batchItems.length > 0
const targets = isBatch ? props.batchItems : [{
reportId: props.reportId,
flowId: props.flowId
}]
await feedback.confirm(isBatch ? `是否确认批量通过选中的 ${targets.length} 个项目?` : "是否确认通过?");
submitLoading.value = true
try {
const createSubmitData = (target) => ({
...formData.value,
data: {...formData.value.data},
reportId: target.reportId,
flowId: target.flowId,
nextNode: props.nextNode || formData.value.nextNode
})
if (isBatch) {
const results = await Promise.allSettled(targets.map(target =>
auditPassWarningDistribute(createSubmitData(target))
))
const successCount = results.filter(item => item.status === 'fulfilled').length
const failCount = results.length - successCount
if (failCount > 0) {
feedback.msgError(`批量通过完成:成功 ${successCount} 个,失败 ${failCount}`)
} else {
feedback.msgSuccess(`已批量通过 ${successCount} 个项目`)
}
} else if(props.isWarning){
await auditPassWarningDistribute(createSubmitData(targets[0]));
}else{
await auditReport(createSubmitData(targets[0]));
}
emits('submitFeedback',true)
closeAdd()
} finally {
submitLoading.value = false
}
emits('submitFeedback',true)
closeAdd()
}
@ -295,7 +316,7 @@ watch(()=>formData.value.approverId,(val)=>{
</el-form>
<div class="flex end">
<el-button @click="closeAdd">关闭</el-button>
<el-button type="primary" @click="submitFun">提交</el-button>
<el-button type="primary" :loading="submitLoading" @click="submitFun">提交</el-button>
</div>
</el-dialog>
</template>

17
src/views/report/edit/controlPrice.vue

@ -82,6 +82,7 @@ const editAll = ref(false)
//
const delDialog = ref(false);
const delFormRef = ref();
const delFormData = ref({});
const deleteFlag = ref(false)
@ -92,6 +93,10 @@ const fixPrecision = (num, precision = 2) => {
}
const handleDel= async ()=> {
if (!delFormRef.value) return;
const isValid = await delFormRef.value.validate().catch(() => false);
if (!isValid) return;
const body ={
id: route.query.id,
deleteReason: delFormData.value.deleteReason
@ -1462,14 +1467,9 @@ function hasAuditAttachment() {
<el-table-column width="50" type="index" label="序号" :index="(index)=> index+1"></el-table-column>
<el-table-column label="操作" prop="reportCode"></el-table-column>
<el-table-column label="办理人" prop="approver"></el-table-column>
<el-table-column label="提交时间" prop="areportTime">
<template #default="{row}">
{{ timeFormat(row.areportTime,'yyyy-mm-dd hh:MM:ss') }}
</template>
</el-table-column>
<el-table-column label="完成时间" prop="approverTime">
<el-table-column label="操作时间" prop="approverTime">
<template #default="{row}">
{{ timeFormat(row.approverTime,'yyyy-mm-dd hh:MM:ss') }}
{{ row.approverTime ? timeFormat(row.approverTime,'yyyy-mm-dd hh:MM:ss') : '/' }}
</template>
</el-table-column>
<el-table-column label="办理结果" prop="approverState">
@ -1508,9 +1508,10 @@ function hasAuditAttachment() {
<el-form :label-width="120" :model="delFormData" ref="delFormRef">
<el-form-item
label="删除原因"
prop="delReason"
prop="deleteReason"
:rules="{
required: true,
whitespace: true,
message: '请输入删除原因',
}"
>

9
src/views/warning/business.vue

@ -484,14 +484,9 @@ onMounted(() => {
<el-table-column width="50" type="index" label="序号" :index="(index) => index + 1"/>
<el-table-column label="操作" prop="reportCode"/>
<el-table-column label="办理人" prop="approver"/>
<el-table-column label="提交时间" prop="areportTime">
<el-table-column label="操作时间">
<template #default="{row}">
{{ timeFormat(row.areportTime, 'yyyy-mm-dd hh:MM:ss') }}
</template>
</el-table-column>
<el-table-column label="完成时间" prop="approverTime">
<template #default="{row}">
{{ timeFormat(row.approverTime, 'yyyy-mm-dd hh:MM:ss') }}
{{ row.approverTime ? timeFormat(row.approverTime, 'yyyy-mm-dd hh:MM:ss') : '/' }}
</template>
</el-table-column>
<el-table-column label="办理结果" prop="approverState">

75
src/views/warning/index.vue

@ -2,11 +2,17 @@
<script setup>
import {warningPage, excelWarningList} from "@/api/warning/index";
import {auditRejectWarning} from "@/api/warning/business";
import {timeFormat} from "@/utils/util";
import {useRoute} from "vue-router";
import feedback from "@/utils/feedback";
import finishDistrbute from '@/components/reportAudit/finishDistrbute.vue';
const route = useRoute()
const loading =ref(false)
const exportLoading = ref(false)
const batchRejectLoading = ref(false)
const finishDialog = ref(false)
const selectedRows = ref([])
const total =ref(10)
const tableData =ref([])
const activeTab = ref(route.query.specialArea === 'cwlnt' ? 'cwlnt' : route.query.warningState === '1' ? '1' : '0')
@ -44,6 +50,44 @@ const reset =()=>{
getList();
}
const warningStateDisabled = computed(() => activeTab.value !== 'cwlnt' && activeTab.value !== 'all')
const batchItems = computed(() => selectedRows.value.map(row => ({
reportId: row.id,
flowId: row.flowId
})))
const handleSelectionChange = (rows) => {
selectedRows.value = rows
}
const selectable = (row) => Boolean(row.flowId)
const handleBatchPass = () => {
finishDialog.value = true
}
const handleBatchPassSuccess = () => {
finishDialog.value = false
selectedRows.value = []
getList()
}
const handleBatchReject = async () => {
await feedback.confirm(`确定批量驳回选中的 ${selectedRows.value.length} 个项目吗?`)
batchRejectLoading.value = true
try {
const results = await Promise.allSettled(selectedRows.value.map(row => auditRejectWarning({
flowId: row.flowId,
reportId: row.id,
approverMessage: ''
})))
const successCount = results.filter(item => item.status === 'fulfilled').length
const failCount = results.length - successCount
if (failCount > 0) {
feedback.msgError(`批量驳回完成:成功 ${successCount} 个,失败 ${failCount}`)
} else {
feedback.msgSuccess(`已批量驳回 ${successCount} 个项目`)
}
selectedRows.value = []
getList()
} finally {
batchRejectLoading.value = false
}
}
const getList = async ()=>{
loading.value=true
const res = await warningPage(query.value)
@ -57,6 +101,7 @@ const editFun = (row) =>{
let routeQuery ={
// isEnd:row.reportType === "",
reportId:row.id,
...(row.flowId ? { flowId: row.flowId } : {}),
// isEdit:true,
backPath:'/warning',
}
@ -145,6 +190,19 @@ watch(()=>route.query.load,(val)=>{
</el-form>
<div class="flex end">
<div>
<template v-if="activeTab === '2'">
<el-button
type="success"
:disabled="selectedRows.length === 0"
@click="handleBatchPass"
>批量通过</el-button>
<el-button
type="danger"
:disabled="selectedRows.length === 0"
:loading="batchRejectLoading"
@click="handleBatchReject"
>批量驳回</el-button>
</template>
<el-button type="primary" :loading="exportLoading" @click="handleExcel">导出</el-button>
<el-button type="primary" @click="getList">
<template #icon>
@ -165,7 +223,13 @@ watch(()=>route.query.load,(val)=>{
<el-tab-pane label="已预警" name="1"></el-tab-pane>
<el-tab-pane label="长望浏宁" name="cwlnt"></el-tab-pane>
</el-tabs>
<el-table :data="tableData">
<el-table :data="tableData" @selection-change="handleSelectionChange">
<el-table-column
v-if="activeTab === '2'"
type="selection"
width="50"
:selectable="selectable"
/>
<el-table-column label="项目名称" prop="reportName" width="200" />
<el-table-column
label="报审类型"
@ -293,6 +357,15 @@ watch(()=>route.query.load,(val)=>{
<p>
列表根据权限范围展示涉及的可预警项目针对项目进行问题预警报审单位签收
</p>
<finish-distrbute
v-if="finishDialog"
@submitFeedback="handleBatchPassSuccess"
@closeFun="finishDialog = false"
:isWarning="true"
:batchItems="batchItems"
:dialog="finishDialog"
:nextNode="'end'"
/>
</el-main>
</div>
</template>

Loading…
Cancel
Save