feat(new tool): ipinfo
This commit is contained in:
		
							parent
							
								
									bbf73747e4
								
							
						
					
					
						commit
						133b08dc83
					
				
							
								
								
									
										3
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -89,9 +89,11 @@ declare module '@vue/runtime-core' { | |||||||
|     HtmlWysiwygEditor: typeof import('./src/tools/html-wysiwyg-editor/html-wysiwyg-editor.vue')['default'] |     HtmlWysiwygEditor: typeof import('./src/tools/html-wysiwyg-editor/html-wysiwyg-editor.vue')['default'] | ||||||
|     HttpStatusCodes: typeof import('./src/tools/http-status-codes/http-status-codes.vue')['default'] |     HttpStatusCodes: typeof import('./src/tools/http-status-codes/http-status-codes.vue')['default'] | ||||||
|     IbanValidatorAndParser: typeof import('./src/tools/iban-validator-and-parser/iban-validator-and-parser.vue')['default'] |     IbanValidatorAndParser: typeof import('./src/tools/iban-validator-and-parser/iban-validator-and-parser.vue')['default'] | ||||||
|  |     'IconMdi:brushVariant': typeof import('~icons/mdi/brush-variant')['default'] | ||||||
|     'IconMdi:kettleSteamOutline': typeof import('~icons/mdi/kettle-steam-outline')['default'] |     'IconMdi:kettleSteamOutline': typeof import('~icons/mdi/kettle-steam-outline')['default'] | ||||||
|     InputCopyable: typeof import('./src/components/InputCopyable.vue')['default'] |     InputCopyable: typeof import('./src/components/InputCopyable.vue')['default'] | ||||||
|     IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default'] |     IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default'] | ||||||
|  |     IpInfo: typeof import('./src/tools/ip-info/ip-info.vue')['default'] | ||||||
|     Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-converter.vue')['default'] |     Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-converter.vue')['default'] | ||||||
|     Ipv4RangeExpander: typeof import('./src/tools/ipv4-range-expander/ipv4-range-expander.vue')['default'] |     Ipv4RangeExpander: typeof import('./src/tools/ipv4-range-expander/ipv4-range-expander.vue')['default'] | ||||||
|     Ipv4SubnetCalculator: typeof import('./src/tools/ipv4-subnet-calculator/ipv4-subnet-calculator.vue')['default'] |     Ipv4SubnetCalculator: typeof import('./src/tools/ipv4-subnet-calculator/ipv4-subnet-calculator.vue')['default'] | ||||||
| @ -121,6 +123,7 @@ declare module '@vue/runtime-core' { | |||||||
|     MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default'] |     MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default'] | ||||||
|     NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default'] |     NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default'] | ||||||
|     NConfigProvider: typeof import('naive-ui')['NConfigProvider'] |     NConfigProvider: typeof import('naive-ui')['NConfigProvider'] | ||||||
|  |     NH1: typeof import('naive-ui')['NH1'] | ||||||
|     NIcon: typeof import('naive-ui')['NIcon'] |     NIcon: typeof import('naive-ui')['NIcon'] | ||||||
|     NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default'] |     NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default'] | ||||||
|     OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default'] |     OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default'] | ||||||
|  | |||||||
| @ -407,3 +407,25 @@ tools: | |||||||
|     notification: |     notification: | ||||||
|       success: Export successful! |       success: Export successful! | ||||||
|       error: Export failed, please try again. |       error: Export failed, please try again. | ||||||
|  | 
 | ||||||
|  |   ip-info: | ||||||
|  |     title: 'IP Info' | ||||||
|  |     description: 'Query IP address information including location, ISP, and more' | ||||||
|  |     placeholder: 'Enter IP address (e.g. 117.25.96.225)' | ||||||
|  |     query: 'Query' | ||||||
|  |     loading: 'Loading...' | ||||||
|  |     copied: 'Copied to clipboard!' | ||||||
|  |     errors: | ||||||
|  |       emptyIp: 'Please enter an IP address' | ||||||
|  |       fetchFailed: 'Failed to fetch IP information' | ||||||
|  |       generic: 'An error occurred' | ||||||
|  |     fields: | ||||||
|  |       ip: 'IP Address' | ||||||
|  |       hostname: 'Hostname' | ||||||
|  |       city: 'City' | ||||||
|  |       region: 'Region' | ||||||
|  |       country: 'Country' | ||||||
|  |       loc: 'Location' | ||||||
|  |       org: 'Organization' | ||||||
|  |       postal: 'Postal Code' | ||||||
|  |       timezone: 'Timezone' | ||||||
|  | |||||||
| @ -403,3 +403,25 @@ tools: | |||||||
|     notification: |     notification: | ||||||
|       success: 导出成功! |       success: 导出成功! | ||||||
|       error: 导出失败,请重试。 |       error: 导出失败,请重试。 | ||||||
|  | 
 | ||||||
