!64 版本升级
* Merge branch 'dev' of gitee.com:JavaLionLi/plus-ui into ts * 升级依赖 * !61 fix: 删除重复环境变量ElUploadInstance * fix: 删除重复环境变量ElUploadInstance
This commit is contained in:
23
.eslintrc.js
23
.eslintrc.js
@ -1,28 +1,35 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
env: {
|
env: {
|
||||||
browser: true,
|
browser: true,
|
||||||
es2021: true,
|
node: true,
|
||||||
node: true
|
es6: true
|
||||||
},
|
},
|
||||||
parser: 'vue-eslint-parser',
|
parser: 'vue-eslint-parser',
|
||||||
extends: [
|
extends: [
|
||||||
'eslint:recommended',
|
'plugin:vue/vue3-recommended',
|
||||||
'plugin:vue/vue3-essential',
|
|
||||||
'plugin:@typescript-eslint/recommended',
|
|
||||||
'./.eslintrc-auto-import.json',
|
'./.eslintrc-auto-import.json',
|
||||||
'plugin:prettier/recommended'
|
'plugin:@typescript-eslint/recommended',
|
||||||
|
"prettier",
|
||||||
|
'plugin:prettier/recommended',
|
||||||
],
|
],
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
ecmaVersion: '2020',
|
ecmaVersion: '2020',
|
||||||
sourceType: 'module',
|
sourceType: 'module',
|
||||||
|
project: "./tsconfig.*?.json",
|
||||||
parser: '@typescript-eslint/parser'
|
parser: '@typescript-eslint/parser'
|
||||||
},
|
},
|
||||||
plugins: ['vue', '@typescript-eslint'],
|
plugins: ['vue', '@typescript-eslint', 'import', 'promise', 'node', 'prettier'],
|
||||||
rules: {
|
rules: {
|
||||||
'vue/multi-word-component-names': 'off',
|
|
||||||
'@typescript-eslint/no-empty-function': 'off',
|
'@typescript-eslint/no-empty-function': 'off',
|
||||||
'@typescript-eslint/no-explicit-any': 'off',
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
|
|
||||||
|
// vue
|
||||||
|
'vue/multi-word-component-names': 'off',
|
||||||
|
'vue/valid-define-props': 'off',
|
||||||
'vue/no-v-model-argument': 'off',
|
'vue/no-v-model-argument': 'off',
|
||||||
|
'prefer-rest-params': 'off',
|
||||||
|
// prettier
|
||||||
|
'prettier/prettier': 'error',
|
||||||
'@typescript-eslint/ban-types': [
|
'@typescript-eslint/ban-types': [
|
||||||
'error',
|
'error',
|
||||||
{
|
{
|
||||||
|
|||||||
20
.prettierrc
Normal file
20
.prettierrc
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"printWidth": 150,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"useTabs": false,
|
||||||
|
"semi": true,
|
||||||
|
"singleQuote": true,
|
||||||
|
"quoteProps": "as-needed",
|
||||||
|
"jsxSingleQuote": false,
|
||||||
|
"bracketSameLine": false,
|
||||||
|
"trailingComma": "none",
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"embeddedLanguageFormatting": "auto",
|
||||||
|
"arrowParens": "always",
|
||||||
|
"requirePragma": false,
|
||||||
|
"insertPragma": false,
|
||||||
|
"proseWrap": "preserve",
|
||||||
|
"htmlWhitespaceSensitivity": "css",
|
||||||
|
"vueIndentScriptAndStyle": false,
|
||||||
|
"endOfLine": "auto"
|
||||||
|
}
|
||||||
63
package.json
63
package.json
@ -6,9 +6,10 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite serve --mode development",
|
"dev": "vite serve --mode development",
|
||||||
"build:prod": "vite build --mode production &&vue-tsc --noEmit",
|
"build:prod": "vite build --mode production",
|
||||||
|
"build:dev": "vite build --mode development",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"lint": "eslint src/**/*.{ts,js,vue} --fix",
|
"lint:eslint": "eslint --fix --ext .ts,.js,.vue ./src ",
|
||||||
"prepare": "husky install",
|
"prepare": "husky install",
|
||||||
"prettier": "prettier --write ."
|
"prettier": "prettier --write ."
|
||||||
},
|
},
|
||||||
@ -19,28 +20,28 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@element-plus/icons-vue": "2.1.0",
|
"@element-plus/icons-vue": "2.1.0",
|
||||||
"@vueup/vue-quill": "1.2.0",
|
"@vueup/vue-quill": "1.2.0",
|
||||||
"@vueuse/core": "9.5.0",
|
"@vueuse/core": "10.7.0",
|
||||||
"animate.css": "4.1.1",
|
"animate.css": "4.1.1",
|
||||||
"await-to-js": "^3.0.0",
|
"await-to-js": "^3.0.0",
|
||||||
"axios": "^1.3.4",
|
"axios": "^1.3.4",
|
||||||
|
"crypto-js": "^4.1.1",
|
||||||
"echarts": "5.4.0",
|
"echarts": "5.4.0",
|
||||||
"element-plus": "2.2.27",
|
"element-plus": "2.4.3",
|
||||||
"file-saver": "2.0.5",
|
"file-saver": "2.0.5",
|
||||||
"fuse.js": "6.6.2",
|
"fuse.js": "6.6.2",
|
||||||
"js-cookie": "3.0.1",
|
"js-cookie": "3.0.1",
|
||||||
"jsencrypt": "3.3.1",
|
"jsencrypt": "3.3.1",
|
||||||
"crypto-js": "^4.1.1",
|
|
||||||
"nprogress": "0.2.0",
|
"nprogress": "0.2.0",
|
||||||
"path-browserify": "1.0.1",
|
"path-browserify": "1.0.1",
|
||||||
"path-to-regexp": "6.2.0",
|
"path-to-regexp": "6.2.0",
|
||||||
"pinia": "2.0.22",
|
"pinia": "2.1.7",
|
||||||
"screenfull": "6.0.0",
|
"screenfull": "6.0.0",
|
||||||
"vform3-builds": "3.0.8",
|
"vform3-builds": "3.0.8",
|
||||||
"vue": "3.2.45",
|
"vue": "3.3.11",
|
||||||
"vue-cropper": "1.0.3",
|
"vue-cropper": "1.0.3",
|
||||||
"vue-i18n": "9.2.2",
|
"vue-i18n": "9.2.2",
|
||||||
"vue-router": "4.1.4",
|
"vue-router": "4.2.5",
|
||||||
"vue-types": "^5.0.3"
|
"vue-types": "5.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@iconify/json": "^2.2.40",
|
"@iconify/json": "^2.2.40",
|
||||||
@ -51,34 +52,38 @@
|
|||||||
"@types/node": "18.14.2",
|
"@types/node": "18.14.2",
|
||||||
"@types/nprogress": "0.2.0",
|
"@types/nprogress": "0.2.0",
|
||||||
"@types/path-browserify": "^1.0.0",
|
"@types/path-browserify": "^1.0.0",
|
||||||
"@typescript-eslint/eslint-plugin": "5.56.0",
|
"@typescript-eslint/eslint-plugin": "6.14.0",
|
||||||
"@typescript-eslint/parser": "5.56.0",
|
"@typescript-eslint/parser": "6.14.0",
|
||||||
"@unocss/preset-attributify": "^0.50.6",
|
"@unocss/preset-attributify": "^0.58.0",
|
||||||
"@unocss/preset-icons": "^0.50.6",
|
"@unocss/preset-icons": "^0.58.0",
|
||||||
"@unocss/preset-uno": "^0.50.6",
|
"@unocss/preset-uno": "^0.58.0",
|
||||||
"@vitejs/plugin-vue": "4.0.0",
|
|
||||||
"@vue/compiler-sfc": "3.2.45",
|
"@vue/compiler-sfc": "3.2.45",
|
||||||
|
"@vitejs/plugin-vue": "4.5.2",
|
||||||
"autoprefixer": "10.4.14",
|
"autoprefixer": "10.4.14",
|
||||||
"eslint": "8.36.0",
|
"eslint": "8.55.0",
|
||||||
"eslint-config-prettier": "8.8.0",
|
"eslint-config-prettier": "9.1.0",
|
||||||
"eslint-plugin-prettier": "4.2.1",
|
"eslint-define-config": "2.0.0",
|
||||||
"eslint-plugin-vue": "9.9.0",
|
"eslint-plugin-prettier": "5.0.1",
|
||||||
|
"eslint-plugin-promise": "6.1.1",
|
||||||
|
"eslint-plugin-node": "11.1.0",
|
||||||
|
"eslint-plugin-import": "2.29.0",
|
||||||
|
"eslint-plugin-vue": "9.19.2",
|
||||||
"fast-glob": "^3.2.11",
|
"fast-glob": "^3.2.11",
|
||||||
"husky": "7.0.4",
|
"husky": "7.0.4",
|
||||||
"postcss": "^8.4.21",
|
"postcss": "^8.4.21",
|
||||||
"prettier": "2.8.6",
|
"prettier": "3.1.1",
|
||||||
"sass": "1.56.1",
|
"sass": "1.56.1",
|
||||||
"typescript": "4.9.5",
|
"typescript": "5.2.2",
|
||||||
"unocss": "^0.50.6",
|
"unocss": "^0.58.0",
|
||||||
"unplugin-auto-import": "0.13.0",
|
"unplugin-auto-import": "0.17.2",
|
||||||
"unplugin-icons": "0.15.1",
|
"unplugin-icons": "0.18.1",
|
||||||
"unplugin-vue-components": "0.23.0",
|
"unplugin-vue-components": "0.26.0",
|
||||||
"vite": "4.3.1",
|
"unplugin-vue-setup-extend-plus": "0.4.9",
|
||||||
"vite-plugin-compression": "0.5.1",
|
"vite-plugin-compression": "0.5.1",
|
||||||
"vite-plugin-svg-icons": "2.0.1",
|
"vite-plugin-svg-icons": "2.0.1",
|
||||||
"unplugin-vue-setup-extend-plus": "0.4.9",
|
|
||||||
"vitest": "^0.29.7",
|
"vitest": "^0.29.7",
|
||||||
"vue-eslint-parser": "9.1.0",
|
"vue-eslint-parser": "9.3.2",
|
||||||
"vue-tsc": "0.35.0"
|
"vue-tsc": "0.35.0",
|
||||||
|
"vite": "5.0.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
src/App.vue
10
src/App.vue
@ -5,8 +5,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import useSettingsStore from '@/store/modules/settings'
|
import useSettingsStore from '@/store/modules/settings';
|
||||||
import { handleThemeStyle } from '@/utils/theme'
|
import { handleThemeStyle } from '@/utils/theme';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
@ -15,7 +15,7 @@ const size = computed(() => appStore.size as any);
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
// 初始化主题样式
|
// 初始化主题样式
|
||||||
handleThemeStyle(useSettingsStore().theme)
|
handleThemeStyle(useSettingsStore().theme);
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -28,7 +28,7 @@ export const getGenTable = (tableId: string | number): AxiosPromise<GenTableVO>
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 修改代码生成信息
|
// 修改代码生成信息
|
||||||
export const updateGenTable = (data: DbTableForm) => {
|
export const updateGenTable = (data: DbTableForm): AxiosPromise<GenTableVO> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/tool/gen',
|
url: '/tool/gen',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
@ -37,7 +37,7 @@ export const updateGenTable = (data: DbTableForm) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 导入表
|
// 导入表
|
||||||
export const importTable = (data: { tables: string; dataName: string }) => {
|
export const importTable = (data: { tables: string; dataName: string }): AxiosPromise<GenTableVO> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/tool/gen/importTable',
|
url: '/tool/gen/importTable',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
|
|||||||
@ -2,8 +2,7 @@
|
|||||||
<el-breadcrumb class="app-breadcrumb" separator="/">
|
<el-breadcrumb class="app-breadcrumb" separator="/">
|
||||||
<transition-group name="breadcrumb">
|
<transition-group name="breadcrumb">
|
||||||
<el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path">
|
<el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path">
|
||||||
<span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect">{{
|
<span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect">{{ item.meta?.title }}</span>
|
||||||
item.meta?.title }}</span>
|
|
||||||
<a v-else @click.prevent="handleLink(item)">{{ item.meta?.title }}</a>
|
<a v-else @click.prevent="handleLink(item)">{{ item.meta?.title }}</a>
|
||||||
</el-breadcrumb-item>
|
</el-breadcrumb-item>
|
||||||
</transition-group>
|
</transition-group>
|
||||||
@ -11,42 +10,42 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { RouteLocationMatched } from 'vue-router'
|
import { RouteLocationMatched } from 'vue-router';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const levelList = ref<RouteLocationMatched[]>([])
|
const levelList = ref<RouteLocationMatched[]>([]);
|
||||||
|
|
||||||
const getBreadcrumb = () => {
|
const getBreadcrumb = () => {
|
||||||
// only show routes with meta.title
|
// only show routes with meta.title
|
||||||
let matched = route.matched.filter(item => item.meta && item.meta.title);
|
let matched = route.matched.filter((item) => item.meta && item.meta.title);
|
||||||
const first = matched[0]
|
const first = matched[0];
|
||||||
// 判断是否为首页
|
// 判断是否为首页
|
||||||
if (!isDashboard(first)) {
|
if (!isDashboard(first)) {
|
||||||
matched = ([{ path: '/index', meta: { title: '首页' } }] as any).concat(matched)
|
matched = ([{ path: '/index', meta: { title: '首页' } }] as any).concat(matched);
|
||||||
}
|
}
|
||||||
levelList.value = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
|
levelList.value = matched.filter((item) => item.meta && item.meta.title && item.meta.breadcrumb !== false);
|
||||||
}
|
};
|
||||||
const isDashboard = (route: RouteLocationMatched) => {
|
const isDashboard = (route: RouteLocationMatched) => {
|
||||||
const name = route && route.name as string
|
const name = route && (route.name as string);
|
||||||
if (!name) {
|
if (!name) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
return name.trim() === 'Index'
|
return name.trim() === 'Index';
|
||||||
}
|
};
|
||||||
const handleLink = (item: RouteLocationMatched) => {
|
const handleLink = (item: RouteLocationMatched) => {
|
||||||
const { redirect, path } = item
|
const { redirect, path } = item;
|
||||||
redirect ? router.push(redirect as string) : router.push(path)
|
redirect ? router.push(redirect as string) : router.push(path);
|
||||||
}
|
};
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
// if you go to the redirect page, do not update the breadcrumbs
|
// if you go to the redirect page, do not update the breadcrumbs
|
||||||
if (route.path.startsWith('/redirect/')) return
|
if (route.path.startsWith('/redirect/')) return;
|
||||||
getBreadcrumb()
|
getBreadcrumb();
|
||||||
})
|
});
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getBreadcrumb();
|
getBreadcrumb();
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@ -1,53 +1,50 @@
|
|||||||
<!-- 代码构建 -->
|
|
||||||
<script setup lang="ts">
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
showBtn: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
formJson: {
|
|
||||||
type: Object,
|
|
||||||
default: undefined
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
||||||
const buildRef = ref();
|
|
||||||
const emits = defineEmits(['reJson', 'saveDesign']);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//获取表单json
|
|
||||||
const getJson = () => {
|
|
||||||
const formJson = JSON.stringify(buildRef.value.getFormJson())
|
|
||||||
const fieldJson = JSON.stringify(buildRef.value.getFieldWidgets())
|
|
||||||
let data = {
|
|
||||||
formJson, fieldJson
|
|
||||||
}
|
|
||||||
emits("saveDesign", data)
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
if (props.formJson) {
|
|
||||||
buildRef.value.setFormJson(props.formJson)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<!-- 代码构建 -->
|
||||||
<div>
|
<div>
|
||||||
<v-form-designer
|
<v-form-designer
|
||||||
class="build"
|
|
||||||
ref="buildRef"
|
ref="buildRef"
|
||||||
|
class="build"
|
||||||
:designer-config="{ importJsonButton: true, exportJsonButton: true, exportCodeButton: true, generateSFCButton: true, formTemplates: true }"
|
:designer-config="{ importJsonButton: true, exportJsonButton: true, exportCodeButton: true, generateSFCButton: true, formTemplates: true }"
|
||||||
>
|
>
|
||||||
<template #customToolButtons v-if="showBtn">
|
<template v-if="showBtn" #customToolButtons>
|
||||||
<el-button link type="primary" icon="Select" @click="getJson">保存</el-button>
|
<el-button link type="primary" icon="Select" @click="getJson">保存</el-button>
|
||||||
</template>
|
</template>
|
||||||
</v-form-designer>
|
</v-form-designer>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
interface Props {
|
||||||
|
showBtn: boolean;
|
||||||
|
formJson: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
showBtn: true,
|
||||||
|
formJson: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
const buildRef = ref();
|
||||||
|
const emits = defineEmits(['reJson', 'saveDesign']);
|
||||||
|
|
||||||
|
//获取表单json
|
||||||
|
const getJson = () => {
|
||||||
|
const formJson = JSON.stringify(buildRef.value.getFormJson());
|
||||||
|
const fieldJson = JSON.stringify(buildRef.value.getFieldWidgets());
|
||||||
|
let data = {
|
||||||
|
formJson,
|
||||||
|
fieldJson
|
||||||
|
};
|
||||||
|
emits('saveDesign', data);
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (props.formJson) {
|
||||||
|
buildRef.value.setFormJson(props.formJson);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.build {
|
.build {
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
|
|||||||
@ -1,26 +1,28 @@
|
|||||||
|
<template>
|
||||||
|
<div class="">
|
||||||
|
<v-form-render ref="vFormRef" :form-json="formJson" :form-data="formData" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<!-- 动态表单渲染 -->
|
<!-- 动态表单渲染 -->
|
||||||
<script setup name="Render">
|
<script setup name="Render" lang="ts">
|
||||||
|
interface Props {
|
||||||
|
formJson: string | object;
|
||||||
|
formData: string | object;
|
||||||
|
isView: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
const props = defineProps({
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
formJson: {
|
formJson: '',
|
||||||
type: [String, Object],
|
formData: '',
|
||||||
default: ""
|
isView: false
|
||||||
},
|
});
|
||||||
formData: {
|
|
||||||
type: [String, Object],
|
|
||||||
default: ""
|
|
||||||
},
|
|
||||||
isView: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const vFormRef = ref(null)
|
const vFormRef = ref(null);
|
||||||
// 获取表单数据-异步
|
// 获取表单数据-异步
|
||||||
const getFormData = () => {
|
const getFormData = () => {
|
||||||
return vFormRef.value.getFormData()
|
return vFormRef.value.getFormData();
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置表单内容
|
* 设置表单内容
|
||||||
@ -28,35 +30,28 @@ const getFormData = () => {
|
|||||||
* formConfig:{ formTemplate:表单模板,formData:表单数据,hiddenField:需要隐藏的字段字符串集合,disabledField:需要禁用的自读字符串集合}
|
* formConfig:{ formTemplate:表单模板,formData:表单数据,hiddenField:需要隐藏的字段字符串集合,disabledField:需要禁用的自读字符串集合}
|
||||||
*/
|
*/
|
||||||
const initForm = (formConf) => {
|
const initForm = (formConf) => {
|
||||||
const { formTemplate, formData, hiddenField, disabledField } = toRaw(formConf)
|
const { formTemplate, formData, hiddenField, disabledField } = toRaw(formConf);
|
||||||
if (formTemplate) {
|
if (formTemplate) {
|
||||||
vFormRef.value.setFormJson(formTemplate)
|
vFormRef.value.setFormJson(formTemplate);
|
||||||
if (formData) {
|
if (formData) {
|
||||||
vFormRef.value.setFormData(formData)
|
vFormRef.value.setFormData(formData);
|
||||||
}
|
}
|
||||||
if (disabledField && disabledField.length > 0) {
|
if (disabledField && disabledField.length > 0) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
vFormRef.value.disableWidgets(disabledField)
|
vFormRef.value.disableWidgets(disabledField);
|
||||||
}, 200)
|
}, 200);
|
||||||
}
|
}
|
||||||
if (hiddenField && hiddenField.length > 0) {
|
if (hiddenField && hiddenField.length > 0) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
vFormRef.value.hideWidgets(hiddenField)
|
vFormRef.value.hideWidgets(hiddenField);
|
||||||
}, 200)
|
}, 200);
|
||||||
}
|
}
|
||||||
if (props.isView) {
|
if (props.isView) {
|
||||||
console.log(props.isView)
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
vFormRef.value.disableForm()
|
vFormRef.value.disableForm();
|
||||||
}, 100)
|
}, 100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
defineExpose({ getFormData, initForm })
|
defineExpose({ getFormData, initForm });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="">
|
|
||||||
<v-form-render ref="vFormRef" :form-json="formJson" :form-data="formData" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|||||||
@ -8,13 +8,13 @@
|
|||||||
</span>
|
</span>
|
||||||
<el-tag
|
<el-tag
|
||||||
v-else
|
v-else
|
||||||
:disable-transitions="true"
|
|
||||||
:key="item.value + ''"
|
:key="item.value + ''"
|
||||||
|
:disable-transitions="true"
|
||||||
:index="index"
|
:index="index"
|
||||||
:type="(item.elTagType === 'primary' || item.elTagType === 'default')? '' : item.elTagType"
|
:type="(item.elTagType === 'primary' || item.elTagType === 'default')? '' : item.elTagType"
|
||||||
:class="item.elTagClass"
|
:class="item.elTagClass"
|
||||||
>
|
>
|
||||||
{{ item.label + " " }}
|
{{ item.label + ' ' }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
@ -25,57 +25,53 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { propTypes } from '@/utils/propTypes';
|
interface Props {
|
||||||
|
options: Array<DictDataOption>;
|
||||||
|
value: number | string | Array<number | string>;
|
||||||
const props = defineProps({
|
showValue: boolean;
|
||||||
// 数据
|
separator: string;
|
||||||
options: {
|
}
|
||||||
type: Array as PropType<DictDataOption[]>,
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
default: null,
|
showValue: true,
|
||||||
},
|
separator: ','
|
||||||
// 当前的值
|
|
||||||
value: [Number, String, Array] as PropType<number | string | Array<number | string>>,
|
|
||||||
// 当未找到匹配的数据时,显示value
|
|
||||||
showValue: propTypes.bool.def(true),
|
|
||||||
separator: propTypes.string.def(","),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const values = computed(() => {
|
const values = computed(() => {
|
||||||
if (props.value === '' || props.value === null || typeof props.value === "undefined") return []
|
if (props.value === '' || props.value === null || typeof props.value === 'undefined') return [];
|
||||||
return Array.isArray(props.value) ? props.value.map(item => '' + item) : String(props.value).split(props.separator);
|
return Array.isArray(props.value) ? props.value.map((item) => '' + item) : String(props.value).split(props.separator);
|
||||||
});
|
});
|
||||||
|
|
||||||
const unmatch = computed(() => {
|
const unmatch = computed(() => {
|
||||||
if (props.options?.length == 0 || props.value === '' || props.value === null || typeof props.value === "undefined") return false
|
if (props.options?.length == 0 || props.value === '' || props.value === null || typeof props.value === 'undefined') return false;
|
||||||
// 传入值为非数组
|
// 传入值为非数组
|
||||||
values.value.forEach(item => {
|
values.value.forEach((item) => {
|
||||||
if (!props.options.some(v => v.value === item)) {
|
if (!props.options.some((v) => v.value === item)) {
|
||||||
return true // 如果有未匹配项,将标志设置为true
|
return true; // 如果有未匹配项,将标志设置为true
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
return false // 返回标志的值
|
return false; // 返回标志的值
|
||||||
});
|
});
|
||||||
|
|
||||||
const unmatchArray = computed(() => {
|
const unmatchArray = computed(() => {
|
||||||
// 记录未匹配的项
|
// 记录未匹配的项
|
||||||
const itemUnmatchArray: Array<string | number> = [];
|
const itemUnmatchArray: Array<string | number> = [];
|
||||||
if (props.value !== '' && props.value !== null && typeof props.value !== "undefined") {
|
if (props.value !== '' && props.value !== null && typeof props.value !== 'undefined') {
|
||||||
values.value.forEach(item => {
|
values.value.forEach((item) => {
|
||||||
if (!props.options.some(v => v.value === item)) {
|
if (!props.options.some((v) => v.value === item)) {
|
||||||
itemUnmatchArray.push(item);
|
itemUnmatchArray.push(item);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
// 没有value不显示
|
// 没有value不显示
|
||||||
return handleArray(itemUnmatchArray);
|
return handleArray(itemUnmatchArray);
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleArray = (array: Array<string | number>) => {
|
const handleArray = (array: Array<string | number>) => {
|
||||||
if (array.length === 0) return "";
|
if (array.length === 0) return '';
|
||||||
return array.reduce((pre, cur) => {
|
return array.reduce((pre, cur) => {
|
||||||
return pre + " " + cur;
|
return pre + ' ' + cur;
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<el-upload
|
<el-upload
|
||||||
|
v-if="type === 'url'"
|
||||||
|
ref="uploadRef"
|
||||||
:action="upload.url"
|
:action="upload.url"
|
||||||
:before-upload="handleBeforeUpload"
|
:before-upload="handleBeforeUpload"
|
||||||
:on-success="handleUploadSuccess"
|
:on-success="handleUploadSuccess"
|
||||||
@ -9,18 +11,16 @@
|
|||||||
name="file"
|
name="file"
|
||||||
:show-file-list="false"
|
:show-file-list="false"
|
||||||
:headers="upload.headers"
|
:headers="upload.headers"
|
||||||
ref="uploadRef"
|
|
||||||
v-if="type === 'url'"
|
|
||||||
>
|
>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
<div class="editor">
|
<div class="editor">
|
||||||
<quill-editor
|
<quill-editor
|
||||||
ref="quillEditorRef"
|
ref="quillEditorRef"
|
||||||
v-model:content="content"
|
v-model:content="content"
|
||||||
contentType="html"
|
content-type="html"
|
||||||
@textChange="(e: any) => $emit('update:modelValue', content)"
|
|
||||||
:options="options"
|
:options="options"
|
||||||
:style="styles"
|
:style="styles"
|
||||||
|
@text-change="(e: any) => $emit('update:modelValue', content)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -30,7 +30,7 @@
|
|||||||
import { QuillEditor, Quill } from '@vueup/vue-quill';
|
import { QuillEditor, Quill } from '@vueup/vue-quill';
|
||||||
import '@vueup/vue-quill/dist/vue-quill.snow.css';
|
import '@vueup/vue-quill/dist/vue-quill.snow.css';
|
||||||
import { propTypes } from '@/utils/propTypes';
|
import { propTypes } from '@/utils/propTypes';
|
||||||
import { globalHeaders } from "@/utils/request";
|
import { globalHeaders } from '@/utils/request';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
/* 编辑器的内容 */
|
/* 编辑器的内容 */
|
||||||
@ -52,42 +52,42 @@ const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|||||||
const upload = reactive<UploadOption>({
|
const upload = reactive<UploadOption>({
|
||||||
headers: globalHeaders(),
|
headers: globalHeaders(),
|
||||||
url: import.meta.env.VITE_APP_BASE_API + '/resource/oss/upload'
|
url: import.meta.env.VITE_APP_BASE_API + '/resource/oss/upload'
|
||||||
})
|
});
|
||||||
const quillEditorRef = ref();
|
const quillEditorRef = ref();
|
||||||
|
|
||||||
const options = ref({
|
const options = ref({
|
||||||
theme: "snow",
|
theme: 'snow',
|
||||||
bounds: document.body,
|
bounds: document.body,
|
||||||
debug: "warn",
|
debug: 'warn',
|
||||||
modules: {
|
modules: {
|
||||||
// 工具栏配置
|
// 工具栏配置
|
||||||
toolbar: {
|
toolbar: {
|
||||||
container: [
|
container: [
|
||||||
["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线
|
['bold', 'italic', 'underline', 'strike'], // 加粗 斜体 下划线 删除线
|
||||||
["blockquote", "code-block"], // 引用 代码块
|
['blockquote', 'code-block'], // 引用 代码块
|
||||||
[{ list: "ordered" }, { list: "bullet" }], // 有序、无序列表
|
[{ list: 'ordered' }, { list: 'bullet' }], // 有序、无序列表
|
||||||
[{ indent: "-1" }, { indent: "+1" }], // 缩进
|
[{ indent: '-1' }, { indent: '+1' }], // 缩进
|
||||||
[{ size: ["small", false, "large", "huge"] }], // 字体大小
|
[{ size: ['small', false, 'large', 'huge'] }], // 字体大小
|
||||||
[{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
|
[{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
|
||||||
[{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
|
[{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
|
||||||
[{ align: [] }], // 对齐方式
|
[{ align: [] }], // 对齐方式
|
||||||
["clean"], // 清除文本格式
|
['clean'], // 清除文本格式
|
||||||
["link", "image", "video"] // 链接、图片、视频
|
['link', 'image', 'video'] // 链接、图片、视频
|
||||||
],
|
],
|
||||||
handlers: {
|
handlers: {
|
||||||
image: function (value: any) {
|
image: function (value: any) {
|
||||||
if (value) {
|
if (value) {
|
||||||
// 调用element图片上传
|
// 调用element图片上传
|
||||||
(document.querySelector(".editor-img-uploader>.el-upload") as HTMLDivElement)?.click();
|
(document.querySelector('.editor-img-uploader>.el-upload') as HTMLDivElement)?.click();
|
||||||
} else {
|
} else {
|
||||||
Quill.format("image", true);
|
Quill.format('image', true);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
placeholder: "请输入内容",
|
placeholder: '请输入内容',
|
||||||
readOnly: props.readOnly,
|
readOnly: props.readOnly
|
||||||
});
|
});
|
||||||
|
|
||||||
const styles = computed(() => {
|
const styles = computed(() => {
|
||||||
@ -99,14 +99,18 @@ const styles = computed(() => {
|
|||||||
style.height = `${props.height}px`;
|
style.height = `${props.height}px`;
|
||||||
}
|
}
|
||||||
return style;
|
return style;
|
||||||
})
|
});
|
||||||
|
|
||||||
const content = ref("");
|
const content = ref('');
|
||||||
watch(() => props.modelValue, (v) => {
|
watch(
|
||||||
if (v !== content.value) {
|
() => props.modelValue,
|
||||||
content.value = v === undefined ? "<p></p>" : v;
|
(v) => {
|
||||||
}
|
if (v !== content.value) {
|
||||||
}, { immediate: true });
|
content.value = v === undefined ? '<p></p>' : v;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
// 图片上传成功返回图片地址
|
// 图片上传成功返回图片地址
|
||||||
const handleUploadSuccess = (res: any) => {
|
const handleUploadSuccess = (res: any) => {
|
||||||
@ -117,7 +121,7 @@ const handleUploadSuccess = (res: any) => {
|
|||||||
// 获取光标位置
|
// 获取光标位置
|
||||||
let length = quill.selection.savedRange.index;
|
let length = quill.selection.savedRange.index;
|
||||||
// 插入图片,res为服务器返回的图片链接地址
|
// 插入图片,res为服务器返回的图片链接地址
|
||||||
quill.insertEmbed(length, "image", res.data.url);
|
quill.insertEmbed(length, 'image', res.data.url);
|
||||||
// 调整光标到最后
|
// 调整光标到最后
|
||||||
quill.setSelection(length + 1);
|
quill.setSelection(length + 1);
|
||||||
proxy?.$modal.closeLoading();
|
proxy?.$modal.closeLoading();
|
||||||
@ -125,11 +129,11 @@ const handleUploadSuccess = (res: any) => {
|
|||||||
proxy?.$modal.loading(res.msg);
|
proxy?.$modal.loading(res.msg);
|
||||||
proxy?.$modal.closeLoading();
|
proxy?.$modal.closeLoading();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// 图片上传前拦截
|
// 图片上传前拦截
|
||||||
const handleBeforeUpload = (file: any) => {
|
const handleBeforeUpload = (file: any) => {
|
||||||
const type = ["image/jpeg", "image/jpg", "image/png", "image/svg"];
|
const type = ['image/jpeg', 'image/jpg', 'image/png', 'image/svg'];
|
||||||
const isJPG = type.includes(file.type);
|
const isJPG = type.includes(file.type);
|
||||||
//检验文件格式
|
//检验文件格式
|
||||||
if (!isJPG) {
|
if (!isJPG) {
|
||||||
@ -146,13 +150,13 @@ const handleBeforeUpload = (file: any) => {
|
|||||||
}
|
}
|
||||||
proxy?.$modal.loading('正在上传文件,请稍候...');
|
proxy?.$modal.loading('正在上传文件,请稍候...');
|
||||||
return true;
|
return true;
|
||||||
}
|
};
|
||||||
|
|
||||||
// 图片失败拦截
|
// 图片失败拦截
|
||||||
const handleUploadError = (err: any) => {
|
const handleUploadError = (err: any) => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
proxy?.$modal.msgError('上传文件失败');
|
proxy?.$modal.msgError('上传文件失败');
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@ -167,71 +171,71 @@ const handleUploadError = (err: any) => {
|
|||||||
.quill-img {
|
.quill-img {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.ql-snow .ql-tooltip[data-mode="link"]::before {
|
.ql-snow .ql-tooltip[data-mode='link']::before {
|
||||||
content: "请输入链接地址:";
|
content: '请输入链接地址:';
|
||||||
}
|
}
|
||||||
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
|
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
|
||||||
border-right: 0;
|
border-right: 0;
|
||||||
content: "保存";
|
content: '保存';
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
}
|
}
|
||||||
.ql-snow .ql-tooltip[data-mode="video"]::before {
|
.ql-snow .ql-tooltip[data-mode='video']::before {
|
||||||
content: "请输入视频地址:";
|
content: '请输入视频地址:';
|
||||||
}
|
}
|
||||||
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
|
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
|
||||||
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
|
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
|
||||||
content: "14px";
|
content: '14px';
|
||||||
}
|
}
|
||||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
|
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='small']::before,
|
||||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
|
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='small']::before {
|
||||||
content: "10px";
|
content: '10px';
|
||||||
}
|
}
|
||||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
|
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='large']::before,
|
||||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
|
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='large']::before {
|
||||||
content: "18px";
|
content: '18px';
|
||||||
}
|
}
|
||||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
|
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='huge']::before,
|
||||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
|
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='huge']::before {
|
||||||
content: "32px";
|
content: '32px';
|
||||||
}
|
}
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-label::before,
|
.ql-snow .ql-picker.ql-header .ql-picker-label::before,
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
|
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
|
||||||
content: "文本";
|
content: '文本';
|
||||||
}
|
}
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
|
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='1']::before,
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
|
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='1']::before {
|
||||||
content: "标题1";
|
content: '标题1';
|
||||||
}
|
}
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
|
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='2']::before,
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
|
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='2']::before {
|
||||||
content: "标题2";
|
content: '标题2';
|
||||||
}
|
}
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
|
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='3']::before,
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
|
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='3']::before {
|
||||||
content: "标题3";
|
content: '标题3';
|
||||||
}
|
}
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
|
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='4']::before,
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
|
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='4']::before {
|
||||||
content: "标题4";
|
content: '标题4';
|
||||||
}
|
}
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
|
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='5']::before,
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
|
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='5']::before {
|
||||||
content: "标题5";
|
content: '标题5';
|
||||||
}
|
}
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
|
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='6']::before,
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
|
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='6']::before {
|
||||||
content: "标题6";
|
content: '标题6';
|
||||||
}
|
}
|
||||||
.ql-snow .ql-picker.ql-font .ql-picker-label::before,
|
.ql-snow .ql-picker.ql-font .ql-picker-label::before,
|
||||||
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
|
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
|
||||||
content: "标准字体";
|
content: '标准字体';
|
||||||
}
|
}
|
||||||
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
|
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value='serif']::before,
|
||||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
|
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value='serif']::before {
|
||||||
content: "衬线字体";
|
content: '衬线字体';
|
||||||
}
|
}
|
||||||
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
|
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value='monospace']::before,
|
||||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
|
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value='monospace']::before {
|
||||||
content: "等宽字体";
|
content: '等宽字体';
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="upload-file">
|
<div class="upload-file">
|
||||||
<el-upload
|
<el-upload
|
||||||
|
ref="fileUploadRef"
|
||||||
multiple
|
multiple
|
||||||
:action="uploadFileUrl"
|
:action="uploadFileUrl"
|
||||||
:before-upload="handleBeforeUpload"
|
:before-upload="handleBeforeUpload"
|
||||||
@ -12,30 +13,29 @@
|
|||||||
:show-file-list="false"
|
:show-file-list="false"
|
||||||
:headers="headers"
|
:headers="headers"
|
||||||
class="upload-file-uploader"
|
class="upload-file-uploader"
|
||||||
ref="fileUploadRef"
|
|
||||||
>
|
>
|
||||||
<!-- 上传按钮 -->
|
<!-- 上传按钮 -->
|
||||||
<el-button type="primary">选取文件</el-button>
|
<el-button type="primary">选取文件</el-button>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
<!-- 上传提示 -->
|
<!-- 上传提示 -->
|
||||||
<div class="el-upload__tip" v-if="showTip">
|
<div v-if="showTip" class="el-upload__tip">
|
||||||
请上传
|
请上传
|
||||||
<template v-if="fileSize">
|
<template v-if="fileSize">
|
||||||
大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
|
大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="fileType">
|
<template v-if="fileType">
|
||||||
格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b>
|
格式为 <b style="color: #f56c6c">{{ fileType.join('/') }}</b>
|
||||||
</template>
|
</template>
|
||||||
的文件
|
的文件
|
||||||
</div>
|
</div>
|
||||||
<!-- 文件列表 -->
|
<!-- 文件列表 -->
|
||||||
<transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
|
<transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
|
||||||
<li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList">
|
<li v-for="(file, index) in fileList" :key="file.uid" class="el-upload-list__item ele-upload-list__item-content">
|
||||||
<el-link :href="`${file.url}`" :underline="false" target="_blank">
|
<el-link :href="`${file.url}`" :underline="false" target="_blank">
|
||||||
<span class="el-icon-document"> {{ getFileName(file.name) }} </span>
|
<span class="el-icon-document"> {{ getFileName(file.name) }} </span>
|
||||||
</el-link>
|
</el-link>
|
||||||
<div class="ele-upload-list__item-content-action">
|
<div class="ele-upload-list__item-content-action">
|
||||||
<el-link :underline="false" @click="handleDelete(index)" type="danger">删除</el-link>
|
<el-link :underline="false" type="danger" @click="handleDelete(index)">删除</el-link>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</transition-group>
|
</transition-group>
|
||||||
@ -43,20 +43,20 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { listByIds, delOss } from "@/api/system/oss";
|
import { listByIds, delOss } from '@/api/system/oss';
|
||||||
import { propTypes } from '@/utils/propTypes';
|
import { propTypes } from '@/utils/propTypes';
|
||||||
import { globalHeaders } from "@/utils/request";
|
import { globalHeaders } from '@/utils/request';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: [String, Object, Array],
|
modelValue: [String, Object, Array],
|
||||||
// 数量限制
|
// 数量限制
|
||||||
limit: propTypes.number.def(5),
|
limit: propTypes.number.def(5),
|
||||||
// 大小限制(MB)
|
// 大小限制(MB)
|
||||||
fileSize: propTypes.number.def(5),
|
fileSize: propTypes.number.def(5),
|
||||||
// 文件类型, 例如['png', 'jpg', 'jpeg']
|
// 文件类型, 例如['png', 'jpg', 'jpeg']
|
||||||
fileType: propTypes.array.def(["doc", "xls", "ppt", "txt", "pdf"]),
|
fileType: propTypes.array.def(['doc', 'xls', 'ppt', 'txt', 'pdf']),
|
||||||
// 是否显示提示
|
// 是否显示提示
|
||||||
isShowTip: propTypes.bool.def(true),
|
isShowTip: propTypes.bool.def(true)
|
||||||
});
|
});
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
@ -65,153 +65,163 @@ const number = ref(0);
|
|||||||
const uploadList = ref<any[]>([]);
|
const uploadList = ref<any[]>([]);
|
||||||
|
|
||||||
const baseUrl = import.meta.env.VITE_APP_BASE_API;
|
const baseUrl = import.meta.env.VITE_APP_BASE_API;
|
||||||
const uploadFileUrl = ref(baseUrl + "/resource/oss/upload"); // 上传文件服务器地址
|
const uploadFileUrl = ref(baseUrl + '/resource/oss/upload'); // 上传文件服务器地址
|
||||||
const headers = ref(globalHeaders());
|
const headers = ref(globalHeaders());
|
||||||
|
|
||||||
const fileList = ref<any[]>([]);
|
const fileList = ref<any[]>([]);
|
||||||
const showTip = computed(
|
const showTip = computed(() => props.isShowTip && (props.fileType || props.fileSize));
|
||||||
() => props.isShowTip && (props.fileType || props.fileSize)
|
|
||||||
);
|
|
||||||
|
|
||||||
const fileUploadRef = ref<ElUploadInstance>();
|
const fileUploadRef = ref<ElUploadInstance>();
|
||||||
|
|
||||||
watch(() => props.modelValue, async val => {
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
async (val) => {
|
||||||
if (val) {
|
if (val) {
|
||||||
let temp = 1;
|
let temp = 1;
|
||||||
// 首先将值转为数组
|
// 首先将值转为数组
|
||||||
let list = [];
|
let list = [];
|
||||||
if (Array.isArray(val)) {
|
if (Array.isArray(val)) {
|
||||||
list = val;
|
list = val;
|
||||||
} else {
|
} else {
|
||||||
const res = await listByIds(val as string)
|
const res = await listByIds(val as string);
|
||||||
list = res.data.map((oss) => {
|
list = res.data.map((oss) => {
|
||||||
const data = { name: oss.originalName, url: oss.url, ossId: oss.ossId };
|
const data = {
|
||||||
return data;
|
name: oss.originalName,
|
||||||
});
|
url: oss.url,
|
||||||
}
|
ossId: oss.ossId
|
||||||
// 然后将数组转为对象数组
|
};
|
||||||
fileList.value = list.map(item => {
|
return data;
|
||||||
item = { name: item.name, url: item.url, ossId: item.ossId };
|
|
||||||
item.uid = item.uid || new Date().getTime() + temp++;
|
|
||||||
return item;
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
// 然后将数组转为对象数组
|
||||||
|
fileList.value = list.map((item) => {
|
||||||
|
item = { name: item.name, url: item.url, ossId: item.ossId };
|
||||||
|
item.uid = item.uid || new Date().getTime() + temp++;
|
||||||
|
return item;
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
fileList.value = [];
|
fileList.value = [];
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}, { deep: true, immediate: true });
|
},
|
||||||
|
{ deep: true, immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
// 上传前校检格式和大小
|
// 上传前校检格式和大小
|
||||||
const handleBeforeUpload = (file: any) => {
|
const handleBeforeUpload = (file: any) => {
|
||||||
// 校检文件类型
|
// 校检文件类型
|
||||||
if (props.fileType.length) {
|
if (props.fileType.length) {
|
||||||
const fileName = file.name.split('.');
|
const fileName = file.name.split('.');
|
||||||
const fileExt = fileName[fileName.length - 1];
|
const fileExt = fileName[fileName.length - 1];
|
||||||
const isTypeOk = props.fileType.indexOf(fileExt) >= 0;
|
const isTypeOk = props.fileType.indexOf(fileExt) >= 0;
|
||||||
if (!isTypeOk) {
|
if (!isTypeOk) {
|
||||||
proxy?.$modal.msgError(`文件格式不正确, 请上传${props.fileType.join("/")}格式文件!`);
|
proxy?.$modal.msgError(`文件格式不正确, 请上传${props.fileType.join('/')}格式文件!`);
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// 校检文件大小
|
}
|
||||||
if (props.fileSize) {
|
// 校检文件大小
|
||||||
const isLt = file.size / 1024 / 1024 < props.fileSize;
|
if (props.fileSize) {
|
||||||
if (!isLt) {
|
const isLt = file.size / 1024 / 1024 < props.fileSize;
|
||||||
proxy?.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
|
if (!isLt) {
|
||||||
return false;
|
proxy?.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
|
||||||
}
|
return false;
|
||||||
}
|
}
|
||||||
proxy?.$modal.loading("正在上传文件,请稍候...");
|
}
|
||||||
number.value++;
|
proxy?.$modal.loading('正在上传文件,请稍候...');
|
||||||
return true;
|
number.value++;
|
||||||
}
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
// 文件个数超出
|
// 文件个数超出
|
||||||
const handleExceed = () => {
|
const handleExceed = () => {
|
||||||
proxy?.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
|
proxy?.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
|
||||||
}
|
};
|
||||||
|
|
||||||
// 上传失败
|
// 上传失败
|
||||||
const handleUploadError = () => {
|
const handleUploadError = () => {
|
||||||
proxy?.$modal.msgError("上传文件失败");
|
proxy?.$modal.msgError('上传文件失败');
|
||||||
}
|
};
|
||||||
|
|
||||||
// 上传成功回调
|
// 上传成功回调
|
||||||
const handleUploadSuccess = (res: any, file: UploadFile) => {
|
const handleUploadSuccess = (res: any, file: UploadFile) => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
uploadList.value.push({ name: res.data.fileName, url: res.data.url, ossId: res.data.ossId });
|
uploadList.value.push({
|
||||||
uploadedSuccessfully();
|
name: res.data.fileName,
|
||||||
} else {
|
url: res.data.url,
|
||||||
number.value--;
|
ossId: res.data.ossId
|
||||||
proxy?.$modal.closeLoading();
|
});
|
||||||
proxy?.$modal.msgError(res.msg);
|
uploadedSuccessfully();
|
||||||
fileUploadRef.value?.handleRemove(file);
|
} else {
|
||||||
uploadedSuccessfully();
|
number.value--;
|
||||||
}
|
proxy?.$modal.closeLoading();
|
||||||
}
|
proxy?.$modal.msgError(res.msg);
|
||||||
|
fileUploadRef.value?.handleRemove(file);
|
||||||
|
uploadedSuccessfully();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 删除文件
|
// 删除文件
|
||||||
const handleDelete = (index: number) => {
|
const handleDelete = (index: number) => {
|
||||||
let ossId = fileList.value[index].ossId;
|
let ossId = fileList.value[index].ossId;
|
||||||
delOss(ossId);
|
delOss(ossId);
|
||||||
fileList.value.splice(index, 1);
|
fileList.value.splice(index, 1);
|
||||||
emit("update:modelValue", listToString(fileList.value));
|
emit('update:modelValue', listToString(fileList.value));
|
||||||
}
|
};
|
||||||
|
|
||||||
// 上传结束处理
|
// 上传结束处理
|
||||||
const uploadedSuccessfully = () => {
|
const uploadedSuccessfully = () => {
|
||||||
if (number.value > 0 && uploadList.value.length === number.value) {
|
if (number.value > 0 && uploadList.value.length === number.value) {
|
||||||
fileList.value = fileList.value.filter(f => f.url !== undefined).concat(uploadList.value);
|
fileList.value = fileList.value.filter((f) => f.url !== undefined).concat(uploadList.value);
|
||||||
uploadList.value = [];
|
uploadList.value = [];
|
||||||
number.value = 0;
|
number.value = 0;
|
||||||
emit("update:modelValue", listToString(fileList.value));
|
emit('update:modelValue', listToString(fileList.value));
|
||||||
proxy?.$modal.closeLoading();
|
proxy?.$modal.closeLoading();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// 获取文件名称
|
// 获取文件名称
|
||||||
const getFileName = (name: string) => {
|
const getFileName = (name: string) => {
|
||||||
// 如果是url那么取最后的名字 如果不是直接返回
|
// 如果是url那么取最后的名字 如果不是直接返回
|
||||||
if (name.lastIndexOf("/") > -1) {
|
if (name.lastIndexOf('/') > -1) {
|
||||||
return name.slice(name.lastIndexOf("/") + 1);
|
return name.slice(name.lastIndexOf('/') + 1);
|
||||||
} else {
|
} else {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// 对象转成指定字符串分隔
|
// 对象转成指定字符串分隔
|
||||||
const listToString = (list: any[], separator?: string) => {
|
const listToString = (list: any[], separator?: string) => {
|
||||||
let strs = "";
|
let strs = '';
|
||||||
separator = separator || ",";
|
separator = separator || ',';
|
||||||
list.forEach(item => {
|
list.forEach((item) => {
|
||||||
if (item.ossId) {
|
if (item.ossId) {
|
||||||
strs += item.ossId + separator;
|
strs += item.ossId + separator;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
return strs != "" ? strs.substring(0, strs.length - 1) : "";
|
return strs != '' ? strs.substring(0, strs.length - 1) : '';
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.upload-file-uploader {
|
.upload-file-uploader {
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.upload-file-list .el-upload-list__item {
|
.upload-file-list .el-upload-list__item {
|
||||||
border: 1px solid #e4e7ed;
|
border: 1px solid #e4e7ed;
|
||||||
line-height: 2;
|
line-height: 2;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.upload-file-list .ele-upload-list__item-content {
|
.upload-file-list .ele-upload-list__item-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ele-upload-list__item-content-action .el-link {
|
.ele-upload-list__item-content-action .el-link {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="padding: 0 15px;" @click="toggleClick">
|
<div style="padding: 0 15px" @click="toggleClick">
|
||||||
<svg :class="{ 'is-active': isActive }" class="hamburger" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="64" height="64">
|
<svg :class="{ 'is-active': isActive }" class="hamburger" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="64" height="64">
|
||||||
<path
|
<path
|
||||||
d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z"
|
d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z"
|
||||||
@ -13,12 +13,12 @@ import { propTypes } from '@/utils/propTypes';
|
|||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
isActive: propTypes.bool.def(false)
|
isActive: propTypes.bool.def(false)
|
||||||
})
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['toggleClick'])
|
const emit = defineEmits(['toggleClick']);
|
||||||
const toggleClick = () => {
|
const toggleClick = () => {
|
||||||
emit('toggleClick');
|
emit('toggleClick');
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :class="{ 'show': show }" class="header-search">
|
<div :class="{ show: show }" class="header-search">
|
||||||
<svg-icon class-name="search-icon" icon-class="search" @click.stop="click"/>
|
<svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
|
||||||
<el-select
|
<el-select
|
||||||
ref="headerSearchSelectRef"
|
ref="headerSearchSelectRef"
|
||||||
v-model="search"
|
v-model="search"
|
||||||
@ -12,23 +12,22 @@
|
|||||||
class="header-search-select"
|
class="header-search-select"
|
||||||
@change="change"
|
@change="change"
|
||||||
>
|
>
|
||||||
<el-option v-for="option in options" :key="option.item.path" :value="option.item"
|
<el-option v-for="option in options" :key="option.item.path" :value="option.item" :label="option.item.title.join(' > ')" />
|
||||||
:label="option.item.title.join(' > ')"/>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="HeaderSearch">
|
<script setup lang="ts" name="HeaderSearch">
|
||||||
import Fuse from 'fuse.js';
|
import Fuse from 'fuse.js';
|
||||||
import {getNormalPath} from '@/utils/ruoyi';
|
import { getNormalPath } from '@/utils/ruoyi';
|
||||||
import {isHttp} from '@/utils/validate';
|
import { isHttp } from '@/utils/validate';
|
||||||
import usePermissionStore from '@/store/modules/permission';
|
import usePermissionStore from '@/store/modules/permission';
|
||||||
import {RouteOption} from 'vue-router';
|
import { RouteRecordRaw } from 'vue-router';
|
||||||
|
|
||||||
type Router = Array<{
|
type Router = Array<{
|
||||||
path: string;
|
path: string;
|
||||||
title: string[];
|
title: string[];
|
||||||
}>
|
}>;
|
||||||
|
|
||||||
const search = ref('');
|
const search = ref('');
|
||||||
const options = ref<any>([]);
|
const options = ref<any>([]);
|
||||||
@ -40,36 +39,36 @@ const router = useRouter();
|
|||||||
const routes = computed(() => usePermissionStore().routes);
|
const routes = computed(() => usePermissionStore().routes);
|
||||||
|
|
||||||
const click = () => {
|
const click = () => {
|
||||||
show.value = !show.value
|
show.value = !show.value;
|
||||||
if (show.value) {
|
if (show.value) {
|
||||||
headerSearchSelectRef.value && headerSearchSelectRef.value.focus()
|
headerSearchSelectRef.value && headerSearchSelectRef.value.focus();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const close = () => {
|
const close = () => {
|
||||||
headerSearchSelectRef.value && headerSearchSelectRef.value.blur()
|
headerSearchSelectRef.value && headerSearchSelectRef.value.blur();
|
||||||
options.value = []
|
options.value = [];
|
||||||
show.value = false
|
show.value = false;
|
||||||
}
|
};
|
||||||
const change = (val: any) => {
|
const change = (val: any) => {
|
||||||
const path = val.path;
|
const path = val.path;
|
||||||
const query = val.query;
|
const query = val.query;
|
||||||
if (isHttp(path)) {
|
if (isHttp(path)) {
|
||||||
// http(s):// 路径新窗口打开
|
// http(s):// 路径新窗口打开
|
||||||
const pindex = path.indexOf("http");
|
const pindex = path.indexOf('http');
|
||||||
window.open(path.substr(pindex, path.length), "_blank");
|
window.open(path.substr(pindex, path.length), '_blank');
|
||||||
} else {
|
} else {
|
||||||
if (query) {
|
if (query) {
|
||||||
router.push({ path: path, query: JSON.parse(query) });
|
router.push({ path: path, query: JSON.parse(query) });
|
||||||
} else {
|
} else {
|
||||||
router.push(path)
|
router.push(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
search.value = ''
|
search.value = '';
|
||||||
options.value = []
|
options.value = [];
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
show.value = false
|
show.value = false;
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
const initFuse = (list: Router) => {
|
const initFuse = (list: Router) => {
|
||||||
fuse.value = new Fuse(list, {
|
fuse.value = new Fuse(list, {
|
||||||
shouldSort: true,
|
shouldSort: true,
|
||||||
@ -77,20 +76,23 @@ const initFuse = (list: Router) => {
|
|||||||
location: 0,
|
location: 0,
|
||||||
distance: 100,
|
distance: 100,
|
||||||
minMatchCharLength: 1,
|
minMatchCharLength: 1,
|
||||||
keys: [{
|
keys: [
|
||||||
name: 'title',
|
{
|
||||||
weight: 0.7
|
name: 'title',
|
||||||
}, {
|
weight: 0.7
|
||||||
name: 'path',
|
},
|
||||||
weight: 0.3
|
{
|
||||||
}]
|
name: 'path',
|
||||||
})
|
weight: 0.3
|
||||||
}
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
};
|
||||||
// Filter out the routes that can be displayed in the sidebar
|
// Filter out the routes that can be displayed in the sidebar
|
||||||
// And generate the internationalized title
|
// And generate the internationalized title
|
||||||
const generateRoutes = (routes: RouteOption[], basePath = '', prefixTitle: string[] = []) => {
|
const generateRoutes = (routes: RouteRecordRaw[], basePath = '', prefixTitle: string[] = []) => {
|
||||||
let res: Router = []
|
let res: Router = [];
|
||||||
routes.forEach(r => {
|
routes.forEach((r) => {
|
||||||
// skip hidden router
|
// skip hidden router
|
||||||
if (!r.hidden) {
|
if (!r.hidden) {
|
||||||
const p = r.path.length > 0 && r.path[0] === '/' ? r.path : '/' + r.path;
|
const p = r.path.length > 0 && r.path[0] === '/' ? r.path : '/' + r.path;
|
||||||
@ -98,7 +100,7 @@ const generateRoutes = (routes: RouteOption[], basePath = '', prefixTitle: strin
|
|||||||
path: !isHttp(r.path) ? getNormalPath(basePath + p) : r.path,
|
path: !isHttp(r.path) ? getNormalPath(basePath + p) : r.path,
|
||||||
title: [...prefixTitle],
|
title: [...prefixTitle],
|
||||||
query: ''
|
query: ''
|
||||||
}
|
};
|
||||||
if (r.meta && r.meta.title) {
|
if (r.meta && r.meta.title) {
|
||||||
data.title = [...data.title, r.meta.title];
|
data.title = [...data.title, r.meta.title];
|
||||||
if (r.redirect !== 'noRedirect') {
|
if (r.redirect !== 'noRedirect') {
|
||||||
@ -109,7 +111,7 @@ const generateRoutes = (routes: RouteOption[], basePath = '', prefixTitle: strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (r.query) {
|
if (r.query) {
|
||||||
data.query = r.query
|
data.query = r.query;
|
||||||
}
|
}
|
||||||
|
|
||||||
// recursive child routes
|
// recursive child routes
|
||||||
@ -120,20 +122,20 @@ const generateRoutes = (routes: RouteOption[], basePath = '', prefixTitle: strin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
return res;
|
return res;
|
||||||
}
|
};
|
||||||
const querySearch = (query: string) => {
|
const querySearch = (query: string) => {
|
||||||
if (query !== '') {
|
if (query !== '') {
|
||||||
options.value = fuse.value.search(query)
|
options.value = fuse.value.search(query);
|
||||||
} else {
|
} else {
|
||||||
options.value = []
|
options.value = [];
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
searchPool.value = generateRoutes(routes.value);
|
searchPool.value = generateRoutes(routes.value);
|
||||||
})
|
});
|
||||||
|
|
||||||
// watchEffect(() => {
|
// watchEffect(() => {
|
||||||
// searchPool.value = generateRoutes(routes.value)
|
// searchPool.value = generateRoutes(routes.value)
|
||||||
@ -141,15 +143,15 @@ onMounted(() => {
|
|||||||
|
|
||||||
watch(show, (value) => {
|
watch(show, (value) => {
|
||||||
if (value) {
|
if (value) {
|
||||||
document.body.addEventListener('click', close)
|
document.body.addEventListener('click', close);
|
||||||
} else {
|
} else {
|
||||||
document.body.removeEventListener('click', close)
|
document.body.removeEventListener('click', close);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
watch(searchPool, (list) => {
|
watch(searchPool, (list) => {
|
||||||
initFuse(list)
|
initFuse(list);
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="relative" :style="{ width: width }">
|
<div class="relative" :style="{ width: width }">
|
||||||
<el-input v-model="modelValue" readonly @click="visible = !visible" placeholder="点击选择图标">
|
<el-input v-model="modelValue" readonly placeholder="点击选择图标" @click="visible = !visible">
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<svg-icon :icon-class="modelValue" />
|
<svg-icon :icon-class="modelValue" />
|
||||||
</template>
|
</template>
|
||||||
@ -8,18 +8,18 @@
|
|||||||
|
|
||||||
<el-popover shadow="none" :visible="visible" placement="bottom-end" trigger="click" :width="450">
|
<el-popover shadow="none" :visible="visible" placement="bottom-end" trigger="click" :width="450">
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<div @click="visible = !visible" class="cursor-pointer text-[#999] absolute right-[10px] top-0 height-[32px] leading-[32px]">
|
<div class="cursor-pointer text-[#999] absolute right-[10px] top-0 height-[32px] leading-[32px]" @click="visible = !visible">
|
||||||
<i-ep-caret-top v-show="visible"></i-ep-caret-top>
|
<i-ep-caret-top v-show="visible"></i-ep-caret-top>
|
||||||
<i-ep-caret-bottom v-show="!visible"></i-ep-caret-bottom>
|
<i-ep-caret-bottom v-show="!visible"></i-ep-caret-bottom>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-input class="p-2" v-model="filterValue" placeholder="搜索图标" clearable @input="filterIcons" />
|
<el-input v-model="filterValue" class="p-2" placeholder="搜索图标" clearable @input="filterIcons" />
|
||||||
|
|
||||||
<el-scrollbar height="w-[200px]">
|
<el-scrollbar height="w-[200px]">
|
||||||
<ul class="icon-list">
|
<ul class="icon-list">
|
||||||
<el-tooltip v-for="(iconName, index) in iconNames" :key="index" :content="iconName" placement="bottom" effect="light">
|
<el-tooltip v-for="(iconName, index) in iconNames" :key="index" :content="iconName" placement="bottom" effect="light">
|
||||||
<li :class="['icon-item', {active: modelValue == iconName}]" @click="selectedIcon(iconName)">
|
<li :class="['icon-item', { active: modelValue == iconName }]" @click="selectedIcon(iconName)">
|
||||||
<svg-icon color="var(--el-text-color-regular)" :icon-class="iconName" />
|
<svg-icon color="var(--el-text-color-regular)" :icon-class="iconName" />
|
||||||
</li>
|
</li>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
@ -50,13 +50,11 @@ const filterValue = ref('');
|
|||||||
*/
|
*/
|
||||||
const filterIcons = () => {
|
const filterIcons = () => {
|
||||||
if (filterValue.value) {
|
if (filterValue.value) {
|
||||||
iconNames.value = icons.filter(iconName =>
|
iconNames.value = icons.filter((iconName) => iconName.includes(filterValue.value));
|
||||||
iconName.includes(filterValue.value)
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
iconNames.value = icons;
|
iconNames.value = icons;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
/**
|
/**
|
||||||
* 选择图标
|
* 选择图标
|
||||||
* @param iconName 选择的图标名称
|
* @param iconName 选择的图标名称
|
||||||
@ -64,12 +62,12 @@ const filterIcons = () => {
|
|||||||
const selectedIcon = (iconName: string) => {
|
const selectedIcon = (iconName: string) => {
|
||||||
emit('update:modelValue', iconName);
|
emit('update:modelValue', iconName);
|
||||||
visible.value = false;
|
visible.value = false;
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.el-scrollbar {
|
.el-scrollbar {
|
||||||
max-height: calc(50vh - 100px)!important;
|
max-height: calc(50vh - 100px) !important;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
.el-divider--horizontal {
|
.el-divider--horizontal {
|
||||||
@ -99,8 +97,8 @@ const selectedIcon = (iconName: string) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.active {
|
.active {
|
||||||
border-color: var(--el-color-primary);
|
border-color: var(--el-color-primary);
|
||||||
color: var(--el-color-primary);
|
color: var(--el-color-primary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -15,11 +15,11 @@ const props = defineProps({
|
|||||||
src: propTypes.string.def(''),
|
src: propTypes.string.def(''),
|
||||||
width: {
|
width: {
|
||||||
type: [Number, String],
|
type: [Number, String],
|
||||||
default: ""
|
default: ''
|
||||||
},
|
},
|
||||||
height: {
|
height: {
|
||||||
type: [Number, String],
|
type: [Number, String],
|
||||||
default: ""
|
default: ''
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ const realSrc = computed(() => {
|
|||||||
if (!props.src) {
|
if (!props.src) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let real_src = props.src.split(",")[0];
|
let real_src = props.src.split(',')[0];
|
||||||
return real_src;
|
return real_src;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -35,21 +35,17 @@ const realSrcList = computed(() => {
|
|||||||
if (!props.src) {
|
if (!props.src) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let real_src_list = props.src.split(",");
|
let real_src_list = props.src.split(',');
|
||||||
let srcList: string[] = [];
|
let srcList: string[] = [];
|
||||||
real_src_list.forEach(item => {
|
real_src_list.forEach((item) => {
|
||||||
return srcList.push(item);
|
return srcList.push(item);
|
||||||
});
|
});
|
||||||
return srcList;
|
return srcList;
|
||||||
});
|
});
|
||||||
|
|
||||||
const realWidth = computed(() =>
|
const realWidth = computed(() => (typeof props.width == 'string' ? props.width : `${props.width}px`));
|
||||||
typeof props.width == "string" ? props.width : `${props.width}px`
|
|
||||||
);
|
|
||||||
|
|
||||||
const realHeight = computed(() =>
|
const realHeight = computed(() => (typeof props.height == 'string' ? props.height : `${props.height}px`));
|
||||||
typeof props.height == "string" ? props.height : `${props.height}px`
|
|
||||||
);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="component-upload-image">
|
<div class="component-upload-image">
|
||||||
<el-upload
|
<el-upload
|
||||||
|
ref="imageUpload"
|
||||||
multiple
|
multiple
|
||||||
:action="uploadImgUrl"
|
:action="uploadImgUrl"
|
||||||
list-type="picture-card"
|
list-type="picture-card"
|
||||||
@ -9,7 +10,6 @@
|
|||||||
:limit="limit"
|
:limit="limit"
|
||||||
:on-error="handleUploadError"
|
:on-error="handleUploadError"
|
||||||
:on-exceed="handleExceed"
|
:on-exceed="handleExceed"
|
||||||
ref="imageUpload"
|
|
||||||
:before-remove="handleDelete"
|
:before-remove="handleDelete"
|
||||||
:show-file-list="true"
|
:show-file-list="true"
|
||||||
:headers="headers"
|
:headers="headers"
|
||||||
@ -22,13 +22,13 @@
|
|||||||
</el-icon>
|
</el-icon>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
<!-- 上传提示 -->
|
<!-- 上传提示 -->
|
||||||
<div class="el-upload__tip" v-if="showTip">
|
<div v-if="showTip" class="el-upload__tip">
|
||||||
请上传
|
请上传
|
||||||
<template v-if="fileSize">
|
<template v-if="fileSize">
|
||||||
大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
|
大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="fileType">
|
<template v-if="fileType">
|
||||||
格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b>
|
格式为 <b style="color: #f56c6c">{{ fileType.join('/') }}</b>
|
||||||
</template>
|
</template>
|
||||||
的文件
|
的文件
|
||||||
</div>
|
</div>
|
||||||
@ -40,177 +40,176 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { listByIds, delOss } from "@/api/system/oss";
|
import { listByIds, delOss } from '@/api/system/oss';
|
||||||
import { ComponentInternalInstance } from "vue";
|
import { OssVO } from '@/api/system/oss/types';
|
||||||
import { OssVO } from "@/api/system/oss/types";
|
|
||||||
import { propTypes } from '@/utils/propTypes';
|
import { propTypes } from '@/utils/propTypes';
|
||||||
import {globalHeaders} from "@/utils/request";
|
import { globalHeaders } from '@/utils/request';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: [String, Object, Array],
|
modelValue: [String, Object, Array],
|
||||||
// 图片数量限制
|
// 图片数量限制
|
||||||
limit: propTypes.number.def(5),
|
limit: propTypes.number.def(5),
|
||||||
// 大小限制(MB)
|
// 大小限制(MB)
|
||||||
fileSize: propTypes.number.def(5),
|
fileSize: propTypes.number.def(5),
|
||||||
// 文件类型, 例如['png', 'jpg', 'jpeg']
|
// 文件类型, 例如['png', 'jpg', 'jpeg']
|
||||||
fileType: propTypes.array.def(["png", "jpg", "jpeg"]),
|
fileType: propTypes.array.def(['png', 'jpg', 'jpeg']),
|
||||||
// 是否显示提示
|
// 是否显示提示
|
||||||
isShowTip: {
|
isShowTip: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const emit = defineEmits(['update:modelValue']);
|
const emit = defineEmits(['update:modelValue']);
|
||||||
const number = ref(0);
|
const number = ref(0);
|
||||||
const uploadList = ref<any[]>([]);
|
const uploadList = ref<any[]>([]);
|
||||||
const dialogImageUrl = ref("");
|
const dialogImageUrl = ref('');
|
||||||
const dialogVisible = ref(false);
|
const dialogVisible = ref(false);
|
||||||
|
|
||||||
const baseUrl = import.meta.env.VITE_APP_BASE_API;
|
const baseUrl = import.meta.env.VITE_APP_BASE_API;
|
||||||
const uploadImgUrl = ref(baseUrl + "/resource/oss/upload"); // 上传的图片服务器地址
|
const uploadImgUrl = ref(baseUrl + '/resource/oss/upload'); // 上传的图片服务器地址
|
||||||
const headers = ref(globalHeaders());
|
const headers = ref(globalHeaders());
|
||||||
|
|
||||||
const fileList = ref<any[]>([]);
|
const fileList = ref<any[]>([]);
|
||||||
const showTip = computed(
|
const showTip = computed(() => props.isShowTip && (props.fileType || props.fileSize));
|
||||||
() => props.isShowTip && (props.fileType || props.fileSize)
|
|
||||||
);
|
|
||||||
|
|
||||||
const imageUploadRef = ref<ElUploadInstance>();
|
const imageUploadRef = ref<ElUploadInstance>();
|
||||||
|
|
||||||
watch(() => props.modelValue, async val => {
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
async (val) => {
|
||||||
if (val) {
|
if (val) {
|
||||||
// 首先将值转为数组
|
// 首先将值转为数组
|
||||||
let list: OssVO[] = [];
|
let list: OssVO[] = [];
|
||||||
if (Array.isArray(val)) {
|
if (Array.isArray(val)) {
|
||||||
list = val as OssVO[];
|
list = val as OssVO[];
|
||||||
|
} else {
|
||||||
|
const res = await listByIds(val as string);
|
||||||
|
list = res.data;
|
||||||
|
}
|
||||||
|
// 然后将数组转为对象数组
|
||||||
|
fileList.value = list.map((item) => {
|
||||||
|
// 字符串回显处理 如果此处存的是url可直接回显 如果存的是id需要调用接口查出来
|
||||||
|
let itemData;
|
||||||
|
if (typeof item === 'string') {
|
||||||
|
itemData = { name: item, url: item };
|
||||||
} else {
|
} else {
|
||||||
const res = await listByIds(val as string)
|
// 此处name使用ossId 防止删除出现重名
|
||||||
list = res.data
|
itemData = { name: item.ossId, url: item.url, ossId: item.ossId };
|
||||||
}
|
}
|
||||||
// 然后将数组转为对象数组
|
return itemData;
|
||||||
fileList.value = list.map(item => {
|
});
|
||||||
// 字符串回显处理 如果此处存的是url可直接回显 如果存的是id需要调用接口查出来
|
|
||||||
let itemData;
|
|
||||||
if (typeof item === "string") {
|
|
||||||
itemData = { name: item, url: item };
|
|
||||||
} else {
|
|
||||||
// 此处name使用ossId 防止删除出现重名
|
|
||||||
itemData = { name: item.ossId, url: item.url, ossId: item.ossId };
|
|
||||||
}
|
|
||||||
return itemData;
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
fileList.value = [];
|
fileList.value = [];
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}, { deep: true, immediate: true });
|
},
|
||||||
|
{ deep: true, immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
/** 上传前loading加载 */
|
/** 上传前loading加载 */
|
||||||
const handleBeforeUpload = (file: any) => {
|
const handleBeforeUpload = (file: any) => {
|
||||||
let isImg = false;
|
let isImg = false;
|
||||||
if (props.fileType.length) {
|
if (props.fileType.length) {
|
||||||
let fileExtension = "";
|
let fileExtension = '';
|
||||||
if (file.name.lastIndexOf(".") > -1) {
|
if (file.name.lastIndexOf('.') > -1) {
|
||||||
fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
|
fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1);
|
||||||
}
|
|
||||||
isImg = props.fileType.some((type: any) => {
|
|
||||||
if (file.type.indexOf(type) > -1) return true;
|
|
||||||
if (fileExtension && fileExtension.indexOf(type) > -1) return true;
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
isImg = file.type.indexOf("image") > -1;
|
|
||||||
}
|
}
|
||||||
if (!isImg) {
|
isImg = props.fileType.some((type: any) => {
|
||||||
proxy?.$modal.msgError(
|
if (file.type.indexOf(type) > -1) return true;
|
||||||
`文件格式不正确, 请上传${props.fileType.join("/")}图片格式文件!`
|
if (fileExtension && fileExtension.indexOf(type) > -1) return true;
|
||||||
);
|
return false;
|
||||||
return false;
|
});
|
||||||
|
} else {
|
||||||
|
isImg = file.type.indexOf('image') > -1;
|
||||||
|
}
|
||||||
|
if (!isImg) {
|
||||||
|
proxy?.$modal.msgError(`文件格式不正确, 请上传${props.fileType.join('/')}图片格式文件!`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (props.fileSize) {
|
||||||
|
const isLt = file.size / 1024 / 1024 < props.fileSize;
|
||||||
|
if (!isLt) {
|
||||||
|
proxy?.$modal.msgError(`上传头像图片大小不能超过 ${props.fileSize} MB!`);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
if (props.fileSize) {
|
}
|
||||||
const isLt = file.size / 1024 / 1024 < props.fileSize;
|
proxy?.$modal.loading('正在上传图片,请稍候...');
|
||||||
if (!isLt) {
|
number.value++;
|
||||||
proxy?.$modal.msgError(`上传头像图片大小不能超过 ${props.fileSize} MB!`);
|
};
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
proxy?.$modal.loading("正在上传图片,请稍候...");
|
|
||||||
number.value++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 文件个数超出
|
// 文件个数超出
|
||||||
const handleExceed = () => {
|
const handleExceed = () => {
|
||||||
proxy?.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
|
proxy?.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
|
||||||
}
|
};
|
||||||
|
|
||||||
// 上传成功回调
|
// 上传成功回调
|
||||||
const handleUploadSuccess = (res: any, file: UploadFile) => {
|
const handleUploadSuccess = (res: any, file: UploadFile) => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
uploadList.value.push({ name: res.data.fileName, url: res.data.url, ossId: res.data.ossId });
|
uploadList.value.push({ name: res.data.fileName, url: res.data.url, ossId: res.data.ossId });
|
||||||
uploadedSuccessfully();
|
uploadedSuccessfully();
|
||||||
} else {
|
} else {
|
||||||
number.value--;
|
number.value--;
|
||||||
proxy?.$modal.closeLoading();
|
proxy?.$modal.closeLoading();
|
||||||
proxy?.$modal.msgError(res.msg);
|
proxy?.$modal.msgError(res.msg);
|
||||||
imageUploadRef.value?.handleRemove(file);
|
imageUploadRef.value?.handleRemove(file);
|
||||||
uploadedSuccessfully();
|
uploadedSuccessfully();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// 删除图片
|
// 删除图片
|
||||||
const handleDelete = (file: UploadFile): boolean => {
|
const handleDelete = (file: UploadFile): boolean => {
|
||||||
const findex = fileList.value.map(f => f.name).indexOf(file.name);
|
const findex = fileList.value.map((f) => f.name).indexOf(file.name);
|
||||||
if (findex > -1 && uploadList.value.length === number.value) {
|
if (findex > -1 && uploadList.value.length === number.value) {
|
||||||
let ossId = fileList.value[findex].ossId;
|
let ossId = fileList.value[findex].ossId;
|
||||||
delOss(ossId);
|
delOss(ossId);
|
||||||
fileList.value.splice(findex, 1);
|
fileList.value.splice(findex, 1);
|
||||||
emit("update:modelValue", listToString(fileList.value));
|
emit('update:modelValue', listToString(fileList.value));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
};
|
||||||
|
|
||||||
// 上传结束处理
|
// 上传结束处理
|
||||||
const uploadedSuccessfully = () => {
|
const uploadedSuccessfully = () => {
|
||||||
if (number.value > 0 && uploadList.value.length === number.value) {
|
if (number.value > 0 && uploadList.value.length === number.value) {
|
||||||
fileList.value = fileList.value.filter(f => f.url !== undefined).concat(uploadList.value);
|
fileList.value = fileList.value.filter((f) => f.url !== undefined).concat(uploadList.value);
|
||||||
uploadList.value = [];
|
uploadList.value = [];
|
||||||
number.value = 0;
|
number.value = 0;
|
||||||
emit("update:modelValue", listToString(fileList.value));
|
emit('update:modelValue', listToString(fileList.value));
|
||||||
proxy?.$modal.closeLoading();
|
proxy?.$modal.closeLoading();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// 上传失败
|
// 上传失败
|
||||||
const handleUploadError = () => {
|
const handleUploadError = () => {
|
||||||
proxy?.$modal.msgError("上传图片失败");
|
proxy?.$modal.msgError('上传图片失败');
|
||||||
proxy?.$modal.closeLoading();
|
proxy?.$modal.closeLoading();
|
||||||
}
|
};
|
||||||
|
|
||||||
// 预览
|
// 预览
|
||||||
const handlePictureCardPreview = (file: any) => {
|
const handlePictureCardPreview = (file: any) => {
|
||||||
dialogImageUrl.value = file.url;
|
dialogImageUrl.value = file.url;
|
||||||
dialogVisible.value = true;
|
dialogVisible.value = true;
|
||||||
}
|
};
|
||||||
|
|
||||||
// 对象转成指定字符串分隔
|
// 对象转成指定字符串分隔
|
||||||
const listToString = (list: any[], separator?: string) => {
|
const listToString = (list: any[], separator?: string) => {
|
||||||
let strs = "";
|
let strs = '';
|
||||||
separator = separator || ",";
|
separator = separator || ',';
|
||||||
for (let i in list) {
|
for (let i in list) {
|
||||||
if (undefined !== list[i].ossId && list[i].url.indexOf("blob:") !== 0) {
|
if (undefined !== list[i].ossId && list[i].url.indexOf('blob:') !== 0) {
|
||||||
strs += list[i].ossId + separator;
|
strs += list[i].ossId + separator;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return strs != "" ? strs.substring(0, strs.length - 1) : "";
|
}
|
||||||
}
|
return strs != '' ? strs.substring(0, strs.length - 1) : '';
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
// .el-upload--picture-card 控制加号部分
|
// .el-upload--picture-card 控制加号部分
|
||||||
:deep(.hide .el-upload--picture-card) {
|
:deep(.hide .el-upload--picture-card) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -20,16 +20,15 @@ import { useAppStore } from '@/store/modules/app';
|
|||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const { locale } = useI18n();
|
const { locale } = useI18n();
|
||||||
|
|
||||||
|
|
||||||
const message: any = {
|
const message: any = {
|
||||||
zh_CN: '切换语言成功!',
|
zh_CN: '切换语言成功!',
|
||||||
en_US: 'Switch Language Successful!',
|
en_US: 'Switch Language Successful!'
|
||||||
}
|
};
|
||||||
const handleLanguageChange = (lang: string) => {
|
const handleLanguageChange = (lang: string) => {
|
||||||
locale.value = lang;
|
locale.value = lang;
|
||||||
appStore.changeLanguage(lang);
|
appStore.changeLanguage(lang);
|
||||||
ElMessage.success(message[lang] || '切换语言成功!');
|
ElMessage.success(message[lang] || '切换语言成功!');
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :class="{ 'hidden': hidden }" class="pagination-container">
|
<div :class="{ hidden: hidden }" class="pagination-container">
|
||||||
<el-pagination
|
<el-pagination
|
||||||
:background="background"
|
|
||||||
v-model:current-page="currentPage"
|
v-model:current-page="currentPage"
|
||||||
v-model:page-size="pageSize"
|
v-model:page-size="pageSize"
|
||||||
|
:background="background"
|
||||||
:layout="layout"
|
:layout="layout"
|
||||||
:page-sizes="pageSizes"
|
:page-sizes="pageSizes"
|
||||||
:pager-count="pagerCount"
|
:pager-count="pagerCount"
|
||||||
@ -16,69 +16,69 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export default {
|
export default {
|
||||||
name: 'Pagination'
|
name: 'Pagination'
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { scrollTo } from '@/utils/scroll-to'
|
import { scrollTo } from '@/utils/scroll-to';
|
||||||
import { propTypes } from "@/utils/propTypes";
|
import { propTypes } from '@/utils/propTypes';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
total: propTypes.number,
|
total: propTypes.number,
|
||||||
page: propTypes.number.def(1),
|
page: propTypes.number.def(1),
|
||||||
limit: propTypes.number.def(20),
|
limit: propTypes.number.def(20),
|
||||||
pageSizes: {
|
pageSizes: {
|
||||||
type: Array as PropType<number[]>,
|
type: Array,
|
||||||
default: () => [10, 20, 30, 50]
|
default: () => [10, 20, 30, 50]
|
||||||
},
|
},
|
||||||
// 移动端页码按钮的数量端默认值5
|
// 移动端页码按钮的数量端默认值5
|
||||||
pagerCount: propTypes.number.def(document.body.clientWidth < 992 ? 5 : 7),
|
pagerCount: propTypes.number.def(document.body.clientWidth < 992 ? 5 : 7),
|
||||||
layout: propTypes.string.def('total, sizes, prev, pager, next, jumper'),
|
layout: propTypes.string.def('total, sizes, prev, pager, next, jumper'),
|
||||||
background: propTypes.bool.def(true),
|
background: propTypes.bool.def(true),
|
||||||
autoScroll: propTypes.bool.def(true),
|
autoScroll: propTypes.bool.def(true),
|
||||||
hidden: propTypes.bool.def(false),
|
hidden: propTypes.bool.def(false),
|
||||||
float: propTypes.string.def('right')
|
float: propTypes.string.def('right')
|
||||||
})
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['update:page', 'update:limit', 'pagination']);
|
const emit = defineEmits(['update:page', 'update:limit', 'pagination']);
|
||||||
const currentPage = computed({
|
const currentPage = computed({
|
||||||
get() {
|
get() {
|
||||||
return props.page
|
return props.page;
|
||||||
},
|
},
|
||||||
set(val) {
|
set(val) {
|
||||||
emit('update:page', val)
|
emit('update:page', val);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
const pageSize = computed({
|
const pageSize = computed({
|
||||||
get() {
|
get() {
|
||||||
return props.limit
|
return props.limit;
|
||||||
},
|
},
|
||||||
set(val){
|
set(val) {
|
||||||
emit('update:limit', val)
|
emit('update:limit', val);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
function handleSizeChange(val: number) {
|
function handleSizeChange(val: number) {
|
||||||
if (currentPage.value * val > props.total) {
|
if (currentPage.value * val > props.total) {
|
||||||
currentPage.value = 1
|
currentPage.value = 1;
|
||||||
}
|
}
|
||||||
emit('pagination', { page: currentPage.value, limit: val })
|
emit('pagination', { page: currentPage.value, limit: val });
|
||||||
if (props.autoScroll) {
|
if (props.autoScroll) {
|
||||||
scrollTo(0, 800)
|
scrollTo(0, 800);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function handleCurrentChange(val: number) {
|
function handleCurrentChange(val: number) {
|
||||||
emit('pagination', { page: val, limit: pageSize.value })
|
emit('pagination', { page: val, limit: pageSize.value });
|
||||||
if (props.autoScroll) {
|
if (props.autoScroll) {
|
||||||
scrollTo(0, 800)
|
scrollTo(0, 800);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.pagination-container {
|
.pagination-container {
|
||||||
padding: 32px 16px;
|
padding: 32px 16px;
|
||||||
.el-pagination{
|
.el-pagination {
|
||||||
float: v-bind(float);
|
float: v-bind(float);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="top-right-btn" :style="style">
|
<div class="top-right-btn" :style="style">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top" v-if="search">
|
<el-tooltip v-if="search" class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
|
||||||
<el-button circle icon="Search" @click="toggleSearch()" />
|
<el-button circle icon="Search" @click="toggleSearch()" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
|
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
|
||||||
<el-button circle icon="Refresh" @click="refresh()" />
|
<el-button circle icon="Refresh" @click="refresh()" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip class="item" effect="dark" content="显示/隐藏列" placement="top" v-if="columns">
|
<el-tooltip v-if="columns" class="item" effect="dark" content="显示/隐藏列" placement="top">
|
||||||
<div class="show-btn">
|
<div class="show-btn">
|
||||||
<el-popover placement="bottom" trigger="click">
|
<el-popover placement="bottom" trigger="click">
|
||||||
<div class="tree-header">显示/隐藏列</div>
|
<div class="tree-header">显示/隐藏列</div>
|
||||||
@ -15,9 +15,9 @@
|
|||||||
ref="columnRef"
|
ref="columnRef"
|
||||||
:data="columns"
|
:data="columns"
|
||||||
show-checkbox
|
show-checkbox
|
||||||
@check="columnChange"
|
|
||||||
node-key="key"
|
node-key="key"
|
||||||
:props="{ label: 'label', children: 'children' }"
|
:props="{ label: 'label', children: 'children' }"
|
||||||
|
@check="columnChange"
|
||||||
></el-tree>
|
></el-tree>
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<el-button circle icon="Menu" />
|
<el-button circle icon="Menu" />
|
||||||
@ -33,51 +33,49 @@
|
|||||||
import { propTypes } from '@/utils/propTypes';
|
import { propTypes } from '@/utils/propTypes';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
showSearch: propTypes.bool.def(true),
|
showSearch: propTypes.bool.def(true),
|
||||||
columns: {
|
columns: propTypes.fieldOption,
|
||||||
type: Array as PropType<FieldOption[]>,
|
search: propTypes.bool.def(true),
|
||||||
},
|
gutter: propTypes.number.def(10)
|
||||||
search: propTypes.bool.def(true),
|
});
|
||||||
gutter: propTypes.number.def(10),
|
|
||||||
})
|
|
||||||
|
|
||||||
const columnRef = ref<ElTreeInstance>();
|
const columnRef = ref<ElTreeInstance>();
|
||||||
const emits = defineEmits(['update:showSearch', 'queryTable']);
|
const emits = defineEmits(['update:showSearch', 'queryTable']);
|
||||||
|
|
||||||
const style = computed(() => {
|
const style = computed(() => {
|
||||||
const ret: any = {};
|
const ret: any = {};
|
||||||
if (props.gutter) {
|
if (props.gutter) {
|
||||||
ret.marginRight = `${props.gutter / 2}px`;
|
ret.marginRight = `${props.gutter / 2}px`;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
});
|
});
|
||||||
|
|
||||||
// 搜索
|
// 搜索
|
||||||
function toggleSearch() {
|
function toggleSearch() {
|
||||||
emits("update:showSearch", !props.showSearch);
|
emits('update:showSearch', !props.showSearch);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 刷新
|
// 刷新
|
||||||
function refresh() {
|
function refresh() {
|
||||||
emits("queryTable");
|
emits('queryTable');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更改数据列的显示和隐藏
|
// 更改数据列的显示和隐藏
|
||||||
function columnChange(...args: any[]) {
|
function columnChange(...args: any[]) {
|
||||||
props.columns?.forEach((item) => {
|
props.columns?.forEach((item) => {
|
||||||
item.visible = args[1].checkedKeys.includes(item.key);
|
item.visible = args[1].checkedKeys.includes(item.key);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 显隐列初始默认隐藏列
|
// 显隐列初始默认隐藏列
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
props.columns?.forEach((item) => {
|
props.columns?.forEach((item) => {
|
||||||
if (item.visible) {
|
if (item.visible) {
|
||||||
columnRef.value?.setChecked(item.key, true, false);
|
columnRef.value?.setChecked(item.key, true, false);
|
||||||
// value.value.push(item.key);
|
// value.value.push(item.key);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@ -93,7 +91,7 @@ onMounted(() => {
|
|||||||
.my-el-transfer {
|
.my-el-transfer {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
.tree-header{
|
.tree-header {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
@ -8,6 +8,6 @@
|
|||||||
const url = ref('https://plus-doc.dromara.org/');
|
const url = ref('https://plus-doc.dromara.org/');
|
||||||
|
|
||||||
function goto() {
|
function goto() {
|
||||||
window.open(url.value)
|
window.open(url.value);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -8,6 +8,6 @@
|
|||||||
const url = ref('https://gitee.com/dromara/RuoYi-Vue-Plus');
|
const url = ref('https://gitee.com/dromara/RuoYi-Vue-Plus');
|
||||||
|
|
||||||
function goto() {
|
function goto() {
|
||||||
window.open(url.value)
|
window.open(url.value);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -16,20 +16,20 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import useAppStore from "@/store/modules/app";
|
import useAppStore from '@/store/modules/app';
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const size = computed(() => appStore.size);
|
const size = computed(() => appStore.size);
|
||||||
|
|
||||||
const sizeOptions = ref([
|
const sizeOptions = ref([
|
||||||
{ label: "较大", value: "large" },
|
{ label: '较大', value: 'large' },
|
||||||
{ label: "默认", value: "default" },
|
{ label: '默认', value: 'default' },
|
||||||
{ label: "稍小", value: "small" },
|
{ label: '稍小', value: 'small' }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const handleSetSize = (size: string) => {
|
const handleSetSize = (size: string) => {
|
||||||
appStore.setSize(size);
|
appStore.setSize(size);
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@ -8,17 +8,17 @@
|
|||||||
import { propTypes } from '@/utils/propTypes';
|
import { propTypes } from '@/utils/propTypes';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
iconClass: propTypes.string.isRequired,
|
iconClass: propTypes.string.isRequired,
|
||||||
className: propTypes.string.def(''),
|
className: propTypes.string.def(''),
|
||||||
color: propTypes.string.def(''),
|
color: propTypes.string.def('')
|
||||||
})
|
});
|
||||||
const iconName = computed(() => `#icon-${props.iconClass}`);
|
const iconName = computed(() => `#icon-${props.iconClass}`);
|
||||||
const svgClass = computed(() => {
|
const svgClass = computed(() => {
|
||||||
if (props.className) {
|
if (props.className) {
|
||||||
return `svg-icon ${props.className}`
|
return `svg-icon ${props.className}`;
|
||||||
}
|
}
|
||||||
return 'svg-icon'
|
return 'svg-icon';
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scope lang="scss">
|
<style scope lang="scss">
|
||||||
|
|||||||
@ -1,19 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-menu :default-active="activeMenu" mode="horizontal" @select="handleSelect" :ellipsis="false">
|
<el-menu :default-active="activeMenu" mode="horizontal" :ellipsis="false" @select="handleSelect">
|
||||||
<template v-for="(item, index) in topMenus">
|
<template v-for="(item, index) in topMenus">
|
||||||
<el-menu-item :style="{'--theme': theme}" :index="item.path" :key="index" v-if="index < visibleNumber"
|
<el-menu-item v-if="index < visibleNumber" :key="index" :style="{ '--theme': theme }" :index="item.path"
|
||||||
><svg-icon
|
><svg-icon v-if="item.meta && item.meta.icon && item.meta.icon !== '#'" :icon-class="item.meta ? item.meta.icon : ''" />
|
||||||
v-if="item.meta && item.meta.icon && item.meta.icon !== '#'"
|
{{ item.meta?.title }}</el-menu-item
|
||||||
:icon-class="item.meta ? item.meta.icon : '' " /> {{ item.meta?.title }}</el-menu-item
|
|
||||||
>
|
>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 顶部菜单超出数量折叠 -->
|
<!-- 顶部菜单超出数量折叠 -->
|
||||||
<el-sub-menu :style="{'--theme': theme}" index="more" v-if="topMenus.length > visibleNumber">
|
<el-sub-menu v-if="topMenus.length > visibleNumber" :style="{ '--theme': theme }" index="more">
|
||||||
<template #title>更多菜单</template>
|
<template #title>更多菜单</template>
|
||||||
<template v-for="(item, index) in topMenus">
|
<template v-for="(item, index) in topMenus">
|
||||||
<el-menu-item :index="item.path" :key="index" v-if="index >= visibleNumber"
|
<el-menu-item v-if="index >= visibleNumber" :key="index" :index="item.path"
|
||||||
><svg-icon :icon-class="item.meta ? item.meta.icon : '' " /> {{ item.meta?.title }}</el-menu-item
|
><svg-icon :icon-class="item.meta ? item.meta.icon : ''" /> {{ item.meta?.title }}</el-menu-item
|
||||||
>
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-sub-menu>
|
</el-sub-menu>
|
||||||
@ -26,7 +25,7 @@ import { isHttp } from '@/utils/validate';
|
|||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
import useSettingsStore from '@/store/modules/settings';
|
import useSettingsStore from '@/store/modules/settings';
|
||||||
import usePermissionStore from '@/store/modules/permission';
|
import usePermissionStore from '@/store/modules/permission';
|
||||||
import { RouteOption } from 'vue-router';
|
import { RouteRecordRaw } from 'vue-router';
|
||||||
|
|
||||||
// 顶部栏初始数
|
// 顶部栏初始数
|
||||||
const visibleNumber = ref<number>(-1);
|
const visibleNumber = ref<number>(-1);
|
||||||
@ -35,9 +34,9 @@ const currentIndex = ref<string>();
|
|||||||
// 隐藏侧边栏路由
|
// 隐藏侧边栏路由
|
||||||
const hideList = ['/index', '/user/profile'];
|
const hideList = ['/index', '/user/profile'];
|
||||||
|
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore();
|
||||||
const settingsStore = useSettingsStore()
|
const settingsStore = useSettingsStore();
|
||||||
const permissionStore = usePermissionStore()
|
const permissionStore = usePermissionStore();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
@ -48,73 +47,73 @@ const routers = computed(() => permissionStore.topbarRouters);
|
|||||||
|
|
||||||
// 顶部显示菜单
|
// 顶部显示菜单
|
||||||
const topMenus = computed(() => {
|
const topMenus = computed(() => {
|
||||||
let topMenus:RouteOption[] = [];
|
let topMenus: RouteRecordRaw[] = [];
|
||||||
routers.value.map((menu) => {
|
routers.value.map((menu) => {
|
||||||
if (menu.hidden !== true) {
|
if (menu.hidden !== true) {
|
||||||
// 兼容顶部栏一级菜单内部跳转
|
// 兼容顶部栏一级菜单内部跳转
|
||||||
if (menu.path === "/") {
|
if (menu.path === '/') {
|
||||||
topMenus.push(menu.children? menu.children[0] : menu);
|
topMenus.push(menu.children ? menu.children[0] : menu);
|
||||||
} else {
|
} else {
|
||||||
topMenus.push(menu);
|
topMenus.push(menu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
return topMenus;
|
return topMenus;
|
||||||
})
|
});
|
||||||
|
|
||||||
// 设置子路由
|
// 设置子路由
|
||||||
const childrenMenus = computed(() => {
|
const childrenMenus = computed(() => {
|
||||||
let childrenMenus:RouteOption[] = [];
|
let childrenMenus: RouteRecordRaw[] = [];
|
||||||
routers.value.map((router) => {
|
routers.value.map((router) => {
|
||||||
router.children?.forEach((item) => {
|
router.children?.forEach((item) => {
|
||||||
if (item.parentPath === undefined) {
|
if (item.parentPath === undefined) {
|
||||||
if(router.path === "/") {
|
if (router.path === '/') {
|
||||||
item.path = "/" + item.path;
|
item.path = '/' + item.path;
|
||||||
} else {
|
} else {
|
||||||
if(!isHttp(item.path)) {
|
if (!isHttp(item.path)) {
|
||||||
item.path = router.path + "/" + item.path;
|
item.path = router.path + '/' + item.path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
item.parentPath = router.path;
|
item.parentPath = router.path;
|
||||||
}
|
}
|
||||||
childrenMenus.push(item);
|
childrenMenus.push(item);
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
return constantRoutes.concat(childrenMenus);
|
return constantRoutes.concat(childrenMenus);
|
||||||
})
|
});
|
||||||
|
|
||||||
// 默认激活的菜单
|
// 默认激活的菜单
|
||||||
const activeMenu = computed(() => {
|
const activeMenu = computed(() => {
|
||||||
const path = route.path;
|
const path = route.path;
|
||||||
let activePath = path;
|
let activePath = path;
|
||||||
if (path !== undefined && path.lastIndexOf("/") > 0 && hideList.indexOf(path) === -1) {
|
if (path !== undefined && path.lastIndexOf('/') > 0 && hideList.indexOf(path) === -1) {
|
||||||
const tmpPath = path.substring(1, path.length);
|
const tmpPath = path.substring(1, path.length);
|
||||||
activePath = "/" + tmpPath.substring(0, tmpPath.indexOf("/"));
|
activePath = '/' + tmpPath.substring(0, tmpPath.indexOf('/'));
|
||||||
if (!route.meta.link) {
|
if (!route.meta.link) {
|
||||||
appStore.toggleSideBarHide(false);
|
appStore.toggleSideBarHide(false);
|
||||||
}
|
}
|
||||||
} else if(!route.children) {
|
} else if (!route.children) {
|
||||||
activePath = path;
|
activePath = path;
|
||||||
appStore.toggleSideBarHide(true);
|
appStore.toggleSideBarHide(true);
|
||||||
}
|
}
|
||||||
activeRoutes(activePath);
|
activeRoutes(activePath);
|
||||||
return activePath;
|
return activePath;
|
||||||
})
|
});
|
||||||
|
|
||||||
const setVisibleNumber = () => {
|
const setVisibleNumber = () => {
|
||||||
const width = document.body.getBoundingClientRect().width / 3;
|
const width = document.body.getBoundingClientRect().width / 3;
|
||||||
visibleNumber.value = parseInt(String(width / 85));
|
visibleNumber.value = parseInt(String(width / 85));
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleSelect = (key: string) => {
|
const handleSelect = (key: string) => {
|
||||||
currentIndex.value = key;
|
currentIndex.value = key;
|
||||||
const route = routers.value.find(item => item.path === key);
|
const route = routers.value.find((item) => item.path === key);
|
||||||
if (isHttp(key)) {
|
if (isHttp(key)) {
|
||||||
// http(s):// 路径新窗口打开
|
// http(s):// 路径新窗口打开
|
||||||
window.open(key, "_blank");
|
window.open(key, '_blank');
|
||||||
} else if (!route || !route.children) {
|
} else if (!route || !route.children) {
|
||||||
// 没有子路由路径内部打开
|
// 没有子路由路径内部打开
|
||||||
const routeMenu = childrenMenus.value.find(item => item.path === key);
|
const routeMenu = childrenMenus.value.find((item) => item.path === key);
|
||||||
if (routeMenu && routeMenu.query) {
|
if (routeMenu && routeMenu.query) {
|
||||||
let query = JSON.parse(routeMenu.query);
|
let query = JSON.parse(routeMenu.query);
|
||||||
router.push({ path: key, query: query });
|
router.push({ path: key, query: query });
|
||||||
@ -127,35 +126,35 @@ const handleSelect = (key: string) => {
|
|||||||
activeRoutes(key);
|
activeRoutes(key);
|
||||||
appStore.toggleSideBarHide(false);
|
appStore.toggleSideBarHide(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const activeRoutes = (key: string) => {
|
const activeRoutes = (key: string) => {
|
||||||
let routes:RouteOption[] = [];
|
let routes: RouteRecordRaw[] = [];
|
||||||
if (childrenMenus.value && childrenMenus.value.length > 0) {
|
if (childrenMenus.value && childrenMenus.value.length > 0) {
|
||||||
childrenMenus.value.map((item) => {
|
childrenMenus.value.map((item) => {
|
||||||
if (key == item.parentPath || (key == "index" && "" == item.path)) {
|
if (key == item.parentPath || (key == 'index' && '' == item.path)) {
|
||||||
routes.push(item);
|
routes.push(item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if(routes.length > 0) {
|
if (routes.length > 0) {
|
||||||
permissionStore.setSidebarRouters(routes);
|
permissionStore.setSidebarRouters(routes);
|
||||||
} else {
|
} else {
|
||||||
appStore.toggleSideBarHide(true);
|
appStore.toggleSideBarHide(true);
|
||||||
}
|
}
|
||||||
return routes;
|
return routes;
|
||||||
}
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
window.addEventListener('resize', setVisibleNumber)
|
window.addEventListener('resize', setVisibleNumber);
|
||||||
})
|
});
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
window.removeEventListener('resize', setVisibleNumber)
|
window.removeEventListener('resize', setVisibleNumber);
|
||||||
})
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
setVisibleNumber()
|
setVisibleNumber();
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@ -168,7 +167,8 @@ onMounted(() => {
|
|||||||
margin: 0 10px !important;
|
margin: 0 10px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.topmenu-container.el-menu--horizontal > .el-menu-item.is-active, .el-menu--horizontal > .el-sub-menu.is-active .el-submenu__title {
|
.topmenu-container.el-menu--horizontal > .el-menu-item.is-active,
|
||||||
|
.el-menu--horizontal > .el-sub-menu.is-active .el-submenu__title {
|
||||||
border-bottom: 2px solid #{'var(--theme)'} !important;
|
border-bottom: 2px solid #{'var(--theme)'} !important;
|
||||||
color: #303133;
|
color: #303133;
|
||||||
}
|
}
|
||||||
@ -184,7 +184,9 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 背景色隐藏 */
|
/* 背景色隐藏 */
|
||||||
.topmenu-container.el-menu--horizontal>.el-menu-item:not(.is-disabled):focus, .topmenu-container.el-menu--horizontal>.el-menu-item:not(.is-disabled):hover, .topmenu-container.el-menu--horizontal>.el-submenu .el-submenu__title:hover {
|
.topmenu-container.el-menu--horizontal > .el-menu-item:not(.is-disabled):focus,
|
||||||
|
.topmenu-container.el-menu--horizontal > .el-menu-item:not(.is-disabled):hover,
|
||||||
|
.topmenu-container.el-menu--horizontal > .el-submenu .el-submenu__title:hover {
|
||||||
background-color: #ffffff !important;
|
background-color: #ffffff !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="el-tree-select">
|
<div class="el-tree-select">
|
||||||
<el-select
|
<el-select
|
||||||
style="width: 100%"
|
|
||||||
v-model="valueId"
|
|
||||||
ref="treeSelect"
|
ref="treeSelect"
|
||||||
|
v-model="valueId"
|
||||||
|
style="width: 100%"
|
||||||
:filterable="true"
|
:filterable="true"
|
||||||
:clearable="true"
|
:clearable="true"
|
||||||
@clear="clearHandle"
|
|
||||||
:filter-method="selectFilterData"
|
:filter-method="selectFilterData"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
|
@clear="clearHandle"
|
||||||
>
|
>
|
||||||
<el-option :value="valueId" :label="valueTitle">
|
<el-option :value="valueId" :label="valueTitle">
|
||||||
<el-tree
|
<el-tree
|
||||||
@ -29,43 +29,32 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
interface ObjMap {
|
||||||
|
value: string;
|
||||||
|
label: string;
|
||||||
|
children: string;
|
||||||
|
}
|
||||||
|
interface Props {
|
||||||
|
objMap: ObjMap;
|
||||||
|
accordion: boolean;
|
||||||
|
value: string | number;
|
||||||
|
options: any[];
|
||||||
|
placeholder: string;
|
||||||
|
}
|
||||||
|
|
||||||
const props = defineProps({
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
/* 配置项 */
|
objMap: () => {
|
||||||
objMap: {
|
return {
|
||||||
type: Object,
|
value: 'id',
|
||||||
default: () => {
|
label: 'label',
|
||||||
return {
|
children: 'children'
|
||||||
value: 'id', // ID字段名
|
};
|
||||||
label: 'label', // 显示名称
|
|
||||||
children: 'children' // 子级字段名
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
/* 自动收起 */
|
accordion: false,
|
||||||
accordion: {
|
value: '',
|
||||||
type: Boolean,
|
options: () => [],
|
||||||
default: () => {
|
placeholder: ''
|
||||||
return false
|
});
|
||||||
}
|
|
||||||
},
|
|
||||||
/**当前双向数据绑定的值 */
|
|
||||||
value: {
|
|
||||||
type: [String, Number],
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
/**当前的数据 */
|
|
||||||
options: {
|
|
||||||
type: Array,
|
|
||||||
default: () => []
|
|
||||||
},
|
|
||||||
/**输入框内部的文字 */
|
|
||||||
placeholder: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
const selectTree = ref<ElTreeSelectInstance>();
|
const selectTree = ref<ElTreeSelectInstance>();
|
||||||
|
|
||||||
@ -74,7 +63,7 @@ const emit = defineEmits(['update:value']);
|
|||||||
const valueId = computed({
|
const valueId = computed({
|
||||||
get: () => props.value,
|
get: () => props.value,
|
||||||
set: (val) => {
|
set: (val) => {
|
||||||
emit('update:value', val)
|
emit('update:value', val);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const valueTitle = ref('');
|
const valueTitle = ref('');
|
||||||
@ -83,54 +72,54 @@ const defaultExpandedKey = ref<any[]>([]);
|
|||||||
const initHandle = () => {
|
const initHandle = () => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
const selectedValue = valueId.value;
|
const selectedValue = valueId.value;
|
||||||
if (selectedValue !== null && typeof (selectedValue) !== 'undefined') {
|
if (selectedValue !== null && typeof selectedValue !== 'undefined') {
|
||||||
const node = selectTree.value?.getNode(selectedValue)
|
const node = selectTree.value?.getNode(selectedValue);
|
||||||
if (node) {
|
if (node) {
|
||||||
valueTitle.value = node.data[props.objMap.label]
|
valueTitle.value = node.data[props.objMap.label];
|
||||||
selectTree.value?.setCurrentKey(selectedValue) // 设置默认选中
|
selectTree.value?.setCurrentKey(selectedValue); // 设置默认选中
|
||||||
defaultExpandedKey.value = [selectedValue] // 设置默认展开
|
defaultExpandedKey.value = [selectedValue]; // 设置默认展开
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
clearHandle()
|
clearHandle();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
const handleNodeClick = (node: any) => {
|
const handleNodeClick = (node: any) => {
|
||||||
valueTitle.value = node[props.objMap.label]
|
valueTitle.value = node[props.objMap.label];
|
||||||
valueId.value = node[props.objMap.value];
|
valueId.value = node[props.objMap.value];
|
||||||
defaultExpandedKey.value = [];
|
defaultExpandedKey.value = [];
|
||||||
selectTree.value?.blur()
|
selectTree.value?.blur();
|
||||||
selectFilterData('')
|
selectFilterData('');
|
||||||
}
|
};
|
||||||
const selectFilterData = (val: any) => {
|
const selectFilterData = (val: any) => {
|
||||||
selectTree.value?.filter(val)
|
selectTree.value?.filter(val);
|
||||||
}
|
};
|
||||||
const filterNode = (value: any, data: any) => {
|
const filterNode = (value: any, data: any) => {
|
||||||
if (!value) return true
|
if (!value) return true;
|
||||||
return data[props.objMap['label']].indexOf(value) !== -1
|
return data[props.objMap['label']].indexOf(value) !== -1;
|
||||||
}
|
};
|
||||||
const clearHandle = () => {
|
const clearHandle = () => {
|
||||||
valueTitle.value = ''
|
valueTitle.value = '';
|
||||||
valueId.value = ''
|
valueId.value = '';
|
||||||
defaultExpandedKey.value = [];
|
defaultExpandedKey.value = [];
|
||||||
clearSelected()
|
clearSelected();
|
||||||
}
|
};
|
||||||
const clearSelected = () => {
|
const clearSelected = () => {
|
||||||
const allNode = document.querySelectorAll('#tree-option .el-tree-node')
|
const allNode = document.querySelectorAll('#tree-option .el-tree-node');
|
||||||
allNode.forEach((element) => element.classList.remove('is-current'))
|
allNode.forEach((element) => element.classList.remove('is-current'));
|
||||||
}
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initHandle()
|
initHandle();
|
||||||
})
|
});
|
||||||
|
|
||||||
watch(valueId, () => {
|
watch(valueId, () => {
|
||||||
initHandle();
|
initHandle();
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import "@/assets/styles/variables.module.scss";
|
@import '@/assets/styles/variables.module.scss';
|
||||||
|
|
||||||
.el-scrollbar .el-scrollbar__view .el-select-dropdown__item {
|
.el-scrollbar .el-scrollbar__view .el-select-dropdown__item {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|||||||
@ -9,18 +9,18 @@ import { propTypes } from '@/utils/propTypes';
|
|||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
src: propTypes.string.isRequired
|
src: propTypes.string.isRequired
|
||||||
})
|
});
|
||||||
|
|
||||||
const height = ref(document.documentElement.clientHeight - 94.5 + "px;")
|
const height = ref(document.documentElement.clientHeight - 94.5 + 'px;');
|
||||||
const loading = ref(true)
|
const loading = ref(true);
|
||||||
const url = computed(() => props.src)
|
const url = computed(() => props.src);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}, 300);
|
}, 300);
|
||||||
window.onresize = function temp() {
|
window.onresize = function temp() {
|
||||||
height.value = document.documentElement.clientHeight - 94.5 + "px;";
|
height.value = document.documentElement.clientHeight - 94.5 + 'px;';
|
||||||
};
|
};
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export const hasPermi: Directive = {
|
|||||||
// 「其他角色」按钮权限校验
|
// 「其他角色」按钮权限校验
|
||||||
const { value } = binding;
|
const { value } = binding;
|
||||||
if (value && value instanceof Array && value.length > 0) {
|
if (value && value instanceof Array && value.length > 0) {
|
||||||
const hasPermission = permissions.some((permi) => {
|
const hasPermission = permissions.some((permi: string) => {
|
||||||
return permi === '*:*:*' || value.includes(permi);
|
return permi === '*:*:*' || value.includes(permi);
|
||||||
});
|
});
|
||||||
if (!hasPermission) {
|
if (!hasPermission) {
|
||||||
@ -30,7 +30,7 @@ export const hasRoles: Directive = {
|
|||||||
const { value } = binding;
|
const { value } = binding;
|
||||||
const { roles } = useUserStore();
|
const { roles } = useUserStore();
|
||||||
if (value && value instanceof Array && value.length > 0) {
|
if (value && value instanceof Array && value.length > 0) {
|
||||||
const hasRole = roles.some((role) => {
|
const hasRole = roles.some((role: string) => {
|
||||||
return role === 'admin' || value.includes(role);
|
return role === 'admin' || value.includes(role);
|
||||||
});
|
});
|
||||||
if (!hasRole) {
|
if (!hasRole) {
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
<router-view v-slot="{ Component, route }">
|
<router-view v-slot="{ Component, route }">
|
||||||
<transition :enter-active-class="animante" mode="out-in">
|
<transition :enter-active-class="animante" mode="out-in">
|
||||||
<keep-alive :include="tagsViewStore.cachedViews">
|
<keep-alive :include="tagsViewStore.cachedViews">
|
||||||
<component v-if="!route.meta.link" :is="Component" :key="route.path" />
|
<component :is="Component" v-if="!route.meta.link" :key="route.path" />
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
</transition>
|
</transition>
|
||||||
</router-view>
|
</router-view>
|
||||||
@ -14,22 +14,25 @@
|
|||||||
<script setup name="AppMain" lang="ts">
|
<script setup name="AppMain" lang="ts">
|
||||||
import useTagsViewStore from '@/store/modules/tagsView';
|
import useTagsViewStore from '@/store/modules/tagsView';
|
||||||
import useSettingsStore from '@/store/modules/settings';
|
import useSettingsStore from '@/store/modules/settings';
|
||||||
import IframeToggle from './IframeToggle/index.vue'
|
import IframeToggle from './IframeToggle/index.vue';
|
||||||
import { ComponentInternalInstance } from "vue";
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const tagsViewStore = useTagsViewStore();
|
const tagsViewStore = useTagsViewStore();
|
||||||
|
|
||||||
// 随机动画集合
|
// 随机动画集合
|
||||||
const animante = ref<string>('');
|
const animante = ref<string>('');
|
||||||
const animationEnable = ref(useSettingsStore().animationEnable);
|
const animationEnable = ref(useSettingsStore().animationEnable);
|
||||||
watch(()=> useSettingsStore().animationEnable, (val) => {
|
watch(
|
||||||
|
() => useSettingsStore().animationEnable,
|
||||||
|
(val) => {
|
||||||
animationEnable.value = val;
|
animationEnable.value = val;
|
||||||
if (val) {
|
if (val) {
|
||||||
animante.value = proxy?.animate.animateList[Math.round(Math.random() * proxy?.animate.animateList.length)] as string;
|
animante.value = proxy?.animate.animateList[Math.round(Math.random() * proxy?.animate.animateList.length)] as string;
|
||||||
} else {
|
} else {
|
||||||
animante.value = proxy?.animate.defaultAnimate as string;
|
animante.value = proxy?.animate.defaultAnimate as string;
|
||||||
}
|
}
|
||||||
}, { immediate: true });
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@ -41,7 +44,7 @@ watch(()=> useSettingsStore().animationEnable, (val) => {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fixed-header+.app-main {
|
.fixed-header + .app-main {
|
||||||
padding-top: 50px;
|
padding-top: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +54,7 @@ watch(()=> useSettingsStore().animationEnable, (val) => {
|
|||||||
min-height: calc(100vh - 84px);
|
min-height: calc(100vh - 84px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.fixed-header+.app-main {
|
.fixed-header + .app-main {
|
||||||
padding-top: 84px;
|
padding-top: 84px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,16 +2,16 @@
|
|||||||
<transition-group name="fade-transform" mode="out-in">
|
<transition-group name="fade-transform" mode="out-in">
|
||||||
<inner-link
|
<inner-link
|
||||||
v-for="(item, index) in tagsViewStore.iframeViews"
|
v-for="(item, index) in tagsViewStore.iframeViews"
|
||||||
:key="item.path"
|
|
||||||
:iframeId="'iframe' + index"
|
|
||||||
v-show="route.path === item.path"
|
v-show="route.path === item.path"
|
||||||
|
:key="item.path"
|
||||||
|
:iframe-id="'iframe' + index"
|
||||||
:src="iframeUrl(item.meta ? item.meta.link : '', item.query)"
|
:src="iframeUrl(item.meta ? item.meta.link : '', item.query)"
|
||||||
></inner-link>
|
></inner-link>
|
||||||
</transition-group>
|
</transition-group>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import InnerLink from "../InnerLink/index.vue";
|
import InnerLink from '../InnerLink/index.vue';
|
||||||
import useTagsViewStore from '@/store/modules/tagsView';
|
import useTagsViewStore from '@/store/modules/tagsView';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
@ -19,8 +19,10 @@ const tagsViewStore = useTagsViewStore();
|
|||||||
|
|
||||||
function iframeUrl(url: string, query: any) {
|
function iframeUrl(url: string, query: any) {
|
||||||
if (Object.keys(query).length > 0) {
|
if (Object.keys(query).length > 0) {
|
||||||
let params = Object.keys(query).map((key) => key + "=" + query[key]).join("&");
|
let params = Object.keys(query)
|
||||||
return url + "?" + params;
|
.map((key) => key + '=' + query[key])
|
||||||
|
.join('&');
|
||||||
|
return url + '?' + params;
|
||||||
}
|
}
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,14 +5,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { propTypes } from '@/utils/propTypes';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
src: {
|
src: propTypes.string.def('/'),
|
||||||
type: String,
|
iframeId: propTypes.string.isRequired
|
||||||
default: "/"
|
|
||||||
},
|
|
||||||
iframeId: {
|
|
||||||
type: String
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
const height = ref(document.documentElement.clientHeight - 94.5 + "px");
|
const height = ref(document.documentElement.clientHeight - 94.5 + 'px');
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,18 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="navbar">
|
<div class="navbar">
|
||||||
<hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
|
<hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container" @toggle-click="toggleSideBar" />
|
||||||
<breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!settingsStore.topNav" />
|
<breadcrumb v-if="!settingsStore.topNav" id="breadcrumb-container" class="breadcrumb-container" />
|
||||||
<top-nav id="topmenu-container" class="topmenu-container" v-if="settingsStore.topNav" />
|
<top-nav v-if="settingsStore.topNav" id="topmenu-container" class="topmenu-container" />
|
||||||
|
|
||||||
<div class="right-menu flex align-center">
|
<div class="right-menu flex align-center">
|
||||||
<template v-if="appStore.device !== 'mobile'">
|
<template v-if="appStore.device !== 'mobile'">
|
||||||
<el-select
|
<el-select
|
||||||
|
v-if="userId === 1 && tenantEnabled"
|
||||||
v-model="companyName"
|
v-model="companyName"
|
||||||
clearable
|
clearable
|
||||||
filterable
|
filterable
|
||||||
reserve-keyword
|
reserve-keyword
|
||||||
:placeholder="$t('navbar.selectTenant')"
|
:placeholder="$t('navbar.selectTenant')"
|
||||||
v-if="userId === 1 && tenantEnabled"
|
|
||||||
@change="dynamicTenantEvent"
|
@change="dynamicTenantEvent"
|
||||||
@clear="dynamicClearEvent"
|
@clear="dynamicClearEvent"
|
||||||
>
|
>
|
||||||
@ -63,17 +63,17 @@
|
|||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
<div class="avatar-container">
|
<div class="avatar-container">
|
||||||
<el-dropdown @command="handleCommand" class="right-menu-item hover-effect" trigger="click">
|
<el-dropdown class="right-menu-item hover-effect" trigger="click" @command="handleCommand">
|
||||||
<div class="avatar-wrapper">
|
<div class="avatar-wrapper">
|
||||||
<img :src="userStore.avatar" class="user-avatar" />
|
<img :src="userStore.avatar" class="user-avatar" />
|
||||||
<el-icon><caret-bottom /></el-icon>
|
<el-icon><caret-bottom /></el-icon>
|
||||||
</div>
|
</div>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
<router-link to="/user/profile" v-if="!dynamic">
|
<router-link v-if="!dynamic" to="/user/profile">
|
||||||
<el-dropdown-item>{{ $t('navbar.personalCenter') }}</el-dropdown-item>
|
<el-dropdown-item>{{ $t('navbar.personalCenter') }}</el-dropdown-item>
|
||||||
</router-link>
|
</router-link>
|
||||||
<el-dropdown-item command="setLayout" v-if="settingsStore.showSettings">
|
<el-dropdown-item v-if="settingsStore.showSettings" command="setLayout">
|
||||||
<span>{{ $t('navbar.layoutSetting') }}</span>
|
<span>{{ $t('navbar.layoutSetting') }}</span>
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
<el-dropdown-item divided command="logout">
|
<el-dropdown-item divided command="logout">
|
||||||
@ -92,10 +92,9 @@ import SearchMenu from './TopBar/search.vue';
|
|||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
import useUserStore from '@/store/modules/user';
|
import useUserStore from '@/store/modules/user';
|
||||||
import useSettingsStore from '@/store/modules/settings';
|
import useSettingsStore from '@/store/modules/settings';
|
||||||
import { getTenantList } from "@/api/login";
|
import { getTenantList } from '@/api/login';
|
||||||
import { dynamicClear, dynamicTenant } from "@/api/system/tenant";
|
import { dynamicClear, dynamicTenant } from '@/api/system/tenant';
|
||||||
import { ComponentInternalInstance } from "vue";
|
import { TenantVO } from '@/api/types';
|
||||||
import { TenantVO } from "@/api/types";
|
|
||||||
import notice from './notice/index.vue';
|
import notice from './notice/index.vue';
|
||||||
import useNoticeStore from '@/store/modules/notice';
|
import useNoticeStore from '@/store/modules/notice';
|
||||||
|
|
||||||
@ -119,7 +118,7 @@ const searchMenuRef = ref<InstanceType<typeof SearchMenu>>();
|
|||||||
|
|
||||||
const openSearchMenu = () => {
|
const openSearchMenu = () => {
|
||||||
searchMenuRef.value?.openSearch();
|
searchMenuRef.value?.openSearch();
|
||||||
}
|
};
|
||||||
|
|
||||||
// 动态切换
|
// 动态切换
|
||||||
const dynamicTenantEvent = async (tenantId: string) => {
|
const dynamicTenantEvent = async (tenantId: string) => {
|
||||||
@ -129,14 +128,14 @@ const dynamicTenantEvent = async (tenantId: string) => {
|
|||||||
proxy?.$tab.closeAllPage();
|
proxy?.$tab.closeAllPage();
|
||||||
proxy?.$router.push('/');
|
proxy?.$router.push('/');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const dynamicClearEvent = async () => {
|
const dynamicClearEvent = async () => {
|
||||||
await dynamicClear();
|
await dynamicClear();
|
||||||
dynamic.value = false;
|
dynamic.value = false;
|
||||||
proxy?.$tab.closeAllPage();
|
proxy?.$tab.closeAllPage();
|
||||||
proxy?.$router.push('/');
|
proxy?.$router.push('/');
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 租户列表 */
|
/** 租户列表 */
|
||||||
const initTenantList = async () => {
|
const initTenantList = async () => {
|
||||||
@ -145,56 +144,58 @@ const initTenantList = async () => {
|
|||||||
if (tenantEnabled.value) {
|
if (tenantEnabled.value) {
|
||||||
tenantList.value = data.voList;
|
tenantList.value = data.voList;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
initTenantList,
|
initTenantList
|
||||||
})
|
});
|
||||||
|
|
||||||
const toggleSideBar = () => {
|
const toggleSideBar = () => {
|
||||||
appStore.toggleSideBar(false);
|
appStore.toggleSideBar(false);
|
||||||
}
|
};
|
||||||
|
|
||||||
const logout = async () => {
|
const logout = async () => {
|
||||||
await ElMessageBox.confirm('确定注销并退出系统吗?', '提示', {
|
await ElMessageBox.confirm('确定注销并退出系统吗?', '提示', {
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
type: 'warning'
|
type: 'warning'
|
||||||
})
|
});
|
||||||
await userStore.logout()
|
await userStore.logout();
|
||||||
location.href = import.meta.env.VITE_APP_CONTEXT_PATH + 'index';
|
location.href = import.meta.env.VITE_APP_CONTEXT_PATH + 'index';
|
||||||
}
|
};
|
||||||
|
|
||||||
const emits = defineEmits(['setLayout'])
|
const emits = defineEmits(['setLayout']);
|
||||||
const setLayout = () => {
|
const setLayout = () => {
|
||||||
emits('setLayout');
|
emits('setLayout');
|
||||||
}
|
};
|
||||||
// 定义Command方法对象 通过key直接调用方法
|
// 定义Command方法对象 通过key直接调用方法
|
||||||
const commandMap: {[key: string]: any} = {
|
const commandMap: { [key: string]: any } = {
|
||||||
setLayout,
|
setLayout,
|
||||||
logout
|
logout
|
||||||
};
|
};
|
||||||
const handleCommand = (command: string) => {
|
const handleCommand = (command: string) => {
|
||||||
// 判断是否存在该方法
|
// 判断是否存在该方法
|
||||||
if (commandMap[command]) {
|
if (commandMap[command]) {
|
||||||
commandMap[command]();
|
commandMap[command]();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
//用深度监听 消息
|
//用深度监听 消息
|
||||||
watch(() => noticeStore.state.value.notices, (newVal, oldVal) => {
|
watch(
|
||||||
newNotice.value = newVal.filter((item: any) => !item.read).length;
|
() => noticeStore.state.value.notices,
|
||||||
}, { deep: true });
|
(newVal) => {
|
||||||
|
newNotice.value = newVal.filter((item: any) => !item.read).length;
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
:deep(.el-select .el-input__wrapper) {
|
:deep(.el-select .el-input__wrapper) {
|
||||||
height:30px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-badge__content.is-fixed){
|
:deep(.el-badge__content.is-fixed) {
|
||||||
top: 12px;
|
top: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex {
|
.flex {
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-drawer v-model="showSettings" :withHeader="false" direction="rtl" size="300px" close-on-click-modal>
|
<el-drawer v-model="showSettings" :with-header="false" direction="rtl" size="300px" close-on-click-modal>
|
||||||
<h3 class="drawer-title">主题风格设置</h3>
|
<h3 class="drawer-title">主题风格设置</h3>
|
||||||
|
|
||||||
<div class="setting-drawer-block-checbox">
|
<div class="setting-drawer-block-checbox">
|
||||||
<div class="setting-drawer-block-checbox-item" @click="handleTheme(SideThemeEnum.DARK)">
|
<div class="setting-drawer-block-checbox-item" @click="handleTheme(SideThemeEnum.DARK)">
|
||||||
<img src="@/assets/images/dark.svg" alt="dark" />
|
<img src="@/assets/images/dark.svg" alt="dark" />
|
||||||
<div v-if="sideTheme === 'theme-dark'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
|
<div v-if="sideTheme === 'theme-dark'" class="setting-drawer-block-checbox-selectIcon" style="display: block">
|
||||||
<i aria-label="图标: check" class="anticon anticon-check">
|
<i aria-label="图标: check" class="anticon anticon-check">
|
||||||
<svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true" focusable="false" class>
|
<svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true" focusable="false" class>
|
||||||
<path
|
<path
|
||||||
@ -17,7 +17,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="setting-drawer-block-checbox-item" @click="handleTheme(SideThemeEnum.LIGHT)">
|
<div class="setting-drawer-block-checbox-item" @click="handleTheme(SideThemeEnum.LIGHT)">
|
||||||
<img src="@/assets/images/light.svg" alt="light" />
|
<img src="@/assets/images/light.svg" alt="light" />
|
||||||
<div v-if="sideTheme === 'theme-light'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
|
<div v-if="sideTheme === 'theme-light'" class="setting-drawer-block-checbox-selectIcon" style="display: block">
|
||||||
<i aria-label="图标: check" class="anticon anticon-check">
|
<i aria-label="图标: check" class="anticon anticon-check">
|
||||||
<svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true" focusable="false" class>
|
<svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true" focusable="false" class>
|
||||||
<path
|
<path
|
||||||
@ -37,7 +37,7 @@
|
|||||||
<div class="drawer-item">
|
<div class="drawer-item">
|
||||||
<span>深色模式</span>
|
<span>深色模式</span>
|
||||||
<span class="comp-style">
|
<span class="comp-style">
|
||||||
<el-switch v-model="isDark" @change="toggleDark" class="drawer-switch" />
|
<el-switch v-model="isDark" class="drawer-switch" @change="toggleDark" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -88,126 +88,126 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useDynamicTitle } from '@/utils/dynamicTitle'
|
import { useDynamicTitle } from '@/utils/dynamicTitle';
|
||||||
import useAppStore from '@/store/modules/app'
|
import useAppStore from '@/store/modules/app';
|
||||||
import useSettingsStore from '@/store/modules/settings'
|
import useSettingsStore from '@/store/modules/settings';
|
||||||
import usePermissionStore from '@/store/modules/permission'
|
import usePermissionStore from '@/store/modules/permission';
|
||||||
import { handleThemeStyle } from '@/utils/theme'
|
import { handleThemeStyle } from '@/utils/theme';
|
||||||
import { ComponentInternalInstance } from "vue";
|
import { SettingTypeEnum } from '@/enums/SettingTypeEnum';
|
||||||
import { SettingTypeEnum } from "@/enums/SettingTypeEnum";
|
import { SideThemeEnum } from '@/enums/SideThemeEnum';
|
||||||
import { SideThemeEnum } from "@/enums/SideThemeEnum";
|
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore();
|
||||||
const settingsStore = useSettingsStore()
|
const settingsStore = useSettingsStore();
|
||||||
const permissionStore = usePermissionStore()
|
const permissionStore = usePermissionStore();
|
||||||
|
|
||||||
|
|
||||||
const showSettings = ref(false);
|
const showSettings = ref(false);
|
||||||
const theme = ref(settingsStore.theme);
|
const theme = ref(settingsStore.theme);
|
||||||
const sideTheme = ref(settingsStore.sideTheme);
|
const sideTheme = ref(settingsStore.sideTheme);
|
||||||
const storeSettings = computed(() => settingsStore);
|
const storeSettings = computed(() => settingsStore);
|
||||||
const predefineColors = ref(["#409EFF", "#ff4500", "#ff8c00", "#ffd700", "#90ee90", "#00ced1", "#1e90ff", "#c71585"]);
|
const predefineColors = ref(['#409EFF', '#ff4500', '#ff8c00', '#ffd700', '#90ee90', '#00ced1', '#1e90ff', '#c71585']);
|
||||||
|
|
||||||
// 是否暗黑模式
|
// 是否暗黑模式
|
||||||
const isDark = useDark({
|
const isDark = useDark({
|
||||||
storageKey: 'useDarkKey',
|
storageKey: 'useDarkKey',
|
||||||
valueDark: 'dark',
|
valueDark: 'dark',
|
||||||
valueLight: 'light',
|
valueLight: 'light'
|
||||||
});
|
});
|
||||||
watch(isDark, ()=> {
|
watch(isDark, () => {
|
||||||
if (isDark.value) {
|
if (isDark.value) {
|
||||||
settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: SideThemeEnum.DARK })
|
settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: SideThemeEnum.DARK });
|
||||||
} else {
|
} else {
|
||||||
settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: sideTheme.value })
|
settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: sideTheme.value });
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
const toggleDark = () => useToggle(isDark);
|
const toggleDark = () => useToggle(isDark);
|
||||||
|
|
||||||
/** 是否需要topNav */
|
/** 是否需要topNav */
|
||||||
const topNav = computed({
|
const topNav = computed({
|
||||||
get: () => storeSettings.value.topNav,
|
get: () => storeSettings.value.topNav,
|
||||||
set: (val) => {
|
set: (val) => {
|
||||||
settingsStore.changeSetting({ key: SettingTypeEnum.TOP_NAV, value: val })
|
settingsStore.changeSetting({ key: SettingTypeEnum.TOP_NAV, value: val });
|
||||||
if (!val) {
|
if (!val) {
|
||||||
appStore.toggleSideBarHide(false);
|
appStore.toggleSideBarHide(false);
|
||||||
permissionStore.setSidebarRouters(permissionStore.defaultRoutes);
|
permissionStore.setSidebarRouters(permissionStore.defaultRoutes);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
});
|
||||||
/** 是否需要tagview */
|
/** 是否需要tagview */
|
||||||
const tagsView = computed({
|
const tagsView = computed({
|
||||||
get: () => storeSettings.value.tagsView,
|
get: () => storeSettings.value.tagsView,
|
||||||
set: (val) => {
|
set: (val) => {
|
||||||
settingsStore.changeSetting({ key: SettingTypeEnum.TAGS_VIEW, value: val })
|
settingsStore.changeSetting({ key: SettingTypeEnum.TAGS_VIEW, value: val });
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
/**是否需要固定头部 */
|
/**是否需要固定头部 */
|
||||||
const fixedHeader = computed({
|
const fixedHeader = computed({
|
||||||
get: () => storeSettings.value.fixedHeader,
|
get: () => storeSettings.value.fixedHeader,
|
||||||
set: (val) => {
|
set: (val) => {
|
||||||
settingsStore.changeSetting({ key: SettingTypeEnum.FIXED_HEADER, value: val })
|
settingsStore.changeSetting({ key: SettingTypeEnum.FIXED_HEADER, value: val });
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
/**是否需要侧边栏的logo */
|
/**是否需要侧边栏的logo */
|
||||||
const sidebarLogo = computed({
|
const sidebarLogo = computed({
|
||||||
get: () => storeSettings.value.sidebarLogo,
|
get: () => storeSettings.value.sidebarLogo,
|
||||||
set: (val) => {
|
set: (val) => {
|
||||||
settingsStore.changeSetting({ key: SettingTypeEnum.SIDEBAR_LOGO, value: val })
|
settingsStore.changeSetting({ key: SettingTypeEnum.SIDEBAR_LOGO, value: val });
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
/**是否需要侧边栏的动态网页的title */
|
/**是否需要侧边栏的动态网页的title */
|
||||||
const dynamicTitle = computed({
|
const dynamicTitle = computed({
|
||||||
get: () => storeSettings.value.dynamicTitle,
|
get: () => storeSettings.value.dynamicTitle,
|
||||||
set: (val) => {
|
set: (val) => {
|
||||||
settingsStore.changeSetting({ key: SettingTypeEnum.DYNAMIC_TITLE, value: val })
|
settingsStore.changeSetting({ key: SettingTypeEnum.DYNAMIC_TITLE, value: val });
|
||||||
// 动态设置网页标题
|
// 动态设置网页标题
|
||||||
useDynamicTitle()
|
useDynamicTitle();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const themeChange = (val: string | null) => {
|
const themeChange = (val: string) => {
|
||||||
settingsStore.changeSetting({ key: SettingTypeEnum.THEME, value: val })
|
settingsStore.changeSetting({ key: SettingTypeEnum.THEME, value: val });
|
||||||
theme.value = val;
|
theme.value = val;
|
||||||
if (val) {
|
if (val) {
|
||||||
handleThemeStyle(val);
|
handleThemeStyle(val);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
const handleTheme = (val: string) => {
|
const handleTheme = (val: string) => {
|
||||||
sideTheme.value = val;
|
sideTheme.value = val;
|
||||||
if (isDark.value && val === SideThemeEnum.LIGHT) {
|
if (isDark.value && val === SideThemeEnum.LIGHT) {
|
||||||
// 暗黑模式颜色不变
|
// 暗黑模式颜色不变
|
||||||
settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: SideThemeEnum.DARK })
|
settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: SideThemeEnum.DARK });
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: val })
|
settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: val });
|
||||||
}
|
};
|
||||||
const saveSetting = () => {
|
const saveSetting = () => {
|
||||||
proxy?.$modal.loading("正在保存到本地,请稍候...");
|
proxy?.$modal.loading('正在保存到本地,请稍候...');
|
||||||
let layoutSetting = {
|
let layoutSetting = {
|
||||||
"topNav": storeSettings.value.topNav,
|
topNav: storeSettings.value.topNav,
|
||||||
"tagsView": storeSettings.value.tagsView,
|
tagsView: storeSettings.value.tagsView,
|
||||||
"fixedHeader": storeSettings.value.fixedHeader,
|
fixedHeader: storeSettings.value.fixedHeader,
|
||||||
"sidebarLogo": storeSettings.value.sidebarLogo,
|
sidebarLogo: storeSettings.value.sidebarLogo,
|
||||||
"dynamicTitle": storeSettings.value.dynamicTitle,
|
dynamicTitle: storeSettings.value.dynamicTitle,
|
||||||
"sideTheme": storeSettings.value.sideTheme,
|
sideTheme: storeSettings.value.sideTheme,
|
||||||
"theme": storeSettings.value.theme
|
theme: storeSettings.value.theme
|
||||||
};
|
};
|
||||||
localStorage.setItem("layout-setting", JSON.stringify(layoutSetting));
|
localStorage.setItem('layout-setting', JSON.stringify(layoutSetting));
|
||||||
setTimeout(() => {proxy?.$modal.closeLoading()}, 1000)
|
setTimeout(() => {
|
||||||
}
|
proxy?.$modal.closeLoading();
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
const resetSetting = () => {
|
const resetSetting = () => {
|
||||||
proxy?.$modal.loading("正在清除设置缓存并刷新,请稍候...");
|
proxy?.$modal.loading('正在清除设置缓存并刷新,请稍候...');
|
||||||
localStorage.removeItem("layout-setting")
|
localStorage.removeItem('layout-setting');
|
||||||
setTimeout("window.location.reload()", 1000)
|
setTimeout('window.location.reload()', 1000);
|
||||||
}
|
};
|
||||||
const openSetting = () => {
|
const openSetting = () => {
|
||||||
showSettings.value = true;
|
showSettings.value = true;
|
||||||
}
|
};
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
openSetting,
|
openSetting
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@ -5,36 +5,36 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { isExternal } from '@/utils/validate'
|
import { isExternal } from '@/utils/validate';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
to: {
|
to: {
|
||||||
type: [String, Object],
|
type: [String, Object],
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const isExt = computed(() => {
|
const isExt = computed(() => {
|
||||||
return isExternal(props.to as string)
|
return isExternal(props.to as string);
|
||||||
})
|
});
|
||||||
|
|
||||||
const type = computed(() => {
|
const type = computed(() => {
|
||||||
if (isExt.value) {
|
if (isExt.value) {
|
||||||
return 'a'
|
return 'a';
|
||||||
}
|
}
|
||||||
return 'router-link'
|
return 'router-link';
|
||||||
})
|
});
|
||||||
|
|
||||||
function linkProps() {
|
function linkProps() {
|
||||||
if (isExt.value) {
|
if (isExt.value) {
|
||||||
return {
|
|
||||||
href: props.to,
|
|
||||||
target: '_blank',
|
|
||||||
rel: 'noopener'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
to: props.to
|
href: props.to,
|
||||||
}
|
target: '_blank',
|
||||||
|
rel: 'noopener'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
to: props.to
|
||||||
|
};
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="sidebar-logo-container"
|
class="sidebar-logo-container"
|
||||||
:class="{ 'collapse': collapse }"
|
:class="{ collapse: collapse }"
|
||||||
:style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }"
|
:style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }"
|
||||||
>
|
>
|
||||||
<transition :enter-active-class="proxy?.animate.logoAnimate.enter" mode="out-in">
|
<transition :enter-active-class="proxy?.animate.logoAnimate.enter" mode="out-in">
|
||||||
@ -22,18 +22,17 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import variables from '@/assets/styles/variables.module.scss'
|
import variables from '@/assets/styles/variables.module.scss';
|
||||||
import logo from '@/assets/logo/logo.png'
|
import logo from '@/assets/logo/logo.png';
|
||||||
import useSettingsStore from '@/store/modules/settings'
|
import useSettingsStore from '@/store/modules/settings';
|
||||||
import { ComponentInternalInstance } from "vue";
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
collapse: {
|
collapse: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const title = ref('RuoYi-Vue-Plus');
|
const title = ref('RuoYi-Vue-Plus');
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
@ -77,7 +76,12 @@ const sideTheme = computed(() => settingsStore.sideTheme);
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
line-height: 50px;
|
line-height: 50px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
|
font-family:
|
||||||
|
Avenir,
|
||||||
|
Helvetica Neue,
|
||||||
|
Arial,
|
||||||
|
Helvetica,
|
||||||
|
sans-serif;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
<el-sub-menu v-else ref="subMenu" :index="resolvePath(item.path)" teleported>
|
<el-sub-menu v-else ref="subMenu" :index="resolvePath(item.path)" teleported>
|
||||||
<template v-if="item.meta" #title>
|
<template v-if="item.meta" #title>
|
||||||
<svg-icon :icon-class="item.meta ? item.meta.icon : '' " />
|
<svg-icon :icon-class="item.meta ? item.meta.icon : ''" />
|
||||||
<span class="menu-title" :title="hasTitle(item.meta?.title)">{{ item.meta?.title }}</span>
|
<span class="menu-title" :title="hasTitle(item.meta?.title)">{{ item.meta?.title }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -30,79 +30,75 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { isExternal } from '@/utils/validate'
|
import { isExternal } from '@/utils/validate';
|
||||||
import AppLink from './Link.vue'
|
import AppLink from './Link.vue';
|
||||||
import { getNormalPath } from '@/utils/ruoyi'
|
import { getNormalPath } from '@/utils/ruoyi';
|
||||||
import { RouteOption } from "vue-router";
|
import { RouteRecordRaw } from 'vue-router';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
// route object
|
// route object
|
||||||
item: {
|
item: {
|
||||||
type: Object as PropType<RouteOption>,
|
type: Object as PropType<RouteRecordRaw>,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
isNest: {
|
isNest: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
basePath: {
|
basePath: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const onlyOneChild = ref<any>({});
|
const onlyOneChild = ref<any>({});
|
||||||
|
|
||||||
const hasOneShowingChild = (parent: RouteOption, children?:RouteOption[]) => {
|
const hasOneShowingChild = (parent: RouteRecordRaw, children?: RouteRecordRaw[]) => {
|
||||||
if (!children) {
|
if (!children) {
|
||||||
children = [];
|
children = [];
|
||||||
|
}
|
||||||
|
const showingChildren = children.filter((item) => {
|
||||||
|
if (item.hidden) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
// Temp set(will be used if only has one showing child)
|
||||||
|
onlyOneChild.value = item;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
const showingChildren = children.filter(item => {
|
});
|
||||||
if (item.hidden) {
|
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
// Temp set(will be used if only has one showing child)
|
|
||||||
onlyOneChild.value = item
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// When there is only one child router, the child router is displayed by default
|
// When there is only one child router, the child router is displayed by default
|
||||||
if (showingChildren.length === 1) {
|
if (showingChildren.length === 1) {
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show parent if there are no child router to display
|
// Show parent if there are no child router to display
|
||||||
if (showingChildren.length === 0) {
|
if (showingChildren.length === 0) {
|
||||||
onlyOneChild.value = { ...parent, path: '', noShowingChildren: true }
|
onlyOneChild.value = { ...parent, path: '', noShowingChildren: true };
|
||||||
if (parent.name === '2222') {
|
return true;
|
||||||
console.log(onlyOneChild.value)
|
}
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return false;
|
||||||
return false
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const resolvePath = (routePath:string, routeQuery?:string): any => {
|
const resolvePath = (routePath: string, routeQuery?: string): any => {
|
||||||
if (isExternal(routePath)) {
|
if (isExternal(routePath)) {
|
||||||
return routePath
|
return routePath;
|
||||||
}
|
}
|
||||||
if (isExternal(props.basePath)) {
|
if (isExternal(props.basePath)) {
|
||||||
return props.basePath
|
return props.basePath;
|
||||||
}
|
}
|
||||||
if (routeQuery) {
|
if (routeQuery) {
|
||||||
let query = JSON.parse(routeQuery);
|
let query = JSON.parse(routeQuery);
|
||||||
return { path: getNormalPath(props.basePath + '/' + routePath), query: query }
|
return { path: getNormalPath(props.basePath + '/' + routePath), query: query };
|
||||||
}
|
}
|
||||||
return getNormalPath(props.basePath + '/' + routePath)
|
return getNormalPath(props.basePath + '/' + routePath);
|
||||||
}
|
};
|
||||||
|
|
||||||
const hasTitle = (title: string | undefined): string => {
|
const hasTitle = (title: string | undefined): string => {
|
||||||
if(!title || title.length <= 5) {
|
if (!title || title.length <= 5) {
|
||||||
return "";
|
return '';
|
||||||
}
|
}
|
||||||
return title;
|
return title;
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -21,35 +21,34 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Logo from './Logo.vue'
|
import Logo from './Logo.vue';
|
||||||
import SidebarItem from './SidebarItem.vue'
|
import SidebarItem from './SidebarItem.vue';
|
||||||
import variables from '@/assets/styles/variables.module.scss'
|
import variables from '@/assets/styles/variables.module.scss';
|
||||||
import useAppStore from '@/store/modules/app'
|
import useAppStore from '@/store/modules/app';
|
||||||
import useSettingsStore from '@/store/modules/settings'
|
import useSettingsStore from '@/store/modules/settings';
|
||||||
import usePermissionStore from '@/store/modules/permission'
|
import usePermissionStore from '@/store/modules/permission';
|
||||||
import { RouteOption } from "vue-router";
|
import { RouteRecordRaw } from 'vue-router';
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore();
|
||||||
const settingsStore = useSettingsStore()
|
const settingsStore = useSettingsStore();
|
||||||
const permissionStore = usePermissionStore()
|
const permissionStore = usePermissionStore();
|
||||||
|
const sidebarRouters = computed<RouteRecordRaw[]>(() => permissionStore.sidebarRouters);
|
||||||
const sidebarRouters = computed<RouteOption[]>(() => permissionStore.sidebarRouters);
|
|
||||||
const showLogo = computed(() => settingsStore.sidebarLogo);
|
const showLogo = computed(() => settingsStore.sidebarLogo);
|
||||||
const sideTheme = computed(() => settingsStore.sideTheme);
|
const sideTheme = computed(() => settingsStore.sideTheme);
|
||||||
const theme = computed(() => settingsStore.theme);
|
const theme = computed(() => settingsStore.theme);
|
||||||
const isCollapse = computed(() => !appStore.sidebar.opened);
|
const isCollapse = computed(() => !appStore.sidebar.opened);
|
||||||
|
|
||||||
const activeMenu = computed(() => {
|
const activeMenu = computed(() => {
|
||||||
const { meta, path } = route;
|
const { meta, path } = route;
|
||||||
// if set path, the sidebar will highlight the path you set
|
// if set path, the sidebar will highlight the path you set
|
||||||
if (meta.activeMenu) {
|
if (meta.activeMenu) {
|
||||||
return meta.activeMenu;
|
return meta.activeMenu;
|
||||||
}
|
}
|
||||||
return path;
|
return path;
|
||||||
})
|
});
|
||||||
|
|
||||||
const bgColor = computed(() => sideTheme.value === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground);
|
const bgColor = computed(() => (sideTheme.value === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground));
|
||||||
const textColor = computed(() => sideTheme.value === 'theme-dark' ? variables.menuColor : variables.menuLightColor);
|
const textColor = computed(() => (sideTheme.value === 'theme-dark' ? variables.menuColor : variables.menuLightColor));
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -10,7 +10,6 @@ import { LoginData } from '@/api/types';
|
|||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 接收Route传递的参数
|
* 接收Route传递的参数
|
||||||
* @param {Object} route.query.
|
* @param {Object} route.query.
|
||||||
@ -18,8 +17,7 @@ const loading = ref(true);
|
|||||||
const code = route.query.code as string;
|
const code = route.query.code as string;
|
||||||
const state = route.query.state as string;
|
const state = route.query.state as string;
|
||||||
const source = route.query.source as string;
|
const source = route.query.source as string;
|
||||||
const tenantId = localStorage.getItem("tenantId") ? localStorage.getItem("tenantId") as string : '000000';
|
const tenantId = localStorage.getItem('tenantId') ? (localStorage.getItem('tenantId') as string) : '000000';
|
||||||
|
|
||||||
|
|
||||||
const processResponse = async (res: any) => {
|
const processResponse = async (res: any) => {
|
||||||
if (res.code !== 200) {
|
if (res.code !== 200) {
|
||||||
@ -52,7 +50,6 @@ const callbackByCode = async (data: LoginData) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const loginByCode = async (data: LoginData) => {
|
const loginByCode = async (data: LoginData) => {
|
||||||
console.log(2)
|
|
||||||
try {
|
try {
|
||||||
const res = await login(data);
|
const res = await login(data);
|
||||||
await processResponse(res);
|
await processResponse(res);
|
||||||
|
|||||||
@ -5,84 +5,84 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import useTagsViewStore from '@/store/modules/tagsView'
|
import useTagsViewStore from '@/store/modules/tagsView';
|
||||||
import { TagView } from 'vue-router'
|
import { TagView } from 'vue-router';
|
||||||
const tagAndTagSpacing = ref(4);
|
const tagAndTagSpacing = ref(4);
|
||||||
|
|
||||||
const scrollContainerRef = ref<ElScrollbarInstance>()
|
const scrollContainerRef = ref<ElScrollbarInstance>();
|
||||||
const scrollWrapper = computed(() => scrollContainerRef.value?.$refs.wrapRef as any);
|
const scrollWrapper = computed(() => scrollContainerRef.value?.$refs.wrapRef as any);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
scrollWrapper.value?.addEventListener('scroll', emitScroll, true)
|
scrollWrapper.value?.addEventListener('scroll', emitScroll, true);
|
||||||
})
|
});
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
scrollWrapper.value?.removeEventListener('scroll', emitScroll)
|
scrollWrapper.value?.removeEventListener('scroll', emitScroll);
|
||||||
})
|
});
|
||||||
|
|
||||||
const handleScroll = (e: WheelEvent) => {
|
const handleScroll = (e: WheelEvent) => {
|
||||||
const eventDelta = (e as any).wheelDelta || - e.deltaY * 40
|
const eventDelta = (e as any).wheelDelta || -e.deltaY * 40;
|
||||||
const $scrollWrapper = scrollWrapper.value;
|
const $scrollWrapper = scrollWrapper.value;
|
||||||
$scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
|
$scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4;
|
||||||
}
|
};
|
||||||
const emits = defineEmits(['scroll'])
|
const emits = defineEmits(['scroll']);
|
||||||
const emitScroll = () => {
|
const emitScroll = () => {
|
||||||
emits('scroll')
|
emits('scroll');
|
||||||
}
|
};
|
||||||
|
|
||||||
const tagsViewStore = useTagsViewStore()
|
const tagsViewStore = useTagsViewStore();
|
||||||
const visitedViews = computed(() => tagsViewStore.visitedViews);
|
const visitedViews = computed(() => tagsViewStore.visitedViews);
|
||||||
|
|
||||||
const moveToTarget = (currentTag: TagView) => {
|
const moveToTarget = (currentTag: TagView) => {
|
||||||
const $container = scrollContainerRef.value?.$el
|
const $container = scrollContainerRef.value?.$el;
|
||||||
const $containerWidth = $container.offsetWidth
|
const $containerWidth = $container.offsetWidth;
|
||||||
const $scrollWrapper = scrollWrapper.value;
|
const $scrollWrapper = scrollWrapper.value;
|
||||||
|
|
||||||
let firstTag = null
|
let firstTag = null;
|
||||||
let lastTag = null
|
let lastTag = null;
|
||||||
|
|
||||||
// find first tag and last tag
|
// find first tag and last tag
|
||||||
if (visitedViews.value.length > 0) {
|
if (visitedViews.value.length > 0) {
|
||||||
firstTag = visitedViews.value[0]
|
firstTag = visitedViews.value[0];
|
||||||
lastTag = visitedViews.value[visitedViews.value.length - 1]
|
lastTag = visitedViews.value[visitedViews.value.length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstTag === currentTag) {
|
||||||
|
$scrollWrapper.scrollLeft = 0;
|
||||||
|
} else if (lastTag === currentTag) {
|
||||||
|
$scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth;
|
||||||
|
} else {
|
||||||
|
const tagListDom: any = document.getElementsByClassName('tags-view-item');
|
||||||
|
const currentIndex = visitedViews.value.findIndex((item) => item === currentTag);
|
||||||
|
let prevTag = null;
|
||||||
|
let nextTag = null;
|
||||||
|
|
||||||
|
for (const k in tagListDom) {
|
||||||
|
if (k !== 'length' && Object.hasOwnProperty.call(tagListDom, k)) {
|
||||||
|
if (tagListDom[k].dataset.path === visitedViews.value[currentIndex - 1].path) {
|
||||||
|
prevTag = tagListDom[k];
|
||||||
|
}
|
||||||
|
if (tagListDom[k].dataset.path === visitedViews.value[currentIndex + 1].path) {
|
||||||
|
nextTag = tagListDom[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (firstTag === currentTag) {
|
// the tag's offsetLeft after of nextTag
|
||||||
$scrollWrapper.scrollLeft = 0
|
const afterNextTagOffsetLeft = nextTag.offsetLeft + nextTag.offsetWidth + tagAndTagSpacing.value;
|
||||||
} else if (lastTag === currentTag) {
|
|
||||||
$scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth
|
|
||||||
} else {
|
|
||||||
const tagListDom: any = document.getElementsByClassName('tags-view-item');
|
|
||||||
const currentIndex = visitedViews.value.findIndex(item => item === currentTag)
|
|
||||||
let prevTag = null
|
|
||||||
let nextTag = null
|
|
||||||
|
|
||||||
for (const k in tagListDom) {
|
// the tag's offsetLeft before of prevTag
|
||||||
if (k !== 'length' && Object.hasOwnProperty.call(tagListDom, k)) {
|
const beforePrevTagOffsetLeft = prevTag.offsetLeft - tagAndTagSpacing.value;
|
||||||
if (tagListDom[k].dataset.path === visitedViews.value[currentIndex - 1].path) {
|
if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) {
|
||||||
prevTag = tagListDom[k];
|
$scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth;
|
||||||
}
|
} else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) {
|
||||||
if (tagListDom[k].dataset.path === visitedViews.value[currentIndex + 1].path) {
|
$scrollWrapper.scrollLeft = beforePrevTagOffsetLeft;
|
||||||
nextTag = tagListDom[k];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// the tag's offsetLeft after of nextTag
|
|
||||||
const afterNextTagOffsetLeft = nextTag.offsetLeft + nextTag.offsetWidth + tagAndTagSpacing.value
|
|
||||||
|
|
||||||
// the tag's offsetLeft before of prevTag
|
|
||||||
const beforePrevTagOffsetLeft = prevTag.offsetLeft - tagAndTagSpacing.value
|
|
||||||
if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) {
|
|
||||||
$scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth
|
|
||||||
} else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) {
|
|
||||||
$scrollWrapper.scrollLeft = beforePrevTagOffsetLeft
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
moveToTarget,
|
moveToTarget
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@ -14,36 +14,35 @@
|
|||||||
>
|
>
|
||||||
{{ tag.title }}
|
{{ tag.title }}
|
||||||
<span v-if="!isAffix(tag)" @click.prevent.stop="closeSelectedTag(tag)">
|
<span v-if="!isAffix(tag)" @click.prevent.stop="closeSelectedTag(tag)">
|
||||||
<close class="el-icon-close" style="width: 1em; height: 1em;vertical-align: middle;" />
|
<close class="el-icon-close" style="width: 1em; height: 1em; vertical-align: middle" />
|
||||||
</span>
|
</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
</scroll-pane>
|
</scroll-pane>
|
||||||
<ul v-show="visible" :style="{ left: left + 'px', top: top + 'px' }" class="contextmenu">
|
<ul v-show="visible" :style="{ left: left + 'px', top: top + 'px' }" class="contextmenu">
|
||||||
<li @click="refreshSelectedTag(selectedTag)"><refresh-right style="width: 1em; height: 1em;" /> 刷新页面</li>
|
<li @click="refreshSelectedTag(selectedTag)"><refresh-right style="width: 1em; height: 1em" /> 刷新页面</li>
|
||||||
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)"><close style="width: 1em; height: 1em;" /> 关闭当前</li>
|
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)"><close style="width: 1em; height: 1em" /> 关闭当前</li>
|
||||||
<li @click="closeOthersTags"><circle-close style="width: 1em; height: 1em;" /> 关闭其他</li>
|
<li @click="closeOthersTags"><circle-close style="width: 1em; height: 1em" /> 关闭其他</li>
|
||||||
<li v-if="!isFirstView()" @click="closeLeftTags"><back style="width: 1em; height: 1em;" /> 关闭左侧</li>
|
<li v-if="!isFirstView()" @click="closeLeftTags"><back style="width: 1em; height: 1em" /> 关闭左侧</li>
|
||||||
<li v-if="!isLastView()" @click="closeRightTags"><right style="width: 1em; height: 1em;" /> 关闭右侧</li>
|
<li v-if="!isLastView()" @click="closeRightTags"><right style="width: 1em; height: 1em" /> 关闭右侧</li>
|
||||||
<li @click="closeAllTags(selectedTag)"><circle-close style="width: 1em; height: 1em;" /> 全部关闭</li>
|
<li @click="closeAllTags(selectedTag)"><circle-close style="width: 1em; height: 1em" /> 全部关闭</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ScrollPane from './ScrollPane.vue'
|
import ScrollPane from './ScrollPane.vue';
|
||||||
import { getNormalPath } from '@/utils/ruoyi'
|
import { getNormalPath } from '@/utils/ruoyi';
|
||||||
import useTagsViewStore from "@/store/modules/tagsView";
|
import useTagsViewStore from '@/store/modules/tagsView';
|
||||||
import useSettingsStore from '@/store/modules/settings'
|
import useSettingsStore from '@/store/modules/settings';
|
||||||
import usePermissionStore from '@/store/modules/permission'
|
import usePermissionStore from '@/store/modules/permission';
|
||||||
import { ComponentInternalInstance } from "vue";
|
import { RouteRecordRaw, TagView } from 'vue-router';
|
||||||
import { RouteOption, TagView, RouteLocationRaw } from "vue-router";
|
|
||||||
|
|
||||||
const visible = ref(false);
|
const visible = ref(false);
|
||||||
const top = ref(0);
|
const top = ref(0);
|
||||||
const left = ref(0);
|
const left = ref(0);
|
||||||
const selectedTag = ref<TagView>({});
|
const selectedTag = ref<TagView>({});
|
||||||
const affixTags = ref<TagView[]>([]);
|
const affixTags = ref<TagView[]>([]);
|
||||||
const scrollPaneRef = ref(ScrollPane);
|
const scrollPaneRef = ref<InstanceType<typeof ScrollPane>>();
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
@ -54,186 +53,186 @@ const routes = computed(() => usePermissionStore().routes);
|
|||||||
const theme = computed(() => useSettingsStore().theme);
|
const theme = computed(() => useSettingsStore().theme);
|
||||||
|
|
||||||
watch(route, () => {
|
watch(route, () => {
|
||||||
addTags();
|
addTags();
|
||||||
moveToCurrentTag();
|
moveToCurrentTag();
|
||||||
})
|
});
|
||||||
watch(visible, (value) => {
|
watch(visible, (value) => {
|
||||||
if (value) {
|
if (value) {
|
||||||
document.body.addEventListener('click', closeMenu);
|
document.body.addEventListener('click', closeMenu);
|
||||||
} else {
|
} else {
|
||||||
document.body.removeEventListener('click', closeMenu);
|
document.body.removeEventListener('click', closeMenu);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const isActive = (r: TagView): boolean => {
|
const isActive = (r: TagView): boolean => {
|
||||||
return r.path === route.path;
|
return r.path === route.path;
|
||||||
}
|
};
|
||||||
const activeStyle = (tag: TagView) => {
|
const activeStyle = (tag: TagView) => {
|
||||||
if (!isActive(tag)) return {};
|
if (!isActive(tag)) return {};
|
||||||
return {
|
return {
|
||||||
"background-color": theme.value,
|
'background-color': theme.value,
|
||||||
"border-color": theme.value
|
'border-color': theme.value
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
const isAffix = (tag: TagView) => {
|
const isAffix = (tag: TagView) => {
|
||||||
return tag.meta && tag.meta.affix;
|
return tag.meta && tag.meta.affix;
|
||||||
}
|
};
|
||||||
const isFirstView = () => {
|
const isFirstView = () => {
|
||||||
try {
|
try {
|
||||||
return selectedTag.value.fullPath === '/index' || selectedTag.value.fullPath === visitedViews.value[1].fullPath;
|
return selectedTag.value.fullPath === '/index' || selectedTag.value.fullPath === visitedViews.value[1].fullPath;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
const isLastView = () => {
|
const isLastView = () => {
|
||||||
try {
|
try {
|
||||||
return selectedTag.value.fullPath === visitedViews.value[visitedViews.value.length - 1].fullPath;
|
return selectedTag.value.fullPath === visitedViews.value[visitedViews.value.length - 1].fullPath;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const filterAffixTags = (routes: RouteRecordRaw[], basePath = '') => {
|
||||||
|
let tags: TagView[] = [];
|
||||||
|
|
||||||
|
routes.forEach((route) => {
|
||||||
|
if (route.meta && route.meta.affix) {
|
||||||
|
const tagPath = getNormalPath(basePath + '/' + route.path);
|
||||||
|
tags.push({
|
||||||
|
fullPath: tagPath,
|
||||||
|
path: tagPath,
|
||||||
|
name: route.name as string,
|
||||||
|
meta: { ...route.meta }
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
if (route.children) {
|
||||||
const filterAffixTags = (routes:RouteOption [], basePath = '') => {
|
const tempTags = filterAffixTags(route.children, route.path);
|
||||||
let tags:TagView[] = []
|
if (tempTags.length >= 1) {
|
||||||
routes.forEach(route => {
|
tags = [...tags, ...tempTags];
|
||||||
if (route.meta && route.meta.affix) {
|
}
|
||||||
const tagPath = getNormalPath(basePath + '/' + route.path);
|
}
|
||||||
tags.push({
|
});
|
||||||
fullPath: tagPath,
|
return tags;
|
||||||
path: tagPath,
|
};
|
||||||
name: route.name,
|
|
||||||
meta: { ...route.meta }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (route.children) {
|
|
||||||
const tempTags = filterAffixTags(route.children, route.path);
|
|
||||||
if (tempTags.length >= 1) {
|
|
||||||
tags = [...tags, ...tempTags];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return tags
|
|
||||||
}
|
|
||||||
const initTags = () => {
|
const initTags = () => {
|
||||||
const res = filterAffixTags(routes.value);
|
const res = filterAffixTags(routes.value as any);
|
||||||
affixTags.value = res;
|
affixTags.value = res;
|
||||||
for (const tag of res) {
|
for (const tag of res) {
|
||||||
// Must have tag name
|
// Must have tag name
|
||||||
if (tag.name) {
|
if (tag.name) {
|
||||||
useTagsViewStore().addVisitedView(tag);
|
useTagsViewStore().addVisitedView(tag);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
const addTags = () => {
|
const addTags = () => {
|
||||||
const { name } = route;
|
const { name } = route;
|
||||||
if(route.query.title) {
|
if (route.query.title) {
|
||||||
route.meta.title = route.query.title;
|
route.meta.title = route.query.title as string;
|
||||||
}
|
}
|
||||||
if (name) {
|
if (name) {
|
||||||
useTagsViewStore().addView(route);
|
useTagsViewStore().addView(route as any);
|
||||||
if (route.meta.link) {
|
|
||||||
useTagsViewStore().addIframeView(route);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
const moveToCurrentTag = () => {
|
|
||||||
nextTick(() => {
|
|
||||||
for (const r of visitedViews.value) {
|
|
||||||
if (r.path === route.path) {
|
|
||||||
scrollPaneRef.value.moveToTarget(r);
|
|
||||||
// when query is different then update
|
|
||||||
if (r.fullPath !== route.fullPath) {
|
|
||||||
useTagsViewStore().updateVisitedView(route);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const refreshSelectedTag = (view: TagView) => {
|
|
||||||
proxy?.$tab.refreshPage(view);
|
|
||||||
if (route.meta.link) {
|
if (route.meta.link) {
|
||||||
useTagsViewStore().delIframeView(route);
|
useTagsViewStore().addIframeView(route as any);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
const moveToCurrentTag = () => {
|
||||||
|
nextTick(() => {
|
||||||
|
for (const r of visitedViews.value) {
|
||||||
|
if (r.path === route.path) {
|
||||||
|
scrollPaneRef.value?.moveToTarget(r);
|
||||||
|
// when query is different then update
|
||||||
|
if (r.fullPath !== route.fullPath) {
|
||||||
|
useTagsViewStore().updateVisitedView(route);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const refreshSelectedTag = (view: TagView) => {
|
||||||
|
proxy?.$tab.refreshPage(view);
|
||||||
|
if (route.meta.link) {
|
||||||
|
useTagsViewStore().delIframeView(route as any);
|
||||||
|
}
|
||||||
|
};
|
||||||
const closeSelectedTag = (view: TagView) => {
|
const closeSelectedTag = (view: TagView) => {
|
||||||
proxy?.$tab.closePage(view).then(({ visitedViews }: any) => {
|
proxy?.$tab.closePage(view).then(({ visitedViews }: any) => {
|
||||||
if (isActive(view)) {
|
if (isActive(view)) {
|
||||||
toLastView(visitedViews, view);
|
toLastView(visitedViews, view);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
const closeRightTags = () => {
|
const closeRightTags = () => {
|
||||||
proxy?.$tab.closeRightPage(selectedTag.value).then(visitedViews => {
|
proxy?.$tab.closeRightPage(selectedTag.value).then((visitedViews) => {
|
||||||
if (!visitedViews.find(i => i.fullPath === route.fullPath)) {
|
if (!visitedViews.find((i) => i.fullPath === route.fullPath)) {
|
||||||
toLastView(visitedViews);
|
toLastView(visitedViews);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
const closeLeftTags = () => {
|
const closeLeftTags = () => {
|
||||||
proxy?.$tab.closeLeftPage(selectedTag.value).then(visitedViews => {
|
proxy?.$tab.closeLeftPage(selectedTag.value).then((visitedViews) => {
|
||||||
if (!visitedViews.find(i => i.fullPath === route.fullPath)) {
|
if (!visitedViews.find((i: TagView) => i.fullPath === route.fullPath)) {
|
||||||
toLastView(visitedViews);
|
toLastView(visitedViews);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
const closeOthersTags = () => {
|
const closeOthersTags = () => {
|
||||||
router.push(selectedTag.value as RouteLocationRaw).catch(() => { });
|
router.push(selectedTag.value).catch(() => {});
|
||||||
proxy?.$tab.closeOtherPage(selectedTag.value).then(() => {
|
proxy?.$tab.closeOtherPage(selectedTag.value).then(() => {
|
||||||
moveToCurrentTag();
|
moveToCurrentTag();
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
const closeAllTags = (view: TagView) => {
|
const closeAllTags = (view: TagView) => {
|
||||||
proxy?.$tab.closeAllPage().then(({ visitedViews }) => {
|
proxy?.$tab.closeAllPage().then(({ visitedViews }) => {
|
||||||
if (affixTags.value.some(tag => tag.path === route.path)) {
|
if (affixTags.value.some((tag) => tag.path === route.path)) {
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
toLastView(visitedViews, view);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const toLastView = (visitedViews:TagView[], view?: TagView) => {
|
|
||||||
const latestView = visitedViews.slice(-1)[0];
|
|
||||||
if (latestView) {
|
|
||||||
router.push(latestView.fullPath as string);
|
|
||||||
} else {
|
|
||||||
// now the default is to redirect to the home page if there is no tags-view,
|
|
||||||
// you can adjust it according to your needs.
|
|
||||||
if (view?.name === 'Dashboard') {
|
|
||||||
// to reload home page
|
|
||||||
router.replace({ path: '/redirect' + view?.fullPath });
|
|
||||||
} else {
|
|
||||||
router.push('/');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
toLastView(visitedViews, view);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const toLastView = (visitedViews: TagView[], view?: TagView) => {
|
||||||
|
const latestView = visitedViews.slice(-1)[0];
|
||||||
|
if (latestView) {
|
||||||
|
router.push(latestView.fullPath as string);
|
||||||
|
} else {
|
||||||
|
// now the default is to redirect to the home page if there is no tags-view,
|
||||||
|
// you can adjust it according to your needs.
|
||||||
|
if (view?.name === 'Dashboard') {
|
||||||
|
// to reload home page
|
||||||
|
router.replace({ path: '/redirect' + view?.fullPath });
|
||||||
|
} else {
|
||||||
|
router.push('/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
const openMenu = (tag: TagView, e: MouseEvent) => {
|
const openMenu = (tag: TagView, e: MouseEvent) => {
|
||||||
const menuMinWidth = 105;
|
const menuMinWidth = 105;
|
||||||
const offsetLeft = proxy?.$el.getBoundingClientRect().left; // container margin left
|
const offsetLeft = proxy?.$el.getBoundingClientRect().left; // container margin left
|
||||||
const offsetWidth = proxy?.$el.offsetWidth; // container width
|
const offsetWidth = proxy?.$el.offsetWidth; // container width
|
||||||
const maxLeft = offsetWidth - menuMinWidth; // left boundary
|
const maxLeft = offsetWidth - menuMinWidth; // left boundary
|
||||||
const l = e.clientX - offsetLeft + 15; // 15: margin right
|
const l = e.clientX - offsetLeft + 15; // 15: margin right
|
||||||
|
|
||||||
if (l > maxLeft) {
|
if (l > maxLeft) {
|
||||||
left.value = maxLeft;
|
left.value = maxLeft;
|
||||||
} else {
|
} else {
|
||||||
left.value = l;
|
left.value = l;
|
||||||
}
|
}
|
||||||
|
|
||||||
top.value = e.clientY
|
top.value = e.clientY;
|
||||||
visible.value = true;
|
visible.value = true;
|
||||||
selectedTag.value = tag;
|
selectedTag.value = tag;
|
||||||
}
|
};
|
||||||
const closeMenu = () => {
|
const closeMenu = () => {
|
||||||
visible.value = false;
|
visible.value = false;
|
||||||
}
|
};
|
||||||
const handleScroll = () => {
|
const handleScroll = () => {
|
||||||
closeMenu();
|
closeMenu();
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initTags();
|
initTags();
|
||||||
addTags();
|
addTags();
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@ -242,7 +241,9 @@ onMounted(() => {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: var(--el-bg-color);
|
background-color: var(--el-bg-color);
|
||||||
border: 1px solid var(--el-border-color-light);
|
border: 1px solid var(--el-border-color-light);
|
||||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04);
|
box-shadow:
|
||||||
|
0 1px 3px 0 rgba(0, 0, 0, 0.12),
|
||||||
|
0 0 3px 0 rgba(0, 0, 0, 0.04);
|
||||||
.tags-view-wrapper {
|
.tags-view-wrapper {
|
||||||
.tags-view-item {
|
.tags-view-item {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@ -271,7 +272,7 @@ onMounted(() => {
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
border-color: #42b983;
|
border-color: #42b983;
|
||||||
&::before {
|
&::before {
|
||||||
content: "";
|
content: '';
|
||||||
background: #fff;
|
background: #fff;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 8px;
|
width: 8px;
|
||||||
|
|||||||
@ -3,12 +3,12 @@
|
|||||||
<el-dialog v-model="state.isShowSearch" destroy-on-close :show-close="false">
|
<el-dialog v-model="state.isShowSearch" destroy-on-close :show-close="false">
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-autocomplete
|
<el-autocomplete
|
||||||
|
ref="layoutMenuAutocompleteRef"
|
||||||
v-model="state.menuQuery"
|
v-model="state.menuQuery"
|
||||||
:fetch-suggestions="menuSearch"
|
:fetch-suggestions="menuSearch"
|
||||||
placeholder="搜索"
|
placeholder="搜索"
|
||||||
ref="layoutMenuAutocompleteRef"
|
|
||||||
@select="onHandleSelect"
|
|
||||||
:fit-input-width="true"
|
:fit-input-width="true"
|
||||||
|
@select="onHandleSelect"
|
||||||
>
|
>
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<svg-icon class-name="search-icon" icon-class="search" />
|
<svg-icon class-name="search-icon" icon-class="search" />
|
||||||
@ -29,130 +29,129 @@
|
|||||||
import { getNormalPath } from '@/utils/ruoyi';
|
import { getNormalPath } from '@/utils/ruoyi';
|
||||||
import { isHttp } from '@/utils/validate';
|
import { isHttp } from '@/utils/validate';
|
||||||
import usePermissionStore from '@/store/modules/permission';
|
import usePermissionStore from '@/store/modules/permission';
|
||||||
import { RouteOption } from 'vue-router';
|
import { RouteRecordRaw } from 'vue-router';
|
||||||
type Router = Array<{
|
type Router = Array<{
|
||||||
path: string;
|
path: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
title: string[];
|
title: string[];
|
||||||
}>
|
}>;
|
||||||
type SearchState<T = any> = {
|
type SearchState<T = any> = {
|
||||||
isShowSearch: boolean;
|
isShowSearch: boolean;
|
||||||
menuQuery: string;
|
menuQuery: string;
|
||||||
menuList: T[];
|
menuList: T[];
|
||||||
};
|
};
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
const layoutMenuAutocompleteRef = ref();
|
const layoutMenuAutocompleteRef = ref();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const routes = computed(() => usePermissionStore().routes);
|
const routes = computed(() => usePermissionStore().routes);
|
||||||
const state = reactive<SearchState>({
|
const state = reactive<SearchState>({
|
||||||
isShowSearch: false,
|
isShowSearch: false,
|
||||||
menuQuery: '',
|
menuQuery: '',
|
||||||
menuList: [],
|
menuList: []
|
||||||
});
|
});
|
||||||
|
|
||||||
// 搜索弹窗打开
|
// 搜索弹窗打开
|
||||||
const openSearch = () => {
|
const openSearch = () => {
|
||||||
state.menuQuery = '';
|
state.menuQuery = '';
|
||||||
state.isShowSearch = true;
|
state.isShowSearch = true;
|
||||||
state.menuList = generateRoutes(routes.value);
|
state.menuList = generateRoutes(routes.value);
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
layoutMenuAutocompleteRef.value.focus();
|
layoutMenuAutocompleteRef.value.focus();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// 搜索弹窗关闭
|
// 搜索弹窗关闭
|
||||||
const closeSearch = () => {
|
const closeSearch = () => {
|
||||||
state.isShowSearch = false;
|
state.isShowSearch = false;
|
||||||
};
|
};
|
||||||
// 菜单搜索数据过滤
|
// 菜单搜索数据过滤
|
||||||
const menuSearch = (queryString: string, cb: Function) => {
|
const menuSearch = (queryString: string, cb: Function) => {
|
||||||
let options = state.menuList.filter((item) => {
|
let options = state.menuList.filter((item) => {
|
||||||
return item.title.indexOf(queryString) > -1;
|
return item.title.indexOf(queryString) > -1;
|
||||||
});
|
});
|
||||||
cb(options);
|
cb(options);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Filter out the routes that can be displayed in the sidebar
|
// Filter out the routes that can be displayed in the sidebar
|
||||||
// And generate the internationalized title
|
// And generate the internationalized title
|
||||||
const generateRoutes = (routes: RouteOption[], basePath = '', prefixTitle: string[] = []) => {
|
const generateRoutes = (routes: RouteRecordRaw[], basePath = '', prefixTitle: string[] = []) => {
|
||||||
let res: Router = []
|
let res: Router = [];
|
||||||
routes.forEach(r => {
|
routes.forEach((r) => {
|
||||||
// skip hidden router
|
// skip hidden router
|
||||||
if (!r.hidden) {
|
if (!r.hidden) {
|
||||||
const p = r.path.length > 0 && r.path[0] === '/' ? r.path : '/' + r.path;
|
const p = r.path.length > 0 && r.path[0] === '/' ? r.path : '/' + r.path;
|
||||||
const data: any = {
|
const data: any = {
|
||||||
path: !isHttp(r.path) ? getNormalPath(basePath + p) : r.path,
|
path: !isHttp(r.path) ? getNormalPath(basePath + p) : r.path,
|
||||||
icon: r.meta?.icon,
|
icon: r.meta?.icon,
|
||||||
title: [...prefixTitle]
|
title: [...prefixTitle]
|
||||||
}
|
};
|
||||||
if (r.meta && r.meta.title) {
|
if (r.meta && r.meta.title) {
|
||||||
data.title = [...data.title, r.meta.title];
|
data.title = [...data.title, r.meta.title];
|
||||||
if (r.redirect !== 'noRedirect') {
|
if (r.redirect !== 'noRedirect') {
|
||||||
// only push the routes with title
|
// only push the routes with title
|
||||||
// special case: need to exclude parent router without redirect
|
// special case: need to exclude parent router without redirect
|
||||||
res.push(data);
|
res.push(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// recursive child routes
|
// recursive child routes
|
||||||
if (r.children) {
|
if (r.children) {
|
||||||
const tempRoutes = generateRoutes(r.children, data.path, data.title);
|
const tempRoutes = generateRoutes(r.children, data.path, data.title);
|
||||||
if (tempRoutes.length >= 1) {
|
if (tempRoutes.length >= 1) {
|
||||||
res = [...res, ...tempRoutes];
|
res = [...res, ...tempRoutes];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
res.forEach((item: any) => {
|
res.forEach((item: any) => {
|
||||||
if (item.title instanceof Array) {
|
if (item.title instanceof Array) {
|
||||||
item.title = item.title.join('/');
|
item.title = item.title.join('/');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return res;
|
return res;
|
||||||
}
|
};
|
||||||
// 当前菜单选中时
|
// 当前菜单选中时
|
||||||
const onHandleSelect = (val: any) => {
|
const onHandleSelect = (val: any) => {
|
||||||
const paths = val.path;
|
const paths = val.path;
|
||||||
if (isHttp(paths)) {
|
if (isHttp(paths)) {
|
||||||
// http(s):// 路径新窗口打开
|
// http(s):// 路径新窗口打开
|
||||||
const pindex = paths.indexOf("http");
|
const pindex = paths.indexOf('http');
|
||||||
window.open(paths.substring(pindex, paths.length), "_blank");
|
window.open(paths.substring(pindex, paths.length), '_blank');
|
||||||
} else {
|
} else {
|
||||||
router.push(paths);
|
router.push(paths);
|
||||||
}
|
}
|
||||||
state.menuQuery = ''
|
state.menuQuery = '';
|
||||||
closeSearch();
|
closeSearch();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 暴露变量
|
// 暴露变量
|
||||||
defineExpose({
|
defineExpose({
|
||||||
openSearch
|
openSearch
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.layout-search-dialog {
|
.layout-search-dialog {
|
||||||
position: relative;
|
position: relative;
|
||||||
:deep(.el-dialog) {
|
:deep(.el-dialog) {
|
||||||
.el-dialog__header,
|
.el-dialog__header,
|
||||||
.el-dialog__body {
|
.el-dialog__body {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.el-dialog__footer {
|
.el-dialog__footer {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
top: -53vh;
|
top: -53vh;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
:deep(.el-autocomplete) {
|
:deep(.el-autocomplete) {
|
||||||
width: 560px;
|
width: 560px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 150px;
|
top: 150px;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-navbars-breadcrumb-user-news" v-loading="state.loading">
|
<div v-loading="state.loading" class="layout-navbars-breadcrumb-user-news">
|
||||||
<div class="head-box">
|
<div class="head-box">
|
||||||
<div class="head-box-title">通知公告</div>
|
<div class="head-box-title">通知公告</div>
|
||||||
<div class="head-box-btn" @click="readAll">全部已读</div>
|
<div class="head-box-btn" @click="readAll">全部已读</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content-box" v-loading="state.loading">
|
<div v-loading="state.loading" class="content-box">
|
||||||
<template v-if="newsList.length > 0">
|
<template v-if="newsList.length > 0">
|
||||||
<div class="content-box-item" v-for="(v, k) in newsList" :key="k" @click="onNewsClick(k)">
|
<div v-for="(v, k) in newsList" :key="k" class="content-box-item" @click="onNewsClick(k)">
|
||||||
<div class="item-conten">
|
<div class="item-conten">
|
||||||
<div>{{ v.message }}</div>
|
<div>{{ v.message }}</div>
|
||||||
<div class="content-box-msg"></div>
|
<div class="content-box-msg"></div>
|
||||||
@ -17,26 +17,24 @@
|
|||||||
<span v-else class="el-tag el-tag--danger el-tag--mini read">未读</span>
|
<span v-else class="el-tag el-tag--danger el-tag--mini read">未读</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<el-empty :description="'消息为空'" v-else></el-empty>
|
<el-empty v-else :description="'消息为空'"></el-empty>
|
||||||
</div>
|
</div>
|
||||||
<div class="foot-box" @click="onGoToGiteeClick" v-if="newsList.length > 0">前往gitee</div>
|
<div v-if="newsList.length > 0" class="foot-box" @click="onGoToGiteeClick">前往gitee</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="layoutBreadcrumbUserNews">
|
<script setup lang="ts" name="layoutBreadcrumbUserNews">
|
||||||
import { ref } from "vue";
|
import { storeToRefs } from 'pinia';
|
||||||
import { storeToRefs } from 'pinia'
|
|
||||||
import { nextTick, onMounted, reactive } from "vue";
|
|
||||||
import useNoticeStore from '@/store/modules/notice';
|
import useNoticeStore from '@/store/modules/notice';
|
||||||
|
|
||||||
const noticeStore = storeToRefs(useNoticeStore());
|
const noticeStore = storeToRefs(useNoticeStore());
|
||||||
const {readAll} = useNoticeStore();
|
const { readAll } = useNoticeStore();
|
||||||
|
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
loading: false,
|
loading: false
|
||||||
});
|
});
|
||||||
const newsList =ref([]) as any;
|
const newsList = ref([]) as any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化数据
|
* 初始化数据
|
||||||
@ -48,7 +46,6 @@ const getTableData = async () => {
|
|||||||
state.loading = false;
|
state.loading = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//点击消息,写入已读
|
//点击消息,写入已读
|
||||||
const onNewsClick = (item: any) => {
|
const onNewsClick = (item: any) => {
|
||||||
newsList.value[item].read = true;
|
newsList.value[item].read = true;
|
||||||
@ -58,7 +55,7 @@ const onNewsClick = (item: any) => {
|
|||||||
|
|
||||||
// 前往通知中心点击
|
// 前往通知中心点击
|
||||||
const onGoToGiteeClick = () => {
|
const onGoToGiteeClick = () => {
|
||||||
window.open("https://gitee.com/dromara/RuoYi-Vue-Plus/tree/5.X/");
|
window.open('https://gitee.com/dromara/RuoYi-Vue-Plus/tree/5.X/');
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
<settings ref="settingRef" />
|
<settings ref="settingRef" />
|
||||||
</el-scrollbar> -->
|
</el-scrollbar> -->
|
||||||
<div :class="{ 'fixed-header': fixedHeader }">
|
<div :class="{ 'fixed-header': fixedHeader }">
|
||||||
<navbar ref="navbarRef" @setLayout="setLayout" />
|
<navbar ref="navbarRef" @set-layout="setLayout" />
|
||||||
<tags-view v-if="needTagsView" />
|
<tags-view v-if="needTagsView" />
|
||||||
</div>
|
</div>
|
||||||
<app-main />
|
<app-main />
|
||||||
@ -22,12 +22,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import SideBar from './components/Sidebar/index.vue'
|
import SideBar from './components/Sidebar/index.vue';
|
||||||
import { AppMain, Navbar, Settings, TagsView } from './components'
|
import { AppMain, Navbar, Settings, TagsView } from './components';
|
||||||
import useAppStore from '@/store/modules/app'
|
import useAppStore from '@/store/modules/app';
|
||||||
import useSettingsStore from '@/store/modules/settings'
|
import useSettingsStore from '@/store/modules/settings';
|
||||||
|
|
||||||
const settingsStore = useSettingsStore()
|
const settingsStore = useSettingsStore();
|
||||||
const theme = computed(() => settingsStore.theme);
|
const theme = computed(() => settingsStore.theme);
|
||||||
const sidebar = computed(() => useAppStore().sidebar);
|
const sidebar = computed(() => useAppStore().sidebar);
|
||||||
const device = computed(() => useAppStore().device);
|
const device = computed(() => useAppStore().device);
|
||||||
@ -35,48 +35,48 @@ const needTagsView = computed(() => settingsStore.tagsView);
|
|||||||
const fixedHeader = computed(() => settingsStore.fixedHeader);
|
const fixedHeader = computed(() => settingsStore.fixedHeader);
|
||||||
|
|
||||||
const classObj = computed(() => ({
|
const classObj = computed(() => ({
|
||||||
hideSidebar: !sidebar.value.opened,
|
hideSidebar: !sidebar.value.opened,
|
||||||
openSidebar: sidebar.value.opened,
|
openSidebar: sidebar.value.opened,
|
||||||
withoutAnimation: sidebar.value.withoutAnimation,
|
withoutAnimation: sidebar.value.withoutAnimation,
|
||||||
mobile: device.value === 'mobile'
|
mobile: device.value === 'mobile'
|
||||||
}))
|
}));
|
||||||
|
|
||||||
const { width } = useWindowSize();
|
const { width } = useWindowSize();
|
||||||
const WIDTH = 992; // refer to Bootstrap's responsive design
|
const WIDTH = 992; // refer to Bootstrap's responsive design
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
if (device.value === 'mobile' && sidebar.value.opened) {
|
if (device.value === 'mobile' && sidebar.value.opened) {
|
||||||
useAppStore().closeSideBar({ withoutAnimation: false })
|
useAppStore().closeSideBar({ withoutAnimation: false });
|
||||||
}
|
}
|
||||||
if (width.value - 1 < WIDTH) {
|
if (width.value - 1 < WIDTH) {
|
||||||
useAppStore().toggleDevice('mobile')
|
useAppStore().toggleDevice('mobile');
|
||||||
useAppStore().closeSideBar({ withoutAnimation: true })
|
useAppStore().closeSideBar({ withoutAnimation: true });
|
||||||
} else {
|
} else {
|
||||||
useAppStore().toggleDevice('desktop')
|
useAppStore().toggleDevice('desktop');
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const navbarRef = ref(Navbar);
|
const navbarRef = ref<InstanceType<typeof Navbar>>();
|
||||||
const settingRef = ref(Settings);
|
const settingRef = ref<InstanceType<typeof Settings>>();
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
navbarRef.value.initTenantList();
|
navbarRef.value?.initTenantList();
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
const handleClickOutside = () => {
|
const handleClickOutside = () => {
|
||||||
useAppStore().closeSideBar({ withoutAnimation: false })
|
useAppStore().closeSideBar({ withoutAnimation: false });
|
||||||
}
|
};
|
||||||
|
|
||||||
const setLayout = () => {
|
const setLayout = () => {
|
||||||
settingRef.value.openSetting();
|
settingRef.value?.openSetting();
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import "@/assets/styles/mixin.scss";
|
@import '@/assets/styles/mixin.scss';
|
||||||
@import "@/assets/styles/variables.module.scss";
|
@import '@/assets/styles/variables.module.scss';
|
||||||
|
|
||||||
.app-wrapper {
|
.app-wrapper {
|
||||||
@include clearfix;
|
@include clearfix;
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import { isRelogin } from '@/utils/request';
|
|||||||
import useUserStore from '@/store/modules/user';
|
import useUserStore from '@/store/modules/user';
|
||||||
import useSettingsStore from '@/store/modules/settings';
|
import useSettingsStore from '@/store/modules/settings';
|
||||||
import usePermissionStore from '@/store/modules/permission';
|
import usePermissionStore from '@/store/modules/permission';
|
||||||
|
import { RouteRecordRaw } from 'vue-router';
|
||||||
|
|
||||||
NProgress.configure({ showSpinner: false });
|
NProgress.configure({ showSpinner: false });
|
||||||
const whiteList = ['/login', '/register', '/social-callback'];
|
const whiteList = ['/login', '/register', '/social-callback'];
|
||||||
@ -35,7 +36,7 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
isRelogin.show = false;
|
isRelogin.show = false;
|
||||||
const accessRoutes = await usePermissionStore().generateRoutes();
|
const accessRoutes = await usePermissionStore().generateRoutes();
|
||||||
// 根据roles权限生成可访问的路由表
|
// 根据roles权限生成可访问的路由表
|
||||||
accessRoutes.forEach((route) => {
|
accessRoutes.forEach((route: RouteRecordRaw) => {
|
||||||
if (!isHttp(route.path)) {
|
if (!isHttp(route.path)) {
|
||||||
router.addRoute(route); // 动态添加可访问路由表
|
router.addRoute(route); // 动态添加可访问路由表
|
||||||
}
|
}
|
||||||
@ -48,7 +49,7 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 没有token
|
// 没有token
|
||||||
if (whiteList.indexOf(to.path) !== -1) {
|
if (whiteList.indexOf(to.path as string) !== -1) {
|
||||||
// 在免登录白名单,直接进入
|
// 在免登录白名单,直接进入
|
||||||
next();
|
next();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useTagsViewStore } from '@/store/modules/tagsView';
|
import { useTagsViewStore } from '@/store/modules/tagsView';
|
||||||
import router from '@/router';
|
import router from '@/router';
|
||||||
import { TagView, RouteLocationRaw } from 'vue-router';
|
import { TagView, RouteLocationMatched } from 'vue-router';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
/**
|
/**
|
||||||
@ -10,7 +10,7 @@ export default {
|
|||||||
async refreshPage(obj?: TagView): Promise<void> {
|
async refreshPage(obj?: TagView): Promise<void> {
|
||||||
const { path, query, matched } = router.currentRoute.value;
|
const { path, query, matched } = router.currentRoute.value;
|
||||||
if (obj === undefined) {
|
if (obj === undefined) {
|
||||||
matched.forEach((m) => {
|
matched.forEach((m: RouteLocationMatched) => {
|
||||||
if (m.components && m.components.default && m.components.default.name) {
|
if (m.components && m.components.default && m.components.default.name) {
|
||||||
if (!['Layout', 'ParentView'].includes(m.components.default.name)) {
|
if (!['Layout', 'ParentView'].includes(m.components.default.name)) {
|
||||||
obj = { name: m.components.default.name, path: path, query: query };
|
obj = { name: m.components.default.name, path: path, query: query };
|
||||||
@ -31,8 +31,8 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
// 关闭当前tab页签,打开新页签
|
// 关闭当前tab页签,打开新页签
|
||||||
closeOpenPage(obj: RouteLocationRaw): void {
|
closeOpenPage(obj: TagView): void {
|
||||||
useTagsViewStore().delView(router.currentRoute.value);
|
useTagsViewStore().delView(router.currentRoute.value as any);
|
||||||
if (obj !== undefined) {
|
if (obj !== undefined) {
|
||||||
router.push(obj);
|
router.push(obj);
|
||||||
}
|
}
|
||||||
@ -41,10 +41,10 @@ export default {
|
|||||||
async closePage(obj?: TagView): Promise<{ visitedViews: TagView[]; cachedViews: string[] } | any> {
|
async closePage(obj?: TagView): Promise<{ visitedViews: TagView[]; cachedViews: string[] } | any> {
|
||||||
if (obj === undefined) {
|
if (obj === undefined) {
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const { visitedViews } = await useTagsViewStore().delView(router.currentRoute.value) as any
|
const { visitedViews } = await useTagsViewStore().delView(router.currentRoute.value as any)
|
||||||
const latestView = visitedViews.slice(-1)[0];
|
const latestView = visitedViews.slice(-1)[0];
|
||||||
if (latestView) {
|
if (latestView) {
|
||||||
return router.push(latestView.fullPath);
|
return router.push(latestView.fullPath as any);
|
||||||
}
|
}
|
||||||
return router.push('/');
|
return router.push('/');
|
||||||
}
|
}
|
||||||
@ -56,15 +56,15 @@ export default {
|
|||||||
},
|
},
|
||||||
// 关闭左侧tab页签
|
// 关闭左侧tab页签
|
||||||
closeLeftPage(obj?: TagView) {
|
closeLeftPage(obj?: TagView) {
|
||||||
return useTagsViewStore().delLeftTags(obj || router.currentRoute.value);
|
return useTagsViewStore().delLeftTags(obj || (router.currentRoute.value as any));
|
||||||
},
|
},
|
||||||
// 关闭右侧tab页签
|
// 关闭右侧tab页签
|
||||||
closeRightPage(obj?: TagView) {
|
closeRightPage(obj?: TagView) {
|
||||||
return useTagsViewStore().delRightTags(obj || router.currentRoute.value);
|
return useTagsViewStore().delRightTags(obj || (router.currentRoute.value as any));
|
||||||
},
|
},
|
||||||
// 关闭其他tab页签
|
// 关闭其他tab页签
|
||||||
closeOtherPage(obj?: TagView) {
|
closeOtherPage(obj?: TagView) {
|
||||||
return useTagsViewStore().delOthersViews(obj || router.currentRoute.value);
|
return useTagsViewStore().delOthersViews(obj || (router.currentRoute.value as any));
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 打开tab页签
|
* 打开tab页签
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { createWebHistory, createRouter, RouteOption } from 'vue-router';
|
import { createWebHistory, createRouter, RouteRecordRaw } from 'vue-router';
|
||||||
/* Layout */
|
/* Layout */
|
||||||
import Layout from '@/layout/index.vue';
|
import Layout from '@/layout/index.vue';
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ import Layout from '@/layout/index.vue';
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// 公共路由
|
// 公共路由
|
||||||
export const constantRoutes: RouteOption[] = [
|
export const constantRoutes: RouteRecordRaw[] = [
|
||||||
{
|
{
|
||||||
path: '/redirect',
|
path: '/redirect',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
@ -92,7 +92,7 @@ export const constantRoutes: RouteOption[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
// 动态路由,基于用户权限动态去加载
|
// 动态路由,基于用户权限动态去加载
|
||||||
export const dynamicRoutes: RouteOption[] = [
|
export const dynamicRoutes: RouteRecordRaw[] = [
|
||||||
{
|
{
|
||||||
path: '/system/user-auth',
|
path: '/system/user-auth',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
|
|||||||
@ -22,7 +22,7 @@ export const useNoticeStore = defineStore('notice', () => {
|
|||||||
|
|
||||||
//实现全部已读
|
//实现全部已读
|
||||||
const readAll = () => {
|
const readAll = () => {
|
||||||
state.notices.forEach((item) => {
|
state.notices.forEach((item: any) => {
|
||||||
item.read = true;
|
item.read = true;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -2,35 +2,36 @@ import { defineStore } from 'pinia';
|
|||||||
import router, { constantRoutes, dynamicRoutes } from '@/router';
|
import router, { constantRoutes, dynamicRoutes } from '@/router';
|
||||||
import store from '@/store';
|
import store from '@/store';
|
||||||
import { getRouters } from '@/api/menu';
|
import { getRouters } from '@/api/menu';
|
||||||
|
import auth from '@/plugins/auth';
|
||||||
|
import { RouteRecordRaw } from 'vue-router';
|
||||||
|
|
||||||
import Layout from '@/layout/index.vue';
|
import Layout from '@/layout/index.vue';
|
||||||
import ParentView from '@/components/ParentView/index.vue';
|
import ParentView from '@/components/ParentView/index.vue';
|
||||||
import InnerLink from '@/layout/components/InnerLink/index.vue';
|
import InnerLink from '@/layout/components/InnerLink/index.vue';
|
||||||
import auth from '@/plugins/auth';
|
|
||||||
import { RouteOption } from 'vue-router';
|
|
||||||
// 匹配views里面所有的.vue文件
|
// 匹配views里面所有的.vue文件
|
||||||
const modules = import.meta.glob('./../../views/**/*.vue');
|
const modules = import.meta.glob('./../../views/**/*.vue');
|
||||||
|
|
||||||
export const usePermissionStore = defineStore('permission', () => {
|
export const usePermissionStore = defineStore('permission', () => {
|
||||||
const routes = ref<RouteOption[]>([]);
|
const routes = ref<RouteRecordRaw[]>([]);
|
||||||
const addRoutes = ref<RouteOption[]>([]);
|
const addRoutes = ref<RouteRecordRaw[]>([]);
|
||||||
const defaultRoutes = ref<RouteOption[]>([]);
|
const defaultRoutes = ref<RouteRecordRaw[]>([]);
|
||||||
const topbarRouters = ref<RouteOption[]>([]);
|
const topbarRouters = ref<RouteRecordRaw[]>([]);
|
||||||
const sidebarRouters = ref<RouteOption[]>([]);
|
const sidebarRouters = ref<RouteRecordRaw[]>([]);
|
||||||
|
|
||||||
const setRoutes = (newRoutes: RouteOption[]): void => {
|
const setRoutes = (newRoutes: RouteRecordRaw[]): void => {
|
||||||
addRoutes.value = newRoutes;
|
addRoutes.value = newRoutes;
|
||||||
routes.value = constantRoutes.concat(newRoutes);
|
routes.value = constantRoutes.concat(newRoutes);
|
||||||
};
|
};
|
||||||
const setDefaultRoutes = (routes: RouteOption[]): void => {
|
const setDefaultRoutes = (routes: RouteRecordRaw[]): void => {
|
||||||
defaultRoutes.value = constantRoutes.concat(routes);
|
defaultRoutes.value = constantRoutes.concat(routes);
|
||||||
};
|
};
|
||||||
const setTopbarRoutes = (routes: RouteOption[]): void => {
|
const setTopbarRoutes = (routes: RouteRecordRaw[]): void => {
|
||||||
topbarRouters.value = routes;
|
topbarRouters.value = routes;
|
||||||
};
|
};
|
||||||
const setSidebarRouters = (routes: RouteOption[]): void => {
|
const setSidebarRouters = (routes: RouteRecordRaw[]): void => {
|
||||||
sidebarRouters.value = routes;
|
sidebarRouters.value = routes;
|
||||||
};
|
};
|
||||||
const generateRoutes = async (): Promise<RouteOption[]> => {
|
const generateRoutes = async (): Promise<RouteRecordRaw[]> => {
|
||||||
const res = await getRouters();
|
const res = await getRouters();
|
||||||
const { data } = res;
|
const { data } = res;
|
||||||
const sdata = JSON.parse(JSON.stringify(data));
|
const sdata = JSON.parse(JSON.stringify(data));
|
||||||
@ -47,7 +48,7 @@ export const usePermissionStore = defineStore('permission', () => {
|
|||||||
setSidebarRouters(constantRoutes.concat(sidebarRoutes));
|
setSidebarRouters(constantRoutes.concat(sidebarRoutes));
|
||||||
setDefaultRoutes(sidebarRoutes);
|
setDefaultRoutes(sidebarRoutes);
|
||||||
setTopbarRoutes(defaultRoutes);
|
setTopbarRoutes(defaultRoutes);
|
||||||
return new Promise<RouteOption[]>((resolve) => resolve(rewriteRoutes));
|
return new Promise<RouteRecordRaw[]>((resolve) => resolve(rewriteRoutes));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,22 +57,20 @@ export const usePermissionStore = defineStore('permission', () => {
|
|||||||
* @param lastRouter 上一级路由
|
* @param lastRouter 上一级路由
|
||||||
* @param type 是否是重写路由
|
* @param type 是否是重写路由
|
||||||
*/
|
*/
|
||||||
const filterAsyncRouter = (asyncRouterMap: RouteOption[], lastRouter?: RouteOption, type = false): RouteOption[] => {
|
const filterAsyncRouter = (asyncRouterMap: RouteRecordRaw[], lastRouter?: RouteRecordRaw, type = false): RouteRecordRaw[] => {
|
||||||
return asyncRouterMap.filter((route) => {
|
return asyncRouterMap.filter((route) => {
|
||||||
if (type && route.children) {
|
if (type && route.children) {
|
||||||
route.children = filterChildren(route.children, undefined);
|
route.children = filterChildren(route.children, undefined);
|
||||||
}
|
}
|
||||||
if (route.component) {
|
// Layout ParentView 组件特殊处理
|
||||||
// Layout ParentView 组件特殊处理
|
if (route.component?.toString() === 'Layout') {
|
||||||
if (route.component === 'Layout') {
|
route.component = Layout;
|
||||||
route.component = Layout;
|
} else if (route.component?.toString() === 'ParentView') {
|
||||||
} else if (route.component === 'ParentView') {
|
route.component = ParentView;
|
||||||
route.component = ParentView;
|
} else if (route.component?.toString() === 'InnerLink') {
|
||||||
} else if (route.component === 'InnerLink') {
|
route.component = InnerLink;
|
||||||
route.component = InnerLink;
|
} else {
|
||||||
} else {
|
route.component = loadView(route.component);
|
||||||
route.component = loadView(route.component);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (route.children != null && route.children && route.children.length) {
|
if (route.children != null && route.children && route.children.length) {
|
||||||
route.children = filterAsyncRouter(route.children, route, type);
|
route.children = filterAsyncRouter(route.children, route, type);
|
||||||
@ -82,11 +81,11 @@ export const usePermissionStore = defineStore('permission', () => {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const filterChildren = (childrenMap: RouteOption[], lastRouter?: RouteOption): RouteOption[] => {
|
const filterChildren = (childrenMap: RouteRecordRaw[], lastRouter?: RouteRecordRaw): RouteRecordRaw[] => {
|
||||||
let children: RouteOption[] = [];
|
let children: RouteRecordRaw[] = [];
|
||||||
childrenMap.forEach((el) => {
|
childrenMap.forEach((el) => {
|
||||||
if (el.children && el.children.length) {
|
if (el.children && el.children.length) {
|
||||||
if (el.component === 'ParentView' && !lastRouter) {
|
if (el.component?.toString() === 'ParentView' && !lastRouter) {
|
||||||
el.children.forEach((c) => {
|
el.children.forEach((c) => {
|
||||||
c.path = el.path + '/' + c.path;
|
c.path = el.path + '/' + c.path;
|
||||||
if (c.children && c.children.length) {
|
if (c.children && c.children.length) {
|
||||||
@ -101,8 +100,8 @@ export const usePermissionStore = defineStore('permission', () => {
|
|||||||
if (lastRouter) {
|
if (lastRouter) {
|
||||||
el.path = lastRouter.path + '/' + el.path;
|
el.path = lastRouter.path + '/' + el.path;
|
||||||
if (el.children && el.children.length) {
|
if (el.children && el.children.length) {
|
||||||
children = children.concat(filterChildren(el.children, el))
|
children = children.concat(filterChildren(el.children, el));
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
children = children.concat(el);
|
children = children.concat(el);
|
||||||
@ -113,8 +112,8 @@ export const usePermissionStore = defineStore('permission', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 动态路由遍历,验证是否具备权限
|
// 动态路由遍历,验证是否具备权限
|
||||||
export const filterDynamicRoutes = (routes: RouteOption[]) => {
|
export const filterDynamicRoutes = (routes: RouteRecordRaw[]) => {
|
||||||
const res: RouteOption[] = [];
|
const res: RouteRecordRaw[] = [];
|
||||||
routes.forEach((route) => {
|
routes.forEach((route) => {
|
||||||
if (route.permissions) {
|
if (route.permissions) {
|
||||||
if (auth.hasPermiOr(route.permissions)) {
|
if (auth.hasPermiOr(route.permissions)) {
|
||||||
|
|||||||
@ -2,27 +2,35 @@ import { defineStore } from 'pinia';
|
|||||||
import defaultSettings from '@/settings';
|
import defaultSettings from '@/settings';
|
||||||
import { SettingTypeEnum } from '@/enums/SettingTypeEnum';
|
import { SettingTypeEnum } from '@/enums/SettingTypeEnum';
|
||||||
import { useDynamicTitle } from '@/utils/dynamicTitle';
|
import { useDynamicTitle } from '@/utils/dynamicTitle';
|
||||||
import { Ref } from 'vue';
|
|
||||||
|
|
||||||
export const useSettingsStore = defineStore('setting', () => {
|
export const useSettingsStore = defineStore('setting', () => {
|
||||||
const storageSetting = JSON.parse(localStorage.getItem('layout-setting') || '{}');
|
const storageSetting = JSON.parse(localStorage.getItem('layout-setting') || '{}');
|
||||||
|
const title = ref<string>(defaultSettings.title);
|
||||||
|
const theme = ref<string>(storageSetting.theme || defaultSettings.theme);
|
||||||
|
const sideTheme = ref<string>(storageSetting.sideTheme || defaultSettings.sideTheme);
|
||||||
|
const showSettings = ref<boolean>(storageSetting.showSettings || defaultSettings.showSettings);
|
||||||
|
const topNav = ref<boolean>(storageSetting.topNav === undefined ? defaultSettings.topNav : storageSetting.topNav);
|
||||||
|
const tagsView = ref<boolean>(storageSetting.tagsView === undefined ? defaultSettings.tagsView : storageSetting.tagsView);
|
||||||
|
const fixedHeader = ref<boolean>(storageSetting.fixedHeader === undefined ? defaultSettings.fixedHeader : storageSetting.fixedHeader);
|
||||||
|
const sidebarLogo = ref<boolean>(storageSetting.sidebarLogo === undefined ? defaultSettings.sidebarLogo : storageSetting.sidebarLogo);
|
||||||
|
const dynamicTitle = ref<boolean>(storageSetting.dynamicTitle === undefined ? defaultSettings.dynamicTitle : storageSetting.dynamicTitle);
|
||||||
|
const animationEnable = ref<boolean>(
|
||||||
|
storageSetting.animationEnable === undefined ? defaultSettings.animationEnable : storageSetting.animationEnable
|
||||||
|
);
|
||||||
|
const dark = ref<boolean>(storageSetting.dark || defaultSettings.dark);
|
||||||
|
|
||||||
const prop: { [key: string]: Ref<any> } = {
|
const prop: { [key: string]: Ref<any> } = {
|
||||||
title: ref<string>(''),
|
theme,
|
||||||
theme: ref<string>(storageSetting.theme || defaultSettings.theme),
|
sideTheme,
|
||||||
sideTheme: ref<string>(storageSetting.sideTheme || defaultSettings.sideTheme),
|
showSettings,
|
||||||
showSettings: ref<boolean>(storageSetting.showSettings || defaultSettings.showSettings),
|
topNav,
|
||||||
topNav: ref<boolean>(storageSetting.topNav === undefined ? defaultSettings.topNav : storageSetting.topNav),
|
tagsView,
|
||||||
tagsView: ref<boolean>(storageSetting.tagsView === undefined ? defaultSettings.tagsView : storageSetting.tagsView),
|
fixedHeader,
|
||||||
fixedHeader: ref<boolean>(storageSetting.fixedHeader === undefined ? defaultSettings.fixedHeader : storageSetting.fixedHeader),
|
sidebarLogo,
|
||||||
sidebarLogo: ref<boolean>(storageSetting.sidebarLogo === undefined ? defaultSettings.sidebarLogo : storageSetting.sidebarLogo),
|
dynamicTitle,
|
||||||
dynamicTitle: ref<boolean>(storageSetting.dynamicTitle === undefined ? defaultSettings.dynamicTitle : storageSetting.dynamicTitle),
|
animationEnable,
|
||||||
animationEnable: ref<boolean>(storageSetting.animationEnable === undefined ? defaultSettings.animationEnable : storageSetting.animationEnable),
|
dark
|
||||||
dark: ref<boolean>(storageSetting.dark || defaultSettings.dark)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const { title, theme, sideTheme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo, dynamicTitle, animationEnable, dark } = prop;
|
|
||||||
|
|
||||||
// actions
|
// actions
|
||||||
const changeSetting = (param: { key: SettingTypeEnum; value: any }) => {
|
const changeSetting = (param: { key: SettingTypeEnum; value: any }) => {
|
||||||
const { key, value } = param;
|
const { key, value } = param;
|
||||||
|
|||||||
@ -11,7 +11,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const addIframeView = (view: TagView): void => {
|
const addIframeView = (view: TagView): void => {
|
||||||
if (iframeViews.value.some((v) => v.path === view.path)) return;
|
if (iframeViews.value.some((v: TagView) => v.path === view.path)) return;
|
||||||
iframeViews.value.push(
|
iframeViews.value.push(
|
||||||
Object.assign({}, view, {
|
Object.assign({}, view, {
|
||||||
title: view.meta?.title || 'no-name'
|
title: view.meta?.title || 'no-name'
|
||||||
@ -20,12 +20,12 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
|||||||
};
|
};
|
||||||
const delIframeView = (view: TagView): Promise<TagView[]> => {
|
const delIframeView = (view: TagView): Promise<TagView[]> => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
iframeViews.value = iframeViews.value.filter((item) => item.path !== view.path);
|
iframeViews.value = iframeViews.value.filter((item: TagView) => item.path !== view.path);
|
||||||
resolve([...iframeViews.value]);
|
resolve([...iframeViews.value]);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const addVisitedView = (view: TagView): void => {
|
const addVisitedView = (view: TagView): void => {
|
||||||
if (visitedViews.value.some((v) => v.path === view.path)) return;
|
if (visitedViews.value.some((v: TagView) => v.path === view.path)) return;
|
||||||
visitedViews.value.push(
|
visitedViews.value.push(
|
||||||
Object.assign({}, view, {
|
Object.assign({}, view, {
|
||||||
title: view.meta?.title || 'no-name'
|
title: view.meta?.title || 'no-name'
|
||||||
@ -80,7 +80,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
|||||||
|
|
||||||
const delOthersVisitedViews = (view: TagView): Promise<TagView[]> => {
|
const delOthersVisitedViews = (view: TagView): Promise<TagView[]> => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
visitedViews.value = visitedViews.value.filter((v) => {
|
visitedViews.value = visitedViews.value.filter((v: TagView) => {
|
||||||
return v.meta?.affix || v.path === view.path;
|
return v.meta?.affix || v.path === view.path;
|
||||||
});
|
});
|
||||||
resolve([...visitedViews.value]);
|
resolve([...visitedViews.value]);
|
||||||
@ -111,7 +111,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
|||||||
};
|
};
|
||||||
const delAllVisitedViews = (): Promise<TagView[]> => {
|
const delAllVisitedViews = (): Promise<TagView[]> => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
visitedViews.value = visitedViews.value.filter((tag) => tag.meta?.affix);
|
visitedViews.value = visitedViews.value.filter((tag: TagView) => tag.meta?.affix);
|
||||||
resolve([...visitedViews.value]);
|
resolve([...visitedViews.value]);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -123,7 +123,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateVisitedView = (view: TagView): void => {
|
const updateVisitedView = (view: TagView | RouteLocationNormalized): void => {
|
||||||
for (let v of visitedViews.value) {
|
for (let v of visitedViews.value) {
|
||||||
if (v.path === view.path) {
|
if (v.path === view.path) {
|
||||||
v = Object.assign(v, view);
|
v = Object.assign(v, view);
|
||||||
@ -133,11 +133,11 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
|||||||
};
|
};
|
||||||
const delRightTags = (view: TagView): Promise<TagView[]> => {
|
const delRightTags = (view: TagView): Promise<TagView[]> => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const index = visitedViews.value.findIndex((v) => v.path === view.path);
|
const index = visitedViews.value.findIndex((v: TagView) => v.path === view.path);
|
||||||
if (index === -1) {
|
if (index === -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
visitedViews.value = visitedViews.value.filter((item, idx) => {
|
visitedViews.value = visitedViews.value.filter((item: TagView, idx: number) => {
|
||||||
if (idx <= index || (item.meta && item.meta.affix)) {
|
if (idx <= index || (item.meta && item.meta.affix)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -152,11 +152,11 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
|||||||
};
|
};
|
||||||
const delLeftTags = (view: TagView): Promise<TagView[]> => {
|
const delLeftTags = (view: TagView): Promise<TagView[]> => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const index = visitedViews.value.findIndex((v) => v.path === view.path);
|
const index = visitedViews.value.findIndex((v: TagView) => v.path === view.path);
|
||||||
if (index === -1) {
|
if (index === -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
visitedViews.value = visitedViews.value.filter((item, idx) => {
|
visitedViews.value = visitedViews.value.filter((item: TagView, idx: number) => {
|
||||||
if (idx >= index || (item.meta && item.meta.affix)) {
|
if (idx >= index || (item.meta && item.meta.affix)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -170,7 +170,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const addCachedView = (view: TagView): void => {
|
const addCachedView = (view: TagView | RouteLocationNormalized): void => {
|
||||||
const viewName = view.name as string;
|
const viewName = view.name as string;
|
||||||
if (!viewName) return;
|
if (!viewName) return;
|
||||||
if (cachedViews.value.includes(viewName)) return;
|
if (cachedViews.value.includes(viewName)) return;
|
||||||
|
|||||||
6
src/types/element.d.ts
vendored
6
src/types/element.d.ts
vendored
@ -1,12 +1,12 @@
|
|||||||
import type * as ep from 'element-plus';
|
import type * as ep from 'element-plus';
|
||||||
declare global {
|
declare global {
|
||||||
declare type ElTagType = '' | 'success' | 'warning' | 'info' | 'danger' | 'default' | 'primary';
|
declare type ElTagType = '' | 'success' | 'warning' | 'info' | 'danger' | 'default' | 'primary';
|
||||||
declare type ElFormInstance = InstanceType<typeof ep.ElForm>;
|
declare type ElFormInstance = ep.FormInstance;
|
||||||
declare type ElTableInstance = InstanceType<typeof ep.ElTable>;
|
declare type ElTableInstance = ep.TableInstance;
|
||||||
|
declare type ElUploadInstance = ep.UploadInstance;
|
||||||
declare type ElTreeInstance = InstanceType<typeof ep.ElTree>;
|
declare type ElTreeInstance = InstanceType<typeof ep.ElTree>;
|
||||||
declare type ElTreeSelectInstance = InstanceType<typeof ep.ElTreeSelect>;
|
declare type ElTreeSelectInstance = InstanceType<typeof ep.ElTreeSelect>;
|
||||||
declare type ElSelectInstance = InstanceType<typeof ep.ElSelect>;
|
declare type ElSelectInstance = InstanceType<typeof ep.ElSelect>;
|
||||||
declare type ElUploadInstance = InstanceType<typeof ep.ElUpload>;
|
|
||||||
declare type ElCardInstance = InstanceType<typeof ep.ElCard>;
|
declare type ElCardInstance = InstanceType<typeof ep.ElCard>;
|
||||||
declare type ElDialogInstance = InstanceType<typeof ep.ElDialog>;
|
declare type ElDialogInstance = InstanceType<typeof ep.ElDialog>;
|
||||||
declare type ElInputInstance = InstanceType<typeof ep.ElInput>;
|
declare type ElInputInstance = InstanceType<typeof ep.ElInput>;
|
||||||
|
|||||||
5
src/types/env.d.ts
vendored
5
src/types/env.d.ts
vendored
@ -1,8 +1,9 @@
|
|||||||
declare module '*.vue' {
|
declare module '*.vue' {
|
||||||
import { DefineComponent } from 'vue';
|
import { DefineComponent } from 'vue';
|
||||||
const component: DefineComponent<{}, {}, any>;
|
const Component: DefineComponent<{}, {}, any>;
|
||||||
export default component;
|
export default Component;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '*.avif' {
|
declare module '*.avif' {
|
||||||
const src: string;
|
const src: string;
|
||||||
export default src;
|
export default src;
|
||||||
|
|||||||
73
src/types/global.d.ts
vendored
73
src/types/global.d.ts
vendored
@ -1,4 +1,4 @@
|
|||||||
import type { ComponentInternalInstance as ComponentInstance, PropType as VuePropType } from 'vue';
|
import type { ComponentInternalInstance as ComponentInstance, PropType as VuePropType } from 'vue/runtime-core';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
/** vue Instance */
|
/** vue Instance */
|
||||||
@ -87,5 +87,76 @@ declare global {
|
|||||||
pageNum: number;
|
pageNum: number;
|
||||||
pageSize: number;
|
pageSize: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare type DefaultSettings = {
|
||||||
|
/**
|
||||||
|
* 网页标题
|
||||||
|
*/
|
||||||
|
title: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 侧边栏主题 theme-dark | theme-light
|
||||||
|
*/
|
||||||
|
sideTheme?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否显示系统布局设置
|
||||||
|
*/
|
||||||
|
showSettings?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否显示顶部导航
|
||||||
|
*/
|
||||||
|
topNav?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否显示多标签导航
|
||||||
|
*/
|
||||||
|
tagsView?: boolean;
|
||||||
|
/**
|
||||||
|
* 是否固定头部
|
||||||
|
*/
|
||||||
|
fixedHeader?: boolean;
|
||||||
|
/**
|
||||||
|
* 是否显示侧边栏Logo
|
||||||
|
*/
|
||||||
|
sidebarLogo?: boolean;
|
||||||
|
/**
|
||||||
|
* 导航栏布局
|
||||||
|
*/
|
||||||
|
layout?: string;
|
||||||
|
/**
|
||||||
|
* 主题模式
|
||||||
|
*/
|
||||||
|
theme?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 布局大小
|
||||||
|
*/
|
||||||
|
size?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语言
|
||||||
|
*/
|
||||||
|
language?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否显示动态标题
|
||||||
|
*/
|
||||||
|
dynamicTitle?: boolean;
|
||||||
|
/**
|
||||||
|
* 是否启用动画效果
|
||||||
|
*/
|
||||||
|
animationEnable?: boolean;
|
||||||
|
/**
|
||||||
|
* 是否启用暗黑模式
|
||||||
|
*
|
||||||
|
* true:暗黑模式
|
||||||
|
* false: 明亮模式
|
||||||
|
*/
|
||||||
|
dark?: boolean;
|
||||||
|
|
||||||
|
errorLog?: string;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
export {};
|
export {};
|
||||||
|
|||||||
48
src/types/router.d.ts
vendored
48
src/types/router.d.ts
vendored
@ -1,36 +1,34 @@
|
|||||||
import { RouteRecordRaw } from 'vue-router';
|
import { LocationQuery, type RouteMeta as VRouteMeta } from 'vue-router';
|
||||||
|
|
||||||
declare module 'vue-router' {
|
declare module 'vue-router' {
|
||||||
declare type RouteOption = {
|
interface RouteMeta extends VRouteMeta {
|
||||||
hidden?: boolean;
|
link?: string;
|
||||||
|
title?: string;
|
||||||
|
affix?: boolean;
|
||||||
|
noCache?: boolean;
|
||||||
|
activeMenu?: string;
|
||||||
|
icon?: string;
|
||||||
|
breadcrumb?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface _RouteRecordBase {
|
||||||
|
hidden?: boolean | string | number;
|
||||||
permissions?: string[];
|
permissions?: string[];
|
||||||
roles?: string[];
|
roles?: string[];
|
||||||
component?: any;
|
|
||||||
children?: RouteOption[];
|
|
||||||
alwaysShow?: boolean;
|
alwaysShow?: boolean;
|
||||||
parentPath?: string;
|
|
||||||
meta?: {
|
|
||||||
title: string;
|
|
||||||
icon: string;
|
|
||||||
};
|
|
||||||
query?: string;
|
query?: string;
|
||||||
} & RouteRecordRaw;
|
|
||||||
|
|
||||||
declare interface _RouteLocationBase {
|
|
||||||
children?: RouteOption[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare interface RouteLocationOptions {
|
interface _RouteLocationBase {
|
||||||
|
children?: _RouteRecordBase[];
|
||||||
|
path?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TagView {
|
||||||
fullPath?: string;
|
fullPath?: string;
|
||||||
}
|
name?: string;
|
||||||
|
path?: string;
|
||||||
declare interface TagView extends Partial<_RouteLocationBase> {
|
|
||||||
title?: string;
|
title?: string;
|
||||||
meta?: {
|
meta?: RouteMeta;
|
||||||
link?: string;
|
query?: LocationQuery;
|
||||||
title?: string;
|
|
||||||
affix?: boolean;
|
|
||||||
noCache?: boolean;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
70
src/types/setting.d.ts
vendored
70
src/types/setting.d.ts
vendored
@ -1,70 +0,0 @@
|
|||||||
declare type DefaultSettings = {
|
|
||||||
/**
|
|
||||||
* 网页标题
|
|
||||||
*/
|
|
||||||
title?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 侧边栏主题 theme-dark | theme-light
|
|
||||||
*/
|
|
||||||
sideTheme?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否显示系统布局设置
|
|
||||||
*/
|
|
||||||
showSettings?: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否显示顶部导航
|
|
||||||
*/
|
|
||||||
topNav?: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否显示多标签导航
|
|
||||||
*/
|
|
||||||
tagsView?: boolean;
|
|
||||||
/**
|
|
||||||
* 是否固定头部
|
|
||||||
*/
|
|
||||||
fixedHeader?: boolean;
|
|
||||||
/**
|
|
||||||
* 是否显示侧边栏Logo
|
|
||||||
*/
|
|
||||||
sidebarLogo?: boolean;
|
|
||||||
/**
|
|
||||||
* 导航栏布局
|
|
||||||
*/
|
|
||||||
layout?: string;
|
|
||||||
/**
|
|
||||||
* 主题模式
|
|
||||||
*/
|
|
||||||
theme?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 布局大小
|
|
||||||
*/
|
|
||||||
size?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 语言
|
|
||||||
*/
|
|
||||||
language?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否显示动态标题
|
|
||||||
*/
|
|
||||||
dynamicTitle?: boolean;
|
|
||||||
/**
|
|
||||||
* 是否启用动画效果
|
|
||||||
*/
|
|
||||||
animationEnable?: boolean;
|
|
||||||
/**
|
|
||||||
* 是否启用暗黑模式
|
|
||||||
*
|
|
||||||
* true:暗黑模式
|
|
||||||
* false: 明亮模式
|
|
||||||
*/
|
|
||||||
dark?: boolean;
|
|
||||||
|
|
||||||
errorLog?: string;
|
|
||||||
};
|
|
||||||
@ -3,6 +3,7 @@ import VueTypes, { createTypes, toValidableType, VueTypeValidableDef, VueTypesIn
|
|||||||
|
|
||||||
type PropTypes = VueTypesInterface & {
|
type PropTypes = VueTypesInterface & {
|
||||||
readonly style: VueTypeValidableDef<CSSProperties>;
|
readonly style: VueTypeValidableDef<CSSProperties>;
|
||||||
|
readonly fieldOption: VueTypeValidableDef<Array<FieldOption>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const propTypes = createTypes({
|
const propTypes = createTypes({
|
||||||
|
|||||||
@ -89,7 +89,6 @@ service.interceptors.request.use(
|
|||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
(error: any) => {
|
(error: any) => {
|
||||||
console.log(error);
|
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -138,7 +137,6 @@ service.interceptors.response.use(
|
|||||||
}
|
}
|
||||||
return Promise.reject('无效的会话,或者会话已过期,请重新登录。');
|
return Promise.reject('无效的会话,或者会话已过期,请重新登录。');
|
||||||
} else if (code === HttpStatus.SERVER_ERROR) {
|
} else if (code === HttpStatus.SERVER_ERROR) {
|
||||||
console.log(msg);
|
|
||||||
ElMessage({ message: msg, type: 'error' });
|
ElMessage({ message: msg, type: 'error' });
|
||||||
return Promise.reject(new Error(msg));
|
return Promise.reject(new Error(msg));
|
||||||
} else if (code === HttpStatus.WARN) {
|
} else if (code === HttpStatus.WARN) {
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
import { getToken } from '@/utils/auth';
|
import { getToken } from '@/utils/auth';
|
||||||
import useNoticeStore from '@/store/modules/notice';
|
import useNoticeStore from '@/store/modules/notice';
|
||||||
import { ElNotification } from "element-plus";
|
import { ElNotification } from 'element-plus';
|
||||||
|
|
||||||
const { addNotice } = useNoticeStore();
|
const { addNotice } = useNoticeStore();
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ export const websocketonmessage = () => {
|
|||||||
message: e.data,
|
message: e.data,
|
||||||
type: 'success',
|
type: 'success',
|
||||||
duration: 3000
|
duration: 3000
|
||||||
})
|
});
|
||||||
return e.data;
|
return e.data;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
<div class="mb-[10px]" v-show="showSearch">
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
|
||||||
<el-form-item label="部门id" prop="deptId">
|
<el-form-item label="部门id" prop="deptId">
|
||||||
<el-input v-model="queryParams.deptId" placeholder="请输入部门id" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.deptId" placeholder="请输入部门id" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -32,26 +32,26 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['demo:demo:add']">新增</el-button>
|
<el-button v-hasPermi="['demo:demo:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['demo:demo:edit']">修改</el-button>
|
<el-button v-hasPermi="['demo:demo:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">修改</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['demo:demo:remove']"
|
<el-button v-hasPermi="['demo:demo:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"
|
||||||
>删除</el-button
|
>删除</el-button
|
||||||
>
|
>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['demo:demo:export']">导出</el-button>
|
<el-button v-hasPermi="['demo:demo:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="demoList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" :data="demoList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="主键" align="center" prop="id" v-if="true" />
|
<el-table-column v-if="true" label="主键" align="center" prop="id" />
|
||||||
<el-table-column label="部门id" align="center" prop="deptId" />
|
<el-table-column label="部门id" align="center" prop="deptId" />
|
||||||
<el-table-column label="用户id" align="center" prop="userId" />
|
<el-table-column label="用户id" align="center" prop="userId" />
|
||||||
<el-table-column label="排序号" align="center" prop="orderNum" />
|
<el-table-column label="排序号" align="center" prop="orderNum" />
|
||||||
@ -60,19 +60,19 @@
|
|||||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="修改" placement="top">
|
<el-tooltip content="修改" placement="top">
|
||||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['demo:demo:edit']"></el-button>
|
<el-button v-hasPermi="['demo:demo:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="删除" placement="top">
|
<el-tooltip content="删除" placement="top">
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['demo:demo:remove']"></el-button>
|
<el-button v-hasPermi="['demo:demo:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
|
||||||
</el-card>
|
</el-card>
|
||||||
<!-- 添加或修改测试单对话框 -->
|
<!-- 添加或修改测试单对话框 -->
|
||||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
<el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
|
||||||
<el-form ref="demoFormRef" :model="form" :rules="rules" label-width="80px">
|
<el-form ref="demoFormRef" :model="form" :rules="rules" label-width="80px">
|
||||||
<el-form-item label="部门id" prop="deptId">
|
<el-form-item label="部门id" prop="deptId">
|
||||||
<el-input v-model="form.deptId" placeholder="请输入部门id" />
|
<el-input v-model="form.deptId" placeholder="请输入部门id" />
|
||||||
@ -129,8 +129,8 @@ const initFormData: DemoForm = {
|
|||||||
userId: undefined,
|
userId: undefined,
|
||||||
orderNum: undefined,
|
orderNum: undefined,
|
||||||
testKey: undefined,
|
testKey: undefined,
|
||||||
value: undefined,
|
value: undefined
|
||||||
}
|
};
|
||||||
const data = reactive<PageData<DemoForm, DemoQuery>>({
|
const data = reactive<PageData<DemoForm, DemoQuery>>({
|
||||||
form: { ...initFormData },
|
form: { ...initFormData },
|
||||||
queryParams: {
|
queryParams: {
|
||||||
@ -140,27 +140,15 @@ const data = reactive<PageData<DemoForm, DemoQuery>>({
|
|||||||
userId: undefined,
|
userId: undefined,
|
||||||
orderNum: undefined,
|
orderNum: undefined,
|
||||||
testKey: undefined,
|
testKey: undefined,
|
||||||
value: undefined,
|
value: undefined
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
id: [
|
id: [{ required: true, message: '主键不能为空', trigger: 'blur' }],
|
||||||
{ required: true, message: "主键不能为空", trigger: "blur" }
|
deptId: [{ required: true, message: '部门id不能为空', trigger: 'blur' }],
|
||||||
],
|
userId: [{ required: true, message: '用户id不能为空', trigger: 'blur' }],
|
||||||
deptId: [
|
orderNum: [{ required: true, message: '排序号不能为空', trigger: 'blur' }],
|
||||||
{ required: true, message: "部门id不能为空", trigger: "blur" }
|
testKey: [{ required: true, message: 'key键不能为空', trigger: 'blur' }],
|
||||||
],
|
value: [{ required: true, message: '值不能为空', trigger: 'blur' }]
|
||||||
userId: [
|
|
||||||
{ required: true, message: "用户id不能为空", trigger: "blur" }
|
|
||||||
],
|
|
||||||
orderNum: [
|
|
||||||
{ required: true, message: "排序号不能为空", trigger: "blur" }
|
|
||||||
],
|
|
||||||
testKey: [
|
|
||||||
{ required: true, message: "key键不能为空", trigger: "blur" }
|
|
||||||
],
|
|
||||||
value: [
|
|
||||||
{ required: true, message: "值不能为空", trigger: "blur" }
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -173,55 +161,55 @@ const getList = async () => {
|
|||||||
demoList.value = res.rows;
|
demoList.value = res.rows;
|
||||||
total.value = res.total;
|
total.value = res.total;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
reset();
|
reset();
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 表单重置 */
|
/** 表单重置 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
form.value = { ...initFormData };
|
form.value = { ...initFormData };
|
||||||
demoFormRef.value?.resetFields();
|
demoFormRef.value?.resetFields();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
handleQuery();
|
handleQuery();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 多选框选中数据 */
|
/** 多选框选中数据 */
|
||||||
const handleSelectionChange = (selection: DemoVO[]) => {
|
const handleSelectionChange = (selection: DemoVO[]) => {
|
||||||
ids.value = selection.map(item => item.id);
|
ids.value = selection.map((item) => item.id);
|
||||||
single.value = selection.length != 1;
|
single.value = selection.length != 1;
|
||||||
multiple.value = !selection.length;
|
multiple.value = !selection.length;
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 新增按钮操作 */
|
/** 新增按钮操作 */
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
reset();
|
reset();
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "添加测试单";
|
dialog.title = '添加测试单';
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
const handleUpdate = async (row?: DemoVO) => {
|
const handleUpdate = async (row?: DemoVO) => {
|
||||||
reset();
|
reset();
|
||||||
const _id = row?.id || ids.value[0]
|
const _id = row?.id || ids.value[0];
|
||||||
const res = await getDemo(_id);
|
const res = await getDemo(_id);
|
||||||
Object.assign(form.value, res.data);
|
Object.assign(form.value, res.data);
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "修改测试单";
|
dialog.title = '修改测试单';
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
@ -229,32 +217,36 @@ const submitForm = () => {
|
|||||||
if (valid) {
|
if (valid) {
|
||||||
buttonLoading.value = true;
|
buttonLoading.value = true;
|
||||||
if (form.value.id) {
|
if (form.value.id) {
|
||||||
await updateDemo(form.value).finally(() => buttonLoading.value = false);
|
await updateDemo(form.value).finally(() => (buttonLoading.value = false));
|
||||||
} else {
|
} else {
|
||||||
await addDemo(form.value).finally(() => buttonLoading.value = false);
|
await addDemo(form.value).finally(() => (buttonLoading.value = false));
|
||||||
}
|
}
|
||||||
proxy?.$modal.msgSuccess("修改成功");
|
proxy?.$modal.msgSuccess('修改成功');
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
await getList();
|
await getList();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row?: DemoVO) => {
|
const handleDelete = async (row?: DemoVO) => {
|
||||||
const _ids = row?.id || ids.value;
|
const _ids = row?.id || ids.value;
|
||||||
await proxy?.$modal.confirm('是否确认删除测试单编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
|
await proxy?.$modal.confirm('是否确认删除测试单编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
|
||||||
await delDemo(_ids);
|
await delDemo(_ids);
|
||||||
proxy?.$modal.msgSuccess("删除成功");
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
await getList();
|
await getList();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 导出按钮操作 */
|
/** 导出按钮操作 */
|
||||||
const handleExport = () => {
|
const handleExport = () => {
|
||||||
proxy?.download('demo/demo/export', {
|
proxy?.download(
|
||||||
...queryParams.value
|
'demo/demo/export',
|
||||||
}, `demo_${new Date().getTime()}.xlsx`)
|
{
|
||||||
}
|
...queryParams.value
|
||||||
|
},
|
||||||
|
`demo_${new Date().getTime()}.xlsx`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
<div class="mb-[10px]" v-show="showSearch">
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
|
||||||
<el-form-item label="树节点名" prop="treeName">
|
<el-form-item label="树节点名" prop="treeName">
|
||||||
<el-input v-model="queryParams.treeName" placeholder="请输入树节点名" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.treeName" placeholder="请输入树节点名" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -20,21 +20,21 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['demo:tree:add']">新增</el-button>
|
<el-button v-hasPermi="['demo:tree:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
|
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
<el-table
|
<el-table
|
||||||
|
ref="treeTableRef"
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
:data="treeList"
|
:data="treeList"
|
||||||
row-key="id"
|
row-key="id"
|
||||||
:default-expand-all="isExpandAll"
|
:default-expand-all="isExpandAll"
|
||||||
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
|
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||||
ref="treeTableRef"
|
|
||||||
>
|
>
|
||||||
<el-table-column label="父id" align="center" prop="parentId" />
|
<el-table-column label="父id" align="center" prop="parentId" />
|
||||||
<el-table-column label="部门id" align="center" prop="deptId" />
|
<el-table-column label="部门id" align="center" prop="deptId" />
|
||||||
@ -43,20 +43,20 @@
|
|||||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="修改" placement="top">
|
<el-tooltip content="修改" placement="top">
|
||||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['demo:tree:edit']" />
|
<el-button v-hasPermi="['demo:tree:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="新增" placement="top">
|
<el-tooltip content="新增" placement="top">
|
||||||
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['demo:tree:add']" />
|
<el-button v-hasPermi="['demo:tree:add']" link type="primary" icon="Plus" @click="handleAdd(scope.row)" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="删除" placement="top">
|
<el-tooltip content="删除" placement="top">
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['demo:tree:remove']" />
|
<el-button v-hasPermi="['demo:tree:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-card>
|
</el-card>
|
||||||
<!-- 添加或修改测试树对话框 -->
|
<!-- 添加或修改测试树对话框 -->
|
||||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
<el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
|
||||||
<el-form ref="treeFormRef" :model="form" :rules="rules" label-width="80px">
|
<el-form ref="treeFormRef" :model="form" :rules="rules" label-width="80px">
|
||||||
<el-form-item label="父id" prop="parentId">
|
<el-form-item label="父id" prop="parentId">
|
||||||
<el-tree-select
|
<el-tree-select
|
||||||
@ -89,18 +89,16 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="Tree" lang="ts">
|
<script setup name="Tree" lang="ts">
|
||||||
import { listTree, getTree, delTree, addTree, updateTree } from "@/api/demo/tree";
|
import { listTree, getTree, delTree, addTree, updateTree } from '@/api/demo/tree';
|
||||||
import { TreeVO, TreeQuery, TreeForm } from '@/api/demo/tree/types';
|
import { TreeVO, TreeQuery, TreeForm } from '@/api/demo/tree/types';
|
||||||
|
|
||||||
|
|
||||||
type TreeOption = {
|
type TreeOption = {
|
||||||
id: number;
|
id: number;
|
||||||
treeName: string;
|
treeName: string;
|
||||||
children?: TreeOption[];
|
children?: TreeOption[];
|
||||||
}
|
};
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;;
|
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
|
||||||
const treeList = ref<TreeVO[]>([]);
|
const treeList = ref<TreeVO[]>([]);
|
||||||
const treeOptions = ref<TreeOption[]>([]);
|
const treeOptions = ref<TreeOption[]>([]);
|
||||||
@ -111,46 +109,35 @@ const loading = ref(false);
|
|||||||
|
|
||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
const treeFormRef = ref<ElFormInstance>();
|
const treeFormRef = ref<ElFormInstance>();
|
||||||
const treeTableRef = ref<ElTableInstance>()
|
const treeTableRef = ref<ElTableInstance>();
|
||||||
|
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = reactive<DialogOption>({
|
||||||
visible: false,
|
visible: false,
|
||||||
title: ''
|
title: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const initFormData: TreeForm = {
|
const initFormData: TreeForm = {
|
||||||
id: undefined,
|
id: undefined,
|
||||||
parentId: undefined,
|
parentId: undefined,
|
||||||
deptId: undefined,
|
deptId: undefined,
|
||||||
userId: undefined,
|
userId: undefined,
|
||||||
treeName: undefined,
|
treeName: undefined
|
||||||
}
|
};
|
||||||
|
|
||||||
const data = reactive<PageData<TreeForm, TreeQuery>>({
|
const data = reactive<PageData<TreeForm, TreeQuery>>({
|
||||||
form: {...initFormData},
|
form: { ...initFormData },
|
||||||
queryParams: {
|
queryParams: {
|
||||||
parentId: undefined,
|
parentId: undefined,
|
||||||
deptId: undefined,
|
deptId: undefined,
|
||||||
userId: undefined,
|
userId: undefined,
|
||||||
treeName: undefined,
|
treeName: undefined
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
id: [
|
id: [{ required: true, message: '主键不能为空', trigger: 'blur' }],
|
||||||
{ required: true, message: "主键不能为空", trigger: "blur" }
|
parentId: [{ required: true, message: '父id不能为空', trigger: 'blur' }],
|
||||||
],
|
deptId: [{ required: true, message: '部门id不能为空', trigger: 'blur' }],
|
||||||
parentId: [
|
userId: [{ required: true, message: '用户id不能为空', trigger: 'blur' }],
|
||||||
{ required: true, message: "父id不能为空", trigger: "blur" }
|
treeName: [{ required: true, message: '值不能为空', trigger: 'blur' }]
|
||||||
],
|
|
||||||
deptId: [
|
|
||||||
{ required: true, message: "部门id不能为空", trigger: "blur" }
|
|
||||||
],
|
|
||||||
userId: [
|
|
||||||
{ required: true, message: "用户id不能为空", trigger: "blur" }
|
|
||||||
],
|
|
||||||
treeName: [
|
|
||||||
{ required: true, message: "值不能为空", trigger: "blur" }
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -160,44 +147,44 @@ const { queryParams, form, rules } = toRefs(data);
|
|||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const res = await listTree(queryParams.value);
|
const res = await listTree(queryParams.value);
|
||||||
const data = proxy?.handleTree<TreeVO>(res.data, "id", "parentId");
|
const data = proxy?.handleTree<TreeVO>(res.data, 'id', 'parentId');
|
||||||
if (data) {
|
if (data) {
|
||||||
treeList.value = data;
|
treeList.value = data;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 查询测试树下拉树结构 */
|
/** 查询测试树下拉树结构 */
|
||||||
const getTreeselect = async () => {
|
const getTreeselect = async () => {
|
||||||
const res = await listTree();
|
const res = await listTree();
|
||||||
treeOptions.value = [];
|
treeOptions.value = [];
|
||||||
const data: TreeOption = { id: 0, treeName: '顶级节点', children: [] };
|
const data: TreeOption = { id: 0, treeName: '顶级节点', children: [] };
|
||||||
data.children = proxy?.handleTree<TreeOption>(res.data, "id", "parentId");
|
data.children = proxy?.handleTree<TreeOption>(res.data, 'id', 'parentId');
|
||||||
treeOptions.value.push(data);
|
treeOptions.value.push(data);
|
||||||
}
|
};
|
||||||
|
|
||||||
// 取消按钮
|
// 取消按钮
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
reset();
|
reset();
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
// 表单重置
|
// 表单重置
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
form.value = {...initFormData}
|
form.value = { ...initFormData };
|
||||||
treeFormRef.value?.resetFields();
|
treeFormRef.value?.resetFields();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
handleQuery();
|
handleQuery();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 新增按钮操作 */
|
/** 新增按钮操作 */
|
||||||
const handleAdd = (row?: TreeVO) => {
|
const handleAdd = (row?: TreeVO) => {
|
||||||
@ -209,22 +196,22 @@ const handleAdd = (row?: TreeVO) => {
|
|||||||
form.value.parentId = 0;
|
form.value.parentId = 0;
|
||||||
}
|
}
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "添加测试树";
|
dialog.title = '添加测试树';
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 展开/折叠操作 */
|
/** 展开/折叠操作 */
|
||||||
const handleToggleExpandAll = () => {
|
const handleToggleExpandAll = () => {
|
||||||
isExpandAll.value = !isExpandAll.value;
|
isExpandAll.value = !isExpandAll.value;
|
||||||
toggleExpandAll(treeList.value, isExpandAll.value)
|
toggleExpandAll(treeList.value, isExpandAll.value);
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 展开/折叠操作 */
|
/** 展开/折叠操作 */
|
||||||
const toggleExpandAll = (data: TreeVO[], status: boolean) => {
|
const toggleExpandAll = (data: TreeVO[], status: boolean) => {
|
||||||
data.forEach((item) => {
|
data.forEach((item) => {
|
||||||
treeTableRef.value?.toggleRowExpansion(item, status)
|
treeTableRef.value?.toggleRowExpansion(item, status);
|
||||||
if (item.children && item.children.length > 0) toggleExpandAll(item.children, status)
|
if (item.children && item.children.length > 0) toggleExpandAll(item.children, status);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
const handleUpdate = async (row: TreeVO) => {
|
const handleUpdate = async (row: TreeVO) => {
|
||||||
@ -236,8 +223,8 @@ const handleUpdate = async (row: TreeVO) => {
|
|||||||
const res = await getTree(row.id);
|
const res = await getTree(row.id);
|
||||||
Object.assign(form.value, res.data);
|
Object.assign(form.value, res.data);
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "修改测试树";
|
dialog.title = '修改测试树';
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
@ -245,25 +232,25 @@ const submitForm = () => {
|
|||||||
if (valid) {
|
if (valid) {
|
||||||
buttonLoading.value = true;
|
buttonLoading.value = true;
|
||||||
if (form.value.id) {
|
if (form.value.id) {
|
||||||
await updateTree(form.value).finally(() => buttonLoading.value = false);
|
await updateTree(form.value).finally(() => (buttonLoading.value = false));
|
||||||
} else {
|
} else {
|
||||||
await addTree(form.value).finally(() => buttonLoading.value = false);
|
await addTree(form.value).finally(() => (buttonLoading.value = false));
|
||||||
}
|
}
|
||||||
proxy?.$modal.msgSuccess("操作成功");
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
await getList();
|
await getList();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row: TreeVO) => {
|
const handleDelete = async (row: TreeVO) => {
|
||||||
await proxy?.$modal.confirm('是否确认删除测试树编号为"' + row.id + '"的数据项?');
|
await proxy?.$modal.confirm('是否确认删除测试树编号为"' + row.id + '"的数据项?');
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
await delTree(row.id).finally(() => loading.value = false);
|
await delTree(row.id).finally(() => (loading.value = false));
|
||||||
await getList();
|
await getList();
|
||||||
proxy?.$modal.msgSuccess("删除成功");
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
}
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
|
|||||||
@ -24,11 +24,11 @@ import errImage from '@/assets/401_images/401.gif';
|
|||||||
|
|
||||||
let { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
let { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
|
||||||
const errGif = ref(errImage + "?" + +new Date());
|
const errGif = ref(errImage + '?' + +new Date());
|
||||||
|
|
||||||
function back() {
|
function back() {
|
||||||
if (proxy?.$route.query.noGoBack) {
|
if (proxy?.$route.query.noGoBack) {
|
||||||
proxy.$router.push({ path: "/" });
|
proxy.$router.push({ path: '/' });
|
||||||
} else {
|
} else {
|
||||||
proxy?.$router.go(-1);
|
proxy?.$router.go(-1);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,13 +23,13 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
let message = computed(() => {
|
let message = computed(() => {
|
||||||
return '找不到网页!'
|
return '找不到网页!';
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.wscn-http404-container{
|
.wscn-http404-container {
|
||||||
transform: translate(-50%,-50%);
|
transform: translate(-50%, -50%);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 40%;
|
top: 40%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
|
|||||||
@ -99,13 +99,13 @@
|
|||||||
import { initWebSocket } from '@/utils/websocket';
|
import { initWebSocket } from '@/utils/websocket';
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
let protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://'
|
let protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://';
|
||||||
initWebSocket(protocol + window.location.host + import.meta.env.VITE_APP_BASE_API + "/resource/websocket");
|
initWebSocket(protocol + window.location.host + import.meta.env.VITE_APP_BASE_API + '/resource/websocket');
|
||||||
});
|
});
|
||||||
|
|
||||||
const goTarget = (url:string) => {
|
const goTarget = (url: string) => {
|
||||||
window.open(url, '__blank')
|
window.open(url, '__blank');
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@ -131,7 +131,7 @@ const goTarget = (url:string) => {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
font-family: 'open sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #676a6c;
|
color: #676a6c;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<div class="login">
|
<div class="login">
|
||||||
<el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
|
<el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
|
||||||
<h3 class="title">RuoYi-Vue-Plus多租户管理系统</h3>
|
<h3 class="title">RuoYi-Vue-Plus多租户管理系统</h3>
|
||||||
<el-form-item prop="tenantId" v-if="tenantEnabled">
|
<el-form-item v-if="tenantEnabled" prop="tenantId">
|
||||||
<el-select v-model="loginForm.tenantId" filterable placeholder="请选择/输入公司名称" style="width: 100%">
|
<el-select v-model="loginForm.tenantId" filterable placeholder="请选择/输入公司名称" style="width: 100%">
|
||||||
<el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"></el-option>
|
<el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"></el-option>
|
||||||
<template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
|
<template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
|
||||||
@ -18,16 +18,16 @@
|
|||||||
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
|
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="code" v-if="captchaEnabled">
|
<el-form-item v-if="captchaEnabled" prop="code">
|
||||||
<el-input v-model="loginForm.code" size="large" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter="handleLogin">
|
<el-input v-model="loginForm.code" size="large" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter="handleLogin">
|
||||||
<template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
|
<template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
|
||||||
</el-input>
|
</el-input>
|
||||||
<div class="login-code">
|
<div class="login-code">
|
||||||
<img :src="codeUrl" @click="getCode" class="login-code-img" />
|
<img :src="codeUrl" class="login-code-img" @click="getCode" />
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
|
<el-checkbox v-model="loginForm.rememberMe" style="margin: 0px 0px 25px 0px">记住密码</el-checkbox>
|
||||||
<el-form-item style="float: right;">
|
<el-form-item style="float: right">
|
||||||
<el-button circle title="微信登录" @click="doSocialLogin('wechat')">
|
<el-button circle title="微信登录" @click="doSocialLogin('wechat')">
|
||||||
<svg-icon icon-class="wechat" />
|
<svg-icon icon-class="wechat" />
|
||||||
</el-button>
|
</el-button>
|
||||||
@ -41,12 +41,12 @@
|
|||||||
<svg-icon icon-class="github" />
|
<svg-icon icon-class="github" />
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item style="width:100%;">
|
<el-form-item style="width: 100%">
|
||||||
<el-button :loading="loading" size="large" type="primary" style="width:100%;" @click.prevent="handleLogin">
|
<el-button :loading="loading" size="large" type="primary" style="width: 100%" @click.prevent="handleLogin">
|
||||||
<span v-if="!loading">登 录</span>
|
<span v-if="!loading">登 录</span>
|
||||||
<span v-else>登 录 中...</span>
|
<span v-else>登 录 中...</span>
|
||||||
</el-button>
|
</el-button>
|
||||||
<div style="float: right;" v-if="register">
|
<div v-if="register" style="float: right">
|
||||||
<router-link class="link-type" :to="'/register'">立即注册</router-link>
|
<router-link class="link-type" :to="'/register'">立即注册</router-link>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -64,7 +64,7 @@ import { authBinding } from '@/api/system/social/auth';
|
|||||||
import { useUserStore } from '@/store/modules/user';
|
import { useUserStore } from '@/store/modules/user';
|
||||||
import { LoginData, TenantVO } from '@/api/types';
|
import { LoginData, TenantVO } from '@/api/types';
|
||||||
import { to } from 'await-to-js';
|
import { to } from 'await-to-js';
|
||||||
import { HttpStatus } from "@/enums/RespEnum";
|
import { HttpStatus } from '@/enums/RespEnum';
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -79,7 +79,7 @@ const loginForm = ref<LoginData>({
|
|||||||
} as LoginData);
|
} as LoginData);
|
||||||
|
|
||||||
const loginRules: ElFormRules = {
|
const loginRules: ElFormRules = {
|
||||||
tenantId: [{ required: true, trigger: "blur", message: "请输入您的租户编号" }],
|
tenantId: [{ required: true, trigger: 'blur', message: '请输入您的租户编号' }],
|
||||||
username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
|
username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
|
||||||
password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }],
|
password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }],
|
||||||
code: [{ required: true, trigger: 'change', message: '请输入验证码' }]
|
code: [{ required: true, trigger: 'change', message: '请输入验证码' }]
|
||||||
@ -92,7 +92,6 @@ const captchaEnabled = ref(true);
|
|||||||
// 租户开关
|
// 租户开关
|
||||||
const tenantEnabled = ref(true);
|
const tenantEnabled = ref(true);
|
||||||
|
|
||||||
|
|
||||||
// 注册开关
|
// 注册开关
|
||||||
const register = ref(false);
|
const register = ref(false);
|
||||||
const redirect = ref(undefined);
|
const redirect = ref(undefined);
|
||||||
@ -100,9 +99,13 @@ const loginRef = ref<ElFormInstance>();
|
|||||||
// 租户列表
|
// 租户列表
|
||||||
const tenantList = ref<TenantVO[]>([]);
|
const tenantList = ref<TenantVO[]>([]);
|
||||||
|
|
||||||
watch(() => router.currentRoute.value, (newRoute: any) => {
|
watch(
|
||||||
redirect.value = newRoute.query && newRoute.query.redirect;
|
() => router.currentRoute.value,
|
||||||
}, { immediate: true });
|
(newRoute: any) => {
|
||||||
|
redirect.value = newRoute.query && newRoute.query.redirect;
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
const handleLogin = () => {
|
const handleLogin = () => {
|
||||||
loginRef.value?.validate(async (valid: boolean, fields: any) => {
|
loginRef.value?.validate(async (valid: boolean, fields: any) => {
|
||||||
@ -110,13 +113,13 @@ const handleLogin = () => {
|
|||||||
loading.value = true;
|
loading.value = true;
|
||||||
// 勾选了需要记住密码设置在 localStorage 中设置记住用户名和密码
|
// 勾选了需要记住密码设置在 localStorage 中设置记住用户名和密码
|
||||||
if (loginForm.value.rememberMe) {
|
if (loginForm.value.rememberMe) {
|
||||||
localStorage.setItem("tenantId", String(loginForm.value.tenantId));
|
localStorage.setItem('tenantId', String(loginForm.value.tenantId));
|
||||||
localStorage.setItem('username', String(loginForm.value.username));
|
localStorage.setItem('username', String(loginForm.value.username));
|
||||||
localStorage.setItem('password', String(loginForm.value.password));
|
localStorage.setItem('password', String(loginForm.value.password));
|
||||||
localStorage.setItem('rememberMe', String(loginForm.value.rememberMe));
|
localStorage.setItem('rememberMe', String(loginForm.value.rememberMe));
|
||||||
} else {
|
} else {
|
||||||
// 否则移除
|
// 否则移除
|
||||||
localStorage.removeItem("tenantId");
|
localStorage.removeItem('tenantId');
|
||||||
localStorage.removeItem('username');
|
localStorage.removeItem('username');
|
||||||
localStorage.removeItem('password');
|
localStorage.removeItem('password');
|
||||||
localStorage.removeItem('rememberMe');
|
localStorage.removeItem('rememberMe');
|
||||||
@ -153,7 +156,7 @@ const getCode = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getLoginData = () => {
|
const getLoginData = () => {
|
||||||
const tenantId = localStorage.getItem("tenantId");
|
const tenantId = localStorage.getItem('tenantId');
|
||||||
const username = localStorage.getItem('username');
|
const username = localStorage.getItem('username');
|
||||||
const password = localStorage.getItem('password');
|
const password = localStorage.getItem('password');
|
||||||
const rememberMe = localStorage.getItem('rememberMe');
|
const rememberMe = localStorage.getItem('rememberMe');
|
||||||
@ -163,8 +166,7 @@ const getLoginData = () => {
|
|||||||
password: password === null ? String(loginForm.value.password) : String(password),
|
password: password === null ? String(loginForm.value.password) : String(password),
|
||||||
rememberMe: rememberMe === null ? false : Boolean(rememberMe)
|
rememberMe: rememberMe === null ? false : Boolean(rememberMe)
|
||||||
} as LoginData;
|
} as LoginData;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取租户列表
|
* 获取租户列表
|
||||||
@ -178,12 +180,15 @@ const initTenantList = async () => {
|
|||||||
loginForm.value.tenantId = tenantList.value[0].tenantId;
|
loginForm.value.tenantId = tenantList.value[0].tenantId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
//检测租户选择框的变化
|
//检测租户选择框的变化
|
||||||
watch(() => loginForm.value.tenantId, () => {
|
watch(
|
||||||
localStorage.setItem("tenantId", String(loginForm.value.tenantId))
|
() => loginForm.value.tenantId,
|
||||||
});
|
() => {
|
||||||
|
localStorage.setItem('tenantId', String(loginForm.value.tenantId));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 第三方登录
|
* 第三方登录
|
||||||
@ -200,8 +205,6 @@ const doSocialLogin = (type: string) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getCode();
|
getCode();
|
||||||
initTenantList();
|
initTenantList();
|
||||||
@ -215,7 +218,7 @@ onMounted(() => {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-image: url("../assets/images/login-background.jpg");
|
background-image: url('../assets/images/login-background.jpg');
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
74
src/views/monitor/cache/index.vue
vendored
74
src/views/monitor/cache/index.vue
vendored
@ -4,8 +4,8 @@
|
|||||||
<el-col :span="24" class="card-box">
|
<el-col :span="24" class="card-box">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<template #header>
|
<template #header>
|
||||||
<Monitor style="width: 1em; height: 1em; vertical-align: middle;" />
|
<Monitor style="width: 1em; height: 1em; vertical-align: middle" />
|
||||||
<span style="vertical-align: middle;">基本信息</span>
|
<span style="vertical-align: middle">基本信息</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="el-table el-table--enable-row-hover el-table--medium">
|
<div class="el-table el-table--enable-row-hover el-table--medium">
|
||||||
@ -16,25 +16,25 @@
|
|||||||
<div class="cell">Redis版本</div>
|
<div class="cell">Redis版本</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="el-table__cell is-leaf">
|
<td class="el-table__cell is-leaf">
|
||||||
<div class="cell" v-if="cache.info">{{ cache.info.redis_version }}</div>
|
<div v-if="cache.info" class="cell">{{ cache.info.redis_version }}</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="el-table__cell is-leaf">
|
<td class="el-table__cell is-leaf">
|
||||||
<div class="cell">运行模式</div>
|
<div class="cell">运行模式</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="el-table__cell is-leaf">
|
<td class="el-table__cell is-leaf">
|
||||||
<div class="cell" v-if="cache.info">{{ cache.info.redis_mode === "standalone" ? "单机" : "集群" }}</div>
|
<div v-if="cache.info" class="cell">{{ cache.info.redis_mode === 'standalone' ? '单机' : '集群' }}</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="el-table__cell is-leaf">
|
<td class="el-table__cell is-leaf">
|
||||||
<div class="cell">端口</div>
|
<div class="cell">端口</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="el-table__cell is-leaf">
|
<td class="el-table__cell is-leaf">
|
||||||
<div class="cell" v-if="cache.info">{{ cache.info.tcp_port }}</div>
|
<div v-if="cache.info" class="cell">{{ cache.info.tcp_port }}</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="el-table__cell is-leaf">
|
<td class="el-table__cell is-leaf">
|
||||||
<div class="cell">客户端数</div>
|
<div class="cell">客户端数</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="el-table__cell is-leaf">
|
<td class="el-table__cell is-leaf">
|
||||||
<div class="cell" v-if="cache.info">{{ cache.info.connected_clients }}</div>
|
<div v-if="cache.info" class="cell">{{ cache.info.connected_clients }}</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@ -42,25 +42,25 @@
|
|||||||
<div class="cell">运行时间(天)</div>
|
<div class="cell">运行时间(天)</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="el-table__cell is-leaf">
|
<td class="el-table__cell is-leaf">
|
||||||
<div class="cell" v-if="cache.info">{{ cache.info.uptime_in_days }}</div>
|
<div v-if="cache.info" class="cell">{{ cache.info.uptime_in_days }}</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="el-table__cell is-leaf">
|
<td class="el-table__cell is-leaf">
|
||||||
<div class="cell">使用内存</div>
|
<div class="cell">使用内存</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="el-table__cell is-leaf">
|
<td class="el-table__cell is-leaf">
|
||||||
<div class="cell" v-if="cache.info">{{ cache.info.used_memory_human }}</div>
|
<div v-if="cache.info" class="cell">{{ cache.info.used_memory_human }}</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="el-table__cell is-leaf">
|
<td class="el-table__cell is-leaf">
|
||||||
<div class="cell">使用CPU</div>
|
<div class="cell">使用CPU</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="el-table__cell is-leaf">
|
<td class="el-table__cell is-leaf">
|
||||||
<div class="cell" v-if="cache.info">{{ parseFloat(cache.info.used_cpu_user_children).toFixed(2) }}</div>
|
<div v-if="cache.info" class="cell">{{ parseFloat(cache.info.used_cpu_user_children).toFixed(2) }}</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="el-table__cell is-leaf">
|
<td class="el-table__cell is-leaf">
|
||||||
<div class="cell">内存配置</div>
|
<div class="cell">内存配置</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="el-table__cell is-leaf">
|
<td class="el-table__cell is-leaf">
|
||||||
<div class="cell" v-if="cache.info">{{ cache.info.maxmemory_human }}</div>
|
<div v-if="cache.info" class="cell">{{ cache.info.maxmemory_human }}</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@ -68,25 +68,25 @@
|
|||||||
<div class="cell">AOF是否开启</div>
|
<div class="cell">AOF是否开启</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="el-table__cell is-leaf">
|
<td class="el-table__cell is-leaf">
|
||||||
<div class="cell" v-if="cache.info">{{ cache.info.aof_enabled === "0" ? "否" : "是" }}</div>
|
<div v-if="cache.info" class="cell">{{ cache.info.aof_enabled === '0' ? '否' : '是' }}</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="el-table__cell is-leaf">
|
<td class="el-table__cell is-leaf">
|
||||||
<div class="cell">RDB是否成功</div>
|
<div class="cell">RDB是否成功</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="el-table__cell is-leaf">
|
<td class="el-table__cell is-leaf">
|
||||||
<div class="cell" v-if="cache.info">{{ cache.info.rdb_last_bgsave_status }}</div>
|
<div v-if="cache.info" class="cell">{{ cache.info.rdb_last_bgsave_status }}</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="el-table__cell is-leaf">
|
<td class="el-table__cell is-leaf">
|
||||||
<div class="cell">Key数量</div>
|
<div class="cell">Key数量</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="el-table__cell is-leaf">
|
<td class="el-table__cell is-leaf">
|
||||||
<div class="cell" v-if="cache.dbSize">{{ cache.dbSize }}</div>
|
<div v-if="cache.dbSize" class="cell">{{ cache.dbSize }}</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="el-table__cell is-leaf">
|
<td class="el-table__cell is-leaf">
|
||||||
<div class="cell">网络入口/出口</div>
|
<div class="cell">网络入口/出口</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="el-table__cell is-leaf">
|
<td class="el-table__cell is-leaf">
|
||||||
<div class="cell" v-if="cache.info">
|
<div v-if="cache.info" class="cell">
|
||||||
{{ cache.info.instantaneous_input_kbps }}kps/{{ cache.info.instantaneous_output_kbps }}kps
|
{{ cache.info.instantaneous_input_kbps }}kps/{{ cache.info.instantaneous_output_kbps }}kps
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@ -100,8 +100,8 @@
|
|||||||
<el-col :span="12" class="card-box">
|
<el-col :span="12" class="card-box">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<template #header>
|
<template #header>
|
||||||
<PieChart style="width: 1em; height: 1em; vertical-align: middle;" />
|
<PieChart style="width: 1em; height: 1em; vertical-align: middle" />
|
||||||
<span style="vertical-align: middle;">命令统计</span>
|
<span style="vertical-align: middle">命令统计</span>
|
||||||
</template>
|
</template>
|
||||||
<div class="el-table el-table--enable-row-hover el-table--medium">
|
<div class="el-table el-table--enable-row-hover el-table--medium">
|
||||||
<div ref="commandstats" style="height: 420px" />
|
<div ref="commandstats" style="height: 420px" />
|
||||||
@ -112,7 +112,7 @@
|
|||||||
<el-col :span="12" class="card-box">
|
<el-col :span="12" class="card-box">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<template #header>
|
<template #header>
|
||||||
<Odometer style="width: 1em; height: 1em; vertical-align: middle;" /> <span style="vertical-align: middle;">内存信息</span>
|
<Odometer style="width: 1em; height: 1em; vertical-align: middle" /> <span style="vertical-align: middle">内存信息</span>
|
||||||
</template>
|
</template>
|
||||||
<div class="el-table el-table--enable-row-hover el-table--medium">
|
<div class="el-table el-table--enable-row-hover el-table--medium">
|
||||||
<div ref="usedmemory" style="height: 420px" />
|
<div ref="usedmemory" style="height: 420px" />
|
||||||
@ -133,38 +133,38 @@ const usedmemory = ref();
|
|||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
proxy?.$modal.loading("正在加载缓存监控数据,请稍候!");
|
proxy?.$modal.loading('正在加载缓存监控数据,请稍候!');
|
||||||
const res = await getCache();
|
const res = await getCache();
|
||||||
proxy?.$modal.closeLoading();
|
proxy?.$modal.closeLoading();
|
||||||
cache.value = res.data;
|
cache.value = res.data;
|
||||||
const commandstatsIntance = echarts.init(commandstats.value, "macarons");
|
const commandstatsIntance = echarts.init(commandstats.value, 'macarons');
|
||||||
commandstatsIntance.setOption({
|
commandstatsIntance.setOption({
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: "item",
|
trigger: 'item',
|
||||||
formatter: "{a} <br/>{b} : {c} ({d}%)"
|
formatter: '{a} <br/>{b} : {c} ({d}%)'
|
||||||
},
|
},
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
name: "命令",
|
name: '命令',
|
||||||
type: "pie",
|
type: 'pie',
|
||||||
roseType: "radius",
|
roseType: 'radius',
|
||||||
radius: [15, 95],
|
radius: [15, 95],
|
||||||
center: ["50%", "38%"],
|
center: ['50%', '38%'],
|
||||||
data: res.data.commandStats,
|
data: res.data.commandStats,
|
||||||
animationEasing: "cubicInOut",
|
animationEasing: 'cubicInOut',
|
||||||
animationDuration: 1000
|
animationDuration: 1000
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
const usedmemoryInstance = echarts.init(usedmemory.value, "macarons");
|
const usedmemoryInstance = echarts.init(usedmemory.value, 'macarons');
|
||||||
usedmemoryInstance.setOption({
|
usedmemoryInstance.setOption({
|
||||||
tooltip: {
|
tooltip: {
|
||||||
formatter: "{b} <br/>{a} : " + cache.value.info.used_memory_human
|
formatter: '{b} <br/>{a} : ' + cache.value.info.used_memory_human
|
||||||
},
|
},
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
name: "峰值",
|
name: '峰值',
|
||||||
type: "gauge",
|
type: 'gauge',
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 1000,
|
max: 1000,
|
||||||
detail: {
|
detail: {
|
||||||
@ -173,19 +173,19 @@ const getList = async () => {
|
|||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
value: parseFloat(cache.value.info.used_memory_human),
|
value: parseFloat(cache.value.info.used_memory_human),
|
||||||
name: "内存消耗"
|
name: '内存消耗'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
|
||||||
window.addEventListener("resize",()=>{
|
|
||||||
commandstatsIntance.resize()
|
|
||||||
usedmemoryInstance.resize()
|
|
||||||
});
|
});
|
||||||
}
|
window.addEventListener('resize', () => {
|
||||||
|
commandstatsIntance.resize();
|
||||||
|
usedmemoryInstance.resize();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
<div class="mb-[10px]" v-show="showSearch">
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
|
||||||
<el-form-item label="登录地址" prop="ipaddr">
|
<el-form-item label="登录地址" prop="ipaddr">
|
||||||
<el-input v-model="queryParams.ipaddr" placeholder="请输入登录地址" clearable style="width: 240px;" @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.ipaddr" placeholder="请输入登录地址" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="用户名称" prop="userName">
|
<el-form-item label="用户名称" prop="userName">
|
||||||
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px;" @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="状态" prop="status">
|
<el-form-item label="状态" prop="status">
|
||||||
<el-select v-model="queryParams.status" placeholder="登录状态" clearable style="width: 240px">
|
<el-select v-model="queryParams.status" placeholder="登录状态" clearable style="width: 240px">
|
||||||
@ -39,22 +39,22 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['monitor:logininfor:remove']">
|
<el-button v-hasPermi="['monitor:logininfor:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="danger" plain icon="Delete" @click="handleClean" v-hasPermi="['monitor:logininfor:remove']">清空</el-button>
|
<el-button v-hasPermi="['monitor:logininfor:remove']" type="danger" plain icon="Delete" @click="handleClean">清空</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Unlock" :disabled="single" @click="handleUnlock" v-hasPermi="['monitor:logininfor:unlock']">
|
<el-button v-hasPermi="['monitor:logininfor:unlock']" type="primary" plain icon="Unlock" :disabled="single" @click="handleUnlock">
|
||||||
解锁
|
解锁
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['monitor:logininfor:export']">导出</el-button>
|
<el-button v-hasPermi="['monitor:logininfor:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -62,8 +62,8 @@
|
|||||||
ref="loginInfoTableRef"
|
ref="loginInfoTableRef"
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
:data="loginInfoList"
|
:data="loginInfoList"
|
||||||
@selection-change="handleSelectionChange"
|
|
||||||
:default-sort="defaultSort"
|
:default-sort="defaultSort"
|
||||||
|
@selection-change="handleSelectionChange"
|
||||||
@sort-change="handleSortChange"
|
@sort-change="handleSortChange"
|
||||||
>
|
>
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
@ -99,18 +99,18 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="Logininfor" lang="ts">
|
<script setup name="Logininfor" lang="ts">
|
||||||
import { list, delLoginInfo, cleanLoginInfo, unlockLoginInfo } from "@/api/monitor/loginInfo";
|
import { list, delLoginInfo, cleanLoginInfo, unlockLoginInfo } from '@/api/monitor/loginInfo';
|
||||||
import { LoginInfoQuery, LoginInfoVO } from "@/api/monitor/loginInfo/types";
|
import { LoginInfoQuery, LoginInfoVO } from '@/api/monitor/loginInfo/types';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const { sys_device_type } = toRefs<any>(proxy?.useDict("sys_device_type"));
|
const { sys_device_type } = toRefs<any>(proxy?.useDict('sys_device_type'));
|
||||||
const { sys_common_status } = toRefs<any>(proxy?.useDict("sys_common_status"));
|
const { sys_common_status } = toRefs<any>(proxy?.useDict('sys_common_status'));
|
||||||
|
|
||||||
const loginInfoList = ref<LoginInfoVO[]>([]);
|
const loginInfoList = ref<LoginInfoVO[]>([]);
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
@ -120,85 +120,89 @@ const single = ref(true);
|
|||||||
const multiple = ref(true);
|
const multiple = ref(true);
|
||||||
const selectName = ref<Array<string>>([]);
|
const selectName = ref<Array<string>>([]);
|
||||||
const total = ref(0);
|
const total = ref(0);
|
||||||
const dateRange = ref<[DateModelType,DateModelType]>(['', '']);
|
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
|
||||||
const defaultSort = ref<any>({ prop: "loginTime", order: "descending" });
|
const defaultSort = ref<any>({ prop: 'loginTime', order: 'descending' });
|
||||||
|
|
||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
const loginInfoTableRef = ref<ElTableInstance>();
|
const loginInfoTableRef = ref<ElTableInstance>();
|
||||||
// 查询参数
|
// 查询参数
|
||||||
const queryParams = ref<LoginInfoQuery>({
|
const queryParams = ref<LoginInfoQuery>({
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
ipaddr: '',
|
ipaddr: '',
|
||||||
userName: '',
|
userName: '',
|
||||||
status: '',
|
status: '',
|
||||||
orderByColumn: defaultSort.value.prop,
|
orderByColumn: defaultSort.value.prop,
|
||||||
isAsc: defaultSort.value.order
|
isAsc: defaultSort.value.order
|
||||||
});
|
});
|
||||||
|
|
||||||
/** 查询登录日志列表 */
|
/** 查询登录日志列表 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const res = await list(proxy?.addDateRange(queryParams.value, dateRange.value));
|
const res = await list(proxy?.addDateRange(queryParams.value, dateRange.value));
|
||||||
loginInfoList.value = res.rows;
|
loginInfoList.value = res.rows;
|
||||||
total.value = res.total;
|
total.value = res.total;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
};
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
dateRange.value = ['', ''];
|
dateRange.value = ['', ''];
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
loginInfoTableRef.value?.sort(defaultSort.value.prop, defaultSort.value.order);
|
loginInfoTableRef.value?.sort(defaultSort.value.prop, defaultSort.value.order);
|
||||||
}
|
};
|
||||||
/** 多选框选中数据 */
|
/** 多选框选中数据 */
|
||||||
const handleSelectionChange = (selection: LoginInfoVO[]) => {
|
const handleSelectionChange = (selection: LoginInfoVO[]) => {
|
||||||
ids.value = selection.map(item => item.infoId);
|
ids.value = selection.map((item) => item.infoId);
|
||||||
multiple.value = !selection.length;
|
multiple.value = !selection.length;
|
||||||
single.value = selection.length != 1;
|
single.value = selection.length != 1;
|
||||||
selectName.value = selection.map(item => item.userName);
|
selectName.value = selection.map((item) => item.userName);
|
||||||
}
|
};
|
||||||
/** 排序触发事件 */
|
/** 排序触发事件 */
|
||||||
const handleSortChange = (column: any) => {
|
const handleSortChange = (column: any) => {
|
||||||
queryParams.value.orderByColumn = column.prop;
|
queryParams.value.orderByColumn = column.prop;
|
||||||
queryParams.value.isAsc = column.order;
|
queryParams.value.isAsc = column.order;
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row?: LoginInfoVO) => {
|
const handleDelete = async (row?: LoginInfoVO) => {
|
||||||
const infoIds = row?.infoId || ids.value;
|
const infoIds = row?.infoId || ids.value;
|
||||||
await proxy?.$modal.confirm('是否确认删除访问编号为"' + infoIds + '"的数据项?');
|
await proxy?.$modal.confirm('是否确认删除访问编号为"' + infoIds + '"的数据项?');
|
||||||
await delLoginInfo(infoIds);
|
await delLoginInfo(infoIds);
|
||||||
await getList();
|
await getList();
|
||||||
proxy?.$modal.msgSuccess("删除成功");
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
}
|
};
|
||||||
/** 清空按钮操作 */
|
/** 清空按钮操作 */
|
||||||
const handleClean = async () => {
|
const handleClean = async () => {
|
||||||
await proxy?.$modal.confirm("是否确认清空所有登录日志数据项?");
|
await proxy?.$modal.confirm('是否确认清空所有登录日志数据项?');
|
||||||
await cleanLoginInfo();
|
await cleanLoginInfo();
|
||||||
await getList();
|
await getList();
|
||||||
proxy?.$modal.msgSuccess("清空成功");
|
proxy?.$modal.msgSuccess('清空成功');
|
||||||
}
|
};
|
||||||
/** 解锁按钮操作 */
|
/** 解锁按钮操作 */
|
||||||
const handleUnlock = async () => {
|
const handleUnlock = async () => {
|
||||||
const username = selectName.value;
|
const username = selectName.value;
|
||||||
await proxy?.$modal.confirm('是否确认解锁用户"' + username + '"数据项?');
|
await proxy?.$modal.confirm('是否确认解锁用户"' + username + '"数据项?');
|
||||||
await unlockLoginInfo(username);
|
await unlockLoginInfo(username);
|
||||||
proxy?.$modal.msgSuccess("用户" + username + "解锁成功");
|
proxy?.$modal.msgSuccess('用户' + username + '解锁成功');
|
||||||
}
|
};
|
||||||
/** 导出按钮操作 */
|
/** 导出按钮操作 */
|
||||||
const handleExport = () => {
|
const handleExport = () => {
|
||||||
proxy?.download("monitor/logininfor/export", {
|
proxy?.download(
|
||||||
...queryParams.value,
|
'monitor/logininfor/export',
|
||||||
}, `config_${new Date().getTime()}.xlsx`);
|
{
|
||||||
}
|
...queryParams.value
|
||||||
|
},
|
||||||
|
`config_${new Date().getTime()}.xlsx`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<div class="mb-[10px]">
|
<div class="mb-[10px]">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||||
<el-form-item label="登录地址" prop="ipaddr">
|
<el-form-item label="登录地址" prop="ipaddr">
|
||||||
<el-input v-model="queryParams.ipaddr" placeholder="请输入登录地址" clearable style="width: 200px" @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.ipaddr" placeholder="请输入登录地址" clearable style="width: 200px" @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -20,7 +20,7 @@
|
|||||||
<el-table
|
<el-table
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
:data="onlineList.slice((queryParams.pageNum - 1) * queryParams.pageSize, queryParams.pageNum * queryParams.pageSize)"
|
:data="onlineList.slice((queryParams.pageNum - 1) * queryParams.pageSize, queryParams.pageNum * queryParams.pageSize)"
|
||||||
style="width: 100%;"
|
style="width: 100%"
|
||||||
>
|
>
|
||||||
<el-table-column label="序号" width="50" type="index" align="center">
|
<el-table-column label="序号" width="50" type="index" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
@ -48,14 +48,14 @@
|
|||||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="强退" placement="top">
|
<el-tooltip content="强退" placement="top">
|
||||||
<el-button link type="primary" icon="Delete" @click="handleForceLogout(scope.row)" v-hasPermi="['monitor:online:forceLogout']">
|
<el-button v-hasPermi="['monitor:online:forceLogout']" link type="primary" icon="Delete" @click="handleForceLogout(scope.row)">
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" />
|
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" />
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -67,7 +67,7 @@ import api from "@/api/system/user";
|
|||||||
import {to} from "await-to-js";
|
import {to} from "await-to-js";
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const { sys_device_type } = toRefs<any>(proxy?.useDict("sys_device_type"));
|
const { sys_device_type } = toRefs<any>(proxy?.useDict('sys_device_type'));
|
||||||
|
|
||||||
const onlineList = ref<OnlineVO[]>([]);
|
const onlineList = ref<OnlineVO[]>([]);
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
@ -89,17 +89,17 @@ const getList = async () => {
|
|||||||
onlineList.value = res.rows;
|
onlineList.value = res.rows;
|
||||||
total.value = res.total;
|
total.value = res.total;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
};
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
handleQuery();
|
handleQuery();
|
||||||
}
|
};
|
||||||
/** 强退按钮操作 */
|
/** 强退按钮操作 */
|
||||||
const handleForceLogout = async (row: OnlineVO) => {
|
const handleForceLogout = async (row: OnlineVO) => {
|
||||||
const [err] = await to(proxy?.$modal.confirm('是否确认强退名称为"' + row.userName + '"的用户?') as any);
|
const [err] = await to(proxy?.$modal.confirm('是否确认强退名称为"' + row.userName + '"的用户?') as any);
|
||||||
@ -112,5 +112,5 @@ const handleForceLogout = async (row: OnlineVO) => {
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -3,15 +3,15 @@
|
|||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
<div class="mb-[10px]">
|
<div class="mb-[10px]">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
|
||||||
<el-form-item label="操作地址" prop="operIp">
|
<el-form-item label="操作地址" prop="operIp">
|
||||||
<el-input v-model="queryParams.operIp" placeholder="请输入操作地址" clearable style="width: 240px;" @keyup.enter="handleQuery"/>
|
<el-input v-model="queryParams.operIp" placeholder="请输入操作地址" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="系统模块" prop="title">
|
<el-form-item label="系统模块" prop="title">
|
||||||
<el-input v-model="queryParams.title" placeholder="请输入系统模块" clearable style="width: 240px;" @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.title" placeholder="请输入系统模块" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="操作人员" prop="operName">
|
<el-form-item label="操作人员" prop="operName">
|
||||||
<el-input v-model="queryParams.operName" placeholder="请输入操作人员" clearable style="width: 240px;" @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.operName" placeholder="请输入操作人员" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="类型" prop="businessType">
|
<el-form-item label="类型" prop="businessType">
|
||||||
<el-select v-model="queryParams.businessType" placeholder="操作类型" clearable style="width: 240px">
|
<el-select v-model="queryParams.businessType" placeholder="操作类型" clearable style="width: 240px">
|
||||||
@ -47,17 +47,17 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['monitor:operlog:remove']">
|
<el-button v-hasPermi="['monitor:operlog:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="danger" plain icon="WarnTriangleFilled" @click="handleClean" v-hasPermi="['monitor:operlog:remove']">清空</el-button>
|
<el-button v-hasPermi="['monitor:operlog:remove']" type="danger" plain icon="WarnTriangleFilled" @click="handleClean">清空</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['monitor:operlog:export']">导出</el-button>
|
<el-button v-hasPermi="['monitor:operlog:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -65,8 +65,8 @@
|
|||||||
ref="operLogTableRef"
|
ref="operLogTableRef"
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
:data="operlogList"
|
:data="operlogList"
|
||||||
@selection-change="handleSelectionChange"
|
|
||||||
:default-sort="defaultSort"
|
:default-sort="defaultSort"
|
||||||
|
@selection-change="handleSelectionChange"
|
||||||
@sort-change="handleSortChange"
|
@sort-change="handleSortChange"
|
||||||
>
|
>
|
||||||
<el-table-column type="selection" width="50" align="center" />
|
<el-table-column type="selection" width="50" align="center" />
|
||||||
@ -114,20 +114,20 @@
|
|||||||
<el-table-column label="操作" fixed="right" align="center" class-name="small-padding fixed-width">
|
<el-table-column label="操作" fixed="right" align="center" class-name="small-padding fixed-width">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="详细" placement="top">
|
<el-tooltip content="详细" placement="top">
|
||||||
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['monitor:operlog:query']"> </el-button>
|
<el-button v-hasPermi="['monitor:operlog:query']" link type="primary" icon="View" @click="handleView(scope.row)"> </el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
|
||||||
</el-card>
|
</el-card>
|
||||||
<!-- 操作日志详细 -->
|
<!-- 操作日志详细 -->
|
||||||
<el-dialog title="操作日志详细" v-model="dialog.visible" width="700px" append-to-body>
|
<el-dialog v-model="dialog.visible" title="操作日志详细" width="700px" append-to-body>
|
||||||
<el-form :model="form" label-width="100px">
|
<el-form :model="form" label-width="100px">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="登录信息:">{{ form.operName }} / {{form.deptName}} / {{ form.operIp }} / {{ form.operLocation }}</el-form-item>
|
<el-form-item label="登录信息:">{{ form.operName }} / {{ form.deptName }} / {{ form.operIp }} / {{ form.operLocation }}</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="请求信息:">{{ form.requestMethod }} {{ form.operUrl }}</el-form-item>
|
<el-form-item label="请求信息:">{{ form.requestMethod }} {{ form.operUrl }}</el-form-item>
|
||||||
@ -157,7 +157,7 @@
|
|||||||
<el-form-item label="操作时间:">{{ parseTime(form.operTime) }}</el-form-item>
|
<el-form-item label="操作时间:">{{ parseTime(form.operTime) }}</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="异常信息:" v-if="form.status === 1">{{ form.errorMsg }}</el-form-item>
|
<el-form-item v-if="form.status === 1" label="异常信息:">{{ form.errorMsg }}</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-form>
|
</el-form>
|
||||||
@ -175,7 +175,7 @@ import { list, delOperlog, cleanOperlog } from '@/api/monitor/operlog';
|
|||||||
import { OperLogForm, OperLogQuery, OperLogVO } from '@/api/monitor/operlog/types';
|
import { OperLogForm, OperLogQuery, OperLogVO } from '@/api/monitor/operlog/types';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const { sys_oper_type, sys_common_status } = toRefs<any>(proxy?.useDict("sys_oper_type", "sys_common_status"));
|
const { sys_oper_type, sys_common_status } = toRefs<any>(proxy?.useDict('sys_oper_type', 'sys_common_status'));
|
||||||
|
|
||||||
const operlogList = ref<OperLogVO[]>([]);
|
const operlogList = ref<OperLogVO[]>([]);
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
@ -184,7 +184,7 @@ const ids = ref<Array<number | string>>([]);
|
|||||||
const multiple = ref(true);
|
const multiple = ref(true);
|
||||||
const total = ref(0);
|
const total = ref(0);
|
||||||
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
|
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
|
||||||
const defaultSort = ref<any>({ prop: "operTime", order: "descending" });
|
const defaultSort = ref<any>({ prop: 'operTime', order: 'descending' });
|
||||||
|
|
||||||
const operLogTableRef = ref<ElTableInstance>();
|
const operLogTableRef = ref<ElTableInstance>();
|
||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
@ -194,7 +194,6 @@ const dialog = reactive<DialogOption>({
|
|||||||
title: ''
|
title: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const data = reactive<PageData<OperLogForm, OperLogQuery>>({
|
const data = reactive<PageData<OperLogForm, OperLogQuery>>({
|
||||||
form: {
|
form: {
|
||||||
operId: undefined,
|
operId: undefined,
|
||||||
@ -240,63 +239,67 @@ const getList = async () => {
|
|||||||
operlogList.value = res.rows;
|
operlogList.value = res.rows;
|
||||||
total.value = res.total;
|
total.value = res.total;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
};
|
||||||
/** 操作日志类型字典翻译 */
|
/** 操作日志类型字典翻译 */
|
||||||
const typeFormat = (row: OperLogForm) => {
|
const typeFormat = (row: OperLogForm) => {
|
||||||
return proxy?.selectDictLabel(sys_oper_type.value, row.businessType);
|
return proxy?.selectDictLabel(sys_oper_type.value, row.businessType);
|
||||||
}
|
};
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
dateRange.value = ['', ''];
|
dateRange.value = ['', ''];
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
operLogTableRef.value?.sort(defaultSort.value.prop, defaultSort.value.order);
|
operLogTableRef.value?.sort(defaultSort.value.prop, defaultSort.value.order);
|
||||||
}
|
};
|
||||||
/** 多选框选中数据 */
|
/** 多选框选中数据 */
|
||||||
const handleSelectionChange = (selection: OperLogVO[]) => {
|
const handleSelectionChange = (selection: OperLogVO[]) => {
|
||||||
ids.value = selection.map(item => item.operId);
|
ids.value = selection.map((item) => item.operId);
|
||||||
multiple.value = !selection.length;
|
multiple.value = !selection.length;
|
||||||
}
|
};
|
||||||
/** 排序触发事件 */
|
/** 排序触发事件 */
|
||||||
const handleSortChange = (column: any) => {
|
const handleSortChange = (column: any) => {
|
||||||
queryParams.value.orderByColumn = column.prop;
|
queryParams.value.orderByColumn = column.prop;
|
||||||
queryParams.value.isAsc = column.order;
|
queryParams.value.isAsc = column.order;
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
/** 详细按钮操作 */
|
/** 详细按钮操作 */
|
||||||
const handleView = (row: OperLogVO) => {
|
const handleView = (row: OperLogVO) => {
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
form.value = row;
|
form.value = row;
|
||||||
}
|
};
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row?: OperLogVO) => {
|
const handleDelete = async (row?: OperLogVO) => {
|
||||||
const operIds = row?.operId || ids.value;
|
const operIds = row?.operId || ids.value;
|
||||||
await proxy?.$modal.confirm('是否确认删除日志编号为"' + operIds + '"的数据项?');
|
await proxy?.$modal.confirm('是否确认删除日志编号为"' + operIds + '"的数据项?');
|
||||||
await delOperlog(operIds);
|
await delOperlog(operIds);
|
||||||
await getList();
|
await getList();
|
||||||
proxy?.$modal.msgSuccess("删除成功");
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 清空按钮操作 */
|
/** 清空按钮操作 */
|
||||||
const handleClean = async () => {
|
const handleClean = async () => {
|
||||||
await proxy?.$modal.confirm("是否确认清空所有操作日志数据项?");
|
await proxy?.$modal.confirm('是否确认清空所有操作日志数据项?');
|
||||||
await cleanOperlog();
|
await cleanOperlog();
|
||||||
await getList();
|
await getList();
|
||||||
proxy?.$modal.msgSuccess("清空成功");
|
proxy?.$modal.msgSuccess('清空成功');
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 导出按钮操作 */
|
/** 导出按钮操作 */
|
||||||
const handleExport = () => {
|
const handleExport = () => {
|
||||||
proxy?.download("monitor/operlog/export", {
|
proxy?.download(
|
||||||
...queryParams.value,
|
'monitor/operlog/export',
|
||||||
}, `config_${new Date().getTime()}.xlsx`);
|
{
|
||||||
}
|
...queryParams.value
|
||||||
|
},
|
||||||
|
`config_${new Date().getTime()}.xlsx`
|
||||||
|
);
|
||||||
|
};
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -3,12 +3,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { params, query } = route
|
const { params, query } = route;
|
||||||
const { path } = params
|
const { path } = params;
|
||||||
|
|
||||||
router.replace({ path: '/' + path, query })
|
router.replace({ path: '/' + path, query });
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<div class="register">
|
<div class="register">
|
||||||
<el-form ref="registerRef" :model="registerForm" :rules="registerRules" class="register-form">
|
<el-form ref="registerRef" :model="registerForm" :rules="registerRules" class="register-form">
|
||||||
<h3 class="title">RuoYi-Vue-Plus多租户管理系统</h3>
|
<h3 class="title">RuoYi-Vue-Plus多租户管理系统</h3>
|
||||||
<el-form-item prop="tenantId" v-if="tenantEnabled">
|
<el-form-item v-if="tenantEnabled" prop="tenantId">
|
||||||
<el-select v-model="registerForm.tenantId" filterable placeholder="请选择/输入公司名称" style="width: 100%">
|
<el-select v-model="registerForm.tenantId" filterable placeholder="请选择/输入公司名称" style="width: 100%">
|
||||||
<el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"> </el-option>
|
<el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"> </el-option>
|
||||||
<template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
|
<template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
|
||||||
@ -30,20 +30,20 @@
|
|||||||
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
|
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="code" v-if="captchaEnabled">
|
<el-form-item v-if="captchaEnabled" prop="code">
|
||||||
<el-input size="large" v-model="registerForm.code" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter="handleRegister">
|
<el-input v-model="registerForm.code" size="large" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter="handleRegister">
|
||||||
<template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
|
<template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
|
||||||
</el-input>
|
</el-input>
|
||||||
<div class="register-code">
|
<div class="register-code">
|
||||||
<img :src="codeUrl" @click="getCode" class="register-code-img" />
|
<img :src="codeUrl" class="register-code-img" @click="getCode" />
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item style="width:100%;">
|
<el-form-item style="width: 100%">
|
||||||
<el-button :loading="loading" size="large" type="primary" style="width:100%;" @click.prevent="handleRegister">
|
<el-button :loading="loading" size="large" type="primary" style="width: 100%" @click.prevent="handleRegister">
|
||||||
<span v-if="!loading">注 册</span>
|
<span v-if="!loading">注 册</span>
|
||||||
<span v-else>注 册 中...</span>
|
<span v-else>注 册 中...</span>
|
||||||
</el-button>
|
</el-button>
|
||||||
<div style="float: right;">
|
<div style="float: right">
|
||||||
<router-link class="link-type" :to="'/login'">使用已有账户登录</router-link>
|
<router-link class="link-type" :to="'/login'">使用已有账户登录</router-link>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -63,46 +63,43 @@ import { to } from 'await-to-js';
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const registerForm = ref<RegisterForm>({
|
const registerForm = ref<RegisterForm>({
|
||||||
tenantId: "",
|
tenantId: '',
|
||||||
username: "",
|
username: '',
|
||||||
password: "",
|
password: '',
|
||||||
confirmPassword: "",
|
confirmPassword: '',
|
||||||
code: "",
|
code: '',
|
||||||
uuid: "",
|
uuid: '',
|
||||||
userType: "sys_user"
|
userType: 'sys_user'
|
||||||
});
|
});
|
||||||
|
|
||||||
// 租户开关
|
// 租户开关
|
||||||
const tenantEnabled = ref(true);
|
const tenantEnabled = ref(true);
|
||||||
|
|
||||||
|
|
||||||
const equalToPassword = (rule: any, value: string, callback: any) => {
|
const equalToPassword = (rule: any, value: string, callback: any) => {
|
||||||
if (registerForm.value.password !== value) {
|
if (registerForm.value.password !== value) {
|
||||||
callback(new Error("两次输入的密码不一致"));
|
callback(new Error('两次输入的密码不一致'));
|
||||||
} else {
|
} else {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const registerRules: ElFormRules = {
|
const registerRules: ElFormRules = {
|
||||||
tenantId: [
|
tenantId: [{ required: true, trigger: 'blur', message: '请输入您的租户编号' }],
|
||||||
{ required: true, trigger: "blur", message: "请输入您的租户编号" }
|
|
||||||
],
|
|
||||||
username: [
|
username: [
|
||||||
{ required: true, trigger: "blur", message: "请输入您的账号" },
|
{ required: true, trigger: 'blur', message: '请输入您的账号' },
|
||||||
{ min: 2, max: 20, message: "用户账号长度必须介于 2 和 20 之间", trigger: "blur" }
|
{ min: 2, max: 20, message: '用户账号长度必须介于 2 和 20 之间', trigger: 'blur' }
|
||||||
],
|
],
|
||||||
password: [
|
password: [
|
||||||
{ required: true, trigger: "blur", message: "请输入您的密码" },
|
{ required: true, trigger: 'blur', message: '请输入您的密码' },
|
||||||
{ min: 5, max: 20, message: "用户密码长度必须介于 5 和 20 之间", trigger: "blur" }
|
{ min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' }
|
||||||
],
|
],
|
||||||
confirmPassword: [
|
confirmPassword: [
|
||||||
{ required: true, trigger: "blur", message: "请再次输入您的密码" },
|
{ required: true, trigger: 'blur', message: '请再次输入您的密码' },
|
||||||
{ required: true, validator: equalToPassword, trigger: "blur" }
|
{ required: true, validator: equalToPassword, trigger: 'blur' }
|
||||||
],
|
],
|
||||||
code: [{ required: true, trigger: "change", message: "请输入验证码" }]
|
code: [{ required: true, trigger: 'change', message: '请输入验证码' }]
|
||||||
};
|
};
|
||||||
const codeUrl = ref("");
|
const codeUrl = ref('');
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const captchaEnabled = ref(true);
|
const captchaEnabled = ref(true);
|
||||||
const registerRef = ref<ElFormInstance>();
|
const registerRef = ref<ElFormInstance>();
|
||||||
@ -116,11 +113,11 @@ const handleRegister = () => {
|
|||||||
const [err] = await to(register(registerForm.value));
|
const [err] = await to(register(registerForm.value));
|
||||||
if (!err) {
|
if (!err) {
|
||||||
const username = registerForm.value.username;
|
const username = registerForm.value.username;
|
||||||
await ElMessageBox.alert("<font color='red'>恭喜你,您的账号 " + username + " 注册成功!</font>", "系统提示", {
|
await ElMessageBox.alert("<font color='red'>恭喜你,您的账号 " + username + ' 注册成功!</font>', '系统提示', {
|
||||||
dangerouslyUseHTMLString: true,
|
dangerouslyUseHTMLString: true,
|
||||||
type: "success",
|
type: 'success'
|
||||||
});
|
});
|
||||||
await router.push("/login");
|
await router.push('/login');
|
||||||
} else {
|
} else {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
if (captchaEnabled) {
|
if (captchaEnabled) {
|
||||||
@ -129,7 +126,7 @@ const handleRegister = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const getCode = async () => {
|
const getCode = async () => {
|
||||||
const res = await getCodeImg();
|
const res = await getCodeImg();
|
||||||
@ -150,12 +147,12 @@ const initTenantList = async () => {
|
|||||||
registerForm.value.tenantId = tenantList.value[0].tenantId;
|
registerForm.value.tenantId = tenantList.value[0].tenantId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getCode();
|
getCode();
|
||||||
initTenantList();
|
initTenantList();
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@ -164,7 +161,7 @@ onMounted(() => {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-image: url("../assets/images/login-background.jpg");
|
background-image: url('../assets/images/login-background.jpg');
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
<div class="search" v-show="showSearch">
|
<div v-show="showSearch" class="search">
|
||||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="100px">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="100px">
|
||||||
<el-form-item label="客户端key" prop="clientKey">
|
<el-form-item label="客户端key" prop="clientKey">
|
||||||
<el-input v-model="queryParams.clientKey" placeholder="请输入客户端key" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.clientKey" placeholder="请输入客户端key" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -26,28 +26,28 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:client:add']">新增</el-button>
|
<el-button v-hasPermi="['system:client:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:client:edit']">
|
<el-button v-hasPermi="['system:client:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">
|
||||||
修改
|
修改
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:client:remove']">
|
<el-button v-hasPermi="['system:client:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:client:export']">导出</el-button>
|
<el-button v-hasPermi="['system:client:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="clientList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" :data="clientList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="id" align="center" prop="id" v-if="true" />
|
<el-table-column v-if="true" label="id" align="center" prop="id" />
|
||||||
<el-table-column label="客户端id" align="center" prop="clientId" />
|
<el-table-column label="客户端id" align="center" prop="clientId" />
|
||||||
<el-table-column label="客户端key" align="center" prop="clientKey" />
|
<el-table-column label="客户端key" align="center" prop="clientKey" />
|
||||||
<el-table-column label="客户端秘钥" align="center" prop="clientSecret" />
|
<el-table-column label="客户端秘钥" align="center" prop="clientSecret" />
|
||||||
@ -63,7 +63,7 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="Token活跃超时时间" align="center" prop="activeTimeout" />
|
<el-table-column label="Token活跃超时时间" align="center" prop="activeTimeout" />
|
||||||
<el-table-column label="Token固定超时时间" align="center" prop="timeout" />
|
<el-table-column label="Token固定超时时间" align="center" prop="timeout" />
|
||||||
<el-table-column label="状态" align="center" key="status">
|
<el-table-column key="status" label="状态" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
|
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
|
||||||
</template>
|
</template>
|
||||||
@ -71,19 +71,19 @@
|
|||||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="修改" placement="top">
|
<el-tooltip content="修改" placement="top">
|
||||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:client:edit']"></el-button>
|
<el-button v-hasPermi="['system:client:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="删除" placement="top">
|
<el-tooltip content="删除" placement="top">
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:client:remove']"></el-button>
|
<el-button v-hasPermi="['system:client:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<pagination v-show="total>0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
|
||||||
</el-card>
|
</el-card>
|
||||||
<!-- 添加或修改客户端管理对话框 -->
|
<!-- 添加或修改客户端管理对话框 -->
|
||||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
<el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
|
||||||
<el-form ref="clientFormRef" :model="form" :rules="rules" label-width="100px">
|
<el-form ref="clientFormRef" :model="form" :rules="rules" label-width="100px">
|
||||||
<el-form-item label="客户端key" prop="clientKey">
|
<el-form-item label="客户端key" prop="clientKey">
|
||||||
<el-input v-model="form.clientKey" :disabled="form.id != null" placeholder="请输入客户端key" />
|
<el-input v-model="form.clientKey" :disabled="form.id != null" placeholder="请输入客户端key" />
|
||||||
@ -146,9 +146,9 @@ import { listClient, getClient, delClient, addClient, updateClient, changeStatus
|
|||||||
import { ClientVO, ClientQuery, ClientForm } from '@/api/system/client/types';
|
import { ClientVO, ClientQuery, ClientForm } from '@/api/system/client/types';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable"));
|
const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
|
||||||
const { sys_grant_type } = toRefs<any>(proxy?.useDict("sys_grant_type"));
|
const { sys_grant_type } = toRefs<any>(proxy?.useDict('sys_grant_type'));
|
||||||
const { sys_device_type } = toRefs<any>(proxy?.useDict("sys_device_type"));
|
const { sys_device_type } = toRefs<any>(proxy?.useDict('sys_device_type'));
|
||||||
|
|
||||||
const clientList = ref<ClientVO[]>([]);
|
const clientList = ref<ClientVO[]>([]);
|
||||||
const buttonLoading = ref(false);
|
const buttonLoading = ref(false);
|
||||||
@ -176,10 +176,10 @@ const initFormData: ClientForm = {
|
|||||||
deviceType: undefined,
|
deviceType: undefined,
|
||||||
activeTimeout: undefined,
|
activeTimeout: undefined,
|
||||||
timeout: undefined,
|
timeout: undefined,
|
||||||
status: undefined,
|
status: undefined
|
||||||
}
|
};
|
||||||
const data = reactive<PageData<ClientForm, ClientQuery>>({
|
const data = reactive<PageData<ClientForm, ClientQuery>>({
|
||||||
form: {...initFormData},
|
form: { ...initFormData },
|
||||||
queryParams: {
|
queryParams: {
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
@ -190,27 +190,15 @@ const data = reactive<PageData<ClientForm, ClientQuery>>({
|
|||||||
deviceType: undefined,
|
deviceType: undefined,
|
||||||
activeTimeout: undefined,
|
activeTimeout: undefined,
|
||||||
timeout: undefined,
|
timeout: undefined,
|
||||||
status: undefined,
|
status: undefined
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
id: [
|
id: [{ required: true, message: 'id不能为空', trigger: 'blur' }],
|
||||||
{ required: true, message: "id不能为空", trigger: "blur" }
|
clientId: [{ required: true, message: '客户端id不能为空', trigger: 'blur' }],
|
||||||
],
|
clientKey: [{ required: true, message: '客户端key不能为空', trigger: 'blur' }],
|
||||||
clientId: [
|
clientSecret: [{ required: true, message: '客户端秘钥不能为空', trigger: 'blur' }],
|
||||||
{ required: true, message: "客户端id不能为空", trigger: "blur" }
|
grantTypeList: [{ required: true, message: '授权类型不能为空', trigger: 'change' }],
|
||||||
],
|
deviceType: [{ required: true, message: '设备类型不能为空', trigger: 'change' }]
|
||||||
clientKey: [
|
|
||||||
{ required: true, message: "客户端key不能为空", trigger: "blur" }
|
|
||||||
],
|
|
||||||
clientSecret: [
|
|
||||||
{ required: true, message: "客户端秘钥不能为空", trigger: "blur" }
|
|
||||||
],
|
|
||||||
grantTypeList: [
|
|
||||||
{ required: true, message: "授权类型不能为空", trigger: "change" }
|
|
||||||
],
|
|
||||||
deviceType: [
|
|
||||||
{ required: true, message: "设备类型不能为空", trigger: "change" }
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -223,55 +211,55 @@ const getList = async () => {
|
|||||||
clientList.value = res.rows;
|
clientList.value = res.rows;
|
||||||
total.value = res.total;
|
total.value = res.total;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
reset();
|
reset();
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 表单重置 */
|
/** 表单重置 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
form.value = {...initFormData};
|
form.value = { ...initFormData };
|
||||||
clientFormRef.value?.resetFields();
|
clientFormRef.value?.resetFields();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
handleQuery();
|
handleQuery();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 多选框选中数据 */
|
/** 多选框选中数据 */
|
||||||
const handleSelectionChange = (selection: ClientVO[]) => {
|
const handleSelectionChange = (selection: ClientVO[]) => {
|
||||||
ids.value = selection.map(item => item.id);
|
ids.value = selection.map((item) => item.id);
|
||||||
single.value = selection.length != 1;
|
single.value = selection.length != 1;
|
||||||
multiple.value = !selection.length;
|
multiple.value = !selection.length;
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 新增按钮操作 */
|
/** 新增按钮操作 */
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
reset();
|
reset();
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "添加客户端管理";
|
dialog.title = '添加客户端管理';
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
const handleUpdate = async (row?: ClientVO) => {
|
const handleUpdate = async (row?: ClientVO) => {
|
||||||
reset();
|
reset();
|
||||||
const _id = row?.id || ids.value[0]
|
const _id = row?.id || ids.value[0];
|
||||||
const res = await getClient(_id);
|
const res = await getClient(_id);
|
||||||
Object.assign(form.value, res.data);
|
Object.assign(form.value, res.data);
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "修改客户端管理";
|
dialog.title = '修改客户端管理';
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
@ -279,44 +267,48 @@ const submitForm = () => {
|
|||||||
if (valid) {
|
if (valid) {
|
||||||
buttonLoading.value = true;
|
buttonLoading.value = true;
|
||||||
if (form.value.id) {
|
if (form.value.id) {
|
||||||
await updateClient(form.value).finally(() => buttonLoading.value = false);
|
await updateClient(form.value).finally(() => (buttonLoading.value = false));
|
||||||
} else {
|
} else {
|
||||||
await addClient(form.value).finally(() => buttonLoading.value = false);
|
await addClient(form.value).finally(() => (buttonLoading.value = false));
|
||||||
}
|
}
|
||||||
proxy?.$modal.msgSuccess("修改成功");
|
proxy?.$modal.msgSuccess('修改成功');
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
await getList();
|
await getList();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row?: ClientVO) => {
|
const handleDelete = async (row?: ClientVO) => {
|
||||||
const _ids = row?.id || ids.value;
|
const _ids = row?.id || ids.value;
|
||||||
await proxy?.$modal.confirm('是否确认删除客户端管理编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
|
await proxy?.$modal.confirm('是否确认删除客户端管理编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
|
||||||
await delClient(_ids);
|
await delClient(_ids);
|
||||||
proxy?.$modal.msgSuccess("删除成功");
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
await getList();
|
await getList();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 导出按钮操作 */
|
/** 导出按钮操作 */
|
||||||
const handleExport = () => {
|
const handleExport = () => {
|
||||||
proxy?.download('system/client/export', {
|
proxy?.download(
|
||||||
...queryParams.value
|
'system/client/export',
|
||||||
}, `client_${new Date().getTime()}.xlsx`)
|
{
|
||||||
}
|
...queryParams.value
|
||||||
|
},
|
||||||
|
`client_${new Date().getTime()}.xlsx`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
/** 状态修改 */
|
/** 状态修改 */
|
||||||
const handleStatusChange = async (row: ClientVO) => {
|
const handleStatusChange = async (row: ClientVO) => {
|
||||||
let text = row.status === "0" ? "启用" : "停用"
|
let text = row.status === '0' ? '启用' : '停用';
|
||||||
try {
|
try {
|
||||||
await proxy?.$modal.confirm('确认要"' + text + '"吗?');
|
await proxy?.$modal.confirm('确认要"' + text + '"吗?');
|
||||||
await changeStatus(row.id, row.status);
|
await changeStatus(row.id, row.status);
|
||||||
proxy?.$modal.msgSuccess(text + "成功");
|
proxy?.$modal.msgSuccess(text + '成功');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
row.status = row.status === "0" ? "1" : "0";
|
row.status = row.status === '0' ? '1' : '0';
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
<div class="mb-[10px]" v-show="showSearch">
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
|
||||||
<el-form-item label="参数名称" prop="configName">
|
<el-form-item label="参数名称" prop="configName">
|
||||||
<el-input v-model="queryParams.configName" placeholder="请输入参数名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.configName" placeholder="请输入参数名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -15,7 +15,7 @@
|
|||||||
<el-option v-for="dict in sys_yes_no" :key="dict.value" :label="dict.label" :value="dict.value" />
|
<el-option v-for="dict in sys_yes_no" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="创建时间" style="width: 308px;">
|
<el-form-item label="创建时间" style="width: 308px">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
v-model="dateRange"
|
v-model="dateRange"
|
||||||
value-format="YYYY-MM-DD HH:mm:ss"
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
@ -38,31 +38,31 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:config:add']">新增</el-button>
|
<el-button v-hasPermi="['system:config:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:config:edit']">
|
<el-button v-hasPermi="['system:config:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">
|
||||||
修改
|
修改
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:config:remove']">
|
<el-button v-hasPermi="['system:config:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:config:export']">导出</el-button>
|
<el-button v-hasPermi="['system:config:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="danger" plain icon="Refresh" @click="handleRefreshCache" v-hasPermi="['system:config:remove']">刷新缓存</el-button>
|
<el-button v-hasPermi="['system:config:remove']" type="danger" plain icon="Refresh" @click="handleRefreshCache">刷新缓存</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="configList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" :data="configList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="参数主键" align="center" prop="configId" v-if="false" />
|
<el-table-column v-if="false" label="参数主键" align="center" prop="configId" />
|
||||||
<el-table-column label="参数名称" align="center" prop="configName" :show-overflow-tooltip="true" />
|
<el-table-column label="参数名称" align="center" prop="configName" :show-overflow-tooltip="true" />
|
||||||
<el-table-column label="参数键名" align="center" prop="configKey" :show-overflow-tooltip="true" />
|
<el-table-column label="参数键名" align="center" prop="configKey" :show-overflow-tooltip="true" />
|
||||||
<el-table-column label="参数键值" align="center" prop="configValue" :show-overflow-tooltip="true" />
|
<el-table-column label="参数键值" align="center" prop="configValue" :show-overflow-tooltip="true" />
|
||||||
@ -80,19 +80,19 @@
|
|||||||
<el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
|
<el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="修改" placement="top">
|
<el-tooltip content="修改" placement="top">
|
||||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:config:edit']"></el-button>
|
<el-button v-hasPermi="['system:config:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="删除" placement="top">
|
<el-tooltip content="删除" placement="top">
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:config:remove']"></el-button>
|
<el-button v-hasPermi="['system:config:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<!-- 添加或修改参数配置对话框 -->
|
<!-- 添加或修改参数配置对话框 -->
|
||||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
<el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
|
||||||
<el-form ref="configFormRef" :model="form" :rules="rules" label-width="80px">
|
<el-form ref="configFormRef" :model="form" :rules="rules" label-width="80px">
|
||||||
<el-form-item label="参数名称" prop="configName">
|
<el-form-item label="参数名称" prop="configName">
|
||||||
<el-input v-model="form.configName" placeholder="请输入参数名称" />
|
<el-input v-model="form.configName" placeholder="请输入参数名称" />
|
||||||
@ -123,11 +123,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="Config" lang="ts">
|
<script setup name="Config" lang="ts">
|
||||||
import { listConfig, getConfig, delConfig, addConfig, updateConfig, refreshCache } from "@/api/system/config";
|
import { listConfig, getConfig, delConfig, addConfig, updateConfig, refreshCache } from '@/api/system/config';
|
||||||
import { ConfigForm, ConfigQuery, ConfigVO } from "@/api/system/config/types";
|
import { ConfigForm, ConfigQuery, ConfigVO } from '@/api/system/config/types';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const { sys_yes_no } = toRefs<any>(proxy?.useDict("sys_yes_no"));
|
const { sys_yes_no } = toRefs<any>(proxy?.useDict('sys_yes_no'));
|
||||||
|
|
||||||
const configList = ref<ConfigVO[]>([]);
|
const configList = ref<ConfigVO[]>([]);
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
@ -149,9 +149,9 @@ const initFormData: ConfigForm = {
|
|||||||
configName: '',
|
configName: '',
|
||||||
configKey: '',
|
configKey: '',
|
||||||
configValue: '',
|
configValue: '',
|
||||||
configType: "Y",
|
configType: 'Y',
|
||||||
remark: ''
|
remark: ''
|
||||||
}
|
};
|
||||||
const data = reactive<PageData<ConfigForm, ConfigQuery>>({
|
const data = reactive<PageData<ConfigForm, ConfigQuery>>({
|
||||||
form: { ...initFormData },
|
form: { ...initFormData },
|
||||||
queryParams: {
|
queryParams: {
|
||||||
@ -159,12 +159,12 @@ const data = reactive<PageData<ConfigForm, ConfigQuery>>({
|
|||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
configName: '',
|
configName: '',
|
||||||
configKey: '',
|
configKey: '',
|
||||||
configType: '',
|
configType: ''
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
configName: [{ required: true, message: "参数名称不能为空", trigger: "blur" }],
|
configName: [{ required: true, message: '参数名称不能为空', trigger: 'blur' }],
|
||||||
configKey: [{ required: true, message: "参数键名不能为空", trigger: "blur" }],
|
configKey: [{ required: true, message: '参数键名不能为空', trigger: 'blur' }],
|
||||||
configValue: [{ required: true, message: "参数键值不能为空", trigger: "blur" }]
|
configValue: [{ required: true, message: '参数键值不能为空', trigger: 'blur' }]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -177,40 +177,40 @@ const getList = async () => {
|
|||||||
configList.value = res.rows;
|
configList.value = res.rows;
|
||||||
total.value = res.total;
|
total.value = res.total;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
};
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
reset();
|
reset();
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
}
|
};
|
||||||
/** 表单重置 */
|
/** 表单重置 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
form.value = { ...initFormData };
|
form.value = { ...initFormData };
|
||||||
configFormRef.value?.resetFields();
|
configFormRef.value?.resetFields();
|
||||||
}
|
};
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
dateRange.value = ['', ''];
|
dateRange.value = ['', ''];
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
handleQuery();
|
handleQuery();
|
||||||
}
|
};
|
||||||
/** 多选框选中数据 */
|
/** 多选框选中数据 */
|
||||||
const handleSelectionChange = (selection: ConfigVO[]) => {
|
const handleSelectionChange = (selection: ConfigVO[]) => {
|
||||||
ids.value = selection.map(item => item.configId);
|
ids.value = selection.map((item) => item.configId);
|
||||||
single.value = selection.length != 1;
|
single.value = selection.length != 1;
|
||||||
multiple.value = !selection.length;
|
multiple.value = !selection.length;
|
||||||
}
|
};
|
||||||
/** 新增按钮操作 */
|
/** 新增按钮操作 */
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
reset();
|
reset();
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "添加参数";
|
dialog.title = '添加参数';
|
||||||
}
|
};
|
||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
const handleUpdate = async (row?: ConfigVO) => {
|
const handleUpdate = async (row?: ConfigVO) => {
|
||||||
reset();
|
reset();
|
||||||
@ -218,40 +218,44 @@ const handleUpdate = async (row?: ConfigVO) => {
|
|||||||
const res = await getConfig(configId);
|
const res = await getConfig(configId);
|
||||||
Object.assign(form.value, res.data);
|
Object.assign(form.value, res.data);
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "修改参数";
|
dialog.title = '修改参数';
|
||||||
}
|
};
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
configFormRef.value?.validate(async (valid: boolean) => {
|
configFormRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
form.value.configId ? await updateConfig(form.value) : await addConfig(form.value);
|
form.value.configId ? await updateConfig(form.value) : await addConfig(form.value);
|
||||||
proxy?.$modal.msgSuccess("操作成功");
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
await getList();
|
await getList();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row?: ConfigVO) => {
|
const handleDelete = async (row?: ConfigVO) => {
|
||||||
const configIds = row?.configId || ids.value;
|
const configIds = row?.configId || ids.value;
|
||||||
await proxy?.$modal.confirm('是否确认删除参数编号为"' + configIds + '"的数据项?');
|
await proxy?.$modal.confirm('是否确认删除参数编号为"' + configIds + '"的数据项?');
|
||||||
await delConfig(configIds);
|
await delConfig(configIds);
|
||||||
await getList();
|
await getList();
|
||||||
proxy?.$modal.msgSuccess("删除成功");
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
}
|
};
|
||||||
/** 导出按钮操作 */
|
/** 导出按钮操作 */
|
||||||
const handleExport = () => {
|
const handleExport = () => {
|
||||||
proxy?.download("system/config/export", {
|
proxy?.download(
|
||||||
...queryParams.value
|
'system/config/export',
|
||||||
}, `config_${new Date().getTime()}.xlsx`);
|
{
|
||||||
}
|
...queryParams.value
|
||||||
|
},
|
||||||
|
`config_${new Date().getTime()}.xlsx`
|
||||||
|
);
|
||||||
|
};
|
||||||
/** 刷新缓存按钮操作 */
|
/** 刷新缓存按钮操作 */
|
||||||
const handleRefreshCache = async () => {
|
const handleRefreshCache = async () => {
|
||||||
await refreshCache();
|
await refreshCache();
|
||||||
proxy?.$modal.msgSuccess("刷新缓存成功");
|
proxy?.$modal.msgSuccess('刷新缓存成功');
|
||||||
}
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
<div class="mb-[10px]" v-show="showSearch">
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
|
||||||
<el-form-item label="部门名称" prop="deptName">
|
<el-form-item label="部门名称" prop="deptName">
|
||||||
@ -25,21 +25,21 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10">
|
<el-row :gutter="10">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['system:dept:add']">新增 </el-button>
|
<el-button v-hasPermi="['system:dept:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增 </el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
|
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table
|
<el-table
|
||||||
|
ref="deptTableRef"
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
:data="deptList"
|
:data="deptList"
|
||||||
row-key="deptId"
|
row-key="deptId"
|
||||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||||
ref="deptTableRef"
|
|
||||||
:default-expand-all="isExpandAll"
|
:default-expand-all="isExpandAll"
|
||||||
>
|
>
|
||||||
<el-table-column prop="deptName" label="部门名称" width="260"></el-table-column>
|
<el-table-column prop="deptName" label="部门名称" width="260"></el-table-column>
|
||||||
@ -57,23 +57,23 @@
|
|||||||
<el-table-column fixed="right" align="center" label="操作">
|
<el-table-column fixed="right" align="center" label="操作">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="修改" placement="top">
|
<el-tooltip content="修改" placement="top">
|
||||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dept:edit']" />
|
<el-button v-hasPermi="['system:dept:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="新增" placement="top">
|
<el-tooltip content="新增" placement="top">
|
||||||
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['system:dept:add']" />
|
<el-button v-hasPermi="['system:dept:add']" link type="primary" icon="Plus" @click="handleAdd(scope.row)" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="删除" placement="top">
|
<el-tooltip content="删除" placement="top">
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:dept:remove']" />
|
<el-button v-hasPermi="['system:dept:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-dialog :title="dialog.title" v-model="dialog.visible" destroy-on-close append-to-bod width="600px">
|
<el-dialog v-model="dialog.visible" :title="dialog.title" destroy-on-close append-to-bod width="600px">
|
||||||
<el-form ref="deptFormRef" :model="form" :rules="rules" label-width="80px">
|
<el-form ref="deptFormRef" :model="form" :rules="rules" label-width="80px">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="24" v-if="form.parentId !== 0">
|
<el-col v-if="form.parentId !== 0" :span="24">
|
||||||
<el-form-item label="上级部门" prop="parentId">
|
<el-form-item label="上级部门" prop="parentId">
|
||||||
<el-tree-select
|
<el-tree-select
|
||||||
v-model="form.parentId"
|
v-model="form.parentId"
|
||||||
@ -115,8 +115,7 @@
|
|||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="部门状态">
|
<el-form-item label="部门状态">
|
||||||
<el-radio-group v-model="form.status">
|
<el-radio-group v-model="form.status">
|
||||||
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label
|
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
|
||||||
}}</el-radio>
|
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -133,26 +132,25 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="Dept" lang="ts">
|
<script setup name="Dept" lang="ts">
|
||||||
import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild } from "@/api/system/dept"
|
import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild } from '@/api/system/dept';
|
||||||
import { DeptForm, DeptQuery, DeptVO } from "@/api/system/dept/types";
|
import { DeptForm, DeptQuery, DeptVO } from '@/api/system/dept/types';
|
||||||
import {UserVO} from "@/api/system/user/types";
|
import { UserVO } from '@/api/system/user/types';
|
||||||
import {listUserByDeptId} from "@/api/system/user";
|
import { listUserByDeptId } from '@/api/system/user';
|
||||||
|
|
||||||
interface DeptOptionsType {
|
interface DeptOptionsType {
|
||||||
deptId: number | string;
|
deptId: number | string;
|
||||||
deptName: string;
|
deptName: string;
|
||||||
children: DeptOptionsType[];
|
children: DeptOptionsType[];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable"));
|
const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
|
||||||
|
|
||||||
const deptList = ref<DeptVO[]>([])
|
const deptList = ref<DeptVO[]>([]);
|
||||||
const loading = ref(true)
|
const loading = ref(true);
|
||||||
const showSearch = ref(true)
|
const showSearch = ref(true);
|
||||||
const deptOptions = ref<DeptOptionsType[]>([])
|
const deptOptions = ref<DeptOptionsType[]>([]);
|
||||||
const isExpandAll = ref(true)
|
const isExpandAll = ref(true);
|
||||||
const deptUserList = ref<UserVO[]>([]);
|
const deptUserList = ref<UserVO[]>([]);
|
||||||
|
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = reactive<DialogOption>({
|
||||||
@ -172,8 +170,8 @@ const initFormData: DeptForm = {
|
|||||||
leader: undefined,
|
leader: undefined,
|
||||||
phone: undefined,
|
phone: undefined,
|
||||||
email: undefined,
|
email: undefined,
|
||||||
status: "0"
|
status: '0'
|
||||||
}
|
};
|
||||||
const data = reactive<PageData<DeptForm, DeptQuery>>({
|
const data = reactive<PageData<DeptForm, DeptQuery>>({
|
||||||
form: { ...initFormData },
|
form: { ...initFormData },
|
||||||
queryParams: {
|
queryParams: {
|
||||||
@ -183,30 +181,30 @@ const data = reactive<PageData<DeptForm, DeptQuery>>({
|
|||||||
status: undefined
|
status: undefined
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
parentId: [{ required: true, message: "上级部门不能为空", trigger: "blur" }],
|
parentId: [{ required: true, message: '上级部门不能为空', trigger: 'blur' }],
|
||||||
deptName: [{ required: true, message: "部门名称不能为空", trigger: "blur" }],
|
deptName: [{ required: true, message: '部门名称不能为空', trigger: 'blur' }],
|
||||||
orderNum: [{ required: true, message: "显示排序不能为空", trigger: "blur" }],
|
orderNum: [{ required: true, message: '显示排序不能为空', trigger: 'blur' }],
|
||||||
email: [{ type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
|
email: [{ type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change'] }],
|
||||||
phone: [{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }]
|
phone: [{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: '请输入正确的手机号码', trigger: 'blur' }]
|
||||||
},
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const { queryParams, form, rules } = toRefs<PageData<DeptForm, DeptQuery>>(data)
|
const { queryParams, form, rules } = toRefs<PageData<DeptForm, DeptQuery>>(data);
|
||||||
|
|
||||||
/** 查询菜单列表 */
|
/** 查询菜单列表 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const res = await listDept(queryParams.value);
|
const res = await listDept(queryParams.value);
|
||||||
const data = proxy?.handleTree<DeptVO>(res.data, "deptId")
|
const data = proxy?.handleTree<DeptVO>(res.data, 'deptId');
|
||||||
if (data) {
|
if (data) {
|
||||||
deptList.value = data
|
deptList.value = data;
|
||||||
}
|
}
|
||||||
loading.value = false
|
loading.value = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 查询当前部门的所有用户 */
|
/** 查询当前部门的所有用户 */
|
||||||
async function getDeptAllUser(deptId: any) {
|
async function getDeptAllUser(deptId: any) {
|
||||||
if (deptId !== null && deptId !== "" && deptId !== undefined) {
|
if (deptId !== null && deptId !== '' && deptId !== undefined) {
|
||||||
const res = await listUserByDeptId(deptId);
|
const res = await listUserByDeptId(deptId);
|
||||||
deptUserList.value = res.data;
|
deptUserList.value = res.data;
|
||||||
}
|
}
|
||||||
@ -214,52 +212,52 @@ async function getDeptAllUser(deptId: any) {
|
|||||||
|
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
reset()
|
reset();
|
||||||
dialog.visible = false
|
dialog.visible = false;
|
||||||
}
|
};
|
||||||
/** 表单重置 */
|
/** 表单重置 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
form.value = { ...initFormData };
|
form.value = { ...initFormData };
|
||||||
deptFormRef.value?.resetFields();
|
deptFormRef.value?.resetFields();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
handleQuery()
|
handleQuery();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 展开/折叠操作 */
|
/** 展开/折叠操作 */
|
||||||
const handleToggleExpandAll = () => {
|
const handleToggleExpandAll = () => {
|
||||||
isExpandAll.value = !isExpandAll.value;
|
isExpandAll.value = !isExpandAll.value;
|
||||||
toggleExpandAll(deptList.value, isExpandAll.value)
|
toggleExpandAll(deptList.value, isExpandAll.value);
|
||||||
}
|
};
|
||||||
/** 展开/折叠所有 */
|
/** 展开/折叠所有 */
|
||||||
const toggleExpandAll = (data: DeptVO[], status: boolean) => {
|
const toggleExpandAll = (data: DeptVO[], status: boolean) => {
|
||||||
data.forEach((item) => {
|
data.forEach((item) => {
|
||||||
deptTableRef.value?.toggleRowExpansion(item, status)
|
deptTableRef.value?.toggleRowExpansion(item, status);
|
||||||
if (item.children && item.children.length > 0) toggleExpandAll(item.children, status)
|
if (item.children && item.children.length > 0) toggleExpandAll(item.children, status);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 新增按钮操作 */
|
/** 新增按钮操作 */
|
||||||
const handleAdd = async (row?: DeptVO) => {
|
const handleAdd = async (row?: DeptVO) => {
|
||||||
reset();
|
reset();
|
||||||
const res = await listDept();
|
const res = await listDept();
|
||||||
const data = proxy?.handleTree<DeptOptionsType>(res.data, "deptId");
|
const data = proxy?.handleTree<DeptOptionsType>(res.data, 'deptId');
|
||||||
if (data) {
|
if (data) {
|
||||||
deptOptions.value = data
|
deptOptions.value = data;
|
||||||
if (row && row.deptId) {
|
if (row && row.deptId) {
|
||||||
form.value.parentId = row?.deptId;
|
form.value.parentId = row?.deptId;
|
||||||
}
|
}
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "添加部门";
|
dialog.title = '添加部门';
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
const handleUpdate = async (row: DeptVO) => {
|
const handleUpdate = async (row: DeptVO) => {
|
||||||
@ -267,9 +265,9 @@ const handleUpdate = async (row: DeptVO) => {
|
|||||||
//查询当前部门所有用户
|
//查询当前部门所有用户
|
||||||
getDeptAllUser(row.deptId);
|
getDeptAllUser(row.deptId);
|
||||||
const res = await getDept(row.deptId);
|
const res = await getDept(row.deptId);
|
||||||
form.value = res.data
|
form.value = res.data;
|
||||||
const response = await listDeptExcludeChild(row.deptId);
|
const response = await listDeptExcludeChild(row.deptId);
|
||||||
const data = proxy?.handleTree<DeptOptionsType>(response.data, "deptId")
|
const data = proxy?.handleTree<DeptOptionsType>(response.data, 'deptId');
|
||||||
if (data) {
|
if (data) {
|
||||||
deptOptions.value = data;
|
deptOptions.value = data;
|
||||||
if (data.length === 0) {
|
if (data.length === 0) {
|
||||||
@ -282,26 +280,26 @@ const handleUpdate = async (row: DeptVO) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "修改部门";
|
dialog.title = '修改部门';
|
||||||
}
|
};
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
deptFormRef.value?.validate(async (valid: boolean) => {
|
deptFormRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
form.value.deptId ? await updateDept(form.value) : await addDept(form.value);
|
form.value.deptId ? await updateDept(form.value) : await addDept(form.value);
|
||||||
proxy?.$modal.msgSuccess("操作成功");
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
await getList();
|
await getList();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row: DeptVO) => {
|
const handleDelete = async (row: DeptVO) => {
|
||||||
await proxy?.$modal.confirm('是否确认删除名称为"' + row.deptName + '"的数据项?');
|
await proxy?.$modal.confirm('是否确认删除名称为"' + row.deptName + '"的数据项?');
|
||||||
await delDept(row.deptId);
|
await delDept(row.deptId);
|
||||||
await getList();
|
await getList();
|
||||||
proxy?.$modal.msgSuccess("删除成功");
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
}
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
<div class="mb-[10px]" v-show="showSearch">
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
|
||||||
<el-form-item label="字典名称" prop="dictType">
|
<el-form-item label="字典名称" prop="dictType">
|
||||||
<el-select v-model="queryParams.dictType" style="width: 200px">
|
<el-select v-model="queryParams.dictType" style="width: 200px">
|
||||||
<el-option v-for="item in typeOptions" :key="item.dictId" :label="item.dictName" :value="item.dictType" />
|
<el-option v-for="item in typeOptions" :key="item.dictId" :label="item.dictName" :value="item.dictType" />
|
||||||
@ -24,29 +24,29 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:dict:add']">新增</el-button>
|
<el-button v-hasPermi="['system:dict:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:dict:edit']">修改</el-button>
|
<el-button v-hasPermi="['system:dict:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">修改</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:dict:remove']">
|
<el-button v-hasPermi="['system:dict:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:dict:export']">导出</el-button>
|
<el-button v-hasPermi="['system:dict:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="warning" plain icon="Close" @click="handleClose">关闭</el-button>
|
<el-button type="warning" plain icon="Close" @click="handleClose">关闭</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="字典编码" align="center" prop="dictCode" v-if="false" />
|
<el-table-column v-if="false" label="字典编码" align="center" prop="dictCode" />
|
||||||
<el-table-column label="字典标签" align="center" prop="dictLabel">
|
<el-table-column label="字典标签" align="center" prop="dictLabel">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span v-if="(scope.row.listClass === '' || scope.row.listClass === 'default') && (scope.row.cssClass === '' || scope.row.cssClass == null)">{{ scope.row.dictLabel }}</span>
|
<span v-if="(scope.row.listClass === '' || scope.row.listClass === 'default') && (scope.row.cssClass === '' || scope.row.cssClass == null)">{{ scope.row.dictLabel }}</span>
|
||||||
@ -64,19 +64,19 @@
|
|||||||
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
|
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="修改" placement="top">
|
<el-tooltip content="修改" placement="top">
|
||||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dict:edit']"></el-button>
|
<el-button v-hasPermi="['system:dict:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="删除" placement="top">
|
<el-tooltip content="删除" placement="top">
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:dict:remove']"></el-button>
|
<el-button v-hasPermi="['system:dict:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
|
||||||
</el-card>
|
</el-card>
|
||||||
<!-- 添加或修改参数配置对话框 -->
|
<!-- 添加或修改参数配置对话框 -->
|
||||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
<el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
|
||||||
<el-form ref="dataFormRef" :model="form" :rules="rules" label-width="80px">
|
<el-form ref="dataFormRef" :model="form" :rules="rules" label-width="80px">
|
||||||
<el-form-item label="字典类型">
|
<el-form-item label="字典类型">
|
||||||
<el-input v-model="form.dictType" :disabled="true" />
|
<el-input v-model="form.dictType" :disabled="true" />
|
||||||
@ -118,13 +118,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="Data" lang="ts">
|
<script setup name="Data" lang="ts">
|
||||||
import useDictStore from '@/store/modules/dict'
|
import useDictStore from '@/store/modules/dict';
|
||||||
import { optionselect as getDictOptionselect, getType } from "@/api/system/dict/type";
|
import { optionselect as getDictOptionselect, getType } from '@/api/system/dict/type';
|
||||||
import { listData, getData, delData, addData, updateData } from "@/api/system/dict/data";
|
import { listData, getData, delData, addData, updateData } from '@/api/system/dict/data';
|
||||||
import { DictTypeVO } from '@/api/system/dict/type/types';
|
import { DictTypeVO } from '@/api/system/dict/type/types';
|
||||||
import { DictDataForm, DictDataQuery, DictDataVO } from "@/api/system/dict/data/types";
|
import { DictDataForm, DictDataQuery, DictDataVO } from '@/api/system/dict/data/types';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
const dataList = ref<DictDataVO[]>([]);
|
const dataList = ref<DictDataVO[]>([]);
|
||||||
@ -134,26 +134,25 @@ const ids = ref<Array<string | number>>([]);
|
|||||||
const single = ref(true);
|
const single = ref(true);
|
||||||
const multiple = ref(true);
|
const multiple = ref(true);
|
||||||
const total = ref(0);
|
const total = ref(0);
|
||||||
const defaultDictType = ref("");
|
const defaultDictType = ref('');
|
||||||
const typeOptions = ref<DictTypeVO[]>([]);
|
const typeOptions = ref<DictTypeVO[]>([]);
|
||||||
|
|
||||||
const dataFormRef = ref<ElFormInstance>();
|
const dataFormRef = ref<ElFormInstance>();
|
||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
|
|
||||||
|
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = reactive<DialogOption>({
|
||||||
visible: false,
|
visible: false,
|
||||||
title: ''
|
title: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
// 数据标签回显样式
|
// 数据标签回显样式
|
||||||
const listClassOptions = ref<Array<{ value: string, label: string }>>([
|
const listClassOptions = ref<Array<{ value: string; label: string }>>([
|
||||||
{ value: "default", label: "默认" },
|
{ value: 'default', label: '默认' },
|
||||||
{ value: "primary", label: "主要" },
|
{ value: 'primary', label: '主要' },
|
||||||
{ value: "success", label: "成功" },
|
{ value: 'success', label: '成功' },
|
||||||
{ value: "info", label: "信息" },
|
{ value: 'info', label: '信息' },
|
||||||
{ value: "warning", label: "警告" },
|
{ value: 'warning', label: '警告' },
|
||||||
{ value: "danger", label: "危险" }
|
{ value: 'danger', label: '危险' }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const initFormData: DictDataForm = {
|
const initFormData: DictDataForm = {
|
||||||
@ -161,10 +160,10 @@ const initFormData: DictDataForm = {
|
|||||||
dictLabel: '',
|
dictLabel: '',
|
||||||
dictValue: '',
|
dictValue: '',
|
||||||
cssClass: '',
|
cssClass: '',
|
||||||
listClass: "default",
|
listClass: 'default',
|
||||||
dictSort: 0,
|
dictSort: 0,
|
||||||
remark: ''
|
remark: ''
|
||||||
}
|
};
|
||||||
const data = reactive<PageData<DictDataForm, DictDataQuery>>({
|
const data = reactive<PageData<DictDataForm, DictDataQuery>>({
|
||||||
form: { ...initFormData },
|
form: { ...initFormData },
|
||||||
queryParams: {
|
queryParams: {
|
||||||
@ -175,9 +174,9 @@ const data = reactive<PageData<DictDataForm, DictDataQuery>>({
|
|||||||
dictLabel: ''
|
dictLabel: ''
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
dictLabel: [{ required: true, message: "数据标签不能为空", trigger: "blur" }],
|
dictLabel: [{ required: true, message: '数据标签不能为空', trigger: 'blur' }],
|
||||||
dictValue: [{ required: true, message: "数据键值不能为空", trigger: "blur" }],
|
dictValue: [{ required: true, message: '数据键值不能为空', trigger: 'blur' }],
|
||||||
dictSort: [{ required: true, message: "数据顺序不能为空", trigger: "blur" }]
|
dictSort: [{ required: true, message: '数据顺序不能为空', trigger: 'blur' }]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -189,13 +188,13 @@ const getTypes = async (dictId: string | number) => {
|
|||||||
queryParams.value.dictType = data.dictType;
|
queryParams.value.dictType = data.dictType;
|
||||||
defaultDictType.value = data.dictType;
|
defaultDictType.value = data.dictType;
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 查询字典类型列表 */
|
/** 查询字典类型列表 */
|
||||||
const getTypeList = async () => {
|
const getTypeList = async () => {
|
||||||
const res = await getDictOptionselect()
|
const res = await getDictOptionselect();
|
||||||
typeOptions.value = res.data;
|
typeOptions.value = res.data;
|
||||||
}
|
};
|
||||||
/** 查询字典数据列表 */
|
/** 查询字典数据列表 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
@ -203,46 +202,46 @@ const getList = async () => {
|
|||||||
dataList.value = res.rows;
|
dataList.value = res.rows;
|
||||||
total.value = res.total;
|
total.value = res.total;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
};
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
reset();
|
reset();
|
||||||
}
|
};
|
||||||
/** 表单重置 */
|
/** 表单重置 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
form.value = { ...initFormData };
|
form.value = { ...initFormData };
|
||||||
dataFormRef.value?.resetFields();
|
dataFormRef.value?.resetFields();
|
||||||
}
|
};
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
/** 返回按钮操作 */
|
/** 返回按钮操作 */
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
const obj = { path: "/system/dict" };
|
const obj = { path: '/system/dict' };
|
||||||
proxy?.$tab.closeOpenPage(obj);
|
proxy?.$tab.closeOpenPage(obj);
|
||||||
}
|
};
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
queryParams.value.dictType = defaultDictType.value;
|
queryParams.value.dictType = defaultDictType.value;
|
||||||
handleQuery();
|
handleQuery();
|
||||||
}
|
};
|
||||||
/** 新增按钮操作 */
|
/** 新增按钮操作 */
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
reset();
|
reset();
|
||||||
form.value.dictType = queryParams.value.dictType;
|
form.value.dictType = queryParams.value.dictType;
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "添加字典数据";
|
dialog.title = '添加字典数据';
|
||||||
}
|
};
|
||||||
/** 多选框选中数据 */
|
/** 多选框选中数据 */
|
||||||
const handleSelectionChange = (selection: DictDataVO[]) => {
|
const handleSelectionChange = (selection: DictDataVO[]) => {
|
||||||
ids.value = selection.map(item => item.dictCode);
|
ids.value = selection.map((item) => item.dictCode);
|
||||||
single.value = selection.length != 1;
|
single.value = selection.length != 1;
|
||||||
multiple.value = !selection.length;
|
multiple.value = !selection.length;
|
||||||
}
|
};
|
||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
const handleUpdate = async (row?: DictDataVO) => {
|
const handleUpdate = async (row?: DictDataVO) => {
|
||||||
reset();
|
reset();
|
||||||
@ -250,40 +249,42 @@ const handleUpdate = async (row?: DictDataVO) => {
|
|||||||
const res = await getData(dictCode);
|
const res = await getData(dictCode);
|
||||||
Object.assign(form.value, res.data);
|
Object.assign(form.value, res.data);
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "修改字典数据";
|
dialog.title = '修改字典数据';
|
||||||
}
|
};
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
dataFormRef.value?.validate(async (valid: boolean) => {
|
dataFormRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
form.value.dictCode ? await updateData(form.value) : await addData(form.value);
|
form.value.dictCode ? await updateData(form.value) : await addData(form.value);
|
||||||
useDictStore().removeDict(queryParams.value.dictType);
|
useDictStore().removeDict(queryParams.value.dictType);
|
||||||
proxy?.$modal.msgSuccess("操作成功");
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
await getList();
|
await getList();
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row?: DictDataVO) => {
|
const handleDelete = async (row?: DictDataVO) => {
|
||||||
const dictCodes = row?.dictCode || ids.value;
|
const dictCodes = row?.dictCode || ids.value;
|
||||||
await proxy?.$modal.confirm('是否确认删除字典编码为"' + dictCodes + '"的数据项?');
|
await proxy?.$modal.confirm('是否确认删除字典编码为"' + dictCodes + '"的数据项?');
|
||||||
await delData(dictCodes);
|
await delData(dictCodes);
|
||||||
await getList();
|
await getList();
|
||||||
proxy?.$modal.msgSuccess("删除成功");
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
useDictStore().removeDict(queryParams.value.dictType);
|
useDictStore().removeDict(queryParams.value.dictType);
|
||||||
|
};
|
||||||
}
|
|
||||||
/** 导出按钮操作 */
|
/** 导出按钮操作 */
|
||||||
const handleExport = () => {
|
const handleExport = () => {
|
||||||
proxy?.download("system/dict/data/export", {
|
proxy?.download(
|
||||||
...queryParams.value
|
'system/dict/data/export',
|
||||||
}, `dict_data_${new Date().getTime()}.xlsx`);
|
{
|
||||||
}
|
...queryParams.value
|
||||||
|
},
|
||||||
|
`dict_data_${new Date().getTime()}.xlsx`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getTypes(route.params && route.params.dictId as string);
|
getTypes(route.params && (route.params.dictId as string));
|
||||||
getTypeList();
|
getTypeList();
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
<div class="mb-[10px]" v-show="showSearch">
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
|
||||||
<el-form-item label="字典名称" prop="dictName">
|
<el-form-item label="字典名称" prop="dictName">
|
||||||
<el-input v-model="queryParams.dictName" placeholder="请输入字典名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.dictName" placeholder="请输入字典名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -33,29 +33,29 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:dict:add']">新增</el-button>
|
<el-button v-hasPermi="['system:dict:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:dict:edit']">修改</el-button>
|
<el-button v-hasPermi="['system:dict:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">修改</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:dict:remove']">
|
<el-button v-hasPermi="['system:dict:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:dict:export']">导出</el-button>
|
<el-button v-hasPermi="['system:dict:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="danger" plain icon="Refresh" @click="handleRefreshCache" v-hasPermi="['system:dict:remove']">刷新缓存</el-button>
|
<el-button v-hasPermi="['system:dict:remove']" type="danger" plain icon="Refresh" @click="handleRefreshCache">刷新缓存</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="typeList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" :data="typeList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="字典编号" align="center" prop="dictId" v-if="false" />
|
<el-table-column v-if="false" label="字典编号" align="center" prop="dictId" />
|
||||||
<el-table-column label="字典名称" align="center" prop="dictName" :show-overflow-tooltip="true" />
|
<el-table-column label="字典名称" align="center" prop="dictName" :show-overflow-tooltip="true" />
|
||||||
<el-table-column label="字典类型" align="center" :show-overflow-tooltip="true">
|
<el-table-column label="字典类型" align="center" :show-overflow-tooltip="true">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
@ -73,19 +73,19 @@
|
|||||||
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
|
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="修改" placement="top">
|
<el-tooltip content="修改" placement="top">
|
||||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dict:edit']"></el-button>
|
<el-button v-hasPermi="['system:dict:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="删除" placement="top">
|
<el-tooltip content="删除" placement="top">
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:dict:remove']"></el-button>
|
<el-button v-hasPermi="['system:dict:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
|
||||||
</el-card>
|
</el-card>
|
||||||
<!-- 添加或修改参数配置对话框 -->
|
<!-- 添加或修改参数配置对话框 -->
|
||||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
<el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
|
||||||
<el-form ref="dictFormRef" :model="form" :rules="rules" label-width="80px">
|
<el-form ref="dictFormRef" :model="form" :rules="rules" label-width="80px">
|
||||||
<el-form-item label="字典名称" prop="dictName">
|
<el-form-item label="字典名称" prop="dictName">
|
||||||
<el-input v-model="form.dictName" placeholder="请输入字典名称" />
|
<el-input v-model="form.dictName" placeholder="请输入字典名称" />
|
||||||
@ -108,9 +108,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="Dict" lang="ts">
|
<script setup name="Dict" lang="ts">
|
||||||
import useDictStore from '@/store/modules/dict'
|
import useDictStore from '@/store/modules/dict';
|
||||||
import { listType, getType, delType, addType, updateType, refreshCache } from "@/api/system/dict/type";
|
import { listType, getType, delType, addType, updateType, refreshCache } from '@/api/system/dict/type';
|
||||||
import { DictTypeForm, DictTypeQuery, DictTypeVO } from "@/api/system/dict/type/types";
|
import { DictTypeForm, DictTypeQuery, DictTypeVO } from '@/api/system/dict/type/types';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
|
||||||
@ -126,7 +126,6 @@ const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
|
|||||||
const dictFormRef = ref<ElFormInstance>();
|
const dictFormRef = ref<ElFormInstance>();
|
||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
|
|
||||||
|
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = reactive<DialogOption>({
|
||||||
visible: false,
|
visible: false,
|
||||||
title: ''
|
title: ''
|
||||||
@ -137,7 +136,7 @@ const initFormData: DictTypeForm = {
|
|||||||
dictName: '',
|
dictName: '',
|
||||||
dictType: '',
|
dictType: '',
|
||||||
remark: ''
|
remark: ''
|
||||||
}
|
};
|
||||||
const data = reactive<PageData<DictTypeForm, DictTypeQuery>>({
|
const data = reactive<PageData<DictTypeForm, DictTypeQuery>>({
|
||||||
form: { ...initFormData },
|
form: { ...initFormData },
|
||||||
queryParams: {
|
queryParams: {
|
||||||
@ -147,9 +146,9 @@ const data = reactive<PageData<DictTypeForm, DictTypeQuery>>({
|
|||||||
dictType: ''
|
dictType: ''
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
dictName: [{ required: true, message: "字典名称不能为空", trigger: "blur" }],
|
dictName: [{ required: true, message: '字典名称不能为空', trigger: 'blur' }],
|
||||||
dictType: [{ required: true, message: "字典类型不能为空", trigger: "blur" }]
|
dictType: [{ required: true, message: '字典类型不能为空', trigger: 'blur' }]
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const { queryParams, form, rules } = toRefs(data);
|
const { queryParams, form, rules } = toRefs(data);
|
||||||
@ -157,45 +156,45 @@ const { queryParams, form, rules } = toRefs(data);
|
|||||||
/** 查询字典类型列表 */
|
/** 查询字典类型列表 */
|
||||||
const getList = () => {
|
const getList = () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
listType(proxy?.addDateRange(queryParams.value, dateRange.value)).then(res => {
|
listType(proxy?.addDateRange(queryParams.value, dateRange.value)).then((res) => {
|
||||||
typeList.value = res.rows;
|
typeList.value = res.rows;
|
||||||
total.value = res.total;
|
total.value = res.total;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
reset();
|
reset();
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
}
|
};
|
||||||
/** 表单重置 */
|
/** 表单重置 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
form.value = { ...initFormData };
|
form.value = { ...initFormData };
|
||||||
dictFormRef.value?.resetFields();
|
dictFormRef.value?.resetFields();
|
||||||
}
|
};
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
dateRange.value = ['', ''];
|
dateRange.value = ['', ''];
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
handleQuery();
|
handleQuery();
|
||||||
}
|
};
|
||||||
/** 新增按钮操作 */
|
/** 新增按钮操作 */
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
reset();
|
reset();
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "添加字典类型";
|
dialog.title = '添加字典类型';
|
||||||
}
|
};
|
||||||
/** 多选框选中数据 */
|
/** 多选框选中数据 */
|
||||||
const handleSelectionChange = (selection: DictTypeVO[]) => {
|
const handleSelectionChange = (selection: DictTypeVO[]) => {
|
||||||
ids.value = selection.map(item => item.dictId);
|
ids.value = selection.map((item) => item.dictId);
|
||||||
single.value = selection.length != 1;
|
single.value = selection.length != 1;
|
||||||
multiple.value = !selection.length;
|
multiple.value = !selection.length;
|
||||||
}
|
};
|
||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
const handleUpdate = async (row?: DictTypeVO) => {
|
const handleUpdate = async (row?: DictTypeVO) => {
|
||||||
reset();
|
reset();
|
||||||
@ -203,41 +202,45 @@ const handleUpdate = async (row?: DictTypeVO) => {
|
|||||||
const res = await getType(dictId);
|
const res = await getType(dictId);
|
||||||
Object.assign(form.value, res.data);
|
Object.assign(form.value, res.data);
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "修改字典类型";
|
dialog.title = '修改字典类型';
|
||||||
}
|
};
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
dictFormRef.value?.validate(async (valid: boolean) => {
|
dictFormRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
form.value.dictId ? await updateType(form.value) : await addType(form.value);
|
form.value.dictId ? await updateType(form.value) : await addType(form.value);
|
||||||
proxy?.$modal.msgSuccess("操作成功");
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
getList();
|
getList();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row?: DictTypeVO) => {
|
const handleDelete = async (row?: DictTypeVO) => {
|
||||||
const dictIds = row?.dictId || ids.value;
|
const dictIds = row?.dictId || ids.value;
|
||||||
await proxy?.$modal.confirm('是否确认删除字典编号为"' + dictIds + '"的数据项?');
|
await proxy?.$modal.confirm('是否确认删除字典编号为"' + dictIds + '"的数据项?');
|
||||||
await delType(dictIds);
|
await delType(dictIds);
|
||||||
getList();
|
getList();
|
||||||
proxy?.$modal.msgSuccess("删除成功");
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
}
|
};
|
||||||
/** 导出按钮操作 */
|
/** 导出按钮操作 */
|
||||||
const handleExport = () => {
|
const handleExport = () => {
|
||||||
proxy?.download("system/dict/type/export", {
|
proxy?.download(
|
||||||
...queryParams.value
|
'system/dict/type/export',
|
||||||
}, `dict_${new Date().getTime()}.xlsx`);
|
{
|
||||||
}
|
...queryParams.value
|
||||||
|
},
|
||||||
|
`dict_${new Date().getTime()}.xlsx`
|
||||||
|
);
|
||||||
|
};
|
||||||
/** 刷新缓存按钮操作 */
|
/** 刷新缓存按钮操作 */
|
||||||
const handleRefreshCache = async () => {
|
const handleRefreshCache = async () => {
|
||||||
await refreshCache();
|
await refreshCache();
|
||||||
proxy?.$modal.msgSuccess("刷新成功");
|
proxy?.$modal.msgSuccess('刷新成功');
|
||||||
useDictStore().cleanDict();
|
useDictStore().cleanDict();
|
||||||
}
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
<div class="mb-[10px]" v-show="showSearch">
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
|
||||||
<el-form-item label="菜单名称" prop="menuName">
|
<el-form-item label="菜单名称" prop="menuName">
|
||||||
@ -25,21 +25,21 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10">
|
<el-row :gutter="10">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['system:menu:add']">新增 </el-button>
|
<el-button v-hasPermi="['system:menu:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增 </el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
|
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table
|
<el-table
|
||||||
|
ref="menuTableRef"
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
:data="menuList"
|
:data="menuList"
|
||||||
row-key="menuId"
|
row-key="menuId"
|
||||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||||
ref="menuTableRef"
|
|
||||||
:default-expand-all="isExpandAll"
|
:default-expand-all="isExpandAll"
|
||||||
>
|
>
|
||||||
<el-table-column prop="menuName" label="菜单名称" :show-overflow-tooltip="true" width="160"></el-table-column>
|
<el-table-column prop="menuName" label="菜单名称" :show-overflow-tooltip="true" width="160"></el-table-column>
|
||||||
@ -64,20 +64,20 @@
|
|||||||
<el-table-column fixed="right" label="操作" width="180">
|
<el-table-column fixed="right" label="操作" width="180">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="修改" placement="top">
|
<el-tooltip content="修改" placement="top">
|
||||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:menu:edit']" />
|
<el-button v-hasPermi="['system:menu:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="新增" placement="top">
|
<el-tooltip content="新增" placement="top">
|
||||||
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['system:menu:add']" />
|
<el-button v-hasPermi="['system:menu:add']" link type="primary" icon="Plus" @click="handleAdd(scope.row)" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="删除" placement="top">
|
<el-tooltip content="删除" placement="top">
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:menu:remove']" />
|
<el-button v-hasPermi="['system:menu:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-dialog :title="dialog.title" v-model="dialog.visible" destroy-on-close append-to-bod width="750px">
|
<el-dialog v-model="dialog.visible" :title="dialog.title" destroy-on-close append-to-bod width="750px">
|
||||||
<el-form ref="menuFormRef" :model="form" :rules="rules" label-width="100px">
|
<el-form ref="menuFormRef" :model="form" :rules="rules" label-width="100px">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
@ -101,7 +101,7 @@
|
|||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="24" v-if="form.menuType !== 'F'">
|
<el-col v-if="form.menuType !== 'F'" :span="24">
|
||||||
<el-form-item label="菜单图标" prop="icon">
|
<el-form-item label="菜单图标" prop="icon">
|
||||||
<!-- 图标选择器 -->
|
<!-- 图标选择器 -->
|
||||||
<icon-select v-model="form.icon" />
|
<icon-select v-model="form.icon" />
|
||||||
@ -117,7 +117,7 @@
|
|||||||
<el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
|
<el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12" v-if="form.menuType !== 'F'">
|
<el-col v-if="form.menuType !== 'F'" :span="12">
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<template #label>
|
<template #label>
|
||||||
<span>
|
<span>
|
||||||
@ -134,7 +134,7 @@
|
|||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12" v-if="form.menuType !== 'F'">
|
<el-col v-if="form.menuType !== 'F'" :span="12">
|
||||||
<el-form-item prop="path">
|
<el-form-item prop="path">
|
||||||
<template #label>
|
<template #label>
|
||||||
<span>
|
<span>
|
||||||
@ -149,7 +149,7 @@
|
|||||||
<el-input v-model="form.path" placeholder="请输入路由地址" />
|
<el-input v-model="form.path" placeholder="请输入路由地址" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12" v-if="form.menuType === 'C'">
|
<el-col v-if="form.menuType === 'C'" :span="12">
|
||||||
<el-form-item prop="component">
|
<el-form-item prop="component">
|
||||||
<template #label>
|
<template #label>
|
||||||
<span>
|
<span>
|
||||||
@ -164,7 +164,7 @@
|
|||||||
<el-input v-model="form.component" placeholder="请输入组件路径" />
|
<el-input v-model="form.component" placeholder="请输入组件路径" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12" v-if="form.menuType !== 'M'">
|
<el-col v-if="form.menuType !== 'M'" :span="12">
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-input v-model="form.perms" placeholder="请输入权限标识" maxlength="100" />
|
<el-input v-model="form.perms" placeholder="请输入权限标识" maxlength="100" />
|
||||||
<template #label>
|
<template #label>
|
||||||
@ -179,7 +179,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12" v-if="form.menuType === 'C'">
|
<el-col v-if="form.menuType === 'C'" :span="12">
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-input v-model="form.queryParam" placeholder="请输入路由参数" maxlength="255" />
|
<el-input v-model="form.queryParam" placeholder="请输入路由参数" maxlength="255" />
|
||||||
<template #label>
|
<template #label>
|
||||||
@ -194,7 +194,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12" v-if="form.menuType === 'C'">
|
<el-col v-if="form.menuType === 'C'" :span="12">
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<template #label>
|
<template #label>
|
||||||
<span>
|
<span>
|
||||||
@ -212,7 +212,7 @@
|
|||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12" v-if="form.menuType !== 'F'">
|
<el-col v-if="form.menuType !== 'F'" :span="12">
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<template #label>
|
<template #label>
|
||||||
<span>
|
<span>
|
||||||
@ -271,14 +271,14 @@ interface MenuOptionsType {
|
|||||||
children: MenuOptionsType[] | undefined;
|
children: MenuOptionsType[] | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const { sys_show_hide, sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_show_hide", "sys_normal_disable"));
|
const { sys_show_hide, sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_show_hide', 'sys_normal_disable'));
|
||||||
|
|
||||||
const menuList = ref<MenuVO[]>([])
|
const menuList = ref<MenuVO[]>([]);
|
||||||
const loading = ref(true)
|
const loading = ref(true);
|
||||||
const showSearch = ref(true)
|
const showSearch = ref(true);
|
||||||
const menuOptions = ref<MenuOptionsType[]>([])
|
const menuOptions = ref<MenuOptionsType[]>([]);
|
||||||
const isExpandAll = ref(false)
|
const isExpandAll = ref(false);
|
||||||
|
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = reactive<DialogOption>({
|
||||||
visible: false,
|
visible: false,
|
||||||
@ -295,11 +295,11 @@ const initFormData = {
|
|||||||
icon: '',
|
icon: '',
|
||||||
menuType: MenuTypeEnum.M,
|
menuType: MenuTypeEnum.M,
|
||||||
orderNum: 1,
|
orderNum: 1,
|
||||||
isFrame: "1",
|
isFrame: '1',
|
||||||
isCache: "0",
|
isCache: '0',
|
||||||
visible: "0",
|
visible: '0',
|
||||||
status: "0"
|
status: '0'
|
||||||
}
|
};
|
||||||
const data = reactive<PageData<MenuForm, MenuQuery>>({
|
const data = reactive<PageData<MenuForm, MenuQuery>>({
|
||||||
form: { ...initFormData },
|
form: { ...initFormData },
|
||||||
queryParams: {
|
queryParams: {
|
||||||
@ -307,73 +307,73 @@ const data = reactive<PageData<MenuForm, MenuQuery>>({
|
|||||||
status: undefined
|
status: undefined
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
menuName: [{ required: true, message: "菜单名称不能为空", trigger: "blur" }],
|
menuName: [{ required: true, message: '菜单名称不能为空', trigger: 'blur' }],
|
||||||
orderNum: [{ required: true, message: "菜单顺序不能为空", trigger: "blur" }],
|
orderNum: [{ required: true, message: '菜单顺序不能为空', trigger: 'blur' }],
|
||||||
path: [{ required: true, message: "路由地址不能为空", trigger: "blur" }]
|
path: [{ required: true, message: '路由地址不能为空', trigger: 'blur' }]
|
||||||
},
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const menuTableRef = ref<ElTableInstance>();
|
const menuTableRef = ref<ElTableInstance>();
|
||||||
|
|
||||||
const { queryParams, form, rules } = toRefs<PageData<MenuForm, MenuQuery>>(data)
|
const { queryParams, form, rules } = toRefs<PageData<MenuForm, MenuQuery>>(data);
|
||||||
/** 查询菜单列表 */
|
/** 查询菜单列表 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
loading.value = true
|
loading.value = true;
|
||||||
const res = await listMenu(queryParams.value);
|
const res = await listMenu(queryParams.value);
|
||||||
const data = proxy?.handleTree<MenuVO>(res.data, "menuId")
|
const data = proxy?.handleTree<MenuVO>(res.data, 'menuId');
|
||||||
if (data) {
|
if (data) {
|
||||||
menuList.value = data
|
menuList.value = data;
|
||||||
}
|
}
|
||||||
loading.value = false
|
loading.value = false;
|
||||||
}
|
};
|
||||||
/** 查询菜单下拉树结构 */
|
/** 查询菜单下拉树结构 */
|
||||||
const getTreeselect = async () => {
|
const getTreeselect = async () => {
|
||||||
menuOptions.value = []
|
menuOptions.value = [];
|
||||||
const response = await listMenu();
|
const response = await listMenu();
|
||||||
const menu: MenuOptionsType = { menuId: 0, menuName: "主类目", children: [] }
|
const menu: MenuOptionsType = { menuId: 0, menuName: '主类目', children: [] };
|
||||||
menu.children = proxy?.handleTree<MenuOptionsType>(response.data, "menuId")
|
menu.children = proxy?.handleTree<MenuOptionsType>(response.data, 'menuId');
|
||||||
menuOptions.value.push(menu)
|
menuOptions.value.push(menu);
|
||||||
}
|
};
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
reset()
|
reset();
|
||||||
dialog.visible = false
|
dialog.visible = false;
|
||||||
}
|
};
|
||||||
/** 表单重置 */
|
/** 表单重置 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
form.value = { ...initFormData };
|
form.value = { ...initFormData };
|
||||||
menuFormRef.value?.resetFields();
|
menuFormRef.value?.resetFields();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
handleQuery();
|
handleQuery();
|
||||||
}
|
};
|
||||||
/** 新增按钮操作 */
|
/** 新增按钮操作 */
|
||||||
const handleAdd = (row?: MenuVO) => {
|
const handleAdd = (row?: MenuVO) => {
|
||||||
reset();
|
reset();
|
||||||
getTreeselect();
|
getTreeselect();
|
||||||
row && row.menuId ? form.value.parentId = row.menuId : form.value.parentId = 0;
|
row && row.menuId ? (form.value.parentId = row.menuId) : (form.value.parentId = 0);
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "添加菜单";
|
dialog.title = '添加菜单';
|
||||||
}
|
};
|
||||||
/** 展开/折叠操作 */
|
/** 展开/折叠操作 */
|
||||||
const handleToggleExpandAll = () => {
|
const handleToggleExpandAll = () => {
|
||||||
isExpandAll.value = !isExpandAll.value;
|
isExpandAll.value = !isExpandAll.value;
|
||||||
toggleExpandAll(menuList.value, isExpandAll.value)
|
toggleExpandAll(menuList.value, isExpandAll.value);
|
||||||
}
|
};
|
||||||
/** 展开/折叠所有 */
|
/** 展开/折叠所有 */
|
||||||
const toggleExpandAll = (data: MenuVO[], status: boolean) => {
|
const toggleExpandAll = (data: MenuVO[], status: boolean) => {
|
||||||
data.forEach((item: MenuVO) => {
|
data.forEach((item: MenuVO) => {
|
||||||
menuTableRef.value?.toggleRowExpansion(item, status)
|
menuTableRef.value?.toggleRowExpansion(item, status);
|
||||||
if (item.children && item.children.length > 0) toggleExpandAll(item.children, status)
|
if (item.children && item.children.length > 0) toggleExpandAll(item.children, status);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
const handleUpdate = async (row: MenuVO) => {
|
const handleUpdate = async (row: MenuVO) => {
|
||||||
reset();
|
reset();
|
||||||
@ -383,26 +383,26 @@ const handleUpdate = async (row: MenuVO) => {
|
|||||||
form.value = data;
|
form.value = data;
|
||||||
}
|
}
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "修改菜单";
|
dialog.title = '修改菜单';
|
||||||
}
|
};
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
menuFormRef.value?.validate(async (valid: boolean) => {
|
menuFormRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
form.value.menuId ? await updateMenu(form.value) : await addMenu(form.value);
|
form.value.menuId ? await updateMenu(form.value) : await addMenu(form.value);
|
||||||
proxy?.$modal.msgSuccess("操作成功");
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
await getList();
|
await getList();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row: MenuVO) => {
|
const handleDelete = async (row: MenuVO) => {
|
||||||
await proxy?.$modal.confirm('是否确认删除名称为"' + row.menuName + '"的数据项?');
|
await proxy?.$modal.confirm('是否确认删除名称为"' + row.menuName + '"的数据项?');
|
||||||
await delMenu(row.menuId);
|
await delMenu(row.menuId);
|
||||||
await getList();
|
await getList();
|
||||||
proxy?.$modal.msgSuccess("删除成功");
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
}
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
<div class="mb-[10px]" v-show="showSearch">
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
|
||||||
<el-form-item label="公告标题" prop="noticeTitle">
|
<el-form-item label="公告标题" prop="noticeTitle">
|
||||||
<el-input v-model="queryParams.noticeTitle" placeholder="请输入公告标题" clearable style="width: 200px" @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.noticeTitle" placeholder="请输入公告标题" clearable style="width: 200px" @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -28,25 +28,25 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:notice:add']">新增</el-button>
|
<el-button v-hasPermi="['system:notice:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:notice:edit']"
|
<el-button v-hasPermi="['system:notice:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()"
|
||||||
>修改</el-button
|
>修改</el-button
|
||||||
>
|
>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:notice:remove']">
|
<el-button v-hasPermi="['system:notice:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="noticeList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" :data="noticeList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="序号" align="center" prop="noticeId" width="100" v-if="false" />
|
<el-table-column v-if="false" label="序号" align="center" prop="noticeId" width="100" />
|
||||||
<el-table-column label="公告标题" align="center" prop="noticeTitle" :show-overflow-tooltip="true" />
|
<el-table-column label="公告标题" align="center" prop="noticeTitle" :show-overflow-tooltip="true" />
|
||||||
<el-table-column label="公告类型" align="center" prop="noticeType" width="100">
|
<el-table-column label="公告类型" align="center" prop="noticeType" width="100">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
@ -67,19 +67,19 @@
|
|||||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="修改" placement="top">
|
<el-tooltip content="修改" placement="top">
|
||||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:notice:edit']"></el-button>
|
<el-button v-hasPermi="['system:notice:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="删除" placement="top">
|
<el-tooltip content="删除" placement="top">
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:notice:remove']"></el-button>
|
<el-button v-hasPermi="['system:notice:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
|
||||||
</el-card>
|
</el-card>
|
||||||
<!-- 添加或修改公告对话框 -->
|
<!-- 添加或修改公告对话框 -->
|
||||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="780px" append-to-body>
|
<el-dialog v-model="dialog.visible" :title="dialog.title" width="780px" append-to-body>
|
||||||
<el-form ref="noticeFormRef" :model="form" :rules="rules" label-width="80px">
|
<el-form ref="noticeFormRef" :model="form" :rules="rules" label-width="80px">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
@ -97,8 +97,7 @@
|
|||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="状态">
|
<el-form-item label="状态">
|
||||||
<el-radio-group v-model="form.status">
|
<el-radio-group v-model="form.status">
|
||||||
<el-radio v-for="dict in sys_notice_status" :key="dict.value" :label="dict.value">{{ dict.label
|
<el-radio v-for="dict in sys_notice_status" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
|
||||||
}}</el-radio>
|
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -120,11 +119,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="Notice" lang="ts">
|
<script setup name="Notice" lang="ts">
|
||||||
import { listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api/system/notice";
|
import { listNotice, getNotice, delNotice, addNotice, updateNotice } from '@/api/system/notice';
|
||||||
import { NoticeForm, NoticeQuery, NoticeVO } from "@/api/system/notice/types";
|
import { NoticeForm, NoticeQuery, NoticeVO } from '@/api/system/notice/types';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const { sys_notice_status, sys_notice_type } = toRefs<any>(proxy?.useDict("sys_notice_status", "sys_notice_type"));
|
const { sys_notice_status, sys_notice_type } = toRefs<any>(proxy?.useDict('sys_notice_status', 'sys_notice_type'));
|
||||||
|
|
||||||
const noticeList = ref<NoticeVO[]>([]);
|
const noticeList = ref<NoticeVO[]>([]);
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
@ -137,7 +136,6 @@ const total = ref(0);
|
|||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
const noticeFormRef = ref<ElFormInstance>();
|
const noticeFormRef = ref<ElFormInstance>();
|
||||||
|
|
||||||
|
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = reactive<DialogOption>({
|
||||||
visible: false,
|
visible: false,
|
||||||
title: ''
|
title: ''
|
||||||
@ -148,10 +146,10 @@ const initFormData: NoticeForm = {
|
|||||||
noticeTitle: '',
|
noticeTitle: '',
|
||||||
noticeType: '',
|
noticeType: '',
|
||||||
noticeContent: '',
|
noticeContent: '',
|
||||||
status: "0",
|
status: '0',
|
||||||
remark: '',
|
remark: '',
|
||||||
createByName: ''
|
createByName: ''
|
||||||
}
|
};
|
||||||
const data = reactive<PageData<NoticeForm, NoticeQuery>>({
|
const data = reactive<PageData<NoticeForm, NoticeQuery>>({
|
||||||
form: { ...initFormData },
|
form: { ...initFormData },
|
||||||
queryParams: {
|
queryParams: {
|
||||||
@ -163,9 +161,9 @@ const data = reactive<PageData<NoticeForm, NoticeQuery>>({
|
|||||||
noticeType: ''
|
noticeType: ''
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
noticeTitle: [{ required: true, message: "公告标题不能为空", trigger: "blur" }],
|
noticeTitle: [{ required: true, message: '公告标题不能为空', trigger: 'blur' }],
|
||||||
noticeType: [{ required: true, message: "公告类型不能为空", trigger: "change" }]
|
noticeType: [{ required: true, message: '公告类型不能为空', trigger: 'change' }]
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const { queryParams, form, rules } = toRefs(data);
|
const { queryParams, form, rules } = toRefs(data);
|
||||||
@ -177,39 +175,39 @@ const getList = async () => {
|
|||||||
noticeList.value = res.rows;
|
noticeList.value = res.rows;
|
||||||
total.value = res.total;
|
total.value = res.total;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
};
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
reset();
|
reset();
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
}
|
};
|
||||||
/** 表单重置 */
|
/** 表单重置 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
form.value = { ...initFormData };
|
form.value = { ...initFormData };
|
||||||
noticeFormRef.value?.resetFields();
|
noticeFormRef.value?.resetFields();
|
||||||
}
|
};
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
handleQuery();
|
handleQuery();
|
||||||
}
|
};
|
||||||
/** 多选框选中数据 */
|
/** 多选框选中数据 */
|
||||||
const handleSelectionChange = (selection: NoticeVO[]) => {
|
const handleSelectionChange = (selection: NoticeVO[]) => {
|
||||||
ids.value = selection.map(item => item.noticeId);
|
ids.value = selection.map((item) => item.noticeId);
|
||||||
single.value = selection.length != 1;
|
single.value = selection.length != 1;
|
||||||
multiple.value = !selection.length;
|
multiple.value = !selection.length;
|
||||||
}
|
};
|
||||||
/** 新增按钮操作 */
|
/** 新增按钮操作 */
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
reset();
|
reset();
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "添加公告";
|
dialog.title = '添加公告';
|
||||||
}
|
};
|
||||||
/**修改按钮操作 */
|
/**修改按钮操作 */
|
||||||
const handleUpdate = async (row?: NoticeVO) => {
|
const handleUpdate = async (row?: NoticeVO) => {
|
||||||
reset();
|
reset();
|
||||||
@ -217,29 +215,29 @@ const handleUpdate = async (row?: NoticeVO) => {
|
|||||||
const { data } = await getNotice(noticeId);
|
const { data } = await getNotice(noticeId);
|
||||||
Object.assign(form.value, data);
|
Object.assign(form.value, data);
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "修改公告";
|
dialog.title = '修改公告';
|
||||||
}
|
};
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
noticeFormRef.value?.validate(async (valid: boolean) => {
|
noticeFormRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
form.value.noticeId ? await updateNotice(form.value) : await addNotice(form.value);
|
form.value.noticeId ? await updateNotice(form.value) : await addNotice(form.value);
|
||||||
proxy?.$modal.msgSuccess("修改成功");
|
proxy?.$modal.msgSuccess('修改成功');
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
await getList();
|
await getList();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row?: NoticeVO) => {
|
const handleDelete = async (row?: NoticeVO) => {
|
||||||
const noticeIds = row?.noticeId || ids.value
|
const noticeIds = row?.noticeId || ids.value;
|
||||||
await proxy?.$modal.confirm('是否确认删除公告编号为"' + noticeIds + '"的数据项?');
|
await proxy?.$modal.confirm('是否确认删除公告编号为"' + noticeIds + '"的数据项?');
|
||||||
await delNotice(noticeIds);
|
await delNotice(noticeIds);
|
||||||
await getList();
|
await getList();
|
||||||
proxy?.$modal.msgSuccess("删除成功");
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
}
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
<div class="mb-[10px]" v-show="showSearch">
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
|
||||||
<el-form-item label="配置key" prop="configKey">
|
<el-form-item label="配置key" prop="configKey">
|
||||||
<el-input v-model="queryParams.configKey" placeholder="配置key" clearable style="width: 200px" @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.configKey" placeholder="配置key" clearable style="width: 200px" @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -39,27 +39,27 @@
|
|||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="ossConfigList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" :data="ossConfigList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="主建" align="center" prop="ossConfigId" v-if="columns[0].visible" />
|
<el-table-column v-if="columns[0].visible" label="主建" align="center" prop="ossConfigId" />
|
||||||
<el-table-column label="配置key" align="center" prop="configKey" v-if="columns[1].visible" />
|
<el-table-column v-if="columns[1].visible" label="配置key" align="center" prop="configKey" />
|
||||||
<el-table-column label="访问站点" align="center" prop="endpoint" v-if="columns[2].visible" width="200" />
|
<el-table-column v-if="columns[2].visible" label="访问站点" align="center" prop="endpoint" width="200" />
|
||||||
<el-table-column label="自定义域名" align="center" prop="domain" v-if="columns[3].visible" width="200" />
|
<el-table-column v-if="columns[3].visible" label="自定义域名" align="center" prop="domain" width="200" />
|
||||||
<el-table-column label="桶名称" align="center" prop="bucketName" v-if="columns[4].visible" />
|
<el-table-column v-if="columns[4].visible" label="桶名称" align="center" prop="bucketName" />
|
||||||
<el-table-column label="前缀" align="center" prop="prefix" v-if="columns[5].visible" />
|
<el-table-column v-if="columns[5].visible" label="前缀" align="center" prop="prefix" />
|
||||||
<el-table-column label="域" align="center" prop="region" v-if="columns[6].visible" />
|
<el-table-column v-if="columns[6].visible" label="域" align="center" prop="region" />
|
||||||
<el-table-column label="桶权限类型" align="center" prop="accessPolicy" v-if="columns[7].visible">
|
<el-table-column v-if="columns[7].visible" label="桶权限类型" align="center" prop="accessPolicy">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag type="warning" v-if="scope.row.accessPolicy === '0'">private</el-tag>
|
<el-tag v-if="scope.row.accessPolicy === '0'" type="warning">private</el-tag>
|
||||||
<el-tag type="success" v-if="scope.row.accessPolicy === '1'">public</el-tag>
|
<el-tag v-if="scope.row.accessPolicy === '1'" type="success">public</el-tag>
|
||||||
<el-tag type="info" v-if="scope.row.accessPolicy === '2'">custom</el-tag>
|
<el-tag v-if="scope.row.accessPolicy === '2'" type="info">custom</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="是否默认" align="center" prop="status" v-if="columns[8].visible">
|
<el-table-column v-if="columns[8].visible" label="是否默认" align="center" prop="status">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
|
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
|
||||||
</template>
|
</template>
|
||||||
@ -76,10 +76,10 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
|
||||||
</el-card>
|
</el-card>
|
||||||
<!-- 添加或修改对象存储配置对话框 -->
|
<!-- 添加或修改对象存储配置对话框 -->
|
||||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="800px" append-to-body>
|
<el-dialog v-model="dialog.visible" :title="dialog.title" width="800px" append-to-body>
|
||||||
<el-form ref="ossConfigFormRef" :model="form" :rules="rules" label-width="120px">
|
<el-form ref="ossConfigFormRef" :model="form" :rules="rules" label-width="120px">
|
||||||
<el-form-item label="配置key" prop="configKey">
|
<el-form-item label="配置key" prop="configKey">
|
||||||
<el-input v-model="form.configKey" placeholder="请输入配置key" />
|
<el-input v-model="form.configKey" placeholder="请输入配置key" />
|
||||||
@ -132,19 +132,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="OssConfig" lang="ts">
|
<script setup name="OssConfig" lang="ts">
|
||||||
import {
|
import { listOssConfig, getOssConfig, delOssConfig, addOssConfig, updateOssConfig, changeOssConfigStatus } from '@/api/system/ossConfig';
|
||||||
listOssConfig,
|
import { OssConfigForm, OssConfigQuery, OssConfigVO } from '@/api/system/ossConfig/types';
|
||||||
getOssConfig,
|
|
||||||
delOssConfig,
|
|
||||||
addOssConfig,
|
|
||||||
updateOssConfig,
|
|
||||||
changeOssConfigStatus
|
|
||||||
} from "@/api/system/ossConfig";
|
|
||||||
import { OssConfigForm, OssConfigQuery, OssConfigVO } from "@/api/system/ossConfig/types";
|
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance
|
const { sys_yes_no } = toRefs<any>(proxy?.useDict('sys_yes_no'));
|
||||||
const { sys_yes_no } = toRefs<any>(proxy?.useDict("sys_yes_no"));
|
|
||||||
|
|
||||||
const ossConfigList = ref<OssConfigVO[]>([]);
|
const ossConfigList = ref<OssConfigVO[]>([]);
|
||||||
const buttonLoading = ref(false);
|
const buttonLoading = ref(false);
|
||||||
@ -176,7 +168,6 @@ const columns = ref<FieldOption[]>([
|
|||||||
{ key: 8, label: `状态`, visible: true }
|
{ key: 8, label: `状态`, visible: true }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
const initFormData: OssConfigForm = {
|
const initFormData: OssConfigForm = {
|
||||||
ossConfigId: undefined,
|
ossConfigId: undefined,
|
||||||
configKey: '',
|
configKey: '',
|
||||||
@ -186,12 +177,12 @@ const initFormData: OssConfigForm = {
|
|||||||
prefix: '',
|
prefix: '',
|
||||||
endpoint: '',
|
endpoint: '',
|
||||||
domain: '',
|
domain: '',
|
||||||
isHttps: "N",
|
isHttps: 'N',
|
||||||
accessPolicy: "1",
|
accessPolicy: '1',
|
||||||
region: '',
|
region: '',
|
||||||
status: "1",
|
status: '1',
|
||||||
remark: '',
|
remark: ''
|
||||||
}
|
};
|
||||||
const data = reactive<PageData<OssConfigForm, OssConfigQuery>>({
|
const data = reactive<PageData<OssConfigForm, OssConfigQuery>>({
|
||||||
form: { ...initFormData },
|
form: { ...initFormData },
|
||||||
// 查询参数
|
// 查询参数
|
||||||
@ -200,47 +191,47 @@ const data = reactive<PageData<OssConfigForm, OssConfigQuery>>({
|
|||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
configKey: '',
|
configKey: '',
|
||||||
bucketName: '',
|
bucketName: '',
|
||||||
status: '',
|
status: ''
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
configKey: [{ required: true, message: "configKey不能为空", trigger: "blur" },],
|
configKey: [{ required: true, message: 'configKey不能为空', trigger: 'blur' }],
|
||||||
accessKey: [
|
accessKey: [
|
||||||
{ required: true, message: "accessKey不能为空", trigger: "blur" },
|
{ required: true, message: 'accessKey不能为空', trigger: 'blur' },
|
||||||
{
|
{
|
||||||
min: 2,
|
min: 2,
|
||||||
max: 200,
|
max: 200,
|
||||||
message: "accessKey长度必须介于 2 和 100 之间",
|
message: 'accessKey长度必须介于 2 和 100 之间',
|
||||||
trigger: "blur",
|
trigger: 'blur'
|
||||||
},
|
}
|
||||||
],
|
],
|
||||||
secretKey: [
|
secretKey: [
|
||||||
{ required: true, message: "secretKey不能为空", trigger: "blur" },
|
{ required: true, message: 'secretKey不能为空', trigger: 'blur' },
|
||||||
{
|
{
|
||||||
min: 2,
|
min: 2,
|
||||||
max: 100,
|
max: 100,
|
||||||
message: "secretKey长度必须介于 2 和 100 之间",
|
message: 'secretKey长度必须介于 2 和 100 之间',
|
||||||
trigger: "blur",
|
trigger: 'blur'
|
||||||
},
|
}
|
||||||
],
|
],
|
||||||
bucketName: [
|
bucketName: [
|
||||||
{ required: true, message: "bucketName不能为空", trigger: "blur" },
|
{ required: true, message: 'bucketName不能为空', trigger: 'blur' },
|
||||||
{
|
{
|
||||||
min: 2,
|
min: 2,
|
||||||
max: 100,
|
max: 100,
|
||||||
message: "bucketName长度必须介于 2 和 100 之间",
|
message: 'bucketName长度必须介于 2 和 100 之间',
|
||||||
trigger: "blur",
|
trigger: 'blur'
|
||||||
},
|
}
|
||||||
],
|
],
|
||||||
endpoint: [
|
endpoint: [
|
||||||
{ required: true, message: "endpoint不能为空", trigger: "blur" },
|
{ required: true, message: 'endpoint不能为空', trigger: 'blur' },
|
||||||
{
|
{
|
||||||
min: 2,
|
min: 2,
|
||||||
max: 100,
|
max: 100,
|
||||||
message: "endpoint名称长度必须介于 2 和 100 之间",
|
message: 'endpoint名称长度必须介于 2 和 100 之间',
|
||||||
trigger: "blur",
|
trigger: 'blur'
|
||||||
},
|
}
|
||||||
],
|
],
|
||||||
accessPolicy: [{ required: true, message: "accessPolicy不能为空", trigger: "blur" }]
|
accessPolicy: [{ required: true, message: 'accessPolicy不能为空', trigger: 'blur' }]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -253,39 +244,39 @@ const getList = async () => {
|
|||||||
ossConfigList.value = res.rows;
|
ossConfigList.value = res.rows;
|
||||||
total.value = res.total;
|
total.value = res.total;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
};
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
reset();
|
reset();
|
||||||
}
|
};
|
||||||
/** 表单重置 */
|
/** 表单重置 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
form.value = { ...initFormData };
|
form.value = { ...initFormData };
|
||||||
ossConfigFormRef.value?.resetFields();
|
ossConfigFormRef.value?.resetFields();
|
||||||
}
|
};
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
handleQuery();
|
handleQuery();
|
||||||
}
|
};
|
||||||
/** 选择条数 */
|
/** 选择条数 */
|
||||||
const handleSelectionChange = (selection: OssConfigVO[]) => {
|
const handleSelectionChange = (selection: OssConfigVO[]) => {
|
||||||
ids.value = selection.map(item => item.ossConfigId);
|
ids.value = selection.map((item) => item.ossConfigId);
|
||||||
single.value = selection.length != 1;
|
single.value = selection.length != 1;
|
||||||
multiple.value = !selection.length;
|
multiple.value = !selection.length;
|
||||||
}
|
};
|
||||||
/** 新增按钮操作 */
|
/** 新增按钮操作 */
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
reset();
|
reset();
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "添加对象存储配置";
|
dialog.title = '添加对象存储配置';
|
||||||
}
|
};
|
||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
const handleUpdate = async (row?: OssConfigVO) => {
|
const handleUpdate = async (row?: OssConfigVO) => {
|
||||||
reset();
|
reset();
|
||||||
@ -293,49 +284,49 @@ const handleUpdate = async (row?: OssConfigVO) => {
|
|||||||
const res = await getOssConfig(ossConfigId);
|
const res = await getOssConfig(ossConfigId);
|
||||||
Object.assign(form.value, res.data);
|
Object.assign(form.value, res.data);
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "修改对象存储配置";
|
dialog.title = '修改对象存储配置';
|
||||||
}
|
};
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
ossConfigFormRef.value?.validate(async (valid: boolean) => {
|
ossConfigFormRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
buttonLoading.value = true;
|
buttonLoading.value = true;
|
||||||
if (form.value.ossConfigId) {
|
if (form.value.ossConfigId) {
|
||||||
await updateOssConfig(form.value).finally(() => buttonLoading.value = false);
|
await updateOssConfig(form.value).finally(() => (buttonLoading.value = false));
|
||||||
} else {
|
} else {
|
||||||
await addOssConfig(form.value).finally(() => buttonLoading.value = false);
|
await addOssConfig(form.value).finally(() => (buttonLoading.value = false));
|
||||||
}
|
}
|
||||||
proxy?.$modal.msgSuccess("新增成功");
|
proxy?.$modal.msgSuccess('新增成功');
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
await getList();
|
await getList();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
/** 状态修改 */
|
/** 状态修改 */
|
||||||
const handleStatusChange = async (row: OssConfigVO) => {
|
const handleStatusChange = async (row: OssConfigVO) => {
|
||||||
let text = row.status === "0" ? "启用" : "停用";
|
let text = row.status === '0' ? '启用' : '停用';
|
||||||
try {
|
try {
|
||||||
await proxy?.$modal.confirm('确认要"' + text + '""' + row.configKey + '"配置吗?');
|
await proxy?.$modal.confirm('确认要"' + text + '""' + row.configKey + '"配置吗?');
|
||||||
await changeOssConfigStatus(row.ossConfigId, row.status, row.configKey);
|
await changeOssConfigStatus(row.ossConfigId, row.status, row.configKey);
|
||||||
await getList()
|
await getList();
|
||||||
proxy?.$modal.msgSuccess(text + "成功");
|
proxy?.$modal.msgSuccess(text + '成功');
|
||||||
} catch { return } finally {
|
} catch {
|
||||||
row.status = row.status === "0" ? "1" : "0";
|
return;
|
||||||
|
} finally {
|
||||||
|
row.status = row.status === '0' ? '1' : '0';
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}
|
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row?: OssConfigVO) => {
|
const handleDelete = async (row?: OssConfigVO) => {
|
||||||
const ossConfigIds = row?.ossConfigId || ids.value;
|
const ossConfigIds = row?.ossConfigId || ids.value;
|
||||||
await proxy?.$modal.confirm('是否确认删除OSS配置编号为"' + ossConfigIds + '"的数据项?');
|
await proxy?.$modal.confirm('是否确认删除OSS配置编号为"' + ossConfigIds + '"的数据项?');
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
await delOssConfig(ossConfigIds).finally(() => loading.value = false);
|
await delOssConfig(ossConfigIds).finally(() => (loading.value = false));
|
||||||
await getList();
|
await getList();
|
||||||
proxy?.$modal.msgSuccess("删除成功");
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
|
};
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
<div class="mb-[10px]" v-show="showSearch">
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
|
||||||
<el-form-item label="文件名" prop="fileName">
|
<el-form-item label="文件名" prop="fileName">
|
||||||
<el-input v-model="queryParams.fileName" placeholder="请输入文件名" clearable style="width: 200px" @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.fileName" placeholder="请输入文件名" clearable style="width: 200px" @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -40,44 +40,42 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Upload" @click="handleFile" v-hasPermi="['system:oss:upload']">上传文件</el-button>
|
<el-button v-hasPermi="['system:oss:upload']" type="primary" plain icon="Upload" @click="handleFile">上传文件</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Upload" @click="handleImage" v-hasPermi="['system:oss:upload']">上传图片</el-button>
|
<el-button v-hasPermi="['system:oss:upload']" type="primary" plain icon="Upload" @click="handleImage">上传图片</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:oss:remove']">
|
<el-button v-hasPermi="['system:oss:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button
|
<el-button
|
||||||
|
v-hasPermi="['system:oss:edit']"
|
||||||
:type="previewListResource ? 'danger' : 'warning'"
|
:type="previewListResource ? 'danger' : 'warning'"
|
||||||
plain
|
plain
|
||||||
@click="handlePreviewListResource(!previewListResource)"
|
@click="handlePreviewListResource(!previewListResource)"
|
||||||
v-hasPermi="['system:oss:edit']"
|
>预览开关 : {{ previewListResource ? '禁用' : '启用' }}</el-button
|
||||||
>预览开关 :
|
|
||||||
{{
|
|
||||||
previewListResource ? "禁用" : "启用" }}</el-button
|
|
||||||
>
|
>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="info" plain icon="Operation" @click="handleOssConfig" v-hasPermi="['system:oss:list']">配置管理</el-button>
|
<el-button v-hasPermi="['system:oss:list']" type="info" plain icon="Operation" @click="handleOssConfig">配置管理</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table
|
<el-table
|
||||||
|
v-if="showTable"
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
:data="ossList"
|
:data="ossList"
|
||||||
@selection-change="handleSelectionChange"
|
|
||||||
:header-cell-class-name="handleHeaderClass"
|
:header-cell-class-name="handleHeaderClass"
|
||||||
|
@selection-change="handleSelectionChange"
|
||||||
@header-click="handleHeaderCLick"
|
@header-click="handleHeaderCLick"
|
||||||
v-if="showTable"
|
|
||||||
>
|
>
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="对象存储主键" align="center" prop="ossId" v-if="false" />
|
<el-table-column v-if="false" label="对象存储主键" align="center" prop="ossId" />
|
||||||
<el-table-column label="文件名" align="center" prop="fileName" />
|
<el-table-column label="文件名" align="center" prop="fileName" />
|
||||||
<el-table-column label="原名" align="center" prop="originalName" />
|
<el-table-column label="原名" align="center" prop="originalName" />
|
||||||
<el-table-column label="文件后缀" align="center" prop="fileSuffix" />
|
<el-table-column label="文件后缀" align="center" prop="fileSuffix" />
|
||||||
@ -90,7 +88,7 @@
|
|||||||
:src="scope.row.url"
|
:src="scope.row.url"
|
||||||
:preview-src-list="[scope.row.url]"
|
:preview-src-list="[scope.row.url]"
|
||||||
/>
|
/>
|
||||||
<span v-text="scope.row.url" v-if="!checkFileSuffix(scope.row.fileSuffix) || !previewListResource" />
|
<span v-if="!checkFileSuffix(scope.row.fileSuffix) || !previewListResource" v-text="scope.row.url" />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180" sortable="custom">
|
<el-table-column label="创建时间" align="center" prop="createTime" width="180" sortable="custom">
|
||||||
@ -103,23 +101,23 @@
|
|||||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="下载" placement="top">
|
<el-tooltip content="下载" placement="top">
|
||||||
<el-button link type="primary" icon="Download" @click="handleDownload(scope.row)" v-hasPermi="['system:oss:download']"></el-button>
|
<el-button v-hasPermi="['system:oss:download']" link type="primary" icon="Download" @click="handleDownload(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="删除" placement="top">
|
<el-tooltip content="删除" placement="top">
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:oss:remove']"></el-button>
|
<el-button v-hasPermi="['system:oss:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
|
||||||
</el-card>
|
</el-card>
|
||||||
<!-- 添加或修改OSS对象存储对话框 -->
|
<!-- 添加或修改OSS对象存储对话框 -->
|
||||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
<el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
|
||||||
<el-form ref="ossFormRef" :model="form" :rules="rules" label-width="80px">
|
<el-form ref="ossFormRef" :model="form" :rules="rules" label-width="80px">
|
||||||
<el-form-item label="文件名">
|
<el-form-item label="文件名">
|
||||||
<fileUpload v-model="form.file" v-if="type === 0" />
|
<fileUpload v-if="type === 0" v-model="form.file" />
|
||||||
<imageUpload v-model="form.file" v-if="type === 1" />
|
<imageUpload v-if="type === 1" v-model="form.file" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
@ -133,9 +131,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="Oss" lang="ts">
|
<script setup name="Oss" lang="ts">
|
||||||
import { listOss, delOss } from "@/api/system/oss";
|
import { listOss, delOss } from '@/api/system/oss';
|
||||||
import ImagePreview from "@/components/ImagePreview/index.vue";
|
import ImagePreview from '@/components/ImagePreview/index.vue';
|
||||||
import { OssForm, OssQuery, OssVO } from "@/api/system/oss/types";
|
import { OssForm, OssQuery, OssVO } from '@/api/system/oss/types';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
@ -165,8 +163,8 @@ const ossFormRef = ref<ElFormInstance>();
|
|||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
|
|
||||||
const initFormData = {
|
const initFormData = {
|
||||||
file: undefined,
|
file: undefined
|
||||||
}
|
};
|
||||||
const data = reactive<PageData<OssForm, OssQuery>>({
|
const data = reactive<PageData<OssForm, OssQuery>>({
|
||||||
form: { ...initFormData },
|
form: { ...initFormData },
|
||||||
// 查询参数
|
// 查询参数
|
||||||
@ -182,9 +180,7 @@ const data = reactive<PageData<OssForm, OssQuery>>({
|
|||||||
isAsc: defaultSort.value.order
|
isAsc: defaultSort.value.order
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
file: [
|
file: [{ required: true, message: '文件不能为空', trigger: 'blur' }]
|
||||||
{ required: true, message: "文件不能为空", trigger: "blur" }
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -193,17 +189,17 @@ const { queryParams, form, rules } = toRefs(data);
|
|||||||
/** 查询OSS对象存储列表 */
|
/** 查询OSS对象存储列表 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const res = await proxy?.getConfigKey("sys.oss.previewListResource");
|
const res = await proxy?.getConfigKey('sys.oss.previewListResource');
|
||||||
previewListResource.value = res?.data === undefined ? true : res.data === 'true';
|
previewListResource.value = res?.data === undefined ? true : res.data === 'true';
|
||||||
const response = await listOss(proxy?.addDateRange(queryParams.value, dateRangeCreateTime.value, "CreateTime"));
|
const response = await listOss(proxy?.addDateRange(queryParams.value, dateRangeCreateTime.value, 'CreateTime'));
|
||||||
ossList.value = response.rows;
|
ossList.value = response.rows;
|
||||||
total.value = response.total;
|
total.value = response.total;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
showTable.value = true;
|
showTable.value = true;
|
||||||
}
|
};
|
||||||
function checkFileSuffix(fileSuffix: string[]) {
|
function checkFileSuffix(fileSuffix: string[]) {
|
||||||
let arr = ["png", "jpg", "jpeg"];
|
let arr = ['png', 'jpg', 'jpeg'];
|
||||||
return arr.some(type => {
|
return arr.some((type) => {
|
||||||
return fileSuffix.indexOf(type) > -1;
|
return fileSuffix.indexOf(type) > -1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -233,18 +229,18 @@ function resetQuery() {
|
|||||||
}
|
}
|
||||||
/** 选择条数 */
|
/** 选择条数 */
|
||||||
function handleSelectionChange(selection: OssVO[]) {
|
function handleSelectionChange(selection: OssVO[]) {
|
||||||
ids.value = selection.map(item => item.ossId);
|
ids.value = selection.map((item) => item.ossId);
|
||||||
single.value = selection.length != 1;
|
single.value = selection.length != 1;
|
||||||
multiple.value = !selection.length;
|
multiple.value = !selection.length;
|
||||||
}
|
}
|
||||||
/** 设置列的排序为我们自定义的排序 */
|
/** 设置列的排序为我们自定义的排序 */
|
||||||
const handleHeaderClass = ({ column }: any): any => {
|
const handleHeaderClass = ({ column }: any): any => {
|
||||||
column.order = column.multiOrder
|
column.order = column.multiOrder;
|
||||||
}
|
};
|
||||||
/** 点击表头进行排序 */
|
/** 点击表头进行排序 */
|
||||||
const handleHeaderCLick = (column: any) => {
|
const handleHeaderCLick = (column: any) => {
|
||||||
if (column.sortable !== 'custom') {
|
if (column.sortable !== 'custom') {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
switch (column.multiOrder) {
|
switch (column.multiOrder) {
|
||||||
case 'descending':
|
case 'descending':
|
||||||
@ -257,20 +253,20 @@ const handleHeaderCLick = (column: any) => {
|
|||||||
column.multiOrder = 'descending';
|
column.multiOrder = 'descending';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
handleOrderChange(column.property, column.multiOrder)
|
handleOrderChange(column.property, column.multiOrder);
|
||||||
}
|
};
|
||||||
const handleOrderChange = (prop: string, order: string) => {
|
const handleOrderChange = (prop: string, order: string) => {
|
||||||
let orderByArr = queryParams.value.orderByColumn ? queryParams.value.orderByColumn.split(",") : [];
|
let orderByArr = queryParams.value.orderByColumn ? queryParams.value.orderByColumn.split(',') : [];
|
||||||
let isAscArr = queryParams.value.isAsc ? queryParams.value.isAsc.split(",") : [];
|
let isAscArr = queryParams.value.isAsc ? queryParams.value.isAsc.split(',') : [];
|
||||||
let propIndex = orderByArr.indexOf(prop)
|
let propIndex = orderByArr.indexOf(prop);
|
||||||
if (propIndex !== -1) {
|
if (propIndex !== -1) {
|
||||||
if (order) {
|
if (order) {
|
||||||
//排序里已存在 只修改排序
|
//排序里已存在 只修改排序
|
||||||
isAscArr[propIndex] = order;
|
isAscArr[propIndex] = order;
|
||||||
} else {
|
} else {
|
||||||
//如果order为null 则删除排序字段和属性
|
//如果order为null 则删除排序字段和属性
|
||||||
isAscArr.splice(propIndex, 1);//删除排序
|
isAscArr.splice(propIndex, 1); //删除排序
|
||||||
orderByArr.splice(propIndex, 1);//删除属性
|
orderByArr.splice(propIndex, 1); //删除属性
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//排序里不存在则新增排序
|
//排序里不存在则新增排序
|
||||||
@ -278,58 +274,60 @@ const handleOrderChange = (prop: string, order: string) => {
|
|||||||
isAscArr.push(order);
|
isAscArr.push(order);
|
||||||
}
|
}
|
||||||
//合并排序
|
//合并排序
|
||||||
queryParams.value.orderByColumn = orderByArr.join(",");
|
queryParams.value.orderByColumn = orderByArr.join(',');
|
||||||
queryParams.value.isAsc = isAscArr.join(",");
|
queryParams.value.isAsc = isAscArr.join(',');
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
/** 任务日志列表查询 */
|
/** 任务日志列表查询 */
|
||||||
const handleOssConfig = () => {
|
const handleOssConfig = () => {
|
||||||
router.push('/system/oss-config/index')
|
router.push('/system/oss-config/index');
|
||||||
}
|
};
|
||||||
/** 文件按钮操作 */
|
/** 文件按钮操作 */
|
||||||
const handleFile = () => {
|
const handleFile = () => {
|
||||||
reset();
|
reset();
|
||||||
type.value = 0;
|
type.value = 0;
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "上传文件";
|
dialog.title = '上传文件';
|
||||||
}
|
};
|
||||||
/** 图片按钮操作 */
|
/** 图片按钮操作 */
|
||||||
const handleImage = () => {
|
const handleImage = () => {
|
||||||
reset();
|
reset();
|
||||||
type.value = 1;
|
type.value = 1;
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "上传图片";
|
dialog.title = '上传图片';
|
||||||
}
|
};
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
/** 下载按钮操作 */
|
/** 下载按钮操作 */
|
||||||
const handleDownload = (row: OssVO) => {
|
const handleDownload = (row: OssVO) => {
|
||||||
proxy?.$download.oss(row.ossId)
|
proxy?.$download.oss(row.ossId);
|
||||||
}
|
};
|
||||||
/** 用户状态修改 */
|
/** 用户状态修改 */
|
||||||
const handlePreviewListResource = async (preview: boolean) => {
|
const handlePreviewListResource = async (preview: boolean) => {
|
||||||
let text = preview ? "启用" : "停用";
|
let text = preview ? '启用' : '停用';
|
||||||
try {
|
try {
|
||||||
await proxy?.$modal.confirm('确认要"' + text + '""预览列表图片"配置吗?');
|
await proxy?.$modal.confirm('确认要"' + text + '""预览列表图片"配置吗?');
|
||||||
await proxy?.updateConfigByKey("sys.oss.previewListResource", preview);
|
await proxy?.updateConfigByKey('sys.oss.previewListResource', preview);
|
||||||
await getList()
|
await getList();
|
||||||
proxy?.$modal.msgSuccess(text + "成功");
|
proxy?.$modal.msgSuccess(text + '成功');
|
||||||
} catch { return }
|
} catch {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row?: OssVO) => {
|
const handleDelete = async (row?: OssVO) => {
|
||||||
const ossIds = row?.ossId || ids.value;
|
const ossIds = row?.ossId || ids.value;
|
||||||
await proxy?.$modal.confirm('是否确认删除OSS对象存储编号为"' + ossIds + '"的数据项?');
|
await proxy?.$modal.confirm('是否确认删除OSS对象存储编号为"' + ossIds + '"的数据项?');
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
await delOss(ossIds).finally(() => loading.value = false);
|
await delOss(ossIds).finally(() => (loading.value = false));
|
||||||
await getList();
|
await getList();
|
||||||
proxy?.$modal.msgSuccess("删除成功");
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
}
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
<div class="mb-[10px]" v-show="showSearch">
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="70">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="70">
|
||||||
<el-form-item label="岗位编码" prop="postCode">
|
<el-form-item label="岗位编码" prop="postCode">
|
||||||
<el-input v-model="queryParams.postCode" placeholder="请输入岗位编码" clearable style="width: 200px" @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.postCode" placeholder="请输入岗位编码" clearable style="width: 200px" @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -27,26 +27,26 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:post:add']">新增</el-button>
|
<el-button v-hasPermi="['system:post:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:post:edit']">修改</el-button>
|
<el-button v-hasPermi="['system:post:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">修改</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:post:remove']">
|
<el-button v-hasPermi="['system:post:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:post:export']">导出</el-button>
|
<el-button v-hasPermi="['system:post:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="postList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" :data="postList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="岗位编号" align="center" prop="postId" v-if="false" />
|
<el-table-column v-if="false" label="岗位编号" align="center" prop="postId" />
|
||||||
<el-table-column label="岗位编码" align="center" prop="postCode" />
|
<el-table-column label="岗位编码" align="center" prop="postCode" />
|
||||||
<el-table-column label="岗位名称" align="center" prop="postName" />
|
<el-table-column label="岗位名称" align="center" prop="postName" />
|
||||||
<el-table-column label="岗位排序" align="center" prop="postSort" />
|
<el-table-column label="岗位排序" align="center" prop="postSort" />
|
||||||
@ -63,20 +63,20 @@
|
|||||||
<el-table-column label="操作" width="180" align="center" class-name="small-padding fixed-width">
|
<el-table-column label="操作" width="180" align="center" class-name="small-padding fixed-width">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="修改" placement="top">
|
<el-tooltip content="修改" placement="top">
|
||||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:post:edit']"></el-button>
|
<el-button v-hasPermi="['system:post:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="删除" placement="top">
|
<el-tooltip content="删除" placement="top">
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:post:remove']"></el-button>
|
<el-button v-hasPermi="['system:post:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<!-- 添加或修改岗位对话框 -->
|
<!-- 添加或修改岗位对话框 -->
|
||||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
<el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
|
||||||
<el-form ref="postFormRef" :model="form" :rules="rules" label-width="80px">
|
<el-form ref="postFormRef" :model="form" :rules="rules" label-width="80px">
|
||||||
<el-form-item label="岗位名称" prop="postName">
|
<el-form-item label="岗位名称" prop="postName">
|
||||||
<el-input v-model="form.postName" placeholder="请输入岗位名称" />
|
<el-input v-model="form.postName" placeholder="请输入岗位名称" />
|
||||||
@ -107,11 +107,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="Post" lang="ts">
|
<script setup name="Post" lang="ts">
|
||||||
import { listPost, addPost, delPost, getPost, updatePost } from "@/api/system/post";
|
import { listPost, addPost, delPost, getPost, updatePost } from '@/api/system/post';
|
||||||
import { PostForm, PostQuery, PostVO } from "@/api/system/post/types";
|
import { PostForm, PostQuery, PostVO } from '@/api/system/post/types';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable"));
|
const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
|
||||||
|
|
||||||
const postList = ref<PostVO[]>([]);
|
const postList = ref<PostVO[]>([]);
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
@ -134,9 +134,9 @@ const initFormData: PostForm = {
|
|||||||
postCode: '',
|
postCode: '',
|
||||||
postName: '',
|
postName: '',
|
||||||
postSort: 0,
|
postSort: 0,
|
||||||
status: "0",
|
status: '0',
|
||||||
remark: ''
|
remark: ''
|
||||||
}
|
};
|
||||||
|
|
||||||
const data = reactive<PageData<PostForm, PostQuery>>({
|
const data = reactive<PageData<PostForm, PostQuery>>({
|
||||||
form: { ...initFormData },
|
form: { ...initFormData },
|
||||||
@ -148,9 +148,9 @@ const data = reactive<PageData<PostForm, PostQuery>>({
|
|||||||
status: ''
|
status: ''
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
postName: [{ required: true, message: "岗位名称不能为空", trigger: "blur" }],
|
postName: [{ required: true, message: '岗位名称不能为空', trigger: 'blur' }],
|
||||||
postCode: [{ required: true, message: "岗位编码不能为空", trigger: "blur" }],
|
postCode: [{ required: true, message: '岗位编码不能为空', trigger: 'blur' }],
|
||||||
postSort: [{ required: true, message: "岗位顺序不能为空", trigger: "blur" }],
|
postSort: [{ required: true, message: '岗位顺序不能为空', trigger: 'blur' }]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -163,39 +163,39 @@ const getList = async () => {
|
|||||||
postList.value = res.rows;
|
postList.value = res.rows;
|
||||||
total.value = res.total;
|
total.value = res.total;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
};
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
reset();
|
reset();
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
}
|
};
|
||||||
/** 表单重置 */
|
/** 表单重置 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
form.value = { ...initFormData };
|
form.value = { ...initFormData };
|
||||||
postFormRef.value?.resetFields();
|
postFormRef.value?.resetFields();
|
||||||
}
|
};
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
handleQuery();
|
handleQuery();
|
||||||
}
|
};
|
||||||
/** 多选框选中数据 */
|
/** 多选框选中数据 */
|
||||||
const handleSelectionChange = (selection: PostVO[]) => {
|
const handleSelectionChange = (selection: PostVO[]) => {
|
||||||
ids.value = selection.map(item => item.postId);
|
ids.value = selection.map((item) => item.postId);
|
||||||
single.value = selection.length != 1;
|
single.value = selection.length != 1;
|
||||||
multiple.value = !selection.length;
|
multiple.value = !selection.length;
|
||||||
}
|
};
|
||||||
/** 新增按钮操作 */
|
/** 新增按钮操作 */
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
reset();
|
reset();
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "添加岗位";
|
dialog.title = '添加岗位';
|
||||||
}
|
};
|
||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
const handleUpdate = async (row?: PostVO) => {
|
const handleUpdate = async (row?: PostVO) => {
|
||||||
reset();
|
reset();
|
||||||
@ -203,33 +203,37 @@ const handleUpdate = async (row?: PostVO) => {
|
|||||||
const res = await getPost(postId);
|
const res = await getPost(postId);
|
||||||
Object.assign(form.value, res.data);
|
Object.assign(form.value, res.data);
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "修改岗位";
|
dialog.title = '修改岗位';
|
||||||
}
|
};
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
postFormRef.value?.validate(async (valid: boolean) => {
|
postFormRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
form.value.postId ? await updatePost(form.value) : await addPost(form.value);
|
form.value.postId ? await updatePost(form.value) : await addPost(form.value);
|
||||||
proxy?.$modal.msgSuccess("操作成功");
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
await getList();
|
await getList();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row?: PostVO) => {
|
const handleDelete = async (row?: PostVO) => {
|
||||||
const postIds = row?.postId || ids.value;
|
const postIds = row?.postId || ids.value;
|
||||||
await proxy?.$modal.confirm('是否确认删除岗位编号为"' + postIds + '"的数据项?');
|
await proxy?.$modal.confirm('是否确认删除岗位编号为"' + postIds + '"的数据项?');
|
||||||
await delPost(postIds);
|
await delPost(postIds);
|
||||||
await getList();
|
await getList();
|
||||||
proxy?.$modal.msgSuccess("删除成功");
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
}
|
};
|
||||||
/** 导出按钮操作 */
|
/** 导出按钮操作 */
|
||||||
const handleExport = () => {
|
const handleExport = () => {
|
||||||
proxy?.download("system/post/export", {
|
proxy?.download(
|
||||||
...queryParams.value
|
'system/post/export',
|
||||||
}, `post_${new Date().getTime()}.xlsx`);
|
{
|
||||||
}
|
...queryParams.value
|
||||||
|
},
|
||||||
|
`post_${new Date().getTime()}.xlsx`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
<div class="search" v-show="showSearch">
|
<div v-show="showSearch" class="search">
|
||||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||||
<el-form-item label="用户名称" prop="userName">
|
<el-form-item label="用户名称" prop="userName">
|
||||||
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -20,17 +20,17 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10">
|
<el-row :gutter="10">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="openSelectUser" v-hasPermi="['system:role:add']">添加用户</el-button>
|
<el-button v-hasPermi="['system:role:add']" type="primary" plain icon="Plus" @click="openSelectUser">添加用户</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="danger" plain icon="CircleClose" :disabled="multiple" @click="cancelAuthUserAll" v-hasPermi="['system:role:remove']">
|
<el-button v-hasPermi="['system:role:remove']" type="danger" plain icon="CircleClose" :disabled="multiple" @click="cancelAuthUserAll">
|
||||||
批量取消授权
|
批量取消授权
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="warning" plain icon="Close" @click="handleClose">关闭</el-button>
|
<el-button type="warning" plain icon="Close" @click="handleClose">关闭</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :search="true"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" :search="true" @query-table="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
|
||||||
@ -52,28 +52,27 @@
|
|||||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="取消授权" placement="top">
|
<el-tooltip content="取消授权" placement="top">
|
||||||
<el-button link type="primary" icon="CircleClose" @click="cancelAuthUser(scope.row)" v-hasPermi="['system:role:remove']"> </el-button>
|
<el-button v-hasPermi="['system:role:remove']" link type="primary" icon="CircleClose" @click="cancelAuthUser(scope.row)"> </el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
|
||||||
<select-user ref="selectRef" :roleId="queryParams.roleId" @ok="handleQuery" />
|
<select-user ref="selectRef" :role-id="queryParams.roleId" @ok="handleQuery" />
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="AuthUser" lang="ts">
|
<script setup name="AuthUser" lang="ts">
|
||||||
import { allocatedUserList, authUserCancel, authUserCancelAll } from "@/api/system/role";
|
import { allocatedUserList, authUserCancel, authUserCancelAll } from '@/api/system/role';
|
||||||
import { UserQuery } from "@/api/system/user/types";
|
import { UserQuery } from '@/api/system/user/types';
|
||||||
import { UserVO } from "@/api/system/user/types";
|
import { UserVO } from '@/api/system/user/types';
|
||||||
import SelectUser from "./selectUser.vue";
|
import SelectUser from './selectUser.vue';
|
||||||
|
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable"));
|
const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
|
||||||
|
|
||||||
const userList = ref<UserVO[]>([]);
|
const userList = ref<UserVO[]>([]);
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
@ -90,7 +89,7 @@ const queryParams = reactive<UserQuery>({
|
|||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
roleId: route.params.roleId as string,
|
roleId: route.params.roleId as string,
|
||||||
userName: undefined,
|
userName: undefined,
|
||||||
phonenumber: undefined,
|
phonenumber: undefined
|
||||||
});
|
});
|
||||||
|
|
||||||
/** 查询授权用户列表 */
|
/** 查询授权用户列表 */
|
||||||
@ -100,47 +99,47 @@ const getList = async () => {
|
|||||||
userList.value = res.rows;
|
userList.value = res.rows;
|
||||||
total.value = res.total;
|
total.value = res.total;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
};
|
||||||
// 返回按钮
|
// 返回按钮
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
const obj = { path: "/system/role" };
|
const obj = { path: '/system/role' };
|
||||||
proxy?.$tab.closeOpenPage(obj);
|
proxy?.$tab.closeOpenPage(obj);
|
||||||
}
|
};
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.pageNum = 1;
|
queryParams.pageNum = 1;
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
handleQuery();
|
handleQuery();
|
||||||
}
|
};
|
||||||
// 多选框选中数据
|
// 多选框选中数据
|
||||||
const handleSelectionChange = (selection: UserVO[]) => {
|
const handleSelectionChange = (selection: UserVO[]) => {
|
||||||
userIds.value = selection.map(item => item.userId);
|
userIds.value = selection.map((item) => item.userId);
|
||||||
multiple.value = !selection.length;
|
multiple.value = !selection.length;
|
||||||
}
|
};
|
||||||
/** 打开授权用户表弹窗 */
|
/** 打开授权用户表弹窗 */
|
||||||
const openSelectUser = () => {
|
const openSelectUser = () => {
|
||||||
selectRef.value?.show();
|
selectRef.value?.show();
|
||||||
}
|
};
|
||||||
/** 取消授权按钮操作 */
|
/** 取消授权按钮操作 */
|
||||||
const cancelAuthUser = async (row: UserVO) => {
|
const cancelAuthUser = async (row: UserVO) => {
|
||||||
await proxy?.$modal.confirm('确认要取消该用户"' + row.userName + '"角色吗?');
|
await proxy?.$modal.confirm('确认要取消该用户"' + row.userName + '"角色吗?');
|
||||||
await authUserCancel({ userId: row.userId, roleId: queryParams.roleId });
|
await authUserCancel({ userId: row.userId, roleId: queryParams.roleId });
|
||||||
await getList();
|
await getList();
|
||||||
proxy?.$modal.msgSuccess("取消授权成功");
|
proxy?.$modal.msgSuccess('取消授权成功');
|
||||||
}
|
};
|
||||||
/** 批量取消授权按钮操作 */
|
/** 批量取消授权按钮操作 */
|
||||||
const cancelAuthUserAll = async () => {
|
const cancelAuthUserAll = async () => {
|
||||||
const roleId = queryParams.roleId;
|
const roleId = queryParams.roleId;
|
||||||
const uIds = userIds.value.join(",");
|
const uIds = userIds.value.join(',');
|
||||||
await proxy?.$modal.confirm("是否取消选中用户授权数据项?");
|
await proxy?.$modal.confirm('是否取消选中用户授权数据项?');
|
||||||
await authUserCancelAll({ roleId: roleId, userIds: uIds });
|
await authUserCancelAll({ roleId: roleId, userIds: uIds });
|
||||||
await getList();
|
await getList();
|
||||||
proxy?.$modal.msgSuccess("取消授权成功");
|
proxy?.$modal.msgSuccess('取消授权成功');
|
||||||
}
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
<div class="mb-[10px]" v-show="showSearch">
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
|
||||||
<el-form-item label="角色名称" prop="roleName">
|
<el-form-item label="角色名称" prop="roleName">
|
||||||
@ -28,8 +28,8 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="handleQuery" icon="Search">搜索</el-button>
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||||
<el-button @click="resetQuery" icon="Refresh">重置</el-button>
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
@ -40,24 +40,24 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10">
|
<el-row :gutter="10">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain @click="handleAdd()" icon="Plus" v-hasPermi="['system:role:add']">新增</el-button>
|
<el-button v-hasPermi="['system:role:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="success" plain @click="handleUpdate()" :disabled="single" icon="Edit" v-hasPermi="['system:role:edit']">修改</el-button>
|
<el-button v-hasPermi="['system:role:edit']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">修改</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="danger" plain :disabled="ids.length === 0" @click="handleDelete()" v-hasPermi="['system:role:delete']">删除</el-button>
|
<el-button v-hasPermi="['system:role:delete']" type="danger" plain :disabled="ids.length === 0" @click="handleDelete()">删除</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:role:export']">导出</el-button>
|
<el-button v-hasPermi="['system:role:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table ref="roleTableRef" v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
|
<el-table ref="roleTableRef" v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="角色编号" prop="roleId" width="120" v-if="false" />
|
<el-table-column v-if="false" label="角色编号" prop="roleId" width="120" />
|
||||||
<el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
|
<el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
|
||||||
<el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="200" />
|
<el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="200" />
|
||||||
<el-table-column label="显示顺序" prop="roleSort" width="100" />
|
<el-table-column label="显示顺序" prop="roleSort" width="100" />
|
||||||
@ -74,17 +74,17 @@
|
|||||||
|
|
||||||
<el-table-column fixed="right" label="操作" width="180">
|
<el-table-column fixed="right" label="操作" width="180">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="修改" placement="top" v-if="scope.row.roleId !== 1">
|
<el-tooltip v-if="scope.row.roleId !== 1" content="修改" placement="top">
|
||||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:role:edit']"></el-button>
|
<el-button v-hasPermi="['system:role:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="删除" placement="top" v-if="scope.row.roleId !== 1">
|
<el-tooltip v-if="scope.row.roleId !== 1" content="删除" placement="top">
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:role:remove']"></el-button>
|
<el-button v-hasPermi="['system:role:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="数据权限" placement="top" v-if="scope.row.roleId !== 1">
|
<el-tooltip v-if="scope.row.roleId !== 1" content="数据权限" placement="top">
|
||||||
<el-button link type="primary" icon="CircleCheck" @click="handleDataScope(scope.row)" v-hasPermi="['system:role:edit']"></el-button>
|
<el-button v-hasPermi="['system:role:edit']" link type="primary" icon="CircleCheck" @click="handleDataScope(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="分配用户" placement="top" v-if="scope.row.roleId !== 1">
|
<el-tooltip v-if="scope.row.roleId !== 1" content="分配用户" placement="top">
|
||||||
<el-button link type="primary" icon="User" @click="handleAuthUser(scope.row)" v-hasPermi="['system:role:edit']"></el-button>
|
<el-button v-hasPermi="['system:role:edit']" link type="primary" icon="User" @click="handleAuthUser(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@ -99,7 +99,7 @@
|
|||||||
/>
|
/>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
<el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
|
||||||
<el-form ref="roleFormRef" :model="form" :rules="rules" label-width="100px">
|
<el-form ref="roleFormRef" :model="form" :rules="rules" label-width="100px">
|
||||||
<el-form-item label="角色名称" prop="roleName">
|
<el-form-item label="角色名称" prop="roleName">
|
||||||
<el-input v-model="form.roleName" placeholder="请输入角色名称" />
|
<el-input v-model="form.roleName" placeholder="请输入角色名称" />
|
||||||
@ -120,9 +120,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="状态">
|
<el-form-item label="状态">
|
||||||
<el-radio-group v-model="form.status">
|
<el-radio-group v-model="form.status">
|
||||||
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{
|
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
|
||||||
dict.label
|
|
||||||
}}</el-radio>
|
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="菜单权限">
|
<el-form-item label="菜单权限">
|
||||||
@ -130,10 +128,10 @@
|
|||||||
<el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
|
<el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
|
||||||
<el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
|
<el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
|
||||||
<el-tree
|
<el-tree
|
||||||
|
ref="menuRef"
|
||||||
class="tree-border"
|
class="tree-border"
|
||||||
:data="menuOptions"
|
:data="menuOptions"
|
||||||
show-checkbox
|
show-checkbox
|
||||||
ref="menuRef"
|
|
||||||
node-key="id"
|
node-key="id"
|
||||||
:check-strictly="!form.menuCheckStrictly"
|
:check-strictly="!form.menuCheckStrictly"
|
||||||
empty-text="加载中,请稍候"
|
empty-text="加载中,请稍候"
|
||||||
@ -153,8 +151,8 @@
|
|||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<!-- 分配角色数据权限对话框 -->
|
<!-- 分配角色数据权限对话框 -->
|
||||||
<el-dialog :title="dialog.title" v-model="openDataScope" width="500px" append-to-body>
|
<el-dialog v-model="openDataScope" :title="dialog.title" width="500px" append-to-body>
|
||||||
<el-form :model="form" label-width="80px" ref="dataScopeRef">
|
<el-form ref="dataScopeRef" :model="form" label-width="80px">
|
||||||
<el-form-item label="角色名称">
|
<el-form-item label="角色名称">
|
||||||
<el-input v-model="form.roleName" :disabled="true" />
|
<el-input v-model="form.roleName" :disabled="true" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -166,16 +164,16 @@
|
|||||||
<el-option v-for="item in dataScopeOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
|
<el-option v-for="item in dataScopeOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="数据权限" v-show="form.dataScope === '2'">
|
<el-form-item v-show="form.dataScope === '2'" label="数据权限">
|
||||||
<el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand($event, 'dept')">展开/折叠</el-checkbox>
|
<el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand($event, 'dept')">展开/折叠</el-checkbox>
|
||||||
<el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">全选/全不选</el-checkbox>
|
<el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">全选/全不选</el-checkbox>
|
||||||
<el-checkbox v-model="form.deptCheckStrictly" @change="handleCheckedTreeConnect($event, 'dept')">父子联动</el-checkbox>
|
<el-checkbox v-model="form.deptCheckStrictly" @change="handleCheckedTreeConnect($event, 'dept')">父子联动</el-checkbox>
|
||||||
<el-tree
|
<el-tree
|
||||||
|
ref="deptRef"
|
||||||
class="tree-border"
|
class="tree-border"
|
||||||
:data="deptOptions"
|
:data="deptOptions"
|
||||||
show-checkbox
|
show-checkbox
|
||||||
default-expand-all
|
default-expand-all
|
||||||
ref="deptRef"
|
|
||||||
node-key="id"
|
node-key="id"
|
||||||
:check-strictly="!form.deptCheckStrictly"
|
:check-strictly="!form.deptCheckStrictly"
|
||||||
empty-text="加载中,请稍候"
|
empty-text="加载中,请稍候"
|
||||||
@ -194,7 +192,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="Role" lang="ts">
|
<script setup name="Role" lang="ts">
|
||||||
import { addRole, changeRoleStatus, dataScope, delRole, getRole, listRole, updateRole, deptTreeSelect } from "@/api/system/role";
|
import { addRole, changeRoleStatus, dataScope, delRole, getRole, listRole, updateRole, deptTreeSelect } from '@/api/system/role';
|
||||||
import { roleMenuTreeselect, treeselect as menuTreeselect } from '@/api/system/menu/index';
|
import { roleMenuTreeselect, treeselect as menuTreeselect } from '@/api/system/menu/index';
|
||||||
import { RoleVO, RoleForm, RoleQuery, DeptTreeOption } from '@/api/system/role/types';
|
import { RoleVO, RoleForm, RoleQuery, DeptTreeOption } from '@/api/system/role/types';
|
||||||
import { MenuTreeOption, RoleMenuTree } from '@/api/system/menu/types';
|
import { MenuTreeOption, RoleMenuTree } from '@/api/system/menu/types';
|
||||||
@ -204,29 +202,29 @@ const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|||||||
const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
|
const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
|
||||||
|
|
||||||
const roleList = ref<RoleVO[]>();
|
const roleList = ref<RoleVO[]>();
|
||||||
const loading = ref(true)
|
const loading = ref(true);
|
||||||
const showSearch = ref(true)
|
const showSearch = ref(true);
|
||||||
const ids = ref<Array<string | number>>([])
|
const ids = ref<Array<string | number>>([]);
|
||||||
const single = ref(true)
|
const single = ref(true);
|
||||||
const multiple = ref(true)
|
const multiple = ref(true);
|
||||||
const total = ref(0)
|
const total = ref(0);
|
||||||
const dateRange = ref<[DateModelType, DateModelType]>(['', ''])
|
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
|
||||||
const menuOptions = ref<MenuTreeOption[]>([])
|
const menuOptions = ref<MenuTreeOption[]>([]);
|
||||||
const menuExpand = ref(false)
|
const menuExpand = ref(false);
|
||||||
const menuNodeAll = ref(false)
|
const menuNodeAll = ref(false);
|
||||||
const deptExpand = ref(true)
|
const deptExpand = ref(true);
|
||||||
const deptNodeAll = ref(false)
|
const deptNodeAll = ref(false);
|
||||||
const deptOptions = ref<DeptTreeOption[]>([])
|
const deptOptions = ref<DeptTreeOption[]>([]);
|
||||||
const openDataScope = ref(false)
|
const openDataScope = ref(false);
|
||||||
|
|
||||||
/** 数据范围选项*/
|
/** 数据范围选项*/
|
||||||
const dataScopeOptions = ref([
|
const dataScopeOptions = ref([
|
||||||
{ value: "1", label: "全部数据权限" },
|
{ value: '1', label: '全部数据权限' },
|
||||||
{ value: "2", label: "自定数据权限" },
|
{ value: '2', label: '自定数据权限' },
|
||||||
{ value: "3", label: "本部门数据权限" },
|
{ value: '3', label: '本部门数据权限' },
|
||||||
{ value: "4", label: "本部门及以下数据权限" },
|
{ value: '4', label: '本部门及以下数据权限' },
|
||||||
{ value: "5", label: "仅本人数据权限" }
|
{ value: '5', label: '仅本人数据权限' }
|
||||||
])
|
]);
|
||||||
|
|
||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
const roleFormRef = ref<ElFormInstance>();
|
const roleFormRef = ref<ElFormInstance>();
|
||||||
@ -245,8 +243,8 @@ const initForm: RoleForm = {
|
|||||||
remark: '',
|
remark: '',
|
||||||
dataScope: '1',
|
dataScope: '1',
|
||||||
menuIds: [],
|
menuIds: [],
|
||||||
deptIds: [],
|
deptIds: []
|
||||||
}
|
};
|
||||||
|
|
||||||
const data = reactive<PageData<RoleForm, RoleQuery>>({
|
const data = reactive<PageData<RoleForm, RoleQuery>>({
|
||||||
form: { ...initForm },
|
form: { ...initForm },
|
||||||
@ -255,15 +253,15 @@ const data = reactive<PageData<RoleForm, RoleQuery>>({
|
|||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
roleName: '',
|
roleName: '',
|
||||||
roleKey: '',
|
roleKey: '',
|
||||||
status: '',
|
status: ''
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
roleName: [{ required: true, message: "角色名称不能为空", trigger: "blur" }],
|
roleName: [{ required: true, message: '角色名称不能为空', trigger: 'blur' }],
|
||||||
roleKey: [{ required: true, message: "权限字符不能为空", trigger: "blur" }],
|
roleKey: [{ required: true, message: '权限字符不能为空', trigger: 'blur' }],
|
||||||
roleSort: [{ required: true, message: "角色顺序不能为空", trigger: "blur" }]
|
roleSort: [{ required: true, message: '角色顺序不能为空', trigger: 'blur' }]
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
const { form, queryParams, rules } = toRefs(data)
|
const { form, queryParams, rules } = toRefs(data);
|
||||||
|
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = reactive<DialogOption>({
|
||||||
visible: false,
|
visible: false,
|
||||||
@ -274,13 +272,13 @@ const dialog = reactive<DialogOption>({
|
|||||||
* 查询角色列表
|
* 查询角色列表
|
||||||
*/
|
*/
|
||||||
const getList = () => {
|
const getList = () => {
|
||||||
loading.value = true
|
loading.value = true;
|
||||||
listRole(proxy?.addDateRange(queryParams.value, dateRange.value)).then(res => {
|
listRole(proxy?.addDateRange(queryParams.value, dateRange.value)).then((res) => {
|
||||||
roleList.value = res.rows
|
roleList.value = res.rows;
|
||||||
total.value = res.total
|
total.value = res.total;
|
||||||
loading.value = false
|
loading.value = false;
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 搜索按钮操作
|
* 搜索按钮操作
|
||||||
@ -288,14 +286,14 @@ const getList = () => {
|
|||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 重置 */
|
/** 重置 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
dateRange.value = ['', '']
|
dateRange.value = ['', ''];
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
handleQuery();
|
handleQuery();
|
||||||
}
|
};
|
||||||
/**删除按钮操作 */
|
/**删除按钮操作 */
|
||||||
const handleDelete = async (row?: RoleVO) => {
|
const handleDelete = async (row?: RoleVO) => {
|
||||||
const roleids = row?.roleId || ids.value;
|
const roleids = row?.roleId || ids.value;
|
||||||
@ -303,43 +301,47 @@ const handleDelete = async (row?: RoleVO) => {
|
|||||||
await delRole(roleids);
|
await delRole(roleids);
|
||||||
getList();
|
getList();
|
||||||
proxy?.$modal.msgSuccess('删除成功');
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 导出按钮操作 */
|
/** 导出按钮操作 */
|
||||||
const handleExport = () => {
|
const handleExport = () => {
|
||||||
proxy?.download("system/role/export", {
|
proxy?.download(
|
||||||
...queryParams.value,
|
'system/role/export',
|
||||||
}, `role_${new Date().getTime()}.xlsx`)
|
{
|
||||||
}
|
...queryParams.value
|
||||||
|
},
|
||||||
|
`role_${new Date().getTime()}.xlsx`
|
||||||
|
);
|
||||||
|
};
|
||||||
/** 多选框选中数据 */
|
/** 多选框选中数据 */
|
||||||
const handleSelectionChange = (selection: RoleVO[]) => {
|
const handleSelectionChange = (selection: RoleVO[]) => {
|
||||||
ids.value = selection.map((item: RoleVO) => item.roleId);
|
ids.value = selection.map((item: RoleVO) => item.roleId);
|
||||||
single.value = selection.length != 1;
|
single.value = selection.length != 1;
|
||||||
multiple.value = !selection.length;
|
multiple.value = !selection.length;
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 角色状态修改 */
|
/** 角色状态修改 */
|
||||||
const handleStatusChange = async (row: RoleVO) => {
|
const handleStatusChange = async (row: RoleVO) => {
|
||||||
let text = row.status === "0" ? "启用" : "停用";
|
let text = row.status === '0' ? '启用' : '停用';
|
||||||
try {
|
try {
|
||||||
await proxy?.$modal.confirm('确认要"' + text + '""' + row.roleName + '"角色吗?');
|
await proxy?.$modal.confirm('确认要"' + text + '""' + row.roleName + '"角色吗?');
|
||||||
await changeRoleStatus(row.roleId, row.status);
|
await changeRoleStatus(row.roleId, row.status);
|
||||||
proxy?.$modal.msgSuccess(text + "成功");
|
proxy?.$modal.msgSuccess(text + '成功');
|
||||||
} catch {
|
} catch {
|
||||||
row.status = row.status === "0" ? "1" : "0";
|
row.status = row.status === '0' ? '1' : '0';
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 分配用户 */
|
/** 分配用户 */
|
||||||
const handleAuthUser = (row: RoleVO) => {
|
const handleAuthUser = (row: RoleVO) => {
|
||||||
router.push("/system/role-auth/user/" + row.roleId);
|
router.push('/system/role-auth/user/' + row.roleId);
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 查询菜单树结构 */
|
/** 查询菜单树结构 */
|
||||||
const getMenuTreeselect = async () => {
|
const getMenuTreeselect = async () => {
|
||||||
const res = await menuTreeselect();
|
const res = await menuTreeselect();
|
||||||
menuOptions.value = res.data;
|
menuOptions.value = res.data;
|
||||||
}
|
};
|
||||||
/** 所有部门节点数据 */
|
/** 所有部门节点数据 */
|
||||||
const getDeptAllCheckedKeys = (): any => {
|
const getDeptAllCheckedKeys = (): any => {
|
||||||
// 目前被选中的部门节点
|
// 目前被选中的部门节点
|
||||||
@ -349,67 +351,65 @@ const getDeptAllCheckedKeys = (): any => {
|
|||||||
if (halfCheckedKeys) {
|
if (halfCheckedKeys) {
|
||||||
checkedKeys?.unshift.apply(checkedKeys, halfCheckedKeys);
|
checkedKeys?.unshift.apply(checkedKeys, halfCheckedKeys);
|
||||||
}
|
}
|
||||||
return checkedKeys
|
return checkedKeys;
|
||||||
}
|
};
|
||||||
/** 重置新增的表单以及其他数据 */
|
/** 重置新增的表单以及其他数据 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
menuRef.value?.setCheckedKeys([]);
|
menuRef.value?.setCheckedKeys([]);
|
||||||
menuExpand.value = false
|
menuExpand.value = false;
|
||||||
menuNodeAll.value = false
|
menuNodeAll.value = false;
|
||||||
deptExpand.value = true
|
deptExpand.value = true;
|
||||||
deptNodeAll.value = false
|
deptNodeAll.value = false;
|
||||||
form.value = { ...initForm };
|
form.value = { ...initForm };
|
||||||
roleFormRef.value?.resetFields();
|
roleFormRef.value?.resetFields();
|
||||||
|
};
|
||||||
}
|
|
||||||
|
|
||||||
/** 添加角色 */
|
/** 添加角色 */
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
reset();
|
reset();
|
||||||
getMenuTreeselect();
|
getMenuTreeselect();
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "添加角色";
|
dialog.title = '添加角色';
|
||||||
}
|
};
|
||||||
/** 修改角色 */
|
/** 修改角色 */
|
||||||
const handleUpdate = async (row?: RoleVO) => {
|
const handleUpdate = async (row?: RoleVO) => {
|
||||||
reset();
|
reset();
|
||||||
const roleId = row?.roleId || ids.value[0]
|
const roleId = row?.roleId || ids.value[0];
|
||||||
const { data } = await getRole(roleId);
|
const { data } = await getRole(roleId);
|
||||||
Object.assign(form.value, data);
|
Object.assign(form.value, data);
|
||||||
form.value.roleSort = Number(form.value.roleSort);
|
form.value.roleSort = Number(form.value.roleSort);
|
||||||
const res = await getRoleMenuTreeselect(roleId);
|
const res = await getRoleMenuTreeselect(roleId);
|
||||||
dialog.title = "修改角色";
|
dialog.title = '修改角色';
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
res.checkedKeys.forEach((v) => {
|
res.checkedKeys.forEach((v) => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
menuRef.value?.setChecked(v, true, false);
|
menuRef.value?.setChecked(v, true, false);
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
};
|
||||||
}
|
|
||||||
/** 根据角色ID查询菜单树结构 */
|
/** 根据角色ID查询菜单树结构 */
|
||||||
const getRoleMenuTreeselect = (roleId: string | number) => {
|
const getRoleMenuTreeselect = (roleId: string | number) => {
|
||||||
return roleMenuTreeselect(roleId).then((res): RoleMenuTree => {
|
return roleMenuTreeselect(roleId).then((res): RoleMenuTree => {
|
||||||
menuOptions.value = res.data.menus;
|
menuOptions.value = res.data.menus;
|
||||||
return res.data;
|
return res.data;
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
/** 根据角色ID查询部门树结构 */
|
/** 根据角色ID查询部门树结构 */
|
||||||
const getRoleDeptTreeSelect = async (roleId: string | number) => {
|
const getRoleDeptTreeSelect = async (roleId: string | number) => {
|
||||||
const res = await deptTreeSelect(roleId);
|
const res = await deptTreeSelect(roleId);
|
||||||
deptOptions.value = res.data.depts;
|
deptOptions.value = res.data.depts;
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
};
|
||||||
/** 树权限(展开/折叠)*/
|
/** 树权限(展开/折叠)*/
|
||||||
const handleCheckedTreeExpand = (value: boolean, type: string) => {
|
const handleCheckedTreeExpand = (value: boolean, type: string) => {
|
||||||
if (type == "menu") {
|
if (type == 'menu') {
|
||||||
let treeList = menuOptions.value;
|
let treeList = menuOptions.value;
|
||||||
for (let i = 0; i < treeList.length; i++) {
|
for (let i = 0; i < treeList.length; i++) {
|
||||||
if (menuRef.value) {
|
if (menuRef.value) {
|
||||||
menuRef.value.store.nodesMap[treeList[i].id].expanded = value;
|
menuRef.value.store.nodesMap[treeList[i].id].expanded = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (type == "dept") {
|
} else if (type == 'dept') {
|
||||||
let treeList = deptOptions.value;
|
let treeList = deptOptions.value;
|
||||||
for (let i = 0; i < treeList.length; i++) {
|
for (let i = 0; i < treeList.length; i++) {
|
||||||
if (deptRef.value) {
|
if (deptRef.value) {
|
||||||
@ -417,23 +417,23 @@ const handleCheckedTreeExpand = (value: boolean, type: string) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
/** 树权限(全选/全不选) */
|
/** 树权限(全选/全不选) */
|
||||||
const handleCheckedTreeNodeAll = (value: any, type: string) => {
|
const handleCheckedTreeNodeAll = (value: any, type: string) => {
|
||||||
if (type == "menu") {
|
if (type == 'menu') {
|
||||||
menuRef.value?.setCheckedNodes(value ? menuOptions.value as any : []);
|
menuRef.value?.setCheckedNodes(value ? (menuOptions.value as any) : []);
|
||||||
} else if (type == "dept") {
|
} else if (type == 'dept') {
|
||||||
deptRef.value?.setCheckedNodes(value ? deptOptions.value as any : []);
|
deptRef.value?.setCheckedNodes(value ? (deptOptions.value as any) : []);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
/** 树权限(父子联动) */
|
/** 树权限(父子联动) */
|
||||||
const handleCheckedTreeConnect = (value: any, type: string) => {
|
const handleCheckedTreeConnect = (value: any, type: string) => {
|
||||||
if (type == "menu") {
|
if (type == 'menu') {
|
||||||
form.value.menuCheckStrictly = value;
|
form.value.menuCheckStrictly = value;
|
||||||
} else if (type == "dept") {
|
} else if (type == 'dept') {
|
||||||
form.value.deptCheckStrictly = value;
|
form.value.deptCheckStrictly = value;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
/** 所有菜单节点数据 */
|
/** 所有菜单节点数据 */
|
||||||
const getMenuAllCheckedKeys = (): any => {
|
const getMenuAllCheckedKeys = (): any => {
|
||||||
// 目前被选中的菜单节点
|
// 目前被选中的菜单节点
|
||||||
@ -444,57 +444,57 @@ const getMenuAllCheckedKeys = (): any => {
|
|||||||
checkedKeys?.unshift.apply(checkedKeys, halfCheckedKeys);
|
checkedKeys?.unshift.apply(checkedKeys, halfCheckedKeys);
|
||||||
}
|
}
|
||||||
return checkedKeys;
|
return checkedKeys;
|
||||||
}
|
};
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
roleFormRef.value?.validate(async (valid: boolean) => {
|
roleFormRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
form.value.menuIds = getMenuAllCheckedKeys()
|
form.value.menuIds = getMenuAllCheckedKeys();
|
||||||
form.value.roleId ? await updateRole(form.value) : await addRole(form.value);
|
form.value.roleId ? await updateRole(form.value) : await addRole(form.value);
|
||||||
proxy?.$modal.msgSuccess("操作成功")
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
dialog.visible = false
|
dialog.visible = false;
|
||||||
getList()
|
getList();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
reset()
|
reset();
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
}
|
};
|
||||||
/** 选择角色权限范围触发 */
|
/** 选择角色权限范围触发 */
|
||||||
const dataScopeSelectChange = (value: string) => {
|
const dataScopeSelectChange = (value: string) => {
|
||||||
if (value !== "2") {
|
if (value !== '2') {
|
||||||
deptRef.value?.setCheckedKeys([])
|
deptRef.value?.setCheckedKeys([]);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
/** 分配数据权限操作 */
|
/** 分配数据权限操作 */
|
||||||
const handleDataScope = async (row: RoleVO) => {
|
const handleDataScope = async (row: RoleVO) => {
|
||||||
const response = await getRole(row.roleId);
|
const response = await getRole(row.roleId);
|
||||||
Object.assign(form.value, response.data);
|
Object.assign(form.value, response.data);
|
||||||
const res = await getRoleDeptTreeSelect(row.roleId);
|
const res = await getRoleDeptTreeSelect(row.roleId);
|
||||||
openDataScope.value = true;
|
openDataScope.value = true;
|
||||||
dialog.title = "分配数据权限";
|
dialog.title = '分配数据权限';
|
||||||
await nextTick(() => {
|
await nextTick(() => {
|
||||||
deptRef.value?.setCheckedKeys(res.checkedKeys);
|
deptRef.value?.setCheckedKeys(res.checkedKeys);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
/** 提交按钮(数据权限) */
|
/** 提交按钮(数据权限) */
|
||||||
const submitDataScope = async () => {
|
const submitDataScope = async () => {
|
||||||
if (form.value.roleId) {
|
if (form.value.roleId) {
|
||||||
form.value.deptIds = getDeptAllCheckedKeys();
|
form.value.deptIds = getDeptAllCheckedKeys();
|
||||||
await dataScope(form.value);
|
await dataScope(form.value);
|
||||||
proxy?.$modal.msgSuccess("修改成功");
|
proxy?.$modal.msgSuccess('修改成功');
|
||||||
openDataScope.value = false;
|
openDataScope.value = false;
|
||||||
getList();
|
getList();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
/** 取消按钮(数据权限)*/
|
/** 取消按钮(数据权限)*/
|
||||||
const cancelDataScope = () => {
|
const cancelDataScope = () => {
|
||||||
dataScopeRef.value?.resetFields();
|
dataScopeRef.value?.resetFields();
|
||||||
form.value = { ...initForm };
|
form.value = { ...initForm };
|
||||||
openDataScope.value = false;
|
openDataScope.value = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-dialog title="选择用户" v-model="visible" width="800px" top="5vh" append-to-body>
|
<el-dialog v-model="visible" title="选择用户" width="800px" top="5vh" append-to-body>
|
||||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||||
<el-form-item label="用户名称" prop="userName">
|
<el-form-item label="用户名称" prop="userName">
|
||||||
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -14,7 +14,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-table @row-click="clickRow" ref="tableRef" :data="userList" @selection-change="handleSelectionChange" height="260px">
|
<el-table ref="tableRef" :data="userList" height="260px" @row-click="clickRow" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55"></el-table-column>
|
<el-table-column type="selection" width="55"></el-table-column>
|
||||||
<el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" />
|
<el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" />
|
||||||
<el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" />
|
<el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" />
|
||||||
@ -31,7 +31,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<pagination v-if="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
<pagination v-if="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
|
||||||
</el-row>
|
</el-row>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="dialog-footer">
|
<div class="dialog-footer">
|
||||||
@ -44,16 +44,15 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="SelectUser" lang="ts">
|
<script setup name="SelectUser" lang="ts">
|
||||||
import { authUserSelectAll, unallocatedUserList } from "@/api/system/role";
|
import { authUserSelectAll, unallocatedUserList } from '@/api/system/role';
|
||||||
import { UserVO } from '@/api/system/user/types';
|
import { UserVO } from '@/api/system/user/types';
|
||||||
import { UserQuery } from '@/api/system/user/types';
|
import { UserQuery } from '@/api/system/user/types';
|
||||||
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
roleId: {
|
roleId: {
|
||||||
type: [Number, String]
|
type: [Number, String]
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
|
const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
|
||||||
@ -69,7 +68,7 @@ const queryParams = reactive<UserQuery>({
|
|||||||
roleId: undefined,
|
roleId: undefined,
|
||||||
userName: undefined,
|
userName: undefined,
|
||||||
phonenumber: undefined
|
phonenumber: undefined
|
||||||
})
|
});
|
||||||
|
|
||||||
const tableRef = ref<ElTableInstance>();
|
const tableRef = ref<ElTableInstance>();
|
||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
@ -78,7 +77,7 @@ const show = () => {
|
|||||||
queryParams.roleId = props.roleId;
|
queryParams.roleId = props.roleId;
|
||||||
getList();
|
getList();
|
||||||
visible.value = true;
|
visible.value = true;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 选择行
|
* 选择行
|
||||||
@ -86,35 +85,35 @@ const show = () => {
|
|||||||
const clickRow = (row: any) => {
|
const clickRow = (row: any) => {
|
||||||
// ele的bug
|
// ele的bug
|
||||||
tableRef.value?.toggleRowSelection(row, false);
|
tableRef.value?.toggleRowSelection(row, false);
|
||||||
}
|
};
|
||||||
/** 多选框选中数据 */
|
/** 多选框选中数据 */
|
||||||
const handleSelectionChange = (selection: UserVO[]) => {
|
const handleSelectionChange = (selection: UserVO[]) => {
|
||||||
userIds.value = selection.map((item: UserVO) => item.userId);
|
userIds.value = selection.map((item: UserVO) => item.userId);
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 查询数据 */
|
/** 查询数据 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
const res = await unallocatedUserList(queryParams);
|
const res = await unallocatedUserList(queryParams);
|
||||||
userList.value = res.rows;
|
userList.value = res.rows;
|
||||||
total.value = res.total;
|
total.value = res.total;
|
||||||
}
|
};
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.pageNum = 1;
|
queryParams.pageNum = 1;
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
|
|
||||||
const emit = defineEmits(["ok"]);
|
const emit = defineEmits(['ok']);
|
||||||
/**选择授权用户操作 */
|
/**选择授权用户操作 */
|
||||||
const handleSelectUser = async () => {
|
const handleSelectUser = async () => {
|
||||||
const roleId = queryParams.roleId;
|
const roleId = queryParams.roleId;
|
||||||
const ids = userIds.value.join(',');
|
const ids = userIds.value.join(',');
|
||||||
if (ids == "") {
|
if (ids == '') {
|
||||||
proxy?.$modal.msgError('请选择要分配的用户');
|
proxy?.$modal.msgError('请选择要分配的用户');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -122,10 +121,10 @@ const handleSelectUser = async () => {
|
|||||||
proxy?.$modal.msgSuccess('分配成功');
|
proxy?.$modal.msgSuccess('分配成功');
|
||||||
emit('ok');
|
emit('ok');
|
||||||
visible.value = false;
|
visible.value = false;
|
||||||
}
|
};
|
||||||
// 暴露
|
// 暴露
|
||||||
defineExpose({
|
defineExpose({
|
||||||
show,
|
show
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
<div class="mb-[10px]" v-show="showSearch">
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
|
||||||
<el-form-item label="租户编号" prop="tenantId">
|
<el-form-item label="租户编号" prop="tenantId">
|
||||||
<el-input v-model="queryParams.tenantId" placeholder="请输入租户编号" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.tenantId" placeholder="请输入租户编号" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -29,28 +29,28 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:tenant:add']">新增</el-button>
|
<el-button v-hasPermi="['system:tenant:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:tenant:edit']"
|
<el-button v-hasPermi="['system:tenant:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()"
|
||||||
>修改</el-button
|
>修改</el-button
|
||||||
>
|
>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:tenant:remove']">
|
<el-button v-hasPermi="['system:tenant:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:tenant:export']">导出</el-button>
|
<el-button v-hasPermi="['system:tenant:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="tenantList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" :data="tenantList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="id" align="center" prop="id" v-if="false" />
|
<el-table-column v-if="false" label="id" align="center" prop="id" />
|
||||||
<el-table-column label="租户编号" align="center" prop="tenantId" />
|
<el-table-column label="租户编号" align="center" prop="tenantId" />
|
||||||
<el-table-column label="联系人" align="center" prop="contactUserName" />
|
<el-table-column label="联系人" align="center" prop="contactUserName" />
|
||||||
<el-table-column label="联系电话" align="center" prop="contactPhone" />
|
<el-table-column label="联系电话" align="center" prop="contactPhone" />
|
||||||
@ -69,23 +69,23 @@
|
|||||||
<el-table-column width="150" label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
|
<el-table-column width="150" label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="修改" placement="top">
|
<el-tooltip content="修改" placement="top">
|
||||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:tenant:edit']"></el-button>
|
<el-button v-hasPermi="['system:tenant:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="同步套餐" placement="top">
|
<el-tooltip content="同步套餐" placement="top">
|
||||||
<el-button link type="primary" icon="Refresh" @click="handleSyncTenantPackage(scope.row)" v-hasPermi="['system:tenant:edit']">
|
<el-button v-hasPermi="['system:tenant:edit']" link type="primary" icon="Refresh" @click="handleSyncTenantPackage(scope.row)">
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="删除" placement="top">
|
<el-tooltip content="删除" placement="top">
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:tenant:remove']"></el-button>
|
<el-button v-hasPermi="['system:tenant:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
|
||||||
</el-card>
|
</el-card>
|
||||||
<!-- 添加或修改租户对话框 -->
|
<!-- 添加或修改租户对话框 -->
|
||||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
<el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
|
||||||
<el-form ref="tenantFormRef" :model="form" :rules="rules" label-width="80px">
|
<el-form ref="tenantFormRef" :model="form" :rules="rules" label-width="80px">
|
||||||
<el-form-item label="企业名称" prop="companyName">
|
<el-form-item label="企业名称" prop="companyName">
|
||||||
<el-input v-model="form.companyName" placeholder="请输入企业名称" />
|
<el-input v-model="form.companyName" placeholder="请输入企业名称" />
|
||||||
@ -100,7 +100,7 @@
|
|||||||
<el-input v-model="form.username" placeholder="请输入系统用户名" maxlength="30" />
|
<el-input v-model="form.username" placeholder="请输入系统用户名" maxlength="30" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-if="!form.id" label="用户密码" prop="password">
|
<el-form-item v-if="!form.id" label="用户密码" prop="password">
|
||||||
<el-input type="password" v-model="form.password" placeholder="请输入系统用户密码" maxlength="20" />
|
<el-input v-model="form.password" type="password" placeholder="请输入系统用户密码" maxlength="20" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="租户套餐" prop="packageId">
|
<el-form-item label="租户套餐" prop="packageId">
|
||||||
<el-select v-model="form.packageId" :disabled="!!form.tenantId" placeholder="请选择租户套餐" clearable style="width: 100%">
|
<el-select v-model="form.packageId" :disabled="!!form.tenantId" placeholder="请选择租户套餐" clearable style="width: 100%">
|
||||||
@ -108,7 +108,7 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="过期时间" prop="expireTime">
|
<el-form-item label="过期时间" prop="expireTime">
|
||||||
<el-date-picker clearable v-model="form.expireTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择过期时间">
|
<el-date-picker v-model="form.expireTime" clearable type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择过期时间">
|
||||||
</el-date-picker>
|
</el-date-picker>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="用户数量" prop="accountCount">
|
<el-form-item label="用户数量" prop="accountCount">
|
||||||
@ -124,7 +124,7 @@
|
|||||||
<el-input v-model="form.licenseNumber" placeholder="请输入统一社会信用代码" />
|
<el-input v-model="form.licenseNumber" placeholder="请输入统一社会信用代码" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="企业简介" prop="intro">
|
<el-form-item label="企业简介" prop="intro">
|
||||||
<el-input type="textarea" v-model="form.intro" placeholder="请输入企业简介" />
|
<el-input v-model="form.intro" type="textarea" placeholder="请输入企业简介" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="备注" prop="remark">
|
<el-form-item label="备注" prop="remark">
|
||||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||||
@ -182,8 +182,8 @@ const initFormData: TenantForm = {
|
|||||||
packageId: '',
|
packageId: '',
|
||||||
expireTime: '',
|
expireTime: '',
|
||||||
accountCount: 0,
|
accountCount: 0,
|
||||||
status: '0',
|
status: '0'
|
||||||
}
|
};
|
||||||
const data = reactive<PageData<TenantForm, TenantQuery>>({
|
const data = reactive<PageData<TenantForm, TenantQuery>>({
|
||||||
form: { ...initFormData },
|
form: { ...initFormData },
|
||||||
queryParams: {
|
queryParams: {
|
||||||
@ -195,17 +195,17 @@ const data = reactive<PageData<TenantForm, TenantQuery>>({
|
|||||||
companyName: ''
|
companyName: ''
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
id: [{ required: true, message: "id不能为空", trigger: "blur" }],
|
id: [{ required: true, message: 'id不能为空', trigger: 'blur' }],
|
||||||
tenantId: [{ required: true, message: "租户编号不能为空", trigger: "blur" }],
|
tenantId: [{ required: true, message: '租户编号不能为空', trigger: 'blur' }],
|
||||||
contactUserName: [{ required: true, message: "联系人不能为空", trigger: "blur" }],
|
contactUserName: [{ required: true, message: '联系人不能为空', trigger: 'blur' }],
|
||||||
contactPhone: [{ required: true, message: "联系电话不能为空", trigger: "blur" }],
|
contactPhone: [{ required: true, message: '联系电话不能为空', trigger: 'blur' }],
|
||||||
companyName: [{ required: true, message: "企业名称不能为空", trigger: "blur" }],
|
companyName: [{ required: true, message: '企业名称不能为空', trigger: 'blur' }],
|
||||||
username: [
|
username: [
|
||||||
{ required: true, message: "用户名不能为空", trigger: "blur" },
|
{ required: true, message: '用户名不能为空', trigger: 'blur' },
|
||||||
{ min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur' }
|
{ min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur' }
|
||||||
],
|
],
|
||||||
password: [
|
password: [
|
||||||
{ required: true, message: "密码不能为空", trigger: "blur" },
|
{ required: true, message: '密码不能为空', trigger: 'blur' },
|
||||||
{ min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' }
|
{ min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -215,9 +215,9 @@ const { queryParams, form, rules } = toRefs(data);
|
|||||||
|
|
||||||
/** 查询所有租户套餐 */
|
/** 查询所有租户套餐 */
|
||||||
const getTenantPackage = async () => {
|
const getTenantPackage = async () => {
|
||||||
const res = await selectTenantPackage()
|
const res = await selectTenantPackage();
|
||||||
packageList.value = res.data;
|
packageList.value = res.data;
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 查询租户列表 */
|
/** 查询租户列表 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
@ -226,60 +226,58 @@ const getList = async () => {
|
|||||||
tenantList.value = res.rows;
|
tenantList.value = res.rows;
|
||||||
total.value = res.total;
|
total.value = res.total;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
// 租户套餐状态修改
|
// 租户套餐状态修改
|
||||||
const handleStatusChange = async (row: TenantVO) => {
|
const handleStatusChange = async (row: TenantVO) => {
|
||||||
let text = row.status === "0" ? "启用" : "停用";
|
let text = row.status === '0' ? '启用' : '停用';
|
||||||
try {
|
try {
|
||||||
await proxy?.$modal.confirm('确认要"' + text + '""' + row.companyName + '"租户吗?');
|
await proxy?.$modal.confirm('确认要"' + text + '""' + row.companyName + '"租户吗?');
|
||||||
await changeTenantStatus(row.id, row.tenantId, row.status);
|
await changeTenantStatus(row.id, row.tenantId, row.status);
|
||||||
proxy?.$modal.msgSuccess(text + "成功");
|
proxy?.$modal.msgSuccess(text + '成功');
|
||||||
} catch {
|
} catch {
|
||||||
row.status = row.status === "0" ? "1" : "0";
|
row.status = row.status === '0' ? '1' : '0';
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// 取消按钮
|
// 取消按钮
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
reset();
|
reset();
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
// 表单重置
|
// 表单重置
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
form.value = { ...initFormData };
|
form.value = { ...initFormData };
|
||||||
tenantFormRef.value?.resetFields();
|
tenantFormRef.value?.resetFields();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
handleQuery();
|
handleQuery();
|
||||||
}
|
};
|
||||||
|
|
||||||
// 多选框选中数据
|
// 多选框选中数据
|
||||||
const handleSelectionChange = (selection: TenantVO[]) => {
|
const handleSelectionChange = (selection: TenantVO[]) => {
|
||||||
ids.value = selection.map(item => item.id);
|
ids.value = selection.map((item) => item.id);
|
||||||
single.value = selection.length != 1;
|
single.value = selection.length != 1;
|
||||||
multiple.value = !selection.length;
|
multiple.value = !selection.length;
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 新增按钮操作 */
|
/** 新增按钮操作 */
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
reset();
|
reset();
|
||||||
getTenantPackage();
|
getTenantPackage();
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "添加租户";
|
dialog.title = '添加租户';
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
const handleUpdate = async (row?: TenantVO) => {
|
const handleUpdate = async (row?: TenantVO) => {
|
||||||
@ -287,10 +285,10 @@ const handleUpdate = async (row?: TenantVO) => {
|
|||||||
await getTenantPackage();
|
await getTenantPackage();
|
||||||
const _id = row?.id || ids.value[0];
|
const _id = row?.id || ids.value[0];
|
||||||
const res = await getTenant(_id);
|
const res = await getTenant(_id);
|
||||||
Object.assign(form.value, res.data)
|
Object.assign(form.value, res.data);
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "修改租户";
|
dialog.title = '修改租户';
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
@ -298,28 +296,26 @@ const submitForm = () => {
|
|||||||
if (valid) {
|
if (valid) {
|
||||||
buttonLoading.value = true;
|
buttonLoading.value = true;
|
||||||
if (form.value.id) {
|
if (form.value.id) {
|
||||||
await updateTenant(form.value).finally(() => buttonLoading.value = false);
|
await updateTenant(form.value).finally(() => (buttonLoading.value = false));
|
||||||
} else {
|
} else {
|
||||||
await addTenant(form.value).finally(() => buttonLoading.value = false);
|
await addTenant(form.value).finally(() => (buttonLoading.value = false));
|
||||||
}
|
}
|
||||||
proxy?.$modal.msgSuccess("操作成功");
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
await getList();
|
await getList();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row?: TenantVO) => {
|
const handleDelete = async (row?: TenantVO) => {
|
||||||
const _ids = row?.id || ids.value;
|
const _ids = row?.id || ids.value;
|
||||||
await proxy?.$modal.confirm('是否确认删除租户编号为"' + _ids + '"的数据项?')
|
await proxy?.$modal.confirm('是否确认删除租户编号为"' + _ids + '"的数据项?');
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
await delTenant(_ids).finally(() => loading.value = false);
|
await delTenant(_ids).finally(() => (loading.value = false));
|
||||||
await getList();
|
await getList();
|
||||||
proxy?.$modal.msgSuccess("删除成功");
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
|
};
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 同步租户套餐按钮操作 */
|
/** 同步租户套餐按钮操作 */
|
||||||
const handleSyncTenantPackage = async (row: TenantVO) => {
|
const handleSyncTenantPackage = async (row: TenantVO) => {
|
||||||
@ -328,20 +324,26 @@ const handleSyncTenantPackage = async (row: TenantVO) => {
|
|||||||
loading.value = true;
|
loading.value = true;
|
||||||
await syncTenantPackage(row.tenantId, row.packageId);
|
await syncTenantPackage(row.tenantId, row.packageId);
|
||||||
await getList();
|
await getList();
|
||||||
proxy?.$modal.msgSuccess("同步成功");
|
proxy?.$modal.msgSuccess('同步成功');
|
||||||
} catch { return } finally {
|
} catch {
|
||||||
|
return;
|
||||||
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 导出按钮操作 */
|
/** 导出按钮操作 */
|
||||||
const handleExport = () => {
|
const handleExport = () => {
|
||||||
proxy?.download('system/tenant/export', {
|
proxy?.download(
|
||||||
...queryParams.value
|
'system/tenant/export',
|
||||||
}, `tenant_${new Date().getTime()}.xlsx`)
|
{
|
||||||
}
|
...queryParams.value
|
||||||
|
},
|
||||||
|
`tenant_${new Date().getTime()}.xlsx`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
<div class="mb-[10px]" v-show="showSearch">
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
|
||||||
<el-form-item label="套餐名称" prop="packageName">
|
<el-form-item label="套餐名称" prop="packageName">
|
||||||
<el-input v-model="queryParams.packageName" placeholder="请输入套餐名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.packageName" placeholder="请输入套餐名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -20,28 +20,28 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:tenantPackage:add']"> 新增 </el-button>
|
<el-button v-hasPermi="['system:tenantPackage:add']" type="primary" plain icon="Plus" @click="handleAdd"> 新增 </el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:tenantPackage:edit']">
|
<el-button v-hasPermi="['system:tenantPackage:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">
|
||||||
修改
|
修改
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:tenantPackage:remove']">
|
<el-button v-hasPermi="['system:tenantPackage:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:tenantPackage:export']">导出 </el-button>
|
<el-button v-hasPermi="['system:tenantPackage:export']" type="warning" plain icon="Download" @click="handleExport">导出 </el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="tenantPackageList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" :data="tenantPackageList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="租户套餐id" align="center" prop="packageId" v-if="false" />
|
<el-table-column v-if="false" label="租户套餐id" align="center" prop="packageId" />
|
||||||
<el-table-column label="套餐名称" align="center" prop="packageName" />
|
<el-table-column label="套餐名称" align="center" prop="packageName" />
|
||||||
<el-table-column label="备注" align="center" prop="remark" />
|
<el-table-column label="备注" align="center" prop="remark" />
|
||||||
<el-table-column label="状态" align="center" prop="status">
|
<el-table-column label="状态" align="center" prop="status">
|
||||||
@ -52,20 +52,20 @@
|
|||||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="修改" placement="top">
|
<el-tooltip content="修改" placement="top">
|
||||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:tenantPackage:edit']"></el-button>
|
<el-button v-hasPermi="['system:tenantPackage:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="删除" placement="top">
|
<el-tooltip content="删除" placement="top">
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:tenantPackage:remove']"></el-button>
|
<el-button v-hasPermi="['system:tenantPackage:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<!-- 添加或修改租户套餐对话框 -->
|
<!-- 添加或修改租户套餐对话框 -->
|
||||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
<el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
|
||||||
<el-form ref="tenantPackageFormRef" :model="form" :rules="rules" label-width="80px">
|
<el-form ref="tenantPackageFormRef" :model="form" :rules="rules" label-width="80px">
|
||||||
<el-form-item label="套餐名称" prop="packageName">
|
<el-form-item label="套餐名称" prop="packageName">
|
||||||
<el-input v-model="form.packageName" placeholder="请输入套餐名称" />
|
<el-input v-model="form.packageName" placeholder="请输入套餐名称" />
|
||||||
@ -75,10 +75,10 @@
|
|||||||
<el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选 </el-checkbox>
|
<el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选 </el-checkbox>
|
||||||
<el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动 </el-checkbox>
|
<el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动 </el-checkbox>
|
||||||
<el-tree
|
<el-tree
|
||||||
|
ref="menuTreeRef"
|
||||||
class="tree-border"
|
class="tree-border"
|
||||||
:data="menuOptions"
|
:data="menuOptions"
|
||||||
show-checkbox
|
show-checkbox
|
||||||
ref="menuTreeRef"
|
|
||||||
node-key="id"
|
node-key="id"
|
||||||
:check-strictly="!form.menuCheckStrictly"
|
:check-strictly="!form.menuCheckStrictly"
|
||||||
empty-text="加载中,请稍候"
|
empty-text="加载中,请稍候"
|
||||||
@ -107,11 +107,11 @@ import {
|
|||||||
addTenantPackage,
|
addTenantPackage,
|
||||||
updateTenantPackage,
|
updateTenantPackage,
|
||||||
changePackageStatus
|
changePackageStatus
|
||||||
} from "@/api/system/tenantPackage";
|
} from '@/api/system/tenantPackage';
|
||||||
import { treeselect as menuTreeselect, tenantPackageMenuTreeselect } from "@/api/system/menu";
|
import { treeselect as menuTreeselect, tenantPackageMenuTreeselect } from '@/api/system/menu';
|
||||||
import { TenantPkgForm, TenantPkgQuery, TenantPkgVO } from "@/api/system/tenantPackage/types";
|
import { TenantPkgForm, TenantPkgQuery, TenantPkgVO } from '@/api/system/tenantPackage/types';
|
||||||
import { MenuTreeOption } from "@/api/system/menu/types";
|
import { MenuTreeOption } from '@/api/system/menu/types';
|
||||||
import to from "await-to-js";
|
import to from 'await-to-js';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
|
||||||
@ -133,15 +133,14 @@ const tenantPackageFormRef = ref<ElFormInstance>();
|
|||||||
|
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = reactive<DialogOption>({
|
||||||
visible: false,
|
visible: false,
|
||||||
title: ""
|
title: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const initFormData: TenantPkgForm = {
|
const initFormData: TenantPkgForm = {
|
||||||
packageId: undefined,
|
packageId: undefined,
|
||||||
packageName: "",
|
packageName: '',
|
||||||
menuIds: "",
|
menuIds: '',
|
||||||
remark: "",
|
remark: '',
|
||||||
menuCheckStrictly: true
|
menuCheckStrictly: true
|
||||||
};
|
};
|
||||||
const data = reactive<PageData<TenantPkgForm, TenantPkgQuery>>({
|
const data = reactive<PageData<TenantPkgForm, TenantPkgQuery>>({
|
||||||
@ -149,11 +148,11 @@ const data = reactive<PageData<TenantPkgForm, TenantPkgQuery>>({
|
|||||||
queryParams: {
|
queryParams: {
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
packageName: ""
|
packageName: ''
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
packageId: [{ required: true, message: "租户套餐id不能为空", trigger: "blur" }],
|
packageId: [{ required: true, message: '租户套餐id不能为空', trigger: 'blur' }],
|
||||||
packageName: [{ required: true, message: "套餐名称不能为空", trigger: "blur" }]
|
packageName: [{ required: true, message: '套餐名称不能为空', trigger: 'blur' }]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -195,13 +194,13 @@ const getList = async () => {
|
|||||||
|
|
||||||
// 租户套餐状态修改
|
// 租户套餐状态修改
|
||||||
const handleStatusChange = async (row: TenantPkgVO) => {
|
const handleStatusChange = async (row: TenantPkgVO) => {
|
||||||
let text = row.status === "0" ? "启用" : "停用";
|
let text = row.status === '0' ? '启用' : '停用';
|
||||||
const [err] = await to(proxy?.$modal.confirm("确认要\"" + text + "\"\"" + row.packageName + "\"套餐吗?") as Promise<any>);
|
const [err] = await to(proxy?.$modal.confirm('确认要"' + text + '""' + row.packageName + '"套餐吗?') as Promise<any>);
|
||||||
if (err) {
|
if (err) {
|
||||||
row.status = row.status === "0" ? "1" : "0";
|
row.status = row.status === '0' ? '1' : '0';
|
||||||
} else {
|
} else {
|
||||||
await changePackageStatus(row.packageId, row.status);
|
await changePackageStatus(row.packageId, row.status);
|
||||||
proxy?.$modal.msgSuccess(text + "成功");
|
proxy?.$modal.msgSuccess(text + '成功');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -234,14 +233,14 @@ const resetQuery = () => {
|
|||||||
|
|
||||||
// 多选框选中数据
|
// 多选框选中数据
|
||||||
const handleSelectionChange = (selection: TenantPkgVO[]) => {
|
const handleSelectionChange = (selection: TenantPkgVO[]) => {
|
||||||
ids.value = selection.map(item => item.packageId);
|
ids.value = selection.map((item) => item.packageId);
|
||||||
single.value = selection.length != 1;
|
single.value = selection.length != 1;
|
||||||
multiple.value = !selection.length;
|
multiple.value = !selection.length;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 树权限(展开/折叠)
|
// 树权限(展开/折叠)
|
||||||
const handleCheckedTreeExpand = (value: CheckboxValueType, type: string) => {
|
const handleCheckedTreeExpand = (value: CheckboxValueType, type: string) => {
|
||||||
if (type == "menu") {
|
if (type == 'menu') {
|
||||||
let treeList = menuOptions.value;
|
let treeList = menuOptions.value;
|
||||||
for (let i = 0; i < treeList.length; i++) {
|
for (let i = 0; i < treeList.length; i++) {
|
||||||
if (menuTreeRef.value) {
|
if (menuTreeRef.value) {
|
||||||
@ -253,14 +252,14 @@ const handleCheckedTreeExpand = (value: CheckboxValueType, type: string) => {
|
|||||||
|
|
||||||
// 树权限(全选/全不选)
|
// 树权限(全选/全不选)
|
||||||
const handleCheckedTreeNodeAll = (value: CheckboxValueType, type: string) => {
|
const handleCheckedTreeNodeAll = (value: CheckboxValueType, type: string) => {
|
||||||
if (type == "menu") {
|
if (type == 'menu') {
|
||||||
menuTreeRef.value?.setCheckedNodes(value ? menuOptions.value as any : []);
|
menuTreeRef.value?.setCheckedNodes(value ? (menuOptions.value as any) : []);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 树权限(父子联动)
|
// 树权限(父子联动)
|
||||||
const handleCheckedTreeConnect = (value: CheckboxValueType, type: string) => {
|
const handleCheckedTreeConnect = (value: CheckboxValueType, type: string) => {
|
||||||
if (type == "menu") {
|
if (type == 'menu') {
|
||||||
form.value.menuCheckStrictly = value as boolean;
|
form.value.menuCheckStrictly = value as boolean;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -270,7 +269,7 @@ const handleAdd = () => {
|
|||||||
reset();
|
reset();
|
||||||
getMenuTreeselect();
|
getMenuTreeselect();
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "添加租户套餐";
|
dialog.title = '添加租户套餐';
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
@ -281,7 +280,7 @@ const handleUpdate = async (row?: TenantPkgVO) => {
|
|||||||
form.value = response.data;
|
form.value = response.data;
|
||||||
const res = await getPackageMenuTreeselect(_packageId);
|
const res = await getPackageMenuTreeselect(_packageId);
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "修改租户套餐";
|
dialog.title = '修改租户套餐';
|
||||||
res.data.checkedKeys.forEach((v) => {
|
res.data.checkedKeys.forEach((v) => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
menuTreeRef.value?.setChecked(v, true, false);
|
menuTreeRef.value?.setChecked(v, true, false);
|
||||||
@ -296,11 +295,11 @@ const submitForm = () => {
|
|||||||
buttonLoading.value = true;
|
buttonLoading.value = true;
|
||||||
form.value.menuIds = getMenuAllCheckedKeys();
|
form.value.menuIds = getMenuAllCheckedKeys();
|
||||||
if (form.value.packageId != null) {
|
if (form.value.packageId != null) {
|
||||||
await updateTenantPackage(form.value).finally(() => buttonLoading.value = false);
|
await updateTenantPackage(form.value).finally(() => (buttonLoading.value = false));
|
||||||
} else {
|
} else {
|
||||||
await addTenantPackage(form.value).finally(() => buttonLoading.value = false);
|
await addTenantPackage(form.value).finally(() => (buttonLoading.value = false));
|
||||||
}
|
}
|
||||||
proxy?.$modal.msgSuccess("操作成功");
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
await getList();
|
await getList();
|
||||||
}
|
}
|
||||||
@ -310,20 +309,24 @@ const submitForm = () => {
|
|||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row?: TenantPkgVO) => {
|
const handleDelete = async (row?: TenantPkgVO) => {
|
||||||
const _packageIds = row?.packageId || ids.value;
|
const _packageIds = row?.packageId || ids.value;
|
||||||
await proxy?.$modal.confirm("是否确认删除租户套餐编号为\"" + _packageIds + "\"的数据项?").finally(() => {
|
await proxy?.$modal.confirm('是否确认删除租户套餐编号为"' + _packageIds + '"的数据项?').finally(() => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
});
|
});
|
||||||
await delTenantPackage(_packageIds);
|
await delTenantPackage(_packageIds);
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
await getList();
|
await getList();
|
||||||
proxy?.$modal.msgSuccess("删除成功");
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 导出按钮操作 */
|
/** 导出按钮操作 */
|
||||||
const handleExport = () => {
|
const handleExport = () => {
|
||||||
proxy?.download("system/tenantPackage/export", {
|
proxy?.download(
|
||||||
...queryParams.value
|
'system/tenantPackage/export',
|
||||||
}, `tenantPackage_${new Date().getTime()}.xlsx`);
|
{
|
||||||
|
...queryParams.value
|
||||||
|
},
|
||||||
|
`tenantPackage_${new Date().getTime()}.xlsx`
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|||||||
@ -21,12 +21,12 @@
|
|||||||
<h4 class="panel-title">角色信息</h4>
|
<h4 class="panel-title">角色信息</h4>
|
||||||
<div>
|
<div>
|
||||||
<el-table
|
<el-table
|
||||||
|
ref="tableRef"
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
:row-key="getRowKey"
|
:row-key="getRowKey"
|
||||||
@row-click="clickRow"
|
|
||||||
ref="tableRef"
|
|
||||||
@selection-change="handleSelectionChange"
|
|
||||||
:data="roles.slice((pageNum - 1) * pageSize, pageNum * pageSize)"
|
:data="roles.slice((pageNum - 1) * pageSize, pageNum * pageSize)"
|
||||||
|
@row-click="clickRow"
|
||||||
|
@selection-change="handleSelectionChange"
|
||||||
>
|
>
|
||||||
<el-table-column label="序号" width="55" type="index" align="center">
|
<el-table-column label="序号" width="55" type="index" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
@ -43,8 +43,8 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<pagination v-show="total > 0" :total="total" v-model:page="pageNum" v-model:limit="pageSize" />
|
<pagination v-show="total > 0" v-model:page="pageNum" v-model:limit="pageSize" :total="total" />
|
||||||
<div style="text-align: center;margin-left:-120px;margin-top:30px;">
|
<div style="text-align: center; margin-left: -120px; margin-top: 30px">
|
||||||
<el-button type="primary" @click="submitForm()">提交</el-button>
|
<el-button type="primary" @click="submitForm()">提交</el-button>
|
||||||
<el-button @click="close()">返回</el-button>
|
<el-button @click="close()">返回</el-button>
|
||||||
</div>
|
</div>
|
||||||
@ -55,9 +55,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="AuthRole" lang="ts">
|
<script setup name="AuthRole" lang="ts">
|
||||||
import { RoleVO } from "@/api/system/role/types";
|
import { RoleVO } from '@/api/system/role/types';
|
||||||
import { getAuthRole, updateAuthRole } from "@/api/system/user";
|
import { getAuthRole, updateAuthRole } from '@/api/system/user';
|
||||||
import { UserForm } from "@/api/system/user/types";
|
import { UserForm } from '@/api/system/user/types';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
@ -70,7 +70,7 @@ const roleIds = ref<Array<string | number>>([]);
|
|||||||
const roles = ref<RoleVO[]>([]);
|
const roles = ref<RoleVO[]>([]);
|
||||||
const form = ref<Partial<UserForm>>({
|
const form = ref<Partial<UserForm>>({
|
||||||
nickName: undefined,
|
nickName: undefined,
|
||||||
userName: "",
|
userName: '',
|
||||||
userId: undefined
|
userId: undefined
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ const clickRow = (row: RoleVO) => {
|
|||||||
};
|
};
|
||||||
/** 多选框选中数据 */
|
/** 多选框选中数据 */
|
||||||
const handleSelectionChange = (selection: RoleVO[]) => {
|
const handleSelectionChange = (selection: RoleVO[]) => {
|
||||||
roleIds.value = selection.map(item => item.roleId);
|
roleIds.value = selection.map((item) => item.roleId);
|
||||||
};
|
};
|
||||||
/** 保存选中的数据编号 */
|
/** 保存选中的数据编号 */
|
||||||
const getRowKey = (row: RoleVO): string => {
|
const getRowKey = (row: RoleVO): string => {
|
||||||
@ -91,15 +91,15 @@ const getRowKey = (row: RoleVO): string => {
|
|||||||
};
|
};
|
||||||
/** 关闭按钮 */
|
/** 关闭按钮 */
|
||||||
const close = () => {
|
const close = () => {
|
||||||
const obj = { path: "/system/user" };
|
const obj = { path: '/system/user' };
|
||||||
proxy?.$tab.closeOpenPage(obj);
|
proxy?.$tab.closeOpenPage(obj);
|
||||||
};
|
};
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
const submitForm = async () => {
|
const submitForm = async () => {
|
||||||
const userId = form.value.userId;
|
const userId = form.value.userId;
|
||||||
const rIds = roleIds.value.join(",");
|
const rIds = roleIds.value.join(',');
|
||||||
await updateAuthRole({ userId: userId as string, roleIds: rIds });
|
await updateAuthRole({ userId: userId as string, roleIds: rIds });
|
||||||
proxy?.$modal.msgSuccess("授权成功");
|
proxy?.$modal.msgSuccess('授权成功');
|
||||||
close();
|
close();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -112,7 +112,7 @@ const getList = async () => {
|
|||||||
Object.assign(roles.value, res.data.roles);
|
Object.assign(roles.value, res.data.roles);
|
||||||
total.value = roles.value.length;
|
total.value = roles.value.length;
|
||||||
await nextTick(() => {
|
await nextTick(() => {
|
||||||
roles.value.forEach(row => {
|
roles.value.forEach((row) => {
|
||||||
if (row?.flag) {
|
if (row?.flag) {
|
||||||
tableRef.value?.toggleRowSelection(row, true);
|
tableRef.value?.toggleRowSelection(row, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,8 +6,8 @@
|
|||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-input v-model="deptName" placeholder="请输入部门名称" prefix-icon="Search" clearable />
|
<el-input v-model="deptName" placeholder="请输入部门名称" prefix-icon="Search" clearable />
|
||||||
<el-tree
|
<el-tree
|
||||||
class="mt-2"
|
|
||||||
ref="deptTreeRef"
|
ref="deptTreeRef"
|
||||||
|
class="mt-2"
|
||||||
node-key="id"
|
node-key="id"
|
||||||
:data="deptOptions"
|
:data="deptOptions"
|
||||||
:props="{ label: 'label', children: 'children' }"
|
:props="{ label: 'label', children: 'children' }"
|
||||||
@ -21,7 +21,7 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<el-col :lg="20" :xs="24">
|
<el-col :lg="20" :xs="24">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
<div class="mb-[10px]" v-show="showSearch">
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
|
||||||
<el-form-item label="用户名称" prop="userName">
|
<el-form-item label="用户名称" prop="userName">
|
||||||
@ -42,7 +42,7 @@
|
|||||||
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
|
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="创建时间" style="width: 308px;">
|
<el-form-item label="创建时间" style="width: 308px">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
v-model="dateRange"
|
v-model="dateRange"
|
||||||
value-format="YYYY-MM-DD"
|
value-format="YYYY-MM-DD"
|
||||||
@ -53,8 +53,8 @@
|
|||||||
></el-date-picker>
|
></el-date-picker>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="handleQuery" icon="Search">搜索</el-button>
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||||
<el-button @click="resetQuery" icon="Refresh">重置</el-button>
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
@ -65,15 +65,15 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10">
|
<el-row :gutter="10">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain @click="handleAdd()" v-has-permi="['system:user:add']" icon="Plus">新增</el-button>
|
<el-button v-has-permi="['system:user:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="success" plain @click="handleUpdate()" :disabled="single" v-has-permi="['system:user:add']" icon="Edit">
|
<el-button v-has-permi="['system:user:add']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">
|
||||||
修改
|
修改
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="danger" plain @click="handleDelete()" :disabled="multiple" v-has-permi="['system:user:delete']" icon="Delete">
|
<el-button v-has-permi="['system:user:delete']" type="danger" plain :disabled="multiple" icon="Delete" @click="handleDelete()">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -85,38 +85,38 @@
|
|||||||
></el-button>
|
></el-button>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
<el-dropdown-item @click="importTemplate" icon="Download">下载模板</el-dropdown-item>
|
<el-dropdown-item icon="Download" @click="importTemplate">下载模板</el-dropdown-item>
|
||||||
<el-dropdown-item @click="handleImport" icon="Top"> 导入数据</el-dropdown-item>
|
<el-dropdown-item icon="Top" @click="handleImport"> 导入数据</el-dropdown-item>
|
||||||
<el-dropdown-item @click="handleExport" icon="Download"> 导出数据</el-dropdown-item>
|
<el-dropdown-item icon="Download" @click="handleExport"> 导出数据</el-dropdown-item>
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</template>
|
</template>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :columns="columns" :search="true"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" :columns="columns" :search="true" @query-table="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="50" align="center" />
|
<el-table-column type="selection" width="50" align="center" />
|
||||||
<el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns[0].visible" />
|
<el-table-column v-if="columns[0].visible" key="userId" label="用户编号" align="center" prop="userId" />
|
||||||
<el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
|
<el-table-column v-if="columns[1].visible" key="userName" label="用户名称" align="center" prop="userName" :show-overflow-tooltip="true" />
|
||||||
<el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns[2].visible" :show-overflow-tooltip="true" />
|
<el-table-column v-if="columns[2].visible" key="nickName" label="用户昵称" align="center" prop="nickName" :show-overflow-tooltip="true" />
|
||||||
<el-table-column
|
<el-table-column
|
||||||
|
v-if="columns[3].visible"
|
||||||
|
key="deptName"
|
||||||
label="部门"
|
label="部门"
|
||||||
align="center"
|
align="center"
|
||||||
key="deptName"
|
|
||||||
prop="dept.deptName"
|
prop="dept.deptName"
|
||||||
v-if="columns[3].visible"
|
|
||||||
:show-overflow-tooltip="true"
|
:show-overflow-tooltip="true"
|
||||||
/>
|
/>
|
||||||
<el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" v-if="columns[4].visible" width="120" />
|
<el-table-column v-if="columns[4].visible" key="phonenumber" label="手机号码" align="center" prop="phonenumber" width="120" />
|
||||||
<el-table-column label="状态" align="center" key="status" v-if="columns[5].visible">
|
<el-table-column v-if="columns[5].visible" key="status" label="状态" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
|
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[6].visible" width="160">
|
<el-table-column v-if="columns[6].visible" label="创建时间" align="center" prop="createTime" width="160">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span>{{ scope.row.createTime }}</span>
|
<span>{{ scope.row.createTime }}</span>
|
||||||
</template>
|
</template>
|
||||||
@ -124,19 +124,19 @@
|
|||||||
|
|
||||||
<el-table-column label="操作" fixed="right" width="180" class-name="small-padding fixed-width">
|
<el-table-column label="操作" fixed="right" width="180" class-name="small-padding fixed-width">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="修改" placement="top" v-if="scope.row.userId !== 1">
|
<el-tooltip v-if="scope.row.userId !== 1" content="修改" placement="top">
|
||||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:user:edit']"></el-button>
|
<el-button v-hasPermi="['system:user:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="删除" placement="top" v-if="scope.row.userId !== 1">
|
<el-tooltip v-if="scope.row.userId !== 1" content="删除" placement="top">
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:user:remove']"></el-button>
|
<el-button v-hasPermi="['system:user:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
|
||||||
<el-tooltip content="重置密码" placement="top" v-if="scope.row.userId !== 1">
|
<el-tooltip v-if="scope.row.userId !== 1" content="重置密码" placement="top">
|
||||||
<el-button link type="primary" icon="Key" @click="handleResetPwd(scope.row)" v-hasPermi="['system:user:resetPwd']"></el-button>
|
<el-button v-hasPermi="['system:user:resetPwd']" link type="primary" icon="Key" @click="handleResetPwd(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
|
||||||
<el-tooltip content="分配角色" placement="top" v-if="scope.row.userId !== 1">
|
<el-tooltip v-if="scope.row.userId !== 1" content="分配角色" placement="top">
|
||||||
<el-button link type="primary" icon="CircleCheck" @click="handleAuthRole(scope.row)" v-hasPermi="['system:user:edit']"></el-button>
|
<el-button v-hasPermi="['system:user:edit']" link type="primary" icon="CircleCheck" @click="handleAuthRole(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@ -144,9 +144,9 @@
|
|||||||
|
|
||||||
<pagination
|
<pagination
|
||||||
v-show="total > 0"
|
v-show="total > 0"
|
||||||
:total="total"
|
|
||||||
v-model:page="queryParams.pageNum"
|
v-model:page="queryParams.pageNum"
|
||||||
v-model:limit="queryParams.pageSize"
|
v-model:limit="queryParams.pageSize"
|
||||||
|
:total="total"
|
||||||
@pagination="getList"
|
@pagination="getList"
|
||||||
/>
|
/>
|
||||||
</el-card>
|
</el-card>
|
||||||
@ -154,8 +154,8 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<!-- 添加或修改用户配置对话框 -->
|
<!-- 添加或修改用户配置对话框 -->
|
||||||
<el-dialog ref="formDialogRef" :title="dialog.title" v-model="dialog.visible" width="600px" append-to-body @close="closeDialog">
|
<el-dialog ref="formDialogRef" v-model="dialog.visible" :title="dialog.title" width="600px" append-to-body @close="closeDialog">
|
||||||
<el-form :model="form" :rules="rules" ref="userFormRef" label-width="80px">
|
<el-form ref="userFormRef" :model="form" :rules="rules" label-width="80px">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="用户昵称" prop="nickName">
|
<el-form-item label="用户昵称" prop="nickName">
|
||||||
@ -210,8 +210,7 @@
|
|||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="状态">
|
<el-form-item label="状态">
|
||||||
<el-radio-group v-model="form.status">
|
<el-radio-group v-model="form.status">
|
||||||
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{
|
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
|
||||||
dict.label }}</el-radio>
|
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -261,7 +260,7 @@
|
|||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<!-- 用户导入对话框 -->
|
<!-- 用户导入对话框 -->
|
||||||
<el-dialog :title="upload.title" v-model="upload.open" width="400px" append-to-body>
|
<el-dialog v-model="upload.open" :title="upload.title" width="400px" append-to-body>
|
||||||
<el-upload
|
<el-upload
|
||||||
ref="uploadRef"
|
ref="uploadRef"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
@ -282,7 +281,7 @@
|
|||||||
<div class="text-center el-upload__tip">
|
<div class="text-center el-upload__tip">
|
||||||
<div class="el-upload__tip"><el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据</div>
|
<div class="el-upload__tip"><el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据</div>
|
||||||
<span>仅允许导入xls、xlsx格式文件。</span>
|
<span>仅允许导入xls、xlsx格式文件。</span>
|
||||||
<el-link type="primary" :underline="false" style="font-size:12px;vertical-align: baseline;" @click="importTemplate">下载模板</el-link>
|
<el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">下载模板</el-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
@ -297,22 +296,22 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="User" lang="ts">
|
<script setup name="User" lang="ts">
|
||||||
import api from "@/api/system/user"
|
import api from '@/api/system/user';
|
||||||
import { UserForm, UserQuery, UserVO } from '@/api/system/user/types';
|
import { UserForm, UserQuery, UserVO } from '@/api/system/user/types';
|
||||||
import { treeselect } from "@/api/system/dept";
|
import { treeselect } from '@/api/system/dept';
|
||||||
import { DeptVO } from "@/api/system/dept/types";
|
import { DeptVO } from '@/api/system/dept/types';
|
||||||
import { RoleVO } from "@/api/system/role/types";
|
import { RoleVO } from '@/api/system/role/types';
|
||||||
import { PostVO } from "@/api/system/post/types";
|
import { PostVO } from '@/api/system/post/types';
|
||||||
import { to } from "await-to-js";
|
import { to } from 'await-to-js';
|
||||||
import { globalHeaders } from "@/utils/request";
|
import { globalHeaders } from '@/utils/request';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const { sys_normal_disable, sys_user_sex } = toRefs<any>(proxy?.useDict('sys_normal_disable', 'sys_user_sex'));
|
const { sys_normal_disable, sys_user_sex } = toRefs<any>(proxy?.useDict('sys_normal_disable', 'sys_user_sex'));
|
||||||
|
|
||||||
const userList = ref<UserVO[]>();
|
const userList = ref<UserVO[]>();
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
const showSearch = ref(true)
|
const showSearch = ref(true);
|
||||||
const ids = ref<Array<number | string>>([]);
|
const ids = ref<Array<number | string>>([]);
|
||||||
const single = ref(true);
|
const single = ref(true);
|
||||||
const multiple = ref(true);
|
const multiple = ref(true);
|
||||||
@ -320,7 +319,7 @@ const total = ref(0);
|
|||||||
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
|
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
|
||||||
const deptName = ref('');
|
const deptName = ref('');
|
||||||
const deptOptions = ref<DeptVO[]>([]);
|
const deptOptions = ref<DeptVO[]>([]);
|
||||||
const initPassword = ref<String>('');
|
const initPassword = ref<string>('');
|
||||||
const postOptions = ref<PostVO[]>([]);
|
const postOptions = ref<PostVO[]>([]);
|
||||||
const roleOptions = ref<RoleVO[]>([]);
|
const roleOptions = ref<RoleVO[]>([]);
|
||||||
/*** 用户导入参数 */
|
/*** 用户导入参数 */
|
||||||
@ -328,7 +327,7 @@ const upload = reactive<ImportOption>({
|
|||||||
// 是否显示弹出层(用户导入)
|
// 是否显示弹出层(用户导入)
|
||||||
open: false,
|
open: false,
|
||||||
// 弹出层标题(用户导入)
|
// 弹出层标题(用户导入)
|
||||||
title: "",
|
title: '',
|
||||||
// 是否禁用上传
|
// 是否禁用上传
|
||||||
isUploading: false,
|
isUploading: false,
|
||||||
// 是否更新已经存在的用户数据
|
// 是否更新已经存在的用户数据
|
||||||
@ -336,19 +335,18 @@ const upload = reactive<ImportOption>({
|
|||||||
// 设置上传的请求头部
|
// 设置上传的请求头部
|
||||||
headers: globalHeaders(),
|
headers: globalHeaders(),
|
||||||
// 上传的地址
|
// 上传的地址
|
||||||
url: import.meta.env.VITE_APP_BASE_API + "/system/user/importData"
|
url: import.meta.env.VITE_APP_BASE_API + '/system/user/importData'
|
||||||
})
|
});
|
||||||
// 列显隐信息
|
// 列显隐信息
|
||||||
const columns = ref<FieldOption[]>([
|
const columns = ref<FieldOption[]>([
|
||||||
{ key: 0, label: `用户编号`, visible: false,children: [] },
|
{ key: 0, label: `用户编号`, visible: false, children: [] },
|
||||||
{ key: 1, label: `用户名称`, visible: true,children: [] },
|
{ key: 1, label: `用户名称`, visible: true, children: [] },
|
||||||
{ key: 2, label: `用户昵称`, visible: true,children: [] },
|
{ key: 2, label: `用户昵称`, visible: true, children: [] },
|
||||||
{ key: 3, label: `部门`, visible: true,children: [] },
|
{ key: 3, label: `部门`, visible: true, children: [] },
|
||||||
{ key: 4, label: `手机号码`, visible: true,children: [] },
|
{ key: 4, label: `手机号码`, visible: true, children: [] },
|
||||||
{ key: 5, label: `状态`, visible: true,children: [] },
|
{ key: 5, label: `状态`, visible: true, children: [] },
|
||||||
{ key: 6, label: `创建时间`, visible: true,children: [] }
|
{ key: 6, label: `创建时间`, visible: true, children: [] }
|
||||||
])
|
]);
|
||||||
|
|
||||||
|
|
||||||
const deptTreeRef = ref<ElTreeInstance>();
|
const deptTreeRef = ref<ElTreeInstance>();
|
||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
@ -370,11 +368,11 @@ const initFormData: UserForm = {
|
|||||||
phonenumber: undefined,
|
phonenumber: undefined,
|
||||||
email: undefined,
|
email: undefined,
|
||||||
sex: undefined,
|
sex: undefined,
|
||||||
status: "0",
|
status: '0',
|
||||||
remark: '',
|
remark: '',
|
||||||
postIds: [],
|
postIds: [],
|
||||||
roleIds: []
|
roleIds: []
|
||||||
}
|
};
|
||||||
const data = reactive<PageData<UserForm, UserQuery>>({
|
const data = reactive<PageData<UserForm, UserQuery>>({
|
||||||
form: { ...initFormData },
|
form: { ...initFormData },
|
||||||
queryParams: {
|
queryParams: {
|
||||||
@ -386,24 +384,54 @@ const data = reactive<PageData<UserForm, UserQuery>>({
|
|||||||
deptId: ''
|
deptId: ''
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
userName: [{ required: true, message: "用户名称不能为空", trigger: "blur" }, { min: 2, max: 20, message: "用户名称长度必须介于 2 和 20 之间", trigger: "blur" }],
|
userName: [
|
||||||
nickName: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
|
{ required: true, message: '用户名称不能为空', trigger: 'blur' },
|
||||||
password: [{ required: true, message: "用户密码不能为空", trigger: "blur" }, { min: 5, max: 20, message: "用户密码长度必须介于 5 和 20 之间", trigger: "blur" }],
|
{
|
||||||
email: [{ type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
|
min: 2,
|
||||||
phonenumber: [{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }]
|
max: 20,
|
||||||
|
message: '用户名称长度必须介于 2 和 20 之间',
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
nickName: [{ required: true, message: '用户昵称不能为空', trigger: 'blur' }],
|
||||||
|
password: [
|
||||||
|
{ required: true, message: '用户密码不能为空', trigger: 'blur' },
|
||||||
|
{
|
||||||
|
min: 5,
|
||||||
|
max: 20,
|
||||||
|
message: '用户密码长度必须介于 5 和 20 之间',
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
email: [
|
||||||
|
{
|
||||||
|
type: 'email',
|
||||||
|
message: '请输入正确的邮箱地址',
|
||||||
|
trigger: ['blur', 'change']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
phonenumber: [
|
||||||
|
{
|
||||||
|
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
|
||||||
|
message: '请输入正确的手机号码',
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const { queryParams, form, rules } = toRefs<PageData<UserForm, UserQuery>>(data)
|
const { queryParams, form, rules } = toRefs<PageData<UserForm, UserQuery>>(data);
|
||||||
|
|
||||||
/** 通过条件过滤节点 */
|
/** 通过条件过滤节点 */
|
||||||
const filterNode = (value: string, data: any) => {
|
const filterNode = (value: string, data: any) => {
|
||||||
if (!value) return true
|
if (!value) return true;
|
||||||
return data.label.indexOf(value) !== -1
|
return data.label.indexOf(value) !== -1;
|
||||||
}
|
};
|
||||||
/** 根据名称筛选部门树 */
|
/** 根据名称筛选部门树 */
|
||||||
watchEffect(
|
watchEffect(
|
||||||
() => { deptTreeRef.value?.filter(deptName.value); },
|
() => {
|
||||||
|
deptTreeRef.value?.filter(deptName.value);
|
||||||
|
},
|
||||||
{
|
{
|
||||||
flush: 'post' // watchEffect会在DOM挂载或者更新之前就会触发,此属性控制在DOM元素更新后运行
|
flush: 'post' // watchEffect会在DOM挂载或者更新之前就会触发,此属性控制在DOM元素更新后运行
|
||||||
}
|
}
|
||||||
@ -422,29 +450,28 @@ const getList = async () => {
|
|||||||
loading.value = false;
|
loading.value = false;
|
||||||
userList.value = res.rows;
|
userList.value = res.rows;
|
||||||
total.value = res.total;
|
total.value = res.total;
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 节点单击事件 */
|
/** 节点单击事件 */
|
||||||
const handleNodeClick = (data: DeptVO) => {
|
const handleNodeClick = (data: DeptVO) => {
|
||||||
queryParams.value.deptId = data.id;
|
queryParams.value.deptId = data.id;
|
||||||
handleQuery()
|
handleQuery();
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1
|
queryParams.value.pageNum = 1;
|
||||||
getList()
|
getList();
|
||||||
}
|
};
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
dateRange.value = ['', '']
|
dateRange.value = ['', ''];
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
queryParams.value.deptId = undefined;
|
queryParams.value.deptId = undefined;
|
||||||
deptTreeRef.value?.setCurrentKey(undefined);
|
deptTreeRef.value?.setCurrentKey(undefined);
|
||||||
handleQuery();
|
handleQuery();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row?: UserVO) => {
|
const handleDelete = async (row?: UserVO) => {
|
||||||
@ -453,78 +480,85 @@ const handleDelete = async (row?: UserVO) => {
|
|||||||
if (!err) {
|
if (!err) {
|
||||||
await api.delUser(userIds);
|
await api.delUser(userIds);
|
||||||
await getList();
|
await getList();
|
||||||
proxy?.$modal.msgSuccess("删除成功");
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 用户状态修改 */
|
/** 用户状态修改 */
|
||||||
const handleStatusChange = async (row: UserVO) => {
|
const handleStatusChange = async (row: UserVO) => {
|
||||||
let text = row.status === "0" ? "启用" : "停用"
|
let text = row.status === '0' ? '启用' : '停用';
|
||||||
try {
|
try {
|
||||||
await proxy?.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?');
|
await proxy?.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?');
|
||||||
await api.changeUserStatus(row.userId, row.status);
|
await api.changeUserStatus(row.userId, row.status);
|
||||||
proxy?.$modal.msgSuccess(text + "成功");
|
proxy?.$modal.msgSuccess(text + '成功');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
row.status = row.status === "0" ? "1" : "0";
|
row.status = row.status === '0' ? '1' : '0';
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
/** 跳转角色分配 */
|
/** 跳转角色分配 */
|
||||||
const handleAuthRole = (row: UserVO) => {
|
const handleAuthRole = (row: UserVO) => {
|
||||||
const userId = row.userId;
|
const userId = row.userId;
|
||||||
router.push("/system/user-auth/role/" + userId);
|
router.push('/system/user-auth/role/' + userId);
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 重置密码按钮操作 */
|
/** 重置密码按钮操作 */
|
||||||
const handleResetPwd = async (row: UserVO) => {
|
const handleResetPwd = async (row: UserVO) => {
|
||||||
const [err, res] = await to(ElMessageBox.prompt('请输入"' + row.userName + '"的新密码', "提示", {
|
const [err, res] = await to(
|
||||||
confirmButtonText: "确定",
|
ElMessageBox.prompt('请输入"' + row.userName + '"的新密码', '提示', {
|
||||||
cancelButtonText: "取消",
|
confirmButtonText: '确定',
|
||||||
closeOnClickModal: false,
|
cancelButtonText: '取消',
|
||||||
inputPattern: /^.{5,20}$/,
|
closeOnClickModal: false,
|
||||||
inputErrorMessage: "用户密码长度必须介于 5 和 20 之间",
|
inputPattern: /^.{5,20}$/,
|
||||||
}))
|
inputErrorMessage: '用户密码长度必须介于 5 和 20 之间'
|
||||||
|
})
|
||||||
|
);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
await api.resetUserPwd(row.userId, res.value);
|
await api.resetUserPwd(row.userId, res.value);
|
||||||
proxy?.$modal.msgSuccess("修改成功,新密码是:" + res.value);
|
proxy?.$modal.msgSuccess('修改成功,新密码是:' + res.value);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 选择条数 */
|
/** 选择条数 */
|
||||||
const handleSelectionChange = (selection: UserVO[]) => {
|
const handleSelectionChange = (selection: UserVO[]) => {
|
||||||
ids.value = selection.map((item) => item.userId);
|
ids.value = selection.map((item) => item.userId);
|
||||||
single.value = selection.length != 1;
|
single.value = selection.length != 1;
|
||||||
multiple.value = !selection.length;
|
multiple.value = !selection.length;
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 导入按钮操作 */
|
/** 导入按钮操作 */
|
||||||
const handleImport = () => {
|
const handleImport = () => {
|
||||||
upload.title = "用户导入";
|
upload.title = '用户导入';
|
||||||
upload.open = true;
|
upload.open = true;
|
||||||
}
|
};
|
||||||
/** 导出按钮操作 */
|
/** 导出按钮操作 */
|
||||||
const handleExport = () => {
|
const handleExport = () => {
|
||||||
proxy?.download("system/user/export", {
|
proxy?.download(
|
||||||
...queryParams.value,
|
'system/user/export',
|
||||||
}, `user_${new Date().getTime()}.xlsx`);
|
{
|
||||||
|
...queryParams.value
|
||||||
|
},
|
||||||
|
`user_${new Date().getTime()}.xlsx`
|
||||||
|
);
|
||||||
};
|
};
|
||||||
/** 下载模板操作 */
|
/** 下载模板操作 */
|
||||||
const importTemplate = () => {
|
const importTemplate = () => {
|
||||||
proxy?.download("system/user/importTemplate", {
|
proxy?.download('system/user/importTemplate', {}, `user_template_${new Date().getTime()}.xlsx`);
|
||||||
}, `user_template_${new Date().getTime()}.xlsx`);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
/**文件上传中处理 */
|
/**文件上传中处理 */
|
||||||
const handleFileUploadProgress = () => {
|
const handleFileUploadProgress = () => {
|
||||||
upload.isUploading = true;
|
upload.isUploading = true;
|
||||||
}
|
};
|
||||||
/** 文件上传成功处理 */
|
/** 文件上传成功处理 */
|
||||||
const handleFileSuccess = (response: any, file: UploadFile) => {
|
const handleFileSuccess = (response: any, file: UploadFile) => {
|
||||||
upload.open = false;
|
upload.open = false;
|
||||||
upload.isUploading = false;
|
upload.isUploading = false;
|
||||||
uploadRef.value?.handleRemove(file);
|
uploadRef.value?.handleRemove(file);
|
||||||
ElMessageBox.alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true });
|
ElMessageBox.alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + '</div>', '导入结果', {
|
||||||
|
dangerouslyUseHTMLString: true
|
||||||
|
});
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 提交上传文件 */
|
/** 提交上传文件 */
|
||||||
function submitFileForm() {
|
function submitFileForm() {
|
||||||
@ -538,59 +572,57 @@ const initTreeData = async () => {
|
|||||||
const { data } = await treeselect();
|
const { data } = await treeselect();
|
||||||
deptOptions.value = data;
|
deptOptions.value = data;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
/** 重置操作表单 */
|
/** 重置操作表单 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
form.value = { ...initFormData };
|
form.value = { ...initFormData };
|
||||||
userFormRef.value?.resetFields();
|
userFormRef.value?.resetFields();
|
||||||
}
|
};
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
reset();
|
reset();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 新增按钮操作 */
|
/** 新增按钮操作 */
|
||||||
const handleAdd = async () => {
|
const handleAdd = async () => {
|
||||||
reset();
|
reset();
|
||||||
const { data } = await api.getUser();
|
const { data } = await api.getUser();
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "新增用户";
|
dialog.title = '新增用户';
|
||||||
await initTreeData();
|
await initTreeData();
|
||||||
postOptions.value = data.posts;
|
postOptions.value = data.posts;
|
||||||
roleOptions.value = data.roles;
|
roleOptions.value = data.roles;
|
||||||
form.value.password = initPassword.value.toString();
|
form.value.password = initPassword.value.toString();
|
||||||
}
|
};
|
||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
const handleUpdate = async (row?: UserForm) => {
|
const handleUpdate = async (row?: UserForm) => {
|
||||||
reset();
|
reset();
|
||||||
const userId = row?.userId || ids.value[0]
|
const userId = row?.userId || ids.value[0];
|
||||||
const { data } = await api.getUser(userId)
|
const { data } = await api.getUser(userId);
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "修改用户";
|
dialog.title = '修改用户';
|
||||||
await initTreeData();
|
await initTreeData();
|
||||||
Object.assign(form.value, data.user);
|
Object.assign(form.value, data.user);
|
||||||
postOptions.value = data.posts;
|
postOptions.value = data.posts;
|
||||||
roleOptions.value = data.roles;
|
roleOptions.value = data.roles;
|
||||||
form.value.postIds = data.postIds;
|
form.value.postIds = data.postIds;
|
||||||
form.value.roleIds = data.roleIds;
|
form.value.roleIds = data.roleIds;
|
||||||
form.value.password = "";
|
form.value.password = '';
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
userFormRef.value?.validate(async (valid: boolean) => {
|
userFormRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
form.value.userId ? await api.updateUser(form.value) : await api.addUser(form.value);
|
form.value.userId ? await api.updateUser(form.value) : await api.addUser(form.value);
|
||||||
proxy?.$modal.msgSuccess("操作成功");
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
await getList();
|
await getList();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 关闭用户弹窗
|
* 关闭用户弹窗
|
||||||
@ -598,7 +630,7 @@ const submitForm = () => {
|
|||||||
const closeDialog = () => {
|
const closeDialog = () => {
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
resetForm();
|
resetForm();
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 重置表单
|
* 重置表单
|
||||||
@ -609,11 +641,11 @@ const resetForm = () => {
|
|||||||
|
|
||||||
form.value.id = undefined;
|
form.value.id = undefined;
|
||||||
form.value.status = '1';
|
form.value.status = '1';
|
||||||
}
|
};
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getTreeSelect() // 初始化部门数据
|
getTreeSelect(); // 初始化部门数据
|
||||||
getList() // 初始化列表数据
|
getList(); // 初始化列表数据
|
||||||
proxy?.getConfigKey("sys.user.initPassword").then(response => {
|
proxy?.getConfigKey('sys.user.initPassword').then((response) => {
|
||||||
initPassword.value = response.data;
|
initPassword.value = response.data;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -3,14 +3,14 @@
|
|||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :span="6" :xs="24">
|
<el-col :span="6" :xs="24">
|
||||||
<el-card class="box-card">
|
<el-card class="box-card">
|
||||||
<template v-slot:header>
|
<template #header>
|
||||||
<div class="clearfix">
|
<div class="clearfix">
|
||||||
<span>个人信息</span>
|
<span>个人信息</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div>
|
<div>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<userAvatar/>
|
<userAvatar />
|
||||||
</div>
|
</div>
|
||||||
<ul class="list-group list-group-striped">
|
<ul class="list-group list-group-striped">
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
@ -27,7 +27,7 @@
|
|||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<svg-icon icon-class="tree" />所属部门
|
<svg-icon icon-class="tree" />所属部门
|
||||||
<div class="pull-right" v-if="state.user.dept">{{ state.user.dept.deptName }} / {{ state.postGroup }}</div>
|
<div v-if="state.user.dept" class="pull-right">{{ state.user.dept.deptName }} / {{ state.postGroup }}</div>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<svg-icon icon-class="peoples" />所属角色
|
<svg-icon icon-class="peoples" />所属角色
|
||||||
@ -43,7 +43,7 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="18" :xs="24">
|
<el-col :span="18" :xs="24">
|
||||||
<el-card>
|
<el-card>
|
||||||
<template v-slot:header>
|
<template #header>
|
||||||
<div class="clearfix">
|
<div class="clearfix">
|
||||||
<span>基本资料</span>
|
<span>基本资料</span>
|
||||||
</div>
|
</div>
|
||||||
@ -66,38 +66,38 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="Profile" lang="ts">
|
<script setup name="Profile" lang="ts">
|
||||||
import UserAvatar from "./userAvatar.vue";
|
import UserAvatar from './userAvatar.vue';
|
||||||
import UserInfo from "./userInfo.vue";
|
import UserInfo from './userInfo.vue';
|
||||||
import ResetPwd from "./resetPwd.vue";
|
import ResetPwd from './resetPwd.vue';
|
||||||
import ThirdParty from "./thirdParty.vue";
|
import ThirdParty from './thirdParty.vue';
|
||||||
import { getAuthList } from "@/api/system/social/auth";
|
import { getAuthList } from '@/api/system/social/auth';
|
||||||
import { getUserProfile } from "@/api/system/user";
|
import { getUserProfile } from '@/api/system/user';
|
||||||
|
|
||||||
const activeTab = ref("userinfo");
|
const activeTab = ref('userinfo');
|
||||||
const state = ref<Record<string, any>>({
|
const state = ref<Record<string, any>>({
|
||||||
user: {},
|
user: {},
|
||||||
roleGroup: '',
|
roleGroup: '',
|
||||||
postGroup: '',
|
postGroup: '',
|
||||||
auths: []
|
auths: []
|
||||||
});
|
});
|
||||||
|
|
||||||
const userForm = ref({});
|
const userForm = ref({});
|
||||||
|
|
||||||
const getUser = async () => {
|
const getUser = async () => {
|
||||||
const res = await getUserProfile();
|
const res = await getUserProfile();
|
||||||
state.value.user = res.data.user;
|
state.value.user = res.data.user;
|
||||||
userForm.value = { ...res.data.user }
|
userForm.value = { ...res.data.user };
|
||||||
state.value.roleGroup = res.data.roleGroup;
|
state.value.roleGroup = res.data.roleGroup;
|
||||||
state.value.postGroup = res.data.postGroup;
|
state.value.postGroup = res.data.postGroup;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getAuths = async () => {
|
const getAuths = async () => {
|
||||||
const res = await getAuthList();
|
const res = await getAuthList();
|
||||||
state.value.auths = res.data;
|
state.value.auths = res.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getUser();
|
getUser();
|
||||||
getAuths();
|
getAuths();
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -17,37 +17,43 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { updateUserPwd } from "@/api/system/user";
|
import { updateUserPwd } from '@/api/system/user';
|
||||||
import type { ResetPwdForm } from "@/api/system/user/types";
|
import type { ResetPwdForm } from '@/api/system/user/types';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const pwdRef = ref<ElFormInstance>();
|
const pwdRef = ref<ElFormInstance>();
|
||||||
const user = ref<ResetPwdForm>({
|
const user = ref<ResetPwdForm>({
|
||||||
oldPassword: "",
|
oldPassword: '',
|
||||||
newPassword: "",
|
newPassword: '',
|
||||||
confirmPassword: ""
|
confirmPassword: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
const equalToPassword = (rule: any, value: string, callback: any) => {
|
const equalToPassword = (rule: any, value: string, callback: any) => {
|
||||||
if (user.value.newPassword !== value) {
|
if (user.value.newPassword !== value) {
|
||||||
callback(new Error("两次输入的密码不一致"));
|
callback(new Error('两次输入的密码不一致'));
|
||||||
} else {
|
} else {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const rules = ref({
|
const rules = ref({
|
||||||
oldPassword: [{ required: true, message: "旧密码不能为空", trigger: "blur" }],
|
oldPassword: [{ required: true, message: '旧密码不能为空', trigger: 'blur' }],
|
||||||
newPassword: [{ required: true, message: "新密码不能为空", trigger: "blur" }, {
|
newPassword: [
|
||||||
min: 6,
|
{ required: true, message: '新密码不能为空', trigger: 'blur' },
|
||||||
max: 20,
|
{
|
||||||
message: "长度在 6 到 20 个字符",
|
min: 6,
|
||||||
trigger: "blur"
|
max: 20,
|
||||||
}],
|
message: '长度在 6 到 20 个字符',
|
||||||
confirmPassword: [{ required: true, message: "确认密码不能为空", trigger: "blur" }, {
|
trigger: 'blur'
|
||||||
required: true,
|
}
|
||||||
validator: equalToPassword,
|
],
|
||||||
trigger: "blur"
|
confirmPassword: [
|
||||||
}]
|
{ required: true, message: '确认密码不能为空', trigger: 'blur' },
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
validator: equalToPassword,
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
@ -55,7 +61,7 @@ const submit = () => {
|
|||||||
pwdRef.value?.validate(async (valid: boolean) => {
|
pwdRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
await updateUserPwd(user.value.oldPassword, user.value.newPassword);
|
await updateUserPwd(user.value.oldPassword, user.value.newPassword);
|
||||||
proxy?.$modal.msgSuccess("修改成功");
|
proxy?.$modal.msgSuccess('修改成功');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -4,14 +4,14 @@
|
|||||||
<el-table-column label="序号" width="50" type="index"></el-table-column>
|
<el-table-column label="序号" width="50" type="index"></el-table-column>
|
||||||
<el-table-column label="绑定账号平台" width="140" align="center" prop="source" show-overflow-tooltip />
|
<el-table-column label="绑定账号平台" width="140" align="center" prop="source" show-overflow-tooltip />
|
||||||
<el-table-column label="头像" width="120" align="center" prop="avatar">
|
<el-table-column label="头像" width="120" align="center" prop="avatar">
|
||||||
<template v-slot="scope">
|
<template #default="scope">
|
||||||
<img :src="scope.row.avatar" style="width: 45px; height: 45px" />
|
<img :src="scope.row.avatar" style="width: 45px; height: 45px" />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="系统账号" width="180" align="center" prop="userName" :show-overflow-tooltip="true" />
|
<el-table-column label="系统账号" width="180" align="center" prop="userName" :show-overflow-tooltip="true" />
|
||||||
<el-table-column label="绑定时间" width="180" align="center" prop="createTime" />
|
<el-table-column label="绑定时间" width="180" align="center" prop="createTime" />
|
||||||
<el-table-column label="操作" width="80" align="center" class-name="small-padding fixed-width">
|
<el-table-column label="操作" width="80" align="center" class-name="small-padding fixed-width">
|
||||||
<template v-slot="scope">
|
<template #default="scope">
|
||||||
<el-button size="small" type="text" @click="unlockAuth(scope.row)">解绑</el-button>
|
<el-button size="small" type="text" @click="unlockAuth(scope.row)">解绑</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@ -20,25 +20,25 @@
|
|||||||
<div id="git-user-binding">
|
<div id="git-user-binding">
|
||||||
<h4 class="provider-desc">你可以绑定以下第三方帐号</h4>
|
<h4 class="provider-desc">你可以绑定以下第三方帐号</h4>
|
||||||
<div id="authlist" class="user-bind">
|
<div id="authlist" class="user-bind">
|
||||||
<a class="third-app" href="#" @click="authUrl('wechat');" title="使用 微信 账号授权登录">
|
<a class="third-app" href="#" title="使用 微信 账号授权登录" @click="authUrl('wechat')">
|
||||||
<div class="git-other-login-icon">
|
<div class="git-other-login-icon">
|
||||||
<svg-icon icon-class="wechat" />
|
<svg-icon icon-class="wechat" />
|
||||||
</div>
|
</div>
|
||||||
<span class="app-name">WeiXin</span>
|
<span class="app-name">WeiXin</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="third-app" href="#" @click="authUrl('maxkey');" title="使用 MaxKey 账号授权登录">
|
<a class="third-app" href="#" title="使用 MaxKey 账号授权登录" @click="authUrl('maxkey')">
|
||||||
<div class="git-other-login-icon">
|
<div class="git-other-login-icon">
|
||||||
<svg-icon icon-class="maxkey" />
|
<svg-icon icon-class="maxkey" />
|
||||||
</div>
|
</div>
|
||||||
<span class="app-name">MaxKey</span>
|
<span class="app-name">MaxKey</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="third-app" href="#" @click="authUrl('gitee');" title="使用 Gitee 账号授权登录">
|
<a class="third-app" href="#" title="使用 Gitee 账号授权登录" @click="authUrl('gitee')">
|
||||||
<div class="git-other-login-icon">
|
<div class="git-other-login-icon">
|
||||||
<svg-icon icon-class="gitee" />
|
<svg-icon icon-class="gitee" />
|
||||||
</div>
|
</div>
|
||||||
<span class="app-name">Gitee</span>
|
<span class="app-name">Gitee</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="third-app" href="#" @click="authUrl('github');" title="使用 GitHub 账号授权登录">
|
<a class="third-app" href="#" title="使用 GitHub 账号授权登录" @click="authUrl('github')">
|
||||||
<div class="git-other-login-icon">
|
<div class="git-other-login-icon">
|
||||||
<svg-icon icon-class="github" />
|
<svg-icon icon-class="github" />
|
||||||
</div>
|
</div>
|
||||||
@ -50,31 +50,32 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { authUnlock, authBinding } from "@/api/system/social/auth";
|
import { authUnlock, authBinding } from '@/api/system/social/auth';
|
||||||
import { PropType } from "vue";
|
import { PropType } from 'vue';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
auths: {
|
auths: {
|
||||||
type: Object as PropType<any>,
|
type: Object as PropType<any>
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const auths = computed(() => props.auths);
|
const auths = computed(() => props.auths);
|
||||||
|
|
||||||
|
|
||||||
const unlockAuth = (row: any) => {
|
const unlockAuth = (row: any) => {
|
||||||
ElMessageBox.confirm('您确定要解除"' + row.source + '"的账号绑定吗?')
|
ElMessageBox.confirm('您确定要解除"' + row.source + '"的账号绑定吗?')
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return authUnlock(row.id);
|
return authUnlock(row.id);
|
||||||
}).then((res: any) => {
|
})
|
||||||
|
.then((res: any) => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
proxy?.$modal.msgSuccess("解绑成功");
|
proxy?.$modal.msgSuccess('解绑成功');
|
||||||
proxy?.$tab.refreshPage();
|
proxy?.$tab.refreshPage();
|
||||||
} else {
|
} else {
|
||||||
proxy?.$modal.msgError(res.msg);
|
proxy?.$modal.msgError(res.msg);
|
||||||
}
|
}
|
||||||
}).catch(() => { });
|
})
|
||||||
|
.catch(() => {});
|
||||||
};
|
};
|
||||||
|
|
||||||
const authUrl = (source: string) => {
|
const authUrl = (source: string) => {
|
||||||
@ -111,7 +112,7 @@ const authUrl = (source: string) => {
|
|||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.git-other-login-icon>img {
|
.git-other-login-icon > img {
|
||||||
height: 32px;
|
height: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,15 +123,13 @@ a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.provider-desc {
|
.provider-desc {
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial,
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
|
||||||
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Liberation Sans",
|
'Liberation Sans', 'PingFang SC', 'Microsoft YaHei', 'Hiragino Sans GB', 'Wenquanyi Micro Hei', 'WenQuanYi Zen Hei', 'ST Heiti', SimHei, SimSun,
|
||||||
"PingFang SC", "Microsoft YaHei", "Hiragino Sans GB", "Wenquanyi Micro Hei",
|
'WenQuanYi Zen Hei Sharp', sans-serif;
|
||||||
"WenQuanYi Zen Hei", "ST Heiti", SimHei, SimSun, "WenQuanYi Zen Hei Sharp",
|
|
||||||
sans-serif;
|
|
||||||
font-size: 1.071rem;
|
font-size: 1.071rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
td>img {
|
td > img {
|
||||||
height: 20px;
|
height: 20px;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|||||||
@ -5,16 +5,16 @@
|
|||||||
<el-row>
|
<el-row>
|
||||||
<el-col :xs="24" :md="12" :style="{ height: '350px' }">
|
<el-col :xs="24" :md="12" :style="{ height: '350px' }">
|
||||||
<vue-cropper
|
<vue-cropper
|
||||||
|
v-if="visible"
|
||||||
ref="cropper"
|
ref="cropper"
|
||||||
:img="options.img"
|
:img="options.img"
|
||||||
:info="true"
|
:info="true"
|
||||||
:autoCrop="options.autoCrop"
|
:auto-crop="options.autoCrop"
|
||||||
:autoCropWidth="options.autoCropWidth"
|
:auto-crop-width="options.autoCropWidth"
|
||||||
:autoCropHeight="options.autoCropHeight"
|
:auto-crop-height="options.autoCropHeight"
|
||||||
:fixedBox="options.fixedBox"
|
:fixed-box="options.fixedBox"
|
||||||
:outputType="options.outputType"
|
:output-type="options.outputType"
|
||||||
@realTime="realTime"
|
@real-time="realTime"
|
||||||
v-if="visible"
|
|
||||||
/>
|
/>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="24" :md="12" :style="{ height: '350px' }">
|
<el-col :xs="24" :md="12" :style="{ height: '350px' }">
|
||||||
@ -56,10 +56,10 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import "vue-cropper/dist/index.css";
|
import 'vue-cropper/dist/index.css';
|
||||||
import { VueCropper } from "vue-cropper";
|
import { VueCropper } from 'vue-cropper';
|
||||||
import { uploadAvatar } from "@/api/system/user";
|
import { uploadAvatar } from '@/api/system/user';
|
||||||
import useUserStore from "@/store/modules/user";
|
import useUserStore from '@/store/modules/user';
|
||||||
|
|
||||||
interface Options {
|
interface Options {
|
||||||
img: string | any; // 裁剪图片的地址
|
img: string | any; // 裁剪图片的地址
|
||||||
@ -73,13 +73,12 @@ interface Options {
|
|||||||
visible: boolean;
|
visible: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
|
||||||
const open = ref(false);
|
const open = ref(false);
|
||||||
const visible = ref(false);
|
const visible = ref(false);
|
||||||
const title = ref("修改头像");
|
const title = ref('修改头像');
|
||||||
|
|
||||||
const cropper = ref<any>({});
|
const cropper = ref<any>({});
|
||||||
//图片裁剪数据
|
//图片裁剪数据
|
||||||
@ -89,8 +88,8 @@ const options = reactive<Options>({
|
|||||||
autoCropWidth: 200,
|
autoCropWidth: 200,
|
||||||
autoCropHeight: 200,
|
autoCropHeight: 200,
|
||||||
fixedBox: true,
|
fixedBox: true,
|
||||||
outputType: "png",
|
outputType: 'png',
|
||||||
fileName: "",
|
fileName: '',
|
||||||
previews: {},
|
previews: {},
|
||||||
visible: false
|
visible: false
|
||||||
});
|
});
|
||||||
@ -104,8 +103,7 @@ const modalOpened = () => {
|
|||||||
visible.value = true;
|
visible.value = true;
|
||||||
};
|
};
|
||||||
/** 覆盖默认上传行为 */
|
/** 覆盖默认上传行为 */
|
||||||
const requestUpload = (): any => {
|
const requestUpload = (): any => {};
|
||||||
};
|
|
||||||
/** 向左旋转 */
|
/** 向左旋转 */
|
||||||
const rotateLeft = () => {
|
const rotateLeft = () => {
|
||||||
cropper.value.rotateLeft();
|
cropper.value.rotateLeft();
|
||||||
@ -121,8 +119,8 @@ const changeScale = (num: number) => {
|
|||||||
};
|
};
|
||||||
/** 上传预处理 */
|
/** 上传预处理 */
|
||||||
const beforeUpload = (file: any) => {
|
const beforeUpload = (file: any) => {
|
||||||
if (file.type.indexOf("image/") == -1) {
|
if (file.type.indexOf('image/') == -1) {
|
||||||
proxy?.$modal.msgError("文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。");
|
proxy?.$modal.msgError('文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。');
|
||||||
} else {
|
} else {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.readAsDataURL(file);
|
reader.readAsDataURL(file);
|
||||||
@ -136,7 +134,7 @@ const beforeUpload = (file: any) => {
|
|||||||
const uploadImg = async () => {
|
const uploadImg = async () => {
|
||||||
cropper.value.getCropBlob(async (data: any) => {
|
cropper.value.getCropBlob(async (data: any) => {
|
||||||
let formData = new FormData();
|
let formData = new FormData();
|
||||||
formData.append("avatarfile", data, options.fileName);
|
formData.append('avatarfile', data, options.fileName);
|
||||||
const res = await uploadAvatar(formData);
|
const res = await uploadAvatar(formData);
|
||||||
open.value = false;
|
open.value = false;
|
||||||
options.img = res.data.imgUrl;
|
options.img = res.data.imgUrl;
|
||||||
@ -164,7 +162,7 @@ const closeDialog = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.user-info-head:hover:after {
|
.user-info-head:hover:after {
|
||||||
content: "+";
|
content: '+';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { updateUserProfile } from "@/api/system/user";
|
import { updateUserProfile } from '@/api/system/user';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
user: {
|
user: {
|
||||||
@ -35,26 +35,31 @@ const userForm = computed(() => props.user);
|
|||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const userRef = ref<ElFormInstance>();
|
const userRef = ref<ElFormInstance>();
|
||||||
const rules = ref<ElFormRules>({
|
const rules = ref<ElFormRules>({
|
||||||
nickName: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
|
nickName: [{ required: true, message: '用户昵称不能为空', trigger: 'blur' }],
|
||||||
email: [{ required: true, message: "邮箱地址不能为空", trigger: "blur" }, {
|
email: [
|
||||||
type: "email",
|
{ required: true, message: '邮箱地址不能为空', trigger: 'blur' },
|
||||||
message: "请输入正确的邮箱地址",
|
{
|
||||||
trigger: ["blur", "change"]
|
type: 'email',
|
||||||
}],
|
message: '请输入正确的邮箱地址',
|
||||||
phonenumber: [{
|
trigger: ['blur', 'change']
|
||||||
required: true,
|
}
|
||||||
message: "手机号码不能为空",
|
],
|
||||||
trigger: "blur"
|
phonenumber: [
|
||||||
}, { pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }]
|
{
|
||||||
|
required: true,
|
||||||
|
message: '手机号码不能为空',
|
||||||
|
trigger: 'blur'
|
||||||
|
},
|
||||||
|
{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: '请输入正确的手机号码', trigger: 'blur' }
|
||||||
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
const submit = () => {
|
const submit = () => {
|
||||||
userRef.value?.validate(async (valid: boolean) => {
|
userRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
await updateUserProfile(props.user);
|
await updateUserProfile(props.user);
|
||||||
proxy?.$modal.msgSuccess("修改成功");
|
proxy?.$modal.msgSuccess('修改成功');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,27 +3,27 @@
|
|||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="表名称" prop="tableName">
|
<el-form-item label="表名称" prop="tableName">
|
||||||
<el-input placeholder="请输入仓库名称" v-model="infoForm.tableName" />
|
<el-input v-model="infoForm.tableName" placeholder="请输入仓库名称" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="表描述" prop="tableComment">
|
<el-form-item label="表描述" prop="tableComment">
|
||||||
<el-input placeholder="请输入" v-model="infoForm.tableComment" />
|
<el-input v-model="infoForm.tableComment" placeholder="请输入" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="实体类名称" prop="className">
|
<el-form-item label="实体类名称" prop="className">
|
||||||
<el-input placeholder="请输入" v-model="infoForm.className" />
|
<el-input v-model="infoForm.className" placeholder="请输入" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="作者" prop="functionAuthor">
|
<el-form-item label="作者" prop="functionAuthor">
|
||||||
<el-input placeholder="请输入" v-model="infoForm.functionAuthor" />
|
<el-input v-model="infoForm.functionAuthor" placeholder="请输入" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="备注" prop="remark">
|
<el-form-item label="备注" prop="remark">
|
||||||
<el-input type="textarea" :rows="3" v-model="infoForm.remark"></el-input>
|
<el-input v-model="infoForm.remark" type="textarea" :rows="3"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -31,19 +31,19 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { propTypes } from "@/utils/propTypes";
|
import { propTypes } from '@/utils/propTypes';
|
||||||
|
|
||||||
const prop = defineProps({
|
const prop = defineProps({
|
||||||
info: propTypes.any.def({})
|
info: propTypes.any.def({})
|
||||||
});
|
});
|
||||||
|
|
||||||
const infoForm = computed(() => prop.info)
|
const infoForm = computed(() => prop.info);
|
||||||
|
|
||||||
// 表单校验
|
// 表单校验
|
||||||
const rules = ref({
|
const rules = ref({
|
||||||
tableName: [{ required: true, message: "请输入表名称", trigger: "blur" }],
|
tableName: [{ required: true, message: '请输入表名称', trigger: 'blur' }],
|
||||||
tableComment: [{ required: true, message: "请输入表描述", trigger: "blur" }],
|
tableComment: [{ required: true, message: '请输入表描述', trigger: 'blur' }],
|
||||||
className: [{ required: true, message: "请输入实体类名称", trigger: "blur" }],
|
className: [{ required: true, message: '请输入实体类名称', trigger: 'blur' }],
|
||||||
functionAuthor: [{ required: true, message: "请输入作者", trigger: "blur" }]
|
functionAuthor: [{ required: true, message: '请输入作者', trigger: 'blur' }]
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -35,22 +35,22 @@
|
|||||||
|
|
||||||
<el-table-column label="插入" min-width="5%">
|
<el-table-column label="插入" min-width="5%">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-checkbox true-label="1" false-label="0" v-model="scope.row.isInsert"></el-checkbox>
|
<el-checkbox v-model="scope.row.isInsert" true-label="1" false-label="0"></el-checkbox>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="编辑" min-width="5%">
|
<el-table-column label="编辑" min-width="5%">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-checkbox true-label="1" false-label="0" v-model="scope.row.isEdit"></el-checkbox>
|
<el-checkbox v-model="scope.row.isEdit" true-label="1" false-label="0"></el-checkbox>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="列表" min-width="5%">
|
<el-table-column label="列表" min-width="5%">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-checkbox true-label="1" false-label="0" v-model="scope.row.isList"></el-checkbox>
|
<el-checkbox v-model="scope.row.isList" true-label="1" false-label="0"></el-checkbox>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="查询" min-width="5%">
|
<el-table-column label="查询" min-width="5%">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-checkbox true-label="1" false-label="0" v-model="scope.row.isQuery"></el-checkbox>
|
<el-checkbox v-model="scope.row.isQuery" true-label="1" false-label="0"></el-checkbox>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="查询方式" min-width="10%">
|
<el-table-column label="查询方式" min-width="10%">
|
||||||
@ -69,7 +69,7 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="必填" min-width="5%">
|
<el-table-column label="必填" min-width="5%">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-checkbox true-label="1" false-label="0" v-model="scope.row.isRequired"></el-checkbox>
|
<el-checkbox v-model="scope.row.isRequired" true-label="1" false-label="0"></el-checkbox>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="显示类型" min-width="12%">
|
<el-table-column label="显示类型" min-width="12%">
|
||||||
@ -104,7 +104,7 @@
|
|||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
<el-form label-width="100px">
|
<el-form label-width="100px">
|
||||||
<div style="text-align: center;margin-left:-100px;margin-top:10px;">
|
<div style="text-align: center; margin-left: -100px; margin-top: 10px">
|
||||||
<el-button type="primary" @click="submitForm()">提交</el-button>
|
<el-button type="primary" @click="submitForm()">提交</el-button>
|
||||||
<el-button @click="close()">返回</el-button>
|
<el-button @click="close()">返回</el-button>
|
||||||
</div>
|
</div>
|
||||||
@ -118,7 +118,7 @@ import { DbColumnVO, DbTableVO } from '@/api/tool/gen/types';
|
|||||||
import { optionselect as getDictOptionselect } from '@/api/system/dict/type';
|
import { optionselect as getDictOptionselect } from '@/api/system/dict/type';
|
||||||
import { DictTypeVO } from '@/api/system/dict/type/types';
|
import { DictTypeVO } from '@/api/system/dict/type/types';
|
||||||
import BasicInfoForm from './basicInfoForm.vue';
|
import BasicInfoForm from './basicInfoForm.vue';
|
||||||
import GenInfoForm from "./genInfoForm.vue";
|
import GenInfoForm from './genInfoForm.vue';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
@ -138,8 +138,8 @@ const submitForm = () => {
|
|||||||
const basicForm = basicInfo.value?.$refs.basicInfoForm;
|
const basicForm = basicInfo.value?.$refs.basicInfoForm;
|
||||||
const genForm = genInfo.value?.$refs.genInfoForm;
|
const genForm = genInfo.value?.$refs.genInfoForm;
|
||||||
|
|
||||||
Promise.all([basicForm, genForm].map(getFormPromise)).then(async res => {
|
Promise.all([basicForm, genForm].map(getFormPromise)).then(async (res) => {
|
||||||
const validateResult = res.every(item => !!item);
|
const validateResult = res.every((item) => !!item);
|
||||||
if (validateResult) {
|
if (validateResult) {
|
||||||
const genTable: any = Object.assign({}, info.value);
|
const genTable: any = Object.assign({}, info.value);
|
||||||
genTable.columns = columns.value;
|
genTable.columns = columns.value;
|
||||||
@ -155,24 +155,24 @@ const submitForm = () => {
|
|||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
proxy?.$modal.msgError("表单校验未通过,请重新检查提交内容");
|
proxy?.$modal.msgError('表单校验未通过,请重新检查提交内容');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
const getFormPromise = (form: any) => {
|
const getFormPromise = (form: any) => {
|
||||||
return new Promise(resolve => {
|
return new Promise((resolve) => {
|
||||||
form.validate((res: any) => {
|
form.validate((res: any) => {
|
||||||
resolve(res);
|
resolve(res);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
const close = () => {
|
const close = () => {
|
||||||
const obj = { path: "/tool/gen", query: { t: Date.now(), pageNum: route.query.pageNum } };
|
const obj = { path: '/tool/gen', query: { t: Date.now(), pageNum: route.query.pageNum } };
|
||||||
proxy?.$tab.closeOpenPage(obj);
|
proxy?.$tab.closeOpenPage(obj);
|
||||||
}
|
};
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const tableId = route.params && route.params.tableId as string;
|
const tableId = route.params && (route.params.tableId as string);
|
||||||
if (tableId) {
|
if (tableId) {
|
||||||
// 获取表详细信息
|
// 获取表详细信息
|
||||||
const res = await getGenTable(tableId);
|
const res = await getGenTable(tableId);
|
||||||
|
|||||||
@ -95,7 +95,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="24" v-if="infoForm.genType == '1'">
|
<el-col v-if="infoForm.genType == '1'" :span="24">
|
||||||
<el-form-item prop="genPath">
|
<el-form-item prop="genPath">
|
||||||
<template #label>
|
<template #label>
|
||||||
自定义路径
|
自定义路径
|
||||||
@ -223,7 +223,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { listMenu } from '@/api/system/menu';
|
import { listMenu } from '@/api/system/menu';
|
||||||
import { propTypes } from "@/utils/propTypes";
|
import { propTypes } from '@/utils/propTypes';
|
||||||
|
|
||||||
interface MenuOptionsType {
|
interface MenuOptionsType {
|
||||||
menuId: number | string;
|
menuId: number | string;
|
||||||
@ -246,21 +246,21 @@ const table = computed(() => props.tables);
|
|||||||
|
|
||||||
// 表单校验
|
// 表单校验
|
||||||
const rules = ref({
|
const rules = ref({
|
||||||
tplCategory: [{ required: true, message: "请选择生成模板", trigger: "blur" }],
|
tplCategory: [{ required: true, message: '请选择生成模板', trigger: 'blur' }],
|
||||||
packageName: [{ required: true, message: "请输入生成包路径", trigger: "blur" }],
|
packageName: [{ required: true, message: '请输入生成包路径', trigger: 'blur' }],
|
||||||
moduleName: [{ required: true, message: "请输入生成模块名", trigger: "blur" }],
|
moduleName: [{ required: true, message: '请输入生成模块名', trigger: 'blur' }],
|
||||||
businessName: [{ required: true, message: "请输入生成业务名", trigger: "blur" }],
|
businessName: [{ required: true, message: '请输入生成业务名', trigger: 'blur' }],
|
||||||
functionName: [{ required: true, message: "请输入生成功能名", trigger: "blur" }]
|
functionName: [{ required: true, message: '请输入生成功能名', trigger: 'blur' }]
|
||||||
});
|
});
|
||||||
const subSelectChange = () => {
|
const subSelectChange = () => {
|
||||||
infoForm.value.subTableFkName = "";
|
infoForm.value.subTableFkName = '';
|
||||||
}
|
};
|
||||||
const tplSelectChange = (value: string) => {
|
const tplSelectChange = (value: string) => {
|
||||||
if (value !== "sub") {
|
if (value !== 'sub') {
|
||||||
infoForm.value.subTableName = "";
|
infoForm.value.subTableName = '';
|
||||||
infoForm.value.subTableFkName = "";
|
infoForm.value.subTableFkName = '';
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
const setSubTableColumns = (value: string) => {
|
const setSubTableColumns = (value: string) => {
|
||||||
table.value.forEach((item: any) => {
|
table.value.forEach((item: any) => {
|
||||||
const name = item.tableName;
|
const name = item.tableName;
|
||||||
@ -268,24 +268,27 @@ const setSubTableColumns = (value: string) => {
|
|||||||
subColumns.value = item.columns;
|
subColumns.value = item.columns;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 查询菜单下拉树结构 */
|
/** 查询菜单下拉树结构 */
|
||||||
const getMenuTreeselect = async () => {
|
const getMenuTreeselect = async () => {
|
||||||
const res = await listMenu();
|
const res = await listMenu();
|
||||||
res.data.forEach(m => m.menuId = m.menuId.toString());
|
res.data.forEach((m) => (m.menuId = m.menuId.toString()));
|
||||||
const data = proxy?.handleTree<MenuOptionsType>(res.data, "menuId");
|
const data = proxy?.handleTree<MenuOptionsType>(res.data, 'menuId');
|
||||||
if (data) {
|
if (data) {
|
||||||
menuOptions.value = data
|
menuOptions.value = data;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
watch(() => props.info.subTableName, val => {
|
watch(
|
||||||
setSubTableColumns(val);
|
() => props.info.subTableName,
|
||||||
});
|
(val) => {
|
||||||
|
setSubTableColumns(val);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getMenuTreeselect();
|
getMenuTreeselect();
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- 导入表 -->
|
<!-- 导入表 -->
|
||||||
<el-dialog title="导入表" v-model="visible" width="1100px" top="5vh" append-to-body>
|
<el-dialog v-model="visible" title="导入表" width="1100px" top="5vh" append-to-body>
|
||||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||||
<el-form-item label="数据源" prop="dataName">
|
<el-form-item label="数据源" prop="dataName">
|
||||||
<el-select v-model="queryParams.dataName" filterable placeholder="请选择/输入数据源名称" style="width: 200px">
|
<el-select v-model="queryParams.dataName" filterable placeholder="请选择/输入数据源名称" style="width: 200px">
|
||||||
<el-option v-for="item in dataNameList" :key="item" :label="item" :value="item"> </el-option>
|
<el-option v-for="item in dataNameList" :key="item" :label="item" :value="item"> </el-option>
|
||||||
@ -19,14 +19,14 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-table @row-click="clickRow" ref="tableRef" :data="dbTableList" @selection-change="handleSelectionChange" height="260px">
|
<el-table ref="tableRef" :data="dbTableList" height="260px" @row-click="clickRow" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55"></el-table-column>
|
<el-table-column type="selection" width="55"></el-table-column>
|
||||||
<el-table-column prop="tableName" label="表名称" :show-overflow-tooltip="true"></el-table-column>
|
<el-table-column prop="tableName" label="表名称" :show-overflow-tooltip="true"></el-table-column>
|
||||||
<el-table-column prop="tableComment" label="表描述" :show-overflow-tooltip="true"></el-table-column>
|
<el-table-column prop="tableComment" label="表描述" :show-overflow-tooltip="true"></el-table-column>
|
||||||
<el-table-column prop="createTime" label="创建时间"></el-table-column>
|
<el-table-column prop="createTime" label="创建时间"></el-table-column>
|
||||||
<el-table-column prop="updateTime" label="更新时间"></el-table-column>
|
<el-table-column prop="updateTime" label="更新时间"></el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
|
||||||
</el-row>
|
</el-row>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="dialog-footer">
|
<div class="dialog-footer">
|
||||||
@ -59,7 +59,7 @@ const queryParams = reactive<DbTableQuery>({
|
|||||||
});
|
});
|
||||||
const dataNameList = ref<Array<string>>([]);
|
const dataNameList = ref<Array<string>>([]);
|
||||||
|
|
||||||
const emit = defineEmits(["ok"]);
|
const emit = defineEmits(['ok']);
|
||||||
|
|
||||||
/** 查询参数列表 */
|
/** 查询参数列表 */
|
||||||
const show = (dataName: string) => {
|
const show = (dataName: string) => {
|
||||||
@ -71,53 +71,53 @@ const show = (dataName: string) => {
|
|||||||
}
|
}
|
||||||
getList();
|
getList();
|
||||||
visible.value = true;
|
visible.value = true;
|
||||||
}
|
};
|
||||||
/** 单击选择行 */
|
/** 单击选择行 */
|
||||||
const clickRow = (row: DbTableVO) => {
|
const clickRow = (row: DbTableVO) => {
|
||||||
// ele bug
|
// ele bug
|
||||||
tableRef.value?.toggleRowSelection(row, false);
|
tableRef.value?.toggleRowSelection(row, false);
|
||||||
}
|
};
|
||||||
/** 多选框选中数据 */
|
/** 多选框选中数据 */
|
||||||
const handleSelectionChange = (selection: DbTableVO[]) => {
|
const handleSelectionChange = (selection: DbTableVO[]) => {
|
||||||
tables.value = selection.map(item => item.tableName);
|
tables.value = selection.map((item) => item.tableName);
|
||||||
}
|
};
|
||||||
/** 查询表数据 */
|
/** 查询表数据 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
const res = await listDbTable(queryParams);
|
const res = await listDbTable(queryParams);
|
||||||
dbTableList.value = res.rows;
|
dbTableList.value = res.rows;
|
||||||
total.value = res.total;
|
total.value = res.total;
|
||||||
}
|
};
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.pageNum = 1;
|
queryParams.pageNum = 1;
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
handleQuery();
|
handleQuery();
|
||||||
}
|
};
|
||||||
/** 导入按钮操作 */
|
/** 导入按钮操作 */
|
||||||
const handleImportTable = async () => {
|
const handleImportTable = async () => {
|
||||||
const tableNames = tables.value.join(",");
|
const tableNames = tables.value.join(',');
|
||||||
if (tableNames == "") {
|
if (tableNames == '') {
|
||||||
proxy?.$modal.msgError("请选择要导入的表");
|
proxy?.$modal.msgError('请选择要导入的表');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const res = await importTable({ tables: tableNames, dataName: queryParams.dataName });
|
const res = await importTable({ tables: tableNames, dataName: queryParams.dataName });
|
||||||
proxy?.$modal.msgSuccess(res.msg);
|
proxy?.$modal.msgSuccess(res.msg);
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
visible.value = false;
|
visible.value = false;
|
||||||
emit("ok");
|
emit('ok');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
/** 查询多数据源名称 */
|
/** 查询多数据源名称 */
|
||||||
const getDataNameList = async () => {
|
const getDataNameList = async () => {
|
||||||
const res = await getDataNames()
|
const res = await getDataNames();
|
||||||
dataNameList.value = res.data;
|
dataNameList.value = res.data;
|
||||||
}
|
};
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
show,
|
show
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
<div class="mb-[10px]" v-show="showSearch">
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
|
||||||
<el-form-item label="数据源" prop="dataName">
|
<el-form-item label="数据源" prop="dataName">
|
||||||
<el-select v-model="queryParams.dataName" filterable clearable placeholder="请选择/输入数据源名称" style="width: 200px">
|
<el-select v-model="queryParams.dataName" filterable clearable placeholder="请选择/输入数据源名称" style="width: 200px">
|
||||||
<el-option key="" label="全部" value="" />
|
<el-option key="" label="全部" value="" />
|
||||||
@ -39,20 +39,20 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Download" @click="handleGenTable()" v-hasPermi="['tool:gen:code']">生成</el-button>
|
<el-button v-hasPermi="['tool:gen:code']" type="primary" plain icon="Download" @click="handleGenTable()">生成</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="info" plain icon="Upload" @click="openImportTable" v-hasPermi="['tool:gen:import']">导入</el-button>
|
<el-button v-hasPermi="['tool:gen:import']" type="info" plain icon="Upload" @click="openImportTable">导入</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleEditTable()" v-hasPermi="['tool:gen:edit']">修改</el-button>
|
<el-button v-hasPermi="['tool:gen:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleEditTable()">修改</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['tool:gen:remove']">
|
<el-button v-hasPermi="['tool:gen:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -72,28 +72,28 @@
|
|||||||
<el-table-column label="操作" align="center" width="330" class-name="small-padding fixed-width">
|
<el-table-column label="操作" align="center" width="330" class-name="small-padding fixed-width">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="预览" placement="top">
|
<el-tooltip content="预览" placement="top">
|
||||||
<el-button link type="primary" icon="View" @click="handlePreview(scope.row)" v-hasPermi="['tool:gen:preview']"></el-button>
|
<el-button v-hasPermi="['tool:gen:preview']" link type="primary" icon="View" @click="handlePreview(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="编辑" placement="top">
|
<el-tooltip content="编辑" placement="top">
|
||||||
<el-button link type="primary" icon="Edit" @click="handleEditTable(scope.row)" v-hasPermi="['tool:gen:edit']"></el-button>
|
<el-button v-hasPermi="['tool:gen:edit']" link type="primary" icon="Edit" @click="handleEditTable(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="删除" placement="top">
|
<el-tooltip content="删除" placement="top">
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['tool:gen:remove']"></el-button>
|
<el-button v-hasPermi="['tool:gen:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="同步" placement="top">
|
<el-tooltip content="同步" placement="top">
|
||||||
<el-button link type="primary" icon="Refresh" @click="handleSynchDb(scope.row)" v-hasPermi="['tool:gen:edit']"></el-button>
|
<el-button v-hasPermi="['tool:gen:edit']" link type="primary" icon="Refresh" @click="handleSynchDb(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="生成代码" placement="top">
|
<el-tooltip content="生成代码" placement="top">
|
||||||
<el-button link type="primary" icon="Download" @click="handleGenTable(scope.row)" v-hasPermi="['tool:gen:code']"></el-button>
|
<el-button v-hasPermi="['tool:gen:code']" link type="primary" icon="Download" @click="handleGenTable(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<!-- 预览界面 -->
|
<!-- 预览界面 -->
|
||||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="80%" top="5vh" append-to-body class="scrollbar">
|
<el-dialog v-model="dialog.visible" :title="dialog.title" width="80%" top="5vh" append-to-body class="scrollbar">
|
||||||
<el-tabs v-model="preview.activeName">
|
<el-tabs v-model="preview.activeName">
|
||||||
<el-tab-pane
|
<el-tab-pane
|
||||||
v-for="(value, key) in preview.data"
|
v-for="(value, key) in preview.data"
|
||||||
@ -101,7 +101,7 @@
|
|||||||
:name="key.substring(key.lastIndexOf('/') + 1, key.indexOf('.vm'))"
|
:name="key.substring(key.lastIndexOf('/') + 1, key.indexOf('.vm'))"
|
||||||
:key="value"
|
:key="value"
|
||||||
>
|
>
|
||||||
<el-link :underline="false" icon="DocumentCopy" v-copyText="value" v-copyText:callback="copyTextSuccess" style="float:right">
|
<el-link v-copyText="value" v-copyText:callback="copyTextSuccess" :underline="false" icon="DocumentCopy" style="float: right">
|
||||||
复制
|
复制
|
||||||
</el-link>
|
</el-link>
|
||||||
<pre>{{ value }}</pre>
|
<pre>{{ value }}</pre>
|
||||||
@ -129,7 +129,7 @@ const single = ref(true);
|
|||||||
const multiple = ref(true);
|
const multiple = ref(true);
|
||||||
const total = ref(0);
|
const total = ref(0);
|
||||||
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
|
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
|
||||||
const uniqueId = ref("");
|
const uniqueId = ref('');
|
||||||
const dataNameList = ref<Array<string>>([]);
|
const dataNameList = ref<Array<string>>([]);
|
||||||
|
|
||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
@ -140,13 +140,13 @@ const queryParams = ref<TableQuery>({
|
|||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
tableName: '',
|
tableName: '',
|
||||||
tableComment: '',
|
tableComment: '',
|
||||||
dataName: ""
|
dataName: ''
|
||||||
})
|
});
|
||||||
|
|
||||||
const preview = ref<any>({
|
const preview = ref<any>({
|
||||||
data: {},
|
data: {},
|
||||||
activeName: 'domain.java'
|
activeName: 'domain.java'
|
||||||
})
|
});
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = reactive<DialogOption>({
|
||||||
visible: false,
|
visible: false,
|
||||||
title: '代码预览'
|
title: '代码预览'
|
||||||
@ -161,13 +161,13 @@ onActivated(() => {
|
|||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
getList();
|
getList();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
/** 查询多数据源名称 */
|
/** 查询多数据源名称 */
|
||||||
const getDataNameList = async () => {
|
const getDataNameList = async () => {
|
||||||
const res = await getDataNames()
|
const res = await getDataNames();
|
||||||
dataNameList.value = res.data;
|
dataNameList.value = res.data;
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 查询表集合 */
|
/** 查询表集合 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
@ -176,65 +176,65 @@ const getList = async () => {
|
|||||||
tableList.value = res.rows;
|
tableList.value = res.rows;
|
||||||
total.value = res.total;
|
total.value = res.total;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
};
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
/** 生成代码操作 */
|
/** 生成代码操作 */
|
||||||
const handleGenTable = async (row?: TableVO) => {
|
const handleGenTable = async (row?: TableVO) => {
|
||||||
const tbIds = row?.tableId || ids.value;
|
const tbIds = row?.tableId || ids.value;
|
||||||
if (tbIds == "") {
|
if (tbIds == '') {
|
||||||
proxy?.$modal.msgError('请选择要生成的数据');
|
proxy?.$modal.msgError('请选择要生成的数据');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (row?.genType === "1") {
|
if (row?.genType === '1') {
|
||||||
await genCode(row.tableId);
|
await genCode(row.tableId);
|
||||||
proxy?.$modal.msgSuccess('成功生成到自定义路径:' + row.genPath);
|
proxy?.$modal.msgSuccess('成功生成到自定义路径:' + row.genPath);
|
||||||
} else {
|
} else {
|
||||||
proxy?.$download.zip('/tool/gen/batchGenCode?tableIdStr=' + tbIds, 'ruoyi.zip');
|
proxy?.$download.zip('/tool/gen/batchGenCode?tableIdStr=' + tbIds, 'ruoyi.zip');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
/** 同步数据库操作 */
|
/** 同步数据库操作 */
|
||||||
const handleSynchDb = async (row: TableVO) => {
|
const handleSynchDb = async (row: TableVO) => {
|
||||||
const tableId = row.tableId;
|
const tableId = row.tableId;
|
||||||
await proxy?.$modal.confirm('确认要强制同步"' + row.tableName + '"表结构吗?');
|
await proxy?.$modal.confirm('确认要强制同步"' + row.tableName + '"表结构吗?');
|
||||||
await synchDb(tableId);
|
await synchDb(tableId);
|
||||||
proxy?.$modal.msgSuccess('同步成功');
|
proxy?.$modal.msgSuccess('同步成功');
|
||||||
}
|
};
|
||||||
/** 打开导入表弹窗 */
|
/** 打开导入表弹窗 */
|
||||||
const openImportTable = () => {
|
const openImportTable = () => {
|
||||||
importRef.value?.show(queryParams.value.dataName);
|
importRef.value?.show(queryParams.value.dataName);
|
||||||
}
|
};
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
dateRange.value = ['', ''];
|
dateRange.value = ['', ''];
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
handleQuery();
|
handleQuery();
|
||||||
}
|
};
|
||||||
/** 预览按钮 */
|
/** 预览按钮 */
|
||||||
const handlePreview = async (row: TableVO) => {
|
const handlePreview = async (row: TableVO) => {
|
||||||
const res = await previewTable(row.tableId);
|
const res = await previewTable(row.tableId);
|
||||||
preview.value.data = res.data;
|
preview.value.data = res.data;
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
preview.value.activeName = 'domain.java';
|
preview.value.activeName = 'domain.java';
|
||||||
}
|
};
|
||||||
/** 复制代码成功 */
|
/** 复制代码成功 */
|
||||||
const copyTextSuccess = () => {
|
const copyTextSuccess = () => {
|
||||||
proxy?.$modal.msgSuccess('复制成功');
|
proxy?.$modal.msgSuccess('复制成功');
|
||||||
}
|
};
|
||||||
// 多选框选中数据
|
// 多选框选中数据
|
||||||
const handleSelectionChange = (selection: TableVO[]) => {
|
const handleSelectionChange = (selection: TableVO[]) => {
|
||||||
ids.value = selection.map(item => item.tableId);
|
ids.value = selection.map((item) => item.tableId);
|
||||||
single.value = selection.length != 1;
|
single.value = selection.length != 1;
|
||||||
multiple.value = !selection.length;
|
multiple.value = !selection.length;
|
||||||
}
|
};
|
||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
const handleEditTable = (row?: TableVO) => {
|
const handleEditTable = (row?: TableVO) => {
|
||||||
const tableId = row?.tableId || ids.value[0];
|
const tableId = row?.tableId || ids.value[0];
|
||||||
router.push({ path: '/tool/gen-edit/index/' + tableId, query: { pageNum: queryParams.value.pageNum } });
|
router.push({ path: '/tool/gen-edit/index/' + tableId, query: { pageNum: queryParams.value.pageNum } });
|
||||||
}
|
};
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row?: TableVO) => {
|
const handleDelete = async (row?: TableVO) => {
|
||||||
const tableIds = row?.tableId || ids.value;
|
const tableIds = row?.tableId || ids.value;
|
||||||
@ -242,10 +242,10 @@ const handleDelete = async (row?: TableVO) => {
|
|||||||
await delTable(tableIds);
|
await delTable(tableIds);
|
||||||
await getList();
|
await getList();
|
||||||
proxy?.$modal.msgSuccess('删除成功');
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
}
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
getDataNameList();
|
getDataNameList();
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es2022",
|
"target": "esnext",
|
||||||
"useDefineForClassFields": true,
|
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
"useDefineForClassFields": true,
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
@ -21,6 +21,6 @@
|
|||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"forceConsistentCasingInFileNames": true
|
"forceConsistentCasingInFileNames": true
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts", "src/**/*.vue", "src/types/**/*.d.ts"],
|
"include": ["src/**/*.ts", "src/**/*.vue", "src/types/**/*.d.ts", "vite.config.ts"],
|
||||||
"exclude": ["node_modules", "dist", "**/*.js"]
|
"exclude": ["node_modules", "dist", "**/*.js", "**/*.md", "src/**/*.md"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user