mirror of
https://github.com/fofolee/uTools-quickcommand.git
synced 2025-06-28 11:52:46 +08:00
运行结果界面添加格式化按钮,将树状的对象格式为JSON字符串展示,添加转表格的按钮,将符合条件的对象转为表格字符串展示
This commit is contained in:
parent
601df1f1e3
commit
ab5f90ea51
@ -39,6 +39,7 @@
|
||||
:textbtn="!enableHtml"
|
||||
:imagebtn="!enableHtml && isDataUrl"
|
||||
@showImg="showBase64Img"
|
||||
@updateResult="runResult = $event"
|
||||
:style="{
|
||||
height: headerHeight + 'px',
|
||||
}"
|
||||
|
@ -22,7 +22,12 @@
|
||||
v-else-if="typeof item === 'undefined'"
|
||||
v-text="'undefined'"
|
||||
/>
|
||||
<pre class="result" v-text="item" v-else />
|
||||
<pre
|
||||
class="result"
|
||||
:class="{ wrapLine: !isTable }"
|
||||
v-text="item"
|
||||
v-else
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -78,6 +83,10 @@ export default {
|
||||
)
|
||||
: "";
|
||||
},
|
||||
// 判断是否是转为表格的结果,表格结果不需要换行,第二行一般包含分隔符---
|
||||
isTable() {
|
||||
return this.runResult?.[0]?.split("\n")?.[1]?.includes("---");
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.frameInit();
|
||||
@ -135,16 +144,22 @@ export default {
|
||||
.text {
|
||||
font-family: Consolas, Monaco, "Courier New";
|
||||
}
|
||||
|
||||
.result {
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.result.wrapLine {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.undefined {
|
||||
color: #999;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
iframe {
|
||||
width: 100%;
|
||||
display: block;
|
||||
|
@ -1,13 +1,32 @@
|
||||
<template>
|
||||
<q-btn-group :stretch="stretch" class="text-primary">
|
||||
<q-btn-group :stretch="stretch" class="text-primary result-menu">
|
||||
<q-btn
|
||||
icon="image"
|
||||
label="转为图片"
|
||||
label="转图片"
|
||||
@click="dataUrlToImg"
|
||||
v-show="imagebtn"
|
||||
dense
|
||||
size="sm"
|
||||
></q-btn>
|
||||
<q-btn
|
||||
icon="data_object"
|
||||
@click="updateStringifyResult"
|
||||
v-show="textbtn && hasObject"
|
||||
:label="!dense ? '格式化' : ''"
|
||||
dense
|
||||
size="sm"
|
||||
>
|
||||
<q-tooltip v-if="!dense">格式化JSON</q-tooltip>
|
||||
</q-btn>
|
||||
<q-btn
|
||||
icon="pivot_table_chart"
|
||||
@click="updateTableResult"
|
||||
v-show="textbtn && hasTable"
|
||||
:label="!dense ? '转表格' : ''"
|
||||
dense
|
||||
size="sm"
|
||||
>
|
||||
</q-btn>
|
||||
<q-btn
|
||||
icon="content_paste"
|
||||
@click="copyResult"
|
||||
@ -36,45 +55,180 @@ export default {
|
||||
closebtn: Boolean,
|
||||
runResult: Array,
|
||||
},
|
||||
emits: ["updateResult"],
|
||||
computed: {
|
||||
content() {
|
||||
return this.getContent();
|
||||
/**
|
||||
* 处理运行结果数据,同时完成以下任务:
|
||||
* 1. 查找符合表格显示条件的数组数据(数组元素都是对象)
|
||||
* 2. 格式化所有数据项(对象转JSON,处理null等特殊情况)
|
||||
*
|
||||
* @returns {Object} 处理后的数据对象
|
||||
* - items: 格式化后的所有数据项数组,每项包含:
|
||||
* - raw: 原始数据
|
||||
* - formatted: 格式化后的字符串
|
||||
* - tableData: 找到的第一个可转换为表格的数组,如果没有则为null
|
||||
*/
|
||||
processedData() {
|
||||
// 空数据处理
|
||||
if (!this.runResult) return { items: [], tableData: null };
|
||||
|
||||
let tableData = null;
|
||||
const items = this.runResult.map((item, index) => {
|
||||
// 1. 表格数据检测
|
||||
// 如果还没找到表格数据,且当前项是非空数组,则检查是否可以作为表格数据
|
||||
if (!tableData && Array.isArray(item) && item.length > 0) {
|
||||
// 检查数组的每个元素是否都是非null的普通对象(非数组)
|
||||
const isValidTable = item.every(
|
||||
(elem) =>
|
||||
typeof elem === "object" && elem !== null && !Array.isArray(elem)
|
||||
);
|
||||
// 如果是有效的表格数据,保存起来
|
||||
if (isValidTable) {
|
||||
tableData = item;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 数据格式化
|
||||
// 2.1 处理非对象类型:直接返回原值
|
||||
if (typeof item !== "object") {
|
||||
return { raw: item, formatted: item };
|
||||
}
|
||||
// 2.2 处理 null:转换为字符串 "null"
|
||||
if (item === null) {
|
||||
return { raw: null, formatted: "null" };
|
||||
}
|
||||
// 2.3 处理对象类型
|
||||
try {
|
||||
// 尝试将对象转换为格式化的JSON字符串
|
||||
return {
|
||||
raw: item,
|
||||
formatted: JSON.stringify(item, null, 2),
|
||||
};
|
||||
} catch (error) {
|
||||
// 如果JSON转换失败,则使用toString()方法
|
||||
return {
|
||||
raw: item,
|
||||
formatted: item.toString(),
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// 返回处理后的数据
|
||||
return { items, tableData };
|
||||
},
|
||||
formattedItems() {
|
||||
return this.processedData.items;
|
||||
},
|
||||
validTableData() {
|
||||
return this.processedData.tableData;
|
||||
},
|
||||
hasObject() {
|
||||
return this.formattedItems.some(
|
||||
(item) => typeof item.raw === "object" && item.raw !== null
|
||||
);
|
||||
},
|
||||
hasTable() {
|
||||
return this.validTableData !== null;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
copyResult() {
|
||||
window.utools.copyText(this.content);
|
||||
window.utools.copyText(this.getFormattedContent());
|
||||
quickcommand.showMessageBox("已复制到剪贴板");
|
||||
},
|
||||
sendResult() {
|
||||
window.utools.hideMainWindowTypeString(this.content);
|
||||
window.utools.hideMainWindowTypeString(this.getFormattedContent());
|
||||
},
|
||||
dataUrlToImg() {
|
||||
let imgs = this.content
|
||||
.match(/data:image\/.*?;base64,.*/g)
|
||||
const imagePattern = /data:image\/.*?;base64,.*/g;
|
||||
const imageUrls = this.getFormattedContent()
|
||||
.match(imagePattern)
|
||||
?.map((dataUrl) => `<img src="${dataUrl}"><br>`);
|
||||
if (!imgs) return quickcommand.showMessageBox("dataUrl 格式不正确!");
|
||||
this.$emit("showImg", imgs);
|
||||
|
||||
if (!imageUrls) {
|
||||
return quickcommand.showMessageBox("dataUrl 格式不正确!");
|
||||
}
|
||||
this.$emit("showImg", imageUrls);
|
||||
},
|
||||
saveResult() {
|
||||
window.saveFile(this.content, {
|
||||
const saveOptions = {
|
||||
defaultPath: "quickcommand-result.txt",
|
||||
filters: [{ name: "txt", extensions: ["txt"] }],
|
||||
});
|
||||
};
|
||||
window.saveFile(this.getFormattedContent(), saveOptions);
|
||||
},
|
||||
getContent() {
|
||||
let content = this.runResult.map((item) => {
|
||||
if (typeof item === "object") {
|
||||
try {
|
||||
return JSON.stringify(item, null, 2);
|
||||
} catch (e) {
|
||||
return item.toString();
|
||||
}
|
||||
}
|
||||
return item;
|
||||
getFormattedContent() {
|
||||
return this.formattedItems.map((item) => item.formatted).join("\n");
|
||||
},
|
||||
updateStringifyResult() {
|
||||
this.updateResult([this.getFormattedContent()]);
|
||||
},
|
||||
updateTableResult() {
|
||||
const tableData = this.validTableData;
|
||||
if (!tableData) return;
|
||||
|
||||
const headers = [
|
||||
...new Set(tableData.flatMap((obj) => Object.keys(obj))),
|
||||
];
|
||||
if (!headers.length) return;
|
||||
|
||||
// 计算每列的最大宽度
|
||||
const columnWidths = headers.map((header) => {
|
||||
const maxDataWidth = Math.max(
|
||||
header.length,
|
||||
...tableData.map((obj) => {
|
||||
const value = obj[header];
|
||||
return value === undefined || value === null
|
||||
? 0
|
||||
: String(value).replace(/\n/g, "\\n").length;
|
||||
})
|
||||
);
|
||||
return maxDataWidth;
|
||||
});
|
||||
return content.join("\n");
|
||||
|
||||
// 生成对齐的行
|
||||
const createAlignedRow = (cells) =>
|
||||
"| " +
|
||||
cells
|
||||
.map((cell, index) => {
|
||||
const padding = " ".repeat(
|
||||
Math.max(0, columnWidths[index] - String(cell).length)
|
||||
);
|
||||
return String(cell) + padding;
|
||||
})
|
||||
.join(" | ") +
|
||||
" |";
|
||||
|
||||
const rows = [
|
||||
// 表头行
|
||||
createAlignedRow(headers),
|
||||
// 分隔行
|
||||
"| " +
|
||||
headers.map((_, i) => "-".repeat(columnWidths[i])).join(" | ") +
|
||||
" |",
|
||||
// 数据行
|
||||
...tableData.map((obj) =>
|
||||
createAlignedRow(
|
||||
headers.map((header) => {
|
||||
const value = obj[header];
|
||||
return value === undefined || value === null
|
||||
? ""
|
||||
: String(value).replace(/\n/g, "\\n");
|
||||
})
|
||||
)
|
||||
),
|
||||
];
|
||||
|
||||
this.updateResult([rows.join("\n")]);
|
||||
},
|
||||
updateResult(result) {
|
||||
this.$emit("updateResult", result);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.result-menu {
|
||||
gap: 4px;
|
||||
}
|
||||
</style>
|
||||
|
Loading…
x
Reference in New Issue
Block a user