253 lines
12 KiB
Vue
Executable File
253 lines
12 KiB
Vue
Executable File
<template>
|
|
<div>
|
|
<Head>
|
|
<Title>Vue Table Component</Title>
|
|
<Meta name="description" content="DataTable displays data in tabular format" />
|
|
</Head>
|
|
|
|
<div class="content-section introduction">
|
|
<div class="feature-intro">
|
|
<h1>DataTable</h1>
|
|
<p>DataTable displays data in tabular format.</p>
|
|
</div>
|
|
<AppDemoActions />
|
|
</div>
|
|
|
|
<div class="content-section implementation">
|
|
<div class="card">
|
|
<DataTable
|
|
v-model:selection="selectedCustomers"
|
|
v-model:filters="filters"
|
|
:value="customers"
|
|
:paginator="true"
|
|
class="p-datatable-customers"
|
|
:rows="10"
|
|
dataKey="id"
|
|
:rowHover="true"
|
|
filterDisplay="menu"
|
|
:loading="loading"
|
|
paginatorTemplate="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink CurrentPageReport RowsPerPageDropdown"
|
|
:rowsPerPageOptions="[10, 25, 50]"
|
|
currentPageReportTemplate="Showing {first} to {last} of {totalRecords} entries"
|
|
:globalFilterFields="['name', 'country.name', 'representative.name', 'status']"
|
|
responsiveLayout="scroll"
|
|
>
|
|
<template #header>
|
|
<div class="flex flex-column md:flex-row md:justify-content-between md:align-items-center">
|
|
<h5 class="m-0">Customers</h5>
|
|
<span class="p-input-icon-left">
|
|
<i class="pi pi-search" />
|
|
<InputText v-model="filters['global'].value" placeholder="Keyword Search" />
|
|
</span>
|
|
</div>
|
|
</template>
|
|
<template #empty> No customers found. </template>
|
|
<template #loading> Loading customers data. Please wait. </template>
|
|
<Column selectionMode="multiple" style="min-width: 3rem"></Column>
|
|
<Column field="name" header="Name" sortable style="min-width: 14rem">
|
|
<template #body="{ data }">
|
|
{{ data.name }}
|
|
</template>
|
|
<template #filter="{ filterModel }">
|
|
<InputText v-model="filterModel.value" type="text" class="p-column-filter" placeholder="Search by name" />
|
|
</template>
|
|
</Column>
|
|
<Column field="country.name" header="Country" sortable filterMatchMode="contains" style="min-width: 14rem">
|
|
<template #body="{ data }">
|
|
<img src="../../assets/images/flag_placeholder.png" :class="'flag flag-' + data.country.code" width="30" />
|
|
<span class="image-text">{{ data.country.name }}</span>
|
|
</template>
|
|
<template #filter="{ filterModel }">
|
|
<InputText v-model="filterModel.value" type="text" class="p-column-filter" placeholder="Search by country" />
|
|
</template>
|
|
</Column>
|
|
<Column header="Agent" sortable filterField="representative" sortField="representative.name" :showFilterMatchModes="false" :filterMenuStyle="{ width: '14rem' }" style="min-width: 14rem">
|
|
<template #body="{ data }">
|
|
<img :alt="data.representative.name" :src="baseUrl + 'demo/images/avatar/' + data.representative.image" width="32" style="vertical-align: middle" />
|
|
<span class="image-text">{{ data.representative.name }}</span>
|
|
</template>
|
|
<template #filter="{ filterModel }">
|
|
<div class="mb-3 font-bold">Agent Picker</div>
|
|
<MultiSelect v-model="filterModel.value" :options="representatives" optionLabel="name" placeholder="Any" class="p-column-filter">
|
|
<template #option="slotProps">
|
|
<div class="p-multiselect-representative-option">
|
|
<img :alt="slotProps.option.name" :src="baseUrl + 'demo/images/avatar/' + slotProps.option.image" width="32" style="vertical-align: middle" />
|
|
<span class="image-text">{{ slotProps.option.name }}</span>
|
|
</div>
|
|
</template>
|
|
</MultiSelect>
|
|
</template>
|
|
</Column>
|
|
<Column field="date" header="Date" sortable dataType="date" style="min-width: 8rem">
|
|
<template #body="{ data }">
|
|
{{ formatDate(data.date) }}
|
|
</template>
|
|
<template #filter="{ filterModel }">
|
|
<Calendar v-model="filterModel.value" dateFormat="mm/dd/yy" placeholder="mm/dd/yyyy" />
|
|
</template>
|
|
</Column>
|
|
<Column field="balance" header="Balance" sortable dataType="numeric" style="min-width: 8rem">
|
|
<template #body="{ data }">
|
|
{{ formatCurrency(data.balance) }}
|
|
</template>
|
|
<template #filter="{ filterModel }">
|
|
<InputNumber v-model="filterModel.value" mode="currency" currency="USD" locale="en-US" />
|
|
</template>
|
|
</Column>
|
|
<Column field="status" header="Status" sortable :filterMenuStyle="{ width: '14rem' }" style="min-width: 10rem">
|
|
<template #body="{ data }">
|
|
<span :class="'customer-badge status-' + data.status">{{ data.status }}</span>
|
|
</template>
|
|
<template #filter="{ filterModel }">
|
|
<Dropdown v-model="filterModel.value" :options="statuses" placeholder="Any" class="p-column-filter" :showClear="true">
|
|
<template #value="slotProps">
|
|
<span :class="'customer-badge status-' + slotProps.value">{{ slotProps.value }}</span>
|
|
</template>
|
|
<template #option="slotProps">
|
|
<span :class="'customer-badge status-' + slotProps.option">{{ slotProps.option }}</span>
|
|
</template>
|
|
</Dropdown>
|
|
</template>
|
|
</Column>
|
|
<Column field="activity" header="Activity" sortable :showFilterMatchModes="false" style="min-width: 10rem">
|
|
<template #body="{ data }">
|
|
<ProgressBar :value="data.activity" :showValue="false" />
|
|
</template>
|
|
<template #filter="{ filterModel }">
|
|
<Slider v-model="filterModel.value" range class="m-3"></Slider>
|
|
<div class="flex align-items-center justify-content-between px-2">
|
|
<span>{{ filterModel.value ? filterModel.value[0] : 0 }}</span>
|
|
<span>{{ filterModel.value ? filterModel.value[1] : 100 }}</span>
|
|
</div>
|
|
</template>
|
|
</Column>
|
|
<Column headerStyle="min-width: 4rem; text-align: center" bodyStyle="text-align: center; overflow: visible">
|
|
<template #body>
|
|
<Button type="button" icon="pi pi-cog"></Button>
|
|
</template>
|
|
</Column>
|
|
</DataTable>
|
|
</div>
|
|
</div>
|
|
|
|
<DataTableDoc />
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { FilterMatchMode, FilterOperator } from 'primevue/api';
|
|
import CustomerService from '../../service/CustomerService';
|
|
import DataTableDoc from './DataTableDoc';
|
|
|
|
export default {
|
|
data() {
|
|
return {
|
|
customers: null,
|
|
selectedCustomers: null,
|
|
filters: {
|
|
global: { value: null, matchMode: FilterMatchMode.CONTAINS },
|
|
name: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }] },
|
|
'country.name': { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }] },
|
|
representative: { value: null, matchMode: FilterMatchMode.IN },
|
|
date: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] },
|
|
balance: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }] },
|
|
status: { operator: FilterOperator.OR, constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }] },
|
|
activity: { value: null, matchMode: FilterMatchMode.BETWEEN },
|
|
verified: { value: null, matchMode: FilterMatchMode.EQUALS }
|
|
},
|
|
loading: true,
|
|
representatives: [
|
|
{ name: 'Amy Elsner', image: 'amyelsner.png' },
|
|
{ name: 'Anna Fali', image: 'annafali.png' },
|
|
{ name: 'Asiya Javayant', image: 'asiyajavayant.png' },
|
|
{ name: 'Bernardo Dominic', image: 'bernardodominic.png' },
|
|
{ name: 'Elwin Sharvill', image: 'elwinsharvill.png' },
|
|
{ name: 'Ioni Bowcher', image: 'ionibowcher.png' },
|
|
{ name: 'Ivan Magalhaes', image: 'ivanmagalhaes.png' },
|
|
{ name: 'Onyama Limba', image: 'onyamalimba.png' },
|
|
{ name: 'Stephen Shaw', image: 'stephenshaw.png' },
|
|
{ name: 'XuXue Feng', image: 'xuxuefeng.png' }
|
|
],
|
|
statuses: ['unqualified', 'qualified', 'new', 'negotiation', 'renewal', 'proposal'],
|
|
baseUrl: '/'
|
|
};
|
|
},
|
|
created() {
|
|
this.customerService = new CustomerService();
|
|
},
|
|
mounted() {
|
|
this.customerService.getCustomersLarge().then((data) => {
|
|
this.customers = data;
|
|
this.customers.forEach((customer) => (customer.date = new Date(customer.date)));
|
|
this.loading = false;
|
|
});
|
|
|
|
this.baseUrl = process.dev ? '/' : '/primevue-nuxt/';
|
|
},
|
|
methods: {
|
|
formatDate(value) {
|
|
return value.toLocaleDateString('en-US', {
|
|
day: '2-digit',
|
|
month: '2-digit',
|
|
year: 'numeric'
|
|
});
|
|
},
|
|
formatCurrency(value) {
|
|
return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' });
|
|
}
|
|
},
|
|
components: {
|
|
DataTableDoc: DataTableDoc
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
::v-deep(.p-paginator) {
|
|
.p-paginator-current {
|
|
margin-left: auto;
|
|
}
|
|
}
|
|
|
|
::v-deep(.p-progressbar) {
|
|
height: 0.5rem;
|
|
background-color: #d8dadc;
|
|
|
|
.p-progressbar-value {
|
|
background-color: #607d8b;
|
|
}
|
|
}
|
|
|
|
::v-deep(.p-datepicker) {
|
|
min-width: 25rem;
|
|
|
|
td {
|
|
font-weight: 400;
|
|
}
|
|
}
|
|
|
|
::v-deep(.p-datatable.p-datatable-customers) {
|
|
.p-datatable-header {
|
|
padding: 1rem;
|
|
text-align: left;
|
|
font-size: 1.5rem;
|
|
}
|
|
|
|
.p-paginator {
|
|
padding: 1rem;
|
|
}
|
|
|
|
.p-datatable-thead > tr > th {
|
|
text-align: left;
|
|
}
|
|
|
|
.p-datatable-tbody > tr > td {
|
|
cursor: auto;
|
|
}
|
|
|
|
.p-dropdown-label:not(.p-placeholder) {
|
|
text-transform: uppercase;
|
|
}
|
|
}
|
|
</style>
|