feat(ram): 应用中心安装弹窗支持 RAM 角色授权选择(角色多选→GrantRoles)
This commit is contained in:
1 parent
36afde19da
commit
7e64bdf38a
2 files changed
+72
-10
No files matched your search
+16
-6
@@ -35,6 +35,12 @@ export interface CompanyScopeItem {
|
||||
Installed?: number
|
||||
}
|
||||
|
||||
/** RAM 角色粒度授权候选(当前租户启用角色) */
|
||||
export interface RoleScopeItem {
|
||||
RoleUUID: string
|
||||
RoleName: string
|
||||
}
|
||||
|
||||
/** 个人授权申请项(租户管理员审批台) */
|
||||
export interface PendingItem {
|
||||
UserAppUUID: string
|
||||
@@ -65,14 +71,18 @@ export const appApi = {
|
||||
/** 我的应用(当前用户可用) */
|
||||
myApps: (): Promise<{ list: AppItem[]; total: number }> => get<{ list: AppItem[]; total: number }>('/API/App/MyApps'),
|
||||
|
||||
/** 管理员可安装应用的公司列表(按权限范围);
|
||||
/** 管理员可安装应用的公司列表(按权限范围)+ 租户角色列表(RAM 授权候选);
|
||||
* 传 AppUUID 时附带各公司安装状态(Installed),供管理弹窗用 */
|
||||
manageCompanies: (AppUUID?: string): Promise<{ Scope: string; Companies: CompanyScopeItem[] }> =>
|
||||
get<{ Scope: string; Companies: CompanyScopeItem[] }>('/API/App/ManageCompanies', AppUUID ? { AppUUID } : {}),
|
||||
manageCompanies: (AppUUID?: string): Promise<{ Scope: string; Companies: CompanyScopeItem[]; Roles: RoleScopeItem[] }> =>
|
||||
get<{ Scope: string; Companies: CompanyScopeItem[]; Roles: RoleScopeItem[] }>(
|
||||
'/API/App/ManageCompanies',
|
||||
AppUUID ? { AppUUID } : {},
|
||||
),
|
||||
|
||||
/** 管理员:安装企业功能(不传 CompanyUUIDs=全租户;传 CompanyUUIDs=指定公司) */
|
||||
install: (AppUUID: string, CompanyUUIDs?: string[]): Promise<AppItem> =>
|
||||
post<AppItem>('/API/App/Install', { AppUUID, CompanyUUIDs: CompanyUUIDs || [] }),
|
||||
/** 管理员:安装企业功能(不传 CompanyUUIDs=全租户;传 CompanyUUIDs=指定公司);
|
||||
* GrantRoles=RAM 角色粒度授权(可选):指定角色可见该应用(安装范围内) */
|
||||
install: (AppUUID: string, CompanyUUIDs?: string[], GrantRoles?: string[]): Promise<AppItem> =>
|
||||
post<AppItem>('/API/App/Install', { AppUUID, CompanyUUIDs: CompanyUUIDs || [], GrantRoles: GrantRoles || [] }),
|
||||
|
||||
/** 管理员:停用企业功能(传 CompanyUUIDs=停用指定公司;TenantOnly=仅停用全租户;都不传=停全租户+当前公司) */
|
||||
uninstall: (AppUUID: string, CompanyUUIDs?: string[], TenantOnly?: boolean): Promise<void> =>
|
||||
|
||||
@@ -10,7 +10,7 @@ import { ref, computed, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Grid } from '@element-plus/icons-vue'
|
||||
import { appApi, type AppItem, type CompanyScopeItem } from '@/api/app'
|
||||
import { appApi, type AppItem, type CompanyScopeItem, type RoleScopeItem } from '@/api/app'
|
||||
import { getAppModule, appOpenTarget } from '@/apps'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { setPageTitle } from '@/utils/serverScope'
|
||||
@@ -28,6 +28,8 @@ const loading = ref(false)
|
||||
const manageableCompanies = ref<CompanyScopeItem[]>([])
|
||||
/** 权限范围:all=跨租户 / tenant=租户内 / company=指定公司 */
|
||||
const manageScope = ref('')
|
||||
/** 当前租户角色列表(RAM 角色粒度授权候选) */
|
||||
const tenantRoles = ref<RoleScopeItem[]>([])
|
||||
|
||||
function typeLabel(t: string): { text: string; type: 'success' | 'info' | 'warning' } {
|
||||
if (t === 'enterprise') return { text: '企业功能', type: 'success' }
|
||||
@@ -60,12 +62,15 @@ const installTargetApp = ref<AppItem | null>(null)
|
||||
const installScope = ref<'tenant' | 'company'>('tenant')
|
||||
/** 选中的公司 UUID 列表 */
|
||||
const selectedCompanies = ref<string[]>([])
|
||||
/** RAM 角色粒度授权:选中的角色 UUID 列表(不选=全员可见) */
|
||||
const selectedRoles = ref<string[]>([])
|
||||
|
||||
/** 打开安装弹窗:拉取可管理公司 */
|
||||
/** 打开安装弹窗:拉取可管理公司 + 租户角色(RAM 授权候选) */
|
||||
async function openInstallDialog(a: AppItem): Promise<void> {
|
||||
installTargetApp.value = a
|
||||
installScope.value = 'tenant'
|
||||
selectedCompanies.value = []
|
||||
selectedRoles.value = []
|
||||
installDialogVisible.value = true
|
||||
if (isAdmin.value && !manageableCompanies.value.length) {
|
||||
installDialogLoading.value = true
|
||||
@@ -73,6 +78,7 @@ async function openInstallDialog(a: AppItem): Promise<void> {
|
||||
const r = await appApi.manageCompanies()
|
||||
manageableCompanies.value = r.Companies || []
|
||||
manageScope.value = r.Scope || ''
|
||||
tenantRoles.value = r.Roles || []
|
||||
} catch { /* 拦截器已提示 */ } finally {
|
||||
installDialogLoading.value = false
|
||||
}
|
||||
@@ -86,11 +92,14 @@ async function onConfirmInstall(): Promise<void> {
|
||||
installDialogLoading.value = true
|
||||
try {
|
||||
const companyUUIDs = installScope.value === 'company' ? selectedCompanies.value : []
|
||||
await appApi.install(a.AppUUID, companyUUIDs)
|
||||
await appApi.install(a.AppUUID, companyUUIDs, selectedRoles.value)
|
||||
const scopeText = installScope.value === 'company'
|
||||
? `已为 ${selectedCompanies.value.length} 家公司安装`
|
||||
: '已全租户安装(全员可用)'
|
||||
ElMessage.success(`「${a.AppName}」${scopeText}`)
|
||||
const ramText = selectedRoles.value.length
|
||||
? `,RAM 授权 ${selectedRoles.value.length} 个角色可见`
|
||||
: ''
|
||||
ElMessage.success(`「${a.AppName}」${scopeText}${ramText}`)
|
||||
installDialogVisible.value = false
|
||||
await loadMarket()
|
||||
} catch { /* 拦截器已提示 */ } finally {
|
||||
@@ -380,6 +389,29 @@ onMounted(loadMarket)
|
||||
<p v-else-if="manageScope === 'tenant'" class="gs-scope-tip">您可管理本租户下全部公司。</p>
|
||||
<p v-else-if="manageScope === 'all'" class="gs-scope-tip">您是跨租户管理员,可管理全部公司。</p>
|
||||
</template>
|
||||
|
||||
<!-- RAM 角色粒度授权(可选):勾选角色 → 仅这些角色可见该应用;不选=全员可见 -->
|
||||
<div class="gs-role-block">
|
||||
<div class="gs-role-title">RAM 角色授权(可选)</div>
|
||||
<el-select
|
||||
v-model="selectedRoles"
|
||||
multiple
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
filterable
|
||||
clearable
|
||||
placeholder="不选=安装范围内全员可见"
|
||||
class="gs-role-select"
|
||||
>
|
||||
<el-option
|
||||
v-for="r in tenantRoles"
|
||||
:key="r.RoleUUID"
|
||||
:label="r.RoleName"
|
||||
:value="r.RoleUUID"
|
||||
/>
|
||||
</el-select>
|
||||
<p class="gs-role-tip">勾选后,仅被授权角色的员工在菜单中可见该应用;其他角色不可见。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
@@ -596,6 +628,26 @@ onMounted(loadMarket)
|
||||
color: var(--el-text-color-secondary);
|
||||
margin: 10px 0 0;
|
||||
}
|
||||
/* RAM 角色授权区 */
|
||||
.gs-role-block {
|
||||
margin-top: 16px;
|
||||
padding-top: 14px;
|
||||
border-top: 1px solid var(--el-border-color-lighter);
|
||||
}
|
||||
.gs-role-title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.gs-role-select {
|
||||
width: 100%;
|
||||
}
|
||||
.gs-role-tip {
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
margin: 8px 0 0;
|
||||
}
|
||||
/* 管理弹窗 */
|
||||
.gm-tenant-row {
|
||||
display: flex;
|
||||
|
||||
Reference in new issue
Block a user