first commit

This commit is contained in:
2023-07-07 20:05:25 +08:00
commit 0322866b82
40 changed files with 6040 additions and 0 deletions

7
frontend/src/App.vue Normal file
View File

@@ -0,0 +1,7 @@
<script setup lang="ts">
import FilerLayout from '@/layout/FilerLayout.vue'
</script>
<template>
<FilerLayout></FilerLayout>
</template>

View File

@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@@ -0,0 +1,50 @@
<template>
<div class="navbar bg-base-100">
<div class="navbar-start">
<div class="dropdown">
<label tabindex="0" class="btn btn-ghost btn-circle">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 6h16M4 12h16M4 18h7"
/>
</svg>
</label>
<ul
tabindex="0"
class="menu menu-sm dropdown-content mt-3 z-[1] p-2 shadow bg-base-100 rounded-box w-52"
>
<li>
<RouterLink :to="{ name: 'setting' }">设置</RouterLink>
</li>
<li>
<RouterLink :to="{ name: 'upyun' }">又拍云存储</RouterLink>
</li>
</ul>
</div>
</div>
<div class="navbar-center">
<a class="btn btn-ghost normal-case text-xl">Filer</a>
</div>
<div class="navbar-end">
<BackspaceIcon class="btn btn-ghost btn-circle h-8 w-8 mr-2" @click="quit" />
</div>
</div>
</template>
<script setup lang="ts">
import { BackspaceIcon } from '@heroicons/vue/24/solid'
import { Quit } from '@/../wailsjs/go/controller/Storage'
const quit = () => {
Quit()
}
</script>

View File

@@ -0,0 +1,12 @@
<template>
<div class="flex flex-col min-h-screen bg-base-200">
<Navbar></Navbar>
<div class="flex justify-center">
<RouterView></RouterView>
</div>
</div>
</template>
<script setup lang="ts">
import Navbar from '@/components/Navbar.vue'
</script>

18
frontend/src/main.ts Normal file
View File

@@ -0,0 +1,18 @@
import './assets/app.css'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import { VueClipboard } from '@soerenmartius/vue3-clipboard'
import Notifications from '@kyvg/vue3-notification'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.use(VueClipboard)
app.use(Notifications)
app.mount('#app')

View File

@@ -0,0 +1,20 @@
import { createRouter, createWebHistory } from 'vue-router'
import SettingView from '../views/SettingView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'setting',
component: SettingView
},
{
path: '/upyun',
name: 'upyun',
component: () => import('../views/UpyunView.vue')
}
]
})
export default router

26
frontend/src/style.css Normal file
View File

@@ -0,0 +1,26 @@
html {
background-color: rgba(27, 38, 54, 1);
text-align: center;
color: white;
}
body {
margin: 0;
color: white;
font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
}
@font-face {
font-family: "Nunito";
font-style: normal;
font-weight: 400;
src: local(""),
url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2");
}
#app {
height: 100vh;
text-align: center;
}

View File

@@ -0,0 +1,75 @@
<template>
<notifications />
<div class="card w-96 top-5 bg-base-100 shadow-xl">
<div class="card-body">
<h2 class="card-title">又拍云对象存储!</h2>
<div class="form-control w-full max-w-xs">
<label class="label">
<span class="label-text">服务名</span>
</label>
<input
type="text"
class="input input-bordered input-primary w-full max-w-xs"
v-model="allConfig.config.upyun.bucket"
/>
</div>
<div class="form-control w-full max-w-xs">
<label class="label">
<span class="label-text">操作员名称</span>
</label>
<input
type="text"
class="input input-bordered input-primary w-full max-w-xs"
v-model="allConfig.config.upyun.operator"
/>
</div>
<div class="form-control w-full max-w-xs">
<label class="label">
<span class="label-text">密码</span>
</label>
<input
type="password"
class="input input-bordered input-primary w-full max-w-xs"
v-model="allConfig.config.upyun.password"
/>
</div>
<div class="form-control w-full max-w-xs">
<label class="label">
<span class="label-text">域名</span>
</label>
<input
type="text"
class="input input-bordered input-primary w-full max-w-xs"
v-model="allConfig.config.upyun.domain"
/>
</div>
<div class="card-actions justify-end">
<button class="btn btn-primary" @click="upyun_update">更新配置</button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, reactive } from 'vue'
import { notify } from '@kyvg/vue3-notification'
import { GetConfig, SetUpyunConfig } from '@/../wailsjs/go/controller/Storage'
import { controller } from '@/../wailsjs/go/models'
let current_config: controller.ServerConfig = new controller.ServerConfig()
current_config.upyun = new controller.UpyunConfig()
let allConfig = reactive({ config: current_config })
const upyun_update = async () => {
console.log('current config: ', allConfig.config.upyun)
await SetUpyunConfig(allConfig.config.upyun)
notify({
title: '更新成功',
duration: 5000
})
}
onMounted(async () => {
allConfig.config = await GetConfig()
})
</script>

