feat/MApproval (#1032)
Co-authored-by: bai.zixv <bai.zixv@foxmail.com> Co-authored-by: sealday <zhanglin@daoyoucloud.com> Reviewed-on: daoyoucloud/tachybase#1032 Co-authored-by: wangjiahui <wwwjh0710@163.com> Co-committed-by: wangjiahui <wwwjh0710@163.com>
This commit is contained in:
parent
cfa95bfe1e
commit
602646f2c3
@ -1,13 +1,16 @@
|
||||
import {
|
||||
ExtendCollectionsProvider,
|
||||
SchemaInitializerItem,
|
||||
SchemaInitializerMenu,
|
||||
useSchemaInitializer,
|
||||
useSchemaInitializerItem,
|
||||
} from '@tachybase/client';
|
||||
import React from 'react';
|
||||
import { ISchema } from '@tachybase/schema';
|
||||
import { Toast } from 'antd-mobile';
|
||||
import { CalendarOutline } from 'antd-mobile-icons';
|
||||
import { CollectionWorkflows } from './collection/Workflows.collection';
|
||||
import { CollectionFlowNodes } from './collection/FlowNodes.collection';
|
||||
import { CollectionApprovals } from './collection/Approvals.collection';
|
||||
import { CollectionApprovalTodos } from './collection/ApprovalTodos';
|
||||
|
||||
export const ApprovalBlockInitializer = () => {
|
||||
const { insert } = useSchemaInitializer();
|
||||
@ -20,7 +23,9 @@ export const ApprovalBlockInitializer = () => {
|
||||
'x-toolbar': 'BlockSchemaToolbar',
|
||||
'x-settings': 'ApprovalSettings',
|
||||
'x-component': item.itemComponent,
|
||||
'x-component-props': {},
|
||||
'x-component-props': {
|
||||
collectionName: item.collectionName,
|
||||
},
|
||||
};
|
||||
insert(schema);
|
||||
};
|
||||
@ -46,12 +51,15 @@ export const ApprovalInitializerItem = [
|
||||
name: 'initiationsApproval',
|
||||
title: '发起申请',
|
||||
itemComponent: 'InitiationsBlock',
|
||||
collectionName: 'workflows',
|
||||
},
|
||||
{
|
||||
type: 'item',
|
||||
name: 'currApproval',
|
||||
title: '我发起的',
|
||||
itemComponent: 'UserInitiationsBlock',
|
||||
dataSource: 'main',
|
||||
collectionName: 'approvals',
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -60,5 +68,6 @@ export const ApprovalInitializerItem = [
|
||||
title: '审批',
|
||||
name: 'todos',
|
||||
itemComponent: 'TodosBlock',
|
||||
collectionName: 'approvalRecords',
|
||||
},
|
||||
];
|
||||
|
@ -1,9 +1,54 @@
|
||||
import { SchemaSettings } from '@tachybase/client';
|
||||
import {
|
||||
SchemaSettings,
|
||||
SchemaSettingsDataScope,
|
||||
removeNullCondition,
|
||||
useCollection,
|
||||
useCollectionManager,
|
||||
useDataLoadingMode,
|
||||
useDesignable,
|
||||
useDetailsBlockContext,
|
||||
useFormBlockContext,
|
||||
} from '@tachybase/client';
|
||||
import { useField, useFieldSchema } from '@tachybase/schema';
|
||||
import _ from 'lodash';
|
||||
|
||||
export const ApprovalSettings = new SchemaSettings({
|
||||
name: 'ApprovalSettings',
|
||||
items: [
|
||||
{
|
||||
name: 'setTheDataScope',
|
||||
Component: SchemaSettingsDataScope,
|
||||
useComponentProps() {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const collectionName = fieldSchema['x-component-props']['collectionName'];
|
||||
const field = useField();
|
||||
const { form } = useFormBlockContext();
|
||||
const { dn } = useDesignable();
|
||||
|
||||
return {
|
||||
collectionName,
|
||||
defaultFilter: fieldSchema?.['x-component-props']?.params?.filter || {},
|
||||
form: form,
|
||||
onSubmit: ({ filter }) => {
|
||||
_.set(field.componentProps, 'params', {
|
||||
...field.componentProps?.params,
|
||||
filter,
|
||||
});
|
||||
fieldSchema['x-component-props']['params'] = field.componentProps.params;
|
||||
dn.emit('patch', {
|
||||
schema: {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
'x-component-props': fieldSchema['x-component-props'],
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
// useVisible() {
|
||||
// const fieldSchema = useFieldSchema();
|
||||
// return !isTabSearchCollapsibleInputItem(fieldSchema['x-component']);
|
||||
// },
|
||||
},
|
||||
{
|
||||
name: 'divider',
|
||||
type: 'divider',
|
||||
|
@ -0,0 +1,94 @@
|
||||
import { approvalStatusOptions } from '../constants';
|
||||
import { NAMESPACE } from '../locale';
|
||||
|
||||
export const CollectionApprovalTodos = {
|
||||
title: `{{t("Approval todos", { ns: "${NAMESPACE}" })}}`,
|
||||
name: 'approvalRecords',
|
||||
fields: [
|
||||
{
|
||||
type: 'bigInt',
|
||||
name: 'approvalId',
|
||||
interface: 'number',
|
||||
uiSchema: { type: 'number', title: 'ID', 'x-component': 'InputNumber' },
|
||||
},
|
||||
{
|
||||
type: 'belongsTo',
|
||||
name: 'user',
|
||||
target: 'users',
|
||||
foreignKey: 'userId',
|
||||
interface: 'm2o',
|
||||
uiSchema: {
|
||||
type: 'number',
|
||||
title: `{{t("Assignee", { ns: "${NAMESPACE}" })}}`,
|
||||
'x-component': 'RemoteSelect',
|
||||
'x-component-props': { fieldNames: { label: 'nickname', value: 'id' }, service: { resource: 'users' } },
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'belongsTo',
|
||||
name: 'node',
|
||||
target: 'flow_nodes',
|
||||
foreignKey: 'nodeId',
|
||||
interface: 'm2o',
|
||||
isAssociation: true,
|
||||
uiSchema: {
|
||||
type: 'number',
|
||||
title: `{{t("Task node", { ns: "${NAMESPACE}" })}}`,
|
||||
'x-component': 'RemoteSelect',
|
||||
'x-component-props': { fieldNames: { label: 'title', value: 'id' }, service: { resource: 'flow_nodes' } },
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'belongsTo',
|
||||
name: 'workflow',
|
||||
target: 'workflows',
|
||||
foreignKey: 'workflowId',
|
||||
interface: 'm2o',
|
||||
uiSchema: {
|
||||
type: 'number',
|
||||
title: '{{t("Workflow", { ns: "workflow" })}}',
|
||||
'x-component': 'RemoteSelect',
|
||||
'x-component-props': { fieldNames: { label: 'title', value: 'id' }, service: { resource: 'workflows' } },
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'integer',
|
||||
name: 'status',
|
||||
interface: 'select',
|
||||
uiSchema: {
|
||||
type: 'number',
|
||||
title: '{{t("Status", { ns: "workflow" })}}',
|
||||
'x-component': 'Select',
|
||||
enum: approvalStatusOptions,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'comment',
|
||||
interface: 'markdown',
|
||||
uiSchema: { type: 'string', 'x-component': 'Markdown', title: `{{t("Comment", { ns: "${NAMESPACE}" })}}` },
|
||||
},
|
||||
{
|
||||
name: 'createdAt',
|
||||
type: 'date',
|
||||
interface: 'createdAt',
|
||||
uiSchema: {
|
||||
type: 'datetime',
|
||||
title: '{{t("Created at")}}',
|
||||
'x-component': 'DatePicker',
|
||||
'x-component-props': { showTime: true },
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'updatedAt',
|
||||
type: 'date',
|
||||
interface: 'updatedAt',
|
||||
uiSchema: {
|
||||
type: 'datetime',
|
||||
title: '{{t("Updated at")}}',
|
||||
'x-component': 'DatePicker',
|
||||
'x-component-props': { showTime: true },
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
@ -0,0 +1,63 @@
|
||||
import { ApprovalStatusEnums } from '../constants';
|
||||
import { NAMESPACE } from '../locale';
|
||||
|
||||
export const CollectionApprovals = {
|
||||
title: `{{t("Approval applications", { ns: "${NAMESPACE}" })}}`,
|
||||
name: 'approvals',
|
||||
fields: [
|
||||
{
|
||||
type: 'bigInt',
|
||||
name: 'id',
|
||||
interface: 'number',
|
||||
uiSchema: { type: 'number', title: 'ID', 'x-component': 'InputNumber' },
|
||||
},
|
||||
{
|
||||
type: 'belongsTo',
|
||||
name: 'workflow',
|
||||
target: 'workflows',
|
||||
foreignKey: 'workflowId',
|
||||
interface: 'm2o',
|
||||
uiSchema: {
|
||||
type: 'number',
|
||||
title: '{{t("Workflow", { ns: "workflow" })}}',
|
||||
'x-component': 'RemoteSelect',
|
||||
'x-component-props': { fieldNames: { label: 'title', value: 'id' }, service: { resource: 'workflows' } },
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'belongsTo',
|
||||
name: 'createdBy',
|
||||
target: 'users',
|
||||
foreignKey: 'createdById',
|
||||
interface: 'm2o',
|
||||
uiSchema: {
|
||||
type: 'number',
|
||||
title: `{{t("Initiator", { ns: "${NAMESPACE}" })}}`,
|
||||
'x-component': 'RemoteSelect',
|
||||
'x-component-props': { fieldNames: { label: 'nickname', value: 'id' }, service: { resource: 'users' } },
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'integer',
|
||||
name: 'status',
|
||||
interface: 'select',
|
||||
uiSchema: {
|
||||
type: 'number',
|
||||
title: '{{t("Status", { ns: "workflow" })}}',
|
||||
'x-component': 'Select',
|
||||
enum: ApprovalStatusEnums,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'createdAt',
|
||||
type: 'date',
|
||||
interface: 'createdAt',
|
||||
uiSchema: {
|
||||
type: 'datetime',
|
||||
title: '{{t("Created at")}}',
|
||||
'x-component': 'DatePicker',
|
||||
'x-component-props': { showTime: true },
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
@ -0,0 +1,28 @@
|
||||
import { NAMESPACE } from '../locale';
|
||||
|
||||
export const CollectionFlowNodes = {
|
||||
title: `{{t("Node", { ns: "${NAMESPACE}" })}}`,
|
||||
name: 'flow_nodes',
|
||||
fields: [
|
||||
{
|
||||
type: 'bigInt',
|
||||
name: 'id',
|
||||
interface: 'm2o',
|
||||
uiSchema: {
|
||||
type: 'number',
|
||||
title: 'ID',
|
||||
'x-component': 'RemoteSelect',
|
||||
'x-component-props': {
|
||||
fieldNames: { label: 'title', value: 'id' },
|
||||
service: { resource: 'flow_nodes', params: { filter: { type: 'manual' } } },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'title',
|
||||
interface: 'input',
|
||||
uiSchema: { type: 'string', title: '{{t("Title")}}', 'x-component': 'Input' },
|
||||
},
|
||||
],
|
||||
};
|
@ -0,0 +1,28 @@
|
||||
import { NAMESPACE } from '../locale';
|
||||
|
||||
export const CollectionWorkflows = {
|
||||
title: `{{t("Workflow", { ns: "${NAMESPACE}" })}}`,
|
||||
name: 'workflows',
|
||||
fields: [
|
||||
{
|
||||
type: 'string',
|
||||
name: 'title',
|
||||
interface: 'input',
|
||||
uiSchema: { title: '{{t("Name")}}', type: 'string', 'x-component': 'Input', required: true },
|
||||
},
|
||||
{
|
||||
type: 'boolean',
|
||||
name: 'enabled',
|
||||
interface: 'select',
|
||||
uiSchema: {
|
||||
type: 'boolean',
|
||||
title: '{{t("Status", { ns: "workflow" })}}',
|
||||
'x-component': 'Select',
|
||||
enum: [
|
||||
{ label: '{{t("On", { ns: "workflow" })}}', value: true },
|
||||
{ label: '{{t("Off", { ns: "workflow" })}}', value: false },
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
@ -2,21 +2,21 @@ import { createStyles, useCurrentUserContext } from '@tachybase/client';
|
||||
import { EXECUTION_STATUS } from '@tachybase/plugin-workflow/client';
|
||||
import _ from 'lodash';
|
||||
import React, { useMemo } from 'react';
|
||||
import { APPROVAL_ACTION_STATUS, APPROVAL_STATUS } from '../constants';
|
||||
import { lang, usePluginTranslation } from '../locale';
|
||||
import { APPROVAL_ACTION_STATUS, APPROVAL_STATUS, ApprovalStatusEnums, approvalStatusOptions } from '../constants';
|
||||
import { lang, usePluginTranslation, useTranslation } from '../locale';
|
||||
import { useContextApprovalExecution } from '../context/ApprovalExecution';
|
||||
import { ContextWithActionEnabled } from '../context/WithActionEnabled';
|
||||
import { Space, Steps, Tag } from 'antd-mobile';
|
||||
import { dayjs } from '@tachybase/utils/client';
|
||||
|
||||
// 审批(发起/待办)区块-查看-审批处理
|
||||
export const ApprovalProcess = (props) => {
|
||||
const { t } = usePluginTranslation();
|
||||
const { approval: approvalContext } = useContextApprovalExecution();
|
||||
const { styles } = getStyles();
|
||||
const { data } = useCurrentUserContext();
|
||||
|
||||
const { Step } = Steps;
|
||||
const results = useMemo(() => getResults({ approval: approvalContext, currentUser: data }), [approvalContext, data]);
|
||||
|
||||
// const columns = useMemo(() => getAntdTableColumns({ t, styles }), [t, styles]);
|
||||
const stepsResult = getStepsResult(results, t);
|
||||
|
||||
return (
|
||||
<ContextWithActionEnabled.Provider value={{ actionEnabled: props.actionEnabled }}>
|
||||
@ -25,6 +25,32 @@ export const ApprovalProcess = (props) => {
|
||||
<Table key={item.id} dataSource={item.records} rowKey={'id'} pagination={false} columns={columns} />
|
||||
))}
|
||||
</Space> */}
|
||||
<Steps direction="vertical">
|
||||
{stepsResult.map((item, index) => {
|
||||
return (
|
||||
<Step
|
||||
title={item.title}
|
||||
key={index}
|
||||
description={
|
||||
<Space direction="vertical">
|
||||
{item.description.map((deItem, indexs) => {
|
||||
return (
|
||||
<Space key={indexs}>
|
||||
{deItem.userName}
|
||||
<Tag color={deItem.status.color} fill="outline">
|
||||
{t(deItem.status.label)}
|
||||
</Tag>
|
||||
{deItem.date}
|
||||
</Space>
|
||||
);
|
||||
})}
|
||||
</Space>
|
||||
}
|
||||
status="finish"
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Steps>
|
||||
</ContextWithActionEnabled.Provider>
|
||||
);
|
||||
};
|
||||
@ -112,6 +138,60 @@ function getResults({ approval, currentUser }) {
|
||||
);
|
||||
}
|
||||
|
||||
const getStepsResult = (result) => {
|
||||
const stepData = result.map((value) => {});
|
||||
const getStepsResult = (result, t) => {
|
||||
const stepData = [];
|
||||
result.forEach((item) => {
|
||||
const stepItem = {};
|
||||
item.records.forEach((value, index) => {
|
||||
const status = {};
|
||||
if (
|
||||
(!(value.workflow != null && value.workflow.enabled) ||
|
||||
(value.execution != null && value.execution.stauts) ||
|
||||
value.job?.status) &&
|
||||
[APPROVAL_STATUS.ASSIGNED, APPROVAL_STATUS.PENDING].includes(value.status)
|
||||
) {
|
||||
status['label'] = 'Unprocessed';
|
||||
status['color'] = 'default';
|
||||
} else {
|
||||
const approvalStatus = approvalStatusOptions.find((option) => option.value === value.status);
|
||||
const approvalActionStatus = ApprovalStatusEnums.find((option) => option.value === value.status);
|
||||
if (value.nodeId) {
|
||||
status['label'] = approvalStatus?.label || approvalActionStatus?.label;
|
||||
status['color'] = approvalStatus?.color || approvalActionStatus?.color || 'default';
|
||||
} else {
|
||||
status['label'] = approvalActionStatus?.label || approvalStatus?.label;
|
||||
status['color'] = approvalActionStatus?.color || approvalStatus?.color || 'default';
|
||||
}
|
||||
}
|
||||
if (Object.keys(stepItem).includes(value.nodeId ? value.nodeId.toString() : '')) {
|
||||
stepItem[value.nodeId].description.push({
|
||||
userName: value.user.nickname,
|
||||
status,
|
||||
date: value.status === 0 ? '' : dayjs(value.execution.updatedAt).format('YYYY-MM-DD hh:mm:ss'),
|
||||
});
|
||||
} else {
|
||||
stepItem[value.nodeId || value.node?.title || t(status['label'])] = {
|
||||
title: value.node?.title || t(status['label']),
|
||||
index,
|
||||
description: [
|
||||
{
|
||||
userName: value.user.nickname,
|
||||
status,
|
||||
date:
|
||||
value.status === 0
|
||||
? ''
|
||||
: dayjs(
|
||||
value.nodeId ? value.execution?.updatedAt : value.execution?.createdAt || value.updatedAt,
|
||||
).format('YYYY-MM-DD hh:mm:ss'),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
});
|
||||
const sort = Object.values(stepItem).sort((a, b) => {
|
||||
return a['index'] - b['index'];
|
||||
});
|
||||
stepData.push(...sort);
|
||||
});
|
||||
return stepData.filter(Boolean);
|
||||
};
|
||||
|
@ -0,0 +1,97 @@
|
||||
import { observer } from '@tachybase/schema';
|
||||
import { dayjs } from '@tachybase/utils/client';
|
||||
import { AutoCenter, Button, DatePicker, Grid, Popup, Space, Toast } from 'antd-mobile';
|
||||
import { DownOutline } from 'antd-mobile-icons';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
export const ApprovalReachDataType = observer((props) => {
|
||||
const { changeFilter, filter } = props as any;
|
||||
const [pickerVisible, setPickerVisible] = useState(false);
|
||||
const [popupVisible, setPopupVisible] = useState(false);
|
||||
const now = new Date();
|
||||
const [currPicker, setCurrPicker] = useState('start');
|
||||
const [startData, setStartData] = useState<any>(dayjs(now).startOf('date').toISOString());
|
||||
const [endData, setEndData] = useState<any>(now);
|
||||
return (
|
||||
<>
|
||||
<Space
|
||||
onClick={() => {
|
||||
setPopupVisible(true);
|
||||
}}
|
||||
>
|
||||
{filter['createdAt'] ? `${formatDate(startData)}-${formatDate(endData)} ` : '到达日期'}
|
||||
<DownOutline />
|
||||
</Space>
|
||||
<Popup
|
||||
visible={popupVisible}
|
||||
bodyStyle={{
|
||||
borderTopLeftRadius: '8px',
|
||||
borderTopRightRadius: '8px',
|
||||
minHeight: '15vh',
|
||||
}}
|
||||
onMaskClick={() => {
|
||||
setPopupVisible(false);
|
||||
}}
|
||||
>
|
||||
<Grid columns={9} style={{ height: '10vh' }}>
|
||||
<Grid.Item
|
||||
span={4}
|
||||
onClick={() => {
|
||||
setPickerVisible(true), setCurrPicker('start');
|
||||
}}
|
||||
>
|
||||
<AutoCenter style={{ lineHeight: '10vh' }}>{formatDate(startData) || ''}</AutoCenter>
|
||||
</Grid.Item>
|
||||
<Grid.Item style={{ lineHeight: '10vh' }}>——</Grid.Item>
|
||||
<Grid.Item
|
||||
style={{ lineHeight: '10vh' }}
|
||||
span={4}
|
||||
onClick={() => {
|
||||
setPickerVisible(true), setCurrPicker('end');
|
||||
}}
|
||||
>
|
||||
<AutoCenter>{formatDate(endData) || ''}</AutoCenter>
|
||||
</Grid.Item>
|
||||
</Grid>
|
||||
<Button
|
||||
block
|
||||
color="primary"
|
||||
style={{ width: '99%' }}
|
||||
onClick={() => {
|
||||
if (!startData || !endData) {
|
||||
Toast.show({
|
||||
content: '请将时间范围填写完整',
|
||||
});
|
||||
} else {
|
||||
const changeData = { ...filter };
|
||||
changeData['createdAt'] = { $dateBetween: [startData, endData] };
|
||||
changeFilter(changeData);
|
||||
setPopupVisible(false);
|
||||
}
|
||||
}}
|
||||
>
|
||||
确定
|
||||
</Button>
|
||||
|
||||
<DatePicker
|
||||
visible={pickerVisible}
|
||||
onClose={() => {
|
||||
setPickerVisible(false);
|
||||
}}
|
||||
max={now}
|
||||
onConfirm={(e) => {
|
||||
if (currPicker === 'start') {
|
||||
setStartData(e);
|
||||
} else {
|
||||
setEndData(dayjs(e).endOf('date').toISOString());
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Popup>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
const formatDate = (checkDate) => {
|
||||
return dayjs(checkDate).format('YYYY-MM-DD');
|
||||
};
|
@ -0,0 +1,64 @@
|
||||
import { useAPIClient } from '@tachybase/client';
|
||||
import { observer, useFieldSchema } from '@tachybase/schema';
|
||||
import { Picker, Space } from 'antd-mobile';
|
||||
import { DownOutline } from 'antd-mobile-icons';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useTranslation } from '../locale';
|
||||
|
||||
export const ApprovalTemplateType = observer((props) => {
|
||||
const { changeFilter, filter } = props as any;
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [columns, setColumns] = useState([]);
|
||||
const api = useAPIClient();
|
||||
const { t } = useTranslation();
|
||||
useEffect(() => {
|
||||
api
|
||||
.request({
|
||||
url: 'workflows:list',
|
||||
params: { pageSize: 9999, filter: { type: { $eq: 'approval' }, enabled: { $eq: true } } },
|
||||
})
|
||||
.then((res) => {
|
||||
const columnsData = res.data.data.map((value) => {
|
||||
return { label: value.title?.replace('审批流:', '') || '', value: value.id };
|
||||
});
|
||||
columnsData.unshift({
|
||||
value: 'all',
|
||||
label: t('All'),
|
||||
});
|
||||
setColumns(columnsData);
|
||||
})
|
||||
.catch(() => {
|
||||
console.error;
|
||||
});
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<Space
|
||||
onClick={() => {
|
||||
setVisible(true);
|
||||
}}
|
||||
>
|
||||
{columns.length && filter.workflowId && filter.workflowId !== 'all'
|
||||
? columns.find((item) => item.value === filter.workflowId).label
|
||||
: '模版类型'}
|
||||
<DownOutline />
|
||||
</Space>
|
||||
<Picker
|
||||
columns={[columns]}
|
||||
visible={visible}
|
||||
onClose={() => {
|
||||
setVisible(false);
|
||||
}}
|
||||
onConfirm={(e) => {
|
||||
const changeData = { ...filter };
|
||||
if (e[0] === 'all') {
|
||||
delete changeData['workflowId'];
|
||||
} else {
|
||||
changeData['workflowId'] = e[0];
|
||||
}
|
||||
changeFilter(changeData);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
});
|
@ -18,6 +18,11 @@ export const APPROVAL_STATUS = {
|
||||
/**撤回 */
|
||||
WITHDRAWN: -3,
|
||||
};
|
||||
|
||||
export const ProcessedStatus = [1, 2, -1, -3];
|
||||
|
||||
export const PendingStatus = [0];
|
||||
|
||||
export const approvalStatusOptions = [
|
||||
{ value: APPROVAL_STATUS.ASSIGNED, label: `Assigned`, color: 'blue' },
|
||||
{ value: APPROVAL_STATUS.PENDING, label: `Pending`, color: 'gold' },
|
||||
|
@ -16,8 +16,7 @@ import { Fragment, useContext, useMemo, useRef } from 'react';
|
||||
import { useContextApprovalExecution } from './ApprovalExecution';
|
||||
|
||||
export const FormBlockProvider = (props) => {
|
||||
const { approvalExecution } = useContextApprovalExecution();
|
||||
const { snapshot } = approvalExecution;
|
||||
const { snapshot } = useContextApprovalExecution();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const field = useField();
|
||||
const formBlockRef = useRef(null);
|
||||
|
@ -8,6 +8,7 @@ import { ViewActionTodosContent } from './todos/component/ViewActionTodosContent
|
||||
import { UserInitiationsBlock } from './initiations/UserInitiationsBlock';
|
||||
import { ViewActionUserInitiationsContent } from './initiations/component/ViewActionUserInitiationsContent';
|
||||
import { ApprovalProcess } from './component/ApprovalProcess.view';
|
||||
import { ViewActionInitiationsContent } from './initiations/component/ViewActionInitiationsContent';
|
||||
|
||||
class PluginApproval extends Plugin {
|
||||
async load() {
|
||||
@ -18,6 +19,7 @@ class PluginApproval extends Plugin {
|
||||
UserInitiationsBlock,
|
||||
ViewActionTodosContent,
|
||||
ViewActionUserInitiationsContent,
|
||||
ViewActionInitiationsContent,
|
||||
'ApprovalCommon.ViewComponent.MApprovalProcess': ApprovalProcess,
|
||||
});
|
||||
this.app.schemaSettingsManager.add(ApprovalSettings);
|
||||
|
@ -1,10 +1,17 @@
|
||||
import { BlockItem, css, useAPIClient, useRequest } from '@tachybase/client';
|
||||
import { BlockItem, ExtendCollectionsProvider, css, useAPIClient, useRequest } from '@tachybase/client';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { AutoCenter, Card, SearchBar, Selector, Space } from 'antd-mobile';
|
||||
import { TeamFill } from 'antd-mobile-icons';
|
||||
import { CollectionWorkflows } from '../collection/Workflows.collection';
|
||||
import { CollectionFlowNodes } from '../collection/FlowNodes.collection';
|
||||
import { CollectionApprovals } from '../collection/Approvals.collection';
|
||||
import { CollectionApprovalTodos } from '../collection/ApprovalTodos';
|
||||
import { observer } from '@tachybase/schema';
|
||||
|
||||
export const InitiationsBlock = () => {
|
||||
export const InitiationsBlock = observer((props) => {
|
||||
const { params } = props as any;
|
||||
const [filter, setFilter] = useState({});
|
||||
const [options, setOptions] = useState([]);
|
||||
const api = useAPIClient();
|
||||
const navigate = useNavigate();
|
||||
@ -12,7 +19,7 @@ export const InitiationsBlock = () => {
|
||||
api
|
||||
.request({
|
||||
url: 'workflows:list',
|
||||
params: { pageSize: 9999, filter: { type: { $eq: 'approval' }, enabled: { $eq: true } } },
|
||||
params: { pageSize: 9999, filter: { ...params?.filter, ...filter } },
|
||||
})
|
||||
.then((res) => {
|
||||
const option = res?.data?.data.map((value) => {
|
||||
@ -23,7 +30,7 @@ export const InitiationsBlock = () => {
|
||||
<div
|
||||
style={{ display: 'flex', flexDirection: 'column', alignContent: 'center' }}
|
||||
onClick={(c) => {
|
||||
navigate(`/mobile/${value.config.collection}/approval/${value.id}/page`);
|
||||
navigate(`/mobile/${value.title?.replace('审批流:', '') || ''}/approval/${value.id}/page`);
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
@ -37,29 +44,45 @@ export const InitiationsBlock = () => {
|
||||
setOptions(option);
|
||||
})
|
||||
.catch(() => {});
|
||||
}, []);
|
||||
}, [params, filter]);
|
||||
return (
|
||||
<BlockItem>
|
||||
<div style={{ padding: '10px', height: '90vh' }}>
|
||||
<SearchBar placeholder="请输入内容" clearable style={{ '--background': '#ffffff' }} />
|
||||
<Card
|
||||
className={css`
|
||||
overflow: hidden;
|
||||
margin-top: 20px;
|
||||
.adm-card-body {
|
||||
padding: 0;
|
||||
}
|
||||
`}
|
||||
style={{ padding: '0', backgroundColor: '#f3f3f3' }}
|
||||
>
|
||||
<Selector
|
||||
style={{ '--color': '#ffffff', '--gap': '1px' }}
|
||||
columns={3}
|
||||
showCheckMark={false}
|
||||
options={options}
|
||||
<ExtendCollectionsProvider
|
||||
collections={[CollectionWorkflows, CollectionFlowNodes, CollectionApprovals, CollectionApprovalTodos]}
|
||||
>
|
||||
<BlockItem>
|
||||
<div style={{ padding: '10px', minHeight: '90vh' }}>
|
||||
<SearchBar
|
||||
placeholder="请输入内容"
|
||||
clearable
|
||||
style={{ '--background': '#ffffff' }}
|
||||
onChange={(value) => {
|
||||
if (!value) setFilter({});
|
||||
}}
|
||||
onSearch={(value) => {
|
||||
setFilter({
|
||||
title: { $includes: value },
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
</BlockItem>
|
||||
<Card
|
||||
className={css`
|
||||
overflow: hidden;
|
||||
margin-top: 20px;
|
||||
.adm-card-body {
|
||||
padding: 0;
|
||||
}
|
||||
`}
|
||||
style={{ padding: '0', backgroundColor: '#f3f3f3' }}
|
||||
>
|
||||
<Selector
|
||||
style={{ '--color': '#ffffff', '--gap': '1px' }}
|
||||
columns={3}
|
||||
showCheckMark={false}
|
||||
options={options}
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
</BlockItem>
|
||||
</ExtendCollectionsProvider>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
@ -1,35 +1,48 @@
|
||||
import { BlockItem, SchemaComponent, css } from '@tachybase/client';
|
||||
import { BlockItem, ExtendCollectionsProvider, SchemaComponent, css } from '@tachybase/client';
|
||||
import { Divider, SearchBar, Space, Tabs } from 'antd-mobile';
|
||||
import React, { useState } from 'react';
|
||||
import { useFieldSchema } from '@tachybase/schema';
|
||||
import { ApprovalTemplateType } from './component/ApprovalTemplateType';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { observer, useFieldSchema } from '@tachybase/schema';
|
||||
import { ApprovalTemplateType } from '../component/ApprovalTemplateType';
|
||||
import { ApprovalStatus } from './component/ApprovalStatus';
|
||||
import { ApprovalItem } from './component/ApprovalItem';
|
||||
import { ApprovalReachDataType } from './component/ApprovalReachDataType';
|
||||
import { ApprovalReachDataType } from '../component/ApprovalReachDataType';
|
||||
import '../style/style.css';
|
||||
import { CollectionWorkflows } from '../collection/Workflows.collection';
|
||||
import { CollectionFlowNodes } from '../collection/FlowNodes.collection';
|
||||
import { CollectionApprovals } from '../collection/Approvals.collection';
|
||||
import { CollectionApprovalTodos } from '../collection/ApprovalTodos';
|
||||
|
||||
export const UserInitiationsBlock = () => {
|
||||
export const UserInitiationsBlock = observer((props) => {
|
||||
const [filter, setFilter] = useState({});
|
||||
const fieldSchema = useFieldSchema();
|
||||
fieldSchema['x-component-props'] = fieldSchema['x-component-props']?.['approvalKey']
|
||||
? fieldSchema['x-component-props']
|
||||
: (() => {
|
||||
fieldSchema['x-component-props']['approvalKey'] = 'pending';
|
||||
return fieldSchema['x-component-props'];
|
||||
})();
|
||||
const props = fieldSchema['x-component-props'];
|
||||
const changeFilter = (data) => {
|
||||
setFilter(data);
|
||||
};
|
||||
const filterProps = {
|
||||
...props,
|
||||
changeFilter,
|
||||
filter,
|
||||
};
|
||||
return (
|
||||
<BlockItem>
|
||||
<SearchBar placeholder="搜索人名,标题、内容" clearable style={{ '--background': '#ffffff', padding: '10px' }} />
|
||||
<Space justify="evenly" style={spaceStyle}>
|
||||
{/* 模版类型 */}
|
||||
<ApprovalTemplateType />
|
||||
{/* 到达日期 */}
|
||||
<ApprovalReachDataType />
|
||||
{/* 审批状态 */}
|
||||
<ApprovalStatus />
|
||||
</Space>
|
||||
<ApprovalItem />
|
||||
</BlockItem>
|
||||
<ExtendCollectionsProvider
|
||||
collections={[CollectionWorkflows, CollectionFlowNodes, CollectionApprovals, CollectionApprovalTodos]}
|
||||
>
|
||||
<BlockItem>
|
||||
<SearchBar
|
||||
placeholder="搜索人名,标题、内容"
|
||||
clearable
|
||||
style={{ '--background': '#ffffff', padding: '10px' }}
|
||||
/>
|
||||
<Space justify="evenly" className="userInitiationsStyle">
|
||||
{/* 模版类型 */}
|
||||
<ApprovalTemplateType {...filterProps} />
|
||||
{/* 到达日期 */}
|
||||
<ApprovalReachDataType {...filterProps} />
|
||||
{/* 审批状态 */}
|
||||
<ApprovalStatus {...filterProps} />
|
||||
</Space>
|
||||
<ApprovalItem {...filterProps} />
|
||||
</BlockItem>
|
||||
</ExtendCollectionsProvider>
|
||||
);
|
||||
};
|
||||
|
||||
const spaceStyle = { width: '100%', fontSize: '10px', color: '#8e8e8e' };
|
||||
});
|
||||
|
@ -1,56 +1,25 @@
|
||||
import { useAPIClient, useCollectionManager, useCurrentUserContext } from '@tachybase/client';
|
||||
import { useFieldSchema } from '@tachybase/schema';
|
||||
import { useAPIClient, useCurrentUserContext } from '@tachybase/client';
|
||||
import { Badge, Empty, List, Space, Tag } from 'antd-mobile';
|
||||
import React, { useState } from 'react';
|
||||
import { useAsyncEffect } from 'ahooks';
|
||||
import { useDeepCompareEffect } from 'ahooks';
|
||||
import { ApprovalPriorityType, ApprovalStatusEnums } from '../../constants';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useTranslation } from '../../locale';
|
||||
import { observer } from '@tachybase/schema';
|
||||
|
||||
export const ApprovalItem = () => {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const props = fieldSchema['x-component-props'];
|
||||
const cm = useCollectionManager();
|
||||
export const ApprovalItem = observer((props) => {
|
||||
const { filter, params } = props as any;
|
||||
const api = useAPIClient();
|
||||
const [data, setData] = useState([]);
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const user = useCurrentUserContext();
|
||||
useAsyncEffect(async () => {
|
||||
api
|
||||
.request({
|
||||
url: 'approvals:listCentralized',
|
||||
params: { pageSize: 99999, appends: ['workflow'] },
|
||||
})
|
||||
.then((res) => {
|
||||
const result = res.data?.data.map((item) => {
|
||||
const priorityType = ApprovalPriorityType.find((priorityItem) => priorityItem.value === item.data.priority);
|
||||
const statusType = approvalTodoListStatus(item, t);
|
||||
const categoryTitle = item.workflow.title.replace('审批流:', '');
|
||||
|
||||
return {
|
||||
...item,
|
||||
title: `${user.data.data.nickname}的${categoryTitle}`,
|
||||
categoryTitle: categoryTitle,
|
||||
statusTitle: t(statusType.label),
|
||||
statusColor: statusType.color,
|
||||
reason: item.data.reason || item.data.reason_pay,
|
||||
priorityTitle: priorityType.label,
|
||||
priorityColor: priorityType.color,
|
||||
};
|
||||
});
|
||||
result.sort((a, b) => {
|
||||
return Date.parse(b.createdAt) - Date.parse(a.createdAt);
|
||||
});
|
||||
setData(result);
|
||||
})
|
||||
.catch(() => {
|
||||
console.error;
|
||||
});
|
||||
}, props);
|
||||
useDeepCompareEffect(() => {
|
||||
changService(api, setData, user, { ...params?.filter, ...filter }, t);
|
||||
}, [filter, params]);
|
||||
|
||||
return (
|
||||
<div style={{ marginTop: '10px', minHeight: '70vh' }}>
|
||||
<div style={{ minHeight: '73vh' }}>
|
||||
{data.length ? (
|
||||
<List style={{ '--font-size': '12px' }}>
|
||||
{data.map((item, index) => {
|
||||
@ -82,9 +51,42 @@ export const ApprovalItem = () => {
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
const approvalTodoListStatus = (item, t) => {
|
||||
const { status } = item;
|
||||
return ApprovalStatusEnums.find((value) => value.value === status);
|
||||
};
|
||||
|
||||
const changService = (api, setData, user, filter, t) => {
|
||||
console.log('🚀 ~ changService ~ filter:', filter);
|
||||
api
|
||||
.request({
|
||||
url: 'approvals:listCentralized',
|
||||
params: { pageSize: 99999, appends: ['workflow'], filter },
|
||||
})
|
||||
.then((res) => {
|
||||
const result = res.data?.data.map((item) => {
|
||||
const priorityType = ApprovalPriorityType.find((priorityItem) => priorityItem.value === item.data.priority);
|
||||
const statusType = approvalTodoListStatus(item, t);
|
||||
const categoryTitle = item.workflow.title.replace('审批流:', '');
|
||||
return {
|
||||
...item,
|
||||
title: `${user.data.data.nickname}的${categoryTitle}`,
|
||||
categoryTitle: categoryTitle,
|
||||
statusTitle: t(statusType.label),
|
||||
statusColor: statusType.color,
|
||||
reason: item.data.reason || item.data.reason_pay,
|
||||
priorityTitle: priorityType.label,
|
||||
priorityColor: priorityType.color,
|
||||
};
|
||||
});
|
||||
result.sort((a, b) => {
|
||||
return Date.parse(b.createdAt) - Date.parse(a.createdAt);
|
||||
});
|
||||
setData(result);
|
||||
})
|
||||
.catch(() => {
|
||||
console.error;
|
||||
});
|
||||
};
|
||||
|
@ -1,31 +0,0 @@
|
||||
import { Picker, Space } from 'antd-mobile';
|
||||
import { DownOutline } from 'antd-mobile-icons';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
export const ApprovalReachDataType = () => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
return (
|
||||
<>
|
||||
<Space>
|
||||
到达日期
|
||||
<DownOutline />
|
||||
</Space>
|
||||
<Picker
|
||||
columns={columns}
|
||||
visible={visible}
|
||||
onClose={() => {
|
||||
setVisible(false);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const columns = [
|
||||
[
|
||||
{ label: '全部', value: '1' },
|
||||
{ label: '近7日', value: '2' },
|
||||
{ label: '近30日', value: '3' },
|
||||
{ label: '自定义区间', value: '4' },
|
||||
],
|
||||
];
|
@ -2,8 +2,10 @@ import { Picker, Space } from 'antd-mobile';
|
||||
import { DownOutline } from 'antd-mobile-icons';
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from '../../locale';
|
||||
import { observer, useFieldSchema } from '@tachybase/schema';
|
||||
|
||||
export const ApprovalStatus = () => {
|
||||
export const ApprovalStatus = observer((props) => {
|
||||
const { changeFilter, filter } = props as any;
|
||||
const [visible, setVisible] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
@ -13,12 +15,14 @@ export const ApprovalStatus = () => {
|
||||
setVisible(true);
|
||||
}}
|
||||
>
|
||||
申请状态
|
||||
{filter['status'] && filter['status'] !== 'all'
|
||||
? t(columns.find((item) => item.value === filter['status']).label)
|
||||
: '申请状态'}
|
||||
<DownOutline />
|
||||
</Space>
|
||||
<Picker
|
||||
columns={[
|
||||
columns[0].map((value) => {
|
||||
columns.map((value) => {
|
||||
return { ...value, label: t(value.label) };
|
||||
}),
|
||||
]}
|
||||
@ -26,18 +30,26 @@ export const ApprovalStatus = () => {
|
||||
onClose={() => {
|
||||
setVisible(false);
|
||||
}}
|
||||
value={[filter['status'] || 'all']}
|
||||
onConfirm={(e) => {
|
||||
const changeData = { ...filter };
|
||||
if (e[0] === 'all') {
|
||||
delete changeData['status'];
|
||||
} else {
|
||||
changeData['status'] = e[0];
|
||||
}
|
||||
changeFilter(changeData);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
});
|
||||
const columns = [
|
||||
[
|
||||
{ label: 'Draft', value: '0' },
|
||||
{ label: 'Returned', value: '1' },
|
||||
{ label: 'Submitted', value: '2' },
|
||||
{ label: 'Processing', value: '3' },
|
||||
{ label: 'Approved', value: '4' },
|
||||
{ label: 'Rejected', value: '-1' },
|
||||
],
|
||||
{ label: 'All', value: 'all' },
|
||||
{ label: 'Draft', value: '0' },
|
||||
{ label: 'Returned', value: '1' },
|
||||
{ label: 'Submitted', value: '2' },
|
||||
{ label: 'Processing', value: '3' },
|
||||
{ label: 'Approved', value: '4' },
|
||||
{ label: 'Rejected', value: '-1' },
|
||||
];
|
||||
|
@ -1,37 +0,0 @@
|
||||
import { Picker, Space } from 'antd-mobile';
|
||||
import { DownOutline } from 'antd-mobile-icons';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
export const ApprovalTemplateType = () => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
return (
|
||||
<>
|
||||
<Space
|
||||
onClick={() => {
|
||||
setVisible(true);
|
||||
}}
|
||||
>
|
||||
模版类型
|
||||
<DownOutline />
|
||||
</Space>
|
||||
<Picker
|
||||
columns={columns}
|
||||
visible={visible}
|
||||
onClose={() => {
|
||||
setVisible(false);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const columns = [
|
||||
[
|
||||
{ label: '全部', value: '0' },
|
||||
{ label: '入职申请', value: '1' },
|
||||
{ label: '转正申请', value: '2' },
|
||||
{ label: '调用申请', value: '3' },
|
||||
{ label: '离职申请', value: '4' },
|
||||
{ label: 'xxx申请', value: '5' },
|
||||
],
|
||||
];
|
@ -0,0 +1,123 @@
|
||||
import React, { createContext, useEffect, useState } from 'react';
|
||||
import {
|
||||
CollectionProvider_deprecated,
|
||||
RemoteSchemaComponent,
|
||||
SchemaComponent,
|
||||
SchemaComponentContext,
|
||||
parseCollectionName,
|
||||
useAPIClient,
|
||||
} from '@tachybase/client';
|
||||
import { useContext } from 'react';
|
||||
import { NavBar } from 'antd-mobile';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { useTranslation } from '../../locale';
|
||||
import '../../style/style.css';
|
||||
import { APPROVAL_ACTION_STATUS } from '../../constants';
|
||||
import { useCreateSubmit } from '../hook/useCreateSubmit';
|
||||
|
||||
export const ViewActionInitiationsContent = () => {
|
||||
const params = useParams();
|
||||
const navigate = useNavigate();
|
||||
const { name, id } = params;
|
||||
const { t } = useTranslation();
|
||||
const context = useContext(SchemaComponentContext);
|
||||
const api = useAPIClient();
|
||||
const [schema, setSchema] = useState({});
|
||||
useEffect(() => {
|
||||
api
|
||||
.request({
|
||||
url: 'workflows:list',
|
||||
params: {
|
||||
pageSize: 9999,
|
||||
filter: {
|
||||
type: { $eq: 'approval' },
|
||||
enabled: { $eq: true },
|
||||
id: { $eq: id },
|
||||
},
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
const formConfig = res.data.data[0];
|
||||
const [dataSource, name] = parseCollectionName(formConfig.config.collection);
|
||||
const resSchema = {
|
||||
type: 'void',
|
||||
'x-component': 'MPage',
|
||||
'x-designer': 'MPage.Designer',
|
||||
'x-component-props': {},
|
||||
properties: {
|
||||
Approval: {
|
||||
type: 'void',
|
||||
'x-decorator': 'CollectionProvider_deprecated',
|
||||
'x-decorator-props': {
|
||||
name,
|
||||
dataSource,
|
||||
},
|
||||
'x-component': 'RemoteSchemaComponent',
|
||||
'x-component-props': {
|
||||
uid: formConfig.config.applyForm,
|
||||
noForm: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
setSchema(resSchema);
|
||||
})
|
||||
.catch(() => {
|
||||
console.error;
|
||||
});
|
||||
}, []);
|
||||
return (
|
||||
<div style={{ minHeight: '100vh', backgroundColor: '#f3f3f3', overflow: 'auto' }}>
|
||||
<NavBar
|
||||
onBack={() => {
|
||||
navigate(-1);
|
||||
}}
|
||||
className="navBarStyle"
|
||||
>
|
||||
{name}
|
||||
</NavBar>
|
||||
<SchemaComponentContext.Provider value={{ ...context, designable: false }}>
|
||||
<SchemaComponent
|
||||
schema={schema}
|
||||
components={{
|
||||
RemoteSchemaComponent: RemoteSchemaComponent,
|
||||
CollectionProvider_deprecated: CollectionProvider_deprecated,
|
||||
ApplyActionStatusProvider: ContextInitiationsApprovalStatusProvider,
|
||||
ActionBarProvider,
|
||||
WithdrawActionProvider: WithdrawActionProvider,
|
||||
}}
|
||||
scope={{
|
||||
useSubmit: useCreateSubmit,
|
||||
useWithdrawAction,
|
||||
}}
|
||||
/>
|
||||
</SchemaComponentContext.Provider>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export function WithdrawActionProvider() {
|
||||
return null;
|
||||
}
|
||||
|
||||
export function useWithdrawAction() {
|
||||
return { run() {} };
|
||||
}
|
||||
|
||||
export function ActionBarProvider(props) {
|
||||
return props.children;
|
||||
}
|
||||
|
||||
const ContextInitiationsApprovalStatus = createContext(APPROVAL_ACTION_STATUS.SUBMITTED);
|
||||
|
||||
export function useContextApprovalStatus() {
|
||||
return useContext(ContextInitiationsApprovalStatus);
|
||||
}
|
||||
|
||||
export function ContextInitiationsApprovalStatusProvider(props) {
|
||||
return (
|
||||
<ContextInitiationsApprovalStatus.Provider value={props.value}>
|
||||
{props.children}
|
||||
</ContextInitiationsApprovalStatus.Provider>
|
||||
);
|
||||
}
|
@ -10,7 +10,7 @@ import {
|
||||
useRequest,
|
||||
} from '@tachybase/client';
|
||||
import { DetailsBlockProvider, FlowContext } from '@tachybase/plugin-workflow/client';
|
||||
import { useForm } from '@tachybase/schema';
|
||||
import { useFieldSchema, useForm } from '@tachybase/schema';
|
||||
import { Result, Spin } from 'antd';
|
||||
import { useContext } from 'react';
|
||||
import { ContextWithActionEnabled } from '../../context/WithActionEnabled';
|
||||
@ -22,7 +22,7 @@ import { ActionBarProvider } from '../provider/ActionBar';
|
||||
import { ApplyActionStatusProvider } from '../provider/ApplyActionStatus';
|
||||
import { WithdrawActionProvider } from '../provider/WithdrawAction';
|
||||
import { ContextApprovalExecution } from '../../context/ApprovalExecution';
|
||||
import { useSubmit } from '../hook/useSubmit';
|
||||
import { useUpdateSubmit } from '../hook/useUpadteSubmit';
|
||||
import { useFormBlockProps } from '../hook/useFormBlockProps';
|
||||
import { useWithdrawAction } from '../hook/useWithdrawAction';
|
||||
import { FileOutline, UserContactOutline } from 'antd-mobile-icons';
|
||||
@ -136,17 +136,17 @@ const UserInitiationsComponent = (applyDetail, t, currContext) => {
|
||||
};
|
||||
|
||||
const approvalSchema = {
|
||||
// type: 'void',
|
||||
// 'x-component': 'MPage',
|
||||
// 'x-designer': 'MPage.Designer',
|
||||
// 'x-component-props': {},
|
||||
// properties: {
|
||||
// process: {
|
||||
// type: 'void',
|
||||
// 'x-decorator': 'CardItem',
|
||||
// 'x-component': 'ApprovalCommon.ViewComponent.ApprovalProcess',
|
||||
// },
|
||||
// },
|
||||
type: 'void',
|
||||
'x-component': 'MPage',
|
||||
'x-designer': 'MPage.Designer',
|
||||
'x-component-props': {},
|
||||
properties: {
|
||||
process: {
|
||||
type: 'void',
|
||||
'x-decorator': 'CardItem',
|
||||
'x-component': 'ApprovalCommon.ViewComponent.MApprovalProcess',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
@ -163,7 +163,7 @@ const UserInitiationsComponent = (applyDetail, t, currContext) => {
|
||||
}}
|
||||
scope={{
|
||||
useForm,
|
||||
useSubmit: useSubmit,
|
||||
useSubmit: useUpdateSubmit,
|
||||
useFormBlockProps,
|
||||
useDetailsBlockProps: useFormBlockContext,
|
||||
useWithdrawAction,
|
||||
|
@ -0,0 +1,43 @@
|
||||
import { joinCollectionName, useAPIClient, useBlockRequestContext, useCollection_deprecated } from '@tachybase/client';
|
||||
import { useField, useForm } from '@tachybase/schema';
|
||||
import { APPROVAL_ACTION_STATUS } from '../../constants';
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
export function useCreateSubmit() {
|
||||
const from = useForm();
|
||||
const field = useField();
|
||||
const { __parent } = useBlockRequestContext();
|
||||
const collection = useCollection_deprecated();
|
||||
const contextWe = APPROVAL_ACTION_STATUS.SUBMITTED;
|
||||
const apiClient = useAPIClient();
|
||||
const params = useParams();
|
||||
const { id: workflowId } = params;
|
||||
|
||||
return {
|
||||
async run() {
|
||||
try {
|
||||
from.submit();
|
||||
field.data = field.data || {};
|
||||
field.data.loading = true;
|
||||
|
||||
await apiClient.resource('approvals').create({
|
||||
values: {
|
||||
collectionName: joinCollectionName(collection.dataSource, collection.name),
|
||||
data: from.values,
|
||||
status: contextWe,
|
||||
workflowId: workflowId,
|
||||
},
|
||||
});
|
||||
|
||||
from.reset();
|
||||
field.data.loading = false;
|
||||
const service = __parent.service;
|
||||
if (service) {
|
||||
service.refresh();
|
||||
}
|
||||
} catch (h) {
|
||||
field.data && (field.data.loading = false);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
@ -5,7 +5,7 @@ import _ from 'lodash';
|
||||
import { useContextApprovalExecution } from '../../context/ApprovalExecution';
|
||||
import { useContextApprovalStatus } from '../provider/ApplyActionStatus';
|
||||
|
||||
export function useSubmit() {
|
||||
export function useUpdateSubmit() {
|
||||
const from = useForm();
|
||||
const field = useField();
|
||||
const { approval } = useContextApprovalExecution();
|
@ -19,3 +19,17 @@
|
||||
.approvalContext{
|
||||
margin: 6vh 0 6vh 0;
|
||||
}
|
||||
|
||||
.todosSpacStyle{
|
||||
width:100%;
|
||||
font-size: 10px;
|
||||
color: #8e8e8e;
|
||||
}
|
||||
|
||||
.userInitiationsStyle{
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
padding: 10px 0 10px 0;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
|
@ -1,79 +1,100 @@
|
||||
import { BlockItem, SchemaComponent, css } from '@tachybase/client';
|
||||
import { Divider, SearchBar, Space, Tabs } from 'antd-mobile';
|
||||
import React, { useState } from 'react';
|
||||
import { BlockItem, ExtendCollectionsProvider } from '@tachybase/client';
|
||||
import { SearchBar, Space, Tabs } from 'antd-mobile';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { TabApplicantType } from './component/TabApplicantType';
|
||||
import { TabTemplateType } from './component/TabTemplateType';
|
||||
import { TabReachDataType } from './component/TabReachDataType';
|
||||
import { TabBatchProcessingType } from './component/TabBatchProcessingType';
|
||||
import { TabApprovalType } from './component/TabApprovalType';
|
||||
import { TabReadingType } from './component/TabReadingType';
|
||||
import { TabApprovalItem } from './component/TabApprovalItem';
|
||||
import { useFieldSchema } from '@tachybase/schema';
|
||||
import { observer } from '@tachybase/schema';
|
||||
import '../style/style.css';
|
||||
import { ApprovalReachDataType } from '../component/ApprovalReachDataType';
|
||||
import { ApprovalTemplateType } from '../component/ApprovalTemplateType';
|
||||
import { PendingStatus, ProcessedStatus } from '../constants';
|
||||
import { CollectionWorkflows } from '../collection/Workflows.collection';
|
||||
import { CollectionFlowNodes } from '../collection/FlowNodes.collection';
|
||||
import { CollectionApprovals } from '../collection/Approvals.collection';
|
||||
import { CollectionApprovalTodos } from '../collection/ApprovalTodos';
|
||||
|
||||
export const TodosBlock = () => {
|
||||
const fieldSchema = useFieldSchema();
|
||||
fieldSchema['x-component-props'] = fieldSchema['x-component-props']?.['approvalKey']
|
||||
? fieldSchema['x-component-props']
|
||||
: (() => {
|
||||
fieldSchema['x-component-props']['approvalKey'] = 'pending';
|
||||
return fieldSchema['x-component-props'];
|
||||
})();
|
||||
const props = fieldSchema['x-component-props'];
|
||||
export const TodosBlock = observer((props) => {
|
||||
const [tabValue, setTabValue] = useState('pending');
|
||||
const [filter, setFilter] = useState({});
|
||||
const changeFilter = (data) => {
|
||||
setFilter(data);
|
||||
};
|
||||
useEffect(() => {
|
||||
const changeTabs = { ...filter };
|
||||
switch (tabValue) {
|
||||
case 'pending':
|
||||
changeTabs['status'] = PendingStatus;
|
||||
break;
|
||||
case 'processed':
|
||||
changeTabs['status'] = ProcessedStatus;
|
||||
break;
|
||||
case 'duplicate':
|
||||
break;
|
||||
}
|
||||
setFilter(changeTabs);
|
||||
}, [tabValue]);
|
||||
const filterProps = {
|
||||
...props,
|
||||
filter,
|
||||
changeFilter,
|
||||
};
|
||||
return (
|
||||
<BlockItem>
|
||||
<SearchBar placeholder="搜索人名,标题、内容" clearable style={{ '--background': '#ffffff', padding: '10px' }} />
|
||||
<Tabs
|
||||
onChange={(key) => {
|
||||
props['approvalKey'] = key;
|
||||
}}
|
||||
style={{ '--title-font-size': '12px', backgroundColor: '#ffffff', marginTop: '10px' }}
|
||||
>
|
||||
<Tabs.Tab title="待处理" key="pending">
|
||||
<Space justify="evenly" style={spaceStyle}>
|
||||
{/* 模版类型 */}
|
||||
<TabTemplateType />
|
||||
{/* 申请人 */}
|
||||
<TabApplicantType />
|
||||
{/* 到达日期 */}
|
||||
<TabReachDataType />
|
||||
{/* 批量处理 */}
|
||||
<TabBatchProcessingType />
|
||||
</Space>
|
||||
<TabApprovalItem />
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab title="已处理" key="processed">
|
||||
<Space justify="evenly" style={spaceStyle}>
|
||||
{/* 阅读状态 */}
|
||||
<TabReadingType />
|
||||
{/* 审批状态 */}
|
||||
<TabApprovalType />
|
||||
{/* 模版类型 */}
|
||||
<TabTemplateType />
|
||||
{/* 申请人 */}
|
||||
<TabApplicantType />
|
||||
{/* 到达日期 */}
|
||||
<TabReachDataType />
|
||||
</Space>
|
||||
<TabApprovalItem />
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab title="抄送我" key="duplicate">
|
||||
<Space justify="evenly" style={spaceStyle}>
|
||||
{/* 阅读状态 */}
|
||||
<TabReadingType />
|
||||
{/* 审批状态 */}
|
||||
<TabApprovalType />
|
||||
{/* 模版类型 */}
|
||||
<TabTemplateType />
|
||||
{/* 申请人 */}
|
||||
<TabApplicantType />
|
||||
{/* 到达日期 */}
|
||||
<TabReachDataType />
|
||||
</Space>
|
||||
<TabApprovalItem />
|
||||
</Tabs.Tab>
|
||||
</Tabs>
|
||||
</BlockItem>
|
||||
<ExtendCollectionsProvider
|
||||
collections={[CollectionWorkflows, CollectionFlowNodes, CollectionApprovals, CollectionApprovalTodos]}
|
||||
>
|
||||
<BlockItem>
|
||||
<SearchBar
|
||||
placeholder="搜索人名,标题、内容"
|
||||
clearable
|
||||
style={{ '--background': '#ffffff', padding: '10px' }}
|
||||
/>
|
||||
<Tabs
|
||||
onChange={(key) => {
|
||||
setFilter({});
|
||||
setTabValue(key);
|
||||
}}
|
||||
style={{ '--title-font-size': '12px', backgroundColor: '#ffffff', marginTop: '10px' }}
|
||||
>
|
||||
<Tabs.Tab title="待处理" key="pending">
|
||||
<Space justify="evenly" className="todosSpacStyle">
|
||||
{/* 模版类型 */}
|
||||
<ApprovalTemplateType {...filterProps} />
|
||||
{/* 申请人 */}
|
||||
<TabApplicantType {...filterProps} />
|
||||
{/* 到达日期 */}
|
||||
<ApprovalReachDataType {...filterProps} />
|
||||
</Space>
|
||||
<TabApprovalItem {...filterProps} />
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab title="已处理" key="processed">
|
||||
<Space justify="evenly" className="todosSpacStyle">
|
||||
{/* 审批状态 */}
|
||||
<TabApprovalType {...filterProps} />
|
||||
{/* 模版类型 */}
|
||||
<ApprovalTemplateType {...filterProps} />
|
||||
{/* 申请人 */}
|
||||
<TabApplicantType {...filterProps} />
|
||||
{/* 到达日期 */}
|
||||
<ApprovalReachDataType {...filterProps} />
|
||||
</Space>
|
||||
<TabApprovalItem {...filterProps} />
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab title="抄送我" key="duplicate">
|
||||
<Space justify="evenly" className="todosSpacStyle">
|
||||
{/* 审批状态 */}
|
||||
<TabApprovalType {...filterProps} />
|
||||
{/* 模版类型 */}
|
||||
<ApprovalTemplateType {...filterProps} />
|
||||
{/* 申请人 */}
|
||||
<TabApplicantType {...filterProps} />
|
||||
{/* 到达日期 */}
|
||||
<ApprovalReachDataType {...filterProps} />
|
||||
</Space>
|
||||
<TabApprovalItem {...filterProps} />
|
||||
</Tabs.Tab>
|
||||
</Tabs>
|
||||
</BlockItem>
|
||||
</ExtendCollectionsProvider>
|
||||
);
|
||||
};
|
||||
|
||||
const spaceStyle = { width: '100%', fontSize: '10px', color: '#8e8e8e' };
|
||||
});
|
||||
|
@ -1,10 +1,36 @@
|
||||
import { useFieldSchema } from '@tachybase/schema';
|
||||
import { useAPIClient } from '@tachybase/client';
|
||||
import { observer, useFieldSchema } from '@tachybase/schema';
|
||||
import { Picker, Space } from 'antd-mobile';
|
||||
import { DownOutline } from 'antd-mobile-icons';
|
||||
import React, { useState } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useTranslation } from '../../locale';
|
||||
|
||||
export const TabApplicantType = () => {
|
||||
export const TabApplicantType = observer((props) => {
|
||||
const { changeFilter, filter } = props as any;
|
||||
const [visible, setVisible] = useState(false);
|
||||
const api = useAPIClient();
|
||||
const [columns, setColumns] = useState([]);
|
||||
const { t } = useTranslation();
|
||||
useEffect(() => {
|
||||
api
|
||||
.request({ url: 'users:list', params: { pageSize: 99999 } })
|
||||
.then((res) => {
|
||||
const userData = res.data.data.map((item) => {
|
||||
return {
|
||||
label: item.nickname,
|
||||
value: item.id,
|
||||
};
|
||||
});
|
||||
userData.unshift({
|
||||
label: t('All'),
|
||||
value: 'all',
|
||||
});
|
||||
setColumns(userData);
|
||||
})
|
||||
.catch(() => {
|
||||
console.error;
|
||||
});
|
||||
}, []);
|
||||
return (
|
||||
<Space>
|
||||
<Space
|
||||
@ -12,25 +38,27 @@ export const TabApplicantType = () => {
|
||||
setVisible(true);
|
||||
}}
|
||||
>
|
||||
申请人
|
||||
{columns.length && filter['userId'] && filter['userId'] !== 'all'
|
||||
? columns.find((item) => item.value === filter['userId']).label
|
||||
: '申请人'}
|
||||
<DownOutline />
|
||||
</Space>
|
||||
<Picker
|
||||
columns={columns}
|
||||
columns={[columns]}
|
||||
visible={visible}
|
||||
onClose={() => {
|
||||
setVisible(false);
|
||||
}}
|
||||
onConfirm={(e) => {
|
||||
const changeData = { ...filter };
|
||||
if (e[0] === 'all') {
|
||||
delete changeData['userId'];
|
||||
} else {
|
||||
changeData['userId'] = e[0];
|
||||
}
|
||||
changeFilter(changeData);
|
||||
}}
|
||||
/>
|
||||
</Space>
|
||||
);
|
||||
};
|
||||
|
||||
const columns = [
|
||||
[
|
||||
{ label: '111', value: '1' },
|
||||
{ label: '222', value: '2' },
|
||||
{ label: '333', value: '3' },
|
||||
{ label: '444', value: '4' },
|
||||
],
|
||||
];
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { useAPIClient, useCollectionManager, useRequest } from '@tachybase/client';
|
||||
import { connect, useFieldSchema } from '@tachybase/schema';
|
||||
import { mergeFilter, useAPIClient, useCollectionManager, useRequest } from '@tachybase/client';
|
||||
import { connect, observer, useFieldSchema } from '@tachybase/schema';
|
||||
import { Badge, Empty, List, Space, Tag } from 'antd-mobile';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useAsyncEffect } from 'ahooks';
|
||||
@ -7,10 +7,8 @@ import { APPROVAL_STATUS, ApprovalPriorityType, approvalStatusOptions } from '..
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { tval, useTranslation } from '../../locale';
|
||||
|
||||
export const TabApprovalItem = () => {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const props = fieldSchema['x-component-props'];
|
||||
const cm = useCollectionManager();
|
||||
export const TabApprovalItem = observer((props) => {
|
||||
const { filter, params } = props as any;
|
||||
const api = useAPIClient();
|
||||
const [data, setData] = useState([]);
|
||||
const { t } = useTranslation();
|
||||
@ -20,7 +18,11 @@ export const TabApprovalItem = () => {
|
||||
api
|
||||
.request({
|
||||
url: 'approvalRecords:listCentralized',
|
||||
params: { pageSize: 99999, appends: ['execution', 'job', 'node', 'workflow'] },
|
||||
params: {
|
||||
pageSize: 99999,
|
||||
appends: ['execution', 'job', 'node', 'workflow'],
|
||||
filter: { ...params?.filter, ...filter },
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
const result = res.data?.data.map((item) => {
|
||||
@ -50,7 +52,7 @@ export const TabApprovalItem = () => {
|
||||
.catch(() => {
|
||||
console.error;
|
||||
});
|
||||
}, props);
|
||||
}, [filter, params]);
|
||||
|
||||
return (
|
||||
<div style={{ marginTop: '10px', minHeight: '70vh' }}>
|
||||
@ -85,7 +87,7 @@ export const TabApprovalItem = () => {
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
const approvalTodoListStatus = (item, t) => {
|
||||
const { workflow, execution, job, status } = item;
|
||||
|
@ -1,9 +1,25 @@
|
||||
import { observer } from '@tachybase/schema';
|
||||
import { Picker, Space } from 'antd-mobile';
|
||||
import { DownOutline } from 'antd-mobile-icons';
|
||||
import React, { useState } from 'react';
|
||||
import { ProcessedStatus, approvalStatusOptions } from '../../constants';
|
||||
import { useTranslation } from '../../locale';
|
||||
|
||||
export const TabApprovalType = () => {
|
||||
export const TabApprovalType = observer((props) => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
const { changeFilter, filter } = props as any;
|
||||
const { t } = useTranslation();
|
||||
const columns = approvalStatusOptions
|
||||
.map((item) => {
|
||||
if (ProcessedStatus.includes(item.value)) {
|
||||
return {
|
||||
label: t(item.label),
|
||||
value: item.value,
|
||||
};
|
||||
}
|
||||
})
|
||||
.filter(Boolean);
|
||||
columns.unshift({ label: t('All'), value: 'all' });
|
||||
return (
|
||||
<>
|
||||
<Space
|
||||
@ -11,26 +27,27 @@ export const TabApprovalType = () => {
|
||||
setVisible(true);
|
||||
}}
|
||||
>
|
||||
审批状态
|
||||
{columns.length && typeof filter['status'] === 'number'
|
||||
? columns.find((item) => item.value === filter['status']).label
|
||||
: '审批状态'}
|
||||
<DownOutline />
|
||||
</Space>
|
||||
<Picker
|
||||
columns={columns}
|
||||
columns={[columns]}
|
||||
visible={visible}
|
||||
onClose={() => {
|
||||
setVisible(false);
|
||||
}}
|
||||
onConfirm={(e) => {
|
||||
const changeData = { ...filter };
|
||||
if (e[0] === 'all') {
|
||||
changeData['status'] = ProcessedStatus;
|
||||
} else {
|
||||
changeData['status'] = e[0];
|
||||
}
|
||||
changeFilter(changeData);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const columns = [
|
||||
[
|
||||
{ label: '全部', value: '0' },
|
||||
{ label: '审批中', value: '1' },
|
||||
{ label: '已通过', value: '2' },
|
||||
{ label: '已驳回', value: '3' },
|
||||
{ label: '已撤销', value: '4' },
|
||||
],
|
||||
];
|
||||
});
|
||||
|
@ -1,12 +0,0 @@
|
||||
import { Space } from 'antd-mobile';
|
||||
import { FillinOutline } from 'antd-mobile-icons';
|
||||
import React from 'react';
|
||||
|
||||
export const TabBatchProcessingType = () => {
|
||||
return (
|
||||
<Space>
|
||||
<FillinOutline />
|
||||
批量处理
|
||||
</Space>
|
||||
);
|
||||
};
|
@ -1,31 +0,0 @@
|
||||
import { Picker, Space } from 'antd-mobile';
|
||||
import { DownOutline } from 'antd-mobile-icons';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
export const TabReachDataType = () => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
return (
|
||||
<>
|
||||
<Space>
|
||||
到达日期
|
||||
<DownOutline />
|
||||
</Space>
|
||||
<Picker
|
||||
columns={columns}
|
||||
visible={visible}
|
||||
onClose={() => {
|
||||
setVisible(false);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const columns = [
|
||||
[
|
||||
{ label: '全部', value: '1' },
|
||||
{ label: '近7日', value: '2' },
|
||||
{ label: '近30日', value: '3' },
|
||||
{ label: '自定义区间', value: '4' },
|
||||
],
|
||||
];
|
@ -1,30 +0,0 @@
|
||||
import { Picker, Space } from 'antd-mobile';
|
||||
import { DownOutline } from 'antd-mobile-icons';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
export const TabReadingType = () => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
return (
|
||||
<>
|
||||
<Space>
|
||||
阅读状态
|
||||
<DownOutline />
|
||||
</Space>
|
||||
<Picker
|
||||
columns={columns}
|
||||
visible={visible}
|
||||
onClose={() => {
|
||||
setVisible(false);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const columns = [
|
||||
[
|
||||
{ label: '全部', value: '1' },
|
||||
{ label: '已读', value: '2' },
|
||||
{ label: '未读', value: '3' },
|
||||
],
|
||||
];
|
@ -1,37 +0,0 @@
|
||||
import { Picker, Space } from 'antd-mobile';
|
||||
import { DownOutline } from 'antd-mobile-icons';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
export const TabTemplateType = () => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
return (
|
||||
<>
|
||||
<Space
|
||||
onClick={() => {
|
||||
setVisible(true);
|
||||
}}
|
||||
>
|
||||
模版类型
|
||||
<DownOutline />
|
||||
</Space>
|
||||
<Picker
|
||||
columns={columns}
|
||||
visible={visible}
|
||||
onClose={() => {
|
||||
setVisible(false);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const columns = [
|
||||
[
|
||||
{ label: '全部', value: '0' },
|
||||
{ label: '入职申请', value: '1' },
|
||||
{ label: '转正申请', value: '2' },
|
||||
{ label: '调用申请', value: '3' },
|
||||
{ label: '离职申请', value: '4' },
|
||||
{ label: 'xxx申请', value: '5' },
|
||||
],
|
||||
];
|
@ -10,6 +10,10 @@ export class PluginApprovalMobileClient extends Plugin {
|
||||
|
||||
async load() {
|
||||
this.app.router.add('mobile.approval.page', {
|
||||
path: '/mobile/:name/approval/:id/page',
|
||||
Component: 'ViewActionInitiationsContent',
|
||||
});
|
||||
this.app.router.add('mobile.approval.userPage', {
|
||||
path: '/mobile/:name/:id/page',
|
||||
Component: 'ViewActionUserInitiationsContent',
|
||||
});
|
||||
|
@ -61,5 +61,6 @@
|
||||
"End on reject": "End on reject",
|
||||
"If checked, the workflow will be terminated after rejection branch processed.": "If checked, the workflow will be terminated after rejection branch processed.",
|
||||
"Disabled": "Disabled",
|
||||
"Trigger data": "Trigger data"
|
||||
"Trigger data": "Trigger data",
|
||||
"All":"All"
|
||||
}
|
||||
|
@ -76,5 +76,6 @@
|
||||
"When checked, the workflow will terminate when the rejection branch ends.": "勾选后,否决分支结束后工作流将终止。",
|
||||
"Disabled": "已失效",
|
||||
"Submission may be withdrawn, please try refresh the list.": "提交可能已被撤回,请尝试刷新列表。",
|
||||
"Trigger data": "触发器数据"
|
||||
"Trigger data": "触发器数据",
|
||||
"All":"全部"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user