mirror of https://gitee.com/xiaonuobase/snowy
parent
c2552c29c8
commit
66a62cafa7
2
pom.xml
2
pom.xml
|
@ -375,7 +375,7 @@
|
|||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
|
||||
<version>4.3.0</version>
|
||||
<version>4.3.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- mysql -->
|
||||
|
|
|
@ -9,3 +9,6 @@ VITE_SET_DRAWER = true
|
|||
|
||||
# 本地环境
|
||||
NODE_ENV = development
|
||||
|
||||
# 检测更新(本地建议关闭)
|
||||
VITE_VERSION_UPDATE = false
|
||||
|
|
|
@ -6,3 +6,6 @@ VITE_PORT = 81
|
|||
|
||||
# 开启设置抽屉
|
||||
VITE_SET_DRAWER = false
|
||||
|
||||
# 检测更新(生产建议开启)
|
||||
VITE_VERSION_UPDATE = true
|
||||
|
|
|
@ -18,40 +18,40 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@amap/amap-jsapi-loader": "1.0.1",
|
||||
"@ant-design/colors": "7.0.0",
|
||||
"@ant-design/colors": "7.1.0",
|
||||
"@ant-design/icons-vue": "7.0.1",
|
||||
"@antv/g2plot": "2.4.31",
|
||||
"@antv/g2plot": "2.4.32",
|
||||
"@chenfengyuan/vue-qrcode": "2.0.0",
|
||||
"@highlightjs/vue-plugin": "2.1.0",
|
||||
"@tinymce/tinymce-vue": "5.1.1",
|
||||
"@vue-office/docx": "1.6.0",
|
||||
"@vue-office/excel": "1.7.1",
|
||||
"@vue-office/pdf": "1.6.4",
|
||||
"ant-design-vue": "4.1.2",
|
||||
"axios": "1.6.2",
|
||||
"cropperjs": "1.6.1",
|
||||
"dayjs": "1.11.10",
|
||||
"echarts": "5.4.3",
|
||||
"@vue-office/docx": "1.6.2",
|
||||
"@vue-office/excel": "1.7.11",
|
||||
"@vue-office/pdf": "2.0.2",
|
||||
"ant-design-vue": "4.2.5",
|
||||
"axios": "1.7.7",
|
||||
"cropperjs": "1.6.2",
|
||||
"dayjs": "1.11.13",
|
||||
"echarts": "5.5.1",
|
||||
"echarts-stat": "1.2.0",
|
||||
"enquire.js": "2.1.6",
|
||||
"event-source-polyfill": "1.0.31",
|
||||
"fuse.js": "7.0.0",
|
||||
"highlight.js": "11.9.0",
|
||||
"hotkeys-js": "3.12.2",
|
||||
"js-pinyin": "0.2.5",
|
||||
"highlight.js": "11.10.0",
|
||||
"hotkeys-js": "3.13.7",
|
||||
"js-pinyin": "0.2.7",
|
||||
"lodash-es": "4.17.21",
|
||||
"nprogress": "0.2.0",
|
||||
"pinia": "2.1.7",
|
||||
"qs": "6.11.2",
|
||||
"screenfull": "6.0.2",
|
||||
"pinia": "2.2.2",
|
||||
"qrcode": "1.5.4",
|
||||
"qs": "6.13.0",
|
||||
"sm-crypto": "0.3.13",
|
||||
"snowflake-id": "1.1.0",
|
||||
"sortablejs": "1.15.1",
|
||||
"tinymce": "6.8.1",
|
||||
"vue": "3.4.21",
|
||||
"vue-cropper": "1.1.1",
|
||||
"vue-i18n": "9.8.0",
|
||||
"vue-router": "4.3.0",
|
||||
"sortablejs": "1.15.3",
|
||||
"tinymce": "7.3.0",
|
||||
"vue": "3.5.10",
|
||||
"vue-cropper": "1.1.4",
|
||||
"vue-i18n": "10.0.0",
|
||||
"vue-router": "4.4.5",
|
||||
"vue3-colorpicker": "2.3.0",
|
||||
"vue3-tree-org": "4.2.2",
|
||||
"vuedraggable-es": "4.1.1"
|
||||
|
@ -61,23 +61,23 @@
|
|||
"@vitejs/plugin-legacy": "5.2.0",
|
||||
"@vitejs/plugin-vue": "4.5.2",
|
||||
"@vitejs/plugin-vue-jsx": "3.1.0",
|
||||
"@vue/compiler-sfc": "3.3.10",
|
||||
"@vue/compiler-sfc": "3.5.10",
|
||||
"@vue/eslint-config-standard": "8.0.1",
|
||||
"antd-less-to-css-variable": "1.0.5",
|
||||
"autoprefixer": "10.4.16",
|
||||
"eslint": "8.55.0",
|
||||
"autoprefixer": "10.4.20",
|
||||
"eslint": "8.57.0",
|
||||
"eslint-config-prettier": "9.1.0",
|
||||
"eslint-plugin-prettier": "5.0.1",
|
||||
"eslint-plugin-vue": "9.7.0",
|
||||
"less": "4.1.3",
|
||||
"postcss": "8.4.32",
|
||||
"prettier": "3.1.0",
|
||||
"rollup-plugin-visualizer": "5.10.0",
|
||||
"tailwindcss": "3.3.6",
|
||||
"typescript": "5.3.3",
|
||||
"unplugin-auto-import": "0.17.2",
|
||||
"unplugin-vue-components": "0.26.0",
|
||||
"vite": "5.1.6",
|
||||
"less": "4.2.0",
|
||||
"postcss": "8.4.47",
|
||||
"prettier": "3.3.3",
|
||||
"rollup-plugin-visualizer": "5.12.0",
|
||||
"tailwindcss": "3.4.13",
|
||||
"typescript": "5.6.2",
|
||||
"unplugin-auto-import": "0.18.3",
|
||||
"unplugin-vue-components": "0.27.4",
|
||||
"vite": "5.4.8",
|
||||
"vite-plugin-compression": "0.5.1",
|
||||
"vite-plugin-vue-setup-extend": "0.4.0",
|
||||
"vue-eslint-parser": "9.3.2"
|
||||
|
|
|
@ -45,5 +45,13 @@ export default {
|
|||
// 获取所有移动端模块
|
||||
basicMobileModuleSelector(data) {
|
||||
return request('mobileModuleSelector', data, 'get')
|
||||
},
|
||||
// 获取所有模块
|
||||
basicModuleSelector(data) {
|
||||
return request('moduleSelector', data, 'get')
|
||||
},
|
||||
// 获取所有菜单树包括未授权的
|
||||
basicMenuTreeSelector(data) {
|
||||
return request('menuTreeSelector', data, 'get')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,16 +9,14 @@
|
|||
<template #nextArrow>
|
||||
<div class="custom-slick-arrow" style="right: 10px"><RightOutlined /></div>
|
||||
</template>
|
||||
<div v-if="!isEmpty(slideshowList)">
|
||||
<img
|
||||
v-for="item in slideshowList"
|
||||
:key="item.id"
|
||||
:src="item.image"
|
||||
class="carousel-images"
|
||||
@click="leaveForOpen(item.pathDetails)"
|
||||
/>
|
||||
</div>
|
||||
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
|
||||
<img
|
||||
v-for="item in slideshowList"
|
||||
:key="item.id"
|
||||
:src="item.image"
|
||||
class="carousel-images"
|
||||
@click="leaveForOpen(item.pathDetails)"
|
||||
/>
|
||||
<a-empty v-if="isEmpty(slideshowList)" :image="Empty.PRESENTED_IMAGE_SIMPLE" />
|
||||
</a-carousel>
|
||||
</a-card>
|
||||
</template>
|
||||
|
@ -57,18 +55,18 @@
|
|||
return
|
||||
}
|
||||
const detail = cloneDeep(value)
|
||||
let detailObj = {}
|
||||
let result = {}
|
||||
if (typeof detail !== 'object') {
|
||||
detailObj = JSON.parse(detail)
|
||||
result = JSON.parse(detail)
|
||||
}
|
||||
// json内包含且是开启了点击,否则不处理
|
||||
if (detailObj.whetherToClick && detailObj.whetherToClick === 'ENABLE') {
|
||||
if (detailObj.skipMode && detailObj.skipMode === 'URL') {
|
||||
window.open(detailObj.url)
|
||||
if (result.whetherToClick && result.whetherToClick === 'ENABLE') {
|
||||
if (result.skipMode && result.skipMode === 'URL') {
|
||||
window.open(result.url)
|
||||
}
|
||||
if (detailObj.skipMode && detailObj.skipMode === 'ROUTER') {
|
||||
if (result.skipMode && result.skipMode === 'ROUTER') {
|
||||
router.replace({
|
||||
path: detailObj.url
|
||||
path: result.url
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<template>
|
||||
<a-card :title="title" :bordered="false" :loading="apiLoading">
|
||||
<a-row>
|
||||
<!-- 因租户内定时任务需解决,暂先注释 -->
|
||||
<!--
|
||||
<a-col :span="4">
|
||||
<a-statistic :value="dataSource.jobCount">
|
||||
<template #title>
|
||||
|
@ -9,7 +11,8 @@
|
|||
</template>
|
||||
</a-statistic>
|
||||
</a-col>
|
||||
<a-col :span="4">
|
||||
-->
|
||||
<a-col :span="5">
|
||||
<a-statistic :value="dataSource.sysDictCount">
|
||||
<template #title>
|
||||
<read-outlined style="color: #4b4b4b" />
|
||||
|
@ -17,7 +20,7 @@
|
|||
</template>
|
||||
</a-statistic>
|
||||
</a-col>
|
||||
<a-col :span="4">
|
||||
<a-col :span="5">
|
||||
<a-statistic :value="dataSource.bizDictCount">
|
||||
<template #title>
|
||||
<read-outlined style="color: #353779" />
|
||||
|
@ -25,7 +28,7 @@
|
|||
</template>
|
||||
</a-statistic>
|
||||
</a-col>
|
||||
<a-col :span="4">
|
||||
<a-col :span="5">
|
||||
<a-statistic :value="dataSource.backUserSessionCount">
|
||||
<template #title>
|
||||
<usergroup-delete-outlined style="color: #3ceecd" />
|
||||
|
@ -33,7 +36,7 @@
|
|||
</template>
|
||||
</a-statistic>
|
||||
</a-col>
|
||||
<a-col :span="4">
|
||||
<a-col :span="5">
|
||||
<a-statistic :value="dataSource.clientUserSessionCount">
|
||||
<template #title>
|
||||
<UserSwitchOutlined style="color: rgba(229, 159, 18, 0.35)" />
|
||||
|
@ -58,7 +61,6 @@
|
|||
const title = ref('运维一览')
|
||||
const apiLoading = ref(false)
|
||||
const dataSource = ref({
|
||||
jobCount: 0,
|
||||
sysDictCount: 0,
|
||||
bizDictCount: 0,
|
||||
backUserSessionCount: 0,
|
||||
|
|
|
@ -1,19 +1,34 @@
|
|||
<template>
|
||||
<a-popconfirm title="批量处理此信息?" :open="batchVisible" @openChange="batchVisibleChange" @confirm="deleteBatch">
|
||||
<a-button :type="props.buttonType" :danger="props.buttonDanger" :size="props.size" :loading="buttonLoading">
|
||||
<div v-if="isPopconFirm">
|
||||
<a-popconfirm title="批量处理此信息?" :open="batchVisible" @openChange="batchVisibleChange" @confirm="deleteBatch">
|
||||
<a-button :type="props.buttonType" :danger="props.buttonDanger" :size="props.size" :loading="loading">
|
||||
<template #icon v-if="props.icon">
|
||||
<component :is="props.icon" :style="{ color: props.color }" />
|
||||
</template>
|
||||
{{ props.buttonName }}
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
</div>
|
||||
<div v-else>
|
||||
<a-button
|
||||
:type="props.buttonType"
|
||||
:danger="props.buttonDanger"
|
||||
:size="props.size"
|
||||
:loading="loading"
|
||||
@click="deleteBatch"
|
||||
>
|
||||
<template #icon v-if="props.icon">
|
||||
<component :is="props.icon" :style="{ color: props.color }" />
|
||||
</template>
|
||||
{{ props.buttonName }}
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="commonBatchButton">
|
||||
import { message } from 'ant-design-vue'
|
||||
const batchVisible = ref(false)
|
||||
const emit = defineEmits({ batchCallBack: null })
|
||||
const buttonLoading = ref(false)
|
||||
const props = defineProps({
|
||||
idKey: {
|
||||
type: String,
|
||||
|
@ -46,6 +61,15 @@
|
|||
color: {
|
||||
type: String,
|
||||
default: () => ''
|
||||
},
|
||||
// 是否确认提示
|
||||
isPopconFirm: {
|
||||
type: Boolean,
|
||||
default: () => true
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
}
|
||||
})
|
||||
// 参数校验
|
||||
|
@ -53,17 +77,26 @@
|
|||
if (batchVisible.value) {
|
||||
batchVisible.value = false
|
||||
return false
|
||||
}
|
||||
if (props.selectedRowKeys.length < 1) {
|
||||
message.warning('请选择一条或多条数据')
|
||||
batchVisible.value = false
|
||||
return false
|
||||
} else {
|
||||
batchVisible.value = true
|
||||
if (props.selectedRowKeys.length < 1) {
|
||||
message.warning('请选择一条或多条数据')
|
||||
batchVisible.value = false
|
||||
return false
|
||||
} else {
|
||||
batchVisible.value = true
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
// 批量操作
|
||||
const deleteBatch = () => {
|
||||
if (!props.isPopconFirm) {
|
||||
if (props.selectedRowKeys.length < 1) {
|
||||
message.warning('请选择一条或多条数据')
|
||||
batchVisible.value = false
|
||||
return false
|
||||
}
|
||||
}
|
||||
const params = props.selectedRowKeys.map((m) => {
|
||||
return {
|
||||
[props.idKey]: m
|
||||
|
@ -72,12 +105,4 @@
|
|||
// 发起方法调用,谁的谁来实现
|
||||
emit('batchCallBack', params)
|
||||
}
|
||||
// 打开loading
|
||||
const openLoading = () => {
|
||||
buttonLoading.value = true
|
||||
}
|
||||
// 关闭loading
|
||||
const closeLoading = () => {
|
||||
buttonLoading.value = true
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -55,10 +55,10 @@
|
|||
})
|
||||
const contentValue = ref()
|
||||
const init = ref({
|
||||
language_url: import.meta.env.BASE_URL + 'tinymce/langs/zh_CN.js',
|
||||
language_url: 'tinymce/langs/zh_CN.js',
|
||||
language: 'zh_CN',
|
||||
skin_url: import.meta.env.BASE_URL + 'tinymce/skins/ui/oxide',
|
||||
content_css: import.meta.env.BASE_URL + 'tinymce/skins/content/default/content.css',
|
||||
skin_url: 'tinymce/skins/ui/oxide',
|
||||
content_css: 'tinymce/skins/content/default/content.css',
|
||||
menubar: false,
|
||||
statusbar: true,
|
||||
plugins: props.plugins,
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
<script setup name="uploadIndex">
|
||||
import tool from '@/utils/tool'
|
||||
import sysConfig from '@/config/index'
|
||||
import { convertUrl } from '@/utils/apiAdaptive'
|
||||
import { message, Upload } from 'ant-design-vue'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
const fileList = ref([])
|
||||
|
@ -91,19 +92,19 @@
|
|||
// 上传返回id
|
||||
uploadReturnIdApi: {
|
||||
type: String,
|
||||
default: '/dev/file/uploadLocalReturnId',
|
||||
default: convertUrl('/dev/file/uploadLocalReturnId'),
|
||||
required: false
|
||||
},
|
||||
// 上传返回url
|
||||
uploadDynamicReturnUrlApi: {
|
||||
type: String,
|
||||
default: '/dev/file/uploadDynamicReturnUrl',
|
||||
default: convertUrl('/dev/file/uploadDynamicReturnUrl'),
|
||||
required: false
|
||||
},
|
||||
// 当上传接口为id的情况下,配置下载接口
|
||||
uploadIdDownloadUrl: {
|
||||
type: String,
|
||||
default: '/dev/file/download?id=',
|
||||
default: convertUrl('/dev/file/download?id='),
|
||||
required: false
|
||||
},
|
||||
// 上传样式或图片方式 file || drag || image
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
* 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
|
||||
*/
|
||||
const DEFAULT_CONFIG = {
|
||||
// 是否是微服务cloud版本
|
||||
CLOUD_SERVER: false,
|
||||
|
||||
// 首页地址
|
||||
DASHBOARD_URL: '/index',
|
||||
|
||||
|
@ -18,9 +21,6 @@ const DEFAULT_CONFIG = {
|
|||
// 请求超时
|
||||
TIMEOUT: 60000,
|
||||
|
||||
// 版本更新时间 默认10s
|
||||
UPDATE_VERSION_TIME: 10000,
|
||||
|
||||
// TokenName // Authorization
|
||||
TOKEN_NAME: 'token',
|
||||
|
||||
|
@ -46,7 +46,7 @@ const DEFAULT_CONFIG = {
|
|||
SNOWY_LAYOUT_TAGS_OPEN: true,
|
||||
|
||||
// 是否开启展示面包屑
|
||||
SNOWY_BREADCRUMD_OPEN: false,
|
||||
SNOWY_BREADCRUMB_OPEN: false,
|
||||
|
||||
// 顶栏是否应用主题色
|
||||
SNOWY_TOP_HEADER_THEME_COLOR_OPEN: false,
|
||||
|
@ -61,10 +61,10 @@ const DEFAULT_CONFIG = {
|
|||
SNOWY_LOGIN_USER_WATERMARK_OPEN: false,
|
||||
|
||||
// 页脚版权信息
|
||||
SNOWY_FOOTER_COPYRIGHT_OPEN: true,
|
||||
SNOWY_FOOTER_COPYRIGHT_OPEN: false,
|
||||
|
||||
// 圆角风格
|
||||
SNOWY_ROUNDED_CORNER_STYLE_OPEN: true,
|
||||
SNOWY_ROUNDED_CORNER_STYLE_OPEN: false,
|
||||
|
||||
// 语言
|
||||
LANG: 'zh-cn',
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
import router from '@/router'
|
||||
import { onMounted } from 'vue'
|
||||
import sysConfig from '@/config'
|
||||
import { convertUrl } from '@/utils/apiAdaptive'
|
||||
import { EventSourcePolyfill } from 'event-source-polyfill'
|
||||
import tool from '@/utils/tool'
|
||||
|
||||
|
@ -76,7 +77,7 @@
|
|||
const createSseConnect = () => {
|
||||
if (window.EventSource) {
|
||||
let clientId = tool.data.get('CLIENTID') ? tool.data.get('CLIENTID') : ''
|
||||
let url = sysConfig.API_URL + '/dev/message/createSseConnect?clientId=' + clientId
|
||||
let url = sysConfig.API_URL + convertUrl('/dev/message/createSseConnect?clientId=') + clientId
|
||||
// heartbeatTimeout:心跳超时监测 30s
|
||||
let source = new EventSourcePolyfill(url, {
|
||||
headers: { token: tool.data.get('TOKEN') },
|
||||
|
|
|
@ -53,7 +53,12 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<a-tab-pane v-for="tag in tagList" :key="tag.fullPath" :tab="tag.meta.title" :closable="!tag.meta.affix">
|
||||
<a-tab-pane v-for="tag in tagList" :key="tag.fullPath" :closable="!tag.meta.affix">
|
||||
<template #tab>
|
||||
<span :key="tag.meta.key">
|
||||
{{ tag.meta.title }}
|
||||
</span>
|
||||
</template>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
|
|
|
@ -88,7 +88,6 @@
|
|||
import sysConfig from '@/config/index'
|
||||
import dictApi from '@/api/dev/dictApi'
|
||||
|
||||
let timer = null
|
||||
const store = globalStore()
|
||||
const kStore = keepAliveStore()
|
||||
const route = useRoute()
|
||||
|
@ -265,52 +264,47 @@
|
|||
})
|
||||
})
|
||||
onBeforeUnmount(() => {
|
||||
clearUpdateVersion()
|
||||
window.removeEventListener('resize', onLayoutResize)
|
||||
window.removeEventListener('resize', getNav)
|
||||
})
|
||||
// 新版检测
|
||||
const updateVersion = () => {
|
||||
timer = setInterval(async () => {
|
||||
// 本地
|
||||
let localVersion = getLocalHash()
|
||||
// 线上
|
||||
let onlineVersion = await checkHash()
|
||||
// 如果不一样,提示更新
|
||||
if (localVersion !== onlineVersion) {
|
||||
if (document.querySelector('.notification-update-version')) {
|
||||
return
|
||||
const updateVersionOpen = import.meta.env.VITE_VERSION_UPDATE
|
||||
if (updateVersionOpen) {
|
||||
setTimeout(async () => {
|
||||
// 本地
|
||||
let localVersion = getLocalHash()
|
||||
// 线上
|
||||
let onlineVersion = await checkHash()
|
||||
// 如果不一样,提示更新
|
||||
if (localVersion !== onlineVersion) {
|
||||
if (document.querySelector('.notification-update-version')) {
|
||||
return
|
||||
}
|
||||
const key = `open${Date.now()}`
|
||||
notification.open({
|
||||
type: 'info',
|
||||
message: '发现新版本',
|
||||
description: '检测到新版本,请刷新后使用',
|
||||
duration: 0,
|
||||
class: 'notification-update-version',
|
||||
btn: () =>
|
||||
h(
|
||||
Button,
|
||||
{
|
||||
type: 'primary',
|
||||
size: 'small',
|
||||
onClick: () => {
|
||||
notification.close(key)
|
||||
window.location.reload()
|
||||
}
|
||||
},
|
||||
{ default: () => '立即更新' }
|
||||
),
|
||||
key
|
||||
})
|
||||
}
|
||||
const key = `open${Date.now()}`
|
||||
notification.open({
|
||||
type: 'info',
|
||||
message: '发现新版本',
|
||||
description: '检测到新版本,请刷新后使用',
|
||||
duration: 0,
|
||||
class: 'notification-update-version',
|
||||
btn: () =>
|
||||
h(
|
||||
Button,
|
||||
{
|
||||
type: 'primary',
|
||||
size: 'small',
|
||||
onClick: () => {
|
||||
notification.close(key)
|
||||
window.location.reload()
|
||||
}
|
||||
},
|
||||
{ default: () => '立即更新' }
|
||||
),
|
||||
key
|
||||
})
|
||||
}
|
||||
}, sysConfig.UPDATE_VERSION_TIME)
|
||||
}
|
||||
// 销毁定时器
|
||||
const clearUpdateVersion = () => {
|
||||
if (timer) {
|
||||
clearInterval(timer)
|
||||
timer = null
|
||||
}, 3000)
|
||||
}
|
||||
}
|
||||
// 动态获取横向导航栏隐藏数量
|
||||
|
@ -339,7 +333,7 @@
|
|||
menuList.value = menuNavList
|
||||
return
|
||||
}
|
||||
// 如果大于了课显示的区域,就将其隐藏
|
||||
// 如果大于了显示的区域,就将其隐藏
|
||||
const showNav = menuNavList.slice(0, startIndex)
|
||||
const hiddenNav = menuNavList.slice(startIndex, menuNavList.length)
|
||||
menuList.value = showNav
|
||||
|
|
|
@ -36,7 +36,7 @@ const routes_404 = [
|
|||
const routes = [...systemRouter, ...whiteListRouters, ...routes_404]
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
history: createWebHistory(),
|
||||
routes
|
||||
})
|
||||
|
||||
|
@ -45,7 +45,6 @@ const router = createRouter({
|
|||
|
||||
// 判断是否已加载过动态/静态路由
|
||||
const isGetRouter = ref(false)
|
||||
|
||||
// 白名单校验
|
||||
const exportWhiteListFromRouter = (router) => {
|
||||
const res = []
|
||||
|
@ -53,7 +52,6 @@ const exportWhiteListFromRouter = (router) => {
|
|||
return res
|
||||
}
|
||||
const whiteList = exportWhiteListFromRouter(whiteListRouters)
|
||||
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
NProgress.start()
|
||||
const store = globalStore()
|
||||
|
@ -70,7 +68,6 @@ router.beforeEach(async (to, from, next) => {
|
|||
// NProgress.done()
|
||||
return false
|
||||
}
|
||||
|
||||
if (!isGetRouter.value) {
|
||||
// 初始化菜单加载,代码位置不能变动
|
||||
const menuStore = useMenuStore()
|
||||
|
@ -102,6 +99,14 @@ router.beforeEach(async (to, from, next) => {
|
|||
if (token) {
|
||||
// 有token的时候才保存登录之前要访问的页面
|
||||
tool.data.set('LAST_VIEWS_PATH', to.fullPath)
|
||||
// 验证menu或则用户信息是否存在,不存在那么就是被删除或者退出或者清理缓存了
|
||||
if (!tool.data.get('MENU') || !tool.data.get('USER_INFO')) {
|
||||
tool.data.remove('TOKEN')
|
||||
next({
|
||||
path: '/login'
|
||||
})
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!token) {
|
||||
|
|
|
@ -40,7 +40,7 @@ export const globalStore = defineStore('global', () => {
|
|||
// 多标签栏
|
||||
const layoutTagsOpen = ref(getCacheConfig('SNOWY_LAYOUT_TAGS_OPEN'))
|
||||
// 是否展示面包屑
|
||||
const breadcrumbOpen = ref(getCacheConfig('SNOWY_BREADCRUMD_OPEN'))
|
||||
const breadcrumbOpen = ref(getCacheConfig('SNOWY_BREADCRUMB_OPEN'))
|
||||
// 是否开启固定宽度(顶栏菜单)
|
||||
const fixedWidth = ref(getCacheConfig('SNOWY_FIXEDWIDTH_OPEN'))
|
||||
// 顶栏是否应用主题色
|
||||
|
|
|
@ -69,6 +69,7 @@ export const viewTagsStore = defineStore('viewTags', () => {
|
|||
const nowFullPath = location.hash.substring(1)
|
||||
viewTags.value.forEach((item) => {
|
||||
if (item.fullPath === nowFullPath) {
|
||||
item.meta.key = Date.now()
|
||||
item.meta.title = title
|
||||
}
|
||||
})
|
||||
|
|
|
@ -116,7 +116,6 @@ a, button, input, textarea {
|
|||
|
||||
/* 头部 */
|
||||
.snowy-header {
|
||||
height: 50px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid var(--header-bottom);
|
||||
|
@ -481,6 +480,11 @@ body,
|
|||
.snowy-theme-dark .odd {
|
||||
background-color: #1d1d1d
|
||||
}
|
||||
// 解决浏览器F12爆红aria-hidden问题
|
||||
.ant-modal div[aria-hidden="true"] {
|
||||
display: none !important
|
||||
}
|
||||
|
||||
// 以下是重写表单设计器的样式
|
||||
.list-main {
|
||||
background: var(--auto-judge-before-color) !important;
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
import config from '@/config'
|
||||
// 业务自己新加了模块,当然只限制于微服务情况下,单体不用管
|
||||
const bizCustomization = [
|
||||
{
|
||||
label: '/custom/',
|
||||
value: '/custom/'
|
||||
}
|
||||
]
|
||||
// 微服务环境下如果拆分为多个代码模块,那他的url是网关转发,这里就要配置
|
||||
const PREFIX = [
|
||||
{
|
||||
label: '/mobile/',
|
||||
value: '/api/webapp'
|
||||
},
|
||||
{
|
||||
label: '/sys/',
|
||||
value: '/api/webapp'
|
||||
},
|
||||
{
|
||||
label: '/auth/',
|
||||
value: '/api/webapp'
|
||||
},
|
||||
{
|
||||
label: '/client/',
|
||||
value: '/api/webapp'
|
||||
},
|
||||
{
|
||||
label: '/dev/',
|
||||
value: '/api/webapp'
|
||||
},
|
||||
{
|
||||
label: '/gen/',
|
||||
value: '/api/webapp'
|
||||
},
|
||||
{
|
||||
label: '/biz/',
|
||||
value: '/api/bizapp'
|
||||
}
|
||||
]
|
||||
// 转换url
|
||||
export const convertUrl = (url) => {
|
||||
if (config.CLOUD_SERVER === false) {
|
||||
return url
|
||||
}
|
||||
const apiArray = [...PREFIX, ...bizCustomization]
|
||||
const prefixUrlArray = apiArray.filter((f) => url.indexOf(f.label) > -1)
|
||||
if (prefixUrlArray && prefixUrlArray.length > 0) {
|
||||
return prefixUrlArray[0].value + url
|
||||
}
|
||||
return url
|
||||
}
|
|
@ -24,6 +24,6 @@ export default (error) => {
|
|||
}
|
||||
const errorName = errorMap[error.name] || '未知错误'
|
||||
nextTick(() => {
|
||||
console.error(errorName)
|
||||
console.error(errorName + ' ' + error)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import qs from 'qs'
|
|||
import { Modal, message } from 'ant-design-vue'
|
||||
import sysConfig from '@/config/index'
|
||||
import tool from '@/utils/tool'
|
||||
import { convertUrl } from './apiAdaptive'
|
||||
|
||||
// 以下这些code需要重新登录
|
||||
const reloadCodes = [401, 1011007, 1011008]
|
||||
|
@ -108,7 +109,7 @@ service.interceptors.response.use(
|
|||
// }
|
||||
} else {
|
||||
// 统一成功提示
|
||||
const responseUrls = response.config.url.split('/')
|
||||
const functionName = response.config.url.split('/').pop()
|
||||
const apiNameArray = [
|
||||
'add',
|
||||
'edit',
|
||||
|
@ -129,7 +130,8 @@ service.interceptors.response.use(
|
|||
'saveDraft'
|
||||
]
|
||||
apiNameArray.forEach((apiName) => {
|
||||
if (responseUrls[responseUrls.length - 1] === apiName) {
|
||||
// 上面去掉接口路径后,方法内包含内置的进行统一提示成功
|
||||
if (functionName.includes(apiName)) {
|
||||
message.success(data.msg)
|
||||
}
|
||||
})
|
||||
|
@ -151,7 +153,7 @@ service.interceptors.response.use(
|
|||
|
||||
// 适配器, 用于适配不同的请求方式
|
||||
export const baseRequest = (url, value = {}, method = 'post', options = {}) => {
|
||||
url = sysConfig.API_URL + url
|
||||
url = sysConfig.API_URL + convertUrl(url)
|
||||
if (method === 'post') {
|
||||
return service.post(url, value, options)
|
||||
} else if (method === 'get') {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<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="标题">{{ 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) }}
|
||||
|
@ -15,7 +15,7 @@
|
|||
</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;" />
|
||||
<a-image :src="formData.image" style="width: 100px; height: 50px; margin-bottom: -10px; margin-top: -10px" />
|
||||
</div>
|
||||
<span v-else>未上传</span>
|
||||
</a-descriptions-item>
|
||||
|
@ -23,8 +23,12 @@
|
|||
</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="备注"
|
||||
><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">
|
||||
|
@ -32,48 +36,56 @@
|
|||
</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-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 #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 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 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 {
|
||||
} else {
|
||||
message.warning('未查到该信息')
|
||||
}
|
||||
}
|
||||
// 关闭抽屉
|
||||
const onClose = () => {
|
||||
formData.value = {}
|
||||
open.value = false
|
||||
}
|
||||
// 抛出函数
|
||||
defineExpose({
|
||||
onOpen
|
||||
})
|
||||
}
|
||||
// 关闭抽屉
|
||||
const onClose = () => {
|
||||
formData.value = {}
|
||||
open.value = false
|
||||
}
|
||||
// 抛出函数
|
||||
defineExpose({
|
||||
onOpen
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -1,35 +1,33 @@
|
|||
<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>
|
||||
<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>
|
||||
<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">
|
||||
</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-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="内容:" name="content">
|
||||
<xn-editor v-model:value="formData.content" placeholder="请输入内容" />
|
||||
|
@ -46,11 +44,11 @@
|
|||
/>
|
||||
</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="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
|
||||
|
@ -61,88 +59,92 @@
|
|||
/>
|
||||
</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>
|
||||
<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([])
|
||||
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 {
|
||||
// 打开抽屉
|
||||
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('请选择发布位置')],
|
||||
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
|
||||
})
|
||||
}
|
||||
// 验证并提交数据
|
||||
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>
|
||||
|
|
|
@ -1,73 +1,76 @@
|
|||
<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 }">
|
||||
<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-button
|
||||
v-if="hasPerm('bizNoticeBatchDelete')"
|
||||
buttonName="批量删除"
|
||||
icon="DeleteOutlined"
|
||||
buttonDanger
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
@batchCallBack="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;" />
|
||||
<a-image :src="record.image" style="width: 30px; height: 30px" />
|
||||
</div>
|
||||
<span v-else>未上传</span>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'type'">
|
||||
<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>
|
||||
|
@ -78,12 +81,12 @@
|
|||
{{ $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">
|
||||
</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>
|
||||
<template v-if="column.dataIndex === 'status'">
|
||||
<a-switch
|
||||
:loading="loading"
|
||||
|
@ -93,134 +96,134 @@
|
|||
/>
|
||||
<span v-else>{{ $TOOL.dictTypeData('BIZ_NOTICE_STATUS', record.status) }}</span>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<a-space>
|
||||
<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()" />
|
||||
<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 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()
|
||||
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 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',
|
||||
// 查询区域显示更多控制
|
||||
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: 'type'
|
||||
},
|
||||
{
|
||||
title: '发布位置',
|
||||
dataIndex: 'place'
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sortCode',
|
||||
sorter: true
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status'
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
{
|
||||
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()
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
// 操作栏通过权限判断是否显示
|
||||
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
|
||||
|
@ -244,7 +247,7 @@
|
|||
})
|
||||
}
|
||||
}
|
||||
const typeOptions = tool.dictList('BIZ_NOTICE_TYPE')
|
||||
const placeOptions = tool.dictList('BIZ_NOTICE_PLACE')
|
||||
const statusOptions = tool.dictList('BIZ_NOTICE_STATUS')
|
||||
const typeOptions = tool.dictList('BIZ_NOTICE_TYPE')
|
||||
const placeOptions = tool.dictList('BIZ_NOTICE_PLACE')
|
||||
const statusOptions = tool.dictList('BIZ_NOTICE_STATUS')
|
||||
</script>
|
||||
|
|
|
@ -57,10 +57,13 @@
|
|||
<template #icon><plus-outlined /></template>
|
||||
新增
|
||||
</a-button>
|
||||
<xn-batch-delete
|
||||
<xn-batch-button
|
||||
v-if="hasPerm('bizOrgBatchDelete')"
|
||||
buttonName="批量删除"
|
||||
icon="DeleteOutlined"
|
||||
buttonDanger
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
@batchDelete="deleteBatchOrg"
|
||||
@batchCallBack="deleteBatchOrg"
|
||||
/>
|
||||
</a-space>
|
||||
</template>
|
||||
|
|
|
@ -57,10 +57,13 @@
|
|||
<template #icon><plus-outlined /></template>
|
||||
新增
|
||||
</a-button>
|
||||
<xn-batch-delete
|
||||
<xn-batch-button
|
||||
v-if="hasPerm('bizPositionBatchDelete')"
|
||||
buttonName="批量删除"
|
||||
icon="DeleteOutlined"
|
||||
buttonDanger
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
@batchDelete="deleteBatchPosition"
|
||||
@batchCallBack="deleteBatchPosition"
|
||||
/>
|
||||
</a-space>
|
||||
</template>
|
||||
|
|
|
@ -77,11 +77,13 @@
|
|||
<template #icon><export-outlined /></template>
|
||||
{{ $t('user.batchExportButton') }}
|
||||
</a-button>
|
||||
<xn-batch-delete
|
||||
<xn-batch-button
|
||||
v-if="hasPerm('bizUserBatchDelete')"
|
||||
:buttonName="$t('common.batchRemoveButton')"
|
||||
icon="DeleteOutlined"
|
||||
buttonDanger
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
@batchDelete="deleteBatchUser"
|
||||
@batchCallBack="deleteBatchUser"
|
||||
/>
|
||||
</a-space>
|
||||
</template>
|
||||
|
|
|
@ -183,14 +183,10 @@
|
|||
id: record.id
|
||||
}
|
||||
]
|
||||
dictApi.dictDelete(params).then((res) => {
|
||||
if (res.code === 200) {
|
||||
tableRef.value.refresh(true)
|
||||
} else {
|
||||
res.message && tool.error(res.message)
|
||||
}
|
||||
dictApi.dictDelete(params).then(() => {
|
||||
tableRef.value.refresh()
|
||||
refreshStoreDict()
|
||||
})
|
||||
refreshStoreDict()
|
||||
}
|
||||
// 表单界面回调
|
||||
const formSuccessful = () => {
|
||||
|
|
|
@ -48,7 +48,13 @@
|
|||
<UploadOutlined />
|
||||
文件上传
|
||||
</a-button>
|
||||
<xn-batch-delete :selectedRowKeys="selectedRowKeys" @batchDelete="deleteBatchFile" />
|
||||
<xn-batch-button
|
||||
buttonName="批量删除"
|
||||
icon="DeleteOutlined"
|
||||
buttonDanger
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
@batchCallBack="deleteBatchFile"
|
||||
/>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
|
|
|
@ -19,6 +19,14 @@
|
|||
<a-form-item ref="cronExpressionRef" label="表达式:" name="cronExpression">
|
||||
<cron v-model:modelValue="formData.cronExpression" />
|
||||
</a-form-item>
|
||||
<a-form-item label="扩展参数:" name="extJson">
|
||||
<a-textarea
|
||||
v-model:value="formData.extJson"
|
||||
placeholder="请输入定时扩展参数"
|
||||
:auto-size="{ minRows: 2, maxRows: 5 }"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="排序:" name="sortCode">
|
||||
<a-input-number class="xn-wd" v-model:value="formData.sortCode" :max="100" />
|
||||
</a-form-item>
|
||||
|
@ -54,7 +62,18 @@
|
|||
sortCode: 99
|
||||
}
|
||||
if (record) {
|
||||
formData.value = Object.assign({}, record)
|
||||
submitLoading.value = true
|
||||
const param = {
|
||||
id: record.id
|
||||
}
|
||||
jobApi
|
||||
.jobDetail(param)
|
||||
.then((data) => {
|
||||
formData.value = Object.assign({}, data)
|
||||
})
|
||||
.finally(() => {
|
||||
submitLoading.value = false
|
||||
})
|
||||
}
|
||||
// 加载定时任务类列表
|
||||
jobApi.jobGetActionClass().then((data) => {
|
||||
|
|
|
@ -51,7 +51,13 @@
|
|||
<template #icon><plus-outlined /></template>
|
||||
新增
|
||||
</a-button>
|
||||
<xn-batch-delete :selectedRowKeys="selectedRowKeys" @batchDelete="deleteBatchJob" />
|
||||
<xn-batch-button
|
||||
buttonName="批量删除"
|
||||
icon="DeleteOutlined"
|
||||
buttonDanger
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
@batchCallBack="deleteBatchJob"
|
||||
/>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
|
|
|
@ -34,7 +34,13 @@
|
|||
<template #operator class="table-operator">
|
||||
<a-space>
|
||||
<a-button type="primary" @click="formRef.onOpen()"> 发送站内信 </a-button>
|
||||
<xn-batch-delete :selectedRowKeys="selectedRowKeys" @batchDelete="deleteBatchEmail" />
|
||||
<xn-batch-button
|
||||
buttonName="批量删除"
|
||||
icon="DeleteOutlined"
|
||||
buttonDanger
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
@batchCallBack="deleteBatchEmail"
|
||||
/>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
|
|
|
@ -1,90 +1,89 @@
|
|||
<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>
|
||||
<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-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-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">
|
||||
</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>
|
||||
</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 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 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 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)
|
||||
// 打开抽屉
|
||||
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 = 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(() => {
|
||||
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()
|
||||
|
@ -92,20 +91,20 @@
|
|||
return
|
||||
}
|
||||
formDataParam.pathDetails = JSON.stringify(details)
|
||||
submitLoading.value = true
|
||||
submitLoading.value = true
|
||||
slideshowApi
|
||||
.devSlideshowSubmitForm(formDataParam, formDataParam.id)
|
||||
.then(() => {
|
||||
onClose()
|
||||
emit('successful')
|
||||
})
|
||||
.finally(() => {
|
||||
submitLoading.value = false
|
||||
})
|
||||
})
|
||||
}
|
||||
// 抛出函数
|
||||
defineExpose({
|
||||
onOpen
|
||||
})
|
||||
.devSlideshowSubmitForm(formDataParam, formDataParam.id)
|
||||
.then(() => {
|
||||
onClose()
|
||||
emit('successful')
|
||||
})
|
||||
.finally(() => {
|
||||
submitLoading.value = false
|
||||
})
|
||||
})
|
||||
}
|
||||
// 抛出函数
|
||||
defineExpose({
|
||||
onOpen
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -1,38 +1,38 @@
|
|||
<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-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"
|
||||
>
|
||||
</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>
|
||||
|
@ -59,24 +59,29 @@
|
|||
</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 #operator class="table-operator">
|
||||
<a-space>
|
||||
<a-button type="primary" @click="formRef.onOpen()">
|
||||
<template #icon><plus-outlined /></template>
|
||||
新增
|
||||
</a-button>
|
||||
<xn-batch-button
|
||||
buttonName="批量删除"
|
||||
icon="DeleteOutlined"
|
||||
buttonDanger
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
@batchCallBack="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;" />
|
||||
<a-image :src="record.image" style="width: 50px; height: 30px" />
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'status'">
|
||||
<a-switch
|
||||
|
@ -86,62 +91,61 @@
|
|||
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 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()
|
||||
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'
|
||||
},
|
||||
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',
|
||||
{
|
||||
title: '展示位置',
|
||||
dataIndex: 'place'
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status'
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sortCode',
|
||||
sorter: true
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
align: 'center',
|
||||
width: '150px'
|
||||
}
|
||||
]
|
||||
]
|
||||
const detailsColumns = [
|
||||
{
|
||||
title: '位置',
|
||||
|
@ -161,50 +165,50 @@
|
|||
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
|
||||
}
|
||||
]
|
||||
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) => {
|
||||
tableRef.value.refresh()
|
||||
})
|
||||
}
|
||||
// 批量删除
|
||||
const deleteBatchDevSlideshow = (params) => {
|
||||
slideshowApi.devSlideshowDelete(params).then(() => {
|
||||
tableRef.value.clearRefreshSelected()
|
||||
})
|
||||
}
|
||||
tableRef.value.clearRefreshSelected()
|
||||
})
|
||||
}
|
||||
// 修改状态
|
||||
const editStatus = (record) => {
|
||||
loading.value = true
|
||||
|
@ -228,6 +232,6 @@
|
|||
})
|
||||
}
|
||||
}
|
||||
const placeOptions = tool.dictList('DEV_SLIDESHOW_PLACE')
|
||||
const placeOptions = tool.dictList('DEV_SLIDESHOW_PLACE')
|
||||
const statusOptions = tool.dictList('DEV_SLIDESHOW_STATUS')
|
||||
</script>
|
||||
|
|
|
@ -1,25 +1,33 @@
|
|||
<template>
|
||||
<a-form
|
||||
:model="formData"
|
||||
ref="formRef"
|
||||
name="basic"
|
||||
autocomplete="off"
|
||||
>
|
||||
<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 #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-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-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-input
|
||||
v-model:value="formData[index].url"
|
||||
:disabled="record.whetherToClick === 'DISABLE'"
|
||||
placeholder="请输入URL或路由地址"
|
||||
/>
|
||||
</a-form-item>
|
||||
</template>
|
||||
</template>
|
||||
|
@ -28,7 +36,7 @@
|
|||
</template>
|
||||
|
||||
<script name="subForm" setup>
|
||||
import tool from "@/utils/tool"
|
||||
import tool from '@/utils/tool'
|
||||
import { remove, isEmpty, cloneDeep } from 'lodash-es'
|
||||
const formRef = ref()
|
||||
const formData = ref([])
|
||||
|
@ -48,17 +56,17 @@
|
|||
{
|
||||
title: '位置',
|
||||
dataIndex: 'label',
|
||||
width: '20%',
|
||||
width: '20%'
|
||||
},
|
||||
{
|
||||
title: '点击事件',
|
||||
dataIndex: 'whetherToClick',
|
||||
width: '25%',
|
||||
width: '25%'
|
||||
},
|
||||
{
|
||||
title: '跳转方式',
|
||||
dataIndex: 'skipMode',
|
||||
width: '20%',
|
||||
width: '20%'
|
||||
},
|
||||
{
|
||||
title: 'URL',
|
||||
|
@ -77,7 +85,7 @@
|
|||
const dataFiltrate = (newVal, oldVal) => {
|
||||
let result = ''
|
||||
oldVal.forEach((data) => {
|
||||
if (!newVal.some(item => item === data)) {
|
||||
if (!newVal.some((item) => item === data)) {
|
||||
result = data
|
||||
}
|
||||
})
|
||||
|
@ -89,11 +97,11 @@
|
|||
if (!isEmpty(props.dataArray) && isEmpty(formData.value)) {
|
||||
formData.value = cloneDeep(props.dataArray)
|
||||
} else {
|
||||
if (typeof newVal === "object") {
|
||||
if (typeof newVal === 'object') {
|
||||
if (!isEmpty(formData.value)) {
|
||||
formData.value.forEach(() => {
|
||||
// 如果包含
|
||||
if (!newVal.some(item => item === item.key)) {
|
||||
if (!newVal.some((item) => item === item.key)) {
|
||||
// 需要减少的
|
||||
if (formData.value.length > newVal.length) {
|
||||
const deleteData = dataFiltrate(newVal, oldVal)
|
||||
|
@ -103,10 +111,10 @@
|
|||
if (formData.value.length < newVal.length) {
|
||||
const deleteData = dataFiltrate(oldVal, newVal)
|
||||
// 如果没有,就不增加
|
||||
if (!formData.value.some(item => item === deleteData)) {
|
||||
if (!formData.value.some((item) => item === deleteData)) {
|
||||
const obj = {
|
||||
key: deleteData,
|
||||
label: tool.dictTypeData('DEV_SLIDESHOW_PLACE' , deleteData),
|
||||
label: tool.dictTypeData('DEV_SLIDESHOW_PLACE', deleteData),
|
||||
whetherToClick: 'DISABLE',
|
||||
skipMode: 'URL',
|
||||
url: ''
|
||||
|
@ -120,7 +128,7 @@
|
|||
newVal.forEach((item) => {
|
||||
const obj = {
|
||||
key: item,
|
||||
label: tool.dictTypeData('DEV_SLIDESHOW_PLACE' , item),
|
||||
label: tool.dictTypeData('DEV_SLIDESHOW_PLACE', item),
|
||||
whetherToClick: 'DISABLE',
|
||||
skipMode: 'URL',
|
||||
url: ''
|
||||
|
|
|
@ -48,7 +48,13 @@
|
|||
<template #icon><plus-outlined /></template>
|
||||
发送短信
|
||||
</a-button>
|
||||
<xn-batch-delete :selectedRowKeys="selectedRowKeys" @batchDelete="deleteBatchSms" />
|
||||
<xn-batch-button
|
||||
buttonName="批量删除"
|
||||
icon="DeleteOutlined"
|
||||
buttonDanger
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
@batchCallBack="deleteBatchSms"
|
||||
/>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
|
|
|
@ -180,7 +180,6 @@
|
|||
|
||||
<script setup name="genBasic">
|
||||
import { required } from '@/utils/formRules'
|
||||
import tool from '@/utils/tool'
|
||||
import genBasicApi from '@/api/gen/genBasicApi'
|
||||
const formRef = ref()
|
||||
// 表单数据
|
||||
|
@ -235,10 +234,14 @@
|
|||
// 打开抽屉
|
||||
const onOpen = (record) => {
|
||||
// 加载默认的模块
|
||||
moduleOptions.value = tool.data.get('MENU').map((item) => {
|
||||
return {
|
||||
label: item.name,
|
||||
value: item.id
|
||||
genBasicApi.basicModuleSelector().then((data) => {
|
||||
if (data) {
|
||||
moduleOptions.value = data.map((item) => {
|
||||
return {
|
||||
label: item.name,
|
||||
value: item.id
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
// 获取数据库中的所有表
|
||||
|
@ -324,19 +327,22 @@
|
|||
formData.value.menuPid = undefined
|
||||
}
|
||||
// 加载默认的模块
|
||||
const menuTree = tool.data.get('MENU').find((item) => {
|
||||
if (item.id === value) {
|
||||
return item
|
||||
}
|
||||
})
|
||||
menuTreeData.value = [
|
||||
{
|
||||
id: '0',
|
||||
title: '顶级',
|
||||
menuType: 'CATALOG',
|
||||
children: traverseChildren(menuTree.children)
|
||||
children: []
|
||||
}
|
||||
]
|
||||
const param = {
|
||||
module: value
|
||||
}
|
||||
genBasicApi.basicMenuTreeSelector(param).then((data) => {
|
||||
if (data) {
|
||||
menuTreeData.value[0].children = traverseChildren(data)
|
||||
}
|
||||
})
|
||||
}
|
||||
// 遍历增加属性
|
||||
const traverseChildren = (data = []) => {
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
<span v-else>无</span>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'whetherTable'">
|
||||
<a-checkbox v-model:checked="record.whetherTable" @change="whetherTableChange(record)"/>
|
||||
<a-checkbox v-model:checked="record.whetherTable" @change="whetherTableChange(record)" />
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'whetherRetract'">
|
||||
<a-checkbox v-model:checked="record.whetherRetract" :disabled="!record.whetherTable" />
|
||||
|
|
|
@ -17,7 +17,13 @@
|
|||
<template #icon><plus-outlined /></template>
|
||||
新建
|
||||
</a-button>
|
||||
<xn-batch-delete :selectedRowKeys="selectedRowKeys" @batchDelete="deleteBatchCodeGen" />
|
||||
<xn-batch-button
|
||||
buttonName="批量删除"
|
||||
icon="DeleteOutlined"
|
||||
buttonDanger
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
@batchCallBack="deleteBatchCodeGen"
|
||||
/>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
|
|
|
@ -41,7 +41,13 @@
|
|||
<template #icon><plus-outlined /></template>
|
||||
新增
|
||||
</a-button>
|
||||
<xn-batch-delete :selectedRowKeys="selectedRowKeys" @batchDelete="deleteBatchMobileMenu" />
|
||||
<xn-batch-button
|
||||
buttonName="批量删除"
|
||||
icon="DeleteOutlined"
|
||||
buttonDanger
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
@batchCallBack="deleteBatchMobileMenu"
|
||||
/>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
|
|
|
@ -33,7 +33,13 @@
|
|||
</template>
|
||||
新增模块
|
||||
</a-button>
|
||||
<xn-batch-delete :selectedRowKeys="selectedRowKeys" @batchDelete="deleteBatchModule" />
|
||||
<xn-batch-button
|
||||
buttonName="批量删除"
|
||||
icon="DeleteOutlined"
|
||||
buttonDanger
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
@batchCallBack="deleteBatchModule"
|
||||
/>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
|
|
|
@ -51,7 +51,13 @@
|
|||
<template #icon><plus-outlined /></template>
|
||||
新增
|
||||
</a-button>
|
||||
<xn-batch-delete :selectedRowKeys="selectedRowKeys" @batchDelete="deleteBatchOrg" />
|
||||
<xn-batch-button
|
||||
buttonName="批量删除"
|
||||
icon="DeleteOutlined"
|
||||
buttonDanger
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
@batchCallBack="deleteBatchOrg"
|
||||
/>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
|
|
|
@ -52,7 +52,13 @@
|
|||
<template #icon><plus-outlined /></template>
|
||||
新增
|
||||
</a-button>
|
||||
<xn-batch-delete :selectedRowKeys="selectedRowKeys" @batchDelete="deleteBatchPosition" />
|
||||
<xn-batch-button
|
||||
buttonName="批量删除"
|
||||
icon="DeleteOutlined"
|
||||
buttonDanger
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
@batchCallBack="deleteBatchPosition"
|
||||
/>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
|
|
|
@ -40,9 +40,23 @@
|
|||
<template #icon><plus-outlined /></template>
|
||||
新增菜单
|
||||
</a-button>
|
||||
<xn-batch-delete :selectedRowKeys="selectedRowKeys" @batchDelete="deleteBatchMenu" />
|
||||
<xn-batch-button
|
||||
buttonName="批量删除"
|
||||
icon="DeleteOutlined"
|
||||
buttonDanger
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
@batchCallBack="deleteBatchMenu"
|
||||
/>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #headerCell="{ title, column }">
|
||||
<template v-if="column.dataIndex === 'visible'">
|
||||
<a-tooltip>
|
||||
<template #title> 如果将上级目录设置为隐藏,那么上级目录下的菜单都会被隐藏! </template>
|
||||
<question-circle-outlined />  {{ title }}
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'path'">
|
||||
<span v-if="record.menuType === 'MENU'">{{ record.path }}</span>
|
||||
|
@ -133,12 +147,12 @@
|
|||
const columns = [
|
||||
{
|
||||
title: '显示名称',
|
||||
dataIndex: 'title',
|
||||
width: 260
|
||||
dataIndex: 'title'
|
||||
},
|
||||
{
|
||||
title: '图标',
|
||||
dataIndex: 'icon'
|
||||
dataIndex: 'icon',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '类型',
|
||||
|
@ -160,12 +174,13 @@
|
|||
{
|
||||
title: '是否可见',
|
||||
dataIndex: 'visible',
|
||||
width: 100
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sortCode',
|
||||
sorter: true
|
||||
sorter: true,
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
|
|
|
@ -31,7 +31,13 @@
|
|||
<template #icon><plus-outlined /></template>
|
||||
新增模块
|
||||
</a-button>
|
||||
<xn-batch-delete :selectedRowKeys="selectedRowKeys" @batchDelete="deleteBatchModule" />
|
||||
<xn-batch-button
|
||||
buttonName="批量删除"
|
||||
icon="DeleteOutlined"
|
||||
buttonDanger
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
@batchCallBack="deleteBatchModule"
|
||||
/>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
|
|
|
@ -56,7 +56,13 @@
|
|||
<template #icon><plus-outlined /></template>
|
||||
新增角色
|
||||
</a-button>
|
||||
<xn-batch-delete :selectedRowKeys="selectedRowKeys" @batchDelete="deleteBatchRole" />
|
||||
<xn-batch-button
|
||||
buttonName="批量删除"
|
||||
icon="DeleteOutlined"
|
||||
buttonDanger
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
@batchCallBack="deleteBatchRole"
|
||||
/>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
|
|
|
@ -76,10 +76,12 @@
|
|||
<template #icon><export-outlined /></template>
|
||||
{{ $t('user.batchExportButton') }}
|
||||
</a-button>
|
||||
<xn-batch-delete
|
||||
<xn-batch-button
|
||||
:buttonName="$t('common.batchRemoveButton')"
|
||||
icon="DeleteOutlined"
|
||||
buttonDanger
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
@batchDelete="deleteBatchUser"
|
||||
@batchCallBack="deleteBatchUser"
|
||||
/>
|
||||
</a-space>
|
||||
</template>
|
||||
|
|
|
@ -33,7 +33,7 @@ public enum CommonSortOrderEnum {
|
|||
private final String value;
|
||||
|
||||
CommonSortOrderEnum(String value) {
|
||||
this.value = value.toUpperCase();
|
||||
this.value = value.toLowerCase();
|
||||
}
|
||||
|
||||
public static void validate(String value) {
|
||||
|
|
|
@ -26,5 +26,5 @@ public interface CommonTimerTaskRunner {
|
|||
* @author xuyuxiang
|
||||
* @date 2022/8/15 16:09
|
||||
**/
|
||||
void action();
|
||||
void action(String extJson);
|
||||
}
|
||||
|
|
|
@ -61,9 +61,9 @@ public class CommonNetWorkInfoUtil {
|
|||
input = new BufferedReader(new InputStreamReader(pro.getInputStream()));
|
||||
long[] result2 = readInLine(input, isWindows);
|
||||
String upSpeed = FileUtil.readableFileSize(Convert.toLong(NumberUtil
|
||||
.div(NumberUtil.sub(result2[0], result1[0]), SLEEP_SECONDS)));
|
||||
String downSpeed = FileUtil.readableFileSize(Convert.toLong(NumberUtil
|
||||
.div(NumberUtil.sub(result2[1], result1[1]), SLEEP_SECONDS)));
|
||||
String downSpeed = FileUtil.readableFileSize(Convert.toLong(NumberUtil
|
||||
.div(NumberUtil.sub(result2[0], result1[0]), SLEEP_SECONDS)));
|
||||
result.put("UP", upSpeed + (upSpeed.endsWith("B")?"/S":"B/S"));
|
||||
result.put("DOWN", downSpeed + (downSpeed.endsWith("B")?"/S":"B/S"));
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -12,6 +12,10 @@
|
|||
*/
|
||||
package vip.xiaonuo.sys.api;
|
||||
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 菜单API
|
||||
*
|
||||
|
@ -27,4 +31,12 @@ public interface SysMenuApi {
|
|||
* @date 2022/11/1 13:48
|
||||
**/
|
||||
String addForGenMenu(String parentId, String busName, String module, String title, String path);
|
||||
|
||||
/**
|
||||
* 获取所有菜单树包括未授权的
|
||||
*
|
||||
* @author yubaoshan
|
||||
* @date 2024/9/6 01:24
|
||||
**/
|
||||
List<Tree<String>> menuTreeSelector(String module);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright [2022] [https://www.xiaonuo.vip]
|
||||
*
|
||||
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
|
||||
*
|
||||
* 1.请不要删除和修改根目录下的LICENSE文件。
|
||||
* 2.请不要删除和修改Snowy源码头部的版权声明。
|
||||
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
|
||||
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
|
||||
* 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
|
||||
* 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
|
||||
*/
|
||||
package vip.xiaonuo.sys.api;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 模块API
|
||||
*
|
||||
* @author yubaoshan
|
||||
* @date 2024/9/6 01:24
|
||||
**/
|
||||
public interface SysModuleApi {
|
||||
|
||||
/**
|
||||
* 获取所有模块
|
||||
*
|
||||
* @author yubaoshan
|
||||
* @date 2024/9/6 01:24
|
||||
**/
|
||||
List<JSONObject> moduleSelector();
|
||||
}
|
|
@ -44,7 +44,7 @@ public class DevJobListener implements ApplicationListener<ApplicationStartedEve
|
|||
.forEach(devJob -> CronUtil.schedule(devJob.getId(), devJob.getCronExpression(), () -> {
|
||||
try {
|
||||
// 运行定时任务
|
||||
((CommonTimerTaskRunner) SpringUtil.getBean(Class.forName(devJob.getActionClass()))).action();
|
||||
((CommonTimerTaskRunner) SpringUtil.getBean(Class.forName(devJob.getActionClass()))).action(devJob.getExtJson());
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new CommonException("定时任务找不到对应的类,名称为:{}", devJob.getActionClass());
|
||||
}
|
||||
|
|
|
@ -61,8 +61,9 @@ public class DevApiProvider implements DevApi {
|
|||
DevDictCategoryEnum.FRM.getValue()));
|
||||
Long bizDictCount = devDictService.count(new LambdaQueryWrapper<DevDict>().eq(DevDict::getCategory,
|
||||
DevDictCategoryEnum.BIZ.getValue()));
|
||||
Long jobCount = devJobService.count(new LambdaQueryWrapper<DevJob>().eq(DevJob::getJobStatus,
|
||||
DevJobStatusEnum.RUNNING.getValue()));
|
||||
Long jobCount = 0L;
|
||||
// Long jobCount = devJobService.count(new LambdaQueryWrapper<DevJob>().eq(DevJob::getJobStatus,
|
||||
// DevJobStatusEnum.RUNNING.getValue()));
|
||||
JSONObject json = new JSONObject();
|
||||
json.set("sysDictCount", sysDictCount);
|
||||
json.set("bizDictCount", bizDictCount);
|
||||
|
|
|
@ -70,7 +70,7 @@ public class DevEmailAliyunUtil {
|
|||
}
|
||||
|
||||
try {
|
||||
client = new Client(new Config().setRegionId(regionId).setAccessKeyId(accessKeyId).setAccessKeySecret(accessKeySecret));
|
||||
client = new Client(new Config().setRegionId(regionId).setEndpoint("dm.aliyuncs.com").setAccessKeyId(accessKeyId).setAccessKeySecret(accessKeySecret));
|
||||
} catch (Exception e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
|
|
|
@ -214,7 +214,7 @@ public class DevJobServiceImpl extends ServiceImpl<DevJobMapper, DevJob> impleme
|
|||
CronUtil.schedule(devJob.getId(), devJob.getCronExpression(), () -> {
|
||||
try {
|
||||
// 运行定时任务
|
||||
((CommonTimerTaskRunner) SpringUtil.getBean(Class.forName(devJob.getActionClass()))).action();
|
||||
((CommonTimerTaskRunner) SpringUtil.getBean(Class.forName(devJob.getActionClass()))).action(devJob.getExtJson());
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new CommonException("定时任务找不到对应的类,名称为:{}", devJob.getActionClass());
|
||||
}
|
||||
|
@ -232,7 +232,7 @@ public class DevJobServiceImpl extends ServiceImpl<DevJobMapper, DevJob> impleme
|
|||
}
|
||||
try {
|
||||
// 直接运行一次
|
||||
((CommonTimerTaskRunner) SpringUtil.getBean(Class.forName(devJob.getActionClass()))).action();
|
||||
((CommonTimerTaskRunner) SpringUtil.getBean(Class.forName(devJob.getActionClass()))).action(devJob.getExtJson());
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new CommonException("定时任务找不到对应的类,名称为:{}", devJob.getActionClass());
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ public class DevJobTimerTaskRunner implements CommonTimerTaskRunner {
|
|||
private int n = 1;
|
||||
|
||||
@Override
|
||||
public void action() {
|
||||
public void action(String extJson) {
|
||||
log.info("我是一个定时任务,正在在被执行第" + n + "次");
|
||||
n = n + 1;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import cn.hutool.core.collection.CollStreamUtil;
|
|||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.PhoneUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
|
@ -25,6 +26,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
import vip.xiaonuo.common.enums.CommonSortOrderEnum;
|
||||
import vip.xiaonuo.common.exception.CommonException;
|
||||
import vip.xiaonuo.common.page.CommonPageRequest;
|
||||
import vip.xiaonuo.dev.api.DevConfigApi;
|
||||
import vip.xiaonuo.dev.modular.sms.entity.DevSms;
|
||||
import vip.xiaonuo.dev.modular.sms.enums.DevSmsEngineTypeEnum;
|
||||
import vip.xiaonuo.dev.modular.sms.mapper.DevSmsMapper;
|
||||
|
|
|
@ -16,6 +16,7 @@ import cn.hutool.core.collection.CollectionUtil;
|
|||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.sms4j.api.SmsBlend;
|
||||
|
@ -106,7 +107,8 @@ public class DevSmsXiaonuoUtil {
|
|||
if(smsResponse.isSuccess()) {
|
||||
return JSONUtil.toJsonStr(smsResponse.getData());
|
||||
} else {
|
||||
throw new CommonException("短信发送失败");
|
||||
JSONObject responseData = JSONUtil.parseObj(smsResponse.getData());
|
||||
throw new CommonException(responseData.getStr("resInfo"));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
package vip.xiaonuo.gen.modular.basic.controller;
|
||||
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
@ -29,10 +30,7 @@ import vip.xiaonuo.common.annotation.CommonLog;
|
|||
import vip.xiaonuo.common.pojo.CommonResult;
|
||||
import vip.xiaonuo.gen.modular.basic.entity.GenBasic;
|
||||
import vip.xiaonuo.gen.modular.basic.param.*;
|
||||
import vip.xiaonuo.gen.modular.basic.result.GenBasicMobileModuleSelectorResult;
|
||||
import vip.xiaonuo.gen.modular.basic.result.GenBasicPreviewResult;
|
||||
import vip.xiaonuo.gen.modular.basic.result.GenBasicTableColumnResult;
|
||||
import vip.xiaonuo.gen.modular.basic.result.GenBasicTableResult;
|
||||
import vip.xiaonuo.gen.modular.basic.result.*;
|
||||
import vip.xiaonuo.gen.modular.basic.service.GenBasicService;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -192,5 +190,29 @@ public class GenBasicController {
|
|||
public CommonResult<List<GenBasicMobileModuleSelectorResult>> mobileModuleSelector() {
|
||||
return CommonResult.data(genBasicService.mobileModuleSelector());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有模块
|
||||
*
|
||||
* @author yubaoshan
|
||||
* @date 2024/9/6 01:24
|
||||
*/
|
||||
@Operation(summary = "获取所有模块")
|
||||
@GetMapping("/gen/basic/moduleSelector")
|
||||
public CommonResult<List<GenBasicModuleSelectorResult>> moduleSelector() {
|
||||
return CommonResult.data(genBasicService.moduleSelector());
|
||||
}
|
||||
|
||||
/**
|
||||
* 代码生成获取所有菜单树包括未授权的
|
||||
*
|
||||
* @author yubaoshan
|
||||
* @date 2024/9/6 01:24
|
||||
**/
|
||||
@Operation(summary = "代码生成获取所有菜单树包括未授权的")
|
||||
@GetMapping("/gen/basic/menuTreeSelector")
|
||||
public CommonResult<List<Tree<String>>> menuTreeSelector(@Valid GenBasicSelectorMenuParam genBasicSelectorMenuParam) {
|
||||
return CommonResult.data(genBasicService.menuTreeSelector(genBasicSelectorMenuParam));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright [2022] [https://www.xiaonuo.vip]
|
||||
*
|
||||
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
|
||||
*
|
||||
* 1.请不要删除和修改根目录下的LICENSE文件。
|
||||
* 2.请不要删除和修改Snowy源码头部的版权声明。
|
||||
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
|
||||
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
|
||||
* 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
|
||||
* 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
|
||||
*/
|
||||
package vip.xiaonuo.gen.modular.basic.param;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 菜单选择器参数
|
||||
*
|
||||
* @author yubaoshan
|
||||
* @date 2024/9/6 01:24
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
public class GenBasicSelectorMenuParam {
|
||||
|
||||
/** 模块 */
|
||||
@Schema(description = "模块")
|
||||
@NotBlank(message = "module不能为空")
|
||||
private String module;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright [2022] [https://www.xiaonuo.vip]
|
||||
*
|
||||
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
|
||||
*
|
||||
* 1.请不要删除和修改根目录下的LICENSE文件。
|
||||
* 2.请不要删除和修改Snowy源码头部的版权声明。
|
||||
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
|
||||
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
|
||||
* 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
|
||||
* 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
|
||||
*/
|
||||
package vip.xiaonuo.gen.modular.basic.result;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 代码生成模块所需要用到的模块选择的结果
|
||||
*
|
||||
* @author yubaoshan
|
||||
* @date 2024/9/6 01:24
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
public class GenBasicModuleSelectorResult {
|
||||
|
||||
/** id */
|
||||
@Schema(description = "id")
|
||||
private String id;
|
||||
|
||||
/** 名称 */
|
||||
@Schema(description = "名称")
|
||||
private String name;
|
||||
}
|
|
@ -12,15 +12,13 @@
|
|||
*/
|
||||
package vip.xiaonuo.gen.modular.basic.service;
|
||||
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import vip.xiaonuo.gen.modular.basic.entity.GenBasic;
|
||||
import vip.xiaonuo.gen.modular.basic.param.*;
|
||||
import vip.xiaonuo.gen.modular.basic.result.GenBasicMobileModuleSelectorResult;
|
||||
import vip.xiaonuo.gen.modular.basic.result.GenBasicPreviewResult;
|
||||
import vip.xiaonuo.gen.modular.basic.result.GenBasicTableColumnResult;
|
||||
import vip.xiaonuo.gen.modular.basic.result.GenBasicTableResult;
|
||||
import vip.xiaonuo.gen.modular.basic.result.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
@ -128,4 +126,20 @@ public interface GenBasicService extends IService<GenBasic> {
|
|||
* @date 2023/7/15 22:28
|
||||
**/
|
||||
List<GenBasicMobileModuleSelectorResult> mobileModuleSelector();
|
||||
|
||||
/**
|
||||
* 获取模块
|
||||
*
|
||||
* @author yubaoshan
|
||||
* @date 2024/9/6 01:24
|
||||
**/
|
||||
List<GenBasicModuleSelectorResult> moduleSelector();
|
||||
|
||||
/**
|
||||
* 代码生成获取所有菜单树包括未授权的
|
||||
*
|
||||
* @author yubaoshan
|
||||
* @date 2024/9/6 01:24
|
||||
**/
|
||||
List<Tree<String>> menuTreeSelector(GenBasicSelectorMenuParam genBasicSelectorMenuParam);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import cn.hutool.core.collection.CollectionUtil;
|
|||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
@ -51,10 +52,7 @@ import vip.xiaonuo.gen.modular.basic.enums.GenEffectTypeEnum;
|
|||
import vip.xiaonuo.gen.modular.basic.enums.GenYesNoEnum;
|
||||
import vip.xiaonuo.gen.modular.basic.mapper.GenBasicMapper;
|
||||
import vip.xiaonuo.gen.modular.basic.param.*;
|
||||
import vip.xiaonuo.gen.modular.basic.result.GenBasicMobileModuleSelectorResult;
|
||||
import vip.xiaonuo.gen.modular.basic.result.GenBasicPreviewResult;
|
||||
import vip.xiaonuo.gen.modular.basic.result.GenBasicTableColumnResult;
|
||||
import vip.xiaonuo.gen.modular.basic.result.GenBasicTableResult;
|
||||
import vip.xiaonuo.gen.modular.basic.result.*;
|
||||
import vip.xiaonuo.gen.modular.basic.service.GenBasicService;
|
||||
import vip.xiaonuo.gen.modular.config.entity.GenConfig;
|
||||
import vip.xiaonuo.gen.modular.config.param.GenConfigAddParam;
|
||||
|
@ -62,6 +60,7 @@ import vip.xiaonuo.gen.modular.config.service.GenConfigService;
|
|||
import vip.xiaonuo.mobile.api.MobileModuleApi;
|
||||
import vip.xiaonuo.sys.api.SysButtonApi;
|
||||
import vip.xiaonuo.sys.api.SysMenuApi;
|
||||
import vip.xiaonuo.sys.api.SysModuleApi;
|
||||
import vip.xiaonuo.sys.api.SysRoleApi;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -148,6 +147,9 @@ public class GenBasicServiceImpl extends ServiceImpl<GenBasicMapper, GenBasic> i
|
|||
@Resource
|
||||
private SysMenuApi sysMenuApi;
|
||||
|
||||
@Resource
|
||||
private SysModuleApi sysModuleApi;
|
||||
|
||||
@Resource
|
||||
private SysButtonApi sysButtonApi;
|
||||
|
||||
|
@ -597,7 +599,20 @@ public class GenBasicServiceImpl extends ServiceImpl<GenBasicMapper, GenBasic> i
|
|||
@Override
|
||||
public List<GenBasicMobileModuleSelectorResult> mobileModuleSelector() {
|
||||
return mobileModuleApi.mobileModuleSelector().stream()
|
||||
.map(jsonObject -> JSONUtil.toBean(jsonObject, GenBasicMobileModuleSelectorResult.class)).collect(Collectors.toList());
|
||||
.map(jsonObject -> JSONUtil.toBean(jsonObject, GenBasicMobileModuleSelectorResult.class))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GenBasicModuleSelectorResult> moduleSelector() {
|
||||
return sysModuleApi.moduleSelector().stream()
|
||||
.map(jsonObject -> JSONUtil.toBean(jsonObject, GenBasicModuleSelectorResult.class))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Tree<String>> menuTreeSelector(GenBasicSelectorMenuParam genBasicSelectorMenuParam) {
|
||||
return sysMenuApi.menuTreeSelector(genBasicSelectorMenuParam.getModule());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -96,10 +96,12 @@
|
|||
<template #icon><plus-outlined /></template>
|
||||
新增
|
||||
</a-button>
|
||||
<xn-batch-delete
|
||||
<xn-batch-button
|
||||
v-if="hasPerm('${classNameFirstLower}BatchDelete')"
|
||||
buttonName="批量删除"
|
||||
icon="DeleteOutlined"
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
@batchDelete="deleteBatch${className}"
|
||||
@batchCallBack="deleteBatch${className}"
|
||||
/>
|
||||
</a-space>
|
||||
</template>
|
||||
|
|
|
@ -17,6 +17,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
|||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
|
@ -96,7 +97,7 @@ public class MobileButtonController {
|
|||
@Operation(summary = "删除移动端按钮")
|
||||
@CommonLog("删除移动端按钮")
|
||||
@PostMapping("/mobile/button/delete")
|
||||
public CommonResult<String> delete(@RequestBody @Valid List<MobileButtonIdParam> mobileButtonIdParamList) {
|
||||
public CommonResult<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空") List<MobileButtonIdParam> mobileButtonIdParamList) {
|
||||
mobileButtonService.delete(mobileButtonIdParamList);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
|||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
|
@ -96,7 +97,7 @@ public class SysButtonController {
|
|||
@Operation(summary = "删除按钮")
|
||||
@CommonLog("删除按钮")
|
||||
@PostMapping("/sys/button/delete")
|
||||
public CommonResult<String> delete(@RequestBody @Valid List<SysButtonIdParam> sysButtonIdParamList) {
|
||||
public CommonResult<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空") List<SysButtonIdParam> sysButtonIdParamList) {
|
||||
sysButtonService.delete(sysButtonIdParamList);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
|
|
@ -12,11 +12,15 @@
|
|||
*/
|
||||
package vip.xiaonuo.sys.modular.resource.provider;
|
||||
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import vip.xiaonuo.sys.api.SysMenuApi;
|
||||
import vip.xiaonuo.sys.modular.resource.param.menu.SysMenuSelectorMenuParam;
|
||||
import vip.xiaonuo.sys.modular.resource.service.SysMenuService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 菜单API接口实现类
|
||||
*
|
||||
|
@ -33,4 +37,11 @@ public class SysMenuApiProvider implements SysMenuApi {
|
|||
public String addForGenMenu(String parentId, String busName, String module, String title, String path) {
|
||||
return sysMenuService.addForGenMenu(parentId, busName, title, module, path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Tree<String>> menuTreeSelector(String module) {
|
||||
SysMenuSelectorMenuParam param = new SysMenuSelectorMenuParam();
|
||||
param.setModule(module);
|
||||
return sysMenuService.menuTreeSelector(param);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright [2022] [https://www.xiaonuo.vip]
|
||||
*
|
||||
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
|
||||
*
|
||||
* 1.请不要删除和修改根目录下的LICENSE文件。
|
||||
* 2.请不要删除和修改Snowy源码头部的版权声明。
|
||||
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
|
||||
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
|
||||
* 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
|
||||
* 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
|
||||
*/
|
||||
package vip.xiaonuo.sys.modular.resource.provider;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import vip.xiaonuo.sys.api.SysModuleApi;
|
||||
import vip.xiaonuo.sys.modular.resource.service.SysModuleService;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 模块API接口实现类
|
||||
*
|
||||
* @author yubaoshan
|
||||
* @date 2024/9/6 01:24
|
||||
**/
|
||||
@Service
|
||||
public class SysModuleApiProvider implements SysModuleApi {
|
||||
|
||||
@Resource
|
||||
private SysModuleService sysModuleService;
|
||||
|
||||
@Override
|
||||
public List<JSONObject> moduleSelector() {
|
||||
return sysModuleService.moduleSelector();
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
package vip.xiaonuo.sys.modular.resource.service;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import vip.xiaonuo.sys.modular.resource.entity.SysModule;
|
||||
|
@ -62,6 +63,14 @@ public interface SysModuleService extends IService<SysModule> {
|
|||
*/
|
||||
void delete(List<SysModuleIdParam> sysModuleIdParamList);
|
||||
|
||||
/**
|
||||
* 获取所有模块
|
||||
*
|
||||
* @author yubaoshan
|
||||
* @date 2024/9/6 01:24
|
||||
*/
|
||||
List<JSONObject> moduleSelector();
|
||||
|
||||
/**
|
||||
* 获取模块详情
|
||||
*
|
||||
|
|
|
@ -18,6 +18,7 @@ import cn.hutool.core.collection.CollectionUtil;
|
|||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
|
@ -150,6 +151,16 @@ public class SysModuleServiceImpl extends ServiceImpl<SysModuleMapper, SysModule
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JSONObject> moduleSelector() {
|
||||
LambdaQueryWrapper<SysModule> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
lambdaQueryWrapper.select(SysModule::getId, SysModule::getTitle);
|
||||
lambdaQueryWrapper.eq(SysModule::getCategory, SysResourceCategoryEnum.MODULE.getValue());
|
||||
return this.list(lambdaQueryWrapper).stream()
|
||||
.map(item -> JSONUtil.createObj().set("id", item.getId()).set("name", item.getTitle()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SysModule detail(SysModuleIdParam sysModuleIdParam) {
|
||||
return this.queryEntity(sysModuleIdParam.getId());
|
||||
|
|
|
@ -697,19 +697,19 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
|||
if (sysMenu.getCategory().equals(SysResourceCategoryEnum.MENU.getValue())) {
|
||||
if (!sysMenu.getMenuType().equals(SysResourceMenuTypeEnum.CATALOG.getValue())) {
|
||||
metaJsonObject.set("type", sysMenu.getMenuType().toLowerCase());
|
||||
// 如果设置了不可见,那么设置为false,为了兼容已有,所以只是false的为不显示
|
||||
if (ObjectUtil.isNotEmpty(sysMenu.getVisible()) && sysMenu.getVisible().equals("FALSE")) {
|
||||
metaJsonObject.set("hidden", true);
|
||||
}
|
||||
}
|
||||
if (sysMenu.getId().equals(sysMenus.orElse(null).getId())) {
|
||||
// 如果是首页,则设置affix
|
||||
metaJsonObject.set("affix", true);
|
||||
}
|
||||
}
|
||||
// 如果设置了不可见,那么设置为false,为了兼容已有,所以只是false的为不显示
|
||||
if (ObjectUtil.isNotEmpty(sysMenu.getVisible()) && sysMenu.getVisible().equals("FALSE")) {
|
||||
metaJsonObject.set("hidden", true);
|
||||
}
|
||||
menuJsonObject.set("meta", metaJsonObject);
|
||||
return menuJsonObject;
|
||||
}).collect(Collectors.toList());
|
||||
}).toList();
|
||||
|
||||
// 执行构造树
|
||||
List<TreeNode<String>> treeNodeList = resultJsonObjectList.stream().map(jsonObject ->
|
||||
|
|
|
@ -95,7 +95,7 @@ spring.datasource.dynamic.druid.break-after-acquire-failure=false
|
|||
spring.jackson.time-zone=GMT+8
|
||||
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
|
||||
spring.jackson.locale=zh_CN
|
||||
spring.jackson.serialization.write-dates-as-timestamps=true
|
||||
spring.jackson.serialization.write-dates-as-timestamps=false
|
||||
#########################################
|
||||
# redis configuration
|
||||
#########################################
|
||||
|
|
Loading…
Reference in New Issue