提交 434f7dc5 编写于 作者: B baiy 提交者: ninecents

补码反码原码 #94

crontab 修改时间格式 #99
ARM to HEX #83
垂直高度自动 #95
上级 729b165d
此差异已折叠。
{
"name": "c-tool",
"version": "1.8.3",
"version": "1.9.2",
"private": true,
"scripts": {
"serve": "vue-cli-service serve --port 8081",
"build": "vue-cli-service build",
"report": "vue-cli-service build --report",
"lint": "vue-cli-service lint"
},
"dependencies": {
"@babel/parser": "^7.15.8",
"@prettier/plugin-php": "^0.17.5",
"@prettier/plugin-xml": "^1.1.0",
"@typescript-eslint/typescript-estree": "^5.2.0",
"@babel/parser": "^7.16.4",
"@prettier/plugin-php": "^0.17.6",
"@typescript-eslint/typescript-estree": "^5.4.0",
"angular-html-parser": "^1.8.0",
"axios": "^0.21.4",
"babel-runtime": "^6.26.0",
"bignumber.js": "^9.0.1",
"code-formatter": "0.0.1",
"codemirror": "^5.63.3",
"codemirror-graphql": "^1.1.0",
"cron-parser": "^2.16.3",
"cronstrue": "^1.122.0",
"crypto-js": "^3.3.0",
"diff-match-patch": "^1.0.5",
"file": "^0.2.2",
"http-build-query": "^0.7.0",
"graphql": "15.5.0",
"ipinyinjs": "^1.0.0",
"is-url": "^1.2.4",
"jian_fan": "^1.0.3",
"jimp": "^0.16.1",
"js-base64": "^2.6.4",
"js-htmlencode": "^0.3.0",
"js-yaml": "^3.14.1",
"jsbarcode": "^3.11.5",
"json-to-properties": "^1.1.3",
"json5": "^2.2.0",
"jsonlint": "^1.6.3",
"jsrsasign": "^10.4.1",
"jsrsasign-util": "^1.0.5",
"jwt-decode": "^3.1.2",
"lodash": "^4.17.21",
"mime-types": "^2.1.33",
"mime-types": "^2.1.34",
"moment": "^2.29.1",
"monaco-editor": "^0.29.1",
"monaco-editor-webpack-plugin": "^5.0.0",
"php-array-reader": "^1.3.0",
"php-array-reader": "^1.3.2",
"phparr": "^0.2.0",
"postcss": "^8.3.11",
"postcss-less": "^5.0.0",
"postcss-scss": "^4.0.1",
"postcss-scss": "^4.0.2",
"prettier": "^2.4.1",
"prettier-plugin-java": "^1.5.0",
"prettier-plugin-sql": "^0.3.0",
"properties-to-json": "^0.1.7",
"qrcode": "^1.4.4",
"qrcode-parser": "^1.2.0",
"query-string": "^6.13.7",
"query-string": "^6.14.1",
"serialize-php": "^1.1.2",
"sm-crypto": "^0.1.4",
"system": "^2.0.1",
"typescript": "^4.5.2",
"uglify-js": "3.14.3",
"uuid": "^8.3.2",
"view-design": "^4.6.1",
"view-design": "^4.7.0",
"vue": "^2.6.14",
"vue-color": "^2.8.1",
"vue-i18n": "^8.26.7",
"vue-router": "^3.5.3",
"x2js": "github:abdolence/x2js"
"vuedraggable": "^2.24.3",
"x2js": "github:abdolence/x2js",
"xml-formatter": "^2.5.1"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.12.1",
......@@ -94,6 +100,9 @@
},
"parserOptions": {
"parser": "babel-eslint"
},
"globals": {
"__": "writable"
}
},
"postcss": {
......
......@@ -14,54 +14,54 @@ const DEFAULT_COMMON_TOOL = [
]
const category = [
{'name': 'common', 'title': '常用'},
{'name': 'encryption', 'title': '加解密'},
{'name': 'conversion', 'title': '转换'},
{'name': 'serialize', 'title': '序列化'},
{'name': 'check', 'title': '校验'},
{'name': 'generate', 'title': '生成'},
{'name': 'other', 'title': '其他'},
{'name': 'common'},
{'name': 'encryption'},
{'name': 'conversion'},
{'name': 'encoder_decoder'},
{'name': 'check'},
{'name': 'generate'},
{'name': 'other'},
]
const tool = [
{
'name': 'hash',
'title': '哈希(hash)',
'cat': ['encryption']
},
{
'name': 'encrypt',
'title': '加密/解密',
'cat': ['encryption']
},
{'name': 'sign', 'title': '签名/验签', 'cat': ['encryption']},
{'name': 'base64', 'title': 'BASE64编码', 'cat': ['encryption']},
{'name': 'json', 'title': 'JSON工具', 'cat': ['conversion', 'serialize']},
{'name': 'url', 'title': 'URL编码', 'cat': ['conversion']},
{'name': 'timestamp', 'title': '时间戳', 'cat': ['conversion']},
{'name': 'qrCode', 'title': '二维码', 'cat': ['generate']},
{'name': 'barcode', 'title': '条形码', 'cat': ['generate']},
{'name': 'pinyin', 'title': '汉字转拼音', 'cat': ['conversion']},
{'name': 'ip', 'title': 'IP地址查询', 'cat': ['other']},
{'name': 'code', 'title': '代码格式化', 'cat': ['other']},
{'name': 'unicode', 'title': 'Unicode', 'cat': ['conversion']},
{'name': 'decimalConvert', 'title': '进制转换', 'cat': ['conversion']},
{'name': 'regex', 'title': '正则表达式', 'cat': ['check']},
{'name': 'randomString', 'title': '随机字符生成', 'cat': ['generate']},
{'name': 'serializeConversion', 'title': '序列化转换', 'cat': ['conversion', 'serialize']},
{'name': 'diffs', 'title': '文本差异化对比', 'cat': ['check']},
{'name': 'crontab', 'title': 'crontab校验', 'cat': ['check']},
{'name': 'websocket', 'title': 'websocket调试', 'cat': ['other']},
{'name': 'unit', 'title': '单位换算', 'cat': ['other']},
{'name': 'time', 'title': '时间计算器', 'cat': ['other']},
{'name': 'uuid', 'title': 'UUID生成', 'cat': ['generate']},
{'name': 'jsonToObject', 'title': 'JSON转实体类', 'cat': ['conversion', 'serialize']},
{'name': 'ascii', 'title': 'ASCII转换', 'cat': ['conversion']},
{'name': 'variableConversion', 'title': '变量名转换', 'cat': ['conversion']},
{'name': 'jwt', 'title': 'JWT解码', 'cat': ['conversion']},
{'name': 'hexString', 'title': 'Hex/String转换', 'cat': ['conversion']},
{'name': 'text', 'title': '文本处理', 'cat': ['other']},
{'name': 'html', 'title': 'html编码', 'cat': ['conversion']},
{'name': 'sign', 'cat': ['encryption', 'check']},
{'name': 'base64', 'cat': ['encryption','encoder_decoder']},
{'name': 'json', 'cat': ['conversion']},
{'name': 'url', 'cat': ['encoder_decoder']},
{'name': 'timestamp', 'cat': ['conversion']},
{'name': 'qrCode', 'cat': ['generate']},
{'name': 'barcode', 'cat': ['generate']},
{'name': 'pinyin', 'cat': ['conversion']},
{'name': 'ip', 'cat': ['other']},
{'name': 'code', 'cat': ['other']},
{'name': 'unicode', 'cat': ['encoder_decoder']},
{'name': 'decimalConvert', 'cat': ['conversion']},
{'name': 'regex', 'cat': ['check']},
{'name': 'randomString', 'cat': ['generate']},
{'name': 'serializeConversion', 'cat': ['conversion']},
{'name': 'diffs', 'cat': ['check']},
{'name': 'crontab', 'cat': ['check']},
{'name': 'websocket', 'cat': ['other']},
{'name': 'unit', 'cat': ['other']},
{'name': 'time', 'cat': ['other']},
{'name': 'uuid', 'cat': ['generate']},
{'name': 'jsonToObject', 'cat': ['conversion','generate']},
{'name': 'ascii', 'cat': ['conversion']},
{'name': 'variableConversion', 'cat': ['conversion']},
{'name': 'jwt', 'cat': ['encoder_decoder']},
{'name': 'hexString', 'cat': ['conversion']},
{'name': 'text', 'cat': ['other']},
{'name': 'html', 'cat': ['encoder_decoder']},
{'name': 'binary', 'cat': ['generate']},
{'name': 'armConverter', 'cat': ['conversion']},
]
// 工具类功能配置
......@@ -80,6 +80,8 @@ const utools = {
hexString: ['hex to string', 'string to hex', '十六进制转字符串', '字符串转十六机制'],
text: ['文本处理', '大小写转换', '中英文标点转换', '简繁转换', '字符替换', '字符统计', '行去重', '添加行号', '行排序', '过滤行首尾不可见字符', '过滤空行'],
sign: ['签名', '验签', 'rsa'],
binary: ['原码', '补码', '反码'],
armConverter: ['ARM', 'HEX'],
},
cmds: {
timestamp: [
......
{
"info_source": "Information Source: ",
"convert": "Convert",
"output": "Output",
"error": "error: {0}"
}
{
"input": "Input",
"length": "{0} bit",
"true_form": "trueForm",
"inverse": "Inverse",
"complement": "Complement",
"error": "error: {0}"
}
{
// ui
"ui_setting": "Settings",
"ui_reset": "Reset",
"ui_views": "View",
"ui_load":"Loading",
"ui_load": "Loading",
"ui_close": "Close",
"ui_copy_text_ok":"Result Copied ^o^",
"ui_copy_image_ok":"Image Copied ^o^",
"ui_copy_text_ok": "Result Copied ^o^",
"ui_copy_image_ok": "Image Copied ^o^",
// views
"setting_language": "Language",
"common_tool": "Common Tool",
"keyboard_setting":"Setting Shortcuts",
"unselected_tool": "Unselected Tool",
"keyboard_setting": "Setting Shortcuts",
"display_mode": "Theme",
"display_mode_light":"Light",
"display_mode_dark":"Dark",
"display_mode_auto":"Auto",
"copy_results_to_clipboard":"Copy results to clipboard",
"display_mode_light": "Light",
"display_mode_dark": "Dark",
"display_mode_auto": "Auto",
"copy_results_to_clipboard": "Copy results to clipboard",
"read_content_from_clipboard": "Read content from clipboard",
"read_clipboard_content_trim":"Read clipboard content trim",
"read_clipboard_content_trim": "Read clipboard content trim",
"common_tool_setting": "Common Tool Settings",
"keyboard_firefox_1":"Need to manually set shortcuts",
"keyboard_firefox_1": "Need to manually set shortcuts",
"keyboard_firefox_2": "Open [Add-ons Manager(about:addons)],Click the setting button on the right side of [Manage your extension],Select [Manage Extension Shortcuts] to modify these shortcuts.",
"keyboard_firefox_3":"Operation Method",
"keyboard_firefox_3": "Operation Method",
"history": "History",
"history_clear": "Clear history",
"history_time": "Operation time",
"history_data":"Data",
"history_data": "Data",
"history_op": "Operation",
"history_null":"History not found",
"history_null": "History not found",
// category
"category_common": "Common",
"category_encryption": "En/Decrypt",
"category_conversion": "Convert",
"category_serialize": "Serialize",
"category_encoder_decoder": "En/Decoder",
"category_check": "Validator",
"category_generate": "Generate",
"category_other": "Other",
......@@ -68,7 +67,8 @@
"tool_hexString": "Hex/String",
"tool_text": "Text",
"tool_html": "Html En/Decode",
"tool_binary": "trueForm/inverse/complement",
"tool_armConverter": "ARM/HEX",
// other
"css_main_category_item_style": "padding: 0 10px"
}
......@@ -59,5 +59,5 @@
"explain_blank_line_length_name": "Line Length",
"explain_blank_line_length_info": "Blank lines are also included in the number of lines",
"value": "value",
"stat_show": "Word:{1} UTF-8:{1} GBK:{2}"
"stat_show": "Word:{0} UTF-8:{1} GBK:{2}"
}
{
"info_source": "数据来源:",
"convert": "转换",
"output": "输出",
"error": "错误: {0}"
}
{
"input": "输入",
"length": "{0} 位",
"true_form": "原码",
"inverse": "反码",
"complement": "补码",
"error": "错误: {0}"
}
{
// ui
"ui_setting": "设置",
"ui_reset": "重置",
"ui_views": "查看",
"ui_load":"加载",
"ui_load": "加载",
"ui_close": "关闭",
"ui_copy_text_ok":"结果已复制 ^o^",
"ui_copy_image_ok":"图片已复制 ^o^",
"ui_copy_text_ok": "结果已复制 ^o^",
"ui_copy_image_ok": "图片已复制 ^o^",
// 界面
"setting_language": "语言",
"common_tool": "常用工具",
"keyboard_setting":"快捷键设置",
"unselected_tool": "未选择工具",
"keyboard_setting": "快捷键设置",
"display_mode": "主题",
"display_mode_light":"浅色",
"display_mode_dark":"深色",
"display_mode_auto":"自动",
"copy_results_to_clipboard":"自动复制结果到剪贴板",
"display_mode_light": "浅色",
"display_mode_dark": "深色",
"display_mode_auto": "自动",
"copy_results_to_clipboard": "自动复制结果到剪贴板",
"read_content_from_clipboard": "自动读取剪贴板内容",
"read_clipboard_content_trim":"读取剪贴板内容过滤首尾不可见字符",
"read_clipboard_content_trim": "读取剪贴板内容过滤首尾不可见字符",
"common_tool_setting": "常用工具设置",
"keyboard_firefox_1":"请手动设置快捷键",
"keyboard_firefox_1": "请手动设置快捷键",
"keyboard_firefox_2": "请打开附加组件管理器(about:addons),点击“管理扩展程序”右侧的设置按钮,选择“管理扩展快捷键”来修改这些快捷键。",
"keyboard_firefox_3":"操作方法",
"keyboard_firefox_3": "操作方法",
"history": "历史记录",
"history_clear": "清空历史记录",
"history_time": "操作时间",
"history_data":"数据",
"history_data": "数据",
"history_op": "操作",
"history_null":"暂无历史记录",
"history_null": "暂无历史记录",
// 分类
"category_common": "常用",
"category_encryption": "加解密",
"category_conversion": "转换",
"category_serialize": "序列化",
"category_encoder_decoder": "编解码",
"category_check": "校验",
"category_generate": "生成",
"category_other": "其他",
......@@ -65,10 +64,11 @@
"tool_ascii": "ASCII转换",
"tool_variableConversion": "变量名转换",
"tool_jwt": "JWT解码",
"tool_hexString": "Hex/String转换",
"tool_hexString": "Hex/String",
"tool_text": "文本处理",
"tool_html": "html编码",
"tool_html": "Html编码",
"tool_binary": "原码/反码/补码",
"tool_armConverter": "ARM/HEX",
// 其他
"css_main_category_item_style": "padding: 0 20px"
}
......@@ -145,6 +145,14 @@ const routes = [
{
path: '/tool/html',
component: r => require(['./views/tool/html.vue'], r)
},
{
path: '/tool/binary',
component: r => require(['./views/tool/binary.vue'], r)
},
{
path: '/tool/armConverter',
component: r => require(['./views/tool/armConverter.vue'], r)
}
]
......
......@@ -67,6 +67,7 @@
<script>
import config from './tool/config'
import {dispatchCategoryClickEvent} from './tool/event'
import instance from './tool/instance'
import BottomBlock from './bottom'
import settingBlock from "./views/setting/block"
......@@ -201,6 +202,9 @@ export default {
this.currentCategory = name
model.setCategoryHistory(name)
this.currentTool = model.getToolHistory(this.currentCategory)
this.$nextTick(()=>{
dispatchCategoryClickEvent(name)
})
break
}
},
......
......@@ -33,22 +33,22 @@ const setUserCommon = function (tools) {
cache.setNoVersion('user_common', tools)
}
const getToolTitle = function (name) {
const getToolDefaultCategory = function (name) {
for (let i = 0; i < tool.length; i++) {
if (tool[i].name === name) {
return tool[i].title
return tool[i].cat[0]
}
}
return ''
}
const getToolDefaultCategory = function (name) {
for (let i = 0; i < tool.length; i++) {
if (tool[i].name === name) {
return tool[i].cat[0]
const getToolByName = (name) => {
for (let item of tool) {
if (name === item.name) {
return item
}
}
return ''
return null
}
/**
......@@ -74,19 +74,21 @@ const saveSetting = function (name, value) {
}
export default {
tool,
tool: tool,
saveSetting,
getSetting,
category,
setUserCommon,
getToolTitle,
getUserCommon,
getToolByCategory(cat) {
let common = getUserCommon();
return tool.filter((t) => {
if (cat === 'common') {
return common.includes(t.name)
return getUserCommon().map((name) => {
return getToolByName(name)
}).filter((item) => {
return item !== null
});
}
return tool.filter((t) => {
return t.cat.includes(cat);
})
},
......
// 定义分类点击事件
export const CATEGORY_CLICK_EVENT_NAME = "ctoolCategoryClick"
export const dispatchCategoryClickEvent = (name) => {
const event = new CustomEvent(CATEGORY_CLICK_EVENT_NAME, {detail: {name}})
window.dispatchEvent(event);
}
......@@ -2,44 +2,49 @@
<div>
<div>
<CellGroup @on-click="open">
<Cell title="常用工具设置" name="setting"/>
<Cell v-if="is_chromium || is_firefox" title="快捷键设置" name="shortcuts"/>
<Cell title="外观显示">
<Cell :title="$t('main_common_tool')" name="setting"/>
<Cell v-if="is_chromium || is_firefox" :title="$t('main_keyboard_setting')" name="shortcuts"/>
<Cell :title="$t('main_display_mode')">
<Select v-model="display_mode" slot="extra" transfer>
<Option v-for="item in display_mode_list" :value="item.v" :key="item.v">{{ item.n }}</Option>
<Option v-for="item in display_mode_list" :value="item" :key="item">{{ $t('main_display_mode_'+item)}}</Option>
</Select>
</Cell>
<Cell :title="$t('main_setting_language')">
<Select v-model="locale" slot="extra" transfer>
<Option v-for="item in locales" :value="item.code" :key="item.code">{{ item.name }}</Option>
</Select>
</Cell>
</CellGroup>
<CellGroup>
<Cell title="自动复制结果到剪贴板">
<Cell :title="$t('main_copy_results_to_clipboard')">
<i-switch v-model="auto_save_copy" slot="extra"/>
</Cell>
<Cell title="自动读取剪贴板内容">
<Cell :title="$t('main_read_content_from_clipboard')">
<i-switch v-model="auto_read_copy" slot="extra"/>
</Cell>
<Cell title="读取剪贴板内容过滤首尾不可见字符">
<Cell :title="$t('main_read_clipboard_content_trim')">
<i-switch v-model="auto_read_copy_filter" slot="extra"/>
</Cell>
</CellGroup>
</div>
<Drawer title="设置" placement="left" v-model="settingShow" :width="90">
<setting-block v-if="settingShow"></setting-block>
<Drawer :title="$t('main_common_tool_setting')" placement="left" v-model="commonShow" :width="100">
<setting-common v-if="commonShow"></setting-common>
</Drawer>
</div>
</template>
<script>
import {isChromium, isFirefox, isUtools, openUrl, setDisplayMode} from '../../helper'
import {LOCALE_LISTS, setCurrentLocale} from '../../i18n'
import setting from '../../tool/setting'
import settingBlock from './setting'
import common from "./common"
export default {
components: {
"setting-block": settingBlock
"setting-common": common
},
data() {
return {
settingShow: false,
commonShow: false,
auto_save_copy: true,
auto_read_copy: true,
display_mode: "light",
......@@ -47,16 +52,17 @@ export default {
is_chromium: isChromium,
is_utools: isUtools,
is_firefox: isFirefox,
display_mode_list: [
{n: "浅色", v: "light"},
{n: "深色", v: "dark"},
{n: "自动", v: "auto"},
]
display_mode_list: ["light","dark","auto"],
locales: LOCALE_LISTS,
locale: "",
}
},
watch: {
display_mode(value) {
setDisplayMode(value)
},
locale(value) {
setCurrentLocale(value)
}
},
created() {
......@@ -64,12 +70,14 @@ export default {
this.auto_read_copy = setting.autoReadCopy()
this.auto_read_copy_filter = setting.autoReadCopyFilter()
this.display_mode = setting.displayMode()
this.locale = setting.locale()
},
beforeDestroy() {
setting.autoSaveCopy(this.auto_save_copy)
setting.autoReadCopy(this.auto_read_copy)
setting.autoReadCopyFilter(this.auto_read_copy_filter)
setting.displayMode(this.display_mode)
setting.locale(this.locale)
},
methods: {
open(name) {
......@@ -77,16 +85,16 @@ export default {
case 'shortcuts':
if (this.is_firefox) {
return this.$Notice.success({
title: '请手动设置快捷键',
title: this.$t('main_keyboard_firefox_1'),
render: h => {
return h('span', [
'请打开附加组件管理器(about:addons),点击“管理扩展程序”右侧的设置按钮,选择“管理扩展快捷键”来修改这些快捷键。',
this.$t('main_keyboard_firefox_2'),
h('a', {
attrs: {
href: 'https://jingyan.baidu.com/article/3ea51489f1d0a713e61bbaff.html',
target: '_blank'
}
}, '操作方法'),
}, this.$t('main_keyboard_firefox_3')),
])
}
});
......@@ -94,7 +102,7 @@ export default {
openUrl('chrome://extensions/shortcuts')
break
case 'setting':
this.settingShow = true
this.commonShow = true
break
}
}
......
<template>
<div>
<CheckboxGroup v-model="tools" @on-change="toolUpdate" style="line-height: 30px;">
<Checkbox v-for="(t,k) in all" :key="k" :label="t.name">{{t.title}}</Checkbox>
</CheckboxGroup>
<Card :title="$t('main_common_tool')">
<draggable v-model="selected" group="tool">
<Button style="margin: 5px" v-for="name in selected" type="dashed" :key="name">{{$t('main_tool_'+name)}}</Button>
</draggable>
<Button size="small" slot="extra" type="primary" @click="reset">{{$t('main_ui_reset')}}</Button>
</Card>
<Card :title="$t('main_unselected_tool')" style="margin-top: 10px">
<draggable v-model="unselected" group="tool">
<Button style="margin: 5px" v-for="name in unselected" type="dashed" :key="name">{{$t('main_tool_'+name)}}</Button>
</draggable>
</Card>
</div>
</template>
<script>
import config from "../../tool/config"
import {DEFAULT_COMMON_TOOL} from "../../tool/config"
import draggable from "vuedraggable";
export default {
components: {
draggable
},
data() {
return {
style:"",
selected:[],
unselected:[],
tools: [],
all: config.tool
}
},
created() {
this.tools = config.getToolByCategory('common').map(function (item) {
this.selected = config.getToolByCategory('common').map(function (item) {
return item.name;
});
this.unselected = config.tool.filter(({name})=>{
return !this.selected.includes(name)
}).map(function (item) {
return item.name;
})
},
methods: {
toolUpdate(tools) {
console.log(tools)
config.setUserCommon(tools);
},
watch:{
selected(){
config.setUserCommon(this.selected ? this.selected : []);
}
},
methods:{
reset(){
this.selected = DEFAULT_COMMON_TOOL
}
}
}
</script>
<template>
<Card>
<Tabs value="common">
<TabPane :label="$t('main_common_tool_setting')" name="common">
<setting-common></setting-common>
</TabPane>
</Tabs>
</Card>
</template>
<script>
import common from "./common"
export default {
components: {
"setting-common": common
}
}
</script>
<template>
<div class="tool-armConverter">
<Tabs v-model="current.operation">
<TabPane label="ARM to HEX" name="arm_to_hex"/>
<TabPane label="HEX to ARM" name="hex_to_arm"/>
<Alert style="padding: 5px;margin-bottom:0" slot="extra">
{{ $t('armConverter_info_source') }} <a href="https://armconverter.com/" target="_blank">https://armconverter.com/</a>
</Alert>
</Tabs>
<Row :gutter="10">
<Col span="10">
<div class="page-option-input-block" style="margin-bottom: 5px">
<Input v-model="current.offset" placeholder="0 - for branch and LDR put hex value here">
<span slot="prepend">Offset (hex) 0x</span>
</Input>
</div>
<input-block top="5px">
<heightResize :reduce="45" :append="['.page-option-input-block']">
<autoHeightTextarea v-if="isArmToHex" v-model="current.asm_input" :placeholder="inputPlaceholder"/>
<autoHeightTextarea v-else v-model="current.hex_input" :placeholder="inputPlaceholder"/>
</heightResize>
<template slot="extra">
<Button :loading="loading" type="primary" size="small" @click="convert()">{{ $t('armConverter_convert') }}</Button>
</template>
</input-block>
</Col>
<Col span="14">
<Card dis-hover class="page-option-output-block">
<p slot="title">{{ $t('armConverter_output') }}</p>
<div slot="extra">
<Checkbox :disabled="!isArmToHex" v-model="current.prefix_0x">0x</Checkbox>
<Checkbox :disabled="!isArmToHex" v-model="current.swap_endian">GDB/LLDB</Checkbox>
</div>
</Card>
<heightResize :reduce="45" :append="['.page-option-output-block']" @resize="resize">
<input-block :text="'ARM64'+endianPlaceholder" @on-default-right-bottom-click="()=>copy(outputArm64)">
<autoHeightTextarea :value="outputArm64" :height="outputHeight" :placeholder="'ARM64'+endianPlaceholder"/>
</input-block>
<input-block :text="'ARM'+endianPlaceholder" @on-default-right-bottom-click="()=>copy(outputArm)">
<autoHeightTextarea style="margin-top: 5px" :value="outputArm" :height="outputHeight" :placeholder="'ARM'+endianPlaceholder"/>
</input-block>
<input-block :text="'ARM Big Endian'" @on-default-right-bottom-click="()=>copy(outputArmBigEndian)" v-if="!isArmToHex">
<autoHeightTextarea style="margin-top: 5px" :value="outputArmBigEndian" :height="outputHeight" :placeholder="'ARM Big Endian'"/>
</input-block>
<input-block :text="'THUMB'+endianPlaceholder" @on-default-right-bottom-click="()=>copy(outputThumb)">
<autoHeightTextarea style="margin-top: 5px" :value="outputThumb" :height="outputHeight" :placeholder="'THUMB'+endianPlaceholder"/>
</input-block>
<input-block :text="'THUMB Big Endian'" @on-default-right-bottom-click="()=>copy(outputThumbBigEndian)" v-if="!isArmToHex">
<autoHeightTextarea style="margin-top: 5px" :value="outputThumbBigEndian" :height="outputHeight" :placeholder="'THUMB Big Endian'"/>
</input-block>
</heightResize>
</Col>
</Row>
</div>
</template>
<script>
import heightResize from "./components/heightResize";
import autoHeightTextarea from "./components/autoHeightTextarea";
import axios from "axios";
export default {
components: {
heightResize,
autoHeightTextarea
},
created() {
this.$initToolData()
},
computed: {
isArmToHex() {
return this.current.operation === 'arm_to_hex';
},
endianPlaceholder() {
return this.isArmToHex && this.current.swap_endian ? " Big Endian" : ""
},
inputPlaceholder() {
if (this.isArmToHex) {
return "Input Assembly code:\nNOP\nRET\nB #0x1018DE444\nMOV X0, #0x11FE00000000\nBEQ #0x10020C\nCBNZ R0, #0x682C4"
}
return "Input Hex code:\n40000494\nC0035FD6\nF0 B5 03 AF81b0"
},
outputArm64() {
return this.convertResult('arm64')
},
outputArm() {
return this.convertResult('arm')
},
outputThumb() {
return this.convertResult('thumb')
},
outputArmBigEndian() {
return this.convertResult('armbe')
},
outputThumbBigEndian() {
return this.convertResult('thumbbe')
},
outputHeight() {
return this.isArmToHex ? (this.pageOutputHeight - 10) / 3 : (this.pageOutputHeight - 20) / 5
},
response(){
return this.isArmToHex ? this.current.asm_response : this.current.hex_response
}
},
methods: {
copy(data) {
if (data) {
this.$clipboardCopy(data)
}
},
resize(height) {
this.pageOutputHeight = height;
},
convert() {
this.loading = true
try {
let data = {};
if (this.isArmToHex) {
if (!this.current.asm_input){
throw new Error("input error")
}
data = {
"asm": this.current.asm_input,
"offset": this.current.offset,
"arch": ["arm64", "arm", "thumb"]
};
this.current.asm_response = ""
} else {
if (!this.current.hex_input){
throw new Error("input error")
}
data = {
"hex": this.current.hex_input,
"offset": this.current.offset,
"arch": ["arm64", "arm", "armbe", "thumb", "thumbbe"]
};
this.current.hex_response = ""
}
this.request(data)
} catch (error) {
this.loading = false
return this.$Message.error(
this.$t('armConverter_error', [error.message]).toString()
)
}
},
request(data) {
axios({
url: 'https://www.baiy.org/chrome_tool/armconverter/',
method: 'post',
data: JSON.stringify(data),
headers: {'Content-Type': 'application/json'}
}).then(({data}) => {
if (data.code !== 0) {
return this.$Message.error(
this.$t('armConverter_error', [data.info]).toString()
)
}
if (this.isArmToHex){
this.current.asm_response = data.data["hex"]
}
else{
this.current.hex_response = data.data["asm"]
}
this.$saveToolData(this.current);
}).catch((error) => {
return this.$Message.error(
this.$t('armConverter_error', [error.message]).toString()
)
}).then( ()=> {
this.loading = false
});
},
convertResult(field) {
if (!this.response || !(field in this.response)) {
return "";
}
let text = this.response[field][1]
if (
!this.isArmToHex
|| (!this.current.prefix_0x && !this.current.swap_endian)
) {
return text;
}
const size = {
arm64: 4,
arm: 4,
armbe: 4,
thumb: 2,
thumbbe: 2
}
// prefix_0x && swap_endian
return text.split('\n').map((line) => {
return this.swap(line, size[field], this.current.prefix_0x ? "0x" : "")
}).join('\n');
},
swap(text, size, prefix) {
if (!text || text.startsWith('#')) {
// this is an error, not actual code
return text;
}
if (!this.current.swap_endian) {
return prefix + text;
}
const size_chars = size * 2;
let result = '';
for (let i = 0; i < text.length; i += size_chars) {
const chunk = text.slice(i, i + size_chars);
for (let j = chunk.length; j > 0; j -= 2) {
result += chunk.slice(j - 2, j);
}
}
return prefix + result;
}
},
data() {
return {
current: {
operation: "arm_to_hex",
asm_input: "",
hex_input: "",
offset: "",
asm_response: "",
hex_response: "",
prefix_0x: false,
swap_endian: false
},
loading:false,
pageOutputHeight: 100
}
},
}
</script>
<style>
.tool-armConverter .ivu-tabs-bar {
margin-bottom: 8px;
}
.tool-armConverter .ivu-card-head {
line-height: 31px;
height: 31px;
padding: 0 16px;
}
.tool-armConverter .ivu-card-head p {
line-height: 31px;
height: 31px;
font-weight: normal;
color: #515a6e;
}
.tool-armConverter .ivu-card-extra {
top: 3px;
}
.tool-armConverter .ivu-card-bordered {
border-bottom: none;
}
.tool-armConverter .ivu-card-body {
padding: 0;
}
.tool-armConverter .ivu-card {
margin-bottom: 5px;
}
</style>
<template>
<div>
<Row>
<div id="barcode-setting">
<Row :gutter="10">
<Col span="12">
<Card>
<Form :label-width="100">
<FormItem label="条码内容">
<Form :label-width="80">
<FormItem :label="$t('barcode_content')">
<Input v-model="current.text">
<Select v-model="current.format" slot="append" style="width: 100px">
<Option v-for="type in barcodeFormat" :key="type" :value="type">{{ type }}</Option>
</Select>
</Input>
</FormItem>
<FormItem label="条码宽" class="line-item">
<Row>
<Col span="22">
<Slider v-model="current.width" :min="0" :max="4"></Slider>
<Col span="12">
<FormItem :label="$t('barcode_background')">
<ColorPicker recommend v-model="current.background"/>
</FormItem>
</Col>
<Col span="2">
<Col span="12">
<FormItem :label="$t('barcode_line_color')">
<ColorPicker recommend v-model="current.lineColor"/>
</FormItem>
</Col>
</Row>
<FormItem :label="$t('barcode_bar_width')">
<Row>
<Col span="21">
<Slider v-model="current.width" :min="1" :max="4"></Slider>
</Col>
<Col span="3">
<span style="float: right">{{ this.current.width }}</span>
</Col>
</Row>
</FormItem>
<FormItem label="条码高" class="line-item">
<FormItem :label="$t('barcode_height')">
<Row>
<Col span="22">
<Col span="21">
<Slider v-model="current.height" :min="10" :max="150"></Slider>
</Col>
<Col span="2">
<Col span="3">
<span style="float: right">{{ this.current.height }}</span>
</Col>
</Row>
</FormItem>
<FormItem label="条码外边距" class="line-item">
<FormItem :label="$t('barcode_margin')">
<Row>
<Col span="22">
<Col span="21">
<Slider v-model="current.margin" :min="0" :max="25"></Slider>
</Col>
<Col span="2">
<Col span="3">
<span style="float: right">{{ this.current.margin }}</span>
</Col>
</Row>
</FormItem>
<FormItem label="背景" class="line-item">
<Input type="text" id="backgroundInput" v-model="current.background.hex"
@on-focus="openBackgroundPicker($event)"></Input>
<chrome-picker v-show="showBackgroundPicker" id="backgroundPicker" style="position: fixed;z-index: 1000"
v-model="current.background"
@input="updateBackground"/>
</FormItem>
<FormItem label="线条颜色" class="line-item">
<Input type="text" id="lineColorInput" v-model="current.lineColor.hex"
@on-focus="openLineColorPicker"></Input>
<chrome-picker v-show="showLineColoePicker" id="lineColorPicker" style="position: fixed;z-index: 1000"
v-model="current.lineColor"
@input="updateLineColor"/>
</FormItem>
<FormItem label="显示文本" class="line-item">
<RadioGroup v-model="current.showText" type="button">
<Radio label="true">
<span>显示</span>
</Form>
</Col>
<Col span="12">
<Form :label-width="80">
<FormItem :label="$t('barcode_show_text')">
<RadioGroup v-model="current.textPosition" type="button">
<Radio label="close">
<span>{{ $t('barcode_hide') }}</span>
</Radio>
<Radio label="false">
<span>隐藏</span>
<Radio label="top">
<span>{{ $t('barcode_top') }}</span>
</Radio>
<Radio label="bottom">
<span>{{ $t('barcode_bottom') }}</span>
</Radio>
</RadioGroup>
</FormItem>
<div v-if="this.current.showText === 'true'">
<FormItem label="字体位置" class="line-item">
<FormItem :label="$t('barcode_text_align')">
<RadioGroup v-model="current.textAlign" type="button">
<Radio label="left">
<span>居左</span>
<Radio :disabled="!showText" label="left">
<span>{{ $t('barcode_left') }}</span>
</Radio>
<Radio label="center">
<span>居中</span>
<Radio :disabled="!showText" label="center">
<span>{{ $t('barcode_center') }}</span>
</Radio>
<Radio label="right">
<span>居右</span>
<Radio :disabled="!showText" label="right">
<span>{{ $t('barcode_right') }}</span>
</Radio>
</RadioGroup>
</FormItem>
<FormItem label="字体" class="line-item">
<Select v-model="current.font">
<FormItem :label="$t('barcode_font')">
<Row :gutter="10">
<Col span="12">
<Select :disabled="!showText" v-model="current.font">
<Option v-for="font in fontFamily" :key="font" :value="font">{{ font }}</Option>
</Select>
</FormItem>
<FormItem label="字体样式" class="line-item">
</Col>
<Col span="12">
<CheckboxGroup v-model="current.fontOptions">
<Checkbox label="bold">
<span>粗体</span>
<Checkbox :disabled="!showText" label="bold">
<span>{{ $t('barcode_bold') }}</span>
</Checkbox>
<Checkbox label="italic">
<span>斜体</span>
<Checkbox :disabled="!showText" label="italic">
<span>{{ $t('barcode_italic') }}</span>
</Checkbox>
</CheckboxGroup>
</Col>
</Row>
</FormItem>
<FormItem label="字体大小" class="line-item">
<FormItem :label="$t('barcode_font_size')">
<Row>
<Col span="22">
<Slider v-model="current.fontSize" :min="8" :max="36"></Slider>
<Slider :disabled="!showText" v-model="current.fontSize" :min="8"
:max="36"></Slider>
</Col>
<Col span="2">
<span style="float: right">{{ this.current.fontSize }}</span>
</Col>
</Row>
</FormItem>
<FormItem label="字体外边距" class="line-item">
<FormItem :label="$t('barcode_text_margin')">
<Row>
<Col span="22">
<Slider v-model="current.textMargin" :min="-15" :max="40"></Slider>
<Slider :disabled="!showText" v-model="current.textMargin" :min="-15"
:max="40"></Slider>
</Col>
<Col span="2">
<span style="float: right">{{ this.current.textMargin }}</span>
</Col>
</Row>
</FormItem>
</div>
</Form>
</Card>
</Col>
<Col span="12">
<Card>
<div>
<canvas id="barcode"></canvas>
<p style="color: red">{{ validStr }}</p>
</div>
</Card>
</Col>
</Row>
</div>
<heightResize @resize="resize" ignore :append="['#barcode-setting']">
<div :style="`height: ${outputHeight}px;line-height:${outputHeight}px;text-align: center;vertical-align: middle;`">
<canvas @click="saveImage" :style="`border: ${canvasBorder};vertical-align: middle;`" ref="barcode"
class="barcode" v-show="!validStr" style="cursor:pointer"></canvas>
<p style="color: red" v-show="validStr">{{ validStr }}</p>
</div>
</heightResize>
</div>
</template>
<script>
/**
......@@ -135,29 +143,30 @@
* @date 2021/10/30
* 基于jsbarcode生成条形码,可以自定义条码各项属性
* 不支持中文
* 颜色选择器采用vue-color
*/
import JsBarcode from 'jsbarcode'
import {Chrome} from 'vue-color'
import heightResize from "./components/heightResize";
export default {
components: {
heightResize
},
created() {
this.current = Object.assign(this.current, this.$getToolData("content"))
this.$initToolData('text')
},
components: {
'chrome-picker': Chrome,
computed: {
showText() {
return ['top', 'bottom'].includes(this.current.textPosition)
},
canvasBorder() {
if (this.current.background.toUpperCase() === "#FFFFFF") {
return "1px dashed #666"
}
return "1px dashed #fff";
}
},
mounted() {
// 加载颜色选择器消失的事件
this.loadEvent()
// 生成默认的条形码
this.generate()
},
beforeDestroy() {
// 移除挂载时添加的事件
document.removeEventListener('click', () => {
}, true)
},
watch: {
current: {
handler() {
......@@ -166,112 +175,61 @@ export default {
deep: true
}
},
methods: {
/**
* 检查
* @param event
* @param id
* @returns {boolean}
*/
checkNodeContainsId(event, id) {
// 检查目标元素及目标元素上层是否存在指定id元素
let et = event.target
while (et && et.id !== undefined) {
// 检查当前元素上是否存在指定
if (et.id === id) {
return true
}
et = et.parentNode
}
},
loadEvent() {
let _this = this
document.addEventListener('click', (e) => {
// 如果点击的区域不是输入框或者是背景色选择器则将背景选择器隐藏
if (!_this.checkNodeContainsId(e, 'backgroundInput') && !_this.checkNodeContainsId(e, 'backgroundPicker')) {
_this.showBackgroundPicker = false
}
// 同理
if (!_this.checkNodeContainsId(e, 'lineColorInput') && !_this.checkNodeContainsId(e, 'lineColorPicker')) {
_this.showLineColoePicker = false
}
})
},
openBackgroundPicker() {
this.showBackgroundPicker = true
this.showLineColoePicker = false
},
updateBackground(val) {
this.current.background = val
},
openLineColorPicker() {
this.showLineColoePicker = true
this.showBackgroundPicker = false
},
updateLineColor(val) {
this.current.lineColor = val
},
closeColorPicker() {
this.showLineColoePicker = false
this.showBackgroundPicker = false
},
generate() {
let _this = this;
// 处理字体样式
let fontOptions = this.current.fontOptions.join(" ")
JsBarcode("#barcode", this.current.text, {
format: this.current.format,//选择要使用的条形码类型
const barcodeContent = this.current.text ? this.current.text : "Example 1234"
JsBarcode(this.$refs.barcode, barcodeContent, {
format: this.current.format,
width: this.current.width,
height: this.current.height,
margin: this.current.margin,
background: this.current.background.hex,
lineColor: this.current.lineColor.hex,
displayValue: this.current.showText,//是否在条形码下方显示文字
textPosition: "bottom",//设置文本的垂直位置
background: this.current.background,
lineColor: this.current.lineColor,
displayValue: this.showText,
textPosition: this.current.textPosition,
textAlign: this.current.textAlign,
font: this.current.font,
fontOptions: fontOptions,
fontSize: this.current.fontSize,
textMargin: this.current.textMargin,
valid: function (valid) {
// 显示条码内容无效
if (!valid) {
_this.validStr = "无效的条码内容"
} else {
_this.validStr = ""
valid: (valid) => {
this.validStr = !valid ? `"${barcodeContent}" ${this.$t('barcode_invalid_content').toString()}` : "";
if (!this.validStr && this.current.text) {
this.$saveToolData(this.current)
}
}
})
},
saveImage() {
if (!this.validStr && this.current.text) {
this.$clipboardCopyImages(this.$refs.barcode.toDataURL("image/png"), true)
}
},
resize(height){
this.outputHeight = Math.max(250,height)
}
},
data() {
return {
outputHeight:250,
current: {
text: "Test 123456789",
text: "",
format: "CODE128",
width: 2,
height: 50,
margin: 10,
background: {
hex: '#FFFFFF',
},
lineColor: {
hex: '#000000',
},
showText: "true",
background: "#FFFFFF",
lineColor: "#000000",
textAlign: "center",
textPosition: "bottom",
font: "monospace",
fontOptions: [],
fontSize: 20,
textMargin: 0
},
validStr: '',
// 背景色选择器控制开关
showBackgroundPicker: false,
// 线条颜色选择器控制开关
showLineColoePicker: false,
// 条码格式
barcodeFormat: [
"CODE128",
......@@ -297,8 +255,8 @@ export default {
"Serif",
"Fantasy",
"Cursive"
]
],
barcodeBase64: "",
}
},
}
......@@ -306,7 +264,7 @@ export default {
<style scoped>
/**iview原来的formitem太高了,在浏览器直接使用插件时会被撑开,因此需要压缩下高度**/
.line-item {
margin-top: -20px;
#barcode-setting .ivu-form-item {
margin-bottom: 2px;
}
</style>
<template>
<heightResize @resize="resize">
<Row :gutter="10">
<Col span="8">
<input-block top="5px">
<autoHeightTextarea v-model="current.input" :height="inputHeight"
:placeholder="$t('binary_input')"/>
<Select slot="extra" v-model="current.length" style="width:100px">
<Option :value="8">{{ $t('binary_length', [8]) }}</Option>
<Option :value="16">{{ $t('binary_length', [16]) }}</Option>
<Option :value="32">{{ $t('binary_length', [32]) }}</Option>
</Select>
</input-block>
</Col>
<Col span="16">
<input-block top="5px" :text="$t('binary_true_form')"
@on-default-right-bottom-click="()=>copy(result('trueForm'))">
<autoHeightTextarea :value="result('trueForm')" :height="outputHeight"
:placeholder="$t('binary_true_form')" style="margin-bottom: 10px"/>
</input-block>
<input-block top="5px" :text="$t('binary_inverse')"
@on-default-right-bottom-click="()=>copy(result('inverse'))">
<autoHeightTextarea :value="result('inverse')" :height="outputHeight"
:placeholder="$t('binary_inverse')" style="margin-bottom: 10px"/>
</input-block>
<input-block top="5px" :text="$t('binary_complement')"
@on-default-right-bottom-click="()=>copy(result('complement'))">
<autoHeightTextarea :value="result('complement')" :height="outputHeight"
:placeholder="$t('binary_complement')"/>
</input-block>
</Col>
</Row>
</heightResize>
</template>
<script>
import caculate from "./library/binary"
import heightResize from "./components/heightResize";
import autoHeightTextarea from "./components/autoHeightTextarea";
export default {
components: {
heightResize,
autoHeightTextarea
},
created() {
this.$initToolData('input', (data) => {
return /^[\d\-+\n]+$/.test(data)
})
},
methods: {
copy(data) {
if (data) {
this.$clipboardCopy(data)
}
},
resize(height) {
this.inputHeight = height
this.outputHeight = Math.ceil((height - 20) / 3)
},
result(type) {
if (this.current.input.trim() === "") {
return ""
}
let output = []
for (let input of this.current.input.trim().split("\n")) {
try {
output.push(caculate(input, this.current.length, type))
} catch (e) {
output.push(this.$t('binary_error', [e.message]).toString())
}
}
this.$saveToolData(this.current)
return output.join("\n");
}
},
data() {
return {
current: {
input: "",
length: 8,
},
inputHeight: 100,
outputHeight: 100
}
},
}
</script>
......@@ -4,7 +4,7 @@
</div>
</template>
<script>
import {CATEGORY_CLICK_EVENT_NAME} from '../../../tool/event'
function getAbsoluteHeight(select) {
let el = document.querySelector(select)
if (el === null) {
......@@ -73,9 +73,11 @@ export default {
},
destroyed() {
window.removeEventListener("resize", this.reportWindowSize);
window.removeEventListener(CATEGORY_CLICK_EVENT_NAME, this.reportWindowSize);
},
mounted() {
window.addEventListener("resize", this.reportWindowSize);
window.addEventListener(CATEGORY_CLICK_EVENT_NAME, this.reportWindowSize);
this.resize();
}
};
......
......@@ -2,20 +2,26 @@
<div>
<Row :gutter="16">
<Col span="12">
<Input v-model="current.input" style="margin-bottom: 16px">
<span slot="prepend">表达式</span>
<Input v-model="current.input" style="margin-bottom: 16px" class="page-option-input">
<span slot="prepend">{{ $t('crontab_expression') }}</span>
</Input>
<Input :value="output" :rows="14" type="textarea" placeholder="最近执行时间"></Input>
<heightResize :append="['.page-option-input']">
<autoHeightTextarea :value="output" :placeholder="$t('crontab_execute_time')"/>
</heightResize>
</Col>
<Col span="12">
<Col span="12" class="page-option-reference">
<Tabs value="example">
<TabPane label="例子" name="example">
<Table stripe size="small" height="300" :columns="example.columns" :data="example.data"></Table>
<TabPane :label="$t('crontab_example')" name="example">
<heightResize :reduce="52" @resize="resize">
<Table stripe size="small" :height="referenceHeight" border :columns="example.columns"
:data="example.data"></Table>
</heightResize>
</TabPane>
<TabPane label="格式" name="format" style="text-align: center">
<img src="../../statics/crontab.png" style="height: 300px" alt="">
<TabPane :label="$t('crontab_format')" name="format" style="text-align: center">
<img v-if="locale === 'zh_CN'" src="../../statics/crontab_cn.png" style="height: 300px" alt="">
<img v-else src="../../statics/crontab_en.png" style="height: 300px" alt="">
</TabPane>
<TabPane label="特殊字符" name="special">
<TabPane :label="$t('crontab_symbol')" name="special">
<Table stripe size="small" height="300" :columns="special.columns" :data="special.data"></Table>
</TabPane>
</Tabs>
......@@ -24,21 +30,31 @@
</div>
</template>
<script>
import cronstrue from 'cronstrue/i18n';
import parser from 'cron-parser';
import moment from "moment"
import cronstrue from 'cronstrue/i18n';
import parser from 'cron-parser';
import moment from "moment"
import {getCurrentLocale} from "../../i18n";
import heightResize from "./components/heightResize";
import autoHeightTextarea from "./components/autoHeightTextarea";
export default {
export default {
components: {
heightResize,
autoHeightTextarea
},
computed: {
locale() {
return getCurrentLocale()
},
output() {
if (!this.current.input) return "";
let list = [];
try {
list.push(cronstrue.toString(this.current.input, {locale: "zh_CN"}));
list.push("\n最近10次执行时间");
list.push(this.conversion(this.current.input));
list.push(`\n${this.$t('crontab_execute_time_list')}`);
let interval = parser.parseExpression(this.current.input);
for (let i = 1; i <= 10; i++) {
list.push(`第${i}次: ` + moment(interval.next().toString()).format("YYYY-MM-DD HH:mm:ss"))
list.push(this.$t('crontab_no', [i, moment(interval.next().toString()).format("YYYY-MM-DD HH:mm:ss")]))
}
this.$saveToolData(this.current);
} catch (err) {
......@@ -49,67 +65,88 @@
},
},
created() {
this.current = Object.assign(this.current, this.$getToolData())
this.$initToolData('input', (data) => {
try {
cronstrue.toString(data)
} catch {
return false
}
return true
})
this.example.data = this.example.data.map((item) => {
return {
example: item,
text: this.conversion(item)
}
})
},
methods: {
conversion(input) {
return cronstrue.toString(input, {locale: this.locale, use24HourTimeFormat: true})
},
resize(height) {
this.referenceHeight = height
}
},
data() {
return {
referenceHeight: 101,
current: {
input: "2 */5 * * 2-5",
operation: "check"
input: "2 */5 * * 2-5"
},
special: {
columns: [
{title: '特殊字符', key: 'name', width: 100},
{title: '代表意义', key: 'text'},
{title: this.$t('crontab_symbol'), key: 'name', width: 100},
{title: this.$t('crontab_description'), key: 'text'},
],
data: [
{
name: "*(星号)",
text: "代表任何时刻都接受的意思。举例来说,范例一内那个日、月、周都是*,就代表着不论何月、何日的礼拜几的12:00都执行后续命令的意思。"
name: "*",
text: this.$t('crontab_symbol_description_1')
},
{
name: ",(逗号)",
text: "代表分隔时段的意思。举例来说,如果要执行的工作是3:00与6:00时,就会是:0 3,6 * * * command时间还是有五列,不过第二列是 3,6 ,代表3与6都适用"
name: ",",
text: this.$t('crontab_symbol_description_2')
},
{
name: "-(减号)",
text: "代表一段时间范围内,举例来说,8点到12点之间的每小时的20分都进行一项工作:20 8-12 * * * command仔细看到第二列变成8-12.代表 8,9,10,11,12 都适用的意思"
name: "-",
text: this.$t('crontab_symbol_description_3')
},
{
name: "/n(斜线)",
text: "那个n代表数字,即是每隔n单位间隔的意思,例如每五分钟进行一次,则:*/5 * * * * command用*与/5来搭配,也可以写成0-59/5,意思相同"
name: "/n",
text: this.$t('crontab_symbol_description_4')
}
]
},
example: {
columns: [
{title: '例子', key: 'example', width: 120},
{title: '说明', key: 'text'},
{title: this.$t('crontab_example'), key: 'example', width: 120},
{title: this.$t('crontab_description'), key: 'text'},
],
data: [
{example: "*/1 * * * *", text: "每1分钟执行"},
{example: "* * * * *", text: "每1分钟执行"},
{example: "*/5 * * * *", text: "每5分钟执行"},
{example: "0 * * * *", text: "每小时执行"},
{example: "0 */1 * * *", text: "每小时执行"},
{example: "0 7 * * *", text: "每天上午7点执行"},
{example: "10 7 * * *", text: "每天上午7点10分执行"},
{example: "0 0 * * *", text: "每天定时执行一次"},
{example: "0 0 * * 0", text: "每周定时执行一次"},
{example: "0 0 1 * *", text: "每月定时执行一次"},
{example: "0 0 1 1 *", text: "每年定时执行一次"},
{example: "5 * * * *", text: "指定每小时的第5分钟执行一次命令"},
{example: "30 5 * * *", text: "指定每天的 5:30 执行命令"},
{example: "30 7 8 * *", text: "指定每月8号的7:30分执行命令"},
{example: "30 5 8 6 *", text: "指定每年的6月8日5:30执行命令"},
{example: "30 6 * * 0", text: "指定每星期日的6:30执行命令"},
{example: "30 3 10,20 * *", text: "每月10号及20号的3:30执行命令[注:“,”用来连接多个不连续的时段]"},
{example: "25 8-11 * * *", text: "每天8-11点的第25分钟执行命令[注:“-”用来连接连续的时段"},
{example: "*/15 * * * *", text: "每15分钟执行一次命令 [即每个小时的第0 15 30 45 60分钟执行命令]"},
{example: "30 6 */10 * *", text: "每个月中,每隔10天6:30执行一次命令[即每月的1、11、21、31日是的6:30执行一次命令。]"}
"*/1 * * * *",
"* * * * *",
"*/5 * * * *",
"0 * * * *",
"0 */1 * * *",
"0 7 * * *",
"10 7 * * *",
"0 0 * * *",
"0 0 * * 0",
"0 0 1 * *",
"0 0 1 1 *",
"5 * * * *",
"30 5 * * *",
"30 7 8 * *",
"30 5 8 6 *",
"30 6 * * 0",
"30 3 10,20 * *",
"25 8-11 * * *",
"*/15 * * * *",
"30 6 */10 * *"
]
}
}
}
}
}
</script>
<template>
<div>
<Input v-model="current.input" :rows="7" type="textarea" placeholder="内容"></Input>
<option-block>
<FormItem>
<ButtonGroup>
<Button type="primary" @click="handle(v)" v-for="v in type" :key="v">{{ v }}</Button>
</ButtonGroup>
</FormItem>
<FormItem>
<Checkbox v-model="current.isUppercase">大写字母</Checkbox>
</FormItem>
</option-block>
<Input v-model="current.output" :rows="7" type="textarea" placeholder="结果"></Input>
<div id="tool-hash">
<Row :gutter="10">
<Col span="8">
<input-block>
<heightResize>
<autoHeightTextarea v-model="current.input" :placeholder="$t('hash_content')"/>
</heightResize>
<Checkbox slot="extra" v-model="current.isUppercase">{{ $t('hash_uppercase') }}</Checkbox>
</input-block>
</Col>
<Col span="16">
<heightResize @resize="resize">
<input-block :style="`margin-top: ${no >0 ? 5 : 0}px;`" :text="type" v-for="(type,no) in types" :key="type" @on-default-right-bottom-click="()=>copy(type)">
<autoHeightTextarea :value="result(type)" :height="outputHeight" :placeholder="type"/>
</input-block>
</heightResize>
</Col>
</Row>
</div>
</template>
<script>
import crypto from "crypto-js"
import heightResize from "./components/heightResize";
import autoHeightTextarea from "./components/autoHeightTextarea";
const sm = require('sm-crypto');
export default {
components: {
heightResize,
autoHeightTextarea
},
created() {
this.current = Object.assign(this.current, this.$getToolData("input"))
this.$initToolData('input')
},
computed: {
md5() {
let result = crypto.MD5(this.current.input).toString();
return this.current.isUppercase ? result.toUpperCase() : result;
},
sha1() {
let result = crypto.SHA1(this.current.input).toString();
return this.current.isUppercase ? result.toUpperCase() : result;
},
sha256() {
let result = crypto.SHA256(this.current.input).toString();
return this.current.isUppercase ? result.toUpperCase() : result;
},
methods: {
handle(v) {
if (this.current.input) {
switch (v) {
case "md5":
this.current.output = crypto.MD5(this.current.input).toString();
break;
case "sha1":
this.current.output = crypto.SHA1(this.current.input).toString();
break;
case "sha256":
this.current.output = crypto.SHA256(this.current.input).toString();
break;
case "sha512":
this.current.output = crypto.SHA512(this.current.input).toString();
break;
case "sm3":
this.current.output = require('sm-crypto').sm3(this.current.input);
break;
default:
return;
sha512() {
let result = crypto.SHA512(this.current.input).toString();
return this.current.isUppercase ? result.toUpperCase() : result;
},
sm3() {
let result = sm.sm3(this.current.input);
return this.current.isUppercase ? result.toUpperCase() : result;
},
},
watch: {
current: {
handler() {
if (this.current.input){
this.$saveToolData(this.current);
}
if (this.current.isUppercase) {
this.current.output = this.current.output.toUpperCase()
},
deep: true
}
this.current.operation = v;
this.$clipboardCopy(this.current.output);
this.$saveToolData(this.current);
},
methods:{
result(type){
if (!this.current.input) {
return "";
}
return this[type]
},
copy(type){
if (this[type]){
this.$clipboardCopy(this[type])
}
},
resize(height){
this.outputHeight = (height - 20)/5
}
},
data() {
......@@ -57,10 +86,9 @@ export default {
current: {
input: "",
isUppercase: false,
output: "",
operation: ""
},
type: ['md5', 'sha1', 'sha256', 'sha512', "sm3"]
types: ['md5', 'sha1', 'sha256', 'sha512', "sm3"],
outputHeight:100
}
},
}
......
/**
* @link https://github.com/leizelong/binary
*/
function toFixed(d = '', length = 32, symbol = 0) {
if (d.length < length) {
return symbol + '0'.repeat(length - 1 - d.length) + d;
}
return d;
}
class Binary {
constructor(length) {
this.length = length;
}
getBinary(d) {
return Math.abs(parseInt(d)).toString(2);
}
// 原码
trueForm(d) {
const two = this.getBinary(d);
if (d >= 0) {
return toFixed(two, this.length, 0);
}
return toFixed(two, this.length, 1);
}
// 反码
inverse(d) {
const trueForm = this.trueForm(d);
if (d >= 0) {
return trueForm;
}
let data = '';
// eslint-disable-next-line no-plusplus
for (let index = 0; index < this.length; index++) {
const item = trueForm[index];
if (index === 0) {
data += item;
} else {
data += Math.abs(+item - 1);
}
}
return data;
}
// 补码
complement(d) {
const trueForm = this.trueForm(d);
const inverse = this.inverse(d);
if (d >= 0) {
return trueForm;
}
const valid = inverse.slice(1);
const validTenComplete = parseInt(valid, 2) + 1;
return toFixed(
validTenComplete.toString(2),
this.length,
1
);
}
}
export default (input, length, type) => {
if (!["trueForm", "inverse", "complement"].includes(type)) {
throw new Error("type error")
}
if (![8, 16, 32].includes(length)) {
throw new Error("length error")
}
// 0 特殊处理
if (
input === "0"
|| input === "+0"
|| input === "-0"
) {
if (type === "trueForm") {
return input === "-0" ? ("1" + Array(length).join("0")).slice(0, length - 1) : Array(length).join("0")
}
if (type === "inverse") {
return input === "-0" ? Array(length).join("1") : Array(length).join("0")
}
if (type === "complement") {
return input === "-0" ? Array(length).join("0") : Array(length).join("0")
}
return "";
}
input = parseInt(input);
switch (length) {
case 8:
if (!(input >= -128 && input <= 127)) {
throw new Error('length:8 input:-128 ~ 127')
}
break;
case 16:
if (!(input >= -32768 && input <= 32767)) {
throw new Error('length:16 input:-32768 ~ 32767')
}
break;
case 32:
if (!(input >= -2147483648 && input <= 2147483647)) {
throw new Error('length:32 input:-2147483648 ~ 2147483647')
}
break;
default:
throw new Error('length error')
}
let handle = (new Binary(length))
switch (type) {
case "trueForm":
return handle.trueForm(input)
case "inverse":
return handle.inverse(input)
case "complement":
return handle.complement(input)
}
}
<template>
<div>
<Tabs v-model="current.operation">
<TabPane label="二维码生成" name="generate">
<TabPane :label="$t('qrCode_generate_title')" name="generate">
<Row :gutter="16">
<Col span="14">
<Input v-model="current.generateInput" :rows="14" type="textarea" placeholder="内容"></Input>
<option-block>
<FormItem>
<Button type="primary" @click="generate()">生成</Button>
</FormItem>
</option-block>
<heightResize :reduce="52">
<autoHeightTextarea v-model="current.generateInput" :placeholder="$t('qrCode_generate_input')" />
</heightResize>
</Col>
<Col span="10">
<div style="text-align: center" v-html="current.generateOutput"></div>
<heightResize :reduce="52">
<div class="tool-qrcode-block" v-if="generateOutput">
<img v-if="generateOutput.startsWith('data:')" @click="()=>$clipboardCopyImages(generateOutput)" style="width:70%;min-width:300px;cursor:pointer;" :src="generateOutput" />
<p v-else>{{ generateOutput }}</p>
</div>
</heightResize>
</Col>
</Row>
</TabPane>
<TabPane label="二维码解析" name="reader">
<TabPane :label="$t('qrCode_reader_title')" name="reader">
<Row :gutter="16">
<Col span="14">
<Input v-model="current.readerInput" :rows="5" type="textarea" placeholder="请输入二维码图片地址或点击下方按钮上传图片"></Input>
<option-block>
<FormItem>
<Button type="primary" @click="reader()">解析</Button>
</FormItem>
<FormItem>
<Upload action="#" :before-upload="handleUpload">
<Button icon="ios-cloud-upload-outline">上传图片</Button>
<input-block style="margin-bottom: 10px" bottom="0px" right="10px" class="tool-reader-input">
<pasteClipboardFlie @on-paste-image="handleUpload">
<Input v-model="current.readerInput" :rows="5" type="textarea" :placeholder="$t('qrCode_reader_input')"></Input>
</pasteClipboardFlie>
<Upload slot="extra" action="#" :before-upload="handleUpload">
<Button size="small" type="primary" icon="ios-cloud-upload-outline">{{ $t('qrCode_reader_upload') }}</Button>
</Upload>
</FormItem>
</option-block>
<Input v-model="current.readerOutput" :rows="5" type="textarea" placeholder="解析结果"></Input>
</input-block>
<heightResize :reduce="52" :append="['.tool-reader-input']">
<autoHeightTextarea :value="readerOutput" :placeholder="$t('qrCode_reader_output')" />
</heightResize>
</Col>
<Col span="10" >
<heightResize :reduce="52">
<div class="tool-qrcode-block" v-html="readerInputImg"></div>
</heightResize>
</Col>
<Col span="10" style="text-align: center" v-html="readerInputImg"></Col>
</Row>
</TabPane>
</Tabs>
</div>
</template>
<script>
import generator from 'qrcode'
import qrcodeParser from 'qrcode-parser'
import model from '../../tool/model'
import generator from 'qrcode'
import qrcodeParser from 'qrcode-parser'
import model from '../../tool/model'
import Jimp from 'jimp';
import pasteClipboardFlie from './components/pasteClipboardFlie';
import heightResize from "./components/heightResize";
import autoHeightTextarea from "./components/autoHeightTextarea";
export default {
export default {
components: {
pasteClipboardFlie,
heightResize,
autoHeightTextarea
},
computed: {
readerInputImg () {
readerInputImg() {
if (this.current.readerInput) {
return `<img style="width:300px" src="${this.current.readerInput}" />`
return `<img style="width:70%;min-width:300px;" src="${this.current.readerInput}" />`
}
return ''
}
},
watch: {
"current.generateInput"() {
this.generate()
},
"current.readerInput"() {
this.reader()
}
},
created () {
created() {
let feature = model.getToolCurrentFeature('generate')
if(feature === 'generate'){
this.current = Object.assign(this.current, this.$getToolData('generateInput'))
if (feature === 'generate') {
this.current.operation = feature;
}
else if(feature === 'reader'){
this.current = Object.assign(this.current, this.$getToolData('readerInput'))
this.$initToolData('generateInput')
} else if (feature === 'reader') {
this.current.operation = feature;
}
else{
this.current = Object.assign(this.current, this.$getToolData())
this.$initToolData('readerInput')
} else {
this.$initToolData()
}
},
methods: {
generate () {
if (!this.current.generateInput) return
this.generateHandle(this.current.generateInput)
generate() {
if (!this.current.generateInput) {
this.generateOutput = "";
return;
}
generator.toDataURL(this.current.generateInput, (error, url) => {
if (error) {
this.generateOutput = this.$t("qrCode_generate_error", [error]);
return;
}
this.generateOutput = url
this.$saveToolData(this.current)
})
},
reader () {
reader() {
if (!this.current.readerInput) {
this.readerOutput = "";
return
}
qrcodeParser(this.current.readerInput).then((c) => {
this.current.readerOutput = c.data
this.getReaderImagePngBase64(this.current.readerInput).then((result) => {
this.readerOutput = result
this.$saveToolData(this.current)
this.$Message.success('解析成功')
}).catch(() => {
return this.$Message.error('图片解析错误')
}).catch(e => {
this.readerOutput = this.$t('qrCode_reader_error', [e.message])
})
},
generateHandle (str) {
generator.toDataURL(str, (error, url) => {
if (error) return this.$Message.error('二维码生成错误:' + error)
this.$clipboardCopyImages(url)
this.current.generateOutput = `<img style="width:300px" src="${url}" />`
getReaderImagePngBase64(input) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', input);
xhr.responseType = 'blob';
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 300) {
let blob = xhr.response;
const myReader = new FileReader();
myReader.readAsArrayBuffer(blob);
myReader.addEventListener('loadend', e => {
const buffer = e.target.result;
try {
Jimp.read(buffer, (err, image) => {
if (err) {
return reject(err);
}
image.getBase64Async("image/png").then((img) => {
return qrcodeParser(img)
}).then((c) => {
resolve(c.data)
}).catch((e) => {
reject(e);
})
});
} catch (e) {
reject(e);
}
});
} else {
reject(new Error(this.$t('qrCode_reader_parsing_failure').toString()));
}
};
xhr.onerror = () => reject(new Error(this.$t('qrCode_reader_parsing_failure').toString()));
xhr.send();
})
},
handleUpload (file) {
handleUpload(file) {
if (this.current.operation !== "reader"){
return;
}
let r = new FileReader()
r.readAsDataURL(file)
r.onloadend = () => {
this.current.readerInput = r.result
this.reader()
}
return false
}
},
substr (str) {
str = str.replace(/[\r\n]/g, '').trim()
const strLength = 100
return str.length > strLength ? str.substr(0, strLength) + '...' : str
},
},
data () {
data() {
return {
readerOutput: "",
generateOutput: "",
current: {
generateInput: '',
generateOutput: '',
readerInput: '',
readerOutput: '',
operation: 'generate',
},
}
},
}
}
</script>
<style>
.tool-qrcode-block {
height: 100%;
display: flex;
display: -webkit-flex;
align-items: center;
justify-content: center;
}
</style>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册