UX-2(操作级权限控制)
This commit is contained in:
@@ -3,7 +3,9 @@
|
||||
<div class="header">
|
||||
<span>分类</span>
|
||||
<div v-if="canMaintain">
|
||||
<el-button type="primary" size="small" @click="openForm()">新建</el-button>
|
||||
<PermissionAction action="faq.edit">
|
||||
<el-button type="primary" size="small" @click="openForm()">新建</el-button>
|
||||
</PermissionAction>
|
||||
</div>
|
||||
</div>
|
||||
<el-menu :default-active="activeCategory" @select="onSelect">
|
||||
@@ -12,15 +14,16 @@
|
||||
<span>{{ c.name }}</span>
|
||||
<el-tag v-if="c.study_id" size="small" type="success" class="ml-4">项目</el-tag>
|
||||
<el-tag v-else size="small" class="ml-4">全局</el-tag>
|
||||
<el-button
|
||||
v-if="canEdit(c)"
|
||||
type="text"
|
||||
size="small"
|
||||
style="margin-left: auto"
|
||||
@click.stop="openForm(c)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<PermissionAction v-if="canEdit(c)" action="faq.edit">
|
||||
<el-button
|
||||
type="text"
|
||||
size="small"
|
||||
style="margin-left: auto"
|
||||
@click.stop="openForm(c)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
</PermissionAction>
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
<FaqCategoryForm v-model="showForm" :category="editing" :is-admin="isAdmin" @success="emit('refresh')" />
|
||||
@@ -33,6 +36,8 @@ import FaqCategoryForm from "./FaqCategoryForm.vue";
|
||||
import type { FaqCategory } from "../api/faqs";
|
||||
import { useAuthStore } from "../store/auth";
|
||||
import { useStudyStore } from "../store/study";
|
||||
import PermissionAction from "./PermissionAction.vue";
|
||||
import { usePermission } from "../utils/permission";
|
||||
|
||||
const props = defineProps<{
|
||||
categories: FaqCategory[];
|
||||
@@ -46,8 +51,9 @@ const study = useStudyStore();
|
||||
const showForm = ref(false);
|
||||
const editing = ref<FaqCategory | null>(null);
|
||||
|
||||
const { can } = usePermission();
|
||||
const isAdmin = computed(() => auth.user?.role === "ADMIN");
|
||||
const canMaintain = computed(() => isAdmin.value || auth.user?.role === "PM");
|
||||
const canMaintain = computed(() => can("faq.edit"));
|
||||
|
||||
const sortedCategories = computed(() =>
|
||||
[...props.categories].sort((a, b) => (a.sort_order ?? 0) - (b.sort_order ?? 0))
|
||||
@@ -56,8 +62,9 @@ const sortedCategories = computed(() =>
|
||||
const activeCategory = computed(() => props.modelValue || "");
|
||||
|
||||
const canEdit = (c: FaqCategory) => {
|
||||
if (!canMaintain.value) return false;
|
||||
if (isAdmin.value) return true;
|
||||
return auth.user?.role === "PM" && c.study_id === study.currentStudy?.id;
|
||||
return c.study_id === study.currentStudy?.id;
|
||||
};
|
||||
|
||||
const onSelect = (id: string) => {
|
||||
|
||||
@@ -16,16 +16,19 @@
|
||||
<el-table-column label="操作" width="180">
|
||||
<template #default="scope">
|
||||
<el-button type="text" size="small" @click="view(scope.row)">查看</el-button>
|
||||
<el-button v-if="canEdit" type="text" size="small" @click="edit(scope.row)">编辑</el-button>
|
||||
<el-button
|
||||
v-if="canEdit"
|
||||
type="text"
|
||||
size="small"
|
||||
@click="toggle(scope.row)"
|
||||
:style="{ color: scope.row.is_active ? '#f56c6c' : '#67c23a' }"
|
||||
>
|
||||
{{ scope.row.is_active ? "停用" : "启用" }}
|
||||
</el-button>
|
||||
<PermissionAction v-if="canEdit" action="faq.edit">
|
||||
<el-button type="text" size="small" @click="edit(scope.row)">编辑</el-button>
|
||||
</PermissionAction>
|
||||
<PermissionAction v-if="canEdit" action="faq.edit">
|
||||
<el-button
|
||||
type="text"
|
||||
size="small"
|
||||
@click="toggle(scope.row)"
|
||||
:style="{ color: scope.row.is_active ? '#f56c6c' : '#67c23a' }"
|
||||
>
|
||||
{{ scope.row.is_active ? "停用" : "启用" }}
|
||||
</el-button>
|
||||
</PermissionAction>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -37,6 +40,7 @@ import { computed } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { updateFaqItem } from "../api/faqs";
|
||||
import type { FaqItem, FaqCategory } from "../api/faqs";
|
||||
import PermissionAction from "./PermissionAction.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
items: FaqItem[];
|
||||
|
||||
@@ -1,63 +1,65 @@
|
||||
<template>
|
||||
<div class="actions">
|
||||
<el-button
|
||||
v-if="item.status === 'DRAFT' && canSubmit"
|
||||
type="primary"
|
||||
size="small"
|
||||
:loading="loading"
|
||||
@click="change('SUBMITTED')"
|
||||
>
|
||||
提交
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="item.status === 'SUBMITTED' && canApprove"
|
||||
type="success"
|
||||
size="small"
|
||||
:loading="loading"
|
||||
@click="change('APPROVED')"
|
||||
>
|
||||
审批通过
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="item.status === 'SUBMITTED' && canApprove"
|
||||
type="danger"
|
||||
size="small"
|
||||
:loading="loading"
|
||||
@click="reject"
|
||||
>
|
||||
驳回
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="item.status === 'APPROVED' && canPay"
|
||||
type="warning"
|
||||
size="small"
|
||||
:loading="loading"
|
||||
@click="change('PAID')"
|
||||
>
|
||||
确认支付
|
||||
</el-button>
|
||||
<PermissionAction action="finance.create">
|
||||
<el-button
|
||||
v-if="item.status === 'DRAFT'"
|
||||
type="primary"
|
||||
size="small"
|
||||
:loading="loading"
|
||||
@click="change('SUBMITTED')"
|
||||
>
|
||||
提交
|
||||
</el-button>
|
||||
</PermissionAction>
|
||||
<PermissionAction action="finance.approve">
|
||||
<el-button
|
||||
v-if="item.status === 'SUBMITTED'"
|
||||
type="success"
|
||||
size="small"
|
||||
:loading="loading"
|
||||
@click="change('APPROVED')"
|
||||
>
|
||||
审批通过
|
||||
</el-button>
|
||||
</PermissionAction>
|
||||
<PermissionAction action="finance.approve">
|
||||
<el-button
|
||||
v-if="item.status === 'SUBMITTED'"
|
||||
type="danger"
|
||||
size="small"
|
||||
:loading="loading"
|
||||
@click="reject"
|
||||
>
|
||||
驳回
|
||||
</el-button>
|
||||
</PermissionAction>
|
||||
<PermissionAction action="finance.pay">
|
||||
<el-button
|
||||
v-if="item.status === 'APPROVED'"
|
||||
type="warning"
|
||||
size="small"
|
||||
:loading="loading"
|
||||
@click="change('PAID')"
|
||||
>
|
||||
确认支付
|
||||
</el-button>
|
||||
</PermissionAction>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { computed, ref } from "vue";
|
||||
import { ref } from "vue";
|
||||
import { changeFinanceStatus } from "../api/finance";
|
||||
import { useStudyStore } from "../store/study";
|
||||
import { useAuthStore } from "../store/auth";
|
||||
import PermissionAction from "./PermissionAction.vue";
|
||||
|
||||
const props = defineProps<{ item: any }>();
|
||||
const emit = defineEmits(["success"]);
|
||||
|
||||
const study = useStudyStore();
|
||||
const auth = useAuthStore();
|
||||
const loading = ref(false);
|
||||
|
||||
const role = computed(() => auth.user?.role);
|
||||
const canSubmit = computed(() => role.value === "ADMIN" || role.value === "PM" || role.value === "CRA");
|
||||
const canApprove = computed(() => role.value === "ADMIN" || role.value === "PM");
|
||||
const canPay = canApprove;
|
||||
|
||||
const change = async (status: string, reject_reason?: string) => {
|
||||
if (!study.currentStudy) return;
|
||||
loading.value = true;
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<el-tooltip v-if="!allowed && tooltip" :content="reason" placement="top">
|
||||
<span class="perm-wrapper perm-disabled">
|
||||
<slot />
|
||||
</span>
|
||||
</el-tooltip>
|
||||
<span v-else-if="!allowed" class="perm-wrapper perm-disabled">
|
||||
<slot />
|
||||
</span>
|
||||
<span v-else class="perm-wrapper">
|
||||
<slot />
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
import { usePermission } from "../utils/permission";
|
||||
|
||||
const props = defineProps<{
|
||||
action: string;
|
||||
tooltip?: boolean;
|
||||
}>();
|
||||
|
||||
const { can, reason: reasonFn } = usePermission();
|
||||
const allowed = computed(() => can(props.action));
|
||||
const reason = computed(() => reasonFn(props.action));
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.perm-wrapper {
|
||||
display: inline-block;
|
||||
}
|
||||
.perm-disabled {
|
||||
opacity: 0.55;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user