feat: 新增广告
This commit is contained in:
parent
b4d0b576f3
commit
664797ca46
4
.env
4
.env
@ -54,6 +54,6 @@ VITE_STORAGE_PREFIX=sj_
|
|||||||
# used to control whether the program automatically detects updates
|
# used to control whether the program automatically detects updates
|
||||||
VITE_AUTOMATICALLY_DETECT_UPDATE=Y
|
VITE_AUTOMATICALLY_DETECT_UPDATE=Y
|
||||||
|
|
||||||
VITE_UPDATE_NOTIFY=N
|
VITE_UPDATE_NOTIFY=Y
|
||||||
|
|
||||||
VITE_LOGIN_CODE=N
|
VITE_LOGIN_CODE=Y
|
||||||
|
BIN
public/ad-ali-1.png
Normal file
BIN
public/ad-ali-1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 186 KiB |
BIN
public/ad-ali-2.png
Normal file
BIN
public/ad-ali-2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 244 KiB |
BIN
public/ad-tencent-1.png
Normal file
BIN
public/ad-tencent-1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 MiB |
BIN
public/ad-tencent-2.png
Normal file
BIN
public/ad-tencent-2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 903 KiB |
@ -1,13 +1,10 @@
|
|||||||
<script setup lang="tsx">
|
<script setup lang="ts">
|
||||||
import { onMounted, onUnmounted, reactive, ref } from 'vue';
|
import { reactive, ref } from 'vue';
|
||||||
import Vcode from 'vue3-puzzle-vcode';
|
import Vcode from 'vue3-puzzle-vcode';
|
||||||
import { useRoute } from 'vue-router';
|
|
||||||
import { NA } from 'naive-ui';
|
|
||||||
import { md5 } from '@/utils/common';
|
import { md5 } from '@/utils/common';
|
||||||
import { $t } from '@/locales';
|
import { $t } from '@/locales';
|
||||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
||||||
import { useAuthStore } from '@/store/modules/auth';
|
import { useAuthStore } from '@/store/modules/auth';
|
||||||
import SvgIcon from '@/components/custom/svg-icon.vue';
|
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'PwdLogin'
|
name: 'PwdLogin'
|
||||||
@ -40,45 +37,8 @@ async function handleSubmit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const codeShow = ref(false);
|
const codeShow = ref(false);
|
||||||
const starred = ref<boolean>(true);
|
|
||||||
|
|
||||||
const validateCode = async () => {
|
const validateCode = async () => {
|
||||||
if (!starred.value) {
|
|
||||||
window.$dialog?.error({
|
|
||||||
icon: () => {
|
|
||||||
return <SvgIcon icon="material-symbols:favorite" class="color-#f5222d" />;
|
|
||||||
},
|
|
||||||
title: () => {
|
|
||||||
return <>您的支持将是我们前行的动力</>;
|
|
||||||
},
|
|
||||||
content: () => {
|
|
||||||
return (
|
|
||||||
<div class="mt-20px text-base">
|
|
||||||
<div>
|
|
||||||
💖 如果您喜欢 Snail Job,请给它一个
|
|
||||||
<n-a href="https://gitee.com/aizuda/snail-job" target="_blank">
|
|
||||||
 Star
|
|
||||||
</n-a>
|
|
||||||
,您的支持将是我们前行的动力。 👨💻👨💻👨💻
|
|
||||||
</div>
|
|
||||||
<div class="mt-20px">
|
|
||||||
🚀 本系统将在
|
|
||||||
<n-a href="https://gitee.com/aizuda/snail-job" target="_blank">
|
|
||||||
 Star 
|
|
||||||
</n-a>
|
|
||||||
后正常开放展示,感谢您的理解与支持 🙇
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
positiveText: '去 Start',
|
|
||||||
onPositiveClick: () => {
|
|
||||||
window.open('https://gitee.com/aizuda/snail-job', '_blank');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { VITE_LOGIN_CODE } = import.meta.env;
|
const { VITE_LOGIN_CODE } = import.meta.env;
|
||||||
await validate();
|
await validate();
|
||||||
if (VITE_LOGIN_CODE === 'Y') {
|
if (VITE_LOGIN_CODE === 'Y') {
|
||||||
@ -96,110 +56,9 @@ const onSuccess = () => {
|
|||||||
handleSubmit();
|
handleSubmit();
|
||||||
};
|
};
|
||||||
|
|
||||||
const route = useRoute();
|
const codePopoverStytle = {
|
||||||
|
padding: 0
|
||||||
async function userStarred() {
|
};
|
||||||
const accessToken = localStorage.getItem('gitee_access_token');
|
|
||||||
if (!accessToken) {
|
|
||||||
authorize();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const response = await fetch(`https://gitee.com/api/v5/user/starred/aizuda/snail-job?access_token=${accessToken}`);
|
|
||||||
|
|
||||||
if (response.status === 401) {
|
|
||||||
refreshTokenFn();
|
|
||||||
}
|
|
||||||
|
|
||||||
starred.value = response.status === 204;
|
|
||||||
}
|
|
||||||
|
|
||||||
function authorize() {
|
|
||||||
const clientId = 'aae2edfddf290269fe0a756bc1c1ec1614e41dfabdb71c19322293e2b5179377';
|
|
||||||
const redirectUri = 'https://preview.snailjob.opensnail.com/login';
|
|
||||||
// const redirectUri = 'http://localhost:9527/login';
|
|
||||||
location.href = `https://gitee.com/oauth/authorize?client_id=${clientId}&redirect_uri=${redirectUri}&response_type=code&scope=user_info`;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function refreshTokenFn() {
|
|
||||||
const refreshToken = localStorage.getItem('gitee_refresh_token');
|
|
||||||
if (!refreshToken) {
|
|
||||||
authorize();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await fetch('https://gitee.com/oauth/token', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: new Headers({
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}),
|
|
||||||
body: JSON.stringify({
|
|
||||||
grant_type: 'refresh_token',
|
|
||||||
refresh_token: refreshToken
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.status === 401) {
|
|
||||||
localStorage.removeItem('gitee_access_token');
|
|
||||||
localStorage.removeItem('gitee_refresh_token');
|
|
||||||
authorize();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await response.json();
|
|
||||||
|
|
||||||
localStorage.setItem('gitee_access_token', res.access_token);
|
|
||||||
localStorage.setItem('gitee_refresh_token', res.refresh_token);
|
|
||||||
userStarred();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function oauth2() {
|
|
||||||
const code = route.query.code;
|
|
||||||
if (!code) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const response = await fetch('/api/oauth2/login', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: new Headers({
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}),
|
|
||||||
body: JSON.stringify({ code })
|
|
||||||
});
|
|
||||||
|
|
||||||
const res = await response.json();
|
|
||||||
|
|
||||||
if (res.code !== 200) {
|
|
||||||
authorize();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const accessToken = res.data.access_token;
|
|
||||||
const refreshToken = res.data.refresh_token;
|
|
||||||
localStorage.setItem('gitee_access_token', accessToken);
|
|
||||||
localStorage.setItem('gitee_refresh_token', refreshToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleVisibilitychange() {
|
|
||||||
const state = document.visibilityState;
|
|
||||||
if (state === 'visible') {
|
|
||||||
userStarred();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
document.addEventListener('visibilitychange', handleVisibilitychange);
|
|
||||||
});
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
document.removeEventListener('visibilitychange', handleVisibilitychange);
|
|
||||||
});
|
|
||||||
|
|
||||||
async function init() {
|
|
||||||
if (starred.value) return;
|
|
||||||
await oauth2();
|
|
||||||
await userStarred();
|
|
||||||
}
|
|
||||||
|
|
||||||
init();
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -216,15 +75,7 @@ init();
|
|||||||
/>
|
/>
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
<NSpace vertical :size="24">
|
<NSpace vertical :size="24">
|
||||||
<div v-if="!starred" class="flex-col-center justify-between">
|
<NPopover :show="codeShow" row :style="codePopoverStytle">
|
||||||
<div>
|
|
||||||
💖 如果您喜欢 Snail Job,请给它一个
|
|
||||||
<NA href="https://gitee.com/aizuda/snail-job" target="_blank" rel="noopener noreferrer"> Star </NA>
|
|
||||||
,
|
|
||||||
</div>
|
|
||||||
<div>您的支持将是我们前行的动力。 👨💻👨💻👨💻</div>
|
|
||||||
</div>
|
|
||||||
<NPopover :show="codeShow" row>
|
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<NButton type="primary" size="large" round block :loading="authStore.loginLoading" @click="validateCode">
|
<NButton type="primary" size="large" round block :loading="authStore.loginLoading" @click="validateCode">
|
||||||
{{ $t('page.login.common.login') }}
|
{{ $t('page.login.common.login') }}
|
||||||
@ -245,8 +96,4 @@ init();
|
|||||||
</NForm>
|
</NForm>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped></style>
|
||||||
:deep(.n-popover) {
|
|
||||||
padding: 0 !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { fetchCardCount } from '@/service/api';
|
import { fetchCardCount } from '@/service/api';
|
||||||
import HeaderBanner from './modules/header-banner.vue';
|
// import HeaderBanner from './modules/header-banner.vue';
|
||||||
import CardData from './modules/card-data.vue';
|
import CardData from './modules/card-data.vue';
|
||||||
import TaskTab from './modules/task-tab.vue';
|
import TaskTab from './modules/task-tab.vue';
|
||||||
|
import AdCarousel from './modules/ad-carousel.vue';
|
||||||
|
|
||||||
const cardCount = ref<Api.Dashboard.CardCount>();
|
const cardCount = ref<Api.Dashboard.CardCount>();
|
||||||
|
|
||||||
@ -19,7 +20,7 @@ getCardData();
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NSpace vertical :size="16" class="home-main">
|
<NSpace vertical :size="16" class="home-main">
|
||||||
<HeaderBanner />
|
<AdCarousel />
|
||||||
<CardData v-model="cardCount!" />
|
<CardData v-model="cardCount!" />
|
||||||
<NCard :bordered="false" class="card-wrapper p-t-136px 2xl:p-t-0 lg:p-t-36px md:p-t-90px">
|
<NCard :bordered="false" class="card-wrapper p-t-136px 2xl:p-t-0 lg:p-t-36px md:p-t-90px">
|
||||||
<TaskTab v-model="cardCount!" />
|
<TaskTab v-model="cardCount!" />
|
||||||
|
155
src/views/home/modules/ad-carousel.vue
Normal file
155
src/views/home/modules/ad-carousel.vue
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import { useAppStore } from '@/store/modules/app';
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'AdCarousel'
|
||||||
|
});
|
||||||
|
|
||||||
|
const appStore = useAppStore();
|
||||||
|
|
||||||
|
const gap = computed(() => (appStore.isMobile ? 0 : 16));
|
||||||
|
|
||||||
|
const href = (url: string) => {
|
||||||
|
window.open(url, '_blank');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive>
|
||||||
|
<NGi class="flex-center" span="24 l:12">
|
||||||
|
<NCard title="广告" :bordered="false" class="w-1000px card-wrapper">
|
||||||
|
<template #header-extra>❤️ 开源不易,敬请谅解 ❤️</template>
|
||||||
|
<NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive>
|
||||||
|
<NGi class="flex-center" span="24 s:9">
|
||||||
|
<NCarousel
|
||||||
|
autoplay
|
||||||
|
direction="vertical"
|
||||||
|
dot-type="line"
|
||||||
|
dot-placement="left"
|
||||||
|
class="h-130px w-260px"
|
||||||
|
:interval="3000"
|
||||||
|
mousewheel
|
||||||
|
>
|
||||||
|
<NCarouselItem>
|
||||||
|
<NA href="https://curl.qcloud.com/2j1RuHbf" target="_blank" rel="noopener noreferrer">
|
||||||
|
<img class="carousel-img" src="/ad-tencent-1.png" />
|
||||||
|
</NA>
|
||||||
|
</NCarouselItem>
|
||||||
|
<NCarouselItem>
|
||||||
|
<NA href="https://curl.qcloud.com/HvUPpDGE" target="_blank" rel="noopener noreferrer">
|
||||||
|
<img class="carousel-img" src="/ad-tencent-2.png" />
|
||||||
|
</NA>
|
||||||
|
</NCarouselItem>
|
||||||
|
</NCarousel>
|
||||||
|
</NGi>
|
||||||
|
<NGi class="flex-center" span="24 s:15">
|
||||||
|
<NCarousel
|
||||||
|
autoplay
|
||||||
|
direction="vertical"
|
||||||
|
dot-type="line"
|
||||||
|
dot-placement="left"
|
||||||
|
class="h-130px w-500px"
|
||||||
|
:interval="3000"
|
||||||
|
mousewheel
|
||||||
|
>
|
||||||
|
<NCarouselItem>
|
||||||
|
<NA
|
||||||
|
href="https://www.aliyun.com/daily-act/ecs/activity_selection?userCode=4rntegyg"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
<img class="carousel-img" src="/ad-ali-1.png" />
|
||||||
|
</NA>
|
||||||
|
</NCarouselItem>
|
||||||
|
<NCarouselItem>
|
||||||
|
<NA
|
||||||
|
href="https://www.aliyun.com/daily-act/ecs/ecs_trial_benefits?userCode=4rntegyg"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
<img class="carousel-img" src="/ad-ali-2.png" />
|
||||||
|
</NA>
|
||||||
|
</NCarouselItem>
|
||||||
|
</NCarousel>
|
||||||
|
</NGi>
|
||||||
|
</NGrid>
|
||||||
|
</NCard>
|
||||||
|
</NGi>
|
||||||
|
<NGi class="flex-center" span="24 l:12">
|
||||||
|
<NCard title="赞助商" :bordered="false" class="card-wrapper">
|
||||||
|
<template #header-extra>
|
||||||
|
❤️
|
||||||
|
<NButton text @click="href('https://snailjob.opensnail.com/docs/sponsor.html')">成为赞助商</NButton>
|
||||||
|
❤️
|
||||||
|
</template>
|
||||||
|
<NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive>
|
||||||
|
<NGi class="h-130px w-250px flex-center" span="24 s:12">
|
||||||
|
<div class="float-right max-w-250px w-full flex flex-col-reverse">
|
||||||
|
<div class="order-9999 m-6px max-w-240px text-13px color-gray">
|
||||||
|
<span>官号</span>
|
||||||
|
</div>
|
||||||
|
<NButton quaternary class="h-full" @click="href('https://space.bilibili.com/3493144058399579')">
|
||||||
|
<NThing class="max-w-full flex-center">
|
||||||
|
<template #avatar>
|
||||||
|
<SvgIcon class="text-66px color-#00aeec" local-icon="bilibili" />
|
||||||
|
</template>
|
||||||
|
<template #header>
|
||||||
|
<div class="bilibili-title color-#00aeec font-semibold">Open Snail</div>
|
||||||
|
<div class="flow-long-title ml-3px font-semibold">bilibili 官方账号</div>
|
||||||
|
</template>
|
||||||
|
</NThing>
|
||||||
|
</NButton>
|
||||||
|
</div>
|
||||||
|
</NGi>
|
||||||
|
<NGi class="h-130px w-250px flex-center" span="24 s:12">
|
||||||
|
<div class="float-right max-w-250px w-full flex flex-col-reverse">
|
||||||
|
<div class="order-9999 m-6px max-w-240px text-13px color-gray">
|
||||||
|
<span>赞助商</span>
|
||||||
|
</div>
|
||||||
|
<NButton quaternary class="h-full" @click="href('https://doc.flowlong.com/?from=snail-job')">
|
||||||
|
<NThing class="max-w-full flex-center">
|
||||||
|
<template #avatar>
|
||||||
|
<SvgIcon class="text-66px" local-icon="flowlong" />
|
||||||
|
</template>
|
||||||
|
<template #header>
|
||||||
|
<div class="flow-long-title-color font-semibold">FlowLong</div>
|
||||||
|
<div class="flow-long-title font-semibold">飞龙工作流引擎</div>
|
||||||
|
</template>
|
||||||
|
</NThing>
|
||||||
|
</NButton>
|
||||||
|
</div>
|
||||||
|
</NGi>
|
||||||
|
</NGrid>
|
||||||
|
</NCard>
|
||||||
|
</NGi>
|
||||||
|
</NGrid>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.carousel-img {
|
||||||
|
height: 130px;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flow-long-title-color {
|
||||||
|
text-align: left;
|
||||||
|
line-height: 36px;
|
||||||
|
font-size: 28px;
|
||||||
|
background: -webkit-linear-gradient(120deg, #bd34fe 30%, #41d1ff);
|
||||||
|
background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flow-long-title {
|
||||||
|
text-align: left;
|
||||||
|
line-height: 22px;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bilibili-title {
|
||||||
|
text-align: cneter;
|
||||||
|
line-height: 36px;
|
||||||
|
font-size: 26px;
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in New Issue
Block a user