feat: 合并 1.0.6 版本代码

This commit is contained in:
奔跑的面条 2022-07-21 11:03:04 +08:00
commit a9bb294f60
40 changed files with 1286 additions and 271 deletions

View File

@ -14,6 +14,12 @@
接口地址修改:`.env` 接口地址修改:`.env`
### 🤯 后端项目
后端项目gitee地址[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)
```shell ```shell
# port # port
VITE_DEV_PORT = '8080' VITE_DEV_PORT = '8080'

View File

@ -1,6 +1,6 @@
{ {
"name": "go-view", "name": "go-view",
"version": "2.0.2", "version": "2.0.3",
"scripts": { "scripts": {
"dev": "vite --host", "dev": "vite --host",
"build": "vue-tsc --noEmit && vite build", "build": "vue-tsc --noEmit && vite build",
@ -13,7 +13,7 @@
"@types/crypto-js": "^4.1.1", "@types/crypto-js": "^4.1.1",
"@types/keymaster": "^1.6.30", "@types/keymaster": "^1.6.30",
"animate.css": "^4.1.1", "animate.css": "^4.1.1",
"axios": "0.23.0", "axios": "^0.27.2",
"color": "^4.2.3", "color": "^4.2.3",
"crypto-js": "^4.1.1", "crypto-js": "^4.1.1",
"echarts-liquidfill": "^3.1.0", "echarts-liquidfill": "^3.1.0",

View File

@ -25,6 +25,7 @@ axiosInstance.interceptors.request.use(
return config return config
} }
config.headers = { config.headers = {
...config.headers,
[RequestHttpHeaderEnum.TOKEN]: info[SystemStoreEnum.USER_INFO][SystemStoreUserInfoEnum.USER_TOKEN] || '' [RequestHttpHeaderEnum.TOKEN]: info[SystemStoreEnum.USER_INFO][SystemStoreUserInfoEnum.USER_TOKEN] || ''
} }
return config return config

View File

@ -1,5 +1,13 @@
import axiosInstance from './axios' import axiosInstance from './axios'
import { RequestHttpEnum, ContentTypeEnum } from '@/enums/httpEnum' 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) => { export const get = (url: string, params?: object) => {
return axiosInstance({ return axiosInstance({
@ -20,6 +28,17 @@ export const post = (url: string, data?: object, headersType?: string) => {
}) })
} }
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) => { export const put = (url: string, data?: object, headersType?: ContentTypeEnum) => {
return axiosInstance({ return axiosInstance({
url: url, url: url,
@ -48,6 +67,9 @@ export const http = (type?: RequestHttpEnum) => {
case RequestHttpEnum.POST: case RequestHttpEnum.POST:
return post return post
case RequestHttpEnum.PATCH:
return patch
case RequestHttpEnum.PUT: case RequestHttpEnum.PUT:
return put return put
@ -58,3 +80,111 @@ export const http = (type?: RequestHttpEnum) => {
return get return get
} }
} }
/**
* *
* @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
}
// 处理头部
const headers: RequestParamsObjType = {
...globalRequestParams.Header,
...targetRequestParams.Header,
}
// data 参数
let data: RequestParamsObjType | FormData | string = {}
// params 参数
let params: RequestParamsObjType = targetRequestParams.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 = JSON.parse(targetRequestParams.Body['json'])
// json 赋值给 data
break
case RequestBodyEnum.XML:
headers['Content-Type'] = ContentTypeEnum.XML
// xml 字符串赋值给 data
data = 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, 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, bodyFormUrlencoded[i])
}
// FormData 赋值给 data
data = formData
break
}
// sql 处理
if (requestContentType === RequestContentTypeEnum.SQL) {
headers['Content-Type'] = ContentTypeEnum.JSON
data = requestSQLContent
}
return axiosInstance({
url: `${requestOriginUrl}${requestUrl}`,
method: requestHttpType,
data,
params,
headers
})
}

View File

@ -8,9 +8,9 @@
</n-text> </n-text>
<div <div
class="item-right" class="item-right"
justify="space-between"
:style="{ :style="{
gridTemplateColumns: alone ? '1fr' : '1fr 1fr' gridTemplateColumns: alone ? '1fr' : '1fr 1fr',
...itemRightStyle
}" }"
> >
<slot></slot> <slot></slot>
@ -28,6 +28,11 @@ defineProps({
type: Boolean, type: Boolean,
default: false, default: false,
required: false required: false
},
itemRightStyle: {
type: Object,
default: () => {},
required: false
} }
}) })
</script> </script>
@ -48,7 +53,6 @@ $leftWidth: 60px;
.item-right { .item-right {
display: grid; display: grid;
grid-column-gap: 10px; grid-column-gap: 10px;
grid-template-columns: 1fr 1fr;
width: calc(100% - #{$leftWidth}); width: calc(100% - #{$leftWidth});
} }
} }

View File

@ -5,6 +5,7 @@ import * as monaco from 'monaco-editor'
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker' import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker' import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'
import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker' import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'
import htmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker'
self.MonacoEnvironment = { self.MonacoEnvironment = {
getWorker(workerId, label) { getWorker(workerId, label) {
@ -14,6 +15,9 @@ self.MonacoEnvironment = {
if (label === 'typescript' || label === 'javascript') { if (label === 'typescript' || label === 'javascript') {
return new tsWorker() return new tsWorker()
} }
if (label === 'html') {
return new htmlWorker()
}
return new editorWorker() return new editorWorker()
} }
} }

View File

@ -20,7 +20,15 @@ export enum RequestDataTypeEnum {
// 静态数据 // 静态数据
STATIC = 0, STATIC = 0,
// 请求数据 // 请求数据
AJAX = 1, AJAX = 1
}
// 请求主体类型
export enum RequestContentTypeEnum {
// 普通请求
DEFAULT = 0,
// SQL请求
SQL = 1
} }
// 头部 // 头部
@ -35,17 +43,91 @@ export enum RequestHttpEnum {
POST = 'post', POST = 'post',
PATCH = 'patch', PATCH = 'patch',
PUT = 'put', PUT = 'put',
DELETE = 'delete', DELETE = 'delete'
}
/**
* @description:
*/
export enum RequestHttpIntervalEnum {
// 秒
SECOND = 'second',
// 分
MINUTE = 'minute',
// 时
HOUR = 'hour',
// 天
DAY = 'day'
}
/**
* @description:
*/
export const SelectHttpTimeNameObj = {
[RequestHttpIntervalEnum.SECOND]: '秒',
[RequestHttpIntervalEnum.MINUTE]: '分',
[RequestHttpIntervalEnum.HOUR]: '时',
[RequestHttpIntervalEnum.DAY]: '天'
}
/**
* @description:
*/
export enum RequestBodyEnum {
NONE = 'none',
FORM_DATA = 'form-data',
X_WWW_FORM_URLENCODED = 'x-www-form-urlencoded',
JSON = 'json',
XML = 'xml'
}
/**
* @description:
*/
export const RequestBodyEnumList = [
RequestBodyEnum.NONE,
RequestBodyEnum.FORM_DATA,
RequestBodyEnum.X_WWW_FORM_URLENCODED,
RequestBodyEnum.JSON,
RequestBodyEnum.XML
]
/**
* @description:
*/
export enum RequestParamsTypeEnum {
PARAMS = 'Params',
BODY = 'Body',
HEADER = 'Header',
}
/**
* @description:
*/
export type RequestParamsObjType = {
[T: string]: string
}
export type RequestParams = {
[RequestParamsTypeEnum.PARAMS]: RequestParamsObjType
[RequestParamsTypeEnum.HEADER]: RequestParamsObjType
[RequestParamsTypeEnum.BODY]: {
[RequestBodyEnum.FORM_DATA]: RequestParamsObjType
[RequestBodyEnum.X_WWW_FORM_URLENCODED]: RequestParamsObjType
[RequestBodyEnum.JSON]: string
[RequestBodyEnum.XML]: string
}
} }
// 常用的contentTyp类型 // 常用的contentTyp类型
export enum ContentTypeEnum { export enum ContentTypeEnum {
// json // json
JSON = 'application/json; charset=UTF-8', JSON = 'application/json;charset=UTF-8',
// text // text
TEXT = 'text/plain; charset=UTF-8', TEXT = 'text/plain;charset=UTF-8',
// form-data 一般配合qs // xml
FORM_URLENCODED = 'application/x-www-form-urlencoded; charset=UTF-8', XML = 'application/xml;charset=UTF-8',
// application/x-www-form-urlencoded 一般配合qs
FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8',
// form-data 上传 // form-data 上传
FORM_DATA = 'multipart/form-data; charset=UTF-8', FORM_DATA = 'multipart/form-data;charset=UTF-8'
} }

View File

@ -1,10 +1,10 @@
import { ref, toRefs } from 'vue' import { ref, toRefs, toRaw } from 'vue'
import type VChart from 'vue-echarts' import type VChart from 'vue-echarts'
import { http } from '@/api/http' import { customizeHttp } from '@/api/http'
import { CreateComponentType, ChartFrameEnum } from '@/packages/index.d' import { CreateComponentType, ChartFrameEnum } from '@/packages/index.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { RequestDataTypeEnum } from '@/enums/httpEnum' import { RequestDataTypeEnum } from '@/enums/httpEnum'
import { isPreview, newFunctionHandle } from '@/utils' import { isPreview, newFunctionHandle, intervalUnitHandle } from '@/utils'
// 获取类型 // 获取类型
type ChartEditStoreType = typeof useChartEditStore type ChartEditStoreType = typeof useChartEditStore
@ -25,55 +25,71 @@ export const useChartDataFetch = (
const requestIntervalFn = () => { const requestIntervalFn = () => {
const chartEditStore = useChartEditStore() const chartEditStore = useChartEditStore()
const { requestOriginUrl, requestInterval } = toRefs(chartEditStore.getRequestGlobalConfig)
// 组件类型 // 全局数据
const { chartFrame } = targetComponent.chartConfig const {
// 请求配置 requestOriginUrl,
requestIntervalUnit: globalUnit,
requestInterval: globalRequestInterval
} = toRefs(chartEditStore.getRequestGlobalConfig)
// 目标组件
const { const {
requestDataType, requestDataType,
requestHttpType,
requestUrl, requestUrl,
requestIntervalUnit: targetUnit,
requestInterval: targetInterval requestInterval: targetInterval
} = toRefs(targetComponent.request) } = toRefs(targetComponent.request)
// 组件类型
const { chartFrame } = targetComponent.chartConfig
// 非请求类型 // 非请求类型
if (requestDataType.value !== RequestDataTypeEnum.AJAX) return if (requestDataType.value !== RequestDataTypeEnum.AJAX) return
// 处理地址
if (requestUrl?.value && requestInterval.value > 0) {
// requestOriginUrl 允许为空
const completePath = requestOriginUrl && requestOriginUrl.value + requestUrl.value
if (!completePath) return
clearInterval(fetchInterval) try {
// 处理地址
// @ts-ignore
if (requestUrl?.value) {
// requestOriginUrl 允许为空
const completePath = requestOriginUrl && requestOriginUrl.value + requestUrl.value
if (!completePath) return
const fetchFn = async () => { clearInterval(fetchInterval)
const res = await http(requestHttpType.value)(completePath || '', {}) as unknown as MyResponseType
if (res.data) { const fetchFn = async () => {
try { const res = await customizeHttp(toRaw(targetComponent.request), toRaw(chartEditStore.requestGlobalConfig))
const filter = targetComponent.filter if (res && res.data) {
// 更新回调函数 try {
if (updateCallback) { const filter = targetComponent.filter
updateCallback(newFunctionHandle(res.data, filter)) // 更新回调函数
} else { if (updateCallback) {
// eCharts 组件配合 vChart 库更新方式 updateCallback(newFunctionHandle(res.data, filter))
if (chartFrame === ChartFrameEnum.ECHARTS) { } else {
if (vChartRef.value) { // eCharts 组件配合 vChart 库更新方式
vChartRef.value.setOption({ dataset: newFunctionHandle(res.data, filter) }) if (chartFrame === ChartFrameEnum.ECHARTS) {
if (vChartRef.value) {
vChartRef.value.setOption({ dataset: newFunctionHandle(res.data, filter) })
}
} }
} }
} catch (error) {
console.error(error)
} }
} catch (error) {
console.error(error)
} }
} }
// 立即调用
fetchFn()
// 定时时间
const time = targetInterval && targetInterval.value ? targetInterval.value : globalRequestInterval.value
// 单位
const unit = targetInterval && targetInterval.value ? targetUnit.value : globalUnit.value
// 开启轮询
if (time) fetchInterval = setInterval(fetchFn, intervalUnitHandle(time, unit))
} }
} catch (error) {}
// 立即调用
fetchFn()
// 开启定时
const time = targetInterval && targetInterval.value ? targetInterval.value : requestInterval.value
fetchInterval = setInterval(fetchFn, time * 1000)
}
} }
isPreview() && requestIntervalFn() isPreview() && requestIntervalFn()

View File

@ -7,6 +7,8 @@ import { setupNaive, setupDirectives, setupCustomComponents } from '@/plugins'
import { GoAppProvider } from '@/components/GoAppProvider/index' import { GoAppProvider } from '@/components/GoAppProvider/index'
import { setHtmlTheme } from '@/utils' import { setHtmlTheme } from '@/utils'
// 引入全局样式
import '@/styles/pages/index.scss'
// 引入动画 // 引入动画
import 'animate.css/animate.min.css' import 'animate.css/animate.min.css'
// 引入标尺 // 引入标尺

View File

@ -44,7 +44,7 @@
<n-color-picker <n-color-picker
size="small" size="small"
:modes="['hex']" :modes="['hex']"
v-model:value="optionData.suffixColor" v-model:value="optionData.prefixColor"
></n-color-picker> ></n-color-picker>
</SettingItem> </SettingItem>
<SettingItem name="后缀"> <SettingItem name="后缀">

View File

@ -1,14 +1,36 @@
import { getUUID } from '@/utils' import { getUUID } from '@/utils'
import { PublicConfigType } from '@/packages/index.d' import { PublicConfigType } from '@/packages/index.d'
import { RequestConfigType } from '@/store/modules/chartEditStore/chartEditStore.d' import { RequestConfigType } from '@/store/modules/chartEditStore/chartEditStore.d'
import { RequestHttpEnum, RequestDataTypeEnum } from '@/enums/httpEnum' import {
RequestHttpEnum,
RequestDataTypeEnum,
RequestHttpIntervalEnum,
RequestContentTypeEnum,
RequestBodyEnum
} from '@/enums/httpEnum'
import { chartInitConfig } from '@/settings/designSetting' import { chartInitConfig } from '@/settings/designSetting'
const requestConfig: RequestConfigType = { const requestConfig: RequestConfigType = {
requestDataType: RequestDataTypeEnum.STATIC, requestDataType: RequestDataTypeEnum.STATIC,
requestHttpType: RequestHttpEnum.GET, requestHttpType: RequestHttpEnum.GET,
requestUrl: '', requestUrl: '',
requestInterval: undefined requestInterval: undefined,
requestIntervalUnit: RequestHttpIntervalEnum.SECOND,
requestContentType: RequestContentTypeEnum.DEFAULT,
requestParamsBodyType: RequestBodyEnum.NONE,
requestSQLContent: {
sql: 'select * from where'
},
requestParams: {
Body: {
'form-data': {},
'x-www-form-urlencoded': {},
json: '',
xml: ''
},
Header: {},
Params: {}
}
} }
export class publicConfig implements PublicConfigType { export class publicConfig implements PublicConfigType {

View File

@ -53,7 +53,10 @@ import {
ArrowForward as ArrowForwardIcon, ArrowForward as ArrowForwardIcon,
Planet as PawIcon, Planet as PawIcon,
Search as SearchIcon, Search as SearchIcon,
Reload as ReloadIcon Reload as ReloadIcon,
ChevronUpOutline as ChevronUpOutlineIcon,
ChevronDownOutline as ChevronDownOutlineIcon,
Pulse as PulseIcon
} from '@vicons/ionicons5' } from '@vicons/ionicons5'
import { import {
@ -196,7 +199,15 @@ const ionicons5 = {
// 搜索(放大镜) // 搜索(放大镜)
SearchIcon, SearchIcon,
// 加载 // 加载
ReloadIcon ReloadIcon,
// 过滤器
FilterIcon,
// 向上
ChevronUpOutlineIcon,
// 向下
ChevronDownOutlineIcon,
// 脉搏
PulseIcon
} }
const carbon = { const carbon = {

View File

@ -37,6 +37,7 @@ import {
NTooltip, NTooltip,
NAvatar, NAvatar,
NTabs, NTabs,
NTab,
NTabPane, NTabPane,
NCard, NCard,
NRow, NRow,
@ -68,6 +69,7 @@ import {
NSteps, NSteps,
NStep, NStep,
NInputGroup, NInputGroup,
NInputGroupLabel,
NResult, NResult,
NDescriptions, NDescriptions,
NDescriptionsItem, NDescriptionsItem,
@ -136,6 +138,7 @@ const naive = create({
NTooltip, NTooltip,
NAvatar, NAvatar,
NTabs, NTabs,
NTab,
NTabPane, NTabPane,
NCard, NCard,
NRow, NRow,
@ -167,6 +170,7 @@ const naive = create({
NSteps, NSteps,
NStep, NStep,
NInputGroup, NInputGroup,
NInputGroupLabel,
NResult, NResult,
NDescriptions, NDescriptions,
NDescriptionsItem, NDescriptionsItem,

View File

@ -1,4 +1,5 @@
import { LangEnum, PreviewScaleEnum } from '@/enums/styleEnum' import { LangEnum, PreviewScaleEnum } from '@/enums/styleEnum'
import { RequestHttpIntervalEnum } from '@/enums/httpEnum'
import designColor from './designColor.json' import designColor from './designColor.json'
// 默认语言 // 默认语言
@ -54,5 +55,8 @@ export const requestInterval = 30
// 工作台自动保存间隔s // 工作台自动保存间隔s
export const saveInterval = 30 export const saveInterval = 30
// 数据请求间隔单位
export const requestIntervalUnit = RequestHttpIntervalEnum.SECOND
// 工作区域历史记录存储最大数量 // 工作区域历史记录存储最大数量
export const editHistoryMax = 100 export const editHistoryMax = 100

View File

@ -1,12 +1,17 @@
import { CreateComponentType, FilterEnum} from '@/packages/index.d' import { CreateComponentType, FilterEnum } from '@/packages/index.d'
import { HistoryActionTypeEnum } from '@/store/modules/chartHistoryStore/chartHistoryStore.d' import { HistoryActionTypeEnum } from '@/store/modules/chartHistoryStore/chartHistoryStore.d'
import { RequestHttpEnum, RequestDataTypeEnum } from '@/enums/httpEnum'
import { SyncEnum } from '@/enums/editPageEnum' import { SyncEnum } from '@/enums/editPageEnum'
import {
RequestHttpEnum,
RequestContentTypeEnum,
RequestDataTypeEnum,
RequestHttpIntervalEnum,
RequestParams,
RequestBodyEnum,
RequestParamsObjType
} from '@/enums/httpEnum'
import { PreviewScaleEnum } from '@/enums/styleEnum' import { PreviewScaleEnum } from '@/enums/styleEnum'
import type { import type { ChartColorsNameType, GlobalThemeJsonType } from '@/settings/chartThemes/index'
ChartColorsNameType,
GlobalThemeJsonType,
} from '@/settings/chartThemes/index'
// 项目数据枚举 // 项目数据枚举
export enum ProjectInfoEnum { export enum ProjectInfoEnum {
@ -71,7 +76,7 @@ export enum EditCanvasConfigEnum {
BACKGROUND = 'background', BACKGROUND = 'background',
BACKGROUND_IMAGE = 'backgroundImage', BACKGROUND_IMAGE = 'backgroundImage',
SELECT_COLOR = 'selectColor', SELECT_COLOR = 'selectColor',
PREVIEW_SCALE_TYPE = 'previewScaleType', PREVIEW_SCALE_TYPE = 'previewScaleType'
} }
// 画布属性(需保存) // 画布属性(需保存)
@ -118,7 +123,7 @@ export enum EditCanvasTypeEnum {
START_X = 'startX', START_X = 'startX',
START_Y = 'startY', START_Y = 'startY',
X = 'x', X = 'x',
Y = 'y', Y = 'y'
} }
// 鼠标位置 // 鼠标位置
@ -157,27 +162,43 @@ export enum ChartEditStoreEnum {
// 以下需要存储 // 以下需要存储
EDIT_CANVAS_CONFIG = 'editCanvasConfig', EDIT_CANVAS_CONFIG = 'editCanvasConfig',
REQUEST_GLOBAL_CONFIG = 'requestGlobalConfig', REQUEST_GLOBAL_CONFIG = 'requestGlobalConfig',
COMPONENT_LIST = 'componentList', COMPONENT_LIST = 'componentList'
}
// 请求公共类型
type RequestPublicConfigType = {
// 时间单位(时分秒)
requestIntervalUnit: RequestHttpIntervalEnum
// 请求内容
requestParams: RequestParams
} }
// 全局的图表请求配置 // 全局的图表请求配置
export type RequestGlobalConfigType = { export interface RequestGlobalConfigType extends RequestPublicConfigType {
// 组件定制轮询时间
requestInterval: number
// 请求源地址 // 请求源地址
requestOriginUrl?: string requestOriginUrl?: string
// 全局默认轮询时间
requestInterval: number
} }
// 单个图表请求配置 // 单个图表请求配置
export type RequestConfigType = { export interface RequestConfigType extends RequestPublicConfigType {
// 组件定制轮询时间
requestInterval?: number
// 获取数据的方式 // 获取数据的方式
requestDataType: RequestDataTypeEnum requestDataType: RequestDataTypeEnum
// 请求方式 get/post/del/put/patch // 请求方式 get/post/del/put/patch
requestHttpType: RequestHttpEnum requestHttpType: RequestHttpEnum
// 源后续的 url // 源后续的 url
requestUrl?: string requestUrl?: string
// 组件定制轮询时间 // 请求内容主体方式 普通/sql
requestInterval?: number requestContentType: RequestContentTypeEnum
// 请求体类型
requestParamsBodyType: RequestBodyEnum
// SQL 请求对象
requestSQLContent: {
sql: string
}
} }
// Store 类型 // Store 类型

View File

@ -3,7 +3,8 @@ import { CreateComponentType } from '@/packages/index.d'
import debounce from 'lodash/debounce' import debounce from 'lodash/debounce'
import cloneDeep from 'lodash/cloneDeep' import cloneDeep from 'lodash/cloneDeep'
import { defaultTheme, globalThemeJson } from '@/settings/chartThemes/index' import { defaultTheme, globalThemeJson } from '@/settings/chartThemes/index'
import { requestInterval, previewScaleType } from '@/settings/designSetting' import { requestInterval, previewScaleType, requestIntervalUnit } from '@/settings/designSetting'
import { RequestBodyEnum } from '@/enums/httpEnum'
// 记录记录 // 记录记录
import { useChartHistoryStore } from '@/store/modules/chartHistoryStore/chartHistoryStore' import { useChartHistoryStore } from '@/store/modules/chartHistoryStore/chartHistoryStore'
// 全局设置 // 全局设置
@ -123,7 +124,18 @@ export const useChartEditStore = defineStore({
// 数据请求处理(需存储给后端) // 数据请求处理(需存储给后端)
requestGlobalConfig: { requestGlobalConfig: {
requestOriginUrl: '', requestOriginUrl: '',
requestInterval: requestInterval requestInterval: requestInterval,
requestIntervalUnit: requestIntervalUnit,
requestParams: {
Body: {
"form-data": {},
"x-www-form-urlencoded": {},
json: '',
xml: ''
},
Header: {},
Params: {}
}
}, },
// 图表数组(需存储给后端) // 图表数组(需存储给后端)
componentList: [] componentList: []
@ -401,7 +413,7 @@ export const useChartEditStore = defineStore({
type: isCut ? HistoryActionTypeEnum.CUT : HistoryActionTypeEnum.COPY type: isCut ? HistoryActionTypeEnum.CUT : HistoryActionTypeEnum.COPY
} }
this.setRecordChart(copyData) this.setRecordChart(copyData)
window['$message'].success(isCut ? '剪切成功' : '复制成功!') window['$message'].success(isCut ? '剪切图表成功' : '复制图表成功!')
loadingFinish() loadingFinish()
} }
} catch(value) { } catch(value) {

View File

@ -0,0 +1 @@
// 页面全局样式

View File

@ -6,7 +6,7 @@ import { EditCanvasConfigType } from '@/store/modules/chartEditStore/chartEditSt
type AttrType = PickCreateComponentType<'attr'> type AttrType = PickCreateComponentType<'attr'>
type StylesType = PickCreateComponentType<'styles'> type StylesType = PickCreateComponentType<'styles'>
// 动画 // * 动画
export const animationsClass = (animations: string[]) => { export const animationsClass = (animations: string[]) => {
if (animations.length) { if (animations.length) {
return `animate__animated animate__${animations[0]}` return `animate__animated animate__${animations[0]}`
@ -14,7 +14,7 @@ export const animationsClass = (animations: string[]) => {
return '' return ''
} }
// 滤镜 // * 滤镜
export const getFilterStyle = (styles: StylesType | EditCanvasConfigType) => { export const getFilterStyle = (styles: StylesType | EditCanvasConfigType) => {
const { opacity, saturate, contrast, hueRotate, brightness } = styles const { opacity, saturate, contrast, hueRotate, brightness } = styles
return { return {
@ -23,7 +23,7 @@ export const getFilterStyle = (styles: StylesType | EditCanvasConfigType) => {
} }
} }
// 变换 // * 变换
export const getTransformStyle = (styles: StylesType) => { export const getTransformStyle = (styles: StylesType) => {
const { rotateZ, rotateX, rotateY, skewX, skewY } = styles const { rotateZ, rotateX, rotateY, skewX, skewY } = styles
return { return {

View File

@ -6,7 +6,8 @@ import Image_404 from '../assets/images/exception/image-404.png'
import html2canvas from 'html2canvas' import html2canvas from 'html2canvas'
import { downloadByA } from './file' import { downloadByA } from './file'
import { toString } from './type' import { toString } from './type'
import cloneDeep from 'lodash/cloneDeep'; import cloneDeep from 'lodash/cloneDeep'
import { RequestHttpIntervalEnum, RequestParamsObjType } from '@/enums/httpEnum'
/** /**
* * * *
@ -180,7 +181,7 @@ export const newFunctionHandle = (
try { try {
if (!funcStr) return data if (!funcStr) return data
const fn = new Function('data', funcStr) const fn = new Function('data', funcStr)
const fnRes = fn( cloneDeep(data)) const fnRes = fn(cloneDeep(data))
const resHandle = isToString ? toString(fnRes) : fnRes const resHandle = isToString ? toString(fnRes) : fnRes
// 成功回调 // 成功回调
successCallBack && successCallBack(resHandle) successCallBack && successCallBack(resHandle)
@ -191,3 +192,43 @@ export const newFunctionHandle = (
return '函数执行错误' return '函数执行错误'
} }
} }
/**
* *
* @param num
* @param unit RequestHttpIntervalEnum
* @return number
*/
export const intervalUnitHandle = (num: number, unit: RequestHttpIntervalEnum) => {
switch (unit) {
// 秒
case RequestHttpIntervalEnum.SECOND:
return num * 1000
// 分
case RequestHttpIntervalEnum.MINUTE:
return num * 1000 * 60
// 时
case RequestHttpIntervalEnum.HOUR:
return num * 1000 * 60 * 60
// 天
case RequestHttpIntervalEnum.DAY:
return num * 1000 * 60 * 60 * 24
default:
return num * 1000
}
}
/**
* * cookie
* @param obj
* @returns string
*/
export const objToCookie = (obj: RequestParamsObjType) => {
if(!obj) return ''
let str = ''
for (const key in obj) {
str += key + '=' + obj[key] + ';'
}
return str.substr(0, str.length - 1)
}

View File

@ -1,30 +0,0 @@
<template>
<div class="go-chart-data-setting">
<setting-item-box name="源地址" :alone="true">
<n-input
v-model:value.trim="chartEditStore.getRequestGlobalConfig.requestOriginUrl"
placeholder="源地址如: http://127.0.0.1"
></n-input>
</setting-item-box>
<setting-item-box name="更新间隔" :alone="true">
<n-input-number
v-model:value.trim="chartEditStore.getRequestGlobalConfig.requestInterval"
min="5"
:show-button="false"
placeholder="将应用全局组件"
>
<template #suffix>
</template>
</n-input-number>
</setting-item-box>
</div>
</template>
<script setup lang="ts">
import { SettingItemBox } from '@/components/Pages/ChartItemSetting'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
const chartEditStore = useChartEditStore()
</script>

View File

@ -138,7 +138,7 @@ import { icon } from '@/plugins'
import { uploadFile} from '@/api/path' import { uploadFile} from '@/api/path'
const { ColorPaletteIcon } = icon.ionicons5 const { ColorPaletteIcon } = icon.ionicons5
const { ZAxisIcon, ScaleIcon, FitToScreenIcon, FitToHeightIcon, FitToWidthIcon } = icon.carbon const { ScaleIcon, FitToScreenIcon, FitToHeightIcon, FitToWidthIcon } = icon.carbon
const chartEditStore = useChartEditStore() const chartEditStore = useChartEditStore()
const systemStore = useSystemStore() const systemStore = useSystemStore()
@ -151,9 +151,6 @@ const switchSelectColorLoading = ref(false)
const ChartThemeColor = loadAsyncComponent(() => const ChartThemeColor = loadAsyncComponent(() =>
import('./components/ChartThemeColor/index.vue') import('./components/ChartThemeColor/index.vue')
) )
const ChartDataSetting = loadAsyncComponent(() =>
import('./components/ChartDataSetting/index.vue')
)
// //
const swatchesColors = [ const swatchesColors = [
@ -173,12 +170,6 @@ const globalTabList = [
title: '主题颜色', title: '主题颜色',
icon: ColorPaletteIcon, icon: ColorPaletteIcon,
render: ChartThemeColor render: ChartThemeColor
},
{
key: 'ChartSysSetting',
title: '数据配置',
icon: ZAxisIcon,
render: ChartDataSetting
} }
] ]

View File

@ -1,44 +1,57 @@
<template> <template>
<div class="go-chart-configurations-data-ajax"> <div class="go-chart-configurations-data-ajax">
<setting-item-box name="配置"> <n-card class="n-card-shallow">
<setting-item name="类型"> <setting-item-box name="请求配置">
<n-select v-model:value="targetData.request.requestHttpType" :options="selectOptions" /> <setting-item name="类型">
</setting-item> <n-tag :bordered="false" type="primary" style="border-radius: 5px">
<setting-item name="默认使用全局间隔"> {{ requestContentType === RequestContentTypeEnum.DEFAULT ? '普通请求' : 'SQL请求' }}
<n-input-number </n-tag>
v-model:value.trim="targetData.request.requestInterval" </setting-item>
min="5"
:show-button="false"
placeholder="可以为空"
>
<template #suffix> </template>
</n-input-number>
</setting-item>
</setting-item-box>
<setting-item-box name="源地址:" :alone="true"> <setting-item name="方式">
<n-text type="info">{{ requestOriginUrl || '暂无' }}</n-text> <n-input size="small" :placeholder="requestHttpType || '暂无'" :disabled="true"></n-input>
</setting-item-box> </setting-item>
<setting-item-box :alone="true"> <setting-item name="组件间隔(高级)">
<template #name> <n-input size="small" :placeholder="`${requestInterval || '暂无'}`" :disabled="true">
地址 <template #suffix> {{ SelectHttpTimeNameObj[requestIntervalUnit] }} </template>
<n-tooltip trigger="hover" v-if="isDev()"> </n-input>
<template #trigger> </setting-item>
<n-icon size="21" :depth="3">
<help-outline-icon></help-outline-icon> <setting-item name="全局间隔(默认)">
</n-icon> <n-input size="small" :placeholder="`${GlobalRequestInterval || '暂无'} `" :disabled="true">
<template #suffix> {{ SelectHttpTimeNameObj[GlobalRequestIntervalUnit] }} </template>
</n-input>
</setting-item>
</setting-item-box>
<setting-item-box name="源地址" :alone="true">
<n-input size="small" :placeholder="requestOriginUrl || '暂无'" :disabled="true">
<template #prefix>
<n-icon :component="PulseIcon" />
</template> </template>
<ul class="go-pl-0"> </n-input>
开发环境使用 mock 数据请输入 </setting-item-box>
<li v-for="item in apiList" :key="item.value">
<n-text type="info"> {{ item.value }} </n-text> <setting-item-box name="组件地址" :alone="true">
</li> <n-input size="small" :placeholder="requestUrl || '暂无'" :disabled="true">
</ul> <template #prefix>
</n-tooltip> <n-icon :component="FlashIcon" />
</template> </template>
<n-input v-model:value.trim="targetData.request.requestUrl" :min="1" placeholder="请输入地址(去除源)" /> </n-input>
</setting-item-box> </setting-item-box>
<n-space justify="end">
<n-text depth="3" style="font-size: 12px">更新内容请点击展示区域</n-text>
</n-space>
<div class="edit-text" @click="requestModelHandle">
<div class="go-absolute-center">
<n-button type="primary" secondary>查看更多</n-button>
</div>
</div>
</n-card>
<setting-item-box :alone="true"> <setting-item-box :alone="true">
<template #name> <template #name>
测试 测试
@ -51,105 +64,91 @@
默认赋值给 dataset 字段 默认赋值给 dataset 字段
</n-tooltip> </n-tooltip>
</template> </template>
<n-space> <n-button type="primary" ghost @click="sendHandle">
<n-button @click="sendHandle"> <template #icon>
<template #icon> <n-icon>
<n-icon> <flash-icon />
<flash-icon /> </n-icon>
</n-icon> </template>
</template> 发送请求
发送请求 </n-button>
</n-button>
</n-space>
</setting-item-box> </setting-item-box>
<!-- 底部数据展示 -->
<chart-data-matching-and-show :show="showMatching && !loading" :ajax="true"></chart-data-matching-and-show> <chart-data-matching-and-show :show="showMatching && !loading" :ajax="true"></chart-data-matching-and-show>
<!-- 骨架图 -->
<go-skeleton :load="loading" :repeat="3"></go-skeleton> <go-skeleton :load="loading" :repeat="3"></go-skeleton>
<!-- 请求配置model -->
<chart-data-request v-model:modelShow="requestShow"></chart-data-request>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, toRefs, onBeforeUnmount, watchEffect } from 'vue' import { ref, toRefs, onBeforeUnmount, watchEffect, toRaw } from 'vue'
import { icon } from '@/plugins' import { icon } from '@/plugins'
import { useDesignStore } from '@/store/modules/designStore/designStore'
import { SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting' import { SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import { RequestHttpEnum, ResultEnum } from '@/enums/httpEnum' import { ChartDataRequest } from '../ChartDataRequest/index'
import { RequestHttpEnum, ResultEnum, SelectHttpTimeNameObj, RequestContentTypeEnum } from '@/enums/httpEnum'
import { chartDataUrl, rankListUrl, scrollBoardUrl, numberFloatUrl, numberIntUrl, textUrl, imageUrl } from '@/api/mock' import { chartDataUrl, rankListUrl, scrollBoardUrl, numberFloatUrl, numberIntUrl, textUrl, imageUrl } from '@/api/mock'
import { http } from '@/api/http' import { http, customizeHttp } from '@/api/http'
import { SelectHttpType } from '../../index.d' import { SelectHttpType } from '../../index.d'
import { ChartDataMatchingAndShow } from '../ChartDataMatchingAndShow' import { ChartDataMatchingAndShow } from '../ChartDataMatchingAndShow'
import { useTargetData } from '../../../hooks/useTargetData.hook' import { useTargetData } from '../../../hooks/useTargetData.hook'
import { isDev, newFunctionHandle } from '@/utils' import { isDev, newFunctionHandle } from '@/utils'
const { HelpOutlineIcon, FlashIcon } = icon.ionicons5 const { HelpOutlineIcon, FlashIcon, PulseIcon } = icon.ionicons5
const { targetData, chartEditStore } = useTargetData() const { targetData, chartEditStore } = useTargetData()
const { requestOriginUrl } = toRefs(chartEditStore.getRequestGlobalConfig) const { requestUrl, requestHttpType, requestInterval, requestIntervalUnit, requestContentType } = toRefs(
targetData.value.request
)
const {
requestOriginUrl,
requestInterval: GlobalRequestInterval,
requestIntervalUnit: GlobalRequestIntervalUnit
} = toRefs(chartEditStore.getRequestGlobalConfig)
const designStore = useDesignStore()
const themeColor = ref(designStore.getAppTheme)
// //
const loading = ref(false) const loading = ref(false)
const requestShow = ref(false)
const showMatching = ref(false) const showMatching = ref(false)
let firstFocus = 0
let lastFilter: any = undefined let lastFilter: any = undefined
const apiList = [ // model
{ const requestModelHandle = () => {
value: `【图表】${chartDataUrl}` requestShow.value = true
}, }
{
value: `【文本】${textUrl}`
},
{
value: `【0~100 整数】${numberIntUrl}`
},
{
value: `【0~1小数】${numberFloatUrl}`
},
{
value: `【图片地址】${imageUrl}`
},
{
value: `【排名列表】${rankListUrl}`
},
{
value: `【滚动表格】${scrollBoardUrl}`
}
]
//
const selectOptions: SelectHttpType[] = [
{
label: RequestHttpEnum.GET,
value: RequestHttpEnum.GET
},
{
label: RequestHttpEnum.POST,
value: RequestHttpEnum.POST
}
]
// //
const sendHandle = async () => { const sendHandle = async () => {
if(!targetData.value?.request) return
loading.value = true loading.value = true
if (!targetData.value) return try {
const { requestUrl, requestHttpType } = targetData.value.request const res = await customizeHttp(toRaw(targetData.value.request), toRaw(chartEditStore.requestGlobalConfig))
if (!requestUrl) { loading.value = false
window['$message'].warning('请求参数不正确,请检查!') if (res && res.data) {
return targetData.value.option.dataset = newFunctionHandle(res.data, targetData.value.filter)
showMatching.value = true
return
}
window['$message'].warning('数据异常,请检查参数!')
} catch (error) {
loading.value = false
window['$message'].warning('数据异常,请检查参数!')
} }
const completePath = requestOriginUrl && requestOriginUrl.value + requestUrl
const res = await http(requestHttpType)(completePath || '', {})
loading.value = false
if (res.status === ResultEnum.SUCCESS) {
targetData.value.option.dataset = newFunctionHandle(res.data, targetData.value.filter)
showMatching.value = true
return
}
window['$message'].warning('数据异常,请检查接口数据!')
} }
watchEffect(() => { watchEffect(() => {
const filter = targetData.value?.filter const filter = targetData.value?.filter
if (lastFilter !== filter) { if (lastFilter !== filter && firstFocus) {
lastFilter = filter lastFilter = filter
sendHandle() sendHandle()
} }
firstFocus ++
}) })
onBeforeUnmount(() => { onBeforeUnmount(() => {
@ -159,5 +158,33 @@ onBeforeUnmount(() => {
<style lang="scss" scoped> <style lang="scss" scoped>
@include go('chart-configurations-data-ajax') { @include go('chart-configurations-data-ajax') {
.n-card-shallow {
&.n-card {
@extend .go-background-filter;
@include deep() {
.n-card__content {
padding: 10px;
}
}
}
.edit-text {
position: absolute;
top: 0px;
left: 0px;
width: 325px;
height: 292px;
cursor: pointer;
opacity: 0;
transition: all 0.3s;
@extend .go-background-filter;
backdrop-filter: blur(2px) !important;
}
&:hover {
border-color: v-bind('themeColor');
.edit-text {
opacity: 1;
}
}
}
} }
</style> </style>

View File

@ -72,7 +72,7 @@
</div> </div>
</n-space> </n-space>
<n-card size="small"> <n-card size="small">
<n-code :code="filterRes(source)" language="json"></n-code> <n-code :code="toString(source)" language="json"></n-code>
</n-card> </n-card>
</n-space> </n-space>
</n-timeline-item> </n-timeline-item>
@ -81,7 +81,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, watch } from 'vue' import { ref, computed, watch } from 'vue'
import { CreateComponentType, PackagesCategoryEnum } from '@/packages/index.d' import { PackagesCategoryEnum } from '@/packages/index.d'
import { RequestDataTypeEnum } from '@/enums/httpEnum' import { RequestDataTypeEnum } from '@/enums/httpEnum'
import { icon } from '@/plugins' import { icon } from '@/plugins'
import { DataResultEnum, TimelineTitleEnum } from '../../index.d' import { DataResultEnum, TimelineTitleEnum } from '../../index.d'
@ -89,7 +89,6 @@ import { ChartDataMonacoEditor } from '../ChartDataMonacoEditor'
import { useFile } from '../../hooks/useFile.hooks' import { useFile } from '../../hooks/useFile.hooks'
import { useTargetData } from '../../../hooks/useTargetData.hook' import { useTargetData } from '../../../hooks/useTargetData.hook'
import isObject from 'lodash/isObject' import isObject from 'lodash/isObject'
import cloneDeep from 'lodash/cloneDeep'
import { toString } from '@/utils' import { toString } from '@/utils'
const { targetData } = useTargetData() const { targetData } = useTargetData()
@ -163,20 +162,6 @@ const dimensionsAndSourceHandle = () => {
} }
} }
//
const filterRes = (data: any) => {
try {
if(targetData.value.filter) {
const fn = new Function('data', targetData.value.filter)
const res = fn(cloneDeep(data))
return toString(res)
}
return toString(cloneDeep(data))
} catch (error) {
return '过滤函数错误'
}
}
watch( watch(
() => targetData.value?.option?.dataset, () => targetData.value?.option?.dataset,
( (

View File

@ -17,15 +17,13 @@
</template> </template>
编辑 编辑
</n-button> </n-button>
<n-button tertiary size="small" @click="delFilter"> <n-button tertiary size="small" @click="delFilter"> 删除 </n-button>
删除
</n-button>
</n-space> </n-space>
</template> </template>
</n-card> </n-card>
</template> </template>
<template v-else> <template v-else>
<n-button @click="addFilter"> <n-button class="go-ml-3" @click="addFilter">
<template #icon> <template #icon>
<n-icon> <n-icon>
<filter-icon /> <filter-icon />
@ -97,13 +95,13 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, computed, watch, toRefs } from 'vue' import { ref, computed, watch, toRefs, toRaw } from 'vue'
import { MonacoEditor } from '@/components/Pages/MonacoEditor' import { MonacoEditor } from '@/components/Pages/MonacoEditor'
import { useTargetData } from '../../../hooks/useTargetData.hook' import { useTargetData } from '../../../hooks/useTargetData.hook'
import { RequestHttpEnum, RequestDataTypeEnum, ResultEnum } from '@/enums/httpEnum' import { RequestHttpEnum, RequestDataTypeEnum, ResultEnum } from '@/enums/httpEnum'
import { icon } from '@/plugins' import { icon } from '@/plugins'
import { goDialog, toString } from '@/utils' import { goDialog, toString } from '@/utils'
import { http } from '@/api/http' import { http, customizeHttp } from '@/api/http'
import cloneDeep from 'lodash/cloneDeep' import cloneDeep from 'lodash/cloneDeep'
const { DocumentTextIcon } = icon.ionicons5 const { DocumentTextIcon } = icon.ionicons5
@ -124,20 +122,14 @@ const sourceData = ref<any>('')
// //
const fetchTargetData = async () => { const fetchTargetData = async () => {
try { try {
const { requestUrl, requestHttpType } = targetData.value.request const res = await customizeHttp(toRaw(targetData.value.request), toRaw(chartEditStore.requestGlobalConfig))
if (!requestUrl) { if (res && res.data) {
window['$message'].warning('请求参数不正确,请检查!')
sourceData.value = '请求参数不正确,请检查!'
return
}
const completePath = requestOriginUrl && requestOriginUrl.value + requestUrl
const res = await http(requestHttpType)(completePath || '', {})
if (res.status === ResultEnum.SUCCESS) {
sourceData.value = res.data sourceData.value = res.data
return return
} }
window['$message'].warning('数据异常,请检查参数!')
} catch (error) { } catch (error) {
window['$message'].warning('数据异常,请检查接口数据') window['$message'].warning('数据异常,请检查参数!')
} }
} }

View File

@ -0,0 +1,3 @@
import RequestGlobalConfig from './index.vue'
export { RequestGlobalConfig }

View File

@ -0,0 +1,105 @@
<template>
<!-- 全局配置 -->
<n-card class="n-card-shallow">
<n-tag type="info" :bordered="false" style="border-radius: 5px"> 全局配置 </n-tag>
<setting-item-box
name="服务"
:itemRightStyle="{
gridTemplateColumns: '5fr 2fr 1fr'
}"
>
<!-- 源地址 -->
<setting-item name="前置 URL">
<n-input v-model:value.trim="requestOriginUrl" :disabled="editDisabled" placeholder="例http://127.0.0.1/"></n-input>
</setting-item>
<setting-item name="更新间隔,为 0 只会初始化">
<n-input-group>
<n-input-number
class="select-time-number"
v-model:value.trim="requestInterval"
min="0"
:show-button="false"
:disabled="editDisabled"
placeholder="请输入数字"
>
</n-input-number>
<!-- 单位 -->
<n-select
class="select-time-options"
v-model:value="requestIntervalUnit"
:options="selectTimeOptions"
:disabled="editDisabled"
/>
</n-input-group>
</setting-item>
<n-button v-show="editDisabled" type="primary" ghost @click="editDisabled = false">
<template #icon>
<n-icon>
<pencil-icon />
</n-icon>
</template>
编辑配置
</n-button>
</setting-item-box>
<!-- table 内容体 -->
<n-collapse-transition :show="showTable">
<request-global-header-table :editDisabled="editDisabled"></request-global-header-table>
</n-collapse-transition>
<!-- 箭头 -->
<div v-if="showTable" class="go-flex-center go-mt-3 down" @click="showTable = false">
<n-icon size="32">
<chevron-up-outline-icon />
</n-icon>
</div>
<div v-else class="go-flex-center go-mt-3 down" @click="showTable = true">
<n-tooltip trigger="hover" placement="top" :keep-alive-on-hover="false">
<template #trigger>
<n-icon size="32">
<chevron-down-outline-icon />
</n-icon>
</template>
展开
</n-tooltip>
</div>
</n-card>
</template>
<script setup lang="ts">
import { ref, toRefs } from 'vue'
import { useDesignStore } from '@/store/modules/designStore/designStore'
import { SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import { useTargetData } from '@/views/chart/ContentConfigurations/components/hooks/useTargetData.hook'
import { selectTypeOptions, selectTimeOptions } from '@/views/chart/ContentConfigurations/components/ChartData/index.d'
import { RequestGlobalHeaderTable } from '../RequestGlobalHeaderTable'
import { icon } from '@/plugins'
const { PencilIcon, ChevronDownOutlineIcon, ChevronUpOutlineIcon } = icon.ionicons5
const { chartEditStore } = useTargetData()
const { requestOriginUrl, requestInterval, requestIntervalUnit } = toRefs(chartEditStore.getRequestGlobalConfig)
const editDisabled = ref(true)
const designStore = useDesignStore()
const themeColor = ref(designStore.getAppTheme)
const showTable = ref(false)
</script>
<style lang="scss" scoped>
.n-card-shallow {
&:hover {
border-color: v-bind('themeColor');
}
}
.down {
cursor: pointer;
&:hover {
color: v-bind('themeColor');
}
}
.select-time-number {
width: 100%;
}
.select-time-options {
width: 100px;
}
</style>

View File

@ -0,0 +1,3 @@
import RequestGlobalHeaderTable from './index.vue'
export { RequestGlobalHeaderTable }

View File

@ -0,0 +1,32 @@
<template>
<div>
<n-tabs type="line" animated v-model:value="tabValue">
<n-tab v-for="item in tabs" :key="item" :name="item" :tab="item"> {{ item }} </n-tab>
</n-tabs>
<div class="go-mt-3">
<request-header-table :editDisabled="$attrs.editDisabled" :target="requestParams[tabValue]" @update="updateRequestParams"></request-header-table>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, toRefs } from 'vue'
import { useTargetData } from '@/views/chart/ContentConfigurations/components/hooks/useTargetData.hook'
import { RequestHeaderTable } from '../RequestHeaderTable'
import { RequestParamsTypeEnum, RequestParamsObjType } from '@/enums/httpEnum'
const { chartEditStore } = useTargetData()
const { requestParams } = toRefs(chartEditStore.getRequestGlobalConfig)
const tabValue = ref<RequestParamsTypeEnum>(RequestParamsTypeEnum.HEADER)
const tabs = [RequestParamsTypeEnum.HEADER]
//
const updateRequestParams = (paramsObj: RequestParamsObjType) => {
if (tabValue.value === RequestParamsTypeEnum.HEADER) {
requestParams.value[tabValue.value] = paramsObj
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,3 @@
import RequestHeader from './index.vue'
export { RequestHeader }

View File

@ -0,0 +1,134 @@
<template>
<n-space vertical>
<div style="width: 600px">
<n-tabs v-model:value="requestContentType" type="segment" size="small">
<n-tab :name="RequestContentTypeEnum.DEFAULT" tab="普通请求"> </n-tab>
<n-tab :name="RequestContentTypeEnum.SQL" tab="SQL 请求"> </n-tab>
</n-tabs>
</div>
<div v-show="requestContentType === RequestContentTypeEnum.DEFAULT">
<n-tabs type="line" animated v-model:value="tabValue">
<n-tab v-for="item in RequestParamsTypeEnum" :key="item" :name="item" :tab="item"> {{ item }} </n-tab>
</n-tabs>
<!-- 各个页面 -->
<div class="go-mt-3">
<div v-if="tabValue !== RequestParamsTypeEnum.BODY">
<request-header-table :target="requestParams[tabValue]" @update="updateRequestParams"></request-header-table>
</div>
<!-- 选择了 body -->
<div v-else>
<n-radio-group v-model:value="requestParamsBodyType" name="radiogroup">
<n-space>
<n-radio v-for="bodyEnum in RequestBodyEnumList" :key="bodyEnum" :value="bodyEnum">
{{ bodyEnum }}
</n-radio>
</n-space>
</n-radio-group>
<!-- none -->
<n-card class="go-mt-3 go-pb-3" v-if="requestParamsBodyType === RequestBodyEnum['NONE']">
<n-text depth="3">该请求没有 Body </n-text>
</n-card>
<!-- 具有对象属性时 -->
<template
v-else-if="
requestParamsBodyType === RequestBodyEnum['FORM_DATA'] ||
requestParamsBodyType === RequestBodyEnum['X_WWW_FORM_URLENCODED']
"
>
<request-header-table
class="go-mt-3"
:target="requestParams[RequestParamsTypeEnum.BODY][requestParamsBodyType]"
@update="updateRequestBodyTable"
></request-header-table>
</template>
<!-- json -->
<template v-else-if="requestParamsBodyType === RequestBodyEnum['JSON']">
<monaco-editor
v-model:modelValue="requestParams[RequestParamsTypeEnum.BODY][requestParamsBodyType]"
width="600px"
height="200px"
language="json"
/>
</template>
<!-- xml -->
<template v-else-if="requestParamsBodyType === RequestBodyEnum['XML']">
<monaco-editor
v-model:modelValue="requestParams[RequestParamsTypeEnum.BODY][requestParamsBodyType]"
width="600px"
height="200px"
language="html"
/>
</template>
</div>
</div>
</div>
<div v-show="requestContentType === RequestContentTypeEnum.SQL">
<template v-if="requestHttpType === RequestHttpEnum.GET">
<n-text>SQL 类型不支持 Get 请求请使用其它方式</n-text>
</template>
<template v-else>
<setting-item-box name="键名">
<n-tag type="primary" :bordered="false" style="width: 40px; font-size: 16px"> sql </n-tag>
</setting-item-box>
<setting-item-box name="键值">
<monaco-editor v-model:modelValue="requestSQLContent['sql']" width="600px" height="200px" language="sql" />
</setting-item-box>
</template>
</div>
</n-space>
</template>
<script setup lang="ts">
import { ref, toRefs } from 'vue'
import { MonacoEditor } from '@/components/Pages/MonacoEditor'
import { SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import { useTargetData } from '@/views/chart/ContentConfigurations/components/hooks/useTargetData.hook'
import { RequestHeaderTable } from '../RequestHeaderTable/index'
import {
RequestParamsTypeEnum,
RequestContentTypeEnum,
RequestParamsObjType,
RequestBodyEnumList,
RequestBodyEnum,
RequestHttpEnum
} from '@/enums/httpEnum'
const { targetData } = useTargetData()
const { requestHttpType, requestContentType, requestSQLContent, requestParams, requestParamsBodyType } = toRefs(targetData.value.request)
const tabValue = ref<RequestParamsTypeEnum>(RequestParamsTypeEnum.PARAMS)
//
const updateRequestParams = (paramsObj: RequestParamsObjType) => {
if (tabValue.value !== RequestParamsTypeEnum.BODY) {
requestParams.value[tabValue.value] = paramsObj
}
}
//
const updateRequestBodyTable = (paramsObj: RequestParamsObjType) => {
if (
tabValue.value === RequestParamsTypeEnum.BODY &&
// body
(requestParamsBodyType.value === RequestBodyEnum.FORM_DATA ||
requestParamsBodyType.value === RequestBodyEnum.X_WWW_FORM_URLENCODED)
) {
requestParams.value[RequestParamsTypeEnum.BODY][requestParamsBodyType.value] = paramsObj
}
}
</script>
<style lang="scss" scoped>
.select-type {
width: 300px;
}
</style>

View File

@ -0,0 +1,3 @@
import RequestHeaderTable from './index.vue'
export { RequestHeaderTable }

View File

@ -0,0 +1,161 @@
<template>
<n-table class="go-request-header-table-box" :single-line="false" size="small">
<thead>
<tr>
<th></th>
<th>Key</th>
<th>Value</th>
<th>操作</th>
<th>结果</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in tableArray.content" :key="index">
<td>
{{ index + 1 }}
</td>
<td>
<n-input v-model:value="item.key" :disabled="editDisabled" type="text" size="small" @blur="blur" />
</td>
<td>
<n-input v-model:value="item.value" :disabled="editDisabled" type="text" size="small" @blur="blur" />
</td>
<td>
<div style="width: 80px">
<n-button class="go-ml-2" type="primary" size="small" ghost :disabled="editDisabled" @click="add(index)"
>+</n-button
>
<n-button
class="go-ml-2"
type="warning"
size="small"
ghost
:disabled="index === 0 && editDisabled"
@click="remove(index)"
>
-
</n-button>
</div>
</td>
<td>
<n-button v-if="item.error" class="go-ml-2" text type="error"> 格式错误 </n-button>
<n-button v-else class="go-ml-2" text type="primary"> 格式通过 </n-button>
</td>
</tr>
</tbody>
</n-table>
</template>
<script setup lang="ts">
import { PropType, reactive, ref, toRefs, watch } from 'vue'
import { RequestParamsObjType } from '@/enums/httpEnum'
const emits = defineEmits(['update'])
const props = defineProps({
target: {
type: Object as PropType<RequestParamsObjType>,
required: true,
default: () => {}
},
editDisabled: {
type: Boolean,
required: false,
default: false
}
})
//
const error = ref(false)
//
const defaultItem = {
key: '',
value: '',
error: false
}
const tableArray = reactive<{
content: typeof defaultItem[]
}>({ content: [] })
//
const blur = () => {
let successNum = 0
tableArray.content.forEach(item => {
if ((item.key !== '' && item.value == '') || (item.key === '' && item.value !== '')) {
//
item.error = true
} else {
//
successNum++
item.error = false
}
})
//
if (successNum == tableArray.content.length) {
//
const updateObj: any = {}
tableArray.content.forEach((e: typeof defaultItem) => {
if (e.key) updateObj[e.key] = e.value
})
emits('update', updateObj)
}
}
//
const add = (index: number) => {
tableArray.content.splice(index + 1, 0, {
key: '',
value: '',
error: false
})
}
//
const remove = (index: number) => {
if (tableArray.content.length !== 1) {
tableArray.content.splice(index, 1)
}
blur()
}
//
watch(
() => props.target,
(target: RequestParamsObjType) => {
tableArray.content = []
for (const k in target) {
tableArray.content.push({
key: k,
value: target[k],
error: false
})
}
//
if (!tableArray.content.length) tableArray.content = [JSON.parse(JSON.stringify(defaultItem))]
},
{
immediate: true,
deep: true
}
)
</script>
<style lang="scss">
@include go('request-header-table-box') {
background-color: rgba(0, 0, 0, 0);
@include deep() {
.n-data-table .n-data-table-td {
background-color: rgba(0, 0, 0, 0);
}
.add-btn-box {
width: 100%;
display: flex;
justify-content: center;
.add-btn {
width: 300px;
}
}
}
}
</style>

View File

@ -0,0 +1,3 @@
import RequestTargetConfig from './index.vue'
export { RequestTargetConfig }

View File

@ -0,0 +1,107 @@
<template>
<!-- 组件配置 -->
<n-divider class="go-my-3" title-placement="left"></n-divider>
<setting-item-box
:itemRightStyle="{
gridTemplateColumns: '5fr 2fr 1fr'
}"
>
<template #name>
地址
<n-tooltip trigger="hover" v-if="isDev()">
<template #trigger>
<n-icon size="21" :depth="3">
<help-outline-icon></help-outline-icon>
</n-icon>
</template>
<ul class="go-pl-0">
开发环境使用 mock 数据请输入
<li v-for="item in apiList" :key="item.value">
<n-text type="info"> {{ item.value }} </n-text>
</li>
</ul>
</n-tooltip>
</template>
<setting-item name="请求方式 & URL 地址">
<n-input-group>
<n-select class="select-type-options" v-model:value="requestHttpType" :options="selectTypeOptions" />
<n-input v-model:value.trim="requestUrl" :min="1" placeholder="请输入地址去除前置URL">
<template #prefix>
<n-text>{{ requestOriginUrl }}</n-text>
<n-divider vertical />
</template>
</n-input>
</n-input-group>
<!-- 组件url -->
</setting-item>
<setting-item name="更新间隔,为 0 只会初始化">
<n-input-group>
<n-input-number
v-model:value.trim="requestInterval"
class="select-time-number"
min="0"
:show-button="false"
placeholder="默认使用全局数据"
>
</n-input-number>
<!-- 单位 -->
<n-select class="select-time-options" v-model:value="requestIntervalUnit" :options="selectTimeOptions" />
</n-input-group>
</setting-item>
</setting-item-box>
<setting-item-box name="选择方式" class="go-mt-0">
<request-header></request-header>
</setting-item-box>
</template>
<script setup lang="ts">
import { ref, toRefs } from 'vue'
import { SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import { useTargetData } from '@/views/chart/ContentConfigurations/components/hooks/useTargetData.hook'
import { selectTypeOptions, selectTimeOptions } from '@/views/chart/ContentConfigurations/components/ChartData/index.d'
import { RequestHeader } from '../RequestHeader'
import { isDev } from '@/utils'
import { icon } from '@/plugins'
import { chartDataUrl, rankListUrl, scrollBoardUrl, numberFloatUrl, numberIntUrl, textUrl, imageUrl } from '@/api/mock'
const { HelpOutlineIcon } = icon.ionicons5
const { targetData, chartEditStore } = useTargetData()
const { requestOriginUrl } = toRefs(chartEditStore.getRequestGlobalConfig)
const { requestInterval, requestIntervalUnit, requestHttpType, requestUrl } = toRefs(targetData.value.request)
const apiList = [
{
value: `【图表】${chartDataUrl}`
},
{
value: `【文本】${textUrl}`
},
{
value: `【0~100 整数】${numberIntUrl}`
},
{
value: `【0~1小数】${numberFloatUrl}`
},
{
value: `【图片地址】${imageUrl}`
},
{
value: `【排名列表】${rankListUrl}`
},
{
value: `【滚动表格】${scrollBoardUrl}`
}
]
</script>
<style lang="scss" scoped>
.select-time-number {
width: 100%;
}
.select-time-options {
width: 100px;
}
.select-type-options {
width: 120px;
}
</style>

View File

@ -0,0 +1,3 @@
import ChartDataRequest from './index.vue'
export { ChartDataRequest }

View File

@ -0,0 +1,75 @@
<template>
<n-modal class="go-chart-data-request" v-model:show="modelShow" :mask-closable="false" @afterLeave="closeHandle">
<n-card :bordered="false" role="dialog" size="small" aria-modal="true" style="width: 1000px; height: 800px">
<template #header></template>
<template #header-extra> </template>
<n-scrollbar style="max-height: 718px">
<div class="go-pr-3">
<n-space vertical>
<request-global-config></request-global-config>
<request-target-config></request-target-config>
</n-space>
</div>
</n-scrollbar>
<!-- 底部 -->
<template #action>
<n-space justify="space-between">
<div>
<n-text> {{ chartConfig.categoryName || rename }} </n-text>
<n-text> </n-text>
<n-tag type="primary" :bordered="false" style="border-radius: 5px"> {{ requestContentTypeObj[requestContentType] }} </n-tag>
</div>
<n-button type="primary" @click="closeHandle">确认</n-button>
</n-space>
</template>
</n-card>
</n-modal>
</template>
<script script lang="ts" setup>
import { toRefs } from 'vue'
import { RequestContentTypeEnum } from '@/enums/httpEnum'
import { useTargetData } from '../../../hooks/useTargetData.hook'
import { RequestGlobalConfig } from './components/RequestGlobalConfig'
import { RequestTargetConfig } from './components/RequestTargetConfig'
const emit = defineEmits(['update:modelShow'])
const { targetData } = useTargetData()
//
const { chartConfig, rename } = toRefs(targetData.value)
const { requestContentType } = toRefs(targetData.value.request)
const requestContentTypeObj = {
[RequestContentTypeEnum.DEFAULT]: '普通请求',
[RequestContentTypeEnum.SQL]: 'SQL 请求'
}
defineProps({
modelShow: Boolean
})
const closeHandle = () => {
emit('update:modelShow', false)
}
</script>
<style lang="scss" scoped>
@include go('chart-data-request') {
&.n-card.n-modal,
.n-card {
@extend .go-background-filter;
}
.n-card-shallow {
background-color: rgba(0, 0, 0, 0) !important;
}
@include deep() {
& > .n-card__content {
padding-right: 0;
}
.n-card__content {
padding-bottom: 5px;
}
}
}
</style>

View File

@ -1,4 +1,4 @@
import { RequestHttpEnum, RequestDataTypeEnum } from '@/enums/httpEnum' import { RequestHttpEnum, RequestHttpIntervalEnum, RequestDataTypeEnum, SelectHttpTimeNameObj } from '@/enums/httpEnum'
// 匹配结果 // 匹配结果
export enum DataResultEnum { export enum DataResultEnum {
@ -24,9 +24,81 @@ export interface SelectCreateDataType {
disabled?: boolean disabled?: boolean
} }
// ajax 请求 // ajax 请求类型
export interface SelectHttpType { export interface SelectHttpType {
label: RequestHttpEnum label: RequestHttpEnum
value: RequestHttpEnum value: RequestHttpEnum
disabled?: boolean disabled?: boolean
style?: object
} }
// 类型选项
export const selectTypeOptions: SelectHttpType[] = [
{
label: RequestHttpEnum.GET,
value: RequestHttpEnum.GET,
style: {
color: 'greenyellow',
fontWeight: 'bold'
}
},
{
label: RequestHttpEnum.POST,
value: RequestHttpEnum.POST,
style: {
color: 'skyblue',
fontWeight: 'bold'
}
},
{
label: RequestHttpEnum.PUT,
value: RequestHttpEnum.PUT,
style: {
color: 'goldenrod',
fontWeight: 'bold'
}
},
{
label: RequestHttpEnum.PATCH,
value: RequestHttpEnum.PATCH,
style: {
color: 'violet',
fontWeight: 'bold'
}
},
{
label: RequestHttpEnum.DELETE,
value: RequestHttpEnum.DELETE,
disabled: true,
style: {
fontWeight: 'bold'
}
},
]
// ajax 请求间隔
export interface SelectHttpTimeType {
label: string
value: RequestHttpIntervalEnum
disabled?: boolean
}
// 时间选项
export const selectTimeOptions: SelectHttpTimeType[] = [
{
label: SelectHttpTimeNameObj[RequestHttpIntervalEnum.SECOND],
value: RequestHttpIntervalEnum.SECOND
},
{
label: SelectHttpTimeNameObj[RequestHttpIntervalEnum.MINUTE],
value: RequestHttpIntervalEnum.MINUTE
},
{
label: SelectHttpTimeNameObj[RequestHttpIntervalEnum.HOUR],
value: RequestHttpIntervalEnum.HOUR
},
{
label: SelectHttpTimeNameObj[RequestHttpIntervalEnum.DAY],
value: RequestHttpIntervalEnum.DAY
},
]

View File

@ -7,8 +7,6 @@
/> />
</setting-item-box> </setting-item-box>
<n-divider style="margin: 10px 0;"></n-divider>
<!-- 静态 --> <!-- 静态 -->
<chart-data-static <chart-data-static
v-if="targetData.request.requestDataType === RequestDataTypeEnum.STATIC" v-if="targetData.request.requestDataType === RequestDataTypeEnum.STATIC"

View File

@ -1,13 +0,0 @@
<template>
<div>
事件
</div>
</template>
<script setup>
</script>
<style lang="scss" scoped>
</style>

View File

@ -54,7 +54,7 @@ export default ({ mode }) => defineConfig({
plugins: [ plugins: [
vue(), vue(),
monacoEditorPlugin({ monacoEditorPlugin({
languageWorkers: ['editorWorkerService', 'typescript', 'json'] languageWorkers: ['editorWorkerService', 'typescript', 'json', 'html']
}), }),
viteMockServe({ viteMockServe({
mockPath: '/src/api/mock', mockPath: '/src/api/mock',