提交 54c6cef5 authored 作者: kxjia's avatar kxjia

完善程序

上级 fe7183fd
......@@ -200,7 +200,7 @@ export function getNodesByTableName(tableName) {
export function addMyTaskFlow(data) {
return defHttp.post({
url: '//my/myTaskFlow/add',
url: '/my/myTaskFlow/add',
data: data
})
}
......@@ -149,7 +149,6 @@ export function getMyTaskFlow(data) {
// 得到退回的节点
export function getRejectNode(query) {
alert(JSON.stringify(query))
return defHttp.get({
url: '/flowable/form/getRejectTargetNode',
params: query
......
......@@ -3,13 +3,15 @@
<a-card class="form-card" :bordered="false">
<template #title>
<div class="form-header">
<span class="form-title">当前待办[{{ editableNode?.name || '无' }}]</span>
<a-button color="blue" v-if="!isEditStatus" @click="handleSetEditStatus">转阅</a-button>
<a-button color="blue" v-if="!isEditStatus" @click="handleSetEditStatus">转发</a-button>
<a-button color="blue" v-if="!isEditStatus" @click="handleSetEditStatus">退回</a-button>
<a-button color="blue" v-if="!isEditStatus" @click="handleSetEditStatus">编辑</a-button>
<a-button color="blue" v-if="isEditStatus" @click="handleSetEditStatus">只读</a-button>
<span class="form-title">当前待办<font color="red">[{{ editableNode?.name || '无' }}]</font></span>
<a-space>
<a-button v-if="props.showApprovalPanel" type="primary" ghost @click="handleApproval">审批</a-button>
<a-button v-else type="primary" ghost @click="handleSend">发送</a-button>
<a-button type="primary" ghost @click="handleReject">驳回</a-button>
<a-button type="primary" ghost @click="handleTransmit">转办</a-button>
<a-button type="primary" ghost @click="handleRead">转阅</a-button>
</a-space>
</div>
</template>
<div class="form-content" v-if="editableNode">
......@@ -20,18 +22,28 @@
:readonly="false"
:form-data="props.formData"
:current-flow-node="editableNode"
:showApprovalPanel="props.showApprovalPanel"
@update:form-data="handleFormDataUpdate"
/>
</div>
<div v-else class="empty-form-state">
<a-empty description="未找到可编辑的表单节点" />
</div>
</a-card>
<ApprovalModal @register="registerApprovalModal" />
<TaskModal @register="registerTaskModal" @success="handleFormDataUpdate"/>
</div>
</template>
<script lang="ts" setup>
import { ref, defineAsyncComponent, h, watch, ComponentPublicInstance, nextTick } from 'vue'
import ApprovalModal from './components/ApprovalModal.vue';
import TaskModal from './components/TaskModal.vue';
import { useModal } from '/@/components/Modal';
const [registerApprovalModal, {openModal}] = useModal();
const [registerTaskModal, {openModal: taskOpenModal}] = useModal();
interface WorkflowNode {
id: string
......@@ -41,6 +53,7 @@ interface WorkflowNode {
[key: string]: any
}
// 表单组件实例类型
interface FormComponentInstance extends ComponentPublicInstance {
validate?: () => Promise<any>
......@@ -59,6 +72,18 @@ const props = defineProps({
type: String,
default: ''
},
deployId: {
type: String,
default: ''
},
taskId: {
type: String,
default: ''
},
procInsId: {
type: String,
default: ''
},
externalFormData: {
type: Object as () => Record<string, any>,
default: () => ({})
......@@ -70,22 +95,96 @@ const props = defineProps({
disabled: {
type: Boolean,
default: false
},
assignee: {
type: String,
default: ''
},
userType: {
type: String,
default: ''
},
showApprovalPanel: {
type: Boolean,
default: false
}
})
const emit = defineEmits(['update:form-data', 'form-mounted'])
function handleApproval() {
openModal(true, {
isUpdate: false,
showFooter: true,
taskType: 'approval',
});
}
function handleSend() {
taskOpenModal(true, {
taskTitle: '发送',
isUpdate: false,
showFooter: true,
taskType: 'send',
deployId: props.deployId,
taskId: props.taskId,
procInsId: props.procInsId,
dataId: props.dataId,
assignee: props.assignee,
userType: props.userType,
});
}
function handleReject() {
taskOpenModal(true, {
taskTitle: '驳回',
isUpdate: false,
showFooter: true,
taskType: 'reject',
deployId: props.deployId,
taskId: props.taskId,
procInsId: props.procInsId,
dataId: props.dataId,
assignee: props.assignee,
userType: props.userType,
});
}
function handleTransmit() {
taskOpenModal(true, {
taskTitle: '转办',
isUpdate: false,
showFooter: true,
taskType: 'transmit',
deployId: props.deployId,
taskId: props.taskId,
procInsId: props.procInsId,
dataId: props.dataId,
});
}
function handleRead() {
taskOpenModal(true, {
taskTitle: '转阅',
isUpdate: false,
showFooter: true,
taskType: 'read',
deployId: props.deployId,
taskId: props.taskId,
procInsId: props.procInsId,
dataId: props.dataId,
assignee: props.assignee,
userType: props.userType,
});
}
// 组件缓存
const emit = defineEmits(['update:form-data', 'form-mounted'])
const componentCache = new Map()
const modules = import.meta.glob('@/views/**/*.vue')
// 表单组件实例
const formComponentRef = ref<FormComponentInstance | null>(null)
const formData = ref<any>({})
const isEditStatus = ref(false);
// 设置表单组件 ref
function setFormRef(el: any, nodeId: string) {
if (el) {
formComponentRef.value = el
......@@ -109,8 +208,10 @@ async function callInitFormData(formComponent: FormComponentInstance) {
}
// 处理表单数据更新
function handleFormDataUpdate(data: any) {
formData.value = { ...formData.value, ...data }
async function handleFormDataUpdate(data: any) {
const curFormData = await getFormData();
formData.value = { ...curFormData, ...data }
await handleSaveCurForm(curFormData.value)
emit('update:form-data', formData.value)
}
......@@ -122,11 +223,9 @@ function getFormInstance(): FormComponentInstance | null {
// 获取表单数据
async function getFormData(): Promise<any> {
const formComponent = formComponentRef.value
if (!formComponent) {
return formData.value
}
if (typeof formComponent.getFormData === 'function') {
try {
const data = await formComponent.getFormData()
......@@ -135,7 +234,6 @@ async function getFormData(): Promise<any> {
console.error('调用 getFormData 失败:', error)
}
}
if (formComponent.formData !== undefined) {
return formComponent.formData
}
......@@ -146,11 +244,9 @@ async function getFormData(): Promise<any> {
// 验证表单
async function validateForm(): Promise<boolean> {
const formComponent = formComponentRef.value
if (!formComponent) {
return true
}
if (typeof formComponent.validate === 'function') {
try {
await formComponent.validate()
......@@ -159,7 +255,6 @@ async function validateForm(): Promise<boolean> {
return false
}
}
return true
}
......@@ -256,16 +351,17 @@ function createErrorComponent(msg: string) {
}
}
// 处理编辑状态切换
function handleSetEditStatus() {
isEditStatus.value = !isEditStatus.value
if (formComponentRef.value&&typeof formComponentRef.value.setFormDisabledStatus === 'function') {
formComponentRef.value.setFormDisabledStatus(false)
const handleSaveCurForm = async (curFormData) => {
const valid = await validateForm();
if (!valid) {
return
}
if (formComponentRef.value&&typeof formComponentRef.value.saveForm === 'function') {
await formComponentRef.value.saveForm(curFormData)
}
}
// 暴露方法给父组件
defineExpose({
getFormData,
validateForm,
......
......@@ -31,30 +31,16 @@
:class="{ 'last-card': index === readonlyNodes.length - 1 }"
>
<template #extra>
<a-tag :color="index === readonlyNodes.length - 1 ? 'orange' : 'green'" size="small">
<a-button type="link" size="small" @click="togglePreview(node.id)">
{{ expandedPreviewId === node.id ? '收起' : '展开' }}
</a-button>
<!-- <a-tag :color="index === readonlyNodes.length - 1 ? 'orange' : 'green'" size="small">
{{ index === readonlyNodes.length - 1 ? '已通过' : '已完成' }}
</a-tag>
</a-tag> -->
</template>
<div class="history-card-content">
<div class="node-info">
<span class="node-label">表单名称:</span>
<span class="node-value">{{ node.formName || node.name }}</span>
</div>
<div class="node-info">
<span class="node-label">处理时间:</span>
<span class="node-value">{{ node.processTime || '--' }}</span>
</div>
</div>
<!-- 显示历史表单数据 -->
<template v-if="showHistoryFormData">
<a-divider style="margin: 12px 0" />
<div class="history-form-preview">
<div class="preview-header">
<span>表单数据预览</span>
<a-button type="link" size="small" @click="togglePreview(node.id)">
{{ expandedPreviewId === node.id ? '收起' : '展开' }}
</a-button>
</div>
<div v-show="expandedPreviewId === node.id" class="form-preview-content">
<component
:is="getComponent(node)"
......
......@@ -25,11 +25,8 @@
<!-- 用户/角色选择区域(未选择时) -->
<a-form-item
v-if="!hasAssignee"
v-if="!assigneeId"
:label="localUserType === 'user' ? '选择用户' : '选择角色'"
:required="required"
:validate-status="validateStatus"
:help="validateHelp"
>
<div class="assignee-selector">
<a-input
......@@ -46,7 +43,7 @@
</a-form-item>
<!-- 已指定信息展示 -->
<div v-if="hasAssignee" class="assignee-info-wrapper">
<div v-if="assigneeId" class="assignee-info-wrapper">
<div class="assignee-info-label">已指定{{ localUserType === 'user' ? '用户' : '角色' }}:</div>
<a-descriptions :column="1" size="small" bordered>
<a-descriptions-item :label="localUserType === 'user' ? '用户ID' : '角色ID'">
......@@ -122,9 +119,12 @@ const assigneeDisplayName = ref('')
const confirmLoading = ref(false)
const dataId = ref('')
const deployId = ref('')
const taskId = ref('')
const hasAssignee = ref(false)
// 使用 useDrawerInner 接收外部传入的数据
const [registerBasicDrawer, { closeDrawer, setDrawerProps }] = useDrawerInner((data) => {
alert(JSON.stringify(data))
if (data) {
dataId.value = data.dataId || ''
deployId.value = data.deployId || ''
......@@ -186,7 +186,7 @@ const handleConfirm = async () => {
deployId: myTaskFlow.deployId || '',
taskId: myTaskFlow.taskId,
dataId: dataId.value,
comment: 'eeeeeee',
comment: '',
values: {
approval: assigneeId.value,
approvalType: localUserType.value
......
......@@ -2,7 +2,7 @@
<a-drawer
:title="drawerTitle"
:visible="visible"
:width="drawerWidth"
width="80%"
:closable="true"
:mask-closable="maskClosable"
:header-style="{ backgroundColor: '#018ffb', borderBottom: '1px solid #e8eef2' }"
......@@ -13,13 +13,12 @@
<div class="drawer-container">
<a-row :gutter="10" class="drawer-row" :wrap="false">
<!-- 左侧历史面板 -->
<a-col :width="props.leftPanelWidth">
<a-col :width="props.leftPanelWidth" v-if="showHistoryVisible">
<HistoryPanel style="width: 100%;height: 100%;"
:readonly-nodes="readonlyNodes"
:data-id="dataId"
:show-history-form-data="props.showHistoryFormData"
/>
</a-col>
<!-- 中间表单区域 -->
......@@ -32,14 +31,21 @@
:form-data="props.formData"
:form-bpm="formBpm"
:disabled="showApprovalPanel || false"
:deploy-id="props.deployId"
:task-id="props.taskId"
:proc-ins-id="props.procInsId"
:assignee="props.assignee"
:user-type="props.userType"
:show-approval-panel="props.showApprovalPanel"
@update:form-data="handleFormDataUpdate"
@form-mounted="handleFormMounted"
/>
</a-col>
<!-- 右侧审核面板 -->
<a-col v-if="showApprovalPanel" :width="props.rightPanelWidth">
<!-- <a-col v-if="showApprovalPanel" :width="props.rightPanelWidth">
<ApprovalPanel style="width: 100%;height: 100%;"
ref="approvalPanelRef"
:current-node="editableNode"
......@@ -52,13 +58,14 @@
@success="handleApprovalSuccess"
@approval-fail="handleApprovalFail"
/>
</a-col>
</a-col> -->
</a-row>
</div>
<template #extra>
<a-button @click="handleHistoryHidden()" v-if="showHistoryVisible" type="primary">隐藏历史</a-button>
<a-button @click="handleHistoryHidden()" v-else type="primary">显示历史</a-button>
<a-button @click="openHistoryDrawer()" type="primary">流程追踪</a-button>
<a-button @click="handleClose()" type="primary">关闭抽屉</a-button>
<a-button @click="handleClose()" type="primary">关闭</a-button>
</template>
<FlowHistoryDrawer @register="refFlowHistoryDrawer"/>
</a-drawer>
......@@ -75,7 +82,9 @@ import { useDrawer } from '/@/components/Drawer';
const formBpm = ref(true)
const formDisabled = ref(false)
const drawerHistoryVisible = ref(false)
const showHistoryVisible = ref(true)
const [refFlowHistoryDrawer, { openDrawer }] = useDrawer();
......@@ -96,30 +105,25 @@ interface WorkflowNode {
}
const props = defineProps({
// 基础配置
visible: {
type: Boolean,
default: false
},
title: {
type: String,
default: '表单处理'
default: '工作流表单'
},
width: {
type: [Number, String],
default: "90%"
visible: {
type: Boolean,
default: false
},
maskClosable: {
type: Boolean,
default: false
},
// 工作流配置
currentNodeIndex: {
type: Number,
required: true,
default: 2
},
workflowNodes: {
type: Array as () => WorkflowNode[],
required: true,
......@@ -137,12 +141,14 @@ const props = defineProps({
type: String,
default: ''
},
taskId: {
type: String,
default: ''
},
procInsId: {
type: String,
default: ''
},
dataId: {
type: String,
default: ''
......@@ -151,37 +157,10 @@ const props = defineProps({
type: Boolean,
default: false
},
// 审核面板配置
showApprovalPanel: {
type: Boolean,
default: false
},
// 审核结果配置
approvalResultOptions: {
type: Array,
default: () => [
{
value: 'approved',
label: '通过',
icon: 'CheckCircleOutlined',
className: 'approved'
},
{
value: 'rejected',
label: '退回',
icon: 'CloseCircleOutlined',
className: 'rejected'
}
]
},
defaultApprovalResult: {
type: String,
default: 'approved'
},
flowNodes: {
type: Array as () => WorkflowNode[],
default: () => []
......@@ -192,11 +171,9 @@ const props = defineProps({
},
assignee: { type: String, default: null },
userType: { type: String, default: 'user' },
// 面板宽度配置
leftPanelWidth: { type: String,default: '40%'},
centerPanelWidth: { type: String, default: '40%'},
rightPanelWidth: { type: String,default: '20%'}
})
const emit = defineEmits(['update:visible', 'submit', 'close', 'form-data-update','success','approval-fail'])
......@@ -210,7 +187,7 @@ const approvalPanelRef = ref<InstanceType<typeof ApprovalPanel> | null>(null)
// 计算属性
const drawerTitle = computed(() => props.title)
const drawerWidth = computed(() => props.width)
// 只读节点:索引小于 currentNodeIndex 的节点
const readonlyNodes = computed(() => {
......@@ -258,74 +235,18 @@ function handleApprovalSuccess(dataId: string) {
}
}
// 提交处理
async function handleSubmit() {
if (!editableNode.value) {
message.warning('没有可编辑的表单')
return
}
if (!currentFormPanelRef.value) {
message.warning('表单组件未加载')
return
}
if (props.showApprovalPanel && approvalPanelRef.value) {
const result = await approvalPanelRef.value.validate()
if (!result.valid) {
message.error(result.errors[0] || '请填写完整的审核信息')
return
}
}
submitLoading.value = true
try {
const isValid = await currentFormPanelRef.value.validateForm()
if (!isValid) {
message.error('请完善表单信息')
return
}
const submitData = await currentFormPanelRef.value.getFormData()
const finalSubmitData: any = {
nodeId: editableNode.value.id,
nodeName: editableNode.value.name,
formData: submitData,
procDefId: props.procDefId,
formComponent: currentFormPanelRef.value.getFormInstance()
}
// 如果显示审核面板,添加审核数据
if (props.showApprovalPanel && approvalPanelRef.value) {
const approval = await approvalPanelRef.value.getApprovalData()
finalSubmitData.approval = approval
}
console.log('最终提交数据:', finalSubmitData)
// 4. 触发提交事件
emit('submit', finalSubmitData)
message.success(props.showApprovalPanel ? '审核提交成功' : '提交成功')
handleClose()
} catch (error: any) {
console.error('提交失败:', error)
message.error(error?.message || '提交失败,请重试')
} finally {
submitLoading.value = false
}
}
// 关闭抽屉
function handleClose() {
emit('update:visible', false)
emit('close')
}
function handleHistoryHidden() {
showHistoryVisible.value = !showHistoryVisible.value
}
// 处理审核失败
function handleApprovalFail(dataId: string) {
if (dataId === props.dataId) {
message.error('审核失败')
emit('approval-fail',dataId)
handleClose()
}
......@@ -391,18 +312,6 @@ defineExpose({
}
return currentFormData.value
},
validate: async () => {
if (currentFormPanelRef.value) {
const formValid = await currentFormPanelRef.value.validateForm()
if (props.showApprovalPanel && approvalPanelRef.value) {
const approvalResult = await approvalPanelRef.value.validate()
return formValid && approvalResult.valid
}
return formValid
}
return true
},
submit: handleSubmit
})
</script>
......
<template>
<BasicModal
v-bind="$attrs"
@register="registerModal"
title="审批"
:centered="true"
width="40%"
:minHeight="400"
:useWrapper="true"
:wrapperFooterOffset="20"
@cancel=""
@ok="handleOk"
>
<ApprovalPanel ref="approvalPanelRef" />
</BasicModal>
</template>
<script setup lang="ts">
import { ref, computed, watch, nextTick } from 'vue'
import { BasicModal, useModalInner } from '/@/components/Modal';
import ApprovalPanel from './ApprovalPanel.vue';
import { complete, getMyTaskFlow,rejectTask, assignRead,assign } from '/@/components/Process/api/todo';
const approvalPanelRef = ref();
const emit = defineEmits(['success','approval-fail','update-form-data'])
const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter});
});
function handleOk() {
alert('handleOk');
setModalProps({confirmLoading: true});
approvalPanelRef.value.handleSaveApp();
setModalProps({confirmLoading: false});
}
</script>
\ No newline at end of file
<template>
<div class="approval-panel">
<a-card class="approval-card" :bordered="false">
<template #title>
<a-card class="approval-card">
<!-- <template #title>
<div class="approval-header">
<span class="approval-title">审批操作</span>
</div>
</template>
<template #extra>
<a-button @click="handleSaveApp" type="primary" size="small">保存审批</a-button>
</template>
<div class="approval-content">
<BasicForm @register="registerForm" style="width: 100%;">
</template> -->
<div class="approval-content" style="width: 100%;">
<BasicForm @register="registerForm">
<template #slot_passOrReturn="{ model }">
<a-radio-group v-model:value="model.reviewStatus" button-style="solid" class="approval-radio-group">
<a-radio-button :value="true" class="radio-button">
<a-radio-button :value="true" class="radio-button" @click="handleClickPass">
<CheckCircleOutlined />
通过
</a-radio-button>
<a-radio-button :value="false" class="radio-button">
<a-radio-button :value="false" class="radio-button" @click="handleClickReject">
<CloseCircleOutlined />
退回
</a-radio-button>
......@@ -30,25 +30,23 @@
</template>
<script lang="ts" setup>
import { ref,onMounted,nextTick } from 'vue'
import { useForm, BasicForm, FormSchema } from '/@/components/Form'
import { CheckCircleOutlined, CloseCircleOutlined } from '@ant-design/icons-vue'
import { complete, getMyTaskFlow,getRejectNode,rejectTask } from '/@/components/Process/api/todo'
import { message } from 'ant-design-vue'
import { ref, onMounted, nextTick } from 'vue';
import { useForm, BasicForm, FormSchema } from '/@/components/Form';
import { CheckCircleOutlined, CloseCircleOutlined } from '@ant-design/icons-vue';
import { complete, getMyTaskFlow, getRejectNode, rejectTask } from '/@/components/Process/api/todo';
import { message } from 'ant-design-vue';
const emit = defineEmits(['update:visible', 'success', 'error', 'close','approval-fail'])
const emit = defineEmits(['update:visible', 'success', 'error', 'close', 'approval-fail']);
const props = defineProps({
beforeFlowNode: {
type: Object,
default: () => ({})
default: () => ({}),
},
assignee: { type: String, default: null },
userType: { type: String, default: '' },
deployId: { type: String, default: '' },
dataId: { type: String, default: '' },
})
});
const formSchemas: FormSchema[] = [
{
......@@ -75,8 +73,8 @@
showCount: true,
maxlength: 512,
autoSize: { minRows: 7, maxRows: 10 },
style: { width: '100%' }
}
style: { width: '100%' },
},
},
{
label: '接收人',
......@@ -85,11 +83,11 @@
required: true,
componentProps: {
allowClear: true,
rowKey: 'username',
rowKey: 'id',
labelKey: 'realname',
showButton: false,
modalTitle: '用户',
style: { width: '100%' }
style: { width: '100%' },
},
},
{
......@@ -98,34 +96,33 @@
component: 'RoleSelect',
required: true,
componentProps: {
rowKey: 'id',
labelKey: 'roleName',
allowClear: true,
maxSelectCount: 3,
maxSelectCount: 1,
isRadioSelection: false,
style: { width: '100%' }
style: { width: '100%' },
},
}
]
},
];
const [registerForm, { validate,updateSchema,setFieldsValue }] = useForm({
const [registerForm, { validate, updateSchema, setFieldsValue,setProps }] = useForm({
schemas: formSchemas,
showActionButtonGroup: false,
layout: 'vertical',
labelWidth: '120px',
size: 'small',
baseColProps: { span: 24 },
})
size: 'large',
baseColProps: {style: { width: '100%' } },
});
const handleClose = () => {
emit('update:visible', false)
emit('close')
}
emit('update:visible', false);
emit('close');
};
const handleSaveApp = async () => {
const formDataTmp = await validate()
const myTaskFlow = await getMyTaskFlow({ deploymentId: props.deployId, dataId: props.dataId })
const formDataTmp = await validate();
const myTaskFlow = await getMyTaskFlow({ deploymentId: props.deployId, dataId: props.dataId });
if (myTaskFlow?.taskId) {
const reviewStatus = formDataTmp.reviewStatus;
if (reviewStatus === true) {
await complete({
......@@ -134,149 +131,196 @@
taskId: myTaskFlow.taskId,
comment: formDataTmp.comment,
values: {
approval: formDataTmp.approvalUser || formDataTmp.approvalRole,
approvalType: props.userType
approval: formDataTmp.approvalUser || formDataTmp.approvalRole,
approvalType: props.userType,
},
})
});
} else {
await rejectTask({
instanceId: myTaskFlow.procInsId || '',
deployId: myTaskFlow.deployId || '',
taskId: myTaskFlow.taskId,
comment: formDataTmp.comment,
values: {
rejectNode: props.beforeFlowNode,
},
})
alert(3333)
emit('approval-fail', props.dataId)
}
await rejectTask({
instanceId: myTaskFlow.procInsId || '',
deployId: myTaskFlow.deployId || '',
taskId: myTaskFlow.taskId,
comment: formDataTmp.comment,
values: {
rejectNode: props.beforeFlowNode,
},
});
emit('approval-fail', props.dataId);
}
}
emit('success', props.dataId)
nextTick(() => {
message.success('任务发送成功')
handleClose()
})
}
emit('success', props.dataId);
nextTick(() => {
message.success('任务发送成功');
handleClose();
});
};
onMounted(async() => {
if (props.userType === 'user') {
updateSchema([{
const handleClickReject = async () => {
updateSchema([
{
field: 'approvalUser',
required: true,
ifShow: true,
},{
field: 'approvalRole',
required: false,
ifShow:false,
}])
} else {
updateSchema([{
ifShow: false,
},
{
field: 'approvalRole',
required: true,
ifShow: true,
},{
field: 'approvalUser',
required: false,
ifShow:false,
}])
ifShow: false,
},
]);
};
const handleClickPass = async () => {
updateField(props.userType);
};
const updateField = (userTp) => {
if (userTp === 'user') {
updateSchema([
{
field: 'approvalUser',
required: true,
ifShow: true,
},
{
field: 'approvalRole',
required: false,
ifShow: false,
},
]);
} else {
updateSchema([
{
field: 'approvalRole',
required: true,
ifShow: true,
},
{
field: 'approvalUser',
required: false,
ifShow: false,
},
]);
}
};
onMounted(async () => {
updateField(props.userType);
});
defineExpose({
handleSaveApp,
})
</script>
<style scoped lang="scss">
.approval-panel {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
background-color: #f5f7fa;
.approval-card {
height: 100%;
.approval-panel {
flex: 1;
display: flex;
flex-direction: column;
background-color: #fff;
overflow: hidden;
background-color: #f5f7fa;
:deep(.ant-card-head) {
padding: 0 24px;
background-color: #e9ecef;
border-bottom: 1px solid #e8eef2;
}
.approval-card {
height: 100%;
display: flex;
flex-direction: column;
background-color: #fff;
:deep(.ant-card-body) {
flex: 1;
padding: 24px;
overflow-y: auto;
:deep(.ant-card-head) {
padding: 0 16px;
background-color: #e9ecef;
border-bottom: 1px solid #e8eef2;
}
:deep(.ant-card-body) {
flex: 1;
padding: 16px;
overflow-y: auto;
}
}
}
.approval-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 0;
.approval-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 0;
.approval-title {
font-size: 16px;
font-weight: 500;
color: #1f2f3d;
.approval-title {
font-size: 16px;
font-weight: 500;
color: #1f2f3d;
}
}
}
.approval-content {
flex: 1;
width: 100%;
.approval-radio-group {
.approval-content {
flex: 1;
width: 100%;
display: flex;
gap: 8px;
// 确保表单容器内部无多余间距
:deep(.ant-form) {
margin: 0;
padding: 0;
}
.radio-button {
flex: 1;
text-align: center;
height: 36px;
line-height: 36px;
:deep(.ant-form-item) {
margin-bottom: 16px;
}
:deep(.ant-form-item:last-child) {
margin-bottom: 0;
}
.approval-radio-group {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
font-weight: 500;
gap: 8px;
margin-bottom: 8px;
&:first-child:not(.ant-radio-button-wrapper-checked) {
border-color: #52c41a;
color: #52c41a;
.radio-button {
flex: 1;
text-align: center;
height: 36px;
line-height: 36px;
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
font-weight: 500;
&:hover {
border-color: #73d13d;
color: #73d13d;
&:first-child:not(.ant-radio-button-wrapper-checked) {
border-color: #52c41a;
color: #52c41a;
&:hover {
border-color: #73d13d;
color: #73d13d;
}
}
}
&:last-child:not(.ant-radio-button-wrapper-checked) {
border-color: #ff4d4f;
color: #ff4d4f;
&:last-child:not(.ant-radio-button-wrapper-checked) {
border-color: #ff4d4f;
color: #ff4d4f;
&:hover {
border-color: #ff7875;
color: #ff7875;
&:hover {
border-color: #ff7875;
color: #ff7875;
}
}
}
&.ant-radio-button-wrapper-checked:first-child {
background: #52c41a;
border-color: #52c41a;
}
&.ant-radio-button-wrapper-checked:first-child {
background: #52c41a;
border-color: #52c41a;
}
&.ant-radio-button-wrapper-checked:last-child {
background: #ff4d4f;
border-color: #ff4d4f;
&.ant-radio-button-wrapper-checked:last-child {
background: #ff4d4f;
border-color: #ff4d4f;
}
}
}
}
}
}
</style>
\ No newline at end of file
</style>
<template>
<a-form layout="vertical">
<a-form-item label="用户类型" required>
<a-radio-group v-model:value="localUserType" disabled>
<a-radio value="user">
<UserOutlined /> 用户
</a-radio>
<a-radio value="role">
<TeamOutlined /> 角色
</a-radio>
</a-radio-group>
</a-form-item>
<!-- 用户/角色选择区域(未选择时) -->
<a-form-item
v-if="!assigneeId"
:label="localUserType === 'user' ? '选择用户' : '选择角色'"
>
<div class="assignee-selector">
<a-input
:value="assigneeDisplayName"
:placeholder="`点击'选择'按钮选择${localUserType === 'user' ? '用户' : '角色'}`"
readonly
class="assignee-input"
>
<template #suffix>
<a-button type="link" size="small" @click="handleSelect">选择</a-button>
</template>
</a-input>
</div>
</a-form-item>
<!-- 已指定信息展示 -->
<div v-if="assigneeId" class="assignee-info-wrapper">
<div class="assignee-info-label">已指定{{ localUserType === 'user' ? '用户' : '角色' }}:</div>
<a-descriptions :column="2" size="small" bordered>
<a-descriptions-item :label="localUserType === 'user' ? '用户ID' : '角色ID'">
{{ assigneeId }}
</a-descriptions-item>
<a-descriptions-item :label="localUserType === 'user' ? '用户名' : '角色名'">
{{ assigneeDisplayName || '--' }}
</a-descriptions-item>
<a-descriptions-item>
<a-button type="link" size="small" @click="clearAssignee" class="change-btn">
重新选择
</a-button>
</a-descriptions-item>
</a-descriptions>
</div>
<a-form-item label="说明">
<a-textarea
v-model:value="assigneeRemark"
placeholder="请输入说明"
:rows="4"
allow-clear
show-count
:maxlength="200"
/>
</a-form-item>
</a-form>
<RoleSelectModal
rowKey="id"
@register="registerSelRoleModal"
@getSelectResult="onSelectRoleOk"
isRadioSelection
:showButton="false"
labelKey="roleName"
/>
<UserSelectModal
rowKey="id"
@register="registerSelUserModal"
@getSelectResult="onSelectUserOk"
isRadioSelection
:showButton="false"
labelKey="realname"
/>
</template>
<script lang="ts" setup>
import { ref, computed, watch, nextTick } from 'vue'
import { useModal } from '/@/components/Modal'
import { UserOutlined, TeamOutlined } from '@ant-design/icons-vue'
import UserSelectModal from '/@/components/Form/src/jeecg/components/modal/UserSelectModal.vue'
import RoleSelectModal from '/@/components/Form/src/jeecg/components/modal/RoleSelectModal.vue'
const emit = defineEmits(['success', 'error', 'close'])
const [registerSelUserModal, { openModal: userOpenModal }] = useModal()
const [registerSelRoleModal, { openModal: roleOpenModal }] = useModal()
// 状态
const localUserType = ref<'user' | 'role'>('user')
const assigneeId = ref('')
const assigneeDisplayName = ref('')
const assigneeRemark = ref('')
const setAssigneeData = ((data) => {
if (data) {
if (data.assignee) {
localUserType.value = data.userType === 'role' ? 'role' : 'user'
assigneeId.value = data.assignee
if (data.assigneeName) {
assigneeDisplayName.value = data.assigneeName
}
} else {
localUserType.value = data.userType === 'role' ? 'role' : 'user'
}
}
})
const clearAssignee = () => {
assigneeId.value = ''
assigneeDisplayName.value = ''
}
const handleSelect = () => {
if (localUserType.value === 'user') {
userOpenModal()
} else {
roleOpenModal()
}
}
const onSelectUserOk = (options: any[], values: any[]) => {
if (!values?.length) return
assigneeId.value = values[0]
assigneeDisplayName.value = options[0]?.label || ''
localUserType.value = 'user'
}
const onSelectRoleOk = (options: any[], values: any[]) => {
if (!values?.length) return
assigneeId.value = values[0]
assigneeDisplayName.value = options[0]?.label || ''
localUserType.value = 'role'
}
// 对外暴露的方法
const getAssigneeData = () => ({
userType: localUserType.value,
assignee: assigneeId.value,
name: assigneeDisplayName.value,
remark: assigneeRemark.value
})
defineExpose({
setAssigneeData,
getAssigneeData,
})
</script>
<style scoped lang="scss">
.drawer-content {
height: 100%;
overflow-y: auto;
padding: 16px 20px;
&::-webkit-scrollbar {
width: 4px;
}
&::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 2px;
}
&::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 2px;
&:hover {
background: #a8a8a8;
}
}
}
.assignee-card {
height: 100%;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
:deep(.ant-card-head) {
background-color: #fafbfc;
border-bottom: 1px solid #e8eef2;
.ant-card-head-title {
font-size: 16px;
font-weight: 500;
}
}
:deep(.ant-card-body) {
padding: 24px;
height: calc(100% - 57px);
display: flex;
flex-direction: column;
}
}
.assignee-selector {
display: flex;
align-items: center;
gap: 8px;
.assignee-input {
flex: 1;
:deep(.ant-input) {
background-color: #fafafa;
cursor: pointer;
&:hover {
background-color: #fff;
}
}
}
}
.assignee-info-wrapper {
margin-top: 12px;
padding: 12px;
background-color: #fafbfc;
border-radius: 8px;
.assignee-info-label {
margin-bottom: 8px;
font-weight: 500;
color: #1f2f3d;
}
.change-btn {
margin-top: 8px;
padding-left: 0;
}
:deep(.ant-descriptions) {
.ant-descriptions-item-label {
background-color: #f5f5f5;
width: 80px;
}
}
}
.assignee-actions {
margin-top: auto;
padding-top: 24px;
text-align: center;
border-top: 1px solid #f0f0f0;
}
</style>
\ No newline at end of file
<template>
<BasicModal
v-bind="$attrs"
@register="registerModal"
title="审批"
:centered="true"
width="40%"
:minHeight="400"
:useWrapper="true"
:wrapperFooterOffset="20"
>
<ApprovalPanel />
</BasicModal>
</template>
<script setup lang="ts">
import { BasicModal, useModalInner } from '/@/components/Modal';
import ApprovalPanel from './ApprovalPanel.vue';
const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter});
});
</script>
\ No newline at end of file
<template>
<BasicModal
v-bind="$attrs"
@register="registerModal"
title="审批"
:centered="true"
width="40%"
:minHeight="400"
:useWrapper="true"
:wrapperFooterOffset="20"
>
<ApprovalPanel />
</BasicModal>
</template>
<script setup lang="ts">
import { BasicModal, useModalInner } from '/@/components/Modal';
import ApprovalPanel from './ApprovalPanel.vue';
const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter});
});
</script>
\ No newline at end of file
<template>
<BasicModal
v-bind="$attrs"
@register="registerModal"
title="审批"
:centered="true"
width="40%"
:minHeight="400"
:useWrapper="true"
:wrapperFooterOffset="20"
>
<ApprovalPanel />
</BasicModal>
</template>
<script setup lang="ts">
import { BasicModal, useModalInner } from '/@/components/Modal';
import ApprovalPanel from './ApprovalPanel.vue';
const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter});
});
</script>
\ No newline at end of file
<template>
<BasicModal
v-bind="$attrs"
@register="registerModal"
title="审批"
:centered="true"
width="40%"
:minHeight="400"
:useWrapper="true"
:wrapperFooterOffset="20"
>
<ApprovalPanel />
</BasicModal>
</template>
<script setup lang="ts">
import { BasicModal, useModalInner } from '/@/components/Modal';
import ApprovalPanel from './ApprovalPanel.vue';
const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter});
});
</script>
\ No newline at end of file
<template>
<BasicModal
v-bind="$attrs"
@register="registerModal"
:title="taskTitle"
:centered="true"
width="40%"
:minHeight="400"
:useWrapper="true"
:wrapperFooterOffset="0"
@ok="handleTaskOk"
@cancel="closeThisModal"
>
<div class="assignee-panel-wrapper">
<AssigneePanel ref="refAssigneePanel"/>
</div>
</BasicModal>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { BasicModal, useModalInner } from '/@/components/Modal';
import AssigneePanel from './AssigneePanel.vue';
import { complete, getMyTaskFlow,rejectTask, assignRead,assign } from '/@/components/Process/api/todo';
import { message } from 'ant-design-vue';
const emit = defineEmits(['success','approval-fail','update-form-data'])
const taskTitle = ref('任务')
const sending = ref(false);
const taskType = ref<any>({});
const refAssigneePanel = ref<any>(null);
const myTaskFlow = ref<any>({});
const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter});
taskTitle.value = data?.taskTitle || '任务'
taskType.value = data?.taskType || "";
refAssigneePanel.value.setAssigneeData(data);
myTaskFlow.value = await getMyTaskFlow({
deploymentId: data?.deployId || '',
dataId: data?.dataId || '',
})
});
const handleTaskOk = async () => {
if (sending.value) return;
try {
sending.value = true;
const assigneeData = refAssigneePanel.value.getAssigneeData();
const submitData: any = {
instanceId: myTaskFlow.value.procInsId,
deployId: myTaskFlow.value.deployId,
taskId: myTaskFlow.value.taskId,
comment: assigneeData.remark || '',
values: {
approval: assigneeData.assignee,
approvalType: assigneeData.userType,
}
};
if (taskType.value === 'send') {
await handleSendTask(submitData);
} else if (taskType.value === 'reject') {
await handleRejectTask(submitData);
} else if (taskType.value === 'transmit') {
await handleTransmitTask(submitData);
} else if (taskType.value === 'read') {
await handleReadTask(submitData);
}
//message.success('操作成功');
emit('success', submitData);
closeThisModal();
} catch (error: any) {
} finally {
sending.value = false;
}
}
const handleSendTask = async (submitData: any) => {
const result = await complete(submitData);
return false;
};
const handleRejectTask = async (submitData) => {
const result = await rejectTask(submitData);
return false;
};
const handleReadTask = async (submitData) => {
const result = await assignRead(submitData);
return false;
};
const handleTransmitTask = async (submitData) => {
const result = await assign(submitData);
return false;
};
const closeThisModal = () => {
closeModal();
}
</script>
<style scoped lang="scss">
.assignee-panel-wrapper{
padding: 0px;
}
</style>
\ No newline at end of file
......@@ -17,7 +17,7 @@
</template>
<script lang="ts" name="problem-stProblemCheck" setup>
import { ref } from 'vue';
import { BasicTable, TableAction } from '/@/components/Table';
import { useModal } from '/@/components/Modal';
import { useListPage } from '/@/hooks/system/useListPage';
......@@ -28,18 +28,10 @@
const emit = defineEmits(['callback','openMultiForm'])
const props = defineProps({
beforeFlowNode: {
type: Object,
default: () => ({})
},
currentFlowNode: {
type: Object,
default: () => ({})
},
nextFlowNode: {
type: Object,
default: () => ({})
}
})
......
......@@ -49,6 +49,10 @@
nextFlowNode: {
type: Object,
default: () => ({})
},
todoList: {
type: Array,
default: () => []
}
})
......@@ -64,15 +68,9 @@
api: list,
columns,
canResize: false,
// formConfig: {
// schemas: searchFormSchema,
// autoSubmitOnEnter: true,
// showAdvancedButton: true,
// fieldMapToNumber: [],
// fieldMapToTime: [],
// },
beforeFetch(params) {
params['bmpNodeId'] = props.currentFlowNode.id
params['todoList'] = props.todoList
},
actionColumn: {
width: 200,
......@@ -101,7 +99,7 @@
record: {
bmpNodeId: props.currentFlowNode.id,
deployId: props.currentFlowNode.deployId,
bpmStatus: 1,
bpmStatus: 0,
}
});
}
......@@ -185,7 +183,8 @@
async function handleStartUpdate(flowData) {
let record = {
procInsId: flowData.procInsId,
id:flowData.dataId
id:flowData.dataId,
bpmStatus: 0,
}
await saveOrUpdate(record,true).then(res => {
handleSuccess(null);
......
......@@ -30,7 +30,10 @@
:show-history-form-data="true"
:data-id="dataId"
:deploy-id="deployId"
:task-id="taskId"
:show-approval-panel="isShowApprovalPanel"
:assignee="assignee"
:user-type="userType"
@submit="handleMultiFormSubmit"
@close="handleDrawerClose"
@form-data-update="handleMultiFormDataUpdate"
......@@ -67,6 +70,7 @@
const isShowApprovalPanel = ref(true);
const deployId = ref('');
const procInsId = ref('');
const taskId = ref('');
// 改为动态 ref 对象,存储每个节点的组件实例
const formComponentRefs = ref<Map<number, any>>(new Map());
......@@ -123,6 +127,7 @@
componentPath += '.vue';
}
let loader = modules[componentPath];
if (!loader) {
const ErrorComponent = {
......@@ -156,9 +161,10 @@
const deployId = currentNode.value.deployId || '';
const startResRaw = await definitionStartByDeployId(deployId, formData);
let myTaskFlow = {}
if (startResRaw?.instanceId) {
procInsId.value = startResRaw.instanceId;
taskId.value = startResRaw.taskId;
myTaskFlow["taskId"] = startResRaw.taskId;
myTaskFlow["deployId"] = startResRaw.deployId;
myTaskFlow["procInsId"] = startResRaw.instanceId;
......@@ -173,7 +179,7 @@
if(userType.value==="role"){
myTaskFlow["roleid"] = currentNode.value.assignee;
} else {
myTaskFlow["uid"] = currentNode.value.assignee;
myTaskFlow["uid"] = currentNode.value.assignee;;
}
}
await addMyTaskFlow(myTaskFlow);
......@@ -221,8 +227,6 @@
}
}
}
const handleMultiFormSubmit = async (submitData: {
nodeId: string;nodeName: string;formData: any;procDefId: string;
}) => {
......@@ -245,12 +249,10 @@
};
const handleMultiFormDataUpdate = (data: any) => {
//alert(JSON.stringify(data))
console.log('多表单数据更新:', data);
// 可以在这里实时保存数据到本地
};
function handlSendSuccess(dataId: any) {
const currentFormComponent = getCurrentFormComponent();
if (currentFormComponent && typeof currentFormComponent.handleUpdate === 'function') {
......@@ -269,8 +271,6 @@
const currentFormComponent = getCurrentFormComponent();
if (currentFormComponent && typeof currentFormComponent.handleUpdate === 'function') {
const beforeNode = workflowNodes.value[currentMultiFormIndex.value-1];
alert(currentMultiFormIndex.value)
alert(JSON.stringify(beforeNode))
await currentFormComponent.handleUpdate(dataId,beforeNode);
} else {
console.warn('当前组件实例不存在或没有 handleUpdate 方法');
......@@ -278,10 +278,13 @@
}
async function handleOpenMultiForm(data: any) {
deployId.value = currentNode.value.deployId || '';
procInsId.value = data.procInsId || '';
drawerVisible.value = true;
drawerTitle.value = currentNode.value.name || '表单处理';
dataId.value = data.id || '';
currentNode.value = workflowNodes.value[currentMultiFormIndex.value];
currentProcDefId.value = currentNode.value.procDefId || '';
......@@ -293,6 +296,8 @@
isShowApprovalPanel.value = false;
}
await setNextNodeUser();
}
......
......@@ -7,12 +7,11 @@
</div>
<!-- 底部按钮区域 -->
<div style="text-align: center;" v-if="!formDisabled">
<!-- <div style="text-align: center;" v-if="!formDisabled">
<a-space>
<a-button block @click="saveForm" pre-icon="ant-design:save" type="primary" ghost>保 存</a-button>
<a-button block @click="saveAndSendForm" pre-icon="ant-design:send" type="primary" ghost>保存并发送</a-button>
</a-space>
</div>
</div> -->
</a-card>
</div>
</template>
......@@ -122,13 +121,18 @@
return isEdit
};
const getFormData = () => {
return getFieldsValue();
};
return {
setFormDisabledStatus,
registerForm,
formDisabled,
saveForm,
saveAndSendForm,
initFormData
initFormData,
getFormData
};
},
});
......
......@@ -3,6 +3,7 @@
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"noEmit": true, // 或者使用这行,只做类型检查不生成文件
"strict": true,
"forceConsistentCasingInFileNames": true,
"allowSyntheticDefaultImports": true,
......@@ -41,5 +42,11 @@
"mock/**/*.ts",
"vite.config.ts"
],
"exclude": ["node_modules", "tests/server/**/*.ts", "dist", "**/*.js"]
"exclude": [
"node_modules",
"tests/server/**/*.ts",
"dist",
"src/**/*.js",
"**/*.js"
]
}
......@@ -24,6 +24,7 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
const env = loadEnv(mode, root);
// The boolean type read by loadEnv is a string. This function can be converted to boolean type
const viteEnv = wrapperEnv(env);
const { VITE_PORT, VITE_PUBLIC_PATH, VITE_PROXY } = viteEnv;
......@@ -32,12 +33,14 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
const serverOptions: Recordable = {}
// ----- [begin] 【JEECG作为乾坤子应用】 -----
const {VITE_GLOB_QIANKUN_MICRO_APP_NAME, VITE_GLOB_QIANKUN_MICRO_APP_ENTRY} = viteEnv;
const isQiankunMicro = VITE_GLOB_QIANKUN_MICRO_APP_NAME != null && VITE_GLOB_QIANKUN_MICRO_APP_NAME !== '';
if (isQiankunMicro && !isBuild) {
serverOptions.cors = true;
serverOptions.origin = VITE_GLOB_QIANKUN_MICRO_APP_ENTRY!.split('/').slice(0, 3).join('/');
}
// ----- [end] 【JEECG作为乾坤子应用】 -----
console.log('[init] Start Port: ', VITE_PORT);
console.debug('[init] Vite Proxy Config: ', VITE_PROXY);
......@@ -52,14 +55,17 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
find: 'vue-i18n',
replacement: 'vue-i18n/dist/vue-i18n.cjs.js',
},
// 添加 Vue 别名,确保使用正确的版本
{
find: 'vue',
replacement: 'vue/dist/vue.esm-bundler.js',
},
// /@/xxxx => src/xxxx
{
find: /\/@\//,
replacement: pathResolve('src') + '/',
},
// /#/xxxx => types/xxxx
{
find: /\/#\//,
replacement: pathResolve('types') + '/',
......@@ -68,6 +74,7 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
find: /@\//,
replacement: pathResolve('src') + '/',
},
// /#/xxxx => types/xxxx
{
find: /#\//,
replacement: pathResolve('types') + '/',
......@@ -75,14 +82,20 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
],
},
server: {
// Listening on all local IPs
host: true,
// @ts-ignore
https: false,
port: VITE_PORT,
// Load proxy configuration from .env
proxy: createProxy(VITE_PROXY),
// 合并 server 配置
...serverOptions,
// 预热常用文件,提高首次加载速度
warmup: {
clientFiles: ['./index.html', './src/main.ts', './src/App.vue'],
},
// 启用更快的源文件变更检测
fs: {
strict: false,
},
......@@ -93,12 +106,16 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
cssTarget: 'chrome80',
outDir: OUTPUT_DIR,
rollupOptions: {
// 关闭除屑优化,防止删除重要代码,导致打包后功能出现异常
treeshake: false,
output: {
// 提供命名导出,解决默认导出问题
exports: 'named',
chunkFileNames: 'js/[name]-[hash].js',
entryFileNames: 'js/[name]-[hash].js',
chunkFileNames: 'js/[name]-[hash].js', // 引入文件名的名称
entryFileNames: 'js/[name]-[hash].js', // 包的入口文件名称
// manualChunks配置 (依赖包从大到小排列)
manualChunks: {
// vue vue-router合并打包
'vue-vendor': ['vue', 'vue-router'],
'antd-vue-vendor': ['ant-design-vue','@ant-design/icons-vue','@ant-design/colors'],
'vxe-table-vendor': ['vxe-table','vxe-table-plugin-antd','xe-utils'],
......@@ -107,19 +124,27 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
},
},
},
// 关闭brotliSize显示可以稍微减少打包时间
reportCompressedSize: false,
// 提高超大静态资源警告大小
chunkSizeWarningLimit: 2000,
// 添加 CommonJS 配置
commonjsOptions: {
transformMixedEsModules: true,
include: [/node_modules/],
// 特别处理 form-create 的依赖
requireReturnsDefault: 'auto',
// 忽略导入检查
ignoreTryCatch: false,
},
},
esbuild: {
//清除全局的console.log和debug
drop: isBuild ? ['console', 'debugger'] : [],
},
define: {
// setting vue-i18-next
// Suppress warning
__INTLIFY_PROD_DEVTOOLS__: false,
__APP_INFO__: JSON.stringify(__APP_INFO__),
},
......@@ -131,20 +156,27 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
},
},
},
// The vite plugin used by the project. The quantity is large, so it is separately extracted and managed
// 预加载构建配置(首屏性能)
plugins: createVitePlugins(viteEnv, isBuild, isQiankunMicro),
optimizeDeps: {
esbuildOptions: {
target: 'es2020',
// 为 ES 模块添加支持
supported: {
'dynamic-import': true,
'import-meta': true,
},
},
force: false,
// 强制重新预构建,确保缓存是最新的
force: false, // 设置为 false,避免每次都重新预构建
exclude: [
//升级vite4后,需要排除online依赖
'@jeecg/online',
'@jeecg/aiflow',
],
// 只包含最核心的依赖,让 Vite 自动处理其他依赖
include: [
'vue',
'vue-router',
......@@ -152,6 +184,5 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
'ant-design-vue',
]
},
cacheDir: '.vite',
};
};
};
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论