WholeProcessPlatform/frontend/src/views/system/pushManagement/components/ConfigManagement/PushTargetModal.vue
2026-07-10 17:11:58 +08:00

199 lines
4.8 KiB
Vue

<template>
<a-modal
:open="visible"
title="推送目标配置"
:width="780"
:footer="null"
@cancel="handleCancel"
>
<div class="push-target-modal">
<a-radio-group
v-model:value="targetType"
:options="targetOptions"
class="target-radio"
/>
<div v-show="targetType !== '1'" class="transfer-wrapper">
<a-transfer
v-model:target-keys="targetKeys"
v-model:selected-keys="selectedKeys"
:data-source="transferDataSource"
:titles="transferTitles"
:show-search="true"
:filter-option="filterOption"
:render="item => item.title"
:list-style="{ width: '340px', height: '360px' }"
@change="handleChange"
/>
</div>
<div class="modal-footer">
<a-button type="primary" @click="handleSave" :loading="loading">保存</a-button>
<a-button @click="handleCancel">放弃</a-button>
</div>
</div>
</a-modal>
</template>
<script setup lang="ts">
import { ref, computed, watch, onMounted, nextTick } from 'vue';
import {queryUsersList,queryRolesList,getPushTargets} from '@/api/system/map/pushManagement';
import { useDraggable } from '@/utils/drag';
const props = defineProps<{
visible: boolean;
initialValues: any;
}>();
const emit = defineEmits<{
(e: 'update:visible', val: boolean): void;
(e: 'cancel'): void;
(
e: 'ok',
values: {
targetType: string;
userRoleIds: string[] | null;
configId?: number;
}
): void;
}>();
const targetOptions = [
{ label: '所有人', value: '1' },
{ label: '按人', value: '2' },
{ label: '按角色类型', value: '3' }
];
const targetType = ref('1');
const selectedKeys = ref<string[]>([]);
const targetKeys = ref<string[]>([]);
const userList = ref<{ key: string; title: string }[]>([]);
const roleList = ref<{ key: string; title: string }[]>([]);
const loading = ref(false);
const isInitializing = ref(false);
const transferReady = ref(false);
const cachedPushTargets = ref<any>(null);
const transferDataSource = computed(() => {
return targetType.value === '2' ? userList.value : roleList.value;
});
const transferTitles = computed(() => {
if (targetType.value === '2') {
return ['未关联用户', '已关联用户'];
}
return ['未关联角色', '已关联角色'];
});
const filterOption = (inputValue: string, item: any) => {
return item.title.toLowerCase().includes(inputValue.toLowerCase());
};
const handleEcho = async (data: any) => {
if (!data) return;
const newTargetType = String(data.targetType ?? '1');
const newUserRoleIds = Array.isArray(data.userRoleIds) ? data.userRoleIds : [];
targetType.value = newTargetType;
if (newTargetType !== '1' && newUserRoleIds.length > 0) {
await nextTick();
const dataSource = newTargetType === '2' ? userList.value : roleList.value;
const validKeys = newUserRoleIds.filter(id =>
dataSource.some(item => item.key === id)
);
targetKeys.value = [...validKeys];
} else {
targetKeys.value = [];
}
};
watch(
() => props.visible,
async val => {
if (val) {
loading.value = true;
targetType.value = '1';
targetKeys.value = [];
selectedKeys.value = [];
await initOption();
if (props.initialValues?.id) {
try {
const resh = await getPushTargets({ configId: props.initialValues.id });
if (resh?.data) {
await handleEcho(resh.data);
}
} catch (error) {
console.error('获取推送目标失败:', error);
}
}
loading.value = false;
}
}
);
const handleChange = (newTargetKeys: string[]) => {
targetKeys.value = newTargetKeys;
};
const handleSave = () => {
let userRoleIds: string[] | null = null;
if (targetType.value === '1') {
userRoleIds = userList.value.map(item => item.key);
} else {
userRoleIds = targetKeys.value as string[];
}
emit('ok', {
targetType: targetType.value,
userRoleIds,
configId: props.initialValues?.id
});
};
const handleCancel = () => {
emit('update:visible', false);
emit('cancel');
};
const initOption = async () => {
let res = await queryUsersList({});
let resjv = await queryRolesList({});
userList.value = (res.data || []).map((item: any) => ({
key: item.id,
title: `${item.nickname || item.username || ''}${item.phone ? '(' + item.phone + ')' : ''}`
}));
roleList.value = (resjv.data || []).map((item: any) => ({
key: item.id,
title: item.rolename || ''
}));
};
onMounted(() => {});
</script>
<style scoped lang="scss">
.push-target-modal {
display: flex;
flex-direction: column;
gap: 20px;
}
.target-radio {
margin-bottom: 4px;
}
.transfer-wrapper {
display: flex;
justify-content: center;
}
.modal-footer {
display: flex;
gap: 12px;
justify-content: flex-start;
}
</style>