This commit is contained in:
z9130 2024-10-23 19:13:15 +08:00
commit 21993e7c73
35 changed files with 1524 additions and 650 deletions

View File

@ -547,6 +547,15 @@ export default {
/** 合同系统/履行/履行提示/合同变更 获取合同变更信息 */
get_getContractChangeInfo: (data?: QueryOptions) =>
http.get('/app/lvxChange/getContractChangeInfo', data),
/** 合同系统/履行/履行提示/合同变更 查询流程未配置人员节点 */
get_getFlowNodeUserConfig: (data?: QueryOptions) =>
http.get('/app/lvxChange/getFlowNodeUserConfig', data),
/** 合同系统/履行/履行提示/合同变更 流程启动 */
post_startWorkFlow: (data?: BodyOptions) =>
http.post('/app/lvxChange/startWorkFlow', data),
/** 合同系统/履行/履行提示/合同变更 审核通过 */
post_submit: (data?: BodyOptions) =>
http.post('/app/lvxChange/submit', data),
},
contractRelieve: {
/** 合同系统/履行/履行提示/合同解除 获取合同解除信息 */
@ -579,6 +588,11 @@ export default {
lvxResult: {
/** 合同系统/履行/履行结果 履行结果保存 */
post_save: (data?: BodyOptions) => http.post('/app/lvxResult/save', data),
/** 合同系统/履行/履行结果 分页履行结果查询 */
get_page: (data?: QueryOptions) => http.get('/app/lvxResult/page', data),
/** 合同系统/履行/履行结果 已办 */
get_pageDone: (data?: QueryOptions) =>
http.get('/app/lvxResult/pageDone', data),
},
contractFiling: {
/** 合同系统/履行/履行提示/临时归档 保存临时归档信息 */
@ -641,7 +655,7 @@ export default {
/** 合同系统/签订 获取合同签订信息 */
get_getContractSignInfo: (data?: QueryOptions) =>
http.get('/app/qdSign/getContractSignInfo', data),
/** 合同系统/签订 打印签订审批表 */
/** 合同系统/打印 选商打印 */
get_printApprove: (data?: QueryOptions) =>
http.get('/app/qdSign/printApprove', data),
/** 合同系统/签订 打印文本 */
@ -806,6 +820,15 @@ export default {
/** 合同系统/选商/选商结果 待审核 */
get_toDoPage: (data?: QueryOptions) =>
http.get('/app/biddingResult/toDoPage', data),
/** 合同系统/选商/选商结果 查询合同信息 */
get_getContractInfo: (data?: QueryOptions) =>
http.get('/app/biddingResult/getContractInfo', data),
/** 合同系统/选商/选商结果 查询供应商列表 */
get_getProviderInfo: (data?: QueryOptions) =>
http.get('/app/biddingResult/getProviderInfo', data),
/** 合同系统/选商/选商结果 选商专家列表 */
get_queryBiddingExpert: (data?: QueryOptions) =>
http.get('/app/biddingResult/queryBiddingExpert', data),
},
home: {
/** 合同系统/首页待办/已办 首页待办 */
@ -859,8 +882,8 @@ export default {
/** 设备管理/设备静态库管理/设备调拨 调拨信息保存 */
post_save: (data?: BodyOptions) => http.post('/app/equAllot/save', data),
/** 设备管理/设备静态库管理/设备调拨 调拨信息删除 */
post_delete: (data?: BodyOptions) =>
http.post('/app/equAllot/delete', data),
post_deletes: (data?: BodyOptions) =>
http.post('/app/equAllot/deletes', data),
},
bidding: {
/** 合同系统/标段信息 标段查询 */
@ -870,6 +893,9 @@ export default {
/** 合同系统/标段信息 标段信息删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/bidding/deletes', data),
/** 合同系统/选商/选商结果 查询标段列表 */
get_getBuddingPtInfoList: (data?: QueryOptions) =>
http.get('/app/bidding/getBuddingPtInfoList', data),
},
equAccident: {
/** 设备管理/设备使用管理/事故处理 事故处理(查询/获取) */
@ -915,8 +941,8 @@ export default {
post_save: (data?: BodyOptions) =>
http.post('/app/equDayRepair/save', data),
/** 设备管理/设备使用管理/日常维修 删除 */
get_deletes: (data?: QueryOptions) =>
http.get('/app/equDayRepair/deletes', data),
post_deletes: (data?: BodyOptions) =>
http.post('/app/equDayRepair/deletes', data),
/** 设备管理/查询管理/日常维修查询 查询 */
get_query: (data?: QueryOptions) =>
http.get('/app/equDayRepair/query', data),

View File

@ -121,27 +121,27 @@ function handleMenuClick(e) {
}
onMounted(async () => {
const data = await Apis.home.get_todo({
params: { pageNum: 1, pageSize: 20 },
});
// const data = await Apis.home.get_todo({
// params: { pageNum: 1, pageSize: 20 },
// });
notifications.value = data.rows.map((item) => {
let module =
getDictObj(DICT_TYPE.contract_todo_type, item.module)?.label || '';
module = module.slice(-4);
let moduleTextArr = [...module];
moduleTextArr =
moduleTextArr.length <= 3 ? moduleTextArr : moduleTextArr.slice(-4);
return {
moduleTextArr,
avatar: '',
date: item.createTime,
isRead: true,
message: item.contractName,
title: item.taskName,
};
});
console.log(notifications);
// notifications.value = data.rows.map((item) => {
// let module =
// getDictObj(DICT_TYPE.contract_todo_type, item.module)?.label || '';
// module = module.slice(-4);
// let moduleTextArr = [...module];
// moduleTextArr =
// moduleTextArr.length <= 3 ? moduleTextArr : moduleTextArr.slice(-4);
// return {
// moduleTextArr,
// avatar: '',
// date: item.createTime,
// isRead: true,
// message: item.contractName,
// title: item.taskName,
// };
// });
// console.log(notifications);
// resetAllStores();
});
</script>
@ -172,13 +172,13 @@ onMounted(async () => {
<a-button> {{ value ? `代理${value}` : '代理切换' }} </a-button>
</a-dropdown>
<Notification
<!-- <Notification
:dot="showDot"
:notifications="notifications"
@clear="handleNoticeClear"
@make-all="handleMakeAll"
@view-all="handleViewAll"
/>
/> -->
</template>
<template #extra>
<AuthenticationLoginExpiredModal

View File

@ -57,5 +57,5 @@ export enum DICT_TYPE {
/** 合同授权期限 */
contract_authorization_period = 'contract_authorization_period',
/** 合同待办类型 */
contract_todo_type = 'contract_todo_type',
contract_todo_type = 'contract_todo_type'
}

View File

@ -71,9 +71,12 @@ export default {
contract_approval_flow_node: createEntry('合同立项节点流程', [
{ label: '开始节点', value: 'paStart' },
{ label: '编制', value: 'paEdit' },
{ label: '待部门自审', value: 'paDepartmentAudit' },
{ label: '立项编制', value: 'paEdit' },
{ label: '立项审批中', value: 'paApproval' },
{ label: '选商编制', value: 'smEdit' },
{ label: '选商审批中', value: 'smApproval' },
{ label: '选商结果编制', value: 'smrEdit' },
{ label: '结束', value: 'end' },
]),
contract_business_flow_node: createEntry('合同选商节点流程', [
@ -86,6 +89,7 @@ export default {
{ label: '待主管领导审批', value: 'smManager' },
{ label: '待公司领导审核', value: 'smLeaders' },
{ label: '选商结果填报', value: 'smrEdit' },
{ label: '结束', value: 'end' },
]),
contract_abolish_flow_node: createEntry('合同立项节点流程', [

View File

@ -14,12 +14,12 @@ import temporaryFormModal from '#/components/temporary-form-modal/temporary-form
import { useVxeTable } from '#/hooks/vxeTable';
import { DICT_TYPE, getDictObj } from '#/utils/dict';
import { FileUploader } from '#/utils/file';
import AuditNodeTable from '#/views/contract/components/audit-node-table/audit-node-table.vue';
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' });
@ -156,7 +156,7 @@ const currAuditType = ref<'abolish' | 'audit'>('audit');
const userListByAbolish = ref([]);
async function handleAbolish(type: 'openModal' | 'confirm') {
async function handleAbolish(type: 'confirm' | 'openModal') {
userModalOpenType.value = 'abolish';
if (type === 'openModal') {
Modal.confirm({
@ -177,7 +177,7 @@ async function handleAbolish(type: 'openModal' | 'confirm') {
try {
await Apis.contractBaseInfo.post_abolishFlowStart({
data: {
guid: currData.value['guid'],
guid: currData.value.guid,
assigneeList: userListByAbolish.value.map((item) => item.ACCOUNT_ID),
},
});
@ -233,7 +233,7 @@ async function handleAbolishAudit(
},
data: {
// appId: id.value,
taskId: taskId,
taskId,
nodeId: '',
comment: '通过',
},
@ -285,7 +285,7 @@ async function handleAbolishAudit(
},
data: {
appId: id.value,
taskId: taskId,
taskId,
nodeId: '',
comment,
},
@ -443,6 +443,12 @@ async function handleSave() {
}
async function handleSubmit() {
// flowinstanceid ,退
if (currData.value.flowInstanceId) {
auditType.value = 'access';
handleAudit('confirm');
return;
}
userModalOpenType.value = 'audit';
// isLoading.value = true
chooseUserModalApi.setData({
@ -456,7 +462,7 @@ let auditType = ref('');
const isTemporaryFormModalLoading = ref(false);
async function handleAudit(
type: 'openAccessModal' | 'openRejectModal' | 'confirm',
type: 'confirm' | 'openAccessModal' | 'openRejectModal',
data?: any,
) {
console.log(type);
@ -496,12 +502,13 @@ async function handleAudit(
},
data: {
appId: id.value,
taskId: taskId,
taskId,
nodeId: '',
comment: comment || '',
},
});
message.success('审核通过');
temporaryFormModalApi.close();
back();
} catch (error) {
logger.error('审核通过失败', error);
@ -548,7 +555,7 @@ async function handleAudit(
},
data: {
appId: id.value,
taskId: taskId,
taskId,
nodeId: '',
comment,
},
@ -642,7 +649,11 @@ onMounted(async () => {
<template>
<Page ref="pageRef" content-class="h-full flex flex-col">
<ChooseUserModal class="w-[950px]" multiple @confirm="handleChooseUserConfirm" />
<ChooseUserModal
class="w-[950px]"
multiple
@confirm="handleChooseUserConfirm"
/>
<ChooseSigningBasisModal class="w-[950px]" @confirm="handleChooseConfirm" />
@ -653,7 +664,11 @@ onMounted(async () => {
/>
<!-- {{ currData.step }} -->
<a-affix :offset-top="0" :style="{ zIndex: 50 }" :target="() => pageRef.bodyRef">
<a-affix
:offset-top="0"
:style="{ zIndex: 50 }"
:target="() => pageRef.bodyRef"
>
<div class="flex w-full flex-row bg-white pl-1 pt-1">
<a-space class="flex-1">
<vben-button
@ -671,8 +686,9 @@ onMounted(async () => {
>
提交
</vben-button>
<vben-button
v-if="['paDepartmentAudit'].includes(currData.step) && taskId"
v-if="['paApproval'].includes(currData.step) && taskId"
:disabled="!auditId"
variant="primary"
@click="handleAudit('openAccessModal')"
@ -680,7 +696,7 @@ onMounted(async () => {
通过
</vben-button>
<vben-button
v-if="['paDepartmentAudit'].includes(currData.step) && taskId"
v-if="['paApproval'].includes(currData.step) && taskId"
:disabled="!auditId"
variant="destructive"
@click="handleAudit('openRejectModal')"
@ -732,11 +748,13 @@ onMounted(async () => {
>
通过
</vben-button> -->
<vben-button variant="secondary" @click="handleBack()"> 返回 </vben-button>
<vben-button variant="secondary" @click="handleBack()">
返回
</vben-button>
</a-space>
<vben-button variant="secondary" @click="handleFold()">
一键{{ isFold ? "展开" : "收起" }}
一键{{ isFold ? '展开' : '收起' }}
</vben-button>
</div>
</a-affix>

View File

@ -1,23 +1,24 @@
<script setup lang="tsx">
import {
ref,
reactive,
watch,
onMounted,
computed,
defineEmits,
defineExpose,
withDefaults,
defineProps,
computed,
onMounted,
reactive,
ref,
watch,
withDefaults,
} from 'vue';
import Apis from '#/api'; // Apis
import { filterContractTypes } from '#/views/contract/utils'; // utils
import type { UploadChangeParam } from 'ant-design-vue';
import { DICT_TYPE, getDictDatasAsync } from '#/utils/dict';
import { MdiUpload } from '@vben/icons';
import { FileUploader } from '#/utils/file';
const emit = defineEmits(['update:form', 'field-change']);
import { MdiUpload } from '@vben/icons';
import { DICT_TYPE, getDictDatasAsync } from '#/utils/dict';
import { FileUploader } from '#/utils/file';
const props = withDefaults(
defineProps<{
@ -28,6 +29,8 @@ const props = withDefaults(
},
);
const emit = defineEmits(['update:form', 'field-change']);
const fileUploader = new FileUploader({});
const formRef = ref();
@ -41,16 +44,9 @@ watch(
{ deep: true, immediate: true },
);
// const readOnly = computed(() => {
// return [
// 'smDepartmentAudit',
// 'smPlanningDepartment',
// 'smFinancialDepartment',
// 'smRegulationDepartment',
// 'smManager',
// 'smLeaders',
// ].includes(form.step);
// });
const readOnly = computed(() => {
return ['smApproval'].includes(form.businessStep);
});
watch(
() => props.form.fileUuid,
@ -70,7 +66,6 @@ watch(
() => form,
(newForm) => {
emit('update:form', newForm);
emit('field-change', newForm);
},
{ deep: true },
);
@ -132,21 +127,21 @@ defineExpose({ validate, submit });
<template>
<a-form
:model="form"
:rules="rules"
ref="formRef"
:label-col="{ style: { width: '120px' } }"
:model="form"
:rules="rules"
>
<a-row :gutter="16">
<a-col :span="16">
<a-form-item label="合同名称" name="contractName">
<a-input v-model:value="form.contractName" />
<a-input v-model:value="form.contractName" :disabled="readOnly" />
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="报审序号" name="reportNo">
<a-input v-model:value="form.reportNo" disabled />
<a-input v-model:value="form.reportNo" :disabled="readOnly" />
</a-form-item>
</a-col>
@ -154,8 +149,9 @@ defineExpose({ validate, submit });
<a-form-item label="合同类别" name="ctrType">
<a-select
v-model:value="form.ctrType"
class="min-w-[200px]"
:disabled="readOnly"
:options="filteredContractTypes('-1')"
class="min-w-[200px]"
/>
</a-form-item>
</a-col>
@ -164,8 +160,9 @@ defineExpose({ validate, submit });
<a-form-item label="二级类别" name="ctrTwoType">
<a-select
v-model:value="form.ctrTwoType"
class="min-w-[200px]"
:disabled="readOnly"
:options="filteredContractTypes(form.ctrType)"
class="min-w-[200px]"
/>
</a-form-item>
</a-col>
@ -181,18 +178,20 @@ defineExpose({ validate, submit });
<a-form-item label="预算金额" name="budgetSum">
<a-input-number
v-model:value="form.budgetSum"
class="min-w-[200px]"
:disabled="readOnly"
:min="0"
class="min-w-[200px]"
/>
</a-form-item>
<a-col :span="3">
<a-form-item label="" :colon="false" name="priceType">
<a-form-item :colon="false" label="" name="priceType">
<a-select
class="w-full min-w-[120px]"
v-model:value="form.priceType"
:disabled="readOnly"
:min="0"
:options="dictMap[DICT_TYPE.contract_currency_unit]"
class="w-full min-w-[120px]"
/>
</a-form-item>
</a-col>
@ -203,8 +202,9 @@ defineExpose({ validate, submit });
<a-form-item label="资金流向" name="fundAllocation">
<a-select
v-model:value="form.fundAllocation"
class="min-w-[200px]"
:disabled="readOnly"
:options="dictMap[DICT_TYPE.contract_fund_flow]"
class="min-w-[200px]"
/>
</a-form-item>
</a-col>
@ -213,8 +213,9 @@ defineExpose({ validate, submit });
<a-form-item label="资金渠道" name="fundDitch">
<a-select
v-model:value="form.fundDitch"
class="min-w-[200px]"
:disabled="readOnly"
:options="dictMap[DICT_TYPE.contract_funding_source]"
class="min-w-[200px]"
/>
</a-form-item>
</a-col>
@ -223,6 +224,7 @@ defineExpose({ validate, submit });
<a-form-item label="框架协议" name="frameProtocol">
<a-radio-group
v-model:value="form.frameProtocol"
:disabled="readOnly"
:options="dictMap[DICT_TYPE.common_whether]"
/>
</a-form-item>
@ -232,6 +234,7 @@ defineExpose({ validate, submit });
<a-form-item label="框架协议下的合同" name="frameProtocolCtr">
<a-radio-group
v-model:value="form.frameProtocolCtr"
:disabled="readOnly"
:options="dictMap[DICT_TYPE.common_whether]"
/>
</a-form-item>
@ -241,8 +244,9 @@ defineExpose({ validate, submit });
<a-form-item label="组织方式" name="organiza">
<a-radio-group
v-model:value="form.organiza"
class="min-w-[200px]"
:disabled="readOnly"
:options="dictMap[DICT_TYPE.contract_organization_form]"
class="min-w-[200px]"
/>
</a-form-item>
</a-col>
@ -252,15 +256,22 @@ defineExpose({ validate, submit });
<a-upload
v-model:file-list="form.fileList"
:before-upload="() => false"
:disabled="readOnly"
:max-count="3"
accept=".pdf,.ppt,.pptx"
name="file"
@change="handleChange"
>
<a-button>
<a-button v-if="!readOnly">
<MdiUpload />
点击上传
</a-button>
<div
v-if="readOnly && form.fileList.length === 0"
class="text-gray-700"
>
无附件
</div>
</a-upload>
</a-form-item>
</a-col>

View File

@ -1,33 +1,28 @@
<script setup lang="ts">
import {
ref,
reactive,
watch,
computed,
defineEmits,
defineProps,
withDefaults,
onMounted,
nextTick,
computed,
onMounted,
reactive,
ref,
watch,
withDefaults,
} from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { DICT_TYPE, getDictDatasAsync, getDictObj } from '#/utils/dict';
import { getBidColumns, getProviderColumns } from './bid-columns';
import chooseCompanyModal from '../../company/list/choose-company-modal.vue';
import Apis from '#/api';
import { logger } from 'common-utils';
import { message } from 'ant-design-vue';
import { logger } from 'common-utils';
import { cloneDeep } from 'lodash-es';
import Apis from '#/api';
import { DICT_TYPE, getDictDatasAsync, getDictObj } from '#/utils/dict';
import { FileUploader } from '#/utils/file';
const [ChooseCompanyModal, chooseCompanyModalApi] = useVbenModal({
connectedComponent: chooseCompanyModal,
});
const fileUploader = new FileUploader({});
const emit = defineEmits(['update:form', 'field-change']);
import chooseCompanyModal from '../../company/list/choose-company-modal.vue';
import { getBidColumns, getProviderColumns } from './bid-columns';
const props = withDefaults(
defineProps<{
@ -38,20 +33,21 @@ const props = withDefaults(
},
);
const readOnly = computed(() => {
return [
'smDepartmentAudit',
'smPlanningDepartment',
'smFinancialDepartment',
'smRegulationDepartment',
'smManager',
'smLeaders',
].includes(form.step);
const emit = defineEmits(['update:form', 'field-change']);
const [ChooseCompanyModal, chooseCompanyModalApi] = useVbenModal({
connectedComponent: chooseCompanyModal,
});
const fileUploader = new FileUploader({});
const formRef = ref();
const form = reactive({ ...props.form });
const readOnly = computed(() => {
return ['smApproval'].includes(form.step);
});
const rules = {
projectNum: [{ required: true, message: '请输入项目' }],
projectProp: [{ required: true, message: '请选择项目类别' }],
@ -157,20 +153,29 @@ const currBid = ref();
function handleChooseCompanyConfirm(e) {
console.log(currBid.value);
if (currBid.value.phaseSeq === 99999) {
console.log(providerGridRefs.value);
if (currBid.value.phaseSeq === 99_999) {
const gridRef = providerGridRefs2.value;
e.map((item) => (item.guid = undefined));
e.map((item) => {
item.phaseSeq = `${currBid.value.phaseSeq}`;
item._guid = item.guid;
item.guid = undefined;
});
gridRef.insertAt(e, -1);
return;
}
const gridRef = providerGridRefs.value.get(currBid.value.phaseSeq); // Assuming you have a main grid ref
const gridRef = providerGridRefs.value.get(`${currBid.value.phaseSeq}`); // Assuming you have a main grid ref
//
const bidRef = bidGridRefs.value.get(currBid.value.phaseSeq);
const bidRef = bidGridRefs.value.get(`${currBid.value.phaseSeq}`);
const bidFullData = bidRef.getTableData().fullData;
for (const item of bidFullData) {
if (item.phaseSeq === currBid.value.phaseSeq) {
item.providerList = item.providerList || [];
e.map((item) => (item.guid = undefined));
e.map((item) => {
item.phaseSeq = `${currBid.value.phaseSeq}`;
item._guid = item.guid;
item.guid = undefined;
});
item.providerList.push(...e);
bidRef.loadData(bidFullData);
break;
@ -183,13 +188,14 @@ function handleChooseCompanyConfirm(e) {
function onChooseProvider(row) {
currBid.value = row;
if (row.phaseSeq === 99999) {
if (row.phaseSeq === 99_999) {
const tableFullData =
providerGridRefs2.value?.getTableData()?.fullData || [];
console.log(tableFullData);
chooseCompanyModalApi.setData({
title: '选择推荐供应商',
limitMultipleNum: 5,
guids: tableFullData.map((item) => item.guid) || [],
guids: tableFullData.map((item) => item._guid) || [],
});
chooseCompanyModalApi.open();
@ -197,15 +203,19 @@ function onChooseProvider(row) {
}
const gridRef = providerGridRefs.value.get(currBid.value.phaseSeq); // Assuming you have a main grid ref
const tableFullData = gridRef?.getTableData()?.fullData || [];
console.log(tableFullData);
chooseCompanyModalApi.setData({
title: '选择供应商',
limitMultipleNum: 5,
guids: tableFullData.map((item) => item.guid) || [],
guids: tableFullData.map((item) => item._guid) || [],
});
chooseCompanyModalApi.open();
}
async function removeProvider(row) {
const gridRef = providerGridRefs.value.get(`${row.phaseSeq}`);
console.log(providerGridRefs.value, row);
if (row.guid) {
try {
await Apis.contractRecommendProvider.post_deletes({
@ -219,7 +229,6 @@ async function removeProvider(row) {
return;
}
}
const gridRef = providerGridRefs.value.get(`${row.phaseSeq}`);
gridRef.remove(row);
}
@ -306,15 +315,15 @@ onMounted(async () => {
});
function validate() {
let a = getExtraForm();
if (!a) {
throw new Error('请完成必填项的填写');
const a = getExtraForm();
if (typeof a === 'string') {
throw new TypeError(a);
}
return formRef.value?.validate();
}
function getForm() {
let tempForm = cloneDeep(form);
const tempForm = cloneDeep(form);
tempForm.priceStyleName = getDictObj(
DICT_TYPE.contract_price_style,
@ -325,40 +334,40 @@ function getForm() {
tempForm.choiceType,
)?.label;
let extraForm = getExtraForm();
const extraForm = getExtraForm();
return { form: tempForm, ...extraForm };
return form;
}
function getExtraForm() {
console.log(form);
if (form.frameProtocol === '0') {
let fullData = providerGridRefs2.value.getTableData().fullData || [];
const fullData = providerGridRefs2.value.getTableData().fullData || [];
return {
biddingList: [],
contractRecommendProviderList: fullData.map((item) => ({
...item,
phaseSeq: 99999,
phaseSeq: 99_999,
})),
};
}
if (form.frameProtocol === '1') {
const tempBidList: any = [];
debugger;
const tempProviderList: any = [];
for (const item of bidList.value) {
const gridRef = bidGridRefs.value.get(item.phaseSeq);
const gridRef = bidGridRefs.value.get(`${item.phaseSeq}`);
const fullData = gridRef.getTableData().fullData;
console.log(fullData);
if (fullData.length > 0) {
const bidInfo = fullData[0];
if (!bidInfo.phaseName) {
message.error(`【标段${item.phaseSeq}】中的标段名称不能为空`);
return;
return `【标段${item.phaseSeq}】中的标段名称不能为空`;
}
if (!bidInfo.phaseMoney) {
message.error(`${item.phaseName}】中的预算金额不能为空`);
return;
return `${item.phaseName}】中的预算金额不能为空`;
}
bidInfo.id = undefined;
bidInfo.priceType = form.priceType;
@ -366,23 +375,20 @@ function getExtraForm() {
tempBidList.push(bidInfo);
const providerGrid = providerGridRefs.value.get(item.phaseSeq);
const providerGrid = providerGridRefs.value.get(`${item.phaseSeq}`);
const providerFullData = providerGrid.getTableData().fullData;
console.log(providerFullData);
for (const item2 of providerFullData || []) {
item2.phaseSeq = item.phaseSeq;
if (!item2.aptitudeName) {
message.error(`【标段${item.phaseSeq}】中供应商资质名称不能为空`);
return;
return `【标段${item.phaseSeq}】中供应商资质名称不能为空`;
}
if (!item2.contactPerson) {
message.error(`【标段${item.phaseSeq}】中供应商联系人不能为空`);
return;
return `【标段${item.phaseSeq}】中供应商联系人不能为空`;
}
if (!item2.contactPhone) {
message.error(`【标段${item.phaseSeq}】中供应商联系人电话不能为空`);
return;
return `【标段${item.phaseSeq}】中供应商联系人电话不能为空`;
}
item2.contractId = form.contractId;
tempProviderList.push(item2);
@ -402,10 +408,10 @@ defineExpose({ validate, getForm });
<template>
<ChooseCompanyModal class="w-[950px]" @confirm="handleChooseCompanyConfirm" />
<a-form
:model="form"
:rules="rules"
ref="formRef"
:label-col="{ style: { width: '120px' } }"
:model="form"
:rules="rules"
label-wrap
>
<a-row :gutter="16">
@ -433,8 +439,8 @@ defineExpose({ validate, getForm });
<a-form-item label="项目名称" name="projectName">
<a-select
v-model:value="form.projectName"
:options="dictMap[DICT_TYPE.comprehensive_project_name]"
:disabled="readOnly"
:options="dictMap[DICT_TYPE.comprehensive_project_name]"
/>
</a-form-item>
</a-col>
@ -575,9 +581,9 @@ defineExpose({ validate, getForm });
<span class="ml-2 mr-4 w-full">标段数量</span>
<a-select
v-model:value="form.bidNum"
:disabled="readOnly"
:options="dictMap[DICT_TYPE.section_num]"
class="min-w-[180px]"
:disabled="readOnly"
@change="onBidNumChange"
/>
</div>
@ -608,8 +614,8 @@ defineExpose({ validate, getForm });
<template #phasemoney-slot="{ row }">
<a-input-number
v-model:value="row.phaseMoney"
addon-after="元"
:disabled="readOnly"
addon-after="元"
/>
</template>
@ -622,10 +628,10 @@ defineExpose({ validate, getForm });
<!-- 操作的插槽 -->
<template #operate-slot="{ row }">
<a-button
:disabled="readOnly"
size="small"
type="primary"
@click="onChooseProvider(row)"
:disabled="readOnly"
>
选择供应商
</a-button>

View File

@ -3,7 +3,6 @@ import { ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { dict } from '@fast-crud/fast-crud';
import { VxeGrid } from 'vxe-table';
import { DICT_TYPE } from '#/utils/dict';
@ -18,7 +17,7 @@ const xGridRefs = ref<Map<string, any>>(new Map());
const gridRefs = ref<Map<string, any>>(new Map());
export function getFormSchema(params: any = {}) {
let { formRef, dictMap = {}, bidList = [], showBid = true } = params;
const { formRef, dictMap = {}, bidList = [], showBid = true } = params;
/** Hooks - 表格 */
const gridOptions = {

View File

@ -12,22 +12,22 @@ import {
type UploadChangeParam,
type UploadFile,
} from 'ant-design-vue';
import { cloneDeep } from 'lodash-es';
import Apis from '#/api';
import temporaryFormModal from '#/components/temporary-form-modal/temporary-form-modal.vue';
import { useVxeTable } from '#/hooks/vxeTable';
import { DICT_TYPE, getDictDatasAsync, getDictObj } from '#/utils/dict';
import { FileUploader } from '#/utils/file';
import { logger } from '#/utils/logger';
import AuditNodeTable from '#/views/contract/components/audit-node-table/audit-node-table.vue';
import chooseUserModal from '#/views/system/user/choose-user-modal.vue';
import { getColumns } from '../../approval/signing-basis/columns';
import chooseCompanyModal from '../../company/list/choose-company-modal.vue';
import { getBidColumns, getProviderColumns } from './bid-columns';
import { getFormSchema } from './curd';
import BasicInfoCard from './basic-info-card.vue';
import { cloneDeep } from 'lodash-es';
import { getBidColumns, getProviderColumns } from './bid-columns';
import BusinessCard from './business-card.vue';
const [ChooseCompanyModal, chooseCompanyModalApi] = useVbenModal({
connectedComponent: chooseCompanyModal,
});
@ -67,6 +67,10 @@ const isLoading = ref(true);
const bidGridRefs = ref<Map<string, any>>(new Map());
const providerGridRefs = ref<Map<string, any>>(new Map());
const readOnly = computed(() => {
return ['smApproval'].includes(businessData.value.step);
});
watch(
() => contractData.value.frameProtocol,
(newValue) => {
@ -152,7 +156,7 @@ function handleBack() {
* 页面返回并关闭tab
*/
function back() {
router.replace('/contract/business/list');
router.replace('/contract/business/todo');
}
const handleChange = (info: UploadChangeParam) => {
@ -174,7 +178,7 @@ function handleDelete() {
});
}
const collapses = ['1', '2', '3', '4'];
const collapses = ['1', '2', '3', '4', '5'];
// const collapses = ['3', '4'];
const collapseActiveKey = ref(collapses);
function areArraysEqualUnordered(arr1, arr2) {
@ -381,7 +385,8 @@ async function handleSave() {
try {
await contractCardRef.value.validate();
await businessCardRef.value.validate();
} catch {
} catch (error) {
console.log(error);
message.error('请完成必填项的填写');
return;
}
@ -509,7 +514,6 @@ async function handleSubmit(type: 'openModal' | 'submit') {
}
if (type === 'submit') {
isLoading.value = true;
try {
await Apis.selectMerchantsBasicInfo.post_flowStart({
data: {
@ -556,6 +560,9 @@ onMounted(async () => {
const business: any = await Apis.selectMerchantsBasicInfo.get_getOne({
params: { contractId: contract.contractId },
});
contractData.value.businessStep = business.step;
business.priceType = contract.priceType;
business.priceTypeName = contract.priceTypeName;
business.frameProtocol = contract.frameProtocol;
@ -563,7 +570,8 @@ onMounted(async () => {
selectMerchantsBasicInfoId.value = business.guid;
if (business.fileUuid) {
const files = await fileUploader.select(business.fileUuid);
business.fileList = files;
// business.fileList = files;
fileList.value = files;
}
businessData.value = business;
@ -628,7 +636,10 @@ onMounted(async () => {
保存
</vben-button>
<vben-button
v-if="['smEdit'].includes(selectMerchantsBasicInfo.step)"
v-if="
!selectMerchantsBasicInfoId ||
['smEdit'].includes(selectMerchantsBasicInfo.step)
"
:disabled="!selectMerchantsBasicInfoId"
variant="primary"
@click="handleSubmit('openModal')"
@ -641,14 +652,7 @@ onMounted(async () => {
<vben-button
v-if="
selectMerchantsBasicInfoId &&
[
'smDepartmentAudit',
'smPlanningDepartment',
'smFinancialDepartment',
'smRegulationDepartment',
'smManager',
'smLeaders',
].includes(selectMerchantsBasicInfo.step)
['smApproval'].includes(selectMerchantsBasicInfo.step)
"
variant="primary"
@click="handleAudit('accessConfirm')"
@ -658,14 +662,7 @@ onMounted(async () => {
<vben-button
v-if="
selectMerchantsBasicInfoId &&
[
'smDepartmentAudit',
'smPlanningDepartment',
'smFinancialDepartment',
'smRegulationDepartment',
'smManager',
'smLeaders',
].includes(selectMerchantsBasicInfo.step)
['smApproval'].includes(selectMerchantsBasicInfo.step)
"
variant="destructive"
@click="handleAudit('reject')"
@ -734,19 +731,34 @@ onMounted(async () => {
<a-upload
v-model:file-list="fileList"
:before-upload="() => false"
:disabled="readOnly"
:max-count="3"
accept=".pdf,.ppt,.pptx"
name="file"
@change="handleChange"
>
<a-button>
<a-button v-if="!readOnly">
<MdiUpload />
点击上传
</a-button>
<div
v-if="readOnly && fileList.length === 0"
class="text-gray-700"
>
无附件
</div>
</a-upload>
</a-form-item>
</a-form>
</a-collapse-panel>
<a-collapse-panel
v-if="businessData.flowInstanceId"
key="5"
class="w-full"
header="审批信息"
>
<AuditNodeTable :flow-instance-id="businessData.flowInstanceId" />
</a-collapse-panel>
</a-collapse>
</div>
</a-spin>

View File

@ -1,23 +1,28 @@
<script setup lang="ts">
import { computed, onMounted, reactive, ref } from "vue";
import { useRouter } from "vue-router";
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 { Page } from '@vben/common-ui';
import {
MdiExport,
MdiRadioChecked,
MdiRadioUnchecked,
MdiUpdate,
} from '@vben/icons';
import { message } from "ant-design-vue";
import { message } from 'ant-design-vue';
import Apis from "#/api";
import { useVxeTable } from "#/hooks/vxeTable";
import { toDetailPage } from "#/views/contract/utils.ts";
import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
import { toDetailPage } from '#/views/contract/utils.ts';
import { getColumns, getFormSchema, PrimaryKey } from "./crud.tsx";
import { getColumns, getFormSchema, PrimaryKey } from './crud.tsx';
const router = useRouter();
const searchRef = ref();
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: "xGridRef" });
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
/** Hooks - 表格 */
const gridOptions = reactive(
@ -44,35 +49,37 @@ const gridOptions = reactive(
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["contractId"]}`);
// }
if (false) {
router.push(
`/contract/business/result/${record[PrimaryKey]}?flowInstanceId=${record.flowInstanceId}`,
);
} else {
router.push(
`/contract/business/edit/${record['contractId']}?flowInstanceId=${record.flowInstanceId}`,
);
}
}
function handleExport() {
const $grid = xGridRef.value;
if ($grid) {
$grid.exportData({
type: "xlsx",
type: 'xlsx',
columnFilterMethod: ({ column }) => {
if (["operate", "step"].includes(column.field)) {
if (['operate', 'step'].includes(column.field)) {
return false;
}
if (column.type === "radio") {
if (column.type === 'radio') {
return false;
}
return true;
},
});
message.success("导出成功");
message.success('导出成功');
}
}
@ -96,13 +103,13 @@ function handleCellClick({ row }) {
}
onMounted(() => {
triggerProxy("reload");
triggerProxy('reload');
});
const searchForm = ref({
...getFormSchema(),
onSearch(_context: any) {
triggerProxy("reload");
triggerProxy('reload');
},
});
</script>
@ -133,7 +140,11 @@ const searchForm = ref({
</fs-search>
<div class="min-h-300px flex-1">
<vxe-grid ref="xGridRef" v-bind="gridOptions" @cell-click="handleCellClick">
<vxe-grid
ref="xGridRef"
v-bind="gridOptions"
@cell-click="handleCellClick"
>
<template #toolbar_buttons>
<a-space>
<vben-button

View File

@ -1,23 +1,28 @@
<script setup lang="ts">
import { computed, onMounted, reactive, ref } from "vue";
import { useRouter } from "vue-router";
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 { Page } from '@vben/common-ui';
import {
MdiExport,
MdiRadioChecked,
MdiRadioUnchecked,
MdiUpdate,
} from '@vben/icons';
import { message } from "ant-design-vue";
import { message } from 'ant-design-vue';
import Apis from "#/api";
import { useVxeTable } from "#/hooks/vxeTable";
import { toDetailPage } from "#/views/contract/utils.ts";
import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
import { toDetailPage } from '#/views/contract/utils.ts';
import { getColumns, getFormSchema, PrimaryKey } from "./crud.tsx";
import { getColumns, getFormSchema, PrimaryKey } from './crud.tsx';
const router = useRouter();
const searchRef = ref();
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: "xGridRef" });
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
/** Hooks - 表格 */
const gridOptions = reactive(
@ -44,35 +49,31 @@ const gridOptions = reactive(
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]}`);
}
router.push(
`/contract/business/result/${record.contractId}?flowInstanceId=${record.flowInstanceId}`,
);
}
function handleExport() {
const $grid = xGridRef.value;
if ($grid) {
$grid.exportData({
type: "xlsx",
type: 'xlsx',
columnFilterMethod: ({ column }) => {
if (["operate", "step"].includes(column.field)) {
if (['operate', 'step'].includes(column.field)) {
return false;
}
if (column.type === "radio") {
if (column.type === 'radio') {
return false;
}
return true;
},
});
message.success("导出成功");
message.success('导出成功');
}
}
@ -96,13 +97,13 @@ function handleCellClick({ row }) {
}
onMounted(() => {
triggerProxy("reload");
triggerProxy('reload');
});
const searchForm = ref({
...getFormSchema(),
onSearch(_context: any) {
triggerProxy("reload");
triggerProxy('reload');
},
});
</script>
@ -133,7 +134,11 @@ const searchForm = ref({
</fs-search>
<div class="min-h-300px flex-1">
<vxe-grid ref="xGridRef" v-bind="gridOptions" @cell-click="handleCellClick">
<vxe-grid
ref="xGridRef"
v-bind="gridOptions"
@cell-click="handleCellClick"
>
<template #toolbar_buttons>
<a-space>
<vben-button

View File

@ -1,55 +1,59 @@
<script setup lang="ts">
import { onMounted, ref } from "vue";
import { nextTick, onMounted, ref } from 'vue';
import { useVbenModal } from "@vben/common-ui";
import { useVbenModal } from '@vben/common-ui';
import chooseCompanyModal from "../../company/list/choose-company-modal.vue";
import { message } from "ant-design-vue";
import Apis from "#/api";
import { logger } from "common-utils";
import { message } from 'ant-design-vue';
import { logger } from 'common-utils';
import Apis from '#/api';
import chooseCompanyModal from '../../company/list/choose-company-modal.vue';
const props = withDefaults(
defineProps<{
businseeData: any;
contractId: string;
projectId: string;
}>(),
{
contractId: "",
projectId: "",
}
contractId: '',
projectId: '',
businseeData: () => ({}),
},
);
const emit = defineEmits<{
(e: "submit", data: any): void;
(e: 'submit', data: any): void;
}>();
const [ChooseCompanyModal, chooseCompanyModalApi] = useVbenModal({
connectedComponent: chooseCompanyModal,
});
const companyChooseType = ref<"providerPt" | "biddingProvider">("providerPt");
const companyChooseType = ref<'biddingProvider' | 'providerPt'>('providerPt');
/** 必填字段校验 */
const requiredFieldRules: any = {
// contractName: { required: true, message: "" },
// ctrType: { required: true, message: "" },
// ctrTwoType: { required: true, message: "" },
// fundAllocation: { required: true, message: "" },
// fundDitch: { required: true, message: "" },
// organiza: { required: true, message: "" },
openDate: { required: true, message: '开标时间不得为空' },
openPlace: { required: true, message: '开标地点不得为空' },
participant: { required: true, message: '参加人不得为空' },
processDesc: { required: true, message: '过程描述不得为空' },
};
/** 必填字段校验,如果是必填字段则返回对应message */
function isRequired(field: string): string {
let rule = requiredFieldRules[field];
const rule = requiredFieldRules[field];
if (rule && rule.required) {
return rule.message || `${field}不可为空`;
}
return "";
return '';
}
const biddingExpertRef = ref();
const bidList = ref<any[]>([]);
const biddingExpertList = ref([]);
const providerPtRef1 = ref();
@ -62,42 +66,48 @@ const biddingPtInfo = ref<any>({});
const biddingProviderRef = ref();
const biddingProviderList = ref([{}]);
function onAddProviderPt(type: string, data?: any) {
companyChooseType.value = "providerPt";
companyChooseType.value = 'providerPt';
const tableFullData = providerPtRef1.value.getTableData()?.fullData || [];
if (type === "openModal") {
if (type === 'openModal') {
chooseCompanyModalApi.setData({
title: "选择单位",
title: '选择单位',
limitMultipleNum: 5,
guids: tableFullData.map((item) => item.guid) || [],
guids: tableFullData.map((item) => item._guid) || [],
});
chooseCompanyModalApi.open();
}
if (type === "confirm") {
if (type === 'confirm') {
console.log(data);
data.map((item) => (item.guid = undefined));
data.map((item) => {
item._guid = item.guid;
item.guid = undefined;
});
providerPtRef1.value.insert(data);
providerPtRef2.value.insert(data);
}
}
function onAddBiddingProvider(type: string, data?: any) {
companyChooseType.value = "biddingProvider";
companyChooseType.value = 'biddingProvider';
const tableFullData = biddingProviderRef.value.getTableData()?.fullData || [];
if (type === "openModal") {
console.log(tableFullData);
if (type === 'openModal') {
chooseCompanyModalApi.setData({
title: "选择单位",
title: '选择单位',
limitMultipleNum: 1,
guids: tableFullData.map((item) => item.guid) || [],
guids: [],
});
chooseCompanyModalApi.open();
}
if (type === "confirm") {
if (type === 'confirm') {
console.log(data);
data.map((item) => (item.guid = undefined));
data.map((item) => {
item._guid = item.guid;
item.guid = undefined;
});
biddingProviderRef.value.loadData(data);
}
}
@ -114,7 +124,7 @@ function onRemoveBiddingExpertRow(row) {
function onRemoveProviderPtRow(row) {
providerPtRef1.value.remove(row);
let fullData = providerPtRef2.value.getTableData().fullData;
const fullData = providerPtRef2.value.getTableData().fullData;
for (const item of fullData) {
if (item.providerId === row.providerId) {
providerPtRef2.value.remove(item);
@ -123,11 +133,11 @@ function onRemoveProviderPtRow(row) {
}
function handleChooseCompanyConfirm(e) {
if (companyChooseType.value == "providerPt") {
onAddProviderPt("confirm", e);
if (companyChooseType.value === 'providerPt') {
onAddProviderPt('confirm', e);
}
if (companyChooseType.value == "biddingProvider") {
onAddBiddingProvider("confirm", e);
if (companyChooseType.value === 'biddingProvider') {
onAddBiddingProvider('confirm', e);
}
}
@ -137,26 +147,90 @@ async function verify() {
for (const field of Object.keys(requiredFieldRules)) {
if (!biddingResult.value[field]) {
message.error(isRequired(field));
return;
return false;
}
}
return true;
}
function getFormData() {
let _fullData1 = providerPtRef1.value.getTableData().fullData;
let _fullData2 = providerPtRef2.value.getTableData().fullData;
let _fullData3 = biddingExpertRef.value.getTableData().fullData;
let _fullData4 = biddingProviderRef.value.getTableData().fullData;
async function getFormData() {
if (!(await verify())) {
return;
}
const _fullData1 = providerPtRef1.value.getTableData().fullData;
const _fullData2 = providerPtRef2.value.getTableData().fullData;
const _fullData3 = biddingExpertRef.value.getTableData().fullData;
const _fullData4 = biddingProviderRef.value.getTableData().fullData;
console.log(_fullData1, _fullData2, _fullData3, _fullData4);
let data1: any[] = [];
if (_fullData1.length === 0) {
message.error('请添加标段信息');
return;
}
for (const item of _fullData1) {
if (!item.bidPlace) {
message.error('请补全标段信息中的投标地点');
return;
}
if (!item.bidMoney) {
message.error('请补全标段信息中的投标保证金');
return;
}
}
if (_fullData3.length === 0) {
message.error('请添加专家信息');
return;
}
for (const item of _fullData3) {
if (!item.expertName) {
message.error('请补全专家信息中的评委姓名');
return;
}
if (!item.expertSex) {
message.error('请补全专家信息中的性别');
return;
}
// if (!item.expertAge) {
// message.error('');
// return;
// }
// if (!item.expertDepartName) {
// message.error('');
// return;
// }
// if (!item.professionTypeName) {
// message.error('');
// return;
// }
// if (!item.titleTypeName) {
// message.error('');
// return;
// }
// if (!item.positionName) {
// message.error('');
// return;
// }
}
for (const item of _fullData2) {
if (!item.offerMoney) {
message.error('请补全单位报价及评标信息中的报价');
return;
}
}
const data1: any[] = [];
for (const item1 of _fullData1) {
for (const item2 of _fullData2) {
if (item1.providerId === item2.providerId) {
data1.push({
...item1,
phasePtId: '',
offerMoney: item2.offerMoney,
bidScore: item2.bidScore,
bidDesc: item2.bidDesc,
@ -166,13 +240,14 @@ function getFormData() {
}
}
let tempBiddingResult = JSON.parse(JSON.stringify(biddingResult.value));
const tempBiddingResult = JSON.parse(JSON.stringify(biddingResult.value));
tempBiddingResult.projectId = props.projectId;
let tempBiddingPtInfo = JSON.parse(JSON.stringify(biddingPtInfo.value));
const tempBiddingPtInfo = JSON.parse(JSON.stringify(biddingPtInfo.value));
tempBiddingPtInfo.projectId = props.projectId;
tempBiddingPtInfo.phasePtId = '';
_fullData3.map((item) => (item.projectId = props.projectId));
let form = {
const form = {
biddingResult: tempBiddingResult,
biddingExpertList: _fullData3,
providerPtList: data1,
@ -184,29 +259,76 @@ function getFormData() {
onMounted(async () => {
try {
// ;
let providerData = await Apis.contractRecommendProvider.get_list({
params: {
contractId: props.contractId,
},
});
providerData = providerData.rows || [];
//
nextTick(() => {
providerPtRef1.value.loadData(providerData);
providerPtRef2.value.loadData(providerData);
});
// if (props.businseeData.frameProtocol === '1') {
// for (const item of bidList.value) {
// const rows = [];
// for (const provider of providerData) {
// if (item.phaseSeq == provider.phaseSeq) {
// rows.push(provider);
// }
// }
// item.providerList = rows;
// // nextTick(() => {
// // providerGridRefs.value.get(`${item.phaseSeq}`).insert(rows);
// // });
// }
// } else {
// nextTick(() => {
// providerPtRef1.value.loadData(providerData);
// providerPtRef2.value.loadData(providerData);
// // providerGridRefs2.value.insert(providerData);
// });
// }
//
const expertData = await Apis.biddingResult.get_queryBiddingExpert({
params: {
projectId: props.projectId,
contractId: props.contractId,
},
});
console.log('专家信息', expertData);
nextTick(() => {
biddingExpertRef.value.loadData(expertData.rows);
});
//
let data = await Apis.biddingResult.get_page({
const data = await Apis.biddingResult.get_page({
params: {
pageNum: 1,
pageSize: 1,
projectId: props.projectId,
},
});
if (data.rows.length) {
if (data.rows.length > 0) {
biddingResult.value = data.rows[0];
}
console.log("选商结果信息", biddingResult.value);
console.log('选商结果信息', biddingResult.value);
//
let experData = await Apis.biddingExpert.get_list({
const experData = await Apis.biddingExpert.get_list({
params: {
contractId: props.contractId,
projectId: props.projectId,
},
});
console.log("招标专家信息", experData);
console.log('招标专家信息', experData);
} catch (error) {
logger.error("获取选商结果填报数据出错", error);
logger.error('获取选商结果填报数据出错', error);
}
// biddingResult.value = currData.value;
});
@ -220,7 +342,12 @@ defineExpose({
<template>
<ChooseCompanyModal class="w-[950px]" @confirm="handleChooseCompanyConfirm" />
<a-descriptions :label-style="{ width: '150px' }" bordered size="small" title="">
<a-descriptions
:label-style="{ width: '150px' }"
bordered
size="small"
title=""
>
<a-descriptions-item :span="3" label="标段信息">
<vxe-table ref="providerPtRef1" :data="providerPtList" size="mini">
<vxe-column field="providerName" title="单位名称">
@ -235,12 +362,20 @@ defineExpose({
</vxe-column>
<vxe-column field="bidMoney" title="投标保证金">
<template #default="{ row }">
<a-input-number v-model:value="row.bidMoney" addon-after="" />
<a-input-number
v-model:value="row.bidMoney"
:min="0"
addon-after="元"
/>
</template>
</vxe-column>
<vxe-column field="operate" title="" width="100">
<template #header>
<a-button size="small" type="primary" @click="onAddProviderPt('openModal')">
<a-button
size="small"
type="primary"
@click="onAddProviderPt('openModal')"
>
添加
</a-button>
</template>
@ -319,24 +454,40 @@ defineExpose({
</vxe-column>
</vxe-table>
</a-descriptions-item>
<a-descriptions-item :span="1" label="开标时间">
<a-descriptions-item :span="1">
<template #label>
<span v-if="isRequired('openDate')" class="text-red-500">*</span>
开标时间
</template>
<a-date-picker
v-model:value="biddingResult.openDate"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
/>
</a-descriptions-item>
<a-descriptions-item :span="2" label="开标地点">
<a-descriptions-item :span="2">
<template #label>
<span v-if="isRequired('openPlace')" class="text-red-500">*</span>
开标地点
</template>
<a-input v-model:value="biddingResult.openPlace" />
</a-descriptions-item>
<a-descriptions-item :span="3" label="参加人">
<a-descriptions-item :span="3">
<template #label>
<span v-if="isRequired('participant')" class="text-red-500">*</span>
参加人
</template>
<a-textarea
v-model:value="biddingResult.participant"
:auto-size="{ minRows: 2, maxRows: 5 }"
/>
</a-descriptions-item>
<a-descriptions-item :span="3" label="过程描述">
<a-descriptions-item :span="3">
<template #label>
<span v-if="isRequired('processDesc')" class="text-red-500">*</span>
过程描述
</template>
<a-textarea
v-model:value="biddingResult.processDesc"
:auto-size="{ minRows: 2, maxRows: 5 }"
@ -371,7 +522,11 @@ defineExpose({
</vxe-column>
<vxe-column field="offerMoney" title="报价(人民币元)">
<template #default="{ row }">
<a-input-number v-model:value="row.offerMoney" addon-after="" />
<a-input-number
v-model:value="row.offerMoney"
:min="0"
addon-after="元"
/>
</template>
</vxe-column>
<vxe-column field="bidScore" title="综合得分(综合评价)">
@ -395,10 +550,14 @@ defineExpose({
</a-descriptions-item>
<a-descriptions-item :span="3" label="招标结果">
<vxe-table ref="biddingProviderRef" :data="biddingProviderList" size="mini">
<vxe-table
ref="biddingProviderRef"
:data="biddingProviderList"
size="mini"
>
<vxe-column field="providerName" title="单位名称">
<template #default="{ row }">
{{ row.providerName || "" }}
{{ row.providerName || '' }}
<a-button
size="small"
type="primary"

View File

@ -1,30 +1,42 @@
<script setup lang="ts">
import { computed, onMounted, ref } from "vue";
import { useRoute, useRouter } from "vue-router";
import { computed, onMounted, reactive, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { Page, useVbenModal } from "@vben/common-ui";
import { Page, useVbenModal } from '@vben/common-ui';
import { message, Modal } from "ant-design-vue";
import { logger } from "common-utils";
import { message, Modal, type UploadChangeParam } from 'ant-design-vue';
import { logger } from 'common-utils';
import Apis from "#/api";
import AuditNodeTable from "#/views/contract/components/audit-node-table/audit-node-table.vue";
import FileCard from "#/views/contract/components/file-card/file-card.vue";
import ApprovalCard from "#/views/contract/iframe-info/components/info-approval/approval-card.vue";
import BusinessCard from "#/views/contract/iframe-info/components/info-business/business-card.vue";
import chooseUserModal from "#/views/system/user/choose-user-modal.vue";
import Apis from '#/api';
import { FileUploader } from '#/utils/file';
import AuditNodeTable from '#/views/contract/components/audit-node-table/audit-node-table.vue';
import FileCard from '#/views/contract/components/file-card/file-card.vue';
import ApprovalCard from '#/views/contract/iframe-info/components/info-approval/approval-card.vue';
import BusinessCard from '#/views/contract/iframe-info/components/info-business/business-card.vue';
import chooseUserModal from '#/views/system/user/choose-user-modal.vue';
import FillResultCard from "./fill-result-card.vue";
import FillResultCard from './fill-result-card.vue';
const [ChooseUserModal, chooseUserModalApi] = useVbenModal({
connectedComponent: chooseUserModal,
});
const fileUploader = new FileUploader({});
const router = useRouter();
const route = useRoute();
const pageRef = ref();
const fillResultCardRef = ref();
const formRef = ref();
const form = reactive({
fileList: [],
});
const readOnly = computed(() => {
return false;
});
const id = ref(route.params.id);
const flowInstanceId = ref(route.query.flowInstanceId as string);
@ -35,10 +47,12 @@ const isLoading = ref(false);
const contractTypeData = ref([]);
const bidList = ref<any[]>([]);
const submitGuid = ref();
// const collapses = ['1', '2', '3', '4','5'];
const collapses = ["5"];
// const collapses = ['1', '2', '3', '4', '5'];
const collapses = ['4', '5', '6'];
const collapseActiveKey = ref(collapses);
function areArraysEqualUnordered(arr1, arr2) {
if (arr1.length !== arr2.length) return false;
@ -53,23 +67,27 @@ function handleFold() {
collapseActiveKey.value = isFold.value ? collapses : [];
}
const handleChange = (info: UploadChangeParam) => {
form.fileList = info.fileList.length > 0 ? info.fileList : [];
};
/**
* 页面返回并关闭tab
*/
function back() {
router.replace("/contract/business/list");
router.replace('/contract/business/list');
}
const selectUsers = ref([]);
async function handleChooseUserConfirm(e) {
selectUsers.value = e;
chooseUserModalApi.close();
handleSubmit("submit");
handleSubmit('submit');
}
function handleBack() {
Modal.confirm({
title: "提示",
title: '提示',
content: `是否确认返回上一页面?`,
onOk: async () => {
back();
@ -79,58 +97,86 @@ function handleBack() {
async function handleSave() {
try {
await fillResultCardRef.value.verify();
} catch (error) {
message.error("请完成必填项的填写");
return;
}
try {
let form = fillResultCardRef.value.getFormData();
const form = await fillResultCardRef.value.getFormData();
console.log(form);
let data = await Apis.biddingResult.post_save({
if (!form) {
return;
}
{
const tempFileList = form.fileList || [];
let tempFiles: any = [];
if (tempFileList.length > 0) {
tempFiles = await fileUploader.upload(tempFileList, { source: 'ht' });
}
if (tempFiles) {
form.biddingResult.fileUuid = (
tempFiles.map((item) => item.fileUuid) || []
).join(',');
}
}
const data = await Apis.biddingResult.post_save({
params: {
contractId: businseeData.value.contractId,
projectId: businseeData.value.projectId,
// isKj: currData.value.frameProtocol === '1' ? '' : '',
isKj: '是',
},
data: form,
});
submitGuid.value = data.guid;
message.success("保存成功");
message.success('保存成功');
Modal.confirm({
title: "提示",
content: "保存成功!是否进行提交?提交后数据将不可变更",
title: '提示',
content: '保存成功!是否进行提交?提交后数据将不可变更',
onOk: () => {
handleSubmit("openModal");
handleSubmit('openModal');
},
onCancel: () => {
back();
// back();
},
});
} catch (error) {
logger.error("选商结果填报保存失败", error);
logger.error('选商结果填报保存失败', error);
}
}
async function handleSubmit(type: "openModal" | "submit") {
if (type === "openModal") {
const nodeInfo = ref<any>({});
const chooseUserIds = ref([]);
async function handleSubmit(type: 'openModal' | 'submit') {
if (type === 'openModal') {
//
let tempNodeInfo = await Apis.biddingResult.get_getFlowNodeUserConfig({
params: { guid: submitGuid.value },
});
nodeInfo.value = tempNodeInfo = tempNodeInfo.rows[0];
chooseUserModalApi.setData({
title: "选择审批人",
title: `选择${tempNodeInfo.name}(${tempNodeInfo.selectMode})`,
limitMultipleNum: tempNodeInfo.selectMode === '多选' ? 10 : 1,
});
chooseUserModalApi.open();
}
if (type === "submit") {
if (type === 'submit') {
isLoading.value = true;
chooseUserIds.value = selectUsers.value.map((item) => item.ACCOUNT_ID);
try {
// await Apis.selectMerchantsBasicInfo.post_flowStart({
// data: {
// guid: selectMerchantsBasicInfoId.value,
// assigneeList: selectUsers.value.map((item) => item.ACCOUNT_ID),
// },
// });
message.success("提交成功");
await Apis.selectMerchantsBasicInfo.post_flowStart({
data: {
guid: selectMerchantsBasicInfoId.value,
assigneeList: selectUsers.value.map((item) => item.ACCOUNT_ID),
},
});
message.success('提交成功');
back();
} catch (error) {
message.error("提交失败,请稍候再试");
logger.error("合同选商结果提交", error);
message.error('提交失败,请稍候再试');
logger.error('合同选商结果提交', error);
} finally {
isLoading.value = false;
}
@ -140,28 +186,24 @@ async function handleSubmit(type: "openModal" | "submit") {
onMounted(async () => {
isLoading.value = true;
try {
const contractReferTypeData = await Apis.contractReferType.get_list({
params: {},
});
contractTypeData.value = contractReferTypeData.rows || [];
if (id.value) {
const contract: any = await Apis.contractBaseInfo.get_getOne({
params: { guid: id.value },
params: { contractId: id.value },
});
currData.value = contract;
const business: any = await Apis.selectMerchantsBasicInfo.get_getOne({
params: { contractId: contract.contractId },
});
business.frameProtocol = contract.frameProtocol;
businseeData.value = business;
// xGridRef.value!.reloadColumn(getColumns());
}
} catch (error) {
logger.error("获取合同信息出错", error);
logger.error('获取合同信息出错', error);
Modal.error({
title: "提示",
content: "当前合同信息不存在",
title: '提示',
content: '当前合同信息不存在',
onOk() {},
});
} finally {
@ -172,21 +214,54 @@ onMounted(async () => {
<template>
<Page ref="pageRef" content-class="h-full flex flex-col">
<ChooseUserModal class="w-[950px]" multiple @confirm="handleChooseUserConfirm" />
<ChooseUserModal
class="w-[950px]"
multiple
@confirm="handleChooseUserConfirm"
/>
<a-affix :offset-top="0" :style="{ zIndex: 50 }" :target="() => pageRef.bodyRef">
<a-affix
:offset-top="0"
:style="{ zIndex: 50 }"
:target="() => pageRef.bodyRef"
>
<div class="flex w-full flex-row bg-white pl-1 pt-1">
<a-space class="flex-1">
<template v-if="!isLoading">
<vben-button variant="primary" @click="handleSave()"> 保存 </vben-button>
<vben-button :disabled="!submitGuid" variant="primary" @click="handleSave()">
<vben-button variant="primary" @click="handleSave()">
保存
</vben-button>
<vben-button
:disabled="!submitGuid"
variant="primary"
@click="handleSave()"
>
提交
</vben-button>
<vben-button
v-if="['paApproval'].includes(currData.step) && taskId"
:disabled="!auditId"
variant="primary"
@click="handleAudit('openAccessModal')"
>
通过
</vben-button>
<vben-button
v-if="['paApproval'].includes(currData.step) && taskId"
:disabled="!auditId"
variant="destructive"
@click="handleAudit('openRejectModal')"
>
退回
</vben-button>
</template>
<vben-button variant="secondary" @click="handleBack()"> 返回 </vben-button>
<vben-button variant="secondary" @click="handleBack()">
返回
</vben-button>
</a-space>
<vben-button variant="secondary" @click="handleFold()">
一键{{ isFold ? "展开" : "收起" }}
一键{{ isFold ? '展开' : '收起' }}
</vben-button>
</div>
</a-affix>
@ -204,7 +279,12 @@ onMounted(async () => {
<FileCard file-uuids="" />
</a-collapse-panel>
<a-collapse-panel key="4" class="w-full" header="审批信息">
<a-collapse-panel
v-if="flowInstanceId"
key="4"
class="w-full"
header="审批信息"
>
<AuditNodeTable :flow-instance-id="flowInstanceId" />
</a-collapse-panel>
@ -212,10 +292,41 @@ onMounted(async () => {
<FillResultCard
v-if="businseeData.projectId"
ref="fillResultCardRef"
:businsee-data="businseeData"
:contract-id="businseeData.contractId"
:project-id="businseeData.projectId"
/>
</a-collapse-panel>
<a-collapse-panel key="6" class="w-full" header="招标相关资料上传">
<a-form
ref="formRef"
:label-col="{ style: { width: '120px' } }"
:model="form"
>
<a-form-item label="合同附件" name="fileList">
<a-upload
v-model:file-list="form.fileList"
:before-upload="() => false"
:max-count="3"
accept=".pdf,.ppt,.pptx"
name="file"
@change="handleChange"
>
<a-button v-if="!readOnly">
<MdiUpload />
点击上传
</a-button>
<div
v-if="readOnly && form.fileList.length === 0"
class="text-gray-700"
>
无附件
</div>
</a-upload>
</a-form-item>
</a-form>
</a-collapse-panel>
</a-collapse>
</Page>
</template>

View File

@ -37,6 +37,8 @@ const data = ref({
});
const checkRecords = ref([]);
const checkRecordIds = ref([]);
const limitMultipleNum = ref(1);
const searchBinding = ref({
@ -63,8 +65,13 @@ const gridOptions = reactive(
...searchRef.value.formData,
},
});
for (const row of checkRecords.value) {
xGridRef.value!.setCheckboxRow(row, true);
for (const row of checkRecordIds.value) {
for (const item of result.rows || []) {
if (item.guid === row) {
xGridRef.value!.setCheckboxRow(item, true);
checkRecords.value.push(item);
}
}
}
return result;
},
@ -82,11 +89,10 @@ const gridOptions = reactive(
//
reserve: true,
checkMethod: ({ row }) => {
const checkRecordIds =
checkRecords.value.map((item) => item.guid) || [];
const tempCheckRecordIds = checkRecordIds.value || [];
if (
checkRecords.value.length < limitMultipleNum.value ||
checkRecordIds.includes(row.guid)
checkRecordIds.value.length < limitMultipleNum.value ||
tempCheckRecordIds.includes(row.guid)
) {
return true;
}
@ -115,6 +121,7 @@ function handleCheckboxChange(e) {
if (e.checked) {
const existingIds = new Set(checkRecords.value.map((item) => item.guid));
checkRecordIds.value = [...checkRecordIds.value, e.row.guid];
if (!existingIds.has(e.row.guid)) {
checkRecords.value = [...checkRecords.value, e.row];
@ -133,11 +140,16 @@ function handleCloseTag(row) {
checkRecords.value = checkRecords.value.filter(
(item) => item.guid != row.guid,
);
checkRecordIds.value = checkRecordIds.value.filter(
(item) => item != row.guid,
);
xGridRef.value?.setCheckboxRow(row, false);
}
const title = ref('选择合同相对人');
// id
const existIds = ref([]);
const [BaseModal, baseModalApi] = useVbenModal({
onOpenChange(isOpen: boolean) {
if (isOpen) {
@ -150,6 +162,8 @@ const [BaseModal, baseModalApi] = useVbenModal({
limitMultipleNum.value = data.value.limitMultipleNum;
}
console.log(data.value.guids);
checkRecordIds.value = data.value.guids || [];
existIds.value = data.value.guids || [];
const rows: any = [];
for (const element of checkRecords.value) {
if (data.value.guids.includes(element.guid)) {
@ -160,8 +174,12 @@ const [BaseModal, baseModalApi] = useVbenModal({
}
},
onConfirm() {
console.info('onConfirm');
emit('confirm', checkRecords.value);
console.info('onConfirm', checkRecords.value);
// id
const result = checkRecords.value.filter(
(item) => !existIds.value.includes(item.guid),
);
emit('confirm', result);
baseModalApi.close();
},
onCancel() {

View File

@ -1,14 +1,14 @@
<script setup lang="ts">
import type { VxeGridPropTypes } from 'vxe-table';
import { nextTick, onMounted, reactive, ref, watch } from 'vue';
import { message } from 'ant-design-vue';
import { logger } from 'common-utils';
import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
import { getAuditInfoColumns } from '#/views/contract/schema';
import { DICT_TYPE, getDictObj, getDictOptions } from '#/utils/dict';
import type { VxeGridPropTypes } from 'vxe-table';
import { useRender } from '#/hooks/useRender';
import { useVxeTable } from '#/hooks/vxeTable';
import { DICT_TYPE, getDictObj } from '#/utils/dict';
const props = withDefaults(
defineProps<{
@ -62,7 +62,7 @@ function getColumns(): any {
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
height: '200px',
minHeight: '120px',
columns: getColumns(),
data: [],
toolbarConfig: {

View File

@ -1,5 +1,6 @@
<script setup lang="ts">
import { nextTick, onMounted, reactive, ref } from 'vue';
import { logger } from 'common-utils';
import { useVxeTable } from '#/hooks/vxeTable';
@ -25,7 +26,7 @@ const isLoading = ref(false);
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
height: '200px',
minHeight: '120px',
columns: getColumnsByFiles({ readOnly: true }),
data: [],
toolbarConfig: {

View File

@ -5,7 +5,7 @@ import dayjs, { type Dayjs } from 'dayjs';
import { DICT_TYPE, getDictOptions } from '#/utils/dict';
export function getFormSchema(params: any = {}) {
const { chooseCompanyModalApi, formRef, dictMap } = params || {};
const { chooseCompanyModalApi, formRef, dictMap, sqConsignPt } = params || {};
const disabledDate = (current: Dayjs) => {
const form = formRef.value.form;
@ -83,8 +83,12 @@ export function getFormSchema(params: any = {}) {
name: 'fs-dict-select',
vModel: 'value',
allowClear: false,
showSearch: true,
filterOption: (input, option) => {
return option.label.includes(input.toLowerCase());
},
dict: dict({
data: [],
data: sqConsignPt,
}),
},
},
@ -112,25 +116,27 @@ export function getFormSchema(params: any = {}) {
console.log(formRef.value.form);
chooseCompanyModalApi.setData({
title: '选择合同相对人',
guids: [formRef.value.form.providerId],
guids: formRef.value.form.providerId
? [formRef.value.form.providerId]
: [],
});
chooseCompanyModalApi.open();
},
},
rules: [{ required: true, message: '请选择合同相对人' }],
},
media: {
title: '公告发布方式',
key: 'media',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
},
},
isPerformDate: {
// media: {
// title: '公告发布方式',
// key: 'media',
// col: { span: 12 },
// component: {
// name: 'a-input',
// vModel: 'value',
// },
// },
performType: {
title: '履行期限',
key: 'isPerformDate',
key: 'performType',
col: { span: 24 },
component: {
name: 'a-input',
@ -150,11 +156,11 @@ export function getFormSchema(params: any = {}) {
<a-form-item class="!mb-0 inline-block">
<a-radio-group
options={options1}
v-model:value={form.isPerformDate}
v-model:value={form.performType}
/>
</a-form-item>
<div class="w-2"></div>
{form.isPerformDate === '0' && (
{form.performType === '0' && (
<div class="flex items-center">
<span class="mx-1"></span>
<a-form-item class="!mb-0 inline-block">
@ -210,9 +216,9 @@ export function getFormSchema(params: any = {}) {
vModel: 'value',
},
},
projectNum9: {
disputeMethod: {
title: '纠纷解决方式',
key: 'projectNum9',
key: 'disputeMethod',
col: { span: 16 },
component: {
name: 'fs-dict-radio',

View File

@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, nextTick, onMounted, reactive, ref } from 'vue';
import { computed, nextTick, onMounted, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { Page, useVbenModal } from '@vben/common-ui';
@ -12,11 +12,16 @@ import {
type UploadFile,
} from 'ant-design-vue';
import { logger } from 'common-utils';
import { merge } from 'lodash-es';
import Apis from '#/api';
import temporaryFormModal from '#/components/temporary-form-modal/temporary-form-modal.vue';
import { useVxeTable } from '#/hooks/vxeTable';
import { DICT_TYPE, getDictDatasAsync } from '#/utils/dict';
import { FileUploader } from '#/utils/file';
import AuditNodeTable from '#/views/contract/components/audit-node-table/audit-node-table.vue';
import BasisTable from '#/views/contract/components/basis-table/basis-table.vue';
import ApprovalCard from '#/views/contract/iframe-info/components/info-approval/approval-card.vue';
import chooseUserModal from '#/views/system/user/choose-user-modal.vue';
import chooseCompanyModal from '../../company/list/choose-company-modal.vue';
@ -33,15 +38,22 @@ const [ChooseCompanyModal, chooseCompanyModalApi] = useVbenModal({
connectedComponent: chooseCompanyModal,
});
const [TemporaryFormModal, temporaryFormModalApi] = useVbenModal({
connectedComponent: temporaryFormModal,
});
const fileUploader = new FileUploader({});
const router = useRouter();
const route = useRoute();
const id = ref(route.params.id);
const taskId = route.query.taskId;
const auditId = ref();
const pageRef = ref();
const formRef = ref();
const formRefByBaseInfo = ref();
const sbCtrBasePt = ref<any>({});
const isLoading = ref(false);
@ -56,38 +68,11 @@ const formBindingByBaseInfo = ref({
const formBinding = ref<any>(null);
function getColumns(): any {
return [
{ type: 'seq', title: '序号', width: 60 },
{ field: 'referenceName', title: '签约依据名称', minWidth: 150 },
{ field: 'referenceId', title: '签约依据编号', width: 200 },
{ field: 'attachments', title: '附件', width: 120 },
{
title: '操作',
width: 120,
slots: { default: 'operation' },
},
];
}
const contractData = ref<any>({});
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
height: '120px',
columns: getColumns(),
data: [],
toolbarConfig: {
enabled: false,
},
pagerConfig: {
enabled: false,
},
rowConfig: {
useKey: true,
isCurrent: false,
},
}),
);
const currData = ref({});
const sqConsignPt = ref<any>({});
const fileList = ref<UploadFile[]>([]);
@ -107,7 +92,7 @@ function handleBack() {
* 页面返回并关闭tab
*/
function back() {
router.replace('/contract/declaration/list');
router.replace('/contract/declaration/todo');
}
const handleChange = (info: UploadChangeParam) => {
@ -133,7 +118,7 @@ function handleDelete() {
});
}
const collapses = ['1', '2', '3', '4', '5'];
const collapses = ['1', '2', '3', '4', '5', '6'];
const collapseActiveKey = ref(collapses);
function areArraysEqualUnordered(arr1, arr2) {
if (arr1.length !== arr2.length) return false;
@ -158,8 +143,15 @@ async function handleChooseCompanyConfirm(e) {
});
}
const selectUsers = ref([]);
const chooseUserModalOpenType = ref<'audit' | 'reject' | 'submit'>('audit');
async function handleChooseUserConfirm(e) {
chooseUserModalApi.close();
if (chooseUserModalOpenType.value === 'submit') {
selectUsers.value = e;
handleSubmit('submit');
chooseUserModalApi.close();
return;
}
formRef.value.setFormData({
assigneeList: e.map((item) => item.ACCOUNT_ID),
@ -167,7 +159,6 @@ async function handleChooseUserConfirm(e) {
// isLoading.value = true;
}
function handleDownloadTemplate() {}
async function handleSave() {
isLoading.value = true;
@ -178,34 +169,34 @@ async function handleSave() {
const form = formRef.value.form;
//
// {
// const tempFileList = contractForm.fileList;
// let tempFiles: any = [];
// if (fileList.value && tempFileList.length > 0) {
// tempFiles = await fileUploader.upload(tempFileList, { source: 'ht' });
// }
// console.log(tempFiles);
// if (tempFiles) {
// contractForm.fileUuid = (
// tempFiles.map((item) => item.fileUuid) || []
// ).join(',');
// }
// }
//
{
const tempFileList = fileList.value;
let tempFiles: any = [];
if (tempFileList && tempFileList.length > 0) {
tempFiles = await fileUploader.upload(tempFileList, { source: 'ht' });
}
console.log(tempFiles);
if (tempFiles) {
form.fileUuid = (tempFiles.map((item) => item.fileUuid) || []).join(
',',
);
}
}
//
// {
// const tempFileList = fileList.value;
// let tempFiles: any = [];
// if (fileList.value && tempFileList.length > 0) {
// tempFiles = await fileUploader.upload(tempFileList, { source: 'ht' });
// }
// if (tempFiles) {
// bussinessForm.fileUuid = (
// tempFiles.map((item) => item.fileUuid) || []
// ).join(',');
// }
// }
//
{
const tempFileList = fileListByProfile.value;
let tempFiles: any = [];
if (tempFileList && tempFileList.length > 0) {
tempFiles = await fileUploader.upload(tempFileList, { source: 'ht' });
}
if (tempFiles) {
form.fileUuid2 = (tempFiles.map((item) => item.fileUuid) || []).join(
',',
);
}
}
console.log('提交表单', form);
@ -222,21 +213,34 @@ async function handleSave() {
// newForm.fileUuid = (files.map((item) => item.fileUuid) || []).join(',')
// }
form.ctrBaseId = form.contractId;
form.ctrName = form.contractName;
delete form.guid;
const data = await Apis.sbCtrBasePt.post_save({ data: form });
form.ctrBaseId = contractData.value.contractId;
form.ctrName = contractData.value.contractName;
// delete form.guid;
const guid = form.guid;
const data = await Apis.sbCtrBasePt.post_save({
data: {
...merge(form, contractData.value),
guid,
inputDeptId: contractData.value.inputDepartId,
inputDeptName: contractData.value.inputDepartName,
inputDepartUserId: contractData.value.inputUserId,
inputOpinion: contractData.value.inputOpinion,
inputPerson: contractData.value.inputPerson,
inputUnitId: contractData.value.inputUnitId,
inputUnitName: contractData.value.inputUnitName,
inputUserId: contractData.value.inputUserId,
},
});
id.value = data.value;
message.success('保存成功');
Modal.confirm({
title: '提示',
content: '保存成功!是否进行提交?',
onOk: () => {
handleSubmit();
handleSubmit('openModal');
},
onCancel: () => {
back();
// back();
},
});
} catch (error) {
@ -247,23 +251,125 @@ async function handleSave() {
}
}
async function handleSubmit() {
try {
await Apis.sbCtrBasePt.post_submit({ params: { guid: id.value } });
message.success('提交成功');
back();
} catch (error) {
message.error('提交失败,请稍候再试');
logger.error('申报结果报错失败', error);
} finally {
isLoading.value = false;
async function handleSubmit(type: 'openModal' | 'submit') {
if (type === 'openModal') {
chooseUserModalOpenType.value = 'submit';
chooseUserModalApi.setData({
title: '选择审批人',
});
chooseUserModalApi.open();
}
if (type === 'submit') {
try {
await Apis.sbCtrBasePt.post_start({
data: {
guid: sbCtrBasePt.value.guid || id.value,
assigneeList: selectUsers.value.map((item) => item.ACCOUNT_ID),
},
});
message.success('提交成功');
back();
} catch (error) {
message.error('提交失败,请稍候再试');
logger.error('申报结果报错失败', error);
} finally {
isLoading.value = false;
}
}
}
const contractData = ref<any>({});
const businessData = ref<any>({});
const isTemporaryFormModalLoading = ref(false);
const currData = ref({});
async function handleAudit(
type: 'accessConfirm' | 'reject' | 'rejectConfirm',
data?: any,
) {
console.log(type);
console.log(route);
if (type === 'accessConfirm') {
Modal.confirm({
title: '提示',
content: '是否确认审核通过?',
onOk: async () => {
try {
await Apis.selectMerchantsBasicInfo.post_submit({
params: {
guid: sbCtrBasePt.value.guid,
},
data: {
appId: id.value,
taskId: route.query.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: '请输入退回原因' }],
},
},
},
});
temporaryFormModalApi.open();
},
});
}
if (type === 'rejectConfirm') {
isTemporaryFormModalLoading.value = true;
const comment = data.comment;
try {
await Apis.selectMerchantsBasicInfo.post_rollback({
params: {
guid: sbCtrBasePt.value.guid,
},
data: {
appId: sbCtrBasePt.value.guid,
taskId: route.query.taskId,
nodeId: '',
comment,
},
});
temporaryFormModalApi.close();
message.success('退回成功');
back();
} catch (error) {
logger.error('合同立项退回失败', error);
message.error('退回失败,请稍候再试');
} finally {
isTemporaryFormModalLoading.value = false;
}
}
}
onMounted(async () => {
isLoading.value = true;
@ -275,6 +381,13 @@ onMounted(async () => {
contractTypeData.value = contractReferTypeData.rows || [];
//
const userData = await Apis.sqConsignPt.get_SigningaAuthorizationSerch({
params: {},
});
sqConsignPt.value = userData.rows.map((item) => ({
label: item.userPerson,
value: item.userId,
}));
const dictMap = await getDictDatasAsync(
[
@ -289,6 +402,7 @@ onMounted(async () => {
chooseCompanyModalApi,
formRef,
dictMap,
sqConsignPt: sqConsignPt.value,
});
formBindingByBaseInfo.value.columns = getFormSchemaByBaseInfo({
contractTypeData: contractTypeData.value,
@ -298,23 +412,45 @@ onMounted(async () => {
const contract: any = await Apis.contractBaseInfo.get_getOne({
params: { contractId: id.value },
});
// contract = contract.rows[0];
if (contract && contract.contractId) {
contractData.value = contract;
const business: any = await Apis.selectMerchantsBasicInfo.get_getOne({
params: { contractId: contract.contractId },
//
let sbCtrBasePtData: any = await Apis.sbCtrBasePt.post_page({
params: { CTRBASEID: id.value },
// params: { ctrBaseId: '123456' },
});
console.log(business);
if (business.fileUuid) {
const files = await fileUploader.select(business.fileUuid);
business.fileList = files;
}
businessData.value = business;
sbCtrBasePtData.signUnitName = '克拉玛依市热力有限责任公司';
nextTick(() => {
formRefByBaseInfo.value.setFormData(contract);
formRef.value.setFormData(business);
});
if (sbCtrBasePtData.rows.length > 0) {
sbCtrBasePtData = sbCtrBasePtData.rows[0];
console.log(sbCtrBasePtData);
if (sbCtrBasePtData.fileUuid) {
const files = await fileUploader.select(sbCtrBasePtData.fileUuid);
sbCtrBasePtData.fileList = files;
}
sbCtrBasePtData.signUnitName = '克拉玛依市热力有限责任公司';
sbCtrBasePt.value = sbCtrBasePtData;
// -
if (sbCtrBasePtData.fileUuid) {
fileList.value = await fileUploader.select(
sbCtrBasePtData.fileUuid,
);
}
if (sbCtrBasePtData.fileUuid2) {
fileListByProfile.value = await fileUploader.select(
sbCtrBasePtData.fileUuid2,
);
}
nextTick(() => {
formRef.value.setFormData(sbCtrBasePtData);
});
}
} else {
throw new Error('当前合同信息不存在');
}
@ -352,6 +488,12 @@ onMounted(async () => {
@confirm="handleChooseUserConfirm"
/>
<TemporaryFormModal
v-model:loading="isTemporaryFormModalLoading"
class="w-[950px]"
@confirm="handleAudit('rejectConfirm', $event)"
/>
<a-affix
:offset-top="0"
:style="{ zIndex: 50 }"
@ -359,13 +501,35 @@ onMounted(async () => {
>
<div class="flex w-full flex-row bg-white pl-1 pt-1">
<a-space class="flex-1">
<vben-button variant="primary" @click="handleSave()">
<vben-button v-if="!taskId" variant="primary" @click="handleSave()">
保存
</vben-button>
<vben-button variant="primary" @click="handleSubmit()">
<vben-button
v-if="!taskId"
variant="primary"
@click="handleSubmit('openModal')"
>
送审
</vben-button>
<vben-button variant="destructive" @click="handleDelete()">
<vben-button
v-if="taskId"
variant="primary"
@click="handleAudit('accessConfirm')"
>
通过
</vben-button>
<vben-button
v-if="taskId"
variant="destructive"
@click="handleAudit('reject')"
>
退回
</vben-button>
<vben-button
v-if="sbCtrBasePt.flowInstanceId"
variant="destructive"
@click="handleDelete()"
>
废除
</vben-button>
<vben-button variant="secondary" @click="handleBack()">
@ -382,17 +546,11 @@ onMounted(async () => {
<div class="mx-auto overflow-auto py-2">
<a-collapse v-model:active-key="collapseActiveKey" :bordered="false">
<a-collapse-panel key="1" class="w-full" header="合同基本信息一">
<fs-form
ref="formRefByBaseInfo"
class="w-full"
v-bind="formBindingByBaseInfo"
/>
<ApprovalCard :info="contractData" />
</a-collapse-panel>
<a-collapse-panel key="2" class="w-full" header="签约依据">
<VxeGrid ref="xGridRef" v-bind="gridOptions" class="">
<template #toolbar_buttons></template>
</VxeGrid>
<BasisTable :basis-id="contractData.basisId" />
</a-collapse-panel>
<a-collapse-panel key="3" class="w-full" header="合同基本信息二">
@ -443,6 +601,15 @@ onMounted(async () => {
</a-form-item>
</a-form>
</a-collapse-panel>
<a-collapse-panel
v-if="sbCtrBasePt.flowInstanceId"
key="6"
class="w-full"
header="审批信息"
>
<AuditNodeTable :flow-instance-id="sbCtrBasePt.flowInstanceId" />
</a-collapse-panel>
</a-collapse>
</div>
</a-spin>

View File

@ -1,42 +1,54 @@
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';
export const PrimaryKey = 'guid';
import { useRender } from '#/hooks/useRender';
import { DICT_TYPE, getDictOptions } from '#/utils/dict';
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: 'ctrBaseId', title: '合同申报编号', width: 150 },
{ field: 'contractNumber', title: '合同编号', width: 100 },
{
field: 'ctrName', title: '合同名称', minWidth: 200, slots: {
default: 'contract-name-slot'
}
type: 'radio',
width: 40,
slots: { radio: 'radio_cell' },
align: 'center',
fixed: 'left',
},
{ field: 'objects', title: '合同标的', width: 150 },
{ field: 'CTR_BASE_ID', title: '合同申报编号', width: 150 },
{ field: 'CONTRACT_NUMBER', title: '合同编号', width: 100 },
{
field: 'objectsSum', title: '标的金额', width: 150, slots: {
field: 'CTR_NAME',
title: '合同名称',
minWidth: 200,
slots: {
default: 'contract-name-slot',
},
},
{ field: 'OBJECTS', title: '合同标的', width: 150 },
{
field: 'OBJECTS_SUM',
title: '标的金额',
width: 150,
slots: {
default: ({ row }) => {
return useRender.renderText(row.objectsSum, row.priceTypeName);
}
}
return useRender.renderText(row.OBJECTS_SUM, row.PRICE_TYPE_NAME);
},
},
},
{ field: 'inputPerson', title: '合同承办人', width: 120 },
{ field: 'providerName', title: '合同相对人名称', width: 150 },
{ field: 'contractSourceType', title: '合同来源', width: 100 },
{ field: 'choiceTypeName', title: '采购方式', width: 120 },
{ field: 'inputDeptName', title: '承办人部门', width: 120 },
{ field: 'inputDate', title: '承办时间', width: 150 }
]
{ field: 'INPUT_PERSON', title: '合同承办人', width: 120 },
{ field: 'PROVIDER_NAME', title: '合同相对人名称', width: 150 },
{ field: 'CONTRACT_SOURCE_TYPE', title: '合同来源', width: 100 },
{ field: 'CHOICE_TYPE_NAME', title: '采购方式', width: 120 },
{ field: 'INPUT_DEPT_NAME', title: '承办人部门', width: 120 },
{ field: 'INPUT_DATE', title: '承办时间', width: 150 },
];
}
export function getFormSchema(_params: any = {}) {
return {
initialForm: {
},
initialForm: {},
columns: {
ctrBaseId: {
title: '合同编号',
@ -79,32 +91,40 @@ export function getFormSchema(_params: any = {}) {
autoSearchTrigger: 'enter',
show: true,
render({ form }) {
//注意此处的v-model写法
// 注意此处的v-model写法
return (
<div class="flex">
<a-form-item class="inline-block !mb-0">
<a-input-number v-model:value={form.budgetSum1} class="!w-[120px]" placeholder=""/>
<a-form-item class="!mb-0 inline-block">
<a-input-number
class="!w-[120px]"
placeholder=""
v-model:value={form.budgetSum1}
/>
</a-form-item>
<span class="mx-1"></span>
<a-form-item class="inline-block !mb-0">
<a-input-number v-model:value={form.budgetSum2} class="!w-[120px]" placeholder=""/>
<a-form-item class="!mb-0 inline-block">
<a-input-number
class="!w-[120px]"
placeholder=""
v-model:value={form.budgetSum2}
/>
</a-form-item>
</div>
);
}
},
},
choiceType: {
title: "选商方式",
key: "choiceType",
title: '选商方式',
key: 'choiceType',
autoSearchTrigger: 'enter',
show: true,
component: {
name: "fs-dict-select",
vModel: "value",
name: 'fs-dict-select',
vModel: 'value',
allowClear: true,
class: 'min-w-[200px]',
dict: dict({
data: getDictOptions(DICT_TYPE.contract_selection_method)
data: getDictOptions(DICT_TYPE.contract_selection_method),
}),
},
},
@ -114,32 +134,42 @@ export function getFormSchema(_params: any = {}) {
autoSearchTrigger: 'enter',
show: true,
render({ form }) {
//注意此处的v-model写法
// 注意此处的v-model写法
return (
<div class="flex">
<a-form-item class="inline-block !mb-0">
<a-date-picker v-model:value={form.startDate} placeholder="" format="YYYY-MM-DD" value-format="YYYY-MM-DD" />
<a-form-item class="!mb-0 inline-block">
<a-date-picker
format="YYYY-MM-DD"
placeholder=""
v-model:value={form.startDate}
value-format="YYYY-MM-DD"
/>
</a-form-item>
<span class="mx-1"></span>
<a-form-item class="inline-block !mb-0">
<a-date-picker v-model:value={form.endDate} placeholder="" format="YYYY-MM-DD" value-format="YYYY-MM-DD" />
<a-form-item class="!mb-0 inline-block">
<a-date-picker
format="YYYY-MM-DD"
placeholder=""
v-model:value={form.endDate}
value-format="YYYY-MM-DD"
/>
</a-form-item>
</div>
);
}
},
},
fundDitch: {
title: "资金渠道",
key: "fundDitch",
title: '资金渠道',
key: 'fundDitch',
autoSearchTrigger: 'enter',
show: true,
component: {
name: "fs-dict-select",
vModel: "value",
name: 'fs-dict-select',
vModel: 'value',
allowClear: true,
class: 'min-w-[200px]',
dict: dict({
data: getDictOptions(DICT_TYPE.contract_funding_source)
data: getDictOptions(DICT_TYPE.contract_funding_source),
}),
},
},

View File

@ -1,22 +1,27 @@
<script setup lang="ts">
import { computed, onMounted, reactive, ref } from "vue";
import { useRouter } from "vue-router";
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 { Page } from '@vben/common-ui';
import {
MdiExport,
MdiRadioChecked,
MdiRadioUnchecked,
MdiUpdate,
} from '@vben/icons';
import { message } from "ant-design-vue";
import { message } from 'ant-design-vue';
import Apis from "#/api";
import { useVxeTable } from "#/hooks/vxeTable";
import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
import { getColumns, getFormSchema, PrimaryKey } from "./crud.tsx";
import { getColumns, getFormSchema, PrimaryKey } from './crud.tsx';
const router = useRouter();
const searchRef = ref();
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: "xGridRef" });
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
/** Hooks - 表格 */
const gridOptions = reactive(
@ -42,14 +47,14 @@ const gridOptions = reactive(
toolbarConfig: {
enabled: true,
},
})
}),
);
function handleEdit(record?: any) {
if (record && record[PrimaryKey]) {
router.push(`/contract/declaration/edit/${record.ctrBaseId}`);
router.push(`/contract/declaration/edit/${record.CONTRACT_ID}`);
} else {
router.push("/contract/declaration/edit");
router.push('/contract/declaration/edit');
}
}
@ -57,9 +62,9 @@ function handleExport() {
const $grid = xGridRef.value;
if ($grid) {
$grid.exportData({
type: "xlsx",
type: 'xlsx',
});
message.success("导出成功");
message.success('导出成功');
}
}
@ -83,13 +88,13 @@ function handleCellClick({ row }) {
}
onMounted(() => {
triggerProxy("reload");
triggerProxy('reload');
});
const searchForm = ref({
...getFormSchema(),
onSearch(context: any) {
triggerProxy("reload");
triggerProxy('reload');
},
});
</script>
@ -120,7 +125,11 @@ const searchForm = ref({
</fs-search>
<div class="min-h-300px flex-1">
<vxe-grid ref="xGridRef" v-bind="gridOptions" @cell-click="handleCellClick">
<vxe-grid
ref="xGridRef"
v-bind="gridOptions"
@cell-click="handleCellClick"
>
<template #toolbar_buttons>
<a-space>
<vben-button
@ -146,8 +155,11 @@ const searchForm = ref({
</template>
<template #contract-name-slot="{ row }">
<span class="text-blue cursor-pointer hover:underline" @click="toDetail(row)">
{{ row.ctrName }}
<span
class="text-blue cursor-pointer hover:underline"
@click="toDetail(row)"
>
{{ row.CTR_NAME }}
</span>
</template>

View File

@ -99,12 +99,49 @@ function toDetail(row) {
async function handlePrint(row, type: string) {
const hideLoading = message.loading('加载中', 0);
console.log(row);
try {
const form: any = {};
await Apis.qdSign.get_printApprove({
params: form,
});
if (type === 'xs') {
await Apis.qdSign.get_printApprove({
params: {
modelId: '1',
caseId: row.ctrBaseId,
},
config: {
meta: {
responseType: 'blob',
},
},
});
}
if (type === 'qy') {
await Apis.qdSign.get_printApprove({
params: {
modelId: '2',
caseId: row.ctrBaseId,
},
config: {
meta: {
responseType: 'blob',
},
},
});
}
if (type === 'wb') {
await Apis.qdSign.get_textPrint({
params: {
ctrBaseId: row.ctrBaseId,
},
config: {
meta: {
responseType: 'blob',
},
},
});
}
message.success('文件已下载');
} catch (error) {
message.error('文件下载失败');
logger.error('打印失败', error);
} finally {
hideLoading();

View File

@ -1,15 +1,35 @@
<script setup lang="ts">
import { watch } from 'vue';
import { DICT_TYPE, getDictObj } from '#/utils/dict';
import FileCard from '#/views/contract/components/file-card/file-card.vue';
withDefaults(
// 使 withDefaults defineProps props
const props = withDefaults(
defineProps<{
info: any;
}>(),
{
info: () => {},
info: () => ({}), //
},
);
// info
watch(
() => props.info,
async (newInfo) => {
if (newInfo && Object.keys(newInfo).length > 0) {
// // ,
// console.log('info ...');
// // info
// const updatedData = await fetchData();
// // info
// Object.assign(props.info, updatedData);
// console.log('info :', props.info);
}
},
{ immediate: true }, // immediate: true
);
</script>
<template>
@ -23,10 +43,10 @@ withDefaults(
{{ info.contractName }}
</a-descriptions-item>
<a-descriptions-item :span="1" label="合同类别">
{{ info.contractName }}
{{ info.ctrTypeName }}
</a-descriptions-item>
<a-descriptions-item :span="1" label="二级类别">
{{ info.contractName }}
{{ info.ctrTwoTypeName }}
</a-descriptions-item>
<a-descriptions-item :span="1" label="框架协议">
{{ getDictObj(DICT_TYPE.common_whether, info.frameProtocol)?.label }}
@ -41,11 +61,12 @@ withDefaults(
{{ getDictObj(DICT_TYPE.contract_funding_source, info.fundDitch)?.label }}
</a-descriptions-item>
<a-descriptions-item label="预算金额">
{{ `${info.budgetSum || ''} ${info.priceTypeName || ''}` }}
<!-- {{ `${info.budgetSum || ''} ${info.priceTypeName || ''}` }} -->
{{ `${info.budgetSum || ''} ${'元'}` }}
</a-descriptions-item>
<a-descriptions-item :span="2" label="组织形式">
{{
getDictObj(DICT_TYPE.contract_organization_form, info.organiza?.label)
getDictObj(DICT_TYPE.contract_organization_form, info.organiza)?.label
}}
</a-descriptions-item>
<a-descriptions-item :span="3" label="相关附件">

View File

@ -1,21 +1,19 @@
<script setup lang="ts">
import { nextTick, onMounted, reactive, ref } from 'vue';
import { onMounted, ref } from 'vue';
import { message } from 'ant-design-vue';
import { logger } from 'common-utils';
import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
import { FileUploader } from '#/utils/file';
import { getAuditInfoColumns } from '#/views/contract/schema';
import ApprovalCard from '#/views/contract/iframe-info/components/info-approval/approval-card.vue';
import AuditNodeTable from '#/views/contract/components/audit-node-table/audit-node-table.vue';
import BasisTable from '#/views/contract/components/basis-table/basis-table.vue';
import ApprovalCard from '#/views/contract/iframe-info/components/info-approval/approval-card.vue';
const props = withDefaults(
defineProps<{
contractId?: string;
// flowInstanceId
flowInstanceId: string;
contractId?: string;
id?: string;
}>(),
{
@ -25,11 +23,6 @@ const props = withDefaults(
},
);
const { xGridRef, gridProps } = useVxeTable({ ref: 'xGridRef' });
const { xGridRef: xGridRefByAuditInfo } = useVxeTable({
ref: 'xGridRefByAuditInfo',
});
const currData = ref<any>({});
const isLoading = ref(false);
@ -66,15 +59,20 @@ onMounted(async () => {
<div class="flex h-full w-full flex-col">
<a-collapse v-model:active-key="collapseActiveKey">
<a-collapse-panel key="1" class="w-full" header="基本信息">
<ApprovalCard :info="currData"></ApprovalCard>
<ApprovalCard :info="currData" />
</a-collapse-panel>
<a-collapse-panel key="2" class="w-full" header="签约依据信息">
<BasisTable :basis-id="currData.basisId" />
</a-collapse-panel>
<a-collapse-panel key="3" class="w-full" header="审批信息">
<AuditNodeTable :flow-instance-id="props.flowInstanceId" />
<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>

View File

@ -1,68 +1,206 @@
<script setup lang="ts">
import { DICT_TYPE, getDictObj, getDictOptions } from "#/utils/dict";
import FileCard from "#/views/contract/components/file-card/file-card.vue";
import { onMounted, ref } from 'vue';
withDefaults(
import Apis from '#/api';
import { DICT_TYPE, getDictObj } from '#/utils/dict';
const props = withDefaults(
defineProps<{
info: any;
}>(),
{
info: () => {},
}
},
);
const bidList = ref<any[]>([]);
const providerPtList = ref<any[]>([]);
onMounted(async () => {
// console.log(info.value);
const info = props.info;
//
//
if (info.contractId) {
//
if (info.frameProtocol === '1') {
const bidData = await Apis.bidding.get_list({
params: {
projectId: info.projectId,
contractId: info.contractId,
},
});
bidData.rows.forEach((bid) => {
bid.providerList = [];
});
bidList.value = bidData.rows;
}
//
const providerData = await Apis.contractRecommendProvider.get_list({
params: {
contractId: info.contractId,
},
});
if (info.frameProtocol === '0') {
providerPtList.value = providerData.rows.filter(
(item) => item.phaseSeq === 99_999,
);
}
if (info.frameProtocol === '1') {
bidList.value.forEach((bid) => {
bid.providerList = providerData.rows;
});
}
}
});
</script>
<template>
<a-descriptions title="" size="small" :labelStyle="{ width: '150px' }" bordered>
<a-descriptions-item label="项目" :span="3">
<a-descriptions
v-if="info.contractId"
:label-style="{ width: '150px' }"
bordered
size="small"
title=""
>
<a-descriptions-item :span="3" label="项目">
{{ info.projectNum }}
</a-descriptions-item>
<a-descriptions-item label="项目类别" :span="1">
<a-descriptions-item :span="1" label="项目类别">
{{ getDictObj(DICT_TYPE.contract_project_type, info.projectProp)?.label }}
</a-descriptions-item>
<a-descriptions-item label="项目名称" :span="1">
<a-descriptions-item :span="1" label="项目名称">
{{ info.projectName }}
</a-descriptions-item>
<a-descriptions-item label="商务计价方式" :span="1">
<a-descriptions-item :span="1" label="商务计价方式">
{{ getDictObj(DICT_TYPE.contract_price_style, info.priceStyleId)?.label }}
</a-descriptions-item>
<a-descriptions-item label="备注" :span="3">
{{ info.remark || "无" }}
<a-descriptions-item :span="3" label="备注">
{{ info.remark || '无' }}
</a-descriptions-item>
<a-descriptions-item label="选商方式" :span="1">
{{ getDictObj(DICT_TYPE.contract_selection_method, info.choiceType)?.label }}
<a-descriptions-item :span="3" label="选商方式">
{{
getDictObj(DICT_TYPE.contract_selection_method, info.choiceType)?.label
}}
</a-descriptions-item>
<a-descriptions-item label="选商方式说明" :span="3">
{{ info.choiceReason || "无" }}
<a-descriptions-item :span="3" label="选商方式说明">
{{ info.choiceReason || '无' }}
</a-descriptions-item>
<a-descriptions-item label="资质要求" :span="3">
{{ info.qualificReq || "无" }}
<a-descriptions-item :span="3" label="资质要求">
{{ info.qualificReq || '无' }}
</a-descriptions-item>
<a-descriptions-item label="受托招标代理">
{{ (info.budgetSum || "") + " " + (info.priceTypeName || "") }}
<a-descriptions-item :span="3" label="受托招标代理">
{{ `${info.budgetSum || ''} ${info.priceTypeName || ''}` }}
</a-descriptions-item>
<a-descriptions-item label="推荐供应商" :span="3">
{{ info.stockPlanMx || "无" }}
<a-descriptions-item
v-if="info.frameProtocol === '0'"
:span="3"
label="推荐供应商"
>
<div class="w-full">
<vxe-table :data="providerPtList" size="mini">
<vxe-column field="providerName" title="供应商名称">
<template #default="{ row }">
{{ row.providerName }}
</template>
</vxe-column>
<vxe-column field="qualification" title="资质情况">
<template #default="{ row }">
{{ row.aptitudeName }}
</template>
</vxe-column>
<vxe-column field="contactPerson" title="联系人">
<template #default="{ row }">
{{ row.contactPerson }}
</template>
</vxe-column>
<vxe-column field="contactPhone" title="联系电话">
<template #default="{ row }">
{{ row.contactPhone }}
</template>
</vxe-column>
<vxe-column field="remarks" title="备注">
<template #default="{ row }">
{{ row.remarks }}
</template>
</vxe-column>
</vxe-table>
</div>
</a-descriptions-item>
<a-descriptions-item label="项目范围" :span="3">
{{ info.projectRange || "无" }}
<a-descriptions-item
v-if="info.frameProtocol === '1'"
:span="3"
label="标段信息"
>
<template v-for="bid in bidList" :key="bid.id">
<vxe-table :data="[bid]" size="mini">
<vxe-column field="phaseName" title="标段名称">
<template #default="{ row }">
{{ row.phaseName }}
</template>
</vxe-column>
<vxe-column field="phaseMoney" title="预算金额">
<template #default="{ row }"> {{ row.phaseMoney }} </template>
</vxe-column>
<vxe-column field="phaseDesc" title="标段范围说明">
<template #default="{ row }">
{{ row.phaseDesc }}
</template>
</vxe-column>
</vxe-table>
<vxe-table :data="bid.providerList" size="mini">
<vxe-column field="providerName" title="供应商名称">
<template #default="{ row }">
{{ row.providerName }}
</template>
</vxe-column>
<vxe-column field="qualification" title="资质情况">
<template #default="{ row }">
{{ row.aptitudeName }}
</template>
</vxe-column>
<vxe-column field="contactPerson" title="联系人">
<template #default="{ row }">
{{ row.contactPerson }}
</template>
</vxe-column>
<vxe-column field="contactPhone" title="联系电话">
<template #default="{ row }">
{{ row.contactPhone }}
</template>
</vxe-column>
<vxe-column field="remarks" title="备注">
<template #default="{ row }">
{{ row.remarks }}
</template>
</vxe-column>
</vxe-table>
</template>
</a-descriptions-item>
<a-descriptions-item label="项目内容" :span="3">
{{ info.projectContent || "无" }}
<a-descriptions-item :span="3" label="项目范围">
{{ info.projectRange || '无' }}
</a-descriptions-item>
<a-descriptions-item label="工期/质量要求" :span="3">
{{ info.quality || "无" }}
<a-descriptions-item :span="3" label="项目内容">
{{ info.projectContent || '无' }}
</a-descriptions-item>
<a-descriptions-item label="工程量(采购量)" :span="3">
{{ info.stockNums || "无" }}
<a-descriptions-item :span="3" label="工期/质量要求">
{{ info.quality || '无' }}
</a-descriptions-item>
<a-descriptions-item label="计划投资明细" :span="3">
{{ info.stockPlanMx || "无" }}
<a-descriptions-item :span="3" label="工程量(采购量)">
{{ info.stockNums || '无' }}
</a-descriptions-item>
<a-descriptions-item :span="3" label="计划投资明细">
{{ info.stockPlanMx || '无' }}
</a-descriptions-item>
</a-descriptions>
<a-empty v-else :image="simpleImage" />
</template>

View File

@ -1,29 +1,22 @@
<script setup lang="ts">
import { nextTick, onMounted, reactive, ref } from 'vue';
import { onMounted, ref } from 'vue';
import { useRoute } from 'vue-router';
import { Modal } from 'ant-design-vue';
import { Empty, Modal } from 'ant-design-vue';
import { logger } from 'common-utils';
import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
import { FileUploader } from '#/utils/file';
import {
getAuditInfoColumns,
getColumnsByFiles,
} from '#/views/contract/schema';
import { getFormSchema } from '../info-approval/curd';
import { getFormSchemaByBusiness } from './curd';
import ApprovalCard from '#/views/contract/iframe-info/components/info-approval/approval-card.vue';
import AuditNodeTable from '#/views/contract/components/audit-node-table/audit-node-table.vue';
import FileCard from '#/views/contract/components/file-card/file-card.vue';
import ApprovalCard from '#/views/contract/iframe-info/components/info-approval/approval-card.vue';
import BusinessCard from '#/views/contract/iframe-info/components/info-business/business-card.vue';
const props = withDefaults(
defineProps<{
flowInstanceId: string;
contractId?: string;
flowInstanceId: string;
id?: string;
}>(),
{
@ -33,6 +26,8 @@ const props = withDefaults(
},
);
const simpleImage = Empty.PRESENTED_IMAGE_SIMPLE;
const { xGridRef, gridProps } = useVxeTable({ ref: 'xGridRef' });
const { xGridRef: xGridRefByAuditInfo } = useVxeTable({
ref: 'xGridRefByAuditInfo',
@ -70,6 +65,7 @@ onMounted(async () => {
const business: any = await Apis.selectMerchantsBasicInfo.get_getOne({
params: { contractId: contract.contractId },
});
business.frameProtocol = contract.frameProtocol;
businseeData.value = business;
// xGridRef.value!.reloadColumn(getColumns());
}
@ -88,7 +84,10 @@ onMounted(async () => {
<template>
<div class="flex h-full w-full flex-col">
<a-collapse v-model:active-key="collapseActiveKey">
<a-collapse
v-if="!isLoading && businseeData.contractId"
v-model:active-key="collapseActiveKey"
>
<a-collapse-panel key="1" class="w-full" header="合同基本信息">
<ApprovalCard :info="currData" />
</a-collapse-panel>
@ -98,13 +97,23 @@ onMounted(async () => {
</a-collapse-panel>
<a-collapse-panel key="3" class="w-full" header="招标文件">
<FileCard :fileUuids="''"></FileCard>
<FileCard file-uuids="" />
</a-collapse-panel>
<a-collapse-panel key="4" class="w-full" header="审批信息">
<a-collapse-panel
v-if="props.flowInstanceId"
key="4"
class="w-full"
header="审批信息"
>
<AuditNodeTable :flow-instance-id="props.flowInstanceId" />
</a-collapse-panel>
</a-collapse>
<a-empty v-if="!isLoading && !businseeData.contractId" :image="simpleImage">
<template #description>
<h3 class="text-center text-red-500">无合同选商信息</h3>
</template>
</a-empty>
</div>
</template>

View File

@ -72,9 +72,9 @@ const tabList = [
];
onMounted(() => {
// if (type) {
// tabKey.value = type;
// }
if (type) {
tabKey.value = type;
}
if (!type || !id) {
console.warn('缺少参数');
@ -90,7 +90,7 @@ onMounted(() => {
:is="item.component"
:id="id"
:contract-id="contractId"
:flowInstanceId="flowInstanceId"
:flow-instance-id="flowInstanceId"
/>
</a-tab-pane>
</a-tabs>

View File

@ -4,9 +4,6 @@ import { h } from 'vue';
import { Tooltip } from 'ant-design-vue';
import { DICT_TYPE, getDictObj } from '#/utils/dict';
import { useRender } from '#/hooks/useRender';
export const PrimaryKey = 'guid';
/** 获取待办/已办列表的列 */
@ -104,7 +101,12 @@ export function getAuditInfoColumns(
title: '任务名称',
minWidth: 200,
},
{ field: 'assigneeId', title: '审批人', width: 150 },
{
field: 'assigneeId',
title: '审批人',
width: 150,
slots: { default: ({ row }) => row.userName || row.assigneeId },
},
{ field: 'startTime', title: '送审时间', width: 150 },
{ field: 'endTime', title: '审批时间', width: 150 },
{ field: 'type', title: '审批状态', width: 100 },

View File

@ -372,11 +372,16 @@ onMounted(async () => {
>
保存
</vben-button>
<vben-button
v-if="!id || currData.step === 'edit' || !currData.taskId"
variant="primary"
@click="handleSubmit('openModal')"
>
<vben-button variant="primary" @click="handleSubmit('openModal')">
提交
</vben-button>
<vben-button variant="primary" @click="handleSubmit('openModal')">
签约审批表打印
</vben-button>
<vben-button variant="primary" @click="handleSubmit('openModal')">
合同文本打印
</vben-button>
<vben-button variant="primary" @click="handleSubmit('openModal')">
提交
</vben-button>
<vben-button

View File

@ -10,6 +10,7 @@ import {
CardTitle,
VbenButton,
} from '@vben-core/shadcn-ui';
import { logger } from 'common-utils';
defineOptions({
name: 'WorkbenchTodo',
@ -29,6 +30,29 @@ interface Props {
function handleViewAll() {
router.push('/user/todo');
}
function toDetail(type: string, id: string, row?: any) {
console.log(type, row);
if (['contractSetup', 'contractSetupAbolish'].includes(type)) {
router.push(`/contract/approval/edit/${id}?taskId=${row.taskId}`);
return;
}
if (['selectMerchant'].includes(type)) {
router.push(
`/contract/business/edit/${row.contractId}?taskId=${row.taskId}&flowInstanceId=${row.flowInstanceId}`,
);
return;
}
if (['contractDeclare'].includes(type)) {
router.push(
`/contract/declaration/edit/${row.contractId}?taskId=${row.taskId}&flowInstanceId=${row.flowInstanceId}`,
);
return;
}
logger.error(`toDetail not support type:${type}`, row);
}
</script>
<template>
@ -49,11 +73,12 @@ function handleViewAll() {
'select-none line-through opacity-60': item.completed,
}"
class="flex cursor-pointer justify-between gap-x-6 px-4 py-2"
@click="toDetail(item.module, item.businessId, item)"
>
<div class="flex min-w-0 items-center gap-x-4">
<div class="min-w-0 flex-auto">
<p class="text-foreground text-sm font-semibold leading-6">
{{ item.module }} {{ item.title }}
{{ item.moduleName }} {{ item.title }}
</p>
<!-- eslint-disable vue/no-v-html -->
<p

View File

@ -67,15 +67,16 @@ onMounted(async () => {
});
todoItems.value = data.rows.map((item) => {
let module =
let moduleName =
getDictObj(DICT_TYPE.contract_todo_type, item.module)?.label || '';
if (module) {
module = `[${module}]`;
if (moduleName) {
moduleName = `[${moduleName}]`;
}
return {
module,
...item,
moduleName,
avatar: '',
date: item.createTime,
isRead: true,

View File

@ -35,28 +35,32 @@ export default defineConfig(async () => {
},
'/api/flowCenter': {
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api\/flowCenter/, '/flowCenter'),
rewrite: (path) =>
path.replace(/^\/api\/flowCenter/, '/flowCenter'),
// target: `http://10.71.220.24:8083/rl`,
target: `http://192.168.147.164:19007`,
ws: true,
},
'/api/czg/flowCenter': {
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api\/flowCenter/, '/flowCenter'),
rewrite: (path) =>
path.replace(/^\/api\/czg\/flowCenter/, '/flowCenter'),
// target: `http://10.71.220.24:8083/rl`,
target: `http://192.168.147.164:19007`,
ws: true,
},
'/api/zp/flowCenter': {
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api\/flowCenter/, '/flowCenter'),
rewrite: (path) =>
path.replace(/^\/api\/zp\/flowCenter/, '/flowCenter'),
// target: `http://10.71.220.24:8083/rl`,
target: `http://192.168.147.164:19007`,
ws: true,
},
'/api/zzz/flowCenter': {
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api\/flowCenter/, '/flowCenter'),
rewrite: (path) =>
path.replace(/^\/api\/zzz\/flowCenter/, '/flowCenter'),
// target: `http://10.71.220.24:8083/rl`,
target: `http://192.168.147.164:19007`,
ws: true,

View File

@ -150,13 +150,13 @@ function handleMenuClick(e) {
<a-button> {{ value ? `代理${value}` : '代理切换' }} </a-button>
</a-dropdown>
<Notification
<!-- <Notification
:dot="showDot"
:notifications="notifications"
@clear="handleNoticeClear"
@make-all="handleMakeAll"
@view-all="handleViewAll"
/>
/> -->
</template>
<template #extra>
<AuthenticationLoginExpiredModal

View File

@ -5,11 +5,22 @@ import { isHttpUrl, openWindow } from '@vben/utils';
function useNavigation() {
const router = useRouter();
// Helper function to clean up optional parameters
const cleanPath = (path: string) => {
// 正则匹配类似 :param? 的可选参数
return path.replace(/\/:\w+\?/g, '');
};
const navigation = async (path: string) => {
// 如果是HTTP URL则在新窗口打开
if (isHttpUrl(path)) {
openWindow(path, { target: '_blank' });
} else {
await router.push(path);
// 去除未赋值的可选参数
const cleanedPath = cleanPath(path);
// 路由跳转
await router.push(cleanedPath);
}
};

View File

@ -31,7 +31,7 @@ function mergeDeep(target: any, source: any) {
*/
function defineOverridesPreferences(preferences: DeepPartial<Preferences>) {
let defaultPreferences: DeepPartial<Preferences> = {
const defaultPreferences: DeepPartial<Preferences> = {
app: {
accessMode: 'frontend',
colorGrayMode: false,
@ -41,7 +41,7 @@ function defineOverridesPreferences(preferences: DeepPartial<Preferences>) {
defaultAvatar: '',
dynamicTitle: true,
// 是否开启检查更新
enableCheckUpdates: true,
enableCheckUpdates: false,
// 检查更新的时间间隔,单位为分钟
checkUpdatesInterval: 1,
// 开启布局设置按钮

View File

@ -1,5 +1,6 @@
import type { BodyOptions, QueryOptions } from './global.d';
import { http } from './request/index';
import type { QueryOptions, BodyOptions } from './global.d';
export default {
meeting: {
@ -549,6 +550,15 @@ export default {
/** 合同系统/履行/履行提示/合同变更 获取合同变更信息 */
get_getContractChangeInfo: (data?: QueryOptions) =>
http.get('/app/lvxChange/getContractChangeInfo', data),
/** 合同系统/履行/履行提示/合同变更 查询流程未配置人员节点 */
get_getFlowNodeUserConfig: (data?: QueryOptions) =>
http.get('/app/lvxChange/getFlowNodeUserConfig', data),
/** 合同系统/履行/履行提示/合同变更 流程启动 */
post_startWorkFlow: (data?: BodyOptions) =>
http.post('/app/lvxChange/startWorkFlow', data),
/** 合同系统/履行/履行提示/合同变更 审核通过 */
post_submit: (data?: BodyOptions) =>
http.post('/app/lvxChange/submit', data),
},
contractRelieve: {
/** 合同系统/履行/履行提示/合同解除 获取合同解除信息 */
@ -581,6 +591,11 @@ export default {
lvxResult: {
/** 合同系统/履行/履行结果 履行结果保存 */
post_save: (data?: BodyOptions) => http.post('/app/lvxResult/save', data),
/** 合同系统/履行/履行结果 分页履行结果查询 */
get_page: (data?: QueryOptions) => http.get('/app/lvxResult/page', data),
/** 合同系统/履行/履行结果 已办 */
get_pageDone: (data?: QueryOptions) =>
http.get('/app/lvxResult/pageDone', data),
},
contractFiling: {
/** 合同系统/履行/履行提示/临时归档 保存临时归档信息 */
@ -643,7 +658,7 @@ export default {
/** 合同系统/签订 获取合同签订信息 */
get_getContractSignInfo: (data?: QueryOptions) =>
http.get('/app/qdSign/getContractSignInfo', data),
/** 合同系统/签订 打印签订审批表 */
/** 合同系统/打印 选商打印 */
get_printApprove: (data?: QueryOptions) =>
http.get('/app/qdSign/printApprove', data),
/** 合同系统/签订 打印文本 */
@ -812,6 +827,15 @@ export default {
/** 合同系统/选商/选商结果 待审核 */
get_toDoPage: (data?: QueryOptions) =>
http.get('/app/biddingResult/toDoPage', data),
/** 合同系统/选商/选商结果 查询合同信息 */
get_getContractInfo: (data?: QueryOptions) =>
http.get('/app/biddingResult/getContractInfo', data),
/** 合同系统/选商/选商结果 查询供应商列表 */
get_getProviderInfo: (data?: QueryOptions) =>
http.get('/app/biddingResult/getProviderInfo', data),
/** 合同系统/选商/选商结果 选商专家列表 */
get_queryBiddingExpert: (data?: QueryOptions) =>
http.get('/app/biddingResult/queryBiddingExpert', data),
},
home: {
/** 合同系统/首页待办/已办 首页待办 */
@ -865,8 +889,8 @@ export default {
/** 设备管理/设备静态库管理/设备调拨 调拨信息保存 */
post_save: (data?: BodyOptions) => http.post('/app/equAllot/save', data),
/** 设备管理/设备静态库管理/设备调拨 调拨信息删除 */
post_delete: (data?: BodyOptions) =>
http.post('/app/equAllot/delete', data),
post_deletes: (data?: BodyOptions) =>
http.post('/app/equAllot/deletes', data),
},
bidding: {
/** 合同系统/标段信息 标段查询 */
@ -876,6 +900,9 @@ export default {
/** 合同系统/标段信息 标段信息删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/bidding/deletes', data),
/** 合同系统/选商/选商结果 查询标段列表 */
get_getBuddingPtInfoList: (data?: QueryOptions) =>
http.get('/app/bidding/getBuddingPtInfoList', data),
},
equAccident: {
/** 设备管理/设备使用管理/事故处理 事故处理(查询/获取) */
@ -921,8 +948,8 @@ export default {
post_save: (data?: BodyOptions) =>
http.post('/app/equDayRepair/save', data),
/** 设备管理/设备使用管理/日常维修 删除 */
get_deletes: (data?: QueryOptions) =>
http.get('/app/equDayRepair/deletes', data),
post_deletes: (data?: BodyOptions) =>
http.post('/app/equDayRepair/deletes', data),
/** 设备管理/查询管理/日常维修查询 查询 */
get_query: (data?: QueryOptions) =>
http.get('/app/equDayRepair/query', data),