Browse Source

增加CardPro组件,可设置大小、前缀、后缀

夜鹰 9 months ago
parent
commit
a207355497

+ 74 - 0
Web/src/components/CardPro/README.md

@@ -0,0 +1,74 @@
+# `CardPro` 说明
+
+`CardPro`卡片组件,基于`ElCard`二次封装,增加了大小、标题、图标等属性,可以直接写属性值实现,无需像官方版本一样通过`solt`实现。组件继承了官方版的所有属性、插槽,你也可以按官方版本一样的使用。
+
+---
+
+## 如何使用
+
+### 基本用法
+
+卡片标题、内容以及图标,通过 `prefix-icon` 属性设置卡片图标。与官方版本不同的时,`CardPro` 通过 `title`
+来设置标题,如果你使用 `header` 来设置,它将覆盖 `CardPro` 组件的特有属性,与官方版本完全一致。
+
+```html
+<template>
+    <card-pro title="标题" prefix-icon="ele-DocumentCopy">
+        <!-- 你的内容 -->
+    </card-pro>
+</template>
+<script lang="ts" setup>
+import CardPro from '/@/components/CardPro/index.vue';
+</script>
+```
+
+### 后缀
+
+通过 `suffix` 属性设置卡片右上角文本,你也可以通过 `solt` 来实现自定义内容
+
+```html
+<template>
+    <card-pro title="标题" suffix="more >>>">
+        <!-- 你的内容 -->
+    </card-pro>
+</template>
+<script lang="ts" setup>
+import CardPro from '/@/components/CardPro/index.vue';
+</script>
+```
+
+使用  `solt` 方式来自定义后缀内容,你可以在其中添加按钮、链接、图标、输入框等
+
+```html
+<template>
+    <card-pro title="标题">
+        <template #suffix>
+           <el-button type="primary" icon="ele-Refresh" round plain @click="reset">刷新</el-button>
+        </template>
+
+        <!-- 你的内容 -->
+    </card-pro>
+</template>
+<script lang="ts" setup>
+import CardPro from '/@/components/CardPro/index.vue';
+</script>
+```
+
+### 不同尺寸
+
+使用 `size` 属性配置尺寸,可使用 `large`、`default` 和 `small`
+
+```html
+<template>
+    <card-pro title="标题" size="small">
+        <!-- 你的内容 -->
+    </card-pro>
+</template>
+<script lang="ts" setup>
+import CardPro from '/@/components/CardPro/index.vue';
+</script>
+```
+
+---
+
+最新更新于 2025.10.10

+ 85 - 0
Web/src/components/CardPro/index.vue

@@ -0,0 +1,85 @@
+<template>
+    <el-card v-bind="$attrs">
+        <template #header>
+            <div class="cardpro-header">
+                <div v-if="$slots.prefix || prefixIcon" class="cardpro-header-prefix">
+                    <slot v-if="$slots.prefix" name="prefix" />
+                    <el-icon v-else-if="prefixIcon">
+                        <component :is="prefixIcon" />
+                    </el-icon>
+                </div>
+                <div :class="['cardpro-header-title', sizeClass]">
+                    <span>{{ props.title }}</span>
+                </div>
+                <div v-if="$slots.suffix || suffix" class="cardpro-header-suffix">
+                    <slot v-if="$slots.suffix" name="suffix" />
+                    <span v-else-if="props.suffix">{{ props.suffix }}</span>
+                </div>
+            </div>
+        </template>
+        
+        <template v-for="(value, name) in $slots" #[name]="scopedData">
+            <slot :name="name" v-bind="scopedData"></slot>
+        </template>
+    </el-card>
+</template>
+
+<script setup lang="ts" name="CardPro">
+import { computed } from 'vue';
+import { storeToRefs } from 'pinia';
+import { useSizeProp } from 'element-plus'
+import { useThemeConfig } from '/@/stores/themeConfig';
+
+const storesThemeConfig = useThemeConfig();
+const { themeConfig } = storeToRefs(storesThemeConfig);
+
+const props = defineProps({
+    title: { type: String },
+    prefixIcon: { type: String },
+    suffix: { type: String },
+    size: useSizeProp
+});
+
+// 获取全局组件大小
+const getGlobalComponentSize = computed(() => {
+	return themeConfig.value.globalComponentSize;
+});
+
+const sizeClass = computed(() => {
+    if(props.size) return  "cardpro-" + props.size;
+    else return "cardpro-" + getGlobalComponentSize.value;
+});
+</script>
+
+<style lang="scss" scoped>
+.cardpro-header {
+    display: flex;
+    align-items: center;
+
+    &-prefix {
+        height: 100%;
+        margin-right: 5px;
+        display: flex;
+        align-items: center;
+    }
+    &-title { flex: 1 }
+    &-suffix {
+        height: 100%;
+        margin-left: 5px;
+    }
+}
+
+.cardpro-small {
+    padding: 10px 0;
+}
+.cardpro-default {
+    padding: 15px 0;
+}
+.cardpro-large {
+    padding: 20px 0;
+}
+
+:deep(.el-card__header) {
+    padding: 0 20px;
+}
+</style>

