Apply repository-wide ESLint auto-fix formatting pass

Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
2026-03-08 12:11:57 +08:00
parent 7c48faaa3d
commit 847904c49b
172 changed files with 13629 additions and 9154 deletions

View File

@@ -1,65 +1,112 @@
<template>
<Dialog :visible="listModal" @update:visible="emit('closeModal', $event)" modal :style="{ width: '90vw', height: '90vh' }" :contentClass="contentClass">
<template #header>
<div class=" py-5">
<p class="text-base font-bold">Non-conformance Issue</p>
</div>
</template>
<div class="h-full flex items-start justify-start p-4">
<!-- Trace List -->
<section class="w-80 h-full pr-4">
<p class="h2 px-2 mb-2">Trace List ({{ traceTotal }})</p>
<p class="text-primary h2 px-2 mb-2">
<span class="material-symbols-outlined !text-sm align-[-10%] mr-2">info</span>Click trace number to see more.
</p>
<div class="overflow-y-scroll overflow-x-hidden scrollbar mx-[-8px] max-h-[calc(100%_-_96px)]" >
<table class="border-separate border-spacing-x-2 text-sm">
<caption class="hidden">Trace List</caption>
<thead class="sticky top-0 z-10 bg-neutral-100">
<tr>
<th class="h2 px-2 border-b border-neutral-500">Trace</th>
<th class="h2 px-2 border-b border-neutral-500 text-start" colspan="3">Occurrences</th>
</tr>
</thead>
<tbody>
<tr v-for="(trace, key) in traceList" :key="key" class=" cursor-pointer hover:text-primary" @click="switchCaseData(trace.id)">
<td class="p-2">#{{ trace.id }}</td>
<td class="p-2 w-24">
<div class="h-4 w-full bg-neutral-300 rounded-sm overflow-hidden">
<div class="h-full bg-primary" :style="progressWidth(trace.value)"></div>
</div>
</td>
<td class="py-2 text-right">{{ trace.count }}</td>
<td class="p-2 text-right">{{ trace.ratio }}%</td>
</tr>
</tbody>
</table>
<Dialog
:visible="listModal"
@update:visible="emit('closeModal', $event)"
modal
:style="{ width: '90vw', height: '90vh' }"
:contentClass="contentClass"
>
<template #header>
<div class="py-5">
<p class="text-base font-bold">Non-conformance Issue</p>
</div>
</section>
<!-- Trace item Table -->
<section class="px-4 py-2 h-full w-[calc(100%_-_320px)] bg-neutral-10 rounded-xl">
<p class="h2 mb-2 px-4">Trace #{{ showTraceId }}</p>
<div class="h-36 w-full px-2 mb-2 border border-neutral-300 rounded">
<div class="h-full w-full">
<div id="cfmTrace" ref="cfmTrace" class="h-full min-w-full relative"></div>
</template>
<div class="h-full flex items-start justify-start p-4">
<!-- Trace List -->
<section class="w-80 h-full pr-4">
<p class="h2 px-2 mb-2">Trace List ({{ traceTotal }})</p>
<p class="text-primary h2 px-2 mb-2">
<span class="material-symbols-outlined !text-sm align-[-10%] mr-2"
>info</span
>Click trace number to see more.
</p>
<div
class="overflow-y-scroll overflow-x-hidden scrollbar mx-[-8px] max-h-[calc(100%_-_96px)]"
>
<table class="border-separate border-spacing-x-2 text-sm">
<caption class="hidden">
Trace List
</caption>
<thead class="sticky top-0 z-10 bg-neutral-100">
<tr>
<th class="h2 px-2 border-b border-neutral-500">Trace</th>
<th
class="h2 px-2 border-b border-neutral-500 text-start"
colspan="3"
>
Occurrences
</th>
</tr>
</thead>
<tbody>
<tr
v-for="(trace, key) in traceList"
:key="key"
class="cursor-pointer hover:text-primary"
@click="switchCaseData(trace.id)"
>
<td class="p-2">#{{ trace.id }}</td>
<td class="p-2 w-24">
<div
class="h-4 w-full bg-neutral-300 rounded-sm overflow-hidden"
>
<div
class="h-full bg-primary"
:style="progressWidth(trace.value)"
></div>
</div>
</td>
<td class="py-2 text-right">{{ trace.count }}</td>
<td class="p-2 text-right">{{ trace.ratio }}%</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="overflow-y-auto overflow-x-auto scrollbar h-[calc(100%_-_200px)] infiniteTable" @scroll="handleScroll">
<DataTable :value="caseData" showGridlines tableClass="text-sm" breakpoint="0">
</section>
<!-- Trace item Table -->
<section
class="px-4 py-2 h-full w-[calc(100%_-_320px)] bg-neutral-10 rounded-xl"
>
<p class="h2 mb-2 px-4">Trace #{{ showTraceId }}</p>
<div class="h-36 w-full px-2 mb-2 border border-neutral-300 rounded">
<div class="h-full w-full">
<div
id="cfmTrace"
ref="cfmTrace"
class="h-full min-w-full relative"
></div>
</div>
</div>
<div
class="overflow-y-auto overflow-x-auto scrollbar h-[calc(100%_-_200px)] infiniteTable"
@scroll="handleScroll"
>
<DataTable
:value="caseData"
showGridlines
tableClass="text-sm"
breakpoint="0"
>
<div v-for="(col, index) in columnData" :key="index">
<Column :field="col.field" :header="col.header">
<template #body="{ data }">
<div :class="data[col.field]?.length > 18 ? 'whitespace-normal' : 'whitespace-nowrap'">
<div
:class="
data[col.field]?.length > 18
? 'whitespace-normal'
: 'whitespace-nowrap'
"
>
{{ data[col.field] }}
</div>
</template>
</Column>
</div>
</DataTable>
</div>
</section>
</div>
</Dialog>
</div>
</section>
</div>
</Dialog>
</template>
<script setup>
// The Lucia project.
@@ -74,30 +121,39 @@
* results with expandable activity sequences.
*/
import { ref, computed, watch, nextTick, useTemplateRef } from 'vue';
import { storeToRefs } from 'pinia';
import { useConformanceStore } from '@/stores/conformance';
import cytoscapeMapTrace from '@/module/cytoscapeMapTrace.js';
import { ref, computed, watch, nextTick, useTemplateRef } from "vue";
import { storeToRefs } from "pinia";
import { useConformanceStore } from "@/stores/conformance";
import cytoscapeMapTrace from "@/module/cytoscapeMapTrace.js";
const props = defineProps(['listModal', 'listNo', 'traceId', 'firstCases', 'listTraces', 'taskSeq', 'cases', 'category']);
const emit = defineEmits(['closeModal']);
const props = defineProps([
"listModal",
"listNo",
"traceId",
"firstCases",
"listTraces",
"taskSeq",
"cases",
"category",
]);
const emit = defineEmits(["closeModal"]);
const conformanceStore = useConformanceStore();
const { infinite404 } = storeToRefs(conformanceStore);
// template ref
const cfmTrace = useTemplateRef('cfmTrace');
const cfmTrace = useTemplateRef("cfmTrace");
// data
const contentClass = ref('!bg-neutral-100 border-t border-neutral-300 h-full');
const contentClass = ref("!bg-neutral-100 border-t border-neutral-300 h-full");
const showTraceId = ref(null);
const infiniteData = ref(null);
const maxItems = ref(false);
const infiniteFinish = ref(true); // Whether infinite scroll loading is complete
const startNum = ref(0);
const processMap = ref({
nodes:[],
edges:[],
nodes: [],
edges: [],
});
// computed
@@ -106,23 +162,27 @@ const traceTotal = computed(() => {
});
const traceList = computed(() => {
const sum = props.listTraces.map(trace => trace.count).reduce((acc, cur) => acc + cur, 0);
const sum = props.listTraces
.map((trace) => trace.count)
.reduce((acc, cur) => acc + cur, 0);
return props.listTraces.map(trace => {
return {
id: trace.id,
value: Number((getPercentLabel(trace.count / sum))),
count: trace.count.toLocaleString('en-US'),
count_base: trace.count,
ratio: getPercentLabel(trace.count / sum),
};
}).sort((x, y) => x.id - y.id);
return props.listTraces
.map((trace) => {
return {
id: trace.id,
value: Number(getPercentLabel(trace.count / sum)),
count: trace.count.toLocaleString("en-US"),
count_base: trace.count,
ratio: getPercentLabel(trace.count / sum),
};
})
.sort((x, y) => x.id - y.id);
});
const caseData = computed(() => {
if(infiniteData.value !== null){
if (infiniteData.value !== null) {
const data = JSON.parse(JSON.stringify(infiniteData.value)); // Deep copy the original cases data
data.forEach(item => {
data.forEach((item) => {
item.facets.forEach((facet, index) => {
item[`fac_${index}`] = facet.value; // Create a new key-value pair
});
@@ -132,47 +192,74 @@ const caseData = computed(() => {
item[`att_${index}`] = attribute.value; // Create a new key-value pair
});
delete item.attributes; // Remove the original attributes property
})
});
return data;
}
});
const columnData = computed(() => {
const data = JSON.parse(JSON.stringify(props.cases)); // Deep copy the original cases data
const facetName = facName => facName.trim().replace(/^(.)(.*)$/, (match, firstChar, restOfString) => firstChar.toUpperCase() + restOfString.toLowerCase());
const facetName = (facName) =>
facName
.trim()
.replace(
/^(.)(.*)$/,
(match, firstChar, restOfString) =>
firstChar.toUpperCase() + restOfString.toLowerCase(),
);
const result = [
{ field: 'id', header: 'Case Id' },
{ field: 'started_at', header: 'Start time' },
{ field: 'completed_at', header: 'End time' },
...data[0].facets.map((fac, index) => ({ field: `fac_${index}`, header: facetName(fac.name) })),
...data[0].attributes.map((att, index) => ({ field: `att_${index}`, header: att.key })),
{ field: "id", header: "Case Id" },
{ field: "started_at", header: "Start time" },
{ field: "completed_at", header: "End time" },
...data[0].facets.map((fac, index) => ({
field: `fac_${index}`,
header: facetName(fac.name),
})),
...data[0].attributes.map((att, index) => ({
field: `att_${index}`,
header: att.key,
})),
];
return result
return result;
});
// watch
watch(() => props.listModal, (newValue) => { // Draw the chart when the modal is opened for the first time
if(newValue) createCy();
});
watch(
() => props.listModal,
(newValue) => {
// Draw the chart when the modal is opened for the first time
if (newValue) createCy();
},
);
watch(() => props.taskSeq, (newValue) => {
if (newValue !== null) createCy();
});
watch(
() => props.taskSeq,
(newValue) => {
if (newValue !== null) createCy();
},
);
watch(() => props.traceId, (newValue) => {
// Update showTraceId when the traceId prop changes
showTraceId.value = newValue;
});
watch(
() => props.traceId,
(newValue) => {
// Update showTraceId when the traceId prop changes
showTraceId.value = newValue;
},
);
watch(showTraceId, (newValue, oldValue) => {
const isScrollTop = document.querySelector('.infiniteTable');
if(isScrollTop && typeof isScrollTop.scrollTop !== 'undefined') if(newValue !== oldValue) isScrollTop.scrollTop = 0;
const isScrollTop = document.querySelector(".infiniteTable");
if (isScrollTop && typeof isScrollTop.scrollTop !== "undefined")
if (newValue !== oldValue) isScrollTop.scrollTop = 0;
});
watch(() => props.firstCases, (newValue) => {
infiniteData.value = newValue;
});
watch(
() => props.firstCases,
(newValue) => {
infiniteData.value = newValue;
},
);
watch(infinite404, (newValue) => {
if (newValue === 404) maxItems.value = true;
@@ -184,8 +271,8 @@ watch(infinite404, (newValue) => {
* @param {number} val - The raw ratio value.
* @returns {string} The formatted percentage string.
*/
function getPercentLabel(val){
if((val * 100).toFixed(1) >= 100) return 100;
function getPercentLabel(val) {
if ((val * 100).toFixed(1) >= 100) return 100;
else return parseFloat((val * 100).toFixed(1));
}
/**
@@ -193,78 +280,93 @@ function getPercentLabel(val){
* @param {number} value - The percentage value.
* @returns {string} The CSS width style string.
*/
function progressWidth(value){
return `width:${value}%;`
function progressWidth(value) {
return `width:${value}%;`;
}
/**
* switch case data
* @param {number} id case id
*/
async function switchCaseData(id) {
if(id == showTraceId.value) return;
if (id == showTraceId.value) return;
infinite404.value = null;
maxItems.value = false;
startNum.value = 0;
let result;
if(props.category === 'issue') result = await conformanceStore.getConformanceTraceDetail(props.listNo, id, 0);
else if(props.category === 'loop') result = await conformanceStore.getConformanceLoopsTraceDetail(props.listNo, id, 0);
if (props.category === "issue")
result = await conformanceStore.getConformanceTraceDetail(
props.listNo,
id,
0,
);
else if (props.category === "loop")
result = await conformanceStore.getConformanceLoopsTraceDetail(
props.listNo,
id,
0,
);
infiniteData.value = await result;
showTraceId.value = id; // Set after getDetail so the case table finishes loading before switching showTraceId
}
/**
* Assembles the trace element nodes data for Cytoscape rendering.
*/
function setNodesData(){
function setNodesData() {
// Clear nodes to prevent accumulation on each render
processMap.value.nodes = [];
// Populate nodes with data returned from the API call
if(props.taskSeq !== null) {
if (props.taskSeq !== null) {
props.taskSeq.forEach((node, index) => {
processMap.value.nodes.push({
data: {
id: index,
label: node,
backgroundColor: '#CCE5FF',
bordercolor: '#003366',
shape: 'round-rectangle',
backgroundColor: "#CCE5FF",
bordercolor: "#003366",
shape: "round-rectangle",
height: 80,
width: 100
}
width: 100,
},
});
});
};
}
}
/**
* Assembles the trace edge line data for Cytoscape rendering.
*/
function setEdgesData(){
function setEdgesData() {
processMap.value.edges = [];
if(props.taskSeq !== null) {
if (props.taskSeq !== null) {
props.taskSeq.forEach((edge, index) => {
processMap.value.edges.push({
data: {
source: `${index}`,
target: `${index + 1}`,
lineWidth: 1,
style: 'solid'
}
style: "solid",
},
});
});
};
}
// The number of edges is one less than the number of nodes
processMap.value.edges.pop();
}
/**
* create trace cytoscape's map
*/
function createCy(){
function createCy() {
nextTick(() => {
const graphId = cfmTrace.value;
setNodesData();
setEdgesData();
if(graphId !== null) cytoscapeMapTrace(processMap.value.nodes, processMap.value.edges, graphId);
if (graphId !== null)
cytoscapeMapTrace(
processMap.value.nodes,
processMap.value.edges,
graphId,
);
});
}
/**
@@ -273,12 +375,16 @@ function createCy(){
async function fetchData() {
try {
infiniteFinish.value = false;
startNum.value += 20
const result = await conformanceStore.getConformanceTraceDetail(props.listNo, showTraceId.value, startNum.value);
startNum.value += 20;
const result = await conformanceStore.getConformanceTraceDetail(
props.listNo,
showTraceId.value,
startNum.value,
);
infiniteData.value = [...infiniteData.value, ...result];
infiniteFinish.value = true;
} catch(error) {
console.error('Failed to load data:', error);
} catch (error) {
console.error("Failed to load data:", error);
}
}
/**
@@ -286,10 +392,16 @@ async function fetchData() {
* @param {Event} event - The scroll event.
*/
function handleScroll(event) {
if(maxItems.value || infiniteData.value.length < 20 || infiniteFinish.value === false) return;
if (
maxItems.value ||
infiniteData.value.length < 20 ||
infiniteFinish.value === false
)
return;
const container = event.target;
const overScrollHeight = container.scrollTop + container.clientHeight + 20 >= container.scrollHeight;
const overScrollHeight =
container.scrollTop + container.clientHeight + 20 >= container.scrollHeight;
if (overScrollHeight) fetchData();
}
@@ -298,22 +410,22 @@ function handleScroll(event) {
@reference "../../../assets/tailwind.css";
/* Progress bar color */
:deep(.p-progressbar .p-progressbar-value) {
@apply bg-primary
@apply bg-primary;
}
/* Table set */
:deep(.p-datatable-thead) {
@apply sticky top-0 left-0 z-10 bg-neutral-10
@apply sticky top-0 left-0 z-10 bg-neutral-10;
}
:deep(.p-datatable .p-datatable-thead > tr > th) {
@apply !border-y-0 border-neutral-500 bg-neutral-100 after:absolute after:left-0 after:w-full after:h-full after:block after:top-0 after:border-b after:border-t after:border-neutral-500;
white-space: nowrap;
}
:deep(.p-datatable .p-datatable-tbody > tr > td) {
@apply border-neutral-500 !border-t-0 text-center
@apply border-neutral-500 !border-t-0 text-center;
}
/* Center header title */
:deep(.p-column-header-content) {
@apply justify-center
@apply justify-center;
}
:deep(.p-datatable.p-datatable-gridlines .p-datatable-tbody > tr > td) {
min-width: 72px;