Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@kne-components/components-admin",
"version": "1.1.42",
"version": "1.1.43",
"description": "用于实现一个后台管理系统的必要组件",
"scripts": {
"init": "husky",
Expand Down
20 changes: 20 additions & 0 deletions src/components/Apis/getApis.js
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,10 @@ const getApis = options => {
url: `${prefix}/tenant/admin/send-invite-message`,
method: 'POST'
},
sendOrgMessage: {
url: `${prefix}/tenant/admin/send-org-message`,
method: 'POST'
},
appendArgs: {
url: `${prefix}/tenant/admin/append-args`,
method: 'POST'
Expand Down Expand Up @@ -428,6 +432,18 @@ const getApis = options => {
url: `${prefix}/tenant/org-link-config`,
method: 'GET'
},
orgLinkSave: {
url: `${prefix}/tenant/org-link-save`,
method: 'POST'
},
orgLinkCancel: {
url: `${prefix}/tenant/org-link-cancel`,
method: 'POST'
},
orgLinkSync: {
url: `${prefix}/tenant/org-link-sync`,
method: 'POST'
},
userList: {
url: `${prefix}/tenant/user-list`,
method: 'GET'
Expand Down Expand Up @@ -456,6 +472,10 @@ const getApis = options => {
url: `${prefix}/tenant/send-invite-message`,
method: 'POST'
},
sendOrgMessage: {
url: `${prefix}/tenant/send-org-message`,
method: 'POST'
},
customComponentDetail: {
url: `${prefix}/tenant/custom-component-detail`,
method: 'GET'
Expand Down
3 changes: 3 additions & 0 deletions src/components/BizUnit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,9 @@ render(<ActionsExample />);
| titleExtra | 标题额外内容 | ReactNode | null |
| children | 自定义渲染函数 | Function | - |
| onMount | 组件挂载回调 | Function | - |
| filter | 外部筛选状态(受控),传入后 BizUnit 使用该值代替内部 useState | Array | - |
| onFilterChange | 外部筛选变更回调,与 filter 配合使用 | Function | - |
| urlFilterValue | URL 筛选参数映射,传入后 BizUnit 自动从 URL 初始化 filter。支持数组 `['id', 'status']` 或对象 `{ id: true, status: { multi: true } }` 格式,详见 `Filter.useUrlFilterValue` | Array \| Object | - |

### apis 配置

Expand Down
3 changes: 3 additions & 0 deletions src/components/BizUnit/doc/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
| titleExtra | 标题额外内容 | ReactNode | null |
| children | 自定义渲染函数 | Function | - |
| onMount | 组件挂载回调 | Function | - |
| filter | 外部筛选状态(受控),传入后 BizUnit 使用该值代替内部 useState | Array | - |
| onFilterChange | 外部筛选变更回调,与 filter 配合使用 | Function | - |
| urlFilterValue | URL 筛选参数映射,传入后 BizUnit 自动从 URL 初始化 filter。支持数组 `['id', 'status']` 或对象 `{ id: true, status: { multi: true } }` 格式,详见 `Filter.useUrlFilterValue` | Array \| Object | - |

### apis 配置

Expand Down
39 changes: 11 additions & 28 deletions src/components/BizUnit/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { createWithRemoteLoader } from '@kne/remote-loader';
import { useRef, useState, useEffect, useMemo } from 'react';
import { Flex } from 'antd';
import useRefCallback from '@kne/use-ref-callback';
import merge from 'lodash/merge';
import Actions from './Actions';
import Create from './Actions/Create';
Expand All @@ -25,7 +24,10 @@ const BizUnit = createWithRemoteLoader({
getActionList,
allowKeywordSearch = true,
onMount,
options
options,
filter: outerFilter,
onFilterChange: outerOnFilterChange,
urlFilterValue
}) => {
const { formatMessage } = useIntl();
options = merge(
Expand All @@ -51,12 +53,14 @@ const BizUnit = createWithRemoteLoader({
options
);
const [TablePage, Filter] = remoteModules;
const ref = useRef();
const { SearchInput, getFilterValue } = Filter;
const [filter, setFilter] = useState([]);
const { SearchInput, getFilterValue, useUrlFilterValue } = Filter;
const ref = useRef(null);
const [urlFilter] = useUrlFilterValue(urlFilterValue || []);

const [filter, setFilter] = useState(urlFilter);

const filterValue = options.mapFilterValue ? options.mapFilterValue(filter, getFilterValue) : getFilterValue(filter);
const filterParamsKey = useMemo(() => JSON.stringify(filterValue), [filterValue]);
const isFirstFilterEffect = useRef(true);

const topOptions = (
<Flex gap={8}>
{allowKeywordSearch && <SearchInput size={topOptionsSize} name={options.keywordFilterName} label={options.keywordFilterLabel} />}
Expand Down Expand Up @@ -106,27 +110,6 @@ const BizUnit = createWithRemoteLoader({
name
});

const handlerMount = useRefCallback(() => {
onMount &&
onMount({
filter: { value: filter, onChange: setFilter },
filterList,
topOptions,
tableOptions
});
});

useEffect(() => {
handlerMount();
}, [handlerMount, filter]);

useEffect(() => {
if (isFirstFilterEffect.current) {
isFirstFilterEffect.current = false;
return;
}
ref.current?.reload?.();
}, [filterParamsKey]);
if (typeof children === 'function') {
return children({
filter: { value: filter, onChange: setFilter, list: filterList },
Expand Down
35 changes: 35 additions & 0 deletions src/components/Task/Actions/InputDetail.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { createWithRemoteLoader } from '@kne/remote-loader';
import { Button } from 'antd';
import withLocale from '../withLocale';
import { useIntl } from '@kne/react-intl';
import JsonView from '@kne/json-view';
import '@kne/json-view/dist/index.css';

const InputDetail = createWithRemoteLoader({
modules: ['components-core:Modal@useModal', 'components-core:InfoPage']
})(withLocale(({ remoteModules, data, ...props }) => {
const [useModal, InfoPage] = remoteModules;
const { formatMessage } = useIntl();
const modal = useModal();

return (
<Button
{...props}
onClick={() => {
modal({
title: formatMessage({ id: 'InputParamsTitle' }),
footer: null,
children: (
<InfoPage>
<InfoPage.Part title={formatMessage({ id: 'InputParams' })}>
<JsonView data={data.input} collapsedFrom={1} />
</InfoPage.Part>
</InfoPage>
)
});
}}
/>
);
}));

export default InputDetail;
11 changes: 11 additions & 0 deletions src/components/Task/Actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import CancelTask from './CancelTask';
import RetryTask from './RetryTask';
import ErrorDetail from './ErrorDetail';
import ResultDetail from './ResultDetail';
import InputDetail from './InputDetail';
import ViewLogs from './ViewLogs';

const ActionsInner = createWithRemoteLoader({
Expand All @@ -28,6 +29,16 @@ const ActionsInner = createWithRemoteLoader({
}
}

if (['pending'].indexOf(data.status) > -1) {
list.push({
...props,
buttonComponent: InputDetail,
data,
children: formatMessage({ id: 'ViewInputParams' }),
onSuccess
});
}

if (['pending', 'running'].indexOf(data.status) > -1) {
list.push({
...props,
Expand Down
2 changes: 2 additions & 0 deletions src/components/Task/locale/en-US.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const locale = {
ErrorDetail: 'Error Detail',
ViewResult: 'View Result',
ViewLogs: 'View Logs',
ViewInputParams: 'View Input',
BatchRetry: 'Batch Retry',
// Status Enums
Pending: 'Pending',
Expand All @@ -48,6 +49,7 @@ const locale = {
OutputResult: 'Output Result',
// Modal Titles
ErrorDetailTitle: 'Error Detail',
InputParamsTitle: 'Input Parameters',
TaskResultTitle: 'Task Result',
ViewLogsTitle: 'Execution Logs',
// ViewLogs
Expand Down
2 changes: 2 additions & 0 deletions src/components/Task/locale/zh-CN.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const locale = {
ErrorDetail: '错误详情',
ViewResult: '查看结果',
ViewLogs: '查看日志',
ViewInputParams: '查看参数',
BatchRetry: '批量重试',
// Status Enums
Pending: '等待执行',
Expand All @@ -48,6 +49,7 @@ const locale = {
OutputResult: '输出结果',
// Modal Titles
ErrorDetailTitle: '错误详情',
InputParamsTitle: '输入参数',
TaskResultTitle: '任务结果',
ViewLogsTitle: '执行日志',
// ViewLogs
Expand Down
8 changes: 6 additions & 2 deletions src/components/Tenant/AfterTenantLoginLayout.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { createWithRemoteLoader } from '@kne/remote-loader';
import { Flex, Button } from 'antd';
import { Flex, Button, Tag } from 'antd';
import { Outlet, useNavigate } from 'react-router-dom';
import Authenticate from './Authenticate';
import withLocale from './withLocale';
import { useIntl } from '@kne/react-intl';

import { getSourceIcon, SOURCE_LABEL_MAP } from './constants';

const AfterTenantLoginLayout = createWithRemoteLoader({
modules: ['components-admin:Authenticate@MainLayout', 'components-admin:UserTool']
})(({ remoteModules, navigation, switchTenantPath, children, ...props }) => {
Expand All @@ -27,7 +29,9 @@ const AfterTenantLoginLayout = createWithRemoteLoader({
},
rightOptions: (
<UserTool
name={tenantUserInfo.name}
name={tenantUserInfo.syncSource ? (
<>{tenantUserInfo.name}<Tag icon={getSourceIcon(tenantUserInfo.syncSource)} color="processing" style={{ marginLeft: 6, verticalAlign: 'middle' }}>{SOURCE_LABEL_MAP[tenantUserInfo.syncSource] || tenantUserInfo.syncSource}</Tag></>
) : tenantUserInfo.name}
email={tenantUserInfo.email || tenantUserInfo.phone}
avatar={tenantUserInfo.avatar}
list={[
Expand Down
89 changes: 34 additions & 55 deletions src/components/Tenant/JoinInvitation/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,7 @@ const companyInitial = name => {
};

const JoinInvitation = createWithRemoteLoader({
modules: [
'components-core:Layout@Page',
'components-core:Global@usePreset',
'components-core:LoadingButton',
'components-core:Image'
]
modules: ['components-core:Layout@Page', 'components-core:Global@usePreset', 'components-core:LoadingButton', 'components-core:Image']
})(({ remoteModules, baseUrl = '', token: propsToken, children }) => {
const [Page, usePreset, LoadingButton, Image] = remoteModules;
const [current, setCurrent] = useState(0);
Expand Down Expand Up @@ -59,9 +54,7 @@ const JoinInvitation = createWithRemoteLoader({
<Typography.Title level={4} className={style.headerTitle}>
{formatMessage({ id: 'InviteYouJoin' }, { name: company?.name || '' })}
</Typography.Title>
<Typography.Paragraph className={style.headerSubtitle}>
{formatMessage({ id: 'InviteJoinSubtitle' })}
</Typography.Paragraph>
<Typography.Paragraph className={style.headerSubtitle}>{formatMessage({ id: 'InviteJoinSubtitle' })}</Typography.Paragraph>
</div>
</header>
);
Expand All @@ -72,9 +65,7 @@ const JoinInvitation = createWithRemoteLoader({
{...Object.assign({}, apis.tenant.parseJoinToken, {
data: { token }
})}
error={error =>
renderError(error || formatMessage({ id: 'InviteLinkExpired' }), formatMessage({ id: 'ContactAdmin' }))
}
error={error => renderError(error || formatMessage({ id: 'InviteLinkExpired' }), formatMessage({ id: 'ContactAdmin' }))}
render={({ data }) => {
const { tenant, tenantUser } = data;
if (!(tenant && tenant.status === 'open' && tenantUser && tenantUser.status === 'open')) {
Expand Down Expand Up @@ -153,52 +144,40 @@ const JoinInvitation = createWithRemoteLoader({
{renderHeader(data.company)}
<div className={style.content}>
<div className={style.stepsWrap}>
<Steps
current={current}
size="small"
orientation="horizontal"
titlePlacement="vertical"
responsive={false}
items={stepItems}
/>
<Steps current={current} size="small" orientation="horizontal" titlePlacement="vertical" responsive={false} items={stepItems} />
</div>
<main className={style.main}>
{current === 0 && (
<div className={classnames(style.stepPanel, style.stepPanelCompany)}>
<CompanyInfo.Detail data={data.company} />
</div>
)}
{current === 1 && (
<div className={classnames(style.stepPanel, style.stepPanelEmployee)}>
<Typography.Paragraph className={style.stepHint}>
{formatMessage({ id: 'ConfirmEmployeeInfoHint' })}
</Typography.Paragraph>
<TenantUserPersonalCard
data={tenantUser}
positionList={data.positionList}
/>
</div>
)}
{current === 2 && (
<div className={classnames(style.stepPanel, style.stepPanelSuccess)}>
<CheckCircleFilled className={style.successIcon} />
<Typography.Title level={4} className={style.successTitle}>
{formatMessage({ id: 'WelcomeJoin' }, { name: data.company.name })}
</Typography.Title>
<Typography.Paragraph className={style.successSub}>
<span className={style.countdownNum}>
<CountDown
duration={5}
format="s"
onComplete={() => {
window.location.href = `${baseUrl}/tenant`;
}}
/>
</span>
{formatMessage({ id: 'AutoJump' })}
</Typography.Paragraph>
</div>
)}
<div className={classnames(style.stepPanel, style.stepPanelCompany)}>
<CompanyInfo.Detail data={data.company} />
</div>
)}
{current === 1 && (
<div className={classnames(style.stepPanel, style.stepPanelEmployee)}>
<Typography.Paragraph className={style.stepHint}>{formatMessage({ id: 'ConfirmEmployeeInfoHint' })}</Typography.Paragraph>
<TenantUserPersonalCard data={tenantUser} positionList={data.positionList} />
</div>
)}
{current === 2 && (
<div className={classnames(style.stepPanel, style.stepPanelSuccess)}>
<CheckCircleFilled className={style.successIcon} />
<Typography.Title level={4} className={style.successTitle}>
{formatMessage({ id: 'WelcomeJoin' }, { name: data.company.name })}
</Typography.Title>
<Typography.Paragraph className={style.successSub}>
<span className={style.countdownNum}>
<CountDown
duration={5}
format="s"
onComplete={() => {
window.location.href = `${baseUrl}/tenant`;
}}
/>
</span>
{formatMessage({ id: 'AutoJump' })}
</Typography.Paragraph>
</div>
)}
</main>
</div>
{footerNode ? <footer className={footerClassName}>{footerNode}</footer> : null}
Expand Down
Loading