ui Check Workflow

This commit is contained in:
DESKTOP-1R2VSQH\Lenovo ThinkPad E490 2024-10-30 17:22:25 +07:00
parent 7fcd4968c5
commit a75773b747
4 changed files with 534 additions and 0 deletions

View file

@ -99,4 +99,7 @@ export default {
/** หมอบหมาย*/
commandSysAssign: `${organization}/commandSys/assign`,
posAssign: `${organization}/pos/assign`,
/** View Work Flow*/
viewWorkflow: `${organization}/view-workflow`,
};

View file

@ -0,0 +1,73 @@
interface DataWorkflow {
name: string;
sysName: string;
}
interface WorkflowLists {
createdAt: string;
createdFullName: string;
createdUserId: string;
id: string;
lastUpdateFullName: string;
lastUpdateUserId: string;
lastUpdatedAt: string;
metaWorkflowId: string;
name: string;
order: number;
type: string;
metaStateOperators: MetaStateOperators[];
}
interface MetaStateOperators {
canCancel: boolean;
canChangeState: boolean;
canComment: boolean;
canDelete: boolean;
canOperate: boolean;
canSign: boolean;
canUpdate: boolean;
canView: boolean;
createdAt: string;
createdFullName: string;
createdUserId: string;
id: string;
lastUpdateFullName: string;
lastUpdateUserId: string;
lastUpdatedAt: string;
metaStateId: string;
operator: string;
}
interface OptionsType {
id: string;
name: string;
posLevels: PosLevel[];
}
interface OptionsLevel {
id: string;
name: string;
}
interface PosType {
id: string;
posTypeName: string;
posTypeRank: number;
posLevels: PosLevel[];
}
interface PosLevel {
id: string;
posLevelAuthority: string;
posLevelName: string;
posLevelRank: number;
}
export type {
WorkflowLists,
DataWorkflow,
OptionsType,
OptionsLevel,
PosType,
PosLevel,
};

View file

@ -4,6 +4,7 @@ const MainLayout = () => import("@/views/MainLayout.vue");
const Dashboard = () => import("@/views/Dashboard.vue");
const Error404NotFound = () => import("@/views/Error404NotFound.vue");
const loginView = () => import("@/views/login.vue");
const CheckWorkflow = () => import("@/views/CheckWorkflow.vue");
import ModuleMetadata from "@/modules/01_metadata/router";
import ModuleUser from "@/modules/02_users/router";
@ -32,6 +33,16 @@ const router = createRouter({
Role: ["SUPER_ADMIN", "ADMIN"],
},
},
{
path: "/check-workflow",
name: "check-workflow",
component: CheckWorkflow,
meta: {
Auth: true,
Key: [7],
Role: ["SUPER_ADMIN", "ADMIN"],
},
},
...ModuleMetadata,
...ModuleUser,
...ModuleLogs,

447
src/views/CheckWorkflow.vue Normal file
View file

