update 升级 全部依赖版本与适配性代码修改

This commit is contained in:
疯狂的狮子Li 2026-07-16 18:39:41 +08:00
parent 830eacbf02
commit b1661081d6
12 changed files with 1010 additions and 1007 deletions

View File

@ -22,11 +22,11 @@
"@ant-design/x": "^2.8.0",
"@iconify/react": "^6.0.2",
"@tanstack/react-query": "^5.101.2",
"@umijs/max": "^4.6.68",
"@wangeditor-next/editor": "^5.7.13",
"@umijs/max": "^4.6.78",
"@wangeditor-next/editor": "^5.7.16",
"@wangeditor-next/editor-for-react": "^2.0.3",
"ahooks": "^3.9.7",
"antd": "^6.5.0",
"antd": "^6.5.1",
"antd-style": "^4.1.0",
"axios": "1.18.1",
"browser-image-compression": "^2.0.2",
@ -39,7 +39,7 @@
"nprogress": "0.2.0",
"react": "^19.2.7",
"react-dom": "^19.2.7",
"react-easy-crop": "^6.0.2",
"react-easy-crop": "^6.2.2",
"react-json-view-lite": "^2.5.0",
"react-syntax-highlighter": "^16.1.1",
"screenfull": "^6.0.2",
@ -47,20 +47,20 @@
},
"devDependencies": {
"@types/crypto-js": "4.2.2",
"@types/node": "^26.0.1",
"@types/node": "^26.1.1",
"@types/nprogress": "0.2.3",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"@types/react-syntax-highlighter": "^15.5.13",
"@umijs/lint": "^4.6.68",
"@umijs/lint": "^4.6.78",
"@umijs/max-plugin-openapi": "^2.0.3",
"cross-env": "^10.1.0",
"oxfmt": "^0.56.0",
"oxlint": "^1.71.0",
"oxfmt": "^0.59.0",
"oxlint": "^1.74.0",
"typescript": "^6.0.3"
},
"engines": {
"node": ">=20.0.0",
"node": ">=20.19.0",
"pnpm": ">=10.0.0"
}
}

