feat: 大屏

This commit is contained in:
ygx
2025-12-20 17:39:32 +08:00
commit 593e7d90e5
1005 changed files with 93645 additions and 0 deletions

3
.commitlintrc.js Normal file
View File

@@ -0,0 +1,3 @@
module.exports = {
extends: ["@commitlint/config-conventional"]
};

8
.env Normal file
View File

@@ -0,0 +1,8 @@
# port
VITE_DEV_PORT = '8080'
# development path
VITE_DEV_PATH = 'https://ops.apinb.com'
# production path
VITE_PRO_PATH = 'https://ops.apinb.com'

11
.eslintignore Normal file
View File

@@ -0,0 +1,11 @@
node_modules/
public/
es/
lib/
dist/
package.json
src/assets/
plop-templates/
handlebars/
website/
build/

30
.eslintrc.js Normal file
View File

@@ -0,0 +1,30 @@
module.exports = {
root: true,
parser: 'vue-eslint-parser',
globals: {
postMessage: true
},
parserOptions: {
parser: '@typescript-eslint/parser',
sourceType: 'module',
ecmaFeatures: {
jsx: true,
tsx: true
}
},
env: {
node: true,
// The Follow config only works with eslint-plugin-vue v8.0.0+
'vue/setup-compiler-macros': true
},
extends: ['plugin:vue/vue3-essential', 'eslint:recommended'],
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-unused-vars': 'off',
'vue/no-unused-vars': 'off',
'vue/multi-word-component-names': 'off',
'vue/valid-template-root': 'off',
'vue/no-mutating-props': 'off'
}
}

8
.gitignore vendored Normal file
View File

@@ -0,0 +1,8 @@
node_modules
.DS_Store
dist
dist-ssr
*.local
.vscode
.idea
pnpm-lock

4
.husky/commit-msg Normal file
View File

@@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no-install commitlint -e

View File

@@ -0,0 +1,3 @@
{
"type": "module"
}

View File

@@ -0,0 +1,51 @@
version: '1.0'
name: branch-pipeline
displayName: BranchPipeline
stages:
- stage:
name: compile
displayName: 编译
steps:
- step: build@nodejs
name: build_nodejs
displayName: Nodejs 构建
# 支持8.16.2、10.17.0、12.16.1、14.16.0、15.12.0五个版本
nodeVersion: 14.16.0
# 构建命令:安装依赖 -> 清除上次打包产物残留 -> 执行构建 【请根据项目实际产出进行填写】
commands:
- npm install && rm -rf ./dist && npm run build
# 非必填字段开启后表示将构建产物暂存但不会上传到制品库中7天后自动清除
artifacts:
# 构建产物名字作为产物的唯一标识可向下传递支持自定义默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址
- name: BUILD_ARTIFACT
# 构建产物获取路径,是指代码编译完毕之后构建物的所在路径
path:
- ./dist
- step: publish@general_artifacts
name: publish_general_artifacts
displayName: 上传制品
# 上游构建任务定义的产物名默认BUILD_ARTIFACT
dependArtifact: BUILD_ARTIFACT
# 上传到制品库时的制品命名默认output
artifactName: output
dependsOn: build_nodejs
- stage:
name: release
displayName: 发布
steps:
- step: publish@release_artifacts
name: publish_release_artifacts
displayName: '发布'
# 上游上传制品任务的产出
dependArtifact: output
# 发布制品版本号
version: '1.0.0.0'
# 是否开启版本号自增,默认开启
autoIncrement: true
triggers:
push:
branches:
exclude:
- master
include:
- .*

View File

@@ -0,0 +1,49 @@
version: '1.0'
name: master-pipeline
displayName: MasterPipeline
stages:
- stage:
name: compile
displayName: 编译
steps:
- step: build@nodejs
name: build_nodejs
displayName: Nodejs 构建
# 支持8.16.2、10.17.0、12.16.1、14.16.0、15.12.0五个版本
nodeVersion: 14.16.0
# 构建命令:安装依赖 -> 清除上次打包产物残留 -> 执行构建 【请根据项目实际产出进行填写】
commands:
- npm install && rm -rf ./dist && npm run build
# 非必填字段开启后表示将构建产物暂存但不会上传到制品库中7天后自动清除
artifacts:
# 构建产物名字作为产物的唯一标识可向下传递支持自定义默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址
- name: BUILD_ARTIFACT
# 构建产物获取路径,是指代码编译完毕之后构建物的所在路径
path:
- ./dist
- step: publish@general_artifacts
name: publish_general_artifacts
displayName: 上传制品
# 上游构建任务定义的产物名默认BUILD_ARTIFACT
dependArtifact: BUILD_ARTIFACT
# 上传到制品库时的制品命名默认output
artifactName: output
dependsOn: build_nodejs
- stage:
name: release
displayName: 发布
steps:
- step: publish@release_artifacts
name: publish_release_artifacts
displayName: '发布'
# 上游上传制品任务的产出
dependArtifact: output
# 发布制品版本号
version: '1.0.0.0'
# 是否开启版本号自增,默认开启
autoIncrement: true
triggers:
push:
branches:
include:
- master

36
.workflow/pr-pipeline.yml Normal file
View File

@@ -0,0 +1,36 @@
version: '1.0'
name: pr-pipeline
displayName: PRPipeline
stages:
- stage:
name: compile
displayName: 编译
steps:
- step: build@nodejs
name: build_nodejs
displayName: Nodejs 构建
# 支持8.16.2、10.17.0、12.16.1、14.16.0、15.12.0五个版本
nodeVersion: 14.16.0
# 构建命令:安装依赖 -> 清除上次打包产物残留 -> 执行构建 【请根据项目实际产出进行填写】
commands:
- npm install && rm -rf ./dist && npm run build
# 非必填字段开启后表示将构建产物暂存但不会上传到制品库中7天后自动清除
artifacts:
# 构建产物名字作为产物的唯一标识可向下传递支持自定义默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址
- name: BUILD_ARTIFACT
# 构建产物获取路径,是指代码编译完毕之后构建物的所在路径
path:
- ./dist
- step: publish@general_artifacts
name: publish_general_artifacts
displayName: 上传制品
# 上游构建任务定义的产物名默认BUILD_ARTIFACT
dependArtifact: BUILD_ARTIFACT
# 上传到制品库时的制品命名默认output
artifactName: output
dependsOn: build_nodejs
triggers:
pr:
branches:
include:
- master

178
IFRAME_MODE.md Normal file
View File

