Compare commits

...

3 Commits

Author SHA1 Message Date
plightfield fc7b1bdad5 change 2024-09-13 10:15:43 +08:00
expdsn 744c02798a 完成了自定义网址 2024-09-12 17:59:45 +08:00
expdsn 7e2112aec6 save 2024-09-11 18:40:42 +08:00
14 changed files with 330 additions and 112 deletions

View File

@ -17,6 +17,7 @@
"@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",

View File

@ -1,16 +1,14 @@
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

View File

@ -4,6 +4,7 @@ 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({
@ -53,7 +54,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="w-full h-full relative flex"> <div class={clsx("w-full h-full relative flex", isGame.value&&"bg-[#2c2e3e]")}>
{isGame.value && <AdderPageBack />} {isGame.value && <AdderPageBack />}
<div <div
class={ class={
@ -89,7 +90,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/40 backdrop-blur') (isGame.value ? '' : 'bg-white/80 backdrop-blur')
} }
onContextmenu={(e) => e.stopPropagation()} onContextmenu={(e) => e.stopPropagation()}
> >

View File

@ -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="#1F2028" fill="#2c2e3e"
/> />
<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"

View File

@ -1,10 +1,13 @@
import { computed, defineComponent, reactive } from 'vue' import { computed, defineComponent, reactive, ref, watch } 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 } from 'oh-vue-icons/icons' import { MdUpload, MdImage, MdCheck } from 'oh-vue-icons/icons'
import clsx from 'clsx'
import ImageUploader from '@/utils/ImageUploader'
import useLink from './useLink'
addIcons(MdUpload, MdImage) addIcons(MdUpload, MdImage, MdCheck)
const TypeSelector = defineComponent({ const TypeSelector = defineComponent({
props: { props: {
@ -36,32 +39,70 @@ const TypeSelector = defineComponent({
setup(props, ctx) { setup(props, ctx) {
return () => ( return () => (
<div class="flex gap-4"> <div class="flex gap-4">
<div <div class={'flex justify-center flex-col items-center gap-y-1'}>
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" <div
style={{ 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"
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={{
color: props.color backgroundImage: `url('${props.icon}')`,
backgroundColor: props.icon ? '' : 'rgba(0,0,0,0.2)'
}}
onClick={() => {
ctx.emit('update:value', 0)
}} }}
> >
{props.text ? props.text.substring(0, 2) : 'A'} {!props.icon && <OhVueIcon name="md-image" fill="white" scale={1.8} />}
</span> {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>
<div class="w-[64px] h-[65px] rounded-lg flex justify-center items-center bg-white shadow cursor-pointer hover:scale-105 transition-all"> <div class={'flex justify-center flex-col items-center gap-y-1 '}>
<OhVueIcon name="md-upload" fill="rgba(0,0,0,0.4)" scale={1.8} /> <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
}}
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>
) )
@ -81,7 +122,6 @@ 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: '',
@ -91,41 +131,88 @@ 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-lg p-4 ' + 'absolute left-0 top-0 w-full h-full rounded-2xl p-5 ' +
(isGame.value ? 'bg-white/10' : 'bg-white/80') (isGame.value ? 'bg-white/20' : 'bg-white/20')
} }
> >
<ConfigProvider <div class="flex flex-col">
theme={{ <div></div>
token: isGame.value </div>
? theme.darkAlgorithm(theme.defaultSeed) <div class={clsx('flex flex-col text-[14px] gap-y-3', isGame.value ? 'text-white' : '')}>
: theme.defaultAlgorithm(theme.defaultSeed) <div class={clsx('gap-x-6 flex items-center')}>
}} <span></span>
> <input
<Form labelCol={{ span: 6 }} model={form} class="grid grid-cols-2 gap-4" colon={false}> v-model={form.link}
<Form.Item label="地址" name="link" class="col-span-2" labelCol={{ span: 3 }}> placeholder="搜索想要添加的网址导航"
<Input v-model:value={form.link} /> class={clsx(
</Form.Item> 'w-[350px] rounded-md outline-none h-[40px] px-[10px]',
<Form.Item label="名称" name="name"> isGame.value ? 'bg-black/[.1]' : ''
<Input v-model:value={form.name} /> )}
</Form.Item> ></input>
<Form.Item name="type" label=" " class="col-span-2" labelCol={{ span: 3 }}> <span class={'cursor-pointer'}></span>
<TypeSelector </div>
v-model:value={form.type} <div class={clsx('gap-x-6 flex items-center')}>
v-model:icon={form.icon} <span></span>
text={form.text} <input
color={form.color} v-model={form.name}
background={form.background} placeholder="网站名称"
/> class={clsx(
</Form.Item> 'w-[350px] rounded-md outline-none h-[40px] px-[10px]',
<Form.Item label="图标文字" name="text"> isGame.value ? 'bg-black/[.1]' : ''
<Input v-model:value={form.text} /> )}
</Form.Item> ></input>
</Form> </div>
</ConfigProvider> <div class={clsx('gap-x-6 flex items-start')}>
<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>
) )
} }

View File

@ -0,0 +1,34 @@
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
}

View File

@ -6,6 +6,7 @@ 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)
@ -117,7 +118,7 @@ export default defineComponent(() => {
}} }}
/> />
<div <div
class="w-[56px] h-[56px] bg-white/40 rounded-full border-white border-[2px] border-solid overflow-hidden cursor-pointer" class="w-[56px] h-[56px] 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'
@ -125,7 +126,9 @@ export default defineComponent(() => {
router.path = 'global-login' router.path = 'global-login'
} }
}} }}
></div> >
<AvatarCircle />
</div>
</div> </div>
{/* 添加页面 */} {/* 添加页面 */}
<Transition name="page-adder"> <Transition name="page-adder">

