feat: 组件切换动画过渡效果,查询ip转移到后端实现
This commit is contained in:
+1
-1
@@ -123,7 +123,7 @@ export default [
|
|||||||
//标题筛选
|
//标题筛选
|
||||||
if (title != '') {
|
if (title != '') {
|
||||||
list = list.filter(item => {
|
list = list.filter(item => {
|
||||||
let tmpValue = item.value.toLowerCase()
|
let tmpValue = item.title.toLowerCase()
|
||||||
return tmpValue.indexOf(title.toLowerCase()) !== -1;
|
return tmpValue.indexOf(title.toLowerCase()) !== -1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-1
@@ -11,7 +11,13 @@ import Right from '@/components/Layout/Right/Right.vue'
|
|||||||
<el-col :xl="4" :md="1" class=""></el-col>
|
<el-col :xl="4" :md="1" class=""></el-col>
|
||||||
<el-col :xl="16" :md="22" class="mt-4">
|
<el-col :xl="16" :md="22" class="mt-4">
|
||||||
<el-row class="flex-1">
|
<el-row class="flex-1">
|
||||||
<el-col :xl="19" :md="19" class=""><router-view></router-view></el-col>
|
<el-col :xl="19" :md="19" class="">
|
||||||
|
<router-view v-slot="{ Component, route }">
|
||||||
|
<transition name="animation" mode="out-in">
|
||||||
|
<component :is="Component" :key="route.path"></component>
|
||||||
|
</transition>
|
||||||
|
</router-view>
|
||||||
|
</el-col>
|
||||||
<el-col :xl="5" :md="5" class="">
|
<el-col :xl="5" :md="5" class="">
|
||||||
<Right/>
|
<Right/>
|
||||||
</el-col>
|
</el-col>
|
||||||
@@ -25,4 +31,20 @@ import Right from '@/components/Layout/Right/Right.vue'
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
/* 过度动画配置代码 */
|
||||||
|
.animation-enter-from,
|
||||||
|
.animation-leave-to {
|
||||||
|
transform: translateX(20px);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.animation-enter-to,
|
||||||
|
.animation-leave-from {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
.animation-enter-active {
|
||||||
|
transition: all 0.7s ease;
|
||||||
|
}
|
||||||
|
.animation-leave-active {
|
||||||
|
transition: all 0.3s cubic-bezier(1, 0.6, 0.6, 1);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
+3
-2
@@ -2,6 +2,7 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
|
IpReqData,
|
||||||
getIpResponseData
|
getIpResponseData
|
||||||
} from './type'
|
} from './type'
|
||||||
|
|
||||||
@@ -9,7 +10,7 @@ import type {
|
|||||||
|
|
||||||
enum API {
|
enum API {
|
||||||
//获取ip
|
//获取ip
|
||||||
GET_IP = '/ip/get?ip='
|
GET_IP = '/openapi/ip'
|
||||||
}
|
}
|
||||||
//获取ip
|
//获取ip
|
||||||
export const getIp = (ip:string) => request.get<any, getIpResponseData>(API.GET_IP + ip)
|
export const getIp = (data: IpReqData) => request.post<any, getIpResponseData>(API.GET_IP, data)
|
||||||
+14
-4
@@ -1,6 +1,16 @@
|
|||||||
//响应格式
|
import { ResponseData } from "../common"
|
||||||
export interface getIpResponseData {
|
|
||||||
code: number,
|
export interface IpReqData {
|
||||||
|
ip: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IpInfo {
|
||||||
ip: string,
|
ip: string,
|
||||||
address: string
|
pos: string,
|
||||||
|
isp: string
|
||||||
|
}
|
||||||
|
|
||||||
|
//响应格式
|
||||||
|
export interface getIpResponseData extends ResponseData {
|
||||||
|
data: IpInfo
|
||||||
}
|
}
|
||||||
@@ -28,7 +28,7 @@ onMounted(() => {
|
|||||||
<div>
|
<div>
|
||||||
<!-- card -->
|
<!-- card -->
|
||||||
<div class="mr-3 flex justify-between flex-wrap self-card-div" :gutter="10">
|
<div class="mr-3 flex justify-between flex-wrap self-card-div" :gutter="10">
|
||||||
<router-link v-for="(item, index) in toolsStore.list" :key="index" :to="item.url" class="flex flex-col mt-3 border-solid rounded border-gray border w-[32.5%] p-2 bg-gray-50 hover:shadow-md">
|
<router-link v-for="(item, index) in toolsStore.list" :key="index" :to="item.url" class="flex flex-col mt-3 border-solid rounded border-gray w-[32.5%] p-2 bg-gray-100 hover:shadow-md">
|
||||||
<div class="flex items-center border-b pb-2">
|
<div class="flex items-center border-b pb-2">
|
||||||
<el-image :src="item.logo" class="w-10 h-10 min-h-[2.5rem] min-w-[2.5rem] rounded-full"></el-image>
|
<el-image :src="item.logo" class="w-10 h-10 min-h-[2.5rem] min-w-[2.5rem] rounded-full"></el-image>
|
||||||
<div class="flex flex-col ml-2 w-full">
|
<div class="flex flex-col ml-2 w-full">
|
||||||
|
|||||||
+16
-11
@@ -1,24 +1,26 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, reactive } from 'vue'
|
import { onMounted, reactive } from 'vue'
|
||||||
import { getIp } from '@/api/ip'
|
import { useToolsStore } from '@/store/modules/tools'
|
||||||
import { isIp } from '@/utils/verify'
|
import { isIp } from '@/utils/verify'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import DetailHeader from '@/components/Layout/DetailHeader/DetailHeader.vue'
|
import DetailHeader from '@/components/Layout/DetailHeader/DetailHeader.vue'
|
||||||
|
|
||||||
const info = reactive({
|
const info = reactive({
|
||||||
title: "IP查询",
|
title: "IP查询",
|
||||||
content: '',
|
|
||||||
ip: '',
|
|
||||||
address: '',
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
//store
|
||||||
|
const toolsStore = useToolsStore()
|
||||||
|
const params = reactive({
|
||||||
|
ip: '',
|
||||||
|
})
|
||||||
//查询
|
//查询
|
||||||
const search = async (type: string) => {
|
const search = async (type: string) => {
|
||||||
try {
|
try {
|
||||||
//通过点击获取ip信息
|
//通过点击获取ip信息
|
||||||
if (type == 'click') {
|
if (type == 'click') {
|
||||||
//验证是否ip地址
|
//验证是否ip地址
|
||||||
if (!isIp(info.content)) {
|
if (!isIp(params.ip)) {
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: "无效的ip地址",
|
message: "无效的ip地址",
|
||||||
type: "warning",
|
type: "warning",
|
||||||
@@ -28,9 +30,7 @@ const search = async (type: string) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//获取信息
|
//获取信息
|
||||||
const result: any = await getIp(info.content)
|
await toolsStore.getIp(params)
|
||||||
info.ip = result.data.ip
|
|
||||||
info.address = result.data.address
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
}
|
}
|
||||||
@@ -48,21 +48,26 @@ onMounted(() => {
|
|||||||
<div>
|
<div>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="mr-2 w-60">
|
<div class="mr-2 w-60">
|
||||||
<el-input v-model="info.content" ></el-input>
|
<el-input v-model="params.ip" ></el-input>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-button type="primary" @click="search('click')">查询</el-button>
|
<el-button type="primary" @click="search('click')">查询</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-3 min-h-md bg-gray-100 p-3 mb-3 flex flex-col">
|
<div class="mt-3 min-h-md bg-gray-100 p-3 mb-3 flex flex-col">
|
||||||
<div class="bg-white p-2 font-bold text-xl">您的IP信息</div>
|
<div class="bg-white p-2 font-bold text-xl">您的IP信息</div>
|
||||||
|
<div class="bg-white p-2 flex">
|
||||||
|
<div class="mr-1">运营商: </div>
|
||||||
|
<div>{{ toolsStore.ipData.isp }}</div>
|
||||||
|
</div>
|
||||||
<div class="bg-white p-2 flex">
|
<div class="bg-white p-2 flex">
|
||||||
<div class="mr-1">域名解析地址: </div>
|
<div class="mr-1">域名解析地址: </div>
|
||||||
<div>{{ info.ip }}</div>
|
<div>{{ toolsStore.ipData.ip }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-white p-2 flex">
|
<div class="bg-white p-2 flex">
|
||||||
<div class="mr-1">所在地理位置: </div>
|
<div class="mr-1">所在地理位置: </div>
|
||||||
<div>{{ info.address }}</div>
|
<div>{{ toolsStore.ipData.pos }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ const props = defineProps({
|
|||||||
<div>
|
<div>
|
||||||
<div class="text-gray-600">
|
<div class="text-gray-600">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<a href="/" class="flex items-center">
|
<RouterLink to="/" class="flex items-center">
|
||||||
<el-icon color="blue"><Back /></el-icon>
|
<el-icon color="blue"><Back /></el-icon>
|
||||||
<div>返回首页</div>
|
<div>返回首页</div>
|
||||||
</a>
|
</RouterLink>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -85,7 +85,6 @@ onMounted(() => {
|
|||||||
<div class="mr-3">
|
<div class="mr-3">
|
||||||
<ul class="flex bg-gray-100 h-10 rounded leading-10 pl-3">
|
<ul class="flex bg-gray-100 h-10 rounded leading-10 pl-3">
|
||||||
<li class="flex items-center mr-3">
|
<li class="flex items-center mr-3">
|
||||||
<el-text></el-text>
|
|
||||||
<div
|
<div
|
||||||
class="hover:text-blue-400 hover:underline hover:decoration-2 hover:underline-offset-[6px] text-sm" :class="searchParam.cateId == 0 ? 'text-blue-400 underline decoration-2 underline-offset-[6px]' : ''"
|
class="hover:text-blue-400 hover:underline hover:decoration-2 hover:underline-offset-[6px] text-sm" :class="searchParam.cateId == 0 ? 'text-blue-400 underline decoration-2 underline-offset-[6px]' : ''"
|
||||||
@click="chooseCate(0)"
|
@click="chooseCate(0)"
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive } from 'vue'
|
import { reactive } from 'vue'
|
||||||
import DetailHeader from '@/components/Layout/DetailHeader/DetailHeader.vue'
|
import DetailHeader from '@/components/Layout/DetailHeader/DetailHeader.vue'
|
||||||
import clipboard3 from 'vue-clipboard3'
|
|
||||||
import { ElMessage } from 'element-plus';
|
|
||||||
import { Md5 } from 'ts-md5'
|
import { Md5 } from 'ts-md5'
|
||||||
|
import { copy } from '@/utils/string'
|
||||||
const info = reactive({
|
const info = reactive({
|
||||||
title: "MD5在线加密",
|
title: "MD5在线加密",
|
||||||
encryptStr: '',
|
encryptStr: '',
|
||||||
@@ -26,34 +25,9 @@ const clear = () => {
|
|||||||
info.encryptStr = ''
|
info.encryptStr = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
const {toClipboard} = clipboard3()
|
//copy
|
||||||
const copyRes = async (resStr: string) => {
|
const copyRes = async (resStr: string) => {
|
||||||
try {
|
copy(resStr)
|
||||||
//check
|
|
||||||
if (resStr == '') {
|
|
||||||
ElMessage({
|
|
||||||
message: "无可复制内容",
|
|
||||||
type: "warning",
|
|
||||||
duration: 1500
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//copy
|
|
||||||
await toClipboard(resStr)
|
|
||||||
ElMessage({
|
|
||||||
message: "复制成功",
|
|
||||||
type: "success",
|
|
||||||
duration: 1500
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
console.log("复制失败")
|
|
||||||
console.log(error)
|
|
||||||
ElMessage({
|
|
||||||
message: "复制失败",
|
|
||||||
type: "error",
|
|
||||||
duration: 1500
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,8 @@
|
|||||||
import { onMounted, onUnmounted, reactive } from 'vue'
|
import { onMounted, onUnmounted, reactive } from 'vue'
|
||||||
import { VideoPause,VideoPlay,CopyDocument } from '@element-plus/icons-vue'
|
import { VideoPause,VideoPlay,CopyDocument } from '@element-plus/icons-vue'
|
||||||
import { Jh_getTimeStamp,Jh_timeStampToTime,Jh_convertTimeStamp } from '@/utils/time'
|
import { Jh_getTimeStamp,Jh_timeStampToTime,Jh_convertTimeStamp } from '@/utils/time'
|
||||||
import clipboard3 from 'vue-clipboard3'
|
|
||||||
import { ElMessage } from 'element-plus';
|
|
||||||
import DetailHeader from '@/components/Layout/DetailHeader/DetailHeader.vue'
|
import DetailHeader from '@/components/Layout/DetailHeader/DetailHeader.vue'
|
||||||
|
import { copy } from '@/utils/string'
|
||||||
const info = reactive({
|
const info = reactive({
|
||||||
title: "时间戳转换",
|
title: "时间戳转换",
|
||||||
nowTime: Jh_getTimeStamp(),
|
nowTime: Jh_getTimeStamp(),
|
||||||
@@ -77,24 +76,8 @@ const timeTran = (type: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//复制时间戳
|
//复制时间戳
|
||||||
const {toClipboard} = clipboard3()
|
const copyRes = async () => {
|
||||||
const copyStamp = async () => {
|
copy('' + info.nowTime)
|
||||||
try {
|
|
||||||
await toClipboard('' + info.nowTime)
|
|
||||||
ElMessage({
|
|
||||||
message: "复制成功",
|
|
||||||
type: "success",
|
|
||||||
duration: 1500
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
console.log("复制失败")
|
|
||||||
console.log(error)
|
|
||||||
ElMessage({
|
|
||||||
message: "复制失败",
|
|
||||||
type: "error",
|
|
||||||
duration: 1500
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -105,7 +88,7 @@ const copyStamp = async () => {
|
|||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<div class="flex flex-direction">
|
<div class="flex flex-direction">
|
||||||
<el-text class="mr-2 w-12">现在</el-text>
|
<el-text class="mr-2 w-12">现在</el-text>
|
||||||
<el-button class="mr-3" link @click="copyStamp()">{{ info.nowTime }} <el-icon class="ml-1 mr-1"><CopyDocument /></el-icon></el-button>
|
<el-button class="mr-3" link @click="copyRes()">{{ info.nowTime }} <el-icon class="ml-1 mr-1"><CopyDocument /></el-icon></el-button>
|
||||||
<el-button v-if="info.isPlay" type="danger" link class="flex items-center" @click="isPlayChange()"><el-icon class="mr-1" size="16"><VideoPlay/></el-icon>停止</el-button>
|
<el-button v-if="info.isPlay" type="danger" link class="flex items-center" @click="isPlayChange()"><el-icon class="mr-1" size="16"><VideoPlay/></el-icon>停止</el-button>
|
||||||
<el-button v-else="info.isPlay" type="primary" link class="flex items-center" @click="isPlayChange()"><el-icon class="mr-1" size="16"><VideoPause /></el-icon>开始</el-button>
|
<el-button v-else="info.isPlay" type="primary" link class="flex items-center" @click="isPlayChange()"><el-icon class="mr-1" size="16"><VideoPause /></el-icon>开始</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+2
-2
@@ -14,9 +14,9 @@ const router = createRouter({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
router.beforeEach((to, from, next) => {
|
// _form: ‘_’表示占位变量,可以不被使用
|
||||||
|
router.beforeEach((to, _from, next) => {
|
||||||
if (to.meta.title && to.meta.title != '') {
|
if (to.meta.title && to.meta.title != '') {
|
||||||
console.log(from)
|
|
||||||
let oldTitle = document.title
|
let oldTitle = document.title
|
||||||
document.title = <string>to.meta.title + ' - ' + oldTitle
|
document.title = <string>to.meta.title + ' - ' + oldTitle
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
//创建tools相关的小工具
|
//创建tools相关的小工具
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { getTools, getToolCate} from '@/api/tools'
|
import { getTools, getToolCate} from '@/api/tools'
|
||||||
|
import { getIp } from '@/api/ip'
|
||||||
import type { ToolsReqData, ToolsInfo, ToolCate } from '@/api/tools/type'
|
import type { ToolsReqData, ToolsInfo, ToolCate } from '@/api/tools/type'
|
||||||
|
import type { IpReqData, IpInfo } from '@/api/ip/type'
|
||||||
|
|
||||||
export const useToolsStore = defineStore('tools', {
|
export const useToolsStore = defineStore('tools', {
|
||||||
//用来存放变量
|
//用来存放变量
|
||||||
state: () => ({
|
state: () => ({
|
||||||
list: [] as ToolsInfo[],
|
list: [] as ToolsInfo[],
|
||||||
cates: [] as ToolCate[],
|
cates: [] as ToolCate[],
|
||||||
|
ipData: {} as IpInfo,
|
||||||
}),
|
}),
|
||||||
//方法
|
//方法
|
||||||
actions: {
|
actions: {
|
||||||
@@ -32,6 +35,16 @@ export const useToolsStore = defineStore('tools', {
|
|||||||
} else {
|
} else {
|
||||||
return Promise.reject(new Error(result.message))
|
return Promise.reject(new Error(result.message))
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
//获取ip
|
||||||
|
async getIp(data: IpReqData) {
|
||||||
|
const result: any = await getIp(data)
|
||||||
|
if (result.code == 200) {
|
||||||
|
this.ipData = result.data
|
||||||
|
return result.message
|
||||||
|
} else {
|
||||||
|
return Promise.reject(new Error(result.message))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -2,7 +2,7 @@ import axios from "axios";
|
|||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
//创建axios实例
|
//创建axios实例
|
||||||
let request = axios.create({
|
let request = axios.create({
|
||||||
baseURL: import.meta.env.VITE_APP_BASE_API,
|
baseURL: import.meta.env.VITE_IS_MOCK == 'true' ? import.meta.env.VITE_APP_BASE_API : import.meta.env.VITE_SERVE + import.meta.env.VITE_APP_BASE_API,
|
||||||
timeout: 5000
|
timeout: 5000
|
||||||
})
|
})
|
||||||
//请求拦截器
|
//请求拦截器
|
||||||
|
|||||||
@@ -42,8 +42,6 @@ export function copy(resStr: string) {
|
|||||||
duration: 1500
|
duration: 1500
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("复制失败")
|
|
||||||
console.log(error)
|
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: "复制失败",
|
message: "复制失败",
|
||||||
type: "error",
|
type: "error",
|
||||||
|
|||||||
+3
-11
@@ -9,6 +9,9 @@ import { createHtmlPlugin } from 'vite-plugin-html'
|
|||||||
export default defineConfig(({command, mode}) => {
|
export default defineConfig(({command, mode}) => {
|
||||||
let env = loadEnv(mode, process.cwd())
|
let env = loadEnv(mode, process.cwd())
|
||||||
return {
|
return {
|
||||||
|
define: {
|
||||||
|
'process.env.NODE_ENV': JSON.stringify('production')
|
||||||
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
vue(),
|
vue(),
|
||||||
createSvgIconsPlugin({
|
createSvgIconsPlugin({
|
||||||
@@ -37,17 +40,6 @@ export default defineConfig(({command, mode}) => {
|
|||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
proxy: {
|
proxy: {
|
||||||
'/v1/ip': {
|
|
||||||
target: 'https://searchplugin.csdn.net', //ip查询
|
|
||||||
changeOrigin: true,
|
|
||||||
rewrite: (path) => path.replace(/^\/v1\/ip/, '/api/v1/ip'),
|
|
||||||
// bypass(req, res, options) {
|
|
||||||
// console.log(1111)
|
|
||||||
// const proxyUrl = new URL(options.rewrite(req.url) || '', (options.target) as string)?.href || ''
|
|
||||||
// req.headers['x-req-proxyUrl'] = proxyUrl;
|
|
||||||
// res.setHeader("x-res-proxyUrl", proxyUrl)
|
|
||||||
// }
|
|
||||||
},
|
|
||||||
[env.VITE_APP_BASE_API] : {
|
[env.VITE_APP_BASE_API] : {
|
||||||
target: env.VITE_SERVE,
|
target: env.VITE_SERVE,
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user