refactor(department): dev (#1492)
Reviewed-on: daoyoucloud/tachybase#1492
This commit is contained in:
parent
a654933ab2
commit
bf1f6349f1
@ -0,0 +1,58 @@
|
|||||||
|
import { uid } from '@tachybase/schema';
|
||||||
|
|
||||||
|
export const getSchemaDepartmentTable = (params) => {
|
||||||
|
const { useDataSource } = params;
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'void',
|
||||||
|
properties: {
|
||||||
|
[uid()]: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'RequestProvider',
|
||||||
|
'x-component-props': {
|
||||||
|
useDataSource,
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
actions: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ActionBar',
|
||||||
|
'x-component-props': {
|
||||||
|
style: {
|
||||||
|
marginBottom: 16,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
filter: {
|
||||||
|
type: 'void',
|
||||||
|
title: '{{ t("Filter") }}',
|
||||||
|
default: {
|
||||||
|
$and: [
|
||||||
|
{
|
||||||
|
title: {
|
||||||
|
$includes: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'x-action': 'filter',
|
||||||
|
'x-component': 'Filter.Action',
|
||||||
|
'x-use-component-props': 'useFilterActionProps',
|
||||||
|
'x-component-props': {
|
||||||
|
icon: 'FilterOutlined',
|
||||||
|
},
|
||||||
|
'x-align': 'left',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
departments: {
|
||||||
|
type: 'array',
|
||||||
|
'x-component': 'InternalDepartmentTable',
|
||||||
|
'x-component-props': {
|
||||||
|
useDisabled: '{{ useDisabled }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,24 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { SchemaComponent } from '@tachybase/client';
|
||||||
|
|
||||||
|
import { getSchemaDepartmentTable } from './DepartmentTable.schema';
|
||||||
|
import { InternalDepartmentTable } from './InternalDepartmentTable';
|
||||||
|
import { ProviderRequest } from './Request.povider';
|
||||||
|
import { useFilterActionProps } from './scopes/useFilterActionProps';
|
||||||
|
|
||||||
|
export const ViewDepartmentTable = ({ useDataSource, useDisabled }) => {
|
||||||
|
const schema = getSchemaDepartmentTable({ useDataSource });
|
||||||
|
return (
|
||||||
|
<SchemaComponent
|
||||||
|
schema={schema}
|
||||||
|
components={{
|
||||||
|
RequestProvider: ProviderRequest,
|
||||||
|
InternalDepartmentTable,
|
||||||
|
}}
|
||||||
|
scope={{
|
||||||
|
useDisabled,
|
||||||
|
useFilterActionProps,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,16 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
interface FilterKeysContextProps {
|
||||||
|
expandedKeys: any[];
|
||||||
|
setExpandedKeys: any;
|
||||||
|
hasFilter: any;
|
||||||
|
setHasFilter: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ContextFilterKeys = React.createContext<Partial<FilterKeysContextProps>>({});
|
||||||
|
|
||||||
|
export const ProviderContextFilterKeys = ContextFilterKeys.Provider;
|
||||||
|
|
||||||
|
export function useContextFilterKeys() {
|
||||||
|
return React.useContext(ContextFilterKeys);
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
import React, { useContext, useEffect } from 'react';
|
||||||
|
import { useResourceActionContext } from '@tachybase/client';
|
||||||
|
import { useField } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { Table } from 'antd';
|
||||||
|
|
||||||
|
import { useTranslation } from '../../../locale';
|
||||||
|
import { useGetDepTree } from '../main-tab/hooks/useGetDepTree';
|
||||||
|
import { getDepartmentStr } from '../utils/getDepartmentStr';
|
||||||
|
import { useContextFilterKeys } from './FilterKeys.context';
|
||||||
|
|
||||||
|
const useDisabledDefault = () => ({
|
||||||
|
disabled: () => false,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const InternalDepartmentTable = ({ useDisabled = useDisabledDefault }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const service = useResourceActionContext();
|
||||||
|
|
||||||
|
const { run, data, loading, defaultRequest } = service;
|
||||||
|
const { resource, resourceOf, params } = defaultRequest || {};
|
||||||
|
const { treeData, initData, loadData } = useGetDepTree({ resource, resourceOf, params });
|
||||||
|
|
||||||
|
const field: any = useField();
|
||||||
|
const { disabled: disabled } = useDisabled();
|
||||||
|
|
||||||
|
const { hasFilter, expandedKeys, setExpandedKeys } = useContextFilterKeys();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!hasFilter) {
|
||||||
|
initData(data?.data);
|
||||||
|
}
|
||||||
|
}, [data, initData, loading, hasFilter]);
|
||||||
|
|
||||||
|
const { count, page, pageSize } = data?.meta || {};
|
||||||
|
|
||||||
|
const paginationParams: any = {
|
||||||
|
defaultPageSize: params?.pageSize,
|
||||||
|
total: count,
|
||||||
|
current: page,
|
||||||
|
pageSize: pageSize,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Table
|
||||||
|
rowKey={'id'}
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
dataIndex: 'title',
|
||||||
|
title: t('Department name'),
|
||||||
|
render: (text, record) => (hasFilter ? getDepartmentStr(record) : text),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
rowSelection={{
|
||||||
|
selectedRowKeys: (field?.value || []).map((fieldValue) => fieldValue.id),
|
||||||
|
onChange: (selectedRowKeys, selectedRows) => {
|
||||||
|
return field?.setValue?.(selectedRows);
|
||||||
|
},
|
||||||
|
getCheckboxProps: () => ({ disabled: disabled() }),
|
||||||
|
}}
|
||||||
|
pagination={{
|
||||||
|
...paginationParams,
|
||||||
|
showSizeChanger: true,
|
||||||
|
onChange(f, S) {
|
||||||
|
let O;
|
||||||
|
run({
|
||||||
|
...(service?.params?.[0] || {}),
|
||||||
|
page: f,
|
||||||
|
pageSize: S,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
dataSource={hasFilter ? data?.data || [] : treeData}
|
||||||
|
expandable={{
|
||||||
|
onExpand: (expanded, record) => {
|
||||||
|
loadData({
|
||||||
|
key: record.id,
|
||||||
|
children: record.children,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
expandedRowKeys: expandedKeys,
|
||||||
|
onExpandedRowsChange: (expandedRows) => setExpandedKeys(expandedRows),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -1,10 +1,10 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { CollectionProvider_deprecated, ResourceActionContext } from '@tachybase/client';
|
import { CollectionProvider_deprecated, ResourceActionContext } from '@tachybase/client';
|
||||||
|
|
||||||
import { collectionDepartments } from '../collections/departments.collection';
|
import { collectionDepartments } from '../main-tab/collections/departments.collection';
|
||||||
import { FilterKeysContext } from '../context/FilterKeysContext';
|
import { ProviderContextFilterKeys } from './FilterKeys.context';
|
||||||
|
|
||||||
export const RequestProvider = (prop) => {
|
export const ProviderRequest = (prop) => {
|
||||||
const [expandedKeys, setExpandedKeys] = useState([]);
|
const [expandedKeys, setExpandedKeys] = useState([]);
|
||||||
const [hasFilter, setHasFilter] = useState(false);
|
const [hasFilter, setHasFilter] = useState(false);
|
||||||
const { useDataSource } = prop;
|
const { useDataSource } = prop;
|
||||||
@ -15,9 +15,9 @@ export const RequestProvider = (prop) => {
|
|||||||
return (
|
return (
|
||||||
<ResourceActionContext.Provider value={service}>
|
<ResourceActionContext.Provider value={service}>
|
||||||
<CollectionProvider_deprecated collection={collectionDepartments}>
|
<CollectionProvider_deprecated collection={collectionDepartments}>
|
||||||
<FilterKeysContext.Provider value={{ expandedKeys, setExpandedKeys, hasFilter, setHasFilter }}>
|
<ProviderContextFilterKeys value={{ expandedKeys, setExpandedKeys, hasFilter, setHasFilter }}>
|
||||||
{prop.children}
|
{prop.children}
|
||||||
</FilterKeysContext.Provider>
|
</ProviderContextFilterKeys>
|
||||||
</CollectionProvider_deprecated>
|
</CollectionProvider_deprecated>
|
||||||
</ResourceActionContext.Provider>
|
</ResourceActionContext.Provider>
|
||||||
);
|
);
|
@ -4,9 +4,12 @@ export const useDepartmentFilterActionProps = () => {
|
|||||||
const collection = useCollection();
|
const collection = useCollection();
|
||||||
const options = useFilterFieldOptions(collection.fields);
|
const options = useFilterFieldOptions(collection.fields);
|
||||||
const service = useResourceActionContext();
|
const service = useResourceActionContext();
|
||||||
return useFilterFieldProps({
|
|
||||||
|
const result = useFilterFieldProps({
|
||||||
options,
|
options,
|
||||||
params: service.state?.params?.[0] || service.params,
|
params: service.state?.params?.[0] || service.params,
|
||||||
service,
|
service,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
};
|
};
|
@ -8,11 +8,11 @@ import {
|
|||||||
} from '@tachybase/client';
|
} from '@tachybase/client';
|
||||||
import { useField } from '@tachybase/schema';
|
import { useField } from '@tachybase/schema';
|
||||||
|
|
||||||
import { useTranslation } from '../../../locale';
|
import { useTranslation } from '../../../../locale';
|
||||||
import { FilterKeysContext } from '../context/FilterKeysContext';
|
import { useContextFilterKeys } from '../FilterKeys.context';
|
||||||
|
|
||||||
export const useFilterActionProps = () => {
|
export const useFilterActionProps = () => {
|
||||||
const { setHasFilter, setExpandedKeys } = useContext(FilterKeysContext);
|
const { setHasFilter, setExpandedKeys } = useContextFilterKeys();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const collection = useContext(CollectionContext);
|
const collection = useContext(CollectionContext);
|
||||||
const options = useFilterFieldOptions(collection.fields);
|
const options = useFilterFieldOptions(collection.fields);
|
@ -1,45 +0,0 @@
|
|||||||
import React, { useContext, useRef } from 'react';
|
|
||||||
import { SchemaComponent, useAPIClient, useResourceActionContext } from '@tachybase/client';
|
|
||||||
|
|
||||||
import { DepartmentsContext } from '../context/DepartmentsContext';
|
|
||||||
import { schemaAddMembers } from '../schema/addMembers.schema';
|
|
||||||
|
|
||||||
export const AddMembers = () => {
|
|
||||||
const { department, useAddMembersAction, handleSelect } = useAction();
|
|
||||||
return (
|
|
||||||
<SchemaComponent
|
|
||||||
scope={{
|
|
||||||
useAddMembersAction,
|
|
||||||
department,
|
|
||||||
handleSelect,
|
|
||||||
}}
|
|
||||||
schema={schemaAddMembers}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
function useAction() {
|
|
||||||
const { department } = useContext(DepartmentsContext);
|
|
||||||
const { refresh } = useResourceActionContext();
|
|
||||||
const ref = useRef([]);
|
|
||||||
const api = useAPIClient();
|
|
||||||
const useAddMembersAction = () => ({
|
|
||||||
async run() {
|
|
||||||
const x = ref.current;
|
|
||||||
if (x?.length) {
|
|
||||||
await api.resource('departments.members', department.id).add({ values: x }), (ref.current = []);
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleSelect = (val) => {
|
|
||||||
ref.current = val;
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
department,
|
|
||||||
useAddMembersAction,
|
|
||||||
handleSelect,
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,169 +0,0 @@
|
|||||||
import React, { useContext, useState } from 'react';
|
|
||||||
import { createStyles, useAPIClient, useRequest } from '@tachybase/client';
|
|
||||||
|
|
||||||
import { Button, Dropdown, Empty, Input, theme } from 'antd';
|
|
||||||
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
||||||
|
|
||||||
import { useTranslation } from '../../../locale';
|
|
||||||
import { DepartmentsContext } from '../context/DepartmentsContext';
|
|
||||||
|
|
||||||
const useStyles = createStyles(({ css }) => ({
|
|
||||||
searchDropdown: css`
|
|
||||||
.ant-dropdown-menu {
|
|
||||||
max-height: 500px;
|
|
||||||
overflow-y: scroll;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const DepartmentsTree = () => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { token } = theme.useToken();
|
|
||||||
const { setDepartment, setUser } = useContext(DepartmentsContext);
|
|
||||||
const [open, setOpen] = useState(false);
|
|
||||||
const [keyword, x] = useState('');
|
|
||||||
const [m, g] = useState([]);
|
|
||||||
const [d, A] = useState([]);
|
|
||||||
const [b, h] = useState(true);
|
|
||||||
const [F, C] = useState(true);
|
|
||||||
const { styles } = useStyles();
|
|
||||||
const limit = 10;
|
|
||||||
const api = useAPIClient();
|
|
||||||
const data = useRequest(
|
|
||||||
(params) =>
|
|
||||||
api
|
|
||||||
.resource('departments')
|
|
||||||
.aggregateSearch(params)
|
|
||||||
.then((result) => result?.data?.data),
|
|
||||||
{
|
|
||||||
manual: true,
|
|
||||||
onSuccess: (data, params) => {
|
|
||||||
const {
|
|
||||||
values: { type: q },
|
|
||||||
} = params[0] || {};
|
|
||||||
if (data) {
|
|
||||||
if (!q || (q === 'user' && data.users.length < limit)) {
|
|
||||||
h(false);
|
|
||||||
}
|
|
||||||
if (!q || (q === 'department' && data.departments.length < limit)) {
|
|
||||||
C(false);
|
|
||||||
}
|
|
||||||
g((se) => [...se, ...data.users]);
|
|
||||||
A((se) => [...se, ...data.departments]);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
const { run } = data;
|
|
||||||
const onSearch = (keyword) => {
|
|
||||||
x(keyword);
|
|
||||||
g([]);
|
|
||||||
A([]);
|
|
||||||
h(true);
|
|
||||||
C(true);
|
|
||||||
if (keyword) {
|
|
||||||
run({ values: { keyword, limit } });
|
|
||||||
setOpen(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const onChange = (event) => {
|
|
||||||
if (!event.target.value) {
|
|
||||||
setUser(null);
|
|
||||||
x('');
|
|
||||||
setOpen(false);
|
|
||||||
data.mutate({});
|
|
||||||
g([]);
|
|
||||||
A([]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const NodeLabel = (node) => {
|
|
||||||
const title = node.title;
|
|
||||||
const parent = node.parent;
|
|
||||||
return parent ? NodeLabel(parent) + ' / ' + title : title;
|
|
||||||
};
|
|
||||||
const LinkButton = (params) => (
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
style={{ padding: '0 8px' }}
|
|
||||||
onClick={(P) => {
|
|
||||||
setOpen(true), run({ values: { keyword, limit, ...params } });
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('Load more')}
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
const J = () => {
|
|
||||||
const M = [];
|
|
||||||
return !m.length && !d.length
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
key: '0',
|
|
||||||
label: <Empty description={t('No results')} image={Empty.PRESENTED_IMAGE_SIMPLE} />,
|
|
||||||
disabled: true,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: (m.length &&
|
|
||||||
(M.push({
|
|
||||||
key: '0',
|
|
||||||
type: 'group',
|
|
||||||
label: t('Users'),
|
|
||||||
children: m.map((P) => ({
|
|
||||||
key: P.username,
|
|
||||||
label: jsxs('div', {
|
|
||||||
onClick: () => setUser(P),
|
|
||||||
children: [
|
|
||||||
jsx('div', { children: P.nickname || P.username }),
|
|
||||||
jsx('div', {
|
|
||||||
style: { fontSize: token.fontSizeSM, color: token.colorTextDescription },
|
|
||||||
children: `${P.username}${P.phone ? ' | ' + P.phone : ''}${P.email ? ' | ' + P.email : ''}`,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
})),
|
|
||||||
}),
|
|
||||||
b &&
|
|
||||||
M.push({
|
|
||||||
type: 'group',
|
|
||||||
key: '0-loadMore',
|
|
||||||
label: jsx(LinkButton, { type: 'user', last: m[m.length - 1].id }),
|
|
||||||
})),
|
|
||||||
d.length &&
|
|
||||||
(M.push({
|
|
||||||
key: '1',
|
|
||||||
type: 'group',
|
|
||||||
label: t('Departments'),
|
|
||||||
children: d.map((P) => ({
|
|
||||||
key: P.id,
|
|
||||||
label: jsx('div', { onClick: () => setDepartment(P), children: NodeLabel(P) }),
|
|
||||||
})),
|
|
||||||
}),
|
|
||||||
F &&
|
|
||||||
M.push({
|
|
||||||
type: 'group',
|
|
||||||
key: '1-loadMore',
|
|
||||||
label: <LinkButton type="department" last={d[d.length - 1].id} />,
|
|
||||||
})),
|
|
||||||
M);
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<Dropdown
|
|
||||||
menu={{ items: J() }}
|
|
||||||
overlayClassName={styles.searchDropdown}
|
|
||||||
trigger={['click']}
|
|
||||||
open={open}
|
|
||||||
onOpenChange={(open) => setOpen(open)}
|
|
||||||
>
|
|
||||||
<Input.Search
|
|
||||||
allowClear
|
|
||||||
onClick={() => {
|
|
||||||
keyword || setOpen(false);
|
|
||||||
}}
|
|
||||||
onFocus={() => setDepartment(null)}
|
|
||||||
onSearch={onSearch}
|
|
||||||
onChange={onChange}
|
|
||||||
placeholder={t('Search for departments, users')}
|
|
||||||
style={{ marginBottom: '20px' }}
|
|
||||||
/>
|
|
||||||
</Dropdown>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,163 +0,0 @@
|
|||||||
import { useContext, useEffect } from 'react';
|
|
||||||
import { css, useAPIClient, useResourceActionContext } from '@tachybase/client';
|
|
||||||
|
|
||||||
import { MoreOutlined } from '@ant-design/icons';
|
|
||||||
import { App, Dropdown, Empty, Tree } from 'antd';
|
|
||||||
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
||||||
|
|
||||||
import { useTranslation } from '../../../locale';
|
|
||||||
import { DepartmentsContext } from '../context/DepartmentsContext';
|
|
||||||
import { DepartmentsExpandedContext } from '../context/DepartmentsExpandedContext';
|
|
||||||
import { k } from '../others/k';
|
|
||||||
import { schemaHhe } from '../schema/schemaHhe';
|
|
||||||
import { schemaYye } from '../schema/schemaYye';
|
|
||||||
|
|
||||||
export const ComponentX = () => {
|
|
||||||
const { data: e, loading: t } = useResourceActionContext();
|
|
||||||
const { department, setDepartment, setUser } = useContext(DepartmentsContext);
|
|
||||||
const { treeData, nodeMap, loadData, loadedKeys, setLoadedKeys, initData, expandedKeys, setExpandedKeys } =
|
|
||||||
useContext(DepartmentsExpandedContext);
|
|
||||||
|
|
||||||
const h = (v) => {
|
|
||||||
if (!v.length) return;
|
|
||||||
const l = nodeMap[v[0]];
|
|
||||||
setDepartment(l);
|
|
||||||
setUser(null);
|
|
||||||
};
|
|
||||||
const F = (v) => {
|
|
||||||
setExpandedKeys(v);
|
|
||||||
};
|
|
||||||
const C = (v) => {
|
|
||||||
setLoadedKeys(v);
|
|
||||||
};
|
|
||||||
useEffect(() => {
|
|
||||||
initData(e == null ? void 0 : e.data);
|
|
||||||
}, [e, initData, t]);
|
|
||||||
useEffect(() => {
|
|
||||||
if (!department) return;
|
|
||||||
const v = (u) => (u.parent ? [u.parent.id, ...v(u.parent)] : []),
|
|
||||||
l = v(department);
|
|
||||||
setExpandedKeys((u) => Array.from(new Set([...u, ...l])));
|
|
||||||
}, [department, setExpandedKeys]);
|
|
||||||
|
|
||||||
return jsx('div', {
|
|
||||||
className: css`
|
|
||||||
height: 57vh;
|
|
||||||
overflow: auto;
|
|
||||||
.ant-tree-node-content-wrapper {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
children:
|
|
||||||
treeData != null && treeData.length
|
|
||||||
? jsx(Tree.DirectoryTree, {
|
|
||||||
loadData: loadData,
|
|
||||||
treeData: treeData,
|
|
||||||
loadedKeys: loadedKeys,
|
|
||||||
onSelect: h,
|
|
||||||
selectedKeys: [department == null ? void 0 : department.id],
|
|
||||||
onExpand: F,
|
|
||||||
onLoad: C,
|
|
||||||
expandedKeys: expandedKeys,
|
|
||||||
expandAction: false,
|
|
||||||
showIcon: false,
|
|
||||||
fieldNames: { key: 'id' },
|
|
||||||
})
|
|
||||||
: jsx(Empty, { image: Empty.PRESENTED_IMAGE_SIMPLE }),
|
|
||||||
});
|
|
||||||
// return (
|
|
||||||
// useEffect(() => {
|
|
||||||
// initData(e == null ? void 0 : e.data);
|
|
||||||
// }, [e, initData, t]),
|
|
||||||
// useEffect(() => {
|
|
||||||
// if (!department) return;
|
|
||||||
// const v = (u) => (u.parent ? [u.parent.id, ...v(u.parent)] : []),
|
|
||||||
// l = v(department);
|
|
||||||
// setExpandedKeys((u) => Array.from(new Set([...u, ...l])));
|
|
||||||
// }, [department, setExpandedKeys]),
|
|
||||||
// jsx('div', {
|
|
||||||
// className: css`
|
|
||||||
// height: 57vh;
|
|
||||||
// overflow: auto;
|
|
||||||
// .ant-tree-node-content-wrapper {
|
|
||||||
// overflow: hidden;
|
|
||||||
// }
|
|
||||||
// `,
|
|
||||||
// children:
|
|
||||||
// treeData != null && treeData.length
|
|
||||||
// ? jsx(Tree.DirectoryTree, {
|
|
||||||
// loadData: loadData,
|
|
||||||
// treeData: treeData,
|
|
||||||
// loadedKeys: loadedKeys,
|
|
||||||
// onSelect: h,
|
|
||||||
// selectedKeys: [department == null ? void 0 : department.id],
|
|
||||||
// onExpand: F,
|
|
||||||
// onLoad: C,
|
|
||||||
// expandedKeys: expandedKeys,
|
|
||||||
// expandAction: false,
|
|
||||||
// showIcon: false,
|
|
||||||
// fieldNames: { key: 'id' },
|
|
||||||
// })
|
|
||||||
// : jsx(Empty, { image: Empty.PRESENTED_IMAGE_SIMPLE }),
|
|
||||||
// })
|
|
||||||
// );
|
|
||||||
};
|
|
||||||
ComponentX.Item = function ({ node: t, setVisible: o, setDrawer: a }) {
|
|
||||||
const { t: r } = useTranslation(),
|
|
||||||
{ refreshAsync: c } = useResourceActionContext(),
|
|
||||||
{ setLoadedKeys: i, expandedKeys: x, setExpandedKeys: m } = useContext(DepartmentsExpandedContext),
|
|
||||||
{ modal: g, message: d } = App.useApp(),
|
|
||||||
A = useAPIClient(),
|
|
||||||
b = () => {
|
|
||||||
g.confirm({
|
|
||||||
title: r('Delete'),
|
|
||||||
content: r('Are you sure you want to delete it?'),
|
|
||||||
onOk: () =>
|
|
||||||
k(this, null, function* () {
|
|
||||||
yield A.resource('departments').destroy({ filterByTk: t.id }),
|
|
||||||
d.success(r('Deleted successfully')),
|
|
||||||
m((v) => v.filter((l) => l !== t.id));
|
|
||||||
const C = [...x];
|
|
||||||
i([]), m([]), yield c(), m(C);
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
h = (C) => {
|
|
||||||
a({ schema: C, node: t }), o(true);
|
|
||||||
},
|
|
||||||
F = ({ key: C, domEvent: v }) => {
|
|
||||||
switch ((v.stopPropagation(), C)) {
|
|
||||||
case 'new-sub':
|
|
||||||
h(schemaYye);
|
|
||||||
break;
|
|
||||||
case 'edit':
|
|
||||||
h(schemaHhe);
|
|
||||||
break;
|
|
||||||
case 'delete':
|
|
||||||
b();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return jsxs('div', {
|
|
||||||
style: { display: 'flex', justifyContent: 'space-between', overflow: 'hidden' },
|
|
||||||
children: [
|
|
||||||
jsx('div', {
|
|
||||||
style: { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' },
|
|
||||||
children: t.title,
|
|
||||||
}),
|
|
||||||
jsx(Dropdown, {
|
|
||||||
menu: {
|
|
||||||
items: [
|
|
||||||
{ label: r('New sub department'), key: 'new-sub' },
|
|
||||||
{ label: r('Edit department'), key: 'edit' },
|
|
||||||
{ label: r('Delete department'), key: 'delete' },
|
|
||||||
],
|
|
||||||
onClick: F,
|
|
||||||
},
|
|
||||||
children: jsx('div', {
|
|
||||||
style: { marginLeft: '15px' },
|
|
||||||
children: jsx(MoreOutlined, {}),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
};
|
|
@ -1,34 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { SchemaComponentOptions } from '@tachybase/client';
|
|
||||||
|
|
||||||
import { Col, Row } from 'antd';
|
|
||||||
|
|
||||||
import { useDepartmentFilterActionProps } from '../scopes/useDepartmentFilterActionProps';
|
|
||||||
import { DepartmentsBlock } from './DepartmentsBlock';
|
|
||||||
import { DepartmentSelect } from './DepartmentSelect';
|
|
||||||
import { DepartmentsResourceProvider } from './DepartmentsResourceProvider';
|
|
||||||
import { DepartmentsUsersBlock } from './DepartmentsUsersBlock';
|
|
||||||
import { SuperiorDepartmentSelect } from './SuperiorDepartmentSelect';
|
|
||||||
import { UserResourceProvider } from './UserResourceProvider';
|
|
||||||
|
|
||||||
export const DepartmentManagement = () => {
|
|
||||||
return (
|
|
||||||
<SchemaComponentOptions
|
|
||||||
components={{ SuperiorDepartmentSelect, DepartmentSelect }}
|
|
||||||
scope={{ useFilterActionProps: useDepartmentFilterActionProps }}
|
|
||||||
>
|
|
||||||
<Row gutter={48} style={{ flexWrap: 'nowrap' }}>
|
|
||||||
<Col span={6} style={{ borderRight: '1px solid #eee', minWidth: '300px' }}>
|
|
||||||
<DepartmentsResourceProvider>
|
|
||||||
<DepartmentsBlock />
|
|
||||||
</DepartmentsResourceProvider>
|
|
||||||
</Col>
|
|
||||||
<Col flex="auto" style={{ overflow: 'hidden' }}>
|
|
||||||
<UserResourceProvider>
|
|
||||||
<DepartmentsUsersBlock />
|
|
||||||
</UserResourceProvider>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</SchemaComponentOptions>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,23 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { SchemaComponent } from '@tachybase/client';
|
|
||||||
import { uid } from '@tachybase/schema';
|
|
||||||
|
|
||||||
import { DepartmentManagement } from './DepartmentManagement';
|
|
||||||
|
|
||||||
export const DepartmentManagementComponent = () => {
|
|
||||||
return (
|
|
||||||
<SchemaComponent
|
|
||||||
components={{ DepartmentManagement }}
|
|
||||||
schema={{
|
|
||||||
type: 'void',
|
|
||||||
properties: {
|
|
||||||
[uid()]: {
|
|
||||||
type: 'void',
|
|
||||||
'x-decorator': 'CardItem',
|
|
||||||
'x-component': 'DepartmentManagement',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,73 +0,0 @@
|
|||||||
import { useEffect, useRef, useState } from 'react';
|
|
||||||
import {
|
|
||||||
ActionContextProvider,
|
|
||||||
ResourceActionProvider,
|
|
||||||
SchemaComponent,
|
|
||||||
useActionContext,
|
|
||||||
useRecord,
|
|
||||||
} from '@tachybase/client';
|
|
||||||
import { useField } from '@tachybase/schema';
|
|
||||||
|
|
||||||
import { Select } from 'antd';
|
|
||||||
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
||||||
|
|
||||||
import { schemaFfe } from '../schema/schemaFfe';
|
|
||||||
|
|
||||||
export const DepartmentOwnersField = () => {
|
|
||||||
const [e, t] = useState(false),
|
|
||||||
o = useRecord(),
|
|
||||||
a = useField(),
|
|
||||||
[r, c] = useState([]),
|
|
||||||
i = useRef([]),
|
|
||||||
x = (d, A) => {
|
|
||||||
i.current = A;
|
|
||||||
},
|
|
||||||
m = () => {
|
|
||||||
const { setVisible: d } = useActionContext();
|
|
||||||
return {
|
|
||||||
run() {
|
|
||||||
const A = a.value || [];
|
|
||||||
a.setValue([...A, ...i.current]), (i.current = []), d(false);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
useEffect(() => {
|
|
||||||
a.value && c(a.value.map((d) => ({ value: d.id, label: d.nickname || d.username })));
|
|
||||||
}, [a.value]);
|
|
||||||
const g = (d) => {
|
|
||||||
var A;
|
|
||||||
return jsx(ResourceActionProvider, {
|
|
||||||
collection: 'users',
|
|
||||||
request: {
|
|
||||||
resource: `departments/${o.id}/members`,
|
|
||||||
action: 'list',
|
|
||||||
params: { filter: (A = a.value) != null && A.length ? { id: { $notIn: a.value.map((b) => b.id) } } : {} },
|
|
||||||
},
|
|
||||||
children: d.children,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
return jsxs(ActionContextProvider, {
|
|
||||||
value: { visible: e, setVisible: t },
|
|
||||||
children: [
|
|
||||||
jsx(Select, {
|
|
||||||
open: false,
|
|
||||||
onChange: (d) => {
|
|
||||||
if (!d) {
|
|
||||||
a.setValue([]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
a.setValue(d.map(({ label: A, value: b }) => ({ id: b, nickname: A })));
|
|
||||||
},
|
|
||||||
mode: 'multiple',
|
|
||||||
value: r,
|
|
||||||
labelInValue: true,
|
|
||||||
onDropdownVisibleChange: (d) => t(d),
|
|
||||||
}),
|
|
||||||
jsx(SchemaComponent, {
|
|
||||||
schema: schemaFfe,
|
|
||||||
components: { RequestProvider: g },
|
|
||||||
scope: { department: o, handleSelect: x, useSelectOwners: m },
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
};
|
|
@ -1,14 +0,0 @@
|
|||||||
import React, { useContext } from 'react';
|
|
||||||
|
|
||||||
import { DepartmentsContext } from '../context/DepartmentsContext';
|
|
||||||
import { useDepTree2 } from '../hooks/useDepTree2';
|
|
||||||
import { InternalSuperiorDepartmentSelect } from './InternalSuperiorDepartmentSelect';
|
|
||||||
|
|
||||||
export const DepartmentSelect = () => {
|
|
||||||
const depTree = useDepTree2();
|
|
||||||
const { departmentsResource } = useContext(DepartmentsContext);
|
|
||||||
const {
|
|
||||||
service: { data },
|
|
||||||
} = departmentsResource || {};
|
|
||||||
return <InternalSuperiorDepartmentSelect {...{ ...depTree, originData: data?.data }} />;
|
|
||||||
};
|
|
@ -1,54 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { SchemaComponent } from '@tachybase/client';
|
|
||||||
import { uid } from '@tachybase/schema';
|
|
||||||
|
|
||||||
import { useFilterActionProps } from '../scopes/useFilterActionProps';
|
|
||||||
import { InternalDepartmentTable } from './InternalDepartmentTable';
|
|
||||||
import { RequestProvider } from './RequestProvider';
|
|
||||||
|
|
||||||
export const DepartmentTable = ({ useDataSource, useDisabled }) => (
|
|
||||||
<SchemaComponent
|
|
||||||
scope={{
|
|
||||||
useDisabled,
|
|
||||||
useFilterActionProps,
|
|
||||||
}}
|
|
||||||
components={{
|
|
||||||
InternalDepartmentTable,
|
|
||||||
RequestProvider,
|
|
||||||
}}
|
|
||||||
schema={{
|
|
||||||
type: 'void',
|
|
||||||
properties: {
|
|
||||||
[uid()]: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'RequestProvider',
|
|
||||||
'x-component-props': { useDataSource },
|
|
||||||
properties: {
|
|
||||||
actions: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'ActionBar',
|
|
||||||
'x-component-props': { style: { marginBottom: 16 } },
|
|
||||||
properties: {
|
|
||||||
filter: {
|
|
||||||
type: 'void',
|
|
||||||
title: '{{ t("Filter") }}',
|
|
||||||
default: { $and: [{ title: { $includes: '' } }] },
|
|
||||||
'x-action': 'filter',
|
|
||||||
'x-component': 'Filter.Action',
|
|
||||||
'x-use-component-props': 'useFilterActionProps',
|
|
||||||
'x-component-props': { icon: 'FilterOutlined' },
|
|
||||||
'x-align': 'left',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
departments: {
|
|
||||||
type: 'array',
|
|
||||||
'x-component': 'InternalDepartmentTable',
|
|
||||||
'x-component-props': { useDisabled: '{{ useDisabled }}' },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
@ -1,12 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { useRecord } from '@tachybase/client';
|
|
||||||
|
|
||||||
export const DepartmentTitle = () => {
|
|
||||||
const record = useRecord();
|
|
||||||
const title = (dep) => {
|
|
||||||
const title = dep.title;
|
|
||||||
const parent = dep.parent;
|
|
||||||
return parent ? title(parent) + ' / ' + title : title;
|
|
||||||
};
|
|
||||||
return <>{title(record)}</>;
|
|
||||||
};
|
|
@ -1,51 +0,0 @@
|
|||||||
import React, { useContext, useMemo } from 'react';
|
|
||||||
import { CollectionProvider_deprecated, ResourceActionContext, SchemaComponent, useRequest } from '@tachybase/client';
|
|
||||||
import { RolesManagerContext } from '@tachybase/plugin-acl/client';
|
|
||||||
|
|
||||||
import { useTranslation } from '../../../locale';
|
|
||||||
import { collectionDepartments } from '../collections/departments.collection';
|
|
||||||
import { useAddDepartments } from '../hooks/useAddDepartments';
|
|
||||||
import { useBulkRemoveDepartmentsYyt } from '../hooks/useBulkRemoveDepartmentsYyt';
|
|
||||||
import { useDataSource2 } from '../hooks/useDataSource2';
|
|
||||||
import { useDisabledVvt } from '../hooks/useDisabledVvt';
|
|
||||||
import { useRemoveDepartmentXxt } from '../hooks/useRemoveDepartmentXxt';
|
|
||||||
import { getSchemaDdt } from '../schema/getSchemaDdt';
|
|
||||||
import { useDepartmentFilterActionProps } from '../scopes/useDepartmentFilterActionProps';
|
|
||||||
import { DepartmentTable } from './DepartmentTable';
|
|
||||||
import { DepartmentTitle } from './DepartmentTitle';
|
|
||||||
|
|
||||||
export const Departments = () => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { role } = useContext(RolesManagerContext);
|
|
||||||
const resource = useRequest(
|
|
||||||
{
|
|
||||||
resource: `roles/${role?.name}/departments`,
|
|
||||||
action: 'list',
|
|
||||||
params: { appends: ['parent', 'parent.parent(recursively=true)'] },
|
|
||||||
},
|
|
||||||
{ ready: !!role, refreshDeps: [role] },
|
|
||||||
);
|
|
||||||
const schema = useMemo(() => getSchemaDdt(), [role]);
|
|
||||||
return (
|
|
||||||
<ResourceActionContext.Provider value={resource}>
|
|
||||||
<CollectionProvider_deprecated collection={collectionDepartments}>
|
|
||||||
<SchemaComponent
|
|
||||||
schema={schema}
|
|
||||||
components={{
|
|
||||||
DepartmentTable: DepartmentTable,
|
|
||||||
DepartmentTitle: DepartmentTitle,
|
|
||||||
}}
|
|
||||||
scope={{
|
|
||||||
useFilterActionProps: useDepartmentFilterActionProps,
|
|
||||||
t,
|
|
||||||
useRemoveDepartment: useRemoveDepartmentXxt,
|
|
||||||
useBulkRemoveDepartments: useBulkRemoveDepartmentsYyt,
|
|
||||||
useDataSource: useDataSource2,
|
|
||||||
useDisabled: useDisabledVvt,
|
|
||||||
useAddDepartments,
|
|
||||||
}}
|
|
||||||
></SchemaComponent>
|
|
||||||
</CollectionProvider_deprecated>
|
|
||||||
</ResourceActionContext.Provider>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,43 +0,0 @@
|
|||||||
import React, { useState } from 'react';
|
|
||||||
import { useRequest } from '@tachybase/client';
|
|
||||||
|
|
||||||
import { DepartmentsContext } from '../context/DepartmentsContext';
|
|
||||||
|
|
||||||
export const DepartmentsProvider = ({ children }) => {
|
|
||||||
const [user, setUser] = useState(null);
|
|
||||||
const [department, setDepartment] = useState(null);
|
|
||||||
const usersRequest = useRequest(
|
|
||||||
{
|
|
||||||
resource: 'users',
|
|
||||||
action: 'list',
|
|
||||||
params: {
|
|
||||||
appends: ['departments', 'departments.parent(recursively=true)'],
|
|
||||||
filter: department ? { 'departments.id': department.id } : {},
|
|
||||||
pageSize: 50,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
manual: true,
|
|
||||||
refreshDeps: [department],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
const departmentsRequest = useRequest({
|
|
||||||
resource: 'departments',
|
|
||||||
action: 'list',
|
|
||||||
params: { pagination: false, filter: { parentId: null } },
|
|
||||||
});
|
|
||||||
return (
|
|
||||||
<DepartmentsContext.Provider
|
|
||||||
value={{
|
|
||||||
user,
|
|
||||||
setUser,
|
|
||||||
department,
|
|
||||||
setDepartment,
|
|
||||||
usersResource: { service: usersRequest },
|
|
||||||
departmentsResource: { service: departmentsRequest },
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</DepartmentsContext.Provider>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,66 +0,0 @@
|
|||||||
import React, { useContext, useEffect, useMemo } from 'react';
|
|
||||||
import { SchemaComponent, useResourceActionContext } from '@tachybase/client';
|
|
||||||
|
|
||||||
import { useTranslation } from '../../../locale';
|
|
||||||
import { DepartmentsContext } from '../context/DepartmentsContext';
|
|
||||||
import { useBulkRemoveMembersAction } from '../hooks/useBulkRemoveMembersAction';
|
|
||||||
import { useMembersDataSource } from '../hooks/useMembersDataSource';
|
|
||||||
import { useRemoveMemberAction } from '../hooks/useRemoveMemberAction';
|
|
||||||
import { useShowTotal } from '../hooks/useShowTotal';
|
|
||||||
import { getSchemaHe } from '../schema/getSchemaHe';
|
|
||||||
import { schemaWe } from '../schema/schemaWe';
|
|
||||||
import { schemaZe } from '../schema/schemaZe';
|
|
||||||
import { useDepartmentFilterActionProps } from '../scopes/useDepartmentFilterActionProps';
|
|
||||||
import { AddMembers } from './AddMembers';
|
|
||||||
import { DepartmentField } from './DepartmentField';
|
|
||||||
import { IsOwnerField } from './IsOwnerField';
|
|
||||||
import { UserDepartmentsField } from './UserDepartmentsField';
|
|
||||||
|
|
||||||
export const DepartmentsUsersBlock = () => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { department, user } = useContext(DepartmentsContext);
|
|
||||||
const { data, setState } = useResourceActionContext();
|
|
||||||
|
|
||||||
const MemberActions = () => (department ? <SchemaComponent schema={schemaZe} /> : null);
|
|
||||||
const RowRemoveAction = () =>
|
|
||||||
department ? (
|
|
||||||
<SchemaComponent
|
|
||||||
scope={{
|
|
||||||
useRemoveMemberAction: useRemoveMemberAction,
|
|
||||||
}}
|
|
||||||
schema={schemaWe}
|
|
||||||
/>
|
|
||||||
) : null;
|
|
||||||
|
|
||||||
const schema = useMemo(() => getSchemaHe(department, user), [department, user]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setState?.({
|
|
||||||
selectedRowKeys: [],
|
|
||||||
});
|
|
||||||
}, [data, setState]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<h2>{user ? t('Search results') : t(department?.title ?? 'All users')}</h2>
|
|
||||||
<SchemaComponent
|
|
||||||
scope={{
|
|
||||||
useBulkRemoveMembersAction,
|
|
||||||
useMembersDataSource,
|
|
||||||
t,
|
|
||||||
useShowTotal,
|
|
||||||
useFilterActionProps: useDepartmentFilterActionProps,
|
|
||||||
}}
|
|
||||||
components={{
|
|
||||||
MemberActions,
|
|
||||||
AddMembers,
|
|
||||||
RowRemoveAction,
|
|
||||||
DepartmentField,
|
|
||||||
IsOwnerField,
|
|
||||||
UserDepartmentsField,
|
|
||||||
}}
|
|
||||||
schema={schema}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,60 +0,0 @@
|
|||||||
import { useContext, useEffect } from 'react';
|
|
||||||
import { useResourceActionContext } from '@tachybase/client';
|
|
||||||
import { useField } from '@tachybase/schema';
|
|
||||||
|
|
||||||
import { Table } from 'antd';
|
|
||||||
import { jsx } from 'react/jsx-runtime';
|
|
||||||
|
|
||||||
import { useTranslation } from '../../../locale';
|
|
||||||
import { FilterKeysContext } from '../context/FilterKeysContext';
|
|
||||||
import { useDepTree2 } from '../hooks/useDepTree2';
|
|
||||||
import { T } from '../others/T';
|
|
||||||
import { y } from '../others/y';
|
|
||||||
import { getDepartmentStr } from '../utils/getDepartmentStr';
|
|
||||||
|
|
||||||
const Ze = () => ({ disabled: () => false });
|
|
||||||
export const InternalDepartmentTable = ({ useDisabled: e = Ze }) => {
|
|
||||||
const { t } = useTranslation(),
|
|
||||||
o = useResourceActionContext();
|
|
||||||
console.log(o);
|
|
||||||
const { run: a, data: r, loading: c, defaultRequest: i } = o,
|
|
||||||
{ resource: x, resourceOf: m, params: g } = i || {},
|
|
||||||
{ treeData: d, initData: A, loadData: b } = useDepTree2({ resource: x, resourceOf: m, params: g }),
|
|
||||||
h = useField(),
|
|
||||||
{ disabled: F } = e(),
|
|
||||||
{ hasFilter: C, expandedKeys: v, setExpandedKeys: l } = useContext(FilterKeysContext);
|
|
||||||
useEffect(() => {
|
|
||||||
C || A(r == null ? void 0 : r.data);
|
|
||||||
}, [r, A, c, C]);
|
|
||||||
const u = {};
|
|
||||||
if ((g != null && g.pageSize && (u.defaultPageSize = g.pageSize), !u.total && r != null && r.meta)) {
|
|
||||||
const { count: f, page: S, pageSize: O } = r.meta;
|
|
||||||
(u.total = f), (u.current = S), (u.pageSize = O);
|
|
||||||
}
|
|
||||||
return jsx(Table, {
|
|
||||||
rowKey: 'id',
|
|
||||||
columns: [{ dataIndex: 'title', title: t('Department name'), render: (f, S) => (C ? getDepartmentStr(S) : f) }],
|
|
||||||
rowSelection: {
|
|
||||||
selectedRowKeys: ((h == null ? void 0 : h.value) || []).map((f) => f.id),
|
|
||||||
onChange: (f, S) => {
|
|
||||||
let O;
|
|
||||||
return (O = h == null ? void 0 : h.setValue) == null ? void 0 : O.call(h, S);
|
|
||||||
},
|
|
||||||
getCheckboxProps: (f) => ({ disabled: F(f) }),
|
|
||||||
},
|
|
||||||
pagination: T(y({ showSizeChanger: true }, u), {
|
|
||||||
onChange(f, S) {
|
|
||||||
let O;
|
|
||||||
a(T(y({}, ((O = o == null ? void 0 : o.params) == null ? void 0 : O[0]) || {}), { page: f, pageSize: S }));
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
dataSource: C ? (r == null ? void 0 : r.data) || [] : d,
|
|
||||||
expandable: {
|
|
||||||
onExpand: (f, S) => {
|
|
||||||
b({ key: S.id, children: S.children });
|
|
||||||
},
|
|
||||||
expandedRowKeys: v,
|
|
||||||
onExpandedRowsChange: (f) => l(f),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
@ -1,62 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { SchemaComponent } from '@tachybase/client';
|
|
||||||
|
|
||||||
import { useTranslation } from '../../../locale';
|
|
||||||
|
|
||||||
export const NewDepartment = () => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
return (
|
|
||||||
<SchemaComponent
|
|
||||||
scope={{ t }}
|
|
||||||
schema={{
|
|
||||||
type: 'void',
|
|
||||||
properties: {
|
|
||||||
newDepartment: {
|
|
||||||
type: 'void',
|
|
||||||
title: t('New department'),
|
|
||||||
'x-component': 'Action',
|
|
||||||
'x-component-props': { type: 'text', icon: 'PlusOutlined', style: { width: '100%', textAlign: 'left' } },
|
|
||||||
properties: {
|
|
||||||
drawer: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Action.Drawer',
|
|
||||||
'x-decorator': 'Form',
|
|
||||||
title: t('New department'),
|
|
||||||
properties: {
|
|
||||||
title: { 'x-component': 'CollectionField', 'x-decorator': 'FormItem', required: true },
|
|
||||||
parent: {
|
|
||||||
'x-component': 'CollectionField',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-collection-field': 'departments.parent',
|
|
||||||
'x-component-props': { component: 'DepartmentSelect' },
|
|
||||||
},
|
|
||||||
roles: {
|
|
||||||
'x-component': 'CollectionField',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-collection-field': 'departments.roles',
|
|
||||||
},
|
|
||||||
footer: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Action.Drawer.Footer',
|
|
||||||
properties: {
|
|
||||||
cancel: {
|
|
||||||
title: '{{t("Cancel")}}',
|
|
||||||
'x-component': 'Action',
|
|
||||||
'x-component-props': { useAction: '{{ cm.useCancelAction }}' },
|
|
||||||
},
|
|
||||||
submit: {
|
|
||||||
title: '{{t("Submit")}}',
|
|
||||||
'x-component': 'Action',
|
|
||||||
'x-component-props': { type: 'primary', useAction: '{{ useCreateDepartment }}' },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
></SchemaComponent>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,172 +0,0 @@
|
|||||||
import React, { Fragment, useState } from 'react';
|
|
||||||
import {
|
|
||||||
ActionContextProvider,
|
|
||||||
SchemaComponent,
|
|
||||||
useAPIClient,
|
|
||||||
useRecord,
|
|
||||||
useRequest,
|
|
||||||
useResourceActionContext,
|
|
||||||
} from '@tachybase/client';
|
|
||||||
import { Field, useField, useForm } from '@tachybase/schema';
|
|
||||||
|
|
||||||
import { MoreOutlined, PlusOutlined } from '@ant-design/icons';
|
|
||||||
import { App, Button, Dropdown, Tag } from 'antd';
|
|
||||||
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
||||||
|
|
||||||
import { useTranslation } from '../../../locale';
|
|
||||||
import { useDataSource } from '../hooks/useDataSource';
|
|
||||||
import { schemaJe } from '../schema/schemaJe';
|
|
||||||
import { getDepartmentStr } from '../utils/getDepartmentStr';
|
|
||||||
import { DepartmentTable } from './DepartmentTable';
|
|
||||||
|
|
||||||
export const UserDepartmentsField = () => {
|
|
||||||
const { modal, message } = App.useApp();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const [visible, setVisible] = useState(false);
|
|
||||||
const user = useRecord();
|
|
||||||
const field = useField<Field>();
|
|
||||||
const { refresh } = useResourceActionContext();
|
|
||||||
const m = (l) =>
|
|
||||||
l != null && l.length
|
|
||||||
? l.map((u) => {
|
|
||||||
return {
|
|
||||||
...u,
|
|
||||||
isMain: u.departmentsUsers?.isMain,
|
|
||||||
isOwner: u.departmentsUsers?.isOwner,
|
|
||||||
title: getDepartmentStr(u),
|
|
||||||
};
|
|
||||||
})
|
|
||||||
: [];
|
|
||||||
const api = useAPIClient();
|
|
||||||
useRequest(
|
|
||||||
() =>
|
|
||||||
api
|
|
||||||
.resource('users.departments', user.id)
|
|
||||||
.list({ appends: ['parent(recursively=true)'], pagination: false })
|
|
||||||
.then((result) => {
|
|
||||||
const u = m(result?.data?.data);
|
|
||||||
field.setValue(u);
|
|
||||||
}),
|
|
||||||
{ ready: user.id },
|
|
||||||
);
|
|
||||||
const useAddDepartments = () => {
|
|
||||||
const api = useAPIClient();
|
|
||||||
const form = useForm();
|
|
||||||
const { departments } = form.values || {};
|
|
||||||
return {
|
|
||||||
async run() {
|
|
||||||
await api.resource('users.departments', user.id).add({ values: departments.map((O) => O.id) });
|
|
||||||
form.reset();
|
|
||||||
field.setValue([
|
|
||||||
...field.value,
|
|
||||||
...departments.map((department, index) => ({
|
|
||||||
...department,
|
|
||||||
isMain: index === 0 && field.value.length === 0,
|
|
||||||
title: getDepartmentStr(department),
|
|
||||||
})),
|
|
||||||
]);
|
|
||||||
setVisible(false);
|
|
||||||
refresh();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
const A = (department) => {
|
|
||||||
modal.confirm({
|
|
||||||
title: t('Remove department'),
|
|
||||||
content: t('Are you sure you want to remove it?'),
|
|
||||||
onOk: async () => {
|
|
||||||
await api.resource('users.departments', user.id).remove({ values: [department.id] });
|
|
||||||
message.success(t('Deleted successfully'));
|
|
||||||
field.setValue(
|
|
||||||
field.value
|
|
||||||
.filter((dep) => dep.id !== department.id)
|
|
||||||
.map((dep, index) => ({ ...dep, isMain: (department.isMain && index === 0) || dep.isMain })),
|
|
||||||
);
|
|
||||||
refresh();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const b = async (l) => {
|
|
||||||
await api.resource('users').setMainDepartment({ values: { userId: user.id, departmentId: l.id } });
|
|
||||||
message.success(t('Set successfully'));
|
|
||||||
field.setValue(field.value.map((u) => ({ ...u, isMain: u.id === l.id })));
|
|
||||||
refresh();
|
|
||||||
};
|
|
||||||
const h = async (l) => {
|
|
||||||
await api.resource('departments').setOwner({ values: { userId: user.id, departmentId: l.id } });
|
|
||||||
message.success(t('Set successfully'));
|
|
||||||
field.setValue(field.value.map((u) => ({ ...u, isOwner: u.id === l.id ? true : u.isOwner })));
|
|
||||||
refresh();
|
|
||||||
};
|
|
||||||
const F = async (department) => {
|
|
||||||
await api.resource('departments').removeOwner({ values: { userId: user.id, departmentId: department.id } });
|
|
||||||
message.success(t('Set successfully'));
|
|
||||||
field.setValue(field.value.map((dep) => ({ ...dep, isOwner: dep.id === department.id ? false : dep.isOwner })));
|
|
||||||
refresh();
|
|
||||||
};
|
|
||||||
const C = (l, u) => {
|
|
||||||
switch (l) {
|
|
||||||
case 'setMain':
|
|
||||||
b(u);
|
|
||||||
break;
|
|
||||||
case 'setOwner':
|
|
||||||
h(u);
|
|
||||||
break;
|
|
||||||
case 'removeOwner':
|
|
||||||
F(u);
|
|
||||||
break;
|
|
||||||
case 'remove':
|
|
||||||
A(u);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const useDisabled = () => ({ disabled: (l) => field.value.some((u) => u.id === l.id) });
|
|
||||||
return jsxs(ActionContextProvider, {
|
|
||||||
value: { visible: visible, setVisible: setVisible },
|
|
||||||
children: [
|
|
||||||
jsxs(Fragment, {
|
|
||||||
children: [
|
|
||||||
(field?.value || []).map((l) =>
|
|
||||||
jsxs(
|
|
||||||
Tag,
|
|
||||||
{
|
|
||||||
style: { padding: '5px 8px', background: 'transparent', marginBottom: '5px' },
|
|
||||||
children: [
|
|
||||||
jsx('span', { style: { marginRight: '5px' }, children: l.title }),
|
|
||||||
l.isMain ? jsx(Tag, { color: 'processing', bordered: false, children: t('Main') }) : '',
|
|
||||||
jsx(Dropdown, {
|
|
||||||
menu: {
|
|
||||||
items: [
|
|
||||||
...(l.isMain ? [] : [{ label: t('Set as main department'), key: 'setMain' }]),
|
|
||||||
{ label: t('Remove'), key: 'remove' },
|
|
||||||
],
|
|
||||||
onClick: ({ key: u }) => C(u, l),
|
|
||||||
},
|
|
||||||
children: jsx('div', {
|
|
||||||
style: { float: 'right' },
|
|
||||||
children: jsx(MoreOutlined, {}),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
l.id,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
<Button key={1} icon={<PlusOutlined />} onClick={() => setVisible(true)} />,
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
<SchemaComponent
|
|
||||||
key={2}
|
|
||||||
schema={schemaJe}
|
|
||||||
components={{
|
|
||||||
DepartmentTable: DepartmentTable,
|
|
||||||
}}
|
|
||||||
scope={{
|
|
||||||
user,
|
|
||||||
useDataSource,
|
|
||||||
useAddDepartments,
|
|
||||||
useDisabled,
|
|
||||||
}}
|
|
||||||
/>,
|
|
||||||
],
|
|
||||||
});
|
|
||||||
};
|
|
@ -1,10 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
export interface FilterKeysContextProps {
|
|
||||||
expandedKeys: any[];
|
|
||||||
setExpandedKeys: any;
|
|
||||||
hasFilter: any;
|
|
||||||
setHasFilter: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const FilterKeysContext = React.createContext<Partial<FilterKeysContextProps>>({});
|
|
@ -1,30 +0,0 @@
|
|||||||
import { useContext } from 'react';
|
|
||||||
import { useAPIClient, useResourceActionContext } from '@tachybase/client';
|
|
||||||
import { RolesManagerContext } from '@tachybase/plugin-acl/client';
|
|
||||||
|
|
||||||
import { App } from 'antd';
|
|
||||||
|
|
||||||
import { useTranslation } from '../../../locale';
|
|
||||||
import { k } from '../others/k';
|
|
||||||
|
|
||||||
export const useBulkRemoveDepartmentsYyt = () => {
|
|
||||||
const { t: e } = useTranslation(),
|
|
||||||
{ message: t } = App.useApp(),
|
|
||||||
o = useAPIClient(),
|
|
||||||
{ state: a, setState: r, refresh: c } = useResourceActionContext(),
|
|
||||||
{ role: i } = useContext(RolesManagerContext);
|
|
||||||
return {
|
|
||||||
run() {
|
|
||||||
return k(this, null, function* () {
|
|
||||||
const m = a == null ? void 0 : a.selectedRowKeys;
|
|
||||||
if (!(m != null && m.length)) {
|
|
||||||
t.warning(e('Please select departments'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
yield o.resource(`roles/${i == null ? void 0 : i.name}/departments`).remove({ values: m }),
|
|
||||||
r == null || r({ selectedRowKeys: [] }),
|
|
||||||
c();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,30 +0,0 @@
|
|||||||
import { useContext } from 'react';
|
|
||||||
import { useAPIClient, useResourceActionContext } from '@tachybase/client';
|
|
||||||
|
|
||||||
import { App } from 'antd';
|
|
||||||
|
|
||||||
import { useTranslation } from '../../../locale';
|
|
||||||
import { DepartmentsContext } from '../context/DepartmentsContext';
|
|
||||||
import { k } from '../others/k';
|
|
||||||
|
|
||||||
export const useBulkRemoveMembersAction = () => {
|
|
||||||
const { t: e } = useTranslation(),
|
|
||||||
{ message: t } = App.useApp(),
|
|
||||||
o = useAPIClient(),
|
|
||||||
{ state: a, setState: r, refresh: c } = useResourceActionContext(),
|
|
||||||
{ department: i } = useContext(DepartmentsContext);
|
|
||||||
return {
|
|
||||||
run() {
|
|
||||||
return k(this, null, function* () {
|
|
||||||
const m = a == null ? void 0 : a.selectedRowKeys;
|
|
||||||
if (!(m != null && m.length)) {
|
|
||||||
t.warning(e('Please select members'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
yield o.resource('departments.members', i.id).remove({ values: m }),
|
|
||||||
r == null || r({ selectedRowKeys: [] }),
|
|
||||||
c();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,14 +0,0 @@
|
|||||||
import { useContext } from 'react';
|
|
||||||
import { RolesManagerContext } from '@tachybase/plugin-acl/client';
|
|
||||||
|
|
||||||
export const useDisabledVvt = () => {
|
|
||||||
const { role: e } = useContext(RolesManagerContext);
|
|
||||||
return {
|
|
||||||
disabled: (t) => {
|
|
||||||
let o;
|
|
||||||
return (o = t == null ? void 0 : t.roles) == null
|
|
||||||
? void 0
|
|
||||||
: o.some((a) => a.name === (e == null ? void 0 : e.name));
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,19 +0,0 @@
|
|||||||
import { useContext, useEffect } from 'react';
|
|
||||||
import { useResourceActionContext } from '@tachybase/client';
|
|
||||||
|
|
||||||
import { DepartmentsContext } from '../context/DepartmentsContext';
|
|
||||||
|
|
||||||
export const useMembersDataSource = (e) => {
|
|
||||||
const { user: t } = useContext(DepartmentsContext),
|
|
||||||
o = useResourceActionContext();
|
|
||||||
return (
|
|
||||||
useEffect(() => {
|
|
||||||
if (t) {
|
|
||||||
e == null || e.onSuccess({ data: [t] });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
o.loading || e == null || e.onSuccess(o.data);
|
|
||||||
}, [t, o.loading]),
|
|
||||||
o
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,19 +0,0 @@
|
|||||||
import { useContext } from 'react';
|
|
||||||
import { useAPIClient, useRecord, useResourceActionContext } from '@tachybase/client';
|
|
||||||
import { RolesManagerContext } from '@tachybase/plugin-acl/client';
|
|
||||||
|
|
||||||
import { k } from '../others/k';
|
|
||||||
|
|
||||||
export const useRemoveDepartmentXxt = () => {
|
|
||||||
const e = useAPIClient(),
|
|
||||||
{ role: t } = useContext(RolesManagerContext),
|
|
||||||
{ data: o } = useRecord(),
|
|
||||||
{ refresh: a } = useResourceActionContext();
|
|
||||||
return {
|
|
||||||
run() {
|
|
||||||
return k(this, null, function* () {
|
|
||||||
yield e.resource(`roles/${t == null ? void 0 : t.name}/departments`).remove({ values: [o.id] }), a();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,19 +0,0 @@
|
|||||||
import { useContext } from 'react';
|
|
||||||
import { useAPIClient, useRecord, useResourceActionContext } from '@tachybase/client';
|
|
||||||
|
|
||||||
import { DepartmentsContext } from '../context/DepartmentsContext';
|
|
||||||
import { k } from '../others/k';
|
|
||||||
|
|
||||||
export const useRemoveMemberAction = () => {
|
|
||||||
const e = useAPIClient(),
|
|
||||||
{ department: t } = useContext(DepartmentsContext),
|
|
||||||
{ id: o } = useRecord(),
|
|
||||||
{ refresh: a } = useResourceActionContext();
|
|
||||||
return {
|
|
||||||
run() {
|
|
||||||
return k(this, null, function* () {
|
|
||||||
yield e.resource('departments.members', t.id).remove({ values: [o] }), a();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,10 +0,0 @@
|
|||||||
import { useResourceActionContext } from '@tachybase/client';
|
|
||||||
|
|
||||||
import { useTranslation } from '../../../locale';
|
|
||||||
|
|
||||||
export const useShowTotal = () => {
|
|
||||||
var o;
|
|
||||||
const { data: e } = useResourceActionContext(),
|
|
||||||
{ t } = useTranslation();
|
|
||||||
return t('Total {{count}} members', { count: (o = e == null ? void 0 : e.meta) == null ? void 0 : o.count });
|
|
||||||
};
|
|
@ -1,45 +1,26 @@
|
|||||||
import React from 'react';
|
import { Plugin } from '@tachybase/client';
|
||||||
import { Plugin, SchemaComponentContext, useSchemaComponentContext } from '@tachybase/client';
|
|
||||||
import { PluginACLClient } from '@tachybase/plugin-acl/client';
|
|
||||||
|
|
||||||
import { tval } from '../../locale';
|
import { UserDepartmentsFieldNotSupport } from './common/UserDepartmentsFieldNotSupport';
|
||||||
import { DepartmentManagementComponent } from './components/DepartmentManagementComponent';
|
import { KitMainTabDepartments } from './main-tab/kit';
|
||||||
import { Departments } from './components/Departments';
|
import { KitRoleAuth } from './role-auth/kit';
|
||||||
import { DepartmentsProvider } from './components/DepartmentsProvider';
|
|
||||||
import { UserDepartmentsFieldNotSupport } from './components/UserDepartmentsFieldNotSupport';
|
|
||||||
import { DepartmentOwnersFieldSetting } from './settings/DepartmentOwnersFieldSetting';
|
import { DepartmentOwnersFieldSetting } from './settings/DepartmentOwnersFieldSetting';
|
||||||
import { UserDepartmentsFieldSetting } from './settings/UserDepartmentsFieldSetting';
|
import { UserDepartmentsFieldSetting } from './settings/UserDepartmentsFieldSetting';
|
||||||
import { UserMainDepartmentFieldSetting } from './settings/UserMainDepartmentFieldSetting';
|
import { UserMainDepartmentFieldSetting } from './settings/UserMainDepartmentFieldSetting';
|
||||||
|
|
||||||
export class DepartmentsPlugin extends Plugin {
|
export class DepartmentsPlugin extends Plugin {
|
||||||
|
async afterAdd() {
|
||||||
|
this.pm.add(KitMainTabDepartments);
|
||||||
|
this.pm.add(KitRoleAuth);
|
||||||
|
}
|
||||||
async load() {
|
async load() {
|
||||||
this.app.addComponents({
|
this.app.addComponents({
|
||||||
UserDepartmentsField: UserDepartmentsFieldNotSupport,
|
UserDepartmentsField: UserDepartmentsFieldNotSupport,
|
||||||
UserMainDepartmentField: UserDepartmentsFieldNotSupport,
|
UserMainDepartmentField: UserDepartmentsFieldNotSupport,
|
||||||
DepartmentOwnersField: UserDepartmentsFieldNotSupport,
|
DepartmentOwnersField: UserDepartmentsFieldNotSupport,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.app.schemaSettingsManager.add(UserDepartmentsFieldSetting);
|
this.app.schemaSettingsManager.add(UserDepartmentsFieldSetting);
|
||||||
this.app.schemaSettingsManager.add(UserMainDepartmentFieldSetting);
|
this.app.schemaSettingsManager.add(UserMainDepartmentFieldSetting);
|
||||||
this.app.schemaSettingsManager.add(DepartmentOwnersFieldSetting);
|
this.app.schemaSettingsManager.add(DepartmentOwnersFieldSetting);
|
||||||
this.app.pluginSettingsManager.add('users-permissions.departments', {
|
|
||||||
icon: 'ApartmentOutlined',
|
|
||||||
title: tval('Departments'),
|
|
||||||
Component: () => {
|
|
||||||
const context = useSchemaComponentContext();
|
|
||||||
return (
|
|
||||||
<SchemaComponentContext.Provider value={{ ...context, designable: false }}>
|
|
||||||
<DepartmentsProvider>
|
|
||||||
<DepartmentManagementComponent />
|
|
||||||
</DepartmentsProvider>
|
|
||||||
</SchemaComponentContext.Provider>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
sort: 2,
|
|
||||||
aclSnippet: 'pm.departments',
|
|
||||||
});
|
|
||||||
this.app.pm.get(PluginACLClient).rolesManager.add('departments', {
|
|
||||||
title: tval('Departments'),
|
|
||||||
Component: Departments,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,53 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { useRequest } from '@tachybase/client';
|
||||||
|
|
||||||
|
import { ProviderContextDepartments } from './context/Department.context';
|
||||||
|
|
||||||
|
export const ProviderDepartmentIndex = ({ children }) => {
|
||||||
|
const [user, setUser] = useState(null);
|
||||||
|
const [department, setDepartment] = useState(null);
|
||||||
|
const usersRequest = useRequest(
|
||||||
|
{
|
||||||
|
resource: 'users',
|
||||||
|
action: 'list',
|
||||||
|
params: {
|
||||||
|
appends: ['departments', 'departments.parent(recursively=true)'],
|
||||||
|
filter: department
|
||||||
|
? {
|
||||||
|
'departments.id': department.id,
|
||||||
|
}
|
||||||
|
: {},
|
||||||
|
pageSize: 50,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
manual: true,
|
||||||
|
refreshDeps: [department],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const departmentsRequest = useRequest({
|
||||||
|
resource: 'departments',
|
||||||
|
action: 'list',
|
||||||
|
params: {
|
||||||
|
pagination: false,
|
||||||
|
filter: {
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const ctxValue = {
|
||||||
|
user,
|
||||||
|
setUser,
|
||||||
|
department,
|
||||||
|
setDepartment,
|
||||||
|
usersResource: {
|
||||||
|
service: usersRequest,
|
||||||
|
},
|
||||||
|
departmentsResource: {
|
||||||
|
service: departmentsRequest,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return <ProviderContextDepartments value={ctxValue}>{children}</ProviderContextDepartments>;
|
||||||
|
};
|
@ -0,0 +1,17 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { SchemaComponentContext, useSchemaComponentContext } from '@tachybase/client';
|
||||||
|
|
||||||
|
import { ViewDepartmentManagement } from './DepartmentManagement.view';
|
||||||
|
import { ProviderDepartmentIndex } from './DepartmentIndex.provider';
|
||||||
|
|
||||||
|
// TODO: 名称有待重新确认
|
||||||
|
export const DepartmentIndex = () => {
|
||||||
|
const context = useSchemaComponentContext();
|
||||||
|
return (
|
||||||
|
<SchemaComponentContext.Provider value={{ ...context, designable: false }}>
|
||||||
|
<ProviderDepartmentIndex>
|
||||||
|
<ViewDepartmentManagement />
|
||||||
|
</ProviderDepartmentIndex>
|
||||||
|
</SchemaComponentContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,53 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { SchemaComponentOptions } from '@tachybase/client';
|
||||||
|
|
||||||
|
import { Col, Row } from 'antd';
|
||||||
|
|
||||||
|
import { useDepartmentFilterActionProps } from '../common/scopes/useDepartmentFilterActionProps';
|
||||||
|
import { DepartmentSelect } from './components/DepartmentSelect';
|
||||||
|
import { SuperiorDepartmentSelect } from './components/SuperiorDepartmentSelect';
|
||||||
|
import { DepartmentsBlock } from './departments-block/DepartmentsBlock';
|
||||||
|
import { ViewDepartmentsUsersBlock } from './departments-users-block/DepartmentsUsersBlock';
|
||||||
|
import { ProviderDepartmentsResource } from './providers/DepartmentsResource.provider';
|
||||||
|
import { ProviderUserResource } from './providers/UserResource.provider';
|
||||||
|
|
||||||
|
export const DepartmentManagement = () => (
|
||||||
|
<SchemaComponentOptions
|
||||||
|
components={{
|
||||||
|
SuperiorDepartmentSelect,
|
||||||
|
DepartmentSelect,
|
||||||
|
}}
|
||||||
|
scope={{
|
||||||
|
useFilterActionProps: useDepartmentFilterActionProps,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Row
|
||||||
|
gutter={48}
|
||||||
|
style={{
|
||||||
|
flexWrap: 'nowrap',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Col
|
||||||
|
span={6}
|
||||||
|
style={{
|
||||||
|
borderRight: '1px solid #eee',
|
||||||
|
minWidth: '300px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ProviderDepartmentsResource>
|
||||||
|
<DepartmentsBlock />
|
||||||
|
</ProviderDepartmentsResource>
|
||||||
|
</Col>
|
||||||
|
<Col
|
||||||
|
flex="auto"
|
||||||
|
style={{
|
||||||
|
overflow: 'hidden',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ProviderUserResource>
|
||||||
|
<ViewDepartmentsUsersBlock />
|
||||||
|
</ProviderUserResource>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</SchemaComponentOptions>
|
||||||
|
);
|
@ -0,0 +1,12 @@
|
|||||||
|
import { uid } from '@tachybase/schema';
|
||||||
|
|
||||||
|
export const schemaDepartmentManagement = {
|
||||||
|
type: 'void',
|
||||||
|
properties: {
|
||||||
|
[uid()]: {
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'CardItem',
|
||||||
|
'x-component': 'DepartmentManagement',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
@ -0,0 +1,16 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { SchemaComponent } from '@tachybase/client';
|
||||||
|
|
||||||
|
import { DepartmentManagement } from './DepartmentManagement.component';
|
||||||
|
import { schemaDepartmentManagement as schema } from './DepartmentManagement.schema';
|
||||||
|
|
||||||
|
export const ViewDepartmentManagement = () => {
|
||||||
|
return (
|
||||||
|
<SchemaComponent
|
||||||
|
schema={schema}
|
||||||
|
components={{
|
||||||
|
DepartmentManagement,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,14 @@
|
|||||||
|
import React, { useContext } from 'react';
|
||||||
|
|
||||||
|
import { ContextDepartments } from '../context/Department.context';
|
||||||
|
import { useGetDepTree } from '../hooks/useGetDepTree';
|
||||||
|
import { InternalSuperiorDepartmentSelect } from './InternalSuperiorDepartmentSelect';
|
||||||
|
|
||||||
|
export const DepartmentSelect = () => {
|
||||||
|
const depTree = useGetDepTree();
|
||||||
|
const { departmentsResource } = useContext(ContextDepartments);
|
||||||
|
const { service } = departmentsResource || {};
|
||||||
|
const { data } = service || {};
|
||||||
|
|
||||||
|
return <InternalSuperiorDepartmentSelect {...depTree} originData={data?.data} />;
|
||||||
|
};
|
@ -3,7 +3,7 @@ import { useField } from '@tachybase/schema';
|
|||||||
|
|
||||||
import { TreeSelect } from 'antd';
|
import { TreeSelect } from 'antd';
|
||||||
|
|
||||||
import { getDepartmentStr } from '../utils/getDepartmentStr';
|
import { getDepartmentStr } from '../../utils/getDepartmentStr';
|
||||||
|
|
||||||
interface tempField {
|
interface tempField {
|
||||||
value?: any;
|
value?: any;
|
||||||
@ -19,23 +19,30 @@ interface IState {
|
|||||||
export const InternalSuperiorDepartmentSelect = (props) => {
|
export const InternalSuperiorDepartmentSelect = (props) => {
|
||||||
const field = useField<tempField>();
|
const field = useField<tempField>();
|
||||||
const [value, setValue] = useState<IState>({ label: null, value: null });
|
const [value, setValue] = useState<IState>({ label: null, value: null });
|
||||||
|
|
||||||
const { treeData, initData, getByKeyword, loadData, loadedKeys, setLoadedKeys, originData } = props;
|
const { treeData, initData, getByKeyword, loadData, loadedKeys, setLoadedKeys, originData } = props;
|
||||||
const onSearch = async (h) => {
|
|
||||||
if (!h) {
|
const onSearch = async (keyword) => {
|
||||||
|
if (!keyword) {
|
||||||
initData(originData);
|
initData(originData);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await getByKeyword(h);
|
await getByKeyword(keyword);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
initData(originData);
|
initData(originData);
|
||||||
}, [originData, initData]);
|
}, [originData, initData]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!field.value) {
|
if (!field.value) {
|
||||||
setValue({ label: null, value: null });
|
setValue({
|
||||||
|
label: null,
|
||||||
|
value: null,
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setValue({
|
setValue({
|
||||||
label: getDepartmentStr(field.value) || field.value.label,
|
label: getDepartmentStr(field.value) || field.value.label,
|
||||||
value: field.value.id,
|
value: field.value.id,
|
||||||
@ -45,16 +52,21 @@ export const InternalSuperiorDepartmentSelect = (props) => {
|
|||||||
return (
|
return (
|
||||||
<TreeSelect
|
<TreeSelect
|
||||||
value={value}
|
value={value}
|
||||||
onSelect={(h, currValue) => {
|
onSelect={(value, currValue) => {
|
||||||
field.setValue(currValue);
|
field.setValue(currValue);
|
||||||
}}
|
}}
|
||||||
onChange={(h) => {
|
onChange={(value) => {
|
||||||
h || field.setValue(null);
|
value || field.setValue(null);
|
||||||
}}
|
}}
|
||||||
treeData={treeData}
|
treeData={treeData}
|
||||||
treeLoadedKeys={loadedKeys}
|
treeLoadedKeys={loadedKeys}
|
||||||
onTreeLoad={(keys) => setLoadedKeys(keys)}
|
onTreeLoad={(keys) => setLoadedKeys(keys)}
|
||||||
loadData={(value) => loadData({ key: value.id, children: value.children })}
|
loadData={(value) =>
|
||||||
|
loadData({
|
||||||
|
key: value.id,
|
||||||
|
children: value.children,
|
||||||
|
})
|
||||||
|
}
|
||||||
fieldNames={{ value: 'id' }}
|
fieldNames={{ value: 'id' }}
|
||||||
showSearch={true}
|
showSearch={true}
|
||||||
allowClear={true}
|
allowClear={true}
|
@ -1,27 +1,33 @@
|
|||||||
import React, { useContext, useEffect } from 'react';
|
import React, { useContext, useEffect } from 'react';
|
||||||
import { useRecord } from '@tachybase/client';
|
import { useRecord } from '@tachybase/client';
|
||||||
|
|
||||||
import { DepartmentsContext } from '../context/DepartmentsContext';
|
import { ContextDepartments } from '../context/Department.context';
|
||||||
import { useDepTree2 } from '../hooks/useDepTree2';
|
import { useGetDepTree } from '../hooks/useGetDepTree';
|
||||||
import { InternalSuperiorDepartmentSelect } from './InternalSuperiorDepartmentSelect';
|
import { InternalSuperiorDepartmentSelect } from './InternalSuperiorDepartmentSelect';
|
||||||
|
|
||||||
export const SuperiorDepartmentSelect = () => {
|
export const SuperiorDepartmentSelect = () => {
|
||||||
const depTree = useDepTree2();
|
const depTree = useGetDepTree();
|
||||||
const { setTreeData, getChildrenIds } = depTree;
|
const { setTreeData, getChildrenIds } = depTree;
|
||||||
const record = useRecord();
|
const record = useRecord();
|
||||||
const { departmentsResource } = useContext(DepartmentsContext);
|
const { departmentsResource } = useContext(ContextDepartments);
|
||||||
const {
|
const {
|
||||||
service: { data },
|
service: { data },
|
||||||
} = departmentsResource || {};
|
} = departmentsResource || {};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!record.id) return;
|
if (!record.id) return;
|
||||||
|
|
||||||
const ids = getChildrenIds(record.id);
|
const ids = getChildrenIds(record.id);
|
||||||
|
|
||||||
ids.push(record.id);
|
ids.push(record.id);
|
||||||
|
|
||||||
setTreeData((x) => {
|
setTreeData((x) => {
|
||||||
const m = (g) =>
|
const m = (g) =>
|
||||||
g.map((d) => (ids.includes(d.id) && (d.disabled = true), d.children && (d.children = m(d.children)), d));
|
g.map((d) => (ids.includes(d.id) && (d.disabled = true), d.children && (d.children = m(d.children)), d));
|
||||||
|
|
||||||
return m(x);
|
return m(x);
|
||||||
});
|
});
|
||||||
}, [setTreeData, record.id, getChildrenIds]);
|
}, [setTreeData, record.id, getChildrenIds]);
|
||||||
|
|
||||||
return <InternalSuperiorDepartmentSelect {...{ ...depTree, originData: data?.data }} />;
|
return <InternalSuperiorDepartmentSelect {...{ ...depTree, originData: data?.data }} />;
|
||||||
};
|
};
|
@ -20,13 +20,13 @@ interface contextType {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DepartmentsContext = React.createContext<contextType>({
|
export const ContextDepartments = React.createContext<contextType>({
|
||||||
user: {},
|
user: {},
|
||||||
department: {},
|
department: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const DepartmentsContextProvider = DepartmentsContext.Provider;
|
export const ProviderContextDepartments = ContextDepartments.Provider;
|
||||||
|
|
||||||
export function useDepartments() {
|
export function useContextDepartments() {
|
||||||
return useContext(DepartmentsContext);
|
return useContext(ContextDepartments);
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
|
|
||||||
export interface DepartmentsExpandedProps {
|
interface DepartmentsExpandedProps {
|
||||||
initData: (C: any) => void;
|
initData: (C: any) => void;
|
||||||
treeData: any[];
|
treeData: any[];
|
||||||
setTreeData: React.Dispatch<React.SetStateAction<any[]>>;
|
setTreeData: React.Dispatch<React.SetStateAction<any[]>>;
|
||||||
@ -14,10 +14,10 @@ export interface DepartmentsExpandedProps {
|
|||||||
setExpandedKeys: React.Dispatch<React.SetStateAction<any[]>>;
|
setExpandedKeys: React.Dispatch<React.SetStateAction<any[]>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DepartmentsExpandedContext = React.createContext<Partial<DepartmentsExpandedProps>>({});
|
const ContextDepartmentsExpanded = React.createContext<Partial<DepartmentsExpandedProps>>({});
|
||||||
|
|
||||||
export const DepartmentsExpandedContextProvider = DepartmentsExpandedContext.Provider;
|
export const ProviderContextDepartmentsExpanded = ContextDepartmentsExpanded.Provider;
|
||||||
|
|
||||||
export function useDepartmentsExpanded() {
|
export function useContextDepartmentsExpanded() {
|
||||||
return useContext(DepartmentsExpandedContext);
|
return useContext(ContextDepartmentsExpanded);
|
||||||
}
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
import { tval } from '../../../../locale';
|
||||||
|
|
||||||
|
export const getSchemaAddNewDepartment = () => {
|
||||||
|
return {
|
||||||
|
type: 'void',
|
||||||
|
properties: {
|
||||||
|
newDepartment: {
|
||||||
|
type: 'void',
|
||||||
|
title: tval('New department'),
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': { type: 'text', icon: 'PlusOutlined', style: { width: '100%', textAlign: 'left' } },
|
||||||
|
properties: {
|
||||||
|
drawer: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Action.Drawer',
|
||||||
|
'x-decorator': 'Form',
|
||||||
|
title: tval('New department'),
|
||||||
|
properties: {
|
||||||
|
title: { 'x-component': 'CollectionField', 'x-decorator': 'FormItem', required: true },
|
||||||
|
parent: {
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-collection-field': 'departments.parent',
|
||||||
|
'x-component-props': { component: 'DepartmentSelect' },
|
||||||
|
},
|
||||||
|
roles: {
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-collection-field': 'departments.roles',
|
||||||
|
},
|
||||||
|
footer: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Action.Drawer.Footer',
|
||||||
|
properties: {
|
||||||
|
cancel: {
|
||||||
|
title: '{{t("Cancel")}}',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': { useAction: '{{ cm.useCancelAction }}' },
|
||||||
|
},
|
||||||
|
submit: {
|
||||||
|
title: '{{t("Submit")}}',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': { type: 'primary', useAction: '{{ useCreateDepartment }}' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,9 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { SchemaComponent } from '@tachybase/client';
|
||||||
|
|
||||||
|
import { getSchemaAddNewDepartment } from './AddNewDepartment.schema';
|
||||||
|
|
||||||
|
export const AddNewDepartment = () => {
|
||||||
|
const schema = getSchemaAddNewDepartment();
|
||||||
|
return <SchemaComponent schema={schema}></SchemaComponent>;
|
||||||
|
};
|
@ -2,9 +2,7 @@ import { useEffect } from 'react';
|
|||||||
import { useActionContext, useAPIClient, useRecord, useRequest } from '@tachybase/client';
|
import { useActionContext, useAPIClient, useRecord, useRequest } from '@tachybase/client';
|
||||||
import { uid } from '@tachybase/schema';
|
import { uid } from '@tachybase/schema';
|
||||||
|
|
||||||
import { T } from '../others/T';
|
export const schemaDepartmentEdit = {
|
||||||
|
|
||||||
export const schemaHhe = {
|
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
[uid()]: {
|
[uid()]: {
|
||||||
@ -12,24 +10,28 @@ export const schemaHhe = {
|
|||||||
'x-component': 'Action.Drawer',
|
'x-component': 'Action.Drawer',
|
||||||
'x-decorator': 'Form',
|
'x-decorator': 'Form',
|
||||||
'x-decorator-props': {
|
'x-decorator-props': {
|
||||||
useValues(e) {
|
useValues(options) {
|
||||||
const t = useAPIClient(),
|
const API = useAPIClient();
|
||||||
o = useActionContext(),
|
const ctx = useActionContext();
|
||||||
a = useRecord(),
|
const record = useRecord();
|
||||||
r = useRequest(
|
const result = useRequest(
|
||||||
() =>
|
() =>
|
||||||
t
|
API.resource('departments')
|
||||||
.resource('departments')
|
.get({
|
||||||
.get({ filterByTk: a.id, appends: ['parent(recursively=true)', 'roles', 'owners'] })
|
filterByTk: record.id,
|
||||||
.then((c) => (c == null ? void 0 : c.data)),
|
appends: ['parent(recursively=true)', 'roles', 'owners'],
|
||||||
T({ ...e }, { manual: true }),
|
})
|
||||||
);
|
.then((res) => res?.data),
|
||||||
return (
|
{
|
||||||
useEffect(() => {
|
...options,
|
||||||
o.visible && r.run();
|
manual: true,
|
||||||
}, [o.visible]),
|
},
|
||||||
r
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
ctx.visible && result.run();
|
||||||
|
}, [ctx.visible]);
|
||||||
|
return result;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
title: '{{t("Edit department")}}',
|
title: '{{t("Edit department")}}',
|
||||||
@ -39,14 +41,20 @@ export const schemaHhe = {
|
|||||||
'x-component': 'CollectionField',
|
'x-component': 'CollectionField',
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-collection-field': 'departments.parent',
|
'x-collection-field': 'departments.parent',
|
||||||
'x-component-props': { component: 'SuperiorDepartmentSelect' },
|
'x-component-props': {
|
||||||
|
component: 'SuperiorDepartmentSelect',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
roles: {
|
roles: {
|
||||||
'x-component': 'CollectionField',
|
'x-component': 'CollectionField',
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-collection-field': 'departments.roles',
|
'x-collection-field': 'departments.roles',
|
||||||
},
|
},
|
||||||
owners: { title: '{{t("Owners")}}', 'x-component': 'DepartmentOwnersField', 'x-decorator': 'FormItem' },
|
owners: {
|
||||||
|
title: '{{t("Owners")}}',
|
||||||
|
'x-component': 'DepartmentOwnersField',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
},
|
||||||
footer: {
|
footer: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Action.Drawer.Footer',
|
'x-component': 'Action.Drawer.Footer',
|
||||||
@ -54,12 +62,17 @@ export const schemaHhe = {
|
|||||||
cancel: {
|
cancel: {
|
||||||
title: '{{t("Cancel")}}',
|
title: '{{t("Cancel")}}',
|
||||||
'x-component': 'Action',
|
'x-component': 'Action',
|
||||||
'x-component-props': { useAction: '{{ cm.useCancelAction }}' },
|
'x-component-props': {
|
||||||
|
useAction: '{{ cm.useCancelAction }}',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
submit: {
|
submit: {
|
||||||
title: '{{t("Submit")}}',
|
title: '{{t("Submit")}}',
|
||||||
'x-component': 'Action',
|
'x-component': 'Action',
|
||||||
'x-component-props': { type: 'primary', useAction: '{{ useUpdateDepartment }}' },
|
'x-component-props': {
|
||||||
|
type: 'primary',
|
||||||
|
useAction: '{{ useUpdateDepartment }}',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
@ -1,33 +1,44 @@
|
|||||||
import { useActionContext, useRecord, useRequest } from '@tachybase/client';
|
import { useActionContext, useRecord, useRequest } from '@tachybase/client';
|
||||||
import { uid } from '@tachybase/schema';
|
import { uid } from '@tachybase/schema';
|
||||||
|
|
||||||
import { T } from '../others/T';
|
export const schemaDepartmentNewSub = {
|
||||||
|
|
||||||
export const schemaYye = {
|
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
[uid()]: {
|
[uid()]: {
|
||||||
|
title: '{{t("New sub department")}}',
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Action.Drawer',
|
'x-component': 'Action.Drawer',
|
||||||
'x-decorator': 'Form',
|
'x-decorator': 'Form',
|
||||||
'x-decorator-props': {
|
'x-decorator-props': {
|
||||||
useValues(e) {
|
useValues(options) {
|
||||||
const t = useActionContext(),
|
const ctx = useActionContext();
|
||||||
o = useRecord();
|
const record = useRecord();
|
||||||
return useRequest(
|
return useRequest(
|
||||||
() => Promise.resolve({ data: { parent: { ...o } } }),
|
() =>
|
||||||
T({ ...e }, { refreshDeps: [t.visible] }),
|
Promise.resolve({
|
||||||
|
data: {
|
||||||
|
parent: { ...record },
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
...options,
|
||||||
|
refreshDeps: [ctx.visible],
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
title: '{{t("New sub department")}}',
|
|
||||||
properties: {
|
properties: {
|
||||||
title: { 'x-component': 'CollectionField', 'x-decorator': 'FormItem' },
|
title: {
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
},
|
||||||
parent: {
|
parent: {
|
||||||
'x-component': 'CollectionField',
|
'x-component': 'CollectionField',
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-collection-field': 'departments.parent',
|
'x-collection-field': 'departments.parent',
|
||||||
'x-component-props': { component: 'DepartmentSelect' },
|
'x-component-props': {
|
||||||
|
component: 'DepartmentSelect',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
roles: {
|
roles: {
|
||||||
'x-component': 'CollectionField',
|
'x-component': 'CollectionField',
|
||||||
@ -41,12 +52,17 @@ export const schemaYye = {
|
|||||||
cancel: {
|
cancel: {
|
||||||
title: '{{t("Cancel")}}',
|
title: '{{t("Cancel")}}',
|
||||||
'x-component': 'Action',
|
'x-component': 'Action',
|
||||||
'x-component-props': { useAction: '{{ cm.useCancelAction }}' },
|
'x-component-props': {
|
||||||
|
useAction: '{{ cm.useCancelAction }}',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
submit: {
|
submit: {
|
||||||
title: '{{t("Submit")}}',
|
title: '{{t("Submit")}}',
|
||||||
'x-component': 'Action',
|
'x-component': 'Action',
|
||||||
'x-component-props': { type: 'primary', useAction: '{{ useCreateDepartment }}' },
|
'x-component-props': {
|
||||||
|
type: 'primary',
|
||||||
|
useAction: '{{ useCreateDepartment }}',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
@ -0,0 +1,67 @@
|
|||||||
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
|
import { ActionContextProvider, useActionContext, useRecord } from '@tachybase/client';
|
||||||
|
import { useField } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { Select } from 'antd';
|
||||||
|
|
||||||
|
import { ViewUnKnownOwerns } from './UnknownOwerns.view';
|
||||||
|
|
||||||
|
export const DepartmentOwnersField = () => {
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
const record = useRecord();
|
||||||
|
const field: any = useField();
|
||||||
|
const [value, setValue] = useState([]);
|
||||||
|
const ref = useRef([]);
|
||||||
|
|
||||||
|
const handleSelect = (d, currValue) => {
|
||||||
|
ref.current = currValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
const useSelectOwners = () => {
|
||||||
|
const { setVisible: setVisible } = useActionContext();
|
||||||
|
return {
|
||||||
|
run() {
|
||||||
|
const fieldValue = field.value || [];
|
||||||
|
field.setValue([...fieldValue, ...ref.current]);
|
||||||
|
ref.current = [];
|
||||||
|
setVisible(false);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (field.value) {
|
||||||
|
const fieldValue = field.value.map((item) => ({
|
||||||
|
value: item.id,
|
||||||
|
label: item.nickname || item.username,
|
||||||
|
}));
|
||||||
|
setValue(fieldValue);
|
||||||
|
}
|
||||||
|
}, [field.value]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ActionContextProvider value={{ visible, setVisible }}>
|
||||||
|
<Select
|
||||||
|
open={false}
|
||||||
|
mode={'multiple'}
|
||||||
|
value={value}
|
||||||
|
labelInValue={true}
|
||||||
|
onChange={(params) => {
|
||||||
|
if (!params) {
|
||||||
|
field.setValue([]);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
const values = params.map(({ label, value }) => ({
|
||||||
|
id: value,
|
||||||
|
nickname: label,
|
||||||
|
}));
|
||||||
|
|
||||||
|
field.setValue(values);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onDropdownVisibleChange={(visible) => setVisible(visible)}
|
||||||
|
/>
|
||||||
|
<ViewUnKnownOwerns record={record} field={field} handleSelect={handleSelect} useSelectOwners={useSelectOwners} />
|
||||||
|
</ActionContextProvider>
|
||||||
|
);
|
||||||
|
};
|
@ -4,34 +4,36 @@ import { ActionContextProvider, RecordProvider, SchemaComponent, SchemaComponent
|
|||||||
import { UserOutlined } from '@ant-design/icons';
|
import { UserOutlined } from '@ant-design/icons';
|
||||||
import { Button, Divider, Row, theme } from 'antd';
|
import { Button, Divider, Row, theme } from 'antd';
|
||||||
|
|
||||||
import { useTranslation } from '../../../locale';
|
import { useTranslation } from '../../../../locale';
|
||||||
import { DepartmentsContext } from '../context/DepartmentsContext';
|
import { ContextDepartments } from '../context/Department.context';
|
||||||
import { DepartmentsExpandedContextProvider } from '../context/DepartmentsExpandedContext';
|
import { ProviderContextDepartmentsExpanded } from '../context/DepartmentsExpanded.context';
|
||||||
import { useCreateDepartment } from '../hooks/useCreateDepartment';
|
import { useGetDepTree } from '../hooks/useGetDepTree';
|
||||||
import { useDepTree2 } from '../hooks/useDepTree2';
|
import { AddNewDepartment } from './AddNewDepartment.view';
|
||||||
import { useUpdateDepartment } from '../hooks/useUpdateDepartment';
|
import { DepartmentOwnersField } from './DepartmentOwnersField.component';
|
||||||
import { DepartmentsTree } from './ComponentSe';
|
import { DepartmentsSearch } from './DepartmentsSearch.component';
|
||||||
import { ComponentX } from './ComponentX';
|
import { DepartmentsTree } from './DepartmentsTree.component';
|
||||||
import { DepartmentOwnersField } from './DepartmentOwnersField';
|
import { useCreateDepartment } from './useCreateDepartment';
|
||||||
import { NewDepartment } from './NewDepartment';
|
import { useUpdateDepartment } from './useUpdateDepartment';
|
||||||
|
|
||||||
interface drawerState {
|
interface drawerState {
|
||||||
node?: object;
|
node?: object;
|
||||||
schema?: object;
|
schema?: object;
|
||||||
}
|
}
|
||||||
|
// NOTE: 部门左边-部门列表部分
|
||||||
export const DepartmentsBlock = () => {
|
export const DepartmentsBlock = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const [drawer, setDrawer] = useState<drawerState>({});
|
const [drawer, setDrawer] = useState<drawerState>({});
|
||||||
|
|
||||||
const { department, setDepartment } = useContext(DepartmentsContext);
|
const { department, setDepartment } = useContext(ContextDepartments);
|
||||||
const { token } = theme.useToken();
|
const { token } = theme.useToken();
|
||||||
const m = useDepTree2({
|
const value = useGetDepTree({
|
||||||
label: ({ node }) => <ComponentX.Item node={node} setVisible={setVisible} setDrawer={setDrawer} />,
|
label: ({ node }) => <DepartmentsTree.Item node={node} setVisible={setVisible} setDrawer={setDrawer} />,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const schema = drawer.schema || {};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SchemaComponentOptions
|
<SchemaComponentOptions
|
||||||
scope={{
|
scope={{
|
||||||
@ -39,9 +41,9 @@ export const DepartmentsBlock = () => {
|
|||||||
useUpdateDepartment,
|
useUpdateDepartment,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DepartmentsExpandedContextProvider value={m}>
|
<ProviderContextDepartmentsExpanded value={value}>
|
||||||
<Row>
|
<Row>
|
||||||
<DepartmentsTree />
|
<DepartmentsSearch />
|
||||||
<Button
|
<Button
|
||||||
type="text"
|
type="text"
|
||||||
icon={<UserOutlined />}
|
icon={<UserOutlined />}
|
||||||
@ -57,10 +59,10 @@ export const DepartmentsBlock = () => {
|
|||||||
>
|
>
|
||||||
{t('All users')}
|
{t('All users')}
|
||||||
</Button>
|
</Button>
|
||||||
<NewDepartment />
|
<AddNewDepartment />
|
||||||
</Row>
|
</Row>
|
||||||
<Divider style={{ margin: '12px 0' }} />
|
<Divider style={{ margin: '12px 0' }} />
|
||||||
<ComponentX />
|
<DepartmentsTree />
|
||||||
<ActionContextProvider
|
<ActionContextProvider
|
||||||
value={{
|
value={{
|
||||||
visible,
|
visible,
|
||||||
@ -69,17 +71,14 @@ export const DepartmentsBlock = () => {
|
|||||||
>
|
>
|
||||||
<RecordProvider record={drawer.node || {}}>
|
<RecordProvider record={drawer.node || {}}>
|
||||||
<SchemaComponent
|
<SchemaComponent
|
||||||
scope={{
|
schema={schema}
|
||||||
t,
|
|
||||||
}}
|
|
||||||
components={{
|
components={{
|
||||||
DepartmentOwnersField,
|
DepartmentOwnersField,
|
||||||
}}
|
}}
|
||||||
schema={drawer.schema || {}}
|
|
||||||
/>
|
/>
|
||||||
</RecordProvider>
|
</RecordProvider>
|
||||||
</ActionContextProvider>
|
</ActionContextProvider>
|
||||||
</DepartmentsExpandedContextProvider>
|
</ProviderContextDepartmentsExpanded>
|
||||||
</SchemaComponentOptions>
|
</SchemaComponentOptions>
|
||||||
);
|
);
|
||||||
};
|
};
|
@ -0,0 +1,190 @@
|
|||||||
|
import React, { useContext, useState } from 'react';
|
||||||
|
import { createStyles, useAPIClient, useRequest } from '@tachybase/client';
|
||||||
|
|
||||||
|
import { Button, Dropdown, Empty, Input, theme } from 'antd';
|
||||||
|
|
||||||
|
import { useTranslation } from '../../../../locale';
|
||||||
|
import { ContextDepartments } from '../context/Department.context';
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css }) => ({
|
||||||
|
searchDropdown: css`
|
||||||
|
.ant-dropdown-menu {
|
||||||
|
max-height: 500px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
}));
|
||||||
|
// NOTE: 左边部门搜索组件
|
||||||
|
export const DepartmentsSearch = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { token } = theme.useToken();
|
||||||
|
const { styles } = useStyles();
|
||||||
|
const limit = 10;
|
||||||
|
const api = useAPIClient();
|
||||||
|
|
||||||
|
const { setDepartment, setUser } = useContext(ContextDepartments);
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const [keyword, setKeyword] = useState('');
|
||||||
|
const [users, setUsers] = useState([]);
|
||||||
|
const [departments, setDepartments] = useState([]);
|
||||||
|
const [isUsersBeyond, setIsUsersBeyond] = useState(true);
|
||||||
|
const [isDepartmentBeyond, setIsDepartmentBeyond] = useState(true);
|
||||||
|
|
||||||
|
const data = useRequest(
|
||||||
|
(params) =>
|
||||||
|
api
|
||||||
|
.resource('departments')
|
||||||
|
.aggregateSearch(params)
|
||||||
|
.then((result) => result?.data?.data),
|
||||||
|
{
|
||||||
|
manual: true,
|
||||||
|
onSuccess: (data, params) => {
|
||||||
|
const { values } = params[0] || {};
|
||||||
|
const { type } = values || {};
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
if (!type || (type === 'user' && data.users.length < limit)) {
|
||||||
|
setIsUsersBeyond(false);
|
||||||
|
}
|
||||||
|
if (!type || (type === 'department' && data.departments.length < limit)) {
|
||||||
|
setIsDepartmentBeyond(false);
|
||||||
|
}
|
||||||
|
setUsers((prev) => [...prev, ...data.users]);
|
||||||
|
setDepartments((prev) => [...prev, ...data.departments]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const { run } = data;
|
||||||
|
const onSearch = (keyword) => {
|
||||||
|
setKeyword(keyword);
|
||||||
|
setUsers([]);
|
||||||
|
setDepartments([]);
|
||||||
|
setIsUsersBeyond(true);
|
||||||
|
setIsDepartmentBeyond(true);
|
||||||
|
if (keyword) {
|
||||||
|
run({ values: { keyword, limit } });
|
||||||
|
setOpen(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const onChange = (event) => {
|
||||||
|
if (!event.target.value) {
|
||||||
|
setUser(null);
|
||||||
|
setKeyword('');
|
||||||
|
setOpen(false);
|
||||||
|
data.mutate({});
|
||||||
|
setUsers([]);
|
||||||
|
setDepartments([]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const NodeLabel = (node) => {
|
||||||
|
const title = node.title;
|
||||||
|
const parent = node.parent;
|
||||||
|
return parent ? NodeLabel(parent) + ' / ' + title : title;
|
||||||
|
};
|
||||||
|
const LinkButton = (params) => (
|
||||||
|
<Button
|
||||||
|
type="link"
|
||||||
|
style={{ padding: '0 8px' }}
|
||||||
|
onClick={(P) => {
|
||||||
|
setOpen(true);
|
||||||
|
run({
|
||||||
|
values: {
|
||||||
|
keyword,
|
||||||
|
limit,
|
||||||
|
...params,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('Load more')}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
const getItems = () => {
|
||||||
|
const resultItems = [];
|
||||||
|
return !users.length && !departments.length
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
key: '0',
|
||||||
|
label: <Empty description={t('No results')} image={Empty.PRESENTED_IMAGE_SIMPLE} />,
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: (users.length &&
|
||||||
|
(resultItems.push({
|
||||||
|
key: '0',
|
||||||
|
type: 'group',
|
||||||
|
label: t('Users'),
|
||||||
|
children: users.map((userInfo) => ({
|
||||||
|
key: userInfo.username,
|
||||||
|
label: (
|
||||||
|
<div onClick={() => {}}>
|
||||||
|
<div>{userInfo.nickname || userInfo.username}</div>,
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontSize: token.fontSizeSM,
|
||||||
|
color: token.colorTextDescription,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{`${userInfo.username}${userInfo.phone ? ' | ' + userInfo.phone : ''}${userInfo.email ? ' | ' + userInfo.email : ''}`}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
})),
|
||||||
|
}),
|
||||||
|
isUsersBeyond &&
|
||||||
|
resultItems.push({
|
||||||
|
type: 'group',
|
||||||
|
key: '0-loadMore',
|
||||||
|
label: <LinkButton type="user" last={users[users.length - 1].id} />,
|
||||||
|
})),
|
||||||
|
departments.length &&
|
||||||
|
(resultItems.push({
|
||||||
|
key: '1',
|
||||||
|
type: 'group',
|
||||||
|
label: t('Departments'),
|
||||||
|
children: departments.map((departmentInfo) => ({
|
||||||
|
key: departmentInfo.id,
|
||||||
|
label: (
|
||||||
|
<div
|
||||||
|
onClick={() => {
|
||||||
|
setDepartment(departmentInfo);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{NodeLabel(departmentInfo)}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
})),
|
||||||
|
}),
|
||||||
|
isDepartmentBeyond &&
|
||||||
|
resultItems.push({
|
||||||
|
type: 'group',
|
||||||
|
key: '1-loadMore',
|
||||||
|
label: <LinkButton type="department" last={departments[departments.length - 1].id} />,
|
||||||
|
})),
|
||||||
|
resultItems);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Dropdown
|
||||||
|
menu={{
|
||||||
|
items: getItems(),
|
||||||
|
}}
|
||||||
|
overlayClassName={styles.searchDropdown}
|
||||||
|
trigger={['click']}
|
||||||
|
open={open}
|
||||||
|
onOpenChange={(open) => setOpen(open)}
|
||||||
|
>
|
||||||
|
<Input.Search
|
||||||
|
allowClear
|
||||||
|
onClick={() => {
|
||||||
|
keyword || setOpen(false);
|
||||||
|
}}
|
||||||
|
onFocus={() => setDepartment(null)}
|
||||||
|
onSearch={onSearch}
|
||||||
|
onChange={onChange}
|
||||||
|
placeholder={t('Search for departments, users')}
|
||||||
|
style={{ marginBottom: '20px' }}
|
||||||
|
/>
|
||||||
|
</Dropdown>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,164 @@
|
|||||||
|
import React, { useContext, useEffect } from 'react';
|
||||||
|
import { css, useAPIClient, useResourceActionContext } from '@tachybase/client';
|
||||||
|
|
||||||
|
import { MoreOutlined } from '@ant-design/icons';
|
||||||
|
import { App, Dropdown, Empty, Tree } from 'antd';
|
||||||
|
|
||||||
|
import { useTranslation } from '../../../../locale';
|
||||||
|
import { schemaDepartmentEdit } from './DepartmentEdit.schema';
|
||||||
|
import { schemaDepartmentNewSub } from './DepartmentNewSub.schema';
|
||||||
|
import { ContextDepartments } from '../context/Department.context';
|
||||||
|
import { useContextDepartmentsExpanded } from '../context/DepartmentsExpanded.context';
|
||||||
|
|
||||||
|
// 部门左边-部门列表
|
||||||
|
export const DepartmentsTree = () => {
|
||||||
|
const { data, loading } = useResourceActionContext();
|
||||||
|
const { department, setDepartment, setUser } = useContext(ContextDepartments);
|
||||||
|
const { treeData, nodeMap, loadData, loadedKeys, setLoadedKeys, initData, expandedKeys, setExpandedKeys } =
|
||||||
|
useContextDepartmentsExpanded() as any;
|
||||||
|
|
||||||
|
const onSelect = (keys) => {
|
||||||
|
if (!keys.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const department = nodeMap[keys[0]];
|
||||||
|
setDepartment(department);
|
||||||
|
setUser(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onExpand = (key) => {
|
||||||
|
setExpandedKeys(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onLoad = (key) => {
|
||||||
|
setLoadedKeys(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
initData(data?.data);
|
||||||
|
}, [data, initData, loading]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!department) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getDepartmentIds = (department) =>
|
||||||
|
department.parent ? [department.parent.id, ...getDepartmentIds(department.parent)] : [];
|
||||||
|
|
||||||
|
const departmentIds = getDepartmentIds(department);
|
||||||
|
|
||||||
|
setExpandedKeys((keys) => Array.from(new Set([...keys, ...departmentIds])));
|
||||||
|
}, [department, setExpandedKeys]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={css`
|
||||||
|
height: 57vh;
|
||||||
|
overflow: auto;
|
||||||
|
.ant-tree-node-content-wrapper {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
{treeData?.length ? (
|
||||||
|
<Tree.DirectoryTree
|
||||||
|
loadData={loadData}
|
||||||
|
treeData={treeData}
|
||||||
|
loadedKeys={loadedKeys}
|
||||||
|
onSelect={onSelect}
|
||||||
|
selectedKeys={[department?.id]}
|
||||||
|
onExpand={onExpand}
|
||||||
|
onLoad={onLoad}
|
||||||
|
expandedKeys={expandedKeys}
|
||||||
|
expandAction={false}
|
||||||
|
showIcon={false}
|
||||||
|
fieldNames={{ key: 'id' }}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
DepartmentsTree.Item = ({ node, setVisible, setDrawer }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { refreshAsync } = useResourceActionContext();
|
||||||
|
const { setLoadedKeys, expandedKeys, setExpandedKeys } = useContextDepartmentsExpanded();
|
||||||
|
const { modal, message } = App.useApp();
|
||||||
|
const API = useAPIClient();
|
||||||
|
const showModalDelete = () => {
|
||||||
|
modal.confirm({
|
||||||
|
title: t('Delete'),
|
||||||
|
content: t('Are you sure you want to delete it?'),
|
||||||
|
onOk: async () => {
|
||||||
|
await API.resource('departments').destroy({ filterByTk: node.id });
|
||||||
|
|
||||||
|
message.success(t('Deleted successfully'));
|
||||||
|
|
||||||
|
setExpandedKeys((keys) => keys.filter((target) => target !== node.id));
|
||||||
|
|
||||||
|
const newExpandedKeys = [...expandedKeys];
|
||||||
|
|
||||||
|
setLoadedKeys([]);
|
||||||
|
setExpandedKeys([]);
|
||||||
|
|
||||||
|
await refreshAsync();
|
||||||
|
|
||||||
|
setExpandedKeys(newExpandedKeys);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const setSchema = (schema) => {
|
||||||
|
setDrawer({ schema, node });
|
||||||
|
setVisible(true);
|
||||||
|
};
|
||||||
|
const onClick: any = ({ key, domeEvent }) => {
|
||||||
|
domeEvent.stopPropagation();
|
||||||
|
switch (key) {
|
||||||
|
case 'new-sub':
|
||||||
|
setSchema(schemaDepartmentNewSub);
|
||||||
|
break;
|
||||||
|
case 'edit':
|
||||||
|
setSchema(schemaDepartmentEdit);
|
||||||
|
break;
|
||||||
|
case 'delete':
|
||||||
|
showModalDelete();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
overflow: 'hidden',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{node.title}
|
||||||
|
</div>
|
||||||
|
<Dropdown
|
||||||
|
menu={{
|
||||||
|
items: [
|
||||||
|
{ label: t('New sub department'), key: 'new-sub' },
|
||||||
|
{ label: t('Edit department'), key: 'edit' },
|
||||||
|
{ label: t('Delete department'), key: 'delete' },
|
||||||
|
],
|
||||||
|
onClick,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ marginLeft: '15px' }}>
|
||||||
|
<MoreOutlined />
|
||||||
|
</div>
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,27 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { ResourceActionProvider } from '@tachybase/client';
|
||||||
|
|
||||||
|
export const ProviderRequest = (props) => {
|
||||||
|
const { field, record, children } = props;
|
||||||
|
return (
|
||||||
|
// @ts-ignore
|
||||||
|
<ResourceActionProvider
|
||||||
|
collection={'users'}
|
||||||
|
request={{
|
||||||
|
resource: `departments/${record.id}/members`,
|
||||||
|
action: 'list',
|
||||||
|
params: {
|
||||||
|
filter: field.value.length
|
||||||
|
? {
|
||||||
|
id: {
|
||||||
|
$notIn: field.value.map((fieldValue) => fieldValue.id),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</ResourceActionProvider>
|
||||||
|
);
|
||||||
|
};
|
@ -1,4 +1,4 @@
|
|||||||
export const schemaFfe = {
|
export const schemaUnknownOwerns = {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
properties: {
|
properties: {
|
||||||
drawer: {
|
drawer: {
|
||||||
@ -13,16 +13,35 @@ export const schemaFfe = {
|
|||||||
actions: {
|
actions: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'ActionBar',
|
'x-component': 'ActionBar',
|
||||||
'x-component-props': { style: { marginBottom: 16 } },
|
'x-component-props': {
|
||||||
|
style: {
|
||||||
|
marginBottom: 16,
|
||||||
|
},
|
||||||
|
},
|
||||||
properties: {
|
properties: {
|
||||||
filter: {
|
filter: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '{{ t("Filter") }}',
|
title: '{{ t("Filter") }}',
|
||||||
default: { $and: [{ username: { $includes: '' } }, { nickname: { $includes: '' } }] },
|
default: {
|
||||||
|
$and: [
|
||||||
|
{
|
||||||
|
username: {
|
||||||
|
$includes: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nickname: {
|
||||||
|
$includes: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
'x-action': 'filter',
|
'x-action': 'filter',
|
||||||
'x-component': 'Filter.Action',
|
'x-component': 'Filter.Action',
|
||||||
'x-use-component-props': 'useFilterActionProps',
|
'x-use-component-props': 'useFilterActionProps',
|
||||||
'x-component-props': { icon: 'FilterOutlined' },
|
'x-component-props': {
|
||||||
|
icon: 'FilterOutlined',
|
||||||
|
},
|
||||||
'x-align': 'left',
|
'x-align': 'left',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -32,7 +51,10 @@ export const schemaFfe = {
|
|||||||
'x-component': 'Table.Void',
|
'x-component': 'Table.Void',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
rowKey: 'id',
|
rowKey: 'id',
|
||||||
rowSelection: { type: 'checkbox', onChange: '{{ handleSelect }}' },
|
rowSelection: {
|
||||||
|
type: 'checkbox',
|
||||||
|
onChange: '{{ handleSelect }}',
|
||||||
|
},
|
||||||
useDataSource: '{{ cm.useDataSourceFromRAC }}',
|
useDataSource: '{{ cm.useDataSourceFromRAC }}',
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
@ -41,7 +63,11 @@ export const schemaFfe = {
|
|||||||
'x-decorator': 'Table.Column.Decorator',
|
'x-decorator': 'Table.Column.Decorator',
|
||||||
'x-component': 'Table.Column',
|
'x-component': 'Table.Column',
|
||||||
properties: {
|
properties: {
|
||||||
username: { type: 'string', 'x-component': 'CollectionField', 'x-read-pretty': true },
|
username: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-read-pretty': true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
nickname: {
|
nickname: {
|
||||||
@ -49,20 +75,36 @@ export const schemaFfe = {
|
|||||||
'x-decorator': 'Table.Column.Decorator',
|
'x-decorator': 'Table.Column.Decorator',
|
||||||
'x-component': 'Table.Column',
|
'x-component': 'Table.Column',
|
||||||
properties: {
|
properties: {
|
||||||
nickname: { type: 'string', 'x-component': 'CollectionField', 'x-read-pretty': true },
|
nickname: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-read-pretty': true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
phone: {
|
phone: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-decorator': 'Table.Column.Decorator',
|
'x-decorator': 'Table.Column.Decorator',
|
||||||
'x-component': 'Table.Column',
|
'x-component': 'Table.Column',
|
||||||
properties: { phone: { type: 'string', 'x-component': 'CollectionField', 'x-read-pretty': true } },
|
properties: {
|
||||||
|
phone: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-read-pretty': true,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
email: {
|
email: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-decorator': 'Table.Column.Decorator',
|
'x-decorator': 'Table.Column.Decorator',
|
||||||
'x-component': 'Table.Column',
|
'x-component': 'Table.Column',
|
||||||
properties: { email: { type: 'string', 'x-component': 'CollectionField', 'x-read-pretty': true } },
|
properties: {
|
||||||
|
email: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-read-pretty': true,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -75,12 +117,17 @@ export const schemaFfe = {
|
|||||||
cancel: {
|
cancel: {
|
||||||
title: '{{t("Cancel")}}',
|
title: '{{t("Cancel")}}',
|
||||||
'x-component': 'Action',
|
'x-component': 'Action',
|
||||||
'x-component-props': { useAction: '{{ cm.useCancelAction }}' },
|
'x-component-props': {
|
||||||
|
useAction: '{{ cm.useCancelAction }}',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
confirm: {
|
confirm: {
|
||||||
title: '{{t("Confirm")}}',
|
title: '{{t("Confirm")}}',
|
||||||
'x-component': 'Action',
|
'x-component': 'Action',
|
||||||
'x-component-props': { type: 'primary', useAction: '{{ useSelectOwners }}' },
|
'x-component-props': {
|
||||||
|
type: 'primary',
|
||||||
|
useAction: '{{ useSelectOwners }}',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
@ -0,0 +1,30 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { SchemaComponent } from '@tachybase/client';
|
||||||
|
|
||||||
|
import { schemaUnknownOwerns as schema } from './UnknownOwerns.schema';
|
||||||
|
import { ProviderRequest } from './Request.provider';
|
||||||
|
|
||||||
|
// TODO: 有待重新命名组件名称
|
||||||
|
export const ViewUnKnownOwerns = (props) => {
|
||||||
|
const { record, field, handleSelect, useSelectOwners } = props;
|
||||||
|
|
||||||
|
const RequestProvider = ({ children }) => (
|
||||||
|
<ProviderRequest field={field} record={record}>
|
||||||
|
{children}
|
||||||
|
</ProviderRequest>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SchemaComponent
|
||||||
|
schema={schema}
|
||||||
|
components={{
|
||||||
|
RequestProvider,
|
||||||
|
}}
|
||||||
|
scope={{
|
||||||
|
department: record,
|
||||||
|
handleSelect,
|
||||||
|
useSelectOwners,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -1,8 +1,7 @@
|
|||||||
import { useContext } from 'react';
|
|
||||||
import { useActionContext, useAPIClient, useResourceActionContext } from '@tachybase/client';
|
import { useActionContext, useAPIClient, useResourceActionContext } from '@tachybase/client';
|
||||||
import { useField, useForm } from '@tachybase/schema';
|
import { useField, useForm } from '@tachybase/schema';
|
||||||
|
|
||||||
import { DepartmentsExpandedContext } from '../context/DepartmentsExpandedContext';
|
import { useContextDepartmentsExpanded } from '../context/DepartmentsExpanded.context';
|
||||||
|
|
||||||
export const useCreateDepartment = () => {
|
export const useCreateDepartment = () => {
|
||||||
const form = useForm();
|
const form = useForm();
|
||||||
@ -10,7 +9,7 @@ export const useCreateDepartment = () => {
|
|||||||
const { setVisible } = useActionContext();
|
const { setVisible } = useActionContext();
|
||||||
const { refreshAsync } = useResourceActionContext();
|
const { refreshAsync } = useResourceActionContext();
|
||||||
const api = useAPIClient();
|
const api = useAPIClient();
|
||||||
const { expandedKeys, setLoadedKeys, setExpandedKeys } = useContext(DepartmentsExpandedContext);
|
const { expandedKeys, setLoadedKeys, setExpandedKeys } = useContextDepartmentsExpanded();
|
||||||
return {
|
return {
|
||||||
async run() {
|
async run() {
|
||||||
try {
|
try {
|
@ -1,9 +1,8 @@
|
|||||||
import { useContext } from 'react';
|
|
||||||
import { useActionContext, useAPIClient, useRecord, useResourceActionContext } from '@tachybase/client';
|
import { useActionContext, useAPIClient, useRecord, useResourceActionContext } from '@tachybase/client';
|
||||||
import { useField, useForm } from '@tachybase/schema';
|
import { useField, useForm } from '@tachybase/schema';
|
||||||
|
|
||||||
import { DepartmentsContext } from '../context/DepartmentsContext';
|
import { useContextDepartments } from '../context/Department.context';
|
||||||
import { DepartmentsExpandedContext } from '../context/DepartmentsExpandedContext';
|
import { useContextDepartmentsExpanded } from '../context/DepartmentsExpanded.context';
|
||||||
|
|
||||||
export const useUpdateDepartment = () => {
|
export const useUpdateDepartment = () => {
|
||||||
const field = useField();
|
const field = useField();
|
||||||
@ -12,8 +11,8 @@ export const useUpdateDepartment = () => {
|
|||||||
const { refreshAsync } = useResourceActionContext();
|
const { refreshAsync } = useResourceActionContext();
|
||||||
const api = useAPIClient();
|
const api = useAPIClient();
|
||||||
const { id } = useRecord();
|
const { id } = useRecord();
|
||||||
const { expandedKeys, setLoadedKeys, setExpandedKeys } = useContext(DepartmentsExpandedContext);
|
const { expandedKeys, setLoadedKeys, setExpandedKeys } = useContextDepartmentsExpanded();
|
||||||
const { department, setDepartment } = useContext(DepartmentsContext);
|
const { department, setDepartment } = useContextDepartments();
|
||||||
return {
|
return {
|
||||||
async run() {
|
async run() {
|
||||||
await form.submit();
|
await form.submit();
|
@ -0,0 +1,19 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { SchemaComponent } from '@tachybase/client';
|
||||||
|
|
||||||
|
import { schemaAddMembers as schema } from './AddMembers.schema';
|
||||||
|
import { usePropsAddMembers } from './scopes/usePropsAddMember';
|
||||||
|
|
||||||
|
export const ViewAddMembers = () => {
|
||||||
|
const { department, useAddMembersAction, handleSelect } = usePropsAddMembers();
|
||||||
|
return (
|
||||||
|
<SchemaComponent
|
||||||
|
schema={schema}
|
||||||
|
scope={{
|
||||||
|
useAddMembersAction,
|
||||||
|
department,
|
||||||
|
handleSelect,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -2,11 +2,11 @@ import React, { useContext } from 'react';
|
|||||||
import { EllipsisWithTooltip } from '@tachybase/client';
|
import { EllipsisWithTooltip } from '@tachybase/client';
|
||||||
import { useField } from '@tachybase/schema';
|
import { useField } from '@tachybase/schema';
|
||||||
|
|
||||||
import { DepartmentsContext } from '../context/DepartmentsContext';
|
import { getDepartmentStr } from '../../utils/getDepartmentStr';
|
||||||
import { getDepartmentStr } from '../utils/getDepartmentStr';
|
import { ContextDepartments } from '../context/Department.context';
|
||||||
|
|
||||||
export const DepartmentField = () => {
|
export const DepartmentField = () => {
|
||||||
const { setDepartment } = useContext(DepartmentsContext);
|
const { setDepartment } = useContext(ContextDepartments);
|
||||||
const field = useField<{ value: Array<any> }>();
|
const field = useField<{ value: Array<any> }>();
|
||||||
const fieldValues = field.value || [];
|
const fieldValues = field.value || [];
|
||||||
|
|
||||||
@ -27,7 +27,18 @@ export const DepartmentField = () => {
|
|||||||
>
|
>
|
||||||
{getDepartmentStr(currFieldValue)}
|
{getDepartmentStr(currFieldValue)}
|
||||||
</a>
|
</a>
|
||||||
{index !== fieldValues.length - 1 ? <span style={{ marginRight: 4, color: '#aaa' }}>,</span> : ''}
|
{index !== fieldValues.length - 1 ? (
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
marginRight: 4,
|
||||||
|
color: '#aaa',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
,
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
''
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
))}
|
))}
|
||||||
</EllipsisWithTooltip>
|
</EllipsisWithTooltip>
|
@ -0,0 +1,176 @@
|
|||||||
|
import { uid } from '@tachybase/schema';
|
||||||
|
|
||||||
|
export const getSchemaDepartmentsUsersBlock = (department, user) => {
|
||||||
|
const schemaNotUser = user
|
||||||
|
? {}
|
||||||
|
: {
|
||||||
|
actions: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ActionBar',
|
||||||
|
'x-component-props': {
|
||||||
|
style: {
|
||||||
|
marginBottom: 16,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
[uid()]: {
|
||||||
|
type: 'void',
|
||||||
|
title: '{{ t("Filter") }}',
|
||||||
|
'x-action': 'filter',
|
||||||
|
'x-component': 'Filter.Action',
|
||||||
|
'x-use-component-props': 'useFilterActionProps',
|
||||||
|
'x-component-props': {
|
||||||
|
icon: 'FilterOutlined',
|
||||||
|
},
|
||||||
|
'x-align': 'left',
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'MemberActions',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const tableSchemaDepartMent = department
|
||||||
|
? {
|
||||||
|
isOwner: {
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'Table.Column.Decorator',
|
||||||
|
'x-component': 'Table.Column',
|
||||||
|
'x-component-props': { style: { minWidth: 100 } },
|
||||||
|
title: '{{t("Owner")}}',
|
||||||
|
properties: {
|
||||||
|
isOwner: {
|
||||||
|
type: 'boolean',
|
||||||
|
'x-component': 'IsOwnerField',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
|
||||||
|
const schemaActions = department
|
||||||
|
? {
|
||||||
|
remove: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'RowRemoveAction',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'void',
|
||||||
|
properties: {
|
||||||
|
...schemaNotUser,
|
||||||
|
table: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Table.Void',
|
||||||
|
'x-component-props': {
|
||||||
|
rowKey: 'id',
|
||||||
|
rowSelection: {
|
||||||
|
type: 'checkbox',
|
||||||
|
},
|
||||||
|
useDataSource: '{{ useMembersDataSource }}',
|
||||||
|
pagination: {
|
||||||
|
showTotal: '{{ useShowTotal }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
nickname: {
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'Table.Column.Decorator',
|
||||||
|
'x-component': 'Table.Column',
|
||||||
|
properties: {
|
||||||
|
nickname: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-read-pretty': true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
username: {
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'Table.Column.Decorator',
|
||||||
|
'x-component': 'Table.Column',
|
||||||
|
properties: {
|
||||||
|
username: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-read-pretty': true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
departments: {
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'Table.Column.Decorator',
|
||||||
|
'x-component': 'Table.Column',
|
||||||
|
properties: {
|
||||||
|
departments: { type: 'string', 'x-component': 'CollectionField', 'x-read-pretty': true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
...tableSchemaDepartMent,
|
||||||
|
phone: {
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'Table.Column.Decorator',
|
||||||
|
'x-component': 'Table.Column',
|
||||||
|
properties: {
|
||||||
|
phone: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-read-pretty': true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
email: {
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'Table.Column.Decorator',
|
||||||
|
'x-component': 'Table.Column',
|
||||||
|
properties: {
|
||||||
|
email: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-read-pretty': true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
type: 'void',
|
||||||
|
title: '{{t("Actions")}}',
|
||||||
|
'x-component': 'Table.Column',
|
||||||
|
properties: {
|
||||||
|
actions: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Space',
|
||||||
|
'x-component-props': { split: '|' },
|
||||||
|
properties: {
|
||||||
|
update: {
|
||||||
|
type: 'void',
|
||||||
|
title: '{{t("Configure")}}',
|
||||||
|
'x-component': 'Action.Link',
|
||||||
|
'x-component-props': { type: 'primary' },
|
||||||
|
properties: {
|
||||||
|
drawer: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Action.Drawer',
|
||||||
|
'x-decorator': 'FormV2',
|
||||||
|
title: '{{t("Configure")}}',
|
||||||
|
properties: {
|
||||||
|
departments: {
|
||||||
|
title: '{{t("Departments")}}',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'UserDepartmentsField',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
...schemaActions,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,58 @@
|
|||||||
|
import React, { useContext, useEffect, useMemo } from 'react';
|
||||||
|
import { SchemaComponent, useResourceActionContext } from '@tachybase/client';
|
||||||
|
|
||||||
|
import { useTranslation } from '../../../../locale';
|
||||||
|
import { useDepartmentFilterActionProps } from '../../common/scopes/useDepartmentFilterActionProps';
|
||||||
|
import { ContextDepartments } from '../context/Department.context';
|
||||||
|
import { ViewAddMembers } from './AddMembers.view';
|
||||||
|
import { DepartmentField } from './DepartmentField.component';
|
||||||
|
import { getSchemaDepartmentsUsersBlock } from './DepartmentsUsersBlock.schema';
|
||||||
|
import { IsOwnerField } from './IsOwnerField.component';
|
||||||
|
import { ViewMemberActions } from './MemberActions.view';
|
||||||
|
import { ViewRowRemoveAction } from './RowRemoveAction.view';
|
||||||
|
import { useBulkRemoveMembersAction } from './scopes/useBulkRemoveMembersAction';
|
||||||
|
import { useMembersDataSource } from './scopes/useMembersDataSource';
|
||||||
|
import { useShowTotal } from './scopes/useShowTotal';
|
||||||
|
import { UserDepartmentsField } from './UserDepartmentsField.component';
|
||||||
|
|
||||||
|
// 部门右边-用户列表部分
|
||||||
|
export const ViewDepartmentsUsersBlock = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { department, user } = useContext(ContextDepartments);
|
||||||
|
const { data, setState } = useResourceActionContext();
|
||||||
|
|
||||||
|
const MemberActions = () => <ViewMemberActions department={department} />;
|
||||||
|
|
||||||
|
const RowRemoveAction = () => <ViewRowRemoveAction department={department} />;
|
||||||
|
|
||||||
|
const schema = useMemo(() => getSchemaDepartmentsUsersBlock(department, user), [department, user]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setState?.({
|
||||||
|
selectedRowKeys: [],
|
||||||
|
});
|
||||||
|
}, [data, setState]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h2>{user ? t('Search results') : t(department?.title ?? 'All users')}</h2>
|
||||||
|
<SchemaComponent
|
||||||
|
schema={schema}
|
||||||
|
components={{
|
||||||
|
MemberActions,
|
||||||
|
AddMembers: ViewAddMembers,
|
||||||
|
RowRemoveAction,
|
||||||
|
DepartmentField,
|
||||||
|
IsOwnerField,
|
||||||
|
UserDepartmentsField,
|
||||||
|
}}
|
||||||
|
scope={{
|
||||||
|
useBulkRemoveMembersAction,
|
||||||
|
useMembersDataSource,
|
||||||
|
useShowTotal,
|
||||||
|
useFilterActionProps: useDepartmentFilterActionProps,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
@ -1,10 +1,10 @@
|
|||||||
import React, { useContext } from 'react';
|
import React from 'react';
|
||||||
import { Checkbox, useRecord } from '@tachybase/client';
|
import { Checkbox, useRecord } from '@tachybase/client';
|
||||||
|
|
||||||
import { DepartmentsContext } from '../context/DepartmentsContext';
|
import { useContextDepartments } from '../context/Department.context';
|
||||||
|
|
||||||
export const IsOwnerField = () => {
|
export const IsOwnerField = () => {
|
||||||
const { department } = useContext(DepartmentsContext);
|
const { department } = useContextDepartments();
|
||||||
const dep = useRecord().departments?.find((d) => d?.id === department?.id);
|
const dep = useRecord().departments?.find((d) => d?.id === department?.id);
|
||||||
return <Checkbox.ReadPretty value={dep?.departmentsUsers.isOwner} />;
|
return <Checkbox.ReadPretty value={dep?.departmentsUsers.isOwner} />;
|
||||||
};
|
};
|
@ -1,4 +1,4 @@
|
|||||||
export const schemaZe = {
|
export const schemaMemberActions = {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Space',
|
'x-component': 'Space',
|
||||||
properties: {
|
properties: {
|
||||||
@ -12,7 +12,9 @@ export const schemaZe = {
|
|||||||
title: "{{t('Remove members')}}",
|
title: "{{t('Remove members')}}",
|
||||||
content: "{{t('Are you sure you want to remove these members?')}}",
|
content: "{{t('Are you sure you want to remove these members?')}}",
|
||||||
},
|
},
|
||||||
style: { marginRight: 8 },
|
style: {
|
||||||
|
marginRight: 8,
|
||||||
|
},
|
||||||
useAction: '{{ useBulkRemoveMembersAction }}',
|
useAction: '{{ useBulkRemoveMembersAction }}',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -20,8 +22,16 @@ export const schemaZe = {
|
|||||||
type: 'void',
|
type: 'void',
|
||||||
title: '{{t("Add members")}}',
|
title: '{{t("Add members")}}',
|
||||||
'x-component': 'Action',
|
'x-component': 'Action',
|
||||||
'x-component-props': { type: 'primary', icon: 'UserAddOutlined' },
|
'x-component-props': {
|
||||||
properties: { drawer: { type: 'void', 'x-component': 'AddMembers' } },
|
type: 'primary',
|
||||||
|
icon: 'UserAddOutlined',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
drawer: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'AddMembers',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
@ -0,0 +1,9 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { SchemaComponent } from '@tachybase/client';
|
||||||
|
|
||||||
|
import { schemaMemberActions } from './MemberActions.schema';
|
||||||
|
|
||||||
|
export const ViewMemberActions = (props) => {
|
||||||
|
const { department } = props;
|
||||||
|
return department ? <SchemaComponent schema={schemaMemberActions} /> : null;
|
||||||
|
};
|
@ -1,11 +1,14 @@
|
|||||||
export const schemaWe = {
|
export const schemaRowRemoveAction = {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
properties: {
|
properties: {
|
||||||
remove: {
|
remove: {
|
||||||
title: '{{ t("Remove") }}',
|
title: '{{ t("Remove") }}',
|
||||||
'x-component': 'Action.Link',
|
'x-component': 'Action.Link',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
confirm: { title: "{{t('Remove member')}}", content: "{{t('Are you sure you want to remove it?')}}" },
|
confirm: {
|
||||||
|
title: "{{t('Remove member')}}",
|
||||||
|
content: "{{t('Are you sure you want to remove it?')}}",
|
||||||
|
},
|
||||||
useAction: '{{ useRemoveMemberAction }}',
|
useAction: '{{ useRemoveMemberAction }}',
|
||||||
},
|
},
|
||||||
},
|
},
|
@ -0,0 +1,18 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { SchemaComponent } from '@tachybase/client';
|
||||||
|
|
||||||
|
import { schemaRowRemoveAction as schema } from './RowRemoveAction.schema';
|
||||||
|
import { useRemoveMemberAction } from './scopes/useRemoveMemberAction';
|
||||||
|
|
||||||
|
export const ViewRowRemoveAction = (props) => {
|
||||||
|
const { department } = props;
|
||||||
|
|
||||||
|
return department ? (
|
||||||
|
<SchemaComponent
|
||||||
|
schema={schema}
|
||||||
|
scope={{
|
||||||
|
useRemoveMemberAction: useRemoveMemberAction,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : null;
|
||||||
|
};
|
@ -1,4 +1,4 @@
|
|||||||
export const schemaJe = {
|
export const schemaUnknownUserDepartment = {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
properties: {
|
properties: {
|
||||||
drawer: {
|
drawer: {
|
||||||
@ -10,7 +10,10 @@ export const schemaJe = {
|
|||||||
type: 'void',
|
type: 'void',
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-component': 'DepartmentTable',
|
'x-component': 'DepartmentTable',
|
||||||
'x-component-props': { useDataSource: '{{ useDataSource }}', useDisabled: '{{ useDisabled }}' },
|
'x-component-props': {
|
||||||
|
useDataSource: '{{ useDataSource }}',
|
||||||
|
useDisabled: '{{ useDisabled }}',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
footer: {
|
footer: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
@ -19,12 +22,17 @@ export const schemaJe = {
|
|||||||
cancel: {
|
cancel: {
|
||||||
title: '{{t("Cancel")}}',
|
title: '{{t("Cancel")}}',
|
||||||
'x-component': 'Action',
|
'x-component': 'Action',
|
||||||
'x-component-props': { useAction: '{{ cm.useCancelAction }}' },
|
'x-component-props': {
|
||||||
|
useAction: '{{ cm.useCancelAction }}',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
confirm: {
|
confirm: {
|
||||||
title: '{{t("Submit")}}',
|
title: '{{t("Submit")}}',
|
||||||
'x-component': 'Action',
|
'x-component': 'Action',
|
||||||
'x-component-props': { type: 'primary', useAction: '{{ useAddDepartments }}' },
|
'x-component-props': {
|
||||||
|
type: 'primary',
|
||||||
|
useAction: '{{ useAddDepartments }}',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
@ -0,0 +1,26 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { SchemaComponent } from '@tachybase/client';
|
||||||
|
|
||||||
|
import { ViewDepartmentTable } from '../../common/DepartmentTable.view';
|
||||||
|
import { useDataSource } from './scopes/useDataSource';
|
||||||
|
import { schemaUnknownUserDepartment as schema } from './UnknownUserDepartment.schema';
|
||||||
|
|
||||||
|
// TODO: 有待重新命名组件
|
||||||
|
export const ViewUnknownUserDepartment = (props) => {
|
||||||
|
const { user, useAddDepartments, useDisabled } = props;
|
||||||
|
return (
|
||||||
|
<SchemaComponent
|
||||||
|
key={2}
|
||||||
|
schema={schema}
|
||||||
|
components={{
|
||||||
|
DepartmentTable: ViewDepartmentTable,
|
||||||
|
}}
|
||||||
|
scope={{
|
||||||
|
user,
|
||||||
|
useDataSource,
|
||||||
|
useAddDepartments,
|
||||||
|
useDisabled,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,167 @@
|
|||||||
|
import React, { Fragment, useState } from 'react';
|
||||||
|
import {
|
||||||
|
ActionContextProvider,
|
||||||
|
useAPIClient,
|
||||||
|
useRecord,
|
||||||
|
useRequest,
|
||||||
|
useResourceActionContext,
|
||||||
|
} from '@tachybase/client';
|
||||||
|
import { Field, useField, useForm } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { MoreOutlined, PlusOutlined } from '@ant-design/icons';
|
||||||
|
import { App, Button, Dropdown, Tag } from 'antd';
|
||||||
|
|
||||||
|
import { useTranslation } from '../../../../locale';
|
||||||
|
import { getDepartmentStr } from '../../utils/getDepartmentStr';
|
||||||
|
import { ViewUnknownUserDepartment } from './UnknownUserDepartment.view';
|
||||||
|
|
||||||
|
export const UserDepartmentsField = () => {
|
||||||
|
const { modal, message } = App.useApp();
|
||||||
|
const API = useAPIClient();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
const user = useRecord();
|
||||||
|
const field = useField<Field>();
|
||||||
|
const { refresh } = useResourceActionContext();
|
||||||
|
|
||||||
|
const mapDepartment = (value = []) => {
|
||||||
|
return value.map((item) => ({
|
||||||
|
...item,
|
||||||
|
title: getDepartmentStr(item),
|
||||||
|
isMain: item.departmentsUsers?.isMain,
|
||||||
|
isOwner: item.departmentsUsers?.isOwner,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
useRequest(
|
||||||
|
() =>
|
||||||
|
API.resource('users.departments', user.id)
|
||||||
|
.list({
|
||||||
|
appends: ['parent(recursively=true)'],
|
||||||
|
pagination: false,
|
||||||
|
})
|
||||||
|
.then((result) => {
|
||||||
|
const value = mapDepartment(result?.data?.data);
|
||||||
|
field.setValue(value);
|
||||||
|
}),
|
||||||
|
{ ready: user.id },
|
||||||
|
);
|
||||||
|
|
||||||
|
const useAddDepartments = () => {
|
||||||
|
const api = useAPIClient();
|
||||||
|
const form = useForm();
|
||||||
|
const { departments } = form.values || {};
|
||||||
|
return {
|
||||||
|
async run() {
|
||||||
|
await api.resource('users.departments', user.id).add({ values: departments.map((O) => O.id) });
|
||||||
|
form.reset();
|
||||||
|
field.setValue([
|
||||||
|
...field.value,
|
||||||
|
...departments.map((department, index) => ({
|
||||||
|
...department,
|
||||||
|
isMain: index === 0 && field.value.length === 0,
|
||||||
|
title: getDepartmentStr(department),
|
||||||
|
})),
|
||||||
|
]);
|
||||||
|
setVisible(false);
|
||||||
|
refresh();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const showModalRemove = (department) => {
|
||||||
|
modal.confirm({
|
||||||
|
title: t('Remove department'),
|
||||||
|
content: t('Are you sure you want to remove it?'),
|
||||||
|
onOk: async () => {
|
||||||
|
await API.resource('users.departments', user.id).remove({ values: [department.id] });
|
||||||
|
message.success(t('Deleted successfully'));
|
||||||
|
field.setValue(
|
||||||
|
field.value
|
||||||
|
.filter((dep) => dep.id !== department.id)
|
||||||
|
.map((dep, index) => ({ ...dep, isMain: (department.isMain && index === 0) || dep.isMain })),
|
||||||
|
);
|
||||||
|
refresh();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const setMain = async (l) => {
|
||||||
|
await API.resource('users').setMainDepartment({
|
||||||
|
values: {
|
||||||
|
userId: user.id,
|
||||||
|
departmentId: l.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
message.success(t('Set successfully'));
|
||||||
|
field.setValue(field.value.map((u) => ({ ...u, isMain: u.id === l.id })));
|
||||||
|
refresh();
|
||||||
|
};
|
||||||
|
|
||||||
|
const setOwner = async (l) => {
|
||||||
|
await API.resource('departments').setOwner({ values: { userId: user.id, departmentId: l.id } });
|
||||||
|
message.success(t('Set successfully'));
|
||||||
|
field.setValue(field.value.map((u) => ({ ...u, isOwner: u.id === l.id ? true : u.isOwner })));
|
||||||
|
refresh();
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeOwner = async (department) => {
|
||||||
|
await API.resource('departments').removeOwner({ values: { userId: user.id, departmentId: department.id } });
|
||||||
|
message.success(t('Set successfully'));
|
||||||
|
field.setValue(field.value.map((dep) => ({ ...dep, isOwner: dep.id === department.id ? false : dep.isOwner })));
|
||||||
|
refresh();
|
||||||
|
};
|
||||||
|
|
||||||
|
const C = (l, u) => {
|
||||||
|
switch (l) {
|
||||||
|
case 'setMain':
|
||||||
|
setMain(u);
|
||||||
|
break;
|
||||||
|
case 'setOwner':
|
||||||
|
setOwner(u);
|
||||||
|
break;
|
||||||
|
case 'removeOwner':
|
||||||
|
removeOwner(u);
|
||||||
|
break;
|
||||||
|
case 'remove':
|
||||||
|
showModalRemove(u);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const useDisabled = () => ({ disabled: (l) => field.value.some((u) => u.id === l.id) });
|
||||||
|
return (
|
||||||
|
<ActionContextProvider value={{ visible: visible, setVisible: setVisible }}>
|
||||||
|
<Fragment>
|
||||||
|
{(field?.value || []).map((val) => (
|
||||||
|
<Tag key={val.id} style={{ padding: '5px 8px', background: 'transparent', marginBottom: '5px' }}>
|
||||||
|
<span style={{ marginRight: '5px' }}>{val.title}</span>
|
||||||
|
{val.isMain ? (
|
||||||
|
<Tag color={'processing'} bordered={false}>
|
||||||
|
{t('Main')}
|
||||||
|
</Tag>
|
||||||
|
) : (
|
||||||
|
''
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Dropdown
|
||||||
|
menu={{
|
||||||
|
items: [
|
||||||
|
...(val.isMain ? [] : [{ label: t('Set as main department'), key: 'setMain' }]),
|
||||||
|
{ label: t('Remove'), key: 'remove' },
|
||||||
|
],
|
||||||
|
onClick: ({ key }) => C(key, val),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ float: 'right' }}>
|
||||||
|
{' '}
|
||||||
|
<MoreOutlined />
|
||||||
|
</div>
|
||||||
|
</Dropdown>
|
||||||
|
</Tag>
|
||||||
|
))}
|
||||||
|
<Button key={1} icon={<PlusOutlined />} onClick={() => setVisible(true)} />,
|
||||||
|
</Fragment>
|
||||||
|
<ViewUnknownUserDepartment user={user} useAddDepartments={useAddDepartments} useDisabled={useDisabled} />
|
||||||
|
</ActionContextProvider>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,29 @@
|
|||||||
|
import { useAPIClient, useResourceActionContext } from '@tachybase/client';
|
||||||
|
|
||||||
|
import { App } from 'antd';
|
||||||
|
|
||||||
|
import { useTranslation } from '../../../../../locale';
|
||||||
|
import { useContextDepartments } from '../../context/Department.context';
|
||||||
|
|
||||||
|
export const useBulkRemoveMembersAction = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { message } = App.useApp();
|
||||||
|
const API = useAPIClient();
|
||||||
|
const { state, setState, refresh } = useResourceActionContext();
|
||||||
|
const { department } = useContextDepartments();
|
||||||
|
|
||||||
|
return {
|
||||||
|
async run() {
|
||||||
|
const selectedRowKeys = state?.selectedRowKeys;
|
||||||
|
if (!selectedRowKeys?.length) {
|
||||||
|
message.warning(t('Please select members'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await API.resource('departments.members', department.id).remove({ values: selectedRowKeys });
|
||||||
|
|
||||||
|
setState({ selectedRowKeys: [] });
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
@ -4,7 +4,10 @@ export const useDataSource = (props) => {
|
|||||||
const params = {
|
const params = {
|
||||||
resource: 'departments',
|
resource: 'departments',
|
||||||
action: 'list',
|
action: 'list',
|
||||||
params: { appends: ['parent(recursively=true)'], sort: ['createdAt'] },
|
params: {
|
||||||
|
appends: ['parent(recursively=true)'],
|
||||||
|
sort: ['createdAt'],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
const service = useRequest(params, props);
|
const service = useRequest(params, props);
|
||||||
return { ...service, defaultRequest: params };
|
return { ...service, defaultRequest: params };
|
@ -0,0 +1,22 @@
|
|||||||
|
import { useContext, useEffect } from 'react';
|
||||||
|
import { useResourceActionContext } from '@tachybase/client';
|
||||||
|
|
||||||
|
import { ContextDepartments } from '../../context/Department.context';
|
||||||
|
|
||||||
|
export const useMembersDataSource = (props) => {
|
||||||
|
const { user } = useContext(ContextDepartments);
|
||||||
|
const ctx = useResourceActionContext();
|
||||||
|
useEffect(() => {
|
||||||
|
if (user) {
|
||||||
|
props?.onSuccess({ data: [user] });
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctx.loading) {
|
||||||
|
props?.onSuccess(ctx.data);
|
||||||
|
}
|
||||||
|
}, [user, ctx.loading]);
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
};
|
@ -0,0 +1,35 @@
|
|||||||
|
import { useRef } from 'react';
|
||||||
|
import { useAPIClient, useResourceActionContext } from '@tachybase/client';
|
||||||
|
|
||||||
|
import { useContextDepartments } from '../../context/Department.context';
|
||||||
|
|
||||||
|
export function usePropsAddMembers(): any {
|
||||||
|
const { department } = useContextDepartments();
|
||||||
|
const { refresh } = useResourceActionContext();
|
||||||
|
const ref = useRef([]);
|
||||||
|
const api = useAPIClient();
|
||||||
|
const useAddMembersAction = () => ({
|
||||||
|
async run() {
|
||||||
|
const currMembers = ref.current;
|
||||||
|
if (currMembers?.length) {
|
||||||
|
await api.resource('departments.members', department.id).add({
|
||||||
|
values: currMembers,
|
||||||
|
});
|
||||||
|
|
||||||
|
ref.current = [];
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleSelect = (val) => {
|
||||||
|
ref.current = val;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
department,
|
||||||
|
useAddMembersAction,
|
||||||
|
handleSelect,
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
import { useAPIClient, useRecord, useResourceActionContext } from '@tachybase/client';
|
||||||
|
|
||||||
|
import { useContextDepartments } from '../../context/Department.context';
|
||||||
|
|
||||||
|
export const useRemoveMemberAction = () => {
|
||||||
|
const API = useAPIClient();
|
||||||
|
const { department } = useContextDepartments();
|
||||||
|
const { id } = useRecord();
|
||||||
|
const { refresh } = useResourceActionContext();
|
||||||
|
|
||||||
|
return {
|
||||||
|
async run() {
|
||||||
|
await API.resource('departments.members', department.id).remove({ values: [id] });
|
||||||
|
refresh();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,11 @@
|
|||||||
|
import { useResourceActionContext } from '@tachybase/client';
|
||||||
|
|
||||||
|
import { useTranslation } from '../../../../../locale';
|
||||||
|
|
||||||
|
export const useShowTotal = () => {
|
||||||
|
const service = useResourceActionContext();
|
||||||
|
const { data } = service;
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return t('Total {{count}} members', { count: data?.meta?.count });
|
||||||
|
};
|
@ -1,31 +1,33 @@
|
|||||||
import { useAPIClient } from '@tachybase/client';
|
import { useAPIClient } from '@tachybase/client';
|
||||||
|
|
||||||
import { useDepTree } from './useHooksDe';
|
import { useDepTree } from './useDeepTree';
|
||||||
|
|
||||||
export const useDepTree2 = (props?) => {
|
export const useGetDepTree = (props?) => {
|
||||||
const { resource = 'departments', resourceOf, params = {} } = props || {};
|
const { resource = 'departments', resourceOf, params = {} } = props || {};
|
||||||
const service = useAPIClient().resource(resource, resourceOf);
|
const service = useAPIClient().resource(resource, resourceOf);
|
||||||
const depTree = useDepTree(props);
|
const depTree = useDepTree(props);
|
||||||
const { setTreeData, updateTreeData, initData } = depTree;
|
const { setTreeData, updateTreeData, initData } = depTree;
|
||||||
const loadData =
|
const loadData = async ({ key, children }) => {
|
||||||
(_) =>
|
if (children != null && children.length) return;
|
||||||
async ({ key, children }) => {
|
const { data } = await service.list({
|
||||||
if (children != null && children.length) return;
|
...params,
|
||||||
const { data } = await service.list({
|
pagination: false,
|
||||||
...params,
|
appends: ['parent(recursively=true)'],
|
||||||
pagination: false,
|
filter: { parentId: key },
|
||||||
appends: ['parent(recursively=true)'],
|
});
|
||||||
filter: { parentId: key },
|
if (data?.data?.length) {
|
||||||
});
|
setTreeData(updateTreeData(key, data?.data));
|
||||||
if (data?.data?.length) {
|
}
|
||||||
setTreeData(updateTreeData(key, data?.data));
|
};
|
||||||
}
|
|
||||||
};
|
|
||||||
const getByKeyword = async (keyword) => {
|
const getByKeyword = async (keyword) => {
|
||||||
const { data } = await service.list({
|
const { data } = await service.list({
|
||||||
...params,
|
...params,
|
||||||
pagination: false,
|
pagination: false,
|
||||||
filter: { title: { $includes: keyword } },
|
filter: {
|
||||||
|
title: {
|
||||||
|
$includes: keyword,
|
||||||
|
},
|
||||||
|
},
|
||||||
appends: ['parent(recursively=true)'],
|
appends: ['parent(recursively=true)'],
|
||||||
pageSize: 100,
|
pageSize: 100,
|
||||||
});
|
});
|
@ -0,0 +1,17 @@
|
|||||||
|
import { Plugin } from '@tachybase/client';
|
||||||
|
|
||||||
|
import { tval } from '../../../locale';
|
||||||
|
import { DepartmentIndex } from './DepartmentIndex';
|
||||||
|
|
||||||
|
export class KitMainTabDepartments extends Plugin {
|
||||||
|
async load() {
|
||||||
|
// 用户-部门-角色和权限
|
||||||
|
this.app.pluginSettingsManager.add('users-permissions.departments', {
|
||||||
|
icon: 'ApartmentOutlined',
|
||||||
|
title: tval('Departments'),
|
||||||
|
sort: 2,
|
||||||
|
aclSnippet: 'pm.departments',
|
||||||
|
Component: DepartmentIndex,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -2,10 +2,10 @@ import React from 'react';
|
|||||||
import { CollectionProvider_deprecated, ResourceActionContext } from '@tachybase/client';
|
import { CollectionProvider_deprecated, ResourceActionContext } from '@tachybase/client';
|
||||||
|
|
||||||
import { collectionDepartments } from '../collections/departments.collection';
|
import { collectionDepartments } from '../collections/departments.collection';
|
||||||
import { useDepartments } from '../context/DepartmentsContext';
|
import { useContextDepartments } from '../context/Department.context';
|
||||||
|
|
||||||
export const DepartmentsResourceProvider = ({ children }) => {
|
export const ProviderDepartmentsResource = ({ children }) => {
|
||||||
const context = useDepartments();
|
const context = useContextDepartments();
|
||||||
const { departmentsResource } = context;
|
const { departmentsResource } = context;
|
||||||
const { service } = departmentsResource || {};
|
const { service } = departmentsResource || {};
|
||||||
|
|
@ -2,10 +2,10 @@ import React, { useContext } from 'react';
|
|||||||
import { CollectionProvider_deprecated, ResourceActionContext } from '@tachybase/client';
|
import { CollectionProvider_deprecated, ResourceActionContext } from '@tachybase/client';
|
||||||
|
|
||||||
import { collectionUsers } from '../collections/users.collection';
|
import { collectionUsers } from '../collections/users.collection';
|
||||||
import { DepartmentsContext } from '../context/DepartmentsContext';
|
import { ContextDepartments } from '../context/Department.context';
|
||||||
|
|
||||||
export const UserResourceProvider = ({ children }) => {
|
export const ProviderUserResource = ({ children }) => {
|
||||||
const { usersResource } = useContext(DepartmentsContext);
|
const { usersResource } = useContext(ContextDepartments);
|
||||||
const { service } = usersResource || {};
|
const { service } = usersResource || {};
|
||||||
|
|
||||||
return (
|
return (
|
@ -1,4 +0,0 @@
|
|||||||
// NOTE: ohters 文件里都是工具函数, 替换后可删除
|
|
||||||
import { Ft, Mt } from './wt';
|
|
||||||
|
|
||||||
export var T = (w, s) => Ft(w, Mt(s));
|
|
@ -1,4 +0,0 @@
|
|||||||
import { wt } from './wt';
|
|
||||||
|
|
||||||
export var de = (w, s, n) =>
|
|
||||||
s in w ? wt(w, s, { enumerable: true, configurable: true, writable: true, value: n }) : (w[s] = n);
|
|
@ -1,19 +0,0 @@
|
|||||||
export var k = (w, s, n) =>
|
|
||||||
new Promise((D, p) => {
|
|
||||||
var j = (V) => {
|
|
||||||
try {
|
|
||||||
N(n.next(V));
|
|
||||||
} catch (I) {
|
|
||||||
p(I);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Y = (V) => {
|
|
||||||
try {
|
|
||||||
N(n.throw(V));
|
|
||||||
} catch (I) {
|
|
||||||
p(I);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
N = (V) => (V.done ? D(V.value) : Promise.resolve(V.value).then(j, Y));
|
|
||||||
N((n = n.apply(w, s)).next());
|
|
||||||
});
|
|
@ -1,6 +0,0 @@
|
|||||||
export var wt = Object.defineProperty;
|
|
||||||
export var Ft = Object.defineProperties;
|
|
||||||
export var Mt = Object.getOwnPropertyDescriptors;
|
|
||||||
export var me = Object.getOwnPropertySymbols;
|
|
||||||
export var Tt = Object.prototype.hasOwnProperty;
|
|
||||||
export var It = Object.prototype.propertyIsEnumerable;
|
|
@ -1,8 +0,0 @@
|
|||||||
import { de } from './de';
|
|
||||||
import { It, me, Tt } from './wt';
|
|
||||||
|
|
||||||
export var y = (w, s) => {
|
|
||||||
for (var n in s || (s = {})) Tt.call(s, n) && de(w, n, s[n]);
|
|
||||||
if (me) for (var n of me(s)) It.call(s, n) && de(w, n, s[n]);
|
|
||||||
return w;
|
|
||||||
};
|
|
@ -0,0 +1,19 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { useRecord } from '@tachybase/client';
|
||||||
|
|
||||||
|
export const DepartmentTitle = () => {
|
||||||
|
const record = useRecord();
|
||||||
|
const title = getTitle(record);
|
||||||
|
|
||||||
|
return <>{title}</>;
|
||||||
|
};
|
||||||
|
|
||||||
|
// utils
|
||||||
|
function getTitle(record) {
|
||||||
|
const { title, parent } = record;
|
||||||
|
if (parent) {
|
||||||
|
return getTitle(parent) + ' /' + title;
|
||||||
|
} else {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,16 @@
|
|||||||
import { uid } from '@tachybase/schema';
|
import { uid } from '@tachybase/schema';
|
||||||
|
|
||||||
export const getSchemaDdt = () => ({
|
export const getSchemaDepartments = () => ({
|
||||||
type: 'void',
|
type: 'void',
|
||||||
properties: {
|
properties: {
|
||||||
actions: {
|
actions: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'ActionBar',
|
'x-component': 'ActionBar',
|
||||||
'x-component-props': { style: { marginBottom: 16 } },
|
'x-component-props': {
|
||||||
|
style: {
|
||||||
|
marginBottom: 16,
|
||||||
|
},
|
||||||
|
},
|
||||||
properties: {
|
properties: {
|
||||||
[uid()]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
@ -14,7 +18,9 @@ export const getSchemaDdt = () => ({
|
|||||||
'x-action': 'filter',
|
'x-action': 'filter',
|
||||||
'x-component': 'Filter.Action',
|
'x-component': 'Filter.Action',
|
||||||
'x-use-component-props': 'useFilterActionProps',
|
'x-use-component-props': 'useFilterActionProps',
|
||||||
'x-component-props': { icon: 'FilterOutlined' },
|
'x-component-props': {
|
||||||
|
icon: 'FilterOutlined',
|
||||||
|
},
|
||||||
'x-align': 'left',
|
'x-align': 'left',
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
@ -39,7 +45,10 @@ export const getSchemaDdt = () => ({
|
|||||||
type: 'void',
|
type: 'void',
|
||||||
title: '{{t("Add departments")}}',
|
title: '{{t("Add departments")}}',
|
||||||
'x-component': 'Action',
|
'x-component': 'Action',
|
||||||
'x-component-props': { type: 'primary', icon: 'PlusOutlined' },
|
'x-component-props': {
|
||||||
|
type: 'primary',
|
||||||
|
icon: 'PlusOutlined',
|
||||||
|
},
|
||||||
properties: {
|
properties: {
|
||||||
drawer: {
|
drawer: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
@ -63,12 +72,17 @@ export const getSchemaDdt = () => ({
|
|||||||
cancel: {
|
cancel: {
|
||||||
title: '{{t("Cancel")}}',
|
title: '{{t("Cancel")}}',
|
||||||
'x-component': 'Action',
|
'x-component': 'Action',
|
||||||
'x-component-props': { useAction: '{{ cm.useCancelAction }}' },
|
'x-component-props': {
|
||||||
|
useAction: '{{ cm.useCancelAction }}',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
submit: {
|
submit: {
|
||||||
title: '{{t("Submit")}}',
|
title: '{{t("Submit")}}',
|
||||||
'x-component': 'Action',
|
'x-component': 'Action',
|
||||||
'x-component-props': { type: 'primary', useAction: '{{ useAddDepartments }}' },
|
'x-component-props': {
|
||||||
|
type: 'primary',
|
||||||
|
useAction: '{{ useAddDepartments }}',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -94,7 +108,12 @@ export const getSchemaDdt = () => ({
|
|||||||
title: '{{t("Department name")}}',
|
title: '{{t("Department name")}}',
|
||||||
'x-decorator': 'Table.Column.Decorator',
|
'x-decorator': 'Table.Column.Decorator',
|
||||||
'x-component': 'Table.Column',
|
'x-component': 'Table.Column',
|
||||||
properties: { title: { type: 'string', 'x-component': 'DepartmentTitle' } },
|
properties: {
|
||||||
|
title: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'DepartmentTitle',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
@ -104,7 +123,9 @@ export const getSchemaDdt = () => ({
|
|||||||
actions: {
|
actions: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Space',
|
'x-component': 'Space',
|
||||||
'x-component-props': { split: '|' },
|
'x-component-props': {
|
||||||
|
split: '|',
|
||||||
|
},
|
||||||
properties: {
|
properties: {
|
||||||
remove: {
|
remove: {
|
||||||
type: 'void',
|
type: 'void',
|
@ -0,0 +1,49 @@
|
|||||||
|
import React, { useContext, useMemo } from 'react';
|
||||||
|
import { CollectionProvider_deprecated, ResourceActionContext, SchemaComponent, useRequest } from '@tachybase/client';
|
||||||
|
import { RolesManagerContext } from '@tachybase/plugin-acl/client';
|
||||||
|
|
||||||
|
import { ViewDepartmentTable } from '../common/DepartmentTable.view';
|
||||||
|
import { useDepartmentFilterActionProps } from '../common/scopes/useDepartmentFilterActionProps';
|
||||||
|
import { collectionDepartments } from '../main-tab/collections/departments.collection';
|
||||||
|
import { getSchemaDepartments } from './Departments.schema';
|
||||||
|
import { DepartmentTitle } from './DepartmentTitle.component';
|
||||||
|
import { useAddDepartments } from './scopes/useAddDepartments';
|
||||||
|
import { useBulkRemoveDepartments } from './scopes/useBulkRemoveDepartments';
|
||||||
|
import { useDataSource } from './scopes/useDataSource';
|
||||||
|
import { useDisabled } from './scopes/useDisabled';
|
||||||
|
import { useRemoveDepartment } from './scopes/useRemoveDepartment';
|
||||||
|
|
||||||
|
export const Departments = () => {
|
||||||
|
const { role } = useContext(RolesManagerContext);
|
||||||
|
const resourceData = useRequest(
|
||||||
|
{
|
||||||
|
resource: `roles/${role?.name}/departments`,
|
||||||
|
action: 'list',
|
||||||
|
params: { appends: ['parent', 'parent.parent(recursively=true)'] },
|
||||||
|
},
|
||||||
|
{ ready: !!role, refreshDeps: [role] },
|
||||||
|
);
|
||||||
|
const schema = useMemo(() => getSchemaDepartments(), [role]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ResourceActionContext.Provider value={resourceData}>
|
||||||
|
<CollectionProvider_deprecated collection={collectionDepartments}>
|
||||||
|
<SchemaComponent
|
||||||
|
schema={schema}
|
||||||
|
components={{
|
||||||
|
DepartmentTable: ViewDepartmentTable,
|
||||||
|
DepartmentTitle,
|
||||||
|
}}
|
||||||
|
scope={{
|
||||||
|
useFilterActionProps: useDepartmentFilterActionProps,
|
||||||
|
useRemoveDepartment,
|
||||||
|
useBulkRemoveDepartments,
|
||||||
|
useDataSource,
|
||||||
|
useDisabled,
|
||||||
|
useAddDepartments,
|
||||||
|
}}
|
||||||
|
></SchemaComponent>
|
||||||
|
</CollectionProvider_deprecated>
|
||||||
|
</ResourceActionContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,2 @@
|
|||||||
|
## 简介
|
||||||
|
1. 用户和权限/角色和权限下的, 部门部分
|
@ -0,0 +1,15 @@
|
|||||||
|
import { Plugin } from '@tachybase/client';
|
||||||
|
import PluginACLClient from '@tachybase/plugin-acl/client';
|
||||||
|
|
||||||
|
import { tval } from '../../../locale';
|
||||||
|
import { Departments } from './Departments';
|
||||||
|
|
||||||
|
export class KitRoleAuth extends Plugin {
|
||||||
|
async load() {
|
||||||
|
// 角色和权限: 部门管理
|
||||||
|
this.app.pm.get(PluginACLClient).rolesManager.add('departments', {
|
||||||
|
title: tval('Departments'),
|
||||||
|
Component: Departments,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -12,9 +12,12 @@ export const useAddDepartments = () => {
|
|||||||
const { departments: departments } = form.values || {};
|
const { departments: departments } = form.values || {};
|
||||||
return {
|
return {
|
||||||
async run() {
|
async run() {
|
||||||
await api.resource('roles.departments', role.name).add({ values: departments.map((dep) => dep.id) });
|
const apiResource = api.resource('roles.departments', role.name);
|
||||||
|
await apiResource.add({ values: departments.map((dep) => dep.id) });
|
||||||
|
|
||||||
form.reset();
|
form.reset();
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
|
|
||||||
refresh();
|
refresh();
|
||||||
},
|
},
|
||||||
};
|
};
|
@ -0,0 +1,35 @@
|
|||||||
|
import { useContext } from 'react';
|
||||||
|
import { useAPIClient, useResourceActionContext } from '@tachybase/client';
|
||||||
|
import { RolesManagerContext } from '@tachybase/plugin-acl/client';
|
||||||
|
|
||||||
|
import { App } from 'antd';
|
||||||
|
|
||||||
|
import { useTranslation } from '../../../../locale';
|
||||||
|
|
||||||
|
export const useBulkRemoveDepartments = () => {
|
||||||
|
const API = useAPIClient();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { message } = App.useApp();
|
||||||
|
|
||||||
|
const { state, setState, refresh } = useResourceActionContext();
|
||||||
|
const { role } = useContext(RolesManagerContext);
|
||||||
|
|
||||||
|
return {
|
||||||
|
async run() {
|
||||||
|
const selectedRowKeys = state?.selectedRowKeys;
|
||||||
|
if (!selectedRowKeys?.length) {
|
||||||
|
message.warning(t('Please select departments'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const apiResource = API.resource(`roles/${role == null ? void 0 : role.name}/departments`);
|
||||||
|
await apiResource.remove({ values: selectedRowKeys });
|
||||||
|
|
||||||
|
setState?.({
|
||||||
|
selectedRowKeys: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
@ -1,10 +1,13 @@
|
|||||||
import { useRequest } from '@tachybase/client';
|
import { useRequest } from '@tachybase/client';
|
||||||
|
|
||||||
export const useDataSource2 = (props) => {
|
export const useDataSource = (props) => {
|
||||||
const params = {
|
const params = {
|
||||||
resource: 'departments',
|
resource: 'departments',
|
||||||
action: 'list',
|
action: 'list',
|
||||||
params: { appends: ['roles', 'parent(recursively=true)'], sort: ['createdAt'] },
|
params: {
|
||||||
|
appends: ['roles', 'parent(recursively=true)'],
|
||||||
|
sort: ['createdAt'],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
const service = useRequest(params, props);
|
const service = useRequest(params, props);
|
||||||
return { ...service, defaultRequest: params };
|
return { ...service, defaultRequest: params };
|
@ -0,0 +1,11 @@
|
|||||||
|
import { useContext } from 'react';
|
||||||
|
import { RolesManagerContext } from '@tachybase/plugin-acl/client';
|
||||||
|
|
||||||
|
export const useDisabled = () => {
|
||||||
|
const { role } = useContext(RolesManagerContext);
|
||||||
|
return {
|
||||||
|
disabled: (params) => {
|
||||||
|
return params?.roles?.some((itemRole) => itemRole.name === role?.name);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,20 @@
|
|||||||
|
import { useContext } from 'react';
|
||||||
|
import { useAPIClient, useRecord, useResourceActionContext } from '@tachybase/client';
|
||||||
|
import { RolesManagerContext } from '@tachybase/plugin-acl/client';
|
||||||
|
|
||||||
|
export const useRemoveDepartment = () => {
|
||||||
|
const API = useAPIClient();
|
||||||
|
const { role } = useContext(RolesManagerContext);
|
||||||
|
const { data } = useRecord();
|
||||||
|
const { refresh } = useResourceActionContext();
|
||||||
|
|
||||||
|
return {
|
||||||
|
async run() {
|
||||||
|
const apiResource = API.resource(`roles/${role == null ? void 0 : role.name}/departments`);
|
||||||
|
|
||||||
|
await apiResource.remove({ values: [data.id] });
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
@ -1,322 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { uid } from '@tachybase/schema';
|
|
||||||
|
|
||||||
export const getSchemaHe = (department, user) => {
|
|
||||||
const schemaNotUser = user
|
|
||||||
? {}
|
|
||||||
: {
|
|
||||||
actions: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'ActionBar',
|
|
||||||
'x-component-props': {
|
|
||||||
style: {
|
|
||||||
marginBottom: 16,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
[uid()]: {
|
|
||||||
type: 'void',
|
|
||||||
title: '{{ t("Filter") }}',
|
|
||||||
'x-action': 'filter',
|
|
||||||
'x-component': 'Filter.Action',
|
|
||||||
'x-use-component-props': 'useFilterActionProps',
|
|
||||||
'x-component-props': {
|
|
||||||
icon: 'FilterOutlined',
|
|
||||||
},
|
|
||||||
'x-align': 'left',
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'MemberActions',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const tableSchemaDepartMent = department
|
|
||||||
? {
|
|
||||||
isOwner: {
|
|
||||||
type: 'void',
|
|
||||||
'x-decorator': 'Table.Column.Decorator',
|
|
||||||
'x-component': 'Table.Column',
|
|
||||||
'x-component-props': { style: { minWidth: 100 } },
|
|
||||||
title: '{{t("Owner")}}',
|
|
||||||
properties: {
|
|
||||||
isOwner: {
|
|
||||||
type: 'boolean',
|
|
||||||
'x-component': 'IsOwnerField',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: {};
|
|
||||||
|
|
||||||
const schemaActions = department
|
|
||||||
? {
|
|
||||||
remove: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'RowRemoveAction',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: {};
|
|
||||||
|
|
||||||
return {
|
|
||||||
type: 'void',
|
|
||||||
properties: {
|
|
||||||
...schemaNotUser,
|
|
||||||
table: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Table.Void',
|
|
||||||
'x-component-props': {
|
|
||||||
rowKey: 'id',
|
|
||||||
rowSelection: {
|
|
||||||
type: 'checkbox',
|
|
||||||
},
|
|
||||||
useDataSource: '{{ useMembersDataSource }}',
|
|
||||||
pagination: {
|
|
||||||
showTotal: '{{ useShowTotal }}',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
nickname: {
|
|
||||||
type: 'void',
|
|
||||||
'x-decorator': 'Table.Column.Decorator',
|
|
||||||
'x-component': 'Table.Column',
|
|
||||||
properties: {
|
|
||||||
nickname: {
|
|
||||||
type: 'string',
|
|
||||||
'x-component': 'CollectionField',
|
|
||||||
'x-read-pretty': true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
username: {
|
|
||||||
type: 'void',
|
|
||||||
'x-decorator': 'Table.Column.Decorator',
|
|
||||||
'x-component': 'Table.Column',
|
|
||||||
properties: {
|
|
||||||
username: {
|
|
||||||
type: 'string',
|
|
||||||
'x-component': 'CollectionField',
|
|
||||||
'x-read-pretty': true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
departments: {
|
|
||||||
type: 'void',
|
|
||||||
'x-decorator': 'Table.Column.Decorator',
|
|
||||||
'x-component': 'Table.Column',
|
|
||||||
properties: {
|
|
||||||
departments: { type: 'string', 'x-component': 'CollectionField', 'x-read-pretty': true },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
...tableSchemaDepartMent,
|
|
||||||
phone: {
|
|
||||||
type: 'void',
|
|
||||||
'x-decorator': 'Table.Column.Decorator',
|
|
||||||
'x-component': 'Table.Column',
|
|
||||||
properties: {
|
|
||||||
phone: {
|
|
||||||
type: 'string',
|
|
||||||
'x-component': 'CollectionField',
|
|
||||||
'x-read-pretty': true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
email: {
|
|
||||||
type: 'void',
|
|
||||||
'x-decorator': 'Table.Column.Decorator',
|
|
||||||
'x-component': 'Table.Column',
|
|
||||||
properties: {
|
|
||||||
email: {
|
|
||||||
type: 'string',
|
|
||||||
'x-component': 'CollectionField',
|
|
||||||
'x-read-pretty': true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
type: 'void',
|
|
||||||
title: '{{t("Actions")}}',
|
|
||||||
'x-component': 'Table.Column',
|
|
||||||
properties: {
|
|
||||||
actions: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Space',
|
|
||||||
'x-component-props': { split: '|' },
|
|
||||||
properties: {
|
|
||||||
update: {
|
|
||||||
type: 'void',
|
|
||||||
title: '{{t("Configure")}}',
|
|
||||||
'x-component': 'Action.Link',
|
|
||||||
'x-component-props': { type: 'primary' },
|
|
||||||
properties: {
|
|
||||||
drawer: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Action.Drawer',
|
|
||||||
'x-decorator': 'FormV2',
|
|
||||||
title: '{{t("Configure")}}',
|
|
||||||
properties: {
|
|
||||||
departments: {
|
|
||||||
title: '{{t("Departments")}}',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'UserDepartmentsField',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
...schemaActions,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// return {
|
|
||||||
// type: 'void',
|
|
||||||
// properties: T(
|
|
||||||
// y(
|
|
||||||
// {},
|
|
||||||
// user
|
|
||||||
// ? {}
|
|
||||||
// : {
|
|
||||||
// actions: {
|
|
||||||
// type: 'void',
|
|
||||||
// 'x-component': 'ActionBar',
|
|
||||||
// 'x-component-props': {
|
|
||||||
// style: {
|
|
||||||
// marginBottom: 16,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// properties: {
|
|
||||||
// [uid()]: {
|
|
||||||
// type: 'void',
|
|
||||||
// title: '{{ t("Filter") }}',
|
|
||||||
// 'x-action': 'filter',
|
|
||||||
// 'x-component': 'Filter.Action',
|
|
||||||
// 'x-use-component-props': 'useFilterActionProps',
|
|
||||||
// 'x-component-props': {
|
|
||||||
// icon: 'FilterOutlined',
|
|
||||||
// },
|
|
||||||
// 'x-align': 'left',
|
|
||||||
// },
|
|
||||||
// actions: {
|
|
||||||
// type: 'void',
|
|
||||||
// 'x-component': 'MemberActions',
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
// {
|
|
||||||
// table: {
|
|
||||||
// type: 'void',
|
|
||||||
// 'x-component': 'Table.Void',
|
|
||||||
// 'x-component-props': {
|
|
||||||
// rowKey: 'id',
|
|
||||||
// rowSelection: { type: 'checkbox' },
|
|
||||||
// useDataSource: '{{ useMembersDataSource }}',
|
|
||||||
// pagination: { showTotal: '{{ useShowTotal }}' },
|
|
||||||
// },
|
|
||||||
// properties: T(
|
|
||||||
// y(
|
|
||||||
// {
|
|
||||||
// nickname: {
|
|
||||||
// type: 'void',
|
|
||||||
// 'x-decorator': 'Table.Column.Decorator',
|
|
||||||
// 'x-component': 'Table.Column',
|
|
||||||
// properties: { nickname: { type: 'string', 'x-component': 'CollectionField', 'x-read-pretty': true } },
|
|
||||||
// },
|
|
||||||
// username: {
|
|
||||||
// type: 'void',
|
|
||||||
// 'x-decorator': 'Table.Column.Decorator',
|
|
||||||
// 'x-component': 'Table.Column',
|
|
||||||
// properties: { username: { type: 'string', 'x-component': 'CollectionField', 'x-read-pretty': true } },
|
|
||||||
// },
|
|
||||||
// departments: {
|
|
||||||
// type: 'void',
|
|
||||||
// 'x-decorator': 'Table.Column.Decorator',
|
|
||||||
// 'x-component': 'Table.Column',
|
|
||||||
// properties: {
|
|
||||||
// departments: { type: 'string', 'x-component': 'CollectionField', 'x-read-pretty': true },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// department
|
|
||||||
// ? {
|
|
||||||
// isOwner: {
|
|
||||||
// type: 'void',
|
|
||||||
// 'x-decorator': 'Table.Column.Decorator',
|
|
||||||
// 'x-component': 'Table.Column',
|
|
||||||
// 'x-component-props': { style: { minWidth: 100 } },
|
|
||||||
// title: '{{t("Owner")}}',
|
|
||||||
// properties: { isOwner: { type: 'boolean', 'x-component': 'IsOwnerField' } },
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
// : {},
|
|
||||||
// ),
|
|
||||||
// {
|
|
||||||
// phone: {
|
|
||||||
// type: 'void',
|
|
||||||
// 'x-decorator': 'Table.Column.Decorator',
|
|
||||||
// 'x-component': 'Table.Column',
|
|
||||||
// properties: { phone: { type: 'string', 'x-component': 'CollectionField', 'x-read-pretty': true } },
|
|
||||||
// },
|
|
||||||
// email: {
|
|
||||||
// type: 'void',
|
|
||||||
// 'x-decorator': 'Table.Column.Decorator',
|
|
||||||
// 'x-component': 'Table.Column',
|
|
||||||
// properties: { email: { type: 'string', 'x-component': 'CollectionField', 'x-read-pretty': true } },
|
|
||||||
// },
|
|
||||||
// actions: {
|
|
||||||
// type: 'void',
|
|
||||||
// title: '{{t("Actions")}}',
|
|
||||||
// 'x-component': 'Table.Column',
|
|
||||||
// properties: {
|
|
||||||
// actions: {
|
|
||||||
// type: 'void',
|
|
||||||
// 'x-component': 'Space',
|
|
||||||
// 'x-component-props': { split: '|' },
|
|
||||||
// properties: y(
|
|
||||||
// {
|
|
||||||
// update: {
|
|
||||||
// type: 'void',
|
|
||||||
// title: '{{t("Configure")}}',
|
|
||||||
// 'x-component': 'Action.Link',
|
|
||||||
// 'x-component-props': { type: 'primary' },
|
|
||||||
// properties: {
|
|
||||||
// drawer: {
|
|
||||||
// type: 'void',
|
|
||||||
// 'x-component': 'Action.Drawer',
|
|
||||||
// 'x-decorator': 'FormV2',
|
|
||||||
// title: '{{t("Configure")}}',
|
|
||||||
// properties: {
|
|
||||||
// departments: {
|
|
||||||
// title: '{{t("Departments")}}',
|
|
||||||
// 'x-decorator': 'FormItem',
|
|
||||||
// 'x-component': 'UserDepartmentsField',
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// department ? { remove: { type: 'void', 'x-component': 'RowRemoveAction' } } : {},
|
|
||||||
// ),
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
|
|
||||||
// // properties: {
|
|
||||||
|
|
||||||
// // }
|
|
||||||
// };
|
|
||||||
};
|
|
@ -1,19 +0,0 @@
|
|||||||
import { Ee, Fe, L } from './tools';
|
|
||||||
import { Ve } from './Ve';
|
|
||||||
|
|
||||||
export function B(e, t, o) {
|
|
||||||
(o = o || {}),
|
|
||||||
(o.arrayMerge = o.arrayMerge || Ee),
|
|
||||||
(o.isMergeableObject = o.isMergeableObject || Fe),
|
|
||||||
(o.cloneUnlessOtherwiseSpecified = L);
|
|
||||||
var a = Array.isArray(t),
|
|
||||||
r = Array.isArray(e),
|
|
||||||
c = a === r;
|
|
||||||
return c ? (a ? o.arrayMerge(e, t, o) : Ve(e, t, o)) : L(t, o);
|
|
||||||
}
|
|
||||||
B.all = function (t, o) {
|
|
||||||
if (!Array.isArray(t)) throw new Error('first argument should be an array');
|
|
||||||
return t.reduce(function (a, r) {
|
|
||||||
return B(a, r, o);
|
|
||||||
}, {});
|
|
||||||
};
|
|
@ -1,15 +0,0 @@
|
|||||||
import { ae, ce, Ke, L, qe } from './tools';
|
|
||||||
|
|
||||||
export function Ve(e, t, o) {
|
|
||||||
var a = {};
|
|
||||||
return (
|
|
||||||
o.isMergeableObject(e) &&
|
|
||||||
ae(e).forEach(function (r) {
|
|
||||||
a[r] = L(e[r], o);
|
|
||||||
}),
|
|
||||||
ae(t).forEach(function (r) {
|
|
||||||
qe(e, r) || (ce(e, r) && o.isMergeableObject(t[r]) ? (a[r] = Ke(r, o)(e[r], t[r], o)) : (a[r] = L(t[r], o)));
|
|
||||||
}),
|
|
||||||
a
|
|
||||||
);
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user