Showing
50 changed files
with
2633 additions
and
42 deletions
1 | # Proxy | 1 | # Proxy |
2 | -VITE_GLOB_PROXY = [["/api", "http://222.180.200.114:48080/api"]] | 2 | +# VITE_GLOB_PROXY = [["/api", "http://222.180.200.114:48080/api"]] |
3 | +VITE_GLOB_PROXY = [["/api", "http://192.168.10.118:8080/api"]] | ||
3 | 4 | ||
4 | # Api prefix | 5 | # Api prefix |
5 | VITE_GLOB_API_URL = /api | 6 | VITE_GLOB_API_URL = /api |
@@ -2,7 +2,9 @@ module.exports = { | @@ -2,7 +2,9 @@ module.exports = { | ||
2 | root: true, | 2 | root: true, |
3 | parser: 'vue-eslint-parser', | 3 | parser: 'vue-eslint-parser', |
4 | globals: { | 4 | globals: { |
5 | - postMessage: true | 5 | + postMessage: true, |
6 | + Recordable: 'readonly', | ||
7 | + Nullable: 'readonly', | ||
6 | }, | 8 | }, |
7 | parserOptions: { | 9 | parserOptions: { |
8 | parser: '@typescript-eslint/parser', | 10 | parser: '@typescript-eslint/parser', |
@@ -31,8 +33,5 @@ module.exports = { | @@ -31,8 +33,5 @@ module.exports = { | ||
31 | 'vue/multi-word-component-names': 'off', | 33 | 'vue/multi-word-component-names': 'off', |
32 | 'vue/valid-template-root': 'off', | 34 | 'vue/valid-template-root': 'off', |
33 | 'vue/no-mutating-props': 'off', | 35 | 'vue/no-mutating-props': 'off', |
34 | - }, | ||
35 | - global: { | ||
36 | - Recordable: 'readonly' | ||
37 | } | 36 | } |
38 | } | 37 | } |
src/api/external/common/index.ts
0 → 100644
1 | +import { defHttp } from "@/utils/external/http/axios"; | ||
2 | +import { DictItem } from "./model"; | ||
3 | + | ||
4 | +enum Api { | ||
5 | + GET_DICT = '/dict_item' | ||
6 | +} | ||
7 | + | ||
8 | +export const getDictItemByCode = (value: string) => { | ||
9 | + return defHttp.post<DictItem[]>({ | ||
10 | + url: `${Api.GET_DICT}/find`, | ||
11 | + params: { | ||
12 | + dictCode: value | ||
13 | + } | ||
14 | + }) | ||
15 | +} |
src/api/external/common/model/index.ts
0 → 100644
src/api/external/customRequest/index.ts
0 → 100644
1 | +import { RequestBodyEnum } from "@/enums/httpEnum" | ||
2 | +import { RequestConfigType, RequestGlobalConfigType } from "@/store/modules/chartEditStore/chartEditStore.d" | ||
3 | +import { defHttp } from "@/utils/external/http/axios" | ||
4 | + | ||
5 | +export const isFullUrl = (url = '') => { | ||
6 | + try { | ||
7 | + new URL(url) | ||
8 | + return true | ||
9 | + } catch (error) { | ||
10 | + return false | ||
11 | + } | ||
12 | +} | ||
13 | + | ||
14 | +export const getUrl = (url = '') => { | ||
15 | + const isFullUrlFlag = isFullUrl(url) | ||
16 | + const { origin } = window.location | ||
17 | + return isFullUrlFlag ? new URL(url) : { pathname: url, origin } | ||
18 | +} | ||
19 | + | ||
20 | +export const customRequest = async (request: RequestConfigType) => { | ||
21 | + const { requestHttpType, requestParams, requestParamsBodyType, requestUrl } = request as RequestGlobalConfigType & RequestConfigType | ||
22 | + const { Params, Header, Body } = requestParams | ||
23 | + | ||
24 | + const { origin, pathname } = getUrl(requestUrl!) | ||
25 | + | ||
26 | + const body = Body[requestParamsBodyType as Exclude<'NONE', keyof typeof RequestBodyEnum>] | ||
27 | + | ||
28 | + return defHttp.request<any>({ | ||
29 | + url: pathname, | ||
30 | + baseURL: origin, | ||
31 | + method: requestHttpType, | ||
32 | + params: Params, | ||
33 | + data: body, | ||
34 | + headers: Header | ||
35 | + }, { | ||
36 | + joinPrefix: false, | ||
37 | + apiUrl: '' | ||
38 | + }) | ||
39 | +} |
src/api/external/dynamicRequest/index.ts
0 → 100644
1 | + import { defHttp } from '@/utils/external/http/axios'; | ||
2 | +import { DeviceAttributesRecord, GetDeviceListParams, PublicInterfaceRecord } from './model'; | ||
3 | +import { PaginationResult } from '/#/external/axios'; | ||
4 | + | ||
5 | +enum Api { | ||
6 | + PUBLIC_API = '/data_view_interface', | ||
7 | + ORG_LISt = '/organization/me/list', | ||
8 | + DEVICE_PROFILE_LIST = '/device_profile/me/list', | ||
9 | + DEVICE_LIST = '/device/list', | ||
10 | + DEVICE_ATTR_LIST = '/device/attributes', | ||
11 | + GET_PUBLIC_INTERFACE_ALL = '/data_view_interface/find_all_interface', | ||
12 | + GET_PUBLIC_INTERFACE_DETAIL = '/data_view_interface/get_interface_details' | ||
13 | +} | ||
14 | + | ||
15 | +export const getPublicInterface = async (params: Record<'page' | 'pageSize', number>) => { | ||
16 | + return defHttp.get<PaginationResult<PublicInterfaceRecord>>({ | ||
17 | + url: Api.PUBLIC_API, | ||
18 | + params | ||
19 | + }) | ||
20 | +} | ||
21 | + | ||
22 | +export const getOrgList = async () => { | ||
23 | + return defHttp.get({ | ||
24 | + url: Api.ORG_LISt | ||
25 | + }) | ||
26 | +} | ||
27 | + | ||
28 | +export const getDeviceProfileList = async (params?: Record<'deviceType', string>) => { | ||
29 | + return defHttp.get({ | ||
30 | + url: Api.DEVICE_PROFILE_LIST, | ||
31 | + params | ||
32 | + }) | ||
33 | +} | ||
34 | + | ||
35 | +export const getDeviceList = async (params?: GetDeviceListParams) => { | ||
36 | + return defHttp.get({ | ||
37 | + url: Api.DEVICE_LIST, | ||
38 | + params | ||
39 | + }) | ||
40 | +} | ||
41 | + | ||
42 | +export const getDeviceAttrList = async (deviceProfileId: string) => { | ||
43 | + return defHttp.get<DeviceAttributesRecord[]>({ | ||
44 | + url: `${Api.DEVICE_ATTR_LIST}/${deviceProfileId}` | ||
45 | + }) | ||
46 | +} | ||
47 | + | ||
48 | + | ||
49 | +export const getDeviceInterfaceDetail = async (interfaces: string[]) => { | ||
50 | + return defHttp.get({ | ||
51 | + url: Api.GET_PUBLIC_INTERFACE_DETAIL, | ||
52 | + params: interfaces | ||
53 | + }) | ||
54 | +} | ||
55 | + | ||
56 | +export const getAllPublicInterface = async () => { | ||
57 | + return defHttp.get<PublicInterfaceRecord[]>({ | ||
58 | + url: Api.GET_PUBLIC_INTERFACE_ALL | ||
59 | + }) | ||
60 | +} |
1 | +import { RequestParams as OriginRequestParams } from "@/enums/httpEnum" | ||
2 | + | ||
3 | +export interface RequestParams { | ||
4 | + Body: Recordable | ||
5 | + Header: Recordable | ||
6 | + Params: { | ||
7 | + key: string | ||
8 | + required: boolean | ||
9 | + value: string | ||
10 | + }[] | ||
11 | +} | ||
12 | + | ||
13 | +export interface PublicInterfaceRecord { | ||
14 | + id: string, | ||
15 | + creator: string, | ||
16 | + createTime: string, | ||
17 | + updater: string, | ||
18 | + updateTime: string, | ||
19 | + enabled: boolean, | ||
20 | + tenantId: string, | ||
21 | + interfaceName: string, | ||
22 | + requestContentType: number, | ||
23 | + requestOriginUrl: string, | ||
24 | + requestHttpType: string, | ||
25 | + requestParamsBodyType: string, | ||
26 | + requestUrl: string, | ||
27 | + requestParams: string | OriginRequestParams, | ||
28 | +} | ||
29 | + | ||
30 | + | ||
31 | +export interface GetDeviceListParams { | ||
32 | + organizationId?: string | ||
33 | + deviceProfileId?: string | ||
34 | + deviceType?: string | ||
35 | +} | ||
36 | + | ||
37 | +export interface DeviceAttributesDetail { | ||
38 | + dataType: { | ||
39 | + specs: Recordable | ||
40 | + type: string | ||
41 | + } | ||
42 | +} | ||
43 | + | ||
44 | +export interface DeviceAttributesRecord { | ||
45 | + name: string, | ||
46 | + identifier: string | ||
47 | + detail: DeviceAttributesDetail | ||
48 | +} |
src/components/external/Icon/Form/index.ts
0 → 100644
1 | +<script lang="ts" setup> | ||
2 | +import { NForm, NGrid } from 'naive-ui'; | ||
3 | +import { computed, reactive, ref, unref, useAttrs } from 'vue'; | ||
4 | +import { BasicFormProps, FormSchema } from './types/form'; | ||
5 | +import { basicProps } from './props'; | ||
6 | +import { useDesign } from '@/hooks/external/useDesign'; | ||
7 | +import { dateItemType } from './helper'; | ||
8 | +import { dateUtil } from '@/utils/external/dateUtil'; | ||
9 | +import { Dayjs } from 'dayjs'; | ||
10 | +import FormItem from './components/FormItem.vue'; | ||
11 | +import { deepMerge } from '@/utils/external'; | ||
12 | + | ||
13 | +const props = defineProps(basicProps) | ||
14 | + | ||
15 | +const attrs = useAttrs() | ||
16 | + | ||
17 | +const fromModel = reactive<Recordable>({}) | ||
18 | + | ||
19 | +const defaultValueRef = ref<Recordable>({}) | ||
20 | + | ||
21 | +const isInitialDefaultRef = ref(false) | ||
22 | + | ||
23 | +const propsRef = ref<Partial<BasicFormProps>>({}) | ||
24 | + | ||
25 | +const schemaRef = ref<Nullable<FormSchema[]>>(null) | ||
26 | + | ||
27 | +const formElRef = ref<Nullable<Recordable>>(null) | ||
28 | + | ||
29 | +const { prefixCls } = useDesign('basic-form') | ||
30 | + | ||
31 | +const getProps = computed(() => { | ||
32 | + return { ...props, ...unref(propsRef) } as BasicFormProps | ||
33 | +}) | ||
34 | + | ||
35 | + | ||
36 | +const getBindValue = computed(() => { | ||
37 | + return { ...attrs, ...unref(getProps) } as Recordable | ||
38 | +}) | ||
39 | + | ||
40 | + | ||
41 | +const getSchema = computed(() => { | ||
42 | + const schemas = unref(schemaRef) || unref(getProps).schemas | ||
43 | + | ||
44 | + for (const schema of schemas) { | ||
45 | + const { defaultValue, component } = schema | ||
46 | + | ||
47 | + if (defaultValue && dateItemType.includes(component)) { | ||
48 | + if (!Array.isArray(defaultValue)) { | ||
49 | + schema.defaultValue = dateUtil(defaultValue) | ||
50 | + } else { | ||
51 | + const def: Dayjs[] = [] | ||
52 | + defaultValue.forEach(item => def.push(dateUtil(item))) | ||
53 | + schema.defaultValue = def | ||
54 | + } | ||
55 | + } | ||
56 | + } | ||
57 | + | ||
58 | + return schemas | ||
59 | +}) | ||
60 | + | ||
61 | +async function setProps(params: Partial<BasicFormProps>) { | ||
62 | + propsRef.value = deepMerge(unref(propsRef) || {},) | ||
63 | +} | ||
64 | + | ||
65 | +const setFormModel = (key: string, value: any) => { | ||
66 | + fromModel[key] = value | ||
67 | + | ||
68 | +} | ||
69 | + | ||
70 | +const handleEnterPress = () => { | ||
71 | + | ||
72 | +} | ||
73 | + | ||
74 | + | ||
75 | +</script> | ||
76 | + | ||
77 | +<template> | ||
78 | + <NForm ref="formElRef" :model="fromModel" @keypress.enter="handleEnterPress"> | ||
79 | + <NGrid> | ||
80 | + <slot name="formHeader" /> | ||
81 | + <template v-for="schema in getSchema" :key="schema.field"> | ||
82 | + <FormItem :schema="schema" :formProps="getProps" :allDefaultValues="defaultValueRef" :formModel="fromModel" | ||
83 | + :setFormModel="setFormModel"> | ||
84 | + <template #[item]="data" v-for="item in Object.keys($slots)"> | ||
85 | + <slot :name="item" v-bind="data" /> | ||
86 | + </template> | ||
87 | + </FormItem> | ||
88 | + </template> | ||
89 | + <slot name="formFooter" /> | ||
90 | + </NGrid> | ||
91 | + </NForm> | ||
92 | +</template> | ||
93 | + | ||
94 | +<style scoped lang="scss"> | ||
95 | +</style> |
1 | +import { FormProps } from 'naive-ui' | ||
2 | +import { FormSchema } from './types/form' | ||
3 | + | ||
4 | +const DEFAULT_FORM_PROPS: FormProps = { | ||
5 | + size: 'small', | ||
6 | + | ||
7 | +} | ||
8 | + | ||
9 | +export const basicProps = { | ||
10 | + formProps: { | ||
11 | + type: Object as PropType<FormProps>, | ||
12 | + default: () => DEFAULT_FORM_PROPS | ||
13 | + }, | ||
14 | + | ||
15 | + /** | ||
16 | + * @description 表单字段映射成时间 | ||
17 | + */ | ||
18 | + fieldMapToTime: { | ||
19 | + type: Array as PropType<any[]>, | ||
20 | + default: () => [] | ||
21 | + }, | ||
22 | + | ||
23 | + /** | ||
24 | + * @description 表单配置 | ||
25 | + */ | ||
26 | + schemas: { | ||
27 | + type: Array as PropType<FormSchema[]>, | ||
28 | + default: () => [] | ||
29 | + }, | ||
30 | + | ||
31 | + | ||
32 | +} |
1 | +import { ExtractPropTypes } from "vue"; | ||
2 | +import { FormComponentTypeEnum } from "."; | ||
3 | +import { basicProps } from "../props"; | ||
4 | + | ||
5 | +export type BasicFormProps = ExtractPropTypes<typeof basicProps> | ||
6 | + | ||
7 | + | ||
8 | +export interface FormSchema { | ||
9 | + field: string | ||
10 | + | ||
11 | + changeEvent?: string | ||
12 | + | ||
13 | + valueField?: string | ||
14 | + | ||
15 | + label: string | ||
16 | + | ||
17 | + component: FormComponentTypeEnum | ||
18 | + | ||
19 | + defaultValue?: any | ||
20 | +} |
1 | <script lang="ts" setup> | 1 | <script lang="ts" setup> |
2 | -import { NInput, NPopover, NScrollbar } from 'naive-ui'; | 2 | +import { NInput, NInputGroup, NInputGroupLabel, NPopover, NScrollbar } from 'naive-ui'; |
3 | import '@/assets/external/iconfont/iconfont.js' | 3 | import '@/assets/external/iconfont/iconfont.js' |
4 | import iconfont from '@/assets/external/iconfont/iconfont.json' | 4 | import iconfont from '@/assets/external/iconfont/iconfont.json' |
5 | import SvgIcon from './SvgIcon.vue'; | 5 | import SvgIcon from './SvgIcon.vue'; |
6 | import { computed, ref, unref } from 'vue'; | 6 | import { computed, ref, unref } from 'vue'; |
7 | +import { useDesignStore } from '@/store/modules/designStore/designStore'; | ||
7 | 8 | ||
8 | const props = defineProps({ | 9 | const props = defineProps({ |
9 | value: { | 10 | value: { |
@@ -21,7 +22,11 @@ const getIconList = computed(() => { | @@ -21,7 +22,11 @@ const getIconList = computed(() => { | ||
21 | return icons.filter(icon => icon.includes(text)) | 22 | return icons.filter(icon => icon.includes(text)) |
22 | }) | 23 | }) |
23 | 24 | ||
25 | +const designStore = useDesignStore() | ||
24 | 26 | ||
27 | +const themeColor = computed(() => { | ||
28 | + return designStore.getAppTheme | ||
29 | +}) | ||
25 | 30 | ||
26 | const handleChange = (icon: string) => { | 31 | const handleChange = (icon: string) => { |
27 | emit('update:value', icon) | 32 | emit('update:value', icon) |
@@ -30,28 +35,38 @@ const handleChange = (icon: string) => { | @@ -30,28 +35,38 @@ const handleChange = (icon: string) => { | ||
30 | </script> | 35 | </script> |
31 | 36 | ||
32 | <template> | 37 | <template> |
33 | - <NInput :value="value" placeholder="请选择图标" disabled> | ||
34 | - <template #suffix> | ||
35 | - <NPopover trigger="click"> | ||
36 | - <NInput v-model:value="searchValue" size="small" /> | ||
37 | - <NScrollbar style="max-height: 120px; max-width: 210px;"> | ||
38 | - <ul class="icon-list"> | ||
39 | - <li class="icon-item" v-for="icon in getIconList" :key="icon" @click="handleChange(icon)" | ||
40 | - :style="{ border: icon === props.value ? '1px solid #51d6a9' : '' }"> | ||
41 | - <SvgIcon :name="icon" prefix="iconfont" /> | ||
42 | - </li> | ||
43 | - </ul> | ||
44 | - </NScrollbar> | ||
45 | - <template #trigger> | 38 | + <NInputGroup class="icon-picker"> |
39 | + <NInput :value="value" placeholder="请选择图标" disabled /> | ||
40 | + <NPopover trigger="click"> | ||
41 | + <NInput v-model:value="searchValue" size="small" style="text-overflow: ellipsis;" /> | ||
42 | + <NScrollbar style="max-height: 120px; max-width: 210px; margin-top: 5px;"> | ||
43 | + <ul class="icon-list"> | ||
44 | + <li class="icon-item" v-for="icon in getIconList" :key="icon" @click="handleChange(icon)" | ||
45 | + :style="{ border: icon === props.value ? `1px solid ${themeColor}` : '' }"> | ||
46 | + <SvgIcon :name="icon" prefix="iconfont" /> | ||
47 | + </li> | ||
48 | + </ul> | ||
49 | + </NScrollbar> | ||
50 | + <template #trigger> | ||
51 | + <NInputGroupLabel style="cursor: pointer;"> | ||
46 | <SvgIcon :name="value || 'grid-one'" prefix="iconfont" style="cursor: pointer;" /> | 52 | <SvgIcon :name="value || 'grid-one'" prefix="iconfont" style="cursor: pointer;" /> |
47 | - </template> | ||
48 | - </NPopover> | ||
49 | - </template> | ||
50 | - </NInput> | 53 | + </NInputGroupLabel> |
54 | + </template> | ||
55 | + </NPopover> | ||
56 | + </NInputGroup> | ||
51 | </template> | 57 | </template> |
52 | 58 | ||
53 | -<style lang="scss"> | 59 | +<style lang="scss" scoped> |
54 | .icon { | 60 | .icon { |
61 | + &-picker { | ||
62 | + @include deep() { | ||
63 | + .n-input__input-el { | ||
64 | + text-overflow: ellipsis; | ||
65 | + } | ||
66 | + } | ||
67 | + } | ||
68 | + | ||
69 | + | ||
55 | &-list { | 70 | &-list { |
56 | display: flex; | 71 | display: flex; |
57 | list-style: none; | 72 | list-style: none; |
@@ -70,11 +85,13 @@ const handleChange = (icon: string) => { | @@ -70,11 +85,13 @@ const handleChange = (icon: string) => { | ||
70 | display: flex; | 85 | display: flex; |
71 | justify-content: center; | 86 | justify-content: center; |
72 | align-items: center; | 87 | align-items: center; |
88 | + transition: transform .5s linear; | ||
73 | 89 | ||
74 | &:hover { | 90 | &:hover { |
75 | - border: 1px solid #51d6a9; | 91 | + border: 1px solid v-bind("themeColor"); |
76 | } | 92 | } |
77 | } | 93 | } |
78 | 94 | ||
95 | + | ||
79 | } | 96 | } |
80 | </style> | 97 | </style> |
src/enums/external/dictEnum.ts
0 → 100644
1 | +export { RequestDataTypeEnum } from '../httpEnum' | ||
2 | + | ||
1 | /** | 3 | /** |
2 | * @description: Request result set | 4 | * @description: Request result set |
3 | */ | 5 | */ |
@@ -29,3 +31,33 @@ export enum ContentTypeEnum { | @@ -29,3 +31,33 @@ export enum ContentTypeEnum { | ||
29 | // form-data upload | 31 | // form-data upload |
30 | FORM_DATA = 'multipart/form-data;charset=UTF-8', | 32 | FORM_DATA = 'multipart/form-data;charset=UTF-8', |
31 | } | 33 | } |
34 | + | ||
35 | + | ||
36 | +// 请求主体类型 | ||
37 | +export enum RequestContentTypeEnum { | ||
38 | + // 普通请求 | ||
39 | + DEFAULT = 0, | ||
40 | + // SQL请求 | ||
41 | + SQL = 1, | ||
42 | + // websocket请求 | ||
43 | + WEB_SOCKET = 2 | ||
44 | +} | ||
45 | + | ||
46 | +export enum RequestContentTypeNameEnum { | ||
47 | + // 普通请求 | ||
48 | + DEFAULT = '普通请求', | ||
49 | + // SQL请求 | ||
50 | + SQL = 'SQL请求', | ||
51 | + // websocket请求 | ||
52 | + WEB_SOCKET = 'WebSocket请求' | ||
53 | +} | ||
54 | + | ||
55 | + | ||
56 | +export enum RequestDataTypeNameEnum { | ||
57 | + // 静态数据 | ||
58 | + STATIC = '静态数据', | ||
59 | + // 请求数据 | ||
60 | + AJAX = '自定义请求', | ||
61 | + // 数据池 | ||
62 | + Pond = '公共接口' | ||
63 | +} |
src/hooks/external/useChartDataFetch.hook.ts
0 → 100644
1 | +import { ref, toRefs, toRaw } from 'vue' | ||
2 | +import type VChart from 'vue-echarts' | ||
3 | +import { customizeHttp } from '@/api/http' | ||
4 | +import { useChartDataPondFetch } from '@/hooks/' | ||
5 | +import { CreateComponentType, ChartFrameEnum } from '@/packages/index.d' | ||
6 | +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' | ||
7 | +import { RequestDataTypeEnum } from '@/enums/httpEnum' | ||
8 | +import { isPreview, newFunctionHandle, intervalUnitHandle } from '@/utils' | ||
9 | +import { setOption } from '@/packages/public/chart' | ||
10 | + | ||
11 | +// 获取类型 | ||
12 | +type ChartEditStoreType = typeof useChartEditStore | ||
13 | + | ||
14 | +/** | ||
15 | + * setdata 数据监听与更改 | ||
16 | + * @param targetComponent | ||
17 | + * @param useChartEditStore 若直接引会报错,只能动态传递 | ||
18 | + * @param updateCallback 自定义更新函数 | ||
19 | + */ | ||
20 | +export const useChartDataFetch = ( | ||
21 | + targetComponent: CreateComponentType, | ||
22 | + useChartEditStore: ChartEditStoreType, | ||
23 | + updateCallback?: (...args: any) => any | ||
24 | +) => { | ||
25 | + const vChartRef = ref<typeof VChart | null>(null) | ||
26 | + let fetchInterval: any = 0 | ||
27 | + | ||
28 | + // 数据池 | ||
29 | + const { addGlobalDataInterface } = useChartDataPondFetch() | ||
30 | + | ||
31 | + // 组件类型 | ||
32 | + const { chartFrame } = targetComponent.chartConfig | ||
33 | + | ||
34 | + // eCharts 组件配合 vChart 库更新方式 | ||
35 | + const echartsUpdateHandle = (dataset: any) => { | ||
36 | + if (chartFrame === ChartFrameEnum.ECHARTS) { | ||
37 | + if (vChartRef.value) { | ||
38 | + setOption(vChartRef.value, { dataset: dataset }) | ||
39 | + } | ||
40 | + } | ||
41 | + } | ||
42 | + | ||
43 | + const requestIntervalFn = () => { | ||
44 | + const chartEditStore = useChartEditStore() | ||
45 | + | ||
46 | + // 全局数据 | ||
47 | + const { | ||
48 | + requestOriginUrl, | ||
49 | + requestIntervalUnit: globalUnit, | ||
50 | + requestInterval: globalRequestInterval | ||
51 | + } = toRefs(chartEditStore.getRequestGlobalConfig) | ||
52 | + | ||
53 | + // 目标组件 | ||
54 | + const { | ||
55 | + requestDataType, | ||
56 | + requestUrl, | ||
57 | + requestIntervalUnit: targetUnit, | ||
58 | + requestInterval: targetInterval | ||
59 | + } = toRefs(targetComponent.request) | ||
60 | + | ||
61 | + // 非请求类型 | ||
62 | + if (requestDataType.value !== RequestDataTypeEnum.AJAX) return | ||
63 | + | ||
64 | + try { | ||
65 | + // 处理地址 | ||
66 | + if (requestUrl?.value) { | ||
67 | + // requestOriginUrl 允许为空 | ||
68 | + const completePath = requestOriginUrl && requestOriginUrl.value + requestUrl.value | ||
69 | + if (!completePath) return | ||
70 | + | ||
71 | + clearInterval(fetchInterval) | ||
72 | + | ||
73 | + const fetchFn = async () => { | ||
74 | + const res = await customizeHttp(toRaw(targetComponent.request), toRaw(chartEditStore.getRequestGlobalConfig)) | ||
75 | + if (res) { | ||
76 | + try { | ||
77 | + const filter = targetComponent.filter | ||
78 | + echartsUpdateHandle(newFunctionHandle(res?.data, res, filter)) | ||
79 | + // 更新回调函数 | ||
80 | + if (updateCallback) { | ||
81 | + updateCallback(newFunctionHandle(res?.data, res, filter)) | ||
82 | + } | ||
83 | + } catch (error) { | ||
84 | + console.error(error) | ||
85 | + } | ||
86 | + } | ||
87 | + } | ||
88 | + | ||
89 | + // 立即调用 | ||
90 | + fetchFn() | ||
91 | + // 定时时间 | ||
92 | + const time = targetInterval && targetInterval.value ? targetInterval.value : globalRequestInterval.value | ||
93 | + // 单位 | ||
94 | + const unit = targetInterval && targetInterval.value ? targetUnit.value : globalUnit.value | ||
95 | + // 开启轮询 | ||
96 | + if (time) fetchInterval = setInterval(fetchFn, intervalUnitHandle(time, unit)) | ||
97 | + } | ||
98 | + // eslint-disable-next-line no-empty | ||
99 | + } catch (error) { | ||
100 | + console.log(error) | ||
101 | + } | ||
102 | + } | ||
103 | + | ||
104 | + if (isPreview()) { | ||
105 | + // 判断是否是数据池类型 | ||
106 | + targetComponent.request.requestDataType === RequestDataTypeEnum.Pond | ||
107 | + ? addGlobalDataInterface(targetComponent, useChartEditStore, updateCallback || echartsUpdateHandle) | ||
108 | + : requestIntervalFn() | ||
109 | + } | ||
110 | + return { vChartRef } | ||
111 | +} |
@@ -4,9 +4,10 @@ import { ConfigType, PackagesCategoryEnum } from '@/packages/index.d' | @@ -4,9 +4,10 @@ import { ConfigType, PackagesCategoryEnum } from '@/packages/index.d' | ||
4 | import { ClockConfig } from '@/packages/components/external/Decorates/Mores/Icon' | 4 | import { ClockConfig } from '@/packages/components/external/Decorates/Mores/Icon' |
5 | 5 | ||
6 | export function useInjectLib(packagesList: EPackagesType) { | 6 | export function useInjectLib(packagesList: EPackagesType) { |
7 | + | ||
7 | packagesList[EPackagesCategoryEnum.COMPOSES] = ComposesList | 8 | packagesList[EPackagesCategoryEnum.COMPOSES] = ComposesList |
8 | 9 | ||
9 | - // addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.DECORATES, ClockConfig) | 10 | + addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.DECORATES, ClockConfig) |
10 | } | 11 | } |
11 | 12 | ||
12 | /** | 13 | /** |
src/packages/external/types/index.ts
0 → 100644
1 | +import { RequestBodyEnum, RequestContentTypeEnum, RequestDataTypeEnum, RequestHttpEnum } from "@/enums/httpEnum"; | ||
2 | +import { CreateComponentType } from "@/packages/index.d"; | ||
3 | + | ||
4 | + | ||
5 | +export interface DynamicRequest { | ||
6 | + // 所选全局数据池的对应 id | ||
7 | + requestDataPondId?: string | ||
8 | + // 组件定制轮询时间 | ||
9 | + requestInterval?: number | ||
10 | + // 获取数据的方式 | ||
11 | + requestDataType: RequestDataTypeEnum | ||
12 | + // 请求方式 get/post/del/put/patch | ||
13 | + requestHttpType: RequestHttpEnum | ||
14 | + // 源后续的 url | ||
15 | + requestUrl?: string | ||
16 | + // 请求内容主体方式 普通/sql | ||
17 | + requestContentType: RequestContentTypeEnum | ||
18 | + // 请求体类型 | ||
19 | + requestParamsBodyType: RequestBodyEnum | ||
20 | + // SQL 请求对象 | ||
21 | + requestSQLContent: { | ||
22 | + sql: string | ||
23 | + } | ||
24 | +} | ||
25 | + | ||
26 | +export interface ECreateComponentType extends CreateComponentType { | ||
27 | + test: 123 | ||
28 | +} |
1 | +export enum DynamicRequestStoreEnum { | ||
2 | + // 组件id | ||
3 | + ID = 'id', | ||
4 | + // 请求源地址 | ||
5 | + REQUEST_ORIGIN_URL = 'requestOriginUrl', | ||
6 | + // 请求间隔时间 | ||
7 | + REQUEST_INTERVAL = 'requestInterval', | ||
8 | + // 请求单位 | ||
9 | + REQUEST_INTERVAL_UNIT = 'requestIntervalUnit', | ||
10 | + // 请求头 | ||
11 | + REQUEST_HEADER = 'requestHeader' | ||
12 | +} | ||
13 | + | ||
14 | +export interface DynamicRequestStoreType { | ||
15 | + | ||
16 | +} |
src/store/external/module/dynamicRequest.ts
0 → 100644
src/utils/external/dateUtil.ts
0 → 100644
1 | +import dayjs, { ConfigType } from 'dayjs'; | ||
2 | + | ||
3 | +export const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss'; | ||
4 | +export const DATE_FORMAT = 'YYYY-MM-DD '; | ||
5 | + | ||
6 | +export function formatToDateTime( | ||
7 | + date: ConfigType = undefined, | ||
8 | + format = DATE_TIME_FORMAT | ||
9 | +): string { | ||
10 | + return dayjs(date).format(format); | ||
11 | +} | ||
12 | + | ||
13 | +export function formatToDate(date: ConfigType = undefined, format = DATE_FORMAT): string { | ||
14 | + return dayjs(date).format(format); | ||
15 | +} | ||
16 | + | ||
17 | +export const dateUtil = dayjs; |
@@ -45,7 +45,7 @@ const transform: AxiosTransform = { | @@ -45,7 +45,7 @@ const transform: AxiosTransform = { | ||
45 | if (apiUrl && isString(apiUrl)) { | 45 | if (apiUrl && isString(apiUrl)) { |
46 | config.url = `${apiUrl}${config.url}`; | 46 | config.url = `${apiUrl}${config.url}`; |
47 | } | 47 | } |
48 | - | 48 | + |
49 | const params = config.params || {}; | 49 | const params = config.params || {}; |
50 | const data = config.data || false; | 50 | const data = config.data || false; |
51 | formatDate && data && !isString(data) && formatRequestDate(data); | 51 | formatDate && data && !isString(data) && formatRequestDate(data); |
@@ -143,7 +143,7 @@ const transform: AxiosTransform = { | @@ -143,7 +143,7 @@ const transform: AxiosTransform = { | ||
143 | } | 143 | } |
144 | } catch (error: any) { | 144 | } catch (error: any) { |
145 | throw new Error(error); | 145 | throw new Error(error); |
146 | - } | 146 | + } |
147 | checkStatus(error?.response?.status, msg, errorMessageMode); | 147 | checkStatus(error?.response?.status, msg, errorMessageMode); |
148 | return Promise.reject(response?.data); | 148 | return Promise.reject(response?.data); |
149 | }, | 149 | }, |
@@ -197,9 +197,3 @@ function createAxios(opt?: Partial<CreateAxiosOptions>) { | @@ -197,9 +197,3 @@ function createAxios(opt?: Partial<CreateAxiosOptions>) { | ||
197 | } | 197 | } |
198 | export const defHttp = createAxios(); | 198 | export const defHttp = createAxios(); |
199 | 199 | ||
200 | -// other api url | ||
201 | -export const otherHttp = createAxios({ | ||
202 | - requestOptions: { | ||
203 | - apiUrl: 'xxx', | ||
204 | - }, | ||
205 | -}); |
@@ -89,3 +89,5 @@ export const withInstall = <T extends Component>(component: T, alias?: string) = | @@ -89,3 +89,5 @@ export const withInstall = <T extends Component>(component: T, alias?: string) = | ||
89 | }; | 89 | }; |
90 | return component as T & Plugin; | 90 | return component as T & Plugin; |
91 | }; | 91 | }; |
92 | + | ||
93 | + |
src/utils/external/useAppContext.ts
0 → 100644
1 | +import { inject, InjectionKey, provide, reactive, readonly as defineReadonly } from 'vue' | ||
2 | + | ||
3 | +export interface CreateContextOptions { | ||
4 | + readonly?: boolean | ||
5 | + createProvider?: boolean | ||
6 | + native?: boolean | ||
7 | +} | ||
8 | + | ||
9 | +export function createContext<T>(context: any, key: InjectionKey<T> = Symbol(), options: CreateContextOptions = {}) { | ||
10 | + const { readonly, createProvider, native } = options | ||
11 | + | ||
12 | + const state = reactive(context) | ||
13 | + | ||
14 | + const provideData = readonly ? defineReadonly(state) : state | ||
15 | + | ||
16 | + !createProvider && provide(key, native ? context : provideData) | ||
17 | + | ||
18 | + return { | ||
19 | + state | ||
20 | + } | ||
21 | +} | ||
22 | + | ||
23 | +export function useContext<T>(key: InjectionKey<T> = Symbol(), defaultValue?: any) { | ||
24 | + return inject(key, defaultValue || {}) | ||
25 | +} |
1 | +<template> | ||
2 | + <NTimeline class="go-chart-configurations-timeline"> | ||
3 | + <NTimelineItem v-show="isCharts && dimensionsAndSource" type="info" :title="TimelineTitleEnum.MAPPING"> | ||
4 | + <n-table striped> | ||
5 | + <thead> | ||
6 | + <tr> | ||
7 | + <th v-for="item in tableTitle" :key="item">{{ item }}</th> | ||
8 | + </tr> | ||
9 | + </thead> | ||
10 | + <tbody> | ||
11 | + <tr v-for="(item, index) in dimensionsAndSource" :key="index"> | ||
12 | + <td>{{ item.field }}</td> | ||
13 | + <td>{{ item.mapping }}</td> | ||
14 | + <td> | ||
15 | + <NSpace v-if="item.result === 0"> | ||
16 | + <NBadge dot type="success"></NBadge> | ||
17 | + <NText>无</NText> | ||
18 | + </NSpace> | ||
19 | + <NSpace v-else> | ||
20 | + <NBadge dot :type="item.result === 1 ? 'success' : 'error'"></NBadge> | ||
21 | + <NText>匹配{{ item.result === 1 ? '成功' : '失败' }}</NText> | ||
22 | + </NSpace> | ||
23 | + </td> | ||
24 | + </tr> | ||
25 | + </tbody> | ||
26 | + </n-table> | ||
27 | + </NTimelineItem> | ||
28 | + <NTimelineItem v-show="filterShow" color="#97846c" :title="TimelineTitleEnum.FILTER"> | ||
29 | + <NSpace :size="18" vertical> | ||
30 | + <NText depth="3">过滤器默认处理接口返回值的「data」字段</NText> | ||
31 | + <ChartDataMonacoEditor></ChartDataMonacoEditor> | ||
32 | + </NSpace> | ||
33 | + </NTimelineItem> | ||
34 | + <NTimelineItem type="success" :title="TimelineTitleEnum.CONTENT"> | ||
35 | + <NSpace vertical> | ||
36 | + <NSpace class="source-btn-box"> | ||
37 | + <NUpload v-model:file-list="uploadFileListRef" :show-file-list="false" :customRequest="customRequest" | ||
38 | + @before-upload="beforeUpload"> | ||
39 | + <NSpace> | ||
40 | + <NButton v-if="!ajax" class="sourceBtn-item" :disabled="noData"> | ||
41 | + <template #icon> | ||
42 | + <NIcon> | ||
43 | + <document-add-icon /> | ||
44 | + </NIcon> | ||
45 | + </template> | ||
46 | + 导入(json / txt) | ||
47 | + </NButton> | ||
48 | + </NSpace> | ||
49 | + </NUpload> | ||
50 | + <div> | ||
51 | + <NButton class="sourceBtn-item" :disabled="noData" @click="download"> | ||
52 | + <template #icon> | ||
53 | + <NIcon> | ||
54 | + <document-download-icon /> | ||
55 | + </NIcon> | ||
56 | + </template> | ||
57 | + 下载 | ||
58 | + </NButton> | ||
59 | + <n-tooltip trigger="hover"> | ||
60 | + <template #trigger> | ||
61 | + <NIcon class="go-ml-1" size="21" :depth="3"> | ||
62 | + <help-outline-icon></help-outline-icon> | ||
63 | + </NIcon> | ||
64 | + </template> | ||
65 | + <NText depth="3">点击【下载】查看完整数据</NText> | ||
66 | + </n-tooltip> | ||
67 | + </div> | ||
68 | + </NSpace> | ||
69 | + <NCard size="small"> | ||
70 | + <NScrollbar style="max-height: 400px;"> | ||
71 | + <NCode :code="toString(source)" language="json"></NCode> | ||
72 | + </NScrollbar> | ||
73 | + </NCard> | ||
74 | + </NSpace> | ||
75 | + </NTimelineItem> | ||
76 | + </NTimeline> | ||
77 | +</template> | ||
78 | + | ||
79 | +<script setup lang="ts"> | ||
80 | +import { ref, computed, watch } from 'vue' | ||
81 | +import { ChartFrameEnum } from '@/packages/index.d' | ||
82 | +import { RequestDataTypeEnum } from '@/enums/httpEnum' | ||
83 | +import { icon } from '@/plugins' | ||
84 | +import isObject from 'lodash/isObject' | ||
85 | +import { toString, isArray } from '@/utils' | ||
86 | +import { useTargetData } from '../../../../hooks/useTargetData.hook' | ||
87 | +import { DataResultEnum, TimelineTitleEnum } from '../../../index.d' | ||
88 | +import { useFile } from '../../../hooks/useFile.hooks' | ||
89 | +import { ChartDataMonacoEditor } from '../ChartDataMonacoEditor' | ||
90 | +import { NBadge, NButton, NCard, NCode, NIcon, NScrollbar, NSpace, NText, NTimeline, NTimelineItem, NUpload } from 'naive-ui' | ||
91 | + | ||
92 | +const { targetData } = useTargetData() | ||
93 | +const props = defineProps({ | ||
94 | + show: { | ||
95 | + type: Boolean, | ||
96 | + required: false | ||
97 | + }, | ||
98 | + ajax: { | ||
99 | + type: Boolean, | ||
100 | + required: true | ||
101 | + } | ||
102 | +}) | ||
103 | + | ||
104 | +// 表格标题 | ||
105 | +const tableTitle = ['字段', '映射', '状态'] | ||
106 | + | ||
107 | +const { HelpOutlineIcon } = icon.ionicons5 | ||
108 | +const { DocumentAddIcon, DocumentDownloadIcon } = icon.carbon | ||
109 | + | ||
110 | +const source = ref() | ||
111 | +const dimensions = ref() | ||
112 | +const dimensionsAndSource = ref() | ||
113 | +const noData = ref(false) | ||
114 | + | ||
115 | +const { uploadFileListRef, customRequest, beforeUpload, download } = useFile(targetData) | ||
116 | + | ||
117 | +// 是否展示过滤器 | ||
118 | +const filterShow = computed(() => { | ||
119 | + return targetData.value.request.requestDataType !== RequestDataTypeEnum.STATIC | ||
120 | +}) | ||
121 | + | ||
122 | +// 是支持 dataset 的图表类型 | ||
123 | +const isCharts = computed(() => { | ||
124 | + return targetData.value.chartConfig.chartFrame === ChartFrameEnum.ECHARTS | ||
125 | +}) | ||
126 | + | ||
127 | +// 处理映射列表状态结果 | ||
128 | +const matchingHandle = (mapping: string) => { | ||
129 | + let res = DataResultEnum.SUCCESS | ||
130 | + for (let i = 0; i < source.value.length; i++) { | ||
131 | + if (source.value[i][mapping] === undefined) { | ||
132 | + res = DataResultEnum.FAILURE | ||
133 | + return res | ||
134 | + } | ||
135 | + } | ||
136 | + return DataResultEnum.SUCCESS | ||
137 | +} | ||
138 | + | ||
139 | +// 处理映射列表 | ||
140 | +const dimensionsAndSourceHandle = () => { | ||
141 | + try { | ||
142 | + // 去除首项数据轴标识 | ||
143 | + return dimensions.value.map((dimensionsItem: string, index: number) => { | ||
144 | + return index === 0 | ||
145 | + ? { | ||
146 | + // 字段 | ||
147 | + field: '通用标识', | ||
148 | + // 映射 | ||
149 | + mapping: dimensionsItem, | ||
150 | + // 结果 | ||
151 | + result: DataResultEnum.NULL | ||
152 | + } | ||
153 | + : { | ||
154 | + field: `数据项-${index}`, | ||
155 | + mapping: dimensionsItem, | ||
156 | + result: matchingHandle(dimensionsItem) | ||
157 | + } | ||
158 | + }) | ||
159 | + } catch (error) { | ||
160 | + return [] | ||
161 | + } | ||
162 | +} | ||
163 | + | ||
164 | +watch( | ||
165 | + () => targetData.value?.option?.dataset, | ||
166 | + ( | ||
167 | + newData?: { | ||
168 | + source: any | ||
169 | + dimensions: any | ||
170 | + } | null | ||
171 | + ) => { | ||
172 | + if (newData && targetData?.value?.chartConfig?.chartFrame === ChartFrameEnum.ECHARTS) { | ||
173 | + // 只有 DataSet 数据才有对应的格式 | ||
174 | + source.value = newData | ||
175 | + if (isCharts.value) { | ||
176 | + dimensions.value = newData.dimensions | ||
177 | + dimensionsAndSource.value = dimensionsAndSourceHandle() | ||
178 | + } | ||
179 | + } else if (newData !== undefined && newData !== null) { | ||
180 | + dimensionsAndSource.value = null | ||
181 | + source.value = newData | ||
182 | + } else { | ||
183 | + noData.value = true | ||
184 | + source.value = '此组件无数据源' | ||
185 | + } | ||
186 | + if (isArray(newData)) { | ||
187 | + dimensionsAndSource.value = null | ||
188 | + } | ||
189 | + }, | ||
190 | + { | ||
191 | + immediate: true | ||
192 | + } | ||
193 | +) | ||
194 | +</script> | ||
195 | + | ||
196 | +<style lang="scss" scoped> | ||
197 | +@include go('chart-configurations-timeline') { | ||
198 | + @include deep() { | ||
199 | + pre { | ||
200 | + white-space: pre-wrap; | ||
201 | + word-wrap: break-word; | ||
202 | + } | ||
203 | + } | ||
204 | + | ||
205 | + .source-btn-box { | ||
206 | + margin-top: 10px !important; | ||
207 | + } | ||
208 | +} | ||
209 | +</style> |
1 | +<template> | ||
2 | + <template v-if="targetData.filter"> | ||
3 | + <NCard> | ||
4 | + <p><span class="func-keyword">function</span> filter(res) {</p> | ||
5 | + <!-- 函数体 --> | ||
6 | + <div class="go-ml-4"> | ||
7 | + <NCode :code="targetData.filter" language="typescript"></NCode> | ||
8 | + </div> | ||
9 | + <p>}</p> | ||
10 | + <template #footer> | ||
11 | + <NSpace justify="end"> | ||
12 | + <NButton type="primary" tertiary size="small" @click="addFilter"> | ||
13 | + <template #icon> | ||
14 | + <NIcon> | ||
15 | + <filter-edit-icon /> | ||
16 | + </NIcon> | ||
17 | + </template> | ||
18 | + 编辑 | ||
19 | + </NButton> | ||
20 | + <NButton tertiary size="small" @click="delFilter"> 删除 </NButton> | ||
21 | + </NSpace> | ||
22 | + </template> | ||
23 | + </NCard> | ||
24 | + </template> | ||
25 | + <template v-else> | ||
26 | + <NButton class="go-ml-3" @click="addFilter"> | ||
27 | + <template #icon> | ||
28 | + <NIcon> | ||
29 | + <filter-icon /> | ||
30 | + </NIcon> | ||
31 | + </template> | ||
32 | + 新增过滤器 | ||
33 | + </NButton> | ||
34 | + </template> | ||
35 | + | ||
36 | + <!-- 弹窗 --> | ||
37 | + <NModal class="go-chart-data-monaco-editor" v-model:show="showModal" :mask-closable="false" :closeOnEsc="false"> | ||
38 | + <NCard :bordered="false" role="dialog" size="small" aria-modal="true" style="width: 1000px; height: 600px"> | ||
39 | + <template #header> | ||
40 | + <NSpace> | ||
41 | + <NText>过滤器函数编辑器</NText> | ||
42 | + </NSpace> | ||
43 | + </template> | ||
44 | + <template #header-extra> </template> | ||
45 | + <NSpace size="small" vertical> | ||
46 | + <NSpace justify="space-between"> | ||
47 | + <div> | ||
48 | + <NSpace vertical> | ||
49 | + <NTag type="info"> | ||
50 | + <span class="func-keyword">function</span> filter(res) { | ||
51 | + </NTag> | ||
52 | + <monaco-editor v-model:modelValue="filter" width="460px" height="380px" language="javascript" /> | ||
53 | + <NTag type="info">}</NTag> | ||
54 | + </NSpace> | ||
55 | + </div> | ||
56 | + <NDivider vertical style="height: 480px" /> | ||
57 | + <NScrollbar style="max-height: 480px"> | ||
58 | + <NSpace :size="15" vertical> | ||
59 | + <!-- <div class="editor-data-show"> --> | ||
60 | + <!-- <NSpace> | ||
61 | + <NText depth="3">默认过滤数据(data):</NText> | ||
62 | + <NCode :code="toString(sourceData?.data) || '暂无'" language="json" :word-wrap="true"></NCode> | ||
63 | + </NSpace> --> | ||
64 | + <!-- </div> --> | ||
65 | + <div class="editor-data-show"> | ||
66 | + <NSpace> | ||
67 | + <NText depth="3">接口返回数据(res):</NText> | ||
68 | + <NScrollbar style="max-height: 300px;"> | ||
69 | + <NCode :code="toString(sourceData) || '暂无'" language="json" :word-wrap="true"></NCode> | ||
70 | + </NScrollbar> | ||
71 | + </NSpace> | ||
72 | + </div> | ||
73 | + <div class="editor-data-show"> | ||
74 | + <NSpace> | ||
75 | + <NText depth="3">过滤器结果:</NText> | ||
76 | + <NCode :code="filterRes || '暂无'" language="json" :word-wrap="true"></NCode> | ||
77 | + </NSpace> | ||
78 | + </div> | ||
79 | + </NSpace> | ||
80 | + </NScrollbar> | ||
81 | + </NSpace> | ||
82 | + </NSpace> | ||
83 | + <template #action> | ||
84 | + <NSpace justify="space-between"> | ||
85 | + <div class="go-flex-items-center"> | ||
86 | + <NTag :bordered="false" type="primary"> | ||
87 | + <template #icon> | ||
88 | + <NIcon :component="DocumentTextIcon" /> | ||
89 | + </template> | ||
90 | + 规则 | ||
91 | + </NTag> | ||
92 | + <NText class="go-ml-2" depth="2">过滤器默认处理接口返回值的「data」字段</NText> | ||
93 | + </div> | ||
94 | + | ||
95 | + <NSpace> | ||
96 | + <NButton size="medium" @click="closeFilter">取消</NButton> | ||
97 | + <NButton size="medium" type="primary" @click="saveFilter">保存</NButton> | ||
98 | + </NSpace> | ||
99 | + </NSpace> | ||
100 | + </template> | ||
101 | + </NCard> | ||
102 | + </NModal> | ||
103 | +</template> | ||
104 | + | ||
105 | +<script lang="ts" setup> | ||
106 | +import { ref, computed, watch, toRaw } from 'vue' | ||
107 | +import { MonacoEditor } from '@/components/Pages/MonacoEditor' | ||
108 | +import { icon } from '@/plugins' | ||
109 | +import { goDialog, toString } from '@/utils' | ||
110 | +import cloneDeep from 'lodash/cloneDeep' | ||
111 | +import { useTargetData } from '../../../../hooks/useTargetData.hook' | ||
112 | +import { customRequest } from '@/api/external/customRequest' | ||
113 | +import { NButton, NCard, NCode, NDivider, NIcon, NModal, NScrollbar, NSpace, NTag, NText } from 'naive-ui' | ||
114 | + | ||
115 | +const { DocumentTextIcon } = icon.ionicons5 | ||
116 | +const { FilterIcon, FilterEditIcon } = icon.carbon | ||
117 | +const { targetData } = useTargetData() | ||
118 | + | ||
119 | +// 受控弹窗 | ||
120 | +const showModal = ref(false) | ||
121 | +// filter 函数模板 | ||
122 | +const filter = ref(targetData.value.filter || `return res`) | ||
123 | +// 过滤错误标识 | ||
124 | +const errorFlag = ref(false) | ||
125 | +// 目标静态/接口数据 | ||
126 | +const sourceData = ref<any>('') | ||
127 | + | ||
128 | +// 动态获取数据 | ||
129 | +const fetchTargetData = async () => { | ||
130 | + try { | ||
131 | + const res = await customRequest(toRaw(targetData.value.request)) | ||
132 | + if (res) { | ||
133 | + sourceData.value = res | ||
134 | + return | ||
135 | + } | ||
136 | + window['$message'].warning('没有拿到返回值,请检查接口!') | ||
137 | + } catch (error) { | ||
138 | + console.error(error); | ||
139 | + window['$message'].warning('数据异常,请检查参数!') | ||
140 | + } | ||
141 | +} | ||
142 | + | ||
143 | +// 过滤结果 | ||
144 | +const filterRes = computed(() => { | ||
145 | + try { | ||
146 | + const fn = new Function('data', 'res', filter.value) | ||
147 | + const response = cloneDeep(sourceData.value) | ||
148 | + const res = fn(response?.data, response) | ||
149 | + // eslint-disable-next-line vue/no-side-effects-in-computed-properties | ||
150 | + errorFlag.value = false | ||
151 | + return toString(res) | ||
152 | + } catch (error) { | ||
153 | + // eslint-disable-next-line vue/no-side-effects-in-computed-properties | ||
154 | + errorFlag.value = true | ||
155 | + return `过滤函数错误,日志:${error}` | ||
156 | + } | ||
157 | +}) | ||
158 | + | ||
159 | +// 新增过滤器 | ||
160 | +const addFilter = () => { | ||
161 | + showModal.value = true | ||
162 | +} | ||
163 | + | ||
164 | +// 删除过滤器 | ||
165 | +const delFilter = () => { | ||
166 | + goDialog({ | ||
167 | + message: '是否删除过滤器', | ||
168 | + onPositiveCallback: () => { | ||
169 | + targetData.value.filter = undefined | ||
170 | + } | ||
171 | + }) | ||
172 | +} | ||
173 | + | ||
174 | +// 关闭过滤器 | ||
175 | +const closeFilter = () => { | ||
176 | + showModal.value = false | ||
177 | +} | ||
178 | + | ||
179 | +// 新增过滤器 | ||
180 | +const saveFilter = () => { | ||
181 | + if (errorFlag.value) { | ||
182 | + window['$message'].error('过滤函数错误,无法进行保存') | ||
183 | + return | ||
184 | + } | ||
185 | + targetData.value.filter = filter.value | ||
186 | + closeFilter() | ||
187 | +} | ||
188 | + | ||
189 | +watch( | ||
190 | + () => showModal.value, | ||
191 | + (newData: boolean) => { | ||
192 | + if (newData) { | ||
193 | + fetchTargetData() | ||
194 | + filter.value = targetData.value.filter || `return res` | ||
195 | + } | ||
196 | + } | ||
197 | +) | ||
198 | +</script> | ||
199 | + | ||
200 | +<style lang="scss" scoped> | ||
201 | +.func-keyword { | ||
202 | + color: #b478cf; | ||
203 | +} | ||
204 | + | ||
205 | +@include go('chart-data-monaco-editor') { | ||
206 | + | ||
207 | + &.NCard.NModal, | ||
208 | + .NCard { | ||
209 | + @extend .go-background-filter; | ||
210 | + } | ||
211 | + | ||
212 | + .editor-data-show { | ||
213 | + @include fetch-bg-color('filter-color'); | ||
214 | + width: 420px; | ||
215 | + padding: 20px; | ||
216 | + border-radius: 5px; | ||
217 | + } | ||
218 | +} | ||
219 | +</style> |
1 | +export { default as ChartDynamicRequest } from './index.vue' |
1 | +<script setup lang="ts"> | ||
2 | +import { ref, computed, onBeforeUnmount, watchEffect, toRaw, unref } from 'vue' | ||
3 | +import { icon } from '@/plugins' | ||
4 | +import { useDesignStore } from '@/store/modules/designStore/designStore' | ||
5 | +import { SettingItemBox } from '@/components/Pages/ChartItemSetting' | ||
6 | +import { RequestDataTypeEnum } from '@/enums/external/httpEnum' | ||
7 | +import { ChartDataMatchingAndShow } from '../../../external/components/ChartDataMatchingAndShow' | ||
8 | +import { newFunctionHandle } from '@/utils' | ||
9 | +import { useTargetData } from '../../../../hooks/useTargetData.hook' | ||
10 | +import { NButton, NSelect, NTooltip, NIcon, SelectOption } from 'naive-ui' | ||
11 | +import { RequestInfoPanel } from '../RequestInfoPanel' | ||
12 | +import { RequestModal } from '../RequestModal' | ||
13 | +import { customRequest } from '@/api/external/customRequest' | ||
14 | + | ||
15 | +const { HelpOutlineIcon, FlashIcon } = icon.ionicons5 | ||
16 | +const { targetData } = useTargetData() | ||
17 | + | ||
18 | +const requestModal = ref<InstanceType<typeof RequestModal>>() | ||
19 | + | ||
20 | +const designStore = useDesignStore() | ||
21 | + | ||
22 | + | ||
23 | +const selectedRequestType = ref(targetData.value.request.requestDataType || RequestDataTypeEnum.AJAX) | ||
24 | + | ||
25 | +const getApiRequestType: SelectOption[] = [ | ||
26 | + { label: '自定义请求', value: RequestDataTypeEnum.AJAX }, | ||
27 | + { label: '公共接口', value: RequestDataTypeEnum.Pond } | ||
28 | +] | ||
29 | + | ||
30 | +// 是否展示数据分析 | ||
31 | +const loading = ref(false) | ||
32 | +const showMatching = ref(false) | ||
33 | + | ||
34 | +let firstFocus = 0 | ||
35 | +let lastFilter: any = undefined | ||
36 | + | ||
37 | +// 发送请求 | ||
38 | +const sendHandle = async () => { | ||
39 | + if (!targetData.value?.request) return | ||
40 | + | ||
41 | + loading.value = true | ||
42 | + try { | ||
43 | + console.log('enter') | ||
44 | + const res = await customRequest(toRaw(targetData.value.request)) | ||
45 | + loading.value = false | ||
46 | + if (res) { | ||
47 | + targetData.value.option.dataset = newFunctionHandle(res, res, targetData.value.filter) | ||
48 | + showMatching.value = true | ||
49 | + return | ||
50 | + } | ||
51 | + window['$message'].warning('数据异常,请检查参数!') | ||
52 | + } catch (error) { | ||
53 | + loading.value = false | ||
54 | + window['$message'].warning('数据异常,请检查参数!') | ||
55 | + } | ||
56 | +} | ||
57 | + | ||
58 | +// 颜色 | ||
59 | +const themeColor = computed(() => { | ||
60 | + return designStore.getAppTheme | ||
61 | +}) | ||
62 | + | ||
63 | +const handleClickPanel = () => { | ||
64 | + unref(requestModal)?.openModal(true, unref(selectedRequestType)) | ||
65 | +} | ||
66 | + | ||
67 | +watchEffect(() => { | ||
68 | + const filter = targetData.value?.filter | ||
69 | + if (lastFilter !== filter && firstFocus) { | ||
70 | + lastFilter = filter | ||
71 | + sendHandle() | ||
72 | + } | ||
73 | + firstFocus++ | ||
74 | +}) | ||
75 | + | ||
76 | +onBeforeUnmount(() => { | ||
77 | + lastFilter = null | ||
78 | +}) | ||
79 | + | ||
80 | + | ||
81 | +</script> | ||
82 | + | ||
83 | +<template> | ||
84 | + <div class="things-kit-chart-configurations-data-ajax"> | ||
85 | + <SettingItemBox name="接口方式" :alone="true"> | ||
86 | + <NSelect v-model:value="selectedRequestType" :options="getApiRequestType" /> | ||
87 | + </SettingItemBox> | ||
88 | + | ||
89 | + <RequestInfoPanel @clickPanel="handleClickPanel" /> | ||
90 | + | ||
91 | + <SettingItemBox :alone="true"> | ||
92 | + <template #name> | ||
93 | + 测试 | ||
94 | + <NTooltip trigger="hover"> | ||
95 | + <template #trigger> | ||
96 | + <NIcon size="21" :depth="3"> | ||
97 | + <HelpOutlineIcon /> | ||
98 | + </NIcon> | ||
99 | + </template> | ||
100 | + 默认赋值给 dataset 字段 | ||
101 | + </NTooltip> | ||
102 | + </template> | ||
103 | + <NButton type="primary" ghost @click="sendHandle"> | ||
104 | + <template #icon> | ||
105 | + <NIcon> | ||
106 | + <FlashIcon /> | ||
107 | + </NIcon> | ||
108 | + </template> | ||
109 | + 发送请求 | ||
110 | + </NButton> | ||
111 | + </SettingItemBox> | ||
112 | + | ||
113 | + <!-- 底部数据展示 --> | ||
114 | + <ChartDataMatchingAndShow :show="showMatching && !loading" :ajax="true"></ChartDataMatchingAndShow> | ||
115 | + | ||
116 | + <!-- 骨架图 --> | ||
117 | + <go-skeleton :load="loading" :repeat="3"></go-skeleton> | ||
118 | + | ||
119 | + <RequestModal ref="requestModal" /> | ||
120 | + </div> | ||
121 | +</template> | ||
122 | + | ||
123 | + | ||
124 | + | ||
125 | +<style lang="scss" scoped> | ||
126 | +@include thingsKit('chart-configurations-data-ajax') { | ||
127 | + .n-card-shallow { | ||
128 | + &.n-card { | ||
129 | + @extend .go-background-filter; | ||
130 | + | ||
131 | + @include deep() { | ||
132 | + .n-card__content { | ||
133 | + padding: 10px; | ||
134 | + } | ||
135 | + } | ||
136 | + } | ||
137 | + | ||
138 | + .edit-text { | ||
139 | + position: absolute; | ||
140 | + top: 0px; | ||
141 | + left: 0px; | ||
142 | + width: 325px; | ||
143 | + height: 270px; | ||
144 | + cursor: pointer; | ||
145 | + opacity: 0; | ||
146 | + transition: all 0.3s; | ||
147 | + @extend .go-background-filter; | ||
148 | + backdrop-filter: blur(2px) !important; | ||
149 | + } | ||
150 | + | ||
151 | + &:hover { | ||
152 | + border-color: v-bind('themeColor'); | ||
153 | + | ||
154 | + .edit-text { | ||
155 | + opacity: 1; | ||
156 | + } | ||
157 | + } | ||
158 | + } | ||
159 | +} | ||
160 | +</style> |
1 | +export { default as PublicInterfaceForm } from './index.vue' |
1 | +<script lang="ts" setup> | ||
2 | +import { getAllPublicInterface, getPublicInterface } from '@/api/external/dynamicRequest' | ||
3 | +import { PublicInterfaceRecord } from '@/api/external/dynamicRequest/model'; | ||
4 | +import { SettingItem, SettingItemBox } from '@/components/Pages/ChartItemSetting'; | ||
5 | +import { RequestContentTypeEnum, RequestContentTypeNameEnum } from '@/enums/external/httpEnum'; | ||
6 | +import { RequestBodyEnum, RequestHttpEnum, RequestHttpIntervalEnum, RequestParams, RequestParamsTypeEnum } from '@/enums/httpEnum'; | ||
7 | +import { RequestConfigType } from '@/store/modules/chartEditStore/chartEditStore.d'; | ||
8 | +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'; | ||
9 | +import { NForm, NCard, NDatePicker, NEmpty, NFormItem, NInput, NInputGroup, NInputNumber, NScrollbar, NSelect, NSpin, NTabPane, NTabs, NTreeSelect, SelectOption, FormInst, NButton, FormItemInst } from 'naive-ui'; | ||
10 | +import { ref, reactive, onMounted, computed, unref } from 'vue' | ||
11 | +import { selectTimeOptions, selectTypeOptions } from '../../../index.d'; | ||
12 | +import ParamsTable from '../RequestModal/ParamsTable.vue'; | ||
13 | +import RequestBody from '../RequestModal/RequestBody.vue'; | ||
14 | +import { ComponentType, useDynamicPublicForm } from './useDynamicPublicForm'; | ||
15 | +import { transferData } from './utils'; | ||
16 | + | ||
17 | +const componentMap: { [key in ComponentType]?: any } = { | ||
18 | + [ComponentType.SELECT_TREE]: NTreeSelect, | ||
19 | + [ComponentType.SELECT]: NSelect, | ||
20 | + [ComponentType.INPUT]: NInput, | ||
21 | + [ComponentType.DATE_PICKER]: NDatePicker | ||
22 | +} | ||
23 | +const publicInterfaceList = ref<PublicInterfaceRecord[]>([]) | ||
24 | + | ||
25 | +const selectedPublicInterface = ref<string>() | ||
26 | + | ||
27 | +const toJSON = (string: string) => { | ||
28 | + try { | ||
29 | + return JSON.parse(string) | ||
30 | + } catch (error) { | ||
31 | + return {} | ||
32 | + } | ||
33 | +} | ||
34 | + | ||
35 | +const getSelectedInterface = computed(() => { | ||
36 | + const record = unref(publicInterfaceList).find(item => item.id === unref(selectedPublicInterface))! || {} | ||
37 | + const _record = JSON.parse(JSON.stringify(record)) | ||
38 | + _record.requestParams = toJSON(_record.requestParams) | ||
39 | + return _record | ||
40 | +}) | ||
41 | + | ||
42 | +const getPublicInterfaceList = async () => { | ||
43 | + if (unref(publicInterfaceList).length) return | ||
44 | + const result = await getAllPublicInterface() | ||
45 | + publicInterfaceList.value = result | ||
46 | +} | ||
47 | + | ||
48 | +const handleFilter = (query: string, option: SelectOption) => { | ||
49 | + return ((option as Recordable).interfaceName).includes(query) | ||
50 | +} | ||
51 | + | ||
52 | +const { getDynamicFormSchemas, params, createForm, validFlag, setDynamicFormValue } = useDynamicPublicForm(getSelectedInterface) | ||
53 | + | ||
54 | +const getConfigurationData = () => { | ||
55 | + const value = transferData(unref(getSelectedInterface), unref(getSelectedInterface).requestParams as unknown as RequestParams, params) | ||
56 | + return value | ||
57 | +} | ||
58 | + | ||
59 | +const requestHttpTypeRef = ref<RequestHttpEnum>() | ||
60 | + | ||
61 | +const requestIntervalValueRef = ref<number>(30) | ||
62 | + | ||
63 | +const requestIntervalUnitRef = ref<RequestHttpIntervalEnum>(RequestHttpIntervalEnum.SECOND) | ||
64 | + | ||
65 | +const requestContentTypeRef = ref<RequestContentTypeEnum>() | ||
66 | + | ||
67 | +const requestParamsTypeRef = ref<RequestParamsTypeEnum>(RequestParamsTypeEnum.PARAMS) | ||
68 | + | ||
69 | +const requestParams = ref<RequestParams>({ Body: { [RequestBodyEnum.FORM_DATA]: {}, [RequestBodyEnum.JSON]: '', [RequestBodyEnum.XML]: '', [RequestBodyEnum.X_WWW_FORM_URLENCODED]: {} }, Header: {}, Params: {} }) | ||
70 | + | ||
71 | +const requestParamsBodyTypeRef = ref<RequestBodyEnum>(RequestBodyEnum.X_WWW_FORM_URLENCODED) | ||
72 | + | ||
73 | +const headerRef = ref() | ||
74 | + | ||
75 | +const dynamicFormItemEl = ref<FormItemInst[]>() | ||
76 | + | ||
77 | +const handleSelectedInterfaceChange = (value: string, option: PublicInterfaceRecord) => { | ||
78 | + createForm() | ||
79 | + requestContentTypeRef.value = option.requestContentType as RequestContentTypeEnum | ||
80 | + requestHttpTypeRef.value = option.requestHttpType as RequestHttpEnum | ||
81 | +} | ||
82 | + | ||
83 | +const getGetRequestTypeName = (key: RequestContentTypeEnum) => { | ||
84 | + return RequestContentTypeNameEnum[RequestContentTypeEnum[key] as keyof typeof RequestContentTypeEnum] | ||
85 | +} | ||
86 | + | ||
87 | +const setConfigurationData = async (request: RequestConfigType) => { | ||
88 | + await getPublicInterfaceList() | ||
89 | + const { requestDataPondId, requestParams: params, requestParamsBodyType, requestContentType, requestHttpType, } = request | ||
90 | + const { Header } = params | ||
91 | + selectedPublicInterface.value = requestDataPondId | ||
92 | + requestContentTypeRef.value = requestContentType | ||
93 | + requestHttpTypeRef.value = requestHttpType | ||
94 | + headerRef.value = Header | ||
95 | + requestParamsBodyTypeRef.value = requestParamsBodyType | ||
96 | + requestParams.value = params | ||
97 | + setDynamicFormValue(params) | ||
98 | +} | ||
99 | + | ||
100 | + | ||
101 | +const validate = async () => { | ||
102 | + for (const item of unref(dynamicFormItemEl) || []) { | ||
103 | + await item.validate() | ||
104 | + } | ||
105 | + return unref(validFlag) | ||
106 | +} | ||
107 | + | ||
108 | + | ||
109 | +defineExpose({ | ||
110 | + getConfigurationData, | ||
111 | + setConfigurationData, | ||
112 | + validate | ||
113 | +}) | ||
114 | + | ||
115 | +onMounted(() => { | ||
116 | + getPublicInterfaceList() | ||
117 | +}) | ||
118 | + | ||
119 | +</script> | ||
120 | + | ||
121 | +<template> | ||
122 | + <SettingItemBox name="公共接口" :alone="true" :item-right-style="{ gridTemplateColumns: '5fr 2fr 1fr' }"> | ||
123 | + <SettingItem name="请求方式 & URL地址"> | ||
124 | + <NInputGroup> | ||
125 | + <NSelect v-model:value="selectedPublicInterface" label-field="interfaceName" value-field="id" | ||
126 | + :options="publicInterfaceList" :filter="handleFilter" filterable :reset-menu-on-options-change="false" | ||
127 | + @update-value="handleSelectedInterfaceChange" size="small"> | ||
128 | + </NSelect> | ||
129 | + <NSelect v-if="requestContentTypeRef !== RequestContentTypeEnum.WEB_SOCKET" v-model:value="requestHttpTypeRef" | ||
130 | + style="width: 150px;" size="small" :options="(selectTypeOptions as SelectOption[])" :disabled="true" /> | ||
131 | + <NSelect v-if="requestContentTypeRef === RequestContentTypeEnum.WEB_SOCKET" :disabled="true" style="width: 150px;" | ||
132 | + :default-value="RequestContentTypeEnum.WEB_SOCKET" size="small" | ||
133 | + :options="[{ label: 'WebSocket', value: RequestContentTypeEnum.WEB_SOCKET, type: 'ignored' }]"> | ||
134 | + </NSelect> | ||
135 | + </NInputGroup> | ||
136 | + </SettingItem> | ||
137 | + <SettingItem name="更新间隔,为 0 只会初始化"> | ||
138 | + <NInputGroup> | ||
139 | + <NInputNumber v-model:value="requestIntervalValueRef" class="select-time-number" size="small" min="0" | ||
140 | + :show-button="false" placeholder="请输入数字" /> | ||
141 | + <!-- 单位 --> | ||
142 | + <NSelect v-model:value="requestIntervalUnitRef" class="select-time-options" size="small" | ||
143 | + :options="(selectTimeOptions as SelectOption[])" /> | ||
144 | + </NInputGroup> | ||
145 | + </SettingItem> | ||
146 | + </SettingItemBox> | ||
147 | + <SettingItemBox name="请求方式" :alone="true" :item-right-style="{ gridTemplateColumns: '1fr 1fr' }"> | ||
148 | + <NTabs v-model:value="requestContentTypeRef" type="segment" size="small"> | ||
149 | + <NTabPane :disabled="requestContentTypeRef !== RequestContentTypeEnum.DEFAULT" | ||
150 | + :name="RequestContentTypeEnum.DEFAULT" :tab="getGetRequestTypeName(RequestContentTypeEnum.DEFAULT)" /> | ||
151 | + <NTabPane :disabled="requestContentTypeRef !== RequestContentTypeEnum.SQL" :name="RequestContentTypeEnum.SQL" | ||
152 | + :tab="getGetRequestTypeName(RequestContentTypeEnum.SQL)" /> | ||
153 | + <NTabPane :disabled="requestContentTypeRef !== RequestContentTypeEnum.WEB_SOCKET" | ||
154 | + :name="RequestContentTypeEnum.WEB_SOCKET" :tab="getGetRequestTypeName(RequestContentTypeEnum.WEB_SOCKET)" /> | ||
155 | + </NTabs> | ||
156 | + </SettingItemBox> | ||
157 | + <SettingItemBox> | ||
158 | + <NTabs v-model:value="requestParamsTypeRef" :default-value="RequestParamsTypeEnum.PARAMS"> | ||
159 | + <NTabPane v-for="item in RequestParamsTypeEnum" :name="item" :key="item"></NTabPane> | ||
160 | + </NTabs> | ||
161 | + </SettingItemBox> | ||
162 | + | ||
163 | + <SettingItemBox :item-right-style="{ gridTemplateColumns: '3fr 2fr' }"> | ||
164 | + <NCard v-if="requestParamsTypeRef === RequestParamsTypeEnum.PARAMS" class="dynamic-form"> | ||
165 | + <NScrollbar style="max-height: 400px; padding: 0 10px; box-sizing: border-box;;"> | ||
166 | + <NForm> | ||
167 | + <template v-for="item in getDynamicFormSchemas" :key="item.key"> | ||
168 | + <NFormItem ref="dynamicFormItemEl" :required="item.required" :label="item.name" :rule="item.rules"> | ||
169 | + <component :is="componentMap[item.component]" v-bind="item.props" clearable /> | ||
170 | + </NFormItem> | ||
171 | + </template> | ||
172 | + </NForm> | ||
173 | + <NEmpty v-if="!selectedPublicInterface || !getDynamicFormSchemas.length" description="请选择公共接口" /> | ||
174 | + </NScrollbar> | ||
175 | + </NCard> | ||
176 | + | ||
177 | + | ||
178 | + <RequestBody v-if="requestParamsTypeRef === RequestParamsTypeEnum.BODY" | ||
179 | + v-model:request-params-body-type="requestParamsBodyTypeRef" v-model:value="requestParams" /> | ||
180 | + | ||
181 | + <ParamsTable v-if="requestParamsTypeRef === RequestParamsTypeEnum.HEADER" v-model:value="headerRef" /> | ||
182 | + | ||
183 | + </SettingItemBox> | ||
184 | +</template> | ||
185 | + | ||
186 | +<style scoped lang="scss"> | ||
187 | +.loading-container { | ||
188 | + display: flex; | ||
189 | + align-items: center; | ||
190 | + justify-content: center; | ||
191 | +} | ||
192 | + | ||
193 | +.dynamic-form { | ||
194 | + @include deep() { | ||
195 | + .n-date-picker { | ||
196 | + width: 100%; | ||
197 | + } | ||
198 | + } | ||
199 | +} | ||
200 | +</style> |
1 | +import { getDictItemByCode } from "@/api/external/common" | ||
2 | +import { DictItem } from "@/api/external/common/model" | ||
3 | +import { getDeviceAttrList, getDeviceList, getDeviceProfileList, getOrgList } from "@/api/external/dynamicRequest" | ||
4 | +import { PublicInterfaceRecord, RequestParams } from "@/api/external/dynamicRequest/model" | ||
5 | +import { RequestConfigType } from "@/store/modules/chartEditStore/chartEditStore.d" | ||
6 | +import { DatePickerProps, FormItemRule, InputProps, SelectProps, TreeSelectProps } from "naive-ui" | ||
7 | +import { computed, onMounted, reactive, Ref, ref, unref } from "vue" | ||
8 | +import { DictEnum } from '@/enums/external/dictEnum' | ||
9 | + | ||
10 | +const GROUP_SEPARATOR = ',' | ||
11 | + | ||
12 | +export enum BuiltInVariable { | ||
13 | + DATE = 'date', | ||
14 | + KEYS = 'keys', | ||
15 | + ENTITY_ID = 'entityId', | ||
16 | + ORGANIZATION_ID = 'organizationId', | ||
17 | + DEVICE_PROFILE_ID = 'deviceProfileId', | ||
18 | +} | ||
19 | + | ||
20 | +export enum ComponentType { | ||
21 | + SELECT = 'select', | ||
22 | + SELECT_TREE = 'selectTree', | ||
23 | + DATE_PICKER = 'datePicker', | ||
24 | + INPUT = 'input' | ||
25 | +} | ||
26 | + | ||
27 | +export interface DynamicFormSchema { | ||
28 | + key: string | ||
29 | + name?: string | ||
30 | + component: ComponentType, | ||
31 | + required?: boolean | ||
32 | + rules?: FormItemRule | ||
33 | + props: Recordable | ||
34 | +} | ||
35 | + | ||
36 | +export type BuiltInVariableRecord = { [key in BuiltInVariable]: DictItem } | ||
37 | + | ||
38 | +export const useDynamicPublicForm = (publicInterfaceRef: Ref<PublicInterfaceRecord>) => { | ||
39 | + | ||
40 | + const getParams = computed(() => { | ||
41 | + let params = (publicInterfaceRef.value.requestParams as unknown as RequestParams).Params || [] | ||
42 | + if (!Array.isArray(params)) params = [] | ||
43 | + return params | ||
44 | + }) | ||
45 | + | ||
46 | + const getUsedBuiltInVariable = computed(() => { | ||
47 | + const hasUsed = unref(getParams).reduce((prev, next) => { | ||
48 | + const groupList = next.key.split(GROUP_SEPARATOR) | ||
49 | + return [...prev, ...(groupList.length > 1 ? groupList : [next.key])] | ||
50 | + }, [] as string[]) | ||
51 | + return hasUsed | ||
52 | + }) | ||
53 | + | ||
54 | + const builtInVariable = ref<BuiltInVariableRecord>() | ||
55 | + | ||
56 | + const params = reactive<Recordable & { [key in BuiltInVariable]?: any }>({}) | ||
57 | + | ||
58 | + const optionsSet = reactive<Recordable>({}) | ||
59 | + | ||
60 | + const basicPreset = (filterKey: string) => { | ||
61 | + return { | ||
62 | + size: 'small', | ||
63 | + filterable: true, | ||
64 | + filter(query, option: Recordable) { | ||
65 | + return option[filterKey].includes(query) | ||
66 | + } | ||
67 | + } as SelectProps | ||
68 | + } | ||
69 | + | ||
70 | + const validIsExist = (keys: BuiltInVariable) => { | ||
71 | + return unref(getUsedBuiltInVariable).includes(keys) | ||
72 | + } | ||
73 | + | ||
74 | + const handleSelectOrgEffect = () => { | ||
75 | + params[BuiltInVariable.ENTITY_ID] = null | ||
76 | + getDeviceOption() | ||
77 | + } | ||
78 | + | ||
79 | + const handleSelectDeviceProfileEffect = () => { | ||
80 | + params[BuiltInVariable.ENTITY_ID] = null | ||
81 | + params[BuiltInVariable.KEYS] = null | ||
82 | + getDeviceOption() | ||
83 | + getDeviceAttrOption() | ||
84 | + } | ||
85 | + | ||
86 | + const getBuiltInVariable = async () => { | ||
87 | + if (Object.keys(unref(builtInVariable) || {}).length) return | ||
88 | + const result = await getDictItemByCode(DictEnum.BUILTIN_PARAMS) | ||
89 | + builtInVariable.value = result.reduce((prev, next) => { | ||
90 | + return { ...prev, [next.itemValue]: next } | ||
91 | + }, {} as BuiltInVariableRecord) | ||
92 | + } | ||
93 | + | ||
94 | + const getOrgOption = async () => { | ||
95 | + if (!validIsExist(BuiltInVariable.ORGANIZATION_ID)) return | ||
96 | + optionsSet[BuiltInVariable.ORGANIZATION_ID] = await getOrgList() | ||
97 | + } | ||
98 | + | ||
99 | + const getDeviceProfileOption = async () => { | ||
100 | + if (!validIsExist(BuiltInVariable.DEVICE_PROFILE_ID)) return | ||
101 | + optionsSet[BuiltInVariable.DEVICE_PROFILE_ID] = await getDeviceProfileList() | ||
102 | + } | ||
103 | + | ||
104 | + const getDeviceOption = async () => { | ||
105 | + if (!validIsExist(BuiltInVariable.DEVICE_PROFILE_ID) || !validIsExist(BuiltInVariable.ORGANIZATION_ID) || !params[BuiltInVariable.ORGANIZATION_ID]) return | ||
106 | + optionsSet[BuiltInVariable.ENTITY_ID] = await getDeviceList({ [BuiltInVariable.ORGANIZATION_ID]: params[BuiltInVariable.ORGANIZATION_ID], [BuiltInVariable.DEVICE_PROFILE_ID]: params[BuiltInVariable.DEVICE_PROFILE_ID] }) | ||
107 | + } | ||
108 | + | ||
109 | + const getDeviceAttrOption = async () => { | ||
110 | + if (!validIsExist(BuiltInVariable.KEYS)) return | ||
111 | + if (!params[BuiltInVariable.DEVICE_PROFILE_ID]) return | ||
112 | + const result = await getDeviceAttrList(params[BuiltInVariable.DEVICE_PROFILE_ID]) | ||
113 | + if (Array.isArray(result)) optionsSet[BuiltInVariable.KEYS] = result | ||
114 | + } | ||
115 | + | ||
116 | + const getSelectOrgTree = computed<TreeSelectProps>(() => { | ||
117 | + return { | ||
118 | + ...basicPreset('name'), | ||
119 | + value: params[BuiltInVariable.ORGANIZATION_ID], | ||
120 | + options: unref(optionsSet[BuiltInVariable.ORGANIZATION_ID]), | ||
121 | + labelField: 'name', | ||
122 | + keyField: 'id', | ||
123 | + childrenField: 'children', | ||
124 | + onUpdateValue(value) { | ||
125 | + params[BuiltInVariable.ORGANIZATION_ID] = value | ||
126 | + handleSelectOrgEffect() | ||
127 | + } | ||
128 | + } as TreeSelectProps | ||
129 | + }) | ||
130 | + | ||
131 | + | ||
132 | + const getSelectDeviceProfile = computed<SelectProps>(() => { | ||
133 | + return { | ||
134 | + ...basicPreset('name'), | ||
135 | + value: params[BuiltInVariable.DEVICE_PROFILE_ID], | ||
136 | + options: unref(optionsSet[BuiltInVariable.DEVICE_PROFILE_ID]), | ||
137 | + labelField: 'name', | ||
138 | + valueField: 'id', | ||
139 | + onUpdateValue(value) { | ||
140 | + params[BuiltInVariable.DEVICE_PROFILE_ID] = value | ||
141 | + handleSelectDeviceProfileEffect() | ||
142 | + } | ||
143 | + } | ||
144 | + }) | ||
145 | + | ||
146 | + const getSelectDevice = computed<SelectProps>(() => { | ||
147 | + return { | ||
148 | + ...basicPreset('name'), | ||
149 | + value: params[BuiltInVariable.ENTITY_ID], | ||
150 | + options: unref(optionsSet[BuiltInVariable.ENTITY_ID]), | ||
151 | + labelField: 'name', | ||
152 | + valueField: 'id', | ||
153 | + onUpdateValue(value) { | ||
154 | + params[BuiltInVariable.ENTITY_ID] = value | ||
155 | + } | ||
156 | + } | ||
157 | + }) | ||
158 | + | ||
159 | + const getSelectDeviceAttr = computed<SelectProps>(() => { | ||
160 | + return { | ||
161 | + ...basicPreset('name'), | ||
162 | + value: params[BuiltInVariable.KEYS], | ||
163 | + options: unref(optionsSet[BuiltInVariable.KEYS]), | ||
164 | + labelField: 'name', | ||
165 | + valueField: 'identifier', | ||
166 | + onUpdateValue(value) { | ||
167 | + params[BuiltInVariable.KEYS] = value | ||
168 | + } | ||
169 | + } | ||
170 | + }) | ||
171 | + | ||
172 | + const getSelectDate = computed(() => { | ||
173 | + return { | ||
174 | + size: 'small', | ||
175 | + value: params[BuiltInVariable.DATE], | ||
176 | + type: 'datetimerange', | ||
177 | + clearable: true, | ||
178 | + defaultTime: ['00:00:00', '00:00:00'], | ||
179 | + onUpdateValue(value) { | ||
180 | + params[BuiltInVariable.DATE] = value | ||
181 | + } | ||
182 | + } as DatePickerProps | ||
183 | + }) | ||
184 | + | ||
185 | + const getBasicInput = (key: string) => { | ||
186 | + return { | ||
187 | + size: 'small', | ||
188 | + value: params[key], | ||
189 | + onUpdateValue(value) { | ||
190 | + params[key] = value | ||
191 | + } | ||
192 | + } as InputProps | ||
193 | + } | ||
194 | + | ||
195 | + const builtInVariableConfiguration: { [key in BuiltInVariable]?: DynamicFormSchema } = { | ||
196 | + [BuiltInVariable.ORGANIZATION_ID]: { | ||
197 | + component: ComponentType.SELECT_TREE, | ||
198 | + key: BuiltInVariable.ORGANIZATION_ID, | ||
199 | + props: getSelectOrgTree | ||
200 | + }, | ||
201 | + [BuiltInVariable.DEVICE_PROFILE_ID]: { | ||
202 | + component: ComponentType.SELECT, | ||
203 | + key: BuiltInVariable.DEVICE_PROFILE_ID, | ||
204 | + props: getSelectDeviceProfile | ||
205 | + }, | ||
206 | + [BuiltInVariable.ENTITY_ID]: { | ||
207 | + component: ComponentType.SELECT, | ||
208 | + key: BuiltInVariable.ENTITY_ID, | ||
209 | + props: getSelectDevice | ||
210 | + }, | ||
211 | + [BuiltInVariable.KEYS]: { | ||
212 | + component: ComponentType.SELECT, | ||
213 | + key: BuiltInVariable.KEYS, | ||
214 | + props: getSelectDeviceAttr | ||
215 | + }, | ||
216 | + [BuiltInVariable.DATE]: { | ||
217 | + component: ComponentType.DATE_PICKER, | ||
218 | + key: BuiltInVariable.DATE, | ||
219 | + props: getSelectDate | ||
220 | + } | ||
221 | + } | ||
222 | + | ||
223 | + const validFlag = ref(true) | ||
224 | + | ||
225 | + const createRules = (required: boolean, key: string, message: string) => { | ||
226 | + return [{ | ||
227 | + trigger: ['blur', 'change'], | ||
228 | + validator() { | ||
229 | + if (required && !params[key]) { | ||
230 | + validFlag.value = false | ||
231 | + return new Error(`${message}是必填项`) | ||
232 | + } | ||
233 | + validFlag.value = true | ||
234 | + } | ||
235 | + }] as FormItemRule | ||
236 | + } | ||
237 | + | ||
238 | + const toFormSchemas = (builtInVariableKey: string, required: boolean, value: any) => { | ||
239 | + const groupList = builtInVariableKey.split(GROUP_SEPARATOR) | ||
240 | + return groupList.reduce((prev, next) => { | ||
241 | + const result = builtInVariableConfiguration[next as BuiltInVariable] | ||
242 | + const props = unref(result?.props) | ||
243 | + const name = (unref(builtInVariable) || {})[next as BuiltInVariable]?.itemText | ||
244 | + let schema: DynamicFormSchema | ||
245 | + if (builtInVariableConfiguration[next as BuiltInVariable]) { | ||
246 | + schema = { | ||
247 | + ...result, | ||
248 | + props, | ||
249 | + name, | ||
250 | + required, | ||
251 | + rules: createRules(required, next, name || next) | ||
252 | + } as DynamicFormSchema | ||
253 | + } else { | ||
254 | + schema = { | ||
255 | + key: value, | ||
256 | + name: value, | ||
257 | + component: ComponentType.INPUT, | ||
258 | + props: getBasicInput(value), | ||
259 | + required, | ||
260 | + rules: createRules(required, value, value) | ||
261 | + } as DynamicFormSchema | ||
262 | + } | ||
263 | + | ||
264 | + return [...prev, schema] | ||
265 | + | ||
266 | + }, [] as DynamicFormSchema[]) | ||
267 | + | ||
268 | + } | ||
269 | + | ||
270 | + const getDynamicFormSchemas = computed(() => { | ||
271 | + return unref(getParams).reduce((prev, { key, value, required }) => { | ||
272 | + const schemas = toFormSchemas(key, required, value) | ||
273 | + return [...prev, ...schemas] | ||
274 | + }, [] as DynamicFormSchema[]) | ||
275 | + }) | ||
276 | + | ||
277 | + const createForm = async () => { | ||
278 | + await getBuiltInVariable() | ||
279 | + await getOrgOption() | ||
280 | + getDeviceProfileOption() | ||
281 | + getDeviceOption() | ||
282 | + } | ||
283 | + | ||
284 | + const setParams = (Params: Recordable) => { | ||
285 | + unref(getParams).forEach(({ key, value }) => { | ||
286 | + if (unref(getUsedBuiltInVariable).includes(key)) { | ||
287 | + params[key] = Params[key] | ||
288 | + } | ||
289 | + params[value] = Params[value] | ||
290 | + }) | ||
291 | + } | ||
292 | + | ||
293 | + const setDynamicFormValue = (requestParams: RequestConfigType['requestParams']) => { | ||
294 | + const { Params } = requestParams | ||
295 | + setParams(Params) | ||
296 | + getOrgOption() | ||
297 | + getDeviceProfileOption() | ||
298 | + getDeviceOption() | ||
299 | + getDeviceAttrOption() | ||
300 | + } | ||
301 | + | ||
302 | + onMounted(() => { | ||
303 | + getBuiltInVariable() | ||
304 | + }) | ||
305 | + | ||
306 | + return { | ||
307 | + validFlag, | ||
308 | + params, | ||
309 | + getDynamicFormSchemas, | ||
310 | + setDynamicFormValue, | ||
311 | + createForm | ||
312 | + } | ||
313 | +} | ||
314 | + |
1 | +import { PublicInterfaceRecord } from "@/api/external/dynamicRequest/model" | ||
2 | +import { RequestDataTypeEnum, RequestParams } from "@/enums/httpEnum" | ||
3 | +import { RequestConfigType } from "@/store/modules/chartEditStore/chartEditStore.d" | ||
4 | + | ||
5 | +export const transferData = (publicInterfaceRecord: PublicInterfaceRecord, requestParams: RequestParams, fillParams: Recordable) => { | ||
6 | + const { requestContentType, requestHttpType, id, requestUrl, requestParamsBodyType, requestOriginUrl } = publicInterfaceRecord | ||
7 | + const { Header, Body } = requestParams | ||
8 | + return { | ||
9 | + requestDataPondId: id, | ||
10 | + // requestInterval | ||
11 | + // 获取数据的方式 | ||
12 | + requestDataType: RequestDataTypeEnum.Pond, | ||
13 | + // 请求方式 get/post/del/put/patch | ||
14 | + requestHttpType, | ||
15 | + // 源后续的 url | ||
16 | + requestUrl: `${requestOriginUrl}${requestUrl}`, | ||
17 | + // 请求内容主体方式 普通/sql | ||
18 | + requestContentType, | ||
19 | + // 请求体类型 | ||
20 | + requestParamsBodyType, | ||
21 | + // SQL 请求对象 | ||
22 | + // requestSQLContent: { | ||
23 | + // sql: '' | ||
24 | + // } | ||
25 | + // requestIntervalUnit | ||
26 | + requestParams: { | ||
27 | + Header, | ||
28 | + Body, | ||
29 | + Params: fillParams | ||
30 | + } | ||
31 | + | ||
32 | + } as RequestConfigType | ||
33 | +} |
1 | +export { default as RequestInfoPanel } from './index.vue' |
1 | +<script setup lang="ts"> | ||
2 | +import { toRefs, computed } from 'vue' | ||
3 | +import { icon } from '@/plugins' | ||
4 | +import { useDesignStore } from '@/store/modules/designStore/designStore' | ||
5 | +import { SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting' | ||
6 | +import { SelectHttpTimeNameObj, RequestContentTypeEnum } from '@/enums/httpEnum' | ||
7 | +import { useTargetData } from '@/views/chart/ContentConfigurations/components/hooks/useTargetData.hook' | ||
8 | +import { NButton, NCard, NTag, NInput, NIcon } from 'naive-ui' | ||
9 | + | ||
10 | +const emit = defineEmits(['clickPanel']) | ||
11 | + | ||
12 | +const { FlashIcon, PulseIcon } = icon.ionicons5 | ||
13 | +const { targetData, chartEditStore } = useTargetData() | ||
14 | + | ||
15 | +const { | ||
16 | + requestOriginUrl, | ||
17 | + requestInterval: GlobalRequestInterval, | ||
18 | + requestIntervalUnit: GlobalRequestIntervalUnit | ||
19 | +} = toRefs(chartEditStore.getRequestGlobalConfig) | ||
20 | + | ||
21 | +const designStore = useDesignStore() | ||
22 | + | ||
23 | +// 请求配置 model | ||
24 | +const requestModelHandle = () => { | ||
25 | + emit('clickPanel') | ||
26 | +} | ||
27 | + | ||
28 | +// 颜色 | ||
29 | +const themeColor = computed(() => { | ||
30 | + return designStore.getAppTheme | ||
31 | +}) | ||
32 | + | ||
33 | +</script> | ||
34 | + | ||
35 | +<template> | ||
36 | + <NCard class="n-card-shallow"> | ||
37 | + <SettingItemBox name="请求配置"> | ||
38 | + <SettingItem name="类型"> | ||
39 | + <NTag :bordered="false" type="primary" style="border-radius: 5px"> | ||
40 | + {{ targetData.request.requestContentType === RequestContentTypeEnum.DEFAULT ? '普通请求' : 'SQL请求' }} | ||
41 | + </NTag> | ||
42 | + </SettingItem> | ||
43 | + | ||
44 | + <SettingItem name="方式"> | ||
45 | + <NInput size="small" :placeholder="targetData.request.requestHttpType || '暂无'" :disabled="true"></NInput> | ||
46 | + </SettingItem> | ||
47 | + | ||
48 | + <SettingItem name="组件间隔"> | ||
49 | + <NInput size="small" :placeholder="`${targetData.request.requestInterval || '暂无'}`" :disabled="true"> | ||
50 | + <template #suffix> {{ SelectHttpTimeNameObj[targetData.request.requestIntervalUnit] }} </template> | ||
51 | + </NInput> | ||
52 | + </SettingItem> | ||
53 | + | ||
54 | + <SettingItem name="全局间隔(默认)"> | ||
55 | + <NInput size="small" :placeholder="`${GlobalRequestInterval || '暂无'} `" :disabled="true"> | ||
56 | + <template #suffix> {{ SelectHttpTimeNameObj[GlobalRequestIntervalUnit] }} </template> | ||
57 | + </NInput> | ||
58 | + </SettingItem> | ||
59 | + </SettingItemBox> | ||
60 | + | ||
61 | + <SettingItemBox name="源地址" :alone="true"> | ||
62 | + <NInput size="small" :placeholder="requestOriginUrl || '暂无'" :disabled="true"> | ||
63 | + <template #prefix> | ||
64 | + <NIcon :component="PulseIcon" /> | ||
65 | + </template> | ||
66 | + </NInput> | ||
67 | + </SettingItemBox> | ||
68 | + | ||
69 | + <SettingItemBox name="组件地址" :alone="true"> | ||
70 | + <NInput size="small" :placeholder="targetData.request.requestUrl || '暂无'" :disabled="true"> | ||
71 | + <template #prefix> | ||
72 | + <NIcon :component="FlashIcon" /> | ||
73 | + </template> | ||
74 | + </NInput> | ||
75 | + </SettingItemBox> | ||
76 | + | ||
77 | + <div class="edit-text" @click="requestModelHandle"> | ||
78 | + <div class="go-absolute-center"> | ||
79 | + <NButton type="primary" secondary>编辑配置</NButton> | ||
80 | + </div> | ||
81 | + </div> | ||
82 | + </NCard> | ||
83 | +</template> | ||
84 | + | ||
85 | +<style lang="scss" scoped> | ||
86 | +.n-card-shallow { | ||
87 | + &.n-card { | ||
88 | + @extend .go-background-filter; | ||
89 | + | ||
90 | + @include deep() { | ||
91 | + .n-card__content { | ||
92 | + padding: 10px; | ||
93 | + } | ||
94 | + } | ||
95 | + } | ||
96 | + | ||
97 | + .edit-text { | ||
98 | + position: absolute; | ||
99 | + top: 0px; | ||
100 | + left: 0px; | ||
101 | + width: 325px; | ||
102 | + height: 270px; | ||
103 | + cursor: pointer; | ||
104 | + opacity: 0; | ||
105 | + transition: all 0.3s; | ||
106 | + @extend .go-background-filter; | ||
107 | + backdrop-filter: blur(2px) !important; | ||
108 | + } | ||
109 | + | ||
110 | + &:hover { | ||
111 | + border-color: v-bind('themeColor'); | ||
112 | + | ||
113 | + .edit-text { | ||
114 | + opacity: 1; | ||
115 | + } | ||
116 | + } | ||
117 | +} | ||
118 | +</style> |
1 | +<script setup lang="ts"> | ||
2 | +import { NInput, NInputNumber, NInputGroup, NButton, NSelect, SelectOption, NTabs, NTabPane, NSpace } from 'naive-ui' | ||
3 | +import { SettingItem, SettingItemBox } from '@/components/Pages/ChartItemSetting'; | ||
4 | +import { selectTimeOptions, selectTypeOptions } from '../../../index.d'; | ||
5 | +import { RequestBodyEnum, RequestContentTypeEnum, RequestDataTypeEnum, RequestHttpEnum, RequestHttpIntervalEnum, RequestParams } from '@/enums/httpEnum'; | ||
6 | +import { ref, unref } from 'vue'; | ||
7 | +import DefaultRequestContent from './DefaultRequestContent.vue'; | ||
8 | +import SqlConfiguration from './SqlConfiguration.vue'; | ||
9 | +import { RequestConfigType } from '@/store/modules/chartEditStore/chartEditStore.d'; | ||
10 | +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'; | ||
11 | +import { getUrl } from '@/api/external/customRequest' | ||
12 | + | ||
13 | +const chartEditStore = useChartEditStore() | ||
14 | + | ||
15 | +const requestContentTypeRef = ref(RequestContentTypeEnum.DEFAULT) | ||
16 | + | ||
17 | +const requestHttpTypeRef = ref(RequestHttpEnum.GET) | ||
18 | + | ||
19 | +const requestIntervalRef = ref<number | undefined>(20) | ||
20 | + | ||
21 | +const requestIntervalUnitRef = ref(RequestHttpIntervalEnum.SECOND) | ||
22 | + | ||
23 | +const requestSQLContentRef = ref('select * from where') | ||
24 | + | ||
25 | +const requestParamsRef = ref({ Header: {}, Params: {}, Body: { 'form-data': {}, 'json': '', 'x-www-form-urlencoded': {}, 'xml': '' } } as RequestParams) | ||
26 | + | ||
27 | +const requestParamsBodyTypeRef = ref(RequestBodyEnum.NONE) | ||
28 | + | ||
29 | +const requestUrlRef = ref<string>() | ||
30 | + | ||
31 | +const getConfigurationData = (): RequestConfigType => { | ||
32 | + return { | ||
33 | + requestContentType: unref(requestContentTypeRef), | ||
34 | + requestHttpType: unref(requestHttpTypeRef), | ||
35 | + requestInterval: unref(requestIntervalRef), | ||
36 | + requestIntervalUnit: unref(requestIntervalUnitRef), | ||
37 | + requestDataType: RequestDataTypeEnum.AJAX, | ||
38 | + requestParamsBodyType: unref(requestParamsBodyTypeRef), | ||
39 | + requestSQLContent: { | ||
40 | + sql: unref(requestSQLContentRef) | ||
41 | + }, | ||
42 | + requestParams: unref(requestParamsRef), | ||
43 | + requestUrl: `${chartEditStore.requestGlobalConfig.requestOriginUrl}${unref(requestUrlRef)}` | ||
44 | + } | ||
45 | +} | ||
46 | + | ||
47 | + | ||
48 | +const setConfigurationData = (request: RequestConfigType) => { | ||
49 | + const { requestContentType, requestHttpType, requestInterval, requestIntervalUnit, requestParamsBodyType, requestSQLContent, requestParams, requestUrl } = request | ||
50 | + requestContentTypeRef.value = requestContentType | ||
51 | + requestHttpTypeRef.value = requestHttpType | ||
52 | + requestIntervalRef.value = requestInterval | ||
53 | + requestIntervalUnitRef.value = requestIntervalUnit | ||
54 | + requestParamsBodyTypeRef.value = requestParamsBodyType | ||
55 | + requestSQLContentRef.value = requestSQLContent.sql | ||
56 | + requestParamsRef.value = requestParams | ||
57 | + const { pathname } = getUrl(requestUrl!) | ||
58 | + requestUrlRef.value = pathname | ||
59 | +} | ||
60 | + | ||
61 | +defineExpose({ | ||
62 | + getConfigurationData, | ||
63 | + setConfigurationData | ||
64 | +}) | ||
65 | + | ||
66 | +</script> | ||
67 | + | ||
68 | +<template> | ||
69 | + <SettingItemBox name="地址" :itemRightStyle="{ | ||
70 | + gridTemplateColumns: '5fr 2fr 1fr' | ||
71 | + }"> | ||
72 | + <SettingItem name="请求方式 & URL地址"> | ||
73 | + <NInputGroup> | ||
74 | + <NSelect v-model:value="requestHttpTypeRef" style="width: 150px;" size="small" | ||
75 | + :options="(selectTypeOptions as SelectOption[])" /> | ||
76 | + <NInput v-model:value="requestUrlRef" class="select-time-number" size="small" min="0" :show-button="false" | ||
77 | + placeholder="请输入URL地址" /> | ||
78 | + </NInputGroup> | ||
79 | + </SettingItem> | ||
80 | + <SettingItem name="更新间隔,为 0 只会初始化"> | ||
81 | + <NInputGroup> | ||
82 | + <NInputNumber v-model:value="requestIntervalRef" class="select-time-number" size="small" min="0" | ||
83 | + :show-button="false" placeholder="请输入数字" /> | ||
84 | + <!-- 单位 --> | ||
85 | + <NSelect v-model:value="requestIntervalUnitRef" class="select-time-options" size="small" | ||
86 | + :options="(selectTimeOptions as SelectOption[])" /> | ||
87 | + </NInputGroup> | ||
88 | + </SettingItem> | ||
89 | + </SettingItemBox> | ||
90 | + <SettingItemBox name="选择方式"> | ||
91 | + <NTabs v-model:value="requestContentTypeRef" type="segment" size="small"> | ||
92 | + <NTabPane :name="RequestContentTypeEnum.DEFAULT" tab="普通请求" /> | ||
93 | + <NTabPane :name="RequestContentTypeEnum.SQL" tab="SQL请求" /> | ||
94 | + </NTabs> | ||
95 | + </SettingItemBox> | ||
96 | + <SettingItemBox> | ||
97 | + <DefaultRequestContent v-if="requestContentTypeRef === RequestContentTypeEnum.DEFAULT" | ||
98 | + v-model:value="requestParamsRef" v-model:request-params-body-type="requestParamsBodyTypeRef" /> | ||
99 | + <SqlConfiguration v-model:value="requestSQLContentRef" v-if="requestContentTypeRef === RequestContentTypeEnum.SQL" /> | ||
100 | + </SettingItemBox> | ||
101 | +</template> |
1 | +<script lang="ts" setup> | ||
2 | +import { RequestBodyEnum, RequestParams, RequestParamsTypeEnum } from '@/enums/httpEnum'; | ||
3 | +import { NTabPane, NTabs } from 'naive-ui'; | ||
4 | +import { ref } from 'vue'; | ||
5 | +import ParamsTable from './ParamsTable.vue'; | ||
6 | +import RequestBody from './RequestBody.vue'; | ||
7 | + | ||
8 | +defineProps<{ | ||
9 | + value: RequestParams | ||
10 | + requestParamsBodyType: RequestBodyEnum | ||
11 | +}>() | ||
12 | + | ||
13 | +const emit = defineEmits(['update:requestParamsBodyType']) | ||
14 | + | ||
15 | +const tabValue = ref(RequestParamsTypeEnum.PARAMS) | ||
16 | + | ||
17 | +const handleSyncRequestParamsBodyType = (value: RequestBodyEnum) => { | ||
18 | + emit('update:requestParamsBodyType', value) | ||
19 | +} | ||
20 | + | ||
21 | + | ||
22 | +</script> | ||
23 | + | ||
24 | +<template> | ||
25 | + <section class="container"> | ||
26 | + <NTabs v-model:value="tabValue"> | ||
27 | + <NTabPane v-for="item in RequestParamsTypeEnum" :name="item" :key="item"></NTabPane> | ||
28 | + </NTabs> | ||
29 | + <section v-if="tabValue === RequestParamsTypeEnum.PARAMS"> | ||
30 | + <ParamsTable v-model:value="value[RequestParamsTypeEnum.PARAMS]" /> | ||
31 | + </section> | ||
32 | + | ||
33 | + <RequestBody v-model:value="value" @update:requestParamsBodyType="handleSyncRequestParamsBodyType" | ||
34 | + v-model:requestParamsBodyType="requestParamsBodyType" v-if="tabValue === RequestParamsTypeEnum.BODY" /> | ||
35 | + | ||
36 | + <ParamsTable v-if="tabValue === RequestParamsTypeEnum.HEADER" v-model:value="value.Header" /> | ||
37 | + </section> | ||
38 | +</template> | ||
39 | + | ||
40 | +<style lang="scss" scoped> | ||
41 | +.container { | ||
42 | + width: 600px; | ||
43 | +} | ||
44 | + | ||
45 | +.body-container { | ||
46 | + margin-top: 20px; | ||
47 | +} | ||
48 | +</style> |
1 | +<script lang="ts" setup> | ||
2 | +import { RequestParamsTypeEnum } from '@/enums/httpEnum'; | ||
3 | +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'; | ||
4 | +import { NTabPane, NTabs } from 'naive-ui'; | ||
5 | +import { ref } from 'vue'; | ||
6 | +import ParamsTable from './ParamsTable.vue'; | ||
7 | + | ||
8 | +const chartEditStore = useChartEditStore() | ||
9 | + | ||
10 | +const tabs: RequestParamsTypeEnum[] = [RequestParamsTypeEnum.HEADER] | ||
11 | + | ||
12 | +const currenPanel = ref(RequestParamsTypeEnum.HEADER) | ||
13 | + | ||
14 | + | ||
15 | +</script> | ||
16 | + | ||
17 | +<template> | ||
18 | + <NTabs type="line" animated> | ||
19 | + <NTabPane v-model:value="currenPanel" v-for="item in tabs" :name="item" :tab="item" :key="item" /> | ||
20 | + </NTabs> | ||
21 | + <section> | ||
22 | + <ParamsTable v-if="currenPanel === RequestParamsTypeEnum.HEADER" v-model:value="chartEditStore.requestGlobalConfig.requestParams.Header" /> | ||
23 | + </section> | ||
24 | +</template> |
1 | +<script lang="ts" setup> | ||
2 | +import { SettingItem, SettingItemBox } from '@/components/Pages/ChartItemSetting'; | ||
3 | +import { icon } from '@/plugins'; | ||
4 | +import { NButton, NCard, NCollapseTransition, NIcon, NInput, NInputGroup, NInputNumber, NSelect, NSpace, NTag, NTooltip, SelectOption } from 'naive-ui'; | ||
5 | +import { computed, ref, unref } from 'vue'; | ||
6 | +import GlobalParamsConfiguration from './GlobalParamsConfiguration.vue' | ||
7 | +import { ChevronDown, ChevronUp } from '@vicons/carbon' | ||
8 | +import { useDesignStore } from '@/store/modules/designStore/designStore'; | ||
9 | +import { selectTimeOptions } from '../../../index.d'; | ||
10 | +import { RequestConfigType, RequestGlobalConfigType } from '@/store/modules/chartEditStore/chartEditStore.d' | ||
11 | +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'; | ||
12 | +import { useTargetData } from '../../../../hooks/useTargetData.hook'; | ||
13 | +import { RequestHttpIntervalEnum } from '@/enums/httpEnum'; | ||
14 | + | ||
15 | +const { PencilIcon } = icon.ionicons5 | ||
16 | +const designStore = useDesignStore() | ||
17 | +const editDisabled = ref(false) | ||
18 | +const collapseHeaderTable = ref(false) | ||
19 | + | ||
20 | +const { chartEditStore } = useTargetData() | ||
21 | + | ||
22 | +const handleCollapse = () => { | ||
23 | + collapseHeaderTable.value = !unref(collapseHeaderTable) | ||
24 | +} | ||
25 | + | ||
26 | + | ||
27 | +// 颜色 | ||
28 | +const themeColor = computed(() => { | ||
29 | + return designStore.getAppTheme | ||
30 | +}) | ||
31 | + | ||
32 | + | ||
33 | + | ||
34 | +</script> | ||
35 | + | ||
36 | +<template> | ||
37 | + <NCard> | ||
38 | + <template #header> | ||
39 | + <NTag type="info">全局公共配置</NTag> | ||
40 | + </template> | ||
41 | + <NSpace vertical> | ||
42 | + <SettingItemBox name="服务" :itemRightStyle="{ | ||
43 | + gridTemplateColumns: '5fr 2fr 1fr' | ||
44 | + }"> | ||
45 | + <!-- 源地址 --> | ||
46 | + <SettingItem name="前置 URL"> | ||
47 | + <NInput v-model:value="chartEditStore.requestGlobalConfig.requestOriginUrl" default-value="http://127.0.0.1" :disabled="editDisabled" | ||
48 | + size="small" placeholder="例:http://127.0.0.1"></NInput> | ||
49 | + </SettingItem> | ||
50 | + <SettingItem name="更新间隔,为 0 只会初始化"> | ||
51 | + <NInputGroup> | ||
52 | + <NInputNumber v-model:value="chartEditStore.requestGlobalConfig.requestInterval" class="select-time-number" | ||
53 | + size="small" min="0" :show-button="false" :disabled="editDisabled" placeholder="请输入数字"> | ||
54 | + </NInputNumber> | ||
55 | + <!-- 单位 --> | ||
56 | + <NSelect v-model:value="chartEditStore.requestGlobalConfig.requestIntervalUnit" class="select-time-options" | ||
57 | + size="small" :default-value="RequestHttpIntervalEnum.SECOND" :options="selectTimeOptions as SelectOption[]" | ||
58 | + :disabled="editDisabled" /> | ||
59 | + </NInputGroup> | ||
60 | + </SettingItem> | ||
61 | + <NButton v-show="editDisabled" type="primary" ghost @click="editDisabled = false"> | ||
62 | + <template #icon> | ||
63 | + <NIcon> | ||
64 | + <PencilIcon /> | ||
65 | + </NIcon> | ||
66 | + </template> | ||
67 | + 编辑配置 | ||
68 | + </NButton> | ||
69 | + </SettingItemBox> | ||
70 | + <NCollapseTransition :show="collapseHeaderTable"> | ||
71 | + <GlobalParamsConfiguration /> | ||
72 | + </NCollapseTransition> | ||
73 | + <section class="arrow"> | ||
74 | + <NTooltip> | ||
75 | + <template #trigger> | ||
76 | + <NIcon @click="handleCollapse" size="30"> | ||
77 | + <ChevronDown v-show="!collapseHeaderTable" /> | ||
78 | + <ChevronUp v-show="collapseHeaderTable" /> | ||
79 | + </NIcon> | ||
80 | + </template> | ||
81 | + <span>{{ collapseHeaderTable ? '收起' : '展开' }}</span> | ||
82 | + </NTooltip> | ||
83 | + </section> | ||
84 | + </NSpace> | ||
85 | + </NCard> | ||
86 | +</template> | ||
87 | + | ||
88 | + | ||
89 | +<style lang="scss" scoped> | ||
90 | +.arrow { | ||
91 | + display: flex; | ||
92 | + justify-content: center; | ||
93 | + align-items: center; | ||
94 | + cursor: pointer; | ||
95 | + | ||
96 | + &:hover { | ||
97 | + color: v-bind('themeColor'); | ||
98 | + | ||
99 | + } | ||
100 | +} | ||
101 | +</style> |
1 | +<script setup lang="ts" > | ||
2 | +import { getUUID } from '@/utils'; | ||
3 | +import { ButtonProps, DataTableColumns, InputProps, NButton, NDataTable, NIcon, NInput, NSpace, NTag, NTooltip, TagProps } from 'naive-ui'; | ||
4 | +import { computed, h, ref, unref, watch } from 'vue'; | ||
5 | +import { Subtract, Add } from '@vicons/carbon' | ||
6 | +import { isObject } from '@/utils/external/is'; | ||
7 | + | ||
8 | +interface DataSource { | ||
9 | + id: string | ||
10 | + value?: string | ||
11 | + keyName?: string | ||
12 | + result?: boolean | ||
13 | +} | ||
14 | + | ||
15 | +const columns: DataTableColumns<DataSource> = [ | ||
16 | + { | ||
17 | + title: '序号', | ||
18 | + key: 'index', | ||
19 | + render: (_, index) => index + 1, | ||
20 | + width: 50, | ||
21 | + }, | ||
22 | + { | ||
23 | + title: 'Key', | ||
24 | + key: 'keyName', | ||
25 | + render: (row, index) => { | ||
26 | + return h( | ||
27 | + NInput, | ||
28 | + { | ||
29 | + value: row.keyName, | ||
30 | + onBlur: () => handleInputBlur(row), | ||
31 | + onUpdateValue: (value: string) => unref(dataSource)[index].keyName = value, | ||
32 | + size: 'small', | ||
33 | + disabled: props.disabled | ||
34 | + } as InputProps | ||
35 | + ) | ||
36 | + } | ||
37 | + }, | ||
38 | + { | ||
39 | + title: 'Value', | ||
40 | + key: 'value', | ||
41 | + render: (row, index) => { | ||
42 | + return h( | ||
43 | + NInput, | ||
44 | + { | ||
45 | + value: row.value, | ||
46 | + onBlur: () => handleInputBlur(row), | ||
47 | + onUpdateValue: (value: string) => unref(dataSource)[index].value = value, | ||
48 | + size: 'small', | ||
49 | + disabled: props.disabled | ||
50 | + } as InputProps | ||
51 | + ) | ||
52 | + } | ||
53 | + }, | ||
54 | + { | ||
55 | + title: '操作', | ||
56 | + key: 'actions', | ||
57 | + render: (row) => { | ||
58 | + return h( | ||
59 | + NSpace, | ||
60 | + () => [ | ||
61 | + h( | ||
62 | + NTooltip, | ||
63 | + null, | ||
64 | + { | ||
65 | + trigger: () => h( | ||
66 | + NButton, | ||
67 | + { | ||
68 | + type: 'success', | ||
69 | + size: 'small', | ||
70 | + ghost: true, | ||
71 | + onClick: () => handleAddRow(row), | ||
72 | + disabled: props.disabled || !unref(canAddRow) | ||
73 | + } as ButtonProps, | ||
74 | + { | ||
75 | + default: () => h(NIcon, () => h(Add)) | ||
76 | + } | ||
77 | + ), | ||
78 | + default: () => '插入行' | ||
79 | + } | ||
80 | + ), | ||
81 | + h( | ||
82 | + NTooltip, | ||
83 | + null, | ||
84 | + { | ||
85 | + trigger: () => h( | ||
86 | + NButton, | ||
87 | + { | ||
88 | + type: 'warning', | ||
89 | + size: 'small', | ||
90 | + ghost: true, | ||
91 | + onClick: () => handleSubtractRow(row), | ||
92 | + disabled: props.disabled || !unref(canDeleteRow) | ||
93 | + } as ButtonProps, | ||
94 | + { | ||
95 | + default: () => h(NIcon, () => h(Subtract)) | ||
96 | + } | ||
97 | + ), | ||
98 | + default: () => '删除行' | ||
99 | + } | ||
100 | + ) | ||
101 | + ] | ||
102 | + ) | ||
103 | + }, | ||
104 | + width: 100, | ||
105 | + }, | ||
106 | + { | ||
107 | + title: '结果', | ||
108 | + key: 'result', | ||
109 | + render: (row) => { | ||
110 | + return h(NTag, { type: row.result ? 'success' : 'error' } as TagProps, () => `${row.result ? '' : '未'}通过`) | ||
111 | + }, | ||
112 | + width: 80 | ||
113 | + } | ||
114 | +] | ||
115 | + | ||
116 | +const props = withDefaults( | ||
117 | + defineProps<{ | ||
118 | + value?: Recordable | ||
119 | + disabled?: boolean | ||
120 | + maxRow?: number | ||
121 | + }>(), | ||
122 | + { | ||
123 | + disabled: false, | ||
124 | + maxRow: 50, | ||
125 | + } | ||
126 | +) | ||
127 | + | ||
128 | +const emit = defineEmits(['update:value']) | ||
129 | + | ||
130 | +const createNewRow = () => { | ||
131 | + return { id: getUUID(), result: true } as DataSource | ||
132 | +} | ||
133 | + | ||
134 | +const dataSource = ref<DataSource[]>([ | ||
135 | + createNewRow() | ||
136 | +]) | ||
137 | + | ||
138 | +watch( | ||
139 | + () => props.value, | ||
140 | + (target) => { | ||
141 | + if (target && isObject(target) && Object.keys(target).length) { | ||
142 | + dataSource.value = Object.keys(props.value || {}).map(keyName => ({ ...createNewRow(), keyName, value: Reflect.get(props.value || {}, keyName) })) | ||
143 | + } else { | ||
144 | + dataSource.value = [createNewRow()] | ||
145 | + } | ||
146 | + }, | ||
147 | + { | ||
148 | + immediate: true, | ||
149 | + deep: true | ||
150 | + } | ||
151 | +) | ||
152 | + | ||
153 | +const canDeleteRow = computed(() => { | ||
154 | + return unref(dataSource).length >= 2 | ||
155 | +}) | ||
156 | + | ||
157 | +const canAddRow = computed(() => { | ||
158 | + return unref(dataSource).length < props.maxRow | ||
159 | +}) | ||
160 | + | ||
161 | +const handleAddRow = (record: DataSource) => { | ||
162 | + const index = unref(dataSource).findIndex(item => item.id === record.id) | ||
163 | + unref(dataSource).splice(index + 1, 0, createNewRow()) | ||
164 | +} | ||
165 | + | ||
166 | +const handleSubtractRow = (record: DataSource) => { | ||
167 | + const index = unref(dataSource).findIndex(item => item.id === record.id) | ||
168 | + unref(dataSource).splice(index, 1) | ||
169 | +} | ||
170 | + | ||
171 | + | ||
172 | +const handleInputBlur = (record: DataSource) => { | ||
173 | + const { keyName, value } = record | ||
174 | + record.result = !!(keyName && value) | ||
175 | + if (unref(dataSource).every(item => item.result)) { | ||
176 | + emit('update:value', getHeaderConfiguration()) | ||
177 | + } | ||
178 | +} | ||
179 | + | ||
180 | +const getHeaderConfiguration = () => { | ||
181 | + return unref(dataSource).reduce((prev, next) => { | ||
182 | + const { result, value, keyName } = next | ||
183 | + const header = result && value && keyName ? { [keyName]: value } : {} | ||
184 | + return { ...prev, ...header } | ||
185 | + }, {} as Recordable) | ||
186 | +} | ||
187 | + | ||
188 | +</script> | ||
189 | + | ||
190 | +<template> | ||
191 | + <NDataTable size="small" :columns="columns" :data="dataSource" max-height="300" /> | ||
192 | +</template> |
1 | +<script lang="ts" setup> | ||
2 | +import { MonacoEditor } from '@/components/Pages/MonacoEditor'; | ||
3 | +import { RequestBodyEnum, RequestBodyEnumList, RequestParams } from '@/enums/httpEnum'; | ||
4 | +import { NCard } from 'naive-ui'; | ||
5 | +import ParamsTable from './ParamsTable.vue'; | ||
6 | + | ||
7 | +defineProps<{ | ||
8 | + requestParamsBodyType: RequestBodyEnum | ||
9 | + value: RequestParams | ||
10 | +}>() | ||
11 | + | ||
12 | +const emit = defineEmits(['update:requestParamsBodyType']) | ||
13 | + | ||
14 | +const handleSyncRequestParamsBodyType = (value: RequestBodyEnum) => { | ||
15 | + emit('update:requestParamsBodyType', value) | ||
16 | +} | ||
17 | + | ||
18 | +</script> | ||
19 | + | ||
20 | +<template> | ||
21 | + <section> | ||
22 | + <NRadioGroup v-model:value="requestParamsBodyType" @update:value="handleSyncRequestParamsBodyType"> | ||
23 | + <NSpace> | ||
24 | + <NRadio v-for="item in RequestBodyEnumList" :key="item" :value="item"> | ||
25 | + {{ item }} | ||
26 | + </NRadio> | ||
27 | + </NSpace> | ||
28 | + </NRadioGroup> | ||
29 | + | ||
30 | + <section class="body-container"> | ||
31 | + <!-- 为 none 时 --> | ||
32 | + <NCard v-if="requestParamsBodyType === RequestBodyEnum.NONE"> | ||
33 | + <NText depth="3">该接口没有 Body 体</NText> | ||
34 | + </NCard> | ||
35 | + | ||
36 | + <ParamsTable v-if="requestParamsBodyType === RequestBodyEnum.FORM_DATA" | ||
37 | + v-model:value="value.Body[RequestBodyEnum.FORM_DATA]" /> | ||
38 | + | ||
39 | + <ParamsTable v-if="requestParamsBodyType === RequestBodyEnum.X_WWW_FORM_URLENCODED" | ||
40 | + v-model:value="value.Body[RequestBodyEnum.X_WWW_FORM_URLENCODED]" /> | ||
41 | + | ||
42 | + <MonacoEditor v-if="requestParamsBodyType === RequestBodyEnum.JSON" | ||
43 | + v-model:modelValue="value.Body[RequestBodyEnum.JSON]" width="600px" height="200px" language="json" /> | ||
44 | + | ||
45 | + <MonacoEditor v-if="requestParamsBodyType === RequestBodyEnum.XML" | ||
46 | + v-model:modelValue="value.Body[RequestBodyEnum.XML]" width="600px" height="200px" language="xml" /> | ||
47 | + </section> | ||
48 | + </section> | ||
49 | +</template> | ||
50 | + | ||
51 | +<style lang="scss" scoped> | ||
52 | + .body-container { | ||
53 | + margin-top: 20px; | ||
54 | + } | ||
55 | +</style> |
1 | +<script lang="ts" setup> | ||
2 | +import { SettingItemBox } from '@/components/Pages/ChartItemSetting'; | ||
3 | +import { MonacoEditor } from '@/components/Pages/MonacoEditor'; | ||
4 | +import { NTag } from 'naive-ui'; | ||
5 | + | ||
6 | +defineProps<{ | ||
7 | + value: string | ||
8 | +}>() | ||
9 | + | ||
10 | +const emits = defineEmits(['update:value']) | ||
11 | + | ||
12 | +const updateValue = (value: string) => { | ||
13 | + emits('update:value', value) | ||
14 | +} | ||
15 | + | ||
16 | +</script> | ||
17 | + | ||
18 | +<template> | ||
19 | + <section> | ||
20 | + <NTag type="warning">需要后台提供专门处理sql的借口</NTag> | ||
21 | + <SettingItemBox name="键名"> | ||
22 | + <NTag type="success" style="width: fit-content;">sql</NTag> | ||
23 | + </SettingItemBox> | ||
24 | + <SettingItemBox name="键值"> | ||
25 | + <MonacoEditor v-model:modelValue="value" @update:modelValue="updateValue" width="600px" height="200px" | ||
26 | + language="sql" /> | ||
27 | + </SettingItemBox> | ||
28 | + </section> | ||
29 | +</template> |
src/views/chart/ContentConfigurations/components/ChartData/external/components/RequestModal/index.ts
0 → 100644
1 | +export { default as RequestModal } from './index.vue' |
1 | +<script lang="ts" setup> | ||
2 | +import { RequestDataTypeEnum, RequestDataTypeNameEnum } from '@/enums/external/httpEnum'; | ||
3 | +import { useDesign } from '@/hooks/external/useDesign'; | ||
4 | +import { CreateComponentType } from '@/packages/index.d'; | ||
5 | +import { CreateComponentGroupType } from '@/packages/index.d'; | ||
6 | +import { RequestConfigType } from '@/store/modules/chartEditStore/chartEditStore.d'; | ||
7 | +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'; | ||
8 | +import { GlobalComponentConfig, NButton, NDivider, NModal, NSpace, NTag } from 'naive-ui'; | ||
9 | +import { ref, unref, computed, nextTick } from 'vue'; | ||
10 | +import { PublicInterfaceForm } from '../PublicInterfaceForm'; | ||
11 | +import ComponentConfiguration from './ComponentConfiguration.vue'; | ||
12 | +import GlobalPublicConfiguration from './GlobalPublicConfiguration.vue'; | ||
13 | +import { createRequestModalContext } from './useRequestModalContext'; | ||
14 | + | ||
15 | +const requestDataType = ref<RequestDataTypeEnum>(RequestDataTypeEnum.AJAX) | ||
16 | + | ||
17 | +const showModal = ref(false) | ||
18 | + | ||
19 | +const chartEditStore = useChartEditStore() | ||
20 | + | ||
21 | +const globalConfigurationEl = ref<Nullable<InstanceType<typeof GlobalPublicConfiguration>>>() | ||
22 | + | ||
23 | +const componentConfigurationEl = ref<Nullable<InstanceType<typeof ComponentConfiguration>>>() | ||
24 | + | ||
25 | +const publicInterfaceFormEl = ref<Nullable<InstanceType<typeof PublicInterfaceForm>>>() | ||
26 | + | ||
27 | +const getRequestTypeName = computed(() => { | ||
28 | + return RequestDataTypeNameEnum[RequestDataTypeEnum[unref(requestDataType)] as keyof typeof RequestDataTypeEnum] | ||
29 | +}) | ||
30 | + | ||
31 | +const { prefixCls } = useDesign('chart-data-request') | ||
32 | + | ||
33 | +const openModal = async (flag = true, type: RequestDataTypeEnum) => { | ||
34 | + requestDataType.value = type | ||
35 | + showModal.value = flag | ||
36 | + await nextTick() | ||
37 | + unref(componentConfigurationEl)?.setConfigurationData(unref(selectTarget)!.request || {}) | ||
38 | + unref(publicInterfaceFormEl)?.setConfigurationData(unref(selectTarget)!.request || {}) | ||
39 | +} | ||
40 | + | ||
41 | +const handleSaveAndRequest = () => { | ||
42 | + handleSaveAction() | ||
43 | +} | ||
44 | + | ||
45 | +const selectTarget = computed<CreateComponentType | CreateComponentGroupType | undefined>(() => { | ||
46 | + const selectId = chartEditStore.getTargetChart.selectId | ||
47 | + // 排除多个 | ||
48 | + if (selectId.length !== 1) return undefined | ||
49 | + const target = chartEditStore.componentList[chartEditStore.fetchTargetIndex()] | ||
50 | + return target as CreateComponentType | CreateComponentGroupType | ||
51 | +}) | ||
52 | + | ||
53 | +const validate = async () => { | ||
54 | + if (unref(requestDataType) === RequestDataTypeEnum.Pond) { | ||
55 | + return await unref(publicInterfaceFormEl)?.validate() | ||
56 | + } | ||
57 | + return true | ||
58 | +} | ||
59 | + | ||
60 | +const getResult = () => { | ||
61 | + if (unref(requestDataType) === RequestDataTypeEnum.AJAX) { | ||
62 | + return unref(componentConfigurationEl)?.getConfigurationData() | ||
63 | + } else if (unref(requestDataType) === RequestDataTypeEnum.Pond) { | ||
64 | + return unref(publicInterfaceFormEl)?.getConfigurationData() | ||
65 | + } | ||
66 | + | ||
67 | + return {} as unknown as RequestConfigType | ||
68 | +} | ||
69 | + | ||
70 | +const handleSaveAction = async () => { | ||
71 | + if (!(await validate())) return | ||
72 | + const value = getResult() | ||
73 | + console.log(value) | ||
74 | + if (unref(selectTarget)) { | ||
75 | + chartEditStore.updateComponentList(chartEditStore.fetchTargetIndex(), { | ||
76 | + ...unref(selectTarget)!, | ||
77 | + request: value! | ||
78 | + }) | ||
79 | + } | ||
80 | + showModal.value = false | ||
81 | +} | ||
82 | + | ||
83 | +createRequestModalContext({ | ||
84 | + requestDataType | ||
85 | +}) | ||
86 | + | ||
87 | +defineExpose({ | ||
88 | + openModal, | ||
89 | +}) | ||
90 | + | ||
91 | +</script> | ||
92 | + | ||
93 | +<template> | ||
94 | + <NModal :class="prefixCls" v-model:show="showModal" preset="card" style="width: 1000px;" title="请求配置"> | ||
95 | + <GlobalPublicConfiguration v-if="requestDataType === RequestDataTypeEnum.AJAX" ref="globalConfigurationEl" /> | ||
96 | + <NDivider v-if="requestDataType === RequestDataTypeEnum.AJAX" /> | ||
97 | + <ComponentConfiguration v-if="requestDataType === RequestDataTypeEnum.AJAX" ref="componentConfigurationEl" /> | ||
98 | + <PublicInterfaceForm v-if="requestDataType === RequestDataTypeEnum.Pond" ref="publicInterfaceFormEl" /> | ||
99 | + <template #action> | ||
100 | + <NSpace justify="space-between"> | ||
101 | + <div style="display: flex; align-items: center; "> | ||
102 | + <span>「 更多 」</span> | ||
103 | + <span style="margin-right: 5px;">——</span> | ||
104 | + <NTag type="info">{{ getRequestTypeName }}</NTag> | ||
105 | + </div> | ||
106 | + <NButton type="primary" @click="handleSaveAndRequest">保存 & 发送请求</NButton> | ||
107 | + </NSpace> | ||
108 | + </template> | ||
109 | + </NModal> | ||
110 | +</template> | ||
111 | + | ||
112 | + | ||
113 | +<style lang="scss" > | ||
114 | +@include thingsKit('chart-data-request') { | ||
115 | + | ||
116 | + &.n-card.n-modal, | ||
117 | + .n-card { | ||
118 | + @extend .go-background-filter; | ||
119 | + } | ||
120 | + | ||
121 | + .n-card-shallow { | ||
122 | + background-color: rgba(0, 0, 0, 0) !important; | ||
123 | + } | ||
124 | + | ||
125 | + @include deep() { | ||
126 | + &>.n-card__content { | ||
127 | + padding-right: 0; | ||
128 | + } | ||
129 | + | ||
130 | + .n-card__content { | ||
131 | + padding-bottom: 5px; | ||
132 | + } | ||
133 | + } | ||
134 | +} | ||
135 | +</style> |
1 | +import { RequestDataTypeEnum } from "@/enums/external/httpEnum" | ||
2 | +import { createContext, useContext } from "@/utils/external/useAppContext" | ||
3 | +import { InjectionKey, Ref } from "vue" | ||
4 | + | ||
5 | +export interface RequestContextProps { | ||
6 | + requestDataType: Ref<RequestDataTypeEnum> | ||
7 | +} | ||
8 | + | ||
9 | +const key: InjectionKey<RequestContextProps> = Symbol() | ||
10 | + | ||
11 | +export const useRequestModalContext = () => { | ||
12 | + return useContext<RequestContextProps>(key) | ||
13 | +} | ||
14 | + | ||
15 | +export const createRequestModalContext = (context: RequestContextProps) => { | ||
16 | + return createContext(context, key) | ||
17 | +} |
1 | <template> | 1 | <template> |
2 | <div class="go-chart-configurations-data" v-if="targetData"> | 2 | <div class="go-chart-configurations-data" v-if="targetData"> |
3 | <setting-item-box name="请求方式" :alone="true"> | 3 | <setting-item-box name="请求方式" :alone="true"> |
4 | - <n-select v-model:value="targetData.request.requestDataType" :disabled="isNotData" :options="selectOptions" /> | 4 | + <!-- THINGS_KIT 请求方式选项修改--> |
5 | + <n-select v-if="targetData.request.requestDataType !== RequestDataTypeEnum.Pond" | ||
6 | + v-model:value="targetData.request.requestDataType" :disabled="isNotData" :options="selectOptions" /> | ||
7 | + <n-select v-if="targetData.request.requestDataType === RequestDataTypeEnum.Pond" | ||
8 | + v-model:value="targetData.request.requestDataType" :disabled="isNotData" :options="[ | ||
9 | + { | ||
10 | + label: SelectCreateDataEnum.STATIC, | ||
11 | + value: RequestDataTypeEnum.STATIC | ||
12 | + }, | ||
13 | + { | ||
14 | + label: SelectCreateDataEnum.AJAX, | ||
15 | + value: RequestDataTypeEnum.Pond | ||
16 | + } | ||
17 | + ]" /> | ||
5 | </setting-item-box> | 18 | </setting-item-box> |
6 | <!-- 静态 --> | 19 | <!-- 静态 --> |
7 | <chart-data-static v-if="targetData.request.requestDataType === RequestDataTypeEnum.STATIC"></chart-data-static> | 20 | <chart-data-static v-if="targetData.request.requestDataType === RequestDataTypeEnum.STATIC"></chart-data-static> |
21 | + <!-- THINGS_KIT 重写动态请求面板 --> | ||
22 | + <ChartDynamicRequest v-if="targetData.request.requestDataType !== RequestDataTypeEnum.STATIC" /> | ||
8 | <!-- 动态 --> | 23 | <!-- 动态 --> |
9 | - <chart-data-ajax v-if="targetData.request.requestDataType === RequestDataTypeEnum.AJAX"></chart-data-ajax> | 24 | + <!-- <chart-data-ajax v-if="targetData.request.requestDataType === RequestDataTypeEnum.AJAX"></chart-data-ajax> --> |
25 | + | ||
26 | + <!-- THINGS_KIT 隐藏公共请求面板 --> | ||
10 | <!-- 数据池 --> | 27 | <!-- 数据池 --> |
11 | - <chart-data-pond v-if="targetData.request.requestDataType === RequestDataTypeEnum.Pond"></chart-data-pond> | 28 | + <!-- <chart-data-pond v-if="targetData.request.requestDataType === RequestDataTypeEnum.Pond"></chart-data-pond> --> |
12 | </div> | 29 | </div> |
13 | </template> | 30 | </template> |
14 | 31 | ||
@@ -23,7 +40,10 @@ import { SelectCreateDataType, SelectCreateDataEnum } from './index.d' | @@ -23,7 +40,10 @@ import { SelectCreateDataType, SelectCreateDataEnum } from './index.d' | ||
23 | 40 | ||
24 | const ChartDataStatic = loadAsyncComponent(() => import('./components/ChartDataStatic/index.vue')) | 41 | const ChartDataStatic = loadAsyncComponent(() => import('./components/ChartDataStatic/index.vue')) |
25 | const ChartDataAjax = loadAsyncComponent(() => import('./components/ChartDataAjax/index.vue')) | 42 | const ChartDataAjax = loadAsyncComponent(() => import('./components/ChartDataAjax/index.vue')) |
26 | -const ChartDataPond = loadAsyncComponent(() => import('./components/ChartDataPond/index.vue')) | 43 | + |
44 | +// THINGS_KIT 重写动态请求面板 | ||
45 | +// const ChartDataPond = loadAsyncComponent(() => import('./components/ChartDataPond/index.vue')) | ||
46 | +const ChartDynamicRequest = loadAsyncComponent(() => import('./external/components/ChartDynamicRequest/index.vue')) | ||
27 | 47 | ||
28 | const { targetData } = useTargetData() | 48 | const { targetData } = useTargetData() |
29 | 49 | ||
@@ -37,10 +57,11 @@ const selectOptions: SelectCreateDataType[] = [ | @@ -37,10 +57,11 @@ const selectOptions: SelectCreateDataType[] = [ | ||
37 | label: SelectCreateDataEnum.AJAX, | 57 | label: SelectCreateDataEnum.AJAX, |
38 | value: RequestDataTypeEnum.AJAX | 58 | value: RequestDataTypeEnum.AJAX |
39 | }, | 59 | }, |
40 | - { | ||
41 | - label: SelectCreateDataEnum.Pond, | ||
42 | - value: RequestDataTypeEnum.Pond | ||
43 | - } | 60 | + // THINGS_KIT 隐藏公共请求面板 |
61 | + // { | ||
62 | + // label: SelectCreateDataEnum.Pond, | ||
63 | + // value: RequestDataTypeEnum.Pond | ||
64 | + // } | ||
44 | ] | 65 | ] |
45 | 66 | ||
46 | // 无数据源 | 67 | // 无数据源 |