23 changed files with 2235 additions and 280 deletions
@ -0,0 +1,57 @@ |
|||||
|
import { defHttp } from '@/utils/http/axios'; |
||||
|
import { ID, IDS, commonExport } from '@/api/base'; |
||||
|
import { ContractualInfoVO, ContractualInfoForm, ContractualInfoQuery } from './model'; |
||||
|
|
||||
|
/** |
||||
|
* 查询合同信息保存列表 |
||||
|
* @param params |
||||
|
* @returns |
||||
|
*/ |
||||
|
export function ContractualInfoList(params?: ContractualInfoQuery) { |
||||
|
return defHttp.get<ContractualInfoVO[]>({ url: '/productManagement/ContractualInfo/list', params }); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 导出合同信息保存列表 |
||||
|
* @param params |
||||
|
* @returns |
||||
|
*/ |
||||
|
export function ContractualInfoExport(params?: ContractualInfoQuery) { |
||||
|
return commonExport('/productManagement/ContractualInfo/export', params ?? {}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 查询合同信息保存详细 |
||||
|
* @param id id |
||||
|
* @returns |
||||
|
*/ |
||||
|
export function ContractualInfoInfo(id: ID) { |
||||
|
return defHttp.get<ContractualInfoVO>({ url: '/productManagement/ContractualInfo/' + id }); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 新增合同信息保存 |
||||
|
* @param data |
||||
|
* @returns |
||||
|
*/ |
||||
|
export function ContractualInfoAdd(data: ContractualInfoForm) { |
||||
|
return defHttp.postWithMsg<void>({ url: '/productManagement/ContractualInfo', data }); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 更新合同信息保存 |
||||
|
* @param data |
||||
|
* @returns |
||||
|
*/ |
||||
|
export function ContractualInfoUpdate(data: ContractualInfoForm) { |
||||
|
return defHttp.putWithMsg<void>({ url: '/productManagement/ContractualInfo', data }); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 删除合同信息保存 |
||||
|
* @param id id |
||||
|
* @returns |
||||
|
*/ |
||||
|
export function ContractualInfoRemove(id: ID | IDS) { |
||||
|
return defHttp.deleteWithMsg<void>({ url: '/productManagement/ContractualInfo/' + id },); |
||||
|
} |
@ -0,0 +1,90 @@ |
|||||
|
import { BaseEntity, PageQuery } from '@/api/base'; |
||||
|
|
||||
|
export interface ContractualInfoVO { |
||||
|
/** |
||||
|
* 合同名称 |
||||
|
*/ |
||||
|
fileName: string; |
||||
|
|
||||
|
/** |
||||
|
* 采购人名称 |
||||
|
*/ |
||||
|
purchaserName: string; |
||||
|
|
||||
|
/** |
||||
|
* 供应商名称或姓名 |
||||
|
*/ |
||||
|
supplierName: string; |
||||
|
|
||||
|
/** |
||||
|
* 合同签订时间 |
||||
|
*/ |
||||
|
signDate: string; |
||||
|
|
||||
|
/** |
||||
|
* 合同金额 |
||||
|
*/ |
||||
|
contractAmount: string; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
export interface ContractualInfoForm extends BaseEntity { |
||||
|
/** |
||||
|
* 合同名称 |
||||
|
*/ |
||||
|
fileName?: string; |
||||
|
|
||||
|
/** |
||||
|
* 采购人名称 |
||||
|
*/ |
||||
|
purchaserName?: string; |
||||
|
|
||||
|
/** |
||||
|
* 供应商名称或姓名 |
||||
|
*/ |
||||
|
supplierName?: string; |
||||
|
|
||||
|
/** |
||||
|
* 合同签订时间 |
||||
|
*/ |
||||
|
signDate?: string; |
||||
|
|
||||
|
/** |
||||
|
* 合同金额 |
||||
|
*/ |
||||
|
contractAmount?: string; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
export interface ContractualInfoQuery extends PageQuery { |
||||
|
|
||||
|
/** |
||||
|
* 合同名称 |
||||
|
*/ |
||||
|
fileName?: string; |
||||
|
|
||||
|
/** |
||||
|
* 采购人名称 |
||||
|
*/ |
||||
|
purchaserName?: string; |
||||
|
|
||||
|
/** |
||||
|
* 供应商名称或姓名 |
||||
|
*/ |
||||
|
supplierName?: string; |
||||
|
|
||||
|
/** |
||||
|
* 合同签订时间 |
||||
|
*/ |
||||
|
signDate?: string; |
||||
|
|
||||
|
/** |
||||
|
* 合同金额 |
||||
|
*/ |
||||
|
contractAmount?: string; |
||||
|
|
||||
|
/** |
||||
|
* 日期范围参数 |
||||
|
*/ |
||||
|
params?: any; |
||||
|
} |
@ -0,0 +1,103 @@ |
|||||
|
import { defHttp } from '@/utils/http/axios'; |
||||
|
import { ID, IDS, commonExport } from '@/api/base'; |
||||
|
import { JyjcontractualTaskBatchVO, JyjcontractualTaskBatchForm, JyjcontractualTaskBatchQuery } from './model'; |
||||
|
|
||||
|
/** |
||||
|
* 查询合同批处理记录列表 |
||||
|
* @param params |
||||
|
* @returns |
||||
|
*/ |
||||
|
export function JyjcontractualTaskBatchList(params?: JyjcontractualTaskBatchQuery) { |
||||
|
return defHttp.get<JyjcontractualTaskBatchVO[]>({ url: '/productManagement/JyjcontractualTaskBatch/list', params }); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 导出合同批处理记录列表 |
||||
|
* @param params |
||||
|
* @returns |
||||
|
*/ |
||||
|
export function JyjcontractualTaskBatchExport(params?: JyjcontractualTaskBatchQuery) { |
||||
|
return commonExport('/productManagement/JyjcontractualTaskBatch/export', params ?? {}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 查询合同批处理记录详细 |
||||
|
* @param id id |
||||
|
* @returns |
||||
|
*/ |
||||
|
export function JyjcontractualTaskBatchInfo(id: ID) { |
||||
|
return defHttp.get<JyjcontractualTaskBatchVO>({ url: '/productManagement/JyjcontractualTaskBatch/' + id }); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 新增合同批处理记录 |
||||
|
* @param data |
||||
|
* @returns |
||||
|
*/ |
||||
|
export function JyjcontractualTaskBatchAdd(data: JyjcontractualTaskBatchForm) { |
||||
|
return defHttp.postWithMsg<void>({ url: '/productManagement/JyjcontractualTaskBatch', data ,timeout:1000 * 60 * 10}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 更新合同批处理记录 |
||||
|
* @param data |
||||
|
* @returns |
||||
|
*/ |
||||
|
export function JyjcontractualTaskBatchUpdate(data: JyjcontractualTaskBatchForm) { |
||||
|
return defHttp.putWithMsg<void>({ url: '/productManagement/JyjcontractualTaskBatch', data }); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 删除合同批处理记录 |
||||
|
* @param id id |
||||
|
* @returns |
||||
|
*/ |
||||
|
export function JyjcontractualTaskBatchRemove(id: ID | IDS) { |
||||
|
return defHttp.deleteWithMsg<void>({ url: '/productManagement/JyjcontractualTaskBatch/' + id },); |
||||
|
} |
||||
|
|
||||
|
import { UploadFileParams } from '#/axios'; |
||||
|
import { AxiosProgressEvent } from 'axios'; |
||||
|
|
||||
|
/** |
||||
|
* @description: Upload interface |
||||
|
*/ |
||||
|
export function uploadContractual( |
||||
|
params: UploadFileParams, |
||||
|
onUploadProgress?: (progressEvent: AxiosProgressEvent) => void, |
||||
|
) { |
||||
|
return defHttp.uploadFile<any>( |
||||
|
{ |
||||
|
// 固定url地址
|
||||
|
url: '/productManagement/JyjcontractualTaskBatch/back/upload', |
||||
|
onUploadProgress, |
||||
|
timeout: 1000 * 60 * 10, |
||||
|
}, |
||||
|
params, |
||||
|
); |
||||
|
} |
||||
|
/** |
||||
|
* 根据id获取合同的审查结果 |
||||
|
* @param id id |
||||
|
* @returns |
||||
|
*/ |
||||
|
export function getContractualResultById(id: ID) { |
||||
|
return defHttp.get({ url: '/productManagement/JyjcontractualTaskBatch/getContractulResultById/' + id }); |
||||
|
} |
||||
|
/** |
||||
|
* 获取PDF文件流 |
||||
|
* @param fileName - PDF文件名 |
||||
|
* @returns Blob 数据 |
||||
|
*/ |
||||
|
export function getPdfFile(id:Number) { |
||||
|
return defHttp.get( |
||||
|
{ |
||||
|
url: `/productManagement/JyjcontractualTaskBatch/getContractulPdf/${id}`, |
||||
|
responseType: 'blob', |
||||
|
headers: { |
||||
|
Accept: 'application/pdf', |
||||
|
} |
||||
|
}, |
||||
|
{ isReturnNativeResponse: true } |
||||
|
); |
||||
|
} |
@ -0,0 +1,160 @@ |
|||||
|
import { BaseEntity, PageQuery } from '@/api/base'; |
||||
|
|
||||
|
export interface JyjcontractualTaskBatchVO { |
||||
|
/** |
||||
|
* 任务名称 |
||||
|
*/ |
||||
|
taskName: string; |
||||
|
|
||||
|
/** |
||||
|
* 任务类型 |
||||
|
*/ |
||||
|
taskType: string; |
||||
|
|
||||
|
/** |
||||
|
* 文档名称 |
||||
|
*/ |
||||
|
documentName: string; |
||||
|
|
||||
|
/** |
||||
|
* OSS文件ID |
||||
|
*/ |
||||
|
ossId: string | number; |
||||
|
|
||||
|
/** |
||||
|
* 进度状态 |
||||
|
*/ |
||||
|
progressStatus: string; |
||||
|
|
||||
|
/** |
||||
|
* 列队任务id |
||||
|
*/ |
||||
|
groupId: string | number; |
||||
|
|
||||
|
/** |
||||
|
* 合同总数 |
||||
|
*/ |
||||
|
totalContracts: number; |
||||
|
|
||||
|
/** |
||||
|
* 已审批总数 |
||||
|
*/ |
||||
|
approvedCount: number; |
||||
|
|
||||
|
/** |
||||
|
* 审核通过数量 |
||||
|
*/ |
||||
|
passCount: number; |
||||
|
|
||||
|
/** |
||||
|
* 审核不通过数量 |
||||
|
*/ |
||||
|
rejectCount: number; |
||||
|
|
||||
|
/** |
||||
|
* 非审查范围数量 |
||||
|
*/ |
||||
|
irrelevantCount: number; |
||||
|
|
||||
|
/** |
||||
|
* 进度(百分比) |
||||
|
*/ |
||||
|
progress: number; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
export interface JyjcontractualTaskBatchForm extends BaseEntity { |
||||
|
/** |
||||
|
* 任务名称 |
||||
|
*/ |
||||
|
taskName?: string; |
||||
|
|
||||
|
/** |
||||
|
* 任务类型 |
||||
|
*/ |
||||
|
taskType?: string; |
||||
|
|
||||
|
/** |
||||
|
* 文档名称 |
||||
|
*/ |
||||
|
documentName?: string; |
||||
|
|
||||
|
/** |
||||
|
* OSS文件ID |
||||
|
*/ |
||||
|
ossId?: string | number; |
||||
|
|
||||
|
/** |
||||
|
* 进度状态 |
||||
|
*/ |
||||
|
progressStatus?: string; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
export interface JyjcontractualTaskBatchQuery extends PageQuery { |
||||
|
|
||||
|
/** |
||||
|
* 任务名称 |
||||
|
*/ |
||||
|
taskName?: string; |
||||
|
|
||||
|
/** |
||||
|
* 任务类型 |
||||
|
*/ |
||||
|
taskType?: string; |
||||
|
|
||||
|
/** |
||||
|
* 文档名称 |
||||
|
*/ |
||||
|
documentName?: string; |
||||
|
|
||||
|
/** |
||||
|
* OSS文件ID |
||||
|
*/ |
||||
|
ossId?: string | number; |
||||
|
|
||||
|
/** |
||||
|
* 进度状态 |
||||
|
*/ |
||||
|
progressStatus?: string; |
||||
|
|
||||
|
/** |
||||
|
* 列队任务id |
||||
|
*/ |
||||
|
groupId?: string | number; |
||||
|
|
||||
|
/** |
||||
|
* 合同总数 |
||||
|
*/ |
||||
|
totalContracts?: number; |
||||
|
|
||||
|
/** |
||||
|
* 已审批总数 |
||||
|
*/ |
||||
|
approvedCount?: number; |
||||
|
|
||||
|
/** |
||||
|
* 审核通过数量 |
||||
|
*/ |
||||
|
passCount?: number; |
||||
|
|
||||
|
/** |
||||
|
* 审核不通过数量 |
||||
|
*/ |
||||
|
rejectCount?: number; |
||||
|
|
||||
|
/** |
||||
|
* 非审查范围数量 |
||||
|
*/ |
||||
|
irrelevantCount?: number; |
||||
|
|
||||
|
/** |
||||
|
* 进度(百分比) |
||||
|
*/ |
||||
|
progress?: number; |
||||
|
|
||||
|
/** |
||||
|
* 日期范围参数 |
||||
|
*/ |
||||
|
params?: any; |
||||
|
} |
@ -0,0 +1,85 @@ |
|||||
|
import { BasicColumn } from '@/components/Table'; |
||||
|
import { FormSchema } from '@/components/Form'; |
||||
|
export const formSchemas: FormSchema[] = [ |
||||
|
{ |
||||
|
label: '合同名称', |
||||
|
field: 'fileName', |
||||
|
component: 'Input', |
||||
|
}, |
||||
|
{ |
||||
|
label: '采购人名称', |
||||
|
field: 'purchaserName', |
||||
|
component: 'Input', |
||||
|
}, |
||||
|
{ |
||||
|
label: '供应商名称或姓名', |
||||
|
field: 'supplierName', |
||||
|
component: 'Input', |
||||
|
}, |
||||
|
{ |
||||
|
label: '合同签订时间', |
||||
|
field: 'signDate', |
||||
|
component: 'Input', |
||||
|
}, |
||||
|
{ |
||||
|
label: '合同金额', |
||||
|
field: 'contractAmount', |
||||
|
component: 'Input', |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
export const columns: BasicColumn[] = [ |
||||
|
{ |
||||
|
title: '合同名称', |
||||
|
dataIndex: 'fileName', |
||||
|
}, |
||||
|
{ |
||||
|
title: '采购人名称', |
||||
|
dataIndex: 'purchaserName', |
||||
|
}, |
||||
|
{ |
||||
|
title: '供应商名称或姓名', |
||||
|
dataIndex: 'supplierName', |
||||
|
}, |
||||
|
{ |
||||
|
title: '合同签订时间', |
||||
|
dataIndex: 'signDate', |
||||
|
}, |
||||
|
{ |
||||
|
title: '合同金额', |
||||
|
dataIndex: 'contractAmount', |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
export const modalSchemas: FormSchema[] = [ |
||||
|
{ |
||||
|
label: '合同名称', |
||||
|
field: 'fileName', |
||||
|
required: true, |
||||
|
component: 'Input', |
||||
|
}, |
||||
|
{ |
||||
|
label: '采购人名称', |
||||
|
field: 'purchaserName', |
||||
|
required: true, |
||||
|
component: 'Input', |
||||
|
}, |
||||
|
{ |
||||
|
label: '供应商名称或姓名', |
||||
|
field: 'supplierName', |
||||
|
required: true, |
||||
|
component: 'Input', |
||||
|
}, |
||||
|
{ |
||||
|
label: '合同签订时间', |
||||
|
field: 'signDate', |
||||
|
required: true, |
||||
|
component: 'Input', |
||||
|
}, |
||||
|
{ |
||||
|
label: '合同金额', |
||||
|
field: 'contractAmount', |
||||
|
required: true, |
||||
|
component: 'Input', |
||||
|
}, |
||||
|
]; |
@ -0,0 +1,68 @@ |
|||||
|
<template> |
||||
|
<BasicModal |
||||
|
v-bind="$attrs" |
||||
|
:title="title" |
||||
|
@register="registerInnerModal" |
||||
|
@ok="handleSubmit" |
||||
|
@cancel="resetForm" |
||||
|
> |
||||
|
<BasicForm @register="registerForm" /> |
||||
|
</BasicModal> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { BasicModal, useModalInner } from '@/components/Modal'; |
||||
|
import { BasicForm, useForm } from '@/components/Form'; |
||||
|
import { computed, ref, unref } from 'vue'; |
||||
|
import { ContractualInfoInfo, ContractualInfoAdd, ContractualInfoUpdate } from '@/api/contractReview/ContractualInfo'; |
||||
|
import { modalSchemas } from './ContractualInfo.data'; |
||||
|
|
||||
|
defineOptions({ name: 'ContractualInfoModal' }); |
||||
|
|
||||
|
const emit = defineEmits(['register', 'reload']); |
||||
|
|
||||
|
const isUpdate = ref<boolean>(false); |
||||
|
const title = computed<string>(() => { |
||||
|
return isUpdate.value ? '编辑合同信息保存' : '新增合同信息保存'; |
||||
|
}); |
||||
|
|
||||
|
const [registerInnerModal, { modalLoading, closeModal }] = useModalInner( |
||||
|
async (data: { record?: Recordable; update: boolean }) => { |
||||
|
modalLoading(true); |
||||
|
const { record, update } = data; |
||||
|
isUpdate.value = update; |
||||
|
if (update && record) { |
||||
|
const ret = await ContractualInfoInfo(record.id); |
||||
|
await setFieldsValue(ret); |
||||
|
} |
||||
|
modalLoading(false); |
||||
|
}, |
||||
|
); |
||||
|
|
||||
|
const [registerForm, { setFieldsValue, resetForm, validate }] = useForm({ |
||||
|
labelWidth: 100, |
||||
|
showActionButtonGroup: false, |
||||
|
baseColProps: { span: 24 }, |
||||
|
schemas: modalSchemas, |
||||
|
}); |
||||
|
|
||||
|
async function handleSubmit() { |
||||
|
try { |
||||
|
modalLoading(true); |
||||
|
const data = await validate(); |
||||
|
if (unref(isUpdate)) { |
||||
|
await ContractualInfoUpdate(data); |
||||
|
} else { |
||||
|
await ContractualInfoAdd(data); |
||||
|
} |
||||
|
emit('reload'); |
||||
|
closeModal(); |
||||
|
await resetForm(); |
||||
|
} catch (e) { |
||||
|
} finally { |
||||
|
modalLoading(false); |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped></style> |
@ -0,0 +1,115 @@ |
|||||
|
<template> |
||||
|
<PageWrapper dense> |
||||
|
<BasicTable @register="registerTable"> |
||||
|
<template #toolbar> |
||||
|
<a-button |
||||
|
@click="downloadExcel(ContractualInfoExport, '合同信息保存数据', getForm().getFieldsValue())" |
||||
|
v-auth="'productManagement:ContractualInfo:export'" |
||||
|
>导出</a-button |
||||
|
> |
||||
|
<a-button |
||||
|
type="primary" |
||||
|
danger |
||||
|
@click="multipleRemove(ContractualInfoRemove)" |
||||
|
:disabled="!selected" |
||||
|
v-auth="'productManagement:ContractualInfo:remove'" |
||||
|
>删除</a-button |
||||
|
> |
||||
|
<a-button |
||||
|
type="primary" |
||||
|
@click="handleAdd" |
||||
|
v-auth="'productManagement:ContractualInfo:add'" |
||||
|
>新增</a-button |
||||
|
> |
||||
|
</template> |
||||
|
<template #bodyCell="{ column, record }"> |
||||
|
<template v-if="column.key === 'action'"> |
||||
|
<TableAction |
||||
|
stopButtonPropagation |
||||
|
:actions="[ |
||||
|
{ |
||||
|
label: '修改', |
||||
|
icon: IconEnum.EDIT, |
||||
|
type: 'primary', |
||||
|
ghost: true, |
||||
|
auth: 'productManagement:ContractualInfo:edit', |
||||
|
onClick: handleEdit.bind(null, record), |
||||
|
}, |
||||
|
{ |
||||
|
label: '删除', |
||||
|
icon: IconEnum.DELETE, |
||||
|
type: 'primary', |
||||
|
danger: true, |
||||
|
ghost: true, |
||||
|
auth: 'productManagement:ContractualInfo:remove', |
||||
|
popConfirm: { |
||||
|
placement: 'left', |
||||
|
title: '是否删除合同信息保存[' + record.id + ']?', |
||||
|
confirm: handleDelete.bind(null, record), |
||||
|
}, |
||||
|
}, |
||||
|
]" |
||||
|
/> |
||||
|
</template> |
||||
|
</template> |
||||
|
</BasicTable> |
||||
|
<ContractualInfoModal @register="registerModal" @reload="reload" /> |
||||
|
</PageWrapper> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { PageWrapper } from '@/components/Page'; |
||||
|
import { BasicTable, useTable, TableAction } from '@/components/Table'; |
||||
|
import { ContractualInfoList, ContractualInfoExport, ContractualInfoRemove } from '@/api/contractReview/ContractualInfo'; |
||||
|
import { downloadExcel } from '@/utils/file/download'; |
||||
|
import { useModal } from '@/components/Modal'; |
||||
|
import ContractualInfoModal from './ContractualInfoModal.vue'; |
||||
|
import { formSchemas, columns } from './ContractualInfo.data'; |
||||
|
import { IconEnum } from '@/enums/appEnum'; |
||||
|
|
||||
|
defineOptions({ name: 'ContractualInfo' }); |
||||
|
|
||||
|
const [registerTable, { reload, multipleRemove, selected, getForm }] = useTable({ |
||||
|
rowSelection: { |
||||
|
type: 'checkbox', |
||||
|
}, |
||||
|
title: '合同信息保存列表', |
||||
|
api: ContractualInfoList, |
||||
|
showIndexColumn: false, |
||||
|
rowKey: 'id', |
||||
|
useSearchForm: true, |
||||
|
formConfig: { |
||||
|
schemas: formSchemas, |
||||
|
baseColProps: { |
||||
|
xs: 24, |
||||
|
sm: 24, |
||||
|
md: 24, |
||||
|
lg: 6, |
||||
|
}, |
||||
|
}, |
||||
|
columns: columns, |
||||
|
actionColumn: { |
||||
|
width: 200, |
||||
|
title: '操作', |
||||
|
key: 'action', |
||||
|
fixed: 'right', |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
const [registerModal, { openModal }] = useModal(); |
||||
|
|
||||
|
function handleEdit(record: Recordable) { |
||||
|
openModal(true, { record, update: true }); |
||||
|
} |
||||
|
|
||||
|
function handleAdd() { |
||||
|
openModal(true, { update: false }); |
||||
|
} |
||||
|
|
||||
|
async function handleDelete(record: Recordable) { |
||||
|
await ContractualInfoRemove([record.id]); |
||||
|
await reload(); |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped></style> |
@ -0,0 +1,264 @@ |
|||||
|
<template> |
||||
|
<BasicModal |
||||
|
v-bind="$attrs" |
||||
|
title="title" |
||||
|
:canFullscreen="true" |
||||
|
:defaultFullscreen="true" |
||||
|
:showOkBtn="false" |
||||
|
@register="registerInnerModal" |
||||
|
> |
||||
|
<div class="grid grid-cols-5 gap-4"> |
||||
|
<div class="col-span-3"> |
||||
|
<!-- <CanvasEditor |
||||
|
ref="canvasEditor" |
||||
|
:parentContent="parentContent" |
||||
|
:view="view" |
||||
|
@save-content="handleSaveCanvasEditorContent" |
||||
|
/> --> |
||||
|
<PdfViewer :id="currentId" :key="pdfViewerkey" v-if="currentId!=0"/> |
||||
|
</div> |
||||
|
<div class="col-span-2"> |
||||
|
<!-- 添加 col-span-2 和高度样式 --> |
||||
|
<div class="tabs-container"> |
||||
|
<Tabs v-model:activeKey="activeKey" type="card"> |
||||
|
<TabPane key="1" tab="审查结果"> |
||||
|
<div class="scroll-container"> |
||||
|
<div class="card-container"> |
||||
|
<Card |
||||
|
v-for="(item, index) in cardList" |
||||
|
:key="index" |
||||
|
:class="['custom-card', { 'card-selected': selectedCard === item.title }]" |
||||
|
@click="handleCardClick(item.title)" |
||||
|
> |
||||
|
<template #title>{{ item.title }}</template> |
||||
|
{{ item.text }} |
||||
|
{{ item.content }} |
||||
|
</Card> |
||||
|
</div> |
||||
|
</div> |
||||
|
</TabPane> |
||||
|
<!-- <TabPane key="2" tab="Tab 2">Content of Tab Pane 2</TabPane> |
||||
|
<TabPane key="3" tab="Tab 3">Content of Tab Pane 3</TabPane> --> |
||||
|
</Tabs> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</BasicModal> |
||||
|
</template> |
||||
|
<script lang="ts" setup> |
||||
|
import { ref, onMounted, reactive } from 'vue'; |
||||
|
import { BasicModal, useModalInner } from '@/components/Modal'; |
||||
|
|
||||
|
import { Tabs, TabPane, Card } from 'ant-design-vue'; |
||||
|
import { useRouter } from 'vue-router'; |
||||
|
import CanvasEditor from '@/views/CanvasEditor/index.vue'; |
||||
|
import { getContractualResultById } from '@/api/contractReview/JyjcontractualTaskBatch'; |
||||
|
import PdfViewer from "./PdfViewer.vue" |
||||
|
const activeKey = ref('1'); |
||||
|
const currentId = ref<any>(0); |
||||
|
const pdfViewerkey = ref(0); |
||||
|
// 卡片数据 |
||||
|
const cardList = ref<any>([]); |
||||
|
const selectedCard = ref(''); // 用于存储当前选中的卡片标题 |
||||
|
const handleCardClick = (title) => { |
||||
|
selectedCard.value = title; |
||||
|
console.log('点击的卡片标题:', title); |
||||
|
}; |
||||
|
|
||||
|
const [registerInnerModal, { modalLoading, closeModal }] = useModalInner( |
||||
|
async (data: { record?: Recordable }) => { |
||||
|
modalLoading(true); |
||||
|
cardList.value=[] |
||||
|
const { record } = data; |
||||
|
const res = await getContractualResultById(record.id); |
||||
|
pdfViewerkey.value+=1 |
||||
|
currentId.value=record.id |
||||
|
for (const item of res.results) { |
||||
|
for (const content of item.contentList) { |
||||
|
cardList.value.push({ |
||||
|
title: content.problemTitle, |
||||
|
text: content.text, |
||||
|
content: content.problemDesc, |
||||
|
isPosition: content.isPosition, |
||||
|
accord: item.accord, |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
modalLoading(false); |
||||
|
}, |
||||
|
); |
||||
|
|
||||
|
// 存放父组件传递的数据 |
||||
|
let parentContent = reactive<any>(undefined); |
||||
|
// 存放子组件数据 |
||||
|
const content = ref<any>(undefined); |
||||
|
// 标识符 |
||||
|
const view = ref<string | undefined>(undefined); |
||||
|
|
||||
|
// 初始化数据 |
||||
|
onMounted(() => { |
||||
|
console.log('模拟父组件向后端请求数据, 传递给子组件'); |
||||
|
getEditorContent(); |
||||
|
view.value = 'parent'; |
||||
|
}); |
||||
|
|
||||
|
// 模拟后端获取数据的方法 |
||||
|
const getEditorContent = () => { |
||||
|
parentContent = { |
||||
|
header: [ |
||||
|
{ |
||||
|
value: '', |
||||
|
size: 12, |
||||
|
bold: false, |
||||
|
color: 'rgb(33, 53, 71)', |
||||
|
italic: false, |
||||
|
}, |
||||
|
], |
||||
|
main: [ |
||||
|
{ |
||||
|
value: |
||||
|
'父类传递的数据 通过后端获取!\n甲方:企查查科技股份有限公司\n法定代表人:陈德强\n住所:苏州工业园区科创东区东石泾港路2号润港产业园6号楼10层1001室11', |
||||
|
size: 10, |
||||
|
bold: false, |
||||
|
}, |
||||
|
], |
||||
|
}; |
||||
|
}; |
||||
|
|
||||
|
// 组件引用 |
||||
|
const canvasEditor = ref<InstanceType<typeof CanvasEditor> | null>(null); |
||||
|
|
||||
|
// 保存内容方法 |
||||
|
const handleSaveContent = () => { |
||||
|
// 访问子组件的方法 |
||||
|
(canvasEditor.value as any).saveContent(); |
||||
|
}; |
||||
|
|
||||
|
// 处理子组件传递的数据 |
||||
|
const handleSaveCanvasEditorContent = (data: any) => { |
||||
|
console.log('从子组件接收到的数据:', data); |
||||
|
// 将data数据转换为 json 格式的数据, 方便入库处理 |
||||
|
content.value = JSON.stringify(data); |
||||
|
console.log('转换后的数据 content 为: ', content.value); |
||||
|
}; |
||||
|
|
||||
|
const router = useRouter(); |
||||
|
// 状态定义 |
||||
|
const loading = ref(false); |
||||
|
const handleMenuClick = ({ key }) => { |
||||
|
console.log(key); |
||||
|
router.push({ path: key }); |
||||
|
}; |
||||
|
// 获取任务列表 |
||||
|
const fetchTaskList = async () => {}; |
||||
|
|
||||
|
// 页面加载时获取数据 |
||||
|
onMounted(() => { |
||||
|
fetchTaskList(); |
||||
|
}); |
||||
|
setTimeout(() => { |
||||
|
loading.value = false; |
||||
|
}, 1500); |
||||
|
</script> |
||||
|
<style scoped> |
||||
|
/* Tabs 相关样式 */ |
||||
|
/* 设置未选中标签的基本样式 */ |
||||
|
:deep(.ant-tabs-card > .ant-tabs-nav .ant-tabs-tab) { |
||||
|
color: rgba(0, 0, 0, 0.85) !important; /* 文字颜色为黑色,带透明度 */ |
||||
|
background: #fff; /* 背景色为白色 */ |
||||
|
border: 1px solid #f0f0f0; /* 浅灰色边框 */ |
||||
|
} |
||||
|
|
||||
|
/* 设置选中标签的样式 */ |
||||
|
:deep(.ant-tabs-card > .ant-tabs-nav .ant-tabs-tab-active) { |
||||
|
color: #ffffff !important; /* 文字颜色为白色 */ |
||||
|
background: #1890ff !important; /* 背景色为蓝色 */ |
||||
|
border-color: #1890ff !important; /* 边框颜色也改为蓝色 */ |
||||
|
} |
||||
|
|
||||
|
/* 确保选中标签的文字颜色为白色 */ |
||||
|
:deep(.ant-tabs-card > .ant-tabs-nav .ant-tabs-tab-active .ant-tabs-tab-btn) { |
||||
|
color: #ffffff !important; /* 文字颜色强制设为白色 */ |
||||
|
} |
||||
|
|
||||
|
/* 鼠标悬停时的文字颜色效果 */ |
||||
|
:deep(.ant-tabs-card > .ant-tabs-nav .ant-tabs-tab:hover .ant-tabs-tab-btn) { |
||||
|
color: #1890ff !important; /* 悬停时文字变为蓝色 */ |
||||
|
} |
||||
|
|
||||
|
/* Card 相关样式 */ |
||||
|
/* 卡片容器布局设置 */ |
||||
|
.card-container { |
||||
|
display: flex; |
||||
|
gap: 16px; |
||||
|
flex-wrap: wrap; |
||||
|
width: 100%; |
||||
|
} |
||||
|
|
||||
|
/* 单个卡片的基本样式 */ |
||||
|
.custom-card { |
||||
|
width: 100%; |
||||
|
margin-bottom: 16px; |
||||
|
cursor: pointer; |
||||
|
transition: all 0.3s; |
||||
|
background-color: #fff; /* 添加默认背景色 */ |
||||
|
border: 1px solid #e8e8e8; /* 添加默认边框 */ |
||||
|
} |
||||
|
|
||||
|
/* 卡片选中状态 */ |
||||
|
.custom-card.card-selected { |
||||
|
background-color: #e6f4ff !important; /* 选中时的淡蓝色背景 */ |
||||
|
border: 1px solid #1890ff !important; /* 选中时的蓝色边框 */ |
||||
|
} |
||||
|
|
||||
|
/* 卡片悬停效果 */ |
||||
|
.custom-card:hover { |
||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); |
||||
|
transform: translateY(-2px); |
||||
|
} |
||||
|
|
||||
|
/* 选中状态下的悬停效果 */ |
||||
|
.custom-card.card-selected:hover { |
||||
|
background-color: #e6f4ff !important; |
||||
|
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.1); |
||||
|
} |
||||
|
|
||||
|
/* 卡片点击效果 */ |
||||
|
.custom-card:active { |
||||
|
transform: translateY(0); |
||||
|
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); |
||||
|
} |
||||
|
|
||||
|
/* 修改卡片内容区域的内边距 */ |
||||
|
:deep(.ant-card-body) { |
||||
|
padding: 16px; |
||||
|
} |
||||
|
|
||||
|
/* 滚动容器样式 */ |
||||
|
.scroll-container { |
||||
|
height: calc(100vh - 25vh); /* 可以根据实际需要调整高度 */ |
||||
|
overflow-y: auto; /* 添加垂直滚动条 */ |
||||
|
padding: 16px; |
||||
|
} |
||||
|
|
||||
|
/* 美化滚动条样式(可选) */ |
||||
|
.scroll-container::-webkit-scrollbar { |
||||
|
width: 6px; /* 滚动条宽度 */ |
||||
|
} |
||||
|
|
||||
|
.scroll-container::-webkit-scrollbar-thumb { |
||||
|
background-color: #ccc; /* 滚动条颜色 */ |
||||
|
border-radius: 3px; /* 滚动条圆角 */ |
||||
|
} |
||||
|
|
||||
|
.scroll-container::-webkit-scrollbar-track { |
||||
|
background-color: #f1f1f1; /* 滚动条轨道颜色 */ |
||||
|
} |
||||
|
|
||||
|
/* 保持原有的卡片容器样式 */ |
||||
|
.card-container { |
||||
|
display: flex; |
||||
|
gap: 16px; |
||||
|
flex-wrap: wrap; |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,208 @@ |
|||||
|
<template> |
||||
|
<PageWrapper dense> |
||||
|
<BasicTable @register="registerTable"> |
||||
|
<template #toolbar v-if="props.showAdd"> |
||||
|
<a-button |
||||
|
type="primary" |
||||
|
@click="handleAdd" |
||||
|
v-auth="'productManagement:ContractualTasks:add'" |
||||
|
>新增</a-button |
||||
|
> |
||||
|
</template> |
||||
|
<template #bodyCell="{ column, record }"> |
||||
|
<template v-if="column.key === 'action'"> |
||||
|
<TableAction |
||||
|
stopButtonPropagation |
||||
|
:actions="[ |
||||
|
{ |
||||
|
label: '详情', |
||||
|
icon: IconEnum.EDIT, |
||||
|
type: 'primary', |
||||
|
ghost: true, |
||||
|
ifShow: () => { |
||||
|
if ( |
||||
|
record.progressStatus != 'PENDING' && |
||||
|
record.progressStatus != 'STARTED' && |
||||
|
record.progressStatus != 'REVOKED' |
||||
|
) { |
||||
|
return true; |
||||
|
} else { |
||||
|
return false; |
||||
|
} |
||||
|
}, |
||||
|
onClick: handleDetail.bind(null, record), |
||||
|
}, |
||||
|
// { |
||||
|
// label: '下载', |
||||
|
// icon: IconEnum.DOWNLOAD, |
||||
|
// type: 'primary', |
||||
|
// color: 'success', |
||||
|
// ghost: true, |
||||
|
// ifShow: () => { |
||||
|
// if ( |
||||
|
// record.progressStatus != 'PENDING' && |
||||
|
// record.progressStatus != 'STARTED' && |
||||
|
// record.progressStatus != 'REVOKED' |
||||
|
// ) { |
||||
|
// return true; |
||||
|
// } else { |
||||
|
// return false; |
||||
|
// } |
||||
|
// }, |
||||
|
// onClick: handleDownload.bind(null, record), |
||||
|
// }, |
||||
|
// { |
||||
|
// label: '下载', |
||||
|
// icon: IconEnum.DOWNLOAD, |
||||
|
// type: 'primary', |
||||
|
// color: 'success', |
||||
|
// ghost: true, |
||||
|
// ifShow: () => { |
||||
|
// if ( |
||||
|
// record.progressStatus != 'PENDING' && |
||||
|
// record.progressStatus != 'STARTED' && |
||||
|
// record.progressStatus != 'REVOKED' |
||||
|
// ) { |
||||
|
// return true; |
||||
|
// } else { |
||||
|
// return false; |
||||
|
// } |
||||
|
// }, |
||||
|
// onClick: handleDownload.bind(null, record), |
||||
|
// }, |
||||
|
{ |
||||
|
label: '终止任务', |
||||
|
icon: IconEnum.DELETE, |
||||
|
type: 'primary', |
||||
|
danger: true, |
||||
|
ghost: true, |
||||
|
ifShow: () => { |
||||
|
if (record.progressStatus == 'PENDING') { |
||||
|
return true; |
||||
|
} else { |
||||
|
return false; |
||||
|
} |
||||
|
}, |
||||
|
popConfirm: { |
||||
|
placement: 'left', |
||||
|
title: '是否终止当前任务?', |
||||
|
confirm: handleStop.bind(null, record), |
||||
|
}, |
||||
|
}, |
||||
|
]" |
||||
|
/> |
||||
|
</template> |
||||
|
</template> |
||||
|
</BasicTable> |
||||
|
<ContractualTasksModal @register="registerModal" @reload="reload" /> |
||||
|
<ContractualShowModal @register="registerShowModal" /> |
||||
|
<DocsDrawer @register="registerDrawer" /> |
||||
|
|
||||
|
</PageWrapper> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { PageWrapper } from '@/components/Page'; |
||||
|
import { BasicTable, useTable, TableAction } from '@/components/Table'; |
||||
|
|
||||
|
import { useModal } from '@/components/Modal'; |
||||
|
import ContractualTasksModal from './ContractualTasksModal.vue'; |
||||
|
import DocsDrawer from '@/views/documentReview/DocumentTasks/DocsDrawer.vue'; |
||||
|
|
||||
|
import { formSchemas, columns } from './ContractualTasks.data'; |
||||
|
import { IconEnum } from '@/enums/appEnum'; |
||||
|
import ContractualShowModal from '@/views/contractReview/ContractualTasks/ContractualShowModal.vue'; |
||||
|
import { DocumentTasksStop } from '@/api/documentReview/DocumentTasks'; |
||||
|
import { ContractualTasksList } from '@/api/contractReview/ContractualTasks'; |
||||
|
import { |
||||
|
DocumentTaskResultsInfoByTaskId, |
||||
|
DocumentTaskResultDownload, |
||||
|
} from '@/api/documentReview/DocumentTaskResults'; |
||||
|
import { onMounted } from 'vue'; |
||||
|
import { useDrawer } from '@/components/Drawer'; |
||||
|
|
||||
|
// 组件初始化时判断 batchName 是否存在 |
||||
|
onMounted(() => { |
||||
|
console.log('onMountedonMountedonMounted'); |
||||
|
const { setFieldsValue, updateSchema } = getForm(); |
||||
|
if (props.batchName) { |
||||
|
setFieldsValue({ batchName: props.batchName }); |
||||
|
updateSchema({ field: 'batchName', dynamicDisabled: true }); |
||||
|
} |
||||
|
if (props.resultType) { |
||||
|
if (props.resultType == '审查失败文件') { |
||||
|
setFieldsValue({ progressStatus: 'FAILURE', groupId: props.groupId }); |
||||
|
updateSchema([ |
||||
|
{ field: 'progressStatus', dynamicDisabled: true }, |
||||
|
{ field: 'resultType', dynamicDisabled: true }, |
||||
|
]); |
||||
|
} else { |
||||
|
setFieldsValue({ resultType: props.resultType, groupId: props.groupId }); |
||||
|
updateSchema({ field: 'resultType', dynamicDisabled: true }); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
const [registerShowModal, { openModal: openShowModal }] = useModal(); |
||||
|
const [registerDrawer, { openDrawer }] = useDrawer(); |
||||
|
|
||||
|
defineOptions({ name: 'ContractualTasks' }); |
||||
|
let props = defineProps(['showAdd', 'groupId', 'batchName', 'resultType']); |
||||
|
|
||||
|
const [registerTable, { reload, multipleRemove, selected, getForm }] = useTable({ |
||||
|
rowSelection: { |
||||
|
type: 'checkbox', |
||||
|
}, |
||||
|
title: '合同任务列表', |
||||
|
api: ContractualTasksList, |
||||
|
showIndexColumn: false, |
||||
|
rowKey: 'id', |
||||
|
useSearchForm: true, |
||||
|
formConfig: { |
||||
|
schemas: formSchemas, |
||||
|
baseColProps: { |
||||
|
xs: 24, |
||||
|
sm: 24, |
||||
|
md: 24, |
||||
|
lg: 6, |
||||
|
}, |
||||
|
}, |
||||
|
columns: columns, |
||||
|
actionColumn: { |
||||
|
width: 200, |
||||
|
title: '操作', |
||||
|
key: 'action', |
||||
|
fixed: 'right', |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
const [registerModal, { openModal }] = useModal(); |
||||
|
|
||||
|
async function handleDetail(record: Recordable) { |
||||
|
if(record.progressStatus=="FAILURE"){ |
||||
|
let res = await DocumentTaskResultsInfoByTaskId(record.id); |
||||
|
openDrawer(true, { value: res.result, type: 'markdown' }); |
||||
|
}else{ |
||||
|
openShowModal(true, {record }); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
//根据record.id查询结果详情 |
||||
|
} |
||||
|
|
||||
|
async function handleStop(record: Recordable) { |
||||
|
await DocumentTasksStop(record.id); |
||||
|
await reload(); |
||||
|
} |
||||
|
|
||||
|
function handleAdd() { |
||||
|
openModal(true, { update: false }); |
||||
|
} |
||||
|
|
||||
|
async function handleDownload(record: Recordable) { |
||||
|
await DocumentTaskResultDownload([record.id]); |
||||
|
await reload(); |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped></style> |
@ -0,0 +1,127 @@ |
|||||
|
<template> |
||||
|
<div class="pdf-container"> |
||||
|
<vue-office-docx |
||||
|
:src="pdfUrl" |
||||
|
/> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { ref, onMounted, nextTick } from 'vue'; |
||||
|
//引入VueOfficeDocx组件 |
||||
|
import VueOfficeDocx from '@vue-office/pdf' |
||||
|
//引入相关样式 |
||||
|
import { message } from 'ant-design-vue'; |
||||
|
import { MinusOutlined, PlusOutlined } from '@ant-design/icons-vue'; |
||||
|
import { getPdfFile } from '@/api/contractReview/JyjcontractualTaskBatch'; |
||||
|
|
||||
|
// Props 定义 |
||||
|
interface Props { |
||||
|
id: string; |
||||
|
} |
||||
|
const props = defineProps<Props>(); |
||||
|
|
||||
|
const pdfUrl = ref<string>(''); |
||||
|
const currentPage = ref(1); |
||||
|
const pageCount = ref(0); |
||||
|
const documentLoaded = ref(false); |
||||
|
const scale = ref(1.5); // 初始缩放比例 |
||||
|
|
||||
|
|
||||
|
// 适应宽度 |
||||
|
const fitToWidth = () => { |
||||
|
const pdfContainer = document.querySelector('.pdf-wrapper'); |
||||
|
if (pdfContainer) { |
||||
|
const containerWidth = pdfContainer.clientWidth; |
||||
|
const pdfCanvas = document.querySelector('.vue3-pdf canvas') as HTMLCanvasElement; |
||||
|
if (pdfCanvas) { |
||||
|
const originalWidth = pdfCanvas.width / scale.value; |
||||
|
scale.value = +(containerWidth / originalWidth * 0.95).toFixed(1); // 95% 的容器宽度 |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
// 加载 PDF |
||||
|
const loadPdf = async () => { |
||||
|
try { |
||||
|
if(props.id==0){ |
||||
|
pdfUrl.value=''; |
||||
|
return; |
||||
|
} |
||||
|
console.log('PDF加载成功1:', pdfUrl.value); |
||||
|
|
||||
|
const response = await getPdfFile(props.id); |
||||
|
if (response?.data) { |
||||
|
console.log('PDF加载成功2:', pdfUrl.value); |
||||
|
|
||||
|
const blob = new Blob([response.data], { type: 'application/pdf' }); |
||||
|
pdfUrl.value = URL.createObjectURL(blob); |
||||
|
console.log('PDF加载成功3:', pdfUrl.value); |
||||
|
// PDF 加载完成后自动适应宽度 |
||||
|
nextTick(() => { |
||||
|
setTimeout(fitToWidth, 500); |
||||
|
}); |
||||
|
} |
||||
|
} catch (error) { |
||||
|
console.error('PDF加载失败:', error); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const handleError = (error: Error) => { |
||||
|
message.error('PDF显示出错:' + error.message); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
onMounted(() => { |
||||
|
loadPdf(); |
||||
|
}); |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.pdf-container { |
||||
|
width: 100%; |
||||
|
height: 100vh; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
background: #f0f2f5; |
||||
|
} |
||||
|
|
||||
|
.pdf-wrapper { |
||||
|
flex: 1; |
||||
|
overflow: auto; |
||||
|
padding: 20px; |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
background: #f0f2f5; |
||||
|
} |
||||
|
|
||||
|
.loading { |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
height: 100%; |
||||
|
font-size: 16px; |
||||
|
color: #666; |
||||
|
} |
||||
|
|
||||
|
.pdf-controls { |
||||
|
padding: 16px; |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
background: #fff; |
||||
|
border-top: 1px solid #f0f0f0; |
||||
|
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.05); |
||||
|
} |
||||
|
|
||||
|
:deep(.vue3-pdf) { |
||||
|
background: white; |
||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); |
||||
|
padding: 20px; |
||||
|
} |
||||
|
|
||||
|
:deep(.vue3-pdf canvas) { |
||||
|
max-width: 100%; |
||||
|
height: auto !important; |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,149 @@ |
|||||
|
<template> |
||||
|
<!-- 添加 col-span-2 和高度样式 --> |
||||
|
<div class="tabs-container"> |
||||
|
<Tabs v-model:activeKey="activeKey" type="card"> |
||||
|
<TabPane key="1" tab="审查结果"> |
||||
|
<div class="scroll-container"> |
||||
|
<div class="card-container"> |
||||
|
<Card |
||||
|
v-for="(item, index) in props.cardList" |
||||
|
:key="index" |
||||
|
:class="['custom-card', { 'card-selected': selectedCard === item.title }]" |
||||
|
@click="handleCardClick(item.title)" |
||||
|
> |
||||
|
<template #title>{{ item.title }}</template> |
||||
|
{{ item.text }} |
||||
|
{{ item.content }} |
||||
|
</Card> |
||||
|
</div> |
||||
|
</div> |
||||
|
</TabPane> |
||||
|
<!-- <TabPane key="2" tab="Tab 2">Content of Tab Pane 2</TabPane> |
||||
|
<TabPane key="3" tab="Tab 3">Content of Tab Pane 3</TabPane> --> |
||||
|
</Tabs> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script lang="ts" setup> |
||||
|
import { ref, onMounted, reactive } from 'vue'; |
||||
|
|
||||
|
import { Tabs, TabPane, Card } from 'ant-design-vue'; |
||||
|
// Props 定义 |
||||
|
interface Props { |
||||
|
cardList:any[]; |
||||
|
} |
||||
|
const props = defineProps<Props>(); |
||||
|
const activeKey = ref('1'); |
||||
|
// 卡片数据 |
||||
|
const selectedCard = ref(''); // 用于存储当前选中的卡片标题 |
||||
|
const handleCardClick = (title) => { |
||||
|
selectedCard.value = title; |
||||
|
console.log('点击的卡片标题:', title); |
||||
|
}; |
||||
|
|
||||
|
// 初始化数据 |
||||
|
onMounted(() => { |
||||
|
|
||||
|
}); |
||||
|
</script> |
||||
|
<style scoped> |
||||
|
/* Tabs 相关样式 */ |
||||
|
/* 设置未选中标签的基本样式 */ |
||||
|
:deep(.ant-tabs-card > .ant-tabs-nav .ant-tabs-tab) { |
||||
|
color: rgba(0, 0, 0, 0.85) !important; /* 文字颜色为黑色,带透明度 */ |
||||
|
background: #fff; /* 背景色为白色 */ |
||||
|
border: 1px solid #f0f0f0; /* 浅灰色边框 */ |
||||
|
} |
||||
|
|
||||
|
/* 设置选中标签的样式 */ |
||||
|
:deep(.ant-tabs-card > .ant-tabs-nav .ant-tabs-tab-active) { |
||||
|
color: #ffffff !important; /* 文字颜色为白色 */ |
||||
|
background: #1890ff !important; /* 背景色为蓝色 */ |
||||
|
border-color: #1890ff !important; /* 边框颜色也改为蓝色 */ |
||||
|
} |
||||
|
|
||||
|
/* 确保选中标签的文字颜色为白色 */ |
||||
|
:deep(.ant-tabs-card > .ant-tabs-nav .ant-tabs-tab-active .ant-tabs-tab-btn) { |
||||
|
color: #ffffff !important; /* 文字颜色强制设为白色 */ |
||||
|
} |
||||
|
|
||||
|
/* 鼠标悬停时的文字颜色效果 */ |
||||
|
:deep(.ant-tabs-card > .ant-tabs-nav .ant-tabs-tab:hover .ant-tabs-tab-btn) { |
||||
|
color: #1890ff !important; /* 悬停时文字变为蓝色 */ |
||||
|
} |
||||
|
|
||||
|
/* Card 相关样式 */ |
||||
|
/* 卡片容器布局设置 */ |
||||
|
.card-container { |
||||
|
display: flex; |
||||
|
gap: 16px; |
||||
|
flex-wrap: wrap; |
||||
|
width: 100%; |
||||
|
} |
||||
|
|
||||
|
/* 单个卡片的基本样式 */ |
||||
|
.custom-card { |
||||
|
width: 100%; |
||||
|
margin-bottom: 16px; |
||||
|
cursor: pointer; |
||||
|
transition: all 0.3s; |
||||
|
background-color: #fff; /* 添加默认背景色 */ |
||||
|
border: 1px solid #e8e8e8; /* 添加默认边框 */ |
||||
|
} |
||||
|
|
||||
|
/* 卡片选中状态 */ |
||||
|
.custom-card.card-selected { |
||||
|
background-color: #e6f4ff !important; /* 选中时的淡蓝色背景 */ |
||||
|
border: 1px solid #1890ff !important; /* 选中时的蓝色边框 */ |
||||
|
} |
||||
|
|
||||
|
/* 卡片悬停效果 */ |
||||
|
.custom-card:hover { |
||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); |
||||
|
transform: translateY(-2px); |
||||
|
} |
||||
|
|
||||
|
/* 选中状态下的悬停效果 */ |
||||
|
.custom-card.card-selected:hover { |
||||
|
background-color: #e6f4ff !important; |
||||
|
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.1); |
||||
|
} |
||||
|
|
||||
|
/* 卡片点击效果 */ |
||||
|
.custom-card:active { |
||||
|
transform: translateY(0); |
||||
|
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); |
||||
|
} |
||||
|
|
||||
|
/* 修改卡片内容区域的内边距 */ |
||||
|
:deep(.ant-card-body) { |
||||
|
padding: 16px; |
||||
|
} |
||||
|
|
||||
|
/* 滚动容器样式 */ |
||||
|
.scroll-container { |
||||
|
height: calc(100vh - 25vh); /* 可以根据实际需要调整高度 */ |
||||
|
overflow-y: auto; /* 添加垂直滚动条 */ |
||||
|
padding: 16px; |
||||
|
} |
||||
|
|
||||
|
/* 美化滚动条样式(可选) */ |
||||
|
.scroll-container::-webkit-scrollbar { |
||||
|
width: 6px; /* 滚动条宽度 */ |
||||
|
} |
||||
|
|
||||
|
.scroll-container::-webkit-scrollbar-thumb { |
||||
|
background-color: #ccc; /* 滚动条颜色 */ |
||||
|
border-radius: 3px; /* 滚动条圆角 */ |
||||
|
} |
||||
|
|
||||
|
.scroll-container::-webkit-scrollbar-track { |
||||
|
background-color: #f1f1f1; /* 滚动条轨道颜色 */ |
||||
|
} |
||||
|
|
||||
|
/* 保持原有的卡片容器样式 */ |
||||
|
.card-container { |
||||
|
display: flex; |
||||
|
gap: 16px; |
||||
|
flex-wrap: wrap; |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,71 @@ |
|||||
|
<template> |
||||
|
<BasicModal |
||||
|
v-bind="$attrs" |
||||
|
:title="title" |
||||
|
:canFullscreen="true" |
||||
|
:defaultFullscreen="true" |
||||
|
:showOkBtn="false" |
||||
|
@register="registerInnerModal" |
||||
|
> |
||||
|
<ContractualTasksTable |
||||
|
:showAdd="false" |
||||
|
:groupId="groupId" |
||||
|
:batchName="batchName" |
||||
|
:resultType="resultType" |
||||
|
:key="randomKey" |
||||
|
/> |
||||
|
</BasicModal> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { BasicModal, useModalInner } from '@/components/Modal'; |
||||
|
import { BasicForm, useForm } from '@/components/Form'; |
||||
|
import { computed, ref, unref } from 'vue'; |
||||
|
import { |
||||
|
JyjcontractualTaskBatchInfo, |
||||
|
JyjcontractualTaskBatchAdd, |
||||
|
JyjcontractualTaskBatchUpdate, |
||||
|
} from '@/api/contractReview/JyjcontractualTaskBatch'; |
||||
|
import { modalSchemas } from './JyjcontractualTaskBatch.data'; |
||||
|
import ContractualTasksTable from '@/views/contractReview/ContractualTasks/ContractualTasksTable.vue'; |
||||
|
defineOptions({ name: 'ContractualTasksTableModal' }); |
||||
|
// 定义随机 key 的生成函数 |
||||
|
const randomKey = ref('1'); |
||||
|
|
||||
|
const emit = defineEmits(['register', 'reload']); |
||||
|
const title = ref(''); |
||||
|
const resultType = ref(''); |
||||
|
const batchName = ref(''); |
||||
|
const groupId = ref(''); |
||||
|
const isUpdate = ref<boolean>(false); |
||||
|
|
||||
|
const [registerInnerModal, { modalLoading, closeModal }] = useModalInner( |
||||
|
async (data: { record?: Recordable; type?: string }) => { |
||||
|
modalLoading(true); |
||||
|
const { record, type } = data; |
||||
|
if (type == 'passCount') { |
||||
|
title.value = '查看审核通过记录'; |
||||
|
resultType.value = '审查合格'; |
||||
|
} else if (type == 'rejectCount') { |
||||
|
title.value = '查看审核不通过记录'; |
||||
|
resultType.value = '审查不合格'; |
||||
|
} else if(type=="irrelevantCount"){ |
||||
|
title.value = '查看非审查范围记录'; |
||||
|
resultType.value = '非审查范围文件'; |
||||
|
}else{ |
||||
|
title.value = '查看审查失败的范围记录'; |
||||
|
resultType.value = '审查失败文件'; |
||||
|
} |
||||
|
batchName.value = record.batchName; |
||||
|
groupId.value = record.id; |
||||
|
console.log(batchName.value, groupId.value); |
||||
|
const generateRandomKey = () => Math.random().toString(36).substr(2, 9); |
||||
|
|
||||
|
// 定义响应式变量 |
||||
|
randomKey.value = generateRandomKey(); // 初始化随机 key |
||||
|
modalLoading(false); |
||||
|
}, |
||||
|
); |
||||
|
</script> |
||||
|
|
||||
|
<style scoped></style> |
@ -0,0 +1,109 @@ |
|||||
|
import { BasicColumn } from '@/components/Table'; |
||||
|
import { FormSchema } from '@/components/Form'; |
||||
|
import { getDictOptions } from '@/utils/dict'; |
||||
|
import { useRender } from '@/hooks/component/useRender'; |
||||
|
import { uploadContractual } from '@/api/contractReview/JyjcontractualTaskBatch'; |
||||
|
|
||||
|
export const formSchemas: FormSchema[] = [ |
||||
|
{ |
||||
|
label: '文档名称', |
||||
|
field: 'documentName', |
||||
|
component: 'Input', |
||||
|
}, |
||||
|
{ |
||||
|
label: '批次名称', |
||||
|
field: 'batchName', |
||||
|
component: 'Input', |
||||
|
}, |
||||
|
{ |
||||
|
label: '进度状态', |
||||
|
field: 'progressStatus', |
||||
|
component: 'Select', |
||||
|
componentProps: { |
||||
|
options: getDictOptions('document_task_status'), |
||||
|
}, |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
const { renderDict } = useRender(); |
||||
|
export const columns: BasicColumn[] = [ |
||||
|
{ |
||||
|
title: '文件名称', |
||||
|
dataIndex: 'documentName', |
||||
|
}, |
||||
|
{ |
||||
|
title: '批次名称', |
||||
|
dataIndex: 'batchName', |
||||
|
}, |
||||
|
{ |
||||
|
title: '合同总数', |
||||
|
dataIndex: 'totalContracts', |
||||
|
}, |
||||
|
{ |
||||
|
title: '已审批总数', |
||||
|
dataIndex: 'approvedCount', |
||||
|
|
||||
|
}, |
||||
|
{ |
||||
|
title: '审核通过数量', |
||||
|
dataIndex: 'passCount', |
||||
|
width: 120, |
||||
|
|
||||
|
}, |
||||
|
{ |
||||
|
title: '审核不通过数量', |
||||
|
dataIndex: 'rejectCount', |
||||
|
width: 130, |
||||
|
|
||||
|
}, |
||||
|
{ |
||||
|
title: '非审查范围数量', |
||||
|
dataIndex: 'irrelevantCount', |
||||
|
width: 130, |
||||
|
}, |
||||
|
{ |
||||
|
title: '审核失败数量', |
||||
|
dataIndex: 'failCount', |
||||
|
width: 100, |
||||
|
}, |
||||
|
{ |
||||
|
title: '进度(百分比)', |
||||
|
dataIndex: 'progress', |
||||
|
}, |
||||
|
{ |
||||
|
title: '处理时间', |
||||
|
dataIndex: 'processingTime', |
||||
|
}, |
||||
|
{ |
||||
|
title: '状态', |
||||
|
dataIndex: 'progressStatus', |
||||
|
customRender: ({ value }) => renderDict(value, 'document_task_status'), |
||||
|
}, |
||||
|
]; |
||||
|
export const modalSchemas: FormSchema[] = [ |
||||
|
{ |
||||
|
label: '文件名称', |
||||
|
field: 'ossId', |
||||
|
required: true, |
||||
|
component: 'Upload', |
||||
|
componentProps: { |
||||
|
accept: ['.zip'], |
||||
|
maxSize: 500, |
||||
|
multiple: false, |
||||
|
resultField: 'ossId', |
||||
|
api: uploadContractual, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
label: '批次名称', |
||||
|
field: 'batchName', |
||||
|
required: false, |
||||
|
component: 'Input', |
||||
|
}, |
||||
|
{ |
||||
|
label: '备注', |
||||
|
field: 'remark', |
||||
|
required: false, |
||||
|
component: 'InputTextArea', |
||||
|
}, |
||||
|
]; |
@ -0,0 +1,74 @@ |
|||||
|
<template> |
||||
|
<BasicModal |
||||
|
v-bind="$attrs" |
||||
|
:title="title" |
||||
|
@register="registerInnerModal" |
||||
|
@ok="handleSubmit" |
||||
|
@cancel="resetForm" |
||||
|
> |
||||
|
<BasicForm @register="registerForm" /> |
||||
|
</BasicModal> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { BasicModal, useModalInner } from '@/components/Modal'; |
||||
|
import { BasicForm, useForm } from '@/components/Form'; |
||||
|
import { computed, ref, unref } from 'vue'; |
||||
|
import { JyjcontractualTaskBatchInfo, JyjcontractualTaskBatchAdd, JyjcontractualTaskBatchUpdate } from '@/api/contractReview/JyjcontractualTaskBatch'; |
||||
|
import { modalSchemas } from './JyjcontractualTaskBatch.data'; |
||||
|
|
||||
|
defineOptions({ name: 'JyjcontractualTaskBatchModal' }); |
||||
|
|
||||
|
const emit = defineEmits(['register', 'reload']); |
||||
|
|
||||
|
const isUpdate = ref<boolean>(false); |
||||
|
const title = computed<string>(() => { |
||||
|
return isUpdate.value ? '编辑合同批处理记录' : '新增合同批处理记录'; |
||||
|
}); |
||||
|
|
||||
|
const [registerInnerModal, { modalLoading, closeModal }] = useModalInner( |
||||
|
async (data: { record?: Recordable; update: boolean }) => { |
||||
|
modalLoading(true); |
||||
|
const { record, update } = data; |
||||
|
isUpdate.value = update; |
||||
|
if (update && record) { |
||||
|
const ret = await JyjcontractualTaskBatchInfo(record.id); |
||||
|
await setFieldsValue(ret); |
||||
|
} |
||||
|
modalLoading(false); |
||||
|
}, |
||||
|
); |
||||
|
|
||||
|
const [registerForm, { setFieldsValue, resetForm, validate }] = useForm({ |
||||
|
labelWidth: 100, |
||||
|
showActionButtonGroup: false, |
||||
|
baseColProps: { span: 24 }, |
||||
|
schemas: modalSchemas, |
||||
|
}); |
||||
|
|
||||
|
async function handleSubmit() { |
||||
|
try { |
||||
|
modalLoading(true); |
||||
|
const data = await validate(); |
||||
|
//修改 |
||||
|
if (unref(isUpdate)) { |
||||
|
data["ossId"]=data["ossId"][0] |
||||
|
await JyjcontractualTaskBatchUpdate(data); |
||||
|
} else { |
||||
|
//新增 |
||||
|
data["ossId"]=data["ossId"][0] |
||||
|
data["taskName"]="batchReview" |
||||
|
data["taskType"]="contract_review" |
||||
|
await JyjcontractualTaskBatchAdd(data); |
||||
|
} |
||||
|
emit('reload'); |
||||
|
closeModal(); |
||||
|
await resetForm(); |
||||
|
} catch (e) { |
||||
|
} finally { |
||||
|
modalLoading(false); |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped></style> |
@ -0,0 +1,200 @@ |
|||||
|
<template> |
||||
|
<PageWrapper dense> |
||||
|
<BasicTable @register="registerTable"> |
||||
|
<template #toolbar> |
||||
|
<!-- <a-button |
||||
|
@click=" |
||||
|
downloadExcel( |
||||
|
JyjcontractualTaskBatchExport, |
||||
|
'合同批处理记录数据', |
||||
|
getForm().getFieldsValue(), |
||||
|
) |
||||
|
" |
||||
|
v-auth="'productManagement:JyjcontractualTaskBatch:export'" |
||||
|
>导出</a-button |
||||
|
> |
||||
|
<a-button |
||||
|
type="primary" |
||||
|
danger |
||||
|
@click="multipleRemove(JyjcontractualTaskBatchRemove)" |
||||
|
:disabled="!selected" |
||||
|
v-auth="'productManagement:JyjcontractualTaskBatch:remove'" |
||||
|
>删除</a-button |
||||
|
> --> |
||||
|
<a-button |
||||
|
type="primary" |
||||
|
@click="handleAdd" |
||||
|
v-auth="'productManagement:JyjcontractualTaskBatch:add'" |
||||
|
>新增</a-button |
||||
|
> |
||||
|
</template> |
||||
|
<template #bodyCell="{ column, record }"> |
||||
|
<template v-if="column.key === 'passCount'"> |
||||
|
<div class="grid grid-flow-row auto-rows-max"> |
||||
|
<div> {{ record.passCount }}</div> |
||||
|
<div><TableAction |
||||
|
stopButtonPropagation |
||||
|
:actions="[ |
||||
|
{ |
||||
|
label: '查看', |
||||
|
icon: IconEnum.PREVIEW, |
||||
|
type: 'primary', |
||||
|
color:'success', |
||||
|
ifShow:()=>{ |
||||
|
if(record.passCount&&record.passCount>0){ |
||||
|
return true |
||||
|
}else{ |
||||
|
return false |
||||
|
} |
||||
|
}, |
||||
|
ghost: true, |
||||
|
onClick: handlePreview.bind(null, record,'passCount'), |
||||
|
}, |
||||
|
]" |
||||
|
/></div> |
||||
|
</div> |
||||
|
</template> |
||||
|
<template v-if="column.key === 'rejectCount'"> |
||||
|
<div class="grid grid-flow-row auto-rows-max"> |
||||
|
<div> {{ record.rejectCount }}</div> |
||||
|
<div><TableAction |
||||
|
stopButtonPropagation |
||||
|
:actions="[ |
||||
|
{ |
||||
|
label: '查看', |
||||
|
icon: IconEnum.PREVIEW, |
||||
|
type: 'primary', |
||||
|
color:'error', |
||||
|
ifShow:()=>{ |
||||
|
if(record.rejectCount&&record.rejectCount>0){ |
||||
|
return true |
||||
|
}else{ |
||||
|
return false |
||||
|
} |
||||
|
}, |
||||
|
ghost: true, |
||||
|
onClick: handlePreview.bind(null, record,'rejectCount'), |
||||
|
}, |
||||
|
]" |
||||
|
/></div> |
||||
|
</div> |
||||
|
</template> |
||||
|
<template v-if="column.key === 'irrelevantCount'"> |
||||
|
<div class="grid grid-flow-row auto-rows-max"> |
||||
|
<div> {{ record.irrelevantCount }}</div> |
||||
|
<div><TableAction |
||||
|
stopButtonPropagation |
||||
|
:actions="[ |
||||
|
{ |
||||
|
label: '查看', |
||||
|
icon: IconEnum.PREVIEW, |
||||
|
type: 'primary', |
||||
|
color:'warning', |
||||
|
ifShow:()=>{ |
||||
|
if(record.irrelevantCount&&record.irrelevantCount>0){ |
||||
|
return true |
||||
|
}else{ |
||||
|
return false |
||||
|
} |
||||
|
}, |
||||
|
ghost: true, |
||||
|
onClick: handlePreview.bind(null, record,'irrelevantCount'), |
||||
|
}, |
||||
|
]" |
||||
|
/></div> |
||||
|
</div> |
||||
|
</template> |
||||
|
<template v-if="column.key === 'failCount'"> |
||||
|
<div class="grid grid-flow-row auto-rows-max"> |
||||
|
<div> {{ record.failCount }}</div> |
||||
|
<div><TableAction |
||||
|
:actions="[ |
||||
|
{ |
||||
|
label: '查看', |
||||
|
icon: IconEnum.PREVIEW, |
||||
|
type: 'primary', |
||||
|
ifShow:()=>{ |
||||
|
if(record.failCount&&record.failCount>0){ |
||||
|
return true |
||||
|
}else{ |
||||
|
return false |
||||
|
} |
||||
|
}, |
||||
|
ghost: true, |
||||
|
onClick: handlePreview.bind(null, record,'failCount'), |
||||
|
}, |
||||
|
]" |
||||
|
/></div> |
||||
|
</div> |
||||
|
</template> |
||||
|
</template> |
||||
|
</BasicTable> |
||||
|
<JyjcontractualTaskBatchModal @register="registerModal" @reload="reload" /> |
||||
|
<ContractualTasksTableModal @register="registerTableModal"/> |
||||
|
</PageWrapper> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { PageWrapper } from '@/components/Page'; |
||||
|
import { BasicTable, useTable, TableAction } from '@/components/Table'; |
||||
|
import { |
||||
|
JyjcontractualTaskBatchList, |
||||
|
JyjcontractualTaskBatchExport, |
||||
|
JyjcontractualTaskBatchRemove, |
||||
|
} from '@/api/contractReview/JyjcontractualTaskBatch'; |
||||
|
import { downloadExcel } from '@/utils/file/download'; |
||||
|
import { useModal } from '@/components/Modal'; |
||||
|
import JyjcontractualTaskBatchModal from './JyjcontractualTaskBatchModal.vue'; |
||||
|
import ContractualTasksTableModal from './ContractualTasksTableModal.vue' |
||||
|
import { formSchemas, columns } from './JyjcontractualTaskBatch.data'; |
||||
|
import { IconEnum } from '@/enums/appEnum'; |
||||
|
|
||||
|
defineOptions({ name: 'JyjcontractualTaskBatch' }); |
||||
|
|
||||
|
const [registerTable, { reload, multipleRemove, selected, getForm }] = useTable({ |
||||
|
rowSelection: { |
||||
|
type: 'checkbox', |
||||
|
}, |
||||
|
title: '合同批处理记录列表', |
||||
|
api: JyjcontractualTaskBatchList, |
||||
|
showIndexColumn: false, |
||||
|
rowKey: 'id', |
||||
|
useSearchForm: true, |
||||
|
formConfig: { |
||||
|
schemas: formSchemas, |
||||
|
baseColProps: { |
||||
|
xs: 24, |
||||
|
sm: 24, |
||||
|
md: 24, |
||||
|
lg: 6, |
||||
|
}, |
||||
|
}, |
||||
|
columns: columns, |
||||
|
actionColumn: { |
||||
|
ifShow:false, |
||||
|
width: 200, |
||||
|
title: '操作', |
||||
|
key: 'action', |
||||
|
fixed: 'right', |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
const [registerModal, { openModal }] = useModal(); |
||||
|
const [registerTableModal,{openModal:openTableModal}]= useModal(); |
||||
|
function handleEdit(record: Recordable) { |
||||
|
openModal(true, { record, update: true }); |
||||
|
} |
||||
|
|
||||
|
function handleAdd() { |
||||
|
openModal(true, { update: false }); |
||||
|
} |
||||
|
function handlePreview(record: Recordable,type:string){ |
||||
|
openTableModal(true,{record,type:type}) |
||||
|
} |
||||
|
async function handleDelete(record: Recordable) { |
||||
|
await JyjcontractualTaskBatchRemove([record.id]); |
||||
|
await reload(); |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped></style> |
@ -0,0 +1,251 @@ |
|||||
|
<template> |
||||
|
<PageWrapper dense> |
||||
|
<div class="grid grid-cols-5 gap-4"> |
||||
|
<div class="col-span-3"> |
||||
|
<CanvasEditor |
||||
|
ref="canvasEditor" |
||||
|
:parentContent="parentContent" |
||||
|
:view="view" |
||||
|
@save-content="handleSaveCanvasEditorContent" |
||||
|
/> |
||||
|
</div> |
||||
|
<div class="col-span-2"> |
||||
|
<!-- 添加 col-span-2 和高度样式 --> |
||||
|
<div class="tabs-container"> |
||||
|
<Tabs v-model:activeKey="activeKey" type="card"> |
||||
|
<TabPane key="1" tab="Tab 1"> |
||||
|
<div class="scroll-container"> |
||||
|
<div class="card-container"> |
||||
|
<Card |
||||
|
v-for="(item, index) in cardList" |
||||
|
:key="index" |
||||
|
:class="['custom-card', { 'card-selected': selectedCard === item.title }]" |
||||
|
@click="handleCardClick(item.title)" |
||||
|
> |
||||
|
<template #title>{{ item.title }}</template> |
||||
|
{{ item.content }} |
||||
|
</Card> |
||||
|
</div> |
||||
|
</div> |
||||
|
</TabPane> |
||||
|
<TabPane key="2" tab="Tab 2">Content of Tab Pane 2</TabPane> |
||||
|
<TabPane key="3" tab="Tab 3">Content of Tab Pane 3</TabPane> |
||||
|
</Tabs> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</PageWrapper> |
||||
|
</template> |
||||
|
<script lang="ts" setup> |
||||
|
import { ref, onMounted, reactive } from 'vue'; |
||||
|
import { PageWrapper } from '@/components/Page'; |
||||
|
import WorkbenchHeader from './components/WorkbenchHeader.vue'; |
||||
|
import { Tabs, TabPane, Card, Dropdown, Menu, MenuItem } from 'ant-design-vue'; |
||||
|
import ProjectCard from './components/ProjectCard.vue'; |
||||
|
import QuickNav from './components/QuickNav.vue'; |
||||
|
import DocumentTasksTable from '@/views/documentReview/DocumentTasks/DocumentTasksTable.vue'; |
||||
|
import { useRouter } from 'vue-router'; |
||||
|
import { DownOutlined, UserOutlined } from '@ant-design/icons-vue'; |
||||
|
import { groupItems } from './components/data'; |
||||
|
import CanvasEditor from '@/views/CanvasEditor/index.vue'; |
||||
|
const activeKey = ref('1'); |
||||
|
// 卡片数据 |
||||
|
const cardList = ref([ |
||||
|
{ title: '标题1', content: '内容1' }, |
||||
|
{ title: '标题2', content: '内容2' }, |
||||
|
{ title: '标题3', content: '内容3' }, |
||||
|
{ title: '标题1', content: '内容1' }, |
||||
|
{ title: '标题2', content: '内容2' }, |
||||
|
{ title: '标题3', content: '内容3' }, |
||||
|
{ title: '标题1', content: '内容1' }, |
||||
|
{ title: '标题2', content: '内容2' }, |
||||
|
{ title: '标题3', content: '内容3' }, |
||||
|
{ title: '标题1', content: '内容1' }, |
||||
|
{ title: '标题2', content: '内容2' }, |
||||
|
{ title: '标题3', content: '内容3' }, |
||||
|
{ title: '标题1', content: '内容1' }, |
||||
|
{ title: '标题2', content: '内容2' }, |
||||
|
{ title: '标题3', content: '内容3' }, |
||||
|
{ title: '标题1', content: '内容1' }, |
||||
|
{ title: '标题2', content: '内容2' }, |
||||
|
{ title: '标题3', content: '内容3' }, |
||||
|
]); |
||||
|
const selectedCard = ref(''); // 用于存储当前选中的卡片标题 |
||||
|
const handleCardClick = (title) => { |
||||
|
selectedCard.value = title; |
||||
|
console.log('点击的卡片标题:', title); |
||||
|
}; |
||||
|
// 存放父组件传递的数据 |
||||
|
let parentContent = reactive<any>(undefined); |
||||
|
// 存放子组件数据 |
||||
|
const content = ref<any>(undefined); |
||||
|
// 标识符 |
||||
|
const view = ref<string | undefined>(undefined); |
||||
|
|
||||
|
// 初始化数据 |
||||
|
onMounted(() => { |
||||
|
console.log('模拟父组件向后端请求数据, 传递给子组件'); |
||||
|
getEditorContent(); |
||||
|
view.value = 'parent'; |
||||
|
}); |
||||
|
|
||||
|
// 模拟后端获取数据的方法 |
||||
|
const getEditorContent = () => { |
||||
|
parentContent = { |
||||
|
header: [ |
||||
|
{ |
||||
|
value: '', |
||||
|
size: 12, |
||||
|
bold: false, |
||||
|
color: 'rgb(33, 53, 71)', |
||||
|
italic: false, |
||||
|
}, |
||||
|
], |
||||
|
main: [ |
||||
|
{ |
||||
|
value: |
||||
|
'父类传递的数据 通过后端获取!\n甲方:企查查科技股份有限公司\n法定代表人:陈德强\n住所:苏州工业园区科创东区东石泾港路2号润港产业园6号楼10层1001室11', |
||||
|
size: 10, |
||||
|
bold: false, |
||||
|
}, |
||||
|
], |
||||
|
}; |
||||
|
}; |
||||
|
|
||||
|
// 组件引用 |
||||
|
const canvasEditor = ref<InstanceType<typeof CanvasEditor> | null>(null); |
||||
|
|
||||
|
// 保存内容方法 |
||||
|
const handleSaveContent = () => { |
||||
|
// 访问子组件的方法 |
||||
|
(canvasEditor.value as any).saveContent(); |
||||
|
}; |
||||
|
|
||||
|
// 处理子组件传递的数据 |
||||
|
const handleSaveCanvasEditorContent = (data: any) => { |
||||
|
console.log('从子组件接收到的数据:', data); |
||||
|
// 将data数据转换为 json 格式的数据, 方便入库处理 |
||||
|
content.value = JSON.stringify(data); |
||||
|
console.log('转换后的数据 content 为: ', content.value); |
||||
|
}; |
||||
|
|
||||
|
const router = useRouter(); |
||||
|
// 状态定义 |
||||
|
const loading = ref(false); |
||||
|
const handleMenuClick = ({ key }) => { |
||||
|
console.log(key); |
||||
|
router.push({ path: key }); |
||||
|
}; |
||||
|
// 获取任务列表 |
||||
|
const fetchTaskList = async () => {}; |
||||
|
|
||||
|
// 页面加载时获取数据 |
||||
|
onMounted(() => { |
||||
|
fetchTaskList(); |
||||
|
}); |
||||
|
setTimeout(() => { |
||||
|
loading.value = false; |
||||
|
}, 1500); |
||||
|
</script> |
||||
|
<style scoped> |
||||
|
/* Tabs 相关样式 */ |
||||
|
/* 设置未选中标签的基本样式 */ |
||||
|
:deep(.ant-tabs-card > .ant-tabs-nav .ant-tabs-tab) { |
||||
|
color: rgba(0, 0, 0, 0.85) !important; /* 文字颜色为黑色,带透明度 */ |
||||
|
background: #fff; /* 背景色为白色 */ |
||||
|
border: 1px solid #f0f0f0; /* 浅灰色边框 */ |
||||
|
} |
||||
|
|
||||
|
/* 设置选中标签的样式 */ |
||||
|
:deep(.ant-tabs-card > .ant-tabs-nav .ant-tabs-tab-active) { |
||||
|
color: #ffffff !important; /* 文字颜色为白色 */ |
||||
|
background: #1890ff !important; /* 背景色为蓝色 */ |
||||
|
border-color: #1890ff !important; /* 边框颜色也改为蓝色 */ |
||||
|
} |
||||
|
|
||||
|
/* 确保选中标签的文字颜色为白色 */ |
||||
|
:deep(.ant-tabs-card > .ant-tabs-nav .ant-tabs-tab-active .ant-tabs-tab-btn) { |
||||
|
color: #ffffff !important; /* 文字颜色强制设为白色 */ |
||||
|
} |
||||
|
|
||||
|
/* 鼠标悬停时的文字颜色效果 */ |
||||
|
:deep(.ant-tabs-card > .ant-tabs-nav .ant-tabs-tab:hover .ant-tabs-tab-btn) { |
||||
|
color: #1890ff !important; /* 悬停时文字变为蓝色 */ |
||||
|
} |
||||
|
|
||||
|
/* Card 相关样式 */ |
||||
|
/* 卡片容器布局设置 */ |
||||
|
.card-container { |
||||
|
display: flex; |
||||
|
gap: 16px; |
||||
|
flex-wrap: wrap; |
||||
|
width: 100%; |
||||
|
} |
||||
|
|
||||
|
/* 单个卡片的基本样式 */ |
||||
|
.custom-card { |
||||
|
width: 100%; |
||||
|
margin-bottom: 16px; |
||||
|
cursor: pointer; |
||||
|
transition: all 0.3s; |
||||
|
background-color: #fff; /* 添加默认背景色 */ |
||||
|
border: 1px solid #e8e8e8; /* 添加默认边框 */ |
||||
|
} |
||||
|
|
||||
|
/* 卡片选中状态 */ |
||||
|
.custom-card.card-selected { |
||||
|
background-color: #e6f4ff !important; /* 选中时的淡蓝色背景 */ |
||||
|
border: 1px solid #1890ff !important; /* 选中时的蓝色边框 */ |
||||
|
} |
||||
|
|
||||
|
/* 卡片悬停效果 */ |
||||
|
.custom-card:hover { |
||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); |
||||
|
transform: translateY(-2px); |
||||
|
} |
||||
|
|
||||
|
/* 选中状态下的悬停效果 */ |
||||
|
.custom-card.card-selected:hover { |
||||
|
background-color: #e6f4ff !important; |
||||
|
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.1); |
||||
|
} |
||||
|
|
||||
|
/* 卡片点击效果 */ |
||||
|
.custom-card:active { |
||||
|
transform: translateY(0); |
||||
|
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); |
||||
|
} |
||||
|
|
||||
|
/* 修改卡片内容区域的内边距 */ |
||||
|
:deep(.ant-card-body) { |
||||
|
padding: 16px; |
||||
|
} |
||||
|
|
||||
|
/* 滚动容器样式 */ |
||||
|
.scroll-container { |
||||
|
height: calc(100vh - 25vh); /* 可以根据实际需要调整高度 */ |
||||
|
overflow-y: auto; /* 添加垂直滚动条 */ |
||||
|
padding: 16px; |
||||
|
} |
||||
|
|
||||
|
/* 美化滚动条样式(可选) */ |
||||
|
.scroll-container::-webkit-scrollbar { |
||||
|
width: 6px; /* 滚动条宽度 */ |
||||
|
} |
||||
|
|
||||
|
.scroll-container::-webkit-scrollbar-thumb { |
||||
|
background-color: #ccc; /* 滚动条颜色 */ |
||||
|
border-radius: 3px; /* 滚动条圆角 */ |
||||
|
} |
||||
|
|
||||
|
.scroll-container::-webkit-scrollbar-track { |
||||
|
background-color: #f1f1f1; /* 滚动条轨道颜色 */ |
||||
|
} |
||||
|
|
||||
|
/* 保持原有的卡片容器样式 */ |
||||
|
.card-container { |
||||
|
display: flex; |
||||
|
gap: 16px; |
||||
|
flex-wrap: wrap; |
||||
|
} |
||||
|
</style> |
Loading…
Reference in new issue