提交代码

This commit is contained in:
jiangzhe 2024-05-29 15:58:30 +08:00
parent b065bbdfaa
commit 74bb340696
28 changed files with 788 additions and 379 deletions

View File

@ -1,11 +1,10 @@
# 页面标题 # 页面标题
VITE_APP_TITLE = RuoYi-Vue-Plus多租户管理系统 VITE_APP_TITLE = 校本资源库管理系统
# 开发环境配置 # 开发环境配置
VITE_APP_ENV = 'development' VITE_APP_ENV = 'development'
# 开发环境 # 开发环境
VITE_APP_BASE_API = '/dev-api' VITE_APP_BASE_API = '/api'
# 应用访问路径 例如使用前缀 /admin/ # 应用访问路径 例如使用前缀 /admin/
VITE_APP_CONTEXT_PATH = '/' VITE_APP_CONTEXT_PATH = '/'

View File

@ -1,6 +1,5 @@
# 页面标题 # 页面标题
VITE_APP_TITLE = RuoYi-Vue-Plus多租户管理系统 VITE_APP_TITLE = 校本资源库管理系统
# 生产环境配置 # 生产环境配置
VITE_APP_ENV = 'production' VITE_APP_ENV = 'production'
@ -14,7 +13,7 @@ VITE_APP_MONITRO_ADMIN = '/admin/applications'
VITE_APP_SNAILJOB_ADMIN = 'http://localhost:8800/snail-job' VITE_APP_SNAILJOB_ADMIN = 'http://localhost:8800/snail-job'
# 生产环境 # 生产环境
VITE_APP_BASE_API = '/prod-api' VITE_APP_BASE_API = '/api'
# 是否在打包时开启压缩,支持 gzip 和 brotli # 是否在打包时开启压缩,支持 gzip 和 brotli
VITE_BUILD_COMPRESS = gzip VITE_BUILD_COMPRESS = gzip

View File

@ -1,7 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2019 RuoYi-Vue-Plus Copyright (c) 2019 校本资源库管理系统
Permission is hereby granted, free of charge, to any person obtaining a copy of Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to the Software without restriction, including without limitation the rights to

View File

@ -6,7 +6,7 @@
<meta name="renderer" content="webkit" /> <meta name="renderer" content="webkit" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" /> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
<title>RuoYi-Vue-Plus多租户管理系统</title> <title>校本资源库管理系统多租户管理系统</title>
<!--[if lt IE 11 <!--[if lt IE 11
]><script> ]><script>
window.location.href = '/html/ie.html'; window.location.href = '/html/ie.html';

View File

@ -50,6 +50,7 @@
"vform3-builds": "3.0.10", "vform3-builds": "3.0.10",
"vue": "3.4.25", "vue": "3.4.25",
"vue-cropper": "1.1.1", "vue-cropper": "1.1.1",
"vue-echarts": "^6.7.2",
"vue-i18n": "9.10.2", "vue-i18n": "9.10.2",
"vue-router": "4.3.2", "vue-router": "4.3.2",
"vue-types": "5.1.1", "vue-types": "5.1.1",
@ -76,10 +77,10 @@
"eslint": "8.57.0", "eslint": "8.57.0",
"eslint-config-prettier": "9.1.0", "eslint-config-prettier": "9.1.0",
"eslint-define-config": "2.1.0", "eslint-define-config": "2.1.0",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-prettier": "5.1.3", "eslint-plugin-prettier": "5.1.3",
"eslint-plugin-promise": "6.1.1", "eslint-plugin-promise": "6.1.1",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-vue": "9.23.0", "eslint-plugin-vue": "9.23.0",
"fast-glob": "3.3.2", "fast-glob": "3.3.2",
"postcss": "8.4.36", "postcss": "8.4.36",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
src/assets/icons/course.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
src/assets/icons/image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

BIN
src/assets/icons/video.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -213,3 +213,7 @@ aside {
margin-bottom: 10px; margin-bottom: 10px;
} }
} }
.w100 {
width: 100%;
}

View File

@ -5,7 +5,7 @@
</template> </template>
<script setup> <script setup>
const url = ref('https://gitee.com/dromara/RuoYi-Vue-Plus'); const url = ref('https://gitee.com/dromara/校本资源库管理系统');
function goto() { function goto() {
window.open(url.value); window.open(url.value);

View File

@ -1,67 +1,23 @@
<template> <template>
<div class="navbar"> <div class="navbar">
<hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container" @toggle-click="toggleSideBar" /> <hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container"
@toggle-click="toggleSideBar" />
<breadcrumb v-if="!settingsStore.topNav" id="breadcrumb-container" class="breadcrumb-container" /> <breadcrumb v-if="!settingsStore.topNav" id="breadcrumb-container" class="breadcrumb-container" />
<top-nav v-if="settingsStore.topNav" id="topmenu-container" class="topmenu-container" /> <top-nav v-if="settingsStore.topNav" id="topmenu-container" class="topmenu-container" />
<div class="right-menu flex align-center"> <div class="right-menu flex align-center">
<template v-if="appStore.device !== 'mobile'"> <template v-if="appStore.device !== 'mobile'">
<el-select <el-select v-if="userId === 1 && tenantEnabled" v-model="companyName" class="min-w-244px" clearable filterable
v-if="userId === 1 && tenantEnabled" reserve-keyword :placeholder="$t('navbar.selectTenant')" @change="dynamicTenantEvent"
v-model="companyName" @clear="dynamicClearEvent">
class="min-w-244px" <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId">
clearable </el-option>
filterable
reserve-keyword
:placeholder="$t('navbar.selectTenant')"
@change="dynamicTenantEvent"
@clear="dynamicClearEvent"
>
<el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"> </el-option>
<template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template> <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
</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" /> <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="$t('navbar.message')" effect="dark" placement="bottom">
<div>
<el-popover placement="bottom" trigger="click" transition="el-zoom-in-top" :width="300" :persistent="false">
<template #reference>
<el-badge :value="newNotice > 0 ? newNotice : ''" :max="99">
<svg-icon icon-class="message" />
</el-badge>
</template>
<template #default>
<notice></notice>
</template>
</el-popover>
</div>
</el-tooltip>
<el-tooltip content="Github" effect="dark" placement="bottom">
<ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
</el-tooltip>
<el-tooltip :content="$t('navbar.document')" effect="dark" placement="bottom">
<ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
</el-tooltip>
<el-tooltip :content="$t('navbar.full')" effect="dark" placement="bottom">
<screenfull id="screenfull" class="right-menu-item hover-effect" />
</el-tooltip>
<el-tooltip :content="$t('navbar.language')" effect="dark" placement="bottom">
<lang-select id="lang-select" class="right-menu-item hover-effect" />
</el-tooltip>
<el-tooltip :content="$t('navbar.layoutSize')" effect="dark" placement="bottom">
<size-select id="size-select" class="right-menu-item hover-effect" />
</el-tooltip>
</template> </template>
<div class="avatar-container"> <div class="avatar-container">
<el-dropdown class="right-menu-item hover-effect" trigger="click" @command="handleCommand"> <el-dropdown class="right-menu-item hover-effect" trigger="click" @command="handleCommand">
@ -74,9 +30,7 @@
<router-link v-if="!dynamic" to="/user/profile"> <router-link v-if="!dynamic" to="/user/profile">
<el-dropdown-item>{{ $t('navbar.personalCenter') }}</el-dropdown-item> <el-dropdown-item>{{ $t('navbar.personalCenter') }}</el-dropdown-item>
</router-link> </router-link>
<el-dropdown-item v-if="settingsStore.showSettings" command="setLayout">
<span>{{ $t('navbar.layoutSetting') }}</span>
</el-dropdown-item>
<el-dropdown-item divided command="logout"> <el-dropdown-item divided command="logout">
<span>{{ $t('navbar.logout') }}</span> <span>{{ $t('navbar.logout') }}</span>
</el-dropdown-item> </el-dropdown-item>

View File

@ -34,7 +34,7 @@ defineProps({
} }
}); });
const title = ref('RuoYi-Vue-Plus'); const title = ref('校本资源库管理系统');
const settingsStore = useSettingsStore(); const settingsStore = useSettingsStore();
const sideTheme = computed(() => settingsStore.sideTheme); const sideTheme = computed(() => settingsStore.sideTheme);
</script> </script>

