gaoluyang
2026-06-24 c0cb161bb52ce0fbdce5c66ec391d107c75e2452
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
<script lang="ts" setup>
import { ref } from 'vue';
 
import { useVbenModal } from '..\..\..\..\..\..\..\..\packages\effects\common-ui\src';
import { IconifyIcon } from '..\..\..\..\..\..\..\..\packages\icons\src';
 
import { Button, Input } from 'ant-design-vue';
 
defineOptions({ name: 'HttpHeaderEditor' });
 
const emit = defineEmits(['save']);
 
interface HeaderItem {
  key: string;
  value: string;
}
 
const headerList = ref<HeaderItem[]>([]);
 
// 解析请求头字符串为列表
const parseHeaders = (headersStr: string): HeaderItem[] => {
  if (!headersStr || !headersStr.trim()) {
    return [{ key: '', value: '' }];
  }
 
  const lines = headersStr.split('\n').filter((line) => line.trim());
  const parsed = lines.map((line) => {
    const colonIndex = line.indexOf(':');
    if (colonIndex > 0) {
      return {
        key: line.slice(0, Math.max(0, colonIndex)).trim(),
        value: line.slice(Math.max(0, colonIndex + 1)).trim(),
      };
    }
    return { key: line.trim(), value: '' };
  });
 
  return parsed.length > 0 ? parsed : [{ key: '', value: '' }];
};
 
// 将列表转换为请求头字符串
const stringifyHeaders = (headers: HeaderItem[]): string => {
  return headers
    .filter((item) => item.key.trim())
    .map((item) => `${item.key}: ${item.value}`)
    .join('\n');
};
 
// 添加请求头
const addHeader = () => {
  headerList.value.push({ key: '', value: '' });
};
 
// 移除请求头
const removeHeader = (index: number) => {
  if (headerList.value.length === 1) {
    // 至少保留一行
    headerList.value = [{ key: '', value: '' }];
  } else {
    headerList.value.splice(index, 1);
  }
};
 
// 保存
const handleSave = () => {
  const headersStr = stringifyHeaders(headerList.value);
  emit('save', headersStr);
  modalApi.close();
};
 
const [Modal, modalApi] = useVbenModal({
  destroyOnClose: true,
  onOpenChange(isOpen) {
    if (!isOpen) {
      return;
    }
    const { headers } = modalApi.getData();
    headerList.value = parseHeaders(headers);
  },
  onConfirm: handleSave,
});
</script>
 
<template>
  <Modal title="编辑请求头" class="w-3/5">
    <div class="space-y-4">
      <div class="mb-2 space-y-3 overflow-y-auto">
        <div
          v-for="(item, index) in headerList"
          :key="index"
          class="flex items-center gap-2"
        >
          <Input
            v-model:value="item.key"
            placeholder="请输入参数名"
            class="w-48"
            allow-clear
          />
          <span class="font-medium text-gray-600">:</span>
          <Input
            v-model:value="item.value"
            placeholder="请输入参数值 (支持表达式 ${变量名})"
            class="flex-1"
            allow-clear
          />
          <Button type="text" danger size="small" @click="removeHeader(index)">
            <template #icon>
              <IconifyIcon icon="ep:delete" />
            </template>
          </Button>
        </div>
      </div>
      <Button type="primary" class="w-full" @click="addHeader">
        <template #icon>
          <IconifyIcon icon="ep:plus" />
        </template>
        添加请求头
      </Button>
    </div>
  </Modal>
</template>