多租户前端修改提交

This commit is contained in:
yaoyn
2024-07-19 17:47:11 +08:00
parent d85c09bd83
commit 8034e9b090
23 changed files with 958 additions and 43 deletions

View File

@ -0,0 +1,112 @@
<template>
<BasicModal
v-bind="$attrs"
@register="registerRoleAuthModal"
:title="t('功能授权')"
destroy-on-close
@ok="handleSubmit"
width="40%"
>
<div style="margin-left: 30%">
<div class="text-base border-l-6 border-[#5e95ff] pl-3 h-5 leading-5 mb-3 ml-2">
{{ t('系统功能') }}
</div>
<div class="treebox">
<BasicTree
:treeData="treeData"
checkable
ref="treeRef"
@check="handleTreeSelect"
:fieldNames="{ title: 'title', key: 'id' }"
>
<template #title="{ title, systemName, parentId }">
<div v-if="parentId == 0">{{ title }} {{ systemName }}</div>
<div v-else>{{ title }}</div>
</template>
</BasicTree>
</div>
</div>
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, unref } from 'vue';
import { getTenantMenuSimpleTree } from '/@/api/system/menu';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { TreeItem, BasicTree, TreeActionType } from '/@/components/Tree';
import { useMessage } from '/@/hooks/web/useMessage';
import { getAuthorize, setAuthorize } from '/@/api/system/tenant';
import { useI18n } from '/@/hooks/web/useI18n';
const emits = defineEmits(['success', 'register']);
const { notification } = useMessage();
const { t } = useI18n();
const treeRef = ref<Nullable<TreeActionType>>(null);
const treeData = ref<TreeItem[]>([]);
const menuKeys = ref<string[]>([]);
const rowId = ref('');
function getTree(tree) {
return tree || null;
}
const [registerRoleAuthModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
setModalProps({ confirmLoading: false });
rowId.value = data.id;
treeData.value = await getTenantMenuSimpleTree();
const authList = await getAuthorize(rowId.value);
menuKeys.value = authList || [];
let menuCheckedKey = [];
menuKeys.value.forEach((o) => {
getParentKeys(menuCheckedKey, treeData.value, o);
});
menuKeys.value = menuCheckedKey;
getTree(unref(treeRef)).setCheckedKeys(authList);
getTree(unref(treeRef)).expandAll(true);
});
async function handleSubmit() {
try {
setModalProps({ confirmLoading: true });
await setAuthorize({
id: rowId.value,
menuIds: menuKeys.value,
});
notification.success({
message: t('提示'),
description: t('功能授权更新成功'),
});
closeModal();
emits('success');
} catch (error) {
setModalProps({ confirmLoading: false });
}
}
function handleTreeSelect(keys, e) {
//keys 所有全选中的key
//e.halfCheckedKeys 所有半选中的
//如果没有半选 就证明全部全选 直接使用keys
//如果有半选需要 使用keys + e.halfCheckedKeys
const menuSelect: string[] = [...e.halfCheckedKeys, ...keys];
menuKeys.value = menuSelect;
}
function getParentKeys(checkedKey, arr, keys) {
for (let i = 0; i < arr.length; i++) {
let o = arr[i];
if (o.id == keys) {
checkedKey.push(o.id);
if (o.parentId > 0 && !checkedKey.includes(o.parentId)) {
checkedKey.push(o.parentId);
}
}
if (o.children?.length > 0) {
getParentKeys(checkedKey, o.children, keys);
}
}
}
</script>

View File

@ -0,0 +1,143 @@
<template>
<BasicModal
v-bind="$attrs"
@register="registerDrawer"
showFooter
:title="getTitle"
width="50%"
@ok="handleSubmit"
>
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, computed, unref } from 'vue';
import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { useMessage } from '/@/hooks/web/useMessage';
// import { useI18n } from 'vue-i18n';
import { addTenant, updateTenant } from '/@/api/system/tenant';
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n();
const formSchema: FormSchema[] = [
{
field: 'name',
label: t('租户名称'),
component: 'Input',
required: true,
colProps: { lg: 24, md: 24 },
},
{
field: 'code',
label: t('租户编码'),
component: 'Input',
required: true,
colProps: { lg: 24, md: 24 },
},
{
field: 'startTime',
label: t('开始时间'),
component: 'DatePicker',
required: true,
colProps: { lg: 24, md: 24 },
componentProps: {
getPopupContainer: () => document.body,
},
},
{
field: 'endTime',
label: t('结束时间'),
component: 'DatePicker',
required: true,
colProps: { lg: 24, md: 24 },
componentProps: {
getPopupContainer: () => document.body,
},
},
{
field: 'enabledMark',
label: t('状态'),
component: 'RadioButtonGroup',
defaultValue: 1,
componentProps: {
options: [
{ label: t('启用'), value: 1 },
{ label: t('禁用'), value: 0 },
],
},
required: true,
},
{
field: 'rootDepartmentId',
label: t('根部门'),
component: 'DeptTree',
defaultValue: 1,
componentProps: {
},
required: true,
},
{
field: 'remark',
label: t('备注'),
component: 'InputTextArea',
colProps: { lg: 24, md: 24 },
},
];
const isUpdate = ref(true);
const { notification } = useMessage();
const rowId = ref('');
const emit = defineEmits(['success', 'register']);
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
labelWidth: 100,
schemas: formSchema,
showActionButtonGroup: false,
baseColProps: { lg: 12, md: 24 },
});
const [registerDrawer, { setModalProps, closeModal }] = useModalInner(async (data) => {
resetFields();
setModalProps({ confirmLoading: false });
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
rowId.value = data.record.id;
setFieldsValue({
...data.record,
});
}
});
const getTitle = computed(() => (!unref(isUpdate) ? t('新增租户') : t('更新租户')));
async function handleSubmit() {
try {
const values = await validate();
setModalProps({ confirmLoading: true });
// TODO custom api
if (!unref(isUpdate)) {
//false 新增
await addTenant(values);
notification.success({
message: t('提示'),
description: t('新增成功'),
}); //提示消息
} else {
values.id = rowId.value;
await updateTenant(values);
notification.success({
message: t('提示'),
description: t('编辑成功'),
}); //提示消息
}
closeModal();
emit('success');
} catch (error) {
setModalProps({ confirmLoading: false });
}
}
</script>

