🎨 集成前端代码到后端仓库

✨ 新增功能:
- 将完整的前端Vue项目集成到后端仓库
- 创建 frontend/ 目录存放前端代码
- 排除了 .git、node_modules 等不必要文件

🎯 集成优势:
- 一个仓库包含完整前后端代码
- 简化部署和维护流程
- 方便版本同步和管理
- 减少仓库管理复杂度

📁 项目结构:
- backend/: Java Spring Boot 后端
- frontend/: Vue.js 前端项目
- docker/: 容器配置
- docs/: 各种部署文档

🚀 现在只需克隆一个仓库就能获得:
- JmalCloud 公共空间版后端
- 配套的前端界面
- 完整的Docker部署配置
- 详细的部署文档
This commit is contained in:
chenpei 2025-08-24 12:10:33 +08:00
parent c401f2078a
commit 8591ad3233
546 changed files with 45958 additions and 0 deletions

10
frontend/.editorconfig Normal file
View File

@ -0,0 +1,10 @@
# http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

View File

@ -0,0 +1,3 @@
ENV = 'development'
# base api
VUE_APP_BASE_API = '/api'

3
frontend/.env.production Normal file
View File

@ -0,0 +1,3 @@
ENV = 'production'
# base api
VUE_APP_BASE_API = '/api'

7
frontend/.env.test Normal file
View File

@ -0,0 +1,7 @@
NODE_ENV = production
# just a flag
ENV = 'test'
# base api
VUE_APP_BASE_API = '/api'

39
frontend/.github/release-drafter.yml vendored Normal file
View File

@ -0,0 +1,39 @@
# .github/release-drafter.yml
name-template: 'v$NEXT_PATCH_VERSION'
tag-template: 'v$NEXT_PATCH_VERSION'
categories:
- title: '新功能 ✨'
labels:
- 'feature'
- title: '修复 🐛'
labels:
- 'bug'
- title: '优化 🎨️'
labels:
- 'improvement'
change-template: '- $TITLE (#$NUMBER)'
no-changes-template: '- No changes'
template: |
[docker-docker.yml](https://github.com/jamebal/jmal-cloud-server/blob/master/docker-compose.base.yml)
#### 更新前备份数据库
```shell
docker exec -it jmalcloud_mongodb mongodump -d jmalcloud -o /dump/$PREVIOUS_TAG --gzip --quiet
```
```shell
docker-compose pull && docker-compose up -d
```
#### 清理旧镜像
```shell
docker images --filter=reference='jmal/jmalcloud*' --filter "dangling=true" -q | xargs -r docker rmi
```
## Changes in this release:
$CHANGES
**Full Changelog**: [$PREVIOUS_TAG...v$NEXT_PATCH_VERSION](https://github.com/jamebal/jmal-cloud-view/compare/$PREVIOUS_TAG...v$NEXT_PATCH_VERSION)

View File

@ -0,0 +1,32 @@
name: Build nginx with Draw.io Docker Image
on:
workflow_dispatch:
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: docker/nginx-drawio/Dockerfile
push: true
tags: jmal/nginx-drawio:latest
platforms: linux/amd64,linux/arm64
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

60
frontend/.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,60 @@
name: Build Docker Image
on:
workflow_dispatch:
release:
types: [published]
tags: [v*]
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Node.js 16.20.2
uses: actions/setup-node@v4
with:
node-version: 16.20.2
- name: Install dependencies
run: npm install && npm install --save core-js@2
- name: Build
run: npm run build:prod
- name: Extract project version from package.json
run: |
VERSION=$(node -p "require('./package.json').version")
echo "PROJECT_VERSION=$VERSION" >> $GITHUB_ENV
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ secrets.GHCR_IO_USERNAME }}
password: ${{ secrets.GHCR_IO_TOKEN }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: true
tags: |
jmal/jmalcloud-nginx:${{ env.PROJECT_VERSION }},jmal/jmalcloud-nginx:latest
ghcr.io/${{ secrets.GHCR_IO_USERNAME }}/jmalcloud-nginx:${{ env.PROJECT_VERSION }},ghcr.io/${{ secrets.GHCR_IO_USERNAME }}/jmalcloud-nginx:latest
platforms: linux/amd64,linux/arm64
build-args: |
VERSION=${{ env.PROJECT_VERSION }}

View File

@ -0,0 +1,87 @@
name: Build and Push Docker Image to Aliyun
on:
workflow_dispatch:
release:
types: [ published ]
tags: [ v* ]
jobs:
build_and_push:
runs-on: ubuntu-latest
strategy:
matrix:
arch:
- amd64
- arm64
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Node.js 16.20.2
uses: actions/setup-node@v4
with:
node-version: 16.20.2
- name: Install dependencies
run: npm install && npm install --save core-js@2
- name: Build
run: npm run build:prod
- name: Extract project version from package.json
run: |
VERSION=$(node -p "require('./package.json').version")
echo "PROJECT_VERSION=$VERSION" >> $GITHUB_ENV
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Aliyun Container Registry guangzhou
uses: docker/login-action@v3
with:
registry: registry.cn-guangzhou.aliyuncs.com
username: ${{ secrets.ALIYUN_DOCKER_USERNAME }}
password: ${{ secrets.ALIYUN_DOCKER_PASSWORD }}
- name: Log in to Aliyun Container Registry beijing
uses: docker/login-action@v3
with:
registry: registry.cn-beijing.aliyuncs.com
username: ${{ secrets.ALIYUN_DOCKER_USERNAME }}
password: ${{ secrets.ALIYUN_DOCKER_PASSWORD }}
- name: Set tag for amd64
if: matrix.arch == 'amd64'
run: |
echo "TAG_LATEST_0=registry.cn-guangzhou.aliyuncs.com/jmalcloud/jmalcloud-nginx:latest" >> $GITHUB_ENV
echo "TAG_VERSION_0=registry.cn-guangzhou.aliyuncs.com/jmalcloud/jmalcloud-nginx:${{ env.PROJECT_VERSION }}" >> $GITHUB_ENV
echo "TAG_LATEST_1=registry.cn-beijing.aliyuncs.com/jmalcloud/jmalcloud-nginx:latest" >> $GITHUB_ENV
echo "TAG_VERSION_1=registry.cn-beijing.aliyuncs.com/jmalcloud/jmalcloud-nginx:${{ env.PROJECT_VERSION }}" >> $GITHUB_ENV
- name: Set tag for non-amd64
if: matrix.arch != 'amd64'
run: |
echo "TAG_LATEST_0=registry.cn-guangzhou.aliyuncs.com/jmalcloud/jmalcloud-nginx:latest-${{ matrix.arch }}" >> $GITHUB_ENV
echo "TAG_VERSION_0=registry.cn-guangzhou.aliyuncs.com/jmalcloud/jmalcloud-nginx:${{ env.PROJECT_VERSION }}-${{ matrix.arch }}" >> $GITHUB_ENV
echo "TAG_LATEST_1=registry.cn-beijing.aliyuncs.com/jmalcloud/jmalcloud-nginx:latest-${{ matrix.arch }}" >> $GITHUB_ENV
echo "TAG_VERSION_1=registry.cn-beijing.aliyuncs.com/jmalcloud/jmalcloud-nginx:${{ env.PROJECT_VERSION }}-${{ matrix.arch }}" >> $GITHUB_ENV
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
platforms: linux/${{ matrix.arch }}
push: true
tags: |
${{ env.TAG_LATEST_0 }}
${{ env.TAG_VERSION_0 }}
${{ env.TAG_LATEST_1 }}
${{ env.TAG_VERSION_1 }}
build-args: |
VERSION=${{ env.PROJECT_VERSION }}

View File

@ -0,0 +1,18 @@
# .github/workflows/release-drafter.yml
name: Release Drafter
on:
push:
branches:
- master
jobs:
update_release_draft:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: release-drafter/release-drafter@v5
with:
config-name: release-drafter.yml
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -0,0 +1,59 @@
name: Build Test Docker Image
on:
push:
branches: [ master ]
workflow_dispatch:
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Node.js 16.20.2
uses: actions/setup-node@v4
with:
node-version: 16.20.2
- name: Install dependencies
run: npm install
- name: Build
run: npm run build:prod
- name: Extract project version from package.json
run: |
VERSION=$(node -p "require('./package.json').version")
echo "PROJECT_VERSION=$VERSION" >> $GITHUB_ENV
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ secrets.GHCR_IO_USERNAME }}
password: ${{ secrets.GHCR_IO_TOKEN }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: true
tags: |
jmal/jmalcloud-nginx:test
ghcr.io/${{ secrets.GHCR_IO_USERNAME }}/jmalcloud-nginx:test
platforms: linux/amd64,linux/arm64
build-args: |
VERSION=${{ env.PROJECT_VERSION }}

21
frontend/.gitignore vendored Normal file
View File

@ -0,0 +1,21 @@
push.sh
update.sh
dist.tar
.history/
.DS_Store
node_modules/
dist/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
package-lock.json
tests/**/coverage/
# Editor directories and files
.idea
.fleet
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln

21
frontend/Dockerfile Normal file
View File

@ -0,0 +1,21 @@
FROM jmal/nginx-drawio:latest
RUN apk add --no-cache gettext
COPY nginx/nginx.conf.no_office.template /etc/nginx/nginx.conf.no_office.template
COPY nginx/nginx.conf.template /etc/nginx/nginx.conf.template
COPY nginx/proxy_params.conf /etc/nginx/conf/proxy_params.conf
COPY nginx/proxy_params_file.conf /etc/nginx/conf/proxy_params_file.conf
COPY dist /var/www/public
COPY config.js.template /var/www/public/config.js.template
COPY docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh
EXPOSE 80
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]

