192 lines
4.9 KiB
Vue
192 lines
4.9 KiB
Vue
<script lang="ts" setup>
|
|
import { ref } from 'vue';
|
|
import { useI18n } from 'vue-i18n';
|
|
import SelectMenuWithSearch from '../shared/SelectMenuWithSearch.vue';
|
|
|
|
const { t } = useI18n();
|
|
|
|
defineProps<{
|
|
readonly?: boolean;
|
|
}>();
|
|
|
|
const attachment = defineModel<string[]>('attachment', { default: [] });
|
|
|
|
const mapName = (val: string): string => {
|
|
const name = objectOptions.find((v) => v.value === val);
|
|
return name ? name.label : '';
|
|
};
|
|
|
|
const objectOptions = [
|
|
{
|
|
label: 'customerEmployee.fileType.passport',
|
|
value: 'passport',
|
|
},
|
|
{
|
|
label: 'customerEmployee.fileType.visa',
|
|
value: 'visa',
|
|
},
|
|
{
|
|
label: 'customerEmployee.fileType.tm6',
|
|
value: 'tm6',
|
|
},
|
|
{
|
|
label: 'customerEmployee.fileType.workPermit',
|
|
value: 'workPermit',
|
|
},
|
|
{
|
|
label: 'customerEmployee.fileType.noticeJobEmployment',
|
|
value: 'noticeJobEmployment',
|
|
},
|
|
{
|
|
label: 'customerEmployee.fileType.noticeJobEntry',
|
|
value: 'noticeJobEntry',
|
|
},
|
|
{
|
|
label: 'customerEmployee.fileType.historyJob',
|
|
value: 'historyJob',
|
|
},
|
|
{
|
|
label: 'customerEmployee.fileType.acceptJob',
|
|
value: 'acceptJob',
|
|
},
|
|
];
|
|
|
|
const options = ref(objectOptions);
|
|
|
|
function selectAttachment(val: Record<string, unknown>) {
|
|
const existIndex = attachment.value.findIndex((p) => p === val.value);
|
|
|
|
if (existIndex === -1) {
|
|
attachment.value.push(val.value as string);
|
|
} else {
|
|
attachment.value.splice(Number(existIndex), 1);
|
|
}
|
|
}
|
|
|
|
function selectAll() {
|
|
if (attachment.value.length === options.value.length) {
|
|
attachment.value = [];
|
|
return;
|
|
}
|
|
|
|
options.value.forEach((opt) => {
|
|
const existItem = attachment.value.some((v) => v === opt.value);
|
|
|
|
if (!existItem) selectAttachment(opt);
|
|
});
|
|
}
|
|
|
|
function optionSearch(val: string | null) {
|
|
if (val === '') {
|
|
options.value = objectOptions;
|
|
return;
|
|
}
|
|
|
|
const needle = val ? val.toLowerCase() : '';
|
|
options.value = objectOptions.filter(
|
|
(v) => t(v.label).toLowerCase().indexOf(needle) > -1,
|
|
);
|
|
}
|
|
</script>
|
|
<template>
|
|
<div class="row col-12">
|
|
<div class="col-12 q-pb-sm row items-center">
|
|
<q-icon
|
|
flat
|
|
size="xs"
|
|
class="q-pa-sm rounded q-mr-sm"
|
|
color="info"
|
|
name="mdi-file-outline"
|
|
style="background-color: var(--surface-3)"
|
|
/>
|
|
<span class="text-body1 text-weight-bold">
|
|
{{ $t('general.information', { msg: $t('general.attachment') }) }}
|
|
</span>
|
|
</div>
|
|
|
|
<div class="col-12 row q-col-gutter-sm">
|
|
<q-select
|
|
:readonly
|
|
outlined
|
|
dense
|
|
v-model="attachment"
|
|
multiple
|
|
:options="options"
|
|
use-chips
|
|
option-label="label"
|
|
option-value="value"
|
|
emit-value
|
|
:label="$t('general.select', { msg: $t('general.attachment') })"
|
|
class="col"
|
|
:hide-dropdown-icon="readonly"
|
|
>
|
|
<template v-slot:selected-item="scope">
|
|
<q-chip
|
|
:removable="!readonly"
|
|
@remove="scope.removeAtIndex(scope.index)"
|
|
>
|
|
{{ $t(mapName(scope.opt)) }}
|
|
</q-chip>
|
|
</template>
|
|
<template v-slot:option></template>
|
|
|
|
<SelectMenuWithSearch
|
|
v-if="!readonly"
|
|
:title="$t('general.select', { msg: $t('general.attachment') })"
|
|
:option="options"
|
|
width="353.66px"
|
|
@search="(v) => optionSearch(v as string)"
|
|
@select="(v) => selectAttachment(v)"
|
|
>
|
|
<template #prepend>
|
|
<q-item
|
|
dense
|
|
clickable
|
|
class="bordered-t flex items-center app-text-muted"
|
|
style="padding: 0px 16px"
|
|
>
|
|
<q-icon name="mdi-plus" class="q-pa-sm q-mr-sm" />
|
|
{{ $t('general.add', { text: $t('general.attachment') }) }}
|
|
</q-item>
|
|
<q-item
|
|
dense
|
|
clickable
|
|
class="flex items-center"
|
|
style="
|
|
padding: 0px 16px;
|
|
background-color: hsla(var(--info-bg) / 0.1);
|
|
"
|
|
@click="selectAll()"
|
|
>
|
|
<q-checkbox
|
|
:model-value="
|
|
options.length > 0 && attachment.length === options.length
|
|
"
|
|
class="q-pr-sm"
|
|
size="xs"
|
|
@click="selectAll()"
|
|
/>
|
|
{{ $t('general.selectAll') }}
|
|
</q-item>
|
|
</template>
|
|
<template #option="{ opt }">
|
|
<q-checkbox
|
|
:model-value="attachment.some((v) => v === opt.value)"
|
|
class="q-pr-sm"
|
|
size="xs"
|
|
@click="selectAttachment(opt)"
|
|
/>
|
|
<span
|
|
:class="{
|
|
'app-text-info': attachment.some((v) => v === opt.value),
|
|
}"
|
|
>
|
|
{{ $t(opt.label as string) }}
|
|
</span>
|
|
</template>
|
|
</SelectMenuWithSearch>
|
|
</q-select>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<style></style>
|