Commit 55c5f1e06720ab55568c010d4c9d478315dd6352
1 parent
cf4e70dd
Merge branch 'local_dev_ft' into 'main_dev'
feat:新增公共接口管理(先测试) See merge request yunteng/thingskit-front!513 (cherry picked from commit 93d60ba9) 0ae5e563 feat:大屏设计器新增发布 a7b74b96 Merge branch 'main' into local_dev_ft 1ad96f55 wip:公共接口管理开发中 9365c432 wip:公共接口管理开发中 c7192456 Merge branch 'main' into local_dev_ft 53dbbcf3 feat:pc端新增公共接口管理 9527b942 feat:pc端新增公共接口管理 c6568d8e feat:pc端新增大屏设计器发布和未发布状态修改 9e4ba1a1 feat:pc端新增公共接口管理
Showing
21 changed files
with
1685 additions
and
86 deletions
| ... | ... | @@ -3,17 +3,20 @@ import type { | 
| 3 | 3 | queryPageParams, | 
| 4 | 4 | BigScreenCenterParams, | 
| 5 | 5 | ConfigurationCenterInfo, | 
| 6 | - BigScreenCenterItemsModal, | |
| 6 | + BigScreenCenterItemsModel, | |
| 7 | + BigScreenInterfaceParams, | |
| 7 | 8 | } from './model/bigscreenCenterModel'; | 
| 8 | 9 | import { getPageData } from '../../base'; | 
| 9 | 10 | import { FileUploadResponse } from '../../oem/model'; | 
| 10 | 11 | enum API { | 
| 11 | 12 | basicUrl = '/data_view', | 
| 12 | 13 | UPLOAD = '/oss/upload', | 
| 14 | + //大屏公共接口 | |
| 15 | + DATA_VIEW_INTERFACE = '/data_view_interface', | |
| 13 | 16 | } | 
| 14 | 17 | |
| 15 | 18 | export const getPage = (params: queryPageParams) => { | 
| 16 | - return getPageData<BigScreenCenterItemsModal>(params, API.basicUrl); | |
| 19 | + return getPageData<BigScreenCenterItemsModel>(params, API.basicUrl); | |
| 17 | 20 | }; | 
| 18 | 21 | |
| 19 | 22 | export const saveConfigurationCenter = (params: BigScreenCenterParams) => { | 
| ... | ... | @@ -46,3 +49,58 @@ export const saveOrUpdateBigScreenCenter = (params: ConfigurationCenterInfo, isU | 
| 46 | 49 | export const uploadThumbnail = (file: FormData) => { | 
| 47 | 50 | return defHttp.post<FileUploadResponse>({ url: API.UPLOAD, params: file }); | 
| 48 | 51 | }; | 
| 52 | + | |
| 53 | +export const bigScreenPublish = (id) => { | |
| 54 | + return defHttp.get({ | |
| 55 | + url: API.basicUrl + '/publish/' + id, | |
| 56 | + }); | |
| 57 | +}; | |
| 58 | + | |
| 59 | +export const bigScreenCancelPublish = (id) => { | |
| 60 | + return defHttp.get({ | |
| 61 | + url: API.basicUrl + '/cancel_publish/' + id, | |
| 62 | + }); | |
| 63 | +}; | |
| 64 | + | |
| 65 | +/** | |
| 66 | + * 大屏公共接口 | |
| 67 | + */ | |
| 68 | + | |
| 69 | +export const getDataViewInterfacePage = (params: queryPageParams) => { | |
| 70 | + return getPageData<BigScreenCenterItemsModel>(params, API.DATA_VIEW_INTERFACE); | |
| 71 | +}; | |
| 72 | + | |
| 73 | +export const saveDataViewInterface = (params: BigScreenInterfaceParams) => { | |
| 74 | + return defHttp.post({ | |
| 75 | + url: API.DATA_VIEW_INTERFACE, | |
| 76 | + data: params, | |
| 77 | + }); | |
| 78 | +}; | |
| 79 | + | |
| 80 | +export const updateDataViewInterface = (params: BigScreenInterfaceParams) => { | |
| 81 | + return defHttp.put({ | |
| 82 | + url: API.DATA_VIEW_INTERFACE, | |
| 83 | + data: params, | |
| 84 | + }); | |
| 85 | +}; | |
| 86 | + | |
| 87 | +export const deleteBigViewInterface = (ids: string[]) => { | |
| 88 | + return defHttp.delete({ | |
| 89 | + url: API.DATA_VIEW_INTERFACE, | |
| 90 | + data: { | |
| 91 | + ids: ids, | |
| 92 | + }, | |
| 93 | + }); | |
| 94 | +}; | |
| 95 | + | |
| 96 | +export const getPublish = (id) => { | |
| 97 | + return defHttp.get({ | |
| 98 | + url: API.DATA_VIEW_INTERFACE + '/publish/' + id, | |
| 99 | + }); | |
| 100 | +}; | |
| 101 | + | |
| 102 | +export const getCancelPublish = (id) => { | |
| 103 | + return defHttp.get({ | |
| 104 | + url: API.DATA_VIEW_INTERFACE + '/cancel_publish/' + id, | |
| 105 | + }); | |
| 106 | +}; | ... | ... | 
| ... | ... | @@ -25,3 +25,32 @@ export interface BigScreenCenterParams { | 
| 25 | 25 | defaultContent?: string; | 
| 26 | 26 | } | 
| 27 | 27 | export type ConfigurationCenterInfo = BigScreenCenterParams; | 
| 28 | + | |
| 29 | +/** | |
| 30 | + * 大屏公共接口 | |
| 31 | + */ | |
| 32 | +export interface BigScreenInterfaceParams { | |
| 33 | + createTime: string; | |
| 34 | + creator: string; | |
| 35 | + defaultConfig: string; | |
| 36 | + description: string; | |
| 37 | + enabled: boolean; | |
| 38 | + icon: string; | |
| 39 | + id: string; | |
| 40 | + interfaceName: string; | |
| 41 | + name: string; | |
| 42 | + remark: string; | |
| 43 | + requestContentType: 0; | |
| 44 | + requestHttpType: string; | |
| 45 | + requestOriginUrl: string; | |
| 46 | + requestParams: string; | |
| 47 | + requestUrl: string; | |
| 48 | + roleIds: [string]; | |
| 49 | + state: number; | |
| 50 | + tenantExpireTime: string; | |
| 51 | + tenantId: string; | |
| 52 | + tenantProfileId: string; | |
| 53 | + tenantStatus: string; | |
| 54 | + updateTime: string; | |
| 55 | + updater: string; | |
| 56 | +} | ... | ... | 
| 1 | -<script lang="ts" setup> | |
| 2 | - import { Dropdown, Menu, Popconfirm } from 'ant-design-vue'; | |
| 3 | - import { computed, useSlots } from 'vue'; | |
| 4 | - import Icon from '../Icon'; | |
| 5 | - import { usePermission } from '/@/hooks/web/usePermission'; | |
| 6 | - | |
| 7 | - export interface AuthDropDownProps { | |
| 8 | - dropMenuList: AuthDropMenuList[]; | |
| 9 | - trigger?: ('contextmenu' | 'click' | 'hover')[]; | |
| 10 | - } | |
| 11 | - | |
| 12 | - export interface AuthDropMenuList { | |
| 13 | - icon?: string; | |
| 14 | - event: string | number; | |
| 15 | - text: string; | |
| 16 | - disabled?: boolean; | |
| 17 | - divider?: boolean; | |
| 18 | - auth?: string; | |
| 19 | - onClick?: Fn; | |
| 20 | - popconfirm?: { | |
| 21 | - cancelText?: string; | |
| 22 | - okText?: string; | |
| 23 | - okType?: string; | |
| 24 | - title?: string; | |
| 25 | - icon?: string; | |
| 26 | - disabled?: boolean; | |
| 27 | - onCancel?: Fn; | |
| 28 | - onConfirm?: Fn; | |
| 29 | - onVisibleChange?: Fn; | |
| 30 | - }; | |
| 31 | - } | |
| 32 | - | |
| 33 | - const props = defineProps<AuthDropDownProps>(); | |
| 34 | - | |
| 35 | - const slot = useSlots(); | |
| 36 | - | |
| 37 | - const { hasPermission } = usePermission(); | |
| 38 | - | |
| 39 | - const getMenuList = computed(() => { | |
| 40 | - const { dropMenuList } = props; | |
| 41 | - return dropMenuList.filter((menu) => (menu.auth ? hasPermission(menu.auth) : true)); | |
| 42 | - }); | |
| 43 | - | |
| 44 | - const hasDefaultSlot = computed(() => { | |
| 45 | - return !!slot.default; | |
| 46 | - }); | |
| 47 | -</script> | |
| 48 | - | |
| 49 | -<template> | |
| 50 | - <Dropdown :trigger="$props.trigger"> | |
| 51 | - <template #overlay> | |
| 52 | - <Menu v-if="getMenuList.length"> | |
| 53 | - <template v-for="item in getMenuList" :key="item.event"> | |
| 54 | - <Menu.Divider v-if="item.divider" /> | |
| 55 | - <Menu.Item v-if="!item.popconfirm" @click="item.onClick"> | |
| 56 | - <span class="flex justify-center items-center"> | |
| 57 | - <Icon :icon="item.icon" /> | |
| 58 | - <span class="ml-2">{{ item.text }}</span> | |
| 59 | - </span> | |
| 60 | - </Menu.Item> | |
| 61 | - <Menu.Item v-if="item.popconfirm"> | |
| 62 | - <Popconfirm v-bind="item.popconfirm"> | |
| 63 | - <template v-if="item.popconfirm.icon" #icon> | |
| 64 | - <Icon :icon="item.popconfirm.icon" /> | |
| 65 | - </template> | |
| 66 | - <span class="flex justify-center items-center"> | |
| 67 | - <Icon :icon="item.icon" /> | |
| 68 | - <span class="ml-2">{{ item.text }}</span> | |
| 69 | - </span> | |
| 70 | - </Popconfirm> | |
| 71 | - </Menu.Item> | |
| 72 | - </template> | |
| 73 | - </Menu> | |
| 74 | - </template> | |
| 75 | - <Icon | |
| 76 | - v-if="!hasDefaultSlot" | |
| 77 | - class="items-center justify-center" | |
| 78 | - icon="ant-design:ellipsis-outlined" | |
| 79 | - :class="!getMenuList.length ? '!text-gray-200 !cursor-not-allowed' : ''" | |
| 80 | - /> | |
| 81 | - <slot name="default"></slot> | |
| 82 | - </Dropdown> | |
| 83 | -</template> | |
| 1 | +<script lang="ts" setup> | |
| 2 | + import { Dropdown, Menu, Popconfirm } from 'ant-design-vue'; | |
| 3 | + import { computed, useSlots } from 'vue'; | |
| 4 | + import Icon from '../Icon'; | |
| 5 | + import { usePermission } from '/@/hooks/web/usePermission'; | |
| 6 | + | |
| 7 | + export interface AuthDropDownProps { | |
| 8 | + dropMenuList: AuthDropMenuList[]; | |
| 9 | + trigger?: ('contextmenu' | 'click' | 'hover')[]; | |
| 10 | + } | |
| 11 | + | |
| 12 | + export interface AuthDropMenuList { | |
| 13 | + icon?: string; | |
| 14 | + event: string | number; | |
| 15 | + text: string; | |
| 16 | + disabled?: boolean; | |
| 17 | + divider?: boolean; | |
| 18 | + auth?: string; | |
| 19 | + onClick?: Fn; | |
| 20 | + popconfirm?: { | |
| 21 | + cancelText?: string; | |
| 22 | + okText?: string; | |
| 23 | + okType?: string; | |
| 24 | + title?: string; | |
| 25 | + icon?: string; | |
| 26 | + disabled?: boolean; | |
| 27 | + onCancel?: Fn; | |
| 28 | + onConfirm?: Fn; | |
| 29 | + onVisibleChange?: Fn; | |
| 30 | + }; | |
| 31 | + } | |
| 32 | + | |
| 33 | + const props = defineProps<AuthDropDownProps>(); | |
| 34 | + | |
| 35 | + const slot = useSlots(); | |
| 36 | + | |
| 37 | + const { hasPermission } = usePermission(); | |
| 38 | + | |
| 39 | + const getMenuList = computed(() => { | |
| 40 | + const { dropMenuList } = props; | |
| 41 | + return dropMenuList.filter((menu) => (menu.auth ? hasPermission(menu.auth) : true)); | |
| 42 | + }); | |
| 43 | + | |
| 44 | + const hasDefaultSlot = computed(() => { | |
| 45 | + return !!slot.default; | |
| 46 | + }); | |
| 47 | +</script> | |
| 48 | + | |
| 49 | +<template> | |
| 50 | + <Dropdown :trigger="$props.trigger"> | |
| 51 | + <template #overlay> | |
| 52 | + <Menu v-if="getMenuList.length"> | |
| 53 | + <template v-for="item in getMenuList" :key="item.event"> | |
| 54 | + <Menu.Divider v-if="item.divider" /> | |
| 55 | + <Menu.Item :disabled="item.disabled" v-if="!item.popconfirm" @click="item.onClick"> | |
| 56 | + <span class="flex justify-center items-center"> | |
| 57 | + <Icon :icon="item.icon" /> | |
| 58 | + <span class="ml-2">{{ item.text }}</span> | |
| 59 | + </span> | |
| 60 | + </Menu.Item> | |
| 61 | + <Menu.Item :disabled="item.disabled" v-if="item.popconfirm"> | |
| 62 | + <Popconfirm v-bind="item.popconfirm"> | |
| 63 | + <template v-if="item.popconfirm.icon" #icon> | |
| 64 | + <Icon :icon="item.popconfirm.icon" /> | |
| 65 | + </template> | |
| 66 | + <span class="flex justify-center items-center"> | |
| 67 | + <Icon :icon="item.icon" /> | |
| 68 | + <span class="ml-2">{{ item.text }}</span> | |
| 69 | + </span> | |
| 70 | + </Popconfirm> | |
| 71 | + </Menu.Item> | |
| 72 | + </template> | |
| 73 | + </Menu> | |
| 74 | + </template> | |
| 75 | + <Icon | |
| 76 | + v-if="!hasDefaultSlot" | |
| 77 | + class="items-center justify-center" | |
| 78 | + icon="ant-design:ellipsis-outlined" | |
| 79 | + :class="!getMenuList.length ? '!text-gray-200 !cursor-not-allowed' : ''" | |
| 80 | + /> | |
| 81 | + <slot name="default"></slot> | |
| 82 | + </Dropdown> | |
| 83 | +</template> | ... | ... | 
| ... | ... | @@ -3,7 +3,12 @@ | 
| 3 | 3 | import { ReloadOutlined } from '@ant-design/icons-vue'; | 
| 4 | 4 | import { onMounted, reactive, ref, unref } from 'vue'; | 
| 5 | 5 | import { OrganizationIdTree, useResetOrganizationTree } from '../common/organizationIdTree'; | 
| 6 | - import { deleteBigScreenenter, getPage } from '/@/api/bigscreen/center/bigscreenCenter'; | |
| 6 | + import { | |
| 7 | + bigScreenCancelPublish, | |
| 8 | + bigScreenPublish, | |
| 9 | + deleteBigScreenenter, | |
| 10 | + getPage, | |
| 11 | + } from '/@/api/bigscreen/center/bigscreenCenter'; | |
| 7 | 12 | import { BigScreenCenterItemsModel } from '/@/api/bigscreen/center/model/bigscreenCenterModel'; | 
| 8 | 13 | import { PageWrapper } from '/@/components/Page'; | 
| 9 | 14 | import { BasicForm, useForm } from '/@/components/Form'; | 
| ... | ... | @@ -18,6 +23,7 @@ | 
| 18 | 23 | import { useGlobSetting } from '/@/hooks/setting'; | 
| 19 | 24 | import { AuthIcon, CardLayoutButton } from '/@/components/Widget'; | 
| 20 | 25 | import AuthDropDown from '/@/components/Widget/AuthDropDown.vue'; | 
| 26 | + import { PublicApiDrawer } from './publicApi/index'; | |
| 21 | 27 | |
| 22 | 28 | const listColumn = ref(5); | 
| 23 | 29 | |
| ... | ... | @@ -88,6 +94,8 @@ | 
| 88 | 94 | |
| 89 | 95 | const [registerDrawer, { openDrawer }] = useDrawer(); | 
| 90 | 96 | |
| 97 | + const [registerPublicDrawer, { openDrawer: openPublicApiDrawer }] = useDrawer(); | |
| 98 | + | |
| 91 | 99 | const handleCreateOrUpdate = (record?: BigScreenCenterItemsModel) => { | 
| 92 | 100 | if (record) { | 
| 93 | 101 | openDrawer(true, { | 
| ... | ... | @@ -101,6 +109,8 @@ | 
| 101 | 109 | } | 
| 102 | 110 | }; | 
| 103 | 111 | |
| 112 | + const handleCreateOrUpdatePublicApi = () => openPublicApiDrawer(true); | |
| 113 | + | |
| 104 | 114 | const { largeDesignerPrefix } = useGlobSetting(); | 
| 105 | 115 | |
| 106 | 116 | const handlePreview = (record: BigScreenCenterItemsModel) => { | 
| ... | ... | @@ -143,6 +153,19 @@ | 
| 143 | 153 | (listContainerEl.style.overflowY = 'auto') && | 
| 144 | 154 | (listContainerEl.style.overflowX = 'hidden'); | 
| 145 | 155 | }); | 
| 156 | + | |
| 157 | + const getPublicApiListData = () => {}; | |
| 158 | + | |
| 159 | + const handlePublish = async ({ id }) => { | |
| 160 | + await bigScreenPublish(id); | |
| 161 | + createMessage.success('发布成功'); | |
| 162 | + getListData(); | |
| 163 | + }; | |
| 164 | + const handleCancelPublish = async ({ id }) => { | |
| 165 | + await bigScreenCancelPublish(id); | |
| 166 | + createMessage.success('取消发布成功'); | |
| 167 | + getListData(); | |
| 168 | + }; | |
| 146 | 169 | </script> | 
| 147 | 170 | |
| 148 | 171 | <template> | 
| ... | ... | @@ -166,6 +189,9 @@ | 
| 166 | 189 | <Authority :value="ConfigurationPermission.CREATE"> | 
| 167 | 190 | <Button type="primary" @click="handleCreateOrUpdate()">新增大屏</Button> | 
| 168 | 191 | </Authority> | 
| 192 | + <Authority :value="ConfigurationPermission.CREATE"> | |
| 193 | + <Button type="primary" @click="handleCreateOrUpdatePublicApi()">公共接口管理</Button> | |
| 194 | + </Authority> | |
| 169 | 195 | <CardLayoutButton v-model:value="listColumn" @change="handleCardLayoutChange" /> | 
| 170 | 196 | <Tooltip title="刷新"> | 
| 171 | 197 | <Button type="primary" @click="getListData"> | 
| ... | ... | @@ -196,6 +222,11 @@ | 
| 196 | 222 | >所属组织:{{ item.organizationDTO.name }}</span | 
| 197 | 223 | > | 
| 198 | 224 | </div> | 
| 225 | + <div> | |
| 226 | + <span class="masker-text-state" | |
| 227 | + >发布状态:{{ item.state === 1 ? '已发布' : '未发布' }}</span | |
| 228 | + > | |
| 229 | + </div> | |
| 199 | 230 | </div> | 
| 200 | 231 | </div> | 
| 201 | 232 | </div> | 
| ... | ... | @@ -218,16 +249,33 @@ | 
| 218 | 249 | <AuthDropDown | 
| 219 | 250 | :dropMenuList="[ | 
| 220 | 251 | { | 
| 252 | + text: '发布', | |
| 253 | + auth: ConfigurationPermission.UPDATE, | |
| 254 | + icon: 'ant-design:node-expand-outlined', | |
| 255 | + event: '', | |
| 256 | + onClick: handlePublish.bind(null, item), | |
| 257 | + disabled: item.state === 0 ? false : true, | |
| 258 | + }, | |
| 259 | + { | |
| 260 | + text: '取消发布', | |
| 261 | + icon: 'ant-design:node-collapse-outlined', | |
| 262 | + event: '', | |
| 263 | + onClick: handleCancelPublish.bind(null, item), | |
| 264 | + disabled: item.state === 1 ? false : true, | |
| 265 | + }, | |
| 266 | + { | |
| 221 | 267 | text: '编辑', | 
| 222 | 268 | auth: ConfigurationPermission.UPDATE, | 
| 223 | 269 | icon: 'clarity:note-edit-line', | 
| 224 | 270 | event: '', | 
| 225 | 271 | onClick: handleCreateOrUpdate.bind(null, item), | 
| 272 | + disabled: item.state === 0 ? false : true, | |
| 226 | 273 | }, | 
| 227 | 274 | { | 
| 228 | 275 | text: '删除', | 
| 229 | 276 | auth: ConfigurationPermission.DELETE, | 
| 230 | 277 | icon: 'ant-design:delete-outlined', | 
| 278 | + disabled: item.state === 0 ? false : true, | |
| 231 | 279 | event: '', | 
| 232 | 280 | popconfirm: { | 
| 233 | 281 | title: '是否确认删除操作?', | 
| ... | ... | @@ -244,6 +292,7 @@ | 
| 244 | 292 | </List> | 
| 245 | 293 | </section> | 
| 246 | 294 | <ConfigurationCenterDrawer @register="registerDrawer" @success="getListData" /> | 
| 295 | + <PublicApiDrawer @register="registerPublicDrawer" @success="getPublicApiListData" /> | |
| 247 | 296 | </PageWrapper> | 
| 248 | 297 | </template> | 
| 249 | 298 | |
| ... | ... | @@ -298,6 +347,13 @@ | 
| 298 | 347 | bottom: 0; | 
| 299 | 348 | left: 0.8rem; | 
| 300 | 349 | } | 
| 350 | + | |
| 351 | + .masker-text-state { | |
| 352 | + font-size: 12px; | |
| 353 | + position: absolute; | |
| 354 | + bottom: 0; | |
| 355 | + right: 0.8rem; | |
| 356 | + } | |
| 301 | 357 | } | 
| 302 | 358 | } | 
| 303 | 359 | ... | ... | 
| 1 | +<template> | |
| 2 | + <div class="table-content"> | |
| 3 | + <!-- 采用的原生表格 --> | |
| 4 | + <table align="center"> | |
| 5 | + <thead> | |
| 6 | + <tr> | |
| 7 | + <th></th> | |
| 8 | + <th>内置参数</th> | |
| 9 | + <th>参数名</th> | |
| 10 | + <th>是否必须</th> | |
| 11 | + <th>操作</th> | |
| 12 | + </tr> | |
| 13 | + </thead> | |
| 14 | + <tbody> | |
| 15 | + <tr v-for="(item, index) in tableArray.content" :key="index"> | |
| 16 | + <td> | |
| 17 | + {{ index + 1 }} | |
| 18 | + </td> | |
| 19 | + <td> | |
| 20 | + <Select | |
| 21 | + v-model:value="item.key" | |
| 22 | + placeholder="请选择" | |
| 23 | + :options="selectOptions" | |
| 24 | + @change="handleChange" | |
| 25 | + allowClear | |
| 26 | + /> | |
| 27 | + </td> | |
| 28 | + <td> | |
| 29 | + <a-input | |
| 30 | + :disabled="item.editDisabled" | |
| 31 | + placeholder="请输入" | |
| 32 | + v-model:value="item.value" | |
| 33 | + /> | |
| 34 | + </td> | |
| 35 | + <td> | |
| 36 | + <a-switch v-model:checked="item.required" /> | |
| 37 | + </td> | |
| 38 | + <td> | |
| 39 | + <div> | |
| 40 | + <Button type="dashed" @click="add(item, index)"> | |
| 41 | + <template #icon><PlusOutlined /></template | |
| 42 | + ></Button> | |
| 43 | + <Button type="dashed" style="margin-left: 5px" @click="remove(item, index)"> | |
| 44 | + <template #icon> <MinusOutlined /></template> | |
| 45 | + </Button> | |
| 46 | + </div> | |
| 47 | + </td> | |
| 48 | + </tr> | |
| 49 | + </tbody> | |
| 50 | + </table> | |
| 51 | + </div> | |
| 52 | +</template> | |
| 53 | +<script lang="ts" setup name="editCellTable"> | |
| 54 | + import { reactive, ref, onMounted, nextTick } from 'vue'; | |
| 55 | + import { Select, Button } from 'ant-design-vue'; | |
| 56 | + import { findDictItemByCode } from '/@/api/system/dict'; | |
| 57 | + import { PlusOutlined, MinusOutlined } from '@ant-design/icons-vue'; | |
| 58 | + | |
| 59 | + defineProps({ | |
| 60 | + method: { | |
| 61 | + type: String, | |
| 62 | + }, | |
| 63 | + }); | |
| 64 | + | |
| 65 | + onMounted(() => { | |
| 66 | + getSelectOptions(); | |
| 67 | + }); | |
| 68 | + | |
| 69 | + const getSelectOptions = async () => { | |
| 70 | + const res = await findDictItemByCode({ dictCode: 'dataview_builtin_params' }); | |
| 71 | + selectOptions.value = res.map((m) => ({ label: m.itemText, value: m.itemValue })); | |
| 72 | + selectOptions.value.push({ | |
| 73 | + label: '自定义', | |
| 74 | + value: 'scope', | |
| 75 | + }); | |
| 76 | + }; | |
| 77 | + | |
| 78 | + const selectOptions = ref<{ label: string; value: string; disabled?: boolean }[]>([]); | |
| 79 | + | |
| 80 | + type defaultItem = { | |
| 81 | + key: null | string; | |
| 82 | + value: string; | |
| 83 | + editDisabled: boolean; | |
| 84 | + required: boolean; | |
| 85 | + }; | |
| 86 | + | |
| 87 | + const tableArray = reactive<{ | |
| 88 | + content: defaultItem[]; | |
| 89 | + }>({ | |
| 90 | + content: [ | |
| 91 | + { | |
| 92 | + key: null, | |
| 93 | + value: '', | |
| 94 | + editDisabled: false, | |
| 95 | + required: false, | |
| 96 | + }, | |
| 97 | + ], | |
| 98 | + }); | |
| 99 | + | |
| 100 | + // 新增 | |
| 101 | + const add = (_, index: number) => { | |
| 102 | + tableArray.content.splice(index + 1, 0, { | |
| 103 | + key: null, | |
| 104 | + value: '', | |
| 105 | + editDisabled: false, | |
| 106 | + required: false, | |
| 107 | + }); | |
| 108 | + }; | |
| 109 | + | |
| 110 | + // 减少 | |
| 111 | + const remove = (item, index: number) => { | |
| 112 | + if (tableArray.content.length !== 1) { | |
| 113 | + selectOptions.value.forEach((ele) => { | |
| 114 | + if (ele.value == item.key) { | |
| 115 | + ele.disabled = false; | |
| 116 | + } | |
| 117 | + }); | |
| 118 | + tableArray.content.splice(index, 1); | |
| 119 | + } | |
| 120 | + }; | |
| 121 | + | |
| 122 | + //Select互斥 | |
| 123 | + const handleChange = () => { | |
| 124 | + selectOptions.value.forEach((ele) => { | |
| 125 | + ele.disabled = false; | |
| 126 | + tableArray.content.forEach((element) => { | |
| 127 | + if (element.key === 'scope') { | |
| 128 | + element.editDisabled = false; | |
| 129 | + } else { | |
| 130 | + element.value = ''; | |
| 131 | + element.editDisabled = true; | |
| 132 | + } | |
| 133 | + if (element.key === ele.value && element.key !== 'scope') { | |
| 134 | + ele.disabled = true; | |
| 135 | + } | |
| 136 | + }); | |
| 137 | + }); | |
| 138 | + }; | |
| 139 | + | |
| 140 | + //获取数据 | |
| 141 | + const getValue = () => { | |
| 142 | + return tableArray.content; | |
| 143 | + }; | |
| 144 | + | |
| 145 | + //设置数据 | |
| 146 | + const setValue = (data) => { | |
| 147 | + nextTick(() => (tableArray.content = data)); | |
| 148 | + nextTick(() => | |
| 149 | + setTimeout(() => { | |
| 150 | + tableArray.content.forEach(() => { | |
| 151 | + handleChange(); | |
| 152 | + }); | |
| 153 | + }, 20) | |
| 154 | + ); | |
| 155 | + }; | |
| 156 | + | |
| 157 | + //重置数据 | |
| 158 | + const resetValue = () => { | |
| 159 | + tableArray.content = []; | |
| 160 | + tableArray.content.push({ | |
| 161 | + key: null, | |
| 162 | + value: '', | |
| 163 | + editDisabled: false, | |
| 164 | + required: false, | |
| 165 | + }); | |
| 166 | + nextTick(() => { | |
| 167 | + tableArray.content.forEach(() => { | |
| 168 | + handleChange(); | |
| 169 | + }); | |
| 170 | + }); | |
| 171 | + }; | |
| 172 | + defineExpose({ | |
| 173 | + getValue, | |
| 174 | + setValue, | |
| 175 | + resetValue, | |
| 176 | + }); | |
| 177 | +</script> | |
| 178 | + | |
| 179 | +<style scoped lang="less"> | |
| 180 | + @table-color: #e5e7eb; | |
| 181 | + | |
| 182 | + .table-border-color { | |
| 183 | + border: 1px solid #e5e7eb; | |
| 184 | + text-align: center; | |
| 185 | + } | |
| 186 | + | |
| 187 | + .table-content { | |
| 188 | + overflow-x: auto; | |
| 189 | + | |
| 190 | + table { | |
| 191 | + border-collapse: collapse; | |
| 192 | + width: 100%; | |
| 193 | + &:extend(.table-border-color); | |
| 194 | + } | |
| 195 | + | |
| 196 | + table td { | |
| 197 | + width: 7vw; | |
| 198 | + padding: 5px; | |
| 199 | + white-space: nowrap; | |
| 200 | + &:extend(.table-border-color); | |
| 201 | + } | |
| 202 | + | |
| 203 | + table th { | |
| 204 | + padding: 5px; | |
| 205 | + &:extend(.table-border-color); | |
| 206 | + } | |
| 207 | + } | |
| 208 | +</style> | ... | ... | 
| 1 | +<template> | |
| 2 | + <div> | |
| 3 | + <a-radio-group | |
| 4 | + v-model:value="getRequestBody.content.requestParamsBodyType" | |
| 5 | + @change="handleChange" | |
| 6 | + > | |
| 7 | + <a-radio v-for="item in RequestBodyTypeEnum" :key="item" :value="item">{{ item }}</a-radio> | |
| 8 | + </a-radio-group> | |
| 9 | + <div class="mt-3"> | |
| 10 | + <a-textarea | |
| 11 | + v-show="getRequestBody.content.requestParamsBodyType === 'none'" | |
| 12 | + disabled | |
| 13 | + placeholder="该接口没有 Body 体" | |
| 14 | + :rows="2" | |
| 15 | + /> | |
| 16 | + <EditCellTable | |
| 17 | + ref="editCellTableRef" | |
| 18 | + v-show=" | |
| 19 | + getRequestBody.content.requestParamsBodyType === 'form-data' || | |
| 20 | + getRequestBody.content.requestParamsBodyType === 'x-www-form-urlencoded' | |
| 21 | + " | |
| 22 | + /> | |
| 23 | + <a-textarea | |
| 24 | + v-model:value="getRequestBody.content.json" | |
| 25 | + v-show="getRequestBody.content.requestParamsBodyType === 'json'" | |
| 26 | + placeholder="请输入json" | |
| 27 | + :rows="6" | |
| 28 | + /> | |
| 29 | + <a-textarea | |
| 30 | + v-model:value="getRequestBody.content.xml" | |
| 31 | + v-show="getRequestBody.content.requestParamsBodyType === 'xml'" | |
| 32 | + placeholder="请输入xml" | |
| 33 | + :rows="6" | |
| 34 | + /> | |
| 35 | + </div> | |
| 36 | + </div> | |
| 37 | +</template> | |
| 38 | +<script lang="ts" setup name="body"> | |
| 39 | + import { reactive, ref, nextTick } from 'vue'; | |
| 40 | + import { RequestBodyTypeEnum } from '../../enum/index'; | |
| 41 | + import { EditCellTable } from '../EditCellTable/index'; | |
| 42 | + | |
| 43 | + defineProps({ | |
| 44 | + method: { | |
| 45 | + type: String, | |
| 46 | + }, | |
| 47 | + paramsType: { | |
| 48 | + type: String, | |
| 49 | + }, | |
| 50 | + data: { | |
| 51 | + type: Array, | |
| 52 | + }, | |
| 53 | + }); | |
| 54 | + | |
| 55 | + const getRequestBody = reactive({ | |
| 56 | + content: { | |
| 57 | + requestParamsBodyType: 'none', | |
| 58 | + json: '', | |
| 59 | + xml: '', | |
| 60 | + 'form-data': {}, | |
| 61 | + 'x-www-form-urlencoded': {}, | |
| 62 | + }, | |
| 63 | + }); | |
| 64 | + | |
| 65 | + const editCellTableRef = ref<InstanceType<typeof EditCellTable>>(); | |
| 66 | + | |
| 67 | + const handleChange = ({ target }) => { | |
| 68 | + const { value } = target; | |
| 69 | + getRequestBody.content.requestParamsBodyType = value; | |
| 70 | + }; | |
| 71 | + | |
| 72 | + //获取数据 | |
| 73 | + const getValue = () => { | |
| 74 | + const type = Reflect.get(getRequestBody.content, 'requestParamsBodyType'); | |
| 75 | + if (type === 'none') getRequestBody.content = {} as any; | |
| 76 | + const values = editCellTableRef.value?.getValue(); | |
| 77 | + if (type === 'form-data') getRequestBody.content['form-data'] = values as any; | |
| 78 | + if (type === 'x-www-form-urlencoded') | |
| 79 | + getRequestBody.content['x-www-form-urlencoded'] = values as any; | |
| 80 | + return getRequestBody.content; | |
| 81 | + }; | |
| 82 | + | |
| 83 | + //设置数据 | |
| 84 | + const setValue = (data) => { | |
| 85 | + nextTick(() => { | |
| 86 | + try { | |
| 87 | + if (!data) return; | |
| 88 | + const type = data?.requestParamsBodyType; | |
| 89 | + getRequestBody.content.requestParamsBodyType = type; | |
| 90 | + type === 'none' | |
| 91 | + ? null | |
| 92 | + : type === 'form-data' | |
| 93 | + ? editCellTableRef.value?.setValue(data['form-data']) | |
| 94 | + : type === 'x-www-form-urlencoded' | |
| 95 | + ? editCellTableRef.value?.setValue(data['x-www-form-urlencoded']) | |
| 96 | + : type === 'json' | |
| 97 | + ? (getRequestBody.content.json = data['json']) | |
| 98 | + : type === 'xml' | |
| 99 | + ? (getRequestBody.content.xml = data['xml']) | |
| 100 | + : ''; | |
| 101 | + } finally { | |
| 102 | + } | |
| 103 | + }); | |
| 104 | + }; | |
| 105 | + | |
| 106 | + //重置数据 | |
| 107 | + const resetValue = () => { | |
| 108 | + for (let i in getRequestBody.content) Reflect.set(getRequestBody.content, i, ''); | |
| 109 | + getRequestBody.content.requestParamsBodyType = 'none'; | |
| 110 | + nextTick(() => editCellTableRef?.value?.resetValue()); | |
| 111 | + }; | |
| 112 | + defineExpose({ | |
| 113 | + getValue, | |
| 114 | + setValue, | |
| 115 | + resetValue, | |
| 116 | + }); | |
| 117 | +</script> | ... | ... | 
| 1 | +<template> | |
| 2 | + <div> | |
| 3 | + <Tabs @change="handleChange" v-model:activeKey="activeKey"> | |
| 4 | + <TabPane class="tab-pane" forceRender key="Params" tab="Params"> | |
| 5 | + <EditCellTable ref="editCellTableRef" :method="method" /> | |
| 6 | + <TestRequest | |
| 7 | + @testInterface="handleTestInterface" | |
| 8 | + ref="testParRequestRef" | |
| 9 | + :method="method" | |
| 10 | + :data="dataList" | |
| 11 | + /> | |
| 12 | + </TabPane> | |
| 13 | + <TabPane | |
| 14 | + v-if="method !== '2' && paramsType !== 'GET'" | |
| 15 | + class="tab-pane" | |
| 16 | + forceRender | |
| 17 | + key="Body" | |
| 18 | + tab="Body" | |
| 19 | + > | |
| 20 | + <Body ref="bodyRef" :method="method" :paramsType="paramsType" :data="dataList" /> | |
| 21 | + <TestRequest | |
| 22 | + @testInterface="handleTestInterface" | |
| 23 | + ref="testBodyRequestRef" | |
| 24 | + :method="method" | |
| 25 | + :data="dataList" | |
| 26 | + /> | |
| 27 | + </TabPane> | |
| 28 | + <TabPane v-if="method !== '2'" class="tab-pane" forceRender key="Header" tab="Header"> | |
| 29 | + <EditCellTable ref="editHeaderCellTableRef" :method="method" /> | |
| 30 | + <TestRequest | |
| 31 | + @testInterface="handleTestInterface" | |
| 32 | + ref="testHeaderRequestRef" | |
| 33 | + :method="method" | |
| 34 | + :data="dataList" | |
| 35 | + /> | |
| 36 | + </TabPane> | |
| 37 | + </Tabs> | |
| 38 | + </div> | |
| 39 | +</template> | |
| 40 | +<script lang="ts" setup name="simpleRequest"> | |
| 41 | + import { ref, nextTick } from 'vue'; | |
| 42 | + import { Tabs, TabPane } from 'ant-design-vue'; | |
| 43 | + import { EditCellTable } from '../EditCellTable'; | |
| 44 | + import Body from './body.vue'; | |
| 45 | + import { TestRequest } from '../TestRequest/index'; | |
| 46 | + | |
| 47 | + defineProps({ | |
| 48 | + method: { | |
| 49 | + type: String, | |
| 50 | + }, | |
| 51 | + paramsType: { | |
| 52 | + type: String, | |
| 53 | + }, | |
| 54 | + }); | |
| 55 | + | |
| 56 | + const emits = defineEmits(['activeKey']); | |
| 57 | + | |
| 58 | + const activeKey = ref('Params'); | |
| 59 | + | |
| 60 | + const editCellTableRef = ref<InstanceType<typeof EditCellTable>>(); | |
| 61 | + | |
| 62 | + const editHeaderCellTableRef = ref<InstanceType<typeof EditCellTable>>(); | |
| 63 | + | |
| 64 | + const testParRequestRef = ref<InstanceType<typeof TestRequest>>(); | |
| 65 | + | |
| 66 | + const testBodyRequestRef = ref<InstanceType<typeof TestRequest>>(); | |
| 67 | + | |
| 68 | + const testHeaderRequestRef = ref<InstanceType<typeof TestRequest>>(); | |
| 69 | + | |
| 70 | + const dataList: any = ref(null); | |
| 71 | + | |
| 72 | + const bodyRef = ref<InstanceType<typeof Body>>(); | |
| 73 | + | |
| 74 | + const handleChange = () => { | |
| 75 | + testParRequestRef.value?.setValue(); | |
| 76 | + testHeaderRequestRef.value?.setValue(); | |
| 77 | + testBodyRequestRef.value?.setValue(); | |
| 78 | + }; | |
| 79 | + | |
| 80 | + const handleTestInterface = () => { | |
| 81 | + const value = getValue(false); | |
| 82 | + nextTick(() => (dataList.value = value)); | |
| 83 | + }; | |
| 84 | + | |
| 85 | + //获取数据 | |
| 86 | + const getValue = (status) => { | |
| 87 | + const type = activeKey.value; | |
| 88 | + const Body = bodyRef.value?.getValue(); | |
| 89 | + const Params = editCellTableRef.value?.getValue(); | |
| 90 | + const Header = editHeaderCellTableRef.value?.getValue(); | |
| 91 | + status ? emits('activeKey', type) : null; | |
| 92 | + return type === 'Params' ? Params : type === 'Body' ? Body : Header; | |
| 93 | + }; | |
| 94 | + | |
| 95 | + //设置数据 | |
| 96 | + const setValue = (data) => { | |
| 97 | + const Objects = JSON.parse(data?.requestParams); | |
| 98 | + nextTick(() => { | |
| 99 | + if (!Objects) return; | |
| 100 | + activeKey.value = Objects?.type; | |
| 101 | + if (activeKey.value === 'Params') { | |
| 102 | + editCellTableRef.value?.setValue(Objects?.Params); | |
| 103 | + testParRequestRef.value?.setValue(); | |
| 104 | + } else if (activeKey.value === 'Body') { | |
| 105 | + bodyRef.value?.setValue(Objects?.Body); | |
| 106 | + testBodyRequestRef.value?.setValue(); | |
| 107 | + } else if (activeKey.value === 'Header') { | |
| 108 | + editHeaderCellTableRef.value?.setValue(Objects?.Header); | |
| 109 | + testHeaderRequestRef.value?.setValue(); | |
| 110 | + } else { | |
| 111 | + } | |
| 112 | + }); | |
| 113 | + }; | |
| 114 | + | |
| 115 | + //重置数据 | |
| 116 | + const resetValue = () => { | |
| 117 | + activeKey.value = 'Params'; | |
| 118 | + nextTick(() => { | |
| 119 | + editCellTableRef.value?.resetValue(); | |
| 120 | + editHeaderCellTableRef.value?.resetValue(); | |
| 121 | + bodyRef.value?.resetValue(); | |
| 122 | + handleChange(); | |
| 123 | + }); | |
| 124 | + }; | |
| 125 | + | |
| 126 | + defineExpose({ | |
| 127 | + getValue, | |
| 128 | + setValue, | |
| 129 | + resetValue, | |
| 130 | + }); | |
| 131 | +</script> | |
| 132 | + | |
| 133 | +<style lang="less" scoped> | |
| 134 | + .tab-pane { | |
| 135 | + display: flex; | |
| 136 | + justify-content: flex-start; | |
| 137 | + flex-direction: column; | |
| 138 | + align-items: flex-start; | |
| 139 | + } | |
| 140 | +</style> | ... | ... | 
| 1 | +<template> | |
| 2 | + <div class="table-content"> | |
| 3 | + <table align="center" style="width: 100%" cellspacing="0"> | |
| 4 | + <thead> | |
| 5 | + <tr> | |
| 6 | + <th></th> | |
| 7 | + <th>内置参数</th> | |
| 8 | + <th>参数名</th> | |
| 9 | + </tr> | |
| 10 | + </thead> | |
| 11 | + <tbody> | |
| 12 | + <tr v-for="(item, index) in tableTestArray.content" :key="index"> | |
| 13 | + <td> | |
| 14 | + {{ index + 1 }} | |
| 15 | + </td> | |
| 16 | + <td> | |
| 17 | + <Select | |
| 18 | + :disabled="true" | |
| 19 | + v-model:value="item.key" | |
| 20 | + placeholder="请选择" | |
| 21 | + notFoundContent="请选择" | |
| 22 | + style="width: 14rem" | |
| 23 | + :options="selectOptions" | |
| 24 | + @change="handleChange(item)" | |
| 25 | + allowClear | |
| 26 | + /> | |
| 27 | + </td> | |
| 28 | + <td> | |
| 29 | + <a-input | |
| 30 | + v-if="item.key === 'scope'" | |
| 31 | + placeholder="请输入" | |
| 32 | + v-model:value="item.value" | |
| 33 | + style="width: 14rem" | |
| 34 | + /> | |
| 35 | + <a-tree-select | |
| 36 | + v-else-if="item.key === 'organizationId'" | |
| 37 | + v-model:value="item.value" | |
| 38 | + show-search | |
| 39 | + style="width: 14rem" | |
| 40 | + :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" | |
| 41 | + placeholder="请选择组织" | |
| 42 | + allow-clear | |
| 43 | + tree-default-expand-all | |
| 44 | + :tree-data="treeData" | |
| 45 | + @change="handleOrgnationChange(item)" | |
| 46 | + /> | |
| 47 | + <Select | |
| 48 | + v-else-if="item.key === 'entityId'" | |
| 49 | + v-model:value="item.value" | |
| 50 | + placeholder="请选择" | |
| 51 | + notFoundContent="请选择" | |
| 52 | + style="width: 14rem" | |
| 53 | + :options="entityOptions" | |
| 54 | + allowClear | |
| 55 | + /> | |
| 56 | + <Select | |
| 57 | + v-else-if="item.key === 'keys'" | |
| 58 | + v-model:value="item.value" | |
| 59 | + placeholder="请选择" | |
| 60 | + notFoundContent="请选择" | |
| 61 | + style="width: 14rem" | |
| 62 | + :options="attributeOptions" | |
| 63 | + allowClear | |
| 64 | + /> | |
| 65 | + <Select | |
| 66 | + v-else | |
| 67 | + v-model:value="item.value" | |
| 68 | + placeholder="请选择" | |
| 69 | + notFoundContent="请选择" | |
| 70 | + style="width: 14rem" | |
| 71 | + :options="valueOptions" | |
| 72 | + allowClear | |
| 73 | + @change="handleValueChange(item)" | |
| 74 | + /> | |
| 75 | + </td> | |
| 76 | + </tr> | |
| 77 | + </tbody> | |
| 78 | + </table> | |
| 79 | + </div> | |
| 80 | +</template> | |
| 81 | +<script lang="ts" setup name="editCellTable"> | |
| 82 | + import { reactive, ref, onMounted } from 'vue'; | |
| 83 | + import { Select } from 'ant-design-vue'; | |
| 84 | + import { findDictItemByCode } from '/@/api/system/dict'; | |
| 85 | + import { getAllDeviceByOrg } from '/@/api/dataBoard'; | |
| 86 | + import { getDeviceAttributes } from '/@/api/dataBoard'; | |
| 87 | + import { useApi } from '../../hooks/useApi'; | |
| 88 | + import { cloneDeep } from 'lodash-es'; | |
| 89 | + | |
| 90 | + const props = defineProps({ | |
| 91 | + method: { | |
| 92 | + type: String, | |
| 93 | + }, | |
| 94 | + }); | |
| 95 | + | |
| 96 | + onMounted(async () => { | |
| 97 | + const res = await findDictItemByCode({ dictCode: 'dataview_builtin_params' }); | |
| 98 | + selectOptions.value = res.map((m) => ({ label: m.itemText, value: m.itemValue })); | |
| 99 | + selectOptions.value.push({ | |
| 100 | + label: '自定义', | |
| 101 | + value: 'scope', | |
| 102 | + }); | |
| 103 | + if (props.method === '2') | |
| 104 | + selectOptions.value = selectOptions.value.filter((f) => f.value !== 'scope'); | |
| 105 | + }); | |
| 106 | + | |
| 107 | + const selectOptions = ref<{ label: string; value: string; disabled?: boolean }[]>([]); | |
| 108 | + | |
| 109 | + const valueOptions = ref<{ label: string; value: string; disabled?: boolean }[]>([]); | |
| 110 | + | |
| 111 | + const entityOptions = ref<{ label: string; value: string; disabled?: boolean }[]>([]); | |
| 112 | + | |
| 113 | + const attributeOptions = ref<{ label: string; value: string; disabled?: boolean }[]>([]); | |
| 114 | + | |
| 115 | + const treeData = ref([]); | |
| 116 | + | |
| 117 | + type defaultItem = { | |
| 118 | + key: null | string; | |
| 119 | + value: null | string; | |
| 120 | + editDisabled: boolean; | |
| 121 | + }; | |
| 122 | + | |
| 123 | + const tableTestArray = reactive<{ | |
| 124 | + content: defaultItem[]; | |
| 125 | + }>({ | |
| 126 | + content: [ | |
| 127 | + { | |
| 128 | + key: null, | |
| 129 | + value: null, | |
| 130 | + editDisabled: false, | |
| 131 | + }, | |
| 132 | + ], | |
| 133 | + }); | |
| 134 | + | |
| 135 | + //设置数据 | |
| 136 | + const setTableArray = (data) => { | |
| 137 | + const list = cloneDeep(data); | |
| 138 | + if (Array.isArray(list)) (tableTestArray.content = list) && getApi(list); | |
| 139 | + if (list.hasOwnProperty('form-data') && Array.isArray(list['form-data'])) | |
| 140 | + (tableTestArray.content = list['form-data']) && getApi(list['form-data']); | |
| 141 | + if ( | |
| 142 | + list.hasOwnProperty('x-www-form-urlencoded') && | |
| 143 | + Array.isArray(list['x-www-form-urlencoded']) | |
| 144 | + ) | |
| 145 | + (tableTestArray.content = list['x-www-form-urlencoded']) && | |
| 146 | + getApi(list['x-www-form-urlencoded']); | |
| 147 | + }; | |
| 148 | + | |
| 149 | + const getApi = (list) => { | |
| 150 | + list?.forEach(async (it) => { | |
| 151 | + if (it.key === 'deviceProfileId') { | |
| 152 | + const { options } = await useApi(it.key); | |
| 153 | + valueOptions.value = options; | |
| 154 | + } else if (it.key === 'organizationId') { | |
| 155 | + const { options } = await useApi(it.key); | |
| 156 | + treeData.value = options as any; | |
| 157 | + } | |
| 158 | + }); | |
| 159 | + }; | |
| 160 | + | |
| 161 | + //Select互斥 | |
| 162 | + const handleChange = async (e) => { | |
| 163 | + selectOptions.value.forEach((ele) => { | |
| 164 | + ele.disabled = false; | |
| 165 | + tableTestArray.content.forEach((element) => { | |
| 166 | + if (element.key === e.key && element.key !== 'scope') { | |
| 167 | + element.value = null; | |
| 168 | + } | |
| 169 | + if (element.key === ele.value && element.key !== 'scope') { | |
| 170 | + ele.disabled = true; | |
| 171 | + } | |
| 172 | + }); | |
| 173 | + }); | |
| 174 | + //获取对应项 | |
| 175 | + if (e.key === 'deviceProfileId') { | |
| 176 | + const { options } = await useApi(e.key); | |
| 177 | + valueOptions.value = options; | |
| 178 | + } else if (e.key === 'organizationId') { | |
| 179 | + const { options } = await useApi(e.key); | |
| 180 | + treeData.value = options as any; | |
| 181 | + } else if (e.key === 'entityId') { | |
| 182 | + const getOrganizationIds = tableTestArray.content | |
| 183 | + .map((f) => { | |
| 184 | + if (f.key === 'organizationId') { | |
| 185 | + return f.value; | |
| 186 | + } | |
| 187 | + }) | |
| 188 | + .filter(Boolean); | |
| 189 | + if (getOrganizationIds.length === 0) return; | |
| 190 | + getEntityOptions(getOrganizationIds?.at(-1)); | |
| 191 | + } else if (e.key === 'keys') { | |
| 192 | + const getIds = tableTestArray.content | |
| 193 | + .map((f) => { | |
| 194 | + if (f.key === 'deviceProfileId') { | |
| 195 | + return f.value; | |
| 196 | + } | |
| 197 | + }) | |
| 198 | + .filter(Boolean); | |
| 199 | + if (getIds.length === 0) return; | |
| 200 | + getAttributeOptions({ deviceProfileId: getIds?.at(-1) }); | |
| 201 | + } else if (e.key === 'date') { | |
| 202 | + valueOptions.value = []; | |
| 203 | + } | |
| 204 | + }; | |
| 205 | + | |
| 206 | + const handleOrgnationChange = async (e) => { | |
| 207 | + tableTestArray.content.forEach((f) => { | |
| 208 | + if (f.key === 'entityId') { | |
| 209 | + f.value = null; | |
| 210 | + } | |
| 211 | + }); | |
| 212 | + getEntityOptions(e.value); | |
| 213 | + }; | |
| 214 | + | |
| 215 | + const getEntityOptions = async (organizationId: string, deviceProfileId?: string) => { | |
| 216 | + const res = await getAllDeviceByOrg(organizationId, deviceProfileId); | |
| 217 | + entityOptions.value = res.map((item) => ({ | |
| 218 | + label: item.name, | |
| 219 | + value: item.tbDeviceId, | |
| 220 | + })); | |
| 221 | + }; | |
| 222 | + | |
| 223 | + const getAttributeOptions = async (params) => { | |
| 224 | + const res = await getDeviceAttributes(params); | |
| 225 | + if (Object.keys(res).length === 0) return (attributeOptions.value.length = 0); | |
| 226 | + attributeOptions.value = res?.map((item) => ({ label: item.name, value: item.identifier })); | |
| 227 | + }; | |
| 228 | + | |
| 229 | + const handleValueChange = (e) => { | |
| 230 | + if (e.key === 'deviceProfileId') { | |
| 231 | + tableTestArray.content.forEach((f) => { | |
| 232 | + if (f.key === 'keys') { | |
| 233 | + f.value = null; | |
| 234 | + } | |
| 235 | + }); | |
| 236 | + getAttributeOptions({ deviceProfileId: e.value }); | |
| 237 | + } | |
| 238 | + }; | |
| 239 | + | |
| 240 | + //获取数据 | |
| 241 | + const getValue = () => { | |
| 242 | + return tableTestArray.content; | |
| 243 | + }; | |
| 244 | + defineExpose({ | |
| 245 | + getValue, | |
| 246 | + setTableArray, | |
| 247 | + }); | |
| 248 | +</script> | |
| 249 | + | |
| 250 | +<style scoped lang="less"> | |
| 251 | + @table-color: #e5e7eb; | |
| 252 | + | |
| 253 | + .table-border-color { | |
| 254 | + border: 1px solid #e5e7eb; | |
| 255 | + text-align: center; | |
| 256 | + } | |
| 257 | + | |
| 258 | + .table-content { | |
| 259 | + table { | |
| 260 | + &:extend(.table-border-color); | |
| 261 | + } | |
| 262 | + | |
| 263 | + table td { | |
| 264 | + width: 7vw; | |
| 265 | + padding: 5px; | |
| 266 | + white-space: nowrap; | |
| 267 | + &:extend(.table-border-color); | |
| 268 | + } | |
| 269 | + | |
| 270 | + table th { | |
| 271 | + padding: 5px; | |
| 272 | + &:extend(.table-border-color); | |
| 273 | + } | |
| 274 | + } | |
| 275 | +</style> | ... | ... | 
| 1 | +<template> | |
| 2 | + <div> | |
| 3 | + <div class="mt-8"> | |
| 4 | + <div> | |
| 5 | + <Button @click="handleTest" type="primary"> 测试接口 </Button> | |
| 6 | + </div> | |
| 7 | + <div v-if="showTestEditCell" class="mt-8"> | |
| 8 | + <a-row type="flex" justify="center"> | |
| 9 | + <a-col :span="3"> 参数设置 </a-col> | |
| 10 | + <a-col :span="21"> | |
| 11 | + <TestEditCellTable ref="testEditCellTableRef" :method="method" /> | |
| 12 | + </a-col> | |
| 13 | + </a-row> | |
| 14 | + </div> | |
| 15 | + </div> | |
| 16 | + <div v-if="showTestEditCell" class="mt-8"> | |
| 17 | + <div> | |
| 18 | + <Button @click="handleExcute" type="primary"> 执行 </Button> | |
| 19 | + </div> | |
| 20 | + <div class="mt-8"> | |
| 21 | + <a-row type="flex" justify="center"> | |
| 22 | + <a-col :span="3"> 测试结果 </a-col> | |
| 23 | + <a-col :span="21"> | |
| 24 | + <a-textarea | |
| 25 | + allow-clear | |
| 26 | + show-count | |
| 27 | + v-model:value="testResult" | |
| 28 | + placeholder="测试结果为:" | |
| 29 | + :rows="8" | |
| 30 | + /> | |
| 31 | + </a-col> | |
| 32 | + </a-row> | |
| 33 | + </div> | |
| 34 | + </div> | |
| 35 | + </div> | |
| 36 | +</template> | |
| 37 | +<script lang="ts" setup name="testRequest"> | |
| 38 | + import { ref, nextTick } from 'vue'; | |
| 39 | + import { Button } from 'ant-design-vue'; | |
| 40 | + import { TestEditCellTable } from '../TestEditCellTable/index'; | |
| 41 | + import { getAllDeviceByOrg } from '/@/api/dataBoard'; | |
| 42 | + import { getDeviceAttributes } from '/@/api/dataBoard'; | |
| 43 | + | |
| 44 | + const emits = defineEmits(['testInterface']); | |
| 45 | + | |
| 46 | + const props = defineProps({ | |
| 47 | + method: { | |
| 48 | + type: String, | |
| 49 | + }, | |
| 50 | + data: { | |
| 51 | + type: Array, | |
| 52 | + }, | |
| 53 | + }); | |
| 54 | + | |
| 55 | + const showTestEditCell = ref(false); | |
| 56 | + | |
| 57 | + const testEditCellTableRef = ref<InstanceType<typeof TestEditCellTable>>(); | |
| 58 | + | |
| 59 | + const testResult = ref(''); | |
| 60 | + | |
| 61 | + // const testNeedKeys = ['organizationId', 'deviceProfileId', 'entityId', 'keys', 'date']; | |
| 62 | + | |
| 63 | + const handleTest = () => { | |
| 64 | + showTestEditCell.value = true; | |
| 65 | + emits('testInterface'); | |
| 66 | + getValue(); | |
| 67 | + }; | |
| 68 | + | |
| 69 | + const getValue = async () => { | |
| 70 | + await nextTick(); | |
| 71 | + await nextTick(() => { | |
| 72 | + testEditCellTableRef.value?.setTableArray(props.data); | |
| 73 | + }); | |
| 74 | + }; | |
| 75 | + | |
| 76 | + const handleExcute = async () => { | |
| 77 | + const params = testEditCellTableRef.value?.getValue(); | |
| 78 | + const keys = params?.map((m) => ({ key: m.key, value: m.value })); | |
| 79 | + keys?.forEach(async (it: any) => { | |
| 80 | + if (it.key === 'organizationId') { | |
| 81 | + //获取设备 | |
| 82 | + const data = await getAllDeviceByOrg(it.value!); | |
| 83 | + testResult.value = JSON.stringify(data); | |
| 84 | + } | |
| 85 | + if (it.key === 'deviceProfileId') { | |
| 86 | + //获取属性 | |
| 87 | + const data = await getDeviceAttributes({ deviceProfileId: it.value! }); | |
| 88 | + testResult.value = JSON.stringify(data); | |
| 89 | + } | |
| 90 | + }); | |
| 91 | + }; | |
| 92 | + | |
| 93 | + //设置数据 | |
| 94 | + const setValue = () => { | |
| 95 | + showTestEditCell.value = false; | |
| 96 | + testResult.value = ''; | |
| 97 | + }; | |
| 98 | + defineExpose({ | |
| 99 | + setValue, | |
| 100 | + handleTest, | |
| 101 | + }); | |
| 102 | +</script> | |
| 103 | + | |
| 104 | +<style scoped lang="less"></style> | ... | ... | 
| 1 | +<template> | |
| 2 | + <div class="mt-8"> | |
| 3 | + <div> | |
| 4 | + <Button @click="handleExcute" type="primary"> 测试SQL </Button> | |
| 5 | + </div> | |
| 6 | + </div> | |
| 7 | + <div v-if="testResultStatus" class="mt-8"> | |
| 8 | + <div class="mt-8"> | |
| 9 | + <a-row type="flex" justify="center"> | |
| 10 | + <a-col :span="3"> 测试结果 </a-col> | |
| 11 | + <a-col :span="21"> | |
| 12 | + <a-textarea | |
| 13 | + allow-clear | |
| 14 | + show-count | |
| 15 | + v-model:value="testResult" | |
| 16 | + placeholder="测试结果为:" | |
| 17 | + :rows="8" | |
| 18 | + /> | |
| 19 | + </a-col> | |
| 20 | + </a-row> | |
| 21 | + </div> | |
| 22 | + </div> | |
| 23 | +</template> | |
| 24 | +<script lang="ts" setup name="testRequest"> | |
| 25 | + import { ref } from 'vue'; | |
| 26 | + import { Button } from 'ant-design-vue'; | |
| 27 | + | |
| 28 | + defineProps({ | |
| 29 | + method: { | |
| 30 | + type: String, | |
| 31 | + }, | |
| 32 | + }); | |
| 33 | + | |
| 34 | + const testResult = ref(''); | |
| 35 | + | |
| 36 | + const testResultStatus = ref(false); | |
| 37 | + | |
| 38 | + const handleExcute = async () => { | |
| 39 | + testResultStatus.value = true; | |
| 40 | + testResult.value = '测试结果为:1234'; | |
| 41 | + }; | |
| 42 | + | |
| 43 | + const resetValue = () => (testResult.value = ''); | |
| 44 | + | |
| 45 | + defineExpose({ | |
| 46 | + resetValue, | |
| 47 | + }); | |
| 48 | +</script> | |
| 49 | + | |
| 50 | +<style scoped lang="less"></style> | ... | ... | 
src/views/dataview/publicApi/config.ts
0 → 100644
| 1 | +import { BasicColumn, FormSchema } from '/@/components/Table'; | |
| 2 | +import { h } from 'vue'; | |
| 3 | +import { Tag } from 'ant-design-vue'; | |
| 4 | +import { findDictItemByCode } from '/@/api/system/dict'; | |
| 5 | + | |
| 6 | +// 表格配置 | |
| 7 | +export const columns: BasicColumn[] = [ | |
| 8 | + { | |
| 9 | + title: '接口名称', | |
| 10 | + dataIndex: 'interfaceName', | |
| 11 | + width: 150, | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + title: '请求方式', | |
| 15 | + dataIndex: 'requestContentType', | |
| 16 | + width: 90, | |
| 17 | + format(text) { | |
| 18 | + return Number(text) === 0 ? '普通请求' : Number(text) === 1 ? 'SQL请求' : 'websocket请求'; | |
| 19 | + }, | |
| 20 | + }, | |
| 21 | + { | |
| 22 | + title: '接口内容', | |
| 23 | + dataIndex: 'content', | |
| 24 | + width: 80, | |
| 25 | + slots: { customRender: 'content' }, | |
| 26 | + }, | |
| 27 | + { | |
| 28 | + title: '状态', | |
| 29 | + dataIndex: 'state', | |
| 30 | + width: 80, | |
| 31 | + customRender: ({ record }) => { | |
| 32 | + const status = record.state; | |
| 33 | + const color = status == 1 ? 'green' : 'red'; | |
| 34 | + const text = status == 1 ? '发布' : '未发布'; | |
| 35 | + return h(Tag, { color: color }, () => text); | |
| 36 | + }, | |
| 37 | + }, | |
| 38 | +]; | |
| 39 | + | |
| 40 | +// 查询配置 | |
| 41 | +export const searchFormSchema: FormSchema[] = [ | |
| 42 | + { | |
| 43 | + field: 'name', | |
| 44 | + label: '接口名称', | |
| 45 | + component: 'Input', | |
| 46 | + colProps: { span: 8 }, | |
| 47 | + componentProps: { | |
| 48 | + maxLength: 36, | |
| 49 | + placeholder: '请输入接口名称', | |
| 50 | + }, | |
| 51 | + }, | |
| 52 | + { | |
| 53 | + field: 'state', | |
| 54 | + label: '发布状态', | |
| 55 | + component: 'Select', | |
| 56 | + colProps: { span: 8 }, | |
| 57 | + componentProps: { | |
| 58 | + options: [ | |
| 59 | + { | |
| 60 | + label: '发布', | |
| 61 | + value: 1, | |
| 62 | + }, | |
| 63 | + { | |
| 64 | + label: '未发布', | |
| 65 | + value: 0, | |
| 66 | + }, | |
| 67 | + ], | |
| 68 | + placeholder: '请选择发布状态', | |
| 69 | + }, | |
| 70 | + }, | |
| 71 | +]; | |
| 72 | + | |
| 73 | +//表单配置 | |
| 74 | +export const schemas: FormSchema[] = [ | |
| 75 | + { | |
| 76 | + field: 'interfaceName', | |
| 77 | + label: '接口名称', | |
| 78 | + colProps: { span: 24 }, | |
| 79 | + required: true, | |
| 80 | + component: 'Input', | |
| 81 | + componentProps: { | |
| 82 | + maxLength: 64, | |
| 83 | + placeholder: '请输入接口名称', | |
| 84 | + }, | |
| 85 | + }, | |
| 86 | + { | |
| 87 | + field: 'requestContentType', | |
| 88 | + label: '请求方式', | |
| 89 | + component: 'ApiSelect', | |
| 90 | + required: true, | |
| 91 | + colProps: { span: 24 }, | |
| 92 | + defaultValue: '0', | |
| 93 | + componentProps: ({ formActionType }) => { | |
| 94 | + const { setFieldsValue, updateSchema } = formActionType; | |
| 95 | + return { | |
| 96 | + api: findDictItemByCode, | |
| 97 | + params: { | |
| 98 | + dictCode: 'dataview_select_methods', | |
| 99 | + }, | |
| 100 | + placeholder: '请选择请求方式', | |
| 101 | + labelField: 'itemText', | |
| 102 | + valueField: 'itemValue', | |
| 103 | + getPopupContainer: () => document.body, | |
| 104 | + async onChange(e) { | |
| 105 | + setFieldsValue({ requestHttpType: e === '1' ? 'POST' : 'GET' }); | |
| 106 | + const res = await findDictItemByCode({ | |
| 107 | + dictCode: e === '1' ? 'dataview_select_sql_request' : 'dataview_select_request', | |
| 108 | + }); | |
| 109 | + const options = res.map((m) => ({ label: m.itemText, value: m.itemValue })); | |
| 110 | + updateSchema({ | |
| 111 | + field: 'requestHttpType', | |
| 112 | + componentProps: { | |
| 113 | + options, | |
| 114 | + }, | |
| 115 | + }); | |
| 116 | + }, | |
| 117 | + }; | |
| 118 | + }, | |
| 119 | + }, | |
| 120 | + { | |
| 121 | + field: 'requestOriginUrl', | |
| 122 | + label: '源地址', | |
| 123 | + colProps: { span: 24 }, | |
| 124 | + required: true, | |
| 125 | + component: 'Input', | |
| 126 | + componentProps: { | |
| 127 | + maxLength: 64, | |
| 128 | + placeholder: '请输入源地址', | |
| 129 | + }, | |
| 130 | + }, | |
| 131 | + { | |
| 132 | + field: 'requestHttpType', | |
| 133 | + label: '请求类型', | |
| 134 | + component: 'ApiSelect', | |
| 135 | + required: true, | |
| 136 | + colProps: { span: 6 }, | |
| 137 | + defaultValue: 'GET', | |
| 138 | + componentProps: { | |
| 139 | + placeholder: '请选择请求类型', | |
| 140 | + api: findDictItemByCode, | |
| 141 | + params: { | |
| 142 | + dictCode: 'dataview_select_request', | |
| 143 | + }, | |
| 144 | + labelField: 'itemText', | |
| 145 | + valueField: 'itemValue', | |
| 146 | + }, | |
| 147 | + ifShow: ({ values }) => | |
| 148 | + values['requestContentType'] === '0' || values['requestContentType'] === '1', | |
| 149 | + }, | |
| 150 | + { | |
| 151 | + field: 'requestUrl', | |
| 152 | + label: '', | |
| 153 | + component: 'Input', | |
| 154 | + required: true, | |
| 155 | + colProps: { span: 18 }, | |
| 156 | + componentProps: { | |
| 157 | + maxLength: 64, | |
| 158 | + placeholder: '请输入接口地址', | |
| 159 | + }, | |
| 160 | + ifShow: ({ values }) => | |
| 161 | + values['requestContentType'] === '0' || values['requestContentType'] === '1', | |
| 162 | + }, | |
| 163 | + { | |
| 164 | + field: 'requestSQLKey', | |
| 165 | + label: '键名', | |
| 166 | + colProps: { span: 12 }, | |
| 167 | + component: 'Input', | |
| 168 | + defaultValue: 'sql', | |
| 169 | + componentProps: { | |
| 170 | + disabled: true, | |
| 171 | + }, | |
| 172 | + ifShow: ({ values }) => values['requestContentType'] === '1', | |
| 173 | + }, | |
| 174 | + { | |
| 175 | + field: 'requestSQLContent', | |
| 176 | + label: '键值', | |
| 177 | + colProps: { span: 24 }, | |
| 178 | + component: 'InputTextArea', | |
| 179 | + defaultValue: 'select * from where', | |
| 180 | + componentProps: { | |
| 181 | + maxLength: 255, | |
| 182 | + placeholder: '请输入键值', | |
| 183 | + rows: 6, | |
| 184 | + }, | |
| 185 | + ifShow: ({ values }) => values['requestContentType'] === '1', | |
| 186 | + }, | |
| 187 | + { | |
| 188 | + field: 'slot', | |
| 189 | + label: '参数设置', | |
| 190 | + component: 'Input', | |
| 191 | + slot: 'selectMethods', | |
| 192 | + colProps: { span: 24 }, | |
| 193 | + ifShow: ({ values }) => values['requestContentType'] !== '1', | |
| 194 | + }, | |
| 195 | + { | |
| 196 | + field: 'testSlot', | |
| 197 | + label: '', | |
| 198 | + component: 'Input', | |
| 199 | + slot: 'testSql', | |
| 200 | + colProps: { span: 24 }, | |
| 201 | + ifShow: ({ values }) => values['requestContentType'] === '1', | |
| 202 | + }, | |
| 203 | +]; | ... | ... | 
src/views/dataview/publicApi/enum/index.ts
0 → 100644
| 1 | +/** | |
| 2 | + * @description: 请求参数类型 | |
| 3 | + */ | |
| 4 | +export enum RequestParamsTypeEnum { | |
| 5 | + PARAMS = 'Params', | |
| 6 | + BODY = 'Body', | |
| 7 | + HEADER = 'Header', | |
| 8 | +} | |
| 9 | + | |
| 10 | +/** | |
| 11 | + * @description: 请求体类型 | |
| 12 | + */ | |
| 13 | +export enum RequestBodyTypeEnum { | |
| 14 | + NONE = 'none', | |
| 15 | + FORMDATA = 'form-data', | |
| 16 | + XWWW = 'x-www-form-urlencoded', | |
| 17 | + JSON = 'json', | |
| 18 | + XML = 'xml', | |
| 19 | +} | ... | ... | 
src/views/dataview/publicApi/form.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div> | |
| 3 | + <BasicDrawer | |
| 4 | + showFooter | |
| 5 | + v-bind="$attrs" | |
| 6 | + @register="registerDrawer" | |
| 7 | + width="45%" | |
| 8 | + @ok="handleOnSubmit" | |
| 9 | + > | |
| 10 | + <BasicForm @register="registerForm"> | |
| 11 | + <template #selectMethods="{ model }"> | |
| 12 | + <SimpleRequest | |
| 13 | + ref="simpleRequestRef" | |
| 14 | + v-if="model['requestContentType'] === '0'" | |
| 15 | + @activeKey="handleActiveKey" | |
| 16 | + :paramsType="model['requestHttpType']" | |
| 17 | + :method="model['requestContentType']" | |
| 18 | + /> | |
| 19 | + <SimpleRequest | |
| 20 | + ref="simpleRequestRef" | |
| 21 | + @activeKey="handleActiveKey" | |
| 22 | + v-else-if="model['requestContentType'] === '2'" | |
| 23 | + :paramsType="model['requestHttpType']" | |
| 24 | + :method="model['requestContentType']" | |
| 25 | + /> | |
| 26 | + </template> | |
| 27 | + <template #testSql="{ model }"> | |
| 28 | + <div style="margin: auto 7.5rem"> | |
| 29 | + <TestSql | |
| 30 | + ref="testSqlRef" | |
| 31 | + v-if="model['requestContentType'] === '1'" | |
| 32 | + :method="model['requestContentType']" | |
| 33 | + /> | |
| 34 | + </div> | |
| 35 | + </template> | |
| 36 | + </BasicForm> | |
| 37 | + </BasicDrawer> | |
| 38 | + </div> | |
| 39 | +</template> | |
| 40 | +<script lang="ts" setup name="publicApi"> | |
| 41 | + import { ref, nextTick } from 'vue'; | |
| 42 | + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; | |
| 43 | + import { BasicForm, useForm } from '/@/components/Form'; | |
| 44 | + import { schemas } from './config'; | |
| 45 | + import SimpleRequest from './components/SimpleRequest/index.vue'; | |
| 46 | + import { TestSql } from './components/TestSql/index'; | |
| 47 | + import { | |
| 48 | + saveDataViewInterface, | |
| 49 | + updateDataViewInterface, | |
| 50 | + } from '/@/api/bigscreen/center/bigscreenCenter'; | |
| 51 | + import { useMessage } from '/@/hooks/web/useMessage'; | |
| 52 | + import { findDictItemByCode } from '/@/api/system/dict'; | |
| 53 | + | |
| 54 | + const emits = defineEmits(['success', 'register']); | |
| 55 | + | |
| 56 | + const { createMessage } = useMessage(); | |
| 57 | + | |
| 58 | + const isUpdate = ref(false); | |
| 59 | + | |
| 60 | + const putId = ref(''); | |
| 61 | + | |
| 62 | + const activeKey = ref(''); | |
| 63 | + | |
| 64 | + const simpleRequestRef = ref<InstanceType<typeof SimpleRequest>>(); | |
| 65 | + | |
| 66 | + const testSqlRef = ref<InstanceType<typeof TestSql>>(); | |
| 67 | + | |
| 68 | + const [registerForm, { resetFields, validate, setFieldsValue, updateSchema }] = useForm({ | |
| 69 | + labelWidth: 120, | |
| 70 | + schemas, | |
| 71 | + showActionButtonGroup: false, | |
| 72 | + }); | |
| 73 | + | |
| 74 | + const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => { | |
| 75 | + setDrawerProps({ loading: true }); | |
| 76 | + await nextTick(); | |
| 77 | + await resetFields(); | |
| 78 | + await nextTick(() => simpleRequestRef.value?.resetValue()); | |
| 79 | + await nextTick(() => testSqlRef.value?.resetValue()); | |
| 80 | + const title = `${!data.isUpdate ? '新增' : '修改'}公共接口`; | |
| 81 | + setDrawerProps({ title }); | |
| 82 | + isUpdate.value = data.isUpdate; | |
| 83 | + !isUpdate.value ? (putId.value = '') : (putId.value = data.record.id); | |
| 84 | + if (isUpdate.value) { | |
| 85 | + await setFieldsValue({ | |
| 86 | + ...data.record, | |
| 87 | + requestContentType: String(data.record?.requestContentType), | |
| 88 | + requestSQLContent: JSON.parse(data.record?.requestParams)?.requestSQLContent?.sql, | |
| 89 | + }); | |
| 90 | + await nextTick(() => | |
| 91 | + setTimeout(() => { | |
| 92 | + simpleRequestRef.value?.setValue(data.record); | |
| 93 | + }, 200) | |
| 94 | + ); | |
| 95 | + const res = await findDictItemByCode({ | |
| 96 | + dictCode: | |
| 97 | + data.record?.requestContentType === 1 | |
| 98 | + ? 'dataview_select_sql_request' | |
| 99 | + : 'dataview_select_request', | |
| 100 | + }); | |
| 101 | + const options = res.map((m) => ({ label: m.itemText, value: m.itemValue })); | |
| 102 | + updateSchema({ | |
| 103 | + field: 'requestHttpType', | |
| 104 | + componentProps: { | |
| 105 | + options, | |
| 106 | + }, | |
| 107 | + }); | |
| 108 | + } | |
| 109 | + setDrawerProps({ loading: false }); | |
| 110 | + }); | |
| 111 | + | |
| 112 | + const handleActiveKey = (v) => (activeKey.value = v); | |
| 113 | + | |
| 114 | + const handleOnSubmit = async () => { | |
| 115 | + setDrawerProps({ loading: true }); | |
| 116 | + try { | |
| 117 | + const values = await validate(); | |
| 118 | + if (!values) return; | |
| 119 | + const Objects = simpleRequestRef.value?.getValue(true); | |
| 120 | + const data = { | |
| 121 | + ...values, | |
| 122 | + id: !putId.value ? null : putId.value, | |
| 123 | + requestParams: JSON.stringify({ | |
| 124 | + requestSQLContent: { | |
| 125 | + sql: values?.requestSQLContent, | |
| 126 | + }, | |
| 127 | + type: activeKey.value, | |
| 128 | + Params: activeKey.value === 'Params' ? Objects : {}, | |
| 129 | + Body: activeKey.value === 'Body' ? Objects : {}, | |
| 130 | + Header: activeKey.value === 'Header' ? Objects : {}, | |
| 131 | + }), | |
| 132 | + }; | |
| 133 | + !putId.value ? await saveDataViewInterface(data) : await updateDataViewInterface(data); | |
| 134 | + emits('success'); | |
| 135 | + closeDrawer(); | |
| 136 | + createMessage.success(`${!isUpdate.value ? '新增' : '修改'}成功`); | |
| 137 | + } finally { | |
| 138 | + setDrawerProps({ loading: false }); | |
| 139 | + } | |
| 140 | + }; | |
| 141 | +</script> | ... | ... | 
src/views/dataview/publicApi/hooks/useApi.ts
0 → 100644
| 1 | +import { ref } from 'vue'; | |
| 2 | +import { deviceProfile } from '/@/api/device/deviceManager'; | |
| 3 | +import { getOrganizationList } from '/@/api/system/system'; | |
| 4 | +// import { copyTransFun } from '/@/utils/fnUtils'; | |
| 5 | +// import { getAllDeviceByOrg } from '/@/api/dataBoard'; | |
| 6 | +// import { getDeviceAttributes } from '/@/api/dataBoard'; | |
| 7 | +import { copyTransFun } from '/@/utils/fnUtils'; | |
| 8 | + | |
| 9 | +export const useApi = async (key) => { | |
| 10 | + const options = ref<{ label: string; value: string; disabled?: boolean }[]>([]); | |
| 11 | + switch (key) { | |
| 12 | + case 'deviceProfileId': | |
| 13 | + const res = await deviceProfile(); | |
| 14 | + options.value = res?.map((m) => ({ label: m.name, value: m.id })); | |
| 15 | + break; | |
| 16 | + case 'organizationId': | |
| 17 | + const data = await getOrganizationList(); | |
| 18 | + copyTransFun(data as never as any); | |
| 19 | + options.value = data as any; | |
| 20 | + } | |
| 21 | + | |
| 22 | + return { options: options.value }; | |
| 23 | +}; | ... | ... | 
src/views/dataview/publicApi/index.ts
0 → 100644
src/views/dataview/publicApi/index.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div> | |
| 3 | + <BasicDrawer v-bind="$attrs" @register="registerDrawer" title="公共接口管理页" width="50%"> | |
| 4 | + <PublicApiList /> | |
| 5 | + </BasicDrawer> | |
| 6 | + </div> | |
| 7 | +</template> | |
| 8 | +<script lang="ts" setup name="publicApi"> | |
| 9 | + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; | |
| 10 | + import { PublicApiList } from './index'; | |
| 11 | + | |
| 12 | + const [registerDrawer] = useDrawerInner(); | |
| 13 | +</script> | ... | ... | 
src/views/dataview/publicApi/list.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div> | |
| 3 | + <BasicTable @register="registerTable"> | |
| 4 | + <template #content="{ record }"> | |
| 5 | + <a-button type="link" class="ml-2" @click="handleRecordContent(record)"> 查看 </a-button> | |
| 6 | + </template> | |
| 7 | + <template #toolbar> | |
| 8 | + <a-button type="primary" @click="handleCreateOrEdit(null)"> 新增公共接口 </a-button> | |
| 9 | + <Popconfirm | |
| 10 | + title="您确定要批量删除数据" | |
| 11 | + ok-text="确定" | |
| 12 | + cancel-text="取消" | |
| 13 | + @confirm="handleDeleteOrBatchDelete(null)" | |
| 14 | + > | |
| 15 | + <a-button color="error" :disabled="hasBatchDelete"> 批量删除 </a-button> | |
| 16 | + </Popconfirm> | |
| 17 | + </template> | |
| 18 | + <template #action="{ record }"> | |
| 19 | + <TableAction | |
| 20 | + :actions="[ | |
| 21 | + { | |
| 22 | + label: '发布', | |
| 23 | + icon: 'ant-design:node-expand-outlined', | |
| 24 | + onClick: handlePublish.bind(null, record), | |
| 25 | + ifShow: () => { | |
| 26 | + return record.state === 0; | |
| 27 | + }, | |
| 28 | + }, | |
| 29 | + { | |
| 30 | + label: '取消发布', | |
| 31 | + icon: 'ant-design:node-collapse-outlined', | |
| 32 | + onClick: handleCancelPublish.bind(null, record), | |
| 33 | + ifShow: () => { | |
| 34 | + return record.state === 1; | |
| 35 | + }, | |
| 36 | + }, | |
| 37 | + { | |
| 38 | + label: '修改', | |
| 39 | + icon: 'clarity:note-edit-line', | |
| 40 | + onClick: handleCreateOrEdit.bind(null, record), | |
| 41 | + ifShow: () => { | |
| 42 | + return record.state === 0; | |
| 43 | + }, | |
| 44 | + }, | |
| 45 | + { | |
| 46 | + label: '删除', | |
| 47 | + icon: 'ant-design:delete-outlined', | |
| 48 | + color: 'error', | |
| 49 | + ifShow: () => { | |
| 50 | + return record.state === 0; | |
| 51 | + }, | |
| 52 | + popConfirm: { | |
| 53 | + title: '是否确认删除', | |
| 54 | + confirm: handleDeleteOrBatchDelete.bind(null, record), | |
| 55 | + }, | |
| 56 | + }, | |
| 57 | + ]" | |
| 58 | + /> | |
| 59 | + </template> | |
| 60 | + </BasicTable> | |
| 61 | + </div> | |
| 62 | + <PublicApiForm @register="registerDrawer" @success="handleSuccess" /> | |
| 63 | +</template> | |
| 64 | +<script lang="ts" setup name="list"> | |
| 65 | + import { nextTick, h } from 'vue'; | |
| 66 | + import { BasicTable, useTable, TableAction } from '/@/components/Table'; | |
| 67 | + import { useDrawer } from '/@/components/Drawer'; | |
| 68 | + import { columns, searchFormSchema } from './config'; | |
| 69 | + import { PublicApiForm } from './index'; | |
| 70 | + import { | |
| 71 | + getDataViewInterfacePage, | |
| 72 | + deleteBigViewInterface, | |
| 73 | + getPublish, | |
| 74 | + getCancelPublish, | |
| 75 | + } from '/@/api/bigscreen/center/bigscreenCenter'; | |
| 76 | + import { useBatchDelete } from '/@/hooks/web/useBatchDelete'; | |
| 77 | + import { Popconfirm, Modal } from 'ant-design-vue'; | |
| 78 | + import { JsonPreview } from '/@/components/CodeEditor'; | |
| 79 | + import { useMessage } from '/@/hooks/web/useMessage'; | |
| 80 | + | |
| 81 | + const [registerTable, { reload, setProps }] = useTable({ | |
| 82 | + api: getDataViewInterfacePage, | |
| 83 | + columns, | |
| 84 | + showIndexColumn: false, | |
| 85 | + clickToRowSelect: false, | |
| 86 | + showTableSetting: true, | |
| 87 | + bordered: true, | |
| 88 | + formConfig: { | |
| 89 | + labelWidth: 120, | |
| 90 | + schemas: searchFormSchema, | |
| 91 | + }, | |
| 92 | + useSearchForm: true, | |
| 93 | + actionColumn: { | |
| 94 | + width: 150, | |
| 95 | + title: '操作', | |
| 96 | + dataIndex: 'action', | |
| 97 | + slots: { customRender: 'action' }, | |
| 98 | + fixed: 'right', | |
| 99 | + }, | |
| 100 | + }); | |
| 101 | + | |
| 102 | + const [registerDrawer, { openDrawer }] = useDrawer(); | |
| 103 | + | |
| 104 | + const { createMessage } = useMessage(); | |
| 105 | + | |
| 106 | + const handleSuccess = () => reload(); | |
| 107 | + | |
| 108 | + const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions } = useBatchDelete( | |
| 109 | + deleteBigViewInterface, | |
| 110 | + handleSuccess, | |
| 111 | + setProps | |
| 112 | + ); | |
| 113 | + | |
| 114 | + nextTick(() => { | |
| 115 | + setProps(selectionOptions); | |
| 116 | + }); | |
| 117 | + | |
| 118 | + const handleCreateOrEdit = (record) => { | |
| 119 | + const isUpdate = record === null ? false : true; | |
| 120 | + const recordContent = record === null ? null : record; | |
| 121 | + openDrawer(true, { | |
| 122 | + isUpdate, | |
| 123 | + record: recordContent, | |
| 124 | + }); | |
| 125 | + }; | |
| 126 | + | |
| 127 | + const handleRecordContent = (record) => { | |
| 128 | + Modal.info({ | |
| 129 | + title: '接口内容', | |
| 130 | + width: 600, | |
| 131 | + content: h(JsonPreview, { data: JSON.parse(record.requestParams) }), | |
| 132 | + }); | |
| 133 | + }; | |
| 134 | + | |
| 135 | + const handlePublish = async (record) => { | |
| 136 | + await getPublish(record.id); | |
| 137 | + createMessage.success(`发布成功`); | |
| 138 | + handleSuccess(); | |
| 139 | + }; | |
| 140 | + | |
| 141 | + const handleCancelPublish = async (record) => { | |
| 142 | + await getCancelPublish(record.id); | |
| 143 | + createMessage.success(`取消发布成功`); | |
| 144 | + handleSuccess(); | |
| 145 | + }; | |
| 146 | +</script> | ... | ... |