@@ -0,0 +1,178 @@
# GoView iframe 嵌入模式使用说明
## 概述
GoView 已支持通过 iframe 嵌入到其他系统中运行,无需独立的登录流程。系统会自动从 URL 参数中读取 token 进行身份验证。
**默认跳转**:系统启动后会直接跳转到项目列表页面 (`/project/items`),跳过登录步骤。
## 使用方法
### 1. 基本用法
在 iframe 的 src 中添加 `token` 参数:
```html
<!-- 默认跳转到项目列表 -->
<iframe
src="http://your-goview-domain/#/?token=YOUR_TOKEN_HERE"
width="100%"
height="100%"
></iframe>
<!-- 或直接指定项目列表路径 -->
<iframe
src="http://your-goview-domain/#/project/items?token=YOUR_TOKEN_HERE"
width="100%"
height="100%"
></iframe>
```
### 2. URL 参数说明
- `token` (必需): 用户身份认证令牌
**示例:**
```
# 默认路径,自动跳转到项目列表
http://localhost:3000/#/?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
# 或明确指定项目列表路径
http://localhost:3000/#/project/items?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
### 3. 支持的页面路由
您可以直接跳转到任何页面,只需在 URL 中添加 token 参数:
- **项目列表**(默认): `/#/?token=YOUR_TOKEN``/#/project/items?token=YOUR_TOKEN`
- 项目首页: `/#/project?token=YOUR_TOKEN`
- 图表编辑: `/#/chart/home/PROJECT_ID?token=YOUR_TOKEN`
- 图表预览: `/#/chart/preview/PROJECT_ID?token=YOUR_TOKEN`
## 技术实现
### 修改内容
1. **路由守卫** (`src/router/router-guards.ts`)
- 自动从 URL 提取 token 并保存到本地存储
- **完全移除登录验证**:不再检查登录状态
- **允许所有路由直接访问**:无需登录即可访问任何页面
2. **路由配置** (`src/router/index.ts`)
- 默认路由修改为 `/project/items`(项目列表)
- 跳过登录页面
3. **Axios 拦截器** (`src/api/axios.ts`)
- 请求拦截器:移除重定向到登录页的逻辑
- 响应拦截器token 过期时不再跳转登录页
- 所有请求自动携带 token
4. **应用初始化** (`src/main.ts`)
- 应用启动时自动读取 URL 中的 token
- 初始化用户信息到 store
### Token 存储
Token 会被自动存储到以下位置:
- **localStorage**: 持久化存储,刷新页面后仍然有效
- **Pinia Store**: 应用运行时状态管理
## 注意事项
### 1. Token 刷新
如果 token 发生变化,需要更新 iframe 的 src
```javascript
// 更新 token
const newToken = 'NEW_TOKEN_HERE'
iframe.src = `http://your-goview-domain/#/?token=${newToken}`
```
### 2. Token 过期处理
当 token 过期时:
- 系统会在控制台输出警告信息
- 用户会看到"登录过期"的提示
- 不会自动跳转到登录页
- 需要父系统更新 iframe 的 token 参数
### 3. 安全建议
- 确保 token 通过 HTTPS 传输
- token 应该设置合理的过期时间
- 考虑使用短期 token + 刷新 token 机制
### 4. 跨域问题
如果 GoView 和父系统不在同一域名下,需要:
- 配置 CORS 允许跨域请求
- 确保 API 服务器允许来自父系统域名的请求
## 控制台日志
系统会输出以下日志帮助调试:
-`[GoView] iframe 模式:已从 URL 参数中获取 token 并初始化`
- ⚠️ `[GoView] iframe 模式:未在 URL 中检测到 token 参数`
- ⚠️ `[GoView] iframe 模式:未找到身份信息,请确保 URL 中包含 token 参数`
-`[GoView] iframe 模式token 已过期,请更新 URL 中的 token 参数`
## 示例代码
### 父系统嵌入示例
```html
<!DOCTYPE html>
<html>
<head>
<title>GoView 嵌入示例</title>
</head>
<body>
<div id="goview-container">
<iframe
id="goview-iframe"
src=""
width="100%"
height="800px"
frameborder="0"
></iframe>
</div>
<script>
// 从您的认证系统获取 token
const token = 'YOUR_USER_TOKEN'
// 设置 iframe src默认跳转到项目列表
const iframe = document.getElementById('goview-iframe')
iframe.src = `http://localhost:3000/#/?token=${token}`
// 如果需要更新 token
function updateToken(newToken) {
iframe.src = `http://localhost:3000/#/?token=${newToken}`
}
</script>
</body>
</html>
```
## 兼容性说明
- ✅ 保留了原有的登录功能(如果不通过 URL 传递 token仍可使用登录页面
- ✅ iframe 模式和独立部署模式可以共存
- ✅ 所有原有功能均不受影响
## 回退到登录模式
如果需要回退到原有的登录模式,只需:
1. 访问不带 token 参数的 URL
2. 系统会提示警告但允许继续访问
3. 或者恢复之前的代码版本
## 技术支持
如有问题,请查看:
1. 浏览器控制台日志
2. 网络请求中的 token 是否正确携带
3. API 响应是否返回 token 过期错误

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-present GoView
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.

25
Makefile Normal file
View File

@@ -0,0 +1,25 @@
.PHONY: dist test
default: help
dev:
npm run dev
dist:
npm run build
view:
npm run preview
lint:
npm run lint
new:
npm run new
help:
@echo " make dev [npm run dev] 开发模式"
@echo " make dist [npm run build] 编译模式"
@echo " make view [npm run preview] 预览打包文件"
@echo " make new [npm run lint] 通过自动化流程创建代码"
@echo " make lint [npm run new] 格式校验"

119
README.md Normal file
View File

@@ -0,0 +1,119 @@
## 总览
**`master-fetch` 分支是带有后端接口请求的分支**
**后端项目地址:[https://gitee.com/MTrun/go-view-serve](https://gitee.com/MTrun/go-view-serve)**
**接口说明地址:[https://docs.apipost.cn/preview/5aa85d10a59d66ce/ddb813732007ad2b?target_id=84dbc5b0-158f-4bcb-8f74-793ac604ada3#3e053622-1e76-43f9-a039-756aee822dbb](https://docs.apipost.cn/preview/5aa85d10a59d66ce/ddb813732007ad2b?target_id=84dbc5b0-158f-4bcb-8f74-793ac604ada3#3e053622-1e76-43f9-a039-756aee822dbb)**
## 使用
所有的接口地址位置:`src\api\path\*`
接口地址修改:`.env`
```shell
# port
VITE_DEV_PORT = '8080'
# development path
VITE_DEV_PATH = 'http://127.0.0.1:8080'
# production path
VITE_PRO_PATH = 'http://127.0.0.1:8080'
```
公共前缀修改:`src\settings\httpSetting.ts`
```shell
// 请求前缀
export const axiosPre = '/api/goview'
```
接口封装:`src\api\http.ts`
```ts
import axiosInstance from './axios'
import { RequestHttpEnum, ContentTypeEnum } from '@/enums/httpEnum'
export const get = (url: string, params?: object) => {
return axiosInstance({
url: url,
method: RequestHttpEnum.GET,
params: params,
})
}
export const post = (url: string, data?: object, headersType?: string) => {
return axiosInstance({
url: url,
method: RequestHttpEnum.POST,
data: data,
headers: {
'Content-Type': headersType || ContentTypeEnum.JSON
}
})
}
export const put = (url: string, data?: object, headersType?: string) => {
return axiosInstance({
url: url,
method: RequestHttpEnum.PUT,
data: data,
headers: {
'Content-Type': headersType || ContentTypeEnum.JSON
}
})
}
export const del = (url: string, params?: object) => {
return axiosInstance({
url: url,
method: RequestHttpEnum.DELETE,
params
})
}
// 获取请求函数默认get
export const http = (type?: RequestHttpEnum) => {
switch (type) {
case RequestHttpEnum.GET:
return get
case RequestHttpEnum.POST:
return post
case RequestHttpEnum.PUT:
return put
case RequestHttpEnum.DELETE:
return del
default:
return get
}
}
```
## 代码提交
* feat: 新功能
* fix: 修复 Bug
* docs: 文档修改
* perf: 性能优化
* revert: 版本回退
* ci: CICD集成相关
* test: 添加测试代码
* refactor: 代码重构
* build: 影响项目构建或依赖修改
* style: 不影响程序逻辑的代码修改
* chore: 不属于以上类型的其他类型(日常事务)
## 交流
QQ 群1030129384
![QQ群](readme/go-view-qq.png)
![渲染海报](readme/logo-poster.png)

41
build/constant.ts Normal file
View File

@@ -0,0 +1,41 @@
import path from 'path'
export const OUTPUT_DIR = 'dist'
// monaco-editor 路径
export const prefix = `monaco-editor/esm/vs`
// chunk 警告大小
export const chunkSizeWarningLimit = 2000
// 禁用 brotliSize 压缩大小报告
export const brotliSize = false
// 分包
export const rollupOptions = {
output: {
chunkFileNames: 'static/js/[name]-[hash].js',
entryFileNames: 'static/js/[name]-[hash].js',
assetFileNames: (chunkInfo) => {
if(['.png', '.jpg', '.jpeg'].includes(path.extname(chunkInfo.name))) {
return `static/[ext]/[name].[ext]`
}
return `static/[ext]/[name]-[hash].[ext]`
},
manualChunks: {
jsonWorker: [`${prefix}/language/json/json.worker`],
cssWorker: [`${prefix}/language/css/css.worker`],
htmlWorker: [`${prefix}/language/html/html.worker`],
tsWorker: [`${prefix}/language/typescript/ts.worker`],
editorWorker: [`${prefix}/editor/editor.worker`]
}
}
}
// 去除开发代码
export const terserOptions = {
compress: {
keep_infinity: true,
drop_console: true,
drop_debugger: true
}
}

85
index.css Normal file
View File

@@ -0,0 +1,85 @@
* {
margin: 0;
}
.first-loading-wrp {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #17171a;
}
.first-loading-wrp > h1 {
font-size: 128px;
}
.first-loading-wrp .loading-wrp {
padding: 98px;
display: flex;
justify-content: center;
align-items: center;
}
.dot {
animation: antRotate 1.2s infinite linear;
transform: rotate(45deg);
position: relative;
display: inline-block;
font-size: 32px;
width: 32px;
height: 32px;
box-sizing: border-box;
}
.dot i {
width: 14px;
height: 14px;
position: absolute;
display: block;
background-color: #1890ff;
border-radius: 100%;
transform: scale(0.75);
transform-origin: 50% 50%;
opacity: 0.3;
animation: antSpinMove 1s infinite linear alternate;
}
.dot i:nth-child(1) {
top: 0;
left: 0;
}
.dot i:nth-child(2) {
top: 0;
right: 0;
-webkit-animation-delay: 0.4s;
animation-delay: 0.4s;
}
.dot i:nth-child(3) {
right: 0;
bottom: 0;
-webkit-animation-delay: 0.8s;
animation-delay: 0.8s;
}
.dot i:nth-child(4) {
bottom: 0;
left: 0;
-webkit-animation-delay: 1.2s;
animation-delay: 1.2s;
}
@keyframes antRotate {
to {
-webkit-transform: rotate(405deg);
transform: rotate(405deg);
}
}
@-webkit-keyframes antRotate {
to {
-webkit-transform: rotate(405deg);
transform: rotate(405deg);
}
}
@keyframes antSpinMove {
to {
opacity: 1;
}
}
@-webkit-keyframes antSpinMove {
to {
opacity: 1;
}
}

27
index.html Normal file
View File

@@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="renderer" content="webkit" />
<meta name="description" content="GoView 是高效、高性能的拖拽式低代码数据可视化开发平台,将页面元素封装为基础组件,无需编写代码即可完成业务需求。">
<meta name="keywords" content="GoViewgoview低代码可视化">
<meta name="author" content="奔跑的面条,面条">
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1,maximum-scale=1,user-scalable=0">
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=yes" media="(min-width: 769px)">
<link rel="icon" href="./favicon.ico" />
<title>GoView</title>
<link rel="stylesheet" href="./index.css" />
</head>
<body>
<div id="appProvider" style="display: none;"></div>
<div id="app">
<div class="first-loading-wrp">
<div class="loading-wrp">
<span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
</div>
</div>
</div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

91
package.json Normal file
View File

@@ -0,0 +1,91 @@
{
"name": "go-view",
"version": "2.2.9",
"engines": {
"node": ">=16.14"
},
"scripts": {
"dev": "vite --host",
"build": "vite build",
"preview": "vite preview",
"new": "plop --plopfile ./plop/plopfile.js",
"postinstall": "husky install",
"lint": "eslint --ext .js,.jsx,.ts,.tsx,.vue src",
"lint:fix": "eslint --ext .js,.jsx,.ts,.tsx,.vue src --fix"
},
"dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1",
"@amap/amap-jsapi-types": "^0.0.8",
"@iconify/json": "^2.2.158",
"@types/color": "^3.0.3",
"@types/crypto-js": "^4.1.1",
"@types/keymaster": "^1.6.30",
"@types/lodash": "^4.14.184",
"@visactor/vchart": "^2.0.0",
"@visactor/vchart-theme": "^1.12.2",
"animate.css": "^4.1.1",
"axios": "^1.4.0",
"color": "^4.2.3",
"crypto-js": "^4.1.1",
"dayjs": "^1.11.7",
"dom-helpers": "^5.2.1",
"echarts-liquidfill": "^3.1.0",
"echarts-stat": "^1.2.0",
"echarts-wordcloud": "^2.0.0",
"gsap": "^3.11.3",
"highlight.js": "^11.5.0",
"html2canvas": "^1.4.1",
"iconify-icon": "^1.0.8",
"keymaster": "^1.6.2",
"mitt": "^3.0.0",
"monaco-editor": "^0.33.0",
"naive-ui": "2.40.3",
"pinia": "^2.0.13",
"screenfull": "^6.0.1",
"three": "^0.145.0",
"vue": "^3.5.13",
"vue-demi": "^0.13.1",
"vue-i18n": "9.2.2",
"vue-router": "4.0.12",
"vue3-lazyload": "^0.2.5-beta",
"vue3-sketch-ruler": "1.3.3",
"vuedraggable": "^4.1.0"
},
"devDependencies": {
"@commitlint/cli": "^17.0.2",
"@commitlint/config-conventional": "^17.0.2",
"@types/node": "^16.11.26",
"@types/three": "^0.144.0",
"@typescript-eslint/eslint-plugin": "^5.18.0",
"@typescript-eslint/parser": "^5.18.0",
"@vicons/carbon": "^0.12.0",
"@vicons/ionicons5": "~0.11.0",
"@vitejs/plugin-vue": "^4.2.3",
"@vitejs/plugin-vue-jsx": "^3.0.1",
"@vue/compiler-sfc": "^3.2.31",
"@vueuse/core": "^7.7.1",
"commitlint": "^17.0.2",
"default-passive-events": "^2.0.0",
"echarts": "^5.3.2",
"eslint": "^8.12.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.5.0",
"husky": "^8.0.1",
"lodash": "~4.17.21",
"mockjs": "^1.1.0",
"plop": "^3.0.5",
"prettier": "^2.6.2",
"sass": "1.49.11",
"sass-loader": "^12.6.0",
"typescript": "4.6.3",
"vite": "4.3.6",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-importer": "^0.2.5",
"vite-plugin-mock": "^2.9.6",
"vite-plugin-monaco-editor": "^1.1.0",
"vue-echarts": "^6.0.2",
"vue-tsc": "^0.28.10"
}
}

5
plop/plopfile.js Normal file
View File

@@ -0,0 +1,5 @@
const storeGenerator = require('./store-template/prompt')
module.exports = (plop) => {
plop.setGenerator('store', storeGenerator)
}

View File

@@ -0,0 +1,3 @@
export interface {{upperDataName}}StoreType {
}

View File

@@ -0,0 +1,11 @@
import { defineStore } from 'pinia'
import { {{upperDataName}}StoreType } from './{{name}}Store.d'
import { setLocalStorage, getLocalStorage } from '@/utils'
import { StorageEnum } from '@/enums/storageEnum'
export const use{{upperDataName}}Store = defineStore({
id: 'use{{upperDataName}}Store',
state: (): {{upperDataName}}StoreType => ({}),
getters: {},
actions: {}
})

View File

@@ -0,0 +1,45 @@
module.exports = {
description: 'create a store',
prompts: [
{
type: 'input',
name: 'name',
message: 'Please enter store namesuch as "newStoreName" :',
validate (value) {
if (!value || value.trim === '') {
return 'name is required';
}
return true;
},
}
],
actions: (data) => {
const dataName = data.name
// 首字母大写
const upperDataName = dataName.slice(0, 1).toUpperCase() + dataName.slice(1)
const actions = [
{
type: 'add',
path: `${process.cwd()}/src/store/modules/${dataName}Store/${dataName}Store.ts`, // 这里的name就是上面定义的键
templateFile: './store-template/index.hbs',
data: {
name: data.name,
upperDataName,
}
},
{
type: 'add',
path: `${process.cwd()}/src/store/modules/${dataName}Store/${dataName}Store.d.ts`, // 这里的name就是上面定义的键
templateFile: './store-template/index.d.hbs',
data: {
name: data.name,
upperDataName,
}
},
]
return actions
}
}

8360
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

12
prettier.config.js Normal file
View File

@@ -0,0 +1,12 @@
module.exports = {
printWidth: 120,
tabWidth: 2,
useTabs: false,
singleQuote: true,
semi: false,
trailingComma: "none",
bracketSpacing: true,
jsxSingleQuote: true,
jsxBracketSameLine: false,
arrowParens: "avoid"
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
readme/go-view-canvas.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 398 KiB

BIN
readme/go-view-color.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

BIN
readme/go-view-fetch.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

BIN
readme/go-view-filter.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 KiB

BIN
readme/go-view-qq.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
readme/logo-poster.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

BIN
readme/logo-t-y.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
readme/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

37
src/App.vue Normal file
View File

@@ -0,0 +1,37 @@
<template>
<n-config-provider
:theme="darkTheme"
:hljs="hljsTheme"
:locale="locale"
:date-locale="dateLocale"
:theme-overrides="overridesTheme"
>
<go-app-provider>
<I18n></I18n>
<router-view></router-view>
</go-app-provider>
</n-config-provider>
</template>
<script lang="ts" setup>
import { NConfigProvider } from 'naive-ui'
import { GoAppProvider } from '@/components/GoAppProvider'
import { I18n } from '@/components/I18n'
import { useSystemInit, useDarkThemeHook, useThemeOverridesHook, useCode, useLang } from '@/hooks'
// 暗黑主题
const darkTheme = useDarkThemeHook()
// 主题配置
const overridesTheme = useThemeOverridesHook()
// 代码主题
const hljsTheme = useCode()
// 系统全局数据初始化
useSystemInit()
// 全局语言
const { locale, dateLocale } = useLang()
//测试提交
</script>

21
src/api/axios.config.ts Normal file
View File

@@ -0,0 +1,21 @@
import { ModuleTypeEnum } from '@/enums/httpEnum'
// 接口白名单(免登录)
export const fetchAllowList = [
// 登录
`${ModuleTypeEnum.SYSTEM}/login`,
// 注册
`${ModuleTypeEnum.SYSTEM}/register`,
// 获取 OSS 接口
`${ModuleTypeEnum.SYSTEM}/getOssInfo`,
// 预览获取数据
`${ModuleTypeEnum.PROJECT}/getData`,
]
// 接口黑名单
export const fetchBlockList = []
// fts 接口列表(不添加 /Visual/v1 前缀)
export const ftsList = [
'/fts/v1/uploader'
]

107
src/api/axios.ts Normal file
View File

@@ -0,0 +1,107 @@
import axios, { AxiosResponse, AxiosRequestConfig, Axios, AxiosError, InternalAxiosRequestConfig } from 'axios'
import { RequestHttpHeaderEnum, ResultEnum, ModuleTypeEnum } from '@/enums/httpEnum'
import { PageEnum, ErrorPageNameMap } from '@/enums/pageEnum'
import { StorageEnum } from '@/enums/storageEnum'
import { axiosPre } from '@/settings/httpSetting'
import { SystemStoreEnum, SystemStoreUserInfoEnum } from '@/store/modules/systemStore/systemStore.d'
import { redirectErrorPage, getLocalStorage, routerTurnByName, isPreview } from '@/utils'
import { fetchAllowList, ftsList } from './axios.config'
import includes from 'lodash/includes'
export interface MyResponseType<T> {
code: ResultEnum
data?: T
details?: T
message: string
timeseq?: number
}
export interface MyRequestInstance extends Axios {
<T = any>(config: AxiosRequestConfig): Promise<MyResponseType<T>>
}
const axiosInstance = axios.create({
// iframe 嵌入模式:直接请求后端地址,不使用代理
baseURL: `${import.meta.env.PROD ? import.meta.env.VITE_PRO_PATH : import.meta.env.VITE_DEV_PATH}${axiosPre}`,
timeout: ResultEnum.TIMEOUT
}) as unknown as MyRequestInstance
axiosInstance.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
// fts 接口特殊处理:使用完整路径,不添加 /Visual/v1 前缀
if (config.url && includes(ftsList, config.url)) {
const baseUrl = import.meta.env.PROD ? import.meta.env.VITE_PRO_PATH : import.meta.env.VITE_DEV_PATH
config.baseURL = baseUrl
}
// 获取 token 并添加到所有请求
const info = getLocalStorage(StorageEnum.GO_SYSTEM_STORE)
if (info) {
const userInfo = info[SystemStoreEnum.USER_INFO]
if (userInfo && userInfo[SystemStoreUserInfoEnum.USER_TOKEN]) {
config.headers['authorization'] = userInfo[SystemStoreUserInfoEnum.USER_TOKEN]
}
}
return config
},
(err: AxiosError) => {
Promise.reject(err)
}
)
// 响应拦截器
axiosInstance.interceptors.response.use(
(res: AxiosResponse) => {
// 统一处理后台返回 details 字段的情况,将其转换为 data 字段
const { code, details, message } = res.data as { code: number; details?: any; message?: string }
const responseData = details !== undefined
? { code, message, data: details }
: res.data
// 预览页面错误不进行处理
if (isPreview()) {
return Promise.resolve(responseData)
}
if (code === undefined || code === null) return Promise.resolve(responseData)
// 成功
if (code === ResultEnum.SUCCESS) {
return Promise.resolve(responseData)
}
// 登录过期
if (code === ResultEnum.TOKEN_OVERDUE) {
window['$message'].error(window['$t']('http.token_overdue_message'))
// iframe 嵌入模式下token 过期不重定向到登录页
console.error('[GoView] iframe 模式token 已过期,请更新 URL 中的 token 参数')
return Promise.resolve(responseData)
}
// 固定错误码重定向
if (ErrorPageNameMap.get(code)) {
redirectErrorPage(code)
return Promise.resolve(responseData)
}
// 提示错误
window['$message'].error(window['$t']((res.data as any).msg || message))
return Promise.resolve(responseData)
},
(err: AxiosError) => {
const status = err.response?.status
switch (status) {
case 401:
routerTurnByName(PageEnum.BASE_LOGIN_NAME)
Promise.reject(err)
break
default:
Promise.reject(err)
break
}
}
)
export default axiosInstance

29
src/api/fts.ts Normal file
View File

@@ -0,0 +1,29 @@
import { AxiosProgressEvent } from "axios";
import axiosInstance from '@/api/axios'
import { ContentTypeEnum } from '@/enums/httpEnum'
/** 上传文件 */
const FtsUpload = (data: any, onUploadProgress?: (progress: number) => void) => {
data.append('provider', 'local')
data.append('bucket', 'visual')
// 使用完整URL绕过 /Visual/v1 前缀
const baseUrl = import.meta.env.PROD ? import.meta.env.VITE_PRO_PATH : import.meta.env.VITE_DEV_PATH
return axiosInstance({
url: `${baseUrl}/fts/v1/uploader`,
method: 'POST',
data,
headers: {
'Content-Type': ContentTypeEnum.FORM_DATA
},
onUploadProgress: onUploadProgress ? (progressEvent: AxiosProgressEvent) => {
if (progressEvent.total) {
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
onUploadProgress(percentCompleted);
}
} : undefined
})
}
export default FtsUpload

226
src/api/http.ts Normal file
View File

@@ -0,0 +1,226 @@
import axiosInstance from './axios'
import {
RequestHttpEnum,
ContentTypeEnum,
RequestBodyEnum,
RequestDataTypeEnum,
RequestContentTypeEnum,
RequestParamsObjType
} from '@/enums/httpEnum'
import type { RequestGlobalConfigType, RequestConfigType } from '@/store/modules/chartEditStore/chartEditStore.d'
export const get = <T = any>(url: string, params?: object) => {
return axiosInstance<T>({
url: url,
method: RequestHttpEnum.GET,
params: params,
})
}
export const post = <T = any>(url: string, data?: object, headersType?: string) => {
return axiosInstance<T>({
url: url,
method: RequestHttpEnum.POST,
data: data,
headers: {
'Content-Type': headersType || ContentTypeEnum.JSON
}
})
}
export const patch = <T = any>(url: string, data?: object, headersType?: string) => {
return axiosInstance<T>({
url: url,
method: RequestHttpEnum.PATCH,
data: data,
headers: {
'Content-Type': headersType || ContentTypeEnum.JSON
}
})
}
export const put = <T = any>(url: string, data?: object, headersType?: ContentTypeEnum) => {
return axiosInstance<T>({
url: url,
method: RequestHttpEnum.PUT,
data: data,
headers: {
'Content-Type': headersType || ContentTypeEnum.JSON
}
})
}
export const del = <T = any>(url: string, params?: object) => {
return axiosInstance<T>({
url: url,
method: RequestHttpEnum.DELETE,
params
})
}
// 获取请求函数默认get
export const http = (type?: RequestHttpEnum) => {
switch (type) {
case RequestHttpEnum.GET:
return get
case RequestHttpEnum.POST:
return post
case RequestHttpEnum.PATCH:
return patch
case RequestHttpEnum.PUT:
return put
case RequestHttpEnum.DELETE:
return del
default:
return get
}
}
const prefix = 'javascript:'
// 对输入字符进行转义处理
export const translateStr = (target: string | Record<any, any>) => {
if (typeof target === 'string') {
if (target.startsWith(prefix)) {
const funcStr = target.split(prefix)[1]
let result
try {
result = new Function(`${funcStr}`)()
} catch (error) {
console.log(error)
window['$message'].error('js内容解析有误')
}
return result
} else {
return target
}
}
for (const key in target) {
if (Object.prototype.hasOwnProperty.call(target, key)) {
const subTarget = target[key]
target[key] = translateStr(subTarget)
}
}
return target
}
/**
* * 自定义请求
* @param targetParams 当前组件参数
* @param globalParams 全局参数
*/
export const customizeHttp = (targetParams: RequestConfigType, globalParams: RequestGlobalConfigType) => {
if (!targetParams || !globalParams) {
return
}
// 全局
const {
// 全局请求源地址
requestOriginUrl,
// 全局请求内容
requestParams: globalRequestParams
} = globalParams
// 目标组件(优先级 > 全局组件)
const {
// 请求地址
requestUrl,
// 普通 / sql
requestContentType,
// 获取数据的方式
requestDataType,
// 请求方式 get/post/del/put/patch
requestHttpType,
// 请求体类型 none / form-data / x-www-form-urlencoded / json /xml
requestParamsBodyType,
// SQL 请求对象
requestSQLContent,
// 请求内容 params / cookie / header / body: 同 requestParamsBodyType
requestParams: targetRequestParams
} = targetParams
// 静态排除
if (requestDataType === RequestDataTypeEnum.STATIC) return
if (!requestUrl) {
return
}
// 处理头部
let headers: RequestParamsObjType = {
...globalRequestParams.Header,
...targetRequestParams.Header
}
headers = translateStr(headers)
// data 参数
let data: RequestParamsObjType | FormData | string = {}
// params 参数
let params: RequestParamsObjType = { ...targetRequestParams.Params }
params = translateStr(params)
// form 类型处理
let formData: FormData = new FormData()
// 类型处理
switch (requestParamsBodyType) {
case RequestBodyEnum.NONE:
break
case RequestBodyEnum.JSON:
headers['Content-Type'] = ContentTypeEnum.JSON
//json对象也能使用'javasctipt:'来动态拼接参数
data = translateStr(targetRequestParams.Body['json'])
if(typeof data === 'string') data = JSON.parse(data)
// json 赋值给 data
break
case RequestBodyEnum.XML:
headers['Content-Type'] = ContentTypeEnum.XML
// xml 字符串赋值给 data
data = translateStr(targetRequestParams.Body['xml'])
break
case RequestBodyEnum.X_WWW_FORM_URLENCODED: {
headers['Content-Type'] = ContentTypeEnum.FORM_URLENCODED
const bodyFormData = targetRequestParams.Body['x-www-form-urlencoded']
for (const i in bodyFormData) formData.set(i, translateStr(bodyFormData[i]))
// FormData 赋值给 data
data = formData
break
}
case RequestBodyEnum.FORM_DATA: {
headers['Content-Type'] = ContentTypeEnum.FORM_DATA
const bodyFormUrlencoded = targetRequestParams.Body['form-data']
for (const i in bodyFormUrlencoded) {
formData.set(i, translateStr(bodyFormUrlencoded[i]))
}
// FormData 赋值给 data
data = formData
break
}
}
// sql 处理
if (requestContentType === RequestContentTypeEnum.SQL) {
headers['Content-Type'] = ContentTypeEnum.JSON
data = requestSQLContent
}
try {
const url = (new Function("return `" + `${requestOriginUrl}${requestUrl}`.trim() + "`"))();
return axiosInstance({
url,
method: requestHttpType,
data,
params,
headers
})
} catch (error) {
console.log(error)
window['$message'].error('URL地址格式有误')
}
}

100
src/api/mock/graph.json Normal file
View File

@@ -0,0 +1,100 @@
{
"nodes": [
{
"id": "0",
"name": "Myriel",
"symbolSize": "@integer(0, 50)",
"x": -266.82776,
"y": 299.6904,
"value": "@integer(0, 50)",
"category": 3
},
{
"id": "1",
"name": "Napoleon",
"symbolSize": "@integer(0, 50)",
"x": -418.08344,
"y": 446.8853,
"value": "@integer(0, 50)",
"category": 5
},
{
"id": "2",
"name": "MlleBaptistine",
"symbolSize": "@integer(0, 50)",
"x": -212.76357,
"y": 245.29176,
"value": "@integer(0, 50)",
"category": 1
},
{
"id": "3",
"name": "MmeMagloire",
"symbolSize": "@integer(0, 50)",
"x": -242.82404,
"y": 235.26283,
"value": "@integer(0, 50)",
"category": 1
},
{
"id": "4",
"name": "CountessDeLo",
"symbolSize": "@integer(0, 50)",
"x": -379.30386,
"y": 429.06424,
"value": "@integer(0, 50)",
"category": 0
}
],
"links": [
{
"source": "1",
"target": "@integer(2, 4)"
},
{
"source": "2",
"target": "@integer(3, 4)"
},
{
"source": "3",
"target": "@integer(0, 2)"
},
{
"source": "3",
"target": "@integer(0, 1)"
},
{
"source": "4",
"target": "@integer(0, 3)"
}
],
"categories": [
{
"name": "A"
},
{
"name": "B"
},
{
"name": "C"
},
{
"name": "D"
},
{
"name": "E"
},
{
"name": "F"
},
{
"name": "G"
},
{
"name": "H"
},
{
"name": "I"
}
]
}

View File

@@ -0,0 +1,199 @@
{
"xAxis": [
"12a",
"1a",
"2a",
"3a",
"4a",
"5a",
"6a",
"7a",
"8a",
"9a",
"10a",
"11a",
"12p",
"1p",
"2p",
"3p",
"4p",
"5p",
"6p",
"7p",
"8p",
"9p",
"10p",
"11p"
],
"yAxis": ["Saturday", "Friday", "Thursday", "Wednesday", "Tuesday", "Monday", "Sunday"],
"seriesData": [
[0, 0, "@integer(0, 10)"],
[1, 0, "@integer(0, 10)"],
[2, 0, "-"],
[3, 0, "-"],
[4, 0, "-"],
[5, 0, "-"],
[6, 0, "-"],
[7, 0, "-"],
[8, 0, "-"],
[9, 0, "-"],
[10, 0, "-"],
[11, 0, "@integer(0, 10)"],
[12, 0, "@integer(0, 10)"],
[13, 0, "@integer(0, 10)"],
[14, 0, "@integer(0, 10)"],
[15, 0, "@integer(0, 10)"],
[16, 0, "@integer(0, 10)"],
[17, 0, "@integer(0, 10)"],
[18, 0, "@integer(0, 10)"],
[19, 0, "@integer(0, 10)"],
[20, 0, "@integer(0, 10)"],
[21, 0, "@integer(0, 10)"],
[22, 0, "@integer(0, 10)"],
[23, 0, "@integer(0, 10)"],
[0, 1, 7],
[1, 1, "-"],
[2, 1, "-"],
[3, 1, "-"],
[4, 1, "-"],
[5, 1, "-"],
[6, 1, "-"],
[7, 1, "-"],
[8, 1, "-"],
[9, 1, "-"],
[10, 1, "@integer(0, 10)"],
[11, 1, "@integer(0, 10)"],
[12, 1, "@integer(0, 10)"],
[13, 1, "@integer(0, 10)"],
[14, 1, "@integer(0, 10)"],
[15, 1, "@integer(0, 10)"],
[16, 1, "@integer(0, 10)"],
[17, 1, "@integer(0, 10)"],
[18, 1, "@integer(0, 10)"],
[19, 1, "@integer(0, 10)"],
[20, 1, "@integer(0, 10)"],
[21, 1, "@integer(0, 10)"],
[22, 1, "@integer(0, 10)"],
[23, 1, "@integer(0, 10)"],
[0, 2, 1],
[1, 2, 1],
[2, 2, "-"],
[3, 2, "-"],
[4, 2, "-"],
[5, 2, "-"],
[6, 2, "-"],
[7, 2, "-"],
[8, 2, "-"],
[9, 2, "-"],
[10, 2, "@integer(0, 10)"],
[11, 2, "@integer(0, 10)"],
[12, 2, "@integer(0, 10)"],
[13, 2, "@integer(0, 10)"],
[14, 2, "@integer(0, 10)"],
[15, 2, "@integer(0, 10)"],
[16, 2, "@integer(0, 10)"],
[17, 2, "@integer(0, 10)"],
[18, 2, "@integer(0, 10)"],
[19, 2, "@integer(0, 10)"],
[20, 2, "@integer(0, 10)"],
[21, 2, "@integer(0, 10)"],
[22, 2, "@integer(0, 10)"],
[23, 2, "@integer(0, 10)"],
[0, 3, 7],
[1, 3, 3],
[2, 3, "-"],
[3, 3, "-"],
[4, 3, "-"],
[5, 3, "-"],
[6, 3, "-"],
[7, 3, "-"],
[8, 3, 1],
[9, 3, "-"],
[10, 3, "@integer(0, 10)"],
[11, 3, "@integer(0, 10)"],
[12, 3, "@integer(0, 10)"],
[13, 3, "@integer(0, 10)"],
[14, 3, "@integer(0, 10)"],
[15, 3, "@integer(0, 10)"],
[16, 3, "@integer(0, 10)"],
[17, 3, "@integer(0, 10)"],
[18, 3, "@integer(0, 10)"],
[19, 3, "@integer(0, 10)"],
[20, 3, "@integer(0, 10)"],
[21, 3, "@integer(0, 10)"],
[22, 3, "@integer(0, 10)"],
[23, 3, "@integer(0, 10)"],
[0, 4, "@integer(0, 10)"],
[1, 4, "@integer(0, 10)"],
[2, 4, "-"],
[3, 4, "-"],
[4, 4, "-"],
[5, 4, "@integer(0, 10)"],
[6, 4, "-"],
[7, 4, "-"],
[8, 4, "-"],
[9, 4, "@integer(0, 10)"],
[10, 4, "@integer(0, 10)"],
[11, 4, "@integer(0, 10)"],
[12, 4, "@integer(0, 10)"],
[13, 4, "@integer(0, 10)"],
[14, 4, "@integer(0, 10)"],
[15, 4, "@integer(0, 10)"],
[16, 4, "@integer(0, 10)"],
[17, 4, "@integer(0, 10)"],
[18, 4, "@integer(0, 10)"],
[19, 4, "@integer(0, 10)"],
[20, 4, "@integer(0, 10)"],
[21, 4, "@integer(0, 10)"],
[22, 4, "@integer(0, 10)"],
[23, 4, "-"],
[0, 5, "@integer(0, 10)"],
[1, 5, "@integer(0, 10)"],
[2, 5, "-"],
[3, 5, "@integer(0, 10)"],
[4, 5, "-"],
[5, 5, "-"],
[6, 5, "-"],
[7, 5, "-"],
[8, 5, "@integer(0, 10)"],
[9, 5, "-"],
[10, 5, "@integer(0, 10)"],
[11, 5, "@integer(0, 10)"],
[12, 5, "@integer(0, 10)"],
[13, 5, "@integer(0, 10)"],
[14, 5, "@integer(0, 10)"],
[15, 5, "@integer(0, 10)"],
[16, 5, "@integer(0, 10)"],
[17, 5, "@integer(0, 10)"],
[18, 5, "-"],
[19, 5, "@integer(0, 10)"],
[20, 5, "@integer(0, 10)"],
[21, 5, "@integer(0, 10)"],
[22, 5, "@integer(0, 10)"],
[23, 5, "-"],
[0, 6, "@integer(0, 10)"],
[1, 6, "-"],
[2, 6, "-"],
[3, 6, "-"],
[4, 6, "-"],
[5, 6, "-"],
[6, 6, "-"],
[7, 6, "-"],
[8, 6, "-"],
[9, 6, "-"],
[10, 6, "@integer(0, 10)"],
[11, 6, "-"],
[12, 6, "@integer(0, 10)"],
[13, 6, "@integer(0, 10)"],
[14, 6, "@integer(0, 10)"],
[15, 6, "@integer(0, 10)"],
[16, 6, "-"],
[17, 6, "-"],
[18, 6, "-"],
[19, 6, "-"],
[20, 6, "@integer(0, 10)"],
[21, 6, "@integer(0, 10)"],
[22, 6, "@integer(0, 10)"],
[23, 6, "@integer(0, 10)"]
]
}

128
src/api/mock/index.ts Normal file
View File

@@ -0,0 +1,128 @@
import test from './test.mock'
import vchart from './vchart.mock'
import { MockMethod } from 'vite-plugin-mock'
import { RequestHttpEnum } from '@/enums/httpEnum'
// 单个X数据
export const chartDataUrl = '/mock/chartData'
export const chartSingleDataUrl = '/mock/chartSingleData'
export const numberFloatUrl = '/mock/number/float'
export const numberIntUrl = '/mock/number/int'
export const textUrl = '/mock/text'
export const imageUrl = '/mock/image'
export const rankListUrl = '/mock/rankList'
export const scrollBoardUrl = '/mock/scrollBoard'
export const radarUrl = '/mock/radarData'
export const heatMapUrl = '/mock/heatMapData'
export const scatterBasicUrl = '/mock/scatterBasic'
export const mapUrl = '/mock/map'
export const capsuleUrl = '/mock/capsule'
export const wordCloudUrl = '/mock/wordCloud'
export const treemapUrl = '/mock/treemap'
export const threeEarth01Url = '/mock/threeEarth01Data'
export const sankeyUrl = '/mock/sankey'
export const graphUrl = '/mock/graphData'
export const vchartBarDataUrl = '/mock/vchart/barDataUrl'
const mockObject: MockMethod[] = [
{
// 正则
// url: /\/mock\/mockData(|\?\S*)$/,
url: chartDataUrl,
method: RequestHttpEnum.GET,
response: () => test.fetchMockData
},
{
url: chartSingleDataUrl,
method: RequestHttpEnum.GET,
response: () => test.fetchMockSingleData
},
{
url: numberFloatUrl,
method: RequestHttpEnum.GET,
response: () => test.fetchNumberFloat
},
{
url: numberIntUrl,
method: RequestHttpEnum.GET,
response: () => test.fetchNumberInt
},
{
url: textUrl,
method: RequestHttpEnum.GET,
response: () => test.fetchText
},
{
url: imageUrl,
method: RequestHttpEnum.GET,
response: () => test.fetchImage(Math.round(Math.random() * 10))
},
{
url: rankListUrl,
method: RequestHttpEnum.GET,
response: () => test.fetchRankList
},
{
url: scrollBoardUrl,
method: RequestHttpEnum.GET,
response: () => test.fetchScrollBoard
},
{
url: radarUrl,
method: RequestHttpEnum.GET,
response: () => test.fetchRadar
},
{
url: heatMapUrl,
method: RequestHttpEnum.GET,
response: () => test.fetchHeatmap
},
{
url: scatterBasicUrl,
method: RequestHttpEnum.GET,
response: () => test.fetchScatterBasic
},
{
url: mapUrl,
method: RequestHttpEnum.GET,
response: () => test.fetchMap
},
{
url: capsuleUrl,
method: RequestHttpEnum.GET,
response: () => test.fetchCapsule
},
{
url: wordCloudUrl,
method: RequestHttpEnum.GET,
response: () => test.fetchWordCloud
},
{
url: treemapUrl,
method: RequestHttpEnum.GET,
response: () => test.fetchTreemap
},
{
url: threeEarth01Url,
method: RequestHttpEnum.GET,
response: () => test.threeEarth01Data
},
{
url: sankeyUrl,
method: RequestHttpEnum.GET,
response: () => test.fetchSankey
},
{
url: graphUrl,
method: RequestHttpEnum.GET,
response: () => test.graphData
},
{
url: vchartBarDataUrl,
method: RequestHttpEnum.GET,
response: () => vchart.bar
}
]
export default mockObject

9
src/api/mock/map.json Normal file
View File

@@ -0,0 +1,9 @@
{
"markers|50": [
{
"name": "某某地市",
"value": "@integer(2, 20)",
"position": ["@float(115, 117, 1, 6)", "@float(38, 40, 1, 6)"]
}
]
}

86
src/api/mock/sankey.json Normal file
View File

@@ -0,0 +1,86 @@
{
"label": [
{
"name": "a"
},
{
"name": "b"
},
{
"name": "a1"
},
{
"name": "a2"
},
{
"name": "b1"
},
{
"name": "b2"
}
],
"links": [
{
"source": "a",
"target": "a1",
"value": "@integer(0, 10)"
},
{
"source": "a",
"target": "a2",
"value": "@integer(0, 10)"
},
{
"source": "b",
"target": "b1",
"value": "@integer(0, 10)"
},
{
"source": "a",
"target": "b1",
"value": "@integer(0, 10)"
},
{
"source": "b1",
"target": "a1",
"value": "@integer(0, 10)"
},
{
"source": "b1",
"target": "b2",
"value": "@integer(0, 10)"
}
],
"levels": [
{
"depth": 0,
"itemStyle": {
"color": "#decbe4"
},
"lineStyle": {
"color": "source",
"opacity": 0.9
}
},
{
"depth": 1,
"itemStyle": {
"color": "#b3cde3"
},
"lineStyle": {
"color": "source",
"opacity": 0.6
}
},
{
"depth": 2,
"itemStyle": {
"color": "#ccebc5"
},
"lineStyle": {
"color": "source",
"opacity": 0.6
}
}
]
}

56
src/api/mock/scatter.json Normal file
View File

@@ -0,0 +1,56 @@
[
{
"dimensions": ["data1"],
"source": [
[10.0, "@integer(0, 100)"],
[8.07, "@integer(0, 100)"],
[13.0, "@integer(0, 100)"],
[9.05, "@integer(0, 100)"],
[11.0, "@integer(0, 100)"],
[14.0, "@integer(0, 100)"],
[13.4, "@integer(0, 100)"],
[10.0, "@integer(0, 100)"],
[14.0, "@integer(0, 100)"],
[12.5, "@integer(0, 100)"],
[9.15, "@integer(0, 100)"],
[11.5, "@integer(0, 100)"],
[3.03, "@integer(0, 100)"],
[12.2, "@integer(0, 100)"],
[2.02, "@integer(0, 100)"],
[1.05, "@integer(0, 100)"],
[4.05, "@integer(0, 100)"],
[6.03, "@integer(0, 100)"],
[12.0, "@integer(0, 100)"],
[12.0, "@integer(0, 100)"],
[7.08, "@integer(0, 100)"],
[5.02, "@integer(0, 100)"]
]
},
{
"dimensions": ["data2"],
"source": [
[10.0, "@integer(0, 70)"],
[8.07, "@integer(0, 70)"],
[13.0, "@integer(0, 70)"],
[9.05, "@integer(0, 70)"],
[11.0, "@integer(0, 70)"],
[14.0, "@integer(0, 70)"],
[13.4, "@integer(0, 70)"],
[10.0, "@integer(0, 70)"],
[14.0, "@integer(0, 70)"],
[12.5, "@integer(0, 70)"],
[9.15, "@integer(0, 70)"],
[11.5, "@integer(0, 70)"],
[3.03, "@integer(0, 70)"],
[12.2, "@integer(0, 70)"],
[2.02, "@integer(0, 70)"],
[1.05, "@integer(0, 70)"],
[4.05, "@integer(0, 70)"],
[6.03, "@integer(0, 70)"],
[12.0, "@integer(0, 70)"],
[12.0, "@integer(0, 70)"],
[7.08, "@integer(0, 70)"],
[5.02, "@integer(0, 70)"]
]
}
]

239
src/api/mock/test.mock.ts Normal file
View File

@@ -0,0 +1,239 @@
import heatmapJson from './heatMapData.json'
import scatterJson from './scatter.json'
import mapJson from './map.json'
import tTreemapJson from './treemap.json'
import sankeyJson from './sankey.json'
import graphDataJson from './graph.json'
export default {
// 单图表
fetchMockSingleData: {
code: 0,
status: 200,
msg: '请求成功',
data: {
dimensions: ['product', 'dataOne'],
'source|20': [
{
product: '@name',
'dataOne|0-900': 3
}
]
}
},
// 胶囊图
fetchCapsule: {
code: 0,
status: 200,
msg: '请求成功',
data: {
dimensions: ['name', 'value'],
"source|2-5": [
{ 'name|+1': ["厦门","福州","北京","上海","新疆","郑州","湖南","内蒙古"], 'value|0-40': 20 },
]
}
},
// 图表
fetchMockData: {
code: 0,
status: 200,
msg: '请求成功',
data: {
dimensions: ['product', 'dataOne', 'dataTwo', 'dataThree'],
'source|20': [
{
product: '@name',
'dataOne|100-900': 3,
'dataTwo|100-900': 3,
'dataThree|100-900': 3
}
]
}
},
// 排名列表
fetchRankList: {
code: 0,
status: 200,
msg: '请求成功',
'data|50': [{ name: '@name', 'value|100-900': 5 }]
},
// 轮播表格
fetchScrollBoard: {
code: 0,
status: 200,
msg: '请求成功',
data: [
['行1列1', '行1列2', '1'],
['行2列1', '行2列2', '2'],
['行3列1', '行3列2', '3'],
['行4列1', '行4列2', '4'],
['行5列1', '行5列2', '5'],
['行6列1', '行6列2', '6'],
['行7列1', '行7列2', '行7列3'],
['行8列1', '行8列2', '行8列3'],
['行9列1', '行9列2', '行9列3'],
['行10列1', '行10列2', '行10列3']
]
},
// 获取数字-浮点型
fetchNumberFloat: {
code: 0,
status: 200,
msg: '请求成功',
data: '@float(0, 0.99, 1, 4)'
},
// 获取数字-整型
fetchNumberInt: {
code: 0,
status: 200,
msg: '请求成功',
data: '@integer(0, 100)'
},
// 文字
fetchText: {
code: 0,
status: 200,
msg: '请求成功',
data: '@paragraph(1, 10)'
},
// 图片
fetchImage: (num: number) => ({
code: 0,
status: 200,
msg: '请求成功',
data: `https://robohash.org/${num}`
}),
// 雷达
fetchRadar: {
code: 0,
status: 200,
msg: '请求成功',
data: {
radarIndicator: [
{ name: '@name', max: 10000 },
{ name: '@name', max: 10000 },
{ name: '@name', max: 10000 },
{ name: '@name', max: 10000 },
{ name: '@name', max: 10000 },
{ name: '@name', max: 10000 }
],
seriesData: [
{
value: [
'@integer(0, 10000)',
'@integer(0, 10000)',
'@integer(0, 10000)',
'@integer(0, 10000)',
'@integer(0, 10000)',
'@integer(0, 10000)'
],
name: 'data1'
},
{
value: [
'@integer(0, 10000)',
'@integer(0, 10000)',
'@integer(0, 10000)',
'@integer(0, 10000)',
'@integer(0, 10000)',
'@integer(0, 10000)'
],
name: 'data2'
}
]
}
},
// 热力图
fetchHeatmap: {
code: 0,
status: 200,
msg: '请求成功',
data: heatmapJson
},
// 散点图
fetchScatterBasic: {
code: 0,
status: 200,
msg: '请求成功',
data: scatterJson
},
// 中国地图
fetchMap: {
code: 0,
status: 200,
msg: '请求成功',
data: mapJson
},
// 词云
fetchWordCloud: {
code: 0,
status: 200,
msg: '请求成功',
data: [
{
name: '@name',
value: 8000,
textStyle: {
color: '#78fbb2'
},
emphasis: {
textStyle: {
color: 'red'
}
}
},
{ name: '@name', value: '@integer(10, 8000)' },
{ name: '@name', value: '@integer(10, 8000)' },
{ name: '@name', value: '@integer(10, 8000)' },
{ name: '@name', value: '@integer(10, 8000)' },
{ name: '@name', value: '@integer(10, 8000)' },
{ name: '@name', value: '@integer(10, 8000)' },
{ name: '@name', value: '@integer(10, 8000)' },
{ name: '@name', value: '@integer(10, 8000)' },
{ name: '@name', value: '@integer(10, 8000)' },
{ name: '@name', value: '@integer(10, 8000)' },
{ name: '@name', value: '@integer(10, 8000)' },
{ name: '@name', value: '@integer(10, 8000)' },
{ name: '@name', value: '@integer(10, 8000)' },
{ name: '@name', value: '@integer(10, 8000)' },
{ name: '@name', value: '@integer(10, 8000)' },
{ name: '@name', value: '@integer(10, 8000)' },
{ name: '@name', value: '@integer(10, 8000)' },
{ name: '@name', value: '@integer(10, 8000)' },
{ name: '@name', value: '@integer(10, 8000)' }
]
},
// 树图
fetchTreemap: {
code: 0,
status: 200,
msg: '请求成功',
data: tTreemapJson
},
// 三维地球
threeEarth01Data: {
code: 0,
status: 200,
msg: '请求成功',
data: [
{
startArray: { name: '@name', N: '@integer(10, 100)', E: '@integer(10, 100)' },
'endArray|10': [{ name: '@name', N: '@integer(10, 100)', E: '@integer(10, 100)' }]
}
]
},
// 桑基图
fetchSankey: {
code: 0,
status: 200,
msg: '请求成功',
data: sankeyJson
},
// 关系图
graphData: {
code: 0,
status: 200,
msg: '请求成功',
data: graphDataJson
},
}

