fix(04): service with workflow
This commit is contained in:
parent
e2d2f526e8
commit
aaa39fc72f
4 changed files with 994 additions and 557 deletions
|
|
@ -74,7 +74,12 @@ async function addWork() {
|
||||||
workItems.value.push({
|
workItems.value.push({
|
||||||
id: '',
|
id: '',
|
||||||
name: '',
|
name: '',
|
||||||
attributes: { additional: [], showTotalPrice: false },
|
attributes: {
|
||||||
|
additional: [],
|
||||||
|
showTotalPrice: false,
|
||||||
|
stepProperties: [],
|
||||||
|
workflowId: '',
|
||||||
|
},
|
||||||
product: [],
|
product: [],
|
||||||
});
|
});
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
|
@ -177,8 +182,16 @@ watch(
|
||||||
v-model:product-items="work.product"
|
v-model:product-items="work.product"
|
||||||
v-model:attributes="work.attributes"
|
v-model:attributes="work.attributes"
|
||||||
@add-product="$emit('addProduct', index)"
|
@add-product="$emit('addProduct', index)"
|
||||||
@move-work-up="moveItemUp(workItems, index)"
|
@move-work-up="
|
||||||
@move-work-down="moveItemDown(workItems, index)"
|
() => {
|
||||||
|
moveItemUp(workItems, index);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
@move-work-down="
|
||||||
|
() => {
|
||||||
|
moveItemDown(workItems, index);
|
||||||
|
}
|
||||||
|
"
|
||||||
@delete-work="confirmDelete(workItems, index)"
|
@delete-work="confirmDelete(workItems, index)"
|
||||||
@move-product-up="moveItemUp"
|
@move-product-up="moveItemUp"
|
||||||
@move-product-down="moveItemDown"
|
@move-product-down="moveItemDown"
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,35 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { onMounted, ref, watch } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { Option } from 'stores/options/types';
|
import { Option } from 'stores/options/types';
|
||||||
import { Attributes } from 'stores/product-service/types';
|
import { Attributes } from 'stores/product-service/types';
|
||||||
import { moveItemUp, moveItemDown, deleteItem, dialog } from 'stores/utils';
|
import { moveItemUp, moveItemDown, deleteItem, dialog } from 'stores/utils';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { QSelect } from 'quasar';
|
||||||
|
|
||||||
|
import { useWorkflowTemplate } from 'src/stores/workflow-template';
|
||||||
|
import { WorkflowTemplate } from 'src/stores/workflow-template/types';
|
||||||
|
|
||||||
|
import SelectInput from '../shared/SelectInput.vue';
|
||||||
import NoData from '../NoData.vue';
|
import NoData from '../NoData.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const workflowStore = useWorkflowTemplate();
|
||||||
|
const { data: workflowData } = storeToRefs(workflowStore);
|
||||||
|
|
||||||
const propertiesOption =
|
const propertiesOption =
|
||||||
defineModel<(Option & { type: Attributes['additional'][number]['type'] })[]>(
|
defineModel<(Option & { type: Attributes['additional'][number]['type'] })[]>(
|
||||||
'propertiesOption',
|
'propertiesOption',
|
||||||
);
|
);
|
||||||
const formServiceProperties = defineModel<Attributes>('formServiceProperties');
|
const formServiceProperties = defineModel<Attributes>('formServiceProperties', {
|
||||||
|
required: true,
|
||||||
|
default: {
|
||||||
|
workflowId: '',
|
||||||
|
stepProperties: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const currWorkflow = ref<WorkflowTemplate>();
|
||||||
const typeOption = ref([
|
const typeOption = ref([
|
||||||
{
|
{
|
||||||
label: 'Text',
|
label: 'Text',
|
||||||
|
|
@ -43,21 +58,22 @@ const typeOption = ref([
|
||||||
]);
|
]);
|
||||||
|
|
||||||
function manageProperties(
|
function manageProperties(
|
||||||
|
stepIndex: number,
|
||||||
property: string,
|
property: string,
|
||||||
propertyType?: Attributes['additional'][number]['type'],
|
propertyType?: Attributes['additional'][number]['type'],
|
||||||
) {
|
) {
|
||||||
if (property === 'all' && propertiesOption.value) {
|
if (property === 'all' && propertiesOption.value) {
|
||||||
if (
|
if (
|
||||||
formServiceProperties.value?.additional.length ===
|
formServiceProperties.value.stepProperties[stepIndex].attributes
|
||||||
propertiesOption.value.length
|
.length === propertiesOption.value.length
|
||||||
) {
|
) {
|
||||||
formServiceProperties.value.additional = [];
|
formServiceProperties.value.stepProperties[stepIndex].attributes = [];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const ops of propertiesOption.value) {
|
for (const ops of propertiesOption.value) {
|
||||||
if (
|
if (
|
||||||
formServiceProperties.value?.additional.some(
|
formServiceProperties.value.stepProperties[stepIndex].attributes.some(
|
||||||
(prop) => prop.fieldName === ops.value,
|
(prop) => prop.fieldName === ops.value,
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
|
@ -65,22 +81,22 @@ function manageProperties(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ops.type === 'date') {
|
if (ops.type === 'date') {
|
||||||
formServiceProperties.value?.additional.push({
|
formServiceProperties.value.stepProperties[stepIndex].attributes.push({
|
||||||
type: ops.type,
|
type: ops.type,
|
||||||
fieldName: ops.value,
|
fieldName: ops.value,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ops.type === 'array') {
|
if (ops.type === 'array') {
|
||||||
formServiceProperties.value?.additional.push({
|
formServiceProperties.value.stepProperties[stepIndex].attributes.push({
|
||||||
type: ops.type,
|
type: ops.type,
|
||||||
fieldName: ops.value,
|
fieldName: ops.value,
|
||||||
options: [''],
|
options: [],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ops.type === 'string') {
|
if (ops.type === 'string') {
|
||||||
formServiceProperties.value?.additional.push({
|
formServiceProperties.value.stepProperties[stepIndex].attributes.push({
|
||||||
type: ops.type,
|
type: ops.type,
|
||||||
fieldName: ops.value,
|
fieldName: ops.value,
|
||||||
isPhoneNumber: false,
|
isPhoneNumber: false,
|
||||||
|
|
@ -89,7 +105,7 @@ function manageProperties(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ops.type === 'number') {
|
if (ops.type === 'number') {
|
||||||
formServiceProperties.value?.additional.push({
|
formServiceProperties.value.stepProperties[stepIndex].attributes.push({
|
||||||
type: ops.type,
|
type: ops.type,
|
||||||
fieldName: ops.value,
|
fieldName: ops.value,
|
||||||
comma: false,
|
comma: false,
|
||||||
|
|
@ -101,31 +117,34 @@ function manageProperties(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (formServiceProperties.value) {
|
if (formServiceProperties.value.stepProperties[stepIndex].attributes) {
|
||||||
const propertyIndex = formServiceProperties.value.additional.findIndex(
|
const propertyIndex = formServiceProperties.value.stepProperties[
|
||||||
(prop) => prop.fieldName === property,
|
stepIndex
|
||||||
);
|
].attributes.findIndex((prop) => prop.fieldName === property);
|
||||||
|
|
||||||
if (propertyIndex !== -1) {
|
if (propertyIndex !== -1) {
|
||||||
formServiceProperties.value.additional.splice(propertyIndex, 1);
|
formServiceProperties.value.stepProperties[stepIndex].attributes.splice(
|
||||||
|
propertyIndex,
|
||||||
|
1,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
if (propertyType === 'date') {
|
if (propertyType === 'date') {
|
||||||
formServiceProperties.value?.additional.push({
|
formServiceProperties.value.stepProperties[stepIndex].attributes.push({
|
||||||
type: propertyType,
|
type: propertyType,
|
||||||
fieldName: property,
|
fieldName: property,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (propertyType === 'array') {
|
if (propertyType === 'array') {
|
||||||
formServiceProperties.value?.additional.push({
|
formServiceProperties.value.stepProperties[stepIndex].attributes.push({
|
||||||
type: propertyType,
|
type: propertyType,
|
||||||
fieldName: property,
|
fieldName: property,
|
||||||
options: [''],
|
options: [],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (propertyType === 'string') {
|
if (propertyType === 'string') {
|
||||||
formServiceProperties.value?.additional.push({
|
formServiceProperties.value.stepProperties[stepIndex].attributes.push({
|
||||||
type: propertyType,
|
type: propertyType,
|
||||||
fieldName: property,
|
fieldName: property,
|
||||||
isPhoneNumber: false,
|
isPhoneNumber: false,
|
||||||
|
|
@ -134,7 +153,7 @@ function manageProperties(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (propertyType === 'number') {
|
if (propertyType === 'number') {
|
||||||
formServiceProperties.value?.additional.push({
|
formServiceProperties.value.stepProperties[stepIndex].attributes.push({
|
||||||
type: propertyType,
|
type: propertyType,
|
||||||
fieldName: property,
|
fieldName: property,
|
||||||
comma: false,
|
comma: false,
|
||||||
|
|
@ -146,16 +165,18 @@ function manageProperties(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function shouldShowItem(opt: Option) {
|
function shouldShowItem(opt: Option, stepIndex: number) {
|
||||||
if (formServiceProperties.value) {
|
if (formServiceProperties.value.stepProperties[stepIndex].attributes) {
|
||||||
const additionalFieldNames = new Set(
|
const additionalFieldNames = new Set(
|
||||||
formServiceProperties.value.additional.map((o) => o.fieldName),
|
formServiceProperties.value.stepProperties[stepIndex].attributes.map(
|
||||||
|
(o) => o.fieldName,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
return !!opt && !additionalFieldNames.has(opt.value);
|
return !!opt && !additionalFieldNames.has(opt.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeType(fieldName: string) {
|
function changeType(fieldName: string, stepIndex: number) {
|
||||||
if (!propertiesOption.value) return;
|
if (!propertiesOption.value) return;
|
||||||
|
|
||||||
const defaultPropType = propertiesOption.value.find(
|
const defaultPropType = propertiesOption.value.find(
|
||||||
|
|
@ -164,29 +185,29 @@ function changeType(fieldName: string) {
|
||||||
|
|
||||||
if (!defaultPropType) return;
|
if (!defaultPropType) return;
|
||||||
|
|
||||||
const idx = formServiceProperties.value?.additional.findIndex(
|
const idx = formServiceProperties.value.stepProperties[
|
||||||
(v) => v.fieldName === fieldName,
|
stepIndex
|
||||||
);
|
].attributes.findIndex((v) => v.fieldName === fieldName);
|
||||||
|
|
||||||
if (!idx) return;
|
if (!idx) return;
|
||||||
|
|
||||||
if (defaultPropType === 'date') {
|
if (defaultPropType === 'date') {
|
||||||
formServiceProperties.value?.additional.push({
|
formServiceProperties.value.stepProperties[stepIndex].attributes.push({
|
||||||
type: defaultPropType,
|
type: defaultPropType,
|
||||||
fieldName,
|
fieldName,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defaultPropType === 'array') {
|
if (defaultPropType === 'array') {
|
||||||
formServiceProperties.value?.additional.push({
|
formServiceProperties.value.stepProperties[stepIndex].attributes.push({
|
||||||
type: defaultPropType,
|
type: defaultPropType,
|
||||||
fieldName,
|
fieldName,
|
||||||
options: [''],
|
options: [],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defaultPropType === 'string') {
|
if (defaultPropType === 'string') {
|
||||||
formServiceProperties.value?.additional.push({
|
formServiceProperties.value.stepProperties[stepIndex].attributes.push({
|
||||||
type: defaultPropType,
|
type: defaultPropType,
|
||||||
fieldName,
|
fieldName,
|
||||||
isPhoneNumber: false,
|
isPhoneNumber: false,
|
||||||
|
|
@ -195,7 +216,7 @@ function changeType(fieldName: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defaultPropType === 'number') {
|
if (defaultPropType === 'number') {
|
||||||
formServiceProperties.value?.additional.push({
|
formServiceProperties.value.stepProperties[stepIndex].attributes.push({
|
||||||
type: defaultPropType,
|
type: defaultPropType,
|
||||||
fieldName,
|
fieldName,
|
||||||
comma: false,
|
comma: false,
|
||||||
|
|
@ -218,32 +239,141 @@ function confirmDelete(items: unknown[], index: number) {
|
||||||
cancel: () => {},
|
cancel: () => {},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function filter(val: string, update: (...args: unknown[]) => void) {
|
||||||
|
update(
|
||||||
|
async () => {
|
||||||
|
await fetchWorkflowOption(val);
|
||||||
|
},
|
||||||
|
|
||||||
|
(ref: QSelect) => {
|
||||||
|
if (val !== '' && ref.options && ref.options?.length > 0) {
|
||||||
|
ref.setOptionIndex(-1);
|
||||||
|
ref.moveOptionSelection(1, true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchWorkflowOption(val?: string) {
|
||||||
|
const res = await workflowStore.getWorkflowTemplateList({
|
||||||
|
query: val,
|
||||||
|
pageSize: 30,
|
||||||
|
});
|
||||||
|
if (res) workflowData.value = res.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapStepName(id: string) {
|
||||||
|
const targetFlow = workflowData.value.find(
|
||||||
|
(w) => w.id === formServiceProperties.value.workflowId,
|
||||||
|
);
|
||||||
|
if (!targetFlow) return;
|
||||||
|
const name = targetFlow.step.find((s) => s.id === id)?.name;
|
||||||
|
return name || '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await fetchWorkflowOption();
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => formServiceProperties.value.workflowId,
|
||||||
|
() => {
|
||||||
|
if (!formServiceProperties.value.workflowId) return;
|
||||||
|
formServiceProperties.value.stepProperties = [];
|
||||||
|
currWorkflow.value = workflowData.value.find(
|
||||||
|
(s) => s.id === formServiceProperties.value.workflowId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!currWorkflow.value) return;
|
||||||
|
|
||||||
|
currWorkflow.value.step.forEach((s) => {
|
||||||
|
formServiceProperties.value.stepProperties.push({
|
||||||
|
id: s.id,
|
||||||
|
productsId: [],
|
||||||
|
attributes: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="full-width full-height column no-wrap">
|
<div
|
||||||
<div class="row">
|
class="bordered-b surface-3 row items-center no-wrap q-py-sm"
|
||||||
<q-btn-dropdown
|
:class="{
|
||||||
id="btn-dropdow-properties"
|
'q-px-lg': $q.screen.gt.sm,
|
||||||
for="btn-dropdow-properties"
|
'q-px-md': !$q.screen.gt.sm,
|
||||||
dense
|
}"
|
||||||
unelevated
|
>
|
||||||
color="primary"
|
{{ $t('flow.title') }}
|
||||||
:label="$t('productService.service.properties')"
|
<SelectInput
|
||||||
class="q-px-sm q-mb-lg text-capitalize"
|
v-model="formServiceProperties.workflowId"
|
||||||
menu-anchor="bottom end"
|
id="select-workflow"
|
||||||
|
for="select-workflow"
|
||||||
|
incremental
|
||||||
|
:option="workflowData"
|
||||||
|
option-label="name"
|
||||||
|
option-value="id"
|
||||||
|
class="q-ml-md"
|
||||||
|
:label="$t('general.select', { msg: $t('flow.title') })"
|
||||||
|
@filter="(val: string, update) => filter(val, update)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col column no-wrap">
|
||||||
|
<div
|
||||||
|
v-if="!formServiceProperties?.workflowId"
|
||||||
|
class="bordered rounded surface-1 flex justify-center items-center col"
|
||||||
|
:class="{
|
||||||
|
'q-my-md q-mx-lg': $q.screen.gt.sm,
|
||||||
|
'q-my-sm q-mx-md ': !$q.screen.gt.sm,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<NoData use-field />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- attributes step -->
|
||||||
|
<div v-if="formServiceProperties?.workflowId" class="column">
|
||||||
|
<section
|
||||||
|
v-for="(step, stepIndex) in formServiceProperties.stepProperties"
|
||||||
|
:key="step.id"
|
||||||
|
class="column"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="row items-center q-py-sm bordered-b"
|
||||||
|
:class="{
|
||||||
|
'q-px-lg': $q.screen.gt.sm,
|
||||||
|
'q-px-md ': !$q.screen.gt.sm,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ $t('flow.stepNo', { msg: stepIndex + 1 }) }}
|
||||||
|
<span class="app-text-muted">: {{ mapStepName(step.id) }}</span>
|
||||||
|
<q-btn-dropdown
|
||||||
|
unelevated
|
||||||
|
no-icon-animation
|
||||||
|
size="sm"
|
||||||
|
padding="0 0"
|
||||||
|
class="rounded q-ml-md"
|
||||||
|
dropdown-icon="mdi-plus"
|
||||||
|
style="color: hsl(var(--text-mute))"
|
||||||
|
>
|
||||||
|
<q-list
|
||||||
|
dense
|
||||||
|
v-if="
|
||||||
|
formServiceProperties?.stepProperties[stepIndex].attributes &&
|
||||||
|
propertiesOption
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<q-list dense v-if="formServiceProperties && propertiesOption">
|
|
||||||
<q-item
|
<q-item
|
||||||
for="list-all"
|
for="list-all"
|
||||||
id="list-all"
|
id="list-all"
|
||||||
clickable
|
clickable
|
||||||
@click="manageProperties('all')"
|
@click="manageProperties(stepIndex, 'all')"
|
||||||
>
|
>
|
||||||
<div class="full-width flex items-center">
|
<div class="full-width flex items-center">
|
||||||
<q-icon
|
<q-icon
|
||||||
v-if="
|
v-if="
|
||||||
formServiceProperties.additional.length ===
|
formServiceProperties?.stepProperties[stepIndex]
|
||||||
propertiesOption.length
|
.attributes.length === propertiesOption.length
|
||||||
"
|
"
|
||||||
name="mdi-checkbox-marked"
|
name="mdi-checkbox-marked"
|
||||||
size="xs"
|
size="xs"
|
||||||
|
|
@ -265,17 +395,17 @@ function confirmDelete(items: unknown[], index: number) {
|
||||||
v-for="(ops, index) in propertiesOption"
|
v-for="(ops, index) in propertiesOption"
|
||||||
clickable
|
clickable
|
||||||
:key="index"
|
:key="index"
|
||||||
@click="manageProperties(ops.value, ops.type)"
|
@click="manageProperties(stepIndex, ops.value, ops.type)"
|
||||||
:for="`list-${ops.value}`"
|
:for="`list-${ops.value}`"
|
||||||
:id="`list-${ops.value}`"
|
:id="`list-${ops.value}`"
|
||||||
>
|
>
|
||||||
<div class="full-width flex items-center no-wrap">
|
<div class="full-width flex items-center no-wrap">
|
||||||
<q-icon
|
<q-icon
|
||||||
v-if="
|
v-if="
|
||||||
formServiceProperties &&
|
formServiceProperties?.stepProperties[stepIndex] &&
|
||||||
formServiceProperties.additional.some(
|
formServiceProperties?.stepProperties[
|
||||||
(add) => add.fieldName === ops.value,
|
stepIndex
|
||||||
)
|
].attributes.some((add) => add.fieldName === ops.value)
|
||||||
"
|
"
|
||||||
name="mdi-checkbox-marked"
|
name="mdi-checkbox-marked"
|
||||||
size="xs"
|
size="xs"
|
||||||
|
|
@ -294,29 +424,34 @@ function confirmDelete(items: unknown[], index: number) {
|
||||||
</q-item>
|
</q-item>
|
||||||
</q-list>
|
</q-list>
|
||||||
</q-btn-dropdown>
|
</q-btn-dropdown>
|
||||||
</div>
|
</span>
|
||||||
|
|
||||||
|
<!-- step attribute -->
|
||||||
<div
|
<div
|
||||||
v-if="formServiceProperties?.additional.length === 0"
|
:class="{
|
||||||
class="bordered rounded surface-1 flex justify-center items-center col"
|
'q-px-lg': $q.screen.gt.sm,
|
||||||
>
|
'q-px-md': !$q.screen.gt.sm,
|
||||||
<NoData use-field />
|
}"
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
v-if="
|
|
||||||
formServiceProperties?.additional &&
|
|
||||||
formServiceProperties.additional.length > 0
|
|
||||||
"
|
|
||||||
class="q-gutter-y-md"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-for="(p, index) in formServiceProperties.additional"
|
v-for="(p, index) in formServiceProperties?.stepProperties[
|
||||||
|
stepIndex
|
||||||
|
].attributes"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="bordered surface-1 rounded q-py-sm q-px-md row items-start"
|
class="bordered surface-1 rounded q-py-sm q-px-md row items-start"
|
||||||
:class="
|
:class="{
|
||||||
index === formServiceProperties.additional.length - 1 && 'q-mb-lg'
|
'q-mt-md': index === 0,
|
||||||
"
|
'q-mb-sm':
|
||||||
|
index !==
|
||||||
|
formServiceProperties.stepProperties[stepIndex].attributes
|
||||||
|
.length -
|
||||||
|
1,
|
||||||
|
'q-mb-md':
|
||||||
|
index ===
|
||||||
|
formServiceProperties.stepProperties[stepIndex].attributes
|
||||||
|
.length -
|
||||||
|
1,
|
||||||
|
}"
|
||||||
>
|
>
|
||||||
<div class="col-md col-12 row items-center">
|
<div class="col-md col-12 row items-center">
|
||||||
<q-btn
|
<q-btn
|
||||||
|
|
@ -328,7 +463,12 @@ function confirmDelete(items: unknown[], index: number) {
|
||||||
:disable="index === 0"
|
:disable="index === 0"
|
||||||
:size="$q.screen.xs ? 'xs' : ''"
|
:size="$q.screen.xs ? 'xs' : ''"
|
||||||
style="color: hsl(var(--text-mute-2))"
|
style="color: hsl(var(--text-mute-2))"
|
||||||
@click="moveItemUp(formServiceProperties.additional, index)"
|
@click="
|
||||||
|
moveItemUp(
|
||||||
|
formServiceProperties.stepProperties[stepIndex].attributes,
|
||||||
|
index,
|
||||||
|
)
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
<q-btn
|
<q-btn
|
||||||
id="btn-move-down-product"
|
id="btn-move-down-product"
|
||||||
|
|
@ -337,9 +477,19 @@ function confirmDelete(items: unknown[], index: number) {
|
||||||
flat
|
flat
|
||||||
round
|
round
|
||||||
:size="$q.screen.xs ? 'xs' : ''"
|
:size="$q.screen.xs ? 'xs' : ''"
|
||||||
:disable="index === formServiceProperties.additional.length - 1"
|
:disable="
|
||||||
|
index ===
|
||||||
|
formServiceProperties.stepProperties[stepIndex].attributes
|
||||||
|
.length -
|
||||||
|
1
|
||||||
|
"
|
||||||
style="color: hsl(var(--text-mute-2))"
|
style="color: hsl(var(--text-mute-2))"
|
||||||
@click="moveItemDown(formServiceProperties.additional, index)"
|
@click="
|
||||||
|
moveItemDown(
|
||||||
|
formServiceProperties.stepProperties[stepIndex].attributes,
|
||||||
|
index,
|
||||||
|
)
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<q-avatar
|
<q-avatar
|
||||||
|
|
@ -365,11 +515,11 @@ function confirmDelete(items: unknown[], index: number) {
|
||||||
option-value="value"
|
option-value="value"
|
||||||
:options="propertiesOption"
|
:options="propertiesOption"
|
||||||
v-model="p.fieldName"
|
v-model="p.fieldName"
|
||||||
@update:model-value="changeType"
|
@update:model-value="(v) => changeType(v, stepIndex)"
|
||||||
>
|
>
|
||||||
<template v-slot:option="scope">
|
<template v-slot:option="scope">
|
||||||
<q-item
|
<q-item
|
||||||
v-if="scope.opt && shouldShowItem(scope.opt)"
|
v-if="scope.opt && shouldShowItem(scope.opt, stepIndex)"
|
||||||
v-bind="scope.itemProps"
|
v-bind="scope.itemProps"
|
||||||
class="row items-center col-12"
|
class="row items-center col-12"
|
||||||
>
|
>
|
||||||
|
|
@ -393,24 +543,34 @@ function confirmDelete(items: unknown[], index: number) {
|
||||||
option-value="value"
|
option-value="value"
|
||||||
@update:model-value="
|
@update:model-value="
|
||||||
(t: 'string' | 'number' | 'date' | 'array') => {
|
(t: 'string' | 'number' | 'date' | 'array') => {
|
||||||
if (!formServiceProperties) return;
|
if (
|
||||||
|
!formServiceProperties.stepProperties[stepIndex]
|
||||||
|
.attributes
|
||||||
|
)
|
||||||
|
return;
|
||||||
if (t === 'date') {
|
if (t === 'date') {
|
||||||
formServiceProperties.additional[index] = {
|
formServiceProperties.stepProperties[
|
||||||
|
stepIndex
|
||||||
|
].attributes[index] = {
|
||||||
type: t,
|
type: t,
|
||||||
fieldName: p.fieldName,
|
fieldName: p.fieldName,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t === 'array') {
|
if (t === 'array') {
|
||||||
formServiceProperties.additional[index] = {
|
formServiceProperties.stepProperties[
|
||||||
|
stepIndex
|
||||||
|
].attributes[index] = {
|
||||||
type: t,
|
type: t,
|
||||||
fieldName: p.fieldName,
|
fieldName: p.fieldName,
|
||||||
options: [''],
|
options: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t === 'string') {
|
if (t === 'string') {
|
||||||
formServiceProperties.additional[index] = {
|
formServiceProperties.stepProperties[
|
||||||
|
stepIndex
|
||||||
|
].attributes[index] = {
|
||||||
type: t,
|
type: t,
|
||||||
fieldName: p.fieldName,
|
fieldName: p.fieldName,
|
||||||
isPhoneNumber: false,
|
isPhoneNumber: false,
|
||||||
|
|
@ -419,7 +579,9 @@ function confirmDelete(items: unknown[], index: number) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t === 'number') {
|
if (t === 'number') {
|
||||||
formServiceProperties.additional[index] = {
|
formServiceProperties.stepProperties[
|
||||||
|
stepIndex
|
||||||
|
].attributes[index] = {
|
||||||
type: t,
|
type: t,
|
||||||
fieldName: p.fieldName,
|
fieldName: p.fieldName,
|
||||||
comma: false,
|
comma: false,
|
||||||
|
|
@ -560,7 +722,9 @@ function confirmDelete(items: unknown[], index: number) {
|
||||||
outlined
|
outlined
|
||||||
input-class="text-caption"
|
input-class="text-caption"
|
||||||
:label="$t('form.selection')"
|
:label="$t('form.selection')"
|
||||||
:rules="[(val) => !!val || $t('form.error.required')]"
|
:rules="[
|
||||||
|
(val) => !!val || $t('form.error.required'),
|
||||||
|
]"
|
||||||
hide-bottom-space
|
hide-bottom-space
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -613,10 +777,17 @@ function confirmDelete(items: unknown[], index: number) {
|
||||||
round
|
round
|
||||||
color="negative"
|
color="negative"
|
||||||
class="q-ml-sm"
|
class="q-ml-sm"
|
||||||
@click="confirmDelete(formServiceProperties.additional, index)"
|
@click="
|
||||||
|
confirmDelete(
|
||||||
|
formServiceProperties.stepProperties[stepIndex].attributes,
|
||||||
|
index,
|
||||||
|
)
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,32 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { Icon } from '@iconify/vue';
|
import { QSelect } from 'quasar';
|
||||||
import { formatNumberDecimal } from 'stores/utils';
|
|
||||||
|
|
||||||
import useProductServiceStore from 'stores/product-service';
|
|
||||||
import useOptionStore from 'stores/options';
|
|
||||||
import { Attributes, Product } from 'stores/product-service/types';
|
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { ref, watch } from 'vue';
|
import { Icon } from '@iconify/vue';
|
||||||
|
import { onMounted, ref, watch } from 'vue';
|
||||||
|
|
||||||
|
import useOptionStore from 'stores/options';
|
||||||
|
import useProductServiceStore from 'stores/product-service';
|
||||||
|
import { formatNumberDecimal } from 'stores/utils';
|
||||||
|
import { useWorkflowTemplate } from 'src/stores/workflow-template';
|
||||||
|
import { Attributes, Product } from 'stores/product-service/types';
|
||||||
|
import { WorkflowTemplate } from 'src/stores/workflow-template/types';
|
||||||
|
|
||||||
|
import SelectInput from '../shared/SelectInput.vue';
|
||||||
|
import NoData from '../NoData.vue';
|
||||||
|
import { AddButton } from '../button';
|
||||||
|
|
||||||
const baseUrl = ref<string>(import.meta.env.VITE_API_BASE_URL);
|
const baseUrl = ref<string>(import.meta.env.VITE_API_BASE_URL);
|
||||||
const productServiceStore = useProductServiceStore();
|
const productServiceStore = useProductServiceStore();
|
||||||
const optionStore = useOptionStore();
|
const optionStore = useOptionStore();
|
||||||
|
const workflowStore = useWorkflowTemplate();
|
||||||
|
|
||||||
const { fetchListOfWork } = productServiceStore;
|
// const { fetchListOfWork } = productServiceStore;
|
||||||
const { workNameItems } = storeToRefs(productServiceStore);
|
const { splitPay } = storeToRefs(productServiceStore);
|
||||||
|
|
||||||
withDefaults(
|
const { getWorkflowTemplateList } = workflowStore;
|
||||||
|
const { data: workflowData } = storeToRefs(workflowStore);
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
workIndex: number;
|
workIndex: number;
|
||||||
length: number;
|
length: number;
|
||||||
|
|
@ -46,7 +57,7 @@ const productItems = defineModel<(Product & { nameEn: string })[]>(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const refMenu = ref();
|
// const refMenu = ref();
|
||||||
|
|
||||||
defineEmits<{
|
defineEmits<{
|
||||||
(e: 'moveWorkUp'): void;
|
(e: 'moveWorkUp'): void;
|
||||||
|
|
@ -61,18 +72,94 @@ defineEmits<{
|
||||||
(e: 'workProperties'): void;
|
(e: 'workProperties'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
watch(
|
// watch(
|
||||||
() => workNameItems.value,
|
// () => workNameItems.value,
|
||||||
(c, o) => {
|
// (c, o) => {
|
||||||
const list = c.map((v: { name: string }) => v.name);
|
// const list = c.map((v: { name: string }) => v.name);
|
||||||
const oldList = o.map((v: { name: string }) => v.name);
|
// const oldList = o.map((v: { name: string }) => v.name);
|
||||||
const index = oldList.indexOf(workName.value);
|
// const index = oldList.indexOf(workName.value);
|
||||||
|
|
||||||
if (list[index] !== oldList[index] && !list.includes(workName.value)) {
|
// if (list[index] !== oldList[index] && !list.includes(workName.value)) {
|
||||||
if (list.length - 1 === index - 1) workName.value = list[index - 1];
|
// if (list.length - 1 === index - 1) workName.value = list[index - 1];
|
||||||
else workName.value = list[index];
|
// else workName.value = list[index];
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
|
||||||
|
function mapFlowName(id: string): string {
|
||||||
|
const targetFlow = workflowData.value.find(
|
||||||
|
(w) => w.id === attributes.value.workflowId,
|
||||||
|
);
|
||||||
|
return targetFlow?.name || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapStepName(id: string) {
|
||||||
|
const targetFlow = workflowData.value.find(
|
||||||
|
(w) => w.id === attributes.value.workflowId,
|
||||||
|
);
|
||||||
|
if (!targetFlow) return;
|
||||||
|
const name = targetFlow.step.find((s) => s.id === id)?.name;
|
||||||
|
return name || '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectFlow(workflow: WorkflowTemplate) {
|
||||||
|
workName.value = workflow.name;
|
||||||
|
attributes.value.workflowId = workflow.id;
|
||||||
|
attributes.value.stepProperties = workflow.step.map((s) => ({
|
||||||
|
id: s.id,
|
||||||
|
attributes: [],
|
||||||
|
productsId: [],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function filter(val: string, update: (...args: unknown[]) => void) {
|
||||||
|
update(
|
||||||
|
async () => {
|
||||||
|
await fetchWorkflowOption(val);
|
||||||
|
},
|
||||||
|
|
||||||
|
(ref: QSelect) => {
|
||||||
|
if (val !== '' && ref.options && ref.options?.length > 0) {
|
||||||
|
ref.setOptionIndex(-1);
|
||||||
|
ref.moveOptionSelection(1, true);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchWorkflowOption(val?: string) {
|
||||||
|
const res = await workflowStore.getWorkflowTemplateList({
|
||||||
|
query: val,
|
||||||
|
pageSize: 30,
|
||||||
|
});
|
||||||
|
if (res) workflowData.value = res.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleCheckProductInStep(id: string, stepIndex: number) {
|
||||||
|
const index =
|
||||||
|
attributes.value.stepProperties[stepIndex].productsId.indexOf(id);
|
||||||
|
|
||||||
|
if (!attributes.value.stepProperties[stepIndex].productsId.includes(id)) {
|
||||||
|
attributes.value.stepProperties[stepIndex].productsId.push(id);
|
||||||
|
} else {
|
||||||
|
attributes.value.stepProperties[stepIndex].productsId.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
if (props.workIndex === 0) {
|
||||||
|
await fetchWorkflowOption();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => productItems.value,
|
||||||
|
() => {
|
||||||
|
attributes.value.stepProperties.forEach((s) => {
|
||||||
|
s.productsId = productItems.value.map((p) => p.id);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ deep: true },
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -84,7 +171,7 @@ watch(
|
||||||
switch-toggle-side
|
switch-toggle-side
|
||||||
default-opened
|
default-opened
|
||||||
expand-icon="mdi-chevron-down-circle"
|
expand-icon="mdi-chevron-down-circle"
|
||||||
header-class="surface-2 expansion-rounded"
|
header-class="expansion-rounded"
|
||||||
header-style="border-top-left-radius: var(--radius-2); border-top-right-radius: var(--radius-2)"
|
header-style="border-top-left-radius: var(--radius-2); border-top-right-radius: var(--radius-2)"
|
||||||
>
|
>
|
||||||
<template v-slot:header>
|
<template v-slot:header>
|
||||||
|
|
@ -115,7 +202,7 @@ watch(
|
||||||
style="color: hsl(var(--text-mute-2))"
|
style="color: hsl(var(--text-mute-2))"
|
||||||
@click.stop="$emit('moveWorkDown')"
|
@click.stop="$emit('moveWorkDown')"
|
||||||
/>
|
/>
|
||||||
<div
|
<!-- <div
|
||||||
:for="`select-work-name-${index + 1}`"
|
:for="`select-work-name-${index + 1}`"
|
||||||
class="col q-py-sm q-px-md"
|
class="col q-py-sm q-px-md"
|
||||||
style="background-color: var(--surface-1); z-index: 2"
|
style="background-color: var(--surface-1); z-index: 2"
|
||||||
|
|
@ -184,7 +271,28 @@ watch(
|
||||||
</div>
|
</div>
|
||||||
</q-item>
|
</q-item>
|
||||||
</q-menu>
|
</q-menu>
|
||||||
</div>
|
</div> -->
|
||||||
|
<SelectInput
|
||||||
|
:readonly
|
||||||
|
incremental
|
||||||
|
:model-value="mapFlowName(attributes.workflowId)"
|
||||||
|
id="select-workflow-name"
|
||||||
|
for="select-workflow-name"
|
||||||
|
class="col"
|
||||||
|
option-label="name"
|
||||||
|
:option="workflowData"
|
||||||
|
:placeholder="$t('productService.service.workName')"
|
||||||
|
@update:model-value="(val: WorkflowTemplate) => selectFlow(val)"
|
||||||
|
@filter="(val: string, update) => filter(val, update)"
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<span class="text-body2" style="color: var(--foreground)">
|
||||||
|
{{
|
||||||
|
$t('productService.service.workNo', { msg: workIndex + 1 })
|
||||||
|
}}:
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</SelectInput>
|
||||||
<q-btn
|
<q-btn
|
||||||
v-if="!readonly"
|
v-if="!readonly"
|
||||||
id="btn-delete-work"
|
id="btn-delete-work"
|
||||||
|
|
@ -203,60 +311,14 @@ watch(
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="surface-2">
|
<section
|
||||||
<!-- properties -->
|
v-if="!workName && productItems.length === 0"
|
||||||
<div class="bordered-t">
|
class="surface-2 row items-center justify-center q-py-sm"
|
||||||
<div
|
|
||||||
class="q-py-xs text-weight-medium row justify-between items-center q-px-md"
|
|
||||||
style="background-color: hsla(var(--info-bg) / 0.1)"
|
|
||||||
>
|
>
|
||||||
<span>
|
<NoData />
|
||||||
{{ $t('productService.service.propertiesInWork') }}
|
</section>
|
||||||
{{ workIndex + 1 }}
|
|
||||||
</span>
|
|
||||||
<q-btn
|
|
||||||
v-if="!readonly"
|
|
||||||
id="btn-add-work-product"
|
|
||||||
class="text-capitalize"
|
|
||||||
flat
|
|
||||||
dense
|
|
||||||
padding="0"
|
|
||||||
style="color: hsl(var(--info-bg))"
|
|
||||||
@click.stop="$emit('workProperties')"
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
icon="basil:settings-adjust-solid"
|
|
||||||
width="24px"
|
|
||||||
class="q-mr-sm"
|
|
||||||
style="color: hsl(var(--info-bg))"
|
|
||||||
/>
|
|
||||||
<span v-if="$q.screen.gt.xs">
|
|
||||||
{{ $t('productService.service.properties') }}
|
|
||||||
</span>
|
|
||||||
</q-btn>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="q-py-md q-px-md full-width">
|
|
||||||
<div
|
|
||||||
v-if="attributes.additional.length > 0"
|
|
||||||
class="row items-center full-width surface-1 q-pb-md q-pt-sm q-px-sm q-gutter-sm scroll"
|
|
||||||
:style="$q.screen.xs ? 'max-height: 100px' : ''"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-for="(p, index) in attributes.additional"
|
|
||||||
:key="index"
|
|
||||||
class="bordered q-px-sm surface-3"
|
|
||||||
style="border-radius: 6px"
|
|
||||||
>
|
|
||||||
{{ optionStore.mapOption(p.fieldName ?? '') }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div v-else class="app-text-muted">
|
|
||||||
{{ $t('productService.service.noProperties') }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<section v-else class="surface-2">
|
||||||
<!-- product -->
|
<!-- product -->
|
||||||
<div class="bordered-t">
|
<div class="bordered-t">
|
||||||
<div
|
<div
|
||||||
|
|
@ -276,19 +338,11 @@ watch(
|
||||||
:disable="readonly"
|
:disable="readonly"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<q-btn
|
<AddButton
|
||||||
v-if="!readonly"
|
v-if="!readonly"
|
||||||
|
icon-only
|
||||||
id="btn-add-work-product"
|
id="btn-add-work-product"
|
||||||
for="btn-add-work-product"
|
for="btn-add-work-product"
|
||||||
flat
|
|
||||||
dense
|
|
||||||
icon="mdi-plus"
|
|
||||||
class="text-capitalize"
|
|
||||||
:label="
|
|
||||||
$q.screen.gt.xs ? $t('productService.product.addTitle') : ''
|
|
||||||
"
|
|
||||||
padding="0"
|
|
||||||
style="color: hsl(var(--info-bg))"
|
|
||||||
@click.stop="$emit('addProduct')"
|
@click.stop="$emit('addProduct')"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -297,15 +351,17 @@ watch(
|
||||||
v-if="productItems.length > 0"
|
v-if="productItems.length > 0"
|
||||||
class="q-py-md q-px-md full-width q-gutter-y-sm"
|
class="q-py-md q-px-md full-width q-gutter-y-sm"
|
||||||
>
|
>
|
||||||
<div
|
<section
|
||||||
v-for="(product, index) in productItems"
|
v-for="(product, index) in productItems"
|
||||||
:key="product.id"
|
:key="product.id"
|
||||||
class="full-width row items-center justify-between"
|
class="full-width row items-center justify-between"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="row col items-center justify-between full-width surface-1 q-py-md q-px-sm"
|
class="row col items-center justify-between full-width surface-1 q-px-sm q-py-xs"
|
||||||
|
style="min-height: 70px"
|
||||||
>
|
>
|
||||||
<div
|
<!-- product detail -->
|
||||||
|
<section
|
||||||
class="row items-center col-md col-12 no-wrap"
|
class="row items-center col-md col-12 no-wrap"
|
||||||
v-if="productItems"
|
v-if="productItems"
|
||||||
>
|
>
|
||||||
|
|
@ -316,6 +372,7 @@ watch(
|
||||||
dense
|
dense
|
||||||
flat
|
flat
|
||||||
round
|
round
|
||||||
|
size="sm"
|
||||||
:disable="index === 0"
|
:disable="index === 0"
|
||||||
style="color: hsl(var(--text-mute-2))"
|
style="color: hsl(var(--text-mute-2))"
|
||||||
@click.stop="$emit('moveProductUp', productItems, index)"
|
@click.stop="$emit('moveProductUp', productItems, index)"
|
||||||
|
|
@ -328,27 +385,27 @@ watch(
|
||||||
dense
|
dense
|
||||||
flat
|
flat
|
||||||
round
|
round
|
||||||
class="q-mx-sm"
|
size="sm"
|
||||||
:disable="index === productItems.length - 1"
|
:disable="index === productItems.length - 1"
|
||||||
style="color: hsl(var(--text-mute-2))"
|
style="color: hsl(var(--text-mute-2))"
|
||||||
@click.stop="$emit('moveProductDown', productItems, index)"
|
@click.stop="$emit('moveProductDown', productItems, index)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<q-avatar
|
<q-avatar
|
||||||
size="md"
|
size="sm"
|
||||||
:class="$q.screen.gt.xs ? 'q-mx-lg' : 'q-mr-lg'"
|
class="q-mx-sm"
|
||||||
style="background-color: var(--surface-tab)"
|
style="background-color: var(--surface-tab)"
|
||||||
>
|
>
|
||||||
{{ index + 1 }}
|
{{ index + 1 }}
|
||||||
</q-avatar>
|
</q-avatar>
|
||||||
|
|
||||||
<div class="row no-wrap">
|
<div class="col row no-wrap items-center">
|
||||||
<div
|
<div
|
||||||
v-if="$q.screen.gt.xs"
|
v-if="$q.screen.gt.xs"
|
||||||
class="bordered q-mx-md col-3 image-box"
|
class="bordered q-mx-md col-3 image-box"
|
||||||
>
|
>
|
||||||
<q-img
|
<q-img
|
||||||
:src="`${baseUrl}/product/${product?.id}/image`"
|
:src="`${baseUrl}/product/${product.id}/image/${product.selectedImage}`"
|
||||||
style="object-fit: cover; width: 100%; height: 100%"
|
style="object-fit: cover; width: 100%; height: 100%"
|
||||||
>
|
>
|
||||||
<template #error>
|
<template #error>
|
||||||
|
|
@ -360,35 +417,30 @@ watch(
|
||||||
</template>
|
</template>
|
||||||
</q-img>
|
</q-img>
|
||||||
</div>
|
</div>
|
||||||
<div class="column col justify-between">
|
<article class="column col full-width justify-between">
|
||||||
<span
|
<span
|
||||||
class="text-weight-bold ellipsis-2-lines"
|
class="text-weight-medium ellipsis-2-lines full-width"
|
||||||
:style="`max-width: ${$q.screen.gt.sm ? (!readonly ? '10vw' : '25vw') : '20vw'}`"
|
|
||||||
>
|
>
|
||||||
{{ product.name }}
|
{{ product.name }}
|
||||||
<q-tooltip>
|
<q-tooltip>
|
||||||
{{ product.name }}
|
{{ product.name }}
|
||||||
</q-tooltip>
|
</q-tooltip>
|
||||||
</span>
|
</span>
|
||||||
<div
|
<div class="text-caption">
|
||||||
class="bordered q-px-xs ellipsis"
|
<span class="bordered q-px-xs rounded q-mr-sm">
|
||||||
style="border-radius: 6px; max-width: 100px"
|
|
||||||
>
|
|
||||||
{{ product.code }}
|
{{ product.code }}
|
||||||
</div>
|
</span>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
<q-icon name="mdi-clock-outline" />
|
||||||
class="row justify-end text-right col-md-6 col-12"
|
{{ product.process }} {{ $t('general.day') }}
|
||||||
:class="$q.screen.xs ? 'q-mt-sm text-caption' : 'q-pr-sm'"
|
</div>
|
||||||
>
|
</article>
|
||||||
<span
|
</div>
|
||||||
class="col-12 row"
|
</section>
|
||||||
:class="{ 'q-col-gutter-md': $q.screen.gt.xs }"
|
|
||||||
style="color: var(--teal-9)"
|
<!-- product price -->
|
||||||
>
|
<div class="row justify-end text-right col-md col-12">
|
||||||
|
<span class="col-12 row" style="color: var(--teal-9)">
|
||||||
<span
|
<span
|
||||||
v-if="priceDisplay?.price"
|
v-if="priceDisplay?.price"
|
||||||
class="col ellipsis price-orange text-weight-bold"
|
class="col ellipsis price-orange text-weight-bold"
|
||||||
|
|
@ -437,28 +489,33 @@ watch(
|
||||||
฿{{ formatNumberDecimal(product.serviceCharge, 2) }}
|
฿{{ formatNumberDecimal(product.serviceCharge, 2) }}
|
||||||
</q-tooltip>
|
</q-tooltip>
|
||||||
</span>
|
</span>
|
||||||
<span class="col ellipsis text-weight-bold">
|
<span class="col ellipsis column text-weight-medium">
|
||||||
<div class="text-caption app-text-muted-2">
|
<div class="text-caption app-text-muted-2">
|
||||||
งวดที่จ่าย
|
งวดที่จ่าย
|
||||||
</div>
|
</div>
|
||||||
{{ !readonly ? '' : product.installmentNo }}
|
{{ !readonly ? '' : product.installmentNo }}
|
||||||
|
<span class="row justify-end">
|
||||||
<q-input
|
<q-input
|
||||||
v-if="!readonly && $q.screen.gt.xs"
|
v-if="!readonly && $q.screen.gt.xs"
|
||||||
outlined
|
outlined
|
||||||
|
:max="splitPay"
|
||||||
|
input-class="text-right no-padding"
|
||||||
for="input-bankbook"
|
for="input-bankbook"
|
||||||
hide-bottom-space
|
hide-bottom-space
|
||||||
class="col-2"
|
class="installment-no col-10"
|
||||||
dense
|
dense
|
||||||
type="number"
|
type="number"
|
||||||
v-model="product.installmentNo"
|
v-model="product.installmentNo"
|
||||||
min="0"
|
min="0"
|
||||||
|
@update:model-value="
|
||||||
|
(v) => {
|
||||||
|
if (Number(v) > splitPay)
|
||||||
|
product.installmentNo = splitPay;
|
||||||
|
}
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class="col-9 q-mt-sm text-caption app-text-muted-2">
|
|
||||||
{{ $t('productService.product.processingTime') }}
|
|
||||||
{{ product.process }} {{ $t('general.day') }}
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -478,19 +535,149 @@ watch(
|
||||||
>
|
>
|
||||||
<q-tooltip>{{ $t('general.delete') }}</q-tooltip>
|
<q-tooltip>{{ $t('general.delete') }}</q-tooltip>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div v-else class="app-text-muted q-py-md q-px-md">
|
||||||
<div v-else class="app-text-muted q-py-md q-px-lg">
|
|
||||||
{{ $t('productService.product.noProduct') }}
|
{{ $t('productService.product.noProduct') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- properties -->
|
||||||
|
<div class="bordered-t">
|
||||||
|
<div
|
||||||
|
class="q-py-xs text-weight-medium row justify-between items-center q-px-md"
|
||||||
|
style="background-color: hsla(var(--info-bg) / 0.1)"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
{{ $t('flow.processStep') }}
|
||||||
|
</span>
|
||||||
|
<q-btn
|
||||||
|
v-if="!readonly"
|
||||||
|
id="btn-add-work-product"
|
||||||
|
class="text-capitalize rounded"
|
||||||
|
flat
|
||||||
|
dense
|
||||||
|
padding="4px 8px"
|
||||||
|
style="color: hsl(var(--info-bg))"
|
||||||
|
@click.stop="$emit('workProperties')"
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
icon="basil:settings-adjust-solid"
|
||||||
|
width="20.08px"
|
||||||
|
style="color: hsl(var(--info-bg))"
|
||||||
|
/>
|
||||||
|
</q-btn>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="q-py-md q-px-md full-width column">
|
||||||
|
<span
|
||||||
|
v-if="
|
||||||
|
attributes.stepProperties?.length === 0 ||
|
||||||
|
!attributes.stepProperties
|
||||||
|
"
|
||||||
|
class="app-text-muted"
|
||||||
|
>
|
||||||
|
{{ $t('flow.noProcessStep') }}
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
v-else
|
||||||
|
v-for="(step, stepIndex) in attributes.stepProperties"
|
||||||
|
:key="step.id"
|
||||||
|
>
|
||||||
|
<q-icon name="mdi-circle-medium" />
|
||||||
|
{{ $t('flow.stepNo', { msg: stepIndex + 1 }) }}:
|
||||||
|
{{ mapStepName(step.id) }}
|
||||||
|
|
||||||
|
<!-- step att -->
|
||||||
|
<section
|
||||||
|
class="col scroll q-pa-sm flex items-center surface-1 rounded"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="
|
||||||
|
attributes.stepProperties[stepIndex].attributes.length > 0
|
||||||
|
"
|
||||||
|
class="row q-gutter-sm"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
v-for="(att, i) in step.attributes"
|
||||||
|
:key="i"
|
||||||
|
class="surface-2 bordered rounded q-px-xs"
|
||||||
|
>
|
||||||
|
{{ optionStore.mapOption(att.fieldName ?? '') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div v-else class="app-text-muted-2">
|
||||||
|
{{ $t('productService.service.noProperties') }}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- step product -->
|
||||||
|
<section
|
||||||
|
class="q-pt-sm q-pl-lg column"
|
||||||
|
:class="{
|
||||||
|
'q-pb-sm': stepIndex !== attributes.stepProperties.length - 1,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<span class="app-text-muted-2 text-caption">
|
||||||
|
{{
|
||||||
|
$t('general.select', {
|
||||||
|
msg: $t('productService.product.title'),
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="productItems.length > 0"
|
||||||
|
class="surface-1 rounded q-pa-xs"
|
||||||
|
>
|
||||||
|
<div v-for="product in productItems" :key="product.id">
|
||||||
|
<q-checkbox
|
||||||
|
:disable="readonly"
|
||||||
|
:model-value="
|
||||||
|
attributes.stepProperties[
|
||||||
|
stepIndex
|
||||||
|
].productsId.includes(product.id)
|
||||||
|
"
|
||||||
|
@click="toggleCheckProductInStep(product.id, stepIndex)"
|
||||||
|
size="xs"
|
||||||
|
/>
|
||||||
|
{{ product.name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span v-else class="app-text-muted-2 surface-1 rounded q-pa-xs">
|
||||||
|
{{ $t('productService.product.noProduct') }}
|
||||||
|
</span>
|
||||||
|
</section>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- <div class="q-py-md q-px-md full-width">
|
||||||
|
<div
|
||||||
|
v-if="attributes.additional.length > 0"
|
||||||
|
class="row items-center full-width surface-1 q-pb-md q-pt-sm q-px-sm q-gutter-sm scroll"
|
||||||
|
:style="$q.screen.xs ? 'max-height: 100px' : ''"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="(p, index) in attributes.additional"
|
||||||
|
:key="index"
|
||||||
|
class="bordered q-px-sm surface-3"
|
||||||
|
style="border-radius: 6px"
|
||||||
|
>
|
||||||
|
{{ optionStore.mapOption(p.fieldName ?? '') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="app-text-muted">
|
||||||
|
{{ $t('productService.service.noProperties') }}
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</q-expansion-item>
|
</q-expansion-item>
|
||||||
<div class="q-py-sm q-px-md bordered-t row items-center justify-between">
|
<div class="q-py-sm q-px-md bordered-t row items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
{{ $t('productService.service.totalProductWork') }}
|
{{ $t('productService.service.totalProductWork') }}
|
||||||
<span class="app-text-muted-2">
|
<span class="app-text-muted-2">
|
||||||
{{ workName }}
|
{{ mapFlowName(attributes.workflowId) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -502,8 +689,8 @@ watch(
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.image-box {
|
.image-box {
|
||||||
height: 70px;
|
height: 45px;
|
||||||
width: 70px;
|
width: 45px;
|
||||||
border-color: var(--teal-9);
|
border-color: var(--teal-9);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
background-color: var(--surface-3);
|
background-color: var(--surface-3);
|
||||||
|
|
@ -540,4 +727,18 @@ watch(
|
||||||
.price-pink {
|
.price-pink {
|
||||||
color: var(--pink-6);
|
color: var(--pink-6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:deep(i.q-icon.mdi.mdi-chevron-down-circle.q-expansion-item__toggle-icon) {
|
||||||
|
color: hsl(var(--text-mute));
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(
|
||||||
|
i.q-icon.mdi.mdi-chevron-down-circle.q-expansion-item__toggle-icon.q-expansion-item__toggle-icon--rotated
|
||||||
|
) {
|
||||||
|
color: var(--brand-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.installment-no .q-field__control) {
|
||||||
|
height: 23px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ import {
|
||||||
Attributes,
|
Attributes,
|
||||||
} from 'stores/product-service/types';
|
} from 'stores/product-service/types';
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
import { WorkflowTemplate } from 'src/stores/workflow-template/types';
|
||||||
|
|
||||||
const flowStore = useFlowStore();
|
const flowStore = useFlowStore();
|
||||||
const utilsStore = useUtilsStore();
|
const utilsStore = useUtilsStore();
|
||||||
|
|
@ -94,7 +95,7 @@ const {
|
||||||
deleteWork,
|
deleteWork,
|
||||||
} = productServiceStore;
|
} = productServiceStore;
|
||||||
|
|
||||||
const { workNameItems } = storeToRefs(productServiceStore);
|
const { workNameItems, splitPay } = storeToRefs(productServiceStore);
|
||||||
const readOnlybranchOption = ref<boolean>(false);
|
const readOnlybranchOption = ref<boolean>(false);
|
||||||
const allStat = ref<{ mode: string; count: number }[]>([]);
|
const allStat = ref<{ mode: string; count: number }[]>([]);
|
||||||
const stat = ref<
|
const stat = ref<
|
||||||
|
|
@ -264,10 +265,14 @@ const formDataProduct = ref<ProductCreate>({
|
||||||
image: undefined,
|
image: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const workflow = ref<WorkflowTemplate>();
|
||||||
const formDataProductService = ref<ServiceCreate>({
|
const formDataProductService = ref<ServiceCreate>({
|
||||||
work: [],
|
work: [],
|
||||||
attributes: {
|
attributes: {
|
||||||
|
showTotalPrice: false,
|
||||||
additional: [],
|
additional: [],
|
||||||
|
workflowId: '',
|
||||||
|
stepProperties: [],
|
||||||
},
|
},
|
||||||
detail: '',
|
detail: '',
|
||||||
name: '',
|
name: '',
|
||||||
|
|
@ -892,6 +897,9 @@ async function assignFormDataGroup(data: ProductGroup) {
|
||||||
const prevService = ref<ServiceCreate>({
|
const prevService = ref<ServiceCreate>({
|
||||||
work: [],
|
work: [],
|
||||||
attributes: {
|
attributes: {
|
||||||
|
showTotalPrice: false,
|
||||||
|
workflowId: '',
|
||||||
|
stepProperties: [],
|
||||||
additional: [],
|
additional: [],
|
||||||
},
|
},
|
||||||
detail: '',
|
detail: '',
|
||||||
|
|
@ -941,6 +949,11 @@ async function assignFormDataProductService(id: string) {
|
||||||
formDataProductService.value.work = prevService.value.work;
|
formDataProductService.value.work = prevService.value.work;
|
||||||
|
|
||||||
workItems.value = res.work.map((item) => {
|
workItems.value = res.work.map((item) => {
|
||||||
|
splitPay.value = Math.max(
|
||||||
|
...item.productOnWork.map(
|
||||||
|
(productOnWorkItem) => productOnWorkItem.installmentNo,
|
||||||
|
),
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
id: item.id,
|
id: item.id,
|
||||||
name: item.name,
|
name: item.name,
|
||||||
|
|
@ -1043,13 +1056,16 @@ function clearFormService() {
|
||||||
name: '',
|
name: '',
|
||||||
detail: '',
|
detail: '',
|
||||||
attributes: {
|
attributes: {
|
||||||
|
workflowId: '',
|
||||||
|
stepProperties: [],
|
||||||
additional: [],
|
additional: [],
|
||||||
|
showTotalPrice: false,
|
||||||
},
|
},
|
||||||
work: [],
|
work: [],
|
||||||
status: undefined,
|
status: undefined,
|
||||||
productGroupId: '',
|
productGroupId: '',
|
||||||
};
|
};
|
||||||
|
splitPay.value = 0;
|
||||||
workItems.value = [];
|
workItems.value = [];
|
||||||
selectProduct.value = [];
|
selectProduct.value = [];
|
||||||
dialogService.value = false;
|
dialogService.value = false;
|
||||||
|
|
@ -1229,6 +1245,9 @@ function triggerConfirmCloseWork() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const tempValueProperties = ref<Attributes>({
|
const tempValueProperties = ref<Attributes>({
|
||||||
|
showTotalPrice: false,
|
||||||
|
workflowId: '',
|
||||||
|
stepProperties: [],
|
||||||
additional: [],
|
additional: [],
|
||||||
});
|
});
|
||||||
const currentPropertiesMode = ref<'service' | 'work'>('service');
|
const currentPropertiesMode = ref<'service' | 'work'>('service');
|
||||||
|
|
@ -3818,13 +3837,13 @@ watch(
|
||||||
<div
|
<div
|
||||||
class="col surface-1 rounded bordered scroll row relative-position"
|
class="col surface-1 rounded bordered scroll row relative-position"
|
||||||
:class="{
|
:class="{
|
||||||
'q-mb-lg q-mx-lg ': $q.screen.gt.sm,
|
'q-mb-md q-mx-lg ': $q.screen.gt.sm,
|
||||||
'q-mb-sm q-mx-md': !$q.screen.gt.sm,
|
'q-mb-sm q-mx-md': !$q.screen.gt.sm,
|
||||||
}"
|
}"
|
||||||
id="service-form"
|
id="service-form"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="col"
|
class="col column justify-between"
|
||||||
style="height: 100%; max-height: 100; overflow-y: auto"
|
style="height: 100%; max-height: 100; overflow-y: auto"
|
||||||
v-if="$q.screen.gt.sm"
|
v-if="$q.screen.gt.sm"
|
||||||
>
|
>
|
||||||
|
|
@ -3876,6 +3895,20 @@ watch(
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<span
|
||||||
|
class="row items-center justify-center q-py-md text-caption no-wrap"
|
||||||
|
>
|
||||||
|
{{ $t('productService.service.splitPay') }}
|
||||||
|
<q-input
|
||||||
|
dense
|
||||||
|
outlined
|
||||||
|
class="col-3 split-pay q-mx-sm"
|
||||||
|
input-class="text-caption text-right"
|
||||||
|
type="number"
|
||||||
|
v-model="splitPay"
|
||||||
|
/>
|
||||||
|
{{ $t('quotation.receiptDialog.installments') }}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="col-12 col-md-10"
|
class="col-12 col-md-10"
|
||||||
|
|
@ -3973,7 +4006,7 @@ watch(
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<!-- <div
|
||||||
class="col-2 surface-1 rounded bordered row"
|
class="col-2 surface-1 rounded bordered row"
|
||||||
:class="{
|
:class="{
|
||||||
'q-mb-lg q-mx-lg ': $q.screen.gt.sm,
|
'q-mb-lg q-mx-lg ': $q.screen.gt.sm,
|
||||||
|
|
@ -3993,7 +4026,7 @@ watch(
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div> -->
|
||||||
</DialogForm>
|
</DialogForm>
|
||||||
|
|
||||||
<!-- service properties -->
|
<!-- service properties -->
|
||||||
|
|
@ -4026,12 +4059,12 @@ watch(
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div class="q-pa-lg full-width full-height">
|
<section class="col column">
|
||||||
<ServiceProperties
|
<ServiceProperties
|
||||||
v-model:properties-option="propertiesOption"
|
v-model:properties-option="propertiesOption"
|
||||||
v-model:form-service-properties="tempValueProperties"
|
v-model:form-service-properties="tempValueProperties"
|
||||||
/>
|
/>
|
||||||
</div>
|
</section>
|
||||||
</DialogForm>
|
</DialogForm>
|
||||||
|
|
||||||
<!-- manage work name -->
|
<!-- manage work name -->
|
||||||
|
|
@ -4241,7 +4274,7 @@ watch(
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="col"
|
class="col column justify-between"
|
||||||
style="height: 100%; max-height: 100; overflow-y: auto"
|
style="height: 100%; max-height: 100; overflow-y: auto"
|
||||||
v-if="$q.screen.gt.sm"
|
v-if="$q.screen.gt.sm"
|
||||||
>
|
>
|
||||||
|
|
@ -4297,13 +4330,28 @@ watch(
|
||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<span
|
||||||
|
class="row items-center justify-center q-py-md text-caption no-wrap"
|
||||||
|
>
|
||||||
|
{{ $t('productService.service.splitPay') }}
|
||||||
|
<q-input
|
||||||
|
:readonly="!infoServiceEdit"
|
||||||
|
dense
|
||||||
|
outlined
|
||||||
|
class="col-3 split-pay q-mx-sm"
|
||||||
|
input-class="text-caption text-right"
|
||||||
|
type="number"
|
||||||
|
v-model="splitPay"
|
||||||
|
/>
|
||||||
|
{{ $t('quotation.receiptDialog.installments') }}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="col-12 col-md-10"
|
class="col-12 col-md-10"
|
||||||
id="customer-form-content"
|
id="customer-form-content"
|
||||||
:class="{
|
:class="{
|
||||||
'q-py-md q-pr-md ': $q.screen.gt.sm,
|
'q-py-md q-pr-md ': $q.screen.gt.sm,
|
||||||
'q-py-md q-px-lg': !$q.screen.gt.sm,
|
'q-py-sm q-px-lg': !$q.screen.gt.sm,
|
||||||
}"
|
}"
|
||||||
style="height: 100%; max-height: 100%; overflow-y: auto"
|
style="height: 100%; max-height: 100%; overflow-y: auto"
|
||||||
>
|
>
|
||||||
|
|
@ -4354,7 +4402,7 @@ watch(
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<!-- <div
|
||||||
class="col-2 surface-1 rounded bordered row"
|
class="col-2 surface-1 rounded bordered row"
|
||||||
:class="{
|
:class="{
|
||||||
'q-mb-lg q-mx-lg ': $q.screen.gt.sm,
|
'q-mb-lg q-mx-lg ': $q.screen.gt.sm,
|
||||||
|
|
@ -4375,7 +4423,7 @@ watch(
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div> -->
|
||||||
</DialogForm>
|
</DialogForm>
|
||||||
|
|
||||||
<q-dialog v-model="holdDialog" position="bottom">
|
<q-dialog v-model="holdDialog" position="bottom">
|
||||||
|
|
@ -4751,4 +4799,8 @@ watch(
|
||||||
color: hsl(var(--info-bg));
|
color: hsl(var(--info-bg));
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:deep(.split-pay .q-field__control) {
|
||||||
|
height: 23px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue