feat(customer): creatable select business type
Some checks failed
Spell Check / Spell Check with Typos (push) Failing after 5s
Some checks failed
Spell Check / Spell Check with Typos (push) Failing after 5s
This commit is contained in:
parent
ff94980b06
commit
77f66ca302
3 changed files with 150 additions and 45 deletions
97
src/components/shared/select/SelectBase.vue
Normal file
97
src/components/shared/select/SelectBase.vue
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
<script lang="ts" setup generic="T extends Record<string, unknown>">
|
||||||
|
import { QSelect } from 'quasar';
|
||||||
|
|
||||||
|
const model = defineModel<string | string[] | Record<string, unknown> | null>();
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
id?: string;
|
||||||
|
label?: string;
|
||||||
|
options: T[];
|
||||||
|
optionLabel?: keyof T | string;
|
||||||
|
optionValue?: keyof T | string;
|
||||||
|
placeholder?: string;
|
||||||
|
|
||||||
|
readonly?: boolean;
|
||||||
|
clearable?: boolean;
|
||||||
|
disable?: boolean;
|
||||||
|
multiple?: boolean;
|
||||||
|
hideInput?: boolean;
|
||||||
|
hideDropdownIcon?: boolean;
|
||||||
|
|
||||||
|
rules?: ((value: string) => string | true)[];
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
option: () => [],
|
||||||
|
optionLabel: 'label',
|
||||||
|
optionValue: 'value',
|
||||||
|
disable: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
defineEmits<{
|
||||||
|
(
|
||||||
|
e: 'filter',
|
||||||
|
val: string,
|
||||||
|
update: (callbackFn: () => void, afterFn?: (ref: QSelect) => void) => void,
|
||||||
|
): void;
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<q-select
|
||||||
|
dense
|
||||||
|
outlined
|
||||||
|
emit-value
|
||||||
|
map-options
|
||||||
|
hide-bottom-space
|
||||||
|
autocomplete="off"
|
||||||
|
input-debounce="500"
|
||||||
|
:placeholder
|
||||||
|
:clearable
|
||||||
|
:disable
|
||||||
|
:multiple
|
||||||
|
:readonly
|
||||||
|
:label
|
||||||
|
:options
|
||||||
|
:rules
|
||||||
|
:use-input="!hideInput"
|
||||||
|
:use-chips="multiple"
|
||||||
|
:hide-dropdown-icon="readonly"
|
||||||
|
:option-value="
|
||||||
|
typeof props.optionValue === 'string' ? props.optionValue : 'value'
|
||||||
|
"
|
||||||
|
:option-label="
|
||||||
|
typeof props.optionLabel === 'string' ? props.optionLabel : 'label'
|
||||||
|
"
|
||||||
|
:for="id"
|
||||||
|
v-model="model"
|
||||||
|
@filter="(value, update) => $emit('filter', value, update)"
|
||||||
|
@clear="model = multiple ? [] : ''"
|
||||||
|
>
|
||||||
|
<template v-if="$slots['prepend']" v-slot:prepend>
|
||||||
|
<slot name="prepend"></slot>
|
||||||
|
</template>
|
||||||
|
<template v-if="$slots['append']" v-slot:append>
|
||||||
|
<slot name="append"></slot>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:no-option>
|
||||||
|
<slot name="no-option">
|
||||||
|
<q-item-section class="text-grey">
|
||||||
|
{{ $t('general.noData') }}
|
||||||
|
</q-item-section>
|
||||||
|
</slot>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-if="$slots['selected-item']" v-slot:selected-item="scope">
|
||||||
|
<slot name="selected-item" :scope="scope" :opt="scope.opt as T"></slot>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-if="$slots['option']" v-slot:option="scope">
|
||||||
|
<slot name="option" :scope="scope" :opt="scope.opt as T"></slot>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-if="$slots['before-options']" #before-options>
|
||||||
|
<slot name="before-options"></slot>
|
||||||
|
</template>
|
||||||
|
</q-select>
|
||||||
|
</template>
|
||||||
|
|
@ -2,11 +2,11 @@
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted } from 'vue';
|
||||||
|
|
||||||
import { createSelect, SelectProps } from './select';
|
import { createSelect, SelectProps } from './select';
|
||||||
import SelectInput from '../SelectInput.vue';
|
|
||||||
|
|
||||||
import { BusinessType } from 'src/stores/business-type/types';
|
import { BusinessType } from 'src/stores/business-type/types';
|
||||||
|
|
||||||
import useStore from 'src/stores/business-type';
|
import useStore from 'src/stores/business-type';
|
||||||
|
import SelectBase from './SelectBase.vue';
|
||||||
|
|
||||||
type SelectOption = BusinessType;
|
type SelectOption = BusinessType;
|
||||||
|
|
||||||
|
|
@ -74,17 +74,15 @@ function setDefaultValue() {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<SelectInput
|
<SelectBase
|
||||||
v-model="value"
|
v-model="value"
|
||||||
incremental
|
clearable
|
||||||
option-value="id"
|
option-value="id"
|
||||||
:label="label || $t('menu.manage.businessType')"
|
:label="label || $t('menu.manage.businessType')"
|
||||||
:placeholder
|
:placeholder
|
||||||
:readonly
|
:readonly
|
||||||
:disable="disabled"
|
:disable="disabled"
|
||||||
:option="selectOptions"
|
:options="selectOptions"
|
||||||
:hide-selected="false"
|
|
||||||
:fill-input="false"
|
|
||||||
:rules="[
|
:rules="[
|
||||||
(v: string) => !props.required || !!v || $t('form.error.required'),
|
(v: string) => !props.required || !!v || $t('form.error.required'),
|
||||||
]"
|
]"
|
||||||
|
|
@ -167,14 +165,5 @@ function setDefaultValue() {
|
||||||
|
|
||||||
<q-separator class="q-mx-sm" />
|
<q-separator class="q-mx-sm" />
|
||||||
</template>
|
</template>
|
||||||
|
</SelectBase>
|
||||||
<template #append v-if="clearable">
|
|
||||||
<q-icon
|
|
||||||
v-if="!readonly && value"
|
|
||||||
name="mdi-close-circle"
|
|
||||||
@click.stop="value = ''"
|
|
||||||
class="cursor-pointer clear-btn"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</SelectInput>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,12 @@ import {
|
||||||
commaInput,
|
commaInput,
|
||||||
formatNumberWithCommas,
|
formatNumberWithCommas,
|
||||||
} from 'stores/utils';
|
} from 'stores/utils';
|
||||||
import { onMounted, watch } from 'vue';
|
import { onMounted, watch, reactive, ref } from 'vue';
|
||||||
import { ref } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import ThaiBahtText from 'thai-baht-text';
|
import ThaiBahtText from 'thai-baht-text';
|
||||||
import SelectBusinessType from 'src/components/shared/select/SelectBusinessType.vue';
|
import SelectBusinessType from 'src/components/shared/select/SelectBusinessType.vue';
|
||||||
|
import BusinessTypeDialog from 'src/pages/16_business-type-management/BusinessTypeDialog.vue';
|
||||||
|
import useBusinessTypeStore, { BusinessType } from 'src/stores/business-type';
|
||||||
|
|
||||||
const { locale } = useI18n({ useScope: 'global' });
|
const { locale } = useI18n({ useScope: 'global' });
|
||||||
|
|
||||||
|
|
@ -24,8 +25,12 @@ const wageRateText = defineModel<string>('wageRateText', { default: '0' });
|
||||||
|
|
||||||
const rate = ref<string>(commaInput(wageRate.value?.toString() || '0'));
|
const rate = ref<string>(commaInput(wageRate.value?.toString() || '0'));
|
||||||
|
|
||||||
const typeBusinessOption = ref([]);
|
const businessTypeDialog = ref(false);
|
||||||
const typeBusinessENOption = ref([]);
|
const businessTypeForm = reactive({
|
||||||
|
name: '',
|
||||||
|
nameEN: '',
|
||||||
|
});
|
||||||
|
|
||||||
const jobPositionOption = ref([]);
|
const jobPositionOption = ref([]);
|
||||||
const jobPositionENOption = ref([]);
|
const jobPositionENOption = ref([]);
|
||||||
|
|
||||||
|
|
@ -40,15 +45,12 @@ defineProps<{
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const resultOption = await fetch('/option/option.json');
|
const resultOption = await fetch('/option/option.json');
|
||||||
rawOption.value = await resultOption.json();
|
|
||||||
jobPositionENOption.value = rawOption.value.eng.position;
|
|
||||||
|
|
||||||
if (locale.value === 'eng') {
|
rawOption.value = await resultOption.json();
|
||||||
jobPositionOption.value = rawOption.value.eng.position;
|
|
||||||
}
|
jobPositionOption.value =
|
||||||
if (locale.value === 'tha') {
|
rawOption.value[locale.value === 'tha' ? 'tha' : 'eng'].position;
|
||||||
jobPositionOption.value = rawOption.value.tha.position;
|
jobPositionENOption.value = rawOption.value.eng.position;
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
|
@ -75,13 +77,6 @@ watch([jobPositionOption, jobPositionENOption], () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const typeBusinessOptions = ref<Record<string, unknown>[]>([]);
|
|
||||||
let typeBusinessFilter = selectFilterOptionRefMod(
|
|
||||||
typeBusinessOption,
|
|
||||||
typeBusinessOptions,
|
|
||||||
'label',
|
|
||||||
);
|
|
||||||
|
|
||||||
const jobPositionOptions = ref<Record<string, unknown>[]>([]);
|
const jobPositionOptions = ref<Record<string, unknown>[]>([]);
|
||||||
let jobPositionFilter = selectFilterOptionRefMod(
|
let jobPositionFilter = selectFilterOptionRefMod(
|
||||||
jobPositionOption,
|
jobPositionOption,
|
||||||
|
|
@ -89,19 +84,29 @@ let jobPositionFilter = selectFilterOptionRefMod(
|
||||||
'label',
|
'label',
|
||||||
);
|
);
|
||||||
|
|
||||||
const typeBusinessENOptions = ref<Record<string, unknown>[]>([]);
|
|
||||||
let typeBusinessENFilter = selectFilterOptionRefMod(
|
|
||||||
typeBusinessENOption,
|
|
||||||
typeBusinessENOptions,
|
|
||||||
'label',
|
|
||||||
);
|
|
||||||
|
|
||||||
const jobPositionENOptions = ref<Record<string, unknown>[]>([]);
|
const jobPositionENOptions = ref<Record<string, unknown>[]>([]);
|
||||||
let jobPositionENFilter = selectFilterOptionRefMod(
|
let jobPositionENFilter = selectFilterOptionRefMod(
|
||||||
jobPositionENOption,
|
jobPositionENOption,
|
||||||
jobPositionENOptions,
|
jobPositionENOptions,
|
||||||
'label',
|
'label',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// NOTE: ~ BUSINESS TYPE SECTION
|
||||||
|
|
||||||
|
const businessType = useBusinessTypeStore();
|
||||||
|
|
||||||
|
async function createBusinessType() {
|
||||||
|
const created = await businessType.create(businessTypeForm);
|
||||||
|
|
||||||
|
if (created) {
|
||||||
|
businessTypeId.value = created.id;
|
||||||
|
businessTypeDialog.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
businessTypeForm.name = businessTypeForm.nameEN = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: ~ BUSINESS TYPE SECTION END
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="col-12 row q-col-gutter-sm">
|
<div class="col-12 row q-col-gutter-sm">
|
||||||
|
|
@ -121,16 +126,24 @@ let jobPositionENFilter = selectFilterOptionRefMod(
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SelectBusinessType
|
<SelectBusinessType
|
||||||
class="col-md-6 col-12"
|
|
||||||
v-model:value="businessTypeId"
|
v-model:value="businessTypeId"
|
||||||
:readonly
|
class="col-md-6 col-12"
|
||||||
lang="tha"
|
lang="tha"
|
||||||
|
clearable
|
||||||
|
:readonly
|
||||||
|
:creatable="!readonly"
|
||||||
|
:creatable-disabled-text="`(${$t('form.error.selectField')})`"
|
||||||
|
@create="businessTypeDialog = true"
|
||||||
/>
|
/>
|
||||||
<SelectBusinessType
|
<SelectBusinessType
|
||||||
class="col-md-6 col-12"
|
|
||||||
v-model:value="businessTypeId"
|
v-model:value="businessTypeId"
|
||||||
|
class="col-md-6 col-12"
|
||||||
lang="eng"
|
lang="eng"
|
||||||
|
clearable
|
||||||
:readonly
|
:readonly
|
||||||
|
:creatable="!readonly"
|
||||||
|
:creatable-disabled-text="`(${$t('form.error.selectField')})`"
|
||||||
|
@create="createBusinessType"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<q-select
|
<q-select
|
||||||
|
|
@ -282,4 +295,10 @@ let jobPositionENFilter = selectFilterOptionRefMod(
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<BusinessTypeDialog
|
||||||
|
v-model="businessTypeDialog"
|
||||||
|
v-bind:data="businessTypeForm"
|
||||||
|
@submit="createBusinessType"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue