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 { token } = theme.useToken();
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 { SchemaComponentOptions } from '@tachybase/client';
import { Col, Row } from 'antd';
import { useFilterActionPropsZ } from '../scopes/useFilterActionPropsZ';
import { ComponentEEE } from './ComponentEEE';
import { ComponentIit } from './ComponentIit';
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';
@ -16,46 +15,20 @@ export const DepartmentManagement = () => {
return (
<SchemaComponentOptions
components={{ SuperiorDepartmentSelect, DepartmentSelect }}
scope={{ useFilterActionProps: useFilterActionPropsZ }}
scope={{ useFilterActionProps: useDepartmentFilterActionProps }}
>
<Row gutter={48} style={{ flexWrap: 'nowrap' }}>
<Col span={6} style={{ borderRight: '1px solid #eee', minWidth: '300px' }}>
<DepartmentsResourceProvider>
<ComponentEEE />
<DepartmentsBlock />
</DepartmentsResourceProvider>
</Col>
<Col flex="auto" style={{ overflow: 'hidden' }}>
<UserResourceProvider>
<ComponentIit />
<DepartmentsUsersBlock />
</UserResourceProvider>
</Col>
</Row>
</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 { jsx } from 'react/jsx-runtime';
import React, { useContext } from 'react';
import { DepartmentsContext } from '../context/DepartmentsContext';
import { useDepTree2 } from '../hooks/useDepTree2';
import { T } from '../others/T';
import { y } from '../others/y';
import { ComponentLle } from './ComponentLle';
import { InternalSuperiorDepartmentSelect } from './InternalSuperiorDepartmentSelect';
export const DepartmentSelect = () => {
const e = useDepTree2(),
{ departmentsResource: t } = useContext(DepartmentsContext),
{
service: { data: o },
} = t || {};
return jsx(ComponentLle, T(y({}, e), { originData: o == null ? void 0 : o.data }));
const depTree = useDepTree2();
const { departmentsResource } = useContext(DepartmentsContext);
const {
service: { data },
} = departmentsResource || {};
return <InternalSuperiorDepartmentSelect {...{ ...depTree, originData: data?.data }} />;
};

View File

@ -1,29 +1,28 @@
import React from 'react';
import { SchemaComponent } from '@tachybase/client';
import { uid } from '@tachybase/schema';
import { jsx } from 'react/jsx-runtime';
import { useFilterActionPropsXe } from '../scopes/useFilterActionPropsXe';
import { InternalDepartmentTableRe } from './InternalDepartmentTableRe';
import { useFilterActionProps } from '../scopes/useFilterActionProps';
import { InternalDepartmentTable } from './InternalDepartmentTable';
import { RequestProvider } from './RequestProvider';
export const DepartmentTablePpe = ({ useDataSource: e, useDisabled: t }) =>
jsx(SchemaComponent, {
scope: {
useDisabled: t,
useFilterActionProps: useFilterActionPropsXe,
},
components: {
InternalDepartmentTable: InternalDepartmentTableRe,
RequestProvider: RequestProvider,
},
schema: {
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: e },
'x-component-props': { useDataSource },
properties: {
actions: {
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 { useRemoveDepartmentXxt } from '../hooks/useRemoveDepartmentXxt';
import { getSchemaDdt } from '../schema/getSchemaDdt';
import { useFilterActionPropsZ } from '../scopes/useFilterActionPropsZ';
import { DepartmentTablePpe } from './DepartmentTablePpe';
import { DepartmentTitleHht } from './DepartmentTitleHht';
import { useDepartmentFilterActionProps } from '../scopes/useDepartmentFilterActionProps';
import { DepartmentTable } from './DepartmentTable';
import { DepartmentTitle } from './DepartmentTitle';
export const Departments = () => {
const { t } = useTranslation();
@ -32,11 +32,11 @@ export const Departments = () => {
<SchemaComponent
schema={schema}
components={{
DepartmentTable: DepartmentTablePpe,
DepartmentTitle: DepartmentTitleHht,
DepartmentTable: DepartmentTable,
DepartmentTitle: DepartmentTitle,
}}
scope={{
useFilterActionProps: useFilterActionPropsZ,
useFilterActionProps: useDepartmentFilterActionProps,
t,
useRemoveDepartment: useRemoveDepartmentXxt,
useBulkRemoveDepartments: useBulkRemoveDepartmentsYyt,

View File

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

View File

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

View File

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

View File

@ -1,26 +1,172 @@
import React from 'react';
import { AssociationField } from '@tachybase/client';
import { connect, mapReadPretty } from '@tachybase/schema';
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 { 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 = connect(() => {
export const UserDepartmentsField = () => {
const { modal, message } = App.useApp();
const { t } = useTranslation();
// return jsxs('div', {
// style: {
// color: '#ccc',
// },
// children: [t('This field is currently not supported for use in form blocks.'), ' '],
// });
return (
<div
style={{
color: '#ccc',
}}
>
{t('This field is currently not supported for use in form blocks.')}
</div>
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 },
);
}, 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 { DepartmentsProvider } from './components/DepartmentsProvider';
import { DepartmentManagementComponent } from './components/DepartmentManagementComponent';
import { UserDepartmentsField } from './components/UserDepartmentsField';
import { UserDepartmentsFieldNotSupport } from './components/UserDepartmentsFieldNotSupport';
import { DepartmentOwnersFieldSetting } from './settings/DepartmentOwnersFieldSetting';
import { UserDepartmentsFieldSetting } from './settings/UserDepartmentsFieldSetting';
import { UserMainDepartmentFieldSetting } from './settings/UserMainDepartmentFieldSetting';
@ -14,9 +14,9 @@ import { UserMainDepartmentFieldSetting } from './settings/UserMainDepartmentFie
export class DepartmentsPlugin extends Plugin {
async load() {
this.app.addComponents({
UserDepartmentsField: UserDepartmentsField,
UserMainDepartmentField: UserDepartmentsField,
DepartmentOwnersField: UserDepartmentsField,
UserDepartmentsField: UserDepartmentsFieldNotSupport,
UserMainDepartmentField: UserDepartmentsFieldNotSupport,
DepartmentOwnersField: UserDepartmentsFieldNotSupport,
});
this.app.schemaSettingsManager.add(UserDepartmentsFieldSetting);
this.app.schemaSettingsManager.add(UserMainDepartmentFieldSetting);

View File

@ -1,6 +1,6 @@
import { useCollection, useFilterFieldOptions, useFilterFieldProps, useResourceActionContext } from '@tachybase/client';
export const useFilterActionPropsZ = () => {
export const useDepartmentFilterActionProps = () => {
const collection = useCollection();
const options = useFilterFieldOptions(collection.fields);
const service = useResourceActionContext();

View File

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

View File

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