mirror of https://github.com/veypi/OneAuth.git
文件编辑 管理 上传
parent
24937738db
commit
e48c269357
File diff suppressed because one or more lines are too long
@ -0,0 +1,67 @@
|
||||
<!--
|
||||
* FsTree.vue
|
||||
* Copyright (C) 2023 veypi <i@veypi.com>
|
||||
* 2023-10-06 15:35
|
||||
* Distributed under terms of the MIT license.
|
||||
-->
|
||||
<template>
|
||||
<div>
|
||||
<div :style="{ paddingLeft: depth * 2 + 'rem' }"
|
||||
class="cursor-pointer rounded-full h-8 pr-4 flex items-center hover:bg-gray-100" @click="toggle">
|
||||
<q-icon class="transition-all mx-2" :class="[expand ? 'rotate-90' :
|
||||
'']" style="font-size: 24px;" :name="root.type ===
|
||||
'directory' ? 'v-caret-right' : 'v-file'"> </q-icon>
|
||||
<div>
|
||||
{{ root.filename }}
|
||||
</div>
|
||||
<div class="grow"></div>
|
||||
<div>{{ new Date(root.lastmod).toLocaleString() }}</div>
|
||||
</div>
|
||||
<div v-if="expand">
|
||||
<template v-for="(s, si) of subs" :key="si">
|
||||
<FsTree :root="s" :depth="depth + 1"></FsTree>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import FsTree from './FsTree.vue'
|
||||
import { ref } from 'vue';
|
||||
import oafs, { fileProps } from 'src/libs/oafs';
|
||||
import { util } from 'src/libs';
|
||||
|
||||
|
||||
|
||||
|
||||
let expand = ref(false)
|
||||
let subs = ref([] as fileProps[])
|
||||
|
||||
let props = withDefaults(defineProps<{
|
||||
root: fileProps,
|
||||
depth?: number,
|
||||
}>(),
|
||||
{
|
||||
depth: 0
|
||||
}
|
||||
)
|
||||
|
||||
const toggle = () => {
|
||||
if (props.root.type === 'file') {
|
||||
util.goto('/file' + props.root.filename)
|
||||
return
|
||||
}
|
||||
if (!expand.value) {
|
||||
oafs.dav().dir(props.root.filename).then(
|
||||
(e: any) => {
|
||||
subs.value = e
|
||||
expand.value = true
|
||||
})
|
||||
return
|
||||
}
|
||||
expand.value = !expand.value
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
@ -0,0 +1,12 @@
|
||||
/*
|
||||
* evt.ts
|
||||
* Copyright (C) 2023 veypi <i@veypi.com>
|
||||
* 2023-10-08 02:21
|
||||
* Distributed under terms of the MIT license.
|
||||
*/
|
||||
|
||||
|
||||
import mitt from "mitt";
|
||||
|
||||
const evt = mitt()
|
||||
export default evt
|
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* fs.ts
|
||||
* Copyright (C) 2023 veypi <i@veypi.com>
|
||||
* 2023-10-08 01:55
|
||||
* Distributed under terms of the MIT license.
|
||||
*/
|
||||
|
||||
|
||||
import axios from "axios";
|
||||
import { Base64 } from 'js-base64'
|
||||
import util from "./util";
|
||||
import { createClient, WebDAVClient } from 'webdav'
|
||||
|
||||
export interface fileProps {
|
||||
filename: string,
|
||||
basename: string,
|
||||
lastmod: string,
|
||||
size: number,
|
||||
type: "directory" | "file",
|
||||
etag: string
|
||||
}
|
||||
|
||||
let cfg = {
|
||||
token: '',
|
||||
host: '',
|
||||
dav: {} as WebDAVClient,
|
||||
}
|
||||
|
||||
const setCfg = (token: string) => {
|
||||
cfg.token = token
|
||||
cfg.dav = createClient('/file/',
|
||||
{ headers: { auth_token: cfg.token } })
|
||||
}
|
||||
|
||||
const rename = (o: string, n?: string) => {
|
||||
let ext = '.' + o.split('.').pop()?.toLowerCase()
|
||||
if (n) {
|
||||
return n + ext
|
||||
}
|
||||
let d = new Date().getTime()
|
||||
return d + Base64.encode(o) + ext
|
||||
}
|
||||
|
||||
|
||||
const get = (url: string): Promise<string> => {
|
||||
return fetch(url, { headers: { auth_token: util.getToken() } }).then((response) => response.text())
|
||||
}
|
||||
|
||||
const upload = (f: FileList | File[], renames?: string[]) => {
|
||||
return new Promise<string[]>((resolve, reject) => {
|
||||
var data = new FormData();
|
||||
for (let i = 0; i < f.length; i++) {
|
||||
let nf = renames ? new File([f[i]], rename(f[i].name, renames[i]), { type: f[i].type }) : f[i]
|
||||
data.append('files', nf, nf.name)
|
||||
}
|
||||
axios.post("/api/upload/", data, {
|
||||
headers: {
|
||||
"Content-Type": 'multipart/form-data',
|
||||
'auth_token': cfg.token,
|
||||
}
|
||||
}).then(e => {
|
||||
resolve(e.data)
|
||||
}).catch(reject)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const dav = () => {
|
||||
return {
|
||||
stat: cfg.dav.stat,
|
||||
dir: cfg.dav.getDirectoryContents,
|
||||
upload: (dir: string, name: string, file: any) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let reader = new FileReader()
|
||||
reader.onload = function(event) {
|
||||
var res = event.target?.result
|
||||
// let data = new Blob([res])
|
||||
cfg.dav.putFileContents(name, res).then(e => {
|
||||
resolve(e)
|
||||
}).catch(reject)
|
||||
}
|
||||
reader.readAsArrayBuffer(file)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
setCfg,
|
||||
get,
|
||||
upload,
|
||||
dav,
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
<!--
|
||||
* doc.vue
|
||||
* Copyright (C) 2023 veypi <i@veypi.com>
|
||||
* 2023-10-07 22:07
|
||||
* Distributed under terms of the MIT license.
|
||||
-->
|
||||
<template>
|
||||
<div>
|
||||
<h1 class="page-h1">文档中心</h1>
|
||||
<div class="mx-8 mt-10">
|
||||
<template v-for="(doc, i) in Docs" :key="i">
|
||||
<div class="mb-10">
|
||||
<div class="text-xl flex items-center mb-4">
|
||||
<q-icon class="mx-2" :name="doc.icon"></q-icon>
|
||||
<span>{{ doc.name }}</span>
|
||||
</div>
|
||||
<div class="flex gap-8">
|
||||
<template v-for="item in doc.items" :key="item.name">
|
||||
<q-chip class="" clickable outline @click="$router.push({
|
||||
name: 'doc_item',
|
||||
params: { url: item.url, typ: 'public' }
|
||||
})" icon="bookmark" color="none">
|
||||
<span>{{ item.name }}</span>
|
||||
</q-chip>
|
||||
</template>
|
||||
</div>
|
||||
<q-separator class="mt-6" inset></q-separator>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { DocGroup } from 'src/models';
|
||||
import { ref } from 'vue';
|
||||
const Docs = ref<DocGroup[]>([
|
||||
{
|
||||
name: '用户',
|
||||
icon: 'v-team',
|
||||
items: [
|
||||
{ name: '用户注册授权过程', url: '' },
|
||||
{ name: '用户角色与权限', url: '' },
|
||||
{ name: 'api文档', url: '' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "应用",
|
||||
icon: 'v-apps',
|
||||
items: [
|
||||
{ name: '应用创建及基本设置', url: '' },
|
||||
{ name: '应用权限设置', url: '' },
|
||||
{ name: '应用对接oa流程', url: '' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "系统使用",
|
||||
icon: "v-setting",
|
||||
items: [
|
||||
{ name: "编辑器使用及语法", url: 'markdown.md' }
|
||||
]
|
||||
}
|
||||
])
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
@ -0,0 +1,64 @@
|
||||
<!--
|
||||
* docItem.vue
|
||||
* Copyright (C) 2023 veypi <i@veypi.com>
|
||||
* 2023-10-07 22:16
|
||||
* Distributed under terms of the MIT license.
|
||||
-->
|
||||
<template>
|
||||
<div class="w-full h-full">
|
||||
<h1 class="page-h1">文档中心</h1>
|
||||
<div>
|
||||
{{ url }}
|
||||
</div>
|
||||
<q-inner-loading :showing="!visible" label="Please wait..." label-class="text-teal" label-style="font-size: 1.1em" />
|
||||
<Editor v-if='doc' eid='doc' preview :content="doc"></Editor>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import msg from '@veypi/msg';
|
||||
import Editor from 'src/components/editor'
|
||||
import oafs from 'src/libs/oafs';
|
||||
import { computed, watch, onMounted, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
let doc = ref('')
|
||||
|
||||
|
||||
const visible = ref(false)
|
||||
let route = useRoute()
|
||||
let router = useRouter()
|
||||
|
||||
let url = computed(() => {
|
||||
if (route.params.typ === 'public') {
|
||||
return '/doc/' + route.params.url
|
||||
}
|
||||
return route.params.url
|
||||
})
|
||||
|
||||
watch(url, u => {
|
||||
render(u as string)
|
||||
})
|
||||
|
||||
|
||||
const render = (url: string) => {
|
||||
console.log(url)
|
||||
if (!url) {
|
||||
return
|
||||
}
|
||||
oafs.get(url).then((value) => {
|
||||
doc.value = value
|
||||
visible.value = true
|
||||
}).catch(e => {
|
||||
console.warn(e)
|
||||
msg.Warn('访问文档地址不存在')
|
||||
router.back()
|
||||
});
|
||||
}
|
||||
onMounted(() => {
|
||||
render(url.value as string)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
|
@ -0,0 +1,31 @@
|
||||
<!--
|
||||
* fsFile.vue
|
||||
* Copyright (C) 2023 veypi <i@veypi.com>
|
||||
* 2023-10-08 05:12
|
||||
* Distributed under terms of the MIT license.
|
||||
-->
|
||||
<template>
|
||||
<div>
|
||||
<h1 class="page-h1">云文件中心</h1>
|
||||
<div class="px-4">
|
||||
<FsTree v-if="root.filename" :root="root"></FsTree>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import FsTree from 'src/components/FsTree.vue';
|
||||
import oafs, { fileProps } from 'src/libs/oafs';
|
||||
import { onMounted, ref } from 'vue';
|
||||
let root = ref({} as fileProps)
|
||||
|
||||
onMounted(() => {
|
||||
oafs.dav().stat('/').then(e => {
|
||||
console.log(e)
|
||||
root.value = e as fileProps
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
@ -0,0 +1,19 @@
|
||||
<!--
|
||||
* settings.vue
|
||||
* Copyright (C) 2023 veypi <i@veypi.com>
|
||||
* 2023-10-08 06:10
|
||||
* Distributed under terms of the MIT license.
|
||||
-->
|
||||
<template>
|
||||
<div>
|
||||
<h1 class="page-h1">系统设置</h1>
|
||||
<div class="px-4">
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
@ -0,0 +1,17 @@
|
||||
<!--
|
||||
* user.vue
|
||||
* Copyright (C) 2023 veypi <i@veypi.com>
|
||||
* 2023-10-08 05:31
|
||||
* Distributed under terms of the MIT license.
|
||||
-->
|
||||
<template>
|
||||
<div>
|
||||
<h1 class="page-h1">账号设置</h1>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
Loading…
Reference in New Issue