Compare commits

...

6 Commits

Author SHA1 Message Date
bd25138da0 123
All checks were successful
continuous-integration/drone/pr Build is passing
2025-07-05 20:48:24 +08:00
a581cd7c51 更新
Some checks failed
continuous-integration/drone/pr Build is failing
2025-07-05 20:13:00 +08:00
8a973db679 文字显示不正常的Bug
All checks were successful
continuous-integration/drone/pr Build is passing
2025-06-29 15:00:17 +08:00
a262c52c73 增加印章
All checks were successful
continuous-integration/drone/pr Build is passing
2025-06-29 03:01:56 +08:00
803139a1c9 改title
All checks were successful
continuous-integration/drone/pr Build is passing
2025-06-28 22:56:11 +08:00
af8b5f6a8d 改成hash 2025-06-28 22:54:13 +08:00
16 changed files with 2351 additions and 260 deletions

89
.drone copy.yml Normal file
View File

@ -0,0 +1,89 @@
kind: pipeline # 定义一个管道
type: docker # 当前管道的类型
name: test # 当前管道的名称
steps:
# 第一步:构建项目
- name: 构建项目
image: node:18-alpine
commands:
- rm -rf node_modules
- npm ci
- npm run build
# 第二步上传静态资源到腾讯云COS (使用另一个插件)
- name: 静态资源上传到cos
image: ccr.ccs.tencentyun.com/xiaoqidun/gocos
settings:
secret_id:
from_secret: cos_secret_id
secret_key:
from_secret: cos_secret_key
bucket_url: https://files-1302416092.cos.ap-shanghai.myqcloud.com
source: dist
target: /utils
strip_prefix: dist
# 第三步:部署到服务器
- name: 清除服务器缓存
image: appleboy/drone-ssh
settings:
host:
from_secret: server_host
username:
from_secret: server_username
password:
from_secret: server_password
# 或者使用SSH密钥
# key:
# from_secret: server_ssh_key
port: 22
script:
- rm -rf /www/wwwroot/utils.zguiy.com/*
- mkdir -p /www/wwwroot/utils.zguiy.com/
- chmod 755 /www/wwwroot/utils.zguiy.com/
when:
branch:
- main
- master
- dev
# 第四步:上传构建文件
- name: 上传构建文件
image: appleboy/drone-scp
settings:
host:
from_secret: server_host
username:
from_secret: server_username
password:
from_secret: server_password
# 或者使用SSH密钥
# key:
# from_secret: server_ssh_key
port: 22
source: dist/*
target: /www/wwwroot/utils.zguiy.com/
strip_components: 1
when:
branch:
- main
- master
- dev
# 定义数据卷用于缓存node_modules
volumes:
- name: node_modules_cache
host:
path: /tmp/drone_cache/node_modules
# 触发条件
trigger:
branch:
- main
- master
- dev
event:
- push
- pull_request

View File

@ -8,11 +8,9 @@ steps:
- name: 构建项目
image: node:18-alpine
commands:
- npm install
- rm -rf node_modules
- npm ci
- npm run build
volumes:
- name: node_modules_cache
path: /drone/src/node_modules
# 第二步上传静态资源到腾讯云COS (使用另一个插件)
- name: 静态资源上传到cos
@ -74,11 +72,6 @@ steps:
- master
- dev
# 定义数据卷用于缓存node_modules
volumes:
- name: node_modules_cache
host:
path: /tmp/drone_cache/node_modules
# 触发条件
trigger:

View File

@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>子归云 工具箱</title>
<title>子归云工具箱</title>
</head>
<body>
<div id="app"></div>

View File

@ -10,7 +10,7 @@
:class="[
'px-3 py-2 text-sm font-medium rounded transition-all',
activeAlgorithm === algorithm.type
? 'bg-primary text-white shadow-sm'
? 'bg-primary-500 text-white shadow-sm'
: 'bg-block text-secondary border hover:bg-hover'
]"
@click="setActiveAlgorithm(algorithm.type)"
@ -27,7 +27,7 @@
<button
:class="[
'flex-1 px-4 py-2 text-sm font-medium rounded transition-all',
!isDecoding ? 'bg-primary text-white' : 'bg-block text-secondary border'
!isDecoding ? 'bg-primary-500 text-white' : 'bg-block text-secondary border'
]"
@click="isDecoding = false"
>
@ -36,7 +36,7 @@
<button
:class="[
'flex-1 px-4 py-2 text-sm font-medium rounded transition-all',
isDecoding ? 'bg-primary text-white' : 'bg-block text-secondary border'
isDecoding ? 'bg-primary-500 text-white' : 'bg-block text-secondary border'
]"
@click="isDecoding = true"
>

View File

@ -5,8 +5,8 @@
<div class="flex items-center bg-card rounded-md p-1 border">
<button
:class="[
'px-4 py-2 text-sm font-medium transition-all rounded-l-md',
mode === 'diff' ? 'bg-primary text-white shadow-sm' : 'text-secondary hover:text-primary'
'px-4 py-2 text-sm font-medium rounded-l transition-all',
mode === 'diff' ? 'bg-primary-500 text-white shadow-sm' : 'text-secondary hover:text-primary'
]"
@click="mode = 'diff'"
>
@ -14,8 +14,8 @@
</button>
<button
:class="[
'px-4 py-2 text-sm font-medium transition-all rounded-r-md',
mode === 'add' ? 'bg-primary text-white shadow-sm' : 'text-secondary hover:text-primary'
'px-4 py-2 text-sm font-medium rounded-r transition-all',
mode === 'add' ? 'bg-primary-500 text-white shadow-sm' : 'text-secondary hover:text-primary'
]"
@click="mode = 'add'"
>

View File

@ -14,7 +14,7 @@
:key="'from-' + base.id"
:class="[
'px-3 py-2 text-sm rounded transition-all',
fromBase === base.id ? 'bg-primary text-white' : 'btn-secondary'
fromBase === base.id ? 'bg-primary-500 text-white' : 'btn-secondary'
]"
@click="setFromBase(base.id)"
>
@ -44,7 +44,7 @@
:key="'to-' + base.id"
:class="[
'px-3 py-2 text-sm rounded transition-all',
toBase === base.id ? 'bg-primary text-white' : 'btn-secondary'
toBase === base.id ? 'bg-primary-500 text-white' : 'btn-secondary'
]"
@click="setToBase(base.id)"
>

View File

@ -176,7 +176,7 @@
<div class="space-y-1">
<div class="flex items-start gap-2">
<span class="text-xs text-tertiary min-w-[40px]">完整:</span>
<code class="text-sm text-primary bg-primary/10 px-1 rounded break-all">
<code class="text-sm text-primary-600 bg-primary-100 px-1 rounded break-all">
{{ match[0] || '' }}
</code>
</div>
@ -187,7 +187,7 @@
class="flex items-start gap-2"
>
<span class="text-xs text-tertiary min-w-[40px]"> {{ group }}:</span>
<code class="text-sm text-primary bg-primary/10 px-1 rounded break-all">
<code class="text-sm text-primary-600 bg-primary-100 px-1 rounded break-all">
{{ match[group] || '(空)' }}
</code>
</div>

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@ import { ref, watch } from 'vue'
type Theme = 'light' | 'dark'
// 全局主题状态
const currentTheme = ref<Theme>('dark')
const currentTheme = ref<Theme>('light')
export const useTheme = () => {
// 切换主题

View File

@ -99,114 +99,252 @@ export default {
unicode_decode: 'Unicode Decode'
},
chrome_bookmark_recovery: {
title: 'Chrome Bookmarks Recovery Tool',
description: 'Recover your lost Chrome bookmarks from local backup files or Google server',
// 标签页
windows: 'Windows',
mac: 'Mac',
linux: 'Linux',
google: 'Google Server',
// 文件上传区域
fileUpload: {
title: 'Choose a file or drag it here',
dragHint: 'Drag Chrome bookmark files here',
chooseFile: 'Choose file',
dropHint: 'Search with the keyword of "Bookmarks" and select all the files found.',
loading: 'Loading...',
ready: 'Download ready',
downloaded: 'Downloaded',
error: 'Error! The file is invalid. Try again!',
bookmarksFound: 'bookmarks found'
},
// 操作系统说明
title: 'Chrome Bookmark Recovery',
description: 'Chrome browser bookmark file recovery tool',
upload_file: 'Upload Bookmark File',
file_analysis: 'File Analysis',
bookmark_list: 'Bookmark List',
export_bookmarks: 'Export Bookmarks',
recovery_success: 'Recovery Successful',
file_format_error: 'File Format Error',
instructions: {
windows: {
title: 'Here is how to recover your lost bookmarks (Windows):',
title: 'Windows System Instructions',
steps: [
'Copy C:\\Users\\%username%\\AppData\\Local\\Google\\Chrome\\User Data into File Explorer.',
'In search bar, type Bookmarks, you will see a list of files named Bookmarks and/or Bookmarks.bak. (Note: If there is more than one user using the same Chrome, bookmarks from other users will be listed too)',
'Select all the files with mouse and drag them to the block below.',
'Download all the HTML files.',
'Open each HTML file with Chrome and determine the HTML file that contains your bookmarks. (Note: The largest file is most likely the correct one)',
'In your Chrome browser, click the Chrome menu icon and go to Bookmarks > Bookmark Manager.',
'Click the menu icon beside search bar and click "Import Bookmarks".',
'Select the HTML file that contains your bookmarks.',
'Your bookmarks should now be imported back to Chrome.'
]
},
mac: {
title: 'Here is how to recover your lost bookmarks (Mac):',
steps: [
'In the Mac menu bar at the top of the screen, click Go.',
'Select Go to Folder.',
'Type ~/Library/Application Support/Google/Chrome and click Go.',
'In search bar, type Bookmarks, you will see a list of files named Bookmarks and/or Bookmarks.bak. (Note: If there is more than one user using the same Chrome, bookmarks from other users will be listed too)',
'Select all the files with mouse and drag them to the block below.',
'Download all the HTML files.',
'Open each HTML file with Chrome and determine the HTML file that contains your bookmarks. (Note: The largest file is most likely the correct one)',
'In your Chrome browser, click the Chrome menu icon and go to Bookmarks > Bookmark Manager.',
'Click the menu icon beside search bar and click "Import Bookmarks".',
'Select the HTML file that contains your bookmarks.',
'Your bookmarks should now be imported back to Chrome.'
]
},
linux: {
title: 'Here is how to recover your lost bookmarks (Linux):',
steps: [
'Open your file explorer (Nautilus, Dolphin ...).',
'Go to ~/.config/google-chrome (Use Ctrl+L on Nautilus).',
'Search for Bookmarks*, you will see a list of files named Bookmarks and/or Bookmarks.bak. (Note: If there is more than one user using the same Chrome, bookmarks from other users will be listed too)',
'Select all the files with mouse and drag them to the block below.',
'Download all the HTML files.',
'Open each HTML file with Chrome and determine the HTML file that contains your bookmarks. (Note: The largest file is most likely the correct one)',
'In your Chrome browser, click the Chrome menu icon and go to Bookmarks > Bookmark Manager.',
'Click the menu icon beside search bar and click "Import Bookmarks".',
'Select the HTML file that contains your bookmarks.',
'Your bookmarks should now be imported back to Chrome.'
]
},
google: {
title: 'If you are sure that Chrome sync data stored in Google server still have your bookmarks, here is how to retrieve them from Google server:',
steps: [
'Go to Google Takeout and sign in to the Google Account used for Chrome Sync.',
'Click the "Select None" button.',
'Check "Chrome" in product list.',
'Expand "All Chrome data types".',
'Click the "Select Chrome data" option.',
'In the popup, check the "Bookmarks" option and uncheck the rest.',
'Scroll down to the bottom of the page and click "Next" button.',
'Click the "Create archive" button.',
'Download and unzip the archive.',
'In the unzipped folder, navigate to "Chrome" folder. The HTML file named "Bookmarks" is the one we need.',
'In your Chrome browser, click the Chrome menu icon and go to Bookmarks > Bookmark Manager.',
'Click the menu icon beside search bar and click "Import Bookmarks".',
'Select the HTML file that contains your bookmarks.',
'Your bookmarks should now be imported back to Chrome.'
'Copy C:\\Users\\%username%\\AppData\\Local\\Google\\Chrome\\User Data into File Explorer',
'In search bar, type Bookmarks, you will see a list of files named Bookmarks and/or Bookmarks.bak',
'Note: If there is more than one user using the same Chrome, bookmarks from other users will be listed too',
'Select all the files with mouse and drag them to the upload area below',
'Download all the converted HTML files',
'Open each HTML file with Chrome and determine the HTML file that contains your bookmarks (Note: The largest file is most likely the correct one)',
'In your Chrome browser, click the Chrome menu icon and go to Bookmarks > Bookmark Manager',
'Click the menu icon beside search bar and click "Import Bookmarks"',
'Select the HTML file that contains your bookmarks',
'Your bookmarks should now be imported back to Chrome'
]
}
},
// 其他恢复方式
otherMethods: {
title: 'Other ways to recover bookmarks',
personalBackup: {
title: 'Personal backup',
content: 'In the case when backups of your computer are available, find the bookmarks files in the backups, upload them to this tool and continue with the steps above.'
},
oldDevices: {
title: 'Recover from old devices',
content: 'Do you have a device (e.g: old laptop) that is signed in to your Google Account and it hasn\'t been synced since the moment your bookmarks were lost? If so, find the files in this device, upload them to this tool and continue with the steps above.'
},
tipsAndTricks: {
title: 'Tips and tricks',
content: 'You can use this tool or Export Bookmarks function in Bookmark Manager to generate HTML file that can be used as archive/backup of your bookmarks. Regularly making backup is useful in case your bookmarks get lost again in the future.'
}
},
disclaimer: 'Disclaimer: this is not an official Google product.'
}
},
ip_lookup: {
title: 'IP Lookup',
description: 'IP address geolocation query and type analysis tool',
ip_address: 'IP Address',
lookup: 'Lookup',
query: 'Query',
get_my_ip: 'Get My IP',
clear: 'Clear',
ip_input: 'IP Input',
placeholder: 'Please enter IP address...',
common_ips: 'Common IPs',
querying: 'Querying...',
ip_info: 'IP Information',
location: 'Location',
isp: 'ISP',
organization: 'Organization',
country: 'Country',
region: 'Region',
city: 'City',
timezone: 'Timezone',
coordinates: 'Coordinates',
ip_type: 'IP Type',
public_ip: 'Public IP',
private_ip: 'Private IP',
current_ip: 'Current IP',
ip_analysis: 'IP Analysis',
format: 'Format',
access_type: 'Access Type',
class: 'IP Class'
},
seal_generator: {
title: 'Seal Generator',
description: 'Electronic seal creation tool, supports company and personal seals',
basic_settings: 'Basic Settings',
text_settings: 'Text Settings',
border_settings: 'Border Settings',
seal_type: 'Seal Type',
company_round: 'Company Round Seal',
company_oval: 'Company Oval Seal',
personal_square: 'Personal Square Seal',
personal_round: 'Personal Round Seal',
seal_size: 'Seal Size',
seal_color: 'Seal Color',
background_color: 'Background Color',
main_text: 'Main Text',
center_text: 'Center Text',
header_text: 'Header Text',
sub_text: 'Sub Text',
font_size: 'Font Size',
main_font_size: 'Main Font Size',
center_font_size: 'Center Font Size',
outer_border_width: 'Outer Border Width',
inner_border_width: 'Inner Border Width',
show_star: 'Show Star',
generate_seal: 'Generate Seal',
download_seal: 'Download Seal',
clear_all: 'Clear All',
seal_preview: 'Seal Preview',
company_name_placeholder: 'Company Name',
personal_name_placeholder: 'Name',
center_text_placeholder: 'Seal',
header_text_placeholder: 'e.g., Head Office, Branch',
sub_text_placeholder: 'e.g., Co., Ltd., Corp.',
preview_tip: 'Please fill in seal information and click generate',
usage_instructions: 'Usage Instructions',
company_seal_features: 'Company Seal Features',
personal_seal_features: 'Personal Seal Features',
important_notice: 'Important Notice',
legal_notice: 'The seals generated by this tool are for learning and testing purposes only. Do not use for illegal purposes. Official company seals need to be registered with relevant authorities.'
},
text_counter: {
title: 'Text Counter',
description: 'Word count, character count, line count and other text analysis tools',
clear: 'Clear',
paste: 'Paste',
sample: 'Sample',
text_input: 'Text Input',
placeholder: 'Please enter or paste text to analyze...',
basic_stats: 'Basic Statistics',
characters: 'Characters',
characters_no_spaces: 'Characters (No Spaces)',
words: 'Words',
lines: 'Lines',
paragraphs: 'Paragraphs',
sentences: 'Sentences',
character_types: 'Character Types',
letters: 'Letters',
numbers: 'Numbers',
spaces: 'Spaces',
punctuation: 'Punctuation',
reading_time: 'Reading Time',
slow_reading: 'Slow Reading',
normal_reading: 'Normal Reading',
fast_reading: 'Fast Reading',
top_words: 'Top Words',
character_count: 'Character Count',
word_count: 'Word Count',
line_count: 'Line Count',
paragraph_count: 'Paragraph Count',
sentence_count: 'Sentence Count',
reading_speed: 'Reading Speed',
fast: 'Fast',
normal: 'Normal',
slow: 'Slow',
most_used_words: 'Most Used Words'
},
image_compressor: {
title: 'Image Compressor',
description: 'Image compression and quality adjustment tool',
compress: 'Compress',
download: 'Download',
reset: 'Reset',
upload_image: 'Upload Image',
click_or_drag: 'Click or drag to upload image',
compression_settings: 'Compression Settings',
quality: 'Quality',
max_width: 'Max Width',
max_height: 'Max Height',
keep_aspect_ratio: 'Keep Aspect Ratio',
output_format: 'Output Format',
original_info: 'Original Info',
size: 'File Size',
dimensions: 'Dimensions',
format: 'Format',
original_preview: 'Original Preview',
compressed_preview: 'Compressed Preview',
compressed_size: 'Compressed Size',
compression_ratio: 'Compression Ratio',
size_reduction: 'Size Reduction',
compressing: 'Compressing...',
width: 'Width',
height: 'Height',
original_size: 'Original Size',
maintain_aspect_ratio: 'Maintain Aspect Ratio',
download_result: 'Download Result'
},
qrcode_generator: {
title: 'QR Code Generator',
description: 'Text to QR code generation tool with customizable styles',
generate: 'Generate',
download: 'Download',
clear: 'Clear',
text_input: 'Text Input',
placeholder: 'Please enter content to generate QR code...',
settings: 'Settings',
size: 'Size',
qr_size: 'QR Code Size',
error_level: 'Error Level',
foreground_color: 'Foreground Color',
background_color: 'Background Color',
preview: 'Preview',
qr_code: 'QR Code',
generating: 'Generating...',
no_preview: 'Please enter content and generate QR code',
download_qr: 'Download QR Code',
qr_preview: 'QR Code Preview'
},
code_formatter: {
title: 'Code Formatter',
description: 'Code beautification, formatting and minification tool',
format: 'Format',
minify: 'Minify',
copy: 'Copy',
clear: 'Clear',
language: 'Language',
indent_size: 'Indent Size',
line_width: 'Line Width',
input: 'Input',
output: 'Output',
output_placeholder: 'Formatted result will be displayed here...',
copy_result: 'Copy Result',
clear_all: 'Clear All',
input_placeholder: 'Please enter code...',
line_count: 'Line Count',
char_count: 'Character Count'
},
base64_to_image: {
title: 'Base64 to Image',
description: 'Base64 and image bidirectional conversion tool',
base64_to_image: 'Base64 to Image',
download_image: 'Download Image',
clear: 'Clear',
base64_input: 'Base64 Input',
base64_placeholder: 'Please enter Base64 encoding...',
image_to_base64: 'Image to Base64',
click_or_drag: 'Click or drag to upload image',
image_preview: 'Image Preview',
preview_image: 'Preview Image',
converting: 'Converting...',
no_preview: 'Please enter Base64 or upload image',
base64_output: 'Base64 Output',
upload_image: 'Upload Image',
image_info: 'Image Info',
copy_base64: 'Copy Base64'
},
yml_properties_converter: {
title: 'YML/Properties Converter',
description: 'YML and Properties configuration file format converter',
yml_to_properties: 'YML to Properties',
properties_to_yml: 'Properties to YML',
yml_to_json: 'YML to JSON',
json_to_yml: 'JSON to YML',
clear: 'Clear',
input: 'Input',
output: 'Output',
paste: 'Paste',
copy: 'Copy',
input_format: 'Input Format',
output_format: 'Output Format',
input_placeholder_yml: 'Enter YAML content...',
input_placeholder_properties: 'Enter Properties content...',
input_placeholder_json: 'Enter JSON content...',
output_placeholder: 'Conversion result will be displayed here...',
use_example: 'Use This Example',
format_description: 'Format Description',
yml_example: 'YAML Example',
properties_example: 'Properties Example',
json_example: 'JSON Example',
convert: 'Convert',
conversion_result: 'Conversion Result'
}
}
}

View File

@ -264,14 +264,19 @@ export default {
code_formatter: {
title: '代码格式化',
description: '代码美化、格式化、压缩工具',
language: '语言',
format: '格式化',
minify: '压缩',
copy: '复制',
clear: '清除',
language: '语言',
indent_size: '缩进大小',
line_width: '行宽',
input: '输入',
output: '输出',
output_placeholder: '格式化结果将显示在这里...',
copy_result: '复制结果',
clear_all: '清除全部',
input_placeholder: '请输入代码...',
output_placeholder: '格式化结果将显示在这里...',
indent_size: '缩进大小',
line_count: '行数',
char_count: '字符数'
},
@ -342,16 +347,30 @@ export default {
description: 'IP地址归属地查询、类型分析工具',
ip_address: 'IP地址',
lookup: '查询',
query: '查询',
get_my_ip: '获取我的IP',
clear: '清除',
ip_input: 'IP输入',
placeholder: '请输入IP地址...',
common_ips: '常用IP',
querying: '查询中...',
ip_info: 'IP信息',
location: '位置信息',
isp: '运营商',
organization: '组织',
country: '国家',
region: '省份',
city: '城市',
timezone: '时区',
coordinates: '坐标',
ip_type: 'IP类型',
public_ip: '公网IP',
private_ip: '私网IP',
current_ip: '当前IP'
current_ip: '当前IP',
ip_analysis: 'IP分析',
format: '格式',
access_type: '访问类型',
class: 'IP类别'
},
date_calculator: {
title: '日期计算',
@ -383,13 +402,33 @@ export default {
text_counter: {
title: '文本统计',
description: '字数、词数、行数等统计分析工具',
clear: '清除',
paste: '粘贴',
sample: '示例',
text_input: '文本输入',
placeholder: '请输入或粘贴需要统计的文本...',
basic_stats: '基础统计',
characters: '字符数',
characters_no_spaces: '字符数(不含空格)',
words: '词数',
lines: '行数',
paragraphs: '段落数',
sentences: '句子数',
character_types: '字符类型',
letters: '字母',
numbers: '数字',
spaces: '空格',
punctuation: '标点符号',
reading_time: '阅读时间',
slow_reading: '慢速阅读',
normal_reading: '正常阅读',
fast_reading: '快速阅读',
top_words: '最常用词汇',
character_count: '字符数',
word_count: '词数',
line_count: '行数',
paragraph_count: '段落数',
sentence_count: '句子数',
reading_time: '阅读时间',
reading_speed: '阅读速度',
fast: '快速',
normal: '正常',
@ -431,27 +470,51 @@ export default {
image_compressor: {
title: '图片压缩',
description: '图片压缩优化、质量调整工具',
upload_image: '上传图片',
compress: '压缩',
download: '下载',
reset: '重置',
upload_image: '上传图片',
click_or_drag: '点击或拖拽上传图片',
compression_settings: '压缩设置',
quality: '质量',
width: '宽度',
height: '高度',
max_width: '最大宽度',
max_height: '最大高度',
keep_aspect_ratio: '保持宽高比',
output_format: '输出格式',
original_info: '原图信息',
size: '文件大小',
dimensions: '尺寸',
format: '格式',
original_size: '原始大小',
original_preview: '原图预览',
compressed_preview: '压缩预览',
compressed_size: '压缩后大小',
compression_ratio: '压缩比',
size_reduction: '减少大小',
compressing: '压缩中...',
width: '宽度',
height: '高度',
original_size: '原始大小',
maintain_aspect_ratio: '保持宽高比',
download_result: '下载结果'
},
qrcode_generator: {
title: '二维码生成',
description: '文本转二维码、自定义样式工具',
text_input: '文本输入',
generate: '生成',
download: '下载',
clear: '清除',
text_input: '文本输入',
placeholder: '请输入要生成二维码的内容...',
settings: '设置选项',
size: '尺寸',
qr_size: '二维码大小',
error_level: '容错级别',
foreground_color: '前景色',
background_color: '背景色',
preview: '预览',
qr_code: '二维码',
generating: '生成中...',
no_preview: '请输入内容并生成二维码',
download_qr: '下载二维码',
qr_preview: '二维码预览'
},
@ -488,6 +551,24 @@ export default {
description: 'YML与Properties配置文件格式互转',
yml_to_properties: 'YML转Properties',
properties_to_yml: 'Properties转YML',
yml_to_json: 'YML转JSON',
json_to_yml: 'JSON转YML',
clear: '清空',
input: '输入',
output: '输出',
paste: '粘贴',
copy: '复制',
input_format: '输入格式',
output_format: '输出格式',
input_placeholder_yml: '请输入YAML内容...',
input_placeholder_properties: '请输入Properties内容...',
input_placeholder_json: '请输入JSON内容...',
output_placeholder: '转换结果将显示在这里...',
use_example: '使用此示例',
format_description: '格式说明',
yml_example: 'YAML 示例',
properties_example: 'Properties 示例',
json_example: 'JSON 示例',
convert: '转换',
yml_input: 'YML输入',
properties_input: 'Properties输入',
@ -496,13 +577,20 @@ export default {
base64_to_image: {
title: 'Base64转图片',
description: 'Base64与图片双向转换工具',
image_to_base64: '图片转Base64',
base64_to_image: 'Base64转图片',
upload_image: '上传图片',
base64_input: 'Base64输入',
image_preview: '图片预览',
image_info: '图片信息',
download_image: '下载图片',
clear: '清除',
base64_input: 'Base64输入',
base64_placeholder: '请输入Base64编码...',
image_to_base64: '图片转Base64',
click_or_drag: '点击或拖拽上传图片',
image_preview: '图片预览',
preview_image: '预览图片',
converting: '转换中...',
no_preview: '请输入Base64或上传图片',
base64_output: 'Base64输出',
upload_image: '上传图片',
image_info: '图片信息',
copy_base64: '复制Base64'
},
image_watermark: {
@ -550,114 +638,71 @@ export default {
validate: '验证'
},
chrome_bookmark_recovery: {
title: 'Chrome书签恢复工具',
description: '恢复丢失的Chrome书签支持从本地备份文件或Google服务器导入',
// 标签页
windows: 'Windows',
mac: 'Mac',
linux: 'Linux',
google: 'Google服务器',
// 文件上传区域
fileUpload: {
title: '选择文件或拖拽到此处',
dragHint: '拖拽Chrome书签文件到此处',
chooseFile: '选择文件',
dropHint: '使用关键词"Bookmarks"搜索并选择找到的所有文件',
loading: '加载中...',
ready: '准备下载',
downloaded: '已下载',
error: '错误!文件无效,请重试!',
bookmarksFound: '个书签'
},
// 操作系统说明
title: 'Chrome书签恢复',
description: 'Chrome浏览器书签文件恢复工具',
upload_file: '上传书签文件',
file_analysis: '文件分析',
bookmark_list: '书签列表',
export_bookmarks: '导出书签',
recovery_success: '恢复成功',
file_format_error: '文件格式错误',
instructions: {
windows: {
title: '以下是恢复丢失书签的方法 (Windows):',
title: 'Windows 系统操作说明',
steps: [
'复制 C:\\Users\\%username%\\AppData\\Local\\Google\\Chrome\\User Data 到文件资源管理器',
'在搜索栏中输入 Bookmarks看到名为 Bookmarks 和/或 Bookmarks.bak 的文件列表注意如果有多个用户使用同一个Chrome其他用户的书签也会被列出',
'用鼠标选择所有文件并拖拽到下面的区域',
'下载所有HTML文件',
'用Chrome打开每个HTML文件确定包含你的书签的HTML文件注意最大的文件很可能是正确的',
'在Chrome浏览器中点击Chrome菜单图标进入 书签 > 书签管理器',
'点击搜索栏旁边的菜单图标,点击"导入书签"',
'选择包含你的书签的HTML文件',
'你的书签现在应该已导入回Chrome'
]
},
mac: {
title: '以下是恢复丢失书签的方法 (Mac):',
steps: [
'在屏幕顶部的Mac菜单栏中点击前往',
'选择前往文件夹',
'输入 ~/Library/Application Support/Google/Chrome 并点击前往',
'在搜索栏中输入 Bookmarks你会看到名为 Bookmarks 和/或 Bookmarks.bak 的文件列表注意如果有多个用户使用同一个Chrome其他用户的书签也会被列出',
'用鼠标选择所有文件并拖拽到下面的区域',
'下载所有HTML文件',
'用Chrome打开每个HTML文件确定包含你的书签的HTML文件注意最大的文件很可能是正确的',
'在Chrome浏览器中点击Chrome菜单图标进入 书签 > 书签管理器',
'点击搜索栏旁边的菜单图标,点击"导入书签"',
'选择包含你的书签的HTML文件',
'你的书签现在应该已导入回Chrome'
]
},
linux: {
title: '以下是恢复丢失书签的方法 (Linux):',
steps: [
'打开你的文件管理器Nautilus, Dolphin ...',
'进入 ~/.config/google-chrome在Nautilus中使用Ctrl+L',
'搜索 Bookmarks*,你会看到名为 Bookmarks 和/或 Bookmarks.bak 的文件列表注意如果有多个用户使用同一个Chrome其他用户的书签也会被列出',
'用鼠标选择所有文件并拖拽到下面的区域',
'下载所有HTML文件',
'用Chrome打开每个HTML文件确定包含你的书签的HTML文件注意最大的文件很可能是正确的',
'在Chrome浏览器中点击Chrome菜单图标进入 书签 > 书签管理器',
'点击搜索栏旁边的菜单图标,点击"导入书签"',
'选择包含你的书签的HTML文件',
'你的书签现在应该已导入回Chrome'
]
},
google: {
title: '如果你确信存储在Google服务器中的Chrome同步数据仍有你的书签以下是从Google服务器检索它们的方法:',
steps: [
'前往 Google Takeout 并登录用于Chrome同步的Google账户',
'点击"全不选"按钮',
'在产品列表中勾选"Chrome"',
'展开"所有Chrome数据类型"',
'点击"选择Chrome数据"选项',
'在弹窗中,勾选"书签"选项并取消选择其余选项',
'滚动到页面底部并点击"下一步"按钮',
'点击"创建归档"按钮',
'下载并解压归档文件',
'在解压的文件夹中,导航到"Chrome"文件夹。名为"Bookmarks"的HTML文件就是我们需要的',
'在Chrome浏览器中点击Chrome菜单图标进入 书签 > 书签管理器',
'点击搜索栏旁边的菜单图标,点击"导入书签"',
'选择包含你的书签的HTML文件',
'你的书签现在应该已导入回Chrome'
'复制路径 C:\\Users\\%username%\\AppData\\Local\\Google\\Chrome\\User Data 到文件资源管理器',
'在搜索栏中输入 Bookmarks看到名为 Bookmarks 和/或 Bookmarks.bak 的文件列表',
'如果同一台电脑上有多个用户使用 Chrome其他用户的书签文件也会被列出',
'选择所有文件并将它们拖拽到下方的上传区域',
'下载所有转换后的 HTML 文件',
'用 Chrome 打开每个 HTML 文件,确定哪个文件包含你的书签(通常最大的文件是正确的)',
'在 Chrome 浏览器中,点击菜单图标,进入 书签 > 书签管理器',
'点击搜索栏旁边的菜单图标,选择"导入书签"',
'选择包含你书签的 HTML 文件',
'你的书签现在应该已经导入到 Chrome 中了'
]
}
},
// 其他恢复方式
otherMethods: {
title: '其他恢复书签的方法',
personalBackup: {
title: '个人备份',
content: '在计算机备份可用的情况下,在备份中找到书签文件,将它们上传到此工具并继续上述步骤。'
},
oldDevices: {
title: '从旧设备恢复',
content: '你是否有一台设备例如旧笔记本电脑已登录到你的Google账户并且自你的书签丢失以来没有同步过如果是这样在该设备中找到文件将它们上传到此工具并继续上述步骤。'
},
tipsAndTricks: {
title: '提示和技巧',
content: '你可以使用此工具或书签管理器中的"导出书签"功能来生成可用作书签存档/备份的HTML文件。定期制作备份对于防止将来再次丢失书签很有用。'
}
},
disclaimer: '免责声明这不是Google的官方产品。'
}
},
seal_generator: {
title: '印章生成器',
description: '电子印章制作工具,支持公司印章和个人印章',
basic_settings: '基础参数',
text_settings: '文字设置',
border_settings: '边框设置',
seal_type: '印章样式',
company_round: '公司圆章',
company_oval: '公司椭圆章',
personal_square: '个人方章',
personal_round: '个人圆章',
seal_size: '印章大小',
seal_color: '印章颜色',
background_color: '背景颜色',
main_text: '主文字',
center_text: '中心文字',
header_text: '抬头文字',
sub_text: '副文字',
font_size: '字体大小',
main_font_size: '主文字大小',
center_font_size: '中心文字大小',
outer_border_width: '外边线宽度',
inner_border_width: '内边线宽度',
show_star: '显示五角星',
generate_seal: '生成印章',
download_seal: '下载印章',
clear_all: '清空',
seal_preview: '印章预览',
company_name_placeholder: '公司名称',
personal_name_placeholder: '姓名',
center_text_placeholder: '印',
header_text_placeholder: '例:总公司、分公司',
sub_text_placeholder: '例:有限公司、股份有限公司',
preview_tip: '请填写印章信息并点击生成',
usage_instructions: '使用说明',
company_seal_features: '公司印章功能',
personal_seal_features: '个人印章功能',
important_notice: '重要提示',
legal_notice: '本工具生成的印章仅供学习和测试使用,请勿用于非法用途。正式的公司印章需要到相关部门进行备案注册。'
}
}
}

View File

@ -2,18 +2,18 @@ import {
faCode, faExchangeAlt, faClock, faGlobe, faLink, faLock,
faImage, faCogs, faFileCode, faKey, faFont,
faCalendarAlt, faPalette, faEdit, faRuler, faNetworkWired,
faEraser, faCalculator, faFileAlt, faBookmark
faEraser, faCalculator, faFileAlt, faBookmark, faStamp
} from '@fortawesome/free-solid-svg-icons'
import type { Tool } from '@/types/tools'
// 定义工具列表
const tools: Tool[] = [
{
code: 'json_formatter',
icon: faCode,
category: ['common', 'json'],
keywords: ['json', 'json格式化', '格式化', '美化', '压缩', '校验', 'formatter', 'validator', 'gshjson', 'gshjson', 'jsonxg', 'jxg']
},
// {
// code: 'json_formatter',
// icon: faCode,
// category: ['common', 'json'],
// keywords: ['json', 'json格式化', '格式化', '美化', '压缩', '校验', 'formatter', 'validator', 'gshjson', 'gshjson', 'jsonxg', 'jxg']
// },
{
code: 'http_tester',
icon: faGlobe,
@ -170,17 +170,17 @@ const tools: Tool[] = [
category: ['image'],
keywords: ['图标', 'ico', '图片转ico', 'icon', '图标生成', '图标转换', 'favicon', '网站图标', 'tubiao', 'tb', 'zhuanicon', 'icon转换', 'icon生成']
},
{
code: 'cron_generator',
icon: faCalendarAlt,
category: ['datetime'],
keywords: ['cron', 'cron表达式', '定时任务', '调度', '表达式生成', '执行时间', 'crontab', 'quartz', 'schedule', 'dingshi', 'dingshibiaodashi', 'dsrw', 'bds', 'cronbds']
},
{
code: 'chrome_bookmark_recovery',
icon: faBookmark,
category: ['common', 'file'],
keywords: ['chrome书签', '书签恢复', '书签导入', '书签', 'chrome', 'bookmark', '书签备份', '书签导出', 'shuqian', 'sq', 'huifu', 'hf', 'chrome书签恢复', 'chromehuifu']
},
{
code: 'seal_generator',
icon: faStamp,
category: ['common', 'image'],
keywords: ['印章', '印章生成', '电子印章', '公司印章', '个人印章', '印章制作', 'seal', 'stamp', 'yinzhang', 'yz', 'yinzhangshengcheng', 'yzsc', 'gongsiyz', 'gerenyinzhang', 'seal generator']
}
]

View File

@ -19,7 +19,8 @@ import {
faExternalLinkAlt, faCopy, faCheck, faCompress, faExpand,
faTrash, faSync, faFolderOpen, faFolder, faSpinner,
faSave, faHistory, faEdit as faEditIcon, faTrashAlt,
faSun, faMoon, faHome, faArrowLeft, faArrowUp, faClipboard
faSun, faMoon, faHome, faArrowLeft, faArrowUp, faClipboard,
faStamp, faDownload, faEye, faInfoCircle, faExclamationTriangle
} from '@fortawesome/free-solid-svg-icons'
import { faStar as farStar } from '@fortawesome/free-regular-svg-icons'
@ -39,6 +40,7 @@ library.add(
faTrash, faSync, faFolderOpen, faFolder, faSpinner,
faSave, faHistory, faEditIcon, faTrashAlt,
faSun, faMoon, faHome, faArrowLeft, faArrowUp, faClipboard,
faStamp, faDownload, faEye, faInfoCircle, faExclamationTriangle,
farStar, faGithub
)

View File

@ -1,8 +1,8 @@
import { createRouter, createWebHistory } from 'vue-router'
import { createRouter, createWebHashHistory } from 'vue-router'
import HomeView from '@/views/HomeView.vue'
const router = createRouter({
history: createWebHistory('/'),
history: createWebHashHistory(),
routes: [
{
path: '/',

View File

@ -150,7 +150,8 @@ const toolComponentMap: Record<string, () => Promise<any>> = {
image_to_ico: () => import('@/components/tools/ImageToIco.vue'),
cron_generator: () => import('@/components/tools/CronGenerator.vue'),
http_tester: () => import('@/components/tools/HttpTester.vue'),
chrome_bookmark_recovery: () => import('@/components/tools/ChromeBookmarkRecovery.vue')
chrome_bookmark_recovery: () => import('@/components/tools/ChromeBookmarkRecovery.vue'),
seal_generator: () => import('@/components/tools/SealGenerator.vue')
}
// 加载工具组件

290
test-seal.html Normal file
View File

@ -0,0 +1,290 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>印章生成器测试</title>
<style>
body {
font-family: Arial, sans-serif;
padding: 20px;
background: #f5f5f5;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.controls {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 15px;
margin-bottom: 20px;
}
.form-group {
display: flex;
flex-direction: column;
}
label {
margin-bottom: 5px;
font-weight: bold;
}
input, select, button {
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
}
button {
background: #6366f1;
color: white;
cursor: pointer;
border: none;
}
button:hover {
background: #5855eb;
}
.preview {
text-align: center;
padding: 20px;
background: #f9f9f9;
border-radius: 8px;
}
canvas {
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
</style>
</head>
<body>
<div class="container">
<h1>🖃 印章生成器测试</h1>
<div class="controls">
<div class="form-group">
<label for="sealType">印章类型</label>
<select id="sealType">
<option value="company_round">公司圆章</option>
<option value="company_oval">公司椭圆章</option>
<option value="personal_square">个人方章</option>
<option value="personal_round">个人圆章</option>
</select>
</div>
<div class="form-group">
<label for="mainText">主文字</label>
<input type="text" id="mainText" placeholder="输入公司名称或姓名" value="子归云科技">
</div>
<div class="form-group">
<label for="centerText">中心文字</label>
<input type="text" id="centerText" placeholder="印" value="印" maxlength="2">
</div>
<div class="form-group">
<label for="sealSize">印章大小</label>
<input type="range" id="sealSize" min="200" max="600" value="300">
<span id="sizeValue">300px</span>
</div>
<div class="form-group">
<label for="sealColor">印章颜色</label>
<input type="color" id="sealColor" value="#FF0000">
</div>
<div class="form-group">
<button onclick="generateSeal()">🎨 生成印章</button>
</div>
</div>
<div class="preview">
<h3>印章预览</h3>
<canvas id="sealCanvas" width="300" height="300"></canvas>
<br><br>
<button onclick="downloadSeal()" style="display:none;" id="downloadBtn">📥 下载印章</button>
</div>
</div>
<script>
const canvas = document.getElementById('sealCanvas');
const ctx = canvas.getContext('2d');
const sizeSlider = document.getElementById('sealSize');
const sizeValue = document.getElementById('sizeValue');
// 更新大小显示
sizeSlider.addEventListener('input', function() {
sizeValue.textContent = this.value + 'px';
canvas.width = this.value;
canvas.height = this.value;
});
function generateSeal() {
const sealType = document.getElementById('sealType').value;
const mainText = document.getElementById('mainText').value;
const centerText = document.getElementById('centerText').value;
const sealSize = parseInt(document.getElementById('sealSize').value);
const sealColor = document.getElementById('sealColor').value;
if (!mainText.trim()) {
alert('请输入主文字!');
return;
}
// 清空画布
ctx.clearRect(0, 0, sealSize, sealSize);
// 设置背景
ctx.fillStyle = '#FFFFFF';
ctx.fillRect(0, 0, sealSize, sealSize);
// 设置印章颜色
ctx.strokeStyle = sealColor;
ctx.fillStyle = sealColor;
const centerX = sealSize / 2;
const centerY = sealSize / 2;
if (sealType.startsWith('company')) {
drawCompanySeal(centerX, centerY, sealSize, mainText, centerText, sealColor);
} else {
drawPersonalSeal(centerX, centerY, sealSize, mainText, sealColor);
}
document.getElementById('downloadBtn').style.display = 'inline-block';
}
function drawCompanySeal(centerX, centerY, sealSize, mainText, centerText, sealColor) {
const radius = sealSize * 0.4;
// 绘制外边框
ctx.lineWidth = 3;
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI);
ctx.stroke();
// 绘制内边框
ctx.lineWidth = 1;
ctx.beginPath();
ctx.arc(centerX, centerY, radius - 15, 0, 2 * Math.PI);
ctx.stroke();
// 绘制弧形主文字
drawCurvedText(mainText, centerX, centerY, radius - 25, 24);
// 绘制五角星
drawStar(centerX, centerY - radius * 0.1, 15);
// 绘制中心文字
if (centerText.trim()) {
ctx.font = 'bold 40px SimSun, serif';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(centerText, centerX, centerY + radius * 0.2);
}
}
function drawPersonalSeal(centerX, centerY, sealSize, mainText, sealColor) {
const size = sealSize * 0.8;
const sealType = document.getElementById('sealType').value;
// 绘制边框
ctx.lineWidth = 3;
ctx.beginPath();
if (sealType === 'personal_round') {
ctx.arc(centerX, centerY, size / 2, 0, 2 * Math.PI);
} else {
const halfSize = size / 2;
ctx.rect(centerX - halfSize, centerY - halfSize, size, size);
}
ctx.stroke();
// 绘制文字
const text = mainText.trim();
const textLength = text.length;
const fontSize = 32;
ctx.font = `bold ${fontSize}px SimSun, serif`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
if (textLength === 2) {
// 两字:上下排列
ctx.fillText(text[0], centerX, centerY - fontSize * 0.6);
ctx.fillText(text[1], centerX, centerY + fontSize * 0.6);
} else if (textLength === 3) {
// 三字:品字形
ctx.fillText(text[0], centerX, centerY - fontSize * 0.8);
ctx.fillText(text[1], centerX - fontSize * 0.7, centerY + fontSize * 0.4);
ctx.fillText(text[2], centerX + fontSize * 0.7, centerY + fontSize * 0.4);
} else if (textLength === 4) {
// 四字:田字格
ctx.fillText(text[0], centerX - fontSize * 0.6, centerY - fontSize * 0.6);
ctx.fillText(text[1], centerX + fontSize * 0.6, centerY - fontSize * 0.6);
ctx.fillText(text[2], centerX - fontSize * 0.6, centerY + fontSize * 0.6);
ctx.fillText(text[3], centerX + fontSize * 0.6, centerY + fontSize * 0.6);
} else {
// 其他情况:单行
ctx.fillText(text, centerX, centerY);
}
}
function drawCurvedText(text, centerX, centerY, radius, fontSize) {
ctx.font = `${fontSize}px SimSun, serif`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
const angleStep = (Math.PI * 1.4) / text.length;
const startOffset = -Math.PI * 0.7;
for (let i = 0; i < text.length; i++) {
const angle = startOffset + i * angleStep;
const x = centerX + Math.cos(angle) * radius;
const y = centerY + Math.sin(angle) * radius;
ctx.save();
ctx.translate(x, y);
ctx.rotate(angle + Math.PI / 2);
ctx.fillText(text[i], 0, 0);
ctx.restore();
}
}
function drawStar(centerX, centerY, radius) {
const spikes = 5;
const outerRadius = radius;
const innerRadius = radius * 0.4;
ctx.beginPath();
for (let i = 0; i < spikes * 2; i++) {
const angle = (i * Math.PI) / spikes - Math.PI / 2;
const r = i % 2 === 0 ? outerRadius : innerRadius;
const x = centerX + Math.cos(angle) * r;
const y = centerY + Math.sin(angle) * r;
if (i === 0) {
ctx.moveTo(x, y);
} else {
ctx.lineTo(x, y);
}
}
ctx.closePath();
ctx.fill();
}
function downloadSeal() {
const link = document.createElement('a');
link.download = `seal-${Date.now()}.png`;
link.href = canvas.toDataURL('image/png');
link.click();
}
// 初始生成一个示例印章
setTimeout(() => {
generateSeal();
}, 100);
</script>
</body>
</html>