chore: project permission

This commit is contained in:
xiaojunnuo
2026-02-26 00:12:59 +08:00
parent faf08f6513
commit 3a8b5de8f7
14 changed files with 119 additions and 30 deletions
@@ -1,12 +1,14 @@
import { usePermission } from "/@/plugin/permission"; import { usePermission } from "/@/plugin/permission";
import { merge as LodashMerge } from "lodash-es"; import { merge as LodashMerge } from "lodash-es";
import { useProjectStore } from "/@/store/project";
export type UseCrudPermissionExtraProps = { export type UseCrudPermissionExtraProps = {
hasActionPermission: (action: string) => boolean; hasActionPermission: (action: string) => boolean;
}; };
export type UseCrudPermissionExtra = (props: UseCrudPermissionExtraProps) => any; export type UseCrudPermissionExtra = (props: UseCrudPermissionExtraProps) => any;
export type UseCrudPermissionCompProps = { export type UseCrudPermissionCompProps = {
prefix: string; isProjectPermission?: boolean;
prefix?: string;
extra?: UseCrudPermissionExtra; extra?: UseCrudPermissionExtra;
[key: string]: any; [key: string]: any;
}; };
@@ -20,14 +22,31 @@ export type UseCrudPermissionProps = {
export function useCrudPermission({ permission }: UseCrudPermissionProps) { export function useCrudPermission({ permission }: UseCrudPermissionProps) {
const { hasPermissions } = usePermission(); const { hasPermissions } = usePermission();
const prefix = permission instanceof Object ? permission.prefix : permission;
//根据权限显示按钮 //根据权限显示按钮
function hasActionPermission(action: string) { let hasActionPermission = (action: string) => {
if (!prefix) { if (!prefix) {
return true; return true;
} }
return hasPermissions(prefix + ":" + action); return hasPermissions(prefix + ":" + action);
};
let per: UseCrudPermissionCompProps = permission as any;
if (per == null) {
per = { prefix: "" };
}
if (typeof per === "string") {
per = {
prefix: per || "",
};
}
let prefix = per.prefix || "";
const isProjectPermission = per.isProjectPermission || false;
if (isProjectPermission) {
const projectStore = useProjectStore();
prefix = "";
hasActionPermission = function (value: string) {
return projectStore.hasPermission(value as string);
};
} }
function buildCrudPermission(): any { function buildCrudPermission(): any {
@@ -36,25 +55,44 @@ export function useCrudPermission({ permission }: UseCrudPermissionProps) {
} }
let extra = {}; let extra = {};
if (permission instanceof Object) { if (per instanceof Object) {
extra = permission.extra; extra = per.extra;
if (permission.extra && permission.extra instanceof Function) { if (per.extra && per.extra instanceof Function) {
extra = permission.extra({ hasActionPermission }); extra = per.extra({ hasActionPermission });
} }
} }
let viewPermission = "view";
if (isProjectPermission) {
viewPermission = "read";
}
let addPermission = "add";
if (isProjectPermission) {
addPermission = "write";
}
let editPermission = "edit";
if (isProjectPermission) {
editPermission = "write";
}
let removePermission = "remove";
if (isProjectPermission) {
removePermission = "write";
}
return LodashMerge( return LodashMerge(
{ {
actionbar: { actionbar: {
buttons: { buttons: {
add: { show: hasActionPermission("add") }, add: { show: hasActionPermission(addPermission) },
}, },
}, },
rowHandle: { rowHandle: {
buttons: { buttons: {
edit: { show: hasActionPermission("edit") }, edit: { show: hasActionPermission(editPermission) },
remove: { show: hasActionPermission("remove") }, remove: { show: hasActionPermission(removePermission) },
view: { show: hasActionPermission("view") }, view: { show: hasActionPermission(viewPermission) },
}, },
}, },
}, },
@@ -98,6 +98,20 @@ export const useProjectStore = defineStore("app.project", () => {
return currentProject.value?.permission === "admin"; return currentProject.value?.permission === "admin";
}); });
function hasPermission(value: string) {
if (!isEnterprise.value) {
return true;
}
if (value === "read") {
return isRead.value;
} else if (value === "write") {
return isWrite.value;
} else if (value === "admin") {
return isAdmin.value;
}
return false;
}
function $reset() { function $reset() {
myProjects.value = []; myProjects.value = [];
currentProjectId.value = ""; currentProjectId.value = "";
@@ -118,5 +132,6 @@ export const useProjectStore = defineStore("app.project", () => {
reload, reload,
init, init,
$reset, $reset,
hasPermission,
}; };
}); });
@@ -22,7 +22,7 @@ export default defineComponent({
setup() { setup() {
const { t } = useI18n(); const { t } = useI18n();
const api = createAccessApi("user"); const api = createAccessApi("user");
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: { api } }); const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: { api, permission: { isProjectPermission: true } } });
// 页面打开后获取列表数据 // 页面打开后获取列表数据
onMounted(() => { onMounted(() => {
@@ -12,6 +12,7 @@ import { useI18n } from "/src/locales";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet { export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const router = useRouter(); const router = useRouter();
const { t } = useI18n(); const { t } = useI18n();
const { hasActionPermission } = context;
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => { const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetList(query); return await api.GetList(query);
}; };
@@ -96,6 +97,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
icon: "ion:add-circle-outline", icon: "ion:add-circle-outline",
}, },
import: { import: {
show: hasActionPermission("write"),
title: "从域名提供商导入域名", title: "从域名提供商导入域名",
type: "primary", type: "primary",
text: "从域名提供商导入", text: "从域名提供商导入",
@@ -111,6 +113,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
}, },
}, },
syncExpirationDate: { syncExpirationDate: {
show: hasActionPermission("write"),
title: "同步域名过期时间", title: "同步域名过期时间",
type: "primary", type: "primary",
icon: "ion:refresh-outline", icon: "ion:refresh-outline",
@@ -10,7 +10,7 @@
</template> </template>
<fs-crud ref="crudRef" v-bind="crudBinding"> <fs-crud ref="crudRef" v-bind="crudBinding">
<template #pagination-left> <template #pagination-left>
<a-tooltip :title="t('certd.batch_delete')"> <a-tooltip v-if="hasActionPermission('write')" :title="t('certd.batch_delete')">
<fs-button icon="DeleteOutlined" @click="handleBatchDelete"></fs-button> <fs-button icon="DeleteOutlined" @click="handleBatchDelete"></fs-button>
</a-tooltip> </a-tooltip>
</template> </template>
@@ -25,13 +25,22 @@ import createCrudOptions from "./crud";
import { message, Modal } from "ant-design-vue"; import { message, Modal } from "ant-design-vue";
import { DeleteBatch } from "./api"; import { DeleteBatch } from "./api";
import { useI18n } from "/src/locales"; import { useI18n } from "/src/locales";
import { useCrudPermission } from "/@/plugin/permission";
const { t } = useI18n(); const { t } = useI18n();
defineOptions({ defineOptions({
name: "DomainManager", name: "DomainManager",
}); });
const { crudBinding, crudRef, crudExpose, context } = useFs({ createCrudOptions }); const context: any = {
permission: {
isProjectPermission: true,
},
};
const { hasActionPermission } = useCrudPermission({ permission: context.permission });
context.hasActionPermission = hasActionPermission;
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context });
const selectedRowKeys = context.selectedRowKeys; const selectedRowKeys = context.selectedRowKeys;
const handleBatchDelete = () => { const handleBatchDelete = () => {
@@ -15,6 +15,7 @@ import GroupSelector from "../../basic/group/group-selector.vue";
import { createGroupDictRef } from "../../basic/group/api"; import { createGroupDictRef } from "../../basic/group/api";
import { useProjectStore } from "/@/store/project"; import { useProjectStore } from "/@/store/project";
import { useDicts } from "../../dicts"; import { useDicts } from "../../dicts";
import { useCrudPermission } from "/@/plugin/permission";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet { export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const { t } = useI18n(); const { t } = useI18n();
const api = siteInfoApi; const api = siteInfoApi;
@@ -109,6 +110,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
} }
const projectStore = useProjectStore(); const projectStore = useProjectStore();
const { hasActionPermission } = useCrudPermission({ permission: context.permission });
return { return {
id: "siteMonitorCrud", id: "siteMonitorCrud",
crudOptions: { crudOptions: {
@@ -231,7 +233,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
}, },
//导入按钮 //导入按钮
import: { import: {
show: true, show: hasActionPermission("write"),
text: t("monitor.bulkImport"), text: t("monitor.bulkImport"),
type: "primary", type: "primary",
async click() { async click() {
@@ -34,7 +34,12 @@ const { t } = useI18n();
defineOptions({ defineOptions({
name: "SiteCertMonitor", name: "SiteCertMonitor",
}); });
const { crudBinding, crudRef, crudExpose, context } = useFs({ createCrudOptions }); const context: any = {
permission: {
isProjectPermission: true,
},
};
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context });
const handleBatchDelete = context.handleBatchDelete; const handleBatchDelete = context.handleBatchDelete;
@@ -17,7 +17,7 @@ import { useI18n } from "/src/locales";
import { useDicts } from "../dicts"; import { useDicts } from "../dicts";
import { useProjectStore } from "/@/store/project"; import { useProjectStore } from "/@/store/project";
export default function ({ crudExpose, context: { selectedRowKeys, openCertApplyDialog } }: CreateCrudOptionsProps): CreateCrudOptionsRet { export default function ({ crudExpose, context: { selectedRowKeys, openCertApplyDialog, hasActionPermission } }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const router = useRouter(); const router = useRouter();
const lastResRef = ref(); const lastResRef = ref();
@@ -124,9 +124,11 @@ export default function ({ crudExpose, context: { selectedRowKeys, openCertApply
click() { click() {
openCertApplyDialog({ key: "CertApply" }); openCertApplyDialog({ key: "CertApply" });
}, },
show: hasActionPermission("add"),
}, },
uploadCert: { uploadCert: {
order: 2, order: 2,
show: hasActionPermission("uploadCert"),
text: t("certd.commercialCertHosting"), text: t("certd.commercialCertHosting"),
type: "primary", type: "primary",
tooltip: { tooltip: {
@@ -207,6 +209,7 @@ export default function ({ crudExpose, context: { selectedRowKeys, openCertApply
}, },
}, },
copy: { copy: {
show: hasActionPermission("write"),
click: async context => { click: async context => {
settingStore.checkPlus(); settingStore.checkPlus();
const { ui } = useUi(); const { ui } = useUi();
@@ -224,6 +227,7 @@ export default function ({ crudExpose, context: { selectedRowKeys, openCertApply
class: "need-plus", class: "need-plus",
}, },
config: { config: {
show: hasActionPermission("write"),
order: 1, order: 1,
title: t("certd.actions.editPipeline"), title: t("certd.actions.editPipeline"),
type: "link", type: "link",
@@ -234,6 +238,7 @@ export default function ({ crudExpose, context: { selectedRowKeys, openCertApply
}, },
}, },
edit: { edit: {
show: hasActionPermission("write"),
order: 2, order: 2,
title: t("certd.actions.editConfigGroup"), title: t("certd.actions.editConfigGroup"),
icon: "ant-design:setting-outlined", icon: "ant-design:setting-outlined",
@@ -13,7 +13,7 @@
</a-alert> --> </a-alert> -->
<fs-crud ref="crudRef" v-bind="crudBinding"> <fs-crud ref="crudRef" v-bind="crudBinding">
<template #actionbar-right> <template #actionbar-right>
<a-dropdown class="ml-1"> <a-dropdown v-if="hasActionPermission('write')" class="ml-1">
<a-button type="primary" class="ant-dropdown-link" @click.prevent> <a-button type="primary" class="ant-dropdown-link" @click.prevent>
{{ t("certd.pipelinePage.addMore") }} {{ t("certd.pipelinePage.addMore") }}
<DownOutlined /> <DownOutlined />
@@ -68,6 +68,7 @@ import { useSettingStore } from "/@/store/settings";
import { groupDictRef } from "./group/dicts"; import { groupDictRef } from "./group/dicts";
import { useCertPipelineCreator } from "./certd-form/use"; import { useCertPipelineCreator } from "./certd-form/use";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { useCrudPermission } from "/@/plugin/permission";
defineOptions({ defineOptions({
name: "PipelineManager", name: "PipelineManager",
@@ -106,7 +107,10 @@ function openCertApplyDialog(req: { key: string; title: string }) {
openAddCertdPipelineDialog({ pluginName: req.key, defaultGroupId, title: req.title }); openAddCertdPipelineDialog({ pluginName: req.key, defaultGroupId, title: req.title });
} }
context.openCertApplyDialog = openCertApplyDialog; context.openCertApplyDialog = openCertApplyDialog;
context.permission = { isProjectPermission: true };
const { hasActionPermission } = useCrudPermission({ permission: { isProjectPermission: true } });
context.hasActionPermission = hasActionPermission;
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context }); const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context });
// 页面打开后获取列表数据 // 页面打开后获取列表数据
@@ -46,7 +46,7 @@
</span> </span>
</a-tag> </a-tag>
</div> </div>
<div class="basis-40 flex justify-end mr-10"> <div v-if="hasActionPermission('write')" class="basis-40 flex justify-end mr-10">
<template v-if="editMode"> <template v-if="editMode">
<fs-button type="primary" :loading="saveLoading" @click="save">保存</fs-button> <fs-button type="primary" :loading="saveLoading" @click="save">保存</fs-button>
<fs-button class="ml-5" @click="cancel">取消</fs-button> <fs-button class="ml-5" @click="cancel">取消</fs-button>
@@ -333,6 +333,7 @@ import { getCronNextTimes } from "/@/components/cron-editor/utils";
import { useCertViewer } from "/@/views/certd/pipeline/use"; import { useCertViewer } from "/@/views/certd/pipeline/use";
import { useI18n } from "/@/locales"; import { useI18n } from "/@/locales";
import TriggerIcon from "./component/trigger-icon.vue"; import TriggerIcon from "./component/trigger-icon.vue";
import { useCrudPermission } from "/@/plugin/permission";
export default defineComponent({ export default defineComponent({
name: "PipelineEdit", name: "PipelineEdit",
@@ -1002,12 +1003,15 @@ export default defineComponent({
const hasWebhookTrigger = computed(() => { const hasWebhookTrigger = computed(() => {
return currentPipeline.value?.triggers?.some((item: any) => item.type === "webhook"); return currentPipeline.value?.triggers?.some((item: any) => item.type === "webhook");
}); });
const { hasActionPermission } = useCrudPermission({ permission: { isProjectPermission: true } });
return { return {
isCert, isCert,
pipeline, pipeline,
currentHistory, currentHistory,
histories, histories,
goBack, goBack,
hasActionPermission,
userStore, userStore,
settingStore, settingStore,
...useTaskRet, ...useTaskRet,
@@ -78,7 +78,6 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
add: { add: {
text: t("certd.template.createTemplate"), text: t("certd.template.createTemplate"),
type: "primary", type: "primary",
show: true,
}, },
}, },
}, },
@@ -21,7 +21,12 @@ import { useI18n } from "/src/locales";
defineOptions({ defineOptions({
name: "PipelineTemplate", name: "PipelineTemplate",
}); });
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: {} }); const { crudBinding, crudRef, crudExpose } = useFs({
createCrudOptions,
context: {
permission: { isProjectPermission: true },
},
});
const { t } = useI18n(); const { t } = useI18n();
// 页面打开后获取列表数据 // 页面打开后获取列表数据
onMounted(() => { onMounted(() => {
@@ -6,7 +6,7 @@ import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq,
import { useUserStore } from "/@/store/user"; import { useUserStore } from "/@/store/user";
import { useSettingStore } from "/@/store/settings"; import { useSettingStore } from "/@/store/settings";
import { Modal } from "ant-design-vue"; import { Modal } from "ant-design-vue";
import { userDict } from "../dicts"; import { userDict } from "../../sys/enterprise/dicts";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet { export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const router = useRouter(); const router = useRouter();
@@ -1,12 +1,12 @@
import * as api from "./api"; import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
import { useI18n } from "/src/locales";
import { computed, Ref, ref } from "vue";
import { useRouter } from "vue-router";
import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes, utils } from "@fast-crud/fast-crud";
import { useUserStore } from "/@/store/user";
import { useSettingStore } from "/@/store/settings";
import { Modal } from "ant-design-vue"; import { Modal } from "ant-design-vue";
import { Ref, ref } from "vue";
import { useRouter } from "vue-router";
import { userDict } from "../dicts"; import { userDict } from "../dicts";
import * as api from "./api";
import { useSettingStore } from "/@/store/settings";
import { useUserStore } from "/@/store/user";
import { useI18n } from "/src/locales";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet { export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const router = useRouter(); const router = useRouter();