mirror of
https://github.com/nagisa77/OpenIsle.git
synced 2026-08-10 05:10:59 +00:00
fix: setup 迁移完成 v1
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
NUXT_PUBLIC_API_BASE_URL=https://www.open-isle.com
|
NUXT_PUBLIC_API_BASE_URL=https://www.open-isle.com
|
||||||
|
NUXT_PUBLIC_WEBSITE_BASE_URL=https://www.open-isle.com
|
||||||
NUXT_PUBLIC_GOOGLE_CLIENT_ID=777830451304-xxx.apps.googleusercontent.com
|
NUXT_PUBLIC_GOOGLE_CLIENT_ID=777830451304-xxx.apps.googleusercontent.com
|
||||||
NUXT_PUBLIC_GITHUB_CLIENT_ID=Ov23liVkO1NPAX5JyWxJ
|
NUXT_PUBLIC_GITHUB_CLIENT_ID=Ov23liVkO1NPAX5JyWxJ
|
||||||
NUXT_PUBLIC_DISCORD_CLIENT_ID=1394985417044000779
|
NUXT_PUBLIC_DISCORD_CLIENT_ID=1394985417044000779
|
||||||
|
|||||||
@@ -11,29 +11,20 @@
|
|||||||
</BasePopup>
|
</BasePopup>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import BasePopup from '~/components/BasePopup.vue'
|
import BasePopup from '~/components/BasePopup.vue'
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
|
|
||||||
export default {
|
const props = defineProps({
|
||||||
name: 'ActivityPopup',
|
visible: { type: Boolean, default: false },
|
||||||
components: { BasePopup },
|
icon: String,
|
||||||
props: {
|
text: String,
|
||||||
visible: { type: Boolean, default: false },
|
})
|
||||||
icon: String,
|
const emit = defineEmits(['close'])
|
||||||
text: String,
|
const gotoActivity = async () => {
|
||||||
},
|
emit('close')
|
||||||
emits: ['close'],
|
await navigateTo('/activities', { replace: true })
|
||||||
setup(props, { emit }) {
|
|
||||||
const router = useRouter()
|
|
||||||
const gotoActivity = () => {
|
|
||||||
emit('close')
|
|
||||||
router.push('/activities')
|
|
||||||
}
|
|
||||||
const close = () => emit('close')
|
|
||||||
return { gotoActivity, close }
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
const close = () => emit('close')
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -12,25 +12,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import { useRouter } from 'vue-router'
|
const props = defineProps({
|
||||||
|
category: { type: Object, default: null },
|
||||||
|
})
|
||||||
|
|
||||||
export default {
|
const gotoCategory = async () => {
|
||||||
name: 'ArticleCategory',
|
if (!props.category) return
|
||||||
props: {
|
const value = encodeURIComponent(props.category.id ?? props.category.name)
|
||||||
category: { type: Object, default: null },
|
await navigateTo({ path: '/', query: { category: value } }, { replace: true })
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const router = useRouter()
|
|
||||||
const gotoCategory = () => {
|
|
||||||
if (!props.category) return
|
|
||||||
const value = encodeURIComponent(props.category.id ?? props.category.name)
|
|
||||||
router.push({ path: '/', query: { category: value } }).then(() => {
|
|
||||||
window.location.reload()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return { gotoCategory }
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -17,24 +17,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import { useRouter } from 'vue-router'
|
defineProps({
|
||||||
|
tags: { type: Array, default: () => [] },
|
||||||
|
})
|
||||||
|
|
||||||
export default {
|
const gotoTag = async (tag) => {
|
||||||
name: 'ArticleTags',
|
const value = encodeURIComponent(tag.id ?? tag.name)
|
||||||
props: {
|
await navigateTo({ path: '/', query: { tags: value } }, { replace: true })
|
||||||
tags: { type: Array, default: () => [] },
|
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
const router = useRouter()
|
|
||||||
const gotoTag = (tag) => {
|
|
||||||
const value = encodeURIComponent(tag.id ?? tag.name)
|
|
||||||
router.push({ path: '/', query: { tags: value } }).then(() => {
|
|
||||||
window.location.reload()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return { gotoTag }
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref, watch } from 'vue'
|
import { computed, ref, watch } from 'vue'
|
||||||
import VueEasyLightbox from 'vue-easy-lightbox'
|
import VueEasyLightbox from 'vue-easy-lightbox'
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
import { toast } from '~/main'
|
import { toast } from '~/main'
|
||||||
import { authState, getToken } from '~/utils/auth'
|
import { authState, getToken } from '~/utils/auth'
|
||||||
import { handleMarkdownClick, renderMarkdown } from '~/utils/markdown'
|
import { handleMarkdownClick, renderMarkdown } from '~/utils/markdown'
|
||||||
@@ -121,7 +120,6 @@ const props = defineProps({
|
|||||||
|
|
||||||
const emit = defineEmits(['deleted'])
|
const emit = defineEmits(['deleted'])
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
const showReplies = ref(props.level === 0 ? true : props.defaultShowReplies)
|
const showReplies = ref(props.level === 0 ? true : props.defaultShowReplies)
|
||||||
watch(
|
watch(
|
||||||
() => props.defaultShowReplies,
|
() => props.defaultShowReplies,
|
||||||
@@ -237,11 +235,11 @@ const submitReply = async (parentUserName, text, clear) => {
|
|||||||
reply: [],
|
reply: [],
|
||||||
openReplies: false,
|
openReplies: false,
|
||||||
src: r.author.avatar,
|
src: r.author.avatar,
|
||||||
iconClick: () => router.push(`/users/${r.author.id}`),
|
iconClick: () => navigateTo(`/users/${r.author.id}`),
|
||||||
})),
|
})),
|
||||||
openReplies: false,
|
openReplies: false,
|
||||||
src: data.author.avatar,
|
src: data.author.avatar,
|
||||||
iconClick: () => router.push(`/users/${data.author.id}`),
|
iconClick: () => navigateTo(`/users/${data.author.id}`),
|
||||||
})
|
})
|
||||||
clear()
|
clear()
|
||||||
showEditor.value = false
|
showEditor.value = false
|
||||||
|
|||||||
@@ -15,9 +15,11 @@
|
|||||||
import ActivityPopup from '~/components/ActivityPopup.vue'
|
import ActivityPopup from '~/components/ActivityPopup.vue'
|
||||||
import MedalPopup from '~/components/MedalPopup.vue'
|
import MedalPopup from '~/components/MedalPopup.vue'
|
||||||
import NotificationSettingPopup from '~/components/NotificationSettingPopup.vue'
|
import NotificationSettingPopup from '~/components/NotificationSettingPopup.vue'
|
||||||
import { API_BASE_URL } from '~/main'
|
|
||||||
import { authState } from '~/utils/auth'
|
import { authState } from '~/utils/auth'
|
||||||
|
|
||||||
|
const config = useRuntimeConfig()
|
||||||
|
const API_BASE_URL = config.public.apiBaseUrl
|
||||||
|
|
||||||
const showMilkTeaPopup = ref(false)
|
const showMilkTeaPopup = ref(false)
|
||||||
const milkTeaIcon = ref('')
|
const milkTeaIcon = ref('')
|
||||||
const showNotificationPopup = ref(false)
|
const showNotificationPopup = ref(false)
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
</header>
|
</header>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import { ClientOnly } from '#components'
|
import { ClientOnly } from '#components'
|
||||||
import { computed, nextTick, ref, watch } from 'vue'
|
import { computed, nextTick, ref, watch } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
@@ -57,141 +57,109 @@ import SearchDropdown from '~/components/SearchDropdown.vue'
|
|||||||
import { authState, clearToken, loadCurrentUser } from '~/utils/auth'
|
import { authState, clearToken, loadCurrentUser } from '~/utils/auth'
|
||||||
import { fetchUnreadCount, notificationState } from '~/utils/notification'
|
import { fetchUnreadCount, notificationState } from '~/utils/notification'
|
||||||
import { useIsMobile } from '~/utils/screen'
|
import { useIsMobile } from '~/utils/screen'
|
||||||
|
const props = defineProps({
|
||||||
export default {
|
showMenuBtn: {
|
||||||
name: 'HeaderComponent',
|
type: Boolean,
|
||||||
components: { DropdownMenu, SearchDropdown },
|
default: true,
|
||||||
props: {
|
|
||||||
showMenuBtn: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
setup(props, { expose }) {
|
})
|
||||||
const isLogin = computed(() => authState.loggedIn)
|
|
||||||
const isMobile = useIsMobile()
|
|
||||||
const unreadCount = computed(() => notificationState.unreadCount)
|
|
||||||
const router = useRouter()
|
|
||||||
const avatar = ref('')
|
|
||||||
const showSearch = ref(false)
|
|
||||||
const searchDropdown = ref(null)
|
|
||||||
const userMenu = ref(null)
|
|
||||||
const menuBtn = ref(null)
|
|
||||||
|
|
||||||
expose({
|
const isLogin = computed(() => authState.loggedIn)
|
||||||
menuBtn,
|
const isMobile = useIsMobile()
|
||||||
})
|
const unreadCount = computed(() => notificationState.unreadCount)
|
||||||
|
const router = useRouter()
|
||||||
|
const avatar = ref('')
|
||||||
|
const showSearch = ref(false)
|
||||||
|
const searchDropdown = ref(null)
|
||||||
|
const userMenu = ref(null)
|
||||||
|
const menuBtn = ref(null)
|
||||||
|
|
||||||
const goToHome = () => {
|
const goToHome = async () => {
|
||||||
router.push('/').then(() => {
|
await navigateTo('/', { replace: true })
|
||||||
window.location.reload()
|
}
|
||||||
})
|
const search = () => {
|
||||||
|
showSearch.value = true
|
||||||
|
nextTick(() => {
|
||||||
|
searchDropdown.value.toggle()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const closeSearch = () => {
|
||||||
|
nextTick(() => {
|
||||||
|
showSearch.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const goToLogin = () => {
|
||||||
|
navigateTo('/login', { replace: true })
|
||||||
|
}
|
||||||
|
const goToSettings = () => {
|
||||||
|
navigateTo('/settings', { replace: true })
|
||||||
|
}
|
||||||
|
const goToProfile = async () => {
|
||||||
|
if (!authState.loggedIn) {
|
||||||
|
navigateTo('/login', { replace: true })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let id = authState.username || authState.userId
|
||||||
|
if (!id) {
|
||||||
|
const user = await loadCurrentUser()
|
||||||
|
if (user) {
|
||||||
|
id = user.username || user.id
|
||||||
}
|
}
|
||||||
const search = () => {
|
}
|
||||||
showSearch.value = true
|
if (id) {
|
||||||
nextTick(() => {
|
navigateTo(`/users/${id}`, { replace: true })
|
||||||
searchDropdown.value.toggle()
|
}
|
||||||
})
|
}
|
||||||
}
|
const goToSignup = () => {
|
||||||
const closeSearch = () => {
|
navigateTo('/signup', { replace: true })
|
||||||
nextTick(() => {
|
}
|
||||||
showSearch.value = false
|
const goToLogout = () => {
|
||||||
})
|
clearToken()
|
||||||
}
|
navigateTo('/login', { replace: true })
|
||||||
const goToLogin = () => {
|
}
|
||||||
router.push('/login')
|
|
||||||
}
|
const headerMenuItems = computed(() => [
|
||||||
const goToSettings = () => {
|
{ text: '设置', onClick: goToSettings },
|
||||||
router.push('/settings')
|
{ text: '个人主页', onClick: goToProfile },
|
||||||
}
|
{ text: '退出', onClick: goToLogout },
|
||||||
const goToProfile = async () => {
|
])
|
||||||
if (!authState.loggedIn) {
|
|
||||||
router.push('/login')
|
onMounted(async () => {
|
||||||
return
|
const updateAvatar = async () => {
|
||||||
}
|
if (authState.loggedIn) {
|
||||||
let id = authState.username || authState.userId
|
const user = await loadCurrentUser()
|
||||||
if (!id) {
|
if (user && user.avatar) {
|
||||||
const user = await loadCurrentUser()
|
avatar.value = user.avatar
|
||||||
if (user) {
|
|
||||||
id = user.username || user.id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (id) {
|
|
||||||
router.push(`/users/${id}`)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const goToSignup = () => {
|
}
|
||||||
router.push('/signup')
|
const updateUnread = async () => {
|
||||||
}
|
if (authState.loggedIn) {
|
||||||
const goToLogout = () => {
|
await fetchUnreadCount()
|
||||||
clearToken()
|
} else {
|
||||||
this.$router.push('/login')
|
notificationState.unreadCount = 0
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const headerMenuItems = computed(() => [
|
await updateAvatar()
|
||||||
{ text: '设置', onClick: goToSettings },
|
await updateUnread()
|
||||||
{ text: '个人主页', onClick: goToProfile },
|
|
||||||
{ text: '退出', onClick: goToLogout },
|
|
||||||
])
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
const updateAvatar = async () => {
|
|
||||||
if (authState.loggedIn) {
|
|
||||||
const user = await loadCurrentUser()
|
|
||||||
if (user && user.avatar) {
|
|
||||||
avatar.value = user.avatar
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const updateUnread = async () => {
|
|
||||||
if (authState.loggedIn) {
|
|
||||||
await fetchUnreadCount()
|
|
||||||
} else {
|
|
||||||
notificationState.unreadCount = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => authState.loggedIn,
|
||||||
|
async () => {
|
||||||
await updateAvatar()
|
await updateAvatar()
|
||||||
await updateUnread()
|
await updateUnread()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => authState.loggedIn,
|
() => router.currentRoute.value.fullPath,
|
||||||
async () => {
|
() => {
|
||||||
await updateAvatar()
|
if (userMenu.value) userMenu.value.close()
|
||||||
await updateUnread()
|
showSearch.value = false
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
})
|
||||||
watch(
|
|
||||||
() => router.currentRoute.value.fullPath,
|
|
||||||
() => {
|
|
||||||
if (userMenu.value) userMenu.value.close()
|
|
||||||
showSearch.value = false
|
|
||||||
},
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
|
||||||
isLogin,
|
|
||||||
isMobile,
|
|
||||||
headerMenuItems,
|
|
||||||
unreadCount,
|
|
||||||
goToHome,
|
|
||||||
search,
|
|
||||||
closeSearch,
|
|
||||||
goToLogin,
|
|
||||||
goToSettings,
|
|
||||||
goToProfile,
|
|
||||||
goToSignup,
|
|
||||||
goToLogout,
|
|
||||||
showSearch,
|
|
||||||
searchDropdown,
|
|
||||||
userMenu,
|
|
||||||
avatar,
|
|
||||||
menuBtn,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -9,18 +9,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import { useRouter } from 'vue-router'
|
const goLogin = () => {
|
||||||
|
navigateTo('/login', { replace: true })
|
||||||
export default {
|
|
||||||
name: 'LoginOverlay',
|
|
||||||
setup() {
|
|
||||||
const router = useRouter()
|
|
||||||
const goLogin = () => {
|
|
||||||
router.push('/login')
|
|
||||||
}
|
|
||||||
return { goLogin }
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -16,33 +16,25 @@
|
|||||||
</BasePopup>
|
</BasePopup>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import BasePopup from '~/components/BasePopup.vue'
|
import BasePopup from '~/components/BasePopup.vue'
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
import { authState } from '~/utils/auth'
|
import { authState } from '~/utils/auth'
|
||||||
|
|
||||||
export default {
|
defineProps({
|
||||||
name: 'MedalPopup',
|
visible: { type: Boolean, default: false },
|
||||||
components: { BasePopup },
|
medals: { type: Array, default: () => [] },
|
||||||
props: {
|
})
|
||||||
visible: { type: Boolean, default: false },
|
const emit = defineEmits(['close'])
|
||||||
medals: { type: Array, default: () => [] },
|
|
||||||
},
|
const gotoMedals = () => {
|
||||||
emits: ['close'],
|
emit('close')
|
||||||
setup(props, { emit }) {
|
if (authState.username) {
|
||||||
const router = useRouter()
|
navigateTo(`/users/${authState.username}?tab=achievements`, { replace: true })
|
||||||
const gotoMedals = () => {
|
} else {
|
||||||
emit('close')
|
navigateTo('/', { replace: true })
|
||||||
if (authState.username) {
|
}
|
||||||
router.push(`/users/${authState.username}?tab=achievements`)
|
|
||||||
} else {
|
|
||||||
router.push('/')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const close = () => emit('close')
|
|
||||||
return { gotoMedals, close }
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
const close = () => emit('close')
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -124,10 +124,10 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { ref, computed, watch, onMounted } from 'vue'
|
||||||
import { themeState, cycleTheme, ThemeMode } from '~/utils/theme'
|
import { themeState, cycleTheme, ThemeMode } from '~/utils/theme'
|
||||||
import { authState } from '~/utils/auth'
|
import { authState } from '~/utils/auth'
|
||||||
import { fetchUnreadCount, notificationState } from '~/utils/notification'
|
import { fetchUnreadCount, notificationState } from '~/utils/notification'
|
||||||
import { ref, computed, watch, onMounted } from 'vue'
|
|
||||||
const config = useRuntimeConfig()
|
const config = useRuntimeConfig()
|
||||||
const API_BASE_URL = config.public.apiBaseUrl
|
const API_BASE_URL = config.public.apiBaseUrl
|
||||||
|
|
||||||
@@ -140,7 +140,6 @@ const props = defineProps({
|
|||||||
|
|
||||||
const emit = defineEmits(['item-click'])
|
const emit = defineEmits(['item-click'])
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
const categoryOpen = ref(true)
|
const categoryOpen = ref(true)
|
||||||
const tagOpen = ref(true)
|
const tagOpen = ref(true)
|
||||||
const isLoadingCategory = ref(false)
|
const isLoadingCategory = ref(false)
|
||||||
@@ -193,9 +192,7 @@ onMounted(async () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const handleHomeClick = () => {
|
const handleHomeClick = () => {
|
||||||
router.push('/').then(() => {
|
navigateTo('/', { replace: true })
|
||||||
window.location.reload()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleItemClick = () => {
|
const handleItemClick = () => {
|
||||||
@@ -209,13 +206,13 @@ const isImageIcon = (icon) => {
|
|||||||
|
|
||||||
const gotoCategory = (c) => {
|
const gotoCategory = (c) => {
|
||||||
const value = encodeURIComponent(c.id ?? c.name)
|
const value = encodeURIComponent(c.id ?? c.name)
|
||||||
router.push({ path: '/', query: { category: value } })
|
navigateTo({ path: '/', query: { category: value } }, { replace: true })
|
||||||
handleItemClick()
|
handleItemClick()
|
||||||
}
|
}
|
||||||
|
|
||||||
const gotoTag = (t) => {
|
const gotoTag = (t) => {
|
||||||
const value = encodeURIComponent(t.id ?? t.name)
|
const value = encodeURIComponent(t.id ?? t.name)
|
||||||
router.push({ path: '/', query: { tags: value } })
|
navigateTo({ path: '/', query: { tags: value } }, { replace: true })
|
||||||
handleItemClick()
|
handleItemClick()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,27 +11,19 @@
|
|||||||
</BasePopup>
|
</BasePopup>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import BasePopup from '~/components/BasePopup.vue'
|
import BasePopup from '~/components/BasePopup.vue'
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
|
|
||||||
export default {
|
defineProps({
|
||||||
name: 'NotificationSettingPopup',
|
visible: { type: Boolean, default: false },
|
||||||
components: { BasePopup },
|
})
|
||||||
props: {
|
const emit = defineEmits(['close'])
|
||||||
visible: { type: Boolean, default: false },
|
|
||||||
},
|
const gotoSetting = () => {
|
||||||
emits: ['close'],
|
emit('close')
|
||||||
setup(props, { emit }) {
|
navigateTo('/message?tab=control', { replace: true })
|
||||||
const router = useRouter()
|
|
||||||
const gotoSetting = () => {
|
|
||||||
emit('close')
|
|
||||||
router.push('/message?tab=control')
|
|
||||||
}
|
|
||||||
const close = () => emit('close')
|
|
||||||
return { gotoSetting, close }
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
const close = () => emit('close')
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -54,6 +54,17 @@ import { reactionEmojiMap } from '~/utils/reactions'
|
|||||||
const config = useRuntimeConfig()
|
const config = useRuntimeConfig()
|
||||||
const API_BASE_URL = config.public.apiBaseUrl
|
const API_BASE_URL = config.public.apiBaseUrl
|
||||||
const emit = defineEmits(['update:modelValue'])
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: { type: Array, default: () => [] },
|
||||||
|
contentType: { type: String, required: true },
|
||||||
|
contentId: { type: [Number, String], required: true },
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
(v) => (reactions.value = v),
|
||||||
|
)
|
||||||
|
|
||||||
const reactions = ref(props.modelValue)
|
const reactions = ref(props.modelValue)
|
||||||
const reactionTypes = ref([])
|
const reactionTypes = ref([])
|
||||||
|
|
||||||
@@ -76,17 +87,6 @@ const fetchTypes = async () => {
|
|||||||
return cachedTypes
|
return cachedTypes
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
modelValue: { type: Array, default: () => [] },
|
|
||||||
contentType: { type: String, required: true },
|
|
||||||
contentId: { type: [Number, String], required: true },
|
|
||||||
})
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.modelValue,
|
|
||||||
(v) => (reactions.value = v),
|
|
||||||
)
|
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
reactionTypes.value = await fetchTypes()
|
reactionTypes.value = await fetchTypes()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -37,17 +37,15 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, watch } from 'vue'
|
|
||||||
import { useIsMobile } from '~/utils/screen'
|
import { useIsMobile } from '~/utils/screen'
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
import Dropdown from '~/components/Dropdown.vue'
|
import Dropdown from '~/components/Dropdown.vue'
|
||||||
import { stripMarkdown } from '~/utils/markdown'
|
import { stripMarkdown } from '~/utils/markdown'
|
||||||
|
import { ref, watch } from 'vue'
|
||||||
const config = useRuntimeConfig()
|
const config = useRuntimeConfig()
|
||||||
const API_BASE_URL = config.public.apiBaseUrl
|
const API_BASE_URL = config.public.apiBaseUrl
|
||||||
|
|
||||||
const emit = defineEmits(['close'])
|
const emit = defineEmits(['close'])
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
const keyword = ref('')
|
const keyword = ref('')
|
||||||
const selected = ref(null)
|
const selected = ref(null)
|
||||||
const results = ref([])
|
const results = ref([])
|
||||||
@@ -97,17 +95,17 @@ watch(selected, (val) => {
|
|||||||
const opt = results.value.find((r) => r.id === val)
|
const opt = results.value.find((r) => r.id === val)
|
||||||
if (!opt) return
|
if (!opt) return
|
||||||
if (opt.type === 'post' || opt.type === 'post_title') {
|
if (opt.type === 'post' || opt.type === 'post_title') {
|
||||||
router.push(`/posts/${opt.id}`)
|
navigateTo(`/posts/${opt.id}`, { replace: true })
|
||||||
} else if (opt.type === 'user') {
|
} else if (opt.type === 'user') {
|
||||||
router.push(`/users/${opt.id}`)
|
navigateTo(`/users/${opt.id}`, { replace: true })
|
||||||
} else if (opt.type === 'comment') {
|
} else if (opt.type === 'comment') {
|
||||||
if (opt.postId) {
|
if (opt.postId) {
|
||||||
router.push(`/posts/${opt.postId}#comment-${opt.id}`)
|
navigateTo(`/posts/${opt.postId}#comment-${opt.id}`, { replace: true })
|
||||||
}
|
}
|
||||||
} else if (opt.type === 'category') {
|
} else if (opt.type === 'category') {
|
||||||
router.push({ path: '/', query: { category: opt.id } })
|
navigateTo({ path: '/', query: { category: opt.id } }, { replace: true })
|
||||||
} else if (opt.type === 'tag') {
|
} else if (opt.type === 'tag') {
|
||||||
router.push({ path: '/', query: { tags: opt.id } })
|
navigateTo({ path: '/', query: { tags: opt.id } }, { replace: true })
|
||||||
}
|
}
|
||||||
selected.value = null
|
selected.value = null
|
||||||
keyword.value = ''
|
keyword.value = ''
|
||||||
|
|||||||
@@ -11,20 +11,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import BasePlaceholder from '~/components/BasePlaceholder.vue'
|
import BasePlaceholder from '~/components/BasePlaceholder.vue'
|
||||||
|
|
||||||
export default {
|
defineProps({
|
||||||
name: 'UserList',
|
users: { type: Array, default: () => [] },
|
||||||
components: { BasePlaceholder },
|
})
|
||||||
props: {
|
|
||||||
users: { type: Array, default: () => [] },
|
const handleUserClick = (user) => {
|
||||||
},
|
navigateTo(`/users/${user.id}`, { replace: true })
|
||||||
methods: {
|
|
||||||
handleUserClick(user) {
|
|
||||||
this.$router.push(`/users/${user.id}`)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export const WEBSITE_BASE_URL = 'https://www.open-isle.com'
|
|
||||||
@@ -5,6 +5,7 @@ export default defineNuxtConfig({
|
|||||||
runtimeConfig: {
|
runtimeConfig: {
|
||||||
public: {
|
public: {
|
||||||
apiBaseUrl: process.env.NUXT_PUBLIC_API_BASE_URL || '',
|
apiBaseUrl: process.env.NUXT_PUBLIC_API_BASE_URL || '',
|
||||||
|
websiteBaseUrl: process.env.NUXT_PUBLIC_WEBSITE_BASE_URL || '',
|
||||||
googleClientId: process.env.NUXT_PUBLIC_GOOGLE_CLIENT_ID || '',
|
googleClientId: process.env.NUXT_PUBLIC_GOOGLE_CLIENT_ID || '',
|
||||||
githubClientId: process.env.NUXT_PUBLIC_GITHUB_CLIENT_ID || '',
|
githubClientId: process.env.NUXT_PUBLIC_GITHUB_CLIENT_ID || '',
|
||||||
discordClientId: process.env.NUXT_PUBLIC_DISCORD_CLIENT_ID || '',
|
discordClientId: process.env.NUXT_PUBLIC_DISCORD_CLIENT_ID || '',
|
||||||
|
|||||||
@@ -2,24 +2,20 @@
|
|||||||
<CallbackPage />
|
<CallbackPage />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import CallbackPage from '~/components/CallbackPage.vue'
|
import CallbackPage from '~/components/CallbackPage.vue'
|
||||||
import { discordExchange } from '~/utils/discord'
|
import { discordExchange } from '~/utils/discord'
|
||||||
|
|
||||||
export default {
|
onMounted(async () => {
|
||||||
name: 'DiscordCallbackPageView',
|
const url = new URL(window.location.href)
|
||||||
components: { CallbackPage },
|
const code = url.searchParams.get('code')
|
||||||
async mounted() {
|
const state = url.searchParams.get('state')
|
||||||
const url = new URL(window.location.href)
|
const result = await discordExchange(code, state, '')
|
||||||
const code = url.searchParams.get('code')
|
|
||||||
const state = url.searchParams.get('state')
|
|
||||||
const result = await discordExchange(code, state, '')
|
|
||||||
|
|
||||||
if (result.needReason) {
|
if (result.needReason) {
|
||||||
this.$router.push('/signup-reason?token=' + result.token)
|
navigateTo(`/signup-reason?token=${result.token}`, { replace: true })
|
||||||
} else {
|
} else {
|
||||||
this.$router.push('/')
|
navigateTo('/', { replace: true })
|
||||||
}
|
}
|
||||||
},
|
})
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ const resetPassword = async () => {
|
|||||||
const data = await res.json()
|
const data = await res.json()
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
toast.success('密码已重置')
|
toast.success('密码已重置')
|
||||||
router.push('/login')
|
navigateTo('/login', { replace: true })
|
||||||
} else if (data.field === 'password') {
|
} else if (data.field === 'password') {
|
||||||
passwordError.value = data.error
|
passwordError.value = data.error
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -2,24 +2,20 @@
|
|||||||
<CallbackPage />
|
<CallbackPage />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import CallbackPage from '~/components/CallbackPage.vue'
|
import CallbackPage from '~/components/CallbackPage.vue'
|
||||||
import { githubExchange } from '~/utils/github'
|
import { githubExchange } from '~/utils/github'
|
||||||
|
|
||||||
export default {
|
onMounted(async () => {
|
||||||
name: 'GithubCallbackPageView',
|
const url = new URL(window.location.href)
|
||||||
components: { CallbackPage },
|
const code = url.searchParams.get('code')
|
||||||
async mounted() {
|
const state = url.searchParams.get('state')
|
||||||
const url = new URL(window.location.href)
|
const result = await githubExchange(code, state, '')
|
||||||
const code = url.searchParams.get('code')
|
|
||||||
const state = url.searchParams.get('state')
|
|
||||||
const result = await githubExchange(code, state, '')
|
|
||||||
|
|
||||||
if (result.needReason) {
|
if (result.needReason) {
|
||||||
this.$router.push('/signup-reason?token=' + result.token)
|
navigateTo(`/signup-reason?token=${result.token}`, { replace: true })
|
||||||
} else {
|
} else {
|
||||||
this.$router.push('/')
|
navigateTo('/', { replace: true })
|
||||||
}
|
}
|
||||||
},
|
})
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -2,29 +2,25 @@
|
|||||||
<CallbackPage />
|
<CallbackPage />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import CallbackPage from '~/components/CallbackPage.vue'
|
import CallbackPage from '~/components/CallbackPage.vue'
|
||||||
import { googleAuthWithToken } from '~/utils/google'
|
import { googleAuthWithToken } from '~/utils/google'
|
||||||
|
|
||||||
export default {
|
onMounted(async () => {
|
||||||
name: 'GoogleCallbackPageView',
|
const hash = new URLSearchParams(window.location.hash.substring(1))
|
||||||
components: { CallbackPage },
|
const idToken = hash.get('id_token')
|
||||||
async mounted() {
|
if (idToken) {
|
||||||
const hash = new URLSearchParams(window.location.hash.substring(1))
|
await googleAuthWithToken(
|
||||||
const idToken = hash.get('id_token')
|
idToken,
|
||||||
if (idToken) {
|
() => {
|
||||||
await googleAuthWithToken(
|
navigateTo('/', { replace: true })
|
||||||
idToken,
|
},
|
||||||
() => {
|
(token) => {
|
||||||
this.$router.push('/')
|
navigateTo(`/signup-reason?token=${token}`, { replace: true })
|
||||||
},
|
},
|
||||||
(token) => {
|
)
|
||||||
this.$router.push('/signup-reason?token=' + token)
|
} else {
|
||||||
},
|
navigateTo('/login', { replace: true })
|
||||||
)
|
}
|
||||||
} else {
|
})
|
||||||
this.$router.push('/login')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ import BaseInput from '~/components/BaseInput.vue'
|
|||||||
import { registerPush } from '~/utils/push'
|
import { registerPush } from '~/utils/push'
|
||||||
const config = useRuntimeConfig()
|
const config = useRuntimeConfig()
|
||||||
const API_BASE_URL = config.public.apiBaseUrl
|
const API_BASE_URL = config.public.apiBaseUrl
|
||||||
|
|
||||||
const username = ref('')
|
const username = ref('')
|
||||||
const password = ref('')
|
const password = ref('')
|
||||||
const isWaitingForLogin = ref(false)
|
const isWaitingForLogin = ref(false)
|
||||||
@@ -81,15 +80,18 @@ const submitLogin = async () => {
|
|||||||
await loadCurrentUser()
|
await loadCurrentUser()
|
||||||
toast.success('登录成功')
|
toast.success('登录成功')
|
||||||
registerPush()
|
registerPush()
|
||||||
router.push('/')
|
await navigateTo('/', { replace: true })
|
||||||
} else if (data.reason_code === 'NOT_VERIFIED') {
|
} else if (data.reason_code === 'NOT_VERIFIED') {
|
||||||
toast.info('当前邮箱未验证,已经为您重新发送验证码')
|
toast.info('当前邮箱未验证,已经为您重新发送验证码')
|
||||||
router.push({ path: '/signup', query: { verify: 1, u: username.value } })
|
await navigateTo(
|
||||||
|
{ path: '/signup', query: { verify: '1', u: username.value } },
|
||||||
|
{ replace: true },
|
||||||
|
)
|
||||||
} else if (data.reason_code === 'IS_APPROVING') {
|
} else if (data.reason_code === 'IS_APPROVING') {
|
||||||
toast.info('您的注册正在审批中, 请留意邮件')
|
toast.info('您的注册正在审批中, 请留意邮件')
|
||||||
router.push('/')
|
await navigateTo('/', { replace: true })
|
||||||
} else if (data.reason_code === 'NOT_APPROVED') {
|
} else if (data.reason_code === 'NOT_APPROVED') {
|
||||||
router.push('/signup-reason?token=' + data.token)
|
await navigateTo({ path: '/signup-reason', query: { token: data.token } }, { replace: true })
|
||||||
} else {
|
} else {
|
||||||
toast.error(data.error || '登录失败')
|
toast.error(data.error || '登录失败')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -480,7 +480,6 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, computed } from 'vue'
|
import { ref, onMounted, computed } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
import BaseTimeline from '~/components/BaseTimeline.vue'
|
import BaseTimeline from '~/components/BaseTimeline.vue'
|
||||||
import BasePlaceholder from '~/components/BasePlaceholder.vue'
|
import BasePlaceholder from '~/components/BasePlaceholder.vue'
|
||||||
import NotificationContainer from '~/components/NotificationContainer.vue'
|
import NotificationContainer from '~/components/NotificationContainer.vue'
|
||||||
@@ -492,7 +491,6 @@ import TimeManager from '~/utils/time'
|
|||||||
import { reactionEmojiMap } from '~/utils/reactions'
|
import { reactionEmojiMap } from '~/utils/reactions'
|
||||||
const config = useRuntimeConfig()
|
const config = useRuntimeConfig()
|
||||||
const API_BASE_URL = config.public.apiBaseUrl
|
const API_BASE_URL = config.public.apiBaseUrl
|
||||||
const router = useRouter()
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const notifications = ref([])
|
const notifications = ref([])
|
||||||
const isLoadingMessage = ref(false)
|
const isLoadingMessage = ref(false)
|
||||||
@@ -590,7 +588,7 @@ const fetchNotifications = async () => {
|
|||||||
src: n.comment.author.avatar,
|
src: n.comment.author.avatar,
|
||||||
iconClick: () => {
|
iconClick: () => {
|
||||||
markRead(n.id)
|
markRead(n.id)
|
||||||
router.push(`/users/${n.comment.author.id}`)
|
navigateTo(`/users/${n.comment.author.id}`, { replace: true })
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
} else if (n.type === 'REACTION') {
|
} else if (n.type === 'REACTION') {
|
||||||
@@ -600,7 +598,7 @@ const fetchNotifications = async () => {
|
|||||||
iconClick: () => {
|
iconClick: () => {
|
||||||
if (n.fromUser) {
|
if (n.fromUser) {
|
||||||
markRead(n.id)
|
markRead(n.id)
|
||||||
router.push(`/users/${n.fromUser.id}`)
|
navigateTo(`/users/${n.fromUser.id}`, { replace: true })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -612,7 +610,7 @@ const fetchNotifications = async () => {
|
|||||||
iconClick: () => {
|
iconClick: () => {
|
||||||
if (n.fromUser) {
|
if (n.fromUser) {
|
||||||
markRead(n.id)
|
markRead(n.id)
|
||||||
router.push(`/users/${n.fromUser.id}`)
|
navigateTo(`/users/${n.fromUser.id}`, { replace: true })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -622,7 +620,7 @@ const fetchNotifications = async () => {
|
|||||||
src: n.comment.author.avatar,
|
src: n.comment.author.avatar,
|
||||||
iconClick: () => {
|
iconClick: () => {
|
||||||
markRead(n.id)
|
markRead(n.id)
|
||||||
router.push(`/users/${n.comment.author.id}`)
|
navigateTo(`/users/${n.comment.author.id}`, { replace: true })
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
} else if (n.type === 'USER_ACTIVITY') {
|
} else if (n.type === 'USER_ACTIVITY') {
|
||||||
@@ -631,7 +629,7 @@ const fetchNotifications = async () => {
|
|||||||
src: n.comment.author.avatar,
|
src: n.comment.author.avatar,
|
||||||
iconClick: () => {
|
iconClick: () => {
|
||||||
markRead(n.id)
|
markRead(n.id)
|
||||||
router.push(`/users/${n.comment.author.id}`)
|
navigateTo(`/users/${n.comment.author.id}`, { replace: true })
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
} else if (n.type === 'MENTION') {
|
} else if (n.type === 'MENTION') {
|
||||||
@@ -641,7 +639,7 @@ const fetchNotifications = async () => {
|
|||||||
iconClick: () => {
|
iconClick: () => {
|
||||||
if (n.fromUser) {
|
if (n.fromUser) {
|
||||||
markRead(n.id)
|
markRead(n.id)
|
||||||
router.push(`/users/${n.fromUser.id}`)
|
navigateTo(`/users/${n.fromUser.id}`, { replace: true })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -652,7 +650,7 @@ const fetchNotifications = async () => {
|
|||||||
iconClick: () => {
|
iconClick: () => {
|
||||||
if (n.fromUser) {
|
if (n.fromUser) {
|
||||||
markRead(n.id)
|
markRead(n.id)
|
||||||
router.push(`/users/${n.fromUser.id}`)
|
navigateTo(`/users/${n.fromUser.id}`, { replace: true })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -663,7 +661,7 @@ const fetchNotifications = async () => {
|
|||||||
iconClick: () => {
|
iconClick: () => {
|
||||||
if (n.post) {
|
if (n.post) {
|
||||||
markRead(n.id)
|
markRead(n.id)
|
||||||
router.push(`/posts/${n.post.id}`)
|
navigateTo(`/posts/${n.post.id}`, { replace: true })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -674,7 +672,7 @@ const fetchNotifications = async () => {
|
|||||||
iconClick: () => {
|
iconClick: () => {
|
||||||
if (n.post) {
|
if (n.post) {
|
||||||
markRead(n.id)
|
markRead(n.id)
|
||||||
router.push(`/posts/${n.post.id}`)
|
navigateTo(`/posts/${n.post.id}`, { replace: true })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -686,7 +684,7 @@ const fetchNotifications = async () => {
|
|||||||
iconClick: () => {
|
iconClick: () => {
|
||||||
if (n.post) {
|
if (n.post) {
|
||||||
markRead(n.id)
|
markRead(n.id)
|
||||||
router.push(`/posts/${n.post.id}`)
|
navigateTo(`/posts/${n.post.id}`, { replace: true })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, computed } from 'vue'
|
import { ref, onMounted, computed } from 'vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import PostEditor from '~/components/PostEditor.vue'
|
import PostEditor from '~/components/PostEditor.vue'
|
||||||
import CategorySelect from '~/components/CategorySelect.vue'
|
import CategorySelect from '~/components/CategorySelect.vue'
|
||||||
import TagSelect from '~/components/TagSelect.vue'
|
import TagSelect from '~/components/TagSelect.vue'
|
||||||
@@ -56,7 +56,6 @@ const isAiLoading = ref(false)
|
|||||||
const isLogin = computed(() => authState.loggedIn)
|
const isLogin = computed(() => authState.loggedIn)
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
|
||||||
const postId = route.params.id
|
const postId = route.params.id
|
||||||
|
|
||||||
const loadPost = async () => {
|
const loadPost = async () => {
|
||||||
@@ -197,7 +196,7 @@ const submitPost = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const cancelEdit = () => {
|
const cancelEdit = () => {
|
||||||
router.push(`/posts/${postId}`)
|
navigateTo(`/posts/${postId}`, { replace: true })
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -343,7 +343,7 @@ const startCountdown = () => {
|
|||||||
updateCountdown()
|
updateCountdown()
|
||||||
countdownTimer = setInterval(updateCountdown, 1000)
|
countdownTimer = setInterval(updateCountdown, 1000)
|
||||||
}
|
}
|
||||||
const gotoUser = (id) => router.push(`/users/${id}`)
|
const gotoUser = (id) => navigateTo(`/users/${id}`, { replace: true })
|
||||||
const articleMenuItems = computed(() => {
|
const articleMenuItems = computed(() => {
|
||||||
const items = []
|
const items = []
|
||||||
if (isAuthor.value || isAdmin.value) {
|
if (isAuthor.value || isAdmin.value) {
|
||||||
@@ -394,7 +394,7 @@ const mapComment = (c, parentUserName = '', level = 0) => ({
|
|||||||
reply: (c.replies || []).map((r) => mapComment(r, c.author.username, level + 1)),
|
reply: (c.replies || []).map((r) => mapComment(r, c.author.username, level + 1)),
|
||||||
openReplies: level === 0,
|
openReplies: level === 0,
|
||||||
src: c.author.avatar,
|
src: c.author.avatar,
|
||||||
iconClick: () => router.push(`/users/${c.author.id}`),
|
iconClick: () => navigateTo(`/users/${c.author.id}`, { replace: true }),
|
||||||
parentUserName: parentUserName,
|
parentUserName: parentUserName,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -641,7 +641,7 @@ const unpinPost = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const editPost = () => {
|
const editPost = () => {
|
||||||
router.push(`/posts/${postId}/edit`)
|
navigateTo(`/posts/${postId}/edit`, { replace: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
const deletePost = async () => {
|
const deletePost = async () => {
|
||||||
@@ -656,7 +656,7 @@ const deletePost = async () => {
|
|||||||
})
|
})
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
toast.success('已删除')
|
toast.success('已删除')
|
||||||
router.push('/')
|
navigateTo('/', { replace: true })
|
||||||
} else {
|
} else {
|
||||||
toast.error('操作失败')
|
toast.error('操作失败')
|
||||||
}
|
}
|
||||||
@@ -766,7 +766,7 @@ const jumpToHashComment = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const gotoProfile = () => {
|
const gotoProfile = () => {
|
||||||
router.push(`/users/${author.value.id}`)
|
navigateTo(`/users/${author.value.id}`, { replace: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
|||||||
@@ -65,6 +65,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
import AvatarCropper from '~/components/AvatarCropper.vue'
|
import AvatarCropper from '~/components/AvatarCropper.vue'
|
||||||
import BaseInput from '~/components/BaseInput.vue'
|
import BaseInput from '~/components/BaseInput.vue'
|
||||||
import Dropdown from '~/components/Dropdown.vue'
|
import Dropdown from '~/components/Dropdown.vue'
|
||||||
@@ -72,7 +73,6 @@ import { toast } from '~/main'
|
|||||||
import { fetchCurrentUser, getToken, setToken } from '~/utils/auth'
|
import { fetchCurrentUser, getToken, setToken } from '~/utils/auth'
|
||||||
const config = useRuntimeConfig()
|
const config = useRuntimeConfig()
|
||||||
const API_BASE_URL = config.public.apiBaseUrl
|
const API_BASE_URL = config.public.apiBaseUrl
|
||||||
const router = useRouter()
|
|
||||||
const username = ref('')
|
const username = ref('')
|
||||||
const introduction = ref('')
|
const introduction = ref('')
|
||||||
const usernameError = ref('')
|
const usernameError = ref('')
|
||||||
@@ -102,7 +102,7 @@ onMounted(async () => {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
toast.error('请先登录')
|
toast.error('请先登录')
|
||||||
router.push('/login')
|
navigateTo('/login', { replace: true })
|
||||||
}
|
}
|
||||||
isLoadingPage.value = false
|
isLoadingPage.value = false
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -29,10 +29,10 @@ const error = ref('')
|
|||||||
const isWaitingForRegister = ref(false)
|
const isWaitingForRegister = ref(false)
|
||||||
const token = ref('')
|
const token = ref('')
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(async () => {
|
||||||
token.value = route.query.token || ''
|
token.value = route.query.token || ''
|
||||||
if (!token.value) {
|
if (!token.value) {
|
||||||
router.push('/signup')
|
await navigateTo({ path: '/signup' }, { replace: true })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -58,10 +58,10 @@ const submit = async () => {
|
|||||||
const data = await res.json()
|
const data = await res.json()
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
toast.success('注册理由已提交,请等待审核')
|
toast.success('注册理由已提交,请等待审核')
|
||||||
router.push('/')
|
await navigateTo('/', { replace: true })
|
||||||
} else if (data.reason_code === 'INVALID_CREDENTIALS') {
|
} else if (data.reason_code === 'INVALID_CREDENTIALS') {
|
||||||
toast.error('登录已过期,请重新登录')
|
toast.error('登录已过期,请重新登录')
|
||||||
router.push('/login')
|
await navigateTo('/login', { replace: true })
|
||||||
} else {
|
} else {
|
||||||
toast.error(data.error || '提交失败')
|
toast.error(data.error || '提交失败')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -189,10 +189,10 @@ const verifyCode = async () => {
|
|||||||
const data = await res.json()
|
const data = await res.json()
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
if (registerMode.value === 'WHITELIST') {
|
if (registerMode.value === 'WHITELIST') {
|
||||||
router.push('/signup-reason?token=' + data.token)
|
navigateTo(`/signup-reason?token=${data.token}`, { replace: true })
|
||||||
} else {
|
} else {
|
||||||
toast.success('注册成功,请登录')
|
toast.success('注册成功,请登录')
|
||||||
router.push('/login')
|
navigateTo('/login', { replace: true })
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
toast.error(data.error || '注册失败')
|
toast.error(data.error || '注册失败')
|
||||||
|
|||||||
@@ -2,24 +2,20 @@
|
|||||||
<CallbackPage />
|
<CallbackPage />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import CallbackPage from '~/components/CallbackPage.vue'
|
import CallbackPage from '~/components/CallbackPage.vue'
|
||||||
import { twitterExchange } from '~/utils/twitter'
|
import { twitterExchange } from '~/utils/twitter'
|
||||||
|
|
||||||
export default {
|
onMounted(async () => {
|
||||||
name: 'TwitterCallbackPageView',
|
const url = new URL(window.location.href)
|
||||||
components: { CallbackPage },
|
const code = url.searchParams.get('code')
|
||||||
async mounted() {
|
const state = url.searchParams.get('state')
|
||||||
const url = new URL(window.location.href)
|
const result = await twitterExchange(code, state, '')
|
||||||
const code = url.searchParams.get('code')
|
|
||||||
const state = url.searchParams.get('state')
|
|
||||||
const result = await twitterExchange(code, state, '')
|
|
||||||
|
|
||||||
if (result.needReason) {
|
if (result.needReason) {
|
||||||
this.$router.push('/signup-reason?token=' + result.token)
|
navigateTo(`/signup-reason?token=${result.token}`, { replace: true })
|
||||||
} else {
|
} else {
|
||||||
this.$router.push('/')
|
navigateTo('/', { replace: true })
|
||||||
}
|
}
|
||||||
},
|
})
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -506,7 +506,7 @@ const unsubscribeUser = async () => {
|
|||||||
|
|
||||||
const gotoTag = (tag) => {
|
const gotoTag = (tag) => {
|
||||||
const value = encodeURIComponent(tag.id ?? tag.name)
|
const value = encodeURIComponent(tag.id ?? tag.name)
|
||||||
router.push({ path: '/', query: { tags: value } })
|
navigateTo({ path: '/', query: { tags: value } }, { replace: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
const init = async () => {
|
const init = async () => {
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import { DISCORD_CLIENT_ID, toast } from '../main'
|
import { toast } from '../main'
|
||||||
import { WEBSITE_BASE_URL } from '../constants'
|
|
||||||
import { setToken, loadCurrentUser } from './auth'
|
import { setToken, loadCurrentUser } from './auth'
|
||||||
import { registerPush } from './push'
|
import { registerPush } from './push'
|
||||||
|
|
||||||
export function discordAuthorize(state = '') {
|
export function discordAuthorize(state = '') {
|
||||||
|
const config = useRuntimeConfig()
|
||||||
|
const WEBSITE_BASE_URL = config.public.websiteBaseUrl
|
||||||
|
const DISCORD_CLIENT_ID = config.public.discordClientId
|
||||||
if (!DISCORD_CLIENT_ID) {
|
if (!DISCORD_CLIENT_ID) {
|
||||||
toast.error('Discord 登录不可用')
|
toast.error('Discord 登录不可用')
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import { GITHUB_CLIENT_ID, toast } from '../main'
|
import { toast } from '../main'
|
||||||
import { setToken, loadCurrentUser } from './auth'
|
import { setToken, loadCurrentUser } from './auth'
|
||||||
import { WEBSITE_BASE_URL } from '../constants'
|
|
||||||
import { registerPush } from './push'
|
import { registerPush } from './push'
|
||||||
|
|
||||||
export function githubAuthorize(state = '') {
|
export function githubAuthorize(state = '') {
|
||||||
|
const config = useRuntimeConfig()
|
||||||
|
const WEBSITE_BASE_URL = config.public.websiteBaseUrl
|
||||||
|
const GITHUB_CLIENT_ID = config.public.githubClientId
|
||||||
if (!GITHUB_CLIENT_ID) {
|
if (!GITHUB_CLIENT_ID) {
|
||||||
toast.error('GitHub 登录不可用')
|
toast.error('GitHub 登录不可用')
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import { GOOGLE_CLIENT_ID, toast } from '../main'
|
import { toast } from '../main'
|
||||||
import { setToken, loadCurrentUser } from './auth'
|
import { setToken, loadCurrentUser } from './auth'
|
||||||
import { registerPush } from './push'
|
import { registerPush } from './push'
|
||||||
import { WEBSITE_BASE_URL } from '../constants'
|
|
||||||
|
|
||||||
export async function googleGetIdToken() {
|
export async function googleGetIdToken() {
|
||||||
|
const config = useRuntimeConfig()
|
||||||
|
const GOOGLE_CLIENT_ID = config.public.googleClientId
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!window.google || !GOOGLE_CLIENT_ID) {
|
if (!window.google || !GOOGLE_CLIENT_ID) {
|
||||||
toast.error('Google 登录不可用, 请检查网络设置与VPN')
|
toast.error('Google 登录不可用, 请检查网络设置与VPN')
|
||||||
@@ -20,6 +22,8 @@ export async function googleGetIdToken() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function googleAuthorize() {
|
export function googleAuthorize() {
|
||||||
|
const config = useRuntimeConfig()
|
||||||
|
const GOOGLE_CLIENT_ID = config.public.googleClientId
|
||||||
if (!GOOGLE_CLIENT_ID) {
|
if (!GOOGLE_CLIENT_ID) {
|
||||||
toast.error('Google 登录不可用, 请检查网络设置与VPN')
|
toast.error('Google 登录不可用, 请检查网络设置与VPN')
|
||||||
return
|
return
|
||||||
@@ -67,15 +71,13 @@ export async function googleSignIn(redirect_success, redirect_not_approved) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
import router from '../router'
|
|
||||||
|
|
||||||
export function loginWithGoogle() {
|
export function loginWithGoogle() {
|
||||||
googleSignIn(
|
googleSignIn(
|
||||||
() => {
|
() => {
|
||||||
router.push('/')
|
navigateTo('/', { replace: true })
|
||||||
},
|
},
|
||||||
(token) => {
|
(token) => {
|
||||||
router.push('/signup-reason?token=' + token)
|
navigateTo(`/signup-reason?token=${token}`, { replace: true })
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { TWITTER_CLIENT_ID, toast } from '../main'
|
import { toast } from '../main'
|
||||||
import { WEBSITE_BASE_URL } from '../constants'
|
|
||||||
import { setToken, loadCurrentUser } from './auth'
|
import { setToken, loadCurrentUser } from './auth'
|
||||||
import { registerPush } from './push'
|
import { registerPush } from './push'
|
||||||
|
|
||||||
@@ -22,6 +21,9 @@ async function generateCodeChallenge(codeVerifier) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function twitterAuthorize(state = '') {
|
export async function twitterAuthorize(state = '') {
|
||||||
|
const config = useRuntimeConfig()
|
||||||
|
const WEBSITE_BASE_URL = config.public.websiteBaseUrl
|
||||||
|
const TWITTER_CLIENT_ID = config.public.twitterClientId
|
||||||
if (!TWITTER_CLIENT_ID) {
|
if (!TWITTER_CLIENT_ID) {
|
||||||
toast.error('Twitter 登录不可用')
|
toast.error('Twitter 登录不可用')
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user