@ -0,0 +1,447 @@
<script setup lang="ts">
import { onMounted, reactive, ref } from "vue";
import { useQuasar } from "quasar";
import { useCounterMixin } from "@/stores/mixin";
import http from "@/plugins/http";
import config from "@/app.config";
import type { QTableProps } from "quasar";
import type {
WorkflowLists,
DataWorkflow,
OptionsType,
OptionsLevel,
PosType,
PosLevel,
} from "@/interface/viewWorkflow/response";
const $q = useQuasar();
const { showLoader, hideLoader, messageError } = useCounterMixin();
const isSearch = ref<boolean>(false);
const formFilter = reactive({
name: "",
type: "",
level: "",
});
const dataWorkflow = ref<DataWorkflow[]>([]);
const dataType = ref<OptionsType[]>([]);
const dataLevel = ref<OptionsLevel[]>([]);
const optionName = ref<DataWorkflow[]>([]);
const optionType = ref<OptionsType[]>([]);
const optionLevel = ref<OptionsLevel[]>([]);
const rows = ref<WorkflowLists[]>([]);
const expanded = ref<string[]>(["รอดำเนินการ"]);
const columns = ref<QTableProps["columns"]>([
{
name: "name",
align: "left",
label: "ขั้นตอนการทำงาน",
sortable: false,
field: "name",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
]);
const columnsExpanded = ref<QTableProps["columns"]>([
{
name: "operator",
align: "left",
label: "ผู้ดำเนินการ",
sortable: false,
field: "operator",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "canCancel",
align: "left",
label: "canCancel",
sortable: false,
field: "canCancel",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "canChangeState",
align: "left",
label: "canChangeState",
sortable: false,
field: "canChangeState",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "canComment",
align: "left",
label: "canComment",
sortable: false,
field: "canComment",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "canDelete",
align: "left",
label: "canDelete",
sortable: false,
field: "canDelete",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "canOperate",
align: "left",
label: "canOperate",
sortable: false,
field: "canOperate",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "canSign",
align: "left",
label: "canSign",
sortable: false,
field: "canSign",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "canUpdate",
align: "left",
label: "canUpdate",
sortable: false,
field: "canUpdate",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "canView",
align: "left",
label: "canView",
sortable: false,
field: "canView",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
]);
function fetchWorkflowList() {
http
.get(config.API.viewWorkflow + `/lists`)
.then((res) => {
const data = res.data.result;
dataWorkflow.value = data;
optionName.value = data;
})
.catch((err) => {
messageError($q, err);
});
}
function fetchType() {
http
.get(config.API.orgPosType)
.then((res) => {
const data = res.data.result;
dataType.value = data.map((e: PosType) => ({
id: e.posTypeName,
name: e.posTypeName,
posLevels: e.posLevels,
}));
optionType.value = dataType.value;
})
.catch((err) => {
messageError($q, err);
});
}
function onSelectPosType(id: string) {
const data = dataType.value.find(
(e: OptionsType) => e.id === id && e.posLevels
)?.posLevels;
dataLevel.value =
data?.map((e: PosLevel) => ({
id: e.posLevelName,
name: e.posLevelName,
})) || [];
formFilter.level = "";
}
async function searchWorkflow() {
if (
formFilter.name !== "" &&
formFilter.type !== "" &&
formFilter.level !== ""
) {
showLoader();
rows.value = [];
await http
.get(
config.API.viewWorkflow +
`?sysName=${formFilter.name}&posTypeName=${formFilter.type}&posLevelName=${formFilter.level}`
)
.then(async (res) => {
const data = await res.data.result;
if (data && data[0]?.metaStates) {
rows.value = data[0].metaStates;
expanded.value = rows.value.map((e: WorkflowLists) => e.name);
}
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
isSearch.value = true;
});
}
}
function filterSelector(val: string, update: Function, refData: string) {
switch (refData) {
case "name":
update(() => {
optionName.value = dataWorkflow.value.filter(
(v: DataWorkflow) => v.name.indexOf(val) > -1
);
});
break;
case "type":
update(() => {
optionType.value = dataType.value.filter(
(v: OptionsType) => v.name.indexOf(val) > -1
);
});
break;
case "level":
update(() => {
optionLevel.value = dataLevel.value.filter(
(v: OptionsLevel) => v.name.indexOf(val) > -1
);
});
break;
default:
break;
}
}
onMounted(async () => {
showLoader();
await Promise.all([fetchType(), fetchWorkflowList()]).finally(() => {
hideLoader();
});
});
</script>
<template>
<div class="toptitle text-dark col-12 row items-center">Check Workflow</div>
<div class="q-pa-sm">
<q-card>
<div class="row col-12 q-mb-sm">
<q-form
class="col-12"
q-form
greedy
@submit.prevent
@validation-success="searchWorkflow"
>
<div class="row justify-between q-gutter-y-sm q-pa-lg">
<div class="col-6 col-md-4">
<q-select
dense
outlined
use-input
lazy-rules
emit-value
map-options
hide-bottom-space
option-label="name"
option-value="sysName"
v-model="formFilter.name"
:options="optionName"
label="Workflow"
:rules="[(val: string) => !!val || `${'กรุณาเลือก Workflow'}`]"
@filter="(inputValue: string,
doneFn: Function) => filterSelector(inputValue, doneFn, 'name'
)"
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-italic text-grey">
ไมอม
</q-item-section>
</q-item>
</template>
</q-select>
</div>
<div class="col-5 col-md-3">
<q-select
dense
outlined
use-input
lazy-rules
emit-value
map-options
hide-bottom-space
option-label="name"
option-value="id"
v-model="formFilter.type"
:options="optionType"
@update:model-value="onSelectPosType"
label="ประเภทตำแหน่ง"
:rules="[(val: string) => !!val || `${'กรุณาเลือก ประเภทตำแหน่ง'}`]"
@filter="(inputValue: string,
doneFn: Function) => filterSelector(inputValue, doneFn, 'type'
)"
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-italic text-grey">
ไมอม
</q-item-section>
</q-item>
</template>
</q-select>
</div>
<div class="col-5 col-md-3">
<q-select
dense
outlined
use-input
lazy-rules
emit-value
map-options
hide-bottom-space
option-label="name"
option-value="id"
v-model="formFilter.level"
:options="optionLevel"
label="ระดับตำแหน่ง"
:rules="[(val: string) => !!val || `${'กรุณาเลือก ระดับตำแหน่ง'}`]"
@filter="(inputValue: string,
doneFn: Function) => filterSelector(inputValue, doneFn, 'level'
)"
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-italic text-grey">
ไมอม
</q-item-section>
</q-item>
</template>
</q-select>
</div>
<q-btn
type="submit"
dense
unelevated
color="primary"
class="col-5 col-md-1"
label="ค้นหา"
/>
</div>
</q-form>
</div>
<q-card v-if="isSearch">
<d-table
v-if="rows.length !== 0"
flat
bordered
:rows="rows"
:columns="columns"
row-key="name"
v-model:expanded="expanded"
:hide-bottom="true"
>
<template v-slot:header="props">
<q-tr :props="props">
<q-th v-for="col in props.cols" :key="col.name" :props="props">
{{ col.label }}
</q-th>
</q-tr>
</template>
<template v-slot:body="props">
<q-tr :props="props">
<q-td v-for="col in props.cols" :key="col.name" :props="props">
{{ col.value }}
</q-td>
</q-tr>
<q-tr v-show="props.expand" :props="props">
<q-td colspan="100%">
<div class="q-pa-md">
<q-card bordered>
<q-card-section style="padding: 0px">
<d-table
flat
bordered
:rows="props.row.metaStateOperators"
:columns="columnsExpanded"
row-key="name"
:hide-bottom="true"
>
<template v-slot:header="props">
<q-tr :props="props">
<q-th
v-for="col in props.cols"
:key="col.name"
:props="props"
>
{{ col.label }}
</q-th>
</q-tr>
</template>
<template v-slot:body="props">
<q-tr :props="props">
<q-td
v-for="col in props.cols"
:key="col.name"
:props="props"
>
<div v-if="col.name !== 'operator'">
<q-icon
v-if="col.value"
name="check"
color="primary"
size="sm"
/>
</div>
<div v-else>
{{ col.value }}
</div>
</q-td>
</q-tr>
</template>
</d-table>
</q-card-section>
</q-card>
</div>
</q-td>
</q-tr>
</template>
</d-table>
<q-banner inline-actions rounded class="bg-grey-1 text-center" v-else>
ไมอม
</q-banner>
</q-card>
</q-card>
</div>
</template>
<style scoped></style>