| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- <template>
- <el-dialog
- v-model="dialogVisible"
- title="编辑请求头"
- width="600px"
- :close-on-click-modal="false"
- @close="handleClose"
- >
- <div class="header-editor">
- <div class="header-list">
- <div v-for="(item, index) in headerList" :key="index" class="header-item">
- <el-input v-model="item.key" placeholder="请输入参数名" class="header-key" clearable />
- <span class="separator">:</span>
- <el-input
- v-model="item.value"
- placeholder="请输入参数值 (支持表达式 ${变量名})"
- class="header-value"
- clearable
- />
- <el-button
- type="danger"
- :icon="Delete"
- circle
- size="small"
- @click="removeHeader(index)"
- />
- </div>
- </div>
- <el-button type="primary" :icon="Plus" class="add-btn" @click="addHeader">
- 添加请求头
- </el-button>
- </div>
- <template #footer>
- <span class="dialog-footer">
- <el-button @click="handleClose">取消</el-button>
- <el-button type="primary" @click="handleSave">保存</el-button>
- </span>
- </template>
- </el-dialog>
- </template>
- <script lang="ts" setup>
- import { Delete, Plus } from '@element-plus/icons-vue'
- defineOptions({ name: 'HttpHeaderEditor' })
- const props = defineProps({
- modelValue: {
- type: Boolean,
- default: false
- },
- headers: {
- type: String,
- default: ''
- }
- })
- const emit = defineEmits(['update:modelValue', 'save'])
- interface HeaderItem {
- key: string
- value: string
- }
- const dialogVisible = computed({
- get: () => props.modelValue,
- set: (val) => emit('update:modelValue', val)
- })
- 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.substring(0, colonIndex).trim(),
- value: line.substring(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)
- dialogVisible.value = false
- }
- // 关闭
- const handleClose = () => {
- dialogVisible.value = false
- }
- // 监听对话框打开,初始化数据
- watch(
- () => props.modelValue,
- (val) => {
- if (val) {
- headerList.value = parseHeaders(props.headers)
- }
- },
- { immediate: true }
- )
- </script>
- <style lang="scss" scoped>
- .header-editor {
- .header-list {
- max-height: 400px;
- overflow-y: auto;
- margin-bottom: 16px;
- }
- .header-item {
- display: flex;
- align-items: center;
- gap: 8px;
- margin-bottom: 12px;
- .header-key {
- flex: 0 0 180px;
- }
- .separator {
- color: #606266;
- font-weight: 500;
- }
- .header-value {
- flex: 1;
- }
- }
- .add-btn {
- width: 100%;
- }
- }
- .dialog-footer {
- display: flex;
- justify-content: flex-end;
- gap: 10px;
- }
- </style>
|