style: set print width to 120
This commit is contained in:
parent
4721e0b576
commit
a36855bfd3
|
@ -1,6 +1,6 @@
|
|||
/** @type {import("prettier").Config} */
|
||||
const config = {
|
||||
printWidth: 80, // 每行字符数
|
||||
printWidth: 120, // 每行字符数
|
||||
tabWidth: 2, // 缩进空格数
|
||||
useTabs: false, // 使用tab缩进
|
||||
semi: false, // 在语句末尾使用分号
|
||||
|
|
|
@ -40,11 +40,7 @@ onMounted(() => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<n-config-provider
|
||||
:locale="customizedLocale"
|
||||
:date-locale="dateZhCN"
|
||||
:theme="isDarkMode ? darkTheme : null"
|
||||
>
|
||||
<n-config-provider :locale="customizedLocale" :date-locale="dateZhCN" :theme="isDarkMode ? darkTheme : null">
|
||||
<FeedbackProvider>
|
||||
<div class="container">
|
||||
<div v-show="banner" class="banner">
|
||||
|
|
|
@ -26,10 +26,7 @@ export function getAnnouncements(
|
|||
/**
|
||||
* 更新公告状态
|
||||
*/
|
||||
export function updateAnnouncementStatus(
|
||||
id: string,
|
||||
disabled: boolean,
|
||||
): RequestResponse<undefined> {
|
||||
export function updateAnnouncementStatus(id: string, disabled: boolean): RequestResponse<undefined> {
|
||||
return Request.put(
|
||||
`/announcement/${id}/status`,
|
||||
{
|
||||
|
@ -53,11 +50,7 @@ export function deleteAnnouncement(id: string): RequestResponse<undefined> {
|
|||
/**
|
||||
* 修改公告
|
||||
*/
|
||||
export function updateAnnouncement(
|
||||
id: string,
|
||||
title?: string,
|
||||
content?: string,
|
||||
): RequestResponse<undefined> {
|
||||
export function updateAnnouncement(id: string, title?: string, content?: string): RequestResponse<undefined> {
|
||||
const requestData: { title?: string; content?: string } = {}
|
||||
if (hasText(title)) {
|
||||
requestData.title = title
|
||||
|
@ -74,9 +67,6 @@ export function updateAnnouncement(
|
|||
* @param data 公告信息
|
||||
* @returns 公告ID
|
||||
*/
|
||||
export function addAnnouncement(data: {
|
||||
title: string
|
||||
content: string
|
||||
}): RequestResponse<string> {
|
||||
export function addAnnouncement(data: { title: string; content: string }): RequestResponse<string> {
|
||||
return Request.post("/announcement", data)
|
||||
}
|
||||
|
|
|
@ -2,9 +2,7 @@ import Request, { config } from "./request"
|
|||
import type { AxiosProgressEvent } from "axios"
|
||||
|
||||
/** 获取目录内容 */
|
||||
export function getFolderContent(
|
||||
id: string | null = null,
|
||||
): RequestResponse<FolderContent> {
|
||||
export function getFolderContent(id: string | null = null): RequestResponse<FolderContent> {
|
||||
return Request.get("/file", { params: { folder: id } })
|
||||
}
|
||||
|
||||
|
@ -22,11 +20,7 @@ export function getFileTemporaryToken(id: string): RequestResponse<string> {
|
|||
* @param single 是否单线程下载
|
||||
* @param name 文件名
|
||||
*/
|
||||
export function getFileTemporaryUrl(
|
||||
id: string,
|
||||
single: boolean = false,
|
||||
name?: string,
|
||||
): Promise<string> {
|
||||
export function getFileTemporaryUrl(id: string, single: boolean = false, name?: string): Promise<string> {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
getFileTemporaryToken(id)
|
||||
.then((response) => {
|
||||
|
@ -90,10 +84,7 @@ export function deleteFile(id: string): RequestResponse<null> {
|
|||
* @param id 文件ID
|
||||
* @param folderId 目标文件夹ID
|
||||
*/
|
||||
export function moveFile(
|
||||
id: string,
|
||||
folderId: string | undefined,
|
||||
): RequestResponse<null> {
|
||||
export function moveFile(id: string, folderId: string | undefined): RequestResponse<null> {
|
||||
return Request.put(
|
||||
`/file/${id}/move`,
|
||||
{},
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
import Request from "./request"
|
||||
|
||||
/** 创建文件夹 */
|
||||
export function createFolder(
|
||||
name: string | undefined,
|
||||
parent?: string,
|
||||
): RequestResponse<undefined> {
|
||||
export function createFolder(name: string | undefined, parent?: string): RequestResponse<undefined> {
|
||||
return Request.post("/folder", { name: name, parent: parent || null })
|
||||
}
|
||||
|
||||
|
@ -13,10 +10,7 @@ export function createFolder(
|
|||
* @param id 文件夹ID
|
||||
* @param parent 目标文件夹ID
|
||||
*/
|
||||
export function moveFolder(
|
||||
id: string,
|
||||
parent: string | undefined,
|
||||
): RequestResponse<undefined> {
|
||||
export function moveFolder(id: string, parent: string | undefined): RequestResponse<undefined> {
|
||||
return Request.put(
|
||||
`/folder/${id}/move`,
|
||||
{},
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
import Request from "./request"
|
||||
|
||||
/** 获取所有角色 */
|
||||
export function getRoles(
|
||||
index: number = 0,
|
||||
size: number = 10,
|
||||
expression?: string,
|
||||
): RequestResponse<Page<Role>> {
|
||||
export function getRoles(index: number = 0, size: number = 10, expression?: string): RequestResponse<Page<Role>> {
|
||||
return Request.get("/role", {
|
||||
params: {
|
||||
index: index,
|
||||
|
@ -31,18 +27,12 @@ export function deleteRole(id: string): RequestResponse<null> {
|
|||
}
|
||||
|
||||
/** 更新角色信息 */
|
||||
export function updateRole(
|
||||
id: string,
|
||||
data: UpdateRoleData,
|
||||
): RequestResponse<null> {
|
||||
export function updateRole(id: string, data: UpdateRoleData): RequestResponse<null> {
|
||||
return Request.put(`/role/${id}`, data)
|
||||
}
|
||||
|
||||
/** 更新角色状态 */
|
||||
export function updateRoleStatus(
|
||||
id: string,
|
||||
disabled?: boolean,
|
||||
): RequestResponse<null> {
|
||||
export function updateRoleStatus(id: string, disabled?: boolean): RequestResponse<null> {
|
||||
const requestData: any = {}
|
||||
if (disabled !== undefined) {
|
||||
requestData.disabled = disabled
|
||||
|
@ -60,18 +50,12 @@ export function getRoleUsers(id: string): RequestResponse<string[]> {
|
|||
}
|
||||
|
||||
/** 分配角色用户 */
|
||||
export function assignRoleUsers(
|
||||
id: string,
|
||||
userIds: string[],
|
||||
): RequestResponse<null> {
|
||||
export function assignRoleUsers(id: string, userIds: string[]): RequestResponse<null> {
|
||||
return Request.put(`/role/${id}/users`, userIds)
|
||||
}
|
||||
|
||||
/** 取消分配角色用户 */
|
||||
export function unassignRoleUsers(
|
||||
id: string,
|
||||
userIds: string[],
|
||||
): RequestResponse<null> {
|
||||
export function unassignRoleUsers(id: string, userIds: string[]): RequestResponse<null> {
|
||||
return Request.delete(`/role/${id}/users`, {
|
||||
data: userIds,
|
||||
})
|
||||
|
|
|
@ -11,10 +11,7 @@ export function getConfig(): RequestResponse<Object> {
|
|||
}
|
||||
|
||||
/** 更新设置 */
|
||||
export function updateSetting(
|
||||
key: string,
|
||||
value: string | number | boolean,
|
||||
): RequestResponse<undefined> {
|
||||
export function updateSetting(key: string, value: string | number | boolean): RequestResponse<undefined> {
|
||||
return Request.put(
|
||||
`/system/setting/${key}`,
|
||||
{ value },
|
||||
|
|
|
@ -18,12 +18,7 @@ export function deleteUser(id: string) {
|
|||
}
|
||||
|
||||
/** 新增用户 */
|
||||
export function addUser(data: {
|
||||
username: string
|
||||
password: string
|
||||
nickname?: string
|
||||
email?: string
|
||||
}) {
|
||||
export function addUser(data: { username: string; password: string; nickname?: string; email?: string }) {
|
||||
// 检查undefined,不发送
|
||||
const requestData: any = {}
|
||||
if (hasText(data.nickname)) {
|
||||
|
@ -40,10 +35,7 @@ export function addUser(data: {
|
|||
}
|
||||
|
||||
/** 更新用户信息 */
|
||||
export function updateUserInfo(
|
||||
id: string,
|
||||
data: { password?: string; nickname?: string; email?: string },
|
||||
) {
|
||||
export function updateUserInfo(id: string, data: { password?: string; nickname?: string; email?: string }) {
|
||||
// 检查undefined,不发送
|
||||
const requestData: any = {}
|
||||
if (hasText(data.nickname)) {
|
||||
|
@ -107,10 +99,7 @@ export function uploadUserAvatar(file: File) {
|
|||
/**
|
||||
* 更新用户禁用状态
|
||||
*/
|
||||
export function updateUserDisabled(
|
||||
id: string,
|
||||
disabled: boolean,
|
||||
): Promise<any> {
|
||||
export function updateUserDisabled(id: string, disabled: boolean): Promise<any> {
|
||||
return Request.put(
|
||||
`/user/${id}/disable`,
|
||||
{
|
||||
|
@ -127,10 +116,7 @@ export function updateUserDisabled(
|
|||
/**
|
||||
* (管理员)重置密码
|
||||
*/
|
||||
export function updateUserPassword(
|
||||
id: string,
|
||||
newPassword: string,
|
||||
): Promise<any> {
|
||||
export function updateUserPassword(id: string, newPassword: string): Promise<any> {
|
||||
return Request.put(`/user/${id}/password`, {
|
||||
newPassword: newPassword,
|
||||
})
|
||||
|
@ -146,32 +132,21 @@ export function getUserRoles(id: string): RequestResponse<string[]> {
|
|||
/**
|
||||
* (管理员)分配用户角色
|
||||
*/
|
||||
export function assignRoles(
|
||||
id: string,
|
||||
roles: string[],
|
||||
): RequestResponse<null> {
|
||||
export function assignRoles(id: string, roles: string[]): RequestResponse<null> {
|
||||
return Request.put(`/user/${id}/role`, roles)
|
||||
}
|
||||
|
||||
/**
|
||||
* (管理员)移除用户角色
|
||||
*/
|
||||
export function removeRoles(
|
||||
id: string,
|
||||
roles: string[],
|
||||
): RequestResponse<null> {
|
||||
export function removeRoles(id: string, roles: string[]): RequestResponse<null> {
|
||||
return Request.delete(`/user/${id}/role`, { data: roles })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取注册邮件验证码
|
||||
*/
|
||||
export function sendRegisterEmailCode(
|
||||
username: string,
|
||||
password: string,
|
||||
email: string,
|
||||
captcha: GeetestSuccessInfo,
|
||||
) {
|
||||
export function sendRegisterEmailCode(username: string, password: string, email: string, captcha: GeetestSuccessInfo) {
|
||||
return Request.post(
|
||||
"/user/register/email",
|
||||
{
|
||||
|
|
|
@ -4,24 +4,17 @@ const props = defineProps<{
|
|||
config: GeetestConfig
|
||||
}>()
|
||||
defineExpose({
|
||||
validate: (
|
||||
onFail: (w: GeetestFailInfo) => void = () => {},
|
||||
): Promise<GeetestSuccessInfo> =>
|
||||
new Promise<GeetestSuccessInfo>(
|
||||
(
|
||||
resolve: (value: GeetestSuccessInfo) => void = () => {},
|
||||
reject = () => {},
|
||||
) => {
|
||||
if (!geetest) {
|
||||
reject(new Error("geetest not ready"))
|
||||
return
|
||||
}
|
||||
geetest.onSuccess(() => resolve(geetest.getValidate()))
|
||||
geetest.onFail(onFail)
|
||||
geetest.onError(reject)
|
||||
geetest.showCaptcha()
|
||||
},
|
||||
),
|
||||
validate: (onFail: (w: GeetestFailInfo) => void = () => {}): Promise<GeetestSuccessInfo> =>
|
||||
new Promise<GeetestSuccessInfo>((resolve: (value: GeetestSuccessInfo) => void = () => {}, reject = () => {}) => {
|
||||
if (!geetest) {
|
||||
reject(new Error("geetest not ready"))
|
||||
return
|
||||
}
|
||||
geetest.onSuccess(() => resolve(geetest.getValidate()))
|
||||
geetest.onFail(onFail)
|
||||
geetest.onError(reject)
|
||||
geetest.showCaptcha()
|
||||
}),
|
||||
})
|
||||
|
||||
onBeforeMount(() => {
|
||||
|
|
|
@ -30,8 +30,7 @@ import {
|
|||
import { useAppConfig } from "@/stores/app-config"
|
||||
import { renderIcon } from "@/utils"
|
||||
|
||||
const { expandedMenuKeys, isMenuCollapsed, isDebugMode } =
|
||||
storeToRefs(useAppConfig())
|
||||
const { expandedMenuKeys, isMenuCollapsed, isDebugMode } = storeToRefs(useAppConfig())
|
||||
|
||||
const menuOptions = ref([
|
||||
{
|
||||
|
@ -92,6 +91,7 @@ const menuOptions = ref([
|
|||
key: "recycle",
|
||||
icon: renderIcon(TrashOutline),
|
||||
disabled: true,
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
label: "设置",
|
||||
|
@ -108,6 +108,7 @@ const menuOptions = ref([
|
|||
label: "系统状态",
|
||||
key: "system-status",
|
||||
icon: renderIcon(SpeedometerOutline),
|
||||
show: false,
|
||||
children: [
|
||||
{
|
||||
label: "运行信息",
|
||||
|
|
|
@ -1,20 +1,13 @@
|
|||
<script setup lang="ts">
|
||||
import { useRouter } from "vue-router/auto"
|
||||
import { storeToRefs } from "pinia"
|
||||
import {
|
||||
ArrowUpOutline,
|
||||
LogOutOutline,
|
||||
MoonOutline,
|
||||
PersonCircleOutline,
|
||||
SunnyOutline,
|
||||
} from "@vicons/ionicons5"
|
||||
import { ArrowUpOutline, LogOutOutline, MoonOutline, PersonCircleOutline, SunnyOutline } from "@vicons/ionicons5"
|
||||
import { useAppConfig } from "@/stores/app-config"
|
||||
import { useUserInfo } from "@/stores/user-info"
|
||||
import { renderIcon } from "@/utils"
|
||||
import QrCode from "@/components/QrCode.vue"
|
||||
|
||||
const { isDarkMode, isUploadDrawerShow, isDebugMode, uploadItemCount } =
|
||||
storeToRefs(useAppConfig())
|
||||
const { isDarkMode, isUploadDrawerShow, isDebugMode, uploadItemCount } = storeToRefs(useAppConfig())
|
||||
const { nickname, isLoggedIn, avatarUrl } = storeToRefs(useUserInfo())
|
||||
const { removeInfo } = useUserInfo()
|
||||
const router = useRouter()
|
||||
|
@ -54,23 +47,8 @@ const onSelect = (key: string) => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<n-layout-header
|
||||
style="
|
||||
height: 64px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
"
|
||||
bordered
|
||||
>
|
||||
<n-space
|
||||
style="
|
||||
margin-left: 36px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 36px;
|
||||
"
|
||||
>
|
||||
<n-layout-header style="height: 64px; display: flex; align-items: center; justify-content: space-between" bordered>
|
||||
<n-space style="margin-left: 36px; display: flex; align-items: center; height: 36px">
|
||||
<n-popover trigger="hover" title="网站二维码" :disabled="!isDebugMode">
|
||||
<template #header>
|
||||
<n-text depth="1" strong> 网站二维码,扫码立即体验</n-text>
|
||||
|
@ -93,24 +71,13 @@ const onSelect = (key: string) => {
|
|||
<QrCode :value="host" :size="200" />
|
||||
</n-popover>
|
||||
</n-space>
|
||||
<n-space
|
||||
style="
|
||||
margin-right: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 64px;
|
||||
"
|
||||
>
|
||||
<n-space style="margin-right: 24px; display: flex; align-items: center; height: 64px">
|
||||
<n-button circle quaternary strong @click="isDarkMode = !isDarkMode">
|
||||
<template #icon>
|
||||
<n-icon :component="isDarkMode ? MoonOutline : SunnyOutline" />
|
||||
</template>
|
||||
</n-button>
|
||||
<n-badge
|
||||
v-if="isLoggedIn && !isPlayer"
|
||||
:max="999"
|
||||
:value="uploadItemCount"
|
||||
>
|
||||
<n-badge v-if="isLoggedIn && !isPlayer" :max="999" :value="uploadItemCount">
|
||||
<n-button circle secondary strong @click="isUploadDrawerShow = true">
|
||||
<template #icon>
|
||||
<n-icon :component="ArrowUpOutline" />
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import {
|
||||
useLoadingBar,
|
||||
useDialog,
|
||||
useMessage,
|
||||
useNotification,
|
||||
useModal,
|
||||
} from "naive-ui"
|
||||
import { useLoadingBar, useDialog, useMessage, useNotification, useModal } from "naive-ui"
|
||||
|
||||
window.$loadingbar = useLoadingBar()
|
||||
window.$dialog = useDialog()
|
||||
|
|
|
@ -19,9 +19,7 @@ export class SHA256Calculator {
|
|||
throw new Error("Data must be a string or ArrayBuffer")
|
||||
}
|
||||
|
||||
const combinedData = new Uint8Array(
|
||||
this.digestBuffer.length + newData.length,
|
||||
)
|
||||
const combinedData = new Uint8Array(this.digestBuffer.length + newData.length)
|
||||
combinedData.set(this.digestBuffer, 0)
|
||||
combinedData.set(newData, this.digestBuffer.length)
|
||||
this.digestBuffer = combinedData
|
||||
|
|
|
@ -25,11 +25,7 @@ const displayMap = reactive(new Map<number, UploadDisplayInfo>())
|
|||
watch(displayMap, () => {
|
||||
let notDoneCount = 0
|
||||
displayMap.forEach((value) => {
|
||||
if (
|
||||
value.status !== "mirrored" &&
|
||||
value.status !== "merged" &&
|
||||
value.status !== "canceled"
|
||||
) {
|
||||
if (value.status !== "mirrored" && value.status !== "merged" && value.status !== "canceled") {
|
||||
notDoneCount++
|
||||
}
|
||||
})
|
||||
|
@ -156,12 +152,7 @@ function onPauseButtonClick(taskId: number) {
|
|||
function onRemoveButtonClick(taskId: number) {
|
||||
const info = displayMap.get(taskId)
|
||||
if (!info) return
|
||||
if (
|
||||
info.status === "mirrored" ||
|
||||
info.status === "merged" ||
|
||||
info.status === "canceled" ||
|
||||
info.status === "error"
|
||||
) {
|
||||
if (info.status === "mirrored" || info.status === "merged" || info.status === "canceled" || info.status === "error") {
|
||||
displayMap.delete(taskId)
|
||||
} else {
|
||||
uploader.postMessage({
|
||||
|
@ -174,20 +165,8 @@ function onRemoveButtonClick(taskId: number) {
|
|||
|
||||
<template>
|
||||
<input v-show="false" ref="fileInputRef" MULTIPLE type="file" />
|
||||
<input
|
||||
v-show="false"
|
||||
ref="folderInputRef"
|
||||
mozdirectory
|
||||
odirectory
|
||||
type="file"
|
||||
webkitdirectory
|
||||
/>
|
||||
<n-drawer
|
||||
v-model:show="isUploadDrawerShow"
|
||||
:placement="'right'"
|
||||
:width="502"
|
||||
:auto-focus="false"
|
||||
>
|
||||
<input v-show="false" ref="folderInputRef" mozdirectory odirectory type="file" webkitdirectory />
|
||||
<n-drawer v-model:show="isUploadDrawerShow" :placement="'right'" :width="502" :auto-focus="false">
|
||||
<n-drawer-content
|
||||
id="content"
|
||||
:native-scrollbar="false"
|
||||
|
|
|
@ -1,12 +1,5 @@
|
|||
<script lang="ts" setup>
|
||||
import {
|
||||
ArchiveOutline,
|
||||
CheckmarkOutline,
|
||||
CloseOutline,
|
||||
HelpOutline,
|
||||
PauseOutline,
|
||||
PlayOutline,
|
||||
} from "@vicons/ionicons5"
|
||||
import { CheckmarkOutline, CloseOutline, HelpOutline, PauseOutline, PlayOutline } from "@vicons/ionicons5"
|
||||
import { useThemeVars } from "naive-ui"
|
||||
import { type2Icon } from "@/utils"
|
||||
|
||||
|
@ -24,18 +17,18 @@ const info = computed<UploadDisplayInfo>(() => props.data)
|
|||
const themeVars = useThemeVars()
|
||||
const progress = computed(() => info.value.progress)
|
||||
const progressText = computed(() => `${progress.value.toFixed(2)}%`)
|
||||
const finished = computed(() => info.value.status === 'mirrored' || info.value.status === 'uploaded')
|
||||
const finished = computed(() => info.value.status === "mirrored" || info.value.status === "merged")
|
||||
const progressColor = computed(() => {
|
||||
switch (info.value.status) {
|
||||
case 'uploading':
|
||||
case 'waiting':
|
||||
case "uploading":
|
||||
case "waiting":
|
||||
return `${themeVars.value.primaryColor}50`
|
||||
case 'paused':
|
||||
case "paused":
|
||||
return `${themeVars.value.warningColor}50`
|
||||
case 'error':
|
||||
case "error":
|
||||
return `${themeVars.value.errorColor}50`
|
||||
}
|
||||
return `transparent`
|
||||
return "transparent"
|
||||
})
|
||||
|
||||
// 根据文件类型选择图标
|
||||
|
@ -64,7 +57,7 @@ const onRemoveButtonClick = (() => {
|
|||
const text = computed(() => {
|
||||
switch (info.value.status) {
|
||||
case "uploading":
|
||||
return `${Math.min(info.value.progress, 100).toFixed(0)}%`
|
||||
return `${Math.min(progress.value, 100).toFixed(0)}%`
|
||||
case "paused":
|
||||
return "已暂停"
|
||||
case "waiting":
|
||||
|
@ -100,8 +93,14 @@ const buttonIcon = computed(() => {
|
|||
<n-button v-show="false" circle quaternary size="small" :disabled="finished" @click="emit('onPauseButtonClick')">
|
||||
<n-icon :component="info.status == 'paused' ? PlayOutline : PauseOutline" />
|
||||
</n-button>
|
||||
<n-button style="margin-right: 24px" :quaternary="!isConfirming" circle size="small"
|
||||
:type="finished ? 'success' : 'error'" @click="onRemoveButtonClick">
|
||||
<n-button
|
||||
style="margin-right: 24px"
|
||||
:quaternary="!isConfirming"
|
||||
circle
|
||||
size="small"
|
||||
:type="finished ? 'success' : 'error'"
|
||||
@click="onRemoveButtonClick"
|
||||
>
|
||||
<n-icon :component="buttonIcon" />
|
||||
</n-button>
|
||||
</n-flex>
|
||||
|
@ -111,7 +110,7 @@ const buttonIcon = computed(() => {
|
|||
.container {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
position: relative
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.container::before {
|
||||
|
@ -124,6 +123,8 @@ const buttonIcon = computed(() => {
|
|||
transform: scaleX(v-bind(progressText));
|
||||
transform-origin: left;
|
||||
background-color: v-bind(progressColor);
|
||||
transition: transform 0.2s linear, background-color 0.5s;
|
||||
transition:
|
||||
transform 0.2s linear,
|
||||
background-color 0.5s;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -248,12 +248,9 @@ async function uploadByTask(task: UploadTask, fileHash: string): Promise<void> {
|
|||
log("upload finished")
|
||||
// 轮询检查合并状态
|
||||
const checkMergeStatus = async () => {
|
||||
const response = await fetch(
|
||||
`${config.createTaskUrl}/${taskId}`,
|
||||
{
|
||||
headers: requestHeader,
|
||||
},
|
||||
)
|
||||
const response = await fetch(`${config.createTaskUrl}/${taskId}`, {
|
||||
headers: requestHeader,
|
||||
})
|
||||
const responseJson = await response.json()
|
||||
log("checkMergeStatus", responseJson)
|
||||
const merged = responseJson["data"]["merged"]
|
||||
|
@ -268,9 +265,7 @@ async function uploadByTask(task: UploadTask, fileHash: string): Promise<void> {
|
|||
}
|
||||
} else {
|
||||
log("upload failed", xhr.responseText)
|
||||
reject(
|
||||
new Error(`Failed to upload chunk ${index}: ${xhr.statusText}`),
|
||||
)
|
||||
reject(new Error(`Failed to upload chunk ${index}: ${xhr.statusText}`))
|
||||
}
|
||||
}
|
||||
xhr.onerror = function () {
|
||||
|
@ -290,8 +285,7 @@ async function uploadByTask(task: UploadTask, fileHash: string): Promise<void> {
|
|||
function onProgress(event, index) {
|
||||
log(`Chunk ${index} progress: ${event.loaded}/${event.total}`)
|
||||
progressList[index] = event.loaded
|
||||
const overallProgress =
|
||||
progressList.reduce((acc, cur) => acc + cur, 0) / file.size
|
||||
const overallProgress = progressList.reduce((acc, cur) => acc + cur, 0) / file.size
|
||||
log(`Overall progress: ${overallProgress * 100}%`)
|
||||
postMessage({
|
||||
event: "progress",
|
||||
|
|
|
@ -5,10 +5,7 @@ import { useGlobal } from "./vue"
|
|||
* 使用事件总线
|
||||
* @returns 事件总线
|
||||
*/
|
||||
export function useBusEvent<T extends BusEvent>(
|
||||
event: T,
|
||||
callback: (...args: EventParams[T]) => void,
|
||||
) {
|
||||
export function useBusEvent<T extends BusEvent>(event: T, callback: (...args: EventParams[T]) => void) {
|
||||
const { $bus } = useGlobal()
|
||||
$bus.on(event, callback as (...args: any[]) => void)
|
||||
onUnmounted(() => $bus.off(event, callback as (...args: any[]) => void))
|
||||
|
@ -17,10 +14,7 @@ export function useBusEvent<T extends BusEvent>(
|
|||
/**
|
||||
* 发出事件
|
||||
*/
|
||||
export function emitBusEvent<T extends BusEvent>(
|
||||
event: T,
|
||||
...args: EventParams[T]
|
||||
) {
|
||||
export function emitBusEvent<T extends BusEvent>(event: T, ...args: EventParams[T]) {
|
||||
const { $bus } = useGlobal()
|
||||
console.debug(`[Bus] Emit event: ${event}`, ...args)
|
||||
$bus.emit(event, ...args)
|
||||
|
|
|
@ -8,11 +8,7 @@ export * from "./vue"
|
|||
* @param event 事件名称
|
||||
* @param callback 事件回调
|
||||
*/
|
||||
export function useEventListener(
|
||||
target: EventTarget,
|
||||
event: string,
|
||||
callback: EventListenerOrEventListenerObject,
|
||||
) {
|
||||
export function useEventListener(target: EventTarget, event: string, callback: EventListenerOrEventListenerObject) {
|
||||
onMounted(() => target.addEventListener(event, callback))
|
||||
onUnmounted(() => target.removeEventListener(event, callback))
|
||||
}
|
||||
|
|
|
@ -29,9 +29,7 @@ export const useGlobal = (() => {
|
|||
* @param fn 需要缓存的函数
|
||||
* @returns 带缓存的函数
|
||||
*/
|
||||
export function useComputedFn<T>(
|
||||
fn: (...args: unknown[]) => T,
|
||||
): (...args: unknown[]) => ComputedRef<T> {
|
||||
export function useComputedFn<T>(fn: (...args: unknown[]) => T): (...args: unknown[]) => ComputedRef<T> {
|
||||
const cache: Map<string, ComputedRef<T>> = new Map()
|
||||
return (...args: unknown[]) => {
|
||||
const cacheKey = JSON.stringify(args)
|
||||
|
|
25
src/main.ts
25
src/main.ts
|
@ -72,21 +72,16 @@ function createGeetest(): GeetestComponent {
|
|||
document.head.appendChild(script)
|
||||
return {
|
||||
validate: (onFail: (w: GeetestFailInfo) => void = () => {}) =>
|
||||
new Promise<GeetestSuccessInfo>(
|
||||
(
|
||||
resolve: (value: GeetestSuccessInfo) => void = () => {},
|
||||
reject = () => {},
|
||||
) => {
|
||||
if (!geetest) {
|
||||
reject(new Error("geetest not ready"))
|
||||
return
|
||||
}
|
||||
geetest.onSuccess(() => resolve(geetest.getValidate()))
|
||||
geetest.onFail(onFail)
|
||||
geetest.onError(reject)
|
||||
geetest.showCaptcha()
|
||||
},
|
||||
),
|
||||
new Promise<GeetestSuccessInfo>((resolve: (value: GeetestSuccessInfo) => void = () => {}, reject = () => {}) => {
|
||||
if (!geetest) {
|
||||
reject(new Error("geetest not ready"))
|
||||
return
|
||||
}
|
||||
geetest.onSuccess(() => resolve(geetest.getValidate()))
|
||||
geetest.onFail(onFail)
|
||||
geetest.onError(reject)
|
||||
geetest.showCaptcha()
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,13 +15,7 @@ const router = useRouter()
|
|||
|
||||
<template>
|
||||
<n-card class="page">
|
||||
<n-result
|
||||
class="center"
|
||||
status="error"
|
||||
title="404 页面不存在"
|
||||
size="huge"
|
||||
description="需要帮助请联系管理员"
|
||||
>
|
||||
<n-result class="center" status="error" title="404 页面不存在" size="huge" description="需要帮助请联系管理员">
|
||||
<template #footer>
|
||||
<n-space justify="center">
|
||||
<n-button @click="router.replace('/')"> 回到首页 </n-button>
|
||||
|
|
|
@ -79,11 +79,7 @@ onBeforeMount(async () => {
|
|||
Kenko Drive Vue 前端
|
||||
<n-popover trigger="hover">
|
||||
<template #trigger>
|
||||
<n-tag
|
||||
style="cursor: pointer"
|
||||
type="info"
|
||||
@click="showRoadMap = !showRoadMap"
|
||||
>
|
||||
<n-tag style="cursor: pointer" type="info" @click="showRoadMap = !showRoadMap">
|
||||
{{ frontendVersion }}
|
||||
</n-tag>
|
||||
</template>
|
||||
|
@ -105,20 +101,8 @@ onBeforeMount(async () => {
|
|||
<p>MIT License</p>
|
||||
<p>
|
||||
<n-space>
|
||||
<n-button
|
||||
:href="`${frontendRepoUrl}/issues`"
|
||||
tag="a"
|
||||
target="_blank"
|
||||
>
|
||||
问题反馈
|
||||
</n-button>
|
||||
<n-button
|
||||
:href="`${frontendRepoUrl}/releases`"
|
||||
tag="a"
|
||||
target="_blank"
|
||||
>
|
||||
发布日志
|
||||
</n-button>
|
||||
<n-button :href="`${frontendRepoUrl}/issues`" tag="a" target="_blank"> 问题反馈 </n-button>
|
||||
<n-button :href="`${frontendRepoUrl}/releases`" tag="a" target="_blank"> 发布日志 </n-button>
|
||||
</n-space>
|
||||
</p>
|
||||
</div>
|
||||
|
@ -147,20 +131,8 @@ onBeforeMount(async () => {
|
|||
<p>MIT License</p>
|
||||
<p>
|
||||
<n-space>
|
||||
<n-button
|
||||
:href="`${backendRepoUrl}/issues`"
|
||||
tag="a"
|
||||
target="_blank"
|
||||
>
|
||||
问题反馈
|
||||
</n-button>
|
||||
<n-button
|
||||
:href="`${backendRepoUrl}/releases`"
|
||||
tag="a"
|
||||
target="_blank"
|
||||
>
|
||||
发布日志
|
||||
</n-button>
|
||||
<n-button :href="`${backendRepoUrl}/issues`" tag="a" target="_blank"> 问题反馈 </n-button>
|
||||
<n-button :href="`${backendRepoUrl}/releases`" tag="a" target="_blank"> 发布日志 </n-button>
|
||||
</n-space>
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
@ -10,14 +10,7 @@
|
|||
<script setup lang="ts">
|
||||
import { AddOutline, RefreshOutline, SearchOutline } from "@vicons/ionicons5"
|
||||
import type { PaginationProps } from "naive-ui"
|
||||
import {
|
||||
type FormInst,
|
||||
NButton,
|
||||
NInput,
|
||||
NSpace,
|
||||
NText,
|
||||
NTooltip,
|
||||
} from "naive-ui"
|
||||
import { type FormInst, NButton, NInput, NSpace, NText, NTooltip } from "naive-ui"
|
||||
import {
|
||||
addAnnouncement,
|
||||
deleteAnnouncement,
|
||||
|
@ -272,11 +265,7 @@ function onModalPositiveButtonClick() {
|
|||
if (!selectRow.value.id) {
|
||||
throw new Error("未获取到用户ID")
|
||||
}
|
||||
updateAnnouncement(
|
||||
selectRow.value.id,
|
||||
modalData.value.title,
|
||||
modalData.value.content,
|
||||
)
|
||||
updateAnnouncement(selectRow.value.id, modalData.value.title, modalData.value.content)
|
||||
.then(() => {
|
||||
getData()
|
||||
window.$message.success("修改成功")
|
||||
|
@ -313,11 +302,7 @@ function onEditButtonClick(row: Announcement) {
|
|||
/** 获取表格数据 */
|
||||
function getData() {
|
||||
isLoading.value = true
|
||||
getAnnouncements(
|
||||
pagination.page - 1,
|
||||
pagination.pageSize,
|
||||
searchExpression.value,
|
||||
)
|
||||
getAnnouncements(pagination.page - 1, pagination.pageSize, searchExpression.value)
|
||||
.then((res) => {
|
||||
let data: Page<any> = res.data
|
||||
requestData.value = data.list
|
||||
|
@ -334,10 +319,7 @@ function getData() {
|
|||
<template>
|
||||
<div style="padding: 12px">
|
||||
<!-- 确认删除模态框 -->
|
||||
<ConfirmModal
|
||||
v-model:show="showDeleteConfirmModal"
|
||||
@positive-click="onDeleteConfirm"
|
||||
/>
|
||||
<ConfirmModal v-model:show="showDeleteConfirmModal" @positive-click="onDeleteConfirm" />
|
||||
|
||||
<!-- 新增删除模态框 -->
|
||||
<n-modal
|
||||
|
@ -350,30 +332,17 @@ function getData() {
|
|||
@after-leave="onAfterEditModalLeave"
|
||||
>
|
||||
<n-space vertical>
|
||||
<n-form
|
||||
ref="modalFormRef"
|
||||
:model="modalData"
|
||||
:rules="rules"
|
||||
label-placement="left"
|
||||
label-width="auto"
|
||||
>
|
||||
<n-form ref="modalFormRef" :model="modalData" :rules="rules" label-placement="left" label-width="auto">
|
||||
<n-form-item label="标题" path="title">
|
||||
<n-input v-model:value="modalData.title" placeholder="输入标题" />
|
||||
</n-form-item>
|
||||
<n-form-item label="内容" path="content">
|
||||
<n-input
|
||||
v-model:value="modalData.content"
|
||||
placeholder="输入内容"
|
||||
type="textarea"
|
||||
/>
|
||||
<n-input v-model:value="modalData.content" placeholder="输入内容" type="textarea" />
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</n-space>
|
||||
<n-space justify="end" style="width: 100%">
|
||||
<n-button
|
||||
:type="isEdit ? 'warning' : 'success'"
|
||||
@click="onModalPositiveButtonClick"
|
||||
>
|
||||
<n-button :type="isEdit ? 'warning' : 'success'" @click="onModalPositiveButtonClick">
|
||||
{{ isEdit ? "修改" : "确定" }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
|
@ -408,13 +377,7 @@ function getData() {
|
|||
<n-icon :component="SearchOutline" />
|
||||
</template>
|
||||
</n-input>
|
||||
<n-button
|
||||
:disabled="isLoading || searchExpression.length === 0"
|
||||
ghost
|
||||
@click="getData"
|
||||
>
|
||||
搜索
|
||||
</n-button>
|
||||
<n-button :disabled="isLoading || searchExpression.length === 0" ghost @click="getData"> 搜索 </n-button>
|
||||
</n-input-group>
|
||||
</n-space>
|
||||
|
||||
|
|
|
@ -49,11 +49,7 @@ const columns = [
|
|||
secondary: true,
|
||||
size: "small",
|
||||
disabled: loading.value,
|
||||
type: loading.value
|
||||
? "tertiary"
|
||||
: isUserInRole(row)
|
||||
? "error"
|
||||
: "primary",
|
||||
type: loading.value ? "tertiary" : isUserInRole(row) ? "error" : "primary",
|
||||
onClick: () => onActionClick(row),
|
||||
},
|
||||
{ default: () => (isUserInRole(row) ? "移除角色" : "分配角色") },
|
||||
|
@ -116,9 +112,7 @@ const onActionClick = (user: User) => {
|
|||
unassignRoleUsers(props.role.id, [user.id])
|
||||
.then(() => {
|
||||
window.$message.success("移除成功")
|
||||
selectedUserIds.value = selectedUserIds.value.filter(
|
||||
(id) => id !== user.id,
|
||||
)
|
||||
selectedUserIds.value = selectedUserIds.value.filter((id) => id !== user.id)
|
||||
})
|
||||
.catch((e) => {
|
||||
window.$message.error("移除失败")
|
||||
|
|
|
@ -11,14 +11,7 @@
|
|||
import { AddOutline, RefreshOutline, SearchOutline } from "@vicons/ionicons5"
|
||||
import type { FormInst, PaginationProps } from "naive-ui"
|
||||
import { NButton, NInput, NSpace, NSwitch } from "naive-ui"
|
||||
import {
|
||||
addRole,
|
||||
deleteRole,
|
||||
getPermissions,
|
||||
getRoles,
|
||||
updateRole,
|
||||
updateRoleStatus,
|
||||
} from "@/api/role"
|
||||
import { addRole, deleteRole, getPermissions, getRoles, updateRole, updateRoleStatus } from "@/api/role"
|
||||
import ConfirmModal from "@/components/ConfirmModal.vue"
|
||||
import UserTable from "./UserTable.vue"
|
||||
|
||||
|
@ -213,9 +206,7 @@ const onModalConfirm = () => {
|
|||
.then(() => {
|
||||
showEditModal.value = false
|
||||
window.$message.success("修改成功")
|
||||
const index = tableData.value.findIndex(
|
||||
(r) => r.id === modalData.value.id,
|
||||
)
|
||||
const index = tableData.value.findIndex((r) => r.id === modalData.value.id)
|
||||
if (index !== -1) {
|
||||
tableData.value[index] = {
|
||||
...tableData.value[index],
|
||||
|
@ -298,9 +289,7 @@ const onDeleteConfirm = () => {
|
|||
deleteRole(selectedRow.value.id)
|
||||
.then(() => {
|
||||
window.$message.success("删除成功")
|
||||
tableData.value = tableData.value.filter(
|
||||
(r) => r.id !== selectedRow.value?.id,
|
||||
)
|
||||
tableData.value = tableData.value.filter((r) => r.id !== selectedRow.value?.id)
|
||||
})
|
||||
.catch(() => {
|
||||
window.$message.error("删除失败")
|
||||
|
@ -349,10 +338,7 @@ const getData = () => {
|
|||
<template>
|
||||
<div style="padding: 12px">
|
||||
<!-- 确认删除模态框 -->
|
||||
<ConfirmModal
|
||||
v-model:show="showDeleteConfirmModal"
|
||||
@positive-click="onDeleteConfirm"
|
||||
/>
|
||||
<ConfirmModal v-model:show="showDeleteConfirmModal" @positive-click="onDeleteConfirm" />
|
||||
|
||||
<!-- 新增编辑模态框 -->
|
||||
<n-modal
|
||||
|
@ -367,26 +353,12 @@ const getData = () => {
|
|||
@after-leave="onModalClosed"
|
||||
>
|
||||
<n-flex vertical>
|
||||
<n-form
|
||||
ref="modalFormRef"
|
||||
:model="modalData"
|
||||
:rules="rules"
|
||||
label-placement="left"
|
||||
label-width="auto"
|
||||
>
|
||||
<n-form ref="modalFormRef" :model="modalData" :rules="rules" label-placement="left" label-width="auto">
|
||||
<n-form-item path="name" label="角色名">
|
||||
<n-input
|
||||
v-model:value="modalData.name"
|
||||
clearable
|
||||
placeholder="输入角色名"
|
||||
/>
|
||||
<n-input v-model:value="modalData.name" clearable placeholder="输入角色名" />
|
||||
</n-form-item>
|
||||
<n-form-item path="description" label="描述">
|
||||
<n-input
|
||||
v-model:value="modalData.description"
|
||||
clearable
|
||||
placeholder="可空"
|
||||
/>
|
||||
<n-input v-model:value="modalData.description" clearable placeholder="可空" />
|
||||
</n-form-item>
|
||||
<n-form-item path="default" label="设为默认">
|
||||
<n-switch v-model:value="modalData.default" />
|
||||
|
@ -421,12 +393,7 @@ const getData = () => {
|
|||
<n-form :show-label="false" inline :show-feedback="false">
|
||||
<n-formItem>
|
||||
<n-space>
|
||||
<n-button
|
||||
tertiary
|
||||
type="info"
|
||||
:disabled="isLoading"
|
||||
@click="getData"
|
||||
>
|
||||
<n-button tertiary type="info" :disabled="isLoading" @click="getData">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<RefreshOutline />
|
||||
|
@ -445,17 +412,12 @@ const getData = () => {
|
|||
</n-button>
|
||||
|
||||
<n-input-group>
|
||||
<n-input
|
||||
v-model:value="searchExpression"
|
||||
placeholder="角色名、描述"
|
||||
>
|
||||
<n-input v-model:value="searchExpression" placeholder="角色名、描述">
|
||||
<template #prefix>
|
||||
<n-icon :component="SearchOutline" />
|
||||
</template>
|
||||
</n-input>
|
||||
<n-button ghost :disabled="isLoading" @click="getData">
|
||||
搜索
|
||||
</n-button>
|
||||
<n-button ghost :disabled="isLoading" @click="getData"> 搜索 </n-button>
|
||||
</n-input-group>
|
||||
</n-space>
|
||||
</n-formItem>
|
||||
|
|
|
@ -84,18 +84,10 @@ const updateSettingsDebounced = useDebounceFn(() => {
|
|||
<template>
|
||||
<div style="padding: 20px; width: 500px; margin: 0 auto">
|
||||
<n-flex vertical>
|
||||
<n-form
|
||||
label-placement="left"
|
||||
label-width="auto"
|
||||
require-mark-placement="right-hanging"
|
||||
:show-feedback="true"
|
||||
>
|
||||
<n-form label-placement="left" label-width="auto" require-mark-placement="right-hanging" :show-feedback="true">
|
||||
<n-h3>用户注册</n-h3>
|
||||
<n-form-item label="开放注册">
|
||||
<n-switch
|
||||
v-model:value="settings.registerEnabled"
|
||||
:disabled="isLoading"
|
||||
/>
|
||||
<n-switch v-model:value="settings.registerEnabled" :disabled="isLoading" />
|
||||
</n-form-item>
|
||||
<n-form-item label="注册需要邮箱验证">
|
||||
<n-switch :disabled="true" :value="true" />
|
||||
|
@ -153,8 +145,7 @@ const updateSettingsDebounced = useDebounceFn(() => {
|
|||
:disabled="true"
|
||||
:options="[
|
||||
{
|
||||
label:
|
||||
'Everybody\'s Got Something to Hide Except Me and My Monkey',
|
||||
label: 'Everybody\'s Got Something to Hide Except Me and My Monkey',
|
||||
value: 'song0',
|
||||
disabled: true,
|
||||
},
|
||||
|
|
|
@ -50,11 +50,7 @@ const columns = [
|
|||
secondary: true,
|
||||
size: "small",
|
||||
disabled: loading.value,
|
||||
type: loading.value
|
||||
? "tertiary"
|
||||
: isRoleInUser(row)
|
||||
? "error"
|
||||
: "primary",
|
||||
type: loading.value ? "tertiary" : isRoleInUser(row) ? "error" : "primary",
|
||||
onClick: () => onActionClick(row),
|
||||
},
|
||||
{ default: () => (isRoleInUser(row) ? "移除角色" : "分配角色") },
|
||||
|
@ -118,9 +114,7 @@ const onActionClick = (role: Role) => {
|
|||
removeRoles(props.user.id, [role.id])
|
||||
.then(() => {
|
||||
window.$message.success("移除成功")
|
||||
selectedRoleIds.value = selectedRoleIds.value.filter(
|
||||
(id) => id !== role.id,
|
||||
)
|
||||
selectedRoleIds.value = selectedRoleIds.value.filter((id) => id !== role.id)
|
||||
})
|
||||
.catch((e) => {
|
||||
window.$message.error("移除失败")
|
||||
|
|
|
@ -10,24 +10,9 @@
|
|||
<script setup lang="ts">
|
||||
import { changeColor } from "seemly"
|
||||
import { AddOutline, RefreshOutline, SearchOutline } from "@vicons/ionicons5"
|
||||
import {
|
||||
NButton,
|
||||
NInput,
|
||||
NProgress,
|
||||
NSpace,
|
||||
NText,
|
||||
NTooltip,
|
||||
useThemeVars,
|
||||
} from "naive-ui"
|
||||
import { NButton, NInput, NProgress, NSpace, NText, NTooltip, useThemeVars } from "naive-ui"
|
||||
import type { FormInst, PaginationProps } from "naive-ui"
|
||||
import {
|
||||
addUser,
|
||||
deleteUser,
|
||||
getUsers,
|
||||
updateUserDisabled,
|
||||
updateUserInfo,
|
||||
updateUserPassword,
|
||||
} from "@/api/user"
|
||||
import { addUser, deleteUser, getUsers, updateUserDisabled, updateUserInfo, updateUserPassword } from "@/api/user"
|
||||
import RoleTable from "./RoleTable.vue"
|
||||
import ConfirmModal from "@/components/ConfirmModal.vue"
|
||||
import { renderTooltip } from "@/utils"
|
||||
|
@ -446,10 +431,7 @@ const getData = () => {
|
|||
<template>
|
||||
<div style="padding: 12px">
|
||||
<!-- 确认删除模态框 -->
|
||||
<ConfirmModal
|
||||
v-model:show="showDeleteConfirmModal"
|
||||
@positive-click="onDeleteUserConfirm"
|
||||
/>
|
||||
<ConfirmModal v-model:show="showDeleteConfirmModal" @positive-click="onDeleteUserConfirm" />
|
||||
|
||||
<!-- 重置密码模态框 -->
|
||||
<n-modal
|
||||
|
@ -473,12 +455,7 @@ const getData = () => {
|
|||
label-width="auto"
|
||||
>
|
||||
<n-form-item path="password" label="新密码">
|
||||
<n-input
|
||||
v-model:value="resetPasswordData.password"
|
||||
clearable
|
||||
placeholder="输入新密码"
|
||||
type="password"
|
||||
/>
|
||||
<n-input v-model:value="resetPasswordData.password" clearable placeholder="输入新密码" type="password" />
|
||||
</n-form-item>
|
||||
<n-form-item path="confirmPassword" label="确认密码">
|
||||
<n-input
|
||||
|
@ -490,15 +467,8 @@ const getData = () => {
|
|||
</n-form-item>
|
||||
</n-form>
|
||||
<n-space justify="end">
|
||||
<n-button
|
||||
type="error"
|
||||
@click="() => (showResetPasswordModal = false)"
|
||||
>
|
||||
取消
|
||||
</n-button>
|
||||
<n-button type="primary" @click="onResetPasswordClick">
|
||||
确定
|
||||
</n-button>
|
||||
<n-button type="error" @click="() => (showResetPasswordModal = false)"> 取消 </n-button>
|
||||
<n-button type="primary" @click="onResetPasswordClick"> 确定 </n-button>
|
||||
</n-space>
|
||||
</n-space>
|
||||
</n-modal>
|
||||
|
@ -516,13 +486,7 @@ const getData = () => {
|
|||
@after-leave="onAfterEditModalLeave"
|
||||
>
|
||||
<n-space vertical>
|
||||
<n-form
|
||||
ref="modalFormRef"
|
||||
:model="modalData"
|
||||
:rules="rules"
|
||||
label-placement="left"
|
||||
label-width="auto"
|
||||
>
|
||||
<n-form ref="modalFormRef" :model="modalData" :rules="rules" label-placement="left" label-width="auto">
|
||||
<n-form-item path="username" label="用户名">
|
||||
<n-tooltip :disabled="!isEdit" trigger="hover" placement="top">
|
||||
<template #trigger>
|
||||
|
@ -547,34 +511,18 @@ const getData = () => {
|
|||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="repeatPassword" label="确认密码">
|
||||
<n-input
|
||||
v-model:value="modalData.repeatPassword"
|
||||
type="password"
|
||||
clearable
|
||||
placeholder="重复密码"
|
||||
/>
|
||||
<n-input v-model:value="modalData.repeatPassword" type="password" clearable placeholder="重复密码" />
|
||||
</n-form-item>
|
||||
<n-form-item path="nickname" label="昵称">
|
||||
<n-input
|
||||
v-model:value="modalData.nickname"
|
||||
clearable
|
||||
placeholder="输入昵称"
|
||||
/>
|
||||
<n-input v-model:value="modalData.nickname" clearable placeholder="输入昵称" />
|
||||
</n-form-item>
|
||||
<n-form-item path="email" label="邮箱">
|
||||
<n-input
|
||||
v-model:value="modalData.email"
|
||||
clearable
|
||||
placeholder="输入邮箱"
|
||||
/>
|
||||
<n-input v-model:value="modalData.email" clearable placeholder="输入邮箱" />
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</n-space>
|
||||
<n-space justify="end" style="width: 100%">
|
||||
<n-button
|
||||
:type="isEdit ? 'warning' : 'success'"
|
||||
@click="onModalPositiveButtonClick"
|
||||
>
|
||||
<n-button :type="isEdit ? 'warning' : 'success'" @click="onModalPositiveButtonClick">
|
||||
{{ isEdit ? "修改" : "确定" }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
|
@ -615,13 +563,7 @@ const getData = () => {
|
|||
<n-icon :component="SearchOutline" />
|
||||
</template>
|
||||
</n-input>
|
||||
<n-button
|
||||
ghost
|
||||
:disabled="isLoading || searchExpression.length === 0"
|
||||
@click="getData"
|
||||
>
|
||||
搜索
|
||||
</n-button>
|
||||
<n-button ghost :disabled="isLoading || searchExpression.length === 0" @click="getData"> 搜索 </n-button>
|
||||
</n-input-group>
|
||||
</n-space>
|
||||
|
||||
|
|
|
@ -20,10 +20,7 @@ const isLoading = ref(false)
|
|||
const folderName = ref("")
|
||||
const create = () => {
|
||||
isLoading.value = true
|
||||
createFolder(
|
||||
hasText(folderName.value) ? folderName.value : undefined,
|
||||
props.parent,
|
||||
)
|
||||
createFolder(hasText(folderName.value) ? folderName.value : undefined, props.parent)
|
||||
.then(() => {
|
||||
emit("success")
|
||||
show.value = false
|
||||
|
@ -47,21 +44,11 @@ const create = () => {
|
|||
<n-flex vertical>
|
||||
<n-form :show-label="false" :disabled="isLoading">
|
||||
<n-form-item required>
|
||||
<n-input
|
||||
v-model:value="folderName"
|
||||
placeholder="请输入文件夹名称"
|
||||
@keyup.enter="create"
|
||||
/>
|
||||
<n-input v-model:value="folderName" placeholder="请输入文件夹名称" @keyup.enter="create" />
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-flex justify="end" style="margin-top: -10px">
|
||||
<n-button
|
||||
type="primary"
|
||||
:disabled="isLoading"
|
||||
:loading="isLoading"
|
||||
@click="create"
|
||||
>确定</n-button
|
||||
>
|
||||
<n-button type="primary" :disabled="isLoading" :loading="isLoading" @click="create">确定</n-button>
|
||||
</n-flex>
|
||||
</n-flex>
|
||||
</n-modal>
|
||||
|
|
|
@ -11,22 +11,10 @@
|
|||
import { useRouter } from "vue-router/auto"
|
||||
import { storeToRefs } from "pinia"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import {
|
||||
NButton,
|
||||
NDropdown,
|
||||
NFlex,
|
||||
NIcon,
|
||||
NImage,
|
||||
useThemeVars,
|
||||
} from "naive-ui"
|
||||
import { NButton, NDropdown, NFlex, NIcon, NImage, useThemeVars } from "naive-ui"
|
||||
import type { DataTableColumns } from "naive-ui"
|
||||
import { ArrowUp, Folder } from "@vicons/carbon"
|
||||
import {
|
||||
AddOutline,
|
||||
ArrowUpOutline,
|
||||
RefreshOutline,
|
||||
TrashBinOutline,
|
||||
} from "@vicons/ionicons5"
|
||||
import { AddOutline, ArrowUpOutline, RefreshOutline, TrashBinOutline } from "@vicons/ionicons5"
|
||||
import { FolderOpenOutlined } from "@vicons/material"
|
||||
import {
|
||||
ArrowDownload24Regular as DownloadIcon,
|
||||
|
@ -37,12 +25,7 @@ import {
|
|||
Share24Regular as ShareIcon,
|
||||
} from "@vicons/fluent"
|
||||
import { filesize } from "filesize"
|
||||
import {
|
||||
deleteFile as deleteFileEndpoint,
|
||||
getFileTemporaryUrl,
|
||||
getFolderContent,
|
||||
moveFile,
|
||||
} from "@/api/file"
|
||||
import { deleteFile as deleteFileEndpoint, getFileTemporaryUrl, getFolderContent, moveFile } from "@/api/file"
|
||||
import CreateFolderModal from "./CreateFolderModal.vue"
|
||||
import { renderIcon, type2Icon } from "@/utils"
|
||||
import { useAppConfig } from "@/stores/app-config"
|
||||
|
@ -182,12 +165,7 @@ const columns: DataTableColumns<TableData> = [
|
|||
NIcon,
|
||||
{ size: 30, color: themeVars.value.primaryColor, depth: 2 },
|
||||
{
|
||||
default: () =>
|
||||
h(
|
||||
isFolder
|
||||
? FolderOpenOutlined
|
||||
: type2Icon(row.fileType, row.name),
|
||||
),
|
||||
default: () => h(isFolder ? FolderOpenOutlined : type2Icon(row.fileType, row.name)),
|
||||
},
|
||||
),
|
||||
h(
|
||||
|
@ -265,8 +243,7 @@ function onActionSelect(key: string, row: TableData) {
|
|||
const { openConfirmModal } = useConfirmModal()
|
||||
function deleteItem(row: TableData) {
|
||||
openConfirmModal(() => {
|
||||
const endpoint =
|
||||
row.type === "folder" ? deleteFolderEndpoint : deleteFileEndpoint
|
||||
const endpoint = row.type === "folder" ? deleteFolderEndpoint : deleteFileEndpoint
|
||||
endpoint(row.id).then(() => {
|
||||
window.$message.success("删除成功")
|
||||
loadFolder(currentFolderId.value)
|
||||
|
@ -333,10 +310,7 @@ function playFile(row: TableData) {
|
|||
}
|
||||
|
||||
// docx
|
||||
if (
|
||||
fileType ===
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document"
|
||||
) {
|
||||
if (fileType === "application/vnd.openxmlformats-officedocument.wordprocessingml.document") {
|
||||
getFileTemporaryUrl(row.id).then((res) => {
|
||||
const route = router.resolve({
|
||||
name: "docx-preview",
|
||||
|
@ -347,10 +321,7 @@ function playFile(row: TableData) {
|
|||
return
|
||||
}
|
||||
// xlsx
|
||||
if (
|
||||
fileType ===
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
||||
) {
|
||||
if (fileType === "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") {
|
||||
getFileTemporaryUrl(row.id).then((res) => {
|
||||
const route = router.resolve({
|
||||
name: "xlsx-preview",
|
||||
|
@ -572,34 +543,14 @@ function onBreadcrumbDrop(folderId: string | undefined, event: DragEvent) {
|
|||
ref="imageRef"
|
||||
:show-toolbar-tooltip="true"
|
||||
:src="imagePreviewUrl"
|
||||
style="
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
"
|
||||
style="display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%)"
|
||||
@load="onImageLoaded"
|
||||
/>
|
||||
<n-modal
|
||||
v-model:show="showMarkdownPreview"
|
||||
preset="card"
|
||||
style="width: 70%"
|
||||
title="Markdown 预览"
|
||||
>
|
||||
<n-modal v-model:show="showMarkdownPreview" preset="card" style="width: 70%" title="Markdown 预览">
|
||||
<MarkdownPreview :value="markdownPreviewValue" />
|
||||
</n-modal>
|
||||
<n-modal
|
||||
v-model:show="showMonaco"
|
||||
preset="card"
|
||||
style="width: 80%; height: 80vh"
|
||||
title="代码预览"
|
||||
>
|
||||
<MonacoEditor
|
||||
:content="monacoPreviewValue"
|
||||
:dark="isDarkMode"
|
||||
:language="monacoLanguage"
|
||||
/>
|
||||
<n-modal v-model:show="showMonaco" preset="card" style="width: 80%; height: 80vh" title="代码预览">
|
||||
<MonacoEditor :content="monacoPreviewValue" :dark="isDarkMode" :language="monacoLanguage" />
|
||||
</n-modal>
|
||||
<div style="padding-top: 10px">
|
||||
<CreateFolderModal
|
||||
|
@ -610,15 +561,8 @@ function onBreadcrumbDrop(folderId: string | undefined, event: DragEvent) {
|
|||
<!-- 页面内容 -->
|
||||
<n-flex vertical>
|
||||
<!-- 操作按钮 -->
|
||||
<n-flex
|
||||
class="buttons-container"
|
||||
:style="{ '--color': themeVars.dividerColor }"
|
||||
>
|
||||
<n-button
|
||||
tertiary
|
||||
type="info"
|
||||
@click="() => loadFolder(currentFolderId)"
|
||||
>
|
||||
<n-flex class="buttons-container" :style="{ '--color': themeVars.dividerColor }">
|
||||
<n-button tertiary type="info" @click="() => loadFolder(currentFolderId)">
|
||||
<template #icon>
|
||||
<n-icon :component="RefreshOutline" />
|
||||
</template>
|
||||
|
|
|
@ -63,12 +63,8 @@ function fetchAnnouncements() {
|
|||
// 把 时间 字符串转换为 Date 对象
|
||||
// 格式:2023-08-25T09:05:13.497+00:00
|
||||
announcements.value.forEach((announcement) => {
|
||||
announcement.createTime = new Date(
|
||||
announcement.createTime,
|
||||
).toLocaleString()
|
||||
announcement.updateTime = new Date(
|
||||
announcement.updateTime,
|
||||
).toLocaleString()
|
||||
announcement.createTime = new Date(announcement.createTime).toLocaleString()
|
||||
announcement.updateTime = new Date(announcement.updateTime).toLocaleString()
|
||||
})
|
||||
lastFetchTime.value = Date.now()
|
||||
})
|
||||
|
@ -107,18 +103,13 @@ onActivated(() => {
|
|||
</n-flex>
|
||||
|
||||
<n-list v-show="announcements.length > 0" bordered>
|
||||
<n-list-item
|
||||
v-for="announcement in announcements"
|
||||
:key="announcement.title"
|
||||
>
|
||||
<n-list-item v-for="announcement in announcements" :key="announcement.title">
|
||||
<n-thing
|
||||
:title="announcement.title"
|
||||
:title-extra="announcement.userNickname"
|
||||
:description="announcement.updateTime"
|
||||
>
|
||||
<div v-for="line in announcement.content.split('\n')" :key="line">
|
||||
{{ line }}<br />
|
||||
</div>
|
||||
<div v-for="line in announcement.content.split('\n')" :key="line">{{ line }}<br /></div>
|
||||
</n-thing>
|
||||
</n-list-item>
|
||||
</n-list>
|
||||
|
|
|
@ -73,9 +73,7 @@ const uploadAvatar = (fileList: UploadFileInfo[]) => {
|
|||
@update:file-list="uploadAvatar"
|
||||
>
|
||||
<n-space vertical>
|
||||
<n-upload-dragger
|
||||
style="margin: 0; padding: 0; height: 100px; width: 100px"
|
||||
>
|
||||
<n-upload-dragger style="margin: 0; padding: 0; height: 100px; width: 100px">
|
||||
<n-image
|
||||
object-fit="fill"
|
||||
preview-disabled
|
||||
|
@ -94,9 +92,7 @@ const uploadAvatar = (fileList: UploadFileInfo[]) => {
|
|||
<n-space>
|
||||
<n-space vertical>
|
||||
<n-input-group>
|
||||
<n-input-group-label class="info-label">
|
||||
用户名
|
||||
</n-input-group-label>
|
||||
<n-input-group-label class="info-label"> 用户名 </n-input-group-label>
|
||||
<n-tooltip trigger="hover" placement="top">
|
||||
<template #trigger>
|
||||
<n-input :value="username" disabled />
|
||||
|
@ -105,15 +101,11 @@ const uploadAvatar = (fileList: UploadFileInfo[]) => {
|
|||
</n-tooltip>
|
||||
</n-input-group>
|
||||
<n-input-group>
|
||||
<n-input-group-label class="info-label">
|
||||
昵称
|
||||
</n-input-group-label>
|
||||
<n-input-group-label class="info-label"> 昵称 </n-input-group-label>
|
||||
<n-input v-model:value="personalInfo.nickname" />
|
||||
</n-input-group>
|
||||
<n-input-group>
|
||||
<n-input-group-label class="info-label">
|
||||
邮箱
|
||||
</n-input-group-label>
|
||||
<n-input-group-label class="info-label"> 邮箱 </n-input-group-label>
|
||||
<n-input v-model:value="personalInfo.email" />
|
||||
</n-input-group>
|
||||
</n-space>
|
||||
|
@ -127,10 +119,7 @@ const uploadAvatar = (fileList: UploadFileInfo[]) => {
|
|||
<n-space style="display: flex">
|
||||
<n-button-group>
|
||||
<span style="align-self: center; margin-right: 10px">主题</span>
|
||||
<n-button
|
||||
:type="!isDarkMode ? 'primary' : 'default'"
|
||||
@click="toggleDarkMode"
|
||||
>
|
||||
<n-button :type="!isDarkMode ? 'primary' : 'default'" @click="toggleDarkMode">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<WeatherSunny16Regular />
|
||||
|
@ -138,10 +127,7 @@ const uploadAvatar = (fileList: UploadFileInfo[]) => {
|
|||
</template>
|
||||
亮色
|
||||
</n-button>
|
||||
<n-button
|
||||
:type="isDarkMode ? 'primary' : 'default'"
|
||||
@click="toggleDarkMode"
|
||||
>
|
||||
<n-button :type="isDarkMode ? 'primary' : 'default'" @click="toggleDarkMode">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<WeatherMoon16Regular />
|
||||
|
|
|
@ -14,15 +14,7 @@ import "vue-cropper/dist/index.css"
|
|||
import { VueCropper } from "vue-cropper"
|
||||
import VueWordCloud from "vuewordcloud"
|
||||
// Chart.js
|
||||
import {
|
||||
BarElement,
|
||||
CategoryScale,
|
||||
Chart as ChartJS,
|
||||
Legend,
|
||||
LinearScale,
|
||||
Title,
|
||||
Tooltip,
|
||||
} from "chart.js"
|
||||
import { BarElement, CategoryScale, Chart as ChartJS, Legend, LinearScale, Title, Tooltip } from "chart.js"
|
||||
import { Bar } from "vue-chartjs"
|
||||
import GeetestCaptcha from "@/components/GeetestCaptcha.vue"
|
||||
import { useGlobal } from "@/hooks"
|
||||
|
@ -523,9 +515,7 @@ const editorMounted = (editor) => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<NDivider title-placement="right">
|
||||
This is playground. 下面是开发者用来测试组件的区域。
|
||||
</NDivider>
|
||||
<NDivider title-placement="right"> This is playground. 下面是开发者用来测试组件的区域。 </NDivider>
|
||||
<div style="padding: 24px">
|
||||
<MonacoEditor
|
||||
v-model:content="value1"
|
||||
|
@ -541,11 +531,7 @@ const editorMounted = (editor) => {
|
|||
/>
|
||||
|
||||
<NSpace vertical>
|
||||
<n-modal
|
||||
:show="false"
|
||||
preset="card"
|
||||
style="max-width: 60%; height: 80%; padding: 10px"
|
||||
>
|
||||
<n-modal :show="false" preset="card" style="max-width: 60%; height: 80%; padding: 10px">
|
||||
<template #header>
|
||||
<div>Markdown 预览</div>
|
||||
</template>
|
||||
|
@ -577,42 +563,22 @@ const editorMounted = (editor) => {
|
|||
}"
|
||||
/>
|
||||
<NSpace>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
height="20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg fill="currentColor" height="20" width="20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M15 4a1 1 0 1 0 0 2V4zm0 11v-1a1 1 0 0 0-1 1h1zm0 4l-.707.707A1 1 0 0 0 16 19h-1zm-4-4l.707-.707A1 1 0 0 0 11 14v1zm-4.707-1.293a1 1 0 0 0-1.414 1.414l1.414-1.414zm-.707.707l-.707-.707.707.707zM9 11v-1a1 1 0 0 0-.707.293L9 11zm-4 0h1a1 1 0 0 0-1-1v1zm0 4H4a1 1 0 0 0 1.707.707L5 15zm10-9h2V4h-2v2zm2 0a1 1 0 0 1 1 1h2a3 3 0 0 0-3-3v2zm1 1v6h2V7h-2zm0 6a1 1 0 0 1-1 1v2a3 3 0 0 0 3-3h-2zm-1 1h-2v2h2v-2zm-3 1v4h2v-4h-2zm1.707 3.293l-4-4-1.414 1.414 4 4 1.414-1.414zM11 14H7v2h4v-2zm-4 0c-.276 0-.525-.111-.707-.293l-1.414 1.414C5.42 15.663 6.172 16 7 16v-2zm-.707 1.121l3.414-3.414-1.414-1.414-3.414 3.414 1.414 1.414zM9 12h4v-2H9v2zm4 0a3 3 0 0 0 3-3h-2a1 1 0 0 1-1 1v2zm3-3V3h-2v6h2zm0-6a3 3 0 0 0-3-3v2a1 1 0 0 1 1 1h2zm-3-3H3v2h10V0zM3 0a3 3 0 0 0-3 3h2a1 1 0 0 1 1-1V0zM0 3v6h2V3H0zm0 6a3 3 0 0 0 3 3v-2a1 1 0 0 1-1-1H0zm3 3h2v-2H3v2zm1-1v4h2v-4H4zm1.707 4.707l.586-.586-1.414-1.414-.586.586 1.414 1.414z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
height="17"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg fill="currentColor" height="17" width="20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M11 2.253a1 1 0 1 0-2 0h2zm-2 13a1 1 0 1 0 2 0H9zm.447-12.167a1 1 0 1 0 1.107-1.666L9.447 3.086zM1 2.253L.447 1.42A1 1 0 0 0 0 2.253h1zm0 13H0a1 1 0 0 0 1.553.833L1 15.253zm8.447.833a1 1 0 1 0 1.107-1.666l-1.107 1.666zm0-14.666a1 1 0 1 0 1.107 1.666L9.447 1.42zM19 2.253h1a1 1 0 0 0-.447-.833L19 2.253zm0 13l-.553.833A1 1 0 0 0 20 15.253h-1zm-9.553-.833a1 1 0 1 0 1.107 1.666L9.447 14.42zM9 2.253v13h2v-13H9zm1.553-.833C9.203.523 7.42 0 5.5 0v2c1.572 0 2.961.431 3.947 1.086l1.107-1.666zM5.5 0C3.58 0 1.797.523.447 1.42l1.107 1.666C2.539 2.431 3.928 2 5.5 2V0zM0 2.253v13h2v-13H0zm1.553 13.833C2.539 15.431 3.928 15 5.5 15v-2c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM5.5 15c1.572 0 2.961.431 3.947 1.086l1.107-1.666C9.203 13.523 7.42 13 5.5 13v2zm5.053-11.914C11.539 2.431 12.928 2 14.5 2V0c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM14.5 2c1.573 0 2.961.431 3.947 1.086l1.107-1.666C18.203.523 16.421 0 14.5 0v2zm3.5.253v13h2v-13h-2zm1.553 12.167C18.203 13.523 16.421 13 14.5 13v2c1.573 0 2.961.431 3.947 1.086l1.107-1.666zM14.5 13c-1.92 0-3.703.523-5.053 1.42l1.107 1.666C11.539 15.431 12.928 15 14.5 15v-2z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
height="20"
|
||||
width="18"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg fill="currentColor" height="20" width="18" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M11.447 8.894a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm0 1.789a1 1 0 1 0 .894-1.789l-.894 1.789zM7.447 7.106a1 1 0 1 0-.894 1.789l.894-1.789zM10 9a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0H8zm9.447-5.606a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm2 .789a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zM18 5a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0h-2zm-5.447-4.606a1 1 0 1 0 .894-1.789l-.894 1.789zM9 1l.447-.894a1 1 0 0 0-.894 0L9 1zm-2.447.106a1 1 0 1 0 .894 1.789l-.894-1.789zm-6 3a1 1 0 1 0 .894 1.789L.553 4.106zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zm-2-.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 2.789a1 1 0 1 0 .894-1.789l-.894 1.789zM2 5a1 1 0 1 0-2 0h2zM0 7.5a1 1 0 1 0 2 0H0zm8.553 12.394a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 1a1 1 0 1 0 .894 1.789l-.894-1.789zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zM8 19a1 1 0 1 0 2 0H8zm2-2.5a1 1 0 1 0-2 0h2zm-7.447.394a1 1 0 1 0 .894-1.789l-.894 1.789zM1 15H0a1 1 0 0 0 .553.894L1 15zm1-2.5a1 1 0 1 0-2 0h2zm12.553 2.606a1 1 0 1 0 .894 1.789l-.894-1.789zM17 15l.447.894A1 1 0 0 0 18 15h-1zm1-2.5a1 1 0 1 0-2 0h2zm-7.447-5.394l-2 1 .894 1.789 2-1-.894-1.789zm-1.106 1l-2-1-.894 1.789 2 1 .894-1.789zM8 9v2.5h2V9H8zm8.553-4.894l-2 1 .894 1.789 2-1-.894-1.789zm.894 0l-2-1-.894 1.789 2 1 .894-1.789zM16 5v2.5h2V5h-2zm-4.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zm-2.894-1l-2 1 .894 1.789 2-1L8.553.106zM1.447 5.894l2-1-.894-1.789-2 1 .894 1.789zm-.894 0l2 1 .894-1.789-2-1-.894 1.789zM0 5v2.5h2V5H0zm9.447 13.106l-2-1-.894 1.789 2 1 .894-1.789zm0 1.789l2-1-.894-1.789-2 1 .894 1.789zM10 19v-2.5H8V19h2zm-6.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zM2 15v-2.5H0V15h2zm13.447 1.894l2-1-.894-1.789-2 1 .894 1.789zM18 15v-2.5h-2V15h2z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
height="20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg fill="currentColor" height="20" width="20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M10 3.22l-.61-.6a5.5 5.5 0 0 0-7.666.105 5.5 5.5 0 0 0-.114 7.665L10 18.78l8.39-8.4a5.5 5.5 0 0 0-.114-7.665 5.5 5.5 0 0 0-7.666-.105l-.61.61z"
|
||||
/>
|
||||
|
|
|
@ -22,13 +22,7 @@ import {
|
|||
} from "@vicons/ionicons5"
|
||||
import { useAppConfig } from "@/stores/app-config"
|
||||
import { useUserInfo } from "@/stores/user-info"
|
||||
import {
|
||||
confirmRegisterEmailCode,
|
||||
confirmSmsCode,
|
||||
getToken,
|
||||
sendRegisterEmailCode,
|
||||
sendSmsCode,
|
||||
} from "@/api/user"
|
||||
import { confirmRegisterEmailCode, confirmSmsCode, getToken, sendRegisterEmailCode, sendSmsCode } from "@/api/user"
|
||||
import { getRegisterEnabled } from "@/api/server"
|
||||
import { ResponseMessagesSimplifiedChinese } from "@/api/ResponseMessages"
|
||||
import { hasText } from "@/utils"
|
||||
|
@ -134,12 +128,7 @@ function onSendEmailCodeLogoClick() {
|
|||
?.validate()
|
||||
.then(() => {
|
||||
geetest.validate().then((w) => {
|
||||
sendRegisterEmailCode(
|
||||
loginForm.value.username,
|
||||
loginForm.value.password,
|
||||
loginForm.value.email,
|
||||
w,
|
||||
)
|
||||
sendRegisterEmailCode(loginForm.value.username, loginForm.value.password, loginForm.value.email, w)
|
||||
.then(() => {
|
||||
window.$message.success("验证码已发送,请查收")
|
||||
isCooldown.value = true
|
||||
|
@ -252,11 +241,7 @@ const onSendSmsCodeLogoClick = () => {
|
|||
:show-require-mark="false"
|
||||
>
|
||||
<n-form-item-row label="手机号" path="phone">
|
||||
<n-input
|
||||
v-model:value="smsLoginForm.phone"
|
||||
:input-props="{ autocomplete: 'phone' }"
|
||||
placeholder="手机号"
|
||||
>
|
||||
<n-input v-model:value="smsLoginForm.phone" :input-props="{ autocomplete: 'phone' }" placeholder="手机号">
|
||||
<template #prefix>
|
||||
<n-icon :component="PhonePortraitOutline" />
|
||||
</template>
|
||||
|
@ -282,24 +267,10 @@ const onSendSmsCodeLogoClick = () => {
|
|||
</n-input>
|
||||
</n-form-item-row>
|
||||
</n-form>
|
||||
<n-button
|
||||
block
|
||||
secondary
|
||||
strong
|
||||
type="primary"
|
||||
@click="onSmsLoginButtonClick"
|
||||
>
|
||||
登录
|
||||
</n-button>
|
||||
<n-button block secondary strong type="primary" @click="onSmsLoginButtonClick"> 登录 </n-button>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="signin" tab="登录">
|
||||
<n-form
|
||||
ref="modalFormRef"
|
||||
:show-require-mark="false"
|
||||
:show-label="false"
|
||||
:model="loginForm"
|
||||
:rules="rules"
|
||||
>
|
||||
<n-form ref="modalFormRef" :show-require-mark="false" :show-label="false" :model="loginForm" :rules="rules">
|
||||
<n-form-item-row path="username" label="账号">
|
||||
<n-input
|
||||
v-model:value="loginForm.username"
|
||||
|
@ -326,23 +297,10 @@ const onSendSmsCodeLogoClick = () => {
|
|||
</n-input>
|
||||
</n-form-item-row>
|
||||
</n-form>
|
||||
<n-button
|
||||
block
|
||||
secondary
|
||||
strong
|
||||
type="primary"
|
||||
@click="onLoginButtonClick"
|
||||
>
|
||||
登录
|
||||
</n-button>
|
||||
<n-button block secondary strong type="primary" @click="onLoginButtonClick"> 登录 </n-button>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane v-if="isRegisterEnabled" name="signup" tab="注册">
|
||||
<n-form
|
||||
ref="registerFormRef"
|
||||
:model="loginForm"
|
||||
:rules="rules"
|
||||
:show-require-mark="false"
|
||||
>
|
||||
<n-form ref="registerFormRef" :model="loginForm" :rules="rules" :show-require-mark="false">
|
||||
<n-form-item-row path="username" label="用户名">
|
||||
<n-input
|
||||
v-model:value="loginForm.username"
|
||||
|
@ -368,11 +326,7 @@ const onSendSmsCodeLogoClick = () => {
|
|||
/>
|
||||
</n-form-item-row>
|
||||
<n-form-item-row label="邮箱" path="email">
|
||||
<n-input
|
||||
v-model:value="loginForm.email"
|
||||
:disabled="isCooldown"
|
||||
@keyup.enter="onSendEmailCodeLogoClick"
|
||||
>
|
||||
<n-input v-model:value="loginForm.email" :disabled="isCooldown" @keyup.enter="onSendEmailCodeLogoClick">
|
||||
<template #suffix>
|
||||
<n-icon
|
||||
:component="isCooldown ? CheckmarkOutline : SendSharp"
|
||||
|
@ -383,20 +337,10 @@ const onSendSmsCodeLogoClick = () => {
|
|||
</n-input>
|
||||
</n-form-item-row>
|
||||
<n-form-item-row label="验证码" path="code">
|
||||
<n-input
|
||||
ref="codeInputRef"
|
||||
v-model:value="loginForm.code"
|
||||
:disabled="!sentEmailCode"
|
||||
/>
|
||||
<n-input ref="codeInputRef" v-model:value="loginForm.code" :disabled="!sentEmailCode" />
|
||||
</n-form-item-row>
|
||||
</n-form>
|
||||
<n-button
|
||||
:disabled="!sentEmailCode"
|
||||
block
|
||||
secondary
|
||||
strong
|
||||
type="primary"
|
||||
@click="onRegisterButtonClick"
|
||||
<n-button :disabled="!sentEmailCode" block secondary strong type="primary" @click="onRegisterButtonClick"
|
||||
>注册
|
||||
</n-button>
|
||||
</n-tab-pane>
|
||||
|
|
|
@ -45,13 +45,7 @@ export const useAppConfig = defineStore(
|
|||
{
|
||||
persist: {
|
||||
storage: localStorage,
|
||||
paths: [
|
||||
"isDarkMode",
|
||||
"isMenuCollapsed",
|
||||
"expandedMenuKeys",
|
||||
"currentRouteName",
|
||||
"isDebugMode",
|
||||
],
|
||||
paths: ["isDarkMode", "isMenuCollapsed", "expandedMenuKeys", "currentRouteName", "isDebugMode"],
|
||||
},
|
||||
},
|
||||
)
|
||||
|
|
|
@ -56,9 +56,7 @@ export const useUserInfo = defineStore(
|
|||
* @param imageData 图片数据
|
||||
*/
|
||||
function setAvatar(imageData: ArrayBuffer) {
|
||||
const imageUrl = URL.createObjectURL(
|
||||
new Blob([imageData], { type: "imageType" }),
|
||||
)
|
||||
const imageUrl = URL.createObjectURL(new Blob([imageData], { type: "imageType" }))
|
||||
if (hasText(avatarUrl.value)) {
|
||||
URL.revokeObjectURL(avatarUrl.value)
|
||||
}
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
declare interface Window {
|
||||
initGeetest4: (
|
||||
options: GeetestConfig,
|
||||
callback: (captchaObj: Geetest) => void,
|
||||
) => void
|
||||
initGeetest4: (options: GeetestConfig, callback: (captchaObj: Geetest) => void) => void
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,16 +8,7 @@ export function unmarshalDate(date: string | Date) {
|
|||
return date
|
||||
}
|
||||
|
||||
const parts: number[] = date
|
||||
.split(/[-T:.+]/)
|
||||
.map((part) => parseInt(part, 10))
|
||||
const parts: number[] = date.split(/[-T:.+]/).map((part) => parseInt(part, 10))
|
||||
// 注意:JavaScript中的月份从0开始,所以需要将月份减1
|
||||
return new Date(
|
||||
parts[0],
|
||||
parts[1] - 1,
|
||||
parts[2],
|
||||
parts[3],
|
||||
parts[4],
|
||||
parts[5],
|
||||
)
|
||||
return new Date(parts[0], parts[1] - 1, parts[2], parts[3], parts[4], parts[5])
|
||||
}
|
||||
|
|
|
@ -28,23 +28,16 @@ export function detectBrowserTypeByComputedStyle() {
|
|||
*/
|
||||
export function detectBrowserByFeature() {
|
||||
// Opera 8.0+
|
||||
const isOpera =
|
||||
(!!window.opr && !!opr.addons) ||
|
||||
!!window.opera ||
|
||||
navigator.userAgent.indexOf(" OPR/") >= 0
|
||||
const isOpera = (!!window.opr && !!opr.addons) || !!window.opera || navigator.userAgent.indexOf(" OPR/") >= 0
|
||||
// Firefox 1.0+
|
||||
const isFirefox = typeof InstallTrigger !== "undefined"
|
||||
// Safari 3.0+
|
||||
const isSafari =
|
||||
/constructor/i.test(window.HTMLElement) ||
|
||||
(
|
||||
typeof safari !== "undefined" && window["safari"].pushNotification
|
||||
).toString() === "[object SafariRemoteNotification]"
|
||||
(typeof safari !== "undefined" && window["safari"].pushNotification).toString() ===
|
||||
"[object SafariRemoteNotification]"
|
||||
// Internet Explorer 6-11
|
||||
const isIE =
|
||||
!!window.ActiveXObject ||
|
||||
"ActiveXObject" in window ||
|
||||
!!document.documentMode
|
||||
const isIE = !!window.ActiveXObject || "ActiveXObject" in window || !!document.documentMode
|
||||
// 旧 Edge 20+
|
||||
const isEdge = !isIE && !!window.StyleMedia
|
||||
// Chrome 1 - 79
|
||||
|
|
|
@ -10,11 +10,7 @@ import {
|
|||
SpaceDashboardOutlined,
|
||||
TerminalOutlined,
|
||||
} from "@vicons/material"
|
||||
import {
|
||||
DocumentPdf32Regular,
|
||||
SlideLayout24Regular,
|
||||
Gif24Regular,
|
||||
} from "@vicons/fluent"
|
||||
import { DocumentPdf32Regular, SlideLayout24Regular, Gif24Regular } from "@vicons/fluent"
|
||||
import { Java, Markdown, Vuejs } from "@vicons/fa"
|
||||
import {
|
||||
ArchiveOutline,
|
||||
|
@ -31,10 +27,7 @@ import {
|
|||
* @param content 提示内容
|
||||
* @returns 提示组件
|
||||
*/
|
||||
export function renderTooltip(
|
||||
trigger: VNode<RendererNode, RendererElement, { [key: string]: any }>,
|
||||
content: string,
|
||||
) {
|
||||
export function renderTooltip(trigger: VNode<RendererNode, RendererElement, { [key: string]: any }>, content: string) {
|
||||
return h(NTooltip, null, {
|
||||
trigger: () => trigger,
|
||||
default: () => content,
|
||||
|
|
Loading…
Reference in New Issue