【升级】v3.3版本更新

pull/237/head v3.3
俞宝山 2 months ago
parent c2552c29c8
commit 66a62cafa7

@ -375,7 +375,7 @@
<dependency> <dependency>
<groupId>com.baomidou</groupId> <groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId> <artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
<version>4.3.0</version> <version>4.3.1</version>
</dependency> </dependency>
<!-- mysql --> <!-- mysql -->

@ -9,3 +9,6 @@ VITE_SET_DRAWER = true
# 本地环境 # 本地环境
NODE_ENV = development NODE_ENV = development
# 检测更新(本地建议关闭)
VITE_VERSION_UPDATE = false

@ -6,3 +6,6 @@ VITE_PORT = 81
# 开启设置抽屉 # 开启设置抽屉
VITE_SET_DRAWER = false VITE_SET_DRAWER = false
# 检测更新(生产建议开启)
VITE_VERSION_UPDATE = true

@ -18,40 +18,40 @@
}, },
"dependencies": { "dependencies": {
"@amap/amap-jsapi-loader": "1.0.1", "@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", "@ant-design/icons-vue": "7.0.1",
"@antv/g2plot": "2.4.31", "@antv/g2plot": "2.4.32",
"@chenfengyuan/vue-qrcode": "2.0.0", "@chenfengyuan/vue-qrcode": "2.0.0",
"@highlightjs/vue-plugin": "2.1.0", "@highlightjs/vue-plugin": "2.1.0",
"@tinymce/tinymce-vue": "5.1.1", "@tinymce/tinymce-vue": "5.1.1",
"@vue-office/docx": "1.6.0", "@vue-office/docx": "1.6.2",
"@vue-office/excel": "1.7.1", "@vue-office/excel": "1.7.11",
"@vue-office/pdf": "1.6.4", "@vue-office/pdf": "2.0.2",
"ant-design-vue": "4.1.2", "ant-design-vue": "4.2.5",
"axios": "1.6.2", "axios": "1.7.7",
"cropperjs": "1.6.1", "cropperjs": "1.6.2",
"dayjs": "1.11.10", "dayjs": "1.11.13",
"echarts": "5.4.3", "echarts": "5.5.1",
"echarts-stat": "1.2.0", "echarts-stat": "1.2.0",
"enquire.js": "2.1.6", "enquire.js": "2.1.6",
"event-source-polyfill": "1.0.31", "event-source-polyfill": "1.0.31",
"fuse.js": "7.0.0", "fuse.js": "7.0.0",
"highlight.js": "11.9.0", "highlight.js": "11.10.0",
"hotkeys-js": "3.12.2", "hotkeys-js": "3.13.7",
"js-pinyin": "0.2.5", "js-pinyin": "0.2.7",
"lodash-es": "4.17.21", "lodash-es": "4.17.21",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"pinia": "2.1.7", "pinia": "2.2.2",
"qs": "6.11.2", "qrcode": "1.5.4",
"screenfull": "6.0.2", "qs": "6.13.0",
"sm-crypto": "0.3.13", "sm-crypto": "0.3.13",
"snowflake-id": "1.1.0", "snowflake-id": "1.1.0",
"sortablejs": "1.15.1", "sortablejs": "1.15.3",
"tinymce": "6.8.1", "tinymce": "7.3.0",
"vue": "3.4.21", "vue": "3.5.10",
"vue-cropper": "1.1.1", "vue-cropper": "1.1.4",
"vue-i18n": "9.8.0", "vue-i18n": "10.0.0",
"vue-router": "4.3.0", "vue-router": "4.4.5",
"vue3-colorpicker": "2.3.0", "vue3-colorpicker": "2.3.0",
"vue3-tree-org": "4.2.2", "vue3-tree-org": "4.2.2",
"vuedraggable-es": "4.1.1" "vuedraggable-es": "4.1.1"
@ -61,23 +61,23 @@
"@vitejs/plugin-legacy": "5.2.0", "@vitejs/plugin-legacy": "5.2.0",
"@vitejs/plugin-vue": "4.5.2", "@vitejs/plugin-vue": "4.5.2",
"@vitejs/plugin-vue-jsx": "3.1.0", "@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", "@vue/eslint-config-standard": "8.0.1",
"antd-less-to-css-variable": "1.0.5", "antd-less-to-css-variable": "1.0.5",
"autoprefixer": "10.4.16", "autoprefixer": "10.4.20",
"eslint": "8.55.0", "eslint": "8.57.0",
"eslint-config-prettier": "9.1.0", "eslint-config-prettier": "9.1.0",
"eslint-plugin-prettier": "5.0.1", "eslint-plugin-prettier": "5.0.1",
"eslint-plugin-vue": "9.7.0", "eslint-plugin-vue": "9.7.0",
"less": "4.1.3", "less": "4.2.0",
"postcss": "8.4.32", "postcss": "8.4.47",
"prettier": "3.1.0", "prettier": "3.3.3",
"rollup-plugin-visualizer": "5.10.0", "rollup-plugin-visualizer": "5.12.0",
"tailwindcss": "3.3.6", "tailwindcss": "3.4.13",
"typescript": "5.3.3", "typescript": "5.6.2",
"unplugin-auto-import": "0.17.2", "unplugin-auto-import": "0.18.3",
"unplugin-vue-components": "0.26.0", "unplugin-vue-components": "0.27.4",
"vite": "5.1.6", "vite": "5.4.8",
"vite-plugin-compression": "0.5.1", "vite-plugin-compression": "0.5.1",
"vite-plugin-vue-setup-extend": "0.4.0", "vite-plugin-vue-setup-extend": "0.4.0",
"vue-eslint-parser": "9.3.2" "vue-eslint-parser": "9.3.2"

@ -45,5 +45,13 @@ export default {
// 获取所有移动端模块 // 获取所有移动端模块
basicMobileModuleSelector(data) { basicMobileModuleSelector(data) {
return request('mobileModuleSelector', data, 'get') 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> <template #nextArrow>
<div class="custom-slick-arrow" style="right: 10px"><RightOutlined /></div> <div class="custom-slick-arrow" style="right: 10px"><RightOutlined /></div>
</template> </template>
<div v-if="!isEmpty(slideshowList)"> <img
<img v-for="item in slideshowList"
v-for="item in slideshowList" :key="item.id"
:key="item.id" :src="item.image"
:src="item.image" class="carousel-images"
class="carousel-images" @click="leaveForOpen(item.pathDetails)"
@click="leaveForOpen(item.pathDetails)" />
/> <a-empty v-if="isEmpty(slideshowList)" :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</div>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</a-carousel> </a-carousel>
</a-card> </a-card>
</template> </template>
@ -57,18 +55,18 @@
return return
} }
const detail = cloneDeep(value) const detail = cloneDeep(value)
let detailObj = {} let result = {}
if (typeof detail !== 'object') { if (typeof detail !== 'object') {
detailObj = JSON.parse(detail) result = JSON.parse(detail)
} }
// json // json
if (detailObj.whetherToClick && detailObj.whetherToClick === 'ENABLE') { if (result.whetherToClick && result.whetherToClick === 'ENABLE') {
if (detailObj.skipMode && detailObj.skipMode === 'URL') { if (result.skipMode && result.skipMode === 'URL') {
window.open(detailObj.url) window.open(result.url)
} }
if (detailObj.skipMode && detailObj.skipMode === 'ROUTER') { if (result.skipMode && result.skipMode === 'ROUTER') {
router.replace({ router.replace({
path: detailObj.url path: result.url
}) })
} }
} }

@ -1,6 +1,8 @@
<template> <template>
<a-card :title="title" :bordered="false" :loading="apiLoading"> <a-card :title="title" :bordered="false" :loading="apiLoading">
<a-row> <a-row>
<!-- 因租户内定时任务需解决暂先注释 -->
<!--
<a-col :span="4"> <a-col :span="4">
<a-statistic :value="dataSource.jobCount"> <a-statistic :value="dataSource.jobCount">
<template #title> <template #title>
@ -9,7 +11,8 @@
</template> </template>
</a-statistic> </a-statistic>
</a-col> </a-col>
<a-col :span="4"> -->
<a-col :span="5">
<a-statistic :value="dataSource.sysDictCount"> <a-statistic :value="dataSource.sysDictCount">
<template #title> <template #title>
<read-outlined style="color: #4b4b4b" /> <read-outlined style="color: #4b4b4b" />
@ -17,7 +20,7 @@
</template> </template>
</a-statistic> </a-statistic>
</a-col> </a-col>
<a-col :span="4"> <a-col :span="5">
<a-statistic :value="dataSource.bizDictCount"> <a-statistic :value="dataSource.bizDictCount">
<template #title> <template #title>
<read-outlined style="color: #353779" /> <read-outlined style="color: #353779" />
@ -25,7 +28,7 @@
</template> </template>
</a-statistic> </a-statistic>
</a-col> </a-col>
<a-col :span="4"> <a-col :span="5">
<a-statistic :value="dataSource.backUserSessionCount"> <a-statistic :value="dataSource.backUserSessionCount">
<template #title> <template #title>
<usergroup-delete-outlined style="color: #3ceecd" /> <usergroup-delete-outlined style="color: #3ceecd" />
@ -33,7 +36,7 @@
</template> </template>
</a-statistic> </a-statistic>
</a-col> </a-col>
<a-col :span="4"> <a-col :span="5">
<a-statistic :value="dataSource.clientUserSessionCount"> <a-statistic :value="dataSource.clientUserSessionCount">
<template #title> <template #title>
<UserSwitchOutlined style="color: rgba(229, 159, 18, 0.35)" /> <UserSwitchOutlined style="color: rgba(229, 159, 18, 0.35)" />
@ -58,7 +61,6 @@
const title = ref('运维一览') const title = ref('运维一览')
const apiLoading = ref(false) const apiLoading = ref(false)
const dataSource = ref({ const dataSource = ref({
jobCount: 0,
sysDictCount: 0, sysDictCount: 0,
bizDictCount: 0, bizDictCount: 0,
backUserSessionCount: 0, backUserSessionCount: 0,

@ -1,19 +1,34 @@
<template> <template>
<a-popconfirm title="批量处理此信息?" :open="batchVisible" @openChange="batchVisibleChange" @confirm="deleteBatch"> <div v-if="isPopconFirm">
<a-button :type="props.buttonType" :danger="props.buttonDanger" :size="props.size" :loading="buttonLoading"> <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"> <template #icon v-if="props.icon">
<component :is="props.icon" :style="{ color: props.color }" /> <component :is="props.icon" :style="{ color: props.color }" />
</template> </template>
{{ props.buttonName }} {{ props.buttonName }}
</a-button> </a-button>
</a-popconfirm> </div>
</template> </template>
<script setup name="commonBatchButton"> <script setup name="commonBatchButton">
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'
const batchVisible = ref(false) const batchVisible = ref(false)
const emit = defineEmits({ batchCallBack: null }) const emit = defineEmits({ batchCallBack: null })
const buttonLoading = ref(false)
const props = defineProps({ const props = defineProps({
idKey: { idKey: {
type: String, type: String,
@ -46,6 +61,15 @@
color: { color: {
type: String, type: String,
default: () => '' default: () => ''
},
//
isPopconFirm: {
type: Boolean,
default: () => true
},
loading: {
type: Boolean,
default: () => false
} }
}) })
// //
@ -53,17 +77,26 @@
if (batchVisible.value) { if (batchVisible.value) {
batchVisible.value = false batchVisible.value = false
return false return false
}
if (props.selectedRowKeys.length < 1) {
message.warning('请选择一条或多条数据')
batchVisible.value = false
return false
} else { } else {
batchVisible.value = true if (props.selectedRowKeys.length < 1) {
message.warning('请选择一条或多条数据')
batchVisible.value = false
return false
} else {
batchVisible.value = true
return true
}
} }
} }
// //
const deleteBatch = () => { const deleteBatch = () => {
if (!props.isPopconFirm) {
if (props.selectedRowKeys.length < 1) {
message.warning('请选择一条或多条数据')
batchVisible.value = false
return false
}
}
const params = props.selectedRowKeys.map((m) => { const params = props.selectedRowKeys.map((m) => {
return { return {
[props.idKey]: m [props.idKey]: m
@ -72,12 +105,4 @@
// //
emit('batchCallBack', params) emit('batchCallBack', params)
} }
// loading
const openLoading = () => {
buttonLoading.value = true
}
// loading
const closeLoading = () => {
buttonLoading.value = true
}
</script> </script>

@ -55,10 +55,10 @@
}) })
const contentValue = ref() const contentValue = ref()
const init = 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', language: 'zh_CN',
skin_url: import.meta.env.BASE_URL + 'tinymce/skins/ui/oxide', skin_url: 'tinymce/skins/ui/oxide',
content_css: import.meta.env.BASE_URL + 'tinymce/skins/content/default/content.css', content_css: 'tinymce/skins/content/default/content.css',
menubar: false, menubar: false,
statusbar: true, statusbar: true,
plugins: props.plugins, plugins: props.plugins,

@ -76,6 +76,7 @@
<script setup name="uploadIndex"> <script setup name="uploadIndex">
import tool from '@/utils/tool' import tool from '@/utils/tool'
import sysConfig from '@/config/index' import sysConfig from '@/config/index'
import { convertUrl } from '@/utils/apiAdaptive'
import { message, Upload } from 'ant-design-vue' import { message, Upload } from 'ant-design-vue'
import { cloneDeep } from 'lodash-es' import { cloneDeep } from 'lodash-es'
const fileList = ref([]) const fileList = ref([])
@ -91,19 +92,19 @@
// id // id
uploadReturnIdApi: { uploadReturnIdApi: {
type: String, type: String,
default: '/dev/file/uploadLocalReturnId', default: convertUrl('/dev/file/uploadLocalReturnId'),
required: false required: false
}, },
// url // url
uploadDynamicReturnUrlApi: { uploadDynamicReturnUrlApi: {
type: String, type: String,
default: '/dev/file/uploadDynamicReturnUrl', default: convertUrl('/dev/file/uploadDynamicReturnUrl'),
required: false required: false
}, },
// id // id
uploadIdDownloadUrl: { uploadIdDownloadUrl: {
type: String, type: String,
default: '/dev/file/download?id=', default: convertUrl('/dev/file/download?id='),
required: false required: false
}, },
// file || drag || image // file || drag || image

@ -9,6 +9,9 @@
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip * 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/ */
const DEFAULT_CONFIG = { const DEFAULT_CONFIG = {
// 是否是微服务cloud版本
CLOUD_SERVER: false,
// 首页地址 // 首页地址
DASHBOARD_URL: '/index', DASHBOARD_URL: '/index',
@ -18,9 +21,6 @@ const DEFAULT_CONFIG = {
// 请求超时 // 请求超时
TIMEOUT: 60000, TIMEOUT: 60000,
// 版本更新时间 默认10s
UPDATE_VERSION_TIME: 10000,
// TokenName // Authorization // TokenName // Authorization
TOKEN_NAME: 'token', TOKEN_NAME: 'token',
@ -46,7 +46,7 @@ const DEFAULT_CONFIG = {
SNOWY_LAYOUT_TAGS_OPEN: true, SNOWY_LAYOUT_TAGS_OPEN: true,
// 是否开启展示面包屑 // 是否开启展示面包屑
SNOWY_BREADCRUMD_OPEN: false, SNOWY_BREADCRUMB_OPEN: false,
// 顶栏是否应用主题色 // 顶栏是否应用主题色
SNOWY_TOP_HEADER_THEME_COLOR_OPEN: false, SNOWY_TOP_HEADER_THEME_COLOR_OPEN: false,
@ -61,10 +61,10 @@ const DEFAULT_CONFIG = {
SNOWY_LOGIN_USER_WATERMARK_OPEN: false, 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', LANG: 'zh-cn',

@ -60,6 +60,7 @@
import router from '@/router' import router from '@/router'
import { onMounted } from 'vue' import { onMounted } from 'vue'
import sysConfig from '@/config' import sysConfig from '@/config'
import { convertUrl } from '@/utils/apiAdaptive'
import { EventSourcePolyfill } from 'event-source-polyfill' import { EventSourcePolyfill } from 'event-source-polyfill'
import tool from '@/utils/tool' import tool from '@/utils/tool'
@ -76,7 +77,7 @@
const createSseConnect = () => { const createSseConnect = () => {
if (window.EventSource) { if (window.EventSource) {
let clientId = tool.data.get('CLIENTID') ? tool.data.get('CLIENTID') : '' 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 // heartbeatTimeout: 30s
let source = new EventSourcePolyfill(url, { let source = new EventSourcePolyfill(url, {
headers: { token: tool.data.get('TOKEN') }, headers: { token: tool.data.get('TOKEN') },

@ -53,7 +53,12 @@
</div> </div>
</template> </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-tab-pane>
</a-tabs> </a-tabs>
</div> </div>

@ -88,7 +88,6 @@
import sysConfig from '@/config/index' import sysConfig from '@/config/index'
import dictApi from '@/api/dev/dictApi' import dictApi from '@/api/dev/dictApi'
let timer = null
const store = globalStore() const store = globalStore()
const kStore = keepAliveStore() const kStore = keepAliveStore()
const route = useRoute() const route = useRoute()
@ -265,52 +264,47 @@
}) })
}) })
onBeforeUnmount(() => { onBeforeUnmount(() => {
clearUpdateVersion()
window.removeEventListener('resize', onLayoutResize) window.removeEventListener('resize', onLayoutResize)
window.removeEventListener('resize', getNav) window.removeEventListener('resize', getNav)
}) })
// //
const updateVersion = () => { const updateVersion = () => {
timer = setInterval(async () => { const updateVersionOpen = import.meta.env.VITE_VERSION_UPDATE
// if (updateVersionOpen) {
let localVersion = getLocalHash() setTimeout(async () => {
// 线 //
let onlineVersion = await checkHash() let localVersion = getLocalHash()
// // 线
if (localVersion !== onlineVersion) { let onlineVersion = await checkHash()
if (document.querySelector('.notification-update-version')) { //
return 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()}` }, 3000)
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
} }
} }
// //
@ -339,7 +333,7 @@
menuList.value = menuNavList menuList.value = menuNavList
return return
} }
// //
const showNav = menuNavList.slice(0, startIndex) const showNav = menuNavList.slice(0, startIndex)
const hiddenNav = menuNavList.slice(startIndex, menuNavList.length) const hiddenNav = menuNavList.slice(startIndex, menuNavList.length)
menuList.value = showNav menuList.value = showNav

@ -36,7 +36,7 @@ const routes_404 = [
const routes = [...systemRouter, ...whiteListRouters, ...routes_404] const routes = [...systemRouter, ...whiteListRouters, ...routes_404]
const router = createRouter({ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), history: createWebHistory(),
routes routes
}) })
@ -45,7 +45,6 @@ const router = createRouter({
// 判断是否已加载过动态/静态路由 // 判断是否已加载过动态/静态路由
const isGetRouter = ref(false) const isGetRouter = ref(false)
// 白名单校验 // 白名单校验
const exportWhiteListFromRouter = (router) => { const exportWhiteListFromRouter = (router) => {
const res = [] const res = []
@ -53,7 +52,6 @@ const exportWhiteListFromRouter = (router) => {
return res return res
} }
const whiteList = exportWhiteListFromRouter(whiteListRouters) const whiteList = exportWhiteListFromRouter(whiteListRouters)
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
NProgress.start() NProgress.start()
const store = globalStore() const store = globalStore()
@ -70,7 +68,6 @@ router.beforeEach(async (to, from, next) => {
// NProgress.done() // NProgress.done()
return false return false
} }
if (!isGetRouter.value) { if (!isGetRouter.value) {
// 初始化菜单加载,代码位置不能变动 // 初始化菜单加载,代码位置不能变动
const menuStore = useMenuStore() const menuStore = useMenuStore()
@ -102,6 +99,14 @@ router.beforeEach(async (to, from, next) => {
if (token) { if (token) {
// 有token的时候才保存登录之前要访问的页面 // 有token的时候才保存登录之前要访问的页面
tool.data.set('LAST_VIEWS_PATH', to.fullPath) 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) { if (!token) {

@ -40,7 +40,7 @@ export const globalStore = defineStore('global', () => {
// 多标签栏 // 多标签栏
const layoutTagsOpen = ref(getCacheConfig('SNOWY_LAYOUT_TAGS_OPEN')) 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')) const fixedWidth = ref(getCacheConfig('SNOWY_FIXEDWIDTH_OPEN'))
// 顶栏是否应用主题色 // 顶栏是否应用主题色

@ -69,6 +69,7 @@ export const viewTagsStore = defineStore('viewTags', () => {
const nowFullPath = location.hash.substring(1) const nowFullPath = location.hash.substring(1)
viewTags.value.forEach((item) => { viewTags.value.forEach((item) => {
if (item.fullPath === nowFullPath) { if (item.fullPath === nowFullPath) {
item.meta.key = Date.now()
item.meta.title = title item.meta.title = title
} }
}) })

@ -116,7 +116,6 @@ a, button, input, textarea {
/* 头部 */ /* 头部 */
.snowy-header { .snowy-header {
height: 50px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
border-bottom: 1px solid var(--header-bottom); border-bottom: 1px solid var(--header-bottom);
@ -481,6 +480,11 @@ body,
.snowy-theme-dark .odd { .snowy-theme-dark .odd {
background-color: #1d1d1d background-color: #1d1d1d
} }
// 解决浏览器F12爆红aria-hidden问题
.ant-modal div[aria-hidden="true"] {
display: none !important
}
// 以下是重写表单设计器的样式 // 以下是重写表单设计器的样式
.list-main { .list-main {
background: var(--auto-judge-before-color) !important; 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] || '未知错误' const errorName = errorMap[error.name] || '未知错误'
nextTick(() => { nextTick(() => {
console.error(errorName) console.error(errorName + ' ' + error)
}) })
} }

@ -14,6 +14,7 @@ import qs from 'qs'
import { Modal, message } from 'ant-design-vue' import { Modal, message } from 'ant-design-vue'
import sysConfig from '@/config/index' import sysConfig from '@/config/index'
import tool from '@/utils/tool' import tool from '@/utils/tool'
import { convertUrl } from './apiAdaptive'
// 以下这些code需要重新登录 // 以下这些code需要重新登录
const reloadCodes = [401, 1011007, 1011008] const reloadCodes = [401, 1011007, 1011008]
@ -108,7 +109,7 @@ service.interceptors.response.use(
// } // }
} else { } else {
// 统一成功提示 // 统一成功提示
const responseUrls = response.config.url.split('/') const functionName = response.config.url.split('/').pop()
const apiNameArray = [ const apiNameArray = [
'add', 'add',
'edit', 'edit',
@ -129,7 +130,8 @@ service.interceptors.response.use(
'saveDraft' 'saveDraft'
] ]
apiNameArray.forEach((apiName) => { apiNameArray.forEach((apiName) => {
if (responseUrls[responseUrls.length - 1] === apiName) { // 上面去掉接口路径后,方法内包含内置的进行统一提示成功
if (functionName.includes(apiName)) {
message.success(data.msg) message.success(data.msg)
} }
}) })
@ -151,7 +153,7 @@ service.interceptors.response.use(
// 适配器, 用于适配不同的请求方式 // 适配器, 用于适配不同的请求方式
export const baseRequest = (url, value = {}, method = 'post', options = {}) => { export const baseRequest = (url, value = {}, method = 'post', options = {}) => {
url = sysConfig.API_URL + url url = sysConfig.API_URL + convertUrl(url)
if (method === 'post') { if (method === 'post') {
return service.post(url, value, options) return service.post(url, value, options)
} else if (method === 'get') { } else if (method === 'get') {

@ -1,7 +1,7 @@
<template> <template>
<xn-form-container title="详情" :width="1000" v-model:open="open" :destroy-on-close="true" @close="onClose"> <xn-form-container title="详情" :width="1000" v-model:open="open" :destroy-on-close="true" @close="onClose">
<a-descriptions bordered> <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-descriptions-item label="类型">
<a-tag :bordered="false" color="success" v-if="formData.type === 'NOTICE'"> <a-tag :bordered="false" color="success" v-if="formData.type === 'NOTICE'">
{{ $TOOL.dictTypeData('BIZ_NOTICE_TYPE', formData.type) }} {{ $TOOL.dictTypeData('BIZ_NOTICE_TYPE', formData.type) }}
@ -15,7 +15,7 @@
</a-descriptions-item> </a-descriptions-item>
<a-descriptions-item label="封面图"> <a-descriptions-item label="封面图">
<div v-if="formData.image"> <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> </div>
<span v-else></span> <span v-else></span>
</a-descriptions-item> </a-descriptions-item>
@ -23,8 +23,12 @@
</a-descriptions> </a-descriptions>
<a-descriptions bordered :column="2" class="mt-2"> <a-descriptions bordered :column="2" class="mt-2">
<a-descriptions-item label="摘要">{{ formData.digest }}</a-descriptions-item> <a-descriptions-item label="摘要">{{ formData.digest }}</a-descriptions-item>
<a-descriptions-item label="备注"><span>{{ formData.remark }}</span></a-descriptions-item> <a-descriptions-item label="备注"
<a-descriptions-item label="排序"><span>{{ formData.sortCode }}</span></a-descriptions-item> ><span>{{ formData.remark }}</span></a-descriptions-item
>
<a-descriptions-item label="排序"
><span>{{ formData.sortCode }}</span></a-descriptions-item
>
<a-descriptions-item label="发布位置"> <a-descriptions-item label="发布位置">
<div v-if="formData.place"> <div v-if="formData.place">
<a-tag v-for="textValue in JSON.parse(formData.place)" :key="textValue" color="processing"> <a-tag v-for="textValue in JSON.parse(formData.place)" :key="textValue" color="processing">
@ -32,48 +36,56 @@
</a-tag> </a-tag>
</div> </div>
</a-descriptions-item> </a-descriptions-item>
<a-descriptions-item label="创建人"><span>{{ formData.createUserName }}</span></a-descriptions-item> <a-descriptions-item label="创建人"
<a-descriptions-item label="创建时间"><span>{{ formData.createTime }}</span></a-descriptions-item> ><span>{{ formData.createUserName }}</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.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> </a-descriptions>
<template #footer> <template #footer>
<a-button style="margin-right: 8px" @click="onClose"></a-button> <a-button style="margin-right: 8px" @click="onClose"></a-button>
<a-button type="primary" @click="onClose" :loading="submitLoading">确定</a-button> <a-button type="primary" @click="onClose" :loading="submitLoading">确定</a-button>
</template> </template>
</xn-form-container> </xn-form-container>
</template> </template>
<script setup name="bizNoticeDetail"> <script setup name="bizNoticeDetail">
import bizNoticeApi from '@/api/biz/bizNoticeApi' import bizNoticeApi from '@/api/biz/bizNoticeApi'
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'
// //
const open = ref(false) const open = ref(false)
const emit = defineEmits({ successful: null }) const emit = defineEmits({ successful: null })
// //
const formData = ref({}) const formData = ref({})
const submitLoading = ref(false) const submitLoading = ref(false)
// //
const onOpen = (id) => { const onOpen = (id) => {
open.value = true open.value = true
if (id) { if (id) {
const param = { const param = {
id: id id: id
} }
bizNoticeApi.bizNoticeDetail(param).then((data) => { bizNoticeApi.bizNoticeDetail(param).then((data) => {
formData.value = Object.assign({}, data) formData.value = Object.assign({}, data)
}) })
} else { } else {
message.warning('未查到该信息') message.warning('未查到该信息')
} }
} }
// //
const onClose = () => { const onClose = () => {
formData.value = {} formData.value = {}
open.value = false open.value = false
} }
// //
defineExpose({ defineExpose({
onOpen onOpen
}) })
</script> </script>

@ -1,35 +1,33 @@
<template> <template>
<xn-form-container <xn-form-container
:title="formData.id ? '编辑通知公告' : '增加通知公告'" :title="formData.id ? '编辑通知公告' : '增加通知公告'"
:width="1000" :width="1000"
v-model:open="open" v-model:open="open"
:destroy-on-close="true" :destroy-on-close="true"
@close="onClose" @close="onClose"
> >
<a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical"> <a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
<a-row :gutter="16"> <a-row :gutter="16">
<a-col :span="19"> <a-col :span="19">
<a-form-item label="标题:" name="title"> <a-form-item label="标题:" name="title">
<a-input v-model:value="formData.title" placeholder="请输入标题" allow-clear /> <a-input v-model:value="formData.title" placeholder="请输入标题" allow-clear />
</a-form-item> </a-form-item>
<a-form-item name="type"> <a-form-item name="type">
<template #label> <template #label>
<a-tooltip> <a-tooltip>
<template #title> <template #title> 这里只是标签的类型 </template>
这里只是标签的类型
</template>
<question-circle-outlined /> <question-circle-outlined />
类型 类型
</a-tooltip> </a-tooltip>
</template> </template>
<a-radio-group v-model:value="formData.type" placeholder="请选择类型" :options="typeOptions" /> <a-radio-group v-model:value="formData.type" placeholder="请选择类型" :options="typeOptions" />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="5"> <a-col :span="5">
<a-form-item label="封面图:" name="image"> <a-form-item label="封面图:" name="image">
<xn-upload v-model:value="formData.image" uploadMode="image" /> <xn-upload v-model:value="formData.image" uploadMode="image" />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="24"> <a-col :span="24">
<a-form-item label="内容:" name="content"> <a-form-item label="内容:" name="content">
<xn-editor v-model:value="formData.content" placeholder="请输入内容" /> <xn-editor v-model:value="formData.content" placeholder="请输入内容" />
@ -46,11 +44,11 @@
/> />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="18"> <a-col :span="18">
<a-form-item label="发布位置:" name="place"> <a-form-item label="发布位置:" name="place">
<a-checkbox-group v-model:value="formData.place" placeholder="请选择发布位置" :options="placeOptions" /> <a-checkbox-group v-model:value="formData.place" placeholder="请选择发布位置" :options="placeOptions" />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="6"> <a-col :span="6">
<a-form-item label="排序:" name="sortCode"> <a-form-item label="排序:" name="sortCode">
<a-input-number <a-input-number
@ -61,88 +59,92 @@
/> />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="24"> <a-col :span="24">
<a-form-item label="备注:" name="remark"> <a-form-item label="备注:" name="remark">
<a-textarea v-model:value="formData.remark" placeholder="请输入备注" :auto-size="{ minRows: 3, maxRows: 5 }" /> <a-textarea
</a-form-item> v-model:value="formData.remark"
</a-col> placeholder="请输入备注"
</a-row> :auto-size="{ minRows: 3, maxRows: 5 }"
</a-form> />
<template #footer> </a-form-item>
<a-button style="margin-right: 8px" @click="onClose"></a-button> </a-col>
<a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button> </a-row>
</template> </a-form>
</xn-form-container> <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> </template>
<script setup name="bizNoticeForm"> <script setup name="bizNoticeForm">
import tool from '@/utils/tool' import tool from '@/utils/tool'
import { cloneDeep } from 'lodash-es' import { cloneDeep } from 'lodash-es'
import { required } from '@/utils/formRules' import { required } from '@/utils/formRules'
import bizNoticeApi from '@/api/biz/bizNoticeApi' import bizNoticeApi from '@/api/biz/bizNoticeApi'
// //
const open = ref(false) const open = ref(false)
const emit = defineEmits({ successful: null }) const emit = defineEmits({ successful: null })
const formRef = ref() const formRef = ref()
// //
const formData = ref({}) const formData = ref({})
const submitLoading = ref(false) const submitLoading = ref(false)
const typeOptions = ref([]) const typeOptions = ref([])
const placeOptions = ref([]) const placeOptions = ref([])
const statusOptions = ref([]) const statusOptions = ref([])
// //
const onOpen = (record) => { const onOpen = (record) => {
open.value = true open.value = true
if (record) { if (record) {
let recordData = cloneDeep(record) let recordData = cloneDeep(record)
recordData.place = JSON.parse(recordData.place) recordData.place = JSON.parse(recordData.place)
formData.value = Object.assign({}, recordData) formData.value = Object.assign({}, recordData)
} else { } else {
formData.value = { formData.value = {
type: 'NOTICE', type: 'NOTICE',
place: ['BACK_MOBILE', 'BACK_INDEX'], place: ['BACK_MOBILE', 'BACK_INDEX'],
sortCode: 99 sortCode: 99
} }
} }
typeOptions.value = tool.dictList('BIZ_NOTICE_TYPE') typeOptions.value = tool.dictList('BIZ_NOTICE_TYPE')
placeOptions.value = tool.dictList('BIZ_NOTICE_PLACE') placeOptions.value = tool.dictList('BIZ_NOTICE_PLACE')
statusOptions.value = tool.dictList('BIZ_NOTICE_STATUS') statusOptions.value = tool.dictList('BIZ_NOTICE_STATUS')
} }
// //
const onClose = () => { const onClose = () => {
formRef.value.resetFields() formRef.value.resetFields()
formData.value = {} formData.value = {}
open.value = false open.value = false
} }
// //
const formRules = { const formRules = {
title: [required('请输入标题')], title: [required('请输入标题')],
content: [required('请输入内容')], content: [required('请输入内容')],
digest: [required('请输入摘要')], digest: [required('请输入摘要')],
type: [required('请选择类型')], type: [required('请选择类型')],
place: [required('请选择发布位置')], place: [required('请选择发布位置')],
sortCode: [required('请输入排序')] sortCode: [required('请输入排序')]
} }
// //
const onSubmit = () => { const onSubmit = () => {
formRef.value.validate().then(() => { formRef.value.validate().then(() => {
submitLoading.value = true submitLoading.value = true
const formDataParam = cloneDeep(formData.value) const formDataParam = cloneDeep(formData.value)
formDataParam.place = JSON.stringify(formDataParam.place) formDataParam.place = JSON.stringify(formDataParam.place)
bizNoticeApi bizNoticeApi
.bizNoticeSubmitForm(formDataParam, formDataParam.id) .bizNoticeSubmitForm(formDataParam, formDataParam.id)
.then(() => { .then(() => {
onClose() onClose()
emit('successful') emit('successful')
}) })
.finally(() => { .finally(() => {
submitLoading.value = false submitLoading.value = false
}) })
}) })
} }
// //
defineExpose({ defineExpose({
onOpen onOpen
}) })
</script> </script>

@ -1,73 +1,76 @@
<template> <template>
<a-card :bordered="false"> <a-card :bordered="false">
<a-form ref="searchFormRef" name="advanced_search" :model="searchFormState" class="ant-advanced-search-form"> <a-form ref="searchFormRef" name="advanced_search" :model="searchFormState" class="ant-advanced-search-form">
<a-row :gutter="24"> <a-row :gutter="24">
<a-col :span="6"> <a-col :span="6">
<a-form-item label="标题" name="title"> <a-form-item label="标题" name="title">
<a-input v-model:value="searchFormState.title" placeholder="请输入标题" /> <a-input v-model:value="searchFormState.title" placeholder="请输入标题" />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="6"> <a-col :span="6">
<a-form-item label="类型" name="type"> <a-form-item label="类型" name="type">
<a-select v-model:value="searchFormState.type" placeholder="请选择类型" :options="typeOptions" /> <a-select v-model:value="searchFormState.type" placeholder="请选择类型" :options="typeOptions" />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="6"> <a-col :span="6">
<a-form-item label="发布位置" name="place"> <a-form-item label="发布位置" name="place">
<a-select v-model:value="searchFormState.place" placeholder="请选择发布位置" :options="placeOptions" /> <a-select v-model:value="searchFormState.place" placeholder="请选择发布位置" :options="placeOptions" />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="6" v-show="advanced"> <a-col :span="6" v-show="advanced">
<a-form-item label="状态" name="status"> <a-form-item label="状态" name="status">
<a-select v-model:value="searchFormState.status" placeholder="请选择状态" :options="statusOptions" /> <a-select v-model:value="searchFormState.status" placeholder="请选择状态" :options="statusOptions" />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="6" v-show="advanced"> <a-col :span="6" v-show="advanced">
<a-form-item label="创建时间" name="createTime"> <a-form-item label="创建时间" name="createTime">
<a-range-picker v-model:value="searchFormState.createTime" show-time /> <a-range-picker v-model:value="searchFormState.createTime" show-time />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="6"> <a-col :span="6">
<a-button type="primary" @click="tableRef.refresh(true)"></a-button> <a-button type="primary" @click="tableRef.refresh(true)"></a-button>
<a-button style="margin: 0 8px" @click="reset"></a-button> <a-button style="margin: 0 8px" @click="reset"></a-button>
<a @click="toggleAdvanced" style="margin-left: 8px"> <a @click="toggleAdvanced" style="margin-left: 8px">
{{ advanced ? '收起' : '展开' }} {{ advanced ? '收起' : '展开' }}
<component :is="advanced ? 'up-outlined' : 'down-outlined'"/> <component :is="advanced ? 'up-outlined' : 'down-outlined'" />
</a> </a>
</a-col> </a-col>
</a-row> </a-row>
</a-form> </a-form>
<s-table <s-table
ref="tableRef" ref="tableRef"
:columns="columns" :columns="columns"
:data="loadData" :data="loadData"
:alert="options.alert.show" :alert="options.alert.show"
bordered bordered
:row-key="(record) => record.id" :row-key="(record) => record.id"
:tool-config="toolConfig" :tool-config="toolConfig"
:row-selection="options.rowSelection" :row-selection="options.rowSelection"
> >
<template #operator class="table-operator"> <template #operator class="table-operator">
<a-space> <a-space>
<a-button type="primary" @click="formRef.onOpen()" v-if="hasPerm('bizNoticeAdd')"> <a-button type="primary" @click="formRef.onOpen()" v-if="hasPerm('bizNoticeAdd')">
<template #icon><plus-outlined /></template> <template #icon><plus-outlined /></template>
新增 新增
</a-button> </a-button>
<xn-batch-delete <xn-batch-button
v-if="hasPerm('bizNoticeBatchDelete')" v-if="hasPerm('bizNoticeBatchDelete')"
:selectedRowKeys="selectedRowKeys" buttonName="批量删除"
@batchDelete="deleteBatchBizNotice" icon="DeleteOutlined"
/> buttonDanger
</a-space> :selectedRowKeys="selectedRowKeys"
</template> @batchCallBack="deleteBatchBizNotice"
<template #bodyCell="{ column, record }"> />
</a-space>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'image'"> <template v-if="column.dataIndex === 'image'">
<div v-if="record.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> </div>
<span v-else></span> <span v-else></span>
</template> </template>
<template v-if="column.dataIndex === 'type'"> <template v-if="column.dataIndex === 'type'">
<a-tag :bordered="false" color="success" v-if="record.type === 'NOTICE'"> <a-tag :bordered="false" color="success" v-if="record.type === 'NOTICE'">
{{ $TOOL.dictTypeData('BIZ_NOTICE_TYPE', record.type) }} {{ $TOOL.dictTypeData('BIZ_NOTICE_TYPE', record.type) }}
</a-tag> </a-tag>
@ -78,12 +81,12 @@
{{ $TOOL.dictTypeData('BIZ_NOTICE_TYPE', record.type) }} {{ $TOOL.dictTypeData('BIZ_NOTICE_TYPE', record.type) }}
</a-tag> </a-tag>
<span v-else></span> <span v-else></span>
</template> </template>
<template v-if="column.dataIndex === 'place'"> <template v-if="column.dataIndex === 'place'">
<a-tag v-for="textValue in JSON.parse(record.place)" :key="textValue" color="processing"> <a-tag v-for="textValue in JSON.parse(record.place)" :key="textValue" color="processing">
{{ $TOOL.dictTypeData('BIZ_NOTICE_PLACE', textValue) }} {{ $TOOL.dictTypeData('BIZ_NOTICE_PLACE', textValue) }}
</a-tag> </a-tag>
</template> </template>
<template v-if="column.dataIndex === 'status'"> <template v-if="column.dataIndex === 'status'">
<a-switch <a-switch
:loading="loading" :loading="loading"
@ -93,134 +96,134 @@
/> />
<span v-else>{{ $TOOL.dictTypeData('BIZ_NOTICE_STATUS', record.status) }}</span> <span v-else>{{ $TOOL.dictTypeData('BIZ_NOTICE_STATUS', record.status) }}</span>
</template> </template>
<template v-if="column.dataIndex === 'action'"> <template v-if="column.dataIndex === 'action'">
<a-space> <a-space>
<a @click="detailRef.onOpen(record.id)" v-if="hasPerm('bizNoticeDetail')"></a> <a @click="detailRef.onOpen(record.id)" v-if="hasPerm('bizNoticeDetail')"></a>
<a-divider type="vertical" v-if="hasPerm(['bizNoticeEdit', 'bizNoticeDetail'], 'and')" /> <a-divider type="vertical" v-if="hasPerm(['bizNoticeEdit', 'bizNoticeDetail'], 'and')" />
<a @click="formRef.onOpen(record)" v-if="hasPerm('bizNoticeEdit')"></a> <a @click="formRef.onOpen(record)" v-if="hasPerm('bizNoticeEdit')"></a>
<a-divider type="vertical" v-if="hasPerm(['bizNoticeEdit', 'bizNoticeDelete'], 'and')" /> <a-divider type="vertical" v-if="hasPerm(['bizNoticeEdit', 'bizNoticeDelete'], 'and')" />
<a-popconfirm title="确定要删除吗?" @confirm="deleteBizNotice(record)"> <a-popconfirm title="确定要删除吗?" @confirm="deleteBizNotice(record)">
<a-button type="link" danger size="small" v-if="hasPerm('bizNoticeDelete')"></a-button> <a-button type="link" danger size="small" v-if="hasPerm('bizNoticeDelete')"></a-button>
</a-popconfirm> </a-popconfirm>
</a-space> </a-space>
</template> </template>
</template> </template>
</s-table> </s-table>
</a-card> </a-card>
<Form ref="formRef" @successful="tableRef.refresh()" /> <Form ref="formRef" @successful="tableRef.refresh()" />
<detail ref="detailRef" /> <detail ref="detailRef" />
</template> </template>
<script setup name="notice"> <script setup name="notice">
import tool from '@/utils/tool' import tool from '@/utils/tool'
import { cloneDeep } from 'lodash-es' import { cloneDeep } from 'lodash-es'
import Form from './form.vue' import Form from './form.vue'
import Detail from './detail.vue' import Detail from './detail.vue'
import bizNoticeApi from '@/api/biz/bizNoticeApi' import bizNoticeApi from '@/api/biz/bizNoticeApi'
const searchFormState = ref({}) const searchFormState = ref({})
const searchFormRef = ref() const searchFormRef = ref()
const tableRef = ref() const tableRef = ref()
const formRef = ref() const formRef = ref()
const detailRef = 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 loading = ref(false)
// //
const advanced = ref(false) const advanced = ref(false)
const toggleAdvanced = () => { const toggleAdvanced = () => {
advanced.value = !advanced.value advanced.value = !advanced.value
} }
const columns = [ const columns = [
{ {
title: '标题', title: '标题',
dataIndex: 'title' dataIndex: 'title'
}, },
{ {
title: '封面图', title: '封面图',
dataIndex: 'image', dataIndex: 'image',
width: '100px' width: '100px'
}, },
{ {
title: '类型', title: '类型',
dataIndex: 'type' dataIndex: 'type'
}, },
{ {
title: '发布位置', title: '发布位置',
dataIndex: 'place' dataIndex: 'place'
}, },
{ {
title: '排序', title: '排序',
dataIndex: 'sortCode', dataIndex: 'sortCode',
sorter: true sorter: true
}, },
{ {
title: '状态', title: '状态',
dataIndex: 'status' dataIndex: 'status'
}, },
{ {
title: '创建时间', title: '创建时间',
dataIndex: 'createTime', dataIndex: 'createTime',
width: '150px' width: '150px'
}, }
] ]
// //
if (hasPerm(['bizNoticeEdit', 'bizNoticeDelete'])) { if (hasPerm(['bizNoticeEdit', 'bizNoticeDelete'])) {
columns.push({ columns.push({
title: '操作', title: '操作',
dataIndex: 'action', dataIndex: 'action',
align: 'center', align: 'center',
width: '200px' width: '200px'
}) })
} }
const selectedRowKeys = ref([]) const selectedRowKeys = ref([])
// //
const options = { const options = {
// columns needTotal: true // columns needTotal: true
alert: { alert: {
show: false, show: false,
clear: () => { clear: () => {
selectedRowKeys.value = ref([]) selectedRowKeys.value = ref([])
} }
}, },
rowSelection: { rowSelection: {
onChange: (selectedRowKey, selectedRows) => { onChange: (selectedRowKey, selectedRows) => {
selectedRowKeys.value = selectedRowKey selectedRowKeys.value = selectedRowKey
} }
} }
} }
const loadData = (parameter) => { const loadData = (parameter) => {
const searchFormParam = cloneDeep(searchFormState.value) const searchFormParam = cloneDeep(searchFormState.value)
// createTime // createTime
if (searchFormParam.createTime) { if (searchFormParam.createTime) {
searchFormParam.startCreateTime = searchFormParam.createTime[0] searchFormParam.startCreateTime = searchFormParam.createTime[0]
searchFormParam.endCreateTime = searchFormParam.createTime[1] searchFormParam.endCreateTime = searchFormParam.createTime[1]
delete searchFormParam.createTime delete searchFormParam.createTime
} }
return bizNoticeApi.bizNoticePage(Object.assign(parameter, searchFormParam)).then((data) => { return bizNoticeApi.bizNoticePage(Object.assign(parameter, searchFormParam)).then((data) => {
return data return data
}) })
} }
// //
const reset = () => { const reset = () => {
searchFormRef.value.resetFields() searchFormRef.value.resetFields()
tableRef.value.refresh(true) tableRef.value.refresh(true)
} }
// //
const deleteBizNotice = (record) => { const deleteBizNotice = (record) => {
let params = [ let params = [
{ {
id: record.id id: record.id
} }
] ]
bizNoticeApi.bizNoticeDelete(params).then(() => { bizNoticeApi.bizNoticeDelete(params).then(() => {
tableRef.value.refresh(true) tableRef.value.refresh(true)
}) })
} }
// //
const deleteBatchBizNotice = (params) => { const deleteBatchBizNotice = (params) => {
bizNoticeApi.bizNoticeDelete(params).then(() => { bizNoticeApi.bizNoticeDelete(params).then(() => {
tableRef.value.clearRefreshSelected() tableRef.value.clearRefreshSelected()
}) })
} }
// //
const editStatus = (record) => { const editStatus = (record) => {
loading.value = true loading.value = true
@ -244,7 +247,7 @@
}) })
} }
} }
const typeOptions = tool.dictList('BIZ_NOTICE_TYPE') const typeOptions = tool.dictList('BIZ_NOTICE_TYPE')
const placeOptions = tool.dictList('BIZ_NOTICE_PLACE') const placeOptions = tool.dictList('BIZ_NOTICE_PLACE')
const statusOptions = tool.dictList('BIZ_NOTICE_STATUS') const statusOptions = tool.dictList('BIZ_NOTICE_STATUS')
</script> </script>

@ -57,10 +57,13 @@
<template #icon><plus-outlined /></template> <template #icon><plus-outlined /></template>
新增 新增
</a-button> </a-button>
<xn-batch-delete <xn-batch-button
v-if="hasPerm('bizOrgBatchDelete')" v-if="hasPerm('bizOrgBatchDelete')"
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys" :selectedRowKeys="selectedRowKeys"
@batchDelete="deleteBatchOrg" @batchCallBack="deleteBatchOrg"
/> />
</a-space> </a-space>
</template> </template>

@ -57,10 +57,13 @@
<template #icon><plus-outlined /></template> <template #icon><plus-outlined /></template>
新增 新增
</a-button> </a-button>
<xn-batch-delete <xn-batch-button
v-if="hasPerm('bizPositionBatchDelete')" v-if="hasPerm('bizPositionBatchDelete')"
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys" :selectedRowKeys="selectedRowKeys"
@batchDelete="deleteBatchPosition" @batchCallBack="deleteBatchPosition"
/> />
</a-space> </a-space>
</template> </template>

@ -77,11 +77,13 @@
<template #icon><export-outlined /></template> <template #icon><export-outlined /></template>
{{ $t('user.batchExportButton') }} {{ $t('user.batchExportButton') }}
</a-button> </a-button>
<xn-batch-delete <xn-batch-button
v-if="hasPerm('bizUserBatchDelete')" v-if="hasPerm('bizUserBatchDelete')"
:buttonName="$t('common.batchRemoveButton')" :buttonName="$t('common.batchRemoveButton')"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys" :selectedRowKeys="selectedRowKeys"
@batchDelete="deleteBatchUser" @batchCallBack="deleteBatchUser"
/> />
</a-space> </a-space>
</template> </template>

@ -183,14 +183,10 @@
id: record.id id: record.id
} }
] ]
dictApi.dictDelete(params).then((res) => { dictApi.dictDelete(params).then(() => {
if (res.code === 200) { tableRef.value.refresh()
tableRef.value.refresh(true) refreshStoreDict()
} else {
res.message && tool.error(res.message)
}
}) })
refreshStoreDict()
} }
// //
const formSuccessful = () => { const formSuccessful = () => {

@ -48,7 +48,13 @@
<UploadOutlined /> <UploadOutlined />
文件上传 文件上传
</a-button> </a-button>
<xn-batch-delete :selectedRowKeys="selectedRowKeys" @batchDelete="deleteBatchFile" /> <xn-batch-button
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchFile"
/>
</a-space> </a-space>
</template> </template>
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">

@ -19,6 +19,14 @@
<a-form-item ref="cronExpressionRef" label="表达式:" name="cronExpression"> <a-form-item ref="cronExpressionRef" label="表达式:" name="cronExpression">
<cron v-model:modelValue="formData.cronExpression" /> <cron v-model:modelValue="formData.cronExpression" />
</a-form-item> </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-form-item label="排序:" name="sortCode">
<a-input-number class="xn-wd" v-model:value="formData.sortCode" :max="100" /> <a-input-number class="xn-wd" v-model:value="formData.sortCode" :max="100" />
</a-form-item> </a-form-item>
@ -54,7 +62,18 @@
sortCode: 99 sortCode: 99
} }
if (record) { 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) => { jobApi.jobGetActionClass().then((data) => {

@ -51,7 +51,13 @@
<template #icon><plus-outlined /></template> <template #icon><plus-outlined /></template>
新增 新增
</a-button> </a-button>
<xn-batch-delete :selectedRowKeys="selectedRowKeys" @batchDelete="deleteBatchJob" /> <xn-batch-button
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchJob"
/>
</a-space> </a-space>
</template> </template>
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">

@ -34,7 +34,13 @@
<template #operator class="table-operator"> <template #operator class="table-operator">
<a-space> <a-space>
<a-button type="primary" @click="formRef.onOpen()"> </a-button> <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> </a-space>
</template> </template>
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">

@ -1,90 +1,89 @@
<template> <template>
<xn-form-container <xn-form-container
:title="formData.id ? '编辑轮播图' : '增加轮播图'" :title="formData.id ? '编辑轮播图' : '增加轮播图'"
:width="700" :width="700"
v-model:open="open" v-model:open="open"
:destroy-on-close="true" :destroy-on-close="true"
@close="onClose" @close="onClose"
> >
<a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical"> <a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
<a-row :gutter="16"> <a-row :gutter="16">
<a-col :span="18"> <a-col :span="18">
<a-form-item label="标题:" name="title"> <a-form-item label="标题:" name="title">
<a-input v-model:value="formData.title" placeholder="请输入标题" allow-clear /> <a-input v-model:value="formData.title" placeholder="请输入标题" allow-clear />
</a-form-item> </a-form-item>
<a-form-item label="排序:" name="sortCode"> <a-form-item label="排序:" name="sortCode">
<a-input v-model:value="formData.sortCode" placeholder="请输入排序" allow-clear /> <a-input v-model:value="formData.sortCode" placeholder="请输入排序" allow-clear />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="6"> <a-col :span="6">
<a-form-item label="图片:" name="image"> <a-form-item label="图片:" name="image">
<xn-upload v-model:value="formData.image" uploadMode="image" /> <xn-upload v-model:value="formData.image" uploadMode="image" />
</a-form-item> </a-form-item>
</a-col>
</a-col> <a-col :span="24">
<a-col :span="24">
<a-form-item label="展示位置:" name="place"> <a-form-item label="展示位置:" name="place">
<a-checkbox-group v-model:value="formData.place" placeholder="请选择展示位置" :options="placeOptions" /> <a-checkbox-group v-model:value="formData.place" placeholder="请选择展示位置" :options="placeOptions" />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="24"> <a-col :span="24">
<sub-form ref="sumFormRef" :data-array="formData.pathDetails" :place="formData.place" /> <sub-form ref="sumFormRef" :data-array="formData.pathDetails" :place="formData.place" />
</a-col> </a-col>
</a-row> </a-row>
</a-form> </a-form>
<template #footer> <template #footer>
<a-button style="margin-right: 8px" @click="onClose"></a-button> <a-button style="margin-right: 8px" @click="onClose"></a-button>
<a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button> <a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button>
</template> </template>
</xn-form-container> </xn-form-container>
</template> </template>
<script setup name="devSlideshowForm"> <script setup name="devSlideshowForm">
import tool from '@/utils/tool' import tool from '@/utils/tool'
import { cloneDeep } from 'lodash-es' import { cloneDeep } from 'lodash-es'
import { required } from '@/utils/formRules' import { required } from '@/utils/formRules'
import slideshowApi from '@/api/dev/slideshowApi' import slideshowApi from '@/api/dev/slideshowApi'
import SubForm from './subForm.vue' import SubForm from './subForm.vue'
// //
const open = ref(false) const open = ref(false)
const emit = defineEmits({ successful: null }) const emit = defineEmits({ successful: null })
const formRef = ref() const formRef = ref()
const sumFormRef = ref() const sumFormRef = ref()
// //
const formData = ref({}) const formData = ref({})
const submitLoading = ref(false) const submitLoading = ref(false)
const placeOptions = ref([]) const placeOptions = ref([])
// //
const onOpen = (record) => { const onOpen = (record) => {
open.value = true open.value = true
if (record) { if (record) {
let recordData = cloneDeep(record) let recordData = cloneDeep(record)
recordData.place = JSON.parse(recordData.place) recordData.place = JSON.parse(recordData.place)
recordData.pathDetails = JSON.parse(recordData.pathDetails) recordData.pathDetails = JSON.parse(recordData.pathDetails)
formData.value = Object.assign({}, recordData) formData.value = Object.assign({}, recordData)
} else { } else {
formData.value = { formData.value = {
place: ['BACK_SYS_INDEX'] place: ['BACK_SYS_INDEX']
} }
} }
placeOptions.value = tool.dictList('DEV_SLIDESHOW_PLACE') placeOptions.value = tool.dictList('DEV_SLIDESHOW_PLACE')
} }
// //
const onClose = () => { const onClose = () => {
formRef.value.resetFields() formRef.value.resetFields()
formData.value = {} formData.value = {}
open.value = false open.value = false
} }
// //
const formRules = { const formRules = {
title: [required('请输入标题')], title: [required('请输入标题')],
place: [required('请输入展示位置')], place: [required('请输入展示位置')],
sortCode: [required('请输入排序')] sortCode: [required('请输入排序')]
} }
// //
const onSubmit = () => { const onSubmit = () => {
formRef.value.validate().then(() => { formRef.value.validate().then(() => {
const formDataParam = cloneDeep(formData.value) const formDataParam = cloneDeep(formData.value)
formDataParam.place = JSON.stringify(formDataParam.place) formDataParam.place = JSON.stringify(formDataParam.place)
const details = sumFormRef.value.getData() const details = sumFormRef.value.getData()
@ -92,20 +91,20 @@
return return
} }
formDataParam.pathDetails = JSON.stringify(details) formDataParam.pathDetails = JSON.stringify(details)
submitLoading.value = true submitLoading.value = true
slideshowApi slideshowApi
.devSlideshowSubmitForm(formDataParam, formDataParam.id) .devSlideshowSubmitForm(formDataParam, formDataParam.id)
.then(() => { .then(() => {
onClose() onClose()
emit('successful') emit('successful')
}) })
.finally(() => { .finally(() => {
submitLoading.value = false submitLoading.value = false
}) })
}) })
} }
// //
defineExpose({ defineExpose({
onOpen onOpen
}) })
</script> </script>

@ -1,38 +1,38 @@
<template> <template>
<a-card :bordered="false"> <a-card :bordered="false">
<a-form ref="searchFormRef" name="advanced_search" :model="searchFormState" class="ant-advanced-search-form"> <a-form ref="searchFormRef" name="advanced_search" :model="searchFormState" class="ant-advanced-search-form">
<a-row :gutter="24"> <a-row :gutter="24">
<a-col :span="6"> <a-col :span="6">
<a-form-item label="标题" name="title"> <a-form-item label="标题" name="title">
<a-input v-model:value="searchFormState.title" placeholder="请输入标题" /> <a-input v-model:value="searchFormState.title" placeholder="请输入标题" />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="6"> <a-col :span="6">
<a-form-item label="展示位置" name="place"> <a-form-item label="展示位置" name="place">
<a-select v-model:value="searchFormState.place" placeholder="请选择展示位置" :options="placeOptions" /> <a-select v-model:value="searchFormState.place" placeholder="请选择展示位置" :options="placeOptions" />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="6"> <a-col :span="6">
<a-form-item label="状态" name="status"> <a-form-item label="状态" name="status">
<a-select v-model:value="searchFormState.status" placeholder="请选择状态" :options="statusOptions" /> <a-select v-model:value="searchFormState.status" placeholder="请选择状态" :options="statusOptions" />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="6"> <a-col :span="6">
<a-button type="primary" @click="tableRef.refresh(true)"></a-button> <a-button type="primary" @click="tableRef.refresh(true)"></a-button>
<a-button style="margin: 0 8px" @click="reset"></a-button> <a-button style="margin: 0 8px" @click="reset"></a-button>
</a-col> </a-col>
</a-row> </a-row>
</a-form> </a-form>
<s-table <s-table
ref="tableRef" ref="tableRef"
:columns="columns" :columns="columns"
:data="loadData" :data="loadData"
:alert="options.alert.show" :alert="options.alert.show"
bordered bordered
:row-key="(record) => record.id" :row-key="(record) => record.id"
:tool-config="toolConfig" :tool-config="toolConfig"
:row-selection="options.rowSelection" :row-selection="options.rowSelection"
> >
<template #expandColumnTitle> <template #expandColumnTitle>
<span>更多</span> <span>更多</span>
</template> </template>
@ -59,24 +59,29 @@
</template> </template>
</a-table> </a-table>
</template> </template>
<template #operator class="table-operator"> <template #operator class="table-operator">
<a-space> <a-space>
<a-button type="primary" @click="formRef.onOpen()"> <a-button type="primary" @click="formRef.onOpen()">
<template #icon><plus-outlined /></template> <template #icon><plus-outlined /></template>
新增 新增
</a-button> </a-button>
<xn-batch-delete <xn-batch-button
:selectedRowKeys="selectedRowKeys" buttonName="批量删除"
@batchDelete="deleteBatchDevSlideshow" icon="DeleteOutlined"
/> buttonDanger
</a-space> :selectedRowKeys="selectedRowKeys"
</template> @batchCallBack="deleteBatchDevSlideshow"
<template #bodyCell="{ column, record }"> />
<template v-if="column.dataIndex === 'place'"> </a-space>
<a-tag v-for="textValue in JSON.parse(record.place)" :key="textValue" color="green">{{ $TOOL.dictTypeData('DEV_SLIDESHOW_PLACE', textValue) }}</a-tag> </template>
</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'"> <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>
<template v-if="column.dataIndex === 'status'"> <template v-if="column.dataIndex === 'status'">
<a-switch <a-switch
@ -86,62 +91,61 @@
v-if="hasPerm('bizNoticerUpdateStatus')" v-if="hasPerm('bizNoticerUpdateStatus')"
/> />
</template> </template>
<template v-if="column.dataIndex === 'action'"> <template v-if="column.dataIndex === 'action'">
<a-space> <a-space>
<a @click="formRef.onOpen(record)"></a> <a @click="formRef.onOpen(record)"></a>
<a-divider type="vertical" /> <a-divider type="vertical" />
<a-popconfirm title="确定要删除吗?" @confirm="deleteDevSlideshow(record)"> <a-popconfirm title="确定要删除吗?" @confirm="deleteDevSlideshow(record)">
<a-button type="link" danger size="small">删除</a-button> <a-button type="link" danger size="small">删除</a-button>
</a-popconfirm> </a-popconfirm>
</a-space> </a-space>
</template> </template>
</template> </template>
</s-table>
</s-table> </a-card>
</a-card> <Form ref="formRef" @successful="tableRef.refresh()" />
<Form ref="formRef" @successful="tableRef.refresh()" />
</template> </template>
<script setup name="slideshow"> <script setup name="slideshow">
import tool from '@/utils/tool' import tool from '@/utils/tool'
import { cloneDeep } from 'lodash-es' import { cloneDeep } from 'lodash-es'
import Form from './form.vue' import Form from './form.vue'
import slideshowApi from '@/api/dev/slideshowApi' import slideshowApi from '@/api/dev/slideshowApi'
const searchFormState = ref({}) const searchFormState = ref({})
const searchFormRef = ref() const searchFormRef = ref()
const tableRef = ref() const tableRef = ref()
const formRef = ref() const formRef = ref()
const loading = ref(false) const loading = ref(false)
const toolConfig = { refresh: true, height: true, columnSetting: true, striped: false } const toolConfig = { refresh: true, height: true, columnSetting: true, striped: false }
const columns = [ const columns = [
{ {
title: '标题', title: '标题',
dataIndex: 'title' dataIndex: 'title'
}, },
{ {
title: '图片', title: '图片',
dataIndex: 'image' dataIndex: 'image'
}, },
{ {
title: '展示位置', title: '展示位置',
dataIndex: 'place' dataIndex: 'place'
}, },
{ {
title: '状态', title: '状态',
dataIndex: 'status' dataIndex: 'status'
}, },
{ {
title: '排序', title: '排序',
dataIndex: 'sortCode', dataIndex: 'sortCode',
sorter: true sorter: true
}, },
{ {
title: '操作', title: '操作',
dataIndex: 'action', dataIndex: 'action',
align: 'center', align: 'center',
width: '150px' width: '150px'
} }
] ]
const detailsColumns = [ const detailsColumns = [
{ {
title: '位置', title: '位置',
@ -161,50 +165,50 @@
dataIndex: 'url' dataIndex: 'url'
} }
] ]
const selectedRowKeys = ref([]) const selectedRowKeys = ref([])
// //
const options = { const options = {
// columns needTotal: true // columns needTotal: true
alert: { alert: {
show: false, show: false,
clear: () => { clear: () => {
selectedRowKeys.value = ref([]) selectedRowKeys.value = ref([])
} }
}, },
rowSelection: { rowSelection: {
onChange: (selectedRowKey, selectedRows) => { onChange: (selectedRowKey, selectedRows) => {
selectedRowKeys.value = selectedRowKey selectedRowKeys.value = selectedRowKey
} }
} }
} }
const loadData = (parameter) => { const loadData = (parameter) => {
const searchFormParam = cloneDeep(searchFormState.value) const searchFormParam = cloneDeep(searchFormState.value)
return slideshowApi.devSlideshowPage(Object.assign(parameter, searchFormParam)).then((data) => { return slideshowApi.devSlideshowPage(Object.assign(parameter, searchFormParam)).then((data) => {
return data return data
}) })
} }
// //
const reset = () => { const reset = () => {
searchFormRef.value.resetFields() searchFormRef.value.resetFields()
tableRef.value.refresh(true) tableRef.value.refresh(true)
} }
// //
const deleteDevSlideshow = (record) => { const deleteDevSlideshow = (record) => {
let params = [ let params = [
{ {
id: record.id id: record.id
} }
] ]
slideshowApi.devSlideshowDelete(params).then(() => { slideshowApi.devSlideshowDelete(params).then(() => {
tableRef.value.refresh() tableRef.value.refresh()
}) })
} }
// //
const deleteBatchDevSlideshow = (params) => { const deleteBatchDevSlideshow = (params) => {
slideshowApi.devSlideshowDelete(params).then(() => { slideshowApi.devSlideshowDelete(params).then(() => {
tableRef.value.clearRefreshSelected() tableRef.value.clearRefreshSelected()
}) })
} }
// //
const editStatus = (record) => { const editStatus = (record) => {
loading.value = true 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') const statusOptions = tool.dictList('DEV_SLIDESHOW_STATUS')
</script> </script>

@ -1,25 +1,33 @@
<template> <template>
<a-form <a-form :model="formData" ref="formRef" name="basic" autocomplete="off">
:model="formData"
ref="formRef"
name="basic"
autocomplete="off"
>
<a-table :columns="columns" :dataSource="formData" size="middle"> <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'"> <template v-if="column.dataIndex === 'whetherToClick'">
<a-form-item :validate-status="validateStatus(record, '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> </a-form-item>
</template> </template>
<template v-if="column.dataIndex === 'skipMode'"> <template v-if="column.dataIndex === 'skipMode'">
<a-form-item :validate-status="validateStatus(record, '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> </a-form-item>
</template> </template>
<template v-if="column.dataIndex === 'url'"> <template v-if="column.dataIndex === 'url'">
<a-form-item :validate-status="validateStatus(record, '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> </a-form-item>
</template> </template>
</template> </template>
@ -28,7 +36,7 @@
</template> </template>
<script name="subForm" setup> <script name="subForm" setup>
import tool from "@/utils/tool" import tool from '@/utils/tool'
import { remove, isEmpty, cloneDeep } from 'lodash-es' import { remove, isEmpty, cloneDeep } from 'lodash-es'
const formRef = ref() const formRef = ref()
const formData = ref([]) const formData = ref([])
@ -48,17 +56,17 @@
{ {
title: '位置', title: '位置',
dataIndex: 'label', dataIndex: 'label',
width: '20%', width: '20%'
}, },
{ {
title: '点击事件', title: '点击事件',
dataIndex: 'whetherToClick', dataIndex: 'whetherToClick',
width: '25%', width: '25%'
}, },
{ {
title: '跳转方式', title: '跳转方式',
dataIndex: 'skipMode', dataIndex: 'skipMode',
width: '20%', width: '20%'
}, },
{ {
title: 'URL', title: 'URL',
@ -77,7 +85,7 @@
const dataFiltrate = (newVal, oldVal) => { const dataFiltrate = (newVal, oldVal) => {
let result = '' let result = ''
oldVal.forEach((data) => { oldVal.forEach((data) => {
if (!newVal.some(item => item === data)) { if (!newVal.some((item) => item === data)) {
result = data result = data
} }
}) })
@ -89,11 +97,11 @@
if (!isEmpty(props.dataArray) && isEmpty(formData.value)) { if (!isEmpty(props.dataArray) && isEmpty(formData.value)) {
formData.value = cloneDeep(props.dataArray) formData.value = cloneDeep(props.dataArray)
} else { } else {
if (typeof newVal === "object") { if (typeof newVal === 'object') {
if (!isEmpty(formData.value)) { if (!isEmpty(formData.value)) {
formData.value.forEach(() => { formData.value.forEach(() => {
// //
if (!newVal.some(item => item === item.key)) { if (!newVal.some((item) => item === item.key)) {
// //
if (formData.value.length > newVal.length) { if (formData.value.length > newVal.length) {
const deleteData = dataFiltrate(newVal, oldVal) const deleteData = dataFiltrate(newVal, oldVal)
@ -103,10 +111,10 @@
if (formData.value.length < newVal.length) { if (formData.value.length < newVal.length) {
const deleteData = dataFiltrate(oldVal, newVal) const deleteData = dataFiltrate(oldVal, newVal)
// //
if (!formData.value.some(item => item === deleteData)) { if (!formData.value.some((item) => item === deleteData)) {
const obj = { const obj = {
key: deleteData, key: deleteData,
label: tool.dictTypeData('DEV_SLIDESHOW_PLACE' , deleteData), label: tool.dictTypeData('DEV_SLIDESHOW_PLACE', deleteData),
whetherToClick: 'DISABLE', whetherToClick: 'DISABLE',
skipMode: 'URL', skipMode: 'URL',
url: '' url: ''
@ -120,7 +128,7 @@
newVal.forEach((item) => { newVal.forEach((item) => {
const obj = { const obj = {
key: item, key: item,
label: tool.dictTypeData('DEV_SLIDESHOW_PLACE' , item), label: tool.dictTypeData('DEV_SLIDESHOW_PLACE', item),
whetherToClick: 'DISABLE', whetherToClick: 'DISABLE',
skipMode: 'URL', skipMode: 'URL',
url: '' url: ''

@ -48,7 +48,13 @@
<template #icon><plus-outlined /></template> <template #icon><plus-outlined /></template>
发送短信 发送短信
</a-button> </a-button>
<xn-batch-delete :selectedRowKeys="selectedRowKeys" @batchDelete="deleteBatchSms" /> <xn-batch-button
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchSms"
/>
</a-space> </a-space>
</template> </template>
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">

@ -180,7 +180,6 @@
<script setup name="genBasic"> <script setup name="genBasic">
import { required } from '@/utils/formRules' import { required } from '@/utils/formRules'
import tool from '@/utils/tool'
import genBasicApi from '@/api/gen/genBasicApi' import genBasicApi from '@/api/gen/genBasicApi'
const formRef = ref() const formRef = ref()
// //
@ -235,10 +234,14 @@
// //
const onOpen = (record) => { const onOpen = (record) => {
// //
moduleOptions.value = tool.data.get('MENU').map((item) => { genBasicApi.basicModuleSelector().then((data) => {
return { if (data) {
label: item.name, moduleOptions.value = data.map((item) => {
value: item.id return {
label: item.name,
value: item.id
}
})
} }
}) })
// //
@ -324,19 +327,22 @@
formData.value.menuPid = undefined formData.value.menuPid = undefined
} }
// //
const menuTree = tool.data.get('MENU').find((item) => {
if (item.id === value) {
return item
}
})
menuTreeData.value = [ menuTreeData.value = [
{ {
id: '0', id: '0',
title: '顶级', title: '顶级',
menuType: 'CATALOG', 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 = []) => { const traverseChildren = (data = []) => {

@ -43,7 +43,7 @@
<span v-else></span> <span v-else></span>
</template> </template>
<template v-if="column.dataIndex === 'whetherTable'"> <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>
<template v-if="column.dataIndex === 'whetherRetract'"> <template v-if="column.dataIndex === 'whetherRetract'">
<a-checkbox v-model:checked="record.whetherRetract" :disabled="!record.whetherTable" /> <a-checkbox v-model:checked="record.whetherRetract" :disabled="!record.whetherTable" />

@ -17,7 +17,13 @@
<template #icon><plus-outlined /></template> <template #icon><plus-outlined /></template>
新建 新建
</a-button> </a-button>
<xn-batch-delete :selectedRowKeys="selectedRowKeys" @batchDelete="deleteBatchCodeGen" /> <xn-batch-button
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchCodeGen"
/>
</a-space> </a-space>
</template> </template>
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">

@ -41,7 +41,13 @@
<template #icon><plus-outlined /></template> <template #icon><plus-outlined /></template>
新增 新增
</a-button> </a-button>
<xn-batch-delete :selectedRowKeys="selectedRowKeys" @batchDelete="deleteBatchMobileMenu" /> <xn-batch-button
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchMobileMenu"
/>
</a-space> </a-space>
</template> </template>
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">

@ -33,7 +33,13 @@
</template> </template>
新增模块 新增模块
</a-button> </a-button>
<xn-batch-delete :selectedRowKeys="selectedRowKeys" @batchDelete="deleteBatchModule" /> <xn-batch-button
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchModule"
/>
</a-space> </a-space>
</template> </template>
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">

@ -51,7 +51,13 @@
<template #icon><plus-outlined /></template> <template #icon><plus-outlined /></template>
新增 新增
</a-button> </a-button>
<xn-batch-delete :selectedRowKeys="selectedRowKeys" @batchDelete="deleteBatchOrg" /> <xn-batch-button
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchOrg"
/>
</a-space> </a-space>
</template> </template>
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">

@ -52,7 +52,13 @@
<template #icon><plus-outlined /></template> <template #icon><plus-outlined /></template>
新增 新增
</a-button> </a-button>
<xn-batch-delete :selectedRowKeys="selectedRowKeys" @batchDelete="deleteBatchPosition" /> <xn-batch-button
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchPosition"
/>
</a-space> </a-space>
</template> </template>
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">

@ -40,9 +40,23 @@
<template #icon><plus-outlined /></template> <template #icon><plus-outlined /></template>
新增菜单 新增菜单
</a-button> </a-button>
<xn-batch-delete :selectedRowKeys="selectedRowKeys" @batchDelete="deleteBatchMenu" /> <xn-batch-button
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchMenu"
/>
</a-space> </a-space>
</template> </template>
<template #headerCell="{ title, column }">
<template v-if="column.dataIndex === 'visible'">
<a-tooltip>
<template #title> 如果将上级目录设置为隐藏那么上级目录下的菜单都会被隐藏 </template>
<question-circle-outlined />&nbsp {{ title }}
</a-tooltip>
</template>
</template>
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'path'"> <template v-if="column.dataIndex === 'path'">
<span v-if="record.menuType === 'MENU'">{{ record.path }}</span> <span v-if="record.menuType === 'MENU'">{{ record.path }}</span>
@ -133,12 +147,12 @@
const columns = [ const columns = [
{ {
title: '显示名称', title: '显示名称',
dataIndex: 'title', dataIndex: 'title'
width: 260
}, },
{ {
title: '图标', title: '图标',
dataIndex: 'icon' dataIndex: 'icon',
width: 100
}, },
{ {
title: '类型', title: '类型',
@ -160,12 +174,13 @@
{ {
title: '是否可见', title: '是否可见',
dataIndex: 'visible', dataIndex: 'visible',
width: 100 width: 120
}, },
{ {
title: '排序', title: '排序',
dataIndex: 'sortCode', dataIndex: 'sortCode',
sorter: true sorter: true,
width: 100
}, },
{ {
title: '操作', title: '操作',

@ -31,7 +31,13 @@
<template #icon><plus-outlined /></template> <template #icon><plus-outlined /></template>
新增模块 新增模块
</a-button> </a-button>
<xn-batch-delete :selectedRowKeys="selectedRowKeys" @batchDelete="deleteBatchModule" /> <xn-batch-button
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchModule"
/>
</a-space> </a-space>
</template> </template>
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">

@ -56,7 +56,13 @@
<template #icon><plus-outlined /></template> <template #icon><plus-outlined /></template>
新增角色 新增角色
</a-button> </a-button>
<xn-batch-delete :selectedRowKeys="selectedRowKeys" @batchDelete="deleteBatchRole" /> <xn-batch-button
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchRole"
/>
</a-space> </a-space>
</template> </template>
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">

@ -76,10 +76,12 @@
<template #icon><export-outlined /></template> <template #icon><export-outlined /></template>
{{ $t('user.batchExportButton') }} {{ $t('user.batchExportButton') }}
</a-button> </a-button>
<xn-batch-delete <xn-batch-button
:buttonName="$t('common.batchRemoveButton')" :buttonName="$t('common.batchRemoveButton')"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys" :selectedRowKeys="selectedRowKeys"
@batchDelete="deleteBatchUser" @batchCallBack="deleteBatchUser"
/> />
</a-space> </a-space>
</template> </template>

@ -33,7 +33,7 @@ public enum CommonSortOrderEnum {
private final String value; private final String value;
CommonSortOrderEnum(String value) { CommonSortOrderEnum(String value) {
this.value = value.toUpperCase(); this.value = value.toLowerCase();
} }
public static void validate(String value) { public static void validate(String value) {

@ -26,5 +26,5 @@ public interface CommonTimerTaskRunner {
* @author xuyuxiang * @author xuyuxiang
* @date 2022/8/15 16:09 * @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())); input = new BufferedReader(new InputStreamReader(pro.getInputStream()));
long[] result2 = readInLine(input, isWindows); long[] result2 = readInLine(input, isWindows);
String upSpeed = FileUtil.readableFileSize(Convert.toLong(NumberUtil 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))); .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("UP", upSpeed + (upSpeed.endsWith("B")?"/S":"B/S"));
result.put("DOWN", downSpeed + (downSpeed.endsWith("B")?"/S":"B/S")); result.put("DOWN", downSpeed + (downSpeed.endsWith("B")?"/S":"B/S"));
} catch (Exception e) { } catch (Exception e) {

@ -12,6 +12,10 @@
*/ */
package vip.xiaonuo.sys.api; package vip.xiaonuo.sys.api;
import cn.hutool.core.lang.tree.Tree;
import java.util.List;
/** /**
* API * API
* *
@ -27,4 +31,12 @@ public interface SysMenuApi {
* @date 2022/11/1 13:48 * @date 2022/11/1 13:48
**/ **/
String addForGenMenu(String parentId, String busName, String module, String title, String path); 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]
*
* SnowyAPACHE 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(), () -> { .forEach(devJob -> CronUtil.schedule(devJob.getId(), devJob.getCronExpression(), () -> {
try { try {
// 运行定时任务 // 运行定时任务
((CommonTimerTaskRunner) SpringUtil.getBean(Class.forName(devJob.getActionClass()))).action(); ((CommonTimerTaskRunner) SpringUtil.getBean(Class.forName(devJob.getActionClass()))).action(devJob.getExtJson());
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
throw new CommonException("定时任务找不到对应的类,名称为:{}", devJob.getActionClass()); throw new CommonException("定时任务找不到对应的类,名称为:{}", devJob.getActionClass());
} }

@ -61,8 +61,9 @@ public class DevApiProvider implements DevApi {
DevDictCategoryEnum.FRM.getValue())); DevDictCategoryEnum.FRM.getValue()));
Long bizDictCount = devDictService.count(new LambdaQueryWrapper<DevDict>().eq(DevDict::getCategory, Long bizDictCount = devDictService.count(new LambdaQueryWrapper<DevDict>().eq(DevDict::getCategory,
DevDictCategoryEnum.BIZ.getValue())); DevDictCategoryEnum.BIZ.getValue()));
Long jobCount = devJobService.count(new LambdaQueryWrapper<DevJob>().eq(DevJob::getJobStatus, Long jobCount = 0L;
DevJobStatusEnum.RUNNING.getValue())); // Long jobCount = devJobService.count(new LambdaQueryWrapper<DevJob>().eq(DevJob::getJobStatus,
// DevJobStatusEnum.RUNNING.getValue()));
JSONObject json = new JSONObject(); JSONObject json = new JSONObject();
json.set("sysDictCount", sysDictCount); json.set("sysDictCount", sysDictCount);
json.set("bizDictCount", bizDictCount); json.set("bizDictCount", bizDictCount);

@ -70,7 +70,7 @@ public class DevEmailAliyunUtil {
} }
try { 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) { } catch (Exception e) {
throw new CommonException(e.getMessage()); throw new CommonException(e.getMessage());
} }

@ -214,7 +214,7 @@ public class DevJobServiceImpl extends ServiceImpl<DevJobMapper, DevJob> impleme
CronUtil.schedule(devJob.getId(), devJob.getCronExpression(), () -> { CronUtil.schedule(devJob.getId(), devJob.getCronExpression(), () -> {
try { try {
// 运行定时任务 // 运行定时任务
((CommonTimerTaskRunner) SpringUtil.getBean(Class.forName(devJob.getActionClass()))).action(); ((CommonTimerTaskRunner) SpringUtil.getBean(Class.forName(devJob.getActionClass()))).action(devJob.getExtJson());
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
throw new CommonException("定时任务找不到对应的类,名称为:{}", devJob.getActionClass()); throw new CommonException("定时任务找不到对应的类,名称为:{}", devJob.getActionClass());
} }
@ -232,7 +232,7 @@ public class DevJobServiceImpl extends ServiceImpl<DevJobMapper, DevJob> impleme
} }
try { try {
// 直接运行一次 // 直接运行一次
((CommonTimerTaskRunner) SpringUtil.getBean(Class.forName(devJob.getActionClass()))).action(); ((CommonTimerTaskRunner) SpringUtil.getBean(Class.forName(devJob.getActionClass()))).action(devJob.getExtJson());
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
throw new CommonException("定时任务找不到对应的类,名称为:{}", devJob.getActionClass()); throw new CommonException("定时任务找不到对应的类,名称为:{}", devJob.getActionClass());
} }

@ -29,7 +29,7 @@ public class DevJobTimerTaskRunner implements CommonTimerTaskRunner {
private int n = 1; private int n = 1;
@Override @Override
public void action() { public void action(String extJson) {
log.info("我是一个定时任务,正在在被执行第" + n + "次"); log.info("我是一个定时任务,正在在被执行第" + n + "次");
n = n + 1; n = n + 1;
} }

@ -17,6 +17,7 @@ import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.PhoneUtil; import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 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.enums.CommonSortOrderEnum;
import vip.xiaonuo.common.exception.CommonException; import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.page.CommonPageRequest; 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.entity.DevSms;
import vip.xiaonuo.dev.modular.sms.enums.DevSmsEngineTypeEnum; import vip.xiaonuo.dev.modular.sms.enums.DevSmsEngineTypeEnum;
import vip.xiaonuo.dev.modular.sms.mapper.DevSmsMapper; 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.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil; import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.sms4j.api.SmsBlend; import org.dromara.sms4j.api.SmsBlend;
@ -106,7 +107,8 @@ public class DevSmsXiaonuoUtil {
if(smsResponse.isSuccess()) { if(smsResponse.isSuccess()) {
return JSONUtil.toJsonStr(smsResponse.getData()); return JSONUtil.toJsonStr(smsResponse.getData());
} else { } else {
throw new CommonException("短信发送失败"); JSONObject responseData = JSONUtil.parseObj(smsResponse.getData());
throw new CommonException(responseData.getStr("resInfo"));
} }
} catch (Exception e) { } catch (Exception e) {
throw new CommonException(e.getMessage()); throw new CommonException(e.getMessage());

@ -12,6 +12,7 @@
*/ */
package vip.xiaonuo.gen.modular.basic.controller; package vip.xiaonuo.gen.modular.basic.controller;
import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; 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.common.pojo.CommonResult;
import vip.xiaonuo.gen.modular.basic.entity.GenBasic; import vip.xiaonuo.gen.modular.basic.entity.GenBasic;
import vip.xiaonuo.gen.modular.basic.param.*; import vip.xiaonuo.gen.modular.basic.param.*;
import vip.xiaonuo.gen.modular.basic.result.GenBasicMobileModuleSelectorResult; import vip.xiaonuo.gen.modular.basic.result.*;
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.service.GenBasicService; import vip.xiaonuo.gen.modular.basic.service.GenBasicService;
import java.io.IOException; import java.io.IOException;
@ -192,5 +190,29 @@ public class GenBasicController {
public CommonResult<List<GenBasicMobileModuleSelectorResult>> mobileModuleSelector() { public CommonResult<List<GenBasicMobileModuleSelectorResult>> mobileModuleSelector() {
return CommonResult.data(genBasicService.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]
*
* SnowyAPACHE 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]
*
* SnowyAPACHE 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; 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.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import vip.xiaonuo.gen.modular.basic.entity.GenBasic; import vip.xiaonuo.gen.modular.basic.entity.GenBasic;
import vip.xiaonuo.gen.modular.basic.param.*; import vip.xiaonuo.gen.modular.basic.param.*;
import vip.xiaonuo.gen.modular.basic.result.GenBasicMobileModuleSelectorResult; import vip.xiaonuo.gen.modular.basic.result.*;
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 java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -128,4 +126,20 @@ public interface GenBasicService extends IService<GenBasic> {
* @date 2023/7/15 22:28 * @date 2023/7/15 22:28
**/ **/
List<GenBasicMobileModuleSelectorResult> mobileModuleSelector(); 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.DateTime;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil; 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.enums.GenYesNoEnum;
import vip.xiaonuo.gen.modular.basic.mapper.GenBasicMapper; import vip.xiaonuo.gen.modular.basic.mapper.GenBasicMapper;
import vip.xiaonuo.gen.modular.basic.param.*; import vip.xiaonuo.gen.modular.basic.param.*;
import vip.xiaonuo.gen.modular.basic.result.GenBasicMobileModuleSelectorResult; import vip.xiaonuo.gen.modular.basic.result.*;
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.service.GenBasicService; import vip.xiaonuo.gen.modular.basic.service.GenBasicService;
import vip.xiaonuo.gen.modular.config.entity.GenConfig; import vip.xiaonuo.gen.modular.config.entity.GenConfig;
import vip.xiaonuo.gen.modular.config.param.GenConfigAddParam; 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.mobile.api.MobileModuleApi;
import vip.xiaonuo.sys.api.SysButtonApi; import vip.xiaonuo.sys.api.SysButtonApi;
import vip.xiaonuo.sys.api.SysMenuApi; import vip.xiaonuo.sys.api.SysMenuApi;
import vip.xiaonuo.sys.api.SysModuleApi;
import vip.xiaonuo.sys.api.SysRoleApi; import vip.xiaonuo.sys.api.SysRoleApi;
import java.io.File; import java.io.File;
@ -148,6 +147,9 @@ public class GenBasicServiceImpl extends ServiceImpl<GenBasicMapper, GenBasic> i
@Resource @Resource
private SysMenuApi sysMenuApi; private SysMenuApi sysMenuApi;
@Resource
private SysModuleApi sysModuleApi;
@Resource @Resource
private SysButtonApi sysButtonApi; private SysButtonApi sysButtonApi;
@ -597,7 +599,20 @@ public class GenBasicServiceImpl extends ServiceImpl<GenBasicMapper, GenBasic> i
@Override @Override
public List<GenBasicMobileModuleSelectorResult> mobileModuleSelector() { public List<GenBasicMobileModuleSelectorResult> mobileModuleSelector() {
return mobileModuleApi.mobileModuleSelector().stream() 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> <template #icon><plus-outlined /></template>
新增 新增
</a-button> </a-button>
<xn-batch-delete <xn-batch-button
v-if="hasPerm('${classNameFirstLower}BatchDelete')" v-if="hasPerm('${classNameFirstLower}BatchDelete')"
buttonName="批量删除"
icon="DeleteOutlined"
:selectedRowKeys="selectedRowKeys" :selectedRowKeys="selectedRowKeys"
@batchDelete="deleteBatch${className}" @batchCallBack="deleteBatch${className}"
/> />
</a-space> </a-space>
</template> </template>

@ -17,6 +17,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -96,7 +97,7 @@ public class MobileButtonController {
@Operation(summary = "删除移动端按钮") @Operation(summary = "删除移动端按钮")
@CommonLog("删除移动端按钮") @CommonLog("删除移动端按钮")
@PostMapping("/mobile/button/delete") @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); mobileButtonService.delete(mobileButtonIdParamList);
return CommonResult.ok(); return CommonResult.ok();
} }

@ -17,6 +17,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -96,7 +97,7 @@ public class SysButtonController {
@Operation(summary = "删除按钮") @Operation(summary = "删除按钮")
@CommonLog("删除按钮") @CommonLog("删除按钮")
@PostMapping("/sys/button/delete") @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); sysButtonService.delete(sysButtonIdParamList);
return CommonResult.ok(); return CommonResult.ok();
} }

@ -12,11 +12,15 @@
*/ */
package vip.xiaonuo.sys.modular.resource.provider; package vip.xiaonuo.sys.modular.resource.provider;
import cn.hutool.core.lang.tree.Tree;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import vip.xiaonuo.sys.api.SysMenuApi; import vip.xiaonuo.sys.api.SysMenuApi;
import vip.xiaonuo.sys.modular.resource.param.menu.SysMenuSelectorMenuParam;
import vip.xiaonuo.sys.modular.resource.service.SysMenuService; import vip.xiaonuo.sys.modular.resource.service.SysMenuService;
import java.util.List;
/** /**
* API * API
* *
@ -33,4 +37,11 @@ public class SysMenuApiProvider implements SysMenuApi {
public String addForGenMenu(String parentId, String busName, String module, String title, String path) { public String addForGenMenu(String parentId, String busName, String module, String title, String path) {
return sysMenuService.addForGenMenu(parentId, busName, title, module, 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]
*
* SnowyAPACHE 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; 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.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import vip.xiaonuo.sys.modular.resource.entity.SysModule; import vip.xiaonuo.sys.modular.resource.entity.SysModule;
@ -62,6 +63,14 @@ public interface SysModuleService extends IService<SysModule> {
*/ */
void delete(List<SysModuleIdParam> sysModuleIdParamList); 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.ObjectUtil;
import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 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 @Override
public SysModule detail(SysModuleIdParam sysModuleIdParam) { public SysModule detail(SysModuleIdParam sysModuleIdParam) {
return this.queryEntity(sysModuleIdParam.getId()); 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.getCategory().equals(SysResourceCategoryEnum.MENU.getValue())) {
if (!sysMenu.getMenuType().equals(SysResourceMenuTypeEnum.CATALOG.getValue())) { if (!sysMenu.getMenuType().equals(SysResourceMenuTypeEnum.CATALOG.getValue())) {
metaJsonObject.set("type", sysMenu.getMenuType().toLowerCase()); 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())) { if (sysMenu.getId().equals(sysMenus.orElse(null).getId())) {
// 如果是首页则设置affix // 如果是首页则设置affix
metaJsonObject.set("affix", true); metaJsonObject.set("affix", true);
} }
} }
// 如果设置了不可见那么设置为false为了兼容已有所以只是false的为不显示
if (ObjectUtil.isNotEmpty(sysMenu.getVisible()) && sysMenu.getVisible().equals("FALSE")) {
metaJsonObject.set("hidden", true);
}
menuJsonObject.set("meta", metaJsonObject); menuJsonObject.set("meta", metaJsonObject);
return menuJsonObject; return menuJsonObject;
}).collect(Collectors.toList()); }).toList();
// 执行构造树 // 执行构造树
List<TreeNode<String>> treeNodeList = resultJsonObjectList.stream().map(jsonObject -> 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.time-zone=GMT+8
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.locale=zh_CN spring.jackson.locale=zh_CN
spring.jackson.serialization.write-dates-as-timestamps=true spring.jackson.serialization.write-dates-as-timestamps=false
######################################### #########################################
# redis configuration # redis configuration
######################################### #########################################

Loading…
Cancel
Save