From e66256581e5826e03aaad5170cb7de10f5ceabf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E7=86=8A?= <50282105+xtanyu@users.noreply.github.com> Date: Thu, 10 Jul 2025 20:39:02 +0800 Subject: [PATCH] =?UTF-8?q?feat(tenant):=20=E6=96=B0=E5=A2=9E=E5=A4=9A?= =?UTF-8?q?=E7=A7=9F=E6=88=B7=E6=A8=A1=E5=9D=97=20(#75)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/common/captcha.ts | 5 + src/apis/tenant/tenant.ts | 94 ++++++ src/apis/tenant/tenantDbConnect.ts | 65 ++++ src/apis/tenant/tenantPackage.ts | 73 +++++ src/components/GiLeftRightPane/index.vue | 60 ++++ src/components/SelectTenant/index.vue | 168 ++++++++++ src/hooks/app/useMenu.ts | 16 +- src/types/components.d.ts | 2 + src/utils/http.ts | 8 + src/utils/tenant.ts | 14 + src/views/login/index.vue | 1 + src/views/setting/message/index.vue | 146 +++++++++ .../config/components/CaptchaSetting.vue | 151 +++++++++ src/views/system/role/RoleAddModal.vue | 299 ++++++++++++++++++ .../tenant/package/TenantPackageAddModal.vue | 155 +++++++++ .../package/TenantPackageDetailDrawer.vue | 67 ++++ src/views/tenant/package/index.vue | 133 ++++++++ .../TenantDbConnectAddModal.vue | 142 +++++++++ .../TenantDbConnectDetailDrawer.vue | 44 +++ src/views/tenant/tenantDbConnect/index.vue | 142 +++++++++ src/views/tenant/user/TenantAddModal.vue | 230 ++++++++++++++ src/views/tenant/user/TenantDetailDrawer.vue | 87 +++++ src/views/tenant/user/TenantUserEditModal.vue | 104 ++++++ src/views/tenant/user/index.vue | 200 ++++++++++++ 24 files changed, 2405 insertions(+), 1 deletion(-) create mode 100644 src/apis/tenant/tenant.ts create mode 100644 src/apis/tenant/tenantDbConnect.ts create mode 100644 src/apis/tenant/tenantPackage.ts create mode 100644 src/components/GiLeftRightPane/index.vue create mode 100644 src/components/SelectTenant/index.vue create mode 100644 src/utils/tenant.ts create mode 100644 src/views/setting/message/index.vue create mode 100644 src/views/system/config/components/CaptchaSetting.vue create mode 100644 src/views/system/role/RoleAddModal.vue create mode 100644 src/views/tenant/package/TenantPackageAddModal.vue create mode 100644 src/views/tenant/package/TenantPackageDetailDrawer.vue create mode 100644 src/views/tenant/package/index.vue create mode 100644 src/views/tenant/tenantDbConnect/TenantDbConnectAddModal.vue create mode 100644 src/views/tenant/tenantDbConnect/TenantDbConnectDetailDrawer.vue create mode 100644 src/views/tenant/tenantDbConnect/index.vue create mode 100644 src/views/tenant/user/TenantAddModal.vue create mode 100644 src/views/tenant/user/TenantDetailDrawer.vue create mode 100644 src/views/tenant/user/TenantUserEditModal.vue create mode 100644 src/views/tenant/user/index.vue diff --git a/src/apis/common/captcha.ts b/src/apis/common/captcha.ts index 29ac1cb..5887f01 100644 --- a/src/apis/common/captcha.ts +++ b/src/apis/common/captcha.ts @@ -5,6 +5,11 @@ export type * from './type' const BASE_URL = '/captcha' +/** @desc 获取图片验证码 */ +export function getCaptchaConfig() { + return http.get(`${BASE_URL}/config`) +} + /** @desc 获取图片验证码 */ export function getImageCaptcha() { return http.get(`${BASE_URL}/image`) diff --git a/src/apis/tenant/tenant.ts b/src/apis/tenant/tenant.ts new file mode 100644 index 0000000..e02e45c --- /dev/null +++ b/src/apis/tenant/tenant.ts @@ -0,0 +1,94 @@ +import http from '@/utils/http' +import type { TenantCommon } from '@/utils/tenant' + +const BASE_URL = '/tenant/user' + +export interface TenantResp { + id: string + name: string + domain: string + packageId: string + status: string + expireTime: string + createTime: string + createUserString: string + updateUserString: string +} +export interface TenantDetailResp { + id: string + name: string + domain: string + packageId: string + status: string + expireTime: string + createUser: string + createTime: string + updateUser: string + updateTime: string + createUserString: string + updateUserString: string + packageName: string + menuIds: [] +} +export interface TenantQuery { + name: string + packageId: string + status: string + sort: Array +} +export interface TenantPageQuery extends TenantQuery, PageQuery {} + +/** @desc 查询租户列表 */ +export function listTenant(query: TenantPageQuery) { + return http.get>(`${BASE_URL}`, query) +} + +/** @desc 查询租户详情 */ +export function getTenant(id: string) { + return http.get(`${BASE_URL}/${id}`) +} + +/** @desc 新增租户 */ +export function addTenant(data: any) { + return http.post(`${BASE_URL}`, data) +} + +/** @desc 修改租户 */ +export function updateTenant(data: any, id: string) { + return http.put(`${BASE_URL}/${id}`, data) +} + +/** @desc 删除租户 */ +export function deleteTenant(id: string) { + return http.del(`${BASE_URL}/${id}`) +} + +/** @desc 导出租户 */ +export function exportTenant(query: TenantQuery) { + return http.download(`${BASE_URL}/export`, query) +} + +/** @desc 多租户通用信息查询 */ +export const getTenantCommon = () => { + return http.get(`${BASE_URL}/common`) +} + +/** @desc 获取租户管理账号用户名 */ +export const getTenantLoginUser = (tenantId: string) => { + return http.get(`${BASE_URL}/loginUser/${tenantId}`) +} + +/** @desc 租户管理账号信息更新 */ +export const updateTenantLoginUser = (data: any) => { + return http.put(`${BASE_URL}/loginUser`, data) +} + +/** @desc 获取套餐列表 */ +export const listAllPackage = () => { + return http.get(`${BASE_URL}/all/package`) +} + +/** @desc 获取数据连接列表 */ +export const listAllDbConnect = () => { + return http.get(`${BASE_URL}/all/dbConnect`) +} diff --git a/src/apis/tenant/tenantDbConnect.ts b/src/apis/tenant/tenantDbConnect.ts new file mode 100644 index 0000000..8f10983 --- /dev/null +++ b/src/apis/tenant/tenantDbConnect.ts @@ -0,0 +1,65 @@ +import http from '@/utils/http' + +const BASE_URL = '/tenant/dbConnect' + +export interface TenantDbConnectResp { + id: string + connectName: string + type: string + host: string + port: string + username: string + password: string + createUserString: string + updateUserString: string +} +export interface TenantDbConnectDetailResp { + id: string + connectName: string + type: string + host: string + port: string + username: string + password: string + createUser: string + createTime: string + updateUser: string + updateTime: string + createUserString: string + updateUserString: string +} +export interface TenantDbConnectQuery { + connectName: string + sort: Array +} +export interface TenantDbConnectPageQuery extends TenantDbConnectQuery, PageQuery {} + +/** @desc 查询租户数据连接列表 */ +export function listTenantDbConnect(query: TenantDbConnectPageQuery) { + return http.get>(`${BASE_URL}`, query) +} + +/** @desc 查询租户数据连接详情 */ +export function getTenantDbConnect(id: string) { + return http.get(`${BASE_URL}/${id}`) +} + +/** @desc 新增租户数据连接 */ +export function addTenantDbConnect(data: any) { + return http.post(`${BASE_URL}`, data) +} + +/** @desc 修改租户数据连接 */ +export function updateTenantDbConnect(data: any, id: string) { + return http.put(`${BASE_URL}/${id}`, data) +} + +/** @desc 删除租户数据连接 */ +export function deleteTenantDbConnect(id: string) { + return http.del(`${BASE_URL}/${id}`) +} + +/** @desc 导出租户数据连接 */ +export function exportTenantDbConnect(query: TenantDbConnectQuery) { + return http.download(`${BASE_URL}/export`, query) +} diff --git a/src/apis/tenant/tenantPackage.ts b/src/apis/tenant/tenantPackage.ts new file mode 100644 index 0000000..1ccd1c8 --- /dev/null +++ b/src/apis/tenant/tenantPackage.ts @@ -0,0 +1,73 @@ +import http from '@/utils/http' + +const BASE_URL = '/tenant/package' + +export interface TenantPackageResp { + id: string + name: string + menuIds: string + menuCheckStrictly: string + status: string + createTime: string + createUserString: string + updateUserString: string +} +export interface TenantPackageDetailResp { + id: string + name: string + menuIds: [] + menuCheckStrictly: string + status: string + createUser: string + createTime: string + updateUser: string + updateTime: string + createUserString: string + updateUserString: string +} +export interface TenantPackageQuery { + name: string + status: string + sort: Array +} +export interface TenantPackagePageQuery extends TenantPackageQuery, PageQuery {} + +/** @desc 查询租户套餐列表 */ +export function listTenantPackage(query: TenantPackagePageQuery) { + return http.get>(`${BASE_URL}`, query) +} + +/** @desc 查询租户套餐详情 */ +export function getTenantPackage(id: string) { + return http.get(`${BASE_URL}/${id}`) +} + +/** @desc 新增租户套餐 */ +export function addTenantPackage(data: any) { + return http.post(`${BASE_URL}`, data) +} + +/** @desc 修改租户套餐 */ +export function updateTenantPackage(data: any, id: string) { + return http.put(`${BASE_URL}/${id}`, data) +} + +/** @desc 删除租户套餐 */ +export function deleteTenantPackage(id: string) { + return http.del(`${BASE_URL}/${id}`) +} + +/** @desc 导出租户套餐 */ +export function exportTenantPackage(query: TenantPackageQuery) { + return http.download(`${BASE_URL}/export`, query) +} + +/** @desc 查询所有套餐 */ +export function listAllTenantPackage() { + return http.get(`${BASE_URL}/list`) +} + +/** @desc 查询套餐菜单 */ +export function listTenantPackageMenu() { + return http.get(`${BASE_URL}/menuTree`) +} diff --git a/src/components/GiLeftRightPane/index.vue b/src/components/GiLeftRightPane/index.vue new file mode 100644 index 0000000..20ae6cd --- /dev/null +++ b/src/components/GiLeftRightPane/index.vue @@ -0,0 +1,60 @@ + + + + + diff --git a/src/components/SelectTenant/index.vue b/src/components/SelectTenant/index.vue new file mode 100644 index 0000000..4588eb4 --- /dev/null +++ b/src/components/SelectTenant/index.vue @@ -0,0 +1,168 @@ + + + + + diff --git a/src/hooks/app/useMenu.ts b/src/hooks/app/useMenu.ts index d3e0309..6d5a639 100644 --- a/src/hooks/app/useMenu.ts +++ b/src/hooks/app/useMenu.ts @@ -1,6 +1,7 @@ import { ref } from 'vue' import type { TreeNodeData } from '@arco-design/web-vue' import { listMenuTree } from '@/apis' +import { listTenantPackageMenu } from '@/apis/tenant/tenantPackage' /** 菜单模块 */ export function useMenu(options?: { onSuccess?: () => void }) { @@ -17,5 +18,18 @@ export function useMenu(options?: { onSuccess?: () => void }) { loading.value = false } } - return { menuList, getMenuList, loading } + + // 获取租户套餐菜单 + const getTenantPackageMenuList = async () => { + try { + loading.value = true + const res = await listTenantPackageMenu() + menuList.value = res.data + options?.onSuccess && options.onSuccess() + } finally { + loading.value = false + } + } + + return { menuList, getMenuList, loading, getTenantPackageMenuList } } diff --git a/src/types/components.d.ts b/src/types/components.d.ts index 7ea3f11..9a6149c 100644 --- a/src/types/components.d.ts +++ b/src/types/components.d.ts @@ -30,6 +30,7 @@ declare module 'vue' { GiIconBox: typeof import('./../components/GiIconBox/index.vue')['default'] GiIconSelector: typeof import('./../components/GiIconSelector/index.vue')['default'] GiIframe: typeof import('./../components/GiIframe/index.vue')['default'] + GiLeftRightPane: typeof import('./../components/GiLeftRightPane/index.vue')['default'] GiOption: typeof import('./../components/GiOption/index.vue')['default'] GiOptionItem: typeof import('./../components/GiOptionItem/index.vue')['default'] GiPageLayout: typeof import('./../components/GiPageLayout/index.vue')['default'] @@ -56,6 +57,7 @@ declare module 'vue' { RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] SecondForm: typeof import('./../components/GenCron/CronForm/component/second-form.vue')['default'] + SelectTenant: typeof import('./../components/SelectTenant/index.vue')['default'] SplitPanel: typeof import('./../components/SplitPanel/index.vue')['default'] TextCopy: typeof import('./../components/TextCopy/index.vue')['default'] UserSelect: typeof import('./../components/UserSelect/index.vue')['default'] diff --git a/src/utils/http.ts b/src/utils/http.ts index 5868f50..536e9e8 100644 --- a/src/utils/http.ts +++ b/src/utils/http.ts @@ -7,6 +7,7 @@ import modalErrorWrapper from '@/utils/modal-error-wrapper' import messageErrorWrapper from '@/utils/message-error-wrapper' import notificationErrorWrapper from '@/utils/notification-error-wrapper' import router from '@/router' +import { getTenantId } from '@/utils/tenant' interface ICodeMessage { [propName: number]: string @@ -57,6 +58,13 @@ http.interceptors.request.use( } config.headers.Authorization = `Bearer ${token}` } + const tenantId = getTenantId() + if (tenantId) { + if (!config.headers) { + config.headers = {} + } + config.headers['X-Tenant-Id'] = tenantId + } return config }, (error) => Promise.reject(error), diff --git a/src/utils/tenant.ts b/src/utils/tenant.ts new file mode 100644 index 0000000..7deeb18 --- /dev/null +++ b/src/utils/tenant.ts @@ -0,0 +1,14 @@ +const CURRENT_TENANT = 'current_tenant' + +export interface TenantCommon { + isEnabled: boolean + availableList: any[] +} + +export const getTenantId = () => { + return localStorage.getItem(CURRENT_TENANT) +} + +export const setTenantId = (tenantId: string) => { + localStorage.setItem(CURRENT_TENANT, tenantId) +} diff --git a/src/views/login/index.vue b/src/views/login/index.vue index 636d078..5f4a8e3 100644 --- a/src/views/login/index.vue +++ b/src/views/login/index.vue @@ -87,6 +87,7 @@ + + + diff --git a/src/views/system/config/components/CaptchaSetting.vue b/src/views/system/config/components/CaptchaSetting.vue new file mode 100644 index 0000000..5c04e79 --- /dev/null +++ b/src/views/system/config/components/CaptchaSetting.vue @@ -0,0 +1,151 @@ + + + + + diff --git a/src/views/system/role/RoleAddModal.vue b/src/views/system/role/RoleAddModal.vue new file mode 100644 index 0000000..8e107b3 --- /dev/null +++ b/src/views/system/role/RoleAddModal.vue @@ -0,0 +1,299 @@ + + + + + diff --git a/src/views/tenant/package/TenantPackageAddModal.vue b/src/views/tenant/package/TenantPackageAddModal.vue new file mode 100644 index 0000000..3624e94 --- /dev/null +++ b/src/views/tenant/package/TenantPackageAddModal.vue @@ -0,0 +1,155 @@ + + + + + diff --git a/src/views/tenant/package/TenantPackageDetailDrawer.vue b/src/views/tenant/package/TenantPackageDetailDrawer.vue new file mode 100644 index 0000000..e7df2ab --- /dev/null +++ b/src/views/tenant/package/TenantPackageDetailDrawer.vue @@ -0,0 +1,67 @@ + + + + + diff --git a/src/views/tenant/package/index.vue b/src/views/tenant/package/index.vue new file mode 100644 index 0000000..c93c2bf --- /dev/null +++ b/src/views/tenant/package/index.vue @@ -0,0 +1,133 @@ + + + + + diff --git a/src/views/tenant/tenantDbConnect/TenantDbConnectAddModal.vue b/src/views/tenant/tenantDbConnect/TenantDbConnectAddModal.vue new file mode 100644 index 0000000..d3408fe --- /dev/null +++ b/src/views/tenant/tenantDbConnect/TenantDbConnectAddModal.vue @@ -0,0 +1,142 @@ + + + + + diff --git a/src/views/tenant/tenantDbConnect/TenantDbConnectDetailDrawer.vue b/src/views/tenant/tenantDbConnect/TenantDbConnectDetailDrawer.vue new file mode 100644 index 0000000..bbfade4 --- /dev/null +++ b/src/views/tenant/tenantDbConnect/TenantDbConnectDetailDrawer.vue @@ -0,0 +1,44 @@ + + + + + diff --git a/src/views/tenant/tenantDbConnect/index.vue b/src/views/tenant/tenantDbConnect/index.vue new file mode 100644 index 0000000..2b15be4 --- /dev/null +++ b/src/views/tenant/tenantDbConnect/index.vue @@ -0,0 +1,142 @@ + + + + + diff --git a/src/views/tenant/user/TenantAddModal.vue b/src/views/tenant/user/TenantAddModal.vue new file mode 100644 index 0000000..854a9dd --- /dev/null +++ b/src/views/tenant/user/TenantAddModal.vue @@ -0,0 +1,230 @@ + + + + + diff --git a/src/views/tenant/user/TenantDetailDrawer.vue b/src/views/tenant/user/TenantDetailDrawer.vue new file mode 100644 index 0000000..2f8b6a0 --- /dev/null +++ b/src/views/tenant/user/TenantDetailDrawer.vue @@ -0,0 +1,87 @@ + + + + + diff --git a/src/views/tenant/user/TenantUserEditModal.vue b/src/views/tenant/user/TenantUserEditModal.vue new file mode 100644 index 0000000..40debb0 --- /dev/null +++ b/src/views/tenant/user/TenantUserEditModal.vue @@ -0,0 +1,104 @@ + + + + + diff --git a/src/views/tenant/user/index.vue b/src/views/tenant/user/index.vue new file mode 100644 index 0000000..58d890a --- /dev/null +++ b/src/views/tenant/user/index.vue @@ -0,0 +1,200 @@ + + + + +