50
src/api/mock/treemap.json Normal file
View File

@@ -0,0 +1,50 @@
[
{
"name": "@name",
"value": "@integer(0, 1000)",
"children": [
{
"name": "@name",
"value": "@integer(0, 500)"
},
{
"name": "@name",
"value": "@integer(0, 500)"
}
]
},
{
"name": "@name",
"value": "@integer(0, 1000)",
"children": [
{
"name": "@name",
"value": "@integer(0, 00)"
},
{
"name": "@name",
"value": "@integer(0, 500)"
}
]
},
{
"name": "@name",
"value": "@integer(0, 1000)",
"children": [
{
"name": "@name",
"value": "@integer(0, 1000)"
}
]
},
{
"name": "@name",
"value": "@integer(0, 1000)",
"children": [
{
"name": "@name",
"value": "@integer(0, 1000)"
}
]
}
]

View File

@@ -0,0 +1,10 @@
import bar from './vchart/bar.json'
export default {
bar: {
code: 0,
status: 200,
msg: '请求成功',
data: bar
}
}

View File

@@ -0,0 +1,16 @@
{
"values": [
{ "type": "Nail polish", "year": "Africa", "value|100-900": 3 },
{ "type": "Nail polish", "year": "EU", "value|100-900": 3 },
{ "type": "Nail polish", "year": "China", "value|100-900": 3 },
{ "type": "Nail polish", "year": "USA", "value|100-900": 3 },
{ "type": "Eyebrow pencil", "year": "Africa", "value|100-900": 3 },
{ "type": "Eyebrow pencil", "year": "EU", "value|100-900": 3 },
{ "type": "Eyebrow pencil", "year": "China", "value|100-900": 3 },
{ "type": "Eyebrow pencil", "year": "USA", "value|100-900": 3 },
{ "type": "Rouge", "year": "Africa", "value|100-900": 3 },
{ "type": "Rouge", "year": "EU", "value|100-900": 3 },
{ "type": "Rouge", "year": "China", "value|100-900": 3 },
{ "type": "Rouge", "year": "USA", "value|100-900": 3 }
]
}

