(
{
+ if (!selected.modal) return
router.go(`widget-${props.block.name}`)
}}
>
diff --git a/src/main.css b/src/main.css
index 56b04fa..d0ce42b 100644
--- a/src/main.css
+++ b/src/main.css
@@ -165,6 +165,10 @@ body {
scrollbar-width: none;
-ms-overflow-style: none;
}
+
+.hover-move:hover {
+ transform: translateY(-4px);
+}
@layer utilities {
.scrollbar-transparent::-webkit-scrollbar {
width: 0;
diff --git a/src/widgets/index.ts b/src/widgets/index.ts
index 7957d90..434b09c 100644
--- a/src/widgets/index.ts
+++ b/src/widgets/index.ts
@@ -1,12 +1,13 @@
import type { Component } from 'vue'
import calendar from './calendar'
import weather from './weather'
+import weApply from './weApply'
export interface Widget {
name: string // 小组件类型唯一标识
label: string // 小组件名称
description: string // 小组件描述
icon: string // 小组件图标
- modal: Component // 弹框组件
+ modal: Component | null // 弹框组件
list: {
w: number
h: number
@@ -15,4 +16,4 @@ export interface Widget {
}[] // 不同尺寸小组件块
}
-export default [calendar, weather] as Widget[]
+export default [calendar, weather, weApply] as Widget[]
diff --git a/src/widgets/weApply/Large.tsx b/src/widgets/weApply/Large.tsx
new file mode 100644
index 0000000..93687aa
--- /dev/null
+++ b/src/widgets/weApply/Large.tsx
@@ -0,0 +1,171 @@
+import { defineComponent, ref, watch, type VNodeRef } from 'vue'
+import { useWeApplyStore } from './useWeApplyStore'
+import { addIcons, OhVueIcon } from 'oh-vue-icons'
+import { HiChevronDown } from 'oh-vue-icons/icons'
+import clsx from 'clsx'
+addIcons(HiChevronDown)
+export default defineComponent(() => {
+ const store = useWeApplyStore()
+ const gameRef = ref
(null)
+ const isGameBottom = ref(false)
+ const isWorkBottom = ref(false)
+ const workRef = ref(null)
+ const computIsBottom = (ref: any) => {
+ if (ref) {
+ const { scrollTop, clientHeight, scrollHeight } = ref
+ return scrollTop + clientHeight >= scrollHeight
+ }
+ }
+ const handleGameScroll = () => {
+ const isAtBottom = computIsBottom(gameRef.value)
+ console.log(isAtBottom ? '已滚动到底部!' : '未滚动到底部。')
+ if (isAtBottom) {
+ isGameBottom.value = true
+ } else {
+ isGameBottom.value = false
+ }
+ }
+ const handleWorkScroll = () => {
+ const isAtBottom = computIsBottom(workRef.value)
+ console.log(isAtBottom ? '已滚动到底部!' : '未滚动到底部。')
+ if (isAtBottom) {
+ isWorkBottom.value = true
+ } else {
+ isWorkBottom.value = false
+ }
+ }
+ watch(gameRef, (val, _, onCleanup) => {
+ console.log(val)
+ if (!val) return
+ val.addEventListener('scroll', handleGameScroll)
+ // if (val + gameRef.value.clientHeight >= gameRef.value.scrollHeight) {
+ // isGameBottom.value = true
+ // } else {
+ // isGameBottom.value = false
+ // }
+ onCleanup(() => {
+ val.removeEventListener('scroll', handleGameScroll)
+ })
+ })
+ watch(workRef, (val, _, onCleanup) => {
+ console.log(val)
+ if (!val) return
+
+ val.addEventListener('scroll', handleWorkScroll)
+ // if (val + gameRef.value.clientHeight >= gameRef.value.scrollHeight) {
+ // isGameBottom.value = true
+ // } else {
+ // isGameBottom.value = false
+ // }
+ onCleanup(() => {
+ val.removeEventListener('scroll', handleWorkScroll)
+ })
+ })
+ return () => (
+
+
+ {!isGameBottom.value && (
+
{
+ e.stopPropagation()
+ e.preventDefault()
+ if (gameRef.value) {
+ gameRef.value.scrollTop += 40
+ }
+ }}
+ >
+
+
+ )}
+
+
{
+ console.log('wheel')
+ }}
+ >
+ {store.state.list
+ .filter((val) => val.type === 'game')
+ .map((item) => (
+
+
+
+ {item.name}
+
+ {item.des}
+
+
+
+ ))}
+
+
+
+ {!isWorkBottom.value && (
+
{
+ e.stopPropagation()
+ e.preventDefault()
+ if (workRef.value) {
+ workRef.value.scrollTop += 20
+ }
+ }}
+ >
+
+
+ )}
+
+
{
+ console.log('wheel')
+ }}
+ >
+ {store.state.list
+ .filter((val) => val.type === 'work')
+ .map((item) => (
+
+
+
+ {item.name}
+
+ {item.des}
+
+
+
+ ))}
+
+
+
+ )
+})
diff --git a/src/widgets/weApply/index.ts b/src/widgets/weApply/index.ts
new file mode 100644
index 0000000..fa76ef1
--- /dev/null
+++ b/src/widgets/weApply/index.ts
@@ -0,0 +1,18 @@
+import asyncLoader from '@/utils/asyncLoader'
+import type { Widget } from '..'
+
+export default {
+ name: 'weApply',
+ label: '大家都在用',
+ description: '大家都在用',
+ icon: '/icons/recommendedIcon.png',
+ modal: null,
+ list: [
+ {
+ w: 4,
+ h: 2,
+ label: '大',
+ component: asyncLoader(() => import('./Large'))
+ }
+ ]
+} as Widget
diff --git a/src/widgets/weApply/useWeApplyStore.ts b/src/widgets/weApply/useWeApplyStore.ts
new file mode 100644
index 0000000..805c66b
--- /dev/null
+++ b/src/widgets/weApply/useWeApplyStore.ts
@@ -0,0 +1,29 @@
+import request from "@/utils/request"
+import { defineStore } from "pinia"
+import { reactive } from "vue"
+type WeApplyType = {
+ id: string;
+ name: string;
+ url: string;
+ icon: string;
+ des: string;
+ type: string;
+}
+export const useWeApplyStore = defineStore('weApply', () => {
+ const state = reactive({
+ list: [] as WeApplyType[]
+ })
+ const getWeApplyList = async () => {
+ return request('GET', '/api/app/weApplys').then(res => {
+ return res
+ })
+ }
+ const getList = async () => {
+ state.list = await getWeApplyList()
+ }
+ getList()
+ return {
+ state,
+ getList
+ }
+})
\ No newline at end of file