392 lines
10 KiB
Vue
392 lines
10 KiB
Vue
<template>
|
|
<div id="app-container" class="p-3">
|
|
<el-row :gutter="10">
|
|
<el-col :span="1.5">
|
|
<el-button @click="handleAdd" type="primary" size="small" icon="plus"
|
|
>新增
|
|
</el-button>
|
|
</el-col>
|
|
<el-col :span="1.5">
|
|
<el-button
|
|
icon="delete"
|
|
@click="handleDelete()"
|
|
type="danger"
|
|
size="small"
|
|
:disabled="multiple"
|
|
>批量删除
|
|
</el-button>
|
|
</el-col>
|
|
</el-row>
|
|
<el-table
|
|
class="short-link-table"
|
|
:data="shortLinkList"
|
|
@selection-change="handleSelectionChange"
|
|
v-loading
|
|
>
|
|
<el-table-column align="center" type="selection" width="50" />
|
|
<el-table-column
|
|
align="center"
|
|
label="名称"
|
|
prop="name"
|
|
width="120"
|
|
></el-table-column>
|
|
<el-table-column align="center" label="短链接网址" prop="jumpUrl">
|
|
<template #default="{ row }">
|
|
<el-row :gutter="5">
|
|
<el-col :span="18">
|
|
<div>
|
|
<a
|
|
class="short-link"
|
|
:href="`${row.urlPrefix}/dlj/${row.urlSuffix}`"
|
|
>
|
|
{{ row.urlPrefix }}/dlj/{{ row.urlSuffix }}
|
|
</a>
|
|
</div>
|
|
<div class="jump-url">{{ row.jumpUrl }}</div>
|
|
</el-col>
|
|
<el-col :span="6">
|
|
<el-row :gutter="5">
|
|
<el-col :span="1.5">
|
|
<i
|
|
class="iconfont icon-qrcode"
|
|
:style="{
|
|
cursor: 'pointer',
|
|
}"
|
|
@click="handleShowQrCode(row)"
|
|
></i>
|
|
</el-col>
|
|
<el-col :span="1.5">
|
|
<el-icon
|
|
:style="{
|
|
cursor: 'pointer',
|
|
}"
|
|
@click="copyToClipboard(row)"
|
|
>
|
|
<CopyDocument />
|
|
</el-icon>
|
|
</el-col>
|
|
</el-row>
|
|
</el-col>
|
|
</el-row>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="访问次数" width="160" align="center">
|
|
<template #default="{ row }">
|
|
<div class="visit-count">
|
|
<div>
|
|
<span class="title">今日</span>
|
|
<span class="count">{{ row.todayVisit }}</span>
|
|
</div>
|
|
<div>
|
|
<span class="title">累计</span>
|
|
<span class="count">{{ row.historyVisit }}</span>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column
|
|
align="center"
|
|
label="过期时间"
|
|
prop="validityTime"
|
|
></el-table-column>
|
|
<el-table-column align="center" label="操作">
|
|
<template #default="{ row }">
|
|
<el-button
|
|
@click="handleUpdate(row.id)"
|
|
link
|
|
size="small"
|
|
type="warning"
|
|
>编辑
|
|
</el-button>
|
|
<el-button
|
|
@click="handleDelete(row.id)"
|
|
link
|
|
size="small"
|
|
type="danger"
|
|
>删除
|
|
</el-button>
|
|
<el-button
|
|
@click="goLogList(row.urlSuffix)"
|
|
link
|
|
size="small"
|
|
type="primary"
|
|
>访问记录
|
|
</el-button>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
<div class="pagination">
|
|
<el-pagination
|
|
background
|
|
layout="prev, pager, next"
|
|
:page-size="queryParams.pageSize"
|
|
:current-page="queryParams.pageNum"
|
|
@update:current-page="handleCurrentChange"
|
|
:total="total"
|
|
/>
|
|
</div>
|
|
<el-dialog v-model="showEditDialog" title="新增短链接">
|
|
<el-form :model="form" ref="formRef" :rules="rules" :label-width="100">
|
|
<el-form-item label="链接标题" prop="name">
|
|
<el-input placeholder="请输入链接标题" v-model="form.name"></el-input>
|
|
</el-form-item>
|
|
<el-form-item label="跳转链接" prop="jumpUrl">
|
|
<el-input
|
|
placeholder="请输入跳转链接"
|
|
v-model="form.jumpUrl"
|
|
></el-input>
|
|
</el-form-item>
|
|
<el-form-item label="URL前缀" prop="urlPrefix">
|
|
<el-input
|
|
placeholder="请输入URL前缀"
|
|
v-model="form.urlPrefix"
|
|
></el-input>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="有效期" prop="validityTime">
|
|
<el-date-picker
|
|
value-format="YYYY-MM-DD HH:mm:ss"
|
|
v-model="form.validityTime"
|
|
type="datetime"
|
|
placeholder="请选择过期时间"
|
|
/>
|
|
</el-form-item>
|
|
</el-form>
|
|
<template #footer>
|
|
<div class="dialog-footer">
|
|
<el-button type="primary" @click="submitForm">确 定</el-button>
|
|
<el-button @click="showEditDialog = false">取 消</el-button>
|
|
</div>
|
|
</template>
|
|
</el-dialog>
|
|
<el-dialog v-model="showQrCodeDialog" width="320">
|
|
<qrcode-vue
|
|
class="qrcode-canvas"
|
|
:value="qrcodeValue"
|
|
:size="280"
|
|
ref="qrcodeRef"
|
|
:margin="1"
|
|
></qrcode-vue>
|
|
<el-button
|
|
type="primary"
|
|
@click="downloadQrCode"
|
|
:style="{
|
|
width: '100%',
|
|
marginTop: '10px',
|
|
}"
|
|
>下载二维码
|
|
</el-button>
|
|
</el-dialog>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts" name="GenShortLink">
|
|
import {
|
|
addShortLink,
|
|
deleteShortLink,
|
|
getDetailById,
|
|
listShortLink,
|
|
updateShortLink,
|
|
} from "@/api/shortlink";
|
|
import { reactive, ref, toRefs } from "vue";
|
|
import { ElMessage, ElMessageBox } from "element-plus";
|
|
import type { ShortLink } from "@/models/shortLink";
|
|
|
|
import QrcodeVue from "qrcode.vue";
|
|
import { useRouter } from "vue-router";
|
|
|
|
const qrcodeRef = ref();
|
|
const shortLinkList = ref<ShortLink[]>([]);
|
|
const showEditDialog = ref(false);
|
|
const editDialogTitle = ref<string>("");
|
|
const showQrCodeDialog = ref(false);
|
|
const qrcodeValue = ref("");
|
|
const qrcodeFileName = ref("");
|
|
const formRef = ref();
|
|
const data = reactive<{
|
|
queryParams: { pageNum: number; pageSize: number };
|
|
form: ShortLink;
|
|
rules: any;
|
|
}>({
|
|
queryParams: {
|
|
pageNum: 1,
|
|
pageSize: 10,
|
|
},
|
|
form: {},
|
|
rules: {
|
|
name: [
|
|
{
|
|
required: true,
|
|
message: "请输入短链接名称",
|
|
trigger: "blur",
|
|
},
|
|
],
|
|
jumpUrl: [
|
|
{
|
|
required: true,
|
|
message: "请输入短链接",
|
|
trigger: "blur",
|
|
},
|
|
],
|
|
urlPrefix: [
|
|
{
|
|
required: true,
|
|
message: "请输入URL前缀",
|
|
trigger: "blur",
|
|
},
|
|
],
|
|
validityTime: [
|
|
{
|
|
required: true,
|
|
message: "请选择过期时间",
|
|
trigger: "change",
|
|
},
|
|
],
|
|
},
|
|
});
|
|
const { form, queryParams, rules } = toRefs(data);
|
|
const total = ref<number>(0);
|
|
const router = useRouter();
|
|
const getList = async () => {
|
|
const resp = await listShortLink(queryParams.value);
|
|
shortLinkList.value = resp.data.rows;
|
|
total.value = resp.data.total;
|
|
};
|
|
const handleShowQrCode = (data: ShortLink) => {
|
|
qrcodeValue.value = `${data.urlPrefix}/dlj/${data.urlSuffix}`;
|
|
qrcodeFileName.value = `${data.urlSuffix}.png`;
|
|
showQrCodeDialog.value = true;
|
|
};
|
|
const goLogList = (suffix: string) => {
|
|
router.push({
|
|
path: `/log-list/${suffix}`,
|
|
});
|
|
};
|
|
const reset = () => {
|
|
form.value = {
|
|
urlPrefix: "https://chuhuankj.com",
|
|
};
|
|
if (formRef.value) {
|
|
formRef.value.resetFields();
|
|
}
|
|
};
|
|
// 多选框选中数据
|
|
const linkIds = ref<number[]>([]);
|
|
const multiple = ref(true);
|
|
const single = ref(true);
|
|
const downloadQrCode = () => {
|
|
console.log(qrcodeRef.value);
|
|
const qrcodeCanvas: HTMLCanvasElement | null =
|
|
document.querySelector(".qrcode-canvas");
|
|
qrcodeCanvas?.toBlob((blob: Blob | null) => {
|
|
if (blob != null) {
|
|
let aLink = document.createElement("a");
|
|
aLink.download = qrcodeFileName.value;
|
|
aLink.href = URL.createObjectURL(blob);
|
|
aLink.click();
|
|
} else {
|
|
ElMessage.error("下载二维码失败");
|
|
}
|
|
});
|
|
};
|
|
const handleSelectionChange = (selection: ShortLink[]) => {
|
|
linkIds.value = selection.map((item: ShortLink) => item.id!);
|
|
single.value = selection.length != 1;
|
|
multiple.value = !selection.length;
|
|
};
|
|
const copyToClipboard = (data: ShortLink) => {
|
|
navigator.clipboard.writeText(`${data.urlPrefix}/dlj/${data.urlSuffix}`);
|
|
ElMessage.success("短链接已拷贝到剪贴板");
|
|
};
|
|
const handleAdd = () => {
|
|
reset();
|
|
editDialogTitle.value = "新增短链接";
|
|
showEditDialog.value = true;
|
|
};
|
|
const handleUpdate = async (id: number) => {
|
|
reset();
|
|
const { data } = await getDetailById(id);
|
|
form.value = data.data;
|
|
editDialogTitle.value = "修改短链接";
|
|
showEditDialog.value = true;
|
|
};
|
|
const handleDelete = (id?: string) => {
|
|
let ids: string;
|
|
if (id) {
|
|
ids = id;
|
|
} else {
|
|
ids = linkIds.value.join(",");
|
|
}
|
|
ElMessageBox.confirm("确认删除该短链接吗", "删除短链接", {
|
|
type: "warning",
|
|
}).then(async () => {
|
|
await deleteShortLink(ids);
|
|
ElMessage.success("删除短链接成功");
|
|
getList();
|
|
});
|
|
};
|
|
|
|
const submitForm = async () => {
|
|
if (form.value.id) {
|
|
await updateShortLink(form.value);
|
|
ElMessage.success("短链接修改成功");
|
|
showEditDialog.value = false;
|
|
getList();
|
|
} else {
|
|
await addShortLink(form.value);
|
|
ElMessage.success("短链接添加成功");
|
|
showEditDialog.value = false;
|
|
getList();
|
|
}
|
|
};
|
|
const handleCurrentChange = (page: number) => {
|
|
queryParams.value.pageNum = page;
|
|
getList();
|
|
};
|
|
getList();
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
#app-container {
|
|
padding: 20px;
|
|
|
|
a.short-link {
|
|
//overflow: hidden;
|
|
//text-overflow: ellipsis;
|
|
//white-space: nowrap;
|
|
}
|
|
|
|
.jump-url {
|
|
margin-top: 5px;
|
|
font-size: 12px;
|
|
//width: 80%;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.visit-count {
|
|
display: flex;
|
|
flex-direction: column;
|
|
padding: 0 20px;
|
|
|
|
& > div {
|
|
width: 100%;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
}
|
|
}
|
|
|
|
.short-link-table {
|
|
margin-top: 20px;
|
|
}
|
|
|
|
.pagination {
|
|
margin-top: 20px;
|
|
margin-right: 10px;
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
}
|
|
}
|
|
</style>
|