Initial commit: One Pipe System
完整的管理系统,包含账户管理、卡片管理、套餐管理、财务管理等功能模块。 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
142
src/views/template/banners/index.vue
Normal file
142
src/views/template/banners/index.vue
Normal file
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<div class="banners">
|
||||
<h1 class="page-title">基础横幅</h1>
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :xs="24" :sm="12" :md="12">
|
||||
<ArtBasicBanner
|
||||
title="欢迎回来,管理员!"
|
||||
subtitle="今日系统访问量增长了23%,运行状态良好。"
|
||||
buttonText="查看详情"
|
||||
buttonColor="rgb(var(--art-secondary))"
|
||||
buttonTextColor="#fff"
|
||||
@click="handleBannerClick"
|
||||
/>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :md="12">
|
||||
<ArtBasicBanner
|
||||
title="欢迎使用本系统!"
|
||||
subtitle="这是一个基于Vue3和Element Plus的后台管理系统模板。"
|
||||
buttonText="开始使用"
|
||||
buttonColor="rgb(var(--art-success))"
|
||||
buttonTextColor="#fff"
|
||||
backgroundColor="#D4F1F7"
|
||||
titleColor="#333"
|
||||
subtitleColor="#666"
|
||||
@click="handleBannerClick"
|
||||
/>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<h1 class="page-title">基础横幅(图片)</h1>
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :xs="24" :sm="12" :md="12">
|
||||
<ArtBasicBanner
|
||||
title="欢迎回来,管理员!"
|
||||
subtitle="今日系统访问量增长了23%,运行状态良好。"
|
||||
buttonText="查看详情"
|
||||
buttonColor="#FF3E76"
|
||||
backgroundColor="#FF80A4"
|
||||
buttonTextColor="#fff"
|
||||
:backgroundImage="icon3"
|
||||
@click="handleBannerClick"
|
||||
/>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :md="12">
|
||||
<ArtBasicBanner
|
||||
title="欢迎使用本系统!"
|
||||
subtitle="这是一个基于Vue3和Element Plus的后台管理系统模板。"
|
||||
buttonText="开始使用"
|
||||
buttonColor="#1385FF"
|
||||
buttonTextColor="#fff"
|
||||
backgroundColor="#88A7FF"
|
||||
:backgroundImage="icon5"
|
||||
@click="handleBannerClick"
|
||||
/>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<h1 class="page-title">卡片横幅</h1>
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :xs="24" :sm="12" :md="12" :lg="6">
|
||||
<ArtCardBanner
|
||||
title="系统状态良好"
|
||||
description="所有服务运行正常,无异常情况。"
|
||||
buttonText="查看详情"
|
||||
/>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :md="12" :lg="6">
|
||||
<ArtCardBanner
|
||||
:icon="icon2"
|
||||
title="新消息提醒"
|
||||
description="您有3条未读消息需要处理。"
|
||||
buttonText="立即查看"
|
||||
buttonColor="rgb(var(--art-warning))"
|
||||
/>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :md="12" :lg="6">
|
||||
<ArtCardBanner
|
||||
:icon="icon3"
|
||||
title="数据分析报告"
|
||||
description="本周数据分析报告已生成完毕。"
|
||||
buttonText="下载报告"
|
||||
buttonColor="rgb(var(--art-error))"
|
||||
/>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :md="12" :lg="6">
|
||||
<ArtCardBanner
|
||||
:icon="icon4"
|
||||
title="系统更新提示"
|
||||
description="新版本V2.1.0已发布,建议及时更新。"
|
||||
buttonText="更新"
|
||||
buttonColor="rgb(var(--art-primary))"
|
||||
:showCancel="true"
|
||||
cancelButtonText="取消"
|
||||
cancelButtonColor="#eee"
|
||||
cancelButtonTextColor="#333"
|
||||
@click="handleConfirm"
|
||||
@cancel="handleCancel"
|
||||
/>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import icon2 from '@imgs/3d/icon2.webp'
|
||||
import icon3 from '@imgs/3d/icon3.webp'
|
||||
import icon4 from '@imgs/3d/icon4.webp'
|
||||
import icon5 from '@imgs/3d/icon7.webp'
|
||||
import { ElRow } from 'element-plus'
|
||||
|
||||
const handleBannerClick = () => {
|
||||
console.log('banner clicked')
|
||||
}
|
||||
|
||||
const handleConfirm = () => {
|
||||
console.log('confirm clicked')
|
||||
}
|
||||
|
||||
const handleCancel = () => {
|
||||
console.log('cancel clicked')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.banners {
|
||||
padding-top: 20px;
|
||||
|
||||
.page-title {
|
||||
margin: 20px 0 15px;
|
||||
font-size: 22px;
|
||||
font-weight: 500;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.el-col {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
294
src/views/template/calendar/index.vue
Normal file
294
src/views/template/calendar/index.vue
Normal file
@@ -0,0 +1,294 @@
|
||||
<template>
|
||||
<div class="page-content">
|
||||
<!-- 日历主体 -->
|
||||
<ElCalendar v-model="currentDate">
|
||||
<template #date-cell="{ data }">
|
||||
<div
|
||||
class="calendar-cell"
|
||||
:class="{ 'is-selected': data.isSelected }"
|
||||
@click="handleCellClick(data.day)"
|
||||
>
|
||||
<!-- 日期显示 -->
|
||||
<p class="calendar-date">{{ formatDate(data.day) }}</p>
|
||||
|
||||
<!-- 事件列表 -->
|
||||
<div class="calendar-events">
|
||||
<div
|
||||
v-for="event in getEvents(data.day)"
|
||||
:key="`${event.date}-${event.content}`"
|
||||
class="calendar-event"
|
||||
@click.stop="handleEventClick(event)"
|
||||
>
|
||||
<div class="event-tag" :class="[`${event.type || 'bg-primary'}`]">
|
||||
{{ event.content }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</ElCalendar>
|
||||
|
||||
<!-- 事件编辑弹窗 -->
|
||||
<ElDialog v-model="dialogVisible" :title="dialogTitle" width="600px" @closed="resetForm">
|
||||
<ElForm :model="eventForm" label-width="80px">
|
||||
<ElFormItem label="活动标题" required>
|
||||
<ElInput v-model="eventForm.content" placeholder="请输入活动标题" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="事件颜色">
|
||||
<ElRadioGroup v-model="eventForm.type">
|
||||
<ElRadio v-for="type in eventTypes" :key="type.value" :value="type.value">
|
||||
{{ type.label }}
|
||||
</ElRadio>
|
||||
</ElRadioGroup>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="开始日期" required>
|
||||
<ElDatePicker
|
||||
style="width: 100%"
|
||||
v-model="eventForm.date"
|
||||
type="date"
|
||||
placeholder="选择日期"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="结束日期">
|
||||
<ElDatePicker
|
||||
style="width: 100%"
|
||||
v-model="eventForm.endDate"
|
||||
type="date"
|
||||
placeholder="选择结束日期"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
:min-date="eventForm.date"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<ElButton v-if="isEditing" type="danger" @click="handleDeleteEvent"> 删除 </ElButton>
|
||||
<ElButton type="primary" @click="handleSaveEvent">
|
||||
{{ isEditing ? '更新' : '添加' }}
|
||||
</ElButton>
|
||||
</span>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 类型定义
|
||||
interface CalendarEvent {
|
||||
date: string
|
||||
endDate?: string
|
||||
content: string
|
||||
type?: 'bg-primary' | 'bg-success' | 'bg-warning' | 'bg-danger'
|
||||
}
|
||||
|
||||
// 常量定义
|
||||
const eventTypes = [
|
||||
{ label: '基本', value: 'bg-primary' },
|
||||
{ label: '成功', value: 'bg-success' },
|
||||
{ label: '警告', value: 'bg-warning' },
|
||||
{ label: '危险', value: 'bg-danger' }
|
||||
] as const
|
||||
|
||||
// 状态管理
|
||||
const currentDate = ref(new Date('2025-02-07'))
|
||||
const events = ref<CalendarEvent[]>([
|
||||
{ date: '2025-02-01', content: '产品需求评审', type: 'bg-primary' },
|
||||
{
|
||||
date: '2025-02-03',
|
||||
endDate: '2025-02-05',
|
||||
content: '项目周报会议(跨日期)',
|
||||
type: 'bg-primary'
|
||||
},
|
||||
{ date: '2025-02-10', content: '瑜伽课程', type: 'bg-success' },
|
||||
{ date: '2025-02-15', content: '团队建设活动', type: 'bg-primary' },
|
||||
{ date: '2025-02-20', content: '健身训练', type: 'bg-success' },
|
||||
{ date: '2025-02-20', content: '代码评审', type: 'bg-danger' },
|
||||
{ date: '2025-02-20', content: '团队午餐', type: 'bg-primary' },
|
||||
{ date: '2025-02-20', content: '项目进度汇报', type: 'bg-warning' },
|
||||
{ date: '2025-02-28', content: '月度总结会', type: 'bg-warning' }
|
||||
])
|
||||
|
||||
// 弹窗状态管理
|
||||
const dialogVisible = ref(false)
|
||||
const dialogTitle = ref('添加事件')
|
||||
const editingEventIndex = ref<number>(-1)
|
||||
const eventForm = ref<CalendarEvent>({
|
||||
date: '',
|
||||
endDate: '',
|
||||
content: '',
|
||||
type: 'bg-primary'
|
||||
})
|
||||
|
||||
// 计算属性
|
||||
const isEditing = computed(() => editingEventIndex.value >= 0)
|
||||
|
||||
// 工具函数
|
||||
const formatDate = (date: string) => date.split('-')[2]
|
||||
|
||||
const getEvents = (day: string) => {
|
||||
return events.value.filter((event) => {
|
||||
const eventDate = new Date(event.date)
|
||||
const currentDate = new Date(day)
|
||||
const endDate = event.endDate ? new Date(event.endDate) : new Date(event.date)
|
||||
|
||||
return currentDate >= eventDate && currentDate <= endDate
|
||||
})
|
||||
}
|
||||
|
||||
const resetForm = () => {
|
||||
eventForm.value = {
|
||||
date: '',
|
||||
endDate: '',
|
||||
content: '',
|
||||
type: 'bg-primary'
|
||||
}
|
||||
editingEventIndex.value = -1
|
||||
}
|
||||
|
||||
// 事件处理函数
|
||||
const handleCellClick = (day: string) => {
|
||||
dialogTitle.value = '添加事件'
|
||||
eventForm.value = {
|
||||
date: day,
|
||||
content: '',
|
||||
type: 'bg-primary'
|
||||
}
|
||||
editingEventIndex.value = -1
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
const handleEventClick = (event: CalendarEvent) => {
|
||||
dialogTitle.value = '编辑事件'
|
||||
eventForm.value = { ...event }
|
||||
editingEventIndex.value = events.value.findIndex(
|
||||
(e) => e.date === event.date && e.content === event.content
|
||||
)
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
const handleSaveEvent = () => {
|
||||
if (!eventForm.value.content || !eventForm.value.date) {
|
||||
return
|
||||
}
|
||||
|
||||
if (isEditing.value) {
|
||||
events.value[editingEventIndex.value] = { ...eventForm.value }
|
||||
} else {
|
||||
events.value.push({ ...eventForm.value })
|
||||
}
|
||||
|
||||
dialogVisible.value = false
|
||||
resetForm()
|
||||
}
|
||||
|
||||
const handleDeleteEvent = () => {
|
||||
if (isEditing.value) {
|
||||
events.value.splice(editingEventIndex.value, 1)
|
||||
dialogVisible.value = false
|
||||
resetForm()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.page-content {
|
||||
height: 100%;
|
||||
|
||||
:deep(.el-calendar) {
|
||||
height: 100%;
|
||||
|
||||
.el-calendar__body {
|
||||
height: calc(100% - 70px);
|
||||
}
|
||||
|
||||
.el-calendar-table {
|
||||
height: 100%;
|
||||
|
||||
.is-selected {
|
||||
// 选中日期的背景颜色
|
||||
background-color: var(--el-color-warning-light-9) !important;
|
||||
}
|
||||
|
||||
.el-calendar-day {
|
||||
height: 100%;
|
||||
|
||||
&:hover {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-cell {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
min-height: 120px;
|
||||
max-height: 120px;
|
||||
padding: 4px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
|
||||
.calendar-date {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 4px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.calendar-events {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
width: 100%;
|
||||
max-height: 85px;
|
||||
padding-right: 4px;
|
||||
margin-top: 24px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.event-tag {
|
||||
min-width: 100px;
|
||||
padding: 6px 12px;
|
||||
overflow: hidden;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
line-height: 24px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
border-radius: 4px;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: inline-block;
|
||||
width: 4px;
|
||||
height: 100%;
|
||||
content: '';
|
||||
}
|
||||
|
||||
&.event-continues::after {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 4px;
|
||||
font-size: 12px;
|
||||
content: '►';
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-dialog__body) {
|
||||
padding-top: 20px;
|
||||
}
|
||||
</style>
|
||||
442
src/views/template/cards/index.vue
Normal file
442
src/views/template/cards/index.vue
Normal file
@@ -0,0 +1,442 @@
|
||||
<template>
|
||||
<div class="cards">
|
||||
<h1 class="page-title">统计卡片(文字)</h1>
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :xs="24" :sm="12" :md="6" v-for="card in statsCards" :key="card.id">
|
||||
<ArtStatsCard
|
||||
:icon="card.icon"
|
||||
:title="card.title"
|
||||
:description="card.description"
|
||||
:iconSize="card.iconSize"
|
||||
iconColor="#fff"
|
||||
:iconBgColor="card.iconBgColor"
|
||||
:showArrow="card.showArrow"
|
||||
/>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<h1 class="page-title">统计卡片(数字滚动)</h1>
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :xs="24" :sm="12" :md="6" v-for="card in statsCards" :key="card.id">
|
||||
<ArtStatsCard
|
||||
:icon="card.icon"
|
||||
:count="card.count"
|
||||
:description="card.description"
|
||||
:iconSize="card.iconSize"
|
||||
iconColor="#fff"
|
||||
:iconBgColor="card.iconBgColor"
|
||||
:showArrow="card.showArrow"
|
||||
/>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<h1 class="page-title">统计卡片(自定义样式)</h1>
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :xs="24" :sm="12" :md="6" v-for="card in statsCards" :key="card.id">
|
||||
<ArtStatsCard
|
||||
:icon="card.icon"
|
||||
:title="card.title"
|
||||
:description="card.description"
|
||||
:iconColor="card.iconColor"
|
||||
:textColor="card.textColor"
|
||||
:backgroundColor="card.backgroundColor"
|
||||
:showArrow="card.showArrow"
|
||||
/>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<h1 class="page-title">进度卡片</h1>
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :xs="24" :sm="12" :md="6" v-for="card in progressCards" :key="card.id">
|
||||
<ArtProgressCard :percentage="card.percentage" :title="card.title" :color="card.color" />
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<h1 class="page-title">进度卡片(icon)</h1>
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :xs="24" :sm="12" :md="6" v-for="card in progressCards" :key="card.id">
|
||||
<ArtProgressCard
|
||||
:percentage="card.percentage"
|
||||
:title="card.title"
|
||||
:color="card.color"
|
||||
:icon="card.icon"
|
||||
:iconColor="card.iconColor"
|
||||
:iconBgColor="card.iconBgColor"
|
||||
:iconSize="card.iconSize"
|
||||
/>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<h1 class="page-title">图表卡片(小图表)</h1>
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :xs="24" :sm="12" :md="6">
|
||||
<ArtLineChartCard
|
||||
:isMiniChart="true"
|
||||
:value="2545"
|
||||
label="新用户"
|
||||
date="过去7天"
|
||||
:percentage="1.2"
|
||||
:height="9.5"
|
||||
:chartData="[120, 132, 101, 134, 90, 230, 210]"
|
||||
/>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :md="6">
|
||||
<ArtBarChartCard
|
||||
:isMiniChart="true"
|
||||
:value="15480"
|
||||
label="浏览量"
|
||||
date="过去 14 天"
|
||||
:percentage="-4.15"
|
||||
:height="9.5"
|
||||
:chartData="[120, 100, 150, 140, 90, 120, 130]"
|
||||
/>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :md="6">
|
||||
<ArtLineChartCard
|
||||
:isMiniChart="true"
|
||||
:value="2545"
|
||||
label="粉丝数"
|
||||
date="过去 30 天"
|
||||
:percentage="1.2"
|
||||
:height="9.5"
|
||||
:showAreaColor="true"
|
||||
:chartData="[150, 180, 160, 200, 180, 220, 240]"
|
||||
/>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :md="6">
|
||||
<ArtDonutChartCard
|
||||
:value="36358"
|
||||
title="粉丝量"
|
||||
:percentage="18"
|
||||
:data="[50, 40]"
|
||||
:height="9.5"
|
||||
currentYear="2022"
|
||||
previousYear="2021"
|
||||
:radius="['50%', '70%']"
|
||||
/>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<h1 class="page-title">图表卡片(大图表)</h1>
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :xs="24" :sm="12" :md="6">
|
||||
<ArtLineChartCard
|
||||
:value="2545"
|
||||
label="新用户"
|
||||
:percentage="1.2"
|
||||
:height="11"
|
||||
:chartData="[120, 132, 101, 134, 90, 230, 210]"
|
||||
/>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :md="6">
|
||||
<ArtBarChartCard
|
||||
:value="15480"
|
||||
label="浏览量"
|
||||
:percentage="-4.15"
|
||||
:height="11"
|
||||
:chartData="[120, 100, 150, 140, 90, 120, 130, 110]"
|
||||
/>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :md="6">
|
||||
<ArtLineChartCard
|
||||
:value="2545"
|
||||
label="粉丝数"
|
||||
:percentage="1.2"
|
||||
:height="11"
|
||||
:showAreaColor="true"
|
||||
:chartData="[150, 180, 160, 200, 180, 220, 240]"
|
||||
/>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :md="6">
|
||||
<ArtDonutChartCard
|
||||
:value="36358"
|
||||
title="粉丝量"
|
||||
:percentage="18"
|
||||
:data="[70, 30]"
|
||||
:height="11"
|
||||
currentYear="2022"
|
||||
previousYear="2021"
|
||||
/>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<h1 class="page-title">数据列表卡片</h1>
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :xs="24" :sm="12" :lg="8">
|
||||
<ArtDataListCard :list="dataList" title="待办事项" subtitle="今日待处理任务" />
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :lg="8">
|
||||
<ArtDataListCard
|
||||
:maxCount="4"
|
||||
:list="dataList"
|
||||
title="最近活动"
|
||||
subtitle="近期活动列表"
|
||||
:showMoreButton="true"
|
||||
@more="handleMore"
|
||||
/>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :lg="8">
|
||||
<ArtTimelineListCard :list="timelineData" title="最近交易" subtitle="2024年12月20日" />
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<h1 class="page-title">图片卡片</h1>
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :xs="24" :sm="12" :md="6" v-for="card in imageCards" :key="card.id">
|
||||
<ArtImageCard
|
||||
:imageUrl="card.imageUrl"
|
||||
:title="card.title"
|
||||
:category="card.category"
|
||||
:readTime="card.readTime"
|
||||
:views="card.views"
|
||||
:comments="card.comments"
|
||||
:date="card.date"
|
||||
/>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import cover1 from '@imgs/cover/img1.webp'
|
||||
import cover2 from '@imgs/cover/img2.webp'
|
||||
import cover3 from '@imgs/cover/img3.webp'
|
||||
import cover4 from '@imgs/cover/img4.webp'
|
||||
|
||||
const statsCards = [
|
||||
{
|
||||
id: 1,
|
||||
title: '销售产品',
|
||||
count: 1235,
|
||||
description: '鞋子、牛仔裤、派对服装、手表',
|
||||
icon: '',
|
||||
iconColor: 'rgb(var(--art-primary))',
|
||||
iconSize: 20,
|
||||
iconBgColor: 'rgb(var(--art-info))',
|
||||
textColor: 'rgb(var(--art-primary))',
|
||||
backgroundColor: 'rgb(var(--art-bg-primary))',
|
||||
showArrow: false
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '活跃用户',
|
||||
count: 5000,
|
||||
description: '日活跃用户超过5,000+',
|
||||
icon: '',
|
||||
iconColor: 'rgb(var(--art-warning))',
|
||||
iconSize: 20,
|
||||
iconBgColor: 'rgb(var(--art-success))',
|
||||
textColor: 'rgb(var(--art-warning))',
|
||||
backgroundColor: 'rgb(var(--art-bg-warning))',
|
||||
showArrow: false
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: '总收入',
|
||||
count: 35000,
|
||||
description: '月收入超过¥350,000+',
|
||||
icon: '',
|
||||
iconColor: 'rgb(var(--art-secondary))',
|
||||
iconSize: 20,
|
||||
iconBgColor: 'rgb(var(--art-secondary))',
|
||||
textColor: 'rgb(var(--art-secondary))',
|
||||
backgroundColor: 'rgb(var(--art-bg-secondary))',
|
||||
showArrow: false
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: '客户评价',
|
||||
count: 4800,
|
||||
description: '平均评分4.8/5',
|
||||
icon: '',
|
||||
iconColor: 'rgb(var(--art-error))',
|
||||
iconSize: 20,
|
||||
iconBgColor: 'rgb(var(--art-error))',
|
||||
textColor: 'rgb(var(--art-error))',
|
||||
backgroundColor: 'rgb(var(--art-bg-error))',
|
||||
showArrow: false
|
||||
}
|
||||
]
|
||||
|
||||
const progressCards = [
|
||||
{
|
||||
id: 1,
|
||||
title: '完成进度',
|
||||
percentage: 75,
|
||||
color: 'rgb(var(--art-success))',
|
||||
icon: '',
|
||||
iconColor: 'rgb(var(--art-success))',
|
||||
iconBgColor: 'rgb(var(--art-bg-success))',
|
||||
iconSize: 20
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '项目进度',
|
||||
percentage: 65,
|
||||
color: 'rgb(var(--art-primary))',
|
||||
icon: '',
|
||||
iconColor: 'rgb(var(--art-primary))',
|
||||
iconBgColor: 'rgb(var(--art-bg-primary))',
|
||||
iconSize: 20
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: '学习进度',
|
||||
percentage: 45,
|
||||
color: 'rgb(var(--art-error))',
|
||||
icon: '',
|
||||
iconColor: 'rgb(var(--art-error))',
|
||||
iconBgColor: 'rgb(var(--art-bg-error))',
|
||||
iconSize: 20
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: '任务进度',
|
||||
percentage: 90,
|
||||
color: 'rgb(var(--art-secondary))',
|
||||
icon: '',
|
||||
iconColor: 'rgb(var(--art-secondary))',
|
||||
iconBgColor: 'rgb(var(--art-bg-secondary))',
|
||||
iconSize: 20
|
||||
}
|
||||
]
|
||||
|
||||
const imageCards = [
|
||||
{
|
||||
id: 1,
|
||||
imageUrl: cover1,
|
||||
title: 'AI技术在医疗领域的创新应用与发展前景',
|
||||
category: '社交',
|
||||
readTime: '2分钟',
|
||||
views: 9125,
|
||||
comments: 3,
|
||||
date: '12月19日 周一'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
imageUrl: cover2,
|
||||
title: '大数据分析助力企业决策的实践案例',
|
||||
category: '技术',
|
||||
readTime: '3分钟',
|
||||
views: 7234,
|
||||
comments: 5,
|
||||
date: '12月20日 周二'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
imageUrl: cover3,
|
||||
title: '区块链技术在供应链管理中的应用',
|
||||
category: '科技',
|
||||
readTime: '4分钟',
|
||||
views: 5678,
|
||||
comments: 8,
|
||||
date: '12月21日 周三'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
imageUrl: cover4,
|
||||
title: '云计算技术发展趋势与未来展望',
|
||||
category: '云技术',
|
||||
readTime: '5分钟',
|
||||
views: 4321,
|
||||
comments: 6,
|
||||
date: '12月22日 周四'
|
||||
}
|
||||
]
|
||||
|
||||
const dataList = [
|
||||
{
|
||||
title: '新加坡之行',
|
||||
status: '进行中',
|
||||
time: '5分钟',
|
||||
class: 'bg-primary',
|
||||
icon: ''
|
||||
},
|
||||
{
|
||||
title: '归档数据',
|
||||
status: '进行中',
|
||||
time: '10分钟',
|
||||
class: 'bg-secondary',
|
||||
icon: ''
|
||||
},
|
||||
{
|
||||
title: '客户会议',
|
||||
status: '待处理',
|
||||
time: '15分钟',
|
||||
class: 'bg-warning',
|
||||
icon: ''
|
||||
},
|
||||
{
|
||||
title: '筛选任务团队',
|
||||
status: '进行中',
|
||||
time: '20分钟',
|
||||
class: 'bg-danger',
|
||||
icon: ''
|
||||
},
|
||||
{
|
||||
title: '发送信封给小王',
|
||||
status: '已完成',
|
||||
time: '20分钟',
|
||||
class: 'bg-success',
|
||||
icon: ''
|
||||
}
|
||||
]
|
||||
|
||||
const timelineData = [
|
||||
{
|
||||
time: '上午 09:30',
|
||||
status: 'rgb(73, 190, 255)',
|
||||
content: '收到 John Doe 支付的 385.90 美元'
|
||||
},
|
||||
{
|
||||
time: '上午 10:00',
|
||||
status: 'rgb(54, 158, 255)',
|
||||
content: '新销售记录',
|
||||
code: 'ML-3467'
|
||||
},
|
||||
{
|
||||
time: '上午 12:00',
|
||||
status: 'rgb(103, 232, 207)',
|
||||
content: '向 Michael 支付了 64.95 美元'
|
||||
},
|
||||
{
|
||||
time: '下午 14:30',
|
||||
status: 'rgb(255, 193, 7)',
|
||||
content: '系统维护通知',
|
||||
code: 'MT-2023'
|
||||
},
|
||||
{
|
||||
time: '下午 15:45',
|
||||
status: 'rgb(255, 105, 105)',
|
||||
content: '紧急订单取消提醒',
|
||||
code: 'OR-9876'
|
||||
},
|
||||
{
|
||||
time: '下午 17:00',
|
||||
status: 'rgb(103, 232, 207)',
|
||||
content: '完成每日销售报表'
|
||||
}
|
||||
]
|
||||
|
||||
const handleMore = () => {}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.cards {
|
||||
padding: 20px 0;
|
||||
|
||||
.page-title {
|
||||
margin: 20px 0 15px;
|
||||
font-size: 22px;
|
||||
font-weight: 500;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.el-col {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
185
src/views/template/charts/index.vue
Normal file
185
src/views/template/charts/index.vue
Normal file
@@ -0,0 +1,185 @@
|
||||
<template>
|
||||
<div class="charts">
|
||||
<h1 class="page-title">图表</h1>
|
||||
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :xs="24" :md="12" :lg="8">
|
||||
<div class="card art-custom-card">
|
||||
<div class="card-header">
|
||||
<span>柱状图</span>
|
||||
</div>
|
||||
<ArtBarChart
|
||||
:data="[50, 80, 120, 90, 60, 70, 100]"
|
||||
:xAxisData="['一月', '二月', '三月', '四月', '五月', '六月', '七月']"
|
||||
/>
|
||||
</div>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :md="12" :lg="8">
|
||||
<div class="card art-custom-card">
|
||||
<div class="card-header">
|
||||
<span>折线图</span>
|
||||
</div>
|
||||
<ArtLineChart
|
||||
:data="[58, 15, 82, 35, 90, 82, 85]"
|
||||
:xAxisData="['一月', '二月', '三月', '四月', '五月', '六月', '七月']"
|
||||
/>
|
||||
</div>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :md="12" :lg="8">
|
||||
<div class="card art-custom-card">
|
||||
<div class="card-header">
|
||||
<span>折线图(渐变背景)</span>
|
||||
</div>
|
||||
<ArtLineChart
|
||||
:data="[58, 15, 82, 35, 90, 82, 85]"
|
||||
:xAxisData="['一月', '二月', '三月', '四月', '五月', '六月', '七月']"
|
||||
:showAreaColor="true"
|
||||
/>
|
||||
</div>
|
||||
</ElCol>
|
||||
|
||||
<ElCol :xs="24" :md="12" :lg="8">
|
||||
<div class="card art-custom-card">
|
||||
<div class="card-header">
|
||||
<span>散点图</span>
|
||||
</div>
|
||||
<ArtScatterChart
|
||||
:data="[
|
||||
{ value: [1, 3] },
|
||||
{ value: [2, 4] },
|
||||
{ value: [3, 5] },
|
||||
{ value: [4, 6] },
|
||||
{ value: [5, 7] },
|
||||
{ value: [6, 8] },
|
||||
{ value: [7, 7] },
|
||||
{ value: [8, 9] },
|
||||
{ value: [9, 8] },
|
||||
{ value: [10, 6] },
|
||||
{ value: [11, 7] },
|
||||
{ value: [12, 8] }
|
||||
]"
|
||||
width="100%"
|
||||
/>
|
||||
</div>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :md="12" :lg="8">
|
||||
<div class="card art-custom-card">
|
||||
<div class="card-header">
|
||||
<span>环形图</span>
|
||||
</div>
|
||||
<ArtRingChart
|
||||
:data="[
|
||||
{ value: 30, name: '分类A' },
|
||||
{ value: 25, name: '分类B' },
|
||||
{ value: 45, name: '分类C' }
|
||||
]"
|
||||
:color="['#4C87F3', '#93F1B4', '#8BD8FC']"
|
||||
/>
|
||||
</div>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :md="12" :lg="8">
|
||||
<div class="card art-custom-card">
|
||||
<div class="card-header">
|
||||
<span>饼图</span>
|
||||
</div>
|
||||
<ArtRingChart
|
||||
:data="[
|
||||
{ value: 30, name: '分类A' },
|
||||
{ value: 25, name: '分类B' },
|
||||
{ value: 45, name: '分类C' }
|
||||
]"
|
||||
:color="['#4C87F3', '#93F1B4', '#8BD8FC']"
|
||||
:radius="['0%', '80%']"
|
||||
/>
|
||||
</div>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :md="12" :lg="8">
|
||||
<div class="card art-custom-card">
|
||||
<div class="card-header">
|
||||
<span>k线图</span>
|
||||
</div>
|
||||
<ArtKLineChart
|
||||
:data="[
|
||||
{ time: '2024-01-01', open: 20, close: 23, high: 25, low: 18 },
|
||||
{ time: '2024-01-02', open: 23, close: 21, high: 24, low: 20 },
|
||||
{ time: '2024-01-03', open: 21, close: 25, high: 26, low: 21 }
|
||||
]"
|
||||
/>
|
||||
</div>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :md="12" :lg="8">
|
||||
<div class="card art-custom-card">
|
||||
<div class="card-header">
|
||||
<span>雷达图</span>
|
||||
</div>
|
||||
<ArtRadarChart
|
||||
:indicator="[
|
||||
{ name: '销售', max: 100 },
|
||||
{ name: '管理', max: 100 },
|
||||
{ name: '技术', max: 100 },
|
||||
{ name: '客服', max: 100 },
|
||||
{ name: '开发', max: 100 }
|
||||
]"
|
||||
:data="[
|
||||
{
|
||||
name: '预算分配',
|
||||
value: [80, 70, 90, 85, 75]
|
||||
},
|
||||
{
|
||||
name: '实际开销',
|
||||
value: [70, 75, 85, 80, 70]
|
||||
}
|
||||
]"
|
||||
:colors="['#8BD8FC', '#409EFF']"
|
||||
/>
|
||||
</div>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :md="12" :lg="8">
|
||||
<div class="card art-custom-card">
|
||||
<div class="card-header">
|
||||
<span>柱状图(水平)</span>
|
||||
</div>
|
||||
<ArtHBarChart
|
||||
:data="[50, 80, 120, 90, 60]"
|
||||
:xAxisData="['产品A', '产品B', '产品C', '产品D', '产品E']"
|
||||
/>
|
||||
</div>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.charts {
|
||||
padding-top: 20px;
|
||||
|
||||
.page-title {
|
||||
margin: 20px 0 15px;
|
||||
font-size: 22px;
|
||||
font-weight: 500;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 20px;
|
||||
background-color: var(--art-main-bg-color);
|
||||
border-radius: var(--custom-radius);
|
||||
|
||||
.card-header {
|
||||
padding-bottom: 15px;
|
||||
|
||||
span {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-col {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
771
src/views/template/chat/index.vue
Normal file
771
src/views/template/chat/index.vue
Normal file
@@ -0,0 +1,771 @@
|
||||
<template>
|
||||
<div class="chat" :style="{ height: containerMinHeight }">
|
||||
<ElRow>
|
||||
<ElCol :span="12">
|
||||
<div class="grid-content ep-bg-purple" />
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<div class="grid-content ep-bg-purple-light" />
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<div class="person-list">
|
||||
<div class="person-item-header">
|
||||
<div class="user-info">
|
||||
<ElAvatar :size="50" :src="selectedPerson?.avatar" />
|
||||
<div class="user-details">
|
||||
<div class="name">{{ selectedPerson?.name }}</div>
|
||||
<div class="email">{{ selectedPerson?.email }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="search-box">
|
||||
<ElInput v-model="searchQuery" placeholder="搜索联系人" prefix-icon="Search" clearable />
|
||||
</div>
|
||||
<ElDropdown trigger="click" placement="bottom-start">
|
||||
<span class="sort-btn">
|
||||
排序方式
|
||||
<ElIcon class="el-icon--right">
|
||||
<arrow-down />
|
||||
</ElIcon>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<ElDropdownMenu>
|
||||
<ElDropdownItem>按时间排序</ElDropdownItem>
|
||||
<ElDropdownItem>按名称排序</ElDropdownItem>
|
||||
<ElDropdownItem>全部标为已读</ElDropdownItem>
|
||||
</ElDropdownMenu>
|
||||
</template>
|
||||
</ElDropdown>
|
||||
</div>
|
||||
<ElScrollbar>
|
||||
<div
|
||||
v-for="item in personList"
|
||||
:key="item.id"
|
||||
class="person-item"
|
||||
:class="{ active: selectedPerson?.id === item.id }"
|
||||
@click="selectPerson(item)"
|
||||
>
|
||||
<div class="avatar-wrapper">
|
||||
<ElAvatar :size="40" :src="item.avatar">
|
||||
{{ item.name.charAt(0) }}
|
||||
</ElAvatar>
|
||||
<div class="status-dot" :class="{ online: item.online }"></div>
|
||||
</div>
|
||||
<div class="person-info">
|
||||
<div class="info-top">
|
||||
<span class="person-name">{{ item.name }}</span>
|
||||
<span class="last-time">{{ item.lastTime }}</span>
|
||||
</div>
|
||||
<div class="info-bottom">
|
||||
<span class="email">{{ item.email }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ElScrollbar>
|
||||
</div>
|
||||
<div class="chat-modal">
|
||||
<div class="header">
|
||||
<div class="header-left">
|
||||
<span class="name">Art Bot</span>
|
||||
<div class="status">
|
||||
<div class="dot" :class="{ online: isOnline, offline: !isOnline }"></div>
|
||||
<span class="status-text">{{ isOnline ? '在线' : '离线' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="btn">
|
||||
<i class="iconfont-sys"></i>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<i class="iconfont-sys"></i>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<i class="iconfont-sys"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chat-container">
|
||||
<!-- 聊天消息区域 -->
|
||||
<div class="chat-messages" ref="messageContainer">
|
||||
<template v-for="(message, index) in messages" :key="index">
|
||||
<div :class="['message-item', message.isMe ? 'message-right' : 'message-left']">
|
||||
<ElAvatar :size="32" :src="message.avatar" class="message-avatar" />
|
||||
<div class="message-content">
|
||||
<div class="message-info">
|
||||
<span class="sender-name">{{ message.sender }}</span>
|
||||
<span class="message-time">{{ message.time }}</span>
|
||||
</div>
|
||||
<div class="message-text">{{ message.content }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- 聊天输入区域 -->
|
||||
<div class="chat-input">
|
||||
<ElInput
|
||||
v-model="messageText"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="输入消息"
|
||||
resize="none"
|
||||
@keyup.enter.prevent="sendMessage"
|
||||
>
|
||||
<template #append>
|
||||
<div class="input-actions">
|
||||
<ElButton :icon="Paperclip" circle plain />
|
||||
<ElButton :icon="Picture" circle plain />
|
||||
<ElButton type="primary" @click="sendMessage" v-ripple>发送</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElInput>
|
||||
<div class="chat-input-actions">
|
||||
<div class="left">
|
||||
<i class="iconfont-sys"></i>
|
||||
<i class="iconfont-sys"></i>
|
||||
</div>
|
||||
<ElButton type="primary" @click="sendMessage" v-ripple>发送</ElButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { Picture, Paperclip } from '@element-plus/icons-vue'
|
||||
import { mittBus } from '@/utils/sys'
|
||||
import meAvatar from '@/assets/img/avatar/avatar5.webp'
|
||||
import aiAvatar from '@/assets/img/avatar/avatar10.webp'
|
||||
import avatar2 from '@/assets/img/avatar/avatar2.webp'
|
||||
import avatar3 from '@/assets/img/avatar/avatar3.webp'
|
||||
import avatar4 from '@/assets/img/avatar/avatar4.webp'
|
||||
import avatar5 from '@/assets/img/avatar/avatar5.webp'
|
||||
import avatar6 from '@/assets/img/avatar/avatar6.webp'
|
||||
import avatar7 from '@/assets/img/avatar/avatar7.webp'
|
||||
import avatar8 from '@/assets/img/avatar/avatar8.webp'
|
||||
import avatar9 from '@/assets/img/avatar/avatar9.webp'
|
||||
import avatar10 from '@/assets/img/avatar/avatar10.webp'
|
||||
import { useCommon } from '@/composables/useCommon'
|
||||
|
||||
const { containerMinHeight } = useCommon()
|
||||
|
||||
const searchQuery = ref('')
|
||||
|
||||
// 抽屉显示状态
|
||||
const isDrawerVisible = ref(false)
|
||||
// 是否在线
|
||||
const isOnline = ref(true)
|
||||
|
||||
interface Person {
|
||||
id: number
|
||||
name: string
|
||||
email: string
|
||||
avatar: string
|
||||
online?: boolean
|
||||
lastTime: string
|
||||
unread?: number
|
||||
}
|
||||
|
||||
const selectedPerson = ref<Person | null>(null)
|
||||
|
||||
const personList = ref<Person[]>([
|
||||
{
|
||||
id: 1,
|
||||
name: '梅洛迪·梅西',
|
||||
email: 'melody@altbox.com',
|
||||
avatar: meAvatar,
|
||||
online: true,
|
||||
lastTime: '20小时前',
|
||||
unread: 0
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '马克·史密斯',
|
||||
email: 'max@kt.com',
|
||||
avatar: avatar2,
|
||||
online: true,
|
||||
lastTime: '2周前',
|
||||
unread: 6
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '肖恩·宾',
|
||||
email: 'sean@dellito.com',
|
||||
avatar: avatar3,
|
||||
online: false,
|
||||
lastTime: '5小时前',
|
||||
unread: 5
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: '爱丽丝·约翰逊',
|
||||
email: 'alice@domain.com',
|
||||
avatar: avatar4,
|
||||
online: true,
|
||||
lastTime: '1小时前',
|
||||
unread: 2
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: '鲍勃·布朗',
|
||||
email: 'bob@domain.com',
|
||||
avatar: avatar5,
|
||||
online: false,
|
||||
lastTime: '3天前',
|
||||
unread: 1
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: '查理·戴维斯',
|
||||
email: 'charlie@domain.com',
|
||||
avatar: avatar6,
|
||||
online: true,
|
||||
lastTime: '10分钟前',
|
||||
unread: 0
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: '戴安娜·普林斯',
|
||||
email: 'diana@domain.com',
|
||||
avatar: avatar7,
|
||||
online: true,
|
||||
lastTime: '15分钟前',
|
||||
unread: 3
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: '伊桑·亨特',
|
||||
email: 'ethan@domain.com',
|
||||
avatar: avatar8,
|
||||
online: true,
|
||||
lastTime: '5分钟前',
|
||||
unread: 0
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: '杰西卡·琼斯',
|
||||
email: 'jessica@domain.com',
|
||||
avatar: avatar9,
|
||||
online: false,
|
||||
lastTime: '1天前',
|
||||
unread: 4
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: '彼得·帕克',
|
||||
email: 'peter@domain.com',
|
||||
avatar: avatar10,
|
||||
online: true,
|
||||
lastTime: '2小时前',
|
||||
unread: 1
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: '克拉克·肯特',
|
||||
email: 'clark@domain.com',
|
||||
avatar: avatar3,
|
||||
online: true,
|
||||
lastTime: '30分钟前',
|
||||
unread: 2
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: '布鲁斯·韦恩',
|
||||
email: 'bruce@domain.com',
|
||||
avatar: avatar5,
|
||||
online: false,
|
||||
lastTime: '3天前',
|
||||
unread: 0
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
name: '韦德·威尔逊',
|
||||
email: 'wade@domain.com',
|
||||
avatar: avatar6,
|
||||
online: true,
|
||||
lastTime: '10分钟前',
|
||||
unread: 5
|
||||
}
|
||||
])
|
||||
|
||||
const selectPerson = (person: Person) => {
|
||||
selectedPerson.value = person
|
||||
}
|
||||
|
||||
// 消息相关数据
|
||||
const messageText = ref('')
|
||||
const messages = ref([
|
||||
{
|
||||
id: 1,
|
||||
sender: 'Art Bot',
|
||||
content: '你好!我是你的AI助手,有什么我可以帮你的吗?',
|
||||
time: '10:00',
|
||||
isMe: false,
|
||||
avatar: aiAvatar
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
sender: 'Ricky',
|
||||
content: '我想了解一下系统的使用方法。',
|
||||
time: '10:01',
|
||||
isMe: true,
|
||||
avatar: meAvatar
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
sender: 'Art Bot',
|
||||
content: '好的,我来为您介绍系统的主要功能。首先,您可以通过左侧菜单访问不同的功能模块...',
|
||||
time: '10:02',
|
||||
isMe: false,
|
||||
avatar: aiAvatar
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
sender: 'Ricky',
|
||||
content: '听起来很不错,能具体讲讲数据分析部分吗?',
|
||||
time: '10:05',
|
||||
isMe: true,
|
||||
avatar: meAvatar
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
sender: 'Art Bot',
|
||||
content: '当然可以。数据分析模块可以帮助您实时监控关键指标,并生成详细的报表...',
|
||||
time: '10:06',
|
||||
isMe: false,
|
||||
avatar: aiAvatar
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
sender: 'Ricky',
|
||||
content: '太好了,那我如何开始使用呢?',
|
||||
time: '10:08',
|
||||
isMe: true,
|
||||
avatar: meAvatar
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
sender: 'Art Bot',
|
||||
content: '您可以先创建一个项目,然后在项目中添加相关的数据源,系统会自动进行分析。',
|
||||
time: '10:09',
|
||||
isMe: false,
|
||||
avatar: aiAvatar
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
sender: 'Ricky',
|
||||
content: '明白了,谢谢你的帮助!',
|
||||
time: '10:10',
|
||||
isMe: true,
|
||||
avatar: meAvatar
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
sender: 'Art Bot',
|
||||
content: '不客气,有任何问题随时联系我。',
|
||||
time: '10:11',
|
||||
isMe: false,
|
||||
avatar: aiAvatar
|
||||
}
|
||||
])
|
||||
|
||||
const messageId = ref(10) // 用于生成唯一的消息ID
|
||||
|
||||
const userAvatar = ref(meAvatar) // 使用导入的头像
|
||||
|
||||
// 发送消息
|
||||
const sendMessage = () => {
|
||||
const text = messageText.value.trim()
|
||||
if (!text) return
|
||||
|
||||
messages.value.push({
|
||||
id: messageId.value++,
|
||||
sender: 'Ricky',
|
||||
content: text,
|
||||
time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
|
||||
isMe: true,
|
||||
avatar: userAvatar.value
|
||||
})
|
||||
|
||||
messageText.value = ''
|
||||
scrollToBottom()
|
||||
}
|
||||
|
||||
// 滚动到底部
|
||||
const messageContainer = ref<HTMLElement | null>(null)
|
||||
const scrollToBottom = () => {
|
||||
setTimeout(() => {
|
||||
if (messageContainer.value) {
|
||||
messageContainer.value.scrollTop = messageContainer.value.scrollHeight
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
|
||||
const openChat = () => {
|
||||
isDrawerVisible.value = true
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
scrollToBottom()
|
||||
mittBus.on('openChat', openChat)
|
||||
|
||||
selectedPerson.value = personList.value[0]
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.chat-modal {
|
||||
.el-overlay {
|
||||
background-color: rgb(0 0 0 / 20%) !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.chat {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
background-color: var(--art-main-bg-color);
|
||||
border: 1px solid var(--art-border-color);
|
||||
border-radius: 10px;
|
||||
|
||||
.person-list {
|
||||
box-sizing: border-box;
|
||||
width: 360px;
|
||||
height: 100%;
|
||||
padding: 20px;
|
||||
border-right: 1px solid var(--art-border-color);
|
||||
|
||||
.person-item-header {
|
||||
padding-bottom: 20px;
|
||||
|
||||
.user-info {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
|
||||
.user-details {
|
||||
.name {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: var(--art-gray-900);
|
||||
}
|
||||
|
||||
.email {
|
||||
margin-top: 4px;
|
||||
font-size: 13px;
|
||||
color: var(--art-gray-500);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-box {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.sort-btn {
|
||||
margin-top: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.person-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 12px;
|
||||
cursor: pointer;
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover,
|
||||
&.active {
|
||||
background-color: var(--el-fill-color-light);
|
||||
}
|
||||
|
||||
.avatar-wrapper {
|
||||
position: relative;
|
||||
margin-right: 12px;
|
||||
|
||||
.status-dot {
|
||||
position: absolute;
|
||||
right: 1px;
|
||||
bottom: 1px;
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
background-color: var(--el-color-error);
|
||||
border-radius: 50%;
|
||||
|
||||
&.online {
|
||||
background-color: var(--el-color-success);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.person-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
.info-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 4px;
|
||||
|
||||
.person-name {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
|
||||
.last-time {
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.info-bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.email {
|
||||
overflow: hidden;
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.unread-badge {
|
||||
:deep(.el-badge__content) {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chat-modal {
|
||||
box-sizing: border-box;
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.header-left {
|
||||
.name {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.status {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
margin-top: 6px;
|
||||
|
||||
.dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
|
||||
&.online {
|
||||
background-color: var(--el-color-success);
|
||||
}
|
||||
|
||||
&.offline {
|
||||
background-color: var(--el-color-danger);
|
||||
}
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-size: 12px;
|
||||
color: var(--art-gray-600);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header-right {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
|
||||
.btn {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
line-height: 42px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
transition: background-color 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--art-gray-200);
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 20px;
|
||||
color: var(--art-text-gray-700);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chat-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: calc(100% - 85px);
|
||||
|
||||
.chat-messages {
|
||||
flex: 1;
|
||||
padding: 30px 16px;
|
||||
overflow-y: auto;
|
||||
border-top: 1px solid var(--el-border-color-lighter);
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 5px !important;
|
||||
}
|
||||
|
||||
.message-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 8px;
|
||||
align-items: flex-start;
|
||||
width: 100%;
|
||||
margin-bottom: 30px;
|
||||
|
||||
.message-text {
|
||||
font-size: 14px;
|
||||
color: var(--art-gray-900);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
&.message-left {
|
||||
justify-content: flex-start;
|
||||
|
||||
.message-content {
|
||||
align-items: flex-start;
|
||||
|
||||
.message-info {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.message-text {
|
||||
background-color: var(--art-gray-200);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.message-right {
|
||||
flex-direction: row-reverse;
|
||||
|
||||
.message-content {
|
||||
align-items: flex-end;
|
||||
|
||||
.message-info {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
.message-text {
|
||||
background-color: #e9f3ff;
|
||||
background-color: rgb(var(--art-bg-secondary));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.message-avatar {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-width: 70%;
|
||||
|
||||
.message-info {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 4px;
|
||||
font-size: 12px;
|
||||
|
||||
.message-time {
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
.sender-name {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.message-text {
|
||||
padding: 10px 14px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chat-input {
|
||||
padding: 16px; // 增加填充以提升输入区域的布局
|
||||
|
||||
.input-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.chat-input-actions {
|
||||
display: flex;
|
||||
align-items: center; // 修正为单数
|
||||
justify-content: space-between;
|
||||
margin-top: 12px;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
i {
|
||||
margin-right: 20px;
|
||||
font-size: 16px;
|
||||
color: var(--art-gray-500);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
// 确保发送按钮与输入框对齐
|
||||
el-button {
|
||||
min-width: 80px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: $device-ipad-pro) {
|
||||
.chat {
|
||||
flex-direction: column;
|
||||
|
||||
.person-list {
|
||||
width: 100%;
|
||||
height: 170px;
|
||||
border-right: none;
|
||||
|
||||
.person-item-header {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-modal {
|
||||
height: calc(70% - 30px);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
22
src/views/template/map/index.vue
Normal file
22
src/views/template/map/index.vue
Normal file
@@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<div class="page-content" v-loading="loading" element-loading-text="加载中...">
|
||||
<ArtMapChart @onRenderComplete="onLoaded" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
const loading = ref(true)
|
||||
const onLoaded = () => {
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
const ArtMapChart = defineAsyncComponent(() => import('@/components/core/charts/ArtMapChart.vue'))
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page-content {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
278
src/views/template/pricing/index.vue
Normal file
278
src/views/template/pricing/index.vue
Normal file
@@ -0,0 +1,278 @@
|
||||
<template>
|
||||
<div class="pricing-container">
|
||||
<div class="pricing-header">
|
||||
<h1 class="title">超过 53,476 位信赖的开发者</h1>
|
||||
<h2 class="subtitle">以及众多科技巨头的选择</h2>
|
||||
</div>
|
||||
|
||||
<div class="pricing-cards">
|
||||
<ElRow :gutter="20" justify="center">
|
||||
<ElCol v-for="plan in pricingPlans" :key="plan.type" :xs="24" :sm="12" :md="6">
|
||||
<ElCard class="pricing-card" :class="{ popular: plan.isPopular }" shadow="never">
|
||||
<div class="card-header">
|
||||
<h3>{{ plan.title }}</h3>
|
||||
<p class="description">{{ plan.description }}</p>
|
||||
<div class="price">
|
||||
<span class="amount">¥{{ plan.price }}</span>
|
||||
<span class="period">/一次性付款</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="features">
|
||||
<div v-for="(feature, index) in plan.features" :key="index" class="feature-item">
|
||||
<ElIcon :class="feature.available ? 'available' : 'unavailable'">
|
||||
<Check v-if="feature.available" />
|
||||
<Close v-else />
|
||||
</ElIcon>
|
||||
<span>{{ feature.text }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-footer">
|
||||
<ElButton type="primary" class="purchase-btn" v-ripple>立即购买</ElButton>
|
||||
</div>
|
||||
</ElCard>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { Check, Close } from '@element-plus/icons-vue'
|
||||
|
||||
interface Feature {
|
||||
text: string
|
||||
available: boolean
|
||||
}
|
||||
|
||||
interface PricingPlan {
|
||||
type: string
|
||||
title: string
|
||||
description: string
|
||||
price: number
|
||||
isPopular: boolean
|
||||
features: Feature[]
|
||||
}
|
||||
|
||||
const pricingPlans = ref<PricingPlan[]>([
|
||||
{
|
||||
type: 'single',
|
||||
title: '单次使用版',
|
||||
description: '适用于单个最终产品,最终用户无需付费。',
|
||||
price: 349,
|
||||
isPopular: false,
|
||||
features: [
|
||||
{ text: '完整源代码', available: true },
|
||||
{ text: '技术文档', available: true },
|
||||
{ text: 'SaaS应用授权', available: false },
|
||||
{ text: '单个项目使用', available: true },
|
||||
{ text: '一年技术支持', available: true },
|
||||
{ text: '一年免费更新', available: true }
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'multiple',
|
||||
title: '多次使用版',
|
||||
description: '适用于无限个最终产品,最终用户无需付费。',
|
||||
price: 629,
|
||||
isPopular: false,
|
||||
features: [
|
||||
{ text: '完整源代码', available: true },
|
||||
{ text: '技术文档', available: true },
|
||||
{ text: 'SaaS应用授权', available: false },
|
||||
{ text: '无限项目使用', available: true },
|
||||
{ text: '一年技术支持', available: true },
|
||||
{ text: '一年免费更新', available: true }
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'extended',
|
||||
title: '扩展授权版',
|
||||
description: '适用于单个最终产品,最终用户需要付费。',
|
||||
price: 2099,
|
||||
isPopular: false,
|
||||
features: [
|
||||
{ text: '完整源代码', available: true },
|
||||
{ text: '技术文档', available: true },
|
||||
{ text: 'SaaS应用授权', available: true },
|
||||
{ text: '单个项目使用', available: true },
|
||||
{ text: '一年技术支持', available: true },
|
||||
{ text: '一年免费更新', available: true }
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'unlimited',
|
||||
title: '无限授权版',
|
||||
description: '适用于无限个最终产品,最终用户需要付费。',
|
||||
price: 3499,
|
||||
isPopular: false,
|
||||
features: [
|
||||
{ text: '完整源代码', available: true },
|
||||
{ text: '技术文档', available: true },
|
||||
{ text: 'SaaS应用授权', available: true },
|
||||
{ text: '无限项目使用', available: true },
|
||||
{ text: '一年技术支持', available: true },
|
||||
{ text: '一年免费更新', available: true }
|
||||
]
|
||||
}
|
||||
])
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.pricing-container {
|
||||
padding: 5rem 1rem !important;
|
||||
background-color: transparent !important;
|
||||
border: none !important;
|
||||
|
||||
.pricing-header {
|
||||
margin-bottom: 40px;
|
||||
text-align: center;
|
||||
|
||||
.title {
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 2.5rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 1.4rem;
|
||||
font-weight: 400;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.pricing-cards {
|
||||
margin-top: 80px;
|
||||
|
||||
.el-col {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.pricing-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
border-radius: 10px;
|
||||
|
||||
&.popular {
|
||||
position: relative;
|
||||
border: 2px solid var(--el-color-primary);
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
padding: 2px 8px;
|
||||
font-size: 12px;
|
||||
color: var(--el-color-primary);
|
||||
content: '热门';
|
||||
background-color: var(--el-color-primary-light-9);
|
||||
border-radius: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-header {
|
||||
margin-bottom: 20px;
|
||||
|
||||
h3 {
|
||||
margin-bottom: 10px;
|
||||
font-size: 1.3rem;
|
||||
color: var(--art-text-gray-900) !important;
|
||||
}
|
||||
|
||||
.description {
|
||||
display: -webkit-box;
|
||||
height: 40px;
|
||||
padding-bottom: 20px;
|
||||
margin-bottom: 20px;
|
||||
overflow: hidden;
|
||||
font-size: 14px;
|
||||
color: var(--art-text-gray-600);
|
||||
text-overflow: ellipsis;
|
||||
border-bottom: 1px solid var(--art-border-color);
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.price {
|
||||
margin-top: 30px;
|
||||
|
||||
.amount {
|
||||
font-size: 1.8rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.period {
|
||||
margin-left: 10px;
|
||||
font-size: 14px;
|
||||
color: var(--art-text-gray-600);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.features {
|
||||
flex-grow: 1;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.feature-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
font-size: 14px;
|
||||
|
||||
.el-icon {
|
||||
margin-right: 10px;
|
||||
|
||||
&.available {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
&.unavailable {
|
||||
color: var(--el-color-danger);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
margin-top: auto;
|
||||
text-align: center;
|
||||
|
||||
.purchase-btn {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: $device-notebook) {
|
||||
.pricing-container {
|
||||
padding: 2rem 0 !important;
|
||||
|
||||
.pricing-cards {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: $device-phone) {
|
||||
.pricing-container {
|
||||
.pricing-header {
|
||||
.title {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.el-col {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user