first commit
This commit is contained in:
@@ -0,0 +1,413 @@
|
||||
<template>
|
||||
<div>
|
||||
<BasicTable @register="registerTable" :rowSelection="rowSelection">
|
||||
<template #form-bizTaskType="{ model, field }">
|
||||
<a-radio-group v-model:value="queryParam.bizTaskType" @change="onBizTaskTypeChange(model, field)">
|
||||
<a-radio value="1">待我审批</a-radio>
|
||||
<a-radio value="2">我发起的申请</a-radio>
|
||||
</a-radio-group>
|
||||
</template>
|
||||
<template #notify="{ text, record }">
|
||||
<SoundTwoTone title="催办提醒" v-if="record.taskUrge" twoToneColor="#eb2f96" @click.stop="taskNotifyMe(flowCode, record.id)" />
|
||||
{{ text }}
|
||||
</template>
|
||||
<template #tableTitle>
|
||||
<template v-if="queryParam.bizTaskType == '2'">
|
||||
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="handleCreate"> 新增</a-button>
|
||||
<a-dropdown v-if="selectedRowKeys.length > 0">
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item key="1" @click="batchHandleDelete">
|
||||
<Icon icon="ant-design:delete-outlined"></Icon>
|
||||
删除
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
<a-button
|
||||
>批量操作
|
||||
<Icon icon="mdi:chevron-down"></Icon>
|
||||
</a-button>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
<template v-else>
|
||||
<a-button @click="handleBatch(1)" type="primary" preIcon="ant-design:caret-right-outlined">批量发送</a-button>
|
||||
<a-button @click="handleBatch(2)" type="primary" preIcon="ant-design:user-outlined">批量委托</a-button>
|
||||
<a-button @click="handleBatch(3)" type="primary" preIcon="ant-design:rollback-outlined">批量退回</a-button>
|
||||
<a-button @click="handleBatch(4)" type="primary" preIcon="ant-design:lock-outlined">批量挂起</a-button>
|
||||
<a-button @click="handleBatch(5)" type="primary" preIcon="ant-design:unlock-outlined">批量解挂</a-button>
|
||||
</template>
|
||||
</template>
|
||||
<!--操作栏-->
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
<!--新增编辑弹窗-->
|
||||
<BizLeaveModal @register="registerModal" @success="reload"></BizLeaveModal>
|
||||
<!--业务办理弹窗-->
|
||||
<BpmBizTaskDealModal ref="taskDealModal" :path="path" :formData="formData" @ok="handleClear"></BpmBizTaskDealModal>
|
||||
<!--审批跟踪记录弹窗-->
|
||||
<BpmProcessTrackModal ref="trackModal"></BpmProcessTrackModal>
|
||||
<!--催办弹窗-->
|
||||
<BizTaskNotifyModal ref="taskNotifyModal"></BizTaskNotifyModal>
|
||||
<!--催办自己弹窗-->
|
||||
<BizTaskNotifyMeModal ref="taskNotifyMeModal"></BizTaskNotifyMeModal>
|
||||
<!--批量发送-->
|
||||
<BpmBizBatchCompleteDealModal ref="completeModal" @ok="handleClear"></BpmBizBatchCompleteDealModal>
|
||||
<!--批量委托-->
|
||||
<BpmBizBatchEntrusterDealModal ref="entrusterModal" @ok="handleClear"></BpmBizBatchEntrusterDealModal>
|
||||
<!--批量退回-->
|
||||
<BpmBizBatchRejectDealModal ref="rejectModal" @ok="handleClear"></BpmBizBatchRejectDealModal>
|
||||
<!--批量挂起-->
|
||||
<BpmBizBatchSuspendDealModal ref="suspendModal" @ok="handleClear"></BpmBizBatchSuspendDealModal>
|
||||
<!--批量解挂-->
|
||||
<BpmBizBatchRestartDealModal ref="restartModal" @ok="handleClear"></BpmBizBatchRestartDealModal>
|
||||
|
||||
<!-- 测试流程设计modal -->
|
||||
<mini-des-flow-modal @register="registerMiniDesFlowModal"></mini-des-flow-modal>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" name="biz-leave-list" setup>
|
||||
import { ref, reactive, toRaw, getCurrentInstance, unref } from 'vue';
|
||||
import { BasicTable, TableAction } from '/src/components/Table';
|
||||
import BizLeaveModal from './components/BizLeaveModal.vue';
|
||||
import BpmBizTaskDealModal from './components/BpmBizTaskDealModal.vue';
|
||||
import BpmProcessTrackModal from './components/BpmProcessTrackModal.vue';
|
||||
import BizTaskNotifyModal from './components/BizTaskNotifyModal.vue';
|
||||
import BizTaskNotifyMeModal from './components/BizTaskNotifyMeModal.vue';
|
||||
import BpmBizBatchCompleteDealModal from './components/BpmBizBatchCompleteDealModal.vue';
|
||||
import BpmBizBatchEntrusterDealModal from './components/BpmBizBatchEntrusterDealModal.vue';
|
||||
import BpmBizBatchRejectDealModal from './components/BpmBizBatchRejectDealModal.vue';
|
||||
import BpmBizBatchSuspendDealModal from './components/BpmBizBatchSuspendDealModal.vue';
|
||||
import BpmBizBatchRestartDealModal from './components/BpmBizBatchRestartDealModal.vue';
|
||||
import { SoundTwoTone } from '@ant-design/icons-vue';
|
||||
import { useModal } from '/src/components/Modal';
|
||||
import { useMessage } from '/src/hooks/web/useMessage';
|
||||
import { showDealBtn } from '/src/utils';
|
||||
import { columns, searchFormSchema } from './leave.data';
|
||||
import { list, startProcess, deleteOne, invalidProcess, queryFlowData, batchDelete, checkNotify } from './leave.api';
|
||||
import { getBizProcessNodeInfo } from '/src/views/super/bpm/process/manage/components/bpm.api.ts';
|
||||
import { useListPage } from '/src/hooks/system/useListPage';
|
||||
const { createMessage } = useMessage();
|
||||
//弹窗
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
//查询条件
|
||||
const queryParam = reactive({
|
||||
bizTaskType: '1',
|
||||
name: '',
|
||||
});
|
||||
//弹窗示例
|
||||
const instance = getCurrentInstance();
|
||||
const formData = ref({});
|
||||
const path = ref('');
|
||||
const flowCode = 'TEST001';
|
||||
const formUrl = 'super/bpm/example/batch/components/BizLeaveForm';
|
||||
const formUrlMobile = 'super/bpm/example/batch/components/BizLeaveForm';
|
||||
// 列表页面公共参数、方法 NY5LzSY2VW1BSthYSnJArCFqbgwtZqSuyPQ/OD1n1twWJGU2RN/wkzf+kBVO5DztN85Ca9keeuaRAiwcatr8N0M15+Wv2SmRw82lMwawE2naX5tpJMpkxrUhUUcjnC+BSBL4+PV2JUXBFW8/oOG8HLqYvmPxoP7MMBhMi9D7lRY=
|
||||
const { prefixCls, tableContext } = useListPage({
|
||||
designScope: 'leave-list',
|
||||
tableProps: {
|
||||
title: '业务办理',
|
||||
api: list,
|
||||
columns: columns,
|
||||
canResize: false,
|
||||
afterFetch: afterFetch,
|
||||
formConfig: {
|
||||
schemas: searchFormSchema,
|
||||
resetFunc: handleReset,
|
||||
},
|
||||
actionColumn: {
|
||||
width: 120,
|
||||
fixed: 'right',
|
||||
},
|
||||
},
|
||||
});
|
||||
const [registerTable, { reload, clearSelectedRowKeys }, { rowSelection, selectedRowKeys, selectedRows }] = tableContext;
|
||||
const [registerMiniDesFlowModal, { openModal: openDesignModalTest }] = useModal();
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
function handleCreate() {
|
||||
openModal(true, {
|
||||
isUpdate: false,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 编辑
|
||||
*/
|
||||
function handleEdit(record: Recordable) {
|
||||
console.log('点击了编辑', record);
|
||||
openModal(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 删除
|
||||
* @param id
|
||||
*/
|
||||
async function handleDelete(id) {
|
||||
console.log('点击了删除', id);
|
||||
await deleteOne({ id }, reload);
|
||||
}
|
||||
/**
|
||||
* 详情
|
||||
* @param id
|
||||
*/
|
||||
async function handleDetail(record) {
|
||||
console.log('点击了详情', record);
|
||||
openModal(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
isDetail: true,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 办理
|
||||
* @param record
|
||||
*/
|
||||
async function handleProcess(record) {
|
||||
console.log('点击了办理', record);
|
||||
let res = await getBizProcessNodeInfo({ flowCode: flowCode, dataId: record.id });
|
||||
if (res.success) {
|
||||
console.log('获取流程节点信息', res);
|
||||
let data = {
|
||||
dataId: res.result.dataId,
|
||||
taskId: res.result.taskId,
|
||||
taskDefKey: res.result.taskDefKey,
|
||||
procInsId: res.result.procInsId,
|
||||
tableName: res.result.tableName,
|
||||
permissionList: res.result.permissionList,
|
||||
bizTaskList: res.result.bizTaskList,
|
||||
vars: res.result.records,
|
||||
};
|
||||
formData.value = data;
|
||||
console.log('------获取流程节点信息', unref(formData));
|
||||
path.value = res.result.formUrl;
|
||||
console.log('获取流程节点信息', unref(path));
|
||||
instance.refs.taskDealModal.deal(data);
|
||||
instance.refs.taskDealModal.title = '流程办理';
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 提交流程
|
||||
* @param record
|
||||
*/
|
||||
async function handleStartProcess(record) {
|
||||
let params = {
|
||||
flowCode: flowCode,
|
||||
id: record.id,
|
||||
formUrl: formUrl,
|
||||
formUrlMobile: formUrlMobile,
|
||||
};
|
||||
let res = await startProcess(params);
|
||||
if (res && res.success) {
|
||||
createMessage.success(res.message);
|
||||
handleClear();
|
||||
} else {
|
||||
createMessage.warning(res.message || '流程启动异常');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 清空并重新加载
|
||||
* @param record
|
||||
*/
|
||||
function handleClear() {
|
||||
reload();
|
||||
clearSelectedRowKeys();
|
||||
}
|
||||
/**
|
||||
* 列表接口请求后处理
|
||||
* @param record
|
||||
*/
|
||||
async function afterFetch(data) {
|
||||
if (queryParam.bizTaskType == '1') {
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let item = data[i];
|
||||
let params = { flowCode: flowCode, dataId: item.id }; //查询条件
|
||||
let res2 = await checkNotify(params);
|
||||
if (res2.result) {
|
||||
item.taskUrge = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//提醒我的
|
||||
async function taskNotifyMe(flowCode, dataId) {
|
||||
let params = { flowCode: flowCode, dataId: dataId }; //查询条件
|
||||
await queryFlowData(params, (res) => {
|
||||
if (res.success) {
|
||||
instance.refs.taskNotifyMeModal.notify(res.result.processInstId);
|
||||
instance.refs.taskNotifyMeModal.title = '催办提醒';
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 批量删除事件
|
||||
*/
|
||||
async function batchHandleDelete() {
|
||||
await batchDelete({ ids: selectedRowKeys.value }, () => {
|
||||
selectedRowKeys.value = [];
|
||||
reload();
|
||||
});
|
||||
}
|
||||
//批量挂起
|
||||
function handleBatch(type) {
|
||||
let rows = toRaw(selectedRows.value);
|
||||
if (rows.length > 0) {
|
||||
let param = [];
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
let data = { dataId: rows[i].id, flowCode, bizTitle: rows[i].name };
|
||||
param.push(data);
|
||||
}
|
||||
switch (type) {
|
||||
case 1:
|
||||
instance.refs.completeModal.deal(param);
|
||||
instance.refs.completeModal.title = '批量发送';
|
||||
break;
|
||||
case 2:
|
||||
instance.refs.entrusterModal.deal(param);
|
||||
instance.refs.entrusterModal.title = '批量委派';
|
||||
break;
|
||||
case 3:
|
||||
instance.refs.rejectModal.deal(param);
|
||||
instance.refs.rejectModal.title = '批量退回';
|
||||
break;
|
||||
case 4:
|
||||
instance.refs.suspendModal.deal(param);
|
||||
instance.refs.suspendModal.title = '批量挂起';
|
||||
break;
|
||||
case 5:
|
||||
instance.refs.restartModal.deal(param);
|
||||
instance.refs.restartModal.title = '批量解挂';
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
createMessage.warning('请选择一条记录!');
|
||||
}
|
||||
}
|
||||
|
||||
//催办
|
||||
async function taskNotify(record) {
|
||||
let params = { flowCode: flowCode, dataId: record.id }; //查询条件
|
||||
await queryFlowData(params, (res) => {
|
||||
if (res.success) {
|
||||
instance.refs.taskNotifyModal.notify(res.result.processInstId);
|
||||
instance.refs.taskNotifyModal.data.title = '催办提醒';
|
||||
}
|
||||
});
|
||||
}
|
||||
//审批进度
|
||||
function handleTrack(record) {
|
||||
let params = { flowCode: flowCode, dataId: record.id }; //查询条件
|
||||
instance.refs.trackModal.handleTrack(params);
|
||||
instance.refs.trackModal.data.title = '审批跟踪记录';
|
||||
}
|
||||
//审批进度(简版)
|
||||
function handleSimpleTrack(record) {
|
||||
openDesignModalTest(true, {
|
||||
dataId: record.id,
|
||||
preview:"true",
|
||||
flowCode: flowCode
|
||||
});
|
||||
}
|
||||
//作废流程
|
||||
async function handleInvalidProcess(record) {
|
||||
await invalidProcess({ flowCode: flowCode, dataId: record.id }, reload);
|
||||
}
|
||||
//类型切换
|
||||
function onBizTaskTypeChange(model, field) {
|
||||
model[field] = queryParam.bizTaskType;
|
||||
reload();
|
||||
}
|
||||
//自定义重置
|
||||
function handleReset() {
|
||||
queryParam.bizTaskType = '1';
|
||||
}
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
ifShow: () => {
|
||||
return record.bpmStatus === '1';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '提交流程',
|
||||
popConfirm: {
|
||||
title: '确认提交流程吗?',
|
||||
confirm: handleStartProcess.bind(null, record),
|
||||
},
|
||||
ifShow: () => {
|
||||
return record.bpmStatus === '1';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '办理',
|
||||
onClick: handleProcess.bind(null, record),
|
||||
ifShow: () => {
|
||||
return showDealBtn(record.bpmStatus) && queryParam.bizTaskType == '1';
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
/**
|
||||
* 下拉操作栏
|
||||
*/
|
||||
function getDropDownAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '详情',
|
||||
onClick: handleDetail.bind(null, record),
|
||||
ifShow: () => {
|
||||
return queryParam.bizTaskType == '2';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '催办',
|
||||
onClick: taskNotify.bind(null, record),
|
||||
ifShow: () => {
|
||||
return record.bpmStatus !== '1' && record.bpmStatus !== '3' && queryParam.bizTaskType == '2';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '审批进度',
|
||||
onClick: handleTrack.bind(null, record),
|
||||
ifShow: () => {
|
||||
return record.bpmStatus !== '1';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '审批进度(简版)',
|
||||
onClick: handleSimpleTrack.bind(null, record),
|
||||
ifShow: () => {
|
||||
return record.bpmStatus !== '1';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '作废流程',
|
||||
popConfirm: {
|
||||
title: '是否确认作废',
|
||||
confirm: handleInvalidProcess.bind(null, record),
|
||||
},
|
||||
ifShow: () => {
|
||||
return showDealBtn(record.bpmStatus) && queryParam.bizTaskType == '2';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
confirm: handleDelete.bind(null, record.id),
|
||||
},
|
||||
ifShow: () => {
|
||||
return record.bpmStatus === '1';
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<div>
|
||||
<BasicForm ref="form" @register="registerForm" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, unref } from 'vue';
|
||||
import { BasicForm, useForm } from '/src/components/Form';
|
||||
import { formSchema } from '../leave.data';
|
||||
import { queryById } from '../leave.api';
|
||||
|
||||
const props = defineProps({
|
||||
formData: {
|
||||
type: Object,
|
||||
},
|
||||
});
|
||||
const form = ref(null);
|
||||
//表单配置
|
||||
const [registerForm] = useForm({
|
||||
// labelWidth: 150,
|
||||
schemas: formSchema,
|
||||
showActionButtonGroup: false,
|
||||
disabled: true,
|
||||
});
|
||||
|
||||
/**
|
||||
* 初始化表单数据
|
||||
*/
|
||||
async function initFormData() {
|
||||
if (unref(form)) {
|
||||
form.value.resetFields();
|
||||
let res = await queryById({ id: props.formData.dataId });
|
||||
if (res.success) {
|
||||
form.value.setFieldsValue(res.result);
|
||||
}
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
initFormData();
|
||||
}, 10);
|
||||
}
|
||||
}
|
||||
initFormData();
|
||||
</script>
|
||||
@@ -0,0 +1,55 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" :bodyStyle="{height: '350px'}" :title="title" @ok="handleSubmit" :width="700">
|
||||
<BasicForm @register="registerForm" />
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, unref } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { BasicForm, useForm } from '/@/components/Form';
|
||||
import { formSchema } from '../leave.data';
|
||||
import { saveOrUpdate } from '../leave.api';
|
||||
// 声明Emits
|
||||
const emit = defineEmits(['success', 'register']);
|
||||
const isUpdate = ref(true);
|
||||
//表单配置
|
||||
const [registerForm, { resetFields, setFieldsValue, validate, setProps }] = useForm({
|
||||
// labelWidth: 150,
|
||||
schemas: formSchema,
|
||||
showActionButtonGroup: false,
|
||||
});
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
//重置表单
|
||||
await resetFields();
|
||||
setModalProps({ confirmLoading: false, showOkBtn: !!!data?.isDetail });
|
||||
// update-begin--author:liaozhiyang---date:20240625---for:【TV360X-1359】批量审批详情弹窗应该禁用
|
||||
setProps({ disabled: !!data?.isDetail });
|
||||
// update-end--author:liaozhiyang---date:20240625---for:【TV360X-1359】批量审批详情弹窗应该禁用
|
||||
isUpdate.value = !!data?.isUpdate;
|
||||
if (unref(isUpdate)) {
|
||||
//表单赋值
|
||||
await setFieldsValue({
|
||||
...data.record,
|
||||
});
|
||||
}
|
||||
});
|
||||
//设置标题
|
||||
const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
|
||||
|
||||
//表单提交事件
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
const values = await validate();
|
||||
setModalProps({ confirmLoading: true });
|
||||
//提交表单
|
||||
await saveOrUpdate(values, isUpdate.value);
|
||||
//关闭弹窗
|
||||
closeModal();
|
||||
//刷新列表
|
||||
emit('success');
|
||||
} finally {
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,301 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-modal centered :title="title" :width="1200" :open="visible" @ok="handleOk" @cancel="handleCancel" cancelText="关闭">
|
||||
<a-row :gutter="18">
|
||||
<a-col :xs="24" :sm="16">
|
||||
<a-card title="选择人员" :bordered="true">
|
||||
<!-- 查询区域 -->
|
||||
<div class="jeecg-basic-table-form-container" @keyup.enter="searchQuery">
|
||||
<a-form ref="formRef" :model="queryParam" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="8">
|
||||
<a-form-item label="用户姓名">
|
||||
<a-input placeholder="请输入姓名" v-model:value="queryParam.realname"></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<span style="float: left; overflow: hidden" class="table-page-search-submitButtons">
|
||||
<a-col :span="6">
|
||||
<a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button>
|
||||
<a-button type="primary" preIcon="ant-design:reload-outlined" @click="searchReset" style="margin-left: 8px">重置</a-button>
|
||||
</a-col>
|
||||
</span>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</div>
|
||||
<!-- table区域-begin -->
|
||||
<div>
|
||||
<a-table
|
||||
size="small"
|
||||
bordered
|
||||
rowKey="id"
|
||||
:columns="columns1"
|
||||
:dataSource="dataSource1"
|
||||
:pagination="ipagination"
|
||||
:loading="loading"
|
||||
:rowSelection="{ selectedRowKeys: selectedRowKeys, onSelectAll: onSelectAll, onSelect: onSelect, onChange: onSelectChange }"
|
||||
@change="handleTableChange"
|
||||
>
|
||||
<template #username="{ text, record }">
|
||||
<JEllipsis :value="text" :length="15" />
|
||||
</template>
|
||||
<template #realname="{ text, record }">
|
||||
<JEllipsis :value="text" :length="10" />
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
<!-- table区域-end -->
|
||||
</a-card>
|
||||
</a-col>
|
||||
<a-col :xs="24" :sm="8">
|
||||
<a-card title="用户选择" :bordered="true">
|
||||
<div>
|
||||
<a-table size="small" bordered rowKey="id" :columns="columns2" :dataSource="dataSource2" :loading="loading" :scroll="{ y: 240 }">
|
||||
<template #action="{ text, record }">
|
||||
<a-button type="primary" size="small" @click="handleDelete(record)" preIcon="ant-design:delete-outlined">删除</a-button>
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
</a-card>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, toRefs } from 'vue';
|
||||
import { getBizProcessNodeInfo, suspend } from '/src/views/super/bpm/process/manage/components/bpm.api';
|
||||
import { useMessage } from '/src/hooks/web/useMessage';
|
||||
import { list } from '/src/views/system/user/user.api.ts';
|
||||
import JEllipsis from '/src/components/Form/src/jeecg/components/JEllipsis.vue';
|
||||
import { filterObj } from '/src/utils/common/compUtils';
|
||||
|
||||
export default defineComponent({
|
||||
props: ['formData'],
|
||||
components: {
|
||||
JEllipsis,
|
||||
},
|
||||
emits: ['selectFinished'],
|
||||
setup(_, { emit }) {
|
||||
const { createMessage } = useMessage();
|
||||
function searchQuery() {
|
||||
loadData(1);
|
||||
}
|
||||
function searchReset() {
|
||||
_this.queryParam = {};
|
||||
loadData(1);
|
||||
}
|
||||
function handleCancel() {
|
||||
_this.visible = false;
|
||||
}
|
||||
function handleOk() {
|
||||
if (_this.dataSource2.length <= 0) {
|
||||
createMessage.warning('请选用户信息');
|
||||
return;
|
||||
}
|
||||
emit('selectFinished', _this.dataSource2);
|
||||
_this.visible = false;
|
||||
}
|
||||
function add() {
|
||||
_this.visible = true;
|
||||
}
|
||||
function loadData(arg?) {
|
||||
//加载数据 若传入参数1则加载第一页的内容
|
||||
if (arg === 1) {
|
||||
_this.ipagination.current = 1;
|
||||
}
|
||||
let params = getQueryParams(); //查询条件
|
||||
list(params).then((res) => {
|
||||
if (res.records) {
|
||||
_this.dataSource1 = res.records;
|
||||
_this.ipagination.total = res.total;
|
||||
}
|
||||
});
|
||||
}
|
||||
function getQueryParams() {
|
||||
let param = Object.assign({}, _this.queryParam, _this.isorter);
|
||||
param.pageNo = _this.ipagination.current;
|
||||
param.pageSize = _this.ipagination.pageSize;
|
||||
return filterObj(param);
|
||||
}
|
||||
|
||||
function onSelectAll(selected, selectedRows, changeRows) {
|
||||
if (selected === true) {
|
||||
for (let a = 0; a < changeRows.length; a++) {
|
||||
_this.dataSource2.push(changeRows[a]);
|
||||
}
|
||||
} else {
|
||||
for (let b = 0; b < changeRows.length; b++) {
|
||||
_this.dataSource2.splice(_this.dataSource2.indexOf(changeRows[b]), 1);
|
||||
}
|
||||
}
|
||||
// console.log(selected, selectedRows, changeRows);
|
||||
}
|
||||
function onSelect(record, selected) {
|
||||
if (selected === true) {
|
||||
_this.dataSource2.push(record);
|
||||
} else {
|
||||
var index = _this.dataSource2.indexOf(record);
|
||||
//console.log();
|
||||
if (index >= 0) {
|
||||
_this.dataSource2.splice(_this.dataSource2.indexOf(record), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
function onSelectChange(selectedRowKeys, selectedRows) {
|
||||
_this.selectedRowKeys = selectedRowKeys;
|
||||
_this.selectionRows = selectedRows;
|
||||
}
|
||||
function onClearSelected() {
|
||||
_this.selectedRowKeys = [];
|
||||
_this.selectionRows = [];
|
||||
}
|
||||
function handleDelete(record) {
|
||||
_this.dataSource2.splice(_this.dataSource2.indexOf(record), 1);
|
||||
}
|
||||
function handleTableChange(pagination, filters, sorter) {
|
||||
//分页、排序、筛选变化时触发
|
||||
//TODO 筛选
|
||||
if (Object.keys(sorter).length > 0) {
|
||||
_this.isorter.column = sorter.field;
|
||||
_this.isorter.order = 'ascend' == sorter.order ? 'asc' : 'desc';
|
||||
}
|
||||
_this.ipagination = pagination;
|
||||
loadData();
|
||||
}
|
||||
const _this = reactive({
|
||||
title: '用户列表',
|
||||
names: [],
|
||||
visible: false,
|
||||
placement: 'right',
|
||||
description: '人员管理页面',
|
||||
// 查询条件
|
||||
queryParam: {},
|
||||
dataSource1: [],
|
||||
dataSource2: [],
|
||||
// 分页参数
|
||||
ipagination: {
|
||||
current: 1,
|
||||
pageSize: 5,
|
||||
pageSizeOptions: ['5', '10', '20'],
|
||||
showTotal: (total, range) => {
|
||||
return range[0] + '-' + range[1] + ' 共' + total + '条';
|
||||
},
|
||||
showQuickJumper: true,
|
||||
showSizeChanger: true,
|
||||
total: 0,
|
||||
},
|
||||
isorter: {
|
||||
column: 'createTime',
|
||||
order: 'desc',
|
||||
},
|
||||
loading: false,
|
||||
selectedRowKeys: [],
|
||||
selectedRows: [],
|
||||
// 表头
|
||||
columns1: [
|
||||
{
|
||||
title: '#',
|
||||
dataIndex: '',
|
||||
key: 'rowIndex',
|
||||
width: 30,
|
||||
align: 'center',
|
||||
customRender: ({ index }) => {
|
||||
return parseInt(index) + 1;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '用户账号',
|
||||
align: 'center',
|
||||
dataIndex: 'username',
|
||||
width: 120,
|
||||
slots: { customRender: 'username' },
|
||||
},
|
||||
{
|
||||
title: '用户姓名',
|
||||
align: 'center',
|
||||
width: 100,
|
||||
dataIndex: 'realname',
|
||||
slots: { customRender: 'realname' },
|
||||
},
|
||||
],
|
||||
columns2: [
|
||||
{
|
||||
title: '用户姓名',
|
||||
align: 'center',
|
||||
width: '60%',
|
||||
dataIndex: 'realname',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
align: 'center',
|
||||
width: '40%',
|
||||
slots: { customRender: 'action' },
|
||||
},
|
||||
],
|
||||
dealStatus: false,
|
||||
disabledButton: false,
|
||||
});
|
||||
const labelCol = reactive({
|
||||
xs: { span: 24 },
|
||||
sm: { span: 7 },
|
||||
});
|
||||
const wrapperCol = reactive({
|
||||
xs: { span: 24 },
|
||||
sm: { span: 16 },
|
||||
});
|
||||
loadData(1);
|
||||
return {
|
||||
...toRefs(_this),
|
||||
handleOk,
|
||||
handleCancel,
|
||||
searchQuery,
|
||||
searchReset,
|
||||
onSelectAll,
|
||||
onSelect,
|
||||
onSelectChange,
|
||||
handleTableChange,
|
||||
handleDelete,
|
||||
labelCol,
|
||||
wrapperCol,
|
||||
add,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-card-body .table-operator {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.anty-row-operator button {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.ant-btn-danger {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.ant-modal-cust-warp {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ant-modal-cust-warp .ant-modal-body {
|
||||
height: calc(100% - 110px) !important;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.ant-modal-cust-warp .ant-modal-content {
|
||||
height: 90% !important;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.jeecg-basic-table-form-container {
|
||||
.table-page-search-submitButtons {
|
||||
display: block;
|
||||
margin-bottom: 24px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,422 @@
|
||||
<template>
|
||||
<!--流程办理的任务处理弹窗-->
|
||||
<div style="background: #fff; margin-right: 10px">
|
||||
<!-- 步骤条 -->
|
||||
<a-spin :spinning="loading">
|
||||
<div class="ant-alert ant-alert-info" style="margin-bottom: 16px">
|
||||
当前任务办理环节:
|
||||
<a-select style="width: 300px" v-model:value="currTask.id">
|
||||
<a-select-option :value="currTask.id">{{ currTask.taskName }}</a-select-option>
|
||||
</a-select>
|
||||
</div>
|
||||
<a-card>
|
||||
<a-steps progressDot :current="stepIndex" style="padding: 10px" size="default">
|
||||
<template v-if="resultObj.bpmLogListCount > 3">
|
||||
<a-step>
|
||||
<template #title>
|
||||
<div class="task-title">...</div>
|
||||
</template>
|
||||
</a-step>
|
||||
</template>
|
||||
<template v-for="(item, index) in resultObj.bpmLogStepList" :key="index">
|
||||
<a-step>
|
||||
<template #title>
|
||||
<div class="task-title">{{ item.taskName }}</div>
|
||||
</template>
|
||||
<template #description>
|
||||
<div class="task-date">
|
||||
<span><JEllipsis :value="'处理时间:' + item.opTime"></JEllipsis></span>
|
||||
</div>
|
||||
<div class="task-user">操作人:{{ item.opUserName }}</div>
|
||||
</template>
|
||||
</a-step>
|
||||
</template>
|
||||
<a-step v-if="resultObj.taskName && resultObj.taskName != ''">
|
||||
<template #title>
|
||||
<div class="task-title">{{ resultObj.taskName }}</div>
|
||||
</template>
|
||||
<template #description>
|
||||
<div class="task-date">
|
||||
<span style="color: #ff6d75"><JEllipsis :value="'处理时间:' + resultObj.taskNameStartTime"></JEllipsis></span
|
||||
></div>
|
||||
<div class="task-user">操作人:{{ resultObj.taskAssigneeName }}</div>
|
||||
</template>
|
||||
</a-step>
|
||||
<a-step>
|
||||
<template #title>
|
||||
<div class="task-title">...</div>
|
||||
</template>
|
||||
</a-step>
|
||||
</a-steps>
|
||||
</a-card>
|
||||
<!-- 意见 -->
|
||||
<a-card title="意见信息" :bodyStyle="{ padding: '0 20px' }" size="default" style="margin-top: 20px">
|
||||
<a-list itemLayout="vertical">
|
||||
<template v-for="(item, index) in resultObj.bpmLogList" :key="index">
|
||||
<a-list-item>
|
||||
<a-list-item-meta :description="item.remarks || '无意见信息'">
|
||||
<template #title>
|
||||
<a
|
||||
><p>{{ item.opUserName }}</p
|
||||
><span style="color: #ff6d75">[{{ item.taskName }}]</span> {{ item.opTime }}</a
|
||||
>
|
||||
</template>
|
||||
<template #avatar>
|
||||
<a-avatar :size="36" style="background-color: #51cbff">
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
</template>
|
||||
</a-list-item-meta>
|
||||
<template v-for="(file, index) in item.bpmFiles" :key="index">
|
||||
<div class="ant-upload-list ant-upload-list-text">
|
||||
<div class="ant-upload-list-item ant-upload-list-item-done">
|
||||
<div class="ant-upload-list-item-info">
|
||||
<span>
|
||||
<PaperClipOutlined />
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
:title="file.fileName"
|
||||
:href="getFileAccessHttpUrl(file.filePath)"
|
||||
class="ant-upload-list-item-name"
|
||||
>{{ file.fileName }}</a
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-list-item>
|
||||
</template>
|
||||
<a-list-item>
|
||||
<div style="width: 100%">
|
||||
<div style="margin-bottom: 5px">
|
||||
处理意见:
|
||||
<a-select style="width: 300px" placeholder="常用审批语" @change="handleChangeSelect">
|
||||
<template #suffixIcon>
|
||||
<Icon icon="ant-design:smile-outlined" />
|
||||
</template>
|
||||
<a-select-option v-for="(item, key) in remarksDictOptions" :key="key" :value="item.value">{{ item.text }}</a-select-option>
|
||||
</a-select>
|
||||
</div>
|
||||
<a-textarea rows="3" v-model:value="model.reason" />
|
||||
</div>
|
||||
</a-list-item>
|
||||
<a-list-item>
|
||||
<JUpload v-model:value="fileList" :returnUrl="false" :maxCount="10"></JUpload>
|
||||
</a-list-item>
|
||||
<a-list-item v-show="false">
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<a-radio-group v-model:value="model.processModel">
|
||||
<a-radio :checked="true" :value="1">单分支模式</a-radio>
|
||||
<a-radio :value="2">多分支模式</a-radio>
|
||||
<a-radio :value="3" v-if="resultObj.histListSize > 0">驳回</a-radio>
|
||||
</a-radio-group>
|
||||
<span :hidden="model.processModel !== 2">
|
||||
<span style="color: red">多分支模式默认执行所有分支:</span>
|
||||
<template v-for="(item, index) in resultObj.transitionList" :key="index">
|
||||
<a-checkbox :checked="true" :value="item.nextnode">{{ item.Transition }}</a-checkbox>
|
||||
</template>
|
||||
</span>
|
||||
<!-- 选择要驳回的节点 -->
|
||||
<span :hidden="model.processModel !== 3" v-if="resultObj.histListSize > 0">
|
||||
<a-select v-model:value="model.rejectModelNode" style="width: 150px">
|
||||
<template v-for="(item, index) in resultObj.histListNode" :key="index">
|
||||
<a-select-option :value="item.TASK_DEF_KEY_">{{ item.NAME_ }}</a-select-option>
|
||||
</template>
|
||||
</a-select>
|
||||
</span>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-list-item>
|
||||
<!--选择下一步处理/抄送人-->
|
||||
<a-list-item>
|
||||
<a-checkbox :checked="checkedNext" @change="handleCheckedNextChange">指定下一步操作人(指定下一步会签人员)</a-checkbox>
|
||||
<a-checkbox :checked="checkedCc" @change="handleCheckedCcChange">是否抄送</a-checkbox>
|
||||
</a-list-item>
|
||||
<a-list-item style="line-height: 32px" :hidden="!checkedNext">
|
||||
<span>指定下一步操作人(指定下一步会签人员):</span>
|
||||
<a-select style="width: 300px" mode="multiple" placeholder="点击选择按钮" :value="hqUserList"></a-select>
|
||||
<a-button type="primary" @click="handleHqUserSelect" preIcon="ant-design:search-outlined" style="margin-left: 8px">选择</a-button>
|
||||
<a-button type="primary" @click="hqUserSelectReset" preIcon="ant-design:reload-outlined" style="margin-left: 8px">清空</a-button>
|
||||
<span>(如果不指定则按照系统默认)</span>
|
||||
</a-list-item>
|
||||
<a-list-item style="line-height: 32px" :hidden="!checkedCc">
|
||||
<span>抄送给:</span>
|
||||
<a-select style="width: 300px" mode="multiple" placeholder="点击选择按钮" :value="ccUserList"></a-select>
|
||||
<a-button type="primary" @click="handleCcUserSelect" preIcon="ant-design:search-outlined" style="margin-left: 8px">选择</a-button>
|
||||
<a-button type="primary" @click="ccUserSelectReset" preIcon="ant-design:reload-outlined" style="margin-left: 8px">清空</a-button>
|
||||
</a-list-item>
|
||||
</a-list>
|
||||
<!-- 流转按钮 -->
|
||||
<div style="margin-top: 20px; text-align: center">
|
||||
<template v-if="model.processModel == 1">
|
||||
<template v-for="(item, index) in resultObj.transitionList">
|
||||
<a-button type="primary" @click="handleProcessComplete(item.nextnode)">{{ item.Transition }}</a-button>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<a-button type="primary" @click="handleManyProcessComplete()">确认提交</a-button>
|
||||
</template>
|
||||
</div>
|
||||
<br />
|
||||
</a-card>
|
||||
<BizSelectUserModal ref="selectHqUserModal" @selectFinished="selectHqUserOK"></BizSelectUserModal>
|
||||
<BizSelectUserModal ref="selectCcUserModal" @selectFinished="selectCcUserOK"></BizSelectUserModal>
|
||||
</a-spin>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { ref, toRefs, onMounted, computed, defineComponent, reactive } from 'vue';
|
||||
import JEllipsis from '/src/components/Form/src/jeecg/components/JEllipsis.vue';
|
||||
import BizSelectUserModal from './BizSelectUserModal.vue';
|
||||
import { JUpload } from '/src/components/Form/src/jeecg/components/JUpload';
|
||||
import { getFileAccessHttpUrl } from '/src/utils/common/compUtils';
|
||||
import { UserOutlined, PaperClipOutlined } from '@ant-design/icons-vue';
|
||||
import { initDictOptions } from '/src/utils/dict';
|
||||
import { getProcessTaskTransInfo, processComplete } from '/src/views/super/bpm/process/manage/components/bpm.api.ts';
|
||||
import { getToken } from '/src/utils/auth';
|
||||
import { useMessage } from '/src/hooks/web/useMessage';
|
||||
import { isString } from "@/utils/is";
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
formData: { type: Object },
|
||||
},
|
||||
components: { UserOutlined, PaperClipOutlined, JEllipsis, JUpload, BizSelectUserModal },
|
||||
emits: ['complete'],
|
||||
setup(props, { emit }) {
|
||||
const { createMessage, createConfirm } = useMessage();
|
||||
//选择用户弹窗dom
|
||||
const selectHqUserModal = ref(null);
|
||||
const selectCcUserModal = ref(null);
|
||||
//数据
|
||||
const _this = reactive({
|
||||
headers: {},
|
||||
resultObj: {},
|
||||
checkedNext: false,
|
||||
transition: [],
|
||||
hqUserSelectList: [],
|
||||
ccUserSelectList: [],
|
||||
remarksDictOptions: [],
|
||||
currTask: {},
|
||||
model: {
|
||||
taskId: '',
|
||||
nextnode: '',
|
||||
nextCodeCount: '',
|
||||
reason: '',
|
||||
processModel: 1,
|
||||
rejectModelNode: '',
|
||||
nextUserName: '',
|
||||
nextUserId: '',
|
||||
ccUserIds: '',
|
||||
ccUserRealNames: '',
|
||||
fileList: '',
|
||||
},
|
||||
bodyStyle: {
|
||||
padding: '10px',
|
||||
},
|
||||
checkedCc: false,
|
||||
fileList: [],
|
||||
loading: false,
|
||||
});
|
||||
//步骤点
|
||||
const stepIndex = computed(() => {
|
||||
if (_this.resultObj.bpmLogListCount > 3) {
|
||||
return _this.resultObj.bpmLogStepListCount + 1;
|
||||
}
|
||||
return _this.resultObj.bpmLogStepListCount;
|
||||
});
|
||||
//下一步用户
|
||||
const hqUserList = computed(() => {
|
||||
let names = [];
|
||||
let ids = [];
|
||||
for (let a = 0; a < _this.hqUserSelectList.length; a++) {
|
||||
names.push(_this.hqUserSelectList[a].realname);
|
||||
ids.push(_this.hqUserSelectList[a].username);
|
||||
}
|
||||
_this.model.nextUserId = ids.join(',');
|
||||
_this.model.nextUserName = names.join(',');
|
||||
return names;
|
||||
});
|
||||
//抄送用户
|
||||
const ccUserList = computed(() => {
|
||||
let names = [];
|
||||
let ids = [];
|
||||
for (let a = 0; a < _this.ccUserSelectList.length; a++) {
|
||||
names.push(_this.ccUserSelectList[a].realname);
|
||||
ids.push(_this.ccUserSelectList[a].username);
|
||||
}
|
||||
_this.model.ccUserIds = ids.join(',');
|
||||
_this.model.ccUserRealNames = names.join(',');
|
||||
return names;
|
||||
});
|
||||
//下拉选择处理意见
|
||||
function handleChangeSelect(value) {
|
||||
_this.model.reason = value;
|
||||
}
|
||||
//初始化字典值
|
||||
async function initDictConfig() {
|
||||
let res = await initDictOptions('approval_remarks');
|
||||
_this.remarksDictOptions = res && res.length > 0 ? res : [];
|
||||
}
|
||||
//是否指定下一步操作人
|
||||
function handleCheckedNextChange(e) {
|
||||
_this.checkedNext = e.target.checked;
|
||||
hqUserSelectReset();
|
||||
}
|
||||
//是否指定抄送
|
||||
function handleCheckedCcChange(e) {
|
||||
_this.checkedCc = e.target.checked;
|
||||
ccUserSelectReset();
|
||||
}
|
||||
//办理流程
|
||||
function handleProcessComplete(nextnode?) {
|
||||
if (!_this.model.reason || _this.model.reason.length == 0) {
|
||||
//update-begin-author:taoyan date:2022-9-5 for: VUEN-2157 2. 意见允许为空
|
||||
//createMessage.warning('请填写处理意见');
|
||||
//return;
|
||||
//update-end-author:taoyan date:2022-9-5 for: VUEN-2157 2. 意见允许为空
|
||||
}
|
||||
if (nextnode) {
|
||||
_this.model.nextnode = nextnode;
|
||||
}
|
||||
console.log('流程办理数据:_this:------>', _this);
|
||||
createConfirm({
|
||||
title: '提示',
|
||||
content: '确认提交审批吗?',
|
||||
centered: false,
|
||||
onOk: async () => {
|
||||
_this.loading = true;
|
||||
console.log('_this.fileList------->>', _this.fileList);
|
||||
_this.model.fileList = isString(_this.fileList) ? _this.fileList : JSON.stringify(_this.fileList);
|
||||
let res = await processComplete(_this.model);
|
||||
_this.loading = false;
|
||||
if (res.success) {
|
||||
createMessage.success(res.message);
|
||||
emit('complete');
|
||||
} else {
|
||||
createMessage.warning(res.message);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
//发送流程
|
||||
function handleManyProcessComplete() {
|
||||
if (_this.model.processModel == 3) {
|
||||
if (!_this.model.rejectModelNode || _this.model.rejectModelNode.length == 0) {
|
||||
createMessage.warning('请选择驳回节点');
|
||||
return;
|
||||
}
|
||||
}
|
||||
handleProcessComplete();
|
||||
}
|
||||
//选择下一步操作人
|
||||
function handleHqUserSelect() {
|
||||
selectHqUserModal.value.add();
|
||||
}
|
||||
//选择下一步操作人回调
|
||||
function selectHqUserOK(data) {
|
||||
_this.hqUserSelectList = data;
|
||||
}
|
||||
//下一步操作人清除
|
||||
function hqUserSelectReset() {
|
||||
_this.hqUserSelectList = [];
|
||||
}
|
||||
//选择抄送人员
|
||||
function handleCcUserSelect() {
|
||||
selectCcUserModal.value.add();
|
||||
}
|
||||
//选择抄送人员回调
|
||||
function selectCcUserOK(data) {
|
||||
_this.ccUserSelectList = data;
|
||||
}
|
||||
//抄送人员清除
|
||||
function ccUserSelectReset() {
|
||||
_this.ccUserSelectList = [];
|
||||
}
|
||||
/**
|
||||
* 加载数据
|
||||
* @param formData
|
||||
*/
|
||||
async function loadData(formData) {
|
||||
let params = { taskId: formData.taskId }; //查询条件
|
||||
_this.loading = true;
|
||||
const res = await getProcessTaskTransInfo(params);
|
||||
_this.loading = false;
|
||||
if (res.success) {
|
||||
_this.resultObj = res.result;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const token = getToken();
|
||||
_this.headers = { 'X-Access-Token': token };
|
||||
console.log('任务办理组件数据:', props.formData);
|
||||
_this.currTask = props.formData.bizTaskList[0];
|
||||
_this.model.taskId = _this.currTask.id;
|
||||
loadData(props.formData);
|
||||
initDictConfig();
|
||||
});
|
||||
|
||||
return {
|
||||
handleChangeSelect,
|
||||
handleCheckedNextChange,
|
||||
handleCheckedCcChange,
|
||||
handleProcessComplete,
|
||||
handleManyProcessComplete,
|
||||
getFileAccessHttpUrl,
|
||||
handleCcUserSelect,
|
||||
ccUserSelectReset,
|
||||
handleHqUserSelect,
|
||||
hqUserSelectReset,
|
||||
selectHqUserOK,
|
||||
selectCcUserOK,
|
||||
stepIndex,
|
||||
hqUserList,
|
||||
ccUserList,
|
||||
selectHqUserModal,
|
||||
selectCcUserModal,
|
||||
...toRefs(_this),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.task-info {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.task-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.task-date {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ant-steps-item-description {
|
||||
max-width: 200px !important;
|
||||
}
|
||||
|
||||
/** Button按钮间距 */
|
||||
.ant-btn {
|
||||
margin-left: 3px;
|
||||
}
|
||||
/** 标题和描述对齐 */
|
||||
:deep(.ant-steps-item-content) {
|
||||
text-align: left;
|
||||
margin-left: 50px;
|
||||
}
|
||||
/** 描述的样式 */
|
||||
.descriptionDiv {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
align-items: center;
|
||||
margin-top: 5px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<!--催办form-->
|
||||
<div style="padding: 24px">
|
||||
<a-form ref="formRef" :rules="rules" :model="formState" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||
<a-form-item label="催办类型">
|
||||
<a-checkbox-group v-model:value="formState.notifyType">
|
||||
<a-checkbox value="1" name="type">页面通知</a-checkbox>
|
||||
<a-checkbox value="2" name="type">邮件</a-checkbox>
|
||||
</a-checkbox-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="催办内容" name="remarks">
|
||||
<a-textarea rows="3" v-model:value="formState.remarks" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<div style="text-align: center; margin-top: 10px">
|
||||
<a-button type="primary" :loading="loading" @click="handleOk()">保存</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, unref, reactive, toRaw } from 'vue';
|
||||
import { saveOrUpdateNotify } from '/src/views/super/bpm/process/manage/components/bpm.api.ts';
|
||||
import { propTypes } from '/src/utils/propTypes';
|
||||
import { ValidateErrorEntity } from 'ant-design-vue/es/form/interface';
|
||||
//props声明
|
||||
const props = defineProps({
|
||||
procInstId: propTypes.string.def(''),
|
||||
});
|
||||
// Emits声明
|
||||
const emit = defineEmits(['success']);
|
||||
const loading = ref(false);
|
||||
const formRef = ref();
|
||||
const formState = reactive({
|
||||
notifyType: '1,2',
|
||||
remarks: '',
|
||||
procInstId: props.procInstId,
|
||||
});
|
||||
const labelCol = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 5 },
|
||||
};
|
||||
const wrapperCol = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 16 },
|
||||
};
|
||||
const rules = {
|
||||
remarks: [{ required: true, message: '催办内容不允许为空!' }],
|
||||
};
|
||||
/**
|
||||
* 初始化表单数据
|
||||
*/
|
||||
function initFormData() {
|
||||
formState.notifyType = '1,2';
|
||||
formState.procInstId = props.procInstId;
|
||||
}
|
||||
|
||||
//表单提交事件
|
||||
function handleOk() {
|
||||
let values = toRaw(unref(formState));
|
||||
formRef.value
|
||||
.validate()
|
||||
.then(async () => {
|
||||
loading.value = true;
|
||||
values.notifyType = Array.isArray(values.notifyType) ? values.notifyType.join(',') : values.notifyType;
|
||||
//提交表单
|
||||
await saveOrUpdateNotify(values);
|
||||
loading.value = false;
|
||||
//刷新列表
|
||||
emit('success');
|
||||
})
|
||||
.catch((error: ValidateErrorEntity<any>) => {
|
||||
console.log('error', error);
|
||||
});
|
||||
}
|
||||
|
||||
initFormData();
|
||||
</script>
|
||||
@@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<BasicTable @register="registerTable" :rowSelection="rowSelection"> </BasicTable>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { BasicTable } from '/src/components/Table';
|
||||
import { getNotifyMeList } from '/src/views/super/bpm/process/manage/components/bpm.api.ts';
|
||||
import { useListPage } from '/src/hooks/system/useListPage';
|
||||
import { propTypes } from '/src/utils/propTypes';
|
||||
|
||||
const props = defineProps({
|
||||
procInstId: propTypes.string.def(''),
|
||||
});
|
||||
// 列表页面公共参数、方法
|
||||
const { prefixCls, tableContext } = useListPage({
|
||||
tableProps: {
|
||||
api: getNotifyMeList,
|
||||
columns: [
|
||||
{
|
||||
title: '流程名称',
|
||||
align: 'center',
|
||||
dataIndex: 'procName',
|
||||
},
|
||||
{
|
||||
title: '任务名称',
|
||||
align: 'center',
|
||||
dataIndex: 'taskName',
|
||||
},
|
||||
{
|
||||
title: '任务处理人',
|
||||
align: 'center',
|
||||
dataIndex: 'taskAssignee',
|
||||
},
|
||||
{
|
||||
title: '催办时间',
|
||||
align: 'center',
|
||||
dataIndex: 'opTime',
|
||||
},
|
||||
{
|
||||
title: '催办类型',
|
||||
align: 'center',
|
||||
dataIndex: 'notifyType',
|
||||
customRender: ({ text }) => {
|
||||
var srtArr = text.split(',');
|
||||
var value = '';
|
||||
if (srtArr.includes('1')) {
|
||||
value += ',系统通知';
|
||||
}
|
||||
if (srtArr.includes('2')) {
|
||||
value += ',邮件';
|
||||
}
|
||||
return value.substring(1);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '催办说明',
|
||||
align: 'center',
|
||||
dataIndex: 'remarks',
|
||||
},
|
||||
],
|
||||
size: 'middle',
|
||||
maxHeight: 200,
|
||||
useSearchForm: false,
|
||||
showTableSetting: false,
|
||||
showActionColumn: false,
|
||||
searchInfo: { procInstId: props.procInstId },
|
||||
},
|
||||
});
|
||||
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||
</script>
|
||||
@@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<!-- 审催办弹出框 -->
|
||||
<a-modal width="60%" style="top: 20px" destroyOnClose :title="data.title" v-model:open="data.visible" :footer="null" @cancel="handleModalCancel">
|
||||
<a-tabs defaultActiveKey="1">
|
||||
<a-tab-pane key="1">
|
||||
<template #tab>
|
||||
<Icon icon="ant-design:user-outlined" />
|
||||
<span>提醒我的</span>
|
||||
</template>
|
||||
<BizTaskNotifyMeList :procInstId="procInstId"></BizTaskNotifyMeList>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, unref, reactive } from 'vue';
|
||||
import BizTaskNotifyMeList from './BizTaskNotifyMeList.vue';
|
||||
|
||||
//数据
|
||||
const data = reactive({
|
||||
loading: false,
|
||||
title: '催办',
|
||||
visible: false,
|
||||
});
|
||||
|
||||
const procInstId = ref('');
|
||||
/**
|
||||
* 关闭弹窗
|
||||
*/
|
||||
function handleModalCancel() {
|
||||
data.visible = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 催办
|
||||
* @param record
|
||||
*/
|
||||
async function notify(id) {
|
||||
procInstId.value = id;
|
||||
data.visible = true;
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
notify,
|
||||
data,
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<!-- 催办弹出框 -->
|
||||
<a-modal width="60%" style="top: 20px" destroyOnClose :title="data.title" v-model:open="data.visible" :footer="null" @cancel="handleModalCancel">
|
||||
<a-tabs defaultActiveKey="1">
|
||||
<a-tab-pane key="1">
|
||||
<template #tab>
|
||||
<Icon icon="ant-design:file-text-outlined" />
|
||||
<span>催办</span>
|
||||
</template>
|
||||
<BizTaskNotifyForm :procInstId="procInstId" @success="handleModalCancel"></BizTaskNotifyForm>
|
||||
</a-tab-pane>
|
||||
|
||||
<a-tab-pane key="2">
|
||||
<template #tab>
|
||||
<Icon icon="ant-design:user-outlined" />
|
||||
<span>我提醒的</span>
|
||||
</template>
|
||||
<MyBizTaskNotifyList :procInstId="procInstId"></MyBizTaskNotifyList>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, unref, reactive } from 'vue';
|
||||
import { createAsyncComponent } from '/src/utils/factory/createAsyncComponent';
|
||||
import MyBizTaskNotifyList from './MyBizTaskNotifyList.vue';
|
||||
|
||||
const BizTaskNotifyForm = createAsyncComponent(() => import('./BizTaskNotifyForm.vue'), { loading: true });
|
||||
//数据
|
||||
const data = reactive({
|
||||
loading: false,
|
||||
title: '催办',
|
||||
visible: false,
|
||||
});
|
||||
|
||||
const procInstId = ref('');
|
||||
/**
|
||||
* 关闭弹窗
|
||||
*/
|
||||
function handleModalCancel() {
|
||||
data.visible = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 催办
|
||||
* @param record
|
||||
*/
|
||||
async function notify(id) {
|
||||
procInstId.value = id;
|
||||
data.visible = true;
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
notify,
|
||||
data,
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,403 @@
|
||||
<template>
|
||||
<!--驳回的任务办理-->
|
||||
<div style="background: #fff; margin-right: 10px">
|
||||
<!-- 步骤条 -->
|
||||
<a-spin :spinning="loading">
|
||||
<div class="ant-alert ant-alert-info" style="margin-bottom: 16px">
|
||||
当前任务办理环节:
|
||||
<a-select style="width: 300px" v-model:value="currTask.id">
|
||||
<a-select-option :value="currTask.id">{{ currTask.taskName }}</a-select-option>
|
||||
</a-select>
|
||||
<span :hidden="model.processModel !== 3" v-if="resultObj.histListSize > 0">
|
||||
驳回到:
|
||||
<a-select v-model:value="model.rejectModelNode" style="width: 200px">
|
||||
<template v-for="(item, index) in resultObj.histListNode" :key="index">
|
||||
<a-select-option :value="item.TASK_DEF_KEY_">{{ item.NAME_ }}</a-select-option>
|
||||
</template>
|
||||
</a-select>
|
||||
</span>
|
||||
</div>
|
||||
<a-card>
|
||||
<a-steps progressDot :current="stepIndex" style="padding: 10px" size="default">
|
||||
<template v-if="resultObj.bpmLogListCount > 3">
|
||||
<a-step>
|
||||
<template #title>
|
||||
<div class="task-title">...</div>
|
||||
</template>
|
||||
</a-step>
|
||||
</template>
|
||||
<template v-for="(item, index) in resultObj.bpmLogStepList" :key="index">
|
||||
<a-step>
|
||||
<template #title>
|
||||
<div class="task-title">{{ item.taskName }}</div>
|
||||
</template>
|
||||
<template #description>
|
||||
<div class="task-date">
|
||||
<span><JEllipsis :value="'处理时间:' + item.opTime"></JEllipsis></span>
|
||||
</div>
|
||||
<div class="task-user">操作人:{{ item.opUserName }}</div>
|
||||
</template>
|
||||
</a-step>
|
||||
</template>
|
||||
<a-step v-if="resultObj.taskName && resultObj.taskName != ''">
|
||||
<template #title>
|
||||
<div class="task-title">{{ resultObj.taskName }}</div>
|
||||
</template>
|
||||
<template #description>
|
||||
<div class="task-date">
|
||||
<span style="color: #ff6d75"><JEllipsis :value="'处理时间:' + resultObj.taskNameStartTime"></JEllipsis></span
|
||||
></div>
|
||||
<div class="task-user">操作人:{{ resultObj.taskAssigneeName }}</div>
|
||||
</template>
|
||||
</a-step>
|
||||
<a-step>
|
||||
<template #title>
|
||||
<div class="task-title">...</div>
|
||||
</template>
|
||||
</a-step>
|
||||
</a-steps>
|
||||
</a-card>
|
||||
<!-- 意见 -->
|
||||
<a-card title="意见信息" :bodyStyle="{ padding: '0 20px' }" size="default" style="margin-top: 20px">
|
||||
<a-list itemLayout="vertical">
|
||||
<template v-for="(item, index) in resultObj.bpmLogList" :key="index">
|
||||
<a-list-item>
|
||||
<a-list-item-meta :description="item.remarks||'无意见信息'">
|
||||
<template #title>
|
||||
<a
|
||||
><p>{{ item.opUserName }}</p
|
||||
><span style="color: #ff6d75">[{{ item.taskName }}]</span> {{ item.opTime }}</a
|
||||
>
|
||||
</template>
|
||||
<template #avatar>
|
||||
<a-avatar :size="36" style="background-color: #51cbff">
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
</template>
|
||||
</a-list-item-meta>
|
||||
<template v-for="(file, index) in item.bpmFiles" :key="index">
|
||||
<div class="ant-upload-list ant-upload-list-text">
|
||||
<div class="ant-upload-list-item ant-upload-list-item-done">
|
||||
<div class="ant-upload-list-item-info">
|
||||
<span>
|
||||
<PaperClipOutlined />
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
:title="file.fileName"
|
||||
:href="getFileAccessHttpUrl(file.filePath)"
|
||||
class="ant-upload-list-item-name"
|
||||
>{{ file.fileName }}</a
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-list-item>
|
||||
</template>
|
||||
<a-list-item>
|
||||
<div style="width: 100%">
|
||||
<div style="margin-bottom: 5px">
|
||||
处理意见:
|
||||
<a-select style="width: 300px" placeholder="常用审批语" @change="handleChangeSelect">
|
||||
<template #suffixIcon>
|
||||
<Icon icon="ant-design:smile-outlined" />
|
||||
</template>
|
||||
<a-select-option v-for="(item, key) in remarksDictOptions" :key="key" :value="item.value">{{ item.text }}</a-select-option>
|
||||
</a-select>
|
||||
</div>
|
||||
<a-textarea rows="3" v-model:value="model.reason" />
|
||||
</div>
|
||||
</a-list-item>
|
||||
<a-list-item>
|
||||
<JUpload v-model:value="fileList" :returnUrl="false"></JUpload>
|
||||
</a-list-item>
|
||||
<!--选择下一步处理/抄送人-->
|
||||
<a-list-item v-show="false">
|
||||
<a-checkbox :checked="checkedNext" @change="handleCheckedNextChange">指定下一步操作人(指定下一步会签人员)</a-checkbox>
|
||||
<a-checkbox :checked="checkedCc" @change="handleCheckedCcChange">是否抄送</a-checkbox>
|
||||
</a-list-item>
|
||||
<a-list-item style="line-height: 32px" :hidden="!checkedNext">
|
||||
<span>指定下一步操作人(指定下一步会签人员):</span>
|
||||
<a-select style="width: 300px" mode="multiple" placeholder="点击选择按钮" :value="hqUserList"></a-select>
|
||||
<a-button type="primary" @click="handleHqUserSelect" preIcon="ant-design:search-outlined" style="margin-left: 8px">选择</a-button>
|
||||
<a-button type="primary" @click="hqUserSelectReset" preIcon="ant-design:reload-outlined" style="margin-left: 8px">清空</a-button>
|
||||
<span>(如果不指定则按照系统默认)</span>
|
||||
</a-list-item>
|
||||
<a-list-item style="line-height: 32px" :hidden="!checkedCc">
|
||||
<span>抄送给:</span>
|
||||
<a-select style="width: 300px" mode="multiple" placeholder="点击选择按钮" :value="ccUserList"></a-select>
|
||||
<a-button type="primary" @click="handleCcUserSelect" preIcon="ant-design:search-outlined" style="margin-left: 8px">选择</a-button>
|
||||
<a-button type="primary" @click="ccUserSelectReset" preIcon="ant-design:reload-outlined" style="margin-left: 8px">清空</a-button>
|
||||
</a-list-item>
|
||||
</a-list>
|
||||
<!-- 流转按钮 -->
|
||||
<div v-if="resultObj.histListSize > 0" style="margin-top: 20px; text-align: center">
|
||||
<template v-if="model.processModel == 1">
|
||||
<template v-for="(item, index) in resultObj.transitionList">
|
||||
<a-button type="primary" @click="handleProcessComplete(item.nextnode)">{{ item.Transition }}</a-button>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<a-button type="primary" @click="handleManyProcessComplete()">确认提交</a-button>
|
||||
</template>
|
||||
</div>
|
||||
<div v-else style="margin-top: 20px; text-align: center">
|
||||
<div class="ant-alert ant-alert-info" style="margin-bottom: 16px"> 暂无可驳回的任务 </div>
|
||||
</div>
|
||||
<br />
|
||||
</a-card>
|
||||
<BizSelectUserModal ref="selectHqUserModal" @selectFinished="selectHqUserOK"></BizSelectUserModal>
|
||||
<BizSelectUserModal ref="selectCcUserModal" @selectFinished="selectCcUserOK"></BizSelectUserModal>
|
||||
</a-spin>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { ref, toRefs, onMounted, computed, defineComponent, reactive } from 'vue';
|
||||
import JEllipsis from '/src/components/Form/src/jeecg/components/JEllipsis.vue';
|
||||
import BizSelectUserModal from './BizSelectUserModal.vue';
|
||||
import { JUpload } from '/src/components/Form/src/jeecg/components/JUpload';
|
||||
import { getFileAccessHttpUrl } from '/src/utils/common/compUtils';
|
||||
import { UserOutlined, PaperClipOutlined } from '@ant-design/icons-vue';
|
||||
import { initDictOptions } from '/src/utils/dict';
|
||||
import { getProcessTaskTransInfo, processComplete } from '/src/views/super/bpm/process/manage/components/bpm.api.ts';
|
||||
import { getToken } from '/src/utils/auth';
|
||||
import { useMessage } from '/src/hooks/web/useMessage';
|
||||
import {isString} from "@/utils/is";
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
formData: { type: Object },
|
||||
},
|
||||
components: { UserOutlined, PaperClipOutlined, JEllipsis, JUpload, BizSelectUserModal },
|
||||
emits: ['complete'],
|
||||
setup(props, { emit }) {
|
||||
const { createMessage, createConfirm } = useMessage();
|
||||
const selectHqUserModal = ref(null);
|
||||
const selectCcUserModal = ref(null);
|
||||
const _this = reactive({
|
||||
headers: {},
|
||||
resultObj: {},
|
||||
checkedNext: false,
|
||||
transition: [],
|
||||
hqUserSelectList: [],
|
||||
ccUserSelectList: [],
|
||||
remarksDictOptions: [],
|
||||
currTask: {},
|
||||
model: {
|
||||
taskId: '',
|
||||
nextnode: '',
|
||||
nextCodeCount: '',
|
||||
reason: '',
|
||||
processModel: 3,
|
||||
rejectModelNode: '',
|
||||
nextUserName: '',
|
||||
nextUserId: '',
|
||||
ccUserIds: '',
|
||||
ccUserRealNames: '',
|
||||
fileList: '',
|
||||
},
|
||||
bodyStyle: {
|
||||
padding: '10px',
|
||||
},
|
||||
checkedCc: false,
|
||||
fileList: [],
|
||||
loading: false,
|
||||
});
|
||||
//步骤点
|
||||
const stepIndex = computed(() => {
|
||||
if (_this.resultObj.bpmLogListCount > 3) {
|
||||
return _this.resultObj.bpmLogStepListCount + 1;
|
||||
}
|
||||
return _this.resultObj.bpmLogStepListCount;
|
||||
});
|
||||
const hqUserList = computed(() => {
|
||||
let names = [];
|
||||
let ids = [];
|
||||
for (let a = 0; a < _this.hqUserSelectList.length; a++) {
|
||||
names.push(_this.hqUserSelectList[a].realname);
|
||||
ids.push(_this.hqUserSelectList[a].username);
|
||||
}
|
||||
_this.model.nextUserId = ids.join(',');
|
||||
_this.model.nextUserName = names.join(',');
|
||||
return names;
|
||||
});
|
||||
const ccUserList = computed(() => {
|
||||
let names = [];
|
||||
let ids = [];
|
||||
for (let a = 0; a < _this.ccUserSelectList.length; a++) {
|
||||
names.push(_this.ccUserSelectList[a].realname);
|
||||
ids.push(_this.ccUserSelectList[a].username);
|
||||
}
|
||||
_this.model.ccUserIds = ids.join(',');
|
||||
_this.model.ccUserRealNames = names.join(',');
|
||||
return names;
|
||||
});
|
||||
function handleChangeSelect(value) {
|
||||
_this.model.reason = value;
|
||||
}
|
||||
function handleChangeSelect(value) {
|
||||
_this.model.reason = value;
|
||||
}
|
||||
|
||||
async function initDictConfig() {
|
||||
let res = await initDictOptions('approval_remarks');
|
||||
_this.remarksDictOptions = res && res.length > 0 ? res : [];
|
||||
}
|
||||
function handleCheckedNextChange(e) {
|
||||
_this.checkedNext = e.target.checked;
|
||||
hqUserSelectReset();
|
||||
}
|
||||
function handleCheckedCcChange(e) {
|
||||
_this.checkedCc = e.target.checked;
|
||||
ccUserSelectReset();
|
||||
}
|
||||
function handleProcessComplete(nextnode?) {
|
||||
if (!_this.model.reason || _this.model.reason.length == 0) {
|
||||
createMessage.warning('请填写处理意见');
|
||||
return;
|
||||
}
|
||||
if (nextnode) {
|
||||
_this.model.nextnode = nextnode;
|
||||
}
|
||||
createConfirm({
|
||||
title: '提示',
|
||||
content: '确认驳回吗?',
|
||||
centered: false,
|
||||
onOk: async () => {
|
||||
_this.loading = true;
|
||||
_this.model.fileList = isString(_this.fileList) ? _this.fileList : JSON.stringify(_this.fileList);
|
||||
let res = await processComplete(_this.model);
|
||||
_this.loading = false;
|
||||
if (res.success) {
|
||||
createMessage.success(res.message);
|
||||
emit('complete');
|
||||
} else {
|
||||
createMessage.warning(res.message);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
function handleManyProcessComplete() {
|
||||
if (_this.model.processModel == 3) {
|
||||
if (!_this.model.rejectModelNode || _this.model.rejectModelNode.length == 0) {
|
||||
createMessage.warning('请选择驳回节点');
|
||||
return;
|
||||
}
|
||||
}
|
||||
handleProcessComplete();
|
||||
}
|
||||
function handleHqUserSelect() {
|
||||
selectHqUserModal.value.add();
|
||||
}
|
||||
function selectHqUserOK(data) {
|
||||
_this.hqUserSelectList = data;
|
||||
}
|
||||
function hqUserSelectReset() {
|
||||
_this.hqUserSelectList = [];
|
||||
}
|
||||
|
||||
function handleCcUserSelect() {
|
||||
selectCcUserModal.value.add();
|
||||
}
|
||||
function selectCcUserOK(data) {
|
||||
_this.ccUserSelectList = data;
|
||||
}
|
||||
function ccUserSelectReset() {
|
||||
_this.ccUserSelectList = [];
|
||||
}
|
||||
/**
|
||||
* 加载数据
|
||||
* @param formData
|
||||
*/
|
||||
async function loadData(formData) {
|
||||
let params = { taskId: formData.taskId }; //查询条件
|
||||
_this.loading = true;
|
||||
const res = await getProcessTaskTransInfo(params);
|
||||
_this.loading = false;
|
||||
if (res.success) {
|
||||
_this.resultObj = res.result;
|
||||
getDefaultRejectNode();
|
||||
}
|
||||
}
|
||||
function getDefaultRejectNode() {
|
||||
let taskDefKey = '';
|
||||
for (let item of _this.resultObj.histListNode) {
|
||||
if (item.TASK_DEF_KEY_ == _this.currTask.taskId) {
|
||||
break;
|
||||
}
|
||||
taskDefKey = item.TASK_DEF_KEY_;
|
||||
}
|
||||
_this.model.rejectModelNode = taskDefKey;
|
||||
}
|
||||
onMounted(() => {
|
||||
const token = getToken();
|
||||
_this.headers = { 'X-Access-Token': token };
|
||||
console.log('任务办理组件数据:', props.formData);
|
||||
_this.currTask = props.formData.bizTaskList[0];
|
||||
_this.model.taskId = _this.currTask.id;
|
||||
loadData(props.formData);
|
||||
initDictConfig();
|
||||
});
|
||||
|
||||
return {
|
||||
handleChangeSelect,
|
||||
handleCheckedNextChange,
|
||||
handleCheckedCcChange,
|
||||
handleProcessComplete,
|
||||
handleManyProcessComplete,
|
||||
getFileAccessHttpUrl,
|
||||
handleCcUserSelect,
|
||||
ccUserSelectReset,
|
||||
handleHqUserSelect,
|
||||
hqUserSelectReset,
|
||||
selectHqUserOK,
|
||||
selectCcUserOK,
|
||||
stepIndex,
|
||||
hqUserList,
|
||||
ccUserList,
|
||||
selectHqUserModal,
|
||||
selectCcUserModal,
|
||||
...toRefs(_this),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.task-info {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.task-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.task-date {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ant-steps-item-description {
|
||||
max-width: 200px !important;
|
||||
}
|
||||
|
||||
/** Button按钮间距 */
|
||||
.ant-btn {
|
||||
margin-left: 3px;
|
||||
}
|
||||
/** 标题和描述对齐 */
|
||||
:deep(.ant-steps-item-content) {
|
||||
text-align: left;
|
||||
margin-left: 50px;
|
||||
}
|
||||
/** 描述的样式 */
|
||||
.descriptionDiv {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
align-items: center;
|
||||
margin-top: 5px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,317 @@
|
||||
<template>
|
||||
<!-- 弹出框 -->
|
||||
<a-modal
|
||||
:open="visible"
|
||||
:title="title"
|
||||
width="80%"
|
||||
:bodyStyle="{ height: '80vh', overflow:'auto' }"
|
||||
style="top: 20px"
|
||||
:footer="null"
|
||||
destroyOnClose
|
||||
@cancel="handleModalCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<!--已选择单据-->
|
||||
<div style="width: 60%; margin: 0 auto">
|
||||
<a-divider orientation="left">已选择的单据</a-divider>
|
||||
<a-table
|
||||
ref="table"
|
||||
size="middle"
|
||||
bordered
|
||||
rowKey="dataId"
|
||||
:pagination="false"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource"
|
||||
:loading="loading"
|
||||
>
|
||||
</a-table>
|
||||
</div>
|
||||
<!--处理意见-->
|
||||
<div style="width: 60%; margin: 0 auto">
|
||||
<a-divider orientation="left">处理意见</a-divider>
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<a-list-item>
|
||||
<div style="width: 100%">
|
||||
<div style="margin-bottom: 5px">
|
||||
处理意见:
|
||||
<a-select style="width: 300px" placeholder="常用审批语" @change="handleChangeSelect">
|
||||
<template #suffixIcon>
|
||||
<Icon icon="ant-design:smile-outlined" />
|
||||
</template>
|
||||
<a-select-option v-for="(item, key) in remarksDictOptions" :key="key" :value="item.value">{{ item.text }}</a-select-option>
|
||||
</a-select>
|
||||
</div>
|
||||
<a-textarea rows="3" v-model:value="model.reason" />
|
||||
</div>
|
||||
</a-list-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<div style="text-align: center">
|
||||
<a-button type="primary" :disabled="disabledButton" @click="handleBatchComplete">确认提交</a-button>
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
<!--反馈结果-->
|
||||
<div style="width: 60%; margin: 0 auto" v-show="dealStatus">
|
||||
<a-divider orientation="left">处理结果</a-divider>
|
||||
<a-table
|
||||
ref="table"
|
||||
size="middle"
|
||||
bordered
|
||||
rowKey="dataId"
|
||||
:pagination="false"
|
||||
:columns="columns2"
|
||||
:dataSource="dataSource2"
|
||||
:loading="loading"
|
||||
>
|
||||
</a-table>
|
||||
</div>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, toRefs } from 'vue';
|
||||
import { initDictOptions } from '/src/utils/dict';
|
||||
import { getBizProcessNodeInfo, getProcessTaskTransInfo, processComplete } from '/src/views/super/bpm/process/manage/components/bpm.api';
|
||||
import { useMessage } from '/src/hooks/web/useMessage';
|
||||
export default defineComponent({
|
||||
props: ['paramData'],
|
||||
emits: ['ok'],
|
||||
setup(_, { emit }) {
|
||||
const { createMessage, createConfirm } = useMessage();
|
||||
|
||||
async function initDictConfig() {
|
||||
//初始化字典
|
||||
let res = await initDictOptions('approval_remarks');
|
||||
data.remarksDictOptions = res && res.length > 0 ? res : [];
|
||||
}
|
||||
|
||||
function handleChangeSelect(value) {
|
||||
data.model.reason = value;
|
||||
}
|
||||
|
||||
// 关闭模态框
|
||||
function handleModalCancel() {
|
||||
data.visible = false;
|
||||
}
|
||||
function deal(param) {
|
||||
data.dealStatus = false;
|
||||
data.model.reason = '';
|
||||
data.dataSource = [];
|
||||
data.dataSource2 = [];
|
||||
data.disabledButton = false;
|
||||
data.visible = true;
|
||||
initFlowData(param);
|
||||
}
|
||||
//加载流程信息
|
||||
async function initFlowData(param) {
|
||||
data.loading = true;
|
||||
for (let i = 0; i < param.length; i++) {
|
||||
let params = { flowCode: param[i].flowCode, dataId: param[i].dataId }; //查询条件
|
||||
let res = await getBizProcessNodeInfo(params);
|
||||
if (res.success) {
|
||||
let currTask = res.result.bizTaskList[0];
|
||||
let taskId = currTask.id;
|
||||
let taskName = currTask.taskName;
|
||||
param[i].taskClaimFlag = currTask.taskClaimFlag;
|
||||
param[i].taskName = taskName;
|
||||
param[i].taskId = taskId;
|
||||
let res2 = await getProcessTaskTransInfo({ taskId });
|
||||
if (res2.success) {
|
||||
if (res2.result.nextCodeCount == 1) {
|
||||
param[i].status = '-1'; //待处理
|
||||
param[i].nextnode = res2.result.transitionList[0].nextnode;
|
||||
continue;
|
||||
} else if (res2.result.nextCodeCount > 1) {
|
||||
param[i].msg = '多流转分支不能进行提交处理';
|
||||
}
|
||||
}
|
||||
}
|
||||
param[i].status = '0';
|
||||
}
|
||||
data.loading = false;
|
||||
data.dataSource = param;
|
||||
}
|
||||
//批量处理
|
||||
function handleBatchComplete() {
|
||||
if (!data.model.reason || data.model.reason.length == 0) {
|
||||
//update-begin-author:taoyan date:2022-9-5 for: VUEN-2157 2. 意见允许为空
|
||||
//createMessage.warning('请填写处理意见');
|
||||
//return;
|
||||
//update-end-author:taoyan date:2022-9-5 for: VUEN-2157 2. 意见允许为空
|
||||
}
|
||||
createConfirm({
|
||||
title: '确认提交',
|
||||
centered: false,
|
||||
content: '是否提交选中数据?',
|
||||
onOk: () => {
|
||||
handleProcessComplete();
|
||||
},
|
||||
});
|
||||
}
|
||||
//批量完成
|
||||
async function handleProcessComplete() {
|
||||
data.confirmLoading = true;
|
||||
data.disabledButton = true;
|
||||
for (var i = 0; i < data.dataSource.length; i++) {
|
||||
if (data.dataSource[i].taskClaimFlag) {
|
||||
//未签收,不做处理
|
||||
data.dataSource[i].msg = '未签收不能进行提交处理';
|
||||
data.dataSource[i].status = '0';
|
||||
continue;
|
||||
}
|
||||
if (data.dataSource[i].status == '-1') {
|
||||
let param = {
|
||||
taskId: data.dataSource[i].taskId,
|
||||
nextnode: data.dataSource[i].nextnode,
|
||||
nextCodeCount: '1',
|
||||
reason: data.model.reason,
|
||||
processModel: 1,
|
||||
rejectModelNode: '',
|
||||
nextUserName: '',
|
||||
nextUserId: '',
|
||||
ccUserIds: '',
|
||||
ccUserRealNames: '',
|
||||
fileList: '',
|
||||
};
|
||||
console.log('流程办理数据:', param);
|
||||
let res = await processComplete(param);
|
||||
if (res.success) {
|
||||
data.dataSource[i].status = '1';
|
||||
continue;
|
||||
}
|
||||
}
|
||||
data.dataSource[i].status = '0';
|
||||
}
|
||||
data.dealStatus = true;
|
||||
data.dataSource2 = data.dataSource;
|
||||
data.confirmLoading = false;
|
||||
emit('ok');
|
||||
}
|
||||
//初始化字典
|
||||
initDictConfig();
|
||||
//初始化数据
|
||||
const data = reactive({
|
||||
loading: false,
|
||||
title: '批量处理',
|
||||
visible: false,
|
||||
confirmLoading: false,
|
||||
currTask: {},
|
||||
dataSource: [],
|
||||
dataSource2: [],
|
||||
// 表头
|
||||
columns: [
|
||||
{
|
||||
title: '#',
|
||||
dataIndex: '',
|
||||
key: 'rowIndex',
|
||||
width: 60,
|
||||
align: 'center',
|
||||
customRender: ({ index }) => {
|
||||
return parseInt(index) + 1;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '标题',
|
||||
align: 'center',
|
||||
dataIndex: 'bizTitle',
|
||||
},
|
||||
{
|
||||
title: '流程编码',
|
||||
align: 'center',
|
||||
dataIndex: 'flowCode',
|
||||
},
|
||||
{
|
||||
title: '业务key',
|
||||
align: 'center',
|
||||
dataIndex: 'dataId',
|
||||
},
|
||||
{
|
||||
title: '当前环节',
|
||||
align: 'center',
|
||||
dataIndex: 'taskName',
|
||||
},
|
||||
],
|
||||
columns2: [
|
||||
{
|
||||
title: '#',
|
||||
dataIndex: '',
|
||||
key: 'rowIndex',
|
||||
width: 60,
|
||||
align: 'center',
|
||||
customRender: ({ index }) => {
|
||||
return parseInt(index) + 1;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '标题',
|
||||
align: 'center',
|
||||
dataIndex: 'bizTitle',
|
||||
},
|
||||
{
|
||||
title: '流程编码',
|
||||
align: 'center',
|
||||
dataIndex: 'flowCode',
|
||||
},
|
||||
{
|
||||
title: '业务key',
|
||||
align: 'center',
|
||||
dataIndex: 'dataId',
|
||||
},
|
||||
{
|
||||
title: '当前环节',
|
||||
align: 'center',
|
||||
dataIndex: 'taskName',
|
||||
},
|
||||
{
|
||||
title: '处理状态',
|
||||
align: 'center',
|
||||
dataIndex: 'status',
|
||||
customRender: ({ text }) => {
|
||||
if (text == '1') {
|
||||
return '处理成功';
|
||||
} else if (text == '0') {
|
||||
return '处理失败';
|
||||
} else {
|
||||
return '待处理';
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '描述',
|
||||
align: 'center',
|
||||
dataIndex: 'msg',
|
||||
},
|
||||
],
|
||||
remarksDictOptions: [],
|
||||
dealStatus: false,
|
||||
disabledButton: false,
|
||||
model: {
|
||||
taskId: '',
|
||||
nextnode: '',
|
||||
nextCodeCount: '',
|
||||
reason: '',
|
||||
processModel: 1,
|
||||
rejectModelNode: '',
|
||||
nextUserName: '',
|
||||
nextUserId: '',
|
||||
ccUserIds: '',
|
||||
ccUserRealNames: '',
|
||||
fileList: '',
|
||||
},
|
||||
});
|
||||
return {
|
||||
deal,
|
||||
handleModalCancel,
|
||||
handleChangeSelect,
|
||||
handleBatchComplete,
|
||||
...toRefs(data),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,262 @@
|
||||
<template>
|
||||
<!-- 弹出框 -->
|
||||
<a-modal
|
||||
:open="visible"
|
||||
:title="title"
|
||||
width="80%"
|
||||
:bodyStyle="{ height: '80vh', overflow:'auto' }"
|
||||
style="top: 20px"
|
||||
:footer="null"
|
||||
destroyOnClose
|
||||
@cancel="handleModalCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<!--已选择单据-->
|
||||
<div style="width: 60%; margin: 0 auto">
|
||||
<a-divider orientation="left">已选择的单据</a-divider>
|
||||
<a-table
|
||||
ref="table"
|
||||
size="middle"
|
||||
bordered
|
||||
rowKey="dataId"
|
||||
:pagination="false"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource"
|
||||
:loading="loading"
|
||||
>
|
||||
</a-table>
|
||||
</div>
|
||||
<!--处理意见-->
|
||||
<div style="width: 60%; margin: 0 auto">
|
||||
<a-divider orientation="left">选择委托人</a-divider>
|
||||
<a-row>
|
||||
<a-col :span="18">
|
||||
<a-form-item label="用户名:" :label-col="{ span: 5 }" :wrapper-col="{ span: 18 }">
|
||||
<JSelectUserByDept :isRadioSelection="true" :showButton="false" v-model:value="model.userName"></JSelectUserByDept>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-form-item>
|
||||
<a-button type="primary" :disabled="disabledButton" @click="handleBatchEntruster">确认委托</a-button>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
<!--反馈结果-->
|
||||
<div style="width: 60%; margin: 0 auto" v-show="dealStatus">
|
||||
<a-divider orientation="left">处理结果</a-divider>
|
||||
<a-table
|
||||
ref="table"
|
||||
size="middle"
|
||||
bordered
|
||||
rowKey="dataId"
|
||||
:pagination="false"
|
||||
:columns="columns2"
|
||||
:dataSource="dataSource2"
|
||||
:loading="loading"
|
||||
>
|
||||
</a-table>
|
||||
</div>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, toRefs, toRaw } from 'vue';
|
||||
import JSelectUserByDept from '/src/components/Form/src/jeecg/components/JSelectUserByDept.vue';
|
||||
import { getBizProcessNodeInfo } from '/src/views/super/bpm/process/manage/components/bpm.api';
|
||||
import { taskEntrust } from '../leave.api';
|
||||
import { useMessage } from '/src/hooks/web/useMessage';
|
||||
export default defineComponent({
|
||||
props: ['formData'],
|
||||
components: { JSelectUserByDept },
|
||||
emits: ['ok'],
|
||||
setup(_, { emit }) {
|
||||
const { createMessage, createConfirm } = useMessage();
|
||||
|
||||
// 关闭模态框
|
||||
function handleModalCancel() {
|
||||
data.visible = false;
|
||||
}
|
||||
function deal(processData) {
|
||||
data.dealStatus = false;
|
||||
data.model.reason = '';
|
||||
data.dataSource = [];
|
||||
data.dataSource2 = [];
|
||||
data.disabledButton = false;
|
||||
data.model.userName = '';
|
||||
data.userInfo = {};
|
||||
data.visible = true;
|
||||
initFlowData(processData);
|
||||
}
|
||||
|
||||
async function initFlowData(processData) {
|
||||
data.loading = true;
|
||||
for (let i = 0; i < processData.length; i++) {
|
||||
let params = { flowCode: processData[i].flowCode, dataId: processData[i].dataId }; //查询条件
|
||||
let res = await getBizProcessNodeInfo(params);
|
||||
if (res.success) {
|
||||
let currTask = res.result.bizTaskList[0];
|
||||
let taskId = currTask.id;
|
||||
let taskName = currTask.taskName;
|
||||
processData[i].taskClaimFlag = currTask.taskClaimFlag;
|
||||
processData[i].taskName = taskName;
|
||||
processData[i].taskId = taskId;
|
||||
processData[i].status = '-1'; //待处理
|
||||
continue;
|
||||
}
|
||||
processData[i].status = '0';
|
||||
}
|
||||
data.loading = false;
|
||||
data.dataSource = processData;
|
||||
console.log('------数据初始化--------', data.dataSource);
|
||||
}
|
||||
function handleBatchEntruster() {
|
||||
let username = toRaw(data.model.userName);
|
||||
if (!username || username.length == 0) {
|
||||
createMessage.warning('请选择委托人!');
|
||||
return;
|
||||
}
|
||||
createConfirm({
|
||||
title: '确认委托',
|
||||
centered: false,
|
||||
content: '是否委托选中数据?',
|
||||
onOk: () => {
|
||||
batchEntruster();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function batchEntruster() {
|
||||
data.confirmLoading = true;
|
||||
data.disabledButton = true;
|
||||
let username = toRaw(data.model.userName);
|
||||
let taskAssignee = Array.isArray(username) ? username.join('') : username;
|
||||
for (var i = 0; i < data.dataSource.length; i++) {
|
||||
if (data.dataSource[i].taskClaimFlag) {
|
||||
//未签收,不做处理
|
||||
data.dataSource[i].msg = '未签收不能进行委托处理';
|
||||
data.dataSource[i].status = '0';
|
||||
continue;
|
||||
}
|
||||
if (data.dataSource[i].status == '-1') {
|
||||
let params = {
|
||||
taskId: data.dataSource[i].taskId,
|
||||
taskAssignee: taskAssignee,
|
||||
};
|
||||
console.log('委托', params);
|
||||
let res = await taskEntrust(params);
|
||||
if (res.success) {
|
||||
data.dataSource[i].status = '1';
|
||||
continue;
|
||||
}
|
||||
}
|
||||
data.dataSource[i].status = '0';
|
||||
}
|
||||
data.dealStatus = true;
|
||||
data.dataSource2 = data.dataSource;
|
||||
data.confirmLoading = false;
|
||||
emit('ok');
|
||||
}
|
||||
const data = reactive({
|
||||
loading: false,
|
||||
title: '批量处理',
|
||||
visible: false,
|
||||
confirmLoading: false,
|
||||
currTask: {},
|
||||
dataSource: [],
|
||||
dataSource2: [],
|
||||
// 表头
|
||||
columns: [
|
||||
{
|
||||
title: '#',
|
||||
dataIndex: '',
|
||||
key: 'rowIndex',
|
||||
width: 60,
|
||||
align: 'center',
|
||||
customRender: ({ index }) => {
|
||||
return parseInt(index) + 1;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '标题',
|
||||
align: 'center',
|
||||
dataIndex: 'bizTitle',
|
||||
},
|
||||
{
|
||||
title: '流程编码',
|
||||
align: 'center',
|
||||
dataIndex: 'flowCode',
|
||||
},
|
||||
{
|
||||
title: '业务key',
|
||||
align: 'center',
|
||||
dataIndex: 'dataId',
|
||||
},
|
||||
{
|
||||
title: '当前环节',
|
||||
align: 'center',
|
||||
dataIndex: 'taskName',
|
||||
},
|
||||
],
|
||||
columns2: [
|
||||
{
|
||||
title: '#',
|
||||
dataIndex: '',
|
||||
key: 'rowIndex',
|
||||
width: 60,
|
||||
align: 'center',
|
||||
customRender: ({ index }) => {
|
||||
return parseInt(index) + 1;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '标题',
|
||||
align: 'center',
|
||||
dataIndex: 'bizTitle',
|
||||
},
|
||||
{
|
||||
title: '流程编码',
|
||||
align: 'center',
|
||||
dataIndex: 'flowCode',
|
||||
},
|
||||
{
|
||||
title: '业务key',
|
||||
align: 'center',
|
||||
dataIndex: 'dataId',
|
||||
},
|
||||
{
|
||||
title: '当前环节',
|
||||
align: 'center',
|
||||
dataIndex: 'taskName',
|
||||
},
|
||||
{
|
||||
title: '处理状态',
|
||||
align: 'center',
|
||||
dataIndex: 'status',
|
||||
customRender: ({ text }) => {
|
||||
if (text == '1') {
|
||||
return '处理成功';
|
||||
} else if (text == '0') {
|
||||
return '处理失败';
|
||||
} else {
|
||||
return '待处理';
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
dealStatus: false,
|
||||
disabledButton: false,
|
||||
model: {
|
||||
userName: '',
|
||||
},
|
||||
});
|
||||
return {
|
||||
deal,
|
||||
handleModalCancel,
|
||||
handleBatchEntruster,
|
||||
...toRefs(data),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,348 @@
|
||||
<template>
|
||||
<!-- 弹出框 -->
|
||||
<a-modal
|
||||
:open="visible"
|
||||
:title="title"
|
||||
width="80%"
|
||||
:bodyStyle="{ height: '80vh', overflow:'auto' }"
|
||||
style="top: 20px"
|
||||
:footer="null"
|
||||
destroyOnClose
|
||||
@cancel="handleModalCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<!--已选择单据-->
|
||||
<div style="width: 60%; margin: 0 auto">
|
||||
<a-divider orientation="left">已选择的单据</a-divider>
|
||||
<a-table
|
||||
ref="table"
|
||||
size="middle"
|
||||
bordered
|
||||
rowKey="dataId"
|
||||
:pagination="false"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource"
|
||||
:loading="loading"
|
||||
>
|
||||
<template #currTask="{ text, record, index }">
|
||||
<a-select style="width: 200px" :defaultValue="record.taskId">
|
||||
<a-select-option :value="record.taskId">{{ record.taskName }}</a-select-option>
|
||||
</a-select>
|
||||
</template>
|
||||
<template #rejectTask="{ text, record, index }">
|
||||
<a-select v-model:value="record.rejectModelNode" style="width: 200px" @change="handleRejectNodeChange">
|
||||
<template v-for="(item, index) in record.histListNode" :key="index">
|
||||
<a-select-option :value="item.TASK_DEF_KEY_">{{ item.NAME_ }}</a-select-option>
|
||||
</template>
|
||||
</a-select>
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
<!--处理意见-->
|
||||
<div style="width: 60%; margin: 0 auto">
|
||||
<a-divider orientation="left">处理意见</a-divider>
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<a-list-item>
|
||||
<div style="width: 100%">
|
||||
<div style="margin-bottom: 5px">
|
||||
处理意见:
|
||||
<a-select style="width: 300px" placeholder="常用审批语" @change="handleChangeSelect">
|
||||
<template #suffixIcon>
|
||||
<Icon icon="ant-design:smile-outlined" />
|
||||
</template>
|
||||
<a-select-option v-for="(item, key) in remarksDictOptions" :key="key" :value="item.value">{{ item.text }}</a-select-option>
|
||||
</a-select>
|
||||
</div>
|
||||
<a-textarea rows="3" v-model:value="model.reason" />
|
||||
</div>
|
||||
</a-list-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<div style="text-align: center">
|
||||
<a-button type="primary" :disabled="disabledButton" @click="handleBatchReject">确认驳回</a-button>
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
<!--反馈结果-->
|
||||
<div style="width: 60%; margin: 0 auto" v-show="dealStatus">
|
||||
<a-divider orientation="left">处理结果</a-divider>
|
||||
<a-table
|
||||
ref="table"
|
||||
size="middle"
|
||||
bordered
|
||||
rowKey="dataId"
|
||||
:pagination="false"
|
||||
:columns="columns2"
|
||||
:dataSource="dataSource2"
|
||||
:loading="loading"
|
||||
>
|
||||
</a-table>
|
||||
</div>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, toRefs } from 'vue';
|
||||
import { initDictOptions } from '/src/utils/dict';
|
||||
import { getBizProcessNodeInfo, getProcessTaskTransInfo, processComplete } from '/src/views/super/bpm/process/manage/components/bpm.api';
|
||||
import { useMessage } from '/src/hooks/web/useMessage';
|
||||
export default defineComponent({
|
||||
props: ['paramData'],
|
||||
emits: ['ok'],
|
||||
setup(_, { emit }) {
|
||||
const { createMessage, createConfirm } = useMessage();
|
||||
|
||||
async function initDictConfig() {
|
||||
//初始化字典
|
||||
let res = await initDictOptions('approval_remarks');
|
||||
data.remarksDictOptions = res && res.length > 0 ? res : [];
|
||||
}
|
||||
|
||||
function handleChangeSelect(value) {
|
||||
data.model.reason = value;
|
||||
}
|
||||
|
||||
// 关闭模态框
|
||||
function handleModalCancel() {
|
||||
data.visible = false;
|
||||
}
|
||||
function deal(processData) {
|
||||
data.dealStatus = false;
|
||||
data.model.reason = '';
|
||||
data.dataSource = [];
|
||||
data.dataSource2 = [];
|
||||
data.disabledButton = false;
|
||||
data.visible = true;
|
||||
initFlowData(processData);
|
||||
}
|
||||
|
||||
async function initFlowData(processData) {
|
||||
data.loading = true;
|
||||
for (let i = 0; i < processData.length; i++) {
|
||||
let params = { flowCode: processData[i].flowCode, dataId: processData[i].dataId }; //查询条件
|
||||
let res = await getBizProcessNodeInfo(params);
|
||||
if (res.success) {
|
||||
let currTask = res.result.bizTaskList[0];
|
||||
let taskId = currTask.id;
|
||||
let taskName = currTask.taskName;
|
||||
processData[i].taskClaimFlag = currTask.taskClaimFlag;
|
||||
processData[i].taskName = taskName;
|
||||
processData[i].taskId = taskId;
|
||||
let res2 = await getProcessTaskTransInfo({ taskId });
|
||||
if (res2.success) {
|
||||
processData[i].histListNode = res2.result.histListNode;
|
||||
processData[i].rejectModelNode = getDefaultRejectNode(processData[i].histListNode, currTask);
|
||||
processData[i].status = '-1'; //待处理
|
||||
continue;
|
||||
}
|
||||
}
|
||||
processData[i].status = '0';
|
||||
}
|
||||
data.loading = false;
|
||||
data.dataSource = processData;
|
||||
console.log('processData------------->', processData);
|
||||
}
|
||||
function getDefaultRejectNode(histListNode, currTask) {
|
||||
let taskDefKey = '';
|
||||
for (let item of histListNode) {
|
||||
if (item.TASK_DEF_KEY_ == currTask.taskId) {
|
||||
break;
|
||||
}
|
||||
taskDefKey = item.TASK_DEF_KEY_;
|
||||
}
|
||||
return taskDefKey;
|
||||
}
|
||||
function handleBatchReject() {
|
||||
if (!data.model.reason || data.model.reason.length == 0) {
|
||||
createMessage.warning('请填写处理意见');
|
||||
return;
|
||||
}
|
||||
createConfirm({
|
||||
title: '确认驳回',
|
||||
centered: false,
|
||||
content: '是否驳回选中数据?',
|
||||
onOk: () => {
|
||||
handleProcessComplete();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function handleProcessComplete() {
|
||||
data.confirmLoading = true;
|
||||
data.disabledButton = true;
|
||||
for (var i = 0; i < data.dataSource.length; i++) {
|
||||
if (data.dataSource[i].taskClaimFlag) {
|
||||
//未签收,不做处理
|
||||
data.dataSource[i].msg = '未签收不能进行驳回处理';
|
||||
data.dataSource[i].status = '0';
|
||||
continue;
|
||||
}
|
||||
if (data.dataSource[i].rejectModelNode == '') {
|
||||
data.dataSource[i].msg = '未选中驳回节点不能进行驳回处理';
|
||||
data.dataSource[i].status = '0';
|
||||
continue;
|
||||
}
|
||||
if (data.dataSource[i].status == '-1') {
|
||||
let param = {
|
||||
taskId: data.dataSource[i].taskId,
|
||||
nextnode: data.dataSource[i].nextnode,
|
||||
nextCodeCount: '1',
|
||||
reason: data.model.reason,
|
||||
processModel: 3,
|
||||
rejectModelNode: data.dataSource[i].rejectModelNode,
|
||||
nextUserName: '',
|
||||
nextUserId: '',
|
||||
ccUserIds: '',
|
||||
ccUserRealNames: '',
|
||||
fileList: '',
|
||||
};
|
||||
console.log('驳回办理数据:', param);
|
||||
let res = await processComplete(param);
|
||||
if (res.success) {
|
||||
data.dataSource[i].status = '1';
|
||||
continue;
|
||||
}
|
||||
}
|
||||
data.dataSource[i].status = '0';
|
||||
}
|
||||
data.dealStatus = true;
|
||||
data.dataSource2 = data.dataSource;
|
||||
data.confirmLoading = false;
|
||||
emit('ok');
|
||||
}
|
||||
function handleRejectNodeChange(value) {
|
||||
console.log('------handleRejectNodeChange--------', data.dataSource);
|
||||
}
|
||||
initDictConfig();
|
||||
const data = reactive({
|
||||
loading: false,
|
||||
title: '批量处理',
|
||||
visible: false,
|
||||
confirmLoading: false,
|
||||
currTask: {},
|
||||
dataSource: [],
|
||||
dataSource2: [],
|
||||
// 表头
|
||||
columns: [
|
||||
{
|
||||
title: '#',
|
||||
dataIndex: '',
|
||||
key: 'rowIndex',
|
||||
width: 60,
|
||||
align: 'center',
|
||||
customRender: ({ index }) => {
|
||||
return parseInt(index) + 1;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '标题',
|
||||
align: 'center',
|
||||
dataIndex: 'bizTitle',
|
||||
},
|
||||
{
|
||||
title: '流程编码',
|
||||
align: 'center',
|
||||
dataIndex: 'flowCode',
|
||||
},
|
||||
{
|
||||
title: '业务key',
|
||||
align: 'center',
|
||||
dataIndex: 'dataId',
|
||||
},
|
||||
{
|
||||
title: '当前环节',
|
||||
align: 'center',
|
||||
dataIndex: 'currTask',
|
||||
slots: { customRender: 'currTask' },
|
||||
},
|
||||
{
|
||||
title: '驳回到',
|
||||
align: 'center',
|
||||
dataIndex: 'rejectTask',
|
||||
slots: { customRender: 'rejectTask' },
|
||||
},
|
||||
],
|
||||
columns2: [
|
||||
{
|
||||
title: '#',
|
||||
dataIndex: '',
|
||||
key: 'rowIndex',
|
||||
width: 60,
|
||||
align: 'center',
|
||||
customRender: ({ index }) => {
|
||||
return parseInt(index) + 1;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '标题',
|
||||
align: 'center',
|
||||
dataIndex: 'bizTitle',
|
||||
},
|
||||
{
|
||||
title: '流程编码',
|
||||
align: 'center',
|
||||
dataIndex: 'flowCode',
|
||||
},
|
||||
{
|
||||
title: '业务key',
|
||||
align: 'center',
|
||||
dataIndex: 'dataId',
|
||||
},
|
||||
{
|
||||
title: '当前环节',
|
||||
align: 'center',
|
||||
dataIndex: 'taskName',
|
||||
},
|
||||
{
|
||||
title: '处理状态',
|
||||
align: 'center',
|
||||
dataIndex: 'status',
|
||||
customRender: ({ text }) => {
|
||||
if (text == '1') {
|
||||
return '处理成功';
|
||||
} else if (text == '0') {
|
||||
return '处理失败';
|
||||
} else {
|
||||
return '待处理';
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '描述',
|
||||
align: 'center',
|
||||
dataIndex: 'msg',
|
||||
},
|
||||
],
|
||||
remarksDictOptions: [],
|
||||
dealStatus: false,
|
||||
disabledButton: false,
|
||||
model: {
|
||||
taskId: '',
|
||||
nextnode: '',
|
||||
nextCodeCount: '',
|
||||
reason: '',
|
||||
processModel: 3,
|
||||
rejectModelNode: '',
|
||||
nextUserName: '',
|
||||
nextUserId: '',
|
||||
ccUserIds: '',
|
||||
ccUserRealNames: '',
|
||||
fileList: '',
|
||||
},
|
||||
});
|
||||
return {
|
||||
deal,
|
||||
handleModalCancel,
|
||||
handleChangeSelect,
|
||||
handleBatchReject,
|
||||
handleRejectNodeChange,
|
||||
...toRefs(data),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,250 @@
|
||||
<template>
|
||||
<!-- 弹出框 -->
|
||||
<a-modal
|
||||
:open="visible"
|
||||
:title="title"
|
||||
width="80%"
|
||||
:bodyStyle="{ height: '80vh', overflow:'auto' }"
|
||||
style="top: 20px"
|
||||
:footer="null"
|
||||
destroyOnClose
|
||||
@cancel="handleModalCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<!--已选择单据-->
|
||||
<div style="width: 60%; margin: 0 auto">
|
||||
<a-divider orientation="left">已选择的单据</a-divider>
|
||||
<a-table
|
||||
ref="table"
|
||||
size="middle"
|
||||
bordered
|
||||
rowKey="dataId"
|
||||
:pagination="false"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource"
|
||||
:loading="loading"
|
||||
>
|
||||
</a-table>
|
||||
</div>
|
||||
<!--处理意见-->
|
||||
<div style="width: 60%; margin: 0 auto">
|
||||
<a-divider orientation="left">解挂</a-divider>
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<div style="text-align: center">
|
||||
<a-button type="primary" :disabled="disabledButton" @click="handleBatchRestart">确认解挂</a-button>
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
<!--反馈结果-->
|
||||
<div style="width: 60%; margin: 0 auto" v-show="dealStatus">
|
||||
<a-divider orientation="left">处理结果</a-divider>
|
||||
<a-table
|
||||
ref="table2"
|
||||
size="middle"
|
||||
bordered
|
||||
rowKey="dataId"
|
||||
:pagination="false"
|
||||
:columns="columns2"
|
||||
:dataSource="dataSource2"
|
||||
:loading="loading"
|
||||
>
|
||||
</a-table>
|
||||
</div>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, toRefs } from 'vue';
|
||||
import { getBizProcessNodeInfo, restart } from '/src/views/super/bpm/process/manage/components/bpm.api';
|
||||
import { useMessage } from '/src/hooks/web/useMessage';
|
||||
|
||||
export default defineComponent({
|
||||
props: ['formData'],
|
||||
emits: ['ok'],
|
||||
setup(_, { emit }) {
|
||||
const { createMessage, createConfirm } = useMessage();
|
||||
|
||||
// 关闭模态框
|
||||
function handleModalCancel() {
|
||||
data.visible = false;
|
||||
}
|
||||
function deal(processData) {
|
||||
data.dealStatus = false;
|
||||
data.dataSource = [];
|
||||
data.dataSource2 = [];
|
||||
data.disabledButton = false;
|
||||
data.visible = true;
|
||||
initFlowData(processData);
|
||||
}
|
||||
function completeProcess() {
|
||||
data.visible = false;
|
||||
emit('ok');
|
||||
}
|
||||
async function initFlowData(processData) {
|
||||
data.loading = true;
|
||||
for (let i = 0; i < processData.length; i++) {
|
||||
let params = { flowCode: processData[i].flowCode, dataId: processData[i].dataId }; //查询条件
|
||||
let res = await getBizProcessNodeInfo(params);
|
||||
if (res.success) {
|
||||
let currTask = res.result.bizTaskList[0];
|
||||
let taskId = currTask.id;
|
||||
let taskName = currTask.taskName;
|
||||
processData[i].taskClaimFlag = currTask.taskClaimFlag;
|
||||
processData[i].procInstId = currTask.procInstId;
|
||||
processData[i].taskName = taskName;
|
||||
processData[i].taskId = taskId;
|
||||
processData[i].status = '-1'; //待处理
|
||||
continue;
|
||||
}
|
||||
processData[i].status = '0';
|
||||
}
|
||||
data.loading = false;
|
||||
data.dataSource = processData;
|
||||
console.log('------数据初始化--------', data.dataSource);
|
||||
}
|
||||
function handleBatchRestart() {
|
||||
createConfirm({
|
||||
title: '确认解挂',
|
||||
centered: false,
|
||||
content: '是否解挂选中数据?',
|
||||
onOk: () => {
|
||||
batchRestart();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function batchRestart() {
|
||||
data.confirmLoading = true;
|
||||
data.disabledButton = true;
|
||||
for (var i = 0; i < data.dataSource.length; i++) {
|
||||
if (data.dataSource[i].status == '-1') {
|
||||
let param = { processInstanceId: data.dataSource[i].procInstId };
|
||||
let res = await restart(param);
|
||||
if (res.success) {
|
||||
data.dataSource[i].status = '1';
|
||||
continue;
|
||||
}
|
||||
}
|
||||
data.dataSource[i].status = '0';
|
||||
}
|
||||
data.dealStatus = true;
|
||||
data.dataSource2 = data.dataSource;
|
||||
data.confirmLoading = false;
|
||||
emit('ok');
|
||||
}
|
||||
const data = reactive({
|
||||
loading: false,
|
||||
title: '批量处理',
|
||||
visible: false,
|
||||
confirmLoading: false,
|
||||
currTask: {},
|
||||
dataSource: [],
|
||||
dataSource2: [],
|
||||
// 表头
|
||||
columns: [
|
||||
{
|
||||
title: '#',
|
||||
dataIndex: '',
|
||||
key: 'rowIndex',
|
||||
width: 60,
|
||||
align: 'center',
|
||||
customRender: ({ index }) => {
|
||||
return parseInt(index) + 1;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '标题',
|
||||
align: 'center',
|
||||
dataIndex: 'bizTitle',
|
||||
},
|
||||
{
|
||||
title: '流程编码',
|
||||
align: 'center',
|
||||
dataIndex: 'flowCode',
|
||||
},
|
||||
{
|
||||
title: '业务key',
|
||||
align: 'center',
|
||||
dataIndex: 'dataId',
|
||||
},
|
||||
{
|
||||
title: '当前环节',
|
||||
align: 'center',
|
||||
dataIndex: 'taskName',
|
||||
},
|
||||
],
|
||||
columns2: [
|
||||
{
|
||||
title: '#',
|
||||
dataIndex: '',
|
||||
key: 'rowIndex',
|
||||
width: 60,
|
||||
align: 'center',
|
||||
customRender: ({ index }) => {
|
||||
return parseInt(index) + 1;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '标题',
|
||||
align: 'center',
|
||||
dataIndex: 'bizTitle',
|
||||
},
|
||||
{
|
||||
title: '流程编码',
|
||||
align: 'center',
|
||||
dataIndex: 'flowCode',
|
||||
},
|
||||
{
|
||||
title: '业务key',
|
||||
align: 'center',
|
||||
dataIndex: 'dataId',
|
||||
},
|
||||
{
|
||||
title: '当前环节',
|
||||
align: 'center',
|
||||
dataIndex: 'taskName',
|
||||
},
|
||||
{
|
||||
title: '处理状态',
|
||||
align: 'center',
|
||||
dataIndex: 'status',
|
||||
customRender: ({ text }) => {
|
||||
if (text == '1') {
|
||||
return '处理成功';
|
||||
} else if (text == '0') {
|
||||
return '处理失败';
|
||||
} else {
|
||||
return '待处理';
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
remarksDictOptions: [],
|
||||
dealStatus: false,
|
||||
disabledButton: false,
|
||||
model: {
|
||||
taskId: '',
|
||||
nextnode: '',
|
||||
nextCodeCount: '',
|
||||
reason: '',
|
||||
processModel: 1,
|
||||
rejectModelNode: '',
|
||||
nextUserName: '',
|
||||
nextUserId: '',
|
||||
ccUserIds: '',
|
||||
ccUserRealNames: '',
|
||||
fileList: '',
|
||||
},
|
||||
});
|
||||
return {
|
||||
deal,
|
||||
handleModalCancel,
|
||||
handleBatchRestart,
|
||||
...toRefs(data),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,239 @@
|
||||
<template>
|
||||
<!-- 弹出框 -->
|
||||
<a-modal
|
||||
:open="visible"
|
||||
:title="title"
|
||||
width="80%"
|
||||
:bodyStyle="{ height: '80vh', overflow:'auto' }"
|
||||
style="top: 20px"
|
||||
:footer="null"
|
||||
destroyOnClose
|
||||
@cancel="handleModalCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<!--已选择单据-->
|
||||
<div style="width: 60%; margin: 0 auto">
|
||||
<a-divider orientation="left">已选择的单据</a-divider>
|
||||
<a-table
|
||||
ref="table"
|
||||
size="middle"
|
||||
bordered
|
||||
rowKey="dataId"
|
||||
:pagination="false"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource"
|
||||
:loading="loading"
|
||||
>
|
||||
</a-table>
|
||||
</div>
|
||||
<!--处理意见-->
|
||||
<div style="width: 60%; margin: 0 auto">
|
||||
<a-divider orientation="left">挂起</a-divider>
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<div style="text-align: center">
|
||||
<a-button type="primary" :disabled="disabledButton" @click="handleBatchSuspend">确认挂起</a-button>
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
<!--反馈结果-->
|
||||
<div style="width: 60%; margin: 0 auto" v-show="dealStatus">
|
||||
<a-divider orientation="left">处理结果</a-divider>
|
||||
<a-table
|
||||
ref="table2"
|
||||
size="middle"
|
||||
bordered
|
||||
rowKey="dataId"
|
||||
:pagination="false"
|
||||
:columns="columns2"
|
||||
:dataSource="dataSource2"
|
||||
:loading="loading"
|
||||
>
|
||||
</a-table>
|
||||
</div>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, toRefs } from 'vue';
|
||||
import { getBizProcessNodeInfo, suspend } from '/src/views/super/bpm/process/manage/components/bpm.api';
|
||||
import { useMessage } from '/src/hooks/web/useMessage';
|
||||
export default defineComponent({
|
||||
props: ['formData'],
|
||||
emits: ['ok'],
|
||||
setup(_, { emit }) {
|
||||
const { createMessage, createConfirm } = useMessage();
|
||||
|
||||
// 关闭模态框
|
||||
function handleModalCancel() {
|
||||
data.visible = false;
|
||||
}
|
||||
function deal(processData) {
|
||||
data.dealStatus = false;
|
||||
data.dataSource = [];
|
||||
data.dataSource2 = [];
|
||||
data.disabledButton = false;
|
||||
data.visible = true;
|
||||
initFlowData(processData);
|
||||
}
|
||||
|
||||
async function initFlowData(processData) {
|
||||
data.loading = true;
|
||||
for (let i = 0; i < processData.length; i++) {
|
||||
let params = { flowCode: processData[i].flowCode, dataId: processData[i].dataId }; //查询条件
|
||||
let res = await getBizProcessNodeInfo(params);
|
||||
if (res.success) {
|
||||
let currTask = res.result.bizTaskList[0];
|
||||
let taskId = currTask.id;
|
||||
let taskName = currTask.taskName;
|
||||
processData[i].taskClaimFlag = currTask.taskClaimFlag;
|
||||
processData[i].procInstId = currTask.procInstId;
|
||||
processData[i].taskName = taskName;
|
||||
processData[i].taskId = taskId;
|
||||
processData[i].status = '-1'; //待处理
|
||||
continue;
|
||||
}
|
||||
processData[i].status = '0';
|
||||
}
|
||||
data.loading = false;
|
||||
data.dataSource = processData;
|
||||
console.log('------数据初始化--------', data.dataSource);
|
||||
}
|
||||
function handleBatchSuspend() {
|
||||
createConfirm({
|
||||
title: '确认挂起',
|
||||
centered: false,
|
||||
content: '是否挂起选中数据?',
|
||||
onOk: () => {
|
||||
batchSuspend();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function batchSuspend() {
|
||||
data.confirmLoading = true;
|
||||
data.disabledButton = true;
|
||||
for (var i = 0; i < data.dataSource.length; i++) {
|
||||
if (data.dataSource[i].taskClaimFlag) {
|
||||
//未签收,不做处理
|
||||
data.dataSource[i].msg = '未签收不能进行挂起处理';
|
||||
data.dataSource[i].status = '0';
|
||||
continue;
|
||||
}
|
||||
if (data.dataSource[i].status == '-1') {
|
||||
let param = { processInstanceId: data.dataSource[i].procInstId };
|
||||
console.log('挂起:', param);
|
||||
let res = await suspend(param);
|
||||
if (res.success) {
|
||||
data.dataSource[i].status = '1';
|
||||
continue;
|
||||
}
|
||||
}
|
||||
data.dataSource[i].status = '0';
|
||||
}
|
||||
data.dealStatus = true;
|
||||
data.dataSource2 = data.dataSource;
|
||||
data.confirmLoading = false;
|
||||
emit('ok');
|
||||
}
|
||||
const data = reactive({
|
||||
loading: false,
|
||||
title: '批量处理',
|
||||
visible: false,
|
||||
confirmLoading: false,
|
||||
currTask: {},
|
||||
dataSource: [],
|
||||
dataSource2: [],
|
||||
// 表头
|
||||
columns: [
|
||||
{
|
||||
title: '#',
|
||||
dataIndex: '',
|
||||
key: 'rowIndex',
|
||||
width: 60,
|
||||
align: 'center',
|
||||
customRender: ({ index }) => {
|
||||
return parseInt(index) + 1;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '标题',
|
||||
align: 'center',
|
||||
dataIndex: 'bizTitle',
|
||||
},
|
||||
{
|
||||
title: '流程编码',
|
||||
align: 'center',
|
||||
dataIndex: 'flowCode',
|
||||
},
|
||||
{
|
||||
title: '业务key',
|
||||
align: 'center',
|
||||
dataIndex: 'dataId',
|
||||
},
|
||||
{
|
||||
title: '当前环节',
|
||||
align: 'center',
|
||||
dataIndex: 'taskName',
|
||||
},
|
||||
],
|
||||
columns2: [
|
||||
{
|
||||
title: '#',
|
||||
dataIndex: '',
|
||||
key: 'rowIndex',
|
||||
width: 60,
|
||||
align: 'center',
|
||||
customRender: ({ index }) => {
|
||||
return parseInt(index) + 1;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '标题',
|
||||
align: 'center',
|
||||
dataIndex: 'bizTitle',
|
||||
},
|
||||
{
|
||||
title: '流程编码',
|
||||
align: 'center',
|
||||
dataIndex: 'flowCode',
|
||||
},
|
||||
{
|
||||
title: '业务key',
|
||||
align: 'center',
|
||||
dataIndex: 'dataId',
|
||||
},
|
||||
{
|
||||
title: '当前环节',
|
||||
align: 'center',
|
||||
dataIndex: 'taskName',
|
||||
},
|
||||
{
|
||||
title: '处理状态',
|
||||
align: 'center',
|
||||
dataIndex: 'status',
|
||||
customRender: ({ text }) => {
|
||||
if (text == '1') {
|
||||
return '处理成功';
|
||||
} else if (text == '0') {
|
||||
return '处理失败';
|
||||
} else {
|
||||
return '待处理';
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
dealStatus: false,
|
||||
disabledButton: false,
|
||||
});
|
||||
return {
|
||||
deal,
|
||||
handleModalCancel,
|
||||
handleBatchSuspend,
|
||||
...toRefs(data),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,265 @@
|
||||
<template>
|
||||
<!-- 批量业务办理弹出框 -->
|
||||
<a-modal :open="visible" width="100%" destroyOnClose :bodyStyle="bodyStyle" style="top: 0" :footer="null" @cancel="handleModalCancel">
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<div class="ant-alert ant-alert-info" style="margin-bottom: 16px">
|
||||
当前任务环节:
|
||||
<a-select style="width: 300px" :defaultValue="currTask.id">
|
||||
<a-select-option :value="currTask.id">{{ currTask.taskName }}</a-select-option>
|
||||
</a-select>
|
||||
<template v-if="!currTask.suspendFlag">
|
||||
<template v-if="currTask.taskClaimFlag">
|
||||
<a-button @click="handleClaim()" type="primary" preIcon="ant-design:caret-right-outlined">签收</a-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<a-button @click="handleOpt('submit')" type="primary" preIcon="ant-design:caret-right-outlined">发送</a-button>
|
||||
<a-button @click="handleOpt('reject')" type="primary" preIcon="ant-design:rollback-outlined">退回</a-button>
|
||||
<a-button @click="selectEntruster()" type="primary" preIcon="ant-design:user-outlined">委托</a-button>
|
||||
<a-button @click="handleSuspend()" type="primary" preIcon="ant-design:lock-outlined">挂起</a-button>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<a-button @click="handleActive()" type="primary" preIcon="ant-design:unlock-outlined">解挂</a-button>
|
||||
</template>
|
||||
<span style="color: red" v-if="currTask.suspendFlag">当前流程已挂起,需要进行解挂,再进行办理!</span>
|
||||
</div>
|
||||
<div>
|
||||
<template v-if="isComp">
|
||||
<DynamicLink :path="path" :formData="formData"></DynamicLink>
|
||||
</template>
|
||||
<template v-else>
|
||||
<iframe :src="iframeUrl" frameborder="0" width="100%" :height="height" scrolling="auto"></iframe>
|
||||
</template>
|
||||
</div>
|
||||
</a-spin>
|
||||
<DelegateModal @register="registerModal" @success="handleEntruster"></DelegateModal>
|
||||
<BpmBizTaskOptModal ref="bpmBizTaskOptModal" :formData="formData" @success="completeProcess"></BpmBizTaskOptModal>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, toRefs, computed, getCurrentInstance } from 'vue';
|
||||
import DelegateModal from '/src/views/super/bpm/process/manage/components/DelegateModal.vue';
|
||||
import DynamicLink from '/src/views/super/bpm/process/manage/components/DynamicLink.vue';
|
||||
import BpmBizTaskOptModal from './BpmBizTaskOptModal.vue';
|
||||
import { isUrl, getBpmFormUrl } from '/src/utils/is';
|
||||
import { getToken } from '/src/utils/auth';
|
||||
import { useGlobSetting } from '/src/hooks/setting';
|
||||
import { useMessage } from '/src/hooks/web/useMessage';
|
||||
import { useModal } from '/src/components/Modal';
|
||||
import { claim, taskEntrust, suspend, restart } from '/src/views/super/bpm/process/manage/components/bpm.api.ts';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'BpmBizTaskDealModal',
|
||||
components: {
|
||||
DynamicLink,
|
||||
DelegateModal,
|
||||
BpmBizTaskOptModal,
|
||||
},
|
||||
props: ['path', 'formData'],
|
||||
emits: ['ok'],
|
||||
setup(props, { emit }) {
|
||||
const globSetting = useGlobSetting();
|
||||
const { createMessage, createConfirm } = useMessage();
|
||||
//委派弹窗
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
|
||||
//弹窗示例
|
||||
const instance = getCurrentInstance();
|
||||
|
||||
const data = reactive({
|
||||
loading: false,
|
||||
title: '流程',
|
||||
visible: false,
|
||||
confirmLoading: false,
|
||||
currTask: {},
|
||||
bodyStyle: {
|
||||
padding: '0',
|
||||
height: window.innerHeight + 'px',
|
||||
'overflow-y': 'auto',
|
||||
},
|
||||
iframeUrl: '',
|
||||
});
|
||||
|
||||
let TOKEN = getToken();
|
||||
let DOMAIN_URL = globSetting.domainUrl;
|
||||
let TASKID = props.formData.taskDefKey;
|
||||
//是否组件
|
||||
const isComp = computed(() => {
|
||||
//获取流程审批url
|
||||
//let URL = (props.path || '').replace(/{{([^}}]+)?}}/g, (s1, s2) => eval(s2)); // URL支持{{ window.xxx }}占位符变量
|
||||
let URL = getBpmFormUrl(props.path, TOKEN, DOMAIN_URL, TASKID);
|
||||
|
||||
if (isUrl(URL)) {
|
||||
data.iframeUrl = URL;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
// 关闭模态框
|
||||
function handleModalCancel() {
|
||||
data.visible = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开弹窗处理数据
|
||||
* @param processData
|
||||
*/
|
||||
function deal(processData) {
|
||||
console.log('-----任务办理组件数据:-------', processData);
|
||||
let taskList = processData.bizTaskList;
|
||||
data.currTask = taskList && taskList.length > 0 ? taskList[0] : {};
|
||||
data.visible = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 完成
|
||||
*/
|
||||
function completeProcess() {
|
||||
data.visible = false;
|
||||
emit('ok');
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送
|
||||
* @param opt
|
||||
*/
|
||||
function handleOpt(opt) {
|
||||
console.log('handleOpt', opt);
|
||||
instance.refs.bpmBizTaskOptModal.deal(opt);
|
||||
instance.refs.bpmBizTaskOptModal.data.title = opt == 'submit' ? '发送' : '退回';
|
||||
}
|
||||
//签收
|
||||
function handleClaim() {
|
||||
let params = { taskId: data.currTask?.id }; //查询条件
|
||||
createConfirm({
|
||||
title: '确认签收吗',
|
||||
centered: false,
|
||||
content: '是否签收该任务?',
|
||||
onOk: async () => {
|
||||
data.confirmLoading = true;
|
||||
let res = await claim(params);
|
||||
data.confirmLoading = false;
|
||||
if (res.success) {
|
||||
createMessage.success(res.message);
|
||||
completeProcess();
|
||||
} else {
|
||||
createMessage.warning(res.message);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
//委托
|
||||
function selectEntruster() {
|
||||
openModal(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 委派选择回调
|
||||
* @param data
|
||||
*/
|
||||
async function handleEntruster(obj) {
|
||||
let params = { taskId: data.currTask.id, taskAssignee: obj.username };
|
||||
await taskEntrust(params, (res) => {
|
||||
if (res.success) {
|
||||
createMessage.success(res.message);
|
||||
completeProcess();
|
||||
} else {
|
||||
createMessage.warning(res.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
//挂起
|
||||
function handleSuspend() {
|
||||
let params = { processInstanceId: data.currTask?.procInstId }; //查询条件
|
||||
createConfirm({
|
||||
title: '确认挂起吗',
|
||||
centered: false,
|
||||
content: '是否挂起该任务?',
|
||||
onOk: async () => {
|
||||
data.confirmLoading = true;
|
||||
let res = await suspend(params);
|
||||
data.confirmLoading = false;
|
||||
if (res.success) {
|
||||
createMessage.success(res.message);
|
||||
completeProcess();
|
||||
} else {
|
||||
createMessage.warning(res.message);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 解挂
|
||||
*/
|
||||
function handleActive() {
|
||||
let params = { processInstanceId: data.currTask?.procInstId }; //查询条件
|
||||
createConfirm({
|
||||
title: '确认解挂吗',
|
||||
centered: false,
|
||||
content: '是否解挂该任务?',
|
||||
onOk: async () => {
|
||||
data.confirmLoading = true;
|
||||
let res = await restart(params);
|
||||
data.confirmLoading = false;
|
||||
if (res.success) {
|
||||
createMessage.success(res.message);
|
||||
completeProcess();
|
||||
} else {
|
||||
createMessage.warning(res.message);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
return {
|
||||
handleModalCancel,
|
||||
handleOpt,
|
||||
handleClaim,
|
||||
selectEntruster,
|
||||
handleEntruster,
|
||||
handleActive,
|
||||
handleSuspend,
|
||||
completeProcess,
|
||||
deal,
|
||||
registerModal,
|
||||
isComp,
|
||||
...toRefs(data),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
html[data-theme='light'] {
|
||||
.ant-alert {
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
}
|
||||
}
|
||||
/** Button按钮间距 */
|
||||
.ant-btn {
|
||||
margin-left: 3px;
|
||||
}
|
||||
.ant-alert {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
font-size: 14px;
|
||||
font-variant: tabular-nums;
|
||||
line-height: 1.5715;
|
||||
list-style: none;
|
||||
font-feature-settings: tnum;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 15px;
|
||||
word-wrap: break-word;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.ant-alert-info {
|
||||
background-color: @alert-info-bg-color;
|
||||
border: 1px solid @alert-info-border-color;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<!-- 流程任务处理弹出框 -->
|
||||
<a-modal
|
||||
width="100%"
|
||||
style="top: 0"
|
||||
wrapClassName="full-modal"
|
||||
destroyOnClose
|
||||
:title="data.title"
|
||||
v-model:open="data.visible"
|
||||
:bodyStyle="data.bodyStyle"
|
||||
:footer="null"
|
||||
@cancel="handleModalCancel"
|
||||
>
|
||||
<a-tabs defaultActiveKey="1" tabPosition="left">
|
||||
<a-tab-pane key="1">
|
||||
<template #tab>
|
||||
<Icon icon="ant-design:file-text-outlined" />
|
||||
<span>任务处理</span>
|
||||
</template>
|
||||
<template v-if="data.opt == 'submit'">
|
||||
<BizTaskModal :formData="formData" @complete="completeProcess"></BizTaskModal>
|
||||
</template>
|
||||
<template v-else-if="data.opt == 'reject'">
|
||||
<BizTaskRejectModal :formData="formData" @complete="completeProcess"></BizTaskRejectModal>
|
||||
</template>
|
||||
</a-tab-pane>
|
||||
|
||||
<a-tab-pane key="2">
|
||||
<template #tab>
|
||||
<Icon icon="ant-design:sliders-outlined" />
|
||||
<span>流程图</span>
|
||||
</template>
|
||||
<ProcessDiagram :formData="formData"></ProcessDiagram>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, reactive, toRef } from 'vue';
|
||||
import {getBpmFormUrl, isUrl} from '/src/utils/is';
|
||||
import { getToken } from '/src/utils/auth';
|
||||
import { useGlobSetting } from '/src/hooks/setting';
|
||||
import BizTaskModal from './BizTaskModal.vue';
|
||||
import BizTaskRejectModal from './BizTaskRejectModal.vue';
|
||||
import ProcessDiagram from '/src/views/super/bpm/process/manage/components/ProcessDiagram.vue';
|
||||
|
||||
const globSetting = useGlobSetting();
|
||||
//声明props
|
||||
const props = defineProps({
|
||||
path: { type: String },
|
||||
formData: { type: Object },
|
||||
});
|
||||
// 声明Emits
|
||||
const emit = defineEmits(['success']);
|
||||
|
||||
//数据
|
||||
const data = reactive({
|
||||
loading: false,
|
||||
title: '流程',
|
||||
visible: false,
|
||||
bodyStyle: {
|
||||
padding: '0',
|
||||
height: window.innerHeight - 80 + 'px',
|
||||
'overflow-y': 'auto',
|
||||
},
|
||||
height: window.innerHeight - 120 + 'px',
|
||||
iframeUrl: '',
|
||||
opt: '',
|
||||
});
|
||||
|
||||
let TOKEN = getToken();
|
||||
let DOMAIN_URL = globSetting.domainUrl;
|
||||
let TASKID = props.formData.taskDefKey;
|
||||
//是否组件
|
||||
const isComp = computed(() => {
|
||||
//获取流程审批url
|
||||
//let URL = (props.path || '').replace(/{{([^}}]+)?}}/g, (s1, s2) => eval(s2)); // URL支持{{ window.xxx }}占位符变量
|
||||
let URL = getBpmFormUrl(props.path, TOKEN, DOMAIN_URL, TASKID);
|
||||
|
||||
if (isUrl(URL)) {
|
||||
data.iframeUrl = URL;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
/**
|
||||
* 关闭弹窗
|
||||
*/
|
||||
function completeProcess() {
|
||||
data.visible = false;
|
||||
emit('success');
|
||||
}
|
||||
/**
|
||||
* 关闭弹窗
|
||||
*/
|
||||
function handleModalCancel() {
|
||||
data.visible = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开弹窗前处理
|
||||
* @param record
|
||||
*/
|
||||
function deal(opt) {
|
||||
data.opt = opt;
|
||||
data.visible = true;
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
deal,
|
||||
data,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
@@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<!-- 审批进度弹出框 -->
|
||||
<a-modal
|
||||
width="80%"
|
||||
style="top: 20px"
|
||||
destroyOnClose
|
||||
:title="data.title"
|
||||
v-model:open="data.visible"
|
||||
:bodyStyle="data.bodyStyle"
|
||||
:footer="null"
|
||||
@cancel="handleModalCancel"
|
||||
>
|
||||
<a-tabs defaultActiveKey="1" tabPosition="left">
|
||||
<a-tab-pane key="1">
|
||||
<template #tab>
|
||||
<Icon icon="ant-design:file-text-outlined" />
|
||||
<span>审批记录</span>
|
||||
</template>
|
||||
<HisTaskModule :formData="formData"></HisTaskModule>
|
||||
</a-tab-pane>
|
||||
|
||||
<a-tab-pane key="2">
|
||||
<template #tab>
|
||||
<Icon icon="ant-design:sliders-outlined" />
|
||||
<span>流程跟踪</span>
|
||||
</template>
|
||||
<ProcessDiagram :formData="formData"></ProcessDiagram>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, unref, reactive } from 'vue';
|
||||
import ProcessDiagram from '/src/views/super/bpm/process/manage/components/ProcessDiagram.vue';
|
||||
import HisTaskModule from '/src/views/super/bpm/process/manage/components/HisTaskModule.vue';
|
||||
import { getBizHisProcessNodeInfo } from '/src/views/super/bpm/process/manage/components/bpm.api';
|
||||
//数据
|
||||
const data = reactive({
|
||||
loading: false,
|
||||
title: '流程',
|
||||
visible: false,
|
||||
bodyStyle: {
|
||||
padding: '0',
|
||||
height: window.innerHeight - 80 + 'px',
|
||||
'overflow-y': 'auto',
|
||||
},
|
||||
height: window.innerHeight - 120 + 'px',
|
||||
});
|
||||
|
||||
const formData = ref({});
|
||||
const path = ref('');
|
||||
/**
|
||||
* 关闭弹窗
|
||||
*/
|
||||
function handleModalCancel() {
|
||||
data.visible = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开弹窗前处理
|
||||
* @param record
|
||||
*/
|
||||
async function handleTrack(params) {
|
||||
let res = await getBizHisProcessNodeInfo(params);
|
||||
if (res.success) {
|
||||
console.log('获取流程节点信息', res);
|
||||
formData.value = {
|
||||
dataId: res.result.dataId,
|
||||
procInsId: res.result.procInsId,
|
||||
tableName: res.result.tableName,
|
||||
vars: res.result.records,
|
||||
};
|
||||
path.value = res.result.formUrl;
|
||||
data.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
handleTrack,
|
||||
data,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.ant-tabs-left-content {
|
||||
padding-top: 10px !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<BasicTable @register="registerTable" :rowSelection="rowSelection"> </BasicTable>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { BasicTable } from '/src/components/Table';
|
||||
import { getNotifyList } from '/src/views/super/bpm/process/manage/components/bpm.api.ts';
|
||||
import { useListPage } from '/src/hooks/system/useListPage';
|
||||
import { propTypes } from '/src/utils/propTypes';
|
||||
|
||||
const props = defineProps({
|
||||
procInstId: propTypes.string.def(''),
|
||||
});
|
||||
// 列表页面公共参数、方法
|
||||
const { prefixCls, tableContext } = useListPage({
|
||||
tableProps: {
|
||||
api: getNotifyList,
|
||||
columns: [
|
||||
{
|
||||
title: '流程名称',
|
||||
align: 'center',
|
||||
dataIndex: 'procName',
|
||||
},
|
||||
{
|
||||
title: '任务名称',
|
||||
align: 'center',
|
||||
dataIndex: 'taskName',
|
||||
},
|
||||
{
|
||||
title: '任务处理人',
|
||||
align: 'center',
|
||||
dataIndex: 'taskAssignee',
|
||||
},
|
||||
{
|
||||
title: '催办时间',
|
||||
align: 'center',
|
||||
dataIndex: 'opTime',
|
||||
},
|
||||
{
|
||||
title: '催办类型',
|
||||
align: 'center',
|
||||
dataIndex: 'notifyType',
|
||||
customRender: ({ text }) => {
|
||||
let srtArr = text.split(',');
|
||||
let value = '';
|
||||
if (srtArr.includes('1')) {
|
||||
value += ',页面通知';
|
||||
}
|
||||
if (srtArr.includes('2')) {
|
||||
value += ',邮件';
|
||||
}
|
||||
return value.substring(1);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '催办说明',
|
||||
align: 'center',
|
||||
dataIndex: 'remarks',
|
||||
},
|
||||
],
|
||||
size: 'middle',
|
||||
maxHeight: 200,
|
||||
useSearchForm: false,
|
||||
showTableSetting: false,
|
||||
showActionColumn: false,
|
||||
searchInfo: { procInstId: props.procInstId },
|
||||
},
|
||||
});
|
||||
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||
</script>
|
||||
@@ -0,0 +1,95 @@
|
||||
import { defHttp } from '/src/utils/http/axios';
|
||||
import { Modal } from 'ant-design-vue';
|
||||
enum Api {
|
||||
list = '/joa/biz/extBizLeave/list',
|
||||
add = '/joa/biz/extBizLeave/add',
|
||||
edit = '/joa/biz/extBizLeave/edit',
|
||||
delete = '/joa/biz/extBizLeave/delete',
|
||||
deleteBatch = '/joa/biz/extBizLeave/deleteBatch',
|
||||
queryById = '/joa/biz/extBizLeave/queryById',
|
||||
startProcess = '/act/process/extActProcess/startMutilProcess',
|
||||
invalidProcess = '/act/task/invalidBizProcess',
|
||||
queryFlowDataByCodeAndId = '/act/process/extActFlowData/queryFlowDataByCodeAndId',
|
||||
taskEntrust = '/act/task/taskEntrust',
|
||||
checkNotify = '/act/process/extActFlowData/checkNotify',
|
||||
}
|
||||
/**
|
||||
* 列表
|
||||
* @param params
|
||||
*/
|
||||
export const list = (params) => defHttp.get({ url: Api.list, params });
|
||||
/**
|
||||
* 根据id查询
|
||||
* @param params
|
||||
*/
|
||||
export const queryById = (params) => defHttp.get({ url: Api.queryById, params }, { isTransformResponse: false });
|
||||
/**
|
||||
* 保存或者更新
|
||||
* @param params
|
||||
*/
|
||||
export const saveOrUpdate = (params, isUpdate) => {
|
||||
let url = isUpdate ? Api.edit : Api.add;
|
||||
return defHttp.post({ url: url, params });
|
||||
};
|
||||
/**
|
||||
* 删除
|
||||
*/
|
||||
export const deleteOne = (params, handleSuccess) => {
|
||||
return defHttp.delete({ url: Api.delete, params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 批量删除
|
||||
* @param params
|
||||
*/
|
||||
export const batchDelete = (params, handleSuccess) => {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: '是否删除选中数据',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then((res) => {
|
||||
handleSuccess(res);
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 提交流程
|
||||
* @param params
|
||||
*/
|
||||
export const startProcess = (params) => {
|
||||
return defHttp.post({ url: Api.startProcess, params }, { isTransformResponse: false });
|
||||
};
|
||||
/**
|
||||
* 作废流程
|
||||
* @param params
|
||||
*/
|
||||
export const invalidProcess = (params, handleSuccess) => {
|
||||
return defHttp.put({ url: Api.invalidProcess, params }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 查询流程数据
|
||||
* @param params
|
||||
*/
|
||||
export const queryFlowData = (params, handleSuccess) => {
|
||||
return defHttp.get({ url: Api.queryFlowDataByCodeAndId, params }, { isTransformResponse: false }).then((res) => {
|
||||
handleSuccess(res);
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 查询催办
|
||||
* @param params
|
||||
*/
|
||||
export const checkNotify = (params) => {
|
||||
return defHttp.get({ url: Api.checkNotify, params }, { isTransformResponse: false });
|
||||
};
|
||||
/**
|
||||
* 委派
|
||||
* @param params
|
||||
*/
|
||||
export const taskEntrust = (params) => defHttp.put({ url: Api.taskEntrust, params }, { isTransformResponse: false });
|
||||
@@ -0,0 +1,107 @@
|
||||
import { FormSchema } from '/src/components/Table';
|
||||
import { render } from '/src/utils/common/renderUtils';
|
||||
|
||||
export const columns = [
|
||||
{
|
||||
title: '请假人',
|
||||
dataIndex: 'name',
|
||||
width: 100,
|
||||
slots: { customRender: 'notify' },
|
||||
},
|
||||
{
|
||||
title: '请假天数',
|
||||
dataIndex: 'days',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '开始时间',
|
||||
dataIndex: 'beginDate',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '结束时间',
|
||||
dataIndex: 'endDate',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '请假原因',
|
||||
dataIndex: 'reason',
|
||||
ellipsis: true,
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'bpmStatus',
|
||||
width: 80,
|
||||
customRender: ({ text }) => {
|
||||
return render.renderDict(text, 'bpm_status');
|
||||
},
|
||||
},
|
||||
];
|
||||
export const searchFormSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'bizTaskType',
|
||||
label: '类型',
|
||||
component: 'Input',
|
||||
defaultValue: '1',
|
||||
slot: 'bizTaskType',
|
||||
},
|
||||
{
|
||||
field: 'name',
|
||||
label: '请假人',
|
||||
component: 'Input',
|
||||
},
|
||||
];
|
||||
/**
|
||||
* 表单form
|
||||
*/
|
||||
export const formSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'id',
|
||||
label: '',
|
||||
component: 'Input',
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
label: '请假人',
|
||||
field: 'name',
|
||||
required: true,
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '请假天数',
|
||||
field: 'days',
|
||||
component: 'InputNumber',
|
||||
componentProps: {
|
||||
width: '100%',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '开始时间',
|
||||
field: 'beginDate',
|
||||
component: 'DatePicker',
|
||||
componentProps: {
|
||||
showTime: true,
|
||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
placeholder: '请选择开始时间',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '结束时间',
|
||||
field: 'endDate',
|
||||
component: 'DatePicker',
|
||||
componentProps: {
|
||||
showTime: true,
|
||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
placeholder: '请选择结束时间',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '请假原因',
|
||||
field: 'reason',
|
||||
component: 'InputTextArea',
|
||||
componentProps: {
|
||||
rows: 4
|
||||
}
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,60 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { Modal } from 'ant-design-vue';
|
||||
|
||||
enum Api {
|
||||
list = '/joa/joaBusinesStrip/list',
|
||||
queryById = '/joa/joaBusinesStrip/queryById',
|
||||
save = '/joa/joaBusinesStrip/add',
|
||||
edit = '/joa/joaBusinesStrip/edit',
|
||||
deleteOne = '/joa/joaBusinesStrip/delete',
|
||||
deleteBatch = '/joa/joaBusinesStrip/deleteBatch',
|
||||
getDepartName = '/sys/sysDepart/listAll',
|
||||
}
|
||||
/**
|
||||
* 列表
|
||||
* @param params
|
||||
*/
|
||||
export const list = (params) => defHttp.get({ url: Api.list, params });
|
||||
/**
|
||||
* 获取部门名称
|
||||
* @param params
|
||||
*/
|
||||
export const getDepartName = (params) => defHttp.get({ url: Api.getDepartName, params });
|
||||
/**
|
||||
* 根据id查询
|
||||
* @param params
|
||||
*/
|
||||
export const queryById = (params) => defHttp.get({ url: Api.queryById, params }, { isTransformResponse: false });
|
||||
/**
|
||||
* 删除一个
|
||||
*/
|
||||
export const deleteOne = (params, handleSuccess) => {
|
||||
return defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 批量删除
|
||||
* @param params
|
||||
*/
|
||||
export const batchDelete = (params, handleSuccess) => {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: '是否删除选中数据',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 保存或者更新
|
||||
* @param params
|
||||
*/
|
||||
export const saveOrUpdate = (params, isUpdate) => {
|
||||
let url = isUpdate ? Api.edit : Api.save;
|
||||
return defHttp.post({ url: url, params });
|
||||
};
|
||||
@@ -0,0 +1,78 @@
|
||||
import { FormSchema } from '/@/components/Table';
|
||||
import { render } from '/@/utils/common/renderUtils';
|
||||
export const columns = [
|
||||
{
|
||||
title: '出差人',
|
||||
dataIndex: 'applyUserName',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '部门名称',
|
||||
dataIndex: 'departName',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '项目名称',
|
||||
dataIndex: 'projectName',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '目的地',
|
||||
dataIndex: 'destination',
|
||||
width: 100,
|
||||
slots: { customRender: 'pcaSlot' },
|
||||
},
|
||||
{
|
||||
title: '出发时间',
|
||||
dataIndex: 'departureTime',
|
||||
width: 100,
|
||||
customRender: function ({ text }) {
|
||||
if (!text) {
|
||||
return '';
|
||||
}
|
||||
if (text.length > 10) {
|
||||
return text.substring(0, 10);
|
||||
}
|
||||
return text;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '出差天数',
|
||||
dataIndex: 'dayNum',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '出行工具',
|
||||
dataIndex: 'travelTool',
|
||||
width: 100,
|
||||
customRender: ({ text }) => {
|
||||
if (text == 1) {
|
||||
return '客车';
|
||||
} else if (text == 2) {
|
||||
return '火车';
|
||||
} else if (text == 3) {
|
||||
return '飞机';
|
||||
} else {
|
||||
return text;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '流程状态',
|
||||
align: 'center',
|
||||
dataIndex: 'bpmStatus',
|
||||
width: 100,
|
||||
customRender: ({ text }) => {
|
||||
return render.renderDict(text, 'bpm_status');
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export const searchFormSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'applyUserName',
|
||||
label: '出差人',
|
||||
component: 'Input',
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,180 @@
|
||||
<template>
|
||||
<BasicTable @register="registerTable" :rowSelection="rowSelection">
|
||||
<template #tableTitle>
|
||||
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="handleCreate"> 新增</a-button>
|
||||
<a-dropdown v-if="selectedRowKeys.length > 0">
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item key="1" @click="batchHandleDelete">
|
||||
<Icon icon="ant-design:delete-outlined"></Icon>
|
||||
删除
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
<a-button
|
||||
>批量操作
|
||||
<Icon icon="mdi:chevron-down"></Icon>
|
||||
</a-button>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
<template #pcaSlot="{ text }">
|
||||
{{ getAreaTextByCode(text) }}
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
<!--角色工单授权-->
|
||||
<BusinessTripModal @register="registerModal" @success="reload" />
|
||||
<BpmPictureModal @register="registerBpmModal" />
|
||||
</template>
|
||||
<script lang="ts" name="leave-list" setup>
|
||||
import { ref } from 'vue';
|
||||
import { BasicTable, TableAction } from '/@/components/Table';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import BusinessTripModal from './components/BusinessTripModal.vue';
|
||||
import BpmPictureModal from '/@/views/super/bpm/process/manage/components/BpmPictureModal.vue';
|
||||
import { columns, searchFormSchema } from './business.trip.data';
|
||||
import { list, deleteOne, batchDelete } from './business.trip.api';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
import { startProcess } from '/@/views/super/bpm/example/batch/leave.api';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { getAreaTextByCode } from '/@/components/Form/src/utils/Area';
|
||||
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
const [registerBpmModal, { openModal: bpmPicModal }] = useModal();
|
||||
const { createMessage, createConfirm } = useMessage();
|
||||
|
||||
// 列表页面公共参数、方法
|
||||
const { prefixCls, tableContext } = useListPage({
|
||||
designScope: 'business-trip-list',
|
||||
tableProps: {
|
||||
api: list,
|
||||
columns: columns,
|
||||
canResize: false,
|
||||
formConfig: {
|
||||
schemas: searchFormSchema,
|
||||
},
|
||||
actionColumn: {
|
||||
width: 120,
|
||||
},
|
||||
},
|
||||
});
|
||||
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||
const flowCode = 'joa_biz_trip_01';
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
function handleCreate() {
|
||||
openModal(true, {
|
||||
isUpdate: false,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 编辑
|
||||
*/
|
||||
function handleEdit(record: Recordable) {
|
||||
openModal(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 详情
|
||||
*/
|
||||
function handleDetail(record) {
|
||||
openModal(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
isDetail: true,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 删除事件
|
||||
*/
|
||||
async function handleDelete(record) {
|
||||
await deleteOne({ id: record.id }, reload);
|
||||
}
|
||||
/**
|
||||
* 批量删除事件
|
||||
*/
|
||||
async function batchHandleDelete() {
|
||||
await batchDelete({ ids: selectedRowKeys.value }, reload);
|
||||
}
|
||||
/**
|
||||
* 提交流程
|
||||
*/
|
||||
function handleStartProcess(record) {
|
||||
createConfirm({
|
||||
iconType: 'warning',
|
||||
title: '提示',
|
||||
content: '确认提交流程吗?',
|
||||
onOk: async () => {
|
||||
let res = await startProcess({
|
||||
flowCode: flowCode,
|
||||
id: record.id,
|
||||
formUrl: 'super/bpm/example/joa/businessTrip/components/BusinessTripForm',
|
||||
formUrlMobile: 'applyform/businesStrip',
|
||||
});
|
||||
if (res.success) {
|
||||
createMessage.success(res.message);
|
||||
reload();
|
||||
} else {
|
||||
createMessage.warning(res.message);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 审批进度
|
||||
*/
|
||||
async function handlePreviewPic(record) {
|
||||
bpmPicModal(true, {
|
||||
flowCode,
|
||||
dataId: record.id,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
ifShow: record.bpmStatus === '1',
|
||||
},
|
||||
{
|
||||
label: '提交流程',
|
||||
onClick: handleStartProcess.bind(null, record),
|
||||
ifShow: record.bpmStatus === '1',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 下拉操作栏
|
||||
*/
|
||||
function getDropDownAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '详情',
|
||||
onClick: handleDetail.bind(null, record),
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
confirm: handleDelete.bind(null, record),
|
||||
},
|
||||
ifShow: record.bpmStatus === '1',
|
||||
},
|
||||
{
|
||||
label: '审批进度',
|
||||
onClick: handlePreviewPic.bind(null, record),
|
||||
ifShow: record.bpmStatus !== '1',
|
||||
},
|
||||
];
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,384 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-form ref="formRef" :model="model" :labelCol="labelCol" :wrapperCol="wrapperCol" :rules="validatorRules" style="padding-bottom: 10px">
|
||||
<JFormContainer :disabled="true">
|
||||
<a-card id="staffCard" class="ant-card">
|
||||
<span id="staffEvectionTitle">员工出差申请单</span>
|
||||
<table border="1px" id="staffEvectionTable">
|
||||
<tr>
|
||||
<td class="firstTr">出差人</td>
|
||||
<td class="firstTr" colspan="2">
|
||||
<a-form-item>
|
||||
<span class="fontiframe">{{ nickname }}</span>
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td class="firstTr">部门</td>
|
||||
<td class="firstTr" colspan="2">
|
||||
<a-form-item>
|
||||
<JSelectDept v-model:value="model.departId" :multiple="false" :checkStrictly="true" :showButton="false"></JSelectDept>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 目的地 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item name="destination" class="mudidi">
|
||||
<JAreaLinkage placeholder="请选择" v-model:value="model.destination" :showArea="true" :showAll="false" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 项目名称 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item name="projectName">
|
||||
<a-input class="text" v-model:value="model.projectName" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 出发时间 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-date-picker class="input" @change="difference" format="YYYY-MM-DD" v-model:value="model.departureTime" :allowClear="false" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 计划返回时间 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-date-picker class="input" @change="difference" format="YYYY-MM-DD" v-model:value="model.plannedReturnTime" :allowClear="false" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 实际返回时间 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-date-picker class="input" placeholder="" format="YYYY-MM-DD" v-model:value="model.actualReturnTime" :allowClear="false" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 出差天数 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-input class="text" v-model:value="model.dayNum" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 出差经费支出 </td>
|
||||
<td colspan="5">
|
||||
<a-form-item>
|
||||
<a-radio-group class="fontiframe" name="radioGroup" v-model:value="model.travelExpensesType">
|
||||
<a-radio class="radioGroup" value="1">预支借款</a-radio>
|
||||
<a-radio class="radioGroup" value="2">个人垫付</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 出发地 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<JAreaLinkage v-model:value="model.departAddress" placeholder="请选择" :showArea="true" :showAll="false" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 出行工具 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-radio-group class="fontiframe" name="radioGroup" v-model:value="model.travelTool">
|
||||
<a-radio class="radioGroup" :value="1">客车</a-radio>
|
||||
<a-radio class="radioGroup" :value="2">火车</a-radio>
|
||||
<a-radio class="radioGroup" :value="3">飞机</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 任务及事由 </td>
|
||||
<td colspan="5">
|
||||
<a-form-item>
|
||||
<a-textarea v-model:value="model.reason" class="textArea"></a-textarea>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="height: 38px">
|
||||
<td> 部门领导审核 </td>
|
||||
<td colspan="2">
|
||||
<span>{{ model.departLeaderAudit }}</span>
|
||||
</td>
|
||||
<td> 财务审核 </td>
|
||||
<td colspan="2">
|
||||
<span>{{ model.financeAudit }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="height: 38px">
|
||||
<td> 出纳放款 </td>
|
||||
<td colspan="2">
|
||||
<span>{{ model.cashierLoanAmount }}</span>
|
||||
</td>
|
||||
<td> 总经理审核 </td>
|
||||
<td colspan="2">
|
||||
<span>{{ model.managerAudit }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</a-card>
|
||||
</JFormContainer>
|
||||
</a-form>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, unref, reactive, toRaw } from 'vue';
|
||||
import JAreaLinkage from '/@/components/Form/src/jeecg/components/JAreaLinkage.vue';
|
||||
import JSelectDept from '/@/components/Form/src/jeecg/components/JSelectDept.vue';
|
||||
import JFormContainer from '/@/components/Form/src/jeecg/components/JFormContainer.vue';
|
||||
import { getRealCode } from '/@/components/Form/src/utils/areaDataUtil.js';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import { queryById } from '../business.trip.api';
|
||||
import dayjs from "dayjs";
|
||||
// props声明
|
||||
const props = defineProps({
|
||||
formData: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
const userStore = useUserStore();
|
||||
const formRef = ref(null);
|
||||
const nickname = ref(userStore.getUserInfo?.realname);
|
||||
const model = reactive({
|
||||
applyUserName: '',
|
||||
departId: '',
|
||||
destination: '',
|
||||
projectName: '',
|
||||
departureTime: null,
|
||||
plannedReturnTime: null,
|
||||
actualReturnTime: null,
|
||||
dayNum: 0,
|
||||
travelExpensesType: '1',
|
||||
departAddress: '',
|
||||
travelTool: 1,
|
||||
reason: '',
|
||||
departLeaderAudit: '',
|
||||
financeAudit: '',
|
||||
cashierLoanAmount: '',
|
||||
managerAudit: '',
|
||||
});
|
||||
//表单校验
|
||||
const validatorRules = {
|
||||
destination: [{ required: true, message: '目的地不能为空!' }],
|
||||
projectName: [{ required: true, message: '请输入项目名称!' }],
|
||||
};
|
||||
|
||||
const labelCol = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 3 },
|
||||
};
|
||||
const wrapperCol = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 21 },
|
||||
};
|
||||
|
||||
async function initFormData() {
|
||||
let res = await queryById({ id: props.formData.dataId });
|
||||
if (res.success) {
|
||||
console.log('获取流程节点信息', res);
|
||||
let obj = res.result;
|
||||
//表单赋值
|
||||
obj.destination = getRealCode(obj.destination, 3);
|
||||
obj.departAddress && (obj.departAddress = getRealCode(obj.departAddress, 3));
|
||||
Object.assign(model, { ...obj });
|
||||
|
||||
//时间格式化(升级antd3后,时间值不允许是字符串)
|
||||
model.departureTime = model.departureTime?dayjs(model.departureTime,'YYYY-MM-DD'):null;
|
||||
model.plannedReturnTime = model.plannedReturnTime?dayjs(model.plannedReturnTime,'YYYY-MM-DD'):null;
|
||||
model.actualReturnTime = model.actualReturnTime?dayjs(model.actualReturnTime,'YYYY-MM-DD'):null;
|
||||
}
|
||||
}
|
||||
initFormData();
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
html[data-theme='light'] {
|
||||
.ant-card {
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
background: #fff;
|
||||
border: 1px solid #e8e8e8;
|
||||
}
|
||||
#staffCard {
|
||||
border: 1px solid #fff;
|
||||
box-shadow:
|
||||
0 0 1px 1px #aaa,
|
||||
3px 0 5px 0 #aaa,
|
||||
0 4px 7px 0 #aaa;
|
||||
}
|
||||
#staffEvectionTitle {
|
||||
color: black;
|
||||
}
|
||||
#staffEvectionTable {
|
||||
background-color: #fff;
|
||||
border: 1px solid #000;
|
||||
|
||||
tr,
|
||||
th {
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
td,
|
||||
th {
|
||||
border-right: 1px solid #000;
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
.input {
|
||||
:deep(.ant-input) {
|
||||
border: 0 solid black !important;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
.ant-input {
|
||||
border: 0 solid black !important;
|
||||
background-color: #fff;
|
||||
}
|
||||
.text {
|
||||
background-color: #fff;
|
||||
}
|
||||
.firstTr {
|
||||
color: #000;
|
||||
}
|
||||
.smallText .ant-input-number-input {
|
||||
background-color: #fff;
|
||||
}
|
||||
.textArea {
|
||||
border: 0 solid white;
|
||||
}
|
||||
:deep(.ant-input-number) {
|
||||
border: 0 solid black !important;
|
||||
}
|
||||
}
|
||||
/**去掉日期控件边框*/
|
||||
.ant-picker {
|
||||
border: 0 solid black !important;
|
||||
}
|
||||
}
|
||||
html[data-theme='dark'] {
|
||||
@borderColor: #3a3a3a;
|
||||
#staffEvectionTable {
|
||||
border: 1px solid @borderColor;
|
||||
tr,
|
||||
th {
|
||||
border-bottom: 1px solid @borderColor;
|
||||
}
|
||||
td,
|
||||
th {
|
||||
border-right: 1px solid @borderColor;
|
||||
border-bottom: 1px solid @borderColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ant-card {
|
||||
border-radius: 2px;
|
||||
margin: 0 auto;
|
||||
width: 1000px;
|
||||
}
|
||||
|
||||
#staffCard {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 5px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#staffEvectionTitle {
|
||||
margin-top: 1px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
display: block;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
#staffEvectionTable {
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
|
||||
|
||||
tr td:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
tr:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.fontiframe {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.ant-form-item {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.input {
|
||||
:deep(.ant-input) {
|
||||
border-radius: 0;
|
||||
display: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-input {
|
||||
border-radius: 0;
|
||||
display: inherit;
|
||||
margin: 0;
|
||||
width: 255px;
|
||||
}
|
||||
|
||||
:deep(.ant-calendar-picker-input) {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.text {
|
||||
border: none !important;
|
||||
border-radius: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.textArea {
|
||||
resize: none;
|
||||
height: 98px;
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
border-radius: 0px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.colfirst {
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.colfour {
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.firstTr {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.radioGroup {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.smallText .ant-input-number-input {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
:deep(.ant-input-number) {
|
||||
border: 0 solid black !important;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**去掉地区控件边框、字号改小*/
|
||||
:deep(.ant-select:not(.ant-select-customize-input) .ant-select-selector){
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,484 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit" width="1200px">
|
||||
<a-form ref="formRef" :model="model" :labelCol="labelCol" :wrapperCol="wrapperCol" :rules="validatorRules" style="padding-bottom: 10px">
|
||||
<JFormContainer :disabled="formDisabled">
|
||||
<a-card id="staffCard" class="ant-card">
|
||||
<span id="staffEvectionTitle">员工出差申请单</span>
|
||||
<table border="1px" id="staffEvectionTable">
|
||||
<tr>
|
||||
<td class="firstTr">出差人</td>
|
||||
<td class="firstTr" colspan="2">
|
||||
<a-form-item>
|
||||
<span class="fontiframe">{{ nickname }}</span>
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td class="firstTr">部门</td>
|
||||
<td class="firstTr" colspan="2">
|
||||
<a-form-item>
|
||||
<JSelectDept v-model:value="model.departId" :multiple="false" :checkStrictly="true" :showButton="false"></JSelectDept>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 目的地 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item name="destination" class="mudidi">
|
||||
<JAreaLinkage placeholder="请选择" v-model:value="model.destination" :showArea="true" :showAll="false" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 项目名称 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item name="projectName">
|
||||
<a-input class="text" v-model:value="model.projectName" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 出发时间 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-date-picker class="input" @change="difference" format="YYYY-MM-DD" v-model:value="model.departureTime" :allowClear="false" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 计划返回时间 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-date-picker class="input" @change="difference" format="YYYY-MM-DD" v-model:value="model.plannedReturnTime" :allowClear="false" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 实际返回时间 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-date-picker class="input" placeholder="" format="YYYY-MM-DD" v-model:value="model.actualReturnTime" :allowClear="false" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 出差天数 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-input class="text" v-model:value="model.dayNum" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 出差经费支出 </td>
|
||||
<td colspan="5">
|
||||
<a-form-item>
|
||||
<a-radio-group class="fontiframe" name="radioGroup" v-model:value="model.travelExpensesType">
|
||||
<a-radio class="radioGroup" value="1">预支借款</a-radio>
|
||||
<a-radio class="radioGroup" value="2">个人垫付</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 出发地 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item class="mudidi">
|
||||
<JAreaLinkage v-model:value="model.departAddress" placeholder="请选择" :showArea="true" :showAll="false" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 出行工具 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-radio-group class="fontiframe" name="radioGroup" v-model:value="model.travelTool">
|
||||
<a-radio class="radioGroup" :value="1">客车</a-radio>
|
||||
<a-radio class="radioGroup" :value="2">火车</a-radio>
|
||||
<a-radio class="radioGroup" :value="3">飞机</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 任务及事由 </td>
|
||||
<td colspan="5">
|
||||
<a-form-item>
|
||||
<a-textarea v-model:value="model.reason" class="textArea"></a-textarea>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="height: 38px">
|
||||
<td> 部门领导审核 </td>
|
||||
<td colspan="2">
|
||||
<span>{{ model.departLeaderAudit }}</span>
|
||||
</td>
|
||||
<td> 财务审核 </td>
|
||||
<td colspan="2">
|
||||
<span>{{ model.financeAudit }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="height: 38px">
|
||||
<td> 出纳放款 </td>
|
||||
<td colspan="2">
|
||||
<span>{{ model.cashierLoanAmount }}</span>
|
||||
</td>
|
||||
<td> 总经理审核 </td>
|
||||
<td colspan="2">
|
||||
<span>{{ model.managerAudit }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</a-card>
|
||||
</JFormContainer>
|
||||
</a-form>
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, unref, reactive, toRaw } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import JAreaLinkage from '/@/components/Form/src/jeecg/components/JAreaLinkage.vue';
|
||||
import JSelectDept from '/@/components/Form/src/jeecg/components/JSelectDept.vue';
|
||||
import JFormContainer from '/@/components/Form/src/jeecg/components/JFormContainer.vue';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { saveOrUpdate, getDepartName } from '../business.trip.api';
|
||||
import { formatToDateTime } from '/@/utils/dateUtil';
|
||||
import { getRealCode } from '/@/components/Form/src/utils/areaDataUtil.js';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import dayjs from "dayjs";
|
||||
// Emits声明
|
||||
const emit = defineEmits(['register', 'success']);
|
||||
//提示弹窗
|
||||
const $message = useMessage();
|
||||
const userStore = useUserStore();
|
||||
const isUpdate = ref(true);
|
||||
const formRef = ref(null);
|
||||
const nickname = ref(userStore.getUserInfo?.realname);
|
||||
const formDisabled = ref(false);
|
||||
const model = reactive({
|
||||
applyUserName: '',
|
||||
departId: '',
|
||||
destination: '',
|
||||
projectName: '',
|
||||
departureTime: null,
|
||||
plannedReturnTime: null,
|
||||
actualReturnTime: null,
|
||||
dayNum: 0,
|
||||
travelExpensesType: '1',
|
||||
departAddress: '',
|
||||
travelTool: 1,
|
||||
reason: '',
|
||||
departLeaderAudit: '',
|
||||
financeAudit: '',
|
||||
cashierLoanAmount: '',
|
||||
managerAudit: '',
|
||||
});
|
||||
//表单校验
|
||||
const validatorRules = {
|
||||
destination: [{ required: true, message: '目的地不能为空!' }],
|
||||
projectName: [{ required: true, message: '请输入项目名称!' }],
|
||||
};
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
setModalProps({ confirmLoading: false, showOkBtn: !!!data?.isDetail });
|
||||
isUpdate.value = !!data?.isUpdate;
|
||||
if (unref(isUpdate)) {
|
||||
//转换地区选择组件数据格式复核要求
|
||||
let obj = { ...data.record };
|
||||
obj.destination = getRealCode(obj.destination, 3);
|
||||
obj.departAddress && (obj.departAddress = getRealCode(obj.departAddress, 3));
|
||||
Object.assign(model, { ...obj });
|
||||
} else {
|
||||
Object.assign(model, { ...initData });
|
||||
}
|
||||
|
||||
//时间格式化(升级antd3后,时间值不允许是字符串)
|
||||
model.departureTime = model.departureTime?dayjs(model.departureTime,'YYYY-MM-DD'):null;
|
||||
model.plannedReturnTime = model.plannedReturnTime?dayjs(model.plannedReturnTime,'YYYY-MM-DD'):null;
|
||||
model.actualReturnTime = model.actualReturnTime?dayjs(model.actualReturnTime,'YYYY-MM-DD'):null;
|
||||
|
||||
// update-begin-author:taoyan date:2022-9-5 for: VUEN-2157 出差申请、借款申请、请假申请、公文申请都有这个问题,详情不让改
|
||||
if(data.isDetail === true){
|
||||
formDisabled.value = true;
|
||||
}else{
|
||||
formDisabled.value = false;
|
||||
}
|
||||
// update-end-author:taoyan date:2022-9-5 for: VUEN-2157 出差申请、借款申请、请假申请、公文申请都有这个问题,详情不让改
|
||||
});
|
||||
//设置标题
|
||||
const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
|
||||
|
||||
//表单提交事件
|
||||
function handleSubmit() {
|
||||
try {
|
||||
formRef.value
|
||||
.validate()
|
||||
.then(async () => {
|
||||
let formData = toRaw(unref(model));
|
||||
//时间格式化
|
||||
formData.departureTime = formData.departureTime ? formatToDateTime(formData.departureTime, 'YYYY-MM-DD HH:mm:ss') : null;
|
||||
formData.plannedReturnTime = formData.plannedReturnTime ? formatToDateTime(formData.plannedReturnTime, 'YYYY-MM-DD HH:mm:ss') : null;
|
||||
formData.actualReturnTime = formData.actualReturnTime ? formatToDateTime(formData.actualReturnTime, 'YYYY-MM-DD HH:mm:ss') : null;
|
||||
formData.cashierLoanTime = formData.cashierLoanTime ? formatToDateTime(formData.cashierLoanTime, 'YYYY-MM-DD HH:mm:ss') : null;
|
||||
//地区数据处理
|
||||
formData.destination = formData.destination ? formData.destination[2] : '';
|
||||
formData.departAddress = formData.departAddress ? formData.departAddress[2] : '';
|
||||
|
||||
if (formData.departId) {
|
||||
let result = await getDepartName({ id: formData.departId });
|
||||
formData.departName = result[0].departName;
|
||||
}
|
||||
setModalProps({ confirmLoading: true });
|
||||
//提交表单
|
||||
await saveOrUpdate(formData, isUpdate.value);
|
||||
//关闭弹窗
|
||||
closeModal();
|
||||
//刷新列表
|
||||
emit('success');
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log('error', error);
|
||||
});
|
||||
} finally {
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
|
||||
const labelCol = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 3 },
|
||||
};
|
||||
const wrapperCol = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 21 },
|
||||
};
|
||||
//初始化数据
|
||||
const initData = {
|
||||
applyUserName: userStore.getUserInfo?.username,
|
||||
departId: '',
|
||||
destination: '',
|
||||
projectName: '',
|
||||
departureTime: null,
|
||||
plannedReturnTime: null,
|
||||
actualReturnTime: null,
|
||||
dayNum: 0,
|
||||
travelExpensesType: '1',
|
||||
departAddress: '',
|
||||
travelTool: 1,
|
||||
reason: '',
|
||||
departLeaderAudit: '',
|
||||
financeAudit: '',
|
||||
cashierLoanAmount: '',
|
||||
managerAudit: '',
|
||||
};
|
||||
/**
|
||||
* 获取当前时间
|
||||
*/
|
||||
function nowTimes() {
|
||||
let date = new Date();
|
||||
let year = date.getFullYear();
|
||||
let month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1;
|
||||
let day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
|
||||
return dayjs(year + '-' + month + '-' + day);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算天数
|
||||
*/
|
||||
function difference() {
|
||||
let data = toRaw(unref(model));
|
||||
if (data.departureTime && data.plannedReturnTime) {
|
||||
let beginTime = formatToDateTime(data.departureTime, 'YYYY-MM-DD HH:mm:ss');
|
||||
let endTime = formatToDateTime(data.plannedReturnTime, 'YYYY-MM-DD HH:mm:ss');
|
||||
if (beginTime != '' && endTime != '') {
|
||||
let dateBegin = new Date(beginTime);
|
||||
let dateEnd = new Date(endTime);
|
||||
let dateDiff = dateEnd.getTime() - dateBegin.getTime(); //时间差的毫秒数
|
||||
let dayDiff = Math.floor(dateDiff / (24 * 3600 * 1000)); //计算出相差天数
|
||||
if (dayDiff < 0) {
|
||||
$message.createMessage.warning('结束时间不能小于开始时间');
|
||||
model.dayNum = 0;
|
||||
} else {
|
||||
model.dayNum = dayDiff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
html[data-theme='light'] {
|
||||
.ant-card {
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
background: #fff;
|
||||
border: 1px solid #e8e8e8;
|
||||
}
|
||||
#staffCard {
|
||||
border: 1px solid #fff;
|
||||
box-shadow:
|
||||
0 0 1px 1px #aaa,
|
||||
3px 0 5px 0 #aaa,
|
||||
0 4px 7px 0 #aaa;
|
||||
}
|
||||
#documentsIssuedTitle {
|
||||
color: black;
|
||||
}
|
||||
#staffEvectionTable {
|
||||
background-color: #fff;
|
||||
border: 1px solid #000;
|
||||
|
||||
tr,
|
||||
th {
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
td,
|
||||
th {
|
||||
border-right: 1px solid #000;
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
.input {
|
||||
:deep(.ant-input) {
|
||||
border: 0 solid black !important;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
.ant-input {
|
||||
border: 0 solid black !important;
|
||||
background-color: #fff;
|
||||
}
|
||||
.text {
|
||||
background-color: #fff;
|
||||
}
|
||||
.firstTr {
|
||||
color: #000;
|
||||
}
|
||||
.smallText .ant-input-number-input {
|
||||
background-color: #fff;
|
||||
}
|
||||
.textArea {
|
||||
border: 0 solid white;
|
||||
}
|
||||
:deep(.ant-input-number) {
|
||||
border: 0 solid black !important;
|
||||
}
|
||||
}
|
||||
/**去掉日期控件边框*/
|
||||
.ant-picker {
|
||||
border: 0 solid black !important;
|
||||
}
|
||||
}
|
||||
html[data-theme='dark'] {
|
||||
@borderColor: #3a3a3a;
|
||||
#staffEvectionTable {
|
||||
border: 1px solid @borderColor;
|
||||
tr,
|
||||
th {
|
||||
border-bottom: 1px solid @borderColor;
|
||||
}
|
||||
td,
|
||||
th {
|
||||
border-right: 1px solid @borderColor;
|
||||
border-bottom: 1px solid @borderColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ant-card {
|
||||
border-radius: 2px;
|
||||
margin: 0 auto;
|
||||
width: 1000px;
|
||||
}
|
||||
|
||||
#staffCard {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 5px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#staffEvectionTitle {
|
||||
margin-top: 1px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
display: block;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
#staffEvectionTable {
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
|
||||
tr td:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
tr:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.fontiframe {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.ant-form-item {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.input {
|
||||
:deep(.ant-input) {
|
||||
border-radius: 0;
|
||||
display: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-input {
|
||||
border-radius: 0;
|
||||
display: inherit;
|
||||
margin: 0;
|
||||
width: 255px;
|
||||
}
|
||||
|
||||
:deep(.ant-calendar-picker-input) {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.text {
|
||||
border: none !important;
|
||||
border-radius: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.textArea {
|
||||
resize: none;
|
||||
box-shadow: none;
|
||||
height: 98px;
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
border-radius: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.colfirst {
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.colfour {
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.firstTr {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.radioGroup {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.smallText .ant-input-number-input {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
:deep(.ant-input-number) {
|
||||
border: 0 solid black !important;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
/**去掉地区控件边框、字号改小*/
|
||||
.ant-select:not(.ant-select-customize-input) .ant-select-selector{
|
||||
font-size: 12px;
|
||||
border: 0 solid black !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,389 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-form ref="formRef" :model="model" :labelCol="labelCol" :wrapperCol="wrapperCol" :rules="validatorRules" style="padding-bottom: 10px">
|
||||
<JFormContainer :disabled="true">
|
||||
<a-card id="staffCard" class="ant-card">
|
||||
<span id="documentsIssuedTitle">发文单</span>
|
||||
<table border="1px" id="documentsIssueTable">
|
||||
<tr>
|
||||
<td class="firstTr">公文标题</td>
|
||||
<td class="firstTr" colspan="2">
|
||||
<a-form-item name="title">
|
||||
<a-input class="text" v-model:value="model.title" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td class="firstTr">发文字号</td>
|
||||
<td class="firstTr" colspan="2">
|
||||
<a-form-item>
|
||||
<a-input style="text-align: left" class="text" readOnly placeholder="< 系统自动生成 >" v-model:value="model.docCode" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 公文分类 </td>
|
||||
<td colspan="2" style="width: 200px">
|
||||
<a-form-item :wrapperCol="{ xs: { span: 20 } }">
|
||||
<a-radio-group class="fontiframe" name="radioGroup" v-model:value="model.docType">
|
||||
<a-radio class="radioGroup" value="1">普通文件</a-radio>
|
||||
<a-radio class="radioGroup" value="2">盖章文件</a-radio>
|
||||
<a-radio class="radioGroup" value="3">正式文件</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 文种 </td>
|
||||
<td colspan="2" style="width: 200px">
|
||||
<a-form-item>
|
||||
<a-select v-model:value="model.classification">
|
||||
<a-select-option value="1">公告</a-select-option>
|
||||
<a-select-option value="2">通知</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 缓急程度 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item :wrapperCol="{ xs: { span: 15 } }">
|
||||
<a-radio-group class="fontiframe" name="radioGroup" v-model:value="model.urgency">
|
||||
<a-radio class="radioGroup" value="1">普通</a-radio>
|
||||
<a-radio class="radioGroup" value="2">特急</a-radio>
|
||||
<a-radio class="radioGroup" value="3">紧急</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 印刷份数 </td>
|
||||
<td>
|
||||
<a-form-item>
|
||||
<a-input class="text" v-model:value="model.printScore" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 发文目标 </td>
|
||||
<td colspan="2" style="width: 260px">
|
||||
<a-form-item :wrapperCol="{ xs: { span: 23 } }">
|
||||
<a-radio-group class="fontiframe" name="radioGroup" v-model:value="model.sendTarget">
|
||||
<a-radio class="radioGroup" value="1">公司内</a-radio>
|
||||
<a-radio class="radioGroup" value="2">公司外</a-radio>
|
||||
<a-radio class="radioGroup" value="3">子公司</a-radio>
|
||||
<a-radio class="radioGroup" value="4">主公司</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 机密程度 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item :wrapperCol="{ xs: { span: 20 } }">
|
||||
<a-radio-group class="fontiframe" name="radioGroup" v-model:value="model.confidentiality">
|
||||
<a-radio class="radioGroup" value="1">公开</a-radio>
|
||||
<a-radio class="radioGroup" value="2">秘密</a-radio>
|
||||
<a-radio class="radioGroup" value="3">机密</a-radio>
|
||||
<a-radio class="radioGroup" value="4">绝密</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td> 机关代字 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-input class="text" v-model:value="model.officeCode" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 排序码 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-input-number class="text" v-model:value="model.orderNo" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td> 主题词 </td>
|
||||
<td colspan="5">
|
||||
<a-form-item>
|
||||
<a-textarea v-model:value="model.theme" class="textArea"></a-textarea>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 收文人 </td>
|
||||
<td colspan="5">
|
||||
<a-form-item>
|
||||
<a-textarea v-model:value="model.receiverName" class="textArea"></a-textarea>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="height: 35px">
|
||||
<td> 文件 </td>
|
||||
<td colspan="5"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 登记人 </td>
|
||||
<td colspan="2">
|
||||
<span>{{ nickname }}</span>
|
||||
</td>
|
||||
<td> 登记时间 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-date-picker class="input" placeholder="" format="YYYY-MM-DD" v-model:value="model.bookDate" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 成文日期 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-date-picker class="input" placeholder="" format="YYYY-MM-DD" v-model:value="model.writtenDate" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 审阅时间 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-date-picker class="input" placeholder="" format="YYYY-MM-DD" v-model:value="model.reviewDate" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</a-card>
|
||||
</JFormContainer>
|
||||
</a-form>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, unref, reactive, toRaw } from 'vue';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import JFormContainer from '/@/components/Form/src/jeecg/components/JFormContainer.vue';
|
||||
import { queryById } from '../doc.send.api';
|
||||
import dayjs from "dayjs";
|
||||
// props声明
|
||||
const props = defineProps({
|
||||
formData: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
const userStore = useUserStore();
|
||||
const formRef = ref(null);
|
||||
const nickname = ref(userStore.getUserInfo?.realname);
|
||||
const model = reactive({
|
||||
id: '',
|
||||
title: '',
|
||||
docCode: '',
|
||||
docType: '1',
|
||||
classification: '1',
|
||||
urgency: '1',
|
||||
printScore: 0,
|
||||
sendTarget: '1',
|
||||
confidentiality: '1',
|
||||
officeCode: '',
|
||||
orderNo: '',
|
||||
theme: '',
|
||||
receiverName: '',
|
||||
bookDate: null,
|
||||
writtenDate: null,
|
||||
reviewDate: null,
|
||||
});
|
||||
|
||||
const labelCol = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 5 },
|
||||
};
|
||||
const wrapperCol = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 24 },
|
||||
};
|
||||
|
||||
async function initFormData() {
|
||||
let res = await queryById({ id: props.formData.dataId });
|
||||
console.log('DocSendForm获取流程节点信息', res);
|
||||
if (res.success) {
|
||||
let obj = res.result;
|
||||
//表单赋值
|
||||
Object.assign(model, { ...obj });
|
||||
|
||||
//时间格式化(升级antd3后,时间值不允许是字符串)
|
||||
model.bookDate = model.bookDate?dayjs(model.bookDate,'YYYY-MM-DD'):null;
|
||||
model.writtenDate = model.writtenDate?dayjs(model.writtenDate,'YYYY-MM-DD'):null;
|
||||
model.reviewDate = model.reviewDate?dayjs(model.reviewDate,'YYYY-MM-DD'):null;
|
||||
}
|
||||
}
|
||||
initFormData();
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
html[data-theme='light'] {
|
||||
.ant-card {
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
background: #fff;
|
||||
border: 1px solid #e8e8e8;
|
||||
}
|
||||
#staffCard {
|
||||
border: 1px solid #fff;
|
||||
box-shadow:
|
||||
0 0 1px 1px #aaa,
|
||||
3px 0 5px 0 #aaa,
|
||||
0 4px 7px 0 #aaa;
|
||||
}
|
||||
#documentsIssuedTitle {
|
||||
color: black;
|
||||
}
|
||||
#documentsIssueTable {
|
||||
background-color: #fff;
|
||||
border: 1px solid #000;
|
||||
tr,
|
||||
th {
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
td,
|
||||
th {
|
||||
border-right: 1px solid #000;
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
.input {
|
||||
:deep(.ant-input) {
|
||||
border: 0 solid black !important;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
.ant-input {
|
||||
border: 0 solid black !important;
|
||||
background-color: #fff;
|
||||
}
|
||||
.text {
|
||||
background-color: #fff;
|
||||
}
|
||||
.firstTr {
|
||||
color: #000;
|
||||
}
|
||||
.smallText .ant-input-number-input {
|
||||
background-color: #fff;
|
||||
}
|
||||
.textArea {
|
||||
border: 0 solid white;
|
||||
}
|
||||
}
|
||||
/**去掉日期控件边框*/
|
||||
.ant-picker {
|
||||
border: 0 solid black !important;
|
||||
}
|
||||
}
|
||||
html[data-theme='dark'] {
|
||||
@borderColor: #3a3a3a;
|
||||
#documentsIssueTable {
|
||||
border: 1px solid @borderColor;
|
||||
}
|
||||
tr,
|
||||
th {
|
||||
border-bottom: 1px solid @borderColor;
|
||||
}
|
||||
td,
|
||||
th {
|
||||
border-right: 1px solid @borderColor;
|
||||
border-bottom: 1px solid @borderColor;
|
||||
}
|
||||
}
|
||||
.ant-card {
|
||||
border-radius: 2px;
|
||||
margin: 0 auto;
|
||||
width: 1000px;
|
||||
}
|
||||
|
||||
#staffCard {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 5px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#documentsIssuedTitle {
|
||||
margin-top: 1px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
display: block;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
#documentsIssueTable {
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
|
||||
tr td:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
tr:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.fontiframe {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.ant-form-item {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.input {
|
||||
:deep(.ant-input) {
|
||||
border-radius: 0;
|
||||
display: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-input {
|
||||
border-radius: 0;
|
||||
display: inherit;
|
||||
margin: 0;
|
||||
width: 255px;
|
||||
}
|
||||
|
||||
:deep(.ant-calendar-picker-input) {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.text {
|
||||
border: none !important;
|
||||
border-radius: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.textArea {
|
||||
resize: none;
|
||||
box-shadow: none;
|
||||
height: 98px;
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
border-radius: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.colfirst {
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.colfour {
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.firstTr {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.radioGroup {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.smallText .ant-input-number-input {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
:deep(.ant-input-number) {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,451 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit" width="1200px">
|
||||
<a-form ref="formRef" :model="model" :labelCol="labelCol" :wrapperCol="wrapperCol" :rules="validatorRules" style="padding-bottom: 10px">
|
||||
<JFormContainer :disabled="formDisabled">
|
||||
<a-card id="staffCard" class="ant-card">
|
||||
<span id="documentsIssuedTitle">发文单</span>
|
||||
<table border="1px" id="documentsIssueTable">
|
||||
<tr>
|
||||
<td class="firstTr">公文标题</td>
|
||||
<td class="firstTr" colspan="2">
|
||||
<a-form-item name="title">
|
||||
<a-input class="text" v-model:value="model.title" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td class="firstTr">发文字号</td>
|
||||
<td class="firstTr" colspan="2">
|
||||
<a-form-item>
|
||||
<a-input style="text-align: left" class="text" readOnly placeholder="< 系统自动生成 >" v-model:value="model.docCode" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 公文分类 </td>
|
||||
<td colspan="2" style="width: 200px">
|
||||
<a-form-item :wrapperCol="{ xs: { span: 20 } }">
|
||||
<a-radio-group class="fontiframe" name="radioGroup" v-model:value="model.docType">
|
||||
<a-radio class="radioGroup" value="1">普通文件</a-radio>
|
||||
<a-radio class="radioGroup" value="2">盖章文件</a-radio>
|
||||
<a-radio class="radioGroup" value="3">正式文件</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 文种 </td>
|
||||
<td colspan="2" style="width: 200px">
|
||||
<a-form-item>
|
||||
<a-select v-model:value="model.classification">
|
||||
<a-select-option value="1">公告</a-select-option>
|
||||
<a-select-option value="2">通知</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 缓急程度 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item :wrapperCol="{ xs: { span: 15 } }">
|
||||
<a-radio-group class="fontiframe" name="radioGroup" v-model:value="model.urgency">
|
||||
<a-radio class="radioGroup" value="1">普通</a-radio>
|
||||
<a-radio class="radioGroup" value="2">特急</a-radio>
|
||||
<a-radio class="radioGroup" value="3">紧急</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 印刷份数 </td>
|
||||
<td>
|
||||
<a-form-item>
|
||||
<a-input class="text" v-model:value="model.printScore" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 发文目标 </td>
|
||||
<td colspan="2" style="width: 260px">
|
||||
<a-form-item :wrapperCol="{ xs: { span: 23 } }">
|
||||
<a-radio-group class="fontiframe" name="radioGroup" v-model:value="model.sendTarget">
|
||||
<a-radio class="radioGroup" value="1">公司内</a-radio>
|
||||
<a-radio class="radioGroup" value="2">公司外</a-radio>
|
||||
<a-radio class="radioGroup" value="3">子公司</a-radio>
|
||||
<a-radio class="radioGroup" value="4">主公司</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 机密程度 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item :wrapperCol="{ xs: { span: 20 } }">
|
||||
<a-radio-group class="fontiframe" name="radioGroup" v-model:value="model.confidentiality">
|
||||
<a-radio class="radioGroup" value="1">公开</a-radio>
|
||||
<a-radio class="radioGroup" value="2">秘密</a-radio>
|
||||
<a-radio class="radioGroup" value="3">机密</a-radio>
|
||||
<a-radio class="radioGroup" value="4">绝密</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td> 机关代字 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-input class="text" v-model:value="model.officeCode" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 排序码 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-input-number class="text" v-model:value="model.orderNo" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td> 主题词 </td>
|
||||
<td colspan="5">
|
||||
<a-form-item>
|
||||
<a-textarea v-model:value="model.theme" class="textArea"></a-textarea>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 收文人 </td>
|
||||
<td colspan="5">
|
||||
<a-form-item>
|
||||
<a-textarea v-model:value="model.receiverName" class="textArea"></a-textarea>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="height: 35px">
|
||||
<td> 文件 </td>
|
||||
<td colspan="5"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 登记人 </td>
|
||||
<td colspan="2">
|
||||
<span>{{ nickname }}</span>
|
||||
</td>
|
||||
<td> 登记时间 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-date-picker class="input" placeholder="" format="YYYY-MM-DD" v-model:value="model.bookDate" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 成文日期 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-date-picker class="input" placeholder="" format="YYYY-MM-DD" v-model:value="model.writtenDate" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 审阅时间 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-date-picker class="input" placeholder="" format="YYYY-MM-DD" v-model:value="model.reviewDate" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</a-card>
|
||||
</JFormContainer>
|
||||
</a-form>
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, unref, reactive, toRaw } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { saveOrUpdate, getDepartName } from '../doc.send.api';
|
||||
import { formatToDateTime } from '/@/utils/dateUtil';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import JFormContainer from '/@/components/Form/src/jeecg/components/JFormContainer.vue';
|
||||
import dayjs from "dayjs";
|
||||
// Emits声明
|
||||
const emit = defineEmits(['register', 'success']);
|
||||
//提示弹窗
|
||||
const $message = useMessage();
|
||||
const userStore = useUserStore();
|
||||
const isUpdate = ref(true);
|
||||
const formRef = ref(null);
|
||||
const nickname = ref(userStore.getUserInfo?.realname);
|
||||
const model = reactive({
|
||||
id: '',
|
||||
title: '',
|
||||
docCode: '',
|
||||
docType: '1',
|
||||
classification: '1',
|
||||
urgency: '1',
|
||||
printScore: 0,
|
||||
sendTarget: '1',
|
||||
confidentiality: '1',
|
||||
officeCode: '',
|
||||
orderNo: '',
|
||||
theme: '',
|
||||
receiverName: '',
|
||||
bookDate: null,
|
||||
writtenDate: null,
|
||||
reviewDate: null,
|
||||
});
|
||||
//表单校验
|
||||
const validatorRules = {
|
||||
title: [{ required: true, message: '请输入公文标题!' }],
|
||||
};
|
||||
const formDisabled = ref(false);
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
setModalProps({ confirmLoading: false, showOkBtn: !!!data?.isDetail });
|
||||
isUpdate.value = !!data?.isUpdate;
|
||||
if (unref(isUpdate)) {
|
||||
let obj = { ...data.record };
|
||||
Object.assign(model, { ...obj });
|
||||
} else {
|
||||
Object.assign(model, { ...initData });
|
||||
}
|
||||
|
||||
//时间格式化(升级antd3后,时间值不允许是字符串)
|
||||
model.bookDate = model.bookDate?dayjs(model.bookDate,'YYYY-MM-DD'):null;
|
||||
model.writtenDate = model.writtenDate?dayjs(model.writtenDate,'YYYY-MM-DD'):null;
|
||||
model.reviewDate = model.reviewDate?dayjs(model.reviewDate,'YYYY-MM-DD'):null;
|
||||
|
||||
|
||||
// update-begin-author:taoyan date:2022-9-5 for: VUEN-2157 出差申请、借款申请、请假申请、公文申请都有这个问题,详情不让改
|
||||
if(data.isDetail === true){
|
||||
formDisabled.value = true;
|
||||
}else{
|
||||
formDisabled.value = false;
|
||||
}
|
||||
// update-end-author:taoyan date:2022-9-5 for: VUEN-2157 出差申请、借款申请、请假申请、公文申请都有这个问题,详情不让改
|
||||
});
|
||||
//设置标题
|
||||
const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
|
||||
|
||||
//表单提交事件
|
||||
function handleSubmit() {
|
||||
try {
|
||||
formRef.value
|
||||
.validate()
|
||||
.then(async () => {
|
||||
let formData = toRaw(unref(model));
|
||||
//时间格式化
|
||||
formData.bookDate = formData.bookDate ? formatToDateTime(formData.bookDate, 'YYYY-MM-DD HH:mm:ss') : null;
|
||||
formData.writtenDate = formData.writtenDate ? formatToDateTime(formData.writtenDate, 'YYYY-MM-DD HH:mm:ss') : null;
|
||||
formData.reviewDate = formData.reviewDate ? formatToDateTime(formData.reviewDate, 'YYYY-MM-DD HH:mm:ss') : null;
|
||||
setModalProps({ confirmLoading: true });
|
||||
//提交表单
|
||||
await saveOrUpdate(formData, isUpdate.value);
|
||||
//关闭弹窗
|
||||
closeModal();
|
||||
//刷新列表
|
||||
emit('success');
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log('error', error);
|
||||
});
|
||||
} finally {
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
|
||||
const labelCol = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 5 },
|
||||
};
|
||||
const wrapperCol = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 24 },
|
||||
};
|
||||
//初始化数据
|
||||
const initData = {
|
||||
title: '',
|
||||
docCode: '',
|
||||
docType: '1',
|
||||
classification: '1',
|
||||
urgency: '1',
|
||||
printScore: 0,
|
||||
sendTarget: '1',
|
||||
confidentiality: '1',
|
||||
officeCode: '',
|
||||
orderNo: '',
|
||||
theme: '',
|
||||
receiverName: '',
|
||||
bookDate: null,
|
||||
writtenDate: null,
|
||||
reviewDate: null,
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
html[data-theme='light'] {
|
||||
.ant-card {
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
background: #fff;
|
||||
border: 1px solid #e8e8e8;
|
||||
}
|
||||
#staffCard {
|
||||
border: 1px solid #fff;
|
||||
box-shadow:
|
||||
0 0 1px 1px #aaa,
|
||||
3px 0 5px 0 #aaa,
|
||||
0 4px 7px 0 #aaa;
|
||||
}
|
||||
#documentsIssuedTitle {
|
||||
color: black;
|
||||
}
|
||||
#documentsIssueTable {
|
||||
background-color: #fff;
|
||||
border: 1px solid #000;
|
||||
tr,
|
||||
th {
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
td,
|
||||
th {
|
||||
border-right: 1px solid #000;
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
.input {
|
||||
:deep(.ant-input) {
|
||||
border: 0 solid black !important;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
.ant-input {
|
||||
border: 0 solid black !important;
|
||||
background-color: #fff;
|
||||
}
|
||||
.text {
|
||||
background-color: #fff;
|
||||
}
|
||||
.firstTr {
|
||||
color: #000;
|
||||
}
|
||||
.smallText .ant-input-number-input {
|
||||
background-color: #fff;
|
||||
}
|
||||
.textArea {
|
||||
border: 0 solid white;
|
||||
}
|
||||
}
|
||||
/**去掉日期控件边框*/
|
||||
.ant-picker {
|
||||
border: 0 solid black !important;
|
||||
}
|
||||
}
|
||||
html[data-theme='dark'] {
|
||||
@borderColor: #3a3a3a;
|
||||
#documentsIssueTable {
|
||||
border: 1px solid @borderColor;
|
||||
}
|
||||
tr,
|
||||
th {
|
||||
border-bottom: 1px solid @borderColor;
|
||||
}
|
||||
td,
|
||||
th {
|
||||
border-right: 1px solid @borderColor;
|
||||
border-bottom: 1px solid @borderColor;
|
||||
}
|
||||
}
|
||||
.ant-card {
|
||||
border-radius: 2px;
|
||||
margin: 0 auto;
|
||||
width: 1000px;
|
||||
}
|
||||
|
||||
#staffCard {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 5px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#documentsIssuedTitle {
|
||||
margin-top: 1px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
display: block;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
#documentsIssueTable {
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
|
||||
tr td:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
tr:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.fontiframe {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.ant-form-item {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.input {
|
||||
:deep(.ant-input) {
|
||||
border-radius: 0;
|
||||
display: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-input {
|
||||
border-radius: 0;
|
||||
display: inherit;
|
||||
margin: 0;
|
||||
width: 255px;
|
||||
}
|
||||
|
||||
:deep(.ant-calendar-picker-input) {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.text {
|
||||
border: none !important;
|
||||
border-radius: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.textArea {
|
||||
resize: none;
|
||||
box-shadow: none;
|
||||
height: 98px;
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
border-radius: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.colfirst {
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.colfour {
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.firstTr {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.radioGroup {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.smallText .ant-input-number-input {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
:deep(.ant-input-number) {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,54 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { Modal } from 'ant-design-vue';
|
||||
|
||||
enum Api {
|
||||
list = '/joa/joaDocSending/list',
|
||||
queryById = '/joa/joaDocSending/queryById',
|
||||
save = '/joa/joaDocSending/add',
|
||||
edit = '/joa/joaDocSending/edit',
|
||||
deleteOne = '/joa/joaDocSending/delete',
|
||||
deleteBatch = '/joa/joaDocSending/deleteBatch',
|
||||
}
|
||||
/**
|
||||
* 列表
|
||||
* @param params
|
||||
*/
|
||||
export const list = (params) => defHttp.get({ url: Api.list, params });
|
||||
/**
|
||||
* 根据id查询
|
||||
* @param params
|
||||
*/
|
||||
export const queryById = (params) => defHttp.get({ url: Api.queryById, params }, { isTransformResponse: false });
|
||||
/**
|
||||
* 删除一个
|
||||
*/
|
||||
export const deleteOne = (params, handleSuccess) => {
|
||||
return defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 批量删除
|
||||
* @param params
|
||||
*/
|
||||
export const batchDelete = (params, handleSuccess) => {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: '是否删除选中数据',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 保存或者更新
|
||||
* @param params
|
||||
*/
|
||||
export const saveOrUpdate = (params, isUpdate) => {
|
||||
let url = isUpdate ? Api.edit : Api.save;
|
||||
return defHttp.post({ url: url, params });
|
||||
};
|
||||
@@ -0,0 +1,85 @@
|
||||
import { FormSchema } from '/@/components/Table';
|
||||
import { render } from '/@/utils/common/renderUtils';
|
||||
export const columns = [
|
||||
{
|
||||
title: '公文标题',
|
||||
dataIndex: 'title',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '文种',
|
||||
dataIndex: 'classification',
|
||||
width: 100,
|
||||
|
||||
customRender: ({ text }) => {
|
||||
if (text == 1) {
|
||||
return '公告';
|
||||
} else if (text == 2) {
|
||||
return '通知';
|
||||
} else {
|
||||
return text;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '公文分类',
|
||||
dataIndex: 'docType',
|
||||
width: 100,
|
||||
|
||||
customRender: ({ text }) => {
|
||||
if (text == 1) {
|
||||
return '普通文件';
|
||||
} else if (text == 2) {
|
||||
return '盖章通知';
|
||||
} else if (text == 3) {
|
||||
return '正式文件';
|
||||
} else {
|
||||
return text;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '缓急程度',
|
||||
dataIndex: 'urgency',
|
||||
width: 100,
|
||||
customRender: ({ text }) => {
|
||||
if (text == 1) {
|
||||
return '普通';
|
||||
} else if (text == 2) {
|
||||
return '紧急';
|
||||
} else if (text == 3) {
|
||||
return '特急';
|
||||
} else {
|
||||
return text;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '印刷分数',
|
||||
dataIndex: 'printScore',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '登记时间',
|
||||
dataIndex: 'bookDate',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '流程状态',
|
||||
align: 'center',
|
||||
dataIndex: 'bpmStatus',
|
||||
width: 100,
|
||||
customRender: ({ text }) => {
|
||||
return render.renderDict(text, 'bpm_status');
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export const searchFormSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'title',
|
||||
label: '公文标题',
|
||||
component: 'Input',
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,179 @@
|
||||
<template>
|
||||
<BasicTable @register="registerTable" :rowSelection="rowSelection">
|
||||
<template #tableTitle>
|
||||
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="handleCreate"> 新增</a-button>
|
||||
<a-dropdown v-if="selectedRowKeys.length > 0">
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item key="1" @click="batchHandleDelete">
|
||||
<Icon icon="ant-design:delete-outlined"></Icon>
|
||||
删除
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
<a-button
|
||||
>批量操作
|
||||
<Icon icon="mdi:chevron-down"></Icon>
|
||||
</a-button>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
<template #pcaSlot="{ text }">
|
||||
{{ getAreaTextByCode(text) }}
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
<!--角色工单授权-->
|
||||
<DocSendModal @register="registerModal" @success="reload" />
|
||||
<BpmPictureModal @register="registerBpmModal" />
|
||||
</template>
|
||||
<script lang="ts" name="doc-send-list" setup>
|
||||
import { ref } from 'vue';
|
||||
import { BasicTable, TableAction } from '/@/components/Table';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import DocSendModal from './components/DocSendModal.vue';
|
||||
import BpmPictureModal from '/@/views/super/bpm/process/manage/components/BpmPictureModal.vue';
|
||||
import { columns, searchFormSchema } from './doc.send.data';
|
||||
import { list, deleteOne, batchDelete } from './doc.send.api';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
import { startProcess } from '/@/views/super/bpm/example/batch/leave.api';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
const [registerBpmModal, { openModal: bpmPicModal }] = useModal();
|
||||
const { createMessage, createConfirm } = useMessage();
|
||||
|
||||
// 列表页面公共参数、方法
|
||||
const { prefixCls, tableContext } = useListPage({
|
||||
designScope: 'doc-send-list',
|
||||
tableProps: {
|
||||
api: list,
|
||||
columns: columns,
|
||||
canResize: false,
|
||||
formConfig: {
|
||||
schemas: searchFormSchema,
|
||||
},
|
||||
actionColumn: {
|
||||
width: 120,
|
||||
},
|
||||
},
|
||||
});
|
||||
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||
const flowCode = 'joa_doc_send_01';
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
function handleCreate() {
|
||||
openModal(true, {
|
||||
isUpdate: false,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 编辑
|
||||
*/
|
||||
function handleEdit(record: Recordable) {
|
||||
openModal(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 详情
|
||||
*/
|
||||
function handleDetail(record) {
|
||||
openModal(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
isDetail: true,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 删除事件
|
||||
*/
|
||||
async function handleDelete(record) {
|
||||
await deleteOne({ id: record.id }, reload);
|
||||
}
|
||||
/**
|
||||
* 批量删除事件
|
||||
*/
|
||||
async function batchHandleDelete() {
|
||||
await batchDelete({ ids: selectedRowKeys.value }, reload);
|
||||
}
|
||||
/**
|
||||
* 提交流程
|
||||
*/
|
||||
function handleStartProcess(record) {
|
||||
createConfirm({
|
||||
iconType: 'warning',
|
||||
title: '提示',
|
||||
content: '确认提交流程吗?',
|
||||
onOk: async () => {
|
||||
let res = await startProcess({
|
||||
flowCode: flowCode,
|
||||
id: record.id,
|
||||
formUrl: 'super/bpm/example/joa/docSend/components/DocSendForm',
|
||||
formUrlMobile: 'applyform/docSend',
|
||||
});
|
||||
if (res.success) {
|
||||
createMessage.success(res.message);
|
||||
reload();
|
||||
} else {
|
||||
createMessage.warning(res.message);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 审批进度
|
||||
*/
|
||||
async function handlePreviewPic(record) {
|
||||
bpmPicModal(true, {
|
||||
flowCode,
|
||||
dataId: record.id,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
ifShow: record.bpmStatus === '1',
|
||||
},
|
||||
{
|
||||
label: '提交流程',
|
||||
onClick: handleStartProcess.bind(null, record),
|
||||
ifShow: record.bpmStatus === '1',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 下拉操作栏
|
||||
*/
|
||||
function getDropDownAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '详情',
|
||||
onClick: handleDetail.bind(null, record),
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
confirm: handleDelete.bind(null, record),
|
||||
},
|
||||
ifShow: record.bpmStatus === '1',
|
||||
},
|
||||
{
|
||||
label: '审批进度',
|
||||
onClick: handlePreviewPic.bind(null, record),
|
||||
ifShow: record.bpmStatus !== '1',
|
||||
},
|
||||
];
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,368 @@
|
||||
<template>
|
||||
<a-form ref="formRef" :model="model" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<JFormContainer :disabled="true">
|
||||
<a-card id="staffCard" class="ant-card">
|
||||
<span id="staffLeaveTitle">员工请假单</span>
|
||||
<div class="staffLeaveTableId" style="margin-bottom: 5px">
|
||||
<a-form-item :labelCol="{ xs: { span: 24 }, sm: { span: 10 } }" :wrapperCol="{ xs: { span: 24 }, sm: { span: 10 } }" label="编号:">
|
||||
<a-input class="fontiframe" style="border: none" readOnly v-model:value="model.applyNo" />
|
||||
</a-form-item>
|
||||
</div>
|
||||
<table id="staffLeaveTable">
|
||||
<tr class="tr-style">
|
||||
<td class="firstTr">请假人</td>
|
||||
<td class="firstTr">
|
||||
<a-form-item>
|
||||
<span class="fontiframe">{{ nickname }}</span>
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td class="firstTr">部门</td>
|
||||
<td class="firstTr">
|
||||
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span class="fontiframe">{{ model.department }}</span>
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td class="firstTr">职务</td>
|
||||
<td class="firstTr">
|
||||
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span class="fontiframe">{{ model.duty }}</span>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="tr-style">
|
||||
<td colspan="6">
|
||||
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" style="font-size: 12px" label="请假类别:">
|
||||
<a-radio-group class="fontiframe" name="radioGroup" v-model:value="model.leaveCategory">
|
||||
<template v-for="(item, index) in leaveCategoryOpt" :key="index">
|
||||
<a-radio class="radioGroup" :value="item.value">{{ item.label }}</a-radio>
|
||||
</template>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="6">
|
||||
<a-form-item label="请假事由:">
|
||||
<a-textarea v-model:value="model.leaveReason" class="textArea"></a-textarea>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="tr-style">
|
||||
<td colspan="6">
|
||||
<a-form-item class="fontiframe lineHeight" label="请假时间:">
|
||||
自(
|
||||
<a-date-picker class="input" format="YYYY-MM-DD" v-model:value="model.leaveStartDate" :allowClear="false" />
|
||||
) 至(
|
||||
<a-date-picker class="input" format="YYYY-MM-DD" v-model:value="model.leaveEndDate" :allowClear="false" />
|
||||
) 总共请<a-input-number class="smallText" v-model:value="model.total" size="small" :min="0" />天<br />
|
||||
<span class="fontiframe" style="color: #f00; position: relative; right: 86px"
|
||||
>1.请假半天可以写0.5不能写0.1,0.2等小数。2.全天假以00:00:00开始以23:59:59结束,下午请假以12:00:00开始</span
|
||||
>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="tr-style">
|
||||
<td colspan="3">
|
||||
<a-form-item :labelCol="{ xs: { span: 24 }, sm: { span: 10 } }" :wrapperCol="wrapperCol" label="休息期间联系方式:">
|
||||
<a-input class="text" v-model:value="model.contactWay" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td colspan="3">
|
||||
<a-form-item :labelCol="{ xs: { span: 24 }, sm: { span: 11 } }" :wrapperCol="wrapperCol" label="休息期间应急工作委托人:">
|
||||
<a-input class="text" v-model:value="model.dutyDeputy" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="height: 100px; line-height: 100px">
|
||||
<td colspan="3">
|
||||
<a-form-item :labelCol="{ xs: { span: 24 }, sm: { span: 10 } }" :wrapperCol="wrapperCol" label="部门主管(经理)意见:">
|
||||
<div style="display: flex; margin-top: 20px; height: 80px">
|
||||
<div>{{ model.leaderApproval }}</div>
|
||||
<div class="fontiframe" style="position: absolute; bottom: 10px">负责人:</div>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td colspan="3">
|
||||
<a-form-item :labelCol="{ xs: { span: 24 }, sm: { span: 11 } }" :wrapperCol="wrapperCol" label="人力资源部(行政办)意见:">
|
||||
<div style="display: flex; margin-top: 20px; height: 80px">
|
||||
<div class="fontiframe">{{ model.hrPrincipalApproval }}</div
|
||||
><br />
|
||||
<div class="fontiframe" style="position: absolute; bottom: 10px">负责人:</div>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
<a-form-item :labelCol="{ xs: { span: 24 }, sm: { span: 10 } }" :wrapperCol="wrapperCol" label="总经理意见:">
|
||||
<div style="display: flex; height: 100px">
|
||||
<div class="fontiframe" style="margin-top: 30px">{{ model.deptPrincipalApproval }}</div>
|
||||
<div class="fontiframe" style="position: absolute; bottom: 10px">总经理:</div>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td colspan="3" style="text-align: left">
|
||||
<p class="fontiframe">
|
||||
说明<br />
|
||||
1.返回公司报到时间为销假时间。<br />
|
||||
2.所有员工3天及以上请假需总经理批准。<br />
|
||||
3.本表存人力资源部(行政办)备案。<br />
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</a-card>
|
||||
<a-form-item hidden>
|
||||
<a-date-picker class="input" placeholder="" format="YYYY-MM-DD" disabled v-model:value="model.applyDate" />
|
||||
</a-form-item>
|
||||
</JFormContainer>
|
||||
</a-form>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, unref, reactive, toRaw } from 'vue';
|
||||
import { queryById } from '../leave.api';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import JFormContainer from '/@/components/Form/src/jeecg/components/JFormContainer.vue';
|
||||
import { leaveCategoryOpt } from '../leave.data';
|
||||
import dayjs from "dayjs";
|
||||
|
||||
// props声明
|
||||
const props = defineProps({
|
||||
formData: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
const userStore = useUserStore();
|
||||
const nickname = ref(userStore.getUserInfo?.realname);
|
||||
const model = reactive({
|
||||
applyNo: '',
|
||||
department: '',
|
||||
duty: '',
|
||||
leaveReason: '',
|
||||
leaveStartDate: null,
|
||||
leaveEndDate: null,
|
||||
leaveCategory: '1',
|
||||
total: 0,
|
||||
contactWay: '',
|
||||
dutyDeputy: '',
|
||||
leaderApproval: '',
|
||||
hrPrincipalApproval: '',
|
||||
deptPrincipalApproval: '',
|
||||
applyDate: null,
|
||||
});
|
||||
|
||||
const labelCol = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 3 },
|
||||
};
|
||||
const wrapperCol = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 21 },
|
||||
};
|
||||
|
||||
async function initFormData() {
|
||||
let res = await queryById({ id: props.formData.dataId });
|
||||
console.log('LeaveForm获取流程节点信息', res);
|
||||
if (res.success) {
|
||||
//表单赋值
|
||||
Object.assign(model, { ...res.result });
|
||||
//时间格式化(antd3升级后,时间值不允许是字符串)
|
||||
model.leaveStartDate = model.leaveStartDate?dayjs(model.leaveStartDate,'YYYY-MM-DD'):null;
|
||||
model.leaveEndDate = model.leaveEndDate?dayjs(model.leaveEndDate,'YYYY-MM-DD'):null;
|
||||
model.applyDate = model.applyDate?dayjs(model.applyDate,'YYYY-MM-DD'):null;
|
||||
}
|
||||
}
|
||||
initFormData();
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
html[data-theme='light'] {
|
||||
.ant-card {
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
background: #fff;
|
||||
border: 1px solid #e8e8e8;
|
||||
}
|
||||
#staffCard {
|
||||
border: 1px solid #fff;
|
||||
box-shadow:
|
||||
0 0 1px 1px #aaa,
|
||||
3px 0 5px 0 #aaa,
|
||||
0 4px 7px 0 #aaa;
|
||||
}
|
||||
#staffLeaveTitle {
|
||||
color: black;
|
||||
}
|
||||
#staffLeaveTable {
|
||||
background-color: #fff;
|
||||
border: 1px solid #000;
|
||||
tr,
|
||||
th {
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
td,
|
||||
th {
|
||||
border-right: 1px solid #000;
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
.input {
|
||||
:deep(.ant-input) {
|
||||
border: 0 solid black !important;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
.ant-input {
|
||||
border: 0 solid black !important;
|
||||
background-color: #fff;
|
||||
}
|
||||
.text {
|
||||
background-color: #fff;
|
||||
}
|
||||
.firstTr {
|
||||
color: #000;
|
||||
}
|
||||
.smallText .ant-input-number-input {
|
||||
background-color: #fff;
|
||||
}
|
||||
.textArea {
|
||||
border: 0 solid white;
|
||||
}
|
||||
}
|
||||
/**去掉日期控件边框*/
|
||||
.ant-picker {
|
||||
border: 0 solid black !important;
|
||||
}
|
||||
}
|
||||
html[data-theme='dark'] {
|
||||
@borderColor: #3a3a3a;
|
||||
#staffLeaveTable {
|
||||
border: 1px solid @borderColor;
|
||||
}
|
||||
tr,
|
||||
th {
|
||||
border-bottom: 1px solid @borderColor;
|
||||
}
|
||||
td,
|
||||
th {
|
||||
border-right: 1px solid @borderColor;
|
||||
border-bottom: 1px solid @borderColor;
|
||||
}
|
||||
}
|
||||
.ant-card {
|
||||
border-radius: 2px;
|
||||
margin: 0 auto;
|
||||
width: 750px;
|
||||
}
|
||||
|
||||
#staffCard {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 5px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#staffLeaveTitle {
|
||||
margin-top: 1px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
display: block;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
#staffLeaveTable {
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
|
||||
.tr-style {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
}
|
||||
tr td:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
tr:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.fontiframe {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.ant-form-item {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.input {
|
||||
:deep(.ant-input) {
|
||||
border-radius: 0;
|
||||
display: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-input {
|
||||
border-radius: 0;
|
||||
display: inherit;
|
||||
margin: 0;
|
||||
width: 255px;
|
||||
}
|
||||
|
||||
:deep(.ant-calendar-picker-input) {
|
||||
border: none !important;
|
||||
font-size: 12px;
|
||||
}
|
||||
:deep(.ant-input-number-sm) {
|
||||
border: none !important;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.text {
|
||||
border: none !important;
|
||||
border-radius: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.firstTr {
|
||||
width: 16%;
|
||||
|
||||
.ant-form-item-control-wrapper {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.smallText .ant-input-number-input {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.lineHeight .ant-form-item-control {
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.textArea {
|
||||
resize: none;
|
||||
height: 118px;
|
||||
font-size: 12px;
|
||||
border-radius: 0;
|
||||
margin-bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.staffLeaveTableId {
|
||||
margin-right: 87px;
|
||||
float: right;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
.ant-form label {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
:deep(.ant-form-item-label label) {
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,468 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" :bodyStyle="{ height: '720px' }" :title="title" @ok="handleSubmit" width="950px">
|
||||
<a-form ref="formRef" :model="model" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<JFormContainer :disabled="formDisabled">
|
||||
<a-card id="staffCard" class="ant-card">
|
||||
<span id="staffLeaveTitle">员工请假单</span>
|
||||
<div class="staffLeaveTableId">
|
||||
<a-form-item :labelCol="{ xs: { span: 24 }, sm: { span: 10 } }" :wrapperCol="{ xs: { span: 24 }, sm: { span: 10 } }" label="编号:">
|
||||
<a-input class="fontiframe" style="border: none" readOnly v-model:value="model.applyNo" />
|
||||
</a-form-item>
|
||||
</div>
|
||||
<table id="staffLeaveTable">
|
||||
<tr class="tr-style">
|
||||
<td class="firstTr">请假人</td>
|
||||
<td class="firstTr">
|
||||
<a-form-item>
|
||||
<span class="fontiframe">{{ nickname }}</span>
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td class="firstTr">部门</td>
|
||||
<td class="firstTr">
|
||||
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span class="fontiframe">{{ model.department }}</span>
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td class="firstTr">职务</td>
|
||||
<td class="firstTr">
|
||||
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span class="fontiframe">{{ model.duty }}</span>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="tr-style">
|
||||
<td colspan="6">
|
||||
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" style="font-size: 12px" label="请假类别:">
|
||||
<a-radio-group class="fontiframe" name="radioGroup" v-model:value="model.leaveCategory">
|
||||
<template v-for="(item, index) in leaveCategoryOpt" :key="index">
|
||||
<a-radio class="radioGroup" :value="item.value">{{ item.label }}</a-radio>
|
||||
</template>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="6">
|
||||
<a-form-item label="请假事由:">
|
||||
<a-textarea v-model:value="model.leaveReason" class="textArea"></a-textarea>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="tr-style">
|
||||
<td colspan="6">
|
||||
<a-form-item class="fontiframe lineHeight" label="请假时间:">
|
||||
自(
|
||||
<a-date-picker class="input" format="YYYY-MM-DD" @change="dateChange" v-model:value="model.leaveStartDate" :allowClear="false" />
|
||||
) 至(
|
||||
<a-date-picker class="input" format="YYYY-MM-DD" @change="dateChange" v-model:value="model.leaveEndDate" :allowClear="false" />
|
||||
) 总共请<a-input-number class="smallText" v-model:value="model.total" size="small" :min="0" />天<br />
|
||||
<span class="fontiframe" style="display:none; color: #f00; position: relative; right: 86px"
|
||||
>1.请假半天可以写0.5不能写0.1,0.2等小数。2.全天假以00:00:00开始以23:59:59结束,下午请假以12:00:00开始</span
|
||||
>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="tr-style">
|
||||
<td colspan="3">
|
||||
<a-form-item :labelCol="{ xs: { span: 24 }, sm: { span: 10 } }" :wrapperCol="wrapperCol" label="休息期间联系方式:">
|
||||
<a-input class="text" v-model:value="model.contactWay" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td colspan="3">
|
||||
<a-form-item :labelCol="{ xs: { span: 24 }, sm: { span: 11 } }" :wrapperCol="wrapperCol" label="休息期间应急工作委托人:">
|
||||
<a-input class="text" v-model:value="model.dutyDeputy" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="height: 100px; line-height: 100px">
|
||||
<td colspan="3">
|
||||
<a-form-item :labelCol="{ xs: { span: 24 }, sm: { span: 10 } }" :wrapperCol="wrapperCol" label="部门主管(经理)意见:">
|
||||
<div style="display: flex; margin-top: 20px; height: 80px">
|
||||
<div>{{ model.leaderApproval }}</div>
|
||||
<div class="fontiframe" style="position: absolute; bottom: 10px">负责人:</div>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td colspan="3">
|
||||
<a-form-item :labelCol="{ xs: { span: 24 }, sm: { span: 11 } }" :wrapperCol="wrapperCol" label="人力资源部(行政办)意见:">
|
||||
<div style="display: flex; margin-top: 20px; height: 80px">
|
||||
<div class="fontiframe">{{ model.hrPrincipalApproval }}</div
|
||||
><br />
|
||||
<div class="fontiframe" style="position: absolute; bottom: 10px">负责人:</div>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
<a-form-item :labelCol="{ xs: { span: 24 }, sm: { span: 10 } }" :wrapperCol="wrapperCol" label="总经理意见:">
|
||||
<div style="display: flex; height: 100px">
|
||||
<div class="fontiframe" style="margin-top: 30px">{{ model.deptPrincipalApproval }}</div>
|
||||
<div class="fontiframe" style="position: absolute; bottom: 10px">总经理:</div>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td colspan="3" style="text-align: left">
|
||||
<p class="fontiframe">
|
||||
说明<br />
|
||||
1.返回公司报到时间为销假时间。<br />
|
||||
2.所有员工3天及以上请假需总经理批准。<br />
|
||||
3.本表存人力资源部(行政办)备案。<br />
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</a-card>
|
||||
</JFormContainer>
|
||||
<a-form-item hidden>
|
||||
<a-date-picker class="input" placeholder="" format="YYYY-MM-DD" disabled v-model:value="model.applyDate" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, unref, reactive, toRaw } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { saveOrUpdate } from '../leave.api';
|
||||
import { leaveCategoryOpt } from '../leave.data';
|
||||
import { formatToDateTime } from '/@/utils/dateUtil';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import JFormContainer from '/@/components/Form/src/jeecg/components/JFormContainer.vue';
|
||||
import {string} from "vue-types";
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
// Emits声明
|
||||
const emit = defineEmits(['register', 'success']);
|
||||
//提示弹窗
|
||||
const $message = useMessage();
|
||||
const userStore = useUserStore();
|
||||
const isUpdate = ref(true);
|
||||
const nickname = ref(userStore.getUserInfo?.realname);
|
||||
const model = reactive({
|
||||
applyNo: '',
|
||||
department: '',
|
||||
duty: '',
|
||||
leaveReason: '',
|
||||
leaveCategory: '1',
|
||||
leaveStartDate: '',
|
||||
leaveEndDate: '',
|
||||
total: 0,
|
||||
contactWay: '',
|
||||
dutyDeputy: '',
|
||||
leaderApproval: '',
|
||||
hrPrincipalApproval: '',
|
||||
deptPrincipalApproval: '',
|
||||
applyDate: null,
|
||||
});
|
||||
|
||||
const formDisabled = ref(false);
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
setModalProps({ confirmLoading: false, showOkBtn: !!!data?.isDetail });
|
||||
isUpdate.value = !!data?.isUpdate;
|
||||
if (unref(isUpdate)) {
|
||||
Object.assign(model, { ...data.record });
|
||||
} else {
|
||||
Object.assign(model, { ...initData });
|
||||
}
|
||||
|
||||
//时间初始化(antd3升级后,时间值不允许是字符串)
|
||||
model.applyDate = model.applyDate ? dayjs(model.applyDate) : null;
|
||||
model.leaveStartDate = model.leaveStartDate ? dayjs(model.leaveStartDate) : null;
|
||||
model.leaveEndDate = model.leaveEndDate ? dayjs(model.leaveEndDate) : null;
|
||||
|
||||
// update-begin-author:taoyan date:2022-9-5 for: VUEN-2157 出差申请、借款申请、请假申请、公文申请都有这个问题,详情不让改
|
||||
if(data.isDetail === true){
|
||||
formDisabled.value = true;
|
||||
}else{
|
||||
formDisabled.value = false;
|
||||
}
|
||||
// update-end-author:taoyan date:2022-9-5 for: VUEN-2157 出差申请、借款申请、请假申请、公文申请都有这个问题,详情不让改
|
||||
});
|
||||
//设置标题
|
||||
const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
|
||||
|
||||
//表单提交事件
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
let formData = toRaw(unref(model));
|
||||
if (!model.leaveStartDate) {
|
||||
$message.createMessage.warning('请假开始时间不能是空');
|
||||
return false;
|
||||
}
|
||||
if (!model.leaveEndDate) {
|
||||
$message.createMessage.warning('请假结束时间不能是空');
|
||||
return false;
|
||||
}
|
||||
if (model.total == 0) {
|
||||
$message.createMessage.warning('请假天数不能是0天');
|
||||
return false;
|
||||
}
|
||||
if (model.total == '' || model.total == undefined || model.total == null) {
|
||||
$message.createMessage.warning('请假天数不能是空');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//时间格式化
|
||||
formData.applyDate = formData.applyDate ? formatToDateTime(formData.applyDate, 'YYYY-MM-DD HH:mm:ss') : null;
|
||||
formData.leaveStartDate = formData.leaveStartDate ? formatToDateTime(formData.leaveStartDate, 'YYYY-MM-DD HH:mm:ss') : null;
|
||||
formData.leaveEndDate = formData.leaveEndDate ? formatToDateTime(formData.leaveEndDate, 'YYYY-MM-DD HH:mm:ss') : null;
|
||||
setModalProps({ confirmLoading: true });
|
||||
//提交表单
|
||||
await saveOrUpdate(formData, isUpdate.value);
|
||||
//关闭弹窗
|
||||
closeModal();
|
||||
//刷新列表
|
||||
emit('success');
|
||||
} finally {
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
const labelCol = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 3 },
|
||||
};
|
||||
const wrapperCol = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 21 },
|
||||
};
|
||||
const initData = {
|
||||
id: '',
|
||||
applyNo: '',
|
||||
name: userStore.getUserInfo?.username,
|
||||
department: '系统管理部',
|
||||
duty: '普通员工',
|
||||
leaveReason: '',
|
||||
leaveStartDate: null,
|
||||
leaveEndDate: null,
|
||||
leaveCategory: '1',
|
||||
total: 0,
|
||||
contactWay: '',
|
||||
dutyDeputy: '',
|
||||
leaderApproval: '',
|
||||
hrPrincipalApproval: '',
|
||||
deptPrincipalApproval: '小于三天无需总经理批准',
|
||||
applyDate: nowTimes()
|
||||
};
|
||||
function nowTimes() {
|
||||
let date = new Date();
|
||||
let year = date.getFullYear();
|
||||
let month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1;
|
||||
let day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
|
||||
return dayjs(year + '-' + month + '-' + day);
|
||||
}
|
||||
|
||||
//update-begin-author:taoyan date:2022-9-5 for: VUEN-2157 4、请假申请,只需要年月日不需要时分秒,默认计算请假天数
|
||||
function dateChange(){
|
||||
let { leaveEndDate, leaveStartDate} = model;
|
||||
if(leaveEndDate && leaveStartDate){
|
||||
let leaveStartDateTemp = dayjs(leaveStartDate,'YYYY-MM-DD');
|
||||
let leaveEndDateTemp = dayjs(leaveEndDate,'YYYY-MM-DD');
|
||||
let temp = leaveEndDateTemp.diff(leaveStartDateTemp, 'days');
|
||||
if(temp === 0){
|
||||
model.total = 1
|
||||
}else if(temp && temp > 0){
|
||||
model.total = temp + 1;
|
||||
}else{
|
||||
model.total = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
//update-end-author:taoyan date:2022-9-5 for: VUEN-2157 4、请假申请,只需要年月日不需要时分秒,默认计算请假天数
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
html[data-theme='light'] {
|
||||
.ant-card {
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
background: #fff;
|
||||
border: 1px solid #e8e8e8;
|
||||
}
|
||||
#staffCard {
|
||||
border: 1px solid #fff;
|
||||
box-shadow:
|
||||
0 0 1px 1px #aaa,
|
||||
3px 0 5px 0 #aaa,
|
||||
0 4px 7px 0 #aaa;
|
||||
}
|
||||
#staffLeaveTitle {
|
||||
color: black;
|
||||
}
|
||||
#staffLeaveTable {
|
||||
background-color: #fff;
|
||||
border: 1px solid #000;
|
||||
tr,
|
||||
th {
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
td,
|
||||
th {
|
||||
border-right: 1px solid #000;
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
.input {
|
||||
:deep(.ant-input) {
|
||||
border: 0 solid black !important;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
.ant-input {
|
||||
border: 0 solid black !important;
|
||||
background-color: #fff;
|
||||
}
|
||||
.firstTr {
|
||||
color: #000;
|
||||
}
|
||||
.smallText .ant-input-number-input {
|
||||
background-color: #fff;
|
||||
}
|
||||
.textArea {
|
||||
border: 0 solid white;
|
||||
}
|
||||
}
|
||||
/**去掉日期控件边框*/
|
||||
.ant-picker {
|
||||
border: 0 solid black !important;
|
||||
}
|
||||
}
|
||||
html[data-theme='dark'] {
|
||||
@borderColor: #3a3a3a;
|
||||
#staffLeaveTable {
|
||||
border: 1px solid @borderColor;
|
||||
}
|
||||
tr,
|
||||
th {
|
||||
border-bottom: 1px solid @borderColor;
|
||||
}
|
||||
td,
|
||||
th {
|
||||
border-right: 1px solid @borderColor;
|
||||
border-bottom: 1px solid @borderColor;
|
||||
}
|
||||
}
|
||||
.ant-card {
|
||||
border-radius: 2px;
|
||||
margin: 0 auto;
|
||||
width: 750px;
|
||||
height: 700px;
|
||||
}
|
||||
|
||||
#staffCard {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 5px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#staffLeaveTitle {
|
||||
margin-top: 1px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
display: block;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
#staffLeaveTable {
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
|
||||
.tr-style {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
}
|
||||
|
||||
tr td:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
tr:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.fontiframe {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.ant-form-item {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.input {
|
||||
:deep(.ant-input) {
|
||||
border-radius: 0;
|
||||
display: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-input {
|
||||
border-radius: 0;
|
||||
display: inherit;
|
||||
margin: 0;
|
||||
width: 255px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
:deep(.ant-calendar-picker-input) {
|
||||
border: none !important;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
:deep(.ant-input-number-sm) {
|
||||
border: none !important;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.text {
|
||||
border: none !important;
|
||||
border-radius: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.firstTr {
|
||||
width: 16%;
|
||||
.ant-form-item-control-wrapper {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.smallText .ant-input-number-input {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.lineHeight .ant-form-item-control {
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.textArea {
|
||||
resize: none;
|
||||
box-shadow: none;
|
||||
height: 118px;
|
||||
font-size: 12px;
|
||||
border-radius: 0;
|
||||
margin-bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.staffLeaveTableId {
|
||||
margin-right: 87px;
|
||||
float: right;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
.ant-form label {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
:deep(.ant-form-item-label label) {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,60 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { Modal } from 'ant-design-vue';
|
||||
|
||||
enum Api {
|
||||
list = '/joa/joaEmployeeLeave/list',
|
||||
taskList = '/joa/joaEmployeeLeave/taskList',
|
||||
queryById = '/joa/joaEmployeeLeave/queryById',
|
||||
save = '/joa/joaEmployeeLeave/add',
|
||||
edit = '/joa/joaEmployeeLeave/edit',
|
||||
deleteOne = '/joa/joaEmployeeLeave/delete',
|
||||
deleteBatch = '/joa/joaEmployeeLeave/deleteBatch',
|
||||
}
|
||||
/**
|
||||
* 列表
|
||||
* @param params
|
||||
*/
|
||||
export const list = (params) => defHttp.get({ url: Api.list, params });
|
||||
/**
|
||||
* 任务列表
|
||||
* @param params
|
||||
*/
|
||||
export const taskList = (params) => defHttp.get({ url: Api.taskList, params });
|
||||
/**
|
||||
* 根据id查询
|
||||
* @param params
|
||||
*/
|
||||
export const queryById = (params) => defHttp.get({ url: Api.queryById, params }, { isTransformResponse: false });
|
||||
/**
|
||||
* 删除一个
|
||||
*/
|
||||
export const deleteOne = (params, handleSuccess) => {
|
||||
return defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 批量删除
|
||||
* @param params
|
||||
*/
|
||||
export const batchDelete = (params, handleSuccess) => {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: '是否删除选中数据',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 保存或者更新
|
||||
* @param params
|
||||
*/
|
||||
export const saveOrUpdate = (params, isUpdate) => {
|
||||
let url = isUpdate ? Api.edit : Api.save;
|
||||
return defHttp.post({ url: url, params });
|
||||
};
|
||||
@@ -0,0 +1,116 @@
|
||||
import { FormSchema } from '/@/components/Table';
|
||||
import { render } from '/@/utils/common/renderUtils';
|
||||
export const leaveCategoryOpt = [
|
||||
{
|
||||
label: '病假',
|
||||
value: '1',
|
||||
key: '1',
|
||||
},
|
||||
{
|
||||
label: '事假',
|
||||
value: '2',
|
||||
key: '2',
|
||||
},
|
||||
{
|
||||
label: '年假',
|
||||
value: '3',
|
||||
key: '3',
|
||||
},
|
||||
{
|
||||
label: '婚假',
|
||||
value: '4',
|
||||
key: '4',
|
||||
},
|
||||
{
|
||||
label: '产假',
|
||||
value: '5',
|
||||
key: '5',
|
||||
},
|
||||
{
|
||||
label: '丧假',
|
||||
value: '6',
|
||||
key: '6',
|
||||
},
|
||||
{
|
||||
label: '探亲假',
|
||||
value: '7',
|
||||
key: '7',
|
||||
},
|
||||
{
|
||||
label: '护理假',
|
||||
value: '8',
|
||||
key: '8',
|
||||
},
|
||||
{
|
||||
label: '其他',
|
||||
value: '9',
|
||||
key: '9',
|
||||
},
|
||||
];
|
||||
export const columns = [
|
||||
{
|
||||
title: '申请编号',
|
||||
dataIndex: 'applyNo',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'name',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '申请日期',
|
||||
dataIndex: 'applyDate',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '请假类别',
|
||||
dataIndex: 'leaveCategory',
|
||||
width: 100,
|
||||
customRender: ({ text }) => {
|
||||
let item = leaveCategoryOpt.filter((t) => t.value == text);
|
||||
if (item && item.length > 0) {
|
||||
return item[0].label;
|
||||
} else {
|
||||
return text;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '请假开始时间',
|
||||
dataIndex: 'leaveStartDate',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '请假结束时间',
|
||||
dataIndex: 'leaveEndDate',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '流程状态',
|
||||
align: 'center',
|
||||
dataIndex: 'bpmStatus',
|
||||
width: 100,
|
||||
customRender: ({ text }) => {
|
||||
return render.renderDict(text, 'bpm_status');
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export const searchFormSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'name',
|
||||
label: '名称',
|
||||
component: 'Input',
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
{
|
||||
field: 'leaveCategory',
|
||||
label: '请假类别',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: leaveCategoryOpt,
|
||||
},
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,130 @@
|
||||
<template>
|
||||
<BasicTable @register="registerTable">
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
<!--角色工单授权-->
|
||||
<LeaveModal @register="registerModal" @success="reload" />
|
||||
<BpmPictureModal @register="registerBpmModal" />
|
||||
<!--业务办理弹窗-->
|
||||
<BpmBizTaskDealModal ref="taskDealModal" :path="path" :formData="formData" @ok="taskOk"></BpmBizTaskDealModal>
|
||||
</template>
|
||||
<script lang="ts" name="leave-list" setup>
|
||||
import { ref } from 'vue';
|
||||
import { BasicTable, TableAction } from '/@/components/Table';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import LeaveModal from './components/LeaveModal.vue';
|
||||
import BpmPictureModal from '/@/views/super/bpm/process/manage/components/BpmPictureModal.vue';
|
||||
import BpmBizTaskDealModal from '/@/views/super/bpm/example/batch/components/BpmBizTaskDealModal.vue';
|
||||
import { columns, searchFormSchema } from './leave.data';
|
||||
import { taskList } from './leave.api';
|
||||
import { claim, getBizProcessNodeInfo } from '/@/views/super/bpm/process/manage/components/bpm.api.ts';
|
||||
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
const [registerBpmModal, { openModal: bpmPicModal }] = useModal();
|
||||
const { createMessage, createConfirm } = useMessage();
|
||||
|
||||
// 列表页面公共参数、方法
|
||||
const { prefixCls, tableContext } = useListPage({
|
||||
designScope: 'leave-list',
|
||||
tableProps: {
|
||||
api: taskList,
|
||||
columns: columns,
|
||||
canResize: false,
|
||||
formConfig: {
|
||||
schemas: searchFormSchema,
|
||||
},
|
||||
actionColumn: {
|
||||
width: 120,
|
||||
},
|
||||
},
|
||||
});
|
||||
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||
const flowCode = 'joa_leave_01';
|
||||
const path = ref('');
|
||||
const formData = ref({});
|
||||
const taskDealModal = ref(null);
|
||||
/**
|
||||
* 签收
|
||||
*/
|
||||
function handleClaim(record) {
|
||||
createConfirm({
|
||||
iconType: 'warning',
|
||||
title: '确认签收吗',
|
||||
content: '是否签收该任务?',
|
||||
onOk: async () => {
|
||||
let res = await claim({ taskId: record.taskId });
|
||||
if (res.success) {
|
||||
createMessage.success(res.message);
|
||||
} else {
|
||||
createMessage.warning(res.message);
|
||||
}
|
||||
reload();
|
||||
},
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 办理
|
||||
*/
|
||||
async function handleProcess(record) {
|
||||
let res = await getBizProcessNodeInfo({ flowCode: flowCode, dataId: record.id });
|
||||
if (res.success) {
|
||||
console.log('获取流程节点信息', res);
|
||||
console.log('表单数据', res.result.records);
|
||||
let data = {
|
||||
dataId: res.result.dataId,
|
||||
taskId: res.result.taskId,
|
||||
flowCode: flowCode,
|
||||
taskDefKey: res.result.taskDefKey,
|
||||
procInsId: res.result.procInsId,
|
||||
tableName: res.result.tableName,
|
||||
permissionList: res.result.permissionList,
|
||||
bizTaskList: res.result.bizTaskList,
|
||||
vars: res.result.records,
|
||||
};
|
||||
formData.value = data;
|
||||
path.value = res.result.formUrl;
|
||||
console.log('------获取流程节点信息>>', data);
|
||||
console.log('------流程表单地址>>', path.value);
|
||||
taskDealModal.value.deal(data);
|
||||
}
|
||||
}
|
||||
|
||||
function taskOk() {
|
||||
reload();
|
||||
}
|
||||
/**
|
||||
* 审批进度
|
||||
*/
|
||||
function handlePreviewPic(record) {
|
||||
bpmPicModal(true, {
|
||||
flowCode,
|
||||
dataId: record.id,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '签收',
|
||||
onClick: handleClaim.bind(null, record),
|
||||
ifShow: !!!record.assignee,
|
||||
},
|
||||
{
|
||||
label: '办理',
|
||||
onClick: handleProcess.bind(null, record),
|
||||
ifShow: !!record.assignee,
|
||||
},
|
||||
{
|
||||
label: '审批进度',
|
||||
onClick: handlePreviewPic.bind(null, record),
|
||||
},
|
||||
];
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,176 @@
|
||||
<template>
|
||||
<BasicTable @register="registerTable" :rowSelection="rowSelection">
|
||||
<template #tableTitle>
|
||||
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="handleCreate"> 新增</a-button>
|
||||
<a-dropdown v-if="selectedRowKeys.length > 0">
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item key="1" @click="batchHandleDelete">
|
||||
<Icon icon="ant-design:delete-outlined"></Icon>
|
||||
删除
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
<a-button
|
||||
>批量操作
|
||||
<Icon icon="mdi:chevron-down"></Icon>
|
||||
</a-button>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
<!--角色工单授权-->
|
||||
<LeaveModal @register="registerModal" @success="reload" />
|
||||
<BpmPictureModal @register="registerBpmModal" />
|
||||
</template>
|
||||
<script lang="ts" name="leave-list" setup>
|
||||
import { ref } from 'vue';
|
||||
import { BasicTable, TableAction } from '/@/components/Table';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import LeaveModal from './components/LeaveModal.vue';
|
||||
import BpmPictureModal from '/@/views/super/bpm/process/manage/components/BpmPictureModal.vue';
|
||||
import { columns, searchFormSchema } from './leave.data';
|
||||
import { list, deleteOne, batchDelete } from './leave.api';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
import { startProcess } from '/@/views/super/bpm/example/batch/leave.api.ts';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
const [registerBpmModal, { openModal: bpmPicModal }] = useModal();
|
||||
const { createMessage, createConfirm } = useMessage();
|
||||
|
||||
// 列表页面公共参数、方法
|
||||
const { prefixCls, tableContext } = useListPage({
|
||||
designScope: 'leave-list',
|
||||
tableProps: {
|
||||
api: list,
|
||||
columns: columns,
|
||||
canResize: false,
|
||||
formConfig: {
|
||||
schemas: searchFormSchema,
|
||||
},
|
||||
actionColumn: {
|
||||
width: 120,
|
||||
},
|
||||
},
|
||||
});
|
||||
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||
const flowCode = 'joa_leave_01';
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
function handleCreate() {
|
||||
openModal(true, {
|
||||
isUpdate: false,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 编辑
|
||||
*/
|
||||
function handleEdit(record: Recordable) {
|
||||
openModal(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 详情
|
||||
*/
|
||||
function handleDetail(record) {
|
||||
openModal(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
isDetail: true,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 删除事件
|
||||
*/
|
||||
async function handleDelete(record) {
|
||||
await deleteOne({ id: record.id }, reload);
|
||||
}
|
||||
/**
|
||||
* 批量删除事件
|
||||
*/
|
||||
async function batchHandleDelete() {
|
||||
await batchDelete({ ids: selectedRowKeys.value }, reload);
|
||||
}
|
||||
/**
|
||||
* 提交流程
|
||||
*/
|
||||
function handleStartProcess(record) {
|
||||
createConfirm({
|
||||
iconType: 'warning',
|
||||
title: '提示',
|
||||
content: '确认提交流程吗?',
|
||||
onOk: async () => {
|
||||
let res = await startProcess({
|
||||
flowCode: flowCode,
|
||||
id: record.id,
|
||||
formUrl: 'super/bpm/example/joa/leave/components/LeaveForm',
|
||||
formUrlMobile: 'applyform/leave',
|
||||
});
|
||||
if (res.success) {
|
||||
createMessage.success(res.message);
|
||||
reload();
|
||||
} else {
|
||||
createMessage.warning(res.message);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 审批进度
|
||||
*/
|
||||
async function handlePreviewPic(record) {
|
||||
bpmPicModal(true, {
|
||||
flowCode,
|
||||
dataId: record.id,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
ifShow: record.bpmStatus === '1',
|
||||
},
|
||||
{
|
||||
label: '提交流程',
|
||||
onClick: handleStartProcess.bind(null, record),
|
||||
ifShow: record.bpmStatus === '1',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 下拉操作栏
|
||||
*/
|
||||
function getDropDownAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '详情',
|
||||
onClick: handleDetail.bind(null, record),
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
confirm: handleDelete.bind(null, record),
|
||||
},
|
||||
ifShow: record.bpmStatus === '1',
|
||||
},
|
||||
{
|
||||
label: '审批进度',
|
||||
onClick: handlePreviewPic.bind(null, record),
|
||||
ifShow: record.bpmStatus !== '1',
|
||||
},
|
||||
];
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,576 @@
|
||||
<template>
|
||||
<a-card id="staffCard" class="ant-card">
|
||||
<a-form ref="formRef" :model="model" :labelCol="labelCol" :wrapperCol="wrapperCol" :rules="validatorRules">
|
||||
<span id="staffTitle">借款单(主流程)</span>
|
||||
<table border="1px" class="staffTable">
|
||||
<tr>
|
||||
<td class="colfirst">借款人</td>
|
||||
<td class="secend">
|
||||
<a-form-item>
|
||||
<a-input class="text" :disabled="disabled" v-model:value="model.loanUserName" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td>借款人部门</td>
|
||||
<td style="width: 100px">
|
||||
<a-form-item>
|
||||
<span class="fontiframe">{{ model.departName }}</span>
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 借款时间 </td>
|
||||
<td>
|
||||
<a-form-item>
|
||||
<a-date-picker class="input" format="YYYY-MM-DD" disabled v-model:value="model.loanTime" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>借款金额</td>
|
||||
<td>
|
||||
<a-form-item name="loanAmount">
|
||||
<a-input-number class="smallText" v-model:value="model.loanAmount" size="small" :min="0" :max="99999999" @change="upperOnChange" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td>金额大写</td>
|
||||
<td colspan="3">
|
||||
{{ model.upperSum }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 借款用途 </td>
|
||||
<td colspan="5">
|
||||
<a-form-item>
|
||||
<a-textarea v-model:value="model.loanUsage" class="textArea"></a-textarea>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 备注 </td>
|
||||
<td colspan="5">
|
||||
<a-form-item>
|
||||
<a-textarea v-model:value="model.remarks" class="textArea"> </a-textarea>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="height: 45px">
|
||||
<td> 部门领导审核 </td>
|
||||
<td>
|
||||
<span>{{ model.departLeaderAudit }}</span>
|
||||
</td>
|
||||
<td> 财务审核 </td>
|
||||
<td>
|
||||
<span>{{ model.financeAudit }}</span>
|
||||
</td>
|
||||
<td> 总经理审核 </td>
|
||||
<td>
|
||||
<span>{{ model.managerAudit }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="height: 45px">
|
||||
<td> 出纳放款 </td>
|
||||
<td>
|
||||
<span>{{ model.cashierLoanAmount }}</span>
|
||||
</td>
|
||||
<td>借款发放时间</td>
|
||||
<td colspan="3">
|
||||
<span>
|
||||
{{ model.cashierLoanTime }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div style="text-align: center; margin-top: 10px">
|
||||
<a-button type="primary" @click="handleOk()">保存</a-button>
|
||||
</div>
|
||||
</a-form>
|
||||
<br />
|
||||
<a-form :model="model2" :labelCol="labelCol" :wrapperCol="wrapperCol2">
|
||||
<a-divider orientation="left">员工出差申请记录</a-divider>
|
||||
<JFormContainer :disabled="true">
|
||||
<table border="1px" class="staffTable">
|
||||
<tr>
|
||||
<td class="firstTr">出差人</td>
|
||||
<td class="firstTr" colspan="2">
|
||||
<a-form-item>
|
||||
<span class="fontiframe">{{ nickname }}</span>
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td class="firstTr">部门</td>
|
||||
<td class="firstTr" colspan="2">
|
||||
<a-form-item>
|
||||
<JSelectDept v-model:value="model2.departId" :multiple="false" :checkStrictly="true" :showButton="false"></JSelectDept>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 目的地 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item name="destination">
|
||||
<JAreaLinkage placeholder="请选择" v-model:value="model2.destination" :showArea="true" :showAll="false" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 项目名称 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item name="projectName">
|
||||
<a-input class="text" v-model:value="model2.projectName" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 出发时间 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-date-picker class="input" format="YYYY-MM-DD" v-model:value="model2.departureTime" :allowClear="false" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 计划返回时间 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-date-picker class="input" format="YYYY-MM-DD" v-model:value="model2.plannedReturnTime" :allowClear="false" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 实际返回时间 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-date-picker class="input" placeholder="" format="YYYY-MM-DD" v-model:value="model2.actualReturnTime" :allowClear="false" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 出差天数 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-input class="text" v-model:value="model2.dayNum" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 出差经费支出 </td>
|
||||
<td colspan="5">
|
||||
<a-form-item>
|
||||
<a-radio-group class="fontiframe" name="radioGroup" v-model:value="model2.travelExpensesType">
|
||||
<a-radio class="radioGroup" value="1">预支借款</a-radio>
|
||||
<a-radio class="radioGroup" value="2">个人垫付</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 出发地 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<JAreaLinkage v-model:value="model2.departAddress" placeholder="请选择" :showArea="true" :showAll="false" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 出行工具 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-radio-group class="fontiframe" name="radioGroup" v-model:value="model2.travelTool">
|
||||
<a-radio class="radioGroup" :value="1">客车</a-radio>
|
||||
<a-radio class="radioGroup" :value="2">火车</a-radio>
|
||||
<a-radio class="radioGroup" :value="3">飞机</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 任务及事由 </td>
|
||||
<td colspan="5">
|
||||
<a-form-item>
|
||||
<a-textarea v-model:value="model2.reason" class="textArea"></a-textarea>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="height: 38px">
|
||||
<td> 部门领导审核 </td>
|
||||
<td colspan="2">
|
||||
<span>{{ model2.departLeaderAudit }}</span>
|
||||
</td>
|
||||
<td> 财务审核 </td>
|
||||
<td colspan="2">
|
||||
<span>{{ model2.financeAudit }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="height: 38px">
|
||||
<td> 出纳放款 </td>
|
||||
<td colspan="2">
|
||||
<span>{{ model2.cashierLoanAmount }}</span>
|
||||
</td>
|
||||
<td> 总经理审核 </td>
|
||||
<td colspan="2">
|
||||
<span>{{ model2.managerAudit }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</JFormContainer>
|
||||
</a-form>
|
||||
</a-card>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, unref, reactive, toRaw } from 'vue';
|
||||
import { numToUpper } from '/@/utils';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import { queryByTripApplyNo, queryTripByApplyNo, saveOrUpdate } from '../loan.api';
|
||||
import JAreaLinkage from '/@/components/Form/src/jeecg/components/JAreaLinkage.vue';
|
||||
import JSelectDept from '/@/components/Form/src/jeecg/components/JSelectDept.vue';
|
||||
import JFormContainer from '/@/components/Form/src/jeecg/components/JFormContainer.vue';
|
||||
import { getRealCode } from '/@/components/Form/src/utils/areaDataUtil.js';
|
||||
import { formatToDateTime } from '/@/utils/dateUtil';
|
||||
import dayjs from "dayjs";
|
||||
|
||||
// props声明
|
||||
const props = defineProps({
|
||||
formData: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
const userStore = useUserStore();
|
||||
const formRef = ref(null);
|
||||
const nickname = ref(userStore.getUserInfo?.realname);
|
||||
const disabled = ref(true);
|
||||
const model = reactive({
|
||||
id: '',
|
||||
departName: '',
|
||||
loanUserName: '',
|
||||
loanTime: nowTimes(),
|
||||
loanAmount: 0,
|
||||
upperSum: '',
|
||||
loanUsage: '',
|
||||
remarks: '',
|
||||
departLeaderAudit: '',
|
||||
financeAudit: 0,
|
||||
managerAudit: '',
|
||||
cashierLoanAmount: '',
|
||||
cashierLoanTime: null,
|
||||
});
|
||||
const model2 = reactive({
|
||||
applyUserName: '',
|
||||
departId: '',
|
||||
destination: '',
|
||||
projectName: '',
|
||||
departureTime: null,
|
||||
plannedReturnTime: null,
|
||||
actualReturnTime: null,
|
||||
dayNum: 0,
|
||||
travelExpensesType: '1',
|
||||
departAddress: '',
|
||||
travelTool: 1,
|
||||
reason: '',
|
||||
departLeaderAudit: '',
|
||||
financeAudit: '',
|
||||
cashierLoanAmount: '',
|
||||
managerAudit: '',
|
||||
loanMoney: 0,
|
||||
});
|
||||
//表单校验
|
||||
const validatorRules = {
|
||||
loanAmount: [{ required: true, message: '请输入借款金额!' }],
|
||||
};
|
||||
function nowTimes() {
|
||||
let date = new Date();
|
||||
let year = date.getFullYear();
|
||||
let month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1;
|
||||
let day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
|
||||
return dayjs(year + '-' + month + '-' + day);
|
||||
}
|
||||
|
||||
function upperOnChange(value) {
|
||||
let numText = numToUpper(value);
|
||||
if (numText) {
|
||||
model.upperSum = numText;
|
||||
} else {
|
||||
model.loanAmount = 0;
|
||||
model.upperSum = '';
|
||||
}
|
||||
}
|
||||
const labelCol = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 3 },
|
||||
};
|
||||
const wrapperCol = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 25 },
|
||||
};
|
||||
const wrapperCol2 = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 21 },
|
||||
};
|
||||
async function initFormData() {
|
||||
let res = await queryByTripApplyNo({ id: props.formData.vars.apply_no });
|
||||
if (res.success) {
|
||||
console.log('获取流程节点信息', res.result);
|
||||
//表单赋值
|
||||
edit(res.result);
|
||||
} else {
|
||||
edit({ tripApplyNo: props.formData.vars.apply_no });
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//通过出差单号,查询出差单
|
||||
let params = { tripApplyNo: props.formData.vars.apply_no }; //查询条件
|
||||
let res2 = await queryTripByApplyNo(params);
|
||||
if (res2.success) {
|
||||
let obj = res2.result;
|
||||
console.log('获取出差单信息', obj);
|
||||
//表单赋值
|
||||
detailStrip(obj);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
function add() {
|
||||
edit({});
|
||||
}
|
||||
|
||||
function edit(record) {
|
||||
Object.assign(model, { ...record });
|
||||
if (model.loanAmount != '' && model.loanAmount != null && model.loanAmount != undefined) {
|
||||
upperOnChange(model.loanAmount);
|
||||
}
|
||||
//时间格式化(升级antd3后,时间值不允许是字符串)
|
||||
model.cashierLoanTime = model.cashierLoanTime ? formatToDateTime(model.cashierLoanTime, 'YYYY-MM-DD HH:mm:ss') : null;
|
||||
model.loanTime = nowTimes();
|
||||
|
||||
model.loanUserName = userStore.getUserInfo?.username;
|
||||
model.departName = '系统管理部';
|
||||
model.departLeaderAudit = '';
|
||||
model.financeAudit = '';
|
||||
model.managerAudit = '金额大于五千才需向总经理审批';
|
||||
model.cashierLoanAmount = '';
|
||||
}
|
||||
|
||||
function detailStrip(record) {
|
||||
//表单赋值
|
||||
record.destination = getRealCode(record.destination, 3);
|
||||
record.departAddress && (record.departAddress = getRealCode(record.departAddress, 3));
|
||||
Object.assign(model2, { ...record });
|
||||
|
||||
//时间格式化(升级antd3后,时间值不允许是字符串)
|
||||
model2.departureTime = model2.departureTime?dayjs(model2.departureTime,'YYYY-MM-DD'):null;
|
||||
model2.plannedReturnTime = model2.plannedReturnTime?dayjs(model2.plannedReturnTime,'YYYY-MM-DD'):null;
|
||||
model2.actualReturnTime = model2.actualReturnTime?dayjs(model2.actualReturnTime,'YYYY-MM-DD'):null;
|
||||
|
||||
if (model2.loanMoney != '' && model2.loanMoney != null && model2.loanMoney != undefined) {
|
||||
upperOnChange(model2.loanMoney);
|
||||
}
|
||||
}
|
||||
|
||||
function handleOk() {
|
||||
try {
|
||||
formRef.value
|
||||
.validate()
|
||||
.then(async () => {
|
||||
let formData = toRaw(unref(model));
|
||||
console.log('formData------>', formData);
|
||||
console.log('!!formData.id------>', !!formData.id);
|
||||
//时间格式化
|
||||
formData.loanTime = formData.loanTime ? formatToDateTime(formData.loanTime, 'YYYY-MM-DD HH:mm:ss') : null;
|
||||
formData.cashierLoanTime = formData.cashierLoanTime ? formatToDateTime(formData.cashierLoanTime, 'YYYY-MM-DD HH:mm:ss') : null;
|
||||
//提交表单
|
||||
await saveOrUpdate(formData, !!formData.id);
|
||||
//刷新表单
|
||||
initFormData();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log('error', error);
|
||||
});
|
||||
} finally {
|
||||
}
|
||||
}
|
||||
|
||||
initFormData();
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
html[data-theme='light'] {
|
||||
.ant-card {
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
background: #fff;
|
||||
border: 1px solid #e8e8e8;
|
||||
}
|
||||
#staffCard {
|
||||
border: 1px solid #fff;
|
||||
box-shadow:
|
||||
0 0 1px 1px #aaa,
|
||||
3px 0 5px 0 #aaa,
|
||||
0 4px 7px 0 #aaa;
|
||||
}
|
||||
#documentsIssuedTitle {
|
||||
color: black;
|
||||
}
|
||||
.staffTable {
|
||||
background-color: #fff;
|
||||
border: 1px solid #000;
|
||||
}
|
||||
tr,
|
||||
th {
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
td,
|
||||
th {
|
||||
border-right: 1px solid #000;
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
.input {
|
||||
:deep(.ant-input) {
|
||||
border: 0 solid black !important;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
.ant-input {
|
||||
border: 0 solid black !important;
|
||||
background-color: #fff;
|
||||
}
|
||||
.text {
|
||||
background-color: #fff;
|
||||
}
|
||||
.firstTr {
|
||||
color: #000;
|
||||
}
|
||||
.smallText .ant-input-number-input {
|
||||
background-color: #fff;
|
||||
}
|
||||
.textArea {
|
||||
border: 0 solid white;
|
||||
}
|
||||
/**去掉日期控件边框*/
|
||||
.ant-picker {
|
||||
border: 0 solid black !important;
|
||||
}
|
||||
}
|
||||
html[data-theme='dark'] {
|
||||
@borderColor: #3a3a3a;
|
||||
.staffTable {
|
||||
border: 1px solid @borderColor;
|
||||
}
|
||||
tr,
|
||||
th {
|
||||
border-bottom: 1px solid @borderColor;
|
||||
}
|
||||
td,
|
||||
th {
|
||||
border-right: 1px solid @borderColor;
|
||||
border-bottom: 1px solid @borderColor;
|
||||
}
|
||||
}
|
||||
.ant-card {
|
||||
border-radius: 2px;
|
||||
margin: 0 auto;
|
||||
width: 950px;
|
||||
}
|
||||
|
||||
#staffCard {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 5px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#staffTitle {
|
||||
margin-top: 1px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
display: block;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.staffTable {
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
|
||||
.tr-style {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
}
|
||||
|
||||
tr td:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
tr:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.colfirst {
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.colfour {
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.fontiframe {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.ant-form-item {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.input {
|
||||
:deep(.ant-input) {
|
||||
border-radius: 0;
|
||||
display: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-input {
|
||||
border-radius: 0;
|
||||
display: inherit;
|
||||
margin: 0;
|
||||
width: 255px;
|
||||
}
|
||||
|
||||
:deep(.ant-calendar-picker-input) {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.text {
|
||||
border: none !important;
|
||||
border-radius: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.firstTr {
|
||||
width: 16%;
|
||||
|
||||
.ant-form-item-control-wrapper {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.smallText .ant-input-number-input {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.lineHeight .ant-form-item-control {
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.textArea {
|
||||
resize: none;
|
||||
box-shadow: none;
|
||||
height: 118px;
|
||||
font-size: 12px;
|
||||
border-radius: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.staffLeaveTableId {
|
||||
margin-right: 87px;
|
||||
float: right;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
.ant-form label {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
:deep(.ant-form-item-label label) {
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,523 @@
|
||||
<template>
|
||||
<a-card id="staffCard" class="ant-card">
|
||||
<a-form :model="model" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span id="staffTitle">借款单(子流程)</span>
|
||||
<table border="1px" class="staffTable">
|
||||
<tr>
|
||||
<td class="colfirst">借款人</td>
|
||||
<td class="secend">
|
||||
<a-form-item>
|
||||
<a-input class="text" :disabled="true" v-model:value="model.loanUserName" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td>借款人部门</td>
|
||||
<td style="width: 100px">
|
||||
<a-form-item>
|
||||
<span class="fontiframe">{{ model.departName }}</span>
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 借款时间 </td>
|
||||
<td>
|
||||
<a-form-item>
|
||||
<a-date-picker class="input" format="YYYY-MM-DD" disabled v-model:value="model.loanTime" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>借款金额</td>
|
||||
<td>
|
||||
<a-form-item>
|
||||
<a-input-number
|
||||
class="smallText"
|
||||
:disabled="true"
|
||||
v-model:value="model.loanAmount"
|
||||
size="small"
|
||||
:min="0"
|
||||
:max="99999999"
|
||||
@change="upperOnChange"
|
||||
/>
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td>金额大写</td>
|
||||
<td colspan="3">
|
||||
{{ model.upperSum }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 借款用途 </td>
|
||||
<td colspan="5">
|
||||
<a-form-item>
|
||||
<a-textarea :disabled="true" v-model:value="model.loanUsage" class="textArea"></a-textarea>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 备注 </td>
|
||||
<td colspan="5">
|
||||
<a-form-item>
|
||||
<a-textarea :disabled="true" v-model:value="model.remarks" class="textArea"> </a-textarea>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="height: 45px">
|
||||
<td> 部门领导审核 </td>
|
||||
<td>
|
||||
<span>{{ model.departLeaderAudit }}</span>
|
||||
</td>
|
||||
<td> 财务审核 </td>
|
||||
<td>
|
||||
<span>{{ model.financeAudit }}</span>
|
||||
</td>
|
||||
<td> 总经理审核 </td>
|
||||
<td>
|
||||
<span>{{ model.managerAudit }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="height: 45px">
|
||||
<td> 出纳放款 </td>
|
||||
<td>
|
||||
<span>{{ model.cashierLoanAmount }}</span>
|
||||
</td>
|
||||
<td>借款发放时间</td>
|
||||
<td colspan="3">
|
||||
<span>
|
||||
{{ model.cashierLoanTime }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</a-form>
|
||||
<br />
|
||||
<a-form :model="model2" :labelCol="labelCol" :wrapperCol="wrapperCol2">
|
||||
<a-divider orientation="left">员工出差申请记录</a-divider>
|
||||
<JFormContainer :disabled="true">
|
||||
<table border="1px" class="staffTable">
|
||||
<tr>
|
||||
<td class="firstTr">出差人</td>
|
||||
<td class="firstTr" colspan="2">
|
||||
<a-form-item>
|
||||
<span class="fontiframe">{{ nickname }}</span>
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td class="firstTr">部门</td>
|
||||
<td class="firstTr" colspan="2">
|
||||
<a-form-item>
|
||||
<JSelectDept v-model:value="model2.departId" :multiple="false" :checkStrictly="true" :showButton="false"></JSelectDept>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 目的地 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item name="destination">
|
||||
<JAreaLinkage placeholder="请选择" v-model:value="model2.destination" :showArea="true" :showAll="false" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 项目名称 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item name="projectName">
|
||||
<a-input class="text" v-model:value="model2.projectName" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 出发时间 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-date-picker class="input" format="YYYY-MM-DD" v-model:value="model2.departureTime" :allowClear="false" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 计划返回时间 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-date-picker class="input" format="YYYY-MM-DD" v-model:value="model2.plannedReturnTime" :allowClear="false" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 实际返回时间 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-date-picker class="input" placeholder="" format="YYYY-MM-DD" v-model:value="model2.actualReturnTime" :allowClear="false" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 出差天数 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-input class="text" v-model:value="model2.dayNum" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 出差经费支出 </td>
|
||||
<td colspan="5">
|
||||
<a-form-item>
|
||||
<a-radio-group class="fontiframe" name="radioGroup" v-model:value="model2.travelExpensesType">
|
||||
<a-radio class="radioGroup" value="1">预支借款</a-radio>
|
||||
<a-radio class="radioGroup" value="2">个人垫付</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 出发地 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<JAreaLinkage v-model:value="model2.departAddress" placeholder="请选择" :showArea="true" :showAll="false" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 出行工具 </td>
|
||||
<td colspan="2">
|
||||
<a-form-item>
|
||||
<a-radio-group class="fontiframe" name="radioGroup" v-model:value="model2.travelTool">
|
||||
<a-radio class="radioGroup" :value="1">客车</a-radio>
|
||||
<a-radio class="radioGroup" :value="2">火车</a-radio>
|
||||
<a-radio class="radioGroup" :value="3">飞机</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 任务及事由 </td>
|
||||
<td colspan="5">
|
||||
<a-form-item>
|
||||
<a-textarea v-model:value="model2.reason" class="textArea"></a-textarea>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="height: 38px">
|
||||
<td> 部门领导审核 </td>
|
||||
<td colspan="2">
|
||||
<span>{{ model2.departLeaderAudit }}</span>
|
||||
</td>
|
||||
<td> 财务审核 </td>
|
||||
<td colspan="2">
|
||||
<span>{{ model2.financeAudit }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="height: 38px">
|
||||
<td> 出纳放款 </td>
|
||||
<td colspan="2">
|
||||
<span>{{ model2.cashierLoanAmount }}</span>
|
||||
</td>
|
||||
<td> 总经理审核 </td>
|
||||
<td colspan="2">
|
||||
<span>{{ model2.managerAudit }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</JFormContainer>
|
||||
</a-form>
|
||||
</a-card>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, unref, reactive, toRaw } from 'vue';
|
||||
import { numToUpper } from '/@/utils';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import { queryByTripApplyNo, queryTripByApplyNo } from '../loan.api';
|
||||
import JAreaLinkage from '/@/components/Form/src/jeecg/components/JAreaLinkage.vue';
|
||||
import JSelectDept from '/@/components/Form/src/jeecg/components/JSelectDept.vue';
|
||||
import JFormContainer from '/@/components/Form/src/jeecg/components/JFormContainer.vue';
|
||||
import { getRealCode } from '/@/components/Form/src/utils/areaDataUtil.js';
|
||||
import dayjs from "dayjs";
|
||||
|
||||
// props声明
|
||||
const props = defineProps({
|
||||
formData: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
const userStore = useUserStore();
|
||||
const nickname = ref(userStore.getUserInfo?.realname);
|
||||
const model = reactive({
|
||||
id: '',
|
||||
departName: '',
|
||||
loanUserName: '',
|
||||
loanTime: nowTimes(),
|
||||
loanAmount: '',
|
||||
upperSum: '',
|
||||
loanUsage: '',
|
||||
remarks: '',
|
||||
departLeaderAudit: '',
|
||||
financeAudit: 0,
|
||||
managerAudit: '',
|
||||
cashierLoanAmount: '',
|
||||
cashierLoanTime: null,
|
||||
});
|
||||
const model2 = reactive({
|
||||
applyUserName: '',
|
||||
departId: '',
|
||||
destination: '',
|
||||
projectName: '',
|
||||
departureTime: null,
|
||||
plannedReturnTime: null,
|
||||
actualReturnTime: null,
|
||||
dayNum: 0,
|
||||
travelExpensesType: '1',
|
||||
departAddress: '',
|
||||
travelTool: 1,
|
||||
reason: '',
|
||||
departLeaderAudit: '',
|
||||
financeAudit: '',
|
||||
cashierLoanAmount: '',
|
||||
managerAudit: '',
|
||||
});
|
||||
|
||||
function nowTimes() {
|
||||
let date = new Date();
|
||||
let year = date.getFullYear();
|
||||
let month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1;
|
||||
let day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
|
||||
return dayjs(year + '-' + month + '-' + day);
|
||||
}
|
||||
|
||||
function upperOnChange(value) {
|
||||
let numText = numToUpper(value);
|
||||
if (numText) {
|
||||
model.upperSum = numText;
|
||||
} else {
|
||||
model.loanAmount = 0;
|
||||
model.upperSum = '';
|
||||
}
|
||||
}
|
||||
const labelCol = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 3 },
|
||||
};
|
||||
const wrapperCol = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 25 },
|
||||
};
|
||||
const wrapperCol2 = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 21 },
|
||||
};
|
||||
async function initFormData() {
|
||||
//update-begin-author:liusq---date:20220614--for: 借款申请在历史流程节点时,id取值存在问题 ---
|
||||
let id = props.formData.vars.id ? props.formData.vars.id : props.formData.dataId;
|
||||
let res = await queryByTripApplyNo({ id });
|
||||
//update-end-author:liusq---date:20220614--for: 借款申请在历史流程节点时,id取值存在问题 ---
|
||||
if (res.success) {
|
||||
console.log('获取流程节点信息', res.result);
|
||||
//表单赋值
|
||||
model.upperSum = numToUpper(res.result.loanAmount);
|
||||
Object.assign(model, { ...res.result });
|
||||
|
||||
//时间格式化(升级antd3后,时间值不允许是字符串)
|
||||
model.loanTime = model.loanTime?dayjs(model.loanTime,'YYYY-MM-DD'):null;
|
||||
model.cashierLoanTime = model.cashierLoanTime?dayjs(model.cashierLoanTime,'YYYY-MM-DD'):null;
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//通过出差单号,查询出差单
|
||||
let params = { tripApplyNo: res.result.tripApplyNo }; //查询条件
|
||||
let res2 = await queryTripByApplyNo(params);
|
||||
if (res2.success) {
|
||||
let obj = res2.result;
|
||||
console.log('获取出差单信息', obj);
|
||||
//表单赋值
|
||||
obj.destination = getRealCode(obj.destination, 3);
|
||||
obj.departAddress && (obj.departAddress = getRealCode(obj.departAddress, 3));
|
||||
Object.assign(model2, { ...obj });
|
||||
}
|
||||
|
||||
//时间格式化(升级antd3后,时间值不允许是字符串)
|
||||
model2.departureTime = model2.departureTime?dayjs(model2.departureTime,'YYYY-MM-DD'):null;
|
||||
model2.plannedReturnTime = model2.plannedReturnTime?dayjs(model2.plannedReturnTime,'YYYY-MM-DD'):null;
|
||||
model2.actualReturnTime = model2.actualReturnTime?dayjs(model2.actualReturnTime,'YYYY-MM-DD'):null;
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
}
|
||||
}
|
||||
initFormData();
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
html[data-theme='light'] {
|
||||
.ant-card {
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
background: #fff;
|
||||
border: 1px solid #e8e8e8;
|
||||
}
|
||||
#staffCard {
|
||||
border: 1px solid #fff;
|
||||
box-shadow:
|
||||
0 0 1px 1px #aaa,
|
||||
3px 0 5px 0 #aaa,
|
||||
0 4px 7px 0 #aaa;
|
||||
}
|
||||
#staffTitle {
|
||||
color: black;
|
||||
}
|
||||
.staffTable {
|
||||
background-color: #fff;
|
||||
border: 1px solid #000;
|
||||
tr,
|
||||
th {
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
td,
|
||||
th {
|
||||
border-right: 1px solid #000;
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
.input {
|
||||
:deep(.ant-input) {
|
||||
border: 0 solid black !important;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
.ant-input {
|
||||
border: 0 solid black !important;
|
||||
background-color: #fff;
|
||||
}
|
||||
.firstTr {
|
||||
color: #000;
|
||||
}
|
||||
.smallText .ant-input-number-input {
|
||||
background-color: #fff;
|
||||
}
|
||||
.textArea {
|
||||
border: 0 solid white;
|
||||
}
|
||||
}
|
||||
/**去掉日期控件边框*/
|
||||
.ant-picker {
|
||||
border: 0 solid black !important;
|
||||
}
|
||||
}
|
||||
html[data-theme='dark'] {
|
||||
@borderColor: #3a3a3a;
|
||||
.staffTable {
|
||||
border: 1px solid @borderColor;
|
||||
tr,
|
||||
th {
|
||||
border-bottom: 1px solid @borderColor;
|
||||
}
|
||||
td,
|
||||
th {
|
||||
border-right: 1px solid @borderColor;
|
||||
border-bottom: 1px solid @borderColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ant-card {
|
||||
border-radius: 2px;
|
||||
margin: 0 auto;
|
||||
width: 950px;
|
||||
}
|
||||
|
||||
#staffCard {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 5px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#staffTitle {
|
||||
margin-top: 1px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
display: block;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.staffTable {
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
.tr-style {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
}
|
||||
|
||||
tr td:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
tr:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.colfirst {
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.colfour {
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.fontiframe {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.ant-form-item {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.input {
|
||||
:deep(.ant-input) {
|
||||
border-radius: 0;
|
||||
display: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-input {
|
||||
border-radius: 0;
|
||||
display: inherit;
|
||||
margin: 0;
|
||||
width: 255px;
|
||||
}
|
||||
|
||||
:deep(.ant-calendar-picker-input) {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.text {
|
||||
border: none !important;
|
||||
border-radius: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.firstTr {
|
||||
width: 16%;
|
||||
.ant-form-item-control-wrapper {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.smallText .ant-input-number-input {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.lineHeight .ant-form-item-control {
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.textArea {
|
||||
resize: none;
|
||||
box-shadow: none;
|
||||
height: 118px;
|
||||
font-size: 12px;
|
||||
border-radius: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.staffLeaveTableId {
|
||||
margin-right: 87px;
|
||||
float: right;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
.ant-form label {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
:deep(.ant-form-item-label label) {
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,408 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit" width="950px">
|
||||
<a-form ref="formRef" :model="model" :labelCol="labelCol" :wrapperCol="wrapperCol" :rules="validatorRules" style="padding-bottom: 10px">
|
||||
<JFormContainer :disabled="formDisabled">
|
||||
<a-card id="staffCard" class="ant-card">
|
||||
<span id="staffBmTitle">借款单</span>
|
||||
<table border="1px" id="staffBmTable">
|
||||
<tr>
|
||||
<td class="colfirst">借款人</td>
|
||||
<td class="secend">
|
||||
<a-form-item>
|
||||
<span class="fontiframe">{{ nickname }}</span>
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td>借款人部门</td>
|
||||
<td style="width: 100px">
|
||||
<a-form-item>
|
||||
<span class="fontiframe">{{ model.departName }}</span>
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td> 借款时间 </td>
|
||||
<td>
|
||||
<a-form-item>
|
||||
<a-date-picker class="input" format="YYYY-MM-DD" disabled v-model:value="model.loanTime" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>借款金额</td>
|
||||
<td>
|
||||
<a-form-item name="loanAmount">
|
||||
<a-input-number class="smallText" v-model:value="model.loanAmount" size="small" :min="0" :max="99999999" @change="upperOnChange" />
|
||||
</a-form-item>
|
||||
</td>
|
||||
<td>金额大写</td>
|
||||
<td colspan="3">
|
||||
{{ model.upperSum }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 借款用途 </td>
|
||||
<td colspan="5">
|
||||
<a-form-item>
|
||||
<a-textarea v-model:value="model.loanUsage" class="textArea"></a-textarea>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 备注 </td>
|
||||
<td colspan="5">
|
||||
<a-form-item>
|
||||
<a-textarea v-model:value="model.remarks" class="textArea"> </a-textarea>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="height: 45px">
|
||||
<td> 部门领导审核 </td>
|
||||
<td>
|
||||
<span>{{ model.departLeaderAudit }}</span>
|
||||
</td>
|
||||
<td> 财务审核 </td>
|
||||
<td>
|
||||
<span>{{ model.financeAudit }}</span>
|
||||
</td>
|
||||
<td> 总经理审核 </td>
|
||||
<td>
|
||||
<span>{{ model.managerAudit }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="height: 45px">
|
||||
<td> 出纳放款 </td>
|
||||
<td>
|
||||
<span>{{ model.cashierLoanAmount }}</span>
|
||||
</td>
|
||||
<td>借款发放时间</td>
|
||||
<td colspan="3">
|
||||
<span>
|
||||
{{ model.cashierLoanTime }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</a-card>
|
||||
</JFormContainer>
|
||||
</a-form>
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, unref, reactive, toRaw } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { saveOrUpdate } from '../loan.api';
|
||||
import { formatToDateTime } from '/@/utils/dateUtil';
|
||||
import { numToUpper } from '/@/utils';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import JFormContainer from '/@/components/Form/src/jeecg/components/JFormContainer.vue';
|
||||
import dayjs from "dayjs";
|
||||
|
||||
// Emits声明
|
||||
const emit = defineEmits(['register', 'success']);
|
||||
//提示弹窗
|
||||
const $message = useMessage();
|
||||
const userStore = useUserStore();
|
||||
const formRef = ref(null);
|
||||
const isUpdate = ref(true);
|
||||
const nickname = ref(userStore.getUserInfo?.realname);
|
||||
const model = reactive({
|
||||
id: '',
|
||||
departName: '系统管理部',
|
||||
loanUserName: userStore.getUserInfo?.username,
|
||||
loanTime: nowTimes(),
|
||||
loanAmount: '',
|
||||
upperSum: '',
|
||||
loanUsage: '',
|
||||
remarks: '',
|
||||
departLeaderAudit: '',
|
||||
financeAudit: 0,
|
||||
managerAudit: '金额大于五千才需向总经理审批',
|
||||
cashierLoanAmount: '',
|
||||
cashierLoanTime: null,
|
||||
});
|
||||
//表单校验
|
||||
const validatorRules = {
|
||||
loanAmount: [{ required: true, message: '请输入借款金额!' }],
|
||||
};
|
||||
const formDisabled = ref(false);
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
setModalProps({ confirmLoading: false, showOkBtn: !!!data?.isDetail });
|
||||
isUpdate.value = !!data?.isUpdate;
|
||||
if (unref(isUpdate)) {
|
||||
Object.assign(model, { ...data.record });
|
||||
} else {
|
||||
Object.assign(model, { ...initData });
|
||||
}
|
||||
|
||||
//时间格式化(升级antd3后,时间值不允许是字符串)
|
||||
model.loanTime = model.loanTime?dayjs(model.loanTime,'YYYY-MM-DD'):null;
|
||||
model.cashierLoanTime = model.cashierLoanTime?dayjs(model.cashierLoanTime,'YYYY-MM-DD'):null;
|
||||
|
||||
// update-begin-author:taoyan date:2022-9-5 for: VUEN-2157 出差申请、借款申请、请假申请、公文申请都有这个问题,详情不让改
|
||||
if(data.isDetail === true){
|
||||
formDisabled.value = true;
|
||||
}else{
|
||||
formDisabled.value = false;
|
||||
}
|
||||
// update-end-author:taoyan date:2022-9-5 for: VUEN-2157 出差申请、借款申请、请假申请、公文申请都有这个问题,详情不让改
|
||||
});
|
||||
//设置标题
|
||||
const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
|
||||
|
||||
//表单提交事件
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
formRef.value
|
||||
.validate()
|
||||
.then(async () => {
|
||||
let formData = toRaw(unref(model));
|
||||
//时间格式化
|
||||
formData.loanTime = formData.loanTime ? formatToDateTime(formData.loanTime, 'YYYY-MM-DD HH:mm:ss') : null;
|
||||
formData.cashierLoanTime = formData.cashierLoanTime ? formatToDateTime(formData.cashierLoanTime, 'YYYY-MM-DD HH:mm:ss') : null;
|
||||
setModalProps({ confirmLoading: true });
|
||||
//提交表单
|
||||
await saveOrUpdate(formData, isUpdate.value);
|
||||
//关闭弹窗
|
||||
closeModal();
|
||||
//刷新列表
|
||||
emit('success');
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log('error', error);
|
||||
});
|
||||
} finally {
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
|
||||
function nowTimes() {
|
||||
let date = new Date();
|
||||
let year = date.getFullYear();
|
||||
let month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1;
|
||||
let day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
|
||||
return dayjs(year + '-' + month + '-' + day);
|
||||
}
|
||||
|
||||
function upperOnChange(value) {
|
||||
let numText = numToUpper(value);
|
||||
if (numText) {
|
||||
model.upperSum = numText;
|
||||
} else {
|
||||
model.loanAmount = 0;
|
||||
model.upperSum = '';
|
||||
}
|
||||
}
|
||||
const labelCol = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 3 },
|
||||
};
|
||||
const wrapperCol = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 25 },
|
||||
};
|
||||
const initData = {
|
||||
departName: '系统管理部',
|
||||
loanUserName: userStore.getUserInfo?.username,
|
||||
loanTime: nowTimes(),
|
||||
loanAmount: '',
|
||||
upperSum: '',
|
||||
loanUsage: '',
|
||||
remarks: '',
|
||||
departLeaderAudit: '',
|
||||
financeAudit: 0,
|
||||
managerAudit: '金额大于五千才需向总经理审批',
|
||||
cashierLoanAmount: '',
|
||||
cashierLoanTime: null,
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
html[data-theme='light'] {
|
||||
.ant-card {
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
background: #fff;
|
||||
border: 1px solid #e8e8e8;
|
||||
}
|
||||
#staffCard {
|
||||
border: 1px solid #fff;
|
||||
box-shadow:
|
||||
0 0 1px 1px #aaa,
|
||||
3px 0 5px 0 #aaa,
|
||||
0 4px 7px 0 #aaa;
|
||||
}
|
||||
#staffBmTitle {
|
||||
color: black;
|
||||
}
|
||||
#staffBmTable {
|
||||
background-color: #fff;
|
||||
border: 1px solid #000;
|
||||
tr,
|
||||
th {
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
td,
|
||||
th {
|
||||
border-right: 1px solid #000;
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
.input {
|
||||
:deep(.ant-input) {
|
||||
border: 0 solid black !important;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
.ant-input {
|
||||
border: 0 solid black !important;
|
||||
background-color: #fff;
|
||||
}
|
||||
.firstTr {
|
||||
color: #000;
|
||||
}
|
||||
.smallText .ant-input-number-input {
|
||||
background-color: #fff;
|
||||
}
|
||||
.textArea {
|
||||
border: 0 solid white;
|
||||
}
|
||||
}
|
||||
/**去掉日期控件边框*/
|
||||
.ant-picker {
|
||||
border: 0 solid black !important;
|
||||
}
|
||||
}
|
||||
html[data-theme='dark'] {
|
||||
@borderColor: #3a3a3a;
|
||||
#staffBmTable {
|
||||
border: 1px solid @borderColor;
|
||||
tr,
|
||||
th {
|
||||
border-bottom: 1px solid @borderColor;
|
||||
}
|
||||
td,
|
||||
th {
|
||||
border-right: 1px solid @borderColor;
|
||||
border-bottom: 1px solid @borderColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ant-card {
|
||||
border-radius: 2px;
|
||||
margin: 0 auto;
|
||||
width: 750px;
|
||||
}
|
||||
|
||||
#staffCard {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 5px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#staffBmTitle {
|
||||
margin-top: 1px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
display: block;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
#staffBmTable {
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
|
||||
.tr-style {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
}
|
||||
|
||||
tr td:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
tr:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.colfirst {
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.colfour {
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.fontiframe {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.ant-form-item {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.input {
|
||||
:deep(.ant-input) {
|
||||
border-radius: 0;
|
||||
display: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-input {
|
||||
border-radius: 0;
|
||||
display: inherit;
|
||||
margin: 0;
|
||||
width: 255px;
|
||||
}
|
||||
|
||||
:deep(.ant-calendar-picker-input) {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.text {
|
||||
border: none !important;
|
||||
border-radius: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.firstTr {
|
||||
width: 16%;
|
||||
|
||||
.ant-form-item-control-wrapper {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.smallText .ant-input-number-input {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.lineHeight .ant-form-item-control {
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.textArea {
|
||||
resize: none;
|
||||
height: 118px;
|
||||
font-size: 12px;
|
||||
border-radius: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.staffLeaveTableId {
|
||||
margin-right: 87px;
|
||||
float: right;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
.ant-form label {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
:deep(.ant-form-item-label label) {
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,60 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { Modal } from 'ant-design-vue';
|
||||
|
||||
enum Api {
|
||||
list = '/joa/joaLoan/list',
|
||||
queryByTripApplyNo = '/joa/joaLoan/queryByTripApplyNo',
|
||||
queryTripByApplyNo = '/joa/joaBusinesStrip/queryByTripApplyNo',
|
||||
save = '/joa/joaLoan/add',
|
||||
edit = '/joa/joaLoan/edit',
|
||||
deleteOne = '/joa/joaLoan/delete',
|
||||
deleteBatch = '/joa/joaLoan/deleteBatch',
|
||||
}
|
||||
/**
|
||||
* 列表
|
||||
* @param params
|
||||
*/
|
||||
export const list = (params) => defHttp.get({ url: Api.list, params });
|
||||
/**
|
||||
* 根据借款信息
|
||||
* @param params
|
||||
*/
|
||||
export const queryByTripApplyNo = (params) => defHttp.get({ url: Api.queryByTripApplyNo, params }, { isTransformResponse: false });
|
||||
/**
|
||||
* 根据出差信息
|
||||
* @param params
|
||||
*/
|
||||
export const queryTripByApplyNo = (params) => defHttp.get({ url: Api.queryTripByApplyNo, params }, { isTransformResponse: false });
|
||||
/**
|
||||
* 删除一个
|
||||
*/
|
||||
export const deleteOne = (params, handleSuccess) => {
|
||||
return defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 批量删除
|
||||
* @param params
|
||||
*/
|
||||
export const batchDelete = (params, handleSuccess) => {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: '是否删除选中数据',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 保存或者更新
|
||||
* @param params
|
||||
*/
|
||||
export const saveOrUpdate = (params, isUpdate) => {
|
||||
let url = isUpdate ? Api.edit : Api.save;
|
||||
return defHttp.post({ url: url, params });
|
||||
};
|
||||
@@ -0,0 +1,42 @@
|
||||
import { FormSchema } from '/@/components/Table';
|
||||
export const columns = [
|
||||
{
|
||||
title: '借款人',
|
||||
dataIndex: 'loanUserName',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '部门名称',
|
||||
dataIndex: 'departName',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '借款时间',
|
||||
dataIndex: 'loanTime',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '借款金额',
|
||||
dataIndex: 'loanAmount',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '借款用途',
|
||||
dataIndex: 'loanUsage',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
dataIndex: 'remarks',
|
||||
width: 100,
|
||||
},
|
||||
];
|
||||
|
||||
export const searchFormSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'loanUserName',
|
||||
label: '借款人',
|
||||
component: 'Input',
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,136 @@
|
||||
<template>
|
||||
<BasicTable @register="registerTable" :rowSelection="rowSelection">
|
||||
<template #tableTitle>
|
||||
<!--<a-button type="primary" preIcon="ant-design:plus-outlined" @click="handleCreate"> 新增</a-button>-->
|
||||
<a-dropdown v-if="selectedRowKeys.length > 0">
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item key="1" @click="batchHandleDelete">
|
||||
<Icon icon="ant-design:delete-outlined"></Icon>
|
||||
删除
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
<a-button
|
||||
>批量操作
|
||||
<Icon icon="mdi:chevron-down"></Icon>
|
||||
</a-button>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
<!--借款申请-->
|
||||
<LoanModal @register="registerModal" @success="reload" />
|
||||
</template>
|
||||
<script lang="ts" name="leave-list" setup>
|
||||
import { ref } from 'vue';
|
||||
import { BasicTable, TableAction } from '/@/components/Table';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import LoanModal from './components/LoanModal.vue';
|
||||
import { columns, searchFormSchema } from './loan.data';
|
||||
import { list, deleteOne, batchDelete } from './loan.api';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
const [registerBpmModal, { openModal: bpmPicModal }] = useModal();
|
||||
const { createMessage, createConfirm } = useMessage();
|
||||
|
||||
// 列表页面公共参数、方法
|
||||
const { prefixCls, tableContext } = useListPage({
|
||||
designScope: 'loan-list',
|
||||
tableProps: {
|
||||
api: list,
|
||||
columns: columns,
|
||||
canResize: false,
|
||||
formConfig: {
|
||||
schemas: searchFormSchema,
|
||||
},
|
||||
actionColumn: {
|
||||
width: 120,
|
||||
},
|
||||
},
|
||||
});
|
||||
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
function handleCreate() {
|
||||
openModal(true, {
|
||||
isUpdate: false,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 编辑
|
||||
*/
|
||||
function handleEdit(record: Recordable) {
|
||||
openModal(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 详情
|
||||
*/
|
||||
function handleDetail(record) {
|
||||
openModal(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
isDetail: true,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 删除事件
|
||||
*/
|
||||
async function handleDelete(record) {
|
||||
await deleteOne({ id: record.id }, reload);
|
||||
}
|
||||
/**
|
||||
* 批量删除事件
|
||||
*/
|
||||
async function batchHandleDelete() {
|
||||
await batchDelete({ ids: selectedRowKeys.value }, reload);
|
||||
}
|
||||
/**
|
||||
* 审批进度
|
||||
*/
|
||||
async function handlePreviewPic(record) {
|
||||
bpmPicModal(true, {
|
||||
flowCode,
|
||||
dataId: record.id,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 下拉操作栏
|
||||
*/
|
||||
function getDropDownAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '详情',
|
||||
onClick: handleDetail.bind(null, record),
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
confirm: handleDelete.bind(null, record),
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,149 @@
|
||||
<template>
|
||||
<div v-if="iframeUrl" class="component_div" style="overflow-y: auto">
|
||||
<DesformView
|
||||
v-if="designFormInfo.status"
|
||||
class="desform-view"
|
||||
:isOnline="false"
|
||||
mode=""
|
||||
:url="designFormInfo.url"
|
||||
:parentNode="parentNode"
|
||||
:desformCode="designFormInfo.code"
|
||||
:dataId="designFormInfo.dataId"
|
||||
/>
|
||||
<iframe v-else :src="iframeUrl" frameborder="0" width="100%" :height="height" scrolling="auto"></iframe>
|
||||
</div>
|
||||
<div v-else class="component_div">
|
||||
<Suspense v-if="path">
|
||||
<template #default>
|
||||
<component v-if="path" :is="currentComponent" :formData="formData" form-bpm></component>
|
||||
</template>
|
||||
<template #fallback>
|
||||
<div style="width: 100%; text-align: center; padding-top: 60px">
|
||||
<a-spin spinning tip="表单加载中..." />
|
||||
</div>
|
||||
</template>
|
||||
</Suspense>
|
||||
<div v-else>表单地址不存在</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
/**
|
||||
* 流程动态表单
|
||||
*/
|
||||
import { ref, computed, reactive } from 'vue';
|
||||
import { getToken } from '/@/utils/auth';
|
||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
||||
import { importViewsFile } from '/@/utils';
|
||||
import { useGlobSetting } from '../../../../../hooks/setting';
|
||||
import { getBpmFormUrl } from "/@/utils/is";
|
||||
|
||||
export default {
|
||||
name: 'BpmDynamicForm',
|
||||
props: {
|
||||
path: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
formData: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
// 父级html
|
||||
parentNode: { type: Object as PropType<HTMLElement> },
|
||||
},
|
||||
setup(props) {
|
||||
const height = window.innerHeight - 120 + 'px';
|
||||
|
||||
/**
|
||||
* 如果是表单设计器表单 需要设置一些参数
|
||||
*/
|
||||
const designFormInfo = reactive({
|
||||
status: false,
|
||||
code: '',
|
||||
url: '',
|
||||
dataId: ''
|
||||
});
|
||||
|
||||
/**
|
||||
* 获取表单地址
|
||||
* @type {ComputedRef<unknown>}
|
||||
*/
|
||||
const iframeUrl = computed(() => {
|
||||
const { domainUrl } = useGlobSetting();
|
||||
//update:scott--date:20220830--for:注意未显示使用的const定义变量,ts编译的时候会被删掉,导致动态replace替换变量失效。
|
||||
// 将任务ID放到计算函数内部 当formData改变的时候会触发iframeUrl重复赋值
|
||||
let TASKID = props.formData.taskDefKey;
|
||||
let TOKEN = getToken();
|
||||
let DOMAIN_URL = domainUrl
|
||||
// TOKEN = NY5LzSY2VW1BSthYSnJArCFqbgwtZqSuyPQ/OD1n1twWJGU2RN/wkzf+kBVO5DztN85Ca9keeuaRAiwcatr8N0M15+Wv2SmRw82lMwawE2naX5tpJMpkxrUhUUcjnC+BSBL4+PV2JUXBFW8/oOG8HLqYvmPxoP7MMBhMi9D7lRY=
|
||||
|
||||
// URL支持{{ window.xxx }}占位符变量
|
||||
//const URL = (props.path || '').replace(/{{([^}}]+)?}}/g, (s1, s2) => eval(s2));
|
||||
const URL = getBpmFormUrl(props.path, TOKEN, DOMAIN_URL, TASKID);
|
||||
if (isURL(URL)) {
|
||||
if(URL.indexOf('desform/edit/')>=0 || URL.indexOf('desform/detail/')>=0){
|
||||
designFormInfo.url = URL;
|
||||
designFormInfo.status = true;
|
||||
designFormInfo.dataId = props.formData.vars['BPM_DES_DATA_ID'];
|
||||
designFormInfo.code = props.formData.vars['BPM_DES_FORM_CODE'];
|
||||
console.log('设计器表单参数', designFormInfo)
|
||||
}else{
|
||||
designFormInfo.status = false
|
||||
}
|
||||
return URL;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
});
|
||||
|
||||
// 表单地址兼容vue2
|
||||
const FORM_PATH_MAP = {
|
||||
'modules/bpm/task/form/OnlineFormDetail': 'super/bpm/process/components/OnlineFormDetail',
|
||||
'modules/bpm/task/form/OnlineFormOpt': 'super/bpm/process/components/OnlineFormOpt',
|
||||
//借款申请表单
|
||||
'modules/extbpm/joa/modules/JoaLoanApplyForm': 'super/bpm/example/joa/loan/components/LoanApplyForm',
|
||||
//借款表单
|
||||
'modules/extbpm/joa/modules/JoaLoanForm': 'super/bpm/example/joa/loan/components/LoanForm',
|
||||
//出差表单
|
||||
'modules/extbpm/joa/modules/JoaBusinesStripForm': 'super/bpm/example/joa/businessTrip/components/BusinessTripForm',
|
||||
//请假表单
|
||||
'modules/extbpm/joa/modules/JoaEmployeeLeaveForm': 'super/bpm/example/joa/leave/components/LeaveForm',
|
||||
//公文表单
|
||||
'modules/extbpm/joa/modules/JoaDocSendingForm': 'super/bpm/example/joa/docSend/components/DocSendForm',
|
||||
//批量请假单
|
||||
'modules/extbpm/biz/modules/ExtBizLeaveForm': 'super/bpm/example/batch/components/BizLeaveForm',
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取组件
|
||||
* @type {ComputedRef<function(): *>}
|
||||
*/
|
||||
const currentComponent = computed(() => {
|
||||
let temp = props.path;
|
||||
if (FORM_PATH_MAP[temp]) {
|
||||
temp = FORM_PATH_MAP[temp];
|
||||
}
|
||||
console.log('bpm组件名称:' + temp, 'bpm组件数据:' + props.formData);
|
||||
return createAsyncComponent(() => importViewsFile(temp));
|
||||
});
|
||||
|
||||
/**
|
||||
* 判断是否URL地址
|
||||
* @param {*} s
|
||||
*/
|
||||
function isURL(s) {
|
||||
return /^http[s]?:\/\/.*/.test(s);
|
||||
}
|
||||
|
||||
return {
|
||||
height,
|
||||
iframeUrl,
|
||||
currentComponent,
|
||||
designFormInfo
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,292 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="jee-bpm-graphic-containers">
|
||||
<div class="jee-bpm-graphic-canvas" :id="containerId"></div>
|
||||
</div>
|
||||
<bpm-node-info-modal @register="registerModal" @notify="handleModalVisible"></bpm-node-info-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { watch, ref, onMounted } from 'vue';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import BpmNodeInfoModal from './BpmNodeInfoModal.vue';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import inherits from 'inherits';
|
||||
import Viewer from 'bpmn-js/lib/Viewer';
|
||||
import ZoomScrollModule from 'diagram-js/lib/navigation/zoomscroll';
|
||||
import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas';
|
||||
import { append as svgAppend, attr as svgAttr, create as svgCreate } from 'tiny-svg';
|
||||
import { query as domQuery } from 'min-dom';
|
||||
function CustomViewer(options) {
|
||||
Viewer.call(this, options);
|
||||
}
|
||||
inherits(CustomViewer, Viewer);
|
||||
CustomViewer.prototype._modules = [].concat(Viewer.prototype._modules, [ZoomScrollModule, MoveCanvasModule]);
|
||||
|
||||
export default {
|
||||
name: 'BpmGraphic',
|
||||
props: {
|
||||
// 流程实例ID
|
||||
instanceId: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
center:{
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
components: {
|
||||
BpmNodeInfoModal,
|
||||
},
|
||||
emits: ['task'],
|
||||
setup(props, { emit }) {
|
||||
const url = {
|
||||
getProcessInfo: '/act/designer/api/getProcessXmlByInstanceId',
|
||||
getInstanceInfo: '/act/task/getFlowMsgByProcInstId',
|
||||
getNodePositionInfo: '/act/task/getNodePositionInfo',
|
||||
};
|
||||
const [registerModal, { openModal, closeModal }] = useModal();
|
||||
const containerId = 'jee-bpm-graphic-canvas';
|
||||
let bpmViewer = null;
|
||||
onMounted(() => {
|
||||
newViewer();
|
||||
});
|
||||
|
||||
let taskList = [];
|
||||
let currentTaskId = '';
|
||||
let currentNodeList = [];
|
||||
let historyNodeList = [];
|
||||
let historyLineList = [];
|
||||
let delayHandler = '';
|
||||
|
||||
watch(
|
||||
() => props.instanceId,
|
||||
(val) => {
|
||||
if (val) {
|
||||
init();
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
async function init() {
|
||||
let params = { processInstanceId: props.instanceId };
|
||||
// 1.加载流程设计xml
|
||||
let xml = await defHttp.get({ url: url.getProcessInfo, params }, { isTransformResponse: false });
|
||||
//console.log('xml', xml);
|
||||
// 2.加载流程实例信息
|
||||
let instanceInfo = await defHttp.get({ url: url.getInstanceInfo, params }, { isTransformResponse: false });
|
||||
//console.log('instanceInfo', instanceInfo);
|
||||
// 2.加载节点信息 NY5LzSY2VW1BSthYSnJArCFqbgwtZqSuyPQ/OD1n1twWJGU2RN/wkzf+kBVO5DztN85Ca9keeuaRAiwcatr8N0M15+Wv2SmRw82lMwawE2naX5tpJMpkxrUhUUcjnC+BSBL4+PV2JUXBFW8/oOG8HLqYvmPxoP7MMBhMi9D7lRY=
|
||||
let nodeInfo = await defHttp.get({ url: url.getNodePositionInfo, params }, { isTransformResponse: false });
|
||||
//console.log('nodeInfo', nodeInfo);
|
||||
if (nodeInfo.success) {
|
||||
taskList = nodeInfo.result.hisTasks;
|
||||
emit('task', taskList);
|
||||
}
|
||||
// console.log('taskList', nodeInfo.result)
|
||||
try {
|
||||
// 3.解析流程实例信息
|
||||
if (instanceInfo.success) {
|
||||
historyNodeList = instanceInfo.result.highLightedActivitiIdList;
|
||||
currentNodeList = instanceInfo.result.runningActivitiIdList;
|
||||
historyLineList = instanceInfo.result.highLightedFlowIds;
|
||||
}
|
||||
// 4.绘制流程
|
||||
newViewer();
|
||||
const result = await bpmViewer.importXML(xml);
|
||||
const { warnings } = result;
|
||||
console.log('bpm graphic warnings', warnings);
|
||||
// 5.调整图片位置
|
||||
const canvas = bpmViewer.get('canvas');
|
||||
if(props.center == true){
|
||||
canvas.zoom('fit-viewport', true);
|
||||
}
|
||||
// 6.创建箭头标记
|
||||
createArrow();
|
||||
// 7.设置节点、线的颜色
|
||||
setColor();
|
||||
// 8.节点事件
|
||||
addEvent();
|
||||
} catch (err) {
|
||||
console.log(err.message, err.warnings);
|
||||
}
|
||||
}
|
||||
|
||||
function setColor() {
|
||||
// access viewer components
|
||||
const canvas = bpmViewer.get('canvas');
|
||||
// 获取到全部节点
|
||||
const allShapes = bpmViewer.get('elementRegistry').getAll();
|
||||
//循环节点添加class
|
||||
allShapes.forEach((element) => {
|
||||
const shapeId = element.businessObject.id;
|
||||
// const shapeAttrs = element.businessObject.$attrs
|
||||
//console.info('123element', element)
|
||||
let type = element.type;
|
||||
if (type == 'bpmn:ExclusiveGateway' || type == 'bpmn:InclusiveGateway' || type == 'bpmn:ParallelGateway') {
|
||||
canvas.addMarker(shapeId, 'jee-bpm-gateway');
|
||||
}
|
||||
// add marker
|
||||
if (element.businessObject.$type != 'bpmn:Group') {
|
||||
if (element.businessObject.$type == 'bpmn:SequenceFlow') {
|
||||
if (historyLineList.includes(shapeId)) {
|
||||
canvas.addMarker(shapeId, 'jee-bpm-history-line');
|
||||
}
|
||||
} else {
|
||||
if (historyNodeList.includes(shapeId) && !currentNodeList.includes(shapeId)) {
|
||||
canvas.addMarker(shapeId, 'jee-bpm-history-node');
|
||||
}
|
||||
if (currentNodeList.includes(shapeId)) {
|
||||
canvas.addMarker(shapeId, 'jee-bpm-current-node');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 自定义箭头标记-默认箭头是黑色的
|
||||
function createArrow() {
|
||||
const marker = svgCreate('marker');
|
||||
svgAttr(marker, {
|
||||
id: 'active-arrow',
|
||||
viewBox: '0 0 20 20',
|
||||
refX: '11',
|
||||
refY: '10',
|
||||
markerWidth: '10',
|
||||
markerHeight: '10',
|
||||
orient: 'auto',
|
||||
fill: '#408af1',
|
||||
});
|
||||
const path = svgCreate('path');
|
||||
svgAttr(path, {
|
||||
d: 'M 1 5 L 11 10 L 1 15 Z',
|
||||
style: 'stroke-width: 1px; stroke-linecap: round; stroke-dasharray: 10000, 1;',
|
||||
});
|
||||
const defs = domQuery('defs');
|
||||
svgAppend(marker, path);
|
||||
svgAppend(defs, marker);
|
||||
}
|
||||
|
||||
//添加节点事件
|
||||
function addEvent() {
|
||||
const eventBus = bpmViewer.get('eventBus');
|
||||
eventBus.on('element.hover', (e) => {
|
||||
const { element } = e;
|
||||
if (!element.parent) {
|
||||
// 这里关闭modal
|
||||
delayClose();
|
||||
currentTaskId = '';
|
||||
//console.log('鼠标移至空白处', element);
|
||||
return;
|
||||
}
|
||||
if (!e || element.type === 'bpmn:Process') {
|
||||
return false;
|
||||
} else {
|
||||
let temp = element.id;
|
||||
let type = element.type;
|
||||
if (currentTaskId != temp && 'bpmn:UserTask' == type && historyNodeList.indexOf(temp) >= 0) {
|
||||
/**
|
||||
* 满足3个条件才弹框显示节点信息
|
||||
* 1.当前节点不是鼠标选中的节点,防止多次调用
|
||||
* 2.必须是任务节点
|
||||
* 3.必须是处理过的节点
|
||||
*/
|
||||
currentTaskId = temp;
|
||||
//console.log('准备开启modal', e);
|
||||
showNodeInfo();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showNodeInfo() {
|
||||
closeModal();
|
||||
openModal(true, {
|
||||
dataList: taskList,
|
||||
taskId: currentTaskId,
|
||||
});
|
||||
}
|
||||
|
||||
function handleModalVisible(flag) {
|
||||
//console.log('handleModalVisible', flag)
|
||||
if (flag == true) {
|
||||
clearTimeout(delayHandler);
|
||||
}
|
||||
}
|
||||
|
||||
function delayClose() {
|
||||
//console.log('delayClose')
|
||||
delayHandler = setTimeout(() => {
|
||||
//console.log('准备关闭modal');
|
||||
if (currentTaskId) {
|
||||
showNodeInfo();
|
||||
} else {
|
||||
closeModal();
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function newViewer() {
|
||||
if (bpmViewer == null) {
|
||||
let dom = document.getElementById(containerId);
|
||||
bpmViewer = new CustomViewer({
|
||||
container: dom,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
registerModal,
|
||||
containerId,
|
||||
handleModalVisible,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.jee-bpm-graphic-containers {
|
||||
width: 100%;
|
||||
height: calc(100vh - 250px);
|
||||
}
|
||||
|
||||
.jee-bpm-graphic-canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.jee-bpm-graphic-canvas .bjs-powered-by {
|
||||
display: none;
|
||||
}
|
||||
/**网关样式*/
|
||||
.jee-bpm-gateway .djs-visual path {
|
||||
stroke: none !important;
|
||||
}
|
||||
|
||||
/**走过的分支线样式 */
|
||||
.jee-bpm-history-line .djs-visual > :nth-child(1) {
|
||||
stroke: #408af1 !important;
|
||||
}
|
||||
.jee-bpm-history-line path {
|
||||
marker-end: url(#active-arrow) !important;
|
||||
stroke-width: 2px!important;
|
||||
}
|
||||
|
||||
/**走过的节点样式 */
|
||||
.jee-bpm-history-node .djs-visual > :nth-child(1) {
|
||||
fill: #51a2f13b !important;
|
||||
stroke: #408af1 !important;
|
||||
}
|
||||
|
||||
/**当前节点样式 */
|
||||
.jee-bpm-current-node .djs-visual > :nth-child(1) {
|
||||
fill: #f9ca6d !important;
|
||||
stroke: #cd9423 !important;
|
||||
}
|
||||
/* .jee-bpm-current-node .djs-visual > text {
|
||||
fill: #fff !important;
|
||||
}*/
|
||||
</style>
|
||||
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<BasicModal title="流程图" @register="registerModal" keyboard maskClosable :bodyStyle="bodyStyle" :width="modalWidth" destroyOnClose :footer="null" @close="handleClose">
|
||||
<a-spin :spinning="loading">
|
||||
<BpmGraphic :instanceId="procInsId" center></BpmGraphic>
|
||||
</a-spin>
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { ref, nextTick } from 'vue';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import BpmGraphic from './BpmGraphic.vue';
|
||||
|
||||
export default {
|
||||
name: 'BpmGraphicModal',
|
||||
components: {
|
||||
BpmGraphic,
|
||||
BasicModal,
|
||||
},
|
||||
setup() {
|
||||
const procInsId = ref('');
|
||||
const loading = ref(true);
|
||||
//useModalInner
|
||||
const [registerModal, { closeModal }] = useModalInner((data) => {
|
||||
const { flowCode, dataId } = data;
|
||||
loading.value = true;
|
||||
preview(flowCode, dataId);
|
||||
});
|
||||
|
||||
const modalWidth = window.innerWidth * 0.8;
|
||||
const bodyStyle = ref({});
|
||||
let height = window.innerHeight - 180;
|
||||
bodyStyle.value = {
|
||||
height: height+'px',
|
||||
overflowY: 'auto'
|
||||
}
|
||||
|
||||
|
||||
function preview(flowCode, dataId) {
|
||||
let params = {
|
||||
flowCode: flowCode,
|
||||
dataId: dataId,
|
||||
};
|
||||
const url = '/act/process/extActFlowData/getProcessInfo';
|
||||
defHttp.get({ url, params }).then((data) => {
|
||||
procInsId.value = data.processInstanceId;
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
function handleClose() {
|
||||
closeModal();
|
||||
}
|
||||
|
||||
return {
|
||||
registerModal,
|
||||
handleClose,
|
||||
procInsId,
|
||||
loading,
|
||||
modalWidth,
|
||||
bodyStyle
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,137 @@
|
||||
<template>
|
||||
<BasicModal
|
||||
title="任务审批详情"
|
||||
@register="registerModal"
|
||||
keyboard
|
||||
:canFullscreen="false"
|
||||
:width="280"
|
||||
:mask="false"
|
||||
:footer="null"
|
||||
:centered="true"
|
||||
@close="handleClose"
|
||||
wrapClassName="jeecg-bpm-node-detail"
|
||||
:bodyStyle="{ padding: '0' }"
|
||||
>
|
||||
<div style="height: 300px; padding-bottom: 5px; overflow: hidden; overflow-y: auto; overflow-x: auto">
|
||||
<a-descriptions title="" size="small" :column="1" bordered v-for="item in nodeInfoList" style="margin-bottom: 5px">
|
||||
<a-descriptions-item v-for="(schema, index) in nodeSchema" :key="index" :label="schema.label" :labelMinWidth="70">{{
|
||||
item[schema.field]
|
||||
}}</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</div>
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { ref, nextTick } from 'vue';
|
||||
|
||||
export default {
|
||||
name: 'BpmNodeInfoModal',
|
||||
components: {
|
||||
BasicModal,
|
||||
},
|
||||
emits: ['register', 'notify'],
|
||||
setup(_p, { emit }) {
|
||||
//useModalInner
|
||||
const [registerModal, { closeModal }] = useModalInner((data) => {
|
||||
const { dataList, taskId } = data;
|
||||
getNodeInfo(dataList, taskId);
|
||||
});
|
||||
|
||||
const nodeSchema = [
|
||||
{
|
||||
field: 'taskName',
|
||||
label: '任务名称',
|
||||
labelMinWidth: 60,
|
||||
},
|
||||
{
|
||||
field: 'taskAssigneeId',
|
||||
label: '执行人',
|
||||
},
|
||||
{
|
||||
field: 'taskBeginTime',
|
||||
label: '开始时间',
|
||||
},
|
||||
{
|
||||
field: 'taskEndTime',
|
||||
label: '结束时间',
|
||||
},
|
||||
{
|
||||
field: 'durationStr',
|
||||
label: '耗时',
|
||||
},
|
||||
{
|
||||
field: 'remarks',
|
||||
label: '意见',
|
||||
/*style="word-break: break-all;"*/
|
||||
},
|
||||
];
|
||||
|
||||
const nodeInfoList = ref([]);
|
||||
function getNodeInfo(dataList, taskId) {
|
||||
let arr = [];
|
||||
for (let item of dataList) {
|
||||
if (item.taskId == taskId) {
|
||||
arr.push(item);
|
||||
}
|
||||
}
|
||||
nodeInfoList.value = arr;
|
||||
toggleModalEvent(true);
|
||||
}
|
||||
|
||||
function handleClose() {
|
||||
closeModal();
|
||||
nodeInfoList.value = [];
|
||||
toggleModalEvent(false);
|
||||
}
|
||||
|
||||
function notifyClose() {
|
||||
emit('notify', false);
|
||||
}
|
||||
function notifyVisible() {
|
||||
emit('notify', true);
|
||||
}
|
||||
// 鼠标进入/离开modal,都会通知父组件
|
||||
function toggleModalEvent(flag) {
|
||||
nextTick(() => {
|
||||
const arr = document.getElementsByClassName('jeecg-bpm-node-detail');
|
||||
let modal = arr[0];
|
||||
if (modal) {
|
||||
if (flag == true) {
|
||||
modal.addEventListener('mouseenter', notifyVisible);
|
||||
modal.addEventListener('mouseleave', notifyClose);
|
||||
} else {
|
||||
modal.removeEventListener('mouseenter', notifyVisible);
|
||||
modal.removeEventListener('mouseleave', notifyClose);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
registerModal,
|
||||
nodeInfoList,
|
||||
nodeSchema,
|
||||
handleClose,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.jeecg-bpm-node-detail {
|
||||
pointer-events: none;
|
||||
.ant-modal-header {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.ant-modal-close-x {
|
||||
height: 46px;
|
||||
}
|
||||
.ant-descriptions-item-label {
|
||||
padding: 8px !important;
|
||||
width: 80px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<div>
|
||||
<process-online-form :table-name="tableName" :task-id="taskId" :data-id="dataId" disabled />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ProcessOnlineForm from '/@/views/super/online/cgform/auto/comp/ProcessOnlineForm.vue';
|
||||
import { ref } from 'vue';
|
||||
export default {
|
||||
name: 'OnlineFormDetail',
|
||||
components: {
|
||||
ProcessOnlineForm,
|
||||
},
|
||||
props: {
|
||||
formData: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const tableName = ref('');
|
||||
const dataId = ref('');
|
||||
const taskId = ref('');
|
||||
//update--begin--autor:scott-----date:20191005------for:流程节点配置组件URL的时候也支持传递参数了,解决TASK #3238流程节点无法与online的复制视图对接------
|
||||
//节点配置表单URL,VUE组件类型对应的拓展参数
|
||||
let extendUrlParams = props.formData.extendUrlParams;
|
||||
if (extendUrlParams && extendUrlParams.view) {
|
||||
tableName.value = extendUrlParams.view;
|
||||
} else {
|
||||
tableName.value = props.formData.tableName;
|
||||
}
|
||||
//update--end--autor:scott-----date:20191005------for:流程节点配置组件URL的时候也支持传递参数了,解决TASK #3238流程节点无法与online的复制视图对接------
|
||||
dataId.value = props.formData.dataId;
|
||||
taskId.value = props.formData.taskDefKey;
|
||||
|
||||
return {
|
||||
tableName,
|
||||
dataId,
|
||||
taskId,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<div>
|
||||
<process-online-form :table-name="tableName" :task-id="taskId" :data-id="dataId" :disabled="false" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ProcessOnlineForm from '/@/views/super/online/cgform/auto/comp/ProcessOnlineForm.vue';
|
||||
import { ref } from 'vue';
|
||||
export default {
|
||||
name: 'OnlineFormOpt',
|
||||
components: {
|
||||
ProcessOnlineForm,
|
||||
},
|
||||
props: {
|
||||
formData: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const tableName = ref('');
|
||||
const dataId = ref('');
|
||||
const taskId = ref('');
|
||||
//update--begin--autor:scott-----date:20191005------for:流程节点配置组件URL的时候也支持传递参数了,解决TASK #3238流程节点无法与online的复制视图对接------
|
||||
//节点配置表单URL,VUE组件类型对应的拓展参数
|
||||
let extendUrlParams = props.formData.extendUrlParams;
|
||||
if (extendUrlParams && extendUrlParams.view) {
|
||||
tableName.value = extendUrlParams.view;
|
||||
} else {
|
||||
tableName.value = props.formData.tableName;
|
||||
}
|
||||
//update--end--autor:scott-----date:20191005------for:流程节点配置组件URL的时候也支持传递参数了,解决TASK #3238流程节点无法与online的复制视图对接------
|
||||
dataId.value = props.formData.dataId;
|
||||
taskId.value = props.formData.taskDefKey;
|
||||
|
||||
return {
|
||||
tableName,
|
||||
dataId,
|
||||
taskId,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,263 @@
|
||||
<template>
|
||||
<BasicModal title="选择用户" @register="registerModal" width="100%" @ok="handleSelectSuccess" :canFullscreen="false" keyboard defaultFullscreen>
|
||||
<a-row>
|
||||
<!-- 左侧树-选择部门 -->
|
||||
<a-col :xs="24" :sm="5">
|
||||
<a-card title="组织机构" :bordered="true">
|
||||
<a-alert type="info" :showIcon="true">
|
||||
<template #message>
|
||||
当前选择:
|
||||
<span v-if="departInfo.currentSelectRow.title">{{ departInfo.currentSelectRow.title }}</span>
|
||||
<a v-if="departInfo.currentSelectRow.title" style="margin-left: 10px" @click="onClearSelectedDepart">取消选择</a>
|
||||
</template>
|
||||
</a-alert>
|
||||
<!--组织机构-->
|
||||
<a-directory-tree
|
||||
selectable
|
||||
:selectedKeys="departInfo.selectedKeys"
|
||||
:checkStrictly="true"
|
||||
@select="onSelectDepart"
|
||||
:dropdownStyle="{ maxHeight: '200px', overflow: 'auto' }"
|
||||
:load-data="onLoadTreeData"
|
||||
:treeData="departInfo.treeData"
|
||||
/>
|
||||
</a-card>
|
||||
</a-col>
|
||||
|
||||
<!-- 中间列表-展示用户信息 -->
|
||||
<a-col :xs="24" :sm="13">
|
||||
<a-card title="选择人员" :bordered="true" :bodyStyle="{ paddingTop: '1px' }">
|
||||
<BasicTable @register="registerTable" :rowSelection="rowSelection" />
|
||||
</a-card>
|
||||
</a-col>
|
||||
|
||||
<!-- 右侧显示已经选中用户,支持调整顺序 -->
|
||||
<a-col :xs="24" :sm="6">
|
||||
<a-card title="已选用户" :bordered="true">
|
||||
<BasicTable @register="registerSelectedUserTable">
|
||||
<!--操作栏-->
|
||||
<template #action="{ record }">
|
||||
<a-button type="primary" size="small" @click="handleDelete(record)" preIcon="ant-design:delete">删除</a-button>
|
||||
</template>
|
||||
</BasicTable>
|
||||
</a-card>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { ref, nextTick, unref, reactive, toRaw, watch } from 'vue';
|
||||
import { getDepartTreeData, getDepartUserList, getUserList, columns, selectedUserColumns, searchFormSchema } from './useSelectUser';
|
||||
import { BasicTable, TableAction } from '/@/components/Table';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
|
||||
export default {
|
||||
name: 'BpmSelectUserModal',
|
||||
components: {
|
||||
BasicModal,
|
||||
BasicTable,
|
||||
},
|
||||
props: {
|
||||
multi: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
emits: ['selected', 'register'],
|
||||
setup(props, { emit }) {
|
||||
const selectedList = ref([]);
|
||||
const [registerModal, { closeModal }] = useModalInner((data) => {
|
||||
showSelectedValue(data);
|
||||
});
|
||||
|
||||
/*-----------------部门---begin----------------*/
|
||||
const departInfo = reactive({
|
||||
treeData: [],
|
||||
selectedKeys: [],
|
||||
currentSelectRow: {
|
||||
title: '',
|
||||
},
|
||||
});
|
||||
function onSelectDepart(data, { node }) {
|
||||
departInfo.selectedKeys[0] = data[0];
|
||||
departInfo.currentSelectRow = toRaw(node.dataRef);
|
||||
console.log(departInfo);
|
||||
reload();
|
||||
}
|
||||
function onClearSelectedDepart() {
|
||||
departInfo.selectedKeys = [];
|
||||
departInfo.currentSelectRow = { title: '' };
|
||||
reload();
|
||||
}
|
||||
|
||||
async function loadRootDepart() {
|
||||
const result = await getDepartTreeData();
|
||||
if (Array.isArray(result)) {
|
||||
departInfo.treeData = result;
|
||||
}
|
||||
}
|
||||
async function onLoadTreeData(treeNode) {
|
||||
try {
|
||||
const result = await getDepartTreeData({
|
||||
pid: treeNode.dataRef.id,
|
||||
});
|
||||
if (result.length == 0) {
|
||||
treeNode.dataRef.isLeaf = true;
|
||||
} else {
|
||||
treeNode.dataRef.children = result;
|
||||
}
|
||||
// departInfo.treeData = [...departInfo.treeData]
|
||||
} catch (e) {
|
||||
console.error('部门树子节点加载失败', e);
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
/*-----------------部门---end----------------*/
|
||||
|
||||
/*-----------------用户列表---begin----------------*/
|
||||
async function queryUserList(params) {
|
||||
let arr = departInfo.selectedKeys;
|
||||
if (arr.length > 0) {
|
||||
//根据部门查询
|
||||
params['id'] = arr[0];
|
||||
let result = await getDepartUserList(params);
|
||||
if (params.username) {
|
||||
result.records = result.records.filter((item) => {
|
||||
return item.username.indexOf(params.username) != -1;
|
||||
});
|
||||
}
|
||||
return Promise.resolve(result);
|
||||
} else {
|
||||
return getUserList(params);
|
||||
}
|
||||
}
|
||||
const { tableContext } = useListPage({
|
||||
designScope: 'bpm-select-user',
|
||||
pagination: true,
|
||||
tableProps: {
|
||||
title: '',
|
||||
api: queryUserList,
|
||||
columns: columns,
|
||||
showActionColumn: false,
|
||||
showTableSetting: false,
|
||||
canResize: false,
|
||||
clickToRowSelect: true,
|
||||
formConfig: {
|
||||
labelWidth: '90px',
|
||||
schemas: searchFormSchema,
|
||||
autoAdvancedCol: 4,
|
||||
//update-begin-author:liusq---date:2024-06-11--for: 指定会签人员的弹框 查询遮挡了
|
||||
baseColProps: { xs: 24, sm: 24, md: 24, lg: 12, xl: 8, xxl: 8 },
|
||||
actionColOptions: { xs: 24, sm: 24, md: 24, lg: 12, xl: 8, xxl: 8 },
|
||||
//update-end-author:liusq---date:2024-06-11--for:指定会签人员的弹框 查询遮挡了
|
||||
},
|
||||
},
|
||||
});
|
||||
const [registerTable, { reload, deleteSelectRowByKey }, { rowSelection, selectedRows, selectedRowKeys }] = tableContext;
|
||||
|
||||
watch(
|
||||
() => props.multi,
|
||||
(val) => {
|
||||
if (val === false) {
|
||||
rowSelection.type = 'radio';
|
||||
} else {
|
||||
rowSelection.type = 'checkbox';
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/*-----------------用户列表--end-----------------*/
|
||||
const selectedUserList = ref([]);
|
||||
//update-begin-author:liusq---date:2024-06-11--for: TV360X-1047 指定下一步操作人/抄送给,选人组件无法多选。
|
||||
watch(
|
||||
selectedRows,
|
||||
() => {
|
||||
let arr = [];
|
||||
for (let row of unref(selectedRows)) {
|
||||
arr.push({
|
||||
realname: row.realname,
|
||||
username: row.username,
|
||||
id: row.id,
|
||||
});
|
||||
}
|
||||
selectedUserList.value = arr;
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
//update-end-author:liusq---date:2024-06-11--for: TV360X-1047 指定下一步操作人/抄送给,选人组件无法多选。
|
||||
|
||||
const { tableContext: selectedTableContext } = useListPage({
|
||||
designScope: 'bpm-select-user',
|
||||
pagination: false,
|
||||
tableProps: {
|
||||
title: '',
|
||||
columns: selectedUserColumns,
|
||||
pagination: false,
|
||||
dataSource: selectedUserList,
|
||||
showActionColumn: true,
|
||||
showTableSetting: false,
|
||||
canResize: false,
|
||||
useSearchForm: false,
|
||||
},
|
||||
});
|
||||
const [registerSelectedUserTable] = selectedTableContext;
|
||||
function handleDelete(record) {
|
||||
let id = record.id;
|
||||
let arr = selectedUserList.value;
|
||||
arr = arr.filter((item) => item.id != id);
|
||||
selectedUserList.value = arr;
|
||||
deleteSelectRowByKey(record.id);
|
||||
}
|
||||
|
||||
function handleSelectSuccess() {
|
||||
let arr = toRaw(selectedUserList.value);
|
||||
emit('selected', arr);
|
||||
closeModal();
|
||||
}
|
||||
|
||||
/**
|
||||
* 弹框打开 回显下拉框选中的数据
|
||||
* @param data
|
||||
*/
|
||||
function showSelectedValue(data) {
|
||||
let selectedValue = data.selected;
|
||||
if (!selectedValue || selectedValue.length == 0) {
|
||||
selectedUserList.value = [];
|
||||
selectedRows.value = [];
|
||||
selectedRowKeys.value = [];
|
||||
} else {
|
||||
let arr1 = [],
|
||||
arr2 = [],
|
||||
arr3 = [];
|
||||
for (let item of selectedValue) {
|
||||
arr1.push(item.id);
|
||||
arr2.push({ ...item });
|
||||
arr3.push({ ...item });
|
||||
}
|
||||
selectedRowKeys.value = arr1;
|
||||
selectedUserList.value = arr2;
|
||||
selectedRows.value = arr3;
|
||||
}
|
||||
}
|
||||
|
||||
loadRootDepart();
|
||||
return {
|
||||
registerModal,
|
||||
handleSelectSuccess,
|
||||
selectedList,
|
||||
departInfo,
|
||||
onSelectDepart,
|
||||
onClearSelectedDepart,
|
||||
onLoadTreeData,
|
||||
registerTable,
|
||||
rowSelection,
|
||||
registerSelectedUserTable,
|
||||
handleDelete,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<div class="bpmSelectUser" v-bind="$attrs">
|
||||
<a-select style="width: 300px" mode="multiple" :placeholder="placeholder" :value="selectValue" :options="options" @change="handleChange" />
|
||||
<a-button type="primary" @click="openSelect" preIcon="ant-design:search-outlined" style="margin-left: 8px">选择</a-button>
|
||||
<a-button type="primary" @click="clearSelected" preIcon="ant-design:reload-outlined" style="margin-left: 8px">清空</a-button>
|
||||
</div>
|
||||
<teleport to="body">
|
||||
<bpm-select-user-modal @register="registerModal" @selected="onSelected" />
|
||||
</teleport>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 流程审批中选择用户用 - 只管选择,不管回显
|
||||
*/
|
||||
import { ref, toRaw, computed } from 'vue';
|
||||
import BpmSelectUserModal from './BpmSelectUserModal.vue';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
|
||||
export default {
|
||||
name: 'BpmSelectUser',
|
||||
components: {
|
||||
BpmSelectUserModal,
|
||||
},
|
||||
props: {
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
emits: ['change'],
|
||||
setup(_p, { emit }) {
|
||||
let selectedUserList = [];
|
||||
const options = ref([]);
|
||||
const selectValue = ref([]);
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
const lastSelectedRows = ref([]);
|
||||
|
||||
function openSelect() {
|
||||
let arr = getModalData();
|
||||
openModal(true, {
|
||||
selected: arr,
|
||||
});
|
||||
selectedUserList = [];
|
||||
}
|
||||
|
||||
function clearSelected() {
|
||||
selectValue.value = [];
|
||||
}
|
||||
|
||||
function getModalData() {
|
||||
//找rows
|
||||
let arr = lastSelectedRows.value;
|
||||
//找username
|
||||
let arr2 = selectValue.value;
|
||||
let dataArray = arr.filter((item) => arr2.indexOf(item.username) >= 0);
|
||||
return dataArray;
|
||||
}
|
||||
|
||||
function onSelected(data) {
|
||||
lastSelectedRows.value = data;
|
||||
let arr1 = [],
|
||||
arr2 = [];
|
||||
if (data && data.length > 0) {
|
||||
data.map((item) => {
|
||||
arr1.push(item.username);
|
||||
arr2.push({ value: item.username });
|
||||
});
|
||||
}
|
||||
selectValue.value = arr1;
|
||||
options.value = arr2;
|
||||
selectedUserList = data;
|
||||
emit('change', data);
|
||||
}
|
||||
|
||||
function handleChange(values) {
|
||||
selectValue.value = values;
|
||||
let data = selectedUserList.filter((item) => values.indexOf(item.username) >= 0);
|
||||
emit('change', data);
|
||||
}
|
||||
|
||||
return {
|
||||
selectValue,
|
||||
options,
|
||||
openSelect,
|
||||
clearSelected,
|
||||
onSelected,
|
||||
handleChange,
|
||||
registerModal,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
// update-begin--author:liaozhiyang---date:20240605---for:【TV360X-1050】Safari浏览器指定下一步处理人页面控件没对齐
|
||||
.ant-select {
|
||||
vertical-align: middle;
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20240605---for:【TV360X-1050】Safari浏览器指定下一步处理人页面控件没对齐
|
||||
</style>
|
||||
@@ -0,0 +1,88 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { BasicColumn, FormSchema } from '/@/components/Table';
|
||||
|
||||
export enum Api {
|
||||
departList = '/sys/sysDepart/queryDepartTreeSync',
|
||||
userList = '/sys/user/list',
|
||||
departUserList = '/sys/user/queryUserByDepId',
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取部门树列表
|
||||
*/
|
||||
export const getDepartTreeData = (params?) => defHttp.get({ url: Api.departList, params });
|
||||
|
||||
/**
|
||||
* 获取用户列表
|
||||
*/
|
||||
export const getUserList = (params?) => defHttp.get({ url: Api.userList, params });
|
||||
|
||||
/**
|
||||
* 获取指定部门用户列表
|
||||
*/
|
||||
export const getDepartUserList = (params?) => defHttp.get({ url: Api.departUserList, params });
|
||||
|
||||
/**
|
||||
* 用户列表
|
||||
*/
|
||||
export const columns: BasicColumn[] = [
|
||||
{
|
||||
title: '用户账号',
|
||||
align: 'center',
|
||||
dataIndex: 'username',
|
||||
ellipsis: true,
|
||||
width: 130,
|
||||
},
|
||||
{
|
||||
title: '用户姓名',
|
||||
align: 'center',
|
||||
width: 150,
|
||||
dataIndex: 'realname',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '部门',
|
||||
align: 'center',
|
||||
width: 150,
|
||||
dataIndex: 'orgCode',
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* 选中用户列表
|
||||
*/
|
||||
export const selectedUserColumns: BasicColumn[] = [
|
||||
{
|
||||
title: '用户姓名',
|
||||
align: 'center',
|
||||
width: 150,
|
||||
dataIndex: 'realname',
|
||||
ellipsis: true,
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* 查询条件
|
||||
*/
|
||||
export const searchFormSchema: FormSchema[] = [
|
||||
{
|
||||
label: '用户姓名',
|
||||
field: 'realname',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
style: {
|
||||
width: '150px',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '用户账号',
|
||||
field: 'username',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
style: {
|
||||
width: '150px',
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<!--流程图弹窗-->
|
||||
<BasicModal v-bind="$attrs" :bodyStyle="bodyStyle" :width="900" destroyOnClose :footer="null" @register="registerModal" title="流程图">
|
||||
<BpmGraphic :instanceId="procInsId"></BpmGraphic>
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, unref, reactive, toRaw } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/src/components/Modal';
|
||||
import BpmGraphic from '/src/views/super/bpm/process/components/BpmGraphic.vue';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { getProcessInfo } from './bpm.api';
|
||||
|
||||
// Emits声明
|
||||
const emit = defineEmits(['register']);
|
||||
// 提示声明
|
||||
const $message = useMessage();
|
||||
// 流程实例id
|
||||
const procInsId = ref('');
|
||||
//样式
|
||||
const bodyStyle = {
|
||||
'overflow-y': 'auto',
|
||||
'overflow-x': 'auto',
|
||||
};
|
||||
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (params) => {
|
||||
//初始化数据
|
||||
await initData(params);
|
||||
});
|
||||
|
||||
/**
|
||||
* 初始化流程数据
|
||||
* @param params
|
||||
*/
|
||||
async function initData(params) {
|
||||
let res = await getProcessInfo(params);
|
||||
if (res.success) {
|
||||
procInsId.value = res.result.processInstanceId;
|
||||
} else {
|
||||
$message.warning(res.message);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,126 @@
|
||||
<template>
|
||||
<!-- 历史流程任务处理弹出框 -->
|
||||
<a-modal
|
||||
width="80%"
|
||||
style="top: 20px"
|
||||
destroyOnClose
|
||||
:title="data.title"
|
||||
v-model:open="data.visible"
|
||||
:bodyStyle="data.bodyStyle"
|
||||
:footer="null"
|
||||
@cancel="handleModalCancel"
|
||||
>
|
||||
<a-tabs defaultActiveKey="1" tabPosition="left">
|
||||
<a-tab-pane key="1">
|
||||
<template #tab>
|
||||
<Icon icon="ant-design:file-text-outlined" />
|
||||
<span>附加单据</span>
|
||||
</template>
|
||||
<div class="component_div">
|
||||
<template v-if="data.compType == 'comp'">
|
||||
<DynamicLink :path="path" :formData="formData"></DynamicLink>
|
||||
</template>
|
||||
<template v-else-if="data.compType == 'iframe'">
|
||||
<iframe :src="data.iframeUrl" frameborder="0" width="100%" :height="data.height" scrolling="auto"></iframe>
|
||||
</template>
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
|
||||
<a-tab-pane key="2">
|
||||
<template #tab>
|
||||
<Icon icon="ant-design:file-text-outlined" />
|
||||
<span>审批记录</span>
|
||||
</template>
|
||||
<HisTaskModule :formData="formData"></HisTaskModule>
|
||||
</a-tab-pane>
|
||||
|
||||
<a-tab-pane key="3">
|
||||
<template #tab>
|
||||
<Icon icon="ant-design:sliders-outlined" />
|
||||
<span>流程跟踪</span>
|
||||
</template>
|
||||
<ProcessDiagram :formData="formData"></ProcessDiagram>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, unref, reactive } from 'vue';
|
||||
import {getBpmFormUrl, isUrl} from '/@/utils/is';
|
||||
import { getToken } from '/@/utils/auth';
|
||||
import { useGlobSetting } from '/@/hooks/setting';
|
||||
import DynamicLink from './DynamicLink.vue';
|
||||
import ProcessDiagram from './ProcessDiagram.vue';
|
||||
import HisTaskModule from './HisTaskModule.vue';
|
||||
import { getBizHisProcessNodeInfo } from './bpm.api';
|
||||
const { domainUrl } = useGlobSetting();
|
||||
//数据
|
||||
const data = reactive({
|
||||
loading: false,
|
||||
title: '流程',
|
||||
visible: false,
|
||||
bodyStyle: {
|
||||
padding: '0',
|
||||
height: window.innerHeight - 80 + 'px',
|
||||
'overflow-y': 'auto',
|
||||
},
|
||||
height: window.innerHeight - 120 + 'px',
|
||||
iframeUrl: '',
|
||||
compType: '',
|
||||
});
|
||||
|
||||
const formData = ref({});
|
||||
const path = ref('');
|
||||
/**
|
||||
* 关闭弹窗
|
||||
*/
|
||||
function handleModalCancel() {
|
||||
data.visible = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开弹窗前处理
|
||||
* @param record
|
||||
*/
|
||||
async function handleTrack(params) {
|
||||
let res = await getBizHisProcessNodeInfo(params);
|
||||
if (res.success) {
|
||||
console.log('获取流程节点信息', res);
|
||||
formData.value = {
|
||||
dataId: res.result.dataId,
|
||||
procInsId: res.result.procInsId,
|
||||
tableName: res.result.tableName,
|
||||
vars: res.result.records,
|
||||
};
|
||||
console.log('------获取流程节点信息', unref(formData));
|
||||
path.value = res.result.formUrl;
|
||||
console.log('获取流程节点信息', path);
|
||||
let TOKEN = getToken();
|
||||
let DOMAIN_URL = domainUrl;
|
||||
let TASKID = unref(formData).taskDefKey;
|
||||
|
||||
//let URL = (unref(path) || '').replace(/{{([^}}]+)?}}/g, (s1, s2) => eval(s2)); // URL支持{{ window.xxx }}占位符变量
|
||||
//获取流程审批url
|
||||
let URL = getBpmFormUrl(unref(path), TOKEN, DOMAIN_URL, TASKID);
|
||||
if (isUrl(URL)) {
|
||||
data.iframeUrl = URL;
|
||||
data.compType = 'iframe';
|
||||
} else {
|
||||
data.compType = 'comp';
|
||||
}
|
||||
data.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
handleTrack,
|
||||
data,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.ant-tabs-left-content {
|
||||
padding-top: 10px !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<!--委派弹窗-->
|
||||
<BasicModal
|
||||
v-bind="$attrs"
|
||||
@register="registerModal"
|
||||
destroyOnClose
|
||||
:bodyStyle="{ minHeight: '100px', maxHeight: '100px' }"
|
||||
:title="title"
|
||||
@ok="handleSubmit"
|
||||
:width="700"
|
||||
>
|
||||
<BasicForm @register="registerForm" />
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, unref } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||
import { delegateFormSchema } from './bpm.data';
|
||||
// 声明Emits
|
||||
const emit = defineEmits(['success', 'register']);
|
||||
//组件接受传参
|
||||
const props = defineProps({
|
||||
title: { type: String, default: '请选择委托人', required: false },
|
||||
});
|
||||
|
||||
//表单配置
|
||||
const [registerForm, { resetFields, validate }] = useForm({
|
||||
labelWidth: 90,
|
||||
schemas: delegateFormSchema,
|
||||
showActionButtonGroup: false,
|
||||
});
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
await resetFields();
|
||||
});
|
||||
|
||||
//表单提交事件
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
const values = await validate();
|
||||
setModalProps({ confirmLoading: true });
|
||||
//关闭弹窗
|
||||
closeModal();
|
||||
//刷新列表
|
||||
emit('success', values);
|
||||
} finally {
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/*update-begin---author:wangshuai ---date:20230703 for:【QQYUN-5685】3、租户角色下,查询居左显示*/
|
||||
:deep(.ant-form-item-control-input-content){
|
||||
text-align: left;
|
||||
}
|
||||
/*update-end---author:wangshuai ---date:20230703 for:【QQYUN-5685】3、租户角色下,查询居左显示*/
|
||||
</style>
|
||||
@@ -0,0 +1,55 @@
|
||||
<template>
|
||||
<div>
|
||||
<Suspense v-if="comp">
|
||||
<template #default>
|
||||
<component :is="comp" :formData="formData" v-if="comp" form-bpm></component>
|
||||
</template>
|
||||
<template #fallback>
|
||||
<div style="width: 100%; text-align: center; padding-top: 60px">
|
||||
<a-spin spinning tip="表单加载中..." />
|
||||
</div>
|
||||
</template>
|
||||
</Suspense>
|
||||
<div v-else>表单地址不存在</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent, computed, markRaw } from 'vue';
|
||||
import { importViewsFile } from '/@/utils';
|
||||
//组件接受传参
|
||||
const props = defineProps({
|
||||
path: { type: String },
|
||||
formData: { type: Object },
|
||||
});
|
||||
// 表单地址兼容vue2
|
||||
const FORM_PATH_MAP = {
|
||||
'modules/bpm/task/form/OnlineFormDetail': 'super/bpm/process/components/OnlineFormDetail',
|
||||
'modules/bpm/task/form/OnlineFormOpt': 'super/bpm/process/components/OnlineFormOpt',
|
||||
//借款申请表单
|
||||
'modules/extbpm/joa/modules/JoaLoanApplyForm': 'super/bpm/example/joa/loan/components/LoanApplyForm',
|
||||
//借款表单
|
||||
'modules/extbpm/joa/modules/JoaLoanForm': 'super/bpm/example/joa/loan/components/LoanForm',
|
||||
//出差表单
|
||||
'modules/extbpm/joa/modules/JoaBusinesStripForm': 'super/bpm/example/joa/businessTrip/components/BusinessTripForm',
|
||||
//请假表单
|
||||
'modules/extbpm/joa/modules/JoaEmployeeLeaveForm': 'super/bpm/example/joa/leave/components/LeaveForm',
|
||||
//公文表单
|
||||
'modules/extbpm/joa/modules/JoaDocSendingForm': 'super/bpm/example/joa/docSend/components/DocSendForm',
|
||||
//批量请假单
|
||||
'modules/extbpm/biz/modules/ExtBizLeaveForm': 'super/bpm/example/batch/components/BizLeaveForm',
|
||||
};
|
||||
//组件路径
|
||||
/**
|
||||
* 获取组件
|
||||
* @type {ComputedRef<function(): *>}
|
||||
*/
|
||||
const comp = computed(() => {
|
||||
let temp = props.path;
|
||||
if (FORM_PATH_MAP[temp]) {
|
||||
temp = FORM_PATH_MAP[temp];
|
||||
}
|
||||
console.log('bpm组件名称:', temp);
|
||||
console.log('bpm组件数据:', props.formData);
|
||||
return defineAsyncComponent(() => importViewsFile(temp));
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,126 @@
|
||||
<template>
|
||||
<!-- 历史流程任务处理弹出框 -->
|
||||
<a-modal
|
||||
width="100%"
|
||||
style="top: 0"
|
||||
wrapClassName="full-modal"
|
||||
destroyOnClose
|
||||
:title="data.title"
|
||||
v-model:open="data.visible"
|
||||
:bodyStyle="data.bodyStyle"
|
||||
:footer="null"
|
||||
@cancel="handleModalCancel"
|
||||
>
|
||||
<a-tabs defaultActiveKey="1" tabPosition="left">
|
||||
<a-tab-pane key="1">
|
||||
<template #tab>
|
||||
<Icon icon="ant-design:file-text-outlined" />
|
||||
<span>附加单据</span>
|
||||
</template>
|
||||
<div class="component_div">
|
||||
<template v-if="isComp">
|
||||
<DynamicLink v-if="path" :path="path" :formData="formData"></DynamicLink>
|
||||
<div v-else>表单地址不存在</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<iframe :src="data.iframeUrl" frameborder="0" width="100%" :height="data.height" scrolling="auto"></iframe>
|
||||
</template>
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
|
||||
<a-tab-pane key="2">
|
||||
<template #tab>
|
||||
<Icon icon="ant-design:user-outlined" />
|
||||
<span>任务处理</span>
|
||||
</template>
|
||||
<HisTaskModule :formData="formData"></HisTaskModule>
|
||||
</a-tab-pane>
|
||||
|
||||
<a-tab-pane key="3">
|
||||
<template #tab>
|
||||
<Icon icon="ant-design:sliders-outlined" />
|
||||
<span>流程图</span>
|
||||
</template>
|
||||
<ProcessDiagram :formData="formData"></ProcessDiagram>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, reactive } from 'vue';
|
||||
import { getBpmFormUrl, isUrl} from '/@/utils/is';
|
||||
import { getToken } from '/@/utils/auth';
|
||||
import { useGlobSetting } from '/@/hooks/setting';
|
||||
import DynamicLink from './DynamicLink.vue';
|
||||
import ProcessDiagram from './ProcessDiagram.vue';
|
||||
import HisTaskModule from './HisTaskModule.vue';
|
||||
|
||||
const globSetting = useGlobSetting();
|
||||
//组件接受传参
|
||||
const props = defineProps({
|
||||
path: { type: String },
|
||||
formData: { type: Object },
|
||||
});
|
||||
//数据
|
||||
const data = reactive({
|
||||
loading: false,
|
||||
title: '流程',
|
||||
visible: false,
|
||||
bodyStyle: {
|
||||
padding: '0',
|
||||
height: window.innerHeight - 80 + 'px',
|
||||
'overflow-y': 'auto',
|
||||
},
|
||||
height: window.innerHeight - 120 + 'px',
|
||||
iframeUrl: '',
|
||||
});
|
||||
|
||||
let TOKEN = getToken();
|
||||
let DOMAIN_URL = globSetting.domainUrl;
|
||||
let TASKID = props?.formData?.taskDefKey;
|
||||
|
||||
//是否组件
|
||||
const isComp = computed(() => {
|
||||
//获取流程审批url
|
||||
//let URL = (props.path || '').replace(/{{([^}}]+)?}}/g, (s1, s2) => eval(s2)); // URL支持{{ window.xxx }}占位符变量
|
||||
let URL = getBpmFormUrl(props.path, TOKEN, DOMAIN_URL, TASKID);
|
||||
|
||||
if (isUrl(URL)) {
|
||||
data.iframeUrl = URL;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
/**
|
||||
* 关闭弹窗
|
||||
*/
|
||||
function handleModalCancel() {
|
||||
data.visible = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开弹窗前处理
|
||||
* @param record
|
||||
*/
|
||||
function deal(record) {
|
||||
data.visible = true;
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
deal,
|
||||
data,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.component_div {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
:deep(.ant-modal) {
|
||||
top: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,202 @@
|
||||
<template>
|
||||
<!--流程任务历史-->
|
||||
<div>
|
||||
<!-- 步骤条 -->
|
||||
<a-spin :spinning="loading">
|
||||
<a-card>
|
||||
<a-steps progressDot :current="stepIndex" style="padding: 10px" size="default">
|
||||
<template v-if="resultObj.bpmLogListCount > 3">
|
||||
<a-step>
|
||||
<template #title>
|
||||
<div class="task-title">...</div>
|
||||
</template>
|
||||
</a-step>
|
||||
</template>
|
||||
<template v-for="(item, index) in resultObj.bpmLogStepList">
|
||||
<a-step>
|
||||
<template #title>
|
||||
<div class="task-title">{{ item.taskName }}</div>
|
||||
</template>
|
||||
<template #description>
|
||||
<div class="descriptionDiv">
|
||||
<span>
|
||||
<a-avatar shape="square" style="background-color: #40a9ff">
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
</span>
|
||||
<span style="margin-left: 5px">
|
||||
<div class="task-date" style="text-align: left">
|
||||
<a-tooltip placement="top">
|
||||
<template #title
|
||||
><span>{{ item.opTime }}</span></template
|
||||
>
|
||||
<span> {{ item.opTime ? item.opTime.substr(0, 10) : item.opTime }}</span>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
<div class="task-user" style="text-align: left"
|
||||
><span> {{ item.opUserName }}</span></div
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</a-step>
|
||||
</template>
|
||||
<template v-if="resultObj.currTaskName && resultObj.currTaskName != ''">
|
||||
<a-step>
|
||||
<template #title>
|
||||
<div class="task-title">{{ resultObj.currTaskName }}</div>
|
||||
</template>
|
||||
<template #description>
|
||||
<div class="descriptionDiv">
|
||||
<a-avatar style="background-color: #faad14eb">
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
<span style="margin-left: 5px">
|
||||
<div class="task-date" style="text-align: left">
|
||||
<a-tooltip placement="top">
|
||||
<template #title
|
||||
><span>{{ resultObj.currTaskNameStartTime }}</span></template
|
||||
>
|
||||
<span style="color: #ff6d75">
|
||||
{{
|
||||
resultObj.currTaskNameStartTime ? resultObj.currTaskNameStartTime.substr(0, 10) : resultObj.currTaskNameStartTime
|
||||
}}</span
|
||||
>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
<div class="task-user" style="text-align: left"
|
||||
><span> {{ resultObj.currTaskNameAssignee }}</span></div
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</a-step>
|
||||
<a-step>
|
||||
<template #title>
|
||||
<div class="task-title">...</div>
|
||||
</template>
|
||||
</a-step>
|
||||
</template>
|
||||
</a-steps>
|
||||
</a-card>
|
||||
<!-- 意见 -->
|
||||
<a-card title="意见信息" :bodyStyle="{ padding: '0 20px' }" size="default" style="margin-top: 20px">
|
||||
<a-list itemLayout="vertical">
|
||||
<template v-for="(item, index) in resultObj.bpmLogList">
|
||||
<a-list-item>
|
||||
<a-list-item-meta :description="item.remarks||'无意见信息'">
|
||||
<template #title>
|
||||
<a
|
||||
><p>{{ item.opUserName }}</p
|
||||
><span style="color: #ff6d75">[{{ item.taskName }}]</span> {{ item.opTime }}</a
|
||||
>
|
||||
</template>
|
||||
<template #avatar>
|
||||
<a-avatar :size="36" style="background-color: #51cbff">
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
</template>
|
||||
</a-list-item-meta>
|
||||
<template v-for="(file, index) in item.bpmFiles" :key="index">
|
||||
<div class="ant-upload-list ant-upload-list-text">
|
||||
<div class="ant-upload-list-item ant-upload-list-item-done">
|
||||
<div class="ant-upload-list-item-info">
|
||||
<span>
|
||||
<PaperClipOutlined />
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
:title="file.fileName"
|
||||
:href="getFileAccessHttpUrl(file.filePath)"
|
||||
class="ant-upload-list-item-name"
|
||||
>{{ file.fileName }}</a
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-list-item>
|
||||
</template>
|
||||
</a-list>
|
||||
</a-card>
|
||||
</a-spin>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, unref, onMounted, computed } from 'vue';
|
||||
import JEllipsis from '/@/components/Form/src/jeecg/components/JEllipsis.vue';
|
||||
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
|
||||
import { getHisProcessTaskTransInfo } from './bpm.api';
|
||||
import { UserOutlined, PaperClipOutlined } from '@ant-design/icons-vue';
|
||||
|
||||
//组件接受传参
|
||||
const props = defineProps({
|
||||
formData: { type: Object },
|
||||
});
|
||||
//组件接受传参
|
||||
const resultObj = ref({});
|
||||
const loading = ref(false);
|
||||
//步骤点
|
||||
const stepIndex = computed(() => {
|
||||
if (unref(resultObj).bpmLogListCount > 3) {
|
||||
return unref(resultObj).bpmLogStepListCount + 1;
|
||||
}
|
||||
return unref(resultObj).bpmLogStepListCount;
|
||||
});
|
||||
|
||||
/**
|
||||
* 加载数据
|
||||
* @param formData
|
||||
*/
|
||||
async function loadData(formData) {
|
||||
var params = { procInstId: formData.procInsId }; //查询条件
|
||||
loading.value = true;
|
||||
const res = await getHisProcessTaskTransInfo(params);
|
||||
loading.value = false;
|
||||
if (res.success) {
|
||||
resultObj.value = res.result;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadData(props.formData);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.task-info {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.task-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.task-date {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ant-steps-item-description {
|
||||
max-width: 200px !important;
|
||||
}
|
||||
|
||||
/** Button按钮间距 */
|
||||
.ant-btn {
|
||||
margin-left: 3px;
|
||||
}
|
||||
/** 标题和描述对齐 */
|
||||
:deep(.ant-steps-item-content) {
|
||||
text-align: left;
|
||||
margin-left: 50px;
|
||||
}
|
||||
/** 描述的样式 */
|
||||
.descriptionDiv {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
align-items: center;
|
||||
margin-top: 5px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,133 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="graphic">
|
||||
<!--流程图 -->
|
||||
<BpmGraphic :instanceId="formData.procInsId" @task="getTaskList"></BpmGraphic>
|
||||
</div>
|
||||
<a-card title="流程历史跟踪">
|
||||
<a-table rowKey="taskId" :loading="loading" :dataSource="dataSource" :columns="columns" size="small">
|
||||
<!-- 字符串超长截取省略号显示-->
|
||||
<template #remarks="{ record }">
|
||||
<JEllipsis :value="getNodeInfo(record)" :length="25" />
|
||||
</template>
|
||||
</a-table>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, unref, onMounted } from 'vue';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import JEllipsis from '/@/components/Form/src/jeecg/components/JEllipsis.vue';
|
||||
import BpmGraphic from '/@/views/super/bpm/process/components/BpmGraphic.vue';
|
||||
import { getProcessHistoryList } from './bpm.api';
|
||||
//组件接受传参
|
||||
const props = defineProps({
|
||||
formData: { type: Object },
|
||||
});
|
||||
//提示
|
||||
const { createMessage } = useMessage();
|
||||
const loading = ref(false);
|
||||
//列表数据
|
||||
const dataSource = ref([]);
|
||||
const taskList = ref([]);
|
||||
|
||||
// 查询数据
|
||||
async function loadData() {
|
||||
loading.value = true;
|
||||
let params = { processInstanceId: props.formData.procInsId };
|
||||
const res = await getProcessHistoryList(params);
|
||||
loading.value = false;
|
||||
if (res.success) {
|
||||
dataSource.value = res.result.records;
|
||||
} else {
|
||||
createMessage.warning('加载失败');
|
||||
}
|
||||
}
|
||||
|
||||
function getTaskList(result) {
|
||||
taskList.value = result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取节点备注信息
|
||||
* @param record
|
||||
*/
|
||||
function getNodeInfo(record) {
|
||||
let arr = taskList.value;
|
||||
if (arr && arr.length > 0) {
|
||||
for (let item of arr) {
|
||||
if (item.id == record.id) {
|
||||
return item.remarks;
|
||||
}
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
taskList.value = [];
|
||||
loadData();
|
||||
});
|
||||
//定义列
|
||||
const columns = [
|
||||
{
|
||||
title: '#',
|
||||
dataIndex: '#',
|
||||
width: 40,
|
||||
customRender: ({ text, index }) => {
|
||||
return parseInt(index) + 1;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'name',
|
||||
customRender: ({ text }) => {
|
||||
if (text == 'start1') {
|
||||
return '开始';
|
||||
} else if (text == 'end') {
|
||||
return '结束';
|
||||
} else {
|
||||
return text;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '流程实例ID',
|
||||
dataIndex: 'processInstanceId',
|
||||
},
|
||||
{
|
||||
title: '开始时间',
|
||||
dataIndex: 'startTime',
|
||||
},
|
||||
{
|
||||
title: '结束时间',
|
||||
dataIndex: 'endTime',
|
||||
},
|
||||
{
|
||||
title: '负责人',
|
||||
dataIndex: 'assigneeName',
|
||||
},
|
||||
{
|
||||
title: '处理结果',
|
||||
dataIndex: 'deleteReason',
|
||||
},
|
||||
{
|
||||
title: '处理意见',
|
||||
fixed: 'right',
|
||||
width: 350,
|
||||
dataIndex: 'remarks',
|
||||
slots: { customRender: 'remarks' },
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.graphic {
|
||||
margin-bottom: 20px;
|
||||
height: 400px;
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
overflow-x: auto;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,53 @@
|
||||
<!--选择跳转节点弹窗-->
|
||||
<template>
|
||||
<BasicModal
|
||||
v-bind="$attrs"
|
||||
@register="registerModal"
|
||||
destroyOnClose
|
||||
:bodyStyle="{ minHeight: '100px', maxHeight: '100px' }"
|
||||
title="选择跳转节点"
|
||||
@ok="handleSubmit"
|
||||
:width="700"
|
||||
>
|
||||
<BasicForm @register="registerForm" />
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, unref } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||
import { skipNode } from './bpm.api';
|
||||
import { taskNodeFormSchema } from './bpm.data';
|
||||
// 声明Emits
|
||||
const emit = defineEmits(['success', 'register']);
|
||||
//表单配置
|
||||
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
|
||||
labelWidth: 150,
|
||||
schemas: taskNodeFormSchema,
|
||||
showActionButtonGroup: false,
|
||||
});
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
await resetFields();
|
||||
setModalProps({ confirmLoading: false });
|
||||
await setFieldsValue({
|
||||
...data,
|
||||
});
|
||||
});
|
||||
|
||||
//表单提交事件
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
const values = await validate();
|
||||
setModalProps({ confirmLoading: true });
|
||||
//提交跳转
|
||||
await skipNode(values);
|
||||
//关闭弹窗
|
||||
closeModal();
|
||||
//刷新列表
|
||||
emit('success');
|
||||
} finally {
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,133 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
|
||||
enum Api {
|
||||
hisProcessNodeInfo = '/act/process/extActProcessNode/getHisProcessNodeInfo',
|
||||
processHistoryList = '/act/task/processHistoryList',
|
||||
hisProcessTaskTransInfo = '/act/task/getHisProcessTaskTransInfo',
|
||||
skipNode = '/act/processInstance/skipNode',
|
||||
taskEntrust = '/act/task/taskEntrust',
|
||||
getAllTask = '/act/processInstance/getAllTask',
|
||||
reassign = '/act/processInstance/reassign',
|
||||
bizHisProcessNodeInfo = '/act/process/extActProcessNode/getBizHisProcessNodeInfo',
|
||||
getNotifyList = '/act/process/extActTaskNotification/mylist',
|
||||
notifyMeList = '/act/process/extActTaskNotification/list',
|
||||
taskNotification = '/act/process/extActTaskNotification/taskNotification',
|
||||
getBizProcessNodeInfo = '/act/process/extActProcessNode/getBizProcessNodeInfo',
|
||||
getProcessTaskTransInfo = '/act/task/getProcessTaskTransInfo',
|
||||
processComplete = '/act/task/processComplete',
|
||||
suspend = '/act/processInstance/suspend',
|
||||
restart = '/act/processInstance/restart',
|
||||
claim = '/act/task/claim',
|
||||
getProcessInfo = '/act/process/extActFlowData/getProcessInfo',
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程节点历史信息
|
||||
* @param params
|
||||
*/
|
||||
export const hisProcessNodeInfo = (params) => {
|
||||
return defHttp.get({ url: Api.hisProcessNodeInfo, params }, { isTransformResponse: false });
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取流程历史信息
|
||||
* @param params
|
||||
*/
|
||||
export const getProcessHistoryList = (params) => defHttp.get({ url: Api.processHistoryList, params }, { isTransformResponse: false });
|
||||
|
||||
/**
|
||||
* 获取流程历史流转信息
|
||||
* @param params
|
||||
*/
|
||||
export const getHisProcessTaskTransInfo = (params) => defHttp.get({ url: Api.hisProcessTaskTransInfo, params }, { isTransformResponse: false });
|
||||
|
||||
/**
|
||||
* 委派
|
||||
* @param params
|
||||
*/
|
||||
export const taskEntrust = (params, handleSuccess?) => {
|
||||
return defHttp.put({ url: Api.taskEntrust, params }, { isTransformResponse: false }).then((res) => {
|
||||
handleSuccess && handleSuccess(res);
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 获取所有任务节点
|
||||
* @param params
|
||||
*/
|
||||
export const getAllTask = (params) => defHttp.get({ url: Api.getAllTask, params });
|
||||
/**
|
||||
* 跳转节点
|
||||
* @param params
|
||||
*/
|
||||
export const skipNode = (params) => defHttp.get({ url: Api.skipNode, params });
|
||||
/**
|
||||
* 获取业务流程节点信息
|
||||
* @param params
|
||||
*/
|
||||
export const getBizHisProcessNodeInfo = (params) => defHttp.get({ url: Api.bizHisProcessNodeInfo, params }, { isTransformResponse: false });
|
||||
/**
|
||||
* 获取我催办的流程列表
|
||||
* @param params
|
||||
*/
|
||||
export const getNotifyList = (params) => defHttp.get({ url: Api.getNotifyList, params });
|
||||
/**
|
||||
* 获取催办我的流程列表
|
||||
* @param params
|
||||
*/
|
||||
export const getNotifyMeList = (params) => defHttp.get({ url: Api.notifyMeList, params });
|
||||
/**
|
||||
* 催办
|
||||
* @param params
|
||||
*/
|
||||
export const saveOrUpdateNotify = (params) => {
|
||||
return defHttp.post({ url: Api.taskNotification, params });
|
||||
};
|
||||
/**
|
||||
* 获取业务流程节点信息
|
||||
* @param params
|
||||
*/
|
||||
export const getBizProcessNodeInfo = (params) => {
|
||||
return defHttp.get({ url: Api.getBizProcessNodeInfo, params }, { isTransformResponse: false });
|
||||
};
|
||||
/**
|
||||
* 获取业务流转信息
|
||||
* @param params
|
||||
*/
|
||||
export const getProcessTaskTransInfo = (params) => {
|
||||
return defHttp.get({ url: Api.getProcessTaskTransInfo, params }, { isTransformResponse: false });
|
||||
};
|
||||
/**
|
||||
* 流程办理
|
||||
* @param params
|
||||
*/
|
||||
export const processComplete = (params) => {
|
||||
return defHttp.post({ url: Api.processComplete, params }, { isTransformResponse: false });
|
||||
};
|
||||
/**
|
||||
* 挂起
|
||||
* @param params
|
||||
*/
|
||||
export const suspend = (params) => {
|
||||
return defHttp.get({ url: Api.suspend, params }, { isTransformResponse: false });
|
||||
};
|
||||
/**
|
||||
* 解挂
|
||||
* @param params
|
||||
*/
|
||||
export const restart = (params) => {
|
||||
return defHttp.get({ url: Api.restart, params }, { isTransformResponse: false });
|
||||
};
|
||||
/**
|
||||
* 签收
|
||||
* @param params
|
||||
*/
|
||||
export const claim = (params) => {
|
||||
return defHttp.put({ url: Api.claim, params }, { isTransformResponse: false });
|
||||
};
|
||||
/**
|
||||
* 获取流程信息
|
||||
* @param params
|
||||
*/
|
||||
export const getProcessInfo = (params) => {
|
||||
return defHttp.get({ url: Api.getProcessInfo, params }, { isTransformResponse: false });
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
import { FormSchema } from '/@/components/Table';
|
||||
import { getAllTask } from './bpm.api';
|
||||
|
||||
/**
|
||||
* 委派modal的form
|
||||
*/
|
||||
export const delegateFormSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'username',
|
||||
label: '用户名',
|
||||
component: 'JSelectUserByDept',
|
||||
required: true,
|
||||
componentProps: {
|
||||
labelKey: 'realname',
|
||||
rowKey: 'username',
|
||||
showButton: false,
|
||||
isRadioSelection: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
/**
|
||||
* 跳转节点form
|
||||
*/
|
||||
export const taskNodeFormSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'taskId',
|
||||
label: '',
|
||||
component: 'Input',
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
field: 'skipTaskNode',
|
||||
label: '跳转节点',
|
||||
component: 'ApiSelect',
|
||||
required: true,
|
||||
componentProps: ({ formModel }) => {
|
||||
return {
|
||||
api: getAllTask,
|
||||
params: { taskId: formModel.taskId },
|
||||
labelField: 'name',
|
||||
valueField: 'taskKey',
|
||||
immediate: false,
|
||||
onChange: (e) => {
|
||||
console.log('selected:', e);
|
||||
},
|
||||
onOptionsChange: (options) => {
|
||||
console.log('get options', options.length, options);
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,51 @@
|
||||
import { ref, unref } from 'vue';
|
||||
import { hisProcessNodeInfo } from '../bpm.api';
|
||||
import { getQueryVariable } from '/@/utils';
|
||||
import { isUrl } from '/@/utils/is';
|
||||
|
||||
/**
|
||||
*
|
||||
* @param path 路径
|
||||
* @param taskDealRef 弹窗示例
|
||||
*/
|
||||
export function useBpmNodeInfo(path, taskDealRef) {
|
||||
const formData = ref({});
|
||||
/**
|
||||
* 获取流程历史节点信息
|
||||
* @param record
|
||||
*/
|
||||
function getHisProcessNodeInfo(record) {
|
||||
hisProcessNodeInfo({ procInstId: record.processInstanceId }).then((res) => {
|
||||
console.log('获取流程节点信息', res);
|
||||
if (res.success) {
|
||||
let data = {
|
||||
dataId: res.result.dataId,
|
||||
taskId: record.id,
|
||||
taskDefKey: record.taskId,
|
||||
procInsId: record.processInstanceId,
|
||||
tableName: res.result.tableName,
|
||||
vars: res.result.records,
|
||||
};
|
||||
formData.value = data;
|
||||
//update--begin--autor:scott-----date:20191005------for:流程节点配置组件URL的时候也支持传递参数了,解决TASK #3238流程节点无法与online的复制视图对接------
|
||||
console.log('获取流程节点表单URL ', res.result.formUrl);
|
||||
let tempFormUrl = res.result.formUrl;
|
||||
//节点配置表单URL,VUE组件类型对应的拓展参数
|
||||
if (tempFormUrl && tempFormUrl.indexOf('?') != -1 && !isUrl(tempFormUrl) && tempFormUrl.indexOf('{{DOMAIN_URL}}') == -1) {
|
||||
tempFormUrl = res.result.formUrl.split('?')[0];
|
||||
console.log('获取流程节点表单URL(去掉参数)', tempFormUrl);
|
||||
formData.value['extendUrlParams'] = getQueryVariable(res.result.formUrl);
|
||||
}
|
||||
path.value = tempFormUrl;
|
||||
//update--end--autor:scott-----date:20191005------for:流程节点配置组件URL的时候也支持传递参数了,解决TASK #3238流程节点无法与online的复制视图对接------
|
||||
console.log('获取流程节点信息formData', unref(formData));
|
||||
console.log('获取流程节点信息path', unref(path));
|
||||
taskDealRef.value.deal(record);
|
||||
taskDealRef.value.data.title = '流程历史';
|
||||
console.log('taskDealRef', taskDealRef.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return { getHisProcessNodeInfo, formData };
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit" :width="700" :min-height="300">
|
||||
<BasicForm @register="registerForm" />
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, unref } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||
import { formSchema } from '../expression.data';
|
||||
import { saveOrUpdate } from '../expression.api';
|
||||
// 声明Emits
|
||||
const emit = defineEmits(['success', 'register']);
|
||||
const isUpdate = ref(true);
|
||||
//表单配置
|
||||
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
|
||||
// labelWidth: 150,
|
||||
schemas: formSchema,
|
||||
showActionButtonGroup: false,
|
||||
});
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
//重置表单
|
||||
await resetFields();
|
||||
setModalProps({ confirmLoading: false });
|
||||
isUpdate.value = !!data?.isUpdate;
|
||||
if (unref(isUpdate)) {
|
||||
//表单赋值
|
||||
await setFieldsValue({
|
||||
...data.record,
|
||||
});
|
||||
}
|
||||
});
|
||||
//设置标题
|
||||
const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
|
||||
|
||||
//表单提交事件
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
const values = await validate();
|
||||
setModalProps({ confirmLoading: true });
|
||||
//提交表单
|
||||
await saveOrUpdate(values, isUpdate.value);
|
||||
//关闭弹窗
|
||||
closeModal();
|
||||
//刷新列表
|
||||
emit('success');
|
||||
} finally {
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,50 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { Modal } from 'ant-design-vue';
|
||||
|
||||
enum Api {
|
||||
list = '/act/process/extActExpression/list',
|
||||
save = '/act/process/extActExpression/add',
|
||||
edit = '/act/process/extActExpression/edit',
|
||||
delete = '/act/process/extActExpression/delete',
|
||||
deleteBatch = '/act/process/extActExpression/deleteBatch',
|
||||
}
|
||||
/**
|
||||
* 列表
|
||||
* @param params
|
||||
*/
|
||||
export const list = (params) => defHttp.get({ url: Api.list, params });
|
||||
|
||||
/**
|
||||
* 保存或者更新
|
||||
* @param params
|
||||
*/
|
||||
export const saveOrUpdate = (params, isUpdate) => {
|
||||
let url = isUpdate ? Api.edit : Api.save;
|
||||
return isUpdate ? defHttp.put({ url: url, params }) : defHttp.post({ url: url, params });
|
||||
};
|
||||
/**
|
||||
* 删除监听
|
||||
* @param params
|
||||
*/
|
||||
export const deleteOne = (params, handleSuccess) => {
|
||||
return defHttp.delete({ url: Api.delete, data: params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 批量删除
|
||||
* @param params
|
||||
*/
|
||||
export const batchDelete = (params, handleSuccess) => {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: '是否删除选中数据',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,73 @@
|
||||
import { FormSchema } from '/@/components/Table';
|
||||
import {render} from "@/utils/common/renderUtils";
|
||||
|
||||
export const columns = [
|
||||
{
|
||||
title: '表达式名称',
|
||||
dataIndex: 'name',
|
||||
width: 180,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '表达式',
|
||||
width: 180,
|
||||
dataIndex: 'expression',
|
||||
},
|
||||
{
|
||||
title: '业务类型',
|
||||
width: 180,
|
||||
dataIndex: 'bizType',
|
||||
customRender: ({ text }) => {
|
||||
return render.renderDict(text, 'processExpressionBizType');
|
||||
},
|
||||
},
|
||||
];
|
||||
/**
|
||||
* 列表查询form
|
||||
*/
|
||||
export const searchFormSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'name',
|
||||
label: '名称',
|
||||
component: 'Input',
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
// {
|
||||
// field: 'expression',
|
||||
// label: '表达式',
|
||||
// component: 'Input',
|
||||
// colProps: { span: 6 },
|
||||
// },
|
||||
];
|
||||
/**
|
||||
* 表单form
|
||||
*/
|
||||
export const formSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'id',
|
||||
label: '',
|
||||
component: 'Input',
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
label: '表达式名称',
|
||||
field: 'name',
|
||||
required: true,
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '表达式',
|
||||
field: 'expression',
|
||||
required: true,
|
||||
component: 'InputTextArea',
|
||||
},
|
||||
{
|
||||
label: '业务类型',
|
||||
field: 'bizType',
|
||||
required: false,
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: {
|
||||
dictCode: 'processExpressionBizType',
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,117 @@
|
||||
<template>
|
||||
<div>
|
||||
<BasicTable @register="registerTable" :rowSelection="rowSelection">
|
||||
<template #tableTitle>
|
||||
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="handleCreate"> 新增</a-button>
|
||||
<a-dropdown v-if="selectedRowKeys.length > 0">
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item key="1" @click="handleBatchDelete">
|
||||
<Icon icon="ant-design:delete-outlined"></Icon>
|
||||
删除
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
<a-button
|
||||
>批量操作
|
||||
<Icon icon="mdi:chevron-down"></Icon>
|
||||
</a-button>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
<!--操作栏-->
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
<!--监听弹窗-->
|
||||
<ExpressionModal @register="registerModal" @success="reload"></ExpressionModal>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" name="process-expression-list" setup>
|
||||
import { ref } from 'vue';
|
||||
import { BasicTable, TableAction } from '/@/components/Table';
|
||||
import ExpressionModal from './components/ExpressionModal.vue';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import { columns, searchFormSchema } from './expression.data';
|
||||
import { list, deleteOne, batchDelete } from './expression.api';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
//弹窗
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
|
||||
// 列表页面公共参数、方法
|
||||
const { prefixCls, tableContext } = useListPage({
|
||||
designScope: 'process-expression',
|
||||
tableProps: {
|
||||
title: '流程表达式',
|
||||
api: list,
|
||||
columns: columns,
|
||||
formConfig: {
|
||||
schemas: searchFormSchema,
|
||||
},
|
||||
actionColumn: {
|
||||
width: 120,
|
||||
fixed: 'right',
|
||||
},
|
||||
},
|
||||
});
|
||||
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
function handleCreate() {
|
||||
openModal(true, {
|
||||
isUpdate: false,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 编辑
|
||||
*/
|
||||
function handleEdit(record: Recordable) {
|
||||
openModal(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 删除
|
||||
* @param id
|
||||
*/
|
||||
async function handleDelete(id) {
|
||||
await deleteOne({ id }, reload);
|
||||
}
|
||||
/**
|
||||
* 批量删除事件
|
||||
*/
|
||||
async function handleBatchDelete() {
|
||||
await batchDelete({ ids: selectedRowKeys.value }, () => {
|
||||
selectedRowKeys.value = [];
|
||||
reload();
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 下拉操作栏
|
||||
*/
|
||||
function getDropDownAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
confirm: handleDelete.bind(null, record.id),
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,30 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
|
||||
enum Api {
|
||||
list = '/act/task/historyProcessList',
|
||||
invalidProcess = '/act/task/invalidProcess',
|
||||
callBackProcess = '/act/task/callBackProcess',
|
||||
}
|
||||
/**
|
||||
* 列表
|
||||
* @param params
|
||||
*/
|
||||
export const list = (params) => defHttp.get({ url: Api.list, params });
|
||||
/**
|
||||
* 作废流程
|
||||
* @param params
|
||||
*/
|
||||
export const invalidProcess = (params, handleSuccess) => {
|
||||
return defHttp.put({ url: Api.invalidProcess, params }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 取回流程
|
||||
* @param params
|
||||
*/
|
||||
export const callBackProcess = (params, handleSuccess) => {
|
||||
return defHttp.put({ url: Api.callBackProcess, params }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,77 @@
|
||||
import { FormSchema } from '/@/components/Table';
|
||||
|
||||
export const columns = [
|
||||
{
|
||||
title: '业务标题',
|
||||
dataIndex: 'bpmBizTitle',
|
||||
width: 180,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '流程名称',
|
||||
dataIndex: 'prcocessDefinitionName',
|
||||
},
|
||||
{
|
||||
title: '流程实例',
|
||||
dataIndex: 'processInstanceId',
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: '发起人',
|
||||
dataIndex: 'startUserName',
|
||||
},
|
||||
{
|
||||
title: '开始日期',
|
||||
dataIndex: 'startTime',
|
||||
},
|
||||
{
|
||||
title: '流程编号',
|
||||
dataIndex: 'processDefinitionId',
|
||||
},
|
||||
{
|
||||
title: '结束时间',
|
||||
dataIndex: 'endTime',
|
||||
},
|
||||
{
|
||||
title: '耗时',
|
||||
dataIndex: 'spendTimes',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'bpmStatus',
|
||||
customRender: ({ text }) => {
|
||||
switch (text) {
|
||||
case '1':
|
||||
return '待提交';
|
||||
case '2':
|
||||
return '处理中';
|
||||
case '3':
|
||||
return '已完成';
|
||||
case 'rejectProcess':
|
||||
return '已驳回';
|
||||
case 'callBackProcess':
|
||||
return '已取回';
|
||||
case 'invalidProcess':
|
||||
return '已作废';
|
||||
}
|
||||
return text;
|
||||
},
|
||||
},
|
||||
];
|
||||
/**
|
||||
* 列表查询form
|
||||
*/
|
||||
export const searchFormSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'processDefinitionId',
|
||||
label: '流程编号',
|
||||
component: 'Input',
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
{
|
||||
field: 'processName',
|
||||
label: '流程名称',
|
||||
component: 'Input',
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<div>
|
||||
<BasicTable @register="registerTable" :rowSelection="rowSelection">
|
||||
<!--操作栏-->
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
<!--历史-->
|
||||
<HisTaskDealModal ref="taskDealRef" :path="path" :formData="formData"></HisTaskDealModal>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" name="process-hisprocess-list" setup>
|
||||
import { ref, unref } from 'vue';
|
||||
import { BasicTable, TableAction } from '/@/components/Table';
|
||||
import HisTaskDealModal from '../components/HisTaskDealModal.vue';
|
||||
import { useBpmNodeInfo } from '../components/hooks/useBpmNodeInfo';
|
||||
import { columns, searchFormSchema } from './hisprocess.data';
|
||||
import { list, invalidProcess, callBackProcess } from './hisprocess.api';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
|
||||
// 列表页面公共参数、方法
|
||||
const { prefixCls, tableContext } = useListPage({
|
||||
designScope: 'process-hisprocess',
|
||||
tableProps: {
|
||||
api: list,
|
||||
columns: columns,
|
||||
formConfig: {
|
||||
schemas: searchFormSchema,
|
||||
},
|
||||
actionColumn: {
|
||||
width: 120,
|
||||
fixed: 'right',
|
||||
},
|
||||
},
|
||||
});
|
||||
const path = ref('');
|
||||
const taskDealRef = ref(null);
|
||||
const { getHisProcessNodeInfo, formData } = useBpmNodeInfo(path, taskDealRef);
|
||||
|
||||
const [registerTable, rowSelection, { reload }] = tableContext;
|
||||
|
||||
/**
|
||||
* 显示历史
|
||||
* @param record
|
||||
*/
|
||||
function showHistory(record) {
|
||||
getHisProcessNodeInfo(record);
|
||||
}
|
||||
/**
|
||||
* 作废流程
|
||||
* @param record
|
||||
*/
|
||||
async function handleInvalidProcess(record) {
|
||||
await invalidProcess(
|
||||
{
|
||||
processInstanceId: record.processInstanceId,
|
||||
},
|
||||
reload
|
||||
);
|
||||
}
|
||||
/**
|
||||
* 取回流程
|
||||
* @param record
|
||||
*/
|
||||
async function handleCallBackProcess(record) {
|
||||
await callBackProcess(
|
||||
{
|
||||
processInstanceId: record.processInstanceId,
|
||||
},
|
||||
reload
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '历史',
|
||||
onClick: showHistory.bind(null, record),
|
||||
ifShow: () => {
|
||||
return record.endTime && record.endTime != '';
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
/**
|
||||
* 下拉操作栏
|
||||
*/
|
||||
function getDropDownAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '作废流程',
|
||||
popConfirm: {
|
||||
title: '确定要作废流程吗?',
|
||||
confirm: handleInvalidProcess.bind(null, record),
|
||||
},
|
||||
ifShow: () => {
|
||||
return !record.endTime;
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '取回流程',
|
||||
popConfirm: {
|
||||
title: '确定要取回流程吗?',
|
||||
confirm: handleCallBackProcess.bind(null, record),
|
||||
},
|
||||
ifShow: () => {
|
||||
return !record.endTime;
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '历史',
|
||||
onClick: showHistory.bind(null, record),
|
||||
ifShow: () => {
|
||||
return !record.endTime;
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,10 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
|
||||
enum Api {
|
||||
list = '/act/task/taskAllHistoryList',
|
||||
}
|
||||
/**
|
||||
* 列表
|
||||
* @param params
|
||||
*/
|
||||
export const list = (params) => defHttp.get({ url: Api.list, params });
|
||||
@@ -0,0 +1,65 @@
|
||||
import { FormSchema } from '/@/components/Table';
|
||||
|
||||
export const columns = [
|
||||
{
|
||||
title: '业务标题',
|
||||
dataIndex: 'bpmBizTitle',
|
||||
width: 180,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '流程名称',
|
||||
dataIndex: 'processDefinitionName',
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: '流程实例',
|
||||
dataIndex: 'processInstanceId',
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: '任务名称',
|
||||
dataIndex: 'taskName',
|
||||
},
|
||||
{
|
||||
title: '发起人',
|
||||
dataIndex: 'processApplyUserName',
|
||||
},
|
||||
{
|
||||
title: '办理人',
|
||||
dataIndex: 'taskAssigneeName',
|
||||
},
|
||||
{
|
||||
title: '开始时间',
|
||||
dataIndex: 'taskBeginTime',
|
||||
},
|
||||
{
|
||||
title: '结束时间',
|
||||
dataIndex: 'taskEndTime',
|
||||
},
|
||||
{
|
||||
title: '耗时',
|
||||
dataIndex: 'durationStr',
|
||||
},
|
||||
{
|
||||
title: '流程编号',
|
||||
dataIndex: 'processDefinitionId',
|
||||
},
|
||||
];
|
||||
/**
|
||||
* 列表查询form
|
||||
*/
|
||||
export const searchFormSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'processDefinitionId',
|
||||
label: '流程编号',
|
||||
component: 'Input',
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
{
|
||||
field: 'processDefinitionName',
|
||||
label: '流程名称',
|
||||
component: 'Input',
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<div>
|
||||
<BasicTable @register="registerTable" :rowSelection="rowSelection">
|
||||
<!--操作栏-->
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
<!--历史-->
|
||||
<HisTaskDealModal ref="taskDealRef" :path="path" :formData="formData"></HisTaskDealModal>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" name="process-histask-list" setup>
|
||||
import { ref, unref } from 'vue';
|
||||
import { BasicTable, TableAction } from '/@/components/Table';
|
||||
import HisTaskDealModal from '../components/HisTaskDealModal.vue';
|
||||
import { columns, searchFormSchema } from './histask.data';
|
||||
import { list } from './histask.api';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
import { useBpmNodeInfo } from '../components/hooks/useBpmNodeInfo';
|
||||
|
||||
// 列表页面公共参数、方法
|
||||
const { prefixCls, tableContext } = useListPage({
|
||||
designScope: 'process-histask',
|
||||
tableProps: {
|
||||
api: list,
|
||||
columns: columns,
|
||||
formConfig: {
|
||||
schemas: searchFormSchema,
|
||||
},
|
||||
actionColumn: {
|
||||
width: 120,
|
||||
fixed: 'right',
|
||||
},
|
||||
},
|
||||
});
|
||||
const [registerTable, rowSelection, { reload }] = tableContext;
|
||||
const path = ref('');
|
||||
const taskDealRef = ref(null);
|
||||
let { getHisProcessNodeInfo, formData } = useBpmNodeInfo(path, taskDealRef);
|
||||
/**
|
||||
* 显示历史
|
||||
* @param record
|
||||
*/
|
||||
function showHistory(record) {
|
||||
getHisProcessNodeInfo(record);
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '历史',
|
||||
onClick: showHistory.bind(null, record),
|
||||
},
|
||||
];
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit" :width="700">
|
||||
<BasicForm @register="registerForm" />
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, unref } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||
import { formSchema } from '../listener.data';
|
||||
import { saveOrUpdate } from '../listener.api';
|
||||
// 声明Emits
|
||||
const emit = defineEmits(['success', 'register']);
|
||||
const isUpdate = ref(true);
|
||||
//表单配置
|
||||
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
|
||||
// labelWidth: 150,
|
||||
schemas: formSchema,
|
||||
showActionButtonGroup: false,
|
||||
});
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
//重置表单
|
||||
await resetFields();
|
||||
setModalProps({ confirmLoading: false });
|
||||
isUpdate.value = !!data?.isUpdate;
|
||||
if (unref(isUpdate)) {
|
||||
//表单赋值
|
||||
await setFieldsValue({
|
||||
...data.record,
|
||||
});
|
||||
}
|
||||
});
|
||||
//设置标题
|
||||
const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
|
||||
|
||||
//表单提交事件
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
const values = await validate();
|
||||
setModalProps({ confirmLoading: true });
|
||||
//提交表单
|
||||
await saveOrUpdate(values, isUpdate.value);
|
||||
//关闭弹窗
|
||||
closeModal();
|
||||
//刷新列表
|
||||
emit('success');
|
||||
} finally {
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,41 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
|
||||
enum Api {
|
||||
list = '/act/process/extActListener/list',
|
||||
save = '/act/process/extActListener/add',
|
||||
edit = '/act/process/extActListener/edit',
|
||||
delete = '/act/process/extActListener/delete',
|
||||
changeStatus = '/act/process/extActListener/changeStatus',
|
||||
}
|
||||
/**
|
||||
* 列表
|
||||
* @param params
|
||||
*/
|
||||
export const list = (params) => defHttp.get({ url: Api.list, params });
|
||||
|
||||
/**
|
||||
* 保存或者更新
|
||||
* @param params
|
||||
*/
|
||||
export const saveOrUpdate = (params, isUpdate) => {
|
||||
let url = isUpdate ? Api.edit : Api.save;
|
||||
return isUpdate ? defHttp.put({ url: url, params }) : defHttp.post({ url: url, params });
|
||||
};
|
||||
/**
|
||||
* 删除监听
|
||||
* @param params
|
||||
*/
|
||||
export const deleteOne = (params, handleSuccess) => {
|
||||
return defHttp.delete({ url: Api.delete, data: params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 修改状态
|
||||
* @param params
|
||||
*/
|
||||
export const changeStatus = (params, handleSuccess) => {
|
||||
return defHttp.put({ url: Api.changeStatus, data: params }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,164 @@
|
||||
import { FormSchema } from '/@/components/Table';
|
||||
import { render } from '/@/utils/common/renderUtils';
|
||||
|
||||
export const columns = [
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'listenerName',
|
||||
width: 180,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '监听类型',
|
||||
dataIndex: 'listenerType',
|
||||
width: 100,
|
||||
customRender: ({ text }) => {
|
||||
return render.renderDictNative(
|
||||
text,
|
||||
[
|
||||
{ label: '执行监听', value: 1 },
|
||||
{ label: '任务监听', value: 2 },
|
||||
],
|
||||
false
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '事件',
|
||||
dataIndex: 'listenerEvent',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '执行类型',
|
||||
dataIndex: 'listenerValueType',
|
||||
width: 150,
|
||||
customRender: ({ text }) => {
|
||||
return render.renderDictNative(
|
||||
text,
|
||||
[
|
||||
{ label: '表达式', value: 'expression' },
|
||||
{ label: 'JAVA类', value: 'javaClass' },
|
||||
{ label: 'Spring表达式', value: 'delegateExpression' },
|
||||
],
|
||||
false
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '执行内容',
|
||||
dataIndex: 'listenerValue',
|
||||
width: 360,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'listenerStatus',
|
||||
width: 100,
|
||||
customRender: ({ text }) => {
|
||||
return render.renderDictNative(
|
||||
text,
|
||||
[
|
||||
{ label: '已禁用', value: '0' },
|
||||
{ label: '已启用', value: '1' },
|
||||
],
|
||||
false
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
/**
|
||||
* 列表查询form
|
||||
*/
|
||||
export const searchFormSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'listenerName',
|
||||
label: '名称',
|
||||
component: 'Input',
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
];
|
||||
/**
|
||||
* 表单form
|
||||
*/
|
||||
export const formSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'id',
|
||||
label: '',
|
||||
component: 'Input',
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
label: '名称',
|
||||
field: 'listenerName',
|
||||
required: true,
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '监听类型',
|
||||
field: 'listenerType',
|
||||
component: 'Select',
|
||||
componentProps: ({ formModel }) => {
|
||||
return {
|
||||
options: [
|
||||
{ label: '执行监听', value: 1 },
|
||||
{ label: '任务监听', value: 2 },
|
||||
],
|
||||
onChange: () => {
|
||||
formModel.listenerEvent = '';
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '事件属性',
|
||||
field: 'listenerEvent',
|
||||
component: 'Select',
|
||||
componentProps: ({ formModel }) => {
|
||||
const isExecute = [
|
||||
{ label: 'start', value: 'start' },
|
||||
{ label: 'end', value: 'end' },
|
||||
{ label: 'take', value: 'take' },
|
||||
];
|
||||
const isTask = [
|
||||
{ label: 'create', value: 'create' },
|
||||
{ label: 'assignment', value: 'assignment' },
|
||||
{ label: 'complete', value: 'complete' },
|
||||
];
|
||||
let option = !formModel['listenerType'] ? [] : formModel['listenerType'] == 1 ? isExecute : isTask;
|
||||
return {
|
||||
options: option,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '值类型',
|
||||
field: 'listenerValueType',
|
||||
component: 'RadioGroup',
|
||||
defaultValue: 'javaClass',
|
||||
componentProps: ({ formActionType }) => {
|
||||
return {
|
||||
options: [
|
||||
{ label: 'JAVA类', value: 'javaClass' },
|
||||
{ label: '表达式', value: 'expression' },
|
||||
{ label: '代理表达式', value: 'delegateExpression' },
|
||||
],
|
||||
onChange: (e) => {
|
||||
const { updateSchema } = formActionType;
|
||||
let value = e.target.value;
|
||||
const label = value === 'javaClass' ? '类路径' : '表达式';
|
||||
updateSchema([
|
||||
{
|
||||
field: 'listenerValue',
|
||||
label: label,
|
||||
},
|
||||
]);
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '类路径',
|
||||
field: 'listenerValue',
|
||||
component: 'Input',
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<div>
|
||||
<BasicTable @register="registerTable" :rowSelection="rowSelection">
|
||||
<template #tableTitle>
|
||||
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="handleCreate"> 新增</a-button>
|
||||
</template>
|
||||
<!--操作栏-->
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
<!--监听弹窗-->
|
||||
<ListenerModal @register="registerModal" @success="reload"></ListenerModal>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" name="process-listener-list" setup>
|
||||
import { ref } from 'vue';
|
||||
import { BasicTable, TableAction } from '/@/components/Table';
|
||||
import ListenerModal from './components/ListenerModal.vue';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import { columns, searchFormSchema } from './listener.data';
|
||||
import { list, deleteOne, changeStatus } from './listener.api';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
//弹窗
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
|
||||
// 列表页面公共参数、方法
|
||||
const { prefixCls, tableContext } = useListPage({
|
||||
designScope: 'process-listener',
|
||||
tableProps: {
|
||||
title: '流程监听',
|
||||
api: list,
|
||||
columns: columns,
|
||||
formConfig: {
|
||||
labelWidth: 50,
|
||||
schemas: searchFormSchema,
|
||||
},
|
||||
actionColumn: {
|
||||
width: 120,
|
||||
fixed: 'right',
|
||||
},
|
||||
},
|
||||
});
|
||||
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
function handleCreate() {
|
||||
openModal(true, {
|
||||
isUpdate: false,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 编辑
|
||||
*/
|
||||
function handleEdit(record: Recordable) {
|
||||
console.log('点击了编辑', record);
|
||||
openModal(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 删除
|
||||
* @param id
|
||||
*/
|
||||
async function handleDelete(id) {
|
||||
console.log('点击了删除', id);
|
||||
await deleteOne({ id }, reload);
|
||||
}
|
||||
/**
|
||||
* 修改状态
|
||||
* @param id
|
||||
*/
|
||||
async function handleOpen(id) {
|
||||
console.log('点击了启用', id);
|
||||
await changeStatus({ id }, reload);
|
||||
}
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
},
|
||||
{
|
||||
label: '启用',
|
||||
popConfirm: {
|
||||
title: '是否启用?',
|
||||
confirm: handleOpen.bind(null, record.id),
|
||||
},
|
||||
ifShow: () => {
|
||||
return record.listenerStatus == 0;
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '禁用',
|
||||
popConfirm: {
|
||||
title: '是否禁用?',
|
||||
confirm: handleOpen.bind(null, record.id),
|
||||
},
|
||||
ifShow: () => {
|
||||
return record.listenerStatus == 1;
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 下拉操作栏
|
||||
*/
|
||||
function getDropDownAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
confirm: handleDelete.bind(null, record.id),
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,61 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
|
||||
enum Api {
|
||||
list = '/act/processInstance/list',
|
||||
suspend = '/act/processInstance/suspend',
|
||||
restart = '/act/processInstance/restart',
|
||||
close = '/act/processInstance/close',
|
||||
taskEntrust = '/act/task/taskEntrust',
|
||||
taskComplaint = '/act/task/taskComplaint',
|
||||
}
|
||||
/**
|
||||
* 列表
|
||||
* @param params
|
||||
*/
|
||||
export const list = (params) => defHttp.get({ url: Api.list, params });
|
||||
|
||||
/**
|
||||
* 激活
|
||||
* @param params
|
||||
*/
|
||||
export const restart = (params, handleSuccess) => {
|
||||
return defHttp.get({ url: Api.restart, params }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 挂起
|
||||
* @param params
|
||||
*/
|
||||
export const suspend = (params, handleSuccess) => {
|
||||
return defHttp.get({ url: Api.suspend, params }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 关闭
|
||||
* @param params
|
||||
*/
|
||||
export const closeProcess = (params, handleSuccess) => {
|
||||
return defHttp.get({ url: Api.close, params }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 委派
|
||||
* @param params
|
||||
*/
|
||||
export const taskEntrust = (params, handleSuccess) => {
|
||||
return defHttp.put({ url: Api.taskEntrust, params }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 转办
|
||||
* @param params
|
||||
*/
|
||||
export const taskComplaint = (params, handleSuccess) => {
|
||||
return defHttp.put({ url: Api.taskComplaint, params }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,77 @@
|
||||
import { FormSchema } from '/@/components/Table';
|
||||
|
||||
export const columns = [
|
||||
{
|
||||
title: '流程名称',
|
||||
dataIndex: 'prcocessDefinitionName',
|
||||
width: 180,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '业务标题',
|
||||
dataIndex: 'bpmBizTitle',
|
||||
},
|
||||
{
|
||||
title: '当前任务',
|
||||
dataIndex: 'name',
|
||||
},
|
||||
{
|
||||
title: '流程实例',
|
||||
dataIndex: 'processInstanceId',
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: '办理人',
|
||||
dataIndex: 'assigneeName',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '流程ID',
|
||||
dataIndex: 'processDefinitionId',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '开始时间',
|
||||
dataIndex: 'startTime',
|
||||
},
|
||||
{
|
||||
title: '发起人',
|
||||
dataIndex: 'startUserName',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '耗时',
|
||||
dataIndex: 'spendTimes',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'isSuspended',
|
||||
width: 80,
|
||||
customRender: ({ text }) => {
|
||||
return text === 'true' ? '已暂停' : '已启动';
|
||||
},
|
||||
},
|
||||
];
|
||||
/**
|
||||
* 列表查询form
|
||||
*/
|
||||
export const searchFormSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'processInstanceId',
|
||||
label: '流程实例ID',
|
||||
component: 'Input',
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
{
|
||||
field: 'startUserId',
|
||||
label: '流程发起人',
|
||||
component: 'JSelectUserByDept',
|
||||
componentProps: {
|
||||
labelKey: 'realname',
|
||||
rowKey: 'username',
|
||||
showButton: false,
|
||||
maxSelectCount: 1,
|
||||
},
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,202 @@
|
||||
<template>
|
||||
<div>
|
||||
<BasicTable @register="registerTable" :rowSelection="rowSelection">
|
||||
<!--操作栏-->
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
<!--委派弹窗-->
|
||||
<DelegateModal @register="registerModal" @success="handleEntruster" title="请选择委派人"></DelegateModal>
|
||||
<!--转办弹窗-->
|
||||
<DelegateModal @register="registerModalComplaint" @success="handleComplaint" title="请选择转办人"></DelegateModal>
|
||||
<!--跳转弹窗-->
|
||||
<SelectTaskNodeModal @register="registerSkipModal" @success="reload"></SelectTaskNodeModal>
|
||||
<!--历史-->
|
||||
<HisTaskDealModal ref="taskDealRef" :path="path" :formData="formData"></HisTaskDealModal>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" name="process-instance-list" setup>
|
||||
import { ref, unref } from 'vue';
|
||||
import { BasicTable, TableAction } from '/@/components/Table';
|
||||
import DelegateModal from '../components/DelegateModal.vue';
|
||||
import SelectTaskNodeModal from '../components/SelectTaskNodeModal.vue';
|
||||
import HisTaskDealModal from '../components/HisTaskDealModal.vue';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import { columns, searchFormSchema } from './instance.data';
|
||||
import { list, suspend, restart, closeProcess, taskEntrust, taskComplaint } from './instance.api';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
import { useBpmNodeInfo } from '../components/hooks/useBpmNodeInfo';
|
||||
//委派弹窗
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
//委派弹窗
|
||||
const [registerModalComplaint, { openModal: openModalComplaint }] = useModal();
|
||||
//跳转弹窗
|
||||
const [registerSkipModal, { openModal: openSkipModal }] = useModal();
|
||||
|
||||
// 列表页面公共参数、方法
|
||||
const { prefixCls, tableContext } = useListPage({
|
||||
designScope: 'process-expression',
|
||||
tableProps: {
|
||||
api: list,
|
||||
isTreeTable: true,
|
||||
rowKey: 'processInstanceId',
|
||||
columns: columns,
|
||||
formConfig: {
|
||||
schemas: searchFormSchema,
|
||||
},
|
||||
actionColumn: {
|
||||
width: 120,
|
||||
fixed: 'right',
|
||||
},
|
||||
},
|
||||
});
|
||||
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||
const taskId = ref('');
|
||||
const path = ref('');
|
||||
const taskDealRef = ref(null);
|
||||
let { getHisProcessNodeInfo, formData } = useBpmNodeInfo(path, taskDealRef);
|
||||
/**
|
||||
* 激活
|
||||
* @param id
|
||||
*/
|
||||
async function handleRestart(id) {
|
||||
await restart({ processInstanceId: id }, reload);
|
||||
}
|
||||
/**
|
||||
* 挂起
|
||||
* @param id
|
||||
*/
|
||||
async function handleSuspend(id) {
|
||||
await suspend({ processInstanceId: id }, reload);
|
||||
}
|
||||
/**
|
||||
* 关闭
|
||||
* @param id
|
||||
*/
|
||||
async function handleClose(id) {
|
||||
await closeProcess({ processInstanceId: id }, reload);
|
||||
}
|
||||
/**
|
||||
* 选择委派人员弹窗
|
||||
* @param record
|
||||
*/
|
||||
function handleSelectEntruster(record) {
|
||||
taskId.value = record.taskId;
|
||||
openModal(true);
|
||||
}
|
||||
/**
|
||||
* 选择转办人员弹窗
|
||||
* @param record
|
||||
*/
|
||||
function handleSelectComplaint(record) {
|
||||
taskId.value = record.taskId;
|
||||
openModalComplaint(true);
|
||||
}
|
||||
/**
|
||||
* 跳转
|
||||
* @param taskId
|
||||
*/
|
||||
function handleSkipNode(taskId) {
|
||||
openSkipModal(true, { taskId });
|
||||
}
|
||||
/**
|
||||
* 显示历史
|
||||
* @param record
|
||||
*/
|
||||
function showHistory(record) {
|
||||
getHisProcessNodeInfo(record);
|
||||
}
|
||||
|
||||
/**
|
||||
* 委派
|
||||
* @data
|
||||
*/
|
||||
async function handleEntruster(data) {
|
||||
console.log('handleEntruster委派返回值data:', data);
|
||||
let params = { taskId: unref(taskId), taskAssignee: data.username };
|
||||
await taskEntrust(params, reload);
|
||||
}
|
||||
/**
|
||||
* 转办
|
||||
* @data
|
||||
*/
|
||||
async function handleComplaint(data) {
|
||||
console.log('handleComplaint转办返回值data:', data);
|
||||
let params = { taskId: unref(taskId), taskAssignee: data.username };
|
||||
await taskComplaint(params, reload);
|
||||
}
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '激活',
|
||||
popConfirm: {
|
||||
title: '是否激活?',
|
||||
confirm: handleRestart.bind(null, record.id),
|
||||
},
|
||||
ifShow: () => {
|
||||
return record.isSuspended != '' && record.isSuspended === 'true';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '挂起',
|
||||
popConfirm: {
|
||||
title: '是否挂起?',
|
||||
confirm: handleSuspend.bind(null, record.id),
|
||||
},
|
||||
ifShow: () => {
|
||||
return record.isSuspended != '' && record.isSuspended === 'false';
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 下拉操作栏
|
||||
*/
|
||||
function getDropDownAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '关闭',
|
||||
popConfirm: {
|
||||
title: '是否关闭吗?',
|
||||
confirm: handleClose.bind(null, record.id),
|
||||
},
|
||||
ifShow: () => {
|
||||
return record.isSuspended != '' && record.isSuspended != 'finished';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '转办',
|
||||
onClick: handleSelectComplaint.bind(null, record),
|
||||
ifShow: () => {
|
||||
return record.isSuspended != '' && record.isSuspended === 'false' && record.isSuspended != 'finished';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '委派',
|
||||
onClick: handleSelectEntruster.bind(null, record),
|
||||
ifShow: () => {
|
||||
return record.isSuspended != '' && record.isSuspended === 'false' && record.isSuspended != 'finished';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '跳转',
|
||||
onClick: handleSkipNode.bind(null, record.taskId),
|
||||
ifShow: () => {
|
||||
return record.isSuspended != '';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '历史',
|
||||
onClick: showHistory.bind(null, record),
|
||||
ifShow: () => {
|
||||
return record.isSuspended != '';
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,65 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
|
||||
enum Api {
|
||||
add = '/act/process/extActDesignFlowData/add',
|
||||
addCommUse = '/joa/designform/designFormCommuse/commUseDesignAdd',
|
||||
queryByCode = '/desform/queryByCode',
|
||||
roleDegisnList = '/joa/designform/designFormCommuse/roleDegisnList',
|
||||
commUseList = '/joa/designform/designFormCommuse/getCommuseByUserId',
|
||||
onlineList = '/joa/designform/designFormCommuse/queryOnlineFormList',
|
||||
roleOnlineList = '/joa/designform/designFormCommuse/roleOnlineList',
|
||||
sortChange = '/joa/designform/designFormCommuse/sortChange',
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表接口
|
||||
* @param params
|
||||
*/
|
||||
export const roleDegisnList = (params?) => defHttp.get({ url: Api.roleDegisnList, params }, { isTransformResponse: false });
|
||||
/**
|
||||
* 常用流程
|
||||
* @param params
|
||||
*/
|
||||
export const getCommUseList = () => defHttp.get({ url: Api.commUseList }, { isTransformResponse: false });
|
||||
/**
|
||||
* online列表
|
||||
*/
|
||||
export const getOnlineList = () => defHttp.get({ url: Api.onlineList }, { isTransformResponse: false });
|
||||
/**
|
||||
* roleOnlineList列表
|
||||
*/
|
||||
export const roleOnlineList = () => defHttp.get({ url: Api.roleOnlineList }, { isTransformResponse: false });
|
||||
/**
|
||||
* 根据流程编码查询
|
||||
* @param params
|
||||
*/
|
||||
export const queryByCode = (params) => defHttp.get({ url: Api.queryByCode, params }, { isTransformResponse: false });
|
||||
|
||||
/**
|
||||
* 往设计表单和流程的关系表中,插入一条数据
|
||||
* @param params
|
||||
*/
|
||||
export const addDesignFlowData = (params) => {
|
||||
return defHttp.post({ url: Api.add, params }, { isTransformResponse: false });
|
||||
};
|
||||
/**
|
||||
* 保存常用流程
|
||||
* @param params
|
||||
*/
|
||||
export const addCommUse = (params) => {
|
||||
return defHttp.post({ url: Api.addCommUse, params }, { isTransformResponse: false });
|
||||
};
|
||||
/**
|
||||
* 查询online表单数据
|
||||
* @param params
|
||||
*/
|
||||
export const queryOnlineDynamicData = (config) => {
|
||||
return defHttp.get(config, { isTransformResponse: false });
|
||||
};
|
||||
/**
|
||||
* 排序修改
|
||||
* @param params
|
||||
*/
|
||||
export const sortChange = (params) => {
|
||||
return defHttp.post({ url: Api.sortChange, params }, { isTransformResponse: false });
|
||||
};
|
||||
@@ -0,0 +1,479 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-card :bordered="false">
|
||||
<a-spin :spinning="loading">
|
||||
<template v-if="processTypeDictOptions.length > 0">
|
||||
<div style="display: flex; justify-content: space-between">
|
||||
<a-button type="primary" @click="handleSetUse" preIcon="ant-design:setting-outlined">设置常用流程</a-button>
|
||||
<div v-auth="'sys:order_apply:sort'" style="position: fixed; right: 35px; z-index: 999">
|
||||
<a-button v-if="!sortStatus" type="primary" @click="sortStatus = !sortStatus" preIcon="ant-design:drag-outlined">激活排序</a-button>
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="commUseList.length > 0">
|
||||
<a-col :xl="24" :lg="24" :md="24" :sm="24" :xs="24">
|
||||
<a-card :loading="loading" title="常用流程" style="margin-top: 24px; height: auto" :bodyStyle="{ padding: 0 }">
|
||||
<draggable
|
||||
:force-fallback="true"
|
||||
animation="200"
|
||||
dragClass="dragClass"
|
||||
ghostClass="ghostClass"
|
||||
chosenClass="chosenClass"
|
||||
v-model="commUseList"
|
||||
item-key="id"
|
||||
style="display: flex; flex-wrap: wrap"
|
||||
@end="dragEnd('common')"
|
||||
filter=".unmover"
|
||||
>
|
||||
<template #item="{ element }">
|
||||
<a-card-grid :style="{ width: cardWidth }" :class="{ unmover: !sortStatus }" @click="handleOk(element)">
|
||||
<template v-if="element?.desformIcon">
|
||||
<Icon v-if="element?.desformIcon.indexOf('ant-design') >= 0" :icon="element.desformIcon" :style="style" />
|
||||
<a-icon v-else :type="element?.desformIcon" :style="style" />
|
||||
</template>
|
||||
<Icon v-else icon="ant-design:file-text-outlined" :style="style" />
|
||||
<span class="bsSpan no-select" v-if="screenWidth > 700">
|
||||
<JEllipsis :value="element?.desformName" :length="6" />
|
||||
</span>
|
||||
<div v-else class="mobName no-select">
|
||||
<a-icon v-if="element?.appIcon" :type="element.appIcon" :style="style" />
|
||||
<Icon v-else icon="ant-design:file-text-outlined" :style="style" />
|
||||
{{ element?.desformName.length > 4 ? element?.desformName.substr(0, 4) : element.desformName }}
|
||||
</div>
|
||||
</a-card-grid>
|
||||
</template>
|
||||
</draggable>
|
||||
</a-card>
|
||||
</a-col>
|
||||
</template>
|
||||
|
||||
<template v-for="item of processTypeDictOptions">
|
||||
<a-col :xl="24" :lg="24" :md="24" :sm="24" :xs="24">
|
||||
<a-card :loading="loading" :title="item.text" :style="{ marginTop: '24px', height: 'auto' }" :bodyStyle="{ padding: 0 }">
|
||||
<draggable
|
||||
:force-fallback="true"
|
||||
animation="200"
|
||||
dragClass="dragClass"
|
||||
ghostClass="ghostClass"
|
||||
chosenClass="chosenClass"
|
||||
v-model="desformList"
|
||||
item-key="id"
|
||||
style="display: flex; flex-wrap: wrap"
|
||||
@end="dragEnd('desform')"
|
||||
filter=".unmover"
|
||||
>
|
||||
<template #item="{ element }">
|
||||
<a-card-grid
|
||||
v-if="element.procType == item.value"
|
||||
:class="{ unmover: !sortStatus }"
|
||||
:style="{ width: cardWidth }"
|
||||
@click="handleOk(element)"
|
||||
>
|
||||
<template v-if="element.desformIcon">
|
||||
<Icon v-if="element.desformIcon.indexOf('ant-design') >= 0" :icon="element.desformIcon" :style="style" />
|
||||
<a-icon v-else :type="element.desformIcon" :style="style" />
|
||||
</template>
|
||||
<Icon v-else icon="ant-design:file-text-outlined" :style="style" />
|
||||
<span class="bsSpan no-select" v-if="screenWidth > 700">
|
||||
<JEllipsis :value="element.desformName" :length="6" />
|
||||
</span>
|
||||
<div v-else class="mobName no-select">
|
||||
{{ element.desformName.length > 4 ? element.desformName.substr(0, 4) : element.desformName }}
|
||||
</div>
|
||||
</a-card-grid>
|
||||
</template>
|
||||
</draggable>
|
||||
</a-card>
|
||||
</a-col>
|
||||
</template>
|
||||
</template>
|
||||
<!--设置online流程-->
|
||||
<template v-if="onlineFormList && onlineFormList.length > 0">
|
||||
<a-col :xl="24" :lg="24" :md="24" :sm="24" :xs="24">
|
||||
<a-card :loading="loading" title="online表单" :style="{ marginTop: '24px', height: 'auto' }" :bodyStyle="{ padding: 0 }">
|
||||
<draggable
|
||||
:force-fallback="true"
|
||||
animation="200"
|
||||
dragClass="dragClass"
|
||||
ghostClass="ghostClass"
|
||||
chosenClass="chosenClass"
|
||||
v-model="onlineFormList"
|
||||
item-key="id"
|
||||
@end="dragEnd('online')"
|
||||
style="display: flex; flex-wrap: wrap"
|
||||
filter=".unmover"
|
||||
>
|
||||
<template #item="{ element }">
|
||||
<a-card-grid :style="{ width: cardWidth }" :class="{ unmover: !sortStatus }" @click="handleOpenOnlineModal(element)">
|
||||
<template v-if="element.desformIcon">
|
||||
<Icon v-if="element.desformIcon.indexOf('ant-design') >= 0" :icon="element.desformIcon" :style="style" />
|
||||
<a-icon v-else :type="element.desformIcon" :style="style" />
|
||||
</template>
|
||||
<Icon v-else icon="ant-design:file-text-outlined" :style="style" />
|
||||
<span class="bsSpan no-select" v-if="screenWidth > 700">
|
||||
<JEllipsis :value="element.desformName" :length="20" />
|
||||
</span>
|
||||
<div v-else class="mobName no-select">
|
||||
{{ element.desformName.length > 10 ? element.desformName.substr(0, 10) : element.desformName }}
|
||||
</div>
|
||||
</a-card-grid>
|
||||
</template>
|
||||
</draggable>
|
||||
</a-card>
|
||||
</a-col>
|
||||
</template>
|
||||
|
||||
<template v-if="(!onlineFormList || onlineFormList.length == 0) && (!processTypeDictOptions || processTypeDictOptions.length == 0)">
|
||||
<span>没有找到配置的流程!</span>
|
||||
</template>
|
||||
<div class="sticky-button" v-if="sortStatus">
|
||||
<a-button type="primary" size="middle" @click="saveSort" preIcon="ant-design:save-outlined">保存排序</a-button>
|
||||
<a-button class="ml-2" size="middle" type="primary" danger @click="sortStatus = !sortStatus" preIcon="ant-design:close-outlined">取消</a-button>
|
||||
</div>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
<!--online动态弹窗-->
|
||||
<OnlineDynamicModal ref="onlineModal" @register="registerOnlineModal" />
|
||||
<!--表单设计弹窗-->
|
||||
<DesformDataModal ref="desformModal" :dialogOptions="dialogOptions" @added="handleDesformDataAdded" />
|
||||
<!--常用流程设置-->
|
||||
<BpmAutoDesformSetUse @register="registerModal" @success="reload" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" name="order-apply-list" setup>
|
||||
import draggable from 'vuedraggable';
|
||||
import { ref, onMounted, computed, unref, reactive } from 'vue';
|
||||
import { router } from '/@/router';
|
||||
import JEllipsis from '/@/components/Form/src/jeecg/components/JEllipsis.vue';
|
||||
import BpmAutoDesformSetUse from './components/BpmAutoDesformSetUse.vue';
|
||||
import DesformDataModal from '../myApply/components/DesformDataModal.vue';
|
||||
import OnlineDynamicModal from './components/OnlineDynamicModal.vue';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { initDictOptions } from '/@/utils/dict/index';
|
||||
import { roleDegisnList, getCommUseList, queryByCode, addDesignFlowData, getOnlineList, sortChange, roleOnlineList } from './apply.api';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
const commUseList = ref<any>([]);
|
||||
const loading = ref(false);
|
||||
const desformList = ref<any>([]);
|
||||
const processTypeDict = ref<any>([]);
|
||||
const processTypeDictOptions = ref<any>([]);
|
||||
const flowCodePre = 'desform_';
|
||||
const dialogOptions = ref({ top: 60, width: 1000, padding: { top: 25, right: 25, bottom: 30, left: 25 } });
|
||||
const cardWidth = ref('20%');
|
||||
const screenWidth = ref();
|
||||
const sortStatus = ref(false);
|
||||
const onlineFormList = ref<any>([]);
|
||||
const desformModal = ref<any>(null);
|
||||
const onlineModal = ref<any>(null);
|
||||
const { createMessage } = useMessage();
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
const originalData = reactive({
|
||||
online: [],
|
||||
desform: [],
|
||||
commonUse: [],
|
||||
});
|
||||
const style = computed(() => {
|
||||
let style = { 'vertical-align': 'middle' };
|
||||
if (screenWidth.value > 700) {
|
||||
style['font-size'] = '30px';
|
||||
} else {
|
||||
style['font-size'] = '25px';
|
||||
style['margin-left'] = '30%';
|
||||
}
|
||||
return style;
|
||||
});
|
||||
/** 加载desform */
|
||||
async function loadDesformList() {
|
||||
loading.value = true;
|
||||
let dictRes = await initDictOptions('bpm_process_type');
|
||||
if (dictRes && dictRes.length > 0) {
|
||||
processTypeDict.value = dictRes;
|
||||
}
|
||||
let res = await roleDegisnList();
|
||||
if (res.success) {
|
||||
desformList.value = res.result;
|
||||
originalData.desform = cloneDeep(res.result);
|
||||
}
|
||||
//获取指定属性的数据集合
|
||||
let procTypeArr = [...new Set(Array.from(unref(desformList), ({ procType }) => procType))];
|
||||
//工单类型字典项
|
||||
processTypeDictOptions.value = processTypeDict.value.filter((item) => procTypeArr.indexOf(item.value) != -1);
|
||||
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
async function loadCommUseList() {
|
||||
loading.value = true;
|
||||
let res = await getCommUseList();
|
||||
if (res.success) {
|
||||
const sortList = res.result.sort(function (a: any, b: any) {
|
||||
return a.sortNum - b.sortNum;
|
||||
});
|
||||
commUseList.value = sortList;
|
||||
originalData.commonUse = cloneDeep(sortList);
|
||||
}
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
const [registerOnlineModal, { openModal: openOnlineModal }] = useModal();
|
||||
function handleOpenOnlineModal(item) {
|
||||
if (sortStatus.value) {
|
||||
return;
|
||||
}
|
||||
openOnlineModal(true, {
|
||||
id: item.id,
|
||||
name: item.desformCode,
|
||||
});
|
||||
}
|
||||
|
||||
function handleOk(desform) {
|
||||
if (sortStatus.value) {
|
||||
return;
|
||||
}
|
||||
if (desform) {
|
||||
if (desform.formType == 'online') {
|
||||
handleOpenOnlineModal(desform);
|
||||
} else {
|
||||
handleOkBpmSelect(desform);
|
||||
}
|
||||
}
|
||||
}
|
||||
/** bmp 选择 ok */
|
||||
function handleOkBpmSelect(desform) {
|
||||
let title = '表单【' + desform.desformName + '】发起申请';
|
||||
openDesformModal('add', desform, title);
|
||||
}
|
||||
/** 打开表单设计器弹窗*/
|
||||
async function openDesformModal(mode, record, title) {
|
||||
let desform = record,
|
||||
dataId = null;
|
||||
if (mode === 'edit' || mode === 'detail') {
|
||||
let { desformId: id, desformCode, desformDataId } = record;
|
||||
dataId = desformDataId;
|
||||
desform = { id, desformCode };
|
||||
}
|
||||
|
||||
let res = await queryByCode({ desformCode: desform.desformCode });
|
||||
if (res.success) {
|
||||
let designJson = res.result.desformDesignJson;
|
||||
let json = JSON.parse(designJson);
|
||||
// 保存 dialogConfig
|
||||
let options = json.config.dialogOptions;
|
||||
if (options) {
|
||||
dialogOptions.value = options;
|
||||
}
|
||||
desformModal.value?.open(mode, desform, dataId, title);
|
||||
}
|
||||
}
|
||||
|
||||
/** 流程数据保存成功后触发该事件 */
|
||||
async function handleDesformDataAdded(event) {
|
||||
// 将流程保存至后台
|
||||
let { desform, dataId } = event;
|
||||
loading.value = true;
|
||||
|
||||
//发起流程(往设计表单和流程的关系表中,插入一条数据)
|
||||
let res = await addDesignFlowData({
|
||||
desformId: desform.id,
|
||||
desformCode: desform.desformCode,
|
||||
desformDataId: dataId,
|
||||
desformName: desform.desformName,
|
||||
processName: desform.procName,
|
||||
flowCode: flowCodePre + desform.desformCode,
|
||||
titleExp: desform.titleExp,
|
||||
});
|
||||
loading.value = false;
|
||||
if (res.success) {
|
||||
router.push({ path: '/oaOffice/myOrder' });
|
||||
} else {
|
||||
createMessage.error(res.message);
|
||||
}
|
||||
}
|
||||
//打开常用流程设计弹窗
|
||||
function handleSetUse() {
|
||||
openModal(true, { processTypeDict: unref(processTypeDict) });
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新加载常用流程
|
||||
*/
|
||||
async function reload() {
|
||||
let res = await getCommUseList();
|
||||
if (res.success) {
|
||||
commUseList.value = res.result;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 设置卡片size
|
||||
*/
|
||||
function resetCardSize() {
|
||||
console.log('document.body.clientWidth:resetCardSize:', document.body.clientWidth);
|
||||
screenWidth.value = document.body.clientWidth;
|
||||
if (unref(screenWidth) <= 1350) {
|
||||
cardWidth.value = '33.3%';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询online表单
|
||||
*/
|
||||
async function queryOnlineFormList() {
|
||||
onlineFormList.value = [];
|
||||
//update-begin-author:liusq---date:2025-04-28--for:【QQYUN-10237】【流程审批】工单授权,没有对online表单的授权
|
||||
//原来接口 getOnlineLis t查询全部
|
||||
let res = await roleOnlineList();
|
||||
//update-end-author:liusq---date:2025-04-28--for:【QQYUN-10237】【流程审批】工单授权,没有对online表单的授权
|
||||
if (res.success) {
|
||||
onlineFormList.value = res.result;
|
||||
originalData.online = cloneDeep(res.result);
|
||||
}
|
||||
}
|
||||
|
||||
//*********************排序逻辑begin****************************
|
||||
/**
|
||||
* 拖拽结束事件
|
||||
* @param evt
|
||||
*/
|
||||
function dragEnd(type) {
|
||||
if (type == 'online') {
|
||||
for (let i = 0; i < unref(onlineFormList).length; i++) {
|
||||
if (unref(onlineFormList)[i].sortNum != i) {
|
||||
unref(onlineFormList)[i].sortNum = i;
|
||||
}
|
||||
}
|
||||
} else if (type == 'desform') {
|
||||
for (let i = 0; i < unref(desformList).length; i++) {
|
||||
if (unref(desformList)[i].sortNum != i) {
|
||||
unref(desformList)[i].sortNum = i;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < unref(commUseList).length; i++) {
|
||||
if (unref(commUseList)[i].sortNum != i) {
|
||||
unref(commUseList)[i].sortNum = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存排序
|
||||
*/
|
||||
async function saveSort() {
|
||||
let changeItem = [] as any[];
|
||||
unref(onlineFormList).forEach((item) => {
|
||||
const findObj = originalData.online.find((form: any) => form.id == item.id) as any;
|
||||
if (item.sortNum != findObj.sortNum) {
|
||||
changeItem.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
unref(desformList).forEach((item) => {
|
||||
const findObj = originalData.desform.find((form: any) => form.id == item.id) as any;
|
||||
if (item.sortNum != findObj.sortNum) {
|
||||
changeItem.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
// for (let i = 0; i < unref(commUseList).length; i++) {
|
||||
// const findObj = originalData.commonUse.find((form: any) => form.id == unref(commUseList)[i].id) as any;
|
||||
// if (unref(commUseList)[i].sortNum != findObj.sortNum) {
|
||||
// changeItem.push(unref(commUseList)[i]);
|
||||
// }
|
||||
// }
|
||||
sortStatus.value = false;
|
||||
console.log('changeItem', changeItem);
|
||||
if (changeItem.length > 0) {
|
||||
let res = await sortChange({ changeItem: changeItem });
|
||||
if (res.success) {
|
||||
createMessage.success(res.message);
|
||||
initData();
|
||||
}
|
||||
}
|
||||
}
|
||||
//*********************排序逻辑end****************************
|
||||
function initData() {
|
||||
loadDesformList();
|
||||
loadCommUseList();
|
||||
queryOnlineFormList();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initData();
|
||||
//当页面初始化时,根据屏幕大小来给设置card宽度
|
||||
resetCardSize();
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.bsSpan {
|
||||
vertical-align: middle;
|
||||
margin-left: 20px;
|
||||
display: inline-block;
|
||||
width: calc(100% - 51px);
|
||||
overflow: hidden;
|
||||
|
||||
:first-child {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.mobName {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
margin-top: 2px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
html[data-theme='light'] {
|
||||
.ant-card {
|
||||
:deep(.ant-card-head) {
|
||||
background-color: #eaeaea;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-card .ant-card-grid {
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
.ghostClass {
|
||||
background-color: #b3c9e6 !important;
|
||||
}
|
||||
.chosenClass {
|
||||
background-color: #ffece0 !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
.dragClass {
|
||||
background-color: #b3afe6 !important;
|
||||
opacity: 1 !important;
|
||||
box-shadow: none !important;
|
||||
outline: none !important;
|
||||
background-image: none !important;
|
||||
}
|
||||
.no-select {
|
||||
user-select: none; /* 对大多数浏览器有效 */
|
||||
-webkit-user-select: none; /* 对 Safari 有效 */
|
||||
-moz-user-select: none; /* 对 Firefox 有效 */
|
||||
-ms-user-select: none; /* 对 Internet Explorer 和 Edge 有效 */
|
||||
}
|
||||
|
||||
.dimensional-button {
|
||||
border: none; /* 去掉按钮边框 */
|
||||
box-shadow: 0 5px #097ce5; /* 添加阴影效果 */
|
||||
color: white; /* 设置字体颜色 */
|
||||
text-align: center; /* 文字居中 */
|
||||
text-decoration: none; /* 去掉默认下划线 */
|
||||
display: inline-block; /* 行内元素 */
|
||||
font-size: 16px; /* 设置字体大小 */
|
||||
border-radius: 10px; /* 设置圆角 */
|
||||
}
|
||||
|
||||
.sticky-button {
|
||||
position: fixed;
|
||||
bottom: 10px; /* 距离底部10像素 */
|
||||
left: 50%; /* 水平居中 */
|
||||
transform: translateX(-50%); /* 水平向左移动自身宽度的50% */
|
||||
z-index: 999;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,197 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose title="常用流程设置" @ok="handleSubmit" width="1200px">
|
||||
<!--工单部分-->
|
||||
<template v-for="(item, index) of processTypeDictOptions">
|
||||
<a-card :title="item.text" :style="{ marginTop: index == 0 ? '0px' : '12px', height: 'auto' }" :headStyle="{ backgroundColor: '#eaeaea' }">
|
||||
<a-checkbox-group v-model:value="designNameValue[index]" style="width: 100%">
|
||||
<a-row>
|
||||
<template v-for="des in designNameOption">
|
||||
<a-col :span="6" v-if="des.procType == item.value">
|
||||
<a-checkbox :value="des.value">{{ des.text }}</a-checkbox>
|
||||
</a-col>
|
||||
</template>
|
||||
</a-row>
|
||||
</a-checkbox-group>
|
||||
</a-card>
|
||||
</template>
|
||||
<!--online表单部分-->
|
||||
<template v-if="onlineFormList && onlineFormList.length > 0">
|
||||
<a-card title="online表单" :style="{ marginTop: '24px', height: 'auto' }" :headStyle="{ backgroundColor: '#eaeaea' }">
|
||||
<a-checkbox-group v-model:value="onlineCommonUserList" style="width: 100%">
|
||||
<a-row>
|
||||
<template v-for="des in onlineFormList">
|
||||
<a-col :span="6">
|
||||
<a-checkbox :value="des.id">{{ des.desformName.length > 10 ? des.desformName.substr(0, 10) : des.desformName }}</a-checkbox>
|
||||
</a-col>
|
||||
</template>
|
||||
</a-row>
|
||||
</a-checkbox-group>
|
||||
</a-card>
|
||||
</template>
|
||||
<!--树操作部分-->
|
||||
<template #insertFooter>
|
||||
<a-dropdown placement="top">
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item key="1" @click="checkALL">全部勾选</a-menu-item>
|
||||
<a-menu-item key="2" @click="cancelCheckALL">取消全选</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
<a-button style="float: left"> 树操作 <Icon icon="ant-design:up-outlined" /> </a-button>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, unref, toRaw } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/src/components/Modal';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { getCommUseList, roleDegisnList, getOnlineList, addCommUse, roleOnlineList } from '../apply.api';
|
||||
const { createMessage } = useMessage();
|
||||
// 声明Emits
|
||||
const emit = defineEmits(['success', 'register', 'ok']);
|
||||
//原始工单id
|
||||
const oldDesignId = ref('');
|
||||
//新工单id
|
||||
const newDesignId = ref('');
|
||||
//工单字典类型
|
||||
const processTypeDict = ref([]);
|
||||
//工单字典类型项
|
||||
const processTypeDictOptions = ref([]);
|
||||
//工单集合
|
||||
const desformList = ref([]);
|
||||
//工单名称集合
|
||||
const designNameOption = ref([]);
|
||||
//工单数据集合
|
||||
const designNameValue = ref([]);
|
||||
//online集合
|
||||
const onlineFormList = ref([]);
|
||||
//online数据集合
|
||||
const onlineCommonUserList = ref([]);
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
setModalProps({ confirmLoading: false });
|
||||
//初始化数据
|
||||
processTypeDict.value = data.processTypeDict;
|
||||
loadDesformList();
|
||||
queryOnlineFormList();
|
||||
});
|
||||
|
||||
/**
|
||||
* 初始化工单数据
|
||||
*/
|
||||
async function loadDesformList() {
|
||||
//获取表单设计信息
|
||||
let res = await roleDegisnList();
|
||||
if (res.success) {
|
||||
let designList = res.result;
|
||||
desformList.value = res.result;
|
||||
//获取指定属性的数据集合
|
||||
let procTypeArr = [...new Set(Array.from(unref(desformList), ({ procType }) => procType))];
|
||||
//工单类型字典项
|
||||
processTypeDictOptions.value = processTypeDict.value.filter((item) => procTypeArr.indexOf(item.value) != -1);
|
||||
//工单名称集合
|
||||
designNameOption.value = designList.map((design) => {
|
||||
return { value: design.id, text: design.desformName, procType: design.procType };
|
||||
});
|
||||
}
|
||||
//获取表单信息
|
||||
let useRes = await getCommUseList();
|
||||
if (useRes.success) {
|
||||
let commUseList = useRes.result;
|
||||
if (commUseList.length > 0) {
|
||||
let onlineList = commUseList.filter((item) => item.formType == 'online');
|
||||
let designList = commUseList.filter((item) => item.formType !== 'online');
|
||||
let { designName, designValues } = selectedDesign(designList);
|
||||
designNameValue.value = designValues;
|
||||
onlineCommonUserList.value = onlineList.map((item) => item.id);
|
||||
oldDesignId.value = commUseList.map((item) => item.id).join(',');
|
||||
} else {
|
||||
designNameValue.value = [];
|
||||
onlineCommonUserList.value = [];
|
||||
oldDesignId.value = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 初始化online数据
|
||||
*/
|
||||
async function queryOnlineFormList() {
|
||||
onlineFormList.value = [];
|
||||
let res = await roleOnlineList();
|
||||
if (res.success) {
|
||||
onlineFormList.value = res.result;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 点击修改
|
||||
*/
|
||||
function designNameChange(selectedValue) {
|
||||
newDesignId.value = unref(designNameValue).join(',');
|
||||
}
|
||||
/**
|
||||
* 全选
|
||||
*/
|
||||
function checkALL() {
|
||||
let { designName, designValues } = selectedDesign(toRaw(unref(desformList)));
|
||||
designNameValue.value = designValues;
|
||||
onlineCommonUserList.value = onlineFormList.value.map((item) => item.id);
|
||||
newDesignId.value = [...designName, ...toRaw(unref(onlineCommonUserList))].join(',');
|
||||
}
|
||||
/**
|
||||
* 取消全选
|
||||
*/
|
||||
function cancelCheckALL() {
|
||||
designNameValue.value = [];
|
||||
onlineCommonUserList.value = [];
|
||||
newDesignId.value = '';
|
||||
}
|
||||
/**
|
||||
* 选中工单信息
|
||||
*/
|
||||
function selectedDesign(selectedList) {
|
||||
let designName = [];
|
||||
let designValues = [];
|
||||
for (let option of unref(processTypeDictOptions)) {
|
||||
let values = [];
|
||||
for (let value of selectedList) {
|
||||
if (option.value == value.procType) {
|
||||
designName.push(value.id);
|
||||
values.push(value.id);
|
||||
}
|
||||
}
|
||||
designValues.push(values);
|
||||
}
|
||||
return { designName, designValues };
|
||||
}
|
||||
/**
|
||||
* 提交事件
|
||||
*/
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
setModalProps({ confirmLoading: true });
|
||||
let formData = {};
|
||||
//TODO designNameValue的问题
|
||||
let designValues = [];
|
||||
unref(designNameValue).forEach((item) => {
|
||||
designValues.push.apply(designValues, item);
|
||||
});
|
||||
formData['newDesignId'] = [...designValues, ...toRaw(unref(onlineCommonUserList))].join(',');
|
||||
formData['oldDessignId'] = toRaw(unref(oldDesignId));
|
||||
formData['onlineForm'] = onlineCommonUserList.value.join(',');
|
||||
//保存常用流程
|
||||
let res = await addCommUse(formData);
|
||||
if (res.success) {
|
||||
createMessage.success(res.message);
|
||||
emit('success');
|
||||
emit('ok');
|
||||
} else {
|
||||
createMessage.warning(res.message);
|
||||
}
|
||||
//关闭弹窗
|
||||
closeModal();
|
||||
} finally {
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,149 @@
|
||||
<template>
|
||||
<BasicModal :title="title" :width="modalWidth" v-bind="$attrs" @register="registerModal" wrapClassName="jeecg-online-modal" @ok="handleSubmit">
|
||||
<template #footer>
|
||||
<a-button
|
||||
v-for="btn in cgButtonList"
|
||||
:key="btn.id"
|
||||
type="primary"
|
||||
@click="handleCgButtonClick(btn.optType, btn.buttonCode)"
|
||||
:preIcon="btn.buttonIcon ? 'ant-design:' + btn.buttonIcon : ''"
|
||||
>
|
||||
{{ btn.buttonName }}
|
||||
</a-button>
|
||||
|
||||
<a-button v-if="!disableSubmit" key="submit" type="primary" @click="handleSubmit" :loading="submitLoading">确定</a-button>
|
||||
<a-button key="back" @click="handleCancel">关闭</a-button>
|
||||
</template>
|
||||
<online-form
|
||||
ref="onlineFormCompRef"
|
||||
:id="tableId"
|
||||
:disabled="disableSubmit"
|
||||
:form-template="formTemplate"
|
||||
:isTree="isTreeForm"
|
||||
:pidField="pidFieldName"
|
||||
:submitTip="false"
|
||||
@rendered="renderSuccess"
|
||||
@success="handleSuccess"
|
||||
>
|
||||
</online-form>
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, nextTick } from 'vue';
|
||||
import { BasicModal } from '/@/components/Modal';
|
||||
import OnlineForm from '/@/views/super/online/cgform/auto/comp/OnlineForm.vue';
|
||||
import { useAutoModal } from '/@/views/super/online/cgform/hooks/auto/useAutoModal';
|
||||
import { startProcess } from '/@/views/super/bpm/example/batch/leave.api';
|
||||
import { SUBMIT_FLOW_ID } from '/@/views/super/online/cgform/types/onlineRender';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { getRefPromise } from '/@/views/super/online/cgform/hooks/auto/useAutoForm';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'OnlineDynamicModal',
|
||||
components: {
|
||||
BasicModal,
|
||||
OnlineForm,
|
||||
},
|
||||
emits: ['register'],
|
||||
setup() {
|
||||
console.log('工单申请-进入表单弹框》》》》modal');
|
||||
const flow_code_pre = 'onl_';
|
||||
const tableName = ref('');
|
||||
const tableId = ref('');
|
||||
|
||||
const { createMessage } = useMessage();
|
||||
let {
|
||||
title,
|
||||
modalWidth,
|
||||
registerModal,
|
||||
closeModal,
|
||||
cgButtonList,
|
||||
handleCgButtonClick,
|
||||
disableSubmit,
|
||||
handleSubmit,
|
||||
submitLoading,
|
||||
handleCancel,
|
||||
modalObject,
|
||||
isUpdate,
|
||||
handleFormConfig,
|
||||
onlineFormCompRef,
|
||||
formTemplate,
|
||||
isTreeForm,
|
||||
pidFieldName,
|
||||
renderSuccess,
|
||||
formRendered,
|
||||
} = useAutoModal(true);
|
||||
|
||||
/**
|
||||
* 打开弹窗触发
|
||||
* @param data
|
||||
*/
|
||||
modalObject.handleOpenModal = async (data) => {
|
||||
const { id, name } = data;
|
||||
tableId.value = id;
|
||||
tableName.value = name;
|
||||
isUpdate.value = false;
|
||||
disableSubmit.value = false;
|
||||
formRendered.value = false;
|
||||
console.log('工单申请-重新渲染表单》》》》modal', data);
|
||||
await handleFormConfig(id);
|
||||
await nextTick(async () => {
|
||||
await getRefPromise(formRendered);
|
||||
await onlineFormCompRef.value.show(isUpdate);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 表单提交完成触发
|
||||
* @param formData
|
||||
*/
|
||||
function handleSuccess(formData) {
|
||||
handleStartProcess(formData[SUBMIT_FLOW_ID]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交流程
|
||||
* @param id
|
||||
*/
|
||||
async function handleStartProcess(id) {
|
||||
let param = {
|
||||
flowCode: flow_code_pre + tableName.value,
|
||||
id: id,
|
||||
formUrl: 'super/bpm/process/components/OnlineFormDetail',
|
||||
formUrlMobile: 'check/onlineForm/detail',
|
||||
};
|
||||
let res = await startProcess(param);
|
||||
if (res.success) {
|
||||
createMessage.success(res.message);
|
||||
closeModal();
|
||||
} else {
|
||||
createMessage.warning(res.message);
|
||||
}
|
||||
}
|
||||
|
||||
const that = {
|
||||
title,
|
||||
onlineFormCompRef,
|
||||
renderSuccess,
|
||||
registerModal,
|
||||
handleSubmit,
|
||||
handleSuccess,
|
||||
handleCancel,
|
||||
modalWidth,
|
||||
formTemplate,
|
||||
disableSubmit,
|
||||
cgButtonList,
|
||||
handleCgButtonClick,
|
||||
isTreeForm,
|
||||
pidFieldName,
|
||||
submitLoading,
|
||||
tableId,
|
||||
};
|
||||
|
||||
return that;
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,77 @@
|
||||
/** 列表上方操作按钮区域 */
|
||||
.ant-card-body .table-operator {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
/** Button按钮间距 */
|
||||
.table-operator .ant-btn {
|
||||
margin: 0 8px 8px 0;
|
||||
}
|
||||
|
||||
.table-operator .ant-btn-group .ant-btn {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.table-operator .ant-btn-group .ant-btn:last-child {
|
||||
margin: 0 8px 8px 0;
|
||||
}
|
||||
|
||||
/* 列表td的padding设置 可以控制列表大小 */
|
||||
.ant-table-tbody .ant-table-row td {
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
/* 列表页面弹出modal */
|
||||
.ant-modal-cust-warp {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* 弹出modal Y轴滚动条 */
|
||||
.ant-modal-cust-warp .ant-modal-body {
|
||||
height: calc(100% - 110px) !important;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* 弹出modal 先有content后有body 故滚动条控制在body上 */
|
||||
.ant-modal-cust-warp .ant-modal-content {
|
||||
height: 90% !important;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
/* 列表中有图片的加这个样式 参考用户管理 */
|
||||
.anty-img-wrap {
|
||||
height: 25px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.anty-img-wrap > img {
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
/* 列表中范围查询样式 */
|
||||
.query-group-cust {
|
||||
width: calc(50% - 10px);
|
||||
}
|
||||
|
||||
.query-group-split-cust::before {
|
||||
content: '~';
|
||||
width: 20px;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* erp风格子表外框padding设置 */
|
||||
.ant-card-wider-padding.cust-erp-sub-tab > .ant-card-body {
|
||||
padding: 5px 12px;
|
||||
}
|
||||
|
||||
/* 内嵌子表背景颜色 */
|
||||
.j-inner-table-wrapper :deep(.ant-table-expanded-row .ant-table-wrapper .ant-table-tbody .ant-table-row) {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
/** 隐藏样式-modal确定按钮 */
|
||||
.jee-hidden {
|
||||
display: none;
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<div v-if="visible" class="j-auto-desform-data-full-screen" :style="{ backgroundColor: bgColor }">
|
||||
<DesformView
|
||||
class="desform-view"
|
||||
:mode="mode"
|
||||
:desformCode="desForm.desformCode"
|
||||
:dataId="dataId"
|
||||
height="100vh"
|
||||
:innerDialog="true"
|
||||
@close="close"
|
||||
@forceClose="close"
|
||||
@success="handleSuccess"
|
||||
@reload="handleReload"
|
||||
:isOnline="isOnline"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, toRefs, reactive } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
dialogOptions: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
},
|
||||
emits: ['close', 'added', 'edited', 'ok'],
|
||||
setup(_, { emit }) {
|
||||
const _data = reactive({
|
||||
mode: 'add',
|
||||
title: '操作',
|
||||
visible: false,
|
||||
desForm: {},
|
||||
dataId: null,
|
||||
bgColor: 'rgba(0,0,0,0.6)',
|
||||
isOnline: false,
|
||||
/** 开启表单 */
|
||||
});
|
||||
function open(mode, desform, dataId, title) {
|
||||
_data.mode = mode;
|
||||
_data.title = title;
|
||||
_data.dataId = dataId;
|
||||
_data.desForm = desform;
|
||||
_data.visible = true;
|
||||
console.log('_data', _data);
|
||||
}
|
||||
|
||||
/** 开始关闭动画 */
|
||||
function close() {
|
||||
_data.bgColor = 'rgba(0,0,0,0)';
|
||||
setTimeout(() => {
|
||||
closed();
|
||||
}, 150);
|
||||
}
|
||||
|
||||
/** 完全关闭,并初始化所有的字段 */
|
||||
function closed() {
|
||||
_data.visible = false;
|
||||
emit('close');
|
||||
_data.bgColor = 'rgba(0,0,0,0.6)';
|
||||
// 恢复body的滚动
|
||||
document.body.style.overflow = _data.bodyOverflow;
|
||||
_data.bodyOverflow = null;
|
||||
}
|
||||
|
||||
function handleSuccess(event) {
|
||||
if (_data.dataId == null) {
|
||||
emit('added', { desform: _data.desForm, dataId: event.dataId });
|
||||
} else {
|
||||
emit('edited', { desform: _data.desForm, dataId: _data.dataId });
|
||||
}
|
||||
close();
|
||||
}
|
||||
|
||||
function handleReload() {
|
||||
emit('ok');
|
||||
}
|
||||
return {
|
||||
open,
|
||||
close,
|
||||
handleSuccess,
|
||||
handleReload,
|
||||
...toRefs(_data),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.j-auto-desform-data-full-screen {
|
||||
position: fixed;
|
||||
z-index: 999;
|
||||
transition: background-color 150ms;
|
||||
|
||||
&,
|
||||
.desform-view {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.desform-view {
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,61 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { Modal } from 'ant-design-vue';
|
||||
enum Api {
|
||||
list = '/act/process/extActDesignFlowData/list',
|
||||
save = '/act/process/extActDesignFlowData/add',
|
||||
edit = '/act/process/extActDesignFlowData/edit',
|
||||
delete = '/act/process/extActDesignFlowData/delete',
|
||||
queryFormDataById = '/desform/data/queryById',
|
||||
deleteBatch = '/act/process/extActDesignFlowData/deleteBatch',
|
||||
startProcess = '/act/process/extActProcess/startDesFormMutilProcess',
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表接口
|
||||
* @param params
|
||||
*/
|
||||
export const list = (params) => defHttp.get({ url: Api.list, params });
|
||||
|
||||
/**
|
||||
* 提交流程
|
||||
* @param params
|
||||
*/
|
||||
export const startDesFormProcess = (params, handleSuccess) => {
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
content: '确认提交流程吗?',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
return defHttp.get({ url: Api.queryFormDataById, params }, { isTransformResponse: false }).then((res) => {
|
||||
handleSuccess(res);
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 提交流程
|
||||
* @param params
|
||||
*/
|
||||
export const startProcess = (params) => {
|
||||
return defHttp.post({ url: Api.startProcess, params }, { isTransformResponse: false });
|
||||
};
|
||||
/**
|
||||
* 保存或者更新
|
||||
* @param params
|
||||
*/
|
||||
export const saveOrUpdate = (params, isUpdate) => {
|
||||
let url = isUpdate ? Api.edit : Api.save;
|
||||
return isUpdate
|
||||
? defHttp.put({ url: url, params }, { isTransformResponse: false })
|
||||
: defHttp.post({ url: url, params }, { isTransformResponse: false });
|
||||
};
|
||||
/**
|
||||
* 删除监听
|
||||
* @param params
|
||||
*/
|
||||
export const deleteOne = (params, handleSuccess) => {
|
||||
return defHttp.delete({ url: Api.delete, data: params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,154 @@
|
||||
import { FormSchema } from '/@/components/Table';
|
||||
import { render } from '/@/utils/common/renderUtils';
|
||||
|
||||
export const columns = [
|
||||
{
|
||||
title: '业务申请',
|
||||
dataIndex: 'bpmTitle',
|
||||
width: 200,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '表单',
|
||||
dataIndex: 'desformName',
|
||||
width: 250,
|
||||
ellipsis: true,
|
||||
customRender: ({ text }) => {
|
||||
return `工单【${text}】`;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '表单编码',
|
||||
dataIndex: 'desformCode',
|
||||
},
|
||||
{
|
||||
title: '流程名称',
|
||||
dataIndex: 'processName',
|
||||
},
|
||||
{
|
||||
title: '流程编码',
|
||||
dataIndex: 'flowCode',
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'bpmStatus',
|
||||
customRender: ({ text }) => {
|
||||
return render.renderDict(text, 'bpm_status');
|
||||
},
|
||||
},
|
||||
];
|
||||
/**
|
||||
* 列表查询form
|
||||
*/
|
||||
export const searchFormSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'desformCode',
|
||||
label: '表单名称',
|
||||
component: 'JSearchSelect',
|
||||
colProps: { span: 6 },
|
||||
componentProps: {
|
||||
dict: 'design_form where parent_id is null,desform_name,desform_code',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'flowCode',
|
||||
label: '流程编码',
|
||||
component: 'JInput',
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
{
|
||||
field: 'processName',
|
||||
label: '流程名称',
|
||||
component: 'JInput',
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
];
|
||||
/**
|
||||
* 表单form
|
||||
*/
|
||||
export const formSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'id',
|
||||
label: '',
|
||||
component: 'Input',
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
label: '名称',
|
||||
field: 'listenerName',
|
||||
required: true,
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '监听类型',
|
||||
field: 'listenerType',
|
||||
component: 'Select',
|
||||
componentProps: ({ formModel }) => {
|
||||
return {
|
||||
options: [
|
||||
{ label: '执行监听', value: 1 },
|
||||
{ label: '任务监听', value: 2 },
|
||||
],
|
||||
onChange: () => {
|
||||
formModel.listenerEvent = '';
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '事件属性',
|
||||
field: 'listenerEvent',
|
||||
component: 'Select',
|
||||
componentProps: ({ formModel }) => {
|
||||
const isExecute = [
|
||||
{ label: 'start', value: 'start' },
|
||||
{ label: 'end', value: 'end' },
|
||||
{ label: 'take', value: 'take' },
|
||||
];
|
||||
const isTask = [
|
||||
{ label: 'create', value: 'create' },
|
||||
{ label: 'assignment', value: 'assignment' },
|
||||
{ label: 'complete', value: 'complete' },
|
||||
];
|
||||
let option = !formModel['listenerType'] ? [] : formModel['listenerType'] == 1 ? isExecute : isTask;
|
||||
return {
|
||||
options: option,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '值类型',
|
||||
field: 'listenerValueType',
|
||||
component: 'RadioGroup',
|
||||
defaultValue: 'javaClass',
|
||||
componentProps: ({ formActionType }) => {
|
||||
return {
|
||||
options: [
|
||||
{ label: 'JAVA类', value: 'javaClass' },
|
||||
{ label: '表达式', value: 'expression' },
|
||||
{ label: '代理表达式', value: 'delegateExpression' },
|
||||
],
|
||||
onChange: (e) => {
|
||||
const { updateSchema } = formActionType;
|
||||
let value = e.target.value;
|
||||
const label = value === 'javaClass' ? '类路径' : '表达式';
|
||||
updateSchema([
|
||||
{
|
||||
field: 'listenerValue',
|
||||
label: label,
|
||||
},
|
||||
]);
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '类路径',
|
||||
field: 'listenerValue',
|
||||
component: 'Input',
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,216 @@
|
||||
<template>
|
||||
<div>
|
||||
<BasicTable @register="registerTable" :rowSelection="rowSelection">
|
||||
<!--操作栏-->
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
<!-- 审批记录 -->
|
||||
<BpmProcessFormTrackModal ref="trackRef"></BpmProcessFormTrackModal>
|
||||
<!-- 表单区域 -->
|
||||
<DesformDataModal ref="desformModal" @added="handleDesformDataAdded" @edited="handleDesformDataEdited" @close="reload" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" name="process-order-list" setup>
|
||||
import { ref } from 'vue';
|
||||
import { BasicTable, TableAction } from '/@/components/Table';
|
||||
import BpmProcessFormTrackModal from '/@/views/super/bpm/process/manage/components/BpmProcessFormTrackModal.vue';
|
||||
import DesformDataModal from './components/DesformDataModal.vue';
|
||||
import { columns, searchFormSchema } from './my.apply.data';
|
||||
import { list, startProcess, startDesFormProcess, deleteOne, saveOrUpdate } from './my.apply.api';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
|
||||
const { createMessage } = useMessage();
|
||||
// 列表页面公共参数、方法
|
||||
const { prefixCls, tableContext } = useListPage({
|
||||
designScope: 'my-process-order',
|
||||
tableProps: {
|
||||
title: '我的工单',
|
||||
api: list,
|
||||
columns: columns,
|
||||
canResize: false,
|
||||
scroll: { x: 1800 },
|
||||
formConfig: {
|
||||
schemas: searchFormSchema,
|
||||
},
|
||||
actionColumn: {
|
||||
width: 150,
|
||||
fixed: 'right',
|
||||
},
|
||||
},
|
||||
});
|
||||
const [registerTable, { reload, clearSelectedRowKeys }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||
|
||||
const flowCodePre = 'desform_';
|
||||
const trackRef = ref();
|
||||
const desformModal = ref();
|
||||
/**
|
||||
* 提交流程
|
||||
* @param record
|
||||
*/
|
||||
async function handleStartProcess(record) {
|
||||
const success = async (res) => {
|
||||
if (res && res.success) {
|
||||
let jsonData = res.result.desformDataJson;
|
||||
let param = {
|
||||
flowCode: flowCodePre + record.desformCode,
|
||||
id: record.id,
|
||||
formUrl: '{{DOMAIN_URL}}/desform/detail/' + record.desformCode + '/${BPM_DES_DATA_ID}?token={{TOKEN}}&taskId={{TASKID}}',
|
||||
formUrlMobile: '{{DOMAIN_URL}}/desform/detail/' + record.desformCode + '/${BPM_DES_DATA_ID}?token={{TOKEN}}&taskId={{TASKID}}',
|
||||
jsonData: jsonData,
|
||||
};
|
||||
let result = await startProcess(param);
|
||||
if (result && result.success) {
|
||||
createMessage.success(result.message);
|
||||
reload();
|
||||
clearSelectedRowKeys();
|
||||
} else {
|
||||
createMessage.warning(res.message || '流程启动异常');
|
||||
}
|
||||
} else {
|
||||
createMessage.warning(res?.message || '数据加载失败');
|
||||
}
|
||||
};
|
||||
await startDesFormProcess({ desformCode: record.desformCode,id: record.desformDataId }, success);
|
||||
}
|
||||
/**
|
||||
* 编辑
|
||||
* @param record
|
||||
*/
|
||||
function handleEdit(record) {
|
||||
let title = '【' + record.desformName + '】详情';
|
||||
openDesformModal('edit', record, title);
|
||||
}
|
||||
/**
|
||||
* 详情
|
||||
* @param record
|
||||
*/
|
||||
function handleDetail(record) {
|
||||
let title = '详情【' + record.desformName + '】';
|
||||
openDesformModal('detail', record, title);
|
||||
}
|
||||
|
||||
function openDesformModal(mode, record, title) {
|
||||
let desform = record,
|
||||
dataId = null;
|
||||
if (mode === 'edit' || mode === 'detail') {
|
||||
let { desformId: id, desformCode, desformDataId } = record;
|
||||
dataId = desformDataId;
|
||||
desform = { id, desformCode };
|
||||
}
|
||||
desformModal.value.open(mode, desform, dataId, title);
|
||||
}
|
||||
/**
|
||||
* 删除
|
||||
* @param id
|
||||
*/
|
||||
async function handleDelete(id) {
|
||||
await deleteOne({ id }, reload);
|
||||
}
|
||||
/**
|
||||
* 审批进度
|
||||
* @param record
|
||||
*/
|
||||
function handleTrack(record) {
|
||||
console.log('审批进度', record);
|
||||
let flowCode = flowCodePre + record.desformCode;
|
||||
let params = { flowCode: flowCode, dataId: record.id }; //查询条件
|
||||
trackRef.value.handleTrack(params);
|
||||
trackRef.value.data.title = '审批跟踪记录';
|
||||
}
|
||||
/** 流程数据保存成功后触发该事件 */
|
||||
async function handleDesformDataAdded(event) {
|
||||
// 将流程保存至后台
|
||||
let { desform, dataId } = event;
|
||||
|
||||
//发起流程(往设计表单和流程的关系表中,插入一条数据)
|
||||
let res = await saveOrUpdate(
|
||||
{
|
||||
desformId: desform.id,
|
||||
desformCode: desform.desformCode,
|
||||
desformDataId: dataId,
|
||||
desformName: desform.desformName,
|
||||
processName: desform.procName,
|
||||
flowCode: flowCodePre + desform.desformCode,
|
||||
titleExp: desform.titleExp,
|
||||
},
|
||||
false
|
||||
);
|
||||
if (!res.success) {
|
||||
createMessage.error(res.message);
|
||||
} else {
|
||||
reload();
|
||||
}
|
||||
}
|
||||
|
||||
/** 流程数据更新成功后触发该事件 */
|
||||
function handleDesformDataEdited(event) {
|
||||
// 将流程保存至后台
|
||||
let { desform, dataId } = event;
|
||||
saveOrUpdate(
|
||||
{
|
||||
desformDataId: dataId,
|
||||
},
|
||||
true
|
||||
).then((res) => {
|
||||
console.log('res', res);
|
||||
if (!res.success) {
|
||||
createMessage.error(res.message);
|
||||
} else {
|
||||
reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '提交流程',
|
||||
onClick: handleStartProcess.bind(null, record),
|
||||
ifShow: () => {
|
||||
return record.bpmStatus === '1';
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 下拉操作栏
|
||||
*/
|
||||
function getDropDownAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
ifShow: () => {
|
||||
return record.bpmStatus === '1';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '详情',
|
||||
onClick: handleDetail.bind(null, record),
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
confirm: handleDelete.bind(null, record.id),
|
||||
},
|
||||
ifShow: () => {
|
||||
return record.bpmStatus === '1';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '审批进度',
|
||||
onClick: handleTrack.bind(null, record),
|
||||
ifShow: () => {
|
||||
return record.bpmStatus !== '1';
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<div v-if="_data.visible" class="j-auto-desform-data-full-screen" :style="{ backgroundColor: _data.bgColor }">
|
||||
<desform-view
|
||||
class="desform-view"
|
||||
:mode="_data.mode"
|
||||
:desformCode="_data.desformCode"
|
||||
:dataId="_data.dataId"
|
||||
height="100vh"
|
||||
:innerDialog="true"
|
||||
@close="close"
|
||||
@success="handleSuccess"
|
||||
@reload="handleReload"
|
||||
:isOnline="_data.isOnline"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive } from 'vue';
|
||||
|
||||
const emit = defineEmits(['ok']);
|
||||
const _data = reactive({
|
||||
mode: 'add',
|
||||
title: '操作',
|
||||
visible: false,
|
||||
desformCode: null,
|
||||
dataId: null,
|
||||
bodyOverflow: null,
|
||||
bgColor: 'rgba(0,0,0,0.6)',
|
||||
isOnline: false,
|
||||
});
|
||||
|
||||
/** 开启表单 */
|
||||
function open(mode, desformCode, dataId, title, isOnline) {
|
||||
_data.isOnline = isOnline;
|
||||
_data.mode = mode;
|
||||
_data.title = title;
|
||||
_data.dataId = dataId;
|
||||
_data.desformCode = desformCode;
|
||||
_data.visible = true;
|
||||
// 禁止body滚动,防止滚动穿透
|
||||
_data.bodyOverflow = document.body.style.overflow;
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
/** 开始关闭动画 */
|
||||
function close() {
|
||||
_data.bgColor = 'rgba(0,0,0,0)';
|
||||
setTimeout(() => {
|
||||
closed();
|
||||
}, 150);
|
||||
}
|
||||
|
||||
/** 完全关闭,并初始化所有的字段 */
|
||||
function closed() {
|
||||
_data.visible = false;
|
||||
emit('ok');
|
||||
_data.bgColor = 'rgba(0,0,0,0.6)';
|
||||
// 恢复body的滚动
|
||||
document.body.style.overflow = _data.bodyOverflow;
|
||||
_data.bodyOverflow = null;
|
||||
}
|
||||
|
||||
function handleSuccess() {
|
||||
emit('ok');
|
||||
close();
|
||||
}
|
||||
|
||||
function handleReload() {
|
||||
emit('ok');
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.j-auto-desform-data-full-screen {
|
||||
position: fixed;
|
||||
z-index: 999;
|
||||
transition: background-color 150ms;
|
||||
|
||||
&,
|
||||
.desform-view {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.desform-view {
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,39 @@
|
||||
import { Switch, Slider, Rate } from 'ant-design-vue';
|
||||
import JEllipsis from '/@/components/Form/src/jeecg/components/JEllipsis.vue';
|
||||
//设置特殊列类型(仅用于工单查询)
|
||||
export function setCustomRender(item, column, options) {
|
||||
// TODO 开关特殊处理
|
||||
if (item.type === 'switch') {
|
||||
column.customRender = ({ text }) => {
|
||||
let activeValue = options.activeValue || true;
|
||||
return <Switch size="small" checked={text === activeValue} disabled />;
|
||||
};
|
||||
}
|
||||
// TODO 滑块特殊处理
|
||||
if (item.type === 'slider') {
|
||||
let { min, max } = options;
|
||||
column.customRender = ({ text }) => {
|
||||
return <Slider value={text} min={min} max={max} disabled style="margin:0;" />;
|
||||
};
|
||||
}
|
||||
// TODO 评分组件
|
||||
if (item.type === 'rate') {
|
||||
let { max, allowHalf } = options;
|
||||
column.customRender = ({ text }) => {
|
||||
let val = parseInt(text);
|
||||
return <Rate value={val} count={max} allowHalf={allowHalf} disabled style="margin:0;font-size: 16px;" />;
|
||||
};
|
||||
}
|
||||
// TODO 超长截取显示
|
||||
if (!column.slots && !column.customRender) {
|
||||
column.customRender = ({ text }) => {
|
||||
let txt = text;
|
||||
// 如果是数组,就显示为逗号分割
|
||||
if (Array.isArray(text)) {
|
||||
txt = text.join(',');
|
||||
}
|
||||
return <JEllipsis length={50} value={txt} />;
|
||||
};
|
||||
}
|
||||
return column;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
enum Api {
|
||||
list = '/desform/data/list',
|
||||
queryById = '/desform/queryById',
|
||||
getColumns = '/desform/getColumns',
|
||||
queryByCode = '/desform/queryByCode',
|
||||
delete = '/desform/data/delete',
|
||||
deleteBatch = '/desform/data/deleteBatch',
|
||||
exportXls = '/desform/data/exportXls/',
|
||||
importXls = '/desform/data/importXls/',
|
||||
// 对接流程地址
|
||||
startProcess = '/act/process/extActProcess/startDesFormMutilProcess',
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表接口
|
||||
* @param params
|
||||
*/
|
||||
export const list = (params) => defHttp.get({ url: Api.list, params }, { isTransformResponse: false });
|
||||
/**
|
||||
* 直接请求
|
||||
* @param url
|
||||
*/
|
||||
export const getAction = (url) => defHttp.get({ url: url }, { isTransformResponse: false });
|
||||
/**
|
||||
* 获取列信息
|
||||
* @param params
|
||||
*/
|
||||
export const getColumns = (params) => defHttp.get({ url: Api.getColumns, params }, { isTransformResponse: false });
|
||||
|
||||
const getTransitURL = (url) => `/desform/api/transitRESTful?url=${encodeURIComponent(url)}`;
|
||||
// 中转HTTP请求
|
||||
export const transitRESTful = {
|
||||
get: (url, params?) => defHttp.get({ url: getTransitURL(url), params }, { isTransformResponse: false }),
|
||||
post: (url, params?) => defHttp.post({ url: getTransitURL(url), params }, { isTransformResponse: false }),
|
||||
put: (url, params?) => defHttp.put({ url: getTransitURL(url), params }, { isTransformResponse: false }),
|
||||
};
|
||||
/**
|
||||
* 提交流程
|
||||
* @param params
|
||||
*/
|
||||
export const startProcess = (params) => {
|
||||
return defHttp.post({ url: Api.startProcess, params }, { isTransformResponse: false });
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param params
|
||||
*/
|
||||
export const deleteOne = (params, handleSuccess) => {
|
||||
return defHttp.delete({ url: Api.delete, data: params }, { isTransformResponse: false, joinParamsToUrl: true }).then((res) => {
|
||||
handleSuccess(res);
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 批量删除
|
||||
* @param params
|
||||
*/
|
||||
export const deleteBatch = (params, handleSuccess) => {
|
||||
return defHttp.delete({ url: Api.deleteBatch, data: params }, { isTransformResponse: false, joinParamsToUrl: true }).then((res) => {
|
||||
handleSuccess(res);
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<div :class="['p-4']">
|
||||
<DesignFormDataTable v-if="showListTable" :queryDesformCode="data.desformCode" :customButtonsAuth="data.buttonsAuth">
|
||||
<template #buttonBefore>
|
||||
<span style="color: #060606">请选择工单: </span>
|
||||
<a-select
|
||||
v-model:value="data.desformCode"
|
||||
class="search-input"
|
||||
showSearch
|
||||
:showArrow="false"
|
||||
:options="data.desFormOptions"
|
||||
placeholder="搜索表单"
|
||||
optionFilterProp="text"
|
||||
:filterOption="filterOption"
|
||||
@change="onDesformChange"
|
||||
>
|
||||
</a-select>
|
||||
</template>
|
||||
</DesignFormDataTable>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { initDictOptions } from '/@/utils/dict/index';
|
||||
import { nextTick, reactive, computed } from 'vue';
|
||||
import DesignFormDataTable from './components/DesignFormDataTable.vue';
|
||||
|
||||
const data = reactive({
|
||||
reloading: false,
|
||||
desformCode: '',
|
||||
desFormOptions: [],
|
||||
buttonsAuth: {
|
||||
detail: true,
|
||||
superQuery: true,
|
||||
customColumn: true,
|
||||
},
|
||||
});
|
||||
/*初始化字典*/
|
||||
initDictConfig();
|
||||
/*是否显示列表*/
|
||||
const showListTable = computed(() => {
|
||||
return data.desformCode && !data.reloading;
|
||||
});
|
||||
//初始化字典 - 表单数据
|
||||
async function initDictConfig() {
|
||||
let result = await initDictOptions('design_form,desform_name,desform_code,desform_type=1');
|
||||
if (result) {
|
||||
data.desFormOptions = result;
|
||||
let code = data.desFormOptions[0].value;
|
||||
onDesformChange(code);
|
||||
}
|
||||
}
|
||||
// 刷新表格
|
||||
async function reload() {
|
||||
data.reloading = true;
|
||||
await nextTick();
|
||||
data.reloading = false;
|
||||
await nextTick();
|
||||
}
|
||||
/*表单切换*/
|
||||
function onDesformChange(code) {
|
||||
data.desformCode = code;
|
||||
reload();
|
||||
}
|
||||
/*是否根据输入项进行筛选*/
|
||||
function filterOption(inputValue, option) {
|
||||
return option.text.toLowerCase().indexOf(inputValue.toLowerCase()) >= 0;
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.table-operator .search-input {
|
||||
width: 180px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,161 @@
|
||||
<template>
|
||||
<BasicTable @register="registerTable">
|
||||
<!--操作栏-->
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
<!-- 查看历史 -->
|
||||
<TaskHandleModal @register="registerHistoryModal"></TaskHandleModal>
|
||||
|
||||
<!-- 催办 -->
|
||||
<task-notify-modal @register="registerNotifyModal"></task-notify-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { invalidProcess, backProcess, list } from './task.apply.api';
|
||||
import { BasicTable, TableAction } from '/@/components/Table';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
import { columns, searchFormSchema } from './task.apply.data';
|
||||
import TaskHandleModal from '../myHandleTask/modal/TaskHandleModal.vue';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import { getTaskInfoForHistory } from '../myHandleTask/useTaskList';
|
||||
import TaskNotifyModal from './notify/TaskNotifyModal.vue';
|
||||
import { ref } from 'vue';
|
||||
|
||||
export default {
|
||||
name: 'MyApplyTaskList',
|
||||
components: {
|
||||
BasicTable,
|
||||
TableAction,
|
||||
TaskHandleModal,
|
||||
TaskNotifyModal,
|
||||
},
|
||||
setup() {
|
||||
const { tableContext } = useListPage({
|
||||
designScope: 'my-apply-task-list',
|
||||
pagination: true,
|
||||
tableProps: {
|
||||
api: list,
|
||||
columns: columns,
|
||||
showIndexColumn: true,
|
||||
showTableSetting: true,
|
||||
canResize: false,
|
||||
scroll: { x: 1600 },
|
||||
actionColumn: { dataIndex: 'action', fixed: 'right' },
|
||||
formConfig: {
|
||||
schemas: searchFormSchema,
|
||||
autoAdvancedCol: 4,
|
||||
baseColProps: { xs: 24, sm: 12, md: 6, lg: 6, xl: 6, xxl: 6 },
|
||||
actionColOptions: { xs: 24, sm: 12, md: 6, lg: 6, xl: 6, xxl: 6 },
|
||||
},
|
||||
},
|
||||
});
|
||||
const [registerTable, { reload }] = tableContext;
|
||||
|
||||
const [registerHistoryModal, { openModal: openHistoryModal }] = useModal();
|
||||
|
||||
const [registerNotifyModal, { openModal: openNotifyModal }] = useModal();
|
||||
|
||||
function getTableAction(record) {
|
||||
if (record.endTime && record.endTime != '') {
|
||||
return [
|
||||
{
|
||||
label: '历史',
|
||||
onClick: showHistory.bind(null, record),
|
||||
},
|
||||
];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async function showHistory(record) {
|
||||
let { formData, formUrl } = await getTaskInfoForHistory(record);
|
||||
formData['PROCESS_TAB_TYPE'] = 'history';
|
||||
openHistoryModal(true, {
|
||||
formData,
|
||||
formUrl,
|
||||
title: '流程历史',
|
||||
});
|
||||
}
|
||||
|
||||
function getDropDownAction(record) {
|
||||
if (!record.endTime || record.endTime == '') {
|
||||
let arr = [];
|
||||
if(record.urgeStatus!=='0'){
|
||||
arr.push({
|
||||
label: '催办',
|
||||
onClick: handleTaskNotify.bind(null, record),
|
||||
})
|
||||
}
|
||||
arr.push({
|
||||
label: '作废流程',
|
||||
popConfirm: {
|
||||
title: '确定要作废流程吗?',
|
||||
placement: 'left',
|
||||
confirm: handleInvalidTask.bind(null, record),
|
||||
},
|
||||
});
|
||||
|
||||
if(record.backStatus!=='0'){
|
||||
arr.push({
|
||||
label: '取回流程',
|
||||
popConfirm: {
|
||||
title: '确定要取回流程吗?',
|
||||
placement: 'left',
|
||||
confirm: handleBackTask.bind(null, record),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
arr.push({
|
||||
label: '历史',
|
||||
onClick: showHistory.bind(null, record)
|
||||
});
|
||||
|
||||
return arr;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// 流程作废 NY5LzSY2VW1BSthYSnJArCFqbgwtZqSuyPQ/OD1n1twWJGU2RN/wkzf+kBVO5DztN85Ca9keeuaRAiwcatr8N0M15+Wv2SmRw82lMwawE2naX5tpJMpkxrUhUUcjnC+BSBL4+PV2JUXBFW8/oOG8HLqYvmPxoP7MMBhMi9D7lRY=
|
||||
async function handleInvalidTask(record) {
|
||||
let params = {
|
||||
processInstanceId: record.processInstanceId,
|
||||
};
|
||||
await invalidProcess(params);
|
||||
reload();
|
||||
}
|
||||
|
||||
// 流程取回
|
||||
async function handleBackTask(record) {
|
||||
let params = {
|
||||
processInstanceId: record.processInstanceId,
|
||||
};
|
||||
await backProcess(params);
|
||||
reload();
|
||||
}
|
||||
|
||||
//催办
|
||||
function handleTaskNotify(record) {
|
||||
openNotifyModal(true, {
|
||||
title: '催办提醒',
|
||||
procInstId: record.processInstanceId,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
registerTable,
|
||||
registerHistoryModal,
|
||||
registerNotifyModal,
|
||||
getTableAction,
|
||||
getDropDownAction,
|
||||
reload,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<BasicForm @register="registerForm" />
|
||||
<div style="text-align: center; margin-top: 10px; width: 100%">
|
||||
<a-button type="primary" @click="handleOk()" :loading="loading">保存</a-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 展示催办表单
|
||||
*/
|
||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||
import { taskNotification } from '../task.apply.api';
|
||||
import {ref} from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'NotifyForm',
|
||||
props: {
|
||||
procInstId: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
emits: ['ok'],
|
||||
components: {
|
||||
BasicForm,
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const formSchema = [
|
||||
{
|
||||
field: 'notifyType',
|
||||
label: '催办类型',
|
||||
component: 'JCheckbox',
|
||||
defaultValue: '1,2',
|
||||
componentProps: {
|
||||
options: [
|
||||
{ value: '1', label: '系统通知' },
|
||||
{ value: '2', label: '邮件' },
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'remarks',
|
||||
label: '催办内容',
|
||||
component: 'InputTextArea',
|
||||
required: true,
|
||||
componentProps: {
|
||||
placeholder: '请输入催办内容',
|
||||
rows: 3,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
//表单配置
|
||||
const [registerForm, { resetFields, setFieldsValue, validate, updateSchema, getFieldsValue }] = useForm({
|
||||
schemas: formSchema,
|
||||
showActionButtonGroup: false,
|
||||
showSubmitButton: true,
|
||||
baseColProps: { span: 24 },
|
||||
});
|
||||
|
||||
const loading = ref(false)
|
||||
async function handleOk() {
|
||||
try {
|
||||
loading.value = true
|
||||
let formData = await validate();
|
||||
let params = {
|
||||
...formData,
|
||||
procInstId: props.procInstId,
|
||||
};
|
||||
await taskNotification(params);
|
||||
emit('ok');
|
||||
setTimeout(()=>{
|
||||
loading.value = false
|
||||
}, 200)
|
||||
}catch (e) {
|
||||
console.log('催办出错',e)
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
registerForm,
|
||||
handleOk,
|
||||
loading
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<BasicTable @register="registerTable" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 展示指定任务的催办列表
|
||||
*/
|
||||
import { BasicTable } from '/@/components/Table';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
import { taskNotifyList } from '../task.apply.api';
|
||||
import { notifyColumns } from '../task.apply.data';
|
||||
|
||||
export default {
|
||||
name: 'NotifyList',
|
||||
components: {
|
||||
BasicTable,
|
||||
},
|
||||
props: {
|
||||
procInstId: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { tableContext } = useListPage({
|
||||
designScope: 'notify-list',
|
||||
pagination: true,
|
||||
tableProps: {
|
||||
api: taskNotifyList,
|
||||
columns: notifyColumns,
|
||||
showIndexColumn: true,
|
||||
showTableSetting: false,
|
||||
useSearchForm: false,
|
||||
canResize: false,
|
||||
showActionColumn: false,
|
||||
beforeFetch: (params) => {
|
||||
return addQueryParams(params);
|
||||
},
|
||||
},
|
||||
});
|
||||
const [registerTable] = tableContext;
|
||||
|
||||
function addQueryParams(params) {
|
||||
params['procInstId'] = props.procInstId;
|
||||
return params;
|
||||
}
|
||||
|
||||
return {
|
||||
registerTable,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<BasicModal :title="title" width="60%" destroyOnClose :bodyStyle="bodyStyle" :footer="null" @register="registerModal">
|
||||
<a-tabs defaultActiveKey="1" tabPosition="top">
|
||||
<a-tab-pane key="1">
|
||||
<template #tab> <file-text-outlined /><span>催办</span> </template>
|
||||
<notify-form :procInstId="procInstId" @ok="notifyOk"></notify-form>
|
||||
<!--<ext-act-task-notification-modal ref="extActTaskNotificationModal" :procInstId="procInstId" @ok="handleOk"></ext-act-task-notification-modal>-->
|
||||
<p></p>
|
||||
</a-tab-pane>
|
||||
|
||||
<a-tab-pane key="2">
|
||||
<template #tab> <user-outlined /><span>我提醒的</span> </template>
|
||||
<notify-list :procInstId="procInstId"></notify-list>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import NotifyForm from './NotifyForm.vue';
|
||||
import NotifyList from './NotifyList.vue';
|
||||
import { UserOutlined, FileTextOutlined } from '@ant-design/icons-vue';
|
||||
import { ref } from 'vue';
|
||||
|
||||
export default {
|
||||
name: 'TaskNotifyModal',
|
||||
emits: ['register'],
|
||||
components: {
|
||||
BasicModal,
|
||||
NotifyForm,
|
||||
NotifyList,
|
||||
UserOutlined,
|
||||
FileTextOutlined,
|
||||
},
|
||||
setup(_p, { emit }) {
|
||||
const title = ref('');
|
||||
const bodyStyle = {
|
||||
padding: '0 5px',
|
||||
'overflow-y': 'auto',
|
||||
};
|
||||
const procInstId = ref('');
|
||||
|
||||
//useModalInner
|
||||
const [registerModal, { closeModal }] = useModalInner((data) => {
|
||||
console.log('data', data);
|
||||
title.value = data.title;
|
||||
procInstId.value = data.procInstId;
|
||||
});
|
||||
|
||||
function notifyOk() {
|
||||
//emit('success')
|
||||
closeModal();
|
||||
}
|
||||
|
||||
return {
|
||||
title,
|
||||
registerModal,
|
||||
bodyStyle,
|
||||
procInstId,
|
||||
notifyOk,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,39 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
|
||||
enum Api {
|
||||
list = '/act/task/myApplyProcessList',
|
||||
invalidProcess = '/act/task/invalidProcess',
|
||||
backProcess = '/act/task/callBackProcess',
|
||||
taskNotification = '/act/process/extActTaskNotification/taskNotification',
|
||||
notifyList = '/act/process/extActTaskNotification/mylist',
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表
|
||||
* @param params
|
||||
*/
|
||||
export const list = (params) => defHttp.get({ url: Api.list, params });
|
||||
|
||||
/**
|
||||
* 作废
|
||||
* @param params
|
||||
*/
|
||||
export const invalidProcess = (params) => defHttp.put({ url: Api.invalidProcess, params });
|
||||
|
||||
/**
|
||||
* 取回
|
||||
* @param params
|
||||
*/
|
||||
export const backProcess = (params) => defHttp.put({ url: Api.backProcess, params });
|
||||
|
||||
/**
|
||||
* 催办
|
||||
* @param params
|
||||
*/
|
||||
export const taskNotification = (params) => defHttp.post({ url: Api.taskNotification, params });
|
||||
|
||||
/**
|
||||
* 列表查询
|
||||
* @param params
|
||||
*/
|
||||
export const taskNotifyList = (params) => defHttp.get({ url: Api.notifyList, params });
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user