【升级】v3.3版本更新

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

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

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

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

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

@ -45,5 +45,13 @@ export default {
// 获取所有移动端模块
basicMobileModuleSelector(data) {
return request('mobileModuleSelector', data, 'get')
},
// 获取所有模块
basicModuleSelector(data) {
return request('moduleSelector', data, 'get')
},
// 获取所有菜单树包括未授权的
basicMenuTreeSelector(data) {
return request('menuTreeSelector', data, 'get')
}
}

@ -9,16 +9,14 @@
<template #nextArrow>
<div class="custom-slick-arrow" style="right: 10px"><RightOutlined /></div>
</template>
<div v-if="!isEmpty(slideshowList)">
<img
v-for="item in slideshowList"
:key="item.id"
:src="item.image"
class="carousel-images"
@click="leaveForOpen(item.pathDetails)"
/>
</div>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
<img
v-for="item in slideshowList"
:key="item.id"
:src="item.image"
class="carousel-images"
@click="leaveForOpen(item.pathDetails)"
/>
<a-empty v-if="isEmpty(slideshowList)" :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</a-carousel>
</a-card>
</template>
@ -57,18 +55,18 @@
return
}
const detail = cloneDeep(value)
let detailObj = {}
let result = {}
if (typeof detail !== 'object') {
detailObj = JSON.parse(detail)
result = JSON.parse(detail)
}
// json
if (detailObj.whetherToClick && detailObj.whetherToClick === 'ENABLE') {
if (detailObj.skipMode && detailObj.skipMode === 'URL') {
window.open(detailObj.url)
if (result.whetherToClick && result.whetherToClick === 'ENABLE') {
if (result.skipMode && result.skipMode === 'URL') {
window.open(result.url)
}
if (detailObj.skipMode && detailObj.skipMode === 'ROUTER') {
if (result.skipMode && result.skipMode === 'ROUTER') {
router.replace({
path: detailObj.url
path: result.url
})
}
}

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

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

@ -55,10 +55,10 @@
})
const contentValue = ref()
const init = ref({
language_url: import.meta.env.BASE_URL + 'tinymce/langs/zh_CN.js',
language_url: 'tinymce/langs/zh_CN.js',
language: 'zh_CN',
skin_url: import.meta.env.BASE_URL + 'tinymce/skins/ui/oxide',
content_css: import.meta.env.BASE_URL + 'tinymce/skins/content/default/content.css',
skin_url: 'tinymce/skins/ui/oxide',
content_css: 'tinymce/skins/content/default/content.css',
menubar: false,
statusbar: true,
plugins: props.plugins,

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

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

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

@ -53,7 +53,12 @@
</div>
</template>
<a-tab-pane v-for="tag in tagList" :key="tag.fullPath" :tab="tag.meta.title" :closable="!tag.meta.affix">
<a-tab-pane v-for="tag in tagList" :key="tag.fullPath" :closable="!tag.meta.affix">
<template #tab>
<span :key="tag.meta.key">
{{ tag.meta.title }}
</span>
</template>
</a-tab-pane>
</a-tabs>
</div>

@ -88,7 +88,6 @@
import sysConfig from '@/config/index'
import dictApi from '@/api/dev/dictApi'
let timer = null
const store = globalStore()
const kStore = keepAliveStore()
const route = useRoute()
@ -265,52 +264,47 @@
})
})
onBeforeUnmount(() => {
clearUpdateVersion()
window.removeEventListener('resize', onLayoutResize)
window.removeEventListener('resize', getNav)
})
//
const updateVersion = () => {
timer = setInterval(async () => {
//
let localVersion = getLocalHash()
// 线
let onlineVersion = await checkHash()
//
if (localVersion !== onlineVersion) {
if (document.querySelector('.notification-update-version')) {
return
const updateVersionOpen = import.meta.env.VITE_VERSION_UPDATE
if (updateVersionOpen) {
setTimeout(async () => {
//
let localVersion = getLocalHash()
// 线
let onlineVersion = await checkHash()
//
if (localVersion !== onlineVersion) {
if (document.querySelector('.notification-update-version')) {
return
}
const key = `open${Date.now()}`
notification.open({
type: 'info',
message: '发现新版本',
description: '检测到新版本,请刷新后使用',
duration: 0,
class: 'notification-update-version',
btn: () =>
h(
Button,
{
type: 'primary',
size: 'small',
onClick: () => {
notification.close(key)
window.location.reload()
}
},
{ default: () => '立即更新' }
),
key
})
}
const key = `open${Date.now()}`
notification.open({
type: 'info',
message: '发现新版本',
description: '检测到新版本,请刷新后使用',
duration: 0,
class: 'notification-update-version',
btn: () =>
h(
Button,
{
type: 'primary',
size: 'small',
onClick: () => {
notification.close(key)
window.location.reload()
}
},
{ default: () => '立即更新' }
),
key
})
}
}, sysConfig.UPDATE_VERSION_TIME)
}
//
const clearUpdateVersion = () => {
if (timer) {
clearInterval(timer)
timer = null
}, 3000)
}
}
//
@ -339,7 +333,7 @@
menuList.value = menuNavList
return
}
//
//
const showNav = menuNavList.slice(0, startIndex)
const hiddenNav = menuNavList.slice(startIndex, menuNavList.length)
menuList.value = showNav

@ -36,7 +36,7 @@ const routes_404 = [
const routes = [...systemRouter, ...whiteListRouters, ...routes_404]
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
history: createWebHistory(),
routes
})
@ -45,7 +45,6 @@ const router = createRouter({
// 判断是否已加载过动态/静态路由
const isGetRouter = ref(false)
// 白名单校验
const exportWhiteListFromRouter = (router) => {
const res = []
@ -53,7 +52,6 @@ const exportWhiteListFromRouter = (router) => {
return res
}
const whiteList = exportWhiteListFromRouter(whiteListRouters)
router.beforeEach(async (to, from, next) => {
NProgress.start()
const store = globalStore()
@ -70,7 +68,6 @@ router.beforeEach(async (to, from, next) => {
// NProgress.done()
return false
}
if (!isGetRouter.value) {
// 初始化菜单加载,代码位置不能变动
const menuStore = useMenuStore()
@ -102,6 +99,14 @@ router.beforeEach(async (to, from, next) => {
if (token) {
// 有token的时候才保存登录之前要访问的页面
tool.data.set('LAST_VIEWS_PATH', to.fullPath)
// 验证menu或则用户信息是否存在不存在那么就是被删除或者退出或者清理缓存了
if (!tool.data.get('MENU') || !tool.data.get('USER_INFO')) {
tool.data.remove('TOKEN')
next({
path: '/login'
})
return false
}
}
}
if (!token) {

@ -40,7 +40,7 @@ export const globalStore = defineStore('global', () => {
// 多标签栏
const layoutTagsOpen = ref(getCacheConfig('SNOWY_LAYOUT_TAGS_OPEN'))
// 是否展示面包屑
const breadcrumbOpen = ref(getCacheConfig('SNOWY_BREADCRUMD_OPEN'))
const breadcrumbOpen = ref(getCacheConfig('SNOWY_BREADCRUMB_OPEN'))
// 是否开启固定宽度(顶栏菜单)
const fixedWidth = ref(getCacheConfig('SNOWY_FIXEDWIDTH_OPEN'))
// 顶栏是否应用主题色

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

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

@ -0,0 +1,51 @@
import config from '@/config'
// 业务自己新加了模块,当然只限制于微服务情况下,单体不用管
const bizCustomization = [
{
label: '/custom/',
value: '/custom/'
}
]
// 微服务环境下如果拆分为多个代码模块那他的url是网关转发这里就要配置
const PREFIX = [
{
label: '/mobile/',
value: '/api/webapp'
},
{
label: '/sys/',
value: '/api/webapp'
},
{
label: '/auth/',
value: '/api/webapp'
},
{
label: '/client/',
value: '/api/webapp'
},
{
label: '/dev/',
value: '/api/webapp'
},
{
label: '/gen/',
value: '/api/webapp'
},
{
label: '/biz/',
value: '/api/bizapp'
}
]
// 转换url
export const convertUrl = (url) => {
if (config.CLOUD_SERVER === false) {
return url
}
const apiArray = [...PREFIX, ...bizCustomization]
const prefixUrlArray = apiArray.filter((f) => url.indexOf(f.label) > -1)
if (prefixUrlArray && prefixUrlArray.length > 0) {
return prefixUrlArray[0].value + url
}
return url
}

@ -24,6 +24,6 @@ export default (error) => {
}
const errorName = errorMap[error.name] || '未知错误'
nextTick(() => {
console.error(errorName)
console.error(errorName + ' ' + error)
})
}

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

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

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

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

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

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

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

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

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

@ -19,6 +19,14 @@
<a-form-item ref="cronExpressionRef" label="表达式:" name="cronExpression">
<cron v-model:modelValue="formData.cronExpression" />
</a-form-item>
<a-form-item label="扩展参数:" name="extJson">
<a-textarea
v-model:value="formData.extJson"
placeholder="请输入定时扩展参数"
:auto-size="{ minRows: 2, maxRows: 5 }"
allow-clear
/>
</a-form-item>
<a-form-item label="排序:" name="sortCode">
<a-input-number class="xn-wd" v-model:value="formData.sortCode" :max="100" />
</a-form-item>
@ -54,7 +62,18 @@
sortCode: 99
}
if (record) {
formData.value = Object.assign({}, record)
submitLoading.value = true
const param = {
id: record.id
}
jobApi
.jobDetail(param)
.then((data) => {
formData.value = Object.assign({}, data)
})
.finally(() => {
submitLoading.value = false
})
}
//
jobApi.jobGetActionClass().then((data) => {

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

@ -34,7 +34,13 @@
<template #operator class="table-operator">
<a-space>
<a-button type="primary" @click="formRef.onOpen()"> </a-button>
<xn-batch-delete :selectedRowKeys="selectedRowKeys" @batchDelete="deleteBatchEmail" />
<xn-batch-button
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchEmail"
/>
</a-space>
</template>
<template #bodyCell="{ column, record }">

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

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

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

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

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

@ -43,7 +43,7 @@
<span v-else></span>
</template>
<template v-if="column.dataIndex === 'whetherTable'">
<a-checkbox v-model:checked="record.whetherTable" @change="whetherTableChange(record)"/>
<a-checkbox v-model:checked="record.whetherTable" @change="whetherTableChange(record)" />
</template>
<template v-if="column.dataIndex === 'whetherRetract'">
<a-checkbox v-model:checked="record.whetherRetract" :disabled="!record.whetherTable" />

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

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

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

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

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

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

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

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

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

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

@ -26,5 +26,5 @@ public interface CommonTimerTaskRunner {
* @author xuyuxiang
* @date 2022/8/15 16:09
**/
void action();
void action(String extJson);
}

@ -61,9 +61,9 @@ public class CommonNetWorkInfoUtil {
input = new BufferedReader(new InputStreamReader(pro.getInputStream()));
long[] result2 = readInLine(input, isWindows);
String upSpeed = FileUtil.readableFileSize(Convert.toLong(NumberUtil
.div(NumberUtil.sub(result2[0], result1[0]), SLEEP_SECONDS)));
String downSpeed = FileUtil.readableFileSize(Convert.toLong(NumberUtil
.div(NumberUtil.sub(result2[1], result1[1]), SLEEP_SECONDS)));
String downSpeed = FileUtil.readableFileSize(Convert.toLong(NumberUtil
.div(NumberUtil.sub(result2[0], result1[0]), SLEEP_SECONDS)));
result.put("UP", upSpeed + (upSpeed.endsWith("B")?"/S":"B/S"));
result.put("DOWN", downSpeed + (downSpeed.endsWith("B")?"/S":"B/S"));
} catch (Exception e) {

@ -12,6 +12,10 @@
*/
package vip.xiaonuo.sys.api;
import cn.hutool.core.lang.tree.Tree;
import java.util.List;
/**
* API
*
@ -27,4 +31,12 @@ public interface SysMenuApi {
* @date 2022/11/1 13:48
**/
String addForGenMenu(String parentId, String busName, String module, String title, String path);
/**
*
*
* @author yubaoshan
* @date 2024/9/6 01:24
**/
List<Tree<String>> menuTreeSelector(String module);
}

@ -0,0 +1,33 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* 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(), () -> {
try {
// 运行定时任务
((CommonTimerTaskRunner) SpringUtil.getBean(Class.forName(devJob.getActionClass()))).action();
((CommonTimerTaskRunner) SpringUtil.getBean(Class.forName(devJob.getActionClass()))).action(devJob.getExtJson());
} catch (ClassNotFoundException e) {
throw new CommonException("定时任务找不到对应的类,名称为:{}", devJob.getActionClass());
}

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

@ -70,7 +70,7 @@ public class DevEmailAliyunUtil {
}
try {
client = new Client(new Config().setRegionId(regionId).setAccessKeyId(accessKeyId).setAccessKeySecret(accessKeySecret));
client = new Client(new Config().setRegionId(regionId).setEndpoint("dm.aliyuncs.com").setAccessKeyId(accessKeyId).setAccessKeySecret(accessKeySecret));
} catch (Exception e) {
throw new CommonException(e.getMessage());
}

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

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

@ -17,6 +17,7 @@ import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@ -25,6 +26,7 @@ import org.springframework.transaction.annotation.Transactional;
import vip.xiaonuo.common.enums.CommonSortOrderEnum;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.page.CommonPageRequest;
import vip.xiaonuo.dev.api.DevConfigApi;
import vip.xiaonuo.dev.modular.sms.entity.DevSms;
import vip.xiaonuo.dev.modular.sms.enums.DevSmsEngineTypeEnum;
import vip.xiaonuo.dev.modular.sms.mapper.DevSmsMapper;

@ -16,6 +16,7 @@ import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.dromara.sms4j.api.SmsBlend;
@ -106,7 +107,8 @@ public class DevSmsXiaonuoUtil {
if(smsResponse.isSuccess()) {
return JSONUtil.toJsonStr(smsResponse.getData());
} else {
throw new CommonException("短信发送失败");
JSONObject responseData = JSONUtil.parseObj(smsResponse.getData());
throw new CommonException(responseData.getStr("resInfo"));
}
} catch (Exception e) {
throw new CommonException(e.getMessage());

@ -12,6 +12,7 @@
*/
package vip.xiaonuo.gen.modular.basic.controller;
import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
@ -29,10 +30,7 @@ import vip.xiaonuo.common.annotation.CommonLog;
import vip.xiaonuo.common.pojo.CommonResult;
import vip.xiaonuo.gen.modular.basic.entity.GenBasic;
import vip.xiaonuo.gen.modular.basic.param.*;
import vip.xiaonuo.gen.modular.basic.result.GenBasicMobileModuleSelectorResult;
import vip.xiaonuo.gen.modular.basic.result.GenBasicPreviewResult;
import vip.xiaonuo.gen.modular.basic.result.GenBasicTableColumnResult;
import vip.xiaonuo.gen.modular.basic.result.GenBasicTableResult;
import vip.xiaonuo.gen.modular.basic.result.*;
import vip.xiaonuo.gen.modular.basic.service.GenBasicService;
import java.io.IOException;
@ -192,5 +190,29 @@ public class GenBasicController {
public CommonResult<List<GenBasicMobileModuleSelectorResult>> mobileModuleSelector() {
return CommonResult.data(genBasicService.mobileModuleSelector());
}
/**
*
*
* @author yubaoshan
* @date 2024/9/6 01:24
*/
@Operation(summary = "获取所有模块")
@GetMapping("/gen/basic/moduleSelector")
public CommonResult<List<GenBasicModuleSelectorResult>> moduleSelector() {
return CommonResult.data(genBasicService.moduleSelector());
}
/**
*
*
* @author yubaoshan
* @date 2024/9/6 01:24
**/
@Operation(summary = "代码生成获取所有菜单树包括未授权的")
@GetMapping("/gen/basic/menuTreeSelector")
public CommonResult<List<Tree<String>>> menuTreeSelector(@Valid GenBasicSelectorMenuParam genBasicSelectorMenuParam) {
return CommonResult.data(genBasicService.menuTreeSelector(genBasicSelectorMenuParam));
}
}

@ -0,0 +1,34 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* 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;
import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import jakarta.servlet.http.HttpServletResponse;
import vip.xiaonuo.gen.modular.basic.entity.GenBasic;
import vip.xiaonuo.gen.modular.basic.param.*;
import vip.xiaonuo.gen.modular.basic.result.GenBasicMobileModuleSelectorResult;
import vip.xiaonuo.gen.modular.basic.result.GenBasicPreviewResult;
import vip.xiaonuo.gen.modular.basic.result.GenBasicTableColumnResult;
import vip.xiaonuo.gen.modular.basic.result.GenBasicTableResult;
import vip.xiaonuo.gen.modular.basic.result.*;
import java.io.IOException;
import java.util.List;
@ -128,4 +126,20 @@ public interface GenBasicService extends IService<GenBasic> {
* @date 2023/7/15 22:28
**/
List<GenBasicMobileModuleSelectorResult> mobileModuleSelector();
/**
*
*
* @author yubaoshan
* @date 2024/9/6 01:24
**/
List<GenBasicModuleSelectorResult> moduleSelector();
/**
*
*
* @author yubaoshan
* @date 2024/9/6 01:24
**/
List<Tree<String>> menuTreeSelector(GenBasicSelectorMenuParam genBasicSelectorMenuParam);
}

@ -18,6 +18,7 @@ import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
@ -51,10 +52,7 @@ import vip.xiaonuo.gen.modular.basic.enums.GenEffectTypeEnum;
import vip.xiaonuo.gen.modular.basic.enums.GenYesNoEnum;
import vip.xiaonuo.gen.modular.basic.mapper.GenBasicMapper;
import vip.xiaonuo.gen.modular.basic.param.*;
import vip.xiaonuo.gen.modular.basic.result.GenBasicMobileModuleSelectorResult;
import vip.xiaonuo.gen.modular.basic.result.GenBasicPreviewResult;
import vip.xiaonuo.gen.modular.basic.result.GenBasicTableColumnResult;
import vip.xiaonuo.gen.modular.basic.result.GenBasicTableResult;
import vip.xiaonuo.gen.modular.basic.result.*;
import vip.xiaonuo.gen.modular.basic.service.GenBasicService;
import vip.xiaonuo.gen.modular.config.entity.GenConfig;
import vip.xiaonuo.gen.modular.config.param.GenConfigAddParam;
@ -62,6 +60,7 @@ import vip.xiaonuo.gen.modular.config.service.GenConfigService;
import vip.xiaonuo.mobile.api.MobileModuleApi;
import vip.xiaonuo.sys.api.SysButtonApi;
import vip.xiaonuo.sys.api.SysMenuApi;
import vip.xiaonuo.sys.api.SysModuleApi;
import vip.xiaonuo.sys.api.SysRoleApi;
import java.io.File;
@ -148,6 +147,9 @@ public class GenBasicServiceImpl extends ServiceImpl<GenBasicMapper, GenBasic> i
@Resource
private SysMenuApi sysMenuApi;
@Resource
private SysModuleApi sysModuleApi;
@Resource
private SysButtonApi sysButtonApi;
@ -597,7 +599,20 @@ public class GenBasicServiceImpl extends ServiceImpl<GenBasicMapper, GenBasic> i
@Override
public List<GenBasicMobileModuleSelectorResult> mobileModuleSelector() {
return mobileModuleApi.mobileModuleSelector().stream()
.map(jsonObject -> JSONUtil.toBean(jsonObject, GenBasicMobileModuleSelectorResult.class)).collect(Collectors.toList());
.map(jsonObject -> JSONUtil.toBean(jsonObject, GenBasicMobileModuleSelectorResult.class))
.collect(Collectors.toList());
}
@Override
public List<GenBasicModuleSelectorResult> moduleSelector() {
return sysModuleApi.moduleSelector().stream()
.map(jsonObject -> JSONUtil.toBean(jsonObject, GenBasicModuleSelectorResult.class))
.collect(Collectors.toList());
}
@Override
public List<Tree<String>> menuTreeSelector(GenBasicSelectorMenuParam genBasicSelectorMenuParam) {
return sysMenuApi.menuTreeSelector(genBasicSelectorMenuParam.getModule());
}
/**

@ -96,10 +96,12 @@
<template #icon><plus-outlined /></template>
新增
</a-button>
<xn-batch-delete
<xn-batch-button
v-if="hasPerm('${classNameFirstLower}BatchDelete')"
buttonName="批量删除"
icon="DeleteOutlined"
:selectedRowKeys="selectedRowKeys"
@batchDelete="deleteBatch${className}"
@batchCallBack="deleteBatch${className}"
/>
</a-space>
</template>

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

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

@ -12,11 +12,15 @@
*/
package vip.xiaonuo.sys.modular.resource.provider;
import cn.hutool.core.lang.tree.Tree;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import vip.xiaonuo.sys.api.SysMenuApi;
import vip.xiaonuo.sys.modular.resource.param.menu.SysMenuSelectorMenuParam;
import vip.xiaonuo.sys.modular.resource.service.SysMenuService;
import java.util.List;
/**
* API
*
@ -33,4 +37,11 @@ public class SysMenuApiProvider implements SysMenuApi {
public String addForGenMenu(String parentId, String busName, String module, String title, String path) {
return sysMenuService.addForGenMenu(parentId, busName, title, module, path);
}
@Override
public List<Tree<String>> menuTreeSelector(String module) {
SysMenuSelectorMenuParam param = new SysMenuSelectorMenuParam();
param.setModule(module);
return sysMenuService.menuTreeSelector(param);
}
}

@ -0,0 +1,38 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* 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;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import vip.xiaonuo.sys.modular.resource.entity.SysModule;
@ -62,6 +63,14 @@ public interface SysModuleService extends IService<SysModule> {
*/
void delete(List<SysModuleIdParam> sysModuleIdParamList);
/**
*
*
* @author yubaoshan
* @date 2024/9/6 01:24
*/
List<JSONObject> moduleSelector();
/**
*
*

@ -18,6 +18,7 @@ import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@ -150,6 +151,16 @@ public class SysModuleServiceImpl extends ServiceImpl<SysModuleMapper, SysModule
}
}
@Override
public List<JSONObject> moduleSelector() {
LambdaQueryWrapper<SysModule> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.select(SysModule::getId, SysModule::getTitle);
lambdaQueryWrapper.eq(SysModule::getCategory, SysResourceCategoryEnum.MODULE.getValue());
return this.list(lambdaQueryWrapper).stream()
.map(item -> JSONUtil.createObj().set("id", item.getId()).set("name", item.getTitle()))
.collect(Collectors.toList());
}
@Override
public SysModule detail(SysModuleIdParam sysModuleIdParam) {
return this.queryEntity(sysModuleIdParam.getId());

@ -697,19 +697,19 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
if (sysMenu.getCategory().equals(SysResourceCategoryEnum.MENU.getValue())) {
if (!sysMenu.getMenuType().equals(SysResourceMenuTypeEnum.CATALOG.getValue())) {
metaJsonObject.set("type", sysMenu.getMenuType().toLowerCase());
// 如果设置了不可见那么设置为false为了兼容已有所以只是false的为不显示
if (ObjectUtil.isNotEmpty(sysMenu.getVisible()) && sysMenu.getVisible().equals("FALSE")) {
metaJsonObject.set("hidden", true);
}
}
if (sysMenu.getId().equals(sysMenus.orElse(null).getId())) {
// 如果是首页则设置affix
metaJsonObject.set("affix", true);
}
}
// 如果设置了不可见那么设置为false为了兼容已有所以只是false的为不显示
if (ObjectUtil.isNotEmpty(sysMenu.getVisible()) && sysMenu.getVisible().equals("FALSE")) {
metaJsonObject.set("hidden", true);
}
menuJsonObject.set("meta", metaJsonObject);
return menuJsonObject;
}).collect(Collectors.toList());
}).toList();
// 执行构造树
List<TreeNode<String>> treeNodeList = resultJsonObjectList.stream().map(jsonObject ->

@ -95,7 +95,7 @@ spring.datasource.dynamic.druid.break-after-acquire-failure=false
spring.jackson.time-zone=GMT+8
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.locale=zh_CN
spring.jackson.serialization.write-dates-as-timestamps=true
spring.jackson.serialization.write-dates-as-timestamps=false
#########################################
# redis configuration
#########################################

Loading…
Cancel
Save