233 lines
4.6 KiB
Vue
233 lines
4.6 KiB
Vue
|
<template>
|
|||
|
<div class="tool-detail-page">
|
|||
|
|
|||
|
<!-- 设置 -->
|
|||
|
<n-card size="small" title="设置">
|
|||
|
<n-flex>
|
|||
|
<!-- 缩进空格 -->
|
|||
|
<div class="config-item">
|
|||
|
<div class="config-item__label">缩进空格:</div>
|
|||
|
<div class="config-item__content">
|
|||
|
<n-input-number
|
|||
|
v-model:value="data.indentSize"
|
|||
|
:min="0"
|
|||
|
:max="8"
|
|||
|
:precision="0"
|
|||
|
:step="1"
|
|||
|
></n-input-number>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<!-- 排序属性 -->
|
|||
|
<div class="config-item">
|
|||
|
<div class="config-item__label">排序属性:</div>
|
|||
|
<div class="config-item__content">
|
|||
|
<n-switch v-model:value="data.enabledSort" />
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</n-flex>
|
|||
|
</n-card>
|
|||
|
|
|||
|
<!-- 操作 -->
|
|||
|
<n-card size="small" title="操作">
|
|||
|
<n-flex>
|
|||
|
<n-button
|
|||
|
type="primary"
|
|||
|
:disabled="!data.jsonInput"
|
|||
|
@click="formatJson"
|
|||
|
>格式化</n-button>
|
|||
|
<n-button
|
|||
|
type="primary"
|
|||
|
:disabled="!data.jsonOutput"
|
|||
|
@click="copyOutputs"
|
|||
|
>复制结果</n-button>
|
|||
|
<n-button
|
|||
|
type="error"
|
|||
|
:disabled="!data.jsonInput"
|
|||
|
@click="clearInputs"
|
|||
|
>清空输入</n-button>
|
|||
|
<n-button
|
|||
|
type="error"
|
|||
|
:disabled="!data.jsonOutput"
|
|||
|
@click="clearOutputs"
|
|||
|
>清空输出</n-button>
|
|||
|
</n-flex>
|
|||
|
</n-card>
|
|||
|
|
|||
|
<!-- 输入内容 -->
|
|||
|
<n-card size="small" title="输入内容">
|
|||
|
<n-input
|
|||
|
v-model:value="data.jsonInput"
|
|||
|
class="json-input"
|
|||
|
placeholder="请输入 JSON 字符串"
|
|||
|
type="textarea"
|
|||
|
:rows="8"
|
|||
|
@contextmenu.stop
|
|||
|
></n-input>
|
|||
|
</n-card>
|
|||
|
|
|||
|
<!-- 输出内容 -->
|
|||
|
<n-card size="small" title="输出内容">
|
|||
|
<n-code
|
|||
|
class="json-output"
|
|||
|
language="json"
|
|||
|
:code="data.jsonOutput"
|
|||
|
:show-line-numbers="true"
|
|||
|
@contextmenu.stop
|
|||
|
/>
|
|||
|
</n-card>
|
|||
|
|
|||
|
</div>
|
|||
|
</template>
|
|||
|
|
|||
|
<script setup>
|
|||
|
import {
|
|||
|
NButton, NCard, NCode, NFlex,
|
|||
|
NInput, NInputNumber, NSwitch,
|
|||
|
} from 'naive-ui';
|
|||
|
|
|||
|
import {
|
|||
|
reactive,
|
|||
|
} from 'vue';
|
|||
|
|
|||
|
import {
|
|||
|
compareString, isArray, isObject,
|
|||
|
} from '@frost-utils/javascript/common/index';
|
|||
|
|
|||
|
import {
|
|||
|
useClipboard,
|
|||
|
} from '@vueuse/core';
|
|||
|
|
|||
|
import {
|
|||
|
$message, $notification,
|
|||
|
} from '@/assets/js/naive-ui';
|
|||
|
|
|||
|
/** 剪贴板 */
|
|||
|
const clipboard = useClipboard({
|
|||
|
legacy: true,
|
|||
|
read: false,
|
|||
|
});
|
|||
|
|
|||
|
/** 数据 */
|
|||
|
const data = reactive({
|
|||
|
|
|||
|
/** 启用排序 */
|
|||
|
enabledSort: true,
|
|||
|
|
|||
|
/** 缩进空格 */
|
|||
|
indentSize: 2,
|
|||
|
|
|||
|
/** 输入内容 */
|
|||
|
jsonInput: '',
|
|||
|
|
|||
|
/** 输出内容 */
|
|||
|
jsonOutput: '',
|
|||
|
|
|||
|
});
|
|||
|
|
|||
|
/** 清空输入内容 */
|
|||
|
function clearInputs() {
|
|||
|
data.jsonInput = '';
|
|||
|
}
|
|||
|
|
|||
|
/** 清空输出内容 */
|
|||
|
function clearOutputs() {
|
|||
|
data.jsonOutput = '';
|
|||
|
}
|
|||
|
|
|||
|
/** 复制格式化结果 */
|
|||
|
function copyOutputs() {
|
|||
|
if (clipboard.isSupported) {
|
|||
|
return clipboard.copy(data.jsonOutput).then(() => {
|
|||
|
$message.success('复制成功');
|
|||
|
}).catch((error) => {
|
|||
|
console.error('复制失败:');
|
|||
|
console.error(error);
|
|||
|
$message.error('复制失败:异常');
|
|||
|
});
|
|||
|
} else {
|
|||
|
$message.error('复制失败:当前浏览器不支持该操作');
|
|||
|
return Promise.resolve();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/** 格式化输入的 JSON */
|
|||
|
function formatJson() {
|
|||
|
try {
|
|||
|
|
|||
|
let obj = JSON.parse(data.jsonInput);
|
|||
|
|
|||
|
// 排序
|
|||
|
if (data.enabledSort) {
|
|||
|
obj = sortObjectKeys(obj);
|
|||
|
}
|
|||
|
|
|||
|
data.jsonOutput = JSON.stringify(obj, null, data.indentSize);
|
|||
|
|
|||
|
} catch (error) {
|
|||
|
console.warn('格式化 JSON 失败:');
|
|||
|
console.warn(error);
|
|||
|
$notification.create({
|
|||
|
content: String(error),
|
|||
|
duration: 0,
|
|||
|
title: '格式化 JSON 失败',
|
|||
|
type: 'error',
|
|||
|
});
|
|||
|
data.jsonOutput = '';
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/** 排序对象的 key */
|
|||
|
function sortObjectKeys(obj) {
|
|||
|
|
|||
|
// 非对象直接返回
|
|||
|
if (!isArray(obj) && !isObject(obj)) {
|
|||
|
return obj;
|
|||
|
}
|
|||
|
|
|||
|
// 处理数组,递归处理每个元素
|
|||
|
if (isArray(obj)) {
|
|||
|
return obj.map((item) => sortObjectKeys(item));
|
|||
|
}
|
|||
|
|
|||
|
// 获取并排序 key
|
|||
|
let sortedKeys = Object.keys(obj).sort((a, b) => {
|
|||
|
return compareString(a, b);
|
|||
|
});
|
|||
|
|
|||
|
// 排序后的对象
|
|||
|
let sortedObj = {};
|
|||
|
|
|||
|
// 按顺序获取值 & 递归处理
|
|||
|
for (let key of sortedKeys) {
|
|||
|
sortedObj[key] = sortObjectKeys(obj[key]);
|
|||
|
}
|
|||
|
|
|||
|
return sortedObj;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
</script>
|
|||
|
|
|||
|
<style lang="less" scoped>
|
|||
|
.config-item {
|
|||
|
display: flex;
|
|||
|
align-items: center;
|
|||
|
|
|||
|
.n-input-number {
|
|||
|
width: 128px;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
.json-input {
|
|||
|
font-family: monospace;
|
|||
|
}
|
|||
|
|
|||
|
.json-output {
|
|||
|
user-select: text;
|
|||
|
|
|||
|
:deep(pre) {
|
|||
|
overflow-x: auto;
|
|||
|
}
|
|||
|
}
|
|||
|
</style>
|