mirror of
https://github.com/fofolee/uTools-quickcommand.git
synced 2025-06-08 22:51:25 +08:00
命令卡片组件化
This commit is contained in:
parent
5e654a8964
commit
45a2170ff3
@ -1,301 +1,48 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- mini 模式下如果命令未启用或者不可直接运行则隐藏卡片面板 -->
|
<!-- mini 模式下如果命令未启用或者不可直接运行则隐藏卡片面板 -->
|
||||||
<div
|
<div
|
||||||
:class="{ wrapper: 1, warpperHover: isWarpperHover }"
|
:class="{
|
||||||
|
'card-wrapper': 1,
|
||||||
|
'card-wrapper-hover': isWarpperHover,
|
||||||
|
}"
|
||||||
v-show="!cardStyleVars.hideCard"
|
v-show="!cardStyleVars.hideCard"
|
||||||
:id="commandInfo.features.code"
|
:id="commandInfo.features.code"
|
||||||
@mouseenter="isWarpperHover = true"
|
@mouseenter="isWarpperHover = true"
|
||||||
@mouseleave="if (!isCtrlBtnMenuOpen) isWarpperHover = false;"
|
@mouseleave="if (!$refs.controlButtons?.isMenuOpen) isWarpperHover = false;"
|
||||||
>
|
>
|
||||||
<div>
|
|
||||||
<!-- mini 模式下不显示各类按钮 -->
|
<!-- mini 模式下不显示各类按钮 -->
|
||||||
<div v-show="cardStyleVars.showButtons">
|
<ControlButtons
|
||||||
<!-- 开关 -->
|
ref="controlButtons"
|
||||||
<div class="absolute" style="z-index: 1; left: 20px; bottom: 16px">
|
v-model:isVisible="isWarpperHover"
|
||||||
<q-toggle
|
v-show="cardStyleVars.showButtons"
|
||||||
:model-value="isCommandActivated"
|
:isActivated="isCommandActivated"
|
||||||
checked-icon="flash_on"
|
:commandInfo="commandInfo"
|
||||||
color="orange-6"
|
:canRunAtCurrentOS="canRunAtCurrentOS"
|
||||||
@click="toggleCommandActivated"
|
@commandChanged="$emit('commandChanged', $event)"
|
||||||
/>
|
/>
|
||||||
</div>
|
<CommandCardContent
|
||||||
<!-- 选项按钮 -->
|
:commandInfo="commandInfo"
|
||||||
<div
|
:isActivated="isCommandActivated"
|
||||||
class="absolute control-buttons"
|
:cardStyleVars="cardStyleVars"
|
||||||
style="z-index: 1; right: 16px; top: 16px"
|
:canRunAtCurrentOS="canRunAtCurrentOS"
|
||||||
:class="{ 'buttons-visible': isWarpperHover }"
|
:isHovered="isWarpperHover"
|
||||||
>
|
|
||||||
<q-btn
|
|
||||||
flat
|
|
||||||
round
|
|
||||||
dense
|
|
||||||
color="green"
|
|
||||||
icon="play_arrow"
|
|
||||||
v-show="canCommandRun"
|
|
||||||
@click="runCommand"
|
|
||||||
><q-tooltip anchor="top middle" self="center middle">
|
|
||||||
运行
|
|
||||||
</q-tooltip></q-btn
|
|
||||||
>
|
|
||||||
<q-btn
|
|
||||||
v-if="canCommandEdit"
|
|
||||||
dense
|
|
||||||
flat
|
|
||||||
round
|
|
||||||
:color="!!cronExp ? 'amber' : 'blue-9'"
|
|
||||||
:icon="!!cronExp ? 'timer' : 'insights'"
|
|
||||||
@click="isCtrlBtnMenuOpen = true"
|
|
||||||
>
|
|
||||||
<q-tooltip anchor="top middle" self="center middle">
|
|
||||||
设置
|
|
||||||
</q-tooltip>
|
|
||||||
<q-menu
|
|
||||||
transition-show="jump-down"
|
|
||||||
transition-hide="jump-up"
|
|
||||||
@hide="
|
|
||||||
isCtrlBtnMenuOpen = false;
|
|
||||||
isWarpperHover = false;
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<q-list style="min-width: 100px">
|
|
||||||
<q-item clickable v-close-popup @click="exportCommandFile">
|
|
||||||
<q-item-section side>
|
|
||||||
<q-icon name="save" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section>导出</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
<q-item clickable v-close-popup @click="exportCommandRaw">
|
|
||||||
<q-item-section side>
|
|
||||||
<q-icon name="content_paste_go" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section>复制到剪贴板</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
<q-item clickable @click="shareCommand" v-close-popup>
|
|
||||||
<q-item-section side>
|
|
||||||
<q-icon name="share" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section>分享</q-item-section>
|
|
||||||
<q-tooltip>分享到分享中心</q-tooltip>
|
|
||||||
</q-item>
|
|
||||||
<q-item
|
|
||||||
clickable
|
|
||||||
v-close-popup
|
|
||||||
@click="showCrontab = true"
|
|
||||||
:disable="!canCommandAddCron"
|
|
||||||
>
|
|
||||||
<q-item-section side>
|
|
||||||
<q-icon name="timer" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section>定时任务</q-item-section>
|
|
||||||
<q-tooltip
|
|
||||||
>在后台定时执行当前命令,仅匹配类型为关键字时可用,且一律忽略输出<br />
|
|
||||||
不同电脑间的定时任务不会同步</q-tooltip
|
|
||||||
>
|
|
||||||
</q-item>
|
|
||||||
</q-list>
|
|
||||||
</q-menu>
|
|
||||||
</q-btn>
|
|
||||||
<q-btn
|
|
||||||
v-if="canCommandEdit"
|
|
||||||
flat
|
|
||||||
round
|
|
||||||
dense
|
|
||||||
color="red"
|
|
||||||
icon="close"
|
|
||||||
@click="removeCommand"
|
|
||||||
><q-tooltip anchor="top middle" self="center middle">
|
|
||||||
删除
|
|
||||||
</q-tooltip></q-btn
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- 未启用的命令文字为灰色 -->
|
|
||||||
<q-card
|
|
||||||
@click="handleCardClick"
|
@click="handleCardClick"
|
||||||
v-ripple
|
|
||||||
:class="{ [`text-${disabledColor}`]: !isCommandActivated, command: 1 }"
|
|
||||||
>
|
|
||||||
<q-card-section>
|
|
||||||
<!-- logo -->
|
|
||||||
<div class="row" :class="cardStyleVars.logoPosition">
|
|
||||||
<q-avatar
|
|
||||||
square
|
|
||||||
size="48px"
|
|
||||||
:class="{
|
|
||||||
featureIco: 1,
|
|
||||||
featureIcoHover: isWarpperHover,
|
|
||||||
'feature-disabled': !isCommandActivated,
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<img :src="commandInfo.features.icon" />
|
|
||||||
</q-avatar>
|
|
||||||
</div>
|
|
||||||
<!-- 名称 -->
|
|
||||||
<!-- mini 和 small 模式下命令标题字体变小 -->
|
|
||||||
<div :class="'row ' + cardStyleVars.fontPosition">
|
|
||||||
<div
|
|
||||||
class="ellipsis"
|
|
||||||
:style="{
|
|
||||||
fontSize: cardStyleVars.showBiggerTitle ? '1.25rem' : '1.1rem',
|
|
||||||
}"
|
|
||||||
v-html="commandInfo.features.explain.trim() || '<br/>'"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<!-- 匹配模式 -->
|
|
||||||
<div class="row">
|
|
||||||
<div
|
|
||||||
:class="
|
|
||||||
'matchTypesBox flex q-gutter-xs ' + cardStyleVars.fontPosition
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<span v-for="cmd in commandInfo.features.cmds" :key="cmd">
|
|
||||||
<span v-if="typeof cmd === 'string'">
|
|
||||||
<q-badge
|
|
||||||
rounded
|
|
||||||
:color="matchTypeColor()"
|
|
||||||
:class="cardBadgeClass"
|
|
||||||
>
|
|
||||||
<q-icon class="q-mr-xs" :name="commandTypes.key.icon" />
|
|
||||||
{{ getShortStrByByte(cmd) }}
|
|
||||||
</q-badge>
|
|
||||||
<q-tooltip>
|
|
||||||
<div class="text-subtitle2">
|
|
||||||
{{ cmd }}
|
|
||||||
</div>
|
|
||||||
</q-tooltip>
|
|
||||||
</span>
|
|
||||||
<span v-else-if="cmd.type === 'window' && cmd.match">
|
|
||||||
<q-badge
|
|
||||||
rounded
|
|
||||||
:color="matchTypeColor(cmd.type)"
|
|
||||||
:class="cardBadgeClass"
|
|
||||||
>
|
|
||||||
<q-icon class="q-mr-xs" :name="commandTypes.window.icon" />
|
|
||||||
{{ getShortStrByByte(cmd.match.app[0]) }}
|
|
||||||
</q-badge>
|
|
||||||
<q-tooltip>
|
|
||||||
<div
|
|
||||||
class="text-subtitle2"
|
|
||||||
v-for="app in cmd.match.app"
|
|
||||||
:key="app"
|
|
||||||
>
|
|
||||||
{{ app }}
|
|
||||||
</div>
|
|
||||||
</q-tooltip>
|
|
||||||
</span>
|
|
||||||
<span v-else-if="cmd.type === 'files'">
|
|
||||||
<q-badge
|
|
||||||
rounded
|
|
||||||
:color="matchTypeColor(cmd.type)"
|
|
||||||
:class="cardBadgeClass"
|
|
||||||
>
|
|
||||||
<q-icon class="q-mr-xs" :name="commandTypes.files.icon" />
|
|
||||||
{{
|
|
||||||
(cmd.match && getShortStrByByte(cmd.match)) || "所有文件"
|
|
||||||
}}
|
|
||||||
</q-badge>
|
|
||||||
<q-tooltip>
|
|
||||||
<div class="text-subtitle2">
|
|
||||||
{{ cmd.match || "所有文件" }}
|
|
||||||
</div>
|
|
||||||
</q-tooltip>
|
|
||||||
</span>
|
|
||||||
<span v-else-if="cmd.type === 'regex'">
|
|
||||||
<q-badge
|
|
||||||
rounded
|
|
||||||
:color="matchTypeColor(cmd.type)"
|
|
||||||
:class="cardBadgeClass"
|
|
||||||
>
|
|
||||||
<q-icon class="q-mr-xs" :name="commandTypes.regex.icon" />
|
|
||||||
{{ getShortStrByByte(cmd.match) }}
|
|
||||||
</q-badge>
|
|
||||||
<q-tooltip>
|
|
||||||
<div class="text-subtitle2">
|
|
||||||
{{ cmd.match }}
|
|
||||||
</div>
|
|
||||||
</q-tooltip>
|
|
||||||
</span>
|
|
||||||
<span v-else-if="cmd.type === 'over'">
|
|
||||||
<q-badge
|
|
||||||
rounded
|
|
||||||
:color="matchTypeColor(cmd.type)"
|
|
||||||
:class="cardBadgeClass"
|
|
||||||
>
|
|
||||||
<q-icon
|
|
||||||
class="q-mr-xs"
|
|
||||||
:name="commandTypes.over.icon"
|
|
||||||
/>所有文本
|
|
||||||
</q-badge>
|
|
||||||
</span>
|
|
||||||
<span v-else-if="cmd.type === 'img'">
|
|
||||||
<q-badge
|
|
||||||
rounded
|
|
||||||
:color="matchTypeColor(cmd.type)"
|
|
||||||
:class="cardBadgeClass"
|
|
||||||
>
|
|
||||||
<q-icon class="q-mr-xs" :name="commandTypes.img.icon" />图片
|
|
||||||
</q-badge>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- mini模式下不显示语言类型和适配系统 -->
|
|
||||||
<!-- 语言类型 -->
|
|
||||||
<div
|
|
||||||
class="row justify-end items-center q-gutter-xs"
|
|
||||||
v-show="cardStyleVars.showLanguages"
|
|
||||||
>
|
|
||||||
<span :class="`text-${programColor}`">●</span>
|
|
||||||
<span class="text-subtitle2">{{ commandInfo.program }}</span>
|
|
||||||
<!-- mini 和 small 模式下不显示适配系统 -->
|
|
||||||
<!-- 适配系统 -->
|
|
||||||
<div class="q-gutter-xs" v-show="cardStyleVars.showPlatforms">
|
|
||||||
<span
|
|
||||||
v-for="platform in commandInfo.features.platform"
|
|
||||||
:key="platform"
|
|
||||||
:class="`iconfont icon-${platformTypes[platform].icon} text-${programColor}`"
|
|
||||||
style="font-size: 12px"
|
|
||||||
></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</q-card-section>
|
|
||||||
</q-card>
|
|
||||||
</div>
|
|
||||||
<q-dialog v-model="showCrontab">
|
|
||||||
<CrontabSetting
|
|
||||||
:cronExp="cronExp"
|
|
||||||
@addCrontab="addCrontab"
|
|
||||||
@delCrontab="delCrontab"
|
|
||||||
/>
|
|
||||||
</q-dialog>
|
|
||||||
<!-- <q-dialog v-model="showShare">
|
|
||||||
<ShareDialog :command="getRawCommand(commandInfo)" />
|
|
||||||
</q-dialog> -->
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import commandTypes from "js/options/commandTypes.js";
|
import ControlButtons from "components/card/ControlButtons.vue";
|
||||||
import platformTypes from "js/options/platformTypes.js";
|
import CommandCardContent from "components/card/CommandCardContent.vue";
|
||||||
import CrontabSetting from "components/popup/CrontabSetting";
|
|
||||||
// import ShareDialog from "components/popup/ShareDialog";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
CrontabSetting,
|
ControlButtons,
|
||||||
// ShareDialog
|
CommandCardContent,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
allProgrammings: this.$root.programs,
|
|
||||||
maxCmdStingLen: 8,
|
|
||||||
commandTypes: commandTypes,
|
|
||||||
platformTypes: platformTypes,
|
|
||||||
showCrontab: false,
|
|
||||||
// showShare: false,
|
|
||||||
cronJob: null,
|
|
||||||
isWarpperHover: false,
|
isWarpperHover: false,
|
||||||
isCtrlBtnMenuOpen: false,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -312,64 +59,15 @@ export default {
|
|||||||
this.cardStyle.code > 1 ? "justify-end" : "justify-center",
|
this.cardStyle.code > 1 ? "justify-end" : "justify-center",
|
||||||
hideCard:
|
hideCard:
|
||||||
this.cardStyle.code === 1 &&
|
this.cardStyle.code === 1 &&
|
||||||
(!this.isCommandActivated || !this.canCommandRun),
|
(!this.isCommandActivated || !this.$refs.controlButtons?.canRun),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
// 命令是否适合当前平台
|
canRunAtCurrentOS() {
|
||||||
canCommandRunAtCurrentOS() {
|
|
||||||
let { platform } = this.commandInfo.features;
|
let { platform } = this.commandInfo.features;
|
||||||
return !_.isEmpty(platform) && !platform.includes(window.processPlatform)
|
return !_.isEmpty(platform) && !platform.includes(window.processPlatform)
|
||||||
? false
|
? false
|
||||||
: true;
|
: true;
|
||||||
},
|
},
|
||||||
// 命令是否可直接运行, 无论 cmds 长度为多少,只运行 cmds[0]
|
|
||||||
canCommandRun() {
|
|
||||||
// 未启用
|
|
||||||
if (!this.isCommandActivated) return false;
|
|
||||||
if (!this.canCommandRunAtCurrentOS) return false;
|
|
||||||
let { cmds } = this.commandInfo.features;
|
|
||||||
// 窗口模式
|
|
||||||
if (cmds[0].type && cmds[0].type === "window") return false;
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
// 命令未启用也可以添加计划任务
|
|
||||||
canCommandAddCron() {
|
|
||||||
return !!this.commandInfo.features.cmds[0].length;
|
|
||||||
},
|
|
||||||
// 默认命令不可删除
|
|
||||||
canCommandEdit() {
|
|
||||||
if (utools.isDev()) return true;
|
|
||||||
return this.commandInfo.tags?.includes("默认") ? false : true;
|
|
||||||
},
|
|
||||||
// 匹配类型的颜色
|
|
||||||
matchTypeColor() {
|
|
||||||
return (cmdType = "key") => {
|
|
||||||
if (!this.canCommandRunAtCurrentOS || !this.isCommandActivated) {
|
|
||||||
return this.$q.dark.isActive ? "grey-9" : this.disabledColor;
|
|
||||||
}
|
|
||||||
return this.commandTypes[cmdType].color;
|
|
||||||
};
|
|
||||||
},
|
|
||||||
programColor() {
|
|
||||||
return this.isCommandActivated
|
|
||||||
? this.allProgrammings[this.commandInfo.program].color
|
|
||||||
: this.disabledColor;
|
|
||||||
},
|
|
||||||
disabledColor() {
|
|
||||||
return this.$q.dark.isActive ? "grey-6" : "grey-5";
|
|
||||||
},
|
|
||||||
featureCode() {
|
|
||||||
return this.commandInfo.features.code;
|
|
||||||
},
|
|
||||||
cronExp() {
|
|
||||||
return this.$root.nativeProfile.crontabs[this.featureCode];
|
|
||||||
},
|
|
||||||
cardBadgeClass() {
|
|
||||||
return (!this.canCommandRunAtCurrentOS || !this.isCommandActivated) &&
|
|
||||||
this.$q.dark.isActive
|
|
||||||
? "text-grey-6"
|
|
||||||
: "";
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
commandInfo: Object,
|
commandInfo: Object,
|
||||||
@ -377,96 +75,22 @@ export default {
|
|||||||
cardStyle: Object,
|
cardStyle: Object,
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 匹配类型太长的话截断
|
|
||||||
getShortStrByByte(str) {
|
|
||||||
let byteLen = 0;
|
|
||||||
let shortStr = "";
|
|
||||||
for (let i = 0; i < str.length; i++) {
|
|
||||||
byteLen += 129 - str[i].charCodeAt(0) > 0 ? 1 : 2;
|
|
||||||
if (byteLen > this.maxCmdStingLen) break;
|
|
||||||
shortStr += str[i];
|
|
||||||
}
|
|
||||||
return shortStr === str ? shortStr : shortStr + "...";
|
|
||||||
},
|
|
||||||
// 命令卡片点击事件
|
// 命令卡片点击事件
|
||||||
handleCardClick() {
|
handleCardClick() {
|
||||||
// 视图模式直接运行命令
|
// 视图模式直接运行命令
|
||||||
if (this.cardStyle.code === 1) return this.runCommand();
|
if (this.cardStyle.code === 1) {
|
||||||
|
return this.$refs.controlButtons.runCommand();
|
||||||
|
}
|
||||||
this.editCommand();
|
this.editCommand();
|
||||||
},
|
},
|
||||||
// 编辑命令
|
// 编辑命令
|
||||||
editCommand() {
|
editCommand() {
|
||||||
let event = {
|
let event = {
|
||||||
type: "edit",
|
type: "edit",
|
||||||
data: this.featureCode,
|
data: this.commandInfo.features.code,
|
||||||
};
|
};
|
||||||
this.$emit("commandChanged", event);
|
this.$emit("commandChanged", event);
|
||||||
},
|
},
|
||||||
// 运行命令
|
|
||||||
runCommand() {
|
|
||||||
let event = {
|
|
||||||
type: "run",
|
|
||||||
data: this.featureCode,
|
|
||||||
};
|
|
||||||
this.$emit("commandChanged", event);
|
|
||||||
},
|
|
||||||
addCrontab(cronExp) {
|
|
||||||
this.$root.nativeProfile.crontabs[this.featureCode] = cronExp;
|
|
||||||
this.$root.runCronTask(this.featureCode, cronExp);
|
|
||||||
},
|
|
||||||
delCrontab() {
|
|
||||||
delete this.$root.nativeProfile.crontabs[this.featureCode];
|
|
||||||
this.$root.cronJobs[this.featureCode].stop();
|
|
||||||
},
|
|
||||||
// 启用/禁用命令
|
|
||||||
toggleCommandActivated() {
|
|
||||||
let event = {
|
|
||||||
data: this.featureCode,
|
|
||||||
type: "toggle",
|
|
||||||
};
|
|
||||||
event.type = this.isCommandActivated ? "disable" : "enable";
|
|
||||||
this.$emit("commandChanged", event);
|
|
||||||
},
|
|
||||||
// 移除命令
|
|
||||||
removeCommand() {
|
|
||||||
quickcommand.showConfirmBox("删除这个快捷命令").then((x) => {
|
|
||||||
if (!x) return;
|
|
||||||
this.isCommandAlive = false;
|
|
||||||
let code = this.featureCode;
|
|
||||||
this.$emit("commandChanged", {
|
|
||||||
type: "remove",
|
|
||||||
data: code,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
getRawCommand() {
|
|
||||||
let command = _.cloneDeep(this.commandInfo);
|
|
||||||
command.features.explain = window.removeHtmlTags(
|
|
||||||
command.features.explain
|
|
||||||
);
|
|
||||||
return command;
|
|
||||||
},
|
|
||||||
// 导出到剪贴板
|
|
||||||
exportCommandRaw() {
|
|
||||||
utools.copyText(JSON.stringify(this.getRawCommand(), null, 4)) &&
|
|
||||||
utools.showNotification(
|
|
||||||
`「${this.commandInfo.features.explain}」已复制到剪贴板`
|
|
||||||
);
|
|
||||||
},
|
|
||||||
// 导出到文件
|
|
||||||
exportCommandFile() {
|
|
||||||
window.saveFile(JSON.stringify(this.getRawCommand()), {
|
|
||||||
title: "选择保存位置",
|
|
||||||
defaultPath: `${window.removeHtmlTags(
|
|
||||||
this.commandInfo.features.explain
|
|
||||||
)}.json`,
|
|
||||||
filters: [{ name: "json", extensions: ["json"] }],
|
|
||||||
});
|
|
||||||
},
|
|
||||||
shareCommand() {
|
|
||||||
this.exportCommandRaw();
|
|
||||||
utools.shellOpenExternal("https://qc.qaz.ink/submit");
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@ -492,50 +116,12 @@ export default {
|
|||||||
0 3px 1px -2px rgb(69 67 67 / 12%);
|
0 3px 1px -2px rgb(69 67 67 / 12%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.q-badge {
|
.card-wrapper {
|
||||||
font-size: 15px;
|
transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
margin: 0 1px;
|
will-change: transform;
|
||||||
}
|
|
||||||
.ellipsis {
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.matchTypesBox {
|
|
||||||
height: 23px;
|
|
||||||
width: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
.wrapper {
|
|
||||||
transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
}
|
|
||||||
.warpperHover {
|
|
||||||
transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
transform: translateY(-3px);
|
|
||||||
}
|
|
||||||
.featureIco {
|
|
||||||
transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
}
|
|
||||||
.featureIcoHover {
|
|
||||||
transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
transform: scale(1.1);
|
|
||||||
}
|
|
||||||
.control-buttons {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(5px);
|
|
||||||
visibility: hidden;
|
|
||||||
transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.control-buttons.buttons-visible {
|
.card-wrapper-hover {
|
||||||
opacity: 1;
|
transform: scale(1.02);
|
||||||
transform: translateY(0);
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
.feature-disabled {
|
|
||||||
opacity: 0.5;
|
|
||||||
filter: grayscale(100%);
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
190
src/components/card/CommandCardContent.vue
Normal file
190
src/components/card/CommandCardContent.vue
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
<template>
|
||||||
|
<q-card
|
||||||
|
@click="$emit('click')"
|
||||||
|
v-ripple
|
||||||
|
:class="{ [`text-${disabledColor}`]: !isActivated, command: 1 }"
|
||||||
|
>
|
||||||
|
<q-card-section>
|
||||||
|
<!-- logo -->
|
||||||
|
<div class="row" :class="cardStyleVars.logoPosition">
|
||||||
|
<q-avatar
|
||||||
|
square
|
||||||
|
size="48px"
|
||||||
|
:class="{
|
||||||
|
featureIco: 1,
|
||||||
|
featureIcoHover: isHovered,
|
||||||
|
'feature-disabled': !isActivated,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<img :src="commandInfo.features.icon" />
|
||||||
|
</q-avatar>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 名称 -->
|
||||||
|
<div :class="'row ' + cardStyleVars.fontPosition">
|
||||||
|
<div
|
||||||
|
class="ellipsis"
|
||||||
|
:style="{
|
||||||
|
fontSize: cardStyleVars.showBiggerTitle ? '16px' : '14px',
|
||||||
|
}"
|
||||||
|
v-html="commandInfo.features.explain.trim() || '<br/>'"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 匹配模式 -->
|
||||||
|
<div class="row">
|
||||||
|
<div
|
||||||
|
:class="
|
||||||
|
'matchTypesBox flex q-gutter-xs ' + cardStyleVars.fontPosition
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span v-for="cmd in commandInfo.features.cmds" :key="cmd">
|
||||||
|
<CommandTypeTag
|
||||||
|
:cmd="cmd"
|
||||||
|
:isGrayColor="!canRunAtCurrentOS || !isActivated"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 语言类型和适配系统 -->
|
||||||
|
<div
|
||||||
|
class="row justify-end items-center q-gutter-xs"
|
||||||
|
v-show="cardStyleVars.showLanguages"
|
||||||
|
>
|
||||||
|
<span :class="`text-${programColor}`">●</span>
|
||||||
|
<span class="text-subtitle2">{{ commandInfo.program }}</span>
|
||||||
|
|
||||||
|
<div class="q-gutter-xs" v-show="cardStyleVars.showPlatforms">
|
||||||
|
<span
|
||||||
|
v-for="platform in commandInfo.features.platform"
|
||||||
|
:key="platform"
|
||||||
|
:class="`iconfont icon-${platformTypes[platform].icon} text-${programColor}`"
|
||||||
|
style="font-size: 12px"
|
||||||
|
></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import commandTypes from "js/options/commandTypes.js";
|
||||||
|
import platformTypes from "js/options/platformTypes.js";
|
||||||
|
import CommandTypeTag from "./CommandTypeTag.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
CommandTypeTag,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
commandInfo: Object,
|
||||||
|
isActivated: Boolean,
|
||||||
|
cardStyleVars: Object,
|
||||||
|
canRunAtCurrentOS: Boolean,
|
||||||
|
isHovered: Boolean,
|
||||||
|
},
|
||||||
|
emits: ["click"],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
commandTypes,
|
||||||
|
platformTypes,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
programColor() {
|
||||||
|
return this.isActivated
|
||||||
|
? this.$root.programs[this.commandInfo.program].color
|
||||||
|
: this.disabledColor;
|
||||||
|
},
|
||||||
|
disabledColor() {
|
||||||
|
return this.$q.dark.isActive ? "grey-6" : "grey-5";
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// 设置图标URL作为光晕背景
|
||||||
|
this.$el.style.setProperty(
|
||||||
|
"--icon-url",
|
||||||
|
`url(${this.commandInfo.features.icon})`
|
||||||
|
);
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
"commandInfo.features.icon"(newVal) {
|
||||||
|
this.$el.style.setProperty("--icon-url", `url(${newVal})`);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.q-card.command {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
background: rgba(255, 255, 255, 0.3) !important;
|
||||||
|
backdrop-filter: blur(calc(var(--glass-effect-strength) * 1px)) !important;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
box-shadow: 0 4px 16px 0 rgba(31, 38, 135, 0.07);
|
||||||
|
will-change: transform, box-shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body--dark .q-card.command {
|
||||||
|
background: rgba(57, 57, 57, 0.09) !important;
|
||||||
|
border: 1px solid rgb(59 58 58 / 5%);
|
||||||
|
box-shadow: 0 1px 5px rgb(0 0 0 / 20%), 0 2px 2px rgb(0 0 0 / 14%),
|
||||||
|
0 3px 1px -2px rgb(69 67 67 / 12%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ellipsis {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.matchTypesBox {
|
||||||
|
height: 23px;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.featureIco {
|
||||||
|
transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||||
|
will-change: transform;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.featureIcoHover {
|
||||||
|
transform: scale(1.08) translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.featureIco::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
z-index: -1;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||||
|
opacity: 0;
|
||||||
|
background-image: var(--icon-url);
|
||||||
|
background-size: contain;
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
filter: blur(6px) brightness(1.2);
|
||||||
|
transform: scale(1.1);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.featureIcoHover::after {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
filter: grayscale(100%);
|
||||||
|
}
|
||||||
|
</style>
|
96
src/components/card/CommandTypeTag.vue
Normal file
96
src/components/card/CommandTypeTag.vue
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
<template>
|
||||||
|
<span v-if="typeof cmd === 'string'">
|
||||||
|
<q-badge rounded :class="badgeClass">
|
||||||
|
<q-icon class="q-mr-xs" :name="commandTypes.key.icon" />
|
||||||
|
<span class="badge-text">{{ cmd }}</span>
|
||||||
|
</q-badge>
|
||||||
|
<q-tooltip>
|
||||||
|
<div class="text-subtitle2">{{ cmd }}</div>
|
||||||
|
</q-tooltip>
|
||||||
|
</span>
|
||||||
|
<span v-else-if="cmd.type === 'window' && cmd.match">
|
||||||
|
<q-badge rounded :class="badgeClass">
|
||||||
|
<q-icon class="q-mr-xs" :name="commandTypes.window.icon" />
|
||||||
|
<span class="badge-text">{{ cmd.match.app[0] }}</span>
|
||||||
|
</q-badge>
|
||||||
|
<q-tooltip>
|
||||||
|
<div class="text-subtitle2" v-for="app in cmd.match.app" :key="app">
|
||||||
|
{{ app }}
|
||||||
|
</div>
|
||||||
|
</q-tooltip>
|
||||||
|
</span>
|
||||||
|
<span v-else-if="cmd.type === 'files'">
|
||||||
|
<q-badge rounded :class="badgeClass">
|
||||||
|
<q-icon class="q-mr-xs" :name="commandTypes.files.icon" />
|
||||||
|
<span class="badge-text">{{ cmd.match || "所有文件" }}</span>
|
||||||
|
</q-badge>
|
||||||
|
<q-tooltip>
|
||||||
|
<div class="text-subtitle2">
|
||||||
|
{{ cmd.match || "所有文件" }}
|
||||||
|
</div>
|
||||||
|
</q-tooltip>
|
||||||
|
</span>
|
||||||
|
<span v-else-if="cmd.type === 'regex'">
|
||||||
|
<q-badge rounded :class="badgeClass">
|
||||||
|
<q-icon class="q-mr-xs" :name="commandTypes.regex.icon" />
|
||||||
|
<span class="badge-text">{{ cmd.match }}</span>
|
||||||
|
</q-badge>
|
||||||
|
<q-tooltip>
|
||||||
|
<div class="text-subtitle2">
|
||||||
|
{{ cmd.match }}
|
||||||
|
</div>
|
||||||
|
</q-tooltip>
|
||||||
|
</span>
|
||||||
|
<span v-else-if="cmd.type === 'over'">
|
||||||
|
<q-badge rounded :class="badgeClass">
|
||||||
|
<q-icon class="q-mr-xs" :name="commandTypes.over.icon" />所有文本
|
||||||
|
</q-badge>
|
||||||
|
</span>
|
||||||
|
<span v-else-if="cmd.type === 'img'">
|
||||||
|
<q-badge rounded :class="badgeClass">
|
||||||
|
<q-icon class="q-mr-xs" :name="commandTypes.img.icon" />图片
|
||||||
|
</q-badge>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import commandTypes from "js/options/commandTypes.js";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
cmd: [String, Object],
|
||||||
|
isGrayColor: Boolean,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
commandTypes,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
badgeClass() {
|
||||||
|
return this.isGrayColor
|
||||||
|
? this.$q.dark.isActive
|
||||||
|
? "text-grey-6 bg-grey-9"
|
||||||
|
: "bg-grey-5"
|
||||||
|
: "bg-" + this.commandTypes[this.cmd.type || "key"].color;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.q-badge {
|
||||||
|
font-size: 13px;
|
||||||
|
margin: 0 1px;
|
||||||
|
max-width: 120px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-text {
|
||||||
|
display: inline-block;
|
||||||
|
max-width: 80px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
vertical-align: bottom;
|
||||||
|
}
|
||||||
|
</style>
|
250
src/components/card/ControlButtons.vue
Normal file
250
src/components/card/ControlButtons.vue
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<!-- 开关按钮 -->
|
||||||
|
<div class="absolute" style="z-index: 1; left: 20px; bottom: 16px">
|
||||||
|
<q-toggle
|
||||||
|
:model-value="isActivated"
|
||||||
|
checked-icon="flash_on"
|
||||||
|
color="orange-6"
|
||||||
|
@click="toggleCommandActivated"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 控制按钮组 -->
|
||||||
|
<div
|
||||||
|
class="absolute control-buttons"
|
||||||
|
style="z-index: 1; right: 16px; top: 16px"
|
||||||
|
:class="{ 'buttons-visible': isVisible }"
|
||||||
|
>
|
||||||
|
<q-btn
|
||||||
|
flat
|
||||||
|
round
|
||||||
|
dense
|
||||||
|
color="green"
|
||||||
|
icon="play_arrow"
|
||||||
|
v-show="canRun"
|
||||||
|
@click="runCommand"
|
||||||
|
>
|
||||||
|
<q-tooltip anchor="top middle" self="center middle">运行</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
|
|
||||||
|
<q-btn
|
||||||
|
v-if="canEdit"
|
||||||
|
dense
|
||||||
|
flat
|
||||||
|
round
|
||||||
|
:color="!!cronExp ? 'amber' : 'blue-9'"
|
||||||
|
:icon="!!cronExp ? 'timer' : 'insights'"
|
||||||
|
@click="isMenuOpen = true"
|
||||||
|
>
|
||||||
|
<q-tooltip anchor="top middle" self="center middle">设置</q-tooltip>
|
||||||
|
<q-menu
|
||||||
|
transition-show="jump-down"
|
||||||
|
transition-hide="jump-up"
|
||||||
|
@hide="hideMenu"
|
||||||
|
>
|
||||||
|
<q-list style="min-width: 100px">
|
||||||
|
<q-item clickable v-close-popup @click="exportCommandFile">
|
||||||
|
<q-item-section side>
|
||||||
|
<q-icon name="save" />
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section>导出</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
|
||||||
|
<q-item clickable v-close-popup @click="exportCommandRaw">
|
||||||
|
<q-item-section side>
|
||||||
|
<q-icon name="content_paste_go" />
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section>复制到剪贴板</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
|
||||||
|
<q-item clickable @click="shareCommand" v-close-popup>
|
||||||
|
<q-item-section side>
|
||||||
|
<q-icon name="share" />
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section>分享</q-item-section>
|
||||||
|
<q-tooltip>分享到分享中心</q-tooltip>
|
||||||
|
</q-item>
|
||||||
|
|
||||||
|
<q-item
|
||||||
|
clickable
|
||||||
|
v-close-popup
|
||||||
|
@click="showCrontab = true"
|
||||||
|
:disable="!canAddCron"
|
||||||
|
>
|
||||||
|
<q-item-section side>
|
||||||
|
<q-icon name="timer" />
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section>定时任务</q-item-section>
|
||||||
|
<q-tooltip>
|
||||||
|
在后台定时执行当前命令,仅匹配类型为关键字时可用,且一律忽略输出<br />
|
||||||
|
不同电脑间的定时任务不会同步
|
||||||
|
</q-tooltip>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-menu>
|
||||||
|
</q-btn>
|
||||||
|
|
||||||
|
<q-btn
|
||||||
|
v-if="canEdit"
|
||||||
|
flat
|
||||||
|
round
|
||||||
|
dense
|
||||||
|
color="red"
|
||||||
|
icon="close"
|
||||||
|
@click="removeCommand"
|
||||||
|
>
|
||||||
|
<q-tooltip anchor="top middle" self="center middle">删除</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 定时任务设置对话框 -->
|
||||||
|
<q-dialog v-model="showCrontab">
|
||||||
|
<CrontabSetting
|
||||||
|
:cronExp="cronExp"
|
||||||
|
@addCrontab="addCrontab"
|
||||||
|
@delCrontab="delCrontab"
|
||||||
|
/>
|
||||||
|
</q-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import CrontabSetting from "components/popup/CrontabSetting";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
CrontabSetting,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
isVisible: Boolean,
|
||||||
|
isActivated: Boolean,
|
||||||
|
commandInfo: Object,
|
||||||
|
canRunAtCurrentOS: Boolean,
|
||||||
|
},
|
||||||
|
emits: ["update:isVisible", "commandChanged"],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isMenuOpen: false,
|
||||||
|
showCrontab: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 获取定时任务表达式
|
||||||
|
cronExp() {
|
||||||
|
return this.$root.nativeProfile.crontabs[this.featureCode];
|
||||||
|
},
|
||||||
|
// 命令是否可直接运行
|
||||||
|
canRun() {
|
||||||
|
// 未启用
|
||||||
|
if (!this.isActivated) return false;
|
||||||
|
if (!this.canRunAtCurrentOS) return false;
|
||||||
|
let { cmds } = this.commandInfo.features;
|
||||||
|
// 窗口模式
|
||||||
|
if (cmds[0].type && cmds[0].type === "window") return false;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
// 命令未启用可以添加计划任务
|
||||||
|
canAddCron() {
|
||||||
|
return !!this.commandInfo.features.cmds[0].length;
|
||||||
|
},
|
||||||
|
// 默认命令不可删除
|
||||||
|
canEdit() {
|
||||||
|
if (window.utools.isDev()) return true;
|
||||||
|
return this.commandInfo.tags?.includes("默认") ? false : true;
|
||||||
|
},
|
||||||
|
featureCode() {
|
||||||
|
return this.commandInfo.features.code;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
hideMenu() {
|
||||||
|
this.isMenuOpen = false;
|
||||||
|
this.$emit("update:isVisible", false);
|
||||||
|
},
|
||||||
|
runCommand() {
|
||||||
|
this.$emit("commandChanged", {
|
||||||
|
type: "run",
|
||||||
|
data: this.featureCode,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
removeCommand() {
|
||||||
|
quickcommand.showConfirmBox("删除这个快捷命令").then((ok) => {
|
||||||
|
if (!ok) return;
|
||||||
|
this.$emit("commandChanged", {
|
||||||
|
type: "remove",
|
||||||
|
data: this.featureCode,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
toggleCommandActivated() {
|
||||||
|
this.$emit("commandChanged", {
|
||||||
|
type: this.isActivated ? "disable" : "enable",
|
||||||
|
data: this.featureCode,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getRawCommand() {
|
||||||
|
let command = _.cloneDeep(this.commandInfo);
|
||||||
|
command.features.explain = window.removeHtmlTags(
|
||||||
|
command.features.explain
|
||||||
|
);
|
||||||
|
return command;
|
||||||
|
},
|
||||||
|
// 导出到剪贴板
|
||||||
|
exportCommandRaw() {
|
||||||
|
utools.copyText(JSON.stringify(this.getRawCommand(), null, 4)) &&
|
||||||
|
utools.showNotification(
|
||||||
|
`「${this.commandInfo.features.explain}」已复制到剪贴板`
|
||||||
|
);
|
||||||
|
},
|
||||||
|
// 导出到文件
|
||||||
|
exportCommandFile() {
|
||||||
|
window.saveFile(JSON.stringify(this.getRawCommand()), {
|
||||||
|
title: "选择保存位置",
|
||||||
|
defaultPath: `${window.removeHtmlTags(
|
||||||
|
this.commandInfo.features.explain
|
||||||
|
)}.json`,
|
||||||
|
filters: [{ name: "json", extensions: ["json"] }],
|
||||||
|
});
|
||||||
|
},
|
||||||
|
shareCommand() {
|
||||||
|
this.exportCommandRaw();
|
||||||
|
utools.shellOpenExternal("https://qc.qaz.ink/submit");
|
||||||
|
},
|
||||||
|
addCrontab(cronExp) {
|
||||||
|
this.$root.nativeProfile.crontabs[this.featureCode] = cronExp;
|
||||||
|
this.$root.runCronTask(this.featureCode, cronExp);
|
||||||
|
},
|
||||||
|
delCrontab() {
|
||||||
|
delete this.$root.nativeProfile.crontabs[this.featureCode];
|
||||||
|
this.$root.cronJobs[this.featureCode].stop();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.control-buttons {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(5px);
|
||||||
|
visibility: hidden;
|
||||||
|
transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
will-change: transform, opacity, visibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-buttons.buttons-visible {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 按钮悬浮效果 */
|
||||||
|
.q-btn {
|
||||||
|
transition: transform 0.35s cubic-bezier(0.68, -0.6, 0.32, 1.6);
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
.q-btn:hover {
|
||||||
|
transform: scale(1.15);
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
x
Reference in New Issue
Block a user