mirror of
https://github.com/m-xlsea/ruoyi-plus-soybean.git
synced 2025-09-24 07:49:47 +08:00
feat: 更新请假申请表单,添加流程类型选择和流程启动功能
This commit is contained in:
@ -37,11 +37,11 @@ const value = defineModel<CommonType.IdType[]>('value', { required: false, defau
|
||||
|
||||
let fileNum = 0;
|
||||
const fileList = ref<UploadFileInfo[]>([]);
|
||||
const needRelaodData = defineModel<boolean>('needRelaodData', {
|
||||
default: false
|
||||
});
|
||||
|
||||
const needRelaodData = ref<boolean>(false);
|
||||
defineExpose({
|
||||
refreshList: needRelaodData
|
||||
refreshList: needRelaodData,
|
||||
fileList
|
||||
});
|
||||
watch(
|
||||
() => fileList.value,
|
||||
|
103
src/components/custom/workflow-task-apply-modal.vue
Normal file
103
src/components/custom/workflow-task-apply-modal.vue
Normal file
@ -0,0 +1,103 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, watch } from 'vue';
|
||||
import { messageTypeOptions } from '@/constants/workflow';
|
||||
import { fetchCompleteTask, fetchGetTask } from '@/service/api/workflow';
|
||||
import FileUpload from '@/components/custom/file-upload.vue';
|
||||
|
||||
defineOptions({
|
||||
name: 'WorkflowTaskApplyModal'
|
||||
});
|
||||
|
||||
interface Props {
|
||||
/** the task id */
|
||||
taskId: CommonType.IdType;
|
||||
/** the task variables */
|
||||
taskVariables: { [key: string]: any };
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
interface Emits {
|
||||
(e: 'finished'): void;
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const visible = defineModel<boolean>('visible', {
|
||||
default: false
|
||||
});
|
||||
const title = defineModel<string>('title', {
|
||||
default: '流程发起'
|
||||
});
|
||||
|
||||
const fileUploadRef = ref<InstanceType<typeof FileUpload> | null>(null);
|
||||
|
||||
const accept = ref<string>('.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.pdf,.jpg,.jpeg,.png,.gif,.bmp,.webp');
|
||||
|
||||
type Model = Api.Workflow.CompleteTaskOperateParams;
|
||||
|
||||
const task = ref<Api.Workflow.Task>();
|
||||
|
||||
const model: Model = reactive(createDefaultModel());
|
||||
|
||||
function createDefaultModel(): Model {
|
||||
return {
|
||||
taskId: null,
|
||||
fileId: null,
|
||||
flowCopyList: [],
|
||||
messageType: ['1'],
|
||||
taskVariables: {},
|
||||
variables: {},
|
||||
assigneeMap: {}
|
||||
};
|
||||
}
|
||||
|
||||
async function getTask() {
|
||||
const { error, data } = await fetchGetTask(props.taskId);
|
||||
if (error) return;
|
||||
task.value = data;
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
const fileList = fileUploadRef.value?.fileList;
|
||||
if (fileList?.length) {
|
||||
const fileIds = fileList.map(item => item.id);
|
||||
model.fileId = fileIds.join(',');
|
||||
}
|
||||
model.taskId = props.taskId;
|
||||
model.taskVariables = props.taskVariables;
|
||||
const { error } = await fetchCompleteTask(model);
|
||||
if (error) return;
|
||||
window.$message?.success('提交成功');
|
||||
visible.value = false;
|
||||
emit('finished');
|
||||
}
|
||||
|
||||
watch(visible, () => {
|
||||
if (visible.value) {
|
||||
getTask();
|
||||
Object.assign(model, createDefaultModel());
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NModal v-model:show="visible" :title="title" :native-scrollbar="false" closable>
|
||||
<NForm :model="model">
|
||||
<NFormItem label="通知方式" path="messageType">
|
||||
<NCheckboxGroup v-model:value="model.messageType">
|
||||
<NSpace item-style="display: flex;">
|
||||
<NCheckbox v-for="item in messageTypeOptions" :key="item.value" :value="item.value" :label="item.label" />
|
||||
</NSpace>
|
||||
</NCheckboxGroup>
|
||||
</NFormItem>
|
||||
<NFormItem label="附件" path="fileId">
|
||||
<FileUpload ref="fileUploadRef" :file-size="20" :max="20" upload-type="file" :accept="accept" />
|
||||
</NFormItem>
|
||||
</NForm>
|
||||
<template #footer>
|
||||
<NButton @click="visible = false">取消</NButton>
|
||||
<NButton type="primary" @click="handleSubmit">提交</NButton>
|
||||
</template>
|
||||
</NModal>
|
||||
</template>
|
@ -1,5 +1,24 @@
|
||||
import { transformRecordToOption } from '@/utils/common';
|
||||
|
||||
export const messageTypeRecord: Record<Api.Workflow.MessageType, string> = {
|
||||
'1': '站内信',
|
||||
'2': '邮件',
|
||||
'3': '短信'
|
||||
};
|
||||
|
||||
export const messageTypeOptions = transformRecordToOption(messageTypeRecord);
|
||||
|
||||
export const flowCodeTypeRecord: Record<Api.Workflow.FlowCodeType, string> = {
|
||||
leave1: '请假申请-普通',
|
||||
leave2: '请假申请-排他网关',
|
||||
leave3: '请假申请-并行网关',
|
||||
leave4: '请假申请-会签',
|
||||
leave5: '请假申请-并行会签网关',
|
||||
leave6: '请假申请-排他并行会签'
|
||||
};
|
||||
|
||||
export const flowCodeTypeOptions = transformRecordToOption(flowCodeTypeRecord);
|
||||
|
||||
/** leave type */
|
||||
export const leaveTypeRecord: Record<Api.Workflow.LeaveType, string> = {
|
||||
'1': '事假',
|
||||
|
@ -2,3 +2,4 @@ export * from './category';
|
||||
export * from './leave';
|
||||
export * from './instance';
|
||||
export * from './definition';
|
||||
export * from './task';
|
||||
|
@ -18,7 +18,7 @@ export function fetchGetLeaveDetail(id: CommonType.IdType) {
|
||||
|
||||
/** 新增请假申请 */
|
||||
export function fetchCreateLeave(data: Api.Workflow.LeaveOperateParams) {
|
||||
return request<boolean>({
|
||||
return request<Api.Workflow.Leave>({
|
||||
url: '/workflow/leave',
|
||||
method: 'post',
|
||||
data
|
||||
@ -27,7 +27,7 @@ export function fetchCreateLeave(data: Api.Workflow.LeaveOperateParams) {
|
||||
|
||||
/** 修改请假申请 */
|
||||
export function fetchUpdateLeave(data: Api.Workflow.LeaveOperateParams) {
|
||||
return request<boolean>({
|
||||
return request<Api.Workflow.Leave>({
|
||||
url: '/workflow/leave',
|
||||
method: 'put',
|
||||
data
|
||||
|
27
src/service/api/workflow/task.ts
Normal file
27
src/service/api/workflow/task.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { request } from '@/service/request';
|
||||
|
||||
/** 启动任务 */
|
||||
export function fetchStartWorkflow(data: Api.Workflow.StartWorkflowOperateParams) {
|
||||
return request<Api.Workflow.StartWorkflowResult>({
|
||||
url: '/workflow/task/startWorkFlow',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取任务 */
|
||||
export function fetchGetTask(taskId: CommonType.IdType) {
|
||||
return request<Api.Workflow.Task>({
|
||||
url: `/workflow/task/getTask/${taskId}`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/** 完成任务 */
|
||||
export function fetchCompleteTask(data: Api.Workflow.CompleteTaskOperateParams) {
|
||||
return request<Api.Workflow.Task>({
|
||||
url: '/workflow/task/completeTask',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
124
src/typings/api/workflow.api.d.ts
vendored
124
src/typings/api/workflow.api.d.ts
vendored
@ -10,6 +10,8 @@ declare namespace Api {
|
||||
* backend api module: "Workflow"
|
||||
*/
|
||||
namespace Workflow {
|
||||
/** 流程类型 */
|
||||
type FlowCodeType = 'leave1' | 'leave2' | 'leave3' | 'leave4' | 'leave5' | 'leave6';
|
||||
/** 请假状态 */
|
||||
type LeaveType = '1' | '2' | '3' | '4';
|
||||
/** leave */
|
||||
@ -198,5 +200,127 @@ declare namespace Api {
|
||||
/** 作废原因 */
|
||||
comment: string;
|
||||
}>;
|
||||
|
||||
/** 启动流程操作参数 */
|
||||
type StartWorkflowOperateParams = CommonType.RecordNullable<{
|
||||
/** 流程定义ID */
|
||||
flowCode: string;
|
||||
/** 业务ID */
|
||||
businessId: CommonType.IdType;
|
||||
/** 变量 */
|
||||
variables: { [key: string]: any };
|
||||
}>;
|
||||
|
||||
/** 启动流程结果 */
|
||||
type StartWorkflowResult = CommonType.RecordNullable<{
|
||||
/** 流程实例ID */
|
||||
processInstanceId: CommonType.IdType;
|
||||
/** 任务ID */
|
||||
taskId: CommonType.IdType;
|
||||
}>;
|
||||
|
||||
/** 抄送人 */
|
||||
type FlowCopy = CommonType.RecordNullable<{
|
||||
/** 用户ID */
|
||||
userId: CommonType.IdType;
|
||||
/** 用户名称 */
|
||||
userName: string;
|
||||
}>;
|
||||
/** 按钮权限 */
|
||||
type ButtonPermission = CommonType.RecordNullable<{
|
||||
/** 唯一编码 */
|
||||
code: CommonType.IdType;
|
||||
/** 选项值 */
|
||||
value: string;
|
||||
/** 是否显示 */
|
||||
show: boolean;
|
||||
}>;
|
||||
/** 任务详情 */
|
||||
type Task = Common.CommonRecord<{
|
||||
/** 任务ID */
|
||||
id: CommonType.IdType;
|
||||
/** 租户编号 */
|
||||
tenantId: CommonType.IdType;
|
||||
/** 删除标志 */
|
||||
delFlag: number;
|
||||
/** 流程定义ID */
|
||||
definitionId: CommonType.IdType;
|
||||
/** 流程实例ID */
|
||||
instanceId: CommonType.IdType;
|
||||
/** 业务ID */
|
||||
businessId: CommonType.IdType;
|
||||
/** 节点编码 */
|
||||
nodeCode: string;
|
||||
/** 节点类型 */
|
||||
nodeType: WorkflowNodeType;
|
||||
/** 权限列表 */
|
||||
permissionList: string[];
|
||||
/** 用户列表 */
|
||||
userList: any[];
|
||||
/** 审批表单是否自定义 */
|
||||
formCustom: Api.Common.YesOrNoStatus;
|
||||
/** 审批表单路径 */
|
||||
formPath: string;
|
||||
/** 流程状态 */
|
||||
flowStatus: string;
|
||||
/** 流程状态名称 */
|
||||
flowStatusName: string;
|
||||
/** 分类ID */
|
||||
category: CommonType.IdType;
|
||||
/** 分类名称 */
|
||||
categoryName: string;
|
||||
/** 类型 */
|
||||
type: string;
|
||||
/** 审批人 */
|
||||
assigneeIds: string;
|
||||
/** 审批人名称 */
|
||||
assigneeNames: string;
|
||||
/** 审批人 */
|
||||
processedBy: string;
|
||||
/** 审批人名称 */
|
||||
processedByName: string;
|
||||
/** 流程签署比例值 大于0为票签,会签 */
|
||||
nodeRatio: string;
|
||||
/** 创建人名称 */
|
||||
createByName: string;
|
||||
/** 是否为申请人节点 */
|
||||
applyNode: string;
|
||||
/** 按钮列表 */
|
||||
buttonList: ButtonPermission[];
|
||||
/** 节点名称 */
|
||||
nodeName: string;
|
||||
/** 流程定义名称 */
|
||||
flowName: string;
|
||||
/** 流程定义编码 */
|
||||
flowCode: string;
|
||||
/** 流程版本号 */
|
||||
version: string;
|
||||
}>;
|
||||
/** 消息类型 */
|
||||
type MessageType = '1' | '2' | '3';
|
||||
|
||||
/** 完成任务操作参数 */
|
||||
type CompleteTaskOperateParams = CommonType.RecordNullable<{
|
||||
/** 任务ID */
|
||||
taskId: CommonType.IdType;
|
||||
/** 文件ID */
|
||||
fileId: CommonType.IdType;
|
||||
/** 抄送人 */
|
||||
flowCopyList: FlowCopy[];
|
||||
/** 消息类型 */
|
||||
messageType: string[];
|
||||
/** 消息 */
|
||||
message: string;
|
||||
/** 通知 */
|
||||
notice: string;
|
||||
/** 任务变量 */
|
||||
taskVariables: { [key: string]: any };
|
||||
/** 变量 */
|
||||
variables: { [key: string]: any };
|
||||
/** 审批人 */
|
||||
assigneeMap: { [key: string]: string };
|
||||
/** 扩展字段 */
|
||||
ext: string;
|
||||
}>;
|
||||
}
|
||||
}
|
||||
|
4
src/typings/components.d.ts
vendored
4
src/typings/components.d.ts
vendored
@ -55,6 +55,7 @@ declare module 'vue' {
|
||||
IconUilSearch: typeof import('~icons/uil/search')['default']
|
||||
JsonPreview: typeof import('./../components/custom/json-preview.vue')['default']
|
||||
LangSwitch: typeof import('./../components/common/lang-switch.vue')['default']
|
||||
LeaveForm: typeof import('../components/custom/workflow-leave-form.vue')['default']
|
||||
LookForward: typeof import('./../components/custom/look-forward.vue')['default']
|
||||
MenuToggler: typeof import('./../components/common/menu-toggler.vue')['default']
|
||||
MenuTree: typeof import('./../components/custom/menu-tree.vue')['default']
|
||||
@ -68,6 +69,7 @@ declare module 'vue' {
|
||||
NButton: typeof import('naive-ui')['NButton']
|
||||
NCard: typeof import('naive-ui')['NCard']
|
||||
NCheckbox: typeof import('naive-ui')['NCheckbox']
|
||||
NCheckboxGroup: typeof import('naive-ui')['NCheckboxGroup']
|
||||
NCode: typeof import('naive-ui')['NCode']
|
||||
NCollapse: typeof import('naive-ui')['NCollapse']
|
||||
NCollapseItem: typeof import('naive-ui')['NCollapseItem']
|
||||
@ -147,5 +149,7 @@ declare module 'vue' {
|
||||
UserSelect: typeof import('./../components/custom/user-select.vue')['default']
|
||||
WaveBg: typeof import('./../components/custom/wave-bg.vue')['default']
|
||||
WorkflowCategorySelect: typeof import('./../components/custom/workflow-category-select.vue')['default']
|
||||
WorkflowLeaveForm: typeof import('./../components/custom/workflow-leave-form.vue')['default']
|
||||
WorkflowTaskApplyModal: typeof import('./../components/custom/workflow-task-apply-modal.vue')['default']
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive, watch } from 'vue';
|
||||
import { computed, reactive, ref, watch } from 'vue';
|
||||
import dayjs from 'dayjs';
|
||||
import { leaveTypeOptions } from '@/constants/workflow';
|
||||
import { fetchCreateLeave, fetchUpdateLeave } from '@/service/api/workflow';
|
||||
import { useBoolean } from '@sa/hooks';
|
||||
import { flowCodeTypeOptions, leaveTypeOptions } from '@/constants/workflow';
|
||||
import { fetchCreateLeave, fetchStartWorkflow, fetchUpdateLeave } from '@/service/api/workflow';
|
||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
@ -28,7 +29,7 @@ const emit = defineEmits<Emits>();
|
||||
const visible = defineModel<boolean>('visible', {
|
||||
default: false
|
||||
});
|
||||
|
||||
const { bool: taskApplyVisible, setTrue: setTaskApplyVisible } = useBoolean();
|
||||
const { formRef, validate, restoreValidation } = useNaiveForm();
|
||||
const { createRequiredRule } = useFormRules();
|
||||
|
||||
@ -40,12 +41,21 @@ const title = computed(() => {
|
||||
return titles[props.operateType];
|
||||
});
|
||||
|
||||
type Model = Api.Workflow.LeaveOperateParams;
|
||||
const respLeave = ref<Api.Workflow.Leave>();
|
||||
const startWorkflowResult = ref<Api.Workflow.StartWorkflowResult>();
|
||||
|
||||
type Model = Api.Workflow.LeaveOperateParams & {
|
||||
flowCode: Api.Workflow.FlowCodeType;
|
||||
};
|
||||
type StartWorkflowModel = Api.Workflow.StartWorkflowOperateParams;
|
||||
|
||||
const model: Model = reactive(createDefaultModel());
|
||||
|
||||
const startWorkflowModel: StartWorkflowModel = reactive(createDefaultStartWorkflowModel());
|
||||
|
||||
function createDefaultModel(): Model {
|
||||
return {
|
||||
flowCode: 'leave1',
|
||||
leaveType: null,
|
||||
startDate: null,
|
||||
endDate: null,
|
||||
@ -53,6 +63,15 @@ function createDefaultModel(): Model {
|
||||
remark: ''
|
||||
};
|
||||
}
|
||||
|
||||
function createDefaultStartWorkflowModel(): StartWorkflowModel {
|
||||
return {
|
||||
flowCode: null,
|
||||
businessId: null,
|
||||
variables: {}
|
||||
};
|
||||
}
|
||||
|
||||
const dateRange = computed<[string, string] | null>({
|
||||
get: () => {
|
||||
if (!model.startDate || !model.endDate) return null;
|
||||
@ -74,10 +93,11 @@ const dateRange = computed<[string, string] | null>({
|
||||
}
|
||||
});
|
||||
|
||||
type RuleKey = Extract<keyof Model, 'id' | 'leaveType' | 'leaveDays' | 'startDate' | 'endDate'>;
|
||||
type RuleKey = Extract<keyof Model, 'id' | 'leaveType' | 'leaveDays' | 'startDate' | 'endDate'> | 'flowCode';
|
||||
|
||||
const rules: Record<RuleKey, App.Global.FormRule> = {
|
||||
id: createRequiredRule('id不能为空'),
|
||||
flowCode: createRequiredRule('流程类型不能为空'),
|
||||
leaveType: createRequiredRule('请假类型不能为空'),
|
||||
startDate: createRequiredRule('请假时间不能为空'),
|
||||
endDate: createRequiredRule('结束时间不能为空'),
|
||||
@ -99,23 +119,45 @@ function closeDrawer() {
|
||||
visible.value = false;
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
async function handleSaveDraft() {
|
||||
await validate();
|
||||
|
||||
// request
|
||||
if (props.operateType === 'add') {
|
||||
const { leaveType, startDate, endDate, leaveDays, remark } = model;
|
||||
const { error } = await fetchCreateLeave({ leaveType, startDate, endDate, leaveDays, remark });
|
||||
const { error, data } = await fetchCreateLeave({ leaveType, startDate, endDate, leaveDays, remark });
|
||||
if (error) return;
|
||||
respLeave.value = data;
|
||||
}
|
||||
|
||||
if (props.operateType === 'edit') {
|
||||
const { id, leaveType, startDate, endDate, leaveDays, remark } = model;
|
||||
const { error } = await fetchUpdateLeave({ id, leaveType, startDate, endDate, leaveDays, remark });
|
||||
const { error, data } = await fetchUpdateLeave({ id, leaveType, startDate, endDate, leaveDays, remark });
|
||||
if (error) return;
|
||||
respLeave.value = data;
|
||||
}
|
||||
}
|
||||
|
||||
const taskVariables = ref<{ [key: string]: any }>({});
|
||||
|
||||
async function handleSubmit() {
|
||||
await handleSaveDraft();
|
||||
// 提交流程
|
||||
startWorkflowModel.businessId = respLeave.value?.id;
|
||||
startWorkflowModel.flowCode = model.flowCode;
|
||||
taskVariables.value = {
|
||||
leaveDays: respLeave.value?.leaveDays,
|
||||
userList: ['1', '3', '4']
|
||||
};
|
||||
startWorkflowModel.variables = taskVariables.value;
|
||||
const { error, data } = await fetchStartWorkflow(startWorkflowModel);
|
||||
if (error) return;
|
||||
startWorkflowResult.value = data;
|
||||
window.$message?.success($t('common.updateSuccess'));
|
||||
setTaskApplyVisible();
|
||||
}
|
||||
|
||||
function handleTaskFinished() {
|
||||
closeDrawer();
|
||||
emit('submitted');
|
||||
}
|
||||
@ -132,6 +174,9 @@ watch(visible, () => {
|
||||
<NDrawer v-model:show="visible" :title="title" display-directive="show" :width="800" class="max-w-90%">
|
||||
<NDrawerContent :title="title" :native-scrollbar="false" closable>
|
||||
<NForm ref="formRef" :model="model" :rules="rules">
|
||||
<NFormItem label="流程类型" path="flowCode">
|
||||
<NSelect v-model:value="model.flowCode" placeholder="请输入流程类型" :options="flowCodeTypeOptions" />
|
||||
</NFormItem>
|
||||
<NFormItem label="请假类型" path="leaveType">
|
||||
<NSelect v-model:value="model.leaveType" placeholder="请输入请假类型" :options="leaveTypeOptions" />
|
||||
</NFormItem>
|
||||
@ -154,9 +199,16 @@ watch(visible, () => {
|
||||
<template #footer>
|
||||
<NSpace :size="16">
|
||||
<NButton @click="closeDrawer">{{ $t('common.cancel') }}</NButton>
|
||||
<NButton @click="handleSaveDraft">暂存</NButton>
|
||||
<NButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</NButton>
|
||||
</NSpace>
|
||||
</template>
|
||||
<WorkflowTaskApplyModal
|
||||
v-model:visible="taskApplyVisible"
|
||||
:task-id="startWorkflowResult?.taskId || ''"
|
||||
:task-variables="taskVariables"
|
||||
@finished="handleTaskFinished"
|
||||
/>
|
||||
</NDrawerContent>
|
||||
</NDrawer>
|
||||
</template>
|
||||
|
Reference in New Issue
Block a user