-
Notifications
You must be signed in to change notification settings - Fork 2.8k
feat: Workplace resource authorization #3864
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,291 @@ | ||
| <template> | ||
| <el-drawer | ||
| v-model="drawerVisible" | ||
| :title="$t('views.system.resourceAuthorization.title')" | ||
| size="60%" | ||
| :append-to-body="true" | ||
| :modal="false" | ||
| > | ||
| <div class="flex-between mb-16"> | ||
| <el-button | ||
| type="primary" | ||
| :disabled="multipleSelection.length === 0" | ||
| @click="openMulConfigureDialog" | ||
| >{{ $t('views.system.resourceAuthorization.setting.configure') }}</el-button | ||
| > | ||
|
|
||
| <div class="flex-between complex-search"> | ||
| <el-select | ||
| class="complex-search__left" | ||
| v-model="searchType" | ||
| style="width: 100px" | ||
| @change="search_type_change" | ||
| > | ||
| <el-option :label="$t('views.userManage.userForm.nick_name.label')" value="nick_name" /> | ||
| <el-option :label="$t('views.login.loginForm.username.label')" value="username" /> | ||
| <el-option | ||
| :label="$t('views.model.modelForm.permissionType.label')" | ||
| value="publish_status" | ||
| /> | ||
| </el-select> | ||
| <el-input | ||
| v-if="searchType === 'nick_name'" | ||
| v-model="searchForm.nick_name" | ||
| @change="searchHandle" | ||
| :placeholder="$t('common.search')" | ||
| style="width: 220px" | ||
| clearable | ||
| /> | ||
| <el-input | ||
| v-if="searchType === 'username'" | ||
| v-model="searchForm.username" | ||
| @change="searchHandle" | ||
| :placeholder="$t('common.search')" | ||
| style="width: 220px" | ||
| clearable | ||
| /> | ||
|
|
||
| <el-select | ||
| v-else-if="searchType === 'publish_status'" | ||
| v-model="searchForm.publish_status" | ||
| @change="searchHandle" | ||
| filterable | ||
| clearable | ||
| multiple | ||
| collapse-tags | ||
| collapse-tags-tooltip | ||
| style="width: 220px" | ||
| > | ||
| <template v-for="(item, index) in permissionOptions" :key="index"> | ||
| <el-option :label="item.label" :value="item.value" /> | ||
| </template> | ||
| </el-select> | ||
| </div> | ||
| </div> | ||
|
|
||
| <app-table | ||
| ref="multipleTableRef" | ||
| class="mt-16" | ||
| :data="permissionData" | ||
| :pagination-config="paginationConfig" | ||
| @sizeChange="handleSizeChange" | ||
| @changePage="getPermissionList" | ||
| @selection-change="handleSelectionChange" | ||
| :maxTableHeight="200" | ||
| :row-key="(row: any) => row.id" | ||
| v-loading="loading" | ||
| > | ||
| <el-table-column type="selection" width="55" :reserve-selection="true" /> | ||
| <el-table-column | ||
| prop="nick_name" | ||
| :label="$t('views.userManage.userForm.nick_name.label')" | ||
| min-width="120" | ||
| show-overflow-tooltip | ||
| /> | ||
| <el-table-column | ||
| prop="username" | ||
| min-width="120" | ||
| show-overflow-tooltip | ||
| :label="$t('views.login.loginForm.username.label')" | ||
| /> | ||
| <!-- <el-table-column prop="role_name" :label="$t('views.role.member.role')" width="210"> | ||
| <template #default="{ row }"> | ||
| <el-popover :width="400"> | ||
| <template #reference> | ||
| <TagGroup | ||
| class="cursor" | ||
| style="width: fit-content" | ||
| :tags="row.role_name" | ||
| tooltipDisabled | ||
| /> | ||
| </template> | ||
| <template #default> | ||
| <el-table :data="row.role_workspace"> | ||
| <el-table-column prop="role" :label="$t('views.role.member.role')"> | ||
| </el-table-column> | ||
| <el-table-column prop="workspace" :label="$t('views.workspace.title')"> | ||
| </el-table-column> | ||
| </el-table> | ||
| </template> | ||
| </el-popover> | ||
| </template> | ||
| </el-table-column> --> | ||
| <el-table-column :label="$t('common.operation')" align="left" width="340"> | ||
| <template #default="{ row }"> | ||
| <el-radio-group | ||
| v-model="row.permission" | ||
| @change="(val: any) => permissionsHandle(val, row)" | ||
| > | ||
| <template v-for="(item, index) in permissionOptions" :key="index"> | ||
| <el-radio :value="item.value" class="mr-16">{{ item.label }}</el-radio> | ||
| </template> | ||
| </el-radio-group> | ||
| </template> | ||
| </el-table-column> | ||
| </app-table> | ||
|
|
||
| <!-- 批量配置 弹出层 --> | ||
| <el-dialog | ||
| v-model="dialogVisible" | ||
| :title="$t('views.system.resourceAuthorization.setting.configure')" | ||
| destroy-on-close | ||
| @close="closeDialog" | ||
| > | ||
| <el-radio-group v-model="radioPermission" class="radio-block"> | ||
| <template v-for="(item, index) in permissionOptions" :key="index"> | ||
| <el-radio :value="item.value" class="mr-16"> | ||
| <p class="color-text-primary lighter">{{ item.label }}</p> | ||
| <el-text class="color-secondary lighter">{{ item.desc }}</el-text> | ||
| </el-radio> | ||
| </template> | ||
| </el-radio-group> | ||
| <template #footer> | ||
| <div class="dialog-footer mt-24"> | ||
| <el-button @click="closeDialog"> {{ $t('common.cancel') }}</el-button> | ||
| <el-button type="primary" @click="submitDialog"> {{ $t('common.confirm') }}</el-button> | ||
| </div> | ||
| </template> | ||
| </el-dialog> | ||
| </el-drawer> | ||
| </template> | ||
| <script setup lang="ts"> | ||
| import { ref, onMounted, watch, computed, reactive } from 'vue' | ||
| import { permissionOptions } from '@/views/system/resource-authorization/constant' | ||
| import AuthorizationApi from '@/api/system/resource-authorization' | ||
| import { MsgSuccess, MsgConfirm } from '@/utils/message' | ||
| import { t } from '@/locales' | ||
| import useStore from '@/stores' | ||
| const { user } = useStore() | ||
| const props = defineProps<{ | ||
| type: string | ||
| }>() | ||
|
|
||
| const drawerVisible = ref(false) | ||
| const multipleTableRef = ref() | ||
|
|
||
| watch(drawerVisible, (bool) => { | ||
| if (!bool) { | ||
| targetId.value = '' | ||
| searchType.value = 'nick_name' | ||
| searchForm.value = { nick_name: '', username: '', permission: undefined } | ||
| permissionData.value = [] | ||
| paginationConfig.current_page = 1 | ||
| paginationConfig.total = 0 | ||
| multipleSelection.value = [] | ||
| multipleTableRef.value?.clearSelection() | ||
| } | ||
| }) | ||
|
|
||
| const loading = ref(false) | ||
| const targetId = ref('') | ||
| const permissionData = ref<any[]>([]) | ||
| const searchType = ref('nick_name') | ||
| const searchForm = ref<any>({ | ||
| nick_name: '', | ||
| username: '', | ||
| permission: undefined, | ||
| }) | ||
|
|
||
| const search_type_change = () => { | ||
| searchForm.value = { nick_name: '', username: '', permission: undefined } | ||
| } | ||
|
|
||
| const paginationConfig = reactive({ | ||
| current_page: 1, | ||
| page_size: 20, | ||
| total: 0, | ||
| }) | ||
|
|
||
| function handleSizeChange() { | ||
| paginationConfig.current_page = 1 | ||
| getPermissionList() | ||
| } | ||
| function searchHandle() { | ||
| paginationConfig.current_page = 1 | ||
| getPermissionList() | ||
| } | ||
|
|
||
| const multipleSelection = ref<any[]>([]) | ||
|
|
||
| const handleSelectionChange = (val: any[]) => { | ||
| multipleSelection.value = val | ||
| } | ||
|
|
||
| const dialogVisible = ref(false) | ||
| const radioPermission = ref('') | ||
| function openMulConfigureDialog() { | ||
| if (multipleSelection.value.length === 0) { | ||
| return | ||
| } | ||
| dialogVisible.value = true | ||
| } | ||
| function submitDialog() { | ||
| if (multipleSelection.value.length === 0 || !radioPermission.value) { | ||
| return | ||
| } | ||
| const obj = multipleSelection.value.map((item) => ({ | ||
| user_id: item.id, | ||
| permission: radioPermission.value, | ||
| })) | ||
| submitPermissions(obj) | ||
| closeDialog() | ||
| } | ||
| function closeDialog() { | ||
| dialogVisible.value = false | ||
| radioPermission.value = '' | ||
| multipleSelection.value = [] | ||
| multipleTableRef.value?.clearSelection() | ||
| } | ||
|
|
||
| function permissionsHandle(val: any, row: any) { | ||
| const obj = [ | ||
| { | ||
| user_id: row.id, | ||
| permission: val, | ||
| }, | ||
| ] | ||
| submitPermissions(obj) | ||
| } | ||
|
|
||
| function submitPermissions(obj: any) { | ||
| const workspaceId = user.getWorkspaceId() || 'default' | ||
| AuthorizationApi.putWorkspaceResourceAuthorization( | ||
| workspaceId, | ||
| targetId.value, | ||
| props.type, | ||
| obj, | ||
| loading, | ||
| ).then(() => { | ||
| MsgSuccess(t('common.submitSuccess')) | ||
| getPermissionList() | ||
| }) | ||
| } | ||
| const getPermissionList = () => { | ||
| const workspaceId = user.getWorkspaceId() || 'default' | ||
| const params: any = {} | ||
| if (searchForm.value[searchType.value]) { | ||
| params[searchType.value] = searchForm.value[searchType.value] | ||
| } | ||
| AuthorizationApi.getWorkspaceResourceAuthorization( | ||
| workspaceId, | ||
| targetId.value, | ||
| props.type, | ||
| paginationConfig, | ||
| params, | ||
| loading, | ||
| ).then((res) => { | ||
| permissionData.value = res.data.records || [] | ||
| paginationConfig.total = res.data.total || 0 | ||
| }) | ||
| } | ||
|
|
||
| const open = (id: string) => { | ||
| targetId.value = id | ||
| drawerVisible.value = true | ||
| getPermissionList() | ||
| } | ||
| defineExpose({ | ||
| open, | ||
| }) | ||
| </script> | ||
| <style lang="scss" scoped></style> | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Here’s an improved version with some of these considerations: <script setup lang="ts">
import { ref, onMounted, watch, computed, reactive } from 'vue';
import { PermissionOptions } from '@/views/system/resource-authorization/constant';
import AuthorizationApi from '@/api/system/resource-authorization';
import { MsgSuccess, MsgConfirm } from '@/utils/message';
import { t } from '@/locales';
import useStore from '@/stores';
const { user } = useStore();
interface SearchForm {
nick_name?: string;
username?: string;
publish_status?: number[];
}
defineProps({
type: String,
});
const drawerVisible = ref<boolean>(false);
const multipleTableRef = ref(null); // Ensure correct ref declaration
onMounted(() => {
})
watch(drawerVisible, (bool) => {
if (!bool) {
targetId.value = '';
searchType.value = 'nick_name';
searchForm.value = {} as SearchForm; // Initialize form with empty object
permissionData.value = [];
paginationConfig.current_page = 1;
paginationConfig.total = 0;
multipleSelection.value = [];
clearMultipleSelection(); // Custom method to avoid using reference directly
}
});
const loading = ref<boolean>(false);
const targetId = ref<string>('');
const permissionData = ref<any[]>([]);
const searchType = ref<String>('nick_name');
const searchForm = ref<SearchForm>({});
onMounted(() => {
updateSearchFields();
});
search_type_change = () => {
updateSearchFields({ nickname: '' }); // Reset form fields appropriately
}
const paginationConfig = reactive({
current_page: 1,
page_size: 20,
total: 0,
});
const handleSizeChange = async () => {
paginationConfig.current_page = 1
await getPermissionList();
};
function searchHandle() {
paginationConfig.current_page = 1
getPermissionList();
}
async function getPermissionList() {
const workspaceId = user.getWorkspaceId() || 'default';
const params: any = {};
if(searchForm[nickName].length !== 0){
params['nickname'] = searchForm.nickname;
else if(searchForm.username).length !== 0){
params['username'] = searchForm.username;
else if(searchForm.publishStatus && Array.isArray(searchForm.publishStatus)){
params['publish_status'] = [...new Set(searchForm.publishStatus)];
}
try{
const res:any= await AuthorizationApi.getWorkspaceResourceAuthorization(workspaceId,targetId,type,paginationConfig,params,loading);
if(res.status === 200 && res.data){
permissionData.value = res.data.records || [];
paginationConfig.total = res.data.total || 0;
} else {
console.error('Failed:', result.message);
}
} catch(error){
console.error("Error while fetching records:", error);
};
}
function open(id:string): void {
targetId.value = id;
drawerVisible.value = true;
await getPermissionList();
clearSearchFields();
}
// Additional helper functions...
const updateSearchFields={ ... };
const clearMultipleSelection ={ ... };
const clearSearchFields={ ... };
</script>
<style scoped>
/* Define your styles here */
</style>Ensure that you import Also, consider creating custom utility functions for clearing selection and input values to maintain consistency across the codebase. |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The provided code is well-structured and should work as intended. However, there are a few minor improvements and optimizations you can consider:
Naming Consistency: Ensure that all functions and variables follow consistent naming conventions throughout the codebase to maintain readability.
Type Annotations: You might want to add more detailed type annotations to ensure clarity about expectations.
Error Handling: Consider adding error handling logic to better manage potential issues during API calls.
Documentation Comments: Add JSDoc comments explaining each part of the function signatures for easier understanding by other developers.
Here's an improved version of the code with some suggestions:
Key Improvements:
PageRequestinterface for pagination options.loadingparameter asRef<boolean>.try...catchblocks.These changes make the code cleaner, more readable, and potentially more robust.