chore: refactor departments (#1212)

Reviewed-on: daoyoucloud/tachybase#1212
This commit is contained in:
sealday 2024-06-20 11:55:58 +08:00
parent b755424af5
commit d2dbcf8799
22 changed files with 391 additions and 530 deletions

View File

@ -1,114 +0,0 @@
import React, { useEffect, useState } from 'react';
import { useField } from '@tachybase/schema';
import { TreeSelect } from 'antd';
// import { jsx } from 'react/jsx-runtime';
import { k } from '../others/k';
import { getDepartmentStr } from '../utils/getDepartmentStr';
interface tempField {
value?: any;
setValue: Function;
}
interface IState {
label?: object;
value?: object;
}
// 编辑部门-上级部门选择器
export const ComponentLle = (props) => {
const field = useField<tempField>();
const [value, setValue] = useState<IState>({ label: null, value: null });
const {
treeData: treeData,
initData: initData,
getByKeyword: getByKeyword,
loadData: loadData,
loadedKeys: loadedKeys,
setLoadedKeys: setLoadedKeys,
originData: originData,
} = props;
const onSearch = (h) =>
k(this, null, function* () {
if (!h) {
initData(originData);
return;
}
yield getByKeyword(h);
});
// const b = useCallback((h) => {
// const F = h.title,
// C = h.parent;
// return C ? b(C) + ' / ' + F : F;
// }, []);
useEffect(() => {
initData(originData);
}, [originData, initData]);
useEffect(() => {
if (!field.value) {
setValue({ label: null, value: null });
return;
}
setValue({
label: getDepartmentStr(field.value) || field.value.label,
value: field.value.id,
});
}, [field.value, getDepartmentStr]);
// return null;
return (
<TreeSelect
value={value}
onSelect={(h, currValue) => {
field.setValue(currValue);
}}
onChange={(h) => {
h || field.setValue(null);
}}
treeData={treeData}
treeLoadedKeys={loadedKeys}
onTreeLoad={(keys) => setLoadedKeys(keys)}
loadData={(value) => loadData({ key: value.id, children: value.children })}
fieldNames={{ value: 'id' }}
showSearch={true}
allowClear={true}
treeNodeFilterProp={'title'}
onSearch={onSearch}
labelInValue={true}
/>
);
// return (
// useEffect(() => {
// c(d);
// }, [d, c]),
// useEffect(() => {
// if (!t.value) {
// a({ label: null, value: null });
// return;
// }
// a({ label: b(t.value) || t.value.label, value: t.value.id });
// }, [t.value, b]),
// jsx(TreeSelect, {
// value: o,
// onSelect: (h, F) => {
// t.setValue(F);
// },
// onChange: (h) => {
// h || t.setValue(null);
// },
// treeData: r,
// treeLoadedKeys: m,
// onTreeLoad: (h) => g(h),
// loadData: (h) => x({ key: h.id, children: h.children }),
// fieldNames: { value: 'id' },
// showSearch: true,
// allowClear: true,
// treeNodeFilterProp: 'title',
// onSearch: A,
// labelInValue: true,
// })
// );
};

View File

@ -16,7 +16,7 @@ const useStyles = createStyles(({ css }) => ({
`, `,
})); }));
export const ComponentSe = () => { export const DepartmentsTree = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { token } = theme.useToken(); const { token } = theme.useToken();
const { setDepartment, setUser } = useContext(DepartmentsContext); const { setDepartment, setUser } = useContext(DepartmentsContext);

View File

@ -0,0 +1,35 @@
import React, { useContext } from 'react';
import { EllipsisWithTooltip } from '@tachybase/client';
import { useField } from '@tachybase/schema';
import { DepartmentsContext } from '../context/DepartmentsContext';
import { getDepartmentStr } from '../utils/getDepartmentStr';
export const DepartmentField = () => {
const { setDepartment } = useContext(DepartmentsContext);
const field = useField<{ value: Array<any> }>();
const fieldValues = field.value || [];
const department = fieldValues.reduce((acc, curr) => {
acc[curr.id] = curr;
return acc;
}, {});
return (
<EllipsisWithTooltip ellipsis={true}>
{fieldValues.map((currFieldValue, index) => (
<span key={index}>
<a
onClick={(event) => {
event.preventDefault();
setDepartment(department[currFieldValue.id]);
}}
>
{getDepartmentStr(currFieldValue)}
</a>
{index !== fieldValues.length - 1 ? <span style={{ marginRight: 4, color: '#aaa' }}>,</span> : ''}
</span>
))}
</EllipsisWithTooltip>
);
};

View File

@ -1,73 +0,0 @@
import React, { useContext } from 'react';
import { EllipsisWithTooltip } from '@tachybase/client';
import { useField } from '@tachybase/schema';
// import { jsx, jsxs } from 'react/jsx-runtime';
import { DepartmentsContext } from '../context/DepartmentsContext';
import { getDepartmentStr } from '../utils/getDepartmentStr';
export const DepartmentFieldYe = () => {
const { setDepartment } = useContext(DepartmentsContext);
const field = useField<{ value: Array<any> }>();
const fieldValues = field.value || [];
const department = fieldValues.reduce((acc, curr) => {
acc[curr.id] = curr;
return acc;
}, {});
return (
<EllipsisWithTooltip ellipsis={true}>
{fieldValues.map((currFieldValue, index) => (
<span key={index}>
<a
onClick={(event) => {
event.preventDefault();
setDepartment(department[currFieldValue.id]);
}}
>
{getDepartmentStr(currFieldValue)}
</a>
{index !== fieldValues.length - 1 ? <span style={{ marginRight: 4, color: '#aaa' }}>,</span> : ''}
</span>
))}
</EllipsisWithTooltip>
);
// const children2 = fieldValues.map((currFieldValue, index) => {
// return (
// <span key={index}>
// <a
// onClick={(x) => {
// x.preventDefault(), setDepartment(department[currFieldValue.id]);
// }}
// >
// {getDepartmentStr(currFieldValue)}
// </a>
// {index !== fieldValues.length - 1 ? <span style={{ marginRight: 4, color: '#aaa' }}>,</span> : ''}
// </span>
// );
// });
// const children = fieldValues.map((currFieldValue, index) =>
// jsxs(
// 'span',
// {
// children: [
// jsx('a', {
// onClick: (x) => {
// x.preventDefault(), setDepartment(department[currFieldValue.id]);
// },
// children: getDepartmentStr(currFieldValue),
// }),
// index !== fieldValues.length - 1
// ? jsx('span', { style: { marginRight: 4, color: '#aaa' }, children: ',' })
// : '',
// ],
// },
// index,
// ),
// );
// return jsx(EllipsisWithTooltip, { ellipsis: true, children: children });
};

View File

@ -1,14 +1,13 @@
// import { jsx, jsxs } from 'react/jsx-runtime';
import React from 'react'; import React from 'react';
import { SchemaComponentOptions } from '@tachybase/client'; import { SchemaComponentOptions } from '@tachybase/client';
import { Col, Row } from 'antd'; import { Col, Row } from 'antd';
import { useFilterActionPropsZ } from '../scopes/useFilterActionPropsZ'; import { useDepartmentFilterActionProps } from '../scopes/useDepartmentFilterActionProps';
import { ComponentEEE } from './ComponentEEE'; import { DepartmentsBlock } from './DepartmentsBlock';
import { ComponentIit } from './ComponentIit';
import { DepartmentSelect } from './DepartmentSelect'; import { DepartmentSelect } from './DepartmentSelect';
import { DepartmentsResourceProvider } from './DepartmentsResourceProvider'; import { DepartmentsResourceProvider } from './DepartmentsResourceProvider';
import { DepartmentsUsersBlock } from './DepartmentsUsersBlock';
import { SuperiorDepartmentSelect } from './SuperiorDepartmentSelect'; import { SuperiorDepartmentSelect } from './SuperiorDepartmentSelect';
import { UserResourceProvider } from './UserResourceProvider'; import { UserResourceProvider } from './UserResourceProvider';
@ -16,46 +15,20 @@ export const DepartmentManagement = () => {
return ( return (
<SchemaComponentOptions <SchemaComponentOptions
components={{ SuperiorDepartmentSelect, DepartmentSelect }} components={{ SuperiorDepartmentSelect, DepartmentSelect }}
scope={{ useFilterActionProps: useFilterActionPropsZ }} scope={{ useFilterActionProps: useDepartmentFilterActionProps }}
> >
<Row gutter={48} style={{ flexWrap: 'nowrap' }}> <Row gutter={48} style={{ flexWrap: 'nowrap' }}>
<Col span={6} style={{ borderRight: '1px solid #eee', minWidth: '300px' }}> <Col span={6} style={{ borderRight: '1px solid #eee', minWidth: '300px' }}>
<DepartmentsResourceProvider> <DepartmentsResourceProvider>
<ComponentEEE /> <DepartmentsBlock />
</DepartmentsResourceProvider> </DepartmentsResourceProvider>
</Col> </Col>
<Col flex="auto" style={{ overflow: 'hidden' }}> <Col flex="auto" style={{ overflow: 'hidden' }}>
<UserResourceProvider> <UserResourceProvider>
<ComponentIit /> <DepartmentsUsersBlock />
</UserResourceProvider> </UserResourceProvider>
</Col> </Col>
</Row> </Row>
</SchemaComponentOptions> </SchemaComponentOptions>
); );
// return jsx(SchemaComponentOptions, {
// components: {
// SuperiorDepartmentSelect: SuperiorDepartmentSelect,
// DepartmentSelect: DepartmentSelect,
// },
// scope: {
// useFilterActionProps: useFilterActionPropsZ,
// },
// children: jsxs(Row, {
// gutter: 48,
// style: { flexWrap: 'nowrap' },
// children: [
// jsx(Col, {
// span: 6,
// style: { borderRight: '1px solid #eee', minWidth: '300px' },
// children: jsx(CeComponent, { children: jsx(ComponentEEE, {}) }),
// }),
// jsx(Col, {
// flex: 'auto',
// style: { overflow: 'hidden' },
// children: jsx(BeComponent, { children: jsx(ComponentIit, {}) }),
// }),
// ],
// }),
// });
}; };

