This commit is contained in:
ailanyin
2023-06-12 16:03:09 +08:00
parent 830e2e9054
commit 2f1a48b088
9 changed files with 803 additions and 715 deletions

View File

@ -3,87 +3,87 @@ import useUserStore from "@/store/modules/user";
// 登录方法 // 登录方法
export function login(username, password, code, uuid) { export function login(username, password, code, uuid) {
const data = { const data = {
username, username,
password, password,
code, code,
uuid, uuid,
}; };
return request({ return request({
url: "/login", url: "/login",
headers: { headers: {
isToken: false, isToken: false,
}, },
method: "post", method: "post",
data: data, data: data,
}); });
} }
// 注册方法 // 注册方法
export function register(data) { export function register(data) {
return request({ return request({
url: "/register", url: "/register",
headers: { headers: {
isToken: false, isToken: false,
}, },
method: "post", method: "post",
data: data, data: data,
}); });
} }
// 获取用户详细信息 // 获取用户详细信息
export function getInfo() { export function getInfo() {
// if (useUserStore().userInfoRes) { // if (useUserStore().userInfoRes) {
// return new Promise((resolve, reject) => { // return new Promise((resolve, reject) => {
// resolve(useUserStore().userInfoRes); // resolve(useUserStore().userInfoRes);
// }); // });
// } // }
return request({ return request({
url: "/getInfo", url: "/getInfo",
method: "get", method: "get",
}); });
} }
// 退出方法 // 退出方法
export function logout() { export function logout() {
return request({ return request({
url: "/logout", url: "/logout",
method: "post", method: "post",
}); });
} }
// 获取验证码 // 获取验证码
export function getCodeImg() { export function getCodeImg() {
return request({ return request({
url: "/captchaImage", url: "/captchaImage",
headers: { headers: {
isToken: false, isToken: false,
}, },
method: "get", method: "get",
timeout: 20000, timeout: 20000,
}); });
} }
// 获取路由 // 获取路由
export const getRouters = () => { export const getRouters = () => {
// if (usePermissionStore().routesRes) { // if (usePermissionStore().routesRes) {
// return new Promise((resolve, reject) => { // return new Promise((resolve, reject) => {
// resolve(usePermissionStore().routesRes); // resolve(usePermissionStore().routesRes);
// }); // });
// } // }
return request({ return request({
url: "/getRouters", url: "/getRouters",
method: "get", method: "get",
}); });
}; };
export const getTenantNormalList = (query) => { export const getTenantNormalList = (query) => {
return request({ return request({
url: "/tenant/normal-list", url: "/tenant/normal-list",
headers: { headers: {
isToken: false, isToken: false,
}, },
params: query, params: query,
method: "get", method: "get",
}); });
}; };

View File

@ -2,51 +2,51 @@ import request from "@/utils/request";
// 查询租户列表 // 查询租户列表
export function listTenant(query) { export function listTenant(query) {
return request({ return request({
url: "/tenant/list", url: "/tenant/list",
method: "get", method: "get",
params: query, params: query,
}); });
} }
// 查询租户详细 // 查询租户详细
export function getTenant(tenantId) { export function getTenant(tenantId) {
return request({ return request({
url: "/tenant/" + tenantId, url: "/tenant/" + tenantId,
method: "get", method: "get",
}); });
} }
// 新增租户 // 新增租户
export function addTenant(data) { export function addTenant(data) {
return request({ return request({
url: "/tenant", url: "/tenant",
method: "post", method: "post",
data: data, data: data,
}); });
} }
// 修改租户 // 修改租户
export function updateTenant(data) { export function updateTenant(data) {
return request({ return request({
url: "/tenant", url: "/tenant",
method: "put", method: "put",
data: data, data: data,
}); });
} }
// 删除租户 // 删除租户
export function delTenant(tenantId) { export function delTenant(tenantId) {
return request({ return request({
url: "/tenant/" + tenantId, url: "/tenant/" + tenantId,
method: "delete", method: "delete",
}); });
} }
// 查看设置 // 查看设置
export function getSetting(tenantId) { export function getSetting(tenantId) {
return request({ return request({
url: `/tenant/getSetting/${tenantId}`, url: `/tenant/getSetting/${tenantId}`,
method: "get", method: "get",
}); });
} }

View File

