diff --git a/public/api/workspace.php b/public/api/workspace.php
index bfc4247..9121828 100644
--- a/public/api/workspace.php
+++ b/public/api/workspace.php
@@ -218,7 +218,15 @@ function validateWorkspaceContent($content) {
]);
} elseif ($action === 'list') {
+ // 从权限表获取文件
$fileIds = getUserAccessibleFiles($dbPermissions, $username);
+
+ // 兼容旧数据:同时从用户文件列表获取文件
+ $userFilesKey = sanitizeDbKey($username . '_files');
+ $legacyFileIds = $dbUsers->get_array($userFilesKey);
+ if ($legacyFileIds && is_array($legacyFileIds)) {
+ $fileIds = array_unique(array_merge($fileIds ?: [], $legacyFileIds));
+ }
$list = [];
if ($fileIds && is_array($fileIds)) {
@@ -232,6 +240,15 @@ function validateWorkspaceContent($content) {
$fileData = json_decode($fileRaw, true);
if (!$fileData || !isset($fileData['metadata'])) continue;
+ // 兼容旧数据:自动迁移权限记录
+ $permKey = sanitizeDbKey("perm_{$fileId}_{$username}");
+ if ($dbPermissions->get($permKey) === null) {
+ // 检查文件作者是否是当前用户
+ if (isset($fileData['metadata']['author']) && $fileData['metadata']['author'] === $username) {
+ grantFilePermission($dbPermissions, $fileId, $username, 'owner');
+ }
+ }
+
$list[] = [
'fileId' => $fileId,
'metadata' => $fileData['metadata']
@@ -258,11 +275,6 @@ function validateWorkspaceContent($content) {
respond(['success' => false, 'message' => '文件ID格式无效']);
}
- // 检查读权限
- if (!hasFilePermission($dbPermissions, $fileId, $username, 'read')) {
- respond(['success' => false, 'message' => '无权访问该文件'], 403);
- }
-
// 消毒文件 ID
$sanitizedFileId = sanitizeDbKey($fileId);
@@ -276,6 +288,20 @@ function validateWorkspaceContent($content) {
respond(['success' => false, 'message' => '文件格式损坏']);
}
+ // 检查读权限(兼容旧数据:如果没有权限记录,检查文件作者)
+ $permKey = sanitizeDbKey("perm_{$fileId}_{$username}");
+ if ($dbPermissions->get($permKey) === null) {
+ // 没有权限记录,检查文件作者
+ if (isset($fileData['metadata']['author']) && $fileData['metadata']['author'] === $username) {
+ // 自动迁移:创建权限记录
+ grantFilePermission($dbPermissions, $fileId, $username, 'owner');
+ } else {
+ respond(['success' => false, 'message' => '无权访问该文件'], 403);
+ }
+ } elseif (!hasFilePermission($dbPermissions, $fileId, $username, 'read')) {
+ respond(['success' => false, 'message' => '无权访问该文件'], 403);
+ }
+
respond([
'success' => true,
'data' => $fileData
@@ -291,15 +317,26 @@ function validateWorkspaceContent($content) {
respond(['success' => false, 'message' => '文件ID格式无效']);
}
- // 检查写权限
- if (!hasFilePermission($dbPermissions, $fileId, $username, 'write')) {
- respond(['success' => false, 'message' => '无权删除该文件'], 403);
- }
-
// 消毒文件 ID
$sanitizedFileId = sanitizeDbKey($fileId);
$fileRaw = $dbFiles->get($sanitizedFileId);
+
+ // 检查写权限(兼容旧数据:如果没有权限记录,检查文件作者)
+ $permKey = sanitizeDbKey("perm_{$fileId}_{$username}");
+ if ($dbPermissions->get($permKey) === null) {
+ // 没有权限记录,检查文件作者
+ $fileData = $fileRaw ? json_decode($fileRaw, true) : null;
+ if ($fileData && isset($fileData['metadata']['author']) && $fileData['metadata']['author'] === $username) {
+ // 自动迁移:创建权限记录
+ grantFilePermission($dbPermissions, $fileId, $username, 'owner');
+ } else {
+ respond(['success' => false, 'message' => '无权删除该文件'], 403);
+ }
+ } elseif (!hasFilePermission($dbPermissions, $fileId, $username, 'write')) {
+ respond(['success' => false, 'message' => '无权删除该文件'], 403);
+ }
+
if ($fileRaw !== null) {
$dbFiles->delete($sanitizedFileId);
diff --git a/src/App.vue b/src/App.vue
index 0863d16..aa252b1 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -71,14 +71,14 @@ onMounted(async () => {
if (isCtrl && e.key === 'z' && !e.shiftKey) {
e.preventDefault()
- if (canUndo()) {
+ if (canUndo.value) {
undo()
}
}
if (isCtrl && (e.key === 'y' || (e.key === 'z' && e.shiftKey))) {
e.preventDefault()
- if (canRedo()) {
+ if (canRedo.value) {
redo()
}
}
diff --git a/src/assets/main.css b/src/assets/main.css
index e53adc7..b1aba3d 100644
--- a/src/assets/main.css
+++ b/src/assets/main.css
@@ -131,11 +131,11 @@
--color-bg-hover: #2a3f5c;
--color-bg-overlay: rgba(0, 0, 0, 0.7);
- /* 文字颜色 - 提升禁用文字对比度 */
+ /* 文字颜色 - 优化深色模式可读性 */
--color-text-primary: #f1f5f9;
--color-text-secondary: #cbd5e1;
- --color-text-muted: #94a3b8;
- --color-text-disabled: #7b8fa3;
+ --color-text-muted: #a0aec0;
+ --color-text-disabled: #8899aa;
--color-text-inverse: #ffffff;
/* 边框颜色 - 提升可见度 */
@@ -143,7 +143,7 @@
--color-border-strong: #536578;
--color-border-hover: #536578;
--color-border-light: #253347;
- --color-border-dark: #7b8fa3;
+ --color-border-dark: #8899aa;
/* 次要背景色 */
--color-bg-secondary: #151d2e;
@@ -250,15 +250,15 @@
--color-text-primary: #f1f5f9;
--color-text-secondary: #cbd5e1;
- --color-text-muted: #94a3b8;
- --color-text-disabled: #7b8fa3;
+ --color-text-muted: #a0aec0;
+ --color-text-disabled: #8899aa;
--color-text-inverse: #ffffff;
--color-border: #3d4f63;
--color-border-strong: #536578;
--color-border-hover: #536578;
--color-border-light: #253347;
- --color-border-dark: #7b8fa3;
+ --color-border-dark: #8899aa;
--color-bg-secondary: #151d2e;
diff --git a/src/components/auth/LoginDialog.vue b/src/components/auth/LoginDialog.vue
index 42cd5e8..6892fc0 100644
--- a/src/components/auth/LoginDialog.vue
+++ b/src/components/auth/LoginDialog.vue
@@ -247,7 +247,7 @@ const handleSubmit = async () => {
left: 0;
right: 0;
bottom: 0;
- background: rgba(0, 0, 0, 0.5);
+ background: var(--color-bg-overlay);
display: flex;
align-items: center;
justify-content: center;
diff --git a/src/components/auth/SyncSettingsDialog.vue b/src/components/auth/SyncSettingsDialog.vue
index 33597f6..aea36c2 100644
--- a/src/components/auth/SyncSettingsDialog.vue
+++ b/src/components/auth/SyncSettingsDialog.vue
@@ -214,7 +214,7 @@ const handleSubmit = async () => {
left: 0;
right: 0;
bottom: 0;
- background: rgba(0, 0, 0, 0.5);
+ background: var(--color-bg-overlay);
display: flex;
align-items: center;
justify-content: center;
diff --git a/src/components/docs/RuleUsageGuide.vue b/src/components/docs/RuleUsageGuide.vue
index ab4464d..e2262f7 100644
--- a/src/components/docs/RuleUsageGuide.vue
+++ b/src/components/docs/RuleUsageGuide.vue
@@ -305,7 +305,7 @@
padding: 10px 12px;
background: var(--color-info-bg);
border-radius: 8px;
- border: 1px solid #bfdbfe;
+ border: 1px solid var(--color-border);
font-size: 12px;
color: var(--color-info);
line-height: 1.5;
diff --git a/src/components/layout/AppHeader.vue b/src/components/layout/AppHeader.vue
index 1b5168d..df2440b 100644
--- a/src/components/layout/AppHeader.vue
+++ b/src/components/layout/AppHeader.vue
@@ -67,8 +67,6 @@