Compare commits
No commits in common. "1868144c4161def12015d217f0b8d8bdcefdca9d" and "7d09205087887554af5e60eadd6e4d78cf9beadc" have entirely different histories.
1868144c41
...
7d09205087
|
|
@ -28,7 +28,6 @@
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
"pinia-plugin-persistedstate": "^3.2.3",
|
"pinia-plugin-persistedstate": "^3.2.3",
|
||||||
"pixi.js": "^8.4.0",
|
"pixi.js": "^8.4.0",
|
||||||
"qrcode": "^1.5.4",
|
|
||||||
"sortablejs": "^1.15.3",
|
"sortablejs": "^1.15.3",
|
||||||
"ua-parser-js": "^1.0.38",
|
"ua-parser-js": "^1.0.38",
|
||||||
"uuid": "^10.0.0",
|
"uuid": "^10.0.0",
|
||||||
|
|
@ -45,7 +44,6 @@
|
||||||
"@types/ali-oss": "^6.16.11",
|
"@types/ali-oss": "^6.16.11",
|
||||||
"@types/crypto-js": "^4.2.2",
|
"@types/crypto-js": "^4.2.2",
|
||||||
"@types/node": "^20.14.5",
|
"@types/node": "^20.14.5",
|
||||||
"@types/qrcode": "^1.5.5",
|
|
||||||
"@types/sortablejs": "^1.15.8",
|
"@types/sortablejs": "^1.15.8",
|
||||||
"@types/ua-parser-js": "^0.7.39",
|
"@types/ua-parser-js": "^0.7.39",
|
||||||
"@types/uuid": "^10.0.0",
|
"@types/uuid": "^10.0.0",
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 727 B |
|
Before Width: | Height: | Size: 525 B |
|
Before Width: | Height: | Size: 707 B |
|
Before Width: | Height: | Size: 536 B |
|
Before Width: | Height: | Size: 310 B |
|
Before Width: | Height: | Size: 173 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 629 B |
|
Before Width: | Height: | Size: 456 B |
|
Before Width: | Height: | Size: 452 B |
|
Before Width: | Height: | Size: 252 B |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 557 B |
|
Before Width: | Height: | Size: 8.3 KiB |
|
|
@ -14,8 +14,6 @@ import { computed } from 'vue'
|
||||||
import asyncLoader from './utils/asyncLoader'
|
import asyncLoader from './utils/asyncLoader'
|
||||||
import useLayoutStore from './layout/useLayoutStore'
|
import useLayoutStore from './layout/useLayoutStore'
|
||||||
import WelcomePage from './layout/grid/WelcomePage'
|
import WelcomePage from './layout/grid/WelcomePage'
|
||||||
import TomatoPage from './layout/grid/TomatoPage'
|
|
||||||
import useRouterStore from './useRouterStore'
|
|
||||||
const Grid = asyncLoader(() => import('./layout/grid'))
|
const Grid = asyncLoader(() => import('./layout/grid'))
|
||||||
const Fox = asyncLoader(() => import('./fox'))
|
const Fox = asyncLoader(() => import('./fox'))
|
||||||
const settings = useSettingsStore()
|
const settings = useSettingsStore()
|
||||||
|
|
@ -23,7 +21,6 @@ const blockSize = computed(() => settings.state.blockSize + 'rem')
|
||||||
const blockPadding = computed(() => settings.state.blockPadding + 'rem')
|
const blockPadding = computed(() => settings.state.blockPadding + 'rem')
|
||||||
const mainWidth = computed(() => settings.state.mainWidth + '%')
|
const mainWidth = computed(() => settings.state.mainWidth + '%')
|
||||||
const blockRadius = computed(() => settings.state.blockRadius)
|
const blockRadius = computed(() => settings.state.blockRadius)
|
||||||
const router = useRouterStore()
|
|
||||||
const layout = useLayoutStore()
|
const layout = useLayoutStore()
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -34,7 +31,7 @@ const layout = useLayoutStore()
|
||||||
<SettingsOverlay />
|
<SettingsOverlay />
|
||||||
<SettingsButton />
|
<SettingsButton />
|
||||||
<Sider />
|
<Sider />
|
||||||
<LoginModal v-if="router.path !== 'global-login'"/>
|
<LoginModal />
|
||||||
<Grid v-if="layout.ready" />
|
<Grid v-if="layout.ready" />
|
||||||
<Dock />
|
<Dock />
|
||||||
<div class="fixed z-40 right-[14%] top-8">
|
<div class="fixed z-40 right-[14%] top-8">
|
||||||
|
|
@ -43,7 +40,6 @@ const layout = useLayoutStore()
|
||||||
<DirModal />
|
<DirModal />
|
||||||
<GlobalMenu />
|
<GlobalMenu />
|
||||||
<WelcomePage></WelcomePage>
|
<WelcomePage></WelcomePage>
|
||||||
<TomatoPage></TomatoPage>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
import { defineComponent, Transition } from 'vue'
|
import { defineComponent, ref, Transition, watch } from 'vue'
|
||||||
import useLayoutStore from '../useLayoutStore'
|
import useLayoutStore from '../useLayoutStore'
|
||||||
import useSettingsStore from '@/settings/useSettingsStore'
|
import useSettingsStore from '@/settings/useSettingsStore'
|
||||||
import useBackgroundStore from './useBackgroundStore'
|
import useBackgroundStore from './useBackgroundStore'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'BackgroundPage',
|
|
||||||
setup() {
|
setup() {
|
||||||
const layout = useLayoutStore()
|
const layout = useLayoutStore()
|
||||||
const background = useBackgroundStore()
|
const background = useBackgroundStore()
|
||||||
|
|
@ -35,9 +34,7 @@ export default defineComponent({
|
||||||
backgroundColor: `rgba(0,0,0,${settings.state.maskOpacity})`,
|
backgroundColor: `rgba(0,0,0,${settings.state.maskOpacity})`,
|
||||||
backdropFilter: `blur(${settings.state.maskFilter}px)`
|
backdropFilter: `blur(${settings.state.maskFilter}px)`
|
||||||
}}
|
}}
|
||||||
>
|
></div>
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,102 +0,0 @@
|
||||||
import { computed, defineComponent, onMounted, ref, Transition } from 'vue'
|
|
||||||
import WelcomeImg from '~/public/icons/welcome/welcomeTitle.png'
|
|
||||||
import DivBgImg from '~/public/icons/welcome/back.png'
|
|
||||||
import startUseImg from '~/public/icons/welcome/startUse.png'
|
|
||||||
import useBackgroundStore from '../background/useBackgroundStore'
|
|
||||||
import useLayoutStore from '../useLayoutStore'
|
|
||||||
import useTomatoStore from '@/widgets/work/useTomatoStore'
|
|
||||||
import Search from '../header/search'
|
|
||||||
export const DefaultPageSetting = [
|
|
||||||
{
|
|
||||||
name: '游戏',
|
|
||||||
backgroundUrl:
|
|
||||||
'https://newfatfox.oss-cn-beijing.aliyuncs.com/000/user_upload/1/resource/831a4d4c-61ff-4bae-ad31-9c0f4fa2db1c.webp',
|
|
||||||
contentUrl:
|
|
||||||
'https://newfatfox.oss-cn-beijing.aliyuncs.com/000/user_upload/1/resource/b2f3ed2f-f550-499b-8ea1-dfd192cfd388.webp',
|
|
||||||
desct: '聚合多类游戏工具,以及 资讯、排行榜'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '工作台',
|
|
||||||
backgroundUrl:
|
|
||||||
'https://newfatfox.oss-cn-beijing.aliyuncs.com/000/user_upload/1/resource/b82fd47c-24c1-4f58-b0db-51414b3bdda4.webp',
|
|
||||||
contentUrl:
|
|
||||||
'https://newfatfox.oss-cn-beijing.aliyuncs.com/000/user_upload/1/resource/7e4cf74a-85cb-4e39-9e61-385b222ac8c4.webp',
|
|
||||||
desct: '结合番茄计时法等效率工具,让您可以高效学'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '轻娱',
|
|
||||||
backgroundUrl:
|
|
||||||
'https://newfatfox.oss-cn-beijing.aliyuncs.com/000/user_upload/1/resource/73164094-cb0d-4366-8d1a-afc84ac119cc.webp',
|
|
||||||
contentUrl:
|
|
||||||
'https://newfatfox.oss-cn-beijing.aliyuncs.com/000/user_upload/1/resource/bcbbffc6-c8a4-4c8e-8ba5-36fa1fbad4f9.webp',
|
|
||||||
desct: '综合办公、学习、游戏等 属性,功能较为均'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
export default defineComponent(() => {
|
|
||||||
const show = computed(() => true)
|
|
||||||
const selectMode = ref(0)
|
|
||||||
const background = useBackgroundStore()
|
|
||||||
const layout = useLayoutStore()
|
|
||||||
|
|
||||||
const store = useTomatoStore()
|
|
||||||
const isFirst = ref(false)
|
|
||||||
onMounted(() => {
|
|
||||||
// 检查 localStorage 是否已经有访问记录
|
|
||||||
const visited = localStorage.getItem('hasVisited')
|
|
||||||
|
|
||||||
if (!visited) {
|
|
||||||
// 如果没有记录,说明是第一次访问
|
|
||||||
isFirst.value = true
|
|
||||||
// 设置标记,后续访问不会再次显示
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return () =>
|
|
||||||
!store.openFullscreen && (
|
|
||||||
<div class="fixed left-0 top-0 z-50 w-full ">
|
|
||||||
<Transition name="background">
|
|
||||||
{background.bgTrriger && (
|
|
||||||
<>
|
|
||||||
{layout.background.video ? (
|
|
||||||
<video src={layout.background.video} class="w-full h-screen" />
|
|
||||||
) : (
|
|
||||||
<div
|
|
||||||
class="w-full h-screen bg-center bg-cover bg-no-repeat"
|
|
||||||
style={{
|
|
||||||
backgroundImage: `url('${layout.background.image}')`
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Transition>
|
|
||||||
<Transition name="modal">
|
|
||||||
|
|
||||||
<div class={"w-[500px] h-[500px] absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 "}>
|
|
||||||
{
|
|
||||||
Array.from({ length: 60 }).map((_, idx) => (
|
|
||||||
<div class={"bg-white w-[30px] h-[5px] absolute mt-[-2.5px] top-1/2"} style={{
|
|
||||||
transformOrigin: '250px',
|
|
||||||
borderRadius: '3px',
|
|
||||||
transform: `rotateZ(${idx * 6}deg)`
|
|
||||||
|
|
||||||
}}>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
<div class={"w-[500px] flex justify-center flex-col items-center h-full "}>
|
|
||||||
<span class={"text-[24px] leading-[36px]"}>专注中</span>
|
|
||||||
<span class={"font-din text-[82px] font-bold leading-[115px]"}>15:00</span>
|
|
||||||
<div class={"relative"}>
|
|
||||||
<Search isMini></Search>
|
|
||||||
</div>
|
|
||||||
<div class={"w-full flex gap-x-3"}>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</Transition>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
@ -6,33 +6,24 @@ import SearchConfig from './SearchConfig'
|
||||||
import SearchHistory from './SearchHistory'
|
import SearchHistory from './SearchHistory'
|
||||||
import SearchSuggestion from './SearchSuggestion'
|
import SearchSuggestion from './SearchSuggestion'
|
||||||
import useLayoutStore from '@/layout/useLayoutStore'
|
import useLayoutStore from '@/layout/useLayoutStore'
|
||||||
import clsx from 'clsx'
|
|
||||||
|
|
||||||
export default defineComponent((props: {
|
export default defineComponent(() => {
|
||||||
isMini?: boolean
|
|
||||||
}) => {
|
|
||||||
const settings = useSettingsStore()
|
const settings = useSettingsStore()
|
||||||
const search = useSearchStore()
|
const search = useSearchStore()
|
||||||
const searchConfig = useSearchConfigStore()
|
const searchConfig = useSearchConfigStore()
|
||||||
const layout = useLayoutStore()
|
const layout = useLayoutStore()
|
||||||
return () => (
|
return () => (
|
||||||
<div
|
<div
|
||||||
class={clsx(!props?.isMini ? "absolute left-1/2 -translate-x-1/2 z-20 transition-all" : "w-full")}
|
class="absolute left-1/2 -translate-x-1/2 z-20 transition-all"
|
||||||
style={
|
style={{
|
||||||
props.isMini ? {
|
top: layout.isCompact ? '40px' : '172px',
|
||||||
|
width: settings.state.searchWidth + 'rem'
|
||||||
} :
|
}}
|
||||||
{
|
|
||||||
top: layout.isCompact ? '40px' : '172px',
|
|
||||||
width: settings.state.searchWidth + 'rem'
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class={
|
class={
|
||||||
clsx(
|
'w-full h-11 shadow-content overflow-hidden max-w-[90vw] px-1 transition-all flex justify-between items-center gap-4 ' +
|
||||||
'w-full h-11 shadow-content overflow-hidden px-1 transition-all flex justify-between items-center gap-4 ',
|
(search.focus ? 'bg-white/60' : 'bg-white/40 hover:bg-white/60')
|
||||||
(search.focus ? 'bg-white/60' : 'bg-white/40 hover:bg-white/60'),
|
|
||||||
props.isMini ? "" : "max-w-[90vw] w-full")
|
|
||||||
}
|
}
|
||||||
style={{
|
style={{
|
||||||
borderRadius: settings.state.searchRadius + 'px'
|
borderRadius: settings.state.searchRadius + 'px'
|
||||||
|
|
@ -69,7 +60,4 @@ export default defineComponent((props: {
|
||||||
</Transition>
|
</Transition>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}, {
|
|
||||||
name: 'SearchComponent',
|
|
||||||
props: ['isMini']
|
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,42 +1,14 @@
|
||||||
import { defineComponent, onMounted, reactive, ref, Transition, watch } from 'vue'
|
import { defineComponent, reactive, Transition } from 'vue'
|
||||||
import useRouterStore from '@/useRouterStore'
|
import useRouterStore from '@/useRouterStore'
|
||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
import useUserStore from './useUserStore'
|
import useUserStore from './useUserStore'
|
||||||
import Logo from '~/public/logo.png'
|
|
||||||
import LogoIcon from '~/public/loginIcon.png'
|
|
||||||
import LogoClose from '~/public/icons/loginClose.png'
|
|
||||||
import { message, Spin } from 'ant-design-vue'
|
|
||||||
import { v4 as uuid } from 'uuid'
|
|
||||||
import QrCode from 'qrcode'
|
|
||||||
|
|
||||||
export default defineComponent(() => {
|
export default defineComponent(() => {
|
||||||
const router = useRouterStore()
|
const router = useRouterStore()
|
||||||
const user = useUserStore()
|
const user = useUserStore()
|
||||||
|
const form = reactive({
|
||||||
const wxCode = ref('')
|
email: '',
|
||||||
const _id = ref(uuid())
|
password: ''
|
||||||
onMounted(() => {
|
|
||||||
request<string>('GET', `/api/wxloginimg?uuid=${_id.value}`, {
|
|
||||||
returnType: 'text'
|
|
||||||
})
|
|
||||||
.then((res) => QrCode.toDataURL(res))
|
|
||||||
.then((res) => {
|
|
||||||
wxCode.value = res
|
|
||||||
})
|
|
||||||
})
|
|
||||||
watch(wxCode, (url, _, onCleanUp) => {
|
|
||||||
if (!url) return
|
|
||||||
const it = setInterval(() => {
|
|
||||||
request('GET', `/api/wxlogin2/access?uuid=${_id.value}`).then((res) => {
|
|
||||||
if (res) {
|
|
||||||
clearInterval(it)
|
|
||||||
console.log(res)
|
|
||||||
|
|
||||||
message.success('登录成功')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}, 2000)
|
|
||||||
onCleanUp(() => clearInterval(it))
|
|
||||||
})
|
})
|
||||||
return () => (
|
return () => (
|
||||||
<div class="fixed left-0 top-0 z-50 w-full">
|
<div class="fixed left-0 top-0 z-50 w-full">
|
||||||
|
|
@ -52,36 +24,37 @@ export default defineComponent(() => {
|
||||||
</Transition>
|
</Transition>
|
||||||
<Transition name="modal">
|
<Transition name="modal">
|
||||||
{router.path === 'global-login' && (
|
{router.path === 'global-login' && (
|
||||||
<div class="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 overflow-hidden transition-all w-[540px] max-w-[90%] h-[400px] rounded-lg p-1 bg-white/30 backdrop-blur">
|
<div class="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 overflow-hidden transition-all w-[540px] max-w-[90%] rounded-lg p-2 bg-white/40 backdrop-blur">
|
||||||
<div class="w-full h-full rounded-lg bg-white overflow-hidden relative">
|
<div class="w-full h-full rounded-lg bg-white/80 overflow-hidden">
|
||||||
<div class="flex justify-center pt-8">
|
<div class="flex justify-center py-4">
|
||||||
<img src={Logo} alt="logo" class="w-1/3" />
|
<img src="/logo.png" alt="logo" class="w-1/3" />
|
||||||
</div>
|
</div>
|
||||||
<div class={'flex flex-col justify-center items-center my-8 gap-y-7'}>
|
<div class="text-center text-lg text-black/60 font-bold tracking-widest">
|
||||||
<div class={'w-[165px] h-[165px] border-[2px] border-[#d4d4d4] rounded-md'}>
|
登录 Fatfox 新标签页
|
||||||
{wxCode.value ? (
|
</div>
|
||||||
<img src={wxCode.value} alt="wxCode" class="w-full h-full " />
|
<div class="flex flex-col">
|
||||||
) : (
|
测试用
|
||||||
<div class="flex justify-center items-center w-full h-full">
|
<form>
|
||||||
<Spin></Spin>
|
<input placeholder="邮箱" v-model={form.email} />
|
||||||
</div>
|
<input placeholder="密码" type="password" v-model={form.password} />
|
||||||
)}
|
</form>
|
||||||
</div>
|
<button
|
||||||
|
onClick={() => {
|
||||||
<span class={'text-[#666] text-[16px] leading-[24px]'}>
|
request<string>('POST', '/api/user/login', {
|
||||||
打开微信<span class={'text-[#333] font-bold'}>扫一扫,关注公众号</span>
|
data: form,
|
||||||
后即可登录/注册
|
returnType: 'text'
|
||||||
</span>
|
}).then((res) => {
|
||||||
|
user.token = res
|
||||||
|
router.go('')
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
立即登录
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-end py-4">
|
||||||
|
<img src="/logo.png" alt="logo" class="w-1/2 relative top-8 left-4 opacity-10" />
|
||||||
</div>
|
</div>
|
||||||
<img src={LogoIcon} alt="logo" class="w-[220px] absolute bottom-0 right-0 " />
|
|
||||||
<img
|
|
||||||
onClick={() => {
|
|
||||||
router.back()
|
|
||||||
}}
|
|
||||||
src={LogoClose}
|
|
||||||
alt="close icon"
|
|
||||||
class={'w-[32px] right-2 top-2 absolute cursor-pointer'}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
import { defineComponent } from 'vue'
|
|
||||||
|
|
||||||
export default defineComponent(() => {
|
|
||||||
return () => (
|
|
||||||
<div class="w-full h-full bg-[#ecfbff] flex flex-col">
|
|
||||||
large
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
import { defineComponent } from 'vue'
|
|
||||||
|
|
||||||
export default defineComponent(() => {
|
|
||||||
|
|
||||||
return () => (
|
|
||||||
<div class="w-full h-full bg-[#ecfbff] flex flex-col">
|
|
||||||
middle
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
import { defineComponent } from 'vue'
|
|
||||||
|
|
||||||
export default defineComponent(() => {
|
|
||||||
return () => (
|
|
||||||
<div
|
|
||||||
class="w-full h-full bg-red-50 flex "
|
|
||||||
style={{
|
|
||||||
background: 'linear-gradient(180deg,#dcefff 0%,#e7ecff 100%)'
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
import { defineComponent } from 'vue'
|
|
||||||
|
|
||||||
export default defineComponent(() => {
|
|
||||||
return () => (
|
|
||||||
<div
|
|
||||||
class="w-full h-full items-center pl-3 gap-x-2 flex py-3 text-white"
|
|
||||||
style={{
|
|
||||||
background: 'linear-gradient(135deg,#5996ff 0%,#4862ff 100%)'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
import asyncLoader from '@/utils/asyncLoader'
|
|
||||||
import type { Widget } from '..'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'gameNews',
|
|
||||||
label: '游戏资讯',
|
|
||||||
description: '游戏资讯',
|
|
||||||
icon: '/tab/icons/game_news_icon.png',
|
|
||||||
modal: asyncLoader(() => import('./Modal')),
|
|
||||||
list: [
|
|
||||||
{
|
|
||||||
w: 2,
|
|
||||||
h: 1,
|
|
||||||
label: '小',
|
|
||||||
component: asyncLoader(() => import('./Small'))
|
|
||||||
},
|
|
||||||
{
|
|
||||||
w: 2,
|
|
||||||
h: 2,
|
|
||||||
label: '中',
|
|
||||||
component: asyncLoader(() => import('./Middle'))
|
|
||||||
},
|
|
||||||
{
|
|
||||||
w: 4,
|
|
||||||
h: 2,
|
|
||||||
label: '大',
|
|
||||||
component: asyncLoader(() => import('./Large'))
|
|
||||||
}
|
|
||||||
]
|
|
||||||
} as Widget
|
|
||||||
|
|
@ -8,7 +8,6 @@ import discount from './discount'
|
||||||
import hotspot from './hotspot'
|
import hotspot from './hotspot'
|
||||||
import constellation from './constellation'
|
import constellation from './constellation'
|
||||||
import gameVideo from './gameVideo'
|
import gameVideo from './gameVideo'
|
||||||
import work from './work'
|
|
||||||
export interface Widget {
|
export interface Widget {
|
||||||
name: string // 小组件类型唯一标识
|
name: string // 小组件类型唯一标识
|
||||||
label: string // 小组件名称
|
label: string // 小组件名称
|
||||||
|
|
@ -23,4 +22,4 @@ export interface Widget {
|
||||||
}[] // 不同尺寸小组件块
|
}[] // 不同尺寸小组件块
|
||||||
}
|
}
|
||||||
|
|
||||||
export default [calendar, weather, weApply, gameNews, eat, discount, hotspot, constellation, gameVideo, work] as Widget[]
|
export default [calendar, weather, weApply, gameNews, eat, discount, hotspot, constellation, gameVideo] as Widget[]
|
||||||
|
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
import { defineComponent } from 'vue'
|
|
||||||
|
|
||||||
export default defineComponent(() => {
|
|
||||||
return () => (
|
|
||||||
<div class="w-full h-full bg-[#ecfbff] flex flex-col">
|
|
||||||
large
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
@ -1,245 +0,0 @@
|
||||||
import clsx from 'clsx'
|
|
||||||
import { defineComponent, ref } from 'vue'
|
|
||||||
import PlusIcon from '~/public/icons/work/tomato_work_add_icon.png'
|
|
||||||
import DataImg from '~/public/icons/work/dataImg.png'
|
|
||||||
import DateImg from '~/public/icons/work/dateImg.png'
|
|
||||||
import ListImg from '~/public/icons/work/listImg.png'
|
|
||||||
import AddImg from '~/public/icons/work/addTarget.png'
|
|
||||||
import DownImg from "~/public/icons/work/selectDown1.0.3.png"
|
|
||||||
import { v4 as uuid } from "uuid"
|
|
||||||
import List from './modal_view/list'
|
|
||||||
import { DatePicker, Modal, TimePicker } from 'ant-design-vue'
|
|
||||||
import type { TomatoTarget } from './useTomatoStore'
|
|
||||||
import dayjs from 'dayjs'
|
|
||||||
import useTomatoStore from './useTomatoStore'
|
|
||||||
import Calendar from './modal_view/calendar'
|
|
||||||
const workTab = [
|
|
||||||
{
|
|
||||||
title: '目标列表',
|
|
||||||
key: 'list',
|
|
||||||
icon: ListImg
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '目标日历',
|
|
||||||
key: 'schedule',
|
|
||||||
icon: DateImg
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '数据详情',
|
|
||||||
key: 'detail',
|
|
||||||
icon: DataImg
|
|
||||||
}
|
|
||||||
]
|
|
||||||
const EditContent = defineComponent(() => {
|
|
||||||
const store = useTomatoStore()
|
|
||||||
const form = ref<TomatoTarget>(
|
|
||||||
store.openShowModel || {
|
|
||||||
title: '',
|
|
||||||
id: uuid(),
|
|
||||||
finishTime: dayjs().valueOf(),
|
|
||||||
remindTime: null,
|
|
||||||
isCompleted: false
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return () => (
|
|
||||||
<div class={'w-full flex flex-col bg-white items-start gap-y-2 pl-2'}>
|
|
||||||
<span class={'text-[16px] font-bold text-[#333] mt-[10px] text-center flex justify-center w-full'}>新建目标</span>
|
|
||||||
<div
|
|
||||||
class={'w-full h-[40px] mt-4 relative rounded-lg pl-[50px] bg-black/[0.05]'}
|
|
||||||
style={{
|
|
||||||
boxShadow: 'inset 0 1px 6px #0000000d'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
src={AddImg}
|
|
||||||
alt="add img"
|
|
||||||
class={'left-4 absolute top-1/2 -translate-y-1/2 w-[15px] h-[16px]'}
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
value={form.value.title}
|
|
||||||
onInput={(e: any) => {
|
|
||||||
form.value.title = e.target.value
|
|
||||||
}}
|
|
||||||
type="text"
|
|
||||||
placeholder="未命名目标"
|
|
||||||
class={'w-full bg-transparent outline-none text-[14px] text-[#333] h-full'}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<span class={'text-[#666] text-[14px] my-1'}>添加目标完成时间</span>
|
|
||||||
<div class={'flex items-center gap-x-2 '}>
|
|
||||||
<div
|
|
||||||
onClick={() => {
|
|
||||||
form.value.finishTime = dayjs().valueOf()
|
|
||||||
}}
|
|
||||||
class={clsx(
|
|
||||||
' px-6 py-2 rounded-lg cursor-pointer',
|
|
||||||
dayjs(form.value.finishTime).isSame(dayjs(), 'day')
|
|
||||||
? 'bg-[#EBF0FF] text-[#5a6eff]'
|
|
||||||
: 'bg-black/[0.05]'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
今天
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
onClick={() => {
|
|
||||||
form.value.finishTime = dayjs().add(1, 'day').valueOf()
|
|
||||||
}}
|
|
||||||
class={clsx(
|
|
||||||
' px-6 py-2 rounded-lg cursor-pointer',
|
|
||||||
dayjs(form.value.finishTime).isSame(dayjs().add(1, 'day'), 'day')
|
|
||||||
? 'bg-[#EBF0FF] text-[#5a6eff]'
|
|
||||||
: 'bg-black/[0.05]'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
明天
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class={clsx(
|
|
||||||
' px-6 py-2 rounded-lg cursor-pointer relative',
|
|
||||||
!(
|
|
||||||
dayjs(form.value.finishTime).isSame(dayjs(), 'day') ||
|
|
||||||
dayjs(form.value.finishTime).isSame(dayjs().add(1, 'day'), 'day')
|
|
||||||
)
|
|
||||||
? 'bg-[#EBF0FF] text-[#5a6eff]'
|
|
||||||
: 'bg-black/[0.05]'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{dayjs(form.value.finishTime).format('YYYY-MM-DD')}
|
|
||||||
<DatePicker
|
|
||||||
class={'absolute opacity-0 left-0 top-0 w-full h-full'}
|
|
||||||
onChange={(e) => {
|
|
||||||
form.value.finishTime = dayjs(e).valueOf()
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<span class={'text-[#666] text-[14px] my-1'}>添加提醒时间</span>
|
|
||||||
<div
|
|
||||||
class={clsx(
|
|
||||||
' px-6 py-2 rounded-lg cursor-pointer group relative items-center flex gap-x-1',
|
|
||||||
(
|
|
||||||
form.value.remindTime
|
|
||||||
)
|
|
||||||
? 'bg-[#EBF0FF] text-[#5a6eff]'
|
|
||||||
: 'bg-black/[0.05]'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{
|
|
||||||
<>
|
|
||||||
{!form.value.remindTime ? '选择时间' : dayjs(form.value.remindTime).format('HH:mm')}
|
|
||||||
<img src={DownImg} class={"w-[12px] object-cover "}></img>
|
|
||||||
<TimePicker
|
|
||||||
|
|
||||||
class={'absolute opacity-0 left-0 top-0 w-full h-full'}
|
|
||||||
onChange={(e) => {
|
|
||||||
form.value.remindTime = dayjs(e).valueOf()
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<div class={"w-[16px] hidden group-hover:flex h-[16px] absolute -right-1 -top-1 bg-[#ddd] rounded-full items-center justify-center"}
|
|
||||||
onClick={() => {
|
|
||||||
form.value.remindTime = null
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div class={"w-[12px] h-[3px] bg-white"}></div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class={"my-3 w-full text-center flex justify-center"}>
|
|
||||||
{
|
|
||||||
form.value.title ?
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
const idx = store.state.list.findIndex(val => val.id === form.value.id)
|
|
||||||
if (idx !== -1) {
|
|
||||||
store.state.list[idx] = form.value
|
|
||||||
} else {
|
|
||||||
store.state.list.push(form.value)
|
|
||||||
|
|
||||||
}
|
|
||||||
store.openShowModel = undefined
|
|
||||||
}}
|
|
||||||
class={"px-10 py-2 font-bold text-[16px] text-white rounded-lg flex items-center justify-center cursor-pointer hover:opacity-90 duration-150"} style={{
|
|
||||||
background: 'linear-gradient(225deg,#642FFF 0%,#5162FF 100%)',
|
|
||||||
boxShadow: '0 2px 6px #00000026'
|
|
||||||
}}>确定</button> :
|
|
||||||
<button class={"px-10 py-2 font-bold text-[16px] text-white rounded-lg flex items-center bg-[#bdbdbd] justify-center duration-150"} style={{
|
|
||||||
boxShadow: '0 2px 6px #00000026'
|
|
||||||
}}>确定</button>
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
export default defineComponent(() => {
|
|
||||||
const select = ref(0)
|
|
||||||
const store = useTomatoStore()
|
|
||||||
return () => (
|
|
||||||
<div class="w-full h-full flex bg-white">
|
|
||||||
<Modal
|
|
||||||
class={'bg-white p-0 rounded-lg'}
|
|
||||||
zIndex={60}
|
|
||||||
footer={null}
|
|
||||||
centered
|
|
||||||
destroyOnClose
|
|
||||||
open={store.openShowModel !== undefined}
|
|
||||||
onCancel={() => {
|
|
||||||
store.openShowModel = undefined
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<EditContent></EditContent>
|
|
||||||
</Modal>
|
|
||||||
<div class={'w-[174px] h-full bg-[#F8F8F8] flex py-10 flex-col items-center'}>
|
|
||||||
<div
|
|
||||||
onClick={() => {
|
|
||||||
store.openShowModel = null
|
|
||||||
}}
|
|
||||||
class={
|
|
||||||
'w-[126px] h-[44px] leading-[44px] shadow-lg rounded-lg justify-center items-center gap-x-1 font-bold text-white flex hover:opacity-90 cursor-pointer '
|
|
||||||
}
|
|
||||||
style={{
|
|
||||||
background: 'linear-gradient(225deg,#5A6EFF 0%,#519DFF 100%)'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<img class={'w-[16px] h-[16px]'} src={PlusIcon} alt="" />
|
|
||||||
新建目标
|
|
||||||
</div>
|
|
||||||
<div class={'flex flex-col gap-y-1 mt-5 w-full'}>
|
|
||||||
{workTab.map((item, index) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
onClick={() => {
|
|
||||||
select.value = index
|
|
||||||
}}
|
|
||||||
class={clsx(
|
|
||||||
'w-full flex pl-6 items-center py-4 border-l-[8px] gap-x-2 cursor-pointer',
|
|
||||||
select.value === index
|
|
||||||
? 'bg-[#90adff2e] text-[#5a6eff] border-[#5a6eff]'
|
|
||||||
: 'text-[#666666] border-transparent hover:bg-[#97aff02e]'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<img class={'w-[18px] h-[18px]'} src={item.icon} alt="" />
|
|
||||||
<span>{item.title}</span>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class={'flex-1 w-0 h-full p-3'}>
|
|
||||||
{select.value === 0 ? (
|
|
||||||
<List></List>
|
|
||||||
) : select.value === 1 ? (
|
|
||||||
<Calendar />
|
|
||||||
) : select.value === 2 ? (
|
|
||||||
<div>数据详情</div>
|
|
||||||
) : (
|
|
||||||
<>loading</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
import { defineComponent } from 'vue'
|
|
||||||
|
|
||||||
export default defineComponent(() => {
|
|
||||||
return () => (
|
|
||||||
<div
|
|
||||||
class="w-full h-full items-center pl-3 gap-x-2 flex py-3 text-white"
|
|
||||||
style={{
|
|
||||||
background: 'linear-gradient(135deg,#5996ff 0%,#4862ff 100%)'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
import asyncLoader from '@/utils/asyncLoader'
|
|
||||||
import type { Widget } from '..'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'work',
|
|
||||||
label: '番茄工作法',
|
|
||||||
description: '番茄记事法',
|
|
||||||
icon: '/tab/icons/work/tomato_work_icon.png',
|
|
||||||
modal: asyncLoader(() => import('./Modal')),
|
|
||||||
list: [
|
|
||||||
{
|
|
||||||
w: 2,
|
|
||||||
h: 1,
|
|
||||||
label: '小',
|
|
||||||
component: asyncLoader(() => import('./Small'))
|
|
||||||
},
|
|
||||||
{
|
|
||||||
w: 4,
|
|
||||||
h: 2,
|
|
||||||
label: '大',
|
|
||||||
component: asyncLoader(() => import('./Large'))
|
|
||||||
}
|
|
||||||
]
|
|
||||||
} as Widget
|
|
||||||
|
|
@ -1,108 +0,0 @@
|
||||||
import { useCalendarStore } from "@/widgets/calendar/useCalendarStore";
|
|
||||||
import { DatePicker } from "ant-design-vue";
|
|
||||||
import DownImg from "~/public/icons/work/selectDown1.0.3.png"
|
|
||||||
import clsx from "clsx";
|
|
||||||
import dayjs from "dayjs";
|
|
||||||
import { defineComponent, ref } from "vue";
|
|
||||||
import useTomatoStore from "../useTomatoStore";
|
|
||||||
const dayList = ['日', '一', '二', '三', '四', '五', '六']
|
|
||||||
|
|
||||||
export default defineComponent(() => {
|
|
||||||
const selectTime = ref(dayjs().valueOf())
|
|
||||||
const store = useTomatoStore()
|
|
||||||
const dateStore = useCalendarStore()
|
|
||||||
return () => <div class={"w-full h-full flex p-3 flex-col gap-y-2"}>
|
|
||||||
<div
|
|
||||||
class={
|
|
||||||
'bg-black/[.1] cursor-pointer text-[#333] text-[14px] items-center overflow-hidden relative w-[138px] gap-x-1 flex justify-center py-2 rounded'
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<DatePicker
|
|
||||||
class={'w-full absolute left-0 top-0 opacity-0 '}
|
|
||||||
picker="month"
|
|
||||||
onChange={(e) => {
|
|
||||||
selectTime.value = dayjs(e).valueOf()
|
|
||||||
dateStore.state.select = dayjs(selectTime.value)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{dayjs(selectTime.value).format("YYYY年MM月")}
|
|
||||||
<img src={DownImg} class={"w-[12px] object-cover "}></img>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class={'flex-1 h-0 w-full '}>
|
|
||||||
<div class={"grid grid-cols-7 grid-rows-1 w-full"}>
|
|
||||||
{dayList.map((item) => {
|
|
||||||
return (
|
|
||||||
<div key={item} class="p-2">
|
|
||||||
<span class="text-[16px] text-[#333333] dark:text-white">{item}</span>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
<div class={'w-full grid grid-cols-7 grid-rows-auto bg-[#f8f8f8] gap-x-[4px] gap-y-[3px] rounded-lg p-2'}
|
|
||||||
style={{
|
|
||||||
boxShadow: '0 2px 12px #0000001a'
|
|
||||||
}}>
|
|
||||||
{/* {dayList.map((item) => {
|
|
||||||
return (
|
|
||||||
<div key={item} class="flex justify-center items-center ">
|
|
||||||
<span class="text-[16px] font-bold text-[#333333] dark:text-white">{item}</span>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})} */}
|
|
||||||
{dateStore.dayList
|
|
||||||
.filter(
|
|
||||||
(_, index) =>
|
|
||||||
index <
|
|
||||||
(dateStore.dayList.reduce((acc, cur) => (cur!.type !== 1 ? acc + 1 : acc), 0) > 35
|
|
||||||
? 42
|
|
||||||
: 35)
|
|
||||||
)
|
|
||||||
|
|
||||||
.map((el) => (
|
|
||||||
<div
|
|
||||||
onClick={() => {
|
|
||||||
// selectTime.value = el.day.valueOf()
|
|
||||||
}}
|
|
||||||
class={clsx(
|
|
||||||
'p-2 flex gap-x-2 cursor-pointer border-[1px] w-full h-[77px] flex-grow-0 hover:border-[#5A6EFF] rounded',
|
|
||||||
{
|
|
||||||
' opacity-40': el.type === 1 || el.type === -1,
|
|
||||||
'border-[#5A6EFF] border-solid border-[1px] ': el.day.isSame(
|
|
||||||
dayjs(),
|
|
||||||
'day'
|
|
||||||
),
|
|
||||||
'border-transparent border-solid': !el.day.isSame(dayjs(), 'day') && !el.day.isSame(selectTime.value, 'day'),
|
|
||||||
'border-[#5A6EFF] border-solid border-[1px]': !el.day.isSame(dayjs(), 'day') && el.day.isSame(selectTime.value, 'day'),
|
|
||||||
}
|
|
||||||
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<span class={'text-[14px] '}>{el.label}</span>
|
|
||||||
<div class={"flex-1 w-0 h-full"}>
|
|
||||||
<div class={"flex flex-col gap-y-1 justify-between"}>
|
|
||||||
{
|
|
||||||
store.state.list.filter((val, idx) => dayjs(val.finishTime).isSame(dayjs(el.day), 'day') && idx <= 2).map(item => (
|
|
||||||
<span class={clsx("border-l-[4px] leading-[16px] pl-[2px] text-[16px] border-l-[#5A6EFF] whitespace-nowrap overflow-hidden text-ellipsis ",
|
|
||||||
item.isCompleted ? " line-through text-[#999]" : " text-[#333]"
|
|
||||||
)}>
|
|
||||||
{item.title}
|
|
||||||
</span>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
{
|
|
||||||
store.state.list.filter((val) => dayjs(val.finishTime).isSame(dayjs(el.day), 'day')).length > 2 &&
|
|
||||||
<span class={clsx("border-l-[4px] leading-[16px] pl-[2px] text-[16px] border-l-[#5A6EFF] whitespace-nowrap overflow-hidden text-ellipsis ",
|
|
||||||
)}>
|
|
||||||
...
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
})
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
import { defineComponent } from "vue";
|
|
||||||
|
|
||||||
export default defineComponent(() => {
|
|
||||||
return () => (
|
|
||||||
<div class={"w-full h-full"}>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
@ -1,108 +0,0 @@
|
||||||
import { computed, defineComponent, ref } from 'vue'
|
|
||||||
import useTomatoStore from '../useTomatoStore'
|
|
||||||
import NoDataImg from "~/public/icons/work/noData.png"
|
|
||||||
import clsx from 'clsx'
|
|
||||||
import dayjs from 'dayjs'
|
|
||||||
import PlayImg from "~/public/icons/work/work_page-play.png"
|
|
||||||
export default defineComponent(() => {
|
|
||||||
const store = useTomatoStore()
|
|
||||||
const searchText = ref('')
|
|
||||||
|
|
||||||
return () => (
|
|
||||||
<div class={'w-full h-full p-3 flex flex-col'}>
|
|
||||||
<input
|
|
||||||
onInput={(e: any) => {
|
|
||||||
searchText.value = e.target.value
|
|
||||||
}}
|
|
||||||
type="text"
|
|
||||||
placeholder='搜索目标'
|
|
||||||
class={' border-transparent pb-1 border-b-[1px] border-b-[#ddd] overflow-hidden outline-none border-[1px] w-full'}
|
|
||||||
/>
|
|
||||||
<div class="flex flex-1 h-0 w-full ">
|
|
||||||
{
|
|
||||||
store.state.list.length === 0 ?
|
|
||||||
<div class={"w-full h-full flex items-center flex-col justify-center"}>
|
|
||||||
<img src={NoDataImg} alt='no data' class={"w-[300px]"}></img>
|
|
||||||
<div class={"text-[#666] text-[14px]"}>暂无目标</div>
|
|
||||||
</div>
|
|
||||||
: <div class={"w-full flex flex-col gap-y-2 py-2 pr-1 overflow-y-auto overflow-x-visible scrollbar-hide "}>
|
|
||||||
{
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
store.state.list.filter(val => val.title.includes(searchText.value)).sort((a, _) => {
|
|
||||||
return !a.isCompleted ? -1 : 1
|
|
||||||
}).map((item, idx) => (
|
|
||||||
<div
|
|
||||||
key={item.id}
|
|
||||||
onClick={() => {
|
|
||||||
store.openShowModel = item
|
|
||||||
|
|
||||||
}}
|
|
||||||
class={clsx("flex justify-between py-2 rounded-lg cursor-pointer relative group text-[#333] ",
|
|
||||||
item.isCompleted ? "bg-[#e4e4e4]" : "bg-[#EBF0FF] hover:bg-[#5a6eff] hover:text-white "
|
|
||||||
)}>
|
|
||||||
<div class={"w-[50px] flex justify-center items-center"}>
|
|
||||||
<div class={clsx("w-[20px] h-[20px] flex items-center justify-center rounded-full",
|
|
||||||
item.isCompleted ? "bg-[#d1d1d1]" : "bg-[#9fb7ff] group-hover:bg-white"
|
|
||||||
)}
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation()
|
|
||||||
store.state.list[idx].isCompleted = !item.isCompleted
|
|
||||||
}}>
|
|
||||||
{
|
|
||||||
!item.isCompleted &&
|
|
||||||
<div class={"w-[8px] h-[8px] bg-white group-hover:bg-[#9fb7ff] rounded-full"}></div>
|
|
||||||
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class={"flex-1 w-0 flex justify-between pr-4"}>
|
|
||||||
|
|
||||||
<span class={"w-[500px] text-[14px] whitespace-nowrap text-ellipsis overflow-hidden "}>
|
|
||||||
{item.title}
|
|
||||||
</span>
|
|
||||||
<span class={clsx("text-[#666] text-[14px]", !item.isCompleted && "group-hover:text-[#ddd]")}>{dayjs(item.finishTime).format('MM月DD日')}</span>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class={"w-[16px] hidden group-hover:flex z-10 h-[16px] absolute -right-1 -top-1 bg-[#ddd] rounded-full items-center justify-center"}
|
|
||||||
onClick={() => {
|
|
||||||
const idx = store.state.list.findIndex(val => val.id === item.id)
|
|
||||||
if (idx !== -1) {
|
|
||||||
store.state.list.splice(0, 1)
|
|
||||||
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div class={"w-[12px] h-[3px] bg-white"}></div>
|
|
||||||
</div>
|
|
||||||
</div>))
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class={"relative h-[120px] w-full py-1"}>
|
|
||||||
<div class={"w-full h-full rounded-lg border-[1px] border-black/20 justify-between flex items-center px-4"}>
|
|
||||||
<div class={"flex flex-col text-[16px] gap-y-2"}>
|
|
||||||
<span class={" tracking-wide"}>你今日已完成 <span class={"text-[#5b47ff]"}>{store.state.list.filter(val => dayjs(val.finishTime).isSame(dayjs(), 'day') && val.isCompleted).length}</span>个番茄时</span>
|
|
||||||
<span class={"text-[#ff8686]"}>不积跬步无以至千里、千里之行始于足下。</span>
|
|
||||||
</div>
|
|
||||||
<button class={"w-[126px] h-[44px] text-[16px] text-white rounded-lg gap-x-1 font-bold flex items-center justify-center"} style={{
|
|
||||||
background: 'linear-gradient(225deg,#642FFF 0%,#5162FF 100%)',
|
|
||||||
boxShadow: '0 2px 4px #0003'
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
|
||||||
store.openFullscreen = true
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
|
|
||||||
<img src={PlayImg} alt="play img " class={"w-[13px]"} />
|
|
||||||
开始计时
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
import { defineStore } from "pinia";
|
|
||||||
import { reactive, ref } from "vue";
|
|
||||||
|
|
||||||
export type TomatoTarget = {
|
|
||||||
id: string;
|
|
||||||
finishTime: number;
|
|
||||||
remindTime: number | null;
|
|
||||||
title: string;
|
|
||||||
isCompleted: boolean;
|
|
||||||
|
|
||||||
}
|
|
||||||
export type TomatoTime = {
|
|
||||||
date: number;
|
|
||||||
finishTime: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default defineStore("work", () => {
|
|
||||||
const state = reactive({
|
|
||||||
list: [] as TomatoTarget[],
|
|
||||||
timeList: [] as TomatoTime[]
|
|
||||||
|
|
||||||
})
|
|
||||||
const openShowModel = ref<undefined | null | TomatoTarget>()
|
|
||||||
const openFullscreen = ref(false)
|
|
||||||
return {
|
|
||||||
state,
|
|
||||||
openShowModel,
|
|
||||||
openFullscreen
|
|
||||||
}
|
|
||||||
})
|
|
||||||