update: 关系配置组件替换、弹窗优化

This commit is contained in:
easy 2023-03-07 14:08:49 +08:00
parent 9a7c8d3bc7
commit a57870a2e1
5 changed files with 326 additions and 445 deletions

View File

@ -1,13 +1,15 @@
<template>
<a-modal
v-model:visible="dialog.visible"
:title="dialog.title"
<j-modal
visible
:title="dialogTitle"
width="1000px"
@ok="dialog.handleOk"
@ok="confirm"
@cancel="emits('update:visible', false)"
:confirmLoading="loading"
class="edit-dialog-container"
>
<a-form ref="formRef" :model="form.data" layout="vertical">
<a-form-item
<j-form ref="formRef" :model="form.data" layout="vertical">
<j-form-item
name="id"
:rules="[
{ required: true, message: '请输入标识(ID)' },
@ -18,34 +20,37 @@
<template #label>
<span>标识</span>
<span class="required-icon">*</span>
<a-tooltip placement="top">
<j-tooltip placement="top">
<template #title>
<span>标识ID需与代码中的标识ID一致</span>
</template>
<question-circle-outlined style="color: #00000073" />
</a-tooltip>
<AIcon
type="QuestionCircleOutlined"
style="color: #00000073"
/>
</j-tooltip>
</template>
<a-input
<j-input
v-model:value="form.data.id"
placeholder="请输入标识(ID)"
:maxlength="64"
:disabled="dialog.title === '编辑'"
:disabled="dialogTitle === '编辑'"
/>
</a-form-item>
<a-form-item
</j-form-item>
<j-form-item
name="name"
label="名称"
:rules="[{ required: true, message: '请输入名称' }]"
>
<a-input
<j-input
v-model:value="form.data.name"
placeholder="请输入名称"
:maxlength="64"
/>
</a-form-item>
</a-form>
</j-form-item>
</j-form>
<a-table
<j-table
:columns="table.columns"
:data-source="actionTableData"
:pagination="false"
@ -61,54 +66,41 @@
<template
v-else-if="column.key !== 'index' && column.key !== 'act'"
>
<a-input v-model:value="record[column.key]" />
<j-input v-model:value="record[column.key]" />
</template>
<template v-else-if="column.key === 'act'">
<a-button
<j-button
class="delete-btn"
style="padding: 0"
type="link"
@click="table.clickRemove(index)"
>
<delete-outlined />
</a-button>
<AIcon type="DeleteOutlined" />
</j-button>
</template>
</template>
</a-table>
</j-table>
<div class="pager" v-show="pager.total > pager.pageSize">
<a-select v-model:value="pager.current" style="width: 60px">
<a-select-option v-for="(val, i) in pageArr" :value="i + 1">{{
<j-select v-model:value="pager.current" style="width: 60px">
<j-select-option v-for="(val, i) in pageArr" :value="i + 1">{{
i + 1
}}</a-select-option>
</a-select>
<a-pagination
}}</j-select-option>
</j-select>
<j-pagination
v-model:current="pager.current"
:page-size="pager.pageSize"
:total="pager.total"
/>
</div>
<a-button type="dashed" style="width: 100%" @click="table.clickAdd">
<plus-outlined /> 添加
</a-button>
<template #footer>
<a-button key="back" @click="dialog.visible = false">取消</a-button>
<a-button
key="submit"
type="primary"
:loading="form.loading"
@click="dialog.handleOk"
>确定</a-button
>
</template>
</a-modal>
<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 { DeleteOutlined, PlusOutlined } from '@ant-design/icons-vue';
import { QuestionCircleOutlined } from '@ant-design/icons-vue';
import { Rule } from 'ant-design-vue/es/form';
import {
@ -122,42 +114,41 @@ const defaultAction = [
{ action: 'save', name: '保存', describe: '保存' },
{ action: 'delete', name: '删除', describe: '删除' },
];
const emits = defineEmits(['refresh']);
//
const dialog = reactive({
title: '',
visible: false,
handleOk: () => {
formRef.value?.validate().then(() => {
form.submit();
});
},
//
changeVisible: (status: boolean, defaultForm: any = {}) => {
dialog.title = defaultForm.id ? '编辑' : '新增';
form.data = { name: '', ...defaultForm };
table.data = defaultForm.id ? defaultForm.actions : [...defaultAction];
pager.total = table.data.length;
pager.current = 1;
dialog.visible = status;
nextTick(() => {
formRef.value?.clearValidate();
});
},
});
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({
loading: false,
data: {
name: '',
id: '',
...props.data,
},
rules: {
//
idCheck: (_rule: Rule, id: string, cb: Function) => {
if (!id) return cb('请输入标识(ID)');
if (dialog.title === '编辑') return cb();
if (props.data.id) return cb();
else if (!id) return cb('请输入标识(ID)');
checkId_api({ id })
.then((resp: any) => {
if (resp.status === 200 && !resp.result.passed)
@ -165,16 +156,6 @@ const form = reactive({
else cb();
})
.catch(() => cb('验证失败'));
// return new Promise((resolve) => {
// checkId_api({ id })
// .then((resp: any) => {
// if (resp.status === 200 && !resp.result.passed)
// resolve(resp.result.reason);
// else resolve('');
// })
// .catch(() => resolve(''));
// });
},
},
submit: () => {
@ -182,16 +163,9 @@ const form = reactive({
...form.data,
actions: table.data.filter((item: any) => item.action && item.name),
};
const api =
dialog.title === '编辑' ? editPermission_api : addPermission_api;
const api = props.data.id ? editPermission_api : addPermission_api;
api(params).then((resp) => {
if (resp.status === 200) {
message.error('操作成功');
emits('refresh');
dialog.visible = false;
}
});
return api(params);
},
});
@ -202,25 +176,25 @@ const table = reactive({
dataIndex: 'index',
key: 'index',
width: 80,
align:'center'
align: 'center',
},
{
title: '操作类型',
dataIndex: 'action',
key: 'action',
width: 220
width: 220,
},
{
title: '名称',
dataIndex: 'name',
key: 'name',
width: 220
width: 220,
},
{
title: '说明',
dataIndex: 'describe',
key: 'describe',
width: 220
width: 220,
},
{
title: '操作',
@ -228,7 +202,7 @@ const table = reactive({
key: 'act',
},
],
data: <any>[],
data: props.data.id ? props.data.actions : [...defaultAction],
clickRemove: (index: number) => {
pager.total -= 1;
table.data.splice(index, 1);
@ -251,7 +225,7 @@ const table = reactive({
const pager = reactive({
current: 1,
pageSize: 10,
total: 0,
total: table.data.length,
});
const pageArr = computed(() => {
const maxPageNum = Math.ceil(pager.total / pager.pageSize);
@ -267,11 +241,6 @@ const actionTableData = computed(() => {
return table.data.slice(startIndex, endIndex);
});
//
defineExpose({
openDialog: dialog.changeVisible,
});
</script>
<style lang="less" scoped>

View File

@ -1,29 +0,0 @@
<template>
<span class="status-label-container">
<i
class="circle"
:style="{ background: props.statusValue ? '#52c41a' : '#ff4d4f' }"
></i>
<span>{{ props.statusValue ? '启用' : '禁用' }}</span>
</span>
</template>
<script setup lang="ts">
const props = defineProps<{
statusValue: number;
}>();
</script>
<style lang="less" scoped>
.status-label-container {
display: flex;
align-items: center;
.circle {
display: inline-block;
width: 6px;
height: 6px;
border-radius: 50%;
margin-right: 8px;
}
}
</style>

View File

@ -1,14 +1,17 @@
<template>
<page-container>
<div class="permission-container">
<Search :columns="query.columns" @search="query.search" />
<j-advanced-search
:columns="columns"
@search="(params:any) => (queryParams = params)"
/>
<j-pro-table
ref="tableRef"
:columns="table.columns"
:columns="columns"
:request="getPermission_api"
model="TABLE"
:params="query.params"
:params="queryParams"
:defaultParams="{ sorts: [{ name: 'id', order: 'asc' }] }"
>
<template #headerTitle>
@ -19,12 +22,12 @@
>
<AIcon type="PlusOutlined" />新增
</PermissionButton>
<a-dropdown trigger="hover">
<a-button>批量操作</a-button>
<j-dropdown trigger="hover">
<j-button>批量操作</j-button>
<template #overlay>
<a-menu>
<a-menu-item>
<a-upload
<j-menu>
<j-menu-item>
<j-upload
name="file"
action="#"
accept=".json"
@ -41,9 +44,9 @@
>
导入
</PermissionButton>
</a-upload>
</a-menu-item>
<a-menu-item>
</j-upload>
</j-menu-item>
<j-menu-item>
<PermissionButton
:uhasPermission="`${permission}:export`"
:popConfirm="{
@ -54,16 +57,23 @@
>
导出
</PermissionButton>
</a-menu-item>
</a-menu>
</j-menu-item>
</j-menu>
</template>
</a-dropdown>
</j-dropdown>
</template>
<template #status="slotProps">
<StatusLabel :status-value="slotProps.status" />
<BadgeStatus
:status="slotProps.status"
:text="slotProps.status ? '启用' : '禁用'"
:statusNames="{
1: 'success',
0: 'error',
}"
></BadgeStatus>
</template>
<template #action="slotProps">
<a-space :size="16">
<j-space :size="16">
<PermissionButton
:uhasPermission="`${permission}:update`"
type="link"
@ -113,13 +123,16 @@
>
<AIcon type="DeleteOutlined" />
</PermissionButton>
</a-space>
</j-space>
</template>
</j-pro-table>
<div class="dialogs">
<EditDialog ref="editDialogRef" @refresh="table.refresh" />
</div>
<EditDialog
v-if="dialog.visible"
v-model:visible="dialog.visible"
:data="dialog.selectItem"
@refresh="table.refresh"
/>
</div>
</page-container>
</template>
@ -127,7 +140,6 @@
<script setup lang="ts">
import PermissionButton from '@/components/PermissionButton/index.vue';
import EditDialog from './components/EditDialog.vue';
import StatusLabel from './components/StatusLabel.vue';
import { message } from 'ant-design-vue';
import {
getPermission_api,
@ -141,11 +153,7 @@ import { usePermissionStore } from '@/store/permission';
const permission = 'system/Permission';
const hasPermission = usePermissionStore().hasPermission;
const editDialogRef = ref(); //
const tableRef = ref<Record<string, any>>({}); //
//
const query = reactive({
columns: [
const columns = [
{
title: '标识',
dataIndex: 'id',
@ -171,7 +179,6 @@ const query = reactive({
key: 'status',
ellipsis: true,
search: {
rename: 'status',
type: 'select',
options: [
{
@ -184,44 +191,25 @@ const query = reactive({
},
],
},
},
],
params: {},
search: (params: object) => {
query.params = params;
},
});
//
const table = reactive({
columns: [
{
title: '标识',
dataIndex: 'id',
key: 'id',
},
{
title: '名称',
dataIndex: 'name',
key: 'name',
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
scopedSlots: true,
},
{
title: '操作',
dataIndex: 'action',
key: 'action',
width: '200px',
fixed: 'right',
scopedSlots: true,
},
],
tableData: [],
];
const queryParams = ref({});
//
const tableRef = ref<Record<string, any>>({}); //
const table = {
//
openDialog: (row: object | undefined = {}) => {
editDialogRef.value.openDialog(true, row);
dialog.selectItem = { ...row };
dialog.visible = true;
},
//
clickImport: (file: File) => {
@ -248,7 +236,7 @@ const table = reactive({
clickExport: () => {
const params = {
paging: false,
...query.params,
...queryParams,
};
exportPermission_api(params).then((resp) => {
if (resp.status === 200) {
@ -283,12 +271,16 @@ const table = reactive({
refresh: () => {
tableRef.value.reload();
},
};
const dialog = reactive({
selectItem: {},
visible: false,
});
</script>
<style lang="less" scoped>
.permission-container {
.ant-dropdown-trigger {
margin-left: 12px;
}

View File

@ -1,14 +1,16 @@
<template>
<a-modal
v-model:visible="dialog.visible"
:title="dialog.title"
<j-modal
visible
:title="dialogTitle"
:maskClosable="false"
width="675px"
@ok="dialog.handleOk"
@ok="confirm"
@cancel="emits('update:visible', false)"
:confirmLoading="loading"
class="edit-dialog-container"
>
<a-form ref="formRef" :model="form.data" layout="vertical">
<a-form-item
<j-form ref="formRef" :model="form.data" layout="vertical">
<j-form-item
label="名称"
name="name"
:rules="[
@ -16,13 +18,13 @@
{ max: 64, message: '最多可输入64个字符' },
]"
>
<a-input
<j-input
v-model:value="form.data.name"
placeholder="请输入名称"
:maxlength="64"
/>
</a-form-item>
<a-form-item
</j-form-item>
<j-form-item
name="relation"
label="标识"
:rules="[
@ -31,76 +33,66 @@
{ validator: form.rules.checkRelation, trigger: 'change' },
]"
>
<a-input
<j-input
v-model:value="form.data.relation"
placeholder="请输入标识"
:maxlength="64"
:disabled="!!form.data.id"
/>
</a-form-item>
</j-form-item>
<a-row :gutter="24">
<a-col :span="12">
<a-form-item
<j-row :gutter="24">
<j-col :span="12">
<j-form-item
name="objectType"
label="关联方"
:rules="[{ required: true, message: '请选择关联方' }]"
>
<a-select
<j-select
v-model:value="form.data.objectType"
:disabled="!!form.data.id"
>
<a-select-option
<j-select-option
v-for="item in form.objectList"
:value="item.id"
>{{ item.name }}</a-select-option
>{{ item.name }}</j-select-option
>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item
</j-select>
</j-form-item>
</j-col>
<j-col :span="12">
<j-form-item
name="targetType"
label="标识"
label="被关联方"
:rules="[{ required: true, message: '请选择被关联方' }]"
>
<a-select
<j-select
v-model:value="form.data.targetType"
:disabled="!!form.data.id"
>
<a-select-option
v-for="item in form.targetList"
<j-select-option
v-for="item in targetList"
:value="item.id"
>{{ item.name }}</a-select-option
>{{ item.name }}</j-select-option
>
</a-select>
</a-form-item>
</a-col>
</a-row>
<a-form-item
</j-select>
</j-form-item>
</j-col>
</j-row>
<j-form-item
name="description"
label="说明"
:rules="[{ max: 200, message: '最多可输入200个字符' }]"
>
<a-textarea
<j-textarea
v-model:value="form.data.description"
placeholder="请输入说明"
show-count
:maxlength="200"
/>
</a-form-item>
</a-form>
<template #footer>
<a-button key="back" @click="dialog.visible = false">取消</a-button>
<a-button
key="submit"
type="primary"
:loading="form.loading"
@click="dialog.handleOk"
>确定</a-button
>
</template>
</a-modal>
</j-form-item>
</j-form>
</j-modal>
</template>
<script setup lang="ts">
@ -112,53 +104,45 @@ import {
addRelation_api,
editRelation_api,
} from '@/api/system/relationship';
import { dictItemType } from '../../DataSource/typing';
const emits = defineEmits(['refresh']);
const emits = defineEmits(['refresh', 'update:visible']);
const props = defineProps<{
visible: boolean;
data: formType;
}>();
//
const dialog = reactive({
title: '',
visible: false,
handleOk: () => {
formRef.value?.validate().then(() => {
form.submit();
});
},
//
changeVisible: (status: boolean, defaultForm: formType) => {
dialog.title = defaultForm.id ? '编辑' : '新增';
form.data = { ...defaultForm };
dialog.visible = status;
nextTick(() => {
formRef.value?.clearValidate();
});
},
});
//
const initForm: formType = {
name: '',
relation: '',
objectType: '',
targetType: '',
description: '',
const loading = ref(false);
const dialogTitle = computed(() => (props.data.id ? '编辑' : '新增'));
const confirm = () => {
loading.value = true;
formRef.value
?.validate()
.then(() => form.submit())
.then((resp: any) => {
if (resp.status === 200) {
message.success('操作成功');
emits('refresh');
emits('update:visible', false);
}
})
.finally(() => (loading.value = false));
};
const formRef = ref<FormInstance>();
const form = reactive({
loading: false,
data: {} as formType,
data: props.data,
rules: {
checkRelation: (_rule: Rule, value: string): any => {
if (!value) return '';
const reg = new RegExp('^[0-9a-zA-Z_\\\\-]+$');
if (reg.test(value)) return Promise.resolve();
else
return Promise.reject(
'标识只能由数字、字母、下划线、中划线组成',
);
return reg.test(value)
? Promise.resolve()
: Promise.reject('标识只能由数字、字母、下划线、中划线组成');
},
},
objectList: [] as any[],
targetList: [] as any[],
getObjectList: () => {
getObjectList_api().then((resp: any) => {
@ -166,43 +150,23 @@ const form = reactive({
});
},
submit: () => {
formRef.value?.validate().then(() => {
const params = {
...form.data,
objectTypeName: form.objectList.find(
(item) => item.id === form.data.objectType,
).name,
targetTypeName: form.targetList.find(
(item) => item.id === form.data.targetType,
).name,
targetTypeName: targetList.value.find(
(item: dictItemType) => item.id === form.data.targetType,
)?.name,
};
const api =
dialog.title === '编辑'
? editRelation_api
: addRelation_api;
api(params).then((resp: any) => {
if (resp.status === 200) {
message.success('操作成功');
emits('refresh');
dialog.visible = false;
}
});
});
const api = props.data.id ? editRelation_api : addRelation_api;
return api(params);
},
});
form.getObjectList();
watch(
() => form.data.objectType,
(n) => {
form.targetList = n === 'device' ? [{ id: 'user', name: '用户' }] : [];
},
const targetList = computed(() =>
form.data.objectType === 'device' ? [{ id: 'user', name: '用户' }] : [],
);
//
defineExpose({
openDialog: dialog.changeVisible,
});
form.getObjectList();
type formType = {
name: string;
@ -213,5 +177,3 @@ type formType = {
id?: string;
};
</script>
<style scoped></style>

View File

@ -1,14 +1,17 @@
<template>
<page-container>
<div class="relationship-container">
<Search :columns="query.columns" @search="query.search" />
<j-advanced-search
:columns="columns"
@search="(params:any)=>queryParams = {...params}"
/>
<j-pro-table
ref="tableRef"
:columns="table.columns"
:columns="columns"
:request="getRelationshipList_api"
model="TABLE"
:params="query.params.value"
:params="queryParams"
:defaultParams="{
sorts: [{ name: 'createTime', order: 'desc' }],
}"
@ -23,7 +26,7 @@
</PermissionButton>
</template>
<template #action="slotProps">
<a-space :size="16">
<j-space :size="16">
<PermissionButton
:uhasPermission="`${permission}:update`"
type="link"
@ -47,11 +50,16 @@
>
<AIcon type="DeleteOutlined" />
</PermissionButton>
</a-space>
</j-space>
</template>
</j-pro-table>
<EditDialog ref="editDialogRef" @refresh="table.refresh" />
<EditDialog
v-if="dialog.visible"
v-model:visible="dialog.visible"
:data="dialog.selectRow"
@refresh="table.refresh"
/>
</div>
</page-container>
</template>
@ -67,8 +75,7 @@ import EditDialog from './components/EditDialog.vue';
const permission = 'system/Relationship';
const query = {
columns: [
const columns = [
{
title: '名称',
dataIndex: 'name',
@ -89,23 +96,24 @@ const query = {
type: 'select',
options: [
{
label: '用',
value: 1,
label: '',
value: '用户',
},
{
label: '禁用',
value: 0,
label: '设备',
value: '设备',
},
],
},
},
{
title: '被关联方',
dataIndex: 'targetType',
key: 'targetType',
dataIndex: 'targetTypeName',
key: 'targetTypeName',
ellipsis: true,
fixed: 'left',
search: {
rename: 'targetType',
type: 'select',
options: [
{
@ -125,47 +133,21 @@ const query = {
type: 'string',
},
},
],
params: ref({}),
search: (params: object) => {
query.params.value = params;
},
};
const editDialogRef = ref(); //
const tableRef = ref<Record<string, any>>({}); //
const table = {
columns: [
{
title: '名称',
dataIndex: 'name',
key: 'name',
},
{
title: '关联方',
dataIndex: 'objectTypeName',
key: 'objectTypeName',
},
{
title: '被关联方',
dataIndex: 'targetTypeName',
key: 'targetTypeName',
},
{
title: '说明',
dataIndex: 'description',
key: 'description',
},
{
title: '操作',
dataIndex: 'action',
key: 'action',
scopedSlots: true,
},
],
];
const queryParams = ref({});
const tableRef = ref<Record<string, any>>({}); //
const table = {
//
openDialog: (row: object | undefined = {}) => {
editDialogRef.value.openDialog(true, row);
dialog.selectRow = { ...row };
dialog.visible = true;
},
//
clickDel: (row: any) => {
@ -181,6 +163,11 @@ const table = {
tableRef.value.reload();
},
};
const dialog = reactive({
selectRow: {} as any,
visible: false,
});
</script>
<style lang="less" scoped>