|  |   ip-info: | ||||||
|  |     title: 'IP 信息查询' | ||||||
|  |     description: '查询 IP 地址信息,包括位置、ISP 等详细信息' | ||||||
|  |     placeholder: '请输入 IP 地址(例如:117.25.96.225)' | ||||||
|  |     query: '查询' | ||||||
|  |     loading: '加载中...' | ||||||
|  |     copied: '已复制到剪贴板!' | ||||||
|  |     errors: | ||||||
|  |       emptyIp: '请输入 IP 地址' | ||||||
|  |       fetchFailed: '获取 IP 信息失败' | ||||||
|  |       generic: '发生错误' | ||||||
|  |     fields: | ||||||
|  |       ip: 'IP 地址' | ||||||
|  |       hostname: '主机名' | ||||||
|  |       city: '城市' | ||||||
|  |       region: '地区' | ||||||
|  |       country: '国家' | ||||||
|  |       loc: '位置' | ||||||
|  |       org: '组织' | ||||||
|  |       postal: '邮政编码' | ||||||
|  |       timezone: '时区' | ||||||
|  | |||||||
| @ -88,6 +88,7 @@ import { tool as macAddressLookup } from './mac-address-lookup'; | |||||||
| import { tool as xmlFormatter } from './xml-formatter'; | import { tool as xmlFormatter } from './xml-formatter'; | ||||||
| import { tool as yamlViewer } from './yaml-viewer'; | import { tool as yamlViewer } from './yaml-viewer'; | ||||||
| import { tool as markdownWord } from './markdown-to-word'; | import { tool as markdownWord } from './markdown-to-word'; | ||||||
|  | import { tool as ipInfo } from './ip-info'; | ||||||
| 
 | 
 | ||||||