@ -1,9 +1,17 @@
<script setup> <script setup>
import {nextTick, onMounted, onUnmounted, ref, toRefs, watch, watchEffect,} from "vue"; import {
nextTick,
onMounted,
onUnmounted,
ref,
toRefs,
watch,
watchEffect,
} from "vue";
import InfiniteLoading from "v3-infinite-loading"; import InfiniteLoading from "v3-infinite-loading";
import "v3-infinite-loading/lib/style.css"; import "v3-infinite-loading/lib/style.css";
import {debounce} from "lodash-es"; //required if you're not going to override default slots import { debounce } from "lodash-es"; //required if you're not going to override default slots
import {ElInput, ElPopover, ElScrollbar} from "element-plus"; import { ElInput, ElPopover, ElScrollbar } from "element-plus";
const props = defineProps({ const props = defineProps({
modelValue: {}, modelValue: {},
@ -17,7 +25,7 @@ const props = defineProps({
width: { width: {
type: Number, type: Number,
}, },
prefixIcon: {type: String}, prefixIcon: { type: String },
query: { query: {
type: Object, type: Object,
required: true, required: true,
@ -35,14 +43,14 @@ const props = defineProps({
}, },
}); });
const {modelValue} = toRefs(props); const { modelValue } = toRefs(props);
const loadKey = ref(0); const loadKey = ref(0);
const emit = defineEmits(["update:modelValue", "change", "confirm"]); const emit = defineEmits(["update:modelValue", "change", "confirm"]);
const showPopOver = ref(false); const showPopOver = ref(false);
const inputRefWhenShowPop = ref(); const inputRefWhenShowPop = ref();
const inputRefWhenNotShowPop = ref() const inputRefWhenNotShowPop = ref();
const placeholderWhenShowPop = ref(""); const placeholderWhenShowPop = ref("");
const placeholderWhenNotShowPop = ref(""); const placeholderWhenNotShowPop = ref("");
const optionLabelWhenShowPop = ref(""); const optionLabelWhenShowPop = ref("");
@ -52,41 +60,41 @@ const options = ref([]);
const page = ref(0); const page = ref(0);
const initOptions = (keyword) => { const initOptions = (keyword) => {
props props
.remoteMethod({ .remoteMethod({
[props.query.page]: page.value, [props.query.page]: page.value,
[props.query.size]: 10, [props.query.size]: 10,
[props.query.searchKey]: keyword, [props.query.searchKey]: keyword,
}) })
.then((rows) => { .then((rows) => {
options.value = rows; options.value = rows;
}); });
}; };
const loadMore = async ($state) => { const loadMore = async ($state) => {
page.value++; page.value++;
props props
.remoteMethod({ .remoteMethod({
[props.query.page]: page.value, [props.query.page]: page.value,
[props.query.size]: 10, [props.query.size]: 10,
[props.query.searchKey]: showPopOver.value [props.query.searchKey]: showPopOver.value
? optionLabelWhenShowPop.value ?? null ? optionLabelWhenShowPop.value ?? null
: null, : null,
}) })
.then((rows) => { .then((rows) => {
options.value.push(...rows); options.value.push(...rows);
if (rows.length < 10) { if (rows.length < 10) {
$state.complete(); $state.complete();
} else { } else {
$state.loaded(); $state.loaded();
} }
}) })
.catch(() => { .catch(() => {
$state.error(); $state.error();
}); });
}; };
const handleInputClick = (event) => { const handleInputClick = (event) => {
event.stopPropagation() event.stopPropagation();
showPopOver.value = true; showPopOver.value = true;
placeholderWhenShowPop.value = optionLabelWhenNotShowPop.value; placeholderWhenShowPop.value = optionLabelWhenNotShowPop.value;
nextTick(() => { nextTick(() => {
@ -136,12 +144,12 @@ watchEffect(() => {
if (showPopOver.value) return; if (showPopOver.value) return;
if (modelValue.value) { if (modelValue.value) {
optionLabelWhenNotShowPop.value = optionLabelWhenNotShowPop.value =
options.value.find((el) => el[props.prop.value] === modelValue.value)?.[ options.value.find((el) => el[props.prop.value] === modelValue.value)?.[
props.prop.label props.prop.label
] ?? ] ??
(echoLabel.value.length ? echoLabel.value : null) ?? (echoLabel.value.length ? echoLabel.value : null) ??
props.defaultLabel ?? props.defaultLabel ??
"..."; "...";
} else { } else {
optionLabelWhenNotShowPop.value = ""; optionLabelWhenNotShowPop.value = "";
placeholderWhenNotShowPop.value = props.placeholder; placeholderWhenNotShowPop.value = props.placeholder;
@ -152,7 +160,6 @@ watch(modelValue, (value) => {
emit("change", value); emit("change", value);
}); });
/** /**
* 点击空白关闭弹出选项列表 * 点击空白关闭弹出选项列表
* @param event * @param event
@ -173,17 +180,25 @@ onMounted(() => {
page.value++; page.value++;
initOptions(); initOptions();
document.body.addEventListener("click", handleBodyClick); document.body.addEventListener("click", handleBodyClick);
watch(showPopOver, (show) => { watch(
if (show) { showPopOver,
inputRefWhenNotShowPop.value?.input?.parentNode?.removeEventListener('click', handleInputClick) (show) => {
} else { if (show) {
nextTick(() => { inputRefWhenNotShowPop.value?.input?.parentNode?.removeEventListener(
inputRefWhenNotShowPop.value?.input?.parentNode?.addEventListener('click', handleInputClick) "click",
}) handleInputClick
);
} } else {
}, {immediate: true}) nextTick(() => {
inputRefWhenNotShowPop.value?.input?.parentNode?.addEventListener(
"click",
handleInputClick
);
});
}
},
{ immediate: true }
);
}); });
onUnmounted(() => { onUnmounted(() => {
@ -193,48 +208,48 @@ onUnmounted(() => {
<template> <template>
<el-popover <el-popover
:popper-style="{ :popper-style="{
padding: 0, padding: 0,
}" }"
:visible="showPopOver" :visible="showPopOver"
:width="width ?? 240" :width="width ?? 240"
placement="bottom" placement="bottom"
> >
<template #reference> <template #reference>
<div :style="`width: ${width ?? 240}px`"> <div :style="`width: ${width ?? 240}px`">
<!--选项显示时--> <!--选项显示时-->
<el-input <el-input
v-if="showPopOver" v-if="showPopOver"
ref="inputRefWhenShowPop" ref="inputRefWhenShowPop"
v-model="optionLabelWhenShowPop" v-model="optionLabelWhenShowPop"
:placeholder="placeholderWhenShowPop" :placeholder="placeholderWhenShowPop"
:prefix-icon="prefixIcon" :prefix-icon="prefixIcon"
:size="size ?? 'default'" :size="size ?? 'default'"
class="select-inner" class="select-inner"
suffix-icon="ArrowUp" suffix-icon="ArrowUp"
@input="handleInputChange" @input="handleInputChange"
@click.stop @click.stop
> >
<template #prefix> <template #prefix>
<slot name="prefix"/> <slot name="prefix" />
</template> </template>
</el-input> </el-input>
<!--选项隐藏时--> <!--选项隐藏时-->
<el-input <el-input
v-else v-else
ref="inputRefWhenNotShowPop" ref="inputRefWhenNotShowPop"
v-model="optionLabelWhenNotShowPop" v-model="optionLabelWhenNotShowPop"
:placeholder="placeholderWhenNotShowPop" :placeholder="placeholderWhenNotShowPop"
:prefix-icon="prefixIcon" :prefix-icon="prefixIcon"
:size="size ?? 'default'" :size="size ?? 'default'"
class="select-inner" class="select-inner"
clearable clearable
suffix-icon="ArrowDown" suffix-icon="ArrowDown"
@clear="handleClearSeletion" @clear="handleClearSeletion"
> >
<!-- @click.stop="handleFocus"--> <!-- @click.stop="handleFocus"-->
<template #prefix> <template #prefix>
<slot name="prefix"/> <slot name="prefix" />
</template> </template>
</el-input> </el-input>
</div> </div>
@ -242,12 +257,12 @@ onUnmounted(() => {
<el-scrollbar class="options-wrap" height="260" @click.stop> <el-scrollbar class="options-wrap" height="260" @click.stop>
<ul class="options"> <ul class="options">
<li <li
v-for="option in options" v-for="option in options"
:key="option[prop.value]" :key="option[prop.value]"
:class="`option-item ${ :class="`option-item ${
option[prop.value] === modelValue ? 'selected' : null option[prop.value] === modelValue ? 'selected' : null
}`" }`"
@click.stop="selectOption(option)" @click.stop="selectOption(option)"
> >
{{ option[prop.label] }} {{ option[prop.label] }}
</li> </li>
@ -258,7 +273,7 @@ onUnmounted(() => {
</template> </template>
<template #complete> <template #complete>
<div <div
style="display: flex; justify-content: center; align-items: center" style="display: flex; justify-content: center; align-items: center"
> >
- -
</div> </div>

View File

@ -1,36 +1,75 @@
export const sys_normal_disable = [{ export const sys_normal_disable = [
label: "正常", value: "1", elTagType: "success", {
}, { label: "正常",
label: "禁用", value: "0", elTagType: "danger", value: "1",
},]; elTagType: "success",
},
{
label: "禁用",
value: "0",
elTagType: "danger",
},
];
export const sys_user_gender = [{ export const sys_user_gender = [
label: "男", value: "0", {
}, { label: "男",
label: "女", value: "1", value: "0",
}, { },
label: "未知", value: "2", {
},]; label: "女",
value: "1",
},
{
label: "未知",
value: "2",
},
];
export const menu_show_hide = [{ export const menu_show_hide = [
label: "隐藏", value: "0", elTagType: "warning", {
}, { label: "隐藏",
label: "显示", value: "1", elTagType: "success", value: "0",
},]; elTagType: "warning",
},
{
label: "显示",
value: "1",
elTagType: "success",
},
];
export const sys_yes_no = [{ export const sys_yes_no = [
label: "否", value: "N", {
}, { label: "否",
label: "是", value: "Y", elTagType: "danger", value: "N",
},]; },
{
label: "是",
value: "Y",
elTagType: "danger",
},
];
export const database_type_dict = [{ export const database_type_dict = [
label: "MySQL", value: "MySQL", elTagType: "", {
}, { label: "MySQL",
label: "Oracle", value: "Oracle", elTagType: "", value: "MySQL",
}, { elTagType: "",
label: "PostgreSQL", value: "PostgreSQL", elTagType: "", },
}, {
{ label: "Oracle",
label: "Microsoft SQL Server", value: "Microsoft SQL Server", elTagType: "", value: "Oracle",
}]; elTagType: "",
},
{
label: "PostgreSQL",
value: "PostgreSQL",
elTagType: "",
},
{
label: "Microsoft SQL Server",
value: "Microsoft SQL Server",
elTagType: "",
},
];

View File

@ -78,6 +78,7 @@ const useUserStore = defineStore("user", {
this.roles = []; this.roles = [];
this.permissions = []; this.permissions = [];
this.userInfoRes = null; this.userInfoRes = null;
this.tenant = null;
removeToken(); removeToken();
resolve(); resolve();
}) })

View File

@ -1,226 +1,231 @@
import axios from "axios"; import axios from "axios";
import {ElLoading, ElMessage, ElMessageBox, ElNotification,} from "element-plus"; import {
import {getToken} from "@/utils/auth"; ElLoading,
ElMessage,
ElMessageBox,
ElNotification,
} from "element-plus";
import { getToken } from "@/utils/auth";
import errorCode from "@/utils/errorCode"; import errorCode from "@/utils/errorCode";
import {blobValidate, tansParams} from "@/utils/ruoyi"; import { blobValidate, tansParams } from "@/utils/ruoyi";
import cache from "@/plugins/cache"; import cache from "@/plugins/cache";
import {saveAs} from "file-saver"; import { saveAs } from "file-saver";
import useUserStore from "@/store/modules/user"; import useUserStore from "@/store/modules/user";
let downloadLoadingInstance; let downloadLoadingInstance;
// 是否显示重新登录 // 是否显示重新登录
export let isRelogin = {show: false}; export let isRelogin = { show: false };
axios.defaults.headers["Content-Type"] = "application/json;charset=utf-8"; axios.defaults.headers["Content-Type"] = "application/json;charset=utf-8";
// 创建axios实例 // 创建axios实例
const service = axios.create({ const service = axios.create({
// axios中请求配置有baseURL选项表示请求URL公共部分 // axios中请求配置有baseURL选项表示请求URL公共部分
baseURL: import.meta.env.VITE_APP_BASE_API, baseURL: import.meta.env.VITE_APP_BASE_API,
// 超时 // 超时
timeout: 10000, timeout: 10000,
}); });
// request拦截器 // request拦截器
service.interceptors.request.use( service.interceptors.request.use(
(config) => { (config) => {
// 是否需要设置 token // 是否需要设置 token
const isToken = (config.headers || {}).isToken === false; const isToken = (config.headers || {}).isToken === false;
// 是否需要防止数据重复提交 // 是否需要防止数据重复提交
const isRepeatSubmit = (config.headers || {}).repeatSubmit === false; const isRepeatSubmit = (config.headers || {}).repeatSubmit === false;
if (getToken() && !isToken) { if (getToken() && !isToken) {
config.headers["Authorization"] = "Bearer " + getToken(); // 让每个请求携带自定义token 请根据实际情况自行修改 config.headers["Authorization"] = "Bearer " + getToken(); // 让每个请求携带自定义token 请根据实际情况自行修改
}
// if (useUserStore().tenant) {
if (config.url === "/captchaImage") {
config.headers["tenant"] = useUserStore().tempTenant;
} else {
config.headers["tenant"] = useUserStore().tenant;
}
// }
// get请求映射params参数
if (config.method === "get" && config.params) {
let url = config.url + "?" + tansParams(config.params);
url = url.slice(0, -1);
config.params = {};
config.url = url;
}
if (
!isRepeatSubmit &&
(config.method === "post" || config.method === "put")
) {
const requestObj = {
url: config.url,
data:
typeof config.data === "object"
? JSON.stringify(config.data)
: config.data,
time: new Date().getTime(),
};
const sessionObj = cache.session.getJSON("sessionObj");
if (
sessionObj === undefined ||
sessionObj === null ||
sessionObj === ""
) {
cache.session.setJSON("sessionObj", requestObj);
} else {
const s_url = sessionObj.url; // 请求地址
const s_data = sessionObj.data; // 请求数据
const s_time = sessionObj.time; // 请求时间
const interval = 1000; // 间隔时间(ms),小于此时间视为重复提交
if (
s_data === requestObj.data &&
requestObj.time - s_time < interval &&
s_url === requestObj.url
) {
const message = "数据正在处理,请勿重复提交";
console.warn(`[${s_url}]: ` + message);
return Promise.reject(new Error(message));
} else {
cache.session.setJSON("sessionObj", requestObj);
}
}
}
return config;
},
(error) => {
console.log(error);
Promise.reject(error);
} }
// if (useUserStore().tenant) {
if (config.url === "/captchaImage") {
config.headers["tenant"] = useUserStore().tempTenant;
} else {
config.headers["tenant"] = useUserStore().tenant;
}
// }
// get请求映射params参数
if (config.method === "get" && config.params) {
let url = config.url + "?" + tansParams(config.params);
url = url.slice(0, -1);
config.params = {};
config.url = url;
}
if (
!isRepeatSubmit &&
(config.method === "post" || config.method === "put")
) {
const requestObj = {
url: config.url,
data:
typeof config.data === "object"
? JSON.stringify(config.data)
: config.data,
time: new Date().getTime(),
};
const sessionObj = cache.session.getJSON("sessionObj");
if (
sessionObj === undefined ||
sessionObj === null ||
sessionObj === ""
) {
cache.session.setJSON("sessionObj", requestObj);
} else {
const s_url = sessionObj.url; // 请求地址
const s_data = sessionObj.data; // 请求数据
const s_time = sessionObj.time; // 请求时间
const interval = 1000; // 间隔时间(ms),小于此时间视为重复提交
if (
s_data === requestObj.data &&
requestObj.time - s_time < interval &&
s_url === requestObj.url
) {
const message = "数据正在处理,请勿重复提交";
console.warn(`[${s_url}]: ` + message);
return Promise.reject(new Error(message));
} else {
cache.session.setJSON("sessionObj", requestObj);
}
}
}
return config;
},
(error) => {
console.log(error);
Promise.reject(error);
}
); );
// 响应拦截器 // 响应拦截器
service.interceptors.response.use( service.interceptors.response.use(
(res) => { (res) => {
// 未设置状态码则默认成功状态 // 未设置状态码则默认成功状态
const code = res.data.code || 200; const code = res.data.code || 200;
// 获取错误信息 // 获取错误信息
const msg = errorCode[code] || res.data.msg || errorCode["default"]; const msg = errorCode[code] || res.data.msg || errorCode["default"];
// 二进制数据则直接返回 // 二进制数据则直接返回
if ( if (
res.request.responseType === "blob" || res.request.responseType === "blob" ||
res.request.responseType === "arraybuffer" res.request.responseType === "arraybuffer"
) { ) {
return res.data; return res.data;
}
if (code === 401 || code === 4011) {
if (!isRelogin.show) {
isRelogin.show = true;
ElMessageBox.confirm(
"登录状态已过期,您可以继续留在该页面,或者重新登录",
"系统提示",
{
showCancelButton: false,
showClose: false,
confirmButtonText: "重新登录",
closeOnClickModal: false,
closeOnPressEscape: false,
cancelButtonText: "取消",
type: "warning",
}
)
.then(() => {
isRelogin.show = false;
useUserStore()
.abnormalLogOut()
.then(() => {
location.href = "/index";
});
})
.catch(() => {
isRelogin.show = false;
});
}
return Promise.reject("无效的会话,或者会话已过期,请重新登录。");
} else if (code === 4012) {
if (!isRelogin.show) {
isRelogin.show = true;
ElMessageBox.confirm("您已被挤下线", "系统提示", {
showCancelButton: false,
showClose: false,
confirmButtonText: "重新登录",
closeOnClickModal: false,
closeOnPressEscape: false,
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
isRelogin.show = false;
useUserStore()
.abnormalLogOut()
.then(() => {
location.href = "/index";
});
})
.catch(() => {
isRelogin.show = false;
});
}
return Promise.reject("您已被挤下线");
} else if (code === 500) {
ElMessage({message: msg, type: "error"});
return Promise.reject(new Error(msg));
} else if (code === 601) {
ElMessage({message: msg, type: "warning"});
return Promise.reject(new Error(msg));
} else if (code !== 200) {
ElNotification.error({title: msg});
return Promise.reject("error");
} else {
return Promise.resolve(res.data);
}
},
(error) => {
console.log("err" + error);
let {message} = error;
if (message == "Network Error") {
message = "后端接口连接异常";
} else if (message.includes("timeout")) {
message = "系统接口请求超时";
} else if (message.includes("Request failed with status code")) {
message = "系统接口" + message.substr(message.length - 3) + "异常";
}
ElMessage({message: message, type: "error", duration: 5 * 1000});
return Promise.reject(error);
} }
if (code === 401 || code === 4011) {
if (!isRelogin.show) {
isRelogin.show = true;
ElMessageBox.confirm(
"登录状态已过期,您可以继续留在该页面,或者重新登录",
"系统提示",
{
showCancelButton: false,
showClose: false,
confirmButtonText: "重新登录",
closeOnClickModal: false,
closeOnPressEscape: false,
cancelButtonText: "取消",
type: "warning",
}
)
.then(() => {
isRelogin.show = false;
useUserStore()
.abnormalLogOut()
.then(() => {
location.href = "/index";
});
})
.catch(() => {
isRelogin.show = false;
});
}
return Promise.reject("无效的会话,或者会话已过期,请重新登录。");
} else if (code === 4012) {
if (!isRelogin.show) {
isRelogin.show = true;
ElMessageBox.confirm("您已被挤下线", "系统提示", {
showCancelButton: false,
showClose: false,
confirmButtonText: "重新登录",
closeOnClickModal: false,
closeOnPressEscape: false,
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
isRelogin.show = false;
useUserStore()
.abnormalLogOut()
.then(() => {
location.href = "/index";
});
})
.catch(() => {
isRelogin.show = false;
});
}
return Promise.reject("您已被挤下线");
} else if (code === 500) {
ElMessage({ message: msg, type: "error" });
return Promise.reject(new Error(msg));
} else if (code === 601) {
ElMessage({ message: msg, type: "warning" });
return Promise.reject(new Error(msg));
} else if (code !== 200) {
ElNotification.error({ title: msg });
return Promise.reject("error");
} else {
return Promise.resolve(res.data);
}
},
(error) => {
console.log("err" + error);
let { message } = error;
if (message == "Network Error") {
message = "后端接口连接异常";
} else if (message.includes("timeout")) {
message = "系统接口请求超时";
} else if (message.includes("Request failed with status code")) {
message = "系统接口" + message.substr(message.length - 3) + "异常";
}
ElMessage({ message: message, type: "error", duration: 5 * 1000 });
return Promise.reject(error);
}
); );
// 通用下载方法 // 通用下载方法
export function download(url, params, filename, config) { export function download(url, params, filename, config) {
downloadLoadingInstance = ElLoading.service({ downloadLoadingInstance = ElLoading.service({
text: "正在下载数据,请稍候", text: "正在下载数据,请稍候",
background: "rgba(0, 0, 0, 0.7)", background: "rgba(0, 0, 0, 0.7)",
});
return service
.post(url, params, {
transformRequest: [
(params) => {
return tansParams(params);
},
],
headers: { "Content-Type": "application/x-www-form-urlencoded" },
responseType: "blob",
...config,
})
.then(async (data) => {
const isBlob = blobValidate(data);
if (isBlob) {
const blob = new Blob([data]);
saveAs(blob, filename);
} else {
const resText = await data.text();
const rspObj = JSON.parse(resText);
const errMsg =
errorCode[rspObj.code] || rspObj.msg || errorCode["default"];
ElMessage.error(errMsg);
}
downloadLoadingInstance.close();
})
.catch((r) => {
console.error(r);
ElMessage.error("下载文件出现错误,请联系管理员!");
downloadLoadingInstance.close();
}); });
return service
.post(url, params, {
transformRequest: [
(params) => {
return tansParams(params);
},
],
headers: {"Content-Type": "application/x-www-form-urlencoded"},
responseType: "blob",
...config,
})
.then(async (data) => {
const isBlob = blobValidate(data);
if (isBlob) {
const blob = new Blob([data]);
saveAs(blob, filename);
} else {
const resText = await data.text();
const rspObj = JSON.parse(resText);
const errMsg =
errorCode[rspObj.code] || rspObj.msg || errorCode["default"];
ElMessage.error(errMsg);
}
downloadLoadingInstance.close();
})
.catch((r) => {
console.error(r);
ElMessage.error("下载文件出现错误,请联系管理员!");
downloadLoadingInstance.close();
});
} }
export default service; export default service;

View File

@ -1,31 +1,31 @@
<template> <template>
<div class="login"> <div class="login">
<el-form <el-form
ref="loginRef" ref="loginRef"
:model="loginForm" :model="loginForm"
:rules="loginRules" :rules="loginRules"
class="login-form" class="login-form"
> >
<h3 class="title">若依后台管理系统</h3> <h3 class="title">若依后台管理系统</h3>
<el-form-item prop="tenant"> <el-form-item prop="tenant">
<paged-select <paged-select
v-model="loginForm.tenant" v-model="loginForm.tenant"
:default-label="defaultTenantNamt" :default-label="defaultTenantNamt"
:prop="{ :prop="{
label: 'companyName', label: 'companyName',
value: 'tenantId', value: 'tenantId',
}" }"
:query="{ :query="{
page: 'pageNum', page: 'pageNum',
size: 'pageSize', size: 'pageSize',
searchKey: 'companyName', searchKey: 'companyName',
}" }"
:remote-method="loadTenantOptions" :remote-method="loadTenantOptions"
:width="350" :width="350"
prefix-icon="OfficeBuilding" prefix-icon="OfficeBuilding"
size="large" size="large"
@change="handleTenantChange" @change="handleTenantChange"
@confirm="handleTenantConfirm" @confirm="handleTenantConfirm"
/> />
<!-- <el-input--> <!-- <el-input-->
<!-- v-model="loginForm.tenant"--> <!-- v-model="loginForm.tenant"-->
@ -41,70 +41,70 @@
</el-form-item> </el-form-item>
<el-form-item prop="username"> <el-form-item prop="username">
<el-input <el-input
v-model="loginForm.username" v-model="loginForm.username"
auto-complete="off" auto-complete="off"
placeholder="账号" placeholder="账号"
size="large" size="large"
type="text" type="text"
> >
<template #prefix> <template #prefix>
<svg-icon class="el-input__icon input-icon" icon-class="user"/> <svg-icon class="el-input__icon input-icon" icon-class="user" />
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item prop="password"> <el-form-item prop="password">
<el-input <el-input
v-model="loginForm.password" v-model="loginForm.password"
auto-complete="off" auto-complete="off"
placeholder="密码" placeholder="密码"
size="large" size="large"
type="password" type="password"
@keyup.enter="handleLogin" @keyup.enter="handleLogin"
> >
<template #prefix> <template #prefix>
<svg-icon class="el-input__icon input-icon" icon-class="password"/> <svg-icon class="el-input__icon input-icon" icon-class="password" />
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item v-if="captchaEnabled && loginForm.tenant" prop="code"> <el-form-item v-if="captchaEnabled && loginForm.tenant" prop="code">
<el-input <el-input
v-model="loginForm.code" v-model="loginForm.code"
auto-complete="off" auto-complete="off"
placeholder="验证码" placeholder="验证码"
size="large" size="large"
style="width: 63%" style="width: 63%"
@keyup.enter="handleLogin" @keyup.enter="handleLogin"
> >
<template #prefix> <template #prefix>
<svg-icon <svg-icon
class="el-input__icon input-icon" class="el-input__icon input-icon"
icon-class="validCode" icon-class="validCode"
/> />
</template> </template>
</el-input> </el-input>
<div class="login-code"> <div class="login-code">
<img :src="codeUrl" class="login-code-img" @click="getCode"/> <img :src="codeUrl" class="login-code-img" @click="getCode" />
</div> </div>
</el-form-item> </el-form-item>
<el-checkbox <el-checkbox
v-model="loginForm.rememberMe" v-model="loginForm.rememberMe"
style="margin: 0px 0px 25px 0px" style="margin: 0px 0px 25px 0px"
>记住密码 >记住密码
</el-checkbox> </el-checkbox>
<el-form-item style="width: 100%"> <el-form-item style="width: 100%">
<el-button <el-button
:loading="loading" :loading="loading"
size="large" size="large"
style="width: 100%" style="width: 100%"
type="primary" type="primary"
@click.prevent="handleLogin" @click.prevent="handleLogin"
> >
<span v-if="!loading"> </span> <span v-if="!loading"> </span>
<span v-else> 中...</span> <span v-else> 中...</span>
</el-button> </el-button>
<div v-if="register" style="float: right"> <div v-if="register" style="float: right">
<router-link :to="'/register'" class="link-type" <router-link :to="'/register'" class="link-type"
>立即注册 >立即注册
</router-link> </router-link>
</div> </div>
</el-form-item> </el-form-item>
@ -117,16 +117,16 @@
</template> </template>
<script setup> <script setup>
import {getCodeImg, getTenantNormalList} from "@/api/login"; import { getCodeImg, getTenantNormalList } from "@/api/login";
import Cookies from "js-cookie"; import Cookies from "js-cookie";
import {decrypt, encrypt} from "@/utils/jsencrypt"; import { decrypt, encrypt } from "@/utils/jsencrypt";
import useUserStore from "@/store/modules/user"; import useUserStore from "@/store/modules/user";
import PagedSelect from "@/components/InfiniteSelect"; import PagedSelect from "@/components/InfiniteSelect";
import {getCurrentInstance, ref, watchEffect} from "vue"; import { getCurrentInstance, ref, watchEffect } from "vue";
const userStore = useUserStore(); const userStore = useUserStore();
const router = useRouter(); const router = useRouter();
const {proxy} = getCurrentInstance(); const { proxy } = getCurrentInstance();
const loginForm = ref({ const loginForm = ref({
tenant: "", tenant: "",
@ -138,10 +138,10 @@ const loginForm = ref({
}); });
const loginRules = { const loginRules = {
tenant: [{required: true, trigger: "change", message: "请选择租户"}], tenant: [{ required: true, trigger: "change", message: "请选择租户" }],
username: [{required: true, trigger: "blur", message: "请输入您的账号"}], username: [{ required: true, trigger: "blur", message: "请输入您的账号" }],
password: [{required: true, trigger: "blur", message: "请输入您的密码"}], password: [{ required: true, trigger: "blur", message: "请输入您的密码" }],
code: [{required: true, trigger: "change", message: "请输入验证码"}], code: [{ required: true, trigger: "change", message: "请输入验证码" }],
}; };
const defaultTenantNamt = ref(""); const defaultTenantNamt = ref("");
const codeUrl = ref(""); const codeUrl = ref("");
@ -158,12 +158,12 @@ function handleLogin() {
loading.value = true; loading.value = true;
// 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码 // 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码
if (loginForm.value.rememberMe) { if (loginForm.value.rememberMe) {
Cookies.set("tenant", loginForm.value.tenant, {expires: 30}); Cookies.set("tenant", loginForm.value.tenant, { expires: 30 });
Cookies.set("username", loginForm.value.username, {expires: 30}); Cookies.set("username", loginForm.value.username, { expires: 30 });
Cookies.set("password", encrypt(loginForm.value.password), { Cookies.set("password", encrypt(loginForm.value.password), {
expires: 30, expires: 30,
}); });
Cookies.set("rememberMe", loginForm.value.rememberMe, {expires: 30}); Cookies.set("rememberMe", loginForm.value.rememberMe, { expires: 30 });
} else { } else {
// 否则移除 // 否则移除
Cookies.remove("tenant"); Cookies.remove("tenant");
@ -173,17 +173,17 @@ function handleLogin() {
} }
// 调用action的登录方法 // 调用action的登录方法
userStore userStore
.login(loginForm.value) .login(loginForm.value)
.then(() => { .then(() => {
router.push({path: redirect.value || "/"}); router.push({ path: redirect.value || "/" });
}) })
.catch(() => { .catch(() => {
loading.value = false; loading.value = false;
// 重新获取验证码 // 重新获取验证码
if (captchaEnabled.value) { if (captchaEnabled.value) {
getCode(); getCode();
} }
}); });
} }
}); });
} }
@ -191,7 +191,7 @@ function handleLogin() {
function getCode() { function getCode() {
getCodeImg().then((res) => { getCodeImg().then((res) => {
captchaEnabled.value = captchaEnabled.value =
res.captchaEnabled === undefined ? true : res.captchaEnabled; res.captchaEnabled === undefined ? true : res.captchaEnabled;
register.value = res.register === undefined ? true : res.register; register.value = res.register === undefined ? true : res.register;
if (captchaEnabled.value) { if (captchaEnabled.value) {
codeUrl.value = "data:image/gif;base64," + res.img; codeUrl.value = "data:image/gif;base64," + res.img;
@ -207,14 +207,14 @@ function getCookie() {
loginForm.value = { loginForm.value = {
username: username === undefined ? loginForm.value.username : username, username: username === undefined ? loginForm.value.username : username,
password: password:
password === undefined ? loginForm.value.password : decrypt(password), password === undefined ? loginForm.value.password : decrypt(password),
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe), rememberMe: rememberMe === undefined ? false : Boolean(rememberMe),
tenant: useUserStore().tempTenant ?? "", tenant: useUserStore().tempTenant ?? "",
}; };
} }
const loadTenantOptions = (query) => const loadTenantOptions = (query) =>
getTenantNormalList(query).then((resp) => resp.rows); getTenantNormalList(query).then((resp) => resp.rows);
const handleTenantChange = (value) => { const handleTenantChange = (value) => {
console.log(value); console.log(value);
@ -231,12 +231,12 @@ const handleTenantConfirm = (option) => {
}; };
watchEffect(() => { watchEffect(() => {
console.log(loginForm.value.tenant) console.log(loginForm.value.tenant);
if (loginForm.value.tenant) { if (loginForm.value.tenant) {
console.log('getcode') console.log("getcode");
getCode(); getCode();
} }
}) });
getCookie(); getCookie();
defaultTenantNamt.value = useUserStore().tempTenantName; defaultTenantNamt.value = useUserStore().tempTenantName;
</script> </script>

View File

@ -3,110 +3,106 @@
<el-form ref="queryRef" :inline="true" :model="queryParams"> <el-form ref="queryRef" :inline="true" :model="queryParams">
<el-form-item label="用户名称" prop="username"> <el-form-item label="用户名称" prop="username">
<el-input <el-input
v-model="queryParams.username" v-model="queryParams.username"
clearable clearable
placeholder="请输入用户名称" placeholder="请输入用户名称"
style="width: 200px" style="width: 200px"
@keyup.enter="handleQuery" @keyup.enter="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button icon="Search" type="primary" @click="handleQuery" <el-button icon="Search" type="primary" @click="handleQuery"
>搜索 >搜索
</el-button </el-button>
>
<el-button icon="Refresh" @click="resetQuery">重置</el-button> <el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<el-table <el-table v-loading="loading" :data="onlineList" style="width: 100%">
v-loading="loading"
:data="onlineList"
style="width: 100%"
>
<el-table-column align="center" label="序号" type="index" width="100"> <el-table-column align="center" label="序号" type="index" width="100">
<template #default="scope"> <template #default="scope">
<span>{{ (queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1 }}</span> <span>{{
(queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1
}}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
:show-overflow-tooltip="true" :show-overflow-tooltip="true"
align="center" align="center"
label="会话编号" label="会话编号"
prop="deviceSn" prop="deviceSn"
/> />
<el-table-column <el-table-column
:show-overflow-tooltip="true" :show-overflow-tooltip="true"
align="center" align="center"
label="登录名称" label="登录名称"
prop="username" prop="username"
/> />
<el-table-column <el-table-column
:show-overflow-tooltip="true" :show-overflow-tooltip="true"
align="center" align="center"
label="主机" label="主机"
prop="ip" prop="ip"
/> />
<el-table-column <el-table-column
:show-overflow-tooltip="true" :show-overflow-tooltip="true"
align="center" align="center"
label="登录地点" label="登录地点"
prop="address" prop="address"
/> />
<el-table-column <el-table-column
:show-overflow-tooltip="true" :show-overflow-tooltip="true"
align="center" align="center"
label="操作系统" label="操作系统"
prop="os" prop="os"
/> />
<el-table-column <el-table-column
:show-overflow-tooltip="true" :show-overflow-tooltip="true"
align="center" align="center"
label="浏览器" label="浏览器"
prop="browser" prop="browser"
/> />
<el-table-column <el-table-column
align="center" align="center"
label="登录时间" label="登录时间"
prop="loginTime" prop="loginTime"
width="180" width="180"
> >
<template #default="scope"> <template #default="scope">
<span>{{ parseTime(scope.row.loginTime) }}</span> <span>{{ parseTime(scope.row.loginTime) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
align="center" align="center"
class-name="small-padding fixed-width" class-name="small-padding fixed-width"
label="操作" label="操作"
> >
<template #default="scope"> <template #default="scope">
<el-button <el-button
v-hasPermi="['monitor:online:forceLogout']" v-hasPermi="['monitor:online:forceLogout']"
icon="Delete" icon="Delete"
link link
type="primary" type="primary"
@click="handleForceLogout(scope.row)" @click="handleForceLogout(scope.row)"
>强退 >强退
</el-button </el-button>
>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<pagination <pagination
v-show="total > 0" v-show="total > 0"
v-model:limit="queryParams.pageSize" v-model:limit="queryParams.pageSize"
v-model:page="queryParams.pageNum" v-model:page="queryParams.pageNum"
:total="total" :total="total"
@pagination="getList" @pagination="getList"
/> />
</div> </div>
</template> </template>
<script name="Online" setup> <script name="Online" setup>
import {forceLogout, list as initData} from "@/api/monitor/online"; import { forceLogout, list as initData } from "@/api/monitor/online";
const {proxy} = getCurrentInstance(); const { proxy } = getCurrentInstance();
const onlineList = ref([]); const onlineList = ref([]);
const loading = ref(true); const loading = ref(true);
@ -145,16 +141,15 @@ function resetQuery() {
/** 强退按钮操作 */ /** 强退按钮操作 */
function handleForceLogout(row) { function handleForceLogout(row) {
proxy.$modal proxy.$modal
.confirm('是否确认强退名称为"' + row.username + '"的用户?') .confirm('是否确认强退名称为"' + row.username + '"的用户?')
.then(function () { .then(function () {
return forceLogout(row.username, row.deviceSn); return forceLogout(row.username, row.deviceSn);
}) })
.then(() => { .then(() => {
getList(); getList();
proxy.$modal.msgSuccess("删除成功"); proxy.$modal.msgSuccess("删除成功");
}) })
.catch(() => { .catch(() => {});
});
} }
getList(); getList();

View File

@ -1,33 +1,32 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form <el-form
v-show="showSearch" v-show="showSearch"
ref="queryRef" ref="queryRef"
:inline="true" :inline="true"
:model="queryParams" :model="queryParams"
label-width="68px" label-width="68px"
> >
<el-form-item label="公司名称" prop="companyName"> <el-form-item label="公司名称" prop="companyName">
<el-input <el-input
v-model="queryParams.companyName" v-model="queryParams.companyName"
clearable clearable
placeholder="请输入公司名称" placeholder="请输入公司名称"
@keyup.enter="handleQuery" @keyup.enter="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="联系人" prop="contactName"> <el-form-item label="联系人" prop="contactName">
<el-input <el-input
v-model="queryParams.contactName" v-model="queryParams.contactName"
clearable clearable
placeholder="请输入联系人名称" placeholder="请输入联系人名称"
@keyup.enter="handleQuery" @keyup.enter="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button icon="Search" type="primary" @click="handleQuery" <el-button icon="Search" type="primary" @click="handleQuery"
>搜索 >搜索
</el-button </el-button>
>
<el-button icon="Refresh" @click="resetQuery">重置</el-button> <el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -35,172 +34,165 @@
<el-row :gutter="10" class="mb8"> <el-row :gutter="10" class="mb8">
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
v-hasPermi="['tenant:add']" v-hasPermi="['tenant:add']"
icon="Plus" icon="Plus"
plain plain
type="primary" type="primary"
@click="handleAdd" @click="handleAdd"
>新增 >新增
</el-button </el-button>
>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
v-hasPermi="['tenant:edit']" v-hasPermi="['tenant:edit']"
:disabled="single" :disabled="single"
icon="Edit" icon="Edit"
plain plain
type="success" type="success"
@click="handleUpdate" @click="handleUpdate"
>修改 >修改
</el-button </el-button>
>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
v-hasPermi="['tenant:remove']" v-hasPermi="['tenant:remove']"
:disabled="multiple" :disabled="multiple"
icon="Delete" icon="Delete"
plain plain
type="danger" type="danger"
@click="handleDelete" @click="handleDelete"
>删除 >删除
</el-button </el-button>
>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
v-hasPermi="['tenant:export']" v-hasPermi="['tenant:export']"
icon="Download" icon="Download"
plain plain
type="warning" type="warning"
@click="handleExport" @click="handleExport"
>导出 >导出
</el-button </el-button>
>
</el-col> </el-col>
<right-toolbar <right-toolbar
v-model:showSearch="showSearch" v-model:showSearch="showSearch"
@queryTable="getList" @queryTable="getList"
></right-toolbar> ></right-toolbar>
</el-row> </el-row>
<el-table <el-table
v-loading="loading" v-loading="loading"
:data="tenantList" :data="tenantList"
@selection-change="handleSelectionChange" @selection-change="handleSelectionChange"
> >
<el-table-column align="center" type="selection" width="55"/> <el-table-column align="center" type="selection" width="55" />
<el-table-column align="center" label="编码" prop="tenantId"/> <el-table-column align="center" label="编码" prop="tenantId" />
<el-table-column align="center" label="公司名称" prop="companyName"/> <el-table-column align="center" label="公司名称" prop="companyName" />
<el-table-column align="center" label="联系人名称" prop="contactName"/> <el-table-column align="center" label="联系人名称" prop="contactName" />
<el-table-column align="center" label="联系人电话" prop="contactPhone"/> <el-table-column align="center" label="联系人电话" prop="contactPhone" />
<el-table-column align="center" label="公司地址" prop="address"/> <el-table-column align="center" label="公司地址" prop="address" />
<el-table-column <el-table-column
align="center" align="center"
label="过期时间" label="过期时间"
prop="expireTime" prop="expireTime"
width="180" 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>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column align="center" label="用户数量" prop="accountCount"/> <el-table-column align="center" label="用户数量" prop="accountCount" />
<el-table-column align="center" label="状态" prop="status"/> <el-table-column align="center" label="状态" prop="status" />
<el-table-column <el-table-column
align="center" align="center"
class-name="small-padding fixed-width" class-name="small-padding fixed-width"
label="操作" label="操作"
> >
<template #default="scope"> <template #default="scope">
<el-button <el-button
icon="Setting" icon="Setting"
link link
type="primary" type="primary"
@click="handleSetting(scope.row)" @click="handleSetting(scope.row)"
>设置 >设置
</el-button </el-button>
>
<el-button <el-button
v-hasPermi="['tenant:edit']" v-hasPermi="['tenant:edit']"
icon="Edit" icon="Edit"
link link
type="primary" type="primary"
@click="handleUpdate(scope.row)" @click="handleUpdate(scope.row)"
>修改 >修改
</el-button </el-button>
>
<el-button <el-button
v-hasPermi="['tenant:remove']" v-hasPermi="['tenant:remove']"
icon="Delete" icon="Delete"
link link
type="primary" type="primary"
@click="handleDelete(scope.row)" @click="handleDelete(scope.row)"
>删除 >删除
</el-button </el-button>
>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<pagination <pagination
v-show="total > 0" v-show="total > 0"
v-model:limit="queryParams.pageSize" v-model:limit="queryParams.pageSize"
v-model:page="queryParams.pageNum" v-model:page="queryParams.pageNum"
:total="total" :total="total"
@pagination="getList" @pagination="getList"
/> />
<!-- 添加或修改租户对话框 --> <!-- 添加或修改租户对话框 -->
<el-dialog v-model="open" :title="title" append-to-body width="500px"> <el-dialog v-model="open" :title="title" append-to-body width="500px">
<el-form ref="tenantRef" :model="form" :rules="rules" label-width="130px"> <el-form ref="tenantRef" :model="form" :rules="rules" label-width="130px">
<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="contactName"> <el-form-item label="联系人名称" prop="contactName">
<el-input v-model="form.contactName" placeholder="请输入联系人名称"/> <el-input v-model="form.contactName" placeholder="请输入联系人名称" />
</el-form-item> </el-form-item>
<el-form-item label="联系人电话" prop="contactPhone"> <el-form-item label="联系人电话" prop="contactPhone">
<el-input <el-input
v-model="form.contactPhone" v-model="form.contactPhone"
placeholder="请输入联系人电话" placeholder="请输入联系人电话"
/> />
</el-form-item> </el-form-item>
<el-form-item label="公司地址" prop="address"> <el-form-item label="公司地址" prop="address">
<el-input v-model="form.address" placeholder="请输入公司地址"/> <el-input v-model="form.address" placeholder="请输入公司地址" />
</el-form-item> </el-form-item>
<el-form-item label="公司简介" prop="profile"> <el-form-item label="公司简介" prop="profile">
<el-input <el-input
v-model="form.profile" v-model="form.profile"
placeholder="请输入内容" placeholder="请输入内容"
type="textarea" type="textarea"
/> />
</el-form-item> </el-form-item>
<el-form-item label="统一社会信用代码" prop="licenseNumber"> <el-form-item label="统一社会信用代码" prop="licenseNumber">
<el-input <el-input
v-model="form.licenseNumber" v-model="form.licenseNumber"
placeholder="请输入统一社会信用代码" placeholder="请输入统一社会信用代码"
/> />
</el-form-item> </el-form-item>
<el-form-item label="过期时间" prop="expireTime"> <el-form-item label="过期时间" prop="expireTime">
<el-date-picker <el-date-picker
v-model="form.expireTime" v-model="form.expireTime"
clearable clearable
placeholder="请选择过期时间" placeholder="请选择过期时间"
type="datetime" type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss"
> >
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
<el-form-item label="用户数量" prop="accountCount"> <el-form-item label="用户数量" prop="accountCount">
<el-input v-model="form.accountCount" placeholder="请输入用户数量"/> <el-input v-model="form.accountCount" placeholder="请输入用户数量" />
</el-form-item> </el-form-item>
<el-form-item label="备注" prop="remark"> <el-form-item label="备注" prop="remark">
<el-input <el-input
v-model="form.remark" v-model="form.remark"
placeholder="请输入内容" placeholder="请输入内容"
type="textarea" type="textarea"
/> />
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -213,8 +205,18 @@
</el-dialog> </el-dialog>
<!-- 添加或修改租户对话框 --> <!-- 添加或修改租户对话框 -->
<el-dialog v-model="showTenantSetting" append-to-body title="租户设置" width="500px"> <el-dialog
<el-form ref="tenantSettingRef" :model="tenantSettingForm" :rules="tenantSettingRules" label-width="130px"> v-model="showTenantSetting"
append-to-body
title="租户设置"
width="500px"
>
<el-form
ref="tenantSettingRef"
:model="tenantSettingForm"
:rules="tenantSettingRules"
label-width="130px"
>
<!--TODO:--> <!--TODO:-->
<el-form-item label="模式"> <el-form-item label="模式">
<el-radio-group v-model="tenantSettingForm.mode"> <el-radio-group v-model="tenantSettingForm.mode">
@ -223,20 +225,42 @@
<el-radio label="3">数据源</el-radio> <el-radio label="3">数据源</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<template v-if="tenantSettingForm.mode==='3'"> <template v-if="tenantSettingForm.mode === '3'">
<div v-for="item in tenantSettingForm.datasourceList" :key="`${item.ip}-${item.port}-${item.name}`" <div
class="data-source-item"> v-for="item in tenantSettingForm.datasourceList"
:key="`${item.ip}-${item.port}-${item.name}`"
class="data-source-item"
>
<div class="left"> <div class="left">
<div class="database-type">{{ "MySQL" }}</div> <div class="database-type">{{ "MySQL" }}</div>
<div class="database-url">{{ "127.0.0.1" }} : {{ 3306 }}</div> <div class="database-url">{{ "127.0.0.1" }} : {{ 3306 }}</div>
<div class="database-name">{{ "ry-vue" }}</div> <div class="database-name">{{ "ry-vue" }}</div>
</div> </div>
<div class="right"> <div class="right">
<el-button circle icon="edit" plain size="small" type="primary"></el-button> <el-button
<el-button circle icon="delete" plain size="small" type="danger"></el-button> circle
icon="edit"
plain
size="small"
type="primary"
></el-button>
<el-button
circle
icon="delete"
plain
size="small"
type="danger"
></el-button>
</div> </div>
</div> </div>
<el-button icon="plus" plain size="small" style="margin-top: 18px" type="primary">新增数据源</el-button> <el-button
icon="plus"
plain
size="small"
style="margin-top: 18px"
type="primary"
>新增数据源</el-button
>
<!-- <el-form-item label="数据库类型" prop="type">--> <!-- <el-form-item label="数据库类型" prop="type">-->
<!-- <el-select v-model="tenantSettingForm.host">--> <!-- <el-select v-model="tenantSettingForm.host">-->
<!-- <el-option v-for="option in database_type_dict" :key="option.value" :label="option.label"--> <!-- <el-option v-for="option in database_type_dict" :key="option.value" :label="option.label"-->
@ -262,7 +286,9 @@
</el-form> </el-form>
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
<el-button type="primary" @click="submitTenantSetting">确 定</el-button> <el-button type="primary" @click="submitTenantSetting"
>确 定</el-button
>
<el-button @click="cancelSettingTenant"> </el-button> <el-button @click="cancelSettingTenant"> </el-button>
</div> </div>
</template> </template>
@ -271,9 +297,16 @@
</template> </template>
<script name="Tenant" setup> <script name="Tenant" setup>
import {addTenant, delTenant, getSetting, getTenant, listTenant, updateTenant,} from "@/api/tenant/tenant"; import {
addTenant,
delTenant,
getSetting,
getTenant,
listTenant,
updateTenant,
} from "@/api/tenant/tenant";
const {proxy} = getCurrentInstance(); const { proxy } = getCurrentInstance();
const tenantList = ref([]); const tenantList = ref([]);
const open = ref(false); const open = ref(false);
@ -284,9 +317,9 @@ const single = ref(true);
const multiple = ref(true); const multiple = ref(true);
const total = ref(0); const total = ref(0);
const title = ref(""); const title = ref("");
const showTenantSetting = ref(false) /*是否显示租户设置对话框*/ const showTenantSetting = ref(false); /*是否显示租户设置对话框*/
const tenantSettingRef = ref() const tenantSettingRef = ref();
const editDatasourceIndex = ref(-1) const editDatasourceIndex = ref(-1);
const data = reactive({ const data = reactive({
form: {}, form: {},
queryParams: { queryParams: {
@ -307,7 +340,7 @@ const data = reactive({
}, },
rules: { rules: {
companyName: [ companyName: [
{required: true, message: "公司名称不能为空", trigger: "blur"}, { required: true, message: "公司名称不能为空", trigger: "blur" },
], ],
}, },
tenantSettingForm: { tenantSettingForm: {
@ -323,14 +356,14 @@ const data = reactive({
// } // }
// ], // ],
// mode: '3' // mode: '3'
} },
,
tenantSettingRules: { tenantSettingRules: {
/*TODO:*/ /*TODO:*/
} },
}); });
const {queryParams, form, rules, tenantSettingForm, tenantSettingRules} = toRefs(data); const { queryParams, form, rules, tenantSettingForm, tenantSettingRules } =
toRefs(data);
/** 查询租户列表 */ /** 查询租户列表 */
function getList() { function getList() {
@ -352,9 +385,9 @@ function cancel() {
* 取消租户设置 * 取消租户设置
*/ */
const cancelSettingTenant = () => { const cancelSettingTenant = () => {
showTenantSetting.value = false showTenantSetting.value = false;
resetSettingTenant() resetSettingTenant();
} };
// 表单重置 // 表单重置
function reset() { function reset() {
@ -385,17 +418,19 @@ function reset() {
const resetSettingTenant = () => { const resetSettingTenant = () => {
form.value = { form.value = {
/*TODO:*/ /*TODO:*/
datasourceList: [{ datasourceList: [
type: null, {
ip: null, type: null,
port: null, ip: null,
name: null, port: null,
username: null, name: null,
password: null, username: null,
}] password: null,
} },
tenantSettingRef.value?.resetFields() ],
} };
tenantSettingRef.value?.resetFields();
};
/** 搜索按钮操作 */ /** 搜索按钮操作 */
function handleQuery() { function handleQuery() {
@ -440,12 +475,12 @@ function handleUpdate(row) {
*/ */
const handleSetting = (row) => { const handleSetting = (row) => {
// editDatasourceIndex.value = 0 // editDatasourceIndex.value = 0
resetSettingTenant() resetSettingTenant();
getSetting(row.tenantId).then(resp => { getSetting(row.tenantId).then((resp) => {
tenantSettingForm.value = resp.data tenantSettingForm.value = resp.data;
showTenantSetting.value = true showTenantSetting.value = true;
}) });
} };
/** 提交按钮 */ /** 提交按钮 */
function submitForm() { function submitForm() {
@ -473,33 +508,32 @@ function submitForm() {
*/ */
const submitTenantSetting = () => { const submitTenantSetting = () => {
/*TODO:*/ /*TODO:*/
showTenantSetting.value = false showTenantSetting.value = false;
} };
/** 删除按钮操作 */ /** 删除按钮操作 */
function handleDelete(row) { function handleDelete(row) {
const _tenantIds = row.tenantId || ids.value; const _tenantIds = row.tenantId || ids.value;
proxy.$modal proxy.$modal
.confirm('是否确认删除租户编号为"' + _tenantIds + '"的数据项?') .confirm('是否确认删除租户编号为"' + _tenantIds + '"的数据项?')
.then(function () { .then(function () {
return delTenant(_tenantIds); return delTenant(_tenantIds);
}) })
.then(() => { .then(() => {
getList(); getList();
proxy.$modal.msgSuccess("删除成功"); proxy.$modal.msgSuccess("删除成功");
}) })
.catch(() => { .catch(() => {});
});
} }
/** 导出按钮操作 */ /** 导出按钮操作 */
function handleExport() { function handleExport() {
proxy.download( proxy.download(
"tenant/tenant/export", "tenant/tenant/export",
{ {
...queryParams.value, ...queryParams.value,
}, },
`tenant_${new Date().getTime()}.xlsx` `tenant_${new Date().getTime()}.xlsx`
); );
} }
@ -539,6 +573,5 @@ getList();
display: flex; display: flex;
align-items: center; align-items: center;
} }
} }
</style> </style>