iot-ui-vue/src/views/system/Permission/components/EditDialog.vue

327 lines
10 KiB
Vue

<template>
<j-modal
visible
:title="dialogTitle"
width="1000px"
@ok="confirm"
@cancel="emits('update:visible', false)"
:confirmLoading="loading"
destroyOnClose
class="edit-dialog-container"
>
<j-form ref="formRef" :model="form.data" layout="vertical">
<j-form-item
name="id"
:rules="[
{ required: true, message: '' },
{ validator: form.rules.idCheck, trigger: 'blur' },
]"
class="question-item"
>
<template #label>
<span>标识</span>
<span class="required-icon">*</span>
<j-tooltip placement="top">
<template #title>
<span>标识ID需与代码中的标识ID一致</span>
</template>
<AIcon
type="QuestionCircleOutlined"
style="color: #00000073"
/>
</j-tooltip>
</template>
<j-input
v-model:value="form.data.id"
placeholder="请输入标识(ID)"
:disabled="dialogTitle === '编辑'"
/>
</j-form-item>
<j-form-item
name="name"
label="名称"
:rules="[
{ required: true, message: '请输入名称' },
{
max: 64,
message: '最多可输入64个字符',
},
]"
>
<j-input
v-model:value="form.data.name"
placeholder="请输入名称"
/>
</j-form-item>
<!-- 操作权限列表 -->
<j-table
:columns="table.columns"
:data-source="form.data.actionTableData"
:pagination="false"
>
<template #bodyCell="{ column, record, index }">
<template v-if="column.key === 'index'">
{{
`#${
(pager.current - 1) * pager.pageSize +
(index + 1)
}.`
}}
</template>
<template
v-else-if="
column.key !== 'index' && column.key !== 'act'
"
>
<j-form-item
:name="['actionTableData', index, column.key]"
:rules="[
{
required: column.key !== 'describe',
message: `请输入${column.title}`,
},
{
max: 64,
message: '最多可输入64个字符',
},
]"
>
<j-input v-model:value="record[column.key]" />
</j-form-item>
</template>
<template v-else-if="column.key === 'act'">
<j-button
class="delete-btn"
style="padding: 0"
type="link"
@click="table.clickRemove(index)"
>
<AIcon type="DeleteOutlined" />
</j-button>
</template>
</template>
</j-table>
</j-form>
<div class="pager" v-show="pager.total > pager.pageSize">
<j-select v-model:value="pager.current" style="width: 60px">
<j-select-option v-for="(val, i) in pageArr" :value="i + 1">{{
i + 1
}}</j-select-option>
</j-select>
<j-pagination
v-model:current="pager.current"
:page-size="pager.pageSize"
:total="pager.total"
/>
</div>
<j-button type="dashed" style="width: 100%" @click="table.clickAdd">
<AIcon type="PlusOutlined" /> 添加
</j-button>
</j-modal>
</template>
<script setup lang="ts">
import { FormInstance, message } from 'ant-design-vue';
import { Rule } from 'ant-design-vue/es/form';
import {
checkId_api,
editPermission_api,
addPermission_api,
} from '@/api/system/permission';
import { cloneDeep } from 'lodash-es';
const defaultAction = [
{ action: 'query', name: '查询', describe: '查询' },
{ action: 'save', name: '保存', describe: '保存' },
{ action: 'delete', name: '删除', describe: '删除' },
];
const emits = defineEmits(['refresh', 'update:visible']);
const props = defineProps<{
data: any;
visible: boolean;
}>();
const loading = ref(false);
const dialogTitle = computed(() => (props.data?.id ? '编辑' : '新增'));
const confirm = () => {
loading.value = true;
formRef.value
?.validate()
.then(() => form.submit())
.then((resp) => {
if (resp.status === 200) {
message.success('操作成功');
emits('refresh');
emits('update:visible', false);
}
})
.finally(() => (loading.value = false));
};
// 表单相关
const formRef = ref<FormInstance>();
const form = reactive({
data: {
name: '',
id: '',
...props?.data,
actionTableData: computed(() => {
const startIndex = (pager.current - 1) * pager.pageSize;
const endIndex = Math.min(
pager.current * pager.pageSize,
table.data.length,
);
console.log(startIndex, endIndex);
return table.data.slice(startIndex, endIndex);
}),
},
rules: {
// 校验标识是否可用
idCheck: async (_rule: Rule, id: string): Promise<any> => {
if (!id) return Promise.reject('请输入标识(ID)');
else if (id.length > 64)
return Promise.reject('最多可输入64个字符');
else if (props.data?.id && props.data?.id === form.data?.id)
return Promise.resolve();
else {
const resp: any = await checkId_api({ id });
if (resp.result.passed) return Promise.resolve();
else return Promise.reject(resp.result.reason);
}
},
},
submit: () => {
const params = {
...form.data,
actions: table.data.filter((item: any) => item.action && item.name),
};
const api = props.data?.id ? editPermission_api : addPermission_api;
return api(params);
},
});
const table = reactive({
columns: <any>[
{
title: '-',
dataIndex: 'index',
key: 'index',
width: 80,
align: 'center',
},
{
title: '操作类型',
dataIndex: 'action',
key: 'action',
width: 220,
},
{
title: '名称',
dataIndex: 'name',
key: 'name',
width: 220,
},
{
title: '说明',
dataIndex: 'describe',
key: 'describe',
width: 220,
},
{
title: '操作',
dataIndex: 'act',
key: 'act',
},
],
data: props.data?.id ? cloneDeep([...(props.data?.actions || [])]) : [...defaultAction],
clickRemove: (index: number) => {
pager.total -= 1;
table.data.splice(index, 1);
// 当删除的刚好为本页的最后一项时,返回到上一页
if (pager.current > 1 && pager.total % pager.pageSize === 0)
pager.current -= 1;
},
clickAdd: () => {
table.data.push({});
pager.total += 1;
// 当添加的项需要新加一页才能显示时,跳转到最后一页
if (pager.total % pager.pageSize === 1) {
pager.current = Math.ceil(pager.total / pager.pageSize);
}
},
});
const pager = reactive({
current: 1,
pageSize: 10,
total: table.data.length,
});
const pageArr = computed(() => {
const maxPageNum = Math.ceil(pager.total / pager.pageSize);
return new Array(maxPageNum).fill(1);
});
// const actionTableData = computed(() => {
// const startIndex = (pager.current - 1) * pager.pageSize;
// const endIndex = Math.min(
// pager.current * pager.pageSize,
// table.data.length,
// );
// console.log(startIndex, endIndex);
// return table.data.slice(startIndex, endIndex);
// });
</script>
<style lang="less" scoped>
.edit-dialog-container {
.question-item {
:deep(.ant-form-item-required) {
&::before {
display: none;
}
.required-icon {
display: inline-block;
margin-right: 4px;
margin-left: 2px;
color: #ff4d4f;
font-size: 14px;
font-family: SimSun, sans-serif;
line-height: 1;
}
}
}
.ant-table {
color: #ff4d4f;
.ant-table-tbody {
color: #ff4d4f;
}
}
.delete-btn {
color: #000000d9;
&:hover {
color: #415ed1;
}
}
.pager {
display: flex;
justify-content: center;
margin-bottom: 12px;
.ant-pagination {
margin-left: 8px;
:deep(.ant-pagination-item) {
display: none;
}
}
}
}
</style>