feat: 统一复制按钮 (#3129)

This commit is contained in:
zhengkunwang 2023-12-01 16:56:10 +08:00 committed by GitHub
parent e687f82126
commit e773bcbda2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 138 additions and 235 deletions

View File

@ -0,0 +1,14 @@
<template>
<el-button v-if="type == 'icon'" link @click="copyText(content)" icon="DocumentCopy" class="ml-1.5"></el-button>
<el-button type="primary" @click="copyText(content)" v-else>{{ $t('commons.button.copy') }}</el-button>
</template>
<script lang="ts" setup>
import { copyText } from '@/utils/util';
defineOptions({ name: 'CopyButton' });
defineProps({
content: String,
type: String,
});
</script>

View File

@ -6,8 +6,8 @@
<h4>{{ $t('commons.login.errDomain1') }}</h4>
<div>
<h4>{{ $t('commons.login.errHelper') }} 1pctl reset domain</h4>
<div style="cursor: pointer; float: left">
<el-icon color="#409EFC" style="margin-left: 5px; margin-top: 33px" :size="18" @click="onCopy()">
<div class="float-left cursor-pointer">
<el-icon color="#409EFC" class="ml-1.5 mt-8" :size="18" @click="copyText('1pctl reset domain')">
<DocumentCopy />
</el-icon>
</div>
@ -17,18 +17,7 @@
</template>
<script setup lang="ts" name="404">
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
const onCopy = () => {
let input = document.createElement('input');
input.value = '1pctl reset domain';
document.body.appendChild(input);
input.select();
document.execCommand('Copy');
document.body.removeChild(input);
MsgSuccess(i18n.global.t('commons.msg.copySuccess'));
};
import { copyText } from '@/utils/util';
</script>
<style scoped lang="scss">

View File

@ -6,8 +6,8 @@
<h4>{{ $t('commons.login.errIP1') }}</h4>
<div>
<h4>{{ $t('commons.login.errHelper') }} 1pctl reset ips</h4>
<div style="cursor: pointer; float: left">
<el-icon color="#409EFC" style="margin-left: 5px; margin-top: 33px" :size="18" @click="onCopy()">
<div class="float-left cursor-pointer">
<el-icon color="#409EFC" class="ml-1.5 mt-8" :size="18" @click="copyText('1pctl reset ips')">
<DocumentCopy />
</el-icon>
</div>
@ -17,18 +17,7 @@
</template>
<script setup lang="ts" name="404">
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
const onCopy = () => {
let input = document.createElement('input');
input.value = '1pctl reset ips';
document.body.appendChild(input);
input.select();
document.execCommand('Copy');
document.body.removeChild(input);
MsgSuccess(i18n.global.t('commons.msg.copySuccess'));
};
import { copyText } from '@/utils/util';
</script>
<style scoped lang="scss">

View File

@ -6,8 +6,8 @@
<h4>{{ $t('commons.login.safeEntrance1') }}</h4>
<div>
<h4>{{ $t('commons.login.safeEntrance2') }}</h4>
<div style="cursor: pointer; float: left">
<el-icon color="#409EFC" style="margin-left: 5px; margin-top: 33px" :size="18" @click="onCopy()">
<div class="float-left cursor-pointer">
<el-icon color="#409EFC" class="ml-1.5 mt-8" :size="18" @click="copyText('1pctl user-info')">
<DocumentCopy />
</el-icon>
</div>
@ -17,19 +17,7 @@
</template>
<script setup lang="ts" name="404">
import i18n from '@/lang';
import { MsgError, MsgSuccess } from '@/utils/message';
import useClipboard from 'vue-clipboard3';
const { toClipboard } = useClipboard();
const onCopy = async () => {
try {
await toClipboard('1pctl user-info');
MsgSuccess(i18n.global.t('commons.msg.copySuccess'));
} catch (e) {
MsgError(i18n.global.t('commons.msg.copyFailed'));
}
};
import { copyText } from '@/utils/util';
</script>
<style scoped lang="scss">

View File

@ -5,6 +5,7 @@ import ComplexTable from './complex-table/index.vue';
import ErrPrompt from './error-prompt/index.vue';
import OpDialog from './del-dialog/index.vue';
import Tooltip from '@/components/tooltip/index.vue';
import CopyButton from '@/components/copy-button/index.vue';
export default {
install(app: App) {
app.component(LayoutContent.name, LayoutContent);
@ -13,5 +14,6 @@ export default {
app.component(ErrPrompt.name, ErrPrompt);
app.component(OpDialog.name, OpDialog);
app.component(Tooltip.name, Tooltip);
app.component(CopyButton.name, CopyButton);
},
};

View File

@ -393,3 +393,9 @@ html {
text-overflow: ellipsis;
white-space: nowrap;
}
.star-center {
height: 16px;
display: inline-block;
vertical-align: middle;
}

View File

@ -1,5 +1,8 @@
import { AcmeAccountTypes, DNSTypes, KeyTypes } from '@/global/mimetype';
import i18n from '@/lang';
import useClipboard from 'vue-clipboard3';
const { toClipboard } = useClipboard();
import { MsgError, MsgSuccess } from '@/utils/message';
export function deepCopy<T>(obj: any): T {
let newObj: any;
@ -467,3 +470,12 @@ export function getDNSName(type: string) {
}
return '';
}
export async function copyText(content: string) {
try {
await toClipboard(content);
MsgSuccess(i18n.global.t('commons.msg.copySuccess'));
} catch (e) {
MsgError(i18n.global.t('commons.msg.copyFailed'));
}
}

View File

@ -10,7 +10,7 @@
<el-tag>
{{ form.serviceName + ':3306' }}
</el-tag>
<el-button @click="onCopy(form.serviceName + ':3306')" icon="DocumentCopy" link></el-button>
<CopyButton :content="form.serviceName + ':3306'" type="icon" />
<span class="input-help">
{{ $t('database.containerConnHelper') }}
</span>
@ -20,11 +20,7 @@
<el-tag>{{ loadConnInfo(true).substring(0, 48) }}...</el-tag>
</el-tooltip>
<el-tag v-else>{{ loadConnInfo(true) }}</el-tag>
<el-button
@click="onCopy(form.systemIP + ':' + form.port)"
icon="DocumentCopy"
link
></el-button>
<CopyButton :content="form.systemIP + ':' + form.port" type="icon" />
<span class="input-help">{{ $t('database.remoteConnHelper2') }}</span>
</el-form-item>
@ -37,11 +33,12 @@
<el-form-item :label="$t('database.rootPassword')" :rules="Rules.paramComplexity" prop="password">
<el-input type="password" show-password clearable v-model="form.password">
<template #append>
<el-button @click="onCopy(form.password)">{{ $t('commons.button.copy') }}</el-button>
<el-divider direction="vertical" />
<el-button @click="random">
{{ $t('commons.button.random') }}
</el-button>
<el-button-group>
<CopyButton :content="form.password" />
<el-button @click="random">
{{ $t('commons.button.random') }}
</el-button>
</el-button-group>
</template>
</el-input>
</el-form-item>
@ -58,19 +55,15 @@
<el-tag>{{ loadConnInfo(false).substring(0, 48) }}...</el-tag>
</el-tooltip>
<el-tag v-else>{{ loadConnInfo(false) }}</el-tag>
<el-button
@click="onCopy(form.remoteIP + ':' + form.port)"
icon="DocumentCopy"
link
></el-button>
<CopyButton :content="form.remoteIP + ':' + form.port" type="icon" />
</el-form-item>
<el-form-item :label="$t('commons.login.username')">
<el-tag>{{ form.username }}</el-tag>
<el-button @click="onCopy(form.username)" icon="DocumentCopy" link></el-button>
<CopyButton :content="form.username" type="icon" />
</el-form-item>
<el-form-item :label="$t('commons.login.password')">
<el-tag>{{ form.password }}</el-tag>
<el-button @click="onCopy(form.password)" icon="DocumentCopy" link></el-button>
<CopyButton :content="form.password" type="icon" />
</el-form-item>
</el-col>
</el-row>
@ -101,11 +94,9 @@ import { getDatabase, loadRemoteAccess, updateMysqlAccess, updateMysqlPassword }
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
import { GetAppConnInfo } from '@/api/modules/app';
import DrawerHeader from '@/components/drawer-header/index.vue';
import { MsgError, MsgSuccess } from '@/utils/message';
import { MsgSuccess } from '@/utils/message';
import { getRandomStr } from '@/utils/util';
import { getSettingInfo } from '@/api/modules/setting';
import useClipboard from 'vue-clipboard3';
const { toClipboard } = useClipboard();
const loading = ref(false);
@ -156,15 +147,6 @@ const random = async () => {
form.password = getRandomStr(16);
};
const onCopy = async (value: string) => {
try {
await toClipboard(value);
MsgSuccess(i18n.global.t('commons.msg.copySuccess'));
} catch (e) {
MsgError(i18n.global.t('commons.msg.copyFailed'));
}
};
const handleClose = () => {
dialogVisible.value = false;
};

View File

@ -112,27 +112,31 @@
<el-table-column :label="$t('commons.login.username')" prop="username" />
<el-table-column :label="$t('commons.login.password')" prop="password">
<template #default="{ row }">
<div v-if="row.password">
<span style="float: left; line-height: 25px" v-if="!row.showPassword">***********</span>
<div style="cursor: pointer; float: left" v-if="!row.showPassword">
<el-icon
style="margin-left: 5px; margin-top: 3px"
@click="row.showPassword = true"
:size="16"
>
<View />
</el-icon>
<div class="flex items-center" v-if="row.password">
<div class="star-center" v-if="!row.showPassword">
<span>**********</span>
</div>
<span style="float: left" v-if="row.showPassword">{{ row.password }}</span>
<div style="cursor: pointer; float: left" v-if="row.showPassword">
<el-icon class="iconInTable" @click="row.showPassword = false" :size="16">
<Hide />
</el-icon>
<div>
<span v-if="row.showPassword">
{{ row.password }}
</span>
</div>
<div style="cursor: pointer; float: left">
<el-icon class="iconInTable" :size="16" @click="onCopy(row)">
<DocumentCopy />
</el-icon>
<el-button
v-if="!row.showPassword"
link
@click="row.showPassword = true"
icon="View"
class="ml-1.5"
></el-button>
<el-button
v-if="row.showPassword"
link
@click="row.showPassword = false"
icon="Hide"
class="ml-1.5"
></el-button>
<div>
<CopyButton :content="row.password" type="icon" />
</div>
</div>
<div v-else>
@ -240,9 +244,7 @@ import { Database } from '@/api/interface/database';
import { App } from '@/api/interface/app';
import { GetAppPort } from '@/api/modules/app';
import router from '@/routers';
import { MsgError, MsgSuccess } from '@/utils/message';
import useClipboard from 'vue-clipboard3';
const { toClipboard } = useClipboard();
import { MsgSuccess } from '@/utils/message';
import { GlobalStore } from '@/store';
const globalStore = GlobalStore();
@ -452,16 +454,6 @@ const loadDBOptions = async () => {
search();
}
};
const onCopy = async (row: any) => {
try {
await toClipboard(row.password);
MsgSuccess(i18n.global.t('commons.msg.copySuccess'));
} catch (e) {
MsgError(i18n.global.t('commons.msg.copyFailed'));
}
};
const onDelete = async (row: Database.MysqlDBInfo) => {
let param = {
id: row.id,

View File

@ -33,31 +33,31 @@
<el-table-column :label="$t('commons.login.username')" prop="username" />
<el-table-column :label="$t('commons.login.password')" prop="password">
<template #default="{ row }">
<div>
<span style="float: left; line-height: 25px" v-if="!row.showPassword">***********</span>
<div style="cursor: pointer; float: left" v-if="!row.showPassword">
<el-icon
style="margin-left: 5px; margin-top: 3px"
@click="row.showPassword = true"
:size="16"
>
<View />
</el-icon>
<div class="flex items-center">
<div class="star-center">
<span v-if="!row.showPassword">**********</span>
</div>
<span style="float: left" v-if="row.showPassword">{{ row.password }}</span>
<div style="cursor: pointer; float: left" v-if="row.showPassword">
<el-icon
style="margin-left: 5px; margin-top: 3px"
@click="row.showPassword = false"
:size="16"
>
<Hide />
</el-icon>
<div>
<span v-if="row.showPassword">
{{ row.password }}
</span>
</div>
<div style="cursor: pointer; float: left">
<el-icon style="margin-left: 5px; margin-top: 3px" :size="16" @click="onCopy(row)">
<DocumentCopy />
</el-icon>
<el-button
v-if="!row.showPassword"
link
@click="row.showPassword = true"
icon="View"
class="ml-1.5"
></el-button>
<el-button
v-if="row.showPassword"
link
@click="row.showPassword = false"
icon="Hide"
class="ml-1.5"
></el-button>
<div>
<CopyButton :content="row.password" type="icon" />
</div>
</div>
</template>
@ -98,10 +98,7 @@ import AppResources from '@/views/database/mysql/check/index.vue';
import OperateDialog from '@/views/database/mysql/remote/operate/index.vue';
import DeleteDialog from '@/views/database/mysql/remote/delete/index.vue';
import i18n from '@/lang';
import { MsgError, MsgSuccess } from '@/utils/message';
import { Database } from '@/api/interface/database';
import useClipboard from 'vue-clipboard3';
const { toClipboard } = useClipboard();
const loading = ref(false);
@ -156,15 +153,6 @@ const onOpenDialog = async (
dialogRef.value!.acceptParams(params);
};
const onCopy = async (row: any) => {
try {
await toClipboard(row.password);
MsgSuccess(i18n.global.t('commons.msg.copySuccess'));
} catch (e) {
MsgError(i18n.global.t('commons.msg.copyFailed'));
}
};
const onDelete = async (row: Database.DatabaseInfo) => {
const res = await deleteCheckDatabase(row.id);
if (res.data && res.data.length > 0) {

View File

@ -10,7 +10,7 @@
<el-tag>
{{ form.serviceName + ':6379' }}
</el-tag>
<el-button @click="onCopy(form.serviceName + ':6379')" icon="DocumentCopy" link></el-button>
<CopyButton :content="form.serviceName + ':6379'" type="icon" />
<span class="input-help">
{{ $t('database.containerConnHelper') }}
</span>
@ -20,17 +20,18 @@
<el-tag>{{ loadConnInfo().substring(0, 48) }}...</el-tag>
</el-tooltip>
<el-tag v-else>{{ loadConnInfo() }}</el-tag>
<el-button @click="onCopy(form.systemIP + ':6379')" icon="DocumentCopy" link></el-button>
<CopyButton :content="form.systemIP + ':6379'" type="icon" />
<span class="input-help">{{ $t('database.remoteConnHelper2') }}</span>
</el-form-item>
<el-form-item :label="$t('commons.login.password')" :rules="Rules.paramComplexity" prop="password">
<el-input type="password" show-password clearable v-model="form.password">
<template #append>
<el-button @click="onCopy(form.password)">{{ $t('commons.button.copy') }}</el-button>
<el-divider direction="vertical" />
<el-button style="margin-left: 1px" @click="random">
{{ $t('commons.button.random') }}
</el-button>
<el-button-group>
<CopyButton :content="form.password" />
<el-button @click="random">
{{ $t('commons.button.random') }}
</el-button>
</el-button-group>
</template>
</el-input>
</el-form-item>
@ -61,13 +62,11 @@ import { ElForm } from 'element-plus';
import { changeRedisPassword } from '@/api/modules/database';
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
import { GetAppConnInfo } from '@/api/modules/app';
import { MsgError, MsgSuccess } from '@/utils/message';
import { MsgSuccess } from '@/utils/message';
import DrawerHeader from '@/components/drawer-header/index.vue';
import { App } from '@/api/interface/app';
import { getRandomStr } from '@/utils/util';
import useClipboard from 'vue-clipboard3';
import { getSettingInfo } from '@/api/modules/setting';
const { toClipboard } = useClipboard();
const loading = ref(false);
@ -100,15 +99,6 @@ const random = async () => {
form.value.password = getRandomStr(16);
};
const onCopy = async (value: string) => {
try {
await toClipboard(value);
MsgSuccess(i18n.global.t('commons.msg.copySuccess'));
} catch (e) {
MsgError(i18n.global.t('commons.msg.copyFailed'));
}
};
const loadPassword = async () => {
const res = await GetAppConnInfo('redis', '');
const settingInfoRes = await getSettingInfo();

View File

@ -304,13 +304,13 @@ import {
RemoveFavorite,
SearchFavorite,
} from '@/api/modules/files';
import { computeSize, dateFormat, downloadFile, getIcon, getRandomStr } from '@/utils/util';
import { computeSize, copyText, dateFormat, downloadFile, getIcon, getRandomStr } from '@/utils/util';
import { StarFilled, Star } from '@element-plus/icons-vue';
import { File } from '@/api/interface/file';
import { Mimetypes, Languages } from '@/global/mimetype';
import { useRouter } from 'vue-router';
import { Back, Refresh } from '@element-plus/icons-vue';
import { MsgSuccess, MsgWarning } from '@/utils/message';
import { MsgWarning } from '@/utils/message';
import { useSearchable } from './hooks/searchable';
import { ResultData } from '@/api/interface';
import { GlobalStore } from '@/store';
@ -466,13 +466,7 @@ const open = async (row: File.File) => {
const copyDir = (row: File.File) => {
if (row?.path) {
const input = document.createElement('textarea');
input.value = row?.path;
document.body.appendChild(input);
input.select();
document.execCommand('copy');
document.body.removeChild(input);
MsgSuccess(i18n.global.t('commons.msg.copySuccess'));
copyText(row?.path);
}
};

View File

@ -68,13 +68,11 @@
import { generateSecret, loadSecret } from '@/api/modules/host';
import { Rules } from '@/global/form-rules';
import i18n from '@/lang';
import { MsgError, MsgSuccess } from '@/utils/message';
import { dateFormatForName, getRandomStr } from '@/utils/util';
import useClipboard from 'vue-clipboard3';
import { MsgSuccess } from '@/utils/message';
import { copyText, dateFormatForName, getRandomStr } from '@/utils/util';
import { FormInstance } from 'element-plus';
import DrawerHeader from '@/components/drawer-header/index.vue';
import { reactive, ref } from 'vue';
const { toClipboard } = useClipboard();
const loading = ref();
const drawerVisible = ref();
@ -118,12 +116,7 @@ const onLoadSecret = async () => {
};
const onCopy = async (str: string) => {
try {
await toClipboard(str);
MsgSuccess(i18n.global.t('commons.msg.copySuccess'));
} catch (e) {
MsgError(i18n.global.t('commons.msg.copyFailed'));
}
copyText(str);
};
const onGenerate = async (formEl: FormInstance | undefined) => {

View File

@ -37,19 +37,10 @@
</ul>
</el-form-item>
<el-form-item :label="$t('setting.mfaHelper2')">
<el-image style="width: 120px; height: 120px" :src="qrImage" />
<span class="input-help">
<span style="float: left">{{ $t('setting.secret') }}: {{ form.secret }}</span>
<div style="float: left; margin-top: 2px">
<el-icon
color="#409EFC"
style="cursor: pointer; margin-left: 10px"
:size="18"
@click="onCopy()"
>
<DocumentCopy />
</el-icon>
</div>
<el-image class="w-32 h-32" :src="qrImage" />
<span class="input-help flex items-center">
<span>{{ $t('setting.secret') }}: {{ form.secret }}</span>
<CopyButton :content="form.secret" type="icon" />
</span>
</el-form-item>
<el-form-item :label="$t('commons.table.title')" prop="title">
@ -94,11 +85,9 @@ import { bindMFA, loadMFA } from '@/api/modules/setting';
import { reactive, ref } from 'vue';
import { Rules, checkNumberRange } from '@/global/form-rules';
import i18n from '@/lang';
import { MsgError, MsgSuccess } from '@/utils/message';
import { MsgSuccess } from '@/utils/message';
import { FormInstance } from 'element-plus';
import DrawerHeader from '@/components/drawer-header/index.vue';
import useClipboard from 'vue-clipboard3';
const { toClipboard } = useClipboard();
const loading = ref();
const qrImage = ref();
@ -128,15 +117,6 @@ const acceptParams = (params: DialogProps): void => {
drawerVisible.value = true;
};
const onCopy = async () => {
try {
await toClipboard(form.secret);
MsgSuccess(i18n.global.t('commons.msg.copySuccess'));
} catch (e) {
MsgError(i18n.global.t('commons.msg.copyFailed'));
}
};
const loadMfaCodeBefore = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
const result = await formEl.validateField('interval', callback);

View File

@ -15,8 +15,18 @@
<span>{{ $t('ssl.dnsResolveHelper') }}</span>
<el-table :data="dnsResolve" border :table-layout="'auto'">
<el-table-column prop="domain" :label="$t('website.domain')" />
<el-table-column prop="resolve" :label="$t('ssl.resolveDomain')" />
<el-table-column prop="value" :label="$t('ssl.value')" />
<el-table-column prop="resolve" :label="$t('ssl.resolveDomain')">
<template #default="{ row }">
<span>{{ row.resolve }}</span>
<CopyButton :content="row.value" type="icon" />
</template>
</el-table-column>
<el-table-column prop="value" :label="$t('ssl.value')">
<template #default="{ row }">
<span>{{ row.value }}</span>
<CopyButton :content="row.value" type="icon" />
</template>
</el-table-column>
<el-table-column :label="$t('commons.table.type')">TXT</el-table-column>
</el-table>
</div>

View File

@ -38,7 +38,7 @@
<el-input v-model="ca.csr" :autosize="{ minRows: 15, maxRows: 30 }" type="textarea" id="textArea" />
<div>
<br />
<el-button type="primary" @click="copyText(ca.csr)">{{ $t('file.copy') }}</el-button>
<CopyButton :content="ca.csr" />
</div>
</div>
<div v-else class="mt-5">
@ -50,7 +50,7 @@
/>
<div>
<br />
<el-button type="primary" @click="copyText(ca.privateKey)">{{ $t('file.copy') }}</el-button>
<CopyButton :content="ca.privateKey" />
</div>
</div>
</div>
@ -60,10 +60,6 @@
import DrawerHeader from '@/components/drawer-header/index.vue';
import { GetCA } from '@/api/modules/website';
import { ref } from 'vue';
import i18n from '@/lang';
import useClipboard from 'vue-clipboard3';
import { MsgError, MsgSuccess } from '@/utils/message';
const { toClipboard } = useClipboard();
const open = ref(false);
const id = ref(0);
@ -88,15 +84,6 @@ const get = async () => {
ca.value = res.data;
};
const copyText = async (msg) => {
try {
await toClipboard(msg);
MsgSuccess(i18n.global.t('commons.msg.copySuccess'));
} catch (e) {
MsgError(i18n.global.t('commons.msg.copyFailed'));
}
};
defineExpose({
acceptParams,
});

View File

@ -54,7 +54,7 @@
<el-input v-model="ssl.pem" :autosize="{ minRows: 15, maxRows: 30 }" type="textarea" id="textArea" />
<div>
<br />
<el-button type="primary" @click="copyText(ssl.pem)">{{ $t('file.copy') }}</el-button>
<CopyButton :content="ssl.pem" />
</div>
</div>
<div v-else class="mt-5">
@ -66,7 +66,7 @@
/>
<div>
<br />
<el-button type="primary" @click="copyText(ssl.privateKey)">{{ $t('file.copy') }}</el-button>
<CopyButton :content="ssl.privateKey" />
</div>
</div>
</div>
@ -77,10 +77,6 @@ import DrawerHeader from '@/components/drawer-header/index.vue';
import { GetSSL } from '@/api/modules/website';
import { ref } from 'vue';
import { dateFormatSimple, getProvider } from '@/utils/util';
import i18n from '@/lang';
import useClipboard from 'vue-clipboard3';
import { MsgError, MsgSuccess } from '@/utils/message';
const { toClipboard } = useClipboard();
const open = ref(false);
const id = ref(0);
@ -105,15 +101,6 @@ const get = async () => {
ssl.value = res.data;
};
const copyText = async (msg) => {
try {
await toClipboard(msg);
MsgSuccess(i18n.global.t('commons.msg.copySuccess'));
} catch (e) {
MsgError(i18n.global.t('commons.msg.copyFailed'));
}
};
defineExpose({
acceptParams,
});