2
src/api/path/index.ts Normal file
View File

@@ -0,0 +1,2 @@
export * from '@/api/path/project.api'
export * from '@/api/path/system.api'

View File

@@ -0,0 +1,99 @@
import { http } from '@/api/http'
import { httpErrorHandle } from '@/utils'
import { ContentTypeEnum, RequestHttpEnum, ModuleTypeEnum } from '@/enums/httpEnum'
import { ProjectItem, ProjectDetail } from './project'
// * 项目列表
export const projectListApi = async (data: object) => {
try {
const res = await http(RequestHttpEnum.GET)<ProjectItem[]>(`${ModuleTypeEnum.PROJECT}/list`, data)
return res
} catch {
httpErrorHandle()
}
}
// * 新增项目
export const createProjectApi = async (data: object) => {
try {
const res = await http(RequestHttpEnum.POST)<{
/**
* 项目id
*/
id: number
}>(`${ModuleTypeEnum.PROJECT}/create`, data)
return res
} catch {
httpErrorHandle()
}
}
// * 获取项目
export const fetchProjectApi = async (data: object) => {
try {
const res = await http(RequestHttpEnum.GET)<ProjectDetail>(`${ModuleTypeEnum.PROJECT}/getData`, data)
return res
} catch {
httpErrorHandle()
}
}
// * 保存项目
export const saveProjectApi = async (data: object) => {
try {
const res = await http(RequestHttpEnum.POST)(
`${ModuleTypeEnum.PROJECT}/save/data`,
data,
ContentTypeEnum.FORM_URLENCODED
)
return res
} catch {
httpErrorHandle()
}
}
// * 修改项目基础信息
export const updateProjectApi = async (data: object) => {
try {
const res = await http(RequestHttpEnum.POST)(`${ModuleTypeEnum.PROJECT}/edit`, data)
return res
} catch {
httpErrorHandle()
}
}
// * 删除项目
export const deleteProjectApi = async (data: object) => {
try {
const res = await http(RequestHttpEnum.DELETE)(`${ModuleTypeEnum.PROJECT}/delete`, data)
return res
} catch {
httpErrorHandle()
}
}
// * 修改发布状态 [-1未发布,1发布]
export const changeProjectReleaseApi = async (data: object) => {
try {
const res = await http(RequestHttpEnum.PUT)(`${ModuleTypeEnum.PROJECT}/publish`, data)
return res
} catch {
httpErrorHandle()
}
}
// * 上传文件
export const uploadFile = async (data: object) => {
try {
const res = await http(RequestHttpEnum.POST)<{
/**
* 文件地址
*/
fileName: string,
fileurl: string,
}>(`${ModuleTypeEnum.PROJECT}/upload`, data, ContentTypeEnum.FORM_DATA)
return res
} catch {
httpErrorHandle()
}
}