View File

@ -0,0 +1,222 @@
<template>
<PageWrapper dense contentFullHeight fixedHeight>
<BasicTable @register="registerTable">
<template #toolbar>
<a-button type="primary" @click="handleCreate">
{{ t('新增租户') }}
</a-button>
<a-button type="primary" @click="handleAuth">
{{ t('功能授权') }}
</a-button>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex == 'action'">
<TableAction
:actions="[
{
icon: 'clarity:note-edit-line',
onClick: handleEdit.bind(null, record),
},
{
icon: 'ant-design:delete-outlined',
color: 'error',
popConfirm: {
title: t('是否确认删除'),
confirm: handleDelete.bind(null, record),
},
},
]"
/>
</template>
</template>
</BasicTable>
<TenantDrawer @register="registerDrawer" @success="handleSuccess" />
<AuthModal @register="registerModal" @success="handleSuccess" />
</PageWrapper>
</template>
<script lang="ts" setup>
import { h } from 'vue';
import { BasicTable, useTable, TableAction, BasicColumn, FormSchema } from '/@/components/Table';
import { useModal } from '/@/components/Modal';
import { PageWrapper } from '/@/components/Page';
import TenantDrawer from './components/TenantDrawer.vue';
import AuthModal from './components/AuthModal.vue';
import { Switch } from 'ant-design-vue';
import { useMessage } from '/@/hooks/web/useMessage';
import { deleteTenant, getTenantPageList, updateTenantStatus } from '/@/api/system/tenant';
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n();
const columns: BasicColumn[] = [
{
title: t('租户名'),
dataIndex: 'name',
align: 'left',
sorter: true,
},
{
title: t('租户编码'),
dataIndex: 'code',
sorter: true,
align: 'left',
},
{
title: t('开始时间'),
dataIndex: 'startTime',
sorter: true,
align: 'left',
},
{
title: t('结束时间'),
dataIndex: 'endTime',
sorter: true,
align: 'left',
},
{
title: t('状态'),
dataIndex: 'enabledMark',
sorter: true,
customRender: ({ record }) => {
if (!Reflect.has(record, 'pendingStatus')) {
record.pendingStatus = false;
}
return h(Switch, {
checked: record.enabledMark === 1,
checkedChildren: t('已启用'),
unCheckedChildren: t('已禁用'),
loading: record.pendingStatus,
onChange(checked: boolean) {
record.pendingStatus = true;
const newStatus = checked ? 1 : 0;
const { createMessage } = useMessage();
updateTenantStatus(record.id, newStatus)
.then(() => {
record.enabledMark = newStatus;
createMessage.success(t('已成功修改租户状态'));
})
.catch(() => {
createMessage.error(t('修改角色租户失败'));
})
.finally(() => {
record.pendingStatus = false;
});
},
});
},
},
{
title: t('备注'),
dataIndex: 'remark',
align: 'left',
sorter: true,
},
];
const searchFormSchema: FormSchema[] = [
{
field: 'name',
label: t('租户名称'),
component: 'Input',
colProps: { lg: 8, md: 12, sm: 12 },
},
{
field: 'code',
label: t('租户编码'),
component: 'Input',
colProps: { lg: 8, md: 12, sm: 12 },
},
{
field: 'enabledMark',
label: t('状态'),
component: 'Select',
componentProps: {
options: [
{ label: t('启用'), value: 1 },
{ label: t('停用'), value: 0 },
],
},
colProps: { lg: 8, md: 12, sm: 12 },
},
];
const { notification } = useMessage();
const [registerDrawer, { openModal }] = useModal();
const [registerModal, { openModal: openAuthModal }] = useModal();
const [registerTable, { reload, getSelectRowKeys }] = useTable({
title: t('租户列表'),
api: getTenantPageList,
rowKey: 'id',
columns,
formConfig: {
rowProps: {
gutter: 16,
},
schemas: searchFormSchema,
actionColOptions: { span: 16 },
},
// beforeFetch: (params) => {
// return {
// ...params,
// isOrg: 1,
// };
// },
pagination: {
pageSize: 20,
},
striped: false,
useSearchForm: true,
showTableSetting: true,
showIndexColumn: false,
rowSelection: {
type: 'radio',
},
actionColumn: {
width: 100,
title: t('操作'),
dataIndex: 'action',
slots: { customRender: 'action' },
},
});
function handleCreate() {
openModal(true, {
isUpdate: false,
});
}
function handleAuth() {
if (getSelectRowKeys().length === 0) {
notification.warning({
message: t('警告'),
description: t('必须选中一行!'),
});
return;
}
openAuthModal(true, {
id: getSelectRowKeys()[0],
});
}
function handleEdit(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
});
}
function handleDelete(record: Recordable) {
deleteTenant([record.id]).then((_) => {
reload();
notification.success({
message: t('提示'),
description: t('删除成功'),
}); //提示消息
});
}
function handleSuccess() {
reload();
}
</script>