feat: 添加预览组件
parent
ff389d988d
commit
6bc11b3c95
|
|
@ -23,6 +23,7 @@
|
|||
"@vueuse/core": "^9.13.0",
|
||||
"axios": "^1.5.0",
|
||||
"dayjs": "^1.11.9",
|
||||
"dplayer": "^1.27.1",
|
||||
"ejs": "^3.1.9",
|
||||
"less": "^4.2.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
|
|
|
|||
|
|
@ -34,6 +34,9 @@ devDependencies:
|
|||
dayjs:
|
||||
specifier: ^1.11.9
|
||||
version: 1.11.9
|
||||
dplayer:
|
||||
specifier: ^1.27.1
|
||||
version: 1.27.1
|
||||
ejs:
|
||||
specifier: ^3.1.9
|
||||
version: 3.1.9
|
||||
|
|
@ -1785,6 +1788,16 @@ packages:
|
|||
engines: {node: '>= 0.4'}
|
||||
dev: true
|
||||
|
||||
/axios@1.2.3:
|
||||
resolution: {integrity: sha512-pdDkMYJeuXLZ6Xj/Q5J3Phpe+jbGdsSzlQaFVkMQzRUL05+6+tetX8TV3p4HrU4kzuO9bt+io/yGQxuyxA/xcw==}
|
||||
dependencies:
|
||||
follow-redirects: 1.15.2
|
||||
form-data: 4.0.0
|
||||
proxy-from-env: 1.1.0
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
dev: true
|
||||
|
||||
/axios@1.5.0:
|
||||
resolution: {integrity: sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==}
|
||||
dependencies:
|
||||
|
|
@ -1807,6 +1820,10 @@ packages:
|
|||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||
dev: true
|
||||
|
||||
/balloon-css@1.2.0:
|
||||
resolution: {integrity: sha512-urXwkHgwp6GsXVF+it01485Z2Cj4pnW02ICnM0TemOlkKmCNnDLmyy+ZZiRXBpwldUXO+aRNr7Hdia4CBvXJ5A==}
|
||||
dev: true
|
||||
|
||||
/base64-js@1.5.1:
|
||||
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
||||
dev: true
|
||||
|
|
@ -2724,6 +2741,16 @@ packages:
|
|||
engines: {node: '>=12'}
|
||||
dev: true
|
||||
|
||||
/dplayer@1.27.1:
|
||||
resolution: {integrity: sha512-2laBMXs5V1B9zPwJ7eAIw/OBo+Xjvy03i4GHTk3Cg+IWbrq8rKMFO0fFr6ClAYotYOCcFGOvaJDkOZcgKllsCA==}
|
||||
dependencies:
|
||||
axios: 1.2.3
|
||||
balloon-css: 1.2.0
|
||||
promise-polyfill: 8.3.0
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
dev: true
|
||||
|
||||
/duplexer@0.1.2:
|
||||
resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
|
||||
dev: true
|
||||
|
|
@ -5475,6 +5502,10 @@ packages:
|
|||
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
|
||||
dev: true
|
||||
|
||||
/promise-polyfill@8.3.0:
|
||||
resolution: {integrity: sha512-H5oELycFml5yto/atYqmjyigJoAo3+OXwolYiH7OfQuYlAqhxNvTfiNMbV9hsC6Yp83yE5r2KTVmtrG6R9i6Pg==}
|
||||
dev: true
|
||||
|
||||
/promise.allsettled@1.0.6:
|
||||
resolution: {integrity: sha512-22wJUOD3zswWFqgwjNHa1965LvqTX87WPu/lreY2KSd7SVcERfuZ4GfUaOnJNnvtoIv2yXT/W00YIGMetXtFXg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,224 @@
|
|||
<template>
|
||||
<teleport to="body">
|
||||
<div
|
||||
v-if="show"
|
||||
ref="viewRef"
|
||||
class="absolute top-0 left-0 w-full h-full flex items-center justify-center bg-[rgba(0,0,0,.6)]"
|
||||
>
|
||||
<div
|
||||
ref="headerRef"
|
||||
class="absolute top-0 left-0 w-full flex items-center justify-between gap-4 bg-[rgba(0,0,0,.3)] h-14 px-6 text-white"
|
||||
>
|
||||
<div>
|
||||
<button
|
||||
@click="onBack"
|
||||
class="select-none bg-transparent text-white h-8 px-2 rounded hover:bg-[rgba(255,255,255,.1)]"
|
||||
>
|
||||
<i class="icon-park-outline-back mr-1"></i>
|
||||
返回
|
||||
</button>
|
||||
<span class="mx-2">|</span>
|
||||
<span class="ml-2 text-base">
|
||||
<slot name="name">
|
||||
<i :class="typeIcon"></i>
|
||||
<span class="ml-2">{{ name }}</span>
|
||||
</slot>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<button v-if="download" class="bg-transparent text-white h-8 px-3 rounded hover:bg-[rgba(255,255,255,.1)]">
|
||||
<i class="icon-park-outline-download mr-1"></i>
|
||||
<span>下载</span>
|
||||
</button>
|
||||
<button class="bg-transparent text-white text-xl w-8 h-8 rounded hover:bg-[rgba(255,255,255,.1)]">
|
||||
<i class="icon-park-outline-more-one"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div v-if="type === ViewType.VIDEO" ref="videoRef" class="w-[1280px]"></div>
|
||||
<div v-else-if="type === ViewType.TEXT" class="w-[1280px] h-[600px] bg-[rgba(0,0,0,.1)] text-white leading-8">
|
||||
<a-scrollbar outer-class="h-full overflow-hidden" class="h-full overflow-auto">
|
||||
<div class="py-4 px-5">
|
||||
{{ url }}
|
||||
</div>
|
||||
</a-scrollbar>
|
||||
</div>
|
||||
<div v-else-if="type === ViewType.IMAGE">
|
||||
<img :src="url" :alt="name" />
|
||||
</div>
|
||||
<div v-else-if="type === ViewType.AUDIO">
|
||||
<div class="audio-player flex items-center gap-4 bg-[rgba(255,255,255,.1)] text-white px-4 py-4">
|
||||
<div
|
||||
@click="playing = !playing"
|
||||
class="hover:bg-[rgba(255,255,255,.1)] h-8 px-1.5 flex items-center justify-center rounded"
|
||||
>
|
||||
<i v-if="playing" class="text-xl icon-park-outline-pause-one"></i>
|
||||
<i v-else class="text-xl icon-park-outline-play"></i>
|
||||
</div>
|
||||
<div>
|
||||
{{ currentFormated }}
|
||||
</div>
|
||||
<div class="w-96">
|
||||
<audio ref="audioRef" src="" class="hidden"></audio>
|
||||
<a-slider class="block!"></a-slider>
|
||||
</div>
|
||||
<div>
|
||||
{{ durationFormated }}
|
||||
</div>
|
||||
<div class="dd">
|
||||
<a-popover>
|
||||
<div
|
||||
@click="onMuteToggle"
|
||||
class="text-xl hover:bg-[rgba(255,255,255,.1)] h-8 px-1.5 flex items-center justify-center rounded"
|
||||
>
|
||||
<i :class="volumeIcon"></i>
|
||||
</div>
|
||||
<template #content>
|
||||
<div class="flex flex-col items-center">
|
||||
<div class="w-6 text-center">
|
||||
{{ volume }}
|
||||
</div>
|
||||
<a-slider class="min-w-auto!" v-model="volume" direction="vertical"></a-slider>
|
||||
</div>
|
||||
</template>
|
||||
</a-popover>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="w-96 text-center bg-[rgba(0,0,0,.1)] text-white px-4 py-8">
|
||||
<div class="">暂不支持该文件类型的预览</div>
|
||||
<div v-if="download" class="mt-4">
|
||||
<button class="text-white h-8 px-3 rounded bg-[rgba(255,255,255,.1)] hover:bg-[rgba(255,255,255,.2)]">
|
||||
<i class="icon-park-outline-download mr-1"></i>
|
||||
<span>下载文件</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="absolute bottom-20"></div>
|
||||
</div>
|
||||
</teleport>
|
||||
</template>
|
||||
|
||||
<script setup lang="tsx">
|
||||
import { getIcon } from '@/pages/content/material/components/util';
|
||||
import { useVModel } from '@vueuse/core';
|
||||
import DPlayer from 'dplayer';
|
||||
import numeral from 'numeral';
|
||||
import { PropType } from 'vue';
|
||||
|
||||
enum ViewType {
|
||||
TEXT = 'text',
|
||||
IMAGE = 'image',
|
||||
AUDIO = 'audio',
|
||||
VIDEO = 'video',
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
type: {
|
||||
type: String as PropType<'text' | 'image' | 'audio' | 'video'>,
|
||||
},
|
||||
url: {
|
||||
type: String,
|
||||
},
|
||||
download: {
|
||||
type: String,
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: '失落的海峡.mp4',
|
||||
},
|
||||
});
|
||||
|
||||
let dplayer: any;
|
||||
const emit = defineEmits(['update:visible']);
|
||||
const show = useVModel(props, 'visible', emit);
|
||||
const headerRef = ref<HTMLElement | null>(null);
|
||||
const viewRef = ref<HTMLElement | null>(null);
|
||||
const videoRef = ref<HTMLElement | null>(null);
|
||||
const onBack = () => (show.value = false);
|
||||
const playing = ref(true);
|
||||
const volume = ref(50);
|
||||
const volumeLast = ref(50);
|
||||
const current = ref(18);
|
||||
const duration = ref(120);
|
||||
|
||||
const currentFormated = computed(() => numeral(current.value).format('0:00'));
|
||||
const durationFormated = computed(() => numeral(duration.value).format('0:00'));
|
||||
|
||||
const volumeIcon = computed(() => {
|
||||
if (volume.value <= 0) {
|
||||
return 'icon-park-outline-volume-mute';
|
||||
} else if (volume.value <= 50) {
|
||||
return 'icon-park-outline-volume-small';
|
||||
} else {
|
||||
return 'icon-park-outline-volume-notice';
|
||||
}
|
||||
});
|
||||
|
||||
const typeIcon = computed(() => {
|
||||
return getIcon(props.type ?? 'text');
|
||||
});
|
||||
|
||||
const onMuteToggle = () => {
|
||||
if (volume.value === 0) {
|
||||
volume.value = volumeLast.value;
|
||||
} else {
|
||||
volumeLast.value = volume.value;
|
||||
volume.value = 0;
|
||||
}
|
||||
};
|
||||
|
||||
const initClickOutside = async () => {
|
||||
await nextTick();
|
||||
viewRef.value?.addEventListener('click', e => {
|
||||
const target = e.target as HTMLElement;
|
||||
if (target?.contains(headerRef.value)) {
|
||||
return;
|
||||
}
|
||||
show.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const loadVideo = async () => {
|
||||
if (dplayer) {
|
||||
dplayer.destroy();
|
||||
}
|
||||
await nextTick();
|
||||
if (!videoRef.value) {
|
||||
return;
|
||||
}
|
||||
dplayer = new DPlayer({
|
||||
container: videoRef.value,
|
||||
video: {
|
||||
url: props.url,
|
||||
},
|
||||
context: [],
|
||||
});
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
val => {
|
||||
if (!val) {
|
||||
dplayer?.destroy();
|
||||
return;
|
||||
}
|
||||
if (props.type === ViewType.VIDEO) {
|
||||
loadVideo();
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
<BreadPage>
|
||||
<template #content>
|
||||
<a-tabs class="tabs-page">
|
||||
<a-tab-pane key="1" title="素材管理">
|
||||
<a-tab-pane key="1" title="全部素材">
|
||||
<div class="overflow-hidden grid grid-cols-[auto_1fr] gap-2 m-4 mt-1">
|
||||
<!-- <AnGroup class="bg-white p-4 w-[242px]" :current="current" @change="onCategoryChange"></AnGroup> -->
|
||||
<div class="bg-white p-4">
|
||||
|
|
|
|||
|
|
@ -1,117 +1,135 @@
|
|||
<template>
|
||||
<div class="m-4 bg-white p-4">
|
||||
<user-table></user-table>
|
||||
<a-button @click="visible = true">预览</a-button>
|
||||
<an-viewer v-model:visible="visible" type="audio" :url="textUrl" :download="'s'" :name="'明日之星.png'"></an-viewer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="tsx">
|
||||
import { api } from '@/api';
|
||||
import { useTable } from '@/components/AnTable';
|
||||
import AnViewer from '@/components/AnViewer/AnViewer.vue';
|
||||
|
||||
const { component: UserTable } = useTable({
|
||||
columns: [
|
||||
{
|
||||
dataIndex: 'id',
|
||||
title: 'ID',
|
||||
configable: false,
|
||||
},
|
||||
{
|
||||
dataIndex: 'nickname',
|
||||
title: '用户名称',
|
||||
},
|
||||
{
|
||||
dataIndex: 'username',
|
||||
title: '登录账号',
|
||||
},
|
||||
{
|
||||
dataIndex: 'email',
|
||||
title: '邮箱',
|
||||
},
|
||||
{
|
||||
dataIndex: 'phone',
|
||||
title: '手机号码',
|
||||
},
|
||||
{
|
||||
dataIndex: 'createdBy',
|
||||
title: '创建人',
|
||||
},
|
||||
{
|
||||
dataIndex: 'createdAt',
|
||||
title: '创建时间',
|
||||
},
|
||||
{
|
||||
dataIndex: 'updatedBy',
|
||||
title: '更新人',
|
||||
},
|
||||
{
|
||||
dataIndex: 'updatedAt',
|
||||
title: '更新时间',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
type: 'button',
|
||||
width: 180,
|
||||
configable: false,
|
||||
buttons: [
|
||||
{
|
||||
type: 'modify',
|
||||
text: '修改',
|
||||
},
|
||||
{
|
||||
text: '移动',
|
||||
disable: () => true,
|
||||
},
|
||||
{
|
||||
type: 'delete',
|
||||
confirm: '确定删除吗?',
|
||||
text: '删除',
|
||||
onClick(props) {
|
||||
const id = props.record.id;
|
||||
return api.user.delUser(id);
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
source: search => {
|
||||
return [];
|
||||
},
|
||||
search: [
|
||||
{
|
||||
field: 'username',
|
||||
label: '用户名称',
|
||||
setter: 'input',
|
||||
},
|
||||
],
|
||||
create: {
|
||||
title: '新增',
|
||||
width: 580,
|
||||
items: [
|
||||
{
|
||||
field: 'title',
|
||||
label: '标题',
|
||||
setter: 'input',
|
||||
},
|
||||
{
|
||||
field: 'title2',
|
||||
label: '标题',
|
||||
setter: 'input',
|
||||
},
|
||||
{
|
||||
field: 'title1',
|
||||
label: '标题',
|
||||
setter: 'input',
|
||||
},
|
||||
],
|
||||
submit: model => {
|
||||
return 1;
|
||||
},
|
||||
},
|
||||
modify: {
|
||||
extend: true,
|
||||
title: '修改',
|
||||
},
|
||||
});
|
||||
const visible = ref(false);
|
||||
const videoUrl = 'https://api.dogecloud.com/player/get.mp4?vcode=5ac682e6f8231991&userId=17&ext=.mp4'
|
||||
const imageUrl =
|
||||
'https://images.unsplash.com/photo-1682687982468-4584ff11f88a?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDF8MHxlZGl0b3JpYWwtZmVlZHwxfHx8ZW58MHx8fHx8';
|
||||
const textUrl = `
|
||||
1. 是非对错,有时只是角度问题。 2. 越在意什么,什么越会折磨你。 3. 反感一个人,连听见名字都恶心。 4.
|
||||
温和久了,稍有脾气就成了恶人。 5. 离去的都是风景,留下的才是人生。 6. 任何安慰都没有自己看透来的奏效。 7.
|
||||
我也想对每个人好,可狼我喂不饱。 8. 友情都存在着吃醋,更别说爱情了。 9. 原有前程可奔赴,亦有岁月可回首。 10.
|
||||
偏见来自无非两个地方:无知和愚蠢。 11. 其实一切的问题,时间已经给了答案。 12.
|
||||
所有偷过的懒,都会变成打脸的巴掌。 13. 信任变得很难,假的和真的越来越像。 14.
|
||||
理性的人适合共事,感性的人适合共处。 15. 没有新故事的人,才会对过去念念不忘。 16.
|
||||
你嘴巴那么毒,内心一定是有很多苦吧。 17. 人生有两次很棒,虚惊一场和失而复得。 18.
|
||||
如果觉得生活苦,那就给自己撒点糖吧。 19. 如果没有见过光明,我本可以忍受黑暗。 20.
|
||||
谁心里没有故事,只不过是学会了控制。 21. 我觉得单身挺好,可是一直却招人讽刺。 22.
|
||||
我欣赏你的直言不讳,但请管好你的嘴。 23. 希望曾经的仰望,都能成为以后的日常。 24.
|
||||
心若没有栖息的地方,到哪里都是流浪。 25. 越长大你越知道,有钱比有什么都舒坦。 26.
|
||||
两个人的沟通,70%是情绪,30%是内容。 27. 不发生点烂事,永远看不清身边人的模样。 28.
|
||||
对于我们最爱的人,不说永远,只说珍惜。 29. 多少次的义无反顾,在时间面前也得认输。 30.
|
||||
我会等,因为最好的东西,总是压轴出场。 31. 幸福是比较级,要有东西垫底才感觉的到。 32.
|
||||
在泥泞的道路上,要保持一颗玩泥巴的心。 33. 这世界上唯一扛得住岁月摧残的就是才华。 34.
|
||||
半山腰总是最挤的,所以你得去山顶看看。 35. 电影是多么慈祥,总是让错过的人重新相逢。 36.
|
||||
哭,并不是因为脆弱,而是因为坚强得太久。 37. 梦想成真之前,它看上去总是那么遥不可及。 38.
|
||||
人生是场荒芜的旅行,冷暖自知,苦乐在心。 39. 如果每个人都理解你,那你得普通成什么样。 40.
|
||||
少又不甘,多又嫌烦,哪有恰到好处的陪伴。 41. 听说过很多减肥方法,依然胖着过完这一生。 42.
|
||||
我不在意你曾堕落,我只在意你是否会崛起。 43. 我可以受十分的苦,但我受不了半分的委屈。 44.
|
||||
我要做个思想上的女流氓,生活上的好菇凉。 45. 小时候我们词不达意,长大后我们言不由衷。 46.
|
||||
心上的纠葛,解的开,是结,解不开,是劫。 47. 因为陌生,所以勇敢;因为距离,所以美丽。 48.
|
||||
这世界是如此喧哗,让沉默的人显得有点傻。 49. 自己生活贫乏的人,才喜欢刺探别人的私事。 50.
|
||||
不讲道理是女人的特权,发脾气是女人的专利。 51. 历史,只有人名真的;小说,只有人名是假的。 52.
|
||||
楼底与楼顶的风景,永远不同,谁也别羡慕谁。 53. 你都从没得到过名利,却跟我说什么淡泊名利。 54.
|
||||
人类的极限是由少数人创造的,不能一概而论。 55. 生活总嘲笑我们太年轻,可青春却不经易老去。 56.
|
||||
水凉了还可以喝,心凉了连说快乐都显得落寞。 57. 我希望躺在向日葵上,即使沮丧也能朝着阳光。 58.
|
||||
喜欢发呆的人,心里一定有另一个纯净的世界。 59. 一个人需要隐藏多少秘密才能巧妙地度过一生。 60.
|
||||
已婚者不安心,未婚者不甘心,旁观者太热心。 61. 长大这两个字连偏旁部首都没有,一看就孤独。
|
||||
1. 是非对错,有时只是角度问题。 2. 越在意什么,什么越会折磨你。 3. 反感一个人,连听见名字都恶心。 4.
|
||||
温和久了,稍有脾气就成了恶人。 5. 离去的都是风景,留下的才是人生。 6. 任何安慰都没有自己看透来的奏效。 7.
|
||||
我也想对每个人好,可狼我喂不饱。 8. 友情都存在着吃醋,更别说爱情了。 9. 原有前程可奔赴,亦有岁月可回首。 10.
|
||||
偏见来自无非两个地方:无知和愚蠢。 11. 其实一切的问题,时间已经给了答案。 12.
|
||||
所有偷过的懒,都会变成打脸的巴掌。 13. 信任变得很难,假的和真的越来越像。 14.
|
||||
理性的人适合共事,感性的人适合共处。 15. 没有新故事的人,才会对过去念念不忘。 16.
|
||||
你嘴巴那么毒,内心一定是有很多苦吧。 17. 人生有两次很棒,虚惊一场和失而复得。 18.
|
||||
如果觉得生活苦,那就给自己撒点糖吧。 19. 如果没有见过光明,我本可以忍受黑暗。 20.
|
||||
谁心里没有故事,只不过是学会了控制。 21. 我觉得单身挺好,可是一直却招人讽刺。 22.
|
||||
我欣赏你的直言不讳,但请管好你的嘴。 23. 希望曾经的仰望,都能成为以后的日常。 24.
|
||||
心若没有栖息的地方,到哪里都是流浪。 25. 越长大你越知道,有钱比有什么都舒坦。 26.
|
||||
两个人的沟通,70%是情绪,30%是内容。 27. 不发生点烂事,永远看不清身边人的模样。 28.
|
||||
对于我们最爱的人,不说永远,只说珍惜。 29. 多少次的义无反顾,在时间面前也得认输。 30.
|
||||
我会等,因为最好的东西,总是压轴出场。 31. 幸福是比较级,要有东西垫底才感觉的到。 32.
|
||||
在泥泞的道路上,要保持一颗玩泥巴的心。 33. 这世界上唯一扛得住岁月摧残的就是才华。 34.
|
||||
半山腰总是最挤的,所以你得去山顶看看。 35. 电影是多么慈祥,总是让错过的人重新相逢。 36.
|
||||
哭,并不是因为脆弱,而是因为坚强得太久。 37. 梦想成真之前,它看上去总是那么遥不可及。 38.
|
||||
人生是场荒芜的旅行,冷暖自知,苦乐在心。 39. 如果每个人都理解你,那你得普通成什么样。 40.
|
||||
少又不甘,多又嫌烦,哪有恰到好处的陪伴。 41. 听说过很多减肥方法,依然胖着过完这一生。 42.
|
||||
我不在意你曾堕落,我只在意你是否会崛起。 43. 我可以受十分的苦,但我受不了半分的委屈。 44.
|
||||
我要做个思想上的女流氓,生活上的好菇凉。 45. 小时候我们词不达意,长大后我们言不由衷。 46.
|
||||
心上的纠葛,解的开,是结,解不开,是劫。 47. 因为陌生,所以勇敢;因为距离,所以美丽。 48.
|
||||
这世界是如此喧哗,让沉默的人显得有点傻。 49. 自己生活贫乏的人,才喜欢刺探别人的私事。 50.
|
||||
不讲道理是女人的特权,发脾气是女人的专利。 51. 历史,只有人名真的;小说,只有人名是假的。 52.
|
||||
楼底与楼顶的风景,永远不同,谁也别羡慕谁。 53. 你都从没得到过名利,却跟我说什么淡泊名利。 54.
|
||||
人类的极限是由少数人创造的,不能一概而论。 55. 生活总嘲笑我们太年轻,可青春却不经易老去。 56.
|
||||
水凉了还可以喝,心凉了连说快乐都显得落寞。 57. 我希望躺在向日葵上,即使沮丧也能朝着阳光。 58.
|
||||
喜欢发呆的人,心里一定有另一个纯净的世界。 59. 一个人需要隐藏多少秘密才能巧妙地度过一生。 60.
|
||||
已婚者不安心,未婚者不甘心,旁观者太热心。 61. 长大这两个字连偏旁部首都没有,一看就孤独。
|
||||
1. 是非对错,有时只是角度问题。 2. 越在意什么,什么越会折磨你。 3. 反感一个人,连听见名字都恶心。 4.
|
||||
温和久了,稍有脾气就成了恶人。 5. 离去的都是风景,留下的才是人生。 6. 任何安慰都没有自己看透来的奏效。 7.
|
||||
我也想对每个人好,可狼我喂不饱。 8. 友情都存在着吃醋,更别说爱情了。 9. 原有前程可奔赴,亦有岁月可回首。 10.
|
||||
偏见来自无非两个地方:无知和愚蠢。 11. 其实一切的问题,时间已经给了答案。 12.
|
||||
所有偷过的懒,都会变成打脸的巴掌。 13. 信任变得很难,假的和真的越来越像。 14.
|
||||
理性的人适合共事,感性的人适合共处。 15. 没有新故事的人,才会对过去念念不忘。 16.
|
||||
你嘴巴那么毒,内心一定是有很多苦吧。 17. 人生有两次很棒,虚惊一场和失而复得。 18.
|
||||
如果觉得生活苦,那就给自己撒点糖吧。 19. 如果没有见过光明,我本可以忍受黑暗。 20.
|
||||
谁心里没有故事,只不过是学会了控制。 21. 我觉得单身挺好,可是一直却招人讽刺。 22.
|
||||
我欣赏你的直言不讳,但请管好你的嘴。 23. 希望曾经的仰望,都能成为以后的日常。 24.
|
||||
心若没有栖息的地方,到哪里都是流浪。 25. 越长大你越知道,有钱比有什么都舒坦。 26.
|
||||
两个人的沟通,70%是情绪,30%是内容。 27. 不发生点烂事,永远看不清身边人的模样。 28.
|
||||
对于我们最爱的人,不说永远,只说珍惜。 29. 多少次的义无反顾,在时间面前也得认输。 30.
|
||||
我会等,因为最好的东西,总是压轴出场。 31. 幸福是比较级,要有东西垫底才感觉的到。 32.
|
||||
在泥泞的道路上,要保持一颗玩泥巴的心。 33. 这世界上唯一扛得住岁月摧残的就是才华。 34.
|
||||
半山腰总是最挤的,所以你得去山顶看看。 35. 电影是多么慈祥,总是让错过的人重新相逢。 36.
|
||||
哭,并不是因为脆弱,而是因为坚强得太久。 37. 梦想成真之前,它看上去总是那么遥不可及。 38.
|
||||
人生是场荒芜的旅行,冷暖自知,苦乐在心。 39. 如果每个人都理解你,那你得普通成什么样。 40.
|
||||
少又不甘,多又嫌烦,哪有恰到好处的陪伴。 41. 听说过很多减肥方法,依然胖着过完这一生。 42.
|
||||
我不在意你曾堕落,我只在意你是否会崛起。 43. 我可以受十分的苦,但我受不了半分的委屈。 44.
|
||||
我要做个思想上的女流氓,生活上的好菇凉。 45. 小时候我们词不达意,长大后我们言不由衷。 46.
|
||||
心上的纠葛,解的开,是结,解不开,是劫。 47. 因为陌生,所以勇敢;因为距离,所以美丽。 48.
|
||||
这世界是如此喧哗,让沉默的人显得有点傻。 49. 自己生活贫乏的人,才喜欢刺探别人的私事。 50.
|
||||
不讲道理是女人的特权,发脾气是女人的专利。 51. 历史,只有人名真的;小说,只有人名是假的。 52.
|
||||
楼底与楼顶的风景,永远不同,谁也别羡慕谁。 53. 你都从没得到过名利,却跟我说什么淡泊名利。 54.
|
||||
人类的极限是由少数人创造的,不能一概而论。 55. 生活总嘲笑我们太年轻,可青春却不经易老去。 56.
|
||||
水凉了还可以喝,心凉了连说快乐都显得落寞。 57. 我希望躺在向日葵上,即使沮丧也能朝着阳光。 58.
|
||||
喜欢发呆的人,心里一定有另一个纯净的世界。 59. 一个人需要隐藏多少秘密才能巧妙地度过一生。 60.
|
||||
已婚者不安心,未婚者不甘心,旁观者太热心。 61. 长大这两个字连偏旁部首都没有,一看就孤独。
|
||||
1. 是非对错,有时只是角度问题。 2. 越在意什么,什么越会折磨你。 3. 反感一个人,连听见名字都恶心。 4.
|
||||
温和久了,稍有脾气就成了恶人。 5. 离去的都是风景,留下的才是人生。 6. 任何安慰都没有自己看透来的奏效。 7.
|
||||
我也想对每个人好,可狼我喂不饱。 8. 友情都存在着吃醋,更别说爱情了。 9. 原有前程可奔赴,亦有岁月可回首。 10.
|
||||
偏见来自无非两个地方:无知和愚蠢。 11. 其实一切的问题,时间已经给了答案。 12.
|
||||
所有偷过的懒,都会变成打脸的巴掌。 13. 信任变得很难,假的和真的越来越像。 14.
|
||||
理性的人适合共事,感性的人适合共处。 15. 没有新故事的人,才会对过去念念不忘。 16.
|
||||
你嘴巴那么毒,内心一定是有很多苦吧。 17. 人生有两次很棒,虚惊一场和失而复得。 18.
|
||||
如果觉得生活苦,那就给自己撒点糖吧。 19. 如果没有见过光明,我本可以忍受黑暗。 20.
|
||||
谁心里没有故事,只不过是学会了控制。 21. 我觉得单身挺好,可是一直却招人讽刺。 22.
|
||||
我欣赏你的直言不讳,但请管好你的嘴。 23. 希望曾经的仰望,都能成为以后的日常。 24.
|
||||
心若没有栖息的地方,到哪里都是流浪。 25. 越长大你越知道,有钱比有什么都舒坦。 26.
|
||||
两个人的沟通,70%是情绪,30%是内容。 27. 不发生点烂事,永远看不清身边人的模样。 28.
|
||||
对于我们最爱的人,不说永远,只说珍惜。 29. 多少次的义无反顾,在时间面前也得认输。 30.
|
||||
我会等,因为最好的东西,总是压轴出场。 31. 幸福是比较级,要有东西垫底才感觉的到。 32.
|
||||
在泥泞的道路上,要保持一颗玩泥巴的心。 33. 这世界上唯一扛得住岁月摧残的就是才华。 34.
|
||||
半山腰总是最挤的,所以你得去山顶看看。 35. 电影是多么慈祥,总是让错过的人重新相逢。 36.
|
||||
哭,并不是因为脆弱,而是因为坚强得太久。 37. 梦想成真之前,它看上去总是那么遥不可及。 38.
|
||||
人生是场荒芜的旅行,冷暖自知,苦乐在心。 39. 如果每个人都理解你,那你得普通成什么样。 40.
|
||||
少又不甘,多又嫌烦,哪有恰到好处的陪伴。 41. 听说过很多减肥方法,依然胖着过完这一生。 42.
|
||||
我不在意你曾堕落,我只在意你是否会崛起。 43. 我可以受十分的苦,但我受不了半分的委屈。 44.
|
||||
我要做个思想上的女流氓,生活上的好菇凉。 45. 小时候我们词不达意,长大后我们言不由衷。 46.
|
||||
心上的纠葛,解的开,是结,解不开,是劫。 47. 因为陌生,所以勇敢;因为距离,所以美丽。 48.
|
||||
这世界是如此喧哗,让沉默的人显得有点傻。 49. 自己生活贫乏的人,才喜欢刺探别人的私事。 50.
|
||||
不讲道理是女人的特权,发脾气是女人的专利。 51. 历史,只有人名真的;小说,只有人名是假的。 52.
|
||||
楼底与楼顶的风景,永远不同,谁也别羡慕谁。 53. 你都从没得到过名利,却跟我说什么淡泊名利。 54.
|
||||
人类的极限是由少数人创造的,不能一概而论。 55. 生活总嘲笑我们太年轻,可青春却不经易老去。 56.
|
||||
水凉了还可以喝,心凉了连说快乐都显得落寞。 57. 我希望躺在向日葵上,即使沮丧也能朝着阳光。 58.
|
||||
喜欢发呆的人,心里一定有另一个纯净的世界。 59. 一个人需要隐藏多少秘密才能巧妙地度过一生。 60.
|
||||
已婚者不安心,未婚者不甘心,旁观者太热心。 61. 长大这两个字连偏旁部首都没有,一看就孤独。
|
||||
`;
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -5,59 +5,41 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="tsx">
|
||||
import { api } from '@/api';
|
||||
import { useTable } from '@/components/AnTable';
|
||||
import { dayjs } from '@/libs/dayjs';
|
||||
import { Tag } from '@arco-design/web-vue';
|
||||
import { Image } from '@arco-design/web-vue';
|
||||
import data from './data.json';
|
||||
|
||||
defineOptions({ name: 'SystemLogoPage' });
|
||||
|
||||
const { component: OperationTable } = useTable({
|
||||
columns: [
|
||||
{
|
||||
title: '登陆账号',
|
||||
dataIndex: 'nickname',
|
||||
title: '标题',
|
||||
dataIndex: 'title',
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
title: '操作描述',
|
||||
dataIndex: 'description',
|
||||
render: ({ record: { status, description } }) => {
|
||||
render: ({ record }) => {
|
||||
return (
|
||||
<span>
|
||||
<Tag color={status === null || status ? 'green' : 'red'} class="mr-2">
|
||||
{status === null || status ? '成功' : '失败'}
|
||||
</Tag>
|
||||
{description}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '登陆地址',
|
||||
dataIndex: 'ip',
|
||||
width: 200,
|
||||
render: ({ record }) => `${record.addr || '未知'}(${record.ip})`,
|
||||
},
|
||||
{
|
||||
title: '操作系统',
|
||||
dataIndex: 'os',
|
||||
width: 160,
|
||||
},
|
||||
{
|
||||
title: '浏览器',
|
||||
dataIndex: 'browser',
|
||||
width: 160,
|
||||
},
|
||||
{
|
||||
title: '登陆时间',
|
||||
dataIndex: 'createdAt',
|
||||
width: 120,
|
||||
render: ({ record }) => dayjs(record.createdAt).fromNow(),
|
||||
<div class="flex gap-2">
|
||||
<div>
|
||||
<Image width={188} src={record['cover-src']}></Image>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<a-link href={record['title-href']} target="_blank">
|
||||
{ record.title }
|
||||
</a-link>
|
||||
</div>
|
||||
<div>
|
||||
<a-link href={record['user-href']}>{record.user}</a-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
],
|
||||
source: model => {
|
||||
return api.log.getLoginLogs(model);
|
||||
return data;
|
||||
},
|
||||
search: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { NProgress } from '@/libs/nprogress';
|
||||
import { useAppStore } from '@/store';
|
||||
import { Router } from 'vue-router';
|
||||
import { NProgress } from "@/libs/nprogress";
|
||||
import { useAppStore } from "@/store";
|
||||
import { Router } from "vue-router";
|
||||
|
||||
const routeMap = new Map<string, boolean>();
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ declare module '@vue/runtime-core' {
|
|||
AEmpty: typeof import('@arco-design/web-vue')['Empty']
|
||||
AForm: typeof import('@arco-design/web-vue')['Form']
|
||||
AFormItem: typeof import('@arco-design/web-vue')['FormItem']
|
||||
AImage: typeof import('@arco-design/web-vue')['Image']
|
||||
AImagePreview: typeof import('@arco-design/web-vue')['ImagePreview']
|
||||
AImagePreviewGroup: typeof import('@arco-design/web-vue')['ImagePreviewGroup']
|
||||
AInput: typeof import('@arco-design/web-vue')['Input']
|
||||
|
|
@ -42,6 +43,7 @@ declare module '@vue/runtime-core' {
|
|||
AnEmpty: typeof import('./../components/AnEmpty/AnEmpty.vue')['default']
|
||||
AnForbidden: typeof import('./../components/AnForbidden/AnForbidden.vue')['default']
|
||||
AnToast: typeof import('./../components/AnToast/AnToast.vue')['default']
|
||||
AnViewer: typeof import('./../components/AnViewer/AnViewer.vue')['default']
|
||||
APagination: typeof import('@arco-design/web-vue')['Pagination']
|
||||
APopover: typeof import('@arco-design/web-vue')['Popover']
|
||||
AProgress: typeof import('@arco-design/web-vue')['Progress']
|
||||
|
|
@ -49,6 +51,7 @@ declare module '@vue/runtime-core' {
|
|||
ARadioGroup: typeof import('@arco-design/web-vue')['RadioGroup']
|
||||
AScrollbar: typeof import('@arco-design/web-vue')['Scrollbar']
|
||||
ASelect: typeof import('@arco-design/web-vue')['Select']
|
||||
ASlider: typeof import('@arco-design/web-vue')['Slider']
|
||||
ASpace: typeof import('@arco-design/web-vue')['Space']
|
||||
ASpin: typeof import('@arco-design/web-vue')['Spin']
|
||||
ASwitch: typeof import('@arco-design/web-vue')['Switch']
|
||||
|
|
|
|||
|
|
@ -12,4 +12,9 @@ declare module "numeral" {
|
|||
export default numeral;
|
||||
}
|
||||
|
||||
declare module 'dplayer' {
|
||||
const dp: any;
|
||||
export default dp;
|
||||
}
|
||||
|
||||
type Recordable = Record<string, any>;
|
||||
Loading…
Reference in New Issue