mirror of
https://github.com/fofolee/uTools-quickcommand.git
synced 2025-09-24 04:53:31 +08:00
可视化编排添加文本处理,添加堆成和非对称加解密
This commit is contained in:
@@ -163,16 +163,23 @@ export default defineComponent({
|
||||
|
||||
/* 布局更加紧凑 */
|
||||
/* 输入框高度及字体 */
|
||||
.command-composer :deep(.q-field--filled .q-field__control),
|
||||
.command-composer :deep(.q-field--filled .q-field__control > *),
|
||||
.command-composer :deep(.q-field--filled:not(.q-textarea) .q-field__control),
|
||||
.command-composer
|
||||
:deep(.q-field--filled:not(.q-field--labeled) .q-field__native) {
|
||||
border-radius: 5px;
|
||||
font-size: 12px;
|
||||
:deep(.q-field--filled:not(.q-textarea) .q-field__control > *),
|
||||
.command-composer
|
||||
:deep(.q-field--filled:not(.q-field--labeled):not(.q-textarea)
|
||||
.q-field__native) {
|
||||
max-height: 36px !important;
|
||||
min-height: 36px !important;
|
||||
}
|
||||
|
||||
.command-composer :deep(.q-field--filled .q-field__control),
|
||||
.command-composer :deep(.q-field--filled .q-field__control > *),
|
||||
.command-composer :deep(.q-field--filled .q-field__native) {
|
||||
border-radius: 5px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* 输入框图标大小 */
|
||||
.command-composer :deep(.q-field--filled .q-field__control .q-icon) {
|
||||
font-size: 18px;
|
||||
|
@@ -130,6 +130,8 @@ import KeyEditor from "./KeyEditor.vue";
|
||||
import UBrowserEditor from "./ubrowser/UBrowserEditor.vue";
|
||||
import VariableInput from "./VariableInput.vue";
|
||||
import AxiosConfigEditor from "./http/AxiosConfigEditor.vue";
|
||||
import SymmetricCryptoEditor from "./crypto/SymmetricCryptoEditor.vue";
|
||||
import AsymmetricCryptoEditor from "./crypto/AsymmetricCryptoEditor.vue";
|
||||
import { validateVariableName } from "js/common/variableValidator";
|
||||
|
||||
export default defineComponent({
|
||||
@@ -139,6 +141,8 @@ export default defineComponent({
|
||||
UBrowserEditor,
|
||||
VariableInput,
|
||||
AxiosConfigEditor,
|
||||
SymmetricCryptoEditor,
|
||||
AsymmetricCryptoEditor,
|
||||
},
|
||||
props: {
|
||||
command: {
|
||||
@@ -351,7 +355,7 @@ export default defineComponent({
|
||||
|
||||
.command-item:hover {
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
transform: translateY(-1px);
|
||||
/* transform: translateY(-1px); */
|
||||
}
|
||||
|
||||
.composer-card :deep(.q-field__label) {
|
||||
|
398
src/components/editor/composer/crypto/AsymmetricCryptoEditor.vue
Normal file
398
src/components/editor/composer/crypto/AsymmetricCryptoEditor.vue
Normal file
@@ -0,0 +1,398 @@
|
||||
<template>
|
||||
<div class="asymmetric-crypto-editor">
|
||||
<!-- 加密/解密切换 -->
|
||||
<q-btn-toggle
|
||||
v-model="operation"
|
||||
:options="[
|
||||
{ label: '加密', value: 'encrypt' },
|
||||
{ label: '解密', value: 'decrypt' },
|
||||
]"
|
||||
spread
|
||||
dense
|
||||
no-caps
|
||||
unelevated
|
||||
toggle-color="primary"
|
||||
/>
|
||||
|
||||
<!-- 文本输入 -->
|
||||
<div class="row">
|
||||
<VariableInput
|
||||
v-model="text"
|
||||
:label="operation === 'encrypt' ? '要加密的文本' : '要解密的文本'"
|
||||
:command="{
|
||||
icon:
|
||||
operation === 'encrypt' ? 'enhanced_encryption' : 'no_encryption',
|
||||
}"
|
||||
class="col-12"
|
||||
@update:model-value="updateConfig"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- 算法选择 -->
|
||||
<q-select
|
||||
v-model="algorithm"
|
||||
:options="algorithms"
|
||||
label="加密算法"
|
||||
dense
|
||||
filled
|
||||
class="col-grow"
|
||||
emit-value
|
||||
map-options
|
||||
/>
|
||||
<!-- RSA填充选择 -->
|
||||
<q-select
|
||||
v-if="algorithm === 'RSA'"
|
||||
v-model="padding"
|
||||
:options="paddings"
|
||||
label="填充方式"
|
||||
dense
|
||||
filled
|
||||
class="col-grow"
|
||||
emit-value
|
||||
map-options
|
||||
/>
|
||||
<!-- SM2密文格式选择 -->
|
||||
<q-select
|
||||
v-if="algorithm === 'SM2'"
|
||||
v-model="cipherMode"
|
||||
:options="[
|
||||
{ label: 'C1C3C2', value: 1 },
|
||||
{ label: 'C1C2C3', value: 0 },
|
||||
]"
|
||||
label="密文格式"
|
||||
dense
|
||||
filled
|
||||
class="col-grow"
|
||||
emit-value
|
||||
map-options
|
||||
/>
|
||||
<!-- 格式选择 -->
|
||||
<q-select
|
||||
v-model="format"
|
||||
:options="operation === 'encrypt' ? outputFormats : inputFormats"
|
||||
:label="operation === 'encrypt' ? '输出格式' : '输入格式'"
|
||||
dense
|
||||
filled
|
||||
class="col-grow"
|
||||
emit-value
|
||||
map-options
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- 密钥输入区域 -->
|
||||
<div class="col-6 key-input">
|
||||
<div class="key-wrapper">
|
||||
<q-input
|
||||
v-model="publicKey"
|
||||
type="textarea"
|
||||
filled
|
||||
autogrow
|
||||
label="公钥"
|
||||
class="key-textarea"
|
||||
@update:model-value="updateConfig"
|
||||
/>
|
||||
<q-btn-dropdown
|
||||
flat
|
||||
dense
|
||||
:label="publicKeyCodec"
|
||||
class="codec-dropdown"
|
||||
>
|
||||
<q-list>
|
||||
<q-item
|
||||
v-for="codec in keyCodecs"
|
||||
:key="codec.value"
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="publicKeyCodec = codec.value"
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label>{{ codec.label }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-btn-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 key-input">
|
||||
<div class="key-wrapper">
|
||||
<q-input
|
||||
v-model="privateKey"
|
||||
type="textarea"
|
||||
filled
|
||||
autogrow
|
||||
label="私钥"
|
||||
class="key-textarea"
|
||||
@update:model-value="updateConfig"
|
||||
/>
|
||||
<q-btn-dropdown
|
||||
flat
|
||||
dense
|
||||
:label="privateKeyCodec"
|
||||
class="codec-dropdown"
|
||||
>
|
||||
<q-list>
|
||||
<q-item
|
||||
v-for="codec in keyCodecs"
|
||||
:key="codec.value"
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="privateKeyCodec = codec.value"
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label>{{ codec.label }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-btn-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from "vue";
|
||||
import VariableInput from "../VariableInput.vue";
|
||||
import { formatJsonVariables } from "js/composer/formatString";
|
||||
|
||||
export default defineComponent({
|
||||
name: "AsymmetricCryptoEditor",
|
||||
components: {
|
||||
VariableInput,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
operation: "encrypt",
|
||||
text: "",
|
||||
algorithm: "RSA",
|
||||
padding: "RSAES-PKCS1-V1_5",
|
||||
cipherMode: 1,
|
||||
publicKey: "",
|
||||
privateKey: "",
|
||||
publicKeyCodec: "Pem",
|
||||
privateKeyCodec: "Pem",
|
||||
format: "Base64",
|
||||
algorithms: [
|
||||
{ label: "RSA", value: "RSA" },
|
||||
{ label: "SM2", value: "SM2" },
|
||||
],
|
||||
paddings: [
|
||||
{ label: "PKCS#1 v1.5", value: "RSAES-PKCS1-V1_5" },
|
||||
{ label: "OAEP", value: "RSA-OAEP" },
|
||||
{ label: "OAEP/SHA-256", value: "RSA-OAEP-256" },
|
||||
],
|
||||
keyCodecs: [
|
||||
{ label: "PEM", value: "Pem" },
|
||||
{ label: "Base64", value: "Base64" },
|
||||
{ label: "Hex", value: "Hex" },
|
||||
],
|
||||
outputFormats: [
|
||||
{ label: "Base64", value: "Base64" },
|
||||
{ label: "Hex", value: "Hex" },
|
||||
],
|
||||
inputFormats: [
|
||||
{ label: "Base64", value: "Base64" },
|
||||
{ label: "Hex", value: "Hex" },
|
||||
],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
updateConfig() {
|
||||
const code = `quickcomposer.textProcessing.asymmetricCrypto(${formatJsonVariables(
|
||||
{
|
||||
text: this.text,
|
||||
algorithm: this.algorithm,
|
||||
operation: this.operation,
|
||||
format: this.format,
|
||||
publicKey: {
|
||||
key: this.publicKey,
|
||||
codec: this.publicKeyCodec,
|
||||
},
|
||||
privateKey: {
|
||||
key: this.privateKey,
|
||||
codec: this.privateKeyCodec,
|
||||
},
|
||||
padding: this.algorithm === "RSA" ? this.padding : undefined,
|
||||
cipherMode: this.algorithm === "SM2" ? this.cipherMode : undefined,
|
||||
},
|
||||
["text"]
|
||||
)})`;
|
||||
|
||||
this.$emit("update:model-value", code);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
operation() {
|
||||
this.format = "Base64";
|
||||
this.updateConfig();
|
||||
},
|
||||
algorithm() {
|
||||
if (this.algorithm === "RSA") {
|
||||
this.padding = "PKCS#1";
|
||||
} else {
|
||||
this.cipherMode = 1;
|
||||
}
|
||||
this.updateConfig();
|
||||
},
|
||||
// 监听所有可能改变的值
|
||||
text() {
|
||||
this.updateConfig();
|
||||
},
|
||||
padding() {
|
||||
this.updateConfig();
|
||||
},
|
||||
cipherMode() {
|
||||
this.updateConfig();
|
||||
},
|
||||
publicKey() {
|
||||
this.updateConfig();
|
||||
},
|
||||
privateKey() {
|
||||
this.updateConfig();
|
||||
},
|
||||
publicKeyCodec() {
|
||||
this.updateConfig();
|
||||
},
|
||||
privateKeyCodec() {
|
||||
this.updateConfig();
|
||||
},
|
||||
format() {
|
||||
this.updateConfig();
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.asymmetric-crypto-editor {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.col-grow {
|
||||
flex: 1 1 0;
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
/* 密钥输入区域样式 */
|
||||
.key-input {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
min-width: calc(50% - 8px);
|
||||
max-width: calc(50% - 8px);
|
||||
}
|
||||
|
||||
.key-wrapper {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.key-textarea {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 确保输入框占满容器 */
|
||||
.key-textarea :deep(.q-field) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* 确保文本区域占满输入框 */
|
||||
.key-textarea :deep(.q-field__native) {
|
||||
min-height: 120px;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
/* 编码选择下拉按钮样式 */
|
||||
.codec-dropdown {
|
||||
min-width: 45px;
|
||||
max-width: 45px;
|
||||
font-size: 10px;
|
||||
padding: 2px 4px;
|
||||
height: 20px;
|
||||
line-height: 16px;
|
||||
border-radius: 4px;
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
bottom: 8px;
|
||||
}
|
||||
|
||||
/* 下拉菜单项样式 */
|
||||
.codec-dropdown :deep(.q-btn-dropdown__arrow) {
|
||||
font-size: 10px;
|
||||
margin-left: 1px;
|
||||
}
|
||||
|
||||
.codec-dropdown :deep(.q-list) {
|
||||
min-width: 60px;
|
||||
background: white;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.codec-dropdown :deep(.q-item) {
|
||||
min-height: 24px;
|
||||
padding: 2px 6px;
|
||||
}
|
||||
|
||||
.codec-dropdown :deep(.q-item__label) {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.body--dark .codec-dropdown {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.body--dark .codec-dropdown :deep(.q-list) {
|
||||
background: #1d1d1d;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
/* 确保选择器行在空间不够时换行美观 */
|
||||
@media (max-width: 600px) {
|
||||
.col-grow {
|
||||
flex: 1 1 calc(50% - 8px);
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.key-input {
|
||||
min-width: 100%;
|
||||
max-width: 100%;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.q-btn-toggle {
|
||||
border: 1px solid rgba(0, 0, 0, 0.12);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.body--dark .q-btn-toggle {
|
||||
border-color: rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
|
||||
/* 确保下拉按钮内容垂直居中 */
|
||||
.codec-dropdown :deep(.q-btn__content) {
|
||||
min-height: unset;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* 调整下拉按钮的内容间距 */
|
||||
.codec-dropdown :deep(.q-btn__wrapper) {
|
||||
padding: 0 4px;
|
||||
min-height: unset;
|
||||
}
|
||||
</style>
|
432
src/components/editor/composer/crypto/SymmetricCryptoEditor.vue
Normal file
432
src/components/editor/composer/crypto/SymmetricCryptoEditor.vue
Normal file
@@ -0,0 +1,432 @@
|
||||
<template>
|
||||
<div class="symmetric-crypto-editor q-gutter-y-sm">
|
||||
<!-- 加密/解密切换 -->
|
||||
<q-btn-toggle
|
||||
v-model="operation"
|
||||
:options="[
|
||||
{ label: '加密', value: 'encrypt' },
|
||||
{ label: '解密', value: 'decrypt' },
|
||||
]"
|
||||
spread
|
||||
dense
|
||||
no-caps
|
||||
unelevated
|
||||
toggle-color="primary"
|
||||
/>
|
||||
|
||||
<!-- 文本输入 -->
|
||||
<div class="row">
|
||||
<VariableInput
|
||||
v-model="text"
|
||||
:label="operation === 'encrypt' ? '要加密的文本' : '要解密的文本'"
|
||||
:command="{
|
||||
icon:
|
||||
operation === 'encrypt' ? 'enhanced_encryption' : 'no_encryption',
|
||||
}"
|
||||
class="col-8"
|
||||
@update:model-value="updateConfig"
|
||||
/>
|
||||
<q-select
|
||||
v-model="format"
|
||||
:options="operation === 'encrypt' ? outputFormats : inputFormats"
|
||||
:label="operation === 'encrypt' ? '输出格式' : '输入格式'"
|
||||
dense
|
||||
filled
|
||||
class="col-4"
|
||||
emit-value
|
||||
map-options
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- 算法选择 -->
|
||||
<q-select
|
||||
v-model="algorithm"
|
||||
:options="algorithms"
|
||||
label="加密算法"
|
||||
dense
|
||||
filled
|
||||
class="col-select"
|
||||
emit-value
|
||||
map-options
|
||||
/>
|
||||
<!-- AES密钥长度选择 -->
|
||||
<q-select
|
||||
v-if="showKeyLength"
|
||||
v-model="keyLength"
|
||||
:options="[
|
||||
{ label: '128位', value: 128 },
|
||||
{ label: '192位', value: 192 },
|
||||
{ label: '256位', value: 256 },
|
||||
]"
|
||||
label="密钥长度"
|
||||
dense
|
||||
filled
|
||||
class="col-select"
|
||||
emit-value
|
||||
map-options
|
||||
/>
|
||||
<!-- 模式选择 -->
|
||||
<q-select
|
||||
v-model="mode"
|
||||
:options="modes"
|
||||
label="加密模式"
|
||||
dense
|
||||
filled
|
||||
class="col-select"
|
||||
emit-value
|
||||
map-options
|
||||
/>
|
||||
<!-- Padding选择 -->
|
||||
<q-select
|
||||
v-model="padding"
|
||||
:options="paddings"
|
||||
label="填充方式"
|
||||
dense
|
||||
filled
|
||||
class="col-select"
|
||||
emit-value
|
||||
map-options
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- 密钥输入区域 -->
|
||||
<div class="col-grow key-input">
|
||||
<div class="key-wrapper">
|
||||
<q-input
|
||||
v-model="key"
|
||||
filled
|
||||
label="密钥"
|
||||
class="key-input"
|
||||
@update:model-value="updateConfig"
|
||||
/>
|
||||
<q-btn-dropdown flat dense :label="keyCodec" class="codec-dropdown">
|
||||
<q-list>
|
||||
<q-item
|
||||
v-for="codec in keyCodecs"
|
||||
:key="codec.value"
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="keyCodec = codec.value"
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label>{{ codec.label }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-btn-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
<!-- IV输入区域 -->
|
||||
<div v-if="showIV" class="col-grow key-input">
|
||||
<div class="key-wrapper">
|
||||
<q-input
|
||||
v-model="iv"
|
||||
filled
|
||||
label="IV"
|
||||
class="key-input"
|
||||
@update:model-value="updateConfig"
|
||||
/>
|
||||
<q-btn-dropdown flat dense :label="ivCodec" class="codec-dropdown">
|
||||
<q-list>
|
||||
<q-item
|
||||
v-for="codec in keyCodecs"
|
||||
:key="codec.value"
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="ivCodec = codec.value"
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label>{{ codec.label }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-btn-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from "vue";
|
||||
import VariableInput from "../VariableInput.vue";
|
||||
import { formatJsonVariables } from "js/composer/formatString";
|
||||
|
||||
export default defineComponent({
|
||||
name: "SymmetricCryptoEditor",
|
||||
components: {
|
||||
VariableInput,
|
||||
},
|
||||
props: {
|
||||
modelValue: {
|
||||
type: [String, Object],
|
||||
default: "",
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
operation: "encrypt",
|
||||
text: "",
|
||||
algorithm: "AES",
|
||||
keyLength: 128,
|
||||
mode: "CBC",
|
||||
padding: "Pkcs7",
|
||||
key: "",
|
||||
keyCodec: "Utf8",
|
||||
iv: "",
|
||||
ivCodec: "Utf8",
|
||||
format: "Base64",
|
||||
keyCodecs: [
|
||||
{ label: "UTF-8", value: "Utf8" },
|
||||
{ label: "Base64", value: "Base64" },
|
||||
{ label: "Hex", value: "Hex" },
|
||||
],
|
||||
algorithms: [
|
||||
{ label: "AES", value: "AES" },
|
||||
{ label: "SM4", value: "SM4" },
|
||||
],
|
||||
outputFormats: [
|
||||
{ label: "Base64", value: "Base64" },
|
||||
{ label: "Hex", value: "Hex" },
|
||||
],
|
||||
inputFormats: [
|
||||
{ label: "Base64", value: "Base64" },
|
||||
{ label: "Hex", value: "Hex" },
|
||||
],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
modes() {
|
||||
// SM4 只支持 ECB/CBC
|
||||
if (this.algorithm === "SM4") {
|
||||
return [
|
||||
{ label: "ECB", value: "ECB" },
|
||||
{ label: "CBC", value: "CBC" },
|
||||
];
|
||||
}
|
||||
// AES/DES/3DES 支持更多模式
|
||||
return [
|
||||
{ label: "ECB", value: "ECB" },
|
||||
{ label: "CBC", value: "CBC" },
|
||||
{ label: "CFB", value: "CFB" },
|
||||
{ label: "OFB", value: "OFB" },
|
||||
{ label: "CTR", value: "CTR" },
|
||||
{ label: "GCM", value: "GCM" },
|
||||
];
|
||||
},
|
||||
paddings() {
|
||||
// SM4 支持的填充方式
|
||||
if (this.algorithm === "SM4") {
|
||||
return [
|
||||
{ label: "PKCS#7", value: "pkcs#7" },
|
||||
{ label: "None", value: "none" },
|
||||
];
|
||||
}
|
||||
// AES/DES/3DES 支持的填充方式
|
||||
return [
|
||||
{ label: "PKCS7", value: "Pkcs7" },
|
||||
{ label: "Zero Padding", value: "ZeroPadding" },
|
||||
{ label: "No Padding", value: "NoPadding" },
|
||||
{ label: "ISO-10126", value: "Iso10126" },
|
||||
{ label: "ANSI X.923", value: "AnsiX923" },
|
||||
{ label: "ISO-97971", value: "Iso97971" },
|
||||
];
|
||||
},
|
||||
showIV() {
|
||||
return this.mode !== "ECB";
|
||||
},
|
||||
showKeyLength() {
|
||||
return this.algorithm === "AES";
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
updateConfig() {
|
||||
const code = `quickcomposer.textProcessing.symmetricCrypto(${formatJsonVariables(
|
||||
{
|
||||
text: this.text,
|
||||
algorithm: this.algorithm,
|
||||
mode: this.mode,
|
||||
padding: this.padding,
|
||||
key: {
|
||||
value: this.key,
|
||||
codec: this.keyCodec,
|
||||
},
|
||||
keyLength: this.keyLength,
|
||||
operation: this.operation,
|
||||
format: this.format,
|
||||
iv:
|
||||
this.mode !== "ECB"
|
||||
? {
|
||||
value: this.iv,
|
||||
codec: this.ivCodec,
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
["text"]
|
||||
)})`;
|
||||
|
||||
this.$emit("update:model-value", code);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
operation() {
|
||||
// 切换操作时重置格式为默认值
|
||||
this.format = "Base64";
|
||||
this.updateConfig();
|
||||
},
|
||||
text() {
|
||||
this.updateConfig();
|
||||
},
|
||||
algorithm() {
|
||||
// 切换算法时重置模式和填充
|
||||
if (this.algorithm === "SM4") {
|
||||
this.mode = "ECB";
|
||||
this.padding = "pkcs#7";
|
||||
} else {
|
||||
this.mode = "CBC";
|
||||
this.padding = "Pkcs7";
|
||||
}
|
||||
this.updateConfig();
|
||||
},
|
||||
mode() {
|
||||
this.updateConfig();
|
||||
},
|
||||
padding() {
|
||||
this.updateConfig();
|
||||
},
|
||||
format() {
|
||||
this.updateConfig();
|
||||
},
|
||||
keyLength() {
|
||||
this.updateConfig();
|
||||
},
|
||||
key() {
|
||||
this.updateConfig();
|
||||
},
|
||||
iv() {
|
||||
this.updateConfig();
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.crypto-editor {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.col-select {
|
||||
flex: 1;
|
||||
min-width: 120px;
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
.col-grow {
|
||||
flex: 1 1 0;
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
/* 确保第一行的输入框和格式选择器的比例固定 */
|
||||
.row:first-of-type .col-8 {
|
||||
flex: 4;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.row:first-of-type .col-4 {
|
||||
flex: 1;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
/* 确保选择器行在空间不够时换行美观 */
|
||||
@media (max-width: 600px) {
|
||||
.col-select {
|
||||
flex: 1 1 calc(50% - 8px);
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
|
||||
.q-btn-toggle {
|
||||
border: 1px solid rgba(0, 0, 0, 0.12);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.body--dark .q-btn-toggle {
|
||||
border-color: rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
|
||||
.key-input {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.key-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 编码选择下拉按钮样式 */
|
||||
.codec-dropdown {
|
||||
min-width: 45px;
|
||||
max-width: 45px;
|
||||
font-size: 10px;
|
||||
padding: 2px 4px;
|
||||
height: 20px;
|
||||
line-height: 16px;
|
||||
border-radius: 4px;
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
bottom: 8px;
|
||||
}
|
||||
|
||||
/* 下拉菜单项样式 */
|
||||
.codec-dropdown :deep(.q-btn-dropdown__arrow) {
|
||||
font-size: 10px;
|
||||
margin-left: 1px;
|
||||
}
|
||||
|
||||
.codec-dropdown :deep(.q-list) {
|
||||
min-width: 60px;
|
||||
background: white;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.codec-dropdown :deep(.q-item) {
|
||||
min-height: 24px;
|
||||
padding: 2px 6px;
|
||||
}
|
||||
|
||||
.codec-dropdown :deep(.q-item__label) {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.body--dark .codec-dropdown {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.body--dark .codec-dropdown :deep(.q-list) {
|
||||
background: #1d1d1d;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
/* 确保下拉按钮内容垂直居中 */
|
||||
.codec-dropdown :deep(.q-btn__content) {
|
||||
min-height: unset;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* 调整下拉按钮的内容间距 */
|
||||
.codec-dropdown :deep(.q-btn__wrapper) {
|
||||
padding: 0 4px;
|
||||
min-height: unset;
|
||||
}
|
||||
</style>
|
@@ -1,85 +0,0 @@
|
||||
export const encodeCommands = {
|
||||
label: "编码解码",
|
||||
icon: "code",
|
||||
defaultOpened: false,
|
||||
commands: [
|
||||
{
|
||||
value: "(text=>Buffer.from(text).toString('base64'))",
|
||||
label: "Base64编码",
|
||||
config: [
|
||||
{
|
||||
key: "text",
|
||||
label: "要编码的文本",
|
||||
type: "input",
|
||||
defaultValue: "",
|
||||
icon: "lock",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "(text=>Buffer.from(text,'base64').toString())",
|
||||
label: "Base64解码",
|
||||
config: [
|
||||
{
|
||||
key: "text",
|
||||
label: "要解码的Base64文本",
|
||||
type: "input",
|
||||
defaultValue: "",
|
||||
icon: "lock_open",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "(text=>Buffer.from(text).toString('hex'))",
|
||||
label: "十六进制编码",
|
||||
config: [
|
||||
{
|
||||
key: "text",
|
||||
label: "要编码的文本",
|
||||
type: "input",
|
||||
defaultValue: "",
|
||||
icon: "lock",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "(text=>Buffer.from(text,'hex').toString())",
|
||||
label: "十六进制解码",
|
||||
config: [
|
||||
{
|
||||
key: "text",
|
||||
label: "要解码的十六进制文本",
|
||||
type: "input",
|
||||
defaultValue: "",
|
||||
icon: "lock_open",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "encodeURIComponent",
|
||||
label: "URL编码",
|
||||
config: [
|
||||
{
|
||||
key: "text",
|
||||
label: "要编码的文本",
|
||||
type: "input",
|
||||
defaultValue: "",
|
||||
icon: "link",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "decodeURIComponent",
|
||||
label: "URL解码",
|
||||
config: [
|
||||
{
|
||||
key: "text",
|
||||
label: "要解码的URL编码文本",
|
||||
type: "input",
|
||||
defaultValue: "",
|
||||
icon: "link_off",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
@@ -2,7 +2,7 @@ import { fileCommands } from "./fileCommands";
|
||||
import { networkCommands } from "./networkCommands";
|
||||
import { systemCommands } from "./systemCommands";
|
||||
import { notifyCommands } from "./notifyCommands";
|
||||
import { encodeCommands } from "./encodeCommands";
|
||||
import { textProcessingCommands } from "./textProcessingCommands";
|
||||
import { otherCommands } from "./otherCommands";
|
||||
import { keyCommands } from "./keyCommands";
|
||||
|
||||
@@ -11,7 +11,7 @@ export const commandCategories = [
|
||||
networkCommands,
|
||||
systemCommands,
|
||||
notifyCommands,
|
||||
encodeCommands,
|
||||
textProcessingCommands,
|
||||
otherCommands,
|
||||
keyCommands,
|
||||
];
|
||||
|
249
src/js/composer/commands/textProcessingCommands.js
Normal file
249
src/js/composer/commands/textProcessingCommands.js
Normal file
@@ -0,0 +1,249 @@
|
||||
export const textProcessingCommands = {
|
||||
label: "文本处理",
|
||||
icon: "code",
|
||||
defaultOpened: false,
|
||||
commands: [
|
||||
{
|
||||
value: "quickcomposer.textProcessing.base64Encode",
|
||||
label: "Base64编码",
|
||||
config: [
|
||||
{
|
||||
key: "text",
|
||||
label: "要编码的文本",
|
||||
type: "input",
|
||||
defaultValue: "",
|
||||
icon: "lock",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.textProcessing.base64Decode",
|
||||
label: "Base64解码",
|
||||
config: [
|
||||
{
|
||||
key: "text",
|
||||
label: "要解码的Base64文本",
|
||||
type: "input",
|
||||
defaultValue: "",
|
||||
icon: "lock_open",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.textProcessing.hexEncode",
|
||||
label: "十六进制编码",
|
||||
config: [
|
||||
{
|
||||
key: "text",
|
||||
label: "要编码的文本",
|
||||
type: "input",
|
||||
defaultValue: "",
|
||||
icon: "lock",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.textProcessing.hexDecode",
|
||||
label: "十六进制解码",
|
||||
config: [
|
||||
{
|
||||
key: "text",
|
||||
label: "要解码的十六进制文本",
|
||||
type: "input",
|
||||
defaultValue: "",
|
||||
icon: "lock_open",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.textProcessing.urlEncode",
|
||||
label: "URL编码",
|
||||
config: [
|
||||
{
|
||||
key: "text",
|
||||
label: "要编码的文本",
|
||||
type: "input",
|
||||
defaultValue: "",
|
||||
icon: "link",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.textProcessing.urlDecode",
|
||||
label: "URL解码",
|
||||
config: [
|
||||
{
|
||||
key: "text",
|
||||
label: "要解码的URL编码文本",
|
||||
type: "input",
|
||||
defaultValue: "",
|
||||
icon: "link_off",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.textProcessing.htmlEncode",
|
||||
label: "HTML编码",
|
||||
config: [
|
||||
{
|
||||
key: "text",
|
||||
label: "要编码的文本",
|
||||
type: "input",
|
||||
defaultValue: "",
|
||||
icon: "code",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.textProcessing.htmlDecode",
|
||||
label: "HTML解码",
|
||||
config: [
|
||||
{
|
||||
key: "text",
|
||||
label: "要解码的HTML文本",
|
||||
type: "input",
|
||||
defaultValue: "",
|
||||
icon: "code_off",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.textProcessing.reverseString",
|
||||
label: "字符串反转",
|
||||
config: [
|
||||
{
|
||||
key: "text",
|
||||
label: "要反转的文本",
|
||||
type: "input",
|
||||
defaultValue: "",
|
||||
icon: "swap_horiz",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.textProcessing.replaceString",
|
||||
label: "字符串替换",
|
||||
config: [
|
||||
{
|
||||
key: "text",
|
||||
label: "原始文本",
|
||||
type: "input",
|
||||
defaultValue: "",
|
||||
icon: "text_fields",
|
||||
},
|
||||
{
|
||||
key: "oldStr",
|
||||
label: "要替换的文本",
|
||||
type: "input",
|
||||
defaultValue: "",
|
||||
icon: "find_replace",
|
||||
},
|
||||
{
|
||||
key: "newStr",
|
||||
label: "替换为",
|
||||
type: "input",
|
||||
defaultValue: "",
|
||||
icon: "text_fields",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.textProcessing.substring",
|
||||
label: "字符串截取",
|
||||
config: [
|
||||
{
|
||||
key: "text",
|
||||
label: "原始文本",
|
||||
type: "input",
|
||||
defaultValue: "",
|
||||
icon: "text_fields",
|
||||
},
|
||||
{
|
||||
key: "start",
|
||||
label: "起始位置",
|
||||
type: "input",
|
||||
inputType: "number",
|
||||
defaultValue: "0",
|
||||
icon: "first_page",
|
||||
},
|
||||
{
|
||||
key: "end",
|
||||
label: "结束位置",
|
||||
type: "input",
|
||||
inputType: "number",
|
||||
defaultValue: "",
|
||||
icon: "last_page",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.textProcessing.regexExtract",
|
||||
label: "正则提取",
|
||||
config: [
|
||||
{
|
||||
key: "text",
|
||||
label: "原始文本",
|
||||
type: "input",
|
||||
defaultValue: "",
|
||||
icon: "text_fields",
|
||||
},
|
||||
{
|
||||
key: "regex",
|
||||
label: "正则表达式",
|
||||
type: "input",
|
||||
defaultValue: "",
|
||||
icon: "regex",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.textProcessing.symmetricCrypto",
|
||||
label: "对称加解密",
|
||||
component: "SymmetricCryptoEditor",
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.textProcessing.asymmetricCrypto",
|
||||
label: "非对称加解密",
|
||||
component: "AsymmetricCryptoEditor",
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.textProcessing.md5Hash",
|
||||
label: "MD5哈希",
|
||||
config: [
|
||||
{
|
||||
key: "text",
|
||||
label: "要哈希的文本",
|
||||
type: "input",
|
||||
defaultValue: "",
|
||||
icon: "enhanced_encryption",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.textProcessing.sha256Hash",
|
||||
label: "SHA256哈希",
|
||||
config: [
|
||||
{
|
||||
key: "text",
|
||||
label: "要哈希的文本",
|
||||
type: "input",
|
||||
defaultValue: "",
|
||||
icon: "enhanced_encryption",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.textProcessing.sm3Hash",
|
||||
label: "SM3哈希",
|
||||
config: [
|
||||
{
|
||||
key: "text",
|
||||
label: "要哈希的文本",
|
||||
type: "input",
|
||||
defaultValue: "",
|
||||
icon: "enhanced_encryption",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
Reference in New Issue
Block a user