88 lines
3.6 KiB
Vue
88 lines
3.6 KiB
Vue
<script setup lang="ts">
|
||
import { computed } from 'vue';
|
||
import type { HookDetail, HookForm } from '../../api/types';
|
||
import { toast } from '../../composables/toast';
|
||
import { copyText, formatTime, webhookUrl } from '../../utils/format';
|
||
|
||
const props = defineProps<{ form: HookForm; hook: HookDetail | null; groups: string[] }>();
|
||
const emit = defineEmits<{ regenerateToken: [] }>();
|
||
|
||
const url = computed(() => webhookUrl(props.form.slug));
|
||
const slugChanged = computed(() => props.hook !== null && props.hook.slug !== props.form.slug);
|
||
const hasBodyParams = computed(() => props.form.params.some((p) => p.source === 'json' || p.source === 'form'));
|
||
|
||
async function copyUrl() {
|
||
if (await copyText(url.value)) toast.success('调用地址已复制');
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<div class="form-grid">
|
||
<div class="field">
|
||
<label class="required">接口名称</label>
|
||
<input v-model="form.name" maxlength="100" placeholder="如:更新家庭 IP" />
|
||
</div>
|
||
<div class="field">
|
||
<label>分组</label>
|
||
<input v-model="form.group" list="hook-groups" maxlength="50" placeholder="可选,用于在列表中归类" />
|
||
<datalist id="hook-groups">
|
||
<option v-for="g in groups" :key="g" :value="g" />
|
||
</datalist>
|
||
</div>
|
||
|
||
<div class="field">
|
||
<label class="required">接口标识</label>
|
||
<input v-model="form.slug" maxlength="64" placeholder="如:home-ip" class="mono" />
|
||
<div class="hint">小写字母、数字、下划线和连字符,以字母或数字开头。</div>
|
||
</div>
|
||
<div class="field">
|
||
<label class="required">请求方式</label>
|
||
<select v-model="form.method">
|
||
<option value="POST">POST</option>
|
||
<option value="GET">GET</option>
|
||
</select>
|
||
<div v-if="form.method === 'GET' && hasBodyParams" class="hint" style="color: var(--danger)">
|
||
GET 接口只能从 Query 或 Header 提取参数,请调整参数配置。
|
||
</div>
|
||
</div>
|
||
|
||
<div class="field full">
|
||
<label>调用地址</label>
|
||
<div class="row">
|
||
<div class="input-group" style="flex: 1">
|
||
<span class="addon">{{ form.method }}</span>
|
||
<input :value="url" readonly class="mono" />
|
||
</div>
|
||
<button class="btn" :disabled="!form.slug" @click="copyUrl">复制</button>
|
||
</div>
|
||
<div v-if="slugChanged" class="hint" style="color: var(--warning)">
|
||
修改标识后原地址 /hooks/{{ hook!.slug }} 将失效,调用方需同步更新。
|
||
</div>
|
||
</div>
|
||
|
||
<div class="field full">
|
||
<label>描述</label>
|
||
<textarea v-model="form.description" rows="3" maxlength="1000" placeholder="接口用途、调用方等说明" />
|
||
</div>
|
||
|
||
<div class="field full">
|
||
<label>接口 Token</label>
|
||
<template v-if="hook">
|
||
<div class="row">
|
||
<input :value="`hp_••••••••••••••••••••••••${hook.tokenHint}`" readonly class="mono" style="max-width: 360px" />
|
||
<button class="btn btn-danger-outline" @click="emit('regenerateToken')">重新生成</button>
|
||
</div>
|
||
<div class="hint">
|
||
Token 仅在创建或重新生成时完整显示一次。调用时通过 <code>Authorization: Bearer <token></code> 或
|
||
<code>X-Hook-Token</code> 请求头传递。
|
||
</div>
|
||
</template>
|
||
<div v-else class="hint">创建接口后自动生成,届时只显示一次,请妥善保存。</div>
|
||
</div>
|
||
|
||
<div v-if="hook" class="field full">
|
||
<div class="small faint">创建于 {{ formatTime(hook.createdAt) }} · 最后修改 {{ formatTime(hook.updatedAt) }}</div>
|
||
</div>
|
||
</div>
|
||
</template>
|