Merge remote-tracking branch 'origin/dev'
This commit is contained in:
commit
3790a332c5
|
@ -32,9 +32,11 @@
|
|||
"dayjs": "^1.11.13",
|
||||
"echarts": "^5.5.1",
|
||||
"gsap": "^3.12.5",
|
||||
"js-base64": "^3.7.7",
|
||||
"localforage": "^1.10.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lunar-typescript": "^1.7.5",
|
||||
"milkdown-plugin-placeholder": "^0.2.1",
|
||||
"oh-vue-icons": "^1.0.0-rc3",
|
||||
"pinia": "^2.1.7",
|
||||
"pinia-plugin-persistedstate": "^3.2.3",
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
92
src/App.vue
92
src/App.vue
|
@ -19,6 +19,7 @@ import useRouterStore from './useRouterStore'
|
|||
import BackupRecovery from './user/BackupRecovery'
|
||||
import { ConfigProvider } from 'ant-design-vue'
|
||||
import zhCN from 'ant-design-vue/es/locale/zh_CN'
|
||||
import ModalPgae from './layout/grid/ModalPgae'
|
||||
const Grid = asyncLoader(() => import('./layout/grid'))
|
||||
const Fox = asyncLoader(() => import('./fox'))
|
||||
const settings = useSettingsStore()
|
||||
|
@ -30,53 +31,54 @@ const router = useRouterStore()
|
|||
const layout = useLayoutStore()
|
||||
</script>
|
||||
<template>
|
||||
<ConfigProvider :locale="zhCN">
|
||||
<div class="fixed left-0 top-0 w-full h-screen style-root" @contextmenu.prevent>
|
||||
<Header />
|
||||
<Background
|
||||
@dblclick="
|
||||
() => {
|
||||
layout.state.simple = !layout.state.simple
|
||||
}
|
||||
"
|
||||
/>
|
||||
<GLobalModal />
|
||||
<SettingsOverlay />
|
||||
<SettingsButton />
|
||||
<!-- <ConfigProvider :locale="zhCN"> -->
|
||||
<div class="fixed left-0 top-0 w-full h-screen style-root" @contextmenu.prevent>
|
||||
<Header />
|
||||
<Background
|
||||
@dblclick="
|
||||
() => {
|
||||
layout.state.simple = !layout.state.simple
|
||||
}
|
||||
"
|
||||
/>
|
||||
<GLobalModal />
|
||||
<SettingsOverlay />
|
||||
<SettingsButton />
|
||||
|
||||
<Sider
|
||||
v-if="
|
||||
!layout.state.simple ||
|
||||
(layout.state.simple && settings.state.simpleModeShowString.includes('showSider'))
|
||||
"
|
||||
/>
|
||||
<LoginModal v-if="router.path === 'global-login'" />
|
||||
<Transition>
|
||||
<Grid v-if="layout.ready && !layout.state.simple" />
|
||||
</Transition>
|
||||
<Dock
|
||||
v-if="
|
||||
!layout.state.simple ||
|
||||
(layout.state.simple && settings.state.simpleModeShowString.includes('showDock'))
|
||||
"
|
||||
/>
|
||||
<div
|
||||
class="fixed z-40 right-[14%] top-8"
|
||||
v-if="
|
||||
!layout.state.simple ||
|
||||
(layout.state.simple && settings.state.simpleModeShowString.includes('showPet'))
|
||||
"
|
||||
>
|
||||
<Fox />
|
||||
</div>
|
||||
<DirModal />
|
||||
<GlobalMenu />
|
||||
<WelcomePage></WelcomePage>
|
||||
<TomatoPage></TomatoPage>
|
||||
|
||||
<BackupRecovery v-if="router.path === 'global-backup'"></BackupRecovery>
|
||||
<Sider
|
||||
v-if="
|
||||
!layout.state.simple ||
|
||||
(layout.state.simple && settings.state.simpleModeShowString.includes('showSider'))
|
||||
"
|
||||
/>
|
||||
<LoginModal v-if="router.path === 'global-login'" />
|
||||
<Transition>
|
||||
<Grid v-if="layout.ready && !layout.state.simple" />
|
||||
</Transition>
|
||||
<Dock
|
||||
v-if="
|
||||
!layout.state.simple ||
|
||||
(layout.state.simple && settings.state.simpleModeShowString.includes('showDock'))
|
||||
"
|
||||
/>
|
||||
<div
|
||||
class="fixed z-40 right-[14%] top-8"
|
||||
v-if="
|
||||
(!layout.state.simple && settings.state.showPet) ||
|
||||
(layout.state.simple && settings.state.simpleModeShowString.includes('showPet'))
|
||||
"
|
||||
>
|
||||
<Fox />
|
||||
</div>
|
||||
</ConfigProvider>
|
||||
<DirModal />
|
||||
<GlobalMenu />
|
||||
<WelcomePage></WelcomePage>
|
||||
<TomatoPage></TomatoPage>
|
||||
|
||||
<BackupRecovery v-if="router.path === 'global-backup'"></BackupRecovery>
|
||||
</div>
|
||||
<ModalPgae />
|
||||
<!-- </ConfigProvider> -->
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
|
|
|
@ -66,6 +66,10 @@ const Item = defineComponent({
|
|||
noStyle: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
centered: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
emits: {
|
||||
|
@ -75,12 +79,13 @@ const Item = defineComponent({
|
|||
return () => (
|
||||
<div
|
||||
class={clsx(
|
||||
'px-4 py-2 text-sm tracking-widest w-full overflow-hidden text-ellipsis whitespace-nowrap break-all transition-all rounded-lg cursor-pointer mb-2',
|
||||
' py-1 text-sm tracking-widest w-full overflow-hidden flex text-ellipsis whitespace-nowrap break-all transition-all rounded cursor-pointer mb-[2px]',
|
||||
{
|
||||
'bg-red-500/80 hover:bg-red-500 text-white': props.alert,
|
||||
'bg-white/80 hover:bg-white text-black/80': !props.alert && !props.noStyle,
|
||||
' hover:bg-black/20 text-black/80': props.alert,
|
||||
' hover:bg-black/20 text-black/80': !props.alert && !props.noStyle,
|
||||
'bg-transparent text-black/60 hover:text-black/80 hover:bg-white/20': props.noStyle
|
||||
}
|
||||
},
|
||||
props.centered ? 'justify-center' : 'pl-2 justify-start'
|
||||
)}
|
||||
style={
|
||||
props.noStyle
|
||||
|
@ -114,7 +119,7 @@ export default defineComponent(() => {
|
|||
v-outside-click={() => {
|
||||
menu.dismiss()
|
||||
}}
|
||||
class="fixed px-2 pt-4 pb-2 bg-white/60 backdrop-blur shadow-lg rounded-lg overflow-hidden"
|
||||
class="fixed px-2 pt-2 pb-1 bg-white/60 backdrop-blur shadow-lg rounded-lg overflow-hidden"
|
||||
style={{
|
||||
zIndex: '999',
|
||||
left: menu.display.x + 'px',
|
||||
|
@ -216,6 +221,7 @@ export default defineComponent(() => {
|
|||
return (
|
||||
<>
|
||||
<Item
|
||||
centered
|
||||
onClick={() => {
|
||||
menu.showEditPage = true
|
||||
menu.dismiss()
|
||||
|
@ -223,26 +229,32 @@ export default defineComponent(() => {
|
|||
>
|
||||
编辑
|
||||
</Item>
|
||||
<Item
|
||||
alert
|
||||
onClick={() => {
|
||||
// 删除链接
|
||||
console.log(menu.selectPage)
|
||||
{layout.state.content[layout.state.current].pages.length > 1 && (
|
||||
<Item
|
||||
alert
|
||||
centered
|
||||
onClick={() => {
|
||||
// 删除链接
|
||||
|
||||
const idx = layout.state.content[layout.state.current].pages.findIndex(
|
||||
(el) => el.id === menu.selectPage?.id
|
||||
)
|
||||
menu.dismiss()
|
||||
const idx = layout.state.content[layout.state.current].pages.findIndex(
|
||||
(el) => el.id === menu.selectPage?.id
|
||||
)
|
||||
menu.dismiss()
|
||||
|
||||
if (idx < 0) return
|
||||
if (idx === layout.state.currentPage) {
|
||||
return
|
||||
}
|
||||
layout.state.content[layout.state.current].pages.splice(idx, 1)
|
||||
}}
|
||||
>
|
||||
删除
|
||||
</Item>
|
||||
if (idx < 0) return
|
||||
layout.state.content[layout.state.current].pages.splice(idx, 1)
|
||||
if (
|
||||
layout.state.currentPage >=
|
||||
layout.state.content[layout.state.current].pages.length
|
||||
) {
|
||||
layout.state.currentPage =
|
||||
layout.state.content[layout.state.current].pages.length - 1
|
||||
}
|
||||
}}
|
||||
>
|
||||
删除
|
||||
</Item>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -347,7 +359,7 @@ export default defineComponent(() => {
|
|||
text: block.text,
|
||||
background: block.background,
|
||||
color: block.color,
|
||||
type: block.color ? 1 : 0
|
||||
type: !block.icon ? 1 : 0
|
||||
}
|
||||
router.go('global-adder')
|
||||
useAdderPageStore().type = 2
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {
|
||||
computed,
|
||||
defineComponent,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
provide,
|
||||
ref,
|
||||
|
@ -24,6 +25,7 @@ import HotAdder from './HotAdder'
|
|||
import GameAdder from './GameAdder'
|
||||
import work_add_main_checked from '/icons/work_add_main_checked.png'
|
||||
import useAdderPageStore from './useAdderPageStore'
|
||||
import search from '../header/search'
|
||||
addIcons(MdKeyboardcommandkey, FaCompass, FaPencilRuler, IoGameController)
|
||||
|
||||
const ItemButton = defineComponent({
|
||||
|
@ -83,9 +85,11 @@ export default defineComponent(() => {
|
|||
const addTo = ref(layout.state.currentPage)
|
||||
|
||||
provide(AddToToken, addTo)
|
||||
// onUnmounted(() => {
|
||||
// store.type = 1
|
||||
// })
|
||||
onUnmounted(() => {
|
||||
store.isSearch = false
|
||||
|
||||
})
|
||||
|
||||
return () => (
|
||||
<div
|
||||
class={clsx(
|
||||
|
|
|
@ -270,7 +270,6 @@ export default defineComponent(() => {
|
|||
return
|
||||
}
|
||||
if (store.editBlockItem !== null) {
|
||||
console.log(123)
|
||||
layout.changeBlock(form, store.editBlockItem.id)
|
||||
useRouterStore().back()
|
||||
store.editBlockItem = null
|
||||
|
@ -292,6 +291,7 @@ export default defineComponent(() => {
|
|||
label: form.name
|
||||
}
|
||||
layout.addBlock(data, addTo?.value)
|
||||
globalToast.success('添加成功')
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
|
|
@ -5,6 +5,7 @@ import useLayoutStore from '../useLayoutStore'
|
|||
import { AddToToken } from './AdderPage'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
import useAdderPageStore, { type HotAppType } from './useAdderPageStore'
|
||||
import { globalToast } from '@/main'
|
||||
|
||||
export const LinkItem = defineComponent({
|
||||
props: {
|
||||
|
@ -83,8 +84,8 @@ export const LinkItem = defineComponent({
|
|||
}
|
||||
)}
|
||||
onClick={() => {
|
||||
layout.addBlock(
|
||||
{
|
||||
if (layout.openDir) {
|
||||
layout.state.dir[layout.openDir].list.push({
|
||||
id: uuid(),
|
||||
link: props.content.url,
|
||||
name: props.content.name,
|
||||
|
@ -95,11 +96,27 @@ export const LinkItem = defineComponent({
|
|||
color: '',
|
||||
w: 1,
|
||||
h: 1
|
||||
},
|
||||
addTo?.value
|
||||
)
|
||||
if (addTo?.value) {
|
||||
layout.state.currentPage = addTo?.value
|
||||
})
|
||||
globalToast.success('添加成功')
|
||||
} else {
|
||||
layout.addBlock(
|
||||
{
|
||||
id: uuid(),
|
||||
link: props.content.url,
|
||||
name: props.content.name,
|
||||
label: props.content.name,
|
||||
icon: props.content.icon,
|
||||
text: '',
|
||||
background: '',
|
||||
color: '',
|
||||
w: 1,
|
||||
h: 1
|
||||
},
|
||||
addTo?.value
|
||||
)
|
||||
if (addTo?.value) {
|
||||
layout.state.currentPage = addTo?.value
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
|
|
@ -36,7 +36,7 @@ export default defineStore('adderPage', () => {
|
|||
const isSearch = ref(false)
|
||||
const widgetSearchWords = ref('')
|
||||
const gameSearch = ref('')
|
||||
const editBlockItem = ref<EditBlockItemType | null >(null)
|
||||
const editBlockItem = ref<EditBlockItemType | null>(null)
|
||||
request<HotAppCategoryType[]>('GET', '/api/app/hotAppTypes').then((res) => {
|
||||
categoryList.value = res.map((el) => ({
|
||||
id: el.id,
|
||||
|
@ -50,6 +50,12 @@ export default defineStore('adderPage', () => {
|
|||
watch(selectType, (val) => {
|
||||
getApps(val)
|
||||
})
|
||||
watch(isSearch, () => {
|
||||
if (!isSearch.value) {
|
||||
getApps(selectType.value)
|
||||
|
||||
}
|
||||
})
|
||||
const getApps = (_selectType: string) => {
|
||||
loading.value = true
|
||||
request<HotAppType[]>('GET', `/api/app/hotApps?hotAppsId=${_selectType}`)
|
||||
|
@ -64,9 +70,10 @@ export default defineStore('adderPage', () => {
|
|||
}
|
||||
|
||||
const search = (keywords: string) => {
|
||||
if (keywords === '') {
|
||||
if (!keywords) {
|
||||
if (isSearch.value) getApps(selectType.value)
|
||||
|
||||
isSearch.value = false
|
||||
getApps(selectType.value)
|
||||
return
|
||||
}
|
||||
isSearch.value = true
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Button, Slider } from 'ant-design-vue'
|
||||
import { Button, Slider } from 'ant-design-vue'
|
||||
import { defineComponent, ref, Transition, watch } from 'vue'
|
||||
import useLayoutStore from '../useLayoutStore'
|
||||
import { DownloadOutlined, EyeInvisibleOutlined, SwapOutlined } from '@ant-design/icons-vue'
|
||||
|
@ -23,26 +23,33 @@ export default defineComponent(() => {
|
|||
const settings = useSettingsStore()
|
||||
return () => (
|
||||
<div class="absolute left-0 top-0 w-full h-full p-4 overflow-y-auto scrollbar-hide">
|
||||
{/* <SettingItem
|
||||
noBg
|
||||
v-slots={{
|
||||
label: () => <div>所属模式</div>
|
||||
}}
|
||||
>
|
||||
<Select
|
||||
class="w-[100px]"
|
||||
options={[
|
||||
{ label: '游戏', value: 0 },
|
||||
{ label: '工作', value: 1 },
|
||||
{ label: '休闲', value: 2 }
|
||||
]}
|
||||
v-model:value={selected.value}
|
||||
/>
|
||||
</SettingItem> */}
|
||||
<div class="px-4">
|
||||
<div class={'flex flex-col'}>
|
||||
<span
|
||||
class={clsx(
|
||||
'text-[14px] font-bold',
|
||||
useLayoutStore().state.current === 0 ? 'text-white' : ' text-[#333]'
|
||||
)}
|
||||
>
|
||||
壁纸
|
||||
</span>
|
||||
<span class={'text-[13px] text-[#666] '}>调整壁纸</span>
|
||||
<div
|
||||
class={clsx(
|
||||
'w-full h-[1px] bg-black/10 mt-1 mb-2',
|
||||
useLayoutStore().state.current === 0 ? 'bg-white/10' : ' bg-black/10'
|
||||
)}
|
||||
></div>
|
||||
</div>
|
||||
<div class="h-[180px]">
|
||||
{layout.background.video && layout.background.type !== 'own' ? (
|
||||
<video class="w-full h-full" src={layout.background.video} autoplay={false} controls />
|
||||
<video
|
||||
class="w-full h-full"
|
||||
src={layout.background.video}
|
||||
loop
|
||||
autoplay={false}
|
||||
controls
|
||||
/>
|
||||
) : (
|
||||
<div
|
||||
class="w-full h-full bg-center bg-no-repeat bg-cover"
|
||||
|
|
|
@ -166,6 +166,7 @@ export default defineComponent(() => {
|
|||
<div
|
||||
onClick={() => {
|
||||
layout.changeBackground(item.url)
|
||||
background.state.isCustom = false
|
||||
}}
|
||||
class="h-[156px] relative cursor-pointer group w-full flex-grow-0 rounded-xl overflow-hidden"
|
||||
>
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
import upload, { localPrefix, uploadLocal } from '@/utils/upload'
|
||||
import clsx from 'clsx'
|
||||
import { defineComponent, ref, toRef } from 'vue'
|
||||
import { computed, defineComponent, ref, toRef } from 'vue'
|
||||
import useBackgroundStore from './useBackgroundStore'
|
||||
import useResource from './useResource'
|
||||
import useLayoutStore from '../useLayoutStore'
|
||||
import { message } from 'ant-design-vue'
|
||||
import { BgContent } from '.'
|
||||
|
||||
export default defineComponent(() => {
|
||||
const dragging = ref(false)
|
||||
const fileInput = ref<HTMLInputElement | null>(null)
|
||||
const backgroundStore = useBackgroundStore()
|
||||
const tempFile = ref<File | null>(null)
|
||||
const layout = useLayoutStore()
|
||||
const tempBackground = ref('')
|
||||
const type = ref('img')
|
||||
const handleDrop = (e: DragEvent) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
|
@ -20,7 +23,28 @@ export default defineComponent(() => {
|
|||
if (!file) return
|
||||
tempBackground.value = URL.createObjectURL(file)
|
||||
tempFile.value = file
|
||||
|
||||
if (file.type.includes('image')) {
|
||||
type.value = 'img'
|
||||
} else {
|
||||
type.value = 'video'
|
||||
}
|
||||
}
|
||||
const showImg = computed(() => {
|
||||
if (tempBackground.value) {
|
||||
return tempBackground.value
|
||||
}
|
||||
if (backgroundStore.state.isCustom) {
|
||||
if (layout.background.video) {
|
||||
type.value = 'video'
|
||||
return layout.background.video
|
||||
} else {
|
||||
return layout.background.image
|
||||
}
|
||||
}
|
||||
|
||||
return ''
|
||||
})
|
||||
return () => (
|
||||
<div class={'w-full h-full flex flex-col items-center pt-5 pb-10 gap-y-4'}>
|
||||
<div class="flex flex-col text-center gap-y-1">
|
||||
|
@ -47,16 +71,28 @@ export default defineComponent(() => {
|
|||
|
||||
dragging.value ? 'border-[#3f80ff] bg-[#6b9dff1a]' : 'border-transparent bg-[#ebebeb]'
|
||||
)}
|
||||
style={
|
||||
tempBackground.value
|
||||
? {
|
||||
backgroundImage: `url(${tempBackground.value})`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundRepeat: 'no-repeat'
|
||||
}
|
||||
: {}
|
||||
}
|
||||
// style={
|
||||
// tempBackground.value
|
||||
// ? {
|
||||
// backgroundImage: `url(${tempBackground.value})`,
|
||||
// backgroundSize: 'cover',
|
||||
// backgroundRepeat: 'no-repeat'
|
||||
// }
|
||||
// : backgroundStore.state.isCustom
|
||||
// ? {
|
||||
// backgroundImage: `url(${backgroundStore.tag})`,
|
||||
// backgroundSize: 'cover',
|
||||
// backgroundRepeat: 'no-repeat'
|
||||
// }
|
||||
// : null
|
||||
// }
|
||||
>
|
||||
<div class={'absolute top-0 left-0 w-full h-full'}>
|
||||
<BgContent
|
||||
image={showImg.value}
|
||||
video={type.value === 'video' ? showImg.value : undefined}
|
||||
></BgContent>
|
||||
</div>
|
||||
<div class={'w-full h-full absolute left-0 top-0 bottom-0 right-0 group'}>
|
||||
<div
|
||||
class={clsx(
|
||||
|
@ -64,7 +100,7 @@ export default defineComponent(() => {
|
|||
tempBackground.value ? 'bg-black/50 hidden group-hover:flex' : 'flex'
|
||||
)}
|
||||
>
|
||||
<img alt="123" src={new URL('/tab/icons/uploadImg.png', import.meta.url).href}></img>
|
||||
<img alt="123" src={'/tab/icons/uploadImg.png'}></img>
|
||||
<span
|
||||
class={clsx('text-[15px] ', tempBackground.value ? 'text-[#fff]' : 'text-[#333]')}
|
||||
>
|
||||
|
@ -75,12 +111,18 @@ export default defineComponent(() => {
|
|||
</span>
|
||||
<input
|
||||
type="file"
|
||||
accept="image/jpeg,image/png,image/svg + xml,image/gif,video/mp4"
|
||||
ref={fileInput}
|
||||
hidden
|
||||
onChange={(e: any) => {
|
||||
const file = e.target?.files?.[0]
|
||||
if (!file) return
|
||||
tempFile.value = file
|
||||
if (file.type.includes('image')) {
|
||||
type.value = 'img'
|
||||
} else {
|
||||
type.value = 'video'
|
||||
}
|
||||
tempBackground.value = URL.createObjectURL(file)
|
||||
}}
|
||||
/>
|
||||
|
@ -96,9 +138,8 @@ export default defineComponent(() => {
|
|||
if (tempFile.value) {
|
||||
uploadLocal(tempFile.value).then((res) => {
|
||||
useLayoutStore().changeBackground(res)
|
||||
|
||||
backgroundStore.state.isCustom = true
|
||||
tempFile.value = null
|
||||
tempBackground.value = ''
|
||||
message.success('应用成功')
|
||||
})
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import { defineComponent, nextTick, reactive, ref, Transition, watch } from 'vue
|
|||
import useLayoutStore from '../useLayoutStore'
|
||||
import useSettingsStore from '@/settings/useSettingsStore'
|
||||
|
||||
const BgContent = defineComponent({
|
||||
export const BgContent = defineComponent({
|
||||
props: {
|
||||
image: {
|
||||
type: String,
|
||||
|
@ -29,12 +29,14 @@ const BgContent = defineComponent({
|
|||
}}
|
||||
>
|
||||
{props.video ? (
|
||||
<video src={props.video} class="w-full h-full" muted />
|
||||
<video autoplay src={props.video} loop class="w-full h-full object-cover" muted />
|
||||
) : (
|
||||
<div
|
||||
class="w-full h-full bg-center bg-cover bg-no-repeat"
|
||||
style={{
|
||||
backgroundImage: `url('${props.image}')`
|
||||
backgroundImage: `url('${props.image}')`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center center',
|
||||
}}
|
||||
></div>
|
||||
)}
|
||||
|
@ -83,9 +85,9 @@ export default defineComponent({
|
|||
}
|
||||
}
|
||||
)
|
||||
watch(pair, console.log)
|
||||
return () => (
|
||||
<div class="absolute left-0 top-0 w-full h-screen z-0">
|
||||
|
||||
<Transition name={animate.value ? 'background' : ''}>
|
||||
{pair.front ? (
|
||||
<div class="absolute left-0 top-0 w-full h-full">
|
||||
|
|
|
@ -3,6 +3,9 @@ import { reactive, ref, watch } from 'vue'
|
|||
|
||||
export default defineStore('background', () => {
|
||||
const tag = ref(localStorage.getItem('backgroundTag') || '')
|
||||
const state = reactive({
|
||||
isCustom: false,
|
||||
})
|
||||
const resource = reactive({
|
||||
type: 'image',
|
||||
brief: '',
|
||||
|
@ -29,6 +32,9 @@ export default defineStore('background', () => {
|
|||
)
|
||||
return {
|
||||
tag,
|
||||
resource
|
||||
resource,
|
||||
state
|
||||
}
|
||||
}, {
|
||||
persist: true
|
||||
})
|
||||
|
|
|
@ -27,10 +27,12 @@ export default function useResource(tag: Ref<string>, type: string) {
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (val.startsWith('http')) {
|
||||
// 内源
|
||||
if (val.startsWith(ossCdnBase)) {
|
||||
// 地址后缀
|
||||
|
||||
const suffix = val.split('.').pop()
|
||||
if (!suffix) {
|
||||
return
|
||||
|
@ -38,6 +40,7 @@ export default function useResource(tag: Ref<string>, type: string) {
|
|||
if (videoArr.includes(suffix)) {
|
||||
// 内部视频
|
||||
// 先显示截图,再去数据库看是否有存货
|
||||
|
||||
resource.video = ''
|
||||
resource.image = val + '?x-oss-process=video/snapshot,t_0,f_jpg,m_fast'
|
||||
resource.brief = val + '?x-oss-process=video/snapshot,t_0,f_jpg,w_400,h_225,m_fast'
|
||||
|
@ -45,10 +48,12 @@ export default function useResource(tag: Ref<string>, type: string) {
|
|||
if (!res) return
|
||||
const item = res.find((item) => item.tag === val)
|
||||
if (item) {
|
||||
|
||||
resource.video = URL.createObjectURL(item.file)
|
||||
resource.type = 'local'
|
||||
} else {
|
||||
// 不存在,需要存入
|
||||
|
||||
fetch(val)
|
||||
.then((res) => res.blob())
|
||||
.then((blob) => {
|
||||
|
@ -61,6 +66,7 @@ export default function useResource(tag: Ref<string>, type: string) {
|
|||
})
|
||||
}
|
||||
})
|
||||
|
||||
} else {
|
||||
// 图片
|
||||
resource.image = val
|
||||
|
@ -91,7 +97,10 @@ export default function useResource(tag: Ref<string>, type: string) {
|
|||
if (!res) return
|
||||
const item = res.find((item) => item.tag === val)
|
||||
if (!item) return
|
||||
|
||||
const url = URL.createObjectURL(item.file)
|
||||
|
||||
|
||||
resource.image = item.type === 'image' ? url : ''
|
||||
resource.video = item.type === 'video' ? url : ''
|
||||
resource.brief = url
|
||||
|
|
|
@ -5,7 +5,9 @@ import LinkBlock from '../grid/LinkBlock'
|
|||
import useSettingsStore from '@/settings/useSettingsStore'
|
||||
import clsx from 'clsx'
|
||||
import { useMenuStore } from '../GlobalMenu'
|
||||
|
||||
import { HiSolidLockOpen, HiSolidLockClosed } from 'oh-vue-icons/icons'
|
||||
import { addIcons, OhVueIcon } from 'oh-vue-icons'
|
||||
addIcons(HiSolidLockClosed, HiSolidLockOpen)
|
||||
export default defineComponent(() => {
|
||||
const layout = useLayoutStore()
|
||||
const setting = useSettingsStore()
|
||||
|
@ -28,12 +30,16 @@ export default defineComponent(() => {
|
|||
onMouseleave={() => {
|
||||
show.value = false
|
||||
}}
|
||||
class={'w-3/5 min-w-[800px] h-[120px] fixed left-1/2 bottom-0 -translate-x-1/2'}
|
||||
class={'w-3/5 min-w-[800px] group h-[120px] fixed left-1/2 bottom-0 -translate-x-1/2'}
|
||||
>
|
||||
<div
|
||||
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',
|
||||
setting.state.showDock === 'auto' ? show.value ? 'bottom-4' : 'bottom-[-90px]' : 'bottom-4'
|
||||
'fixed bottom-6 left-1/2 duration-150 -translate-x-1/2 px-5 p-4 rounded-xl bg-white/60 backdrop-blur flex gap-5 shadow-lg',
|
||||
setting.state.showDock === 'auto'
|
||||
? show.value
|
||||
? 'bottom-4'
|
||||
: 'bottom-[-90px]'
|
||||
: 'bottom-4'
|
||||
)}
|
||||
ref={container}
|
||||
onMouseleave={() => {
|
||||
|
@ -45,6 +51,21 @@ export default defineComponent(() => {
|
|||
menu.open('dock')
|
||||
}}
|
||||
>
|
||||
<div
|
||||
onClick={()=> {
|
||||
setting.state.showDock = setting.state.showDock === 'auto'? 'show' : 'auto'
|
||||
}}
|
||||
class={clsx(
|
||||
'p-1 group-hover:block hidden rounded-lg cursor-pointer hover:bg-black/[.22] absolute bottom-0 -right-8'
|
||||
)}
|
||||
>
|
||||
<OhVueIcon
|
||||
name={
|
||||
setting.state.showDock === 'auto' ? HiSolidLockClosed.name : HiSolidLockOpen.name
|
||||
}
|
||||
fill="white"
|
||||
></OhVueIcon>
|
||||
</div>
|
||||
{layout.state.dockLabels.split('').map((l, i) => {
|
||||
const block = layout.state.dock[i]
|
||||
return (
|
||||
|
@ -54,8 +75,8 @@ export default defineComponent(() => {
|
|||
style={
|
||||
current.value >= 0
|
||||
? {
|
||||
transform: `translateY(${current.value === i - 1 || current.value === i + 1 ? '-5%' : current.value === i ? '-10%' : '0'}) scale(${current.value === i - 1 || current.value === i + 1 ? 1.1 : current.value === i ? 1.2 : 1})`
|
||||
}
|
||||
transform: `translateY(${current.value === i - 1 || current.value === i + 1 ? '-5%' : current.value === i ? '-10%' : '0'}) scale(${current.value === i - 1 || current.value === i + 1 ? 1.1 : current.value === i ? 1.2 : 1})`
|
||||
}
|
||||
: {}
|
||||
}
|
||||
id={block?.id || ''}
|
||||
|
@ -90,8 +111,8 @@ export default defineComponent(() => {
|
|||
{block && <LinkBlock block={block} dock />}
|
||||
{!setting.state.disabledShortcut && (
|
||||
<div
|
||||
class="absolute z-10 left-0 bottom-0 w-full bg-black/20 text-[12px] text-white text-center"
|
||||
style={{ boxShadow: block ? 'none' : '0 -4px 14px 0 rgba(0,0,0,.3)' }}
|
||||
class="absolute z-10 left-0 bottom-0 w-full bg-black/20 text-[12px] backdrop-blur-md text-white text-center"
|
||||
style={{ boxShadow: block ? 'none' : '0 -4px 14px 0 rgba(0,0,0,.4) ' }}
|
||||
>
|
||||
{l}
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
import SettingItem from '@/settings/SettingItem'
|
||||
import useSettingsStore from '@/settings/useSettingsStore'
|
||||
import { Radio, Switch } from 'ant-design-vue'
|
||||
import clsx from 'clsx'
|
||||
import { defineComponent, watch } from 'vue'
|
||||
import useLayoutStore from '../useLayoutStore'
|
||||
import { sendParent } from '@/utils/parent'
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const settings = useSettingsStore()
|
||||
const layout = useLayoutStore()
|
||||
watch(
|
||||
() => ({
|
||||
autoSearch: settings.state.autoUseAi === 'show',
|
||||
showTabButton: settings.state.showPetOnTab,
|
||||
isSearch: settings.state.autoUseAi === ''
|
||||
}),
|
||||
(val) => {
|
||||
sendParent([
|
||||
'configAI',
|
||||
{
|
||||
autoSearch: val.autoSearch,
|
||||
showTabButton: val.showTabButton,
|
||||
isSearch: val.isSearch
|
||||
}
|
||||
])
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
return () => (
|
||||
<div class="p-4 flex flex-col ">
|
||||
<div class={'flex flex-col'}>
|
||||
<span
|
||||
class={clsx(
|
||||
'text-[14px] font-bold',
|
||||
useLayoutStore().state.current === 0 ? 'text-white' : ' text-[#333]'
|
||||
)}
|
||||
>
|
||||
AI助手
|
||||
</span>
|
||||
<span class={'text-[13px] text-[#666] '}>设置AI助手样式</span>
|
||||
<div
|
||||
class={clsx(
|
||||
'w-full h-[1px] bg-black/10 mt-1 mb-2',
|
||||
useLayoutStore().state.current === 0 ? 'bg-white/10' : ' bg-black/10'
|
||||
)}
|
||||
></div>
|
||||
</div>
|
||||
<span
|
||||
class={clsx(
|
||||
'text-[14px] font-bold my-2',
|
||||
useLayoutStore().state.current === 0 ? 'text-white' : 'text-[#333]'
|
||||
)}
|
||||
>
|
||||
功能开关
|
||||
</span>
|
||||
<SettingItem
|
||||
v-slots={{
|
||||
label: () => <div>标签页助手</div>
|
||||
}}
|
||||
noRoundedB
|
||||
desc="fatfox标签页内的小助手"
|
||||
>
|
||||
<Switch
|
||||
checked={settings.state.showPet}
|
||||
onUpdate:checked={(e) => {
|
||||
if (e) settings.state.showPet = true
|
||||
else settings.state.showPet = false
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
<SettingItem
|
||||
v-slots={{
|
||||
label: () => <div>标签页助手</div>
|
||||
}}
|
||||
desc="fatfox标签页内的小助手"
|
||||
noRoundedT
|
||||
>
|
||||
<Switch
|
||||
checked={settings.state.showPetOnTab}
|
||||
onUpdate:checked={(e) => {
|
||||
if (e) settings.state.showPetOnTab = true
|
||||
else settings.state.showPetOnTab = false
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
<span
|
||||
class={clsx(
|
||||
'text-[14px] font-bold my-2',
|
||||
useLayoutStore().state.current === 0 ? 'text-white' : 'text-[#333]'
|
||||
)}
|
||||
>
|
||||
结果增强
|
||||
</span>
|
||||
<SettingItem
|
||||
v-slots={{
|
||||
label: () => <div>结果增强开关</div>
|
||||
}}
|
||||
desc="使用搜索引擎时,Fatfox会给您更多有效的结果"
|
||||
>
|
||||
<Switch
|
||||
checked={settings.state.autoUseAi !== ''}
|
||||
onUpdate:checked={(e) => {
|
||||
if (e) settings.state.autoUseAi = 'show'
|
||||
else settings.state.autoUseAi = ''
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
|
||||
<div
|
||||
class={clsx('flex w-full py-2 px-3 rounded-lg flex-col', {
|
||||
'bg-black/5': useLayoutStore().state.current !== 0,
|
||||
'bg-white/10': useLayoutStore().state.current === 0
|
||||
})}
|
||||
>
|
||||
<span>何时使用结果增强</span>
|
||||
<SettingItem
|
||||
v-slots={{
|
||||
label: () => <div>每次询问</div>
|
||||
}}
|
||||
noBg
|
||||
desc="每次搜索直接询问fatfox"
|
||||
>
|
||||
<Radio
|
||||
checked={settings.state.autoUseAi === 'show'}
|
||||
onClick={() => {
|
||||
settings.state.autoUseAi = 'show'
|
||||
}}
|
||||
onUpdate:checked={(e) => {
|
||||
if (e) settings.state.showSider = 'auto'
|
||||
else settings.state.showSider = 'show'
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
<SettingItem
|
||||
v-slots={{
|
||||
label: () => <div>手动询问</div>
|
||||
}}
|
||||
noBg
|
||||
desc="每次搜索,提示您进行手动查询"
|
||||
>
|
||||
<Radio
|
||||
checked={settings.state.autoUseAi === 'auto'}
|
||||
onClick={() => {
|
||||
settings.state.autoUseAi = 'auto'
|
||||
}}
|
||||
/>
|
||||
</SettingItem>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
|
@ -2,11 +2,30 @@ import SettingItem from '@/settings/SettingItem'
|
|||
import useSettingsStore from '@/settings/useSettingsStore'
|
||||
import { Slider, Switch } from 'ant-design-vue'
|
||||
import { defineComponent } from 'vue'
|
||||
import useLayoutStore from '../useLayoutStore'
|
||||
import clsx from 'clsx'
|
||||
|
||||
export default defineComponent(() => {
|
||||
const settings = useSettingsStore()
|
||||
return () => (
|
||||
<div class="p-4">
|
||||
<div class={'flex flex-col'}>
|
||||
<span
|
||||
class={clsx(
|
||||
'text-[14px] font-bold',
|
||||
useLayoutStore().state.current === 0 ? 'text-white' : ' text-[#333]'
|
||||
)}
|
||||
>
|
||||
图标
|
||||
</span>
|
||||
<span class={'text-[13px] text-[#666] '}>调整图标样式</span>
|
||||
<div
|
||||
class={clsx(
|
||||
'w-full h-[1px] bg-black/10 mt-1 mb-2',
|
||||
useLayoutStore().state.current === 0 ? 'bg-white/10' : ' bg-black/10'
|
||||
)}
|
||||
></div>
|
||||
</div>
|
||||
<SettingItem
|
||||
v-slots={{
|
||||
label: () => <div>图标显示名称</div>
|
||||
|
|
|
@ -39,8 +39,11 @@ export default defineComponent({
|
|||
style={{
|
||||
gridColumn: `span ${props.block.w}`,
|
||||
gridRow: `span ${props.block.h}`,
|
||||
transition: 'border .3s, transform .2s',
|
||||
border: hover.value ? '2px solid rgba(255,255,255,.5)' : '2px solid rgba(255,255,255,0)'
|
||||
transition: 'border .3s, transform .2s'
|
||||
// border: hover.value ? '2px solid rgba(255,255,255,.5)' : '2px solid rgba(255,255,255,0)'
|
||||
}}
|
||||
onDblclick={e=> {
|
||||
e.stopPropagation()
|
||||
}}
|
||||
data-transportable={props.block.link && !props.block.link.startsWith('id:') ? '1' : ''}
|
||||
onDragover={(e) => {
|
||||
|
@ -69,7 +72,7 @@ export default defineComponent({
|
|||
// 小组件无法合并
|
||||
if (!link) return
|
||||
//游戏不能合并
|
||||
if (props.block.w !== 1) return
|
||||
if (props.block.w === 2 && props.block.h === 1) return
|
||||
const oldIdx = layout.currentPage.list.findIndex((el) => el.id === dragging.id)
|
||||
if (oldIdx < 0) return
|
||||
const oldBlock = layout.currentPage.list[oldIdx]
|
||||
|
@ -79,7 +82,9 @@ export default defineComponent({
|
|||
if (!oldBlock || oldBlock.link.startsWith('id:')) return
|
||||
if (link.startsWith('id:')) {
|
||||
// 本身就是文件夹
|
||||
|
||||
const id = link.slice(3)
|
||||
|
||||
const dir = layout.state.dir[id]
|
||||
if (!dir) return
|
||||
dir.list.push(toRaw(oldBlock))
|
||||
|
@ -88,6 +93,7 @@ export default defineComponent({
|
|||
} else {
|
||||
// 本身不是文件夹
|
||||
const id = props.block.id
|
||||
|
||||
layout.state.dir[id] = {
|
||||
label: props.block.label,
|
||||
list: [toRaw(props.block), toRaw(oldBlock)]
|
||||
|
@ -163,7 +169,7 @@ export default defineComponent({
|
|||
{props.block.link ? (
|
||||
props.block.link.startsWith('id:') ? (
|
||||
// 文件夹
|
||||
<DirBlock block={props.block} big={props.block.w !== 1 || props.block.h !== 1} />
|
||||
<DirBlock block={props.block} big={props.block.w !== 1 || props.block.h !== 1} />
|
||||
) : (
|
||||
// 链接
|
||||
<LinkBlock block={props.block} />
|
||||
|
|
|
@ -32,8 +32,9 @@ export default defineComponent({
|
|||
const menu = useMenuStore()
|
||||
return () => (
|
||||
<div
|
||||
onClick={() => {
|
||||
onClick={(e) => {
|
||||
layout.openDir = props.block.link.slice(3)
|
||||
e.stopPropagation()
|
||||
}}
|
||||
class={clsx('w-full h-full bg-white/60 backdrop-blur grid', {
|
||||
'grid-rows-3 grid-cols-3 gap-[6%] p-[8%]': props.big,
|
||||
|
@ -46,8 +47,11 @@ export default defineComponent({
|
|||
{selectedDir.value.list
|
||||
.filter((_, idx) => idx < (props.big ? 9 : 4))
|
||||
.map((el) => (
|
||||
<div class="w-full h-full rounded-lg overflow-hidden">
|
||||
<LinkBlock block={el} brief />
|
||||
<div
|
||||
class="w-full h-full rounded-lg overflow-hidden"
|
||||
|
||||
>
|
||||
<LinkBlock block={el} brief disable={true} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
@ -3,9 +3,17 @@ import useLayoutStore from '../useLayoutStore'
|
|||
import useSortable from './useSortable'
|
||||
import LinkBlock from './LinkBlock'
|
||||
import type { Block } from '../layout.types'
|
||||
import useRouterStore from '@/useRouterStore'
|
||||
import { globalToast } from '@/main'
|
||||
import { addIcons, OhVueIcon } from 'oh-vue-icons'
|
||||
import { MdAdd } from 'oh-vue-icons/icons'
|
||||
import useAdderPageStore from '../adder/useAdderPageStore'
|
||||
addIcons(MdAdd)
|
||||
|
||||
export default defineComponent(() => {
|
||||
const layout = useLayoutStore()
|
||||
const router = useRouterStore()
|
||||
const addStore = useAdderPageStore()
|
||||
const dir = ref({ label: '', list: [] as Block[] })
|
||||
// 因为有拖拽,关闭弹框不能使内容消失
|
||||
watch(
|
||||
|
@ -18,16 +26,18 @@ export default defineComponent(() => {
|
|||
computed(() => dir.value.list),
|
||||
computed(() => layout.openDir)
|
||||
)
|
||||
|
||||
return () => (
|
||||
<Transition>
|
||||
<div
|
||||
class="fixed w-full h-screen left-0 top-0 flex flex-col justify-center items-center"
|
||||
v-show={layout.openDir}
|
||||
style="z-index: 300"
|
||||
style="z-index: 20"
|
||||
>
|
||||
<div
|
||||
class="absolute left-0 top-0 w-full h-full bg-black/40 backdrop-blur"
|
||||
onClick={() => {
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
layout.openDir = ''
|
||||
}}
|
||||
onDragenter={() => {
|
||||
|
@ -63,14 +73,33 @@ export default defineComponent(() => {
|
|||
style={{
|
||||
borderRadius: `calc(var(--block-radius) * var(--block-size))`
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
}}
|
||||
>
|
||||
<LinkBlock block={block} key={block.id} />
|
||||
<LinkBlock
|
||||
block={block}
|
||||
key={block.id}
|
||||
|
||||
/>
|
||||
</div>
|
||||
<div class="absolute left-0 -bottom-2 text-sm text-black/60 text-center w-full overflow-hidden text-ellipsis whitespace-nowrap break-all">
|
||||
{block.label}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<div class="w-full h-full flex justify-center items-center p-[var(--block-padding)] relative operation-button">
|
||||
<div
|
||||
class="w-full h-full overflow-hidden rounded-[calc(var(--block-radius)_*_var(--block-size))] bg-white/60 backdrop-blur flex justify-center items-center cursor-pointer hover:scale-105 transition-all"
|
||||
onClick={() => {
|
||||
router.go('global-adder')
|
||||
}}
|
||||
>
|
||||
<span style="filter:drop-shadow(0 0 10px hsl(32, 90%, 65%))">
|
||||
<OhVueIcon name="md-add" fill="white" scale={2.4} />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -33,6 +33,23 @@ export default defineComponent({
|
|||
})
|
||||
return () => (
|
||||
<div class="p-4 flex flex-col gap-y-1 ">
|
||||
<div class={'flex flex-col'}>
|
||||
<span
|
||||
class={clsx(
|
||||
'text-[14px] font-bold',
|
||||
useLayoutStore().state.current === 0 ? 'text-white' : ' text-[#333]'
|
||||
)}
|
||||
>
|
||||
快捷栏
|
||||
</span>
|
||||
<span class={'text-[13px] text-[#666] '}>调整快捷栏功能</span>
|
||||
<div
|
||||
class={clsx(
|
||||
'w-full h-[1px] bg-black/10 mt-1 mb-2',
|
||||
useLayoutStore().state.current === 0 ? 'bg-white/10' : ' bg-black/10'
|
||||
)}
|
||||
></div>
|
||||
</div>
|
||||
<SettingItem
|
||||
v-slots={{
|
||||
label: () => <div>快捷栏开关</div>
|
||||
|
|
|
@ -7,6 +7,7 @@ import { addIcons, OhVueIcon } from 'oh-vue-icons'
|
|||
import { message, Modal, Table } from 'ant-design-vue'
|
||||
import request from '@/utils/request'
|
||||
import db from '@/db'
|
||||
import clsx from 'clsx'
|
||||
|
||||
addIcons(MdInbox)
|
||||
export interface Feedback {
|
||||
|
@ -40,22 +41,32 @@ export default defineComponent(() => {
|
|||
get: () => data.images[2],
|
||||
set: (val) => (data.images[2] = val)
|
||||
})
|
||||
const list = [img1, img2, img3]
|
||||
return () => (
|
||||
<div class={'p-4 ' + (isGame.value ? 'text-white' : 'text-black/60')}>
|
||||
<div class="flex justify-between items-center">
|
||||
<div>
|
||||
<span class="text-red-500">*</span>
|
||||
问题描述
|
||||
<div class="flex justify-between items-start">
|
||||
<div class={'flex flex-col'}>
|
||||
<span
|
||||
class={clsx(
|
||||
'text-[14px] font-bold',
|
||||
useLayoutStore().state.current === 0 ? 'text-white' : ' text-[#333]'
|
||||
)}
|
||||
>
|
||||
侧边栏
|
||||
</span>
|
||||
<span class={'text-[13px] text-[#666] '}>调整侧边栏布局</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="cursor-pointer"
|
||||
class="cursor-pointer text-[14px]"
|
||||
onClick={async () => {
|
||||
let his = await db.getItem<Feedback[]>('feedbacks')
|
||||
if (!his) his = []
|
||||
const ins = Modal.info({
|
||||
const ins = Modal.warn({
|
||||
title: '历史反馈',
|
||||
width: '1024px',
|
||||
maskClosable: true,
|
||||
okText: '关闭',
|
||||
content: () => (
|
||||
<Table
|
||||
class="max-h-[50vh] overflow-y-auto"
|
||||
|
@ -70,7 +81,9 @@ export default defineComponent(() => {
|
|||
{
|
||||
title: '问题描述',
|
||||
customRender: ({ record }) => (
|
||||
<div class="w-[200px] break-all">{record.description}</div>
|
||||
<div class="w-[200px] break-all overflow-hidden text-ellipsis whitespace-nowrap" title={record.description}>
|
||||
{record.description}
|
||||
</div>
|
||||
)
|
||||
},
|
||||
{
|
||||
|
@ -95,7 +108,6 @@ export default defineComponent(() => {
|
|||
></Table>
|
||||
),
|
||||
onOk() {
|
||||
console.log('OK')
|
||||
ins.destroy()
|
||||
},
|
||||
onCancel() {
|
||||
|
@ -111,19 +123,46 @@ export default defineComponent(() => {
|
|||
历史反馈
|
||||
</div>
|
||||
</div>
|
||||
<div class={'mt-2 ' + (isGame.value ? 'bg-white/10 text-white' : 'bg-black/5 text-black/60')}>
|
||||
<div
|
||||
class={clsx(
|
||||
'w-full h-[1px] bg-black/10 mt-1 mb-2',
|
||||
useLayoutStore().state.current === 0 ? 'bg-white/10' : ' bg-black/10'
|
||||
)}
|
||||
></div>
|
||||
<div>
|
||||
<span class="text-red-500 ">*</span>
|
||||
问题描述
|
||||
</div>
|
||||
<div
|
||||
class={
|
||||
'mt-2 relative appearance-none rounded-lg h-[124px] ' +
|
||||
(isGame.value ? 'bg-white/10 text-white' : 'bg-black/5 text-black/60')
|
||||
}
|
||||
>
|
||||
<textarea
|
||||
placeholder="在此输入您的问题,并可以添加图片,方便更清晰的描述问题,我们会尽快帮您解决,感谢您的反馈"
|
||||
maxlength={80}
|
||||
v-model={data.description}
|
||||
class="bg-transparent no-textarea w-full p-2"
|
||||
class="bg-transparent no-textarea w-full p-2 appearance-none resize-none placeholder:text-[14px] "
|
||||
style={{
|
||||
color: isGame.value ? 'white' : 'black'
|
||||
}}
|
||||
/>
|
||||
<div class="p-2 flex gap-2">
|
||||
<ImageUploader width={42} v-model:value={img1.value} />
|
||||
<ImageUploader width={42} v-model:value={img2.value} />
|
||||
<ImageUploader width={42} v-model:value={img3.value} />
|
||||
{list
|
||||
.filter(
|
||||
(_, idx) =>
|
||||
idx <=
|
||||
list.reduce((acc, cur) => {
|
||||
if (cur.value) acc++
|
||||
return acc
|
||||
}, 0)
|
||||
)
|
||||
.map((item) => (
|
||||
<ImageUploader width={38} v-model:value={item.value} />
|
||||
))}
|
||||
</div>
|
||||
<span class={'absolute right-2 bottom-2'}>{data.description.length}/80</span>
|
||||
</div>
|
||||
<div class="mt-4">联系方式</div>
|
||||
<div class="text-sm">留下您的联系方式,以便必要时我们可以联系到您</div>
|
||||
|
@ -131,9 +170,11 @@ export default defineComponent(() => {
|
|||
<input
|
||||
v-model={data.qq}
|
||||
placeholder="QQ号"
|
||||
maxlength={15}
|
||||
class={'p-2 rounded-lg ' + (isGame.value ? 'bg-white/10' : 'bg-black/5')}
|
||||
/>
|
||||
<input
|
||||
maxlength={12}
|
||||
v-model={data.phone}
|
||||
placeholder="手机号"
|
||||
class={'p-2 rounded-lg ' + (isGame.value ? 'bg-white/10' : 'bg-black/5')}
|
||||
|
@ -151,13 +192,16 @@ export default defineComponent(() => {
|
|||
await request('POST', '/api/feedback', {
|
||||
data: {
|
||||
content: data.description,
|
||||
qq: data.qq,
|
||||
email: data.qq,
|
||||
phone: data.phone,
|
||||
imgs: data.images
|
||||
},
|
||||
returnType: 'text'
|
||||
})
|
||||
message.success('提交成功')
|
||||
list.forEach((item) => {
|
||||
item.value = ''
|
||||
})
|
||||
Object.assign(data, { ...defaultData })
|
||||
}}
|
||||
class="mt-4 text-center rounded py-1 cursor-pointer bg-[#ffa93d] text-white"
|
||||
|
|
|
@ -16,6 +16,10 @@ export default defineComponent({
|
|||
dock: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
disable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
|
@ -25,19 +29,22 @@ export default defineComponent({
|
|||
<div
|
||||
class="w-full h-full flex justify-center items-center font-bold bg-cover bg-center bg-no-repeat"
|
||||
onContextmenu={() => {
|
||||
if (props.disable) return
|
||||
menu.open(props.block)
|
||||
}}
|
||||
onClick={() => {
|
||||
if (props.disable) return
|
||||
|
||||
jump(props.block.link)
|
||||
}}
|
||||
style={{
|
||||
backgroundColor: props.block.text ? props.block.background || 'white' : 'transparent',
|
||||
backgroundColor: !props.block.icon ? props.block.background || 'white' : 'transparent',
|
||||
color: props.block.color || 'black',
|
||||
backgroundImage: props.block.icon ? `url('${props.block.icon}')` : '',
|
||||
fontSize: props.dock ? '16px' : props.brief ? '12px' : 'calc(var(--block-size) / 5)'
|
||||
}}
|
||||
>
|
||||
<div>{props.brief ? props.block.text[0] : props.block.text}</div>
|
||||
{!props.block.icon && <div>{props.brief ? props.block.text[0] : props.block.text}</div>}
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
import useUserStore from '@/user/useUserStore'
|
||||
import useRouterStore from '@/useRouterStore'
|
||||
import { defineComponent } from 'vue'
|
||||
import HeaderSetting from '../header/headerSetting'
|
||||
|
||||
export default defineComponent(() => {
|
||||
const router = useRouterStore()
|
||||
const user = useUserStore()
|
||||
return () => <>{router.path === 'custom-header' ? <HeaderSetting></HeaderSetting> : null}</>
|
||||
})
|
|
@ -3,6 +3,9 @@ import { Button } from 'ant-design-vue'
|
|||
import clsx from 'clsx'
|
||||
import { computed, defineComponent, ref } from 'vue'
|
||||
import useLayoutStore from '../useLayoutStore'
|
||||
import useUserStore from '@/user/useUserStore'
|
||||
import useTomatoStore from '@/widgets/work/useTomatoStore'
|
||||
import useNotepadStore from '@/widgets/notepad/useNotepadStore'
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
|
@ -13,51 +16,101 @@ export default defineComponent({
|
|||
})
|
||||
return () => (
|
||||
<div class="p-4 flex flex-col ">
|
||||
<div class={'flex flex-col'}>
|
||||
<span
|
||||
class={clsx(
|
||||
'text-[14px] font-bold',
|
||||
useLayoutStore().state.current === 0 ? 'text-white' : ' text-[#333]'
|
||||
)}
|
||||
>
|
||||
重置
|
||||
</span>
|
||||
<span class={'text-[13px] text-[#666] '}>恢复默认设置</span>
|
||||
<div
|
||||
class={clsx(
|
||||
'w-full h-[1px] bg-black/10 mt-1 mb-2',
|
||||
useLayoutStore().state.current === 0 ? 'bg-white/10' : ' bg-black/10'
|
||||
)}
|
||||
></div>
|
||||
</div>
|
||||
<SettingItem
|
||||
v-slots={{
|
||||
label: () => <div >重置</div>
|
||||
label: () => <div>重置</div>
|
||||
}}
|
||||
>
|
||||
<Button type="primary" onClick={() => {
|
||||
open.value = true
|
||||
}}>立即重置</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
open.value = true
|
||||
}}
|
||||
>
|
||||
立即重置
|
||||
</Button>
|
||||
</SettingItem>
|
||||
<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"}>
|
||||
{open.value && (
|
||||
<div
|
||||
class={clsx(
|
||||
'w-[300px] h-[210px] absolute top-0 rounded-2xl right-[-310px] z-10 ',
|
||||
isGame.value ? 'bg-[#2c2e3e]' : 'bg-white'
|
||||
)}
|
||||
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]' : 'text-[#666]'
|
||||
)}
|
||||
>
|
||||
此操作会将您的历史调整的数据清空,为防止您的误操作,请再次确认是否要进行重置
|
||||
</span>
|
||||
<div class={'flex justify-between w-full'}>
|
||||
<button
|
||||
onClick={() => {
|
||||
layout.resetAll()
|
||||
|
||||
useUserStore().logout()
|
||||
useTomatoStore().reset()
|
||||
useNotepadStore().reset()
|
||||
open.value = false
|
||||
}}
|
||||
class={clsx("w-[118px] rounded-lg py-1 flex justify-center", isGame.value ? "bg-white/20" : "")}>重置</button>
|
||||
class={clsx(
|
||||
'w-[118px] rounded-lg py-1 flex justify-center',
|
||||
isGame.value ? 'bg-white/20' : 'bg-black/20 text-white'
|
||||
)}
|
||||
>
|
||||
重置
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
open.value = false
|
||||
|
||||
}}
|
||||
class={clsx("w-[118px] rounded-lg py-1 flex justify-center", isGame.value ? "bg-[#ff7372]" : "")}>取消</button>
|
||||
|
||||
class={clsx(
|
||||
'w-[118px] rounded-lg py-1 flex justify-center ',
|
||||
isGame.value ? 'bg-[#ff7372]' : 'bg-[#ff7372] text-white'
|
||||
)}
|
||||
>
|
||||
取消
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
</div >
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -3,6 +3,8 @@ import useSettingsStore from '@/settings/useSettingsStore'
|
|||
import { Select, Slider, Switch, type SelectProps } from 'ant-design-vue'
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import useSearchConfigStore from '../header/search/useSearchConfigStore'
|
||||
import clsx from 'clsx'
|
||||
import useLayoutStore from '../useLayoutStore'
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
|
@ -16,6 +18,23 @@ export default defineComponent({
|
|||
)
|
||||
return () => (
|
||||
<div class="p-4">
|
||||
<div class={'flex flex-col'}>
|
||||
<span
|
||||
class={clsx(
|
||||
'text-[14px] font-bold',
|
||||
useLayoutStore().state.current === 0 ? 'text-white' : ' text-[#333]'
|
||||
)}
|
||||
>
|
||||
搜索
|
||||
</span>
|
||||
<span class={'text-[13px] text-[#666] '}>调整搜索样式</span>
|
||||
<div
|
||||
class={clsx(
|
||||
'w-full h-[1px] bg-black/10 mt-1 mb-2',
|
||||
useLayoutStore().state.current === 0 ? 'bg-white/10' : ' bg-black/10'
|
||||
)}
|
||||
></div>
|
||||
</div>
|
||||
<SettingItem
|
||||
noRoundedB
|
||||
v-slots={{
|
||||
|
|
|
@ -11,6 +11,23 @@ export default defineComponent({
|
|||
const layout = useLayoutStore()
|
||||
return () => (
|
||||
<div class="p-4 flex flex-col gap-y-4 ">
|
||||
<div class={'flex flex-col'}>
|
||||
<span
|
||||
class={clsx(
|
||||
'text-[14px] font-bold',
|
||||
useLayoutStore().state.current === 0 ? 'text-white' : ' text-[#333]'
|
||||
)}
|
||||
>
|
||||
侧边栏
|
||||
</span>
|
||||
<span class={'text-[13px] text-[#666] '}>调整侧边栏布局</span>
|
||||
<div
|
||||
class={clsx(
|
||||
'w-full h-[1px] bg-black/10 mt-1 mb-2',
|
||||
useLayoutStore().state.current === 0 ? 'bg-white/10' : ' bg-black/10'
|
||||
)}
|
||||
></div>
|
||||
</div>
|
||||
<div
|
||||
class={'p-5 bg-[#000000]/[.05] rounded-lg w-full grid grid-rows-1 grid-cols-2 gap-x-3'}
|
||||
>
|
||||
|
|
|
@ -4,6 +4,7 @@ import { Select, Slider, Switch, type SelectProps } from 'ant-design-vue'
|
|||
import { defineComponent, ref } from 'vue'
|
||||
import useSearchConfigStore from '../header/search/useSearchConfigStore'
|
||||
import clsx from 'clsx'
|
||||
import useLayoutStore from '../useLayoutStore'
|
||||
const list: {
|
||||
label: string
|
||||
value: TimeUnit
|
||||
|
@ -41,6 +42,23 @@ export default defineComponent({
|
|||
)
|
||||
return () => (
|
||||
<div class="p-4">
|
||||
<div class={'flex flex-col'}>
|
||||
<span
|
||||
class={clsx(
|
||||
'text-[14px] font-bold',
|
||||
useLayoutStore().state.current === 0 ? 'text-white' : ' text-[#333]'
|
||||
)}
|
||||
>
|
||||
时间
|
||||
</span>
|
||||
<span class={'text-[13px] text-[#666] '}>调整时间样式</span>
|
||||
<div
|
||||
class={clsx(
|
||||
'w-full h-[1px] bg-black/10 mt-1 mb-2',
|
||||
useLayoutStore().state.current === 0 ? 'bg-white/10' : ' bg-black/10'
|
||||
)}
|
||||
></div>
|
||||
</div>
|
||||
<SettingItem
|
||||
v-slots={{
|
||||
label: () => <div>显示时间</div>
|
||||
|
|
|
@ -1,33 +1,39 @@
|
|||
import { computed, defineComponent, onMounted, ref, Transition } from 'vue'
|
||||
import { computed, defineComponent, onMounted, onUnmounted, ref, Transition } from 'vue'
|
||||
import WelcomeImg from '~/icons/welcome/welcomeTitle.png'
|
||||
import DivBgImg from '~/icons/welcome/back.png'
|
||||
import startUseImg from '~/icons/welcome/startUse.png'
|
||||
import LeftImg from '~/icons/welcome/welcomeLeft.png'
|
||||
import RightImg from '~/icons/welcome/welcomeRight.png'
|
||||
import useLayoutStore from '../useLayoutStore'
|
||||
import request from '@/utils/request'
|
||||
import useStatisticStore from '@/utils/useStatisticStore'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
import { uploadLocal } from '@/utils/upload'
|
||||
import { videoArr } from '@/config'
|
||||
import clsx from 'clsx'
|
||||
export const DefaultPageSetting = [
|
||||
{
|
||||
name: '游戏',
|
||||
backgroundUrl:
|
||||
'https://newfatfox.oss-cn-beijing.aliyuncs.com/000/user_upload/1/resource/831a4d4c-61ff-4bae-ad31-9c0f4fa2db1c.webp',
|
||||
'https://oss.goosetab.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',
|
||||
'https://oss.goosetab.com/000/user_upload/1/resource/b2f3ed2f-f550-499b-8ea1-dfd192cfd388.webp',
|
||||
desct: '聚合多类游戏工具,以及 资讯、排行榜等'
|
||||
},
|
||||
{
|
||||
name: '工作台',
|
||||
name: '工作',
|
||||
backgroundUrl:
|
||||
'https://newfatfox.oss-cn-beijing.aliyuncs.com/000/user_upload/1/resource/b82fd47c-24c1-4f58-b0db-51414b3bdda4.webp',
|
||||
'https://oss.goosetab.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: '结合番茄计时法等效率工具,让您可以高效学'
|
||||
'https://oss.goosetab.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',
|
||||
'https://oss.goosetab.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',
|
||||
'https://oss.goosetab.com/000/user_upload/1/resource/bcbbffc6-c8a4-4c8e-8ba5-36fa1fbad4f9.webp',
|
||||
desct: '综合办公、学习、游戏等 属性,功能较为均勺'
|
||||
}
|
||||
]
|
||||
|
@ -37,6 +43,25 @@ export default defineComponent(() => {
|
|||
const layout = useLayoutStore()
|
||||
|
||||
const isFirst = ref(false)
|
||||
// 创建一个响应式变量来存储屏幕宽度
|
||||
const width = ref(window.innerWidth)
|
||||
|
||||
const updateWidth = () => {
|
||||
width.value = window.innerWidth
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 监听窗口大小变化
|
||||
window.addEventListener('resize', updateWidth)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
// 组件卸载时移除事件监听器
|
||||
window.removeEventListener('resize', updateWidth)
|
||||
})
|
||||
const isBig = computed(() => {
|
||||
return width.value > 1700
|
||||
})
|
||||
onMounted(() => {
|
||||
// 检查 localStorage 是否已经有访问记录
|
||||
const visited = localStorage.getItem('hasVisited')
|
||||
|
@ -47,7 +72,7 @@ export default defineComponent(() => {
|
|||
useStatisticStore().send({
|
||||
widget: 'WELCOME',
|
||||
action: 'OPEN',
|
||||
space: 'TAB',
|
||||
space: 'TAB'
|
||||
})
|
||||
}
|
||||
})
|
||||
|
@ -57,8 +82,8 @@ export default defineComponent(() => {
|
|||
<Transition>
|
||||
{show.value && (
|
||||
<div
|
||||
class="w-full h-screen bg-black/60 "
|
||||
onClick={() => { }}
|
||||
class="w-full h-screen bg-white "
|
||||
onClick={() => {}}
|
||||
style={{
|
||||
backgroundImage: `url('${DefaultPageSetting[selectMode.value].backgroundUrl}')`,
|
||||
backgroundSize: '100% 100%',
|
||||
|
@ -66,7 +91,7 @@ export default defineComponent(() => {
|
|||
backgroundRepeat: 'no-repeat'
|
||||
}}
|
||||
>
|
||||
<div class="w-full h-screen bg-black/60 " onClick={() => { }}></div>
|
||||
<div class="w-full h-screen bg-black/60 " onClick={() => {}}></div>
|
||||
</div>
|
||||
)}
|
||||
</Transition>
|
||||
|
@ -83,24 +108,39 @@ export default defineComponent(() => {
|
|||
>
|
||||
<span class={'leading-[20px] -mt-2 text-[20px] text-white '}>请选择您的初始模式</span>
|
||||
</div>
|
||||
<div class={'w-full h-[370px] flex justify-center'}>
|
||||
<div
|
||||
class={'w-full flex justify-center'}
|
||||
style={
|
||||
isBig.value
|
||||
? {
|
||||
width: 844 + 'px',
|
||||
height: 433 + 'px'
|
||||
}
|
||||
: {
|
||||
width: 709 + 'px',
|
||||
height: 370 + 'px'
|
||||
}
|
||||
}
|
||||
>
|
||||
<div class={'w-[868px] h-[370px] '}>
|
||||
<div class={'relative w-full h-full flex justify-center'}>
|
||||
{DefaultPageSetting.map((item, idx) => (
|
||||
<div
|
||||
class={
|
||||
' w-[709px] h-[370px] cursor-pointer duration-150 absolute top-0 left-0 bg-[#2c2e3e] p-3 overflow-hidden rounded-2xl'
|
||||
' cursor-pointer duration-150 absolute top-0 left-0 bg-[#2c2e3e] p-3 rounded-2xl'
|
||||
}
|
||||
onClick={() => {
|
||||
selectMode.value = idx
|
||||
|
||||
}}
|
||||
style={{
|
||||
transform: `translate(${idx === selectMode.value ? 80 : (((selectMode.value === 2 && idx === 0) || (selectMode.value + 1 === idx)) ? 219 : -52)}px) scale(${idx === selectMode.value ? 1 : 0.85
|
||||
})`,
|
||||
transform: `translate(${idx === selectMode.value ? (isBig.value ? 0 : 0) : (selectMode.value === 2 && idx === 0) || selectMode.value + 1 === idx ? (isBig.value ? 460 : 152) : isBig.value ? -382 : -152}px) scale(${
|
||||
idx === selectMode.value ? 1 : 0.85
|
||||
})`,
|
||||
backgroundImage: `url('${DivBgImg}')`,
|
||||
backgroundSize: '100% 100%',
|
||||
zIndex: selectMode.value === idx ? 10 : 0
|
||||
zIndex: selectMode.value === idx ? 10 : 0,
|
||||
width: (isBig.value ? 844 : 709) + 'px',
|
||||
height: (isBig.value ? 433 : 370) + 'px'
|
||||
}}
|
||||
>
|
||||
<div
|
||||
|
@ -112,6 +152,17 @@ export default defineComponent(() => {
|
|||
backgroundRepeat: 'no-repeat'
|
||||
}}
|
||||
></div>
|
||||
{selectMode.value !== idx ? (
|
||||
(selectMode.value === 2 && idx === 0) || selectMode.value + 1 === idx ? (
|
||||
<div class={'right-[-100px] absolute top-1/2 -translate-y-1/2'}>
|
||||
<img src={RightImg} class={'w-[40px]'} alt="" />
|
||||
</div>
|
||||
) : (
|
||||
<div class={'left-[-100px] absolute top-1/2 -translate-y-1/2'}>
|
||||
<img src={LeftImg} class={'w-[40px]'} alt="" />
|
||||
</div>
|
||||
)
|
||||
) : null}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
@ -122,9 +173,10 @@ export default defineComponent(() => {
|
|||
<span class={'w-[180px]'}>{DefaultPageSetting[selectMode.value].desct}</span>
|
||||
</div>
|
||||
<div
|
||||
class={
|
||||
'w-[175px] h-[41px] mt-4 flex items-center justify-center text-[#333] cursor-pointer'
|
||||
}
|
||||
class={clsx(
|
||||
' mt-4 flex items-center justify-center text-[#333] cursor-pointer',
|
||||
isBig.value ? 'w-[300px] h-[66px] text-[22px]' : 'w-[175px] h-[41px] text-[16px]'
|
||||
)}
|
||||
onClick={() => {
|
||||
localStorage.setItem('hasVisited', 'true')
|
||||
isFirst.value = false
|
||||
|
@ -135,13 +187,32 @@ export default defineComponent(() => {
|
|||
if (!res) return
|
||||
layout.state.dir = res.dir
|
||||
layout.state.content = res.content
|
||||
layout.state.content.forEach(async (val) => {
|
||||
const res = await fetch(val.background).then((res) => res.blob())
|
||||
|
||||
if (res) {
|
||||
const affix = val.background.split('.').pop()
|
||||
if (!affix) return
|
||||
const file = new File([res], `${uuid()}.${affix}`, {
|
||||
type: `${res.type}`
|
||||
})
|
||||
uploadLocal(file).then((res2) => {
|
||||
val.background = res2
|
||||
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
layout.state.current = selectMode.value as 0 | 1 | 2
|
||||
useStatisticStore().send({
|
||||
widget: selectMode.value === 0 ? "WELCOME_GAME" : selectMode.value === 1 ? "WELCOME_WORK" : "WELCOME_RELAX",
|
||||
widget:
|
||||
selectMode.value === 0
|
||||
? 'WELCOME_GAME'
|
||||
: selectMode.value === 1
|
||||
? 'WELCOME_WORK'
|
||||
: 'WELCOME_RELAX',
|
||||
action: 'CLICK',
|
||||
space: 'TAB',
|
||||
space: 'TAB'
|
||||
})
|
||||
}}
|
||||
style={{
|
||||
|
|
|
@ -51,6 +51,10 @@ export default defineComponent(() => {
|
|||
layout.isCompact = false
|
||||
}
|
||||
}}
|
||||
onDblclick={(e) => {
|
||||
e.stopPropagation()
|
||||
layout.state.simple = !layout.state.simple
|
||||
}}
|
||||
onDragover={(e) => e.preventDefault()}
|
||||
onDrop={() => {
|
||||
// 处理移入
|
||||
|
@ -69,6 +73,7 @@ export default defineComponent(() => {
|
|||
const idx = list.findIndex((el) => el.id === dragging.id)
|
||||
if (idx < 0) return
|
||||
const block = list[idx]
|
||||
|
||||
layout.currentPage.list.push(toRaw(block))
|
||||
list.splice(idx, 1)
|
||||
layout.checkDir(dragging.type)
|
||||
|
|
|
@ -32,7 +32,7 @@ export default function useSortable(list: Ref<any[]>, type: Ref<string>) {
|
|||
filter: '.operation-button'
|
||||
}
|
||||
: {}),
|
||||
ghostClass: 'opacity-20',
|
||||
ghostClass: 'opacity-0',
|
||||
onStart: (e: any) => {
|
||||
dragging.type = type.value
|
||||
dragging.id = e.item.id || ''
|
||||
|
|
|
@ -3,6 +3,7 @@ import useTimeStore from '@/utils/useTimeStore'
|
|||
import { Lunar } from 'lunar-typescript'
|
||||
import { computed, defineComponent, Transition } from 'vue'
|
||||
import useLayoutStore from '../useLayoutStore'
|
||||
import clsx from 'clsx'
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
|
@ -39,78 +40,102 @@ export default defineComponent({
|
|||
const layout = useLayoutStore()
|
||||
return () => (
|
||||
<div
|
||||
class="absolute z-20 shadow-text tracking-widest font-normal h-[110px] transition-all "
|
||||
class={clsx(
|
||||
'absolute z-20 shadow-text tracking-widest font-normal transition-all ',
|
||||
layout.isCompact && !layout.state.simple
|
||||
? 'text-[13px] flex z-20 items-center pointer-events-none gap-x-2'
|
||||
: 'h-[110px]'
|
||||
)}
|
||||
onDblclick={(e) => {
|
||||
e.stopPropagation()
|
||||
layout.state.simple = !layout.state.simple
|
||||
}}
|
||||
style={{
|
||||
color: 'white',
|
||||
transitionDuration: '.4s',
|
||||
left: layout.isCompact ? '20px' : '50%',
|
||||
top: layout.isCompact ? '20px' : layout.state.simple ? '100px' : '50px',
|
||||
transform: layout.isCompact ? '' : 'translate(-50%,0)'
|
||||
left: layout.isCompact && !layout.state.simple ? '20px' : '50%',
|
||||
top:
|
||||
layout.isCompact && !layout.state.simple
|
||||
? '20px'
|
||||
: layout.state.simple
|
||||
? '100px'
|
||||
: '50px',
|
||||
transform: layout.isCompact && !layout.state.simple ? '' : 'translate(-50%,0)'
|
||||
}}
|
||||
>
|
||||
<Transition>
|
||||
|
||||
{
|
||||
layout.state.simple ?
|
||||
settings.state.simpleModeShowString.includes('showTime') &&
|
||||
<div
|
||||
class={
|
||||
'transition-all ' +
|
||||
(layout.isCompact ? 'text-[1.4rem] leading-[1.4rem]' : 'text-[8vh] leading-[4rem]')
|
||||
}
|
||||
>
|
||||
{text.value.timeStr}
|
||||
</div>
|
||||
:
|
||||
settings.state!.showTime &&
|
||||
<div
|
||||
class={
|
||||
'transition-all ' +
|
||||
(layout.isCompact ? 'text-[1.4rem] leading-[1.4rem]' : 'text-[8vh] leading-[4rem]')
|
||||
}
|
||||
>
|
||||
{text.value.timeStr}
|
||||
</div>
|
||||
}
|
||||
{layout.state.simple
|
||||
? settings.state.simpleModeShowString.includes('showTime') && (
|
||||
<div
|
||||
class={
|
||||
'transition-all ' +
|
||||
(layout.isCompact && !layout.state.simple
|
||||
? 'text-[1.2rem] leading-[1.4rem]'
|
||||
: 'text-[8vh] leading-[4rem]')
|
||||
}
|
||||
>
|
||||
{text.value.timeStr}
|
||||
</div>
|
||||
)
|
||||
: settings.state!.showTime && (
|
||||
<div
|
||||
class={
|
||||
'transition-all ' +
|
||||
(layout.isCompact && !layout.state.simple
|
||||
? 'text-[1.2rem] leading-[1.4rem]'
|
||||
: 'text-[8vh] leading-[4rem]')
|
||||
}
|
||||
>
|
||||
{text.value.timeStr}
|
||||
</div>
|
||||
)}
|
||||
</Transition>
|
||||
<Transition>
|
||||
{
|
||||
layout.state.simple ?
|
||||
settings.state.simpleModeShowString.includes('showDate') &&
|
||||
<div
|
||||
class={'flex items-center gap-4 mt-4 ' + (layout.isCompact ? '' : 'justify-center')}
|
||||
>
|
||||
{settings.state.timeOptions.includes('date') && <div>{text.value.dateStr}</div>}
|
||||
<Transition>
|
||||
{!layout.isCompact && settings.state.timeOptions.includes('week') && (
|
||||
<div>星期{info.value.dayWeek}</div>
|
||||
)}
|
||||
</Transition>
|
||||
<Transition>
|
||||
{!layout.isCompact && settings.state.timeOptions.includes('lunal') && (
|
||||
<div>{info.value.day}</div>
|
||||
)}
|
||||
</Transition>
|
||||
</div>
|
||||
:
|
||||
settings.state!.showTime &&
|
||||
<div
|
||||
class={'flex items-center gap-4 mt-4 ' + (layout.isCompact ? '' : 'justify-center')}
|
||||
>
|
||||
{settings.state.timeOptions.includes('date') && <div>{text.value.dateStr}</div>}
|
||||
<Transition>
|
||||
{!layout.isCompact && settings.state.timeOptions.includes('week') && (
|
||||
<div>星期{info.value.dayWeek}</div>
|
||||
)}
|
||||
</Transition>
|
||||
<Transition>
|
||||
{!layout.isCompact && settings.state.timeOptions.includes('lunal') && (
|
||||
<div>{info.value.day}</div>
|
||||
)}
|
||||
</Transition>
|
||||
</div>
|
||||
}
|
||||
|
||||
{layout.state.simple
|
||||
? settings.state.simpleModeShowString.includes('showDate') && (
|
||||
<div
|
||||
class={
|
||||
'flex items-center gap-4 ' +
|
||||
(layout.isCompact && !layout.state.simple
|
||||
? 'text-[1.2rem]'
|
||||
: 'justify-center mt-4')
|
||||
}
|
||||
>
|
||||
{settings.state.timeOptions.includes('date') && <div>{text.value.dateStr}</div>}
|
||||
<Transition>
|
||||
{!(layout.isCompact && !layout.state.simple) &&
|
||||
settings.state.timeOptions.includes('week') && (
|
||||
<div>星期{info.value.dayWeek}</div>
|
||||
)}
|
||||
</Transition>
|
||||
<Transition>
|
||||
{!(layout.isCompact && !layout.state.simple) &&
|
||||
settings.state.timeOptions.includes('lunal') && <div>{info.value.day}</div>}
|
||||
</Transition>
|
||||
</div>
|
||||
)
|
||||
: settings.state!.showTime && (
|
||||
<div
|
||||
class={
|
||||
'flex items-center gap-4 ' +
|
||||
(layout.isCompact && !layout.state.simple
|
||||
? ' text-[1.2rem]'
|
||||
: 'mt-4 justify-center')
|
||||
}
|
||||
>
|
||||
{settings.state.timeOptions.includes('date') && <div>{text.value.dateStr}</div>}
|
||||
<Transition>
|
||||
{!layout.isCompact && settings.state.timeOptions.includes('week') && (
|
||||
<div>星期{info.value.dayWeek}</div>
|
||||
)}
|
||||
</Transition>
|
||||
<Transition>
|
||||
{!layout.isCompact && settings.state.timeOptions.includes('lunal') && (
|
||||
<div>{info.value.day}</div>
|
||||
)}
|
||||
</Transition>
|
||||
</div>
|
||||
)}
|
||||
</Transition>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
import useLayoutStore from '@/layout/useLayoutStore'
|
||||
import useUserStore from '@/user/useUserStore'
|
||||
import useRouterStore from '@/useRouterStore'
|
||||
import clsx from 'clsx'
|
||||
import { computed, defineComponent, ref, Transition } from 'vue'
|
||||
import { MdArrowbackiosnew, HiSolidPlus } from 'oh-vue-icons/icons'
|
||||
import { addIcons, OhVueIcon } from 'oh-vue-icons'
|
||||
import { ossBase } from '@/config'
|
||||
import UploadAndCut from '@/utils/UploadAndCut'
|
||||
addIcons(MdArrowbackiosnew, HiSolidPlus)
|
||||
export default defineComponent(() => {
|
||||
const router = useRouterStore()
|
||||
const { profile } = useUserStore()
|
||||
const layout = useLayoutStore()
|
||||
const isGame = computed(() => {
|
||||
return layout.state.current === 0
|
||||
})
|
||||
const list = Array.from({ length: 10 }).map((_, index) => `${ossBase}/admin/${index + 1}.png`)
|
||||
const selectUrl = ref(profile.avatar)
|
||||
const customHeader = ref(profile.avatar)
|
||||
|
||||
return () => (
|
||||
<div class="fixed left-0 bottom-0 z-40 w-full rounded-lg">
|
||||
{/* 背景遮罩 */}
|
||||
<div
|
||||
class="w-full h-screen"
|
||||
onClick={() => {
|
||||
router.replace('')
|
||||
}}
|
||||
></div>
|
||||
{/* 弹框主体 */}
|
||||
<Transition name="settings">
|
||||
<div
|
||||
class={clsx(
|
||||
'absolute left-6 bottom-10 w-[300px] h-[580px] rounded-2xl shadow-2xl flex ',
|
||||
isGame.value ? 'bg-[#2c2e3e] text-white' : 'text-[#000] bg-white'
|
||||
)}
|
||||
style={
|
||||
isGame.value && {
|
||||
backgroundImage: `url('/tab/bg/gameModel.png')`,
|
||||
backgroundSize: '100% 100%'
|
||||
}
|
||||
}
|
||||
>
|
||||
<div class={'w-full h-full flex flex-col px-5 py-1 '}>
|
||||
<div class={'relative flex justify-center w-full font-bold text-[14px] py-2'}>
|
||||
<div
|
||||
class={'left-2 top-1/2 absolute -translate-y-1/2 cursor-pointer'}
|
||||
onClick={() => {
|
||||
router.back()
|
||||
}}
|
||||
>
|
||||
<OhVueIcon name={MdArrowbackiosnew.name} fill="#666"></OhVueIcon>
|
||||
</div>
|
||||
更换头像
|
||||
</div>
|
||||
<div class={'h-[1px] w-full bg-[#d5d5d5] mt-1 mb-3'}></div>
|
||||
<div class={'w-full grid grid-cols-3 gap-3'}>
|
||||
{list.map((item) => {
|
||||
return (
|
||||
<div
|
||||
key={item}
|
||||
class={' cursor-pointer'}
|
||||
onClick={() => {
|
||||
selectUrl.value = item
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src={item}
|
||||
class={clsx(
|
||||
'w-full h-full rounded-full border-[2px] ',
|
||||
selectUrl.value === item
|
||||
? 'border-[2px] border-red-500'
|
||||
: 'border-[2px] border-transparent'
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
{!list.includes(customHeader.value) && customHeader.value && (
|
||||
<div
|
||||
class={' cursor-pointer'}
|
||||
onClick={() => {
|
||||
selectUrl.value = customHeader.value
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src={customHeader.value}
|
||||
class={clsx(
|
||||
'w-full h-full rounded-full border-[2px] ',
|
||||
selectUrl.value === customHeader.value
|
||||
? 'border-[2px] border-red-500'
|
||||
: 'border-[2px] border-transparent'
|
||||
)}
|
||||
alt="header"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div
|
||||
class={'flex items-center w-[78px] h-[78px] justify-center bg-[#E5E5E5] rounded-full cursor-pointer'}
|
||||
>
|
||||
<UploadAndCut
|
||||
onUpdate:value={(e) => {
|
||||
customHeader.value = e
|
||||
selectUrl.value = e
|
||||
}}
|
||||
></UploadAndCut>
|
||||
</div>
|
||||
</div>
|
||||
<div class={'flex justify-center w-full'}>
|
||||
<button
|
||||
onClick={() => {
|
||||
profile.avatar = selectUrl.value
|
||||
useUserStore().updateProfile()
|
||||
router.back()
|
||||
}}
|
||||
class={
|
||||
'px-14 mt-14 py-1 bg-[#ff7372] text-white text-[14px] rounded-lg hover:opacity-80'
|
||||
}
|
||||
>
|
||||
确定
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
)
|
||||
})
|
|
@ -30,7 +30,7 @@ export default defineComponent({
|
|||
'w-full rounded-lg overflow-hidden flex justify-center items-center p-2 hover:scale-110 transition-all cursor-pointer ' +
|
||||
(searchConfig.current.name === item.name
|
||||
? 'bg-white'
|
||||
: 'bg-white/40 hover:bg-white/60')
|
||||
: 'bg-white ')
|
||||
}
|
||||
onClick={() => {
|
||||
searchConfig.current = { ...item }
|
||||
|
@ -45,9 +45,10 @@ export default defineComponent({
|
|||
}}
|
||||
>
|
||||
<div
|
||||
class="w-6 h-6 bg-center bg-no-repeat bg-contain"
|
||||
class="w-[28px] h-[28px] bg-center bg-no-repeat bg-contain rounded-[8px]"
|
||||
style={{
|
||||
backgroundImage: `url('${item.icon}')`
|
||||
backgroundImage: `url('${item.icon}')`,
|
||||
backgroundSize: '100% 100%'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
@ -56,7 +57,7 @@ export default defineComponent({
|
|||
</div>
|
||||
</div>
|
||||
))}
|
||||
<div class="w-12 h-16">
|
||||
{/* <div class="w-12 h-16">
|
||||
<div
|
||||
class="w-full h-10 rounded-lg overflow-hidden flex justify-center items-center p-2 transition-all cursor-pointer bg-white/40 hover:bg-white/60"
|
||||
onClick={() => {
|
||||
|
@ -66,7 +67,7 @@ export default defineComponent({
|
|||
>
|
||||
<OhVueIcon name="fa-plus" scale={1.4} fill="rgba(0,0,0,.4)" />
|
||||
</div>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -17,20 +17,20 @@ export default defineComponent(
|
|||
return () => (
|
||||
<div
|
||||
class={clsx(
|
||||
!props?.isMini ? 'absolute left-1/2 -translate-x-1/2 z-20 transition-all' : 'w-full'
|
||||
!props?.isMini ? 'absolute left-1/2 -translate-x-1/2 z-20 duration-300 transition-all' : 'w-full'
|
||||
)}
|
||||
style={
|
||||
props.isMini
|
||||
? {}
|
||||
: {
|
||||
top: layout.isCompact ? '40px' : layout.state.simple ? '230px' : '172px',
|
||||
top: layout.isCompact && !layout.state.simple ? '50px' : layout.state.simple ? '230px' : '172px',
|
||||
width: settings.state.searchWidth + 'rem'
|
||||
}
|
||||
}
|
||||
>
|
||||
<div
|
||||
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 hover:bg-white',
|
||||
props.isMini ? '' : 'max-w-[90vw] w-full'
|
||||
)}
|
||||
|
|
|
@ -6,6 +6,7 @@ import debounce from 'lodash/debounce'
|
|||
import { aIUrl, translateUrl } from '@/config'
|
||||
import request from '@/utils/request'
|
||||
import useStatisticStore from '@/utils/useStatisticStore'
|
||||
import { Base64 } from "js-base64"
|
||||
export type SearchAdType = {
|
||||
name: string
|
||||
icon: string
|
||||
|
@ -39,15 +40,12 @@ export default defineStore('search', () => {
|
|||
searchStr,
|
||||
(val) => {
|
||||
if (!val) return
|
||||
fetch(
|
||||
`${import.meta.env.PROD ? 'https://suggestion.baidu.com/su' : '/baiduSuggestion'}?wd=${val}&ie=utf-8&p=3&cb=j`
|
||||
)
|
||||
.then((res) => res.text())
|
||||
.then((res: string) => {
|
||||
const list = res.match(/(?<=s:\[").*(?=\]\})/g)?.[0]?.split('","')
|
||||
if (list) {
|
||||
sugList.value = list
|
||||
}
|
||||
request<{
|
||||
list: string[]
|
||||
}>('GET', `/api/lookUp/${Base64.encode(val)}`,)
|
||||
.then(res => {
|
||||
// const list = res.match(/(?<=s:\[").*(?=\]\})/g)?.[0]?.split('","')
|
||||
sugList.value = res.list
|
||||
}) as Promise<string[]>
|
||||
},
|
||||
{
|
||||
|
@ -55,10 +53,8 @@ export default defineStore('search', () => {
|
|||
}
|
||||
)
|
||||
const debouncedHandler = debounce((newValue) => {
|
||||
console.log('数值改变并已防抖处理:', newValue)
|
||||
request<SearchAdType[]>("GET", `/api/app/searchBars?keyword=${newValue || 'undefine'}`).then((res) => {
|
||||
addList.value = res
|
||||
console.log(addList.value);
|
||||
|
||||
})
|
||||
}, 500) //
|
||||
|
@ -82,7 +78,7 @@ export default defineStore('search', () => {
|
|||
searchConfig.addHistory(str)
|
||||
searchStr.value = ''
|
||||
jump(searchConfig.current.url + str)
|
||||
|
||||
|
||||
useStatisticStore().send({
|
||||
widget: 'search',
|
||||
action: 'search',
|
||||
|
|
|
@ -17,7 +17,6 @@ export default defineComponent(() => {
|
|||
(val) => {
|
||||
selected.value = val
|
||||
hover.value = false
|
||||
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
@ -66,7 +65,8 @@ export default defineComponent(() => {
|
|||
<div
|
||||
class={clsx(
|
||||
'absolute top-[18px] text-white text-[13px] z-20 flex flex-col items-center pointer-events-none',
|
||||
settings.state.siderDirection === 'right' ? 'right-[105px]' : 'left-[105px] '
|
||||
settings.state.siderDirection === 'right' ? 'right-[105px]' : 'left-[105px] ',
|
||||
selected.value === 0 || layout.state.current === 0 ? ' opacity-100' : ' opacity-70'
|
||||
)}
|
||||
>
|
||||
<OhVueIcon name="md-videogameasset-twotone" fill="white" scale={1.3} />
|
||||
|
@ -75,7 +75,8 @@ export default defineComponent(() => {
|
|||
<div
|
||||
class={clsx(
|
||||
'absolute top-[80px] text-white text-[13px] z-20 flex flex-col items-center pointer-events-none',
|
||||
settings.state.siderDirection === 'right' ? 'right-[150px] ' : 'left-[150px] '
|
||||
settings.state.siderDirection === 'right' ? 'right-[150px] ' : 'left-[150px] ',
|
||||
selected.value === 1 || layout.state.current === 1 ? ' opacity-100' : ' opacity-70'
|
||||
)}
|
||||
>
|
||||
<OhVueIcon name="md-workhistory-twotone" fill="white" scale={1.3} />
|
||||
|
@ -86,11 +87,12 @@ export default defineComponent(() => {
|
|||
'absolute text-white text-[13px] flex flex-col z-20 items-center pointer-events-none',
|
||||
settings.state.siderDirection === 'right'
|
||||
? 'right-[105px] top-[140px]'
|
||||
: 'left-[105px] top-[140px]'
|
||||
: 'left-[105px] top-[140px]',
|
||||
selected.value === 2 || layout.state.current === 2 ? ' opacity-100' : ' opacity-70'
|
||||
)}
|
||||
>
|
||||
<OhVueIcon name="md-stars-twotone" fill="white" scale={1.3} />
|
||||
休闲
|
||||
轻娱
|
||||
</div>
|
||||
<svg
|
||||
width="200"
|
||||
|
@ -116,7 +118,12 @@ export default defineComponent(() => {
|
|||
/>
|
||||
</g>
|
||||
{/* 判定区块,无颜色 */}
|
||||
<g class="relative z-10">
|
||||
<g
|
||||
class="relative z-10"
|
||||
onClick={() => {
|
||||
layout.state.current = selected.value
|
||||
}}
|
||||
>
|
||||
<path
|
||||
fill="transparent"
|
||||
d="M155.29,94.09c-7.97-10.81-20.68-17.24-34.1-17.24-4.48,0-8.91,.71-13.17,2.1L85.85,11.74c11.31-3.68,23.12-5.54,35.1-5.54,35.71,0,69.72,17.1,91.07,45.78l-56.72,42.12Z"
|
||||
|
@ -156,14 +163,17 @@ export default defineComponent(() => {
|
|||
<path
|
||||
class={
|
||||
'absolute z-30 transition-all opacity-60 ' +
|
||||
(selected.value === 0
|
||||
(layout.state.current === 0
|
||||
? '-rotate-[72deg]'
|
||||
: selected.value === 1
|
||||
: layout.state.current === 1
|
||||
? 'rotate-0'
|
||||
: 'rotate-[72deg]')
|
||||
}
|
||||
onClick={() => {
|
||||
layout.state.current = selected.value
|
||||
onMouseenter={() => {
|
||||
selected.value = layout.state.current
|
||||
}}
|
||||
onClick={()=> {
|
||||
hover.value = false
|
||||
}}
|
||||
style="transform-origin: 50% 50%;"
|
||||
fill="url(#mode-switch-selected)"
|
||||
|
|
|
@ -107,7 +107,7 @@ export default defineComponent(() => {
|
|||
<Transition>
|
||||
{layout.ready && (
|
||||
<div
|
||||
onContextmenu={(e)=> {
|
||||
onContextmenu={(e) => {
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
}}
|
||||
|
@ -174,6 +174,7 @@ export default defineComponent(() => {
|
|||
label="添加"
|
||||
onClick={() => {
|
||||
menu.showEditPage = true
|
||||
menu.selectPage = undefined
|
||||
}}
|
||||
/>
|
||||
<Item
|
||||
|
@ -256,6 +257,7 @@ export default defineComponent(() => {
|
|||
name: selected.value.name,
|
||||
id: uuid()
|
||||
})
|
||||
layout.state.currentPage = layout.currentMode.pages.length - 1
|
||||
}
|
||||
|
||||
menu.showEditPage = false
|
||||
|
|
|
@ -77,7 +77,6 @@ export default defineStore('layout', () => {
|
|||
}
|
||||
const pageList = state.content[state.current].pages[page].list
|
||||
pageList.push(block)
|
||||
globalToast.success('添加成功')
|
||||
}
|
||||
const changeBlock = (item: EditBlockItemType, target: string) => {
|
||||
const idx = currentPage.value.list.findIndex((el) => el.id === target)
|
||||
|
@ -133,7 +132,7 @@ export default defineStore('layout', () => {
|
|||
if (!res) return
|
||||
state.dir = res.dir
|
||||
state.content = res.content
|
||||
|
||||
state.dock = res.dock
|
||||
}).catch(() => {
|
||||
Object.assign(state, defaultLayout)
|
||||
|
||||
|
|
33
src/main.css
33
src/main.css
|
@ -265,17 +265,36 @@ body {
|
|||
.background-enter-active,
|
||||
.background-leave-active {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
transition:
|
||||
transform 0.6s cubic-bezier(0.47, 1.64, 0.41, 0.8),
|
||||
opacity 0.6s ease-out;
|
||||
transition: transform 0.6s cubic-bezier(0.47, 1.64, 0.41, 0.8);
|
||||
}
|
||||
|
||||
.background-enter-from {
|
||||
transform: scale(1.25);
|
||||
opacity: 0;
|
||||
transform: scale(1.2);
|
||||
}
|
||||
.background-leave-to {
|
||||
transform: scale(1);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.eat-enter-active,
|
||||
.eat-leave-active {
|
||||
transition: transform 0.25s ease-in;
|
||||
}
|
||||
|
||||
.eat-enter-from {
|
||||
transform: translateY(0);
|
||||
}
|
||||
.eat-leave-to {
|
||||
transform: translateY(100%);
|
||||
}
|
||||
.neweat-enter-active,
|
||||
.neweat-leave-active {
|
||||
transition: transform 0.25s ease-out ;
|
||||
|
||||
}
|
||||
|
||||
.neweat-enter-from {
|
||||
transform: translateY(0);
|
||||
}
|
||||
.neweat-leave-to {
|
||||
transform: translateY(107%);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
import useLayoutStore from '@/layout/useLayoutStore'
|
||||
import useUserStore from '@/user/useUserStore'
|
||||
import useRouterStore from '@/useRouterStore'
|
||||
import clsx from 'clsx'
|
||||
import { computed, defineComponent, Transition } from 'vue'
|
||||
|
||||
export default defineComponent(() => {
|
||||
const router = useRouterStore()
|
||||
const { profile } = useUserStore()
|
||||
const show = computed(() => router.path.startsWith('settings-header'))
|
||||
const layout = useLayoutStore()
|
||||
const isGame = computed(() => {
|
||||
return layout.state.current === 0
|
||||
})
|
||||
return () => (
|
||||
<div class="fixed left-0 bottom-0 z-40 w-full rounded-lg">
|
||||
{/* 背景遮罩 */}
|
||||
{show.value && (
|
||||
<div
|
||||
class="w-full h-screen"
|
||||
onClick={() => {
|
||||
router.replace('')
|
||||
}}
|
||||
></div>
|
||||
)}
|
||||
{/* 弹框主体 */}
|
||||
<Transition name="settings">
|
||||
{show.value && (
|
||||
<div
|
||||
class={clsx(
|
||||
'absolute left-6 bottom-10 w-[660px] h-[580px] rounded-2xl shadow-2xl flex',
|
||||
isGame.value ? 'bg-[#2c2e3e] text-white' : 'text-[#000] bg-white'
|
||||
)}
|
||||
style={
|
||||
isGame.value && {
|
||||
backgroundImage: `url('/tab/bg/gameModel.png')`,
|
||||
backgroundSize: '100% 100%'
|
||||
}
|
||||
}
|
||||
>
|
||||
|
||||
</div>
|
||||
)}
|
||||
</Transition>
|
||||
</div>
|
||||
)
|
||||
})
|
|
@ -15,6 +15,9 @@ export default defineComponent({
|
|||
noBg: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
desc: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
slots: {} as SlotsType<{
|
||||
|
@ -39,8 +42,17 @@ export default defineComponent({
|
|||
marginBottom: props.noRoundedB ? 0 : '12px'
|
||||
}}
|
||||
>
|
||||
<div class={clsx('text-sm mr-4', isGame.value ? 'text-white' : 'text-black/60')}>
|
||||
{ctx.slots.label?.()}
|
||||
<div
|
||||
class={clsx('text-sm mr-4 flex flex-col', isGame.value ? 'text-white' : 'text-black/60')}
|
||||
>
|
||||
<span> {ctx.slots.label?.()}</span>
|
||||
{props.desc ? (
|
||||
<span
|
||||
class={clsx('text-[12px] ', isGame.value ? 'text-white opacity-50 ' : 'text-black/60')}
|
||||
>
|
||||
{props.desc}
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
<div class="">{ctx.slots.default?.()}</div>
|
||||
{/* {ctx.slots.end?.()} */}
|
||||
|
|
|
@ -10,6 +10,7 @@ import SiderSetting from '@/layout/grid/SiderSetting'
|
|||
import DockSetting from '@/layout/grid/DockSetting'
|
||||
import Feedback from '@/layout/grid/Feedback'
|
||||
import Reset from '@/layout/grid/Reset'
|
||||
import AiSetting from '@/layout/grid/AiSetting'
|
||||
|
||||
export default defineComponent(() => {
|
||||
const router = useRouterStore()
|
||||
|
@ -35,6 +36,8 @@ export default defineComponent(() => {
|
|||
<Reset />
|
||||
) : router.path === 'settings-fallback' ? (
|
||||
<Feedback />
|
||||
) : router.path === 'settings-ai' ? (
|
||||
<AiSetting />
|
||||
) : null}
|
||||
</ThemeProvider>
|
||||
</div>
|
||||
|
|
|
@ -40,7 +40,9 @@ export default defineStore(
|
|||
// 显示隐藏
|
||||
showSider: 'show' as VisibleState,
|
||||
showDock: 'show' as VisibleState,
|
||||
showPet: 'show' as VisibleState,
|
||||
showPet: true,
|
||||
showPetOnTab: true,
|
||||
autoUseAi: 'show' as VisibleState,
|
||||
showTop: 'show' as VisibleState,
|
||||
showTime: true,
|
||||
timeOptions: ['date', 'week', '12hour', 'lunal', 'second'] as TimeUnit[],
|
||||
|
|
|
@ -13,8 +13,9 @@ export type SettingStr =
|
|||
| 'dock'
|
||||
| 'reset'
|
||||
| 'fallback'
|
||||
export type CustomStr = 'background'
|
||||
export type RouteStr = '' | `widget-${string}` | `global-${GlobalStr}` | `settings-${SettingStr}`
|
||||
| 'logout'
|
||||
export type CustomStr = 'header'
|
||||
export type RouteStr = '' | `widget-${string}` | `global-${GlobalStr}` | `settings-${SettingStr}` | `custom-${CustomStr}`
|
||||
|
||||
export default defineStore('router', () => {
|
||||
const his = ref<RouteStr[]>([])
|
||||
|
|
|
@ -8,11 +8,7 @@ addIcons(FaUserAlt)
|
|||
|
||||
export default defineComponent(() => {
|
||||
const store = useUserStore()
|
||||
watch(() => store.profile.avatar, (e) => {
|
||||
console.log(e);
|
||||
|
||||
console.log('avatar change')
|
||||
})
|
||||
return () => {
|
||||
return (
|
||||
<div
|
||||
|
|
|
@ -32,7 +32,6 @@ export default defineComponent(() => {
|
|||
}).then((res) => {
|
||||
if (res) {
|
||||
clearInterval(it)
|
||||
console.log(res)
|
||||
user.token = res
|
||||
router.back()
|
||||
message.success('登录成功')
|
||||
|
|
|
@ -1,96 +1,192 @@
|
|||
import useRouterStore from '@/useRouterStore'
|
||||
import { Button, Modal, Tag } from 'ant-design-vue'
|
||||
import { defineComponent } from 'vue'
|
||||
import { Button, Select } from 'ant-design-vue'
|
||||
import { computed, defineComponent, ref } from 'vue'
|
||||
import AvatarCircle from './AvatarCircle'
|
||||
import useUserStore from './useUserStore'
|
||||
import { EditOutlined, LoginOutlined, LogoutOutlined } from '@ant-design/icons-vue'
|
||||
import { globalToast } from '@/main'
|
||||
import { LoginOutlined } from '@ant-design/icons-vue'
|
||||
import { FaRegularEdit } from 'oh-vue-icons/icons'
|
||||
import clsx from 'clsx'
|
||||
import useLayoutStore from '@/layout/useLayoutStore'
|
||||
|
||||
const labelStyle = 'w-16'
|
||||
import { addIcons, OhVueIcon } from 'oh-vue-icons'
|
||||
import background from '@/layout/background'
|
||||
addIcons(FaRegularEdit)
|
||||
|
||||
export default defineComponent(() => {
|
||||
const router = useRouterStore()
|
||||
const layout = useLayoutStore()
|
||||
const user = useUserStore()
|
||||
const open = ref(false)
|
||||
const isGame = computed(() => {
|
||||
return layout.state.current === 0
|
||||
})
|
||||
return () => (
|
||||
<div class="absolute left-0 top-0 w-full h-full p-4 flex flex-col">
|
||||
<div class="flex justify-center py-4">
|
||||
<div class="w-16 h-16 relative">
|
||||
<AvatarCircle />
|
||||
</div>
|
||||
</div>
|
||||
{user.isLogin && (
|
||||
<div
|
||||
class={clsx(
|
||||
'h-0 flex-grow py-4 px-12 ',
|
||||
layout.state.current === 0 ? 'text-white' : 'text-[#333]'
|
||||
)}
|
||||
>
|
||||
<div class="flex py-2">
|
||||
<div class={labelStyle}>用户名:</div>
|
||||
<div class="w-0 flex-grow overflow-hidden text-ellipsis whitespace-nowrap break-all">
|
||||
{user.profile.username}
|
||||
{user.isLogin ? (
|
||||
<>
|
||||
<div class={'flex flex-col'}>
|
||||
<span
|
||||
class={clsx(
|
||||
'text-[14px] font-bold',
|
||||
useLayoutStore().state.current === 0 ? 'text-white' : ' text-[#333]'
|
||||
)}
|
||||
>
|
||||
个人信息
|
||||
</span>
|
||||
<div
|
||||
class={clsx(
|
||||
'w-full h-[1px] bg-black/10 mt-1 mb-2',
|
||||
useLayoutStore().state.current === 0 ? 'bg-white/10' : ' bg-black/10'
|
||||
)}
|
||||
></div>
|
||||
</div>
|
||||
<div class="flex pl-4 py-4 w-full gap-x-4">
|
||||
<div class="w-16 h-16 rounded-full group overflow-hidden relative">
|
||||
<AvatarCircle />
|
||||
<div
|
||||
onClick={() => {
|
||||
router.go('custom-header')
|
||||
}}
|
||||
class={
|
||||
'absolute hidden left-0 cursor-pointer top-0 opacity-60 rounded-full w-full h-full bg-black z-10 group-hover:flex items-center justify-center'
|
||||
}
|
||||
>
|
||||
<OhVueIcon name={FaRegularEdit.name} fill="#ddd"></OhVueIcon>
|
||||
</div>
|
||||
</div>
|
||||
<div class={'flex flex-col h-full justify-between text-[14px] py-1'}>
|
||||
<div class={'flex gap-x-1 items-center'}>
|
||||
<span class={clsx(' w-[50px]', isGame.value ? 'text-[#fff9]' : 'text-[#666]')}>
|
||||
用户名:
|
||||
</span>
|
||||
<input
|
||||
onBlur={() => {
|
||||
user.updateProfile()
|
||||
}}
|
||||
class={
|
||||
'text-[#666] w-[150px] bg-transparent focus:bg-black/[0.05] border-none outline-none px-1 py-[2px]'
|
||||
}
|
||||
v-model={user.profile.username}
|
||||
></input>
|
||||
</div>
|
||||
<div class={'flex gap-x-1 items-center'}>
|
||||
<span class={clsx(' w-[50px]', isGame.value ? 'text-[#fff9]' : 'text-[#666]')}>
|
||||
性  别:
|
||||
</span>
|
||||
<Select
|
||||
defaultValue={user.profile.gender}
|
||||
v-model={user.profile.gender}
|
||||
class={
|
||||
'w-[150px] bg-transparent appearance-none focus:bg-black/[0.05] overflow-hidden border-none outline-none px-1 py-[2px]'
|
||||
}
|
||||
style={{
|
||||
background: 'transparent !important'
|
||||
}}
|
||||
onChange={(e: any) => {
|
||||
user.profile.gender = e
|
||||
user.updateProfile()
|
||||
}}
|
||||
options={[
|
||||
{
|
||||
label: '男',
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
label: '女',
|
||||
value: 2
|
||||
},
|
||||
{
|
||||
label: '未知',
|
||||
value: 0
|
||||
}
|
||||
]}
|
||||
></Select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex py-2">
|
||||
<div class={labelStyle}>生日:</div> {user.profile.birthday}
|
||||
<div
|
||||
onClick={() => {
|
||||
open.value = true
|
||||
}}
|
||||
class={
|
||||
'w-full h-[32px] mt-5 cursor-pointer hover:opacity-90 flex items-center justify-center text-[13px] rounded bg-[#e5e5e5] text-[#999]'
|
||||
}
|
||||
>
|
||||
退出登录
|
||||
</div>
|
||||
<div class="flex py-2">
|
||||
<div class={labelStyle}>性别:</div>
|
||||
<Tag color={user.profile.gender === 1 ? 'blue' : user.profile.gender === 2 ? 'red' : 'gray'}>
|
||||
{user.profile.gender === 1 ? '男' : user.profile.gender === 2 ? '女' : '未知'}
|
||||
</Tag>
|
||||
</>
|
||||
) : (
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<LoginOutlined />}
|
||||
size="large"
|
||||
onClick={() => {
|
||||
router.go('global-login')
|
||||
}}
|
||||
>
|
||||
登录
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{open.value && (
|
||||
<div
|
||||
class={clsx(
|
||||
'w-[300px] h-[210px] absolute top-0 rounded-2xl right-[-310px] z-10 ',
|
||||
isGame.value ? 'bg-[#2c2e3e]' : 'bg-white'
|
||||
)}
|
||||
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]' : 'text-[#666]'
|
||||
)}
|
||||
>
|
||||
退出登录将会失去多端数据云同步等功能,是否继续?
|
||||
</span>
|
||||
<div class={'flex justify-between w-full'}>
|
||||
<button
|
||||
onClick={() => {
|
||||
open.value = false
|
||||
}}
|
||||
class={clsx(
|
||||
'w-[118px] rounded-lg py-1 flex justify-center',
|
||||
isGame.value ? 'bg-white/20' : 'bg-black/20 text-white'
|
||||
)}
|
||||
>
|
||||
取消
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
user.logout()
|
||||
open.value = false
|
||||
router.replace('')
|
||||
}}
|
||||
class={clsx(
|
||||
'w-[118px] rounded-lg py-1 flex justify-center ',
|
||||
isGame.value ? 'bg-[#ff7372]' : 'bg-[#ff7372] text-white'
|
||||
)}
|
||||
>
|
||||
退出
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
<div class="flex justify-around items-center my-10">
|
||||
{user.isLogin ? (
|
||||
<>
|
||||
<Button
|
||||
onClick={() => {
|
||||
router.go('global-login')
|
||||
}}
|
||||
icon={<EditOutlined />}
|
||||
type="primary"
|
||||
>
|
||||
修改个人信息
|
||||
</Button>
|
||||
<Button
|
||||
type="text"
|
||||
class={'text-[#999] hover:text-[#999]'}
|
||||
icon={<LogoutOutlined />}
|
||||
onClick={() => {
|
||||
Modal.confirm({
|
||||
title: '退出登录',
|
||||
content: '确定要退出登录吗?',
|
||||
onOk: () => {
|
||||
router.go('')
|
||||
user.logout()
|
||||
globalToast.success('已退出登录')
|
||||
}
|
||||
})
|
||||
}}
|
||||
>
|
||||
退出登录
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<LoginOutlined />}
|
||||
size="large"
|
||||
onClick={() => {
|
||||
router.go('global-login')
|
||||
}}
|
||||
>
|
||||
登录
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div >
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
|
|
@ -32,8 +32,6 @@ function areArraysEqualById(arr1: Block[], arr2: Block[]): boolean {
|
|||
|
||||
// 检查 arr1 中的每个 item 是否在 arr2 中存在,并且值是否相同
|
||||
for (let i = 0; i < arr1.length; i++) {
|
||||
console.log(arr1[i].id)
|
||||
console.log(arr2[i].id)
|
||||
|
||||
if (arr1[i].id !== arr2[i].id) {
|
||||
return false
|
||||
|
@ -90,7 +88,6 @@ export default defineStore('user', () => {
|
|||
|
||||
watch(token, async (val) => {
|
||||
if (!val) return
|
||||
console.log(val)
|
||||
|
||||
const data = await request<Layout>('GET', '/api/backup')
|
||||
if (!data) {
|
||||
|
@ -126,9 +123,9 @@ export default defineStore('user', () => {
|
|||
}
|
||||
const comineData = () => {
|
||||
if (!remoteAddList.value) return
|
||||
console.log({ ...remoteAddList.value })
|
||||
remoteAddList.value.map((item) => {
|
||||
layout.state.content[layout.state.current].pages[layout.state.currentPage].list.push(item)
|
||||
if (item.link)
|
||||
layout.state.content[layout.state.current].pages[layout.state.currentPage].list.push(item)
|
||||
})
|
||||
}
|
||||
const coverageData = () => {
|
||||
|
@ -137,10 +134,19 @@ export default defineStore('user', () => {
|
|||
Object.assign(layout.state.dock, remoteData.value.dock)
|
||||
Object.assign(layout.state.dir, remoteData.value.dir)
|
||||
}
|
||||
const updateProfile = () => {
|
||||
request('PUT', '/api/profile', {
|
||||
returnType: 'text',
|
||||
data: {
|
||||
...profile
|
||||
}
|
||||
})
|
||||
}
|
||||
return {
|
||||
token,
|
||||
profile,
|
||||
isLogin,
|
||||
updateProfile,
|
||||
logout,
|
||||
coverageData,
|
||||
comineData
|
||||
|
|
|
@ -158,7 +158,7 @@ export default defineComponent({
|
|||
</div>
|
||||
</Modal>
|
||||
<div
|
||||
class="w-full h-full bg-white flex items-center justify-center"
|
||||
class="w-full h-full flex items-center justify-center"
|
||||
onClick={() => {
|
||||
if (useUserStore().isLogin) {
|
||||
inputRef.value?.click?.()
|
||||
|
|
|
@ -14,7 +14,6 @@ const fetchAdverConfig = async () => {
|
|||
request('GET', '/api/app/adverLinks/params'),
|
||||
request('GET', '/api/app/adverLinks/link')
|
||||
]).then((res: any) => {
|
||||
console.log('----', res)
|
||||
const result: AdverData = { links: [], params: [], expiration: Date.now() + 1000 * 60 * 60 * 4 }
|
||||
if (res[0].status === 'fulfilled') {
|
||||
result.params = res[0].value
|
||||
|
|
|
@ -7,8 +7,9 @@ export function sendParent(
|
|||
| [
|
||||
'configAI',
|
||||
{
|
||||
autoSearch: true
|
||||
showTabButton: true
|
||||
autoSearch: boolean
|
||||
showTabButton: boolean
|
||||
isSearch: boolean
|
||||
}
|
||||
]
|
||||
) {
|
||||
|
|
|
@ -41,7 +41,7 @@ export async function uploadLocal(file: File) {
|
|||
list.push({
|
||||
tag: id,
|
||||
file: file,
|
||||
type: 'image'
|
||||
type: file.type.split('/')[0] === 'video'? 'video' : 'image'
|
||||
})
|
||||
await db.setItem('localList', list)
|
||||
return id
|
||||
|
|
|
@ -17,7 +17,6 @@ export default defineStore('statistic', () => {
|
|||
list.value.push(item)
|
||||
}
|
||||
const debouncedHandler = debounce((newValue: StatisticType[]) => {
|
||||
console.log('数值改变并已防抖处理:', newValue)
|
||||
if (newValue.length === 0) return
|
||||
request("POST", `/api/app/statistics`, {
|
||||
data: newValue.map((item) => ({
|
||||
|
@ -30,11 +29,9 @@ export default defineStore('statistic', () => {
|
|||
}).then(() => {
|
||||
|
||||
list.value = []
|
||||
message.success('发送统计成功')
|
||||
})
|
||||
}, 2500) //
|
||||
watch(list, (newValue) => {
|
||||
console.log(list);
|
||||
|
||||
debouncedHandler(newValue)
|
||||
}, {
|
||||
|
|
|
@ -31,7 +31,7 @@ export default defineComponent(() => {
|
|||
}
|
||||
>
|
||||
<div class="flex flex-col w-full h-full justify-center gap-y-2 py-2 px-3">
|
||||
<span class="text-white text-[14px]">{selectItem.value.name}</span>
|
||||
<span class="text-white text-[14px]">{selectItem.value?.name}</span>
|
||||
<div>
|
||||
<span
|
||||
class={
|
||||
|
|
|
@ -4,6 +4,7 @@ import { addIcons, OhVueIcon } from 'oh-vue-icons'
|
|||
import { IoCloseCircleOutline, RiCloseCircleLine } from 'oh-vue-icons/icons'
|
||||
import useDiscountStore from './useDiscountStore'
|
||||
import { debounce } from 'lodash'
|
||||
import jump from '@/utils/jump'
|
||||
addIcons(RiTimeLine, IoCloseCircleOutline, RiCloseCircleLine)
|
||||
export default defineComponent(() => {
|
||||
const store = useDiscountStore()
|
||||
|
@ -13,7 +14,7 @@ export default defineComponent(() => {
|
|||
const container = containerRef.value
|
||||
if (store.loading) return
|
||||
if (container.scrollTop + container.clientHeight >= container.scrollHeight - 15) {
|
||||
store.state.pageIndex += 1;
|
||||
store.state.pageIndex += 1
|
||||
|
||||
store.getNews()
|
||||
}
|
||||
|
@ -25,13 +26,16 @@ export default defineComponent(() => {
|
|||
store.state.pageIndex = 1
|
||||
store.noMoreData = false
|
||||
store.getNews()
|
||||
}, 500) //
|
||||
}, 500) //
|
||||
watch(searchText, (newValue) => {
|
||||
debouncedHandler(newValue)
|
||||
}, {
|
||||
immediate: true
|
||||
})
|
||||
onMounted(() => {
|
||||
store.state.pageIndex = 1
|
||||
store.getNews()
|
||||
searchText.value = ''
|
||||
})
|
||||
return () => (
|
||||
<div
|
||||
|
@ -57,7 +61,15 @@ export default defineComponent(() => {
|
|||
}
|
||||
}}
|
||||
></input>
|
||||
<div class={'absolute cursor-pointer hidden group-hover:block right-3 top-1/2 -translate-y-1/2'}>
|
||||
<div
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
searchText.value = ''
|
||||
}}
|
||||
class={
|
||||
'absolute cursor-pointer hidden group-hover:block right-3 top-1/2 -translate-y-1/2'
|
||||
}
|
||||
>
|
||||
<OhVueIcon name={RiCloseCircleLine.name} fill="#ddd"></OhVueIcon>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -69,56 +81,61 @@ export default defineComponent(() => {
|
|||
ref={containerRef}
|
||||
>
|
||||
<div class={'grid grid-cols-3 gap-4 '}>
|
||||
{
|
||||
(store.state.find ? store.searchList :
|
||||
store.list).map((item, index) => {
|
||||
return (
|
||||
<div
|
||||
class={
|
||||
'flex cursor-pointer h-[215px] overflow-hidden bg-[#17212d] items-center flex-col rounded-lg relative '
|
||||
}
|
||||
onClick={() => { }}
|
||||
key={index}
|
||||
>
|
||||
<img class={'h-[142px] w-full object-cover'} src={item.commdity[0]?.img}></img>
|
||||
<div
|
||||
class={
|
||||
'absolute bottom-0 w-full h-[100px] rounded-lg bg-[#0003] backdrop-blur-md'
|
||||
}
|
||||
>
|
||||
<div class="flex flex-col w-full h-full justify-between py-2 px-3">
|
||||
<span class="text-white text-[14px]">{item.name}</span>
|
||||
<div>
|
||||
<span
|
||||
class={
|
||||
'border-[1px] border-[#f6d1b8] border-solid text-[#f6d1b8] p-1 text-[12px] rounded'
|
||||
}
|
||||
>
|
||||
{item.typename}
|
||||
</span>
|
||||
</div>
|
||||
<div class="bg-white/20 flex rounded items-center gap-x-2">
|
||||
<div class="bg-[#ef5a41] h-full text-white rounded px-2 text-[18px] font-bold ">
|
||||
-13%
|
||||
</div>
|
||||
<span class="text-[#fffbc2] text-[16px] ml-2">
|
||||
¥{item.commdity[0]?.price}
|
||||
</span>
|
||||
<span class="text-[12px] text-[#bdbdbd] line-through decoration-current">
|
||||
¥{item.commdity[0]?.oldprice}
|
||||
</span>
|
||||
<span class="text-[12px] text-[#ebebeb] ">
|
||||
剩余{1}天
|
||||
</span>
|
||||
</div>
|
||||
{(store.state.find ? store.searchList : store.list).map((item, index) => {
|
||||
return (
|
||||
<div
|
||||
class={
|
||||
'flex cursor-pointer h-[215px] overflow-hidden bg-[#17212d] items-center flex-col rounded-lg relative '
|
||||
}
|
||||
onClick={() => {
|
||||
// jump(item.commdity[0]?.url)
|
||||
window.open(item.commdity[0]?.url)
|
||||
}}
|
||||
key={index}
|
||||
>
|
||||
<img class={'h-[142px] w-full object-cover'} src={item.commdity[0]?.img}></img>
|
||||
<div
|
||||
class={
|
||||
'absolute bottom-0 w-full h-[100px] rounded-lg bg-[#0003] backdrop-blur-md'
|
||||
}
|
||||
>
|
||||
<div class="flex flex-col w-full h-full justify-between py-2 px-3">
|
||||
<span class="text-white text-[14px]">{item.name}</span>
|
||||
<div>
|
||||
<span
|
||||
class={
|
||||
'border-[1px] border-[#f6d1b8] border-solid text-[#f6d1b8] p-1 text-[12px] rounded'
|
||||
}
|
||||
>
|
||||
{item.typename}
|
||||
</span>
|
||||
</div>
|
||||
<div class="bg-white/20 flex rounded items-center gap-x-2">
|
||||
<div class="bg-[#ef5a41] h-full text-white rounded px-2 text-[18px] font-bold ">
|
||||
-13%
|
||||
</div>
|
||||
<span class="text-[#fffbc2] text-[16px] ml-2">
|
||||
¥{item.commdity[0]?.price}
|
||||
</span>
|
||||
<span class="text-[12px] text-[#bdbdbd] line-through decoration-current">
|
||||
¥{item.commdity[0]?.oldprice}
|
||||
</span>
|
||||
<span class="text-[12px] text-[#ebebeb] ">剩余{1}天</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
{store.loading && (
|
||||
<div class={'w-full font-bold flex absolute bottom-2 bg-[#17212d] justify-center text-white py-2'}>加载中...</div>
|
||||
<div
|
||||
class={
|
||||
'w-full font-bold flex absolute bottom-2 bg-[#17212d] justify-center text-white py-2'
|
||||
}
|
||||
>
|
||||
加载中...
|
||||
</div>
|
||||
)}
|
||||
{store.noMoreData && (
|
||||
<div class={'w-full font-bold flex justify-center text-white py-2'}>无更多数据</div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import clsx from 'clsx'
|
||||
import dayjs from 'dayjs'
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import { defineComponent, reactive, ref, Transition, watch } from 'vue'
|
||||
|
||||
export default defineComponent(() => {
|
||||
const list = [
|
||||
|
@ -77,6 +77,11 @@ export default defineComponent(() => {
|
|||
'炒年糕'
|
||||
]
|
||||
const text = ref('')
|
||||
const open = ref(false)
|
||||
const pair = reactive({ front: true, back: true })
|
||||
watch(open, (val) => {
|
||||
if (!val) text.value = ''
|
||||
})
|
||||
return () => (
|
||||
<div
|
||||
class="w-full h-full flex flex-col px-[14px] pt-[23px]"
|
||||
|
@ -85,7 +90,7 @@ export default defineComponent(() => {
|
|||
backgroundSize: '100% 100%'
|
||||
}}
|
||||
onClick={() => {
|
||||
text.value = ''
|
||||
open.value = false
|
||||
}}
|
||||
>
|
||||
<div class={'w-full flex justify-center'}>
|
||||
|
@ -95,12 +100,12 @@ export default defineComponent(() => {
|
|||
<div
|
||||
class={clsx(
|
||||
'w-[130px] duration-150 bg-white relative',
|
||||
text.value ? 'h-[120px]' : 'h-[17px]'
|
||||
open.value ? 'h-[120px]' : 'h-[17px]'
|
||||
)}
|
||||
>
|
||||
<button
|
||||
class={
|
||||
'w-[48px] h-[19px] text-[12px] rounded left-1/2 bottom-[-10px] absolute -translate-x-1/2 rounded-br-[6px] rounded-bl-[6px] text-white'
|
||||
'w-[48px] z-20 h-[19px] text-[12px] rounded left-1/2 bottom-[-10px] absolute -translate-x-1/2 rounded-br-[6px] rounded-bl-[6px] text-white'
|
||||
}
|
||||
style={{
|
||||
background: 'linear-gradient(180deg,#ffa061 0%,#ffb62f 100%)',
|
||||
|
@ -110,26 +115,60 @@ export default defineComponent(() => {
|
|||
e.stopPropagation()
|
||||
const index = Math.floor(Math.random() * list.length)
|
||||
if (text.value) {
|
||||
text.value = ''
|
||||
setTimeout(() => {
|
||||
text.value = list[index]
|
||||
}, 400)
|
||||
}else {
|
||||
pair.front = false
|
||||
text.value = list[index]
|
||||
|
||||
setTimeout(() => {
|
||||
text.value = list[index]
|
||||
pair.back = false
|
||||
setTimeout(() => {
|
||||
pair.front = true
|
||||
pair.back = true
|
||||
}, 250)
|
||||
}, 250)
|
||||
} else {
|
||||
open.value = true
|
||||
text.value = list[index]
|
||||
}
|
||||
}}
|
||||
>
|
||||
{text.value ? '换' : '开始'}
|
||||
{open.value ? '换' : '开始'}
|
||||
</button>
|
||||
<span
|
||||
class={
|
||||
'text-[12px] text-[#333] absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2'
|
||||
}
|
||||
>
|
||||
{text.value}
|
||||
</span>
|
||||
|
||||
<div class={'w-full h-full absolute left-0 top-0 overflow-hidden'}>
|
||||
<Transition name="eat">
|
||||
{pair.front && (
|
||||
<div class={'flex items-center justify-center w-full h-full'}>
|
||||
<span
|
||||
class={
|
||||
'text-[12px] text-[#333] absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2'
|
||||
}
|
||||
>
|
||||
{text.value}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</Transition>
|
||||
<Transition name="neweat">
|
||||
{pair.back && (
|
||||
<div
|
||||
class={
|
||||
'flex items-center justify-center w-full h-full left-0 top-[-130px] absolute '
|
||||
}
|
||||
>
|
||||
<span
|
||||
class={
|
||||
'text-[12px] text-[#333] absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2'
|
||||
}
|
||||
>
|
||||
{text.value}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</Transition>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!text.value && (
|
||||
<>
|
||||
<span class={'text-[24px] mt-[24px] text-[#333]'}>今天吃什么</span>
|
||||
|
|
|
@ -29,7 +29,6 @@ export default defineComponent(() => {
|
|||
watch(
|
||||
selectType,
|
||||
(val) => {
|
||||
console.log(val);
|
||||
appList.value = []
|
||||
loading.value = true
|
||||
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
import useLayoutStore from '@/layout/useLayoutStore'
|
||||
import request from '@/utils/request'
|
||||
import { addIcons, OhVueIcon } from 'oh-vue-icons'
|
||||
import { computed, defineComponent, onMounted, ref, watch, type CSSProperties } from 'vue'
|
||||
import { FaChevronLeft } from 'oh-vue-icons/icons'
|
||||
import PlayImg from '~/icons/game_video_bg_play.png'
|
||||
import type { CarouselRef } from 'ant-design-vue/es/carousel'
|
||||
import { randomNum } from '@/utils/tool'
|
||||
import jump from '@/utils/jump'
|
||||
addIcons(FaChevronLeft)
|
||||
interface Owner {
|
||||
face: string
|
||||
mid: number
|
||||
name: string
|
||||
}
|
||||
|
||||
interface GameData {
|
||||
_id: string
|
||||
aid: number
|
||||
ctime: number
|
||||
duration: number
|
||||
owner: Owner
|
||||
pic: string
|
||||
rid: string
|
||||
time: string
|
||||
title: string
|
||||
type: string
|
||||
}
|
||||
export default defineComponent(() => {
|
||||
const list = ref<GameData[]>([])
|
||||
const currentIndex = ref(-1)
|
||||
|
||||
const current = computed(() => {
|
||||
if (currentIndex.value === -1) {
|
||||
return null
|
||||
} else {
|
||||
return list.value[currentIndex.value]
|
||||
}
|
||||
})
|
||||
watch(
|
||||
() => useLayoutStore().state.current,
|
||||
(val) => {
|
||||
const type = val === 0 ? 'game' : val === 1 ? 'know' : 'ent'
|
||||
request<GameData[]>('GET', `/api/hotVideo?type=${type}`).then((res) => {
|
||||
list.value = res
|
||||
currentIndex.value = randomNum(0, res.length)
|
||||
})
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
onMounted(() => {
|
||||
setInterval(() => {
|
||||
currentIndex.value = currentIndex.value === list.value.length - 1 ? 0 : currentIndex.value + 1
|
||||
}, 7000)
|
||||
})
|
||||
return () => (
|
||||
<div class="w-full h-full p-2 bg-[#17212d] relative flex flex-col ">
|
||||
<img
|
||||
src={PlayImg}
|
||||
class={
|
||||
'absolute z-10 w-[40px] bg-[#ffffff24] rounded-lg backdrop-blur-sm left-1/2 top-10 -translate-x-1/2'
|
||||
}
|
||||
></img>
|
||||
|
||||
{
|
||||
<div
|
||||
class={'w-full h-[92px] rounded-xl relative group'}
|
||||
onClick={() => {
|
||||
jump('https://www.bilibili.com/video/av' + current.value?.aid)
|
||||
}}
|
||||
style={{
|
||||
backgroundImage: `url('${current.value?.pic}')`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center',
|
||||
backgroundRepeat: 'no-repeat'
|
||||
}}
|
||||
>
|
||||
<div
|
||||
class={
|
||||
'absolute bottom-0 left-1/2 -translate-x-1/2 pb-2 w-[300px] flex flex-col text-white '
|
||||
}
|
||||
></div>
|
||||
<div
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
|
||||
currentIndex.value =
|
||||
currentIndex.value === 0 ? list.value.length - 1 : currentIndex.value - 1
|
||||
}}
|
||||
class="absolute hidden bottom-[20px] group-hover:flex items-center justify-center left-[0px] w-[22px] h-[22px] bg-white/30 rounded"
|
||||
>
|
||||
<OhVueIcon name={FaChevronLeft.name} class={'text-white/80'}></OhVueIcon>
|
||||
</div>
|
||||
<div
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
currentIndex.value =
|
||||
currentIndex.value === list.value.length - 1 ? 0 : currentIndex.value + 1
|
||||
}}
|
||||
class="absolute hidden bottom-[20px] group-hover:flex items-center justify-center right-[0px] rotate-180 w-[22px] h-[22px] bg-white/30 rounded"
|
||||
>
|
||||
<OhVueIcon name={FaChevronLeft.name} class={'text-white/80'}></OhVueIcon>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<span class="text-[14px] mt-2 text-ellipsis overflow-hidden text-white line-clamp-2">
|
||||
{current.value?.title}
|
||||
</span>
|
||||
<span class="text-[12px] opacity-60 text-white">{current.value?.owner.name}</span>
|
||||
</div>
|
||||
)
|
||||
})
|
|
@ -0,0 +1,42 @@
|
|||
import useLayoutStore from '@/layout/useLayoutStore'
|
||||
import jump from '@/utils/jump'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent(() => {
|
||||
const layout = useLayoutStore()
|
||||
return () => (
|
||||
<div
|
||||
class="w-full h-full flex items-center px-3"
|
||||
style={{
|
||||
background: `rgb(23,33,46)`,
|
||||
backgroundSize: 'cover'
|
||||
}}
|
||||
onClick={() => {
|
||||
jump(
|
||||
'https://www.bilibili.com/v' +
|
||||
(layout.state.current === 0 ? '/game' : layout.state.current === 1 ? '/knowledge' : '/ent')
|
||||
)
|
||||
}}
|
||||
>
|
||||
<img class={'w-[58px] h-[58px]'} src={'/tab/icons/game_video.png'}></img>
|
||||
<div class={'flex-1 flex justify-center'}>
|
||||
<div class="flex-col flex">
|
||||
<span class={'text-[16px] text-white'}>
|
||||
{useLayoutStore().state.current === 0
|
||||
? '游戏'
|
||||
: useLayoutStore().state.current === 1
|
||||
? '学习'
|
||||
: '娱乐'}
|
||||
视频
|
||||
</span>
|
||||
<div class={'flex items-center text-[#fffc] text-[12px] '}>
|
||||
立即查看
|
||||
<div>
|
||||
<img src="/tab/icons/gt.png"></img>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
|
@ -13,6 +13,18 @@ export default {
|
|||
h: 2,
|
||||
label: '大',
|
||||
component: asyncLoader(() => import('./Large'))
|
||||
},
|
||||
{
|
||||
w: 2,
|
||||
h: 2,
|
||||
label: '中',
|
||||
component: asyncLoader(() => import('./Middle'))
|
||||
},
|
||||
{
|
||||
w: 2,
|
||||
h: 1,
|
||||
label: '小',
|
||||
component: asyncLoader(() => import('./Small'))
|
||||
}
|
||||
]
|
||||
} as Widget
|
||||
|
|
|
@ -114,6 +114,7 @@ export default defineComponent(() => {
|
|||
trriger.value &&
|
||||
<MilkdownProvider >
|
||||
<Editor
|
||||
|
||||
class={"w-full h-full "}
|
||||
modelValue={store.state.list[currentIndex.value]?.content || ''} onUpdate:modelValue={(e) => {
|
||||
if (store.state.list[currentIndex.value]) {
|
||||
|
|
|
@ -1,72 +1,63 @@
|
|||
import { Milkdown, useEditor } from '@milkdown/vue';
|
||||
import { defaultValueCtx, Editor, rootCtx } from '@milkdown/kit/core';
|
||||
import { Milkdown, useEditor } from '@milkdown/vue'
|
||||
import { defaultValueCtx, Editor, rootCtx } from '@milkdown/kit/core'
|
||||
import { nord } from '@milkdown/theme-nord'
|
||||
import { commonmark } from '@milkdown/kit/preset/commonmark'
|
||||
import { gfm } from '@milkdown/kit/preset/gfm';
|
||||
import { defineComponent, watch} from 'vue';
|
||||
import { gfm } from '@milkdown/kit/preset/gfm'
|
||||
import { defineComponent } from 'vue'
|
||||
import { menu, menuConfigCtx, type MenuConfigItem } from '@milkdown-lab/plugin-menu'
|
||||
import { listener, listenerCtx } from '@milkdown/kit/plugin/listener';
|
||||
|
||||
|
||||
import { listener, listenerCtx } from '@milkdown/kit/plugin/listener'
|
||||
const menuItems: MenuConfigItem[][] = [
|
||||
[
|
||||
{
|
||||
type: 'button',
|
||||
content: 'B',
|
||||
// commandKey
|
||||
key: 'ToggleStrong',
|
||||
},
|
||||
{
|
||||
type: 'button',
|
||||
content: 'I',
|
||||
key: 'ToggleEmphasis',
|
||||
},
|
||||
{
|
||||
type: 'button',
|
||||
content: 'S',
|
||||
key: 'ToggleStrikeThrough',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
type: 'button',
|
||||
content: 'B',
|
||||
// commandKey
|
||||
key: 'ToggleStrong'
|
||||
},
|
||||
{
|
||||
type: 'button',
|
||||
content: 'I',
|
||||
key: 'ToggleEmphasis'
|
||||
},
|
||||
{
|
||||
type: 'button',
|
||||
content: 'S',
|
||||
key: 'ToggleStrikeThrough'
|
||||
}
|
||||
]
|
||||
]
|
||||
export default defineComponent({
|
||||
props: {
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: '',
|
||||
}
|
||||
},
|
||||
emits: ['update:modelValue'],
|
||||
setup: (props, ct) => {
|
||||
|
||||
useEditor((root) => {
|
||||
return Editor.make()
|
||||
.config(nord)
|
||||
.config((ctx) => {
|
||||
const listener = ctx.get(listenerCtx);
|
||||
ctx.set(menuConfigCtx.key, {
|
||||
attributes: { class: 'milkdown-menu', 'data-menu': 'true' },
|
||||
items: menuItems,
|
||||
})
|
||||
ctx.set(rootCtx, document.querySelector('#app'))
|
||||
listener.markdownUpdated((ctx, markdown, prevMarkdown) => {
|
||||
if (markdown !== prevMarkdown) {
|
||||
ct.emit('update:modelValue', markdown)
|
||||
}
|
||||
})
|
||||
ctx.set(rootCtx, root)
|
||||
ctx.set(defaultValueCtx, props.modelValue || ' ')
|
||||
})
|
||||
.use(listener)
|
||||
.use(commonmark)
|
||||
.use(gfm)
|
||||
.use(menu)
|
||||
|
||||
|
||||
})
|
||||
return () => (
|
||||
<Milkdown />
|
||||
|
||||
)
|
||||
props: {
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
emits: ['update:modelValue'],
|
||||
setup: (props, ct) => {
|
||||
useEditor((root) => {
|
||||
return Editor.make()
|
||||
.config(nord)
|
||||
.config((ctx) => {
|
||||
const listener = ctx.get(listenerCtx)
|
||||
ctx.set(menuConfigCtx.key, {
|
||||
attributes: { class: 'milkdown-menu', 'data-menu': 'true' },
|
||||
items: menuItems
|
||||
})
|
||||
ctx.set(rootCtx, document.querySelector('#app'))
|
||||
listener.markdownUpdated((ctx, markdown, prevMarkdown) => {
|
||||
if (markdown !== prevMarkdown) {
|
||||
ct.emit('update:modelValue', markdown)
|
||||
}
|
||||
})
|
||||
ctx.set(rootCtx, root)
|
||||
ctx.set(defaultValueCtx, props.modelValue || ' ')
|
||||
})
|
||||
.use(listener)
|
||||
.use(commonmark)
|
||||
.use(gfm)
|
||||
.use(menu)
|
||||
})
|
||||
return () => <Milkdown />
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { defineStore } from "pinia";
|
||||
import { reactive } from "vue";
|
||||
import { v4 as uuid } from "uuid"
|
||||
import dayjs from "dayjs";
|
||||
import { defineStore } from 'pinia'
|
||||
import { reactive } from 'vue'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
import dayjs from 'dayjs'
|
||||
export const DEFALUT_DATA = {
|
||||
content: `
|
||||
content: `
|
||||
欢迎来到FatfoxTab新标签页平台!在这里您将发现海量有趣的内容和实用的工具。
|
||||
|
||||
|
||||
|
@ -104,34 +104,43 @@ FatfoxTab新标签页共分为四个模式;
|
|||
更多新功能正在加速开发中,敬请期待...
|
||||
|
||||
`,
|
||||
title: "FatFoxTab指南",
|
||||
date: 1730877843004,
|
||||
id: "defautId"
|
||||
};
|
||||
export type NotepadItem = {
|
||||
title: string
|
||||
content: string
|
||||
id: string
|
||||
date: number
|
||||
pin: boolean
|
||||
title: 'FatFoxTab指南',
|
||||
date: 1730877843004,
|
||||
id: 'defautId',
|
||||
pin: false
|
||||
}
|
||||
export default defineStore("notepad", () => {
|
||||
export type NotepadItem = {
|
||||
title: string
|
||||
content: string
|
||||
id: string
|
||||
date: number
|
||||
pin: boolean
|
||||
}
|
||||
export default defineStore(
|
||||
'notepad',
|
||||
() => {
|
||||
const state = reactive({
|
||||
list: [DEFALUT_DATA] as NotepadItem[]
|
||||
list: [DEFALUT_DATA] as NotepadItem[]
|
||||
})
|
||||
const addNewNote = () => {
|
||||
state.list.unshift({
|
||||
id: uuid(),
|
||||
title: '',
|
||||
date: dayjs().valueOf(),
|
||||
content: '',
|
||||
pin: false
|
||||
})
|
||||
state.list.unshift({
|
||||
id: uuid(),
|
||||
title: '',
|
||||
date: dayjs().valueOf(),
|
||||
content: '',
|
||||
pin: false
|
||||
})
|
||||
}
|
||||
const reset = () => {
|
||||
state.list = [DEFALUT_DATA]
|
||||
}
|
||||
return {
|
||||
state,
|
||||
addNewNote
|
||||
state,
|
||||
addNewNote,
|
||||
reset
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
persist: true
|
||||
})
|
||||
}
|
||||
)
|
||||
|
|
|
@ -83,13 +83,13 @@ export default defineComponent(() => {
|
|||
>
|
||||
<img src={item.icon} alt="game icon" class={'w-[37px] h-[37px] rounded'}></img>
|
||||
<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>
|
||||
<span
|
||||
class={
|
||||
'text-[#fff9] text-[12px] whitespace-nowrap text-ellipsis overflow-hidden'
|
||||
}
|
||||
>
|
||||
{item.des}
|
||||
{item?.des}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -26,7 +26,7 @@ export default defineComponent(() => {
|
|||
'w-full bg-white/20 text-center rounded text-[14px] overflow-hidden text-ellipsis whitespace-nowrap'
|
||||
}
|
||||
>
|
||||
{store.state.list[0] ? store.state.list[0].title : '无目标'}
|
||||
{store.state.list ? store.state.list.filter((val) => !val.isCompleted).pop()?.title : '无目标'}
|
||||
</div>
|
||||
<span class={'text-[42px] mb-1'}>
|
||||
{store.state.beginTime < 0 ? '15:00' : formatSeconds(store.remainingTime)}
|
||||
|
|
|
@ -31,7 +31,7 @@ export default defineComponent(() => {
|
|||
// 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) => (
|
||||
}).map((item, _) => (
|
||||
<div
|
||||
key={item.id}
|
||||
onClick={() => {
|
||||
|
@ -47,7 +47,11 @@ export default defineComponent(() => {
|
|||
)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
store.state.list[idx].isCompleted = !item.isCompleted
|
||||
const idx = store.state.list.findIndex(val => val.id === item.id)
|
||||
if (idx !== -1) {
|
||||
store.state.list[idx].isCompleted = !item.isCompleted
|
||||
|
||||
}
|
||||
}}>
|
||||
{
|
||||
!item.isCompleted &&
|
||||
|
|
|
@ -39,20 +39,21 @@ export const musicList = [
|
|||
music: 'https://newfatfox.oss-cn-beijing.aliyuncs.com/admin/music/AWonderfulStore.mp3'
|
||||
}
|
||||
]
|
||||
const initData = {
|
||||
list: [] as TomatoTarget[],
|
||||
timeList: [] as number[],
|
||||
isPlaying: false as boolean,
|
||||
selectMusic: 0,
|
||||
isStart: false as boolean,
|
||||
beginTime: -1 as number,
|
||||
}
|
||||
export default defineStore("work", () => {
|
||||
const state = reactive({
|
||||
list: [] as TomatoTarget[],
|
||||
timeList: [] as number[],
|
||||
isPlaying: false as boolean,
|
||||
selectMusic: 0,
|
||||
isStart: false as boolean,
|
||||
beginTime: -1 as number,
|
||||
})
|
||||
const state = reactive({ ...initData })
|
||||
const audio = new Audio()
|
||||
const time = useTimeStore()
|
||||
const remainingTime = computed(() => {
|
||||
|
||||
return dayjs(state.beginTime).add(1, 'minute').diff(dayjs(time.date), 'second')
|
||||
return dayjs(state.beginTime).add(15, 'minute').diff(dayjs(time.date), 'second')
|
||||
})
|
||||
|
||||
const stopTomatoTime = () => {
|
||||
|
@ -91,7 +92,7 @@ export default defineStore("work", () => {
|
|||
|
||||
}
|
||||
watch(remainingTime, (val) => {
|
||||
|
||||
|
||||
if (val < 0) {
|
||||
stopTomatoTime()
|
||||
|
||||
|
@ -117,7 +118,9 @@ export default defineStore("work", () => {
|
|||
return state.list.filter(val => dayjs(val.finishTime).isSame(dayjs().subtract(1, 'day'), 'day') && val.isCompleted).length
|
||||
|
||||
})
|
||||
|
||||
const reset = () => {
|
||||
Object.assign(state, { ...initData })
|
||||
}
|
||||
return {
|
||||
state,
|
||||
openShowModel,
|
||||
|
@ -131,7 +134,8 @@ export default defineStore("work", () => {
|
|||
yestodayHour,
|
||||
todayFinishTarget,
|
||||
yesFinishTarget,
|
||||
setTrack
|
||||
setTrack,
|
||||
reset
|
||||
}
|
||||
}, {
|
||||
persist: true
|
||||
|
|
Loading…
Reference in New Issue