|
|
@ -13,13 +13,78 @@ const props = withDefaults(defineProps<{ |
|
|
}>(),{}) |
|
|
}>(),{}) |
|
|
|
|
|
|
|
|
const weburls=ref<string[]>([]) |
|
|
const weburls=ref<string[]>([]) |
|
|
|
|
|
const tags = ref<string[]>([]) |
|
|
|
|
|
|
|
|
|
|
|
const extractLtag = (url: string) => { |
|
|
|
|
|
if(!url) return '' |
|
|
|
|
|
try { |
|
|
|
|
|
const u = new URL(url) |
|
|
|
|
|
return u.searchParams.get('ltag') || '' |
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
// fallback for non-absolute urls |
|
|
|
|
|
const qIdx = url.indexOf('?') |
|
|
|
|
|
if (qIdx === -1) return '' |
|
|
|
|
|
const qs = url.slice(qIdx + 1) |
|
|
|
|
|
const params = new URLSearchParams(qs) |
|
|
|
|
|
return params.get('ltag') || '' |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const updateUrlWithTag = (url: string, tag: string) => { |
|
|
|
|
|
try { |
|
|
|
|
|
const u = new URL(url || 'http://example.com') // base for relative fallback |
|
|
|
|
|
if (tag) u.searchParams.set('ltag', tag) |
|
|
|
|
|
else u.searchParams.delete('ltag') |
|
|
|
|
|
// if original url had no origin and we used example.com, strip it |
|
|
|
|
|
if (!/^[a-zA-Z]+:\/\//.test(url || '')) { |
|
|
|
|
|
const path = u.pathname + (u.search ? u.search : '') + (u.hash ? u.hash : '') |
|
|
|
|
|
return path === '/' ? (u.search ? u.search.slice(1) : '') : path |
|
|
|
|
|
} |
|
|
|
|
|
return u.toString() |
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
const hasQ = url.includes('?') |
|
|
|
|
|
const parts = url.split('?') |
|
|
|
|
|
const base = parts[0] |
|
|
|
|
|
const qs = parts[1] || '' |
|
|
|
|
|
const params = new URLSearchParams(qs) |
|
|
|
|
|
if (tag) params.set('ltag', tag) |
|
|
|
|
|
else params.delete('ltag') |
|
|
|
|
|
const qsStr = params.toString() |
|
|
|
|
|
return qsStr ? `${base}?${qsStr}` : base |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 新增:只允许文字/数字字符(含中文),去除符号 |
|
|
|
|
|
const sanitizeTag = (val: string) => { |
|
|
|
|
|
if (!val) return '' |
|
|
|
|
|
try { |
|
|
|
|
|
// 优先使用 Unicode property escapes,保留字母和数字 |
|
|
|
|
|
return val.replace(/[^\p{L}\p{N}]+/gu, '') |
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
// fallback:允许 ASCII 字母/数字 与 常见中日韩汉字区间 |
|
|
|
|
|
return val.replace(/[^0-9a-zA-Z\u4e00-\u9fff]+/g, '') |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
const addUrl = () => { |
|
|
const addUrl = () => { |
|
|
weburls.value.push('') |
|
|
weburls.value.push('') |
|
|
|
|
|
tags.value.push('') |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const removeUrl = (index: number) => { |
|
|
const removeUrl = (index: number) => { |
|
|
weburls.value.splice(index, 1) |
|
|
weburls.value.splice(index, 1) |
|
|
|
|
|
tags.value.splice(index, 1) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const onTagChange = (index: number, val: string) => { |
|
|
|
|
|
const clean = sanitizeTag(val) |
|
|
|
|
|
tags.value[index] = clean |
|
|
|
|
|
weburls.value[index] = updateUrlWithTag(weburls.value[index] || '', clean) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const onUrlChange = (index: number, val: string) => { |
|
|
|
|
|
weburls.value[index] = val |
|
|
|
|
|
tags.value[index] = extractLtag(val) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const onSaveChange = () => { |
|
|
const onSaveChange = () => { |
|
|
@ -29,17 +94,19 @@ const onSaveChange = () => { |
|
|
|
|
|
|
|
|
onMounted(() => { |
|
|
onMounted(() => { |
|
|
weburls.value = props.urlstr ? props.urlstr.split(",") : [] |
|
|
weburls.value = props.urlstr ? props.urlstr.split(",") : [] |
|
|
|
|
|
tags.value = weburls.value.map(extractLtag) |
|
|
}) |
|
|
}) |
|
|
</script> |
|
|
</script> |
|
|
|
|
|
|
|
|
<template> |
|
|
<template> |
|
|
<el-dialog :model-value="true" :style="{'max-height': '880px','--el-dialog-width': '33%'}" @close="props.closeFunc"> |
|
|
<el-dialog :model-value="true" :style="{'max-height': '880px','--el-dialog-width': '63%'}" @close="props.closeFunc"> |
|
|
<template #header> |
|
|
<template #header> |
|
|
<span style="font-weight: bold;">{{props.title}}</span> |
|
|
<span style="font-weight: bold;">{{props.title}}</span> |
|
|
</template> |
|
|
</template> |
|
|
<div class="tablelist"> |
|
|
<div class="tablelist"> |
|
|
<div v-for="(url, index) in weburls" :key="index" style="display:flex;align-items:center;margin:8px 0;"> |
|
|
<div v-for="(url, index) in weburls" :key="index" style="display:flex;align-items:center;margin:8px 0;"> |
|
|
<el-input v-model="weburls[index]" placeholder="输入网址" style="flex:1;margin-right:8px;"></el-input> |
|
|
<el-input v-model="tags[index]" :maxlength="20" @input="onTagChange(index, $event)" placeholder="输入网址标签" style="margin-right:8px;width: 30%;"></el-input> |
|
|
|
|
|
<el-input v-model="weburls[index]" @input="onUrlChange(index, $event)" placeholder="输入网址" style="flex:1;margin-right:8px;"></el-input> |
|
|
<el-button circle size="small" type="danger" :icon="Delete" @click="removeUrl(index)"></el-button> |
|
|
<el-button circle size="small" type="danger" :icon="Delete" @click="removeUrl(index)"></el-button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
|