56 changed files with 5442 additions and 264 deletions
@ -0,0 +1,61 @@ |
|||
import { defHttp } from '@/utils/http/axios'; |
|||
import { ID, IDS, commonExport } from '@/api/base'; |
|||
import { ContractualAuditConfigVO, ContractualAuditConfigForm, ContractualAuditConfigQuery } from './model'; |
|||
|
|||
/** |
|||
* 查询合同审核配置列表 |
|||
* @param params |
|||
* @returns |
|||
*/ |
|||
export function ContractualAuditConfigList(params?: ContractualAuditConfigQuery) { |
|||
return defHttp.get<ContractualAuditConfigVO[]>({ url: '/productManagement/ContractualAuditConfig/list', params }); |
|||
} |
|||
|
|||
/** |
|||
* 导出合同审核配置列表 |
|||
* @param params |
|||
* @returns |
|||
*/ |
|||
export function ContractualAuditConfigExport(params?: ContractualAuditConfigQuery) { |
|||
return commonExport('/productManagement/ContractualAuditConfig/export', params ?? {}); |
|||
} |
|||
|
|||
/** |
|||
* 查询合同审核配置详细 |
|||
* @param id id |
|||
* @returns |
|||
*/ |
|||
export function ContractualAuditConfigInfo(id: ID) { |
|||
return defHttp.get<ContractualAuditConfigVO>({ url: '/productManagement/ContractualAuditConfig/' + id }); |
|||
} |
|||
|
|||
/** |
|||
* 新增合同审核配置 |
|||
* @param data |
|||
* @returns |
|||
*/ |
|||
export function ContractualAuditConfigAdd(data: ContractualAuditConfigForm) { |
|||
return defHttp.postWithMsg<void>({ url: '/productManagement/ContractualAuditConfig', data }); |
|||
} |
|||
|
|||
/** |
|||
* 更新合同审核配置 |
|||
* @param data |
|||
* @returns |
|||
*/ |
|||
export function ContractualAuditConfigUpdate(data: ContractualAuditConfigForm) { |
|||
return defHttp.putWithMsg<void>({ url: '/productManagement/ContractualAuditConfig', data }); |
|||
} |
|||
|
|||
/** |
|||
* 删除合同审核配置 |
|||
* @param id id |
|||
* @returns |
|||
*/ |
|||
export function ContractualAuditConfigRemove(id: ID | IDS) { |
|||
return defHttp.deleteWithMsg<void>({ url: '/productManagement/ContractualAuditConfig/' + id },); |
|||
} |
|||
|
|||
export function getRequirementTypeDict(){ |
|||
return defHttp.get<any>({url:"/productManagement/ContractualAuditConfig/getRequirementTypeDict"}) |
|||
} |
@ -0,0 +1,94 @@ |
|||
import { BaseEntity, PageQuery } from '@/api/base'; |
|||
|
|||
export interface ContractualAuditConfigVO { |
|||
/** |
|||
* 主键ID |
|||
*/ |
|||
id: string | number; |
|||
|
|||
/** |
|||
* 规则名称 |
|||
*/ |
|||
auditElement: string; |
|||
|
|||
/** |
|||
* 规则ID |
|||
*/ |
|||
requirementId: string | number; |
|||
|
|||
/** |
|||
* 规则描述 |
|||
*/ |
|||
requirementDescription: string; |
|||
|
|||
/** |
|||
* 是否表单,0-否,1-是 |
|||
*/ |
|||
isForm: number; |
|||
/** |
|||
* CPU/OS/数据库规则配置 |
|||
*/ |
|||
requirementCpuosdatabase?: any[]; |
|||
|
|||
/** |
|||
* 实体规则配置 |
|||
*/ |
|||
requirementEntity?: any[]; |
|||
|
|||
/** |
|||
* 产品属性规则配置 |
|||
*/ |
|||
requirementProductAttribute?: any[]; |
|||
|
|||
/** |
|||
* 普通合同规则配置 |
|||
*/ |
|||
requirementContractualNormal?: any[]; |
|||
|
|||
} |
|||
|
|||
export interface ContractualAuditConfigForm extends BaseEntity { |
|||
/** |
|||
* 主键ID |
|||
*/ |
|||
id?: string | number; |
|||
|
|||
/** |
|||
* 规则名称 |
|||
*/ |
|||
auditElement?: string; |
|||
|
|||
/** |
|||
* 规则ID |
|||
*/ |
|||
requirementId?: string | number; |
|||
|
|||
/** |
|||
* 规则描述 |
|||
*/ |
|||
requirementDescription?: string; |
|||
|
|||
} |
|||
|
|||
export interface ContractualAuditConfigQuery extends PageQuery { |
|||
|
|||
/** |
|||
* 规则名称 |
|||
*/ |
|||
auditElement?: string; |
|||
|
|||
/** |
|||
* 规则ID |
|||
*/ |
|||
requirementId?: string | number; |
|||
|
|||
/** |
|||
* 规则描述 |
|||
*/ |
|||
requirementDescription?: string; |
|||
|
|||
/** |
|||
* 日期范围参数 |
|||
*/ |
|||
params?: any; |
|||
} |
@ -0,0 +1,57 @@ |
|||
import { defHttp } from '@/utils/http/axios'; |
|||
import { ID, IDS, commonExport } from '@/api/base'; |
|||
import { ContractualProductInfoVO, ContractualProductInfoForm, ContractualProductInfoQuery } from './model'; |
|||
|
|||
/** |
|||
* 查询合同产品信息列表 |
|||
* @param params |
|||
* @returns |
|||
*/ |
|||
export function ContractualProductInfoList(params?: ContractualProductInfoQuery) { |
|||
return defHttp.get<ContractualProductInfoVO[]>({ url: '/productManagement/ContractualProductInfo/list', params }); |
|||
} |
|||
|
|||
/** |
|||
* 导出合同产品信息列表 |
|||
* @param params |
|||
* @returns |
|||
*/ |
|||
export function ContractualProductInfoExport(params?: ContractualProductInfoQuery) { |
|||
return commonExport('/productManagement/ContractualProductInfo/export', params ?? {}); |
|||
} |
|||
|
|||
/** |
|||
* 查询合同产品信息详细 |
|||
* @param id id |
|||
* @returns |
|||
*/ |
|||
export function ContractualProductInfoInfo(id: ID) { |
|||
return defHttp.get<ContractualProductInfoVO>({ url: '/productManagement/ContractualProductInfo/' + id }); |
|||
} |
|||
|
|||
/** |
|||
* 新增合同产品信息 |
|||
* @param data |
|||
* @returns |
|||
*/ |
|||
export function ContractualProductInfoAdd(data: ContractualProductInfoForm) { |
|||
return defHttp.postWithMsg<void>({ url: '/productManagement/ContractualProductInfo', data }); |
|||
} |
|||
|
|||
/** |
|||
* 更新合同产品信息 |
|||
* @param data |
|||
* @returns |
|||
*/ |
|||
export function ContractualProductInfoUpdate(data: ContractualProductInfoForm) { |
|||
return defHttp.putWithMsg<void>({ url: '/productManagement/ContractualProductInfo', data }); |
|||
} |
|||
|
|||
/** |
|||
* 删除合同产品信息 |
|||
* @param id id |
|||
* @returns |
|||
*/ |
|||
export function ContractualProductInfoRemove(id: ID | IDS) { |
|||
return defHttp.deleteWithMsg<void>({ url: '/productManagement/ContractualProductInfo/' + id },); |
|||
} |
@ -0,0 +1,160 @@ |
|||
import { BaseEntity, PageQuery } from '@/api/base'; |
|||
|
|||
export interface ContractualProductInfoVO { |
|||
/** |
|||
* 主键ID |
|||
*/ |
|||
id: string | number; |
|||
|
|||
/** |
|||
* 任务ID |
|||
*/ |
|||
taskId: string | number; |
|||
|
|||
/** |
|||
* 文件名称 |
|||
*/ |
|||
fileName: string; |
|||
|
|||
/** |
|||
* 品牌 |
|||
*/ |
|||
brand: string; |
|||
|
|||
/** |
|||
* 版本号 |
|||
*/ |
|||
versionStr: string; |
|||
|
|||
/** |
|||
* 单价 |
|||
*/ |
|||
unitPrice: number; |
|||
|
|||
/** |
|||
* 价格单位 |
|||
*/ |
|||
priceUnit: string; |
|||
|
|||
/** |
|||
* 数量 |
|||
*/ |
|||
quantity: number; |
|||
|
|||
/** |
|||
* 总价 |
|||
*/ |
|||
totalPrice: number; |
|||
|
|||
/** |
|||
* 类型 |
|||
*/ |
|||
type: string; |
|||
|
|||
} |
|||
|
|||
export interface ContractualProductInfoForm extends BaseEntity { |
|||
/** |
|||
* 主键ID |
|||
*/ |
|||
id?: string | number; |
|||
|
|||
/** |
|||
* 任务ID |
|||
*/ |
|||
taskId?: string | number; |
|||
|
|||
/** |
|||
* 文件名称 |
|||
*/ |
|||
fileName?: string; |
|||
|
|||
/** |
|||
* 品牌 |
|||
*/ |
|||
brand?: string; |
|||
|
|||
/** |
|||
* 版本号 |
|||
*/ |
|||
versionStr?: string; |
|||
|
|||
/** |
|||
* 单价 |
|||
*/ |
|||
unitPrice?: number; |
|||
|
|||
/** |
|||
* 价格单位 |
|||
*/ |
|||
priceUnit?: string; |
|||
|
|||
/** |
|||
* 数量 |
|||
*/ |
|||
quantity?: number; |
|||
|
|||
/** |
|||
* 总价 |
|||
*/ |
|||
totalPrice?: number; |
|||
|
|||
/** |
|||
* 类型 |
|||
*/ |
|||
type?: string; |
|||
|
|||
} |
|||
|
|||
export interface ContractualProductInfoQuery extends PageQuery { |
|||
|
|||
/** |
|||
* 任务ID |
|||
*/ |
|||
taskId?: string | number; |
|||
|
|||
/** |
|||
* 文件名称 |
|||
*/ |
|||
fileName?: string; |
|||
|
|||
/** |
|||
* 品牌 |
|||
*/ |
|||
brand?: string; |
|||
|
|||
/** |
|||
* 版本号 |
|||
*/ |
|||
versionStr?: string; |
|||
|
|||
/** |
|||
* 单价 |
|||
*/ |
|||
unitPrice?: number; |
|||
|
|||
/** |
|||
* 价格单位 |
|||
*/ |
|||
priceUnit?: string; |
|||
|
|||
/** |
|||
* 数量 |
|||
*/ |
|||
quantity?: number; |
|||
|
|||
/** |
|||
* 总价 |
|||
*/ |
|||
totalPrice?: number; |
|||
|
|||
/** |
|||
* 类型 |
|||
*/ |
|||
type?: string; |
|||
|
|||
/** |
|||
* 日期范围参数 |
|||
*/ |
|||
params?: any; |
|||
} |
@ -0,0 +1,57 @@ |
|||
import { defHttp } from '@/utils/http/axios'; |
|||
import { ID, IDS, commonExport } from '@/api/base'; |
|||
import { RequirementContractualNormalVO, RequirementContractualNormalForm, RequirementContractualNormalQuery } from './model'; |
|||
|
|||
/** |
|||
* 查询合同常规要求列表 |
|||
* @param params |
|||
* @returns |
|||
*/ |
|||
export function RequirementContractualNormalList(params?: RequirementContractualNormalQuery) { |
|||
return defHttp.get<RequirementContractualNormalVO[]>({ url: '/productManagement/RequirementContractualNormal/list', params }); |
|||
} |
|||
|
|||
/** |
|||
* 导出合同常规要求列表 |
|||
* @param params |
|||
* @returns |
|||
*/ |
|||
export function RequirementContractualNormalExport(params?: RequirementContractualNormalQuery) { |
|||
return commonExport('/productManagement/RequirementContractualNormal/export', params ?? {}); |
|||
} |
|||
|
|||
/** |
|||
* 查询合同常规要求详细 |
|||
* @param id id |
|||
* @returns |
|||
*/ |
|||
export function RequirementContractualNormalInfo(id: ID) { |
|||
return defHttp.get<RequirementContractualNormalVO>({ url: '/productManagement/RequirementContractualNormal/' + id }); |
|||
} |
|||
|
|||
/** |
|||
* 新增合同常规要求 |
|||
* @param data |
|||
* @returns |
|||
*/ |
|||
export function RequirementContractualNormalAdd(data: RequirementContractualNormalForm) { |
|||
return defHttp.postWithMsg<void>({ url: '/productManagement/RequirementContractualNormal', data }); |
|||
} |
|||
|
|||
/** |
|||
* 更新合同常规要求 |
|||
* @param data |
|||
* @returns |
|||
*/ |
|||
export function RequirementContractualNormalUpdate(data: RequirementContractualNormalForm) { |
|||
return defHttp.putWithMsg<void>({ url: '/productManagement/RequirementContractualNormal', data }); |
|||
} |
|||
|
|||
/** |
|||
* 删除合同常规要求 |
|||
* @param id id |
|||
* @returns |
|||
*/ |
|||
export function RequirementContractualNormalRemove(id: ID | IDS) { |
|||
return defHttp.deleteWithMsg<void>({ url: '/productManagement/RequirementContractualNormal/' + id },); |
|||
} |
@ -0,0 +1,70 @@ |
|||
import { BaseEntity, PageQuery } from '@/api/base'; |
|||
|
|||
export interface RequirementContractualNormalVO { |
|||
/** |
|||
* 主键ID |
|||
*/ |
|||
id: string | number; |
|||
|
|||
/** |
|||
* 合同审核配置表ID |
|||
*/ |
|||
configId: string | number; |
|||
|
|||
/** |
|||
* 检查项 |
|||
*/ |
|||
checkItem: string; |
|||
|
|||
/** |
|||
* 要求描述 |
|||
*/ |
|||
requirementDesc: string; |
|||
|
|||
} |
|||
|
|||
export interface RequirementContractualNormalForm extends BaseEntity { |
|||
/** |
|||
* 主键ID |
|||
*/ |
|||
id?: string | number; |
|||
|
|||
/** |
|||
* 合同审核配置表ID |
|||
*/ |
|||
configId?: string | number; |
|||
|
|||
/** |
|||
* 检查项 |
|||
*/ |
|||
checkItem?: string; |
|||
|
|||
/** |
|||
* 要求描述 |
|||
*/ |
|||
requirementDesc?: string; |
|||
|
|||
} |
|||
|
|||
export interface RequirementContractualNormalQuery extends PageQuery { |
|||
|
|||
/** |
|||
* 合同审核配置表ID |
|||
*/ |
|||
configId?: string | number; |
|||
|
|||
/** |
|||
* 检查项 |
|||
*/ |
|||
checkItem?: string; |
|||
|
|||
/** |
|||
* 要求描述 |
|||
*/ |
|||
requirementDesc?: string; |
|||
|
|||
/** |
|||
* 日期范围参数 |
|||
*/ |
|||
params?: any; |
|||
} |
@ -0,0 +1,57 @@ |
|||
import { defHttp } from '@/utils/http/axios'; |
|||
import { ID, IDS, commonExport } from '@/api/base'; |
|||
import { RequirementCpuVO, RequirementCpuForm, RequirementCpuQuery } from './model'; |
|||
|
|||
/** |
|||
* 查询CPU要求列表 |
|||
* @param params |
|||
* @returns |
|||
*/ |
|||
export function RequirementCpuList(params?: RequirementCpuQuery) { |
|||
return defHttp.get<RequirementCpuVO[]>({ url: '/productManagement/RequirementCpu/list', params }); |
|||
} |
|||
|
|||
/** |
|||
* 导出CPU要求列表 |
|||
* @param params |
|||
* @returns |
|||
*/ |
|||
export function RequirementCpuExport(params?: RequirementCpuQuery) { |
|||
return commonExport('/productManagement/RequirementCpu/export', params ?? {}); |
|||
} |
|||
|
|||
/** |
|||
* 查询CPU要求详细 |
|||
* @param id id |
|||
* @returns |
|||
*/ |
|||
export function RequirementCpuInfo(id: ID) { |
|||
return defHttp.get<RequirementCpuVO>({ url: '/productManagement/RequirementCpu/' + id }); |
|||
} |
|||
|
|||
/** |
|||
* 新增CPU要求 |
|||
* @param data |
|||
* @returns |
|||
*/ |
|||
export function RequirementCpuAdd(data: RequirementCpuForm) { |
|||
return defHttp.postWithMsg<void>({ url: '/productManagement/RequirementCpu', data }); |
|||
} |
|||
|
|||
/** |
|||
* 更新CPU要求 |
|||
* @param data |
|||
* @returns |
|||
*/ |
|||
export function RequirementCpuUpdate(data: RequirementCpuForm) { |
|||
return defHttp.putWithMsg<void>({ url: '/productManagement/RequirementCpu', data }); |
|||
} |
|||
|
|||
/** |
|||
* 删除CPU要求 |
|||
* @param id id |
|||
* @returns |
|||
*/ |
|||
export function RequirementCpuRemove(id: ID | IDS) { |
|||
return defHttp.deleteWithMsg<void>({ url: '/productManagement/RequirementCpu/' + id },); |
|||
} |
@ -0,0 +1,85 @@ |
|||
import { BaseEntity, PageQuery } from '@/api/base'; |
|||
|
|||
export interface RequirementCpuVO { |
|||
/** |
|||
* 主键ID |
|||
*/ |
|||
id: string | number; |
|||
|
|||
/** |
|||
* 合同审核配置表ID |
|||
*/ |
|||
configId: string | number; |
|||
|
|||
/** |
|||
* 名称 |
|||
*/ |
|||
name: string; |
|||
|
|||
/** |
|||
* 型号 |
|||
*/ |
|||
model: string; |
|||
|
|||
/** |
|||
* 版本号 |
|||
*/ |
|||
versionStr: string; |
|||
|
|||
} |
|||
|
|||
export interface RequirementCpuForm extends BaseEntity { |
|||
/** |
|||
* 主键ID |
|||
*/ |
|||
id?: string | number; |
|||
|
|||
/** |
|||
* 合同审核配置表ID |
|||
*/ |
|||
configId?: string | number; |
|||
|
|||
/** |
|||
* 名称 |
|||
*/ |
|||
name?: string; |
|||
|
|||
/** |
|||
* 型号 |
|||
*/ |
|||
model?: string; |
|||
|
|||
/** |
|||
* 版本号 |
|||
*/ |
|||
versionStr?: string; |
|||
|
|||
} |
|||
|
|||
export interface RequirementCpuQuery extends PageQuery { |
|||
|
|||
/** |
|||
* 合同审核配置表ID |
|||
*/ |
|||
configId?: string | number; |
|||
|
|||
/** |
|||
* 名称 |
|||
*/ |
|||
name?: string; |
|||
|
|||
/** |
|||
* 型号 |
|||
*/ |
|||
model?: string; |
|||
|
|||
/** |
|||
* 版本号 |
|||
*/ |
|||
versionStr?: string; |
|||
|
|||
/** |
|||
* 日期范围参数 |
|||
*/ |
|||
params?: any; |
|||
} |
@ -0,0 +1,57 @@ |
|||
import { defHttp } from '@/utils/http/axios'; |
|||
import { ID, IDS, commonExport } from '@/api/base'; |
|||
import { RequirementDatabaseVO, RequirementDatabaseForm, RequirementDatabaseQuery } from './model'; |
|||
|
|||
/** |
|||
* 查询数据库要求列表 |
|||
* @param params |
|||
* @returns |
|||
*/ |
|||
export function RequirementDatabaseList(params?: RequirementDatabaseQuery) { |
|||
return defHttp.get<RequirementDatabaseVO[]>({ url: '/productManagement/RequirementDatabase/list', params }); |
|||
} |
|||
|
|||
/** |
|||
* 导出数据库要求列表 |
|||
* @param params |
|||
* @returns |
|||
*/ |
|||
export function RequirementDatabaseExport(params?: RequirementDatabaseQuery) { |
|||
return commonExport('/productManagement/RequirementDatabase/export', params ?? {}); |
|||
} |
|||
|
|||
/** |
|||
* 查询数据库要求详细 |
|||
* @param id id |
|||
* @returns |
|||
*/ |
|||
export function RequirementDatabaseInfo(id: ID) { |
|||
return defHttp.get<RequirementDatabaseVO>({ url: '/productManagement/RequirementDatabase/' + id }); |
|||
} |
|||
|
|||
/** |
|||
* 新增数据库要求 |
|||
* @param data |
|||
* @returns |
|||
*/ |
|||
export function RequirementDatabaseAdd(data: RequirementDatabaseForm) { |
|||
return defHttp.postWithMsg<void>({ url: '/productManagement/RequirementDatabase', data }); |
|||
} |
|||
|
|||
/** |
|||
* 更新数据库要求 |
|||
* @param data |
|||
* @returns |
|||
*/ |
|||
export function RequirementDatabaseUpdate(data: RequirementDatabaseForm) { |
|||
return defHttp.putWithMsg<void>({ url: '/productManagement/RequirementDatabase', data }); |
|||
} |
|||
|
|||
/** |
|||
* 删除数据库要求 |
|||
* @param id id |
|||
* @returns |
|||
*/ |
|||
export function RequirementDatabaseRemove(id: ID | IDS) { |
|||
return defHttp.deleteWithMsg<void>({ url: '/productManagement/RequirementDatabase/' + id },); |
|||
} |
@ -0,0 +1,85 @@ |
|||
import { BaseEntity, PageQuery } from '@/api/base'; |
|||
|
|||
export interface RequirementDatabaseVO { |
|||
/** |
|||
* 主键ID |
|||
*/ |
|||
id: string | number; |
|||
|
|||
/** |
|||
* 合同审核配置表ID |
|||
*/ |
|||
configId: string | number; |
|||
|
|||
/** |
|||
* 名称 |
|||
*/ |
|||
name: string; |
|||
|
|||
/** |
|||
* 型号 |
|||
*/ |
|||
model: string; |
|||
|
|||
/** |
|||
* 版本号 |
|||
*/ |
|||
versionStr: string; |
|||
|
|||
} |
|||
|
|||
export interface RequirementDatabaseForm extends BaseEntity { |
|||
/** |
|||
* 主键ID |
|||
*/ |
|||
id?: string | number; |
|||
|
|||
/** |
|||
* 合同审核配置表ID |
|||
*/ |
|||
configId?: string | number; |
|||
|
|||
/** |
|||
* 名称 |
|||
*/ |
|||
name?: string; |
|||
|
|||
/** |
|||
* 型号 |
|||
*/ |
|||
model?: string; |
|||
|
|||
/** |
|||
* 版本号 |
|||
*/ |
|||
versionStr?: string; |
|||
|
|||
} |
|||
|
|||
export interface RequirementDatabaseQuery extends PageQuery { |
|||
|
|||
/** |
|||
* 合同审核配置表ID |
|||
*/ |
|||
configId?: string | number; |
|||
|
|||
/** |
|||
* 名称 |
|||
*/ |
|||
name?: string; |
|||
|
|||
/** |
|||
* 型号 |
|||
*/ |
|||
model?: string; |
|||
|
|||
/** |
|||
* 版本号 |
|||
*/ |
|||
versionStr?: string; |
|||
|
|||
/** |
|||
* 日期范围参数 |
|||
*/ |
|||
params?: any; |
|||
} |
@ -0,0 +1,57 @@ |
|||
import { defHttp } from '@/utils/http/axios'; |
|||
import { ID, IDS, commonExport } from '@/api/base'; |
|||
import { RequirementEntityVO, RequirementEntityForm, RequirementEntityQuery } from './model'; |
|||
|
|||
/** |
|||
* 查询主体要求列表 |
|||
* @param params |
|||
* @returns |
|||
*/ |
|||
export function RequirementEntityList(params?: RequirementEntityQuery) { |
|||
return defHttp.get<RequirementEntityVO[]>({ url: '/productManagement/RequirementEntity/list', params }); |
|||
} |
|||
|
|||
/** |
|||
* 导出主体要求列表 |
|||
* @param params |
|||
* @returns |
|||
*/ |
|||
export function RequirementEntityExport(params?: RequirementEntityQuery) { |
|||
return commonExport('/productManagement/RequirementEntity/export', params ?? {}); |
|||
} |
|||
|
|||
/** |
|||
* 查询主体要求详细 |
|||
* @param id id |
|||
* @returns |
|||
*/ |
|||
export function RequirementEntityInfo(id: ID) { |
|||
return defHttp.get<RequirementEntityVO>({ url: '/productManagement/RequirementEntity/' + id }); |
|||
} |
|||
|
|||
/** |
|||
* 新增主体要求 |
|||
* @param data |
|||
* @returns |
|||
*/ |
|||
export function RequirementEntityAdd(data: RequirementEntityForm) { |
|||
return defHttp.postWithMsg<void>({ url: '/productManagement/RequirementEntity', data }); |
|||
} |
|||
|
|||
/** |
|||
* 更新主体要求 |
|||
* @param data |
|||
* @returns |
|||
*/ |
|||
export function RequirementEntityUpdate(data: RequirementEntityForm) { |
|||
return defHttp.putWithMsg<void>({ url: '/productManagement/RequirementEntity', data }); |
|||
} |
|||
|
|||
/** |
|||
* 删除主体要求 |
|||
* @param id id |
|||
* @returns |
|||
*/ |
|||
export function RequirementEntityRemove(id: ID | IDS) { |
|||
return defHttp.deleteWithMsg<void>({ url: '/productManagement/RequirementEntity/' + id },); |
|||
} |
@ -0,0 +1,100 @@ |
|||
import { BaseEntity, PageQuery } from '@/api/base'; |
|||
|
|||
export interface RequirementEntityVO { |
|||
/** |
|||
* 主键ID |
|||
*/ |
|||
id: string | number; |
|||
|
|||
/** |
|||
* 合同审核配置表ID |
|||
*/ |
|||
configId: string | number; |
|||
|
|||
/** |
|||
* 主体名称 |
|||
*/ |
|||
entityName: string; |
|||
|
|||
/** |
|||
* 父主体ID,0表示顶级主体 |
|||
*/ |
|||
parentId: string | number; |
|||
|
|||
/** |
|||
* 层级,1表示顶级 |
|||
*/ |
|||
level: number; |
|||
|
|||
/** |
|||
* 层级路径,格式如:0,1,2 |
|||
*/ |
|||
path: string; |
|||
|
|||
} |
|||
|
|||
export interface RequirementEntityForm extends BaseEntity { |
|||
/** |
|||
* 主键ID |
|||
*/ |
|||
id?: string | number; |
|||
|
|||
/** |
|||
* 合同审核配置表ID |
|||
*/ |
|||
configId?: string | number; |
|||
|
|||
/** |
|||
* 主体名称 |
|||
*/ |
|||
entityName?: string; |
|||
|
|||
/** |
|||
* 父主体ID,0表示顶级主体 |
|||
*/ |
|||
parentId?: string | number; |
|||
|
|||
/** |
|||
* 层级,1表示顶级 |
|||
*/ |
|||
level?: number; |
|||
|
|||
/** |
|||
* 层级路径,格式如:0,1,2 |
|||
*/ |
|||
path?: string; |
|||
|
|||
} |
|||
|
|||
export interface RequirementEntityQuery extends PageQuery { |
|||
|
|||
/** |
|||
* 合同审核配置表ID |
|||
*/ |
|||
configId?: string | number; |
|||
|
|||
/** |
|||
* 主体名称 |
|||
*/ |
|||
entityName?: string; |
|||
|
|||
/** |
|||
* 父主体ID,0表示顶级主体 |
|||
*/ |
|||
parentId?: string | number; |
|||
|
|||
/** |
|||
* 层级,1表示顶级 |
|||
*/ |
|||
level?: number; |
|||
|
|||
/** |
|||
* 层级路径,格式如:0,1,2 |
|||
*/ |
|||
path?: string; |
|||
|
|||
/** |
|||
* 日期范围参数 |
|||
*/ |
|||
params?: any; |
|||
} |
@ -0,0 +1,57 @@ |
|||
import { defHttp } from '@/utils/http/axios'; |
|||
import { ID, IDS, commonExport } from '@/api/base'; |
|||
import { RequirementOsVO, RequirementOsForm, RequirementOsQuery } from './model'; |
|||
|
|||
/** |
|||
* 查询操作系统要求列表 |
|||
* @param params |
|||
* @returns |
|||
*/ |
|||
export function RequirementOsList(params?: RequirementOsQuery) { |
|||
return defHttp.get<RequirementOsVO[]>({ url: '/productManagement/RequirementOs/list', params }); |
|||
} |
|||
|
|||
/** |
|||
* 导出操作系统要求列表 |
|||
* @param params |
|||
* @returns |
|||
*/ |
|||
export function RequirementOsExport(params?: RequirementOsQuery) { |
|||
return commonExport('/productManagement/RequirementOs/export', params ?? {}); |
|||
} |
|||
|
|||
/** |
|||
* 查询操作系统要求详细 |
|||
* @param id id |
|||
* @returns |
|||
*/ |
|||
export function RequirementOsInfo(id: ID) { |
|||
return defHttp.get<RequirementOsVO>({ url: '/productManagement/RequirementOs/' + id }); |
|||
} |
|||
|
|||
/** |
|||
* 新增操作系统要求 |
|||
* @param data |
|||
* @returns |
|||
*/ |
|||
export function RequirementOsAdd(data: RequirementOsForm) { |
|||
return defHttp.postWithMsg<void>({ url: '/productManagement/RequirementOs', data }); |
|||
} |
|||
|
|||
/** |
|||
* 更新操作系统要求 |
|||
* @param data |
|||
* @returns |
|||
*/ |
|||
export function RequirementOsUpdate(data: RequirementOsForm) { |
|||
return defHttp.putWithMsg<void>({ url: '/productManagement/RequirementOs', data }); |
|||
} |
|||
|
|||
/** |
|||
* 删除操作系统要求 |
|||
* @param id id |
|||
* @returns |
|||
*/ |
|||
export function RequirementOsRemove(id: ID | IDS) { |
|||
return defHttp.deleteWithMsg<void>({ url: '/productManagement/RequirementOs/' + id },); |
|||
} |
@ -0,0 +1,85 @@ |
|||
import { BaseEntity, PageQuery } from '@/api/base'; |
|||
|
|||
export interface RequirementOsVO { |
|||
/** |
|||
* 主键ID |
|||
*/ |
|||
id: string | number; |
|||
|
|||
/** |
|||
* 合同审核配置表ID |
|||
*/ |
|||
configId: string | number; |
|||
|
|||
/** |
|||
* 名称 |
|||
*/ |
|||
name: string; |
|||
|
|||
/** |
|||
* 型号 |
|||
*/ |
|||
model: string; |
|||
|
|||
/** |
|||
* 版本号 |
|||
*/ |
|||
versionStr: string; |
|||
|
|||
} |
|||
|
|||
export interface RequirementOsForm extends BaseEntity { |
|||
/** |
|||
* 主键ID |
|||
*/ |
|||
id?: string | number; |
|||
|
|||
/** |
|||
* 合同审核配置表ID |
|||
*/ |
|||
configId?: string | number; |
|||
|
|||
/** |
|||
* 名称 |
|||
*/ |
|||
name?: string; |
|||
|
|||
/** |
|||
* 型号 |
|||
*/ |
|||
model?: string; |
|||
|
|||
/** |
|||
* 版本号 |
|||
*/ |
|||
versionStr?: string; |
|||
|
|||
} |
|||
|
|||
export interface RequirementOsQuery extends PageQuery { |
|||
|
|||
/** |
|||
* 合同审核配置表ID |
|||
*/ |
|||
configId?: string | number; |
|||
|
|||
/** |
|||
* 名称 |
|||
*/ |
|||
name?: string; |
|||
|
|||
/** |
|||
* 型号 |
|||
*/ |
|||
model?: string; |
|||
|
|||
/** |
|||
* 版本号 |
|||
*/ |
|||
versionStr?: string; |
|||
|
|||
/** |
|||
* 日期范围参数 |
|||
*/ |
|||
params?: any; |
|||
} |
@ -0,0 +1,57 @@ |
|||
import { defHttp } from '@/utils/http/axios'; |
|||
import { ID, IDS, commonExport } from '@/api/base'; |
|||
import { RequirementProductAttributeVO, RequirementProductAttributeForm, RequirementProductAttributeQuery } from './model'; |
|||
|
|||
/** |
|||
* 查询产品属性要求列表 |
|||
* @param params |
|||
* @returns |
|||
*/ |
|||
export function RequirementProductAttributeList(params?: RequirementProductAttributeQuery) { |
|||
return defHttp.get<RequirementProductAttributeVO[]>({ url: '/productManagement/RequirementProductAttribute/list', params }); |
|||
} |
|||
|
|||
/** |
|||
* 导出产品属性要求列表 |
|||
* @param params |
|||
* @returns |
|||
*/ |
|||
export function RequirementProductAttributeExport(params?: RequirementProductAttributeQuery) { |
|||
return commonExport('/productManagement/RequirementProductAttribute/export', params ?? {}); |
|||
} |
|||
|
|||
/** |
|||
* 查询产品属性要求详细 |
|||
* @param id id |
|||
* @returns |
|||
*/ |
|||
export function RequirementProductAttributeInfo(id: ID) { |
|||
return defHttp.get<RequirementProductAttributeVO>({ url: '/productManagement/RequirementProductAttribute/' + id }); |
|||
} |
|||
|
|||
/** |
|||
* 新增产品属性要求 |
|||
* @param data |
|||
* @returns |
|||
*/ |
|||
export function RequirementProductAttributeAdd(data: RequirementProductAttributeForm) { |
|||
return defHttp.postWithMsg<void>({ url: '/productManagement/RequirementProductAttribute', data }); |
|||
} |
|||
|
|||
/** |
|||
* 更新产品属性要求 |
|||
* @param data |
|||
* @returns |
|||
*/ |
|||
export function RequirementProductAttributeUpdate(data: RequirementProductAttributeForm) { |
|||
return defHttp.putWithMsg<void>({ url: '/productManagement/RequirementProductAttribute', data }); |
|||
} |
|||
|
|||
/** |
|||
* 删除产品属性要求 |
|||
* @param id id |
|||
* @returns |
|||
*/ |
|||
export function RequirementProductAttributeRemove(id: ID | IDS) { |
|||
return defHttp.deleteWithMsg<void>({ url: '/productManagement/RequirementProductAttribute/' + id },); |
|||
} |
@ -0,0 +1,85 @@ |
|||
import { BaseEntity, PageQuery } from '@/api/base'; |
|||
|
|||
export interface RequirementProductAttributeVO { |
|||
/** |
|||
* 主键ID |
|||
*/ |
|||
id: string | number; |
|||
|
|||
/** |
|||
* 合同审核配置表ID |
|||
*/ |
|||
configId: string | number; |
|||
|
|||
/** |
|||
* 属性名称 |
|||
*/ |
|||
attributeName: string; |
|||
|
|||
/** |
|||
* 要求 |
|||
*/ |
|||
requirement: string; |
|||
|
|||
/** |
|||
* 产品类型 |
|||
*/ |
|||
productType: string; |
|||
|
|||
} |
|||
|
|||
export interface RequirementProductAttributeForm extends BaseEntity { |
|||
/** |
|||
* 主键ID |
|||
*/ |
|||
id?: string | number; |
|||
|
|||
/** |
|||
* 合同审核配置表ID |
|||
*/ |
|||
configId?: string | number; |
|||
|
|||
/** |
|||
* 属性名称 |
|||
*/ |
|||
attributeName?: string; |
|||
|
|||
/** |
|||
* 要求 |
|||
*/ |
|||
requirement?: string; |
|||
|
|||
/** |
|||
* 产品类型 |
|||
*/ |
|||
productType?: string; |
|||
|
|||
} |
|||
|
|||
export interface RequirementProductAttributeQuery extends PageQuery { |
|||
|
|||
/** |
|||
* 合同审核配置表ID |
|||
*/ |
|||
configId?: string | number; |
|||
|
|||
/** |
|||
* 属性名称 |
|||
*/ |
|||
attributeName?: string; |
|||
|
|||
/** |
|||
* 要求 |
|||
*/ |
|||
requirement?: string; |
|||
|
|||
/** |
|||
* 产品类型 |
|||
*/ |
|||
productType?: string; |
|||
|
|||
/** |
|||
* 日期范围参数 |
|||
*/ |
|||
params?: any; |
|||
} |
@ -0,0 +1,72 @@ |
|||
import { BasicColumn } from '@/components/Table'; |
|||
import { FormSchema } from '@/components/Form'; |
|||
import { getDictOptions } from '@/utils/dict'; |
|||
import { useRender } from '@/hooks/component/useRender'; |
|||
const { renderDict } = useRender(); |
|||
export const formSchemas: FormSchema[] = [ |
|||
{ |
|||
label: '审核类型', |
|||
field: 'requirementType', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '审核要素', |
|||
field: 'auditElement', |
|||
component: 'Select', |
|||
componentProps: { |
|||
options: getDictOptions('contract_audit_rule_name'), |
|||
}, |
|||
}, |
|||
]; |
|||
|
|||
export const columns: BasicColumn[] = [ |
|||
{ |
|||
title: 'id', |
|||
dataIndex: 'id', |
|||
width: 50, |
|||
ifShow: false, |
|||
}, |
|||
{ |
|||
title: '审核类型', |
|||
dataIndex: 'requirementType', |
|||
}, |
|||
{ |
|||
title: '审核要素', |
|||
dataIndex: 'auditElement', |
|||
customRender: ({ value }) => renderDict(value, 'contract_audit_rule_name'), |
|||
|
|||
}, |
|||
{ |
|||
title: '规则描述', |
|||
dataIndex: 'requirementDescription', |
|||
}, |
|||
]; |
|||
|
|||
export const modalSchemas: FormSchema[] = [ |
|||
{ |
|||
label:"id", |
|||
field:"id", |
|||
component:"Input", |
|||
show:false, |
|||
}, |
|||
{ |
|||
label: '审核类型', |
|||
field:'requirementType', |
|||
component: 'Input', |
|||
required: true, |
|||
}, |
|||
{ |
|||
label: '审核要素', |
|||
field: 'auditElement', |
|||
required: true, |
|||
component: 'Select', |
|||
componentProps: { |
|||
options: getDictOptions('contract_audit_rule_name'), |
|||
}, |
|||
}, |
|||
{ |
|||
label: '规则配置', |
|||
field: 'config', |
|||
slot: 'configSlot', |
|||
}, |
|||
]; |
@ -0,0 +1,177 @@ |
|||
<template> |
|||
<BasicModal |
|||
v-bind="$attrs" |
|||
:title="title" |
|||
:width="1000" |
|||
:scrollTop="true" |
|||
@register="registerInnerModal" |
|||
@ok="handleSubmit" |
|||
@cancel="resetForm" |
|||
> |
|||
<BasicForm @register="registerForm"> |
|||
<template #configSlot="{model}"> |
|||
<component |
|||
:is="currentComponent(model.auditElement)" |
|||
:ref="setComponentRef" |
|||
/> |
|||
</template> |
|||
</BasicForm> |
|||
</BasicModal> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { BasicModal, useModalInner } from '@/components/Modal'; |
|||
import { BasicForm, useForm } from '@/components/Form'; |
|||
import { computed, ref, unref, shallowRef, nextTick } from 'vue'; |
|||
import { ContractualAuditConfigInfo, ContractualAuditConfigAdd, ContractualAuditConfigUpdate } from '@/api/contractReview/ContractualAuditConfig'; |
|||
import { modalSchemas } from './ContractualAuditConfig.data'; |
|||
import cpuOsDatebaseComponent from './components/cpuOsDatebaseComponent.vue'; |
|||
import entityTreeComponent from './components/entityTreeComponent.vue'; |
|||
import productAttributeComponent from './components/productAttributeComponent.vue'; |
|||
import contractualNormalComponent from './components/contractualNormalComponent.vue'; |
|||
|
|||
// 合并为一个通用组件接口 |
|||
interface ComponentInstance { |
|||
validate: () => boolean; |
|||
getData: () => any[]; |
|||
setData?: (data: any[]) => void; // 添加可选的 setData 方法 |
|||
} |
|||
|
|||
const emit = defineEmits(['register', 'reload']); |
|||
|
|||
const isUpdate = ref<boolean>(false); |
|||
const title = computed<string>(() => { |
|||
return isUpdate.value ? '编辑合同审核配置' : '新增合同审核配置'; |
|||
}); |
|||
|
|||
// 当前活动组件的引用 |
|||
const activeComponentRef = ref<ComponentInstance | null>(null); |
|||
|
|||
// 根据需求名称返回对应的组件 |
|||
const currentComponent = (auditElement: string) => { |
|||
if (auditElement === 'os' || auditElement === 'cpu' || auditElement === 'database') { |
|||
return cpuOsDatebaseComponent; |
|||
} else if (auditElement === 'entity') { |
|||
return entityTreeComponent; |
|||
} else if (auditElement === 'productAttribute') { |
|||
return productAttributeComponent; |
|||
} else if (auditElement === 'contractualNormal') { |
|||
return contractualNormalComponent; |
|||
} |
|||
return null; |
|||
}; |
|||
|
|||
// 设置组件引用 |
|||
const setComponentRef = (el: any) => { |
|||
if (el) { |
|||
activeComponentRef.value = el; |
|||
} |
|||
}; |
|||
|
|||
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 ContractualAuditConfigInfo(record.id); |
|||
await setFieldsValue(ret); |
|||
|
|||
// 等待表单值设置完成和组件渲染 |
|||
await nextTick(); |
|||
|
|||
// 根据 auditElement 加载对应的数据到组件中 |
|||
if (activeComponentRef.value?.setData) { |
|||
// 使用类型断言避免类型错误 |
|||
const retData = ret as any; |
|||
|
|||
if (retData.auditElement === 'os' || retData.auditElement === 'cpu' || retData.auditElement === 'database') { |
|||
// 加载 CPU/OS/数据库 数据 |
|||
if (retData.requirementCpuosdatabaseList) { |
|||
activeComponentRef.value.setData(retData.requirementCpuosdatabaseList); |
|||
} |
|||
} else if (retData.auditElement === 'entity') { |
|||
// 加载实体数据 |
|||
if (retData.requirementEntityList) { |
|||
activeComponentRef.value.setData(retData.requirementEntityList); |
|||
} |
|||
} else if (retData.auditElement === 'productAttribute') { |
|||
// 加载产品属性数据 |
|||
if (retData.requirementProductAttributeList) { |
|||
activeComponentRef.value.setData(retData.requirementProductAttributeList); |
|||
} |
|||
} else if (retData.auditElement === 'contractualNormal') { |
|||
// 加载普通合同数据 |
|||
if (retData.requirementContractualNormalList) { |
|||
activeComponentRef.value.setData(retData.requirementContractualNormalList); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
modalLoading(false); |
|||
}, |
|||
); |
|||
|
|||
const [registerForm, { setFieldsValue, resetForm, validate }] = useForm({ |
|||
labelWidth: 100, |
|||
showActionButtonGroup: false, |
|||
baseColProps: { span: 24 }, |
|||
schemas: modalSchemas, |
|||
}); |
|||
|
|||
async function handleSubmit() { |
|||
try { |
|||
modalLoading(true); |
|||
|
|||
// 验证当前活动组件 |
|||
if (activeComponentRef.value) { |
|||
const isValid = activeComponentRef.value.validate(); |
|||
if (!isValid) { |
|||
modalLoading(false); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
const data = await validate(); |
|||
if (data.requirementType) { |
|||
data.requirementType = data.requirementType.trim(); |
|||
} |
|||
|
|||
// 根据 auditElement 获取组件数据并赋值给对应属性 |
|||
if (activeComponentRef.value?.getData) { |
|||
const componentData = activeComponentRef.value.getData() |
|||
// .map(item => { |
|||
// const { id, ...rest } = item; |
|||
// return rest; |
|||
// }); |
|||
|
|||
// 使用类型断言避免类型错误 |
|||
const formData = data as any; |
|||
|
|||
if (formData.auditElement === 'os' || formData.auditElement === 'cpu' || formData.auditElement === 'database') { |
|||
formData.requirementCpuosdatabaseList = componentData; |
|||
} else if (formData.auditElement === 'entity') { |
|||
formData.requirementEntityList = componentData; |
|||
} else if (formData.auditElement === 'productAttribute') { |
|||
formData.requirementProductAttributeList = componentData; |
|||
} else if (formData.auditElement === 'contractualNormal') { |
|||
formData.requirementContractualNormalList = componentData; |
|||
} |
|||
} |
|||
|
|||
if (unref(isUpdate)) { |
|||
await ContractualAuditConfigUpdate(data); |
|||
} else { |
|||
await ContractualAuditConfigAdd(data); |
|||
} |
|||
emit('reload'); |
|||
closeModal(); |
|||
await resetForm(); |
|||
} catch (e) { |
|||
} finally { |
|||
modalLoading(false); |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped></style> |
@ -0,0 +1,148 @@ |
|||
<template> |
|||
<div> |
|||
<Table |
|||
:columns="columns" |
|||
:dataSource="dataSource" |
|||
:bordered="true" |
|||
:pagination="false" |
|||
:rowClassName="() => 'compact-row'" |
|||
> |
|||
<template #bodyCell="{ column, record, index }"> |
|||
<template v-if="column.dataIndex === 'checkItem'"> |
|||
<Form.Item |
|||
:validateStatus="!record.checkItem ? 'error' : ''" |
|||
:help="!record.checkItem ? '产品类型为必填项' : ''" |
|||
class="compact-form-item" |
|||
> |
|||
<Input v-model:value="record.checkItem" placeholder="请输入产品类型" /> |
|||
</Form.Item> |
|||
</template> |
|||
<template v-if="column.dataIndex === 'requirementDesc'"> |
|||
<Form.Item |
|||
:validateStatus="!record.requirementDesc ? 'error' : ''" |
|||
:help="!record.requirementDesc ? '要求为必填项' : ''" |
|||
class="compact-form-item" |
|||
> |
|||
<Textarea |
|||
v-model:value="record.requirementDesc" |
|||
placeholder="请输入要求" |
|||
:rows="2" |
|||
:auto-size="{ minRows: 2, maxRows: 6 }" |
|||
/> |
|||
</Form.Item> |
|||
</template> |
|||
<template v-if="column.key === 'operation'"> |
|||
<a-button type="link" @click="handleDelete(index)">删除</a-button> |
|||
</template> |
|||
</template> |
|||
</Table> |
|||
<Button type="primary" @click="handleAdd" style="margin-top: 16px">新增</Button> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { ref, defineExpose } from 'vue' |
|||
import { Table, Input, Button, Form, message,Textarea } from 'ant-design-vue' |
|||
|
|||
interface TableItem { |
|||
key: string |
|||
checkItem: string |
|||
requirementDesc: string |
|||
requirement: string |
|||
} |
|||
|
|||
const columns = [ |
|||
{ |
|||
title: '检查项(必填)', |
|||
dataIndex: 'checkItem', |
|||
key: 'checkItem', |
|||
width: '33%' |
|||
}, |
|||
{ |
|||
title: '要求描述(必填)', |
|||
dataIndex: 'requirementDesc', |
|||
key: 'requirementDesc', |
|||
width: '33%' |
|||
}, |
|||
{ |
|||
title: '操作', |
|||
key: 'operation', |
|||
width: 80, |
|||
}, |
|||
] |
|||
|
|||
const dataSource = ref<TableItem[]>([]) |
|||
|
|||
const validate = () => { |
|||
const emptyItems = dataSource.value.filter(item => !item.checkItem || !item.requirementDesc) |
|||
if (emptyItems.length > 0) { |
|||
message.error('请填写所有必填项') |
|||
return false |
|||
} |
|||
return true |
|||
} |
|||
|
|||
const handleAdd = () => { |
|||
for (const item of dataSource.value) { |
|||
if (!item.checkItem || !item.requirementDesc) { |
|||
message.error('请先填写已有行的必填项') |
|||
return |
|||
} |
|||
} |
|||
|
|||
dataSource.value.push({ |
|||
key: Date.now().toString(), |
|||
checkItem: '', |
|||
requirementDesc: '', |
|||
requirement: '' |
|||
}) |
|||
} |
|||
|
|||
const getData = () => { |
|||
return dataSource.value |
|||
} |
|||
|
|||
const setData = (data: TableItem[]) => { |
|||
if (!data || data.length === 0) { |
|||
dataSource.value = [] |
|||
return |
|||
} |
|||
|
|||
// 为每条数据添加key |
|||
const formattedData = data.map(item => ({ |
|||
...item, |
|||
key: item.key || Date.now().toString() |
|||
})) |
|||
|
|||
dataSource.value = formattedData |
|||
} |
|||
|
|||
const handleDelete = (index: number) => { |
|||
if (dataSource.value.length <= 1) { |
|||
message.warning('至少保留一行数据') |
|||
return |
|||
} |
|||
dataSource.value.splice(index, 1) |
|||
} |
|||
|
|||
defineExpose({ |
|||
getData, |
|||
validate, |
|||
setData |
|||
}) |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.compact-row :deep(.ant-form-item) { |
|||
margin-bottom: 0; |
|||
} |
|||
|
|||
.compact-form-item { |
|||
margin-bottom: 0 !important; |
|||
} |
|||
|
|||
|
|||
:deep(.ant-table-tbody > tr > td) { |
|||
padding: 8px; |
|||
} |
|||
</style> |
@ -0,0 +1,151 @@ |
|||
<template> |
|||
<div> |
|||
<Table |
|||
:columns="columns" |
|||
:dataSource="dataSource" |
|||
:bordered="true" |
|||
:pagination="false" |
|||
> |
|||
<template #bodyCell="{ column, record, index }"> |
|||
<template v-if="column.dataIndex === 'name'"> |
|||
<Form.Item |
|||
:validateStatus="!record.name ? 'error' : ''" |
|||
:help="!record.name ? '产品名称为必填项' : ''" |
|||
class="compact-form-item" |
|||
> |
|||
<Input v-model:value="record.name" placeholder="请输入名称" /> |
|||
</Form.Item> |
|||
</template> |
|||
<template v-if="column.dataIndex === 'model'"> |
|||
<Input v-model:value="record.model" placeholder="请输入型号" /> |
|||
</template> |
|||
<template v-if="column.dataIndex === 'versionStr'"> |
|||
<Input v-model:value="record.versionStr" placeholder="请输入版本" /> |
|||
</template> |
|||
<template v-if="column.key === 'operation'"> |
|||
<Button type="link" @click="handleDelete(index)">删除</Button> |
|||
</template> |
|||
</template> |
|||
</Table> |
|||
<Button type="primary" @click="handleAdd" style="margin-top: 16px">新增</Button> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { ref, defineExpose } from 'vue' |
|||
import { Table, Input, Button, Form } from 'ant-design-vue' |
|||
import { message } from 'ant-design-vue' |
|||
|
|||
interface TableItem { |
|||
key: string |
|||
name: string |
|||
model: string |
|||
versionStr: string |
|||
} |
|||
|
|||
const columns = [ |
|||
{ |
|||
title: '产品名称(必填)', |
|||
dataIndex: 'name', |
|||
key: 'name', |
|||
width: '33%', |
|||
rules: [{ required: true, message: '名称为必填项' }] |
|||
}, |
|||
{ |
|||
title: '型号', |
|||
dataIndex: 'model', |
|||
key: 'model', |
|||
width: '33%' |
|||
}, |
|||
{ |
|||
title: '版本', |
|||
dataIndex: 'versionStr', |
|||
key: 'versionStr', |
|||
width: '33%' |
|||
}, |
|||
{ |
|||
title: '操作', |
|||
key: 'operation', |
|||
width: 80, |
|||
}, |
|||
] |
|||
|
|||
const dataSource = ref<TableItem[]>([]) |
|||
|
|||
// 添加验证方法 |
|||
const validate = () => { |
|||
const emptyNameItems = dataSource.value.filter(item => !item.name); |
|||
if (emptyNameItems.length > 0) { |
|||
message.error('请填写所有行的名称'); |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
const handleAdd = () => { |
|||
// 检查已有数据是否都填写了必填项 |
|||
for (const item of dataSource.value) { |
|||
if (!item.name) { |
|||
message.error('请先填写已有行的名称') |
|||
return |
|||
} |
|||
} |
|||
|
|||
dataSource.value.push({ |
|||
key: Date.now().toString(), |
|||
name: '', |
|||
model: '', |
|||
versionStr: '' |
|||
}) |
|||
} |
|||
|
|||
const getData = () => { |
|||
return dataSource.value |
|||
} |
|||
|
|||
// 添加设置数据方法 |
|||
const setData = (data: TableItem[]) => { |
|||
if (!data || data.length === 0) { |
|||
dataSource.value = [] |
|||
return |
|||
} |
|||
|
|||
// 为每条数据添加key |
|||
const formattedData = data.map(item => ({ |
|||
...item, |
|||
key: item.key || Date.now().toString() |
|||
})) |
|||
|
|||
dataSource.value = formattedData |
|||
} |
|||
|
|||
// 删除行方法 |
|||
const handleDelete = (index: number) => { |
|||
if (dataSource.value.length <= 1) { |
|||
message.warning('至少保留一行数据'); |
|||
return; |
|||
} |
|||
dataSource.value.splice(index, 1); |
|||
} |
|||
|
|||
defineExpose({ |
|||
getData, |
|||
validate, |
|||
setData |
|||
}) |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.compact-row :deep(.ant-form-item) { |
|||
margin-bottom: 0; |
|||
} |
|||
|
|||
.compact-form-item { |
|||
margin-bottom: 0 !important; |
|||
} |
|||
|
|||
|
|||
:deep(.ant-table-tbody > tr > td) { |
|||
padding: 8px; |
|||
} |
|||
</style> |
@ -0,0 +1,459 @@ |
|||
<template> |
|||
<div> |
|||
<!-- 树形组件,支持选择和展开节点 --> |
|||
<Tree |
|||
v-model:selectedKeys="selectedKeys" |
|||
v-model:expandedKeys="expandedKeys" |
|||
:treeData="treeData" |
|||
:replaceFields="{ title: 'entityName', key: 'id' }" <!-- 映射字段名称 --> |
|||
:autoExpandParent="autoExpandParent" |
|||
> |
|||
<!-- 自定义节点标题渲染 --> |
|||
<template #title="{ entityName, id }"> |
|||
<div class="tree-node"> |
|||
<!-- 编辑状态显示输入框 --> |
|||
<div v-if="editingId == id" class="inline-edit"> |
|||
<Input |
|||
v-model:value="editingName" |
|||
placeholder="请输入主体名称" |
|||
@pressEnter="saveEdit" |
|||
@blur="saveEdit" |
|||
ref="editInputRef" |
|||
/> |
|||
</div> |
|||
<!-- 非编辑状态显示节点名称,支持双击编辑 --> |
|||
<span v-else @dblclick.stop="handleEdit(id, entityName)">{{ entityName }}</span> |
|||
|
|||
<!-- 非根节点的操作按钮 --> |
|||
<div class="operation-btns" v-if="id !== rootId"> |
|||
<Button type="link" @click.stop="handleAdd(id)">新增</Button> |
|||
<Button type="link" @click.stop="handleEdit(id, entityName)">编辑</Button> |
|||
<Button type="link" danger @click.stop="handleDelete(id)">删除</Button> |
|||
</div> |
|||
<!-- 根节点只显示新增按钮 --> |
|||
<div class="operation-btns" v-else> |
|||
<Button type="link" @click.stop="handleAdd(id)">新增</Button> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
</Tree> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { ref, defineExpose, nextTick, onMounted, watch } from 'vue'; |
|||
import { Tree, Button, Input, message } from 'ant-design-vue'; |
|||
import type { TreeDataItem, DataNode } from 'ant-design-vue/es/tree'; |
|||
|
|||
// 定义节点数据结构 |
|||
interface EntityItem { |
|||
id: string; // 节点唯一标识 |
|||
entityName: string; // 节点名称 |
|||
parentId: string; // 父节点ID |
|||
level: number; // 节点层级 |
|||
path: string; // 节点路径,用于快速查找祖先节点 |
|||
children?: EntityItem[]; // 子节点列表 |
|||
key: string; // 兼容Tree组件的key属性,必须有值 |
|||
title?: string; // 兼容Tree组件的title属性 |
|||
} |
|||
|
|||
// 根节点ID为1 |
|||
const rootId = '1'; |
|||
const selectedKeys = ref<string[]>([]); // 当前选中的节点 |
|||
const expandedKeys = ref<string[]>([rootId]); // 当前展开的节点,默认展开根节点 |
|||
const autoExpandParent = ref<boolean>(true); // 是否自动展开父节点 |
|||
const treeData = ref<EntityItem[]>([]); // 树形数据 |
|||
const editingId = ref<string>(''); // 当前正在编辑的节点ID |
|||
const editingName = ref<string>(''); // 当前正在编辑的节点名称 |
|||
const editInputRef = ref(null); // 编辑输入框的引用 |
|||
// 用于生成递增的ID |
|||
const nextId = ref<number>(2); // 从2开始,因为1已经给了根节点 |
|||
|
|||
// 监听expandedKeys变化,当手动展开/收起节点时,关闭自动展开父节点 |
|||
watch(expandedKeys, () => { |
|||
autoExpandParent.value = false; |
|||
}); |
|||
|
|||
// 组件挂载时初始化根节点 |
|||
onMounted(() => { |
|||
initRootNode(); |
|||
}); |
|||
|
|||
/** |
|||
* 初始化根节点 |
|||
* 如果树为空,创建一个"所有单位"的根节点 |
|||
*/ |
|||
const initRootNode = () => { |
|||
// 检查是否已有根节点 |
|||
if (treeData.value.length == 0) { |
|||
const rootNode: EntityItem = { |
|||
id: rootId, |
|||
entityName: '所有单位', |
|||
parentId: '0', // 根节点的父ID为0 |
|||
level: 1, |
|||
path: '0', |
|||
key: rootId, // 确保有key属性 |
|||
children: [] |
|||
}; |
|||
treeData.value.push(rootNode); |
|||
} |
|||
}; |
|||
|
|||
/** |
|||
* 生成新的节点ID |
|||
* 返回递增的数字字符串 |
|||
*/ |
|||
const generateId = (): string => { |
|||
const id = nextId.value.toString(); |
|||
nextId.value++; |
|||
return id; |
|||
}; |
|||
|
|||
/** |
|||
* 将树形数据转换为扁平列表 |
|||
* 用于提交数据到服务器 |
|||
*/ |
|||
const convertToList = (tree: EntityItem[]): EntityItem[] => { |
|||
const list: EntityItem[] = []; |
|||
const traverse = (nodes: EntityItem[]) => { |
|||
nodes.forEach(node => { |
|||
const { children, ...rest } = node; |
|||
list.push(rest); // 添加节点(不包含children) |
|||
if (children) { |
|||
traverse(children); // 递归处理子节点 |
|||
} |
|||
}); |
|||
}; |
|||
traverse(tree); |
|||
console.log(list); |
|||
|
|||
return list; |
|||
}; |
|||
|
|||
/** |
|||
* 将扁平列表转换为树形结构 |
|||
* 用于从服务器接收数据并显示 |
|||
*/ |
|||
const convertToTree = (list: EntityItem[]): EntityItem[] => { |
|||
// 找出最大的ID,更新nextId |
|||
const maxId = Math.max(...list.map(item => parseInt(item.id)), 1); |
|||
nextId.value = maxId + 1; |
|||
|
|||
// 创建节点映射,方便快速查找 |
|||
const nodeMap = new Map<string, EntityItem>(); |
|||
list.forEach(item => { |
|||
// 确保每个节点都有key属性 |
|||
nodeMap.set(item.id, { |
|||
...item, |
|||
key: item.id, // 确保有key属性 |
|||
children: [] |
|||
}); |
|||
}); |
|||
|
|||
// 构建树结构 |
|||
const tree: EntityItem[] = []; |
|||
|
|||
// 先清空所有节点的children |
|||
nodeMap.forEach(node => { |
|||
node.children = []; |
|||
}); |
|||
|
|||
// 构建父子关系 |
|||
nodeMap.forEach(node => { |
|||
if (node.parentId == '0' || !nodeMap.has(node.parentId)) { |
|||
// 根节点或父节点不存在的节点直接添加到树中 |
|||
tree.push(node); |
|||
} else { |
|||
// 将节点添加到父节点的children中 |
|||
const parentNode = nodeMap.get(node.parentId); |
|||
if (parentNode) { |
|||
parentNode.children!.push(node); |
|||
} |
|||
} |
|||
}); |
|||
|
|||
return tree; |
|||
}; |
|||
|
|||
/** |
|||
* 获取数据列表 |
|||
* 将当前树形结构转换为扁平列表返回 |
|||
*/ |
|||
const getData = () => { |
|||
return convertToList(treeData.value); |
|||
}; |
|||
|
|||
/** |
|||
* 设置数据 |
|||
* 接收外部数据并转换为树形结构显示 |
|||
*/ |
|||
const setData = (data: EntityItem[]) => { |
|||
if (!data || data.length == 0) { |
|||
initRootNode(); |
|||
return; |
|||
} |
|||
|
|||
// 确保每个节点都有key属性 |
|||
const processedData = data.map(item => ({ |
|||
...item, |
|||
key: item.id // 确保有key属性 |
|||
})); |
|||
|
|||
// 检查是否有根节点 |
|||
const hasRoot = processedData.some(item => item.id == rootId); |
|||
|
|||
if (!hasRoot) { |
|||
// 如果没有根节点,添加一个 |
|||
processedData.push({ |
|||
id: rootId, |
|||
entityName: '所有单位', |
|||
parentId: '0', |
|||
level: 1, |
|||
path: '0', |
|||
key: rootId // 确保有key属性 |
|||
}); |
|||
} |
|||
|
|||
// 转换为树形结构 |
|||
const tree = convertToTree(processedData); |
|||
treeData.value = tree; |
|||
|
|||
// 展开根节点 |
|||
expandedKeys.value = [rootId]; |
|||
autoExpandParent.value = true; |
|||
}; |
|||
|
|||
/** |
|||
* 处理添加节点 |
|||
* @param parentId 父节点ID |
|||
*/ |
|||
const handleAdd = (parentId: string) => { |
|||
// 查找父节点 |
|||
const parentNode = findNodeById(treeData.value, parentId); |
|||
if (!parentNode) return; |
|||
|
|||
// 检查父节点名称是否为空(根节点除外) |
|||
if (parentId !== rootId && (!parentNode.entityName || parentNode.entityName.trim() == '')) { |
|||
message.error('请先完成当前节点的编辑再添加子节点'); |
|||
return; |
|||
} |
|||
|
|||
// 检查是否有未完成编辑的节点 |
|||
const allNodes = convertToList(treeData.value); |
|||
const emptyNameNode = allNodes.find(node => |
|||
node.id !== rootId && (!node.entityName || node.entityName.trim() == '') |
|||
); |
|||
|
|||
if (emptyNameNode) { |
|||
message.error('存在未完成编辑的节点,请先完成编辑'); |
|||
return; |
|||
} |
|||
|
|||
// 创建新节点 |
|||
const newId = generateId(); |
|||
const newNode: EntityItem = { |
|||
id: newId, |
|||
entityName: '', // 默认为空 |
|||
parentId: parentId, |
|||
level: parentNode.level + 1, |
|||
path: parentNode.path + ',' + parentId, |
|||
key: newId // 确保有key属性 |
|||
}; |
|||
|
|||
// 添加到父节点的children中 |
|||
if (!parentNode.children) parentNode.children = []; |
|||
parentNode.children.push(newNode); |
|||
|
|||
// 确保父节点展开 |
|||
if (!expandedKeys.value.includes(parentId)) { |
|||
expandedKeys.value = [...expandedKeys.value, parentId]; |
|||
autoExpandParent.value = true; |
|||
} |
|||
|
|||
// 使用setTimeout延迟进入编辑模式,避免事件冲突 |
|||
setTimeout(() => { |
|||
handleEdit(newNode.id, newNode.entityName); |
|||
}, 100); |
|||
}; |
|||
|
|||
/** |
|||
* 处理编辑节点 |
|||
* @param id 节点ID |
|||
* @param name 节点名称 |
|||
*/ |
|||
const handleEdit = (id: string, name: string) => { |
|||
// 不允许编辑根节点 |
|||
if (id == rootId) return; |
|||
|
|||
// 设置编辑状态 |
|||
editingId.value = id; |
|||
editingName.value = name; |
|||
|
|||
// 确保节点可见(展开所有父节点) |
|||
const node = findNodeById(treeData.value, id); |
|||
if (node) { |
|||
const pathArray = node.path.split(','); |
|||
expandedKeys.value = Array.from(new Set([...expandedKeys.value, ...pathArray])); |
|||
autoExpandParent.value = true; |
|||
} |
|||
|
|||
// 聚焦到输入框 |
|||
nextTick(() => { |
|||
if (editInputRef.value) { |
|||
(editInputRef.value as any).focus(); |
|||
} |
|||
}); |
|||
}; |
|||
|
|||
/** |
|||
* 保存编辑内容 |
|||
*/ |
|||
const saveEdit = () => { |
|||
// 防止重复保存 |
|||
if (editingId.value == '') { |
|||
return; |
|||
} |
|||
|
|||
// 验证输入内容 |
|||
const trimmedName = editingName.value.trim(); |
|||
if (!trimmedName) { |
|||
message.error('主体名称不能为空'); |
|||
return; |
|||
} |
|||
|
|||
// 更新节点数据,保存时去除前后空格 |
|||
updateNode(treeData.value, editingId.value, { entityName: trimmedName }); |
|||
// 清除编辑状态 |
|||
editingId.value = ''; |
|||
}; |
|||
|
|||
/** |
|||
* 处理删除节点 |
|||
* @param id 节点ID |
|||
*/ |
|||
const handleDelete = async (id: string) => { |
|||
// 不允许删除根节点 |
|||
if (id == rootId) return; |
|||
|
|||
// 检查是否有子节点 |
|||
const node = findNodeById(treeData.value, id); |
|||
if (node && node.children && node.children.length > 0) { |
|||
message.error('该节点包含子节点,不能删除'); |
|||
return; |
|||
} |
|||
|
|||
// 删除节点 |
|||
removeNode(treeData.value, id); |
|||
}; |
|||
|
|||
/** |
|||
* 根据ID查找节点 |
|||
* @param nodes 节点列表 |
|||
* @param id 节点ID |
|||
* @returns 找到的节点或null |
|||
*/ |
|||
const findNodeById = (nodes: EntityItem[], id: string): EntityItem | null => { |
|||
for (const node of nodes) { |
|||
if (node.id == id) return node; |
|||
if (node.children) { |
|||
const found = findNodeById(node.children, id); |
|||
if (found) return found; |
|||
} |
|||
} |
|||
return null; |
|||
}; |
|||
|
|||
/** |
|||
* 更新节点数据 |
|||
* @param nodes 节点列表 |
|||
* @param id 要更新的节点ID |
|||
* @param updatedData 更新的数据 |
|||
*/ |
|||
const updateNode = (nodes: EntityItem[], id: string, updatedData: Partial<EntityItem>) => { |
|||
for (const node of nodes) { |
|||
if (node.id == id) { |
|||
Object.assign(node, updatedData); |
|||
return; |
|||
} |
|||
if (node.children) { |
|||
updateNode(node.children, id, updatedData); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
/** |
|||
* 删除节点 |
|||
* @param nodes 节点列表 |
|||
* @param id 要删除的节点ID |
|||
*/ |
|||
const removeNode = (nodes: EntityItem[], id: string) => { |
|||
for (let i = 0; i < nodes.length; i++) { |
|||
if (nodes[i].id == id) { |
|||
nodes.splice(i, 1); |
|||
return; |
|||
} |
|||
if (nodes[i].children) { |
|||
removeNode(nodes[i].children!, id); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
/** |
|||
* 验证数据有效性 |
|||
* 检查是否有节点,以及是否有空名称的节点 |
|||
*/ |
|||
const validate = () => { |
|||
// 检查是否有除根节点外的其他节点 |
|||
const rootNode = findNodeById(treeData.value, rootId); |
|||
if (!rootNode || !rootNode.children || rootNode.children.length == 0) { |
|||
message.error('请至少添加一个主体'); |
|||
return false; |
|||
} |
|||
|
|||
// 检查是否有空名称的节点 |
|||
const allNodes = convertToList(treeData.value); |
|||
const emptyNameNode = allNodes.find(node => |
|||
node.id !== rootId && (!node.entityName || node.entityName.trim() == '') |
|||
); |
|||
|
|||
if (emptyNameNode) { |
|||
message.error('存在未完成编辑的节点,请完成所有节点的编辑'); |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
}; |
|||
|
|||
// 暴露组件方法供父组件调用 |
|||
defineExpose({ |
|||
getData, // 获取数据 |
|||
validate, // 验证数据 |
|||
setData // 设置数据 |
|||
}); |
|||
</script> |
|||
|
|||
<style scoped> |
|||
/* 节点样式 */ |
|||
.tree-node { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding-right: 8px; |
|||
} |
|||
|
|||
/* 编辑输入框样式 */ |
|||
.inline-edit { |
|||
min-width: 150px; |
|||
margin-right: 8px; |
|||
} |
|||
|
|||
/* 操作按钮样式,默认隐藏 */ |
|||
.operation-btns { |
|||
display: none; |
|||
} |
|||
|
|||
/* 鼠标悬停时显示操作按钮 */ |
|||
.tree-node:hover .operation-btns { |
|||
display: block; |
|||
} |
|||
</style> |
@ -0,0 +1,163 @@ |
|||
<template> |
|||
<div> |
|||
<Table |
|||
:columns="columns" |
|||
:dataSource="dataSource" |
|||
:bordered="true" |
|||
:pagination="false" |
|||
:rowClassName="() => 'compact-row'" |
|||
> |
|||
<template #bodyCell="{ column, record, index }"> |
|||
<template v-if="column.dataIndex === 'productType'"> |
|||
<Form.Item |
|||
:validateStatus="!record.productType ? 'error' : ''" |
|||
:help="!record.productType ? '产品类型为必填项' : ''" |
|||
class="compact-form-item" |
|||
> |
|||
<Input v-model:value="record.productType" placeholder="请输入产品类型" /> |
|||
</Form.Item> |
|||
</template> |
|||
<template v-if="column.dataIndex === 'attributeName'"> |
|||
<Form.Item |
|||
:validateStatus="!record.attributeName ? 'error' : ''" |
|||
:help="!record.attributeName ? '属性名称为必填项' : ''" |
|||
class="compact-form-item" |
|||
> |
|||
<Input v-model:value="record.attributeName" placeholder="请输入属性名称" /> |
|||
</Form.Item> |
|||
</template> |
|||
<template v-if="column.dataIndex === 'requirement'"> |
|||
<Form.Item |
|||
:validateStatus="!record.requirement ? 'error' : ''" |
|||
:help="!record.requirement ? '要求为必填项' : ''" |
|||
class="compact-form-item" |
|||
> |
|||
<Textarea |
|||
v-model:value="record.requirement" |
|||
placeholder="请输入要求" |
|||
:rows="2" |
|||
:auto-size="{ minRows: 2, maxRows: 6 }" |
|||
/> |
|||
</Form.Item> |
|||
</template> |
|||
<template v-if="column.key === 'operation'"> |
|||
<Button type="link" @click="handleDelete(index)">删除</Button> |
|||
</template> |
|||
</template> |
|||
</Table> |
|||
<Button type="primary" @click="handleAdd" style="margin-top: 16px">新增</Button> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { ref, defineExpose } from 'vue' |
|||
import { Table, Input, Button, Form, message,Textarea } from 'ant-design-vue' |
|||
|
|||
interface TableItem { |
|||
key: string |
|||
productType: string |
|||
attributeName: string |
|||
requirement: string |
|||
} |
|||
|
|||
const columns = [ |
|||
{ |
|||
title: '产品类型(必填)', |
|||
dataIndex: 'productType', |
|||
key: 'productType', |
|||
width: '33%' |
|||
}, |
|||
{ |
|||
title: '属性名称(必填)', |
|||
dataIndex: 'attributeName', |
|||
key: 'attributeName', |
|||
width: '33%' |
|||
}, |
|||
{ |
|||
title: '要求(必填)', |
|||
dataIndex: 'requirement', |
|||
key: 'requirement', |
|||
width: '33%' |
|||
}, |
|||
{ |
|||
title: '操作', |
|||
key: 'operation', |
|||
width: 80, |
|||
}, |
|||
] |
|||
|
|||
const dataSource = ref<TableItem[]>([]) |
|||
|
|||
const validate = () => { |
|||
const emptyItems = dataSource.value.filter(item => !item.productType || !item.attributeName || !item.requirement) |
|||
if (emptyItems.length > 0) { |
|||
message.error('请填写所有必填项') |
|||
return false |
|||
} |
|||
return true |
|||
} |
|||
|
|||
const handleAdd = () => { |
|||
for (const item of dataSource.value) { |
|||
if (!item.productType || !item.attributeName || !item.requirement) { |
|||
message.error('请先填写已有行的必填项') |
|||
return |
|||
} |
|||
} |
|||
|
|||
dataSource.value.push({ |
|||
key: Date.now().toString(), |
|||
productType: '', |
|||
attributeName: '', |
|||
requirement: '' |
|||
}) |
|||
} |
|||
|
|||
const handleDelete = (index: number) => { |
|||
if (dataSource.value.length <= 1) { |
|||
message.warning('至少保留一行数据'); |
|||
return; |
|||
} |
|||
dataSource.value.splice(index, 1); |
|||
} |
|||
|
|||
const getData = () => { |
|||
return dataSource.value |
|||
} |
|||
|
|||
const setData = (data: TableItem[]) => { |
|||
if (!data || data.length === 0) { |
|||
dataSource.value = [] |
|||
return |
|||
} |
|||
|
|||
// 为每条数据添加key |
|||
const formattedData = data.map(item => ({ |
|||
...item, |
|||
key: item.key || Date.now().toString() |
|||
})) |
|||
|
|||
dataSource.value = formattedData |
|||
} |
|||
|
|||
defineExpose({ |
|||
getData, |
|||
validate, |
|||
setData |
|||
}) |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.compact-row :deep(.ant-form-item) { |
|||
margin-bottom: 0; |
|||
} |
|||
|
|||
.compact-form-item { |
|||
margin-bottom: 0 !important; |
|||
} |
|||
|
|||
|
|||
:deep(.ant-table-tbody > tr > td) { |
|||
padding: 8px; |
|||
} |
|||
</style> |
@ -0,0 +1,115 @@ |
|||
<template> |
|||
<PageWrapper dense> |
|||
<BasicTable @register="registerTable"> |
|||
<template #toolbar> |
|||
<a-button |
|||
@click="downloadExcel(ContractualAuditConfigExport, '合同审核配置数据', getForm().getFieldsValue())" |
|||
v-auth="'productManagement:ContractualAuditConfig:export'" |
|||
>导出</a-button |
|||
> |
|||
<a-button |
|||
type="primary" |
|||
danger |
|||
@click="multipleRemove(ContractualAuditConfigRemove)" |
|||
:disabled="!selected" |
|||
v-auth="'productManagement:ContractualAuditConfig:remove'" |
|||
>删除</a-button |
|||
> |
|||
<a-button |
|||
type="primary" |
|||
@click="handleAdd" |
|||
v-auth="'productManagement:ContractualAuditConfig: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:ContractualAuditConfig:edit', |
|||
onClick: handleEdit.bind(null, record), |
|||
}, |
|||
{ |
|||
label: '删除', |
|||
icon: IconEnum.DELETE, |
|||
type: 'primary', |
|||
danger: true, |
|||
ghost: true, |
|||
auth: 'productManagement:ContractualAuditConfig:remove', |
|||
popConfirm: { |
|||
placement: 'left', |
|||
title: '是否删除合同审核配置[' + record.id + ']?', |
|||
confirm: handleDelete.bind(null, record), |
|||
}, |
|||
}, |
|||
]" |
|||
/> |
|||
</template> |
|||
</template> |
|||
</BasicTable> |
|||
<ContractualAuditConfigModal @register="registerModal" @reload="reload" /> |
|||
</PageWrapper> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { PageWrapper } from '@/components/Page'; |
|||
import { BasicTable, useTable, TableAction } from '@/components/Table'; |
|||
import { ContractualAuditConfigList, ContractualAuditConfigExport, ContractualAuditConfigRemove } from '@/api/contractReview/ContractualAuditConfig'; |
|||
import { downloadExcel } from '@/utils/file/download'; |
|||
import { useModal } from '@/components/Modal'; |
|||
import ContractualAuditConfigModal from './ContractualAuditConfigModal.vue'; |
|||
import { formSchemas, columns } from './ContractualAuditConfig.data'; |
|||
import { IconEnum } from '@/enums/appEnum'; |
|||
|
|||
defineOptions({ name: 'ContractualAuditConfig' }); |
|||
|
|||
const [registerTable, { reload, multipleRemove, selected, getForm }] = useTable({ |
|||
rowSelection: { |
|||
type: 'checkbox', |
|||
}, |
|||
title: '合同审核配置列表', |
|||
api: ContractualAuditConfigList, |
|||
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 ContractualAuditConfigRemove([record.id]); |
|||
await reload(); |
|||
} |
|||
</script> |
|||
|
|||
<style scoped></style> |
@ -0,0 +1,156 @@ |
|||
import { BasicColumn } from '@/components/Table'; |
|||
import { FormSchema } from '@/components/Form'; |
|||
export const formSchemas: FormSchema[] = [ |
|||
{ |
|||
label: '文件名称', |
|||
field: 'fileName', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '品牌', |
|||
field: 'brand', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '型号(版本号)', |
|||
field: 'versionStr', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '单价', |
|||
field: 'unitPrice', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '价格单位', |
|||
field: 'priceUnit', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '数量', |
|||
field: 'quantity', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '总价', |
|||
field: 'totalPrice', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '类型', |
|||
field: 'type', |
|||
component: 'Input', |
|||
}, |
|||
]; |
|||
|
|||
export const columns: BasicColumn[] = [ |
|||
{ |
|||
title: '主键ID', |
|||
dataIndex: 'id', |
|||
ifShow: false, |
|||
}, |
|||
{ |
|||
title: '任务ID', |
|||
dataIndex: 'taskId', |
|||
ifShow: false, |
|||
}, |
|||
{ |
|||
title: '文件名称', |
|||
dataIndex: 'fileName', |
|||
}, |
|||
{ |
|||
title: '品牌', |
|||
dataIndex: 'brand', |
|||
}, |
|||
{ |
|||
title: '类型', |
|||
dataIndex: 'type', |
|||
}, |
|||
{ |
|||
title: '型号(版本号)', |
|||
dataIndex: 'versionStr', |
|||
}, |
|||
{ |
|||
title: '单价', |
|||
dataIndex: 'unitPrice', |
|||
}, |
|||
{ |
|||
title: '价格单位', |
|||
dataIndex: 'priceUnit', |
|||
}, |
|||
{ |
|||
title: '数量', |
|||
dataIndex: 'quantity', |
|||
}, |
|||
{ |
|||
title: '总价', |
|||
dataIndex: 'totalPrice', |
|||
}, |
|||
|
|||
]; |
|||
|
|||
export const modalSchemas: FormSchema[] = [ |
|||
{ |
|||
label: '主键ID', |
|||
field: 'id', |
|||
required: false, |
|||
component: 'Input', |
|||
show: false, |
|||
}, |
|||
{ |
|||
label: '任务ID', |
|||
field: 'taskId', |
|||
required: false, |
|||
component: 'Input', |
|||
show: false, |
|||
}, |
|||
{ |
|||
label: '文件名称', |
|||
field: 'fileName', |
|||
required: false, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '品牌', |
|||
field: 'brand', |
|||
required: false, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '型号(版本号)', |
|||
field: 'versionStr', |
|||
required: false, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '类型', |
|||
field: 'type', |
|||
required: false, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '单价', |
|||
field: 'unitPrice', |
|||
required: false, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '价格单位', |
|||
field: 'priceUnit', |
|||
required: false, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '数量', |
|||
field: 'quantity', |
|||
required: false, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '总价', |
|||
field: 'totalPrice', |
|||
required: false, |
|||
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 { ContractualProductInfoInfo, ContractualProductInfoAdd, ContractualProductInfoUpdate } from '@/api/contractReview/ContractualProductInfo'; |
|||
import { modalSchemas } from './ContractualProductInfo.data'; |
|||
|
|||
defineOptions({ name: 'ContractualProductInfoModal' }); |
|||
|
|||
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 ContractualProductInfoInfo(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 ContractualProductInfoUpdate(data); |
|||
} else { |
|||
await ContractualProductInfoAdd(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(ContractualProductInfoExport, '合同产品信息数据', getForm().getFieldsValue())" |
|||
v-auth="'productManagement:ContractualProductInfo:export'" |
|||
>导出</a-button |
|||
> |
|||
<a-button |
|||
type="primary" |
|||
danger |
|||
@click="multipleRemove(ContractualProductInfoRemove)" |
|||
:disabled="!selected" |
|||
v-auth="'productManagement:ContractualProductInfo:remove'" |
|||
>删除</a-button |
|||
> |
|||
<a-button |
|||
type="primary" |
|||
@click="handleAdd" |
|||
v-auth="'productManagement:ContractualProductInfo: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:ContractualProductInfo:edit', |
|||
onClick: handleEdit.bind(null, record), |
|||
}, |
|||
{ |
|||
label: '删除', |
|||
icon: IconEnum.DELETE, |
|||
type: 'primary', |
|||
danger: true, |
|||
ghost: true, |
|||
auth: 'productManagement:ContractualProductInfo:remove', |
|||
popConfirm: { |
|||
placement: 'left', |
|||
title: '是否删除合同产品信息[' + record.id + ']?', |
|||
confirm: handleDelete.bind(null, record), |
|||
}, |
|||
}, |
|||
]" |
|||
/> |
|||
</template> |
|||
</template> |
|||
</BasicTable> |
|||
<ContractualProductInfoModal @register="registerModal" @reload="reload" /> |
|||
</PageWrapper> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { PageWrapper } from '@/components/Page'; |
|||
import { BasicTable, useTable, TableAction } from '@/components/Table'; |
|||
import { ContractualProductInfoList, ContractualProductInfoExport, ContractualProductInfoRemove } from '@/api/contractReview/ContractualProductInfo'; |
|||
import { downloadExcel } from '@/utils/file/download'; |
|||
import { useModal } from '@/components/Modal'; |
|||
import ContractualProductInfoModal from './ContractualProductInfoModal.vue'; |
|||
import { formSchemas, columns } from './ContractualProductInfo.data'; |
|||
import { IconEnum } from '@/enums/appEnum'; |
|||
|
|||
defineOptions({ name: 'ContractualProductInfo' }); |
|||
|
|||
const [registerTable, { reload, multipleRemove, selected, getForm }] = useTable({ |
|||
rowSelection: { |
|||
type: 'checkbox', |
|||
}, |
|||
title: '合同产品信息列表', |
|||
api: ContractualProductInfoList, |
|||
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 ContractualProductInfoRemove([record.id]); |
|||
await reload(); |
|||
} |
|||
</script> |
|||
|
|||
<style scoped></style> |
@ -0,0 +1,458 @@ |
|||
<template> |
|||
<BasicModal |
|||
v-bind="$attrs" |
|||
title="title" |
|||
:canFullscreen="true" |
|||
:defaultFullscreen="true" |
|||
@ok="submit" |
|||
@register="registerInnerModal" |
|||
> |
|||
<div class="modal-content"> |
|||
<div class="grid grid-cols-6 gap-4 h-full"> |
|||
<div class="col-span-2 pdf-container"> |
|||
<div class="pdf-container"> |
|||
<vue-office-docx :src="pdfUrl" /> |
|||
</div> |
|||
</div> |
|||
<div class="col-span-2 contract-text-container"> |
|||
<div class="contract-text-header"> |
|||
<h3>合同文本内容</h3> |
|||
</div> |
|||
<div class="contract-text-content"> |
|||
<div class="contract-text-scroll"> |
|||
<pre>{{ contractText }}</pre> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-span-2 review-container"> |
|||
<div class="review-content"> |
|||
<showResultCard v-model:cardList="cardList" /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</BasicModal> |
|||
</template> |
|||
<script lang="ts" setup> |
|||
import { ref, onMounted, reactive, h, nextTick } from 'vue'; |
|||
import { BasicModal, useModalInner } from '@/components/Modal'; |
|||
import VueOfficeDocx from '@vue-office/pdf'; |
|||
|
|||
import { Tabs, TabPane, Card, Modal } from 'ant-design-vue'; |
|||
import { useRouter } from 'vue-router'; |
|||
import CanvasEditor from '@/views/CanvasEditor/index.vue'; |
|||
import { getContractualResultById,getContractulContent } from '@/api/contractReview/JyjcontractualTaskBatch'; |
|||
import { modifyContractReview } from '@/api/documentReview/DocumentTaskResults'; |
|||
import { getPdfFile } from '@/api/contractReview/JyjcontractualTaskBatch'; |
|||
import showResultCard from './showResultCard.vue'; |
|||
import { cloneDeep } from 'lodash-es'; |
|||
const emit = defineEmits(['register', 'reload']); |
|||
const pdfUrl = ref<string>(''); |
|||
const currentId = ref<any>(0); |
|||
const pdfViewerkey = ref(0); |
|||
const scale = ref(1.5); // 初始缩放比例 |
|||
|
|||
// 卡片数据 |
|||
const cardList = ref<any>([]); |
|||
const selectedCard = ref(''); // 用于存储当前选中的卡片标题 |
|||
const handleCardClick = (title) => { |
|||
selectedCard.value = title; |
|||
console.log('点击的卡片标题:', title); |
|||
}; |
|||
|
|||
// 用于存储初始数据,以便比较 |
|||
const initialCardList = ref<any[]>([]); |
|||
|
|||
// 新增合同文本内容变量 |
|||
const contractText = ref<string>(''); |
|||
|
|||
const [registerInnerModal, { modalLoading, closeModal }] = useModalInner( |
|||
async (data: { record?: Recordable }) => { |
|||
modalLoading(true); |
|||
cardList.value = []; |
|||
const { record } = data; |
|||
const res = await getContractualResultById(record.id); |
|||
|
|||
// 获取合同文本内容 |
|||
try { |
|||
const contentRes = await getContractulContent(record.id); |
|||
contractText.value = contentRes || '无法获取合同文本内容'; |
|||
} catch (error) { |
|||
console.error('获取合同文本内容失败:', error); |
|||
contractText.value = '获取合同文本内容失败'; |
|||
} |
|||
|
|||
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, |
|||
}); |
|||
} |
|||
} |
|||
const response = await getPdfFile(record.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); |
|||
}); |
|||
} |
|||
// 保存初始数据的深拷贝 |
|||
initialCardList.value = cloneDeep(cardList.value); |
|||
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 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% 的容器宽度 |
|||
} |
|||
} |
|||
}; |
|||
// 模拟后端获取数据的方法 |
|||
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); |
|||
|
|||
// 提交方法 |
|||
const submit = async () => { |
|||
// 比较当前数据和初始数据的差异 |
|||
const initialLength = initialCardList.value.length; |
|||
const currentLength = cardList.value.length; |
|||
|
|||
// 检查内容是否有变化 |
|||
const hasContentChanged = |
|||
JSON.stringify(initialCardList.value) !== JSON.stringify(cardList.value); |
|||
|
|||
if (!hasContentChanged) { |
|||
// 内容没有变化,直接关闭 |
|||
closeModal(); |
|||
return; |
|||
} |
|||
|
|||
// 从有到无 |
|||
if (initialLength > 0 && currentLength === 0) { |
|||
Modal.confirm({ |
|||
title: '确认提交', |
|||
content: h('div', [ |
|||
'当前合同已无异常点, 状态将变为', |
|||
h('span', { style: { color: '#52c41a', fontWeight: 'bold' } }, '审核通过'), |
|||
',是否确认?', |
|||
]), |
|||
okText: '确认', |
|||
cancelText: '取消', |
|||
async onOk() { |
|||
await handleSubmit(); |
|||
}, |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
// 从无到有 |
|||
if (initialLength === 0 && currentLength > 0) { |
|||
Modal.confirm({ |
|||
title: '确认提交', |
|||
content: h('div', [ |
|||
'当前合同新增异常点, 状态将变为', |
|||
h('span', { style: { color: '#ff4d4f', fontWeight: 'bold' } }, '审核不合格'), |
|||
',是否确认?', |
|||
]), |
|||
okText: '确认', |
|||
cancelText: '取消', |
|||
async onOk() { |
|||
await handleSubmit(); |
|||
}, |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
// 内容有修改 |
|||
Modal.confirm({ |
|||
title: '确认提交', |
|||
content: '内容已修改,是否提交?', |
|||
okText: '确认', |
|||
cancelText: '取消', |
|||
async onOk() { |
|||
await handleSubmit(); |
|||
}, |
|||
}); |
|||
}; |
|||
|
|||
// 实际的提交处理 |
|||
const handleSubmit = async () => { |
|||
try { |
|||
console.log('原始数据', cardList.value); |
|||
|
|||
// 封装数据结构 |
|||
const submitData = { |
|||
results: [ |
|||
{ |
|||
title: '人工干预', // 固定值 |
|||
contentList: cardList.value.map((card) => ({ |
|||
problemTitle: card.title, |
|||
text: card.text, |
|||
problemDesc: card.content, |
|||
isPosition: card.isPosition, |
|||
accord: card.accord, |
|||
})), |
|||
}, |
|||
], |
|||
}; |
|||
|
|||
console.log('封装后的提交数据', submitData); |
|||
|
|||
// TODO: 调用提交接口 |
|||
const res = await modifyContractReview(currentId.value, submitData); |
|||
emit('reload'); |
|||
// 提交成功后关闭弹窗 |
|||
closeModal(); |
|||
|
|||
// 可以添加成功提示 |
|||
Modal.success({ |
|||
title: '提示', |
|||
content: '提交成功!', |
|||
}); |
|||
} catch (error) { |
|||
// 错误处理 |
|||
console.log('提交失败', error); |
|||
Modal.error({ |
|||
title: '错误', |
|||
content: '提交失败,请重试!', |
|||
}); |
|||
} |
|||
}; |
|||
</script> |
|||
<style scoped> |
|||
/* 添加新的样式 */ |
|||
.modal-content { |
|||
height: 100%; |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
.grid { |
|||
flex: 1; |
|||
min-height: 0; /* 重要:防止grid溢出 */ |
|||
} |
|||
|
|||
.pdf-container { |
|||
height: 100%; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.review-container { |
|||
height: 100%; |
|||
display: flex; |
|||
flex-direction: column; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.review-content { |
|||
flex: 1; |
|||
min-height: 0; /* 重要:防止内容溢出 */ |
|||
overflow: hidden; |
|||
} |
|||
|
|||
/* 确保showResultCard组件占满剩余空间 */ |
|||
.review-content :deep(.tabs-container) { |
|||
height: 100%; |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
/* 调整tabs内容区域的高度 */ |
|||
.review-content :deep(.ant-tabs) { |
|||
height: 100%; |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
.review-content :deep(.ant-tabs-content) { |
|||
flex: 1; |
|||
height: 100%; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.review-content :deep(.ant-tabs-tabpane) { |
|||
height: 100%; |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
.review-content :deep(.scroll-container) { |
|||
flex: 1; |
|||
overflow-y: auto; |
|||
} |
|||
|
|||
.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; |
|||
} |
|||
|
|||
/* 合同文本容器样式 */ |
|||
.contract-text-container { |
|||
height: 100%; |
|||
display: flex; |
|||
flex-direction: column; |
|||
background: #fff; |
|||
border-radius: 4px; |
|||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); |
|||
} |
|||
|
|||
.contract-text-header { |
|||
padding: 12px 16px; |
|||
border-bottom: 1px solid #f0f0f0; |
|||
} |
|||
|
|||
.contract-text-header h3 { |
|||
margin: 0; |
|||
color: #333; |
|||
font-size: 16px; |
|||
} |
|||
|
|||
.contract-text-content { |
|||
flex: 1; |
|||
padding: 16px; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.contract-text-scroll { |
|||
height: 100%; |
|||
overflow-y: auto; |
|||
} |
|||
|
|||
.contract-text-scroll pre { |
|||
margin: 0; |
|||
white-space: pre-wrap; |
|||
word-wrap: break-word; |
|||
font-family: 'Source Han Sans CN', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; |
|||
font-size: 14px; |
|||
line-height: 1.6; |
|||
color: #333; |
|||
} |
|||
</style> |
@ -0,0 +1,66 @@ |
|||
import { BasicColumn } from '@/components/Table'; |
|||
import { FormSchema } from '@/components/Form'; |
|||
export const formSchemas: FormSchema[] = [ |
|||
{ |
|||
label: '合同审核配置表ID', |
|||
field: 'configId', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '检查项', |
|||
field: 'checkItem', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '要求描述', |
|||
field: 'requirementDesc', |
|||
component: 'InputTextArea', |
|||
}, |
|||
]; |
|||
|
|||
export const columns: BasicColumn[] = [ |
|||
{ |
|||
title: '主键ID', |
|||
dataIndex: 'id', |
|||
}, |
|||
{ |
|||
title: '合同审核配置表ID', |
|||
dataIndex: 'configId', |
|||
}, |
|||
{ |
|||
title: '检查项', |
|||
dataIndex: 'checkItem', |
|||
}, |
|||
{ |
|||
title: '要求描述', |
|||
dataIndex: 'requirementDesc', |
|||
}, |
|||
]; |
|||
|
|||
export const modalSchemas: FormSchema[] = [ |
|||
{ |
|||
label: '主键ID', |
|||
field: 'id', |
|||
required: false, |
|||
component: 'Input', |
|||
show: false, |
|||
}, |
|||
{ |
|||
label: '合同审核配置表ID', |
|||
field: 'configId', |
|||
required: true, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '检查项', |
|||
field: 'checkItem', |
|||
required: true, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '要求描述', |
|||
field: 'requirementDesc', |
|||
required: true, |
|||
component: 'InputTextArea', |
|||
}, |
|||
]; |
@ -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 { RequirementContractualNormalInfo, RequirementContractualNormalAdd, RequirementContractualNormalUpdate } from '@/api/contractReview/RequirementContractualNormal'; |
|||
import { modalSchemas } from './RequirementContractualNormal.data'; |
|||
|
|||
defineOptions({ name: 'RequirementContractualNormalModal' }); |
|||
|
|||
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 RequirementContractualNormalInfo(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 RequirementContractualNormalUpdate(data); |
|||
} else { |
|||
await RequirementContractualNormalAdd(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(RequirementContractualNormalExport, '合同常规要求数据', getForm().getFieldsValue())" |
|||
v-auth="'productManagement:RequirementContractualNormal:export'" |
|||
>导出</a-button |
|||
> |
|||
<a-button |
|||
type="primary" |
|||
danger |
|||
@click="multipleRemove(RequirementContractualNormalRemove)" |
|||
:disabled="!selected" |
|||
v-auth="'productManagement:RequirementContractualNormal:remove'" |
|||
>删除</a-button |
|||
> |
|||
<a-button |
|||
type="primary" |
|||
@click="handleAdd" |
|||
v-auth="'productManagement:RequirementContractualNormal: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:RequirementContractualNormal:edit', |
|||
onClick: handleEdit.bind(null, record), |
|||
}, |
|||
{ |
|||
label: '删除', |
|||
icon: IconEnum.DELETE, |
|||
type: 'primary', |
|||
danger: true, |
|||
ghost: true, |
|||
auth: 'productManagement:RequirementContractualNormal:remove', |
|||
popConfirm: { |
|||
placement: 'left', |
|||
title: '是否删除合同常规要求[' + record.id + ']?', |
|||
confirm: handleDelete.bind(null, record), |
|||
}, |
|||
}, |
|||
]" |
|||
/> |
|||
</template> |
|||
</template> |
|||
</BasicTable> |
|||
<RequirementContractualNormalModal @register="registerModal" @reload="reload" /> |
|||
</PageWrapper> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { PageWrapper } from '@/components/Page'; |
|||
import { BasicTable, useTable, TableAction } from '@/components/Table'; |
|||
import { RequirementContractualNormalList, RequirementContractualNormalExport, RequirementContractualNormalRemove } from '@/api/contractReview/RequirementContractualNormal'; |
|||
import { downloadExcel } from '@/utils/file/download'; |
|||
import { useModal } from '@/components/Modal'; |
|||
import RequirementContractualNormalModal from './RequirementContractualNormalModal.vue'; |
|||
import { formSchemas, columns } from './RequirementContractualNormal.data'; |
|||
import { IconEnum } from '@/enums/appEnum'; |
|||
|
|||
defineOptions({ name: 'RequirementContractualNormal' }); |
|||
|
|||
const [registerTable, { reload, multipleRemove, selected, getForm }] = useTable({ |
|||
rowSelection: { |
|||
type: 'checkbox', |
|||
}, |
|||
title: '合同常规要求列表', |
|||
api: RequirementContractualNormalList, |
|||
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 RequirementContractualNormalRemove([record.id]); |
|||
await reload(); |
|||
} |
|||
</script> |
|||
|
|||
<style scoped></style> |
@ -0,0 +1,81 @@ |
|||
import { BasicColumn } from '@/components/Table'; |
|||
import { FormSchema } from '@/components/Form'; |
|||
export const formSchemas: FormSchema[] = [ |
|||
{ |
|||
label: '合同审核配置表ID', |
|||
field: 'configId', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '名称', |
|||
field: 'name', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '型号', |
|||
field: 'model', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '版本号', |
|||
field: 'versionStr', |
|||
component: 'Input', |
|||
}, |
|||
]; |
|||
|
|||
export const columns: BasicColumn[] = [ |
|||
{ |
|||
title: '主键ID', |
|||
dataIndex: 'id', |
|||
}, |
|||
{ |
|||
title: '合同审核配置表ID', |
|||
dataIndex: 'configId', |
|||
}, |
|||
{ |
|||
title: '名称', |
|||
dataIndex: 'name', |
|||
}, |
|||
{ |
|||
title: '型号', |
|||
dataIndex: 'model', |
|||
}, |
|||
{ |
|||
title: '版本号', |
|||
dataIndex: 'versionStr', |
|||
}, |
|||
]; |
|||
|
|||
export const modalSchemas: FormSchema[] = [ |
|||
{ |
|||
label: '主键ID', |
|||
field: 'id', |
|||
required: false, |
|||
component: 'Input', |
|||
show: false, |
|||
}, |
|||
{ |
|||
label: '合同审核配置表ID', |
|||
field: 'configId', |
|||
required: true, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '名称', |
|||
field: 'name', |
|||
required: true, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '型号', |
|||
field: 'model', |
|||
required: false, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '版本号', |
|||
field: 'versionStr', |
|||
required: false, |
|||
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 { RequirementCpuInfo, RequirementCpuAdd, RequirementCpuUpdate } from '@/api/contractReview/RequirementCpu'; |
|||
import { modalSchemas } from './RequirementCpu.data'; |
|||
|
|||
defineOptions({ name: 'RequirementCpuModal' }); |
|||
|
|||
const emit = defineEmits(['register', 'reload']); |
|||
|
|||
const isUpdate = ref<boolean>(false); |
|||
const title = computed<string>(() => { |
|||
return isUpdate.value ? '编辑CPU要求' : '新增CPU要求'; |
|||
}); |
|||
|
|||
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 RequirementCpuInfo(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 RequirementCpuUpdate(data); |
|||
} else { |
|||
await RequirementCpuAdd(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(RequirementCpuExport, 'CPU要求数据', getForm().getFieldsValue())" |
|||
v-auth="'productManagement:RequirementCpu:export'" |
|||
>导出</a-button |
|||
> |
|||
<a-button |
|||
type="primary" |
|||
danger |
|||
@click="multipleRemove(RequirementCpuRemove)" |
|||
:disabled="!selected" |
|||
v-auth="'productManagement:RequirementCpu:remove'" |
|||
>删除</a-button |
|||
> |
|||
<a-button |
|||
type="primary" |
|||
@click="handleAdd" |
|||
v-auth="'productManagement:RequirementCpu: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:RequirementCpu:edit', |
|||
onClick: handleEdit.bind(null, record), |
|||
}, |
|||
{ |
|||
label: '删除', |
|||
icon: IconEnum.DELETE, |
|||
type: 'primary', |
|||
danger: true, |
|||
ghost: true, |
|||
auth: 'productManagement:RequirementCpu:remove', |
|||
popConfirm: { |
|||
placement: 'left', |
|||
title: '是否删除CPU要求[' + record.id + ']?', |
|||
confirm: handleDelete.bind(null, record), |
|||
}, |
|||
}, |
|||
]" |
|||
/> |
|||
</template> |
|||
</template> |
|||
</BasicTable> |
|||
<RequirementCpuModal @register="registerModal" @reload="reload" /> |
|||
</PageWrapper> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { PageWrapper } from '@/components/Page'; |
|||
import { BasicTable, useTable, TableAction } from '@/components/Table'; |
|||
import { RequirementCpuList, RequirementCpuExport, RequirementCpuRemove } from '@/api/contractReview/RequirementCpu'; |
|||
import { downloadExcel } from '@/utils/file/download'; |
|||
import { useModal } from '@/components/Modal'; |
|||
import RequirementCpuModal from './RequirementCpuModal.vue'; |
|||
import { formSchemas, columns } from './RequirementCpu.data'; |
|||
import { IconEnum } from '@/enums/appEnum'; |
|||
|
|||
defineOptions({ name: 'RequirementCpu' }); |
|||
|
|||
const [registerTable, { reload, multipleRemove, selected, getForm }] = useTable({ |
|||
rowSelection: { |
|||
type: 'checkbox', |
|||
}, |
|||
title: 'CPU要求列表', |
|||
api: RequirementCpuList, |
|||
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 RequirementCpuRemove([record.id]); |
|||
await reload(); |
|||
} |
|||
</script> |
|||
|
|||
<style scoped></style> |
@ -0,0 +1,81 @@ |
|||
import { BasicColumn } from '@/components/Table'; |
|||
import { FormSchema } from '@/components/Form'; |
|||
export const formSchemas: FormSchema[] = [ |
|||
{ |
|||
label: '合同审核配置表ID', |
|||
field: 'configId', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '名称', |
|||
field: 'name', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '型号', |
|||
field: 'model', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '版本号', |
|||
field: 'versionStr', |
|||
component: 'Input', |
|||
}, |
|||
]; |
|||
|
|||
export const columns: BasicColumn[] = [ |
|||
{ |
|||
title: '主键ID', |
|||
dataIndex: 'id', |
|||
}, |
|||
{ |
|||
title: '合同审核配置表ID', |
|||
dataIndex: 'configId', |
|||
}, |
|||
{ |
|||
title: '名称', |
|||
dataIndex: 'name', |
|||
}, |
|||
{ |
|||
title: '型号', |
|||
dataIndex: 'model', |
|||
}, |
|||
{ |
|||
title: '版本号', |
|||
dataIndex: 'versionStr', |
|||
}, |
|||
]; |
|||
|
|||
export const modalSchemas: FormSchema[] = [ |
|||
{ |
|||
label: '主键ID', |
|||
field: 'id', |
|||
required: false, |
|||
component: 'Input', |
|||
show: false, |
|||
}, |
|||
{ |
|||
label: '合同审核配置表ID', |
|||
field: 'configId', |
|||
required: true, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '名称', |
|||
field: 'name', |
|||
required: true, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '型号', |
|||
field: 'model', |
|||
required: false, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '版本号', |
|||
field: 'versionStr', |
|||
required: false, |
|||
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 { RequirementDatabaseInfo, RequirementDatabaseAdd, RequirementDatabaseUpdate } from '@/api/contractReview/RequirementDatabase'; |
|||
import { modalSchemas } from './RequirementDatabase.data'; |
|||
|
|||
defineOptions({ name: 'RequirementDatabaseModal' }); |
|||
|
|||
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 RequirementDatabaseInfo(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 RequirementDatabaseUpdate(data); |
|||
} else { |
|||
await RequirementDatabaseAdd(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(RequirementDatabaseExport, '数据库要求数据', getForm().getFieldsValue())" |
|||
v-auth="'productManagement:RequirementDatabase:export'" |
|||
>导出</a-button |
|||
> |
|||
<a-button |
|||
type="primary" |
|||
danger |
|||
@click="multipleRemove(RequirementDatabaseRemove)" |
|||
:disabled="!selected" |
|||
v-auth="'productManagement:RequirementDatabase:remove'" |
|||
>删除</a-button |
|||
> |
|||
<a-button |
|||
type="primary" |
|||
@click="handleAdd" |
|||
v-auth="'productManagement:RequirementDatabase: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:RequirementDatabase:edit', |
|||
onClick: handleEdit.bind(null, record), |
|||
}, |
|||
{ |
|||
label: '删除', |
|||
icon: IconEnum.DELETE, |
|||
type: 'primary', |
|||
danger: true, |
|||
ghost: true, |
|||
auth: 'productManagement:RequirementDatabase:remove', |
|||
popConfirm: { |
|||
placement: 'left', |
|||
title: '是否删除数据库要求[' + record.id + ']?', |
|||
confirm: handleDelete.bind(null, record), |
|||
}, |
|||
}, |
|||
]" |
|||
/> |
|||
</template> |
|||
</template> |
|||
</BasicTable> |
|||
<RequirementDatabaseModal @register="registerModal" @reload="reload" /> |
|||
</PageWrapper> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { PageWrapper } from '@/components/Page'; |
|||
import { BasicTable, useTable, TableAction } from '@/components/Table'; |
|||
import { RequirementDatabaseList, RequirementDatabaseExport, RequirementDatabaseRemove } from '@/api/contractReview/RequirementDatabase'; |
|||
import { downloadExcel } from '@/utils/file/download'; |
|||
import { useModal } from '@/components/Modal'; |
|||
import RequirementDatabaseModal from './RequirementDatabaseModal.vue'; |
|||
import { formSchemas, columns } from './RequirementDatabase.data'; |
|||
import { IconEnum } from '@/enums/appEnum'; |
|||
|
|||
defineOptions({ name: 'RequirementDatabase' }); |
|||
|
|||
const [registerTable, { reload, multipleRemove, selected, getForm }] = useTable({ |
|||
rowSelection: { |
|||
type: 'checkbox', |
|||
}, |
|||
title: '数据库要求列表', |
|||
api: RequirementDatabaseList, |
|||
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 RequirementDatabaseRemove([record.id]); |
|||
await reload(); |
|||
} |
|||
</script> |
|||
|
|||
<style scoped></style> |
@ -0,0 +1,96 @@ |
|||
import { BasicColumn } from '@/components/Table'; |
|||
import { FormSchema } from '@/components/Form'; |
|||
export const formSchemas: FormSchema[] = [ |
|||
{ |
|||
label: '合同审核配置表ID', |
|||
field: 'configId', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '主体名称', |
|||
field: 'entityName', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '父主体ID,0表示顶级主体', |
|||
field: 'parentId', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '层级,1表示顶级', |
|||
field: 'level', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '层级路径,格式如:0,1,2', |
|||
field: 'path', |
|||
component: 'Input', |
|||
}, |
|||
]; |
|||
|
|||
export const columns: BasicColumn[] = [ |
|||
{ |
|||
title: '主键ID', |
|||
dataIndex: 'id', |
|||
}, |
|||
{ |
|||
title: '合同审核配置表ID', |
|||
dataIndex: 'configId', |
|||
}, |
|||
{ |
|||
title: '主体名称', |
|||
dataIndex: 'entityName', |
|||
}, |
|||
{ |
|||
title: '父主体ID,0表示顶级主体', |
|||
dataIndex: 'parentId', |
|||
}, |
|||
{ |
|||
title: '层级,1表示顶级', |
|||
dataIndex: 'level', |
|||
}, |
|||
{ |
|||
title: '层级路径,格式如:0,1,2', |
|||
dataIndex: 'path', |
|||
}, |
|||
]; |
|||
|
|||
export const modalSchemas: FormSchema[] = [ |
|||
{ |
|||
label: '主键ID', |
|||
field: 'id', |
|||
required: false, |
|||
component: 'Input', |
|||
show: false, |
|||
}, |
|||
{ |
|||
label: '合同审核配置表ID', |
|||
field: 'configId', |
|||
required: true, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '主体名称', |
|||
field: 'entityName', |
|||
required: true, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '父主体ID,0表示顶级主体', |
|||
field: 'parentId', |
|||
required: true, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '层级,1表示顶级', |
|||
field: 'level', |
|||
required: true, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '层级路径,格式如:0,1,2', |
|||
field: 'path', |
|||
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 { RequirementEntityInfo, RequirementEntityAdd, RequirementEntityUpdate } from '@/api/contractReview/RequirementEntity'; |
|||
import { modalSchemas } from './RequirementEntity.data'; |
|||
|
|||
defineOptions({ name: 'RequirementEntityModal' }); |
|||
|
|||
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 RequirementEntityInfo(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 RequirementEntityUpdate(data); |
|||
} else { |
|||
await RequirementEntityAdd(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(RequirementEntityExport, '主体要求数据', getForm().getFieldsValue())" |
|||
v-auth="'productManagement:RequirementEntity:export'" |
|||
>导出</a-button |
|||
> |
|||
<a-button |
|||
type="primary" |
|||
danger |
|||
@click="multipleRemove(RequirementEntityRemove)" |
|||
:disabled="!selected" |
|||
v-auth="'productManagement:RequirementEntity:remove'" |
|||
>删除</a-button |
|||
> |
|||
<a-button |
|||
type="primary" |
|||
@click="handleAdd" |
|||
v-auth="'productManagement:RequirementEntity: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:RequirementEntity:edit', |
|||
onClick: handleEdit.bind(null, record), |
|||
}, |
|||
{ |
|||
label: '删除', |
|||
icon: IconEnum.DELETE, |
|||
type: 'primary', |
|||
danger: true, |
|||
ghost: true, |
|||
auth: 'productManagement:RequirementEntity:remove', |
|||
popConfirm: { |
|||
placement: 'left', |
|||
title: '是否删除主体要求[' + record.id + ']?', |
|||
confirm: handleDelete.bind(null, record), |
|||
}, |
|||
}, |
|||
]" |
|||
/> |
|||
</template> |
|||
</template> |
|||
</BasicTable> |
|||
<RequirementEntityModal @register="registerModal" @reload="reload" /> |
|||
</PageWrapper> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { PageWrapper } from '@/components/Page'; |
|||
import { BasicTable, useTable, TableAction } from '@/components/Table'; |
|||
import { RequirementEntityList, RequirementEntityExport, RequirementEntityRemove } from '@/api/contractReview/RequirementEntity'; |
|||
import { downloadExcel } from '@/utils/file/download'; |
|||
import { useModal } from '@/components/Modal'; |
|||
import RequirementEntityModal from './RequirementEntityModal.vue'; |
|||
import { formSchemas, columns } from './RequirementEntity.data'; |
|||
import { IconEnum } from '@/enums/appEnum'; |
|||
|
|||
defineOptions({ name: 'RequirementEntity' }); |
|||
|
|||
const [registerTable, { reload, multipleRemove, selected, getForm }] = useTable({ |
|||
rowSelection: { |
|||
type: 'checkbox', |
|||
}, |
|||
title: '主体要求列表', |
|||
api: RequirementEntityList, |
|||
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 RequirementEntityRemove([record.id]); |
|||
await reload(); |
|||
} |
|||
</script> |
|||
|
|||
<style scoped></style> |
@ -0,0 +1,81 @@ |
|||
import { BasicColumn } from '@/components/Table'; |
|||
import { FormSchema } from '@/components/Form'; |
|||
export const formSchemas: FormSchema[] = [ |
|||
{ |
|||
label: '合同审核配置表ID', |
|||
field: 'configId', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '名称', |
|||
field: 'name', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '型号', |
|||
field: 'model', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '版本号', |
|||
field: 'versionStr', |
|||
component: 'Input', |
|||
}, |
|||
]; |
|||
|
|||
export const columns: BasicColumn[] = [ |
|||
{ |
|||
title: '主键ID', |
|||
dataIndex: 'id', |
|||
}, |
|||
{ |
|||
title: '合同审核配置表ID', |
|||
dataIndex: 'configId', |
|||
}, |
|||
{ |
|||
title: '名称', |
|||
dataIndex: 'name', |
|||
}, |
|||
{ |
|||
title: '型号', |
|||
dataIndex: 'model', |
|||
}, |
|||
{ |
|||
title: '版本号', |
|||
dataIndex: 'versionStr', |
|||
}, |
|||
]; |
|||
|
|||
export const modalSchemas: FormSchema[] = [ |
|||
{ |
|||
label: '主键ID', |
|||
field: 'id', |
|||
required: false, |
|||
component: 'Input', |
|||
show: false, |
|||
}, |
|||
{ |
|||
label: '合同审核配置表ID', |
|||
field: 'configId', |
|||
required: true, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '名称', |
|||
field: 'name', |
|||
required: true, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '型号', |
|||
field: 'model', |
|||
required: false, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '版本号', |
|||
field: 'versionStr', |
|||
required: false, |
|||
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 { RequirementOsInfo, RequirementOsAdd, RequirementOsUpdate } from '@/api/contractReview/RequirementOs'; |
|||
import { modalSchemas } from './RequirementOs.data'; |
|||
|
|||
defineOptions({ name: 'RequirementOsModal' }); |
|||
|
|||
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 RequirementOsInfo(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 RequirementOsUpdate(data); |
|||
} else { |
|||
await RequirementOsAdd(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(RequirementOsExport, '操作系统要求数据', getForm().getFieldsValue())" |
|||
v-auth="'productManagement:RequirementOs:export'" |
|||
>导出</a-button |
|||
> |
|||
<a-button |
|||
type="primary" |
|||
danger |
|||
@click="multipleRemove(RequirementOsRemove)" |
|||
:disabled="!selected" |
|||
v-auth="'productManagement:RequirementOs:remove'" |
|||
>删除</a-button |
|||
> |
|||
<a-button |
|||
type="primary" |
|||
@click="handleAdd" |
|||
v-auth="'productManagement:RequirementOs: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:RequirementOs:edit', |
|||
onClick: handleEdit.bind(null, record), |
|||
}, |
|||
{ |
|||
label: '删除', |
|||
icon: IconEnum.DELETE, |
|||
type: 'primary', |
|||
danger: true, |
|||
ghost: true, |
|||
auth: 'productManagement:RequirementOs:remove', |
|||
popConfirm: { |
|||
placement: 'left', |
|||
title: '是否删除操作系统要求[' + record.id + ']?', |
|||
confirm: handleDelete.bind(null, record), |
|||
}, |
|||
}, |
|||
]" |
|||
/> |
|||
</template> |
|||
</template> |
|||
</BasicTable> |
|||
<RequirementOsModal @register="registerModal" @reload="reload" /> |
|||
</PageWrapper> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { PageWrapper } from '@/components/Page'; |
|||
import { BasicTable, useTable, TableAction } from '@/components/Table'; |
|||
import { RequirementOsList, RequirementOsExport, RequirementOsRemove } from '@/api/contractReview/RequirementOs'; |
|||
import { downloadExcel } from '@/utils/file/download'; |
|||
import { useModal } from '@/components/Modal'; |
|||
import RequirementOsModal from './RequirementOsModal.vue'; |
|||
import { formSchemas, columns } from './RequirementOs.data'; |
|||
import { IconEnum } from '@/enums/appEnum'; |
|||
|
|||
defineOptions({ name: 'RequirementOs' }); |
|||
|
|||
const [registerTable, { reload, multipleRemove, selected, getForm }] = useTable({ |
|||
rowSelection: { |
|||
type: 'checkbox', |
|||
}, |
|||
title: '操作系统要求列表', |
|||
api: RequirementOsList, |
|||
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 RequirementOsRemove([record.id]); |
|||
await reload(); |
|||
} |
|||
</script> |
|||
|
|||
<style scoped></style> |
@ -0,0 +1,81 @@ |
|||
import { BasicColumn } from '@/components/Table'; |
|||
import { FormSchema } from '@/components/Form'; |
|||
export const formSchemas: FormSchema[] = [ |
|||
{ |
|||
label: '合同审核配置表ID', |
|||
field: 'configId', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '属性名称', |
|||
field: 'attributeName', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '要求', |
|||
field: 'requirement', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '产品类型', |
|||
field: 'productType', |
|||
component: 'Select', |
|||
}, |
|||
]; |
|||
|
|||
export const columns: BasicColumn[] = [ |
|||
{ |
|||
title: '主键ID', |
|||
dataIndex: 'id', |
|||
}, |
|||
{ |
|||
title: '合同审核配置表ID', |
|||
dataIndex: 'configId', |
|||
}, |
|||
{ |
|||
title: '属性名称', |
|||
dataIndex: 'attributeName', |
|||
}, |
|||
{ |
|||
title: '要求', |
|||
dataIndex: 'requirement', |
|||
}, |
|||
{ |
|||
title: '产品类型', |
|||
dataIndex: 'productType', |
|||
}, |
|||
]; |
|||
|
|||
export const modalSchemas: FormSchema[] = [ |
|||
{ |
|||
label: '主键ID', |
|||
field: 'id', |
|||
required: false, |
|||
component: 'Input', |
|||
show: false, |
|||
}, |
|||
{ |
|||
label: '合同审核配置表ID', |
|||
field: 'configId', |
|||
required: true, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '属性名称', |
|||
field: 'attributeName', |
|||
required: true, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '要求', |
|||
field: 'requirement', |
|||
required: true, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '产品类型', |
|||
field: 'productType', |
|||
required: true, |
|||
component: 'Select', |
|||
}, |
|||
]; |
@ -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 { RequirementProductAttributeInfo, RequirementProductAttributeAdd, RequirementProductAttributeUpdate } from '@/api/contractReview/RequirementProductAttribute'; |
|||
import { modalSchemas } from './RequirementProductAttribute.data'; |
|||
|
|||
defineOptions({ name: 'RequirementProductAttributeModal' }); |
|||
|
|||
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 RequirementProductAttributeInfo(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 RequirementProductAttributeUpdate(data); |
|||
} else { |
|||
await RequirementProductAttributeAdd(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(RequirementProductAttributeExport, '产品属性要求数据', getForm().getFieldsValue())" |
|||
v-auth="'productManagement:RequirementProductAttribute:export'" |
|||
>导出</a-button |
|||
> |
|||
<a-button |
|||
type="primary" |
|||
danger |
|||
@click="multipleRemove(RequirementProductAttributeRemove)" |
|||
:disabled="!selected" |
|||
v-auth="'productManagement:RequirementProductAttribute:remove'" |
|||
>删除</a-button |
|||
> |
|||
<a-button |
|||
type="primary" |
|||
@click="handleAdd" |
|||
v-auth="'productManagement:RequirementProductAttribute: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:RequirementProductAttribute:edit', |
|||
onClick: handleEdit.bind(null, record), |
|||
}, |
|||
{ |
|||
label: '删除', |
|||
icon: IconEnum.DELETE, |
|||
type: 'primary', |
|||
danger: true, |
|||
ghost: true, |
|||
auth: 'productManagement:RequirementProductAttribute:remove', |
|||
popConfirm: { |
|||
placement: 'left', |
|||
title: '是否删除产品属性要求[' + record.id + ']?', |
|||
confirm: handleDelete.bind(null, record), |
|||
}, |
|||
}, |
|||
]" |
|||
/> |
|||
</template> |
|||
</template> |
|||
</BasicTable> |
|||
<RequirementProductAttributeModal @register="registerModal" @reload="reload" /> |
|||
</PageWrapper> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { PageWrapper } from '@/components/Page'; |
|||
import { BasicTable, useTable, TableAction } from '@/components/Table'; |
|||
import { RequirementProductAttributeList, RequirementProductAttributeExport, RequirementProductAttributeRemove } from '@/api/contractReview/RequirementProductAttribute'; |
|||
import { downloadExcel } from '@/utils/file/download'; |
|||
import { useModal } from '@/components/Modal'; |
|||
import RequirementProductAttributeModal from './RequirementProductAttributeModal.vue'; |
|||
import { formSchemas, columns } from './RequirementProductAttribute.data'; |
|||
import { IconEnum } from '@/enums/appEnum'; |
|||
|
|||
defineOptions({ name: 'RequirementProductAttribute' }); |
|||
|
|||
const [registerTable, { reload, multipleRemove, selected, getForm }] = useTable({ |
|||
rowSelection: { |
|||
type: 'checkbox', |
|||
}, |
|||
title: '产品属性要求列表', |
|||
api: RequirementProductAttributeList, |
|||
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 RequirementProductAttributeRemove([record.id]); |
|||
await reload(); |
|||
} |
|||
</script> |
|||
|
|||
<style scoped></style> |
@ -1,76 +1,344 @@ |
|||
<template> |
|||
<PageWrapper> |
|||
<template #headerContent> <WorkbenchHeader /> </template> |
|||
<template #headerContent> |
|||
<WorkbenchHeader /> |
|||
</template> |
|||
<div class="workbench"> |
|||
<div class="h-1/4"> |
|||
<div class="grid grid-cols-5 gap-4"> |
|||
<div class="col-span-3 h-full"> |
|||
<ProjectCard :loading="loading" class="enter-y" /> |
|||
<!-- 平台信息卡片 --> |
|||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4 mb-4"> |
|||
<a-card title="平台信息" :bordered="false" class="enter-y"> |
|||
<template #extra> |
|||
<a-tag color="processing">系统状态: 正常运行</a-tag> |
|||
</template> |
|||
<div class="grid grid-cols-2 gap-4"> |
|||
<div v-for="(item, index) in platformInfo" :key="index" class="flex items-start"> |
|||
<div class="mr-2"> |
|||
<component :is="item.icon" class="text-xl text-primary" /> |
|||
</div> |
|||
<div> |
|||
<div class="text-secondary text-sm">{{ item.label }}</div> |
|||
<div class="font-medium">{{ item.value }}</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-span-2 h-full"> |
|||
<QuickNav :loading="loading" class="enter-y" /> |
|||
</a-card> |
|||
|
|||
<!-- 任务概况卡片 - 调整为更加饱满的布局 --> |
|||
<a-card title="任务概况" :bordered="false" class="enter-y task-stats-card"> |
|||
<template #extra> |
|||
<a-button type="link" @click="refreshTaskStats"> |
|||
<ReloadOutlined /> |
|||
</a-button> |
|||
</template> |
|||
<div class="task-stats-container"> |
|||
<!-- 第一行:正在执行、已完成、总任务数 --> |
|||
<div class="task-stats-row"> |
|||
<div v-for="(stat, index) in taskStatsRow1" :key="index" class="task-stat-item"> |
|||
<div class="task-stat-title">{{ stat.title }}</div> |
|||
<div class="task-stat-value"> |
|||
<component :is="stat.icon" :style="{color: stat.color}" class="task-stat-icon" /> |
|||
<span :style="{color: stat.color}">{{ stat.value }}</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 第二行:审核通过、审核未通过 --> |
|||
<div class="task-stats-row second-row"> |
|||
<div v-for="(stat, index) in taskStatsRow2" :key="index" class="task-stat-item review-stat"> |
|||
<div class="task-stat-title">{{ stat.title }}</div> |
|||
<div class="task-stat-value"> |
|||
<component :is="stat.icon" :style="{color: stat.color}" class="task-stat-icon" /> |
|||
<span :style="{color: stat.color}">{{ stat.value }}</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="h-1/2 mt-4"> |
|||
<Card title="任务看板" :bordered="false" style="width: 100%; height: 100%"> |
|||
<template #extra> |
|||
<!-- 将按钮改为下拉菜单 --> |
|||
<Dropdown> |
|||
<a-button> |
|||
更多 |
|||
<DownOutlined /> |
|||
</a-button> |
|||
<template #overlay> |
|||
<Menu @click="handleMenuClick" mode="vertical"> |
|||
<MenuItem v-for="item in groupItems" |
|||
:key="item.path" |
|||
> |
|||
{{ item.title }} |
|||
</MenuItem> |
|||
</Menu> |
|||
</template> |
|||
</Dropdown> |
|||
</template> |
|||
|
|||
<DocumentTasksTable |
|||
:show-table-setting="false" |
|||
:show-toolbar="false" |
|||
:use-search-form="false" |
|||
:pagination="false" |
|||
/> |
|||
</Card> |
|||
</div> |
|||
</a-card> |
|||
</div> |
|||
|
|||
<!-- 单一图表展示区域 - 使用 useECharts 钩子 --> |
|||
<div class="mb-4"> |
|||
<a-card title="单位合同统计" :loading="loading" class="enter-y"> |
|||
<div ref="chartRef" style="width: 100%; height: 320px;"></div> |
|||
</a-card> |
|||
</div> |
|||
</div> |
|||
</PageWrapper> |
|||
</template> |
|||
|
|||
<script lang="ts" setup> |
|||
import { ref, onMounted } from 'vue'; |
|||
import { ref, reactive, onMounted, watch, Ref } from 'vue'; |
|||
import { PageWrapper } from '@/components/Page'; |
|||
import WorkbenchHeader from './components/WorkbenchHeader.vue'; |
|||
import { 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 { useECharts } from '@/hooks/web/useECharts'; |
|||
import { |
|||
ReloadOutlined, |
|||
ClockCircleOutlined, |
|||
CheckCircleOutlined, |
|||
CloseCircleOutlined, |
|||
AppstoreOutlined, |
|||
CloudServerOutlined, |
|||
DatabaseOutlined, |
|||
HddOutlined, |
|||
LaptopOutlined, |
|||
RobotOutlined, |
|||
CodeOutlined |
|||
} from '@ant-design/icons-vue'; |
|||
import { Card, Button, Tag, Radio } from 'ant-design-vue'; |
|||
|
|||
// 组件重命名 |
|||
const ACard = Card; |
|||
const AButton = Button; |
|||
const ATag = Tag; |
|||
const ARadioGroup = Radio.Group; |
|||
const ARadioButton = Radio.Button; |
|||
|
|||
const router = useRouter(); |
|||
|
|||
// 状态定义 |
|||
const loading = ref(false); |
|||
const handleMenuClick = ({ key }) => { |
|||
console.log(key); |
|||
router.push({ path: key }); |
|||
|
|||
// 图表引用 |
|||
const chartRef = ref<HTMLDivElement | null>(null); |
|||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>); |
|||
|
|||
// 平台信息数据 |
|||
const platformInfo = ref([ |
|||
{ |
|||
label: 'CPU', |
|||
value: 'Kunpeng 920 24Core@2.6GHz x2', |
|||
icon: CloudServerOutlined |
|||
}, |
|||
{ |
|||
label: 'NPU', |
|||
value: 'Atlas 300I Duo 96GB-150W x4', |
|||
icon: HddOutlined |
|||
}, |
|||
{ |
|||
label: '内存', |
|||
value: '64GB×8 DDR4', |
|||
icon: HddOutlined |
|||
}, |
|||
{ |
|||
label: '存储', |
|||
value: '3T SSD', |
|||
icon: DatabaseOutlined |
|||
}, |
|||
{ |
|||
label: '数据库', |
|||
value: 'OceanBase', |
|||
icon: DatabaseOutlined |
|||
}, |
|||
{ |
|||
label: '操作系统', |
|||
value: 'UOS Server 20', |
|||
icon: LaptopOutlined |
|||
}, |
|||
{ |
|||
label: '内置模型', |
|||
value: 'OCR: Qwen2-VL-7B / NLP: QwQ-32B', |
|||
icon: RobotOutlined |
|||
}, |
|||
{ |
|||
label: '模型框架', |
|||
value: 'MindIE/PyTorch', |
|||
icon: CodeOutlined |
|||
} |
|||
]); |
|||
|
|||
// 将任务统计数据分为两行 |
|||
const taskStatsRow1 = ref([ |
|||
{ |
|||
title: '正在执行', |
|||
value: 12, |
|||
icon: ClockCircleOutlined, |
|||
color: '#1890ff' |
|||
}, |
|||
{ |
|||
title: '已完成', |
|||
value: 56, |
|||
icon: CheckCircleOutlined, |
|||
color: '#52c41a' |
|||
}, |
|||
{ |
|||
title: '总任务数', |
|||
value: 78, |
|||
icon: AppstoreOutlined, |
|||
color: '#722ed1' |
|||
} |
|||
]); |
|||
|
|||
const taskStatsRow2 = ref([ |
|||
{ |
|||
title: '审核通过', |
|||
value: 42, |
|||
icon: CheckCircleOutlined, |
|||
color: '#52c41a' |
|||
}, |
|||
{ |
|||
title: '审核未通过', |
|||
value: 14, |
|||
icon: CloseCircleOutlined, |
|||
color: '#f5222d' |
|||
} |
|||
]); |
|||
|
|||
// 单位合同统计图表配置 |
|||
const contractChartOption = { |
|||
title: { |
|||
text: '', |
|||
}, |
|||
tooltip: { |
|||
trigger: 'axis', |
|||
formatter: '{b}个单位: {c}份合同' |
|||
}, |
|||
grid: { |
|||
left: '3%', |
|||
right: '4%', |
|||
bottom: '3%', |
|||
containLabel: true |
|||
}, |
|||
xAxis: { |
|||
type: 'category', |
|||
name: '单位数', |
|||
nameLocation: 'middle', |
|||
nameGap: 30, |
|||
nameTextStyle: { |
|||
fontWeight: 'bold' |
|||
}, |
|||
data: ['5', '10', '15', '20', '25', '30', '35'] |
|||
}, |
|||
yAxis: { |
|||
type: 'value', |
|||
name: '合同数', |
|||
nameLocation: 'middle', |
|||
nameGap: 40, |
|||
nameTextStyle: { |
|||
fontWeight: 'bold' |
|||
} |
|||
}, |
|||
series: [ |
|||
{ |
|||
name: '合同数', |
|||
type: 'line', |
|||
smooth: true, |
|||
symbolSize: 8, |
|||
lineStyle: { |
|||
width: 3 |
|||
}, |
|||
itemStyle: { |
|||
color: '#1890ff' |
|||
}, |
|||
data: [10, 22, 30, 42, 56, 68, 75] |
|||
} |
|||
] |
|||
}; |
|||
|
|||
// 根据当前选择的模式渲染图表 - 简化此函数 |
|||
const renderChart = () => { |
|||
setOptions(contractChartOption); |
|||
}; |
|||
|
|||
// 刷新任务统计 |
|||
const refreshTaskStats = () => { |
|||
loading.value = true; |
|||
// 模拟异步请求 |
|||
setTimeout(() => { |
|||
taskStatsRow1.value[0].value += 2; |
|||
taskStatsRow1.value[1].value += 1; |
|||
taskStatsRow1.value[2].value += 3; |
|||
taskStatsRow2.value[0].value += 1; |
|||
taskStatsRow2.value[1].value += 0; |
|||
loading.value = false; |
|||
}, 800); |
|||
}; |
|||
|
|||
// 获取任务列表和图表数据 |
|||
const fetchData = async () => { |
|||
loading.value = true; |
|||
// 这里可以添加实际的API调用 |
|||
setTimeout(() => { |
|||
renderChart(); |
|||
loading.value = false; |
|||
}, 1500); |
|||
}; |
|||
// 获取任务列表 |
|||
const fetchTaskList = async () => {}; |
|||
|
|||
// 页面加载时获取数据 |
|||
onMounted(() => { |
|||
fetchTaskList(); |
|||
fetchData(); |
|||
}); |
|||
setTimeout(() => { |
|||
loading.value = false; |
|||
}, 1500); |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.workbench { |
|||
margin-top: 12px; |
|||
} |
|||
|
|||
.text-primary { |
|||
color: #1890ff; |
|||
} |
|||
|
|||
.text-secondary { |
|||
color: rgba(0, 0, 0, 0.45); |
|||
} |
|||
|
|||
.task-stats-card { |
|||
:deep(.ant-card-body) { |
|||
height: calc(100% - 58px); |
|||
padding: 16px; |
|||
} |
|||
} |
|||
|
|||
.task-stats-container { |
|||
height: 100%; |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: space-around; |
|||
} |
|||
|
|||
.task-stats-row { |
|||
display: flex; |
|||
justify-content: space-around; |
|||
width: 100%; |
|||
padding: 8px 0; |
|||
} |
|||
|
|||
.second-row { |
|||
justify-content: space-evenly; |
|||
width: 90%; |
|||
margin: 0 auto; |
|||
} |
|||
|
|||
.task-stat-item { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
padding: 12px 20px; |
|||
min-width: 110px; |
|||
} |
|||
|
|||
.review-stat { |
|||
padding: 12px 36px; |
|||
} |
|||
|
|||
.task-stat-title { |
|||
font-size: 15px; |
|||
color: rgba(0, 0, 0, 0.45); |
|||
margin-bottom: 8px; |
|||
white-space: nowrap; |
|||
} |
|||
|
|||
.task-stat-value { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
font-size: 28px; |
|||
font-weight: bold; |
|||
} |
|||
|
|||
.task-stat-icon { |
|||
font-size: 24px; |
|||
margin-right: 8px; |
|||
} |
|||
</style> |
|||
|
Loading…
Reference in new issue