# Discord 互動

本頁說明 `core/discord` 的按鈕開 modal 文字輸入、單選與多選選單，以及各自的答案如何回到 `Reply` handler。

三個方法都接收 `(ctx, channelID, replyTo, text string, ...)`，回傳 prompt 的 `*discordgo.Message`，channel ID 或 prompt 文字為空時回 error。`replyTo` 非空時 prompt 以 reply 方式送出。每個 prompt 都有一個 UUID，嵌在 component custom ID（`go-bot:input:...` 或 `go-bot:select:menu:...`）中，並作為記憶體狀態的 key。其他 custom ID 的 component 交給其他 handler 處理。

## 自由文字輸入：SendInput

```go
prompt, err := bot.SendInput(ctx, in.ChannelID, in.MessageID, "What is your name?")
```

Discord 只能在回應 interaction 時開啟 modal，因此輸入分兩步：

| 步驟 | 行為 |
|---|---|
| 送出 | prompt 文字加一個 **Input** 按鈕 |
| 點按鈕 | 函式庫開啟 modal，標題取 prompt 前 45 bytes，內含一個必填、標籤為 **Input** 的短文字欄位 |
| 送出 modal | 函式庫以 ephemeral `✓` 回應後立即刪除該回應、移除狀態，再以 `Text` = 答案、`MessageID` = prompt ID 呼叫 `Reply` |

送出後按鈕仍留在 prompt 上。再次點擊，或在 `Close()` 後送出，會收到 ephemeral 的 `Expired`。45 bytes 的截斷以 byte 計算，多位元組的 prompt 可能被切在字元中間；請讓 prompt 保持簡短，或把問題寫在訊息文字裡。

## 單選：SendSelect

```go
prompt, err := bot.SendSelect(ctx, in.ChannelID, in.MessageID, "Pick a color", []string{"Red", "Green", "Blue"})
```

原生 string select menu（placeholder `Select (single-select)`、最少 1、最多 1），每個非空項目一個選項，label 與 value 都是該項目。允許 1 到 25 個項目。使用者選取後，函式庫不修改訊息直接回應、移除狀態，並以 `Text` = 選取值呼叫 `Reply`。

## 多選：SendMultiSelect

```go
prompt, err := bot.SendMultiSelect(ctx, in.ChannelID, in.MessageID, "Pick toppings", []string{"Cheese", "Ham", "Olive"})
```

同一種選單，placeholder 為 `Select (multi-select)`、最少 0、最多為選項數。使用者關閉下拉選單時 Discord 一次送出，函式庫以 `CallbackPicks` = 選取值呼叫 `Reply`（`Text` 保持空白）。

## 收到答案之後

選取後選單仍然可見，但狀態已移除，再次選取會收到 ephemeral 的 `Expired`。函式庫刻意保留 prompt：若要替換訊息移除 component，必須同時送出內容，而 discordgo 會序列化空的 content 欄位，被 Discord 以錯誤 50006 拒絕。要移除 prompt 請呼叫 `bot.Delete(ctx, in.ChannelID, in.MessageID)`；modal 與 select 答案的 `in.MessageID` 就是 prompt ID。

## 相關頁面

- [Reply Handler](/zh/reply-handler)
- [Discord 設定](/zh/discord)（`Input` 欄位）
- [Telegram 互動](/zh/telegram-interactions)（Telegram 對應功能）