1905
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -173,7 +173,7 @@ export default function UserSelect({
];
return (
<Modal title={title} open={open} width="80%" onOk={confirm} onCancel={() => onOpenChange(false)} destroyOnHidden>
<Modal title={title} open={open} width="80%" onOk={confirm} onCancel={() => onOpenChange(false)} forceRender>
<div className={`user-select-react${treeCollapsed ? ' is-tree-collapsed' : ''}`}>
<div className="user-select-tree-react">
<div className="user-select-tree-head">

View File

@ -55,7 +55,7 @@ export default function LayoutSettings({ open, value, onChange, onOpenChange }:
<Drawer
title="布局设置"
open={open}
width={320}
size={320}
onClose={() => onOpenChange(false)}
className="layout-settings-drawer"
>

View File

@ -130,6 +130,7 @@ export default function MessageBox({ userId }: MessageBoxProps) {
{currentItems.length ? (
<List
dataSource={currentItems}
rowKey={item => String(item.messageId)}
renderItem={item => (
<List.Item className="message-box-item" onClick={() => readMessage(item)}>
<div className="message-box-item-main">
@ -162,7 +163,7 @@ export default function MessageBox({ userId }: MessageBoxProps) {
trigger="click"
content={content}
arrow={false}
overlayInnerStyle={{ width: 340 }}
styles={{ container: { width: 340 } }}
>
<Tooltip title="消息盒子" open={tooltipOpen && !open} onOpenChange={setTooltipOpen}>
<Badge className="message-box-badge" count={unreadCount} size="small" overflowCount={99} offset={[-5, 5]}>

View File

@ -166,7 +166,7 @@ export default function SystemConfigPage() {
<div className="system-config-page">
<Tabs
activeKey={activeConfigType}
tabPosition="left"
tabPlacement="start"
className="system-config-page__tabs"
items={configTypeTabs}
onChange={changeConfigType}
@ -211,7 +211,7 @@ export default function SystemConfigPage() {
form={form}
layout="vertical"
initialValues={{ configType: 'Y' }}
modalProps={{ destroyOnHidden: true, onCancel: closeModal }}
modalProps={{ forceRender: true, onCancel: closeModal }}
onOpenChange={open => !open && closeModal()}
onFinish={submit}
>

View File

@ -40,7 +40,7 @@ export default function UserDetailDrawer({ open, userId, genderOptions, onClose
};
return (
<Drawer title="用户信息详情" open={open} width={680} onClose={closeDrawer} destroyOnHidden>
<Drawer title="用户信息详情" open={open} size={680} onClose={closeDrawer} destroyOnHidden>
<ProDescriptions
loading={loading}
column={2}

View File

@ -19,8 +19,8 @@ import {
Upload,
type UploadProps
} from 'antd';
import { useCallback, useEffect, useMemo, useState } from 'react';
import Cropper, { type Area, type Point } from 'react-easy-crop';
import { useCallback, useEffect, useMemo, useState, type ComponentType } from 'react';
import CropperModule, { type Area, type CropperProps, type Point } from 'react-easy-crop';
import type { OnlineVO } from '@/api/monitor/online/types';
import type { SocialAuthVO } from '@/api/system/social/types';
import type { UserInfoVO, UserProfileForm } from '@/api/system/user/types';
@ -37,10 +37,14 @@ import defaultAvatar from '@/assets/images/profile.jpg';
import DictTag from '@/components/common/DictTag';
import { useDict } from '@/hooks/useDict';
import { useLoading } from '@/hooks/useLoading';
import { dictOptions } from '@/utils/dict';
import { usePermissionStore } from '@/stores/permissionStore';
import { dictOptions } from '@/utils/dict';
import { getUploadErrorMessage, validateUploadFile } from '@/utils/upload';
// react-easy-crop 6.2.x 的 CommonJS 类型声明遗漏了默认导出,运行时仍为默认组件。
type CropperComponentProps = Partial<CropperProps> & Pick<CropperProps, 'crop' | 'onCropChange'>;
const Cropper = CropperModule as unknown as ComponentType<CropperComponentProps>;
const socialProviders = [
{ source: 'wechat', label: '微信', icon: wechatIcon },
{ source: 'maxkey', label: 'MaxKey', icon: maxkeyIcon },

View File

@ -43,7 +43,6 @@ import { toPageQuery, toTableData } from '@/utils/ruoyi';
type InstanceTab = 'running' | 'finish';
function requestInstanceList(tab: InstanceTab, query: FlowInstanceQuery): Promise<R<PageResult<FlowInstanceVO>>> {
if (tab === 'running') return pageByRunning(query);
return pageByFinish(query);
@ -152,7 +151,7 @@ export default function WorkflowProcessInstancePage() {
const openVariable = async (row: FlowInstanceVO) => {
setVariableRow(row);
openVariableModal();
variableForm.resetFields();
if (canVariable) variableForm.resetFields();
await withVariableLoading(async () => {
const res = await instanceVariable(row.id);
setVariableText(res.data.variable || '');
@ -207,6 +206,7 @@ export default function WorkflowProcessInstancePage() {
{
title: '任务名称',
dataIndex: 'nodeName',
fieldProps: { id: 'workflow-process-instance-node-name' },
width: 150,
render: (_, row) => <EllipsisText value={row.nodeName} maxWidth={130} />
},
@ -367,7 +367,7 @@ export default function WorkflowProcessInstancePage() {
open={invalidOpen}
form={invalidForm}
layout="vertical"
modalProps={{ destroyOnHidden: true, onCancel: closeInvalidModal }}
modalProps={{ forceRender: true, onCancel: closeInvalidModal }}
onOpenChange={open => !open && closeInvalidModal()}
onFinish={submitInvalid}
>
@ -379,14 +379,7 @@ export default function WorkflowProcessInstancePage() {
/>
</ModalForm>
<Modal
title="流程变量"
open={variableOpen}
width={800}
onCancel={closeVariableModal}
footer={null}
destroyOnHidden
>
<Modal title="流程变量" open={variableOpen} width={800} forceRender onCancel={closeVariableModal} footer={null}>
<Card
loading={variableLoading}
title={variableRow?.flowName ? `流程定义名称:${variableRow.flowName}` : '流程变量'}

View File

@ -2,7 +2,7 @@ import { BellOutlined, EyeOutlined, SettingOutlined, SwapOutlined, UserAddOutlin
import { ModalForm, PageContainer, ProTable, type ActionType, type ProColumns } from '@ant-design/pro-components';
import { useBoolean } from 'ahooks';
import { Badge, Button, Form, message, Tabs } from 'antd';
import { useCallback, useMemo, useRef, useState } from 'react';
import { useCallback, useMemo, useRef, useState, type Key } from 'react';
import type { UserVO } from '@/api/system/user/types';
import type { PageResult, R } from '@/api/types';
import type { FlowTaskVO, TaskQuery } from '@/api/workflow/task/types';
@ -23,7 +23,9 @@ import { confirmTitleSafe } from '@/utils/modal';
import { toPageQuery, toTableData } from '@/utils/ruoyi';
type AllTaskTab = 'waiting' | 'finish';
type UserSelectMode = 'applicant' | 'assignee';
type TaskTableRow = FlowTaskVO & {
tableRowKey: string;
};
function requestAllTaskList(tab: AllTaskTab, query: TaskQuery): Promise<R<PageResult<FlowTaskVO>>> {
if (tab === 'waiting') return pageByAllTaskWait(query);
@ -46,7 +48,8 @@ export default function WorkflowAllTaskWaitingPage() {
const [urgeForm] = Form.useForm<{ message: string; messageType: string[] }>();
const dicts = useDict('wf_business_status', 'wf_task_status', 'sys_normal_disable');
const [activeTab, setActiveTab] = useState<AllTaskTab>('waiting');
const [selectedRows, setSelectedRows] = useState<FlowTaskVO[]>([]);
const [selectedRowKeys, setSelectedRowKeys] = useState<Key[]>([]);
const [selectedRows, setSelectedRows] = useState<TaskTableRow[]>([]);
const [selectedApplicants, setSelectedApplicants] = useState<UserVO[]>([]);
const [userModalOpen, { setTrue: openUserModal, setFalse: closeUserModal }] = useBoolean(false);
const [userSelectMode, setUserSelectMode] = useState<UserSelectMode>('applicant');
@ -56,7 +59,7 @@ export default function WorkflowAllTaskWaitingPage() {
const businessStatusOptions = useMemo(() => dictOptions(dicts.wf_business_status), [dicts.wf_business_status]);
const taskStatusOptions = useMemo(() => dictOptions(dicts.wf_task_status), [dicts.wf_task_status]);
const selectedTaskIds = selectedRows.map(item => item.id).filter(Boolean);
const selectedTaskIds = [...new Set(selectedRows.map(item => item.id).filter(Boolean))];
const selectedApplicantIds = selectedApplicants.map(item => item.userId).filter(Boolean) as Array<string | number>;
const resetSearch = useSearchReset(
actionRef,
@ -65,6 +68,7 @@ export default function WorkflowAllTaskWaitingPage() {
const changeTab = (key: string) => {
setActiveTab(key as AllTaskTab);
setSelectedRowKeys([]);
setSelectedRows([]);
setTimeout(() => actionRef.current?.reloadAndRest?.(), 0);
};
@ -102,6 +106,7 @@ export default function WorkflowAllTaskWaitingPage() {
await updateAssignee(selectedTaskIds, userId);
message.success('操作成功');
closeUserModal();
setSelectedRowKeys([]);
setSelectedRows([]);
actionRef.current?.reload();
return;
@ -118,6 +123,8 @@ export default function WorkflowAllTaskWaitingPage() {
await urgeTask({ ...values, taskIdList: selectedTaskIds });
message.success('操作成功');
urgeForm.resetFields();
setSelectedRowKeys([]);
setSelectedRows([]);
actionRef.current?.reload();
return true;
};
@ -127,7 +134,7 @@ export default function WorkflowAllTaskWaitingPage() {
openMeddleModal();
};
const columns: ProColumns<FlowTaskVO>[] = [
const columns: ProColumns<TaskTableRow>[] = [
{
title: '业务编码',
dataIndex: 'businessCode',
@ -172,6 +179,7 @@ export default function WorkflowAllTaskWaitingPage() {
{
title: '任务名称',
dataIndex: 'nodeName',
fieldProps: { id: 'workflow-all-task-node-name' },
width: 150,
render: (_, row) => <EllipsisText value={row.nodeName} maxWidth={130} />
},
@ -208,7 +216,7 @@ export default function WorkflowAllTaskWaitingPage() {
search: false,
width: 120,
fieldProps: { options: taskStatusOptions },
render: (_: unknown, row: FlowTaskVO) => (
render: (_: unknown, row: TaskTableRow) => (
<DictTag options={dicts.wf_task_status} value={row.flowTaskStatus} />
)
}
@ -246,17 +254,20 @@ export default function WorkflowAllTaskWaitingPage() {
{ key: 'finish', label: '已办任务' }
]}
/>
<ProTable<FlowTaskVO, TaskQuery>
<ProTable<TaskTableRow, TaskQuery>
actionRef={actionRef}
rowKey="id"
rowKey="tableRowKey"
columns={columns}
scroll={tableScroll}
search={{ labelWidth: 100 }}
form={{ onReset: resetSearch }}
pagination={{ defaultPageSize: 10, showSizeChanger: true }}
rowSelection={{
selectedRowKeys: selectedTaskIds,
onChange: (_, rows) => setSelectedRows(rows)
selectedRowKeys,
onChange: (keys, rows) => {
setSelectedRowKeys(keys);
setSelectedRows(rows);
}
}}
request={async params => {
const query = toPageQuery(params);
@ -264,7 +275,14 @@ export default function WorkflowAllTaskWaitingPage() {
...query,
createByIds: selectedApplicantIds
});
return toTableData(res);
const tableData = toTableData(res);
return {
...tableData,
data: tableData.data.map((row, index) => ({
...row,
tableRowKey: `${activeTab}:${query.pageNum || 1}:${index}`
}))
};
}}
toolbar={{ title: activeTab === 'waiting' ? '全部待办任务' : '全部已办任务' }}
toolBarRender={() => [
@ -319,7 +337,7 @@ export default function WorkflowAllTaskWaitingPage() {
form={urgeForm}
layout="vertical"
initialValues={{ messageType: ['1'] }}
modalProps={{ destroyOnHidden: true, onCancel: closeUrgeModal }}
modalProps={{ forceRender: true, onCancel: closeUrgeModal }}
onOpenChange={open => !open && closeUrgeModal()}
onFinish={submitUrge}
>

View File

@ -30,7 +30,6 @@ const pageTitle: Record<TaskListType, string> = {
copy: '抄送任务'
};
function requestTaskList(type: TaskListType, query: TaskQuery): Promise<R<PageResult<FlowTaskVO>>> {
if (type === 'wait') return pageByTaskWait(query);
if (type === 'finish') return pageByTaskFinish(query);
@ -98,6 +97,7 @@ export default function WorkflowTaskListPage({ type }: WorkflowTaskListPageProps
{
title: '任务名称',
dataIndex: 'nodeName',
fieldProps: { id: `workflow-task-${type}-node-name` },
width: 150,
render: (_, row) => <EllipsisText value={row.nodeName} maxWidth={130} />
},

View File

@ -31,9 +31,19 @@ function sortNotices(notices: NoticeItem[]) {
return [...notices].sort((a, b) => Number(b.timestamp || 0) - Number(a.timestamp || 0));
}
function dedupeNotices(notices: NoticeItem[]) {
const messageIds = new Set<string>();
return notices.filter(notice => {
const messageId = String(notice.messageId);
if (messageIds.has(messageId)) return false;
messageIds.add(messageId);
return true;
});
}
export const useNoticeStore = create<NoticeState>(set => ({
notices: [],
setNotices: notices => set({ notices: sortNotices(notices) }),
setNotices: notices => set({ notices: sortNotices(dedupeNotices(notices)) }),
addNotice: notice =>
set(state => {
const key = noticeKey(notice);