mirror of
https://github.com/fofolee/uTools-quickcommand.git
synced 2025-06-28 20:02:44 +08:00
运行结果界面添加格式化按钮,将树状的对象格式为JSON字符串展示,添加转表格的按钮,将符合条件的对象转为表格字符串展示
This commit is contained in:
parent
601df1f1e3
commit
ab5f90ea51
@ -39,6 +39,7 @@
|
|||||||
:textbtn="!enableHtml"
|
:textbtn="!enableHtml"
|
||||||
:imagebtn="!enableHtml && isDataUrl"
|
:imagebtn="!enableHtml && isDataUrl"
|
||||||
@showImg="showBase64Img"
|
@showImg="showBase64Img"
|
||||||
|
@updateResult="runResult = $event"
|
||||||
:style="{
|
:style="{
|
||||||
height: headerHeight + 'px',
|
height: headerHeight + 'px',
|
||||||
}"
|
}"
|
||||||
|
@ -22,7 +22,12 @@
|
|||||||
v-else-if="typeof item === 'undefined'"
|
v-else-if="typeof item === 'undefined'"
|
||||||
v-text="'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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -78,6 +83,10 @@ export default {
|
|||||||
)
|
)
|
||||||
: "";
|
: "";
|
||||||
},
|
},
|
||||||
|
// 判断是否是转为表格的结果,表格结果不需要换行,第二行一般包含分隔符---
|
||||||
|
isTable() {
|
||||||
|
return this.runResult?.[0]?.split("\n")?.[1]?.includes("---");
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.frameInit();
|
this.frameInit();
|
||||||
@ -135,16 +144,22 @@ export default {
|
|||||||
.text {
|
.text {
|
||||||
font-family: Consolas, Monaco, "Courier New";
|
font-family: Consolas, Monaco, "Courier New";
|
||||||
}
|
}
|
||||||
|
|
||||||
.result {
|
.result {
|
||||||
white-space: pre-wrap;
|
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.result.wrapLine {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
.undefined {
|
.undefined {
|
||||||
color: #999;
|
color: #999;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
iframe {
|
iframe {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -1,13 +1,32 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-btn-group :stretch="stretch" class="text-primary">
|
<q-btn-group :stretch="stretch" class="text-primary result-menu">
|
||||||
<q-btn
|
<q-btn
|
||||||
icon="image"
|
icon="image"
|
||||||
label="转为图片"
|
label="转图片"
|
||||||
@click="dataUrlToImg"
|
@click="dataUrlToImg"
|
||||||
v-show="imagebtn"
|
v-show="imagebtn"
|
||||||
dense
|
dense
|
||||||
size="sm"
|
size="sm"
|
||||||
></q-btn>
|
></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
|
<q-btn
|
||||||
icon="content_paste"
|
icon="content_paste"
|
||||||
@click="copyResult"
|
@click="copyResult"
|
||||||
@ -36,45 +55,180 @@ export default {
|
|||||||
closebtn: Boolean,
|
closebtn: Boolean,
|
||||||
runResult: Array,
|
runResult: Array,
|
||||||
},
|
},
|
||||||
|
emits: ["updateResult"],
|
||||||
computed: {
|
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: {
|
methods: {
|
||||||
copyResult() {
|
copyResult() {
|
||||||
window.utools.copyText(this.content);
|
window.utools.copyText(this.getFormattedContent());
|
||||||
quickcommand.showMessageBox("已复制到剪贴板");
|
quickcommand.showMessageBox("已复制到剪贴板");
|
||||||
},
|
},
|
||||||
sendResult() {
|
sendResult() {
|
||||||
window.utools.hideMainWindowTypeString(this.content);
|
window.utools.hideMainWindowTypeString(this.getFormattedContent());
|
||||||
},
|
},
|
||||||
dataUrlToImg() {
|
dataUrlToImg() {
|
||||||
let imgs = this.content
|
const imagePattern = /data:image\/.*?;base64,.*/g;
|
||||||
.match(/data:image\/.*?;base64,.*/g)
|
const imageUrls = this.getFormattedContent()
|
||||||
|
.match(imagePattern)
|
||||||
?.map((dataUrl) => `<img src="${dataUrl}"><br>`);
|
?.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() {
|
saveResult() {
|
||||||
window.saveFile(this.content, {
|
const saveOptions = {
|
||||||
defaultPath: "quickcommand-result.txt",
|
defaultPath: "quickcommand-result.txt",
|
||||||
filters: [{ name: "txt", extensions: ["txt"] }],
|
filters: [{ name: "txt", extensions: ["txt"] }],
|
||||||
});
|
};
|
||||||
|
window.saveFile(this.getFormattedContent(), saveOptions);
|
||||||
},
|
},
|
||||||
getContent() {
|
getFormattedContent() {
|
||||||
let content = this.runResult.map((item) => {
|
return this.formattedItems.map((item) => item.formatted).join("\n");
|
||||||
if (typeof item === "object") {
|
},
|
||||||
try {
|
updateStringifyResult() {
|
||||||
return JSON.stringify(item, null, 2);
|
this.updateResult([this.getFormattedContent()]);
|
||||||
} catch (e) {
|
},
|
||||||
return item.toString();
|
updateTableResult() {
|
||||||
}
|
const tableData = this.validTableData;
|
||||||
}
|
if (!tableData) return;
|
||||||
return item;
|
|
||||||
|
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>
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.result-menu {
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user