feat: add product document list (#64)
* feat: product => document select
This commit is contained in:
parent
e501706e88
commit
f3fdaac2b1
3 changed files with 226 additions and 5 deletions
192
src/components/04_product-service/FormDocument.vue
Normal file
192
src/components/04_product-service/FormDocument.vue
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
<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 = options.value.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>
|
||||
Loading…
Add table
Add a link
Reference in a new issue