39
src/api/path/project.d.ts vendored Normal file
View File

@@ -0,0 +1,39 @@
export type ProjectItem = {
/**
* 项目 id
*/
id: string
/**
* 项目名称
*/
projectName: string
/**
* 项目状态:\
* -1: 未发布\
* 1: 已发布
*/
state: number
/**
* 创建时间
*/
createTime: string
/**
* 预览图片url
*/
indexImage: string
/**
* 创建者 id
*/
createUserId: string
/**
* 项目备注
*/
remarks: string
}
export interface ProjectDetail extends ProjectItem {
/**
* 项目参数
*/
content: string
}

View File

@@ -0,0 +1,49 @@
import { http } from '@/api/http'
import { httpErrorHandle } from '@/utils'
import { RequestHttpEnum, ModuleTypeEnum } from '@/enums/httpEnum'
import { LoginResult } from './system'
// * 登录
export const loginApi = async (data: object) => {
try {
const res = await http(RequestHttpEnum.POST)<LoginResult>(`${ModuleTypeEnum.SYSTEM}/login`, data)
return res
} catch (err) {
httpErrorHandle()
}
}
// * 登出
export const logoutApi = async () => {
try {
const res = await http(RequestHttpEnum.GET)(`${ModuleTypeEnum.SYSTEM}/logout`)
return res
} catch (err) {
httpErrorHandle()
}
}
// * 注册
export const registerApi = async (data: object) => {
try {
const res = await http(RequestHttpEnum.POST)(`${ModuleTypeEnum.SYSTEM}/register`, data)
return res
} catch (err) {
httpErrorHandle()
}
}
// * 获取 oss 上传接口
export const ossUrlApi = async (data: object) => {
try {
const res = await http(RequestHttpEnum.GET)<{
/**
* bucket 地址
*/
bucketURL?: string
}>(`${ModuleTypeEnum.SYSTEM}/getOssInfo`, data)
return res
} catch (err) {
httpErrorHandle()
}
}

