!25 部分优化以及新增功能

Merge pull request !25 from ahaos/tspr
This commit is contained in:
疯狂的狮子Li
2023-07-11 13:03:01 +00:00
committed by Gitee
73 changed files with 3434 additions and 3021 deletions

View File

@ -1,5 +1,36 @@
{
"globals": {
"ComponentInternalInstance": true,
"TransferKey": true,
"ElFormRules": true,
"CheckboxValueType": true,
"PropType": true,
"DateModelType": true,
"UploadFile": true,
"ElFormInstance": true,
"ElTableInstance": true,
"ElTreeInstance": true,
"ElTreeSelectInstance": true,
"ElSelectInstance": true,
"ElUploadInstance": true,
"ElCardInstance": true,
"ElDialogInstance": true,
"ElInputInstance": true,
"ElInputNumberInstance": true,
"ElRadioInstance": true,
"ElRadioGroupInstance": true,
"ElRadioButtonInstance": true,
"ElCheckboxInstance": true,
"ElCheckboxGroupInstance": true,
"ElSwitchInstance": true,
"ElDatePickerInstance": true,
"ElTimePickerInstance": true,
"ElTimeSelectInstance": true,
"ElScrollbarInstance": true,
"ElCascaderInstance": true,
"ElColorPickerInstance": true,
"ElRateInstance": true,
"ElSliderInstance": true,
"useRouter": true,
"useRoute": true,
"EffectScope": true,

View File

@ -29,7 +29,8 @@ module.exports = {
// 关闭空类型检查 {}
extendDefaults: true,
types: {
'{}': false
'{}': false,
'Function': false
}
}
]

View File

@ -35,10 +35,12 @@
"path-to-regexp": "6.2.0",
"pinia": "2.0.22",
"screenfull": "6.0.0",
"vform3-builds": "3.0.8",
"vue": "3.2.45",
"vue-cropper": "1.0.3",
"vue-i18n": "9.2.2",
"vue-router": "4.1.4"
"vue-router": "4.1.4",
"vue-types": "^5.0.3"
},
"devDependencies": {
"@iconify/json": "^2.2.40",
@ -71,11 +73,11 @@
"unplugin-auto-import": "0.13.0",
"unplugin-icons": "0.15.1",
"unplugin-vue-components": "0.23.0",
"vite": "4.3.1",
"vite-plugin-compression": "0.5.1",
"vite-plugin-svg-icons": "2.0.1",
"vite-plugin-vue-setup-extend": "^0.4.0",
"vitest": "^0.29.7",
"vite": "4.3.1",
"vue-eslint-parser": "9.1.0",
"vue-tsc": "0.35.0"
}

View File

@ -9,64 +9,64 @@ import { parseStrEmpty } from '@/utils/ruoyi';
* 查询用户列表
* @param query
*/
export function listUser(query: UserQuery): AxiosPromise<UserVO[]> {
export const listUser = (query: UserQuery): AxiosPromise<UserVO[]> => {
return request({
url: '/system/user/list',
method: 'get',
params: query
});
}
};
/**
* 获取用户详情
* @param userId
*/
export function getUser(userId?: string | number): AxiosPromise<UserInfoVO> {
export const getUser = (userId?: string | number): AxiosPromise<UserInfoVO> => {
return request({
url: '/system/user/' + parseStrEmpty(userId),
method: 'get'
});
}
};
/**
* 新增用户
*/
export function addUser(data: UserForm) {
export const addUser = (data: UserForm) => {
return request({
url: '/system/user',
method: 'post',
data: data
});
}
};
/**
* 修改用户
*/
export function updateUser(data: UserForm) {
export const updateUser = (data: UserForm) => {
return request({
url: '/system/user',
method: 'put',
data: data
});
}
};
/**
* 删除用户
* @param userId 用户ID
*/
export function delUser(userId: Array<string | number> | string | number) {
export const delUser = (userId: Array<string | number> | string | number) => {
return request({
url: '/system/user/' + userId,
method: 'delete'
});
}
};
/**
* 用户密码重置
* @param userId 用户ID
* @param password 密码
*/
export function resetUserPwd(userId: string | number, password: string) {
export const resetUserPwd = (userId: string | number, password: string) => {
const data = {
userId,
password
@ -76,14 +76,14 @@ export function resetUserPwd(userId: string | number, password: string) {
method: 'put',
data: data
});
}
};
/**
* 用户状态修改
* @param userId 用户ID
* @param status 用户状态
*/
export function changeUserStatus(userId: number | string, status: string) {
export const changeUserStatus = (userId: number | string, status: string) => {
const data = {
userId,
status
@ -93,36 +93,36 @@ export function changeUserStatus(userId: number | string, status: string) {
method: 'put',
data: data
});
}
};
/**
* 查询用户个人信息
*/
export function getUserProfile(): AxiosPromise<UserInfoVO> {
export const getUserProfile = (): AxiosPromise<UserInfoVO> => {
return request({
url: '/system/user/profile',
method: 'get'
});
}
};
/**
* 修改用户个人信息
* @param data 用户信息
*/
export function updateUserProfile(data: UserForm) {
export const updateUserProfile = (data: UserForm) => {
return request({
url: '/system/user/profile',
method: 'put',
data: data
});
}
};
/**
* 用户密码重置
* @param oldPassword 旧密码
* @param newPassword 新密码
*/
export function updateUserPwd(oldPassword: string, newPassword: string) {
export const updateUserPwd = (oldPassword: string, newPassword: string) => {
const data = {
oldPassword,
newPassword
@ -132,49 +132,66 @@ export function updateUserPwd(oldPassword: string, newPassword: string) {
method: 'put',
params: data
});
}
};
/**
* 用户头像上传
* @param data 头像文件
*/
export function uploadAvatar(data: FormData) {
export const uploadAvatar = (data: FormData) => {
return request({
url: '/system/user/profile/avatar',
method: 'post',
data: data
});
}
};
/**
* 查询授权角色
* @param userId 用户ID
*/
export function getAuthRole(userId: string | number): AxiosPromise<{ user: UserVO; roles: RoleVO[] }> {
export const getAuthRole = (userId: string | number): AxiosPromise<{ user: UserVO; roles: RoleVO[] }> => {
return request({
url: '/system/user/authRole/' + userId,
method: 'get'
});
}
};
/**
* 保存授权角色
* @param data 用户ID
*/
export function updateAuthRole(data: { userId: string; roleIds: string }) {
export const updateAuthRole = (data: { userId: string; roleIds: string }) => {
return request({
url: '/system/user/authRole',
method: 'put',
params: data
});
}
};
/**
* 查询部门下拉树结构
*/
export function deptTreeSelect(): AxiosPromise<DeptVO[]> {
export const deptTreeSelect = (): AxiosPromise<DeptVO[]> => {
return request({
url: '/system/user/deptTree',
method: 'get'
});
}
};
export default {
listUser,
getUser,
addUser,
updateUser,
delUser,
resetUserPwd,
changeUserStatus,
getUserProfile,
updateUserProfile,
updateUserPwd,
uploadAvatar,
getAuthRole,
updateAuthRole,
deptTreeSelect
};

View File

@ -26,6 +26,10 @@ html {
box-sizing: border-box;
}
html.dark .svg-icon, html.dark svg {
fill: var(--el-text-color-regular);
}
#app {
height: 100%;
}
@ -137,6 +141,7 @@ aside {
border: 1px solid var(--el-border-color-light);
background-color: var(--el-bg-color-overlay);
padding: 0.75rem;
transition: all ease 0.3s;
&:hover {
box-shadow: 0 2px 12px #0000001a;
@ -199,4 +204,4 @@ aside {
vertical-align: middle;
margin-bottom: 10px;
}
}
}

View File

