合同立项功能整个流程测试结束

This commit is contained in:
z9130 2024-10-14 19:22:15 +08:00
parent d7a34c3c46
commit 0202f0e524
4 changed files with 446 additions and 92 deletions

View File

@ -323,7 +323,6 @@ const routes: RouteRecordRaw[] = [
title: '履行提示',
},
},
{
name: 'ContractPerformResult',
path: '/contract/perform/result',
@ -333,6 +332,16 @@ const routes: RouteRecordRaw[] = [
title: '履行结果填报',
},
},
{
name: 'ContractPerformResultList',
path: '/contract/perform/resultList',
component: () =>
import('#/views/contract/perform/result-list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '履行结果编制',
},
},
{
name: 'ContractPerformTemporaryArchive',
path: '/contract/perform/temporary-archive',

View File

@ -19,6 +19,7 @@ import chooseUserModal from '#/views/system/user/choose-user-modal.vue';
import chooseSigningBasisModal from '../signing-basis/choose-signing-basis-modal.vue';
import { getColumns } from '../signing-basis/columns';
import { getFormSchema } from './curd';
import AuditNodeTable from '#/views/contract/components/audit-node-table/audit-node-table.vue';
const { xGridRef, gridProps } = useVxeTable({ ref: 'xGridRef' });
@ -86,7 +87,7 @@ const gridOptions = reactive(
}),
);
const collapses = ['1', '2'];
const collapses = ['1', '2', '3'];
const collapseActiveKey = ref(collapses);
function areArraysEqualUnordered(arr1, arr2) {
if (arr1.length !== arr2.length) return false;
@ -115,7 +116,7 @@ function handleBack() {
* 页面返回并关闭tab
*/
function back() {
router.replace('/contract/approval/list');
router.replace('/contract/approval/todo');
}
function handleOpenSignBasisChooseModal() {
@ -189,38 +190,62 @@ async function handleAbolish(type: 'openModal' | 'confirm') {
}
async function handleAbolishAudit(
type: 'accessConfirm' | 'reject' | 'rejectConfirm',
type: 'access' | 'accessConfirm' | 'reject' | 'rejectConfirm',
data?: any,
) {
console.log(type);
if (type === 'accessConfirm') {
if (type === 'access') {
Modal.confirm({
title: '提示',
content: '是否确认立项废除审核通过?',
onOk: async () => {
try {
await Apis.contractBaseInfo.post_abolishSubmit({
params: {
guid: id.value,
onOk: () => {
temporaryFormModalApi.setData({
title: '备注信息',
schema: {
columns: {
comment: {
title: '',
key: 'comment',
col: { span: 24 },
colon: false,
component: {
name: 'a-textarea',
vModel: 'value',
autoSize: { minRows: 4, maxRows: 6 },
placeholder: '请输入',
},
rules: [{ required: true, message: '请输入退回原因' }],
},
},
data: {
// appId: id.value,
taskId: taskId,
nodeId: '',
comment: '通过',
},
});
message.success('审核通过');
back();
} catch (error) {
logger.error('审核通过失败', error);
message.error('审核通过失败,请稍候再试');
}
},
});
temporaryFormModalApi.open();
},
});
}
if (type === 'accessConfirm') {
try {
await Apis.contractBaseInfo.post_abolishSubmit({
params: {
guid: id.value,
},
data: {
// appId: id.value,
taskId: taskId,
nodeId: '',
comment: '通过',
},
});
message.success('审核通过');
back();
} catch (error) {
logger.error('审核通过失败', error);
message.error('审核通过失败,请稍候再试');
}
}
if (type === 'reject') {
Modal.confirm({
title: '提示',
@ -406,7 +431,7 @@ async function handleSave() {
handleSubmit();
},
onCancel: () => {
back();
// back();
},
});
} catch (error) {
@ -427,74 +452,94 @@ async function handleSubmit() {
chooseUserModalApi.open();
}
let auditType = ref('');
const isTemporaryFormModalLoading = ref(false);
async function handleAudit(
type: 'accessConfirm' | 'reject' | 'rejectConfirm',
type: 'openAccessModal' | 'openRejectModal' | 'confirm',
data?: any,
) {
console.log(type);
if (type === 'accessConfirm') {
if (currAuditType.value === 'abolish') {
await handleAbolish('confirm');
return;
}
Modal.confirm({
title: '提示',
content: '是否确认审核通过?',
onOk: async () => {
try {
await Apis.contractBaseInfo.post_submit({
params: {
guid: id.value,
},
data: {
appId: id.value,
taskId: taskId,
nodeId: '',
comment: '通过',
},
});
message.success('审核通过');
back();
} catch (error) {
logger.error('审核通过失败', error);
message.error('审核通过失败,请稍候再试');
}
},
});
}
if (type === 'reject') {
Modal.confirm({
title: '提示',
content: '是否确认退回?',
onOk: () => {
temporaryFormModalApi.setData({
title: '退回原因',
schema: {
columns: {
comment: {
title: '',
key: 'comment',
col: { span: 24 },
colon: false,
component: {
name: 'a-textarea',
vModel: 'value',
autoSize: { minRows: 4, maxRows: 6 },
placeholder: '请输入',
},
rules: [{ required: true, message: '请输入退回原因' }],
},
if (type === 'openAccessModal') {
auditType.value = 'access';
temporaryFormModalApi.setData({
title: '审核通过备注',
schema: {
columns: {
comment: {
title: '',
key: 'comment',
col: { span: 24 },
colon: false,
component: {
name: 'a-textarea',
vModel: 'value',
autoSize: { minRows: 4, maxRows: 6 },
placeholder: '请输入',
},
},
});
temporaryFormModalApi.open();
},
},
});
temporaryFormModalApi.open();
}
if (type === 'rejectConfirm') {
if (type === 'confirm' && auditType.value === 'access') {
isTemporaryFormModalLoading.value = true;
const comment = data.comment;
try {
await Apis.contractBaseInfo.post_submit({
params: {
guid: id.value,
},
data: {
appId: id.value,
taskId: taskId,
nodeId: '',
comment: comment || '',
},
});
message.success('审核通过');
back();
} catch (error) {
logger.error('审核通过失败', error);
message.error('审核通过失败,请稍候再试');
} finally {
isTemporaryFormModalLoading.value = false;
}
}
if (type === 'openRejectModal') {
auditType.value = 'reject';
temporaryFormModalApi.setData({
title: '审核退回原因',
schema: {
columns: {
comment: {
title: '',
key: 'comment',
col: { span: 24 },
colon: false,
component: {
name: 'a-textarea',
vModel: 'value',
autoSize: { minRows: 4, maxRows: 6 },
placeholder: '请输入',
},
rules: [{ required: true, message: '请输入退回原因' }],
},
},
},
});
temporaryFormModalApi.open();
}
if (type === 'confirm' && auditType.value === 'reject') {
isTemporaryFormModalLoading.value = true;
const comment = data.comment;
try {
await Apis.contractBaseInfo.post_rollback({
@ -514,6 +559,8 @@ async function handleAudit(
} catch (error) {
logger.error('合同立项退回失败', error);
message.error('退回失败,请稍候再试');
} finally {
isTemporaryFormModalLoading.value = false;
}
}
}
@ -537,12 +584,12 @@ onMounted(async () => {
formBinding.value.columns = getFormSchema({
contractTypeData: contractTypeData.value,
readOnly: !id.value || currData.value.step !== 'edit',
readOnly: !id.value || currData.value.step !== 'paEdit',
});
xGridRef.value!.reloadColumn(
getColumns({
readOnly: !id.value || currData.value.step !== 'edit',
readOnly: !id.value || currData.value.step !== 'paEdit',
}),
);
@ -600,8 +647,9 @@ onMounted(async () => {
<ChooseSigningBasisModal class="w-[950px]" @confirm="handleChooseConfirm" />
<TemporaryFormModal
class="w-[950px]"
@confirm="handleAudit('rejectConfirm', $event)"
v-model:loading="isTemporaryFormModalLoading"
class="w-[700px]"
@confirm="handleAudit('confirm', $event)"
/>
<!-- {{ currData.step }} -->
@ -609,7 +657,7 @@ onMounted(async () => {
<div class="flex w-full flex-row bg-white pl-1 pt-1">
<a-space class="flex-1">
<vben-button
v-if="!id || ['paEdit'].includes(currData.step)"
v-if="!id || ['paEdit'].includes(currData.step) || !taskId"
variant="primary"
@click="handleSave()"
>
@ -627,7 +675,7 @@ onMounted(async () => {
v-if="['paDepartmentAudit'].includes(currData.step) && taskId"
:disabled="!auditId"
variant="primary"
@click="handleAudit('accessConfirm')"
@click="handleAudit('openAccessModal')"
>
通过
</vben-button>
@ -635,7 +683,7 @@ onMounted(async () => {
v-if="['paDepartmentAudit'].includes(currData.step) && taskId"
:disabled="!auditId"
variant="destructive"
@click="handleAudit('reject')"
@click="handleAudit('openRejectModal')"
>
退回
</vben-button>
@ -658,16 +706,16 @@ onMounted(async () => {
删除
</vben-button>
<vben-button
<!-- <vben-button
v-if="['abolishDepartmentAudit'].includes(currData.step) && taskId"
:disabled="!auditId"
variant="warning"
@click="handleAbolishAudit('accessConfirm')"
>
废除通过
</vben-button>
</vben-button> -->
<vben-button
<!-- <vben-button
v-if="['abolishDepartmentAudit'].includes(currData.step) && taskId"
:disabled="!auditId"
variant="destructive"
@ -683,7 +731,7 @@ onMounted(async () => {
@click="handleAudit('accessConfirm')"
>
通过
</vben-button>
</vben-button> -->
<vben-button variant="secondary" @click="handleBack()"> 返回 </vben-button>
</a-space>
@ -745,6 +793,15 @@ onMounted(async () => {
</template>
</VxeGrid>
</a-collapse-panel>
<a-collapse-panel
v-if="currData.flowInstanceId"
key="3"
class="w-full"
header="审批信息"
>
<AuditNodeTable :flow-instance-id="currData.flowInstanceId" />
</a-collapse-panel>
</a-collapse>
</div>
</a-spin>

View File

@ -0,0 +1,109 @@
import type { VxeGridPropTypes } from 'vxe-table';
import { useRender } from '#/hooks/useRender';
import dayjs from 'dayjs';
import { DICT_TYPE, getDictOptions } from '#/utils/dict';
import { dict } from '@fast-crud/fast-crud';
import { unitComponentProps } from '#/common/unit';
export const PrimaryKey = 'guid';
export function getColumns(params: any = {}): VxeGridPropTypes.Columns {
return [
{
type: 'radio',
width: 40,
slots: { radio: 'radio_cell' },
align: 'center',
fixed: 'left',
},
{
field: 'step',
title: '节点状态',
width: 130,
slots: {
default: ({ row }) => {
return useRender.renderDict(
row.step,
DICT_TYPE.contract_business_flow_node,
);
},
},
},
{ field: 'reportNo', title: '报审序号', width: 100 },
{
field: 'contractName',
title: '合同名称',
minWidth: 200,
slots: {
default: 'contract-name-slot',
},
},
{ field: 'choiceTypeName', title: '选商方式', width: 150 },
{ field: 'fundDitchName', title: '资金渠道', width: 150 },
{ field: 'contractMoney', title: '金额', width: 100 },
{ field: 'priceTypeName', title: '币种', width: 100 },
{ field: 'inputPerson', title: '承办人', width: 100 },
{ field: 'inputDepartName', title: '承办部门', width: 100 },
{ field: 'inputDate', title: '承办时间', width: 130 },
{
field: 'operate',
title: '操作',
width: 60,
fixed: 'right',
slots: { default: 'operate' },
},
];
}
export function getFormSchema(_params: any = {}) {
return {
initialForm: {},
columns: {
contractName: {
title: '合同名称',
key: 'contractName',
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
},
autoSearchTrigger: 'enter',
show: true,
},
inputDepartId: {
title: '承办单位',
key: 'inputUnitId',
component: unitComponentProps,
autoSearchTrigger: 'enter',
show: true,
},
contractMoney: {
title: '合同金额',
key: 'contractMoney',
component: {
name: 'a-input-number',
vModel: 'value',
min: 0,
allowClear: true,
},
autoSearchTrigger: 'enter',
show: true,
},
choiceType: {
title: '选商方式',
key: 'choiceType',
component: {
name: 'fs-dict-select',
vModel: 'value',
class: 'min-w-[180px]',
allowClear: true,
dict: dict({
data: getDictOptions(DICT_TYPE.contract_selection_method),
}),
},
autoSearchTrigger: 'enter',
show: true,
},
},
};
}

View File

@ -0,0 +1,179 @@
<script setup lang="ts">
import { computed, onMounted, reactive, ref } from "vue";
import { useRouter } from "vue-router";
import { Page } from "@vben/common-ui";
import { MdiExport, MdiRadioChecked, MdiRadioUnchecked, MdiUpdate } from "@vben/icons";
import { message } from "ant-design-vue";
import Apis from "#/api";
import { useVxeTable } from "#/hooks/vxeTable";
import { toDetailPage } from "#/views/contract/utils.ts";
import { getColumns, getFormSchema, PrimaryKey } from "./crud.tsx";
const router = useRouter();
const searchRef = ref();
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: "xGridRef" });
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
columns: getColumns(),
proxyConfig: {
autoLoad: false,
ajax: {
query: async ({ page }) => {
const data = await Apis.selectMerchantsBasicInfo.get_page({
params: {
pageNum: page.currentPage,
pageSize: page.pageSize,
...searchRef.value?.formData,
},
});
return data;
},
},
},
pagerConfig: {
enabled: true,
},
toolbarConfig: {
enabled: true,
},
})
);
function handleEdit(record?: any) {
if (["end"].includes(record.step)) {
router.push(
`/contract/business/result/${record[PrimaryKey]}?flowInstanceId=${record.flowInstanceId}`
);
} else {
router.push(`/contract/business/edit/${record[PrimaryKey]}`);
}
}
function handleExport() {
const $grid = xGridRef.value;
if ($grid) {
$grid.exportData({
type: "xlsx",
columnFilterMethod: ({ column }) => {
if (["operate", "step"].includes(column.field)) {
return false;
}
if (column.type === "radio") {
return false;
}
return true;
},
});
message.success("导出成功");
}
}
/** 选中数据 */
const selectRow: any = computed(() => {
return xGridRef.value?.getRadioRecord() || null;
});
/** 单选框选中事件 */
const setSelectRow = (row: any) => {
if (selectRow.value && selectRow.value[PrimaryKey] === row[PrimaryKey]) {
xGridRef.value?.clearRadioRow();
} else {
xGridRef.value?.setRadioRow(row);
}
};
/** 表格单元格单击事件 */
function handleCellClick({ row }) {
setSelectRow(row);
}
onMounted(() => {
triggerProxy("reload");
});
const searchForm = ref({
...getFormSchema(),
onSearch(_context: any) {
triggerProxy("reload");
},
});
</script>
<template>
<Page content-class="h-full flex flex-col">
<fs-search ref="searchRef" v-bind="searchForm">
<template #form_price="{ row }">
<a-input-number v-model:value="row.budgetSum1" placeholder="" />
<span class="mx-1"></span>
<a-input-number v-model:value="row.budgetSum2" placeholder="" />
</template>
<template #form_time="{ row }">
<a-date-picker
v-model:value="row.startTime"
format="YYYY-MM-DD"
placeholder=""
value-format="YYYY-MM-DD"
/>
<span class="mx-1"></span>
<a-date-picker
v-model:value="row.endTime"
format="YYYY-MM-DD"
placeholder=""
value-format="YYYY-MM-DD"
/>
</template>
</fs-search>
<div class="min-h-300px flex-1">
<vxe-grid ref="xGridRef" v-bind="gridOptions" @cell-click="handleCellClick">
<template #toolbar_buttons>
<a-space>
<vben-button
:disabled="!selectRow || !selectRow[PrimaryKey]"
variant="warning"
@click="handleEdit(selectRow)"
>
<MdiUpdate class="mr-0.5 text-lg" />
信息维护
</vben-button>
<vben-button variant="primary" @click="handleExport()">
<MdiExport class="mr-0.5 text-lg" />
导出
</vben-button>
</a-space>
</template>
<template #radio_cell="{ row, checked }">
<span class="text-base" @click.stop="setSelectRow(row)">
<MdiRadioChecked v-if="checked" />
<MdiRadioUnchecked v-else />
</span>
</template>
<template #contract-name-slot="{ row }">
<span class=""> {{ row.contractName }}</span>
</template>
<template #operate="{ row }">
<a-button
size="small"
type="primary"
@click="toDetailPage('business', row.guid, row)"
>
查看
</a-button>
</template>
</vxe-grid>
</div>
</Page>
</template>
<style></style>