From 7b61477a42cf11c4dea6ed390a8b74b7586799f2 Mon Sep 17 00:00:00 2001 From: engigu Date: Tue, 17 Mar 2026 11:41:35 +0800 Subject: [PATCH] chore: add api usage --- web/src/views/notify/components/ApiUsage.vue | 252 +++++++++++++++---- 1 file changed, 208 insertions(+), 44 deletions(-) diff --git a/web/src/views/notify/components/ApiUsage.vue b/web/src/views/notify/components/ApiUsage.vue index a65ebd2..badc72f 100644 --- a/web/src/views/notify/components/ApiUsage.vue +++ b/web/src/views/notify/components/ApiUsage.vue @@ -3,7 +3,8 @@ import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' -import { Copy, Terminal, Key, FileJson, RefreshCw, Check, Hash, Info, AlertTriangle } from 'lucide-vue-next' +import { Copy, Terminal, Key, FileJson, RefreshCw, Check, Hash, Info, AlertTriangle, Code2 } from 'lucide-vue-next' +import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs' import { AlertDialog, AlertDialogAction, @@ -67,10 +68,174 @@ notify-token: <你的API Token> "text": "内容" }` -const shellExample = computed(() => `curl -s -X POST "http://${host.value}/api/v1/notify/send" \\ - -H "Content-Type: application/json" \\ - -H "notify-token: ${props.apiToken || 'YOUR_TOKEN'}" \\ - -d '{"channel_id":"YOUR_CHANNEL_ID","title":"标题","text":"通知内容"}'`) +const shellExample = computed(() => `send_notification() { + curl -s -X POST "http://${host.value}/api/v1/notify/send" \\ + -H "Content-Type: application/json" \\ + -H "notify-token: \${1:-${props.apiToken || 'YOUR_TOKEN'}}" \\ + -d "{\\"channel_id\\":\\"\$2\\",\\"title\\":\\"\$3\\",\\"text\\":\\"\$4\\"}" +} + +# 使用示例: send_notification <渠道ID> <标题> <内容> +send_notification "${props.apiToken || 'YOUR_TOKEN'}" "ID" "任务完成" "脚本执行完毕"`) + +const pythonExample = computed(() => `import requests + +def send_notification(token, channel_id, text, title="通知"): + url = "http://${host.value}/api/v1/notify/send" + headers = { + "Content-Type": "application/json", + "notify-token": token + } + payload = { + "channel_id": channel_id, + "title": title, + "text": text + } + return requests.post(url, json=payload, headers=headers).json() + +# 使用示例 +send_notification("${props.apiToken || 'YOUR_TOKEN'}", "ID", "脚本执行完毕", "任务完成")`) + +const javascriptExample = computed(() => `async function sendNotification(token, channelId, text, title = "通知") { + const url = "http://${host.value}/api/v1/notify/send"; + const res = await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json", + "notify-token": token + }, + body: JSON.stringify({ + channel_id: channelId, + title: title, + text: text + }) + }); + return res.json(); +} + +// 使用示例 +sendNotification("${props.apiToken || 'YOUR_TOKEN'}", "ID", "脚本执行完毕", "任务完成");`) + +const goExample = computed(() => `package main + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" +) + +func sendNotification(token, channelID, title, text string) error { + url := "http://${host.value}/api/v1/notify/send" + payload := map[string]string{ + "channel_id": channelID, + "title": title, + "text": text, + } + body, _ := json.Marshal(payload) + + req, _ := http.NewRequest("POST", url, bytes.NewBuffer(body)) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("notify-token", token) + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + return nil +} + +func main() { + // 使用示例 + sendNotification("${props.apiToken || 'YOUR_TOKEN'}", "ID", "任务完成", "脚本执行完毕") +}`) + +const examples = [ + { id: 'shell', name: 'Shell', icon: Terminal, code: shellExample }, + { id: 'python', name: 'Python', icon: Code2, code: pythonExample }, + { id: 'javascript', name: 'JavaScript', icon: Code2, code: javascriptExample }, + { id: 'go', name: 'Go', icon: Code2, code: goExample }, +] + +const activeLang = ref('shell') + +const highlightCode = (code: string, lang: string) => { + if (!code) return '' + + const colors = { + keyword: 'text-violet-500 dark:text-violet-400 font-medium', + string: 'text-emerald-600 dark:text-emerald-400', + comment: 'text-zinc-400 dark:text-zinc-500 italic', + type: 'text-amber-600 dark:text-amber-500', + function: 'text-blue-500 dark:text-blue-400', + number: 'text-orange-500', + operator: 'text-zinc-400 dark:text-zinc-600' + } + + // 基础转义 + let html = code + .replace(/&/g, '&') + .replace(//g, '>') + + // 1. 处理字符串 (优先处理,防止内部匹配) + html = html.replace(/("(?:\\.|[^"])*")|('(?:\\.|[^'])*')/g, `$1`) + + // 2. 处理注释 (注意排除 http:// 或 https:// 中的双斜杠) + html = html.replace(/(^|[^\:])(\/\/.+)$|(#.+)$/gm, `$1$2$3`) + + // 3. 语言配置 + const langConfig: Record = { + shell: { + keywords: ['curl'], + types: [], + functions: ['send_notification'] + }, + python: { + keywords: ['import', 'def', 'return', 'as', 'from'], + types: ['dict', 'list', 'str', 'int', 'float'], + functions: ['send_notification', 'post', 'json'] + }, + javascript: { + keywords: ['async', 'await', 'function', 'const', 'return', 'let', 'var', 'if', 'else', 'try', 'catch'], + types: ['JSON', 'Promise', 'fetch'], + functions: ['sendNotification', 'stringify', 'json', 'post'] + }, + go: { + keywords: ['package', 'import', 'func', 'return', 'map', 'defer', 'if', 'nil', 'go', 'main'], + types: ['string', 'error', 'byte', 'int'], + functions: ['Marshal', 'NewRequest', 'Set', 'Do', 'Close', 'Sprintf'] + } + } + + const conf = langConfig[lang === 'javascript' ? 'javascript' : (lang === 'shell' ? 'shell' : lang)] + if (conf) { + if (conf.keywords.length) { + const regex = new RegExp(`\\b(${conf.keywords.join('|')})\\b(?![^<]*>)`, 'g') + html = html.replace(regex, `$1`) + } + if (conf.types.length) { + const regex = new RegExp(`\\b(${conf.types.join('|')})\\b(?![^<]*>)`, 'g') + html = html.replace(regex, `$1`) + } + if (conf.functions.length) { + const regex = new RegExp(`\\b(${conf.functions.join('|')})\\b(?![^<]*>)`, 'g') + html = html.replace(regex, `$1`) + } + } + + // 4. 操作符和括号 (可选,这里处理基础) + // html = html.replace(/[:{}[\],]/g, `$&`) + + return html +} + +const currentExample = computed(() => { + const code = examples.find(e => e.id === activeLang.value)?.code.value || '' + return highlightCode(code, activeLang.value) +})