Files
supervision-test-frontend-repo/src/views/dq/inspectTask/DqInspectTaskList.vue
T
wsm 01db46e67c !86 feat(inspectTask): 台账列表新增业务状态列
* Merge branch 'master' of gitee.com:sz_30/supervision-vue into feature/…
* feat(inspectTask): 台账列表新增业务状态列
* feat(feedback): 反馈信息弹窗标题增加已完成条数统计
2026-07-07 02:52:56 +00:00

650 lines
22 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="p-2">
<!--查询区域-->
<div class="jeecg-basic-table-form-container">
<a-form ref="formRef" @keyup.enter.native="reload" :model="queryParam" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-row :gutter="24">
<a-col :lg="6">
<a-form-item name="improveMeasure">
<template #label><span title="整改措施">整改措施</span></template>
<a-input v-model:value="queryParam.improveMeasure" allow-clear />
</a-form-item>
</a-col>
<a-col :lg="8">
<a-form-item name="measureResLeader">
<template #label><span title="措施责任领导">措施责任领导</span></template>
<SzDeptUserModal v-model:value="queryParam.measureResLeader" placeholder="请选择措施责任领导" />
</a-form-item>
</a-col>
<a-col :lg="6">
<a-form-item name="completedStage" label="流程阶段">
<a-select v-model:value="completedStageFilter" placeholder="请选择" allow-clear @change="handleCompletedStageChange">
<a-select-option value="0">未发起巡视整改流程</a-select-option>
<a-select-option value="1">正在巡视整改流程</a-select-option>
<a-select-option value="2">巡视整改流程结束</a-select-option>
<a-select-option value="3">正在巡视整改销号流程</a-select-option>
<a-select-option value="4">巡视整改销号流程结束</a-select-option>
</a-select>
</a-form-item>
</a-col>
<template v-if="toggleSearchStatus">
<a-col :lg="8">
<a-form-item name="measureResDept">
<template #label><span title="措施责任部门">措施责任部门</span></template>
<SzSelectDept v-model:value="queryParam.measureResDept" :multiple="true" checkStrictly allow-clear />
</a-form-item>
</a-col>
</template>
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<span style="float: left; overflow: hidden" class="table-page-search-submitButtons">
<a-col :lg="6">
<a-button type="primary" preIcon="ant-design:search-outlined" @click="reload">查询</a-button>
<a-button preIcon="ant-design:reload-outlined" @click="searchReset" style="margin-left: 8px">重置</a-button>
<a @click="toggleSearchStatus = !toggleSearchStatus" style="margin-left: 8px">
{{ toggleSearchStatus ? '收起' : '展开' }}
<Icon :icon="toggleSearchStatus ? 'ant-design:up-outlined' : 'ant-design:down-outlined'" />
</a>
</a-col>
</span>
</a-col>
</a-row>
</a-form>
</div>
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection" @fetch-success="onFetchSuccess">
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" v-auth="'dqinspecttask:dq_inspect_task:add'" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
<a-button type="primary" v-auth="'dqinspecttask:dq_inspect_task:exportXls'" preIcon="ant-design:export-outlined" @click="onExportXls">
导出</a-button
>
<j-upload-button
type="primary"
v-auth="'dqinspecttask:dq_inspect_task:importExcel'"
preIcon="ant-design:import-outlined"
@click="onImpportXls"
>导入</j-upload-button
>
<a-button
type="primary"
v-auth="'dqinspecttask:dq_inspect_task:exportXls'"
preIcon="ant-design:download-outlined"
@click="handleDownloadTemplate"
>下载模板</a-button
>
<j-upload-button
type="primary"
v-auth="'dqinspecttask:dq_inspect_task:importExcel'"
preIcon="ant-design:check-outlined"
@click="handleCheckExcel"
>模板校验</j-upload-button
>
<j-upload-button
type="primary"
v-auth="'dqinspecttask:dq_inspect_task:importExcel'"
preIcon="ant-design:import-outlined"
@click="handleImportByTemplate"
>模板导入</j-upload-button
>
<a-dropdown v-if="selectedRowKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleDelete">
<Icon icon="ant-design:delete-outlined"></Icon>
删除
</a-menu-item>
</a-menu>
</template>
<a-button v-auth="'dqinspecttask:dq_inspect_task:deleteBatch'"
>批量操作
<Icon icon="mdi:chevron-down"></Icon>
</a-button>
</a-dropdown>
<!-- 高级查询 -->
<super-query :config="superQueryConfig" @search="handleSuperQuery" />
</template>
<!--操作栏-->
<template #action="{ record }">
<Dropdown :trigger="['hover']" :dropMenuList="getFlowMenuList(record)" popconfirm>
<a-button type="link" size="small">流程操作 <Icon icon="mdi-light:chevron-down" /></a-button>
</Dropdown>
<Dropdown :trigger="['hover']" :dropMenuList="getFormMenuList(record)" popconfirm>
<a-button type="link" size="small">表单操作 <Icon icon="mdi-light:chevron-down" /></a-button>
</Dropdown>
</template>
<!--字段回显插槽-->
<template v-slot:bodyCell="{ column, record, index, text }"> </template>
</BasicTable>
<!-- 表单区域 -->
<DqInspectProgressFeedbackViewModal ref="feedbackViewModalRef" />
<DqInspectTaskModal @register="registerModal" @success="handleSuccess"></DqInspectTaskModal>
<!-- 审批记录 -->
<BpmPictureModal @register="registerBpmModal" />
<FlowScheduleStartModal ref="flowScheduleModalRef" @confirm="handleFlowScheduleConfirm" />
<BusinessProcessListModal ref="businessProcessListModalRef" />
</div>
</template>
<script lang="ts" name="dqinspecttask-dqInspectTask" setup>
import { ref, reactive, computed, unref } from 'vue';
import { BasicTable, useTable } from '/@/components/Table';
import { Dropdown } from '/@/components/Dropdown';
import { useListPage } from '/@/hooks/system/useListPage';
import { useModal } from '/@/components/Modal';
import DqInspectTaskModal from './components/DqInspectTaskModal.vue';
import DqInspectProgressFeedbackViewModal from '../inspectProgress/components/DqInspectProgressFeedbackViewModal.vue';
import { ledgerColumns, superQuerySchema } from './DqInspectTask.data';
import {
ledgerList,
deleteOne,
batchDelete,
getImportUrl,
getExportUrl,
getImportExcelByEasyExcelUrl,
getCheckExcelByEasyExcelUrl,
getExportXlsHeadersUrl,
saveOrUpdate,
} from './DqInspectTask.api';
import { defHttp } from '/@/utils/http/axios';
import { showImportValidationErrors } from '/@/utils/helper/importError';
import { downloadFile } from '/@/utils/common/renderUtils';
import { useMessage } from '/@/hooks/web/useMessage';
import Icon from '/@/components/Icon/index';
import SzSelectDept from '/@/components/Form/src/jeecg/components/SzSelectDept.vue';
import SzDeptUserModal from '/@/components/semri/deptUserComponent/SzDeptUserModal.vue';
import { startProcessSchedules, getBusinessStatus } from '/@/api/common/api';
import { dateUtil } from '/@/utils/dateUtil';
import FlowScheduleStartModal from './components/DqInspectTaskFlowScheduleStartModal.vue';
import BusinessProcessListModal from '/src/components/semri/process/BusinessProcessListModal.vue';
const [registerBpmModal, { openModal: bpmPicModal }] = useModal();
import { useUserStore } from '/@/store/modules/user';
const formRef = ref();
const queryParam = reactive<any>({});
const checkedKeys = ref<Array<string | number>>([]);
//注册model
const [registerModal, { openModal }] = useModal();
const feedbackViewModalRef = ref();
const flowScheduleModalRef = ref();
const businessProcessListModalRef = ref();
const completedStageFilter = ref();
const userStore = useUserStore();
const { createMessage } = useMessage();
//注册table数据
const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
tableProps: {
title: 'dq_inspect_task',
api: ledgerList,
columns: ledgerColumns,
canResize: false,
useSearchForm: false,
pagination: {
current: 1,
pageSize: 12,
pageSizeOptions: ['12', '24', '36'],
},
actionColumn: {
width: 240,
fixed: 'right',
},
beforeFetch: async (params) => {
return Object.assign(params, queryParam);
},
afterFetch: async (items) => {
return calcLedgerRowSpan(items);
},
},
exportConfig: {
name: 'dq_inspect_task',
url: getExportUrl,
params: queryParam,
},
importConfig: {
url: getImportUrl,
success: handleSuccess,
},
});
const [registerTable, { reload, setTableData, getDataSource }, { rowSelection, selectedRowKeys }] = tableContext;
// 高级查询配置
const superQueryConfig = reactive(superQuerySchema);
/**
* 高级查询事件
*/
function handleSuperQuery(params) {
Object.keys(params).map((k) => {
queryParam[k] = params[k];
});
reload();
}
/**
* 新增事件
*/
function handleAdd() {
openModal(true, {
isUpdate: false,
showFooter: true,
});
}
/**
* 编辑事件
*/
function handleEdit(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: true,
});
}
/**
* 详情
*/
function handleDetail(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: false,
});
}
/**
* 删除事件
*/
async function handleDelete(record) {
await deleteOne({ id: record.id }, handleSuccess);
}
/**
* 批量删除事件
*/
async function batchHandleDelete() {
await batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
}
/**
* 成功回调
*/
function handleSuccess() {
(selectedRowKeys.value = []) && reload();
}
async function handleDownloadTemplate() {
const data = await defHttp.get({ url: getExportXlsHeadersUrl, params: {}, responseType: 'blob', timeout: 60000 }, { isTransformResponse: false });
if (!data) {
createMessage.warning('文件下载失败');
return;
}
const blob = new Blob([data]);
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = '整改任务-导入模板.xls';
link.click();
URL.revokeObjectURL(link.href);
}
async function handleCheckExcel(data) {
const isReturn = (fileInfo) => {
try {
if (fileInfo.code === 500 || fileInfo.code === 510) {
if (fileInfo.result && Array.isArray(fileInfo.result) && fileInfo.result.length > 0) {
showImportValidationErrors(fileInfo.message || `${data.file.name} 校验失败`, fileInfo.result);
} else {
createMessage.error(fileInfo.message || `${data.file.name} 校验失败`);
}
} else {
createMessage.success(fileInfo.message || `${data.file.name} 校验通过`);
}
} catch {
// ignore
}
};
await defHttp.uploadFile({ url: getCheckExcelByEasyExcelUrl }, { file: data.file }, { success: isReturn });
}
async function handleImportByTemplate(data) {
const isReturn = (fileInfo) => {
try {
if (fileInfo.code === 500 || fileInfo.code === 510) {
if (fileInfo.result && Array.isArray(fileInfo.result) && fileInfo.result.length > 0) {
showImportValidationErrors(fileInfo.message || `${data.file.name} 导入失败`, fileInfo.result);
} else {
createMessage.error(fileInfo.message || `${data.file.name} 导入失败`);
}
} else {
createMessage.success(fileInfo.message || `${data.file.name} 导入成功`);
}
} catch {
// ignore
} finally {
reload();
}
};
await defHttp.uploadFile({ url: getImportExcelByEasyExcelUrl }, { file: data.file }, { success: isReturn });
}
/**
* 只在当前页内计算台账合并行,避免跨页合并导致表格分页行为不可控。
*/
function calcLedgerRowSpan(items) {
if (!items || items.length === 0) {
return items;
}
calcGroupRowSpan(items, (item) => item.categoryId || item.categoryName, '_categoryRowSpan');
calcGroupRowSpan(items, (item) => `${item.categoryId || item.categoryName}_${item.surfaceId || item.surfaceName}`, '_surfaceRowSpan');
calcGroupRowSpan(
items,
(item) => `${item.categoryId || item.categoryName}_${item.surfaceId || item.surfaceName}_${item.specificId || item.specificName}`,
'_specificRowSpan'
);
return items;
}
function calcGroupRowSpan(items, getKey, field) {
let start = 0;
while (start < items.length) {
const key = getKey(items[start]);
let end = start + 1;
while (end < items.length && getKey(items[end]) === key) {
end++;
}
const span = end - start;
items[start][field] = span;
for (let i = start + 1; i < end; i++) {
items[i][field] = 0;
}
start = end;
}
}
/**
* 流程操作菜单
*/
function getFlowMenuList(record) {
const list: any[] = [];
// if ((record.bpmStatus == '1' || !record.bpmStatus) && record.completedStage === 0) {
list.push({ text: '发起巡视整改流程', icon: 'ant-design:play-circle-outlined', event: 'process', onClick: handleProcess.bind(null, record) });
// }
// if (record.bpmStatus && record.bpmStatus !== '1' && record.completedStage === 2) {
list.push({ text: '发起销号流程', icon: 'ant-design:stop-outlined', event: 'deleteProcess', onClick: handleDeleteProcess.bind(null, record) });
// }
list.push({
text: '查询督办流程',
icon: 'ant-design:search-outlined',
event: 'queryProcess',
divider: true,
onClick: handleQueryProcess.bind(null, record),
});
// if (!record.bpmStatus || record.bpmStatus == '1') {
list.push({
text: '调整为未发起巡视整改流程状态',
icon: 'ant-design:rollback-outlined',
event: 'adj0',
onClick: () => adjustCompletedStage(record, 0),
});
list.push({
text: '调整为未发起销号流程状态',
icon: 'ant-design:check-circle-outlined',
event: 'adj2',
onClick: () => adjustCompletedStage(record, 2),
});
list.push({
text: '调整为已完成销号流程状态',
icon: 'ant-design:check-circle-outlined',
event: 'adj4',
onClick: () => adjustCompletedStage(record, 4),
});
//}
return list;
}
/**
* 表单操作菜单
*/
function getFormMenuList(record) {
return [
{ text: '查看办理情况', icon: 'ant-design:eye-outlined', event: 'feedback', divider: true, onClick: handleViewFeedback.bind(null, record) },
{ text: '编辑', icon: 'ant-design:edit-outlined', event: 'edit', onClick: handleEdit.bind(null, record) },
{ text: '详情', icon: 'ant-design:file-text-outlined', event: 'detail', onClick: handleDetail.bind(null, record) },
{
text: '删除',
icon: 'ant-design:delete-outlined',
event: 'delete',
popConfirm: { title: '是否确认删除', confirm: handleDelete.bind(null, record), placement: 'topLeft' },
},
];
}
async function adjustCompletedStage(record, stage) {
await saveOrUpdate({ id: record.id, problemId: record.problemId, completedStage: stage }, true);
handleSuccess();
}
const FLOW_CODE = 'inspect_flow_create_01';
const FLOW_NAME = '巡视整改提升工作';
const BUSINESS_TABLE_NAME = 'dq_inspect_task';
const FORM_URL = 'dq/inspectTask/components/DqInspectTaskBPMForm?showFeedbackInfo=1';
const DELETE_FLOW_CODE = 'dq_delete_01';
const DELETE_FLOW_NAME = '巡视整改提升工作-销号';
const DELETE_FORM_URL = 'dq/inspectTask/components/DqInspectTaskBPMForm?showFeedbackInfo=1';
const currentScheduleFlowCode = ref('');
/**
* 发起流程
*/
function handleProcess(record) {
currentScheduleFlowCode.value = FLOW_CODE;
flowScheduleModalRef.value?.open({
title: '发起整改任务流程',
payload: { record },
deptOptions: getDeptOptions(record),
showSuoleaderFields: true,
isNeedAppro: record.isNeedAppro,
supDeptleaderid: record.supDeptleaderid,
supDeptleaderName: record.supDeptleaderid_dictText,
});
}
/**
* 发起销号流程
*/
function handleDeleteProcess(record) {
currentScheduleFlowCode.value = DELETE_FLOW_CODE;
flowScheduleModalRef.value?.open({
title: '发起销号流程',
payload: { record },
deptOptions: getDeptOptions(record),
showSuoleaderFields: true,
isNeedAppro: record.isNeedAppro,
supDeptleaderid: record.supDeptleaderid,
supDeptleaderName: record.supDeptleaderid_dictText,
});
}
/**
* 流程调度确认
*/
async function handleFlowScheduleConfirm({ payload, options }) {
const record = payload?.record || {};
const isDeleteFlow = currentScheduleFlowCode.value === DELETE_FLOW_CODE;
const flowCode = isDeleteFlow ? DELETE_FLOW_CODE : FLOW_CODE;
const flowName = isDeleteFlow ? DELETE_FLOW_NAME : FLOW_NAME;
const formUrl = isDeleteFlow ? DELETE_FORM_URL : FORM_URL;
const params = {
intervalType: options.intervalType,
startCount: options.startCount,
taskTask: {
triggerType: options.triggerType,
startTime: options.intervalStartTime,
flowCode,
formUrl,
flowName,
jsonData: { ...record },
businessTablename: BUSINESS_TABLE_NAME,
businessId: record.id,
title: record.improveMeasure || '',
content: record.improveMeasure || '',
deptId: options.deptId || record.measureResDept || '',
deptLeaderId: record.measureResLeader || '',
requireFinishDate: record.deadline || undefined,
deadline: record.deadline || undefined,
},
};
await startProcessSchedules(params);
const nextStage = (record.completedStage || 0) + 1;
await saveOrUpdate({ id: record.id, problemId: record.problemId, bpmStatus: '2', completedStage: nextStage }, true);
createMessage.success('发起成功');
handleSuccess();
}
/**
* 查询督办流程
*/
function handleQueryProcess(record) {
businessProcessListModalRef.value?.open({
title: '流程列表',
businessId: record.id,
columns: '',
});
}
/**
* 解析措施责任部门选项
*/
function getDeptOptions(record) {
const deptIds = String(record.measureResDept || '')
.split(/[,]/)
.map((s) => s.trim())
.filter(Boolean);
const deptNames = String(record.measureResDept_dictText || '')
.split(/[,]/)
.map((s) => s.trim())
.filter(Boolean);
return deptIds.map((deptId, index) => ({
value: deptId,
label: deptNames[index] || deptId,
}));
}
/**
* 查看反馈
*/
function handleViewFeedback(record) {
feedbackViewModalRef.value.open(record.id);
}
/**
* 审批进度
*/
async function handlePreviewPic(record) {
bpmPicModal(true, {
flowCode: 'inspect_flow_create_01',
dataId: record.id,
});
}
/* ----------------------以下为原生查询需要添加的-------------------------- */
const toggleSearchStatus = ref<boolean>(false);
const labelCol = reactive({
xs: 24,
sm: 4,
xl: 6,
xxl: 4,
});
const wrapperCol = reactive({
xs: 24,
sm: 20,
});
/**
* 重置
*/
function searchReset() {
formRef.value.resetFields();
selectedRowKeys.value = [];
completedStageFilter.value = undefined;
delete queryParam.completedStage;
//刷新数据
reload();
}
/**
* form点击事件(以逗号分割)
* @param key
* @param value
*/
function handleCompletedStageChange(value) {
if (value != null) {
queryParam.completedStage = Number(value);
} else {
delete queryParam.completedStage;
}
reload();
}
async function refreshBusinessStatus(records) {
if (!records || records.length === 0) return;
try {
const results = await Promise.all(
records.map((item) =>
getBusinessStatus({ businessId: item.id }).catch(() => null)
)
);
const statusMap: Record<string, string> = {};
for (const item of results) {
if (item?.businessId) {
statusMap[item.businessId] = item.status_dictText || '';
}
}
for (const item of records) {
const status = statusMap[item.id];
if (status !== undefined) {
item.status_dictText = status;
}
}
} catch (e) {
// 静默处理查询异常
}
}
async function onFetchSuccess(result) {
if (result?.items?.length > 0) {
await refreshBusinessStatus(result.items);
setTableData([...getDataSource()]);
}
}
function handleFormJoinChange(key, value) {
if (typeof value != 'string') {
queryParam[key] = value.join(',');
}
}
</script>
<style lang="less" scoped>
.jeecg-basic-table-form-container {
padding: 0;
.table-page-search-submitButtons {
display: block;
margin-bottom: 24px;
white-space: nowrap;
}
.query-group-cust {
min-width: 100px !important;
}
.query-group-split-cust {
width: 30px;
display: inline-block;
text-align: center;
}
.ant-form-item:not(.ant-form-item-with-help) {
margin-bottom: 16px;
height: 32px;
}
:deep(.ant-picker),
:deep(.ant-input-number) {
width: 100%;
}
}
</style>