View File

@ -55,7 +55,7 @@ const onNewsClick = (item: any) => {
// //
const onGoToGiteeClick = () => { const onGoToGiteeClick = () => {
window.open('https://gitee.com/dromara/RuoYi-Vue-Plus/tree/5.X/'); window.open('https://gitee.com/dromara/校本资源库管理系统/tree/5.X/');
}; };
onMounted(() => { onMounted(() => {

View File

@ -0,0 +1,359 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
:leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="姓名" prop="nickName">
<el-input v-model="queryParams.nickName" placeholder="请输入用户昵称" clearable style="width: 240px"
@keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="年级班级" prop="deptId">
<el-input v-model="queryParams.deptId" placeholder="请输入年级班级" clearable style="width: 240px"
@keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px"
@keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd"
v-hasPermi="['system:user:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()"
v-hasPermi="['system:user:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"
v-hasPermi="['system:user:remove']">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Upload" @click="handleExport"
v-hasPermi="['system:user:export']">导入人员</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="teacherList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="姓名" align="center" prop="nickName" />
<el-table-column label="手机号码" align="center" prop="phonenumber" />
<el-table-column label="年级/班级" align="center" prop="deptId" />
<el-table-column label="职务" align="center" prop="userType" />
<el-table-column label="学科" align="center" prop="email" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
v-hasPermi="['system:user:edit']">修改</el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
v-hasPermi="['system:user:remove']">删除</el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改教职工管理对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="800px" append-to-body>
<el-form ref="UserFormRef" :model="form" :rules="rules" label-width="90px">
<el-row>
<el-col :span="12">
<el-form-item label="姓名" prop="nickName">
<el-input v-model="form.nickName" placeholder="请输入姓名" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="年级/班级" prop="deptId">
<el-input v-model="form.deptId" placeholder="请输入年级/班级" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="性别" prop="gender">
<el-input v-model="form.userName" placeholder="请输入性别" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="出生日期" prop="email">
<el-input v-model="form.email" placeholder="请输入出生日期" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="学历" prop="avatar">
<el-input v-model="form.avatar" placeholder="请输入学历" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="学位" prop="password">
<el-input v-model="form.password" placeholder="请输入学位" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="form.phonenumber" placeholder="请输入手机号码" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="工作电话" prop="loginIp">
<el-input v-model="form.loginIp" placeholder="请输入工作电话" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="职务" prop="loginDate">
<el-input v-model="form.remark" placeholder="请输入职务" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="学科" prop="remark">
<el-input v-model="form.remark" placeholder="请输入学科" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="电子邮箱" prop="remark">
<el-input v-model="form.remark" placeholder="请输入电子邮箱" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="Teacher" lang="ts">
import { listUser, getUser, delUser, addUser, updateUser } from '@/api/system/user';
import { UserVO, UserQuery, UserForm } from '@/api/system/user/types';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const teacherList = ref<UserVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const queryFormRef = ref<ElFormInstance>();
const UserFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const initFormData: UserForm = {
userId: undefined,
deptId: undefined,
userName: undefined,
nickName: undefined,
userType: undefined,
email: undefined,
phonenumber: undefined,
sex: undefined,
avatar: undefined,
password: undefined,
status: undefined,
loginIp: undefined,
loginDate: undefined,
remark: undefined
}
const data = reactive<PageData<UserForm, UserQuery>>({
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
deptId: undefined,
userName: undefined,
nickName: undefined,
userType: undefined,
email: undefined,
phonenumber: undefined,
sex: undefined,
avatar: undefined,
password: undefined,
status: undefined,
loginIp: undefined,
loginDate: undefined,
params: {
}
},
rules: {
userId: [
{ required: true, message: "用户ID不能为空", trigger: "blur" }
],
deptId: [
{ required: true, message: "部门ID不能为空", trigger: "blur" }
],
userName: [
{ required: true, message: "用户账号不能为空", trigger: "blur" }
],
nickName: [
{ required: true, message: "用户昵称不能为空", trigger: "blur" }
],
userType: [
{ required: true, message: "用户类型不能为空", trigger: "change" }
],
email: [
{ required: true, message: "用户邮箱不能为空", trigger: "blur" }
],
phonenumber: [
{ required: true, message: "手机号码不能为空", trigger: "blur" }
],
sex: [
{ required: true, message: "用户性别不能为空", trigger: "change" }
],
avatar: [
{ required: true, message: "头像地址不能为空", trigger: "blur" }
],
password: [
{ required: true, message: "密码不能为空", trigger: "blur" }
],
status: [
{ required: true, message: "帐号状态不能为空", trigger: "change" }
],
loginIp: [
{ required: true, message: "最后登录IP不能为空", trigger: "blur" }
],
loginDate: [
{ required: true, message: "最后登录时间不能为空", trigger: "blur" }
],
remark: [
{ required: true, message: "备注不能为空", trigger: "blur" }
]
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询教职工管理列表 */
const getList = async () => {
loading.value = true;
const res = await listUser(queryParams.value);
teacherList.value = res.rows;
total.value = res.total;
loading.value = false;
}
/** 取消按钮 */
const cancel = () => {
reset();
dialog.visible = false;
}
/** 表单重置 */
const reset = () => {
form.value = { ...initFormData };
UserFormRef.value?.resetFields();
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();
handleQuery();
}
/** 多选框选中数据 */
const handleSelectionChange = (selection: UserVO[]) => {
ids.value = selection.map(item => item.userId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
const handleAdd = () => {
reset();
dialog.visible = true;
dialog.title = "新增教职工";
}
/** 修改按钮操作 */
const handleUpdate = async (row?: UserVO) => {
reset();
const _userId = row?.userId || ids.value[0]
const res = await getUser(_userId);
Object.assign(form.value, res.data);
dialog.visible = true;
dialog.title = "修改教职工";
}
/** 提交按钮 */
const submitForm = () => {
UserFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (form.value.userId) {
await updateUser(form.value).finally(() => buttonLoading.value = false);
} else {
await addUser(form.value).finally(() => buttonLoading.value = false);
}
proxy?.$modal.msgSuccess("修改成功");
dialog.visible = false;
await getList();
}
});
}
/** 删除按钮操作 */
const handleDelete = async (row?: UserVO) => {
const _userIds = row?.userId || ids.value;
await proxy?.$modal.confirm('是否确认删除教职工管理编号为"' + _userIds + '"的数据项?').finally(() => loading.value = false);
await delUser(_userIds);
proxy?.$modal.msgSuccess("删除成功");
await getList();
}
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download('basic/teacher/export', {
...queryParams.value
}, `teacher_${new Date().getTime()}.xlsx`)
}
onMounted(() => {
getList();
});
</script>

View File

@ -1,165 +1,353 @@
<template> <template>
<div class="app-container home"> <div class="app-container">
<el-row :gutter="20"> <div class="stats-panel">
<el-col :sm="24" :lg="12" style="padding-left: 20px"> <el-card>
<h2>RuoYi-Vue-Plus多租户管理系统</h2> <el-row justify="space-between">
<p> <el-col :span="12">
RuoYi-Vue-Plus 是基于 RuoYi-Vue 针对 分布式集群 场景升级(不兼容原框架) <el-icon :size="60" color="#5B95FA">
<br /> <Histogram />
* 前端开发框架 Vue3TSElement Plus<br /> </el-icon>
* 后端开发框架 Spring Boot<br /> </el-col>
* 容器框架 Undertow 基于 Netty 的高性能容器<br /> <el-col :span="12" class="right">
* 权限认证框架 Sa-Token 支持多终端认证系统<br /> <el-statistic :value="userNum" :value-style="{ color: '#000', fontSize: '30px' }">
* 关系数据库 MySQL 适配 8.X 最低 5.7<br /> <template #title>
* 缓存数据库 Redis 适配 6.X 最低 4.X<br /> <div class="stats-title">
* 数据库框架 Mybatis-Plus 快速 CRUD 增加开发效率<br /> 年级数
* 数据库框架 p6spy 更强劲的 SQL 分析<br /> </div>
* 多数据源框架 dynamic-datasource 支持主从与多种类数据库异构<br /> </template>
* 序列化框架 Jackson 统一使用 jackson 高效可靠<br /> </el-statistic>
* Redis客户端 Redisson 性能强劲API丰富<br /> </el-col>
* 分布式限流 Redisson 全局请求IP集群ID 多种限流<br /> </el-row>
* 分布式锁 Lock4j 注解锁工具锁 多种多样<br /> </el-card>
* 分布式幂等 Lock4j 基于分布式锁实现<br />
* 分布式链路追踪 SkyWalking 支持链路追踪网格分析度量聚合可视化<br />
* 分布式任务调度 SnailJob 高性能 高可靠 易扩展<br />
* 文件存储 Minio 本地存储<br />
* 文件存储 七牛阿里腾讯 云存储<br />
* 监控框架 SpringBoot-Admin 全方位服务监控<br />
* 校验框架 Validation 增强接口安全性 严谨性<br />
* Excel框架 Alibaba EasyExcel 性能优异 扩展性强<br />
* 文档框架 SpringDocjavadoc 无注解零入侵基于java注释<br />
* 工具类框架 HutoolLombok 减少代码冗余 增加安全性<br />
* 代码生成器 适配MPSpringDoc规范化代码 一键生成前后端代码<br />
* 部署方式 Docker 容器编排 一键部署业务集群<br />
* 国际化 SpringMessage Spring标准国际化方案<br />
</p>
<p><b>当前版本:</b> <span>v5.2.0-BETA</span></p>
<p>
<el-tag type="danger">&yen;免费开源</el-tag>
</p>
<p>
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://gitee.com/dromara/RuoYi-Vue-Plus')">访问码云</el-button>
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://github.com/dromara/RuoYi-Vue-Plus')">访问GitHub</el-button>
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://plus-doc.dromara.org/#/ruoyi-vue-plus/changlog')"
>更新日志</el-button
>
</p>
</el-col>
<el-col :sm="24" :lg="12" style="padding-left: 20px"> <el-card>
<h2>RuoYi-Cloud-Plus多租户微服务管理系统</h2> <el-row justify="space-between">
<p> <el-col :span="12">
RuoYi-Cloud-Plus 微服务通用权限管理系统 重写 RuoYi-Cloud 全方位升级(不兼容原框架) <el-icon :size="60" color="#FFB160">
<br /> <Operation />
* 前端开发框架 Vue3TSElement UI<br /> </el-icon>
* 后端开发框架 Spring Boot<br /> </el-col>
* 微服务开发框架 Spring CloudSpring Cloud Alibaba<br /> <el-col :span="12" class="right">
* 容器框架 Undertow 基于 XNIO 的高性能容器<br /> <el-statistic :value="evaluationNum" :value-style="{ color: '#000', fontSize: '30px' }">
* 权限认证框架 Sa-TokenJwt 支持多终端认证系统<br /> <template #title>
* 关系数据库 MySQL 适配 8.X 最低 5.7<br /> <div class="stats-title">
* 关系数据库 Oracle 适配 11g 12c<br /> 班级数
* 关系数据库 PostgreSQL 适配 13 14<br /> </div>
* 关系数据库 SQLServer 适配 2017 2019<br /> </template>
* 缓存数据库 Redis 适配 6.X 最低 5.X<br /> </el-statistic>
* 分布式注册中心 Alibaba Nacos 采用2.X 基于GRPC通信高性能<br /> </el-col>
* 分布式配置中心 Alibaba Nacos 采用2.X 基于GRPC通信高性能<br /> </el-row>
* 服务网关 Spring Cloud Gateway 响应式高性能网关<br /> </el-card>
* 负载均衡 Spring Cloud Loadbalancer 负载均衡处理<br />
* RPC远程调用 Apache Dubbo 原生态使用体验高性能<br /> <el-card>
* 分布式限流熔断 Alibaba Sentinel 无侵入高扩展<br /> <el-row justify="space-between">
* 分布式事务 Alibaba Seata 无侵入高扩展 支持 四种模式<br /> <el-col :span="12">
* 分布式消息队列 Spring Cloud Stream 门面框架兼容各种MQ集成<br /> <el-icon :size="60" color="#69D86A">
* 分布式消息队列 Apache Kafka 高性能高速度<br /> <Avatar />
* 分布式消息队列 Apache RocketMQ 高可用功能多样<br /> </el-icon>
* 分布式消息队列 RabbitMQ 支持各种扩展插件功能多样性<br /> </el-col>
* 分布式搜索引擎 ElasticSearch 业界知名<br /> <el-col :span="12" class="right">
* 分布式链路追踪 Apache SkyWalking 链路追踪网格分析度量聚合可视化<br /> <el-statistic :value="warnNum" :value-style="{ color: '#000', fontSize: '30px' }">
* 分布式日志中心 ELK 业界成熟解决方案<br /> <template #title>
* 分布式监控 PrometheusGrafana 全方位性能监控<br /> <div class="stats-title">
* 其余与 Vue 版本一致<br /> 教职工总数
</p> </div>
<p><b>当前版本:</b> <span>v2.2.0-BETA</span></p> </template>
<p> </el-statistic>
<el-tag type="danger">&yen;免费开源</el-tag> </el-col>
</p> </el-row>
<p> </el-card>
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://gitee.com/dromara/RuoYi-Cloud-Plus')">访问码云</el-button>
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://github.com/dromara/RuoYi-Cloud-Plus')">访问GitHub</el-button> <el-card>
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://plus-doc.dromara.org/#/ruoyi-cloud-plus/changlog')" <el-row justify="space-between">
>更新日志</el-button <el-col :span="12">
> <el-icon :size="60" color="#13DACE">
</p> <HelpFilled />
</el-icon>
</el-col>
<el-col :span="12" class="right">
<el-statistic :value="interveneNum" :value-style="{ color: '#000', fontSize: '30px' }">
<template #title>
<div class="stats-title">
学生总数
</div>
</template>
</el-statistic>
</el-col>
</el-row>
</el-card>
<el-card>
<el-row justify="space-between">
<el-col :span="12">
<el-icon :size="60" color="#A680FA">
<Grid />
</el-icon>
</el-col>
<el-col :span="12" class="right">
<el-statistic :value="interveneNum" :value-style="{ color: '#000', fontSize: '30px' }">
<template #title>
<div class="stats-title">
资源总数
</div>
</template>
</el-statistic>
</el-col>
</el-row>
</el-card>
</div>
<el-card>
<template #header>
<div class="card-header">
<span>快捷操作</span>
</div>
</template>
<div class="quick-action">
<el-card>
<div class="item">
<img src="@/assets/icons/student.png" alt="">
<p>添加学生</p>
</div>
</el-card>
<el-card>
<div class="item">
<img src="@/assets/icons/resource.png" alt="">
<p>资源目录</p>
</div>
</el-card>
<el-card>
<div class="item">
<img src="@/assets/icons/video.png" alt="">
<p>上传视频</p>
</div>
</el-card>
<el-card>
<div class="item">
<img src="@/assets/icons/image.png" alt="">
<p>上传图片</p>
</div>
</el-card>
<el-card>
<div class="item">
<img src="@/assets/icons/course.png" alt="">
<p>上传课件</p>
</div>
</el-card>
</div>
</el-card>
<el-row :gutter="10">
<el-col :span="14">
<el-card>
<template #header>
<div class="card-header">
<span>资源使用排行榜</span>
</div>
</template>
<ul>
<li>
<span>1</span><span>小学劳动课本一年级下册配材料包</span>
</li>
<li>
<span>2</span><span>小学数学课本一年级上册</span>
</li>
<li>
<span>3</span><span>资源名称资源名称资源名称资源名称</span>
</li>
<li>
<span>4</span><span>资源名称资源名称资源名称资源名称</span>
</li>
<li>
<span>5</span><span>资源名称资源名称资源名称资源名称</span>
</li>
<li>
<span>6</span><span>资源名称资源名称资源名称资源名称</span>
</li>
<li>
<span>7</span><span>资源名称资源名称资源名称资源名称</span>
</li>
<li>
<span>8</span><span>资源名称资源名称资源名称资源名称</span>
</li>
</ul>
</el-card>
</el-col>
<el-col :span="10">
<el-card>
<template #header>
<div class="card-header">
<span>资源统计</span>
</div>
</template>
<v-chart class="chart" :option="pieOption" autoresize />
</el-card>
</el-col> </el-col>
</el-row> </el-row>
<el-divider />
</div> </div>
</template> </template>
<script setup name="Index" lang="ts"> <script setup name="Index" lang="ts">
import * as echarts from 'echarts';
import { use } from 'echarts/core'
import { CanvasRenderer } from "echarts/renderers";
import { PieChart } from "echarts/charts";
import { TitleComponent, TooltipComponent, LegendComponent, ToolboxComponent, GridComponent, VisualMapComponent } from "echarts/components";
import VChart from 'vue-echarts'
use([
CanvasRenderer,
PieChart,
TitleComponent,
TooltipComponent,
LegendComponent,
ToolboxComponent,
GridComponent,
VisualMapComponent
]);
const goTarget = (url: string) => { const goTarget = (url: string) => {
window.open(url, '__blank'); window.open(url, '__blank');
}; };
const pieOption = ref({
title: {
text: '资源总数',
subtext: '',
x: 'center',
y: '40%',
textStyle: {
fontSize: 20,
fontWeight: 'normal',
lineHeight: 10,
},
subtextStyle: {
fontSize: 16,
lineHeight: 10,
},
},
tooltip: {
trigger: 'item',
formatter: "{b} : {c} ({d}%)"
},
legend: {
orient: 'vertical',
left: 'left'
},
visualMap: {
show: false,
min: 500,
max: 600,
inRange: {
//colorLightness: [0, 1]
}
},
series: [{
name: '资源总数',
type: 'pie',
radius: ['50%', '70%'],
center: ['50%', '50%'],
color: ['#ACEE62', '#8FAFFF', '#B2EFD5'],
data: [
{ name: '图片数', value: '214' },
{ name: '视频数', value: '519' },
{ name: '课件数', value: '198' }
],
roseType: 'radius',
label: {
formatter: ['{c|{c}}', '{b|{b}}'].join('\n'),
rich: {
c: {
fontSize: 20,
lineHeight: 5
},
b: {
fontSize: 14,
height: 44
},
},
},
labelLine: {
lineStyle: {
color: 'rgb(98,137,169)',
},
smooth: 0.2,
length: 10,
length2: 20,
}
}]
})
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.home { .app-container {
blockquote { padding: 10px;
padding: 10px 20px;
margin: 0 0 20px;
font-size: 17.5px;
border-left: 5px solid #eee;
}
hr {
margin-top: 20px;
margin-bottom: 20px;
border: 0;
border-top: 1px solid #eee;
}
.col-item {
margin-bottom: 20px;
}
ul { ul {
padding: 0;
margin: 0; margin: 0;
} padding: 0;
height: 370px;
font-family: 'open sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; li {
font-size: 13px; list-style-type: none;
color: #676a6c; background-color: #F5F7FB;
overflow-x: hidden; padding: 9px 0;
margin-bottom: 7px;
ul { span {
list-style-type: none; margin: 0 5px;
} }
h4 {
margin-top: 0px;
}
h2 {
margin-top: 10px;
font-size: 26px;
font-weight: 100;
}
p {
margin-top: 10px;
b {
font-weight: 700;
} }
} }
.update-log { .chart {
ol { width: 100%;
display: block; height: 370px;
list-style-type: decimal; }
margin-block-start: 1em;
margin-block-end: 1em; .stats-panel {
margin-inline-start: 0; display: grid;
margin-inline-end: 0; grid-template-columns: repeat(5, 1fr);
padding-inline-start: 40px; grid-template-rows: 1fr;
gap: 10px;
}
.el-card {
margin-bottom: 5px;
}
.stats-title {
font-size: 18px;
padding-bottom: 10px;
}
.right {
text-align: right;
}
.card-header {
font-size: 18px;
font-weight: bold;
}
.quick-action {
display: grid;
grid-template-columns: repeat(5, 1fr);
grid-template-rows: 1fr;
gap: 10px;
.item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
img {
width: 46px;
height: 46px
}
} }
} }
} }

View File

@ -1,10 +1,11 @@
<template> <template>
<div class="login"> <div class="login">
<el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form"> <el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
<h3 class="title">RuoYi-Vue-Plus多租户管理系统</h3> <h3 class="title">校本资源库管理系统</h3>
<el-form-item v-if="tenantEnabled" prop="tenantId"> <el-form-item v-if="tenantEnabled" prop="tenantId">
<el-select v-model="loginForm.tenantId" filterable placeholder="请选择/输入公司名称" style="width: 100%"> <el-select v-model="loginForm.tenantId" filterable placeholder="请选择/输入公司名称" style="width: 100%">
<el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"></el-option> <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName"
:value="item.tenantId"></el-option>
<template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template> <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
</el-select> </el-select>
</el-form-item> </el-form-item>
@ -14,12 +15,14 @@
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item prop="password"> <el-form-item prop="password">
<el-input v-model="loginForm.password" type="password" size="large" auto-complete="off" placeholder="密码" @keyup.enter="handleLogin"> <el-input v-model="loginForm.password" type="password" size="large" auto-complete="off" placeholder="密码"
@keyup.enter="handleLogin">
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template> <template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item v-if="captchaEnabled" prop="code"> <el-form-item v-if="captchaEnabled" prop="code">
<el-input v-model="loginForm.code" size="large" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter="handleLogin"> <el-input v-model="loginForm.code" size="large" auto-complete="off" placeholder="验证码" style="width: 63%"
@keyup.enter="handleLogin">
<template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template> <template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
</el-input> </el-input>
<div class="login-code"> <div class="login-code">
@ -27,23 +30,6 @@
</div> </div>
</el-form-item> </el-form-item>
<el-checkbox v-model="loginForm.rememberMe" style="margin: 0 0 25px 0">记住密码</el-checkbox> <el-checkbox v-model="loginForm.rememberMe" style="margin: 0 0 25px 0">记住密码</el-checkbox>
<el-form-item style="float: right">
<el-button circle title="微信登录" @click="doSocialLogin('wechat')">
<svg-icon icon-class="wechat" />
</el-button>
<el-button circle title="MaxKey登录" @click="doSocialLogin('maxkey')">
<svg-icon icon-class="maxkey" />
</el-button>
<el-button circle title="TopIam登录" @click="doSocialLogin('topiam')">
<svg-icon icon-class="topiam" />
</el-button>
<el-button circle title="Gitee登录" @click="doSocialLogin('gitee')">
<svg-icon icon-class="gitee" />
</el-button>
<el-button circle title="Github登录" @click="doSocialLogin('github')">
<svg-icon icon-class="github" />
</el-button>
</el-form-item>
<el-form-item style="width: 100%"> <el-form-item style="width: 100%">
<el-button :loading="loading" size="large" type="primary" style="width: 100%" @click.prevent="handleLogin"> <el-button :loading="loading" size="large" type="primary" style="width: 100%" @click.prevent="handleLogin">
<span v-if="!loading"> </span> <span v-if="!loading"> </span>
@ -54,10 +40,6 @@
</div> </div>
</el-form-item> </el-form-item>
</el-form> </el-form>
<!-- 底部 -->
<div class="el-login-footer">
<span>Copyright © 2018-2024 疯狂的狮子Li All Rights Reserved.</span>
</div>
</div> </div>
</template> </template>
@ -222,7 +204,7 @@ onMounted(() => {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
height: 100%; height: 100%;
background-image: url('../assets/images/login-background.jpg'); background-image: url('../assets/images/login_bg.jpg');
background-size: cover; background-size: cover;
} }

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="register"> <div class="register">
<el-form ref="registerRef" :model="registerForm" :rules="registerRules" class="register-form"> <el-form ref="registerRef" :model="registerForm" :rules="registerRules" class="register-form">
<h3 class="title">RuoYi-Vue-Plus多租户管理系统</h3> <h3 class="title">校本资源库管理系统多租户管理系统</h3>
<el-form-item v-if="tenantEnabled" prop="tenantId"> <el-form-item v-if="tenantEnabled" prop="tenantId">
<el-select v-model="registerForm.tenantId" filterable placeholder="请选择/输入公司名称" style="width: 100%"> <el-select v-model="registerForm.tenantId" filterable placeholder="请选择/输入公司名称" style="width: 100%">
<el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"> </el-option> <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"> </el-option>

View File

@ -1,18 +1,17 @@
<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 v-show="showSearch" class="mb-[10px]"> <div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover"> <el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true"> <el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="部门名称" prop="deptName"> <el-form-item label="部门名称" prop="deptName">
<el-input v-model="queryParams.deptName" placeholder="请输入部门名称" clearable @keyup.enter="handleQuery" /> <el-input v-model="queryParams.deptName" placeholder="请输入部门名称" clearable @keyup.enter="handleQuery" />
</el-form-item> </el-form-item>
<el-form-item label="类别编码" prop="deptCategory">
<el-input v-model="queryParams.deptCategory" 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 > <el-select v-model="queryParams.status" placeholder="部门状态" clearable>
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" /> <el-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> <el-form-item>
@ -28,7 +27,8 @@
<template #header> <template #header>
<el-row :gutter="10"> <el-row :gutter="10">
<el-col :span="1.5"> <el-col :span="1.5">
<el-button v-hasPermi="['system:dept:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增 </el-button> <el-button v-hasPermi="['system:dept:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增
</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button> <el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
@ -37,16 +37,9 @@
</el-row> </el-row>
</template> </template>
<el-table <el-table ref="deptTableRef" v-loading="loading" :data="deptList" row-key="deptId"
ref="deptTableRef" :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" :default-expand-all="isExpandAll">
v-loading="loading" <el-table-column prop="deptName" label="名称" width="260"></el-table-column>
:data="deptList"
row-key="deptId"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
:default-expand-all="isExpandAll"
>
<el-table-column prop="deptName" label="部门名称" width="260"></el-table-column>
<el-table-column prop="deptCategory" align="center" label="类别编码" width="200"></el-table-column>
<el-table-column prop="orderNum" align="center" label="排序" width="200"></el-table-column> <el-table-column prop="orderNum" align="center" label="排序" width="200"></el-table-column>
<el-table-column prop="status" align="center" label="状态" width="100"> <el-table-column prop="status" align="center" label="状态" width="100">
<template #default="scope"> <template #default="scope">
@ -61,13 +54,16 @@
<el-table-column fixed="right" align="center" label="操作"> <el-table-column fixed="right" align="center" label="操作">
<template #default="scope"> <template #default="scope">
<el-tooltip content="修改" placement="top"> <el-tooltip content="修改" placement="top">
<el-button v-hasPermi="['system:dept:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)" /> <el-button v-hasPermi="['system:dept:edit']" link type="primary" icon="Edit"
@click="handleUpdate(scope.row)" />
</el-tooltip> </el-tooltip>
<el-tooltip content="新增" placement="top"> <el-tooltip content="新增" placement="top">
<el-button v-hasPermi="['system:dept:add']" link type="primary" icon="Plus" @click="handleAdd(scope.row)" /> <el-button v-hasPermi="['system:dept:add']" link type="primary" icon="Plus"
@click="handleAdd(scope.row)" />
</el-tooltip> </el-tooltip>
<el-tooltip content="删除" placement="top"> <el-tooltip content="删除" placement="top">
<el-button v-hasPermi="['system:dept:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)" /> <el-button v-hasPermi="['system:dept:remove']" link type="primary" icon="Delete"
@click="handleDelete(scope.row)" />
</el-tooltip> </el-tooltip>
</template> </template>
</el-table-column> </el-table-column>
@ -78,53 +74,22 @@
<el-form ref="deptFormRef" :model="form" :rules="rules" label-width="80px"> <el-form ref="deptFormRef" :model="form" :rules="rules" label-width="80px">
<el-row> <el-row>
<el-col v-if="form.parentId !== 0" :span="24"> <el-col v-if="form.parentId !== 0" :span="24">
<el-form-item label="上级部门" prop="parentId"> <el-form-item label="所属上级" prop="parentId">
<el-tree-select <el-tree-select v-model="form.parentId" :data="deptOptions"
v-model="form.parentId" :props="{ value: 'deptId', label: 'deptName', children: 'children' }" value-key="deptId"
:data="deptOptions" placeholder="选择所属上级" check-strictly />
:props="{ value: 'deptId', label: 'deptName', children: 'children' }"
value-key="deptId"
placeholder="选择上级部门"
check-strictly
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="部门名称" prop="deptName"> <el-form-item label="名称" prop="deptName">
<el-input v-model="form.deptName" placeholder="请输入部门名称" /> <el-input v-model="form.deptName" placeholder="请输入部门名称" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12">
<el-form-item label="类别编码" prop="deptCategory">
<el-input v-model="form.deptCategory" placeholder="请输入类别编码" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="显示排序" prop="orderNum">
<el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="负责人" prop="leader">
<el-select v-model="form.leader" placeholder="请选择负责人">
<el-option v-for="item in deptUserList" :key="item.userId" :label="item.userName" :value="item.userId" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="联系电话" prop="phone">
<el-input v-model="form.phone" placeholder="请输入联系电话" maxlength="11" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
</el-form-item>
</el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="部门状态"> <el-form-item label="部门状态">
<el-radio-group v-model="form.status"> <el-radio-group v-model="form.status">
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio> <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label
}}</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>

View File

@ -7,9 +7,6 @@
<el-form-item label="角色名称" prop="roleName"> <el-form-item label="角色名称" prop="roleName">
<el-input v-model="queryParams.roleName" placeholder="请输入角色名称" clearable @keyup.enter="handleQuery" /> <el-input v-model="queryParams.roleName" placeholder="请输入角色名称" clearable @keyup.enter="handleQuery" />
</el-form-item> </el-form-item>
<el-form-item label="权限字符" prop="roleKey">
<el-input v-model="queryParams.roleKey" placeholder="请输入权限字符" clearable @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 > <el-select v-model="queryParams.status" placeholder="角色状态" clearable >
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" /> <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />

View File

@ -1,20 +1,15 @@
<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 v-show="showSearch" class="mb-[10px]"> <div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover"> <el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true"> <el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="租户号" prop="tenantId"> <el-form-item label="租户号" prop="tenantId">
<el-input v-model="queryParams.tenantId" placeholder="请输入租户号" clearable @keyup.enter="handleQuery" /> <el-input v-model="queryParams.tenantId" placeholder="请输入租户号" clearable @keyup.enter="handleQuery" />
</el-form-item> </el-form-item>
<el-form-item label="联系人" prop="contactUserName"> <el-form-item label="租户名称" prop="companyName">
<el-input v-model="queryParams.contactUserName" placeholder="请输入联系人" clearable @keyup.enter="handleQuery" /> <el-input v-model="queryParams.companyName" placeholder="请输入租户名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="联系电话" prop="contactPhone">
<el-input v-model="queryParams.contactPhone" placeholder="请输入联系电话" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="企业名称" prop="companyName">
<el-input v-model="queryParams.companyName" placeholder="请输入企业名称" clearable @keyup.enter="handleQuery" />
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
@ -29,20 +24,22 @@
<template #header> <template #header>
<el-row :gutter="10" class="mb8"> <el-row :gutter="10" class="mb8">
<el-col :span="1.5"> <el-col :span="1.5">
<el-button v-hasPermi="['system:tenant:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button> <el-button v-hasPermi="['system:tenant:add']" type="primary" plain icon="Plus"
@click="handleAdd">新增</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button v-hasPermi="['system:tenant:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" <el-button v-hasPermi="['system:tenant:edit']" type="success" plain icon="Edit" :disabled="single"
>修改</el-button @click="handleUpdate()">修改</el-button>
>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button v-hasPermi="['system:tenant:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"> <el-button v-hasPermi="['system:tenant:remove']" type="danger" plain icon="Delete" :disabled="multiple"
@click="handleDelete()">
删除 删除
</el-button> </el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button v-hasPermi="['system:tenant:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button> <el-button v-hasPermi="['system:tenant:export']" type="warning" plain icon="Download"
@click="handleExport">导出</el-button>
</el-col> </el-col>
<right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar> <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
</el-row> </el-row>
@ -51,11 +48,15 @@
<el-table v-loading="loading" :data="tenantList" @selection-change="handleSelectionChange"> <el-table v-loading="loading" :data="tenantList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" /> <el-table-column type="selection" width="55" align="center" />
<el-table-column v-if="false" label="id" align="center" prop="id" /> <el-table-column v-if="false" label="id" align="center" prop="id" />
<el-table-column label="租户编号" align="center" prop="tenantId" /> <el-table-column label="租户账号" align="center" prop="tenantId" />
<el-table-column label="租户名称" align="center" prop="companyName" />
<el-table-column label="联系人" align="center" prop="contactUserName" /> <el-table-column label="联系人" align="center" prop="contactUserName" />
<el-table-column label="联系电话" align="center" prop="contactPhone" /> <el-table-column label="联系电话" align="center" prop="contactPhone" />
<el-table-column label="企业名称" align="center" prop="companyName" /> <el-table-column label="开通时间" align="center" prop="expireTime" width="180">
<el-table-column label="社会信用代码" align="center" prop="licenseNumber" /> <template #default="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="过期时间" align="center" prop="expireTime" width="180"> <el-table-column label="过期时间" align="center" prop="expireTime" width="180">
<template #default="scope"> <template #default="scope">
<span>{{ parseTime(scope.row.expireTime, '{y}-{m}-{d}') }}</span> <span>{{ parseTime(scope.row.expireTime, '{y}-{m}-{d}') }}</span>
@ -63,37 +64,42 @@
</el-table-column> </el-table-column>
<el-table-column label="租户状态" align="center" prop="status"> <el-table-column label="租户状态" align="center" prop="status">
<template #default="scope"> <template #default="scope">
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch> <el-switch v-model="scope.row.status" active-value="0" inactive-value="1"
@change="handleStatusChange(scope.row)"></el-switch>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column width="150" label="操作" align="center" fixed="right" class-name="small-padding fixed-width"> <el-table-column width="150" label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
<template #default="scope"> <template #default="scope">
<el-tooltip content="修改" placement="top"> <el-tooltip content="修改" placement="top">
<el-button v-hasPermi="['system:tenant:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button> <el-button v-hasPermi="['system:tenant:edit']" link type="primary" icon="Edit"
@click="handleUpdate(scope.row)"></el-button>
</el-tooltip> </el-tooltip>
<el-tooltip content="同步套餐" placement="top"> <el-tooltip content="同步套餐" placement="top">
<el-button v-hasPermi="['system:tenant:edit']" link type="primary" icon="Refresh" @click="handleSyncTenantPackage(scope.row)"> <el-button v-hasPermi="['system:tenant:edit']" link type="primary" icon="Refresh"
@click="handleSyncTenantPackage(scope.row)">
</el-button> </el-button>
</el-tooltip> </el-tooltip>
<el-tooltip content="删除" placement="top"> <el-tooltip content="删除" placement="top">
<el-button v-hasPermi="['system:tenant:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button> <el-button v-hasPermi="['system:tenant:remove']" link type="primary" icon="Delete"
@click="handleDelete(scope.row)"></el-button>
</el-tooltip> </el-tooltip>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" /> <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize"
:total="total" @pagination="getList" />
</el-card> </el-card>
<!-- 添加或修改租户对话框 --> <!-- 添加或修改租户对话框 -->
<el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body> <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
<el-form ref="tenantFormRef" :model="form" :rules="rules" label-width="80px"> <el-form ref="tenantFormRef" :model="form" :rules="rules" label-width="120px">
<el-form-item label="企业名称" prop="companyName"> <el-form-item label="租户名称" prop="companyName">
<el-input v-model="form.companyName" placeholder="请输入企业名称" /> <el-input v-model="form.companyName" placeholder="请输入企业名称" />
</el-form-item> </el-form-item>
<el-form-item label="联系人" prop="contactUserName"> <el-form-item label="联系人姓名" prop="contactUserName">
<el-input v-model="form.contactUserName" placeholder="请输入联系人" /> <el-input v-model="form.contactUserName" placeholder="请输入联系人" />
</el-form-item> </el-form-item>
<el-form-item label="联系电话" prop="contactPhone"> <el-form-item label="联系人手机号码" prop="contactPhone">
<el-input v-model="form.contactPhone" placeholder="请输入联系电话" /> <el-input v-model="form.contactPhone" placeholder="请输入联系电话" />
</el-form-item> </el-form-item>
<el-form-item v-if="!form.id" label="用户名" prop="username"> <el-form-item v-if="!form.id" label="用户名" prop="username">
@ -103,12 +109,15 @@
<el-input v-model="form.password" type="password" placeholder="请输入系统用户密码" maxlength="20" /> <el-input v-model="form.password" type="password" placeholder="请输入系统用户密码" maxlength="20" />
</el-form-item> </el-form-item>
<el-form-item label="租户套餐" prop="packageId"> <el-form-item label="租户套餐" prop="packageId">
<el-select v-model="form.packageId" :disabled="!!form.tenantId" placeholder="请选择租户套餐" clearable style="width: 100%"> <el-select v-model="form.packageId" :disabled="!!form.tenantId" placeholder="请选择租户套餐" clearable
<el-option v-for="item in packageList" :key="item.packageId" :label="item.packageName" :value="item.packageId" /> style="width: 100%">
<el-option v-for="item in packageList" :key="item.packageId" :label="item.packageName"
:value="item.packageId" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="过期时间" prop="expireTime"> <el-form-item label="过期时间" prop="expireTime">
<el-date-picker v-model="form.expireTime" clearable type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择过期时间"> <el-date-picker v-model="form.expireTime" clearable type="datetime" value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择过期时间" style="width: 100%">
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
<el-form-item label="用户数量" prop="accountCount"> <el-form-item label="用户数量" prop="accountCount">
@ -117,18 +126,6 @@
<el-form-item label="绑定域名" prop="domain"> <el-form-item label="绑定域名" prop="domain">
<el-input v-model="form.domain" placeholder="请输入绑定域名" /> <el-input v-model="form.domain" placeholder="请输入绑定域名" />
</el-form-item> </el-form-item>
<el-form-item label="企业地址" prop="address">
<el-input v-model="form.address" placeholder="请输入企业地址" />
</el-form-item>
<el-form-item label="企业代码" prop="licenseNumber">
<el-input v-model="form.licenseNumber" placeholder="请输入统一社会信用代码" />
</el-form-item>
<el-form-item label="企业简介" prop="intro">
<el-input v-model="form.intro" type="textarea" placeholder="请输入企业简介" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">

View File

@ -27,25 +27,6 @@
<el-form-item label="用户名称" prop="userName"> <el-form-item label="用户名称" prop="userName">
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" /> <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" />
</el-form-item> </el-form-item>
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="用户状态" clearable>
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="创建时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
></el-date-picker>
</el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button> <el-button icon="Refresh" @click="resetQuery">重置</el-button>
@ -141,7 +122,7 @@
</el-row> </el-row>
<!-- 添加或修改用户配置对话框 --> <!-- 添加或修改用户配置对话框 -->
<el-dialog ref="formDialogRef" v-model="dialog.visible" :title="dialog.title" width="600px" append-to-body @close="closeDialog"> <el-dialog ref="formDialogRef" v-model="dialog.visible" :title="dialog.title" width="700px" append-to-body @close="closeDialog">
<el-form ref="userFormRef" :model="form" :rules="rules" label-width="80px"> <el-form ref="userFormRef" :model="form" :rules="rules" label-width="80px">
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
@ -150,13 +131,13 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="归属部门" prop="deptId"> <el-form-item label="年级/班级" prop="deptId">
<el-tree-select <el-tree-select
v-model="form.deptId" v-model="form.deptId"
:data="deptOptions" :data="deptOptions"
:props="{ value: 'id', label: 'label', children: 'children' }" :props="{ value: 'id', label: 'label', children: 'children' }"
value-key="id" value-key="id"
placeholder="请选择归属部门" placeholder="请选择年级/班级"
check-strictly check-strictly
@change="handleDeptChange" @change="handleDeptChange"
/> />
@ -204,19 +185,6 @@
</el-col> </el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="12">
<el-form-item label="岗位">
<el-select v-model="form.postIds" multiple placeholder="请选择">
<el-option
v-for="item in postOptions"
:key="item.postId"
:label="item.postName"
:value="item.postId"
:disabled="item.status == '1'"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="角色" prop="roleIds"> <el-form-item label="角色" prop="roleIds">
<el-select v-model="form.roleIds" filterable multiple placeholder="请选择"> <el-select v-model="form.roleIds" filterable multiple placeholder="请选择">

View File

@ -55,9 +55,6 @@
<el-tab-pane label="修改密码" name="resetPwd"> <el-tab-pane label="修改密码" name="resetPwd">
<resetPwd /> <resetPwd />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="第三方应用" name="thirdParty">
<thirdParty :auths="state.auths" />
</el-tab-pane>
<el-tab-pane label="在线设备" name="onlinDevice"> <el-tab-pane label="在线设备" name="onlinDevice">
<onlinDevice :devices="state.devices" /> <onlinDevice :devices="state.devices" />
</el-tab-pane> </el-tab-pane>
@ -116,7 +113,7 @@ const getOnlines = async () => {
onMounted(() => { onMounted(() => {
getUser(); getUser();
getAuths(); // getAuths();
getOnlines(); getOnlines();
}); });
</script> </script>