Files
vue3-element-admin/src/views/system/tenant/index.vue

420 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="app-container">
<!-- 搜索区域 -->
<div class="filter-section">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item prop="keywords" label="关键字">
<el-input
v-model="queryParams.keywords"
placeholder="租户名称/租户编码/域名"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item prop="status" label="状态">
<el-select v-model="queryParams.status" placeholder="全部" clearable style="width: 120px">
<el-option label="正常" :value="1" />
<el-option label="禁用" :value="0" />
</el-select>
</el-form-item>
<el-form-item class="search-buttons">
<el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
<el-button icon="refresh" @click="handleResetQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
<el-card shadow="hover" class="table-section">
<div class="table-section__toolbar">
<div class="table-section__toolbar--actions">
<el-button
v-hasPerm="['sys:tenant:create']"
type="success"
icon="plus"
@click="handleOpenDialog()"
>
新增
</el-button>
<el-button
v-hasPerm="['sys:tenant:delete']"
type="danger"
icon="delete"
:disabled="ids.length === 0"
@click="handleDelete()"
>
删除
</el-button>
</div>
</div>
<el-table
v-loading="loading"
:data="pageData"
highlight-current-row
border
class="table-section__content"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="租户名称" prop="name" min-width="160" />
<el-table-column label="租户编码" prop="code" width="140" />
<el-table-column label="域名" prop="domain" min-width="160" />
<el-table-column label="联系人" prop="contactName" width="120" />
<el-table-column label="电话" prop="contactPhone" width="140" />
<el-table-column label="状态" width="120" align="center">
<template #default="scope">
<el-switch
v-if="hasPermChangeStatus"
v-model="scope.row.status"
inline-prompt
active-text="正常"
inactive-text="禁用"
:active-value="1"
:inactive-value="0"
@change="
(val) => {
pageData.length > 0 && handleChangeStatus(scope.row.id, Number(val));
}
"
/>
<el-tag v-else :type="scope.row.status === 1 ? 'success' : 'info'">
{{ scope.row.status === 1 ? "正常" : "禁用" }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="过期时间" prop="expireTime" width="180" />
<el-table-column label="创建时间" prop="createTime" width="180" />
<el-table-column fixed="right" label="操作" width="180">
<template #default="scope">
<el-button
v-hasPerm="['sys:tenant:update']"
type="primary"
size="small"
link
icon="edit"
@click="handleOpenDialog(scope.row.id)"
>
编辑
</el-button>
<el-button
v-hasPerm="['sys:tenant:delete']"
type="danger"
size="small"
link
icon="delete"
@click="handleDelete(scope.row.id)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-if="total > 0"
v-model:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="fetchData"
/>
</el-card>
<!-- 租户表单弹窗 -->
<el-dialog
v-model="dialog.visible"
:title="dialog.title"
width="600px"
@close="handleCloseDialog"
>
<el-form ref="dataFormRef" :model="formData" :rules="rules" label-width="100px">
<el-form-item label="租户名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入租户名称" />
</el-form-item>
<el-form-item label="租户编码" prop="code">
<el-input
v-model="formData.code"
placeholder="请输入租户编码"
:disabled="formData.id != null && String(formData.id) !== ''"
/>
</el-form-item>
<el-form-item label="域名" prop="domain">
<el-input v-model="formData.domain" placeholder="demo.youlai.tech可选" />
</el-form-item>
<el-form-item label="联系人" prop="contactName">
<el-input v-model="formData.contactName" placeholder="可选" />
</el-form-item>
<el-form-item label="联系电话" prop="contactPhone">
<el-input v-model="formData.contactPhone" placeholder="可选" />
</el-form-item>
<el-form-item label="联系邮箱" prop="contactEmail">
<el-input v-model="formData.contactEmail" placeholder="可选" />
</el-form-item>
<el-form-item label="过期时间" prop="expireTime">
<el-date-picker
v-model="formData.expireTime"
type="datetime"
placeholder="不填表示永不过期"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
/>
</el-form-item>
<el-form-item
v-if="formData.id == null || String(formData.id) === ''"
label="管理员账号"
prop="adminUsername"
>
<el-input v-model="formData.adminUsername" placeholder="为空则系统生成" />
</el-form-item>
<el-form-item
v-if="formData.id != null && String(formData.id) !== ''"
label="状态"
prop="status"
>
<el-radio-group v-model="formData.status">
<el-radio :value="1">正常</el-radio>
<el-radio :value="0">禁用</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" type="textarea" :rows="3" placeholder="可选" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="handleSubmit">确定</el-button>
<el-button @click="handleCloseDialog">取消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts">
defineOptions({
name: "Tenant",
inheritAttrs: false,
});
import { ElMessage, ElMessageBox } from "element-plus";
import { useDebounceFn } from "@vueuse/core";
import { hasPerm } from "@/utils/auth";
import TenantAPI from "@/api/system/tenant";
import type { TenantCreateForm, TenantForm, TenantQueryParams, TenantItem } from "@/types/api";
const queryFormRef = ref();
const dataFormRef = ref();
const loading = ref(false);
const ids = ref<number[]>([]);
const total = ref(0);
const queryParams = reactive<TenantQueryParams>({
pageNum: 1,
pageSize: 10,
keywords: "",
});
const pageData = ref<TenantItem[]>([]);
const dialog = reactive({
title: "",
visible: false,
});
const formData = reactive<TenantForm & TenantCreateForm>({
id: undefined,
name: "",
code: "",
domain: "",
contactName: "",
contactPhone: "",
contactEmail: "",
remark: "",
expireTime: undefined,
status: 1,
adminUsername: "",
});
const rules = reactive({
name: [{ required: true, message: "请输入租户名称", trigger: "blur" }],
code: [{ required: true, message: "请输入租户编码", trigger: "blur" }],
});
const hasPermChangeStatus = computed(() => hasPerm("sys:tenant:change-status"));
function fetchData() {
loading.value = true;
TenantAPI.getPage(queryParams)
.then((res) => {
pageData.value = res.data;
total.value = res.page?.total ?? 0;
})
.finally(() => {
loading.value = false;
});
}
function handleQuery() {
queryParams.pageNum = 1;
fetchData();
}
function handleResetQuery() {
queryFormRef.value?.resetFields();
queryParams.pageNum = 1;
fetchData();
}
function handleSelectionChange(selection: any) {
ids.value = selection.map((item: any) => Number(item.id));
}
async function handleOpenDialog(tenantId?: string) {
dialog.visible = true;
if (tenantId != null && tenantId !== "") {
dialog.title = "修改租户";
const data = await TenantAPI.getFormData(tenantId);
Object.assign(formData, data);
formData.adminUsername = "";
} else {
dialog.title = "新增租户";
Object.assign(formData, {
id: undefined,
name: "",
code: "",
domain: "",
contactName: "",
contactPhone: "",
contactEmail: "",
remark: "",
expireTime: undefined,
status: 1,
adminUsername: "",
});
}
}
function handleCloseDialog() {
dialog.visible = false;
dataFormRef.value?.resetFields();
dataFormRef.value?.clearValidate();
Object.assign(formData, {
id: undefined,
name: "",
code: "",
domain: "",
contactName: "",
contactPhone: "",
contactEmail: "",
remark: "",
expireTime: undefined,
status: 1,
adminUsername: "",
});
}
const handleSubmit = useDebounceFn(async () => {
const valid = await dataFormRef.value?.validate().catch(() => false);
if (!valid) return;
loading.value = true;
try {
const tenantId = formData.id;
if (tenantId != null && String(tenantId) !== "") {
const payload: TenantForm = {
id: formData.id,
name: formData.name,
code: formData.code,
domain: formData.domain,
contactName: formData.contactName,
contactPhone: formData.contactPhone,
contactEmail: formData.contactEmail,
remark: formData.remark,
expireTime: formData.expireTime,
status: formData.status,
};
await TenantAPI.update(String(tenantId), payload);
ElMessage.success("修改成功");
} else {
const payload: TenantCreateForm = {
name: formData.name,
code: formData.code,
domain: formData.domain,
contactName: formData.contactName,
contactPhone: formData.contactPhone,
contactEmail: formData.contactEmail,
remark: formData.remark,
expireTime: formData.expireTime,
adminUsername: formData.adminUsername,
};
const result = await TenantAPI.create(payload);
ElMessage.success(`新增成功:管理员账号 ${result?.adminUsername || ""}`);
}
handleCloseDialog();
handleResetQuery();
} catch {
ElMessage.error(formData.id != null && String(formData.id) !== "" ? "修改失败" : "新增失败");
} finally {
loading.value = false;
}
}, 300);
function handleDelete(tenantId?: string) {
const tenantIds = tenantId != null && tenantId !== "" ? tenantId : ids.value.join(",");
if (!tenantIds) {
ElMessage.warning("请勾选删除项");
return;
}
ElMessageBox.confirm("确认删除选中的租户吗?", "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(async () => {
loading.value = true;
try {
await TenantAPI.deleteByIds(tenantIds);
ElMessage.success("删除成功");
handleResetQuery();
} finally {
loading.value = false;
}
})
.catch(() => {
// 用户取消
});
}
async function handleChangeStatus(id: string | undefined, status: number) {
if (id == null || id === "") return;
try {
await TenantAPI.updateStatus(String(id), status);
ElMessage.success("状态更新成功");
} catch {
ElMessage.error("状态更新失败");
fetchData();
}
}
onMounted(() => {
fetchData();
});
</script>
<style scoped lang="scss"></style>