View File

@ -1,3 +1,4 @@
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'
@ -62,7 +63,9 @@ export default defineComponent(() => {
router.path = 'settings-user' router.path = 'settings-user'
}} }}
> >
<div class="w-12 h-12 rounded-full overflow-hidden bg-black/20"></div> <div class="w-12 h-12 relative">
<AvatarCircle />
</div>
</div> </div>
<SettingsTab label="壁纸" path="settings-background" /> <SettingsTab label="壁纸" path="settings-background" />
<SettingsTab label="图标" path="settings-block" /> <SettingsTab label="图标" path="settings-block" />

22
src/user/AvatarCircle.tsx Normal file
View File

@ -0,0 +1,22 @@
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>
)
}
})

View File

@ -34,8 +34,10 @@ export default defineComponent(() => {
</div> </div>
<div class="flex flex-col"> <div class="flex flex-col">
<input placeholder="邮箱" v-model={form.email} /> <form>
<input placeholder="密码" type="password" v-model={form.password} /> <input placeholder="邮箱" v-model={form.email} />
<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', {
@ -43,6 +45,7 @@ export default defineComponent(() => {
returnType: 'text' returnType: 'text'
}).then((res) => { }).then((res) => {
user.token = res user.token = res
router.path = ''
}) })
}} }}
> >

View File

@ -1,19 +1,86 @@
import useRouterStore from '@/useRouterStore' import useRouterStore from '@/useRouterStore'
import { Button } from 'ant-design-vue' import { Button, message, Modal, Tag, Tooltip } 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"> <div class="absolute left-0 top-0 w-full h-full p-4 flex flex-col">
this is user <div class="flex justify-center py-4">
<Button <div class="w-16 h-16 relative">
onClick={() => { <AvatarCircle />
router.path = 'global-login' </div>
}} </div>
> {user.isLogin && (
<div class="h-0 flex-grow py-4 px-12">
</Button> <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}
</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>
) )
}) })

View File

@ -1,43 +1,48 @@
import request from '@/utils/request' import request from '@/utils/request'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { computed, ref, watch } from 'vue' import { computed, reactive, 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 = ref<null | UserInfo>(null) const profile = reactive(defaultUserInfo)
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) => {
profile.value = res Object.assign(profile, res)
}) })
}, },
{ immediate: true } { immediate: true }
) )
const isLogin = computed(() => !!token.value && !!profile.value) const isLogin = computed(() => !!token.value && !!profile.id)
const logout = () => {
token.value = ''
Object.assign(profile, defaultUserInfo)
}
return { return {
token, token,
profile, profile,
isLogin isLogin,
logout
} }
}) })

View File

@ -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>
) )

View File

@ -1,24 +1,20 @@
import { ossBase, ossKeyUrl } from './../config' import { ossBase } 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 config = await fetch(ossKeyUrl, { const token = localStorage.getItem('token')
method: 'POST', if (!token) {
headers: { throw new Error('尚未登录,无法上传')
Authorization: }
'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2NjlkZjA3Y2RhMjkyZTNiZTc0OGM5MmMifQ.9k9-C_Im2r2fONfT6rdAZDxapkqtwGtiVBSen59JDXY' const config = await request<{
} region: string
}).then( accessKeyId: string
(res) => accessKeySecret: string
res.json() as Promise<{ securityToken: string
region: string bucket: string
accessKeyId: string path: string
accessKeySecret: string }>('POST', '/api/ossKey')
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({
@ -28,13 +24,11 @@ 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
} }