@ -90,8 +90,8 @@ h6 {
.el-table__fixed-header-wrapper {
th {
word-break: break-word;
background-color: #f8f8f9 !important;
color: #515a6e;
background-color: $table-header-bg !important;
color: $table-header-text-color;
height: 40px !important;
font-size: 13px;
}

View File

@ -84,7 +84,7 @@
.sub-menu-title-noDropdown,
.el-sub-menu__title {
&:hover {
background-color: rgba(0, 0, 0, 0.06) !important;
background-color: $base-sub-menu-title-hover !important;
}
}
@ -211,7 +211,7 @@
.el-menu-item {
&:hover {
// you can use $sub-menuHover
background-color: rgba(0, 0, 0, 0.06) !important;
background-color: $base-menu-hover !important;
}
}

View File

@ -1,3 +1,38 @@
// 全局SCSS变量
:root {
--menuBg: #304156;
--menuColor: #bfcbd9;
--menuActiveText: #f4f4f5;
--menuHover: #263445;
--subMenuBg: #1f2d3d;
--subMenuActiveText: #f4f4f5;
--subMenuHover: #001528;
--subMenuTitleHover: #293444;
--tableHeaderBg: #f8f8f9;
--tableHeaderTextColor: #515a6e;
}
html.dark {
--menuBg: #1d1e1f;
--menuColor: #bfcbd9;
--menuActiveText: #f4f4f5;
--menuHover: #171819;
--subMenuBg: #1d1e1f;
--subMenuActiveText: #1d1e1f;
--subMenuHover: #171819;
--subMenuTitleHover: #171819;
--tableHeaderBg: var(--el-bg-color);
--tableHeaderTextColor: var(--el-text-color);
// 覆盖ele 高亮当前行的标准暗色
.el-tree-node__content {
--el-color-primary-light-9: #262727;
}
}
// base color
$blue: #324157;
$light-blue: #3a71a8;
@ -9,32 +44,22 @@ $yellow: #fec171;
$panGreen: #30b08f;
// 默认菜单主题风格
$base-menu-color: #bfcbd9;
$base-menu-color-active: #f4f4f5;
$base-menu-background: #304156;
$base-menu-color: var(--menuColor);
$base-menu-hover: var(--menuHover);
$base-menu-color-active: var(--menuActiveText);
$base-menu-background: var(--menuBg);
$base-logo-title-color: #ffffff;
$base-menu-light-color: rgba(0, 0, 0, 0.7);
$base-menu-light-background: #ffffff;
$base-logo-light-title-color: #001529;
$base-sub-menu-background: #1f2d3d;
$base-sub-menu-hover: #001528;
// 自定义暗色菜单风格
/**
$base-menu-color:hsla(0,0%,100%,.65);
$base-menu-color-active:#fff;
$base-menu-background:#001529;
$base-logo-title-color: #ffffff;
$base-menu-light-color:rgba(0,0,0,.70);
$base-menu-light-background:#ffffff;
$base-logo-light-title-color: #001529;
$base-sub-menu-background:#000c17;
$base-sub-menu-hover:#001528;
*/
$base-sub-menu-background: var(--subMenuBg);
$base-sub-menu-hover: var(--subMenuHover);
$base-sub-menu-title-hover: var(--subMenuTitleHover);
// 表单头背景色和标题颜色
$table-header-bg: var(--tableHeaderBg);
$table-header-text-color: var(--tableHeaderTextColor);
$--color-primary: #409eff;
$--color-success: #67c23a;

View File

@ -18,34 +18,34 @@ const router = useRouter();
const levelList = ref<RouteLocationMatched[]>([])
const getBreadcrumb = () => {
// only show routes with meta.title
let matched = route.matched.filter(item => item.meta && item.meta.title);
const first = matched[0]
// 判断是否为首页
if (!isDashboard(first)) {
matched = ([{ path: '/index', meta: { title: '首页' } }] as any).concat(matched)
}
levelList.value = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
// only show routes with meta.title
let matched = route.matched.filter(item => item.meta && item.meta.title);
const first = matched[0]
// 判断是否为首页
if (!isDashboard(first)) {
matched = ([{ path: '/index', meta: { title: '首页' } }] as any).concat(matched)
}
levelList.value = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
}
const isDashboard = (route: RouteLocationMatched) => {
const name = route && route.name as string
if (!name) {
return false
}
return name.trim() === 'Index'
const name = route && route.name as string
if (!name) {
return false
}
return name.trim() === 'Index'
}
const handleLink = (item: RouteLocationMatched) => {
const { redirect, path } = item
redirect ? router.push(redirect as string) : router.push(path)
const { redirect, path } = item
redirect ? router.push(redirect as string) : router.push(path)
}
watchEffect(() => {
// if you go to the redirect page, do not update the breadcrumbs
if (route.path.startsWith('/redirect/')) return
getBreadcrumb()
// if you go to the redirect page, do not update the breadcrumbs
if (route.path.startsWith('/redirect/')) return
getBreadcrumb()
})
onMounted(() => {
getBreadcrumb();
getBreadcrumb();
})
</script>

View File

@ -0,0 +1,64 @@
<!-- 代码构建 -->
<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>
<div>
<v-form-designer
class="build"
ref="buildRef"
:designer-config="{ importJsonButton: true, exportJsonButton: true, exportCodeButton: true, generateSFCButton: true, formTemplates: true }"
>
<template #customToolButtons v-if="showBtn">
<el-button link type="primary" icon="Select" @click="getJson">保存</el-button>
</template>
</v-form-designer>
</div>
</template>
<style lang="scss">
.build {
margin: 0 !important;
overflow-y: auto !important;
& header.main-header {
display: none;
}
& .right-toolbar-con {
text-align: right !important;
}
}
</style>

View File

@ -0,0 +1,62 @@
<!-- 动态表单渲染 -->
<script setup name="Render">
const props = defineProps({
formJson: {
type: [String, Object],
default: {}
},
formData: {
type: [String, Object],
default: {}
},
isView: {
type: Boolean,
default: false
}
})
const vFormRef = ref(null)
// 获取表单数据-异步
const getFormData = () => {
return vFormRef.value.getFormData()
}
/**
* 设置表单内容
* @param {表单配置} formConf
* formConfig{ formTemplate表单模板formData表单数据hiddenField需要隐藏的字段字符串集合disabledField需要禁用的自读字符串集合}
*/
const initForm = (formConf) => {
const { formTemplate, formData, hiddenField, disabledField } = toRaw(formConf)
if (formTemplate) {
vFormRef.value.setFormJson(formTemplate)
if (formData) {
vFormRef.value.setFormData(formData)
}
if (disabledField && disabledField.length > 0) {
setTimeout(() => {
vFormRef.value.disableWidgets(disabledField)
}, 200)
}
if (hiddenField && hiddenField.length > 0) {
setTimeout(() => {
vFormRef.value.hideWidgets(hiddenField)
}, 200)
}
if (props.isView) {
console.log(props.isView)
setTimeout(() => {
vFormRef.value.disableForm()
}, 100)
}
}
}
defineExpose({ getFormData, initForm })
</script>
<template>
<div class="">
<v-form-render ref="vFormRef" :form-json="formJson" :form-data="formData" />
</div>
</template>

View File

@ -24,7 +24,7 @@
</template>
<script setup lang="ts">
import { PropType } from 'vue';
import { propTypes } from '@/utils/propTypes';
const props = defineProps({
@ -36,10 +36,7 @@ const props = defineProps({
// 当前的值
value: [Number, String, Array] as PropType<number | string | Array<number | string>>,
// 当未找到匹配的数据时显示value
showValue: {
type: Boolean as PropType<boolean>,
default: true,
},
showValue: propTypes.bool.def(true),
});
const values = computed(() => {

View File

@ -30,152 +30,139 @@
import { QuillEditor, Quill } from '@vueup/vue-quill';
import '@vueup/vue-quill/dist/vue-quill.snow.css';
import { getToken } from "@/utils/auth";
import { ComponentInternalInstance } from "vue";
import { propTypes } from '@/utils/propTypes';
const props = defineProps({
/* 编辑器的内容 */
modelValue: {
type: String,
},
/* 高度 */
height: {
type: Number,
default: null,
},
/* 最小高度 */
minHeight: {
type: Number,
default: null,
},
/* 只读 */
readOnly: {
type: Boolean,
default: false,
},
/* 上传文件大小限制(MB) */
fileSize: {
type: Number,
default: 5,
},
/* 类型base64格式、url格式 */
type: {
type: String,
default: "url",
}
/* 编辑器的内容 */
modelValue: propTypes.string,
/* 高度 */
height: propTypes.number.def(400),
/* 最小高度 */
minHeight: propTypes.number.def(400),
/* 只读 */
readOnly: propTypes.bool.def(false),
/* 上传文件大小限制(MB) */
fileSize: propTypes.number.def(5),
/* 类型base64格式、url格式 */
type: propTypes.string.def('url')
});
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const upload = reactive<UploadOption>({
headers: { Authorization: "Bearer " + getToken() },
url: import.meta.env.VITE_APP_BASE_API + '/resource/oss/upload'
headers: { Authorization: "Bearer " + getToken() },
url: import.meta.env.VITE_APP_BASE_API + '/resource/oss/upload'
})
const myQuillEditor = ref();
const options = ref({
theme: "snow",
bounds: document.body,
debug: "warn",
modules: {
// 工具栏配置
toolbar: {
container: [
["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线
["blockquote", "code-block"], // 引用 代码块
[{ list: "ordered" }, { list: "bullet"} ], // 有序、无序列表
[{ indent: "-1" }, { indent: "+1" }], // 缩进
[{ size: ["small", false, "large", "huge"] }], // 字体大小
[{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
[{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
[{ align: [] }], // 对齐方式
["clean"], // 清除文本格式
["link", "image", "video"] // 链接、图片、视频
],
handlers: {
image: function (value: any) {
if (value) {
// 调用element图片上传
(document.querySelector(".editor-img-uploader>.el-upload") as HTMLDivElement)?.click();
} else {
Quill.format("image", true);
}
},
},
}
},
placeholder: '请输入内容',
readOnly: props.readOnly,
theme: "snow",
bounds: document.body,
debug: "warn",
modules: {
// 工具栏配置
toolbar: {
container: [
["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线
["blockquote", "code-block"], // 引用 代码块
[{ list: "ordered" }, { list: "bullet" }], // 有序、无序列表
[{ indent: "-1" }, { indent: "+1" }], // 缩进
[{ size: ["small", false, "large", "huge"] }], // 字体大小
[{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
[{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
[{ align: [] }], // 对齐方式
["clean"], // 清除文本格式
["link", "image", "video"] // 链接、图片、视频
],
handlers: {
image: function (value: any) {
if (value) {
// 调用element图片上传
(document.querySelector(".editor-img-uploader>.el-upload") as HTMLDivElement)?.click();
} else {
Quill.format("image", true);
}
},
},
}
},
placeholder: '请输入内容',
readOnly: props.readOnly,
});
const styles = computed(() => {
let style: any = {};
if (props.minHeight) {
style.minHeight = `${props.minHeight}px`;
}
if (props.height) {
style.height = `${props.height}px`;
}
return style;
let style: any = {};
if (props.minHeight) {
style.minHeight = `${props.minHeight}px`;
}
if (props.height) {
style.height = `${props.height}px`;
}
return style;
})
const content = ref("");
watch(() => props.modelValue, (v) => {
if (v !== content.value) {
content.value = v === undefined ? "<p></p>" : v;
}
if (v !== content.value) {
content.value = v === undefined ? "<p></p>" : v;
}
}, { immediate: true });
// 图片上传成功返回图片地址
const handleUploadSuccess = (res: any) => {
// 获取富文本实例
let quill = toRaw(myQuillEditor.value).getQuill();
// 如果上传成功
if (res.code === 200) {
// 获取光标位置
let length = quill.selection.savedRange.index;
// 插入图片res为服务器返回的图片链接地址
quill.insertEmbed(length, "image", res.data.url);
// 调整光标到最后
quill.setSelection(length + 1);
proxy?.$modal.closeLoading();
} else {
proxy?.$modal.loading(res.msg);
proxy?.$modal.closeLoading();
}
// 获取富文本实例
let quill = toRaw(myQuillEditor.value).getQuill();
// 如果上传成功
if (res.code === 200) {
// 获取光标位置
let length = quill.selection.savedRange.index;
// 插入图片res为服务器返回的图片链接地址
quill.insertEmbed(length, "image", res.data.url);
// 调整光标到最后
quill.setSelection(length + 1);
proxy?.$modal.closeLoading();
} else {
proxy?.$modal.loading(res.msg);
proxy?.$modal.closeLoading();
}
}
// 图片上传前拦截
const handleBeforeUpload = (file: any) => {
// 校检文件大小
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;
if (!isLt) {
proxy?.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
return false;
}
proxy?.$modal.loading('正在上传文件,请稍候...');
return true;
}
proxy?.$modal.loading('正在上传文件,请稍候...');
return true;
}
// 图片失败拦截
const handleUploadError = (err: any) => {
console.error(err);
proxy?.$modal.msgError('上传文件失败');
console.error(err);
proxy?.$modal.msgError('上传文件失败');
}
</script>
<style>
.editor, .ql-toolbar {
.editor,
.ql-toolbar {
white-space: pre-wrap !important;
line-height: normal !important;
}
.quill-img {
display: none;
}
.ql-snow .ql-tooltip[data-mode="link"]::before {
content: "请输入链接地址:";
}
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
border-right: 0;
content: "保存";
@ -190,14 +177,17 @@ const handleUploadError = (err: any) => {
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
content: "14px";
}
.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 {
content: "10px";
}
.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 {
content: "18px";
}
.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 {
content: "32px";
@ -207,26 +197,32 @@ const handleUploadError = (err: any) => {
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
content: "文本";
}
.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 {
content: "标题1";
}
.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 {
content: "标题2";
}
.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 {
content: "标题3";
}
.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 {
content: "标题4";
}
.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 {
content: "标题5";
}
.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 {
content: "标题6";
@ -236,10 +232,12 @@ const handleUploadError = (err: any) => {
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
content: "标准字体";
}
.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 {
content: "衬线字体";
}
.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 {
content: "等宽字体";

View File

@ -45,31 +45,18 @@
<script setup lang="ts">
import { getToken } from "@/utils/auth";
import { listByIds, delOss } from "@/api/system/oss";
import { ComponentInternalInstance } from "vue";
import { ElUpload, UploadFile } from "element-plus";
import { propTypes } from '@/utils/propTypes';
const props = defineProps({
modelValue: [String, Object, Array],
// 数量限制
limit: {
type: Number,
default: 5,
},
limit: propTypes.number.def(5),
// 大小限制(MB)
fileSize: {
type: Number,
default: 5,
},
fileSize: propTypes.number.def(5),
// 文件类型, 例如['png', 'jpg', 'jpeg']
fileType: {
type: Array,
default: () => ["doc", "xls", "ppt", "txt", "pdf"],
},
fileType: propTypes.array.def(["doc", "xls", "ppt", "txt", "pdf"]),
// 是否显示提示
isShowTip: {
type: Boolean,
default: true
}
isShowTip: propTypes.bool.def(true),
});
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -86,7 +73,7 @@ const showTip = computed(
() => props.isShowTip && (props.fileType || props.fileSize)
);
const fileUploadRef = ref(ElUpload);
const fileUploadRef = ref<ElUploadInstance>();
watch(() => props.modelValue, async val => {
if (val) {
@ -96,7 +83,7 @@ watch(() => props.modelValue, async val => {
if (Array.isArray(val)) {
list = val;
} else {
const res = await listByIds(val as string)
const res = await listByIds(val as string)
list = res.data.map((oss) => {
const data = { name: oss.originalName, url: oss.url, ossId: oss.ossId };
return data;
@ -104,7 +91,7 @@ watch(() => props.modelValue, async val => {
}
// 然后将数组转为对象数组
fileList.value = list.map(item => {
item = {name: item.name, url: item.url, ossId: item.ossId};
item = { name: item.name, url: item.url, ossId: item.ossId };
item.uid = item.uid || new Date().getTime() + temp++;
return item;
});
@ -112,7 +99,7 @@ watch(() => props.modelValue, async val => {
fileList.value = [];
return [];
}
},{ deep: true, immediate: true });
}, { deep: true, immediate: true });
// 上传前校检格式和大小
const handleBeforeUpload = (file: any) => {
@ -150,7 +137,7 @@ const handleUploadError = () => {
}
// 上传成功回调
const handleUploadSuccess = (res:any, file: UploadFile) => {
const handleUploadSuccess = (res: any, file: UploadFile) => {
if (res.code === 200) {
uploadList.value.push({ name: res.data.fileName, url: res.data.url, ossId: res.data.ossId });
uploadedSuccessfully();
@ -158,7 +145,7 @@ const handleUploadSuccess = (res:any, file: UploadFile) => {
number.value--;
proxy?.$modal.closeLoading();
proxy?.$modal.msgError(res.msg);
fileUploadRef.value.handleRemove(file);
fileUploadRef.value?.handleRemove(file);
uploadedSuccessfully();
}
}
@ -172,7 +159,7 @@ const handleDelete = (index: number) => {
}
// 上传结束处理
const uploadedSuccessfully =() => {
const uploadedSuccessfully = () => {
if (number.value > 0 && uploadList.value.length === number.value) {
fileList.value = fileList.value.filter(f => f.url !== undefined).concat(uploadList.value);
uploadList.value = [];
@ -207,21 +194,24 @@ const listToString = (list: any[], separator?: string) => {
<style scoped lang="scss">
.upload-file-uploader {
margin-bottom: 5px;
margin-bottom: 5px;
}
.upload-file-list .el-upload-list__item {
border: 1px solid #e4e7ed;
line-height: 2;
margin-bottom: 10px;
position: relative;
border: 1px solid #e4e7ed;
line-height: 2;
margin-bottom: 10px;
position: relative;
}
.upload-file-list .ele-upload-list__item-content {
display: flex;
justify-content: space-between;
align-items: center;
color: inherit;
display: flex;
justify-content: space-between;
align-items: center;
color: inherit;
}
.ele-upload-list__item-content-action .el-link {
margin-right: 10px;
margin-right: 10px;
}
</style>

View File

@ -1,6 +1,6 @@
<template>
<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
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"
/>
@ -9,16 +9,15 @@
</template>
<script setup lang="ts">
import { propTypes } from '@/utils/propTypes';
defineProps({
isActive: {
type: Boolean,
default: false
}
isActive: propTypes.bool.def(false)
})
const emit = defineEmits(['toggleClick'])
const toggleClick = () => {
emit('toggleClick');
emit('toggleClick');
}
</script>

View File

@ -17,12 +17,12 @@
</div>
</template>
<script setup lang="ts">
import Fuse from 'fuse.js'
import { getNormalPath } from '@/utils/ruoyi'
import { isHttp } from '@/utils/validate'
import usePermissionStore from '@/store/modules/permission'
import { RouteOption } from 'vue-router'
<script setup lang="ts" name="HeaderSearch">
import Fuse from 'fuse.js';
import { getNormalPath } from '@/utils/ruoyi';
import { isHttp } from '@/utils/validate';
import usePermissionStore from '@/store/modules/permission';
import { RouteOption } from 'vue-router';
type Router = Array<{
path: string;
@ -34,7 +34,7 @@ const options = ref<any>([]);
const searchPool = ref<Router>([]);
const show = ref(false);
const fuse = ref();
const headerSearchSelectRef = ref(ElSelect);
const headerSearchSelectRef = ref<ElSelectInstance>();
const router = useRouter();
const routes = computed(() => usePermissionStore().routes);
@ -123,9 +123,9 @@ onMounted(() => {
searchPool.value = generateRoutes(routes.value);
})
watchEffect(() => {
searchPool.value = generateRoutes(routes.value)
})
// watchEffect(() => {
// searchPool.value = generateRoutes(routes.value)
// })
watch(show, (value) => {
if (value) {
@ -142,40 +142,40 @@ watch(searchPool, (list) => {
<style lang="scss" scoped>
.header-search {
font-size: 0 !important;
font-size: 0 !important;
.search-icon {
cursor: pointer;
font-size: 18px;
vertical-align: middle;
}
.header-search-select {
font-size: 18px;
transition: width 0.2s;
width: 0;
overflow: hidden;
background: transparent;
border-radius: 0;
display: inline-block;
vertical-align: middle;
:deep(.el-input__inner) {
border-radius: 0;
border: 0;
padding-left: 0;
padding-right: 0;
box-shadow: none !important;
border-bottom: 1px solid #d9d9d9;
vertical-align: middle;
.search-icon {
cursor: pointer;
font-size: 18px;
vertical-align: middle;
}
}
&.show {
.header-search-select {
width: 210px;
margin-left: 10px;
font-size: 18px;
transition: width 0.2s;
width: 0;
overflow: hidden;
background: transparent;
border-radius: 0;
display: inline-block;
vertical-align: middle;
:deep(.el-input__inner) {
border-radius: 0;
border: 0;
padding-left: 0;
padding-right: 0;
box-shadow: none !important;
border-bottom: 1px solid #d9d9d9;
vertical-align: middle;
}
}
&.show {
.header-search-select {
width: 210px;
margin-left: 10px;
}
}
}
}
</style>

View File

@ -31,17 +31,11 @@
<script setup lang="ts">
import icons from '@/components/IconSelect/requireIcons';
import { propTypes } from '@/utils/propTypes';
const props = defineProps({
modelValue: {
type: String,
require: true
},
width: {
type: String,
require: false,
default: '400px'
}
modelValue: propTypes.string.isRequired,
width: propTypes.string.def('400px')
});
const emit = defineEmits(['update:modelValue']);

View File

@ -9,47 +9,46 @@
</template>
<script setup lang="ts">
import { propTypes } from '@/utils/propTypes';
const props = defineProps({
src: {
type: String,
default: ""
},
width: {
type: [Number, String],
default: ""
},
height: {
type: [Number, String],
default: ""
}
src: propTypes.string.def(''),
width: {
type: [Number, String],
default: ""
},
height: {
type: [Number, String],
default: ""
}
});
const realSrc = computed(() => {
if (!props.src) {
return;
}
let real_src = props.src.split(",")[0];
return real_src;
if (!props.src) {
return;
}
let real_src = props.src.split(",")[0];
return real_src;
});
const realSrcList = computed(() => {
if (!props.src) {
return;
}
let real_src_list = props.src.split(",");
let srcList:string[] = [];
real_src_list.forEach(item => {
return srcList.push(item);
});
return srcList;
if (!props.src) {
return;
}
let real_src_list = props.src.split(",");
let srcList: string[] = [];
real_src_list.forEach(item => {
return srcList.push(item);
});
return srcList;
});
const realWidth = computed(() =>
typeof props.width == "string" ? props.width : `${props.width}px`
typeof props.width == "string" ? props.width : `${props.width}px`
);
const realHeight = computed(() =>
typeof props.height == "string" ? props.height : `${props.height}px`
typeof props.height == "string" ? props.height : `${props.height}px`
);
</script>
@ -58,13 +57,16 @@ const realHeight = computed(() =>
border-radius: 5px;
background-color: #ebeef5;
box-shadow: 0 0 5px 1px #ccc;
:deep(.el-image__inner) {
transition: all 0.3s;
cursor: pointer;
&:hover {
transform: scale(1.2);
}
}
:deep(.image-slot) {
display: flex;
justify-content: center;

View File

@ -17,7 +17,9 @@
:on-preview="handlePictureCardPreview"
:class="{ hide: fileList.length >= limit }"
>
<el-icon class="avatar-uploader-icon"><plus /></el-icon>
<el-icon class="avatar-uploader-icon">
<plus />
</el-icon>
</el-upload>
<!-- 上传提示 -->
<div class="el-upload__tip" v-if="showTip">
@ -42,25 +44,16 @@ import { getToken } from "@/utils/auth";
import { listByIds, delOss } from "@/api/system/oss";
import { ComponentInternalInstance, PropType } from "vue";
import { OssVO } from "@/api/system/oss/types";
import { ElUpload, UploadFile } from "element-plus";
import { propTypes } from '@/utils/propTypes';
const props = defineProps({
modelValue: [String, Object, Array],
// 图片数量限制
limit: {
type: Number,
default: 5,
},
limit: propTypes.number.def(5),
// 大小限制(MB)
fileSize: {
type: Number,
default: 5,
},
fileSize: propTypes.number.def(5),
// 文件类型, 例如['png', 'jpg', 'jpeg']
fileType: {
type: Array as PropType<string[]>,
default: () => ["png", "jpg", "jpeg"],
},
fileType: propTypes.array.def(["png", "jpg", "jpeg"]),
// 是否显示提示
isShowTip: {
type: Boolean,
@ -84,12 +77,12 @@ const showTip = computed(
() => props.isShowTip && (props.fileType || props.fileSize)
);
const imageUploadRef = ref(ElUpload);
const imageUploadRef = ref<ElUploadInstance>();
watch(() => props.modelValue, async val => {
if (val) {
// 首先将值转为数组
let list:OssVO[] = [];
let list: OssVO[] = [];
if (Array.isArray(val)) {
list = val as OssVO[];
} else {
@ -112,7 +105,7 @@ watch(() => props.modelValue, async val => {
fileList.value = [];
return [];
}
},{ deep: true, immediate: true });
}, { deep: true, immediate: true });
/** 上传前loading加载 */
const handleBeforeUpload = (file: any) => {
@ -122,7 +115,7 @@ const handleBeforeUpload = (file: any) => {
if (file.name.lastIndexOf(".") > -1) {
fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
}
isImg = props.fileType.some((type) => {
isImg = props.fileType.some((type: any) => {
if (file.type.indexOf(type) > -1) return true;
if (fileExtension && fileExtension.indexOf(type) > -1) return true;
return false;
@ -161,7 +154,7 @@ const handleUploadSuccess = (res: any, file: UploadFile) => {
number.value--;
proxy?.$modal.closeLoading();
proxy?.$modal.msgError(res.msg);
imageUploadRef.value.handleRemove(file);
imageUploadRef.value?.handleRemove(file);
uploadedSuccessfully();
}
}
@ -207,7 +200,7 @@ const listToString = (list: any[], separator?: string) => {
let strs = "";
separator = separator || ",";
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;
}
}

View File

@ -22,52 +22,23 @@ export default {
<script setup lang="ts">
import { scrollTo } from '@/utils/scroll-to'
import { PropType } from "vue";
import { propTypes } from "@/utils/propTypes";
const props = defineProps({
total: {
required: true,
type: Number
},
page: {
type: Number,
default: 1
},
limit: {
type: Number,
default: 20
},
total: propTypes.number,
page: propTypes.number.def(1),
limit: propTypes.number.def(20),
pageSizes: {
type: Array as PropType<number[]>,
default() {
return [10, 20, 30, 50]
}
type: Array as PropType<number[]>,
default: () => [10, 20, 30, 50]
},
// 移动端页码按钮的数量端默认值5
pagerCount: {
type: Number,
default: document.body.clientWidth < 992 ? 5 : 7
},
layout: {
type: String,
default: 'total, sizes, prev, pager, next, jumper'
},
background: {
type: Boolean,
default: true
},
autoScroll: {
type: Boolean,
default: true
},
hidden: {
type: Boolean,
default: false
},
float: {
type: String,
default: 'right'
}
pagerCount: propTypes.number.def(document.body.clientWidth < 992 ? 5 : 7),
layout: propTypes.string.def('total, sizes, prev, pager, next, jumper'),
background: propTypes.bool.def(true),
autoScroll: propTypes.bool.def(true),
hidden: propTypes.bool.def(false),
float: propTypes.string.def('right')
})
const emit = defineEmits(['update:page', 'update:limit', 'pagination']);
@ -106,7 +77,6 @@ function handleCurrentChange(val: number) {
<style lang="scss" scoped>
.pagination-container {
background: #fff;
padding: 32px 16px;
.el-pagination{
float: v-bind(float);

View File

@ -18,25 +18,15 @@
</template>
<script setup lang="ts">
import { TransferKey } from "element-plus";
import { PropType } from "vue";
import { propTypes } from '@/utils/propTypes';
const props = defineProps({
showSearch: {
type: Boolean,
default: true,
},
showSearch: propTypes.bool.def(true),
columns: {
type: Array as PropType<FieldOption[]>,
},
search: {
type: Boolean,
default: true,
},
gutter: {
type: Number,
default: 10,
},
search: propTypes.bool.def(true),
gutter: propTypes.number.def(10),
})
const emits = defineEmits(['update:showSearch', 'queryTable']);

View File

@ -5,19 +5,12 @@
</template>
<script setup lang="ts">
import { propTypes } from '@/utils/propTypes';
const props = defineProps({
iconClass: {
type: String,
required: true
},
className: {
type: String,
default: ''
},
color: {
type: String,
default: ''
},
iconClass: propTypes.string.isRequired,
className: propTypes.string.def(''),
color: propTypes.string.def(''),
})
const iconName = computed(() => `#icon-${props.iconClass}`);
const svgClass = computed(() => {

View File

@ -29,94 +29,93 @@
</template>
<script setup lang="ts">
import { ElTreeSelect } from 'element-plus'
const props = defineProps({
/* 配置项 */
objMap: {
type: Object,
default: () => {
return {
value: 'id', // ID字段名
label: 'label', // 显示名称
children: 'children' // 子级字段名
type: Object,
default: () => {
return {
value: 'id', // ID字段名
label: 'label', // 显示名称
children: 'children' // 子级字段名
}
}
}
},
/* 自动收起 */
accordion: {
type: Boolean,
default: () => {
return false
}
type: Boolean,
default: () => {
return false
}
},
/**当前双向数据绑定的值 */
value: {
type: [String, Number],
default: ''
type: [String, Number],
default: ''
},
/**当前的数据 */
options: {
type: Array,
default: () => []
type: Array,
default: () => []
},
/**输入框内部的文字 */
placeholder: {
type: String,
default: ''
type: String,
default: ''
}
})
const selectTree = ref(ElTreeSelect);
const selectTree = ref<ElTreeSelectInstance>();
const emit = defineEmits(['update:value']);
const valueId = computed({
get: () => props.value,
set: (val) => {
emit('update:value', val)
emit('update:value', val)
}
});
const valueTitle = ref('');
const defaultExpandedKey = ref<any[]>([]);
function initHandle() {
const initHandle = () => {
nextTick(() => {
const selectedValue = valueId.value;
if(selectedValue !== null && typeof (selectedValue) !== 'undefined') {
const node = selectTree.value.getNode(selectedValue)
if (node) {
valueTitle.value = node.data[props.objMap.label]
selectTree.value.setCurrentKey(selectedValue) // 设置默认选中
defaultExpandedKey.value = [selectedValue] // 设置默认展开
const selectedValue = valueId.value;
if (selectedValue !== null && typeof (selectedValue) !== 'undefined') {
const node = selectTree.value?.getNode(selectedValue)
if (node) {
valueTitle.value = node.data[props.objMap.label]
selectTree.value?.setCurrentKey(selectedValue) // 设置默认选中
defaultExpandedKey.value = [selectedValue] // 设置默认展开
}
} else {
clearHandle()
}
} else {
clearHandle()
}
})
}
function handleNodeClick(node: any) {
const handleNodeClick = (node: any) => {
valueTitle.value = node[props.objMap.label]
valueId.value = node[props.objMap.value];
defaultExpandedKey.value = [];
selectTree.value.blur()
selectTree.value?.blur()
selectFilterData('')
}
function selectFilterData(val: any) {
selectTree.value.filter(val)
const selectFilterData = (val: any) => {
selectTree.value?.filter(val)
}
function filterNode(value: any, data: any) {
const filterNode = (value: any, data: any) => {
if (!value) return true
return data[props.objMap['label']].indexOf(value) !== -1
}
function clearHandle() {
const clearHandle = () => {
valueTitle.value = ''
valueId.value = ''
defaultExpandedKey.value = [];
clearSelected()
}
function clearSelected() {
const clearSelected = () => {
const allNode = document.querySelectorAll('#tree-option .el-tree-node')
allNode.forEach((element) => element.classList.remove('is-current'))
}
@ -132,6 +131,7 @@ watch(valueId, () => {
<style lang="scss" scoped>
@import "@/assets/styles/variables.module.scss";
.el-scrollbar .el-scrollbar__view .el-select-dropdown__item {
padding: 0;
background-color: #fff;

View File

@ -5,11 +5,10 @@
</template>
<script setup lang="ts">
import { propTypes } from '@/utils/propTypes';
const props = defineProps({
src: {
type: String,
required: true
}
src: propTypes.string.isRequired
})
const height = ref(document.documentElement.clientHeight - 94.5 + "px;")

View File

@ -16,4 +16,4 @@ import useTagsViewStore from '@/store/modules/tagsView';
const route = useRoute();
const tagsViewStore = useTagsViewStore()
</script>
</script>

View File

@ -20,8 +20,13 @@
<template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
</el-select>
<header-search id="header-search" class="right-menu-item" />
<!-- <header-search id="header-search" class="right-menu-item" /> -->
<search-menu ref="searchMenuRef" />
<el-tooltip content="搜索" effect="dark" placement="bottom">
<div class="right-menu-item hover-effect" @click="openSearchMenu">
<svg-icon class-name="search-icon" icon-class="search" />
</div>
</el-tooltip>
<el-tooltip content="Github" effect="dark" placement="bottom">
<ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
</el-tooltip>
@ -68,17 +73,18 @@
</template>
<script setup lang="ts">
import useAppStore from '@/store/modules/app'
import useUserStore from '@/store/modules/user'
import useSettingsStore from '@/store/modules/settings'
import SearchMenu from './topBar/search.vue';
import useAppStore from '@/store/modules/app';
import useUserStore from '@/store/modules/user';
import useSettingsStore from '@/store/modules/settings';
import { getTenantList } from "@/api/login";
import { dynamicClear, dynamicTenant } from "@/api/system/tenant";
import { ComponentInternalInstance } from "vue";
import { TenantVO } from "@/api/types";
const appStore = useAppStore()
const userStore = useUserStore()
const settingsStore = useSettingsStore()
const appStore = useAppStore();
const userStore = useUserStore();
const settingsStore = useSettingsStore();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -89,46 +95,52 @@ const tenantList = ref<TenantVO[]>([]);
const dynamic = ref(false);
// 租户开关
const tenantEnabled = ref(true);
// 搜索菜单
const searchMenuRef = ref<InstanceType<typeof SearchMenu>>();
const openSearchMenu = () => {
searchMenuRef.value?.openSearch();
}
// 动态切换
const dynamicTenantEvent = async (tenantId: string) => {
if (companyName.value != null && companyName.value !== '') {
await dynamicTenant(tenantId);
dynamic.value = true;
proxy?.$tab.closeAllPage();
proxy?.$router.push('/');
}
if (companyName.value != null && companyName.value !== '') {
await dynamicTenant(tenantId);
dynamic.value = true;
proxy?.$tab.closeAllPage();
proxy?.$router.push('/');
}
}
const dynamicClearEvent = async () => {
await dynamicClear();
dynamic.value = false;
proxy?.$tab.closeAllPage();
proxy?.$router.push('/')
await dynamicClear();
dynamic.value = false;
proxy?.$tab.closeAllPage();
proxy?.$router.push('/');
}
/** 租户列表 */
const initTenantList = async () => {
const { data } = await getTenantList();
tenantEnabled.value = data.tenantEnabled === undefined ? true : data.tenantEnabled;
if (tenantEnabled.value) {
tenantList.value = data.voList;
}
const { data } = await getTenantList();
tenantEnabled.value = data.tenantEnabled === undefined ? true : data.tenantEnabled;
if (tenantEnabled.value) {
tenantList.value = data.voList;
}
}
defineExpose({
initTenantList,
initTenantList,
})
const toggleSideBar = () => {
appStore.toggleSideBar(false)
appStore.toggleSideBar(false);
}
const logout = async () => {
await ElMessageBox.confirm('确定注销并退出系统吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
await userStore.logout()
location.href = import.meta.env.VITE_APP_CONTEXT_PATH + 'index';
@ -169,7 +181,7 @@ const handleCommand = (command: string) => {
height: 50px;
overflow: hidden;
position: relative;
background: #fff;
//background: #fff;
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
.hamburger-container {

View File

@ -1,8 +1,7 @@
<template>
<el-drawer v-model="showSettings" :withHeader="false" direction="rtl" size="300px" close-on-click-modal>
<div class="setting-drawer-title">
<h3 class="drawer-title">主题风格设置</h3>
</div>
<h3 class="drawer-title">主题风格设置</h3>
<div class="setting-drawer-block-checbox">
<div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-dark')">
<img src="@/assets/images/dark.svg" alt="dark" />
@ -35,6 +34,13 @@
<el-color-picker v-model="theme" :predefine="predefineColors" @change="themeChange" />
</span>
</div>
<div class="drawer-item">
<span>深色模式</span>
<span class="comp-style">
<el-switch v-model="isDark" @change="toggleDark" class="drawer-switch" />
</span>
</div>
<el-divider />
<h3 class="drawer-title">系统布局配置</h3>
@ -102,7 +108,15 @@ const sideTheme = ref(settingsStore.sideTheme);
const storeSettings = computed(() => settingsStore);
const predefineColors = ref(["#409EFF", "#ff4500", "#ff8c00", "#ffd700", "#90ee90", "#00ced1", "#1e90ff", "#c71585"]);
/** 是否需要topnav */
// 是否暗黑模式
const isDark = useDark({
storageKey: 'useDarkKey',
valueDark: 'dark',
valueLight: 'light',
});
const toggleDark = () => useToggle(isDark);
/** 是否需要topNav */
const topNav = computed({
get: () => storeSettings.value.topNav,
set: (val) => {
@ -234,7 +248,6 @@ defineExpose({
}
.drawer-item {
color: rgba(0, 0, 0, 0.65);
padding: 12px 0;
font-size: 14px;

View File

@ -6,22 +6,21 @@
<script setup lang="ts">
import useTagsViewStore from '@/store/modules/tagsView'
import { ElScrollbar } from 'element-plus';
import { TagView } from 'vue-router'
const tagAndTagSpacing = ref(4);
const scrollContainerRef = ref(ElScrollbar)
const scrollWrapper = computed(() => scrollContainerRef.value.$refs.wrapRef);
const scrollContainerRef = ref<ElScrollbarInstance>()
const scrollWrapper = computed(() => scrollContainerRef.value?.$refs.wrapRef as any);
onMounted(() => {
scrollWrapper.value.addEventListener('scroll', emitScroll, true)
scrollWrapper.value?.addEventListener('scroll', emitScroll, true)
})
onBeforeUnmount(() => {
scrollWrapper.value.removeEventListener('scroll', emitScroll)
scrollWrapper.value?.removeEventListener('scroll', emitScroll)
})
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;
$scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
}
@ -34,7 +33,7 @@ const tagsViewStore = useTagsViewStore()
const visitedViews = computed(() => tagsViewStore.visitedViews);
const moveToTarget = (currentTag: TagView) => {
const $container = scrollContainerRef.value.$el
const $container = scrollContainerRef.value?.$el
const $containerWidth = $container.offsetWidth
const $scrollWrapper = scrollWrapper.value;

View File

@ -125,6 +125,9 @@ const initTags = () => {
}
const addTags = () => {
const { name } = route;
if(route.query.title) {
route.meta.title = route.query.title;
}
if (name) {
useTagsViewStore().addView(route);
if (route.meta.link) {
@ -237,8 +240,8 @@ onMounted(() => {
.tags-view-container {
height: 34px;
width: 100%;
background: #fff;
border-bottom: 1px solid #d8dce5;
background-color: var(--el-bg-color);
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);
.tags-view-wrapper {
.tags-view-item {
@ -247,13 +250,16 @@ onMounted(() => {
cursor: pointer;
height: 26px;
line-height: 23px;
border: 1px solid #d8dce5;
background-color: var(--el-bg-color);
border: 1px solid var(--el-border-color-light);
color: #495060;
background: #fff;
padding: 0 8px;
font-size: 12px;
margin-left: 5px;
margin-top: 4px;
&:hover {
color: var(--el-color-primary);
}
&:first-of-type {
margin-left: 15px;
}
@ -279,7 +285,7 @@ onMounted(() => {
}
.contextmenu {
margin: 0;
background: #fff;
background: var(--el-bg-color);
z-index: 3000;
position: absolute;
list-style-type: none;
@ -287,7 +293,6 @@ onMounted(() => {
border-radius: 4px;
font-size: 12px;
font-weight: 400;
color: #333;
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
li {
margin: 0;

View File

@ -0,0 +1,158 @@
<template>
<div class="layout-search-dialog">
<el-dialog v-model="state.isShowSearch" destroy-on-close :show-close="false">
<template #footer>
<el-autocomplete
v-model="state.menuQuery"
:fetch-suggestions="menuSearch"
placeholder="搜索"
ref="layoutMenuAutocompleteRef"
@select="onHandleSelect"
:fit-input-width="true"
>
<template #prefix>
<svg-icon class-name="search-icon" icon-class="search" />
</template>
<template #default="{ item }">
<div>
<svg-icon :icon-class="item.icon" class="mr5" />
{{ item.title }}
</div>
</template>
</el-autocomplete>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="layoutBreadcrumbSearch">
import { getNormalPath } from '@/utils/ruoyi';
import { isHttp } from '@/utils/validate';
import usePermissionStore from '@/store/modules/permission';
import { RouteOption } from 'vue-router';
type Router = Array<{
path: string;
icon: string;
title: string[];
}>
type SearchState<T = any> = {
isShowSearch: boolean;
menuQuery: string;
menuList: T[];
};
// 定义变量内容
const layoutMenuAutocompleteRef = ref();
const router = useRouter();
const routes = computed(() => usePermissionStore().routes);
const state = reactive<SearchState>({
isShowSearch: false,
menuQuery: '',
menuList: [],
});
// 搜索弹窗打开
const openSearch = () => {
state.menuQuery = '';
state.isShowSearch = true;
state.menuList = generateRoutes(routes.value);
nextTick(() => {
setTimeout(() => {
layoutMenuAutocompleteRef.value.focus();
});
});
};
// 搜索弹窗关闭
const closeSearch = () => {
state.isShowSearch = false;
};
// 菜单搜索数据过滤
const menuSearch = (queryString: string, cb: Function) => {
let options = state.menuList.filter((item) => {
return item.title.indexOf(queryString) > -1;
});
cb(options);
};
// Filter out the routes that can be displayed in the sidebar
// And generate the internationalized title
const generateRoutes = (routes: RouteOption[], basePath = '', prefixTitle: string[] = []) => {
let res: Router = []
routes.forEach(r => {
// skip hidden router
if (!r.hidden) {
const p = r.path.length > 0 && r.path[0] === '/' ? r.path : '/' + r.path;
const data: any = {
path: !isHttp(r.path) ? getNormalPath(basePath + p) : r.path,
icon: r.meta?.icon,
title: [...prefixTitle]
}
if (r.meta && r.meta.title) {
data.title = [...data.title, r.meta.title];
if (r.redirect !== 'noRedirect') {
// only push the routes with title
// special case: need to exclude parent router without redirect
res.push(data);
}
}
// recursive child routes
if (r.children) {
const tempRoutes = generateRoutes(r.children, data.path, data.title);
if (tempRoutes.length >= 1) {
res = [...res, ...tempRoutes];
}
}
}
})
res.forEach((item: any) => {
if (item.title instanceof Array) {
item.title = item.title.join('/');
}
});
return res;
}
// 当前菜单选中时
const onHandleSelect = (val: any) => {
const paths = val.path;
if (isHttp(paths)) {
// http(s):// 路径新窗口打开
const pindex = paths.indexOf("http");
window.open(paths.substring(pindex, paths.length), "_blank");
} else {
router.push(paths);
}
state.menuQuery = ''
closeSearch();
};
// 暴露变量
defineExpose({
openSearch
});
</script>
<style scoped lang="scss">
.layout-search-dialog {
position: relative;
:deep(.el-dialog) {
.el-dialog__header,
.el-dialog__body {
display: none;
}
.el-dialog__footer {
width: 100%;
position: absolute;
left: 50%;
transform: translateX(-50%);
top: -53vh;
}
}
:deep(.el-autocomplete) {
width: 560px;
position: absolute;
top: 150px;
left: 50%;
transform: translateX(-50%);
}
}
</style>

View File

@ -1,57 +1,57 @@
import { ElMessage, ElMessageBox, ElNotification, ElLoading, MessageBoxData } from 'element-plus';
import { MessageBoxData } from 'element-plus';
import { LoadingInstance } from 'element-plus/es/components/loading/src/loading';
let loadingInstance: LoadingInstance;
export default {
// 消息提示
msg(content: string) {
msg(content: any) {
ElMessage.info(content);
},
// 错误消息
msgError(content: string) {
msgError(content: any) {
ElMessage.error(content);
},
// 成功消息
msgSuccess(content: string) {
msgSuccess(content: any) {
ElMessage.success(content);
},
// 警告消息
msgWarning(content: string) {
msgWarning(content: any) {
ElMessage.warning(content);
},
// 弹出提示
alert(content: string) {
alert(content: any) {
ElMessageBox.alert(content, '系统提示');
},
// 错误提示
alertError(content: string) {
alertError(content: any) {
ElMessageBox.alert(content, '系统提示', { type: 'error' });
},
// 成功提示
alertSuccess(content: string, s: string, p: { dangerouslyUseHTMLString: boolean }) {
alertSuccess(content: any) {
ElMessageBox.alert(content, '系统提示', { type: 'success' });
},
// 警告提示
alertWarning(content: string) {
alertWarning(content: any) {
ElMessageBox.alert(content, '系统提示', { type: 'warning' });
},
// 通知提示
notify(content: string) {
notify(content: any) {
ElNotification.info(content);
},
// 错误通知
notifyError(content: string) {
notifyError(content: any) {
ElNotification.error(content);
},
// 成功通知
notifySuccess(content: string) {
notifySuccess(content: any) {
ElNotification.success(content);
},
// 警告通知
notifyWarning(content: string) {
notifyWarning(content: any) {
ElNotification.warning(content);
},
// 确认窗体
confirm(content: string): Promise<MessageBoxData> {
confirm(content: any): Promise<MessageBoxData> {
return ElMessageBox.confirm(content, '系统提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
@ -59,7 +59,7 @@ export default {
});
},
// 提交内容
prompt(content: string) {
prompt(content: any) {
return ElMessageBox.prompt(content, '系统提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',

View File

@ -3,8 +3,11 @@ import router from '@/router';
import { TagView, RouteLocationRaw } from 'vue-router';
export default {
// 刷新当前tab页签
async refreshPage(obj: TagView): Promise<void> {
/**
* 刷新当前tab页签
* @param obj 标签对象
*/
async refreshPage(obj?: TagView): Promise<void> {
const { path, query, matched } = router.currentRoute.value;
if (obj === undefined) {
matched.forEach((m) => {
@ -15,11 +18,16 @@ export default {
}
});
}
// prettier-ignore
await useTagsViewStore().delCachedView(obj)
router.replace({
path: '/redirect' + obj.path,
query: obj.query
let query1: undefined | {} = {};
let path1: undefined | string = '';
if (obj) {
query1 = obj.query;
path1 = obj.path;
}
await useTagsViewStore().delCachedView(obj);
await router.replace({
path: '/redirect' + path1,
query: query1
});
},
// 关闭当前tab页签打开新页签
@ -34,9 +42,9 @@ export default {
if (obj === undefined) {
// prettier-ignore
const { visitedViews } = await useTagsViewStore().delView(router.currentRoute.value) as any
const latestView = visitedViews.slice(-1)[0]
const latestView = visitedViews.slice(-1)[0];
if (latestView) {
return router.push(latestView.fullPath)
return router.push(latestView.fullPath);
}
return router.push('/');
}
@ -47,22 +55,31 @@ export default {
return useTagsViewStore().delAllViews();
},
// 关闭左侧tab页签
closeLeftPage(obj: TagView) {
closeLeftPage(obj?: TagView) {
return useTagsViewStore().delLeftTags(obj || router.currentRoute.value);
},
// 关闭右侧tab页签
closeRightPage(obj: TagView) {
closeRightPage(obj?: TagView) {
return useTagsViewStore().delRightTags(obj || router.currentRoute.value);
},
// 关闭其他tab页签
closeOtherPage(obj: TagView) {
closeOtherPage(obj?: TagView) {
return useTagsViewStore().delOthersViews(obj || router.currentRoute.value);
},
// 打开tab页签
openPage(url: RouteLocationRaw) {
return router.push(url);
/**
* 打开tab页签
* @param url 路由地址
* @param title 标题
* @param query 参数
*/
openPage(url: string, title?: string, query?: any) {
const obj = { path: url, query: { ...query, title } };
return router.push(obj);
},
// 修改tab页签
/**
* 修改tab页签
* @param obj 标签对象
*/
updatePage(obj: TagView) {
return useTagsViewStore().updateVisitedView(obj);
}

View File

@ -54,8 +54,11 @@ export const useTagsViewStore = defineStore('tagsView', () => {
resolve([...visitedViews.value]);
});
};
const delCachedView = (view: TagView): Promise<string[]> => {
const viewName = view.name as string;
const delCachedView = (view?: TagView): Promise<string[]> => {
let viewName = '';
if (view) {
viewName = view.name as string;
}
return new Promise((resolve) => {
const index = cachedViews.value.indexOf(viewName);
index > -1 && cachedViews.value.splice(index, 1);
@ -167,6 +170,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
const addCachedView = (view: TagView): void => {
const viewName = view.name as string;
if (!viewName) return;
if (cachedViews.value.includes(viewName)) return;
if (!view.meta?.noCache) {
cachedViews.value.push(viewName);

View File

@ -1 +1,35 @@
declare type ElTagType = '' | 'success' | 'warning' | 'info' | 'danger' | 'default' | 'primary';
import type * as ep from 'element-plus';
declare global {
declare type ElTagType = '' | 'success' | 'warning' | 'info' | 'danger' | 'default' | 'primary';
declare type ElFormInstance = InstanceType<typeof ep.ElForm>;
declare type ElTableInstance = InstanceType<typeof ep.ElTable>;
declare type ElTreeInstance = InstanceType<typeof ep.ElTree>;
declare type ElTreeSelectInstance = InstanceType<typeof ep.ElTreeSelect>;
declare type ElSelectInstance = InstanceType<typeof ep.ElSelect>;
declare type ElUploadInstance = InstanceType<typeof ep.ElUpload>;
declare type ElCardInstance = InstanceType<typeof ep.ElCard>;
declare type ElDialogInstance = InstanceType<typeof ep.ElDialog>;
declare type ElInputInstance = InstanceType<typeof ep.ElInput>;
declare type ElInputNumberInstance = InstanceType<typeof ep.ElInputNumber>;
declare type ElRadioInstance = InstanceType<typeof ep.ElRadio>;
declare type ElRadioGroupInstance = InstanceType<typeof ep.ElRadioGroup>;
declare type ElRadioButtonInstance = InstanceType<typeof ep.ElRadioButton>;
declare type ElCheckboxInstance = InstanceType<typeof ep.ElCheckbox>;
declare type ElCheckboxGroupInstance = InstanceType<typeof ep.ElCheckboxGroup>;
declare type ElSwitchInstance = InstanceType<typeof ep.ElSwitch>;
declare type ElDatePickerInstance = InstanceType<typeof ep.ElDatePicker>;
declare type ElTimePickerInstance = InstanceType<typeof ep.ElTimePicker>;
declare type ElTimeSelectInstance = InstanceType<typeof ep.ElTimeSelect>;
declare type ElCascaderInstance = InstanceType<typeof ep.ElCascader>;
declare type ElColorPickerInstance = InstanceType<typeof ep.ElColorPicker>;
declare type ElRateInstance = InstanceType<typeof ep.ElRate>;
declare type ElSliderInstance = InstanceType<typeof ep.ElSlider>;
declare type ElUploadInstance = InstanceType<typeof ep.ElUpload>;
declare type ElScrollbarInstance = InstanceType<typeof ep.ElScrollbar>;
declare type TransferKey = ep.TransferKey;
declare type CheckboxValueType = ep.CheckboxValueType;
declare type ElFormRules = ep.FormRules;
declare type DateModelType = ep.DateModelType;
declare type UploadFile = typeof ep.UploadFile;
}

26
src/types/global.d.ts vendored
View File

@ -1,9 +1,15 @@
import { FormRules } from 'element-plus';
import type { ComponentInternalInstance as ComponentInstance, PropType as VuePropType } from 'vue';
declare global {
/** vue Instance */
declare type ComponentInternalInstance = ComponentInstance;
/**vue */
declare type PropType<T> = VuePropType<T>;
/**
* 界面字段隐藏属性
*/
interface FieldOption {
declare interface FieldOption {
key: number;
label: string;
visible: boolean;
@ -12,7 +18,7 @@ declare global {
/**
* 弹窗属性
*/
interface DialogOption {
declare interface DialogOption {
/**
* 弹窗标题
*/
@ -23,7 +29,7 @@ declare global {
visible: boolean;
}
interface UploadOption {
declare interface UploadOption {
/** 设置上传的请求头部 */
headers: { [key: string]: any };
@ -34,7 +40,7 @@ declare global {
/**
* 导入属性
*/
interface ImportOption extends UploadOption {
declare interface ImportOption extends UploadOption {
/** 是否显示弹出层 */
open: boolean;
/** 弹出层标题 */
@ -48,14 +54,14 @@ declare global {
/**
* 字典数据 数据配置
*/
interface DictDataOption {
declare interface DictDataOption {
label: string;
value: string;
elTagType?: ElTagType;
elTagClass?: string;
}
interface BaseEntity {
declare interface BaseEntity {
createBy?: any;
createDept?: any;
createTime?: string;
@ -68,15 +74,15 @@ declare global {
* T : 表单数据
* D : 查询参数
*/
interface PageData<T, D> {
declare interface PageData<T, D> {
form: T;
queryParams: D;
rules: FormRules;
rules: ElFormRules;
}
/**
* 分页查询参数
*/
interface PageQuery {
declare interface PageQuery {
pageNum: number;
pageSize: number;
}

26
src/types/module.d.ts vendored
View File

@ -1,23 +1,27 @@
import modal from '@/plugins/modal';
import tab from '@/plugins/tab';
import { useDict } from '@/utils/dict';
import { addDateRange, handleTree, selectDictLabel, selectDictLabels, parseTime } from '@/utils/ruoyi';
import { getConfigKey, updateConfigByKey } from '@/api/system/config';
import { download as download1 } from '@/utils/request';
import download from '@/plugins/download';
import animate from '@/animate';
import type modal from '@/plugins/modal';
import type tab from '@/plugins/tab';
import type download from '@/plugins/download';
import type auth from '@/plugins/auth';
import type cache from '@/plugins/cache';
import type animate from '@/animate';
import type { useDict } from '@/utils/dict';
import type { addDateRange, handleTree, selectDictLabel, selectDictLabels, parseTime } from '@/utils/ruoyi';
import type { getConfigKey, updateConfigByKey } from '@/api/system/config';
import type { download as rd } from '@/utils/request';
declare module 'vue' {
export interface ComponentCustomProperties {
declare module '@vue/runtime-core' {
interface ComponentCustomProperties {
// 全局方法声明
$modal: typeof modal;
$tab: typeof tab;
$download: typeof download;
$auth: typeof auth;
$cache: typeof cache;
animate: typeof animate;
useDict: typeof useDict;
addDateRange: typeof addDateRange;
download: typeof download1;
download: typeof rd;
handleTree: typeof handleTree;
getConfigKey: typeof getConfigKey;
updateConfigByKey: typeof updateConfigByKey;

View File

@ -1,7 +1,7 @@
import { RouteRecordRaw } from 'vue-router';
declare module 'vue-router' {
type RouteOption = {
declare type RouteOption = {
hidden?: boolean;
permissions?: string[];
roles?: string[];
@ -16,15 +16,15 @@ declare module 'vue-router' {
query?: string;
} & RouteRecordRaw;
interface _RouteLocationBase {
declare interface _RouteLocationBase {
children?: RouteOption[];
}
interface RouteLocationOptions {
declare interface RouteLocationOptions {
fullPath?: string;
}
interface TagView extends Partial<_RouteLocationBase> {
declare interface TagView extends Partial<_RouteLocationBase> {
title?: string;
meta?: {
link?: string;

4
src/types/vform3-builds.d.ts vendored Normal file
View File

@ -0,0 +1,4 @@
declare module 'vform3-builds' {
const content: any;
export = content;
}

25
src/utils/propTypes.ts Normal file
View File

@ -0,0 +1,25 @@
import { CSSProperties } from 'vue';
import { createTypes, VueTypeValidableDef, VueTypesInterface } from 'vue-types';
type PropTypes = VueTypesInterface & {
readonly style: VueTypeValidableDef<CSSProperties>;
};
const propTypes = createTypes({
func: undefined,
bool: undefined,
string: undefined,
number: undefined,
object: undefined,
integer: undefined
}) as PropTypes;
propTypes.extend([
{
name: 'style',
getter: true,
type: [String, Object],
default: undefined
}
]);
export { propTypes };

View File

@ -1,32 +1,34 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="部门id" prop="deptId">
<el-input v-model="queryParams.deptId" placeholder="请输入部门id" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="用户id" prop="userId">
<el-input v-model="queryParams.userId" placeholder="请输入用户id" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="排序号" prop="orderNum">
<el-input v-model="queryParams.orderNum" placeholder="请输入排序号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="key键" prop="testKey">
<el-input v-model="queryParams.testKey" placeholder="请输入key键" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="值" prop="value">
<el-input v-model="queryParams.value" placeholder="请输入值" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb-[10px]" v-show="showSearch">
<el-card shadow="hover">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="部门id" prop="deptId">
<el-input v-model="queryParams.deptId" placeholder="请输入部门id" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="用户id" prop="userId">
<el-input v-model="queryParams.userId" placeholder="请输入用户id" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="排序号" prop="orderNum">
<el-input v-model="queryParams.orderNum" placeholder="请输入排序号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="key键" prop="testKey">
<el-input v-model="queryParams.testKey" placeholder="请输入key键" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="值" prop="value">
<el-input v-model="queryParams.value" placeholder="请输入值" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<el-card shadow="hover">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
@ -36,7 +38,9 @@
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['demo:demo:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['demo:demo:remove']">删除</el-button>
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['demo:demo:remove']"
>删除</el-button
>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['demo:demo:export']">导出</el-button>
@ -65,13 +69,7 @@
</el-table-column>
</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" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改测试单对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
@ -105,8 +103,6 @@
<script setup name="Demo" lang="ts">
import { listDemo, getDemo, delDemo, addDemo, updateDemo } from '@/api/demo/demo';
import { DemoVO, DemoQuery, DemoForm } from '@/api/demo/demo/types';
import { ComponentInternalInstance } from 'vue';
import { ElForm } from 'element-plus';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -119,8 +115,8 @@ const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const queryFormRef = ref(ElForm);
const demoFormRef = ref(ElForm);
const queryFormRef = ref<ElFormInstance>();
const demoFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
@ -136,7 +132,7 @@ const initFormData: DemoForm = {
value: undefined,
}
const data = reactive<PageData<DemoForm, DemoQuery>>({
form: {...initFormData},
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
@ -187,8 +183,8 @@ const cancel = () => {
/** 表单重置 */
const reset = () => {
form.value = {...initFormData};
demoFormRef.value.resetFields();
form.value = { ...initFormData };
demoFormRef.value?.resetFields();
}
/** 搜索按钮操作 */
@ -199,7 +195,7 @@ const handleQuery = () => {
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields();
queryFormRef.value?.resetFields();
handleQuery();
}
@ -235,13 +231,13 @@ const handleUpdate = (row?: DemoVO) => {
/** 提交按钮 */
const submitForm = () => {
demoFormRef.value.validate(async (valid: boolean) => {
demoFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (form.value.id) {
await updateDemo(form.value).finally(() => buttonLoading.value = false);
await updateDemo(form.value).finally(() => buttonLoading.value = false);
} else {
await addDemo(form.value).finally(() => buttonLoading.value = false);
await addDemo(form.value).finally(() => buttonLoading.value = false);
}
proxy?.$modal.msgSuccess("修改成功");
dialog.visible = false;

View File

@ -1,20 +1,22 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="树节点名" prop="treeName">
<el-input v-model="queryParams.treeName" placeholder="请输入树节点名" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb-[10px]" v-show="showSearch">
<el-card shadow="hover">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="树节点名" prop="treeName">
<el-input v-model="queryParams.treeName" placeholder="请输入树节点名" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<el-card shadow="hover">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
@ -89,8 +91,6 @@
<script setup name="Tree" lang="ts">
import { listTree, getTree, delTree, addTree, updateTree } from "@/api/demo/tree";
import { TreeVO, TreeQuery, TreeForm } from '@/api/demo/tree/types';
import { ComponentInternalInstance } from 'vue';
import { ElForm, ElTable } from 'element-plus';
type TreeOption = {
@ -109,9 +109,9 @@ const showSearch = ref(true);
const isExpandAll = ref(true);
const loading = ref(false);
const queryFormRef = ref(ElForm);
const treeFormRef = ref(ElForm);
const treeTableRef = ref(ElTable)
const queryFormRef = ref<ElFormInstance>();
const treeFormRef = ref<ElFormInstance>();
const treeTableRef = ref<ElTableInstance>()
const dialog = reactive<DialogOption>({
visible: false,
@ -185,7 +185,7 @@ const cancel = () => {
// 表单重置
const reset = () => {
form.value = {...initFormData}
treeFormRef.value.resetFields();
treeFormRef.value?.resetFields();
}
/** 搜索按钮操作 */
@ -195,7 +195,7 @@ const handleQuery = () => {
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields();
queryFormRef.value?.resetFields();
handleQuery();
}
@ -223,7 +223,7 @@ const handleToggleExpandAll = () => {
/** 展开/折叠操作 */
const toggleExpandAll = (data: TreeVO[], status: boolean) => {
data.forEach((item) => {
treeTableRef.value.toggleRowExpansion(item, status)
treeTableRef.value?.toggleRowExpansion(item, status)
if (item.children && item.children.length > 0) toggleExpandAll(item.children, status)
})
}
@ -247,7 +247,7 @@ const handleUpdate = (row: TreeVO) => {
/** 提交按钮 */
const submitForm = () => {
treeFormRef.value.validate(async (valid: boolean) => {
treeFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (form.value.id) {
@ -257,7 +257,7 @@ const submitForm = () => {
}
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
getList();
await getList();
}
});
}

View File

@ -21,7 +21,6 @@
<script setup lang="ts">
import errImage from '@/assets/401_images/401.gif';
import { ComponentInternalInstance } from "vue";
let { proxy } = getCurrentInstance() as ComponentInternalInstance;

View File

@ -65,14 +65,14 @@ import Cookies from 'js-cookie';
import { encrypt, decrypt } from '@/utils/jsencrypt';
import { useUserStore } from '@/store/modules/user';
import { LoginData, TenantVO } from '@/api/types';
import { ElForm, FormRules } from 'element-plus';
import { to } from 'await-to-js';
import { HttpStatus } from "@/enums/RespEnum";
const userStore = useUserStore();
const router = useRouter();
const loginForm = ref<LoginData>({
tenantId: "000000",
tenantId: '000000',
username: 'admin',
password: 'admin123',
rememberMe: false,
@ -80,7 +80,7 @@ const loginForm = ref<LoginData>({
uuid: ''
});
const loginRules: FormRules = {
const loginRules: ElFormRules = {
tenantId: [{ required: true, trigger: "blur", message: "请输入您的租户编号" }],
username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }],
@ -98,12 +98,12 @@ const tenantEnabled = ref(true);
// 注册开关
const register = ref(false);
const redirect = ref(undefined);
const loginRef = ref(ElForm);
const loginRef = ref<ElFormInstance>();
// 租户列表
const tenantList = ref<TenantVO[]>([]);
const handleLogin = () => {
loginRef.value.validate(async (valid: boolean, fields: any) => {
loginRef.value?.validate(async (valid: boolean, fields: any) => {
if (valid) {
loading.value = true;
// 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码
@ -120,7 +120,6 @@ const handleLogin = () => {
Cookies.remove('rememberMe');
}
// 调用action的登录方法
// prittier-ignore
const [err] = await to(userStore.login(loginForm.value));
if (!err) {
await router.push({ path: redirect.value || '/' });
@ -189,7 +188,7 @@ watch(() => loginForm.value.tenantId, (val: string) => {
*/
const doSocialLogin = (type: string) => {
authBinding(type).then((res: any) => {
if (res.code === 200) {
if (res.code === HttpStatus.SUCCESS) {
// 获取授权地址跳转
window.location.href = res.data;
} else {

View File

@ -2,7 +2,7 @@
<div class="p-2">
<el-row>
<el-col :span="24" class="card-box">
<el-card>
<el-card shadow="hover">
<template #header>
<Monitor style="width: 1em; height: 1em; vertical-align: middle;" />
<span style="vertical-align: middle;">基本信息</span>
@ -98,7 +98,7 @@
</el-col>
<el-col :span="12" class="card-box">
<el-card>
<el-card shadow="hover">
<template #header>
<PieChart style="width: 1em; height: 1em; vertical-align: middle;" />
<span style="vertical-align: middle;">命令统计</span>
@ -110,7 +110,7 @@
</el-col>
<el-col :span="12" class="card-box">
<el-card>
<el-card shadow="hover">
<template #header>
<Odometer style="width: 1em; height: 1em; vertical-align: middle;" /> <span style="vertical-align: middle;">内存信息</span>
</template>
@ -126,7 +126,6 @@
<script setup name="Cache" lang="ts">
import { getCache } from '@/api/monitor/cache';
import * as echarts from 'echarts';
import { ComponentInternalInstance } from "vue";
const cache = ref<any>({});
const commandstats = ref();

View File

@ -1,39 +1,41 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="登录地址" prop="ipaddr">
<el-input v-model="queryParams.ipaddr" placeholder="请输入登录地址" clearable style="width: 240px;" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="用户名称" prop="userName">
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px;" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="登录状态" clearable style="width: 240px">
<el-option v-for="dict in sys_common_status" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="登录时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb-[10px]" v-show="showSearch">
<el-card shadow="hover">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="登录地址" prop="ipaddr">
<el-input v-model="queryParams.ipaddr" placeholder="请输入登录地址" clearable style="width: 240px;" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="用户名称" prop="userName">
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px;" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="登录状态" clearable style="width: 240px">
<el-option v-for="dict in sys_common_status" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="登录时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<el-card shadow="hover">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
@ -98,9 +100,7 @@
<script setup name="Logininfor" lang="ts">
import { list, delLoginInfo, cleanLoginInfo, unlockLoginInfo } from "@/api/monitor/loginInfo";
import { ComponentInternalInstance } from "vue";
import { LoginInfoQuery, LoginInfoVO } from "@/api/monitor/loginInfo/types";
import { DateModelType } from 'element-plus';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { sys_common_status } = toRefs<any>(proxy?.useDict("sys_common_status"));
@ -116,8 +116,8 @@ const total = ref(0);
const dateRange = ref<[DateModelType,DateModelType]>(['', '']);
const defaultSort = ref<any>({ prop: "loginTime", order: "descending" });
const queryFormRef = ref(ElForm);
const loginInfoTableRef = ref(ElTable);
const queryFormRef = ref<ElFormInstance>();
const loginInfoTableRef = ref<ElTableInstance>();
// 查询参数
const queryParams = ref<LoginInfoQuery>({
pageNum: 1,
@ -145,9 +145,9 @@ const handleQuery = () => {
/** 重置按钮操作 */
const resetQuery = () => {
dateRange.value = ['', ''];
queryFormRef.value.resetFields();
queryFormRef.value?.resetFields();
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[]) => {
@ -167,14 +167,14 @@ const handleDelete = async (row?: LoginInfoVO) => {
const infoIds = row?.infoId || ids.value;
await proxy?.$modal.confirm('是否确认删除访问编号为"' + infoIds + '"的数据项?');
await delLoginInfo(infoIds);
getList();
await getList();
proxy?.$modal.msgSuccess("删除成功");
}
/** 清空按钮操作 */
const handleClean = async () => {
await proxy?.$modal.confirm("是否确认清空所有登录日志数据项?");
await cleanLoginInfo();
getList();
await getList();
proxy?.$modal.msgSuccess("清空成功");
}
/** 解锁按钮操作 */

View File

@ -1,20 +1,22 @@
<template>
<div class="p-2">
<div class="search">
<el-form :model="queryParams" ref="queryFormRef" :inline="true">
<el-form-item label="登录地址" prop="ipaddr">
<el-input v-model="queryParams.ipaddr" placeholder="请输入登录地址" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="用户名称" prop="userName">
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb-[10px]">
<el-card shadow="hover">
<el-form :model="queryParams" ref="queryFormRef" :inline="true">
<el-form-item label="登录地址" prop="ipaddr">
<el-input v-model="queryParams.ipaddr" placeholder="请输入登录地址" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="用户名称" prop="userName">
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
<div class="panel">
<el-card shadow="hover">
<el-table
v-loading="loading"
:data="onlineList.slice((queryParams.pageNum - 1) * queryParams.pageSize, queryParams.pageNum * queryParams.pageSize)"
@ -48,13 +50,12 @@
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" />
</div>
</el-card>
</div>
</template>
<script setup name="Online" lang="ts">
import { forceLogout, list as initData } from "@/api/monitor/online";
import { ComponentInternalInstance } from "vue";
import { OnlineQuery, OnlineVO } from "@/api/monitor/online/types";
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -63,42 +64,42 @@ const onlineList = ref<OnlineVO[]>([]);
const loading = ref(true);
const total = ref(0);
const queryFormRef = ref(ElForm);
const queryFormRef = ref<ElFormInstance>();
const queryParams = ref<OnlineQuery>({
pageNum: 1,
pageSize: 10,
ipaddr: '',
userName: ''
pageNum: 1,
pageSize: 10,
ipaddr: '',
userName: ''
});
/** 查询登录日志列表 */
const getList = async () => {
loading.value = true;
const res = await initData(queryParams.value);
onlineList.value = res.rows;
total.value = res.total;
loading.value = false;
loading.value = true;
const res = await initData(queryParams.value);
onlineList.value = res.rows;
total.value = res.total;
loading.value = false;
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields();
handleQuery();
queryFormRef.value?.resetFields();
handleQuery();
}
/** 强退按钮操作 */
const handleForceLogout = async (row: OnlineVO) => {
await proxy?.$modal.confirm('是否确认强退名称为"' + row.userName + '"的用户?');
await forceLogout(row.tokenId);
getList();
proxy?.$modal.msgSuccess("删除成功");
await proxy?.$modal.confirm('是否确认强退名称为"' + row.userName + '"的用户?');
await forceLogout(row.tokenId);
getList();
proxy?.$modal.msgSuccess("删除成功");
}
onMounted(() => {
getList();
getList();
})
</script>

View File

@ -1,44 +1,46 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="系统模块" prop="title">
<el-input v-model="queryParams.title" placeholder="请输入系统模块" clearable style="width: 240px;" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="操作人员" prop="operName">
<el-input v-model="queryParams.operName" placeholder="请输入操作人员" clearable style="width: 240px;" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="类型" prop="businessType">
<el-select v-model="queryParams.businessType" placeholder="操作类型" clearable style="width: 240px">
<el-option v-for="dict in sys_oper_type" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="操作状态" clearable style="width: 240px">
<el-option v-for="dict in sys_common_status" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="操作时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb-[10px]">
<el-card shadow="hover">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="系统模块" prop="title">
<el-input v-model="queryParams.title" placeholder="请输入系统模块" clearable style="width: 240px;" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="操作人员" prop="operName">
<el-input v-model="queryParams.operName" placeholder="请输入操作人员" clearable style="width: 240px;" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="类型" prop="businessType">
<el-select v-model="queryParams.businessType" placeholder="操作类型" clearable style="width: 240px">
<el-option v-for="dict in sys_oper_type" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="操作状态" clearable style="width: 240px">
<el-option v-for="dict in sys_common_status" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="操作时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<el-card shadow="hover">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
@ -132,7 +134,7 @@
<el-form-item label="操作方法:">{{ form.method }}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="请求参数:">{{form.operParam}}</el-form-item>
<el-form-item label="请求参数:">{{ form.operParam }}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="返回参数:">{{ form.jsonResult }}</el-form-item>
@ -165,12 +167,10 @@
<script setup name="Operlog" lang="ts">
import { list, delOperlog, cleanOperlog } from '@/api/monitor/operlog';
import { ComponentInternalInstance } from 'vue';
import { OperLogForm, OperLogQuery, OperLogVO } from '@/api/monitor/operlog/types';
import { DateModelType } from 'element-plus';
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 loading = ref(true);
@ -181,116 +181,116 @@ const total = ref(0);
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
const defaultSort = ref<any>({ prop: "operTime", order: "descending" });
const operLogTableRef = ref(ElTable);
const queryFormRef = ref(ElForm);
const operLogTableRef = ref<ElTableInstance>();
const queryFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
visible: false,
title: ''
});
const data = reactive<PageData<OperLogForm, OperLogQuery>>({
form: {
operId: undefined,
tenantId: undefined,
title: '',
businessType: 0,
businessTypes: undefined,
method: '',
requestMethod: '',
operatorType: 0,
operName: '',
deptName: '',
operUrl: '',
operIp: '',
operLocation: '',
operParam: '',
jsonResult: '',
status: 0,
errorMsg: '',
operTime: '',
costTime: 0
},
queryParams: {
pageNum: 1,
pageSize: 10,
title: '',
operName: '',
businessType: '',
status: '',
orderByColumn: defaultSort.value.prop,
isAsc: defaultSort.value.order
},
rules: {}
form: {
operId: undefined,
tenantId: undefined,
title: '',
businessType: 0,
businessTypes: undefined,
method: '',
requestMethod: '',
operatorType: 0,
operName: '',
deptName: '',
operUrl: '',
operIp: '',
operLocation: '',
operParam: '',
jsonResult: '',
status: 0,
errorMsg: '',
operTime: '',
costTime: 0
},
queryParams: {
pageNum: 1,
pageSize: 10,
title: '',
operName: '',
businessType: '',
status: '',
orderByColumn: defaultSort.value.prop,
isAsc: defaultSort.value.order
},
rules: {}
});
const { queryParams, form } = toRefs(data);
/** 查询登录日志 */
const getList = async () => {
loading.value = true;
const res = await list(proxy?.addDateRange(queryParams.value, dateRange.value));
operlogList.value = res.rows;
total.value = res.total;
loading.value = false;
loading.value = true;
const res = await list(proxy?.addDateRange(queryParams.value, dateRange.value));
operlogList.value = res.rows;
total.value = res.total;
loading.value = false;
}
/** 操作日志类型字典翻译 */
const typeFormat = (row: OperLogForm) => {
return proxy?.selectDictLabel(sys_oper_type.value, row.businessType);
return proxy?.selectDictLabel(sys_oper_type.value, row.businessType);
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
const resetQuery = () => {
dateRange.value = ['', ''];
queryFormRef.value.resetFields();
queryParams.value.pageNum = 1;
operLogTableRef.value.sort(defaultSort.value.prop, defaultSort.value.order);
dateRange.value = ['', ''];
queryFormRef.value?.resetFields();
queryParams.value.pageNum = 1;
operLogTableRef.value?.sort(defaultSort.value.prop, defaultSort.value.order);
}
/** 多选框选中数据 */
const handleSelectionChange = (selection: OperLogVO[]) => {
ids.value = selection.map(item => item.operId);
multiple.value = !selection.length;
ids.value = selection.map(item => item.operId);
multiple.value = !selection.length;
}
/** 排序触发事件 */
const handleSortChange = (column: any) => {
queryParams.value.orderByColumn = column.prop;
queryParams.value.isAsc = column.order;
getList();
queryParams.value.orderByColumn = column.prop;
queryParams.value.isAsc = column.order;
getList();
}
/** 详细按钮操作 */
const handleView = (row: OperLogVO) => {
dialog.visible = true;
form.value = row;
dialog.visible = true;
form.value = row;
}
/** 删除按钮操作 */
const handleDelete = async (row?: OperLogVO) => {
const operIds = row?.operId || ids.value;
await proxy?.$modal.confirm('是否确认删除日志编号为"' + operIds + '"的数据项?');
await delOperlog(operIds);
getList();
proxy?.$modal.msgSuccess("删除成功");
const operIds = row?.operId || ids.value;
await proxy?.$modal.confirm('是否确认删除日志编号为"' + operIds + '"的数据项?');
await delOperlog(operIds);
await getList();
proxy?.$modal.msgSuccess("删除成功");
}
/** 清空按钮操作 */
const handleClean = async () => {
await proxy?.$modal.confirm("是否确认清空所有操作日志数据项?");
await cleanOperlog();
getList();
proxy?.$modal.msgSuccess("清空成功");
await proxy?.$modal.confirm("是否确认清空所有操作日志数据项?");
await cleanOperlog();
await getList();
proxy?.$modal.msgSuccess("清空成功");
}
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download("monitor/operlog/export", {
...queryParams.value,
}, `config_${new Date().getTime()}.xlsx`);
proxy?.download("monitor/operlog/export", {
...queryParams.value,
}, `config_${new Date().getTime()}.xlsx`);
}
onMounted(() => {
getList();
getList();
})
</script>

View File

@ -58,19 +58,18 @@
<script setup lang="ts">
import { getCodeImg, register, getTenantList } from '@/api/login';
import { RegisterForm, TenantVO } from '@/api/types';
import { FormRules } from 'element-plus';
import { to } from 'await-to-js';
const router = useRouter();
const registerForm = ref<RegisterForm>({
tenantId: "",
username: "",
password: "",
confirmPassword: "",
code: "",
uuid: "",
userType: "sys_user"
tenantId: "",
username: "",
password: "",
confirmPassword: "",
code: "",
uuid: "",
userType: "sys_user"
});
// 租户开关
@ -78,30 +77,30 @@ const tenantEnabled = ref(true);
const equalToPassword = (rule: any, value: string, callback: any) => {
if (registerForm.value.password !== value) {
callback(new Error("两次输入的密码不一致"));
} else {
callback();
}
if (registerForm.value.password !== value) {
callback(new Error("两次输入的密码不一致"));
} else {
callback();
}
};
const registerRules: FormRules = {
tenantId: [
{ required: true, trigger: "blur", message: "请输入您的租户编号" }
],
username: [
{ required: true, trigger: "blur", message: "请输入您的账号" },
{ min: 2, max: 20, message: "用户账号长度必须介于 2 和 20 之间", trigger: "blur" }
],
password: [
{ required: true, trigger: "blur", message: "请输入您的密码" },
{ min: 5, max: 20, message: "用户密码长度必须介于 5 和 20 之间", trigger: "blur" }
],
confirmPassword: [
{ required: true, trigger: "blur", message: "请再次输入您的密码" },
{ required: true, validator: equalToPassword, trigger: "blur" }
],
code: [{ required: true, trigger: "change", message: "请输入验证码" }]
const registerRules: ElFormRules = {
tenantId: [
{ required: true, trigger: "blur", message: "请输入您的租户编号" }
],
username: [
{ required: true, trigger: "blur", message: "请输入您的账号" },
{ min: 2, max: 20, message: "用户账号长度必须介于 2 和 20 之间", trigger: "blur" }
],
password: [
{ required: true, trigger: "blur", message: "请输入您的密码" },
{ min: 5, max: 20, message: "用户密码长度必须介于 5 和 20 之间", trigger: "blur" }
],
confirmPassword: [
{ required: true, trigger: "blur", message: "请再次输入您的密码" },
{ required: true, validator: equalToPassword, trigger: "blur" }
],
code: [{ required: true, trigger: "change", message: "请输入验证码" }]
};
const codeUrl = ref("");
const loading = ref(false);
@ -111,50 +110,50 @@ const registerRef = ref(ElForm);
const tenantList = ref<TenantVO[]>([]);
const handleRegister = () => {
registerRef.value.validate(async (valid: boolean) => {
if (valid) {
loading.value = true;
const [err] = await to(register(registerForm.value));
if (!err) {
const username = registerForm.value.username;
await ElMessageBox.alert("<font color='red'>恭喜你,您的账号 " + username + " 注册成功!</font>", "系统提示", {
dangerouslyUseHTMLString: true,
type: "success",
});
await router.push("/login");
} else {
loading.value = false;
if (captchaEnabled) {
getCode();
}
}
registerRef.value.validate(async (valid: boolean) => {
if (valid) {
loading.value = true;
const [err] = await to(register(registerForm.value));
if (!err) {
const username = registerForm.value.username;
await ElMessageBox.alert("<font color='red'>恭喜你,您的账号 " + username + " 注册成功!</font>", "系统提示", {
dangerouslyUseHTMLString: true,
type: "success",
});
await router.push("/login");
} else {
loading.value = false;
if (captchaEnabled) {
getCode();
}
});
}
}
});
}
const getCode = async () => {
const { data } = await getCodeImg();
captchaEnabled.value = data.captchaEnabled === undefined ? true : data.captchaEnabled;
if (captchaEnabled.value) {
codeUrl.value = "data:image/gif;base64," + data.img;
registerForm.value.uuid = data.uuid;
}
const { data } = await getCodeImg();
captchaEnabled.value = data.captchaEnabled === undefined ? true : data.captchaEnabled;
if (captchaEnabled.value) {
codeUrl.value = "data:image/gif;base64," + data.img;
registerForm.value.uuid = data.uuid;
}
}
const initTenantList = async () => {
const { data } = await getTenantList();
tenantEnabled.value = data.tenantEnabled === undefined ? true : data.tenantEnabled;
if (tenantEnabled.value) {
tenantList.value = data.voList;
if (tenantList.value != null && tenantList.value.length !== 0) {
registerForm.value.tenantId = tenantList.value[0].tenantId;
}
const { data } = await getTenantList();
tenantEnabled.value = data.tenantEnabled === undefined ? true : data.tenantEnabled;
if (tenantEnabled.value) {
tenantList.value = data.voList;
if (tenantList.value != null && tenantList.value.length !== 0) {
registerForm.value.tenantId = tenantList.value[0].tenantId;
}
}
}
onMounted(() => {
getCode();
initTenantList();
getCode();
initTenantList();
})
</script>

View File

@ -1,38 +1,40 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="参数名称" prop="configName">
<el-input v-model="queryParams.configName" placeholder="请输入参数名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="参数键名" prop="configKey">
<el-input v-model="queryParams.configKey" placeholder="请输入参数键名" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="系统内置" prop="configType">
<el-select v-model="queryParams.configType" placeholder="系统内置" clearable>
<el-option v-for="dict in sys_yes_no" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="创建时间" style="width: 308px;">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb-[10px]" v-show="showSearch">
<el-card shadow="hover">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="参数名称" prop="configName">
<el-input v-model="queryParams.configName" placeholder="请输入参数名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="参数键名" prop="configKey">
<el-input v-model="queryParams.configKey" placeholder="请输入参数键名" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="系统内置" prop="configType">
<el-select v-model="queryParams.configType" placeholder="系统内置" clearable>
<el-option v-for="dict in sys_yes_no" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="创建时间" style="width: 308px;">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<el-card shadow="hover">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
@ -123,8 +125,6 @@
<script setup name="Config" lang="ts">
import { listConfig, getConfig, delConfig, addConfig, updateConfig, refreshCache } from "@/api/system/config";
import { ConfigForm, ConfigQuery, ConfigVO } from "@/api/system/config/types";
import { ComponentInternalInstance } from "vue";
import { DateModelType } from 'element-plus';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { sys_yes_no } = toRefs<any>(proxy?.useDict("sys_yes_no"));
@ -138,124 +138,124 @@ const multiple = ref(true);
const total = ref(0);
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
const queryFormRef = ref(ElForm);
const configFormRef = ref(ElForm);
const queryFormRef = ref<ElFormInstance>();
const configFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
visible: false,
title: ''
});
const initFormData: ConfigForm = {
configId: undefined,
configName: '',
configKey: '',
configValue: '',
configType: "Y",
remark: ''
configId: undefined,
configName: '',
configKey: '',
configValue: '',
configType: "Y",
remark: ''
}
const data = reactive<PageData<ConfigForm, ConfigQuery>>({
form: {...initFormData},
queryParams: {
pageNum: 1,
pageSize: 10,
configName: '',
configKey: '',
configType: '',
},
rules: {
configName: [{ required: true, message: "参数名称不能为空", trigger: "blur" }],
configKey: [{ required: true, message: "参数键名不能为空", trigger: "blur" }],
configValue: [{ required: true, message: "参数键值不能为空", trigger: "blur" }]
}
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
configName: '',
configKey: '',
configType: '',
},
rules: {
configName: [{ required: true, message: "参数名称不能为空", trigger: "blur" }],
configKey: [{ required: true, message: "参数键名不能为空", trigger: "blur" }],
configValue: [{ required: true, message: "参数键值不能为空", trigger: "blur" }]
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询参数列表 */
const getList = async () => {
loading.value = true;
const res = await listConfig(proxy?.addDateRange(queryParams.value, dateRange.value));
configList.value = res.rows;
total.value = res.total;
loading.value = false;
loading.value = true;
const res = await listConfig(proxy?.addDateRange(queryParams.value, dateRange.value));
configList.value = res.rows;
total.value = res.total;
loading.value = false;
}
/** 取消按钮 */
const cancel = () => {
reset();
dialog.visible = false;
reset();
dialog.visible = false;
}
/** 表单重置 */
const reset = () => {
form.value = {...initFormData};
configFormRef.value.resetFields();
form.value = { ...initFormData };
configFormRef.value?.resetFields();
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
const resetQuery = () => {
dateRange.value = ['', ''];
queryFormRef.value.resetFields();
handleQuery();
dateRange.value = ['', ''];
queryFormRef.value?.resetFields();
handleQuery();
}
/** 多选框选中数据 */
const handleSelectionChange = (selection: ConfigVO[]) => {
ids.value = selection.map(item => item.configId);
single.value = selection.length != 1;
multiple.value = !selection.length;
ids.value = selection.map(item => item.configId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
const handleAdd = () => {
dialog.visible = true;
dialog.title = "添加参数";
nextTick(() => {
reset();
})
dialog.visible = true;
dialog.title = "添加参数";
nextTick(() => {
reset();
})
}
/** 修改按钮操作 */
const handleUpdate = (row?: ConfigVO) => {
dialog.visible = true;
dialog.title = "修改参数";
const configId = row?.configId || ids.value[0];
nextTick(async () => {
reset();
const res = await getConfig(configId);
form.value = res.data;
})
dialog.visible = true;
dialog.title = "修改参数";
const configId = row?.configId || ids.value[0];
nextTick(async () => {
reset();
const res = await getConfig(configId);
form.value = res.data;
})
}
/** 提交按钮 */
const submitForm = () => {
configFormRef.value.validate(async (valid: boolean) => {
if (valid) {
form.value.configId ? await updateConfig(form.value) : await addConfig(form.value);
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
getList();
}
});
configFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
form.value.configId ? await updateConfig(form.value) : await addConfig(form.value);
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
await getList();
}
});
}
/** 删除按钮操作 */
const handleDelete = async (row?: ConfigVO) => {
const configIds = row?.configId || ids.value;
await proxy?.$modal.confirm('是否确认删除参数编号为"' + configIds + '"的数据项?');
await delConfig(configIds);
getList();
proxy?.$modal.msgSuccess("删除成功");
const configIds = row?.configId || ids.value;
await proxy?.$modal.confirm('是否确认删除参数编号为"' + configIds + '"的数据项?');
await delConfig(configIds);
await getList();
proxy?.$modal.msgSuccess("删除成功");
}
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download("system/config/export", {
...queryParams.value
}, `config_${new Date().getTime()}.xlsx`);
proxy?.download("system/config/export", {
...queryParams.value
}, `config_${new Date().getTime()}.xlsx`);
}
/** 刷新缓存按钮操作 */
const handleRefreshCache = async () => {
await refreshCache();
proxy?.$modal.msgSuccess("刷新缓存成功");
await refreshCache();
proxy?.$modal.msgSuccess("刷新缓存成功");
}
onMounted(() => {
getList();
getList();
})
</script>

View File

@ -1,25 +1,27 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
<el-form-item label="菜单名称" prop="menuName">
<el-input v-model="queryParams.deptName" placeholder="请输入部门名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="部门状态" clearable>
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb-[10px]" v-show="showSearch">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
<el-form-item label="菜单名称" prop="menuName">
<el-input v-model="queryParams.deptName" placeholder="请输入部门名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="部门状态" clearable>
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<el-card shadow="hover">
<template #header>
<el-row :gutter="10">
<el-col :span="1.5">
@ -130,13 +132,12 @@
<script setup name="Dept" lang="ts">
import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild } from "@/api/system/dept"
import { ComponentInternalInstance } from 'vue';
import { DeptForm, DeptQuery, DeptVO } from "@/api/system/dept/types";
interface DeptOptionsType {
deptId: number | string;
deptName: string;
children: DeptOptionsType[];
deptId: number | string;
deptName: string;
children: DeptOptionsType[];
}
@ -151,142 +152,146 @@ const isExpandAll = ref(true)
const dialog = reactive<DialogOption>({
visible: false,
title: ''
visible: false,
title: ''
});
const deptTableRef = ref(ElTable);
const queryFormRef = ref(ElForm);
const deptFormRef = ref(ElForm);
const deptTableRef = ref<ElTableInstance>();
const queryFormRef = ref<ElFormInstance>();
const deptFormRef = ref<ElFormInstance>();
const initFormData: DeptForm = {
deptId: undefined,
parentId: undefined,
deptName: undefined,
orderNum: 0,
leader: undefined,
phone: undefined,
email: undefined,
status: "0"
deptId: undefined,
parentId: undefined,
deptName: undefined,
orderNum: 0,
leader: undefined,
phone: undefined,
email: undefined,
status: "0"
}
const data = reactive<PageData<DeptForm, DeptQuery>>({
form: {...initFormData},
queryParams: {
pageNum: 1,
pageSize: 10,
deptName: undefined,
status: undefined
},
rules: {
parentId: [{ required: true, message: "上级部门不能为空", trigger: "blur" }],
deptName: [{ required: true, message: "部门名称不能为空", trigger: "blur" }],
orderNum: [{ required: true, message: "显示排序不能为空", trigger: "blur" }],
email: [{ type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
phone: [{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }]
},
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
deptName: undefined,
status: undefined
},
rules: {
parentId: [{ required: true, message: "上级部门不能为空", trigger: "blur" }],
deptName: [{ required: true, message: "部门名称不能为空", trigger: "blur" }],
orderNum: [{ required: true, message: "显示排序不能为空", trigger: "blur" }],
email: [{ type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
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 getList = async () => {
loading.value = true;
const res = await listDept(queryParams.value);
const data = proxy?.handleTree<DeptVO>(res.data, "deptId")
if (data) {
deptList.value = data
}
loading.value = false
loading.value = true;
const res = await listDept(queryParams.value);
const data = proxy?.handleTree<DeptVO>(res.data, "deptId")
if (data) {
deptList.value = data
}
loading.value = false
}
/** 取消按钮 */
const cancel = () => {
reset()
dialog.visible = false
reset()
dialog.visible = false
}
/** 表单重置 */
const reset = () => {
form.value = {...initFormData};
deptFormRef.value.resetFields();
form.value = { ...initFormData };
deptFormRef.value?.resetFields();
}
/** 搜索按钮操作 */
const handleQuery = () => {
getList();
getList();
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields();
handleQuery()
queryFormRef.value?.resetFields();
handleQuery()
}
/** 新增按钮操作 */
const handleAdd = (row?: DeptVO) => {
listDept().then(res => {
const data = proxy?.handleTree<DeptOptionsType>(res.data, "deptId");
if (data) {
deptOptions.value = data
dialog.visible = true;
dialog.title = "添加部门";
nextTick(() => {
reset();
if (row && row.deptId) {
form.value.parentId = row?.deptId;
}
})
listDept().then(res => {
const data = proxy?.handleTree<DeptOptionsType>(res.data, "deptId");
if (data) {
deptOptions.value = data
dialog.visible = true;
dialog.title = "添加部门";
nextTick(() => {
reset();
if (row && row.deptId) {
form.value.parentId = row?.deptId;
}
})
})
}
})
}
/** 展开/折叠操作 */
const handleToggleExpandAll = () => {
isExpandAll.value = !isExpandAll.value;
toggleExpandAll(deptList.value, isExpandAll.value)
isExpandAll.value = !isExpandAll.value;
toggleExpandAll(deptList.value, isExpandAll.value)
}
/** 展开/折叠所有 */
const toggleExpandAll = (data: DeptVO[], status: boolean) => {
data.forEach((item) => {
deptTableRef.value.toggleRowExpansion(item, status)
if(item.children && item.children.length > 0) toggleExpandAll(item.children, status)
})
data.forEach((item) => {
deptTableRef.value?.toggleRowExpansion(item, status)
if (item.children && item.children.length > 0) toggleExpandAll(item.children, status)
})
}
/** 修改按钮操作 */
const handleUpdate = async (row: DeptVO) => {
const res = await getDept(row.deptId);
dialog.visible = true;
dialog.title = "修改部门";
nextTick(async () => {
reset();
form.value = res.data
const response = await listDeptExcludeChild(row.deptId);
const data = proxy?.handleTree<DeptOptionsType>(response.data, "deptId")
if (data) {
deptOptions.value = data;
if (data.length === 0) {
const noResultsOptions: DeptOptionsType = { deptId: res.data.parentId, deptName: res.data.parentName, children: [] };
deptOptions.value.push(noResultsOptions);
}
}
})
const res = await getDept(row.deptId);
dialog.visible = true;
dialog.title = "修改部门";
await nextTick(async () => {
reset();
form.value = res.data
const response = await listDeptExcludeChild(row.deptId);
const data = proxy?.handleTree<DeptOptionsType>(response.data, "deptId")
if (data) {
deptOptions.value = data;
if (data.length === 0) {
const noResultsOptions: DeptOptionsType = {
deptId: res.data.parentId,
deptName: res.data.parentName,
children: []
};
deptOptions.value.push(noResultsOptions);
}
}
})
}
/** 提交按钮 */
const submitForm = () => {
deptFormRef.value.validate(async (valid: boolean) => {
if (valid) {
form.value.deptId ? await updateDept(form.value) : await addDept(form.value);
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
getList();
}
})
deptFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
form.value.deptId ? await updateDept(form.value) : await addDept(form.value);
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
await getList();
}
})
}
/** 删除按钮操作 */
const handleDelete = async (row: DeptVO) => {
await proxy?.$modal.confirm('是否确认删除名称为"' + row.deptName + '"的数据项?');
await delDept(row.deptId);
getList();
proxy?.$modal.msgSuccess("删除成功");
await proxy?.$modal.confirm('是否确认删除名称为"' + row.deptName + '"的数据项?');
await delDept(row.deptId);
await getList();
proxy?.$modal.msgSuccess("删除成功");
}
onMounted(() => {
getList();
getList();
});
</script>

View File

@ -1,29 +1,31 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="字典名称" prop="dictType">
<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-select>
</el-form-item>
<el-form-item label="字典标签" prop="dictLabel">
<el-input v-model="queryParams.dictLabel" placeholder="请输入字典标签" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="数据状态" clearable style="width: 200px">
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb-[10px]" v-show="showSearch">
<el-card shadow="hover">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="字典名称" prop="dictType">
<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-select>
</el-form-item>
<el-form-item label="字典标签" prop="dictLabel">
<el-input v-model="queryParams.dictLabel" placeholder="请输入字典标签" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="数据状态" clearable style="width: 200px">
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<el-card shadow="hover">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
@ -136,9 +138,7 @@ import useDictStore from '@/store/modules/dict'
import { optionselect as getDictOptionselect, getType } from "@/api/system/dict/type";
import { listData, getData, delData, addData, updateData } from "@/api/system/dict/data";
import { DictTypeVO } from '@/api/system/dict/type/types';
import { ComponentInternalInstance } from "vue";
import { DictDataForm, DictDataQuery, DictDataVO } from "@/api/system/dict/data/types";
import { ElForm } from 'element-plus';
const { proxy } = getCurrentInstance() as ComponentInternalInstance
const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable"));
@ -154,159 +154,159 @@ const total = ref(0);
const defaultDictType = ref("");
const typeOptions = ref<DictTypeVO[]>([]);
const dataFormRef = ref(ElForm);
const queryFormRef = ref(ElForm);
const dataFormRef = ref<ElFormInstance>();
const queryFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
visible: false,
title: ''
});
// 数据标签回显样式
const listClassOptions = ref<Array<{ value: string, label: string }>>([
{ value: "default", label: "默认" },
{ value: "primary", label: "主要" },
{ value: "success", label: "成功" },
{ value: "info", label: "信息" },
{ value: "warning", label: "警告" },
{ value: "danger", label: "危险" }
{ value: "default", label: "默认" },
{ value: "primary", label: "主要" },
{ value: "success", label: "成功" },
{ value: "info", label: "信息" },
{ value: "warning", label: "警告" },
{ value: "danger", label: "危险" }
]);
const initFormData: DictDataForm = {
dictCode: undefined,
dictLabel: '',
dictValue: '',
cssClass: '',
listClass: "default",
dictSort: 0,
status: "0",
remark: ''
dictCode: undefined,
dictLabel: '',
dictValue: '',
cssClass: '',
listClass: "default",
dictSort: 0,
status: "0",
remark: ''
}
const data = reactive<PageData<DictDataForm, DictDataQuery>>({
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
dictName: '',
dictType: '',
status: '',
dictLabel: ''
},
rules: {
dictLabel: [{ required: true, message: "数据标签不能为空", trigger: "blur" }],
dictValue: [{ required: true, message: "数据键值不能为空", trigger: "blur" }],
dictSort: [{ required: true, message: "数据顺序不能为空", trigger: "blur" }]
}
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
dictName: '',
dictType: '',
status: '',
dictLabel: ''
},
rules: {
dictLabel: [{ required: true, message: "数据标签不能为空", trigger: "blur" }],
dictValue: [{ required: true, message: "数据键值不能为空", trigger: "blur" }],
dictSort: [{ required: true, message: "数据顺序不能为空", trigger: "blur" }]
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询字典类型详细 */
const getTypes = async (dictId: string | number) => {
const { data } = await getType(dictId);
queryParams.value.dictType = data.dictType;
defaultDictType.value = data.dictType;
getList();
const { data } = await getType(dictId);
queryParams.value.dictType = data.dictType;
defaultDictType.value = data.dictType;
getList();
}
/** 查询字典类型列表 */
const getTypeList = async () => {
const res = await getDictOptionselect()
typeOptions.value = res.data;
const res = await getDictOptionselect()
typeOptions.value = res.data;
}
/** 查询字典数据列表 */
const getList = async () => {
loading.value = true;
const res = await listData(queryParams.value);
dataList.value = res.rows;
total.value = res.total;
loading.value = false;
loading.value = true;
const res = await listData(queryParams.value);
dataList.value = res.rows;
total.value = res.total;
loading.value = false;
}
/** 取消按钮 */
const cancel = () => {
dialog.visible = false;
reset();
dialog.visible = false;
reset();
}
/** 表单重置 */
const reset = () => {
form.value = { ...initFormData };
dataFormRef.value.resetFields();
form.value = { ...initFormData };
dataFormRef.value?.resetFields();
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
queryParams.value.pageNum = 1;
getList();
}
/** 返回按钮操作 */
const handleClose = () => {
const obj = { path: "/system/dict" };
proxy?.$tab.closeOpenPage(obj);
const obj = { path: "/system/dict" };
proxy?.$tab.closeOpenPage(obj);
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields();
queryParams.value.dictType = defaultDictType.value;
handleQuery();
queryFormRef.value?.resetFields();
queryParams.value.dictType = defaultDictType.value;
handleQuery();
}
/** 新增按钮操作 */
const handleAdd = () => {
dialog.visible = true;
dialog.title = "添加字典数据";
nextTick(() => {
reset();
form.value.dictType = queryParams.value.dictType;
})
dialog.visible = true;
dialog.title = "添加字典数据";
nextTick(() => {
reset();
form.value.dictType = queryParams.value.dictType;
})
}
/** 多选框选中数据 */
const handleSelectionChange = (selection: DictDataVO[]) => {
ids.value = selection.map(item => item.dictCode);
single.value = selection.length != 1;
multiple.value = !selection.length;
ids.value = selection.map(item => item.dictCode);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 修改按钮操作 */
const handleUpdate = (row?: DictDataVO) => {
const dictCode = row?.dictCode || ids.value[0];
dialog.visible = true;
dialog.title = "修改字典数据";
nextTick(async () => {
const res = await getData(dictCode);
reset();
form.value = res.data;
})
const dictCode = row?.dictCode || ids.value[0];
dialog.visible = true;
dialog.title = "修改字典数据";
nextTick(async () => {
const res = await getData(dictCode);
reset();
form.value = res.data;
})
}
/** 提交按钮 */
const submitForm = () => {
dataFormRef.value.validate(async (valid: boolean) => {
if (valid) {
form.value.dictCode ? await updateData(form.value) : await addData(form.value);
useDictStore().removeDict(queryParams.value.dictType);
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
getList();
dataFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
form.value.dictCode ? await updateData(form.value) : await addData(form.value);
useDictStore().removeDict(queryParams.value.dictType);
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
await getList();
}
});
}
});
}
/** 删除按钮操作 */
const handleDelete = async (row?: DictDataVO) => {
const dictCodes = row?.dictCode || ids.value;
await proxy?.$modal.confirm('是否确认删除字典编码为"' + dictCodes + '"的数据项?');
await delData(dictCodes);
getList();
proxy?.$modal.msgSuccess("删除成功");
useDictStore().removeDict(queryParams.value.dictType);
const dictCodes = row?.dictCode || ids.value;
await proxy?.$modal.confirm('是否确认删除字典编码为"' + dictCodes + '"的数据项?');
await delData(dictCodes);
await getList();
proxy?.$modal.msgSuccess("删除成功");
useDictStore().removeDict(queryParams.value.dictType);
}
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download("system/dict/data/export", {
...queryParams.value
}, `dict_data_${new Date().getTime()}.xlsx`);
proxy?.download("system/dict/data/export", {
...queryParams.value
}, `dict_data_${new Date().getTime()}.xlsx`);
}
onMounted(() => {
getTypes(route.params && route.params.dictId as string);
getTypeList();
getTypes(route.params && route.params.dictId as string);
getTypeList();
})
</script>

View File

@ -1,38 +1,40 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="字典名称" prop="dictName">
<el-input v-model="queryParams.dictName" placeholder="请输入字典名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="字典类型" prop="dictType">
<el-input v-model="queryParams.dictType" placeholder="请输入字典类型" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="字典状态" clearable style="width: 240px">
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="创建时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb-[10px]" v-show="showSearch">
<el-card shadow="hover">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="字典名称" prop="dictName">
<el-input v-model="queryParams.dictName" placeholder="请输入字典名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="字典类型" prop="dictType">
<el-input v-model="queryParams.dictType" placeholder="请输入字典类型" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="字典状态" clearable style="width: 240px">
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="创建时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<el-card shadow="hover">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
@ -123,9 +125,7 @@
<script setup name="Dict" lang="ts">
import useDictStore from '@/store/modules/dict'
import { listType, getType, delType, addType, updateType, refreshCache } from "@/api/system/dict/type";
import { ComponentInternalInstance } from "vue";
import { DictTypeForm, DictTypeQuery, DictTypeVO } from "@/api/system/dict/type/types";
import { DateModelType } from 'element-plus';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable"))
@ -139,128 +139,128 @@ const multiple = ref(true);
const total = ref(0);
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
const dictFormRef = ref(ElForm);
const queryFormRef = ref(ElForm);
const dictFormRef = ref<ElFormInstance>();
const queryFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
visible: false,
title: ''
});
const initFormData: DictTypeForm = {
dictId: undefined,
dictName: '',
dictType: '',
status: "0",
remark: ''
dictId: undefined,
dictName: '',
dictType: '',
status: "0",
remark: ''
}
const data = reactive<PageData<DictTypeForm, DictTypeQuery>>({
form: {...initFormData},
queryParams: {
pageNum: 1,
pageSize: 10,
dictName: '',
dictType: '',
status: ''
},
rules: {
dictName: [{ required: true, message: "字典名称不能为空", trigger: "blur" }],
dictType: [{ required: true, message: "字典类型不能为空", trigger: "blur" }]
},
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
dictName: '',
dictType: '',
status: ''
},
rules: {
dictName: [{ required: true, message: "字典名称不能为空", trigger: "blur" }],
dictType: [{ required: true, message: "字典类型不能为空", trigger: "blur" }]
},
});
const { queryParams, form, rules } = toRefs(data);
/** 查询字典类型列表 */
const getList = () => {
loading.value = true;
listType(proxy?.addDateRange(queryParams.value, dateRange.value)).then(res => {
typeList.value = res.rows;
total.value = res.total;
loading.value = false;
});
loading.value = true;
listType(proxy?.addDateRange(queryParams.value, dateRange.value)).then(res => {
typeList.value = res.rows;
total.value = res.total;
loading.value = false;
});
}
/** 取消按钮 */
const cancel = () => {
reset();
dialog.visible = false;
reset();
dialog.visible = false;
}
/** 表单重置 */
const reset = () => {
form.value = {...initFormData};
dictFormRef.value.resetFields();
form.value = { ...initFormData };
dictFormRef.value?.resetFields();
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
const resetQuery = () => {
dateRange.value = ['', ''];
queryFormRef.value.resetFields();
handleQuery();
dateRange.value = ['', ''];
queryFormRef.value?.resetFields();
handleQuery();
}
/** 新增按钮操作 */
const handleAdd = () => {
dialog.visible = true;
dialog.title = "添加字典类型";
nextTick(() => {
reset();
})
dialog.visible = true;
dialog.title = "添加字典类型";
nextTick(() => {
reset();
})
}
/** 多选框选中数据 */
const handleSelectionChange = (selection: DictTypeVO[]) => {
ids.value = selection.map(item => item.dictId);
single.value = selection.length != 1;
multiple.value = !selection.length;
const handleSelectionChange = (selection: DictTypeVO[]) => {
ids.value = selection.map(item => item.dictId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 修改按钮操作 */
const handleUpdate = (row?: DictTypeVO) => {
dialog.visible = true;
dialog.title = "修改字典类型";
const dictId = row?.dictId || ids.value[0];
nextTick(async () => {
reset();
const res = await getType(dictId);
form.value = res.data;
})
dialog.visible = true;
dialog.title = "修改字典类型";
const dictId = row?.dictId || ids.value[0];
nextTick(async () => {
reset();
const res = await getType(dictId);
form.value = res.data;
})
}
/** 提交按钮 */
const submitForm = () => {
dictFormRef.value.validate(async (valid: boolean) => {
if (valid) {
form.value.dictId ? await updateType(form.value) : await addType(form.value);
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
getList();
}
});
dictFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
form.value.dictId ? await updateType(form.value) : await addType(form.value);
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
getList();
}
});
}
/** 删除按钮操作 */
const handleDelete = async (row?: DictTypeVO) => {
const dictIds = row?.dictId || ids.value;
await proxy?.$modal.confirm('是否确认删除字典编号为"' + dictIds + '"的数据项?');
await delType(dictIds);
getList();
proxy?.$modal.msgSuccess("删除成功");
const dictIds = row?.dictId || ids.value;
await proxy?.$modal.confirm('是否确认删除字典编号为"' + dictIds + '"的数据项?');
await delType(dictIds);
getList();
proxy?.$modal.msgSuccess("删除成功");
}
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download("system/dict/type/export", {
...queryParams.value
}, `dict_${new Date().getTime()}.xlsx`);
proxy?.download("system/dict/type/export", {
...queryParams.value
}, `dict_${new Date().getTime()}.xlsx`);
}
/** 刷新缓存按钮操作 */
const handleRefreshCache = async () => {
await refreshCache();
proxy?.$modal.msgSuccess("刷新成功");
useDictStore().cleanDict();
await refreshCache();
proxy?.$modal.msgSuccess("刷新成功");
useDictStore().cleanDict();
}
onMounted(()=>{
getList();
onMounted(() => {
getList();
})
</script>

View File

@ -1,25 +1,27 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
<el-form-item label="菜单名称" prop="menuName">
<el-input v-model="queryParams.menuName" placeholder="请输入菜单名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="菜单状态" clearable>
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb-[10px]" v-show="showSearch">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
<el-form-item label="菜单名称" prop="menuName">
<el-input v-model="queryParams.menuName" placeholder="请输入菜单名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="菜单状态" clearable>
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<el-card shadow="hover">
<template #header>
<el-row :gutter="10">
<el-col :span="1.5">
@ -37,7 +39,6 @@
:data="menuList"
row-key="menuId"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
border
ref="menuTableRef"
:default-expand-all="isExpandAll"
>
@ -262,14 +263,12 @@
<script setup name="Menu" lang="ts">
import { addMenu, delMenu, getMenu, listMenu, updateMenu } from '@/api/system/menu';
import { MenuForm, MenuQuery, MenuVO } from '@/api/system/menu/types';
import { ComponentInternalInstance } from 'vue';
import { MenuTypeEnum } from '@/enums/MenuTypeEnum';
import { ElTable, ElForm } from 'element-plus';
interface MenuOptionsType {
menuId: number;
menuName: string;
children: MenuOptionsType[] | undefined;
menuId: number;
menuName: string;
children: MenuOptionsType[] | undefined;
}
const { proxy } = getCurrentInstance() as ComponentInternalInstance
@ -282,136 +281,136 @@ const menuOptions = ref<MenuOptionsType[]>([])
const isExpandAll = ref(false)
const dialog = reactive<DialogOption>({
visible: false,
title: ''
visible: false,
title: ''
});
const queryFormRef = ref(ElForm);
const menuFormRef = ref(ElForm);
const queryFormRef = ref<ElFormInstance>();
const menuFormRef = ref<ElFormInstance>();
const initFormData = {
path: '',
menuId: undefined,
parentId: 0,
menuName: '',
icon: '',
menuType: MenuTypeEnum.M,
orderNum: 1,
isFrame: "1",
isCache: "0",
visible: "0",
status: "0"
path: '',
menuId: undefined,
parentId: 0,
menuName: '',
icon: '',
menuType: MenuTypeEnum.M,
orderNum: 1,
isFrame: "1",
isCache: "0",
visible: "0",
status: "0"
}
const data = reactive<PageData<MenuForm, MenuQuery>>({
form: { ...initFormData },
queryParams: {
menuName: undefined,
status: undefined
},
rules: {
menuName: [{ required: true, message: "菜单名称不能为空", trigger: "blur" }],
orderNum: [{ required: true, message: "菜单顺序不能为空", trigger: "blur" }],
path: [{ required: true, message: "路由地址不能为空", trigger: "blur" }]
},
form: { ...initFormData },
queryParams: {
menuName: undefined,
status: undefined
},
rules: {
menuName: [{ required: true, message: "菜单名称不能为空", trigger: "blur" }],
orderNum: [{ required: true, message: "菜单顺序不能为空", trigger: "blur" }],
path: [{ required: true, message: "路由地址不能为空", trigger: "blur" }]
},
})
const menuTableRef = ref(ElTable);
const menuTableRef = ref<ElTableInstance>();
const { queryParams, form, rules } = toRefs<PageData<MenuForm, MenuQuery>>(data)
/** 查询菜单列表 */
const getList = async () => {
loading.value = true
const res = await listMenu(queryParams.value);
const data = proxy?.handleTree<MenuVO>(res.data, "menuId")
if (data) {
menuList.value = data
}
loading.value = false
loading.value = true
const res = await listMenu(queryParams.value);
const data = proxy?.handleTree<MenuVO>(res.data, "menuId")
if (data) {
menuList.value = data
}
loading.value = false
}
/** 查询菜单下拉树结构 */
const getTreeselect = async () => {
menuOptions.value = []
const response = await listMenu();
const menu: MenuOptionsType = { menuId: 0, menuName: "主类目", children: [] }
menu.children = proxy?.handleTree<MenuOptionsType>(response.data, "menuId")
menuOptions.value.push(menu)
menuOptions.value = []
const response = await listMenu();
const menu: MenuOptionsType = { menuId: 0, menuName: "主类目", children: [] }
menu.children = proxy?.handleTree<MenuOptionsType>(response.data, "menuId")
menuOptions.value.push(menu)
}
/** 取消按钮 */
const cancel = () => {
reset()
dialog.visible = false
reset()
dialog.visible = false
}
/** 表单重置 */
const reset = () => {
form.value = { ...initFormData };
menuFormRef.value.resetFields();
form.value = { ...initFormData };
menuFormRef.value?.resetFields();
}
/** 搜索按钮操作 */
const handleQuery = () => {
getList();
getList();
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields();
handleQuery();
queryFormRef.value?.resetFields();
handleQuery();
}
/** 新增按钮操作 */
const handleAdd = (row?: MenuVO) => {
dialog.visible = true;
dialog.title = "添加菜单";
getTreeselect();
nextTick(() => {
reset();
row && row.menuId ? form.value.parentId = row.menuId : form.value.parentId = 0;
})
dialog.visible = true;
dialog.title = "添加菜单";
getTreeselect();
nextTick(() => {
reset();
row && row.menuId ? form.value.parentId = row.menuId : form.value.parentId = 0;
})
}
/** 展开/折叠操作 */
const handleToggleExpandAll = () => {
isExpandAll.value = !isExpandAll.value;
toggleExpandAll(menuList.value, isExpandAll.value)
isExpandAll.value = !isExpandAll.value;
toggleExpandAll(menuList.value, isExpandAll.value)
}
/** 展开/折叠所有 */
const toggleExpandAll = (data: MenuVO[], status: boolean) => {
data.forEach((item: MenuVO) => {
menuTableRef.value.toggleRowExpansion(item, status)
if (item.children && item.children.length > 0) toggleExpandAll(item.children, status)
})
data.forEach((item: MenuVO) => {
menuTableRef.value?.toggleRowExpansion(item, status)
if (item.children && item.children.length > 0) toggleExpandAll(item.children, status)
})
}
/** 修改按钮操作 */
const handleUpdate = async (row: MenuVO) => {
await getTreeselect();
dialog.visible = true;
dialog.title = "修改菜单";
await nextTick(async () => {
if (row.menuId) {
const { data } = await getMenu(row.menuId);
reset();
form.value = data;
}
})
await getTreeselect();
dialog.visible = true;
dialog.title = "修改菜单";
await nextTick(async () => {
if (row.menuId) {
const { data } = await getMenu(row.menuId);
reset();
form.value = data;
}
})
}
/** 提交按钮 */
const submitForm = () => {
menuFormRef.value.validate(async (valid: boolean) => {
if (valid) {
form.value.menuId ? await updateMenu(form.value) : await addMenu(form.value);
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
getList();
}
})
menuFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
form.value.menuId ? await updateMenu(form.value) : await addMenu(form.value);
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
await getList();
}
})
}
/** 删除按钮操作 */
const handleDelete = async (row: MenuVO) => {
await proxy?.$modal.confirm('是否确认删除名称为"' + row.menuName + '"的数据项?');
await delMenu(row.menuId);
getList();
proxy?.$modal.msgSuccess("删除成功");
await proxy?.$modal.confirm('是否确认删除名称为"' + row.menuName + '"的数据项?');
await delMenu(row.menuId);
await getList();
proxy?.$modal.msgSuccess("删除成功");
}
onMounted(() => {
getList();
getList();
});
</script>

View File

@ -1,28 +1,30 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="公告标题" prop="noticeTitle">
<el-input v-model="queryParams.noticeTitle" placeholder="请输入公告标题" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="操作人员" prop="createByName">
<el-input v-model="queryParams.createByName" placeholder="请输入操作人员" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="类型" prop="noticeType">
<el-select v-model="queryParams.noticeType" placeholder="公告类型" clearable style="width: 200px">
<el-option v-for="dict in sys_notice_type" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb-[10px]" v-show="showSearch">
<el-card shadow="hover">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="公告标题" prop="noticeTitle">
<el-input v-model="queryParams.noticeTitle" placeholder="请输入公告标题" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="操作人员" prop="createByName">
<el-input v-model="queryParams.createByName" placeholder="请输入操作人员" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="类型" prop="noticeType">
<el-select v-model="queryParams.noticeType" placeholder="公告类型" clearable style="width: 200px">
<el-option v-for="dict in sys_notice_type" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<el-card shadow="hover">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
@ -119,9 +121,7 @@
<script setup name="Notice" lang="ts">
import { listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api/system/notice";
import { ComponentInternalInstance } from "vue";
import { NoticeForm, NoticeQuery, NoticeVO } from "@/api/system/notice/types";
import { ElForm } from 'element-plus';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { sys_notice_status, sys_notice_type } = toRefs<any>(proxy?.useDict("sys_notice_status", "sys_notice_type"));
@ -134,116 +134,116 @@ const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const queryFormRef = ref(ElForm);
const noticeFormRef = ref(ElForm);
const queryFormRef = ref<ElFormInstance>();
const noticeFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
visible: false,
title: ''
});
const initFormData: NoticeForm = {
noticeId: undefined,
noticeTitle: '',
noticeType: '',
noticeContent: '',
status: "0",
remark: '',
createByName: ''
noticeId: undefined,
noticeTitle: '',
noticeType: '',
noticeContent: '',
status: "0",
remark: '',
createByName: ''
}
const data = reactive<PageData<NoticeForm, NoticeQuery>>({
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
noticeTitle: '',
createByName: '',
status: '',
noticeType: ''
},
rules: {
noticeTitle: [{ required: true, message: "公告标题不能为空", trigger: "blur" }],
noticeType: [{ required: true, message: "公告类型不能为空", trigger: "change" }]
},
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
noticeTitle: '',
createByName: '',
status: '',
noticeType: ''
},
rules: {
noticeTitle: [{ required: true, message: "公告标题不能为空", trigger: "blur" }],
noticeType: [{ required: true, message: "公告类型不能为空", trigger: "change" }]
},
});
const { queryParams, form, rules } = toRefs(data);
/** 查询公告列表 */
const getList = async () => {
loading.value = true;
const res = await listNotice(queryParams.value);
noticeList.value = res.rows;
total.value = res.total;
loading.value = false;
loading.value = true;
const res = await listNotice(queryParams.value);
noticeList.value = res.rows;
total.value = res.total;
loading.value = false;
}
/** 取消按钮 */
const cancel = () => {
reset();
dialog.visible = false;
reset();
dialog.visible = false;
}
/** 表单重置 */
const reset = () => {
form.value = { ...initFormData };
noticeFormRef.value.resetFields();
form.value = { ...initFormData };
noticeFormRef.value?.resetFields();
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields();
handleQuery();
queryFormRef.value?.resetFields();
handleQuery();
}
/** 多选框选中数据 */
const handleSelectionChange = (selection: NoticeVO[]) => {
ids.value = selection.map(item => item.noticeId);
single.value = selection.length != 1;
multiple.value = !selection.length;
ids.value = selection.map(item => item.noticeId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
const handleAdd = () => {
dialog.visible = true;
dialog.title = "添加公告";
nextTick(() => {
reset();
})
dialog.visible = true;
dialog.title = "添加公告";
nextTick(() => {
reset();
})
}
/**修改按钮操作 */
const handleUpdate = (row?: NoticeVO) => {
dialog.visible = true;
dialog.title = "修改公告";
nextTick(async () => {
const noticeId = row?.noticeId || ids.value[0];
reset();
const { data } = await getNotice(noticeId);
form.value = data;
})
dialog.visible = true;
dialog.title = "修改公告";
nextTick(async () => {
const noticeId = row?.noticeId || ids.value[0];
reset();
const { data } = await getNotice(noticeId);
form.value = data;
})
}
/** 提交按钮 */
const submitForm = () => {
noticeFormRef.value.validate(async (valid: boolean) => {
if (valid) {
form.value.noticeId ? await updateNotice(form.value) : await addNotice(form.value);
proxy?.$modal.msgSuccess("修改成功");
dialog.visible = false;
getList();
}
});
noticeFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
form.value.noticeId ? await updateNotice(form.value) : await addNotice(form.value);
proxy?.$modal.msgSuccess("修改成功");
dialog.visible = false;
await getList();
}
});
}
/** 删除按钮操作 */
const handleDelete = async (row?: NoticeVO) => {
const noticeIds = row?.noticeId || ids.value
await proxy?.$modal.confirm('是否确认删除公告编号为"' + noticeIds + '"的数据项?');
await delNotice(noticeIds);
getList();
proxy?.$modal.msgSuccess("删除成功");
const noticeIds = row?.noticeId || ids.value
await proxy?.$modal.confirm('是否确认删除公告编号为"' + noticeIds + '"的数据项?');
await delNotice(noticeIds);
await getList();
proxy?.$modal.msgSuccess("删除成功");
}
onMounted(() => {
getList();
getList();
})
</script>
</script>

View File

@ -1,29 +1,31 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="配置key" prop="configKey">
<el-input v-model="queryParams.configKey" placeholder="配置key" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="桶名称" prop="bucketName">
<el-input v-model="queryParams.bucketName" placeholder="请输入桶名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="是否默认" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable style="width: 200px">
<el-option key="0" label="是" value="0" />
<el-option key="1" label="" value="1" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb-[10px]" v-show="showSearch">
<el-card shadow="hover">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="配置key" prop="configKey">
<el-input v-model="queryParams.configKey" placeholder="配置key" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="桶名称" prop="bucketName">
<el-input v-model="queryParams.bucketName" placeholder="请输入桶名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="是否默认" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable style="width: 200px">
<el-option key="0" label="" value="0" />
<el-option key="1" label="否" value="1" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<el-card shadow="hover">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
@ -131,16 +133,14 @@
<script setup name="OssConfig" lang="ts">
import {
listOssConfig,
getOssConfig,
delOssConfig,
addOssConfig,
updateOssConfig,
changeOssConfigStatus
listOssConfig,
getOssConfig,
delOssConfig,
addOssConfig,
updateOssConfig,
changeOssConfigStatus
} from "@/api/system/ossConfig";
import { ComponentInternalInstance } from "vue";
import { OssConfigForm, OssConfigQuery, OssConfigVO } from "@/api/system/ossConfig/types";
import { ElForm } from 'element-plus';
const { proxy } = getCurrentInstance() as ComponentInternalInstance
@ -155,193 +155,193 @@ const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const queryFormRef = ref(ElForm);
const ossConfigFormRef = ref(ElForm);
const queryFormRef = ref<ElFormInstance>();
const ossConfigFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
visible: false,
title: ''
});
// 列显隐信息
const columns = ref<FieldOption[]>([
{ key: 0, label: `主建`, visible: true },
{ key: 1, label: `配置key`, visible: false },
{ key: 2, label: `访问站点`, visible: true },
{ key: 3, label: `自定义域名`, visible: true },
{ key: 4, label: `桶名称`, visible: true },
{ key: 5, label: `前缀`, visible: true },
{ key: 6, label: ``, visible: true },
{ key: 7, label: `桶权限类型`, visible: true },
{ key: 8, label: `状态`, visible: true }
{ key: 0, label: `主建`, visible: true },
{ key: 1, label: `配置key`, visible: false },
{ key: 2, label: `访问站点`, visible: true },
{ key: 3, label: `自定义域名`, visible: true },
{ key: 4, label: `桶名称`, visible: true },
{ key: 5, label: `前缀`, visible: true },
{ key: 6, label: ``, visible: true },
{ key: 7, label: `桶权限类型`, visible: true },
{ key: 8, label: `状态`, visible: true }
]);
const initFormData: OssConfigForm = {
ossConfigId: undefined,
configKey: '',
accessKey: '',
secretKey: '',
bucketName: '',
prefix: '',
endpoint: '',
domain: '',
isHttps: "N",
accessPolicy: "1",
region: '',
status: "1",
remark: '',
ossConfigId: undefined,
configKey: '',
accessKey: '',
secretKey: '',
bucketName: '',
prefix: '',
endpoint: '',
domain: '',
isHttps: "N",
accessPolicy: "1",
region: '',
status: "1",
remark: '',
}
const data = reactive<PageData<OssConfigForm, OssConfigQuery>>({
form: { ...initFormData },
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
configKey: '',
bucketName: '',
status: '',
},
rules: {
configKey: [{ required: true, message: "configKey不能为空", trigger: "blur" },],
accessKey: [
{ required: true, message: "accessKey不能为空", trigger: "blur" },
{
min: 2,
max: 200,
message: "accessKey长度必须介于 2 和 100 之间",
trigger: "blur",
},
],
secretKey: [
{ required: true, message: "secretKey不能为空", trigger: "blur" },
{
min: 2,
max: 100,
message: "secretKey长度必须介于 2 和 100 之间",
trigger: "blur",
},
],
bucketName: [
{ required: true, message: "bucketName不能为空", trigger: "blur" },
{
min: 2,
max: 100,
message: "bucketName长度必须介于 2 和 100 之间",
trigger: "blur",
},
],
endpoint: [
{ required: true, message: "endpoint不能为空", trigger: "blur" },
{
min: 2,
max: 100,
message: "endpoint名称长度必须介于 2 和 100 之间",
trigger: "blur",
},
],
accessPolicy: [{ required: true, message: "accessPolicy不能为空", trigger: "blur" }]
}
form: { ...initFormData },
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
configKey: '',
bucketName: '',
status: '',
},
rules: {
configKey: [{ required: true, message: "configKey不能为空", trigger: "blur" },],
accessKey: [
{ required: true, message: "accessKey不能为空", trigger: "blur" },
{
min: 2,
max: 200,
message: "accessKey长度必须介于 2 和 100 之间",
trigger: "blur",
},
],
secretKey: [
{ required: true, message: "secretKey不能为空", trigger: "blur" },
{
min: 2,
max: 100,
message: "secretKey长度必须介于 2 和 100 之间",
trigger: "blur",
},
],
bucketName: [
{ required: true, message: "bucketName不能为空", trigger: "blur" },
{
min: 2,
max: 100,
message: "bucketName长度必须介于 2 和 100 之间",
trigger: "blur",
},
],
endpoint: [
{ required: true, message: "endpoint不能为空", trigger: "blur" },
{
min: 2,
max: 100,
message: "endpoint名称长度必须介于 2 和 100 之间",
trigger: "blur",
},
],
accessPolicy: [{ required: true, message: "accessPolicy不能为空", trigger: "blur" }]
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询对象存储配置列表 */
const getList = async () => {
loading.value = true;
const res = await listOssConfig(queryParams.value);
ossConfigList.value = res.rows;
total.value = res.total;
loading.value = false;
loading.value = true;
const res = await listOssConfig(queryParams.value);
ossConfigList.value = res.rows;
total.value = res.total;
loading.value = false;
}
/** 取消按钮 */
const cancel = () => {
dialog.visible = false;
reset();
dialog.visible = false;
reset();
}
/** 表单重置 */
const reset = () => {
form.value = { ...initFormData };
ossConfigFormRef.value.resetFields();
form.value = { ...initFormData };
ossConfigFormRef.value?.resetFields();
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields();
handleQuery();
queryFormRef.value?.resetFields();
handleQuery();
}
/** 选择条数 */
const handleSelectionChange = (selection: OssConfigVO[]) => {
ids.value = selection.map(item => item.ossConfigId);
single.value = selection.length != 1;
multiple.value = !selection.length;
ids.value = selection.map(item => item.ossConfigId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
const handleAdd = () => {
dialog.visible = true;
dialog.title = "添加对象存储配置";
nextTick(() => {
reset();
})
dialog.visible = true;
dialog.title = "添加对象存储配置";
nextTick(() => {
reset();
})
}
/** 修改按钮操作 */
const handleUpdate = (row?: OssConfigVO) => {
loading.value = true;
dialog.visible = true;
dialog.title = "修改对象存储配置";
const ossConfigId = row?.ossConfigId || ids.value[0];
nextTick(async () => {
reset();
const res = await getOssConfig(ossConfigId);
loading.value = false;
form.value = res.data;
})
loading.value = true;
dialog.visible = true;
dialog.title = "修改对象存储配置";
const ossConfigId = row?.ossConfigId || ids.value[0];
nextTick(async () => {
reset();
const res = await getOssConfig(ossConfigId);
loading.value = false;
form.value = res.data;
})
}
/** 提交按钮 */
const submitForm = () => {
ossConfigFormRef.value.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (form.value.ossConfigId) {
await updateOssConfig(form.value).finally(() => buttonLoading.value = false);
} else {
await addOssConfig(form.value).finally(() => buttonLoading.value = false);
}
proxy?.$modal.msgSuccess("新增成功");
dialog.visible = false;
getList();
}
});
ossConfigFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (form.value.ossConfigId) {
await updateOssConfig(form.value).finally(() => buttonLoading.value = false);
} else {
await addOssConfig(form.value).finally(() => buttonLoading.value = false);
}
proxy?.$modal.msgSuccess("新增成功");
dialog.visible = false;
getList();
}
});
}
/** 状态修改 */
const handleStatusChange = async (row: OssConfigVO) => {
let text = row.status === "0" ? "启用" : "停用";
try {
await proxy?.$modal.confirm('确认要"' + text + '""' + row.configKey + '"配置吗?');
await changeOssConfigStatus(row.ossConfigId, row.status, row.configKey);
getList()
proxy?.$modal.msgSuccess(text + "成功");
} catch { return } finally {
row.status = row.status === "0" ? "1" : "0";
}
const handleStatusChange = async (row: OssConfigVO) => {
let text = row.status === "0" ? "启用" : "停用";
try {
await proxy?.$modal.confirm('确认要"' + text + '""' + row.configKey + '"配置吗?');
await changeOssConfigStatus(row.ossConfigId, row.status, row.configKey);
getList()
proxy?.$modal.msgSuccess(text + "成功");
} catch { return } finally {
row.status = row.status === "0" ? "1" : "0";
}
}
/** 删除按钮操作 */
const handleDelete = async (row?: OssConfigVO) => {
const ossConfigIds = row?.ossConfigId || ids.value;
await proxy?.$modal.confirm('是否确认删除OSS配置编号为"' + ossConfigIds + '"的数据项?');
loading.value = true;
await delOssConfig(ossConfigIds).finally(() => loading.value = false);
getList();
proxy?.$modal.msgSuccess("删除成功");
const ossConfigIds = row?.ossConfigId || ids.value;
await proxy?.$modal.confirm('是否确认删除OSS配置编号为"' + ossConfigIds + '"的数据项?');
loading.value = true;
await delOssConfig(ossConfigIds).finally(() => loading.value = false);
getList();
proxy?.$modal.msgSuccess("删除成功");
}
onMounted(() => {
getList();
getList();
})
</script>
</script>

View File

@ -1,40 +1,42 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="文件名" prop="fileName">
<el-input v-model="queryParams.fileName" placeholder="请输入文件名" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="原名" prop="originalName">
<el-input v-model="queryParams.originalName" placeholder="请输入原名" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="文件后缀" prop="fileSuffix">
<el-input v-model="queryParams.fileSuffix" placeholder="请输入文件后缀" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker
v-model="daterangeCreateTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item label="服务商" prop="service">
<el-input v-model="queryParams.service" placeholder="请输入服务商" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb-[10px]" v-show="showSearch">
<el-card shadow="hover">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="文件名" prop="fileName">
<el-input v-model="queryParams.fileName" placeholder="请输入文件名" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="原名" prop="originalName">
<el-input v-model="queryParams.originalName" placeholder="请输入原名" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="文件后缀" prop="fileSuffix">
<el-input v-model="queryParams.fileSuffix" placeholder="请输入文件后缀" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker
v-model="daterangeCreateTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item label="服务商" prop="service">
<el-input v-model="queryParams.service" placeholder="请输入服务商" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<el-card shadow="hover">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
@ -133,9 +135,7 @@
<script setup name="Oss" lang="ts">
import { listOss, delOss } from "@/api/system/oss";
import ImagePreview from "@/components/ImagePreview/index.vue";
import { ComponentInternalInstance } from "vue";
import { OssForm, OssQuery, OssVO } from "@/api/system/oss/types";
import { DateModelType } from 'element-plus';
const router = useRouter();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -154,186 +154,186 @@ const previewListResource = ref(true);
const daterangeCreateTime = ref<[DateModelType, DateModelType]>(['', '']);
const dialog = reactive<DialogOption>({
visible: false,
title: ''
visible: false,
title: ''
});
// 默认排序
const defaultSort = ref({ prop: 'createTime', order: 'ascending' });
const ossFormRef = ref(ElForm);
const queryFormRef = ref(ElForm);
const ossFormRef = ref<ElFormInstance>();
const queryFormRef = ref<ElFormInstance>();
const initFormData = {
file: undefined,
file: undefined,
}
const data = reactive<PageData<OssForm, OssQuery>>({
form: { ...initFormData },
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
fileName: '',
originalName: '',
fileSuffix: '',
createTime: '',
service: '',
orderByColumn: defaultSort.value.prop,
isAsc: defaultSort.value.order
},
rules: {
file: [
{ required: true, message: "文件不能为空", trigger: "blur" }
]
}
form: { ...initFormData },
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
fileName: '',
originalName: '',
fileSuffix: '',
createTime: '',
service: '',
orderByColumn: defaultSort.value.prop,
isAsc: defaultSort.value.order
},
rules: {
file: [
{ required: true, message: "文件不能为空", trigger: "blur" }
]
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询OSS对象存储列表 */
const getList = async () => {
loading.value = true;
const res = await proxy?.getConfigKey("sys.oss.previewListResource");
previewListResource.value = res?.msg === undefined ? true : res.msg === 'true';
const response = await listOss(proxy?.addDateRange(queryParams.value, daterangeCreateTime.value, "CreateTime"));
ossList.value = response.rows;
total.value = response.total;
loading.value = false;
showTable.value = true;
loading.value = true;
const res = await proxy?.getConfigKey("sys.oss.previewListResource");
previewListResource.value = res?.msg === undefined ? true : res.msg === 'true';
const response = await listOss(proxy?.addDateRange(queryParams.value, daterangeCreateTime.value, "CreateTime"));
ossList.value = response.rows;
total.value = response.total;
loading.value = false;
showTable.value = true;
}
function checkFileSuffix(fileSuffix: string[]) {
let arr = ["png", "jpg", "jpeg"];
return arr.some(type => {
return fileSuffix.indexOf(type) > -1;
});
let arr = ["png", "jpg", "jpeg"];
return arr.some(type => {
return fileSuffix.indexOf(type) > -1;
});
}
/** 取消按钮 */
function cancel() {
dialog.visible = false;
reset();
dialog.visible = false;
reset();
}
/** 表单重置 */
function reset() {
form.value = { ...initFormData };
ossFormRef.value.resetFields();
form.value = { ...initFormData };
ossFormRef.value?.resetFields();
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
showTable.value = false;
daterangeCreateTime.value = ['', ''];
queryFormRef.value.resetFields();
queryParams.value.orderByColumn = defaultSort.value.prop;
queryParams.value.isAsc = defaultSort.value.order;
handleQuery();
showTable.value = false;
daterangeCreateTime.value = ['', ''];
queryFormRef.value?.resetFields();
queryParams.value.orderByColumn = defaultSort.value.prop;
queryParams.value.isAsc = defaultSort.value.order;
handleQuery();
}
/** 选择条数 */
function handleSelectionChange(selection: OssVO[]) {
ids.value = selection.map(item => item.ossId);
single.value = selection.length != 1;
multiple.value = !selection.length;
ids.value = selection.map(item => item.ossId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 设置列的排序为我们自定义的排序 */
const handleHeaderClass = ({ column }: any): any => {
column.order = column.multiOrder
column.order = column.multiOrder
}
/** 点击表头进行排序 */
const handleHeaderCLick = (column: any) => {
if (column.sortable !== 'custom') {
return
}
switch (column.multiOrder) {
case 'descending':
column.multiOrder = 'ascending';
break;
case 'ascending':
column.multiOrder = '';
break;
default:
column.multiOrder = 'descending';
break;
}
handleOrderChange(column.property, column.multiOrder)
if (column.sortable !== 'custom') {
return
}
switch (column.multiOrder) {
case 'descending':
column.multiOrder = 'ascending';
break;
case 'ascending':
column.multiOrder = '';
break;
default:
column.multiOrder = 'descending';
break;
}
handleOrderChange(column.property, column.multiOrder)
}
const handleOrderChange = (prop: string, order: string) => {
let orderByArr = queryParams.value.orderByColumn ? queryParams.value.orderByColumn.split(",") : [];
let isAscArr = queryParams.value.isAsc ? queryParams.value.isAsc.split(",") : [];
let propIndex = orderByArr.indexOf(prop)
if (propIndex !== -1) {
if (order) {
//排序里已存在 只修改排序
isAscArr[propIndex] = order;
} else {
//如果order为null 则删除排序字段和属性
isAscArr.splice(propIndex, 1);//删除排序
orderByArr.splice(propIndex, 1);//删除属性
}
let orderByArr = queryParams.value.orderByColumn ? queryParams.value.orderByColumn.split(",") : [];
let isAscArr = queryParams.value.isAsc ? queryParams.value.isAsc.split(",") : [];
let propIndex = orderByArr.indexOf(prop)
if (propIndex !== -1) {
if (order) {
//排序里已存在 只修改排序
isAscArr[propIndex] = order;
} else {
//排序里不存在则新增排序
orderByArr.push(prop);
isAscArr.push(order);
//如果order为null 则删除排序字段和属性
isAscArr.splice(propIndex, 1);//删除排序
orderByArr.splice(propIndex, 1);//删除属性
}
//合并排序
queryParams.value.orderByColumn = orderByArr.join(",");
queryParams.value.isAsc = isAscArr.join(",");
getList();
} else {
//排序里不存在则新增排序
orderByArr.push(prop);
isAscArr.push(order);
}
//合并排序
queryParams.value.orderByColumn = orderByArr.join(",");
queryParams.value.isAsc = isAscArr.join(",");
getList();
}
/** 任务日志列表查询 */
const handleOssConfig = () => {
router.push('/system/oss-config/index')
router.push('/system/oss-config/index')
}
/** 文件按钮操作 */
const handleFile = () => {
dialog.visible = true;
dialog.title = "上传文件";
nextTick(() => {
reset();
type.value = 0;
})
dialog.visible = true;
dialog.title = "上传文件";
nextTick(() => {
reset();
type.value = 0;
})
}
/** 图片按钮操作 */
const handleImage = () => {
dialog.visible = true;
dialog.title = "上传图片";
nextTick(() => {
reset();
type.value = 1;
})
dialog.visible = true;
dialog.title = "上传图片";
nextTick(() => {
reset();
type.value = 1;
})
}
/** 提交按钮 */
const submitForm = () => {
dialog.visible = false;
getList();
dialog.visible = false;
getList();
}
/** 下载按钮操作 */
const handleDownload = (row: OssVO) => {
proxy?.$download.oss(row.ossId)
proxy?.$download.oss(row.ossId)
}
/** 用户状态修改 */
const handlePreviewListResource = async (preview: boolean) => {
let text = preview ? "启用" : "停用";
try {
await proxy?.$modal.confirm('确认要"' + text + '""预览列表图片"配置吗?');
await proxy?.updateConfigByKey("sys.oss.previewListResource", preview);
getList()
proxy?.$modal.msgSuccess(text + "成功");
} catch { return }
let text = preview ? "启用" : "停用";
try {
await proxy?.$modal.confirm('确认要"' + text + '""预览列表图片"配置吗?');
await proxy?.updateConfigByKey("sys.oss.previewListResource", preview);
getList()
proxy?.$modal.msgSuccess(text + "成功");
} catch { return }
}
/** 删除按钮操作 */
const handleDelete = async (row?: OssVO) => {
const ossIds = row?.ossId || ids.value;
await proxy?.$modal.confirm('是否确认删除OSS对象存储编号为"' + ossIds + '"的数据项?');
loading.value = true;
await delOss(ossIds).finally(() => loading.value = false);
getList();
proxy?.$modal.msgSuccess("删除成功");
const ossIds = row?.ossId || ids.value;
await proxy?.$modal.confirm('是否确认删除OSS对象存储编号为"' + ossIds + '"的数据项?');
loading.value = true;
await delOss(ossIds).finally(() => loading.value = false);
getList();
proxy?.$modal.msgSuccess("删除成功");
}
onMounted(() => {
getList();
getList();
})
</script>

View File

@ -1,27 +1,29 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="70">
<el-form-item label="岗位编码" prop="postCode">
<el-input v-model="queryParams.postCode" placeholder="请输入岗位编码" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="岗位名称" prop="postName">
<el-input v-model="queryParams.postName" placeholder="请输入岗位名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="岗位状态" clearable style="width: 200px">
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb-[10px]" v-show="showSearch">
<el-card shadow="hover">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="70">
<el-form-item label="岗位编码" prop="postCode">
<el-input v-model="queryParams.postCode" placeholder="请输入岗位编码" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="岗位名称" prop="postName">
<el-input v-model="queryParams.postName" placeholder="请输入岗位名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="岗位状态" clearable style="width: 200px">
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<el-card shadow="hover">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
@ -107,7 +109,6 @@
<script setup name="Post" lang="ts">
import { listPost, addPost, delPost, getPost, updatePost } from "@/api/system/post";
import { PostForm, PostQuery, PostVO } from "@/api/system/post/types";
import { ComponentInternalInstance } from "vue";
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable"));
@ -120,121 +121,121 @@ const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const postFormRef = ref(ElForm);
const queryFormRef = ref(ElForm);
const postFormRef = ref<ElFormInstance>();
const queryFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
visible: false,
title: ''
});
const initFormData: PostForm = {
postId: undefined,
postCode: '',
postName: '',
postSort: 0,
status: "0",
remark: ''
postId: undefined,
postCode: '',
postName: '',
postSort: 0,
status: "0",
remark: ''
}
const data = reactive<PageData<PostForm, PostQuery>>({
form: {...initFormData},
queryParams: {
pageNum: 1,
pageSize: 10,
postCode: '',
postName: '',
status: ''
},
rules: {
postName: [{ required: true, message: "岗位名称不能为空", trigger: "blur" }],
postCode: [{ required: true, message: "岗位编码不能为空", trigger: "blur" }],
postSort: [{ required: true, message: "岗位顺序不能为空", trigger: "blur" }],
}
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
postCode: '',
postName: '',
status: ''
},
rules: {
postName: [{ required: true, message: "岗位名称不能为空", trigger: "blur" }],
postCode: [{ required: true, message: "岗位编码不能为空", trigger: "blur" }],
postSort: [{ required: true, message: "岗位顺序不能为空", trigger: "blur" }],
}
});
const { queryParams, form, rules } = toRefs<PageData<PostForm, PostQuery>>(data);
/** 查询岗位列表 */
const getList = async () => {
loading.value = true;
const res = await listPost(queryParams.value);
postList.value = res.rows;
total.value = res.total;
loading.value = false;
loading.value = true;
const res = await listPost(queryParams.value);
postList.value = res.rows;
total.value = res.total;
loading.value = false;
}
/** 取消按钮 */
const cancel = () => {
reset();
dialog.visible = false;
reset();
dialog.visible = false;
}
/** 表单重置 */
const reset = () => {
form.value = {...initFormData};
postFormRef.value.resetFields();
form.value = { ...initFormData };
postFormRef.value?.resetFields();
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields();
handleQuery();
queryFormRef.value?.resetFields();
handleQuery();
}
/** 多选框选中数据 */
const handleSelectionChange = (selection: PostVO[]) => {
ids.value = selection.map(item => item.postId);
single.value = selection.length != 1;
multiple.value = !selection.length;
ids.value = selection.map(item => item.postId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
const handleAdd = () => {
dialog.visible = true;
dialog.title = "添加岗位";
nextTick(() => {
reset();
})
dialog.visible = true;
dialog.title = "添加岗位";
nextTick(() => {
reset();
})
}
/** 修改按钮操作 */
const handleUpdate = (row?: PostVO) => {
dialog.visible = true;
dialog.title = "修改岗位";
nextTick(async () => {
reset();
const postId = row?.postId || ids.value[0];
const res = await getPost(postId);
form.value = res.data;
})
dialog.visible = true;
dialog.title = "修改岗位";
nextTick(async () => {
reset();
const postId = row?.postId || ids.value[0];
const res = await getPost(postId);
form.value = res.data;
})
}
/** 提交按钮 */
const submitForm = () => {
postFormRef.value.validate(async (valid: boolean) => {
if (valid) {
form.value.postId ? await updatePost(form.value) : await addPost(form.value);
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
getList();
}
});
postFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
form.value.postId ? await updatePost(form.value) : await addPost(form.value);
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
await getList();
}
});
}
/** 删除按钮操作 */
const handleDelete = async (row?: PostVO) => {
const postIds = row?.postId || ids.value;
await proxy?.$modal.confirm('是否确认删除岗位编号为"' + postIds + '"的数据项?');
await delPost(postIds);
getList();
proxy?.$modal.msgSuccess("删除成功");
const postIds = row?.postId || ids.value;
await proxy?.$modal.confirm('是否确认删除岗位编号为"' + postIds + '"的数据项?');
await delPost(postIds);
await getList();
proxy?.$modal.msgSuccess("删除成功");
}
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download("system/post/export", {
...queryParams.value
}, `post_${new Date().getTime()}.xlsx`);
proxy?.download("system/post/export", {
...queryParams.value
}, `post_${new Date().getTime()}.xlsx`);
}
onMounted(() => {
getList();
getList();
});
</script>

View File

@ -58,13 +58,7 @@
</el-table-column>
</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" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
<select-user ref="selectRef" :roleId="queryParams.roleId" @ok="handleQuery" />
</el-card>
</div>
@ -73,10 +67,8 @@
<script setup name="AuthUser" lang="ts">
import { allocatedUserList, authUserCancel, authUserCancelAll } from "@/api/system/role";
import { UserQuery } from "@/api/system/user/types";
import { ComponentInternalInstance } from "vue";
import { UserVO } from "@/api/system/user/types";
import SelectUser from "./selectUser.vue";
// import { ElForm, ElSelect} from 'element-plus';
const route = useRoute();
@ -90,68 +82,68 @@ const multiple = ref(true);
const total = ref(0);
const userIds = ref<Array<string | number>>([]);
const queryFormRef = ref(ElForm);
const selectRef = ref(SelectUser);
const queryFormRef = ref<ElFormInstance>();
const selectRef = ref<InstanceType<typeof SelectUser>>();
const queryParams = reactive<UserQuery>({
pageNum: 1,
pageSize: 10,
roleId: route.params.roleId as string,
userName: undefined,
phonenumber: undefined,
pageNum: 1,
pageSize: 10,
roleId: route.params.roleId as string,
userName: undefined,
phonenumber: undefined,
});
/** 查询授权用户列表 */
const getList = async () => {
loading.value = true;
const res = await allocatedUserList(queryParams);
userList.value = res.rows;
total.value = res.total;
loading.value = false;
loading.value = true;
const res = await allocatedUserList(queryParams);
userList.value = res.rows;
total.value = res.total;
loading.value = false;
}
// 返回按钮
const handleClose = () => {
const obj = { path: "/system/role" };
proxy?.$tab.closeOpenPage(obj);
const obj = { path: "/system/role" };
proxy?.$tab.closeOpenPage(obj);
}
/** 搜索按钮操作 */
const handleQuery=() => {
queryParams.pageNum = 1;
getList();
const handleQuery = () => {
queryParams.pageNum = 1;
getList();
}
/** 重置按钮操作 */
const resetQuery=() =>{
queryFormRef.value.resetFields();
handleQuery();
const resetQuery = () => {
queryFormRef.value?.resetFields();
handleQuery();
}
// 多选框选中数据
const handleSelectionChange = (selection: UserVO[]) =>{
userIds.value = selection.map(item => item.userId);
multiple.value = !selection.length;
const handleSelectionChange = (selection: UserVO[]) => {
userIds.value = selection.map(item => item.userId);
multiple.value = !selection.length;
}
/** 打开授权用户表弹窗 */
const openSelectUser = () => {
selectRef.value.show();
selectRef.value?.show();
}
/** 取消授权按钮操作 */
const cancelAuthUser = async (row: UserVO) => {
await proxy?.$modal.confirm('确认要取消该用户"' + row.userName + '"角色吗?');
await authUserCancel({ userId: row.userId, roleId: queryParams.roleId });
getList();
proxy?.$modal.msgSuccess("取消授权成功");
await proxy?.$modal.confirm('确认要取消该用户"' + row.userName + '"角色吗?');
await authUserCancel({ userId: row.userId, roleId: queryParams.roleId });
await getList();
proxy?.$modal.msgSuccess("取消授权成功");
}
/** 批量取消授权按钮操作 */
const cancelAuthUserAll = async () => {
const roleId = queryParams.roleId;
const uIds = userIds.value.join(",");
await proxy?.$modal.confirm("是否取消选中用户授权数据项?");
await authUserCancelAll({ roleId: roleId, userIds: uIds });
getList();
proxy?.$modal.msgSuccess("取消授权成功");
const roleId = queryParams.roleId;
const uIds = userIds.value.join(",");
await proxy?.$modal.confirm("是否取消选中用户授权数据项?");
await authUserCancelAll({ roleId: roleId, userIds: uIds });
await getList();
proxy?.$modal.msgSuccess("取消授权成功");
}
onMounted(() => {
getList();
getList();
});
</script>

View File

@ -1,40 +1,42 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
<el-form-item label="角色名称" prop="roleName">
<el-input v-model="queryParams.roleName" placeholder="请输入角色名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="权限字符" prop="roleKey">
<el-input v-model="queryParams.roleKey" placeholder="请输入权限字符" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="角色状态" clearable style="width: 240px">
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="创建时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<div class="mb-[10px]" v-show="showSearch">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
<el-form-item label="角色名称" prop="roleName">
<el-input v-model="queryParams.roleName" placeholder="请输入角色名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="权限字符" prop="roleKey">
<el-input v-model="queryParams.roleKey" placeholder="请输入权限字符" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="角色状态" clearable style="width: 240px">
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="创建时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleQuery" icon="Search">搜索</el-button>
<el-button @click="resetQuery" icon="Refresh">重置</el-button>
</el-form-item>
</el-form>
<el-form-item>
<el-button type="primary" @click="handleQuery" icon="Search">搜索</el-button>
<el-button @click="resetQuery" icon="Refresh">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<el-card shadow="hover">
<template #header>
<el-row :gutter="10">
<el-col :span="1.5">
@ -119,7 +121,7 @@
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{
dict.label
dict.label
}}</el-radio>
</el-radio-group>
</el-form-item>
@ -196,8 +198,6 @@ import { addRole, changeRoleStatus, dataScope, delRole, getRole, listRole, updat
import { roleMenuTreeselect, treeselect as menuTreeselect } from '@/api/system/menu/index';
import { RoleVO, RoleForm, RoleQuery, DeptTreeOption } from '@/api/system/role/types';
import { MenuTreeOption, RoleMenuTree } from '@/api/system/menu/types';
import { ComponentInternalInstance } from 'vue';
import { ElTree, ElForm, DateModelType } from 'element-plus';
const router = useRouter();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -221,54 +221,54 @@ const openDataScope = ref(false)
/** 数据范围选项*/
const dataScopeOptions = ref([
{ value: "1", label: "全部数据权限" },
{ value: "2", label: "自定数据权限" },
{ value: "3", label: "本部门数据权限" },
{ value: "4", label: "本部门及以下数据权限" },
{ value: "5", label: "仅本人数据权限" }
{ value: "1", label: "全部数据权限" },
{ value: "2", label: "自定数据权限" },
{ value: "3", label: "本部门数据权限" },
{ value: "4", label: "本部门及以下数据权限" },
{ value: "5", label: "仅本人数据权限" }
])
const queryFormRef = ref(ElForm);
const roleFormRef = ref(ElForm);
const dataScopeRef = ref(ElForm);
const menuRef = ref(ElTree);
const deptRef = ref(ElTree);
const queryFormRef = ref<ElFormInstance>();
const roleFormRef = ref<ElFormInstance>();
const dataScopeRef = ref<ElFormInstance>();
const menuRef = ref<ElTreeInstance>();
const deptRef = ref<ElTreeInstance>();
const initForm: RoleForm = {
roleId: undefined,
roleSort: 1,
status: '0',
roleName: '',
roleKey: '',
menuCheckStrictly: true,
deptCheckStrictly: true,
remark: '',
dataScope: '1',
menuIds: [],
deptIds: [],
roleId: undefined,
roleSort: 1,
status: '0',
roleName: '',
roleKey: '',
menuCheckStrictly: true,
deptCheckStrictly: true,
remark: '',
dataScope: '1',
menuIds: [],
deptIds: [],
}
const data = reactive<PageData<RoleForm, RoleQuery>>({
form: {...initForm},
queryParams: {
pageNum: 1,
pageSize: 10,
roleName: '',
roleKey: '',
status: '',
},
rules: {
roleName: [{ required: true, message: "角色名称不能为空", trigger: "blur" }],
roleKey: [{ required: true, message: "权限字符不能为空", trigger: "blur" }],
roleSort: [{ required: true, message: "角色顺序不能为空", trigger: "blur" }]
}
form: { ...initForm },
queryParams: {
pageNum: 1,
pageSize: 10,
roleName: '',
roleKey: '',
status: '',
},
rules: {
roleName: [{ required: true, message: "角色名称不能为空", trigger: "blur" }],
roleKey: [{ required: true, message: "权限字符不能为空", trigger: "blur" }],
roleSort: [{ required: true, message: "角色顺序不能为空", trigger: "blur" }]
}
})
const { form, queryParams, rules } = toRefs(data)
const dialog = reactive<DialogOption>({
visible: false,
title: ''
visible: false,
title: ''
});
@ -276,233 +276,241 @@ const dialog = reactive<DialogOption>({
* 查询角色列表
*/
const getList = () => {
loading.value = true
listRole(proxy?.addDateRange(queryParams.value, dateRange.value)).then(res => {
roleList.value = res.rows
total.value = res.total
loading.value = false
})
loading.value = true
listRole(proxy?.addDateRange(queryParams.value, dateRange.value)).then(res => {
roleList.value = res.rows
total.value = res.total
loading.value = false
})
}
/**
* 搜索按钮操作
*/
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
queryParams.value.pageNum = 1;
getList();
}
/** 重置 */
const resetQuery = () => {
dateRange.value = ['', '']
queryFormRef.value.resetFields();
handleQuery();
dateRange.value = ['', '']
queryFormRef.value?.resetFields();
handleQuery();
}
/**删除按钮操作 */
const handleDelete = async (row?: RoleVO) => {
const roleids = row?.roleId || ids.value;
await proxy?.$modal.confirm('是否确认删除角色编号为' + roleids + '数据项目');
await delRole(roleids);
getList();
proxy?.$modal.msgSuccess('删除成功');
const roleids = row?.roleId || ids.value;
await proxy?.$modal.confirm('是否确认删除角色编号为' + roleids + '数据项目');
await delRole(roleids);
getList();
proxy?.$modal.msgSuccess('删除成功');
}
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download("system/role/export", {
...queryParams.value,
}, `role_${new Date().getTime()}.xlsx`)
proxy?.download("system/role/export", {
...queryParams.value,
}, `role_${new Date().getTime()}.xlsx`)
}
/** 多选框选中数据 */
const handleSelectionChange = (selection: RoleVO[]) => {
ids.value = selection.map((item: RoleVO) => item.roleId);
single.value = selection.length != 1;
multiple.value = !selection.length;
ids.value = selection.map((item: RoleVO) => item.roleId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 角色状态修改 */
const handleStatusChange = async (row: RoleVO) => {
let text = row.status === "0" ? "启用" : "停用";
try {
await proxy?.$modal.confirm('确认要"' + text + '""' + row.roleName + '"角色吗?');
await changeRoleStatus(row.roleId, row.status);
proxy?.$modal.msgSuccess(text + "成功");
} catch {
row.status = row.status === "0" ? "1" : "0";
}
let text = row.status === "0" ? "启用" : "停用";
try {
await proxy?.$modal.confirm('确认要"' + text + '""' + row.roleName + '"角色吗?');
await changeRoleStatus(row.roleId, row.status);
proxy?.$modal.msgSuccess(text + "成功");
} catch {
row.status = row.status === "0" ? "1" : "0";
}
}
/** 分配用户 */
const handleAuthUser = (row: RoleVO) => {
router.push("/system/role-auth/user/" + row.roleId);
router.push("/system/role-auth/user/" + row.roleId);
}
/** 查询菜单树结构 */
const getMenuTreeselect = async () => {
const res = await menuTreeselect();
menuOptions.value = res.data;
const res = await menuTreeselect();
menuOptions.value = res.data;
}
/** 所有部门节点数据 */
const getDeptAllCheckedKeys = () => {
// 目前被选中的部门节点
let checkedKeys = deptRef.value.getCheckedKeys();
// 半选中的部门节点
let halfCheckedKeys = deptRef.value.getHalfCheckedKeys();
checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
return checkedKeys
const getDeptAllCheckedKeys = (): any => {
// 目前被选中的部门节点
let checkedKeys = deptRef.value?.getCheckedKeys();
// 半选中的部门节点
let halfCheckedKeys = deptRef.value?.getHalfCheckedKeys();
if (halfCheckedKeys) {
checkedKeys?.unshift.apply(checkedKeys, halfCheckedKeys);
}
return checkedKeys
}
/** 重置新增的表单以及其他数据 */
const reset = () => {
menuRef.value.setCheckedKeys([]);
menuExpand.value = false
menuNodeAll.value = false
deptExpand.value = true
deptNodeAll.value = false
form.value = { ...initForm };
roleFormRef.value.resetFields();
menuRef.value?.setCheckedKeys([]);
menuExpand.value = false
menuNodeAll.value = false
deptExpand.value = true
deptNodeAll.value = false
form.value = { ...initForm };
roleFormRef.value?.resetFields();
}
/** 添加角色 */
const handleAdd = () => {
dialog.visible = true;
dialog.title = "添加角色";
nextTick(() => {
reset();
getMenuTreeselect();
})
dialog.visible = true;
dialog.title = "添加角色";
nextTick(() => {
reset();
getMenuTreeselect();
})
}
/** 修改角色 */
const handleUpdate = async (row?: RoleVO) => {
const roleId = row?.roleId || ids.value[0]
const roleMenu = getRoleMenuTreeselect(roleId)
const { data } = await getRole(roleId);
dialog.visible = true;
dialog.title = "修改角色";
nextTick(() => {
reset();
Object.assign(form.value, data);
form.value.roleSort = Number(form.value.roleSort);
nextTick(async () => {
const res = await roleMenu;
let checkedKeys = res.checkedKeys;
checkedKeys.forEach((v) => {
nextTick(() => {
menuRef.value.setChecked(v, true, false);
})
})
const roleId = row?.roleId || ids.value[0]
const roleMenu = getRoleMenuTreeselect(roleId)
const { data } = await getRole(roleId);
dialog.visible = true;
dialog.title = "修改角色";
await nextTick(() => {
reset();
Object.assign(form.value, data);
form.value.roleSort = Number(form.value.roleSort);
nextTick(async () => {
const res = await roleMenu;
let checkedKeys = res.checkedKeys;
checkedKeys.forEach((v) => {
nextTick(() => {
menuRef.value?.setChecked(v, true, false);
})
})
})
})
}
/** 根据角色ID查询菜单树结构 */
const getRoleMenuTreeselect = (roleId: string | number) => {
return roleMenuTreeselect(roleId).then((res): RoleMenuTree => {
menuOptions.value = res.data.menus;
return res.data;
})
return roleMenuTreeselect(roleId).then((res): RoleMenuTree => {
menuOptions.value = res.data.menus;
return res.data;
})
}
/** 根据角色ID查询部门树结构 */
const getRoleDeptTreeSelect = async (roleId: string | number) => {
const res = await deptTreeSelect(roleId);
deptOptions.value = res.data.depts;
return res.data;
const res = await deptTreeSelect(roleId);
deptOptions.value = res.data.depts;
return res.data;
}
/** 树权限(展开/折叠)*/
const handleCheckedTreeExpand = (value: any, type: string) => {
if (type == "menu") {
let treeList = menuOptions.value;
for (let i = 0; i < treeList.length; i++) {
menuRef.value.store.nodesMap[treeList[i].id].expanded = value;
}
} else if (type == "dept") {
let treeList = deptOptions.value;
for (let i = 0; i < treeList.length; i++) {
deptRef.value.store.nodesMap[treeList[i].id].expanded = value;
}
const handleCheckedTreeExpand = (value: boolean, type: string) => {
if (type == "menu") {
let treeList = menuOptions.value;
for (let i = 0; i < treeList.length; i++) {
if (menuRef.value) {
menuRef.value.store.nodesMap[treeList[i].id].expanded = value;
}
}
} else if (type == "dept") {
let treeList = deptOptions.value;
for (let i = 0; i < treeList.length; i++) {
if (deptRef.value) {
deptRef.value.store.nodesMap[treeList[i].id].expanded = value;
}
}
}
}
/** 树权限(全选/全不选) */
const handleCheckedTreeNodeAll = (value: any, type: string) => {
if (type == "menu") {
menuRef.value.setCheckedNodes(value ? menuOptions.value : []);
} else if (type == "dept") {
deptRef.value.setCheckedNodes(value ? deptOptions.value : []);
}
if (type == "menu") {
menuRef.value?.setCheckedNodes(value ? menuOptions.value as any : []);
} else if (type == "dept") {
deptRef.value?.setCheckedNodes(value ? deptOptions.value as any : []);
}
}
/** 树权限(父子联动) */
const handleCheckedTreeConnect = (value: any, type: string) => {
if (type == "menu") {
form.value.menuCheckStrictly = value;
} else if (type == "dept") {
form.value.deptCheckStrictly = value;
}
if (type == "menu") {
form.value.menuCheckStrictly = value;
} else if (type == "dept") {
form.value.deptCheckStrictly = value;
}
}
/** 所有菜单节点数据 */
const getMenuAllCheckedKeys = () => {
// 目前被选中的菜单节点
let checkedKeys = menuRef.value.getCheckedKeys();
// 半选中的菜单节点
let halfCheckedKeys = menuRef.value.getHalfCheckedKeys();
checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
return checkedKeys;
const getMenuAllCheckedKeys = (): any => {
// 目前被选中的菜单节点
let checkedKeys = menuRef.value?.getCheckedKeys();
// 半选中的菜单节点
let halfCheckedKeys = menuRef.value?.getHalfCheckedKeys();
if (halfCheckedKeys) {
checkedKeys?.unshift.apply(checkedKeys, halfCheckedKeys);
}
return checkedKeys;
}
/** 提交按钮 */
const submitForm = () => {
roleFormRef.value.validate(async (valid: boolean) => {
if (valid) {
form.value.menuIds = getMenuAllCheckedKeys()
form.value.roleId ? await updateRole(form.value) : await addRole(form.value);
proxy?.$modal.msgSuccess("操作成功")
dialog.visible = false
getList()
}
})
roleFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
form.value.menuIds = getMenuAllCheckedKeys()
form.value.roleId ? await updateRole(form.value) : await addRole(form.value);
proxy?.$modal.msgSuccess("操作成功")
dialog.visible = false
getList()
}
})
}
/** 取消按钮 */
const cancel = () => {
reset()
dialog.visible = false;
reset()
dialog.visible = false;
}
/** 选择角色权限范围触发 */
const dataScopeSelectChange = (value: string) => {
if (value !== "2") {
deptRef.value.setCheckedKeys([])
}
if (value !== "2") {
deptRef.value?.setCheckedKeys([])
}
}
/** 分配数据权限操作 */
const handleDataScope = async (row: RoleVO) => {
const roleDeptTreeselect = getRoleDeptTreeSelect(row.roleId);
const response = await getRole(row.roleId);
Object.assign(form.value, response.data);
openDataScope.value = true;
dialog.title = "分配数据权限";
nextTick(async () => {
const res = await roleDeptTreeselect;
nextTick(() => {
if (deptRef.value) {
deptRef.value.setCheckedKeys(res.checkedKeys);
}
})
const roleDeptTreeselect = getRoleDeptTreeSelect(row.roleId);
const response = await getRole(row.roleId);
Object.assign(form.value, response.data);
openDataScope.value = true;
dialog.title = "分配数据权限";
await nextTick(async () => {
const res = await roleDeptTreeselect;
await nextTick(() => {
if (deptRef.value) {
deptRef.value.setCheckedKeys(res.checkedKeys);
}
})
})
}
/** 提交按钮(数据权限) */
const submitDataScope = async () => {
if (form.value.roleId) {
form.value.deptIds = getDeptAllCheckedKeys();
await dataScope(form.value);
proxy?.$modal.msgSuccess("修改成功");
openDataScope.value = false;
getList();
}
if (form.value.roleId) {
form.value.deptIds = getDeptAllCheckedKeys();
await dataScope(form.value);
proxy?.$modal.msgSuccess("修改成功");
openDataScope.value = false;
getList();
}
}
/** 取消按钮(数据权限)*/
const cancelDataScope = () => {
dataScopeRef.value.resetFields();
form.value = {...initForm};
openDataScope.value = false;
dataScopeRef.value?.resetFields();
form.value = { ...initForm };
openDataScope.value = false;
}
onMounted(() => {
getList();
getList();
});
</script>

View File

@ -47,14 +47,12 @@
import { authUserSelectAll, unallocatedUserList } from "@/api/system/role";
import { UserVO } from '@/api/system/user/types';
import { UserQuery } from '@/api/system/user/types';
import { ComponentInternalInstance } from 'vue';
import { ElForm, ElTable } from 'element-plus';
const props = defineProps({
roleId: {
type: [Number, String]
}
roleId: {
type: [Number, String]
}
})
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -66,67 +64,68 @@ const total = ref(0);
const userIds = ref<Array<string | number>>([]);
const queryParams = reactive<UserQuery>({
pageNum: 1,
pageSize: 10,
roleId: undefined,
userName: undefined,
phonenumber: undefined
pageNum: 1,
pageSize: 10,
roleId: undefined,
userName: undefined,
phonenumber: undefined
})
const tableRef = ref(ElTable);
const queryFormRef = ref(ElForm);
const tableRef = ref<ElTableInstance>();
const queryFormRef = ref<ElFormInstance>();
const show = () => {
queryParams.roleId = props.roleId;
getList();
visible.value = true;
queryParams.roleId = props.roleId;
getList();
visible.value = true;
}
/**
* 选择行
*/
const clickRow = (row: any) => {
tableRef.value.toggleRowSelection(row);
// ele的bug
tableRef.value?.toggleRowSelection(row);
}
/** 多选框选中数据 */
const handleSelectionChange = (selection: UserVO[]) => {
userIds.value = selection.map((item: UserVO) => item.userId);
userIds.value = selection.map((item: UserVO) => item.userId);
}
/** 查询数据 */
const getList = async () => {
const res = await unallocatedUserList(queryParams);
userList.value = res.rows;
total.value = res.total;
const res = await unallocatedUserList(queryParams);
userList.value = res.rows;
total.value = res.total;
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNum = 1;
getList();
queryParams.pageNum = 1;
getList();
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields();
getList();
queryFormRef.value?.resetFields();
getList();
}
const emit = defineEmits(["ok"]);
/**选择授权用户操作 */
const handleSelectUser = async () => {
const roleId = queryParams.roleId;
const ids = userIds.value.join(',');
if (ids == "") {
proxy?.$modal.msgError('请选择要分配的用户');
return;
}
await authUserSelectAll({ roleId, userIds: ids });
proxy?.$modal.msgSuccess('分配成功');
emit('ok');
visible.value = false;
const roleId = queryParams.roleId;
const ids = userIds.value.join(',');
if (ids == "") {
proxy?.$modal.msgError('请选择要分配的用户');
return;
}
await authUserSelectAll({ roleId, userIds: ids });
proxy?.$modal.msgSuccess('分配成功');
emit('ok');
visible.value = false;
}
// 暴露
defineExpose({
show,
show,
});
</script>

View File

@ -1,29 +1,31 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="租户编号" prop="tenantId">
<el-input v-model="queryParams.tenantId" placeholder="请输入租户编号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="联系人" prop="contactUserName">
<el-input v-model="queryParams.contactUserName" placeholder="请输入联系人" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="联系电话" prop="contactPhone">
<el-input v-model="queryParams.contactPhone" placeholder="请输入联系电话" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="企业名称" prop="companyName">
<el-input v-model="queryParams.companyName" placeholder="请输入企业名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb-[10px]" v-show="showSearch">
<el-card shadow="hover">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="租户编号" prop="tenantId">
<el-input v-model="queryParams.tenantId" placeholder="请输入租户编号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="联系人" prop="contactUserName">
<el-input v-model="queryParams.contactUserName" placeholder="请输入联系人" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="联系电话" prop="contactPhone">
<el-input v-model="queryParams.contactPhone" placeholder="请输入联系电话" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="企业名称" prop="companyName">
<el-input v-model="queryParams.companyName" placeholder="请输入企业名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<el-card shadow="hover">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
@ -80,7 +82,7 @@
</el-table-column>
</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" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改租户对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
@ -143,8 +145,6 @@ import { listTenant, getTenant, delTenant, addTenant, updateTenant, changeTenant
import { selectTenantPackage } from '@/api/system/tenantPackage';
import { TenantForm, TenantQuery, TenantVO } from '@/api/system/tenant/types';
import { TenantPkgVO } from '@/api/system/tenantPackage/types';
import { ComponentInternalInstance } from 'vue';
import { ElForm } from 'element-plus';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -158,196 +158,196 @@ const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const queryFormRef = ref(ElForm);
const tenantFormRef = ref(ElForm);
const queryFormRef = ref<ElFormInstance>();
const tenantFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
visible: false,
title: ''
});
const initFormData: TenantForm = {
id: undefined,
tenantId: undefined,
contactUserName: '',
contactPhone: '',
username: '',
password: '',
companyName: '',
licenseNumber: '',
domain: '',
address: '',
intro: '',
remark: '',
packageId: '',
expireTime: '',
accountCount: 0,
status: '0',
id: undefined,
tenantId: undefined,
contactUserName: '',
contactPhone: '',
username: '',
password: '',
companyName: '',
licenseNumber: '',
domain: '',
address: '',
intro: '',
remark: '',
packageId: '',
expireTime: '',
accountCount: 0,
status: '0',
}
const data = reactive<PageData<TenantForm, TenantQuery>>({
form: {...initFormData},
queryParams: {
pageNum: 1,
pageSize: 10,
tenantId: '',
contactUserName: '',
contactPhone: '',
companyName: ''
},
rules: {
id: [{ required: true, message: "id不能为空", trigger: "blur" }],
tenantId: [{ required: true, message: "租户编号不能为空", trigger: "blur" }],
contactUserName: [{ required: true, message: "联系人不能为空", trigger: "blur" }],
contactPhone: [{ required: true, message: "联系电话不能为空", trigger: "blur" }],
companyName: [{ required: true, message: "企业名称不能为空", trigger: "blur" }],
username: [
{ required: true, message: "用户名不能为空", trigger: "blur" },
{ min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur' }
],
password: [
{ required: true, message: "密码不能为空", trigger: "blur" },
{ min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' }
]
}
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
tenantId: '',
contactUserName: '',
contactPhone: '',
companyName: ''
},
rules: {
id: [{ required: true, message: "id不能为空", trigger: "blur" }],
tenantId: [{ required: true, message: "租户编号不能为空", trigger: "blur" }],
contactUserName: [{ required: true, message: "联系人不能为空", trigger: "blur" }],
contactPhone: [{ required: true, message: "联系电话不能为空", trigger: "blur" }],
companyName: [{ required: true, message: "企业名称不能为空", trigger: "blur" }],
username: [
{ required: true, message: "用户名不能为空", trigger: "blur" },
{ min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur' }
],
password: [
{ required: true, message: "密码不能为空", trigger: "blur" },
{ min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' }
]
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询所有租户套餐 */
const getTenantPackage = async () => {
const res = await selectTenantPackage()
packageList.value = res.data;
const res = await selectTenantPackage()
packageList.value = res.data;
}
/** 查询租户列表 */
const getList = async () => {
loading.value = true;
const res = await listTenant(queryParams.value);
tenantList.value = res.rows;
total.value = res.total;
loading.value = false;
loading.value = true;
const res = await listTenant(queryParams.value);
tenantList.value = res.rows;
total.value = res.total;
loading.value = false;
}
// 租户套餐状态修改
const handleStatusChange = async (row: TenantVO) => {
let text = row.status === "0" ? "启用" : "停用";
try {
await proxy?.$modal.confirm('确认要"' + text + '""' + row.companyName + '"租户吗?');
await changeTenantStatus(row.id, row.tenantId, row.status);
proxy?.$modal.msgSuccess(text + "成功");
} catch {
row.status = row.status === "0" ? "1" : "0";
}
let text = row.status === "0" ? "启用" : "停用";
try {
await proxy?.$modal.confirm('确认要"' + text + '""' + row.companyName + '"租户吗?');
await changeTenantStatus(row.id, row.tenantId, row.status);
proxy?.$modal.msgSuccess(text + "成功");
} catch {
row.status = row.status === "0" ? "1" : "0";
}
}
// 取消按钮
const cancel = () => {
reset();
dialog.visible = false;
reset();
dialog.visible = false;
}
// 表单重置
const reset = () => {
form.value = {...initFormData};
tenantFormRef.value.resetFields();
form.value = { ...initFormData };
tenantFormRef.value?.resetFields();
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields();
handleQuery();
queryFormRef.value?.resetFields();
handleQuery();
}
// 多选框选中数据
const handleSelectionChange = (selection: TenantVO[]) => {
ids.value = selection.map(item => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
ids.value = selection.map(item => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
const handleAdd = () => {
dialog.visible = true;
dialog.title = "添加租户";
nextTick(() => {
reset();
getTenantPackage();
})
dialog.visible = true;
dialog.title = "添加租户";
nextTick(() => {
reset();
getTenantPackage();
})
}
/** 修改按钮操作 */
const handleUpdate = (row?: TenantVO) => {
loading.value = true;
dialog.visible = true;
dialog.title = "修改租户";
nextTick(async () => {
reset();
getTenantPackage();
const _id = row?.id || ids.value[0];
const res = await getTenant(_id);
loading.value = false;
Object.assign(form.value, res.data)
})
loading.value = true;
dialog.visible = true;
dialog.title = "修改租户";
nextTick(async () => {
reset();
await getTenantPackage();
const _id = row?.id || ids.value[0];
const res = await getTenant(_id);
loading.value = false;
Object.assign(form.value, res.data)
})
}
/** 提交按钮 */
const submitForm = () => {
tenantFormRef.value.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (form.value.id) {
await updateTenant(form.value).finally(() => buttonLoading.value = false);
} else {
await addTenant(form.value).finally(() => buttonLoading.value = false);
}
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
getList();
}
});
tenantFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (form.value.id) {
await updateTenant(form.value).finally(() => buttonLoading.value = false);
} else {
await addTenant(form.value).finally(() => buttonLoading.value = false);
}
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
getList();
}
});
}
/** 删除按钮操作 */
const handleDelete = async (row?: TenantVO) => {
const _ids = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除租户编号为"' + _ids + '"的数据项?')
loading.value = true;
await delTenant(_ids).finally(() => loading.value = false);
getList();
proxy?.$modal.msgSuccess("删除成功");
const _ids = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除租户编号为"' + _ids + '"的数据项?')
loading.value = true;
await delTenant(_ids).finally(() => loading.value = false);
await getList();
proxy?.$modal.msgSuccess("删除成功");
}
/** 同步租户套餐按钮操作 */
const handleSyncTenantPackage = async (row: TenantVO) => {
try {
await proxy?.$modal.confirm('是否确认同步租户套餐租户编号为"' + row.tenantId + '"的数据项?');
loading.value = true;
await syncTenantPackage(row.tenantId, row.packageId);
getList();
proxy?.$modal.msgSuccess("同步成功");
} catch {return} finally {
loading.value = false;
}
try {
await proxy?.$modal.confirm('是否确认同步租户套餐租户编号为"' + row.tenantId + '"的数据项?');
loading.value = true;
await syncTenantPackage(row.tenantId, row.packageId);
await getList();
proxy?.$modal.msgSuccess("同步成功");
} catch { return } finally {
loading.value = false;
}
}
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download('system/tenant/export', {
...queryParams.value
}, `tenant_${new Date().getTime()}.xlsx`)
proxy?.download('system/tenant/export', {
...queryParams.value
}, `tenant_${new Date().getTime()}.xlsx`)
}
onMounted(() => {
getList();
getList();
})
</script>

View File

@ -1,37 +1,39 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="套餐名称" prop="packageName">
<el-input v-model="queryParams.packageName" placeholder="请输入套餐名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb-[10px]" v-show="showSearch">
<el-card shadow="hover">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="套餐名称" prop="packageName">
<el-input v-model="queryParams.packageName" placeholder="请输入套餐名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<el-card shadow="hover">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:tenantPackage:add']">新增</el-button>
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:tenantPackage:add']"> 新增 </el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:tenantPackage:edit']"
>修改</el-button
>
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:tenantPackage:edit']">
修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:tenantPackage:remove']"
>删除</el-button
>
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:tenantPackage:remove']">
删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:tenantPackage:export']">导出</el-button>
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:tenantPackage:export']">导出 </el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
@ -53,13 +55,13 @@
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:tenantPackage:edit']"></el-button>
</el-tooltip>
<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 link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:tenantPackage:remove']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</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" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改租户套餐对话框 -->
@ -70,8 +72,8 @@
</el-form-item>
<el-form-item label="关联菜单">
<el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($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="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选 </el-checkbox>
<el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动 </el-checkbox>
<el-tree
class="tree-border"
:data="menuOptions"
@ -98,12 +100,17 @@
</template>
<script setup name="TenantPackage" lang="ts">
import { listTenantPackage, getTenantPackage, delTenantPackage, addTenantPackage, updateTenantPackage, changePackageStatus } from "@/api/system/tenantPackage";
import {
listTenantPackage,
getTenantPackage,
delTenantPackage,
addTenantPackage,
updateTenantPackage,
changePackageStatus
} from "@/api/system/tenantPackage";
import { treeselect as menuTreeselect, tenantPackageMenuTreeselect } from "@/api/system/menu";
import { ComponentInternalInstance } from "vue";
import { TenantPkgForm, TenantPkgQuery, TenantPkgVO } from "@/api/system/tenantPackage/types";
import { MenuTreeOption } from "@/api/system/menu/types";
import { CheckboxValueType, ElTree, ElForm } from 'element-plus';
import to from "await-to-js";
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -120,212 +127,216 @@ const menuExpand = ref(false);
const menuNodeAll = ref(false);
const menuOptions = ref<MenuTreeOption[]>([]);
const menuTreeRef = ref(ElTree);
const queryFormRef = ref(ElForm);
const tenantPackageFormRef = ref(ElForm);
const menuTreeRef = ref<ElTreeInstance>();
const queryFormRef = ref<ElFormInstance>();
const tenantPackageFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
visible: false,
title: ""
});
const initFormData: TenantPkgForm = {
packageId: undefined,
packageName: '',
menuIds: '',
remark: '',
menuCheckStrictly: true
packageId: undefined,
packageName: "",
menuIds: "",
remark: "",
menuCheckStrictly: true
};
const data = reactive<PageData<TenantPkgForm, TenantPkgQuery>>({
form: {...initFormData},
queryParams: {
pageNum: 1,
pageSize: 10,
packageName: ''
},
rules: {
packageId: [{ required: true, message: "租户套餐id不能为空", trigger: "blur" }],
packageName: [{ required: true, message: "套餐名称不能为空", trigger: "blur" }]
}
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
packageName: ""
},
rules: {
packageId: [{ required: true, message: "租户套餐id不能为空", trigger: "blur" }],
packageName: [{ required: true, message: "套餐名称不能为空", trigger: "blur" }]
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询菜单树结构 */
const getMenuTreeselect = async() => {
const { data } = await menuTreeselect();
menuOptions.value = data;
}
const getMenuTreeselect = async () => {
const { data } = await menuTreeselect();
menuOptions.value = data;
};
// 所有菜单节点数据
const getMenuAllCheckedKeys = () => {
// 目前被选中的菜单节点
let checkedKeys = menuTreeRef.value.getCheckedKeys();
// 半选中的菜单节点
let halfCheckedKeys = menuTreeRef.value.getHalfCheckedKeys();
checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
return checkedKeys;
}
const getMenuAllCheckedKeys = (): any => {
// 目前被选中的菜单节点
let checkedKeys = menuTreeRef.value?.getCheckedKeys();
// 半选中的菜单节点
let halfCheckedKeys = menuTreeRef.value?.getHalfCheckedKeys();
if (halfCheckedKeys) {
checkedKeys?.unshift.apply(checkedKeys, halfCheckedKeys);
}
return checkedKeys;
};
/** 根据租户套餐ID查询菜单树结构 */
const getPackageMenuTreeselect = async(packageId: string | number) => {
const res = await tenantPackageMenuTreeselect(packageId);
menuOptions.value = res.data.menus;
return Promise.resolve(res);
}
const getPackageMenuTreeselect = async (packageId: string | number) => {
const res = await tenantPackageMenuTreeselect(packageId);
menuOptions.value = res.data.menus;
return Promise.resolve(res);
};
/** 查询租户套餐列表 */
const getList = async () => {
loading.value = true;
const res = await listTenantPackage(queryParams.value);
tenantPackageList.value = res.rows;
total.value = res.total;
loading.value = false;
}
loading.value = true;
const res = await listTenantPackage(queryParams.value);
tenantPackageList.value = res.rows;
total.value = res.total;
loading.value = false;
};
// 租户套餐状态修改
const handleStatusChange = async (row: TenantPkgVO) => {
let text = row.status === "0" ? "启用" : "停用";
const [err] = await to(proxy?.$modal.confirm('确认要"' + text + '""' + row.packageName + '"套餐吗?') as Promise<any>)
if (err) {
row.status = row.status === "0" ? "1" : "0";
} else {
await changePackageStatus(row.packageId, row.status);
proxy?.$modal.msgSuccess(text + "成功");
}
}
let text = row.status === "0" ? "启用" : "停用";
const [err] = await to(proxy?.$modal.confirm("确认要\"" + text + "\"\"" + row.packageName + "\"套餐吗?") as Promise<any>);
if (err) {
row.status = row.status === "0" ? "1" : "0";
} else {
await changePackageStatus(row.packageId, row.status);
proxy?.$modal.msgSuccess(text + "成功");
}
};
// 取消按钮
const cancel = () => {
reset();
dialog.visible = false;
}
reset();
dialog.visible = false;
};
// 表单重置
const reset = () => {
menuTreeRef.value.setCheckedKeys([]);
menuExpand.value = false;
menuNodeAll.value = false;
form.value = {...initFormData};
tenantPackageFormRef.value.resetFields();
}
menuTreeRef.value?.setCheckedKeys([]);
menuExpand.value = false;
menuNodeAll.value = false;
form.value = { ...initFormData };
tenantPackageFormRef.value?.resetFields();
};
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
}
queryParams.value.pageNum = 1;
getList();
};
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields();
handleQuery();
}
queryFormRef.value?.resetFields();
handleQuery();
};
// 多选框选中数据
const handleSelectionChange = (selection: TenantPkgVO[]) => {
ids.value = selection.map(item => item.packageId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
ids.value = selection.map(item => item.packageId);
single.value = selection.length != 1;
multiple.value = !selection.length;
};
// 树权限(展开/折叠)
const handleCheckedTreeExpand = (value: CheckboxValueType, type: string) => {
if (type == 'menu') {
let treeList = menuOptions.value;
for (let i = 0; i < treeList.length; i++) {
menuTreeRef.value.store.nodesMap[treeList[i].id].expanded = value;
}
if (type == "menu") {
let treeList = menuOptions.value;
for (let i = 0; i < treeList.length; i++) {
if (menuTreeRef.value) {
menuTreeRef.value.store.nodesMap[treeList[i].id].expanded = value as boolean;
}
}
}
}
};
// 树权限(全选/全不选)
const handleCheckedTreeNodeAll = (value: CheckboxValueType, type: string) => {
if (type == 'menu') {
menuTreeRef.value.setCheckedNodes(value ? menuOptions.value: []);
}
}
if (type == "menu") {
menuTreeRef.value?.setCheckedNodes(value ? menuOptions.value as any : []);
}
};
// 树权限(父子联动)
const handleCheckedTreeConnect = (value: CheckboxValueType, type: string) => {
if (type == 'menu') {
form.value.menuCheckStrictly = value as boolean;
}
}
if (type == "menu") {
form.value.menuCheckStrictly = value as boolean;
}
};
/** 新增按钮操作 */
const handleAdd = () => {
dialog.visible = true;
dialog.title = "添加租户套餐";
nextTick(() => {
reset();
getMenuTreeselect();
})
}
dialog.visible = true;
dialog.title = "添加租户套餐";
nextTick(() => {
reset();
getMenuTreeselect();
});
};
/** 修改按钮操作 */
const handleUpdate = (row?: TenantPkgVO) => {
loading.value = true
dialog.visible = true;
dialog.title = "修改租户套餐";
nextTick(async () => {
reset();
const _packageId = row?.packageId || ids.value[0];
const packageMenu = getPackageMenuTreeselect(_packageId);
const response = await getTenantPackage(_packageId);
loading.value = false;
form.value = response.data;
nextTick(async () => {
const res = await packageMenu;
let checkedKeys = res.data.checkedKeys
checkedKeys.forEach((v) => {
nextTick(() => {
menuTreeRef.value.setChecked(v, true ,false);
})
})
loading.value = true;
dialog.visible = true;
dialog.title = "修改租户套餐";
nextTick(async () => {
reset();
const _packageId = row?.packageId || ids.value[0];
const packageMenu = getPackageMenuTreeselect(_packageId);
const response = await getTenantPackage(_packageId);
loading.value = false;
form.value = response.data;
await nextTick(async () => {
const res = await packageMenu;
let checkedKeys = res.data.checkedKeys;
checkedKeys.forEach((v) => {
nextTick(() => {
menuTreeRef.value?.setChecked(v, true, false);
});
})
}
});
});
});
};
/** 提交按钮 */
const submitForm = () => {
tenantPackageFormRef.value.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
form.value.menuIds = getMenuAllCheckedKeys();
if (form.value.packageId != null) {
await updateTenantPackage(form.value).finally(() => buttonLoading.value = false);
} else {
await addTenantPackage(form.value).finally(() => buttonLoading.value = false);
}
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
getList();
}
});
}
tenantPackageFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
form.value.menuIds = getMenuAllCheckedKeys();
if (form.value.packageId != null) {
await updateTenantPackage(form.value).finally(() => buttonLoading.value = false);
} else {
await addTenantPackage(form.value).finally(() => buttonLoading.value = false);
}
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
await getList();
}
});
};
/** 删除按钮操作 */
const handleDelete = async (row?: TenantPkgVO) => {
const _packageIds = row?.packageId || ids.value;
await proxy?.$modal.confirm('是否确认删除租户套餐编号为"' + _packageIds + '"的数据项?').finally(() => {
loading.value = false;
});
await delTenantPackage(_packageIds);
loading.value = true;
getList();
proxy?.$modal.msgSuccess("删除成功");
}
const _packageIds = row?.packageId || ids.value;
await proxy?.$modal.confirm("是否确认删除租户套餐编号为\"" + _packageIds + "\"的数据项?").finally(() => {
loading.value = false;
});
await delTenantPackage(_packageIds);
loading.value = true;
await getList();
proxy?.$modal.msgSuccess("删除成功");
};
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download('system/tenantPackage/export', {
...queryParams.value
}, `tenantPackage_${new Date().getTime()}.xlsx`)
}
proxy?.download("system/tenantPackage/export", {
...queryParams.value
}, `tenantPackage_${new Date().getTime()}.xlsx`);
};
onMounted(() => {
getList();
})
getList();
});
</script>

View File

@ -55,11 +55,10 @@
</template>
<script setup name="AuthRole" lang="ts">
import { RoleVO } from '@/api/system/role/types';
import { getAuthRole, updateAuthRole } from '@/api/system/user';
import { UserForm } from '@/api/system/user/types';
import { ElTable } from "element-plus";
import { ComponentInternalInstance } from 'vue';
import { RoleVO } from "@/api/system/role/types";
import { getAuthRole, updateAuthRole } from "@/api/system/user";
import { UserForm } from "@/api/system/user/types";
const route = useRoute();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -70,58 +69,59 @@ const pageSize = ref(10);
const roleIds = ref<Array<string | number>>([]);
const roles = ref<RoleVO[]>([]);
const form = ref<Partial<UserForm>>({
nickName: undefined,
userName: '',
userId: undefined
nickName: undefined,
userName: "",
userId: undefined
});
const tableRef = ref(ElTable)
const tableRef = ref<ElTableInstance>();
/** 单击选中行数据 */
const clickRow = (row: RoleVO) => {
tableRef.value.toggleRowSelection(row);
// ele的方法有问题selected应该为可选参数
tableRef.value?.toggleRowSelection(row);
};
/** 多选框选中数据 */
const handleSelectionChange = (selection: RoleVO[]) => {
roleIds.value = selection.map(item => item.roleId);
roleIds.value = selection.map(item => item.roleId);
};
/** 保存选中的数据编号 */
const getRowKey = (row: RoleVO): string => {
return String(row.roleId);
return String(row.roleId);
};
/** 关闭按钮 */
const close = () => {
const obj = { path: "/system/user" };
proxy?.$tab.closeOpenPage(obj);
const obj = { path: "/system/user" };
proxy?.$tab.closeOpenPage(obj);
};
/** 提交按钮 */
const submitForm = async () => {
const userId = form.value.userId;
const rIds = roleIds.value.join(",");
await updateAuthRole({ userId: userId as string, roleIds: rIds })
proxy?.$modal.msgSuccess("授权成功");
close();
const userId = form.value.userId;
const rIds = roleIds.value.join(",");
await updateAuthRole({ userId: userId as string, roleIds: rIds });
proxy?.$modal.msgSuccess("授权成功");
close();
};
const getList = async() => {
const userId = route.params && route.params.userId;
if (userId) {
loading.value = true;
const res = await getAuthRole(userId as string);
Object.assign(form.value, res.data.user)
Object.assign(roles.value, res.data.roles)
total.value = roles.value.length;
await nextTick(() => {
roles.value.forEach(row => {
if (row?.flag) {
tableRef.value.toggleRowSelection(row);
}
});
});
loading.value = false;
}
}
const getList = async () => {
const userId = route.params && route.params.userId;
if (userId) {
loading.value = true;
const res = await getAuthRole(userId as string);
Object.assign(form.value, res.data.user);
Object.assign(roles.value, res.data.roles);
total.value = roles.value.length;
await nextTick(() => {
roles.value.forEach(row => {
if (row?.flag) {
tableRef.value?.toggleRowSelection(row, true);
}
});
});
loading.value = false;
}
};
onMounted(() => {
getList();
})
getList();
});
</script>

View File

@ -16,40 +16,48 @@
highlight-current
default-expand-all
@node-click="handleNodeClick"
></el-tree>
/>
</el-card>
</el-col>
<el-col :lg="20" :xs="24">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
<el-form-item label="用户名称" prop="userName">
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item>
<div class="mb-[10px]" v-show="showSearch">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
<el-form-item label="用户名称" prop="userName">
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="手机号码" prop="phonenumber">
<el-input
v-model="queryParams.phonenumber"
placeholder="请输入手机号码"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="用户状态" clearable style="width: 240px">
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="创建时间" style="width: 308px;">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleQuery" icon="Search">搜索</el-button>
<el-button @click="resetQuery" icon="Refresh">重置</el-button>
</el-form-item>
</el-form>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="用户状态" clearable style="width: 240px">
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="创建时间" style="width: 308px;">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleQuery" icon="Search">搜索</el-button>
<el-button @click="resetQuery" icon="Refresh">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
@ -203,7 +211,7 @@
<el-form-item label="状态">
<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>
dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
@ -289,30 +297,19 @@
</template>
<script setup name="User" lang="ts">
import {
changeUserStatus,
listUser,
resetUserPwd,
delUser,
getUser,
updateUser,
addUser,
deptTreeSelect
} from "@/api/system/user"
import api from "@/api/system/user"
import { UserForm, UserQuery, UserVO } from '@/api/system/user/types';
import { ComponentInternalInstance } from "vue";
import { getToken } from "@/utils/auth";
import { treeselect } from "@/api/system/dept";
import { DeptVO } from "@/api/system/dept/types";
import { RoleVO } from "@/api/system/role/types";
import { PostVO } from "@/api/system/post/types";
import { DateModelType, ElTree, ElUpload, UploadFile, ElForm } from 'element-plus';
import { to } from "await-to-js";
const router = useRouter();
const { proxy } = getCurrentInstance() as ComponentInternalInstance
const { sys_normal_disable, sys_user_sex } = toRefs<any>(proxy?.useDict('sys_normal_disable', 'sys_user_sex'));
const userList = ref<UserVO[]>();
const loading = ref(true);
const showSearch = ref(true)
@ -320,7 +317,7 @@ const ids = ref<Array<number | string>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const dateRange = ref<[DateModelType, DateModelType]>(['','']);
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
const deptName = ref('');
const deptOptions = ref<DeptVO[]>([]);
const initPassword = ref('123456');
@ -328,274 +325,274 @@ const postOptions = ref<PostVO[]>([]);
const roleOptions = ref<RoleVO[]>([]);
/*** 用户导入参数 */
const upload = reactive<ImportOption>({
// 是否显示弹出层(用户导入)
open: false,
// 弹出层标题(用户导入)
title: "",
// 是否禁用上传
isUploading: false,
// 是否更新已经存在的用户数据
updateSupport: 0,
// 设置上传的请求头部
headers: { Authorization: "Bearer " + getToken() },
// 上传的地址
url: import.meta.env.VITE_APP_BASE_API + "/system/user/importData"
// 是否显示弹出层(用户导入)
open: false,
// 弹出层标题(用户导入)
title: "",
// 是否禁用上传
isUploading: false,
// 是否更新已经存在的用户数据
updateSupport: 0,
// 设置上传的请求头部
headers: { Authorization: "Bearer " + getToken() },
// 上传的地址
url: import.meta.env.VITE_APP_BASE_API + "/system/user/importData"
})
// 列显隐信息
const columns = ref<FieldOption[]>([
{ key: 0, label: `用户编号`, visible: false },
{ key: 1, label: `用户名称`, visible: true },
{ key: 2, label: `用户昵称`, visible: true },
{ key: 3, label: `部门`, visible: true },
{ key: 4, label: `手机号码`, visible: true },
{ key: 5, label: `状态`, visible: true },
{ key: 6, label: `创建时间`, visible: true }
{ key: 0, label: `用户编号`, visible: false },
{ key: 1, label: `用户名称`, visible: true },
{ key: 2, label: `用户昵称`, visible: true },
{ key: 3, label: `部门`, visible: true },
{ key: 4, label: `手机号码`, visible: true },
{ key: 5, label: `状态`, visible: true },
{ key: 6, label: `创建时间`, visible: true }
])
const deptTreeRef = ref(ElTree);
const queryFormRef = ref(ElForm);
const userFormRef = ref(ElForm);
const uploadRef = ref(ElUpload);
const deptTreeRef = ref<ElTreeInstance>();
const queryFormRef = ref<ElFormInstance>();
const userFormRef = ref<ElFormInstance>();
const uploadRef = ref<ElUploadInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
visible: false,
title: ''
});
const initFormData: UserForm = {
userId: undefined,
deptId: undefined,
userName: '',
nickName: undefined,
password: '',
phonenumber: undefined,
email: undefined,
sex: undefined,
status: "0",
remark: '',
postIds: [],
roleIds: []
userId: undefined,
deptId: undefined,
userName: '',
nickName: undefined,
password: '',
phonenumber: undefined,
email: undefined,
sex: undefined,
status: "0",
remark: '',
postIds: [],
roleIds: []
}
const data = reactive<PageData<UserForm, UserQuery>>({
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
userName: '',
phonenumber: '',
status: '',
deptId: ''
},
rules: {
userName: [{ required: true, message: "用户名称不能为空", trigger: "blur" }, { min: 2, 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" }]
}
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
userName: '',
phonenumber: '',
status: '',
deptId: ''
},
rules: {
userName: [{ required: true, message: "用户名称不能为空", trigger: "blur" }, { min: 2, 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 filterNode = (value: string, data: any) => {
if (!value) return true
return data.label.indexOf(value) !== -1
if (!value) return true
return data.label.indexOf(value) !== -1
}
/** 根据名称筛选部门树 */
watchEffect(
() => {deptTreeRef.value.filter(deptName.value);},
{
flush: 'post' // watchEffect会在DOM挂载或者更新之前就会触发此属性控制在DOM元素更新后运行
}
() => { deptTreeRef.value?.filter(deptName.value); },
{
flush: 'post' // watchEffect会在DOM挂载或者更新之前就会触发此属性控制在DOM元素更新后运行
}
);
/** 查询部门下拉树结构 */
const getTreeSelect = async () => {
const res = await deptTreeSelect();
deptOptions.value = res.data;
const res = await api.deptTreeSelect();
deptOptions.value = res.data;
};
/** 查询用户列表 */
const getList = async () => {
loading.value = true;
const res = await listUser(proxy?.addDateRange(queryParams.value, dateRange.value));
loading.value = false;
userList.value = res.rows;
total.value = res.total;
loading.value = true;
const res = await api.listUser(proxy?.addDateRange(queryParams.value, dateRange.value));
loading.value = false;
userList.value = res.rows;
total.value = res.total;
}
/** 节点单击事件 */
const handleNodeClick = (data: DeptVO) => {
queryParams.value.deptId = data.id;
handleQuery()
queryParams.value.deptId = data.id;
handleQuery()
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1
getList()
queryParams.value.pageNum = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
dateRange.value = ['','']
queryFormRef.value.resetFields();
queryParams.value.pageNum = 1;
queryParams.value.deptId = undefined;
deptTreeRef.value.setCurrentKey(null);
handleQuery();
dateRange.value = ['', '']
queryFormRef.value?.resetFields();
queryParams.value.pageNum = 1;
queryParams.value.deptId = undefined;
deptTreeRef.value?.setCurrentKey(undefined);
handleQuery();
}
/** 删除按钮操作 */
const handleDelete = async (row?: UserVO) => {
const userIds = row?.userId || ids.value;
const [err] = await to(proxy?.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?') as any);
if (!err) {
await delUser(userIds);
await getList();
proxy?.$modal.msgSuccess("删除成功");
}
const userIds = row?.userId || ids.value;
const [err] = await to(proxy?.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?') as any);
if (!err) {
await api.delUser(userIds);
await getList();
proxy?.$modal.msgSuccess("删除成功");
}
}
/** 用户状态修改 */
const handleStatusChange = async (row: UserVO) => {
let text = row.status === "0" ? "启用" : "停用"
try {
await proxy?.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?');
await changeUserStatus(row.userId, row.status);
proxy?.$modal.msgSuccess(text + "成功");
} catch (err) {
row.status = row.status === "0" ? "1" : "0";
}
let text = row.status === "0" ? "启用" : "停用"
try {
await proxy?.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?');
await api.changeUserStatus(row.userId, row.status);
proxy?.$modal.msgSuccess(text + "成功");
} catch (err) {
row.status = row.status === "0" ? "1" : "0";
}
}
/** 跳转角色分配 */
const handleAuthRole = (row: UserVO) => {
const userId = row.userId;
router.push("/system/user-auth/role/" + userId);
const userId = row.userId;
router.push("/system/user-auth/role/" + userId);
}
/** 重置密码按钮操作 */
const handleResetPwd = async (row: UserVO) => {
const [err, res] = await to(ElMessageBox.prompt('请输入"' + row.userName + '"的新密码', "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
closeOnClickModal: false,
inputPattern: /^.{5,20}$/,
inputErrorMessage: "用户密码长度必须介于 5 和 20 之间",
}))
if (!err) {
await resetUserPwd(row.userId, res.value);
proxy?.$modal.msgSuccess("修改成功,新密码是:" + res.value);
}
const [err, res] = await to(ElMessageBox.prompt('请输入"' + row.userName + '"的新密码', "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
closeOnClickModal: false,
inputPattern: /^.{5,20}$/,
inputErrorMessage: "用户密码长度必须介于 5 和 20 之间",
}))
if (!err) {
await api.resetUserPwd(row.userId, res.value);
proxy?.$modal.msgSuccess("修改成功,新密码是:" + res.value);
}
}
/** 选择条数 */
const handleSelectionChange = (selection: UserVO[]) => {
ids.value = selection.map((item) => item.userId);
single.value = selection.length != 1;
multiple.value = !selection.length;
ids.value = selection.map((item) => item.userId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 导入按钮操作 */
const handleImport = () => {
upload.title = "用户导入";
upload.open = true;
upload.title = "用户导入";
upload.open = true;
}
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download("system/user/export", {
...queryParams.value,
}, `user_${new Date().getTime()}.xlsx`);
proxy?.download("system/user/export", {
...queryParams.value,
}, `user_${new Date().getTime()}.xlsx`);
};
/** 下载模板操作 */
const importTemplate = () => {
proxy?.download("system/user/importTemplate", {
}, `user_template_${new Date().getTime()}.xlsx`);
proxy?.download("system/user/importTemplate", {
}, `user_template_${new Date().getTime()}.xlsx`);
}
/**文件上传中处理 */
const handleFileUploadProgress = () => {
upload.isUploading = true;
upload.isUploading = true;
}
/** 文件上传成功处理 */
const handleFileSuccess = (response: any, file: UploadFile) => {
upload.open = false;
upload.isUploading = false;
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 });
getList();
upload.open = false;
upload.isUploading = false;
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 });
getList();
}
/** 提交上传文件 */
function submitFileForm() {
uploadRef.value.submit();
uploadRef.value?.submit();
}
/** 初始化部门数据 */
const initTreeData = async () => {
// 判断部门的数据是否存在,存在不获取,不存在则获取
if (deptOptions.value === undefined) {
const { data } = await treeselect();
deptOptions.value = data;
}
// 判断部门的数据是否存在,存在不获取,不存在则获取
if (deptOptions.value === undefined) {
const { data } = await treeselect();
deptOptions.value = data;
}
}
/** 重置操作表单 */
const reset = () => {
form.value = { ...initFormData };
userFormRef.value.resetFields();
form.value = { ...initFormData };
userFormRef.value?.resetFields();
}
/** 取消按钮 */
const cancel = () => {
reset();
dialog.visible = false;
reset();
dialog.visible = false;
}
/** 新增按钮操作 */
const handleAdd = () => {
dialog.visible = true;
dialog.title = "新增用户";
nextTick(async () => {
reset();
await initTreeData();
const { data } = await getUser();
postOptions.value = data.posts;
roleOptions.value = data.roles;
form.value.password = initPassword.value;
})
dialog.visible = true;
dialog.title = "新增用户";
nextTick(async () => {
reset();
await initTreeData();
const { data } = await api.getUser();
postOptions.value = data.posts;
roleOptions.value = data.roles;
form.value.password = initPassword.value;
})
}
/** 修改按钮操作 */
const handleUpdate = (row?: UserForm) => {
dialog.visible = true;
dialog.title = "修改用户";
nextTick(async () => {
reset();
await initTreeData();
const userId = row?.userId || ids.value[0]
const { data } = await getUser(userId)
Object.assign(form.value, data.user);
postOptions.value = data.posts;
roleOptions.value = data.roles;
form.value.postIds = data.postIds;
form.value.roleIds = data.roleIds;
form.value.password = "";
})
dialog.visible = true;
dialog.title = "修改用户";
nextTick(async () => {
reset();
await initTreeData();
const userId = row?.userId || ids.value[0]
const { data } = await api.getUser(userId)
Object.assign(form.value, data.user);
postOptions.value = data.posts;
roleOptions.value = data.roles;
form.value.postIds = data.postIds;
form.value.roleIds = data.roleIds;
form.value.password = "";
})
}
/** 提交按钮 */
const submitForm = () => {
userFormRef.value.validate(async (valid: boolean) => {
if (valid) {
form.value.userId ? await updateUser(form.value) : await addUser(form.value);
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
await getList();
}
})
userFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
form.value.userId ? await api.updateUser(form.value) : await api.addUser(form.value);
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
await getList();
}
})
}
@ -603,23 +600,23 @@ const submitForm = () => {
* 关闭用户弹窗
*/
const closeDialog = () => {
dialog.visible = false;
resetForm();
dialog.visible = false;
resetForm();
}
/**
* 重置表单
*/
const resetForm = () => {
userFormRef.value.resetFields();
userFormRef.value.clearValidate();
userFormRef.value?.resetFields();
userFormRef.value?.clearValidate();
form.value.id = undefined;
form.value.status = '1';
form.value.id = undefined;
form.value.status = '1';
}
onMounted(() => {
getTreeSelect() // 初始化部门数据
getList() // 初始化列表数据
getTreeSelect() // 初始化部门数据
getList() // 初始化列表数据
});
</script>

View File

@ -74,11 +74,11 @@ import { getAuthList } from "@/api/system/social/auth";
import { getUserProfile } from "@/api/system/user";
const activeTab = ref("userinfo");
const state = ref<{ user: any; roleGroup: string; postGroup: string; auths:any[]}>({
const state = ref<Record<string, any>>({
user: {},
roleGroup: '',
postGroup: '',
auths: [],
auths: []
});
const userForm = ref({});

View File

@ -17,46 +17,50 @@
</template>
<script setup lang="ts">
import { updateUserPwd } from '@/api/system/user';
import { ComponentInternalInstance } from 'vue';
import { ResetPwdForm } from '@/api/system/user/types'
import { ElForm } from 'element-plus';
import { updateUserPwd } from "@/api/system/user";
import type { ResetPwdForm } from "@/api/system/user/types";
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const pwdRef = ref(ElForm);
const pwdRef = ref<ElFormInstance>();
const user = ref<ResetPwdForm>({
oldPassword: '',
newPassword: '',
confirmPassword: ''
oldPassword: "",
newPassword: "",
confirmPassword: ""
});
const equalToPassword = (rule: any, value: string, callback: any) => {
if (user.value.newPassword !== value) {
callback(new Error("两次输入的密码不一致"));
} else {
callback();
}
if (user.value.newPassword !== value) {
callback(new Error("两次输入的密码不一致"));
} else {
callback();
}
};
const rules = ref({
oldPassword: [{ required: true, message: "旧密码不能为空", trigger: "blur" }],
newPassword: [{ required: true, message: "新密码不能为空", trigger: "blur" }, { min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" }],
confirmPassword: [{ required: true, message: "确认密码不能为空", trigger: "blur" }, { required: true, validator: equalToPassword, trigger: "blur" }]
oldPassword: [{ required: true, message: "旧密码不能为空", trigger: "blur" }],
newPassword: [{ required: true, message: "新密码不能为空", trigger: "blur" }, {
min: 6,
max: 20,
message: "长度在 6 到 20 个字符",
trigger: "blur"
}],
confirmPassword: [{ required: true, message: "确认密码不能为空", trigger: "blur" }, {
required: true,
validator: equalToPassword,
trigger: "blur"
}]
});
/** 提交按钮 */
const submit = () => {
pwdRef.value.validate(async (valid: boolean) => {
if (valid) {
await updateUserPwd(user.value.oldPassword, user.value.newPassword)
proxy?.$modal.msgSuccess("修改成功");
}
});
pwdRef.value?.validate(async (valid: boolean) => {
if (valid) {
await updateUserPwd(user.value.oldPassword, user.value.newPassword);
proxy?.$modal.msgSuccess("修改成功");
}
});
};
/** 关闭按钮 */
const close = () => {
proxy?.$tab.closePage();
proxy?.$tab.closePage();
};
</script>

View File

@ -29,7 +29,9 @@
<el-upload action="#" :http-request="requestUpload" :show-file-list="false" :before-upload="beforeUpload">
<el-button>
选择
<el-icon class="el-icon--right"><Upload /></el-icon>
<el-icon class="el-icon--right">
<Upload />
</el-icon>
</el-button>
</el-upload>
</el-col>
@ -58,18 +60,17 @@ import "vue-cropper/dist/index.css";
import { VueCropper } from "vue-cropper";
import { uploadAvatar } from "@/api/system/user";
import useUserStore from "@/store/modules/user";
import { ComponentInternalInstance } from "vue";
interface Options {
img: string | ArrayBuffer | null // 裁剪图片的地址
autoCrop: boolean // 是否默认生成截图框
autoCropWidth: number // 默认生成截图框宽度
autoCropHeight: number // 默认生成截图框高度
fixedBox: boolean // 固定截图框大小 不允许改变
fileName: string
previews: any // 预览数据
outputType: string
visible: boolean
img: string | ArrayBuffer | null; // 裁剪图片的地址
autoCrop: boolean; // 是否默认生成截图框
autoCropWidth: number; // 默认生成截图框宽度
autoCropHeight: number; // 默认生成截图框高度
fixedBox: boolean; // 固定截图框大小 不允许改变
fileName: string;
previews: any; // 预览数据
outputType: string;
visible: boolean;
}
@ -83,75 +84,76 @@ const title = ref("修改头像");
const cropper = ref<any>({});
//图片裁剪数据
const options = reactive<Options>({
img: userStore.avatar,
autoCrop: true,
autoCropWidth: 200,
autoCropHeight: 200,
fixedBox: true,
outputType: "png",
fileName: '',
previews: {},
visible: false
img: userStore.avatar,
autoCrop: true,
autoCropWidth: 200,
autoCropHeight: 200,
fixedBox: true,
outputType: "png",
fileName: "",
previews: {},
visible: false
});
/** 编辑头像 */
const editCropper = () => {
open.value = true;
}
open.value = true;
};
/** 打开弹出层结束时的回调 */
const modalOpened = () => {
visible.value = true;
}
visible.value = true;
};
/** 覆盖默认上传行为 */
const requestUpload = (): any => {}
const requestUpload = (): any => {
};
/** 向左旋转 */
const rotateLeft = () => {
cropper.value.rotateLeft();
}
cropper.value.rotateLeft();
};
/** 向右旋转 */
const rotateRight = () => {
cropper.value.rotateRight();
}
cropper.value.rotateRight();
};
/** 图片缩放 */
const changeScale = (num: number) => {
num = num || 1;
cropper.value.changeScale(num);
}
num = num || 1;
cropper.value.changeScale(num);
};
/** 上传预处理 */
const beforeUpload = (file: any) => {
if (file.type.indexOf("image/") == -1) {
proxy?.$modal.msgError("文件格式错误,请上传图片类型,如JPGPNG后缀的文件。");
} else {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
options.img = reader.result;
options.fileName = file.name;
};
}
}
if (file.type.indexOf("image/") == -1) {
proxy?.$modal.msgError("文件格式错误,请上传图片类型,如JPGPNG后缀的文件。");
} else {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
options.img = reader.result;
options.fileName = file.name;
};
}
};
/** 上传图片 */
const uploadImg = async () => {
cropper.value.getCropBlob(async (data: any) => {
let formData = new FormData();
formData.append("avatarfile", data, options.fileName);
const res = await uploadAvatar(formData);
open.value = false;
options.img = res.data.imgUrl;
userStore.avatar = options.img as string;
proxy?.$modal.msgSuccess("修改成功");
visible.value = false;
});
}
cropper.value.getCropBlob(async (data: any) => {
let formData = new FormData();
formData.append("avatarfile", data, options.fileName);
const res = await uploadAvatar(formData);
open.value = false;
options.img = res.data.imgUrl;
userStore.avatar = options.img as string
proxy?.$modal.msgSuccess("修改成功");
visible.value = false;
});
};
/** 实时预览 */
const realTime = (data: any) => {
options.previews = data;
}
options.previews = data;
};
/** 关闭窗口 */
const closeDialog = () => {
options.img = userStore.avatar;
options.visible = false;
}
options.img = userStore.avatar;
options.visible = false;
};
</script>
<style lang="scss" scoped>

View File

@ -24,40 +24,42 @@
<script setup lang="ts">
import { updateUserProfile } from "@/api/system/user";
import { FormRules } from "element-plus";
import { ComponentInternalInstance } from "vue";
import { PropType } from "vue";
import { ElForm } from "element-plus";
const props = defineProps({
user: {
type: Object as PropType<any>,
}
user: {
type: Object as PropType<any>,
required: true
}
});
const userForm = computed(() => props.user);
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const userRef = ref(ElForm);
const rules = ref<FormRules>({
nickName: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
email: [{ required: true, message: "邮箱地址不能为空", trigger: "blur" }, { type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
phonenumber: [{ required: true, message: "手机号码不能为空", trigger: "blur" }, { pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }],
const userRef = ref<ElFormInstance>();
const rules = ref<ElFormRules>({
nickName: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
email: [{ required: true, message: "邮箱地址不能为空", trigger: "blur" }, {
type: "email",
message: "请输入正确的邮箱地址",
trigger: ["blur", "change"]
}],
phonenumber: [{
required: true,
message: "手机号码不能为空",
trigger: "blur"
}, { pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }]
});
/** 提交按钮 */
const submit = () => {
userRef.value.validate(async (valid: boolean) => {
if (valid) {
await updateUserProfile(props.user)
proxy?.$modal.msgSuccess("修改成功");
}
});
userRef.value?.validate(async (valid: boolean) => {
if (valid) {
await updateUserProfile(props.user);
proxy?.$modal.msgSuccess("修改成功");
}
});
};
/** 关闭按钮 */
const close = () => {
proxy?.$tab.closePage();
proxy?.$tab.closePage();
};
</script>

View File

@ -31,24 +31,19 @@
</template>
<script setup lang="ts">
import { PropType } from 'vue';
import { propTypes } from "@/utils/propTypes";
const prop = defineProps({
info: {
type: Object as PropType<any>,
default: () => {
return {};
}
}
info: propTypes.any.def({})
});
const infoForm = computed(() => prop.info)
// 表单校验
const rules = ref({
tableName: [{ required: true, message: "请输入表名称", trigger: "blur" }],
tableComment: [{ required: true, message: "请输入表描述", trigger: "blur" }],
className: [{ required: true, message: "请输入实体类名称", trigger: "blur" }],
functionAuthor: [{ required: true, message: "请输入作者", trigger: "blur" }]
tableName: [{ required: true, message: "请输入表名称", trigger: "blur" }],
tableComment: [{ required: true, message: "请输入表描述", trigger: "blur" }],
className: [{ required: true, message: "请输入实体类名称", trigger: "blur" }],
functionAuthor: [{ required: true, message: "请输入作者", trigger: "blur" }]
});
</script>

View File

@ -117,9 +117,8 @@ import { getGenTable, updateGenTable } from '@/api/tool/gen';
import { DbColumnVO, DbTableVO } from '@/api/tool/gen/types';
import { optionselect as getDictOptionselect } from '@/api/system/dict/type';
import { DictTypeVO } from '@/api/system/dict/type/types';
import basicInfoForm from './basicInfoForm.vue';
import genInfoForm from "./genInfoForm.vue";
import { ComponentInternalInstance } from "vue";
import BasicInfoForm from './basicInfoForm.vue';
import GenInfoForm from "./genInfoForm.vue";
const route = useRoute();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -131,13 +130,13 @@ const columns = ref<DbColumnVO[]>([]);
const dictOptions = ref<DictTypeVO[]>([]);
const info = ref<Partial<DbTableVO>>({});
const basicInfo = ref(basicInfoForm);
const genInfo = ref(genInfoForm);
const basicInfo = ref<InstanceType<typeof BasicInfoForm>>();
const genInfo = ref<InstanceType<typeof GenInfoForm>>();
/** 提交按钮 */
const submitForm = () => {
const basicForm = basicInfo.value.$refs.basicInfoForm;
const genForm = genInfo.value.$refs.genInfoForm;
const basicForm = basicInfo.value?.$refs.basicInfoForm;
const genForm = genInfo.value?.$refs.genInfoForm;
Promise.all([basicForm, genForm].map(getFormPromise)).then(async res => {
const validateResult = res.every(item => !!item);
@ -168,7 +167,7 @@ const getFormPromise = (form: any) => {
});
}
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);
}

View File

@ -223,7 +223,7 @@
<script setup lang="ts">
import { listMenu } from '@/api/system/menu';
import { ComponentInternalInstance, PropType } from 'vue';
import { propTypes } from "@/utils/propTypes";
interface MenuOptionsType {
menuId: number | string;
@ -236,14 +236,8 @@ const menuOptions = ref<Array<MenuOptionsType>>([]);
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const props = defineProps({
info: {
type: Object as PropType<any>,
default: null
},
tables: {
type: Array as PropType<any[]>,
default: null
}
info: propTypes.any.def(null),
tables: propTypes.any.def(null)
});
const infoForm = computed(() => props.info);
@ -252,11 +246,11 @@ const table = computed(() => props.tables);
// 表单校验
const rules = ref({
tplCategory: [{required: true, message: "请选择生成模板", trigger: "blur"}],
packageName: [{required: true, message: "请输入生成包路径", trigger: "blur"}],
moduleName: [{required: true, message: "请输入生成模块名", trigger: "blur"}],
businessName: [{required: true, message: "请输入生成业务名", trigger: "blur"}],
functionName: [{required: true, message: "请输入生成功能名", trigger: "blur"}]
tplCategory: [{ required: true, message: "请选择生成模板", trigger: "blur" }],
packageName: [{ required: true, message: "请输入生成包路径", trigger: "blur" }],
moduleName: [{ required: true, message: "请输入生成模块名", trigger: "blur" }],
businessName: [{ required: true, message: "请输入生成业务名", trigger: "blur" }],
functionName: [{ required: true, message: "请输入生成功能名", trigger: "blur" }]
});
const subSelectChange = () => {
infoForm.value.subTableFkName = "";
@ -268,7 +262,7 @@ const tplSelectChange = (value: string) => {
}
}
const setSubTableColumns = (value: string) => {
table.value.forEach(item => {
table.value.forEach((item: any) => {
const name = item.tableName;
if (value === name) {
subColumns.value = item.columns;

View File

@ -3,11 +3,11 @@
<el-dialog title="导入表" v-model="visible" width="1100px" top="5vh" append-to-body>
<el-form :model="queryParams" ref="queryFormRef" :inline="true">
<el-form-item label="数据源" prop="dataName">
<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-select>
</el-form-item>
<el-form-item label="表名称" prop="tableName">
<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-select>
</el-form-item>
<el-form-item label="表名称" prop="tableName">
<el-input v-model="queryParams.tableName" placeholder="请输入表名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="表描述" prop="tableComment">
@ -26,7 +26,7 @@
<el-table-column prop="createTime" label="创建时间"></el-table-column>
<el-table-column prop="updateTime" label="更新时间"></el-table-column>
</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" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-row>
<template #footer>
<div class="dialog-footer">
@ -40,8 +40,6 @@
<script setup lang="ts">
import { listDbTable, importTable, getDataNames } from '@/api/tool/gen';
import { DbTableQuery, DbTableVO } from '@/api/tool/gen/types';
import { ComponentInternalInstance } from 'vue';
import { ElTable, ElForm } from 'element-plus';
const total = ref(0);
const visible = ref(false);
@ -49,15 +47,15 @@ const tables = ref<Array<string>>([]);
const dbTableList = ref<Array<DbTableVO>>([]);
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const tableRef = ref(ElTable);
const queryFormRef = ref(ElForm);
const tableRef = ref<ElTableInstance>();
const queryFormRef = ref<ElFormInstance>();
const queryParams = reactive<DbTableQuery>({
pageNum: 1,
pageSize: 10,
dataName: '',
tableName: '',
tableComment: ''
pageNum: 1,
pageSize: 10,
dataName: '',
tableName: '',
tableComment: ''
});
const dataNameList = ref<Array<string>>([]);
@ -65,52 +63,53 @@ const emit = defineEmits(["ok"]);
/** 查询参数列表 */
const show = (dataName: string) => {
getDataNameList();
if(dataName){
queryParams.dataName = dataName;
} else {
queryParams.dataName = 'master';
}
getList();
visible.value = true;
getDataNameList();
if (dataName) {
queryParams.dataName = dataName;
} else {
queryParams.dataName = 'master';
}
getList();
visible.value = true;
}
/** 单击选择行 */
const clickRow = (row: DbTableVO) => {
tableRef.value.toggleRowSelection(row);
// ele bug
tableRef.value?.toggleRowSelection(row);
}
/** 多选框选中数据 */
const handleSelectionChange = (selection: DbTableVO[]) => {
tables.value = selection.map(item => item.tableName);
tables.value = selection.map(item => item.tableName);
}
/** 查询表数据 */
const getList = async () => {
const res = await listDbTable(queryParams);
dbTableList.value = res.rows;
total.value = res.total;
const res = await listDbTable(queryParams);
dbTableList.value = res.rows;
total.value = res.total;
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNum = 1;
getList();
queryParams.pageNum = 1;
getList();
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields();
handleQuery();
queryFormRef.value?.resetFields();
handleQuery();
}
/** 导入按钮操作 */
const handleImportTable = async () => {
const tableNames = tables.value.join(",");
if (tableNames == "") {
proxy?.$modal.msgError("请选择要导入的表");
return;
}
const res = await importTable({ tables: tableNames, dataName: queryParams.dataName });
proxy?.$modal.msgSuccess(res.msg);
if (res.code === 200) {
visible.value = false;
emit("ok");
}
const tableNames = tables.value.join(",");
if (tableNames == "") {
proxy?.$modal.msgError("请选择要导入的表");
return;
}
const res = await importTable({ tables: tableNames, dataName: queryParams.dataName });
proxy?.$modal.msgSuccess(res.msg);
if (res.code === 200) {
visible.value = false;
emit("ok");
}
}
/** 查询多数据源名称 */
const getDataNameList = async () => {
@ -119,6 +118,6 @@ const getDataNameList = async () => {
}
defineExpose({
show,
show,
});
</script>

View File

@ -1,39 +1,41 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="数据源" prop="dataName">
<el-select v-model="queryParams.dataName" filterable clearable placeholder="请选择/输入数据源名称" style="width: 200px">
<el-option key="" label="全部" value="" />
<el-option v-for="item in dataNameList" :key="item" :label="item" :value="item"> </el-option>
</el-select>
</el-form-item>
<el-form-item label="表名称" prop="tableName">
<el-input v-model="queryParams.tableName" placeholder="请输入表名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="表描述" prop="tableComment">
<el-input v-model="queryParams.tableComment" placeholder="请输入表描述" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="创建时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb-[10px]" v-show="showSearch">
<el-card shadow="hover">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="数据源" prop="dataName">
<el-select v-model="queryParams.dataName" filterable clearable placeholder="请选择/输入数据源名称" style="width: 200px">
<el-option key="" label="全部" value="" />
<el-option v-for="item in dataNameList" :key="item" :label="item" :value="item"> </el-option>
</el-select>
</el-form-item>
<el-form-item label="表名称" prop="tableName">
<el-input v-model="queryParams.tableName" placeholder="请输入表名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="表描述" prop="tableComment">
<el-input v-model="queryParams.tableComment" placeholder="请输入表描述" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="创建时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<el-card shadow="hover">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
@ -99,9 +101,9 @@
:name="(key as any).substring((key as any).lastIndexOf('/') + 1, (key as any).indexOf('.vm'))"
:key="value"
>
<el-link :underline="false" icon="DocumentCopy" v-copyText="value" v-copyText:callback="copyTextSuccess" style="float:right"
>&nbsp;复制</el-link
>
<el-link :underline="false" icon="DocumentCopy" v-copyText="value" v-copyText:callback="copyTextSuccess" style="float:right">
&nbsp;复制
</el-link>
<pre>{{ value }}</pre>
</el-tab-pane>
</el-tabs>
@ -114,9 +116,7 @@
import { listTable, previewTable, delTable, genCode, synchDb, getDataNames } from '@/api/tool/gen';
import { TableQuery, TableVO } from '@/api/tool/gen/types';
import router from '@/router';
import importTable from './importTable.vue';
import { ComponentInternalInstance } from 'vue';
import { ElForm, DateModelType } from 'element-plus';
import ImportTable from './importTable.vue';
const route = useRoute();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -132,35 +132,35 @@ const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
const uniqueId = ref("");
const dataNameList = ref<Array<string>>([]);
const queryFormRef = ref(ElForm);
const importRef = ref(importTable);
const queryFormRef = ref<ElFormInstance>();
const importRef = ref<InstanceType<typeof ImportTable>>();
const queryParams = ref<TableQuery>({
pageNum: 1,
pageSize: 10,
tableName: '',
tableComment: '',
dataName: ""
pageNum: 1,
pageSize: 10,
tableName: '',
tableComment: '',
dataName: ""
})
const preview = ref <any>({
data: {},
activeName: 'domain.java'
const preview = ref<any>({
data: {},
activeName: 'domain.java'
})
const dialog = reactive<DialogOption>({
visible: false,
title: '代码预览'
visible: false,
title: '代码预览'
});
onActivated(() => {
const time = route.query.t;
if (time != null && time != uniqueId.value) {
uniqueId.value = time as string;
queryParams.value.pageNum = Number(route.query.pageNum);
dateRange.value = ['', ''];
queryFormRef.value.resetFields();
getList();
}
const time = route.query.t;
if (time != null && time != uniqueId.value) {
uniqueId.value = time as string;
queryParams.value.pageNum = Number(route.query.pageNum);
dateRange.value = ['', ''];
queryFormRef.value?.resetFields();
getList();
}
})
/** 查询多数据源名称 */
@ -171,81 +171,81 @@ const getDataNameList = async () => {
/** 查询表集合 */
const getList = async () => {
loading.value = true;
const res = await listTable(proxy?.addDateRange(queryParams.value, dateRange.value));
tableList.value = res.rows;
total.value = res.total;
loading.value = false;
loading.value = true;
const res = await listTable(proxy?.addDateRange(queryParams.value, dateRange.value));
tableList.value = res.rows;
total.value = res.total;
loading.value = false;
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
queryParams.value.pageNum = 1;
getList();
}
/** 生成代码操作 */
const handleGenTable = async (row?: TableVO) => {
const tbIds = row?.tableId || ids.value;
if (tbIds == "") {
proxy?.$modal.msgError('请选择要生成的数据');
return;
}
if (row?.genType === "1") {
await genCode(row.tableId);
proxy?.$modal.msgSuccess('成功生成到自定义路径:' + row.genPath);
} else {
proxy?.$download.zip('/tool/gen/batchGenCode?tableIdStr=' + tbIds, 'ruoyi.zip');
}
const tbIds = row?.tableId || ids.value;
if (tbIds == "") {
proxy?.$modal.msgError('请选择要生成的数据');
return;
}
if (row?.genType === "1") {
await genCode(row.tableId);
proxy?.$modal.msgSuccess('成功生成到自定义路径:' + row.genPath);
} else {
proxy?.$download.zip('/tool/gen/batchGenCode?tableIdStr=' + tbIds, 'ruoyi.zip');
}
}
/** 同步数据库操作 */
const handleSynchDb = async (row: TableVO) => {
const tableId = row.tableId;
await proxy?.$modal.confirm('确认要强制同步"' + row.tableName + '"表结构吗?');
await synchDb(tableId);
proxy?.$modal.msgSuccess('同步成功');
const tableId = row.tableId;
await proxy?.$modal.confirm('确认要强制同步"' + row.tableName + '"表结构吗?');
await synchDb(tableId);
proxy?.$modal.msgSuccess('同步成功');
}
/** 打开导入表弹窗 */
const openImportTable = () => {
importRef.value.show(queryParams.value.dataName);
importRef.value?.show(queryParams.value.dataName);
}
/** 重置按钮操作 */
const resetQuery = () => {
dateRange.value = ['', ''];
queryFormRef.value.resetFields();
handleQuery();
dateRange.value = ['', ''];
queryFormRef.value?.resetFields();
handleQuery();
}
/** 预览按钮 */
const handlePreview = async (row: TableVO) => {
const res = await previewTable(row.tableId);
preview.value.data = res.data;
dialog.visible = true;
preview.value.activeName = 'domain.java';
const res = await previewTable(row.tableId);
preview.value.data = res.data;
dialog.visible = true;
preview.value.activeName = 'domain.java';
}
/** 复制代码成功 */
const copyTextSuccess = () => {
proxy?.$modal.msgSuccess('复制成功');
proxy?.$modal.msgSuccess('复制成功');
}
// 多选框选中数据
const handleSelectionChange = (selection: TableVO[]) => {
ids.value = selection.map(item => item.tableId);
single.value = selection.length != 1;
multiple.value = !selection.length;
ids.value = selection.map(item => item.tableId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 修改按钮操作 */
const handleEditTable = (row?: TableVO) => {
const tableId = row?.tableId || ids.value[0];
router.push({ path: '/tool/gen-edit/index/' + tableId, query: { pageNum: queryParams.value.pageNum } });
const tableId = row?.tableId || ids.value[0];
router.push({ path: '/tool/gen-edit/index/' + tableId, query: { pageNum: queryParams.value.pageNum } });
}
/** 删除按钮操作 */
const handleDelete = async (row?: TableVO) => {
const tableIds = row?.tableId || ids.value;
await proxy?.$modal.confirm('是否确认删除表编号为"' + tableIds + '"的数据项?');
await delTable(tableIds);
getList();
proxy?.$modal.msgSuccess('删除成功');
const tableIds = row?.tableId || ids.value;
await proxy?.$modal.confirm('是否确认删除表编号为"' + tableIds + '"的数据项?');
await delTable(tableIds);
getList();
proxy?.$modal.msgSuccess('删除成功');
}
onMounted(() => {
getList();
getDataNameList();
getList();
getDataNameList();
})
</script>