View File

@ -1,18 +1,14 @@
import { useContext } from 'react'; import React, { useContext } from 'react';
import { jsx } from 'react/jsx-runtime';
import { DepartmentsContext } from '../context/DepartmentsContext'; import { DepartmentsContext } from '../context/DepartmentsContext';
import { useDepTree2 } from '../hooks/useDepTree2'; import { useDepTree2 } from '../hooks/useDepTree2';
import { T } from '../others/T'; import { InternalSuperiorDepartmentSelect } from './InternalSuperiorDepartmentSelect';
import { y } from '../others/y';
import { ComponentLle } from './ComponentLle';
export const DepartmentSelect = () => { export const DepartmentSelect = () => {
const e = useDepTree2(), const depTree = useDepTree2();
{ departmentsResource: t } = useContext(DepartmentsContext), const { departmentsResource } = useContext(DepartmentsContext);
{ const {
service: { data: o }, service: { data },
} = t || {}; } = departmentsResource || {};
return jsx(ComponentLle, T(y({}, e), { originData: o == null ? void 0 : o.data })); return <InternalSuperiorDepartmentSelect {...{ ...depTree, originData: data?.data }} />;
}; };

View File

@ -1,29 +1,28 @@
import React from 'react';
import { SchemaComponent } from '@tachybase/client'; import { SchemaComponent } from '@tachybase/client';
import { uid } from '@tachybase/schema'; import { uid } from '@tachybase/schema';
import { jsx } from 'react/jsx-runtime'; import { useFilterActionProps } from '../scopes/useFilterActionProps';
import { InternalDepartmentTable } from './InternalDepartmentTable';
import { useFilterActionPropsXe } from '../scopes/useFilterActionPropsXe';
import { InternalDepartmentTableRe } from './InternalDepartmentTableRe';
import { RequestProvider } from './RequestProvider'; import { RequestProvider } from './RequestProvider';
export const DepartmentTablePpe = ({ useDataSource: e, useDisabled: t }) => export const DepartmentTable = ({ useDataSource, useDisabled }) => (
jsx(SchemaComponent, { <SchemaComponent
scope: { scope={{
useDisabled: t, useDisabled,
useFilterActionProps: useFilterActionPropsXe, useFilterActionProps,
}, }}
components: { components={{
InternalDepartmentTable: InternalDepartmentTableRe, InternalDepartmentTable,
RequestProvider: RequestProvider, RequestProvider,
}, }}
schema: { schema={{
type: 'void', type: 'void',
properties: { properties: {
[uid()]: { [uid()]: {
type: 'void', type: 'void',
'x-component': 'RequestProvider', 'x-component': 'RequestProvider',
'x-component-props': { useDataSource: e }, 'x-component-props': { useDataSource },
properties: { properties: {
actions: { actions: {
type: 'void', type: 'void',
@ -50,5 +49,6 @@ export const DepartmentTablePpe = ({ useDataSource: e, useDisabled: t }) =>
}, },
}, },
}, },
}, }}
}); />
);

View File

@ -0,0 +1,12 @@
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)}</>;
};

