Commit 26c03b64 by 史雅文

处理采集项bug

parent c4924f07
......@@ -6,13 +6,13 @@ VITE_PUBLIC_PATH=/
# 本地开发代理(解决跨域)
# 所有匹配前缀的请求将被代理到目标服务器
VITE_PROXY=[["/system","http://localhost:8080"],["/language","http://localhost:8080"],["/api","http://localhost:8080"]]
VITE_PROXY=[["/system","http://192.168.8.136:8080"],["/language","http://192.168.8.136:8080"],["/api","http://192.168.8.136:8080"]]
# 是否删除Console.log
VITE_DROP_CONSOLE=false
# 接口地址(用于代码中生成 baseURL)
VITE_GLOB_API_URL=http://localhost:8080
VITE_GLOB_API_URL=http://192.168.8.136:8080
# 文件上传接口
VITE_GLOB_UPLOAD_URL=/system/oss/upload
......
......@@ -29,21 +29,6 @@ export async function getMesCollectionItemPage(params: MesCollectionItemPagePara
}
/**
* @description: 查询MesCollectionItem列表(不分页)
*/
export async function getMesCollectionItemList(params?: MesCollectionItemPageParams, mode: ErrorMessageMode = 'modal') {
return defHttp.get<MesCollectionItemPageModel[]>(
{
url: Api.List,
params,
},
{
errorMessageMode: mode,
},
);
}
/**
* @description: 获取MesCollectionItem信息
*/
export async function getMesCollectionItem(id: String, mode: ErrorMessageMode = 'modal') {
......
......@@ -1667,21 +1667,12 @@
localStorage.setItem('tableColumnShowSetting', JSON.stringify(obj));
}
// 获取采集项表单API(用于采集方案页面)
const collectionItemFormApi = inject('collectionItemFormApi', null);
function customClick(executeButton, record?, index?) {
curRecord.value = index;
curButtonModalConfig.value = executeButton.modal;
// 特殊处理:如果是选择采集项按钮,直接调用provide的方法
if (executeButton.key === 'selectCollectionItem' && collectionItemFormApi) {
if (collectionItemFormApi.openCollectionItemSelect) {
collectionItemFormApi.openCollectionItemSelect();
}
return;
}
let obj = {
selectedRows: selectedRowsData.value,
tableDatas: data.value,
......
<template>
<BasicModal
v-bind="$attrs"
@register="registerModal"
title="选择采集项"
width="800"
@ok="handleSubmit"
@cancel="handleCancel"
:destroyOnClose="true"
>
<BasicTable @register="registerTable" />
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, nextTick } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicTable, useTable } from '/@/components/Table';
import { getMesCollectionItemPage } from '/@/api/jcsj/cjx';
import { columns } from './collectionItemColumns';
import { useMessage } from '/@/hooks/web/useMessage';
const emit = defineEmits(['success']);
const { createMessage } = useMessage();
const contentType = ref<string>('');
const getExistingItemIds = ref<(() => string[]) | null>(null); // 获取已存在的采集项ID列表的函数
// 表格配置:不再维护外部 selection 状态
const [registerTable, {
reload,
clearSelectedRowKeys,
getSelectRows,
getDataSource,
setTableData
}] = useTable({
title: '采集项列表',
rowSelection: {
type: 'checkbox',
},
api: async (params) => {
if (!contentType.value) {
createMessage.warning('请先选择采集内容');
return { list: [], total: 0 };
}
const ctParam = String(contentType.value || '');
if (!ctParam) return { list: [], total: 0 };
const queryParams = {
...params,
contentType: ctParam,
size: Math.min(params.pageSize || 50, 100),
};
try {
const result = await getMesCollectionItemPage(queryParams);
// 兼容多种返回格式
if (Array.isArray(result)) {
return { list: result, total: result.length };
}
if (result?.list) {
return { list: result.list, total: result.total ?? result.list.length };
}
if (result?.records) {
return { list: result.records, total: result.total ?? result.records.length };
}
// 泛型兼容:找第一个数组字段
for (const key in result) {
if (Array.isArray(result[key])) {
return { list: result[key], total: result.total ?? result[key].length };
}
}
} catch (error: any) {
console.error('获取采集项失败:', error);
createMessage.error(error?.message || '请求失败');
}
return { list: [], total: 0 };
},
columns,
pagination: { pageSize: 50 },
rowKey: 'id',
canResize: false,
showIndexColumn: false,
useSearchForm: false,
});
// 弹窗注册
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
// 先重置所有状态,确保按钮可用
setModalProps({
confirmLoading: false,
destroyOnClose: true,
});
// 提取 contentType
let ctValue = data?.contentType;
if (Array.isArray(ctValue)) ctValue = ctValue[0];
contentType.value = ctValue ? String(ctValue) : '';
// 保存获取已存在采集项ID列表的函数
getExistingItemIds.value = typeof data?.getExistingItemIds === 'function'
? data.getExistingItemIds
: null;
if (!contentType.value) {
createMessage.warning('请先选择采集内容');
closeModal();
return;
}
// 等待 DOM 更新
await nextTick();
// 清除可能遗留的选中状态和数据
if (clearSelectedRowKeys) {
clearSelectedRowKeys();
}
if (setTableData) {
setTableData([]);
}
// 重新加载对应类型的数据
await reload();
// 再次确保选中已清空
await nextTick();
if (clearSelectedRowKeys) {
clearSelectedRowKeys();
}
// 确保按钮状态正确
setModalProps({
confirmLoading: false,
});
});
// 提交处理:直接从表格获取选中行
async function handleSubmit() {
try {
// 设置加载状态,防止重复点击
setModalProps({ confirmLoading: true });
const selectedRows = getSelectRows();
console.log('handleSubmit - selectedRows:', selectedRows);
if (!selectedRows || selectedRows.length === 0) {
createMessage.warning('请至少选择一个采集项');
setModalProps({ confirmLoading: false });
return;
}
// 在提交时实时获取最新的采集项列表,检查是否重复
let currentExistingItemIds: string[] = [];
if (getExistingItemIds.value) {
try {
const ids = getExistingItemIds.value();
currentExistingItemIds = Array.isArray(ids)
? ids.map(id => String(id)).filter(Boolean)
: [];
} catch (error) {
console.error('获取已存在的采集项列表失败:', error);
}
}
// 检查是否与已存在的采集项重复
const duplicateItems: any[] = [];
selectedRows.forEach((item: any) => {
const itemId = String(item.id || '');
if (currentExistingItemIds.includes(itemId)) {
duplicateItems.push(item);
}
});
if (duplicateItems.length > 0) {
const names = duplicateItems.map(item => item.name || item.code || item.id).join('、');
createMessage.warning(`以下采集项已存在,不可重复选择:${names}`);
setModalProps({ confirmLoading: false });
return;
}
// 触发成功事件
emit('success', selectedRows);
// 重置加载状态
setModalProps({ confirmLoading: false });
// 清空所有数据和状态(这些操作即使失败也不应该影响成功流程)
try {
if (clearSelectedRowKeys) {
clearSelectedRowKeys();
}
if (setTableData) {
setTableData([]);
}
} catch (cleanupError) {
console.warn('清空数据时出错(不影响提交):', cleanupError);
}
// 使用 nextTick 确保状态更新后再关闭
await nextTick();
closeModal();
} catch (error) {
console.error('提交失败:', error);
createMessage.error('提交失败,请重试');
setModalProps({ confirmLoading: false });
}
}
// 取消处理
function handleCancel() {
// 确保按钮状态正确
setModalProps({ confirmLoading: false });
// 清空所有数据和状态
if (clearSelectedRowKeys) {
clearSelectedRowKeys();
}
if (setTableData) {
setTableData([]);
}
closeModal();
}
</script>
......@@ -9,28 +9,28 @@
:isCamelCase="true"
@model-change="handleChange"
/>
<CollectionItemSelectModal @register="registerSelectModal" @success="handleSelectSuccess" />
<SelectCollectionItemModal @register="registerSelectModal" @success="handleSelectSuccess" />
</div>
</template>
<script lang="ts" setup>
import { reactive, ref, onMounted, nextTick, watch, provide } from 'vue';
import { reactive, ref, onMounted, nextTick, watch } from 'vue';
import { formProps, formEventConfigs } from './config';
import SimpleForm from '/@/components/SimpleForm/src/SimpleForm.vue';
import { addMesCollectionScheme, getMesCollectionScheme, updateMesCollectionScheme } from '/@/api/jcsj/cjfa';
import { cloneDeep, isString } from 'lodash-es';
import { FormDataProps } from '/@/components/Designer/src/types';
import { usePermission } from '/@/hooks/web/usePermission';
import CustomButtonModal from '/@/components/Form/src/components/CustomButtonModal.vue';
import { FromPageType } from '/@/enums/workflowEnum';
import { createFormEvent, getFormDataEvent, loadFormEvent, submitFormEvent,} from '/@/hooks/web/useFormEvent';
import { changeWorkFlowForm, changeSchemaDisabled } from '/@/hooks/web/useWorkFlowForm';
import { WorkFlowFormParams } from '/@/model/workflow/bpmnConfig';
import { useRouter } from 'vue-router';
import { useModal } from '/@/components/Modal';
import CollectionItemSelectModal from './CollectionItemSelectModal.vue';
import SelectCollectionItemModal from './SelectCollectionItemModal.vue';
import { useMessage } from '/@/hooks/web/useMessage';
const { filterFormSchemaAuth } = usePermission();
const { notification } = useMessage();
const RowKey = 'id';
const emits = defineEmits(['changeUploadComponentIds','loadingCompleted', 'update:value']);
......@@ -41,21 +41,20 @@
},
});
const systemFormRef = ref();
const data: { formDataProps: FormDataProps } = reactive({
formDataProps: cloneDeep(formProps),
const formDataPropsValue = cloneDeep(formProps);
if (!formDataPropsValue.buttonList) {
formDataPropsValue.buttonList = [];
}
const data: { formDataProps: FormDataProps & { buttonList: any[] } } = reactive({
formDataProps: formDataPropsValue as FormDataProps & { buttonList: any[] },
});
const state = reactive({
formModel: {},
formInfo:{formId:'',formName:''}
formModel: {} as any,
formInfo:{formId:'',formName:''},
subFormRef: null as any,
});
const { currentRoute } = useRouter();
const [registerSelectModal, { openModal: openSelectModal }] = useModal();
const { createMessage } = useMessage();
// 提供方法给SubForm使用
provide('collectionItemFormApi', {
openCollectionItemSelect,
});
watch(
() => state.formModel,
......@@ -67,11 +66,185 @@
},
);
// 监听采集内容变化,更新SubForm配置
watch(
() => state.formModel.contentType,
() => {
updateSubFormConfig();
},
);
// 更新SubForm配置,添加自定义新增逻辑
function updateSubFormConfig() {
const schemas = data.formDataProps.schemas;
if (!schemas) return;
// 查找SubForm组件
const tabSchema = schemas.find((s) => s.component === 'Tab');
if (!tabSchema || !tabSchema.children) return;
const tabPane = tabSchema.children[0];
if (!tabPane || !tabPane.list) return;
const subFormSchema = tabPane.list.find((s: any) => s.component === 'SubForm');
if (!subFormSchema || !subFormSchema.componentProps) return;
// 修改SubForm配置,添加addBefore钩子来拦截新增
subFormSchema.componentProps.addBefore = (formModel: any, pushObj: any) => {
// 检查是否选择了采集内容
const currentContentType = formModel?.contentType;
if (!currentContentType) {
notification.warning({
message: '提示',
description: '请先选择采集内容',
});
// 标记为需要取消,但在addBefore中无法阻止,需要在addAfter中处理
pushObj._shouldCancel = true;
return;
}
// 设置标志,表示需要打开选择弹窗而不是直接添加
pushObj._customAdd = true;
};
// 在addAfter中处理自定义添加逻辑
subFormSchema.componentProps.addAfter = (formModel: any, pushObj: any) => {
// 如果需要取消(未选择采集内容),移除刚添加的行
if (pushObj._shouldCancel) {
nextTick(() => {
const currentList = state.formModel.mesCollectionSchemeItemList || [];
// 使用key属性或对象引用来查找并移除
const index = pushObj.key !== undefined
? currentList.findIndex((item: any) => item.key === pushObj.key)
: currentList.findIndex((item: any) => item === pushObj);
// 如果找不到,尝试移除最后一个元素(通常是刚添加的)
if (index < 0 && currentList.length > 0) {
currentList.pop();
} else if (index >= 0) {
currentList.splice(index, 1);
}
// 更新表单数据
if (systemFormRef.value) {
systemFormRef.value.setFieldsValue(state.formModel);
}
});
return;
}
// 如果是自定义添加(需要打开选择弹窗),移除刚添加的空行并打开选择弹窗
if (pushObj._customAdd) {
nextTick(() => {
const currentList = state.formModel.mesCollectionSchemeItemList || [];
// 使用key属性或对象引用来查找并移除
const index = pushObj.key !== undefined
? currentList.findIndex((item: any) => item.key === pushObj.key)
: currentList.findIndex((item: any) => item === pushObj);
// 如果找不到,尝试移除最后一个元素(通常是刚添加的)
if (index < 0 && currentList.length > 0) {
currentList.pop();
} else if (index >= 0) {
currentList.splice(index, 1);
}
// 更新表单数据
if (systemFormRef.value) {
systemFormRef.value.setFieldsValue(state.formModel);
}
// 打开选择弹窗
const currentContentType = formModel?.contentType;
if (currentContentType) {
openSelectModal(true, { contentType: currentContentType });
}
});
}
};
}
// 处理选择采集项成功
function handleSelectSuccess(selectedItems: any[]) {
if (!selectedItems || selectedItems.length === 0) return;
// 获取当前的采集项列表
const currentList = state.formModel.mesCollectionSchemeItemList || [];
// 获取已存在的采集项ID和编码,避免重复添加
const existingIds = new Set(currentList.map((item: any) => item.id).filter(Boolean));
const existingCodes = new Set(currentList.map((item: any) => item.code).filter(Boolean));
// 记录重复的项
const duplicateItems: string[] = [];
const addedItems: any[] = [];
// 检查并添加选中的采集项
selectedItems.forEach((item) => {
// 检查是否已存在(通过ID或编码判断)
const isDuplicateById = item.id && existingIds.has(item.id);
const isDuplicateByCode = item.code && existingCodes.has(item.code);
if (isDuplicateById || isDuplicateByCode) {
// 记录重复项的名称
duplicateItems.push(item.name || item.code || '未知项');
} else {
// 添加新项
const newItem = {
code: item.code,
name: item.name,
contentType: item.contentType,
note: item.note,
id: item.id,
schemeId: state.formModel.id || '',
};
currentList.push(newItem);
addedItems.push(newItem);
// 更新已存在的ID和编码集合
if (item.id) {
existingIds.add(item.id);
}
if (item.code) {
existingCodes.add(item.code);
}
}
});
// 如果有重复项,提示用户
if (duplicateItems.length > 0) {
notification.warning({
message: '提示',
description: `以下采集项已存在,已跳过:${duplicateItems.join('、')}`,
duration: 3,
});
}
// 如果没有成功添加任何项,直接返回
if (addedItems.length === 0) {
return;
}
// 更新表单模型
state.formModel.mesCollectionSchemeItemList = currentList;
// 更新表单数据,触发表单刷新
nextTick(() => {
if (systemFormRef.value) {
systemFormRef.value.setFieldsValue(state.formModel);
// 触发表单更新事件,让SubForm组件重新渲染
emits('update:value', state.formModel);
}
});
}
onMounted(async () => {
try {
if (props.fromPage == FromPageType.MENU) {
setMenuPermission();
// 更新SubForm配置,添加自定义新增逻辑
updateSubFormConfig();
if(currentRoute.value.meta){
state.formInfo.formName = currentRoute.value.meta.title&&isString(currentRoute.value.meta.title)?currentRoute.value.meta.title:'';
state.formInfo.formId = currentRoute.value.meta.formId&&isString(currentRoute.value.meta.formId)?currentRoute.value.meta.formId:'';
......@@ -126,6 +299,8 @@
const record = await getMesCollectionScheme(rowId);
setFieldsValue(record);
state.formModel = record;
// 编辑模式下,数据加载后需要重新更新SubForm配置
updateSubFormConfig();
await getFormDataEvent(formEventConfigs, state.formModel,
systemFormRef.value,
formProps.schemas, true, state.formInfo.formName,state.formInfo.formId); //表单事件:获取表单数据
......@@ -201,6 +376,8 @@
}
state.formModel = formModels;
setFieldsValue(formModels);
// 工作流模式下,数据加载后需要重新更新SubForm配置
updateSubFormConfig();
} catch (error) {}
await createFormEvent(formEventConfigs, state.formModel,
systemFormRef.value,
......@@ -213,64 +390,6 @@
emits('update:value', val);
}
// 打开采集项选择弹窗
function openCollectionItemSelect() {
const contentType = state.formModel.contentType;
if (!contentType) {
createMessage.warning('请先选择采集内容');
return;
}
// 传入获取最新采集项列表的函数,以便在提交时实时获取最新数据
const getExistingItemIds = () => {
const currentList = state.formModel.mesCollectionSchemeItemList || [];
return currentList.map((item: any) => item.collectionItemId || item.id).filter(Boolean);
};
openSelectModal(true, { contentType, getExistingItemIds });
}
// 处理选择采集项成功
function handleSelectSuccess(selectedItems: any[]) {
try {
if (!selectedItems || selectedItems.length === 0) {
return;
}
const currentList = state.formModel.mesCollectionSchemeItemList || [];
selectedItems.forEach((item) => {
const newItem = {
code: item.code,
name: item.name,
contentType: item.contentType,
note: item.note || '',
collectionItemId: item.id,
schemeId: state.formModel.id || '',
_isFromSelect: true, // 标记为从选择弹窗添加的项,用于禁用编辑
};
currentList.push(newItem);
});
state.formModel.mesCollectionSchemeItemList = currentList;
// 更新表单值
if (systemFormRef.value) {
systemFormRef.value.setFieldsValue({
mesCollectionSchemeItemList: currentList,
});
}
} catch (error) {
console.error('处理选择采集项成功时出错:', error);
// 不抛出错误,避免影响弹窗关闭
}
}
// 暴露方法给外部调用
function getFormApi() {
return {
openCollectionItemSelect,
};
}
async function sendMessageForAllIframe() {
try {
if (systemFormRef.value && systemFormRef.value.sendMessageForAllIframe) {
......@@ -291,9 +410,6 @@
getRowKey,
getFieldsValue,
sendMessageForAllIframe,
getFormApi,
openCollectionItemSelect,
});
</script>
\ No newline at end of file
<template>
<BasicModal
v-bind="$attrs"
@register="registerModal"
title="选择采集项"
@ok="handleSubmit"
@visible-change="handleVisibleChange"
@cancel="handleCancel"
width="800px"
:height="600"
>
<BasicTable @register="registerTable" />
</BasicModal>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicTable, useTable } from '/@/components/Table';
import { FormSchema } from '/@/components/Form';
import { BasicColumn } from '/@/components/Table';
import { getMesCollectionItemPage } from '/@/api/jcsj/cjx';
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n();
const emit = defineEmits(['success', 'register']);
const contentType = ref<string>('');
const searchFormSchema: FormSchema[] = [
{
field: 'code',
label: '编码',
component: 'Input',
colProps: { span: 8 },
},
{
field: 'name',
label: '名称',
component: 'Input',
colProps: { span: 8 },
},
];
const columns: BasicColumn[] = [
{
title: '编码',
dataIndex: 'code',
width: 150,
},
{
title: '名称',
dataIndex: 'name',
width: 200,
},
{
title: '采集内容',
dataIndex: 'contentType',
width: 150,
},
{
title: '备注',
dataIndex: 'note',
width: 200,
},
];
const [registerTable, { getSelectRows, reload, clearSelectedRowKeys, getForm }] = useTable({
title: '采集项列表',
api: getMesCollectionItemPage,
rowKey: 'id',
columns,
formConfig: {
labelWidth: 70,
schemas: searchFormSchema,
},
rowSelection: {
type: 'checkbox',
},
useSearchForm: true,
showTableSetting: false,
bordered: true,
pagination: {
pageSize: 10,
},
beforeFetch: (params) => {
// 根据选择的采集内容过滤
if (contentType.value) {
params.contentType = contentType.value;
}
return params;
},
});
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
contentType.value = data?.contentType || '';
setModalProps({ confirmLoading: false });
await reload();
});
// 清空弹窗内的操作
function clearModalOperations() {
// 清空表格选中项
clearSelectedRowKeys();
// 重置搜索表单
const form = getForm();
if (form) {
form.resetFields();
}
}
// 处理弹窗可见性变化
function handleVisibleChange(visible: boolean) {
// 当弹窗关闭时,清空操作
if (!visible) {
clearModalOperations();
}
}
// 处理取消事件
function handleCancel() {
clearModalOperations();
}
const handleSubmit = () => {
const selectedRows = getSelectRows();
if (selectedRows.length === 0) {
return;
}
emit('success', selectedRows);
closeModal();
};
</script>
import { BasicColumn } from '/@/components/Table';
export const columns: BasicColumn[] = [
{
title: '编码',
dataIndex: 'code',
width: 150,
},
{
title: '名称',
dataIndex: 'name',
width: 200,
},
{
title: '数据类型',
dataIndex: 'dataType',
width: 120,
},
{
title: '备注',
dataIndex: 'note',
width: 200,
},
];
......@@ -409,7 +409,7 @@ export const formProps: FormProps = {
suffix: '',
addonBefore: '',
addonAfter: '',
disabled: (record: any) => record?._isFromSelect === true,
disabled: true,
allowClear: false,
showLabel: true,
required: false,
......@@ -440,7 +440,7 @@ export const formProps: FormProps = {
suffix: '',
addonBefore: '',
addonAfter: '',
disabled: (record: any) => record?._isFromSelect === true,
disabled: true,
allowClear: false,
showLabel: true,
required: false,
......@@ -468,7 +468,7 @@ export const formProps: FormProps = {
showSearch: false,
isMultiple: false,
clearable: false,
disabled: (record: any) => record?._isFromSelect === true,
disabled: true,
staticOptions: [
{ key: 1, label: 'Option 1', value: 'Option 1' },
{ key: 2, label: 'Option 2', value: 'Option 2' },
......@@ -510,7 +510,7 @@ export const formProps: FormProps = {
suffix: '',
addonBefore: '',
addonAfter: '',
disabled: (record: any) => record?._isFromSelect === true,
disabled: true,
allowClear: false,
showLabel: true,
required: false,
......@@ -567,7 +567,7 @@ export const formProps: FormProps = {
buttonName: '选择数据',
showLabel: true,
showComponentBorder: true,
showBorder: true,
showBorder: false,
bordercolor: '#f0f0f0',
bordershowtype: [true, true, true, true],
borderwidth: 1,
......@@ -603,20 +603,12 @@ export const formProps: FormProps = {
checked: false,
},
],
isShowAdd: false,
isShowAdd: true,
isShowDelete: true,
hasCheckedCol: true,
events: {},
showPagenation: true,
showColunmSet: false,
topButtonList: [
{
key: 'selectCollectionItem',
label: '新增',
style: 'primary',
icon: 'ant-design:plus-outlined',
},
],
},
},
],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment