重构云文件管理系统
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
-- 创建数据库
|
||||
CREATE DATABASE IF NOT EXISTS file_system DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
CREATE DATABASE IF NOT EXISTS system DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
USE file_system;
|
||||
USE system;
|
||||
|
||||
-- 用户表
|
||||
CREATE TABLE IF NOT EXISTS sys_user (
|
||||
@@ -15,7 +15,7 @@ CREATE TABLE IF NOT EXISTS sys_user (
|
||||
phone VARCHAR(20) COMMENT '手机号',
|
||||
status INT DEFAULT 1 COMMENT '状态 0-禁用 1-启用',
|
||||
storage_used BIGINT DEFAULT 0 COMMENT '已用存储空间(字节)',
|
||||
storage_limit BIGINT DEFAULT 10737418240 COMMENT '存储限制(字节) 默认10GB',
|
||||
storage_limit BIGINT DEFAULT 21474836480 COMMENT '存储限制(字节) 默认20GB',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
is_deleted INT DEFAULT 0 COMMENT '是否删除 0-否 1-是'
|
||||
@@ -73,6 +73,7 @@ CREATE TABLE IF NOT EXISTS sys_message (
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='消息表';
|
||||
|
||||
-- 插入默认管理员账户 (密码: admin123)
|
||||
-- BCrypt hash generated with strength 10
|
||||
INSERT INTO sys_user (username, password, nickname, status, storage_limit)
|
||||
VALUES ('admin', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9lBOsl7iAt6Z5EH', '管理员', 1, 10737418240)
|
||||
ON DUPLICATE KEY UPDATE username = username;
|
||||
VALUES ('admin', '$2a$10$EqKcp1WFKVQISheBxmXNGexPR.i7QYXOJC.OFfQDT8iSaHuuPdlrW', '管理员', 1, 21474836480)
|
||||
ON DUPLICATE KEY UPDATE password = '$2a$10$EqKcp1WFKVQISheBxmXNGexPR.i7QYXOJC.OFfQDT8iSaHuuPdlrW';
|
||||
|
||||
9
web-vue/package-lock.json
generated
9
web-vue/package-lock.json
generated
@@ -886,7 +886,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz",
|
||||
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/lodash": "*"
|
||||
}
|
||||
@@ -1422,15 +1421,13 @@
|
||||
"version": "4.17.23",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
|
||||
"integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash-es": {
|
||||
"version": "4.17.23",
|
||||
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz",
|
||||
"integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash-unified": {
|
||||
"version": "1.0.3",
|
||||
@@ -1637,7 +1634,6 @@
|
||||
"integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.21.3",
|
||||
"postcss": "^8.4.43",
|
||||
@@ -1697,7 +1693,6 @@
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.31.tgz",
|
||||
"integrity": "sha512-iV/sU9SzOlmA/0tygSmjkEN6Jbs3nPoIPFhCMLD2STrjgOU8DX7ZtzMhg4ahVwf5Rp9KoFzcXeB1ZrVbLBp5/Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.5.31",
|
||||
"@vue/compiler-sfc": "3.5.31",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
title="消息"
|
||||
@@ -310,8 +310,8 @@ const getFileColor = (name) => {
|
||||
|
||||
const loadContacts = async () => {
|
||||
try {
|
||||
const res = await getUsers()
|
||||
contacts.value = (res.data || []).map((u, i) => ({
|
||||
const data = await getUsers()
|
||||
contacts.value = (data || []).map((u, i) => ({
|
||||
...u,
|
||||
id: u.id,
|
||||
name: u.nickname || u.username,
|
||||
@@ -327,8 +327,8 @@ const loadContacts = async () => {
|
||||
|
||||
const loadUnreadChats = async () => {
|
||||
try {
|
||||
const res = await getUnreadList()
|
||||
const list = res.data || []
|
||||
const data = await getUnreadList()
|
||||
const list = data || []
|
||||
if (list.length === 0) return
|
||||
// 加载联系人后再填充未读数据
|
||||
list.forEach(item => {
|
||||
@@ -372,8 +372,8 @@ const selectContact = async (contact) => {
|
||||
contact.unread = 0
|
||||
loadingMessages.value = true
|
||||
try {
|
||||
const res = await getMessages({ userId: contact.id })
|
||||
messages.value[contact.id] = (res.data || []).map(msg => {
|
||||
const data = await getMessages({ userId: contact.id })
|
||||
messages.value[contact.id] = (data || []).map(msg => {
|
||||
const isSelf = String(msg.fromUserId) === String(userStore.userId)
|
||||
return {
|
||||
...msg,
|
||||
@@ -474,11 +474,11 @@ const handleImageSelect = async (e) => {
|
||||
try {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
const res = await uploadChatFile(formData)
|
||||
const data = await uploadChatFile(formData)
|
||||
chatService.send({
|
||||
type: 'chat',
|
||||
toUserId: currentContact.value.id,
|
||||
content: res.url,
|
||||
content: data.url,
|
||||
msgType: 'image'
|
||||
})
|
||||
updateRecentChat(currentContact.value, '[图片]')
|
||||
@@ -525,11 +525,11 @@ const handleFileSelect = async (e) => {
|
||||
try {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
const res = await uploadChatFile(formData)
|
||||
const data = await uploadChatFile(formData)
|
||||
chatService.send({
|
||||
type: 'chat',
|
||||
toUserId: currentContact.value.id,
|
||||
content: res.url,
|
||||
content: data.url,
|
||||
msgType: 'file',
|
||||
fileName: file.name,
|
||||
fileSize: file.size
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
title="个人信息"
|
||||
@@ -136,10 +136,10 @@ const handleAvatarChange = async (e) => {
|
||||
try {
|
||||
const formData = new FormData()
|
||||
formData.append('avatar', file)
|
||||
const res = await request.post('/users/avatar', formData, {
|
||||
const data = await request.post('/users/avatar', formData, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' }
|
||||
})
|
||||
const newUrl = res.data?.url || ''
|
||||
const newUrl = data?.url || ''
|
||||
avatarUrl.value = newUrl
|
||||
userStore.setUser({ avatar: newUrl })
|
||||
ElMessage.success('头像更新成功')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
title="共享文件"
|
||||
@@ -65,8 +65,8 @@ const userList = ref([])
|
||||
|
||||
const loadUsers = async () => {
|
||||
try {
|
||||
const res = await getUsers()
|
||||
userList.value = res.data || []
|
||||
const data = await getUsers()
|
||||
userList.value = data || []
|
||||
} catch (e) {
|
||||
ElMessage.error('获取用户列表失败')
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div class="top-navbar">
|
||||
<div class="navbar-left">
|
||||
<div class="logo-icon">
|
||||
@@ -145,8 +145,8 @@ let pollTimer = null
|
||||
let wsUnsubscribe = null
|
||||
|
||||
const checkUnread = () => {
|
||||
getUnreadCount().then(res => {
|
||||
totalUnread.value = res.data.count || 0
|
||||
getUnreadCount().then(data => {
|
||||
totalUnread.value = data.count || 0
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
|
||||
@@ -251,8 +251,7 @@ const remainingStorage = computed(() => {
|
||||
// 刷新存储数据(从后端精确重算)
|
||||
const refreshStorage = async () => {
|
||||
try {
|
||||
const res = await getCurrentUser()
|
||||
const data = res.data
|
||||
const data = await getCurrentUser()
|
||||
if (data) {
|
||||
userStore.setUser({
|
||||
storageUsed: data.storageUsed ?? 0,
|
||||
@@ -299,26 +298,26 @@ const loadFiles = async () => {
|
||||
loading.value = true
|
||||
currentPage.value = 1
|
||||
try {
|
||||
let res
|
||||
let data
|
||||
switch (activeMenu.value) {
|
||||
case 'trash': res = await getTrashFiles(currentFolderId.value ? { folderId: currentFolderId.value } : {}); break
|
||||
case 'trash': data = await getTrashFiles(currentFolderId.value ? { folderId: currentFolderId.value } : {}); break
|
||||
case 'my-share':
|
||||
if (currentFolderId.value) {
|
||||
res = await getSharedByMeFolderFiles(currentFolderId.value)
|
||||
data = await getSharedByMeFolderFiles(currentFolderId.value)
|
||||
} else {
|
||||
res = await getSharedByMe()
|
||||
data = await getSharedByMe()
|
||||
}
|
||||
break
|
||||
case 'shared-to-me':
|
||||
if (currentFolderId.value) {
|
||||
res = await getSharedFolderFiles(currentFolderId.value)
|
||||
data = await getSharedFolderFiles(currentFolderId.value)
|
||||
} else {
|
||||
res = await getSharedToMe()
|
||||
data = await getSharedToMe()
|
||||
}
|
||||
break
|
||||
default: res = await getFiles({ folderId: currentFolderId.value, keyword: searchKeyword.value })
|
||||
default: data = await getFiles({ folderId: currentFolderId.value, keyword: searchKeyword.value })
|
||||
}
|
||||
files.value = res.data || []
|
||||
files.value = data || []
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
} finally {
|
||||
@@ -601,8 +600,8 @@ const handleBatchMove = async () => {
|
||||
|
||||
try {
|
||||
const selectedIds = selectedFiles.value.map(f => f.id)
|
||||
const res = await getMovableFolders(selectedIds, currentFolderId.value)
|
||||
movableFolders.value = res.data || []
|
||||
const data = await getMovableFolders(selectedIds, currentFolderId.value)
|
||||
movableFolders.value = data || []
|
||||
batchMoveVisible.value = true
|
||||
} catch (e) {
|
||||
ElMessage.error('获取目录列表失败')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<el-form :model="form" :rules="rules" ref="formRef" @submit.prevent="handleLogin">
|
||||
<el-form-item prop="username">
|
||||
<el-input
|
||||
@@ -57,11 +57,13 @@ const handleLogin = async () => {
|
||||
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await login(form)
|
||||
// res.data = { token, user }
|
||||
emit('success', res.data)
|
||||
// login 返回的是 res.data(经过 request.js 拦截器处理)
|
||||
// 后端 ApiResult 格式: { code, message, data }
|
||||
// data = { token, user }
|
||||
const data = await login(form)
|
||||
emit('success', data)
|
||||
} catch (e) {
|
||||
ElMessage.error(e.response?.data?.message || '账号或密码错误')
|
||||
ElMessage.error(e.message || '账号或密码错误')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<el-form :model="form" :rules="rules" ref="formRef" @submit.prevent="handleRegister">
|
||||
<el-form-item prop="username">
|
||||
<el-input
|
||||
@@ -107,7 +107,7 @@ const handleRegister = async () => {
|
||||
ElMessage.success('注册成功,请登录')
|
||||
emit('success')
|
||||
} catch (e) {
|
||||
ElMessage.error(e.response?.data?.message || '注册失败,请重试')
|
||||
ElMessage.error(e.message || '注册失败,请重试')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user