mirror of
https://github.com/fofolee/uTools-quickcommand.git
synced 2026-03-05 13:17:55 +08:00
拆分数据处理分类,新增编码加密、数学计算分类
This commit is contained in:
@@ -1,471 +0,0 @@
|
||||
<template>
|
||||
<div class="asymmetric-crypto-editor">
|
||||
<!-- 加密/解密切换 -->
|
||||
<div class="tabs-container">
|
||||
<q-tabs
|
||||
:model-value="argvs.operation"
|
||||
@update:model-value="updateArgvs('operation', $event)"
|
||||
dense
|
||||
class="text-grey"
|
||||
active-color="primary"
|
||||
indicator-color="primary"
|
||||
align="justify"
|
||||
narrow-indicator
|
||||
inline-label
|
||||
>
|
||||
<q-tab name="encrypt" no-caps>
|
||||
<div class="row items-center no-wrap">
|
||||
<q-icon name="enhanced_encryption" size="16px" />
|
||||
<div class="q-ml-xs">加密</div>
|
||||
</div>
|
||||
</q-tab>
|
||||
<q-tab name="decrypt" no-caps>
|
||||
<div class="row items-center no-wrap">
|
||||
<q-icon name="no_encryption" size="16px" />
|
||||
<div class="q-ml-xs">解密</div>
|
||||
</div>
|
||||
</q-tab>
|
||||
</q-tabs>
|
||||
<q-separator />
|
||||
</div>
|
||||
|
||||
<!-- 文本输入 -->
|
||||
<div class="row">
|
||||
<VariableInput
|
||||
:model-value="argvs.text"
|
||||
@update:model-value="updateArgvs('text', $event)"
|
||||
:label="argvs.operation === 'encrypt' ? '要加密的文本' : '要解密的文本'"
|
||||
:icon="argvs.operation === 'encrypt' ? 'text_fields' : 'password'"
|
||||
class="col-12"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- 算法选择 -->
|
||||
<q-select
|
||||
:model-value="argvs.algorithm"
|
||||
@update:model-value="updateArgvs('algorithm', $event)"
|
||||
:options="algorithms"
|
||||
label="加密算法"
|
||||
dense
|
||||
filled
|
||||
class="col-grow"
|
||||
emit-value
|
||||
map-options
|
||||
/>
|
||||
<!-- RSA填充选择 -->
|
||||
<q-select
|
||||
v-if="argvs.algorithm === 'RSA'"
|
||||
:model-value="argvs.padding"
|
||||
@update:model-value="updateArgvs('padding', $event)"
|
||||
:options="paddings"
|
||||
label="填充方式"
|
||||
dense
|
||||
filled
|
||||
class="col-grow"
|
||||
emit-value
|
||||
map-options
|
||||
/>
|
||||
<!-- SM2密文格式选择 -->
|
||||
<q-select
|
||||
v-if="argvs.algorithm === 'SM2'"
|
||||
:model-value="argvs.cipherMode"
|
||||
@update:model-value="updateArgvs('cipherMode', $event)"
|
||||
:options="[
|
||||
{ label: 'C1C3C2', value: 1 },
|
||||
{ label: 'C1C2C3', value: 0 },
|
||||
]"
|
||||
label="密文格式"
|
||||
dense
|
||||
filled
|
||||
class="col-grow"
|
||||
emit-value
|
||||
map-options
|
||||
/>
|
||||
<!-- 格式选择 -->
|
||||
<q-select
|
||||
:model-value="argvs.format"
|
||||
@update:model-value="updateArgvs('format', $event)"
|
||||
:options="argvs.operation === 'encrypt' ? outputFormats : inputFormats"
|
||||
:label="argvs.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
|
||||
:model-value="argvs.publicKey.key"
|
||||
@update:model-value="
|
||||
(key) => updateArgvs('publicKey', { ...argvs.publicKey, key })
|
||||
"
|
||||
type="textarea"
|
||||
filled
|
||||
autogrow
|
||||
label="公钥"
|
||||
class="key-textarea"
|
||||
/>
|
||||
<q-btn-dropdown
|
||||
flat
|
||||
dense
|
||||
:label="argvs.publicKey.codec"
|
||||
class="codec-dropdown"
|
||||
>
|
||||
<q-list>
|
||||
<q-item
|
||||
v-for="codec in keyCodecs"
|
||||
:key="codec.value"
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="
|
||||
updateArgvs('publicKey', {
|
||||
...argvs.publicKey,
|
||||
codec: 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
|
||||
:model-value="argvs.privateKey.key"
|
||||
@update:model-value="
|
||||
(key) => updateArgvs('privateKey', { ...argvs.privateKey, key })
|
||||
"
|
||||
type="textarea"
|
||||
filled
|
||||
autogrow
|
||||
label="私钥"
|
||||
class="key-textarea"
|
||||
/>
|
||||
<q-btn-dropdown
|
||||
flat
|
||||
dense
|
||||
:label="argvs.privateKey.codec"
|
||||
class="codec-dropdown"
|
||||
>
|
||||
<q-list>
|
||||
<q-item
|
||||
v-for="codec in keyCodecs"
|
||||
:key="codec.value"
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="
|
||||
updateArgvs('privateKey', {
|
||||
...argvs.privateKey,
|
||||
codec: 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 "components/composer/common/VariableInput.vue";
|
||||
import { stringifyArgv, parseFunction } from "js/composer/formatString";
|
||||
import { newVarInputVal } from "js/composer/varInputValManager";
|
||||
export default defineComponent({
|
||||
name: "AsymmetricCryptoEditor",
|
||||
components: {
|
||||
VariableInput,
|
||||
},
|
||||
props: {
|
||||
modelValue: Object,
|
||||
},
|
||||
emits: ["update:modelValue"],
|
||||
data() {
|
||||
return {
|
||||
defaultArgvs: {
|
||||
operation: "encrypt",
|
||||
text: newVarInputVal("str"),
|
||||
algorithm: "RSA",
|
||||
keyLength: 1024,
|
||||
padding: "RSAES-PKCS1-V1_5",
|
||||
cipherMode: 1,
|
||||
publicKey: {
|
||||
key: "",
|
||||
codec: "Pem",
|
||||
},
|
||||
privateKey: {
|
||||
key: "",
|
||||
codec: "Pem",
|
||||
},
|
||||
format: "Base64",
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
argvs() {
|
||||
return (
|
||||
this.modelValue.argvs || this.parseCodeToArgvs(this.modelValue.code)
|
||||
);
|
||||
},
|
||||
algorithms() {
|
||||
return [
|
||||
{ label: "RSA", value: "RSA" },
|
||||
{ label: "SM2", value: "SM2" },
|
||||
];
|
||||
},
|
||||
paddings() {
|
||||
return [
|
||||
{ label: "PKCS#1 v1.5", value: "RSAES-PKCS1-V1_5" },
|
||||
{ label: "OAEP", value: "RSA-OAEP" },
|
||||
{ label: "OAEP/SHA-256", value: "RSA-OAEP-256" },
|
||||
];
|
||||
},
|
||||
keyCodecs() {
|
||||
return [
|
||||
{ label: "PEM", value: "Pem" },
|
||||
{ label: "Base64", value: "Base64" },
|
||||
{ label: "Hex", value: "Hex" },
|
||||
];
|
||||
},
|
||||
outputFormats() {
|
||||
return [
|
||||
{ label: "Base64", value: "Base64" },
|
||||
{ label: "Hex", value: "Hex" },
|
||||
];
|
||||
},
|
||||
inputFormats() {
|
||||
return [
|
||||
{ label: "Base64", value: "Base64" },
|
||||
{ label: "Hex", value: "Hex" },
|
||||
];
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
parseCodeToArgvs(code) {
|
||||
const argvs = window.lodashM.cloneDeep(this.defaultArgvs);
|
||||
if (!code) return argvs;
|
||||
try {
|
||||
const variableFormatPaths = ["arg0.text"];
|
||||
const params = parseFunction(code, { variableFormatPaths });
|
||||
return params.argvs[0];
|
||||
} catch (e) {
|
||||
console.error("解析加密参数失败:", e);
|
||||
}
|
||||
return argvs;
|
||||
},
|
||||
generateCode(argvs = this.argvs) {
|
||||
return `${this.modelValue.value}(${stringifyArgv({
|
||||
text: argvs.text,
|
||||
algorithm: argvs.algorithm,
|
||||
operation: argvs.operation,
|
||||
format: argvs.format,
|
||||
publicKey: argvs.publicKey,
|
||||
privateKey: argvs.privateKey,
|
||||
padding: argvs.algorithm === "RSA" ? argvs.padding : undefined,
|
||||
cipherMode: argvs.algorithm === "SM2" ? argvs.cipherMode : undefined,
|
||||
})})`;
|
||||
},
|
||||
updateArgvs(key, value) {
|
||||
const argvs = { ...this.argvs, [key]: value };
|
||||
|
||||
// 特殊处理
|
||||
if (key === "operation") {
|
||||
argvs.format = "Base64";
|
||||
} else if (key === "algorithm") {
|
||||
if (value === "RSA") {
|
||||
argvs.padding = "PKCS#1";
|
||||
} else {
|
||||
argvs.cipherMode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
this.updateModelValue(argvs);
|
||||
},
|
||||
updateModelValue(argvs) {
|
||||
this.$emit("update:modelValue", {
|
||||
...this.modelValue,
|
||||
summary: this.getSummary(argvs),
|
||||
argvs,
|
||||
code: this.generateCode(argvs),
|
||||
});
|
||||
},
|
||||
getSummary(argvs) {
|
||||
const text = window.lodashM.truncate(argvs.text.value, {
|
||||
length: 30,
|
||||
omission: "...",
|
||||
});
|
||||
|
||||
return argvs.operation === "encrypt"
|
||||
? "加密" + " " + text
|
||||
: "解密" + " " + text;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// 只在没有 argvs 和 code 的情况下生成默认代码
|
||||
if (!this.modelValue.argvs && !this.modelValue.code) {
|
||||
this.updateModelValue(this.defaultArgvs);
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.asymmetric-crypto-editor {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.tabs-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tabs-container .q-tabs {
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
.tabs-container .q-tab {
|
||||
min-height: 32px;
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.tabs-container .q-tab__content {
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
.tabs-container .q-separator {
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 确保下拉按钮内容垂直居中 */
|
||||
.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,491 +0,0 @@
|
||||
<template>
|
||||
<div class="symmetric-crypto-editor">
|
||||
<!-- 加密/解密切换 -->
|
||||
<div class="tabs-container">
|
||||
<q-tabs
|
||||
:model-value="argvs.operation"
|
||||
@update:model-value="updateArgvs('operation', $event)"
|
||||
dense
|
||||
class="text-grey"
|
||||
active-color="primary"
|
||||
indicator-color="primary"
|
||||
align="justify"
|
||||
narrow-indicator
|
||||
inline-label
|
||||
>
|
||||
<q-tab name="encrypt" no-caps>
|
||||
<div class="row items-center no-wrap">
|
||||
<q-icon name="enhanced_encryption" size="16px" />
|
||||
<div class="q-ml-xs">加密</div>
|
||||
</div>
|
||||
</q-tab>
|
||||
<q-tab name="decrypt" no-caps>
|
||||
<div class="row items-center no-wrap">
|
||||
<q-icon name="no_encryption" size="16px" />
|
||||
<div class="q-ml-xs">解密</div>
|
||||
</div>
|
||||
</q-tab>
|
||||
</q-tabs>
|
||||
<q-separator />
|
||||
</div>
|
||||
|
||||
<!-- 文本输入 -->
|
||||
<div class="row q-mt-xs">
|
||||
<VariableInput
|
||||
:model-value="argvs.text"
|
||||
@update:model-value="updateArgvs('text', $event)"
|
||||
:label="argvs.operation === 'encrypt' ? '要加密的文本' : '要解密的文本'"
|
||||
:icon="argvs.operation === 'encrypt' ? 'text_fields' : 'password'"
|
||||
class="col-8"
|
||||
/>
|
||||
<q-select
|
||||
:model-value="argvs.format"
|
||||
@update:model-value="updateArgvs('format', $event)"
|
||||
:options="argvs.operation === 'encrypt' ? outputFormats : inputFormats"
|
||||
:label="argvs.operation === 'encrypt' ? '输出格式' : '输入格式'"
|
||||
dense
|
||||
filled
|
||||
class="col-4"
|
||||
emit-value
|
||||
map-options
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- 算法选择 -->
|
||||
<q-select
|
||||
:model-value="argvs.algorithm"
|
||||
@update:model-value="updateArgvs('algorithm', $event)"
|
||||
:options="algorithms"
|
||||
label="加密算法"
|
||||
dense
|
||||
filled
|
||||
class="col-select"
|
||||
emit-value
|
||||
map-options
|
||||
/>
|
||||
<!-- AES密钥长度选择 -->
|
||||
<q-select
|
||||
v-if="showKeyLength"
|
||||
:model-value="argvs.keyLength"
|
||||
@update:model-value="updateArgvs('keyLength', $event)"
|
||||
: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
|
||||
:model-value="argvs.mode"
|
||||
@update:model-value="updateArgvs('mode', $event)"
|
||||
:options="modes"
|
||||
label="加密模式"
|
||||
dense
|
||||
filled
|
||||
class="col-select"
|
||||
emit-value
|
||||
map-options
|
||||
/>
|
||||
<!-- Padding选择 -->
|
||||
<q-select
|
||||
:model-value="argvs.padding"
|
||||
@update:model-value="updateArgvs('padding', $event)"
|
||||
: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
|
||||
:model-value="argvs.key.value"
|
||||
@update:model-value="
|
||||
updateArgvs('key', { ...argvs.key, value: $event })
|
||||
"
|
||||
filled
|
||||
label="密钥"
|
||||
class="key-input"
|
||||
/>
|
||||
<q-btn-dropdown
|
||||
flat
|
||||
dense
|
||||
:label="argvs.key.codec"
|
||||
class="codec-dropdown"
|
||||
>
|
||||
<q-list>
|
||||
<q-item
|
||||
v-for="codec in keyCodecs"
|
||||
:key="codec.value"
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="
|
||||
updateArgvs('key', { ...argvs.key, codec: 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
|
||||
:model-value="argvs.iv.value"
|
||||
@update:model-value="
|
||||
updateArgvs('iv', { ...argvs.iv, value: $event })
|
||||
"
|
||||
filled
|
||||
label="IV"
|
||||
class="key-input"
|
||||
/>
|
||||
<q-btn-dropdown
|
||||
flat
|
||||
dense
|
||||
:label="argvs.iv.codec"
|
||||
class="codec-dropdown"
|
||||
>
|
||||
<q-list>
|
||||
<q-item
|
||||
v-for="codec in keyCodecs"
|
||||
:key="codec.value"
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="updateArgvs('iv', { ...argvs.iv, codec: 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 "components/composer/common/VariableInput.vue";
|
||||
import { stringifyArgv, parseFunction } from "js/composer/formatString";
|
||||
import { newVarInputVal } from "js/composer/varInputValManager";
|
||||
|
||||
export default defineComponent({
|
||||
name: "SymmetricCryptoEditor",
|
||||
components: {
|
||||
VariableInput,
|
||||
},
|
||||
props: {
|
||||
modelValue: Object,
|
||||
},
|
||||
emits: ["update:modelValue"],
|
||||
data() {
|
||||
return {
|
||||
defaultArgvs: {
|
||||
operation: "encrypt",
|
||||
text: newVarInputVal("str"),
|
||||
algorithm: "AES",
|
||||
keyLength: 128,
|
||||
mode: "CBC",
|
||||
padding: "Pkcs7",
|
||||
key: {
|
||||
value: "",
|
||||
codec: "Utf8",
|
||||
},
|
||||
iv: {
|
||||
value: "",
|
||||
codec: "Utf8",
|
||||
},
|
||||
format: "Base64",
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
argvs() {
|
||||
return (
|
||||
this.modelValue.argvs || this.parseCodeToArgvs(this.modelValue.code)
|
||||
);
|
||||
},
|
||||
keyCodecs() {
|
||||
return [
|
||||
{ label: "UTF-8", value: "Utf8" },
|
||||
{ label: "Base64", value: "Base64" },
|
||||
{ label: "Hex", value: "Hex" },
|
||||
];
|
||||
},
|
||||
algorithms() {
|
||||
return [
|
||||
{ label: "AES", value: "AES" },
|
||||
{ label: "SM4", value: "SM4" },
|
||||
];
|
||||
},
|
||||
outputFormats() {
|
||||
return [
|
||||
{ label: "Base64", value: "Base64" },
|
||||
{ label: "Hex", value: "Hex" },
|
||||
];
|
||||
},
|
||||
inputFormats() {
|
||||
return [
|
||||
{ label: "Base64", value: "Base64" },
|
||||
{ label: "Hex", value: "Hex" },
|
||||
];
|
||||
},
|
||||
modes() {
|
||||
if (this.argvs.algorithm === "SM4") {
|
||||
return [
|
||||
{ label: "ECB", value: "ECB" },
|
||||
{ label: "CBC", value: "CBC" },
|
||||
];
|
||||
}
|
||||
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() {
|
||||
if (this.argvs.algorithm === "SM4") {
|
||||
return [
|
||||
{ label: "PKCS#7", value: "pkcs#7" },
|
||||
{ label: "None", value: "none" },
|
||||
];
|
||||
}
|
||||
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.argvs.mode !== "ECB";
|
||||
},
|
||||
showKeyLength() {
|
||||
return this.argvs.algorithm === "AES";
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
generateCode(argvs = this.argvs) {
|
||||
return `${this.modelValue.value}(${stringifyArgv({
|
||||
text: argvs.text,
|
||||
algorithm: argvs.algorithm,
|
||||
mode: argvs.mode,
|
||||
padding: argvs.padding,
|
||||
key: argvs.key,
|
||||
keyLength: argvs.keyLength,
|
||||
operation: argvs.operation,
|
||||
format: argvs.format,
|
||||
iv: argvs.mode !== "ECB" ? argvs.iv : undefined,
|
||||
})})`;
|
||||
},
|
||||
updateArgvs(key, value) {
|
||||
const argvs = { ...this.argvs, [key]: value };
|
||||
|
||||
if (key === "operation") {
|
||||
argvs.format = "Base64";
|
||||
} else if (key === "algorithm") {
|
||||
if (value === "SM4") {
|
||||
argvs.mode = "ECB";
|
||||
argvs.padding = "pkcs#7";
|
||||
} else {
|
||||
argvs.mode = "CBC";
|
||||
argvs.padding = "Pkcs7";
|
||||
}
|
||||
}
|
||||
|
||||
this.updateModelValue(argvs);
|
||||
},
|
||||
parseCodeToArgvs(code) {
|
||||
const argvs = window.lodashM.cloneDeep(this.defaultArgvs);
|
||||
if (!code) return argvs;
|
||||
try {
|
||||
const variableFormatPaths = ["arg0.text"];
|
||||
const params = parseFunction(code, { variableFormatPaths });
|
||||
return params.argvs[0];
|
||||
} catch (e) {
|
||||
console.error("解析加密参数失败:", e);
|
||||
}
|
||||
return argvs;
|
||||
},
|
||||
getSummary(argvs) {
|
||||
const text = window.lodashM.truncate(argvs.text.value, {
|
||||
length: 30,
|
||||
omission: "...",
|
||||
});
|
||||
return argvs.operation === "encrypt"
|
||||
? "加密" + " " + text
|
||||
: "解密" + " " + text;
|
||||
},
|
||||
updateModelValue(argvs) {
|
||||
this.$emit("update:modelValue", {
|
||||
...this.modelValue,
|
||||
summary: this.getSummary(argvs),
|
||||
argvs,
|
||||
code: this.generateCode(argvs),
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (!this.modelValue.argvs && !this.modelValue.code) {
|
||||
this.updateModelValue(this.defaultArgvs);
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.symmetric-crypto-editor {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.tabs-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tabs-container .q-tabs {
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
.tabs-container .q-tab {
|
||||
min-height: 32px;
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.tabs-container .q-tab__content {
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
.tabs-container .q-separator {
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
||||
.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>
|
||||
Reference in New Issue
Block a user