305 lines
9.6 KiB
TypeScript
305 lines
9.6 KiB
TypeScript
import { computed, defineComponent, inject, onMounted, reactive, ref, watch } from 'vue'
|
||
import useLayoutStore from '../useLayoutStore'
|
||
import { Form, Input } from 'ant-design-vue'
|
||
import { OhVueIcon, addIcons } from 'oh-vue-icons'
|
||
import { MdUpload, MdImage, MdCheck } from 'oh-vue-icons/icons'
|
||
import useLink from '../../utils/useLink'
|
||
import { v4 as uuid } from 'uuid'
|
||
import type { Block } from '../layout.types'
|
||
import 'vue3-colorpicker/style.css'
|
||
import { globalToast } from '@/main'
|
||
import UploadAndCut from '@/utils/UploadAndCut'
|
||
import { AddToToken } from './AdderPage'
|
||
import useAdderPageStore, { type EditBlockItemType } from './useAdderPageStore'
|
||
import useRouterStore from '@/useRouterStore'
|
||
import NativeColorPicker from '@/utils/NativeColorPicker'
|
||
addIcons(MdUpload, MdImage, MdCheck)
|
||
|
||
const TypeSelector = defineComponent({
|
||
props: {
|
||
value: {
|
||
type: Number,
|
||
default: 0
|
||
},
|
||
icon: {
|
||
type: String,
|
||
default: ''
|
||
},
|
||
text: {
|
||
type: String,
|
||
default: ''
|
||
},
|
||
color: {
|
||
type: String,
|
||
default: ''
|
||
},
|
||
background: {
|
||
type: String,
|
||
default: ''
|
||
},
|
||
name: {
|
||
type: String,
|
||
default: ''
|
||
}
|
||
},
|
||
emits: {
|
||
'update:value': (() => true) as (val: number) => boolean,
|
||
'update:icon': (() => true) as (val: string) => boolean
|
||
},
|
||
setup(props, ctx) {
|
||
const layout = useLayoutStore()
|
||
return () => (
|
||
<div class="flex gap-4">
|
||
<div class={'flex justify-center flex-col items-center gap-y-1'}>
|
||
<div
|
||
class="w-[47px] relative h-[47px] bg-center bg-no-repeat bg-cover rounded-lg overflow-hidden flex justify-center items-center cursor-pointer hover:scale-105 transition-all"
|
||
style={{
|
||
backgroundImage: `url('${props.icon}')`,
|
||
backgroundColor: props.icon ? '' : 'rgba(0,0,0,0.2)'
|
||
}}
|
||
onClick={() => {
|
||
ctx.emit('update:value', 0)
|
||
}}
|
||
>
|
||
{!props.icon && <img src={'/tab/icons/bgGameCloud.png'}></img>}
|
||
{props.value === 0 && (
|
||
<div
|
||
class={
|
||
'w-[20px] h-[20px] rounded bg-white/50 flex items-center justify-center absolute right-0 bottom-0'
|
||
}
|
||
>
|
||
<OhVueIcon name="md-check" fill="red" scale={0.8}></OhVueIcon>
|
||
</div>
|
||
)}
|
||
</div>
|
||
<span class={'text-[12px]'}>默认</span>
|
||
</div>
|
||
<div class={'flex justify-center flex-col items-center gap-y-1 '}>
|
||
<div
|
||
class="w-[44px] relative h-[44px] bg-center bg-no-repeat bg-cover rounded-lg overflow-hidden flex justify-center items-center cursor-pointer hover:scale-105 transition-all"
|
||
style={{
|
||
backgroundColor: props.background || 'transparent'
|
||
}}
|
||
onClick={() => {
|
||
ctx.emit('update:value', 1)
|
||
}}
|
||
>
|
||
<span
|
||
class="text-[16px]"
|
||
style={{
|
||
color: props.color
|
||
}}
|
||
>
|
||
{props.text
|
||
? props.text.substring(0, 2)
|
||
: props.name.substring(0, 2).toLocaleUpperCase() || 'A'}
|
||
</span>
|
||
{props.value === 1 && (
|
||
<div
|
||
class={
|
||
'w-[20px] h-[20px] rounded bg-white/50 flex items-center justify-center absolute right-0 bottom-0'
|
||
}
|
||
>
|
||
<OhVueIcon name="md-check" fill="red" scale={0.8}></OhVueIcon>
|
||
</div>
|
||
)}
|
||
</div>
|
||
<span class={'text-[12px]'}>文字</span>
|
||
</div>
|
||
<div class={'flex justify-center flex-col items-center gap-y-1'}>
|
||
<div class="w-[44px] h-[44px] rounded-lg flex overflow-hidden justify-center items-center bg-white shadow cursor-pointer hover:scale-105 transition-all">
|
||
{/* <ImageUploader
|
||
width={44}
|
||
onUpdate:value={(e) => {
|
||
ctx.emit('update:icon', e)
|
||
}}
|
||
></ImageUploader> */}
|
||
<UploadAndCut
|
||
onUpdate:value={(e) => {
|
||
ctx.emit('update:icon', e)
|
||
}}
|
||
></UploadAndCut>
|
||
</div>
|
||
<span class={'text-[12px]'}>自定义</span>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
})
|
||
export default defineComponent(() => {
|
||
const layout = useLayoutStore()
|
||
const form = reactive({
|
||
link: '',
|
||
name: '',
|
||
text: '',
|
||
background: 'rgb(247,169,78)',
|
||
color: 'rgb(255,255,255)',
|
||
icon: '',
|
||
type: 0 // 0 默认,1 文字
|
||
} as EditBlockItemType)
|
||
const isGame = computed(() => layout.state.current === 0)
|
||
const debounced = ref('')
|
||
const store = useAdderPageStore()
|
||
onMounted(() => {
|
||
if (store.editBlockItem !== null) {
|
||
form.link = store.editBlockItem.link
|
||
form.name = store.editBlockItem.name
|
||
form.icon = store.editBlockItem.icon
|
||
form.text = store.editBlockItem.text
|
||
form.background = store.editBlockItem.background
|
||
form.color = store.editBlockItem.color
|
||
form.type = store.editBlockItem.type
|
||
}
|
||
})
|
||
watch(
|
||
() => form.link,
|
||
(val, _, onCleanup) => {
|
||
const it = setTimeout(() => {
|
||
debounced.value = val
|
||
}, 500)
|
||
onCleanup(() => {
|
||
clearTimeout(it)
|
||
})
|
||
}
|
||
)
|
||
|
||
const info = useLink(debounced)
|
||
|
||
watch(info, (val) => {
|
||
if (val.name) form.name = val.name
|
||
if (val.icon) form.icon = val.icon
|
||
})
|
||
watch(
|
||
() => form.type,
|
||
(cur, pre) => {
|
||
if (cur === 1) {
|
||
if (!form.name) {
|
||
globalToast.error('文字图标请至少填写文字或者名称')
|
||
form.type = pre
|
||
return
|
||
} else {
|
||
form.text = form.name.substring(0, 2).toLocaleUpperCase()
|
||
}
|
||
}
|
||
}
|
||
)
|
||
const addTo = inject(AddToToken)
|
||
return () => (
|
||
<div
|
||
class={
|
||
'absolute left-0 top-0 w-full h-full rounded-2xl py-5 pl-6 pr-[30%] ' +
|
||
(isGame.value ? 'bg-white/20' : 'bg-white/70')
|
||
}
|
||
>
|
||
<Form>
|
||
<Form.Item label="地址" class={'relative'}>
|
||
<Input
|
||
v-model:value={form.link}
|
||
placeholder="搜索想要添加的网址导航"
|
||
class={isGame?.value ? '' : ' bg-black/10 '}
|
||
/>
|
||
<span
|
||
class={'absolute right-[-70px] top-1/2 -translate-y-1/2 cursor-pointer'}
|
||
onClick={() => {
|
||
debounced.value = debounced.value + ' '
|
||
}}
|
||
>
|
||
获取地址
|
||
</span>
|
||
</Form.Item>
|
||
<Form.Item label="名称">
|
||
<Input v-model:value={form.name} class={isGame?.value ? '' : ' bg-black/10 '} />
|
||
</Form.Item>
|
||
<Form.Item label="图标">
|
||
<TypeSelector
|
||
v-model:value={form.type}
|
||
v-model:icon={form.icon}
|
||
name={form.name}
|
||
text={form.text}
|
||
color={form.color}
|
||
background={form.background}
|
||
/>
|
||
</Form.Item>
|
||
{form.type === 1 && (
|
||
<>
|
||
<Form.Item label="图标背景">
|
||
<NativeColorPicker
|
||
size={30}
|
||
colorList={[
|
||
'rgb(227, 127, 53)',
|
||
'rgb(239, 195, 57)',
|
||
'rgb(65, 201, 117)',
|
||
'rgb(67, 195, 195)',
|
||
'rgb(97, 182, 255)',
|
||
'rgb(153, 91, 179)'
|
||
]}
|
||
value={form.background}
|
||
onUpdate:value={(e) => {
|
||
form.background = e
|
||
}}
|
||
></NativeColorPicker>
|
||
</Form.Item>
|
||
<Form.Item label="图标文字">
|
||
<Input
|
||
v-model:value={form.text}
|
||
maxlength={2}
|
||
class={isGame?.value ? '' : ' bg-black/10 '}
|
||
/>
|
||
</Form.Item>
|
||
</>
|
||
)}
|
||
<Form.Item label=" " colon={false}>
|
||
<button
|
||
class={
|
||
'outline-none ml-[23px] mt-2 flex items-center hover:opacity-90 text-[16px] justify-center gap-x-2 text-white w-[94px] h-[40px] rounded-lg'
|
||
}
|
||
style={{
|
||
background: 'linear-gradient(180deg,#ffaa4e 0%,#ff6227 100%)'
|
||
}}
|
||
onClick={() => {
|
||
if (form.type === 1 && !form.text && !form.name) {
|
||
globalToast.error('文字图标请至少填写文字或者名称')
|
||
return
|
||
}
|
||
if (!form.link) {
|
||
globalToast.warning('请输入网站链接')
|
||
return
|
||
}
|
||
if (!form.name) {
|
||
globalToast.warning('请输入网站名称')
|
||
return
|
||
}
|
||
if (store.editBlockItem !== null) {
|
||
console.log(123)
|
||
layout.changeBlock(form, store.editBlockItem.id)
|
||
useRouterStore().back()
|
||
store.editBlockItem = null
|
||
} else {
|
||
const id = uuid()
|
||
const data: Block = {
|
||
id,
|
||
link: form.link,
|
||
name: '',
|
||
icon: form.type === 0 ? form.icon || info.icon : '',
|
||
background: form.type === 0 ? '' : form.background,
|
||
color: form.type === 0 ? '' : form.color,
|
||
w: 1,
|
||
h: 1,
|
||
text:
|
||
form.type === 0
|
||
? ''
|
||
: form.text || form.name.substring(0, 2).toLocaleUpperCase(),
|
||
label: form.name
|
||
}
|
||
layout.addBlock(data, addTo?.value)
|
||
}
|
||
}}
|
||
>
|
||
确定
|
||
</button>
|
||
</Form.Item>
|
||
</Form>
|
||
</div>
|
||
)
|
||
})
|