mirror of
https://gitee.com/dromara/go-view.git
synced 2025-02-23 15:52:49 +08:00
!88 feat-unify-test 试验后端工厂和事件机制
Merge pull request !88 from Kenjjj201377/feat-unify-test
This commit is contained in:
commit
fa84ee778c
175
README.md
175
README.md
@ -4,124 +4,71 @@
|
|||||||
|
|
||||||
**`master-fetch` 分支是带有后端接口请求的分支**
|
**`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)**
|
### feat-unify-test 分支目标
|
||||||
|
+ 实现 backend 后端工厂
|
||||||
|
将后端业务逻辑集中到 backend 了,控制 BackEndFactory 就可以适配不同的后端。
|
||||||
|
伪代码如下:
|
||||||
|
export const BackEndFactory = ():IBackend=>{
|
||||||
|
switch(项目后端配置){
|
||||||
|
case "无数据库":
|
||||||
|
return new MockBackend() // 等同: -master ,没有存储
|
||||||
|
case "indexdb":
|
||||||
|
return new IndexDbBackend() // 这次开发的,用 indexdb 做测试
|
||||||
|
case "java":
|
||||||
|
return new JavaBackend() // 等同: -fetch, 没 java 环境,还没做
|
||||||
|
case "python":
|
||||||
|
return new PythonBackend() // 自定义开发的后端
|
||||||
|
。。。 其他 oss 、云平台的后端 。。。
|
||||||
|
}}
|
||||||
|
意义:
|
||||||
|
1 unify 统一 -fetch 和 master 分支,消除分支之间的差异。
|
||||||
|
2 方便接入不同的自定义后端平台。
|
||||||
|
3 前端存储功能让测试工作更加方便
|
||||||
|
|
||||||
## 使用
|
+ 完善事件处理机制
|
||||||
|
在事件中修改图表配置
|
||||||
|
在事件中修改图表数据
|
||||||
|
在事件中调用图表 exposed 函数
|
||||||
|
数据驱动界面
|
||||||
|
|
||||||
所有的接口地址位置:`src\api\path\*`
|
### 试验功能1:Backend 后端工厂
|
||||||
|
+ 对比 -fetch 分支,梳理后端逻辑到 backend 目录的 ibackend 接口
|
||||||
|
+ 登录 - login
|
||||||
|
+ 登出 - logout
|
||||||
|
+ 预览,token 注入或单点登陆 - checkToken
|
||||||
|
+ 显示项目列表和分页 - projectList
|
||||||
|
+ 保存、发布、修改名称 - updateProject
|
||||||
|
+ 复制项目 - copyProject
|
||||||
|
+ 图表内的图片上传 - uploadFile
|
||||||
|
+ 上传图片显示处理 - getFileUrl
|
||||||
|
+ IndexDbBackend 用indexdb浏览器数据库实现了 project 相关所有功能。
|
||||||
|
+ Todo: 统一后端错误处理
|
||||||
|
+ Todo:开发 javabackend,适配现有的后端
|
||||||
|
|
||||||
接口地址修改:`.env`
|
### 试验功能2:事件处理机制
|
||||||
|
+ 实现最常用的互动:找到图表元素、显示或隐藏、修改数据
|
||||||
|
+ 核心代码:useLifeHandler.hook.ts
|
||||||
|
+ 在事件代码中通过 runtime 实现运行时刻的图表管理,提供基础函数:
|
||||||
|
+ selectComponents 选择多个图表
|
||||||
|
+ selectOneComponent 选择一个图表
|
||||||
|
+ getChartConfig 读取图表
|
||||||
|
+ setChartConfig 设置图表
|
||||||
|
+ callExposed 调用图表 exposed 的函数
|
||||||
|
+ 以下例子可以在点击事件中加入代码并预览,测试效果。
|
||||||
|
|
||||||
### 🤯 后端项目
|
+ 例子1 切换显示名称为 饼图 和 柱状图 的图表:
|
||||||
|
const range = runtime.fn.selectComponents("饼图 柱状图")
|
||||||
|
const h = runtime.fn.getChartConfig(range, "hide")
|
||||||
|
runtime.fn.setChartConfig(range, "hide", !h)
|
||||||
|
|
||||||
后端项目gitee地址:[https://gitee.com/MTrun/go-view-serve](https://gitee.com/MTrun/go-view-serve)
|
+ 例子2 修改一个名称 柱状图001 组件id 2wolqibrx3c000 的图表数据,以下两句等效
|
||||||
|
runtime.fn.setChartConfig("柱状图001", "dataset", {"dimensions":["product","data1","data2"],"source":[{"product":"Mon","data1":120,"data2":130}]})
|
||||||
|
runtime.fn.setChartConfig("#2wolqibrx3c000", "dataset", {"dimensions":["product","data1","data2"],"source":[{"product":"Mon","data1":120,"data2":230}]})
|
||||||
|
|
||||||
接口说明地址:[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)
|
+ 例子3 找到一个组并隐藏
|
||||||
|
const c = runtime.fn.selectOneComponent("分组")
|
||||||
```shell
|
if(c){
|
||||||
# port
|
console.log(runtime.fn.getChartConfig(c, "isGroup" ))
|
||||||
VITE_DEV_PORT = '8080'
|
runtime.fn.setChartConfig(c, "hide", true)
|
||||||
|
}
|
||||||
# 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
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
@ -1,38 +1,19 @@
|
|||||||
import axios, { AxiosResponse, AxiosRequestConfig } from 'axios'
|
import axios, { AxiosResponse, AxiosRequestConfig } from 'axios'
|
||||||
import { ResultEnum } from "@/enums/httpEnum"
|
import { ResultEnum } from "@/enums/httpEnum"
|
||||||
import { PageEnum, ErrorPageNameMap } from "@/enums/pageEnum"
|
import { ErrorPageNameMap } from "@/enums/pageEnum"
|
||||||
import { StorageEnum } from '@/enums/storageEnum'
|
import { redirectErrorPage } from '@/utils'
|
||||||
import { axiosPre } from '@/settings/httpSetting'
|
|
||||||
import { SystemStoreEnum, SystemStoreUserInfoEnum } from '@/store/modules/systemStore/systemStore.d'
|
|
||||||
import { redirectErrorPage, getLocalStorage, routerTurnByName, httpErrorHandle } from '@/utils'
|
|
||||||
import { fetchAllowList } from './axios.config'
|
|
||||||
import includes from 'lodash/includes'
|
|
||||||
|
|
||||||
const axiosInstance = axios.create({
|
const axiosInstance = axios.create({
|
||||||
baseURL: `${import.meta.env.PROD ? import.meta.env.VITE_PRO_PATH : ''}${axiosPre}`,
|
baseURL: import.meta.env.DEV ? import.meta.env.VITE_DEV_PATH : import.meta.env.VITE_PRO_PATH,
|
||||||
timeout: ResultEnum.TIMEOUT,
|
timeout: ResultEnum.TIMEOUT,
|
||||||
})
|
})
|
||||||
|
|
||||||
axiosInstance.interceptors.request.use(
|
axiosInstance.interceptors.request.use(
|
||||||
(config: AxiosRequestConfig) => {
|
(config: AxiosRequestConfig) => {
|
||||||
// 白名单校验
|
|
||||||
if (includes(fetchAllowList, config.url)) return config
|
|
||||||
// 获取 token
|
|
||||||
const info = getLocalStorage(StorageEnum.GO_SYSTEM_STORE)
|
|
||||||
// 重新登录
|
|
||||||
if (!info) {
|
|
||||||
routerTurnByName(PageEnum.BASE_LOGIN_NAME)
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
const userInfo = info[SystemStoreEnum.USER_INFO]
|
|
||||||
config.headers = {
|
|
||||||
...config.headers,
|
|
||||||
[userInfo[SystemStoreUserInfoEnum.TOKEN_NAME] || 'token']: userInfo[SystemStoreUserInfoEnum.USER_TOKEN] || ''
|
|
||||||
}
|
|
||||||
return config
|
return config
|
||||||
},
|
},
|
||||||
(err: AxiosRequestConfig) => {
|
(error: AxiosRequestConfig) => {
|
||||||
Promise.reject(err)
|
Promise.reject(error)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -40,27 +21,9 @@ axiosInstance.interceptors.request.use(
|
|||||||
axiosInstance.interceptors.response.use(
|
axiosInstance.interceptors.response.use(
|
||||||
(res: AxiosResponse) => {
|
(res: AxiosResponse) => {
|
||||||
const { code } = res.data as { code: number }
|
const { code } = res.data as { code: number }
|
||||||
|
if (code === ResultEnum.SUCCESS) return Promise.resolve(res.data)
|
||||||
// 成功
|
// 重定向
|
||||||
if (code === ResultEnum.SUCCESS) {
|
if (ErrorPageNameMap.get(code)) redirectErrorPage(code)
|
||||||
return Promise.resolve(res.data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 登录过期
|
|
||||||
if (code === ResultEnum.TOKEN_OVERDUE) {
|
|
||||||
window['$message'].error(window['$t']('http.token_overdue_message'))
|
|
||||||
routerTurnByName(PageEnum.BASE_LOGIN_NAME)
|
|
||||||
return Promise.resolve(res.data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 固定错误码重定向
|
|
||||||
if (ErrorPageNameMap.get(code)) {
|
|
||||||
redirectErrorPage(code)
|
|
||||||
return Promise.resolve(res.data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 提示错误
|
|
||||||
window['$message'].error(window['$t']((res.data as any).msg))
|
|
||||||
return Promise.resolve(res.data)
|
return Promise.resolve(res.data)
|
||||||
},
|
},
|
||||||
(err: AxiosResponse) => {
|
(err: AxiosResponse) => {
|
||||||
|
@ -13,7 +13,7 @@ export const get = (url: string, params?: object) => {
|
|||||||
return axiosInstance({
|
return axiosInstance({
|
||||||
url: url,
|
url: url,
|
||||||
method: RequestHttpEnum.GET,
|
method: RequestHttpEnum.GET,
|
||||||
params: params,
|
params: params
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BIN
src/assets/images/chart/informations/text_barrage.png
Normal file
BIN
src/assets/images/chart/informations/text_barrage.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
BIN
src/assets/images/project/moke-20211219181327.png
Normal file
BIN
src/assets/images/project/moke-20211219181327.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 MiB |
146
src/backend/ibackend.ts
Normal file
146
src/backend/ibackend.ts
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* 后端接口,相关功能对应表:
|
||||||
|
* 登录 - login
|
||||||
|
* 登出 - logout
|
||||||
|
* 预览,token 注入或单点登陆 - checkToken
|
||||||
|
* 显示项目列表和分页 - projectList
|
||||||
|
* 保存、发布、修改名称 - updateProject
|
||||||
|
* 复制项目 - copyProject
|
||||||
|
* 图表内的图片上传 - uploadFile
|
||||||
|
* 上传图片显示处理 - getFileUrl
|
||||||
|
* 所有接口返回格式:MyResponseType
|
||||||
|
*/
|
||||||
|
import { IndexDbBackend } from "./indexdb/indexdbbackend";
|
||||||
|
// import { PythonBackend } from "./python/pythonbackend";
|
||||||
|
|
||||||
|
export interface MyResponseType {
|
||||||
|
code: number; // 状态:200 表示接口调用成功,参考:HttpEnum
|
||||||
|
msg: string; // 提示信息,配合 data 和 code
|
||||||
|
data: any; // data = null 表示接口结果错误,错误原因放在 msg
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MyResponse implements MyResponseType {
|
||||||
|
code: number = 200;
|
||||||
|
msg: string = "";
|
||||||
|
data: any = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实现 IBackend 后端接口
|
||||||
|
* 错误处理:
|
||||||
|
*/
|
||||||
|
export interface IBackend {
|
||||||
|
/**
|
||||||
|
* 初始化后端系统,测试后端连接,oss地址等
|
||||||
|
* @param data 可选,备用
|
||||||
|
*/
|
||||||
|
init(data:any):any
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登陆
|
||||||
|
* @param data {} .username .password
|
||||||
|
* @return MyResponseType
|
||||||
|
* .data 须包含:
|
||||||
|
* token:{tokenValue:"", tokenName:""},
|
||||||
|
* userinfo:{nickname:"", username: "", id: 用户ID}
|
||||||
|
* 错误处理:
|
||||||
|
* 1 接口错误 .code 不为 200 .msg 可选,后端反馈错误信息
|
||||||
|
* 2 登陆错误 .code=200 .data = null, msg 可选,反馈不能登陆的原因
|
||||||
|
* 登陆信息.data 记录:
|
||||||
|
* setLocalStorage(GO_LOGIN_INFO_STORE, res.data)
|
||||||
|
*/
|
||||||
|
login(data:any):any
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知后端登出
|
||||||
|
*/
|
||||||
|
logout():any
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查Token是否有效,配合预览页面和单点登陆,备用
|
||||||
|
* @param data {tokenValue, tokenName}
|
||||||
|
* @return 同 login()
|
||||||
|
*/
|
||||||
|
checkToken(data:any):any
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目列表
|
||||||
|
* @param data {} .page, .limit
|
||||||
|
* @return [项目],字段名称需要进行 map
|
||||||
|
* id: projectId
|
||||||
|
* title:projectName
|
||||||
|
* release,
|
||||||
|
* label:remarks
|
||||||
|
* image:indexImage 如果需要挂刷新,在这里处理。如果需要拼接 url(getFileUrl),也在这里处理好。
|
||||||
|
*/
|
||||||
|
projectList(data:any):any
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增项目
|
||||||
|
* @param data
|
||||||
|
* .projectName
|
||||||
|
* @return id 新项目 ID
|
||||||
|
*/
|
||||||
|
createProject(data: any):any
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取项目
|
||||||
|
* @param data .projectId
|
||||||
|
* @return
|
||||||
|
id:projectId
|
||||||
|
projectName,
|
||||||
|
state: release,
|
||||||
|
remarks,
|
||||||
|
content
|
||||||
|
*/
|
||||||
|
fetchProject(data: any):any
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改项目
|
||||||
|
* @param data
|
||||||
|
* .projectId 必须
|
||||||
|
* .projectName 可选
|
||||||
|
* .release 可选
|
||||||
|
* .content 可选
|
||||||
|
* .object File 可选 对象
|
||||||
|
* .remarks 可选
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
updateProject(data: any):any
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复制项目
|
||||||
|
* @param data
|
||||||
|
* .copyId 需要复制的项目ID
|
||||||
|
* .projectName
|
||||||
|
* @return id 新项目ID
|
||||||
|
*/
|
||||||
|
copyProject(data: any):any
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除项目
|
||||||
|
* @param data
|
||||||
|
* .projectId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
deleteProject(data: any):any
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件上传
|
||||||
|
* @param file File 图片对象
|
||||||
|
* @param params 备用 Todo: 上传文件可带上项目ID和其他附加信息,以便后端文件管理
|
||||||
|
* @return .uri 文件对象 uri。建议在图表中保存相对地址,通过 getFileUrl 得到完整地址
|
||||||
|
*/
|
||||||
|
uploadFile(file: File, params: any):any
|
||||||
|
/**
|
||||||
|
* 文件地址转换,处理 uploadFile 的返回地址。如果是绝对地址,可以不处理
|
||||||
|
* @param uploadUri 上传返回的 uri
|
||||||
|
* @return 供 image.src 使用的地址信息
|
||||||
|
*/
|
||||||
|
getFileUrl(uploadUri:string):string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const BackEndFactory = new IndexDbBackend();
|
||||||
|
// export const BackEndFactory = new MockBackend();
|
||||||
|
// export const BackEndFactory = new PythonBackend();
|
147
src/backend/indexdb/indexdb.ts
Normal file
147
src/backend/indexdb/indexdb.ts
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
/**
|
||||||
|
* IndexDb 帮助类
|
||||||
|
*/
|
||||||
|
|
||||||
|
const win: { [k: string]: any } = window || globalThis;
|
||||||
|
const indexedDB =
|
||||||
|
win.indexedDB || win.mozIndexedDB || win.webkitIndexedDB || win.msIndexedDB;
|
||||||
|
const dbs: { [k: string]: IDBDatabase } = {};
|
||||||
|
let databaseName: string;
|
||||||
|
let request: IDBOpenDBRequest;
|
||||||
|
interface AnyEvent {
|
||||||
|
[k: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TableOption {
|
||||||
|
storeName: string;
|
||||||
|
option: { [K: string]: any };
|
||||||
|
index: { [K: string]: any }[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createDB = (
|
||||||
|
name: string,
|
||||||
|
version?: string,
|
||||||
|
options?: TableOption[],
|
||||||
|
) =>
|
||||||
|
new Promise<IDBDatabase>((resolve, reject) => {
|
||||||
|
if (!indexedDB) reject('浏览器不支持indexedDB');
|
||||||
|
databaseName = name;
|
||||||
|
if (dbs?.[name]) {
|
||||||
|
resolve(dbs[name]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
request = indexedDB.open(name, version);
|
||||||
|
createTable(options)?.then((db: IDBDatabase) => resolve(db));
|
||||||
|
request.onsuccess = (event: AnyEvent) => {
|
||||||
|
// IDBDatabase
|
||||||
|
const db = event.target.result;
|
||||||
|
// 缓存起来
|
||||||
|
dbs[name] = db;
|
||||||
|
resolve(db);
|
||||||
|
};
|
||||||
|
request.onerror = (event: AnyEvent) => reject(event);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const createTable = (options?: TableOption[]) => {
|
||||||
|
if (!options) return;
|
||||||
|
return new Promise<IDBDatabase>((resolve) => {
|
||||||
|
request.onupgradeneeded = (event: AnyEvent) => {
|
||||||
|
const db = event.target.result;
|
||||||
|
dbs[databaseName] = db;
|
||||||
|
for (const i in options) {
|
||||||
|
// 判断是否存在表
|
||||||
|
if (!db.objectStoreNames.contains(options[i].storeName)) {
|
||||||
|
const objectStore = db.createObjectStore(
|
||||||
|
options[i].storeName,
|
||||||
|
options[i].option,
|
||||||
|
);
|
||||||
|
for (const j of options[i].index) {
|
||||||
|
objectStore.createIndex(j.name, j.keyPath, {
|
||||||
|
unique: j.unique,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resolve(db);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTransaction = async (name: string, version?: string) => {
|
||||||
|
let db: IDBDatabase;
|
||||||
|
// 先从缓存获取
|
||||||
|
if (dbs[databaseName]) {
|
||||||
|
db = dbs[databaseName];
|
||||||
|
} else {
|
||||||
|
db = await createDB(databaseName, version);
|
||||||
|
}
|
||||||
|
return db.transaction(name, 'readwrite');
|
||||||
|
};
|
||||||
|
|
||||||
|
const getObjectStore = async (
|
||||||
|
name: string,
|
||||||
|
version?: string,
|
||||||
|
): Promise<IDBObjectStore> => {
|
||||||
|
const transaction = await getTransaction(name, version);
|
||||||
|
return transaction.objectStore(name);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getStore = (name: string, type: string, data: any) =>
|
||||||
|
new Promise<IDBDatabase>((resolve) => {
|
||||||
|
getObjectStore(name).then((objectStore: IDBObjectStore | any) => {
|
||||||
|
const request = objectStore[type](data);
|
||||||
|
request.onsuccess = (event: AnyEvent) =>
|
||||||
|
resolve(event.target.result);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const findStore = (
|
||||||
|
name: string,
|
||||||
|
start: any,
|
||||||
|
end: any,
|
||||||
|
startInclude: any,
|
||||||
|
endInclude: any,
|
||||||
|
) =>
|
||||||
|
new Promise<IDBDatabase>((resolve, reject) => {
|
||||||
|
getObjectStore(name).then((objectStore: IDBObjectStore) => {
|
||||||
|
const request = objectStore.openCursor(
|
||||||
|
IDBKeyRange.bound(start, end, startInclude, endInclude),
|
||||||
|
);
|
||||||
|
request.onsuccess = (event: AnyEvent) =>
|
||||||
|
resolve(event.target.result);
|
||||||
|
request.onerror = (event: AnyEvent) => reject(event);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
export interface DBSelect {
|
||||||
|
add: (data: any) => Promise<IDBDatabase>;
|
||||||
|
get: (data: any) => Promise<IDBDatabase>;
|
||||||
|
getAll: () => Promise<IDBDatabase>;
|
||||||
|
del: (data: any) => Promise<IDBDatabase>;
|
||||||
|
clear: (data: any) => Promise<IDBDatabase>;
|
||||||
|
put: (data: any) => Promise<IDBDatabase>;
|
||||||
|
find: (
|
||||||
|
start: any,
|
||||||
|
end: any,
|
||||||
|
startInclude: any,
|
||||||
|
endInclude: any,
|
||||||
|
) => Promise<IDBDatabase>;
|
||||||
|
}
|
||||||
|
// 获取一个store
|
||||||
|
export const onDBSelect = async (
|
||||||
|
name: string,
|
||||||
|
version: string
|
||||||
|
): Promise<DBSelect> => {
|
||||||
|
const add = (data: any) => getStore(name, 'add', data);
|
||||||
|
const get = (data: any) => getStore(name, 'get', data);
|
||||||
|
const getAll = () => getStore(name, 'getAll', null);
|
||||||
|
const del = (data: any) => getStore(name, 'delete', data);
|
||||||
|
const clear = (data: any) => getStore(name, 'clear', data);
|
||||||
|
const put = (data: any) => getStore(name, 'put', data);
|
||||||
|
const find = (start: any, end: any, startInclude: any, endInclude: any) =>
|
||||||
|
findStore(name, start, end, startInclude, endInclude);
|
||||||
|
const options: DBSelect = { add, get, getAll, clear, del, put, find };
|
||||||
|
getObjectStore(name, version);
|
||||||
|
return options;
|
||||||
|
};
|
155
src/backend/indexdb/indexdbbackend.ts
Normal file
155
src/backend/indexdb/indexdbbackend.ts
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
import { MyResponse, IBackend } from '../ibackend'
|
||||||
|
import { createDB, DBSelect, onDBSelect } from '../indexdb/indexdb'
|
||||||
|
import { fileToUrl, fileToBlob } from "@/utils"
|
||||||
|
|
||||||
|
const PROJECT_TABLE = "project"
|
||||||
|
const IMAGE_TABLE = "image" // 保存图片,未实现,Todo
|
||||||
|
const DB_NAME = "goview"
|
||||||
|
const DB_VER = "1"
|
||||||
|
|
||||||
|
export class IndexDbBackend implements IBackend {
|
||||||
|
public async init(data: any) {
|
||||||
|
let rtn:MyResponse = new MyResponse;
|
||||||
|
const db:IDBDatabase = await createDB(DB_NAME, DB_VER, [
|
||||||
|
{
|
||||||
|
storeName: PROJECT_TABLE,
|
||||||
|
option: {
|
||||||
|
keyPath: "projectId", autoIncrement:true
|
||||||
|
},
|
||||||
|
index: [
|
||||||
|
{name: 'projectId', keyPath: "projectId", unique: true},
|
||||||
|
{name: 'projectName', keyPath: "projectName", unique: false},
|
||||||
|
{name: 'release', keyPath: "release", unique: false},
|
||||||
|
{name: 'remarks', keyPath: "remarks", unique: false},
|
||||||
|
{name: 'content', keyPath: "content", unique: false},
|
||||||
|
{name: 'indexImage', keyPath: "indexImage", unique: false}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
])
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async login(data:any) {
|
||||||
|
let rtn:MyResponse = new MyResponse;
|
||||||
|
if(data.password == "123456" && data.username == "admin"){
|
||||||
|
rtn.data = {
|
||||||
|
token:{tokenValue:"mockToken", tokenName:"name"},
|
||||||
|
userinfo:{nickname:"nickname", username:data.username, id:1}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
rtn.data = null
|
||||||
|
rtn.msg = "admin 和 123456"
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async logout() {
|
||||||
|
let rtn:MyResponse = new MyResponse;
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async checkToken(data: any) {
|
||||||
|
let rtn:MyResponse = new MyResponse;
|
||||||
|
console.log("CheckToken: " + data.token)
|
||||||
|
rtn.data = {
|
||||||
|
token:{tokenValue:"mockToken", tokenName:"name"},
|
||||||
|
userinfo:{nickname:"nickname", username:data.username, id:1}
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async projectList(data:any){
|
||||||
|
let rtn:MyResponse = new MyResponse;
|
||||||
|
const db:DBSelect = await onDBSelect(PROJECT_TABLE, DB_VER)
|
||||||
|
const r:any = await db.getAll()
|
||||||
|
rtn.data = []
|
||||||
|
r.map(function (item: any) {
|
||||||
|
let url = ""
|
||||||
|
if(item.indexImage){
|
||||||
|
const Url = URL || window.URL || window.webkitURL
|
||||||
|
url = Url.createObjectURL(item.indexImage)
|
||||||
|
}
|
||||||
|
rtn.data.push({
|
||||||
|
id: item.projectId,
|
||||||
|
title: item.projectName,
|
||||||
|
release: item.release == 1,
|
||||||
|
label:item.remarks,
|
||||||
|
image:url
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async createProject(data: any){
|
||||||
|
let rtn:MyResponse = new MyResponse;
|
||||||
|
const db:DBSelect = await onDBSelect(PROJECT_TABLE, DB_VER)
|
||||||
|
rtn.data.id = await db.add({ projectName:data.projectName })
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async fetchProject(data: any){
|
||||||
|
let rtn:MyResponse = new MyResponse;
|
||||||
|
const db:DBSelect = await onDBSelect(PROJECT_TABLE, DB_VER)
|
||||||
|
const r:any = await db.get(parseInt(data.projectId))
|
||||||
|
rtn.data = {
|
||||||
|
id:r.projectId,
|
||||||
|
projectName: r.projectName,
|
||||||
|
state: r.release,
|
||||||
|
remarks: r.remarks,
|
||||||
|
content: r.content
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async updateProject(data: any){
|
||||||
|
let rtn:MyResponse = new MyResponse;
|
||||||
|
const db:DBSelect = await onDBSelect(PROJECT_TABLE, DB_VER)
|
||||||
|
const row:any = await db.get(parseInt(data.projectId))
|
||||||
|
if("content" in data) row.content = data.content
|
||||||
|
if("projectName" in data) row.projectName = data.projectName
|
||||||
|
if("release" in data) row.release = data.release
|
||||||
|
if("remarks" in data) row.remarks = data.remarks
|
||||||
|
if("object" in data) {
|
||||||
|
row.indexImage = await fileToBlob(data.object)
|
||||||
|
}
|
||||||
|
await db.put(row)
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async copyProject(data: any){
|
||||||
|
let rtn:MyResponse = new MyResponse;
|
||||||
|
const db:DBSelect = await onDBSelect(PROJECT_TABLE, DB_VER)
|
||||||
|
const row:any = await db.get(parseInt(data.copyId))
|
||||||
|
rtn.data.id =await db.add({
|
||||||
|
projectName:data.projectName,
|
||||||
|
content:row.content,
|
||||||
|
indexImage:row.indexImage,
|
||||||
|
remarks:row.remarks
|
||||||
|
})
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async deleteProject(data: any){
|
||||||
|
let rtn:MyResponse = new MyResponse;
|
||||||
|
const db:DBSelect = await onDBSelect(PROJECT_TABLE, DB_VER)
|
||||||
|
await db.del(parseInt(data.projectId))
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async changeProjectRelease(data: any){
|
||||||
|
let rtn:MyResponse = new MyResponse;
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async uploadFile(data: File, params:any){
|
||||||
|
// Todo: 图片可以保存在表中
|
||||||
|
let rtn:MyResponse = new MyResponse;
|
||||||
|
rtn.data.uri = fileToUrl(data)
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFileUrl(uploadUri:string){
|
||||||
|
return uploadUri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,7 @@
|
|||||||
import { ModuleTypeEnum } from '@/enums/httpEnum'
|
export enum ModuleTypeEnum {
|
||||||
|
SYSTEM = 'sys',
|
||||||
|
PROJECT = 'project',
|
||||||
|
}
|
||||||
|
|
||||||
// 接口白名单(免登录)
|
// 接口白名单(免登录)
|
||||||
export const fetchAllowList = [
|
export const fetchAllowList = [
|
71
src/backend/java/axios.ts
Normal file
71
src/backend/java/axios.ts
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import axios, { AxiosResponse, AxiosRequestConfig } from 'axios'
|
||||||
|
import { ResultEnum } 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, httpErrorHandle } from '@/utils'
|
||||||
|
import { fetchAllowList } from './axios.config'
|
||||||
|
import includes from 'lodash/includes'
|
||||||
|
|
||||||
|
const axiosInstance = axios.create({
|
||||||
|
baseURL: `${import.meta.env.PROD ? import.meta.env.VITE_PRO_PATH : ''}${axiosPre}`,
|
||||||
|
timeout: ResultEnum.TIMEOUT,
|
||||||
|
})
|
||||||
|
|
||||||
|
axiosInstance.interceptors.request.use(
|
||||||
|
(config: AxiosRequestConfig) => {
|
||||||
|
// 白名单校验
|
||||||
|
if (includes(fetchAllowList, config.url)) return config
|
||||||
|
// 获取 token
|
||||||
|
const info = getLocalStorage(StorageEnum.GO_SYSTEM_STORE)
|
||||||
|
// 重新登录
|
||||||
|
if (!info) {
|
||||||
|
routerTurnByName(PageEnum.BASE_LOGIN_NAME)
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
const userInfo = info[SystemStoreEnum.USER_INFO]
|
||||||
|
config.headers = {
|
||||||
|
...config.headers,
|
||||||
|
[userInfo[SystemStoreUserInfoEnum.TOKEN_NAME] || 'token']: userInfo[SystemStoreUserInfoEnum.USER_TOKEN] || ''
|
||||||
|
}
|
||||||
|
return config
|
||||||
|
},
|
||||||
|
(err: AxiosRequestConfig) => {
|
||||||
|
Promise.reject(err)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// 响应拦截器
|
||||||
|
axiosInstance.interceptors.response.use(
|
||||||
|
(res: AxiosResponse) => {
|
||||||
|
const { code } = res.data as { code: number }
|
||||||
|
|
||||||
|
// 成功
|
||||||
|
if (code === ResultEnum.SUCCESS) {
|
||||||
|
return Promise.resolve(res.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 登录过期
|
||||||
|
if (code === ResultEnum.TOKEN_OVERDUE) {
|
||||||
|
window['$message'].error(window['$t']('http.token_overdue_message'))
|
||||||
|
routerTurnByName(PageEnum.BASE_LOGIN_NAME)
|
||||||
|
return Promise.resolve(res.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 固定错误码重定向
|
||||||
|
if (ErrorPageNameMap.get(code)) {
|
||||||
|
redirectErrorPage(code)
|
||||||
|
return Promise.resolve(res.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提示错误
|
||||||
|
window['$message'].error(window['$t']((res.data as any).msg))
|
||||||
|
return Promise.resolve(res.data)
|
||||||
|
},
|
||||||
|
(err: AxiosResponse) => {
|
||||||
|
Promise.reject(err)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export default axiosInstance
|
226
src/backend/java/http.ts
Normal file
226
src/backend/java/http.ts
Normal 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 = (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 patch = (url: string, data?: object, headersType?: string) => {
|
||||||
|
return axiosInstance({
|
||||||
|
url: url,
|
||||||
|
method: RequestHttpEnum.PATCH,
|
||||||
|
data: data,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': headersType || ContentTypeEnum.JSON
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const put = (url: string, data?: object, headersType?: ContentTypeEnum) => {
|
||||||
|
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.PATCH:
|
||||||
|
return patch
|
||||||
|
|
||||||
|
case RequestHttpEnum.PUT:
|
||||||
|
return put
|
||||||
|
|
||||||
|
case RequestHttpEnum.DELETE:
|
||||||
|
return del
|
||||||
|
|
||||||
|
default:
|
||||||
|
return get
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const prefix = 'javascript:'
|
||||||
|
// 对输入字符进行转义处理
|
||||||
|
export const translateStr = (target: string | object) => {
|
||||||
|
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 as any)[key];
|
||||||
|
(target as any)[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()
|
||||||
|
formData.set('default', 'defaultData')
|
||||||
|
// 类型处理
|
||||||
|
|
||||||
|
switch (requestParamsBodyType) {
|
||||||
|
case RequestBodyEnum.NONE:
|
||||||
|
break
|
||||||
|
|
||||||
|
case RequestBodyEnum.JSON:
|
||||||
|
headers['Content-Type'] = ContentTypeEnum.JSON
|
||||||
|
data = translateStr(JSON.parse(targetRequestParams.Body['json']))
|
||||||
|
// 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地址格式有误!')
|
||||||
|
}
|
||||||
|
}
|
130
src/backend/mock/mockbackend.ts
Normal file
130
src/backend/mock/mockbackend.ts
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
import { MyResponse, IBackend } from './ibackend'
|
||||||
|
import { fileToUrl } from '@/utils'
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MockBackend
|
||||||
|
* 模拟纯前端,不会保存,也不报错。
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class MockBackend implements IBackend {
|
||||||
|
public async init(data: any) {
|
||||||
|
let rtn:MyResponse = new MyResponse;
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async login(data:any) {
|
||||||
|
let rtn:MyResponse = new MyResponse;
|
||||||
|
if(data.password == "123456" && data.username == "admin"){
|
||||||
|
rtn.data = {
|
||||||
|
token:{tokenValue:"mockToken", tokenName:"name"},
|
||||||
|
userinfo:{nickname:"nickname", username:data.username, id:1}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
rtn.data = null
|
||||||
|
rtn.msg = "用户名或密码错误!"
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async logout() {
|
||||||
|
let rtn:MyResponse = new MyResponse;
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async checkToken(data:any){
|
||||||
|
let rtn:MyResponse = new MyResponse;
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async projectList(data:any){
|
||||||
|
let rtn:MyResponse = new MyResponse;
|
||||||
|
rtn.data =[
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
title: '假数据不可用',
|
||||||
|
release: true,
|
||||||
|
label: '官方案例'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
title: '物料2-假数据不可用',
|
||||||
|
release: false,
|
||||||
|
label: '官方案例'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
title: '物料3-假数据不可用',
|
||||||
|
release: false,
|
||||||
|
label: '官方案例'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
title: '物料4-假数据不可用',
|
||||||
|
release: false,
|
||||||
|
label: '官方案例'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
title: '物料5-假数据不可用',
|
||||||
|
release: false,
|
||||||
|
label: '官方案例'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async createProject(data: any){
|
||||||
|
let rtn:MyResponse = new MyResponse;
|
||||||
|
rtn.data.id = "newId"
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async fetchProject(data: any){
|
||||||
|
let rtn:MyResponse = new MyResponse;
|
||||||
|
rtn.data = {
|
||||||
|
id:data.projectId,
|
||||||
|
projectName: '假数据不可用',
|
||||||
|
indexImage:'',
|
||||||
|
state: 0,
|
||||||
|
remarks: '官方案例',
|
||||||
|
content: null
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async saveProject(data: object){
|
||||||
|
let rtn:MyResponse = new MyResponse;
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async updateProject(data: any){
|
||||||
|
let rtn:MyResponse = new MyResponse;
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async copyProject(data: any){
|
||||||
|
let rtn:MyResponse = new MyResponse;
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async deleteProject(data: any){
|
||||||
|
let rtn:MyResponse = new MyResponse;
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async changeProjectRelease(data: any){
|
||||||
|
let rtn:MyResponse = new MyResponse;
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async uploadFile(data: File, params:any){
|
||||||
|
let rtn:MyResponse = new MyResponse;
|
||||||
|
rtn.data.uri = fileToUrl(data)
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFileUrl(uploadUri:string){
|
||||||
|
return uploadUri;
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,6 @@
|
|||||||
// 模块 Path 前缀分类
|
/**
|
||||||
export enum ModuleTypeEnum {
|
* @description: 请求结果集
|
||||||
SYSTEM = 'sys',
|
*/
|
||||||
PROJECT = 'project',
|
|
||||||
}
|
|
||||||
|
|
||||||
// 请求结果集
|
|
||||||
export enum ResultEnum {
|
export enum ResultEnum {
|
||||||
DATA_SUCCESS = 0,
|
DATA_SUCCESS = 0,
|
||||||
SUCCESS = 200,
|
SUCCESS = 200,
|
||||||
@ -12,7 +8,7 @@ export enum ResultEnum {
|
|||||||
SERVER_FORBIDDEN = 403,
|
SERVER_FORBIDDEN = 403,
|
||||||
NOT_FOUND = 404,
|
NOT_FOUND = 404,
|
||||||
TOKEN_OVERDUE = 886,
|
TOKEN_OVERDUE = 886,
|
||||||
TIMEOUT = 60000,
|
TIMEOUT = 60000
|
||||||
}
|
}
|
||||||
|
|
||||||
// 数据相关
|
// 数据相关
|
||||||
@ -37,7 +33,9 @@ export enum RequestHttpHeaderEnum {
|
|||||||
COOKIE = 'Cookie'
|
COOKIE = 'Cookie'
|
||||||
}
|
}
|
||||||
|
|
||||||
// 请求方法
|
/**
|
||||||
|
* @description: 请求方法
|
||||||
|
*/
|
||||||
export enum RequestHttpEnum {
|
export enum RequestHttpEnum {
|
||||||
GET = 'get',
|
GET = 'get',
|
||||||
POST = 'post',
|
POST = 'post',
|
||||||
@ -118,7 +116,9 @@ export type RequestParams = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 常用的contentTyp类型
|
/**
|
||||||
|
* @description: 常用的contentTyp类型
|
||||||
|
*/
|
||||||
export enum ContentTypeEnum {
|
export enum ContentTypeEnum {
|
||||||
// json
|
// json
|
||||||
JSON = 'application/json;charset=UTF-8',
|
JSON = 'application/json;charset=UTF-8',
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
export enum StorageEnum {
|
export enum StorageEnum {
|
||||||
// 全局设置
|
// 全局设置
|
||||||
GO_SETTING_STORE = 'GO_SETTING',
|
GO_SYSTEM_SETTING_STORE = 'GO_SYSTEM_SETTING',
|
||||||
|
// token 等信息
|
||||||
|
GO_ACCESS_TOKEN_STORE = 'GO_ACCESS_TOKEN',
|
||||||
// 登录信息
|
// 登录信息
|
||||||
GO_SYSTEM_STORE = 'GO_SYSTEM',
|
GO_LOGIN_INFO_STORE = 'GO_LOGIN_INFO',
|
||||||
// 语言
|
// 语言
|
||||||
GO_LANG_STORE = 'GO_LANG',
|
GO_LANG_STORE = 'GO_LANG',
|
||||||
// 当前选择的主题
|
// 当前选择的主题
|
||||||
|
@ -2,4 +2,4 @@ export * from '@/hooks/useTheme.hook'
|
|||||||
export * from '@/hooks/usePreviewScale.hook'
|
export * from '@/hooks/usePreviewScale.hook'
|
||||||
export * from '@/hooks/useCode.hook'
|
export * from '@/hooks/useCode.hook'
|
||||||
export * from '@/hooks/useChartDataFetch.hook'
|
export * from '@/hooks/useChartDataFetch.hook'
|
||||||
export * from '@/hooks/useSystemInit.hook'
|
export * from '@/hooks/useLifeHandler.hook'
|
280
src/hooks/useLifeHandler.hook.ts
Normal file
280
src/hooks/useLifeHandler.hook.ts
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
import { CreateComponentType, EventLife } from '@/packages/index.d'
|
||||||
|
import * as echarts from 'echarts'
|
||||||
|
import { BackEndFactory } from '@/backend/ibackend'
|
||||||
|
import { reactive, toRef , watch, computed} from 'vue';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 事件测试:
|
||||||
|
*
|
||||||
|
切换显示名称为 饼图 和 柱状图 的图标
|
||||||
|
const range = runtime.fn.selectComponents("饼图 柱状图")
|
||||||
|
const h = runtime.fn.getChartConfig(range, "hide")
|
||||||
|
runtime.fn.setChartConfig(range, "hide", !h)
|
||||||
|
|
||||||
|
修改一个名称 柱状图001 组件id 2wolqibrx3c000 的图表数据,以下两句等效
|
||||||
|
runtime.fn.setChartConfig("柱状图001", "dataset", {"dimensions":["product","data1","data2"],"source":[{"product":"Mon","data1":120,"data2":130}]})
|
||||||
|
runtime.fn.setChartConfig("#2wolqibrx3c000", "dataset", {"dimensions":["product","data1","data2"],"source":[{"product":"Mon","data1":120,"data2":230}]})
|
||||||
|
|
||||||
|
找到一个组并隐藏
|
||||||
|
const c = runtime.fn.selectOneComponent("分组")
|
||||||
|
if(c){
|
||||||
|
console.log(runtime.fn.getChartConfig(c, "isGroup" ))
|
||||||
|
runtime.fn.setChartConfig(c, "hide", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
调用组件 exposed 函数的例子
|
||||||
|
组件中增加: defineExpose({ actionTest:actionTest })
|
||||||
|
以下调用名称为 柱状图 组件的 actionTest
|
||||||
|
runtime.fn.callExposed("柱状图", "actionTest")
|
||||||
|
|
||||||
|
|
||||||
|
数据驱动界面:
|
||||||
|
图表A 的 MOUNTED 加入对 status1 的 Watch, = "0" 隐藏
|
||||||
|
watch(()=>runtime.variables.status1, newValue => runtime.fn.setChartConfig(this, "hide", newValue == "0"))
|
||||||
|
图表B 的 MOUNTED 也加入对 status1 的 Watch = "1" 隐藏
|
||||||
|
watch(()=>runtime.variables.status1, newValue => runtime.fn.setChartConfig(this, "hide", newValue == "1"))
|
||||||
|
点击事件代码,实现图表A 和 图表B 的切换显示:
|
||||||
|
if(runtime.variables.status1 == "0"){
|
||||||
|
runtime.variables.status1 = "1"
|
||||||
|
} else{
|
||||||
|
runtime.variables.status1 = "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
图表A 的 MOUNTED 加入对 data1 的 Watch
|
||||||
|
watch(()=>runtime.datasets.data1,
|
||||||
|
newValue => runtime.fn.setChartConfig(this, "dataset", newValue))
|
||||||
|
图表B 的 MOUNTED 加入对 data1 的 Watch
|
||||||
|
watch(()=>runtime.datasets.data1,
|
||||||
|
newValue => runtime.fn.setChartConfig(this, "dataset", newValue))
|
||||||
|
点击事件代码,修改datasets.data1,同时更新图表A 和 图表B 的数据 :
|
||||||
|
runtime.datasets.data1 = {"dimensions":["product","data1","data2"],"source":[{"product":"Mon","data1":120,"data2":230}]}
|
||||||
|
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// * 初始化
|
||||||
|
export const useSystemInit = async () => {
|
||||||
|
const res = await BackEndFactory.init({}) as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getOneChartConfig = (component:any, configName:string, params?:any)=>{
|
||||||
|
let root = null
|
||||||
|
if(component.proxy.chartConfig) root = component.proxy.chartConfig
|
||||||
|
else if (component.proxy.groupData) root = component.proxy.groupData
|
||||||
|
// if(!root) return null
|
||||||
|
switch(configName){
|
||||||
|
case "hide":
|
||||||
|
return root.status.hide
|
||||||
|
break;
|
||||||
|
case "dataset":
|
||||||
|
return root.option.dataset
|
||||||
|
break;
|
||||||
|
case "isGroup":
|
||||||
|
return root.isGroup
|
||||||
|
break;
|
||||||
|
case "key":
|
||||||
|
return root.key
|
||||||
|
break;
|
||||||
|
case "attr":
|
||||||
|
return root.attr
|
||||||
|
break;
|
||||||
|
case "name":
|
||||||
|
return root.chartConfig.title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const setOneChartConfig = (component:any, configName:string, newValue:any, params?:any)=>{
|
||||||
|
let root = null
|
||||||
|
if(component.proxy.chartConfig) root = component.proxy.chartConfig
|
||||||
|
else if (component.proxy.groupData) root = component.proxy.groupData
|
||||||
|
switch(configName){
|
||||||
|
case "hide":
|
||||||
|
root.status.hide = newValue
|
||||||
|
break;
|
||||||
|
case "dataset":
|
||||||
|
root.option.dataset = newValue
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择器语法:参考 css selectors
|
||||||
|
* 名称 组件名称,不能有空格和特殊字符(. # 引号等)
|
||||||
|
* [name=名称] Todo
|
||||||
|
* #id 组件编号
|
||||||
|
* .key 组件类型 Todo
|
||||||
|
* @param selectors
|
||||||
|
* @returns []
|
||||||
|
*/
|
||||||
|
const getComponentsBySelectors = (selectors:string):any[]=>{
|
||||||
|
// 返回:数组,可能多个
|
||||||
|
let rtn:any[] = []
|
||||||
|
const ar = selectors.split(" ")
|
||||||
|
for(let a of ar){
|
||||||
|
rtn = rtn.concat(getComponentsBySelector(a))
|
||||||
|
}
|
||||||
|
return rtn
|
||||||
|
}
|
||||||
|
|
||||||
|
const getComponentsBySelector = (selector:string):any[]=>{
|
||||||
|
// 返回:数组,可能多个
|
||||||
|
const rtn:any[] = []
|
||||||
|
if(selector.substring(0,1) == "#")
|
||||||
|
{
|
||||||
|
const key = selector.substring(1)
|
||||||
|
if(key in components){
|
||||||
|
return [components[key]]
|
||||||
|
}
|
||||||
|
return rtn
|
||||||
|
}
|
||||||
|
for (let key in components) {
|
||||||
|
if(getOneChartConfig(components[key], "name") == selector){
|
||||||
|
rtn.push(components[key])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rtn
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 所有图表组件集合对象
|
||||||
|
const components: { [K in string]?: any } = {}
|
||||||
|
|
||||||
|
const runtime = {
|
||||||
|
// 变量,管理各种状态
|
||||||
|
variables:reactive({}),
|
||||||
|
// 数据集
|
||||||
|
datasets:reactive({}),
|
||||||
|
// 组件列表 {}
|
||||||
|
components:components,
|
||||||
|
// 帮助类
|
||||||
|
fn:{
|
||||||
|
/**
|
||||||
|
* 选择一个组件
|
||||||
|
* @param selectors string 选择器语法 | component | [component]
|
||||||
|
* @return 第一个符合要求的 component 或 null
|
||||||
|
*/
|
||||||
|
selectOneComponent:(selectors:any)=>{
|
||||||
|
const cList = runtime.fn.selectComponents(selectors)
|
||||||
|
if(cList.length > 0){
|
||||||
|
return cList[0]
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 选择组件
|
||||||
|
* @param selectors string 选择器语法 | component | [component]
|
||||||
|
* @return 要求的 [component] 或 []
|
||||||
|
*/
|
||||||
|
selectComponents:(selectors:any):any[]=>{
|
||||||
|
if(!selectors) return []
|
||||||
|
if(typeof selectors == "string") return getComponentsBySelectors(selectors)
|
||||||
|
if(Array.isArray(selectors)) return selectors
|
||||||
|
return [selectors]
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 获取组件的值,如果多个,使用第一个
|
||||||
|
* @param selectors string 选择器语法 | component | [component]
|
||||||
|
* @param configName 配置名称
|
||||||
|
* @param params 备用参数,可选
|
||||||
|
* @returns 配置的值
|
||||||
|
*/
|
||||||
|
getChartConfig:(selectors:any, configName:string, params?:any)=>{
|
||||||
|
const component:any = runtime.fn.selectOneComponent(selectors)
|
||||||
|
if(!component && !component.proxy) return null
|
||||||
|
return getOneChartConfig(component, configName, params)
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 设置组件的值,支持多个
|
||||||
|
* @param selectors string 选择器语法 | component | [component]
|
||||||
|
* @param configName 配置名称
|
||||||
|
* @param newValue 新值
|
||||||
|
* @param params 备用参数,可选
|
||||||
|
* @returns 配置的值
|
||||||
|
*/
|
||||||
|
setChartConfig:(selectors:any, configName:string, newValue:any, params?:any)=>{
|
||||||
|
const cList:any[] = runtime.fn.selectComponents(selectors)
|
||||||
|
for(let c of cList){
|
||||||
|
if(!c && !c.proxy) return null
|
||||||
|
setOneChartConfig(c, configName, newValue, params)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 调用组件暴露的函数,组件中使用 defineExpose 进行定义
|
||||||
|
* @param selectors string 选择器语法 | component | [component]
|
||||||
|
* @param action 组件中 defineExpose 的函数名
|
||||||
|
* @param params 调用的参数只支持一个参数或没有参数
|
||||||
|
* @returns 无
|
||||||
|
*/
|
||||||
|
callExposed:(selectors:any, action:string, params?:any)=>{
|
||||||
|
const cList:any[] = runtime.fn.selectComponents(selectors)
|
||||||
|
for(let c of cList){
|
||||||
|
if(!c && !c.exposed) return null
|
||||||
|
if(typeof c.exposed[action] == "function") c.exposed[action](params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 项目提供的npm 包变量
|
||||||
|
export const npmPkgs = { echarts, toRef , watch, computed, runtime }
|
||||||
|
|
||||||
|
export const useLifeHandler = (chartConfig: CreateComponentType) => {
|
||||||
|
const events = chartConfig.events || {}
|
||||||
|
console.log("chartConfig.events")
|
||||||
|
console.log(chartConfig.events)
|
||||||
|
// 生成生命周期事件
|
||||||
|
let lifeEvents = {
|
||||||
|
[EventLife.BEFORE_MOUNT](e: any) {
|
||||||
|
// 存储组件
|
||||||
|
components[chartConfig.id] = e.component
|
||||||
|
const fnStr = (events[EventLife.BEFORE_MOUNT] || '').trim()
|
||||||
|
generateFunc(fnStr, e, e.component)
|
||||||
|
},
|
||||||
|
[EventLife.MOUNTED](e: any) {
|
||||||
|
const fnStr = (events[EventLife.MOUNTED] || '').trim()
|
||||||
|
generateFunc(fnStr, e, e.component)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 遍历,按需侦听
|
||||||
|
for(let key in EventLife)
|
||||||
|
{
|
||||||
|
if(key != "BEFORE_MOUNT" && key != "MOUNTED"){
|
||||||
|
const k = EventLife[key as keyof typeof EventLife]
|
||||||
|
const fnStr = (events[<EventLife>k] || '').trim()
|
||||||
|
if(fnStr){
|
||||||
|
lifeEvents[k as keyof typeof lifeEvents] = (e:any) => {
|
||||||
|
const fnStr = (events[<EventLife>k] || '').trim()
|
||||||
|
generateFunc(fnStr, e, components[chartConfig.id])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lifeEvents
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param fnStr 用户方法体代码
|
||||||
|
* @param e 执行生命周期的动态组件实例
|
||||||
|
*/
|
||||||
|
function generateFunc(fnStr: string, e: any, component:any) {
|
||||||
|
if(fnStr == "") return
|
||||||
|
try {
|
||||||
|
// npmPkgs 便于拷贝 echarts 示例时设置option 的formatter等相关内容
|
||||||
|
Function(`
|
||||||
|
"use strict";
|
||||||
|
return (
|
||||||
|
async function(e, components, node_modules){
|
||||||
|
const {${Object.keys(npmPkgs).join()}} = node_modules;
|
||||||
|
${fnStr}
|
||||||
|
}
|
||||||
|
)`)().bind(component)(e, components, npmPkgs)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
@ -1,23 +0,0 @@
|
|||||||
import { useSystemStore } from '@/store/modules/systemStore/systemStore'
|
|
||||||
import { SystemStoreEnum } from '@/store/modules/systemStore/systemStore.d'
|
|
||||||
import { ResultEnum } from '@/enums/httpEnum'
|
|
||||||
import { ossUrlApi } from '@/api/path/'
|
|
||||||
|
|
||||||
|
|
||||||
// * 初始化
|
|
||||||
export const useSystemInit = async () => {
|
|
||||||
const systemStore = useSystemStore()
|
|
||||||
|
|
||||||
// 获取 OSS 信息
|
|
||||||
const getOssUrl = async () => {
|
|
||||||
const res = await ossUrlApi({}) as unknown as MyResponseType
|
|
||||||
if (res.code === ResultEnum.SUCCESS) {
|
|
||||||
systemStore.setItem(SystemStoreEnum.FETCH_INFO, {
|
|
||||||
OSSUrl: res.data?.bucketURL
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 执行
|
|
||||||
getOssUrl()
|
|
||||||
}
|
|
18
src/packages/index.d.ts
vendored
18
src/packages/index.d.ts
vendored
@ -90,6 +90,21 @@ export const BlendModeEnumList = [
|
|||||||
{ label: '亮度', value: 'luminosity' }
|
{ label: '亮度', value: 'luminosity' }
|
||||||
]
|
]
|
||||||
|
|
||||||
|
// vue3 生命周期事件
|
||||||
|
export enum EventLife {
|
||||||
|
// 渲染之后
|
||||||
|
MOUNTED = 'vnodeMounted',
|
||||||
|
// 渲染之前
|
||||||
|
BEFORE_MOUNT = 'vnodeBeforeMount',
|
||||||
|
// 鼠标事件
|
||||||
|
MOUSE_CLICK = 'click',
|
||||||
|
MOUSE_OVER = "mouseover",
|
||||||
|
MOUSE_LEAVE = "mouseleave",
|
||||||
|
// 图表事件
|
||||||
|
ECHART_LEGEND_SELECT_CHANGED = "legendselectchanged",
|
||||||
|
ECHART_HIGH_LIGHT = "highlight"
|
||||||
|
}
|
||||||
|
|
||||||
// 组件实例类
|
// 组件实例类
|
||||||
export interface PublicConfigType {
|
export interface PublicConfigType {
|
||||||
id: string
|
id: string
|
||||||
@ -115,6 +130,9 @@ export interface PublicConfigType {
|
|||||||
}
|
}
|
||||||
filter?: string
|
filter?: string
|
||||||
status: StatusType
|
status: StatusType
|
||||||
|
events?: {
|
||||||
|
[K in EventLife]?: string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreateComponentType extends PublicConfigType, requestConfig {
|
export interface CreateComponentType extends PublicConfigType, requestConfig {
|
||||||
|
@ -81,6 +81,8 @@ export class PublicConfigClass implements PublicConfigType {
|
|||||||
public request = cloneDeep(requestConfig)
|
public request = cloneDeep(requestConfig)
|
||||||
// 数据过滤
|
// 数据过滤
|
||||||
public filter = undefined
|
public filter = undefined
|
||||||
|
// 事件
|
||||||
|
public events = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
// 多选成组类
|
// 多选成组类
|
||||||
|
@ -18,11 +18,13 @@ export function createRouterGuards(router: Router) {
|
|||||||
const isErrorPage = router.getRoutes().findIndex((item) => item.name === to.name);
|
const isErrorPage = router.getRoutes().findIndex((item) => item.name === to.name);
|
||||||
if (isErrorPage === -1) {
|
if (isErrorPage === -1) {
|
||||||
next({ name: PageEnum.ERROR_PAGE_NAME_404 })
|
next({ name: PageEnum.ERROR_PAGE_NAME_404 })
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if (!routerAllowList.includes(to.name) && !loginCheck()) {
|
if (!routerAllowList.includes(to.name) && !loginCheck()) {
|
||||||
next({ name: PageEnum.BASE_LOGIN_NAME })
|
next({ name: PageEnum.BASE_LOGIN_NAME })
|
||||||
|
return
|
||||||
}
|
}
|
||||||
next()
|
next()
|
||||||
})
|
})
|
||||||
|
@ -4,10 +4,10 @@ import { asideCollapsedWidth } from '@/settings/designSetting'
|
|||||||
import { SettingStoreType, ToolsStatusEnum } from './settingStore.d'
|
import { SettingStoreType, ToolsStatusEnum } from './settingStore.d'
|
||||||
import { setLocalStorage, getLocalStorage } from '@/utils'
|
import { setLocalStorage, getLocalStorage } from '@/utils'
|
||||||
import { StorageEnum } from '@/enums/storageEnum'
|
import { StorageEnum } from '@/enums/storageEnum'
|
||||||
const { GO_SETTING_STORE } = StorageEnum
|
const { GO_SYSTEM_SETTING_STORE } = StorageEnum
|
||||||
|
|
||||||
const storageSetting: SettingStoreType = getLocalStorage(
|
const storageSetting: SettingStoreType = getLocalStorage(
|
||||||
GO_SETTING_STORE
|
GO_SYSTEM_SETTING_STORE
|
||||||
)
|
)
|
||||||
|
|
||||||
// 全局设置
|
// 全局设置
|
||||||
@ -48,7 +48,7 @@ export const useSettingStore = defineStore({
|
|||||||
this.$patch(state => {
|
this.$patch(state => {
|
||||||
state[key] = value
|
state[key] = value
|
||||||
})
|
})
|
||||||
setLocalStorage(GO_SETTING_STORE, this.$state)
|
setLocalStorage(GO_SYSTEM_SETTING_STORE, this.$state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -25,6 +25,23 @@ export const base64toFile = (dataurl: string, fileName: string) => {
|
|||||||
return ImageUrl
|
return ImageUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* file转 blob
|
||||||
|
* @param { File } file 文件对象
|
||||||
|
*/
|
||||||
|
export const fileToBlob = (file:File) =>{
|
||||||
|
return new Promise<Blob>(function (resolve, reject) {
|
||||||
|
let reader = new FileReader()
|
||||||
|
reader.readAsArrayBuffer(file)
|
||||||
|
reader.onload = function (e: ProgressEvent<FileReader>) {
|
||||||
|
if(e.target){
|
||||||
|
const blob = new Blob([<ArrayBuffer>e.target.result], { type: file.type });
|
||||||
|
resolve(blob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* * url转file
|
* * url转file
|
||||||
*/
|
*/
|
||||||
|
@ -1,6 +1,27 @@
|
|||||||
/**
|
/**
|
||||||
* * 请求失败统一处理
|
* 请求失败统一处理,allowRoute 允许跳转。
|
||||||
|
* @param MyResponse MyResponseType,可以为空。
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
export const httpErrorHandle = () => {
|
import { ResultEnum } from "@/enums/httpEnum"
|
||||||
|
import { PageEnum, ErrorPageNameMap } from "@/enums/pageEnum"
|
||||||
|
import { redirectErrorPage, routerTurnByName } from '@/utils'
|
||||||
|
|
||||||
|
export const httpErrorHandle = (MyResponse?:any, allowRoute:boolean = true) => {
|
||||||
|
if(MyResponse){
|
||||||
|
const {code, msg} = MyResponse
|
||||||
|
if (MyResponse.code === ResultEnum.TOKEN_OVERDUE) {
|
||||||
|
window['$message'].error(msg || window['$t']('http.token_overdue_message'))
|
||||||
|
if(allowRoute) routerTurnByName(PageEnum.BASE_LOGIN_NAME)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MyResponse.code != ResultEnum.SUCCESS) {
|
||||||
|
// 其他错误处理 Todo
|
||||||
|
if (ErrorPageNameMap.get(code) && allowRoute) {
|
||||||
|
redirectErrorPage(code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
window['$message'].error(window['$t']('http.error_message'))
|
window['$message'].error(window['$t']('http.error_message'))
|
||||||
}
|
}
|
@ -2,11 +2,10 @@ import { useRoute } from 'vue-router'
|
|||||||
import { ResultEnum, RequestHttpHeaderEnum } from '@/enums/httpEnum'
|
import { ResultEnum, RequestHttpHeaderEnum } from '@/enums/httpEnum'
|
||||||
import { ErrorPageNameMap, PageEnum, PreviewEnum } from '@/enums/pageEnum'
|
import { ErrorPageNameMap, PageEnum, PreviewEnum } from '@/enums/pageEnum'
|
||||||
import { docPath, giteeSourceCodePath } from '@/settings/pathConst'
|
import { docPath, giteeSourceCodePath } from '@/settings/pathConst'
|
||||||
import { SystemStoreEnum, SystemStoreUserInfoEnum } from '@/store/modules/systemStore/systemStore.d'
|
|
||||||
import { StorageEnum } from '@/enums/storageEnum'
|
import { StorageEnum } from '@/enums/storageEnum'
|
||||||
import { clearLocalStorage, getLocalStorage, clearCookie } from './storage'
|
import { clearLocalStorage, getLocalStorage, clearCookie } from './storage'
|
||||||
import router from '@/router'
|
import router from '@/router'
|
||||||
import { logoutApi } from '@/api/path'
|
import { BackEndFactory } from '@/backend/ibackend'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* * 根据名字跳转路由
|
* * 根据名字跳转路由
|
||||||
@ -106,11 +105,11 @@ export const reloadRoutePage = () => {
|
|||||||
*/
|
*/
|
||||||
export const logout = async () => {
|
export const logout = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await logoutApi() as unknown as MyResponseType
|
const res = await BackEndFactory.logout() as any
|
||||||
if(res.code === ResultEnum.SUCCESS) {
|
if(res.code === ResultEnum.SUCCESS) {
|
||||||
window['$message'].success(window['$t']('global.logout_success'))
|
window['$message'].success(window['$t']('global.logout_success'))
|
||||||
clearCookie(RequestHttpHeaderEnum.COOKIE)
|
clearCookie(RequestHttpHeaderEnum.COOKIE)
|
||||||
clearLocalStorage(StorageEnum.GO_SYSTEM_STORE)
|
clearLocalStorage(StorageEnum.GO_LOGIN_INFO_STORE)
|
||||||
routerTurnByName(PageEnum.BASE_LOGIN_NAME)
|
routerTurnByName(PageEnum.BASE_LOGIN_NAME)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -147,7 +146,8 @@ export const openGiteeSourceCode = () => {
|
|||||||
* @returns boolean
|
* @returns boolean
|
||||||
*/
|
*/
|
||||||
export const isPreview = () => {
|
export const isPreview = () => {
|
||||||
return document.location.hash.includes('preview')
|
return false
|
||||||
|
//return document.location.hash.includes('preview')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -163,6 +163,15 @@ export const fetchRouteParams = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const fetchRouteQuery = () => {
|
||||||
|
try {
|
||||||
|
const route = useRoute()
|
||||||
|
return route.query
|
||||||
|
} catch (error) {
|
||||||
|
window['$message'].warning('查询路由信息失败,请联系管理员!')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* * 通过硬解析获取当前路由下的参数
|
* * 通过硬解析获取当前路由下的参数
|
||||||
* @returns object
|
* @returns object
|
||||||
@ -188,18 +197,17 @@ export const goHome = () => {
|
|||||||
* * 判断是否登录
|
* * 判断是否登录
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
export const loginCheck = () => {
|
export const loginCheck = () => {
|
||||||
try {
|
try {
|
||||||
const info = getLocalStorage(StorageEnum.GO_SYSTEM_STORE)
|
const info = getLocalStorage(StorageEnum.GO_LOGIN_INFO_STORE)
|
||||||
if (!info) return false
|
if (!info) return false
|
||||||
if (info[SystemStoreEnum.USER_INFO][SystemStoreUserInfoEnum.USER_TOKEN]) {
|
// 检查 Token ?
|
||||||
return true
|
if(info.token && info.userinfo) return true
|
||||||
}
|
|
||||||
return false
|
return false
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* * 预览地址
|
* * 预览地址
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
:onBeforeUpload="beforeUploadHandle"
|
:onBeforeUpload="beforeUploadHandle"
|
||||||
>
|
>
|
||||||
<n-upload-dragger>
|
<n-upload-dragger>
|
||||||
<img v-if="canvasConfig.backgroundImage" class="upload-show" :src="canvasConfig.backgroundImage" alt="背景" />
|
<img v-if="canvasConfig.backgroundImage" class="upload-show" :src="BackEndFactory.getFileUrl(canvasConfig.backgroundImage)" alt="背景" />
|
||||||
<div class="upload-img" v-show="!canvasConfig.backgroundImage">
|
<div class="upload-img" v-show="!canvasConfig.backgroundImage">
|
||||||
<img src="@/assets/images/canvas/noImage.png" />
|
<img src="@/assets/images/canvas/noImage.png" />
|
||||||
<n-text class="upload-desc" depth="3">
|
<n-text class="upload-desc" depth="3">
|
||||||
@ -131,20 +131,19 @@ import { backgroundImageSize } from '@/settings/designSetting'
|
|||||||
import { FileTypeEnum } from '@/enums/fileTypeEnum'
|
import { FileTypeEnum } from '@/enums/fileTypeEnum'
|
||||||
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
|
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
|
||||||
import { EditCanvasConfigEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
|
import { EditCanvasConfigEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
|
||||||
import { useSystemStore } from '@/store/modules/systemStore/systemStore'
|
|
||||||
import { StylesSetting } from '@/components/Pages/ChartItemSetting'
|
import { StylesSetting } from '@/components/Pages/ChartItemSetting'
|
||||||
import { UploadCustomRequestOptions } from 'naive-ui'
|
import { UploadCustomRequestOptions } from 'naive-ui'
|
||||||
import { fileToUrl, loadAsyncComponent, fetchRouteParamsLocation } from '@/utils'
|
import { fileToUrl, loadAsyncComponent, fetchRouteParamsLocation } from '@/utils'
|
||||||
import { PreviewScaleEnum } from '@/enums/styleEnum'
|
import { PreviewScaleEnum } from '@/enums/styleEnum'
|
||||||
import { ResultEnum } from '@/enums/httpEnum'
|
import { ResultEnum } from '@/enums/httpEnum'
|
||||||
import { icon } from '@/plugins'
|
import { icon } from '@/plugins'
|
||||||
import { uploadFile} from '@/api/path'
|
import { BackEndFactory } from '@/backend/ibackend'
|
||||||
|
|
||||||
|
|
||||||
const { ColorPaletteIcon } = icon.ionicons5
|
const { ColorPaletteIcon } = icon.ionicons5
|
||||||
const { ScaleIcon, FitToScreenIcon, FitToHeightIcon, FitToWidthIcon } = icon.carbon
|
const { ScaleIcon, FitToScreenIcon, FitToHeightIcon, FitToWidthIcon } = icon.carbon
|
||||||
|
|
||||||
const chartEditStore = useChartEditStore()
|
const chartEditStore = useChartEditStore()
|
||||||
const systemStore = useSystemStore()
|
|
||||||
const canvasConfig = chartEditStore.getEditCanvasConfig
|
const canvasConfig = chartEditStore.getEditCanvasConfig
|
||||||
const editCanvas = chartEditStore.getEditCanvas
|
const editCanvas = chartEditStore.getEditCanvas
|
||||||
|
|
||||||
@ -273,25 +272,12 @@ const clearColor = () => {
|
|||||||
const customRequest = (options: UploadCustomRequestOptions) => {
|
const customRequest = (options: UploadCustomRequestOptions) => {
|
||||||
const { file } = options
|
const { file } = options
|
||||||
nextTick(async () => {
|
nextTick(async () => {
|
||||||
if(!systemStore.getFetchInfo.OSSUrl) {
|
|
||||||
window['$message'].error('添加图片失败,请刷新页面重试!')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (file.file) {
|
if (file.file) {
|
||||||
// 修改名称
|
const uploadRes = await BackEndFactory.uploadFile(file.file, null) as any
|
||||||
const newNameFile = new File(
|
|
||||||
[file.file],
|
|
||||||
`${fetchRouteParamsLocation()}_index_background.png`,
|
|
||||||
{ type: file.file.type }
|
|
||||||
)
|
|
||||||
let uploadParams = new FormData()
|
|
||||||
uploadParams.append('object', newNameFile)
|
|
||||||
const uploadRes = await uploadFile(systemStore.getFetchInfo.OSSUrl ,uploadParams) as unknown as MyResponseType
|
|
||||||
|
|
||||||
if(uploadRes.code === ResultEnum.SUCCESS) {
|
if(uploadRes.code === ResultEnum.SUCCESS) {
|
||||||
chartEditStore.setEditCanvasConfig(
|
chartEditStore.setEditCanvasConfig(
|
||||||
EditCanvasConfigEnum.BACKGROUND_IMAGE,
|
EditCanvasConfigEnum.BACKGROUND_IMAGE,
|
||||||
uploadRes.data.objectContent.httpRequest.uri
|
uploadRes.data.uri
|
||||||
)
|
)
|
||||||
chartEditStore.setEditCanvasConfig(
|
chartEditStore.setEditCanvasConfig(
|
||||||
EditCanvasConfigEnum.SELECT_COLOR,
|
EditCanvasConfigEnum.SELECT_COLOR,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<n-modal class="go-chart-data-request" v-model:show="modelShow" :mask-closable="false">
|
<n-modal class="go-chart-data-request" v-model:show="modelShow" :mask-closable="false" @esc="escHandler">
|
||||||
<n-card :bordered="false" role="dialog" size="small" aria-modal="true" style="width: 1000px; height: 800px">
|
<n-card :bordered="false" role="dialog" size="small" aria-modal="true" style="width: 1000px; height: 800px">
|
||||||
<template #header></template>
|
<template #header></template>
|
||||||
<template #header-extra> </template>
|
<template #header-extra> </template>
|
||||||
@ -55,6 +55,9 @@ const closeHandle = () => {
|
|||||||
emit('sendHandle')
|
emit('sendHandle')
|
||||||
dataSyncUpdate()
|
dataSyncUpdate()
|
||||||
}
|
}
|
||||||
|
const escHandler = ()=>{
|
||||||
|
emit('update:modelShow', false)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -0,0 +1,177 @@
|
|||||||
|
// 获取实例
|
||||||
|
const eTemplateString = `
|
||||||
|
console.log(e)
|
||||||
|
`
|
||||||
|
// 获取全局 echarts 实例
|
||||||
|
const echartsTemplateString = `
|
||||||
|
console.log(echarts)
|
||||||
|
`
|
||||||
|
|
||||||
|
// 获取当前组件图表集合
|
||||||
|
const componentsTemplateString = `
|
||||||
|
console.log(components)
|
||||||
|
`
|
||||||
|
|
||||||
|
// 获取 nodeModules 实例
|
||||||
|
const nodeModulesTemplateString = `
|
||||||
|
console.log(node_modules)
|
||||||
|
`
|
||||||
|
|
||||||
|
// 异步引入
|
||||||
|
const importTemplateString = `
|
||||||
|
await import('https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/lodash.js/4.17.21/lodash.js')
|
||||||
|
|
||||||
|
// lodash 默认赋值给 "_"
|
||||||
|
console.log('isEqual', _.isEqual(['1'], ['1']))
|
||||||
|
`
|
||||||
|
|
||||||
|
// 修改图表 tooltip
|
||||||
|
const tooltipTemplateString =
|
||||||
|
`
|
||||||
|
// 获取echart实例
|
||||||
|
const chart = this.refs.vChartRef.chart
|
||||||
|
|
||||||
|
// 图表设置tooltip
|
||||||
|
chart.setOption({
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis', //item
|
||||||
|
enterable: true,
|
||||||
|
formatter (params) {
|
||||||
|
return` +
|
||||||
|
'`' +
|
||||||
|
`
|
||||||
|
<div>
|
||||||
|
<img src="https://portrait.gitee.com/uploads/avatars/user/1654/4964818_MTrun_1653229420.png!avatar30">
|
||||||
|
<b><a href="https://gitee.com/dromara/go-view">《这是一个自定义的tooltip》</a></b>
|
||||||
|
<div>
|
||||||
|
<div style='border-radius:35px;color:#666'>
|
||||||
|
` +
|
||||||
|
'$' +
|
||||||
|
`{Object.entries(params[0].value).map(kv => ` +
|
||||||
|
'`' +
|
||||||
|
`<div>` +
|
||||||
|
'$' +
|
||||||
|
`{kv[0]}:` +
|
||||||
|
'$' +
|
||||||
|
`{kv[1]}</div>` +
|
||||||
|
'`' +
|
||||||
|
`).join('')}
|
||||||
|
</div>
|
||||||
|
` +
|
||||||
|
'`;' +
|
||||||
|
`
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
`
|
||||||
|
|
||||||
|
// 添加【轮播列表】样式
|
||||||
|
const addStyleString =
|
||||||
|
`
|
||||||
|
// 组件样式作用域标识
|
||||||
|
const scoped = this.subTree.scopeId
|
||||||
|
function loadStyleString(css){
|
||||||
|
let style = document.createElement('style')
|
||||||
|
style.type = 'text/css'
|
||||||
|
style.appendChild(document.createTextNode(css))
|
||||||
|
let head = document.getElementsByTagName('head')[0]
|
||||||
|
head.appendChild(style)
|
||||||
|
}
|
||||||
|
loadStyleString(` +
|
||||||
|
'`' +
|
||||||
|
`
|
||||||
|
.dv-scroll-board[` +
|
||||||
|
'$' +
|
||||||
|
`{scoped}] {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.dv-scroll-board[` +
|
||||||
|
'$' +
|
||||||
|
`{scoped}]::before {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: -20%;
|
||||||
|
left: -100%;
|
||||||
|
width: 550px;
|
||||||
|
height: 60px;
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
background-image: linear-gradient(rgba(0, 0, 0, 0), rgba(255, 255, 255, 0.3), rgba(0, 0, 0, 0));
|
||||||
|
animation: cross 2s infinite;
|
||||||
|
}
|
||||||
|
@keyframes cross{
|
||||||
|
to{
|
||||||
|
top: 80%;
|
||||||
|
left: 100%;
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
` +
|
||||||
|
'`' +
|
||||||
|
`)
|
||||||
|
`
|
||||||
|
|
||||||
|
// 修改地图原点大小
|
||||||
|
const editMapPointString = `
|
||||||
|
const chart = this.refs.vChartRef.chart
|
||||||
|
// 定义地图原点大小 同理可自定义标签等等内容
|
||||||
|
this.props.chartConfig.option.series[0].symbolSize = (val) => {
|
||||||
|
return Math.sqrt(val[2]) / 3;
|
||||||
|
}
|
||||||
|
this.setupState.vEchartsSetOption();
|
||||||
|
let i = 0; // 当前轮播索引
|
||||||
|
const len = 3; // 轮播部分提示
|
||||||
|
(function showTips() {
|
||||||
|
const action = (type, dataIndex) => {
|
||||||
|
chart.dispatchAction({
|
||||||
|
type,
|
||||||
|
dataIndex,
|
||||||
|
seriesIndex: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setInterval(() => {
|
||||||
|
action("downplay", i);
|
||||||
|
action("hideTip", i);
|
||||||
|
if (i === len) i = 0;
|
||||||
|
i++;
|
||||||
|
action("highlight", i);
|
||||||
|
action("showTip", i);
|
||||||
|
}, 2000);
|
||||||
|
})()
|
||||||
|
`
|
||||||
|
|
||||||
|
export const templateList = [
|
||||||
|
{
|
||||||
|
description: '获取当前组件实例',
|
||||||
|
code: eTemplateString
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: '获取全局 echarts 实例',
|
||||||
|
code: echartsTemplateString
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: '获取组件图表集合',
|
||||||
|
code: componentsTemplateString
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: '获取 nodeModules 实例',
|
||||||
|
code: nodeModulesTemplateString
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: '获取远程 CDN 库',
|
||||||
|
code: importTemplateString
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: '修改图表 tooltip',
|
||||||
|
code: tooltipTemplateString
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: '添加【轮播列表】样式',
|
||||||
|
code: addStyleString
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: '修改【地图】圆点,新增提示自动轮播',
|
||||||
|
code: editMapPointString
|
||||||
|
}
|
||||||
|
]
|
@ -0,0 +1,3 @@
|
|||||||
|
import ChartEventMonacoEditor from './index.vue'
|
||||||
|
|
||||||
|
export { ChartEventMonacoEditor }
|
@ -0,0 +1,290 @@
|
|||||||
|
<template>
|
||||||
|
<n-collapse-item title="高级事件配置" name="2">
|
||||||
|
<template #header-extra>
|
||||||
|
<n-button type="primary" tertiary size="small" @click.stop="showModal = true">
|
||||||
|
<template #icon>
|
||||||
|
<n-icon>
|
||||||
|
<pencil-icon />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
编辑
|
||||||
|
</n-button>
|
||||||
|
</template>
|
||||||
|
<n-card>
|
||||||
|
<!-- 函数体 -->
|
||||||
|
<div v-for="eventName in EventLife" :key="eventName">
|
||||||
|
<p>
|
||||||
|
<span class="func-keyword">async {{ eventName }}</span> (e, components, echarts, node_modules) {
|
||||||
|
</p>
|
||||||
|
<p class="go-ml-4"><n-code :code="(targetData.events || {})[eventName]" language="typescript"></n-code></p>
|
||||||
|
<p>}<span>,</span></p>
|
||||||
|
</div>
|
||||||
|
</n-card>
|
||||||
|
</n-collapse-item>
|
||||||
|
|
||||||
|
<!-- 弹窗 -->
|
||||||
|
<n-modal class="go-chart-data-monaco-editor" v-model:show="showModal" :mask-closable="false">
|
||||||
|
<n-card :bordered="false" role="dialog" size="small" aria-modal="true" style="width: 1200px; height: 700px">
|
||||||
|
<template #header>
|
||||||
|
<n-space>
|
||||||
|
<n-text>高级事件编辑器(配合源码使用)</n-text>
|
||||||
|
</n-space>
|
||||||
|
</template>
|
||||||
|
<template #header-extra> </template>
|
||||||
|
<n-layout has-sider sider-placement="right">
|
||||||
|
<n-layout style="height: 580px; padding-right: 20px">
|
||||||
|
<n-tabs v-model:value="editTab" type="card" tab-style="min-width: 100px;">
|
||||||
|
<!-- 提示 -->
|
||||||
|
<template #suffix>
|
||||||
|
<n-text class="tab-tip" type="warning">tips: {{ EventLifeTip[editTab] }}</n-text>
|
||||||
|
</template>
|
||||||
|
<n-tab-pane
|
||||||
|
v-for="(eventName, index) in EventLife"
|
||||||
|
:key="index"
|
||||||
|
:tab="`${EventLifeName[eventName]}-${eventName}`"
|
||||||
|
:name="eventName"
|
||||||
|
>
|
||||||
|
<!-- 函数名称 -->
|
||||||
|
<p class="go-pl-3">
|
||||||
|
<span class="func-keyword">async function </span>
|
||||||
|
<span class="func-keyNameWord">{{ eventName }}(e, components, echarts, node_modules) {</span>
|
||||||
|
</p>
|
||||||
|
<!-- 编辑主体 -->
|
||||||
|
<monaco-editor v-model:modelValue="events[eventName]" height="480px" language="javascript" />
|
||||||
|
<!-- 函数结束 -->
|
||||||
|
<p class="go-pl-3 func-keyNameWord">}</p>
|
||||||
|
</n-tab-pane>
|
||||||
|
</n-tabs>
|
||||||
|
</n-layout>
|
||||||
|
<n-layout-sider
|
||||||
|
:collapsed-width="14"
|
||||||
|
:width="340"
|
||||||
|
show-trigger="bar"
|
||||||
|
collapse-mode="transform"
|
||||||
|
content-style="padding: 12px 12px 0px 12px;margin-left: 3px;"
|
||||||
|
>
|
||||||
|
<n-tabs default-value="1" justify-content="space-evenly" type="segment">
|
||||||
|
<!-- 验证结果 -->
|
||||||
|
<n-tab-pane tab="验证结果" name="1" size="small">
|
||||||
|
<n-scrollbar trigger="none" style="max-height: 505px">
|
||||||
|
<n-collapse class="go-px-3" arrow-placement="right" :default-expanded-names="[1, 2, 3]">
|
||||||
|
<template v-for="error in [validEvents()]" :key="error">
|
||||||
|
<n-collapse-item title="错误函数" :name="1">
|
||||||
|
<n-text depth="3">{{ error.errorFn || '暂无' }}</n-text>
|
||||||
|
</n-collapse-item>
|
||||||
|
<n-collapse-item title="错误信息" :name="2">
|
||||||
|
<n-text depth="3">{{ error.name || '暂无' }}</n-text>
|
||||||
|
</n-collapse-item>
|
||||||
|
<n-collapse-item title="堆栈信息" :name="3">
|
||||||
|
<n-text depth="3">{{ error.message || '暂无' }}</n-text>
|
||||||
|
</n-collapse-item>
|
||||||
|
</template>
|
||||||
|
</n-collapse>
|
||||||
|
</n-scrollbar>
|
||||||
|
</n-tab-pane>
|
||||||
|
<!-- 辅助说明 -->
|
||||||
|
<n-tab-pane tab="变量说明" name="2">
|
||||||
|
<n-scrollbar trigger="none" style="max-height: 505px">
|
||||||
|
<n-collapse class="go-px-3" arrow-placement="right" :default-expanded-names="[1, 2, 3, 4]">
|
||||||
|
<n-collapse-item title="e" :name="1">
|
||||||
|
<n-text depth="3">触发对应生命周期事件时接收的参数</n-text>
|
||||||
|
</n-collapse-item>
|
||||||
|
<n-collapse-item title="this" :name="2">
|
||||||
|
<n-text depth="3">图表组件实例</n-text>
|
||||||
|
<br />
|
||||||
|
<n-tag class="go-m-1" v-for="prop in ['refs', 'setupState', 'ctx', 'props', '...']" :key="prop">{{
|
||||||
|
prop
|
||||||
|
}}</n-tag>
|
||||||
|
</n-collapse-item>
|
||||||
|
<n-collapse-item title="components" :name="3">
|
||||||
|
<n-text depth="3"
|
||||||
|
>当前大屏内所有组件的集合id 图表组件中的配置id,可以获取其他图表组件进行控制</n-text
|
||||||
|
>
|
||||||
|
<n-code :code="`{\n [id]: component\n}`" language="typescript"></n-code>
|
||||||
|
</n-collapse-item>
|
||||||
|
<n-collapse-item title="node_modules" :name="4">
|
||||||
|
<n-text depth="3">以下是内置在代码环境中可用的包变量</n-text>
|
||||||
|
<br />
|
||||||
|
<n-tag class="go-m-1" v-for="pkg in Object.keys(npmPkgs || {})" :key="pkg">{{ pkg }}</n-tag>
|
||||||
|
</n-collapse-item>
|
||||||
|
</n-collapse>
|
||||||
|
</n-scrollbar>
|
||||||
|
</n-tab-pane>
|
||||||
|
<!-- 介绍案例 -->
|
||||||
|
<n-tab-pane tab="介绍案例" name="3">
|
||||||
|
<n-scrollbar trigger="none" style="max-height: 505px">
|
||||||
|
<n-collapse arrow-placement="right">
|
||||||
|
<n-collapse-item
|
||||||
|
v-for="(item, index) in templateList"
|
||||||
|
:key="index"
|
||||||
|
:title="`案例${index + 1}:${item.description}`"
|
||||||
|
:name="index"
|
||||||
|
>
|
||||||
|
<n-code :code="item.code" language="typescript"></n-code>
|
||||||
|
</n-collapse-item>
|
||||||
|
</n-collapse>
|
||||||
|
</n-scrollbar>
|
||||||
|
</n-tab-pane>
|
||||||
|
</n-tabs>
|
||||||
|
</n-layout-sider>
|
||||||
|
</n-layout>
|
||||||
|
|
||||||
|
<template #action>
|
||||||
|
<n-space justify="space-between">
|
||||||
|
<div class="go-flex-items-center">
|
||||||
|
<n-tag :bordered="false" type="primary">
|
||||||
|
<template #icon>
|
||||||
|
<n-icon :component="DocumentTextIcon" />
|
||||||
|
</template>
|
||||||
|
提示
|
||||||
|
</n-tag>
|
||||||
|
<n-text class="go-ml-2" depth="2">通过提供的参数可为图表增加定制化的tooltip、交互事件等等</n-text>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<n-space>
|
||||||
|
<n-button size="medium" @click="closeEvents">取消</n-button>
|
||||||
|
<n-button size="medium" type="primary" @click="saveEvents">保存</n-button>
|
||||||
|
</n-space>
|
||||||
|
</n-space>
|
||||||
|
</template>
|
||||||
|
</n-card>
|
||||||
|
</n-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, computed, watch, toRefs, toRaw } from 'vue'
|
||||||
|
import { MonacoEditor } from '@/components/Pages/MonacoEditor'
|
||||||
|
import { useTargetData } from '../../../hooks/useTargetData.hook'
|
||||||
|
import { templateList } from './importTemplate'
|
||||||
|
import { npmPkgs } from '@/hooks'
|
||||||
|
import { icon } from '@/plugins'
|
||||||
|
import { goDialog, toString } from '@/utils'
|
||||||
|
import { CreateComponentType, EventLife } from '@/packages/index.d'
|
||||||
|
import { Script } from 'vm'
|
||||||
|
|
||||||
|
const { targetData, chartEditStore } = useTargetData()
|
||||||
|
const { DocumentTextIcon, ChevronDownIcon, PencilIcon } = icon.ionicons5
|
||||||
|
|
||||||
|
const EventLifeName = {
|
||||||
|
[EventLife.BEFORE_MOUNT]: '渲染之前',
|
||||||
|
[EventLife.MOUNTED]: '渲染之后',
|
||||||
|
[EventLife.MOUSE_CLICK] : '点击',
|
||||||
|
[EventLife.MOUSE_OVER] : "进入",
|
||||||
|
[EventLife.MOUSE_LEAVE] : "离开",
|
||||||
|
[EventLife.ECHART_LEGEND_SELECT_CHANGED] : "选择图例",
|
||||||
|
[EventLife.ECHART_HIGH_LIGHT] : "高亮"
|
||||||
|
}
|
||||||
|
|
||||||
|
const EventLifeTip = {
|
||||||
|
[EventLife.BEFORE_MOUNT]: '此时组件 DOM 还未存在',
|
||||||
|
[EventLife.MOUNTED]: '此时组件 DOM 已经存在'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 受控弹窗
|
||||||
|
const showModal = ref(false)
|
||||||
|
// 编辑区域控制
|
||||||
|
const editTab = ref(EventLife.MOUNTED as EventLife.MOUNTED)
|
||||||
|
// events 函数模板
|
||||||
|
let events = ref({ ...targetData.value.events })
|
||||||
|
// 事件错误标识
|
||||||
|
const errorFlag = ref(false)
|
||||||
|
|
||||||
|
// 验证语法
|
||||||
|
const validEvents = () => {
|
||||||
|
let errorFn = ''
|
||||||
|
let message = ''
|
||||||
|
let name = ''
|
||||||
|
|
||||||
|
errorFlag.value = Object.entries(events.value).every(([eventName, str]) => {
|
||||||
|
try {
|
||||||
|
// 支持await,验证语法
|
||||||
|
const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor
|
||||||
|
new AsyncFunction(str)
|
||||||
|
return true
|
||||||
|
} catch (error: any) {
|
||||||
|
message = error.message
|
||||||
|
name = error.name
|
||||||
|
errorFn = eventName
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
errorFn,
|
||||||
|
message,
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭事件
|
||||||
|
const closeEvents = () => {
|
||||||
|
showModal.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增事件
|
||||||
|
const saveEvents = () => {
|
||||||
|
if (validEvents().errorFn) {
|
||||||
|
window['$message'].error('事件函数错误,无法进行保存')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (Object.values(events.value).join('').trim() === '') {
|
||||||
|
// 清空事件
|
||||||
|
targetData.value.events = undefined
|
||||||
|
} else {
|
||||||
|
targetData.value.events = { ...events.value }
|
||||||
|
}
|
||||||
|
closeEvents()
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => showModal.value,
|
||||||
|
(newData: boolean) => {
|
||||||
|
if (newData) {
|
||||||
|
events.value = { ...targetData.value.events }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
/* 外层也要使用 */
|
||||||
|
.func-keyword {
|
||||||
|
color: #b478cf;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include go('chart-data-monaco-editor') {
|
||||||
|
.func-keyNameWord {
|
||||||
|
color: #70c0e8;
|
||||||
|
}
|
||||||
|
.tab-tip {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
&.n-card.n-modal,
|
||||||
|
.n-card {
|
||||||
|
@extend .go-background-filter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include deep() {
|
||||||
|
.n-layout,
|
||||||
|
.n-layout-sider {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
.go-editor-area {
|
||||||
|
max-height: 530px;
|
||||||
|
}
|
||||||
|
.checkbox--hidden:checked {
|
||||||
|
& + label {
|
||||||
|
.n-icon {
|
||||||
|
transition: all 0.3s;
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
& ~ .go-editor-area {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 优化代码换行
|
||||||
|
.n-code > pre {
|
||||||
|
white-space: break-spaces;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,24 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 事件配置 -->
|
||||||
|
<n-collapse class="go-mt-3" arrow-placement="right" :default-expanded-names="['1', '2']">
|
||||||
|
<n-text depth="3">
|
||||||
|
组件 id:
|
||||||
|
<n-text>{{ targetData.id }}</n-text>
|
||||||
|
</n-text>
|
||||||
|
<n-collapse-item title="基础事件配置" name="1">
|
||||||
|
<div class="go-event">
|
||||||
|
<n-text depth="3"> 【单击、双击、移入、移出】尽情期待! </n-text>
|
||||||
|
</div>
|
||||||
|
</n-collapse-item>
|
||||||
|
<chart-event-monaco-editor></chart-event-monaco-editor>
|
||||||
|
</n-collapse>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { ChartEventMonacoEditor } from './components/ChartEventMonacoEditor'
|
||||||
|
import { useTargetData } from '../hooks/useTargetData.hook'
|
||||||
|
|
||||||
|
const { targetData } = useTargetData()
|
||||||
|
const showModal = ref(false)
|
||||||
|
</script>
|
@ -3,4 +3,5 @@ export enum TabsEnum {
|
|||||||
CHART_SETTING = 'chartSetting',
|
CHART_SETTING = 'chartSetting',
|
||||||
CHART_ANIMATION = 'chartAnimation',
|
CHART_ANIMATION = 'chartAnimation',
|
||||||
CHART_DATA = 'chartData',
|
CHART_DATA = 'chartData',
|
||||||
|
CHART_EVENT = 'chartEvent'
|
||||||
}
|
}
|
||||||
|
@ -75,12 +75,13 @@ const { getDetails } = toRefs(useChartLayoutStore())
|
|||||||
const { setItem } = useChartLayoutStore()
|
const { setItem } = useChartLayoutStore()
|
||||||
const chartEditStore = useChartEditStore()
|
const chartEditStore = useChartEditStore()
|
||||||
|
|
||||||
const { ConstructIcon, FlashIcon, DesktopOutlineIcon, LeafIcon } = icon.ionicons5
|
const { ConstructIcon, FlashIcon, DesktopOutlineIcon, LeafIcon, RocketIcon } = icon.ionicons5
|
||||||
|
|
||||||
const ContentEdit = loadAsyncComponent(() => import('../ContentEdit/index.vue'))
|
const ContentEdit = loadAsyncComponent(() => import('../ContentEdit/index.vue'))
|
||||||
const CanvasPage = loadAsyncComponent(() => import('./components/CanvasPage/index.vue'))
|
const CanvasPage = loadAsyncComponent(() => import('./components/CanvasPage/index.vue'))
|
||||||
const ChartSetting = loadAsyncComponent(() => import('./components/ChartSetting/index.vue'))
|
const ChartSetting = loadAsyncComponent(() => import('./components/ChartSetting/index.vue'))
|
||||||
const ChartData = loadAsyncComponent(() => import('./components/ChartData/index.vue'))
|
const ChartData = loadAsyncComponent(() => import('./components/ChartData/index.vue'))
|
||||||
|
const ChartEvent = loadAsyncComponent(() => import('./components/ChartEvent/index.vue'))
|
||||||
const ChartAnimation = loadAsyncComponent(() => import('./components/ChartAnimation/index.vue'))
|
const ChartAnimation = loadAsyncComponent(() => import('./components/ChartAnimation/index.vue'))
|
||||||
|
|
||||||
const collapsed = ref<boolean>(getDetails.value)
|
const collapsed = ref<boolean>(getDetails.value)
|
||||||
@ -148,6 +149,12 @@ const chartsTabList = [
|
|||||||
title: '数据',
|
title: '数据',
|
||||||
icon: FlashIcon,
|
icon: FlashIcon,
|
||||||
render: ChartData
|
render: ChartData
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: TabsEnum.CHART_EVENT,
|
||||||
|
title: '事件',
|
||||||
|
icon: RocketIcon,
|
||||||
|
render: ChartEvent
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
@ -102,6 +102,7 @@ import { EditRule } from './components/EditRule'
|
|||||||
import { EditBottom } from './components/EditBottom'
|
import { EditBottom } from './components/EditBottom'
|
||||||
import { EditShapeBox } from './components/EditShapeBox'
|
import { EditShapeBox } from './components/EditShapeBox'
|
||||||
import { EditTools } from './components/EditTools'
|
import { EditTools } from './components/EditTools'
|
||||||
|
import { BackEndFactory } from '@/backend/ibackend'
|
||||||
|
|
||||||
const chartEditStore = useChartEditStore()
|
const chartEditStore = useChartEditStore()
|
||||||
const { handleContextMenu } = useContextMenu()
|
const { handleContextMenu } = useContextMenu()
|
||||||
@ -158,7 +159,7 @@ const filterShow = computed(() => {
|
|||||||
const rangeStyle = computed(() => {
|
const rangeStyle = computed(() => {
|
||||||
// 设置背景色和图片背景
|
// 设置背景色和图片背景
|
||||||
const background = chartEditStore.getEditCanvasConfig.background
|
const background = chartEditStore.getEditCanvasConfig.background
|
||||||
const backgroundImage = chartEditStore.getEditCanvasConfig.backgroundImage
|
const backgroundImage = BackEndFactory.getFileUrl(chartEditStore.getEditCanvasConfig.backgroundImage as string)
|
||||||
const selectColor = chartEditStore.getEditCanvasConfig.selectColor
|
const selectColor = chartEditStore.getEditCanvasConfig.selectColor
|
||||||
const backgroundColor = background ? background : undefined
|
const backgroundColor = background ? background : undefined
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ import { ChartLayoutStoreEnum } from '@/store/modules/chartLayoutStore/chartLayo
|
|||||||
const { LayersIcon, BarChartIcon, PrismIcon, HomeIcon, ArrowBackIcon, ArrowForwardIcon } = icon.ionicons5
|
const { LayersIcon, BarChartIcon, PrismIcon, HomeIcon, ArrowBackIcon, ArrowForwardIcon } = icon.ionicons5
|
||||||
const { SaveIcon } = icon.carbon
|
const { SaveIcon } = icon.carbon
|
||||||
const { setItem } = useChartLayoutStore()
|
const { setItem } = useChartLayoutStore()
|
||||||
const { dataSyncUpdate } = useSync()
|
const { dataSyncUpdate, removeIntervalDataSync } = useSync()
|
||||||
const { getLayers, getCharts, getDetails } = toRefs(useChartLayoutStore())
|
const { getLayers, getCharts, getDetails } = toRefs(useChartLayoutStore())
|
||||||
const chartEditStore = useChartEditStore()
|
const chartEditStore = useChartEditStore()
|
||||||
const chartHistoryStore = useChartHistoryStore()
|
const chartHistoryStore = useChartHistoryStore()
|
||||||
@ -153,6 +153,7 @@ const goHomeHandle = () => {
|
|||||||
onPositiveCallback: () => {
|
onPositiveCallback: () => {
|
||||||
goHome()
|
goHome()
|
||||||
useRemoveKeyboard()
|
useRemoveKeyboard()
|
||||||
|
removeIntervalDataSync()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ import { StorageEnum } from '@/enums/storageEnum'
|
|||||||
import { ResultEnum } from '@/enums/httpEnum'
|
import { ResultEnum } from '@/enums/httpEnum'
|
||||||
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
|
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
|
||||||
import { ProjectInfoEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
|
import { ProjectInfoEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
|
||||||
import { updateProjectApi } from '@/api/path'
|
import { BackEndFactory } from '@/backend/ibackend'
|
||||||
import {
|
import {
|
||||||
previewPath,
|
previewPath,
|
||||||
renderIcon,
|
renderIcon,
|
||||||
@ -148,11 +148,11 @@ const copyPreviewPath = (successText?: string, failureText?: string) => {
|
|||||||
|
|
||||||
// 发布
|
// 发布
|
||||||
const sendHandle = async () => {
|
const sendHandle = async () => {
|
||||||
const res = (await updateProjectApi({
|
const res = (await BackEndFactory.updateProject({
|
||||||
id: fetchRouteParamsLocation(),
|
projectId: fetchRouteParamsLocation(),
|
||||||
// 反过来
|
// 反过来
|
||||||
state: release.value ? -1 : 1,
|
release: release.value ? -1 : 1,
|
||||||
})) as unknown as MyResponseType
|
})) as any
|
||||||
|
|
||||||
if (res.code === ResultEnum.SUCCESS) {
|
if (res.code === ResultEnum.SUCCESS) {
|
||||||
modelShowHandle()
|
modelShowHandle()
|
||||||
|
@ -32,9 +32,10 @@ import { ResultEnum } from '@/enums/httpEnum'
|
|||||||
import { fetchRouteParamsLocation, httpErrorHandle } from '@/utils'
|
import { fetchRouteParamsLocation, httpErrorHandle } from '@/utils'
|
||||||
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
|
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
|
||||||
import { ProjectInfoEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
|
import { ProjectInfoEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
|
||||||
import { updateProjectApi } from '@/api/path'
|
|
||||||
import { useSync } from '../../hooks/useSync.hook'
|
import { useSync } from '../../hooks/useSync.hook'
|
||||||
import { icon } from '@/plugins'
|
import { icon } from '@/plugins'
|
||||||
|
import { BackEndFactory } from '@/backend/ibackend'
|
||||||
|
|
||||||
const chartEditStore = useChartEditStore()
|
const chartEditStore = useChartEditStore()
|
||||||
const { dataSyncUpdate } = useSync()
|
const { dataSyncUpdate } = useSync()
|
||||||
@ -64,10 +65,10 @@ const handleFocus = () => {
|
|||||||
const handleBlur = async () => {
|
const handleBlur = async () => {
|
||||||
focus.value = false
|
focus.value = false
|
||||||
chartEditStore.setProjectInfo(ProjectInfoEnum.PROJECT_NAME, title.value || '')
|
chartEditStore.setProjectInfo(ProjectInfoEnum.PROJECT_NAME, title.value || '')
|
||||||
const res = (await updateProjectApi({
|
const res = (await BackEndFactory.updateProject({
|
||||||
id: fetchRouteParamsLocation(),
|
projectId: fetchRouteParamsLocation(),
|
||||||
projectName: title.value
|
projectName: title.value
|
||||||
})) as unknown as MyResponseType
|
})) as any
|
||||||
if (res.code === ResultEnum.SUCCESS) {
|
if (res.code === ResultEnum.SUCCESS) {
|
||||||
dataSyncUpdate()
|
dataSyncUpdate()
|
||||||
} else {
|
} else {
|
||||||
|
@ -4,14 +4,14 @@ import { getUUID, httpErrorHandle, fetchRouteParamsLocation, base64toFile } from
|
|||||||
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
|
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
|
||||||
import { EditCanvasTypeEnum, ChartEditStoreEnum, ProjectInfoEnum, ChartEditStorage } from '@/store/modules/chartEditStore/chartEditStore.d'
|
import { EditCanvasTypeEnum, ChartEditStoreEnum, ProjectInfoEnum, ChartEditStorage } from '@/store/modules/chartEditStore/chartEditStore.d'
|
||||||
import { useChartHistoryStore } from '@/store/modules/chartHistoryStore/chartHistoryStore'
|
import { useChartHistoryStore } from '@/store/modules/chartHistoryStore/chartHistoryStore'
|
||||||
import { useSystemStore } from '@/store/modules/systemStore/systemStore'
|
//import { useSystemStore } from '@/store/modules/systemStore/systemStore'
|
||||||
import { fetchChartComponent, fetchConfigComponent, createComponent } from '@/packages/index'
|
import { fetchChartComponent, fetchConfigComponent, createComponent } from '@/packages/index'
|
||||||
import { saveInterval } from '@/settings/designSetting'
|
import { saveInterval } from '@/settings/designSetting'
|
||||||
import throttle from 'lodash/throttle'
|
import throttle from 'lodash/throttle'
|
||||||
// 接口状态
|
// 接口状态
|
||||||
import { ResultEnum } from '@/enums/httpEnum'
|
import { ResultEnum } from '@/enums/httpEnum'
|
||||||
// 接口
|
// 接口
|
||||||
import { saveProjectApi, fetchProjectApi, uploadFile, updateProjectApi } from '@/api/path'
|
import { BackEndFactory } from '@/backend/ibackend'
|
||||||
// 画布枚举
|
// 画布枚举
|
||||||
import { SyncEnum } from '@/enums/editPageEnum'
|
import { SyncEnum } from '@/enums/editPageEnum'
|
||||||
import { CreateComponentType, CreateComponentGroupType, ConfigType } from '@/packages/index.d'
|
import { CreateComponentType, CreateComponentGroupType, ConfigType } from '@/packages/index.d'
|
||||||
@ -45,7 +45,6 @@ const componentMerge = (object: any, sources: any, notComponent = false) => {
|
|||||||
export const useSync = () => {
|
export const useSync = () => {
|
||||||
const chartEditStore = useChartEditStore()
|
const chartEditStore = useChartEditStore()
|
||||||
const chartHistoryStore = useChartHistoryStore()
|
const chartHistoryStore = useChartHistoryStore()
|
||||||
const systemStore = useSystemStore()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* * 组件动态注册
|
* * 组件动态注册
|
||||||
@ -53,7 +52,7 @@ export const useSync = () => {
|
|||||||
* @param isReplace 是否替换数据
|
* @param isReplace 是否替换数据
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const updateComponent = async (projectData: ChartEditStorage, isReplace = false, changeId = false) => {
|
const updateComponent = async (projectData: ChartEditStorage, isReplace = false, changeId = false, isHistory = true) => {
|
||||||
if (isReplace) {
|
if (isReplace) {
|
||||||
// 清除列表
|
// 清除列表
|
||||||
chartEditStore.componentList = []
|
chartEditStore.componentList = []
|
||||||
@ -97,10 +96,10 @@ export const useSync = () => {
|
|||||||
chartEditStore.addComponentList(
|
chartEditStore.addComponentList(
|
||||||
componentMerge(newComponent, { ..._componentInstance, id: getUUID() }),
|
componentMerge(newComponent, { ..._componentInstance, id: getUUID() }),
|
||||||
false,
|
false,
|
||||||
true
|
isHistory
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
chartEditStore.addComponentList(componentMerge(newComponent, _componentInstance), false, true)
|
chartEditStore.addComponentList(componentMerge(newComponent, _componentInstance), false, isHistory)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -129,7 +128,7 @@ export const useSync = () => {
|
|||||||
groupClass.groupList = targetList
|
groupClass.groupList = targetList
|
||||||
|
|
||||||
// 分组插入到列表
|
// 分组插入到列表
|
||||||
chartEditStore.addComponentList(groupClass, false, true)
|
chartEditStore.addComponentList(groupClass, false, isHistory)
|
||||||
} else {
|
} else {
|
||||||
await create(comItem as CreateComponentType)
|
await create(comItem as CreateComponentType)
|
||||||
}
|
}
|
||||||
@ -171,16 +170,17 @@ export const useSync = () => {
|
|||||||
const dataSyncFetch = async () => {
|
const dataSyncFetch = async () => {
|
||||||
chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.START)
|
chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.START)
|
||||||
try {
|
try {
|
||||||
const res = await fetchProjectApi({ projectId: fetchRouteParamsLocation() }) as unknown as MyResponseType
|
const res = await BackEndFactory.fetchProject({ projectId: fetchRouteParamsLocation() }) as any
|
||||||
if (res.code === ResultEnum.SUCCESS) {
|
if (res.code === ResultEnum.SUCCESS) {
|
||||||
if (res.data) {
|
if (res.data) {
|
||||||
updateStoreInfo(res.data)
|
updateStoreInfo(res.data)
|
||||||
// 更新全局数据
|
// 更新全局数据
|
||||||
await updateComponent(JSON.parse(res.data.content))
|
if(res.data.content && res.data.content != "{}"){
|
||||||
return
|
await updateComponent(JSON.parse(res.data.content), true, false, false)
|
||||||
}else {
|
return
|
||||||
chartEditStore.setProjectInfo(ProjectInfoEnum.PROJECT_ID, fetchRouteParamsLocation())
|
}
|
||||||
}
|
}
|
||||||
|
chartEditStore.setProjectInfo(ProjectInfoEnum.PROJECT_ID, fetchRouteParamsLocation())
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.SUCCESS)
|
chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.SUCCESS)
|
||||||
}, 1000)
|
}, 1000)
|
||||||
@ -197,11 +197,6 @@ export const useSync = () => {
|
|||||||
const dataSyncUpdate = throttle(async () => {
|
const dataSyncUpdate = throttle(async () => {
|
||||||
if(!fetchRouteParamsLocation()) return
|
if(!fetchRouteParamsLocation()) return
|
||||||
|
|
||||||
if(!systemStore.getFetchInfo.OSSUrl) {
|
|
||||||
window['$message'].error('数据保存失败,请刷新页面重试!')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let projectId = chartEditStore.getProjectInfo[ProjectInfoEnum.PROJECT_ID];
|
let projectId = chartEditStore.getProjectInfo[ProjectInfoEnum.PROJECT_ID];
|
||||||
if(projectId === null || projectId === ''){
|
if(projectId === null || projectId === ''){
|
||||||
window['$message'].error('数据初未始化成功,请刷新页面!')
|
window['$message'].error('数据初未始化成功,请刷新页面!')
|
||||||
@ -219,23 +214,12 @@ export const useSync = () => {
|
|||||||
useCORS: true
|
useCORS: true
|
||||||
})
|
})
|
||||||
|
|
||||||
// 上传预览图
|
// 保存数据和预览图
|
||||||
let uploadParams = new FormData()
|
const res= await BackEndFactory.updateProject({
|
||||||
uploadParams.append('object', base64toFile(canvasImage.toDataURL(), `${fetchRouteParamsLocation()}_index_preview.png`))
|
projectId,
|
||||||
const uploadRes = await uploadFile(systemStore.getFetchInfo.OSSUrl, uploadParams) as unknown as MyResponseType
|
content:JSON.stringify(chartEditStore.getStorageInfo || {}),
|
||||||
// 保存预览图
|
object:base64toFile(canvasImage.toDataURL(), `${fetchRouteParamsLocation()}_index_preview.png`)
|
||||||
if(uploadRes.code === ResultEnum.SUCCESS) {
|
}) as any
|
||||||
await updateProjectApi({
|
|
||||||
id: fetchRouteParamsLocation(),
|
|
||||||
indexImage: uploadRes.data.objectContent.httpRequest.uri
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存数据
|
|
||||||
let params = new FormData()
|
|
||||||
params.append('projectId', projectId)
|
|
||||||
params.append('content', JSON.stringify(chartEditStore.getStorageInfo || {}))
|
|
||||||
const res= await saveProjectApi(params) as unknown as MyResponseType
|
|
||||||
|
|
||||||
if (res.code === ResultEnum.SUCCESS) {
|
if (res.code === ResultEnum.SUCCESS) {
|
||||||
// 成功状态
|
// 成功状态
|
||||||
@ -244,21 +228,24 @@ export const useSync = () => {
|
|||||||
}, 1000)
|
}, 1000)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
//提示
|
||||||
|
window['$message'].success(window['$t']('global.r_save_fail'))
|
||||||
// 失败状态
|
// 失败状态
|
||||||
chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.FAILURE)
|
chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.FAILURE)
|
||||||
}, 3000)
|
}, 3000)
|
||||||
|
|
||||||
|
let syncTiming:any
|
||||||
// * 定时处理
|
// * 定时处理
|
||||||
const intervalDataSyncUpdate = () => {
|
const intervalDataSyncUpdate = () => {
|
||||||
// 定时获取数据
|
// 定时获取数据
|
||||||
const syncTiming = setInterval(() => {
|
syncTiming = setInterval(() => {
|
||||||
dataSyncUpdate()
|
dataSyncUpdate()
|
||||||
}, saveInterval * 1000)
|
}, saveInterval * 1000)
|
||||||
|
}
|
||||||
// 销毁
|
|
||||||
onUnmounted(() => {
|
// 卸载监听事件
|
||||||
clearInterval(syncTiming)
|
const removeIntervalDataSync = () => {
|
||||||
})
|
clearInterval(syncTiming)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -266,6 +253,7 @@ export const useSync = () => {
|
|||||||
updateStoreInfo,
|
updateStoreInfo,
|
||||||
dataSyncFetch,
|
dataSyncFetch,
|
||||||
dataSyncUpdate,
|
dataSyncUpdate,
|
||||||
intervalDataSyncUpdate
|
intervalDataSyncUpdate,
|
||||||
|
removeIntervalDataSync
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,38 +118,49 @@
|
|||||||
import { reactive, ref, onMounted } from 'vue'
|
import { reactive, ref, onMounted } from 'vue'
|
||||||
import shuffle from 'lodash/shuffle'
|
import shuffle from 'lodash/shuffle'
|
||||||
import { carouselInterval } from '@/settings/designSetting'
|
import { carouselInterval } from '@/settings/designSetting'
|
||||||
import { useSystemStore } from '@/store/modules/systemStore/systemStore'
|
import { useDesignStore } from '@/store/modules/designStore/designStore'
|
||||||
import { SystemStoreUserInfoEnum, SystemStoreEnum } from '@/store/modules/systemStore/systemStore.d'
|
|
||||||
import { GoThemeSelect } from '@/components/GoThemeSelect'
|
import { GoThemeSelect } from '@/components/GoThemeSelect'
|
||||||
import { GoLangSelect } from '@/components/GoLangSelect'
|
import { GoLangSelect } from '@/components/GoLangSelect'
|
||||||
import { LayoutHeader } from '@/layout/components/LayoutHeader'
|
import { LayoutHeader } from '@/layout/components/LayoutHeader'
|
||||||
import { LayoutFooter } from '@/layout/components/LayoutFooter'
|
import { LayoutFooter } from '@/layout/components/LayoutFooter'
|
||||||
import { PageEnum } from '@/enums/pageEnum'
|
import { PageEnum } from '@/enums/pageEnum'
|
||||||
import { StorageEnum } from '@/enums/storageEnum'
|
import { ResultEnum } from '@/enums/httpEnum'
|
||||||
import { icon } from '@/plugins'
|
import { icon } from '@/plugins'
|
||||||
import { routerTurnByName } from '@/utils'
|
import { StorageEnum } from '@/enums/storageEnum'
|
||||||
import { loginApi } from '@/api/path'
|
import { routerTurnByName, cryptoEncode, setLocalStorage, clearLocalStorage } from '@/utils'
|
||||||
|
|
||||||
|
import { BackEndFactory } from '@/backend/ibackend'
|
||||||
|
|
||||||
|
const { GO_LOGIN_INFO_STORE } = StorageEnum
|
||||||
|
|
||||||
|
const { PersonOutlineIcon, LockClosedOutlineIcon } = icon.ionicons5
|
||||||
|
|
||||||
interface FormState {
|
interface FormState {
|
||||||
username: string
|
username: string
|
||||||
password: string
|
password: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const { GO_SYSTEM_STORE } = StorageEnum
|
|
||||||
const { PersonOutlineIcon, LockClosedOutlineIcon } = icon.ionicons5
|
|
||||||
|
|
||||||
const formRef = ref()
|
const formRef = ref()
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const autoLogin = ref(true)
|
const autoLogin = ref(true)
|
||||||
const show = ref(false)
|
const show = ref(false)
|
||||||
const showBg = ref(false)
|
const showBg = ref(false)
|
||||||
const systemStore = useSystemStore()
|
const designStore = useDesignStore()
|
||||||
|
|
||||||
const t = window['$t']
|
const t = window['$t']
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
show.value = true
|
||||||
|
}, 300)
|
||||||
|
setTimeout(() => {
|
||||||
|
showBg.value = true
|
||||||
|
}, 100)
|
||||||
|
})
|
||||||
|
|
||||||
const formInline = reactive({
|
const formInline = reactive({
|
||||||
username: 'admin',
|
username: 'admin',
|
||||||
password: 'admin',
|
password: '123456',
|
||||||
})
|
})
|
||||||
|
|
||||||
const rules = {
|
const rules = {
|
||||||
@ -189,57 +200,43 @@ const getImageUrl = (name: string, folder: string) => {
|
|||||||
return new URL(`../../assets/images/${folder}/${name}.png`, import.meta.url).href
|
return new URL(`../../assets/images/${folder}/${name}.png`, import.meta.url).href
|
||||||
}
|
}
|
||||||
|
|
||||||
// 打乱图片顺序
|
// 打乱
|
||||||
const shuffleHandle = () => {
|
const shuffleHandle = () => {
|
||||||
shuffleTimiing.value = setInterval(() => {
|
shuffleTimiing.value = setInterval(() => {
|
||||||
bgList.value = shuffle(bgList.value)
|
bgList.value = shuffle(bgList.value)
|
||||||
}, carouselInterval)
|
}, carouselInterval)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 登录
|
// 点击事件
|
||||||
const handleSubmit = async (e: Event) => {
|
const handleSubmit = (e: Event) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
formRef.value.validate(async (errors: any) => {
|
formRef.value.validate(async (errors: any) => {
|
||||||
if (!errors) {
|
if (!errors) {
|
||||||
const { username, password } = formInline
|
const { username, password } = formInline
|
||||||
loading.value = true
|
loading.value = true
|
||||||
// 提交请求
|
clearLocalStorage(GO_LOGIN_INFO_STORE)
|
||||||
const res = await loginApi({
|
const res = await BackEndFactory.login({
|
||||||
username,
|
username,
|
||||||
password
|
password
|
||||||
}) as unknown as MyResponseType
|
}) as any
|
||||||
if(res.data) {
|
loading.value = false
|
||||||
const { tokenValue, tokenName } = res.data.token
|
if(res.code=== ResultEnum.SUCCESS && res.data) {
|
||||||
const { nickname, username, id } = res.data.userinfo
|
// const { tokenValue, tokenName } = res.data.token
|
||||||
|
// const { nickname, username, id } = res.data.userinfo
|
||||||
// 存储到 pinia
|
// 保存登陆信息
|
||||||
systemStore.setItem(SystemStoreEnum.USER_INFO, {
|
setLocalStorage( GO_LOGIN_INFO_STORE, res.data)
|
||||||
[SystemStoreUserInfoEnum.USER_TOKEN]: tokenValue,
|
|
||||||
[SystemStoreUserInfoEnum.TOKEN_NAME]: tokenName,
|
|
||||||
[SystemStoreUserInfoEnum.USER_ID]: id,
|
|
||||||
[SystemStoreUserInfoEnum.USER_NAME]: username,
|
|
||||||
[SystemStoreUserInfoEnum.NICK_NAME]: nickname,
|
|
||||||
t
|
|
||||||
})
|
|
||||||
|
|
||||||
window['$message'].success(t('login.login_success'))
|
window['$message'].success(t('login.login_success'))
|
||||||
routerTurnByName(PageEnum.BASE_HOME_NAME, true)
|
routerTurnByName(PageEnum.BASE_HOME_NAME, true)
|
||||||
|
}else{
|
||||||
|
window['$message'].error(res.msg ||`${t('login.login_error')}!`)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
window['$message'].error(t('login.login_message'))
|
window['$message'].error(`${t('login.login_message')}!`)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
setTimeout(() => {
|
|
||||||
show.value = true
|
|
||||||
}, 300)
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
showBg.value = true
|
|
||||||
}, 100)
|
|
||||||
|
|
||||||
shuffleHandle()
|
shuffleHandle()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
:themeSetting="themeSetting"
|
:themeSetting="themeSetting"
|
||||||
:themeColor="themeColor"
|
:themeColor="themeColor"
|
||||||
:style="{ ...getSizeStyle(item.attr) }"
|
:style="{ ...getSizeStyle(item.attr) }"
|
||||||
|
v-on="useLifeHandler(item)"
|
||||||
></component>
|
></component>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -27,7 +28,7 @@ import { PropType } from 'vue'
|
|||||||
import { CreateComponentGroupType } from '@/packages/index.d'
|
import { CreateComponentGroupType } from '@/packages/index.d'
|
||||||
import { animationsClass, getFilterStyle, getTransformStyle, getBlendModeStyle } from '@/utils'
|
import { animationsClass, getFilterStyle, getTransformStyle, getBlendModeStyle } from '@/utils'
|
||||||
import { getSizeStyle, getComponentAttrStyle, getStatusStyle } from '../../utils'
|
import { getSizeStyle, getComponentAttrStyle, getStatusStyle } from '../../utils'
|
||||||
|
import { useLifeHandler } from '@/hooks'
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
groupData: {
|
groupData: {
|
||||||
type: Object as PropType<CreateComponentGroupType>,
|
type: Object as PropType<CreateComponentGroupType>,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="chart-item"
|
class="chart-item"
|
||||||
v-for="(item, index) in localStorageInfo.componentList"
|
v-for="(item, index) in reactiveList"
|
||||||
:class="animationsClass(item.styles.animations)"
|
:class="animationsClass(item.styles.animations)"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
:style="{
|
:style="{
|
||||||
@ -19,6 +19,7 @@
|
|||||||
:groupIndex="index"
|
:groupIndex="index"
|
||||||
:themeSetting="themeSetting"
|
:themeSetting="themeSetting"
|
||||||
:themeColor="themeColor"
|
:themeColor="themeColor"
|
||||||
|
v-on="useLifeHandler(item)"
|
||||||
></preview-render-group>
|
></preview-render-group>
|
||||||
|
|
||||||
<!-- 单组件 -->
|
<!-- 单组件 -->
|
||||||
@ -29,19 +30,20 @@
|
|||||||
:themeSetting="themeSetting"
|
:themeSetting="themeSetting"
|
||||||
:themeColor="themeColor"
|
:themeColor="themeColor"
|
||||||
:style="{ ...getSizeStyle(item.attr) }"
|
:style="{ ...getSizeStyle(item.attr) }"
|
||||||
|
v-on="useLifeHandler(item)"
|
||||||
></component>
|
></component>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { PropType, computed } from 'vue'
|
import { PropType, computed, reactive } from 'vue'
|
||||||
import { ChartEditStorageType } from '../../index.d'
|
import { ChartEditStorageType } from '../../index.d'
|
||||||
import { PreviewRenderGroup } from '../PreviewRenderGroup/index'
|
import { PreviewRenderGroup } from '../PreviewRenderGroup/index'
|
||||||
import { CreateComponentGroupType } from '@/packages/index.d'
|
import { CreateComponentGroupType } from '@/packages/index.d'
|
||||||
import { chartColors } from '@/settings/chartThemes/index'
|
import { chartColors } from '@/settings/chartThemes/index'
|
||||||
import { animationsClass, getFilterStyle, getTransformStyle, getBlendModeStyle } from '@/utils'
|
import { animationsClass, getFilterStyle, getTransformStyle, getBlendModeStyle } from '@/utils'
|
||||||
import { getSizeStyle, getComponentAttrStyle, getStatusStyle } from '../../utils'
|
import { getSizeStyle, getComponentAttrStyle, getStatusStyle } from '../../utils'
|
||||||
|
import { useLifeHandler } from '@/hooks'
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
localStorageInfo: {
|
localStorageInfo: {
|
||||||
type: Object as PropType<ChartEditStorageType>,
|
type: Object as PropType<ChartEditStorageType>,
|
||||||
@ -49,6 +51,7 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const reactiveList = reactive(props.localStorageInfo.componentList)
|
||||||
// 主题色
|
// 主题色
|
||||||
const themeSetting = computed(() => {
|
const themeSetting = computed(() => {
|
||||||
const chartThemeSetting = props.localStorageInfo.editCanvasConfig.chartThemeSetting
|
const chartThemeSetting = props.localStorageInfo.editCanvasConfig.chartThemeSetting
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { getSessionStorage, fetchRouteParamsLocation, httpErrorHandle } from '@/utils'
|
import { loginCheck, getSessionStorage, fetchRouteParamsLocation, httpErrorHandle, fetchRouteParams, fetchRouteQuery, setLocalStorage } from '@/utils'
|
||||||
import { ResultEnum } from '@/enums/httpEnum'
|
import { ResultEnum } from '@/enums/httpEnum'
|
||||||
import { StorageEnum } from '@/enums/storageEnum'
|
import { StorageEnum } from '@/enums/storageEnum'
|
||||||
import { ChartEditStorage } from '@/store/modules/chartEditStore/chartEditStore.d'
|
import { ChartEditStorage } from '@/store/modules/chartEditStore/chartEditStore.d'
|
||||||
import { fetchProjectApi } from '@/api/path'
|
import { BackEndFactory } from '@/backend/ibackend'
|
||||||
|
|
||||||
|
|
||||||
export interface ChartEditStorageType extends ChartEditStorage {
|
export interface ChartEditStorageType extends ChartEditStorage {
|
||||||
id: string
|
id: string
|
||||||
@ -10,16 +11,34 @@ export interface ChartEditStorageType extends ChartEditStorage {
|
|||||||
|
|
||||||
// 根据路由 id 获取存储数据的信息
|
// 根据路由 id 获取存储数据的信息
|
||||||
export const getSessionStorageInfo = async () => {
|
export const getSessionStorageInfo = async () => {
|
||||||
const id = fetchRouteParamsLocation()
|
let id:string = fetchRouteParamsLocation()
|
||||||
|
if(id.indexOf("?") > 0){
|
||||||
|
id = id.substring(0, id.indexOf("?"))
|
||||||
|
}
|
||||||
|
|
||||||
const storageList: ChartEditStorageType[] = getSessionStorage(
|
const storageList: ChartEditStorageType[] = getSessionStorage(
|
||||||
StorageEnum.GO_CHART_STORAGE_LIST
|
StorageEnum.GO_CHART_STORAGE_LIST
|
||||||
)
|
)
|
||||||
|
|
||||||
// 是否本地预览
|
// 是否本地预览
|
||||||
if (!storageList || storageList.findIndex(e => e.id === id.toString()) === -1) {
|
if (!storageList || storageList.findIndex(e => e.id === id.toString()) === -1) {
|
||||||
|
// 处理 Token 注入
|
||||||
|
const q = fetchRouteQuery();
|
||||||
|
if(q && q.token && !loginCheck()){
|
||||||
|
// Token 注入
|
||||||
|
const rt = await BackEndFactory.checkToken({ token: q.token }) as any
|
||||||
|
if (rt.code === ResultEnum.SUCCESS && rt.data) {
|
||||||
|
// 记录登陆信息
|
||||||
|
setLocalStorage( StorageEnum.GO_LOGIN_INFO_STORE, rt.data)
|
||||||
|
}else{
|
||||||
|
httpErrorHandle()
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 接口调用
|
// 接口调用
|
||||||
const res = await fetchProjectApi({ projectId: id }) as unknown as MyResponseType
|
const res = await BackEndFactory.fetchProject({ projectId: id }) as any
|
||||||
if (res.code === ResultEnum.SUCCESS) {
|
if (res.code === ResultEnum.SUCCESS && res.data) {
|
||||||
const { content, state } = res.data
|
const { content, state } = res.data
|
||||||
if (state === -1) {
|
if (state === -1) {
|
||||||
// 跳转未发布页
|
// 跳转未发布页
|
||||||
@ -28,13 +47,15 @@ export const getSessionStorageInfo = async () => {
|
|||||||
return { ...JSON.parse(content), id }
|
return { ...JSON.parse(content), id }
|
||||||
} else {
|
} else {
|
||||||
httpErrorHandle()
|
httpErrorHandle()
|
||||||
|
// 错误处理,Todo
|
||||||
|
return {}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
// 本地读取
|
|
||||||
for (let i = 0; i < storageList.length; i++) {
|
// 本地读取
|
||||||
if (id.toString() === storageList[i]['id']) {
|
for (let i = 0; i < storageList.length; i++) {
|
||||||
return storageList[i]
|
if (id.toString() === storageList[i]['id']) {
|
||||||
}
|
return storageList[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -17,7 +17,7 @@
|
|||||||
object-fit="contain"
|
object-fit="contain"
|
||||||
height="180"
|
height="180"
|
||||||
preview-disabled
|
preview-disabled
|
||||||
:src="`${cardData.image}?time=${new Date().getTime()}`"
|
:src="`${cardData.image}`"
|
||||||
:alt="cardData.title"
|
:alt="cardData.title"
|
||||||
:fallback-src="requireErrorImg()"
|
:fallback-src="requireErrorImg()"
|
||||||
></n-image>
|
></n-image>
|
||||||
@ -98,7 +98,7 @@ const {
|
|||||||
SendIcon
|
SendIcon
|
||||||
} = icon.ionicons5
|
} = icon.ionicons5
|
||||||
|
|
||||||
const emit = defineEmits(['preview', 'delete', 'resize', 'edit', 'release'])
|
const emit = defineEmits(['preview', 'delete', 'resize', 'edit','copy', 'release'])
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
cardData: Object as PropType<Chartype>
|
cardData: Object as PropType<Chartype>
|
||||||
@ -127,7 +127,6 @@ const selectOptions = ref([
|
|||||||
label: renderLang('global.r_copy'),
|
label: renderLang('global.r_copy'),
|
||||||
key: 'copy',
|
key: 'copy',
|
||||||
icon: renderIcon(CopyIcon),
|
icon: renderIcon(CopyIcon),
|
||||||
disabled: true
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: renderLang('global.r_rename'),
|
label: renderLang('global.r_rename'),
|
||||||
@ -171,6 +170,9 @@ const handleSelect = (key: string) => {
|
|||||||
case 'delete':
|
case 'delete':
|
||||||
deleteHandle()
|
deleteHandle()
|
||||||
break
|
break
|
||||||
|
case 'copy':
|
||||||
|
emit('copy', props.cardData)
|
||||||
|
break;
|
||||||
case 'release':
|
case 'release':
|
||||||
releaseHandle()
|
releaseHandle()
|
||||||
break
|
break
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { ref, reactive } from 'vue';
|
import { ref, reactive } from 'vue';
|
||||||
import { goDialog, httpErrorHandle } from '@/utils'
|
import { goDialog, httpErrorHandle } from '@/utils'
|
||||||
import { DialogEnum } from '@/enums/pluginEnum'
|
import { DialogEnum } from '@/enums/pluginEnum'
|
||||||
import { projectListApi, deleteProjectApi, changeProjectReleaseApi } from '@/api/path'
|
import { BackEndFactory } from '@/backend/ibackend'
|
||||||
import { Chartype, ChartList } from '../../../index.d'
|
import { Chartype, ChartList } from '../../../index.d'
|
||||||
import { ResultEnum } from '@/enums/httpEnum'
|
import { ResultEnum } from '@/enums/httpEnum'
|
||||||
|
|
||||||
@ -24,24 +24,14 @@ export const useDataListInit = () => {
|
|||||||
// 数据请求
|
// 数据请求
|
||||||
const fetchList = async () => {
|
const fetchList = async () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
const res = await projectListApi({
|
const res = await BackEndFactory.projectList({
|
||||||
page: paginat.page,
|
page: paginat.page,
|
||||||
limit: paginat.limit
|
limit: paginat.limit
|
||||||
}) as any
|
}) as any
|
||||||
if (res.data) {
|
if (res.code==ResultEnum.SUCCESS) {
|
||||||
const { count } = res
|
const { count } = res
|
||||||
paginat.count = count
|
paginat.count = count
|
||||||
list.value = res.data.map((e: any) => {
|
list.value = res.data;
|
||||||
const { id, projectName, state, createTime, indexImage, createUserId } = e
|
|
||||||
return {
|
|
||||||
id: id,
|
|
||||||
title: projectName,
|
|
||||||
createId: createUserId,
|
|
||||||
time: createTime,
|
|
||||||
image: indexImage,
|
|
||||||
release: state !== -1
|
|
||||||
}
|
|
||||||
})
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}, 500)
|
}, 500)
|
||||||
@ -68,8 +58,8 @@ export const useDataListInit = () => {
|
|||||||
type: DialogEnum.DELETE,
|
type: DialogEnum.DELETE,
|
||||||
promise: true,
|
promise: true,
|
||||||
onPositiveCallback: () => new Promise(res => {
|
onPositiveCallback: () => new Promise(res => {
|
||||||
res(deleteProjectApi({
|
res(BackEndFactory.deleteProject({
|
||||||
ids: cardData.id
|
projectId: cardData.id
|
||||||
}))
|
}))
|
||||||
}),
|
}),
|
||||||
promiseResCallback: (res: any) => {
|
promiseResCallback: (res: any) => {
|
||||||
@ -83,14 +73,32 @@ export const useDataListInit = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 复制项目
|
||||||
|
const copyHandle = async (cardData: Chartype) => {
|
||||||
|
const { id, title } = cardData
|
||||||
|
const res = await BackEndFactory.copyProject({
|
||||||
|
copyId: id,
|
||||||
|
projectName: '复制-' + title
|
||||||
|
}) as any
|
||||||
|
if (res.code === ResultEnum.SUCCESS) {
|
||||||
|
list.value = []
|
||||||
|
fetchList()
|
||||||
|
window['$message'].success("复制项目成功!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
httpErrorHandle()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 发布处理
|
// 发布处理
|
||||||
const releaseHandle = async (cardData: Chartype, index: number) => {
|
const releaseHandle = async (cardData: Chartype, index: number) => {
|
||||||
const { id, release } = cardData
|
const { id, release } = cardData
|
||||||
const res = await changeProjectReleaseApi({
|
const res = await BackEndFactory.updateProject({
|
||||||
id: id,
|
projectId: id,
|
||||||
// [-1未发布, 1发布]
|
// [-1未发布, 1发布]
|
||||||
state: !release ? 1 : -1
|
release: !release ? 1 : -1
|
||||||
}) as unknown as MyResponseType
|
}) as any
|
||||||
if (res.code === ResultEnum.SUCCESS) {
|
if (res.code === ResultEnum.SUCCESS) {
|
||||||
list.value = []
|
list.value = []
|
||||||
fetchList()
|
fetchList()
|
||||||
@ -114,6 +122,7 @@ export const useDataListInit = () => {
|
|||||||
paginat,
|
paginat,
|
||||||
list,
|
list,
|
||||||
fetchList,
|
fetchList,
|
||||||
|
copyHandle,
|
||||||
releaseHandle,
|
releaseHandle,
|
||||||
changeSize,
|
changeSize,
|
||||||
changePage,
|
changePage,
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
@resize="resizeHandle"
|
@resize="resizeHandle"
|
||||||
@delete="deleteHandle(item)"
|
@delete="deleteHandle(item)"
|
||||||
@release="releaseHandle(item, index)"
|
@release="releaseHandle(item, index)"
|
||||||
|
@copy="copyHandle(item)"
|
||||||
@edit="editHandle"
|
@edit="editHandle"
|
||||||
></project-items-card>
|
></project-items-card>
|
||||||
</n-grid-item>
|
</n-grid-item>
|
||||||
@ -53,7 +54,7 @@ import { useDataListInit } from './hooks/useData.hook'
|
|||||||
|
|
||||||
const { CopyIcon, EllipsisHorizontalCircleSharpIcon } = icon.ionicons5
|
const { CopyIcon, EllipsisHorizontalCircleSharpIcon } = icon.ionicons5
|
||||||
const { modalData, modalShow, closeModal, previewHandle, resizeHandle, editHandle } = useModalDataInit()
|
const { modalData, modalShow, closeModal, previewHandle, resizeHandle, editHandle } = useModalDataInit()
|
||||||
const { loading, paginat, list, changeSize, changePage, releaseHandle, deleteHandle } = useDataListInit()
|
const { loading, paginat, list, changeSize, changePage, releaseHandle, copyHandle, deleteHandle } = useDataListInit()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -40,7 +40,7 @@ import { icon } from '@/plugins'
|
|||||||
import { PageEnum, ChartEnum } from '@/enums/pageEnum'
|
import { PageEnum, ChartEnum } from '@/enums/pageEnum'
|
||||||
import { ResultEnum } from '@/enums/httpEnum'
|
import { ResultEnum } from '@/enums/httpEnum'
|
||||||
import { fetchPathByName, routerTurnByPath, renderLang, getUUID } from '@/utils'
|
import { fetchPathByName, routerTurnByPath, renderLang, getUUID } from '@/utils'
|
||||||
import { createProjectApi } from '@/api/path'
|
import { BackEndFactory } from '@/backend/ibackend'
|
||||||
|
|
||||||
const { FishIcon, CloseIcon } = icon.ionicons5
|
const { FishIcon, CloseIcon } = icon.ionicons5
|
||||||
const { StoreIcon, ObjectStorageIcon } = icon.carbon
|
const { StoreIcon, ObjectStorageIcon } = icon.carbon
|
||||||
@ -89,19 +89,19 @@ const btnHandle = async (key: string) => {
|
|||||||
case ChartEnum.CHART_HOME_NAME:
|
case ChartEnum.CHART_HOME_NAME:
|
||||||
try {
|
try {
|
||||||
// 新增项目
|
// 新增项目
|
||||||
const res = await createProjectApi({
|
const res = await BackEndFactory.createProject({
|
||||||
// 项目名称
|
// 项目名称
|
||||||
projectName: getUUID(),
|
projectName: getUUID(),
|
||||||
// remarks
|
// remarks
|
||||||
remarks: null,
|
remarks: null,
|
||||||
// 图片地址
|
// 图片地址
|
||||||
indexImage: null,
|
indexImage: null,
|
||||||
}) as unknown as MyResponseType
|
}) as any
|
||||||
if(res.code === ResultEnum.SUCCESS) {
|
if(res.code === ResultEnum.SUCCESS) {
|
||||||
window['$message'].success(window['$t']('project.create_success'))
|
window['$message'].success(window['$t']('project.create_success'))
|
||||||
|
|
||||||
const { id } = res.data
|
const { id } = res.data
|
||||||
const path = fetchPathByName(ChartEnum.CHART_HOME_NAME, 'href')
|
const path = fetchPathByName(ChartEnum.CHART_HOME_NAME, 'href')
|
||||||
|
|
||||||
routerTurnByPath(path, [id], undefined, true)
|
routerTurnByPath(path, [id], undefined, true)
|
||||||
closeHandle()
|
closeHandle()
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="go-redirect">
|
<n-empty description="你什么也找不到">
|
||||||
<n-empty description="你什么也找不到">
|
<template #extra>
|
||||||
<template #extra>
|
<n-button size="small" @click="goHome">看看别的</n-button>
|
||||||
<n-button size="small" @click="goHome">看看别的</n-button>
|
</template>
|
||||||
</template>
|
</n-empty>
|
||||||
</n-empty>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onBeforeMount } from 'vue'
|
import { onBeforeMount } from 'vue'
|
||||||
@ -16,16 +14,3 @@ const goHome = () => {
|
|||||||
router.replace({ path: '/' })
|
router.replace({ path: '/' })
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
|
||||||
@include go(redirect) {
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
width: 100vw;
|
|
||||||
height: 100vh;
|
|
||||||
overflow: hidden;
|
|
||||||
padding: 100px 0;
|
|
||||||
@include background-image('background-image');
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
Loading…
Reference in New Issue
Block a user