<script setup lang="tsx">
|
import type { FormInst, FormRules } from 'naive-ui'
|
import {
|
NButton,
|
NForm,
|
NFormItem,
|
NInput,
|
NModal,
|
NSelect,
|
NSpace,
|
useDialog,
|
} from 'naive-ui'
|
|
import { addRole, editRole, fetchPermissionGroupPage } from '@/service'
|
|
const props = defineProps<{
|
visible: boolean
|
mode: 'add' | 'edit' | 'view'
|
rowData?: any
|
}>()
|
|
const emit = defineEmits(['update:visible', 'success'])
|
|
const { t } = useI18n()
|
|
const dialog = useDialog()
|
|
const formRef = ref<FormInst>()
|
const loading = ref(false)
|
|
// 下拉框展开状态
|
const isSelectOpen = ref(false)
|
|
// 弹窗标题
|
const modalTitle = computed(() => {
|
return t(`roleManagement.modal.${props.mode}`)
|
})
|
|
// 权限组选项
|
const permissionGroupOptions = ref<any[]>([])
|
|
async function getPermissionGroups() {
|
const { data } = await fetchPermissionGroupPage({ pageNum: 1, pageSize: 1000 })
|
if (data) {
|
permissionGroupOptions.value = (data.records || []).map((item: any) => ({
|
label: item.groupName,
|
value: item.id,
|
}))
|
}
|
}
|
|
// 表单数据
|
const formModel = ref({
|
roleName: '',
|
groupId: null as number | null,
|
remarks: '',
|
})
|
|
// 重置表单
|
function resetForm() {
|
formModel.value = {
|
roleName: '',
|
groupId: null,
|
remarks: '',
|
}
|
formRef.value?.restoreValidation()
|
}
|
|
// 打开弹窗
|
function openModal() {
|
resetForm()
|
getPermissionGroups()
|
if (props.mode === 'edit' && props.rowData) {
|
formModel.value = {
|
roleName: props.rowData.roleName || '',
|
groupId: props.rowData.groupId || null,
|
remarks: props.rowData.remarks || '',
|
}
|
}
|
}
|
|
// 关闭弹窗
|
function closeModal() {
|
emit('update:visible', false)
|
}
|
|
function hasUnsavedInput() {
|
if (props.mode !== 'add')
|
return false
|
|
const roleName = (formModel.value.roleName ?? '').trim()
|
const remarks = (formModel.value.remarks ?? '').trim()
|
return !!roleName || !!formModel.value.groupId || !!remarks
|
}
|
|
function handleRequestClose() {
|
if (!hasUnsavedInput()) {
|
closeModal()
|
return
|
}
|
|
dialog.warning({
|
title: t('roleManagement.modal.closeConfirm.title'),
|
content: t('roleManagement.modal.closeConfirm.content'),
|
positiveText: t('roleManagement.modal.closeConfirm.confirm'),
|
negativeText: t('roleManagement.modal.closeConfirm.continue'),
|
maskClosable: false,
|
autoFocus: false,
|
onPositiveClick: () => {
|
closeModal()
|
},
|
})
|
}
|
|
// 表单验证规则
|
const rules: FormRules = {
|
roleName: [
|
{ required: true, message: t('roleManagement.modal.validation.roleNameRequired'), trigger: ['blur', 'input'] },
|
{ min: 1, max: 20, message: t('roleManagement.modal.validation.roleNameLength'), trigger: ['blur', 'input'] },
|
{
|
pattern: /^[\u4E00-\u9FA5\w]+$/u,
|
message: t('roleManagement.modal.validation.roleNameFormat'),
|
trigger: ['blur', 'input'],
|
},
|
],
|
groupId: [
|
{ required: true, message: t('roleManagement.modal.validation.permissionGroupRequired'), trigger: ['blur', 'change'] },
|
],
|
remarks: [
|
{ max: 100, message: t('roleManagement.modal.validation.remarksLength'), trigger: ['blur', 'input'] },
|
{
|
validator: (rule, value) => {
|
if (!value)
|
return true
|
// 支持中英文、数字、空格、常用标点
|
const pattern = /^[\u4E00-\u9FA5\s\uFF00-\uFFEF\x21-\x7E]*$/u
|
if (!pattern.test(value)) {
|
return new Error(t('roleManagement.modal.validation.remarksFormat'))
|
}
|
return true
|
},
|
trigger: ['blur', 'input'],
|
},
|
],
|
}
|
|
// 提交表单
|
async function handleSubmit() {
|
if (!formRef.value)
|
return
|
|
await formRef.value.validate()
|
|
loading.value = true
|
try {
|
const params = {
|
...formModel.value,
|
}
|
|
if (props.mode === 'add') {
|
const res = await addRole(params)
|
if (res.code === 200) {
|
window.$message.success(t('roleManagement.modal.messages.addSuccess'))
|
window.sessionStorage.setItem('roleManagementNeedRefresh', '1')
|
emit('success')
|
closeModal()
|
}
|
}
|
else if (props.mode === 'edit') {
|
const res = await editRole({
|
...params,
|
id: props.rowData.id,
|
})
|
if (res.code === 200) {
|
window.$message.success(t('roleManagement.modal.messages.editSuccess'))
|
window.sessionStorage.setItem('roleManagementNeedRefresh', '1')
|
emit('success')
|
closeModal()
|
}
|
}
|
}
|
catch (error) {
|
console.error(error)
|
}
|
finally {
|
loading.value = false
|
}
|
}
|
|
// 监听visible变化
|
watch(() => props.visible, (visible) => {
|
if (visible) {
|
openModal()
|
}
|
})
|
</script>
|
|
<template>
|
<NModal
|
:show="visible" :mask-closable="false" preset="card" :title="modalTitle" style="width: 400px" :segmented="{
|
content: true,
|
action: true,
|
}" :content-style="{
|
padding: '16px 24px 0px 24px',
|
}" @close="handleRequestClose"
|
>
|
<NForm
|
ref="formRef" :model="formModel" :rules="rules" label-placement="top" label-width="120" :auto-focus="false"
|
require-mark-placement="left" :show-require-mark="true"
|
>
|
<NGrid :cols="1" :x-gap="24" :y-gap="8">
|
<NGridItem>
|
<NFormItem :label="t('roleManagement.modal.form.roleName')" path="roleName" required>
|
<NInput
|
v-model:value="formModel.roleName" :placeholder="t('roleManagement.modal.placeholder.roleName')" :disabled="mode === 'view'" :maxlength="20"
|
|
/>
|
</NFormItem>
|
</NGridItem>
|
<NGridItem>
|
<NFormItem :label="t('roleManagement.modal.form.permissionGroup')" path="groupId" required>
|
<NSelect
|
v-model:value="formModel.groupId" :options="permissionGroupOptions" :placeholder="t('roleManagement.modal.placeholder.permissionGroup')"
|
:disabled="mode === 'view'" @update:show="isSelectOpen = $event"
|
>
|
<template #arrow>
|
<img
|
src="https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/e120f81c-9f15-4e1a-9938-22252898edf9.png"
|
class="arrow-icon" :class="{ 'arrow-icon--open': isSelectOpen }"
|
style="width: 16px;height: 16px;"
|
alt="arrow"
|
>
|
</template>
|
</NSelect>
|
</NFormItem>
|
</NGridItem>
|
<NGridItem>
|
<NFormItem :label="t('roleManagement.modal.form.remarks')" path="remarks">
|
<NInput
|
v-model:value="formModel.remarks" type="textarea" :placeholder="t('roleManagement.modal.placeholder.remarks')" :disabled="mode === 'view'"
|
:autosize="{ minRows: 3, maxRows: 5 }" :maxlength="100"
|
/>
|
</NFormItem>
|
</NGridItem>
|
</NGrid>
|
</NForm>
|
|
<template #action>
|
<NSpace justify="end" :size="8">
|
<NButton style="padding: 7px 29px; border-radius: 4px;" @click="handleRequestClose">
|
{{ $t('roleManagement.modal.buttons.close') }}
|
</NButton>
|
<NButton
|
v-if="mode !== 'view'" type="primary" :loading="loading" style="padding: 7px 29px; border-radius: 4px;"
|
@click="handleSubmit"
|
>
|
{{ $t('roleManagement.modal.buttons.save') }}
|
</NButton>
|
</NSpace>
|
</template>
|
</NModal>
|
</template>
|
|
<style scoped lang="scss">
|
:deep(.n-form-item-label) {
|
padding-bottom: 8px !important;
|
}
|
|
:deep(.n-card__action) {
|
background-color: transparent !important;
|
}
|
</style>
|