This commit is contained in:
z9130 2024-10-17 15:40:23 +08:00
commit 21f362b172
60 changed files with 4358 additions and 2203 deletions

View File

@ -1,4 +1,4 @@
```shell
generate-api --swagger_url=http://127.0.0.1:4523/export/openapi/2?version=3.0 --template ./resource/apiDefinitions.ejs --output_dir ./resource --type path --prefix_to_filter /
generate-api --swagger_url="http://127.0.0.1:4523/export/openapi?projectId=4582192&specialPurpose=openapi-generator" --template ./resource/apiDefinitions.ejs --output_dir ./resource --type path --prefix_to_filter /
```

View File

@ -170,6 +170,11 @@ export default {
/** 协同办公/出差申请 下一审核节点 */
post_getNextNodeUserConfig: (data?: BodyOptions) =>
http.post('/app/ccsq/getNextNodeUserConfig', data),
/** 协同办公/出差申请 查看出差信息 */
get_getBusinessTripInfo: (data?: QueryOptions) =>
http.get('/app/ccsq/getBusinessTripInfo', data),
/** 协同办公/出差申请 查看审核过程 */
get_history: (data?: QueryOptions) => http.get('/app/ccsq/history', data),
},
orderfood: {
/** 协同办公/订餐管理/订餐 订餐加载接口 */
@ -413,9 +418,6 @@ export default {
/** 合同系统/立项废除 退回 */
post_rollback: (data?: BodyOptions) =>
http.post('/app/contractBaseInfo/rollback', data),
/** 合同系统/立项废除 合同立项废除 */
post_abolish: (data?: BodyOptions) =>
http.post('/app/contractBaseInfo/abolish', data),
/** 合同系统/立项废除 提交 */
post_abolishSubmit: (data?: BodyOptions) =>
http.post('/app/contractBaseInfo/abolishSubmit', data),
@ -535,7 +537,7 @@ export default {
/** 合同系统/选商废除 退回 */
post_abolishRollback: (data?: BodyOptions) =>
http.post('/app/selectMerchantsBasicInfo/abolishRollback', data),
// /contractBaseInfo/applyFlowStart
/** 合同系统/选商 流程启动(非待办提交) */
post_flowStart: (data?: BodyOptions) =>
http.post('/app/selectMerchantsBasicInfo/flowStart', data),
},
@ -613,7 +615,7 @@ export default {
/** 合同系统/归档/合同归档 保存合同归档 */
post_save: (data?: BodyOptions) =>
http.post('/app/contractFilingFormal/save', data),
/** 合同系统/归档/合同回档 分页查询 */
/** 合同系统/归档/合同回档 分页查询-已归档 */
get_pageArchivedContract: (data?: QueryOptions) =>
http.get('/app/contractFilingFormal/pageArchivedContract', data),
/** 合同系统/归档/合同回档 回档 */
@ -653,53 +655,49 @@ export default {
},
flowCenter: {
/** 流程中心 启动流程 */
post_start: (data?: BodyOptions) =>
http.post('/app/flowCenter/start', data),
post_start: (data?: BodyOptions) => http.post('/flowCenter/start', data),
/** 流程中心 审核通过 */
post_agree: (data?: BodyOptions) =>
http.post('/app/flowCenter/agree', data),
post_agree: (data?: BodyOptions) => http.post('/flowCenter/agree', data),
/** 流程中心 审核退回 */
post_rollback: (data?: BodyOptions) =>
http.post('/app/flowCenter/rollback', data),
http.post('/flowCenter/rollback', data),
/** 流程中心 获取待办 */
post_getTodoList: (data?: BodyOptions) =>
http.post('/app/flowCenter/getTodoList', data),
http.post('/flowCenter/getTodoList', data),
/** 流程中心 获取已办 */
post_doneList: (data?: BodyOptions) =>
http.post('/app/flowCenter/doneList', data),
http.post('/flowCenter/doneList', data),
/** 流程中心 审核撤回 */
get_revoke: (data?: QueryOptions) =>
http.get('/app/flowCenter/revoke', data),
get_revoke: (data?: QueryOptions) => http.get('/flowCenter/revoke', data),
/** 流程中心 审核记录 */
get_history: (data?: QueryOptions) =>
http.get('/app/flowCenter/history', data),
get_history: (data?: QueryOptions) => http.get('/flowCenter/history', data),
/** 流程中心 查看流程图 */
get_getFlowImg: (data?: QueryOptions) =>
http.get('/app/flowCenter/getFlowImg', data),
http.get('/flowCenter/getFlowImg', data),
/** 流程中心 获取可退回节点 */
get_getReturnNode: (data?: QueryOptions) =>
http.get('/app/flowCenter/getReturnNode', data),
http.get('/flowCenter/getReturnNode', data),
/** 流程中心 获取流程节点人员配置信息 */
get_getNextNodeUserConfig: (data?: QueryOptions) =>
http.get('/app/flowCenter/getNextNodeUserConfig', data),
http.get('/flowCenter/getNextNodeUserConfig', data),
/** 流程中心 获取待办数量 */
get_getTodoListSize: (data?: QueryOptions) =>
http.get('/app/flowCenter/getTodoListSize', data),
http.get('/flowCenter/getTodoListSize', data),
/** 流程中心 获取当前审核节点配置信息 */
get_getNodeConfigInfo: (data?: QueryOptions) =>
http.get('/app/flowCenter/getNodeConfigInfo', data),
http.get('/flowCenter/getNodeConfigInfo', data),
/** 流程中心 获取下一节点配置信息 */
get_getNextNodeConfig: (data?: QueryOptions) =>
http.get('/app/flowCenter/getNextNodeConfig', data),
http.get('/flowCenter/getNextNodeConfig', data),
/** 流程中心 获取流程节点人员配置信息 */
post_getFlowNodeUserConfig: (data?: BodyOptions) =>
http.post('/app/flowCenter/getFlowNodeUserConfig', data),
http.post('/flowCenter/getFlowNodeUserConfig', data),
/** 流程中心 获取流程变量配置 */
get_getFlowVariablesConfig: (data?: QueryOptions) =>
http.get('/app/flowCenter/getFlowVariablesConfig', data),
http.get('/flowCenter/getFlowVariablesConfig', data),
/** 流程中心 获取流程所有人员配置信息 */
get_getFlowUserConfig: (data?: QueryOptions) =>
http.get('/app/flowCenter/getFlowUserConfig', data),
http.get('/flowCenter/getFlowUserConfig', data),
},
rl: {
moduleParameter: {
@ -782,6 +780,9 @@ export default {
/** 合同系统 流程已办 */
get_getDoneTaskByUserID: (data?: QueryOptions) =>
http.get('/app/workFlow/getDoneTaskByUserID', data),
/** 合同系统 获取流程图 */
get_getFlowImg: (data?: QueryOptions) =>
http.get('/app/workFlow/getFlowImg', data),
},
biddingResult: {
/** 合同系统/选商/选商结果 分页查询 */
@ -822,8 +823,110 @@ export default {
/** 合同系统/签约授权 查询单条签约授权数据 */
get_getOne: (data?: QueryOptions) =>
http.get('/app/sqConsignPt/getOne', data),
/** 合同系统/签约授权 签约授权提交 */
/** 合同系统/签约授权 签约授权提交(非待办提交) */
post_flowStart: (data?: BodyOptions) =>
http.post('/app/sqConsignPt/flowStart', data),
/** 合同系统/签约授权 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/sqConsignPt/deletes', data),
/** 合同系统/签约授权 签约授权提交 */
post_submit: (data?: BodyOptions) =>
http.post('/app/sqConsignPt/submit', data),
},
addressorsort: {
/** 协同办公/会议管理/发言人顺序配置 发言人顺序查询 */
get_page: (data?: QueryOptions) =>
http.get('/app/addressorsort/page', data),
/** 协同办公/会议管理/发言人顺序配置 发言人排序保存 */
post_save: (data?: BodyOptions) =>
http.post('/app/addressorsort/save', data),
/** 协同办公/会议管理/发言人顺序配置 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/addressorsort/deletes', data),
},
equInfo: {
/** 设备管理/设备静态库管理/ 设备信息维护 设备信息保存 */
post_save: (data?: BodyOptions) => http.post('/app/equInfo/save', data),
/** 设备管理/设备静态库管理/ 设备信息维护 设备信息(获取/查询) */
get_page: (data?: QueryOptions) => http.get('/app/equInfo/page', data),
/** 设备管理/设备静态库管理/ 设备信息维护 设备信息删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/equInfo/deletes', data),
},
equAllot: {
/** 设备管理/查询管理/设备调拨查询 查询 */
get_page: (data?: QueryOptions) => http.get('/app/equAllot/page', data),
/** 设备管理/设备静态库管理/设备调拨 调拨信息保存 */
post_save: (data?: BodyOptions) => http.post('/app/equAllot/save', data),
/** 设备管理/设备静态库管理/设备调拨 调拨信息删除 */
post_delete: (data?: BodyOptions) =>
http.post('/app/equAllot/delete', data),
},
bidding: {
/** 合同系统/标段信息 标段查询 */
get_list: (data?: QueryOptions) => http.get('/app/bidding/list', data),
/** 合同系统/标段信息 标段信息保存(弃用,在选商中报错) */
post_save: (data?: BodyOptions) => http.post('/app/bidding/save', data),
/** 合同系统/标段信息 标段信息删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/bidding/deletes', data),
},
equAccident: {
/** 设备管理/设备使用管理/事故处理 事故处理(查询/获取) */
get_page: (data?: QueryOptions) => http.get('/app/equAccident/page', data),
/** 设备管理/设备使用管理/事故处理 保存 */
post_save: (data?: BodyOptions) => http.post('/app/equAccident/save', data),
/** 设备管理/设备使用管理/事故处理 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/equAccident/deletes', data),
/** 设备管理/查询管理/事故处理查询 查询 */
get_query: (data?: QueryOptions) =>
http.get('/app/equAccident/query', data),
},
equStopRepair: {
/** 设备管理/设备使用管理/停炉检修处理 查询 */
get_page: (data?: QueryOptions) =>
http.get('/app/equStopRepair/page', data),
/** 设备管理/设备使用管理/停炉检修处理 保存 */
post_save: (data?: BodyOptions) =>
http.post('/app/equStopRepair/save', data),
/** 设备管理/设备使用管理/停炉检修处理 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/equStopRepair/deletes', data),
/** 设备管理/查询管理/停炉检修处理查询 查询 */
get_query: (data?: QueryOptions) =>
http.get('/app/equStopRepair/query', data),
},
equDanger: {
/** 设备管理/设备使用管理/隐患排查 查询 */
get_page: (data?: QueryOptions) => http.get('/app/equDanger/page', data),
/** 设备管理/设备使用管理/隐患排查 保存 */
post_save: (data?: BodyOptions) => http.post('/app/equDanger/save', data),
/** 设备管理/设备使用管理/隐患排查 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/equDanger/deletes', data),
/** 设备管理/查询管理/隐患排查处理查询 查询 */
get_query: (data?: QueryOptions) => http.get('/app/equDanger/query', data),
},
equDayRepair: {
/** 设备管理/设备使用管理/日常维修 查询 */
get_page: (data?: QueryOptions) => http.get('/app/equDayRepair/page', data),
/** 设备管理/设备使用管理/日常维修 保存 */
post_save: (data?: BodyOptions) =>
http.post('/app/equDayRepair/save', data),
/** 设备管理/设备使用管理/日常维修 删除 */
get_deletes: (data?: QueryOptions) =>
http.get('/app/equDayRepair/deletes', data),
/** 设备管理/查询管理/日常维修查询 查询 */
get_query: (data?: QueryOptions) =>
http.get('/app/equDayRepair/query', data),
},
contractRecommendProvider: {
/** 合同系统/选商/合同推荐供应商信息 推荐供应商查询 */
get_list: (data?: QueryOptions) =>
http.get('/app/contractRecommendProvider/list', data),
/** 合同系统/选商/合同推荐供应商信息 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/contractRecommendProvider/deletes', data),
},
};

View File

@ -0,0 +1,13 @@
import type { VxeGridPropTypes } from 'vxe-table';
import dayjs from 'dayjs';
import { useRender } from '#/hooks/useRender';
export const PrimaryKey = 'guid';
export function getColumns(_params: any = {}): VxeGridPropTypes.Columns {
return [
];
}

View File

@ -1,12 +1,22 @@
<script lang="ts" setup>
import { nextTick, ref } from 'vue';
import { nextTick, ref, watch } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { logger } from 'common-utils';
withDefaults(
defineProps<{
loading?: boolean;
}>(),
{
loading: false,
},
);
const emit = defineEmits<{
(e: 'confirm', data: any): void;
(e: 'update:loading', data: any): void;
}>();
const isConfirmLoading = ref(false);
@ -45,11 +55,7 @@ const [Modal, modalApi] = useVbenModal({
});
</script>
<template>
<Modal
:confirm-loading="isConfirmLoading"
:loading="isConfirmLoading"
:title="data.title"
>
<Modal :confirm-loading="loading" :loading="loading" :title="data.title">
<fs-form v-if="formBinding.columns" ref="formRef" v-bind="formBinding" />
</Modal>
</template>

View File

@ -50,6 +50,15 @@ const routes: RouteRecordRaw[] = [
activePath: '/contract/approval/edit/:id?',
},
},
{
name: 'ContractApprovalList',
path: '/contract/approval/list',
component: () => import('#/views/contract/approval/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '立项编制',
},
},
{
name: 'ContractApprovalTodo',
path: '/contract/approval/todo',
@ -59,15 +68,7 @@ const routes: RouteRecordRaw[] = [
title: '立项提示',
},
},
{
name: 'ContractApprovalList',
path: '/contract/approval/list',
component: () => import('#/views/contract/approval/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '立项查询',
},
},
{
name: 'ContractApprovalSigningBasis',
path: '/contract/approval/signing-basis',
@ -92,12 +93,6 @@ const routes: RouteRecordRaw[] = [
{
name: 'ContractBusinessEdit',
path: '/contract/business/edit/:id?',
beforeEnter: (e) => {
if (e.params.id && e.params.id === ':id') {
e.params.id = '';
e.fullPath = '/contract/business/edit';
}
},
component: () => import('#/views/contract/business/edit/index.vue'),
meta: {
hideInMenu: true,
@ -108,21 +103,44 @@ const routes: RouteRecordRaw[] = [
},
},
{
name: 'ContractBusinessTodo',
path: '/contract/business/todo',
component: () => import('#/views/contract/business/todo/index.vue'),
name: 'ContractBusinessResult',
path: '/contract/business/result/:id?',
component: () => import('#/views/contract/business/result/index.vue'),
meta: {
hideInMenu: true,
hideInTab: true,
icon: 'lucide:area-chart',
title: '选商提示',
title: '选商结果填报',
activePath: '/contract/business/todo',
},
},
{
name: 'ContractBusinessList',
path: '/contract/business/list',
component: () => import('#/views/contract/business/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '选商查询',
title: '选商编制',
},
},
{
name: 'ContractBusinessResultList',
path: '/contract/business/result-list',
component: () =>
import('#/views/contract/business/result-list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '选商结果编制',
},
},
{
name: 'ContractBusinessTodo',
path: '/contract/business/todo',
component: () => import('#/views/contract/business/todo/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '选商提示',
},
},
],
@ -154,6 +172,15 @@ const routes: RouteRecordRaw[] = [
activePath: '/contract/declaration/todo',
},
},
{
name: 'ContractDeclarationList',
path: '/contract/declaration/list',
component: () => import('#/views/contract/declaration/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '申报编制',
},
},
{
name: 'ContractDeclarationTodo',
path: '/contract/declaration/todo',
@ -163,15 +190,7 @@ const routes: RouteRecordRaw[] = [
title: '申报提示',
},
},
{
name: 'ContractDeclarationList',
path: '/contract/declaration/list',
component: () => import('#/views/contract/declaration/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '申报查询',
},
},
{
name: 'ContractDeclarationPrint',
path: '/contract/declaration/print',
@ -239,6 +258,15 @@ const routes: RouteRecordRaw[] = [
activePath: '/contract/sign/todo',
},
},
{
name: 'ContractSignList',
path: '/contract/sign/list',
component: () => import('#/views/contract/sign/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '签订编制',
},
},
{
name: 'ContractSignTodo',
path: '/contract/sign/todo',
@ -248,15 +276,6 @@ const routes: RouteRecordRaw[] = [
title: '签订提示',
},
},
{
name: 'ContractSignList',
path: '/contract/sign/list',
component: () => import('#/views/contract/sign/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '签订查询',
},
},
],
},
{
@ -286,6 +305,15 @@ const routes: RouteRecordRaw[] = [
activePath: '/contract/perform/todo',
},
},
{
name: 'ContractPerformList',
path: '/contract/perform/list',
component: () => import('#/views/contract/perform/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '履行编制',
},
},
{
name: 'ContractPerformTodo',
path: '/contract/perform/todo',
@ -295,15 +323,6 @@ const routes: RouteRecordRaw[] = [
title: '履行提示',
},
},
{
name: 'ContractPerformList',
path: '/contract/perform/list',
component: () => import('#/views/contract/perform/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '履行查询',
},
},
{
name: 'ContractPerformResult',
path: '/contract/perform/result',
@ -313,6 +332,16 @@ const routes: RouteRecordRaw[] = [
title: '履行结果填报',
},
},
{
name: 'ContractPerformResultList',
path: '/contract/perform/resultList',
component: () =>
import('#/views/contract/perform/result-list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '履行结果编制',
},
},
{
name: 'ContractPerformTemporaryArchive',
path: '/contract/perform/temporary-archive',

View File

@ -47,14 +47,16 @@ export function getDictOpts(dictType: string) {
return getDictDatas(dictType);
}
export async function getDictDatasAsync(dictTypes: string[]) {
export async function getDictDatasAsync(
dictTypeParams: { type: string; valueType?: string }[],
) {
const dictDataMap: Record<string, DictDataType[]> = {};
const foundTypes = new Set<string>();
console.log(dictTypes);
// debugger;
// Process static dictionary data
// 处理静态字典数据
for (const dictType of Object.keys(dataModule)) {
if (dictTypes.includes(dictType)) {
const dictParam = dictTypeParams.find((d) => d.type === dictType);
if (dictParam) {
const dictEntries = dataModule[dictType];
if (dictEntries && dictEntries.data && dictEntries.data.length > 0) {
dictEntries.data.forEach((dictData) => {
@ -73,23 +75,22 @@ export async function getDictDatasAsync(dictTypes: string[]) {
});
foundTypes.add(dictType);
}
// If all types are found, return early
console.log(foundTypes.size, dictTypes.length);
if (foundTypes.size === dictTypes.length) {
// 如果所有类型都已找到,提前返回
if (foundTypes.size === dictTypeParams.length) {
return dictDataMap;
}
}
}
console.log(dictDataMap);
// Fetch remote dictionary data in parallel
const promises = dictTypes.map(async (type) => {
// 并行获取远程字典数据
const promises = dictTypeParams.map(async ({ type, valueType }) => {
if (!foundTypes.has(type)) {
try {
const data = await Apis.dictData.get_page({ params: { type } });
const data = await Apis.dictData.get_page({
params: { type },
});
dictDataMap[type] = (data.rows || []).map((dictData: any) => ({
value: dictData.value,
value: convertValue(dictData.value, valueType),
label: dictData.name,
colorType: dictData.colorType,
cssClass: dictData.cssClass,
@ -146,7 +147,9 @@ export async function getDictOptionsAsync(
valueType: 'boolean' | 'number' | 'string' = 'string',
): Promise<DictDataType[]> {
try {
const response = await getDictDatasAsync([dictType]);
const response = await getDictDatasAsync([
{ type: dictType, valueType: valueType },
]);
const dictOptions: DictDataType[] = response[dictType] || [];
return dictOptions.map((dict: DictDataType) => ({

View File

@ -48,6 +48,8 @@ export enum DICT_TYPE {
payment_nature = 'payment_nature',
/** 合同立项节点流程 */
contract_approval_flow_node = 'contract_approval_flow_node',
/** 合同选商节点流程 */
contract_business_flow_node = 'contract_business_flow_node',
/** 合同立项节点流程 */
contract_abolish_flow_node = 'contract_abolish_flow_node',
/** 合同授权类型 */
@ -55,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

@ -70,11 +70,22 @@ export default {
]),
contract_approval_flow_node: createEntry('合同立项节点流程', [
{ label: '待提交', value: 'edit' },
{ label: '待部门审核', value: 'departmentAudit' },
{ label: '已结束', value: 'end' },
{ label: '废除发起', value: 'abolishEdit' },
{ label: '待废除审批', value: 'abolishDepartmentAudit' },
{ label: '开始节点', value: 'paStart' },
{ label: '待编制', value: 'paEdit' },
{ label: '待部门自审', value: 'paDepartmentAudit' },
{ label: '选商编制', value: 'smEdit' },
]),
contract_business_flow_node: createEntry('合同选商节点流程', [
{ label: '开始节点', value: 'smStart' },
{ label: '待编制', value: 'smEdit' },
{ label: '待部门自审', value: 'smDepartmentAudit' },
{ label: '待计划规划部审查', value: 'smPlanningDepartment' },
{ label: '待财务资产部审查', value: 'smFinancialDepartment' },
{ label: '待合规审查(企管法规部)', value: 'smRegulationDepartment' },
{ label: '待主管领导审批', value: 'smManager' },
{ label: '待公司领导审核', value: 'smLeaders' },
{ label: '选商结果填报', value: 'smrEdit' },
]),
contract_abolish_flow_node: createEntry('合同立项节点流程', [
@ -99,15 +110,10 @@ export default {
// 合同待办类型
contract_todo_type: createEntry('合同待办类型', [
{ label: '合同立项', value: 'contractSetup' },
{ label: '合同立项废除', value: 'contractSetupAbolish' },
{ label: '合同选商', value: 'selectMerchant' },
{ label: '合同选商废除', value: 'selectMerchantAbolish' },
{ label: '合同选商结果', value: 'selectMerchantResult' },
{ label: '合同选商结果废除', value: 'selectMerchantResultAbolish' },
{ label: '合同申报', value: 'contractDeclare' },
{ label: '合同签订', value: 'contractSign' },
{ label: '合同履行', value: 'contractPerform' },
{ label: '合同归档', value: 'contractFile' },
{ label: '签约授权', value: 'signAuthorization' },
]),
};

View File

@ -19,6 +19,7 @@ import chooseUserModal from '#/views/system/user/choose-user-modal.vue';
import chooseSigningBasisModal from '../signing-basis/choose-signing-basis-modal.vue';
import { getColumns } from '../signing-basis/columns';
import { getFormSchema } from './curd';
import AuditNodeTable from '#/views/contract/components/audit-node-table/audit-node-table.vue';
const { xGridRef, gridProps } = useVxeTable({ ref: 'xGridRef' });
@ -43,6 +44,7 @@ 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();
@ -85,7 +87,7 @@ const gridOptions = reactive(
}),
);
const collapses = ['1', '2'];
const collapses = ['1', '2', '3'];
const collapseActiveKey = ref(collapses);
function areArraysEqualUnordered(arr1, arr2) {
if (arr1.length !== arr2.length) return false;
@ -114,7 +116,7 @@ function handleBack() {
* 页面返回并关闭tab
*/
function back() {
router.replace('/contract/approval/list');
router.replace('/contract/approval/todo');
}
function handleOpenSignBasisChooseModal() {
@ -149,19 +151,153 @@ function removeRow(row) {
}
}
function handleAbolish() {
Modal.confirm({
title: '提示',
content: '是否确认作废该合同?确认后该合同无法再次使用',
okType: 'danger',
onOk: async () => {
// await Apis.contractBaseInfo.post_abolish({
// data: {
// guid: currData.value['guid'],
// },
// });
},
});
const userModalOpenType = ref<'abolish' | 'audit'>('audit');
const currAuditType = ref<'abolish' | 'audit'>('audit');
const userListByAbolish = ref([]);
async function handleAbolish(type: 'openModal' | 'confirm') {
userModalOpenType.value = 'abolish';
if (type === 'openModal') {
Modal.confirm({
title: '提示',
content: '是否确认作废该合同?确认后该合同无法再次使用',
okType: 'danger',
onOk: async () => {
chooseUserModalApi.setData({
title: '选择立项废除审批人',
userIds: [],
});
chooseUserModalApi.open();
},
});
}
if (type === 'confirm') {
const hideLoading = message.loading('提交中...', 0);
try {
await Apis.contractBaseInfo.post_abolishFlowStart({
data: {
guid: currData.value['guid'],
assigneeList: userListByAbolish.value.map((item) => item.ACCOUNT_ID),
},
});
} catch (error) {
logger.error('立项废除提交失败', error);
} finally {
hideLoading();
}
}
}
async function handleAbolishAudit(
type: 'access' | 'accessConfirm' | 'reject' | 'rejectConfirm',
data?: any,
) {
console.log(type);
if (type === 'access') {
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 === 'accessConfirm') {
try {
await Apis.contractBaseInfo.post_abolishSubmit({
params: {
guid: id.value,
},
data: {
// appId: id.value,
taskId: taskId,
nodeId: '',
comment: '通过',
},
});
message.success('审核通过');
back();
} catch (error) {
logger.error('审核通过失败', error);
message.error('审核通过失败,请稍候再试');
}
}
if (type === 'reject') {
Modal.confirm({
title: '提示',
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') {
const comment = data.comment;
try {
await Apis.contractBaseInfo.post_rollback({
params: {
guid: id.value,
},
data: {
appId: id.value,
taskId: taskId,
nodeId: '',
comment,
},
});
temporaryFormModalApi.close();
message.success('退回成功');
back();
} catch (error) {
logger.error('合同立项退回失败', error);
message.error('退回失败,请稍候再试');
}
}
}
function handleDelete() {
@ -195,6 +331,11 @@ function handleChooseConfirm(rows) {
async function handleChooseUserConfirm(e) {
chooseUserModalApi.close();
isLoading.value = true;
if (userModalOpenType.value === 'abolish') {
userListByAbolish.value = e;
handleAbolish('confirm');
return;
}
try {
await Apis.contractBaseInfo.post_applyFlowStart({
data: {
@ -290,7 +431,7 @@ async function handleSave() {
handleSubmit();
},
onCancel: () => {
back();
// back();
},
});
} catch (error) {
@ -302,77 +443,103 @@ async function handleSave() {
}
async function handleSubmit() {
userModalOpenType.value = 'audit';
// isLoading.value = true
chooseUserModalApi.setData({
title: '选择审批人',
userIds: [],
});
chooseUserModalApi.open();
}
let auditType = ref('');
const isTemporaryFormModalLoading = ref(false);
async function handleAudit(
type: 'accessConfirm' | 'reject' | 'rejectConfirm',
type: 'openAccessModal' | 'openRejectModal' | 'confirm',
data?: any,
) {
console.log(type);
if (type === 'accessConfirm') {
Modal.confirm({
title: '提示',
content: '是否确认审核通过?',
onOk: async () => {
try {
await Apis.contractBaseInfo.post_submit({
params: {
guid: id.value,
},
data: {
appId: id.value,
taskId: currData.value.taskId,
nodeId: '',
comment: '通过',
},
});
message.success('审核通过');
back();
} catch (error) {
logger.error('审核通过失败', error);
message.error('审核通过失败,请稍候再试');
}
},
});
}
if (type === 'reject') {
Modal.confirm({
title: '提示',
content: '是否确认退回?',
onOk: () => {
temporaryFormModalApi.setData({
title: '退回原因',
schema: {
columns: {
comment: {
title: '',
key: 'comment',
col: { span: 24 },
colon: false,
component: {
name: 'a-textarea',
vModel: 'value',
autoSize: { minRows: 4, maxRows: 6 },
placeholder: '请输入',
},
rules: [{ required: true, message: '请输入退回原因' }],
},
if (type === 'openAccessModal') {
auditType.value = 'access';
temporaryFormModalApi.setData({
title: '审核通过备注',
schema: {
columns: {
comment: {
title: '',
key: 'comment',
col: { span: 24 },
colon: false,
component: {
name: 'a-textarea',
vModel: 'value',
autoSize: { minRows: 4, maxRows: 6 },
placeholder: '请输入',
},
},
});
temporaryFormModalApi.open();
},
},
});
temporaryFormModalApi.open();
}
if (type === 'rejectConfirm') {
if (type === 'confirm' && auditType.value === 'access') {
isTemporaryFormModalLoading.value = true;
const comment = data.comment;
try {
await Apis.contractBaseInfo.post_submit({
params: {
guid: id.value,
},
data: {
appId: id.value,
taskId: taskId,
nodeId: '',
comment: comment || '',
},
});
message.success('审核通过');
back();
} catch (error) {
logger.error('审核通过失败', error);
message.error('审核通过失败,请稍候再试');
} finally {
isTemporaryFormModalLoading.value = false;
}
}
if (type === 'openRejectModal') {
auditType.value = 'reject';
temporaryFormModalApi.setData({
title: '审核退回原因',
schema: {
columns: {
comment: {
title: '',
key: 'comment',
col: { span: 24 },
colon: false,
component: {
name: 'a-textarea',
vModel: 'value',
autoSize: { minRows: 4, maxRows: 6 },
placeholder: '请输入',
},
rules: [{ required: true, message: '请输入退回原因' }],
},
},
},
});
temporaryFormModalApi.open();
}
if (type === 'confirm' && auditType.value === 'reject') {
isTemporaryFormModalLoading.value = true;
const comment = data.comment;
try {
await Apis.contractBaseInfo.post_rollback({
@ -381,7 +548,7 @@ async function handleAudit(
},
data: {
appId: id.value,
taskId: currData.value.taskId,
taskId: taskId,
nodeId: '',
comment,
},
@ -392,6 +559,8 @@ async function handleAudit(
} catch (error) {
logger.error('合同立项退回失败', error);
message.error('退回失败,请稍候再试');
} finally {
isTemporaryFormModalLoading.value = false;
}
}
}
@ -415,12 +584,12 @@ onMounted(async () => {
formBinding.value.columns = getFormSchema({
contractTypeData: contractTypeData.value,
readOnly: !id.value || currData.value.step !== 'edit',
readOnly: !id.value || currData.value.step !== 'paEdit',
});
xGridRef.value!.reloadColumn(
getColumns({
readOnly: !id.value || currData.value.step !== 'edit',
readOnly: !id.value || currData.value.step !== 'paEdit',
}),
);
@ -473,35 +642,29 @@ 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" />
<TemporaryFormModal
class="w-[950px]"
@confirm="handleAudit('rejectConfirm', $event)"
v-model:loading="isTemporaryFormModalLoading"
class="w-[700px]"
@confirm="handleAudit('confirm', $event)"
/>
<a-affix
:offset-top="0"
:style="{ zIndex: 50 }"
:target="() => pageRef.bodyRef"
>
<!-- {{ currData.step }} -->
<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
v-if="!id || currData.step === 'edit'"
v-if="!id || ['paEdit'].includes(currData.step) || !taskId"
variant="primary"
@click="handleSave()"
>
保存
</vben-button>
<vben-button
v-if="!id || ['edit'].includes(currData.step) || !currData.taskId"
v-if="!id || ['paEdit'].includes(currData.step) || !taskId"
:disabled="!auditId"
variant="primary"
@click="handleSubmit()"
@ -509,50 +672,71 @@ onMounted(async () => {
提交
</vben-button>
<vben-button
v-if="
['departmentAudit'].includes(currData.step) && currData.taskId
"
v-if="['paDepartmentAudit'].includes(currData.step) && taskId"
:disabled="!auditId"
variant="primary"
@click="handleAudit('accessConfirm')"
@click="handleAudit('openAccessModal')"
>
通过
</vben-button>
<vben-button
v-if="
['departmentAudit'].includes(currData.step) && currData.taskId
"
v-if="['paDepartmentAudit'].includes(currData.step) && taskId"
:disabled="!auditId"
variant="destructive"
@click="handleAudit('reject')"
@click="handleAudit('openRejectModal')"
>
退回
</vben-button>
<vben-button
<!-- <vben-button
v-if="
id &&
!['edit', 'departmentAudit'].includes(currData.step) &&
!['edit', 'setupDepartmentAudit'].includes(currData.step) &&
currData.inputUserId === userInfo!.userId
"
variant="destructive"
@click="handleAbolish()"
@click="handleAbolish('openModal')"
>
废除
</vben-button>
</vben-button> -->
<vben-button
v-if="id && currData.step === 'edit'"
v-if="id && ['paEdit'].includes(currData.step)"
variant="destructive"
@click="handleDelete()"
>
删除
</vben-button>
<vben-button variant="secondary" @click="handleBack()">
返回
<!-- <vben-button
v-if="['abolishDepartmentAudit'].includes(currData.step) && taskId"
:disabled="!auditId"
variant="warning"
@click="handleAbolishAudit('accessConfirm')"
>
废除通过
</vben-button> -->
<!-- <vben-button
v-if="['abolishDepartmentAudit'].includes(currData.step) && taskId"
:disabled="!auditId"
variant="destructive"
@click="handleAbolishAudit('accessConfirm')"
>
废除拒绝
</vben-button>
<vben-button
v-if="['departmentAudit'].includes(currData.step) && taskId"
:disabled="!auditId"
variant="primary"
@click="handleAudit('accessConfirm')"
>
通过
</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>
@ -609,6 +793,15 @@ onMounted(async () => {
</template>
</VxeGrid>
</a-collapse-panel>
<a-collapse-panel
v-if="currData.flowInstanceId"
key="3"
class="w-full"
header="审批信息"
>
<AuditNodeTable :flow-instance-id="currData.flowInstanceId" />
</a-collapse-panel>
</a-collapse>
</div>
</a-spin>

View File

@ -19,7 +19,7 @@ export function getColumns(_params: any = {}): VxeGridPropTypes.Columns {
},
{
field: 'step',
title: '立项状态',
title: '节点状态',
width: 130,
slots: {
default: ({ row }) => {

View File

@ -1,8 +1,8 @@
<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 { Page } from "@vben/common-ui";
import {
MdiAdd,
MdiDelete,
@ -10,25 +10,25 @@ import {
MdiRadioChecked,
MdiRadioUnchecked,
MdiUpdate,
} from '@vben/icons';
} from "@vben/icons";
import { message, Modal } from 'ant-design-vue';
import { message, Modal } 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" });
const searchFormBinding = ref({
...getFormSchema(),
onSearch(_context: any) {
triggerProxy('reload');
triggerProxy("reload");
},
});
@ -57,28 +57,28 @@ const gridOptions = reactive(
toolbarConfig: {
enabled: true,
},
}),
})
);
function handleEdit(record?: any) {
if (record && record[PrimaryKey]) {
router.push(`/contract/approval/edit/${record[PrimaryKey]}`);
} else {
router.push('/contract/approval/edit');
router.push("/contract/approval/edit");
}
}
function handleDelete(row) {
Modal.confirm({
title: '提示',
content: '是否确认删除该条记录?',
okType: 'danger',
title: "提示",
content: "是否确认删除该条记录?",
okType: "danger",
onOk: async () => {
await Apis.contractBaseInfo.post_deletes({
params: { ids: row[PrimaryKey] },
});
message.success('删除成功');
triggerProxy('reload');
message.success("删除成功");
triggerProxy("reload");
},
});
}
@ -87,9 +87,18 @@ function handleExport() {
const $grid = xGridRef.value;
if ($grid) {
$grid.exportData({
type: 'xlsx',
type: "xlsx",
columnFilterMethod: ({ column }) => {
if (["operate", "step"].includes(column.field)) {
return false;
}
if (column.type === "radio") {
return false;
}
return true;
},
});
message.success('导出成功');
message.success("导出成功");
}
}
@ -113,7 +122,7 @@ function handleCellClick({ row }) {
}
onMounted(async () => {
triggerProxy('reload');
triggerProxy("reload");
});
</script>
@ -143,11 +152,7 @@ onMounted(async () => {
</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 variant="primary" @click="handleEdit()">
@ -155,19 +160,27 @@ onMounted(async () => {
新增
</vben-button>
<vben-button
:disabled="!selectRow || !selectRow[PrimaryKey]"
:disabled="
!selectRow ||
!selectRow[PrimaryKey] ||
!['paEdit'].includes(selectRow.step)
"
variant="warning"
@click="handleEdit(selectRow)"
>
<MdiUpdate class="mr-0.5 text-lg" />
修改
信息维护
</vben-button>
<vben-button variant="primary" @click="handleExport()">
<MdiExport class="mr-0.5 text-lg" />
导出
</vben-button>
<vben-button
:disabled="!selectRow || !selectRow[PrimaryKey]"
:disabled="
!selectRow ||
!selectRow[PrimaryKey] ||
!['paEdit'].includes(selectRow.step)
"
variant="destructive"
@click="handleDelete(selectRow)"
>

View File

@ -1,9 +1,12 @@
<script setup lang="ts">
import { Page } from '@vben/common-ui';
import TodoPage from '../../components/todo-page/todo-page.vue';
</script>
<template>
<TodoPage :module="['contractSetup']" />
<Page content-class="h-full">
<TodoPage :module="['contractSetup']" />
</Page>
</template>
<style scoped></style>

View File

@ -0,0 +1,271 @@
<script setup lang="tsx">
import {
ref,
reactive,
watch,
onMounted,
defineEmits,
defineExpose,
withDefaults,
defineProps,
computed,
} 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']);
const props = withDefaults(
defineProps<{
form: Record<string, any>;
}>(),
{
form: () => ({}),
},
);
const fileUploader = new FileUploader({});
const formRef = ref();
const form = reactive({ ...props.form });
watch(
() => props.form,
async (newForm) => {
Object.assign(form, newForm);
},
{ deep: true, immediate: true },
);
// const readOnly = computed(() => {
// return [
// 'smDepartmentAudit',
// 'smPlanningDepartment',
// 'smFinancialDepartment',
// 'smRegulationDepartment',
// 'smManager',
// 'smLeaders',
// ].includes(form.step);
// });
watch(
() => props.form.fileUuid,
async (newFileUuid) => {
if (newFileUuid) {
const files = await fileUploader.select(newFileUuid);
console.log(files);
form.fileList = files;
} else {
form.fileList = []; //
}
},
{ immediate: true },
);
watch(
() => form,
(newForm) => {
emit('update:form', newForm);
emit('field-change', newForm);
},
{ deep: true },
);
const rules = {
contractName: [{ required: true, message: '合同名称是必填项' }],
ctrType: [{ required: true, message: '合同类别是必填项' }],
ctrTwoType: [{ required: true, message: '二级类别是必填项' }],
fundAllocation: [{ required: true, message: '请选择资金流向' }],
fundDitch: [{ required: true, message: '请选择资金渠道' }],
organiza: [{ required: true, message: '请选择组织方式' }],
};
const contractTypeData = ref<any[]>([]);
function filteredContractTypes(parentType: string) {
return filterContractTypes(contractTypeData.value, parentType);
}
const dictMap = ref<any>({
common_whether: [],
contract_currency_unit: [],
contract_fund_flow: [],
contract_funding_source: [],
contract_organization_form: [],
});
onMounted(async () => {
const contractReferTypeData: any = await Apis.contractReferType.get_list({
params: {},
});
contractTypeData.value = contractReferTypeData.rows || [];
//
dictMap.value = await getDictDatasAsync([
{ type: DICT_TYPE.contract_currency_unit, valueType: 'string' },
{ type: DICT_TYPE.common_whether, valueType: 'string' },
{ type: DICT_TYPE.contract_fund_flow, valueType: 'string' },
{ type: DICT_TYPE.contract_funding_source, valueType: 'string' },
{ type: DICT_TYPE.contract_organization_form, valueType: 'string' },
]);
console.log(dictMap.value);
});
const handleChange = (info: UploadChangeParam) => {
form.fileList = info.fileList.length > 0 ? info.fileList : [];
};
function validate() {
return formRef.value?.validate();
}
function submit() {
// return f
}
defineExpose({ validate, submit });
</script>
<template>
<a-form
:model="form"
:rules="rules"
ref="formRef"
:label-col="{ style: { width: '120px' } }"
>
<a-row :gutter="16">
<a-col :span="16">
<a-form-item label="合同名称" name="contractName">
<a-input v-model:value="form.contractName" />
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="报审序号" name="reportNo">
<a-input v-model:value="form.reportNo" disabled />
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="合同类别" name="ctrType">
<a-select
v-model:value="form.ctrType"
class="min-w-[200px]"
:options="filteredContractTypes('-1')"
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="二级类别" name="ctrTwoType">
<a-select
v-model:value="form.ctrTwoType"
class="min-w-[200px]"
:options="filteredContractTypes(form.ctrType)"
/>
</a-form-item>
</a-col>
<a-col :span="8">
<!-- <a-form-item label="三级类别" name="ctrThreeType">
<span>{{ form.ctrThreeType }}</span>
</a-form-item> -->
</a-col>
<a-col :span="24">
<a-row :gutter="16">
<a-form-item label="预算金额" name="budgetSum">
<a-input-number
v-model:value="form.budgetSum"
class="min-w-[200px]"
:min="0"
/>
</a-form-item>
<a-col :span="3">
<a-form-item label="" :colon="false" name="priceType">
<a-select
class="w-full min-w-[120px]"
v-model:value="form.priceType"
:min="0"
:options="dictMap[DICT_TYPE.contract_currency_unit]"
/>
</a-form-item>
</a-col>
</a-row>
</a-col>
<a-col :span="12">
<a-form-item label="资金流向" name="fundAllocation">
<a-select
v-model:value="form.fundAllocation"
class="min-w-[200px]"
:options="dictMap[DICT_TYPE.contract_fund_flow]"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="资金渠道" name="fundDitch">
<a-select
v-model:value="form.fundDitch"
class="min-w-[200px]"
:options="dictMap[DICT_TYPE.contract_funding_source]"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="框架协议" name="frameProtocol">
<a-radio-group
v-model:value="form.frameProtocol"
:options="dictMap[DICT_TYPE.common_whether]"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="框架协议下的合同" name="frameProtocolCtr">
<a-radio-group
v-model:value="form.frameProtocolCtr"
:options="dictMap[DICT_TYPE.common_whether]"
/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="组织方式" name="organiza">
<a-radio-group
v-model:value="form.organiza"
class="min-w-[200px]"
:options="dictMap[DICT_TYPE.contract_organization_form]"
/>
</a-form-item>
</a-col>
<a-col :span="24">
<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>
<MdiUpload />
点击上传
</a-button>
</a-upload>
</a-form-item>
</a-col>
</a-row>
</a-form>
</template>
<style scoped></style>

View File

@ -148,8 +148,8 @@ export function getFormSchema(params: any = {}) {
vModel: 'value',
dict: dict({
data: [
{ label: '是', value: 1 },
{ label: '否', value: 0 },
{ label: '是', value: '1' },
{ label: '否', value: '0' },
],
}),
},
@ -164,8 +164,8 @@ export function getFormSchema(params: any = {}) {
vModel: 'value',
dict: dict({
data: [
{ label: '是', value: 1 },
{ label: '否', value: 0 },
{ label: '是', value: '1' },
{ label: '否', value: '0' },
],
}),
},
@ -180,7 +180,7 @@ export function getFormSchema(params: any = {}) {
allowClear: false,
class: 'min-w-[200px]',
dict: dict({
data: getDictOptions(DICT_TYPE.contract_organization_form),
data: getDictOptions(DICT_TYPE.contract_organization_form, 'number'),
}),
},
rules: [{ required: true, message: '请选择组织方式' }],

View File

@ -2,10 +2,10 @@ import type { VxeGridPropTypes } from 'vxe-table';
export function getBidColumns(_params?: any): VxeGridPropTypes.Columns {
const columns: VxeGridPropTypes.Columns = [
{
type: 'seq',
width: 50,
},
// {
// type: 'seq',
// width: 50,
// },
{
type: 'expand',
width: '0px',
@ -33,8 +33,8 @@ export function getBidColumns(_params?: any): VxeGridPropTypes.Columns {
field: 'operate',
title: '操作',
width: 120,
slots: { default: 'operate-slot' },
fixed: 'right',
slots: { default: 'operate-slot' },
},
];
@ -46,27 +46,38 @@ export function getProviderColumns(_params?: any): VxeGridPropTypes.Columns {
{
field: 'providerName',
title: '供应商名称',
width: 200,
width: 250,
},
{
field: 'qualification',
title: '资质情况',
width: 200,
slots: { default: 'qualification-slot' },
},
{
field: 'contactPerson',
title: '联系人',
width: 150,
slots: { default: 'contactPerson-slot' },
},
{
field: 'contactPhone',
title: '联系电话',
width: 150,
slots: { default: 'contactPhone-slot' },
},
{
field: 'remarks',
title: '备注',
minWidth: 200,
slots: { default: 'remarks-slot' },
},
{
field: 'operate',
title: '操作',
width: 120,
fixed: 'right',
slots: { default: 'operate-slot' },
},
];

View File

@ -0,0 +1,745 @@
<script setup lang="ts">
import {
ref,
reactive,
watch,
defineEmits,
defineProps,
withDefaults,
onMounted,
nextTick,
computed,
} 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 { cloneDeep } from 'lodash-es';
import { FileUploader } from '#/utils/file';
const [ChooseCompanyModal, chooseCompanyModalApi] = useVbenModal({
connectedComponent: chooseCompanyModal,
});
const fileUploader = new FileUploader({});
const emit = defineEmits(['update:form', 'field-change']);
const props = withDefaults(
defineProps<{
form: Record<string, any>;
}>(),
{
form: () => ({}),
},
);
const readOnly = computed(() => {
return [
'smDepartmentAudit',
'smPlanningDepartment',
'smFinancialDepartment',
'smRegulationDepartment',
'smManager',
'smLeaders',
].includes(form.step);
});
const formRef = ref();
const form = reactive({ ...props.form });
const rules = {
projectNum: [{ required: true, message: '请输入项目' }],
projectProp: [{ required: true, message: '请选择项目类别' }],
projectName: [{ required: true, message: '请输入项目名称' }],
choiceType: [{ required: true, message: '请选择选商方式' }],
choiceReason: [{ required: true, message: '请输入选商方式说明' }],
priceStyleId: [{ required: true, message: '请选择商务计价方式' }],
};
watch(
() => props.form,
(newForm) => {
Object.assign(form, newForm);
},
{ deep: true, immediate: true },
);
watch(
() => form,
(newForm) => {
emit('update:form', newForm);
emit('field-change', newForm);
},
{ deep: true },
);
const gridOptionsByBid = ref({
height: 100,
showOverflow: true,
columns: getBidColumns({ readOnly: false }),
data: [],
toolbarConfig: {
enabled: false,
},
pagerConfig: {
enabled: false,
},
rowConfig: {
useKey: true,
isCurrent: false,
keyField: 'id',
},
expandConfig: {
expandAll: true,
reserve: true,
showIcon: false,
},
});
const gridOptionsByProvider = ref({
columns: getProviderColumns({ readOnly: false }),
toolbarConfig: {
enabled: false,
},
pagerConfig: {
enabled: false,
},
rowConfig: {
useKey: true,
isCurrent: false,
},
});
const bidList = ref<any[]>([]);
const bidGridRefs = ref<Map<string, any>>(new Map());
const providerGridRefs = ref<Map<string, any>>(new Map());
const providerGridRefs2 = ref();
function onBidNumChange(value) {
const fullData = bidList.value;
const currentLength = fullData.length;
let rowsToAdd: any = [];
if (value < currentLength) {
// value
fullData.splice(value); //
} else if (value > currentLength) {
//
rowsToAdd = Array.from({ length: value - currentLength }).map((_, i) => ({
phaseSeq: `${currentLength + i + 1}`,
phaseName: `${currentLength + i + 1}标段`,
phaseMoney: null,
phaseDesc: '',
providerList: [],
}));
// fullData
fullData.push(...rowsToAdd); // 使 push
}
bidList.value = fullData;
setTimeout(() => {
console.log(bidGridRefs.value);
console.log(rowsToAdd);
for (const item of rowsToAdd) {
console.log(item.phaseSeq, bidGridRefs.value.get(`${item.phaseSeq}`));
bidGridRefs.value.get(`${item.phaseSeq}`).insertAt(item, -1);
}
}, 150);
}
const currBid = ref();
function handleChooseCompanyConfirm(e) {
console.log(currBid.value);
if (currBid.value.phaseSeq === 99999) {
const gridRef = providerGridRefs2.value;
e.map((item) => (item.guid = undefined));
gridRef.insertAt(e, -1);
return;
}
const gridRef = providerGridRefs.value.get(currBid.value.phaseSeq); // Assuming you have a main grid ref
//
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));
item.providerList.push(...e);
bidRef.loadData(bidFullData);
break;
}
}
console.log(bidRef.getTableData());
gridRef && gridRef.insertAt(e, -1);
}
function onChooseProvider(row) {
currBid.value = row;
if (row.phaseSeq === 99999) {
const tableFullData =
providerGridRefs2.value?.getTableData()?.fullData || [];
chooseCompanyModalApi.setData({
title: '选择推荐供应商',
limitMultipleNum: 5,
guids: tableFullData.map((item) => item.guid) || [],
});
chooseCompanyModalApi.open();
return;
}
const gridRef = providerGridRefs.value.get(currBid.value.phaseSeq); // Assuming you have a main grid ref
const tableFullData = gridRef?.getTableData()?.fullData || [];
chooseCompanyModalApi.setData({
title: '选择供应商',
limitMultipleNum: 5,
guids: tableFullData.map((item) => item.guid) || [],
});
chooseCompanyModalApi.open();
}
async function removeProvider(row) {
if (row.guid) {
try {
await Apis.contractRecommendProvider.post_deletes({
params: {
ids: row.guid,
},
});
} catch (error) {
logger.error('移除供应商失败', error);
message.error('移除供应商失败,请稍候再试');
return;
}
}
const gridRef = providerGridRefs.value.get(`${row.phaseSeq}`);
gridRef.remove(row);
}
async function removeProvider2(row) {
if (row.guid) {
try {
await Apis.contractRecommendProvider.post_deletes({
params: {
ids: row.guid,
},
});
} catch (error) {
logger.error('移除推荐供应商失败', error);
message.error('移除推荐供应商失败,请稍候再试');
return;
}
}
const gridRef = providerGridRefs2.value;
gridRef.remove(row);
}
const dictMap = ref<any>({});
onMounted(async () => {
console.log(form);
dictMap.value = await getDictDatasAsync([
{ type: DICT_TYPE.contract_selection_method, valueType: 'string' },
{ type: DICT_TYPE.contract_project_type, valueType: 'string' },
{ type: DICT_TYPE.comprehensive_project_name, valueType: 'string' },
{ type: DICT_TYPE.contract_price_style, valueType: 'string' },
{ type: DICT_TYPE.section_type, valueType: 'string' },
{ type: DICT_TYPE.section_num, valueType: 'number' },
]);
console.log(dictMap.value);
if (form.fileUuid) {
const files = await fileUploader.select(form.fileUuid);
form.fileList = files;
}
//
if (form.isBid === '1' && form.bidNum) {
const bidData = await Apis.bidding.get_list({
params: {
projectId: form.projectId,
contractId: form.contractId,
},
});
bidList.value = bidData.rows;
setTimeout(() => {
for (const item of bidList.value) {
bidGridRefs.value.get(`${item.phaseSeq}`).insertAt(item, -1);
}
}, 150);
}
//
if (form.contractId) {
let providerData = await Apis.contractRecommendProvider.get_list({
params: {
contractId: form.contractId,
},
});
providerData = providerData.rows || [];
if (form.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(() => {
providerGridRefs2.value.insert(providerData);
});
}
}
});
function validate() {
let a = getExtraForm();
if (!a) {
throw new Error('请完成必填项的填写');
}
return formRef.value?.validate();
}
function getForm() {
let tempForm = cloneDeep(form);
tempForm.priceStyleName = getDictObj(
DICT_TYPE.contract_price_style,
tempForm.priceStyleId,
)?.label;
tempForm.choiceTypeName = getDictObj(
DICT_TYPE.contract_selection_method,
tempForm.choiceType,
)?.label;
let extraForm = getExtraForm();
return { form: tempForm, ...extraForm };
return form;
}
function getExtraForm() {
if (form.frameProtocol === '0') {
let fullData = providerGridRefs2.value.getTableData().fullData || [];
return {
biddingList: [],
contractRecommendProviderList: fullData.map((item) => ({
...item,
phaseSeq: 99999,
})),
};
}
if (form.frameProtocol === '1') {
const tempBidList: any = [];
const tempProviderList: any = [];
for (const item of bidList.value) {
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;
}
if (!bidInfo.phaseMoney) {
message.error(`${item.phaseName}】中的预算金额不能为空`);
return;
}
bidInfo.id = undefined;
bidInfo.priceType = form.priceType;
bidInfo.priceTypeName = form.priceTypeName;
tempBidList.push(bidInfo);
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;
}
if (!item2.contactPerson) {
message.error(`【标段${item.phaseSeq}】中供应商联系人不能为空`);
return;
}
if (!item2.contactPhone) {
message.error(`【标段${item.phaseSeq}】中供应商联系人电话不能为空`);
return;
}
item2.contractId = form.contractId;
tempProviderList.push(item2);
}
}
}
return {
biddingList: tempBidList,
contractRecommendProviderList: tempProviderList,
};
}
return [];
}
defineExpose({ validate, getForm });
</script>
<template>
<ChooseCompanyModal class="w-[950px]" @confirm="handleChooseCompanyConfirm" />
<a-form
:model="form"
:rules="rules"
ref="formRef"
:label-col="{ style: { width: '120px' } }"
label-wrap
>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="项目" name="projectNum">
<a-input v-model:value="form.projectNum" :disabled="readOnly" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="项目类别" name="projectProp">
<a-radio-group v-model:value="form.projectProp" :disabled="readOnly">
<a-radio
v-for="option in dictMap[DICT_TYPE.contract_project_type]"
:key="option.value"
:value="option.value"
>
{{ option.label }}
</a-radio>
</a-radio-group>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="项目名称" name="projectName">
<a-select
v-model:value="form.projectName"
:options="dictMap[DICT_TYPE.comprehensive_project_name]"
:disabled="readOnly"
/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="商务计价方式" name="priceStyleId">
<a-radio-group v-model:value="form.priceStyleId" :disabled="readOnly">
<a-radio
v-for="option in dictMap[DICT_TYPE.contract_price_style]"
:key="option.value"
:value="option.value"
>
{{ option.label }}
</a-radio>
</a-radio-group>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="备注" name="remark">
<a-textarea
v-model:value="form.remark"
:auto-size="{ minRows: 4, maxRows: 6 }"
:disabled="readOnly"
/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="选商方式" name="choiceType">
<a-radio-group v-model:value="form.choiceType" :disabled="readOnly">
<a-radio
v-for="option in dictMap[DICT_TYPE.contract_selection_method]"
:key="option.value"
:value="option.value"
>
{{ option.label }}
</a-radio>
</a-radio-group>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="选商方式说明" name="choiceReason">
<a-textarea
v-model:value="form.choiceReason"
:auto-size="{ minRows: 4, maxRows: 6 }"
:disabled="readOnly"
/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="资质要求" name="qualificReq">
<a-textarea
v-model:value="form.qualificReq"
:auto-size="{ minRows: 4, maxRows: 6 }"
:disabled="readOnly"
/>
</a-form-item>
</a-col>
<a-col v-show="form.frameProtocol === '0'" :span="24">
<a-form-item label="推荐供应商" name="isBid">
<a-button
v-if="!readOnly"
size="small"
type="primary"
@click="onChooseProvider({ phaseSeq: 99999 })"
>
选择供应商
</a-button>
<a-form-item-rest>
<VxeGrid ref="providerGridRefs2" v-bind="gridOptionsByProvider">
<!-- 插槽配置 -->
<template #qualification-slot="{ row }">
<a-input
v-model:value="row.aptitudeName"
:disabled="readOnly"
/>
</template>
<template #contactPerson-slot="{ row }">
<a-input
v-model:value="row.contactPerson"
:disabled="readOnly"
/>
</template>
<template #contactPhone-slot="{ row }">
<a-input
v-model:value="row.contactPhone"
:disabled="readOnly"
/>
</template>
<template #bidname-slot="{ row }">
<a-input v-model:value="row.phaseName" :disabled="readOnly" />
</template>
<template #remarks-slot="{ row }">
<a-input v-model:value="row.remarks" :disabled="readOnly" />
</template>
<!-- 操作的插槽 -->
<template #operate-slot="{ row }">
<a-button
v-if="!readOnly"
class="text-red-500"
size="small"
type="text"
@click="removeProvider2(row)"
>
移除
</a-button>
</template>
</VxeGrid>
</a-form-item-rest>
</a-form-item>
</a-col>
<a-col v-show="form.frameProtocol === '1'" :span="24">
<a-form-item label="划分标段" name="isBid">
<div class="flex flex-col">
<div class="flex items-center">
<a-form-item class="!mb-0 inline-block">
<a-radio-group v-model:value="form.isBid" :disabled="readOnly">
<a-radio
v-for="option in dictMap[DICT_TYPE.section_type]"
:key="option.value"
:value="option.value"
>
{{ option.label }}
</a-radio>
</a-radio-group>
</a-form-item>
<div class="w-2"></div>
<a-form-item-rest v-if="form.isBid === '1'">
<div class="!mb-0 flex flex-row items-center">
<span class="ml-2 mr-4 w-full">标段数量</span>
<a-select
v-model:value="form.bidNum"
:options="dictMap[DICT_TYPE.section_num]"
class="min-w-[180px]"
:disabled="readOnly"
@change="onBidNumChange"
/>
</div>
</a-form-item-rest>
</div>
<div
:style="{
display:
form.isBid === '1' && form.bidNum > 0 ? 'block' : 'none',
}"
>
<a-form-item-rest>
<div v-for="item in bidList" :key="item.phaseSeq">
<a-divider>标段{{ item.phaseSeq }}</a-divider>
<VxeGrid
:ref="(el) => el && bidGridRefs.set(`${item.phaseSeq}`, el)"
v-bind="gridOptionsByBid"
>
<!-- 插槽配置 -->
<template #bidname-slot="{ row }">
<a-input
v-model:value="row.phaseName"
:disabled="readOnly"
/>
</template>
<template #phasemoney-slot="{ row }">
<a-input-number
v-model:value="row.phaseMoney"
addon-after="元"
:disabled="readOnly"
/>
</template>
<template #phasedesc-slot="{ row }">
<a-input
v-model:value="row.phaseDesc"
:disabled="readOnly"
/>
</template>
<!-- 操作的插槽 -->
<template #operate-slot="{ row }">
<a-button
size="small"
type="primary"
@click="onChooseProvider(row)"
:disabled="readOnly"
>
选择供应商
</a-button>
</template>
</VxeGrid>
<VxeGrid
:ref="
(el) => el && providerGridRefs.set(`${item.phaseSeq}`, el)
"
v-bind="gridOptionsByProvider"
>
<!-- 插槽配置 -->
<template #qualification-slot="{ row }">
<a-input
v-model:value="row.aptitudeName"
:disabled="readOnly"
/>
</template>
<template #contactPerson-slot="{ row }">
<a-input
v-model:value="row.contactPerson"
:disabled="readOnly"
/>
</template>
<template #contactPhone-slot="{ row }">
<a-input
v-model:value="row.contactPhone"
:disabled="readOnly"
/>
</template>
<template #bidname-slot="{ row }">
<a-input
v-model:value="row.phaseName"
:disabled="readOnly"
/>
</template>
<template #remarks-slot="{ row }">
<a-input
v-model:value="row.remarks"
:disabled="readOnly"
/>
</template>
<!-- 操作的插槽 -->
<template #operate-slot="{ row }">
<a-button
v-if="!readOnly"
class="text-red-500"
size="small"
type="text"
@click="removeProvider(row)"
>
移除
</a-button>
</template>
</VxeGrid>
</div>
</a-form-item-rest>
</div>
</div>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="项目范围" name="projectRange">
<a-textarea
v-model:value="form.projectRange"
:auto-size="{ minRows: 4, maxRows: 6 }"
:disabled="readOnly"
/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="项目内容" name="projectContent">
<a-textarea
v-model:value="form.projectContent"
:auto-size="{ minRows: 4, maxRows: 6 }"
:disabled="readOnly"
/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="工期/质量要求" name="quality">
<a-textarea
v-model:value="form.quality"
:auto-size="{ minRows: 4, maxRows: 6 }"
:disabled="readOnly"
/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="工程/采购量" name="stockNums">
<a-textarea
v-model:value="form.stockNums"
:auto-size="{ minRows: 4, maxRows: 6 }"
:disabled="readOnly"
/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="计划投资明细" name="stockPlanMx">
<a-textarea
v-model:value="form.stockPlanMx"
:auto-size="{ minRows: 4, maxRows: 6 }"
:disabled="readOnly"
/>
</a-form-item>
</a-col>
</a-row>
</a-form>
</template>

View File

@ -14,13 +14,15 @@ const [ChooseCompanyModal, chooseCompanyModalApi] = useVbenModal({
connectedComponent: chooseCompanyModal,
});
export function getFormSchema(params: any = {}) {
const { formRef, dictMap = {} } = params;
const xGridRefs = ref<Map<string, any>>(new Map());
const xGridRef = ref();
const gridRefs = ref<Map<string, any>>(new Map());
export function getFormSchema(params: any = {}) {
let { formRef, dictMap = {}, bidList = [], showBid = true } = params;
/** Hooks - 表格 */
const gridOptions = {
showOverflow: true,
columns: getBidColumns({ readOnly: false }),
data: [],
toolbarConfig: {
@ -55,15 +57,13 @@ export function getFormSchema(params: any = {}) {
},
};
const gridRefs = ref<Map<string, any>>(new Map());
return {
col: { span: 24 },
initialForm: {
contractName: '',
priceType: 'CNY',
isBid: '0',
budgetSum2: 0,
bidNum: 2,
},
labelCol: { style: { width: '120px' } },
columns: {
@ -167,6 +167,7 @@ export function getFormSchema(params: any = {}) {
title: '划分标段',
key: 'isBid',
col: { span: 24 },
show: showBid,
// component: {
// name: "fs-dict-radio",
// vModel: "value",
@ -174,142 +175,6 @@ export function getFormSchema(params: any = {}) {
// data: getDictOptions(DICT_TYPE.section_type)
// }),
// },
render({ form }) {
// 注意此处的v-model写法
const options1 = dictMap[DICT_TYPE.section_type];
const options2 = dictMap[DICT_TYPE.section_num];
let id = '';
return (
<div class="flex flex-col">
<ChooseCompanyModal
class="w-[950px]"
onConfirm={(e) => {
console.log(e);
console.log(id);
const xGridRef = gridRefs.value.get(id); // Assuming you have a main grid ref
console.log(gridRefs.value);
console.log(xGridRef);
xGridRef && xGridRef.insertAt(e, -1);
}}
></ChooseCompanyModal>
<div class="flex items-center">
<a-form-item class="!mb-0 inline-block">
<a-radio-group
options={options1}
v-model:value={form.isBid}
/>
</a-form-item>
<div class="w-2"></div>
{form.isBid === '1' && (
<a-form-item-rest>
<div class="!mb-0 flex flex-row items-center">
<span class="ml-2 mr-4 w-full"></span>
<a-select
class="min-w-[180px]"
onChange={(value) => {
// 获取当前表格的全部数据
const { fullData } = xGridRef.value.getTableData();
const currentLength = fullData.length;
if (value < currentLength) {
// 删除多余的行(从 value 开始的行)
const rowsToRemove = fullData.slice(value);
xGridRef.value.remove(rowsToRemove);
} else if (value > currentLength) {
// 插入新的行数据
const rowsToAdd = Array.from({
length: value - currentLength,
}).map((_, i) => ({
id: currentLength + i + 1,
bidName: `${currentLength + i + 1}标段`,
providerList: [],
}));
xGridRef.value.insertAt(rowsToAdd, -1);
}
xGridRef.value.setAllRowExpand(true);
}}
options={options2}
v-model:value={form.budgetSum2}
/>
</div>
</a-form-item-rest>
)}
</div>
<div
class="mt-2"
style={{
display:
form.isBid === '1' && form.budgetSum2 > 0
? 'block'
: 'none',
}}
>
<a-form-item-rest>
<VxeGrid ref={xGridRef} {...gridOptions}>
{{
'bidname-slot': ({ row }: any) => (
<a-input v-model:value={row.bidName} />
),
'phasemoney-slot': ({ row }: any) => (
<a-input-number
addon-after="元"
v-model:value={row.phaseMoney}
/>
),
'phasedesc-slot': ({ row }: any) => (
<a-textarea v-model:value={row.phaseDesc} />
),
'expand-content-slot': ({ row }: any) => (
<VxeGrid
data={row.providerList}
ref={(el) => el && gridRefs.value.set(row.id, el)}
{...gridOptionsByProvider}
/>
),
'operate-slot': ({ row }: any) => (
<a-button
onClick={() => {
id = row.id;
const tableFullData =
xGridRef.value?.getTableData().fullData;
if (tableFullData && tableFullData.length > 0) {
chooseCompanyModalApi.setData({
title: '选择签约依据',
guids:
tableFullData.map((item) => item.guid) || [],
});
} else {
chooseCompanyModalApi.setData({
title: '选择签约依据',
guids: [],
});
}
chooseCompanyModalApi.open();
// row.providerList.push({
// providerName: '供应商11',
// qualification: '',
// contactPerson: '',
// contactPhone: '',
// remarks: '',
// });
}}
size="small"
type="primary"
>
</a-button>
),
}}
</VxeGrid>
</a-form-item-rest>
</div>
</div>
);
},
},
projectRange: {
title: '项目范围',

View File

@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, nextTick, onMounted, reactive, ref } from 'vue';
import { computed, nextTick, onMounted, reactive, ref, watch } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { Page, useVbenModal } from '@vben/common-ui';
@ -22,8 +22,15 @@ import { logger } from '#/utils/logger';
import chooseUserModal from '#/views/system/user/choose-user-modal.vue';
import { getColumns } from '../../approval/signing-basis/columns';
import { getFormSchema as getFormSchemaByBaseInfo } from './basic-info-curd';
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 BusinessCard from './business-card.vue';
const [ChooseCompanyModal, chooseCompanyModalApi] = useVbenModal({
connectedComponent: chooseCompanyModal,
});
const [ChooseUserModal, chooseUserModalApi] = useVbenModal({
connectedComponent: chooseUserModal,
@ -41,25 +48,37 @@ const router = useRouter();
const route = useRoute();
const id = ref(route.params.id);
const isContractLoading = ref(true);
const contractCardRef = ref();
const contractData = ref<any>({});
const isBussinessLoading = ref(true);
const businessCardRef = ref();
const businessData = ref<any>({});
const selectMerchantsBasicInfo = ref({});
const selectMerchantsBasicInfoId = ref();
const pageRef = ref();
const formRef = ref();
const formRefByBaseInfo = ref();
const isLoading = ref(false);
const isLoading = ref(true);
const contractTypeData = ref<any[]>([]);
const currData = ref<any>({});
const bidGridRefs = ref<Map<string, any>>(new Map());
const providerGridRefs = ref<Map<string, any>>(new Map());
const formBindingByBaseInfo = ref({
col: { span: 24 },
initialForm: {},
labelCol: { style: { width: '120px' } },
columns: {},
});
watch(
() => contractData.value.frameProtocol,
(newValue) => {
if (contractData.value.guid) {
console.log(newValue);
businessData.value.frameProtocol = newValue;
}
},
{ immediate: true },
);
const formBinding = ref(null);
const formBinding = ref<any>(null);
/** Hooks - 表格 */
const gridOptions = reactive(
@ -80,6 +99,43 @@ const gridOptions = reactive(
}),
);
const gridOptionsByBid = ref({
height: 100,
showOverflow: true,
columns: getBidColumns({ readOnly: false }),
data: [],
toolbarConfig: {
enabled: false,
},
pagerConfig: {
enabled: false,
},
rowConfig: {
useKey: true,
isCurrent: false,
keyField: 'id',
},
expandConfig: {
expandAll: true,
reserve: true,
showIcon: false,
},
});
const gridOptionsByProvider = ref({
columns: getProviderColumns({ readOnly: false }),
toolbarConfig: {
enabled: false,
},
pagerConfig: {
enabled: false,
},
rowConfig: {
useKey: true,
isCurrent: false,
},
});
const fileList = ref<UploadFile[]>([]);
function handleBack() {
@ -119,6 +175,7 @@ function handleDelete() {
}
const collapses = ['1', '2', '3', '4'];
// const collapses = ['3', '4'];
const collapseActiveKey = ref(collapses);
function areArraysEqualUnordered(arr1, arr2) {
if (arr1.length !== arr2.length) return false;
@ -133,9 +190,8 @@ function handleFold() {
collapseActiveKey.value = isFold.value ? collapses : [];
}
function loadDataByContractTypeData() {}
const selectUsers = ref([]);
async function handleChooseUserConfirm(e) {
selectUsers.value = e;
chooseUserModalApi.close();
@ -143,12 +199,100 @@ async function handleChooseUserConfirm(e) {
handleSubmit('submit');
}
const currBid = ref();
function handleChooseCompanyConfirm(e) {
console.log(currBid.value);
const gridRef = providerGridRefs.value.get(currBid.value.phaseSeq); // Assuming you have a main grid ref
//
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));
item.providerList.push(...e);
bidRef.loadData(bidFullData);
break;
}
}
console.log(bidRef.getTableData());
gridRef && gridRef.insertAt(e, -1);
}
const bidList = ref([]);
function onBidNumChange(value) {
const fullData = bidList.value;
const currentLength = fullData.length;
let rowsToAdd = [];
if (value < currentLength) {
// value
fullData.splice(value); //
} else if (value > currentLength) {
//
rowsToAdd = Array.from({ length: value - currentLength }).map((_, i) => ({
phaseSeq: `${currentLength + i + 1}`,
phaseName: `${currentLength + i + 1}标段`,
phaseMoney: null,
phaseDesc: '',
providerList: [],
}));
// fullData
fullData.push(...rowsToAdd); // 使 push
}
bidList.value = fullData;
setTimeout(() => {
console.log(bidGridRefs.value);
console.log(rowsToAdd);
for (const item of rowsToAdd) {
console.log(item.phaseSeq, bidGridRefs.value.get(`${item.phaseSeq}`));
bidGridRefs.value.get(`${item.phaseSeq}`).insertAt(item, -1);
}
}, 150);
}
function onChooseProvider(row) {
currBid.value = row;
const gridRef = providerGridRefs.value.get(currBid.value.phaseSeq); // Assuming you have a main grid ref
const tableFullData = gridRef?.getTableData()?.fullData || [];
chooseCompanyModalApi.setData({
title: '选择供应商',
limitMultipleNum: 5,
guids: tableFullData.map((item) => item.guid) || [],
});
chooseCompanyModalApi.open();
}
async function removeProvider(row) {
if (row.guid) {
try {
await Apis.contractRecommendProvider.post_deletes({
params: {
ids: row.guid,
},
});
} catch (error) {
logger.error('移除供应商失败', error);
message.error('移除供应商失败,请稍候再试');
return;
}
}
const gridRef = providerGridRefs.value.get(`${row.phaseSeq}`);
gridRef.remove(row);
}
const isTemporaryFormModalLoading = ref(false);
async function handleAudit(
type: 'accessConfirm' | 'reject' | 'rejectConfirm',
data?: any,
) {
console.log(type);
console.log(route);
if (type === 'accessConfirm') {
Modal.confirm({
title: '提示',
@ -161,7 +305,7 @@ async function handleAudit(
},
data: {
appId: id.value,
taskId: currData.value.taskId,
taskId: route.query.taskId,
nodeId: '',
comment: '通过',
},
@ -207,6 +351,7 @@ async function handleAudit(
}
if (type === 'rejectConfirm') {
isTemporaryFormModalLoading.value = true;
const comment = data.comment;
try {
await Apis.selectMerchantsBasicInfo.post_rollback({
@ -215,7 +360,7 @@ async function handleAudit(
},
data: {
appId: selectMerchantsBasicInfoId.value,
taskId: currData.value.taskId,
taskId: route.query.taskId,
nodeId: '',
comment,
},
@ -226,39 +371,34 @@ async function handleAudit(
} catch (error) {
logger.error('合同立项退回失败', error);
message.error('退回失败,请稍候再试');
} finally {
isTemporaryFormModalLoading.value = false;
}
}
}
async function handleSave() {
try {
await contractCardRef.value.validate();
await businessCardRef.value.validate();
} catch {
message.error('请完成必填项的填写');
return;
}
const contractForm = cloneDeep(contractData.value);
console.log(contractForm);
// const businessForm = cloneDeep(businessData.value);
// console.log(businessForm);
const businessForm = businessCardRef.value.getForm();
console.log(businessForm);
isLoading.value = true;
try {
try {
await formRef.value.submit();
await formRefByBaseInfo.value.submit();
} catch {
message.error('请完成必填项的填写');
return;
}
const contractForm = formRefByBaseInfo.value.form;
const bussinessForm = formRef.value.form;
bussinessForm.priceStyleName = getDictObj(
DICT_TYPE.contract_price_style,
bussinessForm.priceStyleId,
)?.label;
bussinessForm.choiceTypeName = getDictObj(
DICT_TYPE.contract_selection_method,
bussinessForm.choiceType,
)?.label;
// console.log({
// contractForm,
// bussinessForm,
// });
// return;
//
{
const tempFileList = contractForm.fileList || [];
let tempFiles: any = [];
@ -280,7 +420,7 @@ async function handleSave() {
tempFiles = await fileUploader.upload(tempFileList, { source: 'ht' });
}
if (tempFiles) {
bussinessForm.fileUuid = (
businessForm.form.fileUuid = (
tempFiles.map((item) => item.fileUuid) || []
).join(',');
}
@ -288,34 +428,10 @@ async function handleSave() {
const form = {
contractBaseInfo: contractForm,
selectMerchantsBasicInfo: bussinessForm,
biddingList: [],
selectMerchantsBasicInfo: businessForm.form,
biddingList: businessForm.biddingList,
contractRecommendProviderList: businessForm.contractRecommendProviderList,
};
// if (form.selectMerchantsBasicInfo.isBid) {
// const biddingList: any[] = xGridRef.value?.getTableData().fullData || [];
// console.log(biddingList);
// let index = 1;
// for (const item of biddingList) {
// if (!item.phaseName) {
// message.error(``);
// return;
// }
// if (!item.phaseMoney) {
// message.error(``);
// return;
// }
// if (!item.phaseDesc) {
// message.error(``);
// return;
// }
// item.phaseSeq = `${index}`;
// index++;
// }
// form.biddingList = biddingList;
// }
console.log('提交表单', form);
// return;
@ -368,12 +484,12 @@ async function handleSave() {
message.success('保存成功');
Modal.confirm({
title: '提示',
content: '保存成功!是否进行提交?',
content: '保存成功!是否进行提交?提交后数据将不可变更',
onOk: () => {
handleSubmit('openModal');
},
onCancel: () => {
back();
// back();
},
});
} catch (error) {
@ -412,42 +528,16 @@ async function handleSubmit(type: 'openModal' | 'submit') {
}
}
const contractData = ref<any>({});
const businessData = ref<any>({});
const auditId = ref();
onMounted(async () => {
isLoading.value = true;
try {
if (id.value) {
const dictMap = await getDictDatasAsync([
DICT_TYPE.contract_authorization_period,
DICT_TYPE.comprehensive_project_name,
DICT_TYPE.contract_price_style,
DICT_TYPE.contract_selection_method,
DICT_TYPE.section_type,
DICT_TYPE.contract_project_type,
DICT_TYPE.section_num,
DICT_TYPE.contract_price_style,
]);
console.log(dictMap);
const contractReferTypeData: any = await Apis.contractReferType.get_list({
params: {},
});
contractTypeData.value = contractReferTypeData.rows || [];
formBinding.value = getFormSchema({ formRef, dictMap });
formBindingByBaseInfo.value.columns = getFormSchemaByBaseInfo({
contractTypeData: contractTypeData.value,
});
//
const contract: any = await Apis.contractBaseInfo.get_getOne({
params: { guid: id.value },
params: { contractId: id.value },
});
isContractLoading.value = false;
if (contract && contract.contractId) {
contractData.value = contract;
@ -462,25 +552,25 @@ onMounted(async () => {
});
}
//
const business: any = await Apis.selectMerchantsBasicInfo.get_getOne({
params: { contractId: contract.contractId },
});
business.priceType = contract.priceType;
business.priceTypeName = contract.priceTypeName;
business.frameProtocol = contract.frameProtocol;
selectMerchantsBasicInfo.value = business;
selectMerchantsBasicInfoId.value = business.guid;
if (business.fileUuid) {
const files = await fileUploader.select(business.fileUuid);
business.fileList = files;
}
businessData.value = business;
nextTick(() => {
formRefByBaseInfo.value.setFormData(contract);
formRef.value.setFormData(business);
});
businessData.value = business;
isBussinessLoading.value = false;
} else {
throw new Error('当前合同信息不存在');
}
loadDataByContractTypeData();
} else {
throw new Error('当前合同信息不存在');
}
@ -508,7 +598,13 @@ onMounted(async () => {
@confirm="handleChooseUserConfirm"
/>
<ChooseCompanyModal
class="w-[950px]"
@confirm="handleChooseCompanyConfirm"
/>
<TemporaryFormModal
v-model:loading="isTemporaryFormModalLoading"
class="w-[950px]"
@confirm="handleAudit('rejectConfirm', $event)"
/>
@ -520,33 +616,63 @@ 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>
<vben-button
:disabled="!selectMerchantsBasicInfoId"
variant="primary"
@click="handleSubmit('openModal')"
>
提交
</vben-button>
<vben-button variant="destructive" @click="handleDelete()">
废除
</vben-button>
<vben-button
v-if="selectMerchantsBasicInfoId"
variant="primary"
@click="handleAudit('accessConfirm')"
>
通过
</vben-button>
<vben-button
v-if="selectMerchantsBasicInfoId"
variant="destructive"
@click="handleAudit('reject')"
>
退回
</vben-button>
<template v-if="!isLoading">
<vben-button
v-if="
!selectMerchantsBasicInfoId ||
['smEdit'].includes(selectMerchantsBasicInfo.step)
"
variant="primary"
@click="handleSave()"
>
保存
</vben-button>
<vben-button
v-if="['smEdit'].includes(selectMerchantsBasicInfo.step)"
:disabled="!selectMerchantsBasicInfoId"
variant="primary"
@click="handleSubmit('openModal')"
>
提交
</vben-button>
<!-- <vben-button v-if="false" variant="destructive" @click="handleDelete()">
废除
</vben-button> -->
<vben-button
v-if="
selectMerchantsBasicInfoId &&
[
'smDepartmentAudit',
'smPlanningDepartment',
'smFinancialDepartment',
'smRegulationDepartment',
'smManager',
'smLeaders',
].includes(selectMerchantsBasicInfo.step)
"
variant="primary"
@click="handleAudit('accessConfirm')"
>
通过
</vben-button>
<vben-button
v-if="
selectMerchantsBasicInfoId &&
[
'smDepartmentAudit',
'smPlanningDepartment',
'smFinancialDepartment',
'smRegulationDepartment',
'smManager',
'smLeaders',
].includes(selectMerchantsBasicInfo.step)
"
variant="destructive"
@click="handleAudit('reject')"
>
退回
</vben-button>
</template>
<vben-button variant="secondary" @click="handleBack()">
返回
</vben-button>
@ -560,41 +686,49 @@ onMounted(async () => {
<a-spin :spinning="isLoading">
<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"
>
<template #form_fileList="scope">
<a-upload
v-model:file-list="scope.form.fileList"
:before-upload="() => false"
:max-count="3"
accept=".pdf,.ppt,.pptx"
name="file"
@change="handleChange"
>
<a-button>
<MdiUpload />
点击上传
</a-button>
</a-upload>
</template>
</fs-form>
<a-collapse-panel
key="1"
class="w-full"
force-render
header="基本信息"
>
<BasicInfoCard
v-if="!isContractLoading"
ref="contractCardRef"
v-model:form="contractData"
/>
</a-collapse-panel>
<a-collapse-panel key="2" class="w-full" header="签约依据">
<a-collapse-panel
key="2"
class="w-full"
force-render
header="签约依据"
>
<VxeGrid ref="xGridRef" v-bind="gridOptions" class="">
<template #toolbar_buttons></template>
</VxeGrid>
</a-collapse-panel>
<a-collapse-panel key="3" class="w-full" header="选商资料">
<fs-form ref="formRef" class="w-full" v-bind="formBinding" />
<a-collapse-panel
key="3"
class="w-full"
force-render
header="选商资料"
>
<BusinessCard
v-if="!isBussinessLoading"
ref="businessCardRef"
v-model:form="businessData"
/>
</a-collapse-panel>
<a-collapse-panel key="4" class="w-full" header="招标文件上传">
<a-collapse-panel
key="4"
class="w-full"
force-render
header="招标文件上传"
>
<a-form :label-col="{ style: { width: '120px' } }">
<a-form-item label="附件上传" name="fileList">
<a-upload

View File

@ -3,18 +3,40 @@ import { useRender } from '#/hooks/useRender';
import dayjs from 'dayjs';
import { DICT_TYPE, getDictOptions } from '#/utils/dict';
import { dict } from '@fast-crud/fast-crud';
import { unitComponentProps } from '#/common/unit'
import { unitComponentProps } from '#/common/unit';
export const PrimaryKey = 'guid';
export function getColumns(params: any = {}): VxeGridPropTypes.Columns {
return [
{ type: 'radio', width: 40, slots: { radio: 'radio_cell' }, align: 'center', fixed: 'left' },
{
type: 'radio',
width: 40,
slots: { radio: 'radio_cell' },
align: 'center',
fixed: 'left',
},
{
field: 'step',
title: '节点状态',
width: 130,
slots: {
default: ({ row }) => {
return useRender.renderDict(
row.step,
DICT_TYPE.contract_business_flow_node,
);
},
},
},
{ field: 'reportNo', title: '报审序号', width: 100 },
{
field: 'contractName', title: '合同名称', minWidth: 200, slots: {
default: 'contract-name-slot'
}
field: 'contractName',
title: '合同名称',
minWidth: 200,
slots: {
default: 'contract-name-slot',
},
},
{ field: 'choiceTypeName', title: '选商方式', width: 150 },
{ field: 'fundDitchName', title: '资金渠道', width: 150 },
@ -24,18 +46,19 @@ export function getColumns(params: any = {}): VxeGridPropTypes.Columns {
{ field: 'inputDepartName', title: '承办部门', width: 100 },
{ field: 'inputDate', title: '承办时间', width: 130 },
{
field: "operate",
title: "操作",
field: 'operate',
title: '操作',
width: 60,
fixed: "right",
slots: { default: "operate" },
fixed: 'right',
slots: { default: 'operate' },
},
]
];
}
export function getFormSchema(_params: any = {}) {
return {
initialForm: {
node: 'smEdit',
},
columns: {
contractName: {
@ -77,7 +100,25 @@ export function getFormSchema(_params: any = {}) {
class: 'min-w-[180px]',
allowClear: true,
dict: dict({
data: getDictOptions(DICT_TYPE.contract_selection_method)
data: getDictOptions(DICT_TYPE.contract_selection_method),
}),
},
autoSearchTrigger: 'enter',
show: true,
},
node: {
title: '是否编制',
key: 'node',
component: {
name: 'fs-dict-select',
vModel: 'value',
class: 'min-w-[180px]',
allowClear: true,
dict: dict({
data: [
{ label: '全部', value: '' },
{ label: '待编制', value: 'smEdit' },
],
}),
},
autoSearchTrigger: 'enter',

View File

@ -1,28 +1,23 @@
<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(
@ -49,20 +44,35 @@ const gridOptions = reactive(
toolbarConfig: {
enabled: true,
},
}),
})
);
function handleEdit(record?: any) {
router.push(`/contract/business/edit/${record[PrimaryKey]}`);
// if (["end"].includes(record.step)) {
// router.push(
// `/contract/business/result/${record[PrimaryKey]}?flowInstanceId=${record.flowInstanceId}`
// );
// } else {
router.push(`/contract/business/edit/${record["contractId"]}`);
// }
}
function handleExport() {
const $grid = xGridRef.value;
if ($grid) {
$grid.exportData({
type: 'xlsx',
type: "xlsx",
columnFilterMethod: ({ column }) => {
if (["operate", "step"].includes(column.field)) {
return false;
}
if (column.type === "radio") {
return false;
}
return true;
},
});
message.success('导出成功');
message.success("导出成功");
}
}
@ -86,13 +96,13 @@ function handleCellClick({ row }) {
}
onMounted(() => {
triggerProxy('reload');
triggerProxy("reload");
});
const searchForm = ref({
...getFormSchema(),
onSearch(_context: any) {
triggerProxy('reload');
triggerProxy("reload");
},
});
</script>
@ -123,11 +133,7 @@ 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
@ -136,7 +142,7 @@ const searchForm = ref({
@click="handleEdit(selectRow)"
>
<MdiUpdate class="mr-0.5 text-lg" />
修改
信息维护
</vben-button>
<vben-button variant="primary" @click="handleExport()">
<MdiExport class="mr-0.5 text-lg" />
@ -160,7 +166,7 @@ const searchForm = ref({
<a-button
size="small"
type="primary"
@click="toDetailPage('business', row.guid)"
@click="toDetailPage('business', row.guid, row)"
>
查看
</a-button>

View File

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

View File

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

View File

@ -0,0 +1,441 @@
<script setup lang="ts">
import { onMounted, ref } from "vue";
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";
const props = withDefaults(
defineProps<{
contractId: string;
projectId: string;
}>(),
{
contractId: "",
projectId: "",
}
);
const emit = defineEmits<{
(e: "submit", data: any): void;
}>();
const [ChooseCompanyModal, chooseCompanyModalApi] = useVbenModal({
connectedComponent: chooseCompanyModal,
});
const companyChooseType = ref<"providerPt" | "biddingProvider">("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: "" },
};
/** 必填字段校验,如果是必填字段则返回对应message */
function isRequired(field: string): string {
let rule = requiredFieldRules[field];
if (rule && rule.required) {
return rule.message || `${field}不可为空`;
}
return "";
}
const biddingExpertRef = ref();
const biddingExpertList = ref([]);
const providerPtRef1 = ref();
const providerPtRef2 = ref();
const providerPtList = ref([]);
const biddingResult = ref<any>({});
const biddingPtInfo = ref<any>({});
const biddingProviderRef = ref();
const biddingProviderList = ref([{}]);
function onAddProviderPt(type: string, data?: any) {
companyChooseType.value = "providerPt";
const tableFullData = providerPtRef1.value.getTableData()?.fullData || [];
if (type === "openModal") {
chooseCompanyModalApi.setData({
title: "选择单位",
limitMultipleNum: 5,
guids: tableFullData.map((item) => item.guid) || [],
});
chooseCompanyModalApi.open();
}
if (type === "confirm") {
console.log(data);
data.map((item) => (item.guid = undefined));
providerPtRef1.value.insert(data);
providerPtRef2.value.insert(data);
}
}
function onAddBiddingProvider(type: string, data?: any) {
companyChooseType.value = "biddingProvider";
const tableFullData = biddingProviderRef.value.getTableData()?.fullData || [];
if (type === "openModal") {
chooseCompanyModalApi.setData({
title: "选择单位",
limitMultipleNum: 1,
guids: tableFullData.map((item) => item.guid) || [],
});
chooseCompanyModalApi.open();
}
if (type === "confirm") {
console.log(data);
data.map((item) => (item.guid = undefined));
biddingProviderRef.value.loadData(data);
}
}
function onAddBiddingExpert() {
biddingExpertRef.value.insert({
expertSex: 1,
});
}
function onRemoveBiddingExpertRow(row) {
biddingExpertRef.value.remove(row);
}
function onRemoveProviderPtRow(row) {
providerPtRef1.value.remove(row);
let fullData = providerPtRef2.value.getTableData().fullData;
for (const item of fullData) {
if (item.providerId === row.providerId) {
providerPtRef2.value.remove(item);
}
}
}
function handleChooseCompanyConfirm(e) {
if (companyChooseType.value == "providerPt") {
onAddProviderPt("confirm", e);
}
if (companyChooseType.value == "biddingProvider") {
onAddBiddingProvider("confirm", e);
}
}
async function verify() {
//
//
for (const field of Object.keys(requiredFieldRules)) {
if (!biddingResult.value[field]) {
message.error(isRequired(field));
return;
}
}
}
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;
console.log(_fullData1, _fullData2, _fullData3, _fullData4);
let data1: any[] = [];
for (const item1 of _fullData1) {
for (const item2 of _fullData2) {
if (item1.providerId === item2.providerId) {
data1.push({
...item1,
offerMoney: item2.offerMoney,
bidScore: item2.bidScore,
bidDesc: item2.bidDesc,
projectId: props.projectId,
});
}
}
}
let tempBiddingResult = JSON.parse(JSON.stringify(biddingResult.value));
tempBiddingResult.projectId = props.projectId;
let tempBiddingPtInfo = JSON.parse(JSON.stringify(biddingPtInfo.value));
tempBiddingPtInfo.projectId = props.projectId;
_fullData3.map((item) => (item.projectId = props.projectId));
let form = {
biddingResult: tempBiddingResult,
biddingExpertList: _fullData3,
providerPtList: data1,
biddingPtList: [tempBiddingPtInfo],
};
return form;
}
onMounted(async () => {
try {
//
let data = await Apis.biddingResult.get_page({
params: {
pageNum: 1,
pageSize: 1,
projectId: props.projectId,
},
});
if (data.rows.length) {
biddingResult.value = data.rows[0];
}
console.log("选商结果信息", biddingResult.value);
//
let experData = await Apis.biddingExpert.get_list({
params: {
contractId: props.contractId,
projectId: props.projectId,
},
});
console.log("招标专家信息", experData);
} catch (error) {
logger.error("获取选商结果填报数据出错", error);
}
// biddingResult.value = currData.value;
});
defineExpose({
verify,
getFormData,
});
</script>
<template>
<ChooseCompanyModal class="w-[950px]" @confirm="handleChooseCompanyConfirm" />
<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="单位名称">
<template #default="{ row }">
{{ row.providerName }}
</template>
</vxe-column>
<vxe-column field="bidPlace" title="投标地点">
<template #default="{ row }">
<a-input v-model:value="row.bidPlace" />
</template>
</vxe-column>
<vxe-column field="bidMoney" title="投标保证金">
<template #default="{ row }">
<a-input-number v-model:value="row.bidMoney" 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>
</template>
<template #default="{ row }">
<a-button
class="text-red-500"
size="small"
type="text"
@click="onRemoveProviderPtRow(row)"
>
移除
</a-button>
</template>
</vxe-column>
</vxe-table>
</a-descriptions-item>
<a-descriptions-item :span="3" label="专家信息">
<vxe-table ref="biddingExpertRef" :data="biddingExpertList" size="mini">
<vxe-column field="expertName" title="评委姓名">
<template #default="{ row }">
<a-input v-model:value="row.expertName" />
</template>
</vxe-column>
<vxe-column field="expertSex" title="性别">
<template #default="{ row }">
<a-select v-model:value="row.expertSex" style="width: 80px">
<a-select-option :value="1"></a-select-option>
<a-select-option :value="2"></a-select-option>
</a-select>
</template>
</vxe-column>
<vxe-column field="expertAge" title="年龄">
<template #default="{ row }">
<a-input-number v-model:value="row.expertAge" :max="99" :min="0" />
</template>
</vxe-column>
<vxe-column field="expertDepartName" title="部门">
<template #default="{ row }">
<a-input v-model:value="row.expertDepartName" />
</template>
</vxe-column>
<vxe-column field="professionTypeName" title="专业">
<template #default="{ row }">
<a-input v-model:value="row.professionTypeName" />
</template>
</vxe-column>
<vxe-column field="titleTypeName" title="职称">
<template #default="{ row }">
<a-input v-model:value="row.titleTypeName" />
</template>
</vxe-column>
<vxe-column field="positionName" title="职务">
<template #default="{ row }">
<a-input v-model:value="row.positionName" />
</template>
</vxe-column>
<vxe-column field="operate" title="" width="100">
<template #header>
<a-button size="small" type="primary" @click="onAddBiddingExpert()">
添加
</a-button>
</template>
<template #default="{ row }">
<a-button
class="text-red-500"
size="small"
type="text"
@click="onRemoveBiddingExpertRow(row)"
>
移除
</a-button>
</template>
</vxe-column>
</vxe-table>
</a-descriptions-item>
<a-descriptions-item :span="1" label="开标时间">
<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-input v-model:value="biddingResult.openPlace" />
</a-descriptions-item>
<a-descriptions-item :span="3" label="参加人">
<a-textarea
v-model:value="biddingResult.participant"
:auto-size="{ minRows: 2, maxRows: 5 }"
/>
</a-descriptions-item>
<a-descriptions-item :span="3" label="过程描述">
<a-textarea
v-model:value="biddingResult.processDesc"
:auto-size="{ minRows: 2, maxRows: 5 }"
/>
</a-descriptions-item>
<a-descriptions-item :span="3" label="单位报价及评标信息">
<a-descriptions
:label-style="{ width: '150px', 'font-size': '12px' }"
bordered
size="small"
title=""
>
<a-descriptions-item :span="3" label="评标时间">
<a-date-picker
v-model:value="biddingPtInfo.evalBidDate"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
/>
</a-descriptions-item>
<a-descriptions-item :span="3" label="评标人">
<a-textarea
v-model:value="biddingPtInfo.evalBidPerson"
:auto-size="{ minRows: 2, maxRows: 5 }"
/>
</a-descriptions-item>
<a-descriptions-item :span="3" label="单位报价及专家评分">
<vxe-table ref="providerPtRef2" :data="providerPtList" size="mini">
<vxe-column field="providerName" title="单位名称">
<template #default="{ row }">
{{ row.providerName }}
</template>
</vxe-column>
<vxe-column field="offerMoney" title="报价(人民币元)">
<template #default="{ row }">
<a-input-number v-model:value="row.offerMoney" addon-after="" />
</template>
</vxe-column>
<vxe-column field="bidScore" title="综合得分(综合评价)">
<template #default="{ row }">
<a-input v-model:value="row.bidScore" />
</template>
</vxe-column>
<vxe-column field="bidDesc" title="简要说明">
<template #default="{ row }">
<a-input v-model:value="row.bidDesc" />
</template>
</vxe-column>
</vxe-table>
</a-descriptions-item>
<a-descriptions-item :span="3" label="备注">
<a-textarea
v-model:value="biddingPtInfo.remark"
:auto-size="{ minRows: 2, maxRows: 5 }"
/>
</a-descriptions-item>
<a-descriptions-item :span="3" label="招标结果">
<vxe-table ref="biddingProviderRef" :data="biddingProviderList" size="mini">
<vxe-column field="providerName" title="单位名称">
<template #default="{ row }">
{{ row.providerName || "" }}
<a-button
size="small"
type="primary"
@click="onAddBiddingProvider('openModal')"
>
选择
</a-button>
</template>
</vxe-column>
<vxe-column field="offerMoney" title="法定代表人(负责人)">
<template #default="{ row }">
{{ row.juridicalPerson }}
</template>
</vxe-column>
<vxe-column field="registerMoney" title="注册资金">
<template #default="{ row }">
{{ row.registerMoney }}
</template>
</vxe-column>
<vxe-column field="linkPerson" title="联系人">
<template #default="{ row }">
{{ row.linkPerson }}
</template>
</vxe-column>
<vxe-column field="linkPhone" title="联系电话">
<template #default="{ row }">
{{ row.linkPhone }}
</template>
</vxe-column>
<vxe-column field="resultMoney" title="选商确定价格(元人民币)">
<template #default="{ row }">
{{ row.resultMoney }}
</template>
</vxe-column>
</vxe-table>
</a-descriptions-item>
</a-descriptions>
</a-descriptions-item>
</a-descriptions>
</template>

View File

@ -1,119 +1,44 @@
<script setup lang="ts">
import { computed, nextTick, onMounted, reactive, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { computed, onMounted, ref } from "vue";
import { useRoute, useRouter } from "vue-router";
import { Page, useVbenModal } from '@vben/common-ui';
import { MdiUpload } from '@vben/icons';
import { useUserStore } from '@vben/stores';
import { Page, useVbenModal } from "@vben/common-ui";
import {
message,
Modal,
type UploadChangeParam,
type UploadFile,
} from 'ant-design-vue';
import { message, Modal } from "ant-design-vue";
import { logger } from "common-utils";
import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
import { DICT_TYPE, getDictObj } from '#/utils/dict';
import { FileUploader } from '#/utils/file';
import { logger } from '#/utils/logger';
import chooseUserModal from '#/views/system/user/choose-user-modal.vue';
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 { getColumns } from '../../approval/signing-basis/columns';
import { getFormSchema as getFormSchemaByBaseInfo } from './basic-info-curd';
import { getFormSchema } from './curd';
import FillResultCard from "./fill-result-card.vue";
const [ChooseUserModal, chooseUserModalApi] = useVbenModal({
connectedComponent: chooseUserModal,
});
const { xGridRef, gridProps } = useVxeTable({ ref: 'xGridRef' });
const fileUploader = new FileUploader({});
const router = useRouter();
const route = useRoute();
const id = ref(route.params.id);
const selectMerchantsBasicInfoId = ref();
const pageRef = ref();
const fillResultCardRef = ref();
const formRef = ref();
const formRefByBaseInfo = ref();
const id = ref(route.params.id);
const flowInstanceId = ref(route.query.flowInstanceId as string);
const currData = ref<any>({});
const businseeData = ref<any>({});
const isLoading = ref(false);
const contractTypeData = ref<any[]>([]);
const currData = ref<any>({});
const contractTypeData = ref([]);
const formBindingByBaseInfo = ref({
col: { span: 24 },
initialForm: {},
labelCol: { style: { width: '120px' } },
columns: {},
});
const submitGuid = ref();
const formBinding = ref({ ...getFormSchema() });
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
height: '100px',
columns: getColumns({ readOnly: true }),
data: [],
toolbarConfig: {
enabled: false,
},
pagerConfig: {
enabled: false,
},
rowConfig: {
useKey: true,
isCurrent: false,
},
}),
);
const fileList = ref<UploadFile[]>([]);
function handleBack() {
Modal.confirm({
title: '提示',
content: `是否确认返回上一页面?`,
onOk: async () => {
back();
},
});
}
/**
* 页面返回并关闭tab
*/
function back() {
router.replace('/contract/business/list');
}
const handleChange = (info: UploadChangeParam) => {
fileList.value = info.fileList.length > 0 ? info.fileList : [];
};
function handleDelete() {
Modal.confirm({
title: '提示',
content: '是否确认废除该条选商?',
okType: 'danger',
onOk: async () => {
await Apis.selectMerchantsBasicInfo.post_abolish({
params: { id: id.value },
});
message.success('废除成功');
back();
},
});
}
const collapses = ['1', '2', '3', '4'];
// const collapses = ['1', '2', '3', '4','5'];
const collapses = ["5"];
const collapseActiveKey = ref(collapses);
function areArraysEqualUnordered(arr1, arr2) {
if (arr1.length !== arr2.length) return false;
@ -128,263 +53,116 @@ function handleFold() {
collapseActiveKey.value = isFold.value ? collapses : [];
}
function loadDataByContractTypeData() {}
/**
* 页面返回并关闭tab
*/
function back() {
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: "提示",
content: `是否确认返回上一页面?`,
onOk: async () => {
back();
},
});
}
async function handleSave() {
isLoading.value = true;
try {
await fillResultCardRef.value.verify();
} catch (error) {
message.error("请完成必填项的填写");
return;
}
try {
try {
await formRef.value.submit();
await formRefByBaseInfo.value.submit();
} catch {
message.error('请完成必填项的填写');
return;
}
const contractForm = formRefByBaseInfo.value.form;
const bussinessForm = formRef.value.form;
bussinessForm.priceStyleName = getDictObj(
DICT_TYPE.contract_price_style,
bussinessForm.priceStyleId,
)?.label;
bussinessForm.choiceTypeName = getDictObj(
DICT_TYPE.contract_selection_method,
bussinessForm.choiceType,
)?.label;
// console.log({
// contractForm,
// bussinessForm,
// });
// return;
//
{
const tempFileList = contractForm.fileList || [];
let tempFiles: any = [];
if (fileList.value && tempFileList.length > 0) {
tempFiles = await fileUploader.upload(tempFileList, { source: 'ht' });
}
if (tempFiles) {
contractForm.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 form = {
contractBaseInfo: contractForm,
selectMerchantsBasicInfo: bussinessForm,
biddingList: [],
};
// if (form.selectMerchantsBasicInfo.isBid) {
// const biddingList: any[] = xGridRef.value?.getTableData().fullData || [];
// console.log(biddingList);
// let index = 1;
// for (const item of biddingList) {
// if (!item.phaseName) {
// message.error(``);
// return;
// }
// if (!item.phaseMoney) {
// message.error(``);
// return;
// }
// if (!item.phaseDesc) {
// message.error(``);
// return;
// }
// item.phaseSeq = `${index}`;
// index++;
// }
// form.biddingList = biddingList;
// }
console.log('提交表单', form);
// return;
const userStore = useUserStore();
let newForm = {};
//
// let fileList = formRef.value.form.fileList
// let files: any = []
// if (fileList && fileList.length) {
// files = await fileUploader.upload(fileList, { source: 'ht' })
// }
// console.log(files)
// if (files) {
// newForm.fileUuid = (files.map((item) => item.fileUuid) || []).join(',')
// }
newForm = Object.assign({}, form, newForm);
// // name
// for (const item of contractTypeData.value) {
// if (item.contrLevelId == newForm.ctrType) {
// newForm.ctrTypeName = item.contrLevelName;
// }
// if (item.contrLevelId == newForm.ctrTwoType) {
// newForm.ctrTwoTypeName = item.contrLevelName;
// }
// }
// newForm.fundDitchName = getDictObj(
// DICT_TYPE.contract_funding_source,
// newForm.fundDitch,
// )?.label;
// newForm.priceTypeName = getDictObj(
// DICT_TYPE.contract_currency_unit,
// newForm.priceType,
// )?.label;
// newForm.contractMoney = newForm.budgetSum;
// newForm.currentContStepId = 0;
// console.log(newForm);
const data = await Apis.selectMerchantsBasicInfo.post_saveMultiEntity({
data: newForm,
let form = fillResultCardRef.value.getFormData();
console.log(form);
let data = await Apis.biddingResult.post_save({
data: form,
});
selectMerchantsBasicInfoId.value = data.value;
message.success('保存成功');
submitGuid.value = data.guid;
message.success("保存成功");
Modal.confirm({
title: '提示',
content: '保存成功!是否进行提交?',
title: "提示",
content: "保存成功!是否进行提交?提交后数据将不可变更",
onOk: () => {
handleSubmit('openModal');
handleSubmit("openModal");
},
onCancel: () => {
back();
},
});
} catch (error) {
message.error('提交失败,请稍候再试');
console.log(error);
} finally {
isLoading.value = false;
logger.error("选商结果填报保存失败", error);
}
}
async function handleSubmit(type: 'openModal' | 'submit') {
if (type === 'openModal') {
async function handleSubmit(type: "openModal" | "submit") {
if (type === "openModal") {
chooseUserModalApi.setData({
title: '选择审批人',
title: "选择审批人",
});
chooseUserModalApi.open();
}
if (type === 'submit') {
if (type === "submit") {
isLoading.value = true;
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;
}
}
}
const contractData = ref<any>({});
const businessData = ref<any>({});
onMounted(async () => {
isLoading.value = true;
try {
const contractReferTypeData = await Apis.contractReferType.get_list({
params: {},
});
contractTypeData.value = contractReferTypeData.rows || [];
if (id.value) {
const contractReferTypeData: any = await Apis.contractReferType.get_list({
params: {},
});
contractTypeData.value = contractReferTypeData.rows || [];
formBindingByBaseInfo.value.columns = getFormSchemaByBaseInfo({
contractTypeData: contractTypeData.value,
});
//
const contract: any = await Apis.contractBaseInfo.get_getOne({
params: { guid: id.value },
});
currData.value = contract;
if (contract && contract.contractId) {
contractData.value = contract;
//
if (contract.basisId) {
const basisList: any = await Apis.lxBasisSale.get_page({
params: { basisId: contract.basisId },
});
nextTick(() => {
xGridRef.value!.insert(basisList.rows);
});
}
const business: any = await Apis.selectMerchantsBasicInfo.get_getOne({
params: { contractId: contract.contractId },
});
if (business.fileUuid) {
const files = await fileUploader.select(business.fileUuid);
business.fileList = files;
}
businessData.value = business;
nextTick(() => {
formRefByBaseInfo.value.setFormData(contract);
formRef.value.setFormData(business);
});
} else {
throw new Error('当前合同信息不存在');
}
loadDataByContractTypeData();
} else {
throw new Error('当前合同信息不存在');
const business: any = await Apis.selectMerchantsBasicInfo.get_getOne({
params: { contractId: contract.contractId },
});
businseeData.value = business;
// xGridRef.value!.reloadColumn(getColumns());
}
} catch (error) {
logger.error('合同选商加载异常', error);
logger.error("获取合同信息出错", error);
Modal.error({
title: '提示',
content: '当前合同信息不存在',
onOk() {
back();
},
title: "提示",
content: "当前合同信息不存在",
onOk() {},
});
} finally {
isLoading.value = false;
@ -394,109 +172,52 @@ 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">
<vben-button variant="primary" @click="handleSave()">
保存
</vben-button>
<vben-button variant="primary" @click="handleSubmit()">
提交
</vben-button>
<vben-button variant="destructive" @click="handleDelete()">
废除
</vben-button>
<vben-button variant="secondary" @click="handleBack()">
返回
</vben-button>
<template v-if="!isLoading">
<vben-button variant="primary" @click="handleSave()"> 保存 </vben-button>
<vben-button :disabled="!submitGuid" variant="primary" @click="handleSave()">
提交
</vben-button>
</template>
<vben-button variant="secondary" @click="handleBack()"> 返回 </vben-button>
</a-space>
<vben-button variant="secondary" @click="handleFold()">
一键{{ isFold ? '展开' : '收起' }}
一键{{ isFold ? "展开" : "收起" }}
</vben-button>
</div>
</a-affix>
<a-spin :spinning="isLoading">
<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"
>
<template #form_fileList="scope">
<a-upload
v-model:file-list="scope.form.fileList"
:before-upload="() => false"
:max-count="3"
accept=".pdf,.ppt,.pptx"
name="file"
@change="handleChange"
>
<a-button>
<MdiUpload />
点击上传
</a-button>
</a-upload>
</template>
</fs-form>
</a-collapse-panel>
<a-collapse v-model:active-key="collapseActiveKey">
<a-collapse-panel key="1" class="w-full" header="合同基本信息">
<ApprovalCard :info="currData" />
</a-collapse-panel>
<a-collapse-panel key="2" class="w-full" header="签约依据">
<VxeGrid ref="xGridRef" v-bind="gridOptions" class="">
<template #toolbar_buttons></template>
</VxeGrid>
</a-collapse-panel>
<a-collapse-panel key="2" class="w-full" header="选商资料">
<BusinessCard :info="businseeData" />
</a-collapse-panel>
<a-collapse-panel key="3" class="w-full" header="选商资料">
<fs-form ref="formRef" class="w-full" v-bind="formBinding" />
</a-collapse-panel>
<a-collapse-panel key="3" class="w-full" header="招标文件">
<FileCard file-uuids="" />
</a-collapse-panel>
<a-collapse-panel key="4" class="w-full" header="招标文件上传">
<a-form :label-col="{ style: { width: '120px' } }">
<a-form-item label="附件上传" name="fileList">
<a-upload
v-model:file-list="fileList"
:before-upload="() => false"
:max-count="3"
accept=".pdf,.ppt,.pptx"
name="file"
@change="handleChange"
>
<a-button>
<MdiUpload />
点击上传
</a-button>
</a-upload>
</a-form-item>
</a-form>
</a-collapse-panel>
</a-collapse>
</div>
</a-spin>
<a-collapse-panel key="4" class="w-full" header="审批信息">
<AuditNodeTable :flow-instance-id="flowInstanceId" />
</a-collapse-panel>
<a-collapse-panel key="5" class="w-full" header="招标(谈判)结果填报">
<FillResultCard
v-if="businseeData.projectId"
ref="fillResultCardRef"
:contract-id="businseeData.contractId"
:project-id="businseeData.projectId"
/>
</a-collapse-panel>
</a-collapse>
</Page>
</template>
<style scoped>
.sortable-tree-demo .drag-btn {
font-size: 12px;
text-align: center;
cursor: move;
}
.sortable-tree-demo .vxe-body--row.sortable-ghost,
.sortable-tree-demo .vxe-body--row.sortable-chosen {
background-color: #dfecfb;
}
</style>
<style scoped></style>

View File

@ -1,9 +1,12 @@
<script setup lang="ts">
import { Page } from '@vben/common-ui';
import TodoPage from '../../components/todo-page/todo-page.vue';
</script>
<template>
<TodoPage :module="['selectMerchant']" />
<Page content-class="h-full">
<TodoPage :module="['selectMerchant']" />
</Page>
</template>
<style scoped></style>

View File

@ -3,17 +3,18 @@ import type { VxeGridPropTypes } from 'vxe-table';
import { dict } from '@fast-crud/fast-crud';
import { DICT_TYPE, getDictOptions } from '#/utils/dict';
import { useRender } from '#/hooks/useRender';
export const PrimaryKey = 'guid';
export function getColumns(params: any = {}): VxeGridPropTypes.Columns {
if (params.type === 'choose') {
return [
{ field: 'providerId', title: '编号', type: 'checkbox', width: 100 },
{ field: 'providerId', title: '编号', type: 'checkbox', width: 130 },
{
field: 'providerName',
title: '单位全称',
minWidth: 200,
minWidth: 250,
slots: {
default: 'provider-name-slot',
},
@ -23,11 +24,20 @@ export function getColumns(params: any = {}): VxeGridPropTypes.Columns {
{ field: 'juridicalPerson', title: '法人姓名', width: 100 },
{ field: 'organizeNum', title: '组织机构代码', width: 100 },
{ field: 'creditCode', title: '信用代码', width: 100 },
{ field: 'inputPerson1', title: '注册资金', width: 100 },
{ field: 'registerMoney', title: '注册资金', width: 100 },
{ field: 'currencyTypeName', title: '币种', width: 100 },
{ field: 'createPerson', title: '创建人', width: 100 },
{ field: 'createDate', title: '创建时间', width: 100 },
{ field: 'inputDepartName', title: '备注', width: 100 },
{
field: 'createDate',
title: '创建时间',
width: 120,
slots: {
default: ({ row }) => {
return useRender.renderDate(row.applyTime, 'YYYY-MM-DD');
},
},
},
{ field: 'inputDepartName', title: '备注', width: 150 },
];
}
return [
@ -52,7 +62,7 @@ export function getColumns(params: any = {}): VxeGridPropTypes.Columns {
{ field: 'juridicalPerson', title: '法人姓名', width: 100 },
{ field: 'organizeNum', title: '组织机构代码', width: 100 },
{ field: 'creditCode', title: '信用代码', width: 100 },
{ field: 'inputPerson1', title: '注册资金', width: 100 },
{ field: 'registerMoney', title: '注册资金', width: 100 },
{ field: 'currencyTypeName', title: '币种', width: 100 },
{ field: 'createPerson', title: '创建人', width: 100 },
{ field: 'createDate', title: '创建时间', width: 100 },

View File

@ -0,0 +1,93 @@
<script setup lang="ts">
import { 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';
const props = withDefaults(
defineProps<{
flowInstanceId?: string;
}>(),
{
flowInstanceId: '',
},
);
const { xGridRef, gridProps, triggerProxy } = useVxeTable({ ref: 'xGridRef' });
const isLoading = ref(false);
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
height: '200px',
columns: getAuditInfoColumns({ readOnly: true }),
proxyConfig: {
autoLoad: false,
ajax: {
query: async () => {
let data = await Apis.flowCenter.get_history({
params: {
appId: '66a8c15b79c96d4e77639404',
flowInstanceId: props.flowInstanceId,
},
});
return data;
},
},
},
toolbarConfig: {
enabled: false,
},
pagerConfig: {
enabled: false,
},
rowConfig: {
useKey: true,
isCurrent: false,
},
}),
);
const loadData = async () => {
isLoading.value = true;
try {
// flowInstanceId reload
if (props.flowInstanceId) {
triggerProxy('reload');
} else {
message.warning('缺少 flowInstanceId无法加载数据');
}
} catch (error) {
logger.error('获取合同信息出错', error);
// message.error('');
} finally {
isLoading.value = false;
}
};
onMounted(async () => {
await loadData();
});
// flowInstanceId reload
watch(
() => props.flowInstanceId,
async (newFlowInstanceId, oldFlowInstanceId) => {
if (newFlowInstanceId !== oldFlowInstanceId && newFlowInstanceId) {
await loadData();
}
},
);
</script>
<template>
<VxeGrid ref="xGridRef" v-bind="gridOptions" class="">
<template #toolbar_buttons></template>
</VxeGrid>
</template>
<style scoped></style>

View File

@ -0,0 +1,120 @@
<script setup lang="ts">
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';
const props = withDefaults(
defineProps<{
basisId?: string;
}>(),
{
basisId: '',
},
);
const { xGridRef, gridProps, triggerProxy } = useVxeTable({ ref: 'xGridRef' });
const isLoading = ref(false);
function getColumns(): any {
const columns: VxeGridPropTypes.Columns = [
{ type: 'seq', title: '序号', width: 60 },
{ field: 'basisId', title: '依据号', width: 130 },
{
field: 'basisName',
title: '依据名称',
width: 200,
},
{ field: 'basisNum', title: '依据编号', width: 180 },
{
field: 'basisTypeId',
title: '依据类型',
width: 100,
slots: {
default: ({ row }) => {
return getDictObj(DICT_TYPE.contract_basis_type, row.basisTypeId)
?.label;
},
},
},
{
field: 'endDate',
title: '有效期',
width: 150,
slots: {
default: ({ row }) => {
return useRender.renderDate(row.endDate, 'YYYY-MM-DD');
},
},
},
];
return columns;
}
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
height: '200px',
columns: getColumns(),
data: [],
toolbarConfig: {
enabled: false,
},
pagerConfig: {
enabled: false,
},
rowConfig: {
useKey: true,
isCurrent: false,
},
}),
);
const loadData = async () => {
isLoading.value = true;
try {
// basisId reload
if (props.basisId) {
const basisList = await Apis.lxBasisSale.get_page({
params: { basisId: props.basisId },
});
nextTick(() => {
xGridRef.value!.insert(basisList.rows);
});
}
} catch (error) {
logger.error('获取签约依据信息出错', error);
} finally {
isLoading.value = false;
}
};
onMounted(async () => {
await loadData();
});
watch(
() => props.basisId,
async (newBasisId, oldBasisId) => {
if (newBasisId !== oldBasisId && newBasisId) {
await loadData();
}
},
);
</script>
<template>
<VxeGrid ref="xGridRef" v-bind="gridOptions" class="">
<template #toolbar_buttons></template>
</VxeGrid>
</template>
<style scoped></style>

View File

@ -0,0 +1,69 @@
<script setup lang="ts">
import { nextTick, onMounted, reactive, ref } from 'vue';
import { logger } from 'common-utils';
import { useVxeTable } from '#/hooks/vxeTable';
import { FileUploader } from '#/utils/file';
import { getColumnsByFiles } from '#/views/contract/schema';
const props = withDefaults(
defineProps<{
fileUuids?: string;
}>(),
{
fileUuids: '',
},
);
const { xGridRef, gridProps } = useVxeTable({ ref: 'xGridRef' });
const fileUploader = new FileUploader({});
const formRef = ref();
const isLoading = ref(false);
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
height: '200px',
columns: getColumnsByFiles({ readOnly: true }),
data: [],
toolbarConfig: {
enabled: false,
},
pagerConfig: {
enabled: false,
},
rowConfig: {
useKey: true,
isCurrent: false,
},
}),
);
onMounted(async () => {
isLoading.value = true;
try {
if (props.fileUuids) {
const files = await fileUploader.select(props.fileUuids);
nextTick(() => {
formRef.value.setFormData({
fileList: files,
});
});
}
} catch (error) {
logger.error('获取文件信息出错', error);
} finally {
isLoading.value = false;
}
});
</script>
<template>
<VxeGrid ref="xGridRef" v-bind="gridOptions" class="">
<template #toolbar_buttons></template>
</VxeGrid>
</template>
<style scoped></style>

View File

@ -1,13 +1,13 @@
<script setup lang="ts">
import { onMounted, reactive } from 'vue';
import { useRouter } from 'vue-router';
import { onMounted, reactive, ref, watch } from "vue";
import { useRouter } from "vue-router";
import { Page } from '@vben/common-ui';
import { logger } from "common-utils";
import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
import { getTodoColumns } from '#/views/contract/schema';
import { toDetail, toDetailPage } from '#/views/contract/utils';
import Apis from "#/api";
import { useVxeTable } from "#/hooks/vxeTable";
import { getTodoColumns } from "#/views/contract/schema";
import { toDetailPage } from "#/views/contract/utils";
const props = withDefaults(
defineProps<{
@ -15,21 +15,62 @@ const props = withDefaults(
}>(),
{
module: () => [],
},
}
);
// emit
const emit = defineEmits<{
(e: "update:module", value: string[]): void;
}>();
const router = useRouter();
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: "xGridRef" });
const { xGridRef: xGrid2Ref, triggerProxy: triggerProxy2 } = useVxeTable({
ref: 'xGrid2Ref',
ref: "xGrid2Ref",
});
// module
const localModule = ref([...(props.module || [])]); //
//
let isInternalUpdate = false;
// props.module localModule
watch(
() => props.module,
(newVal) => {
if (!isInternalUpdate) {
// localModule
localModule.value = newVal?.slice() || [];
triggerProxy("reload"); //
triggerProxy2("reload"); //
console.log("module prop changed:", newVal);
}
//
isInternalUpdate = false;
},
{ immediate: true, deep: true }
);
// localModule
watch(
localModule,
(newValue) => {
// localModule props.module emit
if (JSON.stringify(newValue) !== JSON.stringify(props.module)) {
isInternalUpdate = true; //
emit("update:module", newValue); //
}
},
{ deep: true }
);
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
columns: getTodoColumns({ type: 'todo' }),
columns: getTodoColumns({ type: "todo" }),
proxyConfig: {
autoLoad: true,
ajax: {
@ -50,13 +91,13 @@ const gridOptions = reactive(
toolbarConfig: {
enabled: false,
},
}),
})
);
/** Hooks - 表格 */
const grid2Options = reactive(
gridProps({
columns: getTodoColumns({ type: 'done' }),
columns: getTodoColumns({ type: "done" }),
proxyConfig: {
autoLoad: true,
ajax: {
@ -77,76 +118,103 @@ const grid2Options = reactive(
toolbarConfig: {
enabled: false,
},
}),
})
);
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);
}
onMounted(() => {});
//
defineExpose({});
</script>
<template>
<Page content-class="h-full flex flex-col">
<a-space class="flex h-full flex-col" direction="vertical" size="small">
<a-card
:body-style="{ flex: '1' }"
class="flex h-full flex-col"
size="small"
title="待办"
>
<vxe-grid ref="xGridRef" v-bind="gridOptions">
<template #toolbar_buttons> </template>
<template #title_slot="{ row }">
<span
class="cursor-pointer text-blue-500 hover:underline"
@click="toDetail(row.module, row.businessId, row)"
>
{{ row.contractName }}
</span>
</template>
<template #operate="{ row }">
<a-button
class="text-blue-500"
size="small"
type="text"
@click="
toDetailPage('approval', '', { contractId: row.contractId })
"
>
查看
</a-button>
</template>
</vxe-grid>
</a-card>
<a-card
:body-style="{ flex: '1' }"
class="flex h-full flex-col"
size="small"
title="已办"
>
<vxe-grid ref="xGrid2Ref" v-bind="grid2Options">
<template #toolbar_buttons> </template>
<template #title_slot="{ row }">
<span>
{{ row.contractName }}
</span>
</template>
<template #operate="{ row }">
<a-button
class="text-blue-500"
size="small"
type="text"
@click="
toDetailPage('approval', '', { contractId: row.contractId })
"
>
查看
</a-button>
</template>
</vxe-grid>
</a-card>
</a-space>
</Page>
<a-space class="flex h-full flex-col" direction="vertical" size="small">
<a-card
:body-style="{ flex: '1' }"
class="flex h-full flex-col"
size="small"
title="待办"
>
<vxe-grid ref="xGridRef" v-bind="gridOptions">
<template #toolbar_buttons> </template>
<template #title_slot="{ row }">
<span
class="cursor-pointer text-blue-500 hover:underline"
@click="toDetail(row.module, row.businessId, row)"
>
{{ row.contractName }}
</span>
</template>
<template #operate="{ row }">
<a-button
class="text-blue-500"
size="small"
type="text"
@click="
toDetailPage('approval', '', {
contractId: row.contractId,
flowInstanceId: row.flowInstanceId,
})
"
>
查看
</a-button>
</template>
</vxe-grid>
</a-card>
<a-card
:body-style="{ flex: '1' }"
class="flex h-full flex-col"
size="small"
title="已办"
>
<vxe-grid ref="xGrid2Ref" v-bind="grid2Options">
<template #toolbar_buttons> </template>
<template #title_slot="{ row }">
<span>
{{ row.contractName }}
</span>
</template>
<template #operate="{ row }">
<a-button
class="text-blue-500"
size="small"
type="text"
@click="
toDetailPage('approval', '', {
contractId: row.contractId,
flowInstanceId: row.flowInstanceId,
})
"
>
查看
</a-button>
</template>
</vxe-grid>
</a-card>
</a-space>
</template>
<style scoped>

View File

@ -276,11 +276,15 @@ onMounted(async () => {
//
const dictMap = await getDictDatasAsync([
DICT_TYPE.contract_currency_unit,
DICT_TYPE.common_whether,
DICT_TYPE.contract_authorization_period,
]);
const dictMap = await getDictDatasAsync(
[
DICT_TYPE.contract_currency_unit,
DICT_TYPE.common_whether,
DICT_TYPE.contract_authorization_period,
].map((item) => ({
type: item,
})),
);
formBinding.value = getFormSchema({
chooseCompanyModalApi,
formRef,

View File

@ -1,27 +1,22 @@
<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(
@ -47,14 +42,14 @@ const gridOptions = reactive(
toolbarConfig: {
enabled: true,
},
}),
})
);
function handleEdit(record?: any) {
if (record && record[PrimaryKey]) {
router.push(`/contract/declaration/edit/${record.ctrBaseId}`);
} else {
router.push('/contract/declaration/edit');
router.push("/contract/declaration/edit");
}
}
@ -62,9 +57,9 @@ function handleExport() {
const $grid = xGridRef.value;
if ($grid) {
$grid.exportData({
type: 'xlsx',
type: "xlsx",
});
message.success('导出成功');
message.success("导出成功");
}
}
@ -88,13 +83,13 @@ function handleCellClick({ row }) {
}
onMounted(() => {
triggerProxy('reload');
triggerProxy("reload");
});
const searchForm = ref({
...getFormSchema(),
onSearch(context: any) {
triggerProxy('reload');
triggerProxy("reload");
},
});
</script>
@ -125,11 +120,7 @@ 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
@ -138,7 +129,7 @@ const searchForm = ref({
@click="handleEdit(selectRow)"
>
<MdiUpdate class="mr-0.5 text-lg" />
修改
信息维护
</vben-button>
<vben-button variant="primary" @click="handleExport()">
<MdiExport class="mr-0.5 text-lg" />
@ -155,10 +146,7 @@ const searchForm = ref({
</template>
<template #contract-name-slot="{ row }">
<span
class="text-blue cursor-pointer hover:underline"
@click="toDetail(row)"
>
<span class="text-blue cursor-pointer hover:underline" @click="toDetail(row)">
{{ row.ctrName }}
</span>
</template>

View File

@ -1,182 +1,12 @@
<script setup lang="ts">
import { Page } from '@vben/common-ui';
import TodoPage from '../../components/todo-page/todo-page.vue';
</script>
<template>
<Page contentClass="h-full flex flex-col">
<a-space direction="vertical" size="small">
<a-card title="待办" size="small">
<vxe-grid ref="xGridRef" v-bind="gridOptions">
<template #toolbar_buttons> </template>
</vxe-grid>
</a-card>
<a-card title="已办" size="small" contentClass="">
<vxe-grid ref="xGrid2Ref" v-bind="grid2Options">
<template #toolbar_buttons> </template>
</vxe-grid>
</a-card>
</a-space>
<Page content-class="h-full">
<TodoPage :module="['contractDeclare']" />
</Page>
</template>
<script setup lang="ts">
import { defineComponent, ref, reactive, onMounted } from 'vue';
import { FsCrud } from '@fast-crud/fast-crud';
import { type VxeGridProps } from 'vxe-table'
import { Page, useVbenModal } from '@vben/common-ui';
import { useVxeTable } from '#/hooks/vxeTable';
import {
type CreateCrudOptionsProps,
useColumns,
useFormWrapper,
useFs,
utils,
} from '@fast-crud/fast-crud';
import { MdiAdd, MdiUpdate, MdiDelete } from '@vben/icons';
import { dict } from "@fast-crud/fast-crud";
import Apis from '#/api'
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
const { xGridRef:xGrid2Ref, triggerProxy:triggerProxy2 } = useVxeTable({ ref: 'xGrid2Ref' });
const treeData = ref([]);
/** Hooks - 表格 */
const gridOptions = reactive(gridProps({
columns: [
{ type: 'seq', width: 50, align: 'center', fixed: 'left' },
{ field: 'contractId', title: '编号', width: 100 },
{
field: 'title', title: '名称', minWidth: 200, slots: {
default: ({ row }) => {
// let text = row.title
// if (text) {
// let classArr: string[] = ["line-clamp-3"];
// return h(
// NTooltip,
// { trigger: 'hover' },
// {
// trigger: () => h('span', { class: classArr.join(' ') }, text),
// default: () => text
// }
// )
// }
return '';
}
}
},
{ field: 'contractAmount', title: '模块', width: 150 },
{ field: 'contractSubject', title: '任务', width: 200 },
{ field: 'contractCounterparty', title: '分配时间', width: 150 },
{ field: 'cumulativeSettlementAmount', title: '承办单位/部门', width: 150 },
{ field: 'changeCount', title: '承办人', width: 100 },
{ field: 'contractStatus', title: '交接给', width: 100 }
],
proxyConfig: {
autoLoad: true,
ajax: {
query: ({ page }) => {
return Apis.ccsq.get_toDoPage({ params: { pageNum: page.currentPage, pageSize: page.pageSize, ...searchParams } })
}
},
},
pagerConfig: {
enabled: true
},
toolbarConfig: {
enabled: false
},
}));
/** Hooks - 表格 */
const grid2Options = reactive(gridProps({
columns: [
{ type: 'seq', width: 50, align: 'center', fixed: 'left' },
{ field: 'contractId', title: '编号', width: 100 },
{
field: 'title', title: '名称', minWidth: 200, slots: {
default: ({ row }) => {
// let text = row.title
// if (text) {
// let classArr: string[] = ["line-clamp-3"];
// return h(
// NTooltip,
// { trigger: 'hover' },
// {
// trigger: () => h('span', { class: classArr.join(' ') }, text),
// default: () => text
// }
// )
// }
return '';
}
}
},
{ field: 'contractAmount', title: '模块', width: 150 },
{ field: 'contractSubject', title: '任务', width: 200 },
{ field: 'contractCounterparty', title: '分配时间', width: 150 },
{ field: 'cumulativeSettlementAmount', title: '承办单位/部门', width: 150 },
{ field: 'changeCount', title: '承办人', width: 100 },
{ field: 'contractStatus', title: '交接给', width: 100 }
],
proxyConfig: {
autoLoad: true,
ajax: {
query: ({ page }) => {
return Apis.ccsq.get_donePage({ params: { pageNum: page.currentPage, pageSize: page.pageSize, ...searchParams } })
}
},
},
pagerConfig: {
enabled: true
},
toolbarConfig: {
enabled: false
},
}));
onMounted(() => {
})
let searchParams = reactive({})
const searchForm = ref({
columns: {
name: {
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
props: {
type: 'text',
showWordLimit: true,
},
},
title: '字典标签',
key: 'type',
autoSearchTrigger: 'enter',
show: true,
},
age: {
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
},
title: '字典键值',
key: 'value',
autoSearchTrigger: 'enter',
show: true,
},
},
onSearch(context: any) {
searchParams = context.form
triggerProxy('reload')
},
onReset(context: any) {
searchParams = context.form
},
});
//
</script>
<style></style>
<style scoped></style>

View File

@ -0,0 +1,55 @@
<script setup lang="ts">
import { DICT_TYPE, getDictObj } from '#/utils/dict';
import FileCard from '#/views/contract/components/file-card/file-card.vue';
withDefaults(
defineProps<{
info: any;
}>(),
{
info: () => {},
},
);
</script>
<template>
<a-descriptions
:label-style="{ width: '150px' }"
bordered
size="small"
title=""
>
<a-descriptions-item :span="3" label="合同名称">
{{ info.contractName }}
</a-descriptions-item>
<a-descriptions-item :span="1" label="合同类别">
{{ info.contractName }}
</a-descriptions-item>
<a-descriptions-item :span="1" label="二级类别">
{{ info.contractName }}
</a-descriptions-item>
<a-descriptions-item :span="1" label="框架协议">
{{ getDictObj(DICT_TYPE.common_whether, info.frameProtocol)?.label }}
</a-descriptions-item>
<a-descriptions-item :span="1" label="框架协议下的合同">
{{ getDictObj(DICT_TYPE.common_whether, info.frameProtocolCtr)?.label }}
</a-descriptions-item>
<a-descriptions-item :span="1" label="资金流向">
{{ getDictObj(DICT_TYPE.contract_fund_flow, info.fundAllocation)?.label }}
</a-descriptions-item>
<a-descriptions-item :span="1" label="资金渠道">
{{ getDictObj(DICT_TYPE.contract_funding_source, info.fundDitch)?.label }}
</a-descriptions-item>
<a-descriptions-item label="预算金额">
{{ `${info.budgetSum || ''} ${info.priceTypeName || ''}` }}
</a-descriptions-item>
<a-descriptions-item :span="2" label="组织形式">
{{
getDictObj(DICT_TYPE.contract_organization_form, info.organiza?.label)
}}
</a-descriptions-item>
<a-descriptions-item :span="3" label="相关附件">
<FileCard :file-uuids="info.fileUuid" />
</a-descriptions-item>
</a-descriptions>
</template>

View File

@ -36,6 +36,12 @@ export function getFormSchema(params: any = {}): any {
title: '合同名称',
key: 'contractName',
col: { span: 24 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
disabled: readOnly,
},
conditionalRender: {
match(_context) {
return true;
@ -44,12 +50,11 @@ export function getFormSchema(params: any = {}): any {
return <span>{form.contractName}</span>;
},
},
rules: [{ required: true }],
},
ctrType: {
title: '合同类别',
key: 'ctrType',
col: { span: 12 },
col: { span: 6 },
conditionalRender: {
match(_context) {
return true;
@ -64,12 +69,11 @@ export function getFormSchema(params: any = {}): any {
return <span></span>;
},
},
rules: [{ required: true }],
},
ctrTwoType: {
title: '二级类别',
key: 'ctrTwoType',
col: { span: 12 },
col: { span: 6 },
conditionalRender: {
match(_context) {
return true;
@ -84,12 +88,11 @@ export function getFormSchema(params: any = {}): any {
return <span></span>;
},
},
rules: [{ required: true }],
},
frameProtocol: {
title: '框架协议',
key: 'frameProtocol',
col: { span: 8 },
col: { span: 6 },
component: {
name: 'fs-dict-radio',
vModel: 'value',
@ -116,7 +119,7 @@ export function getFormSchema(params: any = {}): any {
frameProtocolCtr: {
title: '框架协议下的合同',
key: 'frameProtocolCtr',
col: { span: 12 },
col: { span: 6 },
labelCol: { style: { width: '200px' } },
component: {
name: 'fs-dict-radio',
@ -144,7 +147,7 @@ export function getFormSchema(params: any = {}): any {
fundAllocation: {
title: '资金流向',
key: 'fundAllocation',
col: { span: 12 },
col: { span: 6 },
component: {
name: 'fs-dict-select',
vModel: 'value',
@ -179,12 +182,11 @@ export function getFormSchema(params: any = {}): any {
);
},
},
rules: [{ required: true, message: '请选择资金流向' }],
},
fundDitch: {
title: '资金渠道',
key: 'fundDitch',
col: { span: 12 },
col: { span: 6 },
component: {
name: 'fs-dict-select',
vModel: 'value',
@ -209,12 +211,11 @@ export function getFormSchema(params: any = {}): any {
);
},
},
rules: [{ required: true, message: '请选择资金渠道' }],
},
budgetSum: {
title: '预算金额',
key: 'budgetSum',
col: { span: 8 },
col: { span: 6 },
colon: false,
component: {
name: 'a-input-number',
@ -222,36 +223,14 @@ export function getFormSchema(params: any = {}): any {
class: 'w-full',
min: 0,
},
conditionalRender: {
match({ form }) {
return readOnly;
},
render({ form }) {
return <span class="">{form.budgetSum}</span>;
},
},
},
priceType: {
title: '',
key: 'priceType',
col: { span: 6 },
labelCol: { style: { width: '12px' } },
colon: false,
component: {
name: 'fs-dict-select',
vModel: 'value',
dict: dict({
data: getDictOptions(DICT_TYPE.contract_currency_unit),
}),
},
conditionalRender: {
match({ form }) {
return readOnly;
},
render({ form }) {
return (
<span class="mr-2">
{getDictObj(DICT_TYPE.contract_currency_unit, form.priceType)}
<span class="">
{form.budgetSum} {form.priceTypeName}
</span>
);
},
@ -260,7 +239,7 @@ export function getFormSchema(params: any = {}): any {
organiza: {
title: '组织形式',
key: 'organiza',
col: { span: 24 },
col: { span: 6 },
component: {
name: 'fs-dict-radio',
vModel: 'value',
@ -285,7 +264,6 @@ export function getFormSchema(params: any = {}): any {
);
},
},
rules: [{ required: true, message: '请选择组织形式' }],
},
fileList: {
title: '相关附件',
@ -294,39 +272,3 @@ export function getFormSchema(params: any = {}): any {
},
};
}
export function getColumns(params?: any): any {
const columns: VxeGridPropTypes.Columns = [
{ type: 'seq', title: '序号', width: 60 },
{ field: 'basisId', title: '依据号', width: 130 },
{
field: 'basisName',
title: '依据名称',
width: 200,
},
{ field: 'basisNum', title: '依据编号', width: 180 },
{
field: 'basisTypeId',
title: '依据类型',
width: 100,
slots: {
default: ({ row }) => {
return getDictObj(DICT_TYPE.contract_basis_type, row.basisTypeId)
?.label;
},
},
},
{
field: 'endDate',
title: '有效期',
width: 150,
slots: {
default: ({ row }) => {
return useRender.renderDate(row.endDate, 'YYYY-MM-DD');
},
},
},
];
return columns;
}

View File

@ -8,15 +8,18 @@ import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
import { FileUploader } from '#/utils/file';
import { getAuditInfoColumns } from '#/views/contract/schema';
import { getColumns, getFormSchema } 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 BasisTable from '#/views/contract/components/basis-table/basis-table.vue';
const props = withDefaults(
defineProps<{
// flowInstanceId
flowInstanceId: string;
contractId?: string;
id?: string;
}>(),
{
flowInstanceId: '',
id: '',
contractId: '',
},
@ -27,12 +30,8 @@ const { xGridRef: xGridRefByAuditInfo } = useVxeTable({
ref: 'xGridRefByAuditInfo',
});
const fileUploader = new FileUploader({});
const currData = ref<any>({});
const formRef = ref();
const isLoading = ref(false);
const contractTypeData = ref([]);
@ -40,52 +39,6 @@ const contractTypeData = ref([]);
const collapses = ['1', '2', '3'];
const collapseActiveKey = ref(collapses);
const formBinding = ref({
...(({ columns: _, ...rest }) => rest)(
getFormSchema({
contractTypeData: [],
}),
),
});
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
height: '200px',
columns: getColumns({ readOnly: true }),
data: [],
toolbarConfig: {
enabled: false,
},
pagerConfig: {
enabled: false,
},
rowConfig: {
useKey: true,
isCurrent: false,
},
}),
);
/** Hooks - 表格 */
const gridOptionsByAuditInfo = reactive(
gridProps({
height: '200px',
columns: getAuditInfoColumns({ readOnly: true }),
data: [],
toolbarConfig: {
enabled: false,
},
pagerConfig: {
enabled: false,
},
rowConfig: {
useKey: true,
isCurrent: false,
},
}),
);
onMounted(async () => {
isLoading.value = true;
try {
@ -99,40 +52,6 @@ onMounted(async () => {
params: { guid: props.id, contractId: props.contractId },
});
currData.value = data;
formBinding.value.columns = getFormSchema({
contractTypeData: contractTypeData.value,
readOnly: !props.id || currData.value.step !== 'edit',
}).columns;
xGridRef.value!.reloadColumn(getColumns());
nextTick(() => {
formRef.value.setFormData(data);
});
//
if (data.basisId) {
const basisList = await Apis.lxBasisSale.get_page({
params: { basisId: data.basisId },
});
nextTick(() => {
xGridRef.value!.insert(basisList.rows);
});
}
if (data.fileUuid) {
const files = await fileUploader.select(data.fileUuid);
nextTick(() => {
formRef.value.setFormData({
fileList: files,
});
});
}
} else {
formBinding.value.columns = getFormSchema({
contractTypeData: contractTypeData.value,
readOnly: false,
}).columns;
}
} catch (error) {
logger.error('获取合同信息出错', error);
@ -145,36 +64,17 @@ onMounted(async () => {
<template>
<div class="flex h-full w-full flex-col">
<a-collapse v-model:active-key="collapseActiveKey" :bordered="false">
<a-collapse v-model:active-key="collapseActiveKey">
<a-collapse-panel key="1" class="w-full" header="基本信息">
<fs-form ref="formRef" class="w-full" v-bind="formBinding">
<template #form_fileList="scope">
<a-upload
v-model:file-list="scope.form.fileList"
:max-count="3"
accept=".pdf,.ppt,.pptx"
name="file"
/>
</template>
</fs-form>
<ApprovalCard :info="currData"></ApprovalCard>
</a-collapse-panel>
<a-collapse-panel key="2" class="w-full" header="签约依据信息">
<template #extra> </template>
<VxeGrid ref="xGridRef" v-bind="gridOptions" class="">
<template #toolbar_buttons></template>
</VxeGrid>
<BasisTable :basis-id="currData.basisId" />
</a-collapse-panel>
<a-collapse-panel key="3" class="w-full" header="审批信息">
<template #extra> </template>
<VxeGrid
ref="xGridRefByAuditInfo"
v-bind="gridOptionsByAuditInfo"
class=""
>
<template #toolbar_buttons></template>
</VxeGrid>
<AuditNodeTable :flow-instance-id="props.flowInstanceId" />
</a-collapse-panel>
</a-collapse>
</div>

View File

@ -0,0 +1,68 @@
<script setup lang="ts">
import { DICT_TYPE, getDictObj, getDictOptions } from "#/utils/dict";
import FileCard from "#/views/contract/components/file-card/file-card.vue";
withDefaults(
defineProps<{
info: any;
}>(),
{
info: () => {},
}
);
</script>
<template>
<a-descriptions title="" size="small" :labelStyle="{ width: '150px' }" bordered>
<a-descriptions-item label="项目" :span="3">
{{ info.projectNum }}
</a-descriptions-item>
<a-descriptions-item label="项目类别" :span="1">
{{ getDictObj(DICT_TYPE.contract_project_type, info.projectProp)?.label }}
</a-descriptions-item>
<a-descriptions-item label="项目名称" :span="1">
{{ info.projectName }}
</a-descriptions-item>
<a-descriptions-item label="商务计价方式" :span="1">
{{ getDictObj(DICT_TYPE.contract_price_style, info.priceStyleId)?.label }}
</a-descriptions-item>
<a-descriptions-item label="备注" :span="3">
{{ info.remark || "无" }}
</a-descriptions-item>
<a-descriptions-item label="选商方式" :span="1">
{{ getDictObj(DICT_TYPE.contract_selection_method, info.choiceType)?.label }}
</a-descriptions-item>
<a-descriptions-item label="选商方式说明" :span="3">
{{ info.choiceReason || "无" }}
</a-descriptions-item>
<a-descriptions-item label="资质要求" :span="3">
{{ info.qualificReq || "无" }}
</a-descriptions-item>
<a-descriptions-item label="受托招标代理">
{{ (info.budgetSum || "") + " " + (info.priceTypeName || "") }}
</a-descriptions-item>
<a-descriptions-item label="推荐供应商" :span="3">
{{ info.stockPlanMx || "无" }}
</a-descriptions-item>
<a-descriptions-item label="项目范围" :span="3">
{{ info.projectRange || "无" }}
</a-descriptions-item>
<a-descriptions-item label="项目内容" :span="3">
{{ info.projectContent || "无" }}
</a-descriptions-item>
<a-descriptions-item label="工期/质量要求" :span="3">
{{ info.quality || "无" }}
</a-descriptions-item>
<a-descriptions-item label="工程量(采购量)" :span="3">
{{ info.stockNums || "无" }}
</a-descriptions-item>
<a-descriptions-item label="计划投资明细" :span="3">
{{ info.stockPlanMx || "无" }}
</a-descriptions-item>
</a-descriptions>
</template>

View File

@ -117,7 +117,7 @@ export function getFormSchemaByBusiness(params: any = {}) {
frameProtocol: {
title: '商务计价方式',
key: 'frameProtocol',
col: { span: 24 },
col: { span: 12 },
component: {
name: 'fs-dict-radio',
vModel: 'value',
@ -144,7 +144,7 @@ export function getFormSchemaByBusiness(params: any = {}) {
frameProtocolCtr: {
title: '选商方式',
key: 'frameProtocolCtr',
col: { span: 24 },
col: { span: 12 },
labelCol: { style: { width: '200px' } },
component: {
name: 'fs-dict-radio',

View File

@ -15,13 +15,19 @@ import {
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 BusinessCard from '#/views/contract/iframe-info/components/info-business/business-card.vue';
const props = withDefaults(
defineProps<{
flowInstanceId: string;
contractId?: string;
id?: string;
}>(),
{
flowInstanceId: '',
id: '',
contractId: '',
},
@ -38,9 +44,8 @@ const route = useRoute();
const id = ref(route.params.id);
const currData = ref<any>({});
const businseeData = ref<any>({});
const formRef = ref();
const formRefByBusiness = ref();
const isLoading = ref(false);
const contractTypeData = ref([]);
@ -48,60 +53,6 @@ const contractTypeData = ref([]);
const collapses = ['1', '2', '3', '4'];
const collapseActiveKey = ref(collapses);
const formBinding = ref({
...(({ columns: _, ...rest }) => rest)(
getFormSchema({
formRef,
}),
),
});
const formBindingByBusiness = ref({
...(({ columns: _, ...rest }) => rest)(
getFormSchemaByBusiness({
formRef,
}),
),
});
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
height: '200px',
columns: getColumnsByFiles({ readOnly: true }),
data: [],
toolbarConfig: {
enabled: false,
},
pagerConfig: {
enabled: false,
},
rowConfig: {
useKey: true,
isCurrent: false,
},
}),
);
/** Hooks - 表格 */
const gridOptionsByAuditInfo = reactive(
gridProps({
height: '200px',
columns: getAuditInfoColumns({ readOnly: true }),
data: [],
toolbarConfig: {
enabled: false,
},
pagerConfig: {
enabled: false,
},
rowConfig: {
useKey: true,
isCurrent: false,
},
}),
);
onMounted(async () => {
isLoading.value = true;
try {
@ -111,50 +62,16 @@ onMounted(async () => {
contractTypeData.value = contractReferTypeData.rows || [];
if (props.id || props.contractId) {
const data: any = await Apis.contractBaseInfo.get_getOne({
const contract: any = await Apis.contractBaseInfo.get_getOne({
params: { guid: props.id, contractId: props.contractId },
});
currData.value = data;
formBinding.value.columns = getFormSchema({
contractTypeData: contractTypeData.value,
readOnly: !props.id || currData.value.step !== 'edit',
}).columns;
formBindingByBusiness.value.columns = getFormSchemaByBusiness({
contractTypeData: contractTypeData.value,
readOnly: !props.id || currData.value.step !== 'edit',
}).columns;
currData.value = contract;
const business: any = await Apis.selectMerchantsBasicInfo.get_getOne({
params: { contractId: contract.contractId },
});
businseeData.value = business;
// xGridRef.value!.reloadColumn(getColumns());
nextTick(() => {
formRef.value.setFormData(data);
});
//
if (data.basisId) {
const basisList = await Apis.lxBasisSale.get_page({
params: { basisId: data.basisId },
});
nextTick(() => {
xGridRef.value!.insert(basisList.rows);
});
}
if (data.fileUuid) {
const files = await fileUploader.select(data.fileUuid);
nextTick(() => {
formRef.value.setFormData({
fileList: files,
});
});
}
} else {
formBinding.value.columns = getFormSchema({
contractTypeData: contractTypeData.value,
readOnly: false,
});
}
} catch (error) {
logger.error('获取合同信息出错', error);
@ -171,45 +88,21 @@ onMounted(async () => {
<template>
<div class="flex h-full w-full flex-col">
<a-collapse v-model:active-key="collapseActiveKey" :bordered="false">
<a-collapse v-model:active-key="collapseActiveKey">
<a-collapse-panel key="1" class="w-full" header="合同基本信息">
<fs-form ref="formRef" class="w-full" v-bind="formBinding">
<template #form_fileList="scope">
<a-upload
v-model:file-list="scope.form.fileList"
:max-count="3"
accept=".pdf,.ppt,.pptx"
name="file"
/>
</template>
</fs-form>
<ApprovalCard :info="currData" />
</a-collapse-panel>
<a-collapse-panel key="2" class="w-full" header="选商资料">
<template #extra> </template>
<fs-form
ref="formRefByBusiness"
class="w-full"
v-bind="formBindingByBusiness"
/>
<BusinessCard :info="businseeData" />
</a-collapse-panel>
<a-collapse-panel key="3" class="w-full" header="招标文件">
<template #extra> </template>
<VxeGrid ref="xGridRef" v-bind="gridOptions" class="">
<template #toolbar_buttons></template>
</VxeGrid>
<FileCard :fileUuids="''"></FileCard>
</a-collapse-panel>
<a-collapse-panel key="4" class="w-full" header="审批信息">
<template #extra> </template>
<VxeGrid
ref="xGridRefByAuditInfo"
v-bind="gridOptionsByAuditInfo"
class=""
>
<template #toolbar_buttons></template>
</VxeGrid>
<AuditNodeTable :flow-instance-id="props.flowInstanceId" />
</a-collapse-panel>
</a-collapse>
</div>

View File

@ -29,6 +29,7 @@ const Track = defineAsyncComponent(
const route = useRoute();
const type = route.query.type as string;
const id = route.query.id as string;
const flowInstanceId = route.query.f as string;
const contractId = route.query.contractId as string;
const tabKey = ref('approval');
@ -85,7 +86,12 @@ onMounted(() => {
<Page content-class="h-full">
<a-tabs v-model:active-key="tabKey">
<a-tab-pane v-for="item in tabList" :key="item.key" :tab="item.tab">
<component :is="item.component" :id="id" :contract-id="contractId" />
<component
:is="item.component"
:id="id"
:contract-id="contractId"
:flowInstanceId="flowInstanceId"
/>
</a-tab-pane>
</a-tabs>
</Page>

View File

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

View File

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

View File

@ -0,0 +1,71 @@
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';
export function getColumns(params: any = {}): VxeGridPropTypes.Columns {
return [
{ type: 'radio', width: 40, slots: { radio: 'radio_cell' }, align: 'center', fixed: 'left' },
{ field: 'contractId', title: '合同编号', width: 100 },
{
field: 'ctrName', title: '合同名称', minWidth: 200, slots: {
default: 'contract-name-slot'
}
},
{ field: 'contractAmount', title: '标的金额', width: 100 },
{ field: 'contractSubject', title: '合同标的', width: 150 },
{ field: 'contractCounterparty', title: '合同相对人', width: 150 },
{ field: 'cumulativeSettlementAmount', title: '累计结算金额', width: 150 },
{ field: 'changeCount', title: '变更次数', width: 100 },
{ field: 'contractStatus', title: '合同状态', width: 100 }
]
}
export function getFormSchema(_params: any = {}) {
return {
initialForm: { },
columns: {
contractName: {
title: '合同名称',
key: 'contractName',
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
},
autoSearchTrigger: 'enter',
show: true,
},
organiza: {
title: '组织形式',
key: 'organiza',
component: {
name: 'fs-dict-select',
vModel: 'value',
class: 'min-w-[180px]',
allowClear: true,
dict: dict({
data: getDictOptions(DICT_TYPE.contract_organization_form)
}),
},
autoSearchTrigger: 'enter',
show: true,
},
price: {
title: '预算金额',
key: 'price',
autoSearchTrigger: 'enter',
show: true,
},
time: {
title: '申报时间',
key: 'startDate',
autoSearchTrigger: 'enter',
show: true,
},
},
};
}

View File

@ -1,182 +1,130 @@
<script setup lang="ts">
import { computed, onMounted, reactive, ref } from "vue";
import { useRouter } from "vue-router";
import { Page } from "@vben/common-ui";
import { MdiExport, MdiRadioChecked, MdiRadioUnchecked, MdiUpdate } from "@vben/icons";
import { message } from "ant-design-vue";
import Apis from "#/api";
import { useVxeTable } from "#/hooks/vxeTable";
import { getColumns, getFormSchema, PrimaryKey } from "./crud.tsx";
const router = useRouter();
const searchRef = ref();
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: "xGridRef" });
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
columns: getColumns(),
proxyConfig: {
autoLoad: false,
ajax: {
query: async ({ page }) => {
let data = await Apis.personTask.get_page({
params: {
pageNum: page.currentPage,
pageSize: page.pageSize,
...searchRef.value?.formData,
},
});
return data;
},
},
},
pagerConfig: {
enabled: true,
},
toolbarConfig: {
enabled: true,
},
})
);
function handleEdit(record?: any) {
if (record && record[PrimaryKey]) {
router.push(`/contract/perform/edit/${record[PrimaryKey]}`);
}
}
function handleExport() {
const $grid = xGridRef.value;
if ($grid) {
$grid.exportData({
type: "xlsx",
});
message.success("导出成功");
}
}
/** 选中数据 */
const selectRow: any = computed(() => {
return xGridRef.value?.getRadioRecord() || null;
});
/** 单选框选中事件 */
const setSelectRow = (row: any) => {
if (selectRow.value && selectRow.value[PrimaryKey] === row[PrimaryKey]) {
xGridRef.value?.clearRadioRow();
} else {
xGridRef.value?.setRadioRow(row);
}
};
/** 表格单元格单击事件 */
function handleCellClick({ row }) {
setSelectRow(row);
}
onMounted(() => {
triggerProxy("reload");
});
const searchForm = ref({
...getFormSchema(),
onSearch(_context: any) {
triggerProxy("reload");
},
});
</script>
<template>
<Page contentClass="h-full flex flex-col">
<a-space direction="vertical" size="small">
<a-card title="待办" size="small">
<vxe-grid ref="xGridRef" v-bind="gridOptions">
<template #toolbar_buttons> </template>
</vxe-grid>
</a-card>
<a-card title="已办" size="small" contentClass="">
<vxe-grid ref="xGrid2Ref" v-bind="grid2Options">
<template #toolbar_buttons> </template>
</vxe-grid>
</a-card>
</a-space>
<Page content-class="h-full flex flex-col">
<fs-search ref="searchRef" v-bind="searchForm" />
<div class="min-h-300px flex-1">
<vxe-grid ref="xGridRef" v-bind="gridOptions" @cell-click="handleCellClick">
<template #toolbar_buttons>
<a-space>
<vben-button
:disabled="!selectRow || !selectRow[PrimaryKey]"
variant="warning"
@click="handleEdit(selectRow)"
>
<MdiUpdate class="mr-0.5 text-lg" />
信息维护
</vben-button>
<vben-button variant="primary" @click="handleExport()">
<MdiExport class="mr-0.5 text-lg" />
导出
</vben-button>
</a-space>
</template>
<template #radio_cell="{ row, checked }">
<span class="text-base" @click.stop="setSelectRow(row)">
<MdiRadioChecked v-if="checked" />
<MdiRadioUnchecked v-else />
</span>
</template>
</vxe-grid>
</div>
</Page>
</template>
<script setup lang="ts">
import { defineComponent, ref, reactive, onMounted } from 'vue';
import { FsCrud } from '@fast-crud/fast-crud';
import { type VxeGridProps } from 'vxe-table'
import { Page, useVbenModal } from '@vben/common-ui';
import { useVxeTable } from '#/hooks/vxeTable';
import {
type CreateCrudOptionsProps,
useColumns,
useFormWrapper,
useFs,
utils,
} from '@fast-crud/fast-crud';
import { MdiAdd, MdiUpdate, MdiDelete } from '@vben/icons';
import { dict } from "@fast-crud/fast-crud";
import Apis from '#/api'
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
const { xGridRef:xGrid2Ref, triggerProxy:triggerProxy2 } = useVxeTable({ ref: 'xGrid2Ref' });
const treeData = ref([]);
/** Hooks - 表格 */
const gridOptions = reactive(gridProps({
columns: [
{ type: 'seq', width: 50, align: 'center', fixed: 'left' },
{ field: 'contractId', title: '编号', width: 100 },
{
field: 'title', title: '名称', minWidth: 200, slots: {
default: ({ row }) => {
// let text = row.title
// if (text) {
// let classArr: string[] = ["line-clamp-3"];
// return h(
// NTooltip,
// { trigger: 'hover' },
// {
// trigger: () => h('span', { class: classArr.join(' ') }, text),
// default: () => text
// }
// )
// }
return '';
}
}
},
{ field: 'contractAmount', title: '模块', width: 150 },
{ field: 'contractSubject', title: '任务', width: 200 },
{ field: 'contractCounterparty', title: '分配时间', width: 150 },
{ field: 'cumulativeSettlementAmount', title: '承办单位/部门', width: 150 },
{ field: 'changeCount', title: '承办人', width: 100 },
{ field: 'contractStatus', title: '交接给', width: 100 }
],
proxyConfig: {
autoLoad: true,
ajax: {
query: ({ page }) => {
return Apis.ccsq.get_toDoPage({ params: { pageNum: page.currentPage, pageSize: page.pageSize, ...searchParams } })
}
},
},
pagerConfig: {
enabled: true
},
toolbarConfig: {
enabled: false
},
}));
/** Hooks - 表格 */
const grid2Options = reactive(gridProps({
columns: [
{ type: 'seq', width: 50, align: 'center', fixed: 'left' },
{ field: 'contractId', title: '编号', width: 100 },
{
field: 'title', title: '名称', minWidth: 200, slots: {
default: ({ row }) => {
// let text = row.title
// if (text) {
// let classArr: string[] = ["line-clamp-3"];
// return h(
// NTooltip,
// { trigger: 'hover' },
// {
// trigger: () => h('span', { class: classArr.join(' ') }, text),
// default: () => text
// }
// )
// }
return '';
}
}
},
{ field: 'contractAmount', title: '模块', width: 150 },
{ field: 'contractSubject', title: '任务', width: 200 },
{ field: 'contractCounterparty', title: '分配时间', width: 150 },
{ field: 'cumulativeSettlementAmount', title: '承办单位/部门', width: 150 },
{ field: 'changeCount', title: '承办人', width: 100 },
{ field: 'contractStatus', title: '交接给', width: 100 }
],
proxyConfig: {
autoLoad: true,
ajax: {
query: ({ page }) => {
return Apis.ccsq.get_donePage({ params: { pageNum: page.currentPage, pageSize: page.pageSize, ...searchParams } })
}
},
},
pagerConfig: {
enabled: true
},
toolbarConfig: {
enabled: false
},
}));
onMounted(() => {
})
let searchParams = reactive({})
const searchForm = ref({
columns: {
name: {
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
props: {
type: 'text',
showWordLimit: true,
},
},
title: '字典标签',
key: 'type',
autoSearchTrigger: 'enter',
show: true,
},
age: {
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
},
title: '字典键值',
key: 'value',
autoSearchTrigger: 'enter',
show: true,
},
},
onSearch(context: any) {
searchParams = context.form
triggerProxy('reload')
},
onReset(context: any) {
searchParams = context.form
},
});
//
</script>
<style></style>

View File

@ -1,182 +1,12 @@
<script setup lang="ts">
import { Page } from '@vben/common-ui';
import TodoPage from '../../components/todo-page/todo-page.vue';
</script>
<template>
<Page contentClass="h-full flex flex-col">
<a-space direction="vertical" size="small">
<a-card title="待办" size="small">
<vxe-grid ref="xGridRef" v-bind="gridOptions">
<template #toolbar_buttons> </template>
</vxe-grid>
</a-card>
<a-card title="已办" size="small" contentClass="">
<vxe-grid ref="xGrid2Ref" v-bind="grid2Options">
<template #toolbar_buttons> </template>
</vxe-grid>
</a-card>
</a-space>
<Page content-class="h-full">
<TodoPage :module="['contractPerform']" />
</Page>
</template>
<script setup lang="ts">
import { defineComponent, ref, reactive, onMounted } from 'vue';
import { FsCrud } from '@fast-crud/fast-crud';
import { type VxeGridProps } from 'vxe-table'
import { Page, useVbenModal } from '@vben/common-ui';
import { useVxeTable } from '#/hooks/vxeTable';
import {
type CreateCrudOptionsProps,
useColumns,
useFormWrapper,
useFs,
utils,
} from '@fast-crud/fast-crud';
import { MdiAdd, MdiUpdate, MdiDelete } from '@vben/icons';
import { dict } from "@fast-crud/fast-crud";
import Apis from '#/api'
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
const { xGridRef:xGrid2Ref, triggerProxy:triggerProxy2 } = useVxeTable({ ref: 'xGrid2Ref' });
const treeData = ref([]);
/** Hooks - 表格 */
const gridOptions = reactive(gridProps({
columns: [
{ type: 'seq', width: 50, align: 'center', fixed: 'left' },
{ field: 'contractId', title: '编号', width: 100 },
{
field: 'title', title: '名称', minWidth: 200, slots: {
default: ({ row }) => {
// let text = row.title
// if (text) {
// let classArr: string[] = ["line-clamp-3"];
// return h(
// NTooltip,
// { trigger: 'hover' },
// {
// trigger: () => h('span', { class: classArr.join(' ') }, text),
// default: () => text
// }
// )
// }
return '';
}
}
},
{ field: 'contractAmount', title: '模块', width: 150 },
{ field: 'contractSubject', title: '任务', width: 200 },
{ field: 'contractCounterparty', title: '分配时间', width: 150 },
{ field: 'cumulativeSettlementAmount', title: '承办单位/部门', width: 150 },
{ field: 'changeCount', title: '承办人', width: 100 },
{ field: 'contractStatus', title: '交接给', width: 100 }
],
proxyConfig: {
autoLoad: true,
ajax: {
query: ({ page }) => {
return Apis.ccsq.get_toDoPage({ params: { pageNum: page.currentPage, pageSize: page.pageSize, ...searchParams } })
}
},
},
pagerConfig: {
enabled: true
},
toolbarConfig: {
enabled: false
},
}));
/** Hooks - 表格 */
const grid2Options = reactive(gridProps({
columns: [
{ type: 'seq', width: 50, align: 'center', fixed: 'left' },
{ field: 'contractId', title: '编号', width: 100 },
{
field: 'title', title: '名称', minWidth: 200, slots: {
default: ({ row }) => {
// let text = row.title
// if (text) {
// let classArr: string[] = ["line-clamp-3"];
// return h(
// NTooltip,
// { trigger: 'hover' },
// {
// trigger: () => h('span', { class: classArr.join(' ') }, text),
// default: () => text
// }
// )
// }
return '';
}
}
},
{ field: 'contractAmount', title: '模块', width: 150 },
{ field: 'contractSubject', title: '任务', width: 200 },
{ field: 'contractCounterparty', title: '分配时间', width: 150 },
{ field: 'cumulativeSettlementAmount', title: '承办单位/部门', width: 150 },
{ field: 'changeCount', title: '承办人', width: 100 },
{ field: 'contractStatus', title: '交接给', width: 100 }
],
proxyConfig: {
autoLoad: true,
ajax: {
query: ({ page }) => {
return Apis.ccsq.get_donePage({ params: { pageNum: page.currentPage, pageSize: page.pageSize, ...searchParams } })
}
},
},
pagerConfig: {
enabled: true
},
toolbarConfig: {
enabled: false
},
}));
onMounted(() => {
})
let searchParams = reactive({})
const searchForm = ref({
columns: {
name: {
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
props: {
type: 'text',
showWordLimit: true,
},
},
title: '字典标签',
key: 'type',
autoSearchTrigger: 'enter',
show: true,
},
age: {
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
},
title: '字典键值',
key: 'value',
autoSearchTrigger: 'enter',
show: true,
},
},
onSearch(context: any) {
searchParams = context.form
triggerProxy('reload')
},
onReset(context: any) {
searchParams = context.form
},
});
//
</script>
<style></style>
<style scoped></style>

View File

@ -5,6 +5,7 @@ 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';
@ -16,22 +17,29 @@ export function getTodoColumns(_params: any = {}): VxeGridPropTypes.Columns {
{
field: 'contractName',
title: '名称',
minWidth: 200,
minWidth: 250,
slots: { default: 'title_slot' },
},
{
field: 'module',
title: '模块',
width: 150,
width: 120,
slots: {
default: ({ row }) => {
return (
getDictObj(DICT_TYPE.contract_todo_type, row.module)?.label || ''
);
return row.flowName;
},
},
},
{
field: 'taskName',
title: '任务',
width: 150,
slots: {
default: ({ row }) => {
return row.taskName;
},
},
},
{ field: 'taskName', title: '任务', width: 200 },
{ field: 'createTime', title: '分配时间', width: 150 },
{ field: 'inputDepartName', title: '承办单位/部门', width: 150 },
{ field: 'assigneeName', title: '承办人', width: 100 },
@ -52,11 +60,11 @@ export function getApprovalColumns(
): VxeGridPropTypes.Columns {
return [
{ type: 'seq', width: 50, align: 'center', fixed: 'left' },
{ field: 'contractId', title: '编号', width: 100 },
{ field: 'contractId', title: '编号', width: 150 },
{
field: 'title',
title: '任务名称',
minWidth: 200,
minWidth: 250,
slots: {
default: ({ row }) => {
const text = row.title;
@ -90,43 +98,24 @@ export function getAuditInfoColumns(
): VxeGridPropTypes.Columns {
return [
{ type: 'seq', width: 50, align: 'center', fixed: 'left' },
{ field: 'contractId', title: '编号', width: 100 },
// { field: 'contractId', title: '编号', width: 100 },
{
field: 'title',
field: 'taskName',
title: '任务名称',
minWidth: 200,
slots: {
default: ({ row }) => {
const text = row.title;
if (text) {
const classArr: string[] = ['line-clamp-3'];
return h(
Tooltip,
{ trigger: 'hover' },
{
trigger: () => h('span', { class: classArr.join(' ') }, text),
default: () => text,
},
);
}
return '';
},
},
},
{ field: 'contractAmount', title: '送审方式', width: 150 },
{ field: 'contractSubject', title: '审批级别', width: 200 },
{ field: 'contractCounterparty', title: '审批人', width: 150 },
{ field: 'cumulativeSettlementAmount', title: '送审时间', width: 150 },
{ field: 'changeCount', title: '审批时间', width: 100 },
{ field: 'contractStatus', title: '审批状态', width: 100 },
{ field: 'contractStatus', title: '审批意见', width: 100 },
{ field: 'assigneeId', title: '审批人', width: 150 },
{ field: 'startTime', title: '送审时间', width: 150 },
{ field: 'endTime', title: '审批时间', width: 150 },
{ field: 'type', title: '审批状态', width: 100 },
{ field: 'message', title: '审批意见', width: 100 },
];
}
export function getColumnsByFiles(_params: any = {}): VxeGridPropTypes.Columns {
return [
{ type: 'seq', width: 50, align: 'center', fixed: 'left' },
{ field: 'contractId', title: '附件编号', width: 100 },
{ type: 'seq', width: 60, align: 'center', fixed: 'left' },
{ field: 'contractId', title: '附件编号', width: 120 },
{
field: 'name',
title: '附件名称',

View File

@ -146,7 +146,6 @@ async function handleSave() {
}
}
debugger;
console.log('提交表单', form, formByAuthRange);
// name
@ -265,9 +264,11 @@ async function handleSubmit(type) {
}
onMounted(async () => {
const data = await getDictDatasAsync([
DICT_TYPE.contract_authorization_period,
]);
const data = await getDictDatasAsync(
[DICT_TYPE.contract_authorization_period].map((item) => ({
type: item,
})),
);
console.log(data);
formBinding.value.columns = getFormSchema({

View File

@ -1,27 +1,22 @@
<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(
@ -49,14 +44,14 @@ const gridOptions = reactive(
toolbarConfig: {
enabled: true,
},
}),
})
);
function handleEdit(record?: any) {
if (record && record[PrimaryKey]) {
router.push(`/contract/sign/edit/${record[PrimaryKey]}`);
} else {
router.push('/contract/sign/edit');
router.push("/contract/sign/edit");
}
}
@ -64,9 +59,9 @@ function handleExport() {
const $grid = xGridRef.value;
if ($grid) {
$grid.exportData({
type: 'xlsx',
type: "xlsx",
});
message.success('导出成功');
message.success("导出成功");
}
}
@ -90,13 +85,13 @@ function handleCellClick({ row }) {
}
onMounted(() => {
triggerProxy('reload');
triggerProxy("reload");
});
const searchForm = ref({
...getFormSchema(),
onSearch(_context: any) {
triggerProxy('reload');
triggerProxy("reload");
},
});
</script>
@ -106,11 +101,7 @@ const searchForm = ref({
<fs-search ref="searchRef" v-bind="searchForm" />
<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
@ -119,7 +110,7 @@ const searchForm = ref({
@click="handleEdit(selectRow)"
>
<MdiUpdate class="mr-0.5 text-lg" />
修改
信息维护
</vben-button>
<vben-button variant="primary" @click="handleExport()">
<MdiExport class="mr-0.5 text-lg" />

View File

@ -1,9 +1,12 @@
<script setup lang="ts">
import TodoPage from '../../components/todo-page/todo-page.vue';
import { Page } from "@vben/common-ui";
import TodoPage from "../../components/todo-page/todo-page.vue";
</script>
<template>
<TodoPage :module="['contractSign']" />
<Page content-class="h-full">
<TodoPage :module="['contractSign']" />
</Page>
</template>
<style scoped></style>

View File

@ -1,26 +1,4 @@
import Apis from '#/api';
import { router } from '#/router';
/**
*
* @param type
* @param id
*/
export function toDetail(type: string, id: string, params?: any) {
switch (type) {
case 'contractSetup': {
router.push(`/contract/approval/edit/${id}`);
break;
}
case 'selectMerchant': {
router.push(`/contract/business/edit/${id}`);
break;
}
default: {
break;
}
}
}
/**
*
@ -28,7 +6,7 @@ export function toDetail(type: string, id: string, params?: any) {
* @param id
*/
export function toDetailPage(type: string, id: string, params?: any) {
const { contractId } = params || {};
const { contractId, flowInstanceId } = params || {};
const name = '合同详情'; // 网页名称,可为空;
const iWidth = 1200; // 弹出窗口的宽度;
const iHeight = 800; // 弹出窗口的高度;
@ -38,16 +16,36 @@ export function toDetailPage(type: string, id: string, params?: any) {
const queryParams = new URLSearchParams();
if (type !== undefined) queryParams.append('type', type);
if (flowInstanceId !== undefined) queryParams.append('f', flowInstanceId);
if (id !== undefined) queryParams.append('id', id);
if (contractId !== undefined) queryParams.append('contractId', contractId);
const url = `/iframe/contract/info?${queryParams.toString()}`;
window.open(
url,
name,
`height=${iHeight},innerHeight=${iHeight},width=${iWidth},innerWidth=${iWidth},top=${iTop},left=${iLeft},toolbar=no,menubar=no,scrollbars=auto,resizable=no,location=no,status=no`,
);
// 5. 创建一个新的 <a> 标签
const a = document.createElement('a');
// 6. 设置 <a> 标签的属性
a.href = url; // 目标 URL
a.target = '_blank'; // 在新标签页中打开
a.rel = 'noopener noreferrer'; // 增加安全性,防止新页面获取原页面的 window 对象
// 7. 隐藏 <a> 标签
a.style.display = 'none'; // 设置为不可见
// 8. 将 <a> 标签添加到页面中
document.body.appendChild(a);
// 9. 模拟点击 <a> 标签
a.click();
// 10. 点击完成后,移除 <a> 标签
document.body.removeChild(a);
// window.open(
// url,
// name,
// `height=${iHeight},innerHeight=${iHeight},width=${iWidth},innerWidth=${iWidth},top=${iTop},left=${iLeft},toolbar=no,menubar=no,scrollbars=auto,resizable=no,location=no,status=no`,
// );
}
/**

View File

@ -5,81 +5,29 @@ import { Page } from '@vben/common-ui';
import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
import { DICT_TYPE, getDictOptions } from '#/utils/dict';
import { getTodoColumns } from '#/views/contract/schema';
import { toDetail, toDetailPage } from '#/views/contract/utils';
import { DICT_TYPE, getDictDatasAsync, getDictOptions } from '#/utils/dict';
import TodoPage from '#/views/contract/components/todo-page/todo-page.vue';
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
const { xGridRef: xGrid2Ref, triggerProxy: triggerProxy2 } = useVxeTable({
ref: 'xGrid2Ref',
});
const treeData = ref();
const todoPageRef = ref();
const selectedKeys = ref<string[]>([]);
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
columns: getTodoColumns({ type: 'todo' }),
proxyConfig: {
autoLoad: true,
ajax: {
query: ({ page }) => {
return Apis.home.get_todo({
params: {
pageNum: page.currentPage,
pageSize: page.pageSize,
moduleId: selectedKeys.value[0],
},
});
},
},
},
pagerConfig: {
enabled: true,
},
toolbarConfig: {
enabled: false,
},
}),
);
let treeKeys = ref([]);
/** Hooks - 表格 */
const grid2Options = reactive(
gridProps({
columns: getTodoColumns({ type: 'done' }),
proxyConfig: {
autoLoad: true,
ajax: {
query: ({ page }) => {
return Apis.home.get_done({
params: {
pageNum: page.currentPage,
pageSize: page.pageSize,
moduleId: selectedKeys.value[0],
},
});
},
},
},
pagerConfig: {
enabled: true,
},
toolbarConfig: {
enabled: false,
},
}),
);
function onTreeSelect() {
triggerProxy('reload');
triggerProxy2('reload');
function onTreeSelect(e) {
console.log(e);
treeKeys.value = e;
}
const expandedKeys = ref<string[]>([]);
async function loadDataByDictType() {
const data = getDictOptions(DICT_TYPE.contract_todo_type);
const dictMap = await getDictDatasAsync(
[DICT_TYPE.contract_todo_type].map((item) => ({
type: item,
})),
);
const data = dictMap[DICT_TYPE.contract_todo_type] || [];
data.forEach((item) => {
item.key = item.value;
item.title = item.label;
@ -112,58 +60,7 @@ onMounted(() => {
</a-card>
</a-col>
<a-col :span="19" class="min-w-700px flex flex-col">
<a-card
:body-style="{ flex: '1' }"
class="flex h-full flex-col"
size="small"
title="待办"
>
<vxe-grid ref="xGridRef" v-bind="gridOptions" class="flex-1">
<template #toolbar_buttons> </template>
<template #title_slot="{ row }">
<span
class="cursor-pointer text-blue-500 hover:underline"
@click="toDetail(row.module, row.businessId, row)"
>
{{ row.contractName }}
</span>
</template>
<template #operate="{ row }">
<a-button
class="text-blue-500"
size="small"
type="text"
@click="
toDetailPage('approval', '', { contractId: row.contractId })
"
>
查看
</a-button>
</template>
</vxe-grid>
</a-card>
<a-card
:body-style="{ flex: '1' }"
class="flex h-full flex-col"
size="small"
title="已办"
>
<vxe-grid ref="xGrid2Ref" v-bind="grid2Options" class="flex-1">
<template #toolbar_buttons> </template>
<template #operate="{ row }">
<a-button
class="text-blue-500"
size="small"
type="text"
@click="
toDetailPage('approval', '', { contractId: row.contractId })
"
>
查看
</a-button>
</template>
</vxe-grid>
</a-card>
<TodoPage ref="todoPageRef" v-model:module="treeKeys"></TodoPage>
</a-col>
</a-row>
</Page>

View File

@ -33,6 +33,34 @@ export default defineConfig(async () => {
target: `http://192.168.147.164:8083/rl`,
ws: true,
},
'/api/flowCenter': {
changeOrigin: true,
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'),
// 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'),
// 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'),
// target: `http://10.71.220.24:8083/rl`,
target: `http://192.168.147.164:19007`,
ws: true,
},
'/api/czg/app': {
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api\/czg\/app/, '/'),

View File

@ -0,0 +1,37 @@
import type { VxeGridPropTypes } from 'vxe-table';
import dayjs from 'dayjs';
import { useRender } from '#/hooks/useRender';
export const PrimaryKey = 'guid';
export function getFlowRecordColumns(_params: any = {}): VxeGridPropTypes.Columns {
return [
{
field: 'flowNodeId',
title: '节点名称',
width: 200,
},
{
field: 'taskName',
title: '操作',
width: 200,
},
{
field: 'assigneeId',
title: '处理人',
width: 200,
},
{
field: 'startTime',
title: '处理时间',
width: 200,
},
{
field: 'type',
title: '处理意见',
width: 200,
},
];
}

View File

@ -116,6 +116,8 @@ const [TemporaryModal, temporaryModalApi] = useVbenModal({
});
async function handleAudit(row, type) {
const hideLoading = message.loading('加载中', 0);
selectRow.value = row;
//
@ -123,28 +125,38 @@ async function handleAudit(row, type) {
params: { taskId: row.taskId },
});
nodeInfo.value = tempNodeInfo = tempNodeInfo.rows[0];
hideLoading();
chooseUserModalApi.setData({
title: `选择${tempNodeInfo.name}(${tempNodeInfo.selectMode})`,
limitMultipleNum: tempNodeInfo.selectMode === '多选' ? 10 : 1,
userIds: chooseUserIds.value || [],
});
if (type === 'access') {
chooseUserModalApi.open();
return;
if (nodeInfo.value && nodeInfo.value.name) {
chooseUserModalApi.setData({
title: `选择${tempNodeInfo.name}(${tempNodeInfo.selectMode})`,
limitMultipleNum: tempNodeInfo.selectMode === '多选' ? 10 : 1,
userIds: chooseUserIds.value || [],
});
if (type === 'access') {
chooseUserModalApi.open();
return;
}
} else {
if (type === 'access') {
type = 'accessConfirm';
}
}
if (type === 'accessConfirm') {
try {
let form = {
guid: selectRow.value.guid,
variables: {},
comment: '通过',
};
if (tempNodeInfo && tempNodeInfo.tempNodeInfo) {
form.variables = {
[nodeInfo.value.variableName]: assigneeList.value,
};
}
await Apis.ccsq.post_submit({
data: {
guid: selectRow.value.guid,
variables: {
[nodeInfo.value.variableName]: assigneeList.value,
},
comment: '通过',
},
data: form,
});
message.success('提交成功');
triggerProxy('reload');
@ -183,21 +195,29 @@ async function handleAudit(row, type) {
};
temporaryModalApi.open();
isConfirmLoading.value = true;
isConfirmLoading.value = false;
}
if (type === 'rejectConfirm') {
await Apis.ccsq.post_rollback({
params: {
...form2Ref.value.form,
guid: selectRow.value.guid,
backNodeId: 'userTask_first_node',
},
});
temporaryModalApi.close();
isConfirmLoading.value = false;
triggerProxy('reload');
triggerProxy2('reload');
isConfirmLoading.value = true;
try {
await Apis.ccsq.post_rollback({
params: {
...form2Ref.value.form,
guid: selectRow.value.guid,
backNodeId: 'userTask_first_node',
},
});
temporaryModalApi.close();
isConfirmLoading.value = false;
triggerProxy('reload');
triggerProxy2('reload');
} catch (error) {
logger.error('出差审批退回出错', error);
} finally {
isConfirmLoading.value = false;
}
}
}

View File

@ -243,6 +243,7 @@ function handleUserRowClick(row) {
formRef.value?.setFormData({
[`${selectField.value}People`]: row.label,
[`${selectField.value}Telphone`]: row.mobile,
[`${selectField.value}Phone`]: row.PHONE,
});
console.log(peoples);
console.log(formRef.value?.form);

View File

@ -251,23 +251,23 @@ function checkOverflow() {
<span class="text-gray-700">{{ currData.meetingType }}</span>
</div>
<div v-if="isRepresentativesMeeting" class="flex items-center">
<div class="mr-2 w-[120px] font-bold">职工代表:</div>
<div class="mr-2 font-bold">职工代表:</div>
<span class="text-green-500">{{
currData.isEmployeeRepresentatives == 1 ? '是' : '否'
}}</span>
</div>
</div>
<div class="flex space-x-4">
<div class="flex items-center">
<div class="mr-2 w-[120px] font-bold">会议内容:</div>
<div class="flex items-start">
<div class="mr-2 font-bold">会议内容:</div>
<span class="text-gray-700" style="white-space: pre-line">{{
currData.meetingContent
}}</span>
</div>
</div>
<div class="flex space-x-4">
<div class="flex items-center">
<div class="mr-2 w-[120px] font-bold">会议附件:</div>
<div class="flex items-start">
<div class="mr-2 font-bold">会议附件:</div>
</div>
</div>
<div class="flex space-x-4">

View File

@ -80,6 +80,7 @@ function getColumns(_params: any = {}): VxeGridPropTypes.Columns {
{ field: 'EMPLOYEE_GENDER', title: '性别', width: 80 },
{ field: 'MAIL_ADDRESS', title: '邮箱', width: 150 },
{ field: 'PHONE_NUM', title: '联系方式', width: 120 },
{ field: 'PHONE', title: '办公室电话', width: 120 },
{ field: 'ORG_NAME', title: '所属组织', minWidth: 120 },
];
return columns;

View File

@ -1,6 +1,5 @@
import type { BodyOptions, QueryOptions } from './global.d';
import { http } from './request/index';
import type { QueryOptions, BodyOptions } from './global.d';
export default {
meeting: {
@ -173,6 +172,11 @@ export default {
/** 协同办公/出差申请 下一审核节点 */
post_getNextNodeUserConfig: (data?: BodyOptions) =>
http.post('/app/ccsq/getNextNodeUserConfig', data),
/** 协同办公/出差申请 查看出差信息 */
get_getBusinessTripInfo: (data?: QueryOptions) =>
http.get('/app/ccsq/getBusinessTripInfo', data),
/** 协同办公/出差申请 查看审核过程 */
get_history: (data?: QueryOptions) => http.get('/app/ccsq/history', data),
},
orderfood: {
/** 协同办公/订餐管理/订餐 订餐加载接口 */
@ -416,9 +420,6 @@ export default {
/** 合同系统/立项废除 退回 */
post_rollback: (data?: BodyOptions) =>
http.post('/app/contractBaseInfo/rollback', data),
/** 合同系统/立项废除 合同立项废除 */
post_abolish: (data?: BodyOptions) =>
http.post('/app/contractBaseInfo/abolish', data),
/** 合同系统/立项废除 提交 */
post_abolishSubmit: (data?: BodyOptions) =>
http.post('/app/contractBaseInfo/abolishSubmit', data),
@ -828,12 +829,15 @@ export default {
/** 合同系统/签约授权 查询单条签约授权数据 */
get_getOne: (data?: QueryOptions) =>
http.get('/app/sqConsignPt/getOne', data),
/** 合同系统/签约授权 签约授权提交 */
/** 合同系统/签约授权 签约授权提交(非待办提交) */
post_flowStart: (data?: BodyOptions) =>
http.post('/app/sqConsignPt/flowStart', data),
/** 合同系统/签约授权 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/sqConsignPt/deletes', data),
/** 合同系统/签约授权 签约授权提交 */
post_submit: (data?: BodyOptions) =>
http.post('/app/sqConsignPt/submit', data),
},
addressorsort: {
/** 协同办公/会议管理/发言人顺序配置 发言人顺序查询 */
@ -846,4 +850,89 @@ export default {
post_deletes: (data?: BodyOptions) =>
http.post('/app/addressorsort/deletes', data),
},
equInfo: {
/** 设备管理/设备静态库管理/ 设备信息维护 设备信息保存 */
post_save: (data?: BodyOptions) => http.post('/app/equInfo/save', data),
/** 设备管理/设备静态库管理/ 设备信息维护 设备信息(获取/查询) */
get_page: (data?: QueryOptions) => http.get('/app/equInfo/page', data),
/** 设备管理/设备静态库管理/ 设备信息维护 设备信息删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/equInfo/deletes', data),
},
equAllot: {
/** 设备管理/查询管理/设备调拨查询 查询 */
get_page: (data?: QueryOptions) => http.get('/app/equAllot/page', data),
/** 设备管理/设备静态库管理/设备调拨 调拨信息保存 */
post_save: (data?: BodyOptions) => http.post('/app/equAllot/save', data),
/** 设备管理/设备静态库管理/设备调拨 调拨信息删除 */
post_delete: (data?: BodyOptions) =>
http.post('/app/equAllot/delete', data),
},
bidding: {
/** 合同系统/标段信息 标段查询 */
get_list: (data?: QueryOptions) => http.get('/app/bidding/list', data),
/** 合同系统/标段信息 标段信息保存(弃用,在选商中报错) */
post_save: (data?: BodyOptions) => http.post('/app/bidding/save', data),
/** 合同系统/标段信息 标段信息删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/bidding/deletes', data),
},
equAccident: {
/** 设备管理/设备使用管理/事故处理 事故处理(查询/获取) */
get_page: (data?: QueryOptions) => http.get('/app/equAccident/page', data),
/** 设备管理/设备使用管理/事故处理 保存 */
post_save: (data?: BodyOptions) => http.post('/app/equAccident/save', data),
/** 设备管理/设备使用管理/事故处理 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/equAccident/deletes', data),
/** 设备管理/查询管理/事故处理查询 查询 */
get_query: (data?: QueryOptions) =>
http.get('/app/equAccident/query', data),
},
equStopRepair: {
/** 设备管理/设备使用管理/停炉检修处理 查询 */
get_page: (data?: QueryOptions) =>
http.get('/app/equStopRepair/page', data),
/** 设备管理/设备使用管理/停炉检修处理 保存 */
post_save: (data?: BodyOptions) =>
http.post('/app/equStopRepair/save', data),
/** 设备管理/设备使用管理/停炉检修处理 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/equStopRepair/deletes', data),
/** 设备管理/查询管理/停炉检修处理查询 查询 */
get_query: (data?: QueryOptions) =>
http.get('/app/equStopRepair/query', data),
},
equDanger: {
/** 设备管理/设备使用管理/隐患排查 查询 */
get_page: (data?: QueryOptions) => http.get('/app/equDanger/page', data),
/** 设备管理/设备使用管理/隐患排查 保存 */
post_save: (data?: BodyOptions) => http.post('/app/equDanger/save', data),
/** 设备管理/设备使用管理/隐患排查 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/equDanger/deletes', data),
/** 设备管理/查询管理/隐患排查处理查询 查询 */
get_query: (data?: QueryOptions) => http.get('/app/equDanger/query', data),
},
equDayRepair: {
/** 设备管理/设备使用管理/日常维修 查询 */
get_page: (data?: QueryOptions) => http.get('/app/equDayRepair/page', data),
/** 设备管理/设备使用管理/日常维修 保存 */
post_save: (data?: BodyOptions) =>
http.post('/app/equDayRepair/save', data),
/** 设备管理/设备使用管理/日常维修 删除 */
get_deletes: (data?: QueryOptions) =>
http.get('/app/equDayRepair/deletes', data),
/** 设备管理/查询管理/日常维修查询 查询 */
get_query: (data?: QueryOptions) =>
http.get('/app/equDayRepair/query', data),
},
contractRecommendProvider: {
/** 合同系统/选商/合同推荐供应商信息 推荐供应商查询 */
get_list: (data?: QueryOptions) =>
http.get('/app/contractRecommendProvider/list', data),
/** 合同系统/选商/合同推荐供应商信息 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/contractRecommendProvider/deletes', data),
},
};