+ 6 - 8
Web/src/views/home/widgets/components/about.vue

@@ -1,10 +1,6 @@
 <template>
-	<el-card shadow="hover" header="关于项目" class="item-background">
-		<template #header>
-			<el-icon style="display: inline; vertical-align: middle"> <ele-QuestionFilled /> </el-icon>
-			<span> 关于项目 </span>
-		</template>
-		<p>
+	<card-pro title="关于项目" prefix-icon="ele-QuestionFilled" shadow="hover">
+        <p>
 			基于 .NET6 (Furion/SqlSugar) 实现的通用权限开发框架,前端采用
 			Vue3+Element-plus+Vite5,整合众多优秀技术和框架,模块插件式开发。集成多租户、缓存、数据校验、鉴权、事件总线、动态API、通讯、远程请求、任务调度、打印等众多黑科技。代码结构简单清晰,注释详尽,易于上手与二次开发,即便是复杂业务逻辑也能迅速实现,真正实现“开箱即用”。
 		</p>
@@ -15,7 +11,7 @@
 				<img src="https://img.shields.io/badge/license-MIT-yellow" alt="license" style="vertical-align: middle" />
 			</a>
 		</p>
-	</el-card>
+    </card-pro>
 </template>
 
 <script lang="ts">
@@ -25,7 +21,9 @@ export default {
 	description: '点个星星支持一下',
 };
 </script>
-<script setup lang="ts" name="about"></script>
+<script setup lang="ts" name="about">
+import CardPro from '/@/components/CardPro/index.vue';
+</script>
 
 <style scoped>
 .item-background p {

+ 7 - 8
Web/src/views/home/widgets/components/commit.vue

@@ -1,11 +1,6 @@
 <template>
-	<el-card shadow="hover" header="更新记录">
-		<template #header>
-			<el-icon style="display: inline; vertical-align: middle"> <ele-DocumentCopy /> </el-icon>
-			<span> 更新记录 </span>
-			<el-button type="primary" icon="ele-Refresh" round plain @click="refresh" style="float: right">更新记录</el-button>
-		</template>
-		<div class="commit" v-loading="state.loading">
+	<card-pro title="更新记录" prefix-icon="ele-DocumentCopy" shadow="hover">
+        <div class="commit" v-loading="state.loading">
 			<el-timeline style="max-width: 600px" v-if="state.list.length > 0">
 				<el-timeline-item v-for="(item, index) in state.list" :key="index" :timestamp="formatDate(new Date(item.commit.committer.date), 'YYYY-mm-dd HH:MM:SS')">
 					<el-link style="white-space: pre-line; word-break: break-all" :href="item.html_url" target="_blank"> {{ item.commit.message }}</el-link>
@@ -13,7 +8,10 @@
 			</el-timeline>
 			<el-empty v-else description="空"></el-empty>
 		</div>
-	</el-card>
+        <template #suffix>
+            <el-button type="primary" icon="ele-Refresh" round plain @click="refresh">更新记录</el-button>
+        </template>
+    </card-pro>
 </template>
 
 <script lang="ts">
@@ -27,6 +25,7 @@ export default {
 <script setup lang="ts" name="commit">
 import { reactive, onMounted } from 'vue';
 import { formatDate } from '/@/utils/formatTime';
+import CardPro from '/@/components/CardPro/index.vue';
 
 const state = reactive({
 	loading: false,

+ 4 - 5
Web/src/views/home/widgets/components/schedule.vue

@@ -1,8 +1,6 @@
 <template>
-	<el-card shadow="hover" header="我的日程" class="item-background">
-		<template #header>
-			<el-icon style="display: inline; vertical-align: middle"> <ele-Calendar /> </el-icon>
-			<span> 我的日程 </span>
+	<card-pro shadow="hover" title="我的日程" prefix-icon="ele-Calendar" class="item-background">
+		<template #suffix>
 			<el-button type="primary" icon="ele-CirclePlus" round plain @click="openAddSchedule" style="float: right">添加日程</el-button>
 		</template>
 
@@ -47,7 +45,7 @@
 		</div>
 
 		<EditSchedule ref="editScheduleRef" :title="state.editTitle" @handleQuery="handleQuery"> </EditSchedule>
-	</el-card>
+	</card-pro>
 </template>
 
 <script lang="ts">
@@ -64,6 +62,7 @@ import { dayjs, ElMessage, ElMessageBox } from 'element-plus';
 import type { CalendarDateType, CalendarInstance } from 'element-plus';
 import calendarCom from '/@/utils/calendar.js';
 
+import CardPro from '/@/components/CardPro/index.vue';
 import EditSchedule from '/@/views/home/widgets/components/scheduleEdit.vue';
 
 import { getAPI } from '/@/utils/axios-utils';