mirror of
https://github.com/fofolee/uTools-quickcommand.git
synced 2025-12-14 22:54:32 +08:00
235 lines
6.7 KiB
Vue
235 lines
6.7 KiB
Vue
<template>
|
||
<q-btn-group :stretch="stretch" class="text-primary result-menu">
|
||
<q-btn
|
||
icon="image"
|
||
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"
|
||
v-show="textbtn"
|
||
dense
|
||
size="sm"
|
||
><q-tooltip v-if="!dense">复制到剪贴板</q-tooltip></q-btn
|
||
>
|
||
<q-btn icon="send" size="sm" @click="sendResult" v-show="textbtn" dense
|
||
><q-tooltip v-if="!dense">发送到活动窗口</q-tooltip></q-btn
|
||
>
|
||
<q-btn icon="save" v-if="!dense" size="sm" @click="saveResult" dense
|
||
><q-tooltip>保存到文件</q-tooltip></q-btn
|
||
>
|
||
<q-btn icon="close" v-close-popup v-show="closebtn" dense size="sm" />
|
||
</q-btn-group>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
props: {
|
||
dense: Boolean,
|
||
stretch: Boolean,
|
||
textbtn: Boolean,
|
||
imagebtn: Boolean,
|
||
closebtn: Boolean,
|
||
runResult: Array,
|
||
},
|
||
emits: ["updateResult"],
|
||
computed: {
|
||
/**
|
||
* 处理运行结果数据,同时完成以下任务:
|
||
* 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.getFormattedContent());
|
||
quickcommand.showMessageBox("已复制到剪贴板");
|
||
},
|
||
sendResult() {
|
||
window.utools.hideMainWindowTypeString(this.getFormattedContent());
|
||
},
|
||
dataUrlToImg() {
|
||
const imagePattern = /data:image\/.*?;base64,.*/g;
|
||
const imageUrls = this.getFormattedContent()
|
||
.match(imagePattern)
|
||
?.map((dataUrl) => `<img src="${dataUrl}"><br>`);
|
||
|
||
if (!imageUrls) {
|
||
return quickcommand.showMessageBox("dataUrl 格式不正确!");
|
||
}
|
||
this.$emit("showImg", imageUrls);
|
||
},
|
||
saveResult() {
|
||
const saveOptions = {
|
||
defaultPath: "quickcommand-result.txt",
|
||
filters: [{ name: "txt", extensions: ["txt"] }],
|
||
};
|
||
window.saveFile(this.getFormattedContent(), saveOptions);
|
||
},
|
||
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;
|
||
});
|
||
|
||
// 生成对齐的行
|
||
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>
|