View File

@ -1,14 +0,0 @@
import { Fragment } from 'react';
import { useRecord } from '@tachybase/client';
import { jsx } from 'react/jsx-runtime';
export const DepartmentTitleHht = () => {
const e = useRecord(),
t = (o) => {
const a = o.title,
r = o.parent;
return r ? t(r) + ' / ' + a : a;
};
return jsx(Fragment, { children: t(e) });
};

View File

@ -10,9 +10,9 @@ import { useDataSource2 } from '../hooks/useDataSource2';
import { useDisabledVvt } from '../hooks/useDisabledVvt'; import { useDisabledVvt } from '../hooks/useDisabledVvt';
import { useRemoveDepartmentXxt } from '../hooks/useRemoveDepartmentXxt'; import { useRemoveDepartmentXxt } from '../hooks/useRemoveDepartmentXxt';
import { getSchemaDdt } from '../schema/getSchemaDdt'; import { getSchemaDdt } from '../schema/getSchemaDdt';
import { useFilterActionPropsZ } from '../scopes/useFilterActionPropsZ'; import { useDepartmentFilterActionProps } from '../scopes/useDepartmentFilterActionProps';
import { DepartmentTablePpe } from './DepartmentTablePpe'; import { DepartmentTable } from './DepartmentTable';
import { DepartmentTitleHht } from './DepartmentTitleHht'; import { DepartmentTitle } from './DepartmentTitle';
export const Departments = () => { export const Departments = () => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -32,11 +32,11 @@ export const Departments = () => {
<SchemaComponent <SchemaComponent
schema={schema} schema={schema}
components={{ components={{
DepartmentTable: DepartmentTablePpe, DepartmentTable: DepartmentTable,
DepartmentTitle: DepartmentTitleHht, DepartmentTitle: DepartmentTitle,
}} }}
scope={{ scope={{
useFilterActionProps: useFilterActionPropsZ, useFilterActionProps: useDepartmentFilterActionProps,
t, t,
useRemoveDepartment: useRemoveDepartmentXxt, useRemoveDepartment: useRemoveDepartmentXxt,
useBulkRemoveDepartments: useBulkRemoveDepartmentsYyt, useBulkRemoveDepartments: useBulkRemoveDepartmentsYyt,

View File

@ -10,7 +10,7 @@ import { DepartmentsExpandedContextProvider } from '../context/DepartmentsExpand
import { useCreateDepartment } from '../hooks/useCreateDepartment'; import { useCreateDepartment } from '../hooks/useCreateDepartment';
import { useDepTree2 } from '../hooks/useDepTree2'; import { useDepTree2 } from '../hooks/useDepTree2';
import { useUpdateDepartment } from '../hooks/useUpdateDepartment'; import { useUpdateDepartment } from '../hooks/useUpdateDepartment';
import { ComponentSe } from './ComponentSe'; import { DepartmentsTree } from './ComponentSe';
import { ComponentX } from './ComponentX'; import { ComponentX } from './ComponentX';
import { DepartmentOwnersField } from './DepartmentOwnersField'; import { DepartmentOwnersField } from './DepartmentOwnersField';
import { NewDepartment } from './NewDepartment'; import { NewDepartment } from './NewDepartment';
@ -20,7 +20,7 @@ interface drawerState {
schema?: object; schema?: object;
} }
export const ComponentEEE = () => { export const DepartmentsBlock = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
@ -41,7 +41,7 @@ export const ComponentEEE = () => {
> >
<DepartmentsExpandedContextProvider value={m}> <DepartmentsExpandedContextProvider value={m}>
<Row> <Row>
<ComponentSe /> <DepartmentsTree />
<Button <Button
type="text" type="text"
icon={<UserOutlined />} icon={<UserOutlined />}
@ -63,8 +63,8 @@ export const ComponentEEE = () => {
<ComponentX /> <ComponentX />
<ActionContextProvider <ActionContextProvider
value={{ value={{
visible: visible, visible,
setVisible: setVisible, setVisible,
}} }}
> >
<RecordProvider record={drawer.node || {}}> <RecordProvider record={drawer.node || {}}>

View File

@ -10,14 +10,14 @@ import { useShowTotal } from '../hooks/useShowTotal';
import { getSchemaHe } from '../schema/getSchemaHe'; import { getSchemaHe } from '../schema/getSchemaHe';
import { schemaWe } from '../schema/schemaWe'; import { schemaWe } from '../schema/schemaWe';
import { schemaZe } from '../schema/schemaZe'; import { schemaZe } from '../schema/schemaZe';
import { useFilterActionPropsZ } from '../scopes/useFilterActionPropsZ'; import { useDepartmentFilterActionProps } from '../scopes/useDepartmentFilterActionProps';
import { AddMembers } from './AddMembers'; import { AddMembers } from './AddMembers';
import { DepartmentFieldYe } from './DepartmentFieldYe'; import { DepartmentField } from './DepartmentField';
import { IsOwnerField } from './IsOwnerField'; import { IsOwnerField } from './IsOwnerField';
import { UserDepartmentsFieldOot } from './UserDepartmentsFieldOot'; import { UserDepartmentsField } from './UserDepartmentsField';
export const ComponentIit = () => { export const DepartmentsUsersBlock = () => {
const { t: tval } = useTranslation(); const { t } = useTranslation();
const { department, user } = useContext(DepartmentsContext); const { department, user } = useContext(DepartmentsContext);
const { data, setState } = useResourceActionContext(); const { data, setState } = useResourceActionContext();
@ -42,22 +42,22 @@ export const ComponentIit = () => {
return ( return (
<> <>
<h2>{user ? tval('Search results') : tval(department?.title ?? 'All users')}</h2> <h2>{user ? t('Search results') : t(department?.title ?? 'All users')}</h2>
<SchemaComponent <SchemaComponent
scope={{ scope={{
useBulkRemoveMembersAction: useBulkRemoveMembersAction, useBulkRemoveMembersAction,
useMembersDataSource: useMembersDataSource, useMembersDataSource,
t: tval, t,
useShowTotal: useShowTotal, useShowTotal,
useFilterActionProps: useFilterActionPropsZ, useFilterActionProps: useDepartmentFilterActionProps,
}} }}
components={{ components={{
MemberActions: MemberActions, MemberActions,
AddMembers: AddMembers, AddMembers,
RowRemoveAction: RowRemoveAction, RowRemoveAction,
DepartmentField: DepartmentFieldYe, DepartmentField,
IsOwnerField: IsOwnerField, IsOwnerField,
UserDepartmentsField: UserDepartmentsFieldOot, UserDepartmentsField,
}} }}
schema={schema} schema={schema}
/> />

View File

@ -6,14 +6,14 @@ import { Table } from 'antd';
import { jsx } from 'react/jsx-runtime'; import { jsx } from 'react/jsx-runtime';
import { useTranslation } from '../../../locale'; import { useTranslation } from '../../../locale';
import { FilterKeysContext } from '../context/FilterKeysContext';
import { useDepTree2 } from '../hooks/useDepTree2'; import { useDepTree2 } from '../hooks/useDepTree2';
import { T } from '../others/T'; import { T } from '../others/T';
import { y } from '../others/y'; import { y } from '../others/y';
import { getDepartmentStr } from '../utils/getDepartmentStr'; import { getDepartmentStr } from '../utils/getDepartmentStr';
import { FilterKeysContext } from '../context/FilterKeysContext';
const Ze = () => ({ disabled: () => false }); const Ze = () => ({ disabled: () => false });
export const InternalDepartmentTableRe = ({ useDisabled: e = Ze }) => { export const InternalDepartmentTable = ({ useDisabled: e = Ze }) => {
const { t } = useTranslation(), const { t } = useTranslation(),
o = useResourceActionContext(); o = useResourceActionContext();
console.log(o); console.log(o);

View File

@ -0,0 +1,66 @@
import React, { useEffect, useState } from 'react';
import { useField } from '@tachybase/schema';
import { TreeSelect } from 'antd';
import { getDepartmentStr } from '../utils/getDepartmentStr';
interface tempField {
value?: any;
setValue: Function;
}
interface IState {
label?: object;
value?: object;
}
// 编辑部门-上级部门选择器
export const InternalSuperiorDepartmentSelect = (props) => {
const field = useField<tempField>();
const [value, setValue] = useState<IState>({ label: null, value: null });
const { treeData, initData, getByKeyword, loadData, loadedKeys, setLoadedKeys, originData } = props;
const onSearch = async (h) => {
if (!h) {
initData(originData);
return;
}
await getByKeyword(h);
};
useEffect(() => {
initData(originData);
}, [originData, initData]);
useEffect(() => {
if (!field.value) {
setValue({ label: null, value: null });
return;
}
setValue({
label: getDepartmentStr(field.value) || field.value.label,
value: field.value.id,
});
}, [field.value]);
return (
<TreeSelect
value={value}
onSelect={(h, currValue) => {
field.setValue(currValue);
}}
onChange={(h) => {
h || field.setValue(null);
}}
treeData={treeData}
treeLoadedKeys={loadedKeys}
onTreeLoad={(keys) => setLoadedKeys(keys)}
loadData={(value) => loadData({ key: value.id, children: value.children })}
fieldNames={{ value: 'id' }}
showSearch={true}
allowClear={true}
treeNodeFilterProp={'title'}
onSearch={onSearch}
labelInValue={true}
/>
);
};

View File

@ -1,33 +1,27 @@
import { useContext, useEffect } from 'react'; import React, { useContext, useEffect } from 'react';
import { useRecord } from '@tachybase/client'; import { useRecord } from '@tachybase/client';
import { jsx } from 'react/jsx-runtime';
import { DepartmentsContext } from '../context/DepartmentsContext'; import { DepartmentsContext } from '../context/DepartmentsContext';
import { useDepTree2 } from '../hooks/useDepTree2'; import { useDepTree2 } from '../hooks/useDepTree2';
import { T } from '../others/T'; import { InternalSuperiorDepartmentSelect } from './InternalSuperiorDepartmentSelect';
import { y } from '../others/y';
import { ComponentLle } from './ComponentLle';
export const SuperiorDepartmentSelect = () => { export const SuperiorDepartmentSelect = () => {
const e = useDepTree2(), const depTree = useDepTree2();
{ setTreeData: t, getChildrenIds: o } = e, const { setTreeData, getChildrenIds } = depTree;
a = useRecord(), const record = useRecord();
{ departmentsResource: r } = useContext(DepartmentsContext), const { departmentsResource } = useContext(DepartmentsContext);
{ const {
service: { data: c }, service: { data },
} = r || {}; } = departmentsResource || {};
return ( useEffect(() => {
useEffect(() => { if (!record.id) return;
if (!a.id) return; const ids = getChildrenIds(record.id);
const i = o(a.id); ids.push(record.id);
i.push(a.id), setTreeData((x) => {
t((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) => (i.includes(d.id) && (d.disabled = true), d.children && (d.children = m(d.children)), d)); return m(x);
return m(x); });
}); }, [setTreeData, record.id, getChildrenIds]);
}, [t, a.id, o]), return <InternalSuperiorDepartmentSelect {...{ ...depTree, originData: data?.data }} />;
jsx(ComponentLle, T(y({}, e), { originData: c == null ? void 0 : c.data }))
);
}; };

View File

@ -1,26 +1,172 @@
import React from 'react'; import React, { Fragment, useState } from 'react';
import { AssociationField } from '@tachybase/client'; import {
import { connect, mapReadPretty } from '@tachybase/schema'; 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 { jsxs } from 'react/jsx-runtime';
import { useTranslation } from '../../../locale'; 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 = connect(() => { export const UserDepartmentsField = () => {
const { modal, message } = App.useApp();
const { t } = useTranslation(); const { t } = useTranslation();
// return jsxs('div', { const [visible, setVisible] = useState(false);
// style: { const user = useRecord();
// color: '#ccc', const field = useField<Field>();
// }, const { refresh } = useResourceActionContext();
// children: [t('This field is currently not supported for use in form blocks.'), ' '], const m = (l) =>
// }); l != null && l.length
? l.map((u) => {
return ( return {
<div ...u,
style={{ isMain: u.departmentsUsers?.isMain,
color: '#ccc', isOwner: u.departmentsUsers?.isOwner,
}} title: getDepartmentStr(u),
> };
{t('This field is currently not supported for use in form blocks.')} })
</div> : [];
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 },
); );
}, mapReadPretty(AssociationField.ReadPretty)); 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,
}}
/>,
],
});
};

View File

@ -0,0 +1,19 @@
import React from 'react';
import { AssociationField } from '@tachybase/client';
import { connect, mapReadPretty } from '@tachybase/schema';
import { useTranslation } from '../../../locale';
export const UserDepartmentsFieldNotSupport = connect(() => {
const { t } = useTranslation();
return (
<div
style={{
color: '#ccc',
}}
>
{t('This field is currently not supported for use in form blocks.')}
</div>
);
}, mapReadPretty(AssociationField.ReadPretty));

View File

@ -1,179 +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 { k } from '../others/k';
import { T } from '../others/T';
import { y } from '../others/y';
import { schemaJe } from '../schema/schemaJe';
import { getDepartmentStr } from '../utils/getDepartmentStr';
import { DepartmentTablePpe } from './DepartmentTablePpe';
export const UserDepartmentsFieldOot = () => {
const { modal, message } = App.useApp();
const { t } = useTranslation();
const [visible, setVisible] = useState(false);
const user = useRecord();
const field = useField<Field>();
const { refresh: x } = 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: f } = form.values || {};
return {
run() {
return k(this, null, function* () {
yield api.resource('users.departments', user.id).add({ values: f.map((O) => O.id) }),
form.reset(),
field.setValue([
...field.value,
...f.map((O, $) =>
T(y({}, O), { isMain: $ === 0 && field.value.length === 0, title: getDepartmentStr(O) }),
),
]),
setVisible(false),
x();
});
},
};
};
const A = (l) => {
modal.confirm({
title: t('Remove department'),
content: t('Are you sure you want to remove it?'),
onOk: () =>
k(this, null, function* () {
yield api.resource('users.departments', user.id).remove({ values: [l.id] }),
message.success(t('Deleted successfully')),
field.setValue(
field.value
.filter((u) => u.id !== l.id)
.map((u, f) => T(y({}, u), { isMain: (l.isMain && f === 0) || u.isMain })),
),
x();
}),
});
};
const b = (l) =>
k(this, null, function* () {
yield api.resource('users').setMainDepartment({ values: { userId: user.id, departmentId: l.id } }),
message.success(t('Set successfully')),
field.setValue(field.value.map((u) => T(y({}, u), { isMain: u.id === l.id }))),
x();
});
const h = (l) =>
k(this, null, function* () {
yield api.resource('departments').setOwner({ values: { userId: user.id, departmentId: l.id } }),
message.success(t('Set successfully')),
field.setValue(field.value.map((u) => T(y({}, u), { isOwner: u.id === l.id ? true : u.isOwner }))),
x();
});
const F = (l) =>
k(this, null, function* () {
yield api.resource('departments').removeOwner({ values: { userId: user.id, departmentId: l.id } }),
message.success(t('Set successfully')),
field.setValue(field.value.map((u) => T(y({}, u), { isOwner: u.id === l.id ? false : u.isOwner }))),
x();
});
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: DepartmentTablePpe,
}}
scope={{
user,
useDataSource,
useAddDepartments,
useDisabled,
}}
/>,
],
});
};

