@liujitcn/kratos-admin-system 0.0.49 → 0.0.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -8
- package/dist/package/declarations/src/api/system/admin/v1/base_i18n_custom.d.ts +18 -0
- package/dist/package/declarations/src/api/system/admin/v1/base_tenant.d.ts +2 -2
- package/dist/package/declarations/src/api/system/admin/v1/base_tenant_project.d.ts +23 -0
- package/dist/package/declarations/src/api/system/admin/v1/base_tenant_project_grant.d.ts +16 -0
- package/dist/package/declarations/src/components/tenant-project/ProjectGrantDialog.vue.d.ts +8 -0
- package/dist/package/declarations/src/components/tenant-project/TenantProjectManager.vue.d.ts +29 -0
- package/dist/package/declarations/src/components/tenant-project/TenantProjectSelect.vue.d.ts +31 -0
- package/dist/package/declarations/src/components/tenant-project/TenantProjectText.vue.d.ts +19 -0
- package/dist/package/declarations/src/components/tenant-project/tenant-project-manager-data.d.ts +14 -0
- package/dist/package/declarations/src/components/tenant-project/tenant-project-manager.d.ts +40 -0
- package/dist/package/declarations/src/index.d.ts +2 -0
- package/dist/package/declarations/src/locales/generated.d.ts +172 -0
- package/dist/package/declarations/src/rpc/base/v1/config.d.ts +11 -0
- package/dist/package/declarations/src/rpc/system/admin/v1/base_i18n_custom.d.ts +105 -0
- package/dist/package/declarations/src/rpc/system/admin/v1/base_tenant.d.ts +10 -1
- package/dist/package/declarations/src/rpc/system/admin/v1/base_tenant_project.d.ts +141 -0
- package/dist/package/declarations/src/rpc/system/admin/v1/base_tenant_project_grant.d.ts +105 -0
- package/dist/package/declarations/src/views/ai/chat/components/SessionPanel.vue.d.ts +2 -2
- package/dist/package/declarations/src/views/base/i18n-custom/index.vue.d.ts +3 -0
- package/dist/package/declarations/src/views/base/project-grant/index.vue.d.ts +3 -0
- package/dist/package/declarations/src/views/base/tenant-project/index.vue.d.ts +3 -0
- package/dist/package/src/api/system/admin/v1/base_i18n_custom.ts +72 -0
- package/dist/package/src/api/system/admin/v1/base_tenant.ts +3 -2
- package/dist/package/src/api/system/admin/v1/base_tenant_project.ts +94 -0
- package/dist/package/src/api/system/admin/v1/base_tenant_project_grant.ts +63 -0
- package/dist/package/src/components/tenant-project/ProjectGrantDialog.vue +108 -0
- package/dist/package/src/components/tenant-project/TenantProjectManager.vue +452 -0
- package/dist/package/src/components/tenant-project/TenantProjectSelect.vue +83 -0
- package/dist/package/src/components/tenant-project/TenantProjectText.vue +37 -0
- package/dist/package/src/components/tenant-project/tenant-project-manager-data.ts +26 -0
- package/dist/package/src/components/tenant-project/tenant-project-manager.ts +48 -0
- package/dist/package/src/index.ts +12 -0
- package/dist/package/src/locales/README.md +1 -1
- package/dist/package/src/locales/en-US.json +45 -2
- package/dist/package/src/locales/ja-JP.json +45 -2
- package/dist/package/src/locales/zh-CN.json +45 -2
- package/dist/package/src/locales/zh-TW.json +45 -2
- package/dist/package/src/module.ts +3 -3
- package/dist/package/src/rpc/base/v1/config.ts +12 -0
- package/dist/package/src/rpc/system/admin/v1/base_i18n_custom.ts +126 -0
- package/dist/package/src/rpc/system/admin/v1/base_tenant.ts +11 -1
- package/dist/package/src/rpc/system/admin/v1/base_tenant_project.ts +166 -0
- package/dist/package/src/rpc/system/admin/v1/base_tenant_project_grant.ts +128 -0
- package/dist/package/src/views/ai/chat/components/XSender.vue +4 -3
- package/dist/package/src/views/base/api-log/index.vue +3 -3
- package/dist/package/src/views/base/config/index.vue +3 -3
- package/dist/package/src/views/base/data-access-log/index.vue +3 -3
- package/dist/package/src/views/base/dept/index.vue +10 -45
- package/dist/package/src/views/base/dict/index.vue +3 -3
- package/dist/package/src/views/base/dict/item.vue +3 -3
- package/dist/package/src/views/base/file/index.vue +12 -3
- package/dist/package/src/views/base/i18n-custom/index.vue +321 -0
- package/dist/package/src/views/base/job/index.vue +3 -3
- package/dist/package/src/views/base/login-log/index.vue +13 -4
- package/dist/package/src/views/base/login-policy/index.vue +97 -34
- package/dist/package/src/views/base/menu/index.vue +3 -3
- package/dist/package/src/views/base/message/index.vue +9 -32
- package/dist/package/src/views/base/message-category/index.vue +2 -4
- package/dist/package/src/views/base/oauth-client/index.vue +8 -42
- package/dist/package/src/views/base/online-session/index.vue +8 -27
- package/dist/package/src/views/base/operation-log/index.vue +3 -3
- package/dist/package/src/views/base/permission-log/index.vue +3 -3
- package/dist/package/src/views/base/policy-evaluation-log/index.vue +3 -3
- package/dist/package/src/views/base/post/index.vue +9 -42
- package/dist/package/src/views/base/project-grant/index.vue +336 -0
- package/dist/package/src/views/base/role/index.vue +13 -47
- package/dist/package/src/views/base/tenant/index.vue +163 -19
- package/dist/package/src/views/base/tenant-project/index.vue +12 -0
- package/dist/package/src/views/base/user/index.vue +30 -51
- package/dist/package/src/views/profile/components/login-log.vue +15 -2
- package/dist/package/src/views/profile/components/password.vue +1 -1
- package/dist/package/src/views/profile/components/security.vue +2 -2
- package/dist/package/src/views/tool/code-gen/components/CodeGenLocaleEditor.vue +2 -2
- package/dist/package/src/views/tool/code-gen/config.ts +2 -1
- package/package.json +2 -2
- /package/dist/package/declarations/src/components/{ChangePasswordForm.vue.d.ts → account/ChangePasswordForm.vue.d.ts} +0 -0
- /package/dist/package/declarations/src/components/{ForcedPasswordDialog.vue.d.ts → account/ForcedPasswordDialog.vue.d.ts} +0 -0
- /package/dist/package/declarations/src/components/{Ai.vue.d.ts → ai/Ai.vue.d.ts} +0 -0
- /package/dist/package/declarations/src/components/{DynamicI18nCell.vue.d.ts → i18n/DynamicI18nCell.vue.d.ts} +0 -0
- /package/dist/package/declarations/src/components/{DynamicI18nEditor.vue.d.ts → i18n/DynamicI18nEditor.vue.d.ts} +0 -0
- /package/dist/package/declarations/src/components/{dynamicI18n.d.ts → i18n/dynamicI18n.d.ts} +0 -0
- /package/dist/package/declarations/src/components/{LogTable.vue.d.ts → log/LogTable.vue.d.ts} +0 -0
- /package/dist/package/declarations/src/components/{log.d.ts → log/log.d.ts} +0 -0
- /package/dist/package/declarations/src/components/{Notification.vue.d.ts → notification/Notification.vue.d.ts} +0 -0
- /package/dist/package/src/components/{ChangePasswordForm.vue → account/ChangePasswordForm.vue} +0 -0
- /package/dist/package/src/components/{ForcedPasswordDialog.vue → account/ForcedPasswordDialog.vue} +0 -0
- /package/dist/package/src/components/{Ai.vue → ai/Ai.vue} +0 -0
- /package/dist/package/src/components/{DynamicI18nCell.vue → i18n/DynamicI18nCell.vue} +0 -0
- /package/dist/package/src/components/{DynamicI18nEditor.vue → i18n/DynamicI18nEditor.vue} +0 -0
- /package/dist/package/src/components/{dynamicI18n.ts → i18n/dynamicI18n.ts} +0 -0
- /package/dist/package/src/components/{LogTable.vue → log/LogTable.vue} +0 -0
- /package/dist/package/src/components/{log.ts → log/log.ts} +0 -0
- /package/dist/package/src/components/{Notification.vue → notification/Notification.vue} +0 -0
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="table-box">
|
|
3
|
+
<ProTable
|
|
4
|
+
ref="proTable"
|
|
5
|
+
:key="isDefaultTenant ? 'default-tenant' : 'current-tenant'"
|
|
6
|
+
row-key="grant_key"
|
|
7
|
+
:columns="columns"
|
|
8
|
+
:header-actions="headerActions"
|
|
9
|
+
:request-api="requestProjectGrantTable"
|
|
10
|
+
/>
|
|
11
|
+
|
|
12
|
+
<FormDialog
|
|
13
|
+
v-model="dialog.visible"
|
|
14
|
+
ref="formDialogRef"
|
|
15
|
+
:title="t(dialog.titleKey, { resource: t('system.base.tenant_project_grant.title') })"
|
|
16
|
+
width="640px"
|
|
17
|
+
:model="formData"
|
|
18
|
+
:fields="formFields"
|
|
19
|
+
:rules="rules"
|
|
20
|
+
:confirm-loading="loading"
|
|
21
|
+
@confirm="handleSubmit"
|
|
22
|
+
@close="handleCloseDialog"
|
|
23
|
+
/>
|
|
24
|
+
</div>
|
|
25
|
+
</template>
|
|
26
|
+
|
|
27
|
+
<script setup lang="ts">
|
|
28
|
+
import { computed, reactive, ref } from "vue";
|
|
29
|
+
import { ElMessage, ElMessageBox } from "element-plus";
|
|
30
|
+
import { CirclePlus, Delete, EditPen } from "@element-plus/icons-vue";
|
|
31
|
+
import type { ColumnProps, HeaderActionProps, ProTableInstance } from "@liujitcn/kratos-admin-core/components/ProTable/interface";
|
|
32
|
+
import ProTable from "@liujitcn/kratos-admin-core/components/ProTable";
|
|
33
|
+
import FormDialog from "@liujitcn/kratos-admin-core/components/Dialog/FormDialog.vue";
|
|
34
|
+
import type { ProFormField, ProFormOption } from "@liujitcn/kratos-admin-core/components/ProForm/interface";
|
|
35
|
+
import { useAuthButtons } from "@liujitcn/kratos-admin-core/auth";
|
|
36
|
+
import { buildPageRequest } from "@liujitcn/kratos-admin-core/table";
|
|
37
|
+
import { useTenantScope } from "@liujitcn/kratos-admin-core/tenant";
|
|
38
|
+
import { t } from "@liujitcn/kratos-admin-core";
|
|
39
|
+
import { defBaseDeptService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_dept";
|
|
40
|
+
import { defBasePostService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_post";
|
|
41
|
+
import { defBaseRoleService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_role";
|
|
42
|
+
import { defBaseTenantProjectService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_tenant_project";
|
|
43
|
+
import { defBaseTenantProjectGrantService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_tenant_project_grant";
|
|
44
|
+
import { defBaseUserService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_user";
|
|
45
|
+
import type { SelectOptionResponse_Option } from "@liujitcn/kratos-admin-system/rpc/common/v1/common";
|
|
46
|
+
import {
|
|
47
|
+
BaseTenantProjectGrantSubjectType,
|
|
48
|
+
type BaseTenantProjectGrant,
|
|
49
|
+
type PageBaseTenantProjectGrantRequest
|
|
50
|
+
} from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_tenant_project_grant";
|
|
51
|
+
|
|
52
|
+
defineOptions({
|
|
53
|
+
name: "BaseTenantProjectGrant",
|
|
54
|
+
inheritAttrs: false
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
type ProjectGrantFormState = {
|
|
58
|
+
tenant_id?: number;
|
|
59
|
+
subject_type: BaseTenantProjectGrantSubjectType;
|
|
60
|
+
subject_id?: number;
|
|
61
|
+
project_id: number[];
|
|
62
|
+
all: boolean;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const { BUTTONS } = useAuthButtons();
|
|
66
|
+
const proTable = ref<ProTableInstance>();
|
|
67
|
+
const formDialogRef = ref<InstanceType<typeof FormDialog>>();
|
|
68
|
+
const { isDefaultTenant, tenantOptions, tenantColumns, tenantFormField, toRequestTenantId, loadTenantOptions } = useTenantScope();
|
|
69
|
+
const projectOptions = ref<SelectOptionResponse_Option[]>([]);
|
|
70
|
+
const subjectOptions = ref<ProFormOption[]>([]);
|
|
71
|
+
const loading = ref(false);
|
|
72
|
+
const dialog = reactive({
|
|
73
|
+
visible: false,
|
|
74
|
+
editing: false,
|
|
75
|
+
titleKey: "common.action.create_resource"
|
|
76
|
+
});
|
|
77
|
+
const DEFAULT_SUBJECT_TYPE = BaseTenantProjectGrantSubjectType.BASE_TENANT_PROJECT_GRANT_SUBJECT_TYPE_POST;
|
|
78
|
+
const formData = reactive<ProjectGrantFormState>({
|
|
79
|
+
tenant_id: undefined,
|
|
80
|
+
subject_type: DEFAULT_SUBJECT_TYPE,
|
|
81
|
+
subject_id: undefined,
|
|
82
|
+
project_id: [],
|
|
83
|
+
all: false
|
|
84
|
+
});
|
|
85
|
+
const subjectTypeOptions = computed<ProFormOption[]>(() => [
|
|
86
|
+
{ label: t("system.base.tenant_project_grant.subject_type.post"), value: BaseTenantProjectGrantSubjectType.BASE_TENANT_PROJECT_GRANT_SUBJECT_TYPE_POST },
|
|
87
|
+
{ label: t("system.base.tenant_project_grant.subject_type.role"), value: BaseTenantProjectGrantSubjectType.BASE_TENANT_PROJECT_GRANT_SUBJECT_TYPE_ROLE },
|
|
88
|
+
{ label: t("system.base.tenant_project_grant.subject_type.dept"), value: BaseTenantProjectGrantSubjectType.BASE_TENANT_PROJECT_GRANT_SUBJECT_TYPE_DEPT },
|
|
89
|
+
{ label: t("system.base.tenant_project_grant.subject_type.user"), value: BaseTenantProjectGrantSubjectType.BASE_TENANT_PROJECT_GRANT_SUBJECT_TYPE_USER }
|
|
90
|
+
]);
|
|
91
|
+
const subjectTypeLabel = computed(() => new Map(subjectTypeOptions.value.map(item => [item.value, item.label])));
|
|
92
|
+
const rules = computed(() => ({
|
|
93
|
+
tenant_id: [{ required: true, message: t("common.validation.required_select", { field: t("common.field.tenant") }), trigger: "change" }],
|
|
94
|
+
subject_type: [{ required: true, type: "number", min: 1, message: t("common.validation.required_select", { field: t("system.base.tenant_project_grant.field.subject_type") }), trigger: "change" }],
|
|
95
|
+
subject_id: [{ required: true, type: "number", min: 1, message: t("common.validation.required_select", { field: t("system.base.tenant_project_grant.field.subject") }), trigger: "change" }]
|
|
96
|
+
}));
|
|
97
|
+
const formFields = computed<ProFormField[]>(() => [
|
|
98
|
+
tenantFormField({
|
|
99
|
+
label: t("common.field.tenant"),
|
|
100
|
+
props: { disabled: dialog.editing || loading.value, onChange: handleTenantChange }
|
|
101
|
+
}),
|
|
102
|
+
{
|
|
103
|
+
prop: "subject_type",
|
|
104
|
+
label: t("system.base.tenant_project_grant.field.subject_type"),
|
|
105
|
+
component: "select",
|
|
106
|
+
options: subjectTypeOptions.value,
|
|
107
|
+
props: { filterable: false, disabled: dialog.editing || loading.value, onChange: handleSubjectTypeChange }
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
prop: "subject_id",
|
|
111
|
+
label: t("system.base.tenant_project_grant.field.subject"),
|
|
112
|
+
component: formData.subject_type === BaseTenantProjectGrantSubjectType.BASE_TENANT_PROJECT_GRANT_SUBJECT_TYPE_DEPT ? "tree-select" : "select",
|
|
113
|
+
options: subjectOptions.value,
|
|
114
|
+
props:
|
|
115
|
+
formData.subject_type === BaseTenantProjectGrantSubjectType.BASE_TENANT_PROJECT_GRANT_SUBJECT_TYPE_DEPT
|
|
116
|
+
? { filterable: true, checkStrictly: true, renderAfterExpand: false, style: { width: "100%" }, disabled: dialog.editing || !formData.tenant_id || loading.value }
|
|
117
|
+
: { filterable: true, clearable: true, disabled: dialog.editing || !formData.tenant_id || formData.subject_type === 0 || loading.value }
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
prop: "all",
|
|
121
|
+
label: t("system.base.tenant_project_grant.field.scope"),
|
|
122
|
+
labelTooltip: t("system.base.tenant_project_grant.tooltip.scope"),
|
|
123
|
+
component: "switch",
|
|
124
|
+
checkboxLabel: t("system.base.tenant_project_grant.all_projects"),
|
|
125
|
+
props: { disabled: !formData.tenant_id || !formData.subject_id || loading.value }
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
prop: "project_id",
|
|
129
|
+
label: t("system.base.tenant_project_grant.field.projects"),
|
|
130
|
+
component: "select",
|
|
131
|
+
options: projectOptions.value,
|
|
132
|
+
visible: () => !formData.all,
|
|
133
|
+
props: { multiple: true, filterable: true, clearable: true, disabled: !formData.tenant_id || loading.value }
|
|
134
|
+
}
|
|
135
|
+
]);
|
|
136
|
+
const columns = computed<ColumnProps[]>(() => [
|
|
137
|
+
...tenantColumns({ label: t("common.field.tenant"), minWidth: 150, order: 1 }),
|
|
138
|
+
{
|
|
139
|
+
prop: "subject_type",
|
|
140
|
+
label: t("system.base.tenant_project_grant.field.subject_type"),
|
|
141
|
+
minWidth: 110,
|
|
142
|
+
search: { el: "select", enum: subjectTypeOptions.value },
|
|
143
|
+
render: scope => subjectTypeLabel.value.get((scope.row as BaseTenantProjectGrant).subject_type) ?? String((scope.row as BaseTenantProjectGrant).subject_type)
|
|
144
|
+
},
|
|
145
|
+
{ prop: "subject_name", label: t("system.base.tenant_project_grant.field.subject"), minWidth: 160, showOverflowTooltip: true },
|
|
146
|
+
{
|
|
147
|
+
prop: "project_names",
|
|
148
|
+
label: t("system.base.tenant_project_grant.field.projects"),
|
|
149
|
+
minWidth: 220,
|
|
150
|
+
showOverflowTooltip: true,
|
|
151
|
+
render: scope => {
|
|
152
|
+
const row = scope.row as BaseTenantProjectGrant;
|
|
153
|
+
return row.project_id.length === 1 && row.project_id[0] === 0
|
|
154
|
+
? t("system.base.tenant_project_grant.all_projects")
|
|
155
|
+
: row.project_names.join(", ") || row.project_id.join(", ") || t("common.value.none");
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
prop: "operation",
|
|
160
|
+
label: t("common.field.operation"),
|
|
161
|
+
fixed: "right",
|
|
162
|
+
cellType: "actions",
|
|
163
|
+
actions: [
|
|
164
|
+
{
|
|
165
|
+
label: t("common.action.edit"),
|
|
166
|
+
type: "primary",
|
|
167
|
+
link: true,
|
|
168
|
+
icon: EditPen,
|
|
169
|
+
hidden: () => !BUTTONS.value["base:tenant:project:grant:update"],
|
|
170
|
+
onClick: scope => handleOpenDialog(scope.row as BaseTenantProjectGrant)
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
label: t("common.action.delete"),
|
|
174
|
+
type: "danger",
|
|
175
|
+
link: true,
|
|
176
|
+
icon: Delete,
|
|
177
|
+
hidden: () => !BUTTONS.value["base:tenant:project:grant:delete"],
|
|
178
|
+
onClick: scope => handleDelete(scope.row as BaseTenantProjectGrant)
|
|
179
|
+
}
|
|
180
|
+
]
|
|
181
|
+
}
|
|
182
|
+
]);
|
|
183
|
+
const headerActions = computed<HeaderActionProps[]>(() => [
|
|
184
|
+
{
|
|
185
|
+
label: t("common.action.create"),
|
|
186
|
+
type: "success",
|
|
187
|
+
icon: CirclePlus,
|
|
188
|
+
hidden: () => !BUTTONS.value["base:tenant:project:grant:create"],
|
|
189
|
+
onClick: () => handleOpenDialog()
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
label: t("common.action.delete"),
|
|
193
|
+
type: "danger",
|
|
194
|
+
icon: Delete,
|
|
195
|
+
hidden: () => !BUTTONS.value["base:tenant:project:grant:delete"],
|
|
196
|
+
disabled: scope => !scope.selectedList.length,
|
|
197
|
+
onClick: scope => handleDelete(scope.selectedList as BaseTenantProjectGrant[])
|
|
198
|
+
}
|
|
199
|
+
]);
|
|
200
|
+
|
|
201
|
+
/** 请求项目授权分页列表。 */
|
|
202
|
+
async function requestProjectGrantTable(params: Record<string, unknown>) {
|
|
203
|
+
const page = buildPageRequest(params) as unknown as PageBaseTenantProjectGrantRequest;
|
|
204
|
+
const tenantId = toRequestTenantId(params.tenant_id);
|
|
205
|
+
const data = await defBaseTenantProjectGrantService.PageBaseTenantProjectGrant({ ...page, tenant_id: tenantId });
|
|
206
|
+
return { data: { list: data.grants ?? [], total: data.total } };
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/** 打开项目授权新增或编辑弹窗。 */
|
|
210
|
+
async function handleOpenDialog(row?: BaseTenantProjectGrant) {
|
|
211
|
+
resetForm();
|
|
212
|
+
dialog.editing = Boolean(row);
|
|
213
|
+
dialog.titleKey = row ? "common.action.edit_resource" : "common.action.create_resource";
|
|
214
|
+
loading.value = true;
|
|
215
|
+
try {
|
|
216
|
+
await loadTenantOptions(true);
|
|
217
|
+
if (!isDefaultTenant.value) formData.tenant_id = Number(tenantOptions.value[0]?.value) || undefined;
|
|
218
|
+
if (row) {
|
|
219
|
+
formData.tenant_id = row.tenant_id;
|
|
220
|
+
formData.subject_type = row.subject_type;
|
|
221
|
+
formData.subject_id = row.subject_id;
|
|
222
|
+
formData.all = row.project_id.length === 1 && row.project_id[0] === 0;
|
|
223
|
+
formData.project_id = formData.all ? [] : [...row.project_id];
|
|
224
|
+
}
|
|
225
|
+
await Promise.all([loadProjectOptions(), loadSubjectOptions()]);
|
|
226
|
+
dialog.visible = true;
|
|
227
|
+
} finally {
|
|
228
|
+
loading.value = false;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/** 加载目标租户项目选项。 */
|
|
233
|
+
async function loadProjectOptions() {
|
|
234
|
+
projectOptions.value = formData.tenant_id ? (await defBaseTenantProjectService.OptionBaseTenantProject({ tenant_id: formData.tenant_id })).list ?? [] : [];
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** 根据授权类型加载岗位、角色、部门或用户主体选项。 */
|
|
238
|
+
async function loadSubjectOptions() {
|
|
239
|
+
subjectOptions.value = [];
|
|
240
|
+
if (!formData.tenant_id || formData.subject_type === BaseTenantProjectGrantSubjectType.BASE_TENANT_PROJECT_GRANT_SUBJECT_TYPE_UNSPECIFIED) return;
|
|
241
|
+
switch (formData.subject_type) {
|
|
242
|
+
case BaseTenantProjectGrantSubjectType.BASE_TENANT_PROJECT_GRANT_SUBJECT_TYPE_POST:
|
|
243
|
+
subjectOptions.value = (await defBasePostService.OptionBasePost({ tenant_id: formData.tenant_id })).list ?? [];
|
|
244
|
+
return;
|
|
245
|
+
case BaseTenantProjectGrantSubjectType.BASE_TENANT_PROJECT_GRANT_SUBJECT_TYPE_ROLE:
|
|
246
|
+
subjectOptions.value = (await defBaseRoleService.OptionBaseRole({ tenant_id: formData.tenant_id })).list ?? [];
|
|
247
|
+
return;
|
|
248
|
+
case BaseTenantProjectGrantSubjectType.BASE_TENANT_PROJECT_GRANT_SUBJECT_TYPE_DEPT:
|
|
249
|
+
subjectOptions.value = ((await defBaseDeptService.OptionBaseDept({ tenant_id: formData.tenant_id })).list ?? []) as unknown as ProFormOption[];
|
|
250
|
+
return;
|
|
251
|
+
case BaseTenantProjectGrantSubjectType.BASE_TENANT_PROJECT_GRANT_SUBJECT_TYPE_USER:
|
|
252
|
+
subjectOptions.value = (await defBaseUserService.OptionBaseUser({ keyword: "", tenant_id: formData.tenant_id })).list ?? [];
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** 切换目标租户时重置主体和项目选择。 */
|
|
257
|
+
async function handleTenantChange(value: unknown) {
|
|
258
|
+
if (loading.value) return;
|
|
259
|
+
formData.tenant_id = Number(value) || undefined;
|
|
260
|
+
formData.subject_type = DEFAULT_SUBJECT_TYPE;
|
|
261
|
+
formData.subject_id = undefined;
|
|
262
|
+
formData.project_id = [];
|
|
263
|
+
formData.all = false;
|
|
264
|
+
await Promise.all([loadProjectOptions(), loadSubjectOptions()]);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/** 切换授权类型时重新加载对应主体数据。 */
|
|
268
|
+
async function handleSubjectTypeChange(value: unknown) {
|
|
269
|
+
if (loading.value) return;
|
|
270
|
+
formData.subject_type = Number(value) as BaseTenantProjectGrantSubjectType;
|
|
271
|
+
formData.subject_id = undefined;
|
|
272
|
+
await loadSubjectOptions();
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/** 提交项目授权新增或编辑。 */
|
|
276
|
+
function handleSubmit() {
|
|
277
|
+
formDialogRef.value?.validate()?.then(valid => {
|
|
278
|
+
if (!valid || !formData.tenant_id || !formData.subject_id || formData.subject_type === 0) return;
|
|
279
|
+
const grant: BaseTenantProjectGrant = {
|
|
280
|
+
tenant_id: formData.tenant_id,
|
|
281
|
+
subject_type: formData.subject_type,
|
|
282
|
+
subject_id: formData.subject_id,
|
|
283
|
+
project_id: formData.all ? [0] : [...formData.project_id],
|
|
284
|
+
tenant_name: "",
|
|
285
|
+
subject_name: "",
|
|
286
|
+
subject_code: "",
|
|
287
|
+
project_names: [],
|
|
288
|
+
grant_key: ""
|
|
289
|
+
};
|
|
290
|
+
loading.value = true;
|
|
291
|
+
const request = dialog.editing
|
|
292
|
+
? defBaseTenantProjectGrantService.UpdateBaseTenantProjectGrant({ base_tenant_project_grant: grant })
|
|
293
|
+
: defBaseTenantProjectGrantService.CreateBaseTenantProjectGrant({ base_tenant_project_grant: grant });
|
|
294
|
+
request.then(() => {
|
|
295
|
+
ElMessage.success(t(dialog.editing ? "common.message.update_success" : "common.message.create_success", { resource: t("system.base.tenant_project_grant.title") }));
|
|
296
|
+
handleCloseDialog();
|
|
297
|
+
proTable.value?.getTableList();
|
|
298
|
+
}).finally(() => { loading.value = false; });
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** 关闭并重置项目授权弹窗。 */
|
|
303
|
+
function handleCloseDialog() {
|
|
304
|
+
dialog.visible = false;
|
|
305
|
+
dialog.editing = false;
|
|
306
|
+
resetForm();
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/** 重置项目授权表单。 */
|
|
310
|
+
function resetForm() {
|
|
311
|
+
formDialogRef.value?.resetFields();
|
|
312
|
+
formDialogRef.value?.clearValidate();
|
|
313
|
+
formData.tenant_id = undefined;
|
|
314
|
+
formData.subject_type = DEFAULT_SUBJECT_TYPE;
|
|
315
|
+
formData.subject_id = undefined;
|
|
316
|
+
formData.project_id = [];
|
|
317
|
+
formData.all = false;
|
|
318
|
+
projectOptions.value = [];
|
|
319
|
+
subjectOptions.value = [];
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/** 删除项目授权,支持单条和批量记录。 */
|
|
323
|
+
function handleDelete(selected: BaseTenantProjectGrant | BaseTenantProjectGrant[]) {
|
|
324
|
+
const rows = Array.isArray(selected) ? selected : [selected];
|
|
325
|
+
if (!rows.length) return;
|
|
326
|
+
const label = rows.length === 1 ? rows[0].subject_name || rows[0].subject_code || rows[0].grant_key : t("common.dialog.delete_batch", { count: rows.length, unit: "", resource: t("system.base.tenant_project_grant.title") });
|
|
327
|
+
const message = rows.length === 1
|
|
328
|
+
? `${t("common.dialog.delete_single", { resource: t("system.base.tenant_project_grant.title") })}\n${t("common.dialog.resource_field", { field: t("system.base.tenant_project_grant.field.subject"), value: label })}`
|
|
329
|
+
: label;
|
|
330
|
+
ElMessageBox.confirm(message, t("common.title.warning"), { confirmButtonText: t("common.action.confirm"), cancelButtonText: t("common.action.cancel"), type: "warning" }).then(async () => {
|
|
331
|
+
await Promise.all(rows.map(row => defBaseTenantProjectGrantService.DeleteBaseTenantProjectGrant({ tenant_id: row.tenant_id, subject_type: row.subject_type, subject_id: row.subject_id })));
|
|
332
|
+
ElMessage.success(t("common.message.delete_success", { resource: t("system.base.tenant_project_grant.title") }));
|
|
333
|
+
proTable.value?.getTableList();
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
</script>
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
</template>
|
|
85
85
|
|
|
86
86
|
<script setup lang="ts">
|
|
87
|
-
import { computed, nextTick, reactive, ref, watch } from "vue";
|
|
87
|
+
import { computed, nextTick, onMounted, reactive, ref, watch } from "vue";
|
|
88
88
|
import { ElMessage, ElMessageBox, ElTree } from "element-plus";
|
|
89
89
|
import type { CheckboxValueType } from "element-plus";
|
|
90
90
|
import { CirclePlus, Delete, EditPen, Position, QuestionFilled, Search, Switch } from "@element-plus/icons-vue";
|
|
@@ -96,12 +96,10 @@ import { useAuthButtons } from "@liujitcn/kratos-admin-core/auth";
|
|
|
96
96
|
import { defBaseRoleService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_role";
|
|
97
97
|
import type { BaseRole, BaseRoleForm, PageBaseRoleRequest } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_role";
|
|
98
98
|
import { defBaseMenuService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_menu";
|
|
99
|
-
import {
|
|
100
|
-
import type { SelectOptionResponse_Option, TreeOptionResponse_Option } from "@liujitcn/kratos-admin-system/rpc/common/v1/common";
|
|
99
|
+
import type { TreeOptionResponse_Option } from "@liujitcn/kratos-admin-system/rpc/common/v1/common";
|
|
101
100
|
import { Status } from "@liujitcn/kratos-admin-system/rpc/common/v1/enum";
|
|
102
101
|
import { buildPageRequest, normalizeSelectedIds } from "@liujitcn/kratos-admin-core/table";
|
|
103
|
-
import {
|
|
104
|
-
import { DEFAULT_TENANT_CODE, requestTenantOptions } from "@liujitcn/kratos-admin-core/tenant";
|
|
102
|
+
import { useTenantScope } from "@liujitcn/kratos-admin-core/tenant";
|
|
105
103
|
import { t } from "@liujitcn/kratos-admin-core";
|
|
106
104
|
|
|
107
105
|
defineOptions({
|
|
@@ -122,7 +120,6 @@ type BaseRoleFormState = Omit<BaseRoleForm, "tenant_id"> & {
|
|
|
122
120
|
};
|
|
123
121
|
|
|
124
122
|
const { BUTTONS } = useAuthButtons();
|
|
125
|
-
const userStore = useUserStore();
|
|
126
123
|
const proTable = ref<ProTableInstance>();
|
|
127
124
|
const formDialogRef = ref<InstanceType<typeof FormDialog>>();
|
|
128
125
|
const permTreeRef = ref<InstanceType<typeof ElTree>>();
|
|
@@ -133,12 +130,12 @@ const dialog = reactive({
|
|
|
133
130
|
});
|
|
134
131
|
|
|
135
132
|
const menuPermOptions = ref<TreeOptionResponse_Option[]>([]);
|
|
136
|
-
const tenantOptions = ref<SelectOptionResponse_Option[]>([]);
|
|
137
133
|
const statusOptions = computed<ProFormOption[]>(() => [
|
|
138
134
|
{ label: t("common.status.enabled"), value: Status.STATUS_ENABLE },
|
|
139
135
|
{ label: t("common.status.disabled"), value: Status.STATUS_DISABLE }
|
|
140
136
|
]);
|
|
141
137
|
const protectedRoleCodes = new Set(["admin", "authuser", "user"]);
|
|
138
|
+
const undeletableRoleCodes = new Set(["super", "tenant", "admin", "authuser", "user"]);
|
|
142
139
|
|
|
143
140
|
const formData = reactive<BaseRoleFormState>({
|
|
144
141
|
/** 角色ID */
|
|
@@ -238,24 +235,14 @@ const permKeywords = ref("");
|
|
|
238
235
|
const isExpanded = ref(true);
|
|
239
236
|
const parentChildLinked = ref(true);
|
|
240
237
|
|
|
241
|
-
|
|
242
|
-
|
|
238
|
+
const { isDefaultTenant, tenantColumns, tenantFormField, toRequestTenantId, loadTenantOptions } = useTenantScope();
|
|
239
|
+
onMounted(() => {
|
|
240
|
+
if (isDefaultTenant.value) void loadTenantOptions();
|
|
241
|
+
});
|
|
243
242
|
|
|
244
243
|
/** 角色表单字段配置。 */
|
|
245
244
|
const formFields = computed<ProFormField[]>(() => [
|
|
246
|
-
{
|
|
247
|
-
prop: "tenant_id",
|
|
248
|
-
label: t("common.field.tenant"),
|
|
249
|
-
component: "select",
|
|
250
|
-
props: {
|
|
251
|
-
placeholder: t("common.placeholder.select"),
|
|
252
|
-
filterable: true,
|
|
253
|
-
disabled: Boolean(formData.id),
|
|
254
|
-
onChange: handleFormTenantChange
|
|
255
|
-
},
|
|
256
|
-
visible: () => isDefaultTenant.value,
|
|
257
|
-
options: tenantOptions.value
|
|
258
|
-
},
|
|
245
|
+
tenantFormField({ label: t("common.field.tenant"), disabledOnEdit: true, props: { onChange: handleFormTenantChange } }),
|
|
259
246
|
{
|
|
260
247
|
prop: "name",
|
|
261
248
|
label: t("system.base.role.field.name"),
|
|
@@ -302,19 +289,7 @@ const formFields = computed<ProFormField[]>(() => [
|
|
|
302
289
|
/** 角色表格列配置。 */
|
|
303
290
|
const columns = computed<ColumnProps[]>(() => [
|
|
304
291
|
{ type: "selection", width: 55, selectable: row => canDeleteRole(row as BaseRole) },
|
|
305
|
-
...(
|
|
306
|
-
? ([
|
|
307
|
-
{
|
|
308
|
-
prop: "tenant_id",
|
|
309
|
-
label: t("common.field.tenant"),
|
|
310
|
-
minWidth: 140,
|
|
311
|
-
align: "left",
|
|
312
|
-
showOverflowTooltip: true,
|
|
313
|
-
search: { el: "select", key: "tenant_id", props: { filterable: true }, order: 1 },
|
|
314
|
-
enum: requestTenantOptions
|
|
315
|
-
}
|
|
316
|
-
] satisfies ColumnProps[])
|
|
317
|
-
: []),
|
|
292
|
+
...tenantColumns({ label: t("common.field.tenant"), order: 1 }),
|
|
318
293
|
{ prop: "name", label: t("system.base.role.field.name"), minWidth: 140, search: { el: "input" } },
|
|
319
294
|
{ prop: "code", label: t("system.base.role.field.code"), minWidth: 160, search: { el: "input" } },
|
|
320
295
|
{
|
|
@@ -401,7 +376,7 @@ const headerActions = computed<HeaderActionProps[]>(() => [
|
|
|
401
376
|
async function requestBaseRoleTable(params: PageBaseRoleRequest) {
|
|
402
377
|
const data = await defBaseRoleService.PageBaseRole({
|
|
403
378
|
...buildPageRequest(params),
|
|
404
|
-
tenant_id:
|
|
379
|
+
tenant_id: toRequestTenantId(params.tenant_id)
|
|
405
380
|
});
|
|
406
381
|
return { data: { list: data.base_roles ?? [], total: data.total } };
|
|
407
382
|
}
|
|
@@ -413,15 +388,6 @@ function refreshTable() {
|
|
|
413
388
|
proTable.value?.getTableList();
|
|
414
389
|
}
|
|
415
390
|
|
|
416
|
-
/**
|
|
417
|
-
* 加载租户下拉选项。
|
|
418
|
-
*/
|
|
419
|
-
async function loadTenantOptions() {
|
|
420
|
-
if (!isDefaultTenant.value || tenantOptions.value.length) return;
|
|
421
|
-
const response = await defBaseTenantService.OptionBaseTenant({ keyword: "" });
|
|
422
|
-
tenantOptions.value = response.list ?? [];
|
|
423
|
-
}
|
|
424
|
-
|
|
425
391
|
/**
|
|
426
392
|
* 按目标角色加载可分配的菜单权限树数据。
|
|
427
393
|
*/
|
|
@@ -516,7 +482,7 @@ function canManageRole(row?: BaseRole) {
|
|
|
516
482
|
return Boolean(row?.code && !row.is_protected);
|
|
517
483
|
}
|
|
518
484
|
|
|
519
|
-
/**
|
|
485
|
+
/** 判断角色是否禁止切换状态。 */
|
|
520
486
|
function isRoleProtected(code?: string) {
|
|
521
487
|
return Boolean(code && protectedRoleCodes.has(code));
|
|
522
488
|
}
|
|
@@ -528,7 +494,7 @@ function canChangeRoleStatus(row?: BaseRole) {
|
|
|
528
494
|
|
|
529
495
|
/** 判断当前账号是否允许删除目标角色。 */
|
|
530
496
|
function canDeleteRole(row?: BaseRole) {
|
|
531
|
-
return canManageRole(row) && !
|
|
497
|
+
return canManageRole(row) && !undeletableRoleCodes.has(row?.code ?? "");
|
|
532
498
|
}
|
|
533
499
|
|
|
534
500
|
/**
|