diff --git a/src/App.vue b/src/App.vue
index c7ecc3d..2c818cc 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,5 +1,12 @@
+
+
+
+
+
+
-
-
diff --git a/src/api/auth.js b/src/api/auth.js
index 39d6891..6739a27 100644
--- a/src/api/auth.js
+++ b/src/api/auth.js
@@ -21,97 +21,97 @@ export default {
},
users: {
list: {
- name: "获得用户列表",
+ name: '获得用户列表',
get: async function (params) {
- return await request.get('auth/users/index', { params });
+ return await request.get('auth/users/index', { params })
},
},
add: {
- name: "添加用户",
+ name: '添加用户',
post: async function (params) {
- return await request.post('auth/users/add', params);
+ return await request.post('auth/users/add', params)
},
},
edit: {
- name: "编辑用户",
+ name: '编辑用户',
post: async function (params) {
- return await request.put('auth/users/edit', params);
+ return await request.put('auth/users/edit', params)
},
},
uppasswd: {
- name: "修改密码",
+ name: '修改密码',
post: async function (params) {
- return await request.put('auth/users/passwd', params);
+ return await request.put('auth/users/passwd', params)
},
},
uprole: {
- name: "设置角色",
+ name: '设置角色',
post: async function (params) {
- return await request.put('auth/users/uprole', params);
+ return await request.put('auth/users/uprole', params)
},
},
delete: {
- name: "删除用户",
+ name: '删除用户',
post: async function (params) {
- return await request.delete('auth/users/delete', params);
+ return await request.delete('auth/users/delete', params)
},
},
},
role: {
list: {
- name: "获得角色列表",
+ name: '获得角色列表',
get: async function (params) {
- return await request.get('auth/role/index', { params });
+ return await request.get('auth/role/index', { params })
},
},
add: {
- name: "添加角色",
+ name: '添加角色',
post: async function (params) {
- return await request.post('auth/role/add', params);
+ return await request.post('auth/role/add', params)
},
},
edit: {
- name: "编辑角色",
+ name: '编辑角色',
post: async function (params) {
- return await request.put('auth/role/edit', params);
+ return await request.put('auth/role/edit', params)
},
},
auth: {
- name: "角色授权",
+ name: '角色授权',
post: async function (params) {
- return await request.put('auth/role/auth', params);
+ return await request.put('auth/role/auth', params)
},
},
delete: {
- name: "删除角色",
+ name: '删除角色',
post: async function (params) {
- return await request.delete('auth/role/delete', params);
+ return await request.delete('auth/role/delete', params)
},
},
},
department: {
list: {
- name: "获得部门列表",
+ name: '获得部门列表',
get: async function (params) {
- return await request.get('auth/department/index', { params });
+ return await request.get('auth/department/index', { params })
},
},
add: {
- name: "添加部门",
+ name: '添加部门',
post: async function (params) {
- return await request.post('auth/department/add', params);
+ return await request.post('auth/department/add', params)
},
},
edit: {
- name: "编辑部门",
+ name: '编辑部门',
post: async function (params) {
- return await request.put('auth/department/edit', params);
+ return await request.put('auth/department/edit', params)
},
},
delete: {
- name: "删除部门",
+ name: '删除部门',
post: async function (params) {
- return await request.delete('auth/department/delete', params);
+ return await request.delete('auth/department/delete', params)
},
},
},
@@ -123,27 +123,27 @@ export default {
},
},
list: {
- name: "获取菜单",
+ name: '获取菜单',
get: async function (params) {
- return await request.get('auth/menu/index', { params });
+ return await request.get('auth/menu/index', { params })
},
},
add: {
- name: "添加菜单",
+ name: '添加菜单',
post: async function (params) {
- return await request.post('auth/menu/add', params);
+ return await request.post('auth/menu/add', params)
},
},
edit: {
- name: "编辑菜单",
+ name: '编辑菜单',
post: async function (params) {
- return await request.put('auth/menu/edit', params);
+ return await request.put('auth/menu/edit', params)
},
},
delete: {
- name: "删除菜单",
+ name: '删除菜单',
post: async function (params) {
- return await request.delete('auth/menu/delete', params);
+ return await request.delete('auth/menu/delete', params)
},
},
},
diff --git a/src/assets/style/auth.scss b/src/assets/style/auth.scss
index adb50b4..3b8849c 100644
--- a/src/assets/style/auth.scss
+++ b/src/assets/style/auth.scss
@@ -2,333 +2,333 @@
// Warm color palette with tech-inspired design
:root {
- --auth-primary: #ff6b35;
- --auth-primary-light: #ff8c5a;
- --auth-primary-dark: #e55a2b;
- --auth-secondary: #ffb347;
- --accent-orange: #ffa500;
- --accent-coral: #ff7f50;
- --accent-amber: #ffc107;
+ --auth-primary: #ff6b35;
+ --auth-primary-light: #ff8c5a;
+ --auth-primary-dark: #e55a2b;
+ --auth-secondary: #ffb347;
+ --accent-orange: #ffa500;
+ --accent-coral: #ff7f50;
+ --accent-amber: #ffc107;
- --bg-gradient-start: #fff5f0;
- --bg-gradient-end: #ffe8dc;
- --card-bg: rgba(255, 255, 255, 0.95);
+ --bg-gradient-start: #fff5f0;
+ --bg-gradient-end: #ffe8dc;
+ --card-bg: rgba(255, 255, 255, 0.95);
- --text-primary: #2d1810;
- --text-secondary: #6b4423;
- --text-muted: #a67c52;
+ --text-primary: #2d1810;
+ --text-secondary: #6b4423;
+ --text-muted: #a67c52;
- --border-color: #ffd4b8;
- --shadow-color: rgba(255, 107, 53, 0.15);
+ --border-color: #ffd4b8;
+ --shadow-color: rgba(255, 107, 53, 0.15);
- --success: #28a745;
- --warning: #ffc107;
- --error: #dc3545;
+ --success: #28a745;
+ --warning: #ffc107;
+ --error: #dc3545;
- --tech-blue: #007bff;
- --tech-purple: #6f42c1;
+ --tech-blue: #007bff;
+ --tech-purple: #6f42c1;
}
.auth-container {
- min-height: 100vh;
- display: flex;
- align-items: center;
- justify-content: center;
- background: linear-gradient(135deg, var(--bg-gradient-start) 0%, var(--bg-gradient-end) 100%);
- position: relative;
- overflow: hidden;
+ min-height: 100vh;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: linear-gradient(135deg, var(--bg-gradient-start) 0%, var(--bg-gradient-end) 100%);
+ position: relative;
+ overflow: hidden;
- // Tech pattern background
- &::before {
- content: '';
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-image:
- radial-gradient(circle at 20% 50%, rgba(255, 107, 53, 0.03) 0%, transparent 50%),
- radial-gradient(circle at 80% 20%, rgba(255, 179, 71, 0.05) 0%, transparent 40%),
- radial-gradient(circle at 40% 80%, rgba(255, 127, 80, 0.04) 0%, transparent 40%);
- pointer-events: none;
- }
+ // Tech pattern background
+ &::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-image:
+ radial-gradient(circle at 20% 50%, rgba(255, 107, 53, 0.03) 0%, transparent 50%), radial-gradient(circle at 80% 20%, rgba(255, 179, 71, 0.05) 0%, transparent 40%), radial-gradient(circle at 40% 80%, rgba(255, 127, 80, 0.04) 0%, transparent 40%);
+ pointer-events: none;
+ }
- // Animated tech elements
- &::after {
- content: '';
- position: absolute;
- width: 600px;
- height: 600px;
- background: radial-gradient(circle, rgba(255, 107, 53, 0.08) 0%, transparent 70%);
- border-radius: 50%;
- top: -200px;
- right: -200px;
- animation: float 20s ease-in-out infinite;
- pointer-events: none;
- }
+ // Animated tech elements
+ &::after {
+ content: '';
+ position: absolute;
+ width: 600px;
+ height: 600px;
+ background: radial-gradient(circle, rgba(255, 107, 53, 0.08) 0%, transparent 70%);
+ border-radius: 50%;
+ top: -200px;
+ right: -200px;
+ animation: float 20s ease-in-out infinite;
+ pointer-events: none;
+ }
}
@keyframes float {
- 0%, 100% {
- transform: translate(0, 0);
- }
- 50% {
- transform: translate(-50px, 50px);
- }
+ 0%,
+ 100% {
+ transform: translate(0, 0);
+ }
+ 50% {
+ transform: translate(-50px, 50px);
+ }
}
.auth-card {
- width: 100%;
- max-width: 440px;
- background: var(--card-bg);
- backdrop-filter: blur(20px);
- border-radius: 24px;
- padding: 48px 40px;
- box-shadow:
- 0 20px 60px var(--shadow-color),
- 0 8px 24px rgba(0, 0, 0, 0.08);
- position: relative;
- z-index: 1;
- margin: 20px;
+ width: 100%;
+ max-width: 440px;
+ background: var(--card-bg);
+ backdrop-filter: blur(20px);
+ border-radius: 24px;
+ padding: 48px 40px;
+ box-shadow:
+ 0 20px 60px var(--shadow-color),
+ 0 8px 24px rgba(0, 0, 0, 0.08);
+ position: relative;
+ z-index: 1;
+ margin: 20px;
- // Tech accent line
- &::before {
- content: '';
- position: absolute;
- top: 0;
- left: 50%;
- transform: translateX(-50%);
- width: 80px;
- height: 4px;
- background: linear-gradient(90deg, var(--auth-primary), var(--auth-secondary));
- border-radius: 0 0 4px 4px;
- }
+ // Tech accent line
+ &::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 50%;
+ transform: translateX(-50%);
+ width: 80px;
+ height: 4px;
+ background: linear-gradient(90deg, var(--auth-primary), var(--auth-secondary));
+ border-radius: 0 0 4px 4px;
+ }
}
.auth-header {
- text-align: center;
- margin-bottom: 40px;
+ text-align: center;
+ margin-bottom: 40px;
- .auth-title {
- font-size: 28px;
- font-weight: 700;
- color: var(--text-primary);
- margin-bottom: 8px;
- background: linear-gradient(135deg, var(--auth-primary-dark), var(--auth-primary));
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- background-clip: text;
- }
+ .auth-title {
+ font-size: 28px;
+ font-weight: 700;
+ color: var(--text-primary);
+ margin-bottom: 8px;
+ background: linear-gradient(135deg, var(--auth-primary-dark), var(--auth-primary));
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+ }
- .auth-subtitle {
- font-size: 14px;
- color: var(--text-secondary);
- line-height: 1.6;
- }
+ .auth-subtitle {
+ font-size: 14px;
+ color: var(--text-secondary);
+ line-height: 1.6;
+ }
}
.auth-form {
- .el-form-item {
- margin-bottom: 24px;
- }
+ .el-form-item {
+ margin-bottom: 24px;
+ }
- .el-input {
- --el-input-border-radius: 12px;
- --el-input-border-color: var(--border-color);
- --el-input-hover-border-color: var(--auth-primary-light);
- --el-input-focus-border-color: var(--auth-primary);
+ .el-input {
+ --el-input-border-radius: 12px;
+ --el-input-border-color: var(--border-color);
+ --el-input-hover-border-color: var(--auth-primary-light);
+ --el-input-focus-border-color: var(--auth-primary);
- .el-input__wrapper {
- padding: 12px 16px;
- box-shadow: 0 2px 8px rgba(255, 107, 53, 0.08);
- transition: all 0.3s ease;
+ .el-input__wrapper {
+ padding: 12px 16px;
+ box-shadow: 0 2px 8px rgba(255, 107, 53, 0.08);
+ transition: all 0.3s ease;
- &.is-focus {
- box-shadow: 0 4px 16px rgba(255, 107, 53, 0.15);
- }
- }
+ &.is-focus {
+ box-shadow: 0 4px 16px rgba(255, 107, 53, 0.15);
+ }
+ }
- .el-input__inner {
- font-size: 14px;
- color: var(--text-primary);
- }
- }
+ .el-input__inner {
+ font-size: 14px;
+ color: var(--text-primary);
+ }
+ }
- .el-input__prefix {
- color: var(--auth-primary);
- font-size: 18px;
- }
+ .el-input__prefix {
+ color: var(--auth-primary);
+ font-size: 18px;
+ }
- .el-input__suffix {
- color: var(--text-muted);
- }
+ .el-input__suffix {
+ color: var(--text-muted);
+ }
- .el-button {
- --el-button-border-radius: 12px;
- height: 48px;
- font-size: 16px;
- font-weight: 600;
+ .el-button {
+ --el-button-border-radius: 12px;
+ height: 48px;
+ font-size: 16px;
+ font-weight: 600;
- &.el-button--primary {
- background: linear-gradient(135deg, var(--auth-primary), var(--auth-primary-dark));
- border: none;
- box-shadow: 0 8px 24px rgba(255, 107, 53, 0.35);
- transition: all 0.3s ease;
+ &.el-button--primary {
+ background: linear-gradient(135deg, var(--auth-primary), var(--auth-primary-dark));
+ border: none;
+ box-shadow: 0 8px 24px rgba(255, 107, 53, 0.35);
+ transition: all 0.3s ease;
- &:hover {
- background: linear-gradient(135deg, var(--auth-primary-light), var(--auth-primary));
- transform: translateY(-2px);
- box-shadow: 0 12px 32px rgba(255, 107, 53, 0.45);
- }
+ &:hover {
+ background: linear-gradient(135deg, var(--auth-primary-light), var(--auth-primary));
+ transform: translateY(-2px);
+ box-shadow: 0 12px 32px rgba(255, 107, 53, 0.45);
+ }
- &:active {
- transform: translateY(0);
- }
- }
- }
+ &:active {
+ transform: translateY(0);
+ }
+ }
+ }
}
.auth-links {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 24px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 24px;
- .remember-me {
- .el-checkbox__label {
- color: var(--text-secondary);
- font-size: 14px;
- }
- }
+ .remember-me {
+ .el-checkbox__label {
+ color: var(--text-secondary);
+ font-size: 14px;
+ }
+ }
- .forgot-password {
- color: var(--auth-primary);
- font-size: 14px;
- text-decoration: none;
- transition: color 0.3s ease;
+ .forgot-password {
+ color: var(--auth-primary);
+ font-size: 14px;
+ text-decoration: none;
+ transition: color 0.3s ease;
- &:hover {
- color: var(--auth-primary-dark);
- }
- }
+ &:hover {
+ color: var(--auth-primary-dark);
+ }
+ }
}
.auth-divider {
- display: flex;
- align-items: center;
- margin: 32px 0;
- color: var(--text-muted);
- font-size: 13px;
+ display: flex;
+ align-items: center;
+ margin: 32px 0;
+ color: var(--text-muted);
+ font-size: 13px;
- &::before,
- &::after {
- content: '';
- flex: 1;
- height: 1px;
- background: var(--border-color);
- }
+ &::before,
+ &::after {
+ content: '';
+ flex: 1;
+ height: 1px;
+ background: var(--border-color);
+ }
- span {
- padding: 0 16px;
- }
+ span {
+ padding: 0 16px;
+ }
}
.auth-footer {
- text-align: center;
- margin-top: 24px;
+ text-align: center;
+ margin-top: 24px;
- .auth-footer-text {
- color: var(--text-secondary);
- font-size: 14px;
+ .auth-footer-text {
+ color: var(--text-secondary);
+ font-size: 14px;
- .auth-link {
- color: var(--auth-primary);
- text-decoration: none;
- font-weight: 600;
- margin-left: 4px;
- transition: color 0.3s ease;
+ .auth-link {
+ color: var(--auth-primary);
+ text-decoration: none;
+ font-weight: 600;
+ margin-left: 4px;
+ transition: color 0.3s ease;
- &:hover {
- color: var(--auth-primary-dark);
- }
- }
- }
+ &:hover {
+ color: var(--auth-primary-dark);
+ }
+ }
+ }
}
.tech-decoration {
- position: absolute;
- width: 100%;
- height: 100%;
- top: 0;
- left: 0;
- pointer-events: none;
- overflow: hidden;
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ pointer-events: none;
+ overflow: hidden;
- .tech-circle {
- position: absolute;
- border: 2px solid rgba(255, 107, 53, 0.1);
- border-radius: 50%;
- animation: pulse 4s ease-in-out infinite;
- }
+ .tech-circle {
+ position: absolute;
+ border: 2px solid rgba(255, 107, 53, 0.1);
+ border-radius: 50%;
+ animation: pulse 4s ease-in-out infinite;
+ }
- .tech-circle:nth-child(1) {
- width: 300px;
- height: 300px;
- top: -150px;
- left: -150px;
- animation-delay: 0s;
- }
+ .tech-circle:nth-child(1) {
+ width: 300px;
+ height: 300px;
+ top: -150px;
+ left: -150px;
+ animation-delay: 0s;
+ }
- .tech-circle:nth-child(2) {
- width: 200px;
- height: 200px;
- bottom: -100px;
- right: -100px;
- animation-delay: 1s;
- }
+ .tech-circle:nth-child(2) {
+ width: 200px;
+ height: 200px;
+ bottom: -100px;
+ right: -100px;
+ animation-delay: 1s;
+ }
- .tech-circle:nth-child(3) {
- width: 150px;
- height: 150px;
- bottom: 20%;
- left: -75px;
- animation-delay: 2s;
- }
+ .tech-circle:nth-child(3) {
+ width: 150px;
+ height: 150px;
+ bottom: 20%;
+ left: -75px;
+ animation-delay: 2s;
+ }
}
@keyframes pulse {
- 0%, 100% {
- opacity: 0.3;
- transform: scale(1);
- }
- 50% {
- opacity: 0.6;
- transform: scale(1.05);
- }
+ 0%,
+ 100% {
+ opacity: 0.3;
+ transform: scale(1);
+ }
+ 50% {
+ opacity: 0.6;
+ transform: scale(1.05);
+ }
}
// Responsive design
@media (max-width: 768px) {
- .auth-card {
- padding: 40px 24px;
- margin: 16px;
- }
+ .auth-card {
+ padding: 40px 24px;
+ margin: 16px;
+ }
- .auth-header {
- .auth-title {
- font-size: 24px;
- }
- }
+ .auth-header {
+ .auth-title {
+ font-size: 24px;
+ }
+ }
}
// Element Plus customizations for auth pages
.el-form-item__error {
- color: var(--error);
- font-size: 12px;
+ color: var(--error);
+ font-size: 12px;
}
.el-message {
- --el-message-bg: rgba(255, 255, 255, 0.98);
- --el-message-border-color: var(--border-color);
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
+ --el-message-bg: rgba(255, 255, 255, 0.98);
+ --el-message-border-color: var(--border-color);
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}
diff --git a/src/boot.js b/src/boot.js
index 97b84b0..f03da87 100644
--- a/src/boot.js
+++ b/src/boot.js
@@ -3,7 +3,6 @@ import * as ElementPlusIconsVue from '@element-plus/icons-vue'
export default {
install(app) {
-
for (let icon in AIcons) {
app.component(`A${icon}`, AIcons[icon])
}
@@ -11,5 +10,5 @@ export default {
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(`${key}`, component)
}
- }
+ },
}
diff --git a/src/components/scEditor/UploadAdapter.js b/src/components/scEditor/UploadAdapter.js
index f689603..af53009 100644
--- a/src/components/scEditor/UploadAdapter.js
+++ b/src/components/scEditor/UploadAdapter.js
@@ -1,144 +1,144 @@
export default class UploadAdapter {
constructor(loader, options) {
- this.loader = loader;
- this.options = options;
- this.timeout = 60000; // 60秒超时
+ this.loader = loader
+ this.options = options
+ this.timeout = 60000 // 60秒超时
}
upload() {
return this.loader.file.then(
(file) =>
new Promise((resolve, reject) => {
- this._initRequest();
- this._initListeners(resolve, reject, file);
- this._sendRequest(file);
- this._initTimeout(reject);
+ this._initRequest()
+ this._initListeners(resolve, reject, file)
+ this._sendRequest(file)
+ this._initTimeout(reject)
}),
- );
+ )
}
abort() {
if (this.xhr) {
- this.xhr.abort();
+ this.xhr.abort()
}
if (this.timeoutId) {
- clearTimeout(this.timeoutId);
+ clearTimeout(this.timeoutId)
}
}
_initRequest() {
- const xhr = (this.xhr = new XMLHttpRequest());
+ const xhr = (this.xhr = new XMLHttpRequest())
- xhr.open("POST", this.options.upload.uploadUrl, true);
- xhr.responseType = "json";
+ xhr.open('POST', this.options.upload.uploadUrl, true)
+ xhr.responseType = 'json'
}
_initListeners(resolve, reject, file) {
- const xhr = this.xhr;
- const loader = this.loader;
- const genericErrorText = `Couldn't upload file: ${file.name}.`;
+ const xhr = this.xhr
+ const loader = this.loader
+ const genericErrorText = `Couldn't upload file: ${file.name}.`
- xhr.addEventListener("error", () => {
- console.error("[UploadAdapter] Upload error for file:", file.name);
- reject(genericErrorText);
- });
+ xhr.addEventListener('error', () => {
+ console.error('[UploadAdapter] Upload error for file:', file.name)
+ reject(genericErrorText)
+ })
- xhr.addEventListener("abort", () => {
- console.warn("[UploadAdapter] Upload aborted for file:", file.name);
- reject();
- });
+ xhr.addEventListener('abort', () => {
+ console.warn('[UploadAdapter] Upload aborted for file:', file.name)
+ reject()
+ })
- xhr.addEventListener("timeout", () => {
- console.error("[UploadAdapter] Upload timeout for file:", file.name);
- reject(`Upload timeout: ${file.name}. Please try again.`);
- });
+ xhr.addEventListener('timeout', () => {
+ console.error('[UploadAdapter] Upload timeout for file:', file.name)
+ reject(`Upload timeout: ${file.name}. Please try again.`)
+ })
- xhr.addEventListener("load", () => {
- const response = xhr.response;
+ xhr.addEventListener('load', () => {
+ const response = xhr.response
// 检查响应状态码
if (xhr.status >= 200 && xhr.status < 300) {
if (!response) {
- console.error("[UploadAdapter] Empty response for file:", file.name);
- reject(genericErrorText);
- return;
+ console.error('[UploadAdapter] Empty response for file:', file.name)
+ reject(genericErrorText)
+ return
}
// 检查业务状态码(假设 code=1 表示成功)
if (response.code == 1 || response.code == undefined) {
- const url = response.data?.url || response.data?.src;
+ const url = response.data?.url || response.data?.src
if (!url) {
- console.error("[UploadAdapter] No URL in response for file:", file.name, response);
- reject("Upload succeeded but no URL returned");
- return;
+ console.error('[UploadAdapter] No URL in response for file:', file.name, response)
+ reject('Upload succeeded but no URL returned')
+ return
}
- resolve({ default: url });
+ resolve({ default: url })
} else {
- const errorMessage = response.message || genericErrorText;
- console.error("[UploadAdapter] Upload failed for file:", file.name, "Error:", errorMessage);
- reject(errorMessage);
+ const errorMessage = response.message || genericErrorText
+ console.error('[UploadAdapter] Upload failed for file:', file.name, 'Error:', errorMessage)
+ reject(errorMessage)
}
} else {
- console.error("[UploadAdapter] HTTP error for file:", file.name, "Status:", xhr.status);
- reject(`Server error (${xhr.status}): ${file.name}`);
+ console.error('[UploadAdapter] HTTP error for file:', file.name, 'Status:', xhr.status)
+ reject(`Server error (${xhr.status}): ${file.name}`)
}
- });
+ })
// 上传进度监听
if (xhr.upload) {
- xhr.upload.addEventListener("progress", (evt) => {
+ xhr.upload.addEventListener('progress', (evt) => {
if (evt.lengthComputable) {
- loader.uploadTotal = evt.total;
- loader.uploaded = evt.loaded;
+ loader.uploadTotal = evt.total
+ loader.uploaded = evt.loaded
}
- });
+ })
}
}
_initTimeout(reject) {
// 清除之前的超时定时器(如果有)
if (this.timeoutId) {
- clearTimeout(this.timeoutId);
+ clearTimeout(this.timeoutId)
}
// 设置新的超时定时器
this.timeoutId = setTimeout(() => {
if (this.xhr) {
- this.xhr.abort();
- reject(new Error("Upload timeout"));
+ this.xhr.abort()
+ reject(new Error('Upload timeout'))
}
- }, this.timeout);
+ }, this.timeout)
}
_sendRequest(file) {
// 设置请求超时
- this.xhr.timeout = this.timeout;
+ this.xhr.timeout = this.timeout
// Set headers if specified.
- const headers = this.options.upload.headers || {};
- const extendData = this.options.upload.extendData || {};
+ const headers = this.options.upload.headers || {}
+ const extendData = this.options.upload.extendData || {}
// Use the withCredentials flag if specified.
- const withCredentials = this.options.upload.withCredentials || false;
- const uploadName = this.options.upload.uploadName || "file";
+ const withCredentials = this.options.upload.withCredentials || false
+ const uploadName = this.options.upload.uploadName || 'file'
for (const headerName of Object.keys(headers)) {
- this.xhr.setRequestHeader(headerName, headers[headerName]);
+ this.xhr.setRequestHeader(headerName, headers[headerName])
}
- this.xhr.withCredentials = withCredentials;
+ this.xhr.withCredentials = withCredentials
- const data = new FormData();
+ const data = new FormData()
for (const key of Object.keys(extendData)) {
- data.append(key, extendData[key]);
+ data.append(key, extendData[key])
}
- data.append(uploadName, file);
+ data.append(uploadName, file)
- this.xhr.send(data);
+ this.xhr.send(data)
}
}
export function UploadAdapterPlugin(editor) {
- editor.plugins.get("FileRepository").createUploadAdapter = (loader) => {
- return new UploadAdapter(loader, editor.config._config);
- };
+ editor.plugins.get('FileRepository').createUploadAdapter = (loader) => {
+ return new UploadAdapter(loader, editor.config._config)
+ }
}
diff --git a/src/components/scEditor/index.vue b/src/components/scEditor/index.vue
index 8be1b79..948c3e2 100644
--- a/src/components/scEditor/index.vue
+++ b/src/components/scEditor/index.vue
@@ -1,7 +1,6 @@
-
+
@@ -69,137 +68,119 @@ import {
Underline,
Undo,
WordCount,
-} from "ckeditor5";
-import { Ckeditor } from "@ckeditor/ckeditor5-vue";
-import { UploadAdapterPlugin } from "./UploadAdapter.js";
+} from 'ckeditor5'
+import { Ckeditor } from '@ckeditor/ckeditor5-vue'
+import { UploadAdapterPlugin } from './UploadAdapter.js'
-import { ref, computed, watch } from "vue";
-import { useCurrentInstance } from "@/utils/tool";
+import { ref, computed, watch } from 'vue'
+import { useCurrentInstance } from '@/utils/tool'
-import coreTranslations from "ckeditor5/translations/zh-cn.js";
-import "ckeditor5/ckeditor5.css";
+import coreTranslations from 'ckeditor5/translations/zh-cn.js'
+import 'ckeditor5/ckeditor5.css'
-const { proxy } = useCurrentInstance();
+const { proxy } = useCurrentInstance()
// 组件名称
defineOptions({
- name: "scCkeditor"
-});
+ name: 'scCkeditor',
+})
// Props 定义
const props = defineProps({
modelValue: {
type: String,
- default: "",
+ default: '',
},
placeholder: {
type: String,
- default: "请输入内容……",
+ default: '请输入内容……',
},
toolbar: {
type: String,
- default: "basic",
+ default: 'basic',
},
height: {
type: String,
- default: "400px",
+ default: '400px',
},
disabled: {
type: Boolean,
default: false,
},
-});
+})
// Emits 定义
-const emit = defineEmits(["update:modelValue"]);
+const emit = defineEmits(['update:modelValue'])
// 工具栏配置常量
const TOOLBARS = {
full: [
- "sourceEditing",
- "undo",
- "redo",
- "heading",
- "style",
- "|",
- "superscript",
- "subscript",
- "removeFormat",
- "bold",
- "italic",
- "underline",
- "link",
- "fontBackgroundColor",
- "fontFamily",
- "fontSize",
- "fontColor",
- "|",
- "outdent",
- "indent",
- "alignment",
- "bulletedList",
- "numberedList",
- "todoList",
- "|",
- "blockQuote",
- "insertTable",
- "imageInsert",
- "mediaEmbed",
- "highlight",
- "horizontalLine",
- "selectAll",
- "showBlocks",
- "specialCharacters",
- "codeBlock",
- "findAndReplace",
+ 'sourceEditing',
+ 'undo',
+ 'redo',
+ 'heading',
+ 'style',
+ '|',
+ 'superscript',
+ 'subscript',
+ 'removeFormat',
+ 'bold',
+ 'italic',
+ 'underline',
+ 'link',
+ 'fontBackgroundColor',
+ 'fontFamily',
+ 'fontSize',
+ 'fontColor',
+ '|',
+ 'outdent',
+ 'indent',
+ 'alignment',
+ 'bulletedList',
+ 'numberedList',
+ 'todoList',
+ '|',
+ 'blockQuote',
+ 'insertTable',
+ 'imageInsert',
+ 'mediaEmbed',
+ 'highlight',
+ 'horizontalLine',
+ 'selectAll',
+ 'showBlocks',
+ 'specialCharacters',
+ 'codeBlock',
+ 'findAndReplace',
],
basic: [
- "sourceEditing",
- "undo",
- "redo",
- "heading",
- "|",
- "removeFormat",
- "bold",
- "italic",
- "underline",
- "link",
- "fontBackgroundColor",
- "fontFamily",
- "fontSize",
- "fontColor",
- "|",
- "outdent",
- "indent",
- "alignment",
- "bulletedList",
- "numberedList",
- "todoList",
- "|",
- "insertTable",
- "imageInsert",
- "mediaEmbed",
+ 'sourceEditing',
+ 'undo',
+ 'redo',
+ 'heading',
+ '|',
+ 'removeFormat',
+ 'bold',
+ 'italic',
+ 'underline',
+ 'link',
+ 'fontBackgroundColor',
+ 'fontFamily',
+ 'fontSize',
+ 'fontColor',
+ '|',
+ 'outdent',
+ 'indent',
+ 'alignment',
+ 'bulletedList',
+ 'numberedList',
+ 'todoList',
+ '|',
+ 'insertTable',
+ 'imageInsert',
+ 'mediaEmbed',
],
- simple: [
- "undo",
- "redo",
- "heading",
- "|",
- "removeFormat",
- "bold",
- "italic",
- "underline",
- "link",
- "fontBackgroundColor",
- "fontFamily",
- "fontSize",
- "fontColor",
- "|",
- "insertTable",
- "imageInsert",
- "mediaEmbed",
- ],
-};
+ simple: ['undo', 'redo', 'heading', '|', 'removeFormat', 'bold', 'italic', 'underline', 'link', 'fontBackgroundColor', 'fontFamily', 'fontSize', 'fontColor', '|', 'insertTable', 'imageInsert', 'mediaEmbed'],
+}
// 插件配置常量
const PLUGINS = [
@@ -265,16 +246,16 @@ const PLUGINS = [
Undo,
WordCount,
UploadAdapterPlugin,
-];
+]
// 响应式数据
-const editorData = ref("");
-const editorHeight = ref(props.height);
-const editor = ClassicEditor;
+const editorData = ref('')
+const editorHeight = ref(props.height)
+const editor = ClassicEditor
// 编辑器配置
const editorConfig = computed(() => ({
- language: { ui: "zh-cn", content: "zh-cn" },
+ language: { ui: 'zh-cn', content: 'zh-cn' },
translations: [coreTranslations],
plugins: PLUGINS,
toolbar: {
@@ -283,27 +264,18 @@ const editorConfig = computed(() => ({
},
placeholder: props.placeholder,
image: {
- styles: ["alignLeft", "alignCenter", "alignRight"],
- toolbar: [
- "imageTextAlternative",
- "toggleImageCaption",
- "|",
- "imageStyle:alignLeft",
- "imageStyle:alignCenter",
- "imageStyle:alignRight",
- "|",
- "linkImage",
- ],
+ styles: ['alignLeft', 'alignCenter', 'alignRight'],
+ toolbar: ['imageTextAlternative', 'toggleImageCaption', '|', 'imageStyle:alignLeft', 'imageStyle:alignCenter', 'imageStyle:alignRight', '|', 'linkImage'],
},
mediaEmbed: {
previewsInData: true,
providers: [
{
- name: "mp4",
+ name: 'mp4',
url: /\.(mp4|avi|mov|flv|wmv|mkv)$/i,
- html: match => {
- const url = match["input"];
- return ('')
+ html: (match) => {
+ const url = match['input']
+ return ''
},
},
],
@@ -314,59 +286,57 @@ const editorConfig = computed(() => ({
style: {
definitions: [
{
- name: "Article category",
- element: "h3",
- classes: ["category"],
+ name: 'Article category',
+ element: 'h3',
+ classes: ['category'],
},
{
- name: "Info box",
- element: "p",
- classes: ["info-box"],
+ name: 'Info box',
+ element: 'p',
+ classes: ['info-box'],
},
],
},
upload: {
- uploadUrl: proxy?.$API?.common?.upload?.url || "",
+ uploadUrl: proxy?.$API?.common?.upload?.url || '',
withCredentials: false,
- extendData: { type: "images" },
+ extendData: { type: 'images' },
headers: {
- Authorization: "Bearer " + proxy?.$TOOL?.data?.get("TOKEN"),
+ Authorization: 'Bearer ' + proxy?.$TOOL?.data?.get('TOKEN'),
},
},
-}));
+}))
// 监听 modelValue 变化
watch(
() => props.modelValue,
(newVal) => {
- editorData.value = newVal ?? "";
+ editorData.value = newVal ?? ''
},
- { immediate: true }
-);
+ { immediate: true },
+)
// 监听 height 变化
watch(
() => props.height,
(newVal) => {
- editorHeight.value = newVal;
- }
-);
+ editorHeight.value = newVal
+ },
+)
// 移除图片宽高的正则替换函数
const stripImageDimensions = (html) => {
return html.replace(/
]*>/gi, (match) => {
- return match
- .replace(/width="[^"]*"/gi, "")
- .replace(/height="[^"]*"/gi, "");
- });
-};
+ return match.replace(/width="[^"]*"/gi, '').replace(/height="[^"]*"/gi, '')
+ })
+}
// 失去焦点事件 - 移除图片的固定宽高,避免响应式布局问题
const onBlur = () => {
- const cleanedData = stripImageDimensions(editorData.value);
- editorData.value = cleanedData;
- emit("update:modelValue", cleanedData);
-};
+ const cleanedData = stripImageDimensions(editorData.value)
+ editorData.value = cleanedData
+ emit('update:modelValue', cleanedData)
+}