| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- <template>
- <el-drawer :title="title" v-model="drawerOpened" @close="close">
- <el-form label-width="80px" :model="formData" :rules="formRules" ref="formInstance">
- <el-form-item label="分组名称" prop="name">
- <el-input
- v-model="formData.name"
- type="textarea"
- :autosize="{ minRows: 1, maxRows: 2 }"
- autocomplete="off"
- placeholder="请输入15字以内分组名称"
- />
- </el-form-item>
- <el-form-item label="分组描述" prop="description">
- <el-input
- v-model="formData.description"
- type="textarea"
- :rows="4"
- maxlength="50"
- show-word-limit
- autocomplete="off"
- placeholder="请输入50字以内分组描述"
- />
- </el-form-item>
- <el-form-item label="组内成员" prop="userList" :rules="[{ required: true, message: '组内成员不能为空' }]">
- <el-select
- placeholder="请添加组内人员"
- v-model="formData.userList"
- value-key="id"
- multiple
- @click="dialogOpened = true"
- >
- <el-option
- v-for="user in selectedUser"
- :key="user.id"
- :label="user.staffNo + '-' + user.realname"
- :value="user"
- />
- </el-select>
- <div class="member-count">
- <span>共 {{ total }} 人</span>
- <span v-if="isEditing" class="import-member-list" @click="batchImportVisible = true">导入成员名单</span>
- </div>
- </el-form-item>
- <el-form-item label="操作人" prop="operator">
- <el-input v-model="operater" disabled="true" />
- </el-form-item>
- </el-form>
- <template #footer>
- <el-button @click="reset">重置</el-button>
- <el-button type="primary" @click="submit">提交</el-button>
- </template>
- </el-drawer>
- <el-dialog
- v-model="dialogOpened"
- title="添加人员"
- align-center
- :close-on-click-modal="false"
- style="height: 583px"
- :width="950"
- :destroy-on-close="true"
- class="workShopDialog"
- >
- <PersonGroupFilter
- ref="dialogInstance"
- :init-selected="selectedUser"
- @cancel="handleDialogCancel"
- @submit="handleDialogSubmit"
- />
- </el-dialog>
- <BatchImport
- :visible="batchImportVisible"
- :importApiUrl="importApiUrl"
- :templateUrl="templateUrl"
- :templateName="'导入名单模版'"
- :data="{ userGroupId: formData.id }"
- responseType="detailed"
- @close="() => (batchImportVisible = false)"
- @update="handleUpdate"
- style="z-index: 10000"
- />
- </template>
- <script setup lang="ts">
- import { reactive, ref, computed, watch } from 'vue';
- import {
- PersonGroupForm,
- AddPersonGroupParams,
- EditPersonGroupParams,
- PersonGroupItem,
- PersonGroupListItem,
- } from '@/types/person-group/type';
- import { addUserGroup, modifyUserGroup, queryUserGroupDetail } from '@/api/system/person-group';
- import { FormRules, FormInstance, ElMessage } from 'element-plus';
- import { useUserStore } from '@/store/modules/user';
- import PersonGroupFilter from '@/components/PersonSelector/PersonGroupFilter.vue';
- import { storeToRefs } from 'pinia';
- import { BatchImport } from '@/components/batch-import';
- import type { ImportResponseDataPerson, ImportResponseData } from '@/components/batch-import/types';
- import { useGlobSetting } from '@/hooks/setting';
- import urlJoin from 'url-join';
- defineProps<{
- title: string;
- }>();
- const emits = defineEmits<{
- (e: 'submitted'): void; // 提交之后触发的事件
- }>();
- const drawerOpened = ref(false);
- const dialogOpened = ref(false);
- const selectedUser = ref<PersonGroupItem[]>([]);
- // 批量导入
- const batchImportVisible = ref(false);
- const { urlPrefix } = useGlobSetting();
- const importApiUrl = ref(urlJoin(urlPrefix, '/userGroup/importUserGroupMembers'));
- const templateUrl = ref('./skyeye-file-upload/sfysecurity/TEMPLATE/import-groupUserList-template.xlsx');
- const handleUpdate = (data?: ImportResponseData | ImportResponseDataPerson | string) => {
- // 处理批量导入返回的 successMembers
- if (data && typeof data === 'object' && 'successMembers' in data) {
- const importData = data as ImportResponseDataPerson;
- if (importData.successMembers && importData.successMembers.length > 0) {
- // 将 successMembers 转换为 PersonGroupItem 格式
- const newMembers: PersonGroupItem[] = importData.successMembers.map((member) => ({
- checked: true,
- id: member.id,
- realname: member.realname,
- deptId: member.deptId,
- deptName: member.deptName,
- staffNo: member.staffNo,
- jobName: member.jobName,
- }));
- // 获取现有成员的 id 集合,用于去重
- const existingIds = new Set(selectedUser.value.map((user) => user.id));
- // 过滤掉已存在的成员,只添加新成员
- const membersToAdd = newMembers.filter((member) => !existingIds.has(member.id));
- if (membersToAdd.length > 0) {
- // 合并到现有列表
- selectedUser.value = [...selectedUser.value, ...membersToAdd];
- formData.userList = [...formData.userList, ...membersToAdd];
- total.value = formData.userList.length;
- ElMessage.success(`成功导入 ${membersToAdd.length} 名成员`);
- } else {
- ElMessage.info('导入的成员已全部存在于当前列表中');
- }
- }
- }
- };
- // 表单相关
- let defaultFormData: PersonGroupForm = {
- id: null,
- name: '',
- description: '',
- userList: [],
- };
- const useUser = useUserStore();
- const { info } = storeToRefs(useUser);
- const operater = ref(info.value.realname);
- const total = ref<number>(0);
- const formData = reactive<PersonGroupForm>(defaultFormData);
- const formRules: FormRules = {
- name: { required: true, trigger: 'blur', message: '请填写分组名称' },
- userList: { required: true, trigger: 'blur', message: '请选择组内成员' },
- };
- const formInstance = ref<FormInstance>();
- const isEditing = computed(() => formData.id != null);
- /** 重置表单 */
- const reset = () => {
- formInstance.value?.resetFields();
- Object.assign(formData, defaultFormData);
- };
- /** 提交表单 */
- const submit = async () => {
- try {
- await formInstance.value?.validate();
- if (isEditing.value) {
- await modifyUserGroup({
- name: formData.name,
- description: formData.description,
- userIdList: formData.userList.map((x) => x.id),
- total: formData.userList.length,
- userGroupId: formData.id!,
- } as EditPersonGroupParams);
- } else {
- await addUserGroup({
- name: formData.name,
- description: formData.description,
- userIdList: formData.userList.map((x) => x.id),
- total: formData.userList.length,
- } as AddPersonGroupParams);
- }
- drawerOpened.value = false;
- ElMessage.success('提交成功');
- emits('submitted');
- } catch (e) {
- console.error(e);
- }
- };
- const close = () => {
- defaultFormData = {
- id: null,
- name: '',
- description: '',
- userList: [],
- };
- reset();
- };
- const handleDialogCancel = () => {
- dialogOpened.value = false;
- };
- const handleDialogSubmit = (selectedData: PersonGroupItem[]) => {
- selectedUser.value = selectedData;
- formData.userList = selectedData;
- total.value = formData.userList.length;
- dialogOpened.value = false;
- };
- const open = async (row?: PersonGroupListItem) => {
- if (row) {
- const res = await queryUserGroupDetail(row.id);
- defaultFormData = {
- id: res.userGroupId,
- name: res.name,
- description: res.description,
- userList: res.userList.map((x) => {
- return {
- checked: true,
- id: x.id,
- realname: x.realname,
- deptName: x.deptName,
- staffNo: x.staffNo,
- jobName: x.jobName,
- } as PersonGroupItem;
- }),
- };
- reset();
- selectedUser.value = formData.userList;
- }
- drawerOpened.value = true;
- };
- watch(
- () => formData.userList,
- (newUserList) => {
- total.value = newUserList.length;
- const ids = newUserList.map((user) => user.id);
- selectedUser.value = selectedUser.value.filter((user) => ids.includes(user.id));
- },
- );
- defineExpose({
- open,
- });
- </script>
- <style scoped lang="scss">
- .member-count {
- width: 100%;
- display: flex;
- justify-content: space-between;
- align-items: center;
- .import-member-list {
- color: $primary-color;
- cursor: pointer;
- }
- }
- </style>
|