| export const toolsByCategory: ToolCategory[] = [ | export const toolsByCategory: ToolCategory[] = [ | ||||||
|   { |   { | ||||||
| @ -166,7 +167,7 @@ export const toolsByCategory: ToolCategory[] = [ | |||||||
|   }, |   }, | ||||||
|   { |   { | ||||||
|     name: 'Network', |     name: 'Network', | ||||||
|     components: [ipv4SubnetCalculator, ipv4AddressConverter, ipv4RangeExpander, macAddressLookup, macAddressGenerator, ipv6UlaGenerator], |     components: [ipv4SubnetCalculator, ipv4AddressConverter, ipv4RangeExpander, macAddressLookup, macAddressGenerator, ipv6UlaGenerator, ipInfo], | ||||||
|   }, |   }, | ||||||
|   { |   { | ||||||
|     name: 'Math', |     name: 'Math', | ||||||
|  | |||||||
							
								
								
									
										19
									
								
								src/tools/ip-info/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/tools/ip-info/index.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | /* | ||||||
|  |  * @Author: guihouchang guihouchang@163.com | ||||||
|  |  * @Date: 2025-06-05 17:06:24 | ||||||
|  |  * @LastEditors: guihouchang guihouchang@163.com | ||||||
|  |  * @LastEditTime: 2025-06-05 17:42:33 | ||||||
|  |  * @FilePath: /it-tools/src/tools/ip-info/index.ts | ||||||
|  |  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 | ||||||
|  |  */ | ||||||
|  | import { ArrowLeftBar } from '@vicons/tabler'; | ||||||
|  | import { defineTool } from '../tool'; | ||||||
|  | 
 | ||||||
|  | export const tool = defineTool({ | ||||||
|  |   name: 'ip-info', | ||||||
|  |   path: '/ip-info', | ||||||
|  |   component: () => import('./ip-info.vue'), | ||||||
|  |   icon: ArrowLeftBar, | ||||||
|  |   keywords: ['ip', 'query', 'info', 'location', 'isp'], | ||||||
|  |   createdAt: new Date('2024-08-25'), | ||||||
|  | }); | ||||||
							
								
								
									
										105
									
								
								src/tools/ip-info/ip-info.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								src/tools/ip-info/ip-info.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,105 @@ | |||||||
|  | <script setup lang="ts"> | ||||||
|  | import { ref } from 'vue'; | ||||||
|  | import { useI18n } from 'vue-i18n'; | ||||||
|  | import { useMessage } from 'naive-ui'; | ||||||
|  | import { useCopy } from '@/composable/copy'; | ||||||
|  | 
 | ||||||
|  | const { t } = useI18n(); | ||||||
|  | const message = useMessage(); | ||||||
|  | const { copy } = useCopy(); | ||||||
|  | 
 | ||||||
|  | interface IpInfo { | ||||||
|  |   ip: string | ||||||
|  |   hostname?: string | ||||||
|  |   city?: string | ||||||
|  |   region?: string | ||||||
|  |   country?: string | ||||||
|  |   loc?: string | ||||||
|  |   org?: string | ||||||
|  |   postal?: string | ||||||
|  |   timezone?: string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const ipAddress = ref(''); | ||||||
|  | const ipInfo = ref<IpInfo | null>(null); | ||||||
|  | const loading = ref(false); | ||||||
|  | const error = ref(''); | ||||||
|  | 
 | ||||||
|  | function fetchIpInfo() { | ||||||
|  |   if (!ipAddress.value) { | ||||||
|  |     error.value = t('tools.ip-info.errors.emptyIp'); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   loading.value = true; | ||||||
|  |   error.value = ''; | ||||||
|  | 
 | ||||||
|  |   return fetch(`https://ipinfo.io/${ipAddress.value}`, { | ||||||
|  |     headers: { | ||||||
|  |       Authorization: 'Bearer 7a8a124a501f25', | ||||||
|  |     }, | ||||||
|  |   }) | ||||||
|  |     .then((response) => { | ||||||
|  |       if (!response.ok) { | ||||||
|  |         throw new Error(t('tools.ip-info.errors.fetchFailed')); | ||||||
|  |       } | ||||||
|  |       return response.json(); | ||||||
|  |     }) | ||||||
|  |     .then((data) => { | ||||||
|  |       ipInfo.value = data; | ||||||
|  |     }) | ||||||
|  |     .catch((e) => { | ||||||
|  |       error.value = e instanceof Error ? e.message : t('tools.ip-info.errors.generic'); | ||||||
|  |     }) | ||||||
|  |     .finally(() => { | ||||||
|  |       loading.value = false; | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function copyToClipboard(text: string | undefined) { | ||||||
|  |   if (text) { | ||||||
|  |     copy(text); | ||||||
|  |     message.success(t('tools.ip-info.copied')); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <template> | ||||||
|  |   <div class="flex flex-col gap-4 p-4"> | ||||||
|  |     <div class="flex gap-4"> | ||||||
|  |       <input | ||||||
|  |         v-model="ipAddress" | ||||||
|  |         type="text" | ||||||
|  |         :placeholder="t('tools.ip-info.placeholder')" | ||||||
|  |         class="flex-1 border rounded px-4 py-2" | ||||||
|  |         @keyup.enter="fetchIpInfo" | ||||||
|  |       > | ||||||
|  |       <button | ||||||
|  |         class="rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-600" | ||||||
|  |         :disabled="loading" | ||||||
|  |         @click="fetchIpInfo" | ||||||
|  |       > | ||||||
|  |         {{ loading ? t('tools.ip-info.loading') : t('tools.ip-info.query') }} | ||||||
|  |       </button> | ||||||
|  |     </div> | ||||||
|  | 
 | ||||||
|  |     <div v-if="error" class="rounded bg-red-100 p-4 text-red-500"> | ||||||
|  |       {{ error }} | ||||||
|  |     </div> | ||||||
|  | 
 | ||||||
|  |     <div v-if="ipInfo" class="grid gap-4 border rounded p-4"> | ||||||
|  |       <div v-for="(value, key) in ipInfo" :key="key" class="flex items-center justify-between"> | ||||||
|  |         <span class="font-medium capitalize">{{ t(`tools.ip-info.fields.${key}`) }}:</span> | ||||||
|  |         <div class="flex items-center gap-2"> | ||||||
|  |           <span>{{ value }}</span> | ||||||
|  |           <button | ||||||
|  |             class="p-1 text-gray-500 hover:text-gray-700" | ||||||
|  |             @click="copyToClipboard(value)" | ||||||
|  |           > | ||||||
|  |             <i class="i-mdi-content-copy" /> | ||||||
|  |           </button> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user