refactor: migrate user group dialogs to shadcn

This commit is contained in:
overtrue
2025-10-26 21:37:59 +08:00
parent 8ed144bcad
commit 3372555e20
4 changed files with 532 additions and 383 deletions
+55 -55
View File
@@ -1,77 +1,77 @@
<template>
<div>
<n-modal
v-model:show="visible"
:mask-closable="false"
preset="card"
:title="group.name"
class="max-w-screen-md"
:segmented="{
content: true,
action: true,
}"
>
<n-card>
<n-tabs type="card">
<n-tab-pane name="users" :tab="t('Members')">
<users-group-members :group="group" @search="getGroupData(group.name)"></users-group-members>
</n-tab-pane>
<n-tab-pane name="policy" :tab="t('Policies')">
<users-group-policies :group="group" @search="getGroupData(group.name)"></users-group-policies>
</n-tab-pane>
<template #suffix>
{{ t('Status') }}
<n-switch
class="ml-2"
checked-value="enabled"
unchecked-value="disabled"
v-model:value="group.status"
:on-update:value="handerGroupStatusChange"
></n-switch>
</template>
</n-tabs>
</n-card>
</n-modal>
</div>
<AppModal v-model="visible" :title="group.name || t('Members')" size="lg" :close-on-backdrop="false">
<AppCard padded class="space-y-4">
<div class="flex items-center justify-between rounded-md border border-border/60 px-3 py-2">
<span class="text-sm text-muted-foreground">{{ t('Status') }}</span>
<AppSwitch v-model="statusBoolean" />
</div>
<Tabs v-model="activeTab" class="flex flex-col gap-4">
<TabsList class="w-full justify-start overflow-x-auto">
<TabsTrigger value="users">{{ t('Members') }}</TabsTrigger>
<TabsTrigger value="policy">{{ t('Policies') }}</TabsTrigger>
</TabsList>
<TabsContent value="users" class="mt-0">
<users-group-members :group="group" @search="getGroupData(group.name)" />
</TabsContent>
<TabsContent value="policy" class="mt-0">
<users-group-policies :group="group" @search="getGroupData(group.name)" />
</TabsContent>
</Tabs>
</AppCard>
</AppModal>
</template>
<script setup lang="ts">
import { useI18n } from 'vue-i18n';
import { AppCard, AppModal, AppSwitch } from '@/components/app'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
import { computed, ref } from 'vue'
import { useI18n } from 'vue-i18n'
const { t } = useI18n();
const visible = ref(false);
const { getGroup, updateGroupStatus } = useGroups();
const { t } = useI18n()
const visible = ref(false)
const activeTab = ref('users')
const { getGroup, updateGroupStatus } = useGroups()
interface GroupInfo {
name: string;
members: string[];
status: string;
name: string
members: string[]
status: string
}
const group = ref<GroupInfo>({
name: '',
members: [],
status: 'enabled',
});
})
// 用户组的状态发生变化
const handerGroupStatusChange = async (val: string) => {
await updateGroupStatus(group.value.name, { ...group.value, status: val });
await getGroupData(group.value.name);
};
async function openDialog(row: any) {
getGroupData(row.name);
visible.value = true;
const statusBoolean = computed({
get: () => group.value.status === 'enabled',
set: async value => {
const nextStatus = value ? 'enabled' : 'disabled'
if (nextStatus !== group.value.status) {
await handleGroupStatusChange(nextStatus)
}
},
})
const handleGroupStatusChange = async (status: string) => {
await updateGroupStatus(group.value.name, { ...group.value, status })
await getGroupData(group.value.name)
}
async function openDialog(row: any) {
await getGroupData(row.name)
activeTab.value = 'users'
visible.value = true
}
// 获取用户信息
async function getGroupData(name: string) {
group.value = await getGroup(name);
group.value = await getGroup(name)
}
defineExpose({
openDialog,
});
})
</script>
<style lang="scss" scoped></style>
+150 -83
View File
@@ -1,106 +1,173 @@
<script setup lang="ts">
import { computed, ref } from 'vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
import { Icon } from '#components'
import { AppButton, AppCard, AppInput, AppModal } from '@/components/app'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from '@/components/ui/command'
import { Label } from '@/components/ui/label'
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
import { computed, reactive, ref } from 'vue'
import { useI18n } from 'vue-i18n'
interface Props {
visible: boolean;
visible: boolean
}
const { visible } = defineProps<Props>();
const message = useMessage();
const { $api } = useNuxtApp();
const group = useGroups();
const user = useUsers();
const emit = defineEmits<Emits>();
const defaultFormModal = {
const props = defineProps<Props>()
const emit = defineEmits<{
(e: 'update:visible', visible: boolean): void
(e: 'search'): void
}>()
const { t } = useI18n()
const message = useMessage()
const { updateGroupMembers } = useGroups()
const { listUsers } = useUsers()
const defaultFormModel = () => ({
group: '',
members: [],
};
const formModel = ref({ ...defaultFormModal });
members: [] as string[],
})
interface Emits {
(e: 'update:visible', visible: boolean): void;
(e: 'search'): void;
}
// 用户列表
const users = ref<any[]>([]);
const getUserList = async () => {
const res = await user.listUsers();
users.value = Object.entries(res).map(([username, info]) => ({
label: username, // 添加用户名
value: username, // 添加用户名
}));
};
getUserList();
const formModel = reactive(defaultFormModel())
const submitting = ref(false)
const memberSelectorOpen = ref(false)
const users = ref<{ label: string; value: string }[]>([])
const modalVisible = computed({
get() {
return visible;
},
set(visible) {
closeModal(visible);
},
});
function closeModal(visible = false) {
formModel.value = { ...defaultFormModal };
emit('update:visible', visible);
get: () => props.visible,
set: value => closeModal(value),
})
const selectedMemberLabels = computed(() => {
const map = users.value.reduce<Record<string, string>>((acc, option) => {
acc[option.value] = option.label
return acc
}, {})
return formModel.members.map(value => map[value] ?? value)
})
const loadUsers = async () => {
try {
const res = await listUsers()
users.value = Object.entries(res ?? {}).map(([username]) => ({
label: username,
value: username,
}))
} catch (error) {
message.error(t('Failed to get data'))
}
}
async function submitForm() {
if (formModel.value.group.trim() === '') {
message.error(t('Please enter user group name'));
return;
loadUsers()
const toggleMember = (value: string) => {
if (formModel.members.includes(value)) {
formModel.members = formModel.members.filter(item => item !== value)
} else {
formModel.members = [...formModel.members, value]
}
}
const closeModal = (visible = false) => {
Object.assign(formModel, defaultFormModel())
memberSelectorOpen.value = false
emit('update:visible', visible)
}
const submitForm = async () => {
if (!formModel.group.trim()) {
message.error(t('Please enter user group name'))
return
}
submitting.value = true
try {
const res = await group.updateGroupMembers({
...formModel.value,
await updateGroupMembers({
...formModel,
groupStatus: 'enabled',
isRemove: false,
});
})
message.success(t('Add success'));
closeModal();
emit('search');
message.success(t('Add success'))
closeModal()
emit('search')
} catch (error) {
message.error(t('Add failed'));
message.error(t('Add failed'))
} finally {
submitting.value = false
}
}
</script>
<template>
<n-modal
v-model:show="modalVisible"
:mask-closable="false"
preset="card"
:title="t('Add group members')"
class="max-w-screen-md"
:segmented="{
content: true,
action: true,
}"
>
<n-card>
<n-form label-placement="left" :model="formModel" label-align="right" :label-width="130">
<n-grid :cols="24" :x-gap="18">
<n-form-item-grid-item :span="24" :label="t('Name')" path="group" required>
<n-input v-model:value="formModel.group" />
</n-form-item-grid-item>
<n-form-item-grid-item :span="24" :label="t('Users')" path="members">
<n-select v-model:value="formModel.members" filterable multiple :options="users" />
</n-form-item-grid-item>
</n-grid>
</n-form>
</n-card>
<template #action>
<n-space justify="center">
<n-button @click="closeModal()">{{ t('Cancel') }}</n-button>
<n-button type="primary" @click="submitForm">{{ t('Submit') }}</n-button>
</n-space>
</template>
</n-modal>
</template>
<AppModal v-model="modalVisible" :title="t('Add group members')" size="lg" :close-on-backdrop="false">
<AppCard padded class="space-y-6">
<div class="space-y-2">
<Label class="text-sm font-medium">{{ t('Name') }}</Label>
<AppInput v-model="formModel.group" autocomplete="off" />
</div>
<style scoped></style>
<div class="space-y-2">
<Label class="text-sm font-medium">{{ t('Users') }}</Label>
<Popover v-model:open="memberSelectorOpen">
<PopoverTrigger as-child>
<Button
type="button"
variant="outline"
class="min-h-10 w-full justify-between gap-2"
:aria-label="t('Users')"
>
<span class="truncate">
{{
selectedMemberLabels.length ? selectedMemberLabels.join(', ') : t('Select user group members')
}}
</span>
<Icon class="size-4 text-muted-foreground" name="ri:arrow-down-s-line" />
</Button>
</PopoverTrigger>
<PopoverContent class="w-72 p-0" align="start">
<Command>
<CommandInput :placeholder="t('Search User')" />
<CommandList>
<CommandEmpty>{{ t('No Data') }}</CommandEmpty>
<CommandGroup>
<CommandItem
v-for="option in users"
:key="option.value"
:value="option.label"
@select="() => toggleMember(option.value)"
>
<Icon
name="ri:check-line"
class="mr-2 size-4"
:class="formModel.members.includes(option.value) ? 'opacity-100' : 'opacity-0'"
/>
<span>{{ option.label }}</span>
</CommandItem>
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
<div v-if="formModel.members.length" class="flex flex-wrap gap-2">
<Badge v-for="value in formModel.members" :key="value" variant="secondary">
{{ value }}
</Badge>
</div>
</div>
</AppCard>
<template #footer>
<div class="flex justify-end gap-2">
<AppButton variant="outline" @click="closeModal()">
{{ t('Cancel') }}
</AppButton>
<AppButton variant="primary" :loading="submitting" @click="submitForm">
{{ t('Submit') }}
</AppButton>
</div>
</template>
</AppModal>
</template>
+187 -116
View File
@@ -1,134 +1,205 @@
<template>
<div>
<n-card>
<n-form ref="formRef" :model="searchForm" label-placement="left" :show-feedback="false">
<n-flex justify="space-between" v-if="!editStatus">
<n-form-item class="!w-64" label="" path="name">
<n-input :placeholder="t('Search Policy')" @input="filterName" />
</n-form-item>
<AppCard padded class="space-y-4">
<div v-if="!editStatus" class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<div class="w-full sm:max-w-xs">
<AppInput v-model="searchTerm" :placeholder="t('Search Policy')" />
</div>
<AppButton variant="secondary" class="inline-flex items-center gap-2" @click="startEditing">
<Icon class="size-4" name="ri:add-line" />
{{ t('Edit Policy') }}
</AppButton>
</div>
<n-space>
<NFlex>
<NButton secondary @click="editStatus = true">
<template #icon>
<Icon name="ri:add-line"></Icon>
</template>
{{ t('Edit Policy') }}
</NButton>
</NFlex>
</n-space>
</n-flex>
<n-flex justify="space-between" v-else>
<n-form-item class="!w-96" :label="t('Select user group policies')" path="policies">
<n-select v-model:value="name" filterable multiple :options="polices" />
</n-form-item>
<n-space>
<NFlex>
<NButton secondary @click="changePolicies">{{ t('Submit') }}</NButton>
</NFlex>
</n-space>
</n-flex>
</n-form>
</n-card>
<n-data-table
class="my-4"
ref="tableRef"
:columns="columns"
:data="listData"
:pagination="false"
:bordered="false"
/>
</div>
<div v-else class="flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between">
<div class="flex w-full flex-col gap-2">
<Label class="text-sm font-medium">{{ t('Select user group policies') }}</Label>
<Popover v-model:open="policySelectorOpen">
<PopoverTrigger as-child>
<Button
type="button"
variant="outline"
class="min-h-10 justify-between gap-2"
:aria-label="t('Select user group policies')"
>
<span class="truncate">
{{ selectedPolicyLabels.length ? selectedPolicyLabels.join(', ') : t('Select user group policies') }}
</span>
<Icon class="size-4 text-muted-foreground" name="ri:arrow-down-s-line" />
</Button>
</PopoverTrigger>
<PopoverContent class="w-72 p-0" align="start">
<Command>
<CommandInput :placeholder="t('Search Policy')" />
<CommandList>
<CommandEmpty>{{ t('No Data') }}</CommandEmpty>
<CommandGroup>
<CommandItem
v-for="option in policies"
:key="option.value"
:value="option.label"
@select="() => togglePolicy(option.value)"
>
<Icon
name="ri:check-line"
class="mr-2 size-4"
:class="selectedPolicies.includes(option.value) ? 'opacity-100' : 'opacity-0'"
/>
<span>{{ option.label }}</span>
</CommandItem>
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
<div v-if="selectedPolicies.length" class="flex flex-wrap gap-2">
<Badge v-for="value in selectedPolicies" :key="value" variant="secondary">{{ value }}</Badge>
</div>
</div>
<div class="flex items-center gap-2 sm:self-start">
<AppButton variant="ghost" @click="cancelEditing">
{{ t('Cancel') }}
</AppButton>
<AppButton variant="secondary" @click="changePolicies">
{{ t('Submit') }}
</AppButton>
</div>
</div>
<Table class="overflow-hidden rounded-lg border">
<TableHeader>
<TableRow>
<TableHead>{{ t('Name') }}</TableHead>
</TableRow>
</TableHeader>
<TableBody v-if="filteredPolicies.length">
<TableRow v-for="policy in filteredPolicies" :key="policy">
<TableCell class="font-medium">{{ policy }}</TableCell>
</TableRow>
</TableBody>
<TableBody v-else>
<TableRow>
<TableCell class="text-center" colspan="1">
<p class="py-6 text-sm text-muted-foreground">{{ t('No Data') }}</p>
</TableCell>
</TableRow>
</TableBody>
</Table>
</AppCard>
</template>
<script setup lang="ts">
import { type DataTableColumns, type DataTableInst, NButton, NSpace } from 'naive-ui';
const { listPolicies, setUserOrGroupPolicy } = usePolicies();
const { t } = useI18n();
import { Icon } from '#components'
import { AppButton, AppCard, AppInput } from '@/components/app'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from '@/components/ui/command'
import { Label } from '@/components/ui/label'
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
import { computed, onMounted, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
const messge = useMessage();
const props = defineProps({
const { listPolicies, setUserOrGroupPolicy } = usePolicies()
const { t } = useI18n()
const message = useMessage()
const props = defineProps<{
group: {
type: Object,
required: true,
name: string
policy?: string
}
}>()
const emit = defineEmits<{ (e: 'search'): void }>()
const searchTerm = ref('')
const editStatus = ref(false)
const policySelectorOpen = ref(false)
const policies = ref<{ label: string; value: string }[]>([])
const selectedPolicies = ref<string[]>([])
const currentPolicies = computed(() => {
if (!props.group?.policy) return []
return props.group.policy.split(',').map(item => item.trim()).filter(Boolean)
})
const filteredPolicies = computed(() => {
const keyword = searchTerm.value.trim().toLowerCase()
const source = currentPolicies.value
if (!keyword) return source
return source.filter(policy => policy.toLowerCase().includes(keyword))
})
const policyLabelMap = computed(() => {
return policies.value.reduce<Record<string, string>>((acc, option) => {
acc[option.value] = option.label
return acc
}, {})
})
const selectedPolicyLabels = computed(() => selectedPolicies.value.map(value => policyLabelMap.value[value] ?? value))
watch(
() => props.group?.policy,
() => {
if (!editStatus.value) {
selectedPolicies.value = [...currentPolicies.value]
}
},
});
{ immediate: true }
)
const searchForm = reactive({
name: '',
});
interface RowData {
name: string;
}
const columns: DataTableColumns<RowData> = [
{
title: t('Name'),
align: 'left',
key: 'name',
filter(value, row) {
return !!row.name.includes(value.toString());
},
},
];
// 搜索过滤
const tableRef = ref<DataTableInst>();
function filterName(value: string) {
tableRef.value &&
tableRef.value.filter({
name: [value],
});
}
const listData = computed(() => {
if (!props.group?.policy) return [];
return (
props.group?.policy?.split(',').map((item: string) => {
return {
name: item,
};
}) || []
);
});
/********************编辑****************/
const editStatus = ref(false);
// 策略列表
const polices = ref<any[]>([]);
const emit = defineEmits<{
(e: 'search'): void;
}>();
const getPoliciesList = async () => {
const res = await listPolicies();
polices.value = Object.keys(res)
.sort((a, b) => a.localeCompare(b))
.map(key => {
return {
const loadPolicies = async () => {
try {
const res = await listPolicies()
policies.value = Object.keys(res ?? {})
.sort((a, b) => a.localeCompare(b))
.map(key => ({
label: key,
value: key,
};
});
};
getPoliciesList();
}))
} catch (error) {
message.error(t('Failed to get data'))
}
}
onMounted(() => {
loadPolicies()
})
const startEditing = () => {
selectedPolicies.value = [...currentPolicies.value]
policySelectorOpen.value = false
editStatus.value = true
}
const cancelEditing = () => {
selectedPolicies.value = [...currentPolicies.value]
policySelectorOpen.value = false
editStatus.value = false
}
const togglePolicy = (value: string) => {
if (selectedPolicies.value.includes(value)) {
selectedPolicies.value = selectedPolicies.value.filter(item => item !== value)
} else {
selectedPolicies.value = [...selectedPolicies.value, value]
}
}
// const name = ref(props.group?.policy?.split(',') || [])
const name = ref(props.group?.policy ? props.group?.policy?.split(',') : []);
const changePolicies = async () => {
try {
await setUserOrGroupPolicy({
policyName: name.value || '',
userOrGroup: props.group.name || '',
policyName: selectedPolicies.value,
userOrGroup: props.group?.name ?? '',
isGroup: true,
});
messge.success('修改成功');
editStatus.value = false;
emit('search');
} catch {
messge.error('修改失败');
})
message.success(t('Edit Success'))
editStatus.value = false
policySelectorOpen.value = false
emit('search')
} catch (error) {
message.error(t('Edit Failed'))
}
};
}
</script>
<style lang="scss" scoped></style>
+140 -129
View File
@@ -1,141 +1,152 @@
<template>
<div>
<n-modal
v-model:show="visible"
:mask-closable="false"
preset="card"
:title="t('Batch allocation policies')"
class="w-1/2"
:segmented="{
content: true,
action: true,
}"
>
<n-card>
<n-form ref="formRef" :model="searchForm" label-placement="left" :show-feedback="false">
<n-flex justify="space-between">
<n-form-item class="!w-64" label="" path="name">
<n-input :placeholder="t('Search Policy')" @input="filterName" />
</n-form-item>
<AppModal v-model="visible" :title="t('Batch allocation policies')" size="xl" :close-on-backdrop="false">
<AppCard padded class="space-y-4">
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<div class="w-full sm:max-w-xs">
<AppInput v-model="searchTerm" :placeholder="t('Search Policy')" />
</div>
<AppButton variant="secondary" :disabled="!checkedKeys.length || submitting" @click="changePolicies">
{{ t('Submit') }}
</AppButton>
</div>
<n-space>
<NFlex>
<NButton secondary @click="changePolicies">{{ t('Submit') }}</NButton>
</NFlex>
</n-space>
</n-flex>
</n-form>
</n-card>
<n-data-table
class="my-4"
ref="tableRef"
:columns="columns"
:data="listData"
:pagination="false"
:bordered="false"
:row-key="rowKey"
@update:checked-row-keys="handleCheck"
/>
</n-modal>
</div>
<Table class="overflow-hidden rounded-lg border">
<TableHeader>
<TableRow>
<TableHead class="w-12">
<AppCheckbox
:checked="allVisibleSelected"
:indeterminate="checkedKeys.length > 0 && !allVisibleSelected"
@update:checked="toggleSelectAll"
/>
</TableHead>
<TableHead>{{ t('Name') }}</TableHead>
</TableRow>
</TableHeader>
<TableBody v-if="filteredPolicies.length">
<TableRow v-for="policy in filteredPolicies" :key="policy.name">
<TableCell>
<AppCheckbox :checked="isSelected(policy.name)" @update:checked="value => toggleSelection(policy.name, value)" />
</TableCell>
<TableCell class="font-medium">{{ policy.name }}</TableCell>
</TableRow>
</TableBody>
<TableBody v-else>
<TableRow>
<TableCell class="text-center" colspan="2">
<p class="py-6 text-sm text-muted-foreground">{{ t('No Data') }}</p>
</TableCell>
</TableRow>
</TableBody>
</Table>
</AppCard>
</AppModal>
</template>
<script setup lang="ts">
import { type DataTableColumns, type DataTableInst, type DataTableRowKey, NButton, NSpace } from 'naive-ui';
const { listPolicies, setUserOrGroupPolicy } = usePolicies();
const { t } = useI18n();
import { AppButton, AppCard, AppCheckbox, AppInput, AppModal } from '@/components/app'
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
import { computed, ref } from 'vue'
import { useI18n } from 'vue-i18n'
const props = defineProps({
checkedKeys: {
type: Array,
required: true,
},
});
const messge = useMessage();
const { listPolicies, setUserOrGroupPolicy } = usePolicies()
const { t } = useI18n()
const message = useMessage()
const visible = ref(false);
async function openDialog() {
visible.value = true;
const props = defineProps<{
checkedKeys: string[]
}>()
const emit = defineEmits<{
(e: 'changePoliciesSuccess'): void
}>()
const visible = ref(false)
const searchTerm = ref('')
const submitting = ref(false)
const policies = ref<{ name: string; content: unknown }[]>([])
const checkedKeys = ref<string[]>([])
const filteredPolicies = computed(() => {
const keyword = searchTerm.value.trim().toLowerCase()
if (!keyword) return policies.value
return policies.value.filter(policy => policy.name.toLowerCase().includes(keyword))
})
const allVisibleSelected = computed(() => {
const visibleNames = filteredPolicies.value.map(item => item.name)
if (!visibleNames.length) return false
return visibleNames.every(name => checkedKeys.value.includes(name))
})
const isSelected = (name: string) => checkedKeys.value.includes(name)
const toggleSelection = (name: string, checked: boolean) => {
if (checked) {
if (!checkedKeys.value.includes(name)) {
checkedKeys.value = [...checkedKeys.value, name]
}
} else {
checkedKeys.value = checkedKeys.value.filter(item => item !== name)
}
}
const toggleSelectAll = (checked: boolean) => {
const visibleNames = filteredPolicies.value.map(item => item.name)
if (!visibleNames.length) return
if (checked) {
const merged = new Set([...checkedKeys.value, ...visibleNames])
checkedKeys.value = Array.from(merged)
} else {
checkedKeys.value = checkedKeys.value.filter(name => !visibleNames.includes(name))
}
}
const loadPolicies = async () => {
try {
const res = await listPolicies()
policies.value = Object.keys(res ?? {})
.sort((a, b) => a.localeCompare(b))
.map(key => ({
name: key,
content: res[key],
}))
} catch (error) {
message.error(t('Failed to get data'))
}
}
const openDialog = async () => {
visible.value = true
checkedKeys.value = []
searchTerm.value = ''
await loadPolicies()
}
const changePolicies = async () => {
if (!checkedKeys.value.length) return
submitting.value = true
try {
await Promise.all(
props.checkedKeys.map(item =>
setUserOrGroupPolicy({
policyName: checkedKeys.value,
userOrGroup: item,
isGroup: true,
})
)
)
message.success(t('Edit Success'))
visible.value = false
emit('changePoliciesSuccess')
} catch (error) {
message.error(t('Edit Failed'))
} finally {
submitting.value = false
}
}
defineExpose({
openDialog,
});
const searchForm = reactive({
name: '',
});
interface RowData {
name: string;
}
const columns: DataTableColumns<RowData> = [
{
type: 'selection',
},
{
title: t('Name'),
align: 'left',
key: 'name',
filter(value, row) {
return !!row.name.includes(value.toString());
},
},
];
// 搜索过滤
const tableRef = ref<DataTableInst>();
function filterName(value: string) {
tableRef.value &&
tableRef.value.filter({
name: [value],
});
}
const listData = ref<any[]>([]);
const getPoliciesList = async () => {
const res = await listPolicies();
listData.value = Object.keys(res)
.sort((a, b) => a.localeCompare(b))
.map(key => {
return {
name: key,
content: res[key],
};
});
};
getPoliciesList();
/********************编辑****************/
function rowKey(row: any): string {
return row.name;
}
const checkedKeys = ref<DataTableRowKey[]>([]);
function handleCheck(keys: DataTableRowKey[]) {
checkedKeys.value = keys;
return checkedKeys;
}
const emit = defineEmits(['changePoliciesSuccess']);
const changePolicies = async () => {
Promise.all(
props.checkedKeys.map(item => {
return setUserOrGroupPolicy({
policyName: checkedKeys.value,
userOrGroup: item,
isGroup: true,
});
})
)
.then(() => {
visible.value = false;
messge.success(t('Edit Success'));
emit('changePoliciesSuccess');
})
.catch(() => {
messge.error(t('Edit Failed'));
});
};
})
</script>
<style lang="scss" scoped></style>