feat: menu
This commit is contained in:
1
.github/workflows/ci.yml
vendored
1
.github/workflows/ci.yml
vendored
@@ -7,6 +7,7 @@ permissions:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
if: false
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
|
|||||||
@@ -152,13 +152,12 @@ export default defineConfig({
|
|||||||
* @doc https://pro.ant.design/zh-cn/docs/openapi/
|
* @doc https://pro.ant.design/zh-cn/docs/openapi/
|
||||||
*/
|
*/
|
||||||
openAPI: [
|
openAPI: [
|
||||||
{
|
// {
|
||||||
requestLibPath: "import { request } from '@umijs/max'",
|
// requestLibPath: "import { request } from '@umijs/max'",
|
||||||
|
// schemaPath: join(__dirname, "oneapi/prodapi.json"),
|
||||||
schemaPath: join(__dirname, "oneapi/prodapi.json"),
|
// mock: false,
|
||||||
mock: false,
|
// projectName: "prodApi",
|
||||||
projectName: "prodApi",
|
// },
|
||||||
},
|
|
||||||
// {schemaPath: "./docs/apifox-api.json",
|
// {schemaPath: "./docs/apifox-api.json",
|
||||||
// requestLibPath: "import { request } from '@umijs/max'",
|
// requestLibPath: "import { request } from '@umijs/max'",
|
||||||
// schemaPath: join(__dirname, "oneapi.json"),
|
// schemaPath: join(__dirname, "oneapi.json"),
|
||||||
|
|||||||
38
src/app.tsx
38
src/app.tsx
@@ -1,5 +1,11 @@
|
|||||||
import React, { Children, Component, JSX, Suspense } from "react";
|
import React, {
|
||||||
import { Spin } from "antd";
|
Children,
|
||||||
|
Component,
|
||||||
|
createContext,
|
||||||
|
JSX,
|
||||||
|
Suspense,
|
||||||
|
} from "react";
|
||||||
|
import { Modal, Spin } from "antd";
|
||||||
import type { Settings as LayoutSettings } from "@ant-design/pro-components";
|
import type { Settings as LayoutSettings } from "@ant-design/pro-components";
|
||||||
import { SettingDrawer } from "@ant-design/pro-components";
|
import { SettingDrawer } from "@ant-design/pro-components";
|
||||||
import type { RequestConfig, RunTimeLayoutConfig } from "@umijs/max";
|
import type { RequestConfig, RunTimeLayoutConfig } from "@umijs/max";
|
||||||
@@ -197,6 +203,34 @@ export const request: RequestConfig = {
|
|||||||
return { url, options: { ...options, headers } };
|
return { url, options: { ...options, headers } };
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
// 添加参数序列化配置
|
||||||
|
paramsSerializer: (params) => {
|
||||||
|
const searchParams = new URLSearchParams();
|
||||||
|
|
||||||
|
const appendParams = (key: string, value: any) => {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
// 特殊处理 createTime 数组,转换为 createTime[0] 和 createTime[1] 格式
|
||||||
|
if (key === "createTime") {
|
||||||
|
value.forEach((val, index) => {
|
||||||
|
searchParams.append(`${key}[${index}]`, val);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// 其他数组参数保持默认行为
|
||||||
|
value.forEach((val) => {
|
||||||
|
searchParams.append(`${key}[]`, val);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (value !== null && value !== undefined) {
|
||||||
|
searchParams.append(key, String(value));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.keys(params).forEach((key) => {
|
||||||
|
appendParams(key, params[key]);
|
||||||
|
});
|
||||||
|
|
||||||
|
return searchParams.toString();
|
||||||
|
},
|
||||||
};
|
};
|
||||||
// umi 4 使用 modifyRoutes
|
// umi 4 使用 modifyRoutes
|
||||||
export function patchClientRoutes({ routes }: { routes: any }) {
|
export function patchClientRoutes({ routes }: { routes: any }) {
|
||||||
|
|||||||
122
src/components/DrawerForm/index.tsx
Normal file
122
src/components/DrawerForm/index.tsx
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
import React, { useImperativeHandle, forwardRef } from "react";
|
||||||
|
import { DrawerForm } from "@ant-design/pro-components";
|
||||||
|
import type { ProFormColumnsType } from "@ant-design/pro-components";
|
||||||
|
import { BetaSchemaForm } from "@ant-design/pro-components";
|
||||||
|
import { Button, Drawer, Space, Typography } from "antd";
|
||||||
|
import { CloseOutlined } from "@ant-design/icons";
|
||||||
|
const { Title } = Typography;
|
||||||
|
interface ConfigurableDrawerFormProps {
|
||||||
|
title?: string;
|
||||||
|
columns: ProFormColumnsType[];
|
||||||
|
onSubmit?: (values: any) => Promise<boolean>;
|
||||||
|
initialValues?: Record<string, any>;
|
||||||
|
width?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ConfigurableDrawerFormRef {
|
||||||
|
open: (data?: Record<string, any>) => void;
|
||||||
|
close: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ConfigurableDrawerForm = forwardRef<
|
||||||
|
ConfigurableDrawerFormRef,
|
||||||
|
ConfigurableDrawerFormProps
|
||||||
|
>(({ title = "表单", columns, onSubmit, initialValues, width = 600 }, ref) => {
|
||||||
|
const [open, setOpen] = React.useState(false);
|
||||||
|
const [formData, setFormData] = React.useState(initialValues || {});
|
||||||
|
const [loading, setLoading] = React.useState<boolean>(false);
|
||||||
|
// 添加表单实例引用
|
||||||
|
const formRef = React.useRef<any>(null);
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
open: (data) => {
|
||||||
|
if (data) {
|
||||||
|
setFormData(data);
|
||||||
|
}
|
||||||
|
console.log("open");
|
||||||
|
setOpen(true);
|
||||||
|
},
|
||||||
|
close: () => setOpen(false),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
try {
|
||||||
|
if (onSubmit) {
|
||||||
|
await formRef.current?.validateFields();
|
||||||
|
setLoading(true);
|
||||||
|
const values = formRef.current?.getFieldsValue();
|
||||||
|
const success = await onSubmit(values);
|
||||||
|
if (success) {
|
||||||
|
setOpen(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const customHeader = (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
padding: "0 0px 16px 0px",
|
||||||
|
borderBottom: "1px solid #f0f0f0",
|
||||||
|
marginBottom: "16px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Title level={4} style={{ margin: 0 }}>
|
||||||
|
{title}
|
||||||
|
</Title>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
icon={<CloseOutlined />}
|
||||||
|
onClick={() => setOpen(false)}
|
||||||
|
style={{
|
||||||
|
border: "none",
|
||||||
|
boxShadow: "none",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<Drawer
|
||||||
|
title={title}
|
||||||
|
styles={{
|
||||||
|
header: {
|
||||||
|
textAlign: "left",
|
||||||
|
position: "relative",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
destroyOnHidden
|
||||||
|
closable={true} // 隐藏默认关闭按钮
|
||||||
|
open={open}
|
||||||
|
onClose={() => setOpen(false)}
|
||||||
|
width={width}
|
||||||
|
footer={
|
||||||
|
<Space style={{ width: "100%", justifyContent: "end" }}>
|
||||||
|
<Button onClick={() => setOpen(false)}>取消</Button>
|
||||||
|
<Button loading={loading} type="primary" onClick={handleSubmit}>
|
||||||
|
保存
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{/* {customHeader} */}
|
||||||
|
<BetaSchemaForm
|
||||||
|
initialValues={formData}
|
||||||
|
layoutType="Form"
|
||||||
|
formRef={formRef}
|
||||||
|
columns={columns}
|
||||||
|
layout="horizontal"
|
||||||
|
labelCol={{ span: 4 }}
|
||||||
|
wrapperCol={{ span: 20 }}
|
||||||
|
submitter={false}
|
||||||
|
/>
|
||||||
|
</Drawer>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default ConfigurableDrawerForm;
|
||||||
@@ -1,5 +1,12 @@
|
|||||||
// components/EnhancedProTable/EnhancedProTable.tsx
|
// components/EnhancedProTable/EnhancedProTable.tsx
|
||||||
import React, { useRef, useState, useCallback, useMemo } from "react";
|
import React, {
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
useCallback,
|
||||||
|
useMemo,
|
||||||
|
act,
|
||||||
|
forwardRef,
|
||||||
|
} from "react";
|
||||||
import {
|
import {
|
||||||
ProTable,
|
ProTable,
|
||||||
ProColumns,
|
ProColumns,
|
||||||
@@ -19,17 +26,19 @@ import {
|
|||||||
handleTableDropdownSelect,
|
handleTableDropdownSelect,
|
||||||
formatPaginationTotal,
|
formatPaginationTotal,
|
||||||
} from "@/utils/antd/tableHelpers";
|
} from "@/utils/antd/tableHelpers";
|
||||||
|
import { PlusOutlined } from "@ant-design/icons";
|
||||||
|
|
||||||
function EnhancedProTable<T extends BaseRecord, U extends ParamsType = any>(
|
function EnhancedProTable<T extends BaseRecord, U extends ParamsType = any>(
|
||||||
props: EnhancedProTableProps<T, U>
|
props: EnhancedProTableProps<T, U>,
|
||||||
|
ref: React.Ref<ActionType | undefined> | undefined
|
||||||
) {
|
) {
|
||||||
const {
|
const {
|
||||||
columns: originalColumns,
|
columns,
|
||||||
request,
|
request,
|
||||||
actions = [],
|
actions = [],
|
||||||
toolbarActions = [],
|
|
||||||
permissions = [],
|
permissions = [],
|
||||||
checkPermission = () => true,
|
checkPermission = () => true,
|
||||||
|
toolbarActions,
|
||||||
showIndex = true,
|
showIndex = true,
|
||||||
showSelection = true,
|
showSelection = true,
|
||||||
showActions = true,
|
showActions = true,
|
||||||
@@ -44,160 +53,8 @@ function EnhancedProTable<T extends BaseRecord, U extends ParamsType = any>(
|
|||||||
...restProps
|
...restProps
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const actionRef = useRef<ActionType>(null);
|
|
||||||
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
|
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
|
||||||
const [selectedRows, setSelectedRows] = useState<T[]>([]);
|
const [selectedRows, setSelectedRows] = useState<T[]>([]);
|
||||||
|
|
||||||
// 权限检查
|
|
||||||
const hasPermission = useCallback(
|
|
||||||
(permission?: string) => {
|
|
||||||
if (!permission) return true;
|
|
||||||
return checkPermission(permission);
|
|
||||||
},
|
|
||||||
[checkPermission]
|
|
||||||
);
|
|
||||||
|
|
||||||
// 过滤有权限的操作
|
|
||||||
const filteredActions = useMemo(() => {
|
|
||||||
return actions.filter((action) => hasPermission(action.permission));
|
|
||||||
}, [actions, hasPermission]);
|
|
||||||
|
|
||||||
const filteredToolbarActions = useMemo(() => {
|
|
||||||
return toolbarActions.filter((action) => hasPermission(action.permission));
|
|
||||||
}, [toolbarActions, hasPermission]);
|
|
||||||
|
|
||||||
// 构建操作列
|
|
||||||
const buildActionColumn = useCallback((): ProColumns<T> => {
|
|
||||||
if (!showActions || filteredActions.length === 0) {
|
|
||||||
return {} as ProColumns<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
title: "操作",
|
|
||||||
valueType: "option",
|
|
||||||
key: "actions",
|
|
||||||
fixed: "right",
|
|
||||||
width: Math.min(filteredActions.length * 60 + 50, 200),
|
|
||||||
render: (_, record, index, action) => {
|
|
||||||
// 过滤可见的操作
|
|
||||||
const visibleActions = filteredActions.filter(
|
|
||||||
(actionItem) => !actionItem.visible || actionItem.visible(record)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (visibleActions.length === 0) return null;
|
|
||||||
|
|
||||||
// 显示的操作按钮
|
|
||||||
const displayActions = visibleActions.slice(0, maxActionCount);
|
|
||||||
// 更多操作
|
|
||||||
const moreActions = visibleActions.slice(maxActionCount);
|
|
||||||
|
|
||||||
const actionElements: React.ReactNode[] = displayActions.map(
|
|
||||||
(actionItem) => (
|
|
||||||
<a
|
|
||||||
key={actionItem.key}
|
|
||||||
onClick={() => actionItem.onClick(record, action)}
|
|
||||||
style={{
|
|
||||||
color: actionItem.danger ? "#ff4d4f" : undefined,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{actionItem.icon} {actionItem.label}
|
|
||||||
</a>
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// 如果有更多操作,添加下拉菜单
|
|
||||||
if (moreActions.length > 0) {
|
|
||||||
const menuItems = buildTableDropdownMenuItems(
|
|
||||||
moreActions.map((actionItem) => ({
|
|
||||||
key: actionItem.key,
|
|
||||||
label: actionItem.label,
|
|
||||||
icon: actionItem.icon,
|
|
||||||
danger: actionItem.danger,
|
|
||||||
disabled: actionItem.disabled?.(record) || false,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
|
|
||||||
actionElements.push(
|
|
||||||
<TableDropdown
|
|
||||||
key="more"
|
|
||||||
onSelect={(key) => {
|
|
||||||
handleTableDropdownSelect(key, moreActions, record, action);
|
|
||||||
action?.reload();
|
|
||||||
}}
|
|
||||||
menus={menuItems}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 自定义操作渲染
|
|
||||||
if (customActionRender) {
|
|
||||||
return customActionRender(record, actionElements);
|
|
||||||
}
|
|
||||||
|
|
||||||
return actionElements;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}, [showActions, filteredActions, maxActionCount, customActionRender]);
|
|
||||||
|
|
||||||
// 构建列配置
|
|
||||||
const enhancedColumns = useMemo(() => {
|
|
||||||
const columns: ProColumns<T>[] = [];
|
|
||||||
|
|
||||||
// 添加序号列
|
|
||||||
if (showIndex) {
|
|
||||||
columns.push({
|
|
||||||
title: "序号",
|
|
||||||
dataIndex: "index",
|
|
||||||
valueType: "indexBorder",
|
|
||||||
width: 48,
|
|
||||||
fixed: "left",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加原始列
|
|
||||||
columns.push(...originalColumns);
|
|
||||||
|
|
||||||
// 添加操作列
|
|
||||||
const actionColumn = buildActionColumn();
|
|
||||||
if (actionColumn.title) {
|
|
||||||
columns.push(actionColumn);
|
|
||||||
}
|
|
||||||
|
|
||||||
return columns;
|
|
||||||
}, [originalColumns, showIndex, buildActionColumn]);
|
|
||||||
|
|
||||||
// 工具栏渲染
|
|
||||||
const toolBarRender = useCallback(() => {
|
|
||||||
const defaultActions = filteredToolbarActions.map((action) => (
|
|
||||||
<Button
|
|
||||||
key={action.key}
|
|
||||||
type={action.type}
|
|
||||||
danger={action.danger}
|
|
||||||
icon={action.icon}
|
|
||||||
disabled={
|
|
||||||
action.disabled ||
|
|
||||||
(action.needSelection && selectedRowKeys.length === 0)
|
|
||||||
}
|
|
||||||
onClick={() =>
|
|
||||||
action.onClick(selectedRowKeys as number[], selectedRows)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{action.label}
|
|
||||||
</Button>
|
|
||||||
));
|
|
||||||
|
|
||||||
if (customToolbarRender) {
|
|
||||||
return customToolbarRender(defaultActions);
|
|
||||||
}
|
|
||||||
|
|
||||||
return defaultActions;
|
|
||||||
}, [
|
|
||||||
filteredToolbarActions,
|
|
||||||
selectedRowKeys,
|
|
||||||
selectedRows,
|
|
||||||
customToolbarRender,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 行选择配置
|
// 行选择配置
|
||||||
const rowSelection = useMemo(() => {
|
const rowSelection = useMemo(() => {
|
||||||
if (!showSelection) return undefined;
|
if (!showSelection) return undefined;
|
||||||
@@ -233,45 +90,60 @@ function EnhancedProTable<T extends BaseRecord, U extends ParamsType = any>(
|
|||||||
[showSelection]
|
[showSelection]
|
||||||
);
|
);
|
||||||
|
|
||||||
// 表格提醒操作渲染
|
const toolBarRender = useCallback(
|
||||||
const tableAlertOptionRender = useCallback(() => {
|
(
|
||||||
if (!showSelection || selectedRowKeys.length === 0) return false;
|
action: ActionType | undefined,
|
||||||
|
rows: {
|
||||||
const batchActions = filteredToolbarActions.filter(
|
selectedRowKeys?: (string | number)[] | undefined;
|
||||||
(action) => action.needSelection
|
selectedRows?: T[] | undefined;
|
||||||
);
|
}
|
||||||
|
) => {
|
||||||
if (batchActions.length === 0) return false;
|
const toolbarElements =
|
||||||
|
toolbarActions?.map((action) => {
|
||||||
return (
|
return (
|
||||||
<Space size={16}>
|
<Button
|
||||||
{batchActions.map((action) => (
|
key={action.key}
|
||||||
<a
|
type={action.type}
|
||||||
key={action.key}
|
danger={action.danger}
|
||||||
onClick={() =>
|
disabled={action.disabled}
|
||||||
action.onClick(selectedRowKeys as number[], selectedRows)
|
icon={<PlusOutlined />}
|
||||||
}
|
onClick={() => action.onClick(selectedRowKeys, selectedRows)}
|
||||||
>
|
>
|
||||||
{action.label}
|
{action.label}
|
||||||
</a>
|
</Button>
|
||||||
))}
|
);
|
||||||
</Space>
|
}) || [];
|
||||||
);
|
// return [
|
||||||
}, [showSelection, selectedRowKeys, selectedRows, filteredToolbarActions]);
|
// <Button
|
||||||
|
// key="button"
|
||||||
|
// icon={<PlusOutlined />}
|
||||||
|
// onClick={}
|
||||||
|
// type="primary"
|
||||||
|
// >
|
||||||
|
// 新建
|
||||||
|
// </Button>,
|
||||||
|
// ];
|
||||||
|
return toolbarElements;
|
||||||
|
},
|
||||||
|
[toolbarActions]
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<ProTable<T, U>
|
<ProTable<T, U>
|
||||||
{...restProps}
|
{...restProps}
|
||||||
columns={enhancedColumns}
|
columns={columns}
|
||||||
actionRef={actionRef}
|
actionRef={ref}
|
||||||
request={request}
|
request={request}
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
rowSelection={rowSelection}
|
rowSelection={rowSelection}
|
||||||
toolBarRender={toolBarRender}
|
toolBarRender={toolBarRender}
|
||||||
|
manualRequest={false}
|
||||||
|
showSorterTooltip
|
||||||
tableAlertRender={tableAlertRender}
|
tableAlertRender={tableAlertRender}
|
||||||
tableAlertOptionRender={tableAlertOptionRender}
|
// tableAlertOptionRender={tableAlertOptionRender}
|
||||||
|
scroll={{ x: "max-content" }}
|
||||||
search={{
|
search={{
|
||||||
labelWidth: "auto",
|
labelWidth: "auto",
|
||||||
|
defaultCollapsed: false,
|
||||||
...restProps.search,
|
...restProps.search,
|
||||||
}}
|
}}
|
||||||
options={{
|
options={{
|
||||||
@@ -291,4 +163,9 @@ function EnhancedProTable<T extends BaseRecord, U extends ParamsType = any>(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default EnhancedProTable;
|
export default forwardRef(EnhancedProTable) as <
|
||||||
|
T extends BaseRecord,
|
||||||
|
U extends ParamsType = any
|
||||||
|
>(
|
||||||
|
props: EnhancedProTableProps<T, U> & { ref?: React.Ref<ActionType> }
|
||||||
|
) => React.ReactElement;
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export interface ToolbarAction {
|
|||||||
type?: ButtonProps["type"];
|
type?: ButtonProps["type"];
|
||||||
danger?: boolean;
|
danger?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
onClick: (selectedKeys: React.Key[], selectedRows: any[]) => void;
|
onClick: (selectedKeys?: React.Key[], selectedRows?: any[]) => void;
|
||||||
permission?: string;
|
permission?: string;
|
||||||
needSelection?: boolean;
|
needSelection?: boolean;
|
||||||
}
|
}
|
||||||
@@ -58,6 +58,7 @@ export interface EnhancedProTableProps<T extends BaseRecord, U = any>
|
|||||||
request?: (
|
request?: (
|
||||||
params: U & { current?: number; pageSize?: number }
|
params: U & { current?: number; pageSize?: number }
|
||||||
) => Promise<ApiResponse<T>>;
|
) => Promise<ApiResponse<T>>;
|
||||||
|
loading?: boolean; // 添加 loading 属性
|
||||||
actions?: TableAction<T>[];
|
actions?: TableAction<T>[];
|
||||||
toolbarActions?: ToolbarAction[];
|
toolbarActions?: ToolbarAction[];
|
||||||
permissions?: string[];
|
permissions?: string[];
|
||||||
|
|||||||
1
src/constants/index.ts
Normal file
1
src/constants/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export const formStatusType = { create: "创建", update: "编辑" };
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
// hooks/useEnhancedTable.ts
|
|
||||||
import { useRef, useState, useCallback } from "react";
|
|
||||||
import { ActionType } from "@ant-design/pro-components";
|
|
||||||
import { message } from "antd";
|
|
||||||
import {
|
|
||||||
UseEnhancedTableOptions,
|
|
||||||
UseEnhancedTableReturn,
|
|
||||||
} from "@/components/EnhancedProTable/types";
|
|
||||||
|
|
||||||
export function useEnhancedTable<T>(
|
|
||||||
options: UseEnhancedTableOptions<T> = {}
|
|
||||||
): UseEnhancedTableReturn<T> {
|
|
||||||
const actionRef = useRef<ActionType>(undefined);
|
|
||||||
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
|
|
||||||
const [selectedRows, setSelectedRows] = useState<T[]>([]);
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
|
|
||||||
const { onAdd, onEdit, onDelete, onView, onExport, onBatchDelete } = options;
|
|
||||||
|
|
||||||
// 刷新表格
|
|
||||||
const reload = useCallback(() => {
|
|
||||||
actionRef.current?.reload();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// 重置表格
|
|
||||||
const reset = useCallback(() => {
|
|
||||||
actionRef.current?.reset?.();
|
|
||||||
setSelectedRowKeys([]);
|
|
||||||
setSelectedRows([]);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// 清空选择
|
|
||||||
const clearSelection = useCallback(() => {
|
|
||||||
setSelectedRowKeys([]);
|
|
||||||
setSelectedRows([]);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// 处理删除
|
|
||||||
const handleDelete = useCallback(
|
|
||||||
async (record: T) => {
|
|
||||||
if (!onDelete) return;
|
|
||||||
|
|
||||||
setLoading(true);
|
|
||||||
try {
|
|
||||||
const success = await onDelete(record);
|
|
||||||
if (success) {
|
|
||||||
message.success("删除成功");
|
|
||||||
reload();
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[onDelete, reload]
|
|
||||||
);
|
|
||||||
|
|
||||||
// 处理批量删除
|
|
||||||
const handleBatchDelete = useCallback(
|
|
||||||
async (keys: React.Key[]) => {
|
|
||||||
if (!onBatchDelete || keys.length === 0) return;
|
|
||||||
|
|
||||||
setLoading(true);
|
|
||||||
try {
|
|
||||||
const success = await onBatchDelete(keys);
|
|
||||||
if (success) {
|
|
||||||
message.success("批量删除成功");
|
|
||||||
clearSelection();
|
|
||||||
reload();
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
message.error("批量删除失败");
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[onBatchDelete, clearSelection, reload]
|
|
||||||
);
|
|
||||||
|
|
||||||
// 处理导出
|
|
||||||
const handleExport = useCallback(
|
|
||||||
(rows: T[]) => {
|
|
||||||
if (!onExport) return;
|
|
||||||
if (rows.length === 0) {
|
|
||||||
message.warning("请选择要导出的数据");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
onExport(rows);
|
|
||||||
},
|
|
||||||
[onExport]
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
actionRef,
|
|
||||||
selectedRowKeys,
|
|
||||||
selectedRows,
|
|
||||||
loading,
|
|
||||||
setSelectedRowKeys,
|
|
||||||
setSelectedRows,
|
|
||||||
reload,
|
|
||||||
reset,
|
|
||||||
clearSelection,
|
|
||||||
handleDelete,
|
|
||||||
handleBatchDelete,
|
|
||||||
handleExport,
|
|
||||||
actions: {
|
|
||||||
add: onAdd,
|
|
||||||
edit: onEdit,
|
|
||||||
delete: handleDelete,
|
|
||||||
view: onView,
|
|
||||||
export: handleExport,
|
|
||||||
batchDelete: handleBatchDelete,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export type { UseEnhancedTableOptions, UseEnhancedTableReturn };
|
|
||||||
131
src/hooks/antd/useModal.ts
Normal file
131
src/hooks/antd/useModal.ts
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
import { App } from "antd";
|
||||||
|
import { useCallback } from "react";
|
||||||
|
|
||||||
|
export interface ConfirmOptions {
|
||||||
|
title: string;
|
||||||
|
content?: string;
|
||||||
|
okText?: string;
|
||||||
|
cancelText?: string;
|
||||||
|
onOk?: () => Promise<void> | void;
|
||||||
|
onCancel?: () => void;
|
||||||
|
type?: "confirm" | "info" | "success" | "error" | "warning";
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useModal = () => {
|
||||||
|
const { modal, message } = App.useApp();
|
||||||
|
|
||||||
|
// 通用确认对话框
|
||||||
|
const showConfirm = useCallback(
|
||||||
|
(options: ConfirmOptions) => {
|
||||||
|
const {
|
||||||
|
title,
|
||||||
|
content,
|
||||||
|
okText = "确定",
|
||||||
|
cancelText = "取消",
|
||||||
|
onOk,
|
||||||
|
onCancel,
|
||||||
|
type = "confirm",
|
||||||
|
} = options;
|
||||||
|
|
||||||
|
const modalMethod = modal[type];
|
||||||
|
|
||||||
|
return modalMethod({
|
||||||
|
title,
|
||||||
|
content,
|
||||||
|
okText,
|
||||||
|
cancelText,
|
||||||
|
onOk,
|
||||||
|
onCancel,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[modal]
|
||||||
|
);
|
||||||
|
|
||||||
|
// 删除确认对话框
|
||||||
|
const showDeleteConfirm = useCallback(
|
||||||
|
(
|
||||||
|
onConfirm: () => Promise<void> | void,
|
||||||
|
title: string = "删除确认",
|
||||||
|
content: string = "确定要删除吗?此操作不可恢复。"
|
||||||
|
) => {
|
||||||
|
return modal.confirm({
|
||||||
|
title,
|
||||||
|
content,
|
||||||
|
okText: "删除",
|
||||||
|
cancelText: "取消",
|
||||||
|
okType: "danger",
|
||||||
|
onOk: async () => {
|
||||||
|
try {
|
||||||
|
await onConfirm();
|
||||||
|
message.success("删除成功");
|
||||||
|
} catch (error) {
|
||||||
|
message.error("删除失败");
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[modal, message]
|
||||||
|
);
|
||||||
|
|
||||||
|
// 编辑确认对话框
|
||||||
|
const showEditConfirm = useCallback(
|
||||||
|
(
|
||||||
|
onConfirm: () => Promise<void> | void,
|
||||||
|
title: string = "编辑确认",
|
||||||
|
content: string = "确定要保存修改吗?"
|
||||||
|
) => {
|
||||||
|
return modal.confirm({
|
||||||
|
title,
|
||||||
|
content,
|
||||||
|
okText: "保存",
|
||||||
|
cancelText: "取消",
|
||||||
|
onOk: async () => {
|
||||||
|
try {
|
||||||
|
await onConfirm();
|
||||||
|
message.success("保存成功");
|
||||||
|
} catch (error) {
|
||||||
|
message.error("保存失败");
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[modal, message]
|
||||||
|
);
|
||||||
|
|
||||||
|
// 状态切换确认对话框
|
||||||
|
const showStatusConfirm = useCallback(
|
||||||
|
(
|
||||||
|
onConfirm: () => Promise<void> | void,
|
||||||
|
action: string,
|
||||||
|
itemName: string = "该项"
|
||||||
|
) => {
|
||||||
|
return modal.confirm({
|
||||||
|
title: `${action}确认`,
|
||||||
|
content: `确定要${action}${itemName}吗?`,
|
||||||
|
okText: action,
|
||||||
|
cancelText: "取消",
|
||||||
|
onOk: async () => {
|
||||||
|
try {
|
||||||
|
await onConfirm();
|
||||||
|
message.success(`${action}成功`);
|
||||||
|
} catch (error) {
|
||||||
|
message.error(`${action}失败`);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[modal, message]
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
modal,
|
||||||
|
message,
|
||||||
|
showConfirm,
|
||||||
|
showDeleteConfirm,
|
||||||
|
showEditConfirm,
|
||||||
|
showStatusConfirm,
|
||||||
|
};
|
||||||
|
};
|
||||||
51
src/hooks/antd/useRequest.ts
Normal file
51
src/hooks/antd/useRequest.ts
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
// hooks/useRequest.ts
|
||||||
|
import { useState, useCallback } from "react";
|
||||||
|
import { message } from "antd";
|
||||||
|
|
||||||
|
export interface UseRequestOptions<T> {
|
||||||
|
onSuccess?: (data: T) => void;
|
||||||
|
onError?: (error: any) => void;
|
||||||
|
showErrorMessage?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useRequest<T = any, P = any>(
|
||||||
|
requestFn: (params: P) => Promise<T>,
|
||||||
|
options: UseRequestOptions<T> = {}
|
||||||
|
) {
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [data, setData] = useState<T | null>(null);
|
||||||
|
const [error, setError] = useState<any>(null);
|
||||||
|
|
||||||
|
const { onSuccess, onError, showErrorMessage = true } = options;
|
||||||
|
|
||||||
|
const run = useCallback(
|
||||||
|
async (params: P) => {
|
||||||
|
setLoading(true);
|
||||||
|
setError(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await requestFn(params);
|
||||||
|
setData(result);
|
||||||
|
onSuccess?.(result);
|
||||||
|
return result;
|
||||||
|
} catch (err) {
|
||||||
|
setError(err);
|
||||||
|
onError?.(err);
|
||||||
|
if (showErrorMessage) {
|
||||||
|
message.error("请求失败");
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[requestFn, onSuccess, onError, showErrorMessage]
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
loading,
|
||||||
|
data,
|
||||||
|
error,
|
||||||
|
run,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,71 +1,71 @@
|
|||||||
export default {
|
export default {
|
||||||
'pages.layouts.userLayout.title':
|
"pages.layouts.userLayout.title":
|
||||||
'Ant Design 是西湖区最具影响力的 Web 设计规范',
|
"Ant Design 是西湖区最具影响力的 Web 设计规范",
|
||||||
'pages.login.accountLogin.tab': '账户密码登录',
|
"pages.login.accountLogin.tab": "账户密码登录",
|
||||||
'pages.login.accountLogin.errorMessage':
|
"pages.login.accountLogin.errorMessage":
|
||||||
'错误的用户名和密码(admin/ant.design)',
|
"错误的用户名和密码(admin/ant.design)",
|
||||||
'pages.login.failure': '登录失败,请重试!',
|
"pages.login.failure": "登录失败,请重试!",
|
||||||
'pages.login.success': '登录成功!',
|
"pages.login.success": "登录成功!",
|
||||||
'pages.login.username.placeholder': '用户名: admin or user',
|
"pages.login.username.placeholder": "用户名: admin or user",
|
||||||
'pages.login.username.required': '用户名是必填项!',
|
"pages.login.username.required": "用户名是必填项!",
|
||||||
'pages.login.password.placeholder': '密码: ant.design',
|
"pages.login.password.placeholder": "密码: ant.design",
|
||||||
'pages.login.password.required': '密码是必填项!',
|
"pages.login.password.required": "密码是必填项!",
|
||||||
'pages.login.phoneLogin.tab': '手机号登录',
|
"pages.login.phoneLogin.tab": "手机号登录",
|
||||||
'pages.login.phoneLogin.errorMessage': '验证码错误',
|
"pages.login.phoneLogin.errorMessage": "验证码错误",
|
||||||
'pages.login.phoneNumber.placeholder': '请输入手机号!',
|
"pages.login.phoneNumber.placeholder": "请输入手机号!",
|
||||||
'pages.login.phoneNumber.required': '手机号是必填项!',
|
"pages.login.phoneNumber.required": "手机号是必填项!",
|
||||||
'pages.login.phoneNumber.invalid': '不合法的手机号!',
|
"pages.login.phoneNumber.invalid": "不合法的手机号!",
|
||||||
'pages.login.captcha.placeholder': '请输入验证码!',
|
"pages.login.captcha.placeholder": "请输入验证码!",
|
||||||
'pages.login.captcha.required': '验证码是必填项!',
|
"pages.login.captcha.required": "验证码是必填项!",
|
||||||
'pages.login.phoneLogin.getVerificationCode': '获取验证码',
|
"pages.login.phoneLogin.getVerificationCode": "获取验证码",
|
||||||
'pages.getCaptchaSecondText': '秒后重新获取',
|
"pages.getCaptchaSecondText": "秒后重新获取",
|
||||||
'pages.login.rememberMe': '自动登录',
|
"pages.login.rememberMe": "自动登录",
|
||||||
'pages.login.forgotPassword': '忘记密码 ?',
|
"pages.login.forgotPassword": "忘记密码 ?",
|
||||||
'pages.login.submit': '登录',
|
"pages.login.submit": "登录",
|
||||||
'pages.login.loginWith': '其他登录方式 :',
|
"pages.login.loginWith": "其他登录方式 :",
|
||||||
'pages.login.registerAccount': '注册账户',
|
"pages.login.registerAccount": "注册账户",
|
||||||
'pages.welcome.link': '欢迎使用',
|
"pages.welcome.link": "欢迎使用",
|
||||||
'pages.welcome.alertMessage': '更快更强的重型组件,已经发布。',
|
"pages.welcome.alertMessage": "更快更强的重型组件,已经发布。",
|
||||||
'pages.404.subTitle': '抱歉,您访问的页面不存在。',
|
"pages.404.subTitle": "抱歉,您访问的页面不存在。",
|
||||||
'pages.404.buttonText': '返回首页',
|
"pages.404.buttonText": "返回首页",
|
||||||
'pages.admin.subPage.title': ' 这个页面只有 admin 权限才能查看',
|
"pages.admin.subPage.title": " 这个页面只有 admin 权限才能查看",
|
||||||
'pages.admin.subPage.alertMessage':
|
"pages.admin.subPage.alertMessage":
|
||||||
'umi ui 现已发布,欢迎使用 npm run ui 启动体验。',
|
"umi ui 现已发布,欢迎使用 npm run ui 启动体验。",
|
||||||
'pages.searchTable.createForm.newRule': '新建规则',
|
"pages.searchTable.createForm.newRule": "新建规则",
|
||||||
'pages.searchTable.updateForm.ruleConfig': '规则配置',
|
"pages.searchTable.updateForm.ruleConfig": "规则配置",
|
||||||
'pages.searchTable.updateForm.basicConfig': '基本信息',
|
"pages.searchTable.updateForm.basicConfig": "基本信息",
|
||||||
'pages.searchTable.updateForm.ruleName.nameLabel': '规则名称',
|
"pages.searchTable.updateForm.ruleName.nameLabel": "规则名称",
|
||||||
'pages.searchTable.updateForm.ruleName.nameRules': '请输入规则名称!',
|
"pages.searchTable.updateForm.ruleName.nameRules": "请输入规则名称!",
|
||||||
'pages.searchTable.updateForm.ruleDesc.descLabel': '规则描述',
|
"pages.searchTable.updateForm.ruleDesc.descLabel": "规则描述",
|
||||||
'pages.searchTable.updateForm.ruleDesc.descPlaceholder': '请输入至少五个字符',
|
"pages.searchTable.updateForm.ruleDesc.descPlaceholder": "请输入至少五个字符",
|
||||||
'pages.searchTable.updateForm.ruleDesc.descRules':
|
"pages.searchTable.updateForm.ruleDesc.descRules":
|
||||||
'请输入至少五个字符的规则描述!',
|
"请输入至少五个字符的规则描述!",
|
||||||
'pages.searchTable.updateForm.ruleProps.title': '配置规则属性',
|
"pages.searchTable.updateForm.ruleProps.title": "配置规则属性",
|
||||||
'pages.searchTable.updateForm.object': '监控对象',
|
"pages.searchTable.updateForm.object": "监控对象",
|
||||||
'pages.searchTable.updateForm.ruleProps.templateLabel': '规则模板',
|
"pages.searchTable.updateForm.ruleProps.templateLabel": "规则模板",
|
||||||
'pages.searchTable.updateForm.ruleProps.typeLabel': '规则类型',
|
"pages.searchTable.updateForm.ruleProps.typeLabel": "规则类型",
|
||||||
'pages.searchTable.updateForm.schedulingPeriod.title': '设定调度周期',
|
"pages.searchTable.updateForm.schedulingPeriod.title": "设定调度周期",
|
||||||
'pages.searchTable.updateForm.schedulingPeriod.timeLabel': '开始时间',
|
"pages.searchTable.updateForm.schedulingPeriod.timeLabel": "开始时间",
|
||||||
'pages.searchTable.updateForm.schedulingPeriod.timeRules': '请选择开始时间!',
|
"pages.searchTable.updateForm.schedulingPeriod.timeRules": "请选择开始时间!",
|
||||||
'pages.searchTable.titleDesc': '描述',
|
"pages.searchTable.titleDesc": "描述",
|
||||||
'pages.searchTable.ruleName': '规则名称为必填项',
|
"pages.searchTable.ruleName": "规则名称为必填项",
|
||||||
'pages.searchTable.titleCallNo': '服务调用次数',
|
"pages.searchTable.titleCallNo": "服务调用次数",
|
||||||
'pages.searchTable.titleStatus': '状态',
|
"pages.searchTable.titleStatus": "状态",
|
||||||
'pages.searchTable.nameStatus.default': '关闭',
|
"pages.searchTable.nameStatus.default": "关闭",
|
||||||
'pages.searchTable.nameStatus.running': '运行中',
|
"pages.searchTable.nameStatus.running": "运行中",
|
||||||
'pages.searchTable.nameStatus.online': '已上线',
|
"pages.searchTable.nameStatus.online": "已上线",
|
||||||
'pages.searchTable.nameStatus.abnormal': '异常',
|
"pages.searchTable.nameStatus.abnormal": "异常",
|
||||||
'pages.searchTable.titleUpdatedAt': '上次调度时间',
|
"pages.searchTable.titleUpdatedAt": "上次调度时间",
|
||||||
'pages.searchTable.exception': '请输入异常原因!',
|
"pages.searchTable.exception": "请输入异常原因!",
|
||||||
'pages.searchTable.titleOption': '操作',
|
"pages.searchTable.titleOption": "操作",
|
||||||
'pages.searchTable.config': '配置',
|
"pages.searchTable.config": "配置",
|
||||||
'pages.searchTable.subscribeAlert': '订阅警报',
|
"pages.searchTable.subscribeAlert": "订阅警报",
|
||||||
'pages.searchTable.title': '查询表格',
|
"pages.searchTable.title": "查询表格",
|
||||||
'pages.searchTable.new': '新建',
|
"pages.searchTable.new": "新增",
|
||||||
'pages.searchTable.chosen': '已选择',
|
"pages.searchTable.chosen": "已选择",
|
||||||
'pages.searchTable.item': '项',
|
"pages.searchTable.item": "项",
|
||||||
'pages.searchTable.totalServiceCalls': '服务调用次数总计',
|
"pages.searchTable.totalServiceCalls": "服务调用次数总计",
|
||||||
'pages.searchTable.tenThousand': '万',
|
"pages.searchTable.tenThousand": "万",
|
||||||
'pages.searchTable.batchDeletion': '批量删除',
|
"pages.searchTable.batchDeletion": "批量删除",
|
||||||
'pages.searchTable.batchApproval': '批量审批',
|
"pages.searchTable.batchApproval": "批量审批",
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,71 +1,71 @@
|
|||||||
export default {
|
export default {
|
||||||
'pages.layouts.userLayout.title':
|
"pages.layouts.userLayout.title":
|
||||||
'Ant Design 是西湖區最具影響力的 Web 設計規範',
|
"Ant Design 是西湖區最具影響力的 Web 設計規範",
|
||||||
'pages.login.accountLogin.tab': '賬戶密碼登錄',
|
"pages.login.accountLogin.tab": "賬戶密碼登錄",
|
||||||
'pages.login.accountLogin.errorMessage':
|
"pages.login.accountLogin.errorMessage":
|
||||||
'錯誤的用戶名和密碼(admin/ant.design)',
|
"錯誤的用戶名和密碼(admin/ant.design)",
|
||||||
'pages.login.failure': '登錄失敗,請重試!',
|
"pages.login.failure": "登錄失敗,請重試!",
|
||||||
'pages.login.success': '登錄成功!',
|
"pages.login.success": "登錄成功!",
|
||||||
'pages.login.username.placeholder': '用戶名: admin or user',
|
"pages.login.username.placeholder": "用戶名: admin or user",
|
||||||
'pages.login.username.required': '用戶名是必填項!',
|
"pages.login.username.required": "用戶名是必填項!",
|
||||||
'pages.login.password.placeholder': '密碼: ant.design',
|
"pages.login.password.placeholder": "密碼: ant.design",
|
||||||
'pages.login.password.required': '密碼是必填項!',
|
"pages.login.password.required": "密碼是必填項!",
|
||||||
'pages.login.phoneLogin.tab': '手機號登錄',
|
"pages.login.phoneLogin.tab": "手機號登錄",
|
||||||
'pages.login.phoneLogin.errorMessage': '驗證碼錯誤',
|
"pages.login.phoneLogin.errorMessage": "驗證碼錯誤",
|
||||||
'pages.login.phoneNumber.placeholder': '請輸入手機號!',
|
"pages.login.phoneNumber.placeholder": "請輸入手機號!",
|
||||||
'pages.login.phoneNumber.required': '手機號是必填項!',
|
"pages.login.phoneNumber.required": "手機號是必填項!",
|
||||||
'pages.login.phoneNumber.invalid': '不合法的手機號!',
|
"pages.login.phoneNumber.invalid": "不合法的手機號!",
|
||||||
'pages.login.captcha.placeholder': '請輸入驗證碼!',
|
"pages.login.captcha.placeholder": "請輸入驗證碼!",
|
||||||
'pages.login.captcha.required': '驗證碼是必填項!',
|
"pages.login.captcha.required": "驗證碼是必填項!",
|
||||||
'pages.login.phoneLogin.getVerificationCode': '獲取驗證碼',
|
"pages.login.phoneLogin.getVerificationCode": "獲取驗證碼",
|
||||||
'pages.getCaptchaSecondText': '秒後重新獲取',
|
"pages.getCaptchaSecondText": "秒後重新獲取",
|
||||||
'pages.login.rememberMe': '自動登錄',
|
"pages.login.rememberMe": "自動登錄",
|
||||||
'pages.login.forgotPassword': '忘記密碼 ?',
|
"pages.login.forgotPassword": "忘記密碼 ?",
|
||||||
'pages.login.submit': '登錄',
|
"pages.login.submit": "登錄",
|
||||||
'pages.login.loginWith': '其他登錄方式 :',
|
"pages.login.loginWith": "其他登錄方式 :",
|
||||||
'pages.login.registerAccount': '註冊賬戶',
|
"pages.login.registerAccount": "註冊賬戶",
|
||||||
'pages.welcome.link': '歡迎使用',
|
"pages.welcome.link": "歡迎使用",
|
||||||
'pages.welcome.alertMessage': '更快更強的重型組件,已經發布。',
|
"pages.welcome.alertMessage": "更快更強的重型組件,已經發布。",
|
||||||
'pages.404.subTitle': '抱歉,您訪問的頁面不存在。',
|
"pages.404.subTitle": "抱歉,您訪問的頁面不存在。",
|
||||||
'pages.404.buttonText': '返回首頁',
|
"pages.404.buttonText": "返回首頁",
|
||||||
'pages.admin.subPage.title': '這個頁面只有 admin 權限才能查看',
|
"pages.admin.subPage.title": "這個頁面只有 admin 權限才能查看",
|
||||||
'pages.admin.subPage.alertMessage':
|
"pages.admin.subPage.alertMessage":
|
||||||
'umi ui 現已發佈,歡迎使用 npm run ui 啓動體驗。',
|
"umi ui 現已發佈,歡迎使用 npm run ui 啓動體驗。",
|
||||||
'pages.searchTable.createForm.newRule': '新建規則',
|
"pages.searchTable.createForm.newRule": "新建規則",
|
||||||
'pages.searchTable.updateForm.ruleConfig': '規則配置',
|
"pages.searchTable.updateForm.ruleConfig": "規則配置",
|
||||||
'pages.searchTable.updateForm.basicConfig': '基本信息',
|
"pages.searchTable.updateForm.basicConfig": "基本信息",
|
||||||
'pages.searchTable.updateForm.ruleName.nameLabel': '規則名稱',
|
"pages.searchTable.updateForm.ruleName.nameLabel": "規則名稱",
|
||||||
'pages.searchTable.updateForm.ruleName.nameRules': '請輸入規則名稱!',
|
"pages.searchTable.updateForm.ruleName.nameRules": "請輸入規則名稱!",
|
||||||
'pages.searchTable.updateForm.ruleDesc.descLabel': '規則描述',
|
"pages.searchTable.updateForm.ruleDesc.descLabel": "規則描述",
|
||||||
'pages.searchTable.updateForm.ruleDesc.descPlaceholder': '請輸入至少五個字符',
|
"pages.searchTable.updateForm.ruleDesc.descPlaceholder": "請輸入至少五個字符",
|
||||||
'pages.searchTable.updateForm.ruleDesc.descRules':
|
"pages.searchTable.updateForm.ruleDesc.descRules":
|
||||||
'請輸入至少五個字符的規則描述!',
|
"請輸入至少五個字符的規則描述!",
|
||||||
'pages.searchTable.updateForm.ruleProps.title': '配置規則屬性',
|
"pages.searchTable.updateForm.ruleProps.title": "配置規則屬性",
|
||||||
'pages.searchTable.updateForm.object': '監控對象',
|
"pages.searchTable.updateForm.object": "監控對象",
|
||||||
'pages.searchTable.updateForm.ruleProps.templateLabel': '規則模板',
|
"pages.searchTable.updateForm.ruleProps.templateLabel": "規則模板",
|
||||||
'pages.searchTable.updateForm.ruleProps.typeLabel': '規則類型',
|
"pages.searchTable.updateForm.ruleProps.typeLabel": "規則類型",
|
||||||
'pages.searchTable.updateForm.schedulingPeriod.title': '設定調度週期',
|
"pages.searchTable.updateForm.schedulingPeriod.title": "設定調度週期",
|
||||||
'pages.searchTable.updateForm.schedulingPeriod.timeLabel': '開始時間',
|
"pages.searchTable.updateForm.schedulingPeriod.timeLabel": "開始時間",
|
||||||
'pages.searchTable.updateForm.schedulingPeriod.timeRules': '請選擇開始時間!',
|
"pages.searchTable.updateForm.schedulingPeriod.timeRules": "請選擇開始時間!",
|
||||||
'pages.searchTable.titleDesc': '描述',
|
"pages.searchTable.titleDesc": "描述",
|
||||||
'pages.searchTable.ruleName': '規則名稱爲必填項',
|
"pages.searchTable.ruleName": "規則名稱爲必填項",
|
||||||
'pages.searchTable.titleCallNo': '服務調用次數',
|
"pages.searchTable.titleCallNo": "服務調用次數",
|
||||||
'pages.searchTable.titleStatus': '狀態',
|
"pages.searchTable.titleStatus": "狀態",
|
||||||
'pages.searchTable.nameStatus.default': '關閉',
|
"pages.searchTable.nameStatus.default": "關閉",
|
||||||
'pages.searchTable.nameStatus.running': '運行中',
|
"pages.searchTable.nameStatus.running": "運行中",
|
||||||
'pages.searchTable.nameStatus.online': '已上線',
|
"pages.searchTable.nameStatus.online": "已上線",
|
||||||
'pages.searchTable.nameStatus.abnormal': '異常',
|
"pages.searchTable.nameStatus.abnormal": "異常",
|
||||||
'pages.searchTable.titleUpdatedAt': '上次調度時間',
|
"pages.searchTable.titleUpdatedAt": "上次調度時間",
|
||||||
'pages.searchTable.exception': '請輸入異常原因!',
|
"pages.searchTable.exception": "請輸入異常原因!",
|
||||||
'pages.searchTable.titleOption': '操作',
|
"pages.searchTable.titleOption": "操作",
|
||||||
'pages.searchTable.config': '配置',
|
"pages.searchTable.config": "配置",
|
||||||
'pages.searchTable.subscribeAlert': '訂閱警報',
|
"pages.searchTable.subscribeAlert": "訂閱警報",
|
||||||
'pages.searchTable.title': '查詢表格',
|
"pages.searchTable.title": "查詢表格",
|
||||||
'pages.searchTable.new': '新建',
|
"pages.searchTable.new": "新增",
|
||||||
'pages.searchTable.chosen': '已選擇',
|
"pages.searchTable.chosen": "已選擇",
|
||||||
'pages.searchTable.item': '項',
|
"pages.searchTable.item": "項",
|
||||||
'pages.searchTable.totalServiceCalls': '服務調用次數總計',
|
"pages.searchTable.totalServiceCalls": "服務調用次數總計",
|
||||||
'pages.searchTable.tenThousand': '萬',
|
"pages.searchTable.tenThousand": "萬",
|
||||||
'pages.searchTable.batchDeletion': '批量刪除',
|
"pages.searchTable.batchDeletion": "批量刪除",
|
||||||
'pages.searchTable.batchApproval': '批量審批',
|
"pages.searchTable.batchApproval": "批量審批",
|
||||||
};
|
};
|
||||||
|
|||||||
5
src/pages/system/dept/index.tsx
Normal file
5
src/pages/system/dept/index.tsx
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
const SyStemDept = () => {
|
||||||
|
return <>SyStemDept</>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SyStemDept;
|
||||||
5
src/pages/system/dict/index.tsx
Normal file
5
src/pages/system/dict/index.tsx
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
const SyStemDict = () => {
|
||||||
|
return <>SyStemDict</>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SyStemDict;
|
||||||
5
src/pages/system/log/login/index.tsx
Normal file
5
src/pages/system/log/login/index.tsx
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
const SyStemLogLogin = () => {
|
||||||
|
return <>SyStemLogLogin</>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SyStemLogLogin;
|
||||||
5
src/pages/system/log/operate/index.tsx
Normal file
5
src/pages/system/log/operate/index.tsx
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
const SyStemLogOperate = () => {
|
||||||
|
return <>SyStemLogOperate</>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SyStemLogOperate;
|
||||||
5
src/pages/system/menu/index.tsx
Normal file
5
src/pages/system/menu/index.tsx
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
const SyStemMenu = () => {
|
||||||
|
return <>SyStemMenu</>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SyStemMenu;
|
||||||
5
src/pages/system/post/index.tsx
Normal file
5
src/pages/system/post/index.tsx
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
const SyStemPost = () => {
|
||||||
|
return <>SyStemPost</>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SyStemPost;
|
||||||
5
src/pages/system/role/index.tsx
Normal file
5
src/pages/system/role/index.tsx
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
const SyStemRole = () => {
|
||||||
|
return <>SyStemRole</>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SyStemRole;
|
||||||
223
src/pages/system/tenant/list/config.tsx
Normal file
223
src/pages/system/tenant/list/config.tsx
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
import { type TenantVO, deleteTenant } from "@/services/system/tenant/list";
|
||||||
|
import { ProColumns } from "@ant-design/pro-components";
|
||||||
|
import { DatePicker, Modal, Popconfirm } from "antd";
|
||||||
|
import { FormInstance } from "antd/lib";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
|
export const baseTenantColumns: ProColumns<TenantVO>[] = [
|
||||||
|
{
|
||||||
|
title: "租户编号",
|
||||||
|
dataIndex: "id",
|
||||||
|
tip: "租户编号",
|
||||||
|
width: 100,
|
||||||
|
hideInSearch: true, // 在搜索表单中隐藏
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "租户名",
|
||||||
|
dataIndex: "name",
|
||||||
|
tip: "租户名", // 提示信息
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "租户套餐",
|
||||||
|
dataIndex: "packageId",
|
||||||
|
valueType: "select",
|
||||||
|
request: async () => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: "默认套餐",
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
},
|
||||||
|
// valueEnum: {
|
||||||
|
// all: { text: "全部", status: "Default" },
|
||||||
|
// open: { text: "未解决", status: "Error" },
|
||||||
|
// closed: { text: "已解决", status: "Success" },
|
||||||
|
// },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "联系人",
|
||||||
|
dataIndex: "contactName",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "联系手机",
|
||||||
|
dataIndex: "contactMobile",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "账号额度",
|
||||||
|
dataIndex: "accountCount",
|
||||||
|
hideInSearch: true, // 在搜索表单中隐藏
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "过期时间",
|
||||||
|
dataIndex: "expireTime",
|
||||||
|
valueType: "dateTime",
|
||||||
|
|
||||||
|
hideInSearch: true, // 在搜索表单中隐藏
|
||||||
|
},
|
||||||
|
{ title: "绑定域名", dataIndex: "website", width: 100 },
|
||||||
|
{
|
||||||
|
title: "租户状态",
|
||||||
|
dataIndex: "status",
|
||||||
|
valueType: "select",
|
||||||
|
valueEnum: {
|
||||||
|
all: { text: "全部", status: "Default" },
|
||||||
|
open: { text: "未解决", status: "Error" },
|
||||||
|
closed: { text: "已解决", status: "Success" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "创建时间",
|
||||||
|
dataIndex: "createTime",
|
||||||
|
valueType: "dateRange",
|
||||||
|
search: {
|
||||||
|
transform: (value) => {
|
||||||
|
return [`${value[0]} 00:00:00`, `${value[1]} 00:00:00`];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
render: (_, record: TenantVO) =>
|
||||||
|
dayjs(record.createTime).format("YYYY-MM-DD HH:mm:ss"),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const formColumns: any = [
|
||||||
|
{
|
||||||
|
title: "租户名",
|
||||||
|
dataIndex: "name",
|
||||||
|
tip: "租户名", // 提示信息
|
||||||
|
formItemProps: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: "请输入用户名",
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// min: 2,
|
||||||
|
// max: 20,
|
||||||
|
// message: "用户名长度为2-20个字符",
|
||||||
|
// },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "租户套餐",
|
||||||
|
dataIndex: "packageId",
|
||||||
|
valueType: "select",
|
||||||
|
formItemProps: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: "请选择租户套餐",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
fieldProps: {
|
||||||
|
placeholder: "请选择套餐类型",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: "普通套餐",
|
||||||
|
value: 111,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "联系人",
|
||||||
|
dataIndex: "contactName",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "联系手机",
|
||||||
|
dataIndex: "contactMobile",
|
||||||
|
formItemProps: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: "请输入联系手机",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "用户名称",
|
||||||
|
dataIndex: "username",
|
||||||
|
hideInForm: true,
|
||||||
|
formItemProps: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: "请输入用户名称",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: /^[a-zA-Z0-9]+$/,
|
||||||
|
message: "用户账号由 0-9、a-z、A-Z 组成",
|
||||||
|
},
|
||||||
|
// 用户账号由 数字、字母组成
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "用户密码",
|
||||||
|
dataIndex: "password",
|
||||||
|
valueType: "password",
|
||||||
|
hideInForm: true,
|
||||||
|
fieldProps: {
|
||||||
|
placeholder: "请输入用户密码",
|
||||||
|
autoComplete: "new-password",
|
||||||
|
},
|
||||||
|
formItemProps: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: "请输入用户密码",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
min: 4,
|
||||||
|
max: 16,
|
||||||
|
message: "密码长度为4-16个字符",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "账号额度",
|
||||||
|
dataIndex: "accountCount",
|
||||||
|
valueType: "digit",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "过期时间",
|
||||||
|
dataIndex: "expireTime",
|
||||||
|
valueType: "date",
|
||||||
|
|
||||||
|
fieldProps: {
|
||||||
|
placeholder: "请选择过期时间",
|
||||||
|
format: "YYYY-MM-DD",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ title: "绑定域名", dataIndex: "website" },
|
||||||
|
{
|
||||||
|
title: "租户状态",
|
||||||
|
dataIndex: "status",
|
||||||
|
valueType: "radio",
|
||||||
|
formItemProps: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: "请选择租户状态",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
fieldProps: {
|
||||||
|
placeholder: "请选择套餐类型",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: "启用",
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "禁用",
|
||||||
|
value: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -1,68 +1,49 @@
|
|||||||
import EnhancedProTable from "@/components/EnhancedProTable";
|
import EnhancedProTable from "@/components/EnhancedProTable";
|
||||||
import {
|
import {
|
||||||
getTenantPage,
|
getTenantPage,
|
||||||
deleteTenant,
|
createTenant,
|
||||||
type TenantPageReqVO,
|
type TenantPageReqVO,
|
||||||
type TenantVO,
|
type TenantVO,
|
||||||
|
deleteTenant,
|
||||||
|
updateTenant,
|
||||||
} from "@/services/system/tenant/list";
|
} from "@/services/system/tenant/list";
|
||||||
|
import React, { createContext, useCallback } from "react";
|
||||||
|
import ConfigurableDrawerForm, {
|
||||||
|
ConfigurableDrawerFormRef,
|
||||||
|
} from "@/components/DrawerForm";
|
||||||
|
import { useRef, useState } from "react";
|
||||||
|
import { formColumns, baseTenantColumns } from "./config";
|
||||||
import { PlusOutlined } from "@ant-design/icons";
|
import { PlusOutlined } from "@ant-design/icons";
|
||||||
import {
|
import { ref } from "process";
|
||||||
ProCoreActionType,
|
import { ActionType, ProColumns } from "@ant-design/pro-components";
|
||||||
ProTable,
|
import { ToolbarAction } from "@/components/EnhancedProTable/types";
|
||||||
TableDropdown,
|
import { Modal, Popconfirm } from "antd";
|
||||||
type ProColumns,
|
import { formStatusType } from "@/constants";
|
||||||
} from "@ant-design/pro-components";
|
import dayjs from "dayjs";
|
||||||
import { Button, Space } from "antd";
|
export const waitTimePromise = async (time: number = 90) => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
import {
|
setTimeout(() => {
|
||||||
createOrderTableConfig,
|
resolve(true);
|
||||||
createCommonActions,
|
}, time);
|
||||||
createCommonToolbarActions,
|
});
|
||||||
} from "@/utils/antd/tableConfigFactory";
|
};
|
||||||
import { useEnhancedTable } from "@/hooks/antd/useEnhancedTable";
|
|
||||||
const TenantList = () => {
|
const TenantList = () => {
|
||||||
const columns: ProColumns<TenantVO>[] = [
|
const configurableDrawerRef = useRef<ConfigurableDrawerFormRef>(null);
|
||||||
{
|
const tableRef = useRef<ActionType>(null);
|
||||||
title: "租户编号",
|
const [type, setType] = useState<"create" | "update">("create");
|
||||||
dataIndex: "id",
|
const [id, setId] = useState<number>(0);
|
||||||
tip: "租户编号",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "租户名",
|
|
||||||
dataIndex: "name",
|
|
||||||
|
|
||||||
ellipsis: true, // 超长省略
|
|
||||||
tip: "租户名", // 提示信息
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "状态",
|
|
||||||
dataIndex: "status",
|
|
||||||
valueType: "select",
|
|
||||||
valueEnum: {
|
|
||||||
all: { text: "全部", status: "Default" },
|
|
||||||
open: { text: "未解决", status: "Error" },
|
|
||||||
closed: { text: "已解决", status: "Success" },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "创建时间",
|
|
||||||
dataIndex: "created_at",
|
|
||||||
valueType: "dateTime",
|
|
||||||
hideInSearch: true, // 在搜索表单中隐藏
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const onFetch = async (
|
const onFetch = async (
|
||||||
params: TenantPageReqVO & {
|
params: TenantPageReqVO & {
|
||||||
pageSize?: number;
|
pageSize?: number;
|
||||||
current?: number;
|
current?: number;
|
||||||
}
|
}
|
||||||
) => {
|
) => {
|
||||||
|
await waitTimePromise();
|
||||||
const data = await getTenantPage({
|
const data = await getTenantPage({
|
||||||
|
...params,
|
||||||
pageNo: params.current,
|
pageNo: params.current,
|
||||||
pageSize: params.pageSize,
|
pageSize: params.pageSize,
|
||||||
});
|
});
|
||||||
console.log(data);
|
|
||||||
return {
|
return {
|
||||||
data: data.list,
|
data: data.list,
|
||||||
success: true,
|
success: true,
|
||||||
@@ -70,39 +51,89 @@ const TenantList = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const { actionRef, selectedRowKeys, selectedRows, actions } =
|
const handleSubmit = useCallback(
|
||||||
useEnhancedTable<TenantVO>({
|
async (values: TenantVO) => {
|
||||||
onEdit: (record) => {
|
if (type === "create") {
|
||||||
console.log("编辑订单:", record);
|
await createTenant(values);
|
||||||
},
|
} else {
|
||||||
onDelete: async (record) => {
|
await updateTenant({
|
||||||
await deleteTenant(record.id);
|
...values,
|
||||||
return true;
|
id,
|
||||||
},
|
expireTime: dayjs(values.expireTime).valueOf(),
|
||||||
});
|
});
|
||||||
const tableActions = createCommonActions<TenantVO>({
|
}
|
||||||
onView: actions.view,
|
tableRef.current?.reload();
|
||||||
onEdit: actions.edit,
|
return true;
|
||||||
onDelete: actions.delete,
|
},
|
||||||
});
|
[type]
|
||||||
|
);
|
||||||
|
|
||||||
const toolbarActions = createCommonToolbarActions({
|
const handleAdd = () => {
|
||||||
onExport: actions.export,
|
setType("create");
|
||||||
});
|
configurableDrawerRef.current?.open({});
|
||||||
|
};
|
||||||
|
const handleEdit = (record: TenantVO) => {
|
||||||
|
setType("update");
|
||||||
|
setId(record.id);
|
||||||
|
|
||||||
|
configurableDrawerRef.current?.open(record);
|
||||||
|
};
|
||||||
|
const toolbarActions: ToolbarAction[] = [
|
||||||
|
{
|
||||||
|
key: "add",
|
||||||
|
label: "新建",
|
||||||
|
type: "primary",
|
||||||
|
icon: <PlusOutlined />,
|
||||||
|
onClick: handleAdd,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const actionColumns: ProColumns<TenantVO> = {
|
||||||
|
title: "操作",
|
||||||
|
dataIndex: "option",
|
||||||
|
valueType: "option",
|
||||||
|
fixed: "right",
|
||||||
|
width: 120,
|
||||||
|
render: (text: React.ReactNode, record: TenantVO, _: any, action: any) => [
|
||||||
|
<a key="editable" onClick={() => handleEdit(record)}>
|
||||||
|
编辑
|
||||||
|
</a>,
|
||||||
|
<Popconfirm
|
||||||
|
title="是否删除?"
|
||||||
|
key="delete"
|
||||||
|
onConfirm={async () => {
|
||||||
|
await deleteTenant(record.id);
|
||||||
|
action?.reload();
|
||||||
|
}}
|
||||||
|
okText="是"
|
||||||
|
cancelText="否"
|
||||||
|
>
|
||||||
|
<a>删除</a>
|
||||||
|
</Popconfirm>,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const columns = [...baseTenantColumns, actionColumns];
|
||||||
return (
|
return (
|
||||||
<div>
|
<>
|
||||||
<EnhancedProTable<TenantVO>
|
<EnhancedProTable<TenantVO>
|
||||||
|
ref={tableRef}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
request={onFetch}
|
request={onFetch}
|
||||||
actions={tableActions}
|
|
||||||
toolbarActions={toolbarActions}
|
toolbarActions={toolbarActions}
|
||||||
headerTitle="订单管理"
|
headerTitle="租户列表"
|
||||||
showIndex={false}
|
showIndex={false}
|
||||||
// showSelection
|
showSelection={false}
|
||||||
showActions
|
showActions
|
||||||
maxActionCount={3}
|
maxActionCount={3}
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
|
<ConfigurableDrawerForm
|
||||||
|
ref={configurableDrawerRef}
|
||||||
|
title={formStatusType[type]}
|
||||||
|
columns={formColumns}
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
5
src/pages/system/user/index.tsx
Normal file
5
src/pages/system/user/index.tsx
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
const SyStemUser = () => {
|
||||||
|
return <>SyStemUser</>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SyStemUser;
|
||||||
@@ -137,6 +137,7 @@ export const errorConfig: RequestConfig = {
|
|||||||
setToken(refreshTokenRes);
|
setToken(refreshTokenRes);
|
||||||
console.log(getAccessToken());
|
console.log(getAccessToken());
|
||||||
config.headers!.Authorization = "Bearer " + getAccessToken();
|
config.headers!.Authorization = "Bearer " + getAccessToken();
|
||||||
|
console.log(requestList);
|
||||||
requestList.forEach((cb: any) => {
|
requestList.forEach((cb: any) => {
|
||||||
cb();
|
cb();
|
||||||
});
|
});
|
||||||
@@ -154,6 +155,7 @@ export const errorConfig: RequestConfig = {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
console.log("刷新令牌失败");
|
||||||
//添加到队列,等待刷新获取到新的令牌
|
//添加到队列,等待刷新获取到新的令牌
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
requestList.push(() => {
|
requestList.push(() => {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export interface TenantVO {
|
|||||||
packageId: number;
|
packageId: number;
|
||||||
username: string;
|
username: string;
|
||||||
password: string;
|
password: string;
|
||||||
expireTime: Date;
|
expireTime: Date | number;
|
||||||
accountCount: number;
|
accountCount: number;
|
||||||
createTime: Date;
|
createTime: Date;
|
||||||
}
|
}
|
||||||
|
|||||||
43
src/utils/antd/commonRules.ts
Normal file
43
src/utils/antd/commonRules.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// 常用的校验规则配置
|
||||||
|
// rules: [
|
||||||
|
// { required: true, message: '请输入用户名' },
|
||||||
|
// { min: 3, max: 20, message: '用户名长度为3-20个字符' },
|
||||||
|
// { pattern: /^[a-zA-Z0-9_]+$/, message: '用户名只能包含字母、数字和下划线' },
|
||||||
|
// ],
|
||||||
|
const commonRules = {
|
||||||
|
// 必填
|
||||||
|
required: { required: true, message: "此项为必填项" },
|
||||||
|
|
||||||
|
// 邮箱
|
||||||
|
email: { type: "email", message: "请输入正确的邮箱格式" },
|
||||||
|
|
||||||
|
// 手机号
|
||||||
|
phone: { pattern: /^1[3-9]\d{9}$/, message: "请输入正确的手机号格式" },
|
||||||
|
|
||||||
|
// 身份证
|
||||||
|
idCard: {
|
||||||
|
pattern: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/,
|
||||||
|
message: "请输入正确的身份证号",
|
||||||
|
},
|
||||||
|
|
||||||
|
// 密码强度
|
||||||
|
strongPassword: {
|
||||||
|
pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d@$!%*?&]{8,}$/,
|
||||||
|
message: "密码必须包含大小写字母、数字,至少8位",
|
||||||
|
},
|
||||||
|
|
||||||
|
// 数字范围
|
||||||
|
numberRange: (min: number, max: number) => ({
|
||||||
|
type: "number",
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
message: `请输入${min}-${max}之间的数字`,
|
||||||
|
}),
|
||||||
|
|
||||||
|
// 字符长度
|
||||||
|
lengthRange: (min: number, max: number) => ({
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
message: `长度为${min}-${max}个字符`,
|
||||||
|
}),
|
||||||
|
};
|
||||||
@@ -2,7 +2,8 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { ProColumns } from "@ant-design/pro-components";
|
import { ProColumns } from "@ant-design/pro-components";
|
||||||
import { Tag } from "antd";
|
import { Tag } from "antd";
|
||||||
import { ICONS, IconType } from "@/constants/icons";
|
import { history, useIntl } from "@umijs/max";
|
||||||
|
import { ICONS, IconType } from "@/constants/antd/icons";
|
||||||
import {
|
import {
|
||||||
TableAction,
|
TableAction,
|
||||||
ToolbarAction,
|
ToolbarAction,
|
||||||
@@ -129,13 +130,18 @@ export const createCommonToolbarActions = (handlers: {
|
|||||||
onImport?: () => void;
|
onImport?: () => void;
|
||||||
}): ToolbarAction[] => {
|
}): ToolbarAction[] => {
|
||||||
const actions: ToolbarAction[] = [];
|
const actions: ToolbarAction[] = [];
|
||||||
|
|
||||||
if (handlers.onAdd) {
|
if (handlers.onAdd) {
|
||||||
actions.push(
|
actions.push(
|
||||||
createToolbarAction("add", "新建", "add", handlers.onAdd, {
|
createToolbarAction(
|
||||||
type: "primary",
|
"add",
|
||||||
permission: "add",
|
useIntl().formatMessage({ id: "pages.searchTable.new" }),
|
||||||
})
|
"add",
|
||||||
|
handlers.onAdd,
|
||||||
|
{
|
||||||
|
type: "primary",
|
||||||
|
permission: "add",
|
||||||
|
}
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user