mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-05-12 11:32:36 +08:00
add dashboard
This commit is contained in:
@@ -67,3 +67,26 @@ export const formatFileSize = (bytes: number) => {
|
||||
|
||||
return `${size.toFixed(2)} ${units[unitIndex]}`;
|
||||
}
|
||||
|
||||
// 将时间秒格式化为时分秒
|
||||
export const formatSeconds = (seconds: number) => {
|
||||
const hours = Math.floor(seconds / 3600);
|
||||
const minutes = Math.floor((seconds % 3600) / 60);
|
||||
const remainingSeconds = seconds % 60;
|
||||
|
||||
let formattedTime = '';
|
||||
|
||||
if (hours > 0) {
|
||||
formattedTime += `${hours}小时`;
|
||||
}
|
||||
|
||||
if (minutes > 0) {
|
||||
formattedTime += `${minutes}分`;
|
||||
}
|
||||
|
||||
if (remainingSeconds > 0 || formattedTime === '') {
|
||||
formattedTime += `${remainingSeconds}秒`;
|
||||
}
|
||||
|
||||
return formattedTime;
|
||||
}
|
||||
|
||||
@@ -426,3 +426,43 @@ export interface User {
|
||||
is_superuser: boolean,
|
||||
avatar: string,
|
||||
};
|
||||
|
||||
|
||||
// 存储空间
|
||||
export interface Storage {
|
||||
total_storage: number,
|
||||
used_storage: number,
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 媒体统计
|
||||
export interface MediaStatistic {
|
||||
// 电影总数
|
||||
movie_count: number,
|
||||
// 电视剧总数
|
||||
tv_count: number,
|
||||
// 电视剧总集数
|
||||
episode_count: number,
|
||||
// 用户数量
|
||||
user_count: number,
|
||||
}
|
||||
|
||||
|
||||
// 后台进程
|
||||
export interface Process {
|
||||
// 进程ID
|
||||
pid: number,
|
||||
// 进程名称
|
||||
name: string,
|
||||
// 进程状态
|
||||
status: string,
|
||||
// 进程启动时间
|
||||
create_time: number,
|
||||
// 进程运行时间
|
||||
run_time: number,
|
||||
// 进程CPU占用率
|
||||
cpu: number,
|
||||
// 进程内存占用
|
||||
memory: number,
|
||||
}
|
||||
|
||||
@@ -1,115 +1,82 @@
|
||||
<script setup lang="ts">
|
||||
import AnalyticsAward from '@/views/dashboard/AnalyticsAward.vue'
|
||||
import AnalyticsBarCharts from '@/views/dashboard/AnalyticsBarCharts.vue'
|
||||
import AnalyticsDepositWithdraw from '@/views/dashboard/AnalyticsDepositWithdraw.vue'
|
||||
import AnalyticsSalesByCountries from '@/views/dashboard/AnalyticsSalesByCountries.vue'
|
||||
import AnalyticsTotalEarning from '@/views/dashboard/AnalyticsTotalEarning.vue'
|
||||
import AnalyticsTotalProfitLineCharts from '@/views/dashboard/AnalyticsTotalProfitLineCharts.vue'
|
||||
import AnalyticsTransactions from '@/views/dashboard/AnalyticsTransactions.vue'
|
||||
import AnalyticsUserTable from '@/views/dashboard/AnalyticsUserTable.vue'
|
||||
import AnalyticsWeeklyOverview from '@/views/dashboard/AnalyticsWeeklyOverview.vue'
|
||||
import CardStatisticsVertical from '@/components/cards/CardStatisticsVertical.vue'
|
||||
import CardStatisticsVertical from "@/components/cards/CardStatisticsVertical.vue";
|
||||
import AnalyticsBarCharts from "@/views/dashboard/AnalyticsBarCharts.vue";
|
||||
import AnalyticsDepositWithdraw from "@/views/dashboard/AnalyticsDepositWithdraw.vue";
|
||||
import AnalyticsMediaStatistic from "@/views/dashboard/AnalyticsMediaStatistic.vue";
|
||||
import AnalyticsProcesses from "@/views/dashboard/AnalyticsProcesses.vue";
|
||||
import AnalyticsSalesByCountries from "@/views/dashboard/AnalyticsSalesByCountries.vue";
|
||||
import AnalyticsStorage from "@/views/dashboard/AnalyticsStorage.vue";
|
||||
import AnalyticsTotalEarning from "@/views/dashboard/AnalyticsTotalEarning.vue";
|
||||
import AnalyticsTotalProfitLineCharts from "@/views/dashboard/AnalyticsTotalProfitLineCharts.vue";
|
||||
import AnalyticsWeeklyOverview from "@/views/dashboard/AnalyticsWeeklyOverview.vue";
|
||||
|
||||
const totalProfit = {
|
||||
title: 'Total Profit',
|
||||
color: 'secondary',
|
||||
icon: 'mdi-poll',
|
||||
stats: '$25.6k',
|
||||
title: "Total Profit",
|
||||
color: "secondary",
|
||||
icon: "mdi-poll",
|
||||
stats: "$25.6k",
|
||||
change: 42,
|
||||
subtitle: 'Weekly Project',
|
||||
}
|
||||
subtitle: "Weekly Project",
|
||||
};
|
||||
|
||||
const newProject = {
|
||||
title: 'New Project',
|
||||
color: 'primary',
|
||||
icon: 'mdi-briefcase-variant-outline',
|
||||
stats: '862',
|
||||
title: "New Project",
|
||||
color: "primary",
|
||||
icon: "mdi-briefcase-variant-outline",
|
||||
stats: "862",
|
||||
change: -18,
|
||||
subtitle: 'Yearly Project',
|
||||
}
|
||||
subtitle: "Yearly Project",
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VRow class="match-height">
|
||||
<VCol
|
||||
cols="12"
|
||||
md="4"
|
||||
>
|
||||
<AnalyticsAward />
|
||||
<VCol cols="12" md="4">
|
||||
<AnalyticsStorage />
|
||||
</VCol>
|
||||
|
||||
<VCol
|
||||
cols="12"
|
||||
md="8"
|
||||
>
|
||||
<AnalyticsTransactions />
|
||||
<VCol cols="12" md="8">
|
||||
<AnalyticsMediaStatistic />
|
||||
</VCol>
|
||||
|
||||
<VCol
|
||||
cols="12"
|
||||
md="4"
|
||||
>
|
||||
<VCol cols="12" md="4">
|
||||
<AnalyticsWeeklyOverview />
|
||||
</VCol>
|
||||
|
||||
<VCol
|
||||
cols="12"
|
||||
md="4"
|
||||
>
|
||||
<VCol cols="12" md="4">
|
||||
<AnalyticsTotalEarning />
|
||||
</VCol>
|
||||
|
||||
<VCol
|
||||
cols="12"
|
||||
md="4"
|
||||
>
|
||||
<VCol cols="12" md="4">
|
||||
<VRow class="match-height">
|
||||
<VCol
|
||||
cols="12"
|
||||
sm="6"
|
||||
>
|
||||
<VCol cols="12" sm="6">
|
||||
<AnalyticsTotalProfitLineCharts />
|
||||
</VCol>
|
||||
|
||||
<VCol
|
||||
cols="12"
|
||||
sm="6"
|
||||
>
|
||||
<VCol cols="12" sm="6">
|
||||
<CardStatisticsVertical v-bind="totalProfit" />
|
||||
</VCol>
|
||||
|
||||
<VCol
|
||||
cols="12"
|
||||
sm="6"
|
||||
>
|
||||
<VCol cols="12" sm="6">
|
||||
<CardStatisticsVertical v-bind="newProject" />
|
||||
</VCol>
|
||||
|
||||
<VCol
|
||||
cols="12"
|
||||
sm="6"
|
||||
>
|
||||
<VCol cols="12" sm="6">
|
||||
<AnalyticsBarCharts />
|
||||
</VCol>
|
||||
</VRow>
|
||||
</VCol>
|
||||
|
||||
<VCol
|
||||
cols="12"
|
||||
md="4"
|
||||
>
|
||||
<VCol cols="12" md="4">
|
||||
<AnalyticsSalesByCountries />
|
||||
</VCol>
|
||||
|
||||
<VCol
|
||||
cols="12"
|
||||
md="8"
|
||||
>
|
||||
<VCol cols="12" md="8">
|
||||
<AnalyticsDepositWithdraw />
|
||||
</VCol>
|
||||
|
||||
<VCol cols="12">
|
||||
<AnalyticsUserTable />
|
||||
<AnalyticsProcesses />
|
||||
</VCol>
|
||||
</VRow>
|
||||
</template>
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { useTheme } from 'vuetify'
|
||||
import triangleDark from '@images/misc/triangle-dark.png'
|
||||
import triangleLight from '@images/misc/triangle-light.png'
|
||||
import trophy from '@images/misc/trophy.png'
|
||||
|
||||
const { global } = useTheme()
|
||||
const triangleBg = computed(() => global.name.value === 'light' ? triangleLight : triangleDark)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VCard
|
||||
title="Congratulations John! 🎉"
|
||||
subtitle="Best seller of the month"
|
||||
class="position-relative"
|
||||
>
|
||||
<VCardText>
|
||||
<h5 class="text-2xl font-weight-medium text-primary">
|
||||
$42.8k
|
||||
</h5>
|
||||
<p>78% of target 🚀</p>
|
||||
<VBtn size="small">
|
||||
View Sales
|
||||
</VBtn>
|
||||
</VCardText>
|
||||
|
||||
<!-- Triangle Background -->
|
||||
<VImg
|
||||
:src="triangleBg"
|
||||
class="triangle-bg flip-in-rtl"
|
||||
/>
|
||||
|
||||
<!-- Trophy -->
|
||||
<VImg
|
||||
:src="trophy"
|
||||
class="trophy"
|
||||
/>
|
||||
</VCard>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@use "@layouts/styles/mixins" as layoutsMixins;
|
||||
|
||||
.v-card .triangle-bg {
|
||||
position: absolute;
|
||||
inline-size: 10.375rem;
|
||||
inset-block-end: 0;
|
||||
inset-inline-end: 0;
|
||||
}
|
||||
|
||||
.v-card .trophy {
|
||||
position: absolute;
|
||||
inline-size: 4.9375rem;
|
||||
inset-block-end: 2rem;
|
||||
inset-inline-end: 2rem;
|
||||
}
|
||||
</style>
|
||||
87
src/views/dashboard/AnalyticsMediaStatistic.vue
Normal file
87
src/views/dashboard/AnalyticsMediaStatistic.vue
Normal file
@@ -0,0 +1,87 @@
|
||||
<script setup lang="ts">
|
||||
import api from "@/api";
|
||||
import { MediaStatistic } from "@/api/types";
|
||||
|
||||
const statistics = ref([
|
||||
{
|
||||
title: "",
|
||||
stats: "",
|
||||
icon: "",
|
||||
color: "",
|
||||
},
|
||||
]);
|
||||
|
||||
// 调用API加载媒体统计数据
|
||||
const loadMediaStatistic = async () => {
|
||||
try {
|
||||
const res: MediaStatistic = await api.get("dashboard/statistic");
|
||||
statistics.value = [
|
||||
{
|
||||
title: "电影",
|
||||
stats: res.movie_count.toLocaleString(),
|
||||
icon: "mdi-movie-roll",
|
||||
color: "primary",
|
||||
},
|
||||
{
|
||||
title: "电视剧",
|
||||
stats: res.tv_count.toLocaleString(),
|
||||
icon: "mdi-television-box",
|
||||
color: "success",
|
||||
},
|
||||
{
|
||||
title: "剧集",
|
||||
stats: res.episode_count.toLocaleString(),
|
||||
icon: "mdi-television-classic",
|
||||
color: "warning",
|
||||
},
|
||||
{
|
||||
title: "用户",
|
||||
stats: res.user_count.toLocaleString(),
|
||||
icon: "mdi-account",
|
||||
color: "info",
|
||||
},
|
||||
];
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
loadMediaStatistic();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VCard>
|
||||
<VCardItem>
|
||||
<VCardTitle>媒体统计</VCardTitle>
|
||||
|
||||
<template #append>
|
||||
<div class="me-n3">
|
||||
<MoreBtn />
|
||||
</div>
|
||||
</template>
|
||||
</VCardItem>
|
||||
|
||||
<VCardText>
|
||||
<VRow>
|
||||
<VCol v-for="item in statistics" :key="item.title" cols="6" sm="3">
|
||||
<div class="d-flex align-center">
|
||||
<div class="me-3">
|
||||
<VAvatar :color="item.color" rounded size="42" class="elevation-1">
|
||||
<VIcon size="24" :icon="item.icon" />
|
||||
</VAvatar>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column">
|
||||
<span class="text-caption">
|
||||
{{ item.title }}
|
||||
</span>
|
||||
<span class="text-h6">{{ item.stats }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</VCol>
|
||||
</VRow>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</template>
|
||||
55
src/views/dashboard/AnalyticsProcesses.vue
Normal file
55
src/views/dashboard/AnalyticsProcesses.vue
Normal file
@@ -0,0 +1,55 @@
|
||||
<script lang="ts" setup>
|
||||
import { formatSeconds } from "@/@core/utils/formatters";
|
||||
import api from "@/api";
|
||||
import { Process } from "@/api/types";
|
||||
|
||||
const headers = ["进程ID", "进程名称", "运行时间", "内存占用"];
|
||||
|
||||
const processList = ref<Process[]>([]);
|
||||
|
||||
// 调用API加载数据
|
||||
const loadProcessList = async () => {
|
||||
try {
|
||||
const res: Process[] = await api.get("dashboard/processes");
|
||||
processList.value = res;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
loadProcessList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VCard>
|
||||
<VTable
|
||||
:headers="headers"
|
||||
:items="processList"
|
||||
item-key="fullName"
|
||||
class="table-rounded"
|
||||
hide-default-footer
|
||||
disable-sort
|
||||
>
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="header in headers" :key="header" :id="header">
|
||||
{{ header }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="row in processList" :key="row.pid">
|
||||
<td class="text-sm" v-text="row.pid" />
|
||||
<!-- name -->
|
||||
<td>
|
||||
<h6 class="text-sm font-weight-medium">{{ row.name }}</h6>
|
||||
</td>
|
||||
<td class="text-sm" v-text="formatSeconds(row.run_time)" />
|
||||
<td class="text-sm" v-text="`${row.memory} MB`" />
|
||||
</tr>
|
||||
</tbody>
|
||||
</VTable>
|
||||
</VCard>
|
||||
</template>
|
||||
74
src/views/dashboard/AnalyticsStorage.vue
Normal file
74
src/views/dashboard/AnalyticsStorage.vue
Normal file
@@ -0,0 +1,74 @@
|
||||
<script setup lang="ts">
|
||||
import { formatFileSize } from "@/@core/utils/formatters";
|
||||
import api from "@/api";
|
||||
import triangleDark from "@images/misc/triangle-dark.png";
|
||||
import triangleLight from "@images/misc/triangle-light.png";
|
||||
import trophy from "@images/misc/trophy.png";
|
||||
import { useTheme } from "vuetify";
|
||||
|
||||
const { global } = useTheme();
|
||||
const triangleBg = computed(() =>
|
||||
global.name.value === "light" ? triangleLight : triangleDark
|
||||
);
|
||||
|
||||
// 总存储空间
|
||||
const storage = ref(0);
|
||||
// 已使用存储空间
|
||||
const used = ref(0);
|
||||
|
||||
// 计算已使用存储空间百分比,精确到小数点后1位
|
||||
const usedPercent = computed(() => {
|
||||
return Math.round((used.value / storage.value) * 1000) / 10;
|
||||
});
|
||||
|
||||
// 调用API,查询存储空间
|
||||
const getStorage = async () => {
|
||||
try {
|
||||
const res: Storage = await api.get("dashboard/storage");
|
||||
storage.value = res.total_storage;
|
||||
used.value = res.used_storage;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getStorage();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VCard title="存储空间" subtitle="" class="position-relative">
|
||||
<VCardText>
|
||||
<h5 class="text-2xl font-weight-medium text-primary">
|
||||
{{ formatFileSize(storage) }}
|
||||
</h5>
|
||||
<p class="mt-2">已使用 {{ usedPercent }}% 🚀</p>
|
||||
<p class="mt-1"><VProgressLinear :model-value="usedPercent" /></p>
|
||||
</VCardText>
|
||||
|
||||
<!-- Triangle Background -->
|
||||
<VImg :src="triangleBg" class="triangle-bg flip-in-rtl" />
|
||||
|
||||
<!-- Trophy -->
|
||||
<VImg :src="trophy" class="trophy" />
|
||||
</VCard>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@use "@layouts/styles/mixins" as layoutsMixins;
|
||||
|
||||
.v-card .triangle-bg {
|
||||
position: absolute;
|
||||
inline-size: 10.375rem;
|
||||
inset-block-end: 0;
|
||||
inset-inline-end: 0;
|
||||
}
|
||||
|
||||
.v-card .trophy {
|
||||
position: absolute;
|
||||
inline-size: 4.9375rem;
|
||||
inset-block-end: 2rem;
|
||||
inset-inline-end: 2rem;
|
||||
}
|
||||
</style>
|
||||
@@ -1,81 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
const statistics = [
|
||||
{
|
||||
title: 'Sales',
|
||||
stats: '245k',
|
||||
icon: 'mdi-trending-up',
|
||||
color: 'primary',
|
||||
},
|
||||
{
|
||||
title: 'Customers',
|
||||
stats: '12.5k',
|
||||
icon: 'mdi-account-outline',
|
||||
color: 'success',
|
||||
},
|
||||
{
|
||||
title: 'Product',
|
||||
stats: '1.54k',
|
||||
icon: 'mdi-cellphone-link',
|
||||
color: 'warning',
|
||||
},
|
||||
{
|
||||
title: 'Revenue',
|
||||
stats: '$88k',
|
||||
icon: 'mdi-currency-usd',
|
||||
color: 'info',
|
||||
},
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VCard>
|
||||
<VCardItem>
|
||||
<VCardTitle>Transactions</VCardTitle>
|
||||
|
||||
<template #append>
|
||||
<div class="me-n3">
|
||||
<MoreBtn />
|
||||
</div>
|
||||
</template>
|
||||
</VCardItem>
|
||||
|
||||
<VCardText>
|
||||
<h6 class="text-sm font-weight-medium mb-12">
|
||||
<span>Total 48.5% Growth 😎</span>
|
||||
<span class="font-weight-regular"> this month</span>
|
||||
</h6>
|
||||
|
||||
<VRow>
|
||||
<VCol
|
||||
v-for="item in statistics"
|
||||
:key="item.title"
|
||||
cols="6"
|
||||
sm="3"
|
||||
>
|
||||
<div class="d-flex align-center">
|
||||
<div class="me-3">
|
||||
<VAvatar
|
||||
:color="item.color"
|
||||
rounded
|
||||
size="42"
|
||||
class="elevation-1"
|
||||
>
|
||||
<VIcon
|
||||
size="24"
|
||||
:icon="item.icon"
|
||||
/>
|
||||
</VAvatar>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column">
|
||||
<span class="text-caption">
|
||||
{{ item.title }}
|
||||
</span>
|
||||
<span class="text-h6">{{ item.stats }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</VCol>
|
||||
</VRow>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</template>
|
||||
@@ -1,204 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
interface DataItem {
|
||||
responsiveId: string
|
||||
id: number
|
||||
fullName: string
|
||||
post: string
|
||||
email: string
|
||||
city: string
|
||||
start_date: string
|
||||
salary: number
|
||||
age: string
|
||||
experience: string
|
||||
status: number
|
||||
}
|
||||
|
||||
const data: DataItem[] = [
|
||||
{
|
||||
responsiveId: '',
|
||||
id: 95,
|
||||
fullName: 'Edwina Ebsworth',
|
||||
post: 'Human Resources Assistant',
|
||||
email: 'eebsworth2m@sbwire.com',
|
||||
city: 'Puzi',
|
||||
start_date: '09/27/2018',
|
||||
salary: 19586.23,
|
||||
age: '27',
|
||||
experience: '2 Years',
|
||||
status: 1,
|
||||
},
|
||||
{
|
||||
responsiveId: '',
|
||||
id: 1,
|
||||
fullName: 'Korrie O\'Crevy',
|
||||
post: 'Nuclear Power Engineer',
|
||||
email: 'kocrevy0@thetimes.co.uk',
|
||||
city: 'Krasnosilka',
|
||||
start_date: '09/23/2016',
|
||||
salary: 23896.35,
|
||||
age: '61',
|
||||
experience: '1 Year',
|
||||
status: 2,
|
||||
},
|
||||
{
|
||||
responsiveId: '',
|
||||
id: 7,
|
||||
fullName: 'Eileen Diehn',
|
||||
post: 'Environmental Specialist',
|
||||
email: 'ediehn6@163.com',
|
||||
city: 'Lampuyang',
|
||||
start_date: '10/15/2017',
|
||||
salary: 18991.67,
|
||||
age: '59',
|
||||
experience: '9 Years',
|
||||
status: 3,
|
||||
},
|
||||
{
|
||||
responsiveId: '',
|
||||
id: 11,
|
||||
fullName: 'De Falloon',
|
||||
post: 'Sales Representative',
|
||||
email: 'dfalloona@ifeng.com',
|
||||
city: 'Colima',
|
||||
start_date: '06/12/2018',
|
||||
salary: 19252.12,
|
||||
age: '30',
|
||||
experience: '0 Year',
|
||||
status: 4,
|
||||
},
|
||||
{
|
||||
responsiveId: '',
|
||||
id: 3,
|
||||
fullName: 'Stella Ganderton',
|
||||
post: 'Operator',
|
||||
email: 'sganderton2@tuttocitta.it',
|
||||
city: 'Golcowa',
|
||||
start_date: '03/24/2018',
|
||||
salary: 13076.28,
|
||||
age: '66',
|
||||
experience: '6 Years',
|
||||
status: 5,
|
||||
},
|
||||
{
|
||||
responsiveId: '',
|
||||
id: 5,
|
||||
fullName: 'Harmonia Nisius',
|
||||
post: 'Senior Cost Accountant',
|
||||
email: 'hnisius4@gnu.org',
|
||||
city: 'Lucan',
|
||||
start_date: '08/25/2017',
|
||||
salary: 10909.52,
|
||||
age: '33',
|
||||
experience: '3 Years',
|
||||
status: 2,
|
||||
},
|
||||
{
|
||||
responsiveId: '',
|
||||
id: 6,
|
||||
fullName: 'Genevra Honeywood',
|
||||
post: 'Geologist',
|
||||
email: 'ghoneywood5@narod.ru',
|
||||
city: 'Maofan',
|
||||
start_date: '06/01/2017',
|
||||
salary: 17803.8,
|
||||
age: '61',
|
||||
experience: '1 Year',
|
||||
status: 1,
|
||||
},
|
||||
{
|
||||
responsiveId: '',
|
||||
id: 4,
|
||||
fullName: 'Dorolice Crossman',
|
||||
post: 'Cost Accountant',
|
||||
email: 'dcrossman3@google.co.jp',
|
||||
city: 'Paquera',
|
||||
start_date: '12/03/2017',
|
||||
salary: 12336.17,
|
||||
age: '22',
|
||||
experience: '2 Years',
|
||||
status: 2,
|
||||
},
|
||||
]
|
||||
|
||||
const status: Record<DataItem['status'], string> = {
|
||||
1: 'Current',
|
||||
2: 'Professional',
|
||||
3: 'Rejected',
|
||||
4: 'Resigned',
|
||||
5: 'Applied',
|
||||
}
|
||||
|
||||
const statusColor: Record<typeof status[number], string> = {
|
||||
Current: 'primary',
|
||||
Professional: 'success',
|
||||
Rejected: 'error',
|
||||
Resigned: 'warning',
|
||||
Applied: 'info',
|
||||
}
|
||||
|
||||
const headers = [
|
||||
'NAME',
|
||||
'EMAIL',
|
||||
'DATE',
|
||||
'SALARY',
|
||||
'AGE',
|
||||
'STATUS',
|
||||
]
|
||||
|
||||
const usreList = data
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VCard>
|
||||
<VTable
|
||||
:headers="headers"
|
||||
:items="usreList"
|
||||
item-key="fullName"
|
||||
class="table-rounded"
|
||||
hide-default-footer
|
||||
disable-sort
|
||||
>
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
v-for="header in headers"
|
||||
:key="header"
|
||||
>
|
||||
{{ header }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="row in data"
|
||||
:key="row.fullName"
|
||||
>
|
||||
<!-- name -->
|
||||
|
||||
<td>
|
||||
<div class="d-flex flex-column">
|
||||
<h6 class="text-sm font-weight-medium">{{ row.fullName }}</h6>
|
||||
<span class="text-xs">{{ row.post }}</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td class="text-sm" v-text="row.email" />
|
||||
<td class="text-sm" v-text="row.start_date" />
|
||||
<td class="text-sm" v-text="`$${row.salary}`" />
|
||||
<td class="text-sm" v-text="row.age" />
|
||||
<!-- status -->
|
||||
<td>
|
||||
<VChip
|
||||
size="small"
|
||||
:color="statusColor[status[row.status]]"
|
||||
class="text-capitalize"
|
||||
>
|
||||
{{ status[row.status] }}
|
||||
</VChip>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</VTable>
|
||||
</VCard>
|
||||
</template>
|
||||
Reference in New Issue
Block a user