You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Discord巴士报告系统:特定目的地嵌入交互功能优化求助

Solution for Dynamic Bus Report Bot Interaction

Key Improvements Made

  • Centralized destination configuration for easy scaling
  • Track user selections from both dropdown menus
  • Generate dynamic embeds with destination-specific images
  • Fixed collector logic to handle menu selections and button clicks correctly

Corrected Full Code

const { SlashCommandBuilder, EmbedBuilder, ButtonBuilder, ActionRowBuilder, SelectMenuBuilder } = require('discord.js');

module.exports = {
  data: new SlashCommandBuilder()
    .setName('bus-test')
    .setDescription('Submit a bus report')
    .addAttachmentOption(option => option.setName('screenshot').setDescription('Upload a screenshot').setRequired(true))
    .addStringOption(option => option.setName('other_drivers').setDescription('Enter all drivers with @').setRequired(true))
    .addStringOption(option => option.setName('passengers').setDescription('Enter all passengers with @').setRequired(true)),

  async execute(interaction) {
    const author = interaction.user;
    const drivers = interaction.options.getString('other_drivers');
    const passengers = interaction.options.getString('passengers');
    const attachment = interaction.options.get('screenshot').value;

    // Format lists with bullet points
    const passengersWithDots = passengers.split(' ').map(passenger => `• ${passenger}`).join('\n');
    const driversWithDots = drivers.split(' ').map(driver => `• ${driver}`).join('\n');
    const driversWithMention = `• ${author}\n${driversWithDots}`;

    // --------------------------
    // Destination Configuration
    // Add/remove destinations here easily
    // --------------------------
    const destinations = {
      option_1: {
        label: 'Option 1',
        imageUrl: 'https://example.com/option1-bus.png' // Replace with actual image URL
      },
      option_2: {
        label: 'Option 2',
        imageUrl: 'https://example.com/option2-bus.png'
      },
      downtown: {
        label: 'Downtown Terminal',
        imageUrl: 'https://example.com/downtown-bus.png'
      },
      airport: {
        label: 'City Airport',
        imageUrl: 'https://example.com/airport-bus.png'
      }
    };

    // --------------------------
    // Build UI Components
    // --------------------------
    // Destination dropdown menu (populated from config)
    const destinationmenu = new SelectMenuBuilder()
      .setCustomId('destination_menu')
      .setPlaceholder('Select destination')
      .addOptions(
        Object.entries(destinations).map(([value, data]) => ({
          label: data.label,
          value: value
        }))
      );

    // Driver count dropdown menu
    const drivermenu = new SelectMenuBuilder()
      .setCustomId('drivernum_menu')
      .setPlaceholder('Select number of drivers')
      .addOptions([
        { label: '1 driver(s)', value: 'driver_num_1' },
        { label: '2 driver(s)', value: 'driver_num_2' },
        { label: '3 driver(s)', value: 'driver_num_3' },
        { label: '4 driver(s)', value: 'driver_num_4' },
        { label: '5 driver(s)', value: 'driver_num_5' },
        { label: '6 driver(s)', value: 'driver_num_6' }
      ]);

    // Buttons
    const Preview = new ButtonBuilder()
      .setCustomId('Preview_button')
      .setLabel('Preview')
      .setStyle('Primary');

    const Cancel = new ButtonBuilder()
      .setCustomId('Cancel_button')
      .setLabel('Cancel')
      .setStyle('Danger');

    // Action rows
    const row1 = new ActionRowBuilder().addComponents(destinationmenu);
    const row2 = new ActionRowBuilder().addComponents(drivermenu);
    const row3 = new ActionRowBuilder().addComponents(Cancel, Preview);

    // Initial reply
    const initialEmbed = new EmbedBuilder()
      .setTitle('**Bus Report Setup**')
      .setColor('Yellow')
      .setDescription(`Please select a destination and number of drivers, then click Preview.\n\n**Drivers:**\n${driversWithMention}\n\n**Passengers:**\n${passengersWithDots}`)
      .setImage(attachment.url);

    const reply = await interaction.reply({
      embeds: [initialEmbed],
      ephemeral: true,
      components: [row1, row2, row3],
    });

    // Track user selections
    let selectedDestination = null;
    let selectedDriverNum = null;

    // Component collector
    const collector = reply.createMessageComponentCollector({ time: 30000 });

    collector.on('collect', async (componentInteraction) => {
      // Only allow the original user to interact
      if (componentInteraction.user.id !== interaction.user.id) {
        return componentInteraction.reply({ content: 'This is not your report!', ephemeral: true });
      }

      // Handle destination selection
      if (componentInteraction.customId === 'destination_menu') {
        selectedDestination = componentInteraction.values[0];
        await componentInteraction.deferUpdate();
      }

      // Handle driver count selection
      else if (componentInteraction.customId === 'drivernum_menu') {
        selectedDriverNum = componentInteraction.values[0];
        await componentInteraction.deferUpdate();
      }

      // Handle Preview button click
      else if (componentInteraction.customId === 'Preview_button') {
        // Validate selections
        if (!selectedDestination || !selectedDriverNum) {
          return componentInteraction.reply({
            content: 'Please select both a destination and number of drivers first!',
            ephemeral: true
          });
        }

        // Get destination data and driver label
        const destData = destinations[selectedDestination];
        const driverLabel = drivermenu.options.find(opt => opt.value === selectedDriverNum).label;

        // Build preview embed
        const previewEmbed = new EmbedBuilder()
          .setTitle(`Bus Report: ${destData.label}`)
          .setColor('Green')
          .setDescription(`
Selected Destination: ${destData.label}
Selected Driver(s): ${driverLabel}

**Drivers:**
${driversWithMention}

**Passengers:**
${passengersWithDots}
          `)
          .setImage(destData.imageUrl)
          .setFooter({ text: `Submitted by ${author.tag}`, iconURL: author.displayAvatarURL() });

        // Update message with preview
        await componentInteraction.update({
          embeds: [previewEmbed],
          components: []
        });
        collector.stop();
      }

      // Handle Cancel button click
      else if (componentInteraction.customId === 'Cancel_button') {
        await componentInteraction.update({
          content: 'Report canceled.',
          embeds: [],
          components: []
        });
        collector.stop();
      }
    });

    collector.on('end', async () => {
      if (!reply.deleted) {
        await reply.edit({
          content: 'This report is no longer active.',
          embeds: [],
          components: []
        });
      }
    });
  },
};

Usage Notes

  1. Add New Destinations: Simply add new entries to the destinations object with a unique value, display label, and image URL. The dropdown menu will auto-populate these options.
  2. Replace Image URLs: Update the imageUrl fields in the destinations config with your actual bus destination images.
  3. Validation: The bot now checks that both a destination and driver count are selected before generating the preview.
  4. User Restriction: Only the original command user can interact with the menus/buttons to prevent unwanted changes.

内容的提问来源于stack exchange,提问作者Abdalrahma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 10:34:56