Compare commits
No commits in common. "fc7b1bdad5ee971906379beb4e4faa36250b225f" and "05c283ee4932379f40df67c86b261a56a30d7456" have entirely different histories.
fc7b1bdad5
...
05c283ee49
|
@ -17,7 +17,6 @@
|
||||||
"@fingerprintjs/fingerprintjs": "^4.4.3",
|
"@fingerprintjs/fingerprintjs": "^4.4.3",
|
||||||
"ali-oss": "^6.21.0",
|
"ali-oss": "^6.21.0",
|
||||||
"ant-design-vue": "4.x",
|
"ant-design-vue": "4.x",
|
||||||
"clsx": "^2.1.1",
|
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"localforage": "^1.10.0",
|
"localforage": "^1.10.0",
|
||||||
"lunar-typescript": "^1.7.5",
|
"lunar-typescript": "^1.7.5",
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
export const aIUrl = 'https://metaso.cn/?s=uitab&referrer_s=uitab&q='
|
export const aIUrl = 'https://metaso.cn/?s=uitab&referrer_s=uitab&q='
|
||||||
export const translateUrl = 'https://fanyi.baidu.com/mtpe-individual/multimodal?lang=zh2en&query='
|
export const translateUrl = 'https://fanyi.baidu.com/mtpe-individual/multimodal?lang=zh2en&query='
|
||||||
|
// 获取 ossKey 地址
|
||||||
|
export const ossKeyUrl = import.meta.env.PROD
|
||||||
|
? 'http://192.168.110.28:8300/ossKey'
|
||||||
|
: 'http://192.168.110.28:8300/ossKey'
|
||||||
// 获取 oss 根目录地址
|
// 获取 oss 根目录地址
|
||||||
export const ossBase = import.meta.env.PROD
|
export const ossBase = import.meta.env.PROD
|
||||||
? 'http://btab.oss-cn-hangzhou.aliyuncs.com'
|
? 'http://btab.oss-cn-hangzhou.aliyuncs.com'
|
||||||
: 'http://btab.oss-cn-hangzhou.aliyuncs.com'
|
: 'http://btab.oss-cn-hangzhou.aliyuncs.com'
|
||||||
|
|
||||||
// 后端地址
|
|
||||||
export const apiBase = import.meta.env.PROD
|
export const apiBase = import.meta.env.PROD
|
||||||
? 'http://192.168.110.28:8300'
|
? 'http://192.168.110.28:8300'
|
||||||
: 'http://192.168.110.28:8300'
|
: 'http://192.168.110.28:8300'
|
||||||
|
|
||||||
// 后端 cdn 加速地址
|
|
||||||
export const cdnBase = import.meta.env.PROD ? apiBase : apiBase
|
export const cdnBase = import.meta.env.PROD ? apiBase : apiBase
|
||||||
|
|
|
@ -4,7 +4,6 @@ import useLayoutStore from '../useLayoutStore'
|
||||||
import { OhVueIcon, addIcons } from 'oh-vue-icons'
|
import { OhVueIcon, addIcons } from 'oh-vue-icons'
|
||||||
import { MdKeyboardcommandkey, FaCompass, FaPencilRuler } from 'oh-vue-icons/icons'
|
import { MdKeyboardcommandkey, FaCompass, FaPencilRuler } from 'oh-vue-icons/icons'
|
||||||
import CustomAdder from './CustomAdder'
|
import CustomAdder from './CustomAdder'
|
||||||
import clsx from 'clsx'
|
|
||||||
addIcons(MdKeyboardcommandkey, FaCompass, FaPencilRuler)
|
addIcons(MdKeyboardcommandkey, FaCompass, FaPencilRuler)
|
||||||
|
|
||||||
const ItemButton = defineComponent({
|
const ItemButton = defineComponent({
|
||||||
|
@ -54,7 +53,7 @@ export default defineComponent(() => {
|
||||||
const isGame = computed(() => layout.state.current === 0)
|
const isGame = computed(() => layout.state.current === 0)
|
||||||
const type = ref(1)
|
const type = ref(1)
|
||||||
return () => (
|
return () => (
|
||||||
<div class={clsx("w-full h-full relative flex", isGame.value&&"bg-[#2c2e3e]")}>
|
<div class="w-full h-full relative flex">
|
||||||
{isGame.value && <AdderPageBack />}
|
{isGame.value && <AdderPageBack />}
|
||||||
<div
|
<div
|
||||||
class={
|
class={
|
||||||
|
@ -90,7 +89,7 @@ export default defineComponent(() => {
|
||||||
<div
|
<div
|
||||||
class={
|
class={
|
||||||
'w-0 h-full flex-grow relative z-10 flex flex-col ' +
|
'w-0 h-full flex-grow relative z-10 flex flex-col ' +
|
||||||
(isGame.value ? '' : 'bg-white/80 backdrop-blur')
|
(isGame.value ? '' : 'bg-white/40 backdrop-blur')
|
||||||
}
|
}
|
||||||
onContextmenu={(e) => e.stopPropagation()}
|
onContextmenu={(e) => e.stopPropagation()}
|
||||||
>
|
>
|
||||||
|
|
|
@ -10,7 +10,7 @@ export default defineComponent(() => () => (
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
d="M16 16C20 11.5 20 5 20 5H880.084C880.084 5 879.089 12.4299 883.067 16.8879C887.045 21.3458 895 21.8411 895 21.8411V518C895 518 887.045 516.5 883.067 521.5C879.089 526.5 880.084 535 880.084 535H20C20 535 19 528.5 16 524C13 519.5 5 518 5 518V22.5C5 22.5 12 20.5 16 16Z"
|
d="M16 16C20 11.5 20 5 20 5H880.084C880.084 5 879.089 12.4299 883.067 16.8879C887.045 21.3458 895 21.8411 895 21.8411V518C895 518 887.045 516.5 883.067 521.5C879.089 526.5 880.084 535 880.084 535H20C20 535 19 528.5 16 524C13 519.5 5 518 5 518V22.5C5 22.5 12 20.5 16 16Z"
|
||||||
fill="#2c2e3e"
|
fill="#1F2028"
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d="M804.5 26.5C804.5 9.5 793.333 6.83333 789 6H878.5C878.5 6 885.5 6.85714 890 12C894.5 17.1429 894.5 22.5 894.5 22.5V67.5C894.5 67.5 856.5 66.5 853.5 58C850.5 49.5 854 38.5 850.5 30.5C848 25.5 840.5 25 831 27C821.5 29 804 35 804.5 26.5Z"
|
d="M804.5 26.5C804.5 9.5 793.333 6.83333 789 6H878.5C878.5 6 885.5 6.85714 890 12C894.5 17.1429 894.5 22.5 894.5 22.5V67.5C894.5 67.5 856.5 66.5 853.5 58C850.5 49.5 854 38.5 850.5 30.5C848 25.5 840.5 25 831 27C821.5 29 804 35 804.5 26.5Z"
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
import { computed, defineComponent, reactive, ref, watch } from 'vue'
|
import { computed, defineComponent, reactive } from 'vue'
|
||||||
import useLayoutStore from '../useLayoutStore'
|
import useLayoutStore from '../useLayoutStore'
|
||||||
import { ConfigProvider, Form, Input, theme } from 'ant-design-vue'
|
import { ConfigProvider, Form, Input, theme } from 'ant-design-vue'
|
||||||
import { OhVueIcon, addIcons } from 'oh-vue-icons'
|
import { OhVueIcon, addIcons } from 'oh-vue-icons'
|
||||||
import { MdUpload, MdImage, MdCheck } from 'oh-vue-icons/icons'
|
import { MdUpload, MdImage } from 'oh-vue-icons/icons'
|
||||||
import clsx from 'clsx'
|
|
||||||
import ImageUploader from '@/utils/ImageUploader'
|
|
||||||
import useLink from './useLink'
|
|
||||||
|
|
||||||
addIcons(MdUpload, MdImage, MdCheck)
|
addIcons(MdUpload, MdImage)
|
||||||
|
|
||||||
const TypeSelector = defineComponent({
|
const TypeSelector = defineComponent({
|
||||||
props: {
|
props: {
|
||||||
|
@ -39,70 +36,32 @@ const TypeSelector = defineComponent({
|
||||||
setup(props, ctx) {
|
setup(props, ctx) {
|
||||||
return () => (
|
return () => (
|
||||||
<div class="flex gap-4">
|
<div class="flex gap-4">
|
||||||
<div class={'flex justify-center flex-col items-center gap-y-1'}>
|
<div
|
||||||
<div
|
class="w-[64px] h-[65px] bg-center bg-no-repeat bg-cover rounded-lg overflow-hidden flex justify-center items-center cursor-pointer hover:scale-105 transition-all"
|
||||||
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)'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{!props.icon && <OhVueIcon name="md-image" fill="white" scale={1.8} />}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="w-[64px] h-[65px] 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
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="text-[30px]"
|
||||||
style={{
|
style={{
|
||||||
backgroundImage: `url('${props.icon}')`,
|
color: props.color
|
||||||
backgroundColor: props.icon ? '' : 'rgba(0,0,0,0.2)'
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
|
||||||
ctx.emit('update:value', 0)
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{!props.icon && <OhVueIcon name="md-image" fill="white" scale={1.8} />}
|
{props.text ? props.text.substring(0, 2) : 'A'}
|
||||||
{props.value === 0 && (
|
</span>
|
||||||
<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>
|
||||||
<div class={'flex justify-center flex-col items-center gap-y-1 '}>
|
<div class="w-[64px] h-[65px] rounded-lg flex justify-center items-center bg-white shadow cursor-pointer hover:scale-105 transition-all">
|
||||||
<div
|
<OhVueIcon name="md-upload" fill="rgba(0,0,0,0.4)" scale={1.8} />
|
||||||
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
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
|
||||||
ctx.emit('update:value', 1)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="text-[20px]"
|
|
||||||
style={{
|
|
||||||
color: props.color
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{props.text ? props.text.substring(0, 2) : '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 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>
|
|
||||||
</div>
|
|
||||||
<span class={'text-[12px]'}>自定义</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -122,6 +81,7 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
setup(props, ctx) {
|
setup(props, ctx) {
|
||||||
const layout = useLayoutStore()
|
const layout = useLayoutStore()
|
||||||
|
const isGame = computed(() => layout.state.current === 0)
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
link: '',
|
link: '',
|
||||||
name: '',
|
name: '',
|
||||||
|
@ -131,88 +91,41 @@ export default defineComponent({
|
||||||
icon: '',
|
icon: '',
|
||||||
type: 0 // 0 默认,1 文字
|
type: 0 // 0 默认,1 文字
|
||||||
})
|
})
|
||||||
const isGame = computed(() => layout.state.current === 0)
|
|
||||||
const debounced = ref('')
|
|
||||||
watch(
|
|
||||||
() => form.link,
|
|
||||||
(val, _, onCleanup) => {
|
|
||||||
const it = setTimeout(() => {
|
|
||||||
debounced.value = val
|
|
||||||
}, 500)
|
|
||||||
onCleanup(() => {
|
|
||||||
clearTimeout(it)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const info = useLink(debounced)
|
|
||||||
console.log(info);
|
|
||||||
|
|
||||||
watch(info, (val) => {
|
|
||||||
console.log(val);
|
|
||||||
|
|
||||||
if (val.name) form.name = val.name
|
|
||||||
if (val.icon) form.icon = val.icon
|
|
||||||
|
|
||||||
})
|
|
||||||
return () => (
|
return () => (
|
||||||
<div
|
<div
|
||||||
class={
|
class={
|
||||||
'absolute left-0 top-0 w-full h-full rounded-2xl p-5 ' +
|
'absolute left-0 top-0 w-full h-full rounded-lg p-4 ' +
|
||||||
(isGame.value ? 'bg-white/20' : 'bg-white/20')
|
(isGame.value ? 'bg-white/10' : 'bg-white/80')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div class="flex flex-col">
|
<ConfigProvider
|
||||||
<div></div>
|
theme={{
|
||||||
</div>
|
token: isGame.value
|
||||||
<div class={clsx('flex flex-col text-[14px] gap-y-3', isGame.value ? 'text-white' : '')}>
|
? theme.darkAlgorithm(theme.defaultSeed)
|
||||||
<div class={clsx('gap-x-6 flex items-center')}>
|
: theme.defaultAlgorithm(theme.defaultSeed)
|
||||||
<span>地址</span>
|
}}
|
||||||
<input
|
>
|
||||||
v-model={form.link}
|
<Form labelCol={{ span: 6 }} model={form} class="grid grid-cols-2 gap-4" colon={false}>
|
||||||
placeholder="搜索想要添加的网址导航"
|
<Form.Item label="地址" name="link" class="col-span-2" labelCol={{ span: 3 }}>
|
||||||
class={clsx(
|
<Input v-model:value={form.link} />
|
||||||
'w-[350px] rounded-md outline-none h-[40px] px-[10px]',
|
</Form.Item>
|
||||||
isGame.value ? 'bg-black/[.1]' : ''
|
<Form.Item label="名称" name="name">
|
||||||
)}
|
<Input v-model:value={form.name} />
|
||||||
></input>
|
</Form.Item>
|
||||||
<span class={'cursor-pointer'}>获取地址</span>
|
<Form.Item name="type" label=" " class="col-span-2" labelCol={{ span: 3 }}>
|
||||||
</div>
|
<TypeSelector
|
||||||
<div class={clsx('gap-x-6 flex items-center')}>
|
v-model:value={form.type}
|
||||||
<span>名称</span>
|
v-model:icon={form.icon}
|
||||||
<input
|
text={form.text}
|
||||||
v-model={form.name}
|
color={form.color}
|
||||||
placeholder="网站名称"
|
background={form.background}
|
||||||
class={clsx(
|
/>
|
||||||
'w-[350px] rounded-md outline-none h-[40px] px-[10px]',
|
</Form.Item>
|
||||||
isGame.value ? 'bg-black/[.1]' : ''
|
<Form.Item label="图标文字" name="text">
|
||||||
)}
|
<Input v-model:value={form.text} />
|
||||||
></input>
|
</Form.Item>
|
||||||
</div>
|
</Form>
|
||||||
<div class={clsx('gap-x-6 flex items-start')}>
|
</ConfigProvider>
|
||||||
<span>图标</span>
|
|
||||||
<TypeSelector
|
|
||||||
v-model:value={form.type}
|
|
||||||
v-model:icon={form.icon}
|
|
||||||
text={form.text}
|
|
||||||
color={form.color}
|
|
||||||
background={form.background}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class={clsx('gap-x-6 flex items-center')}>
|
|
||||||
<span></span>
|
|
||||||
<button
|
|
||||||
v-model:value={form.name}
|
|
||||||
placeholder="网站名称"
|
|
||||||
class={clsx(
|
|
||||||
'bg-gradient-to-b from-[#ffaa4e] to-[#ff6227] rounded-lg w-[94px] h-[40px] text-[16px] ',
|
|
||||||
isGame.value ? 'bg-black/[.1]' : ''
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
确定
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
import request from '@/utils/request'
|
|
||||||
import { reactive, watch, type Ref } from 'vue'
|
|
||||||
|
|
||||||
export interface LinkInfo {
|
|
||||||
background: string
|
|
||||||
desc: string
|
|
||||||
icon: string
|
|
||||||
link: string
|
|
||||||
name: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function useLink(url: Ref<string>) {
|
|
||||||
const info = reactive<LinkInfo>({
|
|
||||||
background: '',
|
|
||||||
desc: '',
|
|
||||||
icon: '',
|
|
||||||
link: '',
|
|
||||||
name: ''
|
|
||||||
})
|
|
||||||
watch(
|
|
||||||
url,
|
|
||||||
(val) => {
|
|
||||||
if (!val) return
|
|
||||||
const tag = val.match(/(?<=http(s?):\/\/)[^/]*/g)?.[0] || val
|
|
||||||
console.log(tag);
|
|
||||||
|
|
||||||
request<LinkInfo>('GET', `/api/app/pic/info/${tag}`).then((res) => {
|
|
||||||
Object.assign(info, res)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{ immediate: true }
|
|
||||||
)
|
|
||||||
return info
|
|
||||||
}
|
|
|
@ -6,7 +6,6 @@ import { PxHeadset, PxAddBox, PxCheck } from 'oh-vue-icons/icons'
|
||||||
import useRouterStore from '@/useRouterStore'
|
import useRouterStore from '@/useRouterStore'
|
||||||
import useLayoutStore from '../useLayoutStore'
|
import useLayoutStore from '../useLayoutStore'
|
||||||
import useUserStore from '@/user/useUserStore'
|
import useUserStore from '@/user/useUserStore'
|
||||||
import AvatarCircle from '@/user/AvatarCircle'
|
|
||||||
|
|
||||||
initIcons()
|
initIcons()
|
||||||
addIcons(PxHeadset, PxAddBox, PxCheck)
|
addIcons(PxHeadset, PxAddBox, PxCheck)
|
||||||
|
@ -118,7 +117,7 @@ export default defineComponent(() => {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
class="w-[56px] h-[56px] rounded-full border-white border-[2px] border-solid overflow-hidden cursor-pointer"
|
class="w-[56px] h-[56px] bg-white/40 rounded-full border-white border-[2px] border-solid overflow-hidden cursor-pointer"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (user.isLogin) {
|
if (user.isLogin) {
|
||||||
router.path = 'settings-user'
|
router.path = 'settings-user'
|
||||||
|
@ -126,9 +125,7 @@ export default defineComponent(() => {
|
||||||
router.path = 'global-login'
|
router.path = 'global-login'
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
></div>
|
||||||
<AvatarCircle />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{/* 添加页面 */}
|
{/* 添加页面 */}
|
||||||
<Transition name="page-adder">
|
<Transition name="page-adder">
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import AvatarCircle from '@/user/AvatarCircle'
|
|
||||||
import useRouterStore from '@/useRouterStore'
|
import useRouterStore from '@/useRouterStore'
|
||||||
import asyncLoader from '@/utils/asyncLoader'
|
import asyncLoader from '@/utils/asyncLoader'
|
||||||
import { computed, defineComponent, Transition } from 'vue'
|
import { computed, defineComponent, Transition } from 'vue'
|
||||||
|
@ -63,9 +62,7 @@ export default defineComponent(() => {
|
||||||
router.path = 'settings-user'
|
router.path = 'settings-user'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div class="w-12 h-12 relative">
|
<div class="w-12 h-12 rounded-full overflow-hidden bg-black/20"></div>
|
||||||
<AvatarCircle />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<SettingsTab label="壁纸" path="settings-background" />
|
<SettingsTab label="壁纸" path="settings-background" />
|
||||||
<SettingsTab label="图标" path="settings-block" />
|
<SettingsTab label="图标" path="settings-block" />
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
import { defineComponent } from 'vue'
|
|
||||||
import { OhVueIcon, addIcons } from 'oh-vue-icons'
|
|
||||||
import { FaUserAlt } from 'oh-vue-icons/icons'
|
|
||||||
import useUserStore from './useUserStore'
|
|
||||||
|
|
||||||
addIcons(FaUserAlt)
|
|
||||||
|
|
||||||
export default defineComponent(() => {
|
|
||||||
const { profile } = useUserStore()
|
|
||||||
return () => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
class="w-full h-full rounded-full bg-black/20 flex justify-center items-center bg-center bg-no-repeat bg-cover"
|
|
||||||
style={{
|
|
||||||
backgroundImage: `url('${profile?.avatar}')`
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{!profile.avatar && <OhVueIcon name="fa-user-alt" fill="white" scale={1.2} />}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
|
@ -34,10 +34,8 @@ export default defineComponent(() => {
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
测试用
|
测试用
|
||||||
<form>
|
<input placeholder="邮箱" v-model={form.email} />
|
||||||
<input placeholder="邮箱" v-model={form.email} />
|
<input placeholder="密码" type="password" v-model={form.password} />
|
||||||
<input placeholder="密码" type="password" v-model={form.password} />
|
|
||||||
</form>
|
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
request<string>('POST', '/api/user/login', {
|
request<string>('POST', '/api/user/login', {
|
||||||
|
@ -45,7 +43,6 @@ export default defineComponent(() => {
|
||||||
returnType: 'text'
|
returnType: 'text'
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
user.token = res
|
user.token = res
|
||||||
router.path = ''
|
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,86 +1,19 @@
|
||||||
import useRouterStore from '@/useRouterStore'
|
import useRouterStore from '@/useRouterStore'
|
||||||
import { Button, message, Modal, Tag, Tooltip } from 'ant-design-vue'
|
import { Button } from 'ant-design-vue'
|
||||||
import { defineComponent } from 'vue'
|
import { defineComponent } from 'vue'
|
||||||
import AvatarCircle from './AvatarCircle'
|
|
||||||
import useUserStore from './useUserStore'
|
|
||||||
import { EditOutlined, LoginOutlined, LogoutOutlined } from '@ant-design/icons-vue'
|
|
||||||
|
|
||||||
const labelStyle = 'w-16 text-black/60'
|
|
||||||
|
|
||||||
export default defineComponent(() => {
|
export default defineComponent(() => {
|
||||||
const router = useRouterStore()
|
const router = useRouterStore()
|
||||||
const user = useUserStore()
|
|
||||||
return () => (
|
return () => (
|
||||||
<div class="absolute left-0 top-0 w-full h-full p-4 flex flex-col">
|
<div class="absolute left-0 top-0 w-full h-full p-4">
|
||||||
<div class="flex justify-center py-4">
|
this is user
|
||||||
<div class="w-16 h-16 relative">
|
<Button
|
||||||
<AvatarCircle />
|
onClick={() => {
|
||||||
</div>
|
router.path = 'global-login'
|
||||||
</div>
|
}}
|
||||||
{user.isLogin && (
|
>
|
||||||
<div class="h-0 flex-grow py-4 px-12">
|
登录
|
||||||
<div class="flex py-2">
|
</Button>
|
||||||
<div class={labelStyle}>用户名:</div>
|
|
||||||
<div class="w-0 flex-grow overflow-hidden text-ellipsis whitespace-nowrap break-all">
|
|
||||||
{user.profile.username}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex py-2">
|
|
||||||
<div class={labelStyle}>生日:</div> {user.profile.birthday}
|
|
||||||
</div>
|
|
||||||
<div class="flex py-2">
|
|
||||||
<div class={labelStyle}>性别:</div>
|
|
||||||
<Tag color={user.profile.gender === 1 ? 'blue' : 'red'}>
|
|
||||||
{user.profile.gender === 1 ? '男' : '女'}
|
|
||||||
</Tag>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div class="flex justify-around items-center my-10">
|
|
||||||
{user.isLogin ? (
|
|
||||||
<>
|
|
||||||
<Button
|
|
||||||
onClick={() => {
|
|
||||||
router.path = 'global-login'
|
|
||||||
}}
|
|
||||||
icon={<EditOutlined />}
|
|
||||||
>
|
|
||||||
修改个人信息
|
|
||||||
</Button>
|
|
||||||
<Tooltip title="退出登录">
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
danger
|
|
||||||
size="large"
|
|
||||||
icon={<LogoutOutlined />}
|
|
||||||
onClick={() => {
|
|
||||||
Modal.confirm({
|
|
||||||
title: '退出登录',
|
|
||||||
content: '确定要退出登录吗?',
|
|
||||||
onOk: () => {
|
|
||||||
router.path = ''
|
|
||||||
user.logout()
|
|
||||||
message.success('已退出登录')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
></Button>
|
|
||||||
</Tooltip>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
icon={<LoginOutlined />}
|
|
||||||
size="large"
|
|
||||||
onClick={() => {
|
|
||||||
router.path = 'global-login'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
登录
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,48 +1,43 @@
|
||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { computed, reactive, ref, watch } from 'vue'
|
import { computed, ref, watch } from 'vue'
|
||||||
|
|
||||||
interface UserInfo {
|
interface UserInfo {
|
||||||
id: string
|
id: string
|
||||||
username: string
|
username: string
|
||||||
|
created: string
|
||||||
|
vipUntil: string
|
||||||
gender: number
|
gender: number
|
||||||
birthday: string
|
birthday: string
|
||||||
|
brief: string
|
||||||
|
email: string
|
||||||
|
password: string
|
||||||
|
type: string
|
||||||
|
updated: string
|
||||||
avatar: string
|
avatar: string
|
||||||
openId: string
|
openId: string
|
||||||
}
|
}
|
||||||
const defaultUserInfo: UserInfo = {
|
|
||||||
id: '',
|
|
||||||
username: '',
|
|
||||||
gender: 0,
|
|
||||||
birthday: '',
|
|
||||||
avatar: '',
|
|
||||||
openId: ''
|
|
||||||
}
|
|
||||||
export default defineStore('user', () => {
|
export default defineStore('user', () => {
|
||||||
const token = ref(localStorage.getItem('token') || '')
|
const token = ref(localStorage.getItem('token') || '')
|
||||||
watch(token, (val) => {
|
watch(token, (val) => {
|
||||||
localStorage.setItem('token', val)
|
localStorage.setItem('token', val)
|
||||||
})
|
})
|
||||||
const profile = reactive(defaultUserInfo)
|
const profile = ref<null | UserInfo>(null)
|
||||||
watch(
|
watch(
|
||||||
token,
|
token,
|
||||||
(val) => {
|
(val) => {
|
||||||
if (!val) return
|
if (!val) return
|
||||||
request<UserInfo>('GET', '/api/profile').then((res) => {
|
request<UserInfo>('GET', '/api/profile').then((res) => {
|
||||||
Object.assign(profile, res)
|
profile.value = res
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
)
|
)
|
||||||
const isLogin = computed(() => !!token.value && !!profile.id)
|
const isLogin = computed(() => !!token.value && !!profile.value)
|
||||||
const logout = () => {
|
|
||||||
token.value = ''
|
|
||||||
Object.assign(profile, defaultUserInfo)
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
token,
|
token,
|
||||||
profile,
|
profile,
|
||||||
isLogin,
|
isLogin
|
||||||
logout
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -89,7 +89,7 @@ export default defineComponent({
|
||||||
<OhVueIcon name="md-upload" scale={2} fill="rgba(0,0,0,0.2)" />
|
<OhVueIcon name="md-upload" scale={2} fill="rgba(0,0,0,0.2)" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{/* <div class="text-xs mt-1 text-black/60">支持上传 .png, .jpeg, .jpg, .svg</div>{' '} */}
|
<div class="text-xs mt-1 text-black/60">支持上传 .png, .jpeg, .jpg, .svg</div>{' '}
|
||||||
</ConfigProvider>
|
</ConfigProvider>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,20 +1,24 @@
|
||||||
import { ossBase } from './../config'
|
import { ossBase, ossKeyUrl } from './../config'
|
||||||
import OSS from 'ali-oss'
|
import OSS from 'ali-oss'
|
||||||
import { v4 as uuid } from 'uuid'
|
import { v4 as uuid } from 'uuid'
|
||||||
import request from './request'
|
|
||||||
export default async function upload(file: File, root: string) {
|
export default async function upload(file: File, root: string) {
|
||||||
const token = localStorage.getItem('token')
|
const config = await fetch(ossKeyUrl, {
|
||||||
if (!token) {
|
method: 'POST',
|
||||||
throw new Error('尚未登录,无法上传')
|
headers: {
|
||||||
}
|
Authorization:
|
||||||
const config = await request<{
|
'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2NjlkZjA3Y2RhMjkyZTNiZTc0OGM5MmMifQ.9k9-C_Im2r2fONfT6rdAZDxapkqtwGtiVBSen59JDXY'
|
||||||
region: string
|
}
|
||||||
accessKeyId: string
|
}).then(
|
||||||
accessKeySecret: string
|
(res) =>
|
||||||
securityToken: string
|
res.json() as Promise<{
|
||||||
bucket: string
|
region: string
|
||||||
path: string
|
accessKeyId: string
|
||||||
}>('POST', '/api/ossKey')
|
accessKeySecret: string
|
||||||
|
securityToken: string
|
||||||
|
bucket: string
|
||||||
|
path: string
|
||||||
|
}>
|
||||||
|
)
|
||||||
const ext = file.name.split('.').pop()
|
const ext = file.name.split('.').pop()
|
||||||
const path = `${config.path}/${root}/${uuid()}.${ext}`
|
const path = `${config.path}/${root}/${uuid()}.${ext}`
|
||||||
const client = new OSS({
|
const client = new OSS({
|
||||||
|
@ -24,11 +28,13 @@ export default async function upload(file: File, root: string) {
|
||||||
stsToken: config.securityToken,
|
stsToken: config.securityToken,
|
||||||
bucket: config.bucket
|
bucket: config.bucket
|
||||||
})
|
})
|
||||||
|
console.log(path)
|
||||||
const { name } = await client.put(path, file, {
|
const { name } = await client.put(path, file, {
|
||||||
mime: file.type,
|
mime: file.type,
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': file.type
|
'Content-Type': file.type
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
console.log(name)
|
||||||
return ossBase + '/' + name
|
return ossBase + '/' + name
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue