mirror of https://gitee.com/xiaonuobase/snowy
【新增】轮播图、通知公告、业务首页前端新增,其次增加多个首页卡片
parent
94eeb52cd3
commit
da0d57b09c
|
@ -0,0 +1,24 @@
|
|||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/biz/index/` + url, ...arg)
|
||||
|
||||
/**
|
||||
* 业务主页Api接口管理器
|
||||
*
|
||||
* @author yubaoshan
|
||||
* @date 2024/07/11 14:46
|
||||
**/
|
||||
export default {
|
||||
// 获取轮播图列表
|
||||
bizIndexSlideshowList(data) {
|
||||
return request('slideshow/list', data, 'get')
|
||||
},
|
||||
// 获取通知公告列表
|
||||
bizIndexNoticeList(data) {
|
||||
return request('notice/list', data, 'get')
|
||||
},
|
||||
// 获取通知公告详情
|
||||
bizIndexNoticeDetail(data) {
|
||||
return request('notice/detail', data, 'get')
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/biz/notice/` + url, ...arg)
|
||||
|
||||
/**
|
||||
* 通知公告Api接口管理器
|
||||
*
|
||||
* @author yubaoshan
|
||||
* @date 2024/07/11 14:46
|
||||
**/
|
||||
export default {
|
||||
// 获取通知公告分页
|
||||
bizNoticePage(data) {
|
||||
return request('page', data, 'get')
|
||||
},
|
||||
// 提交通知公告表单 edit为true时为编辑,默认为新增
|
||||
bizNoticeSubmitForm(data, edit = false) {
|
||||
return request(edit ? 'edit' : 'add', data)
|
||||
},
|
||||
// 删除通知公告
|
||||
bizNoticeDelete(data) {
|
||||
return request('delete', data)
|
||||
},
|
||||
// 获取通知公告详情
|
||||
bizNoticeDetail(data) {
|
||||
return request('detail', data, 'get')
|
||||
},
|
||||
// 禁用通知公告
|
||||
bizNoticeDisableStatus(data) {
|
||||
return request('disableStatus', data)
|
||||
},
|
||||
// 启用通知公告
|
||||
bizNoticeEnableStatus(data) {
|
||||
return request('enableStatus', data)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/dev/slideshow/` + url, ...arg)
|
||||
|
||||
/**
|
||||
* 轮播图Api接口管理器
|
||||
*
|
||||
* @author yubaoshan
|
||||
* @date 2024/07/13 00:31
|
||||
**/
|
||||
export default {
|
||||
// 获取轮播图分页
|
||||
devSlideshowPage(data) {
|
||||
return request('page', data, 'get')
|
||||
},
|
||||
// 提交轮播图表单 edit为true时为编辑,默认为新增
|
||||
devSlideshowSubmitForm(data, edit = false) {
|
||||
return request(edit ? 'edit' : 'add', data)
|
||||
},
|
||||
// 删除轮播图
|
||||
devSlideshowDelete(data) {
|
||||
return request('delete', data)
|
||||
},
|
||||
// 禁用轮播图
|
||||
devSlideshowDisableStatus(data) {
|
||||
return request('disableStatus', data)
|
||||
},
|
||||
// 启用轮播图
|
||||
devSlideshowEnableStatus(data) {
|
||||
return request('enableStatus', data)
|
||||
}
|
||||
}
|
|
@ -49,5 +49,17 @@ export default {
|
|||
// 获取当前用户操作日志列表
|
||||
indexOpLogList(data) {
|
||||
return request('opLog/list', data, 'get')
|
||||
},
|
||||
// 获取基础系统业务数据
|
||||
indexBizDataCount(data) {
|
||||
return request('bizDataCount', data, 'get')
|
||||
},
|
||||
// 获取运维一览数据
|
||||
indexOpDataCount(data) {
|
||||
return request('opDataCount', data, 'get')
|
||||
},
|
||||
// 获取基础工具数据
|
||||
indexToolDataCount(data) {
|
||||
return request('toolDataCount', data, 'get')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<a-card title="站内信" :bordered="false" :bodyStyle="miniMessageBodyStyle">
|
||||
<a-card title="站内信" :bordered="false">
|
||||
<template #extra><a @click="leaveFor('/usercenter')">更多</a></template>
|
||||
<div class="index-message-list">
|
||||
<a-list :data-source="messageList" size="small" :loading="miniMessageLoading">
|
||||
|
@ -125,4 +125,7 @@
|
|||
.index-message-list {
|
||||
overflow: auto;
|
||||
}
|
||||
:deep(.ant-card-body) {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,85 @@
|
|||
<template>
|
||||
<xn-form-container
|
||||
title="详情"
|
||||
:width="1000"
|
||||
v-model:open="open"
|
||||
:destroy-on-close="true"
|
||||
@close="onClose"
|
||||
>
|
||||
<a-descriptions bordered>
|
||||
<a-descriptions-item label="标题">{{formData.title}}</a-descriptions-item>
|
||||
<a-descriptions-item label="类型">
|
||||
<a-tag :bordered="false" color="success" v-if="formData.type === 'NOTICE'">
|
||||
{{ $TOOL.dictTypeData('BIZ_NOTICE_TYPE', formData.type) }}
|
||||
</a-tag>
|
||||
<a-tag :bordered="false" color="processing" v-else-if="formData.type === 'ANNOUNCEMENT'">
|
||||
{{ $TOOL.dictTypeData('BIZ_NOTICE_TYPE', formData.type) }}
|
||||
</a-tag>
|
||||
<a-tag :bordered="false" color="warning" v-else-if="formData.type === 'WARNING'">
|
||||
{{ $TOOL.dictTypeData('BIZ_NOTICE_TYPE', formData.type) }}
|
||||
</a-tag>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="封面图">
|
||||
<div v-if="formData.image">
|
||||
<a-image :src="formData.image" style="width: 100px; height: 50px;margin-bottom: -10px;margin-top: -10px;" />
|
||||
</div>
|
||||
<span v-else>未上传</span>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="内容"><div v-html="formData.content"></div></a-descriptions-item>
|
||||
</a-descriptions>
|
||||
<a-descriptions bordered :column="2" class="mt-2">
|
||||
<a-descriptions-item label="摘要">{{ formData.digest }}</a-descriptions-item>
|
||||
<a-descriptions-item label="备注"><span>{{ formData.remark }}</span></a-descriptions-item>
|
||||
<a-descriptions-item label="排序"><span>{{ formData.sortCode }}</span></a-descriptions-item>
|
||||
<a-descriptions-item label="发布位置">
|
||||
<div v-if="formData.place">
|
||||
<a-tag v-for="textValue in JSON.parse(formData.place)" :key="textValue" color="processing">
|
||||
{{ $TOOL.dictTypeData('BIZ_NOTICE_PLACE', textValue) }}
|
||||
</a-tag>
|
||||
</div>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="创建人"><span>{{ formData.createUserName }}</span></a-descriptions-item>
|
||||
<a-descriptions-item label="创建时间"><span>{{ formData.createTime }}</span></a-descriptions-item>
|
||||
<a-descriptions-item label="修改人"><span>{{ formData.updateUserName }}</span></a-descriptions-item>
|
||||
<a-descriptions-item label="修改时间"><span>{{ formData.updateTime }}</span></a-descriptions-item>
|
||||
</a-descriptions>
|
||||
<template #footer>
|
||||
<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
|
||||
<a-button type="primary" @click="onClose" :loading="submitLoading">确定</a-button>
|
||||
</template>
|
||||
</xn-form-container>
|
||||
</template>
|
||||
|
||||
<script setup name="bizNoticeDetail">
|
||||
import bizIndexApi from '@/api/biz/bizIndexApi'
|
||||
import { message } from 'ant-design-vue'
|
||||
// 抽屉状态
|
||||
const open = ref(false)
|
||||
const emit = defineEmits({ successful: null })
|
||||
// 表单数据
|
||||
const formData = ref({})
|
||||
const submitLoading = ref(false)
|
||||
// 打开抽屉
|
||||
const onOpen = (id) => {
|
||||
open.value = true
|
||||
if (id) {
|
||||
const param = {
|
||||
id: id
|
||||
}
|
||||
bizIndexApi.bizIndexNoticeDetail(param).then((data) => {
|
||||
formData.value = Object.assign({}, data)
|
||||
})
|
||||
} else {
|
||||
message.warning('未查到该信息')
|
||||
}
|
||||
}
|
||||
// 关闭抽屉
|
||||
const onClose = () => {
|
||||
formData.value = {}
|
||||
open.value = false
|
||||
}
|
||||
// 抛出函数
|
||||
defineExpose({
|
||||
onOpen
|
||||
})
|
||||
</script>
|
|
@ -0,0 +1,79 @@
|
|||
<template>
|
||||
<a-card :bordered="false" :title="title">
|
||||
<template #extra><a @click="leaveFor('/biz/notice')">更多</a></template>
|
||||
<a-table
|
||||
:columns="columns"
|
||||
:data-source="dataSource"
|
||||
size="small"
|
||||
:pagination="false"
|
||||
:showHeader="false"
|
||||
:scroll="{ y: 260 }"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'title'">
|
||||
<a-popover>
|
||||
<template #content>
|
||||
<a-flex>
|
||||
<img v-if="record.image" :src="record.image" style="width: 100px; height: 70px" />
|
||||
<div style="padding-left: 10px; width: 300px; max-height: 100px; text-overflow: ellipsis">
|
||||
{{ record.digest }}
|
||||
<div style="float: right; padding-right: 10px">
|
||||
<a-button type="primary" size="small" @click="detailRef.onOpen(record.id)">详情</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</a-flex>
|
||||
</template>
|
||||
<div v-if="record.type === 'NOTICE'">
|
||||
<a-badge color="green" />
|
||||
{{ record.title }}
|
||||
</div>
|
||||
<div v-if="record.type === 'ANNOUNCEMENT'">
|
||||
<a-badge color="blue" />
|
||||
{{ record.title }}
|
||||
</div>
|
||||
<div v-if="record.type === 'WARNING'">
|
||||
<a-badge color="orange" />
|
||||
{{ record.title }}
|
||||
</div>
|
||||
</a-popover>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
<detail ref="detailRef" />
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script setup name="bizIndexNoticeCard">
|
||||
import bizIndexApi from '@/api/biz/bizIndexApi'
|
||||
import router from '@/router'
|
||||
import Detail from './detail.vue'
|
||||
const detailRef = ref()
|
||||
const columns = [
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'title',
|
||||
align: 'left'
|
||||
},
|
||||
{
|
||||
title: '时间',
|
||||
dataIndex: 'createTime',
|
||||
align: 'right',
|
||||
width: '150px'
|
||||
}
|
||||
]
|
||||
const title = ref('通知公告')
|
||||
const dataSource = ref([])
|
||||
bizIndexApi.bizIndexNoticeList().then((data) => {
|
||||
dataSource.value = data
|
||||
})
|
||||
const leaveFor = (url = '/') => {
|
||||
router.replace({
|
||||
path: url
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
:deep(.ant-card-body) {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
</style>
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div>
|
||||
<a-card :title="title" :bordered="false" class="mt-2">
|
||||
<a-calendar v-model:value="calendarValue" :fullscreen="false" @select="onPanelSelect" />
|
||||
<a-card :bordered="false">
|
||||
<a-timeline>
|
||||
|
@ -29,7 +29,7 @@
|
|||
<a-button type="primary" :loading="submitLoading" @click="onSubmit">保存</a-button>
|
||||
</template>
|
||||
</xn-form-container>
|
||||
</div>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script setup name="schedule">
|
||||
|
@ -42,6 +42,7 @@
|
|||
import { required } from '@/utils/formRules'
|
||||
import { onMounted } from 'vue'
|
||||
import indexApi from '@/api/sys/indexApi'
|
||||
const title = ref('我的日程')
|
||||
const scheduleList = ref([])
|
||||
const calendarValue = ref(dayjs())
|
||||
|
||||
|
@ -120,6 +121,12 @@
|
|||
<style scoped>
|
||||
.add-schedule {
|
||||
cursor: pointer;
|
||||
margin-top: -10px;
|
||||
/*margin-top: -10px;*/
|
||||
}
|
||||
:deep(.ant-card-body) {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
:deep(.ant-timeline-item-content) {
|
||||
min-height: 10px !important;
|
||||
}
|
||||
</style>
|
|
@ -1,15 +1,16 @@
|
|||
<template>
|
||||
<a-card :bordered="false">
|
||||
<template #title> 快捷方式 </template>
|
||||
<a-row :gutter="10">
|
||||
<a-col :span="6" :key="shortcut.id" v-for="shortcut in shortcutList" :xs="12" :sm="8" :md="6" :lg="8" :xl="6">
|
||||
<shortcutCard
|
||||
:icon="shortcut.icon ? shortcut.icon : 'menu-outlined'"
|
||||
:label="shortcut.title"
|
||||
@click="leaveFor(shortcut.path)"
|
||||
/>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-card :title="title" :bordered="false">
|
||||
<div class="card-div">
|
||||
<a-row :gutter="10">
|
||||
<a-col :span="6" :key="shortcut.id" v-for="shortcut in shortcutList" :xs="12" :sm="8" :md="6" :lg="8" :xl="6">
|
||||
<shortcutCard
|
||||
:icon="shortcut.icon ? shortcut.icon : 'menu-outlined'"
|
||||
:label="shortcut.title"
|
||||
@click="leaveFor(shortcut.path)"
|
||||
/>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
|
@ -19,12 +20,11 @@
|
|||
import ShortcutCard from '@/components/ShortcutCard/index.vue'
|
||||
import { onMounted } from 'vue'
|
||||
const shortcutList = ref([])
|
||||
|
||||
const title = ref('快捷方式')
|
||||
onMounted(() => {
|
||||
// 进来后执行查询
|
||||
getUserLoginWorkbench()
|
||||
})
|
||||
|
||||
const getUserLoginWorkbench = () => {
|
||||
userCenterApi.userLoginWorkbench().then((data) => {
|
||||
if (data) {
|
||||
|
@ -32,7 +32,6 @@
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
const leaveFor = (url = '/') => {
|
||||
router.replace({
|
||||
path: url
|
||||
|
@ -44,4 +43,11 @@
|
|||
.ant-list-item {
|
||||
padding: 8px 0px !important;
|
||||
}
|
||||
.card-div {
|
||||
overflow: scroll;
|
||||
max-height: 260px;
|
||||
}
|
||||
:deep(.ant-card-body) {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,108 @@
|
|||
<template>
|
||||
<a-card :title="title" :bordered="false">
|
||||
<a-carousel class="snowy-right-card-one" autoplay arrows>
|
||||
<template #prevArrow>
|
||||
<div class="custom-slick-arrow" style="left: 10px; z-index: 1">
|
||||
<LeftOutlined />
|
||||
</div>
|
||||
</template>
|
||||
<template #nextArrow>
|
||||
<div class="custom-slick-arrow" style="right: 10px"><RightOutlined /></div>
|
||||
</template>
|
||||
<img
|
||||
v-for="item in slideshowList"
|
||||
:key="item.id"
|
||||
:src="item.image"
|
||||
class="carousel-images"
|
||||
@click="leaveForOpen(item.pathDetails)"
|
||||
/>
|
||||
</a-carousel>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script setup name="carousel">
|
||||
import bizIndexApi from '@/api/biz/bizIndexApi'
|
||||
import { isEmpty, cloneDeep } from 'lodash-es'
|
||||
import router from '@/router'
|
||||
const slideshowList = ref([])
|
||||
const title = ref('')
|
||||
// 外部传来的参数
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
})
|
||||
// 界面加载完后异步查询
|
||||
onMounted(() => {
|
||||
// 获得业务首页轮播图
|
||||
const param = {
|
||||
// 这是字典内维护的该位置
|
||||
place: props.config.options.place ? props.config.options.place : 'BACK_SYS_INDEX'
|
||||
}
|
||||
bizIndexApi.bizIndexSlideshowList(param).then((data) => {
|
||||
slideshowList.value = data
|
||||
})
|
||||
})
|
||||
// URL跟路由的跳转
|
||||
const leaveForOpen = (value) => {
|
||||
if (isEmpty(value)) {
|
||||
return
|
||||
}
|
||||
const detail = cloneDeep(value)
|
||||
let detailObj = {}
|
||||
if (typeof detail !== 'object') {
|
||||
detailObj = JSON.parse(detail)
|
||||
}
|
||||
// json内包含且是开启了点击,否则不处理
|
||||
if (detailObj.whetherToClick && detailObj.whetherToClick === 'ENABLE') {
|
||||
if (detailObj.skipMode && detailObj.skipMode === 'URL') {
|
||||
window.open(detailObj.url)
|
||||
}
|
||||
if (detailObj.skipMode && detailObj.skipMode === 'ROUTER') {
|
||||
router.replace({
|
||||
path: detailObj.url
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.carousel-images {
|
||||
height: 180px;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
.snowy-right-card-one {
|
||||
height: 180px;
|
||||
}
|
||||
.ant-carousel :deep(.slick-slide) {
|
||||
text-align: center;
|
||||
height: 180px;
|
||||
line-height: 150px;
|
||||
background: #364d79;
|
||||
overflow: hidden;
|
||||
}
|
||||
.ant-carousel :deep(.slick-arrow.custom-slick-arrow) {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
font-size: 25px;
|
||||
color: #fff;
|
||||
background-color: rgba(31, 45, 61, 0.11);
|
||||
opacity: 0.3;
|
||||
z-index: 1;
|
||||
}
|
||||
.ant-carousel :deep(.custom-slick-arrow:before) {
|
||||
display: none;
|
||||
}
|
||||
.ant-carousel :deep(.custom-slick-arrow:hover) {
|
||||
opacity: 0.5;
|
||||
}
|
||||
.ant-carousel :deep(.slick-slide h3) {
|
||||
color: #fff;
|
||||
}
|
||||
:deep(.ant-card-body) {
|
||||
padding: 0 !important;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,60 @@
|
|||
<template>
|
||||
<a-card :title="title" :bordered="false">
|
||||
<a-row>
|
||||
<a-col :span="6">
|
||||
<a-statistic :value="dataSource.userCount">
|
||||
<template #title>
|
||||
<user-outlined style="color: #1890ff" />
|
||||
用户数量
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-statistic :value="dataSource.orgCount">
|
||||
<template #title>
|
||||
<cluster-outlined style="color: rgba(229, 159, 18, 0.35)" />
|
||||
组织数量
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-statistic :value="dataSource.positionCount">
|
||||
<template #title>
|
||||
<apartment-outlined style="color: rgba(245, 6, 6, 0.2)" />
|
||||
职位数量
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-statistic :value="dataSource.roleCount">
|
||||
<template #title>
|
||||
<deployment-unit-outlined style="color: #09c755" />
|
||||
角色数量
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script setup name="sysBizDataCard">
|
||||
import indexApi from '@/api/sys/indexApi'
|
||||
const title = ref('业务数据')
|
||||
const dataSource = ref({
|
||||
userCount: 0,
|
||||
roleCount: 0,
|
||||
orgCount: 0,
|
||||
positionCount: 0
|
||||
})
|
||||
onMounted(() => {
|
||||
indexApi.indexBizDataCount().then((data) => {
|
||||
dataSource.value = data
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.ant-card-body) {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,78 @@
|
|||
<template>
|
||||
<a-card :title="title" :bordered="false">
|
||||
<a-row>
|
||||
<a-col :span="4">
|
||||
<a-statistic :value="dataSource.jobCount">
|
||||
<template #title>
|
||||
<field-time-outlined style="color: #ec2c09" />
|
||||
任务调度
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-col>
|
||||
<a-col :span="4">
|
||||
<a-statistic :value="dataSource.sysDictCount">
|
||||
<template #title>
|
||||
<read-outlined style="color: #4b4b4b" />
|
||||
系统字典
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-col>
|
||||
<a-col :span="4">
|
||||
<a-statistic :value="dataSource.bizDictCount">
|
||||
<template #title>
|
||||
<read-outlined style="color: #353779" />
|
||||
业务字典
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-col>
|
||||
<a-col :span="4">
|
||||
<a-statistic :value="dataSource.backUserSessionCount">
|
||||
<template #title>
|
||||
<usergroup-delete-outlined style="color: #3ceecd" />
|
||||
后台在线用户
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-col>
|
||||
<a-col :span="4">
|
||||
<a-statistic :value="dataSource.clientUserSessionCount">
|
||||
<template #title>
|
||||
<UserSwitchOutlined style="color: rgba(229, 159, 18, 0.35)" />
|
||||
前台在线用户
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-col>
|
||||
<a-col :span="4">
|
||||
<a-statistic :value="dataSource.thirdUserCount">
|
||||
<template #title>
|
||||
<team-outlined style="color: #1890ff" />
|
||||
三方用户
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script setup name="sysBizDataCard">
|
||||
import indexApi from '@/api/sys/indexApi'
|
||||
const title = ref('运维一览')
|
||||
const dataSource = ref({
|
||||
jobCount: 0,
|
||||
sysDictCount: 0,
|
||||
bizDictCount: 0,
|
||||
backUserSessionCount: 0,
|
||||
clientUserSessionCount: 0,
|
||||
thirdUserCount: 0
|
||||
})
|
||||
onMounted(() => {
|
||||
indexApi.indexOpDataCount().then((data) => {
|
||||
dataSource.value = data
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.ant-card-body) {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
</style>
|
|
@ -20,14 +20,14 @@
|
|||
const opLogList = ref([])
|
||||
onMounted(() => {
|
||||
// 进来后执行查询
|
||||
seleOpLogList()
|
||||
getOpLogList()
|
||||
})
|
||||
|
||||
// 是否展示更多按钮
|
||||
const displayMore = () => {
|
||||
return userInfo.roleCodeList && userInfo.roleCodeList.toString().indexOf('superAdmin') !== -1
|
||||
}
|
||||
const seleOpLogList = () => {
|
||||
const getOpLogList = () => {
|
||||
indexApi.indexOpLogList().then((data) => {
|
||||
opLogList.value = data
|
||||
})
|
|
@ -0,0 +1,60 @@
|
|||
<template>
|
||||
<a-card :title="title" :bordered="false">
|
||||
<a-row>
|
||||
<a-col :span="12">
|
||||
<a-statistic :value="dataSource.fileCount">
|
||||
<template #title>
|
||||
<FileFilled style="color: #1890ff" />
|
||||
文件
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-statistic :value="dataSource.smsCount">
|
||||
<template #title>
|
||||
<MessageFilled style="color: #07913e" />
|
||||
短信
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-statistic :value="dataSource.emailCount">
|
||||
<template #title>
|
||||
<MailFilled style="color: #fada00" />
|
||||
邮件
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-statistic :value="dataSource.messageCount">
|
||||
<template #title>
|
||||
<NotificationFilled style="color: #fada00" />
|
||||
站内信
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script setup name="sysToolDataCard">
|
||||
import indexApi from '@/api/sys/indexApi'
|
||||
const title = ref('基础工具')
|
||||
const dataSource = ref({
|
||||
fileCount: 0,
|
||||
smsCount: 0,
|
||||
emailCount: 0,
|
||||
messageCount: 0
|
||||
})
|
||||
onMounted(() => {
|
||||
indexApi.indexToolDataCount().then((data) => {
|
||||
dataSource.value = data
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.ant-card-body) {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
</style>
|
|
@ -1,12 +1,8 @@
|
|||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="xn-acrd-line">
|
||||
<div class="xn-card-line">
|
||||
<div class="xn-flex">
|
||||
<a-avatar
|
||||
class="xn-wh60"
|
||||
:src="userInfo.avatar"
|
||||
:size="{ xs: 24, sm: 32, md: 40, lg: 64, xl: 80, xxl: 100 }"
|
||||
/>
|
||||
<a-avatar class="xn-wh60" :src="userInfo.avatar" :size="{ xs: 24, sm: 32, md: 40, lg: 64, xl: 80, xxl: 100 }" />
|
||||
<div class="snowy-index-card-left-one-username">
|
||||
<span>{{ userInfo.name }}</span>
|
||||
<span>{{ userInfo.orgName }} | {{ userInfo.positionName }}</span>
|
||||
|
@ -42,13 +38,13 @@
|
|||
</script>
|
||||
|
||||
<style scoped>
|
||||
.xn-acrd-line {
|
||||
.xn-card-line {
|
||||
display: flex;
|
||||
justify-content: space-between
|
||||
justify-content: space-between;
|
||||
}
|
||||
.xn-wh60 {
|
||||
width: 60px;
|
||||
height: 60px
|
||||
height: 60px;
|
||||
}
|
||||
.snowy-index-card-left-one-username {
|
||||
margin-left: 8px;
|
||||
|
@ -59,11 +55,11 @@
|
|||
.snowy-index-card-left-one-username > span:nth-child(1) {
|
||||
font-weight: 600;
|
||||
margin: 2px;
|
||||
font-size: 18px
|
||||
font-size: 18px;
|
||||
}
|
||||
.snowy-index-card-left-one-username > span:nth-child(2) {
|
||||
color: #6d737b;
|
||||
margin: 2px
|
||||
margin: 2px;
|
||||
}
|
||||
.snowy-index-userinfo-time {
|
||||
margin: 2px;
|
|
@ -0,0 +1,55 @@
|
|||
<template>
|
||||
<a-card :bordered="false" title="周访问量">
|
||||
<div id="visLogChartLine" class="xn-ht200"></div>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script setup name="visLogChart">
|
||||
import logApi from '@/api/dev/logApi'
|
||||
import { Line } from '@antv/g2plot'
|
||||
import { onMounted } from 'vue'
|
||||
|
||||
const seriesKey = 'series'
|
||||
const valueKey = 'value'
|
||||
const processData = (data, yFields, meta) => {
|
||||
const result = []
|
||||
data.forEach((d) => {
|
||||
yFields.forEach((yField) => {
|
||||
const name = meta?.[yField]?.alias || yField
|
||||
result.push({ ...d, [seriesKey]: name, [valueKey]: d[yField] })
|
||||
})
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const lineMeta = {
|
||||
date: {
|
||||
alias: '登录登出周统计'
|
||||
},
|
||||
loginCount: {
|
||||
alias: '登录'
|
||||
},
|
||||
logoutCount: {
|
||||
alias: '登出'
|
||||
}
|
||||
}
|
||||
logApi.logVisLineChartData().then((data) => {
|
||||
const line = new Line('visLogChartLine', {
|
||||
data: processData(data, ['loginCount', 'logoutCount'], lineMeta),
|
||||
padding: 'auto',
|
||||
xField: 'date',
|
||||
yField: valueKey,
|
||||
seriesField: seriesKey,
|
||||
color: ['#1677FF', 'rgb(188, 189, 190)'],
|
||||
appendPadding: [0, 8, 0, 0]
|
||||
})
|
||||
line.render()
|
||||
})
|
||||
})
|
||||
</script>
|
||||
<style scoped>
|
||||
.xn-ht200 {
|
||||
height: 200px;
|
||||
}
|
||||
</style>
|
|
@ -21,14 +21,14 @@
|
|||
const visLogList = ref([])
|
||||
onMounted(() => {
|
||||
// 进来后执行查询
|
||||
seleVisLogList()
|
||||
getVisLogList()
|
||||
})
|
||||
// 是否展示更多按钮
|
||||
const displayMore = () => {
|
||||
return userInfo.roleCodeList && userInfo.roleCodeList.toString().indexOf('superAdmin') !== -1
|
||||
}
|
||||
// 查询数据
|
||||
const seleVisLogList = () => {
|
||||
const getVisLogList = () => {
|
||||
indexApi.indexVisLogList().then((data) => {
|
||||
visLogList.value = data
|
||||
})
|
|
@ -72,6 +72,7 @@
|
|||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 10px;
|
||||
justify-content: center;
|
||||
}
|
||||
.container-tag-icon {
|
||||
font-size: 25px;
|
||||
|
|
|
@ -365,6 +365,8 @@ body,
|
|||
.ant-tabs-dropdown-menu,
|
||||
.xn-table,
|
||||
.selector-table,
|
||||
.card-div,
|
||||
.ant-table-body,
|
||||
|
||||
.admin-ui-main{
|
||||
&::-webkit-scrollbar {
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
<template>
|
||||
<a-row :gutter="10">
|
||||
<!-- 左侧 -->
|
||||
<a-col :span="16">
|
||||
<!-- 人员信息 -->
|
||||
<sys-user-info-card class="mb-2" />
|
||||
<a-row :gutter="10" class="mt-2">
|
||||
<a-col :span="24">
|
||||
<!-- 快捷方式 -->
|
||||
<biz-shortcut-card />
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="10" class="mt-2">
|
||||
<a-col :span="12">
|
||||
<!-- 通知公告 -->
|
||||
<biz-notice-card />
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<!-- 站内信息 -->
|
||||
<biz-mini-message-card />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
<!-- 右侧 -->
|
||||
<a-col :span="8">
|
||||
<!-- 轮播图 -->
|
||||
<biz-slideshow-card :config="slideshowConfig" />
|
||||
<!-- 我的日程 -->
|
||||
<biz-schedule-card />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
|
||||
<script setup name="bizIndex">
|
||||
// 轮播图组件的配置,在业务首页下,获取对应位置的
|
||||
const slideshowConfig = {
|
||||
options: {
|
||||
place: 'BACK_INDEX'
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,85 @@
|
|||
<template>
|
||||
<xn-form-container
|
||||
title="详情"
|
||||
:width="1000"
|
||||
v-model:open="open"
|
||||
:destroy-on-close="true"
|
||||
@close="onClose"
|
||||
>
|
||||
<a-descriptions bordered>
|
||||
<a-descriptions-item label="标题">{{formData.title}}</a-descriptions-item>
|
||||
<a-descriptions-item label="类型">
|
||||
<a-tag :bordered="false" color="success" v-if="formData.type === 'NOTICE'">
|
||||
{{ $TOOL.dictTypeData('BIZ_NOTICE_TYPE', formData.type) }}
|
||||
</a-tag>
|
||||
<a-tag :bordered="false" color="processing" v-else-if="formData.type === 'ANNOUNCEMENT'">
|
||||
{{ $TOOL.dictTypeData('BIZ_NOTICE_TYPE', formData.type) }}
|
||||
</a-tag>
|
||||
<a-tag :bordered="false" color="warning" v-else-if="formData.type === 'WARNING'">
|
||||
{{ $TOOL.dictTypeData('BIZ_NOTICE_TYPE', formData.type) }}
|
||||
</a-tag>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="封面图">
|
||||
<div v-if="formData.image">
|
||||
<a-image :src="formData.image" style="width: 100px; height: 50px;margin-bottom: -10px;margin-top: -10px;" />
|
||||
</div>
|
||||
<span v-else>未上传</span>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="内容"><div v-html="formData.content"></div></a-descriptions-item>
|
||||
</a-descriptions>
|
||||
<a-descriptions bordered :column="2" class="mt-2">
|
||||
<a-descriptions-item label="摘要">{{ formData.digest }}</a-descriptions-item>
|
||||
<a-descriptions-item label="备注"><span>{{ formData.remark }}</span></a-descriptions-item>
|
||||
<a-descriptions-item label="排序"><span>{{ formData.sortCode }}</span></a-descriptions-item>
|
||||
<a-descriptions-item label="发布位置">
|
||||
<div v-if="formData.place">
|
||||
<a-tag v-for="textValue in JSON.parse(formData.place)" :key="textValue" color="processing">
|
||||
{{ $TOOL.dictTypeData('BIZ_NOTICE_PLACE', textValue) }}
|
||||
</a-tag>
|
||||
</div>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="创建人"><span>{{ formData.createUserName }}</span></a-descriptions-item>
|
||||
<a-descriptions-item label="创建时间"><span>{{ formData.createTime }}</span></a-descriptions-item>
|
||||
<a-descriptions-item label="修改人"><span>{{ formData.updateUserName }}</span></a-descriptions-item>
|
||||
<a-descriptions-item label="修改时间"><span>{{ formData.updateTime }}</span></a-descriptions-item>
|
||||
</a-descriptions>
|
||||
<template #footer>
|
||||
<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
|
||||
<a-button type="primary" @click="onClose" :loading="submitLoading">确定</a-button>
|
||||
</template>
|
||||
</xn-form-container>
|
||||
</template>
|
||||
|
||||
<script setup name="bizNoticeDetail">
|
||||
import bizNoticeApi from '@/api/biz/bizNoticeApi'
|
||||
import { message } from 'ant-design-vue'
|
||||
// 抽屉状态
|
||||
const open = ref(false)
|
||||
const emit = defineEmits({ successful: null })
|
||||
// 表单数据
|
||||
const formData = ref({})
|
||||
const submitLoading = ref(false)
|
||||
// 打开抽屉
|
||||
const onOpen = (id) => {
|
||||
open.value = true
|
||||
if (id) {
|
||||
const param = {
|
||||
id: id
|
||||
}
|
||||
bizNoticeApi.bizNoticeDetail(param).then((data) => {
|
||||
formData.value = Object.assign({}, data)
|
||||
})
|
||||
} else {
|
||||
message.warning('未查到该信息')
|
||||
}
|
||||
}
|
||||
// 关闭抽屉
|
||||
const onClose = () => {
|
||||
formData.value = {}
|
||||
open.value = false
|
||||
}
|
||||
// 抛出函数
|
||||
defineExpose({
|
||||
onOpen
|
||||
})
|
||||
</script>
|
|
@ -0,0 +1,148 @@
|
|||
<template>
|
||||
<xn-form-container
|
||||
:title="formData.id ? '编辑通知公告' : '增加通知公告'"
|
||||
:width="1000"
|
||||
v-model:open="open"
|
||||
:destroy-on-close="true"
|
||||
@close="onClose"
|
||||
>
|
||||
<a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="19">
|
||||
<a-form-item label="标题:" name="title">
|
||||
<a-input v-model:value="formData.title" placeholder="请输入标题" allow-clear />
|
||||
</a-form-item>
|
||||
<a-form-item name="type">
|
||||
<template #label>
|
||||
<a-tooltip>
|
||||
<template #title>
|
||||
这里只是标签的类型
|
||||
</template>
|
||||
<question-circle-outlined />
|
||||
类型:
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<a-radio-group v-model:value="formData.type" placeholder="请选择类型" :options="typeOptions" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="5">
|
||||
<a-form-item label="封面图:" name="image">
|
||||
<xn-upload v-model:value="formData.image" uploadMode="image" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="内容:" name="content">
|
||||
<xn-editor v-model:value="formData.content" placeholder="请输入内容" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="摘要:" name="digest">
|
||||
<a-textarea
|
||||
v-model:value="formData.digest"
|
||||
placeholder="请输入摘要"
|
||||
:auto-size="{ minRows: 3, maxRows: 5 }"
|
||||
:showCount="true"
|
||||
:maxlength="60"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="18">
|
||||
<a-form-item label="发布位置:" name="place">
|
||||
<a-checkbox-group v-model:value="formData.place" placeholder="请选择发布位置" :options="placeOptions" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-form-item label="排序:" name="sortCode">
|
||||
<a-input-number
|
||||
v-model:value="formData.sortCode"
|
||||
placeholder="请输入排序"
|
||||
:max="1000"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="备注:" name="remark">
|
||||
<a-textarea v-model:value="formData.remark" placeholder="请输入备注" :auto-size="{ minRows: 3, maxRows: 5 }" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
<template #footer>
|
||||
<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
|
||||
<a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button>
|
||||
</template>
|
||||
</xn-form-container>
|
||||
</template>
|
||||
|
||||
<script setup name="bizNoticeForm">
|
||||
import tool from '@/utils/tool'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { required } from '@/utils/formRules'
|
||||
import bizNoticeApi from '@/api/biz/bizNoticeApi'
|
||||
// 抽屉状态
|
||||
const open = ref(false)
|
||||
const emit = defineEmits({ successful: null })
|
||||
const formRef = ref()
|
||||
// 表单数据
|
||||
const formData = ref({})
|
||||
const submitLoading = ref(false)
|
||||
const typeOptions = ref([])
|
||||
const placeOptions = ref([])
|
||||
const statusOptions = ref([])
|
||||
|
||||
// 打开抽屉
|
||||
const onOpen = (record) => {
|
||||
open.value = true
|
||||
if (record) {
|
||||
let recordData = cloneDeep(record)
|
||||
recordData.place = JSON.parse(recordData.place)
|
||||
formData.value = Object.assign({}, recordData)
|
||||
} else {
|
||||
formData.value = {
|
||||
type: 'NOTICE',
|
||||
place: ['BACK_MOBILE', 'BACK_INDEX'],
|
||||
sortCode: 99
|
||||
}
|
||||
}
|
||||
typeOptions.value = tool.dictList('BIZ_NOTICE_TYPE')
|
||||
placeOptions.value = tool.dictList('BIZ_NOTICE_PLACE')
|
||||
statusOptions.value = tool.dictList('BIZ_NOTICE_STATUS')
|
||||
}
|
||||
// 关闭抽屉
|
||||
const onClose = () => {
|
||||
formRef.value.resetFields()
|
||||
formData.value = {}
|
||||
open.value = false
|
||||
}
|
||||
// 默认要校验的
|
||||
const formRules = {
|
||||
title: [required('请输入标题')],
|
||||
content: [required('请输入内容')],
|
||||
digest: [required('请输入摘要')],
|
||||
type: [required('请选择类型')],
|
||||
place: [required('请选择发布位置')],
|
||||
sortCode: [required('请输入排序')]
|
||||
}
|
||||
// 验证并提交数据
|
||||
const onSubmit = () => {
|
||||
formRef.value.validate().then(() => {
|
||||
submitLoading.value = true
|
||||
const formDataParam = cloneDeep(formData.value)
|
||||
formDataParam.place = JSON.stringify(formDataParam.place)
|
||||
bizNoticeApi
|
||||
.bizNoticeSubmitForm(formDataParam, formDataParam.id)
|
||||
.then(() => {
|
||||
onClose()
|
||||
emit('successful')
|
||||
})
|
||||
.finally(() => {
|
||||
submitLoading.value = false
|
||||
})
|
||||
})
|
||||
}
|
||||
// 抛出函数
|
||||
defineExpose({
|
||||
onOpen
|
||||
})
|
||||
</script>
|
|
@ -0,0 +1,250 @@
|
|||
<template>
|
||||
<a-card :bordered="false">
|
||||
<a-form ref="searchFormRef" name="advanced_search" :model="searchFormState" class="ant-advanced-search-form">
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="6">
|
||||
<a-form-item label="标题" name="title">
|
||||
<a-input v-model:value="searchFormState.title" placeholder="请输入标题" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-form-item label="类型" name="type">
|
||||
<a-select v-model:value="searchFormState.type" placeholder="请选择类型" :options="typeOptions" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-form-item label="发布位置" name="place">
|
||||
<a-select v-model:value="searchFormState.place" placeholder="请选择发布位置" :options="placeOptions" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="6" v-show="advanced">
|
||||
<a-form-item label="状态" name="status">
|
||||
<a-select v-model:value="searchFormState.status" placeholder="请选择状态" :options="statusOptions" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="6" v-show="advanced">
|
||||
<a-form-item label="创建时间" name="createTime">
|
||||
<a-range-picker v-model:value="searchFormState.createTime" show-time />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-button type="primary" @click="tableRef.refresh(true)">查询</a-button>
|
||||
<a-button style="margin: 0 8px" @click="reset">重置</a-button>
|
||||
<a @click="toggleAdvanced" style="margin-left: 8px">
|
||||
{{ advanced ? '收起' : '展开' }}
|
||||
<component :is="advanced ? 'up-outlined' : 'down-outlined'"/>
|
||||
</a>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
<s-table
|
||||
ref="tableRef"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:alert="options.alert.show"
|
||||
bordered
|
||||
:row-key="(record) => record.id"
|
||||
:tool-config="toolConfig"
|
||||
:row-selection="options.rowSelection"
|
||||
>
|
||||
<template #operator class="table-operator">
|
||||
<a-space>
|
||||
<a-button type="primary" @click="formRef.onOpen()" v-if="hasPerm('bizNoticeAdd')">
|
||||
<template #icon><plus-outlined /></template>
|
||||
新增
|
||||
</a-button>
|
||||
<xn-batch-delete
|
||||
v-if="hasPerm('bizNoticeBatchDelete')"
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
@batchDelete="deleteBatchBizNotice"
|
||||
/>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'image'">
|
||||
<div v-if="record.image">
|
||||
<a-image :src="record.image" style="width: 30px; height: 30px;" />
|
||||
</div>
|
||||
<span v-else>未上传</span>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'type'">
|
||||
<a-tag :bordered="false" color="success" v-if="record.type === 'NOTICE'">
|
||||
{{ $TOOL.dictTypeData('BIZ_NOTICE_TYPE', record.type) }}
|
||||
</a-tag>
|
||||
<a-tag :bordered="false" color="processing" v-else-if="record.type === 'ANNOUNCEMENT'">
|
||||
{{ $TOOL.dictTypeData('BIZ_NOTICE_TYPE', record.type) }}
|
||||
</a-tag>
|
||||
<a-tag :bordered="false" color="warning" v-else-if="record.type === 'WARNING'">
|
||||
{{ $TOOL.dictTypeData('BIZ_NOTICE_TYPE', record.type) }}
|
||||
</a-tag>
|
||||
<span v-else>无</span>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'place'">
|
||||
<a-tag v-for="textValue in JSON.parse(record.place)" :key="textValue" color="processing">
|
||||
{{ $TOOL.dictTypeData('BIZ_NOTICE_PLACE', textValue) }}
|
||||
</a-tag>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'status'">
|
||||
<a-switch
|
||||
:loading="loading"
|
||||
:checked="record.status === 'ENABLE'"
|
||||
@change="editStatus(record)"
|
||||
v-if="hasPerm('bizNoticerUpdateStatus')"
|
||||
/>
|
||||
<span v-else>{{ $TOOL.dictTypeData('BIZ_NOTICE_STATUS', record.status) }}</span>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<a-space>
|
||||
<a @click="detailRef.onOpen(record.id)" v-if="hasPerm('bizNoticeDetail')">详情</a>
|
||||
<a-divider type="vertical" v-if="hasPerm(['bizNoticeEdit', 'bizNoticeDetail'], 'and')" />
|
||||
<a @click="formRef.onOpen(record)" v-if="hasPerm('bizNoticeEdit')">编辑</a>
|
||||
<a-divider type="vertical" v-if="hasPerm(['bizNoticeEdit', 'bizNoticeDelete'], 'and')" />
|
||||
<a-popconfirm title="确定要删除吗?" @confirm="deleteBizNotice(record)">
|
||||
<a-button type="link" danger size="small" v-if="hasPerm('bizNoticeDelete')">删除</a-button>
|
||||
</a-popconfirm>
|
||||
</a-space>
|
||||
</template>
|
||||
</template>
|
||||
</s-table>
|
||||
</a-card>
|
||||
<Form ref="formRef" @successful="tableRef.refresh()" />
|
||||
<detail ref="detailRef" />
|
||||
</template>
|
||||
|
||||
<script setup name="notice">
|
||||
import tool from '@/utils/tool'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import Form from './form.vue'
|
||||
import Detail from './detail.vue'
|
||||
import bizNoticeApi from '@/api/biz/bizNoticeApi'
|
||||
const searchFormState = ref({})
|
||||
const searchFormRef = ref()
|
||||
const tableRef = ref()
|
||||
const formRef = ref()
|
||||
const detailRef = ref()
|
||||
const toolConfig = { refresh: true, height: true, columnSetting: true, striped: false }
|
||||
const loading = ref(false)
|
||||
// 查询区域显示更多控制
|
||||
const advanced = ref(false)
|
||||
const toggleAdvanced = () => {
|
||||
advanced.value = !advanced.value
|
||||
}
|
||||
const columns = [
|
||||
{
|
||||
title: '标题',
|
||||
dataIndex: 'title'
|
||||
},
|
||||
{
|
||||
title: '封面图',
|
||||
dataIndex: 'image',
|
||||
width: '100px'
|
||||
},
|
||||
{
|
||||
title: '类型',
|
||||
dataIndex: 'type'
|
||||
},
|
||||
{
|
||||
title: '发布位置',
|
||||
dataIndex: 'place'
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sortCode',
|
||||
sorter: true
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status'
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
width: '150px'
|
||||
},
|
||||
]
|
||||
// 操作栏通过权限判断是否显示
|
||||
if (hasPerm(['bizNoticeEdit', 'bizNoticeDelete'])) {
|
||||
columns.push({
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
align: 'center',
|
||||
width: '200px'
|
||||
})
|
||||
}
|
||||
const selectedRowKeys = ref([])
|
||||
// 列表选择配置
|
||||
const options = {
|
||||
// columns数字类型字段加入 needTotal: true 可以勾选自动算账
|
||||
alert: {
|
||||
show: false,
|
||||
clear: () => {
|
||||
selectedRowKeys.value = ref([])
|
||||
}
|
||||
},
|
||||
rowSelection: {
|
||||
onChange: (selectedRowKey, selectedRows) => {
|
||||
selectedRowKeys.value = selectedRowKey
|
||||
}
|
||||
}
|
||||
}
|
||||
const loadData = (parameter) => {
|
||||
const searchFormParam = cloneDeep(searchFormState.value)
|
||||
// createTime范围查询条件重载
|
||||
if (searchFormParam.createTime) {
|
||||
searchFormParam.startCreateTime = searchFormParam.createTime[0]
|
||||
searchFormParam.endCreateTime = searchFormParam.createTime[1]
|
||||
delete searchFormParam.createTime
|
||||
}
|
||||
return bizNoticeApi.bizNoticePage(Object.assign(parameter, searchFormParam)).then((data) => {
|
||||
return data
|
||||
})
|
||||
}
|
||||
// 重置
|
||||
const reset = () => {
|
||||
searchFormRef.value.resetFields()
|
||||
tableRef.value.refresh(true)
|
||||
}
|
||||
// 删除
|
||||
const deleteBizNotice = (record) => {
|
||||
let params = [
|
||||
{
|
||||
id: record.id
|
||||
}
|
||||
]
|
||||
bizNoticeApi.bizNoticeDelete(params).then(() => {
|
||||
tableRef.value.refresh(true)
|
||||
})
|
||||
}
|
||||
// 批量删除
|
||||
const deleteBatchBizNotice = (params) => {
|
||||
bizNoticeApi.bizNoticeDelete(params).then(() => {
|
||||
tableRef.value.clearRefreshSelected()
|
||||
})
|
||||
}
|
||||
// 修改状态
|
||||
const editStatus = (record) => {
|
||||
loading.value = true
|
||||
if (record.status === 'ENABLE') {
|
||||
bizNoticeApi
|
||||
.bizNoticeDisableStatus(record)
|
||||
.then(() => {
|
||||
tableRef.value.refresh()
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
} else {
|
||||
bizNoticeApi
|
||||
.bizNoticeEnableStatus(record)
|
||||
.then(() => {
|
||||
tableRef.value.refresh()
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
}
|
||||
const typeOptions = tool.dictList('BIZ_NOTICE_TYPE')
|
||||
const placeOptions = tool.dictList('BIZ_NOTICE_PLACE')
|
||||
const statusOptions = tool.dictList('BIZ_NOTICE_STATUS')
|
||||
</script>
|
|
@ -0,0 +1,111 @@
|
|||
<template>
|
||||
<xn-form-container
|
||||
:title="formData.id ? '编辑轮播图' : '增加轮播图'"
|
||||
:width="700"
|
||||
v-model:open="open"
|
||||
:destroy-on-close="true"
|
||||
@close="onClose"
|
||||
>
|
||||
<a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="18">
|
||||
<a-form-item label="标题:" name="title">
|
||||
<a-input v-model:value="formData.title" placeholder="请输入标题" allow-clear />
|
||||
</a-form-item>
|
||||
<a-form-item label="排序:" name="sortCode">
|
||||
<a-input v-model:value="formData.sortCode" placeholder="请输入排序" allow-clear />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-form-item label="图片:" name="image">
|
||||
<xn-upload v-model:value="formData.image" uploadMode="image" />
|
||||
</a-form-item>
|
||||
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="展示位置:" name="place">
|
||||
<a-checkbox-group v-model:value="formData.place" placeholder="请选择展示位置" :options="placeOptions" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<sub-form ref="sumFormRef" :data-array="formData.pathDetails" :place="formData.place" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
<template #footer>
|
||||
<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
|
||||
<a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button>
|
||||
</template>
|
||||
</xn-form-container>
|
||||
</template>
|
||||
|
||||
<script setup name="devSlideshowForm">
|
||||
import tool from '@/utils/tool'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { required } from '@/utils/formRules'
|
||||
import slideshowApi from '@/api/dev/slideshowApi'
|
||||
import SubForm from './subForm.vue'
|
||||
// 抽屉状态
|
||||
const open = ref(false)
|
||||
const emit = defineEmits({ successful: null })
|
||||
const formRef = ref()
|
||||
const sumFormRef = ref()
|
||||
// 表单数据
|
||||
const formData = ref({})
|
||||
const submitLoading = ref(false)
|
||||
const placeOptions = ref([])
|
||||
|
||||
// 打开抽屉
|
||||
const onOpen = (record) => {
|
||||
open.value = true
|
||||
if (record) {
|
||||
let recordData = cloneDeep(record)
|
||||
recordData.place = JSON.parse(recordData.place)
|
||||
recordData.pathDetails = JSON.parse(recordData.pathDetails)
|
||||
formData.value = Object.assign({}, recordData)
|
||||
} else {
|
||||
formData.value = {
|
||||
place: ['BACK_SYS_INDEX']
|
||||
}
|
||||
}
|
||||
placeOptions.value = tool.dictList('DEV_SLIDESHOW_PLACE')
|
||||
}
|
||||
// 关闭抽屉
|
||||
const onClose = () => {
|
||||
formRef.value.resetFields()
|
||||
formData.value = {}
|
||||
open.value = false
|
||||
}
|
||||
// 默认要校验的
|
||||
const formRules = {
|
||||
title: [required('请输入标题')],
|
||||
place: [required('请输入展示位置')],
|
||||
sortCode: [required('请输入排序')]
|
||||
}
|
||||
// 验证并提交数据
|
||||
const onSubmit = () => {
|
||||
formRef.value.validate().then(() => {
|
||||
const formDataParam = cloneDeep(formData.value)
|
||||
formDataParam.place = JSON.stringify(formDataParam.place)
|
||||
const details = sumFormRef.value.getData()
|
||||
if (details === false) {
|
||||
return
|
||||
}
|
||||
formDataParam.pathDetails = JSON.stringify(details)
|
||||
submitLoading.value = true
|
||||
slideshowApi
|
||||
.devSlideshowSubmitForm(formDataParam, formDataParam.id)
|
||||
.then(() => {
|
||||
onClose()
|
||||
emit('successful')
|
||||
})
|
||||
.finally(() => {
|
||||
submitLoading.value = false
|
||||
})
|
||||
})
|
||||
}
|
||||
// 抛出函数
|
||||
defineExpose({
|
||||
onOpen
|
||||
})
|
||||
</script>
|
|
@ -0,0 +1,233 @@
|
|||
<template>
|
||||
<a-card :bordered="false">
|
||||
<a-form ref="searchFormRef" name="advanced_search" :model="searchFormState" class="ant-advanced-search-form">
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="6">
|
||||
<a-form-item label="标题" name="title">
|
||||
<a-input v-model:value="searchFormState.title" placeholder="请输入标题" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-form-item label="展示位置" name="place">
|
||||
<a-select v-model:value="searchFormState.place" placeholder="请选择展示位置" :options="placeOptions" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-form-item label="状态" name="status">
|
||||
<a-select v-model:value="searchFormState.status" placeholder="请选择状态" :options="statusOptions" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-button type="primary" @click="tableRef.refresh(true)">查询</a-button>
|
||||
<a-button style="margin: 0 8px" @click="reset">重置</a-button>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
<s-table
|
||||
ref="tableRef"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:alert="options.alert.show"
|
||||
bordered
|
||||
:row-key="(record) => record.id"
|
||||
:tool-config="toolConfig"
|
||||
:row-selection="options.rowSelection"
|
||||
>
|
||||
<template #expandColumnTitle>
|
||||
<span>更多</span>
|
||||
</template>
|
||||
<template #expandedRowRender="{ record }">
|
||||
<a-table
|
||||
size="middle"
|
||||
:dataSource="JSON.parse(record.pathDetails)"
|
||||
:columns="detailsColumns"
|
||||
:pagination="false"
|
||||
bordered
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'whetherToClick'">
|
||||
<a-tag color="blue" v-if="record.whetherToClick === 'ENABLE'">
|
||||
{{ $TOOL.dictTypeData('WHETHER_TO_CLICK', record.whetherToClick) }}
|
||||
</a-tag>
|
||||
<a-tag color="red" v-if="record.whetherToClick === 'DISABLE'">
|
||||
{{ $TOOL.dictTypeData('WHETHER_TO_CLICK', record.whetherToClick) }}
|
||||
</a-tag>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'skipMode'">
|
||||
{{ $TOOL.dictTypeData('SKIP_MODE', record.skipMode) }}
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</template>
|
||||
<template #operator class="table-operator">
|
||||
<a-space>
|
||||
<a-button type="primary" @click="formRef.onOpen()">
|
||||
<template #icon><plus-outlined /></template>
|
||||
新增
|
||||
</a-button>
|
||||
<xn-batch-delete
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
@batchDelete="deleteBatchDevSlideshow"
|
||||
/>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'place'">
|
||||
<a-tag v-for="textValue in JSON.parse(record.place)" :key="textValue" color="green">{{ $TOOL.dictTypeData('DEV_SLIDESHOW_PLACE', textValue) }}</a-tag>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'image'">
|
||||
<a-image :src="record.image" style="width: 50px; height: 30px;" />
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'status'">
|
||||
<a-switch
|
||||
:loading="loading"
|
||||
:checked="record.status === 'ENABLE'"
|
||||
@change="editStatus(record)"
|
||||
v-if="hasPerm('bizNoticerUpdateStatus')"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<a-space>
|
||||
<a @click="formRef.onOpen(record)">编辑</a>
|
||||
<a-divider type="vertical" />
|
||||
<a-popconfirm title="确定要删除吗?" @confirm="deleteDevSlideshow(record)">
|
||||
<a-button type="link" danger size="small">删除</a-button>
|
||||
</a-popconfirm>
|
||||
</a-space>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
</s-table>
|
||||
</a-card>
|
||||
<Form ref="formRef" @successful="tableRef.refresh()" />
|
||||
</template>
|
||||
|
||||
<script setup name="slideshow">
|
||||
import tool from '@/utils/tool'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import Form from './form.vue'
|
||||
import slideshowApi from '@/api/dev/slideshowApi'
|
||||
const searchFormState = ref({})
|
||||
const searchFormRef = ref()
|
||||
const tableRef = ref()
|
||||
const formRef = ref()
|
||||
const loading = ref(false)
|
||||
const toolConfig = { refresh: true, height: true, columnSetting: true, striped: false }
|
||||
const columns = [
|
||||
{
|
||||
title: '标题',
|
||||
dataIndex: 'title'
|
||||
},
|
||||
{
|
||||
title: '图片',
|
||||
dataIndex: 'image'
|
||||
},
|
||||
{
|
||||
title: '展示位置',
|
||||
dataIndex: 'place'
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status'
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sortCode',
|
||||
sorter: true
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
align: 'center',
|
||||
width: '150px'
|
||||
}
|
||||
]
|
||||
const detailsColumns = [
|
||||
{
|
||||
title: '位置',
|
||||
dataIndex: 'label',
|
||||
width: '200px'
|
||||
},
|
||||
{
|
||||
title: '点击事件',
|
||||
dataIndex: 'whetherToClick'
|
||||
},
|
||||
{
|
||||
title: '跳转方式',
|
||||
dataIndex: 'skipMode'
|
||||
},
|
||||
{
|
||||
title: 'URL',
|
||||
dataIndex: 'url'
|
||||
}
|
||||
]
|
||||
const selectedRowKeys = ref([])
|
||||
// 列表选择配置
|
||||
const options = {
|
||||
// columns数字类型字段加入 needTotal: true 可以勾选自动算账
|
||||
alert: {
|
||||
show: false,
|
||||
clear: () => {
|
||||
selectedRowKeys.value = ref([])
|
||||
}
|
||||
},
|
||||
rowSelection: {
|
||||
onChange: (selectedRowKey, selectedRows) => {
|
||||
selectedRowKeys.value = selectedRowKey
|
||||
}
|
||||
}
|
||||
}
|
||||
const loadData = (parameter) => {
|
||||
const searchFormParam = cloneDeep(searchFormState.value)
|
||||
return slideshowApi.devSlideshowPage(Object.assign(parameter, searchFormParam)).then((data) => {
|
||||
return data
|
||||
})
|
||||
}
|
||||
// 重置
|
||||
const reset = () => {
|
||||
searchFormRef.value.resetFields()
|
||||
tableRef.value.refresh(true)
|
||||
}
|
||||
// 删除
|
||||
const deleteDevSlideshow = (record) => {
|
||||
let params = [
|
||||
{
|
||||
id: record.id
|
||||
}
|
||||
]
|
||||
slideshowApi.devSlideshowDelete(params).then(() => {
|
||||
tableRef.value.refresh()
|
||||
})
|
||||
}
|
||||
// 批量删除
|
||||
const deleteBatchDevSlideshow = (params) => {
|
||||
slideshowApi.devSlideshowDelete(params).then(() => {
|
||||
tableRef.value.clearRefreshSelected()
|
||||
})
|
||||
}
|
||||
// 修改状态
|
||||
const editStatus = (record) => {
|
||||
loading.value = true
|
||||
if (record.status === 'ENABLE') {
|
||||
slideshowApi
|
||||
.devSlideshowDisableStatus(record)
|
||||
.then(() => {
|
||||
tableRef.value.refresh()
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
} else {
|
||||
slideshowApi
|
||||
.devSlideshowEnableStatus(record)
|
||||
.then(() => {
|
||||
tableRef.value.refresh()
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
}
|
||||
const placeOptions = tool.dictList('DEV_SLIDESHOW_PLACE')
|
||||
const statusOptions = tool.dictList('DEV_SLIDESHOW_STATUS')
|
||||
</script>
|
|
@ -0,0 +1,162 @@
|
|||
<template>
|
||||
<a-form
|
||||
:model="formData"
|
||||
ref="formRef"
|
||||
name="basic"
|
||||
autocomplete="off"
|
||||
>
|
||||
<a-table :columns="columns" :dataSource="formData" size="middle">
|
||||
<template #bodyCell="{text, record, index, column}">
|
||||
<template v-if="column.dataIndex === 'whetherToClick'">
|
||||
<a-form-item :validate-status="validateStatus(record, 'whetherToClick')">
|
||||
<a-radio-group v-model:value="record.whetherToClick" placeholder="请选择跳转方式" :options="whetherToClickOptions" />
|
||||
</a-form-item>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'skipMode'">
|
||||
<a-form-item :validate-status="validateStatus(record, 'skipMode')">
|
||||
<a-select v-model:value="record.skipMode" placeholder="请选择跳转方式" :disabled="record.whetherToClick === 'DISABLE'" :options="skipModeOptions" />
|
||||
</a-form-item>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'url'">
|
||||
<a-form-item :validate-status="validateStatus(record, 'url')">
|
||||
<a-input v-model:value="formData[index].url" :disabled="record.whetherToClick === 'DISABLE'" placeholder="请输入URL或路由地址"/>
|
||||
</a-form-item>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-form>
|
||||
</template>
|
||||
|
||||
<script name="subForm" setup>
|
||||
import tool from "@/utils/tool"
|
||||
import { remove, isEmpty, cloneDeep } from 'lodash-es'
|
||||
const formRef = ref()
|
||||
const formData = ref([])
|
||||
const skipModeOptions = ref(tool.dictList('SKIP_MODE'))
|
||||
const whetherToClickOptions = ref(tool.dictList('WHETHER_TO_CLICK'))
|
||||
const props = defineProps({
|
||||
dataArray: {
|
||||
type: Object,
|
||||
default: []
|
||||
},
|
||||
place: {
|
||||
type: Object,
|
||||
default: []
|
||||
}
|
||||
})
|
||||
const columns = ref([
|
||||
{
|
||||
title: '位置',
|
||||
dataIndex: 'label',
|
||||
width: '20%',
|
||||
},
|
||||
{
|
||||
title: '点击事件',
|
||||
dataIndex: 'whetherToClick',
|
||||
width: '25%',
|
||||
},
|
||||
{
|
||||
title: '跳转方式',
|
||||
dataIndex: 'skipMode',
|
||||
width: '20%',
|
||||
},
|
||||
{
|
||||
title: 'URL',
|
||||
dataIndex: 'url'
|
||||
}
|
||||
])
|
||||
// 每行的校验
|
||||
const validateStatus = (record, name) => {
|
||||
if (record[name]) {
|
||||
return 'success'
|
||||
} else {
|
||||
return 'error'
|
||||
}
|
||||
}
|
||||
// 返回多的数据,用于增减行
|
||||
const dataFiltrate = (newVal, oldVal) => {
|
||||
let result = ''
|
||||
oldVal.forEach((data) => {
|
||||
if (!newVal.some(item => item === data)) {
|
||||
result = data
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
||||
watch(
|
||||
() => props.place,
|
||||
(newVal, oldVal) => {
|
||||
if (!isEmpty(props.dataArray) && isEmpty(formData.value)) {
|
||||
formData.value = cloneDeep(props.dataArray)
|
||||
} else {
|
||||
if (typeof newVal === "object") {
|
||||
if (!isEmpty(formData.value)) {
|
||||
formData.value.forEach(() => {
|
||||
// 如果包含
|
||||
if (!newVal.some(item => item === item.key)) {
|
||||
// 需要减少的
|
||||
if (formData.value.length > newVal.length) {
|
||||
const deleteData = dataFiltrate(newVal, oldVal)
|
||||
remove(formData.value, (item) => item.key === deleteData)
|
||||
}
|
||||
// 需要增加的
|
||||
if (formData.value.length < newVal.length) {
|
||||
const deleteData = dataFiltrate(oldVal, newVal)
|
||||
// 如果没有,就不增加
|
||||
if (!formData.value.some(item => item === deleteData)) {
|
||||
const obj = {
|
||||
key: deleteData,
|
||||
label: tool.dictTypeData('DEV_SLIDESHOW_PLACE' , deleteData),
|
||||
whetherToClick: 'DISABLE',
|
||||
skipMode: 'URL',
|
||||
url: ''
|
||||
}
|
||||
formData.value.push(obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
newVal.forEach((item) => {
|
||||
const obj = {
|
||||
key: item,
|
||||
label: tool.dictTypeData('DEV_SLIDESHOW_PLACE' , item),
|
||||
whetherToClick: 'DISABLE',
|
||||
skipMode: 'URL',
|
||||
url: ''
|
||||
}
|
||||
formData.value.push(obj)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
)
|
||||
// 获取值,校验不通过返回false
|
||||
const getData = () => {
|
||||
if (isEmpty(formData.value)) {
|
||||
return false
|
||||
} else {
|
||||
let result = true
|
||||
formData.value.forEach((item) => {
|
||||
if (item.whetherToClick === 'ENABLE' && isEmpty(item.url)) {
|
||||
result = false
|
||||
}
|
||||
})
|
||||
if (result === false) {
|
||||
return false
|
||||
} else {
|
||||
return formData.value
|
||||
}
|
||||
}
|
||||
}
|
||||
defineExpose({
|
||||
getData
|
||||
})
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-form-item {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
</style>
|
|
@ -1,90 +0,0 @@
|
|||
<template>
|
||||
<a-carousel class="snowy-right-card-one" autoplay arrows>
|
||||
<template #prevArrow>
|
||||
<div class="custom-slick-arrow" style="left: 10px; z-index: 1">
|
||||
<left-circle-outlined />
|
||||
</div>
|
||||
</template>
|
||||
<template #nextArrow>
|
||||
<div class="custom-slick-arrow" style="right: 10px">
|
||||
<right-circle-outlined />
|
||||
</div>
|
||||
</template>
|
||||
<img
|
||||
src="/src/assets/images/index_001.png"
|
||||
class="carousel-images"
|
||||
@click="leaveForOpen('https://www.xiaonuo.vip')"
|
||||
/>
|
||||
<img
|
||||
src="/src/assets/images/index_002.png"
|
||||
class="carousel-images"
|
||||
@click="leaveForOpen('https://www.xiaonuo.vip')"
|
||||
/>
|
||||
<!--
|
||||
<img v-for="(item, index) in carouselList"
|
||||
:src="item.images"
|
||||
class="carousel-images"
|
||||
@click="leaveForOpen(item.url)"
|
||||
/>
|
||||
-->
|
||||
</a-carousel>
|
||||
</template>
|
||||
|
||||
<script setup name="carousel">
|
||||
import { LeftCircleOutlined, RightCircleOutlined } from '@ant-design/icons-vue'
|
||||
const carouselList = ref([
|
||||
{
|
||||
images: '/src/assets/images/index_001.png',
|
||||
url: 'https://www.xiaonuo.vip'
|
||||
},
|
||||
{
|
||||
images: '/src/assets/images/index_002.png',
|
||||
url: 'https://www.xiaonuo.vip'
|
||||
}
|
||||
])
|
||||
// 打开一个新窗口
|
||||
const leaveForOpen = (url) => {
|
||||
if (url) {
|
||||
window.open(url)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.carousel-images {
|
||||
height: 160px;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
.snowy-right-card-one {
|
||||
height: 160px;
|
||||
}
|
||||
|
||||
.ant-carousel :deep(.slick-slide) {
|
||||
text-align: center;
|
||||
height: 160px;
|
||||
line-height: 150px;
|
||||
background: #364d79;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ant-carousel :deep(.slick-arrow.custom-slick-arrow) {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
font-size: 25px;
|
||||
color: #fff;
|
||||
background-color: rgba(31, 45, 61, 0.11);
|
||||
opacity: 0.3;
|
||||
z-index: 1;
|
||||
}
|
||||
.ant-carousel :deep(.custom-slick-arrow:before) {
|
||||
display: none;
|
||||
}
|
||||
.ant-carousel :deep(.custom-slick-arrow:hover) {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.ant-carousel :deep(.slick-slide h3) {
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
|
@ -1,31 +1,39 @@
|
|||
<template>
|
||||
<a-row :gutter="10">
|
||||
<a-col :span="16" :xs="24" :sm="24" :md="24" :lg="16" :xl="16">
|
||||
<userInfo class="mb-2" />
|
||||
<shortcut class="mb-2" />
|
||||
<!-- 人员信息 -->
|
||||
<sys-user-info-card class="mb-2" />
|
||||
<!-- 业务数据 -->
|
||||
<sys-biz-data-card class="mb-2" />
|
||||
<!-- 运维一览 -->
|
||||
<sys-op-data-card class="mb-2" />
|
||||
<a-row :gutter="10">
|
||||
<!-- 访问记录 -->
|
||||
<a-col :span="12" :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
|
||||
<visLog class="mb-2" />
|
||||
<sys-vis-log-card class="mb-2" />
|
||||
</a-col>
|
||||
<!-- 操作记录 -->
|
||||
<a-col :span="12" :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
|
||||
<opLog class="mb-2" />
|
||||
<sys-op-log-card class="mb-2" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
<a-col :span="8" :xs="24" :sm="24" :md="24" :lg="8" :xl="8">
|
||||
<carousel class="mb-2" />
|
||||
<schedule class="mb-2" />
|
||||
<miniMessage class="mb-2" />
|
||||
<!-- 轮播图 -->
|
||||
<biz-slideshow-card :config="slideshowConfig" class="mb-2" />
|
||||
<!-- 基础工具 -->
|
||||
<sys-tool-data-card class="mb-2" />
|
||||
<!-- 周访问量 -->
|
||||
<sys-vis-chart-data-card />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
|
||||
<script setup name="indexHome">
|
||||
import UserInfo from './components/userInfo.vue'
|
||||
import Shortcut from './components/shortcut.vue'
|
||||
import Schedule from './components/schedule.vue'
|
||||
import MiniMessage from './components/miniMessage.vue'
|
||||
import Carousel from './components/carousel.vue'
|
||||
import VisLog from './components/visLog.vue'
|
||||
import OpLog from './components/opLog.vue'
|
||||
// 轮播图配置
|
||||
const slideshowConfig = {
|
||||
options: {
|
||||
place: 'BACK_SYS_INDEX'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -20,11 +20,11 @@ import Less2CssVariablePlugin from 'antd-less-to-css-variable'
|
|||
import viteCompression from 'vite-plugin-compression'
|
||||
|
||||
// ant-design-vue 的 less 变量,通过兼容包将 v4 变量转译成 v3 版本,并通过 less-loader 注入
|
||||
import { theme } from 'ant-design-vue/lib';
|
||||
import convertLegacyToken from 'ant-design-vue/lib/theme/convertLegacyToken';
|
||||
const { defaultAlgorithm, defaultSeed } = theme;
|
||||
const mapToken = defaultAlgorithm(defaultSeed);
|
||||
const v3Token = convertLegacyToken.default(mapToken);
|
||||
import { theme } from 'ant-design-vue/lib'
|
||||
import convertLegacyToken from 'ant-design-vue/lib/theme/convertLegacyToken'
|
||||
const { defaultAlgorithm, defaultSeed } = theme
|
||||
const mapToken = defaultAlgorithm(defaultSeed)
|
||||
const v3Token = convertLegacyToken.default(mapToken)
|
||||
|
||||
export const r = (...args) => resolve(__dirname, '.', ...args)
|
||||
|
||||
|
@ -86,21 +86,30 @@ export default defineConfig(({ command, mode }) => {
|
|||
dts: r('src/auto-imports.d.ts')
|
||||
}),
|
||||
// 组件按需引入
|
||||
Components({
|
||||
dirs: [r('src/components')],
|
||||
dts: false,
|
||||
resolvers: []
|
||||
}),
|
||||
Components(
|
||||
{
|
||||
dirs: [r('src/components')],
|
||||
dts: false,
|
||||
resolvers: []
|
||||
},
|
||||
{
|
||||
dirs: [r('src/components/HomeCard')],
|
||||
dts: false,
|
||||
resolvers: []
|
||||
}
|
||||
),
|
||||
visualizer()
|
||||
],
|
||||
css: {
|
||||
preprocessorOptions: {
|
||||
less: {
|
||||
javascriptEnabled: true,
|
||||
plugins: [new Less2CssVariablePlugin({
|
||||
// TODO:有必要用的情况下,是否需要传入 variables,可能会造成重复引用
|
||||
variables: { ...v3Token }
|
||||
})],
|
||||
plugins: [
|
||||
new Less2CssVariablePlugin({
|
||||
// TODO:有必要用的情况下,是否需要传入 variables,可能会造成重复引用
|
||||
variables: { ...v3Token }
|
||||
})
|
||||
],
|
||||
modifyVars: v3Token
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue