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", "@ant-design/x": "^2.8.0",
"@iconify/react": "^6.0.2", "@iconify/react": "^6.0.2",
"@tanstack/react-query": "^5.101.2", "@tanstack/react-query": "^5.101.2",
"@umijs/max": "^4.6.68", "@umijs/max": "^4.6.78",
"@wangeditor-next/editor": "^5.7.13", "@wangeditor-next/editor": "^5.7.16",
"@wangeditor-next/editor-for-react": "^2.0.3", "@wangeditor-next/editor-for-react": "^2.0.3",
"ahooks": "^3.9.7", "ahooks": "^3.9.7",
"antd": "^6.5.0", "antd": "^6.5.1",
"antd-style": "^4.1.0", "antd-style": "^4.1.0",
"axios": "1.18.1", "axios": "1.18.1",
"browser-image-compression": "^2.0.2", "browser-image-compression": "^2.0.2",
@ -39,7 +39,7 @@
"nprogress": "0.2.0", "nprogress": "0.2.0",
"react": "^19.2.7", "react": "^19.2.7",
"react-dom": "^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-json-view-lite": "^2.5.0",
"react-syntax-highlighter": "^16.1.1", "react-syntax-highlighter": "^16.1.1",
"screenfull": "^6.0.2", "screenfull": "^6.0.2",
@ -47,20 +47,20 @@
}, },
"devDependencies": { "devDependencies": {
"@types/crypto-js": "4.2.2", "@types/crypto-js": "4.2.2",
"@types/node": "^26.0.1", "@types/node": "^26.1.1",
"@types/nprogress": "0.2.3", "@types/nprogress": "0.2.3",
"@types/react": "^19.2.17", "@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"@types/react-syntax-highlighter": "^15.5.13", "@types/react-syntax-highlighter": "^15.5.13",
"@umijs/lint": "^4.6.68", "@umijs/lint": "^4.6.78",
"@umijs/max-plugin-openapi": "^2.0.3", "@umijs/max-plugin-openapi": "^2.0.3",
"cross-env": "^10.1.0", "cross-env": "^10.1.0",
"oxfmt": "^0.56.0", "oxfmt": "^0.59.0",
"oxlint": "^1.71.0", "oxlint": "^1.74.0",
"typescript": "^6.0.3" "typescript": "^6.0.3"
}, },
"engines": { "engines": {
"node": ">=20.0.0", "node": ">=20.19.0",
"pnpm": ">=10.0.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 ( 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-react${treeCollapsed ? ' is-tree-collapsed' : ''}`}>
<div className="user-select-tree-react"> <div className="user-select-tree-react">
<div className="user-select-tree-head"> <div className="user-select-tree-head">

View File

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

View File

@ -130,6 +130,7 @@ export default function MessageBox({ userId }: MessageBoxProps) {
{currentItems.length ? ( {currentItems.length ? (
<List <List
dataSource={currentItems} dataSource={currentItems}
rowKey={item => String(item.messageId)}
renderItem={item => ( renderItem={item => (
<List.Item className="message-box-item" onClick={() => readMessage(item)}> <List.Item className="message-box-item" onClick={() => readMessage(item)}>
<div className="message-box-item-main"> <div className="message-box-item-main">
@ -162,7 +163,7 @@ export default function MessageBox({ userId }: MessageBoxProps) {
trigger="click" trigger="click"
content={content} content={content}
arrow={false} arrow={false}
overlayInnerStyle={{ width: 340 }} styles={{ container: { width: 340 } }}
> >
<Tooltip title="消息盒子" open={tooltipOpen && !open} onOpenChange={setTooltipOpen}> <Tooltip title="消息盒子" open={tooltipOpen && !open} onOpenChange={setTooltipOpen}>
<Badge className="message-box-badge" count={unreadCount} size="small" overflowCount={99} offset={[-5, 5]}> <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"> <div className="system-config-page">
<Tabs <Tabs
activeKey={activeConfigType} activeKey={activeConfigType}
tabPosition="left" tabPlacement="start"
className="system-config-page__tabs" className="system-config-page__tabs"
items={configTypeTabs} items={configTypeTabs}
onChange={changeConfigType} onChange={changeConfigType}
@ -211,7 +211,7 @@ export default function SystemConfigPage() {
form={form} form={form}
layout="vertical" layout="vertical"
initialValues={{ configType: 'Y' }} initialValues={{ configType: 'Y' }}
modalProps={{ destroyOnHidden: true, onCancel: closeModal }} modalProps={{ forceRender: true, onCancel: closeModal }}
onOpenChange={open => !open && closeModal()} onOpenChange={open => !open && closeModal()}
onFinish={submit} onFinish={submit}
> >

View File

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

View File

@ -19,8 +19,8 @@ import {
Upload, Upload,
type UploadProps type UploadProps
} from 'antd'; } from 'antd';
import { useCallback, useEffect, useMemo, useState } from 'react'; import { useCallback, useEffect, useMemo, useState, type ComponentType } from 'react';
import Cropper, { type Area, type Point } from 'react-easy-crop'; import CropperModule, { type Area, type CropperProps, type Point } from 'react-easy-crop';
import type { OnlineVO } from '@/api/monitor/online/types'; import type { OnlineVO } from '@/api/monitor/online/types';
import type { SocialAuthVO } from '@/api/system/social/types'; import type { SocialAuthVO } from '@/api/system/social/types';
import type { UserInfoVO, UserProfileForm } from '@/api/system/user/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 DictTag from '@/components/common/DictTag';
import { useDict } from '@/hooks/useDict'; import { useDict } from '@/hooks/useDict';
import { useLoading } from '@/hooks/useLoading'; import { useLoading } from '@/hooks/useLoading';
import { dictOptions } from '@/utils/dict';
import { usePermissionStore } from '@/stores/permissionStore'; import { usePermissionStore } from '@/stores/permissionStore';
import { dictOptions } from '@/utils/dict';
import { getUploadErrorMessage, validateUploadFile } from '@/utils/upload'; 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 = [ const socialProviders = [
{ source: 'wechat', label: '微信', icon: wechatIcon }, { source: 'wechat', label: '微信', icon: wechatIcon },
{ source: 'maxkey', label: 'MaxKey', icon: maxkeyIcon }, { source: 'maxkey', label: 'MaxKey', icon: maxkeyIcon },

View File

@ -43,7 +43,6 @@ import { toPageQuery, toTableData } from '@/utils/ruoyi';
type InstanceTab = 'running' | 'finish'; type InstanceTab = 'running' | 'finish';
function requestInstanceList(tab: InstanceTab, query: FlowInstanceQuery): Promise<R<PageResult<FlowInstanceVO>>> { function requestInstanceList(tab: InstanceTab, query: FlowInstanceQuery): Promise<R<PageResult<FlowInstanceVO>>> {
if (tab === 'running') return pageByRunning(query); if (tab === 'running') return pageByRunning(query);
return pageByFinish(query); return pageByFinish(query);
@ -152,7 +151,7 @@ export default function WorkflowProcessInstancePage() {
const openVariable = async (row: FlowInstanceVO) => { const openVariable = async (row: FlowInstanceVO) => {
setVariableRow(row); setVariableRow(row);
openVariableModal(); openVariableModal();
variableForm.resetFields(); if (canVariable) variableForm.resetFields();
await withVariableLoading(async () => { await withVariableLoading(async () => {
const res = await instanceVariable(row.id); const res = await instanceVariable(row.id);
setVariableText(res.data.variable || ''); setVariableText(res.data.variable || '');
@ -207,6 +206,7 @@ export default function WorkflowProcessInstancePage() {
{ {
title: '任务名称', title: '任务名称',
dataIndex: 'nodeName', dataIndex: 'nodeName',
fieldProps: { id: 'workflow-process-instance-node-name' },
width: 150, width: 150,
render: (_, row) => <EllipsisText value={row.nodeName} maxWidth={130} /> render: (_, row) => <EllipsisText value={row.nodeName} maxWidth={130} />
}, },
@ -367,7 +367,7 @@ export default function WorkflowProcessInstancePage() {
open={invalidOpen} open={invalidOpen}
form={invalidForm} form={invalidForm}
layout="vertical" layout="vertical"
modalProps={{ destroyOnHidden: true, onCancel: closeInvalidModal }} modalProps={{ forceRender: true, onCancel: closeInvalidModal }}
onOpenChange={open => !open && closeInvalidModal()} onOpenChange={open => !open && closeInvalidModal()}
onFinish={submitInvalid} onFinish={submitInvalid}
> >
@ -379,14 +379,7 @@ export default function WorkflowProcessInstancePage() {
/> />
</ModalForm> </ModalForm>
<Modal <Modal title="流程变量" open={variableOpen} width={800} forceRender onCancel={closeVariableModal} footer={null}>
title="流程变量"
open={variableOpen}
width={800}
onCancel={closeVariableModal}
footer={null}
destroyOnHidden
>
<Card <Card
loading={variableLoading} loading={variableLoading}
title={variableRow?.flowName ? `流程定义名称:${variableRow.flowName}` : '流程变量'} 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 { ModalForm, PageContainer, ProTable, type ActionType, type ProColumns } from '@ant-design/pro-components';
import { useBoolean } from 'ahooks'; import { useBoolean } from 'ahooks';
import { Badge, Button, Form, message, Tabs } from 'antd'; 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 { UserVO } from '@/api/system/user/types';
import type { PageResult, R } from '@/api/types'; import type { PageResult, R } from '@/api/types';
import type { FlowTaskVO, TaskQuery } from '@/api/workflow/task/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'; import { toPageQuery, toTableData } from '@/utils/ruoyi';
type AllTaskTab = 'waiting' | 'finish'; type AllTaskTab = 'waiting' | 'finish';
type UserSelectMode = 'applicant' | 'assignee'; type UserSelectMode = 'applicant' | 'assignee';
type TaskTableRow = FlowTaskVO & {
tableRowKey: string;
};
function requestAllTaskList(tab: AllTaskTab, query: TaskQuery): Promise<R<PageResult<FlowTaskVO>>> { function requestAllTaskList(tab: AllTaskTab, query: TaskQuery): Promise<R<PageResult<FlowTaskVO>>> {
if (tab === 'waiting') return pageByAllTaskWait(query); if (tab === 'waiting') return pageByAllTaskWait(query);
@ -46,7 +48,8 @@ export default function WorkflowAllTaskWaitingPage() {
const [urgeForm] = Form.useForm<{ message: string; messageType: string[] }>(); const [urgeForm] = Form.useForm<{ message: string; messageType: string[] }>();
const dicts = useDict('wf_business_status', 'wf_task_status', 'sys_normal_disable'); const dicts = useDict('wf_business_status', 'wf_task_status', 'sys_normal_disable');
const [activeTab, setActiveTab] = useState<AllTaskTab>('waiting'); 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 [selectedApplicants, setSelectedApplicants] = useState<UserVO[]>([]);
const [userModalOpen, { setTrue: openUserModal, setFalse: closeUserModal }] = useBoolean(false); const [userModalOpen, { setTrue: openUserModal, setFalse: closeUserModal }] = useBoolean(false);
const [userSelectMode, setUserSelectMode] = useState<UserSelectMode>('applicant'); 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 businessStatusOptions = useMemo(() => dictOptions(dicts.wf_business_status), [dicts.wf_business_status]);
const taskStatusOptions = useMemo(() => dictOptions(dicts.wf_task_status), [dicts.wf_task_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 selectedApplicantIds = selectedApplicants.map(item => item.userId).filter(Boolean) as Array<string | number>;
const resetSearch = useSearchReset( const resetSearch = useSearchReset(
actionRef, actionRef,
@ -65,6 +68,7 @@ export default function WorkflowAllTaskWaitingPage() {
const changeTab = (key: string) => { const changeTab = (key: string) => {
setActiveTab(key as AllTaskTab); setActiveTab(key as AllTaskTab);
setSelectedRowKeys([]);
setSelectedRows([]); setSelectedRows([]);
setTimeout(() => actionRef.current?.reloadAndRest?.(), 0); setTimeout(() => actionRef.current?.reloadAndRest?.(), 0);
}; };
@ -102,6 +106,7 @@ export default function WorkflowAllTaskWaitingPage() {
await updateAssignee(selectedTaskIds, userId); await updateAssignee(selectedTaskIds, userId);
message.success('操作成功'); message.success('操作成功');
closeUserModal(); closeUserModal();
setSelectedRowKeys([]);
setSelectedRows([]); setSelectedRows([]);
actionRef.current?.reload(); actionRef.current?.reload();
return; return;
@ -118,6 +123,8 @@ export default function WorkflowAllTaskWaitingPage() {
await urgeTask({ ...values, taskIdList: selectedTaskIds }); await urgeTask({ ...values, taskIdList: selectedTaskIds });
message.success('操作成功'); message.success('操作成功');
urgeForm.resetFields(); urgeForm.resetFields();
setSelectedRowKeys([]);
setSelectedRows([]);
actionRef.current?.reload(); actionRef.current?.reload();
return true; return true;
}; };
@ -127,7 +134,7 @@ export default function WorkflowAllTaskWaitingPage() {
openMeddleModal(); openMeddleModal();
}; };
const columns: ProColumns<FlowTaskVO>[] = [ const columns: ProColumns<TaskTableRow>[] = [
{ {
title: '业务编码', title: '业务编码',
dataIndex: 'businessCode', dataIndex: 'businessCode',
@ -172,6 +179,7 @@ export default function WorkflowAllTaskWaitingPage() {
{ {
title: '任务名称', title: '任务名称',
dataIndex: 'nodeName', dataIndex: 'nodeName',
fieldProps: { id: 'workflow-all-task-node-name' },
width: 150, width: 150,
render: (_, row) => <EllipsisText value={row.nodeName} maxWidth={130} /> render: (_, row) => <EllipsisText value={row.nodeName} maxWidth={130} />
}, },
@ -208,7 +216,7 @@ export default function WorkflowAllTaskWaitingPage() {
search: false, search: false,
width: 120, width: 120,
fieldProps: { options: taskStatusOptions }, fieldProps: { options: taskStatusOptions },
render: (_: unknown, row: FlowTaskVO) => ( render: (_: unknown, row: TaskTableRow) => (
<DictTag options={dicts.wf_task_status} value={row.flowTaskStatus} /> <DictTag options={dicts.wf_task_status} value={row.flowTaskStatus} />
) )
} }
@ -246,17 +254,20 @@ export default function WorkflowAllTaskWaitingPage() {
{ key: 'finish', label: '已办任务' } { key: 'finish', label: '已办任务' }
]} ]}
/> />
<ProTable<FlowTaskVO, TaskQuery> <ProTable<TaskTableRow, TaskQuery>
actionRef={actionRef} actionRef={actionRef}
rowKey="id" rowKey="tableRowKey"
columns={columns} columns={columns}
scroll={tableScroll} scroll={tableScroll}
search={{ labelWidth: 100 }} search={{ labelWidth: 100 }}
form={{ onReset: resetSearch }} form={{ onReset: resetSearch }}
pagination={{ defaultPageSize: 10, showSizeChanger: true }} pagination={{ defaultPageSize: 10, showSizeChanger: true }}
rowSelection={{ rowSelection={{
selectedRowKeys: selectedTaskIds, selectedRowKeys,
onChange: (_, rows) => setSelectedRows(rows) onChange: (keys, rows) => {
setSelectedRowKeys(keys);
setSelectedRows(rows);
}
}} }}
request={async params => { request={async params => {
const query = toPageQuery(params); const query = toPageQuery(params);
@ -264,7 +275,14 @@ export default function WorkflowAllTaskWaitingPage() {
...query, ...query,
createByIds: selectedApplicantIds 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' ? '全部待办任务' : '全部已办任务' }} toolbar={{ title: activeTab === 'waiting' ? '全部待办任务' : '全部已办任务' }}
toolBarRender={() => [ toolBarRender={() => [
@ -319,7 +337,7 @@ export default function WorkflowAllTaskWaitingPage() {
form={urgeForm} form={urgeForm}
layout="vertical" layout="vertical"
initialValues={{ messageType: ['1'] }} initialValues={{ messageType: ['1'] }}
modalProps={{ destroyOnHidden: true, onCancel: closeUrgeModal }} modalProps={{ forceRender: true, onCancel: closeUrgeModal }}
onOpenChange={open => !open && closeUrgeModal()} onOpenChange={open => !open && closeUrgeModal()}
onFinish={submitUrge} onFinish={submitUrge}
> >

View File

@ -30,7 +30,6 @@ const pageTitle: Record<TaskListType, string> = {
copy: '抄送任务' copy: '抄送任务'
}; };
function requestTaskList(type: TaskListType, query: TaskQuery): Promise<R<PageResult<FlowTaskVO>>> { function requestTaskList(type: TaskListType, query: TaskQuery): Promise<R<PageResult<FlowTaskVO>>> {
if (type === 'wait') return pageByTaskWait(query); if (type === 'wait') return pageByTaskWait(query);
if (type === 'finish') return pageByTaskFinish(query); if (type === 'finish') return pageByTaskFinish(query);
@ -98,6 +97,7 @@ export default function WorkflowTaskListPage({ type }: WorkflowTaskListPageProps
{ {
title: '任务名称', title: '任务名称',
dataIndex: 'nodeName', dataIndex: 'nodeName',
fieldProps: { id: `workflow-task-${type}-node-name` },
width: 150, width: 150,
render: (_, row) => <EllipsisText value={row.nodeName} maxWidth={130} /> 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)); 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 => ({ export const useNoticeStore = create<NoticeState>(set => ({
notices: [], notices: [],
setNotices: notices => set({ notices: sortNotices(notices) }), setNotices: notices => set({ notices: sortNotices(dedupeNotices(notices)) }),
addNotice: notice => addNotice: notice =>
set(state => { set(state => {
const key = noticeKey(notice); const key = noticeKey(notice);