refactor: adjust all sample pages and use page components (#4118)
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
<script setup lang="ts">
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@vben-core/shadcn-ui';
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
name: 'AnalysisChartCard',
|
||||
});
|
||||
|
||||
withDefaults(defineProps<Props>(), {});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle class="text-xl">{{ title }}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<slot></slot>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</template>
|
@@ -0,0 +1,40 @@
|
||||
<script setup lang="ts">
|
||||
import type { TabOption } from '@vben/types';
|
||||
|
||||
import { computed } from 'vue';
|
||||
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@vben-core/shadcn-ui';
|
||||
|
||||
interface Props {
|
||||
tabs: TabOption[];
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
name: 'AnalysisChartsTabs',
|
||||
});
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
tabs: () => [],
|
||||
});
|
||||
|
||||
const defaultValue = computed(() => {
|
||||
return props.tabs?.[0]?.value;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="card-box w-full px-4 pb-5 pt-3 shadow">
|
||||
<Tabs :default-value="defaultValue">
|
||||
<TabsList>
|
||||
<template v-for="tab in tabs" :key="tab.label">
|
||||
<TabsTrigger :value="tab.value"> {{ tab.label }} </TabsTrigger>
|
||||
</template>
|
||||
</TabsList>
|
||||
<template v-for="tab in tabs" :key="tab.label">
|
||||
<TabsContent :value="tab.value" class="pt-4">
|
||||
<slot :name="tab.value"></slot>
|
||||
</TabsContent>
|
||||
</template>
|
||||
</Tabs>
|
||||
</div>
|
||||
</template>
|
@@ -0,0 +1,59 @@
|
||||
<script setup lang="ts">
|
||||
import type { AnalysisOverviewItem } from '../typing';
|
||||
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
VbenCountToAnimator,
|
||||
VbenIcon,
|
||||
} from '@vben-core/shadcn-ui';
|
||||
|
||||
interface Props {
|
||||
items: AnalysisOverviewItem[];
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
name: 'AnalysisOverview',
|
||||
});
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
items: () => [],
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="md:flex">
|
||||
<template v-for="(item, index) in items" :key="item.title">
|
||||
<Card
|
||||
:class="{ 'md:mr-4': index + 1 < 4 }"
|
||||
:title="item.title"
|
||||
class="mt-5 w-full md:mt-0 md:w-1/4"
|
||||
>
|
||||
<CardHeader>
|
||||
<CardTitle class="text-xl">{{ item.title }}</CardTitle>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent class="flex items-center justify-between">
|
||||
<VbenCountToAnimator
|
||||
:end-val="item.value"
|
||||
:start-val="1"
|
||||
class="text-xl"
|
||||
prefix=""
|
||||
/>
|
||||
<VbenIcon :icon="item.icon" class="size-8 flex-shrink-0" />
|
||||
</CardContent>
|
||||
<CardFooter class="justify-between">
|
||||
<span>{{ item.totalTitle }}</span>
|
||||
<VbenCountToAnimator
|
||||
:end-val="item.totalValue"
|
||||
:start-val="1"
|
||||
prefix=""
|
||||
/>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
@@ -0,0 +1,3 @@
|
||||
export { default as AnalysisChartCard } from './analysis-chart-card.vue';
|
||||
export { default as AnalysisChartsTabs } from './analysis-charts-tabs.vue';
|
||||
export { default as AnalysisOverview } from './analysis-overview.vue';
|
3
packages/effects/common-ui/src/ui/dashboard/index.ts
Normal file
3
packages/effects/common-ui/src/ui/dashboard/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from './analysis';
|
||||
export type * from './typing';
|
||||
export * from './workbench';
|
46
packages/effects/common-ui/src/ui/dashboard/typing.ts
Normal file
46
packages/effects/common-ui/src/ui/dashboard/typing.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import type { Component } from 'vue';
|
||||
|
||||
interface AnalysisOverviewItem {
|
||||
icon: Component | string;
|
||||
title: string;
|
||||
totalTitle: string;
|
||||
totalValue: number;
|
||||
value: number;
|
||||
}
|
||||
|
||||
interface WorkbenchProjectItem {
|
||||
color?: string;
|
||||
content: string;
|
||||
date: string;
|
||||
group: string;
|
||||
icon: Component | string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
interface WorkbenchTrendItem {
|
||||
avatar: string;
|
||||
content: string;
|
||||
date: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
interface WorkbenchTodoItem {
|
||||
completed: boolean;
|
||||
content: string;
|
||||
date: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
interface WorkbenchQuickNavItem {
|
||||
color?: string;
|
||||
icon: Component | string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export type {
|
||||
AnalysisOverviewItem,
|
||||
WorkbenchProjectItem,
|
||||
WorkbenchQuickNavItem,
|
||||
WorkbenchTodoItem,
|
||||
WorkbenchTrendItem,
|
||||
};
|
@@ -0,0 +1,5 @@
|
||||
export { default as WorkbenchHeader } from './workbench-header.vue';
|
||||
export { default as WorkbenchProject } from './workbench-project.vue';
|
||||
export { default as WorkbenchQuickNav } from './workbench-quick-nav.vue';
|
||||
export { default as WorkbenchTodo } from './workbench-todo.vue';
|
||||
export { default as WorkbenchTrends } from './workbench-trends.vue';
|
@@ -0,0 +1,46 @@
|
||||
<script lang="ts" setup>
|
||||
import { VbenAvatar } from '@vben-core/shadcn-ui';
|
||||
|
||||
interface Props {
|
||||
avatar?: string;
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
name: 'WorkbenchHeader',
|
||||
});
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
avatar: '',
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div class="card-box p-4 py-6 lg:flex">
|
||||
<VbenAvatar :src="avatar" class="size-20" />
|
||||
<div
|
||||
v-if="$slots.title || $slots.description"
|
||||
class="flex flex-col justify-center md:ml-6 md:mt-0"
|
||||
>
|
||||
<h1 v-if="$slots.title" class="text-md font-semibold md:text-xl">
|
||||
<slot name="title"></slot>
|
||||
</h1>
|
||||
<span v-if="$slots.description" class="text-foreground/80 mt-1">
|
||||
<slot name="description"></slot>
|
||||
</span>
|
||||
</div>
|
||||
<div class="mt-4 flex flex-1 justify-end md:mt-0">
|
||||
<div class="flex flex-col justify-center text-right">
|
||||
<span class="text-foreground/80"> 待办 </span>
|
||||
<span class="text-2xl">2/10</span>
|
||||
</div>
|
||||
|
||||
<div class="mx-12 flex flex-col justify-center text-right md:mx-16">
|
||||
<span class="text-foreground/80"> 项目 </span>
|
||||
<span class="text-2xl">8</span>
|
||||
</div>
|
||||
<div class="mr-4 flex flex-col justify-center text-right md:mr-10">
|
||||
<span class="text-foreground/80"> 团队 </span>
|
||||
<span class="text-2xl">300</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
@@ -0,0 +1,60 @@
|
||||
<script setup lang="ts">
|
||||
import type { WorkbenchProjectItem } from '../typing';
|
||||
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
VbenIcon,
|
||||
} from '@vben-core/shadcn-ui';
|
||||
|
||||
interface Props {
|
||||
items: WorkbenchProjectItem[];
|
||||
title: string;
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
name: 'WorkbenchProject',
|
||||
});
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
items: () => [],
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Card>
|
||||
<CardHeader class="py-4">
|
||||
<CardTitle class="text-lg">{{ title }}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent class="flex flex-wrap p-0">
|
||||
<template v-for="(item, index) in items" :key="item.title">
|
||||
<div
|
||||
:class="{
|
||||
'border-r-0': index % 3 === 2,
|
||||
'border-b-0': index < 3,
|
||||
'pb-4': index > 2,
|
||||
}"
|
||||
class="border-border group w-full cursor-pointer border-b border-r border-t p-4 transition-all hover:shadow-xl md:w-1/2 lg:w-1/3"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<VbenIcon
|
||||
:color="item.color"
|
||||
:icon="item.icon"
|
||||
class="size-8 transition-all duration-300 group-hover:scale-110"
|
||||
/>
|
||||
<span class="ml-4 text-lg font-medium">{{ item.title }}</span>
|
||||
</div>
|
||||
<div class="text-foreground/80 mt-4 flex h-10">
|
||||
{{ item.content }}
|
||||
</div>
|
||||
<div class="text-foreground/80 flex justify-between">
|
||||
<span>{{ item.group }}</span>
|
||||
<span>{{ item.date }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</template>
|
@@ -0,0 +1,51 @@
|
||||
<script setup lang="ts">
|
||||
import type { WorkbenchQuickNavItem } from '../typing';
|
||||
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
VbenIcon,
|
||||
} from '@vben-core/shadcn-ui';
|
||||
|
||||
interface Props {
|
||||
items: WorkbenchQuickNavItem[];
|
||||
title: string;
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
name: 'WorkbenchQuickNav',
|
||||
});
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
items: () => [],
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Card>
|
||||
<CardHeader class="py-4">
|
||||
<CardTitle class="text-lg">{{ title }}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent class="flex flex-wrap p-0">
|
||||
<template v-for="(item, index) in items" :key="item.title">
|
||||
<div
|
||||
:class="{
|
||||
'border-r-0': index % 3 === 2,
|
||||
'pb-4': index > 2,
|
||||
'border-b-0': index < 3,
|
||||
}"
|
||||
class="flex-col-center border-border group w-1/3 cursor-pointer border-b border-r border-t py-8 hover:shadow-xl"
|
||||
>
|
||||
<VbenIcon
|
||||
:color="item.color"
|
||||
:icon="item.icon"
|
||||
class="size-7 transition-all duration-300 group-hover:scale-125"
|
||||
/>
|
||||
<span class="text-md mt-2 truncate">{{ item.title }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</template>
|
@@ -0,0 +1,63 @@
|
||||
<script setup lang="ts">
|
||||
import type { WorkbenchTodoItem } from '../typing';
|
||||
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
VbenCheckbox,
|
||||
} from '@vben-core/shadcn-ui';
|
||||
|
||||
interface Props {
|
||||
items: WorkbenchTodoItem[];
|
||||
title: string;
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
name: 'WorkbenchTodo',
|
||||
});
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
items: () => [],
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Card>
|
||||
<CardHeader class="py-4">
|
||||
<CardTitle class="text-lg">{{ title }}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent class="flex flex-wrap p-5 pt-0">
|
||||
<ul class="divide-border w-full divide-y" role="list">
|
||||
<li
|
||||
v-for="item in items"
|
||||
:key="item.title"
|
||||
:class="{
|
||||
'select-none line-through opacity-60': item.completed,
|
||||
}"
|
||||
class="flex cursor-pointer justify-between gap-x-6 py-5"
|
||||
>
|
||||
<div class="flex min-w-0 items-center gap-x-4">
|
||||
<VbenCheckbox v-model:checked="item.completed" name="completed" />
|
||||
<div class="min-w-0 flex-auto">
|
||||
<p class="text-foreground text-sm font-semibold leading-6">
|
||||
{{ item.title }}
|
||||
</p>
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<p
|
||||
class="text-foreground/80 *:text-primary mt-1 truncate text-xs leading-5"
|
||||
v-html="item.content"
|
||||
></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hidden h-full shrink-0 sm:flex sm:flex-col sm:items-end">
|
||||
<span class="text-foreground/80 mt-6 text-xs leading-6">
|
||||
{{ item.date }}
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</template>
|
@@ -0,0 +1,64 @@
|
||||
<script setup lang="ts">
|
||||
import type { WorkbenchTrendItem } from '../typing';
|
||||
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
VbenIcon,
|
||||
} from '@vben-core/shadcn-ui';
|
||||
|
||||
interface Props {
|
||||
items: WorkbenchTrendItem[];
|
||||
title: string;
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
name: 'WorkbenchTrends',
|
||||
});
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
items: () => [],
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Card>
|
||||
<CardHeader class="py-4">
|
||||
<CardTitle class="text-lg">{{ title }}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent class="flex flex-wrap p-5 pt-0">
|
||||
<ul class="divide-border w-full divide-y" role="list">
|
||||
<li
|
||||
v-for="item in items"
|
||||
:key="item.title"
|
||||
class="flex justify-between gap-x-6 py-5"
|
||||
>
|
||||
<div class="flex min-w-0 items-center gap-x-4">
|
||||
<VbenIcon
|
||||
:icon="item.avatar"
|
||||
alt=""
|
||||
class="size-10 flex-none rounded-full"
|
||||
/>
|
||||
<div class="min-w-0 flex-auto">
|
||||
<p class="text-foreground text-sm font-semibold leading-6">
|
||||
{{ item.title }}
|
||||
</p>
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<p
|
||||
class="text-foreground/80 *:text-primary mt-1 truncate text-xs leading-5"
|
||||
v-html="item.content"
|
||||
></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hidden h-full shrink-0 sm:flex sm:flex-col sm:items-end">
|
||||
<span class="text-foreground/80 mt-6 text-xs leading-6">
|
||||
{{ item.date }}
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</template>
|
Reference in New Issue
Block a user