feat: pinia结合mock实现按分类和标题搜索工具,布局和样式调整
This commit is contained in:
+2
-1
@@ -1,5 +1,6 @@
|
|||||||
# 变量必须以 VITE_ 为前缀才能暴露给外部读取
|
# 变量必须以 VITE_ 为前缀才能暴露给外部读取
|
||||||
NODE_ENV = 'dev'
|
NODE_ENV = 'dev'
|
||||||
VITE_APP_TITLE = '工具坊'
|
VITE_APP_TITLE = '工具坊'
|
||||||
|
VITE_APP_WEBSITE = 'xxx.xxx.com'
|
||||||
VITE_APP_BASE_API = '/api'
|
VITE_APP_BASE_API = '/api'
|
||||||
VITE_SERVE = 'http://xxx.com'
|
VITE_SERVE = ''
|
||||||
+2
-2
@@ -11,8 +11,8 @@ node_modules
|
|||||||
dist
|
dist
|
||||||
dist-ssr
|
dist-ssr
|
||||||
*.local
|
*.local
|
||||||
.env.dev
|
.env.development
|
||||||
.env.pro
|
.env.production
|
||||||
.vscode
|
.vscode
|
||||||
|
|
||||||
# Editor directories and files
|
# Editor directories and files
|
||||||
|
|||||||
+153
@@ -0,0 +1,153 @@
|
|||||||
|
//获取tools
|
||||||
|
function getTools() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
value: '时间戳转换',
|
||||||
|
img: 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
|
||||||
|
desc: '在线时间戳转换工具以及获取当前时间戳',
|
||||||
|
url: '/timetran',
|
||||||
|
cateId: 2,
|
||||||
|
cate: '开发运维',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
value: 'MD5在线加密',
|
||||||
|
img: 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
|
||||||
|
desc: 'MD5在线加密,长度包含32位、16位',
|
||||||
|
url: '/MD5',
|
||||||
|
cateId: 2,
|
||||||
|
cate: '开发运维',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
value: 'Json在线转换',
|
||||||
|
img: 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
|
||||||
|
desc: '在线编辑json, 语法检查',
|
||||||
|
url: '/json',
|
||||||
|
cateId: 2,
|
||||||
|
cate: '开发运维',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
value: '正则测试工具',
|
||||||
|
img: 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
|
||||||
|
desc: '正则表达式测试工具, 常用正则表达式',
|
||||||
|
url: '/reg',
|
||||||
|
cateId: 2,
|
||||||
|
cate: '开发运维',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
value: 'Unicode转中文',
|
||||||
|
img: 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
|
||||||
|
desc: 'Unicode和中文的相互转换',
|
||||||
|
url: '/unicode',
|
||||||
|
cateId: 2,
|
||||||
|
cate: '开发运维',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
value: '字数统计',
|
||||||
|
img: 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
|
||||||
|
desc: '在线统计字符串的字数、段落、标点符号数量',
|
||||||
|
url: '/wordCount',
|
||||||
|
cateId: 3,
|
||||||
|
cate: '文本处理',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
value: 'IP查询',
|
||||||
|
img: 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
|
||||||
|
desc: '在线查询ip地址、ip归属地',
|
||||||
|
url: '/ip',
|
||||||
|
cateId: 6,
|
||||||
|
cate: '查询相关',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
value: '常用进制转换',
|
||||||
|
img: 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
|
||||||
|
desc: '在线进制转换工具,可在2到64进制之间相互转换',
|
||||||
|
url: '/scaletran',
|
||||||
|
cateId: 4,
|
||||||
|
cate: '教育学术',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
value: '在线图片处理',
|
||||||
|
img: 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
|
||||||
|
desc: '在线图片裁剪,标注,滤镜,画等操作',
|
||||||
|
url: '/signimage',
|
||||||
|
cateId: 5,
|
||||||
|
cate: '设计工具',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取tools分类
|
||||||
|
function getToolsCate() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: 0,
|
||||||
|
value: '全部工具',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
value: '开发运维'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
value: '文本处理'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
value: '教育学术'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
value: '设计工具'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
value: '查询相关'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
url: '/api/tools',
|
||||||
|
method: 'get',//请求方式
|
||||||
|
response: (request) => {
|
||||||
|
//接收参数
|
||||||
|
const { cateId, title } = request.query
|
||||||
|
//调用获取用户信息函数,用于判断是否有此用户
|
||||||
|
let list = getTools()
|
||||||
|
//标题筛选
|
||||||
|
if (title != '') {
|
||||||
|
list = list.filter(item => {
|
||||||
|
let tmpValue = item.value.toLowerCase()
|
||||||
|
return tmpValue.indexOf(title.toLowerCase()) !== -1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//分类筛选
|
||||||
|
if (cateId > 0) {
|
||||||
|
list = list.filter(item => {
|
||||||
|
return item.cateId == cateId;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return { code: 200, message: 'ok', data: list }
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: '/api/tool/cates',
|
||||||
|
method: 'get',//请求方式
|
||||||
|
response: ({ body }) => {
|
||||||
|
//获取请求体携带过来的用户名与密码
|
||||||
|
//调用获取用户信息函数,用于判断是否有此用户
|
||||||
|
const list = getToolsCate()
|
||||||
|
return { code: 200, message: 'ok', data: list }
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
+2
-2
@@ -5,8 +5,8 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build:dev": "vue-tsc && vite build --mode dev",
|
"build:dev": "vue-tsc && vite build --mode development",
|
||||||
"build:pro": "vue-tsc && vite build --mode pro",
|
"build:pro": "vue-tsc && vite build --mode production",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"preinstall": "node ./scripts/preinstall.js"
|
"preinstall": "node ./scripts/preinstall.js"
|
||||||
},
|
},
|
||||||
|
|||||||
+3
-3
@@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Header from '@/components/Header/Header.vue'
|
import Header from '@/components/Layout/Header/Header.vue'
|
||||||
import Floor from '@/components/Floor/Floor.vue'
|
import Floor from '@/components/Layout/Floor/Floor.vue'
|
||||||
import Right from '@/components/Right/Right.vue'
|
import Right from '@/components/Layout/Right/Right.vue'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
//请求响应的公共数据
|
||||||
|
export interface ResponseData {
|
||||||
|
code: number,
|
||||||
|
message: string,
|
||||||
|
}
|
||||||
+1
-1
@@ -9,7 +9,7 @@ import type {
|
|||||||
|
|
||||||
enum API {
|
enum API {
|
||||||
//获取ip
|
//获取ip
|
||||||
GET_IP = '/api/v1/ip/get?ip='
|
GET_IP = '/v1/ip/get?ip='
|
||||||
}
|
}
|
||||||
//获取ip
|
//获取ip
|
||||||
export const getIp = (ip:string) => request.get<any, getIpResponseData>(API.GET_IP + ip)
|
export const getIp = (ip:string) => request.get<any, getIpResponseData>(API.GET_IP + ip)
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
//响应格式
|
//响应格式
|
||||||
export interface getIpResponseData {
|
export interface getIpResponseData {
|
||||||
code: number,
|
code: number,
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
//统一管理咱们项目用户相关的接口
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
import type {
|
||||||
|
ToolsReqData,
|
||||||
|
ToolsResponseData,
|
||||||
|
ToolCateResponseData
|
||||||
|
} from './type'
|
||||||
|
|
||||||
|
//项目用户相关的请求地址
|
||||||
|
|
||||||
|
enum API {
|
||||||
|
//获取tools
|
||||||
|
GET_TOOLS = '/tools',
|
||||||
|
//获取tool cate
|
||||||
|
GET_TOOL_CATES = '/tool/cates'
|
||||||
|
}
|
||||||
|
//获取tools
|
||||||
|
export const getTools = (data: ToolsReqData) => request.get<any, ToolsResponseData>(API.GET_TOOLS, {
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
//获取tool cate
|
||||||
|
export const getToolCate = () => request.get<any, ToolCateResponseData>(API.GET_TOOL_CATES)
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { ResponseData } from "../common"
|
||||||
|
|
||||||
|
export interface ToolsReqData {
|
||||||
|
cateId: number,
|
||||||
|
title: string
|
||||||
|
}
|
||||||
|
|
||||||
|
//tools
|
||||||
|
export interface ToolsInfo {
|
||||||
|
id: number,
|
||||||
|
value: string,
|
||||||
|
img: string,
|
||||||
|
desc: string,
|
||||||
|
url: string,
|
||||||
|
cate: string
|
||||||
|
}
|
||||||
|
|
||||||
|
//tools cate
|
||||||
|
export interface ToolCate {
|
||||||
|
id: number,
|
||||||
|
value: string,
|
||||||
|
img: string,
|
||||||
|
desc: string,
|
||||||
|
url: string,
|
||||||
|
cate: string
|
||||||
|
}
|
||||||
|
|
||||||
|
//tools list response
|
||||||
|
export interface ToolsResponseData extends ResponseData {
|
||||||
|
data: ToolsInfo[]
|
||||||
|
}
|
||||||
|
|
||||||
|
//tools cate response
|
||||||
|
export interface ToolCateResponseData extends ResponseData {
|
||||||
|
data: ToolCate[]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { ref } from 'vue'
|
|
||||||
// import { Search } from '@element-plus/icons-vue'
|
|
||||||
// const searchInput = ref('')
|
|
||||||
const appName = ref('工具坊')
|
|
||||||
const appNet = ref('tools.ranblogs.com')
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<header class="">
|
|
||||||
<nav class="h-20 w-full leading-10 flex flex-col justify-between pt-2 pb-2">
|
|
||||||
<el-row>
|
|
||||||
<el-col :xl="4" :md="1"></el-col>
|
|
||||||
<el-col :xl="16" :md="22">
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<!-- left -->
|
|
||||||
<router-link class="ml-4 flex flex-row" to="/">
|
|
||||||
<img class="h-10 w-auto rounded-lg lg:h-16 mr-2 mt-auto mb-auto" src="../../assets/logo.png" :alt="appNet">
|
|
||||||
<div class="flex flex-col mt-auto mb-auto">
|
|
||||||
<div class="text-xl">{{ appName }}</div>
|
|
||||||
<div class="text-sm text-gray-500">{{ appNet }}</div>
|
|
||||||
</div>
|
|
||||||
</router-link>
|
|
||||||
|
|
||||||
<!-- right -->
|
|
||||||
<div class=" w-full md:w-auto flex hidden md:block">
|
|
||||||
<ul class="flex mt-4 flex-col md:flex-row md:mt-0 justify-end">
|
|
||||||
<!-- <li class="mr-5">
|
|
||||||
<el-input v-model="searchInput" placeholder="搜索工具" class="w-full max-w-xl h-10" :prefix-icon="Search"/>
|
|
||||||
</li> -->
|
|
||||||
<li class="hover:text-blue-500">语言</li>
|
|
||||||
<li class="ml-5 hover:text-blue-500">加入收藏</li>
|
|
||||||
<li class="ml-5 hover:text-blue-500">常见问题</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xl="4" :md="1" class="flex"></el-col>
|
|
||||||
</el-row>
|
|
||||||
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
||||||
+31
-121
@@ -1,138 +1,48 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive } from 'vue';
|
import { reactive, onMounted } from 'vue';
|
||||||
import { RouterLink } from "vue-router"
|
import { RouterLink } from "vue-router"
|
||||||
const info = reactive({
|
import { Star } from '@element-plus/icons-vue'
|
||||||
cates: [
|
import { useToolsStore } from '@/store/modules/tools'
|
||||||
{
|
|
||||||
id: 1,
|
//store
|
||||||
value: '全部工具',
|
const toolsStore = useToolsStore()
|
||||||
},
|
//查询参数
|
||||||
{
|
const searchParam = reactive({
|
||||||
id: 2,
|
cateId: 0,
|
||||||
value: '文本处理'
|
title: ''
|
||||||
},
|
})
|
||||||
{
|
const getToolsList = async () => {
|
||||||
id: 3,
|
try {
|
||||||
value: '查询相关'
|
await toolsStore.getTools(searchParam)
|
||||||
},
|
} catch (error) {
|
||||||
{
|
console.log(error)
|
||||||
id: 4,
|
}
|
||||||
value: '教育学术'
|
}
|
||||||
},
|
|
||||||
{
|
onMounted(() => {
|
||||||
id: 5,
|
getToolsList()
|
||||||
value: '设计工具'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 6,
|
|
||||||
value: '开发运维'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
tools: [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
value: '时间戳转换',
|
|
||||||
img: 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
|
|
||||||
desc: '在线时间戳转换工具以及获取当前时间戳',
|
|
||||||
url: '/timetran',
|
|
||||||
cate: '开发运维',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
value: 'MD5在线加密',
|
|
||||||
img: 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
|
|
||||||
desc: 'MD5在线加密,长度包含32位、16位',
|
|
||||||
url: '/MD5',
|
|
||||||
cate: '开发运维',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
value: 'Json在线转换',
|
|
||||||
img: 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
|
|
||||||
desc: '在线编辑json, 语法检查',
|
|
||||||
url: '/json',
|
|
||||||
cate: '开发运维',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
value: '正则测试工具',
|
|
||||||
img: 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
|
|
||||||
desc: '正则表达式测试工具, 常用正则表达式',
|
|
||||||
url: '/reg',
|
|
||||||
cate: '开发运维',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
value: 'Unicode转中文',
|
|
||||||
img: 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
|
|
||||||
desc: 'Unicode和中文的相互转换',
|
|
||||||
url: '/unicode',
|
|
||||||
cate: '开发运维',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
value: '字数统计',
|
|
||||||
img: 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
|
|
||||||
desc: '在线统计字符串的字数、段落、标点符号数量',
|
|
||||||
url: '/wordCount',
|
|
||||||
cate: '文本处理',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
value: 'IP查询',
|
|
||||||
img: 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
|
|
||||||
desc: '在线查询ip地址、ip归属地',
|
|
||||||
url: '/ip',
|
|
||||||
cate: '查询相关',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
value: '常用进制转换',
|
|
||||||
img: 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
|
|
||||||
desc: '制转换器是一个在线进制转换工具,可在二进制、八进制、十进制、十六进制、三十二进制以及36以内任意进制之间相互转换',
|
|
||||||
url: '/scaletran',
|
|
||||||
cate: '教育学术',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
value: '在线图片处理',
|
|
||||||
img: 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
|
|
||||||
desc: '在线图片处理',
|
|
||||||
url: '/signimage',
|
|
||||||
cate: '设计工具',
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!-- cates -->
|
|
||||||
<div class="mr-3">
|
|
||||||
<ul class="flex bg-gray-100 h-10 rounded leading-10 pl-3">
|
|
||||||
<li v-for="(item, index) in info.cates" :key="index" class="flex items-center">
|
|
||||||
<el-text>{{ index != 0 ? ' ' : '' }} </el-text>
|
|
||||||
<el-text class="hover:text-blue-400 hover:underline hover:decoration-4 hover:underline-offset-[6px]">{{ item.value }}</el-text>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- card -->
|
<!-- card -->
|
||||||
<div class="mr-3 mt-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 info.tools" :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 border w-[32.5%] p-2 bg-gray-50 hover:shadow-md">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center border-b pb-2">
|
||||||
<el-image :src="item.img" class="w-10 h-10 min-h-[2.5rem] min-w-[2.5rem] rounded-full"></el-image>
|
<el-image :src="item.img" class="w-10 h-10 min-h-[2.5rem] min-w-[2.5rem] rounded-full"></el-image>
|
||||||
<div class="flex flex-col ml-2">
|
<div class="flex flex-col ml-2 w-full">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="font-semibold text-lg ">{{ item.value }}</div>
|
<div class="font-semibold text-lg ">{{ item.value }}</div>
|
||||||
<!-- <div>加入收藏</div> -->
|
|
||||||
</div>
|
</div>
|
||||||
<el-text line-clamp="2">{{ item.desc }}</el-text>
|
<div class="flex justify-between">
|
||||||
|
<el-text size="small">{{ item.cate }}</el-text>
|
||||||
|
<el-button :icon="Star" circle size="small"/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-divider border-style="double" class="m-1" />
|
<div class="flex items-center justify-between mt-2">
|
||||||
<div class="flex items-center justify-between">
|
<el-text line-clamp="1">{{ item.desc }}</el-text>
|
||||||
<el-text size="small">http://tools.ranblogs.com/timeTran</el-text>
|
|
||||||
</div>
|
</div>
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, reactive } from 'vue'
|
import { onMounted, reactive } from 'vue'
|
||||||
import { Back } from '@element-plus/icons-vue'
|
|
||||||
import { getIp } from '@/api/ip'
|
import { getIp } from '@/api/ip'
|
||||||
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'
|
||||||
|
|
||||||
const info = reactive({
|
const info = reactive({
|
||||||
title: "IP查询",
|
title: "IP查询",
|
||||||
@@ -43,16 +43,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col mt-3 ml-4 flex-1 mr-10">
|
<div class="flex flex-col mt-3 ml-4 flex-1 mr-10">
|
||||||
<div class="text-gray-600">
|
<DetailHeader :title="info.title"></DetailHeader>
|
||||||
<a href="/" class="flex items-center">
|
|
||||||
<el-icon color="blue"><Back /></el-icon>
|
|
||||||
<div>返回首页</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-xl mt-5 mb-5">
|
|
||||||
{{ info.title }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive } from 'vue'
|
import { reactive } from 'vue'
|
||||||
import { Back } from '@element-plus/icons-vue'
|
import DetailHeader from '@/components/Layout/DetailHeader/DetailHeader.vue'
|
||||||
import { transferred, copy } from '@/utils/string';
|
import { transferred, copy } from '@/utils/string';
|
||||||
import { Codemirror } from "vue-codemirror";
|
import { Codemirror } from "vue-codemirror";
|
||||||
import { json } from '@codemirror/lang-json';
|
import { json } from '@codemirror/lang-json';
|
||||||
@@ -80,16 +80,7 @@ const copyRes = async () => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col mt-3 ml-4 flex-1 mr-10">
|
<div class="flex flex-col mt-3 ml-4 flex-1 mr-10">
|
||||||
<div class="text-gray-600">
|
<DetailHeader :title="info.title"></DetailHeader>
|
||||||
<a href="/" class="flex items-center">
|
|
||||||
<el-icon color="blue"><Back /></el-icon>
|
|
||||||
<div>返回首页</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-xl mt-5 mb-5">
|
|
||||||
{{ info.title }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="">
|
<div class="">
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { Back } from '@element-plus/icons-vue'
|
||||||
|
const props = defineProps({
|
||||||
|
title: String
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="text-gray-600">
|
||||||
|
<div class="flex">
|
||||||
|
<a href="/" class="flex items-center">
|
||||||
|
<el-icon color="blue"><Back /></el-icon>
|
||||||
|
<div>返回首页</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-xl mt-5 mb-5">
|
||||||
|
{{ props.title }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
const beianNo = ref('xxxxx备案号')
|
const beianNo = ref('粤ICP备19038804号-1')
|
||||||
const copyright = ref('ranblogs.com')
|
const copyright = ref('ranblogs.com')
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, reactive, onMounted } from 'vue'
|
||||||
|
import { Search } from '@element-plus/icons-vue';
|
||||||
|
import { useToolsStore } from '@/store/modules/tools'
|
||||||
|
import { ElMessageBox } from 'element-plus'
|
||||||
|
|
||||||
|
const appName = ref(import.meta.env.VITE_APP_TITLE || '工具坊')
|
||||||
|
const appNet = ref('tools.ranblogs.com')
|
||||||
|
//store
|
||||||
|
const toolsStore = useToolsStore()
|
||||||
|
//查询参数
|
||||||
|
const searchParam = reactive({
|
||||||
|
cateId: 0,
|
||||||
|
title: ''
|
||||||
|
})
|
||||||
|
//获取分类
|
||||||
|
const getToolCates = async () => {
|
||||||
|
try {
|
||||||
|
await toolsStore.getToolCate()
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//search
|
||||||
|
const search = async () => {
|
||||||
|
try {
|
||||||
|
await toolsStore.getTools(searchParam)
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//选择分类
|
||||||
|
const chooseCate = (cateId: number) => {
|
||||||
|
searchParam.cateId = cateId
|
||||||
|
search()
|
||||||
|
}
|
||||||
|
|
||||||
|
//收藏
|
||||||
|
const collect = () => {
|
||||||
|
ElMessageBox({
|
||||||
|
title: '提示',
|
||||||
|
message: '请使用快捷键`Ctrl+D`进行收藏'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getToolCates()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<header class="">
|
||||||
|
<nav class="h-28 w-full leading-10 flex flex-col justify-between pt-2 pb-2">
|
||||||
|
<el-row>
|
||||||
|
<el-col :xl="4" :md="1"></el-col>
|
||||||
|
<el-col :xl="16" :md="22">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<!-- left -->
|
||||||
|
<router-link class="ml-4 flex flex-row" to="/">
|
||||||
|
<img class="h-10 w-auto rounded-lg lg:h-16 mr-2 mt-auto mb-auto" src="@/assets/logo.png" :alt="appNet">
|
||||||
|
<div class="flex flex-col mt-auto mb-auto">
|
||||||
|
<div class="text-xl">{{ appName }}</div>
|
||||||
|
<div class="text-sm text-gray-500">{{ appNet }}</div>
|
||||||
|
</div>
|
||||||
|
</router-link>
|
||||||
|
|
||||||
|
<!-- right -->
|
||||||
|
<div class=" w-full md:w-auto flex hidden md:block">
|
||||||
|
<ul class="flex mt-4 flex-col md:flex-row md:mt-0 justify-end items-center">
|
||||||
|
<li class="hover:text-blue-500">
|
||||||
|
<el-button link size="large" @click="collect">收藏本站</el-button>
|
||||||
|
</li>
|
||||||
|
<li class="ml-3 hover:text-blue-500">
|
||||||
|
<!-- <el-button round>登录/注册</el-button> -->
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-row class="mt-3">
|
||||||
|
<el-col :xl="19" :md="19">
|
||||||
|
<!-- cates -->
|
||||||
|
<div class="mr-3">
|
||||||
|
<ul class="flex bg-gray-100 h-10 rounded leading-10 pl-3">
|
||||||
|
<li v-for="(item, index) in toolsStore.cates" :key="index" class="flex items-center">
|
||||||
|
<el-text>{{ index != 0 ? ' ' : '' }} </el-text>
|
||||||
|
<div
|
||||||
|
class="hover:text-blue-400 hover:underline hover:decoration-2 hover:underline-offset-[6px] text-sm" :class="searchParam.cateId == item.id ? 'text-blue-400 underline decoration-2 underline-offset-[6px]' : ''"
|
||||||
|
@click="chooseCate(item.id)"
|
||||||
|
>{{ item.value }}</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :xl="5" :md="5">
|
||||||
|
<!-- search -->
|
||||||
|
<div>
|
||||||
|
<el-input
|
||||||
|
v-model="searchParam.title"
|
||||||
|
placeholder="搜索工具"
|
||||||
|
class="w-full max-w-xl h-10"
|
||||||
|
@keyup.enter.native="search">
|
||||||
|
<template #append>
|
||||||
|
<el-button :icon="Search" @click="search"/>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-col>
|
||||||
|
<el-col :xl="4" :md="1" class="flex"></el-col>
|
||||||
|
</el-row>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Search } from '@element-plus/icons-vue';
|
|
||||||
import { Tools } from '@element-plus/icons-vue'
|
import { Tools } from '@element-plus/icons-vue'
|
||||||
import { reactive } from 'vue';
|
import { reactive } from 'vue';
|
||||||
const info = reactive({
|
const info = reactive({
|
||||||
searchInput: '',
|
|
||||||
hotTools: [
|
hotTools: [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
@@ -23,7 +21,7 @@ const info = reactive({
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
value: '在线代码运行'
|
value: '在线图片处理'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
@@ -31,10 +29,7 @@ const info = reactive({
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!-- search -->
|
|
||||||
<div>
|
|
||||||
<el-input v-model="info.searchInput" placeholder="搜索工具" class="w-full max-w-xl h-10" :suffix-icon="Search"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- hot tools -->
|
<!-- hot tools -->
|
||||||
<div class="mt-3 border-solid rounded border-gray border p-3">
|
<div class="mt-3 border-solid rounded border-gray border p-3">
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive } from 'vue'
|
import { reactive } from 'vue'
|
||||||
import { Back } from '@element-plus/icons-vue'
|
import DetailHeader from '@/components/Layout/DetailHeader/DetailHeader.vue'
|
||||||
import clipboard3 from 'vue-clipboard3'
|
import clipboard3 from 'vue-clipboard3'
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
import { Md5 } from 'ts-md5'
|
import { Md5 } from 'ts-md5'
|
||||||
@@ -59,16 +59,7 @@ const copyRes = async (resStr: string) => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col mt-3 ml-4 flex-1 mr-10">
|
<div class="flex flex-col mt-3 ml-4 flex-1 mr-10">
|
||||||
<div class="text-gray-600">
|
<DetailHeader :title="info.title"></DetailHeader>
|
||||||
<a href="/" class="flex items-center">
|
|
||||||
<el-icon color="blue"><Back /></el-icon>
|
|
||||||
<div>返回首页</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-xl mt-5 mb-5">
|
|
||||||
{{ info.title }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="">
|
<div class="">
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive } from 'vue'
|
import { reactive } from 'vue'
|
||||||
import { Back } from '@element-plus/icons-vue'
|
import DetailHeader from '@/components/Layout/DetailHeader/DetailHeader.vue'
|
||||||
import { Codemirror } from "vue-codemirror"
|
import { Codemirror } from "vue-codemirror"
|
||||||
|
|
||||||
const info = reactive({
|
const info = reactive({
|
||||||
@@ -116,16 +116,7 @@ const execMatch = () => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col mt-3 ml-4 flex-1 mr-10">
|
<div class="flex flex-col mt-3 ml-4 flex-1 mr-10">
|
||||||
<div class="text-gray-600">
|
<DetailHeader :title="info.title"></DetailHeader>
|
||||||
<a href="/" class="flex items-center">
|
|
||||||
<el-icon color="blue"><Back /></el-icon>
|
|
||||||
<div>返回首页</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-xl mt-5 mb-5">
|
|
||||||
{{ info.title }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive } from 'vue'
|
import { reactive } from 'vue'
|
||||||
import { Back } from '@element-plus/icons-vue'
|
import DetailHeader from '@/components/Layout/DetailHeader/DetailHeader.vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { copy } from '@/utils/string'
|
import { copy } from '@/utils/string'
|
||||||
import { isBinary, isOctal, isDecimal, isHexadecimal } from '@/utils/verify'
|
import { isBinary, isOctal, isDecimal, isHexadecimal } from '@/utils/verify'
|
||||||
@@ -194,16 +194,7 @@ const copyRes = async (index: any) => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col mt-3 ml-4 flex-1 mr-10">
|
<div class="flex flex-col mt-3 ml-4 flex-1 mr-10">
|
||||||
<div class="text-gray-600">
|
<DetailHeader :title="info.title"></DetailHeader>
|
||||||
<a href="/" class="flex items-center">
|
|
||||||
<el-icon color="blue"><Back /></el-icon>
|
|
||||||
<div>返回首页</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-xl mt-5 mb-5">
|
|
||||||
{{ info.title }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="mr-2 w-full">
|
<div class="mr-2 w-full">
|
||||||
|
|||||||
@@ -1,24 +1,29 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive } from "vue"
|
import { ref, reactive } from "vue"
|
||||||
import SignImageCore from './SignImageCore.vue'
|
import SignImageCore from './SignImageCore.vue'
|
||||||
import { Back } from '@element-plus/icons-vue'
|
import DetailHeader from '@/components/Layout/DetailHeader/DetailHeader.vue'
|
||||||
import { UploadProps, UploadInstance, UploadRawFile, genFileId } from 'element-plus'
|
import { UploadProps, UploadInstance, UploadRawFile, genFileId } from 'element-plus'
|
||||||
|
import { autoDown } from '@/utils/file'
|
||||||
|
import { Jh_getTimeStamp } from '@/utils/time'
|
||||||
|
|
||||||
// 图片处理
|
// 图片处理
|
||||||
// const newImg = ref("")
|
|
||||||
const info = reactive({
|
const info = reactive({
|
||||||
title:"在线编辑图片", // 弹框标题
|
title:"在线编辑图片",
|
||||||
previewsImgUrl:"https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg", //图片地址
|
//图片地址
|
||||||
|
previewsImgUrl:"https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg",
|
||||||
//获取处理完的图片
|
//获取处理完的图片
|
||||||
getNewImg:(val: string) => {
|
getNewImg:(url: string) => {
|
||||||
console.log('getNewImg:' + val)
|
//下载
|
||||||
//newImg.value = window.serverUrl.IMG_SERVER + val
|
autoDown(url, Jh_getTimeStamp() + '.png')
|
||||||
},
|
},
|
||||||
cKey: 1, //用于刷新组件视图
|
//用于刷新组件视图
|
||||||
|
cKey: 1,
|
||||||
})
|
})
|
||||||
|
|
||||||
//使用 upload ref
|
//使用 upload ref
|
||||||
const refSignImageCore = ref<UploadInstance>()
|
const upload = ref<UploadInstance>()
|
||||||
|
//使用 SignImageCore ref
|
||||||
|
const refSignImageCore = ref<any>()
|
||||||
|
|
||||||
//上传文件发生变化
|
//上传文件发生变化
|
||||||
const uploadChange: UploadProps['onChange'] = (file) => {
|
const uploadChange: UploadProps['onChange'] = (file) => {
|
||||||
@@ -30,33 +35,29 @@ const uploadChange: UploadProps['onChange'] = (file) => {
|
|||||||
|
|
||||||
//钩子 - 文件上传超出限制
|
//钩子 - 文件上传超出限制
|
||||||
const uploadExceed: UploadProps['onExceed'] = (files) => {
|
const uploadExceed: UploadProps['onExceed'] = (files) => {
|
||||||
refSignImageCore.value!.clearFiles()
|
upload.value!.clearFiles()
|
||||||
const file = files[0] as UploadRawFile
|
const file = files[0] as UploadRawFile
|
||||||
file.uid = genFileId()
|
file.uid = genFileId()
|
||||||
refSignImageCore.value!.handleStart(file)
|
upload.value!.handleStart(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
//保存图片
|
||||||
|
const saveImg = () => {
|
||||||
|
refSignImageCore.value!.save()
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col mt-3 ml-4 flex-1 mr-10">
|
<div class="flex flex-col mt-3 ml-4 flex-1 mr-10">
|
||||||
<div class="text-gray-600">
|
<DetailHeader :title="info.title"></DetailHeader>
|
||||||
<a href="/" class="flex items-center">
|
|
||||||
<el-icon color="blue"><Back /></el-icon>
|
|
||||||
<div>返回首页</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-xl mt-5 mb-5">
|
|
||||||
{{ info.title }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-col mb-3 h-[38rem]">
|
<div class="flex flex-col mb-3 h-[38rem]">
|
||||||
<div class="mb-3 flex flex-row-reverse">
|
<div class="mb-3 flex flex-row-reverse">
|
||||||
<!-- save -->
|
<!-- save -->
|
||||||
<el-button type="primary" class="ml-2">保存</el-button>
|
<el-button type="primary" class="ml-2" @click="saveImg">保存</el-button>
|
||||||
<!-- upload -->
|
<!-- upload -->
|
||||||
<el-upload
|
<el-upload
|
||||||
ref="refSignImageCore"
|
ref="upload"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
@exceed="uploadExceed"
|
@exceed="uploadExceed"
|
||||||
accept="image/*"
|
accept="image/*"
|
||||||
@@ -71,6 +72,7 @@ const uploadExceed: UploadProps['onExceed'] = (files) => {
|
|||||||
</div>
|
</div>
|
||||||
<!-- 图片处理框 -->
|
<!-- 图片处理框 -->
|
||||||
<SignImageCore
|
<SignImageCore
|
||||||
|
ref="refSignImageCore"
|
||||||
:key="info.cKey"
|
:key="info.cKey"
|
||||||
:dialogVisible.sync="true"
|
:dialogVisible.sync="true"
|
||||||
:title="info.title"
|
:title="info.title"
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import { ref, onMounted, nextTick } from 'vue'
|
import { ref, onMounted, nextTick } from 'vue'
|
||||||
import 'tui-image-editor/dist/tui-image-editor.css'
|
import 'tui-image-editor/dist/tui-image-editor.css'
|
||||||
// import 'tui-color-picker/dist/tui-color-picker.css'
|
// import 'tui-color-picker/dist/tui-color-picker.css'
|
||||||
|
import { base64ToBlod } from '@/utils/file'
|
||||||
import ImageEditor from 'tui-image-editor'
|
import ImageEditor from 'tui-image-editor'
|
||||||
|
|
||||||
// 中文菜单
|
// 中文菜单
|
||||||
@@ -195,37 +196,33 @@ const init = ()=> {
|
|||||||
name: 'image'
|
name: 'image'
|
||||||
},
|
},
|
||||||
menu: ['resize', 'crop', 'rotate', 'draw', 'shape', 'icon', 'text', 'filter'], // 底部菜单按钮列表 隐藏镜像flip和遮罩mask
|
menu: ['resize', 'crop', 'rotate', 'draw', 'shape', 'icon', 'text', 'filter'], // 底部菜单按钮列表 隐藏镜像flip和遮罩mask
|
||||||
initMenu: 'draw', // 默认打开的菜单项
|
initMenu: 'none', // 默认打开的菜单项
|
||||||
menuBarPosition: 'bottom', // 菜单所在的位置
|
menuBarPosition: 'left', // 菜单所在的位置
|
||||||
locale: locale_zh, // 本地化语言为中文
|
locale: locale_zh, // 本地化语言为中文
|
||||||
theme: customTheme // 自定义样式
|
theme: customTheme // 自定义样式
|
||||||
},
|
},
|
||||||
cssMaxWidth: 400, // canvas 最大宽度
|
cssMaxWidth: 400, // canvas 最大宽度
|
||||||
cssMaxHeight: 500 // canvas 最大高度
|
cssMaxHeight: 500 // canvas 最大高度
|
||||||
})
|
})
|
||||||
document.getElementsByClassName('tui-image-editor-main')[0].style.top = '45px' // 调整图片显示位置
|
document.getElementsByClassName('tui-image-editor-main')[0].style.top = '0' // 调整图片显示位置
|
||||||
document.getElementsByClassName(
|
document.getElementsByClassName(
|
||||||
'tie-btn-reset tui-image-editor-item help'
|
'tie-btn-reset tui-image-editor-item help'
|
||||||
)[0].style.display = 'none' // 隐藏顶部重置按钮
|
)[0].style.display = 'none' // 隐藏顶部重置按钮
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存图片,并上传
|
// 保存图片,并上传
|
||||||
const save = ()=> {
|
const save = () => {
|
||||||
const base64String = instance.value.toDataURL() // base64 文件
|
// base64 文件
|
||||||
const data = window.atob(base64String.split(',')[1])
|
const base64String = instance.value.toDataURL()
|
||||||
const ia = new Uint8Array(data.length)
|
//转换blod
|
||||||
for (let i = 0; i < data.length; i++) {
|
const url = base64ToBlod(base64String)
|
||||||
ia[i] = data.charCodeAt(i)
|
//传递给父组件
|
||||||
}
|
emit('getNewImg', url);
|
||||||
const blob = new Blob([ia], { type: 'image/png' }) // blob 文件
|
|
||||||
const form = new FormData()
|
|
||||||
form.append("avatarfile", blob);
|
|
||||||
uploadAvatar(form).then(res=>{
|
|
||||||
emit('getNewImg',res.imgUrl);
|
|
||||||
closeDialog()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
save
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, onUnmounted, reactive } from 'vue'
|
import { onMounted, onUnmounted, reactive } from 'vue'
|
||||||
import { VideoPause,VideoPlay,Back,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 clipboard3 from 'vue-clipboard3'
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
|
import DetailHeader from '@/components/Layout/DetailHeader/DetailHeader.vue'
|
||||||
const info = reactive({
|
const info = reactive({
|
||||||
title: "时间戳转换",
|
title: "时间戳转换",
|
||||||
nowTime: Jh_getTimeStamp(),
|
nowTime: Jh_getTimeStamp(),
|
||||||
@@ -99,16 +100,7 @@ const copyStamp = async () => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col mt-3 ml-4 flex-1">
|
<div class="flex flex-col mt-3 ml-4 flex-1">
|
||||||
<div class="text-gray-600">
|
<DetailHeader :title="info.title"></DetailHeader>
|
||||||
<a href="/" class="flex items-center">
|
|
||||||
<el-icon color="blue"><Back /></el-icon>
|
|
||||||
<div>返回首页</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-xl mt-5 mb-5">
|
|
||||||
{{ info.title }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<div class="flex flex-direction">
|
<div class="flex flex-direction">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive } from 'vue'
|
import { reactive } from 'vue'
|
||||||
import { Back } from '@element-plus/icons-vue'
|
import DetailHeader from '@/components/Layout/DetailHeader/DetailHeader.vue'
|
||||||
import { Codemirror } from "vue-codemirror"
|
import { Codemirror } from "vue-codemirror"
|
||||||
import { copy } from '@/utils/string'
|
import { copy } from '@/utils/string'
|
||||||
|
|
||||||
@@ -49,16 +49,7 @@ const copyRes = async () => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col mt-3 ml-4 flex-1 mr-10">
|
<div class="flex flex-col mt-3 ml-4 flex-1 mr-10">
|
||||||
<div class="text-gray-600">
|
<DetailHeader :title="info.title"></DetailHeader>
|
||||||
<a href="/" class="flex items-center">
|
|
||||||
<el-icon color="blue"><Back /></el-icon>
|
|
||||||
<div>返回首页</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-xl mt-5 mb-5">
|
|
||||||
{{ info.title }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive } from 'vue'
|
import { reactive } from 'vue'
|
||||||
import { Back } from '@element-plus/icons-vue'
|
import DetailHeader from '@/components/Layout/DetailHeader/DetailHeader.vue'
|
||||||
|
|
||||||
const info = reactive({
|
const info = reactive({
|
||||||
title: "在线字数统计",
|
title: "在线字数统计",
|
||||||
@@ -36,16 +36,7 @@ const changeContent = () => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col mt-3 ml-4 flex-1 mr-10">
|
<div class="flex flex-col mt-3 ml-4 flex-1 mr-10">
|
||||||
<div class="text-gray-600">
|
<DetailHeader :title="info.title"></DetailHeader>
|
||||||
<a href="/" class="flex items-center">
|
|
||||||
<el-icon color="blue"><Back /></el-icon>
|
|
||||||
<div>返回首页</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-xl mt-5 mb-5">
|
|
||||||
{{ info.title }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -6,13 +6,19 @@ import ElementPlus from 'element-plus';
|
|||||||
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
|
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
|
||||||
//vite-plugin-svg-icons
|
//vite-plugin-svg-icons
|
||||||
import 'virtual:svg-icons-register'
|
import 'virtual:svg-icons-register'
|
||||||
|
//router
|
||||||
import router from './router'
|
import router from './router'
|
||||||
//styles
|
//styles
|
||||||
import './styles/tailwind.css'
|
import './styles/tailwind.css'
|
||||||
//element-plus css
|
//element-plus css
|
||||||
import 'element-plus/dist/index.css'
|
import 'element-plus/dist/index.css'
|
||||||
|
//pinia
|
||||||
|
import pinia from './store'
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
|
console.log(app)
|
||||||
|
//安装仓库
|
||||||
|
app.use(pinia)
|
||||||
app.use(router)
|
app.use(router)
|
||||||
app.use(ElementPlus, {
|
app.use(ElementPlus, {
|
||||||
locale: zhCn
|
locale: zhCn
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { createPinia } from 'pinia'
|
||||||
|
|
||||||
|
//创建大仓库
|
||||||
|
let pinia = createPinia()
|
||||||
|
|
||||||
|
//对外暴露: 入口文件引入
|
||||||
|
export default pinia
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
//创建tools相关的小工具
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import { getTools, getToolCate} from '@/api/tools'
|
||||||
|
import type { ToolsReqData, ToolsInfo, ToolCate } from '@/api/tools/type'
|
||||||
|
|
||||||
|
export const useToolsStore = defineStore('tools', {
|
||||||
|
//用来存放变量
|
||||||
|
state: () => ({
|
||||||
|
list: [] as ToolsInfo[],
|
||||||
|
cates: [] as ToolCate[],
|
||||||
|
}),
|
||||||
|
//方法
|
||||||
|
actions: {
|
||||||
|
//获取tools
|
||||||
|
async getTools(data: ToolsReqData) {
|
||||||
|
//发送请求
|
||||||
|
const result: any = await getTools(data)
|
||||||
|
if (result.code == 200) {
|
||||||
|
this.list = result.data
|
||||||
|
return result.message
|
||||||
|
} else {
|
||||||
|
return Promise.reject(new Error(result.message))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//获取tools cate
|
||||||
|
async getToolCate() {
|
||||||
|
//发送请求
|
||||||
|
const result: any = await getToolCate()
|
||||||
|
if (result.code == 200) {
|
||||||
|
this.cates = result.data
|
||||||
|
return result.message
|
||||||
|
} else {
|
||||||
|
return Promise.reject(new Error(result.message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* base64 to blob
|
||||||
|
* @param base64String
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function base64ToBlod(base64String: string): string {
|
||||||
|
//将Base64编码的文件转换为二进制格式
|
||||||
|
const binaryData = window.atob(base64String.split(',')[1])
|
||||||
|
const ia = new Uint8Array(binaryData.length)
|
||||||
|
for (let i = 0; i < binaryData.length; i++) {
|
||||||
|
//获取unicode值
|
||||||
|
ia[i] = binaryData.charCodeAt(i)
|
||||||
|
}
|
||||||
|
//创建blob对象,以便将二进制数据转换为对象
|
||||||
|
const blob = new Blob([ia], { type: 'image/png' })
|
||||||
|
//转换url
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 直接下载
|
||||||
|
* @param url 下载的文件url
|
||||||
|
* @param filename 文件名
|
||||||
|
*/
|
||||||
|
export function autoDown(url: string, filename: string) {
|
||||||
|
const downloadLink = document.createElement('a');
|
||||||
|
downloadLink.href = url;
|
||||||
|
downloadLink.download = filename; // 指定下载的文件名
|
||||||
|
// 将下载链接添加到 DOM 中并模拟点击下载
|
||||||
|
document.body.appendChild(downloadLink);
|
||||||
|
downloadLink.click();
|
||||||
|
document.body.removeChild(downloadLink);
|
||||||
|
}
|
||||||
|
|
||||||
|
const FileUtils = {
|
||||||
|
base64ToBlod,
|
||||||
|
autoDown
|
||||||
|
}
|
||||||
|
export default FileUtils
|
||||||
+2
-2
@@ -82,7 +82,7 @@ export function scale64ToBase(base64: string) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StringUtils = {
|
const MathUtils = {
|
||||||
baseToScale58,
|
baseToScale58,
|
||||||
scale58ToBase,
|
scale58ToBase,
|
||||||
baseToScale62,
|
baseToScale62,
|
||||||
@@ -90,4 +90,4 @@ const StringUtils = {
|
|||||||
baseToScale64,
|
baseToScale64,
|
||||||
scale64ToBase
|
scale64ToBase
|
||||||
}
|
}
|
||||||
export default StringUtils
|
export default MathUtils
|
||||||
@@ -7,7 +7,6 @@ let request = axios.create({
|
|||||||
})
|
})
|
||||||
//请求拦截器
|
//请求拦截器
|
||||||
request.interceptors.request.use(config => {
|
request.interceptors.request.use(config => {
|
||||||
console.log(config)
|
|
||||||
return config;
|
return config;
|
||||||
});
|
});
|
||||||
//响应拦截器
|
//响应拦截器
|
||||||
|
|||||||
+2
-2
@@ -42,7 +42,7 @@ export function isHexadecimal(data: string): boolean {
|
|||||||
return /^([0-9a-fA-F]+)$/g.test(data) ? true : false;
|
return /^([0-9a-fA-F]+)$/g.test(data) ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StringUtils = {
|
const VerifyUtils = {
|
||||||
isIp,
|
isIp,
|
||||||
isBinary,
|
isBinary,
|
||||||
isOctal,
|
isOctal,
|
||||||
@@ -50,4 +50,4 @@ const StringUtils = {
|
|||||||
isHexadecimal
|
isHexadecimal
|
||||||
}
|
}
|
||||||
|
|
||||||
export default StringUtils
|
export default VerifyUtils
|
||||||
+1
-7
@@ -7,7 +7,6 @@ import path from 'path'
|
|||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig(({command, mode}) => {
|
export default defineConfig(({command, mode}) => {
|
||||||
let env = loadEnv(mode, process.cwd())
|
let env = loadEnv(mode, process.cwd())
|
||||||
console.log('0-0-0-')
|
|
||||||
return {
|
return {
|
||||||
plugins: [
|
plugins: [
|
||||||
vue(),
|
vue(),
|
||||||
@@ -29,13 +28,8 @@ export default defineConfig(({command, mode}) => {
|
|||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
proxy: {
|
proxy: {
|
||||||
// [env.VITE_APP_BASE_API]: {
|
|
||||||
// target: env.VITE_SERVE,
|
|
||||||
// changeOrigin: true,
|
|
||||||
// rewrite: (path) => path.replace(/^\/api/, '')
|
|
||||||
// }
|
|
||||||
'/api': {
|
'/api': {
|
||||||
target: 'https://searchplugin.csdn.net',
|
target: 'https://searchplugin.csdn.net', //ip查询
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
pathRewrite: {
|
pathRewrite: {
|
||||||
'^/api': ''
|
'^/api': ''
|
||||||
|
|||||||
Reference in New Issue
Block a user