Merge remote-tracking branch 'origin/tomato'
This commit is contained in:
commit
ddb834f0f7
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
Binary file not shown.
After Width: | Height: | Size: 765 B |
Binary file not shown.
After Width: | Height: | Size: 381 B |
|
@ -17,6 +17,8 @@ import WelcomePage from './layout/grid/WelcomePage'
|
||||||
import TomatoPage from './layout/grid/TomatoPage'
|
import TomatoPage from './layout/grid/TomatoPage'
|
||||||
import useRouterStore from './useRouterStore'
|
import useRouterStore from './useRouterStore'
|
||||||
import BackupRecovery from './user/BackupRecovery'
|
import BackupRecovery from './user/BackupRecovery'
|
||||||
|
import { ConfigProvider } from 'ant-design-vue'
|
||||||
|
import zhCN from 'ant-design-vue/es/locale/zh_CN'
|
||||||
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()
|
||||||
|
@ -28,6 +30,7 @@ const router = useRouterStore()
|
||||||
const layout = useLayoutStore()
|
const layout = useLayoutStore()
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
<ConfigProvider :locale="zhCN">
|
||||||
<div class="fixed left-0 top-0 w-full h-screen style-root" @contextmenu.prevent>
|
<div class="fixed left-0 top-0 w-full h-screen style-root" @contextmenu.prevent>
|
||||||
<Header />
|
<Header />
|
||||||
<Background
|
<Background
|
||||||
|
@ -73,6 +76,7 @@ const layout = useLayoutStore()
|
||||||
|
|
||||||
<BackupRecovery v-if="router.path === 'global-backup'"></BackupRecovery>
|
<BackupRecovery v-if="router.path === 'global-backup'"></BackupRecovery>
|
||||||
</div>
|
</div>
|
||||||
|
</ConfigProvider>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import useRouterStore, { type RouteStr } from '@/useRouterStore'
|
import useRouterStore, { type RouteStr } from '@/useRouterStore'
|
||||||
import { computed, defineComponent, ref, Transition, watch } from 'vue'
|
import { computed, defineComponent, onMounted, onUnmounted, ref, Transition, watch } from 'vue'
|
||||||
import { OhVueIcon, addIcons } from 'oh-vue-icons'
|
import { OhVueIcon, addIcons } from 'oh-vue-icons'
|
||||||
import { MdClose, MdOpeninfull, MdClosefullscreen } from 'oh-vue-icons/icons'
|
import { MdClose, MdOpeninfull, MdClosefullscreen } from 'oh-vue-icons/icons'
|
||||||
import asyncLoader from './utils/asyncLoader'
|
import asyncLoader from './utils/asyncLoader'
|
||||||
|
@ -24,12 +24,25 @@ export default defineComponent(() => {
|
||||||
watch(router, () => {
|
watch(router, () => {
|
||||||
full.value = false
|
full.value = false
|
||||||
})
|
})
|
||||||
|
onMounted(() => {
|
||||||
|
window.addEventListener('keydown', handleKeydown)
|
||||||
|
})
|
||||||
|
onUnmounted(() => {
|
||||||
|
// 清理事件监听
|
||||||
|
window.removeEventListener('keydown', handleKeydown)
|
||||||
|
})
|
||||||
|
function handleKeydown(e: any) {
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
|
}
|
||||||
return () => (
|
return () => (
|
||||||
<div
|
<div
|
||||||
class="fixed left-0 top-0 z-50 w-full"
|
class="fixed left-0 top-0 z-50 w-full"
|
||||||
onContextmenu={(e) => e.stopPropagation()}
|
onContextmenu={(e) => e.stopPropagation()}
|
||||||
onKeydown={(e) => e.stopPropagation()}
|
onKeydown={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{/* 背景遮罩 */}
|
{/* 背景遮罩 */}
|
||||||
<Transition>
|
<Transition>
|
||||||
|
@ -93,8 +106,7 @@ export default defineComponent(() => {
|
||||||
<AdderPage />
|
<AdderPage />
|
||||||
) : router.path === 'global-background' ? (
|
) : router.path === 'global-background' ? (
|
||||||
<BackgroundSwtich />
|
<BackgroundSwtich />
|
||||||
) :
|
) : router.path.startsWith('widget-') ? (
|
||||||
router.path.startsWith('widget-') ? (
|
|
||||||
(() => {
|
(() => {
|
||||||
const name = router.path.split('-')[1]
|
const name = router.path.split('-')[1]
|
||||||
const selected = widgetList.find((el) => el.name === name)
|
const selected = widgetList.find((el) => el.name === name)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { computed, defineComponent, onUnmounted, reactive, ref } from 'vue'
|
import { computed, defineComponent, onUnmounted, reactive, ref } from 'vue'
|
||||||
import type { Block, LayoutPages } from './layout.types'
|
import type { Block } from './layout.types'
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
import useLayoutStore from './useLayoutStore'
|
import useLayoutStore from './useLayoutStore'
|
||||||
import widgetList from '@/widgets'
|
import widgetList from '@/widgets'
|
||||||
|
@ -17,10 +17,11 @@ const defaultDisplay = {
|
||||||
export const useMenuStore = defineStore('menu', () => {
|
export const useMenuStore = defineStore('menu', () => {
|
||||||
const display = reactive(defaultDisplay)
|
const display = reactive(defaultDisplay)
|
||||||
const selectPage = ref<{
|
const selectPage = ref<{
|
||||||
id: string,
|
id: string
|
||||||
label: string,
|
label: string
|
||||||
name: string,
|
name: string
|
||||||
}>()
|
}>()
|
||||||
|
const isEditPage = ref(false)
|
||||||
const showEditPage = ref(false)
|
const showEditPage = ref(false)
|
||||||
const mPos = {
|
const mPos = {
|
||||||
x: 0,
|
x: 0,
|
||||||
|
@ -49,6 +50,7 @@ export const useMenuStore = defineStore('menu', () => {
|
||||||
display,
|
display,
|
||||||
open,
|
open,
|
||||||
dismiss,
|
dismiss,
|
||||||
|
isEditPage,
|
||||||
show,
|
show,
|
||||||
selectPage,
|
selectPage,
|
||||||
showEditPage
|
showEditPage
|
||||||
|
@ -155,6 +157,15 @@ export default defineComponent(() => {
|
||||||
>
|
>
|
||||||
添加快游戏
|
添加快游戏
|
||||||
</Item>
|
</Item>
|
||||||
|
<Item
|
||||||
|
noStyle
|
||||||
|
onClick={() => {
|
||||||
|
menu.isEditPage = true
|
||||||
|
menu.dismiss()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
编辑主页
|
||||||
|
</Item>
|
||||||
<Item
|
<Item
|
||||||
noStyle
|
noStyle
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -164,6 +175,15 @@ export default defineComponent(() => {
|
||||||
>
|
>
|
||||||
更换壁纸
|
更换壁纸
|
||||||
</Item>
|
</Item>
|
||||||
|
<Item
|
||||||
|
noStyle
|
||||||
|
onClick={() => {
|
||||||
|
window.location.reload()
|
||||||
|
menu.dismiss()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
刷新
|
||||||
|
</Item>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -207,10 +227,18 @@ export default defineComponent(() => {
|
||||||
alert
|
alert
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
// 删除链接
|
// 删除链接
|
||||||
const idx = layout.currentPage.list.findIndex((el) => el.id === block.id)
|
console.log(menu.selectPage)
|
||||||
if (idx < 0) return
|
|
||||||
layout.currentPage.list.splice(idx, 1)
|
const idx = layout.state.content[layout.state.current].pages.findIndex(
|
||||||
|
(el) => el.id === menu.selectPage?.id
|
||||||
|
)
|
||||||
menu.dismiss()
|
menu.dismiss()
|
||||||
|
|
||||||
|
if (idx < 0) return
|
||||||
|
if (idx === layout.state.currentPage) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
layout.state.content[layout.state.current].pages.splice(idx, 1)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
删除
|
删除
|
||||||
|
@ -309,7 +337,25 @@ export default defineComponent(() => {
|
||||||
// 链接
|
// 链接
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Item>编辑</Item>
|
<Item
|
||||||
|
onClick={() => {
|
||||||
|
useAdderPageStore().editBlockItem = {
|
||||||
|
id: block.id,
|
||||||
|
name: block.name,
|
||||||
|
link: block.link,
|
||||||
|
icon: block.icon,
|
||||||
|
text: block.text,
|
||||||
|
background: block.background,
|
||||||
|
color: block.color,
|
||||||
|
type: block.color ? 1 : 0
|
||||||
|
}
|
||||||
|
router.go('global-adder')
|
||||||
|
useAdderPageStore().type = 2
|
||||||
|
menu.dismiss()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
编辑
|
||||||
|
</Item>
|
||||||
<Item
|
<Item
|
||||||
alert
|
alert
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
|
@ -81,10 +81,11 @@ export default defineComponent(() => {
|
||||||
const isGame = computed(() => layout.state.current === 0)
|
const isGame = computed(() => layout.state.current === 0)
|
||||||
const store = useAdderPageStore()
|
const store = useAdderPageStore()
|
||||||
const addTo = ref(layout.state.currentPage)
|
const addTo = ref(layout.state.currentPage)
|
||||||
|
|
||||||
provide(AddToToken, addTo)
|
provide(AddToToken, addTo)
|
||||||
onUnmounted(() => {
|
// onUnmounted(() => {
|
||||||
store.type = 1
|
// store.type = 1
|
||||||
})
|
// })
|
||||||
return () => (
|
return () => (
|
||||||
<div
|
<div
|
||||||
class={clsx(
|
class={clsx(
|
||||||
|
@ -144,9 +145,31 @@ export default defineComponent(() => {
|
||||||
}))}
|
}))}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
{store.type !== 2 && (
|
||||||
<Form.Item>
|
<Form.Item>
|
||||||
<Input.Search class="w-[200px]" placeholder="搜索组件或网站" />
|
<Input.Search
|
||||||
|
onSearch={(e) => {
|
||||||
|
if (store.type === 1) {
|
||||||
|
store.search(e)
|
||||||
|
} else if (store.type === 0) {
|
||||||
|
store.widgetSearchWords = e
|
||||||
|
} else if (store.type === 3) {
|
||||||
|
store.gameSearch = e
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
class="w-[220px]"
|
||||||
|
placeholder={
|
||||||
|
store.type === 0
|
||||||
|
? '搜索想要添加的组件'
|
||||||
|
: store.type === 1
|
||||||
|
? '搜索想要添加的网址导航'
|
||||||
|
: store.type === 2
|
||||||
|
? ''
|
||||||
|
: '搜索想要添加的游戏'
|
||||||
|
}
|
||||||
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
)}
|
||||||
</Form>
|
</Form>
|
||||||
<div class="w-full h-0 flex-grow p-6">
|
<div class="w-full h-0 flex-grow p-6">
|
||||||
<div class="w-full h-full relative">
|
<div class="w-full h-full relative">
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import { computed, defineComponent, inject, reactive, ref, watch } from 'vue'
|
import { computed, defineComponent, inject, onMounted, reactive, ref, watch } from 'vue'
|
||||||
import useLayoutStore from '../useLayoutStore'
|
import useLayoutStore from '../useLayoutStore'
|
||||||
import { Button, Form, Input, InputGroup } from 'ant-design-vue'
|
import { Form, Input } from 'ant-design-vue'
|
||||||
import { OhVueIcon, addIcons } from 'oh-vue-icons'
|
import { OhVueIcon, addIcons } from 'oh-vue-icons'
|
||||||
import { MdUpload, MdImage, MdCheck } from 'oh-vue-icons/icons'
|
import { MdUpload, MdImage, MdCheck } from 'oh-vue-icons/icons'
|
||||||
import useLink from '../../utils/useLink'
|
import useLink from '../../utils/useLink'
|
||||||
import { CheckOutlined } from '@ant-design/icons-vue'
|
|
||||||
import { v4 as uuid } from 'uuid'
|
import { v4 as uuid } from 'uuid'
|
||||||
import type { Block } from '../layout.types'
|
import type { Block } from '../layout.types'
|
||||||
import { ColorPicker } from 'vue3-colorpicker'
|
|
||||||
import 'vue3-colorpicker/style.css'
|
import 'vue3-colorpicker/style.css'
|
||||||
import { globalToast } from '@/main'
|
import { globalToast } from '@/main'
|
||||||
import UploadAndCut from '@/utils/UploadAndCut'
|
import UploadAndCut from '@/utils/UploadAndCut'
|
||||||
import { AddToToken } from './AdderPage'
|
import { AddToToken } from './AdderPage'
|
||||||
|
import useAdderPageStore, { type EditBlockItemType } from './useAdderPageStore'
|
||||||
|
import useRouterStore from '@/useRouterStore'
|
||||||
|
import NativeColorPicker from '@/utils/NativeColorPicker'
|
||||||
addIcons(MdUpload, MdImage, MdCheck)
|
addIcons(MdUpload, MdImage, MdCheck)
|
||||||
|
|
||||||
const TypeSelector = defineComponent({
|
const TypeSelector = defineComponent({
|
||||||
|
@ -47,6 +47,7 @@ const TypeSelector = defineComponent({
|
||||||
'update:icon': (() => true) as (val: string) => boolean
|
'update:icon': (() => true) as (val: string) => boolean
|
||||||
},
|
},
|
||||||
setup(props, ctx) {
|
setup(props, ctx) {
|
||||||
|
const layout = useLayoutStore()
|
||||||
return () => (
|
return () => (
|
||||||
<div class="flex gap-4">
|
<div class="flex gap-4">
|
||||||
<div class={'flex justify-center flex-col items-center gap-y-1'}>
|
<div class={'flex justify-center flex-col items-center gap-y-1'}>
|
||||||
|
@ -60,7 +61,7 @@ const TypeSelector = defineComponent({
|
||||||
ctx.emit('update:value', 0)
|
ctx.emit('update:value', 0)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{!props.icon && <OhVueIcon name="md-image" fill="white" scale={1.8} />}
|
{!props.icon && <img src={'/tab/icons/bgGameCloud.png'}></img>}
|
||||||
{props.value === 0 && (
|
{props.value === 0 && (
|
||||||
<div
|
<div
|
||||||
class={
|
class={
|
||||||
|
@ -113,10 +114,11 @@ const TypeSelector = defineComponent({
|
||||||
ctx.emit('update:icon', e)
|
ctx.emit('update:icon', e)
|
||||||
}}
|
}}
|
||||||
></ImageUploader> */}
|
></ImageUploader> */}
|
||||||
<UploadAndCut onUpdate:value={(e)=> {
|
<UploadAndCut
|
||||||
|
onUpdate:value={(e) => {
|
||||||
ctx.emit('update:icon', e)
|
ctx.emit('update:icon', e)
|
||||||
|
}}
|
||||||
}}></UploadAndCut>
|
></UploadAndCut>
|
||||||
</div>
|
</div>
|
||||||
<span class={'text-[12px]'}>自定义</span>
|
<span class={'text-[12px]'}>自定义</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -134,9 +136,21 @@ export default defineComponent(() => {
|
||||||
color: 'rgb(255,255,255)',
|
color: 'rgb(255,255,255)',
|
||||||
icon: '',
|
icon: '',
|
||||||
type: 0 // 0 默认,1 文字
|
type: 0 // 0 默认,1 文字
|
||||||
})
|
} as EditBlockItemType)
|
||||||
const isGame = computed(() => layout.state.current === 0)
|
const isGame = computed(() => layout.state.current === 0)
|
||||||
const debounced = ref('')
|
const debounced = ref('')
|
||||||
|
const store = useAdderPageStore()
|
||||||
|
onMounted(() => {
|
||||||
|
if (store.editBlockItem !== null) {
|
||||||
|
form.link = store.editBlockItem.link
|
||||||
|
form.name = store.editBlockItem.name
|
||||||
|
form.icon = store.editBlockItem.icon
|
||||||
|
form.text = store.editBlockItem.text
|
||||||
|
form.background = store.editBlockItem.background
|
||||||
|
form.color = store.editBlockItem.color
|
||||||
|
form.type = store.editBlockItem.type
|
||||||
|
}
|
||||||
|
})
|
||||||
watch(
|
watch(
|
||||||
() => form.link,
|
() => form.link,
|
||||||
(val, _, onCleanup) => {
|
(val, _, onCleanup) => {
|
||||||
|
@ -155,6 +169,20 @@ export default defineComponent(() => {
|
||||||
if (val.name) form.name = val.name
|
if (val.name) form.name = val.name
|
||||||
if (val.icon) form.icon = val.icon
|
if (val.icon) form.icon = val.icon
|
||||||
})
|
})
|
||||||
|
watch(
|
||||||
|
() => form.type,
|
||||||
|
(cur, pre) => {
|
||||||
|
if (cur === 1) {
|
||||||
|
if (!form.name) {
|
||||||
|
globalToast.error('文字图标请至少填写文字或者名称')
|
||||||
|
form.type = pre
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
form.text = form.name.substring(0, 2).toLocaleUpperCase()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
const addTo = inject(AddToToken)
|
const addTo = inject(AddToToken)
|
||||||
return () => (
|
return () => (
|
||||||
<div
|
<div
|
||||||
|
@ -163,19 +191,24 @@ export default defineComponent(() => {
|
||||||
(isGame.value ? 'bg-white/20' : 'bg-white/70')
|
(isGame.value ? 'bg-white/20' : 'bg-white/70')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Form labelCol={{ span: 4 }} labelAlign="left">
|
<Form>
|
||||||
<Form.Item label="地址">
|
<Form.Item label="地址" class={'relative'}>
|
||||||
<InputGroup compact style="display:flex">
|
|
||||||
<Input
|
<Input
|
||||||
v-model:value={form.link}
|
v-model:value={form.link}
|
||||||
placeholder="搜索想要添加的网址导航"
|
placeholder="搜索想要添加的网址导航"
|
||||||
class="w-0 flex-grow"
|
class={isGame?.value ? '' : ' bg-black/10 '}
|
||||||
/>
|
/>
|
||||||
<Button>获取地址</Button>
|
<span
|
||||||
</InputGroup>
|
class={'absolute right-[-70px] top-1/2 -translate-y-1/2 cursor-pointer'}
|
||||||
|
onClick={() => {
|
||||||
|
debounced.value = debounced.value + ' '
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
获取地址
|
||||||
|
</span>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="名称">
|
<Form.Item label="名称">
|
||||||
<Input v-model:value={form.name} />
|
<Input v-model:value={form.name} class={isGame?.value ? '' : ' bg-black/10 '} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="图标">
|
<Form.Item label="图标">
|
||||||
<TypeSelector
|
<TypeSelector
|
||||||
|
@ -189,51 +222,59 @@ export default defineComponent(() => {
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{form.type === 1 && (
|
{form.type === 1 && (
|
||||||
<>
|
<>
|
||||||
<div class="flex">
|
<Form.Item label="图标背景">
|
||||||
<Form.Item
|
<NativeColorPicker
|
||||||
label="文字颜色"
|
size={30}
|
||||||
class="w-0 flex-grow"
|
colorList={[
|
||||||
labelCol={{
|
'rgb(227, 127, 53)',
|
||||||
span: 8
|
'rgb(239, 195, 57)',
|
||||||
|
'rgb(65, 201, 117)',
|
||||||
|
'rgb(67, 195, 195)',
|
||||||
|
'rgb(97, 182, 255)',
|
||||||
|
'rgb(153, 91, 179)'
|
||||||
|
]}
|
||||||
|
value={form.background}
|
||||||
|
onUpdate:value={(e) => {
|
||||||
|
form.background = e
|
||||||
}}
|
}}
|
||||||
>
|
></NativeColorPicker>
|
||||||
<ColorPicker
|
|
||||||
class="shadow-lg"
|
|
||||||
format="rgb"
|
|
||||||
shape="square"
|
|
||||||
v-model:pureColor={form.color}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
|
||||||
label="图标背景"
|
|
||||||
class="w-0 flex-grow"
|
|
||||||
labelCol={{
|
|
||||||
span: 8
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ColorPicker
|
|
||||||
class="shadow-lg"
|
|
||||||
format="rgb"
|
|
||||||
shape="square"
|
|
||||||
v-model:pureColor={form.background}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
<Form.Item label="图标文字">
|
<Form.Item label="图标文字">
|
||||||
<Input v-model:value={form.text} maxlength={2} />
|
<Input
|
||||||
|
v-model:value={form.text}
|
||||||
|
maxlength={2}
|
||||||
|
class={isGame?.value ? '' : ' bg-black/10 '}
|
||||||
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<Form.Item label=" " colon={false}>
|
<Form.Item label=" " colon={false}>
|
||||||
<Button
|
<button
|
||||||
type="primary"
|
class={
|
||||||
size="large"
|
'outline-none ml-[23px] mt-2 flex items-center hover:opacity-90 text-[16px] justify-center gap-x-2 text-white w-[94px] h-[40px] rounded-lg'
|
||||||
icon={<CheckOutlined />}
|
}
|
||||||
|
style={{
|
||||||
|
background: 'linear-gradient(180deg,#ffaa4e 0%,#ff6227 100%)'
|
||||||
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (form.type === 1 && !form.text && !form.name) {
|
if (form.type === 1 && !form.text && !form.name) {
|
||||||
globalToast.error('文字图标请至少填写文字或者名称')
|
globalToast.error('文字图标请至少填写文字或者名称')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (!form.link) {
|
||||||
|
globalToast.warning('请输入网站链接')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!form.name) {
|
||||||
|
globalToast.warning('请输入网站名称')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (store.editBlockItem !== null) {
|
||||||
|
console.log(123)
|
||||||
|
layout.changeBlock(form, store.editBlockItem.id)
|
||||||
|
useRouterStore().back()
|
||||||
|
store.editBlockItem = null
|
||||||
|
} else {
|
||||||
const id = uuid()
|
const id = uuid()
|
||||||
const data: Block = {
|
const data: Block = {
|
||||||
id,
|
id,
|
||||||
|
@ -245,14 +286,17 @@ export default defineComponent(() => {
|
||||||
w: 1,
|
w: 1,
|
||||||
h: 1,
|
h: 1,
|
||||||
text:
|
text:
|
||||||
form.type === 0 ? '' : form.text || form.name.substring(0, 2).toLocaleUpperCase(),
|
form.type === 0
|
||||||
|
? ''
|
||||||
|
: form.text || form.name.substring(0, 2).toLocaleUpperCase(),
|
||||||
label: form.name
|
label: form.name
|
||||||
}
|
}
|
||||||
layout.addBlock(data, addTo?.value)
|
layout.addBlock(data, addTo?.value)
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
确定
|
确定
|
||||||
</Button>
|
</button>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { frontAddress, ossBase } from '@/config'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { generateRandomString } from '@/utils/tool'
|
import { generateRandomString } from '@/utils/tool'
|
||||||
import MD5 from 'crypto-js/md5'
|
import MD5 from 'crypto-js/md5'
|
||||||
|
import useAdderPageStore from './useAdderPageStore'
|
||||||
export const SECRET = 'A1Cv12olxT12dOE3xA1vPA=='
|
export const SECRET = 'A1Cv12olxT12dOE3xA1vPA=='
|
||||||
export const URL_ADDRESS = 'http://newfatfox.oss-cn-beijing.aliyuncs.com'
|
export const URL_ADDRESS = 'http://newfatfox.oss-cn-beijing.aliyuncs.com'
|
||||||
export interface GameType {
|
export interface GameType {
|
||||||
|
@ -159,6 +160,7 @@ export default defineComponent(() => {
|
||||||
const isGame = computed(() => layout.state.current === 0)
|
const isGame = computed(() => layout.state.current === 0)
|
||||||
const appList = ref<GameType[]>([])
|
const appList = ref<GameType[]>([])
|
||||||
const selectType = ref('fc')
|
const selectType = ref('fc')
|
||||||
|
const store = useAdderPageStore()
|
||||||
const fetchGame = async (page: number) => {
|
const fetchGame = async (page: number) => {
|
||||||
const parems = `nonce=${generateRandomString(8)}&pid=PIDc8uT24mpo×tamp=${dayjs().unix()}`
|
const parems = `nonce=${generateRandomString(8)}&pid=PIDc8uT24mpo×tamp=${dayjs().unix()}`
|
||||||
const sign = MD5(parems + SECRET).toString()
|
const sign = MD5(parems + SECRET).toString()
|
||||||
|
@ -169,11 +171,11 @@ export default defineComponent(() => {
|
||||||
return res.data.items
|
return res.data.items
|
||||||
}
|
}
|
||||||
watch(
|
watch(
|
||||||
selectType,
|
[selectType, () => store.gameSearch],
|
||||||
(val) => {
|
(val) => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
if (val !== 'yiqiyoo') {
|
if (val[0] !== 'yiqiyoo') {
|
||||||
request<GameType[]>('GET', `/api/games?type=${val}`)
|
request<GameType[]>('GET', `/api/games?type=${val[0]}&keyword=${val[1]}`)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
appList.value = res
|
appList.value = res
|
||||||
})
|
})
|
||||||
|
@ -212,6 +214,7 @@ export default defineComponent(() => {
|
||||||
)
|
)
|
||||||
return () => (
|
return () => (
|
||||||
<div class={'w-full h-full flex flex-col gap-y-4'}>
|
<div class={'w-full h-full flex flex-col gap-y-4'}>
|
||||||
|
{!store.gameSearch && (
|
||||||
<div class={'w-full '}>
|
<div class={'w-full '}>
|
||||||
<CategoryTab
|
<CategoryTab
|
||||||
list={DefautGameTypeList}
|
list={DefautGameTypeList}
|
||||||
|
@ -247,6 +250,8 @@ export default defineComponent(() => {
|
||||||
}}
|
}}
|
||||||
></CategoryTab>
|
></CategoryTab>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div class={'h-0 flex-1 w-full'}>
|
<div class={'h-0 flex-1 w-full'}>
|
||||||
<div class={'w-full h-full overflow-y-scroll scrollbar-hide'}>
|
<div class={'w-full h-full overflow-y-scroll scrollbar-hide'}>
|
||||||
{!loading.value ? (
|
{!loading.value ? (
|
||||||
|
|
|
@ -1,26 +1,11 @@
|
||||||
import CategoryTab from '@/utils/CategoryTab'
|
import CategoryTab from '@/utils/CategoryTab'
|
||||||
import request from '@/utils/request'
|
import { computed, defineComponent, inject } from 'vue'
|
||||||
import { computed, defineComponent, inject, onMounted, ref, watch } from 'vue'
|
|
||||||
import type { BackgroundType } from '../background/BackgroundSwtich'
|
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
import useLayoutStore from '../useLayoutStore'
|
import useLayoutStore from '../useLayoutStore'
|
||||||
import { AddToToken } from './AdderPage'
|
import { AddToToken } from './AdderPage'
|
||||||
import { v4 as uuid } from 'uuid'
|
import { v4 as uuid } from 'uuid'
|
||||||
|
import useAdderPageStore, { type HotAppType } from './useAdderPageStore'
|
||||||
|
|
||||||
interface HotAppCategoryType {
|
|
||||||
id: string
|
|
||||||
name: string
|
|
||||||
ordinal: number
|
|
||||||
}
|
|
||||||
interface HotAppType {
|
|
||||||
id: string
|
|
||||||
name: string
|
|
||||||
url: string
|
|
||||||
ordinal: number
|
|
||||||
desc: string
|
|
||||||
icon: string
|
|
||||||
background: string
|
|
||||||
}
|
|
||||||
export const LinkItem = defineComponent({
|
export const LinkItem = defineComponent({
|
||||||
props: {
|
props: {
|
||||||
content: {
|
content: {
|
||||||
|
@ -34,10 +19,13 @@ export const LinkItem = defineComponent({
|
||||||
const addTo = inject(AddToToken)
|
const addTo = inject(AddToToken)
|
||||||
return () => (
|
return () => (
|
||||||
<div
|
<div
|
||||||
class={clsx(' w-full h-full rounded-lg relative flex flex-col justify-between overflow-hidden shadow p-4', {
|
class={clsx(
|
||||||
|
' w-full h-full rounded-lg relative flex flex-col justify-between overflow-hidden shadow p-4',
|
||||||
|
{
|
||||||
'bg-white/20': isGame.value,
|
'bg-white/20': isGame.value,
|
||||||
'bg-white/80': !isGame.value
|
'bg-white/80': !isGame.value
|
||||||
})}
|
}
|
||||||
|
)}
|
||||||
key={props.content.name}
|
key={props.content.name}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
@ -110,6 +98,9 @@ export const LinkItem = defineComponent({
|
||||||
},
|
},
|
||||||
addTo?.value
|
addTo?.value
|
||||||
)
|
)
|
||||||
|
if (addTo?.value) {
|
||||||
|
layout.state.currentPage = addTo?.value
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
添加
|
添加
|
||||||
|
@ -122,44 +113,19 @@ export const LinkItem = defineComponent({
|
||||||
|
|
||||||
export default defineComponent(() => {
|
export default defineComponent(() => {
|
||||||
const layout = useLayoutStore()
|
const layout = useLayoutStore()
|
||||||
const loading = ref(false)
|
|
||||||
const isGame = computed(() => layout.state.current === 0)
|
const isGame = computed(() => layout.state.current === 0)
|
||||||
const appList = ref<HotAppType[]>([])
|
|
||||||
const categoryList = ref<BackgroundType[]>([])
|
|
||||||
const selectType = ref('')
|
|
||||||
onMounted(() => {
|
|
||||||
request<HotAppCategoryType[]>('GET', '/api/app/hotAppTypes').then((res) => {
|
|
||||||
categoryList.value = res.map((el) => ({
|
|
||||||
id: el.id,
|
|
||||||
oridinal: el.ordinal,
|
|
||||||
type: el.name,
|
|
||||||
attr: 0
|
|
||||||
}))
|
|
||||||
|
|
||||||
selectType.value = res[0].id
|
const store = useAdderPageStore()
|
||||||
})
|
|
||||||
})
|
|
||||||
watch(selectType, (val) => {
|
|
||||||
loading.value = true
|
|
||||||
|
|
||||||
request<HotAppType[]>('GET', `/api/app/hotApps?hotAppsId=${val}`)
|
|
||||||
.then((res) => {
|
|
||||||
appList.value = res
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
setTimeout(() => {
|
|
||||||
loading.value = false
|
|
||||||
}, 200)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
return () => (
|
return () => (
|
||||||
<div class={'w-full h-full flex flex-col gap-y-4'}>
|
<div class={'w-full h-full flex flex-col gap-y-4'}>
|
||||||
|
{!store.isSearch && (
|
||||||
<div class={'w-full '}>
|
<div class={'w-full '}>
|
||||||
<CategoryTab
|
<CategoryTab
|
||||||
list={categoryList.value}
|
list={store.categoryList}
|
||||||
selectType={selectType.value}
|
selectType={store.selectType}
|
||||||
onUpdate:type={(e) => {
|
onUpdate:type={(e) => {
|
||||||
selectType.value = e
|
store.selectType = e
|
||||||
}}
|
}}
|
||||||
v-slots={{
|
v-slots={{
|
||||||
select: (text: string) => (
|
select: (text: string) => (
|
||||||
|
@ -189,11 +155,13 @@ export default defineComponent(() => {
|
||||||
}}
|
}}
|
||||||
></CategoryTab>
|
></CategoryTab>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div class={'h-0 flex-1 w-full'}>
|
<div class={'h-0 flex-1 w-full'}>
|
||||||
<div class={'w-full h-full overflow-y-scroll scrollbar-hide'}>
|
<div class={'w-full h-full overflow-y-scroll scrollbar-hide'}>
|
||||||
{!loading.value ? (
|
{!store.loading ? (
|
||||||
<div class={'w-full grid grid-cols-3 gap-4 '} style="grid-auto-rows: 120px">
|
<div class={'w-full grid grid-cols-3 gap-4 '} style="grid-auto-rows: 120px">
|
||||||
{appList.value.map((el) => (
|
{store.appList.map((el) => (
|
||||||
<LinkItem content={el}></LinkItem>
|
<LinkItem content={el}></LinkItem>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,6 +4,7 @@ import widgetList, { type Widget } from '@/widgets'
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
import { AddToToken } from './AdderPage'
|
import { AddToToken } from './AdderPage'
|
||||||
import { v4 as uuid } from 'uuid'
|
import { v4 as uuid } from 'uuid'
|
||||||
|
import useAdderPageStore from './useAdderPageStore'
|
||||||
|
|
||||||
export const WidgetItem = defineComponent({
|
export const WidgetItem = defineComponent({
|
||||||
props: {
|
props: {
|
||||||
|
@ -32,10 +33,7 @@ export const WidgetItem = defineComponent({
|
||||||
key={props.content.name}
|
key={props.content.name}
|
||||||
>
|
>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<img
|
<img src={props.content.icon} class="w-[58px] h-[58px] bg-cover rounded-lg shadow-lg" />
|
||||||
src={props.content.icon}
|
|
||||||
class="w-[58px] h-[58px] bg-cover rounded-lg shadow-lg"
|
|
||||||
/>
|
|
||||||
<div class="px-2 w-0 flex-grow ">
|
<div class="px-2 w-0 flex-grow ">
|
||||||
<div
|
<div
|
||||||
class={clsx('text text-sm mb-[2px]', {
|
class={clsx('text text-sm mb-[2px]', {
|
||||||
|
@ -120,18 +118,18 @@ export const WidgetItem = defineComponent({
|
||||||
|
|
||||||
export default defineComponent(() => {
|
export default defineComponent(() => {
|
||||||
const layout = useLayoutStore()
|
const layout = useLayoutStore()
|
||||||
|
const store = useAdderPageStore()
|
||||||
return () => (
|
return () => (
|
||||||
<div class="absolute left-0 top-0 w-full h-full overflow-y-auto scrollbar-hide gap-4">
|
<div class="absolute left-0 top-0 w-full h-full overflow-y-auto scrollbar-hide gap-4">
|
||||||
<div class="w-full grid grid-cols-3 grid-flow-row-dense gap-4" style="grid-auto-rows: 120px">
|
<div class="w-full grid grid-cols-3 grid-flow-row-dense gap-4" style="grid-auto-rows: 120px">
|
||||||
{
|
{layout.state.current !== 1
|
||||||
layout.state.current !== 1 ?
|
? widgetList
|
||||||
widgetList.filter(val => val.name !== 'tomato_work').map((el) => (
|
.filter((val) => val.name !== 'tomato_work')
|
||||||
<WidgetItem content={el} key={el.name} />
|
.filter((val) => val.label.includes(store.widgetSearchWords))
|
||||||
)) :
|
.map((el) => <WidgetItem content={el} key={el.name} />)
|
||||||
widgetList.map((el) => (
|
: widgetList
|
||||||
<WidgetItem content={el} key={el.name} />
|
.filter((val) => val.label.includes(store.widgetSearchWords))
|
||||||
))
|
.map((el) => <WidgetItem content={el} key={el.name} />)}
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,9 +1,95 @@
|
||||||
import { defineStore } from "pinia";
|
import request from '@/utils/request'
|
||||||
import { ref } from "vue";
|
import { defineStore } from 'pinia'
|
||||||
|
import { watch } from 'vue'
|
||||||
export default defineStore("adderPage", () => {
|
import { ref } from 'vue'
|
||||||
|
import type { BackgroundType } from '../background/BackgroundSwtich'
|
||||||
|
export interface HotAppType {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
url: string
|
||||||
|
ordinal: number
|
||||||
|
desc: string
|
||||||
|
icon: string
|
||||||
|
background: string
|
||||||
|
}
|
||||||
|
export interface HotAppCategoryType {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
ordinal: number
|
||||||
|
}
|
||||||
|
export type EditBlockItemType = {
|
||||||
|
id: string
|
||||||
|
link: string
|
||||||
|
name: string
|
||||||
|
text: string
|
||||||
|
background: string
|
||||||
|
color: string
|
||||||
|
icon: string
|
||||||
|
type: number // 0 默认,1 文字
|
||||||
|
}
|
||||||
|
export default defineStore('adderPage', () => {
|
||||||
const type = ref(1)
|
const type = ref(1)
|
||||||
|
const selectType = ref('')
|
||||||
|
const loading = ref(false)
|
||||||
|
const appList = ref<HotAppType[]>([])
|
||||||
|
const categoryList = ref<BackgroundType[]>([])
|
||||||
|
const isSearch = ref(false)
|
||||||
|
const widgetSearchWords = ref('')
|
||||||
|
const gameSearch = ref('')
|
||||||
|
const editBlockItem = ref<EditBlockItemType | null >(null)
|
||||||
|
request<HotAppCategoryType[]>('GET', '/api/app/hotAppTypes').then((res) => {
|
||||||
|
categoryList.value = res.map((el) => ({
|
||||||
|
id: el.id,
|
||||||
|
oridinal: el.ordinal,
|
||||||
|
type: el.name,
|
||||||
|
attr: 0
|
||||||
|
}))
|
||||||
|
|
||||||
|
selectType.value = res[0].id
|
||||||
|
})
|
||||||
|
watch(selectType, (val) => {
|
||||||
|
getApps(val)
|
||||||
|
})
|
||||||
|
const getApps = (_selectType: string) => {
|
||||||
|
loading.value = true
|
||||||
|
request<HotAppType[]>('GET', `/api/app/hotApps?hotAppsId=${_selectType}`)
|
||||||
|
.then((res) => {
|
||||||
|
appList.value = res
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
loading.value = false
|
||||||
|
}, 200)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const search = (keywords: string) => {
|
||||||
|
if (keywords === '') {
|
||||||
|
isSearch.value = false
|
||||||
|
getApps(selectType.value)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
isSearch.value = true
|
||||||
|
request<HotAppType[]>('GET', `/api/app/hotApp/search?keyword=${keywords}`)
|
||||||
|
.then((res) => {
|
||||||
|
appList.value = res
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
loading.value = false
|
||||||
|
}, 200)
|
||||||
|
})
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
type
|
type,
|
||||||
|
widgetSearchWords,
|
||||||
|
categoryList,
|
||||||
|
appList,
|
||||||
|
loading,
|
||||||
|
selectType,
|
||||||
|
search,
|
||||||
|
isSearch,
|
||||||
|
gameSearch,
|
||||||
|
editBlockItem
|
||||||
}
|
}
|
||||||
})
|
})
|
|
@ -1,4 +1,4 @@
|
||||||
import { Button, Select, Slider } from 'ant-design-vue'
|
import { Button, Slider } from 'ant-design-vue'
|
||||||
import { defineComponent, ref, Transition, watch } from 'vue'
|
import { defineComponent, ref, Transition, watch } from 'vue'
|
||||||
import useLayoutStore from '../useLayoutStore'
|
import useLayoutStore from '../useLayoutStore'
|
||||||
import { DownloadOutlined, EyeInvisibleOutlined, SwapOutlined } from '@ant-design/icons-vue'
|
import { DownloadOutlined, EyeInvisibleOutlined, SwapOutlined } from '@ant-design/icons-vue'
|
||||||
|
@ -23,7 +23,7 @@ export default defineComponent(() => {
|
||||||
const settings = useSettingsStore()
|
const settings = useSettingsStore()
|
||||||
return () => (
|
return () => (
|
||||||
<div class="absolute left-0 top-0 w-full h-full p-4 overflow-y-auto scrollbar-hide">
|
<div class="absolute left-0 top-0 w-full h-full p-4 overflow-y-auto scrollbar-hide">
|
||||||
<SettingItem
|
{/* <SettingItem
|
||||||
noBg
|
noBg
|
||||||
v-slots={{
|
v-slots={{
|
||||||
label: () => <div>所属模式</div>
|
label: () => <div>所属模式</div>
|
||||||
|
@ -38,7 +38,7 @@ export default defineComponent(() => {
|
||||||
]}
|
]}
|
||||||
v-model:value={selected.value}
|
v-model:value={selected.value}
|
||||||
/>
|
/>
|
||||||
</SettingItem>
|
</SettingItem> */}
|
||||||
<div class="px-4">
|
<div class="px-4">
|
||||||
<div class="h-[180px]">
|
<div class="h-[180px]">
|
||||||
{layout.background.video && layout.background.type !== 'own' ? (
|
{layout.background.video && layout.background.type !== 'own' ? (
|
||||||
|
|
|
@ -154,7 +154,6 @@ export default defineComponent(() => {
|
||||||
fill={isGame.value ? 'white' : 'black'}
|
fill={isGame.value ? 'white' : 'black'}
|
||||||
name={BiChevronDown.name}
|
name={BiChevronDown.name}
|
||||||
class="group pointer-events-none absolute top-1/2 right-2.5 -translate-y-1/2 size-4 "
|
class="group pointer-events-none absolute top-1/2 right-2.5 -translate-y-1/2 size-4 "
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -33,11 +33,7 @@ export default defineComponent(() => {
|
||||||
<div
|
<div
|
||||||
class={clsx(
|
class={clsx(
|
||||||
'fixed bottom-4 left-1/2 duration-150 -translate-x-1/2 p-4 rounded-lg bg-white/60 backdrop-blur flex gap-4 shadow-lg',
|
'fixed bottom-4 left-1/2 duration-150 -translate-x-1/2 p-4 rounded-lg bg-white/60 backdrop-blur flex gap-4 shadow-lg',
|
||||||
setting.state.showDock === 'auto'
|
setting.state.showDock === 'auto' ? show.value ? 'bottom-4' : 'bottom-[-90px]' : 'bottom-4'
|
||||||
? show.value
|
|
||||||
? 'bottom-4'
|
|
||||||
: '-bottom-[90px]'
|
|
||||||
: 'bottom-4'
|
|
||||||
)}
|
)}
|
||||||
ref={container}
|
ref={container}
|
||||||
onMouseleave={() => {
|
onMouseleave={() => {
|
||||||
|
|
|
@ -7,6 +7,9 @@ import LinkBlock from './LinkBlock'
|
||||||
import DirBlock from './DirBlock'
|
import DirBlock from './DirBlock'
|
||||||
import WidgetBlock from './WidgetBlock'
|
import WidgetBlock from './WidgetBlock'
|
||||||
import useSettingsStore from '@/settings/useSettingsStore'
|
import useSettingsStore from '@/settings/useSettingsStore'
|
||||||
|
import { useMenuStore } from '../GlobalMenu'
|
||||||
|
import { block } from '@milkdown/kit/plugin/block'
|
||||||
|
import clsx from 'clsx'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
|
@ -22,11 +25,15 @@ export default defineComponent({
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const settings = useSettingsStore()
|
const settings = useSettingsStore()
|
||||||
const layout = useLayoutStore()
|
const layout = useLayoutStore()
|
||||||
|
const menu = useMenuStore()
|
||||||
let it: any = 0
|
let it: any = 0
|
||||||
const hover = ref(false)
|
const hover = ref(false)
|
||||||
return () => (
|
return () => (
|
||||||
<div
|
<div
|
||||||
class="w-full h-full p-[var(--block-padding)] relative rounded-lg"
|
class={clsx(
|
||||||
|
'w-full h-full p-[var(--block-padding)] relative rounded-lg ',
|
||||||
|
menu.isEditPage && 'animate-wiggle'
|
||||||
|
)}
|
||||||
key={props.block.id}
|
key={props.block.id}
|
||||||
id={props.block.id}
|
id={props.block.id}
|
||||||
style={{
|
style={{
|
||||||
|
@ -115,10 +122,38 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{menu.isEditPage && (
|
||||||
|
<div
|
||||||
|
v-outside-click={() => {
|
||||||
|
menu.isEditPage = false
|
||||||
|
}}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
const idx = layout.state.content[layout.state.current].pages[
|
||||||
|
layout.state.currentPage
|
||||||
|
].list.findIndex((val) => val.id === props.block.id)
|
||||||
|
|
||||||
|
if (idx < 0) return
|
||||||
|
|
||||||
|
layout.state.content[layout.state.current].pages[
|
||||||
|
layout.state.currentPage
|
||||||
|
].list.splice(idx, 1)
|
||||||
|
}}
|
||||||
|
class={
|
||||||
|
'rounded-full cursor-pointer backdrop-blur-md absolute w-[20px] h-[20px] top-[8px] right-[12px] z-10 '
|
||||||
|
}
|
||||||
|
style={{
|
||||||
|
backgroundImage: `url('/tab/bg/del_icon_img.png')`,
|
||||||
|
backgroundSize: 'cover'
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="w-full h-full overflow-hidden relative cursor-pointer shadow-lg hover-move "
|
class="w-full h-full overflow-hidden relative cursor-pointer shadow-lg hover-move "
|
||||||
style={{
|
style={{
|
||||||
borderRadius: `calc(var(--block-radius) * var(--block-size))`
|
borderRadius: `calc(var(--block-radius) * var(--block-size))`,
|
||||||
|
transition: 'transform 0.2s'
|
||||||
}}
|
}}
|
||||||
onContextmenu={(e) => {
|
onContextmenu={(e) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
|
|
@ -31,7 +31,7 @@ export default defineComponent({
|
||||||
jump(props.block.link)
|
jump(props.block.link)
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: props.block.background || 'white',
|
backgroundColor: props.block.text ? props.block.background || 'white' : 'transparent',
|
||||||
color: props.block.color || 'black',
|
color: props.block.color || 'black',
|
||||||
backgroundImage: props.block.icon ? `url('${props.block.icon}')` : '',
|
backgroundImage: props.block.icon ? `url('${props.block.icon}')` : '',
|
||||||
fontSize: props.dock ? '16px' : props.brief ? '12px' : 'calc(var(--block-size) / 5)'
|
fontSize: props.dock ? '16px' : props.brief ? '12px' : 'calc(var(--block-size) / 5)'
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
import SettingItem from '@/settings/SettingItem'
|
import SettingItem from '@/settings/SettingItem'
|
||||||
import useSettingsStore from '@/settings/useSettingsStore'
|
import { Button } from 'ant-design-vue'
|
||||||
import { Button, Switch } from 'ant-design-vue'
|
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
import { defineComponent } from 'vue'
|
import { computed, defineComponent, ref } from 'vue'
|
||||||
|
import useLayoutStore from '../useLayoutStore'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
setup() {
|
setup() {
|
||||||
const settings = useSettingsStore()
|
const open = ref(false)
|
||||||
|
const layout = useLayoutStore()
|
||||||
|
const isGame = computed(() => {
|
||||||
|
return layout.state.current === 0
|
||||||
|
})
|
||||||
return () => (
|
return () => (
|
||||||
<div class="p-4 flex flex-col ">
|
<div class="p-4 flex flex-col ">
|
||||||
<SettingItem
|
<SettingItem
|
||||||
|
@ -14,9 +18,45 @@ export default defineComponent({
|
||||||
label: () => <div >重置</div>
|
label: () => <div >重置</div>
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button type="primary">立即重置</Button>
|
<Button type="primary" onClick={() => {
|
||||||
|
open.value = true
|
||||||
|
}}>立即重置</Button>
|
||||||
</SettingItem>
|
</SettingItem>
|
||||||
<p class={'text-[#666] text-[12px]'}>将会把您的历史调整清空,恢复成最初的样式</p>
|
<p class={'text-[#666] text-[12px]'}>将会把您的历史调整清空,恢复成最初的样式</p>
|
||||||
|
{
|
||||||
|
open.value &&
|
||||||
|
<div class={"w-[300px] h-[210px] absolute rounded-2xl right-[-310px] z-10 bg-[#2c2e3e]"} style={
|
||||||
|
isGame.value ?
|
||||||
|
{
|
||||||
|
backgroundImage: `url('/tab/bg/addBorder.png')`,
|
||||||
|
backgroundSize: '100% 100%',
|
||||||
|
backgroundColor: '#2c2e3e'
|
||||||
|
} : {}}>
|
||||||
|
|
||||||
|
<div class={"flex flex-col w-full h-full p-7 border-b-[1px] items-center justify-between"}>
|
||||||
|
<span class={isGame.value ? "" : ""}>恢复提醒</span>
|
||||||
|
<div class={clsx("w-full h-[1px]", isGame.value ? " bg-white/20" : "bg-black/20")}></div>
|
||||||
|
<span class={clsx("text-[14px] leading-[20px] mb-2 text-center", isGame.value ? "text-[#fff9]" : "")}>此操作会将您的历史调整的数据清空,为防止您的误操作,请再次确认是否要进行重置</span>
|
||||||
|
<div class={"flex justify-between w-full"}>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
layout.resetAll()
|
||||||
|
|
||||||
|
open.value = false
|
||||||
|
}}
|
||||||
|
class={clsx("w-[118px] rounded-lg py-1 flex justify-center", isGame.value ? "bg-white/20" : "")}>重置</button>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
open.value = false
|
||||||
|
|
||||||
|
}}
|
||||||
|
class={clsx("w-[118px] rounded-lg py-1 flex justify-center", isGame.value ? "bg-[#ff7372]" : "")}>取消</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
</div >
|
</div >
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { computed, defineComponent, ref, toRaw } from 'vue'
|
import { computed, defineComponent, ref, toRaw, watch } from 'vue'
|
||||||
import useLayoutStore from '../useLayoutStore'
|
import useLayoutStore from '../useLayoutStore'
|
||||||
import { OhVueIcon, addIcons } from 'oh-vue-icons'
|
import { OhVueIcon, addIcons } from 'oh-vue-icons'
|
||||||
import { MdAdd } from 'oh-vue-icons/icons'
|
import { MdAdd } from 'oh-vue-icons/icons'
|
||||||
|
@ -15,11 +15,21 @@ export default defineComponent(() => {
|
||||||
const layout = useLayoutStore()
|
const layout = useLayoutStore()
|
||||||
const settings = useSettingsStore()
|
const settings = useSettingsStore()
|
||||||
const router = useRouterStore()
|
const router = useRouterStore()
|
||||||
|
const scrollRef = ref<any>()
|
||||||
const container = useSortable(
|
const container = useSortable(
|
||||||
computed(() => layout.currentPage.list),
|
computed(() => layout.currentPage.list),
|
||||||
ref('page')
|
ref('page')
|
||||||
)
|
)
|
||||||
|
watch(
|
||||||
|
() => layout.currentPage.list.length,
|
||||||
|
(cur, old) => {
|
||||||
|
if (cur > old) {
|
||||||
|
if (scrollRef.value) {
|
||||||
|
scrollRef.value.scrollTop = scrollRef.value.scrollHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
listenParent('openSetting', (d) => {
|
listenParent('openSetting', (d) => {
|
||||||
if (d === 'profile') {
|
if (d === 'profile') {
|
||||||
router.go('settings-user')
|
router.go('settings-user')
|
||||||
|
@ -30,6 +40,7 @@ export default defineComponent(() => {
|
||||||
})
|
})
|
||||||
return () => (
|
return () => (
|
||||||
<div
|
<div
|
||||||
|
ref={scrollRef}
|
||||||
class="absolute left-0 top-0 w-full h-screen overflow-y-auto no-scrollbar pt-[240px] px-[calc((100%_-_var(--main-width))_/_2)]"
|
class="absolute left-0 top-0 w-full h-screen overflow-y-auto no-scrollbar pt-[240px] px-[calc((100%_-_var(--main-width))_/_2)]"
|
||||||
onScroll={(e) => {
|
onScroll={(e) => {
|
||||||
const h = (e.target as any).scrollTop
|
const h = (e.target as any).scrollTop
|
||||||
|
|
|
@ -5,6 +5,8 @@ import { EditOutlined, DeleteOutlined, PlusOutlined } from '@ant-design/icons-vu
|
||||||
import asyncLoader from '@/utils/asyncLoader'
|
import asyncLoader from '@/utils/asyncLoader'
|
||||||
import ThemeProvider from '@/utils/ThemeProvider'
|
import ThemeProvider from '@/utils/ThemeProvider'
|
||||||
import { globalToast } from '@/main'
|
import { globalToast } from '@/main'
|
||||||
|
import useUserStore from '@/user/useUserStore'
|
||||||
|
import useRouterStore from '@/useRouterStore'
|
||||||
const SearchAdder = asyncLoader(() => import('./SearchAdder'))
|
const SearchAdder = asyncLoader(() => import('./SearchAdder'))
|
||||||
const SearchItem = defineComponent({
|
const SearchItem = defineComponent({
|
||||||
props: {
|
props: {
|
||||||
|
@ -157,7 +159,12 @@ export default defineComponent(() => {
|
||||||
block
|
block
|
||||||
icon={<PlusOutlined />}
|
icon={<PlusOutlined />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
if (useUserStore().isLogin) {
|
||||||
showAdder.value = null
|
showAdder.value = null
|
||||||
|
} else {
|
||||||
|
globalToast.warning('请先登录')
|
||||||
|
useRouterStore().go('global-login')
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
添加自定义搜索引擎
|
添加自定义搜索引擎
|
||||||
|
|
|
@ -31,10 +31,11 @@ export default defineComponent(
|
||||||
<div
|
<div
|
||||||
class={clsx(
|
class={clsx(
|
||||||
'w-full h-11 shadow-content overflow-hidden 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 hover:bg-white',
|
||||||
props.isMini ? '' : 'max-w-[90vw] w-full'
|
props.isMini ? '' : 'max-w-[90vw] w-full'
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
|
opacity: search.focus ? 1 : settings.state.searchOpacity,
|
||||||
borderRadius: settings.state.searchRadius + 'px'
|
borderRadius: settings.state.searchRadius + 'px'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -58,7 +59,7 @@ export default defineComponent(
|
||||||
onContextmenu={(e) => e.stopPropagation()}
|
onContextmenu={(e) => e.stopPropagation()}
|
||||||
onKeydown={(e) => e.stopPropagation()}
|
onKeydown={(e) => e.stopPropagation()}
|
||||||
class="flex-1 h-full outline-none bg-transparent placeholder:text-slate-600 placeholder:tracking-widest text-slate-800 pr-4"
|
class="flex-1 h-full outline-none bg-transparent placeholder:text-slate-600 placeholder:tracking-widest text-slate-800 pr-4"
|
||||||
placeholder={`输入搜索 ${searchConfig.current.name}`}
|
placeholder={`请输入搜索内容`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Transition name="searchContent">{search.showSearchConfig && <SearchConfig />}</Transition>
|
<Transition name="searchContent">{search.showSearchConfig && <SearchConfig />}</Transition>
|
||||||
|
|
|
@ -42,11 +42,12 @@ const Item = defineComponent({
|
||||||
return () => (
|
return () => (
|
||||||
<div
|
<div
|
||||||
onContextmenu={(e) => {
|
onContextmenu={(e) => {
|
||||||
|
if (!props.id) return
|
||||||
useMenuStore().open('page')
|
useMenuStore().open('page')
|
||||||
useMenuStore().selectPage = {
|
useMenuStore().selectPage = {
|
||||||
id: props.id,
|
id: props.id,
|
||||||
label: props.label,
|
label: props.label,
|
||||||
name: props.name,
|
name: props.name
|
||||||
}
|
}
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
@ -106,6 +107,10 @@ export default defineComponent(() => {
|
||||||
<Transition>
|
<Transition>
|
||||||
{layout.ready && (
|
{layout.ready && (
|
||||||
<div
|
<div
|
||||||
|
onContextmenu={(e)=> {
|
||||||
|
e.stopPropagation()
|
||||||
|
e.preventDefault()
|
||||||
|
}}
|
||||||
class={clsx(
|
class={clsx(
|
||||||
'w-[130px] min-h-[620px] hover:bg-red-10 z-20 fixed top-1/2 -translate-y-1/2 bottom-0 ',
|
'w-[130px] min-h-[620px] hover:bg-red-10 z-20 fixed top-1/2 -translate-y-1/2 bottom-0 ',
|
||||||
settings.state.siderDirection === 'left' ? 'left-0' : 'right-0'
|
settings.state.siderDirection === 'left' ? 'left-0' : 'right-0'
|
||||||
|
@ -194,6 +199,10 @@ export default defineComponent(() => {
|
||||||
{/* 添加页面 */}
|
{/* 添加页面 */}
|
||||||
{menu.showEditPage && (
|
{menu.showEditPage && (
|
||||||
<div
|
<div
|
||||||
|
onContextmenu={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
e.preventDefault()
|
||||||
|
}}
|
||||||
class={clsx(
|
class={clsx(
|
||||||
'absolute bottom-0 w-56 rounded-lg p-4 bg-white/40 backdrop-blur shadow-lg',
|
'absolute bottom-0 w-56 rounded-lg p-4 bg-white/40 backdrop-blur shadow-lg',
|
||||||
settings.state.siderDirection === 'left' ? 'left-[70px]' : 'right-[70px]'
|
settings.state.siderDirection === 'left' ? 'left-[70px]' : 'right-[70px]'
|
||||||
|
@ -230,7 +239,16 @@ export default defineComponent(() => {
|
||||||
if (menu.selectPage) {
|
if (menu.selectPage) {
|
||||||
menu.selectPage.name = selected.value.name
|
menu.selectPage.name = selected.value.name
|
||||||
menu.selectPage.label = label.value
|
menu.selectPage.label = label.value
|
||||||
|
if (!menu.selectPage?.id) return
|
||||||
|
const idx = layout.state.content[layout.state.current].pages.findIndex(
|
||||||
|
(val) => val.id === menu.selectPage?.id
|
||||||
|
)
|
||||||
|
if (idx !== -1) {
|
||||||
|
layout.state.content[layout.state.current].pages[idx].label = label.value
|
||||||
|
layout.state.content[layout.state.current].pages[idx].name =
|
||||||
|
selected.value.name
|
||||||
|
}
|
||||||
|
menu.selectPage = undefined
|
||||||
} else {
|
} else {
|
||||||
layout.currentMode.pages.push({
|
layout.currentMode.pages.push({
|
||||||
list: [],
|
list: [],
|
||||||
|
@ -241,11 +259,10 @@ export default defineComponent(() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.showEditPage = false
|
menu.showEditPage = false
|
||||||
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<OhVueIcon name="px-check" />
|
<OhVueIcon name="px-check" />
|
||||||
{menu.selectPage ? "修改页面" : "添加页面"}
|
{menu.selectPage ? '修改页面' : '添加页面'}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import jump from '@/utils/jump'
|
||||||
import useSettingsStore from '@/settings/useSettingsStore'
|
import useSettingsStore from '@/settings/useSettingsStore'
|
||||||
import useUserStore from '@/user/useUserStore'
|
import useUserStore from '@/user/useUserStore'
|
||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
import type { EditBlockItemType } from './adder/useAdderPageStore'
|
||||||
|
|
||||||
const defaultLayout: Layout = {
|
const defaultLayout: Layout = {
|
||||||
content: [
|
content: [
|
||||||
|
@ -26,7 +27,7 @@ const defaultLayout: Layout = {
|
||||||
export default defineStore('layout', () => {
|
export default defineStore('layout', () => {
|
||||||
const settings = useSettingsStore()
|
const settings = useSettingsStore()
|
||||||
const user = useUserStore()
|
const user = useUserStore()
|
||||||
const state = reactive(defaultLayout)
|
const state = reactive({ ...defaultLayout })
|
||||||
const ready = ref(false)
|
const ready = ref(false)
|
||||||
|
|
||||||
db.getItem<Layout>('layout').then((res) => {
|
db.getItem<Layout>('layout').then((res) => {
|
||||||
|
@ -78,6 +79,21 @@ export default defineStore('layout', () => {
|
||||||
pageList.push(block)
|
pageList.push(block)
|
||||||
globalToast.success('添加成功')
|
globalToast.success('添加成功')
|
||||||
}
|
}
|
||||||
|
const changeBlock = (item: EditBlockItemType, target: string) => {
|
||||||
|
const idx = currentPage.value.list.findIndex((el) => el.id === target)
|
||||||
|
if (idx < 0) return
|
||||||
|
currentPage.value.list.splice(idx, 1, {
|
||||||
|
...currentPage.value.list[idx],
|
||||||
|
label: item.name,
|
||||||
|
color: item.color,
|
||||||
|
text: item.text,
|
||||||
|
link: item.link,
|
||||||
|
background: item.background,
|
||||||
|
icon: item.type === 0 ? item.icon : '',
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
const openDir = ref('')
|
const openDir = ref('')
|
||||||
// 文件夹只有一个时,将当前界面的文件夹替换为图标
|
// 文件夹只有一个时,将当前界面的文件夹替换为图标
|
||||||
const checkDir = (id: string) => {
|
const checkDir = (id: string) => {
|
||||||
|
@ -112,7 +128,17 @@ export default defineStore('layout', () => {
|
||||||
}
|
}
|
||||||
return block.label || ''
|
return block.label || ''
|
||||||
}
|
}
|
||||||
|
const resetAll = () => {
|
||||||
|
request('GET', '/api/app/desktop').then((res: any) => {
|
||||||
|
if (!res) return
|
||||||
|
state.dir = res.dir
|
||||||
|
state.content = res.content
|
||||||
|
|
||||||
|
}).catch(() => {
|
||||||
|
Object.assign(state, defaultLayout)
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
const changeBackground = (url: string) => {
|
const changeBackground = (url: string) => {
|
||||||
state.content[state.current].background = url
|
state.content[state.current].background = url
|
||||||
}
|
}
|
||||||
|
@ -161,6 +187,8 @@ export default defineStore('layout', () => {
|
||||||
openDir,
|
openDir,
|
||||||
checkDir,
|
checkDir,
|
||||||
getLabel,
|
getLabel,
|
||||||
changeBackground
|
changeBackground,
|
||||||
|
resetAll,
|
||||||
|
changeBlock
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -2,18 +2,17 @@ import './main.css'
|
||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
import { createPinia } from 'pinia'
|
import { createPinia } from 'pinia'
|
||||||
import persist from 'pinia-plugin-persistedstate'
|
import persist from 'pinia-plugin-persistedstate'
|
||||||
|
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import getFp from './utils/getFp'
|
import getFp from './utils/getFp'
|
||||||
import vOutsideClick from './utils/vOutsideClick'
|
import vOutsideClick from './utils/vOutsideClick'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
|
import Toast, { useToast } from 'vue-toastification'
|
||||||
import Toast, { useToast, type PluginOptions } from 'vue-toastification'
|
|
||||||
import customParseFormat from 'dayjs/plugin/customParseFormat'
|
import customParseFormat from 'dayjs/plugin/customParseFormat'
|
||||||
import 'vue-toastification/dist/index.css'
|
import 'vue-toastification/dist/index.css'
|
||||||
import 'dayjs/locale/zh-cn'
|
import 'dayjs/locale/zh-cn'
|
||||||
dayjs.locale('zh-cn')
|
dayjs.locale('zh-cn')
|
||||||
|
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
export const globalToast = useToast()
|
export const globalToast = useToast()
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
|
|
|
@ -57,7 +57,7 @@ export default defineComponent(() => {
|
||||||
return layout.state.current === 0
|
return layout.state.current === 0
|
||||||
})
|
})
|
||||||
return () => (
|
return () => (
|
||||||
<div class="fixed left-0 bottom-0 z-40 w-full">
|
<div class="fixed left-0 bottom-0 z-40 w-full rounded-lg">
|
||||||
{/* 背景遮罩 */}
|
{/* 背景遮罩 */}
|
||||||
{show.value && (
|
{show.value && (
|
||||||
<div
|
<div
|
||||||
|
@ -72,13 +72,20 @@ export default defineComponent(() => {
|
||||||
{show.value && (
|
{show.value && (
|
||||||
<div
|
<div
|
||||||
class={clsx(
|
class={clsx(
|
||||||
'absolute left-6 bottom-10 w-[660px] h-[580px] rounded-lg overflow-hidden shadow-2xl flex',
|
'absolute left-6 bottom-10 w-[660px] h-[580px] rounded-2xl shadow-2xl flex',
|
||||||
isGame.value ? 'bg-[#2c2e3e] text-white' : 'text-[#000] bg-white'
|
isGame.value ? 'bg-[#2c2e3e] text-white' : 'text-[#000] bg-white'
|
||||||
)}
|
)}
|
||||||
|
style={
|
||||||
|
isGame.value &&
|
||||||
|
{
|
||||||
|
backgroundImage: `url('/tab/bg/gameModel.png')`,
|
||||||
|
backgroundSize: '100% 100%',
|
||||||
|
}
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class={clsx(
|
class={clsx(
|
||||||
'w-[200px] p-4 h-full backdrop-blur flex flex-col',
|
'w-[200px] p-4 h-full flex flex-col rounded-lg',
|
||||||
isGame.value ? 'bg-[#fff]/10 text-white ' : 'bg-[#ebebeb]'
|
isGame.value ? 'bg-[#fff]/10 text-white ' : 'bg-[#ebebeb]'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
@ -134,7 +141,10 @@ export default defineComponent(() => {
|
||||||
<SettingsTab label="问题反馈" path="settings-fallback" />
|
<SettingsTab label="问题反馈" path="settings-fallback" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class={"flex-1 w-0 h-full relative"}>
|
||||||
<Content />
|
<Content />
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|
|
@ -15,7 +15,7 @@ export default defineComponent(() => {
|
||||||
const router = useRouterStore()
|
const router = useRouterStore()
|
||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<div class="w-0 h-full flex-grow backdrop-blur">
|
<div class="w-full h-full rounded-xl">
|
||||||
<ThemeProvider>
|
<ThemeProvider>
|
||||||
{router.path === 'settings-user' ? (
|
{router.path === 'settings-user' ? (
|
||||||
<UserPage />
|
<UserPage />
|
||||||
|
|
|
@ -75,11 +75,13 @@ export default defineStore('user', () => {
|
||||||
token,
|
token,
|
||||||
async (val) => {
|
async (val) => {
|
||||||
localStorage.setItem('token', val)
|
localStorage.setItem('token', val)
|
||||||
|
|
||||||
if (!val) {
|
if (!val) {
|
||||||
sendParent(['logout'])
|
sendParent(['logout'])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sendParent(['login', val])
|
sendParent(['login', val])
|
||||||
|
|
||||||
const res = await request<UserInfo>('GET', '/api/profile')
|
const res = await request<UserInfo>('GET', '/api/profile')
|
||||||
Object.assign(profile, res)
|
Object.assign(profile, res)
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,6 +5,8 @@ import upload from './upload'
|
||||||
import 'viewerjs/dist/viewer.css'
|
import 'viewerjs/dist/viewer.css'
|
||||||
import { api as showViewer } from 'v-viewer'
|
import { api as showViewer } from 'v-viewer'
|
||||||
import { globalToast } from '@/main'
|
import { globalToast } from '@/main'
|
||||||
|
import useUserStore from '@/user/useUserStore'
|
||||||
|
import useRouterStore from '@/useRouterStore'
|
||||||
|
|
||||||
addIcons(MdUpload, FaEye)
|
addIcons(MdUpload, FaEye)
|
||||||
|
|
||||||
|
@ -33,6 +35,7 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
setup(props, ctx) {
|
setup(props, ctx) {
|
||||||
let input: HTMLInputElement | null = null
|
let input: HTMLInputElement | null = null
|
||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<div>
|
<div>
|
||||||
<input
|
<input
|
||||||
|
@ -62,7 +65,12 @@ export default defineComponent({
|
||||||
backgroundImage: `url('${props.value}')`
|
backgroundImage: `url('${props.value}')`
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
if (useUserStore().isLogin) {
|
||||||
input?.click()
|
input?.click()
|
||||||
|
} else {
|
||||||
|
globalToast.warning('请先登录')
|
||||||
|
useRouterStore().go('global-login')
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props.value ? (
|
{props.value ? (
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import clsx from "clsx";
|
import clsx from 'clsx'
|
||||||
import { computed } from "vue";
|
import { computed } from 'vue'
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent } from 'vue'
|
||||||
import { MdCheck } from "oh-vue-icons/icons";
|
import { MdCheck } from 'oh-vue-icons/icons'
|
||||||
import { addIcons, OhVueIcon } from "oh-vue-icons";
|
import { addIcons, OhVueIcon } from 'oh-vue-icons'
|
||||||
addIcons(MdCheck)
|
addIcons(MdCheck)
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "NativeColorPicker",
|
name: 'NativeColorPicker',
|
||||||
props: {
|
props: {
|
||||||
value: {
|
value: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -15,18 +15,21 @@ export default defineComponent({
|
||||||
type: Array<string>
|
type: Array<string>
|
||||||
},
|
},
|
||||||
class: {
|
class: {
|
||||||
type: String,
|
type: String
|
||||||
},
|
},
|
||||||
transparent: {
|
transparent: {
|
||||||
type: Boolean,
|
type: Boolean
|
||||||
},
|
},
|
||||||
firstColor: {
|
firstColor: {
|
||||||
type: String,
|
type: String
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
type: Number,
|
||||||
|
default: 20
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: {
|
emits: {
|
||||||
"update:value": (_value: string) => true,
|
'update:value': (_value: string) => true
|
||||||
},
|
},
|
||||||
setup(props, context) {
|
setup(props, context) {
|
||||||
const firstColor = props.value
|
const firstColor = props.value
|
||||||
|
@ -53,13 +56,16 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
return list
|
return list
|
||||||
})
|
})
|
||||||
return () => <div class={clsx("flex items-center gap-x-2 ", props.class)}>
|
return () => (
|
||||||
{
|
<div class={clsx('flex items-center gap-x-2 ', props.class)}>
|
||||||
colorList.value.map((item, index) => < div
|
{colorList.value.map((item, index) => (
|
||||||
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
onClick={() => context.emit('update:value', item)}
|
onClick={() => context.emit('update:value', item)}
|
||||||
class="text-[12px] cursor-pointer w-[20px] h-[20px] shadow-[0_0_2px_#999] rounded-full"
|
class="text-[12px] cursor-pointer w-[20px] h-[20px] flex items-center justify-center shadow-[0_0_2px_#999] rounded-full"
|
||||||
style={{
|
style={{
|
||||||
|
width: props.size + 'px',
|
||||||
|
height: props.size + 'px',
|
||||||
backgroundColor: item === 'transparent' ? '' : item,
|
backgroundColor: item === 'transparent' ? '' : item,
|
||||||
backgroundImage:
|
backgroundImage:
|
||||||
item === 'transparent'
|
item === 'transparent'
|
||||||
|
@ -78,23 +84,24 @@ export default defineComponent({
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
</Checkmark16Filled> */}
|
</Checkmark16Filled> */}
|
||||||
{
|
{props.value === item && (
|
||||||
props.value === item &&
|
|
||||||
<OhVueIcon class="text-[#888]" name={MdCheck.name}></OhVueIcon>
|
<OhVueIcon class="text-[#888]" name={MdCheck.name}></OhVueIcon>
|
||||||
|
)}
|
||||||
}
|
</div>
|
||||||
</div >)
|
))}
|
||||||
}
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="text-[12px] cursor-pointer w-[20px] h-[20px] shadow-[0_0_2px_#999] rounded-full relative"
|
class="text-[12px] cursor-pointer shadow-[0_0_2px_#999] rounded-full relative"
|
||||||
|
style={{
|
||||||
|
width: props.size + 'px',
|
||||||
|
height: props.size + 'px'
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="w-full h-full rounded-full cursor-pointer"
|
class="w-full h-full rounded-full cursor-pointer"
|
||||||
style="background: conic-gradient(#dd0010, yellow, green, #0091ff, red)"
|
style="background: conic-gradient(#dd0010, yellow, green, #0091ff, red)"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
|
|
||||||
onInput={(e: any) => {
|
onInput={(e: any) => {
|
||||||
context.emit('update:value', e?.target.value)
|
context.emit('update:value', e?.target.value)
|
||||||
}}
|
}}
|
||||||
|
@ -105,5 +112,6 @@ export default defineComponent({
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
|
@ -21,6 +21,7 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
|
|
||||||
Slider: {
|
Slider: {
|
||||||
railSize: 6
|
railSize: 6
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,14 +3,16 @@ import { defineComponent, ref, watch } from 'vue'
|
||||||
import { VueCropper } from 'vue-cropper'
|
import { VueCropper } from 'vue-cropper'
|
||||||
import 'vue-cropper/dist/index.css'
|
import 'vue-cropper/dist/index.css'
|
||||||
import upload from './upload'
|
import upload from './upload'
|
||||||
import { v4 as uuid } from "uuid"
|
import { v4 as uuid } from 'uuid'
|
||||||
import { MdCroprotateRound, BiPlusLg } from "oh-vue-icons/icons";
|
import { MdCroprotateRound, BiPlusLg } from 'oh-vue-icons/icons'
|
||||||
import { OhVueIcon, addIcons, } from 'oh-vue-icons'
|
import { OhVueIcon, addIcons } from 'oh-vue-icons'
|
||||||
import NativeColorPicker from './NativeColorPicker'
|
import NativeColorPicker from './NativeColorPicker'
|
||||||
|
import useUserStore from '@/user/useUserStore'
|
||||||
|
import { globalToast } from '@/main'
|
||||||
|
import useRouterStore from '@/useRouterStore'
|
||||||
addIcons(MdCroprotateRound, BiPlusLg)
|
addIcons(MdCroprotateRound, BiPlusLg)
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
|
||||||
emits: {
|
emits: {
|
||||||
'update:value': (() => true) as (val: string) => boolean
|
'update:value': (() => true) as (val: string) => boolean
|
||||||
},
|
},
|
||||||
|
@ -73,18 +75,20 @@ export default defineComponent({
|
||||||
<>
|
<>
|
||||||
<Modal
|
<Modal
|
||||||
open={showCutModel.value}
|
open={showCutModel.value}
|
||||||
onCancel={() => showCutModel.value = false}
|
onCancel={() => (showCutModel.value = false)}
|
||||||
onOk={() => {
|
onOk={() => {
|
||||||
cropper.value.getCropBlob((blob: any) => {
|
cropper.value.getCropBlob((blob: any) => {
|
||||||
handleFinish(blob)
|
handleFinish(blob)
|
||||||
|
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div class="w-full flex flex-col items-center gap-y-2">
|
<div class="w-full flex flex-col items-center gap-y-2">
|
||||||
<div class="w-[250px] h-[250px]" style={{
|
<div
|
||||||
backgroundColor: fillColor.value || 'transparent',
|
class="w-[250px] h-[250px]"
|
||||||
}}>
|
style={{
|
||||||
|
backgroundColor: fillColor.value || 'transparent'
|
||||||
|
}}
|
||||||
|
>
|
||||||
<VueCropper
|
<VueCropper
|
||||||
ref={cropper}
|
ref={cropper}
|
||||||
autoCropWidth="250px"
|
autoCropWidth="250px"
|
||||||
|
@ -94,7 +98,6 @@ export default defineComponent({
|
||||||
img={originFile.value}
|
img={originFile.value}
|
||||||
autoCrop={true}
|
autoCrop={true}
|
||||||
fillColor={fillColor.value}
|
fillColor={fillColor.value}
|
||||||
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between w-[250px]">
|
<div class="flex justify-between w-[250px]">
|
||||||
|
@ -102,12 +105,13 @@ export default defineComponent({
|
||||||
class="text-[10px] w-8 h-8 cursor-pointer"
|
class="text-[10px] w-8 h-8 cursor-pointer"
|
||||||
onClick={() => ($refs.cropper as any).rotateRight()}
|
onClick={() => ($refs.cropper as any).rotateRight()}
|
||||||
/> */}
|
/> */}
|
||||||
<span class="flex items-center cursor-pointer"
|
<span
|
||||||
|
class="flex items-center cursor-pointer"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
cropper.value.rotateRight()
|
cropper.value.rotateRight()
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
<OhVueIcon name="md-croprotate-round" scale={1} fill="#707070"></OhVueIcon>
|
<OhVueIcon name="md-croprotate-round" scale={1} fill="#707070"></OhVueIcon>
|
||||||
|
|
||||||
</span>
|
</span>
|
||||||
<span class="flex items-center gap-x-1">
|
<span class="flex items-center gap-x-1">
|
||||||
<svg
|
<svg
|
||||||
|
@ -136,7 +140,11 @@ export default defineComponent({
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<NativeColorPicker value={fillColor.value} onUpdate:value={e => fillColor.value = e} transparent={true} />
|
<NativeColorPicker
|
||||||
|
value={fillColor.value}
|
||||||
|
onUpdate:value={(e) => (fillColor.value = e)}
|
||||||
|
transparent={true}
|
||||||
|
/>
|
||||||
{/* {props.colorList && (
|
{/* {props.colorList && (
|
||||||
<div class="w-[250px] flex justify-center">
|
<div class="w-[250px] flex justify-center">
|
||||||
<NativeColorPicker
|
<NativeColorPicker
|
||||||
|
@ -147,23 +155,32 @@ export default defineComponent({
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)} */}
|
)} */}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
<div class="w-full h-full bg-white flex items-center justify-center"
|
<div
|
||||||
|
class="w-full h-full bg-white flex items-center justify-center"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
if (useUserStore().isLogin) {
|
||||||
inputRef.value?.click?.()
|
inputRef.value?.click?.()
|
||||||
|
} else {
|
||||||
|
globalToast.warning('请先登录')
|
||||||
|
useRouterStore().go('global-login')
|
||||||
|
// useAdderPageStore().type = 2
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<OhVueIcon name={BiPlusLg.name} fill='#666666' scale={2}></OhVueIcon>
|
<OhVueIcon name={BiPlusLg.name} fill="#666666" scale={2}></OhVueIcon>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
style={{
|
style={{
|
||||||
display: 'none'
|
display: 'none'
|
||||||
}} accept=".jpg,.jpeg,.png,.svg" type="file" onChange={handleFile} />
|
}}
|
||||||
|
accept=".jpg,.jpeg,.png,.svg"
|
||||||
|
type="file"
|
||||||
|
onChange={handleFile}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -13,7 +13,7 @@ export default function useLink(url: Ref<string>) {
|
||||||
const info = reactive<LinkInfo>({
|
const info = reactive<LinkInfo>({
|
||||||
background: '',
|
background: '',
|
||||||
desc: '',
|
desc: '',
|
||||||
icon: '',
|
icon: 'https://oss.goosetab.com/000/user_upload/1/resource/120be9d6-1c68-41ba-b539-570c39ce2421.png',
|
||||||
link: '',
|
link: '',
|
||||||
name: ''
|
name: ''
|
||||||
})
|
})
|
||||||
|
|
|
@ -33,7 +33,9 @@ export default defineComponent(() => {
|
||||||
<span class={'text-[48px] font-extrabold pt-2'}>{store.state.select.format('D')}</span>
|
<span class={'text-[48px] font-extrabold pt-2'}>{store.state.select.format('D')}</span>
|
||||||
<span>{store.state.select.format('ddd')}</span>
|
<span>{store.state.select.format('ddd')}</span>
|
||||||
<span>
|
<span>
|
||||||
本年第{store.state.select.diff(store.state.select.set('date', 1).set('months', 0), 'weeks')}周,第
|
本年第
|
||||||
|
{store.state.select.diff(store.state.select.set('date', 1).set('months', 0), 'weeks')}
|
||||||
|
周,第
|
||||||
{store.state.select.diff(store.state.select.set('date', 1).set('month', 0), 'day')}天
|
{store.state.select.diff(store.state.select.set('date', 1).set('month', 0), 'day')}天
|
||||||
</span>
|
</span>
|
||||||
<div class={'w-[138px] h-[1px] flex-shrink-0 my-7 bg-black/10 relative'}></div>
|
<div class={'w-[138px] h-[1px] flex-shrink-0 my-7 bg-black/10 relative'}></div>
|
||||||
|
@ -56,10 +58,8 @@ export default defineComponent(() => {
|
||||||
>
|
>
|
||||||
宜
|
宜
|
||||||
</div>
|
</div>
|
||||||
<div class={'flex flex-col text-[#666] text-[14px]'}>
|
<div class={'flex-1 w-0 text-[#666] text-[14px]'}>
|
||||||
{lunar.value.getDayYi().map((item: any) => {
|
{lunar.value.getDayYi().join(',')}
|
||||||
return <div class={'flex items-center'}>{item},</div>
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class={'flex w-full gap-x-5'}>
|
<div class={'flex w-full gap-x-5'}>
|
||||||
|
@ -70,10 +70,8 @@ export default defineComponent(() => {
|
||||||
>
|
>
|
||||||
忌
|
忌
|
||||||
</div>
|
</div>
|
||||||
<div class={'flex flex-col text-[#666] text-[14px]'}>
|
<div class={'flex-1 w-0 text-[#666] text-[14px]'}>
|
||||||
{lunar.value.getDayJi().map((item: any) => {
|
{lunar.value.getDayJi().join(',')}
|
||||||
return <div class={'flex items-center'}>{item},</div>
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -158,8 +156,10 @@ export default defineComponent(() => {
|
||||||
dayjs(),
|
dayjs(),
|
||||||
'day'
|
'day'
|
||||||
),
|
),
|
||||||
'border-transparent border-solid': !el.day.isSame(dayjs(), 'day') && !el.day.isSame(store.state.select, 'day'),
|
'border-transparent border-solid':
|
||||||
'border-[#76d7f2] border-solid border-[1px]': !el.day.isSame(dayjs(), 'day') && el.day.isSame(store.state.select, 'day'),
|
!el.day.isSame(dayjs(), 'day') && !el.day.isSame(store.state.select, 'day'),
|
||||||
|
'border-[#76d7f2] border-solid border-[1px]':
|
||||||
|
!el.day.isSame(dayjs(), 'day') && el.day.isSame(store.state.select, 'day')
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|
|
@ -3,9 +3,10 @@ import request from '@/utils/request'
|
||||||
import { addIcons, OhVueIcon } from 'oh-vue-icons'
|
import { addIcons, OhVueIcon } from 'oh-vue-icons'
|
||||||
import { computed, defineComponent, onMounted, ref, watch, type CSSProperties } from 'vue'
|
import { computed, defineComponent, onMounted, ref, watch, type CSSProperties } from 'vue'
|
||||||
import { FaChevronLeft } from 'oh-vue-icons/icons'
|
import { FaChevronLeft } from 'oh-vue-icons/icons'
|
||||||
import PlayImg from "~/icons/game_video_bg_play.png"
|
import PlayImg from '~/icons/game_video_bg_play.png'
|
||||||
import type { CarouselRef } from 'ant-design-vue/es/carousel'
|
import type { CarouselRef } from 'ant-design-vue/es/carousel'
|
||||||
import { randomNum } from '@/utils/tool'
|
import { randomNum } from '@/utils/tool'
|
||||||
|
import jump from '@/utils/jump'
|
||||||
addIcons(FaChevronLeft)
|
addIcons(FaChevronLeft)
|
||||||
interface Owner {
|
interface Owner {
|
||||||
face: string
|
face: string
|
||||||
|
@ -56,11 +57,19 @@ export default defineComponent(() => {
|
||||||
})
|
})
|
||||||
return () => (
|
return () => (
|
||||||
<div class="w-full h-full p-2 bg-[#17212d] relative ">
|
<div class="w-full h-full p-2 bg-[#17212d] relative ">
|
||||||
<img src={PlayImg} class={"absolute z-10 w-[40px] bg-[#ffffff24] rounded-lg backdrop-blur-sm left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2"}></img>
|
<img
|
||||||
|
src={PlayImg}
|
||||||
|
class={
|
||||||
|
'absolute z-10 w-[40px] bg-[#ffffff24] rounded-lg backdrop-blur-sm left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2'
|
||||||
|
}
|
||||||
|
></img>
|
||||||
|
|
||||||
{
|
{
|
||||||
<div
|
<div
|
||||||
class={'w-full h-full rounded-xl relative group'}
|
class={'w-full h-full rounded-xl relative group'}
|
||||||
|
onClick={() => {
|
||||||
|
jump('https://www.bilibili.com/video/av' + current.value?.aid)
|
||||||
|
}}
|
||||||
style={{
|
style={{
|
||||||
backgroundImage: `url('${current.value?.pic}')`,
|
backgroundImage: `url('${current.value?.pic}')`,
|
||||||
backgroundSize: 'cover',
|
backgroundSize: 'cover',
|
||||||
|
@ -68,7 +77,6 @@ export default defineComponent(() => {
|
||||||
backgroundRepeat: 'no-repeat'
|
backgroundRepeat: 'no-repeat'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class={
|
class={
|
||||||
'absolute bottom-0 left-1/2 -translate-x-1/2 pb-2 w-[300px] flex flex-col text-white '
|
'absolute bottom-0 left-1/2 -translate-x-1/2 pb-2 w-[300px] flex flex-col text-white '
|
||||||
|
|
|
@ -10,7 +10,7 @@ export default defineComponent(() => {
|
||||||
<img class={'w-[48px] h-[48px]'} src={'/tab/icons/hot_information_icon.png'}></img>
|
<img class={'w-[48px] h-[48px]'} src={'/tab/icons/hot_information_icon.png'}></img>
|
||||||
<div class={'flex-1 flex justify-center'}>
|
<div class={'flex-1 flex justify-center'}>
|
||||||
<div class="flex-col flex">
|
<div class="flex-col flex">
|
||||||
<span class={'text-[16px] text-white'}>热点折扣</span>
|
<span class={'text-[16px] text-white'}>热点资讯</span>
|
||||||
<div class={'flex items-center text-[#fffc] text-[12px] '}>
|
<div class={'flex items-center text-[#fffc] text-[12px] '}>
|
||||||
立即查看
|
立即查看
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { useWeApplyStore } from './useWeApplyStore'
|
||||||
import { addIcons, OhVueIcon } from 'oh-vue-icons'
|
import { addIcons, OhVueIcon } from 'oh-vue-icons'
|
||||||
import { HiChevronDown } from 'oh-vue-icons/icons'
|
import { HiChevronDown } from 'oh-vue-icons/icons'
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
|
import jump from '@/utils/jump'
|
||||||
addIcons(HiChevronDown)
|
addIcons(HiChevronDown)
|
||||||
export default defineComponent(() => {
|
export default defineComponent(() => {
|
||||||
const store = useWeApplyStore()
|
const store = useWeApplyStore()
|
||||||
|
@ -74,7 +75,12 @@ export default defineComponent(() => {
|
||||||
{store.state.list
|
{store.state.list
|
||||||
.filter((val) => val.type === 'game')
|
.filter((val) => val.type === 'game')
|
||||||
.map((item) => (
|
.map((item) => (
|
||||||
<div class={'flex gap-x-2 items-center'}>
|
<div
|
||||||
|
class={'flex gap-x-2 items-center'}
|
||||||
|
onClick={() => {
|
||||||
|
jump(item.url)
|
||||||
|
}}
|
||||||
|
>
|
||||||
<img src={item.icon} alt="game icon" class={'w-[37px] h-[37px] rounded'}></img>
|
<img src={item.icon} alt="game icon" class={'w-[37px] h-[37px] rounded'}></img>
|
||||||
<div class={'flex-1 flex flex-col overflow-hidden'}>
|
<div class={'flex-1 flex flex-col overflow-hidden'}>
|
||||||
<span class={'text-white text-[14px]'}>{item.name}</span>
|
<span class={'text-white text-[14px]'}>{item.name}</span>
|
||||||
|
@ -107,7 +113,6 @@ export default defineComponent(() => {
|
||||||
if (workRef.value) {
|
if (workRef.value) {
|
||||||
workRef.value.scrollTop += 20
|
workRef.value.scrollTop += 20
|
||||||
handleWorkScroll()
|
handleWorkScroll()
|
||||||
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -125,7 +130,12 @@ export default defineComponent(() => {
|
||||||
{store.state.list
|
{store.state.list
|
||||||
.filter((val) => val.type === 'work')
|
.filter((val) => val.type === 'work')
|
||||||
.map((item) => (
|
.map((item) => (
|
||||||
<div class={'flex gap-x-2 items-center'}>
|
<div
|
||||||
|
class={'flex gap-x-2 items-center'}
|
||||||
|
onClick={() => {
|
||||||
|
jump(item.url)
|
||||||
|
}}
|
||||||
|
>
|
||||||
<img src={item.icon} alt="game icon" class={'w-[37px] h-[37px] rounded'}></img>
|
<img src={item.icon} alt="game icon" class={'w-[37px] h-[37px] rounded'}></img>
|
||||||
<div class={'flex-1 flex flex-col overflow-hidden'}>
|
<div class={'flex-1 flex flex-col overflow-hidden'}>
|
||||||
<span class={'text-white text-[14px]'}>{item.name}</span>
|
<span class={'text-white text-[14px]'}>{item.name}</span>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { defineComponent } from 'vue'
|
import { defineComponent } from 'vue'
|
||||||
import { formatSeconds } from '@/utils/tool'
|
import { formatSeconds } from '@/utils/tool'
|
||||||
import PlayStartImg from "~/icons/work/start.png"
|
import PlayStartImg from '~/icons/work/start.png'
|
||||||
import returnImg from "~/icons/work/return.png"
|
import returnImg from '~/icons/work/return.png'
|
||||||
import endImg from "~/icons/work/tomotoIconEnd.png"
|
import endImg from '~/icons/work/tomotoIconEnd.png'
|
||||||
import PlusImg from "~/icons/work/tomatoIconAdd.png"
|
import PlusImg from '~/icons/work/tomatoIconAdd.png'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { Tooltip } from 'ant-design-vue'
|
import { Tooltip } from 'ant-design-vue'
|
||||||
import useTomatoStore from './useTomatoStore'
|
import useTomatoStore from './useTomatoStore'
|
||||||
|
@ -11,41 +11,54 @@ import useTomatoStore from './useTomatoStore'
|
||||||
export default defineComponent(() => {
|
export default defineComponent(() => {
|
||||||
const store = useTomatoStore()
|
const store = useTomatoStore()
|
||||||
return () => (
|
return () => (
|
||||||
<div class="w-full h-full flex relative p-6 justify-between" style={{
|
<div
|
||||||
|
class="w-full h-full flex relative p-6 justify-between"
|
||||||
|
style={{
|
||||||
background: `url('https://newfatfox.oss-cn-beijing.aliyuncs.com/admin/tomotoback.png')`,
|
background: `url('https://newfatfox.oss-cn-beijing.aliyuncs.com/admin/tomotoback.png')`,
|
||||||
backgroundSize: 'cover',
|
backgroundSize: 'cover',
|
||||||
backgroundRepeat: 'no-repeat'
|
backgroundRepeat: 'no-repeat'
|
||||||
}}>
|
}}
|
||||||
<div class={"bg-[#0000004d] absolute top-0 left-0 right-0 bottom-0 "}></div>
|
>
|
||||||
<div class={"w-[115px] h-full flex flex-col items-center z-10 text-white"}>
|
<div class={'bg-[#0000004d] absolute top-0 left-0 right-0 bottom-0 '}></div>
|
||||||
<div class={"w-full bg-white/20 text-center rounded text-[14px]"}>无目标</div>
|
<div class={'w-[115px] h-full flex flex-col items-center z-10 text-white'}>
|
||||||
<span class={"text-[42px] mb-1"}>
|
<div
|
||||||
{
|
class={
|
||||||
store.state.beginTime < 0 ? '15:00' : formatSeconds(store.remainingTime)
|
'w-full bg-white/20 text-center rounded text-[14px] overflow-hidden text-ellipsis whitespace-nowrap'
|
||||||
}
|
}
|
||||||
</span>
|
>
|
||||||
<span class={"text-[14px]"}>你今日已完成
|
{store.state.list[0] ? store.state.list[0].title : '无目标'}
|
||||||
<span class={"text-[#76e6ff] mx-1"}>
|
|
||||||
|
|
||||||
|
|
||||||
{store.state.timeList.filter(val => dayjs(val).isSame(dayjs(), 'day')).length}</span>
|
|
||||||
</span>
|
|
||||||
<span class={"text-[14px]"}>个番茄时</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class={"flex flex-col justify-end"}>
|
<span class={'text-[42px] mb-1'}>
|
||||||
<div class={"flex gap-x-3 "}>
|
{store.state.beginTime < 0 ? '15:00' : formatSeconds(store.remainingTime)}
|
||||||
<Tooltip title={"沉浸模式"}>
|
</span>
|
||||||
|
<span class={'text-[14px]'}>
|
||||||
|
你今日已完成
|
||||||
|
<span class={'text-[#76e6ff] mx-1'}>
|
||||||
|
{store.state.timeList.filter((val) => dayjs(val).isSame(dayjs(), 'day')).length}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span class={'text-[14px]'}>个番茄时</span>
|
||||||
|
</div>
|
||||||
|
<div class={'flex flex-col justify-end'}>
|
||||||
|
<div class={'flex gap-x-3 '}>
|
||||||
|
<Tooltip title={'沉浸模式'}>
|
||||||
<div
|
<div
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
store.openFullscreen = true
|
store.openFullscreen = true
|
||||||
}}
|
}}
|
||||||
class={"w-[42px] h-[42px] bg-white/40 backdrop-blur-md flex items-center justify-center rounded-xl"}>
|
class={
|
||||||
<img src={returnImg} alt="start" class={"w-[18px]"}></img>
|
'w-[42px] h-[42px] bg-white/40 backdrop-blur-md flex items-center justify-center rounded-xl'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<img src={returnImg} alt="start" class={'w-[18px]'}></img>
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title={"开始"}>
|
<Tooltip title={'开始'}>
|
||||||
<div class={"w-[42px] h-[42px] bg-white/40 backdrop-blur-md flex items-center justify-center rounded-xl"}
|
<div
|
||||||
|
class={
|
||||||
|
'w-[42px] h-[42px] bg-white/40 backdrop-blur-md flex items-center justify-center rounded-xl'
|
||||||
|
}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
if (store.state.isStart) {
|
if (store.state.isStart) {
|
||||||
|
@ -53,30 +66,30 @@ export default defineComponent(() => {
|
||||||
} else {
|
} else {
|
||||||
store.beginTomatoTime()
|
store.beginTomatoTime()
|
||||||
store.openFullscreen = true
|
store.openFullscreen = true
|
||||||
|
|
||||||
}
|
|
||||||
}}>
|
|
||||||
{
|
|
||||||
store.state.isStart ?
|
|
||||||
<img src={endImg} alt="start" class={"w-[18px]"}></img>
|
|
||||||
:
|
|
||||||
<img src={PlayStartImg} alt="start" class={"w-[18px]"}></img>
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{store.state.isStart ? (
|
||||||
|
<img src={endImg} alt="start" class={'w-[18px]'}></img>
|
||||||
|
) : (
|
||||||
|
<img src={PlayStartImg} alt="start" class={'w-[18px]'}></img>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title={"添加目标"}>
|
<Tooltip title={'添加目标'}>
|
||||||
<div class={"w-[42px] h-[42px] bg-white/40 backdrop-blur-md flex items-center justify-center rounded-xl"}
|
<div
|
||||||
|
class={
|
||||||
|
'w-[42px] h-[42px] bg-white/40 backdrop-blur-md flex items-center justify-center rounded-xl'
|
||||||
|
}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
store.openShowModel = null
|
store.openShowModel = null
|
||||||
|
|
||||||
}, 300)
|
}, 300)
|
||||||
}}>
|
}}
|
||||||
<img src={PlusImg} alt="start" class={"w-[18px]"}></img>
|
>
|
||||||
|
<img src={PlusImg} alt="start" class={'w-[18px]'}></img>
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -130,7 +130,8 @@ const EditContent = defineComponent(() => {
|
||||||
{!form.value.remindTime ? '选择时间' : dayjs(form.value.remindTime).format('HH:mm')}
|
{!form.value.remindTime ? '选择时间' : dayjs(form.value.remindTime).format('HH:mm')}
|
||||||
<img src={DownImg} class={"w-[12px] object-cover "}></img>
|
<img src={DownImg} class={"w-[12px] object-cover "}></img>
|
||||||
<TimePicker
|
<TimePicker
|
||||||
|
format={'HH:mm'}
|
||||||
|
showNow={false}
|
||||||
class={'absolute opacity-0 left-0 top-0 w-full h-full'}
|
class={'absolute opacity-0 left-0 top-0 w-full h-full'}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
form.value.remindTime = dayjs(e).valueOf()
|
form.value.remindTime = dayjs(e).valueOf()
|
||||||
|
|
|
@ -66,7 +66,8 @@ export default defineComponent(() => {
|
||||||
</div>
|
</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"}
|
<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={() => {
|
onClick={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
const idx = store.state.list.findIndex(val => val.id === item.id)
|
const idx = store.state.list.findIndex(val => val.id === item.id)
|
||||||
if (idx !== -1) {
|
if (idx !== -1) {
|
||||||
store.state.list.splice(0, 1)
|
store.state.list.splice(0, 1)
|
||||||
|
|
|
@ -5,7 +5,17 @@ module.exports = {
|
||||||
content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
|
content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
|
||||||
darkMode: 'class',
|
darkMode: 'class',
|
||||||
theme: {
|
theme: {
|
||||||
extend: {}
|
extend: {
|
||||||
|
animation: {
|
||||||
|
wiggle: 'wiggle .3s ease-in-out infinite'
|
||||||
|
},
|
||||||
|
keyframes: {
|
||||||
|
wiggle: {
|
||||||
|
'0%, 100%': { transform: 'rotate(-1deg)' },
|
||||||
|
'50%': { transform: 'rotate(1deg)' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
plugins: [require('@tailwindcss/typography')]
|
plugins: [require('@tailwindcss/typography')]
|
||||||
|
|
Loading…
Reference in New Issue