Files
supervision-test-frontend-repo/src/views/bg/bqtakepulse/BgTakepulseList.vue
T
wsmandClaude Opus 4.7 98abb8fa95 fix(bqtakepulse): 修复前端页面 QA 审查发现的问题
- 部门树切换点选模式并回写牵头/协办部门
- 导出切换 EasyExcel 端点,统计标签随操作刷新
- 牵头部门必填星号、保存提示、标题点击防连带展开
- bpmStatus 空值不再同时显示发起与再次督办,搜索加防抖

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-11 17:43:30 +08:00

907 lines
30 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="searchQuery" :model="queryParam" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-row :gutter="24">
<a-col :xl="4" :lg="6" :md="8" :sm="12">
<a-form-item name="title">
<template #label>
<a-tooltip title="支持模糊查询,输入意见主题关键词">意见主题</a-tooltip>
</template>
<a-tooltip title="支持模糊查询,输入意见主题关键词"><JInput v-model:value="queryParam.title" type="like" placeholder="请输入意见主题" allow-clear trim @change="debouncedSearchQuery" /></a-tooltip>
</a-form-item>
</a-col>
<a-col :xl="4" :lg="6" :md="8" :sm="12">
<a-form-item name="manageSuoleader">
<template #label>
<a-tooltip title="按所党委分管所领导筛选">分管所领导</a-tooltip>
</template>
<a-tooltip title="按所党委分管所领导筛选"><DeptRoleUserSelectDropDown v-model:value="queryParam.manageSuoleader" :deptId="PARTY_COMMITTEE_DEPT_ID" :roleId="CHARGE_LEADER_ROLE_ID" placeholder="请选择分管所领导" allow-clear style="width: 100%" @change="searchQuery" /></a-tooltip>
</a-form-item>
</a-col>
<a-col :xl="5" :lg="6" :md="8" :sm="12">
<a-form-item name="responDeptid">
<template #label>
<a-tooltip title="按牵头部门筛选">牵头部门</a-tooltip>
</template>
<a-tooltip title="按牵头部门筛选"><sz-select-dept placeholder="请选择牵头部门" v-model:value="selectedResponDept" :checkable="false" checkStrictly allow-clear @change="handleResponDeptChange" /></a-tooltip>
</a-form-item>
</a-col>
<a-col :xl="5" :lg="6" :md="8" :sm="12">
<a-form-item name="assistDeptid">
<template #label>
<a-tooltip title="按协办部门筛选">协办部门</a-tooltip>
</template>
<a-tooltip title="按协办部门筛选"><sz-select-dept placeholder="请选择协办部门" v-model:value="selectedAssistDept" :checkable="false" checkStrictly allow-clear @change="handleAssistDeptChange" /></a-tooltip>
</a-form-item>
</a-col>
<a-col :xl="4" :lg="6" :md="8" :sm="12">
<span class="table-page-search-submitButtons">
<a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button>
<a-button preIcon="ant-design:reload-outlined" style="margin-left: 8px" @click="searchReset">重置</a-button>
</span>
</a-col>
</a-row>
</a-form>
</div>
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection" :expandedRowKeys="expandedRowKeys" @expand="handleExpand" :expandIcon="expandIcon" :rowClassName="(r) => r.bpmStatus ? 'status-row-' + r.bpmStatus : ''">
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" v-auth="'bqtakepulse:bg_takepulse:add'" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
<a-button type="primary" v-auth="'bqtakepulse:bg_takepulse:exportXls'" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
<a-button type="primary" v-auth="'bqtakepulse:bg_takepulse:exportXls'" preIcon="ant-design:download-outlined" @click="handleDownloadTemplate">下载模板</a-button>
<j-upload-button type="primary" v-auth="'bqtakepulse:bg_takepulse:importExcel'" preIcon="ant-design:check-outlined" @click="handleCheckExcel">模板校验</j-upload-button>
<j-upload-button type="primary" v-auth="'bqtakepulse:bg_takepulse: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="'bqtakepulse:bg_takepulse:deleteBatch'">批量操作
<Icon icon="mdi:chevron-down"></Icon>
</a-button>
</a-dropdown>
<!-- 高级查询 -->
<super-query :config="superQueryConfig" @search="handleSuperQuery" />
<a-space style="float: right; font-size: 14px; font-weight: bold">
<a-tag color="warning" style="color: #8c6900">未开始 {{ statsData.notStarted }}</a-tag>
<a-tag color="error">督办中 {{ statsData.inProgress }}已逾期 {{ statsData.overdue }}</a-tag>
<a-tag color="success">已完成 {{ statsData.completed }}</a-tag>
</a-space>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction stopButtonPropagation :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
</template>
<!--字段回显插槽-->
<template v-slot:bodyCell="{ column, record, index, text }">
<template v-if="column.dataIndex === 'title'">
<a-tooltip title="点击查看详情">
<a style="font-weight: 500" @click.stop="handleDetail(record)">{{ text }}</a>
</a-tooltip>
</template>
</template>
<!-- 嵌套反馈信息表仅展示当前事项下的执行情况反馈记录 -->
<template #expandedRowRender="{ record }">
<div class="feedback-expand-table">
<div class="feedback-expand-header">
<div class="feedback-expand-title">
<span class="feedback-expand-icon">
<Icon icon="ant-design:message-outlined" />
</span>
<span>办理情况</span>
<template v-if="getFeedbackTableLoading(record)">
<a-tag class="feedback-expand-count" color="processing">加载中</a-tag>
</template>
<template v-else>
<a-tag class="feedback-expand-count" color="warning" style="color: #8c6900">未开始 {{ getFeedbackStatusCount(record).notStarted }}</a-tag>
<a-tag class="feedback-expand-count" color="error">进行中 {{ getFeedbackStatusCount(record).inProgress }}已逾期 {{ getFeedbackStatusCount(record).overdue }}</a-tag>
<a-tag class="feedback-expand-count" color="success">已完成 {{ getFeedbackStatusCount(record).completed }}</a-tag>
<a-tag class="feedback-expand-count">( {{ getFeedbackStatusCount(record).total }} )</a-tag>
</template>
</div>
<div class="feedback-expand-desc">当前事项的执行情况办理情况记录</div>
</div>
<BasicTable
class="feedback-inner-table"
bordered
size="small"
rowKey="id"
:canResize="false"
:showIndexColumn="false"
:showActionColumn="false"
:showTableSetting="false"
:clickToRowSelect="false"
:columns="feedbackExpandColumns"
:dataSource="getFeedbackTableData(record)"
:loading="getFeedbackTableLoading(record)"
:pagination="false"
:scroll="{ x: 1780 }"
>
<template #feedbackAttachments="{ record: feedbackRecord }">
<SUploadFile
v-if="feedbackRecord.id"
class="feedback-attachment-list"
:bussiness-id="feedbackRecord.id"
:disabled="true"
:multiple="true"
/>
<span v-else>-</span>
</template>
</BasicTable>
</div>
</template>
</BasicTable>
<!-- 表单区域 -->
<BgTakepulseModal @register="registerModal" @success="handleSuccess"></BgTakepulseModal>
<!-- 审批记录 -->
<BpmPictureModal @register="registerBpmModal" />
<FlowScheduleStartModalForBG ref="flowScheduleModalRef" @confirm="handleFlowScheduleConfirm" />
<BusinessProcessListModal ref="businessProcessListModalRef" />
</div>
</template>
<script lang="ts" name="bqtakepulse-bgTakepulse" setup>
import {ref, reactive, h, onMounted} from 'vue';
import {BasicTable, TableAction} from '/@/components/Table';
import type { BasicColumn } from '/@/components/Table';
import { useListPage } from '/@/hooks/system/useListPage'
import {useModal} from '/@/components/Modal';
import BgTakepulseModal from './components/BgTakepulseModal.vue'
import {columns, superQuerySchema} from './BgTakepulse.data';
import {list, statusStats, deleteOne, getImportUrl, getExportXlsByEasyExcelUrl, getImportExcelByEasyExcelUrl, getCheckExcelByEasyExcelUrl, getExportXlsHeadersUrl, saveOrUpdate, bgTakepulseFeedbackList} from './BgTakepulse.api';
import { defHttp } from '/@/utils/http/axios';
import { showImportValidationErrors } from '/@/utils/helper/importError';
import { useMessage } from '/@/hooks/web/useMessage';
import { countFeedbackStatus } from '/@/views/bg/utils/feedbackStatusCount';
import { useDebounceFn } from '@vueuse/core';
import SzSelectDept from '/@/components/Form/src/jeecg/components/SzSelectDept.vue';
import JInput from '/@/components/Form/src/jeecg/components/JInput.vue';
import DeptRoleUserSelectDropDown from '/@/components/semri/userComponent/DeptRoleUserSelectDropDown.vue';
import { Tooltip } from 'ant-design-vue';
import { PARTY_COMMITTEE_DEPT_ID, CHARGE_LEADER_ROLE_ID } from '/@/constant/supervision';
import Icon from '/@/components/Icon/index';
import { startProcessSchedules } from '/@/api/common/api';
import { dateUtil } from '/@/utils/dateUtil';
import FlowScheduleStartModalForBG from '/src/components/semri/process/FlowScheduleStartModalForBG.vue';
import BusinessProcessListModal from '/src/components/semri/process/BusinessProcessListModal.vue';
import SUploadFile from '/@/components/semri/fileComponent/SUploadFile.vue';
import {batchDelete} from "@/views/bg/bqtakepulse/BgTakepulse.api";
const [registerBpmModal, { openModal: bpmPicModal }] = useModal();
const FLOW_CODE = 'dev_task_task_001';
const BUSINESS_TABLE_NAME = 'bg_takepulse';
const FORM_URL = 'bg/bqtakepulse/components/BgTakepulseBPMForm';
const FLOW_NAME = '我为四所把把脉';
function expandIcon({ expanded, onExpand, record }: { expanded: boolean; onExpand: Function; record: Recordable }) {
const iconCls = expanded
? 'ant-table-row-expand-icon ant-table-row-expand-icon-expanded'
: 'ant-table-row-expand-icon ant-table-row-expand-icon-collapsed';
return h(
Tooltip,
{ title: '查看当前事项办理情况' },
{
default: () =>
h('button', {
type: 'button',
class: iconCls,
onClick: (e: Event) => onExpand(record, e),
}),
},
);
}
const formRef = ref();
const queryParam = reactive<any>({});
const selectedResponDept = ref([]);
const selectedAssistDept = ref([]);
const expandedRowKeys = ref<Array<string | number>>([]);
const feedbackTableData = reactive<Record<string, Recordable[]>>({});
const statsData = reactive({ notStarted: 0, inProgress: 0, overdue: 0, completed: 0 });
const feedbackTableLoading = reactive<Record<string, boolean>>({});
//注册model
const [registerModal, {openModal}] = useModal();
const flowScheduleModalRef = ref();
const businessProcessListModalRef = ref();
//注册table数据
const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
tableProps:{
title: '我为四所把把脉',
api: list,
columns,
canResize:false,
useSearchForm: false,
expandRowByClick: true,
clickToRowSelect: false,
rowSelection: { type: 'checkbox' },
actionColumn: {
width: 120,
fixed:'right'
},
beforeFetch: async (params) => {
return Object.assign(params, queryParam);
},
pagination: {
current: 1,
pageSize: 12,
pageSizeOptions: ['12', '24', '36'],
},
},
exportConfig: {
name:"我为四所把把脉",
url: getExportXlsByEasyExcelUrl,
params: queryParam,
},
importConfig: {
url: getImportUrl,
success: handleSuccess
},
})
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext
interface DeptOption {
label: string;
value: string;
}
// 反馈展开区只读展示子表数据,列配置与 BPM 办理页保持同一组核心反馈字段。
const feedbackExpandColumns: BasicColumn[] = [
{ title: '责任部门名称', dataIndex: 'responDeptname', align: 'center', width: 160 },
{ title: '反馈人姓名', dataIndex: 'responPersonname', align: 'center', width: 110 },
{ title: '计划完成目标', dataIndex: 'planExect', align: 'left', width: 260 },
{
title: '计划完成日期',
dataIndex: 'planTime',
align: 'center',
width: 120,
customRender: ({ text }) => (!text ? '' : String(text).slice(0, 10)),
},
{ title: '实际执行情况', dataIndex: 'actualExect', align: 'left', width: 280 },
{ title: '实际完成日期', dataIndex: 'actualTime', align: 'center', width: 155, customRender: ({ text }) => (!text ? '' : String(text).slice(0, 10)) },
{ title: '调整落实措施及执行情况', dataIndex: 'actSt', align: 'left', width: 260 },
{
title: '完成状态',
dataIndex: 'bpmStatus',
align: 'center',
width: 95,
customRender: ({ record }) => record?.bpmStatus_dictText || record?.bpmStatus,
},
{
title: '附件下载',
dataIndex: 'id',
key: 'attachments',
align: 'left',
width: 340,
slots: { customRender: 'feedbackAttachments' },
},
];
// 高级查询配置
const superQueryConfig = reactive(superQuerySchema);
function getFeedbackKey(record: Recordable) {
return String(record?.id ?? '');
}
function getFeedbackTableData(record: Recordable) {
return feedbackTableData[getFeedbackKey(record)] || [];
}
function getFeedbackCount(record: Recordable) {
return getFeedbackTableData(record).length;
}
function getFeedbackTableLoading(record: Recordable) {
return !!feedbackTableLoading[getFeedbackKey(record)];
}
function getFeedbackStatusCount(record: Recordable) {
return countFeedbackStatus(getFeedbackTableData(record), 'bpmStatus', 'planTime');
}
function clearFeedbackTableData() {
Object.keys(feedbackTableData).forEach((key) => {
delete feedbackTableData[key];
});
Object.keys(feedbackTableLoading).forEach((key) => {
delete feedbackTableLoading[key];
});
}
function resetFeedbackExpand() {
expandedRowKeys.value = [];
clearFeedbackTableData();
}
async function loadFeedbackTableData(mainId: string | number) {
const key = String(mainId);
feedbackTableLoading[key] = true;
try {
const res = await bgTakepulseFeedbackList({
mainId,
pageNo: 1,
pageSize: 9999,
column: 'createTime',
order: 'desc',
});
feedbackTableData[key] = Array.isArray(res) ? res : res?.records || res?.result?.records || [];
} finally {
feedbackTableLoading[key] = false;
}
}
async function handleExpand(expanded: boolean, record: Recordable) {
const mainId = record?.id;
expandedRowKeys.value = [];
if (!expanded || mainId === undefined || mainId === null || mainId === '') {
return;
}
expandedRowKeys.value = [mainId];
await loadFeedbackTableData(mainId);
}
/**
* 高级查询事件
*/
function handleSuperQuery(params) {
Object.keys(params).map((k) => {
queryParam[k] = params[k];
});
searchQuery();
}
function searchQuery() {
selectedRowKeys.value = [];
resetFeedbackExpand();
reload({ page: 1 });
fetchStatusStats();
}
// 输入框逐字触发的查询做防抖,查询按钮仍走未防抖的 searchQuery
const debouncedSearchQuery = useDebounceFn(searchQuery, 500);
async function fetchStatusStats() {
try {
const params: Recordable = {};
Object.keys(queryParam).forEach((key) => {
if (queryParam[key] !== undefined && queryParam[key] !== null && queryParam[key] !== '') {
params[key] = queryParam[key];
}
});
const res = await statusStats(params);
if (res) {
Object.assign(statsData, res);
}
} catch (e) {
// stats fetch failure is non-critical
}
}
onMounted(() => {
fetchStatusStats();
});
/**
* 新增事件
*/
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 = [];
resetFeedbackExpand();
reload();
fetchStatusStats();
}
/**
* 操作栏
*/
function getTableAction(record){
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
auth: 'bqtakepulse:bg_takepulse:edit'
}
]
}
/**
* 下拉操作栏
*/
function getDropDownAction(record){
let dropDownAction = [
{
label: '详情',
onClick: handleDetail.bind(null, record),
}, {
label: '删除',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record)
},
auth: 'bqtakepulse:bg_takepulse:delete'
},
// {
// label: '审批进度',
// onClick: handlePreviewPic.bind(null, record),
// ifShow: !!record.bpmStatus && record.bpmStatus !== '1',
// },
{
label: '查询督办流程',
onClick: handleQueryProcess.bind(null, record),
}
];
if(!record.bpmStatus || record.bpmStatus == '1'){
dropDownAction.push({
label: '发起督办流程',
onClick: handleProcess.bind(null, record),
})
}
if(record.bpmStatus == '2'){
dropDownAction.push({
label: '再次督办',
onClick: handleProcess.bind(null, record),
})
}
return dropDownAction;
}
/**
* 提交流程
*/
const CN = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九'];
function toChinese(num: number): string {
return String(num).split('').map(c => CN[Number(c)]).join('');
}
function handleProcess(record) {
const nextCount = getNextSuperviseCount(record.superviseCount);
const title = nextCount > 1
? `发起流程(${record?.title || ''}${toChinese(nextCount)}次督办)`
: '发起流程';
flowScheduleModalRef.value?.open({
title,
taskTitle: nextCount > 1 ? `${record?.title || ''}${nextCount}次督办` : record?.title,
payload: { record },
deptOptions: getResponsibleDeptOptions(record),
showSuoleaderFields: true,
isNeedAppro: record?.isNeedAppro,
supDeptleaderid: record?.supDeptleaderid,
showDeadlineField: true,
deadline: record?.deadline,
showUrgencyLevelField: true,
urgencyLevel: record?.urgencyLevel,
});
}
function splitDeptValue(value) {
if (Array.isArray(value)) {
return value.map((item) => String(item || '').trim()).filter(Boolean);
}
return String(value || '')
.split(/[,\uFF0C]/)
.map((item) => item.trim())
.filter(Boolean);
}
function getResponsibleDeptOptions(record): DeptOption[] {
const optionMap = new Map<string, DeptOption>();
[
{
ids: splitDeptValue(record?.responDeptid),
names: splitDeptValue(record?.responDeptid_dictText || record?.responDeptname),
},
{
ids: splitDeptValue(record?.assistDeptid),
names: splitDeptValue(record?.assistDeptid_dictText || record?.assistDeptname),
},
].forEach(({ ids, names }) => {
ids.forEach((deptId, index) => {
if (optionMap.has(deptId)) {
return;
}
optionMap.set(deptId, {
value: deptId,
label: names[index] || deptId,
});
});
});
return Array.from(optionMap.values());
}
function getResponsibleDeptIds(record) {
return getResponsibleDeptOptions(record)
.map((item) => item.value)
.join(',');
}
function getNextSuperviseCount(value) {
const count = Number(value || 0);
return Number.isFinite(count) ? count + 1 : 1;
}
function handleQueryProcess(record) {
businessProcessListModalRef.value?.open({
title: '流程列表',
businessId: record.id,
columns: '',
});
}
async function handleFlowScheduleConfirm({ payload, options }) {
const record = payload?.record || {};
const formatDate = (value, format) => {
return value ? dateUtil(value).format(format) : undefined;
};
const formatDeadlineDateTime = (value) => {
const deadlineDate = formatDate(value, 'YYYY-MM-DD');
return deadlineDate ? `${deadlineDate} 00:00:00` : undefined;
};
const nextSuperviseCount = getNextSuperviseCount(record.superviseCount);
const selectedTitle = options.title || record.title || '';
const selectedDeadline = options.deadline || record.deadline;
const selectedUrgencyLevel = options.urgencyLevel ?? record.urgencyLevel ?? '0';
const defaultDeptIds = getResponsibleDeptIds(record);
const flowJsonData = {
...record,
isNeedAppro: options.isNeedAppro ?? record.isNeedAppro ?? '',
supDeptleaderid: options.supDeptleaderid ?? record.supDeptleaderid ?? '',
superviseCount: nextSuperviseCount,
// 用户可在发起前确认本次督办标题,仅影响流程数据,不回写台账标题。
title: selectedTitle,
deadline: selectedDeadline,
// 紧急标记随本次流程发起传出,业务表只回写状态和督办次数。
urgencyLevel: selectedUrgencyLevel,
// 首节点自动完成时读取该字段写入审批历史。
startApprovalOpinion: options.approvalOpinion,
};
const params = {
intervalType: options.intervalType,
startCount: options.startCount,
taskTask: {
// 重复督办参数与党委会事项保持一致。
triggerType: options.triggerType,
startTime: options.intervalStartTime,
flowCode: FLOW_CODE,
formUrl: FORM_URL,
flowName: FLOW_NAME,
jsonData: flowJsonData,
businessTablename: BUSINESS_TABLE_NAME,
businessId: record.id,
title: selectedTitle,
content: record.content,
urgencyLevel: selectedUrgencyLevel,
deptId: options.deptId || defaultDeptIds,
deptLeaderId: record.responDeptid,
requireFinishDate: formatDate(selectedDeadline, 'YYYY-MM-DD'),
deadline: formatDeadlineDateTime(selectedDeadline),
},
};
await startProcessSchedules(params);
await saveOrUpdate({ id: record.id, bpmStatus: '2', superviseCount: nextSuperviseCount }, true);
handleSuccess();
}
/**
* 审批进度
*/
async function handlePreviewPic(record) {
bpmPicModal(true, {
flowCode: FLOW_CODE,
dataId: record.id,
});
}
/* ----------------------以下为原生查询需要添加的-------------------------- */
const { createMessage } = useMessage();
const labelCol = reactive({
xs:24,
sm:4,
xl:6,
xxl:8
});
const wrapperCol = reactive({
xs: 24,
sm: 20,
});
/**
* 重置
*/
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 handleResponDeptChange(values) {
if (values && values.length > 0) {
queryParam.responDeptid = values.join(',');
} else {
delete queryParam.responDeptid;
}
searchQuery();
fetchStatusStats();
}
function handleAssistDeptChange(values) {
if (values && values.length > 0) {
queryParam.assistDeptid = values.join(',');
} else {
delete queryParam.assistDeptid;
}
searchQuery();
fetchStatusStats();
}
function searchReset() {
formRef.value.resetFields();
selectedRowKeys.value = [];
selectedResponDept.value = [];
selectedAssistDept.value = [];
resetFeedbackExpand();
//刷新数据
reload({ page: 1 });
fetchStatusStats();
}
/**
* form点击事件(以逗号分割)
* @param key
* @param value
*/
</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%;
}
}
.feedback-expand-table {
margin: 4px 10px 12px 42px;
padding: 12px 14px 14px;
background: #f6fbff;
border: 1px solid #d6e8ff;
border-left: 4px solid #1677ff;
border-radius: 6px;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.72);
.feedback-expand-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-bottom: 10px;
}
.feedback-expand-title {
display: inline-flex;
align-items: center;
min-width: 0;
color: #1f2937;
font-size: 14px;
font-weight: 600;
line-height: 24px;
}
.feedback-expand-icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
margin-right: 8px;
color: #1677ff;
background: #e6f4ff;
border-radius: 50%;
}
.feedback-expand-count {
margin-left: 10px;
}
.feedback-expand-desc {
color: #64748b;
font-size: 13px;
line-height: 22px;
white-space: nowrap;
}
:deep(.jeecg-basic-table) {
background: #fff;
}
:deep(.feedback-inner-table .ant-table-wrapper) {
padding: 0;
border-radius: 4px;
}
:deep(.feedback-inner-table .ant-table-thead > tr > th) {
background: #eef6ff;
color: #334155;
font-weight: 600;
}
:deep(.feedback-inner-table .ant-table-tbody > tr > td) {
background: #fff;
}
:deep(.feedback-inner-table .ant-table-tbody > tr:hover > td) {
background: #f8fbff;
}
.feedback-attachment-list {
min-width: 300px;
:deep(.file-list-wrapper) {
min-height: 0 !important;
padding: 4px 8px !important;
}
:deep(.ant-spin-nested-loading),
:deep(.ant-spin-container) {
min-height: 0 !important;
line-height: 20px;
}
:deep(.file-list-header) {
margin-bottom: 6px;
padding-bottom: 6px;
}
:deep(.file-list .file-item) {
padding: 8px;
margin-bottom: 6px;
}
:deep(.ant-empty) {
margin: 0 !important;
display: flex;
align-items: center;
min-height: 20px;
text-align: left;
}
:deep(.ant-empty-image) {
display: none !important;
}
:deep(.ant-empty-description) {
color: #94a3b8;
font-size: 12px;
line-height: 20px;
}
}
}
</style>
<style lang="less">
.status-row-1 td {
background: #fffbe6 !important;
}
.status-row-2 td {
background: #fff1f0 !important;
}
.status-row-3 td {
background: #f6ffed !important;
}
</style>