Combined with working examples, a multi-functional universal pop-up window component is encapsulated
Technology used: Vue3.2 + arco-design + ts
Function implementation: Realize the addition, deletion, modification and query of tables, realize the encapsulation of pop-up windows, and one pop-up window can adapt to the three functional points of addition, deletion and modification
The general idea is as follows:
//1. The sub-component exposure method opens its own pop-up window, using the defineExpose method. The parent component obtains the sub-component exposure method through the ref of the sub-component and calls it
//2. The parent component tells the child component what operations it wants to perform through the parent-to-child method, and then the child component determines
//3. After the child component implements the relevant functions, it needs to trigger the emit event and tell the parent component. The parent component triggers the relevant events to update the data.
If you want to know how to encapsulate the front-end development of components, you can take a closer look. The encapsulation should be very brief and easy to understand
The parent component code is as follows: You can take a closer look at the details. The relevant interfaces may need to call other people’s interfaces or mock data themselves
<template>
<a-space direction="vertical" :size="20" fill>
<div class="header">
<a-space fill>
<div class="search">
<a-input
v-model="searchKey"
:style="{ width: '320px' }"
:placeholder="$t('settings.search')"
class="search"
allow-clear
@clear="searchIdenInfo"
@keyup.enter="searchIdenInfo"
>
<template #prefix>
<a-button type="text" shape="circle" @click="searchIdenInfo">
<template #icon>
<SvgIcon name="search" />
</template>
</a-button>
</template>
</a-input>
</div>
<div class="btns">
<a-button
type="primary"
:disabled="selectedKeys.length === 0"
@click="delChooseInfo"
>
{<!-- -->{<!-- --> $t('basicData.mailList.identityInfo.del') }}
</a-button>
<a-button type="primary" @click="addIdenInfo">
{<!-- -->{<!-- --> $t('basicData.mailList.identityInfo.add') }}
</a-button>
</div>
</a-space>
</div>
<div class="table">
<div class="theTable">
<a-table
ref="tableRef"
v-model:selectedKeys="selectedKeys"
row-key="guid"
:columns="columns"
:data="IndeListdata"
:loading="loading"
:bordered="{ headerCell: true, wrapper: false }"
:row-selection="rowSelection"
:scroll="{ x: '100%', y: '90%' }"
:hoverable="false"
:pagination="false"
>
<!-- Siren slot -->
<template #siren="{ record }">
<a-link @click="getPolice(record)">{<!-- -->{<!-- --> record.siren }}</a-link>
</template>
<!-- Operation slot -->
<template #optional="{ record }">
<div class="btns">
<a-button
shape="circle"
:disabled="record.judge_sync_edit !== 1"
@click="editRow(record)"
>
<template #icon>
<SvgIcon name="edit" />
</template>
</a-button>
<a-button
shape="circle"
:disabled="record.judge_sync_edit !== 1"
@click="delRow(record)"
>
<template #icon>
<SvgIcon name="delete" />
</template>
</a-button>
</div>
</template>
</a-table>
</div>
<div class="pagination">
<a-pagination
ref="paginationRef"
show-total
show-jumper
show-page-size
:total="pageTotal"
:default-page-size="defaultPageSize"
:page-size-options="pageSizeOption"
:current="currentPage.current"
@change="pageChange"
@page-size-change="pageSizeChange"
/>
</div>
</div>
</a-space>
<IdenInfoModal
ref="IdenInfoModelRef"
:operation-type="operationType"
@refreshInfo="searchIdenInfo"
/>
</template>
<script lang="ts" setup>
import {<!-- --> ref, reactive, computed } from 'vue';
import {<!-- --> Message } from '@arco-design/web-vue';
import {<!-- --> useI18n } from 'vue-i18n';
import {<!-- --> Random } from 'mockjs';
import {<!-- --> configLoginInfoStore } from '@/store';
import request from '@/utils/request';
import useLoading from '@/hooks/loading';
import IdenInfoModal from './IdenInfoModal.vue';
const {<!-- --> t } = useI18n();
const {<!-- --> loading, setLoading } = useLoading(true);
const configLoginStore = configLoginInfoStore();
const IdenInfoModelRef = ref(null);
const searchKey = ref<string>('');
const selectedKeys = ref([]);
type operType = 'add' | 'edit' | 'del' | 'view' | 'delChoose';
const operationType = ref<operType>('add');
const rowSelection = reactive<any>({<!-- -->
type: 'checkbox',
showCheckedAll: true,
});
//Default display number
const defaultPageSize = 15;
//Display the number of items
const pageSizeOption = [10, 15, 20, 30, 40, 50];
//Display the total number of items
const pageTotal = ref<number>(0);
//Current page number, currently displayed quantity
const currentPage = ref({<!-- -->
current: 1,
pageSize: 15,
});
const columns = computed<any>(() => {<!-- -->
return [
{<!-- -->
title: t('basicData.mailList.identityInfo.sysId'),
dataIndex: 'system_id',
align: 'center',
ellipsis: true,
tooltip: true,
width: 100,
},
{<!-- -->
title: t('basicData.mailList.identityInfo.personId'),
dataIndex: 'id_no',
align: 'center',
ellipsis: true,
width: 100,
},
{<!-- -->
title: t('basicData.mailList.identityInfo.policeID'),
slotName: 'siren',
align: 'center',
width: 100,
},
{<!-- -->
title: t('basicData.mailList.identityInfo.policeName'),
dataIndex: 'siren_name',
align: 'center',
ellipsis: true,
tooltip: true,
width: 100,
},
{<!-- -->
title: t('basicData.mailList.identityInfo.departmentId'),
dataIndex: 'department_id',
align: 'center',
ellipsis: true,
tooltip: true,
width: 100,
},
{<!-- -->
title: t('basicData.mailList.identityInfo.departmentAll'),
dataIndex: 'department_full_name',
align: 'center',
ellipsis: true,
tooltip: true,
width: 100,
},
{<!-- -->
title: t('basicData.mailList.identityInfo.departmentShort'),
dataIndex: 'department_name',
align: 'center',
ellipsis: true,
tooltip: true,
width: 100,
},
{<!-- -->
title: t('basicData.mailList.identityInfo.operation'),
slotName: 'optional',
align: 'center',
fixed: 'right',
width: 100,
},
];
});
const IndeListdata = ref([]);
// Get the list
const searchIdenInfo = async () => {<!-- -->
setLoading(true);
const params = {<!-- -->
realm: configLoginStore.getRealm,
cmd_name: 'staff_identifier_request',
cmd_guid: Random.guid(),
is_fuzzy_qry: 1,
page_sizes: currentPage.value.pageSize,
page_index: currentPage.value.current,
querykey: searchKey.value,
};
const data: any = await request(params);
if (data.result === 0) {<!-- -->
IndeListdata.value = data.staff_identifier_list;
pageTotal.value = data.count ? data.count : 0;
setLoading(false);
}
console.log(data);
};
// Get police details
const getPolice = (item) => {<!-- -->
operationType.value = 'view';
IdenInfoModelRef.value.handleClick(item);
};
//Add identity information
const addIdenInfo = () => {<!-- -->
operationType.value = 'add';
IdenInfoModelRef.value.handleClick();
};
// Get selected person information
const isChecked = ref([]);
const getAllChecked = () => {<!-- -->
isChecked.value = IndeListdata.value
.map((item) => {<!-- -->
if (selectedKeys.value.includes(item.guid)) {<!-- -->
return {<!-- -->
puc_id: configLoginStore.getPucId,
realm: configLoginStore.getRealm,
system_id: item.system_id,
siren: item.siren,
};
}
return null;
})
.filter((v) => v);
};
// Delete the selected identity information (multiple selection delete)
const delChooseInfo = () => {<!-- -->
operationType.value = 'delChoose';
getAllChecked();
IdenInfoModelRef.value.handleClick(isChecked.value);
};
//Edit current identity information
const editRow = (item) => {<!-- -->
operationType.value = 'edit';
IdenInfoModelRef.value.handleClick(item);
};
//Delete current identity information
const delRow = (item) => {<!-- -->
operationType.value = 'del';
IdenInfoModelRef.value.handleClick(item);
};
// paging
const pageChange = (current: number) => {<!-- -->
currentPage.value.current = current;
searchIdenInfo();
};
const pageSizeChange = (pageSize: number) => {<!-- -->
currentPage.value.pageSize = pageSize;
searchIdenInfo();
};
defineExpose({<!-- -->
searchIdenInfo,
});
</script>
<style lang="less" scoped>
</style>
Subcomponent code
<template>
<a-modal
v-model:visible="visible"
:title="title"
title-align="start"
:ok-text="
operationType !== 'del' & amp; & amp; operationType !== 'delChoose'
? $t('basicData.mailList.identityInfo.save')
: $t('basicData.mailList.identityInfo.sure')
"
:cancel-text="$t('basicData.mailList.identityInfo.cancel')"
:width="
operationType !== 'del' & amp; & amp; operationType !== 'delChoose'
? '680px'
: '440px'
"
:footer="operationType !== 'view'"
@cancel="handleCancel"
@before-ok="handleBeforeOk"
>
<a-form
v-if="operationType !== 'del' & amp; & amp; operationType !== 'delChoose'"
ref="formRef"
class="form-modal"
layout="vertical"
:model="form"
:rules="rules"
:disabled="operationType === 'view'"
>
<a-form-item
:disabled="operationType === 'edit' || operationType === 'view'"
field="system_id"
:label="$t('basicData.mailList.identityInfo.sysId')"
>
<a-select v-model="form.system_id" allow-clear>
<a-option
v-for="item of systemList"
:key="item.label"
:value="item.value"
:label="item.label"
/>
</a-select>
</a-form-item>
<a-form-item
:disabled="operationType === 'edit' || operationType === 'view'"
field="siren"
:label="$t('basicData.mailList.identityInfo.policeID')"
>
<a-input v-model="form.siren" />
</a-form-item>
<a-form-item
field="id_no"
:label="$t('basicData.mailList.identityInfo.personId')"
>
<a-input v-model="form.id_no" />
</a-form-item>
<a-form-item
field="siren_name"
:label="$t('basicData.mailList.identityInfo.policeName')"
>
<a-input v-model="form.siren_name" />
</a-form-item>
<a-form-item
field="department_id"
:label="$t('basicData.mailList.identityInfo.departmentId')"
>
<a-input v-model="form.department_id" />
</a-form-item>
<a-form-item
field="department_full_name"
:label="$t('basicData.mailList.identityInfo.departmentAll')"
>
<a-input v-model="form.department_full_name" />
</a-form-item>
<a-form-item
field="department_name"
:label="$t('basicData.mailList.identityInfo.departmentShort')"
>
<a-input v-model="form.department_name" />
</a-form-item>
</a-form>
<div v-else>
{<!-- -->{<!-- -->
props.operationType === 'del'
? $t('basicData.mailList.identityInfo.sureCancelRow')
: $t('basicData.mailList.identityInfo.sureCancelChoose')
}}
</div>
</a-modal>
</template>
<script setup lang="ts">
import {<!-- --> ref, computed, nextTick } from 'vue';
import {<!-- --> useI18n } from 'vue-i18n';
import {<!-- --> Random } from 'mockjs';
import {<!-- --> configLoginInfoStore } from '@/store';
import {<!-- --> Message } from '@arco-design/web-vue';
import {<!-- --> showErrorMsgDesc } from '@/hooks/error';
import request from '@/utils/request/index';
const emit = defineEmits<{<!-- -->
(event: 'refreshInfo'): void;
}>();
const {<!-- --> t } = useI18n();
const configLoginStore = configLoginInfoStore();
interface formType {<!-- -->
system_id: string;
id_no: string;
siren: string;
siren_name: string;
department_id: string;
department_full_name: string;
department_name: string;
}
const visible = ref(false);
const formRef = ref();
const systemList = ref<object[]>([]);
const props = defineProps<{<!-- -->
operationType: string;
}>();
const form = ref<formType>({<!-- -->
system_id: '',
id_no: '',
siren: '',
siren_name: '',
department_id: '',
department_full_name: '',
department_name: '',
});
const getSystemList = async () => {<!-- -->
const params = ref({<!-- -->
cmd_name: 'system_list_request',
puc_id: configLoginStore.getPucId,
user_id: configLoginStore.getUserId,
realm: configLoginStore.getRealm,
});
const res = await request(params.value);
const data = res?.system_list || [];
const system_list = data.map((item) => {<!-- -->
return {<!-- -->
...item,
value: item.system_id,
label: `${<!-- -->item.system_alias}(${<!-- -->item.system_id})`,
};
});
systemList.value = system_list;
console.log(systemList.value);
};
//Multiple selection to delete content
const delMultiple = ref([]);
const title = computed(() => {<!-- -->
return t(`basicData.mailList.identityInfo.${<!-- -->props.operationType}`);
});
const rules = computed(() => {<!-- -->
return {<!-- -->
system_id: [
{<!-- -->
required: true,
message: t('basicData.mailList.identityInfo.notNull'),
},
],
siren: [
{<!-- -->
required: true,
trigger: 'blur',
message: t('basicData.mailList.identityInfo.notNull'),
},
{<!-- -->
match: /^[0-9]*$/,
message: t('basicData.mailList.equipment.onlynumber'),
},
],
id_no: [
{<!-- -->
required: true,
trigger: 'blur',
message: t('basicData.mailList.identityInfo.notNull'),
},
{<!-- -->
match: /^[0-9]*$/,
message: t('basicData.mailList.equipment.onlynumber'),
},
],
siren_name: [
{<!-- -->
required: false,
trigger: 'blur',
message: t('basicData.mailList.identityInfo.notNull'),
},
{<!-- -->
validator: (value: any, cb: any) => {<!-- -->
const nameReg = /[\/:*?<>| & amp;#@%$^]/im;
if (nameReg.test(value)) {<!-- -->
cb(
t('basicData.mailList.equipment.device_alias.reg').replace(
'$1',
'/ : * ? < > | & amp; # @ % $ ^'
)
);
}
},
},
],
department_id: [
{<!-- -->
required: false,
trigger: 'blur',
message: t('basicData.mailList.identityInfo.notNull'),
},
{<!-- -->
match: /^[0-9]*$/,
message: t('basicData.mailList.equipment.onlynumber'),
},
],
department_full_name: [
{<!-- -->
required: false,
trigger: 'blur',
message: t('basicData.mailList.identityInfo.notNull'),
},
{<!-- -->
validator: (value: any, cb: any) => {<!-- -->
const nameReg = /[\/:*?<>| & amp;#@%$^]/im;
if (nameReg.test(value)) {<!-- -->
cb(
t('basicData.mailList.equipment.device_alias.reg').replace(
'$1',
'/ : * ? < > | & amp; # @ % $ ^'
)
);
}
},
},
],
department_name: [
{<!-- -->
required: false,
trigger: 'blur',
message: t('basicData.mailList.identityInfo.notNull'),
},
{<!-- -->
validator: (value: any, cb: any) => {<!-- -->
const nameReg = /[\/:*?<>| & amp;#@%$^]/im;
if (nameReg.test(value)) {<!-- -->
cb(
t('basicData.mailList.equipment.device_alias.reg').replace(
'$1',
'/ : * ? < > | & amp; # @ % $ ^'
)
);
}
},
},
],
};
});
// Clear the form
const clearForm = () => {<!-- -->
formRef.value.resetFields();
};
// The function needs to be asynchronous, otherwise the relevant judgment will not take effect
const handleClick = (info) => {<!-- -->
getSystemList();
nextTick(() => {<!-- -->
visible.value = true;
console.log(props.operationType);
if (props.operationType === 'add') {<!-- -->
clearForm();
return;
}
if (props.operationType === 'delChoose') {<!-- -->
delMultiple.value = info;
}
// deep copy
form.value = JSON.parse(JSON.stringify(info));
});
};
// Increase
const add = async (done: (arg: boolean) => void) => {<!-- -->
const param = {<!-- -->
cmd_name: 'add_staff_identifier',
cmd_guid: Random.guid(),
staff_identifier_info: {<!-- -->
puc_id: configLoginStore.getPucId,
guid: '',
realm: configLoginStore.getRealm,
...form.value,
},
};
const res: any = await request(param);
if (res.extbody.result !== 0) {<!-- -->
done(false);
showErrorMsgDesc(res.result, res.msg);
return;
}
await nextTick(() => {<!-- -->
emit('refreshInfo');
done(true);
});
clearForm();
};
// Revise
const edit = async (done: (arg: boolean) => void) => {<!-- -->
const param = {<!-- -->
cmd_name: 'update_staff_identifier',
cmd_guid: Random.guid(),
staff_identifier_info: {<!-- -->
puc_id: configLoginStore.getPucId,
guid: '',
realm: configLoginStore.getRealm,
...form.value,
},
};
const res = await request(param);
if (res.extbody.result !== 0) {<!-- -->
done(false);
showErrorMsgDesc(res.result, res.msg);
return;
}
await nextTick(() => {<!-- -->
emit('refreshInfo');
done(true);
});
};
// Delete the current
const del = async (done: (arg: boolean) => void) => {<!-- -->
const param = {<!-- -->
cmd_name: 'delete_staff_identifier',
cmd_guid: Random.guid(),
del_info_list: [
{<!-- -->
puc_id: configLoginStore.getPucId,
realm: configLoginStore.getRealm,
system_id: form.value.system_id,
siren: form.value.siren,
},
],
};
const res = await request(param);
if (res.extbody.result !== 0) {<!-- -->
done(false);
showErrorMsgDesc(res.result, res.msg);
return;
}
await nextTick(() => {<!-- -->
emit('refreshInfo');
done(true);
});
};
//Multiple selection delete
const delChoose = async (done: (arg: boolean) => void) => {<!-- -->
const param = {<!-- -->
cmd_name: 'delete_staff_identifier',
cmd_guid: Random.guid(),
del_info_list: delMultiple.value,
};
const res = await request(param);
if (res.extbody.result !== 0) {<!-- -->
done(false);
showErrorMsgDesc(res.result, res.msg);
return;
}
await nextTick(() => {<!-- -->
emit('refreshInfo');
done(true);
});
done(true);
};
const handleBeforeOk = (done) => {<!-- -->
// Increase
if (props.operationType === 'add') {<!-- -->
formRef.value.validate().then((value) => {<!-- -->
if (value) {<!-- -->
Message.warning(t('basicData.mailList.identityInfo.checkwarn'));
done(false);
} else {<!-- -->
add(done);
}
});
}
// change
if (props.operationType === 'edit') {<!-- -->
formRef.value.validate().then((value) => {<!-- -->
if (value) {<!-- -->
Message.warning(t('basicData.mailList.identityInfo.checkwarn'));
done(false);
} else {<!-- -->
edit(done);
}
});
}
// delete
if (props.operationType === 'del') {<!-- -->
del(done);
}
//Delete multiple selections
if (props.operationType === 'delChoose') {<!-- -->
delChoose(done);
}
};
const handleCancel = () => {<!-- -->
visible.value = false;
if (props.operationType !== 'delChoose' & amp; & amp; props.operationType !== 'del') {<!-- -->
clearForm();
}
};
defineExpose({<!-- -->
handleClick,
});
</script>
<style scoped lang="less">
</style>