View File

@@ -0,0 +1,182 @@
<template>
<notifications />
<div class="card w-full bg-base-100 shadow-xl mt-8 mx-8">
<div class="card-body">
<div class="card-title">
<div class="join">
<input class="input input-bordered join-item" v-model="current_prefix" />
<button class="btn join-item btn-active rounded-r-full" @click="go_to">Go</button>
</div>
<button class="btn ml-2 btn-outline btn-accent" @click="go_back">返回上级</button>
<button class="btn ml-2 btn-outline btn-success" @click="mkdir">创建目录</button>
<button
class="btn ml-2 join-item btn-active btn-secondary rounded-r-full"
@click="on_file_upload"
>
上传文件
</button>
</div>
<div class="divider"></div>
<div class="overflow-x-auto">
<table class="table">
<tbody>
<tr v-for="(file, index) in current_files.list" :key="index">
<td>
<div class="flex items-center space-x-3">
<div class="avatar">
<div class="mask mask-squircle w-8 h-8" v-if="file.is_dir">
<FolderPlusIcon class="h-8 w-8 text-blue-500" />
</div>
<div class="mask mask-squircle w-8 h-8" v-else>
<DocumentTextIcon class="h-8 w-8 text-orange-800" />
</div>
</div>
<div v-if="file.is_dir">
<a class="font-bold text-blue-300" @click="click_enter_to(file.filename!)">{{
file.filename
}}</a>
</div>
<div v-else>
<div class="font-bold">{{ file.filename }}</div>
</div>
</div>
</td>
<td>
{{ file.created_at }}
</td>
<th>
<button
class="btn btn-ghost btn-outline btn-xs"
v-if="!file.is_dir"
@click="toClipboard(copy_link(file.filename!))"
>
link
</button>
<button
class="btn btn-error btn-outline btn-xs ml-1"
@click="to_delete(file.filename!, file.is_dir!)"
>
delete
</button>
</th>
</tr>
</tbody>
</table>
</div>
<div class="card-actions justify-end">
<div>
当前
<div class="badge badge-accent">{{ current_files.list.length }}</div>
个文件
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { FolderPlusIcon, DocumentTextIcon } from '@heroicons/vue/24/solid'
import { toClipboard } from '@soerenmartius/vue3-clipboard'
import { notify } from '@kyvg/vue3-notification'
import { ref, reactive, onMounted } from 'vue'
import {
GetConfig,
UperList,
UperUpload,
UperDelete,
UperCreateDirectory
} from '@/../wailsjs/go/controller/Storage'
import { controller } from '@/../wailsjs/go/models'
let current_config: controller.ServerConfig = new controller.ServerConfig()
current_config.upyun = new controller.UpyunConfig()
let allConfig = reactive({ config: current_config })
const current_prefix = ref('/')
let file_list_object: Array<controller.FileInfo> = []
let current_files = reactive({ list: file_list_object })
const on_file_upload = async () => {
await UperUpload(current_prefix.value)
notify({
title: '文件上传成功',
duration: 5000
})
await list(current_prefix.value)
}
const list = async (prefix: string) => {
current_files.list = await UperList(prefix)
console.log('get list: ', current_files.list)
}
const mkdir = async () => {
if (current_prefix.value === '/') return
await UperCreateDirectory(current_prefix.value)
await list(current_prefix.value)
notify({
title: '创建目录成功',
duration: 5000
})
}
const go_to = async () => {
await list(current_prefix.value)
}
const to_delete = async (filename: string, is_dir: boolean) => {
let delete_filename = ''
if (current_prefix.value == '/') {
delete_filename = current_prefix.value + filename
} else {
delete_filename = current_prefix.value + '/' + filename
}
await UperDelete(delete_filename, is_dir)
await list(current_prefix.value)
notify({
title: '删除成功',
duration: 5000
})
}
const click_enter_to = async (dir: string) => {
if (current_prefix.value == '/') {
current_prefix.value += dir
} else {
current_prefix.value += '/' + dir
}
await list(current_prefix.value)
}
const go_back = async () => {
if (current_prefix.value === '/') return
const lastIndex = current_prefix.value.lastIndexOf('/')
current_prefix.value = current_prefix.value.substring(0, lastIndex)
if (current_prefix.value === '') current_prefix.value = '/'
await list(current_prefix.value)
}
const copy_link = (filename: string) => {
let real_filename = ''
if (current_prefix.value == '/') {
real_filename = current_prefix.value + filename
} else {
real_filename = current_prefix.value + '/' + filename
}
notify({
title: '已拷贝链接',
duration: 5000
})
return allConfig.config.upyun.domain + real_filename
}
onMounted(async () => {
allConfig.config = await GetConfig()
await list(current_prefix.value)
})
</script>

7
frontend/src/vite-env.d.ts vendored Normal file
View File

@@ -0,0 +1,7 @@
/// <reference types="vite/client" />
declare module '*.vue' {
import type {DefineComponent} from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}