2ab01a61 by lihua

元数据和数据质量功能迁入

1 parent aee6275a
This diff could not be displayed because it is too large.
import request from "@/utils/request";
/**
* 元数据-采集任务
**/
// 新增
export const addMetaDataTask = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/meta-collect-task/add`,
method: 'post',
data: params
})
// 删除
export const deleteMetaDataTask = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/meta-collect-task/del`,
method: 'delete',
data: params
})
// 分页查询
export const getMetaDataTask = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/meta-collect-task/page-list`,
method: 'post',
data: params
})
// 修改
export const updateMetaDataTask = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/meta-collect-task/update`,
method: 'put',
data: params
})
// 详情
export const getMetaDataTaskDetail = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/meta-collect-task/detail/${params}`,
method: 'get'
})
// 上线下线
export const updateMetaDataState = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/meta-collect-task/change-state`,
method: 'get',
params
})
// 名称唯一性验证
export const checkMetaDataTask = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/meta-collect-task/check-exist`,
method: 'post',
data: {
collectTaskName: params,
}
})
// 执行元数据采集任务
export const executeMetaDataTask = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/meta-collect-task/execute/${params}`,
method: 'get'
})
// 执行日志
export const getMetaDataTaskLog = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/meta-collect-exec/page-list`,
method: 'post',
data: params
})
//
export const saveMetaReportAnalysis = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/lineage-analysis-report/add`,
method: 'post',
data: params
})
/**
* 元数据-元数据查询
**/
// 树形数据
export const getMetaTreeData = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/meta-table/meta-tree-list`,
method: 'post',
data: params
})
// 数据库汇总信息
export const getMetaDatabaseCollect = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/meta-table/meta-database-collect-list`,
method: 'post',
data: params
})
// 库分页查询
export const getMetaDataBase = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/meta-table/meta-table-collect-list`,
method: 'post',
data: params
})
// 表分页查询
export const getMetaDataSheet = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/meta-table/meta-table-detail-list`,
method: 'post',
data: params
})
// 表字段查询
export const getMetaSheetField = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/meta-table/meta-table-field-list`,
method: 'post',
params
})
// 表索引查询
export const getMetaSheetKeys = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/meta-table/meta-table-index-list`,
method: 'post',
params
})
// 变更查询
export const getMetaChange = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/meta-table/meta-collect-change-list`,
method: 'post',
data: params
})
// 变更明细
export const getMetaChangeRecord = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/meta-table/meta-change-record-list`,
method: 'post',
data: params
})
//
export const getMetacompareList = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/meta-table/meta-change-compare-list/${params}`,
method: 'get',
//data: params
})
// 表信息详情
export const getMetaDetail = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/meta-table/detail/${params}`,
method: 'get',
})
/** 根据表获取血缘数据 */
export const getTableLineage = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/lineage/lineage-query?guid=${params.guid}&lineageType=tb`,
method: 'get',
})
/** 根据字段获取血缘数据 */
export const getTableFieldLineage = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/lineage/lineage-query?guid=${params.guid}&lineageType=co`,
method: 'get',
})
/** 获取表的所有字段血缘数据 */
export const getTableAllFieldLineage = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/lineage/lineage-query-field?databaseName=${params.databaseName}&tableName=${params.tableName}`,
method: 'get',
})
// 查询列表
export const getMetaList = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/meta-table/list-meta-all`,
method: 'post',
data:params
})
// 元数据表字段查询
export const getMetaTableField = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/meta-table/meta-table-field-list`,
method: 'post',
params,
})
// 保存血缘字段节点
export const saveLineageField = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/lineage/save-field`,
method: 'post',
data:params
})
// 保存血源节点
export const saveLineageTable = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/lineage/save-table`,
method: 'post',
data:params
})
// 删除血源节点
export const delLineageTable = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/lineage/del-vertex?vertexId=${params.vertexId}`,
method: 'delete',
//data:params
})
/** 获取同步任务变更记录 */
export const getTaskChangeList = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/task-change-record/page-list`,
method: 'post',
data:params
})
/** 获取元数据变更记录 */
export const getMetaChangeList = (params) => request({
url: ``,
method: 'post',
data:params
})
/** 获取数据库选择列表 */
export const getDatabase = (params) => request({
url: `${import.meta.env.VITE_APP_API_BASEURL}/data-source/get-source-list`,
method: 'post',
data: params
})
/** 源数据分析报告 */
/**查询列表 */
export const getAnalysisReportList = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/lineage-analysis-report/list`,
method: 'post',
data: params
})
/** 根据guid删除 */
export const delAnalysisRepor = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/lineage-analysis-report/del`,
method: 'delete',
data: params
})
/** 根据guid更新 */
export const updateAnalysisRepor = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/lineage-analysis-report/update`,
method: 'put',
data: params
})
/** 删除边 */
export const delLineAge = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/lineage/del-edge?euid=${params}`,
method: 'delete',
})
/** 判断是否有元数据数据 */
export const checkTableData = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/meta-table/check-table-data/${params}`,
method: 'get',
})
/**校验任务是否有数据库信息 */
export const checkDatabaseIsExist = (dataSourceGuid) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/meta-collect-task/check-database-is-exist/${dataSourceGuid}`,
method: 'get',
})
/**同步任务 变更详情展示 */
export const syncChangeDetail = (guid) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/task-change-record/sync-change-detail/${guid}`,
method: 'get',
})
\ No newline at end of file
import request from "@/utils/request";
/** 获取质量模型对应的所有分组表格数据 */
export const getQualityTreeData = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-model-group/quality-model-tree` + (params ? `?guid=${params}` : ''),
method: 'get'
})
/** 获取数据源下,对应分组的表数据 */
export const getQualityTreeDataByDs = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-model-group/quality-model-tree?guid=${params.guid}&dataSourceGuid=${params.dataSourceGuid}`,
method: 'get'
})
/** 获取质量模型对应的所有分组表格分页数据 */
export const getQualityGroupData = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-model-group/page-list`,
method: 'post',
data: params
})
/** 删除质量模型的指定分组。 */
export const deleteGroup = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-model-group/del`,
method: 'delete',
data: params
})
/** 添加分组 */
export const addQualityGroup = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-model-group/add`,
method: 'post',
data: params
})
/** 修改分组 */
export const updateQualityGroup = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-model-group/update`,
method: 'put',
data: params
})
/** 获取质量分组对应的表格分页数据 */
export const getQualityTable = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-model/page-list`,
method: 'post',
data: params
})
/** 删除质检表 */
export const deleteQualityTable = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-model/del`,
method: 'delete',
data: params
})
/** 获取质量表对应的所有规则数据 */
export const getQualityTableRule = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-model/list/model-rule`,
method: 'post',
data: params
})
/** 删除质检表规则 */
export const deleteQualityTableRule = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-model/conf/del?ruleConfGuid=${params}`,
method: 'delete',
data: params
})
/** 更新质检表规则的禁用和启用状态 */
export const updateRuleBizState = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-model/conf/upate-bizstate?ruleConfGuid=${params.ruleConfGuid}&bizState=${params.bizState}`,
method: 'post',
})
/** 获取数据库表列表 */
export const getDatabase = (params) => request({
url: `${import.meta.env.VITE_APP_API_BASEURL}/data-source/get-source-list`,
method: 'post',
data: params
})
/** 新建质检表,获取主题域分层的主题表树结构 */
export const getSubjectTableTree = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/data-catalog-directory/directory-tree-list`,
method: 'post',
data: params
})
/** 新建质检表,获取主题域分层的主题表树结构 */
export const getSubjectTableByDomain = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/data-catalog-subject/list-by-domain-guid?domainGuid=${params}`,
method: 'get',
data: params
})
/** 获取主题表的字段列表 */
export const getSubjectFields = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/data-catalog-subject/field/list?subjectGuid=${params}`,
method: 'get',
})
/** 表的逻辑条件和sql检验。 */
export const validateSubjectTableRule = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/sql-operate/check-sql`,
method: 'post',
data: params
})
/** 自定义sql检验 */
export const validateCustomSql = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-model/conf/check-custom-sql`,
method: 'post',
data: params
})
/** 批量验证过滤条件 */
export const batchValidateSubjectTableRule = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/sql-operate/batch-check-sql`,
method: 'post',
data: params
})
/** 保存质检表 */
export const saveQualityTable = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-model/add`,
method: 'post',
data: params
})
// 获取规则类型的接口
export const getRuleTypeList = () => request({
url:`${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-rule/list`,
method: 'post',
data: {}
})
// 获取规则大类的接口
export const getLargeCategoryList = () => request({
url:`${import.meta.env.VITE_APP_API_BASEURL}/data-dict/get-data-list`,
method: 'post',
data: { paramCode: "LARGE-CATEGORY" }
})
// 获取规则小类的接口
export const getSmallCategoryList = () => request({
url:`${import.meta.env.VITE_APP_API_BASEURL}/data-dict/get-data-list`,
method: 'post',
data: { paramCode: "SMALL-CATEGORY" }
})
// 根据规则guid获取规则的详情信息。
export const getRuleConfDetail = (param) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-model/conf/detail?ruleConfGuid=${param}`,
method: 'get'
})
// 根据质检模型guid获取详情信息。
export const getModelDetail = (param) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-model/detail/${param}`,
method: 'get'
})
// 更新规则信息。
export const updateModelRule = (params) => request({
url:`${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-model/conf/update`,
method: 'post',
data: params
})
\ No newline at end of file
import request from "@/utils/request";
/** 根据类型获取方案列表 */
export const getPlanList = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-plan/list`,
method: 'post',
data: params
})
/** 删除方案 */
export const deletePlan = (guids) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-plan/del`,
method: 'delete',
data: guids
})
/** 更新指定方案的状态上线,下线。 */
export const updateQualityPlanState = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-plan/state-change?guid=${params.guid}&state=${params.state}`,
method: 'post'
})
/** 手动执行方案 */
export const executePlan = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-plan/exec-plan?planGuid=${params}`,
method: 'post'
})
/** 获取方案详情,用于编辑 */
export const getAssessPlanDetail = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-plan/detail/${params}`,
method: 'get'
})
/** 获取方案详情中的过滤条件,用于编辑 */
export const getPlanFilterDetail = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-plan/query-plan-filter?planGuid=${params}`,
method: 'get'
})
/** 获取方案查看详情列表数据。 */
export const getAssessDetailTableData = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-plan/query-exec-list`,
method: 'post',
data: params
})
/** 根据执行guid,获取方案执行详情。 */
export const getExecPlanDetailTableData = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-plan/query-exec-detail?planGuid=${params.planGuid}&planExecGuid=${params.planExecGuid}`,
method: 'get'
})
/** 获取方案详情中每个表的规则详细执行列表数据。 */
export const getAssessTableRulesData = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-plan/query-exec-table-detail?planExecGuid=${params.planExecGuid}&qualityModelGuid=${params.qualityModelGuid}`,
method: 'get'
})
/** 获取脏数据查询 */
export const getQueryDirtyData = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-plan/query-dirty-data`,
method: 'post',
data: params
})
/** 获取脏数据字段列表 */
export const getQueryDirtyFields = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-plan/query-dirty-data-column?qualityModelGuid=${params}`,
method: 'get'
})
/** 获取数据质量模型统计 */
export const getModelCountList = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-model/list/model-count`,
method: 'post',
data: params
})
/** 获取规则大类统计 */
export const getModelRuleCount = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-model/list/model-rule-category-count`,
method: 'post',
data: params
})
/** 根据modelGuid获取详细的规则统计 */
export const getModelRules = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-model/list/model-rule`,
method: 'post',
data: params
})
/** 检查质检评估方案名称是否重复 */
export const checkPlanExist = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-plan/exist?planName=${params}`,
method: 'get'
})
/** 获取有效的数据分组,用于评估 表选择 */
export const getValidGroup = () => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-model-group/valid-group-list`,
method: 'get'
})
/** 获取数据库列表 */
export const getModelDbGp = (dsGuid: any = null) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-model/list/model-db-gp` + (!dsGuid ? '' : `?dataSourceGuid=${dsGuid}`),
method: 'get'
})
/** 保存质量方案 */
export const saveQualityPlan = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-plan/add`,
method: 'post',
data: params
})
/** 更新质量方案 */
export const updateQualityPlan = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-plan/update`,
method: 'put',
data: params
})
/** 下载脏数据 */
export const downloadDirtyData = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-plan/down-dirty-data`,
method: 'post',
data: params,
responseType: 'blob'
})
/** 获取对应执行方案的规则详情 */
export const getRecordRuleConfDetail = (param) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-model-record/conf/detail?ruleConfGuid=${param.ruleConfGuid}&planExecGuid=${param.planExecGuid}`,
method: 'get'
});
\ No newline at end of file
/** 用于质量分析报告模块 */
import request from "@/utils/request";
/** 获取质量分析报告列表数据。 */
export const getQualityWordList = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-analysis-report/page-list`,
method: 'post',
data: params
})
/** 删除质量分析报告 */
export const deleteQualityWord = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-analysis-report/del`,
method: 'delete',
data: params
})
/** 添加质量报告 */
export const addQualityWord = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-analysis-report/add`,
method: 'post',
data: params
})
/** 更新质量报告 */
export const updateQualityWord = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-analysis-report/update`,
method: 'put',
data: params
})
/** 根据质量报告获取对应的执行日志。 */
export const getWordLogList = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-analysis-report/page-exec-list`,
method: 'post',
data: params
});
/** 获取质量分析报告的详细内容,根绝报告guid。 */
export const getReportDetail = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-analysis-report/get-report-data`,
method: 'post',
data: params
});
/** 获取数据质量一级指标得分统计 */
export const getLargeCategoryScore = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-analysis-report/get-largeCategory-score?reportExecGuid=${params}`,
method: 'get'
});
/** 获取方案执行明细 */
export const getPlanDetail= (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-analysis-report/query-exec-table-detail?reportExecGuid=${params.reportExecGuid}&planGuid=${params.planGuid}`,
method: 'get'
});
/** 获取方案执行表规则查看 */
export const getTableRuleDetail= (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-analysis-report/query-exec-table-rule-detail?reportExecGuid=${params}`,
method: 'get'
});
/** 手动执行报告 */
export const executeReport = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-analysis-report/exec?guid=${params}`,
method: 'get'
})
/** html转word接口 */
export const htmlToWord = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-analysis-report/download/html-to-word`,
method: 'postJsonD',
data: params,
responseType: 'blob'
});
/**上下线 */
export const stateChange = (params) => request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-analysis-report/state-change?guid=${params.guid}&state=${params.state}`,
method: 'post',
});
\ No newline at end of file
/** 通用的分页配置 */
export const commonPageConfig = {
limit: 50,
curr: 1,
sizes: [
{ label: "10", value: 10 },
{ label: "50", value: 50 },
{ label: "100", value: 100 },
{ label: "150", value: 150 },
{ label: "200", value: 200 },
]
}
\ No newline at end of file
......@@ -36,6 +36,10 @@ const pageCount = computed(() => {
return Math.ceil(props.pageInfo.rows / props.pageInfo.limit)
})
const pagerCount = computed(() => {
return props.pageInfo.pagerCount ?? 7;
})
const pageType = computed({
get: () => {
return props.pageInfo.type
......@@ -135,7 +139,7 @@ function inputPageJump(val) {
条数据</span>
</el-pagination>
<el-pagination small layout="prev, slot, next" :total="pageTotal" :default-page-size="pageLimit"
:page-count="pageCount" :current-page="parseInt(pageNum)" @current-change="pageCurrentChange">
:page-count="pageCount" :pager-count="pagerCount" :current-page="parseInt(pageNum)" @current-change="pageCurrentChange">
<div class="page_code">
<el-input class="pagnination" type="number" :min="1" :max="pageCount" v-model.trim="pageNumInput" size="small"
style="width: 40px" @input="handleInput" @change="inputPageJump" :disabled="pageCount <= 1" />
......@@ -162,7 +166,7 @@ function inputPageJump(val) {
}}</span>
条数据</span>
</el-pagination>
<el-pagination background small layout="prev, pager, next, slot" :total="pageTotal" :default-page-size="pageLimit"
<el-pagination background small layout="prev, pager, next, slot" :total="pageTotal" :default-page-size="pageLimit" :pager-count="pagerCount"
:page-count="pageCount" :current-page="pageCurr" @current-change="pageCurrentChange">
<div class="page_jumper">
<el-input class="pagnination" type="number" :min="1" :max="pageCount" v-model.trim="pageNumInput" size="small"
......@@ -237,4 +241,4 @@ function inputPageJump(val) {
padding: 0 8px;
}
}
</style>@/utils/common
\ No newline at end of file
</style>
\ No newline at end of file
......
import type { RouteRecordRaw } from 'vue-router'
function Layout() {
return import('@/layouts/index.vue')
}
const routes: RouteRecordRaw[] = [
{
path: '/data-meta/collect-task',
component: Layout,
meta: {
title: '采集任务',
icon: 'sidebar-videos',
},
children: [
{
path: '',
name: 'collectorTask',
component: () => import('@/views/data_meta/collectorTask.vue'),
meta: {
title: '采集任务',
sidebar: false,
breadcrumb: false,
cache: true
},
},
{
path: 'excution-log',
name: 'excutionLog',
component: () => import('@/views/data_meta/executionLog.vue'),
meta: {
title: '采集日志',
sidebar: false,
breadcrumb: false,
},
beforeEnter: (to, from) => {
if (to.query.name) {
to.meta.title = `采集日志-${to.query.name}`;
}
}
},
],
},
{
path: '/data-meta/metadata-query',
component: Layout,
meta: {
title: '元数据查询',
icon: 'sidebar-videos',
},
children: [
{
path: '',
name: 'metadataQuery',
component: () => import('@/views/data_meta/metadataQuery.vue'),
meta: {
title: '元数据查询',
sidebar: false,
breadcrumb: false,
cache: true
},
},
{
path: 'meta-sheet',
name: 'metaSheet',
component: () => import('@/views/data_meta/metaSheet.vue'),
meta: {
title: '元数据详情-',
sidebar: false,
breadcrumb: false,
cache: true,
reuse: true
},
beforeEnter: (to, from) => {
if (to.query.name) {
to.meta.title = `元数据详情-${to.query.name}`;
}
}
},
],
},
{
path: '/data-meta/metadata-lineage',
component: Layout,
meta: {
title: '元数据血缘',
icon: 'ep:grid',
},
children: [
{
path: 'analysis-view',
name: 'analysisView',
component: () => import('@/views/data_meta/analysisView.vue'),
meta: {
title: '查看血缘',
breadcrumb: false,
cache: true
},
},
{
path: 'change-detection',
name: 'changeDetection',
component: () => import('@/views/data_meta/changeDetection.vue'),
meta: {
title: '血缘变更检测',
breadcrumb: false,
cache: true
},
},
{
path: 'analysis-reports',
name: 'analysisReports',
component: () => import('@/views/data_meta/analysisReports.vue'),
meta: {
title: '血缘关系解析',
breadcrumb: false,
cache: true
},
},
],
},
]
export default routes
import type { RouteRecordRaw } from 'vue-router'
function Layout() {
return import('@/layouts/index.vue')
}
const routes: RouteRecordRaw[] = [
{
path: '/data-quality/quality-rules',
component: Layout,
meta: {
title: '质量规则管理',
icon: 'sidebar-videos',
},
children: [
{
path: '',
name: 'qualityRules',
component: () => import('@/views/data_quality/qualityRules.vue'),
meta: {
title: '质量规则管理',
sidebar: false,
breadcrumb: false,
cache: true
},
},
{
path: 'rule-model',
name: 'ruleModel',
component: () => import('@/views/data_quality/ruleModel.vue'),
meta: {
title: '新建质检表',
sidebar: false,
breadcrumb: false,
cache: true,
reuse: true
},
beforeEnter: (to, from) => {
if (to.query.groupGuid) {
to.meta.title = `新建质检表(${to.query.name})`;
to.meta.editPage = true;
}
}
},
{
path: 'rule-template',
name: 'ruleTemplate',
component: () => import('@/views/data_quality/ruleTemplate.vue'),
meta: {
title: '新建规则',
sidebar: false,
breadcrumb: false,
cache: true,
reuse: true
},
beforeEnter: (to, from) => {
if (to.query.modelGuid) {
to.meta.title = `新建规则(${to.query.name})`;
to.meta.editPage = true;
}
}
},
{
path: 'rule-model-edit',
name: 'ruleModelEdit',
component: () => import('@/views/data_quality/ruleModelEdit.vue'),
meta: {
title: '编辑',
sidebar: false,
breadcrumb: false,
cache: true,
reuse: true,
editPage: true
},
beforeEnter: (to, from) => {
if (to.query.guid) {
to.meta.title = `编辑-`;
}
}
},
{
path: 'import-file',
name: 'importFiles',
component: () => import('@/views/importFile.vue'),
meta: {
title: '文件导入',
sidebar: false,
breadcrumb: false,
cache: true,
reuse: true
},
}
],
},
{
path: '/data-quality/quality-assess',
component: Layout,
meta: {
title: '质量评估方案',
icon: 'sidebar-videos',
},
children: [
{
path: '',
name: 'qualityAssess',
component: () => import('@/views/data_quality/qualityAssess.vue'),
meta: {
title: '质量评估方案',
sidebar: false,
breadcrumb: false,
cache: true
},
},
{
path: 'assess-template',
name: 'assessTemplate',
component: () => import('@/views/data_quality/assessTemplate.vue'),
meta: {
title: '新建质量评估方案',
sidebar: false,
breadcrumb: false,
cache: true,
reuse: true,
editPage: true
},
beforeEnter: (to, from) => {
if (to.query.detail) {
to.meta.title = `方案详情-${to.query.planName}`;
to.meta.editPage = false;
} else if (to.query.planName) {
to.meta.title = `方案编辑-${to.query.planName}`;
}
}
},
{
path: 'assess-detail',
name: 'assessDetail',
component: () => import('@/views/data_quality/assessDetail.vue'),
meta: {
title: '查看结果',
sidebar: false,
breadcrumb: false,
cache: true,
reuse: true
},
beforeEnter: (to, from) => {
if (to.query.name) {
to.meta.title = `查看结果-${to.query.name}`;
}
}
},
{
path: 'assess-dirty',
name: 'assessDirty',
component: () => import('@/views/data_quality/assessDirty.vue'),
meta: {
title: '脏数据',
sidebar: false,
breadcrumb: false,
cache: true,
reuse: true
},
beforeEnter: (to, from) => {
if (to.query.name) {
to.meta.title = `脏数据-${to.query.name}`;
}
}
},
{
path: 'assess-log',
name: 'assessLog',
component: () => import('@/views/data_quality/assessLog.vue'),
meta: {
title: '执行日志',
sidebar: false,
breadcrumb: false,
cache: true,
reuse: true
},
beforeEnter: (to, from) => {
if (to.query.guid) {
to.meta.title = `日志-${to.query.name}`;
}
}
},
],
},
{
path: '/data-quality/quality-analysis',
component: Layout,
meta: {
title: '质量分析报告',
icon: 'ep:grid',
},
children: [
{
path: '',
name: 'qualityAnalysis',
component: () => import('@/views/data_quality/qualityAnalysis.vue'),
meta: {
title: '质量分析报告',
sidebar: false,
breadcrumb: false,
cache: true
},
},
{
path: 'analysis-log',
name: 'analysisLog',
component: () => import('@/views/data_quality/analysisLog.vue'),
meta: {
title: '执行日志',
sidebar: false,
breadcrumb: false,
cache: true,
reuse: true
},
beforeEnter: (to, from) => {
if (to.query.name) {
to.meta.title = `日志-${to.query.name}`;
}
}
},
{
path: 'analysis-report',
name: 'analysisReport',
component: () => import('@/views/data_quality/analysisReport.vue'),
meta: {
title: '分析报告',
sidebar: false,
breadcrumb: false,
cache: true,
reuse: true
},
beforeEnter: (to, from) => {
if (to.query.name) {
to.meta.title = `分析报告-${to.query.name}`;
}
}
},
],
}
]
export default routes
......@@ -2,6 +2,8 @@ import { setupLayouts } from 'virtual:meta-layouts'
import generatedRoutes from 'virtual:generated-pages'
import type { RouteRecordRaw } from 'vue-router'
import DataAssess from './modules/dataAsset';
import DataMeta from './modules/dataMeta';
import DataQuality from './modules/dataQuality';
import type { Route } from '#/global'
import useSettingsStore from '@/store/modules/settings'
......@@ -105,6 +107,22 @@ const asyncRoutes: Route.recordMainRaw[] = [
...DataAssess,
],
},
{
meta: {
title: '元数据',
},
children: [
...DataMeta,
],
},
{
meta: {
title: '数据质量',
},
children: [
...DataQuality,
],
}
]
const constantRoutesByFilesystem = generatedRoutes.filter((item) => {
......
......@@ -46,6 +46,6 @@ const useDataQualityStore = defineStore(
defaultPlanType
}
},
)
)
export default useDataQualityStore
\ No newline at end of file
......
<route lang="yaml">
name: analysisReports
</route>
<script lang="ts" setup name="analysisReports">
import { ref } from 'vue'
import { ElMessage, ElMessageBox } from "element-plus";
import Table from '@/components/Table/index.vue'
import TableTools from '@/components/Tools/table_tools.vue'
import {getAnalysisReportList,delAnalysisRepor,updateAnalysisRepor} from "@/api/modules/dataMetaService"
import { getImageContent } from "@/api/modules/queryService";
import Dialog from '@/components/Dialog/index.vue'
import { getDownloadUrl, download } from "@/utils/common";
import { useRouter } from 'vue-router';
const router = useRouter()
const page = ref({
limit: 50,
curr: 1,
sizes: [
{ label: "10", value: 10 },
{ label: "50", value: 50 },
{ label: "100", value: 100 },
{ label: "150", value: 150 },
{ label: "200", value: 200 },
],
analysisReportName: ''
});
const { proxy } = getCurrentInstance() as any;
const tableInfo = ref({
id: 'analysis-reports-table',
fields: [
{ label: "序号", type: "index", width: 56, align: "center" },
{ label: "血缘关系名称", field: "analysisReportName", width: 150 },
{ label: "数据源中文名称", field: "databaseChName", width: 150 },
{ label: "表名称", field: "table", width: 150 },
{ label: "创建人", field: "updateUserName", width: 140 },
{ label: "创建时间", field: "updateTime", width: 180 }
],
data: [],
page: {
type: "normal",
rows: 0,
...page.value,
},
actionInfo: {
label: "操作",
type: "btn",
width: 185,
fixed: 'right',
btns: (scope) => {
let btnsArr: any = [
{ label: "查看", value: "view" },
{ label: "下载", value: "export" },
{ label: "重命名", value: "rename" },
{ label: "删除", value: "delete" },
]
return btnsArr;
},
},
loading: false
})
const currTableData: any = ref({});
const formItems: any = ref([
{
label: '血缘关系名称',
type: 'input',
placeholder: '请输入',
field: 'analysisReportName',
default: '',
clearable: true,
required: true
},
])
const formRules: any = ref({
analysisReportName: [
{
required: true,
message: "请填写血缘关系名称",
trigger: "blur",
},
],
})
const formInfo = ref({
type: 'form',
title: '',
formInfo: {
id: 'add-dict-form',
items: formItems.value,
rules: formRules.value
}
})
const reportDialogRef = ref();
const dialogInfo = ref({
visible: false,
size: 500,
direction: "column",
header: {
title: "重命名",
},
type: '',
contents: [
formInfo.value,
],
footer: {
btns: [
{ type: "default", label: "取消", value: "cancel" },
{ type: "primary", label: "保存", value: "submit" },
],
},
});
const rowData:any = ref({})
const tableSearchItemList: any = ref([{
type: 'input',
label: '',
field: 'analysisReportName',
default: '',
maxlength: 50,
placeholder: '血缘关系名称',
clearable: true
}]);
const tableBtnClick = (scope, btn) => {
const type = btn.value;
let row = scope.row;
rowData.value = row
currTableData.value = row;
if (type == 'view') {
getImageContent(row.analysisReportUrl).then((res: any) => {
if (res && !res.msg) {
let name = row.analysisReportUrl;
var fileSuffix = name ? name.substring(name.lastIndexOf('.') + 1) : '';
if (fileSuffix === 'png') { //浏览器可以支持图片和pdf预览
let fileUrl = getDownloadUrl(res, name, fileSuffix);
let win = window.open(fileUrl, name);
win && (win.document.title = name);
} else {
download(res, row.analysisReportName, fileSuffix);
}
} else {
res?.msg && ElMessage.error(res?.msg);
}
});
} else if (type == 'export') {
getImageContent(row.analysisReportUrl).then((res: any) => {
if (res && !res.msg) {
let name = row.analysisReportUrl;
var fileSuffix = name ? name.substring(name.lastIndexOf('.') + 1) : '';
download(res, row.analysisReportName, fileSuffix);
} else {
res?.msg && ElMessage.error(res?.msg);
}
});
} else if (type == "rename") {
dialogInfo.value.visible = true
formItems.value[0].default = row.analysisReportName
} else if (type == "delete") {
open("此操作将永久删除, 是否继续?", "warning");
}
};
const dialogBtnClick = (btn,scope)=>{
if(btn.value==="cancel") {
dialogInfo.value.visible = false
} else {
const analysisReportName = reportDialogRef.value.dialogFormRef[0].formInline.analysisReportName;
if(analysisReportName){
console.log(analysisReportName)
updateAnalysisRepor({guid:rowData.value.guid,analysisReportName}).then((res:any)=>{
if(res.code===proxy.$passCode){
ElMessage.success("血缘关系名称修改成功!")
getTableData()
dialogInfo.value.visible = false
} else {
ElMessage.error(res.msg)
}
}).catch((res:any)=>{
ElMessage.error(res.msg)
})
}
}
}
const open = (msg, type) => {
ElMessageBox.confirm(msg, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: type,
}).then(() => {
let guid = currTableData.value.guid;
delAnalysisRepor([guid]).then((res:any)=>{
if(res.code===proxy.$passCode){
getTableData()
ElMessage.success("删除成功")
} else {
ElMessage.error(res.msg)
}
}).catch((res)=>{
ElMessage.error(res.msg)
})
});
};
const tablePageChange = (info) => {
page.value.curr = Number(info.curr);
page.value.limit = Number(info.limit);
getTableData()
};
const getTableData = ()=>{
tableInfo.value.loading = true
getAnalysisReportList({pageIndex:page.value.curr,pageSize:page.value.limit, analysisReportName: page.value.analysisReportName}).then((res:any)=>{
if(res.code===proxy.$passCode){
tableInfo.value.data = res.data.records || []
tableInfo.value.page.rows = res.data.totalRows
tableInfo.value.page.curr = res.data.pageIndex
tableInfo.value.page.limit = res.data.pageSize
tableInfo.value.loading = false
} else {
ElMessage.error(res.msg)
tableInfo.value.loading = false
}
})
}
const toSearch = (val: any, clear: boolean = false) => {
if (clear) {
page.value.analysisReportName = '';
} else {
page.value.analysisReportName = val.analysisReportName;
}
page.value.curr = 1;
getTableData();
};
onActivated(() => {
getTableData()
});
</script>
<template>
<div class="container_wrap">
<div class="table_tool_wrap">
<TableTools :searchItems="tableSearchItemList" :init="false" searchId="report-table-search" @search="toSearch" />
</div>
<div class="table_panel_wrap full">
<Table :tableInfo="tableInfo" @tableBtnClick="tableBtnClick" @tablePageChange="tablePageChange" />
</div>
<Dialog ref="reportDialogRef" :dialogInfo="dialogInfo" @btnClick="dialogBtnClick" />
</div>
</template>
<style scoped lang="scss">
:deep(.el-overlay .el-form .el-form-item) {
width: calc(100%);
}
</style>
\ No newline at end of file
<route lang="yaml">
name: executionLog
</route>
<script lang="ts" setup name="excutionLog">
import { ref } from "vue";
import { ElMessage } from "element-plus";
import Table from "@/components/Table/index.vue";
import Drawer from '@/components/Drawer/index.vue'
import {
getMetaDataTaskLog,getMetacompareList,getMetaChangeRecord
} from "@/api/modules/dataMetaService"
import { useRouter, useRoute } from "vue-router";
import Moment from 'moment';
import { changeNum } from '@/utils/common'
import { TableColumnWidth } from "@/utils/enum";
const { proxy } = getCurrentInstance() as any;
const router = useRouter();
const route = useRoute();
const collectTaskGuid: any = ref(route.query.guid);
const collectTaskType: any = ref(route.query.type);
const page = ref({
limit: 50,
curr: 1,
sizes: [
{ label: "10", value: 10 },
{ label: "50", value: 50 },
{ label: "100", value: 100 },
{ label: "150", value: 150 },
{ label: "200", value: 200 },
],
});
const originFields: any = ref([
{ label: "采集任务名称", field: "collectTaskName", width: 140 },
{ label: "数据源名称", field: "datasourceName", width: 160 },
{ label: "执行计划", field: "collectType", type: 'filter', width: 90 },
{ label: "执行状态", field: "execResult", width: 100, type: "tag", align: 'center' },
{
label: "执行时间", field: "execTime", width: TableColumnWidth.DATETIME, getName: (scope) => {
let row = scope.row;
return row.execTime && Moment(row.execTime).format('YYYY-MM-DD HH:mm:ss');
}
},
{
label: "耗时(秒)", field: "execDuration", width: TableColumnWidth.EXECDURATION, align: "right", getName: (scope) => {
return scope.row.execDuration != null ? changeNum(scope.row.execDuration ?? 0) : '--';
}
},
]);
const tableInfo = ref({
id: "user-authority-table",
fields: [],
data: [],
page: {
type: "normal",
rows: 0,
...page.value,
},
actionInfo: {
label: "操作",
type: "btn",
width: 150,
fixed: 'right',
btns: (scope)=>{
return [
{ label: "元数据变更记录", value: "log_detail",disabled:scope.row['execResult']==='N' || scope.row['execResult']==='R'},
]
}
},
loading: false
});
const metaChangePage: any = ref({
limit: 50,
curr: 1,
sizes: [
{ label: "10", value: 10 },
{ label: "50", value: 50 },
{ label: "100", value: 100 },
{ label: "150", value: 150 },
{ label: "200", value: 200 },
],
metaTaskName: '',
changeState: null,
changeType: ''
});
const formTable = ref({
type: "table",
title: "",
col: 'no-margin',
tableInfo: {
id: "task-detail-table",
minHeight: 'unset',
fields: [
{ label: "序号", type: "index", width: 56, align: "center", fixed: "left" },
{ label: "表中文名称", field: "tableChName", width: 180, },
{ label: "表英文名称", field: "tableName", width: 180, },
{ label: "元数据名称", field: "metaName", width: 180, },
{
label: "元数据类型", field: "metaType", width: 100, getName: (scope) => {
if (!scope.row.metaType) {
return '--';
}
return scope.row.metaType == 'TABLE' ? '表' : (scope.row.metaType == 'INDEX' ? '索引' : (scope.row.metaType == 'PRI' ? '主键' : '字段'));
}
},
{
label: "变更类型", field: "metaChangeType", width: 100, getName: (scope) => {
if (!scope.row.metaChangeType) {
return '--';
}
return scope.row.metaChangeType == 'ADD' ? '新增' : (scope.row.metaChangeType == 'DELETE' ? '删除' : '修改');
}
},
{ label: "变化", field: "metaChangeType", width: 100,type: 'popover',value:'metaCurrValue',column:[{field:"item",label:"变化信息",width:"150"},{field:"oldValue",label:"原值",width:"150"},{field:"newValue",label:"现值",width:"150"}] },
// { label: "原值", field: "metaOldValue", width: 120 },
{ label: "元数据采集时间", field: "changeTime", width: 180, },
// { label: "状态", field: "changeTime", width: 180, },
// { label: "操作时间", field: "changeTime", width: 180, },
],
data: [],
loading: false,
page:{
rows:0,
...metaChangePage.value
},
popoverData:[],
popoverloading:false,
showPage: true,
actionInfo: {
show: false
},
},
})
const drawerInfo: any = ref({
visible: false,
direction: "rtl",
modalClass: "wrap_width_auto",
size: 700,
modalClose:true,
header: {
title: "",
},
type: '',
container: {
contents: [
formTable.value,
],
},
footer: {
visible: false,
btns: [
{ type: 'default', label: '取消', value: 'cancel' },
{ type: 'primary', label: '确认 ', value: 'save' },
]
},
})
const currRow:any = ref({})
const getFirstPageData = () => {
page.value.curr = 1
toSearch({})
}
const toSearch = (val: any, clear: boolean = false) => {
let params: any = Object.keys(val).length ? { ...val } : {}
params.pageIndex = page.value.curr;
params.pageSize = page.value.limit;
params.collectTaskGuid = collectTaskGuid.value
getTableData(params);
};
const getTableData = (params) => {
tableInfo.value.loading = true
getMetaDataTaskLog(params).then((res: any) => {
if (res.code == proxy.$passCode) {
const data = res.data || {}
tableInfo.value.data = data.records || []
tableInfo.value.page.limit = data.pageSize
tableInfo.value.page.curr = data.pageIndex
tableInfo.value.page.rows = data.totalRows
} else {
ElMessage({
type: 'error',
message: res.msg,
})
}
tableInfo.value.loading = false
}).catch(xhr => {
tableInfo.value.loading = false
})
};
const tablePageChange = (info) => {
page.value.curr = Number(info.curr);
page.value.limit = Number(info.limit);
toSearch({})
};
const getMetaChangeTableData = ()=>{
formTable.value.tableInfo.loading = true
getMetaChangeRecord(Object.assign({execGuid:currRow.value.guid},{pageIndex:metaChangePage.value.curr,pageSize:metaChangePage.value.limit})).then((res: any) => {
formTable.value.tableInfo.loading = false
if (res.code == proxy.$passCode && res.data) {
let data = res.data || {}
formTable.value.tableInfo.data = data.records || []
formTable.value.tableInfo.page.rows = data.totalRows
const contents = [formTable.value]
drawerInfo.value.container.contents = contents
drawerInfo.value.footer.visible = false
drawerInfo.value.visible = true
} else {
ElMessage({
type: "error",
message: '未获取到对应人员信息',
});
}
})
}
const drawerTableClick = (scope,btn)=>{
drawerInfo.value.container.contents[0].tableInfo.popoverloading = true
getMetacompareList(scope.row.guid).then((res:any)=>{
drawerInfo.value.container.contents[0].tableInfo.popoverloading = false
drawerInfo.value.container.contents[0].tableInfo.popoverData = res.data
})
}
const tableBtnClick = (scope, btn) => {
const type = btn.value;
const row = scope.row;
currRow.value = row
if (type == 'log_detail') {
drawerInfo.value.header.title = row.collectTaskName;
drawerInfo.value.type = type
formTable.value.tableInfo.data = []
const contents = [formTable.value]
drawerInfo.value.container.contents = contents
drawerInfo.value.footer.visible = false
drawerInfo.value.visible = true
getMetaChangeTableData()
}
};
const drawerBtnClick = (btn, info) => {
if (btn.value == 'cancel') {
drawerInfo.value.visible = false
}
}
const metaChangeTablePageChange = (info) => {
metaChangePage.value.curr = Number(info.curr);
metaChangePage.value.limit = Number(info.limit);
formTable.value.tableInfo.page.limit = metaChangePage.value.limit;
formTable.value.tableInfo.page.curr = metaChangePage.value.curr;
getMetaChangeTableData();
};
onBeforeMount(() => {
if (collectTaskType.value == '1') {
originFields.value.splice(2, 0, { label: "同步策略", field: "collectMode", type: 'filter', width: 90 },)
}
tableInfo.value.fields = originFields.value;
getFirstPageData();
});
</script>
<template>
<div class="container_wrap">
<div class="table_panel_wrap">
<Table :tableInfo="tableInfo" @tableBtnClick="tableBtnClick" @tablePageChange="tablePageChange" />
</div>
<Drawer :drawerInfo="drawerInfo" @drawerBtnClick="drawerBtnClick" @drawerTableBtnClick="drawerTableClick" @drawerTablePageChange="metaChangeTablePageChange" />
</div>
</template>
<style lang="scss" scoped>
.container_wrap {
padding: 0;
.table_panel_wrap {
height: 100%;
padding: 16px 16px 0;
}
}
:deep(.el-drawer) {
.el-drawer__body {
padding: 10px 10px 0px 10px;
}
.drawer_panel {
height: 100%;
.table_panel_wrap {
height: 100%;
}
}
}
</style>
\ No newline at end of file
<route lang="yaml">
name: analysisLog
</route>
<script lang="ts" setup name="analysisLog">
import { ref } from "vue";
import { useRouter, useRoute } from "vue-router";
import Table from "@/components/Table/index.vue";
import { getWordLogList } from "@/api/modules/dataQualityWord";
import { ElMessage } from "element-plus";
const { proxy } = getCurrentInstance() as any;
const router = useRouter();
const route = useRoute();
const guid = route.query.guid;
const wordName = route.query.name;
const page = ref({
limit: 50,
curr: 1,
sizes: [
{ label: "10", value: 10 },
{ label: "50", value: 50 },
{ label: "100", value: 100 },
{ label: "150", value: 150 },
{ label: "200", value: 200 },
],
});
const tableInfo = ref({
id: "word-log-table",
loading: false,
fields: [
{ label: "报告名称", field: "analysisReportName", width: 230 },
{
label: "方案类型", field: "analysisReportType", width: 100, getName: (scope) => {
let planType = scope.row.analysisReportType;
return planType == 1 ? '表' : (planType == 2 ? '数据库' : (planType == 4 ? '数据同步' : '分组'));
}
},
{ label: "报告对象", field: "qualityModelName", width: 180, },
{ label: "质量评分", field: "qualityScore", width: 100, align: "right" },
{ label: "最后执行时间", field: "execTime", width: 180, },
{ label: "执行状态", field: "execResult", type: "tag", width: 120, align: "center" },
],
data: [],
page: {
type: "normal",
rows: 0,
...page.value,
},
actionInfo: {
label: "操作",
type: "btn",
width: 100,
fixed: 'right',
btns: (scope) => {
return [{ label: "查看报告", value: "reportView", disabled: scope.row['execResult'] != 'Y' }];
}
}
});
const getTableData = () => {
tableInfo.value.loading = true;
getWordLogList({ pageIndex: page.value.curr, pageSize: page.value.limit, reportGuid: guid }).then((res: any) => {
tableInfo.value.loading = false;
if (res.code == proxy.$passCode) {
const data = res.data || {}
tableInfo.value.data = data.records || []
tableInfo.value.page.limit = data.pageSize
tableInfo.value.page.curr = data.pageIndex
tableInfo.value.page.rows = data.totalRows
} else {
ElMessage.error(res.msg);
}
})
};
const tableBtnClick = (scope, btn) => {
const type = btn.value;
const row = scope.row;
if (type == 'reportView') {
router.push({
name: 'analysisReport',
query: {
planGuid: row.planGuid,
reportExecGuid: row.guid,
name: wordName
}
});
}
};
onBeforeMount(() => {
getTableData();
});
</script>
<template>
<div class="container_wrap">
<div class="table_panel_wrap">
<Table :tableInfo="tableInfo" @tableBtnClick="tableBtnClick" />
</div>
</div>
</template>
<style lang="scss" scoped>
.container_wrap {
padding: 0;
.table_panel_wrap {
height: 100%;
padding: 16px 16px 0;
}
}
</style>
\ No newline at end of file
<route lang="yaml">
name: assessDirty
</route>
<script lang="ts" setup name="assessDirty">
import { ref } from "vue";
import { calcColumnWidth } from "@/utils/index";
import Moment from 'moment';
import {
getQueryDirtyData,
getQueryDirtyFields,
downloadDirtyData
} from '@/api/modules/dataQualityAssess';
import { download } from '@/utils/common'
import { ElMessage } from "element-plus";
import { TableColumnWidth } from "@/utils/enum";
const { proxy } = getCurrentInstance() as any;
const route: any = useRoute();
const planExecGuid = route.query.planExecGuid;
const qualityModelGuid = route.query.qualityModelGuid;
const name = route.query.name;
const dirtyDataLoading = ref(false);
const dirtyData = ref([{
guid: 1,
}, {
guid: '2',
isDirty: true
}, {
guid: 3
}]);
const dirtyDataFields: any = ref([{
enName: 'guid',
chName: '主键',
dataType: 'string'
}]);
/** 脏数据下载 */
const exportData = () => {
if (!dirtyData.value.length || !dirtyDataFields.value.length) {
ElMessage.error('当没有可下载的脏数据');
return;
}
downloadDirtyData({
planExecGuid: planExecGuid,
qualityModelGuid: qualityModelGuid
}).then((res: any) => {
if (res && !res.msg) {
download(res, `脏数据-${name}.xlsx`, 'excel');
} else {
res?.msg && ElMessage.error(res?.msg);
}
})
}
const getTableData = () => {
dirtyData.value = [];
dirtyDataLoading.value = true;
let ps1 = getQueryDirtyData({
pageSize: pageInfo.value.limit,
pageIndex: pageInfo.value.curr,
qualityModelGuid: qualityModelGuid,
planExecGuid: planExecGuid,
}).then((res: any) => {
if (res.code == proxy.$passCode) {
let data = res.data || {};
dirtyData.value = data.records || [];
pageInfo.value.curr = data.pageIndex;
pageInfo.value.rows = data.totalRows || 0;
} else {
ElMessage.error(res.msg);
}
});
let ps2 = getQueryDirtyFields(qualityModelGuid).then((res: any) => {
if (res.code == proxy.$passCode) {
dirtyDataFields.value = res.data.fields || [];
} else {
ElMessage.error(res.msg);
}
})
Promise.all([ps1, ps2]).then(res => {
dirtyDataLoading.value = false;
});
};
onBeforeMount(() => {
getTableData();
});
const pageInfo = ref({
limit: 50,
curr: 1,
sizes: [
{ label: "10", value: 10 },
{ label: "50", value: 50 },
{ label: "100", value: 100 },
{ label: "150", value: 150 },
{ label: "200", value: 200 },
],
type: "normal",
rows: 0,
})
const pageChange = (info) => {
pageInfo.value.curr = Number(info.curr);
pageInfo.value.limit = Number(info.limit);
getTableData();
}
const formatterPreviewDate = (row, info) => {
let enName = info.enName;
let v = row[enName]?.value;
if (v === "" || v === 0) {
return v;
}
if (v == null) {
return '--';
}
if (info.dataType === 'datetime') {
return Moment(v).format('YYYY-MM-DD HH:mm:ss');
}
if (info.dataType === 'date') {
if (isNaN(<any>(new Date(v)))) {
return Moment(parseInt(v)).format('YYYY-MM-DD');
} else {
return Moment(v).format('YYYY-MM-DD');
}
}
return v;
};
const getTextAlign = (field) => {
if (field.dataType === 'decimal' || field.dataType === 'int' || field.dataType == 'bit' || field.dataType == 'tinyint') {
return 'right';
}
return 'left'
}
/** otherWidth表示使用标题宽度时添加标题排序图标等宽度 */
const calcTableColumnWidth = (data: any[], prop, title, otherWidth = 0) => {
let d: any[] = [];
data.forEach((dt) => d.push(dt[prop]));
return calcColumnWidth(
d,
title,
{
fontSize: 14,
fontFamily: "SimSun",
},
{
fontSize: 14,
fontFamily: "SimSun",
},
otherWidth
);
};
/** 每列字段对应的列宽计算结果。 */
const originTableFieldColumn: any = ref({
guid: 140
});
watch(
() => dirtyData.value,
(val: any[], oldVal) => {
if (!dirtyDataFields.value?.length) {
originTableFieldColumn.value = {};
return;
}
originTableFieldColumn.value = {};
dirtyDataFields.value.forEach((field, index) => {
originTableFieldColumn.value[field.enName] = calcTableColumnWidth(
val?.map(v => {
let json = {};
for (const k in v) {
json[k] = v[k]?.value
}
return json;
}) || [],
field.enName,
field.chName,
24
);
});
}
);
const handleDityCellClass = ({ row, column, rowIndex, columnIndex }) => {
let v = dirtyData.value[rowIndex][column.property];
if (v?.checkInfo?.length) {
return 'dirty-cell-bg';
}
}
</script>
<template>
<div class="container_wrap">
<div class="table_tool_wrap">
<div class="tools_btns">
<el-button type="primary" @click="exportData" v-preReClick>脏数据下载</el-button>
</div>
</div>
<div class="table_panel_wrap">
<el-table key="guid" v-loading="dirtyDataLoading" :data="dirtyData" border tooltip-effect="light" style="
width: 100%;
min-width: 200px;
max-width: 100%;
height: calc(100% - 44px);
display: inline-block;
" stripe :cell-class-name="handleDityCellClass">
<el-table-column v-for="(field, index) in dirtyDataFields" :key="field.enName" :prop="field.enName"
:label="field.chName" :width="field.dataType === 'datetime'
? TableColumnWidth.DATETIME
: field.dataType === 'date'
? TableColumnWidth.DATE
: originTableFieldColumn[field.enName]
" :align="getTextAlign(field)" :header-align="getTextAlign(field)" :show-overflow-tooltip="true"
>
<template #default="scope">
<el-tooltip v-if="scope.row[field.enName].checkInfo?.length" placement="bottom-start" effect="light"
popper-class="table_tooltip" trigger="click">
<template #content>
<div style="width: 236px; text-align: justify">
<p class="tips_title">不符合规则</p>
<p v-for="(item) in (scope.row[field.enName].checkInfo || [])">{{ item }}</p>
</div>
</template>
<span class="dirty-cell-tooltip">{{ formatterPreviewDate(scope.row, field) }}</span>
</el-tooltip>
<span v-else>{{ formatterPreviewDate(scope.row, field) }}</span>
</template>
</el-table-column>
</el-table>
<PageNav :class="[pageInfo.type]" :pageInfo="pageInfo" @pageChange="pageChange" />
</div>
</div>
</template>
<style lang="scss" scoped>
.table_tool_wrap {
width: 100%;
height: 44px;
padding: 8px;
.tools_btns {
padding: 0;
}
}
.table_panel_wrap {
width: 100%;
height: calc(100% - 44px);
padding: 0 8px;
}
:deep(.el-table) {
.dirty-cell-bg {
background: #FFF1D4 !important;
.cell.el-tooltip {
padding: 0px;
}
}
.dirty-cell-tooltip {
width: 100%;
min-height: 24px;
display: block;
overflow: hidden;
text-overflow: ellipsis;
padding: 0 12px;
}
}
</style>
\ No newline at end of file
<route lang="yaml">
name: assessLog
</route>
<script lang="ts" setup name="assessLog">
import { ref } from "vue";
import { useRouter, useRoute } from "vue-router";
import Table from "@/components/Table/index.vue";
import Drawer from "@/components/Drawer/index.vue";
import {
getAssessDetailTableData,
} from '@/api/modules/dataQualityAssess';
import { ElMessage } from "element-plus";
import { changeNum } from '@/utils/common';
import {TableColumnWidth} from "@/utils/enum"
const { proxy } = getCurrentInstance() as any;
const router = useRouter();
const route = useRoute();
/** 方案guid */
const planGuid = route.query.guid;
const planName = route.query.name;
const execType = route.query.type;
const page = ref({
limit: 50,
curr: 1,
sizes: [
{ label: "10", value: 10 },
{ label: "50", value: 50 },
{ label: "100", value: 100 },
{ label: "150", value: 150 },
{ label: "200", value: 200 },
],
});
const tableInfo = ref({
id: "user-authority-table",
fields: [
{ type:"index", width: TableColumnWidth.INDEX, align:"center",label: "序号" },
{ label: "质检执行结果", field: "execResult", type: "tag", width: 120, align: "center" },
{ label: "评估时间", field: "execTime", width: 180, },
{
label: "耗时(秒)", field: "execDuration", align: "right", width: 100, getName: (scope) => {
return scope.row.execDuration != null ? changeNum(scope.row.execDuration ?? 0) : '--';
}
},
{
label: "规则数", field: "ruleNum", width: 100, align: "right", getName: (scope) => {
return scope.row.ruleNum != null ? changeNum(scope.row.ruleNum ?? 0) : '--';
}
},
{
label: "评估总数", field: "totalNum", width: 100, align: "right", getName: (scope) => {
return scope.row.totalNum != null ? changeNum(scope.row.totalNum ?? 0) : '--';
}
},
{
label: "合格条数", field: "qualifiedNum", width: 100, align: "right", getName: (scope) => {
return scope.row.qualifiedNum != null ? changeNum(scope.row.qualifiedNum ?? 0) : '--';
}
},
{
label: "不合格条数", field: "unqualifiedNum", width: 100, align: "right", getName: (scope) => {
return scope.row.unqualifiedNum != null ? changeNum(scope.row.unqualifiedNum ?? 0) : '--';
}
},
{
label: "合格率", field: "qualifiedRate", width: 100, align: "right", getName: (scope) => {
return scope.row.qualifiedRate != null ? ((scope.row.qualifiedRate ?? 0).toFixed(2) + '%') : '--';
}
},
],
loading: false,
data: [],
page: {
type: "normal",
rows: 0,
...page.value,
},
actionInfo: {
label: "操作",
type: "btn",
width: 140,
fixed: 'right',
btns: [
{ label: "查看结果", value: "resultView" },
{ label: "日志", value: "log" }
],
}
});
const formTable = ref({
type: "table",
title: "",
col: 'no-margin',
tableInfo: {
id: "log-detail-table",
loading: false,
fields: [
{ label: "执行时间", field: "changeTime", width: 140, },
{ label: "日志类型", field: "metaCurrValue", width: 120 },
{ label: "日志级别", field: "collectTaskName", width: 110 },
{ label: "执行步骤", field: "updateType", width: 240 },
],
data: [],
showPage: false,
actionInfo: {
show: false
},
},
})
const drawerInfo: any = ref({
visible: false,
direction: "rtl",
modalClass: "wrap_width_auto",
size: 650,
header: {
title: "日志详情",
},
type: '',
container: {
contents: [
formTable.value,
],
},
footer: {
visible: false,
},
})
const tablePageChange = (info) => {
page.value.curr = Number(info.curr);
page.value.limit = Number(info.limit);
getTableData();
};
const getTableData = () => {
tableInfo.value.loading = true;
getAssessDetailTableData({ pageSize: page.value.limit, pageIndex: page.value.curr, planGuid: planGuid }).then((res: any) => {
tableInfo.value.loading = false;
if (res.code == proxy.$passCode) {
const data = res.data || {}
tableInfo.value.data = data.records || []
tableInfo.value.page.limit = data.pageSize ?? 50;
tableInfo.value.page.curr = data.pageIndex
tableInfo.value.page.rows = data.totalRows ?? 0;
} else {
ElMessage.error(res.msg);
}
});
};
const tableBtnClick = (scope, btn) => {
const type = btn.value;
const row = scope.row;
if (type == 'resultView') {
if(!!execType) {
router.push({
name: 'syncAssessDetail',
query: {
name: planName,
planGuid: row.planGuid,
planExecGuid: row.planExecGuid
}
});
} else {
router.push({
name: 'assessDetail',
query: {
name: planName,
planGuid: row.planGuid,
planExecGuid: row.planExecGuid
}
});
}
} else if (type == 'log') {
const params = {
logGuid: row.guid
}
drawerInfo.value.visible = true
// formTable.value.tableInfo.loading = true;
// getLogDetail(params).then((res: any) => {
// formTable.value.tableInfo.loading = false;
// if (res.code == proxy.$passCode && res.data) {
// const data = res.data
// formTable.value.tableInfo.data = data
// drawerInfo.value.container.contents[0].listInfo.data = data
// drawerInfo.value.visible = true
// } else {
// ElMessage({
// type: "info",
// message: res.msg,
// });
// }
// })
}
};
const drawerBtnClick = (btn) => {
drawerInfo.value.visible = false;
};
onBeforeMount(() => {
getTableData();
});
</script>
<template>
<div class="container_wrap">
<div class="table_panel_wrap">
<Table :tableInfo="tableInfo" @tableBtnClick="tableBtnClick" @tablePageChange="tablePageChange" />
</div>
<Drawer :drawerInfo="drawerInfo" @drawerBtnClick="drawerBtnClick" />
</div>
</template>
<style lang="scss" scoped>
.container_wrap {
padding: 0;
.table_panel_wrap {
height: 100%;
padding: 16px 16px 0;
}
}
:deep(.el-drawer) {
.drawer_panel {
height: 100%;
.table_panel_wrap {
height: 100%;
}
}
}
</style>
\ No newline at end of file
<route lang="yaml">
name: ruleModelEdit
</route>
<script lang="ts" setup name="ruleModelEdit">
import { ref } from "vue";
import ruleForm from "../data_quality/ruleForm.vue";
import { useRouter, useRoute } from "vue-router";
import {
getRuleConfDetail,
getRuleTypeList,
getSmallCategoryList,
getLargeCategoryList,
updateModelRule
} from '@/api/modules/dataQuality';
import { ElMessage, ElMessageBox } from "element-plus";
import useUserStore from "@/store/modules/user";
import useDataQualityStore from "@/store/modules/dataQuality";
const userStore = useUserStore();
const dataQualityStore = useDataQualityStore();
const { proxy } = getCurrentInstance() as any;
const router = useRouter();
const route = useRoute();
const ruleGuid = route.query.guid;
const fullPath = route.fullPath;
const fullScreenLoading = ref(false);
const detailLoading = ref(false);
const detailInfo: any = ref({});
const toSubjectTables: any = ref([]);
const ruleType = ref('');
const ruleFormRef = ref();
const cancel = () => {
ElMessageBox.confirm(
"当前页面尚未保存,确定放弃修改吗?",
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}
)
.then(() => {
userStore.setTabbar(userStore.tabbar.filter((tab: any) => tab.fullPath !== fullPath));
router.push({
name: 'qualityRules',
});
})
.catch(() => {
ElMessage({
type: "info",
message: "已取消",
});
});
}
/** 将新建规则之后转化为对应质检表的规则。 */
const transformRulesInfo = (info: any) => {
if (info.ruleCode == "volatility_check") {//表行数波动率。
return Object.assign({}, info, {
guid: ruleGuid,
qualityModelGuid: detailInfo.value.qualityModelGuid,
ruleCode: detailInfo.value.ruleCode,
});
}
else if (info.ruleCode == 'null_value_check' || info.ruleCode == 'repeate_data_check') {
return Object.assign({}, info, {
guid: ruleGuid,
qualityModelGuid: detailInfo.value.qualityModelGuid,
ruleCode: detailInfo.value.ruleCode,
ruleField: info.modelFields[detailInfo.value.subjectZhName] || []
});
} else if (info.ruleCode === 'logic_check') {
let subjectName = detailInfo.value.subjectName;
let fields = info.ruleFields[subjectName];
return Object.assign({}, info, {
guid: ruleGuid,
qualityModelGuid: detailInfo.value.qualityModelGuid,
ruleCode: detailInfo.value.ruleCode,
ruleField: [{
guid: fields.guid,
enName: fields.enName,
chName: fields.chName
}],
conditionSql: info.conditionSqls?.[subjectName],
conditionSqls: '',
ruleFields: ''
});
} else if (info.ruleCode === 'custom_sql') {
let subjectGuid = detailInfo.value.subjectGuid;
return Object.assign({}, info, {
guid: ruleGuid,
qualityModelGuid: detailInfo.value.qualityModelGuid,
ruleCode: detailInfo.value.ruleCode,
customSql: info.customSqls?.[detailInfo.value.subjectName],
ruleField: info.ruleFields?.[detailInfo.value.subjectName]?.map(f => {
return {
enName: f
}
}) || [],
fieldSelects: info.sqlFieldsList?.[detailInfo.value.subjectName] || [],
customSqls: '',
ruleFields: ''
});
} else if (info.ruleCode == 'rows_check') {
return Object.assign({}, info, {
guid: ruleGuid,
qualityModelGuid: detailInfo.value.qualityModelGuid,
ruleCode: detailInfo.value.ruleCode,
contrastSubjectGuid: info.rows[0].contrastSubjectGuid,
differenceRange: info.rows[0].differenceRange,
rows: ''
});
}
}
const save = () => {
ruleFormRef.value?.ruleFormRef?.ruleFormRef?.validate((valid) => {
if (valid) {
let v = ruleFormRef.value?.getFormInfo();
let params = transformRulesInfo(v);
fullScreenLoading.value = true;
updateModelRule(params).then((res: any) => {
fullScreenLoading.value = false;
if (res.code == proxy.$passCode) {
ElMessage.success(`【${params.ruleConfName}】` + '质量规则编辑成功');
//跳到对应的分组下
router.push({
name: 'qualityRules'
});
userStore.setTabbar(userStore.tabbar.filter((tab: any) => tab.fullPath !== fullPath));
dataQualityStore.setModelGuid(params.qualityModelGuid);
} else {
ElMessage.error(res.msg);
}
})
}
});
}
const getRuleDetailInfo = () => {
detailLoading.value = true;
getRuleConfDetail(ruleGuid).then((res: any) => {
detailLoading.value = false;
if (res.code == proxy.$passCode) {
let data = res.data || {};
detailInfo.value = data;
ruleType.value = detailInfo.value.ruleCode;
toSubjectTables.value = [{
guid: detailInfo.value.subjectGuid, //编辑的时候显示的是主题表
enName: detailInfo.value.subjectName,
chName: detailInfo.value.subjectZhName,
label: `${detailInfo.value.subjectName}(${detailInfo.value.subjectZhName})`
}]
detailInfo.value.qualityModelGuids = [detailInfo.value.subjectGuid];
if (fullPath === route.fullPath) {
document.title = `编辑-${data.ruleConfName}(${data.subjectZhName})`;
}
let tab: any = userStore.tabbar.find((tab: any) => tab.fullPath === fullPath);
if (tab) {
tab.meta.title = `编辑-${data.ruleConfName}(${data.subjectZhName})`;
}
} else {
ElMessage.error(res.msg);
}
})
}
const ruleTypeList = ref([]);
const smallCategoryList = ref([]);
const largeCategoryList = ref([]);
onBeforeMount(() => {
getRuleDetailInfo();
getRuleTypeList().then((res: any) => {
if (res.code == proxy.$passCode) {
ruleTypeList.value = res.data?.map((d: any) => {
d.label = d.ruleName;
d.value = d.ruleCode;
return d;
}) || [];
} else {
ElMessage.error(res.msg);
}
})
getSmallCategoryList().then((res: any) => {
if (res.code == proxy.$passCode) {
smallCategoryList.value = res.data || [];
} else {
ElMessage.error(res.msg);
}
})
getLargeCategoryList().then((res: any) => {
if (res.code == proxy.$passCode) {
largeCategoryList.value = res.data || [];
} else {
ElMessage.error(res.msg);
}
})
})
</script>
<template>
<div class="content_main" v-loading="fullScreenLoading">
<div class="operator_panel_wrap">
<div class="operator_panel is-block" v-loading="detailLoading">
<div class="panel_title">
<div class="title_text">
<span>规则</span>
</div>
</div>
<div class="panel_content">
<div class="form_panel">
<ruleForm ref="ruleFormRef" :toSubjectTables="toSubjectTables" :ruleTypeValue="ruleType" :value="detailInfo"
:ruleTypeList="ruleTypeList" :largeCategoryList="largeCategoryList"
:smallCategoryList="smallCategoryList"></ruleForm>
</div>
</div>
</div>
</div>
<div class="bottom_tool_wrap">
<el-button @click="cancel">取消</el-button>
<el-button type="primary" @click="save">保存</el-button>
</div>
</div>
</template>
<style lang="scss" scoped>
.content_main {
display: flex;
flex-direction: column;
height: 100%;
}
.operator_panel_wrap {
height: auto;
min-height: 200px;
display: flex;
justify-content: space-between;
margin: 16px;
max-height: calc(100% - 72px);
:deep(.el-button) {
&.is-text {
height: auto;
padding: 0;
}
}
.operator_panel {
width: calc(50% - 5px);
height: 100%;
border: 1px solid #d9d9d9;
overflow: hidden;
&.is-block {
width: 100%;
}
.panel_title {
height: 48px;
padding: 0 15px;
display: flex;
justify-content: space-between;
align-items: center;
color: var(--el-color-regular);
font-weight: 600;
border-bottom: 1px solid #d9d9d9;
.tips_text {
font-size: 14px;
color: #999;
font-weight: normal;
margin-left: 8px;
}
}
.panel_content {
height: calc(100% - 46px);
>div {
width: 100%;
height: 100%;
overflow: hidden;
}
.form_panel {
padding: 8px 16px 0;
overflow: hidden auto;
}
}
}
}
.bottom_tool_wrap {
height: 40px;
padding: 0 16px;
border-top: 1px solid #d9d9d9;
display: flex;
justify-content: flex-end;
align-items: center;
}
</style>
\ No newline at end of file
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!