View File

@ -6,7 +6,7 @@ import { tval } from '../../locale';
import { Departments } from './components/Departments'; import { Departments } from './components/Departments';
import { DepartmentsProvider } from './components/DepartmentsProvider'; import { DepartmentsProvider } from './components/DepartmentsProvider';
import { DepartmentManagementComponent } from './components/DepartmentManagementComponent'; import { DepartmentManagementComponent } from './components/DepartmentManagementComponent';
import { UserDepartmentsField } from './components/UserDepartmentsField'; 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';
@ -14,9 +14,9 @@ import { UserMainDepartmentFieldSetting } from './settings/UserMainDepartmentFie
export class DepartmentsPlugin extends Plugin { export class DepartmentsPlugin extends Plugin {
async load() { async load() {
this.app.addComponents({ this.app.addComponents({
UserDepartmentsField: UserDepartmentsField, UserDepartmentsField: UserDepartmentsFieldNotSupport,
UserMainDepartmentField: UserDepartmentsField, UserMainDepartmentField: UserDepartmentsFieldNotSupport,
DepartmentOwnersField: UserDepartmentsField, DepartmentOwnersField: UserDepartmentsFieldNotSupport,
}); });
this.app.schemaSettingsManager.add(UserDepartmentsFieldSetting); this.app.schemaSettingsManager.add(UserDepartmentsFieldSetting);
this.app.schemaSettingsManager.add(UserMainDepartmentFieldSetting); this.app.schemaSettingsManager.add(UserMainDepartmentFieldSetting);

View File

@ -1,6 +1,6 @@
import { useCollection, useFilterFieldOptions, useFilterFieldProps, useResourceActionContext } from '@tachybase/client'; import { useCollection, useFilterFieldOptions, useFilterFieldProps, useResourceActionContext } from '@tachybase/client';
export const useFilterActionPropsZ = () => { 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();

View File

@ -11,7 +11,7 @@ import { useField } from '@tachybase/schema';
import { useTranslation } from '../../../locale'; import { useTranslation } from '../../../locale';
import { FilterKeysContext } from '../context/FilterKeysContext'; import { FilterKeysContext } from '../context/FilterKeysContext';
export const useFilterActionPropsXe = () => { export const useFilterActionProps = () => {
const { setHasFilter, setExpandedKeys } = useContext(FilterKeysContext); const { setHasFilter, setExpandedKeys } = useContext(FilterKeysContext);
const { t } = useTranslation(); const { t } = useTranslation();
const collection = useContext(CollectionContext); const collection = useContext(CollectionContext);

View File

@ -19,12 +19,12 @@ export const enableLinkItem: SchemaSettingsItemType = {
return { return {
title: t('Enable link'), title: t('Enable link'),
checked: schema['x-component-props']?.enableLink !== false, checked: schema['x-component-props']?.enableLink !== false,
onChange(x) { onChange(enableLink) {
schema['x-component-props'] = { schema['x-component-props'] = {
...schema?.['x-component-props'], ...schema?.['x-component-props'],
enableLink: x, enableLink,
}; };
field.componentProps.enableLink = x; field.componentProps.enableLink = enableLink;
dn.emit('patch', { dn.emit('patch', {
schema: { schema: {
'x-uid': schema['x-uid'], 'x-uid': schema['x-uid'],