!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": { "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, "useRouter": true,
"useRoute": true, "useRoute": true,
"EffectScope": true, "EffectScope": true,

View File

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

View File

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

View File

@ -9,64 +9,64 @@ import { parseStrEmpty } from '@/utils/ruoyi';
* 查询用户列表 * 查询用户列表
* @param query * @param query
*/ */
export function listUser(query: UserQuery): AxiosPromise<UserVO[]> { export const listUser = (query: UserQuery): AxiosPromise<UserVO[]> => {
return request({ return request({
url: '/system/user/list', url: '/system/user/list',
method: 'get', method: 'get',
params: query params: query
}); });
} };
/** /**
* 获取用户详情 * 获取用户详情
* @param userId * @param userId
*/ */
export function getUser(userId?: string | number): AxiosPromise<UserInfoVO> { export const getUser = (userId?: string | number): AxiosPromise<UserInfoVO> => {
return request({ return request({
url: '/system/user/' + parseStrEmpty(userId), url: '/system/user/' + parseStrEmpty(userId),
method: 'get' method: 'get'
}); });
} };
/** /**
* 新增用户 * 新增用户
*/ */
export function addUser(data: UserForm) { export const addUser = (data: UserForm) => {
return request({ return request({
url: '/system/user', url: '/system/user',
method: 'post', method: 'post',
data: data data: data
}); });
} };
/** /**
* 修改用户 * 修改用户
*/ */
export function updateUser(data: UserForm) { export const updateUser = (data: UserForm) => {
return request({ return request({
url: '/system/user', url: '/system/user',
method: 'put', method: 'put',
data: data data: data
}); });
} };
/** /**
* 删除用户 * 删除用户
* @param userId 用户ID * @param userId 用户ID
*/ */
export function delUser(userId: Array<string | number> | string | number) { export const delUser = (userId: Array<string | number> | string | number) => {
return request({ return request({
url: '/system/user/' + userId, url: '/system/user/' + userId,
method: 'delete' method: 'delete'
}); });
} };
/** /**
* 用户密码重置 * 用户密码重置
* @param userId 用户ID * @param userId 用户ID
* @param password 密码 * @param password 密码
*/ */
export function resetUserPwd(userId: string | number, password: string) { export const resetUserPwd = (userId: string | number, password: string) => {
const data = { const data = {
userId, userId,
password password
@ -76,14 +76,14 @@ export function resetUserPwd(userId: string | number, password: string) {
method: 'put', method: 'put',
data: data data: data
}); });
} };
/** /**
* 用户状态修改 * 用户状态修改
* @param userId 用户ID * @param userId 用户ID
* @param status 用户状态 * @param status 用户状态
*/ */
export function changeUserStatus(userId: number | string, status: string) { export const changeUserStatus = (userId: number | string, status: string) => {
const data = { const data = {
userId, userId,
status status
@ -93,36 +93,36 @@ export function changeUserStatus(userId: number | string, status: string) {
method: 'put', method: 'put',
data: data data: data
}); });
} };
/** /**
* 查询用户个人信息 * 查询用户个人信息
*/ */
export function getUserProfile(): AxiosPromise<UserInfoVO> { export const getUserProfile = (): AxiosPromise<UserInfoVO> => {
return request({ return request({
url: '/system/user/profile', url: '/system/user/profile',
method: 'get' method: 'get'
}); });
} };
/** /**
* 修改用户个人信息 * 修改用户个人信息
* @param data 用户信息 * @param data 用户信息
*/ */
export function updateUserProfile(data: UserForm) { export const updateUserProfile = (data: UserForm) => {
return request({ return request({
url: '/system/user/profile', url: '/system/user/profile',
method: 'put', method: 'put',
data: data data: data
}); });
} };
/** /**
* 用户密码重置 * 用户密码重置
* @param oldPassword 旧密码 * @param oldPassword 旧密码
* @param newPassword 新密码 * @param newPassword 新密码
*/ */
export function updateUserPwd(oldPassword: string, newPassword: string) { export const updateUserPwd = (oldPassword: string, newPassword: string) => {
const data = { const data = {
oldPassword, oldPassword,
newPassword newPassword
@ -132,49 +132,66 @@ export function updateUserPwd(oldPassword: string, newPassword: string) {
method: 'put', method: 'put',
params: data params: data
}); });
} };
/** /**
* 用户头像上传 * 用户头像上传
* @param data 头像文件 * @param data 头像文件
*/ */
export function uploadAvatar(data: FormData) { export const uploadAvatar = (data: FormData) => {
return request({ return request({
url: '/system/user/profile/avatar', url: '/system/user/profile/avatar',
method: 'post', method: 'post',
data: data data: data
}); });
} };
/** /**
* 查询授权角色 * 查询授权角色
* @param userId 用户ID * @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({ return request({
url: '/system/user/authRole/' + userId, url: '/system/user/authRole/' + userId,
method: 'get' method: 'get'
}); });
} };
/** /**
* 保存授权角色 * 保存授权角色
* @param data 用户ID * @param data 用户ID
*/ */
export function updateAuthRole(data: { userId: string; roleIds: string }) { export const updateAuthRole = (data: { userId: string; roleIds: string }) => {
return request({ return request({
url: '/system/user/authRole', url: '/system/user/authRole',
method: 'put', method: 'put',
params: data params: data
}); });
} };
/** /**
* 查询部门下拉树结构 * 查询部门下拉树结构
*/ */
export function deptTreeSelect(): AxiosPromise<DeptVO[]> { export const deptTreeSelect = (): AxiosPromise<DeptVO[]> => {
return request({ return request({
url: '/system/user/deptTree', url: '/system/user/deptTree',
method: 'get' 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; box-sizing: border-box;
} }
html.dark .svg-icon, html.dark svg {
fill: var(--el-text-color-regular);
}
#app { #app {
height: 100%; height: 100%;
} }
@ -137,6 +141,7 @@ aside {
border: 1px solid var(--el-border-color-light); border: 1px solid var(--el-border-color-light);
background-color: var(--el-bg-color-overlay); background-color: var(--el-bg-color-overlay);
padding: 0.75rem; padding: 0.75rem;
transition: all ease 0.3s;
&:hover { &:hover {
box-shadow: 0 2px 12px #0000001a; box-shadow: 0 2px 12px #0000001a;

View File

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

View File

@ -84,7 +84,7 @@
.sub-menu-title-noDropdown, .sub-menu-title-noDropdown,
.el-sub-menu__title { .el-sub-menu__title {
&:hover { &: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 { .el-menu-item {
&:hover { &:hover {
// you can use $sub-menuHover // 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 // base color
$blue: #324157; $blue: #324157;
$light-blue: #3a71a8; $light-blue: #3a71a8;
@ -9,32 +44,22 @@ $yellow: #fec171;
$panGreen: #30b08f; $panGreen: #30b08f;
// 默认菜单主题风格 // 默认菜单主题风格
$base-menu-color: #bfcbd9; $base-menu-color: var(--menuColor);
$base-menu-color-active: #f4f4f5; $base-menu-hover: var(--menuHover);
$base-menu-background: #304156; $base-menu-color-active: var(--menuActiveText);
$base-menu-background: var(--menuBg);
$base-logo-title-color: #ffffff; $base-logo-title-color: #ffffff;
$base-menu-light-color: rgba(0, 0, 0, 0.7); $base-menu-light-color: rgba(0, 0, 0, 0.7);
$base-menu-light-background: #ffffff; $base-menu-light-background: #ffffff;
$base-logo-light-title-color: #001529; $base-logo-light-title-color: #001529;
$base-sub-menu-background: #1f2d3d; $base-sub-menu-background: var(--subMenuBg);
$base-sub-menu-hover: #001528; $base-sub-menu-hover: var(--subMenuHover);
$base-sub-menu-title-hover: var(--subMenuTitleHover);
// 自定义暗色菜单风格 // 表单头背景色和标题颜色
/** $table-header-bg: var(--tableHeaderBg);
$base-menu-color:hsla(0,0%,100%,.65); $table-header-text-color: var(--tableHeaderTextColor);
$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;
*/
$--color-primary: #409eff; $--color-primary: #409eff;
$--color-success: #67c23a; $--color-success: #67c23a;

View File

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

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
<template> <template>
<div style="padding: 0 15px;" @click="toggleClick"> <div style="padding: 0 15px;" @click="toggleClick">
<svg :class="{'is-active':isActive}" class="hamburger" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="64" height="64"> <svg :class="{ 'is-active': isActive }" class="hamburger" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="64" height="64">
<path <path
d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z"
/> />
@ -9,16 +9,15 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { propTypes } from '@/utils/propTypes';
defineProps({ defineProps({
isActive: { isActive: propTypes.bool.def(false)
type: Boolean,
default: false
}
}) })
const emit = defineEmits(['toggleClick']) const emit = defineEmits(['toggleClick'])
const toggleClick = () => { const toggleClick = () => {
emit('toggleClick'); emit('toggleClick');
} }
</script> </script>

View File

@ -17,12 +17,12 @@
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts" name="HeaderSearch">
import Fuse from 'fuse.js' import Fuse from 'fuse.js';
import { getNormalPath } from '@/utils/ruoyi' import { getNormalPath } from '@/utils/ruoyi';
import { isHttp } from '@/utils/validate' import { isHttp } from '@/utils/validate';
import usePermissionStore from '@/store/modules/permission' import usePermissionStore from '@/store/modules/permission';
import { RouteOption } from 'vue-router' import { RouteOption } from 'vue-router';
type Router = Array<{ type Router = Array<{
path: string; path: string;
@ -34,7 +34,7 @@ const options = ref<any>([]);
const searchPool = ref<Router>([]); const searchPool = ref<Router>([]);
const show = ref(false); const show = ref(false);
const fuse = ref(); const fuse = ref();
const headerSearchSelectRef = ref(ElSelect); const headerSearchSelectRef = ref<ElSelectInstance>();
const router = useRouter(); const router = useRouter();
const routes = computed(() => usePermissionStore().routes); const routes = computed(() => usePermissionStore().routes);
@ -123,9 +123,9 @@ onMounted(() => {
searchPool.value = generateRoutes(routes.value); searchPool.value = generateRoutes(routes.value);
}) })
watchEffect(() => { // watchEffect(() => {
searchPool.value = generateRoutes(routes.value) // searchPool.value = generateRoutes(routes.value)
}) // })
watch(show, (value) => { watch(show, (value) => {
if (value) { if (value) {
@ -142,40 +142,40 @@ watch(searchPool, (list) => {
<style lang="scss" scoped> <style lang="scss" scoped>
.header-search { .header-search {
font-size: 0 !important; font-size: 0 !important;
.search-icon { .search-icon {
cursor: pointer; cursor: pointer;
font-size: 18px; font-size: 18px;
vertical-align: middle; 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;
} }
}
&.show {
.header-search-select { .header-search-select {
width: 210px; font-size: 18px;
margin-left: 10px; 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> </style>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -125,6 +125,9 @@ const initTags = () => {
} }
const addTags = () => { const addTags = () => {
const { name } = route; const { name } = route;
if(route.query.title) {
route.meta.title = route.query.title;
}
if (name) { if (name) {
useTagsViewStore().addView(route); useTagsViewStore().addView(route);
if (route.meta.link) { if (route.meta.link) {
@ -237,8 +240,8 @@ onMounted(() => {
.tags-view-container { .tags-view-container {
height: 34px; height: 34px;
width: 100%; width: 100%;
background: #fff; background-color: var(--el-bg-color);
border-bottom: 1px solid #d8dce5; border: 1px solid var(--el-border-color-light);
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04); box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04);
.tags-view-wrapper { .tags-view-wrapper {
.tags-view-item { .tags-view-item {
@ -247,13 +250,16 @@ onMounted(() => {
cursor: pointer; cursor: pointer;
height: 26px; height: 26px;
line-height: 23px; line-height: 23px;
border: 1px solid #d8dce5; background-color: var(--el-bg-color);
border: 1px solid var(--el-border-color-light);
color: #495060; color: #495060;
background: #fff;
padding: 0 8px; padding: 0 8px;
font-size: 12px; font-size: 12px;
margin-left: 5px; margin-left: 5px;
margin-top: 4px; margin-top: 4px;
&:hover {
color: var(--el-color-primary);
}
&:first-of-type { &:first-of-type {
margin-left: 15px; margin-left: 15px;
} }
@ -279,7 +285,7 @@ onMounted(() => {
} }
.contextmenu { .contextmenu {
margin: 0; margin: 0;
background: #fff; background: var(--el-bg-color);
z-index: 3000; z-index: 3000;
position: absolute; position: absolute;
list-style-type: none; list-style-type: none;
@ -287,7 +293,6 @@ onMounted(() => {
border-radius: 4px; border-radius: 4px;
font-size: 12px; font-size: 12px;
font-weight: 400; font-weight: 400;
color: #333;
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3); box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
li { li {
margin: 0; 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'; import { LoadingInstance } from 'element-plus/es/components/loading/src/loading';
let loadingInstance: LoadingInstance; let loadingInstance: LoadingInstance;
export default { export default {
// 消息提示 // 消息提示
msg(content: string) { msg(content: any) {
ElMessage.info(content); ElMessage.info(content);
}, },
// 错误消息 // 错误消息
msgError(content: string) { msgError(content: any) {
ElMessage.error(content); ElMessage.error(content);
}, },
// 成功消息 // 成功消息
msgSuccess(content: string) { msgSuccess(content: any) {
ElMessage.success(content); ElMessage.success(content);
}, },
// 警告消息 // 警告消息
msgWarning(content: string) { msgWarning(content: any) {
ElMessage.warning(content); ElMessage.warning(content);
}, },
// 弹出提示 // 弹出提示
alert(content: string) { alert(content: any) {
ElMessageBox.alert(content, '系统提示'); ElMessageBox.alert(content, '系统提示');
}, },
// 错误提示 // 错误提示
alertError(content: string) { alertError(content: any) {
ElMessageBox.alert(content, '系统提示', { type: 'error' }); ElMessageBox.alert(content, '系统提示', { type: 'error' });
}, },
// 成功提示 // 成功提示
alertSuccess(content: string, s: string, p: { dangerouslyUseHTMLString: boolean }) { alertSuccess(content: any) {
ElMessageBox.alert(content, '系统提示', { type: 'success' }); ElMessageBox.alert(content, '系统提示', { type: 'success' });
}, },
// 警告提示 // 警告提示
alertWarning(content: string) { alertWarning(content: any) {
ElMessageBox.alert(content, '系统提示', { type: 'warning' }); ElMessageBox.alert(content, '系统提示', { type: 'warning' });
}, },
// 通知提示 // 通知提示
notify(content: string) { notify(content: any) {
ElNotification.info(content); ElNotification.info(content);
}, },
// 错误通知 // 错误通知
notifyError(content: string) { notifyError(content: any) {
ElNotification.error(content); ElNotification.error(content);
}, },
// 成功通知 // 成功通知
notifySuccess(content: string) { notifySuccess(content: any) {
ElNotification.success(content); ElNotification.success(content);
}, },
// 警告通知 // 警告通知
notifyWarning(content: string) { notifyWarning(content: any) {
ElNotification.warning(content); ElNotification.warning(content);
}, },
// 确认窗体 // 确认窗体
confirm(content: string): Promise<MessageBoxData> { confirm(content: any): Promise<MessageBoxData> {
return ElMessageBox.confirm(content, '系统提示', { return ElMessageBox.confirm(content, '系统提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
@ -59,7 +59,7 @@ export default {
}); });
}, },
// 提交内容 // 提交内容
prompt(content: string) { prompt(content: any) {
return ElMessageBox.prompt(content, '系统提示', { return ElMessageBox.prompt(content, '系统提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',

View File

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

View File

@ -54,8 +54,11 @@ export const useTagsViewStore = defineStore('tagsView', () => {
resolve([...visitedViews.value]); resolve([...visitedViews.value]);
}); });
}; };
const delCachedView = (view: TagView): Promise<string[]> => { const delCachedView = (view?: TagView): Promise<string[]> => {
const viewName = view.name as string; let viewName = '';
if (view) {
viewName = view.name as string;
}
return new Promise((resolve) => { return new Promise((resolve) => {
const index = cachedViews.value.indexOf(viewName); const index = cachedViews.value.indexOf(viewName);
index > -1 && cachedViews.value.splice(index, 1); index > -1 && cachedViews.value.splice(index, 1);
@ -167,6 +170,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
const addCachedView = (view: TagView): void => { const addCachedView = (view: TagView): void => {
const viewName = view.name as string; const viewName = view.name as string;
if (!viewName) return;
if (cachedViews.value.includes(viewName)) return; if (cachedViews.value.includes(viewName)) return;
if (!view.meta?.noCache) { if (!view.meta?.noCache) {
cachedViews.value.push(viewName); 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 { declare global {
/** vue Instance */
declare type ComponentInternalInstance = ComponentInstance;
/**vue */
declare type PropType<T> = VuePropType<T>;
/** /**
* 界面字段隐藏属性 * 界面字段隐藏属性
*/ */
interface FieldOption { declare interface FieldOption {
key: number; key: number;
label: string; label: string;
visible: boolean; visible: boolean;
@ -12,7 +18,7 @@ declare global {
/** /**
* 弹窗属性 * 弹窗属性
*/ */
interface DialogOption { declare interface DialogOption {
/** /**
* 弹窗标题 * 弹窗标题
*/ */
@ -23,7 +29,7 @@ declare global {
visible: boolean; visible: boolean;
} }
interface UploadOption { declare interface UploadOption {
/** 设置上传的请求头部 */ /** 设置上传的请求头部 */
headers: { [key: string]: any }; headers: { [key: string]: any };
@ -34,7 +40,7 @@ declare global {
/** /**
* 导入属性 * 导入属性
*/ */
interface ImportOption extends UploadOption { declare interface ImportOption extends UploadOption {
/** 是否显示弹出层 */ /** 是否显示弹出层 */
open: boolean; open: boolean;
/** 弹出层标题 */ /** 弹出层标题 */
@ -48,14 +54,14 @@ declare global {
/** /**
* 字典数据 数据配置 * 字典数据 数据配置
*/ */
interface DictDataOption { declare interface DictDataOption {
label: string; label: string;
value: string; value: string;
elTagType?: ElTagType; elTagType?: ElTagType;
elTagClass?: string; elTagClass?: string;
} }
interface BaseEntity { declare interface BaseEntity {
createBy?: any; createBy?: any;
createDept?: any; createDept?: any;
createTime?: string; createTime?: string;
@ -68,15 +74,15 @@ declare global {
* T : 表单数据 * T : 表单数据
* D : 查询参数 * D : 查询参数
*/ */
interface PageData<T, D> { declare interface PageData<T, D> {
form: T; form: T;
queryParams: D; queryParams: D;
rules: FormRules; rules: ElFormRules;
} }
/** /**
* 分页查询参数 * 分页查询参数
*/ */
interface PageQuery { declare interface PageQuery {
pageNum: number; pageNum: number;
pageSize: number; pageSize: number;
} }

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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