715294e4 by lihua

匿名化处理接口联调2

1 parent 371e8ad9
1 const useDataAnonymizationStore = defineStore( 1 const useDataAnonymizationStore = defineStore(
2 // 资产目录guid 2 // 资产目录guid
3 "isRefresh", 3 'isRefresh',
4 () => { 4 () => {
5 const isRefresh = ref<boolean>(false); 5 const isRefresh = ref<boolean>(false);
6 function setIsRefresh(v: boolean) { 6 function setIsRefresh(v: boolean) {
7 isRefresh.value = v; 7 isRefresh.value = v;
8 } 8 }
9 9
10 const isAnonPageRefresh = ref<boolean>(false);
11 function setIsAnonPageRefresh(v: boolean) {
12 isAnonPageRefresh.value = v;
13 }
14
10 return { 15 return {
11 isRefresh, 16 isRefresh,
17 isAnonPageRefresh,
12 setIsRefresh, 18 setIsRefresh,
19 setIsAnonPageRefresh,
13 }; 20 };
14 } 21 }
15 ); 22 );
......
...@@ -38,6 +38,7 @@ const tableFields: any = ref([]); ...@@ -38,6 +38,7 @@ const tableFields: any = ref([]);
38 38
39 const pageInfo: any = ref({ 39 const pageInfo: any = ref({
40 ...commonPageConfig, 40 ...commonPageConfig,
41 rows: 0,
41 }) 42 })
42 43
43 const getData = () => { 44 const getData = () => {
...@@ -61,6 +62,7 @@ const getData = () => { ...@@ -61,6 +62,7 @@ const getData = () => {
61 }); 62 });
62 tableData.value.push(obj); 63 tableData.value.push(obj);
63 }); 64 });
65 pageInfo.value.rows = res.data?.totalRows ?? 0;
64 } else { 66 } else {
65 ElMessage.error(res.msg); 67 ElMessage.error(res.msg);
66 } 68 }
...@@ -128,6 +130,7 @@ watch(() => props.execGuid, (val) => { ...@@ -128,6 +130,7 @@ watch(() => props.execGuid, (val) => {
128 if (res.code == proxy.$passCode) { 130 if (res.code == proxy.$passCode) {
129 let column = res.data?.column || {}; 131 let column = res.data?.column || {};
130 tableFields.value = column; 132 tableFields.value = column;
133 pageInfo.value.curr = 1;
131 getData(); 134 getData();
132 } else { 135 } else {
133 ElMessage.error(res.msg); 136 ElMessage.error(res.msg);
...@@ -210,7 +213,7 @@ const exportData = () => { ...@@ -210,7 +213,7 @@ const exportData = () => {
210 <el-button v-show="props.isPage" style="margin-bottom: 8px;" type="primary" @click="exportData" 213 <el-button v-show="props.isPage" style="margin-bottom: 8px;" type="primary" @click="exportData"
211 v-preReClick>导出数据</el-button> 214 v-preReClick>导出数据</el-button>
212 <el-table ref="tableRef" v-show="tableFields.length" :data="tableData" :highlight-current-row="true" stripe border 215 <el-table ref="tableRef" v-show="tableFields.length" :data="tableData" :highlight-current-row="true" stripe border
213 tooltip-effect="light" height="100%" row-key="guid" :style="{ width: '100%', height: 'calc(100% - 64px)' }"> 216 tooltip-effect="light" height="100%" row-key="guid" :style="{ width: '100%', height: !props.isPage ? 'calc(100% - 34px)' : 'calc(100% - 64px)' }">
214 <template v-for="(item, index) in (tableFields || [])"> 217 <template v-for="(item, index) in (tableFields || [])">
215 <el-table-column :label="item.chName" :width="item.dataType === 'datetime' 218 <el-table-column :label="item.chName" :width="item.dataType === 'datetime'
216 ? TableColumnWidth.DATETIME 219 ? TableColumnWidth.DATETIME
......
...@@ -32,9 +32,13 @@ import anonTaskStepTwo from './anonTaskStepTwo.vue'; ...@@ -32,9 +32,13 @@ import anonTaskStepTwo from './anonTaskStepTwo.vue';
32 import * as XLSX from 'xlsx'; 32 import * as XLSX from 'xlsx';
33 import { ElMessage } from 'element-plus'; 33 import { ElMessage } from 'element-plus';
34 import { isEqual, cloneDeep } from "lodash-es"; 34 import { isEqual, cloneDeep } from "lodash-es";
35 import { download } from "@/utils/common"; 35 import { changeNum, download } from "@/utils/common";
36 import anonResultView from './anonResultView.vue'; 36 import anonResultView from './anonResultView.vue';
37 import useDataAnonymizationStore from "@/store/modules/dataAnonymization";
38 import { RefreshRight, CircleCloseFilled, Right } from "@element-plus/icons-vue";
39 import { commonPageConfig } from '@/components/PageNav';
37 40
41 const anonymizationStore = useDataAnonymizationStore();
38 const { proxy } = getCurrentInstance() as any; 42 const { proxy } = getCurrentInstance() as any;
39 const userStore = useUserStore(); 43 const userStore = useUserStore();
40 const route = useRoute(); 44 const route = useRoute();
...@@ -43,7 +47,7 @@ const fullPath = route.fullPath; ...@@ -43,7 +47,7 @@ const fullPath = route.fullPath;
43 const taskGuid = ref(route.query.guid); 47 const taskGuid = ref(route.query.guid);
44 /** 提交保存和编辑后的执行guid */ 48 /** 提交保存和编辑后的执行guid */
45 const taskExecGuid = ref(''); 49 const taskExecGuid = ref('');
46 /** 是否执行结束 */ 50 /** 是否执行结束,用于第四步获取执行结果 */
47 const isExecEnd = ref(false); 51 const isExecEnd = ref(false);
48 const { required } = useValidator(); 52 const { required } = useValidator();
49 const fullscreenLoading = ref(false); 53 const fullscreenLoading = ref(false);
...@@ -270,12 +274,12 @@ const handleDataSelectFormSelectChange = async (val, row, formInfo) => { ...@@ -270,12 +274,12 @@ const handleDataSelectFormSelectChange = async (val, row, formInfo) => {
270 d.chName = d.columnZhName; 274 d.chName = d.columnZhName;
271 return d; 275 return d;
272 }) || []; 276 }) || [];
277 /** 判断有抽样数据,需要查询接口 */
278 getSampleDataByDsTable();
273 } else { 279 } else {
274 ElMessage.error(res.msg); 280 ElMessage.error(res.msg);
275 } 281 }
276 }); 282 });
277 /** 判断有抽样数据,需要查询接口 */
278 getSampleDataByDsTable();
279 } 283 }
280 } 284 }
281 285
...@@ -402,8 +406,8 @@ const formatterPreviewDate = (row, info) => { ...@@ -402,8 +406,8 @@ const formatterPreviewDate = (row, info) => {
402 if (v === 0) { 406 if (v === 0) {
403 return v; 407 return v;
404 } 408 }
405 if (!v) { 409 if (!v || v == 'null') {
406 return v || '--'; 410 return '--';
407 } 411 }
408 if (info.dataType === 'datetime') { 412 if (info.dataType === 'datetime') {
409 return Moment(v).format('YYYY-MM-DD HH:mm:ss'); 413 return Moment(v).format('YYYY-MM-DD HH:mm:ss');
...@@ -470,13 +474,13 @@ const parseFileData = (fileRaw) => { ...@@ -470,13 +474,13 @@ const parseFileData = (fileRaw) => {
470 }); 474 });
471 } 475 }
472 476
473 /** 获取文件解析后根据抽样比例得出的表格数据 */ 477 /** 获取文件解析后根据抽样比例得出的表格数据,默认查看前500条数据 */
474 const transferSampleData = () => { 478 const transferSampleData = () => {
475 let samplingRate = dataSimpleFormRef.value?.formInline?.samplingRate; 479 let samplingRate = dataSimpleFormRef.value?.formInline?.samplingRate;
476 if (parseFileDataSum.value.length > 1 && samplingRate) { 480 if (parseFileDataSum.value.length > 1 && samplingRate) {
477 let totalCnt = parseFileDataSum.value.length - 1; 481 let totalCnt = parseFileDataSum.value.length - 1;
478 let cnt = Math.ceil(samplingRate * 0.01 * totalCnt) + 1; 482 let cnt = Math.ceil(samplingRate * 0.01 * totalCnt) + 1;
479 sampleTableData.value = parseFileDataSum.value.slice(1, cnt > 1000 ? 1001 : cnt).map((info, row) => { 483 sampleTableData.value = parseFileDataSum.value.slice(1, cnt > 500 ? 501 : cnt).map((info, row) => {
480 let object = {}; 484 let object = {};
481 parseFileDataSum.value[0].forEach((chName, col) => { 485 parseFileDataSum.value[0].forEach((chName, col) => {
482 let name = sampleTableFields.value[col].enName; 486 let name = sampleTableFields.value[col].enName;
...@@ -510,8 +514,8 @@ const getSampleDataByDsTable = () => { ...@@ -510,8 +514,8 @@ const getSampleDataByDsTable = () => {
510 } 514 }
511 sampleTableDataLoading.value = true; 515 sampleTableDataLoading.value = true;
512 getDsTableSampleData({ 516 getDsTableSampleData({
513 limitNum: cnt, 517 limitNum: cnt > 500 ? 500 : cnt,
514 pageSize: cnt, 518 pageSize: cnt > 500 ? 500 : cnt,
515 pageIndex: 1, 519 pageIndex: 1,
516 dataSourceGuid: currDatasourceSelect.value.guid, 520 dataSourceGuid: currDatasourceSelect.value.guid,
517 database: currDatasourceSelect.value.databaseNameEn, 521 database: currDatasourceSelect.value.databaseNameEn,
...@@ -530,7 +534,6 @@ const getSampleDataByDsTable = () => { ...@@ -530,7 +534,6 @@ const getSampleDataByDsTable = () => {
530 } 534 }
531 535
532 const uploadFileChange = (file) => { 536 const uploadFileChange = (file) => {
533 sampleTableFields.value = [];
534 sampleTableData.value = []; 537 sampleTableData.value = [];
535 if (!file.length) { 538 if (!file.length) {
536 sampleTableFields.value = []; 539 sampleTableFields.value = [];
...@@ -545,13 +548,22 @@ const uploadFileChange = (file) => { ...@@ -545,13 +548,22 @@ const uploadFileChange = (file) => {
545 const anonTaskStepTwoRef = ref(); 548 const anonTaskStepTwoRef = ref();
546 549
547 const changeStep = async (val) => { 550 const changeStep = async (val) => {
548 if (val == 2) { 551 if (val <= step.value) {
552 step.value = val - 1;
553 stepsInfo.value.step = val - 1;
554 } else if (val == 2) {
549 formRef.value?.ruleFormRef?.validate((valid) => { 555 formRef.value?.ruleFormRef?.validate((valid) => {
550 if (valid) { 556 if (valid) {
557 if (formRef.value?.formInline?.dataSource == 2 && !sampleTableFields.value?.length) {
558 proxy.$ElMessage.error('上传文件的字段不能为空');
559 return;
560 }
551 dataSimpleFormRef.value?.ruleFormRef?.validate((valid) => { 561 dataSimpleFormRef.value?.ruleFormRef?.validate((valid) => {
552 if (valid) { 562 if (valid) {
563 // 第一步到第二步时,如果字段列表中与字段脱敏规则中的字段不匹配,应清空。
553 step.value = val - 1; 564 step.value = val - 1;
554 stepsInfo.value.step = val - 1; 565 stepsInfo.value.step = val - 1;
566 anonTaskStepTwoRef.value?.updateNextStepRules();
555 } 567 }
556 }); 568 });
557 } 569 }
...@@ -580,7 +592,7 @@ const changeStep = async (val) => { ...@@ -580,7 +592,7 @@ const changeStep = async (val) => {
580 } else { 592 } else {
581 saveParams.samplingRate = null; 593 saveParams.samplingRate = null;
582 } 594 }
583 let privacy = configInfo.anonPrivacyMode; 595 let privacy = configInfo.anonPrivacyMode; //值是克隆过的,可以删除
584 delete privacy.isKaNumber; 596 delete privacy.isKaNumber;
585 delete privacy.isRiskThreshold; 597 delete privacy.isRiskThreshold;
586 delete privacy.isTcField; 598 delete privacy.isTcField;
...@@ -597,8 +609,14 @@ const changeStep = async (val) => { ...@@ -597,8 +609,14 @@ const changeStep = async (val) => {
597 saveParams.guid = taskGuid.value; 609 saveParams.guid = taskGuid.value;
598 } 610 }
599 if (isEqual(saveParams, oldAnonTaskValueInfo.value)) { 611 if (isEqual(saveParams, oldAnonTaskValueInfo.value)) {
612 isExecEnd.value = false;
600 step.value = val - 1; 613 step.value = val - 1;
601 stepsInfo.value.step = val - 1; 614 stepsInfo.value.step = val - 1;
615 if (!analysisResultInfo.value?.status) {
616 processStepThreeResultView();
617 } else {
618 isExecEnd.value = analysisResultInfo.value?.status == 'E' || analysisResultInfo.value?.status == 'Y';
619 }
602 return; 620 return;
603 } 621 }
604 if (!taskGuid.value) { //保存 622 if (!taskGuid.value) { //保存
...@@ -611,7 +629,14 @@ const changeStep = async (val) => { ...@@ -611,7 +629,14 @@ const changeStep = async (val) => {
611 taskExecGuid.value = res.data?.lastExecGuid; 629 taskExecGuid.value = res.data?.lastExecGuid;
612 step.value = val - 1; 630 step.value = val - 1;
613 stepsInfo.value.step = val - 1; 631 stepsInfo.value.step = val - 1;
632 analysisResultInfo.value = {};
633 if (refreshTimer.value) {
634 clearInterval(refreshTimer.value);
635 refreshTimer.value = null;
636 }
637 processStepThreeResultView();
614 oldAnonTaskValueInfo.value = saveParams; 638 oldAnonTaskValueInfo.value = saveParams;
639 anonymizationStore.setIsAnonPageRefresh(true);
615 } else { 640 } else {
616 ElMessage.error(res.msg); 641 ElMessage.error(res.msg);
617 } 642 }
...@@ -625,26 +650,21 @@ const changeStep = async (val) => { ...@@ -625,26 +650,21 @@ const changeStep = async (val) => {
625 taskExecGuid.value = res.data; 650 taskExecGuid.value = res.data;
626 step.value = val - 1; 651 step.value = val - 1;
627 stepsInfo.value.step = val - 1; 652 stepsInfo.value.step = val - 1;
653 analysisResultInfo.value = {};
654 if (refreshTimer.value) {
655 clearInterval(refreshTimer.value);
656 refreshTimer.value = null;
657 }
658 processStepThreeResultView();
628 oldAnonTaskValueInfo.value = saveParams; 659 oldAnonTaskValueInfo.value = saveParams;
660 anonymizationStore.setIsAnonPageRefresh(true);
629 } else { 661 } else {
630 ElMessage.error(res.msg); 662 ElMessage.error(res.msg);
631 } 663 }
632 }) 664 })
633 } 665 }
634 } else if (val == 4) { 666 } else if (val == 4) {
635 //下一步之后,调用分析结果。 667 //下一步之后,设置执行结束, 查看结果。
636
637 getAnonAnalyzeResult(detailInfo.value.lastExecGuid).then((res: any) => {
638 debugger
639 });
640 getAnonAnalyzePageData({
641 pageSize: -1
642 }).then((res: any) => {
643 debugger
644 });
645 step.value = val - 1;
646 stepsInfo.value.step = val - 1;
647 } else if (val <= step.value) {
648 step.value = val - 1; 668 step.value = val - 1;
649 stepsInfo.value.step = val - 1; 669 stepsInfo.value.step = val - 1;
650 } 670 }
...@@ -682,6 +702,7 @@ onBeforeMount(() => { ...@@ -682,6 +702,7 @@ onBeforeMount(() => {
682 getAnonTaskDetail(taskGuid.value).then(async (res: any) => { 702 getAnonTaskDetail(taskGuid.value).then(async (res: any) => {
683 if (res?.code == proxy.$passCode) { 703 if (res?.code == proxy.$passCode) {
684 detailInfo.value = res.data || {}; 704 detailInfo.value = res.data || {};
705 taskExecGuid.value = detailInfo.value.lastExecGuid;
685 oldAnonTaskValueInfo.value = { 706 oldAnonTaskValueInfo.value = {
686 guid: detailInfo.value.guid, 707 guid: detailInfo.value.guid,
687 taskName: detailInfo.value.taskName, 708 taskName: detailInfo.value.taskName,
...@@ -742,6 +763,15 @@ onBeforeMount(() => { ...@@ -742,6 +763,15 @@ onBeforeMount(() => {
742 res?.msg && ElMessage.error(res?.msg); 763 res?.msg && ElMessage.error(res?.msg);
743 } 764 }
744 }) 765 })
766 // 会出现从文件切换到数据库时没有数据库列表的问题。
767 const res: any = await getDatabase({ connectStatus: 1 });
768 if (res?.code == proxy.$passCode) {
769 dataSourceList.value = res.data || [];
770 let item = dataSelectInfoItems.value.find(item => item.field == 'dataSourceGuid');
771 item && (item.options = dataSourceList.value);
772 } else {
773 proxy.$ElMessage.error(res.msg);
774 }
745 } else { 775 } else {
746 const res: any = await getDatabase({ connectStatus: 1 }); 776 const res: any = await getDatabase({ connectStatus: 1 });
747 if (res?.code == proxy.$passCode) { 777 if (res?.code == proxy.$passCode) {
...@@ -783,12 +813,12 @@ onBeforeMount(() => { ...@@ -783,12 +813,12 @@ onBeforeMount(() => {
783 d.chName = d.columnZhName; 813 d.chName = d.columnZhName;
784 return d; 814 return d;
785 }) || []; 815 }) || [];
816 /** 判断有抽样数据,需要查询接口 */
817 getSampleDataByDsTable();
786 } else { 818 } else {
787 ElMessage.error(res.msg); 819 ElMessage.error(res.msg);
788 } 820 }
789 }); 821 });
790 /** 判断有抽样数据,需要查询接口 */
791 getSampleDataByDsTable();
792 } 822 }
793 fullscreenLoading.value = false; 823 fullscreenLoading.value = false;
794 } else { 824 } else {
...@@ -840,6 +870,141 @@ const cancelTask = () => { ...@@ -840,6 +870,141 @@ const cancelTask = () => {
840 }); 870 });
841 } 871 }
842 872
873 const refreshTimer = ref()
874
875 /** 执行结果信息 */
876 const analysisResultInfo: any = ref({});
877
878 const getResultPromise: any = ref(null);
879
880 /** 第三步处理,定时刷新查看结果 */
881 const processStepThreeResultView = (isRefresh = false) => {
882 let process = (isRefresh) => {
883 getResultPromise.value = getAnonAnalyzeResult(taskExecGuid.value).then((res: any) => {
884 getResultPromise.value = null;
885 if (res?.code == proxy.$passCode) {
886 analysisResultInfo.value = res.data || {};
887 if (analysisResultInfo.value.status == 'R') { //正在运行中
888 if (isRefresh) {
889 proxy.$ElMessage.success('刷新成功,正在执行中...');
890 }
891 //添加定时器。
892 if (refreshTimer.value) {
893 return;
894 }
895 refreshTimer.value = setInterval(async () => {
896 process(false);
897 }, 20000);
898 } else if (analysisResultInfo.value.status == 'Y') {
899 //去获取结果。
900 isExecEnd.value = true;
901 refreshTimer.value && clearInterval(refreshTimer.value);
902 refreshTimer.value = null;
903 analysisResultTableFields.value = res.data?.column || [];
904 pageInfo.value.curr = 1;
905 getAnalysisResultPageData();
906 } else if (analysisResultInfo.value.status == 'E') {
907 isExecEnd.value = true
908 refreshTimer.value && clearInterval(refreshTimer.value);
909 refreshTimer.value = null;
910 }
911 } else {
912 proxy.$ElMessage.error(res.msg);
913 }
914 });
915 }
916 process(isRefresh);
917 }
918
919 /** 随时点击刷新查看结果。 */
920 const refreshQueryData = () => {
921 if (getResultPromise.value) {
922 return;
923 }
924 if (refreshTimer.value) {
925 clearInterval(refreshTimer.value);
926 refreshTimer.value = null;
927 }
928 processStepThreeResultView(true);
929 }
930
931 /** ------------------------- 匿名化分析结果页面数据展示 ---------------- */
932 const pageInfo: any = ref({
933 ...commonPageConfig,
934 })
935
936 const pageChange = (info) => {
937 pageInfo.value.curr = Number(info.curr);
938 pageInfo.value.limit = Number(info.limit);
939 getAnalysisResultPageData();
940 }
941
942 /** 每列字段对应的列宽计算结果。 */
943 const originResultTableFieldColumn = ref({});
944
945 /** 结果分析中的字段表格数据 */
946 const resultData: any = ref([]);
947
948 /** 结果分析中的字段信息 */
949 const analysisResultTableFields: any = ref([]);
950
951 const analysisResultLoading = ref(false);
952
953 watch(
954 resultData,
955 (val: any[], oldVal) => {
956 if (!analysisResultTableFields.value?.length) {
957 originResultTableFieldColumn.value = {};
958 return;
959 }
960 originResultTableFieldColumn.value = {};
961 analysisResultTableFields.value.forEach((field, index) => {
962 originResultTableFieldColumn.value[field.enName] = calcTableColumnWidth(
963 val?.slice(0, 20) || [],
964 field.enName,
965 field.chName,
966 24
967 );
968 });
969 },
970 {
971 deep: true,
972 }
973 );
974
975 const getAnalysisResultPageData = () => {
976 analysisResultLoading.value = true;
977 getAnonAnalyzePageData({
978 pageIndex: pageInfo.value.curr,
979 pageSize: pageInfo.value.limit,
980 taskExecGuid: taskExecGuid.value,
981 }).then((res: any) => {
982 analysisResultLoading.value = false;
983 if (res?.code == proxy.$passCode) {
984 pageInfo.value.rows =
985 resultData.value = [];
986 res.data?.records?.forEach(d => {
987 let obj = {};
988 analysisResultTableFields.value.forEach(t => {
989 obj[t.enName] = d.fieldValue?.[t.enName];
990 });
991 obj['equivalenceClassNum'] = changeNum(d.equivalenceClassNum || 0, 0);
992 obj['reIdentifyRisk'] = changeNum(d.reIdentifyRisk || 0, 2);
993 obj['isGtThreshold'] = d.isGtThreshold;
994 resultData.value.push(obj);
995 });
996 pageInfo.value.rows = res.data?.totalRows ?? 0;
997 } else {
998 proxy.$ElMessage.error(res.msg);
999 }
1000 })
1001 }
1002
1003 onUnmounted(() => {
1004 refreshTimer.value && clearInterval(refreshTimer.value);
1005 refreshTimer.value = null;
1006 })
1007
843 </script> 1008 </script>
844 1009
845 <template> 1010 <template>
...@@ -883,17 +1048,88 @@ const cancelTask = () => { ...@@ -883,17 +1048,88 @@ const cancelTask = () => {
883 </div> 1048 </div>
884 </ContentWrap> 1049 </ContentWrap>
885 </div> 1050 </div>
886 <anonTaskStepTwo ref="anonTaskStepTwoRef" v-show="step == 1" :anonTaskRules="detailInfo.anonTaskRules" :isFile="formRef?.formInline?.file?.length > 0" 1051 <anonTaskStepTwo ref="anonTaskStepTwoRef" v-show="step == 1" :anonTaskRules="detailInfo.anonTaskRules"
887 :anonPrivacyMode="detailInfo.anonPrivacyMode" :fieldTypeList="fieldTypeList" :fieldNameList="sampleTableFields"> 1052 :isFile="formRef?.formInline?.file?.length > 0" :anonPrivacyMode="detailInfo.anonPrivacyMode"
1053 :fieldTypeList="fieldTypeList" :fieldNameList="sampleTableFields">
888 </anonTaskStepTwo> 1054 </anonTaskStepTwo>
889 <div class="operator_panel_wrap" v-show="step == 2"> 1055 <div class="operator_panel_wrap" v-show="step == 2">
890 <ContentWrap id="analysis-result" title="匿名结果分析" description="" style="margin-top: 8px;"> 1056 <ContentWrap id="analysis-result" title="匿名结果分析" description="" style="margin-top: 8px;">
891 1057 <div class="wait-result-div" v-show="!isExecEnd">
1058 <img class="loading-img" src="../../assets/images/loading.gif" />
1059 <div class="desc">正在进行匿名化处理,请稍候...</div>
1060 <el-button :icon="RefreshRight" link @click="refreshQueryData" v-preReClick>刷新查看结果</el-button>
1061 </div>
1062 <div class="wait-result-div" v-show="isExecEnd && analysisResultInfo.status == 'E'">
1063 <el-icon class="failed">
1064 <CircleCloseFilled />
1065 </el-icon>
1066 <div class="error-desc">{{ '执行失败,请返回上一步修改配置或联系管理员' }}</div>
1067 <div v-show="analysisResultInfo.errorMsg" class="error-desc">{{ '【' + analysisResultInfo.errorMsg + '】' }}
1068 </div>
1069 </div>
1070 <div class="analysis-result-main" v-show="isExecEnd && analysisResultInfo.status == 'Y'">
1071 <el-table ref="tableRef" v-show="analysisResultTableFields.length" :data="resultData"
1072 v-loading="analysisResultLoading" :highlight-current-row="true" stripe border tooltip-effect="light"
1073 height="100%" row-key="guid" :style="{ width: '100%', height: '280px' }">
1074 <el-table-column label="等价类" type="index" width="68px" align="center" show-overflow-tooltip>
1075 <template #default="scope">
1076 <span>{{
1077 pageInfo.curr !== undefined
1078 ? (pageInfo.curr - 1) * pageInfo.limit + scope.$index + 1
1079 : scope.$index + 1
1080 }}</span>
1081 </template>
1082 </el-table-column>
1083 <template v-for="(item, index) in (analysisResultTableFields || [])">
1084 <el-table-column :label="item.chName" :width="item.dataType === 'datetime'
1085 ? TableColumnWidth.DATETIME
1086 : item.dataType === 'date'
1087 ? TableColumnWidth.DATE
1088 : originResultTableFieldColumn[item.enName]
1089 " :align="getTextAlign(item)" :header-align="getTextAlign(item)"
1090 :formatter="(row) => formatterPreviewDate(row, item)" :show-overflow-tooltip="true">
1091 </el-table-column>
1092 </template>
1093 <el-table-column label="等价类大小" prop="equivalenceClassNum" width="98" align="right" fixed="right"
1094 show-overflow-tooltip></el-table-column>
1095 <el-table-column label="重标识风险" prop="reIdentifyRisk" width="96" align="right" fixed="right"
1096 show-overflow-tooltip></el-table-column>
1097 <el-table-column label="判断重风险是否大于门限阈值" prop="isGtThreshold" width="130" align="left" fixed="right"
1098 show-overflow-tooltip></el-table-column>
1099 </el-table>
1100 <div v-show="!analysisResultTableFields.length" class="empty-content">
1101 <img src="../../assets/images/empty-data.png" :style="{ width: '168px', height: '96px' }" />
1102 <div class="empty-text">暂无数据</div>
1103 </div>
1104 <PageNav :class="[pageInfo.type]" :pageInfo="pageInfo" @pageChange="pageChange" />
1105 <div v-show="Object.keys(analysisResultInfo).length > 0">
1106 <div class="value-desc"><span style="font-weight: 600;margin-right: 8px;">重标识风险指标</span>{{ 'Rb=' +
1107 changeNum(analysisResultInfo.reIdentifyRiskRb || 0, 2) + ' Rc='
1108 +
1109 changeNum(analysisResultInfo.reIdentifyRiskRc || 0, 2) }}</div>
1110 <div class="value-desc"><span style="font-weight: 600;margin-right: 8px;">环境重标识攻击概率</span>{{
1111 'pr(context)=' +
1112 changeNum(analysisResultInfo.envReAttackPr || 0, 2)
1113 }}
1114 </div>
1115 <div class="value-desc"><span style="font-weight: 600;margin-right: 8px;">重标识总体风险</span>{{
1116 'R=Rc*pr(context)=' +
1117 changeNum(analysisResultInfo.reIdentifyOverallRisk || 0,
1118 2) }}</div>
1119 <div class="value-desc" style="font-weight: 600;">{{ '重标识总体风险值小于可接受风险阈值' +
1120 (oldAnonTaskValueInfo.anonPrivacyMode?.riskThreshold ==
1121 null ?
1122 0.05 : (changeNum(oldAnonTaskValueInfo.anonPrivacyMode?.riskThreshold || 0, 2))) + ',评为' +
1123 analysisResultInfo.rating + '级' }}</div>
1124 </div>
1125 </div>
892 </ContentWrap> 1126 </ContentWrap>
893 </div> 1127 </div>
894 <div class="operator_panel_wrap" v-show="step == 3"> 1128 <div class="operator_panel_wrap step-result" v-show="step == 3" style="height: calc(100% - 88px);">
895 <ContentWrap id="analysis-result" title="匿名化数据结果" description="" style="margin-top: 8px;"> 1129 <ContentWrap id="analysis-result" title="匿名化数据结果" description="" style="margin-top: 8px;height: 100%;">
896 <anonResultView :is-page="false" :execGuid="isExecEnd ? taskExecGuid : ''"></anonResultView> 1130 <anonResultView :is-page="false"
1131 :execGuid="analysisResultInfo.status == 'Y' && step == 3 ? taskExecGuid : ''">
1132 </anonResultView>
897 </ContentWrap> 1133 </ContentWrap>
898 </div> 1134 </div>
899 </div> 1135 </div>
...@@ -904,14 +1140,16 @@ const cancelTask = () => { ...@@ -904,14 +1140,16 @@ const cancelTask = () => {
904 </template> 1140 </template>
905 <template v-else-if="step == 1"> 1141 <template v-else-if="step == 1">
906 <el-button @click="changeStep(1)">上一步</el-button> 1142 <el-button @click="changeStep(1)">上一步</el-button>
907 <el-button type="primary" @click="changeStep(3)">保存并下一步</el-button> 1143 <el-button type="primary" @click="changeStep(3)">下一步</el-button>
908 </template> 1144 </template>
909 <template v-else-if="step == 2"> 1145 <template v-else-if="step == 2">
910 <el-button @click="changeStep(2)">上一步</el-button> 1146 <el-button @click="changeStep(2)">上一步</el-button>
911 <el-button type="primary" @click="changeStep(4)">下一步</el-button> 1147 <el-button type="primary"
1148 :disabled="analysisResultInfo.status == 'R' || (isExecEnd && analysisResultInfo.status == 'E')"
1149 @click="changeStep(4)">下一步</el-button>
912 </template> 1150 </template>
913 <template v-else> 1151 <template v-else>
914 <el-button type="primary" @click="changeStep(2)">上一步</el-button> 1152 <el-button @click="changeStep(3)">上一步</el-button>
915 <el-button type="primary" v-preReClick @click="exportResult">导出</el-button> 1153 <el-button type="primary" v-preReClick @click="exportResult">导出</el-button>
916 </template> 1154 </template>
917 </div> 1155 </div>
...@@ -951,6 +1189,75 @@ const cancelTask = () => { ...@@ -951,6 +1189,75 @@ const cancelTask = () => {
951 padding-bottom: 12px; 1189 padding-bottom: 12px;
952 } 1190 }
953 1191
1192 .wait-result-div {
1193 height: 250px;
1194 display: flex;
1195 flex-direction: column;
1196 justify-content: center;
1197 align-items: center;
1198
1199 .loading-img {
1200 width: 40px;
1201 height: 40px;
1202 margin-bottom: 18px;
1203 }
1204
1205 .desc {
1206 color: #999;
1207 margin-bottom: 18px;
1208 margin-left: 26px;
1209 }
1210
1211 :deep(.el-icon.failed) {
1212 color: #E63E33;
1213 width: 32px;
1214 height: 32px;
1215 margin-bottom: 8px;
1216
1217 svg {
1218 width: 32px;
1219 height: 32px;
1220 }
1221 }
1222
1223 .error-desc {
1224 color: #E63E33;
1225 font-size: 14px;
1226 line-height: 21px;
1227 margin-bottom: 8px;
1228 font-weight: 600;
1229 }
1230 }
1231
1232 .analysis-result-main {
1233 min-height: 250px;
1234
1235 .value-desc {
1236 font-size: 14px;
1237 color: #212121;
1238 line-height: 21px;
1239 }
1240 }
1241
1242 .step-result {
1243 :deep(.v-content-wrap) {
1244 height: 100%;
1245
1246 .el-card__body {
1247 height: calc(100% - 50px) !important;
1248
1249 .card-body-content {
1250 height: 100%;
1251 }
1252 }
1253
1254 .table_tool_wrap {
1255 padding: 0px;
1256 }
1257 }
1258
1259 }
1260
954 :deep(.custom-form) { 1261 :deep(.custom-form) {
955 align-items: flex-start; 1262 align-items: flex-start;
956 1263
......
...@@ -12,6 +12,7 @@ import { ...@@ -12,6 +12,7 @@ import {
12 validateAnonRule, 12 validateAnonRule,
13 } from '@/api/modules/dataAnonymization'; 13 } from '@/api/modules/dataAnonymization';
14 import { useValidator } from '@/hooks/useValidator'; 14 import { useValidator } from '@/hooks/useValidator';
15 import { cloneDeep } from 'lodash-es';
15 16
16 const props = defineProps({ 17 const props = defineProps({
17 fieldTypeList: { 18 fieldTypeList: {
...@@ -460,7 +461,7 @@ const drawerBtnClick = async (btn, info) => { ...@@ -460,7 +461,7 @@ const drawerBtnClick = async (btn, info) => {
460 proxy.$ElMessage.error('K匿名泛化与脱敏规则不能同时为空'); 461 proxy.$ElMessage.error('K匿名泛化与脱敏规则不能同时为空');
461 return; 462 return;
462 } 463 }
463 if ((info.fieldTypeCode == 'int' || info.fieldTypeCode == 'decimal' || info.fieldTypeCode == 'tinyint')) { 464 if (!(info.fieldTypeCode == 'int' || info.fieldTypeCode == 'decimal' || info.fieldTypeCode == 'tinyint')) {
464 if (info.desensitiveRuleCode == 'ROUNDING') { 465 if (info.desensitiveRuleCode == 'ROUNDING') {
465 proxy.$ElMessage.error('数值类型字段的脱敏规则不能设置取整'); 466 proxy.$ElMessage.error('数值类型字段的脱敏规则不能设置取整');
466 return; 467 return;
...@@ -1037,7 +1038,7 @@ const getStepTwoConfigInfo = async () => { ...@@ -1037,7 +1038,7 @@ const getStepTwoConfigInfo = async () => {
1037 await privacyFormRef.value?.ruleFormRef?.validate(); 1038 await privacyFormRef.value?.ruleFormRef?.validate();
1038 // 验证通过 1039 // 验证通过
1039 return { 1040 return {
1040 anonPrivacyMode: privacyFormRef.value?.formInline, 1041 anonPrivacyMode: cloneDeep(privacyFormRef.value?.formInline),
1041 anonTaskRules: ruleModelTableInfo.value.data 1042 anonTaskRules: ruleModelTableInfo.value.data
1042 }; 1043 };
1043 } catch (error) { 1044 } catch (error) {
...@@ -1046,8 +1047,43 @@ const getStepTwoConfigInfo = async () => { ...@@ -1046,8 +1047,43 @@ const getStepTwoConfigInfo = async () => {
1046 } 1047 }
1047 } 1048 }
1048 1049
1050 /** 字段改变,可能是切换了表,需要清空规则配置。判断 第一步到第二步时,如果字段列表中与字段脱敏规则中的字段不匹配,应清空,并同时清空T接近字段。 */
1051 const updateNextStepRules = () => {
1052 let deleteFieldNames: string[] = [];
1053 ruleModelTableInfo.value.data = ruleModelTableInfo.value.data.filter(rule => {
1054 if (!props.fieldNameList?.some(v => v.enName == rule.fieldName)) {
1055 deleteFieldNames.push(rule.fieldName);
1056 return false;
1057 }
1058 return true;
1059 });
1060 if (deleteFieldNames?.length) {
1061 let optionsList = ruleModelTableInfo.value.data?.map(v => {
1062 return {
1063 fieldName: v.fieldName,
1064 fieldChName: v.fieldChName
1065 }
1066 }) || [];
1067 privacyFormItems.value[2].children[0].options = optionsList;
1068 privacyFormItems.value[3].children[0].options = optionsList;
1069 let formInline = privacyFormRef.value?.formInline;
1070 privacyFormItems.value.forEach((item, index) => {
1071 item.default = formInline[item.field];
1072 if (item.default == 'Y') {
1073 item.children?.forEach(child => {
1074 child.default = formInline[child.field];
1075 if ((child.field == 'tcFieldName' || child.field == 'ldFieldName') && deleteFieldNames.includes(child.default)) {
1076 child.default = ''
1077 }
1078 });
1079 }
1080 })
1081 }
1082 }
1083
1049 defineExpose({ 1084 defineExpose({
1050 getStepTwoConfigInfo 1085 getStepTwoConfigInfo,
1086 updateNextStepRules
1051 }) 1087 })
1052 1088
1053 </script> 1089 </script>
......
...@@ -12,7 +12,9 @@ import { ...@@ -12,7 +12,9 @@ import {
12 deleteAnonTask, 12 deleteAnonTask,
13 } from '@/api/modules/dataAnonymization'; 13 } from '@/api/modules/dataAnonymization';
14 import { useValidator } from '@/hooks/useValidator'; 14 import { useValidator } from '@/hooks/useValidator';
15 import useDataAnonymizationStore from "@/store/modules/dataAnonymization";
15 16
17 const anonymizationStore = useDataAnonymizationStore();
16 const router = useRouter() 18 const router = useRouter()
17 const { proxy } = getCurrentInstance() as any; 19 const { proxy } = getCurrentInstance() as any;
18 const { required } = useValidator(); 20 const { required } = useValidator();
...@@ -70,8 +72,8 @@ const tableInfo = ref({ ...@@ -70,8 +72,8 @@ const tableInfo = ref({
70 width: 180, 72 width: 180,
71 fixed: 'right', 73 fixed: 'right',
72 btns: (scope) => { 74 btns: (scope) => {
73 return [ { 75 return [{
74 label: "编辑", value: "edit", disabled: scope.row.status == 'R', click: (scope) => { 76 label: "编辑", value: "edit", click: (scope) => {
75 router.push({ 77 router.push({
76 name: 'anonTaskCreate', 78 name: 'anonTaskCreate',
77 query: { 79 query: {
...@@ -92,11 +94,12 @@ const tableInfo = ref({ ...@@ -92,11 +94,12 @@ const tableInfo = ref({
92 }); 94 });
93 } 95 }
94 }, { 96 }, {
95 label: "删除", value: "delete", disabled: scope.row.status == 'R', click: (scope) => { 97 label: "删除", value: "delete", click: (scope) => {
96 proxy.$openMessageBox("此操作将永久删除, 是否继续?", () => { 98 proxy.$openMessageBox("此操作将永久删除, 是否继续?", () => {
97 let guids = [scope.row.guid]; 99 let guids = [scope.row.guid];
98 deleteAnonTask(guids).then((res: any) => { 100 deleteAnonTask(guids).then((res: any) => {
99 if (res?.code == proxy.$passCode) { 101 if (res?.code == proxy.$passCode) {
102 page.value.curr = 1;
100 getTableData(); 103 getTableData();
101 proxy.$ElMessage({ 104 proxy.$ElMessage({
102 type: "success", 105 type: "success",
...@@ -169,8 +172,17 @@ const handleCreate = () => { ...@@ -169,8 +172,17 @@ const handleCreate = () => {
169 172
170 onBeforeMount(() => { 173 onBeforeMount(() => {
171 toSearch({}); 174 toSearch({});
175 anonymizationStore.setIsAnonPageRefresh(false);
172 }) 176 })
173 177
178 onActivated(() => {
179 if (anonymizationStore.isAnonPageRefresh) {//如果是首次加载,则不需要调用
180 page.value.curr = 1;
181 getTableData();
182 anonymizationStore.setIsAnonPageRefresh(false);
183 }
184 });
185
174 </script> 186 </script>
175 187
176 <template> 188 <template>
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!