You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
web-file-system/src/frontend/widgets/UiDirectoryNaming.vue

199 lines
5.9 KiB

<script lang="ts" setup>
import {getRootBarrier} from './utils'
import {dispatch} from '../worker'
import {emit} from '../../shared'
import {computed, nextTick, onMounted, ref, watch} from 'vue'
import {store} from '../store'
import UiDialog from './UiDialog.vue'
import {controller} from './UiDirectoryNamingController'
import {toast} from './UiToastController'
const barrier = ref<Node | null>()
const hasError = ref(false)
const conformClicked = ref(false)
const isSubmitting = ref(false)
const content = ref('')
const title = computed(() => {
if (controller.action === 'rename') {
return '重命名文件夹'
} else if (controller.pid) {
return "创建子文件夹"
} else {
return "创建文件夹"
}
})
const parent = computed(() => {
return controller.pid
? store.directories.get(controller.pid)
: undefined
})
const directory = computed(() => {
return controller.id
? store.directories.get(controller.id)
: undefined
})
const handleCancel = (): void => {
if (!isSubmitting.value) {
controller.visible = false
nextTick(() => {
hasError.value = false
conformClicked.value = false
isSubmitting.value = false
content.value = ''
})
}
}
const handleConfirm = (): void => {
if (isSubmitting.value) {
return;
}
if (content.value.trim().length < 2) {
hasError.value = true
}
if (hasError.value) {
return;
}
if (!conformClicked.value) {
conformClicked.value = true
return
}
isSubmitting.value = true
requestAnimationFrame(async () => {
try {
const title = content.value.trim()
switch (controller.action) {
case "create": {
const pid = parent.value?.id ?? 0
const result = await dispatch("dir", "create", {title, pid});
store.directories.set(result.id, result);
toast("success", `成功创建文件夹 “${title}`)
if (pid && pid === controller.pid) {
emit("directory:expanded", parent.value!.id)
}
break
}
case "rename": {
const dir = store.directories.get(directory.value!.id);
if (!dir) {
toast("error", "文件夹不存在")
break
}
const res = await dispatch("dir", "rename", {id: dir.id, title});
Object.assign(dir, res);
toast("success", `成功将文件夹 “${directory.value!.title}” 重命名为 “${title}`)
break
}
}
isSubmitting.value = false
handleCancel()
} catch (err) {
isSubmitting.value = false
toast('error', err as any)
}
})
}
watch(() => controller.visible, (value) => {
if (value && controller.action === 'rename') {
content.value = directory.value?.title ?? ''
}
})
watch(content, (value) => {
conformClicked.value = false
if (value.trim().length > 1) {
hasError.value = false
}
})
onMounted(() => {
barrier.value = getRootBarrier()
})
</script>
<template>
<UiDialog
v-if="barrier"
:barrier="barrier"
:visible="controller.visible"
class="w-96 rounded-md overflow-hidden shadow-2xl"
outside="shake"
@dismissed="handleCancel"
>
<div class="bg-white p-6">
<h3
id="modal-title"
class="text-base font-semibold leading-6 text-gray-900"
v-text="title"
/>
<p class="text-xs text-gray-500 mt-1">
<template v-if="controller.action === 'rename'">
您正在修改文件夹 “<b
class="text-black align-baseline text-sm">{{ directory!.title }}</b>”;<br/>
</template>
<template v-else-if="controller.pid">
您正在为 “<b
class="text-black align-baseline text-sm">{{ parent!.title }}</b>”
创建子文件夹;<br/>
</template>
<span :class="{ 'text-red-500': hasError }">
文件夹的名称至少 2 个字符,请尽量不要超过 8 个汉字。
</span>
</p>
<div class="mt-4">
<input
v-model="content"
:disabled="isSubmitting" autocomplete="off"
class="block w-full rounded-md border-0 px-4 py-2 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6 disabled:bg-gray-100 disabled:cursor-progress"
maxlength="20" minlength="2"
placeholder="请输入文件夹名称" required
@blur="hasError = content.length < 2"/>
</div>
</div>
<div
class="bg-gray-50 px-6 py-3 flex justify-end gap-4 border-t border-t-slate-200 text-sm font-semibold">
<button
:disabled="isSubmitting"
class="rounded-md px-4 py-2 select-none transition-all bg-white text-gray-900 shadow-sm hover:bg-gray-50 ring-1 ring-inset ring-gray-300 disabled:bg-gray-100 disabled:hover:bg-gray-100 disabled:cursor-progress"
type="button"
@click="handleCancel"
>
取消
</button>
<button
:disabled="isSubmitting"
class="inline-flex items-center gap-2 px-4 py-2 rounded-md transition-all select-none bg-indigo-600 text-white shadow-sm hover:bg-indigo-500 disabled:bg-indigo-400 disabled:hover:bg-indigo-400 disabled:cursor-progress"
type="button"
@click="handleConfirm"
>
<svg
v-if="isSubmitting"
class="animate-spin h-3 w-3 text-white"
fill="none"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<circle
class="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
stroke-width="4"
/>
<path
class="opacity-75"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
fill="currentColor"
/>
</svg>
{{ conformClicked ? "确定提交?" : "提交" }}
</button>
</div>
</UiDialog>
</template>