26
src/api/path/system.d.ts vendored Normal file
View File

@@ -0,0 +1,26 @@
export interface LoginResult {
token: {
/**
* token 值
*/
tokenValue: string
/**
* token key
*/
tokenName: string
}
userinfo: {
/**
* 昵称
*/
nickname: string
/**
* 用户名
*/
username: string
/**
* 用户 id
*/
id: string
}
}

255
src/assets/images/Error.svg Normal file
View File

@@ -0,0 +1,255 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px" y="0px"
viewBox="0 0 600 600" enable-background="new 0 0 600 600" xml:space="preserve">
<g id="LEFT_ARM_1">
<g id="XMLID_46_">
<path id="XMLID_290_" fill="#FFB96C" d="M294.4,485.5c-1.2,0.3-2.4,0.4-3.6,0.4c-0.2,0-0.4,0-0.6,0c-8.4-0.3-16.2-6.9-21-15.7
c-21.3-39.2-27.1-63.4-34.8-89.9c-1.9-6.6-1.4-13.3,1.4-18.1c2.2-3.7,5.7-6.4,10.5-6.9c0.6-0.1,1.1-0.1,1.7-0.1
c8.5,0,17.4,6.8,20.9,15.6l36.5,89.4C310,471.5,305,483.1,294.4,485.5z"/>
<path id="XMLID_280_" fill="#FCAF63" d="M290.2,485.9c-8.4-0.3-16.2-6.9-21-15.7c-21.3-39.2-27.1-63.4-34.8-89.9
c-1.9-6.6-1.4-13.3,1.4-18.1c9.5,23,40.7,98.5,50.3,116.1C287.6,481.1,289,483.6,290.2,485.9z"/>
</g>
</g>
<g id="LEFT_ARM_2">
<g id="XMLID_10_">
<g id="XMLID_42_">
<path id="XMLID_293_" fill="#FFB96C" d="M340.2,472c-0.9,2.3-2.1,4.1-3.3,5c-7.2,5.7-14.3,7-26.2,9.6c-11.9,2.6-24.2,2-29.9-3.4
c-1.9-1.8-3.3-3.8-4.1-5.9c-2.5-6-0.3-12.3,6.8-15c4.2-1.6,42.4-10.6,48.7-9.4C343.1,455,342.9,465.3,340.2,472z"/>
<path id="XMLID_279_" fill="#FCAF63" d="M340.2,472c-0.9,2.3-2.1,4.1-3.3,5c-7.2,5.7-14.3,7-26.2,9.6c-11.9,2.6-24.2,2-29.9-3.4
c-1.9-1.8-3.3-3.8-4.1-5.9c3.2,0.9,9.6,2.1,20.5,0.9C306.4,477.2,325.3,474.3,340.2,472z"/>
</g>
<g id="XMLID_41_">
<path id="XMLID_49_" fill="#FEA691" d="M330.2,453.6c-11.9,4-10.6,11.9-8.8,19.6c1.8,7.7,16.6,27.5,21.1,28.5s4.8-0.8,3.6-4.5
c-1.2-3.7-9.7-16.6-9.7-16.6s9.4,12.8,13.3,16.6c3.9,3.8,7.2,3.5,7.1-0.7c-0.2-4.2-9.5-18.3-9.5-18.3s8.2,10.8,11.6,14.5
s7.9,3.1,6.3-1.9c-1.5-5-8.3-15.9-8.3-15.9s6.6,11,11,12.1c4.4,1.1,1.7-5.5-3-13.9C360.3,464.5,345,448.6,330.2,453.6z"/>
<path id="XMLID_50_" fill="#FEA691" d="M320.2,464.6c0,0-2.5,9.8-0.9,18.4s4.3,10.3,6.1,10.7s2.4-1.9,1.5-5.6
c-0.9-3.7,1.5-11,1.5-11S325.8,462.4,320.2,464.6z"/>
</g>
</g>
</g>
<g id="BODY">
<g id="XMLID_70_">
<path id="XMLID_45_" fill="#FEC272" d="M273.1,496H172.2c0,0-13.9-97.2-5.1-121.1c2.5-6.8,5.8-12.3,9.6-16.9
c9.5-11.6,21.7-16.9,30-19c10.9-2.8,20.4-2.9,28.6-0.9c21.8,5.2,33.9,25.1,37.8,46.8C278.5,414.8,273.1,496,273.1,496z"/>
<path id="XMLID_43_" fill="#F9B35F" d="M207.6,358.5c-13.2,3.4-25.3,3-31-0.5c9.5-11.6,21.7-16.9,30-19
c10.9-2.8,20.4-2.9,28.6-0.9C237,344.9,224.6,354.1,207.6,358.5z"/>
</g>
</g>
<g id="RIGHT_ARM_1">
<g id="XMLID_16_">
<path id="XMLID_278_" fill="#FFCD92" d="M199,381.3c0,1.6-0.1,3.2-0.4,4.7c-4.1,26.6-27.7,90.6-27.7,90.6c-1.7,5.1-5.3,8.9-9.7,11
c-4.4,2-9.5,2.4-14.4,0.5c-7.6-3-11.2-10.2-11.2-18.1c0-1.7,0.2-3.4,0.5-5.1c6.9-37.3,19.2-68.2,29.3-90
c4.4-9.6,15.2-15.6,24.7-10.8c2.9,1.4,4.9,3.7,6.4,6.3C198.3,373.6,199,377.4,199,381.3z"/>
<path id="XMLID_273_" fill="#FCB765" d="M199,381.3c0,1.6-0.1,3.2-0.4,4.7c-4.1,26.6-27.7,90.6-27.7,90.6c-1.7,5.1-5.3,8.9-9.7,11
l35.2-117.3C198.3,373.6,199,377.4,199,381.3z"/>
</g>
</g>
<g id="RIGHT_ARM_2">
<g id="XMLID_17_">
<g id="XMLID_20_">
<path id="XMLID_285_" fill="#FFCD92" d="M230.5,487.4c-2.2,5.4-9.4,5.6-9.4,5.6s-20.2,1.2-37.7,1.2c-17.5,0-34.7,0-41.7-7.9
c-1.4-1.6-2.5-3.4-3.1-5.3c-2.6-7.3,0.7-16,11.1-20.4c7.5-3.2,16.1-2.1,25.5-1.2c9.4,0.9,27.5,5.1,38,7.9
c10.6,2.7,16.9,5.4,17.8,15.4C231.3,484.6,231,486.1,230.5,487.4z"/>
<path id="XMLID_284_" fill="#FCB765" d="M230.5,487.4c-2.2,5.4-9.4,5.6-9.4,5.6s-20.2,1.2-37.7,1.2c-17.5,0-34.7,0-41.7-7.9
c-1.4-1.6-2.5-3.4-3.1-5.3c7.8,2.4,18.3,5.2,26.7,5.9C189,488.9,220.4,487.9,230.5,487.4z"/>
</g>
<g id="XMLID_2_">
<g id="XMLID_18_">
<path id="XMLID_47_" fill="#FEA691" d="M251.6,471.3c0,1.6-0.2,3.3-0.6,5.1c-2.1,8.6-13.2,15.2-30.1,16.1
c-7.5,0.4-12.6,0.4-16-0.4c-4.4-1.1-6.1-3.7-6.5-9.1c-0.5-6.9,4.7-13.2,8.6-15.9c11.7-7.9,22.6-8.5,32.1-7.6
C247.6,460.4,251.5,465.1,251.6,471.3z"/>
<path id="XMLID_44_" fill="#FC8172" d="M251.6,471.3c0,1.6-0.2,3.3-0.6,5.1c-2.1,8.6-13.2,15.2-30.1,16.1
c-7.5,0.4-12.6,0.4-16-0.4c-0.4-1-0.7-2.2-0.8-3.7c-0.5-5.9,4.4-11.4,8.2-13.7c11.1-6.8,21.5-7.4,30.5-6.5
C246.8,468.5,249.7,469.6,251.6,471.3z"/>
</g>
<g id="XMLID_19_">
<path id="XMLID_48_" fill="#C7DCF9" d="M264.7,488.7c0,1.1-0.2,2.1-0.5,3.2h-55c-0.3-1-0.5-2.1-0.5-3.2c0-9.6,12.5-17.4,28-17.4
C252.2,471.3,264.7,479.1,264.7,488.7z"/>
<path id="XMLID_254_" opacity="0.55" fill="#C7DCF9" d="M263.5,490.2c0,0.6-0.1,1.1-0.4,1.7h-50.3c-0.3-0.6-0.4-1.1-0.4-1.7
c0-5.1,11.4-9.3,25.5-9.3C252.1,480.9,263.5,485.1,263.5,490.2z"/>
</g>
<g id="XMLID_37_">
<path id="XMLID_28_" fill="#FEA691" d="M252.6,456.6c3.6,0.4,6.1,2.7,7.5,7.5c1.4,4.8,1.7,11.9,0.2,14.4
c-1.5,2.5-4.3,3.6-7.4,1.1c-3.1-2.5-4.8-9.5-5.8-13C245.9,462,244.5,455.8,252.6,456.6z"/>
<g id="XMLID_4_">
<path id="XMLID_38_" fill="#FEA691" d="M239.2,454.3c3.9,0.4,5.5,3.7,7,8.7c1.5,5,1.8,12.6,0.2,15.3c-1.6,2.6-4.6,3.8-7.9,1.2
c-3.3-2.6-5.2-10.1-6.2-13.8C231,460.8,230.4,453.5,239.2,454.3z"/>
<path id="XMLID_79_" fill="#FF8D76" d="M243.1,480.8c-1.4,0.3-3,0-4.6-1.4c-3.3-2.6-5.1-10.1-6.2-13.8c-1.1-4-1.7-9.7,3-11.1
c-0.9,2.7-0.4,6.4,0.3,9.2c1,4.3,2.9,13,6.2,16C242.3,480.2,242.7,480.6,243.1,480.8z"/>
</g>
<path id="XMLID_39_" fill="#FEA691" d="M224.6,456.6c3.9,0.4,6.5,2.9,8,7.9s1.8,12.6,0.2,15.3c-1.6,2.6-4.6,3.8-7.9,1.2
c-3.3-2.6-5.2-10.1-6.2-13.8C217.4,462.3,215.9,455.7,224.6,456.6z"/>
<path id="XMLID_81_" fill="#FF8D76" d="M228.5,482.4c-1.1,0-2.3-0.5-3.5-1.5c-3.3-2.6-5.1-10.1-6.2-13.8
c-1-3.8-2.2-8.6,1.5-10.2c-0.3,2.5,0.4,5.7,1.1,8.3c1.2,4.5,3.3,13.7,7,17C228.4,482.4,228.4,482.4,228.5,482.4z"/>
<path id="XMLID_40_" fill="#FEA691" d="M211.5,459.4c3.4-1,6,2.7,7.3,7.3c1.3,4.6,1.7,11.6,0.2,14c-1.4,2.4-4.2,3.5-7.2,1.1
c-3-2.4-3.8-7-4.7-10.4C205.9,467,204.9,461.4,211.5,459.4z"/>
<path id="XMLID_82_" fill="#FF8D76" d="M215.2,483.2c-1.1,0-2.2-0.4-3.4-1.4c-3-2.4-3.8-7-4.7-10.4c-1.1-3.8-1.9-8.5,2.1-11
c-0.3,2.7,0.2,5.6,0.7,8.2c0.9,4.6,1.6,10.9,5,14.3C215,483,215.1,483.1,215.2,483.2z"/>
<path id="XMLID_78_" fill="#FF8D76" d="M256.8,480.9c-1.2,0.1-2.5-0.3-3.8-1.4c-3.1-2.5-4.8-9.5-5.8-13c-1-3.7-2.2-8.5,1.8-9.7
c0,2.2,0.5,4.7,1,6.9c1,4.5,2.9,13.5,6.1,16.7C256.4,480.6,256.6,480.8,256.8,480.9z"/>
</g>
</g>
</g>
</g>
<g id="HEAD">
<g id="XMLID_89_">
<path id="XMLID_6_" fill="#FF8D76"
d="M208.8,235c0,0,9.3-3.8,15.6,8.8c6.3,12.7-0.5,20.8-0.5,20.8S217.7,246.3,208.8,235z"/>
<path id="XMLID_173_" fill="#FEA691" d="M215.2,350.9c-8.8,4.1-14.9-1.6-14.9-1.6l-5.5-11.9l-9.9-21.4c14.9-3.2,27.9-5.7,27.9-5.7
l2.3,9.5l4.3,17.7C219.2,337.6,224,346.9,215.2,350.9z"/>
<path id="XMLID_171_" fill="#FF8D76" d="M215,319.9c-1.3,1.9-2.7,3.9-4.4,5.8c-4.3,5.1-10.5,9-15.9,11.7l-9.9-21.4
c14.9-3.2,27.9-5.7,27.9-5.7L215,319.9z"/>
<ellipse id="XMLID_3_" transform="matrix(0.8545 -0.5194 0.5194 0.8545 -114.0092 131.008)"
fill="#FEA691" cx="176.9" cy="269" rx="47.2" ry="57.7"/>
<path id="XMLID_12_" fill="#FF8D76" d="M217.4,308.8c-2.9,3.7-6.5,6.9-10.6,9.5c-22.3,13.5-53.7,2.4-70.3-24.8
c-16.4-26.9-12-59.6,9.7-73.4c-12.6,16.2-13.2,42.2,0.3,64.3c16.5,27.2,48,38.3,70.3,24.8C217,309.1,217.2,309,217.4,308.8z"/>
<path id="XMLID_5_" fill="#283575" d="M157.2,309.5c0,0-17-13.4-21.3-37.4s0.5-33.7,20.2-45.3c19.7-11.5,34.4-7.4,34.4-7.4
s-14-10.5-36.9-6.6c-22.9,3.8-46.2,25.6-41.4,58.4C117.2,306.2,138,316.5,157.2,309.5z"/>
<path id="XMLID_11_" fill="#F76F59" d="M177.8,246.8c-2.7,1.9,1.1,12,9.3,19.5c8.2,7.5,16.1,3.6,16.3-3.8
C203.6,254.9,187.1,240.2,177.8,246.8z"/>
<path id="XMLID_7_" fill="#FF8D76"
d="M137.5,291.4c0,0-16,15.7-1.6,29.4c13.8,13.1,31.2-4.5,31.2-4.5S142.7,303.2,137.5,291.4z"
/>
<path id="XMLID_250_" fill="#F76F59"
d="M139.4,300.5c0,0-9,8.8-0.9,16.6c7.8,7.4,17.6-2.5,17.6-2.5S142.3,307.2,139.4,300.5z"/>
</g>
</g>
<g id="HAIR">
<g id="XMLID_84_">
<path id="XMLID_8_" fill="#283575" d="M188.5,218.1c0,0,1.7-30.2-15.5-42.5c-19.4-13.8-30.3,6.1-23.9,22.4
c2.8,7.3,5.8,11.7,8.2,14.3c2.2,2.4,5.2,3.8,8.4,4L188.5,218.1z"/>
<path id="XMLID_9_" fill="#283575" d="M122.7,192.6c-15.3,12.2-2.1,29.7,4.2,34.4c2.7,2,5.6,3.6,8.1,4.8c3.4,1.6,7.4,1.4,10.6-0.6
l21.6-13.7C167.2,217.6,143,176.5,122.7,192.6z"/>
<path id="XMLID_51_" fill="#3C4E8E"
d="M159,172.3c-4.8,0.6,0.5,9.8,7.5,11S171.3,170.8,159,172.3z"/>
<path id="XMLID_61_" fill="#3C4E8E"
d="M128.7,192.8c-2.8,3.2,4.5,7.3,10.4,5.3C145.1,196.2,134.9,185.8,128.7,192.8z"/>
</g>
</g>
<g id="MOUTH">
<g id="XMLID_83_">
<path id="XMLID_177_" fill="#F76F59" d="M217.7,285c-0.5,1-1.2,1.9-2.2,2.7c-3.7,2.9-6.5,7.1-8.5,11.5c-1.8,3.9-6.4,8.5-10.7,5.2
c-0.5-0.4-1-0.8-1.4-1.4c-4.5-5.7-2.8-20.4,4.2-26.9c5.4-5,12.1-3.7,15.5-0.9C217.9,277.7,219.3,281.7,217.7,285z"/>
<path id="XMLID_175_" fill="#FF6EA9" d="M217.7,285c-0.5,1-1.2,1.9-2.2,2.7c-3.7,2.9-6.5,7.1-8.5,11.5c-1.8,3.9-6.4,8.5-10.7,5.2
c0-6.3,2.3-13.7,6.7-17.7C208.1,282.1,214.1,282.7,217.7,285z"/>
</g>
</g>
<g id="EYE_1">
<g id="XMLID_14_">
<path id="XMLID_86_" fill="#1C3177" d="M155.8,267.7c-3.2,0-5.7-1-5.9-1.1c-1.3-0.5-1.9-2-1.4-3.3c0.5-1.3,2-1.9,3.3-1.4
c0.1,0,5.6,2.2,8.6-1.1c3.9-4.1-0.2-9.4-0.3-9.6c-0.9-1.1-0.7-2.7,0.4-3.6c1.1-0.9,2.7-0.7,3.6,0.4c2.4,3.1,5.5,10.4,0,16.2
C161.6,266.9,158.5,267.7,155.8,267.7z"/>
</g>
</g>
<g id="EYE_2">
<g id="XMLID_15_">
<path id="XMLID_85_" fill="#1C3177" d="M193,242.6c-5.1,0-9.4-3.8-9.7-4c-1.1-0.9-1.1-2.6-0.2-3.6c0.9-1,2.5-1.1,3.6-0.2
c0,0,4.6,3.9,8,2.4c1.5-0.7,0.4-3.8,0.3-3.9c-0.5-1.3,0.1-2.8,1.5-3.3c1.3-0.5,2.8,0.1,3.3,1.4c1.5,3.7,1.1,8.6-3,10.4
C195.5,242.4,194.2,242.6,193,242.6z"/>
</g>
</g>
<g id="EYEBROW_1">
<g id="XMLID_1_">
<path id="XMLID_88_" fill="#1C3177" d="M142.4,261.7c-0.1,0-0.2,0-0.3,0c-1.4-0.2-2.4-1.4-2.3-2.8c0-0.3,0.7-6.3,4.9-12.4
c4.1-6.1,8.3-8.2,8.5-8.3c1.3-0.6,2.8-0.1,3.4,1.2c0.6,1.3,0.1,2.8-1.2,3.4c0,0-3.2,1.7-6.5,6.5c-3.4,5-4,10-4,10.1
C144.8,260.7,143.7,261.7,142.4,261.7z"/>
</g>
</g>
<g id="EYEBROW_2">
<g id="XMLID_13_">
<path id="XMLID_87_" fill="#1C3177" d="M179,232.1c-0.7,0-1.5-0.3-2-0.9c-0.9-1.1-0.7-2.7,0.4-3.6c0.3-0.2,2.6-2.1,6.7-3.3
c4.1-1.2,7.5-1.1,7.6-1.1c1.4,0,2.5,1.2,2.5,2.6c0,1.4-1.3,2.5-2.6,2.5c0,0-2.7-0.1-6,0.9c-3.2,1-5,2.4-5,2.4
C180.1,231.9,179.6,232.1,179,232.1z"/>
</g>
</g>
<g id="TABLE">
<g id="XMLID_248_">
<path id="XMLID_22_" fill="#99ADF9" d="M505.9,506.3H98.3c-4,0-7.2-3.2-7.2-7.2l0,0c0-4,3.2-7.2,7.2-7.2h407.6
c4,0,7.2,3.2,7.2,7.2l0,0C513.1,503,509.9,506.3,505.9,506.3z"/>
<path id="XMLID_198_" fill="#789FEF" d="M505.2,506.3H157.1c-4,0-7.2-3.2-7.2-7.2l0,0c0-4,3.2-7.2,7.2-7.2h348.1
c4,0,7.2,3.2,7.2,7.2l0,0C512.5,503,509.2,506.3,505.2,506.3z"/>
</g>
</g>
<g id="DESKTOP">
<g id="XMLID_186_">
<g id="XMLID_182_">
<path id="XMLID_25_" fill="#E1ECFF" d="M457.6,444.7h-186c-3.3,0-5.9-3-5.3-6.3l19.8-118.7c0.4-2.6,2.7-4.5,5.3-4.5h186
c3.3,0,5.9,3,5.3,6.3L463,440.2C462.5,442.8,460.3,444.7,457.6,444.7z"/>
<path id="XMLID_29_" fill="#C7DCF9" d="M461.6,444.7H278c-3.3,0-5.9-3-5.3-6.3l19.8-118.7c0.4-2.6,2.7-4.5,5.3-4.5h183.6
c3.3,0,5.9,3,5.3,6.3l-19.8,118.7C466.5,442.8,464.2,444.7,461.6,444.7z"/>
<path id="XMLID_31_" fill="#B7D4F7" d="M442.2,432H302c-2.6,0-4.5-2.3-4.1-4.8l15.1-90.6c0.3-2,2.1-3.5,4.1-3.5h140.1
c2.6,0,4.5,2.3,4.1,4.8l-15.1,90.6C445.9,430.5,444.2,432,442.2,432z"/>
</g>
<g id="XMLID_183_">
<path id="XMLID_24_" fill="#E1ECFF" d="M382.3,484.5h-25.5c-2.4,0-4.2-2-4-4.4l6.7-66.5c0.2-2,1.9-3.6,4-3.6H389
c2.4,0,4.2,2,4,4.4l-6.7,66.5C386.1,483,384.4,484.5,382.3,484.5z"/>
<path id="XMLID_26_" fill="#C7DCF9" d="M384.1,484.5h-23.4c-1.5,0-2.7-1.3-2.6-2.8l7-69.4c0.1-1.3,1.2-2.3,2.6-2.3h23.4
c1.5,0,2.7,1.3,2.6,2.8l-7,69.4C386.5,483.5,385.4,484.5,384.1,484.5z"/>
</g>
<g id="XMLID_185_">
<path id="XMLID_27_" fill="#E1ECFF" d="M424.7,491.8H318.5c-2.2,0-4-1.8-4-4V479c0-2.2,1.8-4,4-4h106.2c2.2,0,4,1.8,4,4v8.8
C428.7,490,426.9,491.8,424.7,491.8z"/>
<path id="XMLID_30_" fill="#C7DCF9" d="M426.9,491.8H327c-2.3,0-4.2-1.9-4.2-4.2v-8.4c0-2.3,1.9-4.2,4.2-4.2h99.9
c2.3,0,4.2,1.9,4.2,4.2v8.4C431,489.9,429.2,491.8,426.9,491.8z"/>
</g>
</g>
</g>
<g id="SIGN">
<g id="XMLID_21_">
<path id="XMLID_77_" fill="#FF97C9" d="M501.5,298.7c-1,0.7-2.3,1.2-3.7,1.2H402c-4.8,0-7.8-5-5.6-9.3l34.8-66.9l12.8-24.6
c2.4-4.5,8.8-4.5,11.2,0l48.2,91.5C505,293.6,503.9,297,501.5,298.7z"/>
<path id="XMLID_74_" fill="#FC72BB" d="M501.5,298.7c-1,0.7-2.3,1.2-3.7,1.2H402c-4.8,0-7.8-5-5.6-9.3l34.8-66.9L420.6,280
c-0.9,4.8,2.4,9.3,7.3,9.9L501.5,298.7z"/>
<g id="XMLID_32_">
<g id="XMLID_34_">
<path id="XMLID_35_" fill="#FFFFFF" d="M445.2,264.1l-5-35.8c-0.2-1.2,0.8-2.3,2-2.3h14.2c1.2,0,2.1,1.1,2,2.3l-5,35.8
c-0.1,1-1,1.7-2,1.7h-4.3C446.1,265.9,445.3,265.1,445.2,264.1z"/>
</g>
<circle id="XMLID_33_" fill="#FFFFFF" cx="449.3" cy="279.1" r="7.1"/>
</g>
</g>
</g>
<g id="STAR">
<path id="XMLID_195_" fill="#FEC272" d="M189.7,141.2l1.8,3.7c0.2,0.5,0.7,0.8,1.2,0.8l4,0.6c1.3,0.2,1.8,1.7,0.8,2.6l-2.9,2.8
c-0.4,0.4-0.5,0.9-0.4,1.4l0.7,4c0.2,1.2-1.1,2.2-2.2,1.6l-3.6-1.9c-0.4-0.2-1-0.2-1.4,0l-3.6,1.9c-1.1,0.6-2.4-0.4-2.2-1.6l0.7-4
c0.1-0.5-0.1-1-0.4-1.4l-2.9-2.8c-0.9-0.9-0.4-2.4,0.8-2.6l4-0.6c0.5-0.1,0.9-0.4,1.2-0.8l1.8-3.7
C187.5,140.1,189.1,140.1,189.7,141.2"/>
</g>
<g id="BUBBLE_1">
<path id="XMLID_23_" fill="#F0F6FF" d="M384.3,170.2c0,13.8-4,26.6-10.9,37.5c0,0,0,0,0,0c-2.5,5.8-15.1,30.3-57.9,49.9
c-44.9,20.6-84.7,5.9-84.7,5.9s24.5-16.1,19.9-43c-3.6-21.2-6.1-36.4-5.9-49.2c0-0.4,0-0.7,0-1.1c0-38.5,31.2-69.7,69.7-69.7
S384.3,131.7,384.3,170.2z"/>
</g>
<g id="BUBBLE_2">
<path id="XMLID_187_" fill="#C7DCF9" d="M238.1,216.5c-3.7-9.5-7.4-9.1-9.9-7.3c-2.3,1.7-2.8,7.6,0,13.2s5.6,5.2,8.4,3.7
S239.8,220.9,238.1,216.5z"/>
</g>
<g id="BUBBLE_3">
<path id="XMLID_249_" fill="#C7DCF9" d="M361.6,237.5c-15.4,8.2-14,14.5-10.4,18.3c3.4,3.6,13.5,3.2,22.4-2.6s7.8-10.5,4.7-15
C375.2,233.7,368.7,233.6,361.6,237.5z"/>
</g>
<g id="Layer_23">
<g id="XMLID_75_">
<g id="XMLID_73_">
<path id="XMLID_274_" fill="#99ADF9" d="M364.6,191.8c0,3.8-1.8,7.6-5.2,9.9c-7.4,5.2-19.2,12.9-32.2,19.7
c-8.3,4.4-15.5,7.8-21.3,10.3c-4.8,2.1-10.1,1.7-14.4-0.7c-2.9-1.6-5.3-4.1-6.8-7.3c-1-2.2-1.6-4.6-1.6-7c0-2,0.4-4,1.1-6
l0.4-1.1l17.2-43.6l-23,12.4c-6.4,3.4-14.3,1.2-18-5.1c-0.1-0.2-0.2-0.4-0.3-0.6c-1-2-1.5-4.1-1.5-6.2c0-4.4,2.2-8.8,6.2-11.3
c7.3-4.7,17.9-11.1,30.5-17.8c24.2-12.9,36.2-11.3,39.6-4.8c3.4,6.6-16.1,61.8-16.1,61.8s26.1-13.1,28.9-14.1
c6-2.3,12.7,0.5,15.4,6.3c0.6,1.3,0.9,2.7,1,4.1C364.6,191.2,364.6,191.5,364.6,191.8z"/>
<path id="XMLID_267_" fill="#7D9AF9" d="M309.1,158.8c-5.8,14.3-19.5,47.2-24.3,50.9l17.2-43.6l-23,12.4
c-6.4,3.5-14.5,1.2-18.1-5.2c0.2-0.2,0,0,0.2-0.2c2.3,1.1,6.4,2.1,12.5-0.9c11.4-5.4,24.4-12.5,31.9-16.6
C307.6,154.5,310,156.6,309.1,158.8z"/>
<path id="XMLID_264_" fill="#7D9AF9" d="M364.6,191.8c0,3.8-1.8,7.6-5.2,9.9c-7.4,5.2-19.2,12.9-32.2,19.7
c-8.3,4.4-15.5,7.8-21.3,10.3c-4.8,2.1-10.1,1.7-14.4-0.7c0.9-0.2,1.8-0.4,2.6-0.7c4.5-1.5,24.8-12.2,44.7-22.9
c13-7,21.8-12.6,25.7-16.4C364.6,191.2,364.6,191.5,364.6,191.8z"/>
</g>
<path id="XMLID_76_" opacity="0.49" fill="#FFFFFF" d="M314.2,131.6c-9,3-13.6,8.6-2.8,8s16.5-6.1,14.6-7.9
C324.1,130,318.3,130.2,314.2,131.6z"/>
<path id="XMLID_80_" opacity="0.49" fill="#FFFFFF" d="M348.7,182.6c-5.7,1.9-8.7,5.5-1.8,5.1c6.9-0.4,10.5-3.9,9.3-5
C354.9,181.6,351.3,181.7,348.7,182.6z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 999 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 983 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

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