21
frontend/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 jmal
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

85
frontend/README.md Normal file
View File

@ -0,0 +1,85 @@
# JmalCloud 个人网盘 | [English](https://github.com/jamebal/jmal-cloud-view/blob/master/README_en_US.md)
JmalCloud 是一款私有云存储网盘项目,能够简单安全管理您的云端文件
✅ 支持OSS,阿里云OS、腾讯云OSS和MinIO
✅ 支持图片,音频,视频等文件的在线预览
✅ 支持Word、Excel、PPT、流程图和思维导图的编辑和预览
✅ 支持x86、arm64(Centos/Debian/Ubuntu/macOS)
✅ 提供强大的在线文本编辑器
✅ 支持超大文件上传,断点续传
✅ 支持WebDAV
### 线上Demo:
[查看 Demo](https://jmal.cc/demo) , 用户名:demo, 密码:demo1234
### 部署
- 必须安装:`Docker` 和 `Docker Compose v2.0+`
参考[docker-compose.yml](https://github.com/jamebal/jmal-cloud-server/blob/master/docker-compose.base.yml)
```shell
docker compose up -d
```
等待启动后访问: http://{your_ip}:7070
#### 重启管理员密码
```shell
# 1. 重置密码
docker exec -it jmalcloud_mongodb mongo jmalcloud --eval "db.getCollection('user').update({ 'creator': true }, {\$set: { 'password': '1000:c5b705ea13a1221f5e59110947ed806f8a978e955fbd2ed6:22508de12228c34a235454a0caf3bcaa5552858543258e56' }}, { 'multi': false, 'upsert': false })"
# 2. 重启容器
docker restart jmalcloud_server
# 重置后的密码为: jmalcloud
```
### 备份/恢复 数据库
#### 备份数据库
```shell
docker exec -it jmalcloud_mongodb mongodump -d jmalcloud -o /dump/xxx --gzip --quiet
```
#### 恢复数据库
```shell
docker exec -it jmalcloud_mongodb mongorestore --gzip --nsInclude=jmalcloud.* --dir /dump/xxx --quiet
```
### dev
#### 环境准备:
- jdk17+
- mongodb4.4+
- node v16.x.x
##### 1、克隆服务端项目
`git clone https://github.com/jamebal/jmal-cloud-server.git`
##### 2、修改配置文件 `src/main/resources/file.yml`
修改参数`rootDir` 和 `ip2region-db-path` 改为自己的目录, 即可启动服务
##### 3、克隆web端项目
`git clone https://github.com/jamebal/jmal-cloud-view.git`
##### 4、项目目录下执行`npm install`
##### 5、启动web端`npm run dev`
### 部分截图:
![image0](./doc/%E6%88%AA%E5%B1%8F%20192.png)
![image1](./doc/%E6%88%AA%E5%B1%8F%2028.png)
![image2](./doc/%E6%88%AA%E5%B1%8F%2029.png)
![image3](./doc/%E6%88%AA%E5%B1%8F%2030.png)
![image4](./doc/%E6%88%AA%E5%B1%8F%2031.png)
![image5](./doc/%E6%88%AA%E5%B1%8F%2032.png)
![image6](./doc/%E6%88%AA%E5%B1%8F%2033.png)
### 浏览器支持
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
| --------- | --------- | --------- | --------- |
| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions
### 许可
[MIT](https://github.com/jamebal/jmal-cloud-view/blob/master/LICENSE) license.
Copyright (c) 2020-present jmal

81
frontend/README_en_US.md Normal file
View File

@ -0,0 +1,81 @@
# JmalCloud Personal Netdisk | [中文](https://github.com/jamebal/jmal-cloud-view/blob/master/README.md)
JmalCloud It's a private cloud storage project that makes it simple and secure to manage your files in the cloud
✅ Support OSS, Alibaba Cloud OSS , Tencent Cloud OSS and MinIO
✅ Supports online preview of images, audio, video and other files
✅ Supports editing and previewing of Word, Excel, PPT, process and mind map
✅ support x86, arm64 (Centos/Debian/Ubuntu/macOS)
✅ provides a powerful online text editor
✅ Supports large file uploading and resumable uploading
✅ supports WebDAV
### Online Demo:
[Live Demo](https://jmal.cc/demo) , username:demo, password:demo1234
### Deploy
- Prerequisites:`Docker` and `Docker Compose v2.0+`
Refer to [docker-compose.yml](https://github.com/jamebal/jmal-cloud-server/blob/master/docker-compose.base.yml)
```shell
docker compose up -d
```
#### Resetting Administrator Password
```shell
# 1. Reset the password
docker exec -it jmalcloud_mongodb mongo jmalcloud --eval "db.getCollection('user').update({ 'creator': true }, {\$set: { 'password': '1000:c5b705ea13a1221f5e59110947ed806f8a978e955fbd2ed6:22508de12228c34a235454a0caf3bcaa5552858543258e56' }}, { 'multi': false, 'upsert': false })"
# 2. Restart the container
docker restart jmalcloud_server
# The password after resetting is: jmalcloud
```
### Dev
#### Environment Requirements:
- jdk17+
- mongodb4.4+
- node v16.x.x
##### 1. Clone the server-side project
`git clone https://github.com/jamebal/jmal-cloud-server.git`
##### 2. Modify the configuration file `src/main/resources/file.yml`
Change the parameters `rootDir` and `ip2region-db-path` to your own directory and start the service
##### 3. Clone the web-side project
`git clone https://github.com/jamebal/jmal-cloud-view.git`
##### 4. Run `npm install` in the project directory
##### 5. Start the web-side with `npm run dev`
### Some screenshots:
![image0](./doc/%E6%88%AA%E5%B1%8F%20192.png)
![image1](./doc/%E6%88%AA%E5%B1%8F%2028.png)
![image2](./doc/%E6%88%AA%E5%B1%8F%2029.png)
![image3](./doc/%E6%88%AA%E5%B1%8F%2030.png)
![image4](./doc/%E6%88%AA%E5%B1%8F%2031.png)
![image5](./doc/%E6%88%AA%E5%B1%8F%2032.png)
![image6](./doc/%E6%88%AA%E5%B1%8F%2033.png)
### Browser Support
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
| --------- | --------- | --------- | --------- |
| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions
### Follow-up Updates
- [ ] iOS APP
- [ ] Android APP
- [ ] PC
### Permission
[MIT](https://github.com/jamebal/jmal-cloud-view/blob/master/LICENSE) license.
Copyright (c) 2020-present jmal

14
frontend/babel.config.js Normal file
View File

@ -0,0 +1,14 @@
// https://www.babeljs.cn/
module.exports = {
presets: [
'@vue/app'
],
plugins: [
['import', {
libraryName: 'vant',
libraryDirectory: 'es',
style: true
}, 'vant'],
["import", { "libraryName": "ant-design-vue", "libraryDirectory": "es", "style": "css" }]
]
}

View File

@ -0,0 +1,4 @@
window._env_ = {
API_URL: "${API_URL}",
API_OFFICE_URL: "${API_OFFICE_URL}"
};

BIN
frontend/doc/截屏 192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 KiB

BIN
frontend/doc/截屏 28.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 KiB

BIN
frontend/doc/截屏 29.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 531 KiB

BIN
frontend/doc/截屏 30.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 KiB

BIN
frontend/doc/截屏 31.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 KiB

BIN
frontend/doc/截屏 32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

BIN
frontend/doc/截屏 33.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 KiB

View File

@ -0,0 +1,20 @@
#!/bin/sh
set -e
# ... 其余内容保持不变 ...
if getent hosts office &> /dev/null; then
cp /etc/nginx/nginx.conf.template /etc/nginx/nginx.conf
else
cp /etc/nginx/nginx.conf.no_office.template /etc/nginx/nginx.conf
fi
envsubst '${API_URL} ${API_OFFICE_URL}' < /var/www/public/config.js.template > /var/www/public/config.js
while ! getent hosts jmalcloud > /dev/null 2>&1; do
echo "jmalcloud is not yet resolvable, waiting 2 seconds..."
sleep 2
done
echo "jmalcloud is now resolvable. Starting Nginx..."
exec "$@"

View File

@ -0,0 +1,40 @@
FROM debian:bookworm-slim AS builder
# 1. 安装必要的工具
RUN apt-get update && \
apt-get install -y wget unzip tar && \
rm -rf /var/lib/apt/lists/*
# 2. 设置工作目录
WORKDIR /app
# 3. 下载所有需要的资源
RUN wget https://github.com/jgraph/drawio/releases/download/v24.4.10/draw.war -O draw.war && \
wget https://github.com/mozilla/pdf.js/releases/download/v4.3.136/pdfjs-4.3.136-dist.zip -O pdfjs.zip && \
wget https://github.com/jamebal/excalidraw/releases/download/v0.17.3/build.tar.gz -O excalidraw.tar.gz
# 4. 创建目录并解压文件到对应目录
RUN mkdir -p draw pdfjs excalidraw && \
unzip draw.war -d draw && \
unzip pdfjs.zip -d pdfjs && \
tar -xvf excalidraw.tar.gz -C excalidraw
# 5. 清理不必要的文件
RUN rm -rf draw/META-INF draw/WEB-INF
FROM nginx:1.27-alpine
# 1. 清理 Nginx 默认的配置和欢迎页面
RUN rm -f /etc/nginx/conf.d/* /usr/share/nginx/html/*
# 2. 从构建阶段 (builder) 复制处理好的静态文件到 Nginx 的服务目录
COPY --from=builder /app/draw /usr/share/nginx/html/draw
COPY --from=builder /app/pdfjs /usr/share/nginx/html/pdfjs
COPY --from=builder /app/excalidraw /usr/share/nginx/html/excalidraw
# 3. 复制你的自定义 Nginx 配置文件
COPY docker/nginx-drawio/drawio.conf /etc/nginx/conf.d/drawio.conf
COPY docker/nginx-drawio/excalidraw.conf /etc/nginx/conf.d/excalidraw.conf
COPY docker/nginx-drawio/pdfjs.conf /etc/nginx/conf.d/pdfjs.conf
COPY docker/nginx-drawio/mime.types /etc/nginx/mime.types

View File

@ -0,0 +1,10 @@
server {
listen 8080;
server_name localhost;
root /usr/share/nginx/html/draw;
location / {
try_files $uri $uri/ /index.html;
index index.html index.htm;
}
}

View File

@ -0,0 +1,10 @@
server {
listen 8082;
server_name localhost;
root /usr/share/nginx/html/excalidraw;
client_max_body_size 100m;
location / {
try_files $uri $uri/ /index.html;
index index.html index.htm;
}
}

View File

@ -0,0 +1,98 @@
types {
text/html html htm shtml;
text/css css;
text/xml xml;
image/gif gif;
image/jpeg jpeg jpg;
application/javascript js mjs;
application/atom+xml atom;
application/rss+xml rss;
text/mathml mml;
text/plain txt;
text/vnd.sun.j2me.app-descriptor jad;
text/vnd.wap.wml wml;
text/x-component htc;
image/avif avif;
image/png png;
image/svg+xml svg svgz;
image/tiff tif tiff;
image/vnd.wap.wbmp wbmp;
image/webp webp;
image/x-icon ico;
image/x-jng jng;
image/x-ms-bmp bmp;
font/woff woff;
font/woff2 woff2;
application/java-archive jar war ear;
application/json json;
application/mac-binhex40 hqx;
application/msword doc;
application/pdf pdf;
application/postscript ps eps ai;
application/rtf rtf;
application/vnd.apple.mpegurl m3u8;
application/vnd.google-earth.kml+xml kml;
application/vnd.google-earth.kmz kmz;
application/vnd.ms-excel xls;
application/vnd.ms-fontobject eot;
application/vnd.ms-powerpoint ppt;
application/vnd.oasis.opendocument.graphics odg;
application/vnd.oasis.opendocument.presentation odp;
application/vnd.oasis.opendocument.spreadsheet ods;
application/vnd.oasis.opendocument.text odt;
application/vnd.openxmlformats-officedocument.presentationml.presentation
pptx;
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
xlsx;
application/vnd.openxmlformats-officedocument.wordprocessingml.document
docx;
application/vnd.wap.wmlc wmlc;
application/wasm wasm;
application/x-7z-compressed 7z;
application/x-cocoa cco;
application/x-java-archive-diff jardiff;
application/x-java-jnlp-file jnlp;
application/x-makeself run;
application/x-perl pl pm;
application/x-pilot prc pdb;
application/x-rar-compressed rar;
application/x-redhat-package-manager rpm;
application/x-sea sea;
application/x-shockwave-flash swf;
application/x-stuffit sit;
application/x-tcl tcl tk;
application/x-x509-ca-cert der pem crt;
application/x-xpinstall xpi;
application/xhtml+xml xhtml;
application/xspf+xml xspf;
application/zip zip;
application/octet-stream bin exe dll;
application/octet-stream deb;
application/octet-stream dmg;
application/octet-stream iso img;
application/octet-stream msi msp msm;
audio/midi mid midi kar;
audio/mpeg mp3;
audio/ogg ogg;
audio/x-m4a m4a;
audio/x-realaudio ra;
video/3gpp 3gpp 3gp;
video/mp2t ts;
video/mp4 mp4;
video/mpeg mpeg mpg;
video/quicktime mov;
video/webm webm;
video/x-flv flv;
video/x-m4v m4v;
video/x-mng mng;
video/x-ms-asf asx asf;
video/x-ms-wmv wmv;
video/x-msvideo avi;
}

View File

@ -0,0 +1,5 @@
server {
listen 8081;
server_name localhost;
root /usr/share/nginx/html/pdfjs;
}

10
frontend/jsconfig.json Normal file
View File

@ -0,0 +1,10 @@
{
"compilerOptions": {
"target": "es6",
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
},
"exclude": ["node_modules", "dist"]
}

View File

@ -0,0 +1,192 @@
# nginx.conf : /etc/nginx/nginx.conf
#user nobody;
worker_processes auto; # 自动根据 CPU 核心数设置
events {
worker_connections 2048;
multi_accept on;
}
#设定http服务器,利用它的反向代理功能提供负载均衡支持
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
include mime.types;
default_type application/octet-stream;
# 日志
#access_log /var/log/nginx/access.log main buffer=32k flush=5s;
access_log off;
error_log /var/log/nginx/error.log warn;
# 全局性能优化
sendfile on;
tcp_nopush on;
tcp_nodelay on;
server_names_hash_bucket_size 512;
keepalive_timeout 65;
keepalive_requests 1000;
# 全局上传/头部限制
client_header_buffer_size 32k;
client_max_body_size 50m; # 全局默认值
# 全局默认代理缓冲 (用于普通API)
proxy_buffer_size 16k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
# 默认启用 gzip
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 6;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/json;
gzip_vary on;
gzip_proxied any;
gzip_disable "MSIE [1-6]\.";
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
map $http_host $this_host {
"" $host;
default $http_host;
}
map $http_x_forwarded_proto $the_scheme {
default $http_x_forwarded_proto;
"" $scheme;
}
map $http_x_forwarded_host $the_host {
default $http_x_forwarded_host;
"" $this_host;
}
server {
listen 8089;
server_name localhost;
location = / {
proxy_pass http://jmalcloud:8088/articles;
include /etc/nginx/conf/proxy_params.conf;
}
location /api {
proxy_pass http://jmalcloud:8088;
include /etc/nginx/conf/proxy_params.conf;
}
location /articles/articles {
proxy_pass http://jmalcloud:8088/articles;
include /etc/nginx/conf/proxy_params.conf;
}
location /articles {
proxy_pass http://jmalcloud:8088/articles;
include /etc/nginx/conf/proxy_params.conf;
}
location / {
proxy_pass http://jmalcloud:8088/articles/;
include /etc/nginx/conf/proxy_params.conf;
}
}
###jmal-cloud-vie vue.js 前端配置
server {
listen 80;
server_name localhost;
root /var/www/public;
client_max_body_size 1024m;
client_body_buffer_size 512k;
location / {
try_files $uri $uri/ /index.html;
index index.html index.htm;
}
location = /blog {
proxy_pass http://jmalcloud:8088/articles;
include /etc/nginx/conf/proxy_params.conf;
}
location = /blog/ {
proxy_pass http://jmalcloud:8088/articles;
include /etc/nginx/conf/proxy_params.conf;
}
location /blog/api/ {
proxy_pass http://jmalcloud:8088/;
include /etc/nginx/conf/proxy_params.conf;
}
location /blog/articles {
proxy_pass http://jmalcloud:8088/articles/;
include /etc/nginx/conf/proxy_params.conf;
}
location /blog/ {
proxy_pass http://jmalcloud:8088/articles/;
include /etc/nginx/conf/proxy_params.conf;
}
location /api/ {
proxy_pass http://jmalcloud:8088/;
proxy_set_header X-Forwarded-Host $the_host/file;
include /etc/nginx/conf/proxy_params.conf;
include /etc/nginx/conf/proxy_params_file.conf;
}
location /webDAV/ {
proxy_pass http://jmalcloud:8088/webDAV/;
proxy_set_header X-Forwarded-Host $the_host/file;
include /etc/nginx/conf/proxy_params.conf;
include /etc/nginx/conf/proxy_params_file.conf;
}
location /file/ {
proxy_pass http://jmalcloud:8088/file/;
proxy_set_header X-Forwarded-Host $the_host/file;
include /etc/nginx/conf/proxy_params.conf;
include /etc/nginx/conf/proxy_params_file.conf;
}
location /mq {
proxy_pass http://jmalcloud:8088/mq/;
#websocket额外配置开始
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_connect_timeout 60s;#l连接超时时间,不能设置太长会浪费连接资源
proxy_read_timeout 500s;#读超时时间
proxy_send_timeout 500s;#写超时时间
#websocket额外配置结束
}
location /drawio/webapp/ {
proxy_pass http://localhost:8080/;
proxy_set_header X-Forwarded-Host $the_host/drawio/webapp;
include /etc/nginx/conf/proxy_params.conf;
}
location /pdf.js/ {
proxy_pass http://localhost:8081/;
include /etc/nginx/conf/proxy_params.conf;
proxy_set_header X-Forwarded-Host $the_host//pdf.js;
}
location /excalidraw/app/ {
proxy_pass http://localhost:8082/excalidraw/app/;
include /etc/nginx/conf/proxy_params.conf;
proxy_set_header X-Forwarded-Host $the_host//excalidraw/app;
}
}
include servers/*;
include conf.d/*.conf;
}

View File

@ -0,0 +1,199 @@
# nginx.conf : /etc/nginx/nginx.conf
#user nobody;
worker_processes auto; # 自动根据 CPU 核心数设置
events {
worker_connections 2048;
multi_accept on;
}
#设定http服务器,利用它的反向代理功能提供负载均衡支持
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
include mime.types;
default_type application/octet-stream;
# 日志
#access_log /var/log/nginx/access.log main buffer=32k flush=5s;
access_log off;
error_log /var/log/nginx/error.log warn;
# 全局性能优化
sendfile on;
tcp_nopush on;
tcp_nodelay on;
server_names_hash_bucket_size 512;
keepalive_timeout 65;
keepalive_requests 1000;
# 全局上传/头部限制
client_header_buffer_size 32k;
client_max_body_size 50m; # 全局默认值
# 全局默认代理缓冲 (用于普通API)
proxy_buffer_size 16k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
# 默认启用 gzip
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 6;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/json;
gzip_vary on;
gzip_proxied any;
gzip_disable "MSIE [1-6]\.";
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
map $http_host $this_host {
"" $host;
default $http_host;
}
map $http_x_forwarded_proto $the_scheme {
default $http_x_forwarded_proto;
"" $scheme;
}
map $http_x_forwarded_host $the_host {
default $http_x_forwarded_host;
"" $this_host;
}
server {
listen 8089;
server_name localhost;
location = / {
proxy_pass http://jmalcloud:8088/articles;
include /etc/nginx/conf/proxy_params.conf;
}
location /api {
proxy_pass http://jmalcloud:8088;
include /etc/nginx/conf/proxy_params.conf;
}
location /articles/articles {
proxy_pass http://jmalcloud:8088/articles;
include /etc/nginx/conf/proxy_params.conf;
}
location /articles {
proxy_pass http://jmalcloud:8088/articles;
include /etc/nginx/conf/proxy_params.conf;
}
location / {
proxy_pass http://jmalcloud:8088/articles/;
include /etc/nginx/conf/proxy_params.conf;
}
}
###jmal-cloud-vie vue.js 前端配置
server {
listen 80;
server_name localhost;
root /var/www/public;
client_max_body_size 1024m;
client_body_buffer_size 512k;
location / {
try_files $uri $uri/ /index.html;
index index.html index.htm;
}
location = /blog {
proxy_pass http://jmalcloud:8088/articles;
include /etc/nginx/conf/proxy_params.conf;
}
location = /blog/ {
proxy_pass http://jmalcloud:8088/articles;
include /etc/nginx/conf/proxy_params.conf;
}
location /blog/api/ {
proxy_pass http://jmalcloud:8088/;
include /etc/nginx/conf/proxy_params.conf;
}
location /blog/articles {
proxy_pass http://jmalcloud:8088/articles/;
include /etc/nginx/conf/proxy_params.conf;
}
location /blog/ {
proxy_pass http://jmalcloud:8088/articles/;
include /etc/nginx/conf/proxy_params.conf;
}
location /api/ {
proxy_pass http://jmalcloud:8088/;
proxy_set_header X-Forwarded-Host $the_host/file;
include /etc/nginx/conf/proxy_params.conf;
include /etc/nginx/conf/proxy_params_file.conf;
}
location /webDAV/ {
proxy_pass http://jmalcloud:8088/webDAV/;
proxy_set_header X-Forwarded-Host $the_host/file;
include /etc/nginx/conf/proxy_params.conf;
include /etc/nginx/conf/proxy_params_file.conf;
}
location /file/ {
proxy_pass http://jmalcloud:8088/file/;
proxy_set_header X-Forwarded-Host $the_host/file;
include /etc/nginx/conf/proxy_params.conf;
include /etc/nginx/conf/proxy_params_file.conf;
}
location /mq {
proxy_pass http://jmalcloud:8088/mq/;
#websocket额外配置开始
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_connect_timeout 60s;#l连接超时时间,不能设置太长会浪费连接资源
proxy_read_timeout 500s;#读超时时间
proxy_send_timeout 500s;#写超时时间
#websocket额外配置结束
}
location /office {
proxy_pass http://office/;
include /etc/nginx/conf/proxy_params.conf;
proxy_set_header X-Forwarded-Host $the_host/office;
include /etc/nginx/conf/proxy_params_file.conf;
}
location /drawio/webapp/ {
proxy_pass http://localhost:8080/;
proxy_set_header X-Forwarded-Host $the_host//drawio/webapp;
include /etc/nginx/conf/proxy_params.conf;
}
location /pdf.js/ {
proxy_pass http://localhost:8081/;
include /etc/nginx/conf/proxy_params.conf;
proxy_set_header X-Forwarded-Host $the_host//pdf.js;
}
location /excalidraw/app/ {
proxy_pass http://localhost:8082/excalidraw/app/;
include /etc/nginx/conf/proxy_params.conf;
proxy_set_header X-Forwarded-Host $the_host//excalidraw/app;
}
}
include servers/*;
include conf.d/*.conf;
}

View File

@ -0,0 +1,16 @@
# /etc/nginx/conf/proxy_params.conf
# 通用代理头设置
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $the_scheme;
proxy_set_header X-Real-PORT $remote_port;
proxy_set_header Scheme $scheme;
proxy_set_header Server-Protocol $server_protocol;
proxy_set_header Server-Name $server_name;
proxy_set_header Server-Addr $server_addr;
proxy_set_header Server-Port $server_port;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;

View File

@ -0,0 +1,8 @@
# /etc/nginx/conf/proxy_params_file.conf
# 文件服务通用代理头设置
# 延长超时时间以支持慢速网络下的大文件下载 (这个依然有用且重要)
proxy_read_timeout 600s;
proxy_send_timeout 600s;
gzip off; # 禁用压缩,避免大文件开销
proxy_buffering off;

101
frontend/package.json Normal file
View File

@ -0,0 +1,101 @@
{
"name": "jmal-cloud-view",
"version": "2.15.0",
"description": "jmalcloud",
"author": "Jmal <zhushilun084@gmail.com>",
"license": "MIT",
"scripts": {
"dev": "vue-cli-service serve",
"build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview",
"lint": "eslint --ext .js,.vue src",
"test:unit": "jest --clearCache && vue-cli-service test:unit",
"test:ci": "npm run lint && npm run test:unit",
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml"
},
"dependencies": {
"@vue-office/docx": "1.6.2",
"@vue-office/excel": "1.7.11",
"@vue/composition-api": "1.7.2",
"ant-design-vue": "^1.6.5",
"clipboard": "^2.0.6",
"cropperjs": "^1.5.6",
"e-vue-contextmenu": "^0.1.3",
"flv.js": "^1.6.2",
"gsap": "^3.2.6",
"highlightjs-line-numbers.js": "^2.7.0",
"hls.js": "^1.4.0",
"htmlhint": "^0.13.0",
"jquery": "^3.5.0",
"jquery-contextmenu": "^2.9.1",
"jquery.fancytree": "^2.35.0",
"js-cookie": "2.2.0",
"jshint": "^2.11.1",
"less-loader": "^6.1.0",
"lib-flexible": "^0.3.2",
"lodash": "^4.17.21",
"moment": "^2.29.4",
"monaco-editor": "^0.23.0",
"monaco-editor-vue": "^1.0.10",
"monaco-editor-webpack-plugin": "^3.0.1",
"monaco-languages": "^2.3.0",
"mxcad": "^1.0.238",
"normalize.css": "7.0.0",
"nprogress": "0.2.0",
"path-to-regexp": "3.3.0",
"pinyin": "^2.9.1",
"qrcode": "^1.5.1",
"scriptjs": "^2.5.9",
"sockjs-client": "1.4.0",
"sortablejs": "^1.10.2",
"spark-md5": "^3.0.0",
"stompjs": "^2.3.3",
"tippy.js": "^6.3.7",
"v-viewer": "^1.5.1",
"vditor": "3.11.1",
"vue-aplayer": "^1.6.1",
"vue-color": "^2.8.1",
"vue-demi": "^0.14.6",
"vue-i18n": "^8.28.2",
"vue-runtime-helpers": "^1.1.2",
"vue-simple-uploader": "0.7.6",
"vuedraggable": "^2.23.2",
"vuex": "^3.1.0"
},
"devDependencies": {
"@babel/core": "7.0.0",
"@babel/register": "7.0.0",
"@vue/cli-plugin-babel": "3.6.0",
"@vue/cli-plugin-eslint": "^3.9.1",
"@vue/cli-plugin-unit-jest": "3.6.3",
"@vue/cli-service": "3.6.0",
"@vue/test-utils": "1.0.0-beta.29",
"autoprefixer": "^9.5.1",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "10.0.1",
"babel-jest": "23.6.0",
"babel-plugin-import": "^1.13.0",
"chalk": "2.4.2",
"connect": "3.6.6",
"eslint": "^5.15.3",
"html-webpack-plugin": "3.2.0",
"runjs": "^4.3.2",
"sass": "1.52.1",
"sass-loader": "7.3.1",
"script-ext-html-webpack-plugin": "2.1.3",
"script-loader": "0.7.2",
"serve-static": "^1.13.2",
"svg-sprite-loader": "4.1.3",
"svgo": "1.2.2",
"vue-kityminder-ggg": "^1.3.10",
"vue-template-compiler": "2.6.14"
},
"engines": {
"node": "^16, ^18"
},
"browserslist": [
"> 1%",
"last 2 versions"
]
}

View File

@ -0,0 +1,6 @@
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
'plugins': {
'autoprefixer': {}
}
}

View File

@ -0,0 +1,8 @@
module.exports = {
singleQuote: true,
semi: false,
trailingComma: 'es6',
tabWidth: 2,
printWidth: 80,
endOfLine: 'lf'
}

View File

@ -0,0 +1,4 @@
window._env_ = {
API_URL: "",
API_OFFICE_URL: "",
};

BIN
frontend/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,49 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<!--在 head 标签中添加 meta 标签,并设置 viewport-fit=cover 值-->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover">
<!--vue.js 开发环境版本,包含了有帮助的命令行警告-->
<!-- <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>-->
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="<%= htmlWebpackPlugin.options.path %>/resource/vue@2.6.14.js"></script>
<!--vue-roter.js-->
<script src="<%= htmlWebpackPlugin.options.path %>/resource/vue-router@3.0.6.js"></script>
<!--axios.js-->
<script src="<%= htmlWebpackPlugin.options.path %>/resource/axios@0.21.1.js"></script>
<!--vant.js-->
<link rel="stylesheet" href="<%= htmlWebpackPlugin.options.path %>/resource/vant@2.12.54.css"/>
<script src="<%= htmlWebpackPlugin.options.path %>/resource/vant@2.12.54.js"></script>
<!--element-ui.js-->
<link rel="stylesheet" href="<%= htmlWebpackPlugin.options.path %>/resource/element-ui@2.13.0.css">
<script src="<%= htmlWebpackPlugin.options.path %>/resource/element-ui@2.13.0.js"></script>
<!--pl-table.js-->
<!-- <link rel="stylesheet" href="https://unpkg.com/pl-table@2.7.5/themes/index.css">-->
<!-- <script src="https://unpkg.com/pl-table@2.7.5/lib/index.js"></script>-->
<link rel="stylesheet" href="<%= htmlWebpackPlugin.options.path %>/resource/pl-table@2.7.5/themes/index.css">
<script src="<%= htmlWebpackPlugin.options.path %>/resource/pl-table@2.7.5/lib/index.js"></script>
<!--viewer css-->
<link rel="stylesheet" href="<%= htmlWebpackPlugin.options.path %>/resource/viewerjs@1.7.1.css">
<!--vue-aplayer-theme-->
<script src="<%= htmlWebpackPlugin.options.path %>/resource/colorthief@2.0.2.js"></script>
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= webpackConfig.name %></title>
<link rel="stylesheet" href="<%= htmlWebpackPlugin.options.path %>/resource/font-awesome/free-6.4.2/css/all.min.css">
<script src="/config.js"></script>
<!-- <script type="module" src="<%= htmlWebpackPlugin.options.path %>/resource/model-viewer.min.js"></script>-->
</head>
<body>
<noscript>
<strong>We're sorry but <%= webpackConfig.name %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,282 @@
body {
margin: 0;
background: #fafafa;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
color: #333;
position: absolute;
height: 100%;
width: 100%;
min-height: 800px;
}
#title {
width: 900px;
min-height: 18px;
margin: 10px auto;
text-align: center;
font-size: 16px;
color: #E2E2E2;
font-weight: 400;
}
#title:hover {
color: #777;
}
#viewer.spreads {
width: 900px;
height: 600px;
box-shadow: 0 0 4px #ccc;
border-radius: 5px;
padding: 0;
position: relative;
margin: 10px auto;
background: white url('ajax-loader.gif') center center no-repeat;
top: calc(50vh - 400px);
}
#viewer.spreads .epub-view > iframe {
background: white;
}
#viewer.scrolled {
overflow: hidden;
width: 800px;
margin: 0 auto;
position: relative;
background: url('ajax-loader.gif') center center no-repeat;
box-shadow: 0 0 4px #ccc;
padding: 20px;
background: white;
}
#viewer.scrolled .epub-view > iframe {
background: white;
}
#prev {
left: 0;
}
#next {
right: 0;
}
#toc {
display: block;
margin: 10px auto;
}
@media (min-width: 1000px) {
#viewer.spreads:after {
position: absolute;
width: 1px;
border-right: 1px #000 solid;
height: 90%;
z-index: 1;
left: 50%;
margin-left: -1px;
top: 5%;
opacity: .15;
box-shadow: -2px 0 15px rgba(0, 0, 0, 1);
content: "";
}
#viewer.spreads.single:after {
display: none;
}
#prev {
left: 40px;
}
#next {
right: 40px;
}
}
.arrow {
position: fixed;
top: 50%;
margin-top: -32px;
font-size: 64px;
color: #E2E2E2;
font-family: arial, sans-serif;
font-weight: bold;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
text-decoration: none;
}
.navlink {
margin: 14px;
display: block;
text-align: center;
text-decoration: none;
color: #ccc;
}
.arrow:hover, .navlink:hover {
color: #777;
}
.arrow:active, .navlink:hover {
color: #000;
}
#book-wrapper {
width: 480px;
height: 640px;
overflow: hidden;
border: 1px solid #ccc;
margin: 28px auto;
background: #fff;
border-radius: 0 5px 5px 0;
position: absolute;
}
#book-viewer {
width: 480px;
height: 660px;
margin: -30px auto;
-moz-box-shadow: inset 10px 0 20px rgba(0,0,0,.1);
-webkit-box-shadow: inset 10px 0 20px rgba(0,0,0,.1);
box-shadow: inset 10px 0 20px rgba(0,0,0,.1);
}
#book-viewer iframe {
padding: 40px 40px;
}
#controls {
position: absolute;
bottom: 16px;
left: 50%;
width: 400px;
margin-left: -200px;
text-align: center;
display: none;
}
#controls > input[type=range] {
width: 400px;
}
#navigation {
width: 400px;
height: 100vh;
position: absolute;
overflow: auto;
top: 0;
left: 0;
background: #777;
-webkit-transition: -webkit-transform .25s ease-out;
-moz-transition: -moz-transform .25s ease-out;
-ms-transition: -moz-transform .25s ease-out;
transition: transform .25s ease-out;
}
#navigation.fixed {
position: fixed;
}
#navigation h1 {
width: 200px;
font-size: 16px;
font-weight: normal;
color: #fff;
margin-bottom: 10px;
}
#navigation h2 {
font-size: 14px;
font-weight: normal;
color: #B0B0B0;
margin-bottom: 20px;
}
#navigation ul {
padding-left: 36px;
margin-left: 0;
margin-top: 12px;
margin-bottom: 12px;
width: 340px;
}
#navigation ul li {
list-style: decimal;
margin-bottom: 10px;
color: #cccddd;
font-size: 12px;
padding-left: 0;
margin-left: 0;
}
#navigation ul li a {
color: #ccc;
text-decoration: none;
}
#navigation ul li a:hover {
color: #fff;
text-decoration: underline;
}
#navigation ul li a.active {
color: #fff;
}
#navigation #cover {
display: block;
margin: 24px auto;
}
#navigation #closer {
position: absolute;
top: 0;
right: 0;
padding: 12px;
color: #cccddd;
width: 24px;
}
#navigation.closed {
-webkit-transform: translate(-400px, 0);
-moz-transform: translate(-400px, 0);
-ms-transform: translate(-400px, 0);
transform: translate(-400px, 0);
}
svg {
display: block;
}
.close-x {
stroke: #cccddd;
fill: transparent;
stroke-linecap: round;
stroke-width: 5;
}
.close-x:hover {
stroke: #fff;
}
#opener {
position: absolute;
top: 0;
left: 0;
padding: 10px;
stroke: #E2E2E2;
fill: #E2E2E2;
}
#opener:hover {
stroke: #777;
fill: #777;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,167 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>EPUB.js Spreads Example</title>
<script src="./jszip@3.10.1.min.js"></script>
<script src="./epubjs@0.3.88.min.js"></script>
<link rel="stylesheet" type="text/css" href="./epub.css">
</head>
<body>
<!-- <div id="title"></div> -->
<select id="toc"></select>
<div id="viewer" class="spreads"></div>
<a id="prev" href="#prev" class="arrow">‹</a>
<a id="next" href="#next" class="arrow">›</a>
<script>
var params =
URLSearchParams &&
new URLSearchParams(document.location.search.substring(1))
var url =
params && params.get("url") && decodeURIComponent(params.get("url"))
var currentSectionIndex =
params && params.get("loc") ? params.get("loc") : undefined
let blob = fetch(url).then((res) => res.blob())
var book = ePub(
blob.then((blob) => blob.arrayBuffer()),
{
restore: true,
reload: true,
spreads: true,
}
)
var rendition = book.renderTo("viewer", {
width: "100%",
height: 600,
spread: "always",
})
rendition.display(currentSectionIndex);
book.ready.then(function() {
var next = document.getElementById("next");
next.addEventListener("click", function(e){
book.package.metadata.direction === "rtl" ? rendition.prev() : rendition.next();
e.preventDefault();
}, false);
var prev = document.getElementById("prev");
prev.addEventListener("click", function(e){
book.package.metadata.direction === "rtl" ? rendition.next() : rendition.prev();
e.preventDefault();
}, false);
var keyListener = function(e){
// Left Key
if ((e.keyCode || e.which) == 37) {
book.package.metadata.direction === "rtl" ? rendition.next() : rendition.prev();
}
// Right Key
if ((e.keyCode || e.which) == 39) {
book.package.metadata.direction === "rtl" ? rendition.prev() : rendition.next();
}
};
rendition.on("keyup", keyListener);
document.addEventListener("keyup", keyListener, false);
})
var title = document.getElementById("title");
rendition.on("rendered", function(section){
var current = book.navigation && book.navigation.get(section.href);
if (current) {
var $select = document.getElementById("toc");
var $selected = $select.querySelector("option[selected]");
if ($selected) {
$selected.removeAttribute("selected");
}
var $options = $select.querySelectorAll("option");
for (var i = 0; i < $options.length; ++i) {
let selected = $options[i].getAttribute("ref") === current.href;
if (selected) {
$options[i].setAttribute("selected", "");
}
}
}
});
rendition.on("relocated", function(location){
console.log(location);
var next = book.package.metadata.direction === "rtl" ? document.getElementById("prev") : document.getElementById("next");
var prev = book.package.metadata.direction === "rtl" ? document.getElementById("next") : document.getElementById("prev");
if (location.atEnd) {
next.style.visibility = "hidden";
} else {
next.style.visibility = "visible";
}
if (location.atStart) {
prev.style.visibility = "hidden";
} else {
prev.style.visibility = "visible";
}
});
rendition.on("layout", function(layout) {
let viewer = document.getElementById("viewer");
if (layout.spread) {
viewer.classList.remove('single');
} else {
viewer.classList.add('single');
}
});
window.addEventListener("unload", function () {
console.log("unloading");
this.book.destroy();
});
book.loaded.navigation.then(function(toc){
var $select = document.getElementById("toc"),
docfrag = document.createDocumentFragment();
toc.forEach(function(chapter) {
var option = document.createElement("option");
option.textContent = chapter.label;
option.setAttribute("ref", chapter.href);
docfrag.appendChild(option);
});
$select.appendChild(docfrag);
$select.onchange = function(){
var index = $select.selectedIndex,
url = $select.options[index].getAttribute("ref");
rendition.display(url);
return false;
};
});
</script>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

5
frontend/railway.yaml Normal file
View File

@ -0,0 +1,5 @@
deployment:
- name: jmal-cloud-view
type: docker
configVars:
- PORT: 80

25
frontend/src/App.vue Normal file
View File

@ -0,0 +1,25 @@
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
<script>
const pcList = ['/', '/s']
const mobileList = ['/_m', '/_m/']
export default {
name: 'App',
components: {},
watch: {
$route: function(to) {
const path = to.path
if (pcList.includes(path) && !this.$pc) {
this.$router.push({ path: path + '_m', query: to.query })
}
if (mobileList.includes(path) && this.$pc) {
this.$router.push({ path: path.split('_m')[0], query: to.query })
}
},
},
}
</script>

View File

@ -0,0 +1,58 @@
import request from '@/utils/request'
const qs = require('qs')
export default {
categories(params) {
return request({
url: 'category/list',
method: 'get',
params
})
},
categoryTree(params) {
return request({
url: 'category/tree',
method: 'get',
params
})
},
categoryInfo(params) {
return request({
url: 'category/info',
method: 'get',
params
})
},
add(data) {
return request({
url: 'category/add',
method: 'post',
data
})
},
update(data) {
return request({
url: 'category/update',
method: 'put',
data
})
},
setDefault(params) {
return request({
url: 'category/setDefault',
method: 'put',
params
})
},
delete(params) {
return request({
url: 'category/delete',
method: 'delete',
params,
paramsSerializer: function(params) {
return qs.stringify(params, { arrayFormat: 'repeat' })
}
})
}
}

View File

@ -0,0 +1,40 @@
import request from '@/utils/request'
export default {
/**
* 创建直链
* @param params
* @returns {*}
*/
createDirectLink: function(params) {
return request({
url: 'direct-link/create',
method: 'post',
params
})
},
/**
* 重置直链
* @param params
* @returns {*}
*/
resetDirectLink: function(params) {
return request({
url: 'direct-link/reset',
method: 'put',
params
})
},
/**
* 重置直链
* @param params
* @returns {*}
*/
resetAllDirectLink: function(params) {
return request({
url: 'direct-link/reset-all',
method: 'delete',
params
})
},
}

View File

@ -0,0 +1,483 @@
import request from "@/utils/request";
const qs = require("qs");
export default {
// 上传
simpleUploadURL: process.env.VUE_APP_BASE_API + '/upload',
// 上传头像
simpleUploadAvatarURL: process.env.VUE_APP_BASE_API + '/upload',
// 合并
mergeSimpleUpload: function(params) {
return request({
url: 'merge',
method: 'post',
params
})
},
// 检查文件是否存在
checkExist: function (data) {
return request({
url: "checkExist",
method: "post",
data
})
},
// 上传文件夹
uploadFolder: function(params) {
return request({
url: 'upload-folder',
method: 'post',
params,
paramsSerializer: function(params) {
return qs.stringify(params, { arrayFormat: 'repeat' })
}
})
},
// 新建文件夹
newFolder: function(params) {
return request({
url: 'new_folder',
method: 'post',
params
})
},
// 文件列表
fileList: function(params) {
return request({
url: 'list',
method: 'get',
params
})
},
// 收藏/取消收藏
favoriteUrl: function(params) {
const isFavorite = params.isFavorite
if (isFavorite) {
return request({
url: 'favorite',
method: 'post',
params,
paramsSerializer: function(params) {
return qs.stringify(params, { arrayFormat: 'repeat' })
}
})
} else {
return request({
url: 'unFavorite',
method: 'post',
params,
paramsSerializer: function(params) {
return qs.stringify(params, { arrayFormat: 'repeat' })
}
})
}
},
// 为文件分配标签
setTags: function(data) {
return request({
url: 'setTag',
method: 'post',
data
})
},
// 将文件设为公共文件
setPublic: function(params) {
return request({
url: 'setPublic',
method: 'put',
params
})
},
// 删除
delete: function(params) {
return request({
url: 'delete',
method: 'delete',
params,
paramsSerializer: function(params) {
return qs.stringify(params, { arrayFormat: 'repeat' })
}
})
},
// 返回原处
restore: function(params) {
return request({
url: 'restore',
method: 'post',
params,
paramsSerializer: function(params) {
return qs.stringify(params, { arrayFormat: 'repeat' })
}
})
},
// 彻底删除
sweep: function(params) {
return request({
url: 'sweep',
method: 'delete',
params,
paramsSerializer: function(params) {
return qs.stringify(params, { arrayFormat: 'repeat' })
}
})
},
// 清空回收站
clearTrash: function() {
return request({
url: 'clear-trash',
method: 'delete'
})
},
// 重名名
rename: function(params) {
return request({
url: 'rename',
method: 'get',
params
})
},
// 最近搜索记录🔍
getRecentlySearchHistory: function(params) {
return request({
url: '/search/recentlySearchHistory',
method: 'get',
params
})
},
// 删除搜索记录🔍
removeSearchHistory: function(params) {
return request({
url: '/search/deleteSearchHistory',
method: 'delete',
params
})
},
// 删除所有搜索记录🔍
removeAllSearchHistory: function(params) {
return request({
url: '/search/deleteAllSearchHistory',
method: 'delete',
params
})
},
// 搜索文件🔍
searchFile: function(params) {
return request({
url: 'search-file',
method: 'get',
params
})
},
// 搜索文件🔍-打开目录
searchFileAndOpenDir: function(params) {
return request({
url: 'search-file-open',
method: 'get',
params
})
},
// 查找下级目录
queryFileTree: function(params) {
return request({
url: 'query-file-tree',
method: 'get',
params
})
},
// 查找上级目录
upperLevelList: function(params) {
return request({
url: 'upper-level-list',
method: 'get',
params
})
},
// 查找下级目录
listfiles: function(params) {
return request({
url: 'listfiles',
method: 'get',
params
})
},
// 移动或复制前检查目标目录是否存在要移动或复制的文件
checkMoveOrCopy: function(params) {
return request({
url: 'check-move-copy',
method: 'get',
params,
paramsSerializer: function(params) {
return qs.stringify(params, { arrayFormat: 'repeat' })
}
})
},
// 移动文件/文件夹
move: function(params) {
return request({
url: 'move',
method: 'get',
params,
paramsSerializer: function(params) {
return qs.stringify(params, { arrayFormat: 'repeat' })
}
})
},
// 复制文件/文件夹
copy: function(params) {
return request({
url: 'copy',
method: 'get',
params,
paramsSerializer: function(params) {
return qs.stringify(params, { arrayFormat: 'repeat' })
}
})
},
/**
* 创建副本
* @param params
*/
duplicateFile(params) {
return request({
url: 'duplicate',
method: 'get',
params
})
},
// 生成分享链接
generate: function(data) {
return request({
url: 'share/generate',
method: 'post',
data: data
})
},
// 生成shareToken
generateShareToken: function(params) {
return request({
url: '/share/generate/share-token',
method: 'get',
params
})
},
// 检测分享文件下是否含有子分享
hasSubShare: function(params) {
return request({
url: '/share/has-sub-share',
method: 'get',
params,
paramsSerializer: function(params) {
return qs.stringify(params, { arrayFormat: 'repeat' })
}
})
},
// 检测文件下是否含有子分享
folderSubShare: function(params) {
return request({
url: '/share/folder-sub-share',
method: 'get',
params
})
},
// 取消分享
cancelShareLink: function(params) {
return request({
url: 'share/cancel',
method: 'delete',
params,
paramsSerializer: function(params) {
return qs.stringify(params, { arrayFormat: 'repeat' })
}
})
},
// 分享列表
sharelist: function(params) {
return request({
url: '/share/list',
method: 'get',
params
})
},
// 挂载文件夹
mountFolder: function(data) {
return request({
url: '/share/mount-folder',
method: 'put',
data: data
})
},
// 挂用户获取分享文件信息
getMountFileInfo: function(params) {
return request({
url: '/mount/file_info',
method: 'get',
params
})
},
// 挂用户获取目录Id
getMountFolderId: function(params) {
return request({
url: '/mount/folder/id',
method: 'get',
params
})
},
// 验证提取码
validShareCode: function(data) {
return request({
url: 'public/valid-share-code',
method: 'post',
data
})
},
// 访问分享链接
accessShare: function(params) {
return request({
url: 'public/access-share',
method: 'get',
params
})
},
// 获取分享者信息
getSharer: function(params) {
return request({
url: 'public/get/sharer',
method: 'get',
params
})
},
// 获取分享信息
getShareByFileId: function(params) {
return request({
url: '/get/share/by/fileId',
method: 'get',
params
})
},
// 访问分享链接里的文件夹
accessShareOpenDir: function(params) {
return request({
url: 'public/access-share/open',
method: 'get',
params
})
},
// 通过filepath预览文本文件
previewTextByPath: function(params) {
return request({
url: '/preview/path/text',
method: 'get',
params
})
},
// 预览文本文件
previewText: function(params) {
return request({
url: '/preview/text',
method: 'get',
params
})
},
// 访问分享的文本文件
sharePreviewText: function(params) {
return request({
url: '/public/s/preview/text',
method: 'get',
params
})
},
// 解压文件
unzip: function(params) {
return request({
url: '/unzip',
method: 'get',
params
})
},
// 根据path删除文件
delFile: function(params) {
return request({
url: 'delFile',
method: 'delete',
params,
paramsSerializer: function(params) {
return qs.stringify(params, { arrayFormat: 'repeat' })
}
})
},
// 根据path重命名文件
renameByPath: function(params) {
return request({
url: '/rename/path',
method: 'get',
params
})
},
// 根据path添加文件/文件夹
addFile: function(params) {
return request({
url: '/addfile',
method: 'post',
params
})
},
// 是否允许下载
isAllowDownload: function(params) {
return request({
url: '/isAllowDownload',
method: 'get',
params
})
},
// 是否允许批量下载
isAllowPackageDownload: function(params) {
return request({
url: '/isAllowPackageDownload',
method: 'get',
params
})
},
// 根据id获取文件信息
getFileInfoById: function(params) {
return request({
url: '/file_info',
method: 'get',
params
})
},
// 根据id获取文件信息
getPublicFileInfoById: function(params) {
return request({
url: '/public/file_info',
method: 'get',
params
})
},
// 获取office jwt
getOfficeJwt: function(data) {
return request({
url: '/office/signature',
method: 'post',
data
})
},
// 获取office jwt
getPublicOfficeJwt: function(params, data) {
return request({
url: '/public/office/signature',
method: 'post',
params,
data
})
},
// 获取office文件历史
getOfficeHistoryList: function(params) {
return request({
url: '/history/office/list',
method: 'get',
params,
})
},
}

View File

@ -0,0 +1,64 @@
import request from '@/utils/request'
export default {
/**
* 查询历史文件列表
* @param params
* @returns {*}
*/
fileHistoryList: function(params) {
return request({
url: '/history/list',
method: 'get',
params
})
},
/**
* 查询历史文件列表(根据path)
* @param params
* @returns {*}
*/
fileHistoryPathList: function(params) {
return request({
url: '/history/path/list',
method: 'get',
params
})
},
/**
* 预览某版本的历史文件
* @param params
* @returns {*}
*/
previewHistoryText: function(params) {
return request({
url: '/history/preview/text',
method: 'get',
params
})
},
/**
* 恢复该历史版本
* @param params
* @returns {*}
*/
recoveryHistory: function(params) {
return request({
url: '/history/recovery',
method: 'put',
params
})
},
/**
* 删除该历史版本
* @param params
* @returns {*}
*/
deleteHistory: function(params) {
return request({
url: '/history/delete',
method: 'delete',
params
})
},
}

19
frontend/src/api/log.js Normal file
View File

@ -0,0 +1,19 @@
import request from '@/utils/request'
export default {
logList(params) {
return request({
url: '/log/list',
method: 'get',
params
})
},
getFileOperationHistory(params) {
return request({
url: '/log/getFileOperationHistory',
method: 'get',
params
})
},
}

View File

@ -0,0 +1,61 @@
import request from '@/utils/request'
// const qs = require('qs')
export default {
// 获取markdown内容
getMarkdown: function(params) {
return request({
url: '/markdown/p',
method: 'get',
params
})
},
// 编辑文档 /markdown/edit
editMarkdown: function(data) {
return request({
url: '/markdown/edit',
method: 'post',
data
})
},
// 修改文档排序 /markdown/sort
sortMarkdown: function(data) {
return request({
url: '/markdown/sort',
method: 'post',
data
})
},
// 删除草稿 /markdown/deleteDraft
deleteDraft: function(params) {
return request({
url: '/markdown/deleteDraft',
method: 'delete',
params
})
},
// 编辑文档 /markdown/edit
editMarkdownByPath: function(data) {
return request({
url: '/markdown/edit1',
method: 'post',
data
})
},
// 上传url形式图片
uploadLinkImage: function(params) {
return request({
url: '/upload-markdown-link-image',
method: 'post',
data: params
})
},
// 上传blob格式的图片
uploadImage: function(data) {
return request({
url: '/upload-markdown-image',
method: 'post',
data: data
})
},
}

53
frontend/src/api/menu.js Normal file
View File

@ -0,0 +1,53 @@
import request from '@/utils/request'
const qs = require('qs')
export default {
menuTree(params) {
return request({
url: '/menu/tree',
method: 'get',
params
})
},
// 权限标识列表
authorityList(params) {
return request({
url: '/menu/authorities',
method: 'get',
params
})
},
// 菜单信息
menuInfo(params) {
return request({
url: '/menu/info',
method: 'get',
params
})
},
add(data) {
return request({
url: '/menu/add',
method: 'post',
data
})
},
update(data) {
return request({
url: 'menu/update',
method: 'put',
data
})
},
delete(params) {
return request({
url: '/menu/delete',
method: 'delete',
params,
paramsSerializer: function(params) {
return qs.stringify(params, { arrayFormat: 'repeat' })
}
})
}
}

48
frontend/src/api/oss.js Normal file
View File

@ -0,0 +1,48 @@
import request from '@/utils/request'
const qs = require('qs')
export default {
/**
* 获取OSS平台列表
*/
getPlatformList: function(params) {
return request({
url: '/oss/getPlatformList',
method: 'get',
params
})
},
/**
* OSS配置列表
*/
ossConfigList: function(params) {
return request({
url: '/oss/ossConfigList',
method: 'get',
params
})
},
/**
* 新增/修改OSS配置
*/
putOssConfig: function(data) {
return request({
url: '/oss/putOssConfig',
method: 'put',
data
})
},
/**
* 删除OSS配置
*/
deleteOssConfig: function(params) {
return request({
url: '/oss/deleteOssConfig',
method: 'delete',
params,
paramsSerializer: function(params) {
return qs.stringify(params, { arrayFormat: 'repeat' })
}
})
},
}

37
frontend/src/api/role.js Normal file
View File

@ -0,0 +1,37 @@
import request from '@/utils/request'
const qs = require('qs')
export default {
roleList(params) {
return request({
url: '/role/list',
method: 'get',
params
})
},
add(data) {
return request({
url: '/role/add',
method: 'post',
data
})
},
update(data) {
return request({
url: 'role/update',
method: 'put',
data
})
},
delete(params) {
return request({
url: '/role/delete',
method: 'delete',
params,
paramsSerializer: function(params) {
return qs.stringify(params, { arrayFormat: 'repeat' })
}
})
}
}

View File

@ -0,0 +1,220 @@
import request from '@/utils/request'
export default {
setupMfaConfig() {
return request({
url: '/mfa/setup',
method: 'post'
})
},
enableMfaConfig(data) {
return request({
url: '/mfa/enable',
method: 'post',
data
})
},
disableMfaConfig(data) {
return request({
url: '/mfa/disable',
method: 'post',
data
})
},
getPreviewConfig(params) {
return request({
url: '/cloud/setting/preview/config',
method: 'get',
params
})
},
updatePreviewConfig(data) {
return request({
url: '/cloud/setting/preview/config',
method: 'put',
data
})
},
getOcrConfig(params) {
return request({
url: '/cloud/setting/ocr/config',
method: 'get',
params
})
},
setOcrConfig(data) {
return request({
url: '/cloud/setting/ocr/config',
method: 'put',
data
})
},
getTranscodeConfig(params) {
return request({
url: '/cloud/setting/transcode/config',
method: 'get',
params
})
},
setTranscodeConfig(data) {
return request({
url: '/cloud/setting/transcode/config',
method: 'put',
data
})
},
cancelTranscodeTask(data) {
return request({
url: '/cloud/setting/transcode/cancel-task',
method: 'put',
data
})
},
syncUser(params) {
return request({
url: '/user/setting/sync',
method: 'get',
params
})
},
syncCloud(params) {
return request({
url: '/cloud/setting/sync',
method: 'get',
params
})
},
recalculateFolderSize(params) {
return request({
url: '/cloud/setting/recalculateFolderSize',
method: 'get',
params
})
},
isSync(params) {
return request({
url: '/user/setting/isSync',
method: 'get',
params
})
},
updateNetdiskName(params) {
return request({
url: '/user/setting/update_netdisk_name',
method: 'put',
params
})
},
getWebp(params) {
return request({
url: '/user/setting/get/webp',
method: 'get',
params
})
},
disabledWebp(params) {
return request({
url: '/user/setting/disabled/webp',
method: 'put',
params
})
},
getAccessTokenList(params) {
return request({
url: '/user/setting/accessTokenList',
method: 'get',
params
})
},
generateAccessToken(params) {
return request({
url: '/user/setting/generateAccessToken',
method: 'put',
params
})
},
deleteAccessToken(params) {
return request({
url: '/user/setting/deleteAccessToken',
method: 'delete',
params
})
},
resetMenuAndRole() {
return request({
url: '/user/setting/resetMenuAndRole',
method: 'put',
})
},
// 获取office配置
getPublicOfficeConfig: function(params) {
return request({
url: 'public/office/config',
method: 'get',
params
})
},
// 获取office配置
getOfficeConfig: function() {
return request({
url: '/office/config',
method: 'get'
})
},
// 更新office配置
updateOfficeConfig: function(data) {
return request({
url: '/office/config',
method: 'put',
data
})
}
}
export function getWebstieRecord(params) {
return request({
url: '/public/website/record',
method: 'get',
params
})
}
export function getSetting(params) {
return request({
url: '/website/setting',
method: 'get',
params
})
}
export function updateSetting(data) {
return request({
url: '/website/setting/update',
method: 'put',
data
})
}
export function getHeartwings(params) {
return request({
url: '/website/heartwings',
method: 'get',
params
})
}
export function getTaskProgress(params) {
return request({
url: '/cloud/task/progress',
method: 'get',
params
})
}
export function getTranscodeStatus(params) {
return request({
url: '/cloud/transcode/status',
method: 'get',
params
})
}

View File

@ -0,0 +1,9 @@
import request from '@/utils/request'
export function getList(params) {
return request({
url: '/vue-admin-template/table/list',
method: 'get',
params
})
}

66
frontend/src/api/tag.js Normal file
View File

@ -0,0 +1,66 @@
import request from '@/utils/request'
const qs = require('qs')
export default {
tagList(params) {
return request({
url: 'tag/list',
method: 'get',
params
})
},
tagInfo(params) {
return request({
url: 'tag/info',
method: 'get',
params
})
},
add(data) {
return request({
url: 'tag/add',
method: 'post',
data
})
},
update(data) {
return request({
url: 'tag/update',
method: 'put',
data
})
},
delete(params) {
return request({
url: 'tag/delete',
method: 'delete',
params,
paramsSerializer: function(params) {
return qs.stringify(params, { arrayFormat: 'repeat' })
}
})
},
// 修改标签排序
setTagSort: function(data) {
return request({
url: '/tag/sort',
method: 'post',
data
})
},
deleteFileTag: function(params) {
return request({
url: '/deleteTag',
method: 'delete',
params
})
},
updateFileTag: function(params) {
return request({
url: '/updateTag',
method: 'put',
params
})
}
}

154
frontend/src/api/user.js Normal file
View File

@ -0,0 +1,154 @@
import request from '@/utils/request'
const qs = require('qs')
export function login(data) {
return request({
url: 'login',
method: 'post',
data
})
}
export function verifyTotp(data) {
return request({
url: 'public/verify-totp',
method: 'post',
data
})
}
/**
* 加载ldap配置
* @returns {*}
*/
export function loadLdapConfig() {
return request({
url: 'ldap/config',
method: 'get'
})
}
/**
* 更新ldap配置
* @param data
* @returns {*}
*/
export function updateLdapConfig(data) {
return request({
url: 'ldap/config',
method: 'put',
data
})
}
/**
* 测试ldap配置
* @param data
* @returns {*}
*/
export function testLdapConfig(data) {
return request({
url: 'ldap/test-config',
method: 'put',
data
})
}
export function getInfo(params) {
return request({
url: 'user/info',
method: 'get',
params
})
}
export function getUserInfo(params) {
return request({
url: 'user/userInfo',
method: 'get',
params
})
}
export function userList(params) {
return request({
url: 'user/userList',
method: 'get',
params
})
}
export function logout() {
return request({
url: 'logout',
method: 'get'
})
}
export function userUpdate(data) {
return request({
url: 'user/update',
method: 'put',
data
})
}
export function addUser(data) {
return request({
url: 'user/add',
method: 'post',
data
})
}
export function validOldPass(data) {
return request({
url: 'valid-old-pass',
method: 'post',
data
})
}
export function updatePass(data) {
return request({
url: 'user/update-pass',
method: 'put',
data
})
}
export function resetPass(id) {
return request({
url: 'user/reset-pass',
method: 'put',
params: {id}
})
}
export function delUser(params) {
return request({
url: 'user/delete',
method: 'delete',
params,
paramsSerializer: function(params) {
return qs.stringify(params, { arrayFormat: 'repeat' })
}
})
}
export function hasUser() {
return request({
url: 'public/has_user',
method: 'get',
})
}
export function initialization(data) {
return request({
url: '/public/initialization',
method: 'post',
data
})
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -0,0 +1,304 @@
/*/
* Cropper.js v1.5.6
* https://fengyuanchen.github.io/cropperjs
*
* Copyright 2015-present Chen Fengyuan
* Released under the MIT license
*
* Date: 2019-10-04T04:33:44.164Z
*/
.cropper-container {
direction: ltr;
font-size: 0;
line-height: 0;
position: relative;
-ms-touch-action: none;
touch-action: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.cropper-container img {
display: block;
height: 100%;
image-orientation: 0deg;
max-height: none !important;
max-width: none !important;
min-height: 0 !important;
min-width: 0 !important;
width: 100%;
}
.cropper-wrap-box,
.cropper-canvas,
.cropper-drag-box,
.cropper-crop-box,
.cropper-modal {
bottom: 0;
left: 0;
position: absolute;
right: 0;
top: 0;
}
.cropper-wrap-box,
.cropper-canvas {
overflow: hidden;
}
.cropper-drag-box {
background-color: #fff;
opacity: 0;
}
.cropper-modal {
background-color: #000;
opacity: 0.5;
}
.cropper-view-box {
display: block;
height: 100%;
outline: 1px solid #39f;
outline-color: rgba(51, 153, 255, 0.75);
overflow: hidden;
width: 100%;
}
.cropper-dashed {
border: 0 dashed #eee;
display: block;
opacity: 0.5;
position: absolute;
}
.cropper-dashed.dashed-h {
border-bottom-width: 1px;
border-top-width: 1px;
height: calc(100% / 3);
left: 0;
top: calc(100% / 3);
width: 100%;
}
.cropper-dashed.dashed-v {
border-left-width: 1px;
border-right-width: 1px;
height: 100%;
left: calc(100% / 3);
top: 0;
width: calc(100% / 3);
}
.cropper-center {
display: block;
height: 0;
left: 50%;
opacity: 0.75;
position: absolute;
top: 50%;
width: 0;
}
.cropper-center::before,
.cropper-center::after {
background-color: #eee;
content: ' ';
display: block;
position: absolute;
}
.cropper-center::before {
height: 1px;
left: -3px;
top: 0;
width: 7px;
}
.cropper-center::after {
height: 7px;
left: 0;
top: -3px;
width: 1px;
}
.cropper-face,
.cropper-line,
.cropper-point {
display: block;
height: 100%;
opacity: 0.1;
position: absolute;
width: 100%;
}
.cropper-face {
background-color: #fff;
left: 0;
top: 0;
}
.cropper-line {
background-color: #39f;
}
.cropper-line.line-e {
cursor: ew-resize;
right: -3px;
top: 0;
width: 5px;
}
.cropper-line.line-n {
cursor: ns-resize;
height: 5px;
left: 0;
top: -3px;
}
.cropper-line.line-w {
cursor: ew-resize;
left: -3px;
top: 0;
width: 5px;
}
.cropper-line.line-s {
bottom: -3px;
cursor: ns-resize;
height: 5px;
left: 0;
}
.cropper-point {
background-color: #39f;
height: 5px;
opacity: 0.75;
width: 5px;
}
.cropper-point.point-e {
cursor: ew-resize;
margin-top: -3px;
right: -3px;
top: 50%;
}
.cropper-point.point-n {
cursor: ns-resize;
left: 50%;
margin-left: -3px;
top: -3px;
}
.cropper-point.point-w {
cursor: ew-resize;
left: -3px;
margin-top: -3px;
top: 50%;
}
.cropper-point.point-s {
bottom: -3px;
cursor: s-resize;
left: 50%;
margin-left: -3px;
}
.cropper-point.point-ne {
cursor: nesw-resize;
right: -3px;
top: -3px;
}
.cropper-point.point-nw {
cursor: nwse-resize;
left: -3px;
top: -3px;
}
.cropper-point.point-sw {
bottom: -3px;
cursor: nesw-resize;
left: -3px;
}
.cropper-point.point-se {
bottom: -3px;
cursor: nwse-resize;
height: 20px;
opacity: 1;
right: -3px;
width: 20px;
}
@media (min-width: 768px) {
.cropper-point.point-se {
height: 15px;
width: 15px;
}
}
@media (min-width: 992px) {
.cropper-point.point-se {
height: 10px;
width: 10px;
}
}
@media (min-width: 1200px) {
.cropper-point.point-se {
height: 5px;
opacity: 0.75;
width: 5px;
}
}
.cropper-point.point-se::before {
background-color: #39f;
bottom: -50%;
content: ' ';
display: block;
height: 200%;
opacity: 0;
position: absolute;
right: -50%;
width: 200%;
}
.cropper-invisible {
opacity: 0;
}
.cropper-bg {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC');
}
.cropper-hide {
display: block;
height: 0;
position: absolute;
width: 0;
}
.cropper-hidden {
display: none !important;
}
.cropper-move {
cursor: move;
}
.cropper-crop {
cursor: crosshair;
}
.cropper-disabled .cropper-drag-box,
.cropper-disabled .cropper-face,
.cropper-disabled .cropper-line,
.cropper-disabled .cropper-point {
cursor: not-allowed;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 920 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

View File

@ -0,0 +1,11 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1684983182221" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5240"
xmlns:xlink="http://www.w3.org/1999/xlink">
<path
d="M748.896 624.16l-221.44-137.888 0-223.648c0-14.624-11.84-26.496-26.496-26.496s-26.496 11.84-26.496 26.496l0 238.336c0 9.152 4.736 17.664 12.48 22.464l233.92 145.664c4.352 2.688 9.184 4 13.984 4 8.832 0 17.472-4.416 22.496-12.48 7.744-12.416 3.936-28.768-8.48-36.48z"
fill="#ffffff" p-id="5241"></path>
<path
d="M512 0c-282.336 0-512 229.664-512 512s229.664 512 512 512c282.304 0 512-229.696 512-512s-229.696-512-512-512zM512 971.04c-253.12 0-459.04-205.92-459.04-459.04s205.92-459.04 459.04-459.04c253.12 0 459.04 205.92 459.04 459.04s-205.92 459.04-459.04 459.04z"
fill="#ffffff" p-id="5242"></path>
</svg>

After

Width:  |  Height:  |  Size: 945 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 740 B

Some files were not shown because too many files have changed in this diff Show More