Showing
84 changed files
with
2457 additions
and
984 deletions
Too many changes to show.
To preserve performance only 84 of 129 files are displayed.
| ... | ... | @@ -52,7 +52,7 @@ VITE_GLOB_ALARM_NOTIFY_POLLING_INTERVAL_TIME = 500000 |
| 52 | 52 | VITE_GLOB_ALARM_NOTIFY_DURATION = 5 |
| 53 | 53 | |
| 54 | 54 | # Should Disabled Task Center Execute Interval Unit (Second) |
| 55 | -VITE_GLOB_DISABLED_TASK_CENTER_EXECUTE_INTERVAL_UNIT_SECOND = true | |
| 55 | +VITE_GLOB_DISABLED_TASK_CENTER_EXECUTE_INTERVAL_UNIT_SECOND = false | |
| 56 | 56 | |
| 57 | 57 | # Software version number |
| 58 | 58 | VITE_GLOB_SOFTWARE_VERSION_NUMBER = ThingsKit v1.2.0_release | ... | ... |
| ... | ... | @@ -25,7 +25,7 @@ module.exports = defineConfig({ |
| 25 | 25 | 'plugin:jest/recommended', |
| 26 | 26 | ], |
| 27 | 27 | rules: { |
| 28 | - 'no-console': 'off', | |
| 28 | + 'no-console': 'error', | |
| 29 | 29 | 'vue/script-setup-uses-vars': 'error', |
| 30 | 30 | '@typescript-eslint/ban-ts-ignore': 'off', |
| 31 | 31 | '@typescript-eslint/explicit-function-return-type': 'off', | ... | ... |
| 1 | 1 | import { DataType } from '../../device/model/modelOfMatterModel'; |
| 2 | -import { DataTypeEnum } from '/@/components/Form/src/externalCompns/components/StructForm/config'; | |
| 2 | +import { DataTypeEnum } from '/@/enums/objectModelEnum'; | |
| 3 | 3 | import { DataSource } from '/@/views/visual/palette/types'; |
| 4 | 4 | |
| 5 | 5 | export interface AddDataBoardParams { | ... | ... |
src/api/device/classModal.ts
0 → 100644
| 1 | +import { defHttp } from '/@/utils/http/axios'; | |
| 2 | +// import { PaginationResult } from '/#/axios'; | |
| 3 | + | |
| 4 | +enum Api { | |
| 5 | + DEVICE_PROFILE_CATEGORY = '/device_profile/category', | |
| 6 | +} | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * 新增产品分类 | |
| 10 | + */ | |
| 11 | +export const deviceProfileCategory = (params) => { | |
| 12 | + return defHttp.post<any>({ | |
| 13 | + url: `${Api.DEVICE_PROFILE_CATEGORY}`, | |
| 14 | + params, | |
| 15 | + }); | |
| 16 | +}; | |
| 17 | + | |
| 18 | +/** | |
| 19 | + * 获取列表 | |
| 20 | + */ | |
| 21 | +export const getDeviceClassList = (params) => { | |
| 22 | + return defHttp.get<any>({ | |
| 23 | + url: Api.DEVICE_PROFILE_CATEGORY, | |
| 24 | + params, | |
| 25 | + }); | |
| 26 | +}; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * 删除产品分类 | |
| 30 | + */ | |
| 31 | +export const deleteDeviceClass = (params) => { | |
| 32 | + return defHttp.delete<any>({ | |
| 33 | + url: Api.DEVICE_PROFILE_CATEGORY, | |
| 34 | + params, | |
| 35 | + }); | |
| 36 | +}; | ... | ... |
| 1 | -import { | |
| 2 | - DataTypeEnum, | |
| 3 | - FunctionType, | |
| 4 | -} from '/@/views/device/profiles/step/cpns/physical/cpns/config'; | |
| 1 | +import { DataTypeEnum } from '/@/enums/objectModelEnum'; | |
| 2 | +import { FunctionType } from '/@/views/device/profiles/step/cpns/physical/cpns/config'; | |
| 5 | 3 | |
| 6 | 4 | export interface Specs { |
| 7 | 5 | min: string; |
| ... | ... | @@ -26,7 +24,7 @@ export interface DataType { |
| 26 | 24 | |
| 27 | 25 | export interface StructJSON { |
| 28 | 26 | functionName?: string; |
| 29 | - identifier?: string; | |
| 27 | + identifier: string; | |
| 30 | 28 | remark?: string; |
| 31 | 29 | dataType?: DataType; |
| 32 | 30 | serviceCommand?: string; |
| ... | ... | @@ -41,13 +39,14 @@ export interface FunctionJson { |
| 41 | 39 | } |
| 42 | 40 | |
| 43 | 41 | export interface ModelOfMatterParams { |
| 44 | - deviceProfileId: string; | |
| 42 | + deviceProfileId?: string; | |
| 45 | 43 | functionJson: FunctionJson; |
| 46 | 44 | functionName: string; |
| 47 | 45 | functionType: FunctionType; |
| 48 | 46 | identifier: string; |
| 49 | 47 | remark: string; |
| 50 | 48 | id?: string; |
| 49 | + categoryId?: string; | |
| 51 | 50 | callType?: string; |
| 52 | 51 | eventType?: string; |
| 53 | 52 | accessMode?: string; |
| ... | ... | @@ -57,10 +56,12 @@ export interface ModelOfMatterParams { |
| 57 | 56 | export interface GetModelTslParams { |
| 58 | 57 | functionType: FunctionType; |
| 59 | 58 | deviceProfileId: string; |
| 59 | + ifShowClass?: string | Boolean; | |
| 60 | 60 | } |
| 61 | 61 | |
| 62 | 62 | export interface ImportModelOfMatterType { |
| 63 | 63 | data: Recordable; |
| 64 | 64 | functionType: string; |
| 65 | - tkDeviceProfileId: string; | |
| 65 | + tkDeviceProfileId?: string; | |
| 66 | + categoryId?: string; | |
| 66 | 67 | } | ... | ... |
| ... | ... | @@ -18,13 +18,21 @@ enum ModelOfMatter { |
| 18 | 18 | IMPORT = '/things_model/import', |
| 19 | 19 | |
| 20 | 20 | GET_MODEL_SERVICE = '/things_model/get_services', |
| 21 | + CATEGORY = '/things_model/category', | |
| 22 | + CATEGORY_IMPORT = '/things_model/categoryImport', | |
| 23 | + | |
| 24 | + CATEGORY_EXPORT = '/things_model/categoryGetExport', | |
| 25 | + | |
| 26 | + IMPORT_CSV = '/things_model/csvImport', | |
| 21 | 27 | } |
| 22 | 28 | |
| 23 | 29 | export const getModelList = ( |
| 24 | 30 | params: BasicPageParams & { |
| 25 | - deviceProfileId: string; | |
| 31 | + deviceProfileId?: string; | |
| 26 | 32 | functionTyp?: FunctionType; |
| 27 | 33 | nameOrIdentifier?: string; |
| 34 | + selectType?: string | undefined; | |
| 35 | + id?: string; | |
| 28 | 36 | } |
| 29 | 37 | ) => { |
| 30 | 38 | return defHttp.get({ |
| ... | ... | @@ -82,3 +90,82 @@ export const importModelOfMatter = (data: ImportModelOfMatterType) => { |
| 82 | 90 | data, |
| 83 | 91 | }); |
| 84 | 92 | }; |
| 93 | + | |
| 94 | +// 产品品类接口 | |
| 95 | + | |
| 96 | +// 新增 | |
| 97 | +export const createModelCategory = (params: Partial<ModelOfMatterParams>) => { | |
| 98 | + return defHttp.post({ | |
| 99 | + url: ModelOfMatter.CATEGORY, | |
| 100 | + params, | |
| 101 | + }); | |
| 102 | +}; | |
| 103 | + | |
| 104 | +// 修改 | |
| 105 | +export const updateModelCategory = (params: Partial<ModelOfMatterParams>) => { | |
| 106 | + return defHttp.put({ | |
| 107 | + url: ModelOfMatter.CATEGORY, | |
| 108 | + params, | |
| 109 | + }); | |
| 110 | +}; | |
| 111 | + | |
| 112 | +// 删除 | |
| 113 | +export const deleteModelCategory = (params: string[]) => { | |
| 114 | + return defHttp.delete({ | |
| 115 | + url: ModelOfMatter.CATEGORY, | |
| 116 | + params: { | |
| 117 | + ids: params, | |
| 118 | + }, | |
| 119 | + }); | |
| 120 | +}; | |
| 121 | + | |
| 122 | +// 导入 | |
| 123 | +export const importModelCategory = (data: ImportModelOfMatterType) => { | |
| 124 | + return defHttp.post({ | |
| 125 | + url: ModelOfMatter.CATEGORY_IMPORT, | |
| 126 | + data, | |
| 127 | + }); | |
| 128 | +}; | |
| 129 | + | |
| 130 | +// 导出 | |
| 131 | +export const ExportModelCategory = (params: any) => { | |
| 132 | + const { functionType, deviceProfileId } = params; | |
| 133 | + return defHttp.get({ | |
| 134 | + url: `${ModelOfMatter.CATEGORY_EXPORT}/${functionType}/${deviceProfileId}`, | |
| 135 | + params, | |
| 136 | + }); | |
| 137 | +}; | |
| 138 | + | |
| 139 | +/** | |
| 140 | + * 物模型产品品类界面excel导入 | |
| 141 | + */ | |
| 142 | + | |
| 143 | +export const importCsvCategory = (params: { | |
| 144 | + categoryId?: string; | |
| 145 | + deviceProfileId?: string; | |
| 146 | + file: FormData; | |
| 147 | +}) => { | |
| 148 | + const { categoryId } = params || {}; | |
| 149 | + | |
| 150 | + return defHttp.post<any>({ | |
| 151 | + url: `${ModelOfMatter.IMPORT_CSV}?categoryId=${categoryId}`, | |
| 152 | + params: params.file, | |
| 153 | + }); | |
| 154 | +}; | |
| 155 | + | |
| 156 | +/** | |
| 157 | + * 物模型产品物模型界面excel导入 | |
| 158 | + */ | |
| 159 | + | |
| 160 | +export const importCsvDeviceProfileId = (params: { | |
| 161 | + categoryId?: string; | |
| 162 | + deviceProfileId?: string; | |
| 163 | + file: FormData; | |
| 164 | +}) => { | |
| 165 | + const { deviceProfileId } = params || {}; | |
| 166 | + | |
| 167 | + return defHttp.post<any>({ | |
| 168 | + url: `${ModelOfMatter.IMPORT_CSV}?deviceProfileId=${deviceProfileId}`, | |
| 169 | + params: params.file, | |
| 170 | + }); | |
| 171 | +}; | ... | ... |
| 1 | 1 | import { BasicPageParams } from '/@/api/model/baseModel'; |
| 2 | +import { SceneLinkageDataType } from '/@/views/rule/linkedge/components/SceneLinkageDrawer/type'; | |
| 2 | 3 | |
| 3 | 4 | export type ScreenLinkPageQueryParam = BasicPageParams & ScreenParams; |
| 4 | 5 | |
| ... | ... | @@ -14,97 +15,7 @@ export type ScreenByDeptIdParams = { |
| 14 | 15 | // organizationId: '2f5c8f2a-196c-4941-8771-290f9da76219'; |
| 15 | 16 | }; |
| 16 | 17 | |
| 17 | -export interface ScreenAddModel { | |
| 18 | - createTime?: string; | |
| 19 | - creator?: string; | |
| 20 | - defaultConfig?: string; | |
| 21 | - description?: string; | |
| 22 | - doAction?: [ | |
| 23 | - { | |
| 24 | - command: string; | |
| 25 | - createTime: string; | |
| 26 | - creator: string; | |
| 27 | - defaultConfig: string; | |
| 28 | - description: string; | |
| 29 | - deviceId: string; | |
| 30 | - enabled: true; | |
| 31 | - icon: string; | |
| 32 | - id: string; | |
| 33 | - name: string; | |
| 34 | - outPut: string; | |
| 35 | - outTarget: string; | |
| 36 | - roleIds: []; | |
| 37 | - tenantCode: string; | |
| 38 | - tenantExpireTime: string; | |
| 39 | - tenantId: string; | |
| 40 | - tenantStatus: 'DISABLED'; | |
| 41 | - updateTime: string; | |
| 42 | - updater: string; | |
| 43 | - } | |
| 44 | - ]; | |
| 45 | - doCondition?: [ | |
| 46 | - { | |
| 47 | - compare: 0; | |
| 48 | - createTime: string; | |
| 49 | - creator: string; | |
| 50 | - defaultConfig: string; | |
| 51 | - description: string; | |
| 52 | - deviceId: string; | |
| 53 | - enabled: true; | |
| 54 | - icon: string; | |
| 55 | - id: string; | |
| 56 | - name: string; | |
| 57 | - property: string; | |
| 58 | - roleIds: []; | |
| 59 | - status: string; | |
| 60 | - tenantCode: string; | |
| 61 | - tenantExpireTime: string; | |
| 62 | - tenantId: string; | |
| 63 | - tenantStatus: 'DISABLED'; | |
| 64 | - updateTime: string; | |
| 65 | - updater: string; | |
| 66 | - value: string; | |
| 67 | - } | |
| 68 | - ]; | |
| 69 | - enabled?: true; | |
| 70 | - icon?: string; | |
| 71 | - id?: string; | |
| 72 | - name?: string; | |
| 73 | - organizationId?: string; | |
| 74 | - roleIds?: [string]; | |
| 75 | - status?: string; | |
| 76 | - tenantCode?: string; | |
| 77 | - tenantExpireTime?: string; | |
| 78 | - tenantId?: string; | |
| 79 | - tenantStatus?: 'DISABLED'; | |
| 80 | - triggers?: [ | |
| 81 | - { | |
| 82 | - attributeChoose?: string; | |
| 83 | - compare?: 0; | |
| 84 | - createTime?: string; | |
| 85 | - creator?: string; | |
| 86 | - defaultConfig?: string; | |
| 87 | - description?: string; | |
| 88 | - deviceId?: string; | |
| 89 | - enabled?: true; | |
| 90 | - icon?: string; | |
| 91 | - id?: string; | |
| 92 | - name?: string; | |
| 93 | - roleIds?: []; | |
| 94 | - tenantCode?: string; | |
| 95 | - tenantExpireTime?: string; | |
| 96 | - tenantId?: string; | |
| 97 | - tenantStatus?: 'DISABLED'; | |
| 98 | - tiggerEvent?: string; | |
| 99 | - touchWay?: string; | |
| 100 | - updateTime?: string; | |
| 101 | - updater?: string; | |
| 102 | - value?: string; | |
| 103 | - } | |
| 104 | - ]; | |
| 105 | - updateTime?: string; | |
| 106 | - updater?: string; | |
| 107 | -} | |
| 18 | +export type ScreenAddModel = SceneLinkageDataType; | |
| 108 | 19 | |
| 109 | 20 | export interface IChangeStatus { |
| 110 | 21 | status?: number; | ... | ... |
| ... | ... | @@ -6,6 +6,7 @@ import { |
| 6 | 6 | ScreenByDeptIdParams, |
| 7 | 7 | IChangeStatus, |
| 8 | 8 | } from '/@/api/ruleengine/model/ruleengineModel'; |
| 9 | +import { DeviceModel } from '../device/model/deviceModel'; | |
| 9 | 10 | |
| 10 | 11 | enum ScreenManagerApi { |
| 11 | 12 | /** |
| ... | ... | @@ -126,7 +127,7 @@ export const byOrganizationIdGetMasterDevice = (params: { |
| 126 | 127 | deviceProfileId?: string; |
| 127 | 128 | }) => { |
| 128 | 129 | const { organizationId, deviceProfileId } = params; |
| 129 | - return defHttp.get({ | |
| 130 | + return defHttp.get<DeviceModel[]>({ | |
| 130 | 131 | url: `${ScreenManagerApi.MASTER_GET_DEVICE}`, |
| 131 | 132 | params: { deviceProfileId, organizationId }, |
| 132 | 133 | }); | ... | ... |
| ... | ... | @@ -37,10 +37,11 @@ export interface AccountListItem { |
| 37 | 37 | } |
| 38 | 38 | |
| 39 | 39 | export interface OrganizationListItem { |
| 40 | - id: string; | |
| 41 | - name: string; | |
| 40 | + id?: string; | |
| 41 | + name?: string; | |
| 42 | 42 | parentId?: string; |
| 43 | - remark: string; | |
| 43 | + remark?: string; | |
| 44 | + organizationId?: string; | |
| 44 | 45 | } |
| 45 | 46 | |
| 46 | 47 | export interface MenuListItem { | ... | ... |
src/assets/svg/JSON.svg
0 → 100644
| 1 | +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1699588251601" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1411" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M145.621959 0c-44.79888 0-79.998 36.81188-79.998 81.61076v860.77848c0 44.79888 35.19912 81.61076 79.998 81.61076h732.781681a81.969151 81.969151 0 0 0 81.61076-81.61076V324.80468L657.60916 0h-511.987201z" fill="#F17F53" p-id="1412"></path><path d="M657.60916 0v233.59416c0 25.59936 17.61236 92.79768 97.61036 92.79768h204.79488L657.60916 0z" fill="#FFFFFF" p-id="1413"></path><path d="M109.117272 659.874703c1.61276 0 2.867128 0.614385 3.814305 1.868753s1.663958 2.764731 2.175945 4.582286 0.81918 3.737507 0.972776 5.862253 0.230394 4.044699 0.230394 5.862254v5.708657c2.099148 3.302317 4.78708 6.886228 8.0126 10.726132s6.963026 7.449414 11.18692 10.80293 8.78058 6.143846 13.721257 8.39659 10.214145 3.379116 15.820405 3.379115c5.99025 0 11.622109-1.407965 16.869978-4.198295s10.137347-6.527837 14.617235-11.18692 8.652584-9.98375 12.441288-15.974001 7.21902-12.236494 10.265344-18.661933 5.759856-12.876478 8.089398-19.276318 4.377491-12.287693 6.067048-17.689158 3.046324-10.086148 4.044699-14.028449 1.689558-6.681433 2.099147-8.166196c2.611135-10.598135 4.81268-20.761081 6.681433-30.437639s2.764731-19.250719 2.764731-28.645684c0-2.303942-0.691183-3.60951-2.099147-3.891103l-37.19587 10.495738a19.916302 19.916302 0 0 1-5.094273 0.895978c-3.788705 0-6.963026-1.20317-9.522962-3.60951s-3.814305-5.862253-3.814305-10.342142 0.435189-8.114997 1.279968-10.879728 2.201545-4.81268 4.044699-6.220644 4.275093-2.329542 7.270218-2.764731 6.655834-0.665583 10.956527-0.665583h2.099147c2.40634-0.511987 5.478263-1.20317 9.21577-2.099148s7.935802-1.919952 12.518087-3.071923l14.694032-3.737507 15.743607-4.044699c5.299068-1.356766 10.572536-2.662333 15.820404-3.9679a1637.283868 1637.283868 0 0 1 23.474613-5.63186l5.990251-1.279968a22.01545 22.01545 0 0 1 3.737506-0.588785c1.20317 0 2.303942 0.358391 3.302318 1.049574s1.817555 1.58716 2.483138 2.636734a14.514837 14.514837 0 0 1 2.175945 7.423814c0 2.995125-1.151971 5.60626-3.455913 7.807805s-5.19667 4.121497-8.703783 5.785456-7.321417 3.097523-11.468513 4.351891l-11.62211 3.532711c-3.60951 1.100772-6.681433 2.175946-9.215769 3.22552s-3.967901 2.227144-4.275093 3.532711c-0.511987 4.40309-0.998375 9.292568-1.510363 14.694033s-1.049574 10.546936-1.638359 15.462014c-0.204795 1.20317-0.614385 4.095898-1.279968 8.703782s-1.561561 10.188545-2.687932 16.79318-2.559936 13.823654-4.198295 21.682658-3.532712 15.564411-5.63186 23.167421c-2.303942 8.294193-5.324667 17.151571-9.062173 26.546536s-8.191795 18.559536-13.337267 27.442514-10.982125 17.228369-17.484363 24.984976-13.542061 14.130847-21.145071 19.122721a58.929727 58.929727 0 0 1-23.19302 8.089398 61.336067 61.336067 0 0 1-9.369366 0.742382c-5.19667 0-10.828529-0.691183-16.869978-2.099148s-12.134097-3.404715-18.226744-5.99025-11.9805-5.734257-17.61236-9.369366-10.674933-7.705407-15.078023-12.159696-7.910202-9.21577-10.495738-14.335641-3.891103-10.444539-3.891102-16.050799c0-4.300692 0.435189-8.0126 1.279968-11.110122s2.227144-5.60626 4.121496-7.500613 4.428689-3.302317 7.577411-4.198295 7.014225-1.484763 11.519712-1.484763zM305.61796 693.333067c3.404715 1.20317 6.886228 2.611135 10.418939 4.198295s7.21902 3.123122 11.033324 4.582285 7.782205 2.662333 11.929302 3.686308 8.575786 1.510362 13.286068 1.510362c5.503862 0 11.058924-0.639984 16.639584-1.945551s11.084523-3.225519 16.434789-5.785455 10.470138-5.657459 15.385215-9.292568 9.394965-7.884603 13.490863-12.671683c4.505487-5.094273 8.242994-9.727757 11.238119-13.874854s5.427064-7.859004 7.270218-11.110122 3.174321-6.041449 3.967901-8.39659 1.20317-4.377491 1.20317-6.067048c0-2.508737-0.844779-4.684683-2.559936-6.527837s-3.967901-3.379116-6.835029-4.582285-6.067048-2.073548-9.676558-2.636734-7.347016-0.81918-11.238119-0.81918c-2.303942 0-4.991875 0.076798-8.089398 0.230394l-9.446164 0.460789-9.292567 0.38399a150.39624 150.39624 0 0 1-7.807805 0.153596c-3.302317 0-6.732632-0.38399-10.265344-1.126372s-7.014225-1.971151-10.418939-3.686307-6.553436-3.9935-9.446164-6.911828a35.403915 35.403915 0 0 1-8.831779-15.743606 24.626584 24.626584 0 0 1-0.742382-6.143846c0-2.40634 0.179196-4.684683 0.537587-6.83503s0.767981-4.223894 1.279968-6.220644c1.407965-4.991875 3.737507-10.086148 6.963026-15.231619s7.142221-10.162946 11.698907-15.078023 9.497363-9.650959 14.847629-14.258844 10.854129-8.934177 16.511587-12.978875 11.21252-7.705407 16.639584-10.956526 10.521337-6.01585 15.23162-8.319792c6.604635-3.19992 13.337267-5.529462 20.172295-6.963026s13.61886-2.175946 20.325892-2.175946c3.9935 0 7.807805 0.537587 11.391715 1.58716s6.78383 2.585535 9.522962 4.582286 4.915077 4.479888 6.527837 7.423814 2.40634 6.323042 2.40634 10.137347c0 2.201545-0.255994 4.044699-0.742381 5.555061s-1.151971 2.713532-1.945552 3.686308-1.663958 1.61276-2.636734 2.022349-1.919952 0.588785-2.918327 0.588785c-2.687933 0-5.171071-0.307192-7.423814-0.895977s-4.428689-1.279968-6.527837-2.02235-4.198295-1.459164-6.297443-2.099147-4.40309-0.972776-6.911827-0.972776c-7.398215 0-14.924427 1.484763-22.578635 4.428689s-15.103622 6.707032-22.348242 11.23812-14.105247 9.625359-20.556286 15.231619-12.236494 11.058924-17.330767 16.357991c-2.687933 2.79033-4.684683 5.60626-5.913452 8.39659s-1.868753 5.452664-1.868753 7.961401c0 3.711907 1.61276 6.604635 4.81268 8.703782s7.091023 3.148721 11.698907 3.148722c2.687933 0 5.759856-0.051199 9.138972-0.153597a796.140096 796.140096 0 0 0 20.761081-0.844779c3.353516-0.153596 6.323042-0.230394 8.934176-0.230394 6.195045 0 12.159696 0.870378 17.842754 2.636734s10.751731 4.326292 15.154821 7.731007 7.935802 7.628609 10.572536 12.671683 3.967901 10.828529 3.967901 17.330767c0 3.9935-0.588785 8.038199-1.791955 12.159696s-2.841529 8.217395-4.940677 12.364491-4.505487 8.242994-7.19342 12.287693-5.555061 8.0126-8.550186 11.929301c-5.401465 6.988625-11.417315 13.59326-18.073148 19.788306s-13.721257 11.59651-21.22187 16.204395-15.436414 8.242994-23.781805 10.956526-16.921177 4.044699-25.727357 4.044699a74.724532 74.724532 0 0 1-23.551411-4.121497c-3.891103-1.356766-7.577411-3.046324-11.033325-5.094273s-6.476638-4.377491-9.062173-6.963026-4.684683-5.478263-6.220644-8.626984-2.329542-6.579036-2.329542-10.265344c0-1.791955 0.281593-3.532712 0.819179-5.17107s1.868753-2.559936 4.070299-2.559936zM497.152371 651.631709c1.791955-7.500612 4.40309-15.18042 7.807805-23.013824s7.398215-15.718007 12.0061-23.62821 9.727757-15.666808 15.385215-23.321017a316.868878 316.868878 0 0 1 57.982551-59.928102c3.19992-2.201545 6.143846-3.660708 8.857378-4.351891s5.555061-1.049574 8.550186-1.049573c3.19992 0 6.041449 0.486388 8.550187 1.433564s4.991875 2.662333 7.500612 5.17107c0.79358 0.895978 1.638359 1.689558 2.559936 2.40634s1.740756 1.049574 2.559936 1.049574c0.204795 0 0.460788-0.230394 0.742382-0.665583l0.972775-1.587161c0.358391-0.614385 0.767981-1.228769 1.279968-1.868753s1.100772-1.126372 1.791956-1.433564c1.689558-0.79358 3.737507-1.331167 6.067048-1.58716s4.735882-0.38399 7.116622-0.383991c4.505487 0 8.857379 0.81918 13.055674 2.483138s7.910202 3.967901 11.110122 6.963026c7.60301 7.091023 13.362866 15.59001 17.330767 25.496963s5.913452 20.556286 5.913452 31.948001c0 10.188545-1.510362 21.19627-4.505488 32.997575-2.611135 10.39334-6.323042 20.505087-11.18692 30.309642s-10.546936 18.994725-17.100373 27.59611-13.849254 16.460388-21.887452 23.551412-16.613985 13.20927-25.727357 18.303542-18.610735 9.062173-28.492088 11.929302-19.941901 4.275093-30.156046 4.275093c-9.497363 0-18.021949-1.459164-25.573761-4.351891s-13.951651-6.988625-19.19952-12.287693-9.241369-11.59651-12.006099-18.892328-4.121497-15.410815-4.121497-24.293793c0-3.788705 0.230394-7.628609 0.665583-11.468513s1.151971-7.807805 2.150346-11.801305z m25.343367 10.060549a63.230419 63.230419 0 0 0-1.638359 13.490862c0 5.60626 0.972776 10.521337 2.918327 14.770831s4.710282 7.807805 8.242994 10.649334 7.807805 4.991875 12.748481 6.451039 10.367741 2.175946 16.281193 2.175945c6.988625 0 14.130847-1.100772 21.375465-3.302317s14.335642-5.401465 21.22187-9.59976 13.542061-9.241369 19.941901-15.154821 12.313292-12.594885 17.765956-20.095498 10.290943-15.641209 14.540437-24.447389 7.679808-18.149946 10.265343-28.056898c0.998375-3.60951 1.715157-7.347016 2.175946-11.238119s0.665583-7.654209 0.665583-11.238119c0-5.811055-0.639984-11.340516-1.945551-16.639584s-3.455914-10.00935-6.451039-14.105248-6.937427-7.372616-11.852504-9.830154-10.905327-3.686308-17.99635-3.686308c-0.998375 0-1.766356 0.435189-2.329542 1.279968s-1.126372 1.919952-1.715157 3.225519c-0.511987 1.100772-1.075173 2.252744-1.715157 3.455914a11.878103 11.878103 0 0 1-6.451039 5.555061 15.794805 15.794805 0 0 1-5.785455 0.895978c-1.689558 0-3.19992-0.38399-4.505487-1.126372s-2.611135-1.766356-3.891103-3.071923l-1.510362-1.433564a1.971151 1.971151 0 0 0-1.356766-0.537587c-0.895978 0-2.073548 0.40959-3.532712 1.20317s-2.943926 1.740756-4.505487 2.841529-3.046324 2.252744-4.505488 3.455914-2.585535 2.252744-3.379115 3.148721c-6.80943 6.988625-13.567661 14.617235-20.325892 22.885828s-12.978876 16.767581-18.661934 25.57376-10.674933 17.663558-14.924427 26.623335-7.270218 17.561161-9.16457 25.880953zM760.083398 546.495138c0.588785-2.611135 1.356766-5.375866 2.252744-8.319792s2.099148-5.657459 3.609509-8.089398 3.455914-4.505487 5.862254-6.143847 5.452664-2.483138 9.138971-2.483137c3.507112 0 6.630234 0.972776 9.369366 2.918327s5.222269 3.916702 7.423814 5.913452c2.611135 1.689558 5.094273 5.145471 7.500613 10.342141s4.863878 11.59651 7.423814 19.19952 5.299068 16.204395 8.242994 25.804155 6.195045 19.660308 9.753356 30.156046 7.526212 21.221869 11.929302 32.178396 9.394965 21.631459 15.001225 32.024799l3.148721 5.631859a95.076023 95.076023 0 0 0 7.142222 10.879728c1.049574 1.305567 1.817555 1.945551 2.329542 1.945552 0.307192 0 0.639984-0.742381 1.049573-2.252744s0.844779-3.302317 1.356767-5.401465l1.58716-6.451039a59.902502 59.902502 0 0 1 1.58716-5.401465 476.736882 476.736882 0 0 0 13.721257-37.426264c2.739132-8.447789 5.785455-18.482738 9.062174-30.079248a1560.127397 1560.127397 0 0 0 14.182045-54.526637c1.151971-4.966276 2.252744-10.00935 3.302317-15.154821s1.971151-10.162946 2.764731-15.078023 1.356766-9.138972 1.638359-12.748481a77.540461 77.540461 0 0 1 0.691183-8.242994c0.255994-1.894353 0.563186-3.865503 0.972776-5.913452s0.921577-3.916702 1.58716-5.63186 1.484763-3.097523 2.483138-4.198295 2.201545-1.638359 3.60951-1.638359 3.123122 0.204795 5.171071 0.588786 3.916702 0.998375 5.631859 1.791955c1.894353 2.611135 3.635109 5.734257 5.17107 9.369366s2.329542 8.575786 2.329542 14.77083c0 3.891103-0.40959 8.575786-1.20317 14.02845s-1.817555 11.289318-3.071923 17.561161a634.864128 634.864128 0 0 1-8.934177 38.245443c-1.61276 6.041449-3.123122 11.59651-4.582285 16.639584s-2.662333 9.21577-3.686308 12.518087c-1.791955 5.811055-3.686308 11.775706-5.631859 17.919552s-4.095898 12.594885-6.451039 19.353117-4.889478 13.900452-7.654208 21.452263-5.836654 15.61561-9.21577 24.216995c-1.510362 3.891103-3.225519 7.807805-5.171071 11.698907s-4.172696 7.423814-6.681433 10.572536-5.324667 5.708657-8.473388 7.654209-6.681433 2.918327-10.572536 2.918327c-2.303942 0-4.684683-0.332792-7.116622-0.972776s-4.531087-1.971151-6.220644-3.967901c-8.191795-9.497363-15.487613-20.274693-21.887453-32.331991s-12.134097-24.652184-17.17717-37.810255-9.522962-26.444139-13.414065-39.909402-7.449414-26.316142-10.649334-38.629435l-0.895978-3.455913c-0.40959-1.407965-0.767981-2.81593-1.126371-4.275093s-0.691183-2.764731-1.049574-3.967901-0.742381-2.175946-1.20317-2.918327-0.972776-1.126372-1.58716-1.126372-1.356766 1.100772-2.252744 3.302317-1.791955 4.684683-2.687933 7.423815-1.715157 5.427064-2.483138 8.012599l-1.433564 4.940677c-0.691183 2.611135-1.740756 6.323042-3.148721 11.18692l-4.735882 16.434789c-1.766356 6.118247-3.660708 12.543686-5.708657 19.353117l-5.913452 19.737106a1165.026874 1165.026874 0 0 1-12.902078 40.728582l-3.891102 12.364491c-1.279968 4.147096-2.508737 7.935802-3.60951 11.314917s-1.791955 5.657459-2.099148 6.758231c-1.20317 3.788705-2.969526 6.681433-5.324667 8.626984s-4.735882 2.918327-7.116622 2.918327c-1.510362 0-2.995125-0.537587-4.505487-1.58716s-2.81593-2.329542-3.967901-3.814305-2.099148-3.123122-2.841529-4.863878-1.126372-3.327917-1.126372-4.735882c0-0.79358 0.255994-2.073548 0.742382-3.814304s1.305567-4.735882 2.40634-8.934177l3.891102-15.462013 44.338092-143.638009z" fill="#FFFFFF" p-id="1414"></path></svg> | |
| \ No newline at end of file | ... | ... |
src/assets/svg/excel.svg
0 → 100644
| 1 | +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1699933658783" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1443" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M145.621959 0c-44.79888 0-79.998 36.81188-79.998 81.61076v860.77848c0 44.79888 35.19912 81.61076 79.998 81.61076h732.781681a81.969151 81.969151 0 0 0 81.61076-81.61076V324.80468L657.60916 0h-511.987201z" fill="#25B39E" p-id="1444"></path><path d="M657.60916 0v233.59416c0 25.59936 17.61236 92.79768 97.61036 92.79768h204.79488L657.60916 0z" fill="#FFFFFF" p-id="1445"></path><path d="M158.498438 694.485038c0-3.507112 0.511987-7.19342 1.510362-11.110122 3.404715-13.59326 7.372616-26.930527 11.929302-39.986201s8.678183-26.034549 12.36449-38.936626 6.78383-23.781805 9.21577-32.613585 4.633484-16.460388 6.527837-22.80903 3.660708-11.826904 5.247869-16.434789 3.353516-9.138972 5.247868-13.644459c1.20317-2.687933 2.534337-5.503862 3.967901-8.39659s3.020724-5.58066 4.735882-8.0126 3.481513-4.454289 5.324667-5.99025 3.763106-2.329542 5.785455-2.329542c4.095898 0 7.21902 0.665583 9.369366 2.02235s3.481513 2.585535 3.9935 3.686308l1.356766 6.143846c1.510362-0.102397 3.455914-0.38399 5.862254-0.819179s4.81268-0.921577 7.270218-1.433565 4.735882-0.998375 6.835029-1.510362 3.711907-0.947176 4.81268-1.356766c6.604635-1.791955 12.697283-3.353516 18.303542-4.659083s10.930927-2.38074 15.974001-3.22552 9.881353-1.484763 14.463638-1.868753 9.241369-0.588785 13.951651-0.588785c4.607885 0 8.345391 0.255994 11.238119 0.742381s5.19667 1.177571 6.911828 2.02235 2.867128 1.843154 3.532711 2.995125 0.972776 2.38074 0.972776 3.686308c0 1.20317-0.332792 2.483138-0.972776 3.814304s-1.715157 2.636734-3.225519 3.814305-3.455914 2.252744-5.862254 3.148721-5.401465 1.510362-9.010974 1.791955c-0.895978 0.204795-2.969526 0.563186-6.220645 1.126372l-10.572535 1.791955-10.80293 1.868754a129.60956 129.60956 0 0 0-7.039824 1.356766h0.153596c-0.588785 0.102397-2.022349 0.486388-4.275093 1.126372s-4.966276 1.407965-8.166196 2.252743-6.681433 1.817555-10.41894 2.918327l-11.110122 3.22552a687.163621 687.163621 0 0 0-17.637959 5.324667c-6.092648 2.40634-10.879728 5.58066-14.335642 9.522961s-6.169446 8.370991-8.166195 13.286068c-0.40959 0.895978-0.998375 2.431939-1.791956 4.582286l-2.636734 7.347016-3.071923 8.780581-3.148721 8.857378c-0.998375 2.81593-1.868753 5.350266-2.636734 7.654209s-1.279968 3.9935-1.587161 5.094272c-0.307192 0.998375-0.511987 1.894353-0.588785 2.687933s-0.153596 1.407965-0.153596 1.791955c0 0.588785 0.153596 0.895978 0.460788 0.895978 1.510362 0 4.633484-0.665583 9.369366-2.022349s10.290943-3.020724 16.639584-5.017475l20.40269-6.451039c7.244619-2.303942 14.207645-4.454289 20.837879-6.451038s12.569286-3.686308 17.765956-5.017475 8.959776-2.022349 11.238119-2.022349c3.507112 0 5.862253 0.563186 7.039824 1.715157s1.791955 2.431939 1.791955 3.814304c0 3.60951-1.279968 6.758231-3.814304 9.446164s-5.734257 5.043074-9.522962 7.039824c-1.20317 0.588785-3.430314 1.484763-6.681433 2.636734s-6.758231 2.329542-10.495738 3.532712l-10.726132 3.455914-7.347016 2.406339c-9.804555 3.788705-17.765956 6.937427-23.935402 9.369366s-11.135722 4.454289-14.924427 5.99025l-8.78058 3.532712c-2.047949 0.81918-3.942301 1.484763-5.708657 2.02235s-3.686308 1.075173-5.785456 1.58716-4.940676 1.254369-8.652583 2.150346c-0.895978 2.099148-1.945551 5.273468-3.148722 9.522962s-2.355141 8.652584-3.455913 13.20927-2.022349 8.78058-2.764731 12.671683-1.126372 6.604635-1.126372 8.089398c0 1.791955 0.255994 3.123122 0.742381 3.967901s1.100772 1.433564 1.791956 1.715157 1.407965 0.460788 2.099147 0.460788h1.638359c4.81268 0 10.572536-0.691183 17.330767-2.099147s13.414065-3.251119 20.018699-5.555061c6.297443-2.201545 11.801305-4.607885 16.511588-7.193421s9.113372-5.017475 13.286068-7.270218 8.191795-4.147096 12.159696-5.708657 8.268593-2.38074 12.978875-2.483138c0.998375 0 2.175946 0.102397 3.532712 0.307192s2.636734 0.563186 3.814304 1.126372 2.175946 1.279968 2.918327 2.175946 1.023974 2.047949 0.81918 3.455913c-0.40959 2.892728-1.843154 5.759856-4.351891 8.550186s-5.657459 5.503862-9.446164 8.089398-8.038199 5.094273-12.748481 7.500613-9.497363 4.684683-14.41244 6.835029-9.702157 4.095898-14.41244 5.862253-8.908577 3.276718-12.594885 4.582286c-9.19017 3.19992-18.149946 5.555061-26.853729 7.039824s-16.460388 2.252744-23.372215 2.252743c-7.60301 0-13.414065-1.433564-17.484363-4.275093s-6.067048-7.577411-6.067048-14.182045zM336.541986 699.579311a14.489238 14.489238 0 0 1-13.721257 1.638359c-1.356766-0.691183-2.508737-1.61276-3.455913-2.764731a12.902077 12.902077 0 0 1-2.918327-8.319792c0-2.099148 0.435189-3.865503 1.279968-5.324667s1.894353-2.687933 3.148721-3.737507 2.611135-1.919952 4.044699-2.636734 2.764731-1.305567 3.967901-1.791955c3.9935-2.611135 8.498988-5.811055 13.490863-9.59976s10.137347-7.884603 15.462013-12.236494 10.572536-8.78058 15.820404-13.286068l14.924427-12.902077 6.758231-5.990251a121.59696 121.59696 0 0 0-13.59326-31.128821l-5.017474-8.166196-3.686308-5.990251a7.782205 7.782205 0 0 1-1.279968-4.198295 14.258844 14.258844 0 0 1 7.116622-11.340516 11.417315 11.417315 0 0 1 5.785455-1.433564c3.19992 0 6.01585 0.665583 8.473388 2.022349s4.633484 3.071923 6.527837 5.171071 3.558311 4.377491 4.940677 6.835029 2.662333 4.78708 3.737506 6.963026c0.588785 1.20317 1.254369 2.79033 1.945552 4.81268s1.382365 4.121497 2.022349 6.37424l1.868753 6.604635 1.510363 5.631859c4.40309-4.198295 8.678183-8.601385 12.825279-13.209269a587.556511 587.556511 0 0 0 18.892328-22.194646c1.740756-2.201545 3.58391-4.223894 5.478263-6.067048s3.839904-3.379116 5.862253-4.582285 4.147096-1.791955 6.451039-1.791955c3.891103 0 6.681433 0.998375 8.319792 2.995125s2.483138 4.607885 2.483138 7.807804c0 3.404715-0.614385 6.527837-1.868753 9.369366s-2.867128 5.068673-4.863879 6.681433c-2.892728 2.303942-6.067048 5.068673-9.522962 8.319792s-6.937427 6.681433-10.495737 10.265344l-10.572536 10.649333c-3.507112 3.507112-6.707032 6.655834-9.59976 9.446164-1.20317 1.100772-2.227144 2.201545-3.071923 3.302318s-1.279968 2.508737-1.279968 4.198295c0 0.998375 0.281593 2.252744 0.819179 3.737506s1.254369 3.097523 2.099148 4.81268l2.559936 5.171071c0.870378 1.740756 1.58716 3.327917 2.175945 4.735881 1.20317 2.687933 2.867128 5.887853 5.017475 9.59976s4.300692 7.577411 6.451039 11.62211 4.0191 8.166196 5.631859 12.364491 2.40634 8.191795 2.40634 12.006099a20.761081 20.761081 0 0 1-3.737507 12.082898c-1.075173 1.561561-2.329542 2.764731-3.686308 3.686308s-2.636734 1.356766-3.814304 1.356766c-2.611135 0-4.684683-0.307192-6.220645-0.895977s-2.867128-1.510362-3.967901-2.687933-2.022349-2.662333-2.764731-4.428689-1.58716-3.763106-2.483137-6.067049c-1.305567-3.711907-2.995125-7.961401-5.094273-12.748481s-4.275093-9.548561-6.527837-14.258844-4.377491-9.062173-6.374241-13.132471-3.558311-7.116622-4.659083-9.21577l-8.626984 6.835029-11.468514 9.062174-17.919552 14.105247c-7.244619 5.708657-16.588385 12.953276-28.0057 21.861854zM490.752531 646.921427a158.588035 158.588035 0 0 1 22.041049-48.510787c5.299068-7.833404 11.314917-15.103622 18.073148-21.759456s14.130847-12.082898 22.117847-16.281193c2.611135-1.407965 5.452664-2.457539 8.550187-3.148722s6.246244-1.049574 9.446163-1.049573c3.302317 0 6.374241 0.307192 9.21577 0.895977s5.299068 1.61276 7.347016 2.995125 3.686308 3.19992 4.863879 5.401465 1.791955 4.889478 1.791955 8.089398c0 2.40634-0.358391 4.81268-1.049574 7.270218s-1.740756 4.659084-3.148721 6.604635-3.148721 3.532712-5.247869 4.735882-4.556686 1.791955-7.347016 1.791955c-2.201545 0-4.223894-0.40959-6.067048-1.20317a47.102822 47.102822 0 0 1-7.884603-4.275093 19.916302 19.916302 0 0 0-2.841529-1.279968c-3.9935 1.791955-7.782205 4.172696-11.314917 7.116622s-6.860628 6.220644-9.906953 9.830154-5.862253 7.449414-8.39659 11.545312-4.838279 8.191795-6.911827 12.287693-3.788705 8.114997-5.247869 12.082897-2.636734 7.577411-3.532712 10.879728c-0.691183 2.40634-1.331167 5.119872-1.868753 8.166196s-0.81918 6.01585-0.819179 8.934177c0 1.99675 0.179196 3.891103 0.537586 5.708657s0.972776 3.404715 1.868753 4.81268 2.099148 2.508737 3.60951 3.302317 3.353516 1.20317 5.555061 1.20317c3.507112 0 6.963026-0.460788 10.41894-1.356766s6.835029-2.047949 10.137346-3.455913 6.527837-3.020724 9.676559-4.863879a314.129747 314.129747 0 0 0 14.924426-9.369366c1.919952-1.279968 3.711907-2.457539 5.401465-3.455913s3.276718-1.817555 4.735882-2.483138 2.713532-0.972776 3.814305-0.972776c1.510362 0 2.892728 0.38399 4.198295 1.126372s1.945551 2.022349 1.945551 3.814305a12.79968 12.79968 0 0 1-0.895978 4.351891c-1.407965 3.891103-3.302317 7.398215-5.708657 10.495738s-5.068673 5.862253-8.0126 8.319792-6.092648 4.633484-9.446163 6.527836-6.681433 3.660708-9.983751 5.247869c-6.195045 3.302317-12.466888 5.785455-18.815529 7.423815s-11.673308 2.483138-15.974001 2.483137c-1.407965 0-3.046324-0.153596-4.940677-0.460788s-3.558311-0.742381-4.940676-1.356766c-8.089398-3.507112-14.00285-8.191795-17.689158-14.105247s-5.555061-12.902077-5.555061-20.991476c0-3.507112 0.281593-7.167821 0.81918-11.033324s1.356766-7.807805 2.457538-12.031699zM618.698133 647.689408c0-4.300692 1.151971-7.961401 3.455913-10.956526s5.350266-4.991875 9.138972-5.990251a138.287743 138.287743 0 0 1 13.644459-21.17067c3.404715-4.40309 7.270218-8.831779 11.622109-13.286068s9.138972-8.498988 14.41244-12.159696 10.905327-6.630234 16.946776-8.934177 12.466888-3.455914 19.276318-3.455913c5.811055 0 10.854129 0.691183 15.154821 2.099147s7.859004 3.353516 10.649334 5.862254 4.889478 5.478263 6.297443 8.934176 2.099148 7.167821 2.099147 11.186921c0 3.404715-0.460788 6.655834-1.356766 9.753356-1.407965 5.60626-3.9935 10.495738-7.807805 14.694032s-8.268593 7.884603-13.414064 11.033325-10.751731 5.785455-16.793181 7.884602-12.108497 3.839904-18.149946 5.247869-11.878103 2.483138-17.484363 3.22552-10.444539 1.331167-14.540436 1.715157c-0.895978 1.791955-1.663958 4.070298-2.329542 6.835029s-0.972776 5.427064-0.972776 8.012599c0 5.811055 2.303942 10.290943 6.911828 13.490863s10.956526 4.81268 19.045923 4.81268c4.710282 0 9.19017-0.537587 13.490863-1.58716s8.370991-2.40634 12.236494-4.044699 7.475013-3.455914 10.879728-5.401465 6.502237-3.865503 9.292568-5.785456c3.60951-2.40634 7.014225-4.428689 10.265343-6.067048s6.118247-2.483138 8.626985-2.483138 4.095898 0.614385 4.812679 1.868753 1.049574 2.585535 1.049574 3.967901a34.251944 34.251944 0 0 1-0.307192 4.198295 25.804155 25.804155 0 0 1-8.703783 14.566036c-10.39334 8.191795-21.068273 14.054049-32.024799 17.561161s-22.629834 5.247869-35.019925 5.247869c-2.40634 0-5.222269-0.153596-8.473388-0.460789s-6.630234-0.895978-10.137346-1.791955-6.937427-2.201545-10.342142-3.891103a31.538412 31.538412 0 0 1-15.513212-17.100372 40.037399 40.037399 0 0 1-2.483138-14.847629c0-4.710282 0.639984-9.958151 1.945552-15.743606-1.305567-0.204795-2.534337-0.870378-3.686308-2.02235s-1.715157-2.81593-1.715157-5.017474z m93.898452-41.547762c0.204795-0.511987 0.307192-0.947176 0.307192-1.356766v-1.356766c0-2.687933-0.998375-4.735882-2.995125-6.067048s-4.40309-2.022349-7.19342-2.022349c-4.40309 0-8.729382 1.151971-12.978875 3.455913s-8.242994 5.171071-12.0061 8.626984-7.065423 7.142221-9.983751 11.110123-5.145471 7.526212-6.758231 10.726132c7.19342-0.588785 13.798055-1.58716 19.788306-2.918327s11.21252-3.046324 15.666808-5.094273 8.038199-4.351891 10.80293-6.911827 4.556686-5.299068 5.350266-8.191796zM818.347541 499.929902c0.511987-3.9935 1.305567-7.705407 2.40634-11.110122s2.585535-6.220644 4.428689-8.473389 4.223894-3.379116 7.116623-3.379115c1.61276 0 3.379116 0.307192 5.324666 0.895977s3.788705 1.433564 5.555062 2.483138 3.225519 2.329542 4.428689 3.814305 1.791955 3.148721 1.791955 4.940676c0 0.79358-0.153596 1.715157-0.460788 2.764731s-0.537587 2.073548-0.742382 3.071924l-37.503062 150.293842c-1.510362 5.99025-2.739132 11.724507-3.737507 17.177171s-1.740756 9.932552-2.252744 13.414064v3.60951c0 2.995125-0.204795 6.271843-0.588785 9.830154s-1.151971 6.860628-2.252744 9.906953-2.636734 5.60626-4.582285 7.654208-4.479888 3.071923-7.577411 3.071924c-2.687933 0-5.043074-0.563186-7.039824-1.715158s-3.660708-2.636734-4.940676-4.428689-2.252744-3.737507-2.841529-5.785455-0.895978-3.967901-0.895978-5.785456c0-1.61276 0.153596-3.58391 0.460789-5.913452s0.665583-4.81268 1.126372-7.347016 0.921577-5.094273 1.433564-7.654209 0.998375-4.78708 1.510362-6.681433l38.706232-153.59616a193.275168 193.275168 0 0 1 1.126372-11.058923z" fill="#FFFFFF" p-id="1446"></path></svg> | |
| \ No newline at end of file | ... | ... |
| ... | ... | @@ -191,6 +191,10 @@ |
| 191 | 191 | <slot name="afterFullScreen"></slot> |
| 192 | 192 | </div> |
| 193 | 193 | </div> |
| 194 | - <div ref="jsonEditorElRef" class="flex-auto"></div> | |
| 194 | + <div | |
| 195 | + ref="jsonEditorElRef" | |
| 196 | + class="flex-auto" | |
| 197 | + :style="{ backgroundColor: disabled ? '#f0f0f0' : '' }" | |
| 198 | + ></div> | |
| 195 | 199 | </div> |
| 196 | 200 | </template> | ... | ... |
| ... | ... | @@ -47,6 +47,7 @@ |
| 47 | 47 | isClose: { type: Boolean, default: true }, |
| 48 | 48 | title: { type: String, default: '' }, |
| 49 | 49 | loading: { type: Boolean }, |
| 50 | + defaultExpand: { type: Boolean, default: true }, | |
| 50 | 51 | /** |
| 51 | 52 | * Can it be expanded |
| 52 | 53 | */ |
| ... | ... | @@ -75,7 +76,7 @@ |
| 75 | 76 | |
| 76 | 77 | const emit = defineEmits(['expand', 'change', 'hchange']); |
| 77 | 78 | |
| 78 | - const show = ref(true); | |
| 79 | + const show = ref(props.defaultExpand); | |
| 79 | 80 | |
| 80 | 81 | const { prefixCls } = useDesign('collapse-container'); |
| 81 | 82 | ... | ... |
| ... | ... | @@ -15,6 +15,8 @@ export { default as ApiUpload } from './src/components/ApiUpload.vue'; |
| 15 | 15 | export { default as StructForm } from './src/externalCompns/components/StructForm/StructForm.vue'; |
| 16 | 16 | export { default as JavaScriptFunctionEditor } from './src/components/JavaScriptFunctionEditor.vue'; |
| 17 | 17 | |
| 18 | +export { ThingsModelForm } from './src/externalCompns/components/ThingsModelForm'; | |
| 19 | + | |
| 18 | 20 | //注册自定义组件 |
| 19 | 21 | export { |
| 20 | 22 | JEasyCron, | ... | ... |
| ... | ... | @@ -69,7 +69,7 @@ |
| 69 | 69 | name: 'BasicForm', |
| 70 | 70 | components: { FormItem, Form, Row, FormAction }, |
| 71 | 71 | props: basicProps, |
| 72 | - emits: ['advanced-change', 'reset', 'submit', 'register'], | |
| 72 | + emits: ['advanced-change', 'reset', 'submit', 'register', 'fieldValueChange'], | |
| 73 | 73 | setup(props, { emit, attrs }) { |
| 74 | 74 | const formModel = reactive<Recordable>({}); |
| 75 | 75 | const modalFn = useModalContext(); |
| ... | ... | @@ -230,6 +230,7 @@ |
| 230 | 230 | |
| 231 | 231 | function setFormModel(key: string, value: any) { |
| 232 | 232 | formModel[key] = value; |
| 233 | + emit('fieldValueChange', key, value); | |
| 233 | 234 | const { validateTrigger } = unref(getBindValue); |
| 234 | 235 | if (!validateTrigger || validateTrigger === 'change') { |
| 235 | 236 | validateFields([key]).catch((_) => {}); | ... | ... |
| ... | ... | @@ -4,77 +4,102 @@ |
| 4 | 4 | <!-- 待完善封装InputGroup --> |
| 5 | 5 | <InputGroup compact> |
| 6 | 6 | <Select |
| 7 | - v-if="type !== '2'" | |
| 7 | + v-if="type !== RequestMethodTypeEnum.WEBSOCKET" | |
| 8 | 8 | placeholder="请求类型" |
| 9 | - :style="{ width: type !== '2' ? 15 + '%' : 0 + '%' }" | |
| 10 | - v-model:value="valueObj.requestHttpType" | |
| 9 | + :style="{ width: type !== RequestMethodTypeEnum.WEBSOCKET ? 15 + '%' : 0 + '%' }" | |
| 10 | + v-model:value="requestTypeUrlValue.requestHttpType" | |
| 11 | 11 | :options="selectOptions" |
| 12 | 12 | allowClear |
| 13 | 13 | @change="emitChange" |
| 14 | 14 | /> |
| 15 | 15 | <Input |
| 16 | - @change="emitChange" | |
| 17 | 16 | placeholder="请输入接口地址" |
| 18 | - v-model:value="valueObj.requestUrl" | |
| 19 | - :style="{ width: type !== '2' ? 85 + '%' : 100 + '%' }" | |
| 17 | + v-model:value="requestTypeUrlValue.requestUrl" | |
| 18 | + :style="{ width: type !== RequestMethodTypeEnum.WEBSOCKET ? 85 + '%' : 100 + '%' }" | |
| 19 | + @change="emitChange" | |
| 20 | 20 | /> |
| 21 | 21 | </InputGroup> |
| 22 | 22 | </div> |
| 23 | 23 | </template> |
| 24 | 24 | <script lang="ts" setup> |
| 25 | - import { reactive, ref, watchEffect } from 'vue'; | |
| 25 | + import { reactive, ref, PropType, watch } from 'vue'; | |
| 26 | 26 | import { InputGroup, Select, Input } from 'ant-design-vue'; |
| 27 | - import type { SelectValue } from 'ant-design-vue/lib/select'; | |
| 28 | 27 | import { findDictItemByCode } from '/@/api/system/dict'; |
| 29 | - import { propTypes } from '/@/utils/propTypes'; | |
| 28 | + import { RequestMethodTypeEnum } from '/@/views/dataview/publicApi/config/enum'; | |
| 30 | 29 | |
| 31 | - type TypeInputGroup = { | |
| 32 | - requestHttpType: SelectValue | undefined; | |
| 30 | + interface requestTypeUrlConfig { | |
| 31 | + requestHttpType: undefined; | |
| 33 | 32 | requestUrl?: string; |
| 34 | 33 | disabled?: boolean; |
| 35 | - }; | |
| 34 | + } | |
| 36 | 35 | |
| 37 | - type selectType = { label: string; value: string; disabled?: boolean }; | |
| 36 | + type selectType = { | |
| 37 | + label: string; | |
| 38 | + value: string; | |
| 39 | + }; | |
| 38 | 40 | |
| 39 | 41 | const props = defineProps({ |
| 40 | 42 | type: { |
| 41 | 43 | type: String, |
| 44 | + default: RequestMethodTypeEnum.COMMOM, | |
| 42 | 45 | }, |
| 43 | - value: propTypes.object.def({}), | |
| 46 | + value: Object as PropType<requestTypeUrlConfig>, | |
| 44 | 47 | }); |
| 45 | 48 | |
| 46 | 49 | const emits = defineEmits(['change', 'update:value']); |
| 47 | 50 | |
| 48 | 51 | const selectOptions = ref<selectType[]>([]); |
| 49 | 52 | |
| 50 | - const getOptions = async (e) => { | |
| 51 | - const res = await findDictItemByCode({ | |
| 52 | - dictCode: e === '1' ? 'dataview_select_sql_request' : 'dataview_select_request', | |
| 53 | + const getOptions = async (requestType) => { | |
| 54 | + // 暂且排除SQL和WEBSOCKET | |
| 55 | + const resItem = await findDictItemByCode({ | |
| 56 | + dictCode: 'dataview_select_request', | |
| 53 | 57 | }); |
| 54 | - if (e === '1' || e === '0') { | |
| 55 | - selectOptions.value = res.map((m) => ({ label: m.itemText, value: m.itemValue })); | |
| 58 | + if (requestType === RequestMethodTypeEnum.COMMOM) { | |
| 59 | + selectOptions.value = resItem.map((m) => ({ label: m.itemText, value: m.itemValue })); | |
| 56 | 60 | } else { |
| 57 | 61 | selectOptions.value = []; |
| 58 | 62 | } |
| 59 | 63 | }; |
| 60 | 64 | |
| 61 | - const valueObj = reactive<TypeInputGroup>({ | |
| 65 | + const requestTypeUrlValue = reactive<requestTypeUrlConfig>({ | |
| 62 | 66 | requestHttpType: undefined, |
| 63 | 67 | requestUrl: '', |
| 64 | 68 | }); |
| 65 | 69 | |
| 66 | - watchEffect(() => { | |
| 67 | - initVal(); | |
| 68 | - }); | |
| 70 | + watch( | |
| 71 | + () => props.type, | |
| 72 | + () => { | |
| 73 | + initOption(); | |
| 74 | + }, | |
| 75 | + { | |
| 76 | + immediate: true, | |
| 77 | + } | |
| 78 | + ); | |
| 79 | + | |
| 80 | + watch( | |
| 81 | + () => props.value, | |
| 82 | + () => { | |
| 83 | + initConfig(); | |
| 84 | + }, | |
| 85 | + { | |
| 86 | + immediate: true, | |
| 87 | + } | |
| 88 | + ); | |
| 89 | + | |
| 90 | + function initOption() { | |
| 91 | + if (props.type) { | |
| 92 | + getOptions(props.type); | |
| 93 | + } | |
| 94 | + } | |
| 69 | 95 | |
| 70 | - async function initVal() { | |
| 71 | - if (props?.type) await getOptions(props?.type); | |
| 72 | - if (props?.value) for (let i in props.value) Reflect.set(valueObj, i, props.value[i]); | |
| 96 | + function initConfig() { | |
| 97 | + if (props?.value) | |
| 98 | + for (let i in props.value) Reflect.set(requestTypeUrlValue, i, props.value[i]); | |
| 73 | 99 | } |
| 74 | 100 | |
| 75 | 101 | function emitChange() { |
| 76 | - emits('change', valueObj); | |
| 77 | - emits('update:value', valueObj); | |
| 102 | + emits('change', requestTypeUrlValue); | |
| 103 | + emits('update:value', requestTypeUrlValue); | |
| 78 | 104 | } |
| 79 | 105 | </script> |
| 80 | -<style scoped></style> | ... | ... |
| 1 | 1 | <script lang="ts" setup> |
| 2 | - import { Button, Transfer, Tag } from 'ant-design-vue'; | |
| 2 | + import { Transfer, Select } from 'ant-design-vue'; | |
| 3 | 3 | import { cloneDeep, get } from 'lodash-es'; |
| 4 | 4 | import { computed, CSSProperties, ExtractPropTypes, onMounted, ref, unref, watch } from 'vue'; |
| 5 | 5 | import { BasicModal, useModal } from '/@/components/Modal'; |
| ... | ... | @@ -29,7 +29,7 @@ |
| 29 | 29 | buttonName?: string; |
| 30 | 30 | modalProps?: ExtractPropTypes<InstanceType<typeof BasicModal>['$props']>; |
| 31 | 31 | transferProps?: ExtractPropTypes<TransferType['$props']>; |
| 32 | - buttonProps?: ExtractPropTypes<InstanceType<typeof Button>['$props']>; | |
| 32 | + selectProps?: ExtractPropTypes<InstanceType<typeof Select>['$props']>; | |
| 33 | 33 | disabled?: any; |
| 34 | 34 | }>(), |
| 35 | 35 | { |
| ... | ... | @@ -52,24 +52,15 @@ |
| 52 | 52 | return unref(getOptions).filter((item) => unref(targetKeys).includes(item[valueField])); |
| 53 | 53 | }); |
| 54 | 54 | |
| 55 | - const getShowTagOptions = computed(() => { | |
| 56 | - const { maxTagLength } = props; | |
| 57 | - return unref(targetOptions).slice(0, maxTagLength); | |
| 55 | + const getSelectOptions = computed(() => { | |
| 56 | + return unref(targetOptions).map((item) => ({ ...item, label: item.title, value: item.key })); | |
| 58 | 57 | }); |
| 59 | 58 | |
| 60 | - const getSurplusOptionsLength = computed(() => { | |
| 61 | - const { maxTagLength } = props; | |
| 62 | - const surplusValue = unref(targetKeys).length - maxTagLength; | |
| 63 | - return surplusValue < 0 ? 0 : surplusValue; | |
| 64 | - }); | |
| 65 | - | |
| 66 | - const count = computed(() => { | |
| 67 | - return unref(targetKeys).length; | |
| 68 | - }); | |
| 59 | + const getSelectValue = computed(() => unref(getSelectOptions).map((item) => item.value)); | |
| 69 | 60 | |
| 70 | 61 | const targetKeys = ref<string[]>(props.value || []); |
| 71 | 62 | |
| 72 | - const getOptions = computed<Recordable[]>(() => { | |
| 63 | + const getOptions = computed<Record<'key' | 'title', string>[]>(() => { | |
| 73 | 64 | const { labelField, valueField } = props; |
| 74 | 65 | return unref(options).map((item) => ({ |
| 75 | 66 | ...item, |
| ... | ... | @@ -99,13 +90,14 @@ |
| 99 | 90 | }; |
| 100 | 91 | }); |
| 101 | 92 | |
| 102 | - const getBindButtonProps = computed(() => { | |
| 103 | - const { buttonProps = {} } = props; | |
| 93 | + const getBindSelectProps = computed(() => { | |
| 94 | + const { selectProps = {} } = props; | |
| 104 | 95 | return { |
| 105 | - ...buttonProps, | |
| 106 | - type: 'link', | |
| 107 | - onClick: handleOpenModal, | |
| 108 | - } as ExtractPropTypes<InstanceType<typeof Button>['$props']>; | |
| 96 | + maxTagCount: 3, | |
| 97 | + ...selectProps, | |
| 98 | + open: false, | |
| 99 | + onDropdownVisibleChange: handleOpenModal, | |
| 100 | + } as ExtractPropTypes<InstanceType<typeof Select>['$props']>; | |
| 109 | 101 | }); |
| 110 | 102 | |
| 111 | 103 | const handleChange = (_targetKeys: string[], direction: 'left' | 'right', moveKeys: string[]) => { |
| ... | ... | @@ -165,22 +157,11 @@ |
| 165 | 157 | <Transfer v-bind="getBindProps" /> |
| 166 | 158 | </section> |
| 167 | 159 | </BasicModal> |
| 168 | - <Button v-bind="getBindButtonProps" class="!flex !justify-center !items-center min-h-8"> | |
| 169 | - <span v-if="!count">{{ $props.buttonName }}</span> | |
| 170 | - <div v-if="!!count"> | |
| 171 | - <Tag | |
| 172 | - class="!px-2 !py-1 !bg-gray-50 !border-gray-100" | |
| 173 | - v-for="item in getShowTagOptions" | |
| 174 | - :key="item.key" | |
| 175 | - > | |
| 176 | - <span> | |
| 177 | - {{ item.title }} | |
| 178 | - </span> | |
| 179 | - </Tag> | |
| 180 | - <Tag class="!px-2 !py-1 !bg-gray-50 !border-gray-100" v-if="getSurplusOptionsLength"> | |
| 181 | - <span> +{{ getSurplusOptionsLength }}... </span> | |
| 182 | - </Tag> | |
| 183 | - </div> | |
| 184 | - </Button> | |
| 160 | + <Select | |
| 161 | + v-bind="getBindSelectProps" | |
| 162 | + :options="getSelectOptions" | |
| 163 | + :value="getSelectValue" | |
| 164 | + mode="multiple" | |
| 165 | + /> | |
| 185 | 166 | </div> |
| 186 | 167 | </template> | ... | ... |
src/components/Form/src/components/TransferTableModal.vue
deleted
100644 → 0
| 1 | -<script lang="ts" setup> | |
| 2 | - import { Button, Tabs, Badge, ButtonProps, Tag } from 'ant-design-vue'; | |
| 3 | - import { get, isFunction, set, uniqBy } from 'lodash-es'; | |
| 4 | - import { ExtractPropTypes, computed, unref, ref, nextTick, onMounted, watch } from 'vue'; | |
| 5 | - import { DynamicProps } from '/#/utils'; | |
| 6 | - import { BasicModal, useModal } from '/@/components/Modal'; | |
| 7 | - import { BasicTable, BasicTableProps, TableRowSelection, useTable } from '/@/components/Table'; | |
| 8 | - import { FETCH_SETTING } from '/@/components/Table/src/const'; | |
| 9 | - import { useDesign } from '/@/hooks/web/useDesign'; | |
| 10 | - | |
| 11 | - interface Options extends Recordable { | |
| 12 | - primaryKey?: string; | |
| 13 | - disabled?: boolean; | |
| 14 | - } | |
| 15 | - | |
| 16 | - enum Active { | |
| 17 | - PENDING = 'pending', | |
| 18 | - SELECTED = 'selected', | |
| 19 | - } | |
| 20 | - | |
| 21 | - interface ActionType { | |
| 22 | - setSelectedOptions: (options: Recordable[]) => void; | |
| 23 | - } | |
| 24 | - | |
| 25 | - const emit = defineEmits(['change', 'update:value']); | |
| 26 | - | |
| 27 | - const props = withDefaults( | |
| 28 | - defineProps<{ | |
| 29 | - value?: string[]; | |
| 30 | - labelField?: string; | |
| 31 | - valueField?: string; | |
| 32 | - primaryKey?: string; | |
| 33 | - params?: Recordable; | |
| 34 | - buttonName?: string; | |
| 35 | - pendingTableProps?: BasicTableProps; | |
| 36 | - selectedTableProps?: BasicTableProps; | |
| 37 | - maxTagLength?: number; | |
| 38 | - modalProps?: ExtractPropTypes<InstanceType<typeof BasicModal>['$props']>; | |
| 39 | - buttonProps?: ExtractPropTypes<InstanceType<typeof Button>['$props']>; | |
| 40 | - initSelectedOptions?: (actionType: ActionType) => Promise<Recordable[]>; | |
| 41 | - transformValue?: (selectedRowKeys: string[], selectedRows: Options[]) => any[]; | |
| 42 | - onValueChange?: (selectedRowkeys: string[]) => any[]; | |
| 43 | - onRemoveAfter?: (actionType: ActionType) => Promise<any>; | |
| 44 | - onSelectedAfter?: (actionType: ActionType) => Promise<any>; | |
| 45 | - disabled?: any; | |
| 46 | - }>(), | |
| 47 | - { | |
| 48 | - buttonName: '选择设备', | |
| 49 | - primaryKey: 'id', | |
| 50 | - maxTagLength: 2, | |
| 51 | - labelField: 'label', | |
| 52 | - valueField: 'value', | |
| 53 | - disabled: false, | |
| 54 | - } | |
| 55 | - ); | |
| 56 | - | |
| 57 | - const { prefixCls } = useDesign('transfer-table-modal'); | |
| 58 | - | |
| 59 | - const activeKey = ref<Active>(Active.PENDING); | |
| 60 | - | |
| 61 | - const selectedRows = ref<Options[]>([]); | |
| 62 | - | |
| 63 | - const selectedRowKeys = ref<string[]>(props.value || []); | |
| 64 | - | |
| 65 | - const pendingOptions = ref<Options[]>([]); | |
| 66 | - | |
| 67 | - const selectedConfirmQueue = ref<Options[]>([]); | |
| 68 | - | |
| 69 | - const pendingConfirmQueue = ref<Options[]>([]); | |
| 70 | - | |
| 71 | - const selectedTotal = ref(0); | |
| 72 | - | |
| 73 | - const pendingTotal = ref(0); | |
| 74 | - | |
| 75 | - const getFetchSetting = computed(() => { | |
| 76 | - const { pendingTableProps } = props; | |
| 77 | - return pendingTableProps?.fetchSetting || FETCH_SETTING; | |
| 78 | - }); | |
| 79 | - | |
| 80 | - const getPendingRowSelection = computed<TableRowSelection>(() => { | |
| 81 | - const rowKeys = unref(selectedRowKeys); | |
| 82 | - return { | |
| 83 | - type: 'checkbox', | |
| 84 | - getCheckboxProps: (record: Recordable) => { | |
| 85 | - const { primaryKey } = props; | |
| 86 | - return { | |
| 87 | - ...record, | |
| 88 | - disabled: rowKeys.includes(record[primaryKey]), | |
| 89 | - }; | |
| 90 | - }, | |
| 91 | - onSelect: (_record: Recordable, _selected: boolean, selectedRows: Object[]) => { | |
| 92 | - pendingConfirmQueue.value = selectedRows; | |
| 93 | - }, | |
| 94 | - onSelectAll: (_selected: boolean, selectedRows: Recordable[]) => { | |
| 95 | - pendingConfirmQueue.value = selectedRows; | |
| 96 | - }, | |
| 97 | - }; | |
| 98 | - }); | |
| 99 | - | |
| 100 | - const getPendingTableBindProps = computed<Partial<DynamicProps<BasicTableProps>>>(() => { | |
| 101 | - const { pendingTableProps, primaryKey } = props; | |
| 102 | - return { | |
| 103 | - ...pendingTableProps, | |
| 104 | - rowKey: primaryKey, | |
| 105 | - api: handlePendingApiIntercept, | |
| 106 | - clickToRowSelect: false, | |
| 107 | - rowSelection: getPendingRowSelection, | |
| 108 | - }; | |
| 109 | - }); | |
| 110 | - | |
| 111 | - const getSelectedTableBindProps = computed<Partial<DynamicProps<BasicTableProps>>>(() => { | |
| 112 | - const { selectedTableProps, primaryKey } = props; | |
| 113 | - return { | |
| 114 | - ...selectedTableProps, | |
| 115 | - dataSource: selectedRows, | |
| 116 | - clickToRowSelect: false, | |
| 117 | - rowKey: primaryKey, | |
| 118 | - api: selectedTableProps!.api ? handleSelectedApiIntercept : undefined, | |
| 119 | - rowSelection: { | |
| 120 | - type: 'checkbox', | |
| 121 | - onSelect: (_record: Recordable, _selected: boolean, selectedRows: Object[]) => { | |
| 122 | - selectedConfirmQueue.value = selectedRows; | |
| 123 | - }, | |
| 124 | - onSelectAll: (_selected: boolean, selectedRows: Recordable[]) => { | |
| 125 | - selectedConfirmQueue.value = selectedRows; | |
| 126 | - }, | |
| 127 | - }, | |
| 128 | - }; | |
| 129 | - }); | |
| 130 | - | |
| 131 | - const getModalBindProps = computed(() => { | |
| 132 | - const { modalProps = {} } = props; | |
| 133 | - return { | |
| 134 | - width: '60%', | |
| 135 | - title: '穿梭表格', | |
| 136 | - wrapClassName: prefixCls, | |
| 137 | - ...modalProps, | |
| 138 | - showOkBtn: false, | |
| 139 | - }; | |
| 140 | - }); | |
| 141 | - | |
| 142 | - const getBindButtonProps = computed<ButtonProps>(() => { | |
| 143 | - const { buttonProps = {} } = props; | |
| 144 | - return { | |
| 145 | - type: 'link', | |
| 146 | - ...buttonProps, | |
| 147 | - }; | |
| 148 | - }); | |
| 149 | - | |
| 150 | - const getShowTagOptions = computed(() => { | |
| 151 | - const { maxTagLength } = props; | |
| 152 | - return unref(selectedRows).slice(0, maxTagLength); | |
| 153 | - }); | |
| 154 | - | |
| 155 | - const getSurplusOptionsLength = computed(() => { | |
| 156 | - const { maxTagLength } = props; | |
| 157 | - const surplusValue = unref(selectedRows).length - maxTagLength; | |
| 158 | - return surplusValue < 0 ? 0 : surplusValue; | |
| 159 | - }); | |
| 160 | - | |
| 161 | - const [registerModal, { openModal }] = useModal(); | |
| 162 | - | |
| 163 | - const [ | |
| 164 | - regsterPendingTable, | |
| 165 | - { | |
| 166 | - getSelectRows: getPendingSelectRows, | |
| 167 | - getSelectRowKeys: getPendingSelectRowKeys, | |
| 168 | - reload: reloadPending, | |
| 169 | - clearSelectedRowKeys: clearPendingSelectedRowKeys, | |
| 170 | - }, | |
| 171 | - ] = useTable(unref(getPendingTableBindProps)); | |
| 172 | - | |
| 173 | - const [ | |
| 174 | - registerSelectedTable, | |
| 175 | - { getSelectRowKeys, setProps, clearSelectedRowKeys, reload: reloadSelected }, | |
| 176 | - ] = useTable(unref(getSelectedTableBindProps)); | |
| 177 | - | |
| 178 | - async function handlePendingApiIntercept(params?: Recordable) { | |
| 179 | - try { | |
| 180 | - const { api } = props.pendingTableProps || {}; | |
| 181 | - if (api && isFunction(api)) { | |
| 182 | - let options = await api(params); | |
| 183 | - pendingOptions.value = options; | |
| 184 | - const { totalField, listField } = unref(getFetchSetting); | |
| 185 | - const total = get(options, totalField!); | |
| 186 | - if (unref(selectedTotal) + unref(pendingTotal) !== total) { | |
| 187 | - pendingTotal.value = total; | |
| 188 | - } | |
| 189 | - let list: Recordable[] = get(options, listField!); | |
| 190 | - list = getSelectedRows(list); | |
| 191 | - options = set(options, listField!, list); | |
| 192 | - return options; | |
| 193 | - } | |
| 194 | - } catch (error) { | |
| 195 | - console.error(error); | |
| 196 | - return []; | |
| 197 | - } | |
| 198 | - return []; | |
| 199 | - } | |
| 200 | - | |
| 201 | - async function handleSelectedApiIntercept(params?: Recordable) { | |
| 202 | - try { | |
| 203 | - const { api } = props.selectedTableProps || {}; | |
| 204 | - if (api && isFunction(api)) { | |
| 205 | - let options = await api(params); | |
| 206 | - pendingOptions.value = options; | |
| 207 | - const { totalField, listField } = unref(getFetchSetting); | |
| 208 | - selectedTotal.value = get(options, totalField!); | |
| 209 | - let list: Recordable[] = get(options, listField!); | |
| 210 | - list = getSelectedRows(list); | |
| 211 | - options = set(options, listField!, list); | |
| 212 | - return options; | |
| 213 | - } | |
| 214 | - } catch (error) { | |
| 215 | - console.error(error); | |
| 216 | - return []; | |
| 217 | - } | |
| 218 | - return []; | |
| 219 | - } | |
| 220 | - | |
| 221 | - const handleOpenModal = async () => { | |
| 222 | - const { disabled } = props; | |
| 223 | - if (disabled) return; | |
| 224 | - openModal(true); | |
| 225 | - await nextTick(); | |
| 226 | - if (props.value && !props.value.length) { | |
| 227 | - activeKey.value = Active.PENDING; | |
| 228 | - reloadPending(); | |
| 229 | - } | |
| 230 | - }; | |
| 231 | - | |
| 232 | - const handleTriggerEmit = (selectedRowKeys: string[], selectedRows: Options[]) => { | |
| 233 | - const { transformValue } = props; | |
| 234 | - let value = selectedRowKeys; | |
| 235 | - if (transformValue && isFunction(transformValue)) { | |
| 236 | - value = transformValue(selectedRowKeys, selectedRows); | |
| 237 | - } | |
| 238 | - emit('change', unref(selectedRowKeys), unref(selectedRows)); | |
| 239 | - emit('update:value', unref(value)); | |
| 240 | - }; | |
| 241 | - | |
| 242 | - const handleSelected = async () => { | |
| 243 | - const { onSelectedAfter } = props; | |
| 244 | - const currentPageSelectRows = getPendingSelectRows(); | |
| 245 | - const currentPageSelectRowKeys = getPendingSelectRowKeys(); | |
| 246 | - const { primaryKey } = props; | |
| 247 | - selectedRows.value = uniqBy([...unref(selectedRows), ...currentPageSelectRows], primaryKey); | |
| 248 | - selectedRowKeys.value = [...new Set([...unref(selectedRowKeys), ...currentPageSelectRowKeys])]; | |
| 249 | - pendingConfirmQueue.value = []; | |
| 250 | - // selectedTotal.value = unref(selectedRowKeys).length; | |
| 251 | - pendingTotal.value = unref(pendingTotal) - currentPageSelectRows.length; | |
| 252 | - selectedTotal.value = unref(selectedTotal) + currentPageSelectRows.length; | |
| 253 | - | |
| 254 | - clearPendingSelectedRowKeys(); | |
| 255 | - handleTriggerEmit(unref(selectedRowKeys), unref(selectedRows)); | |
| 256 | - | |
| 257 | - if (onSelectedAfter && isFunction(onSelectedAfter)) { | |
| 258 | - await onSelectedAfter(actionType); | |
| 259 | - } | |
| 260 | - reloadPending(); | |
| 261 | - }; | |
| 262 | - | |
| 263 | - const handleRemoveSelected = async () => { | |
| 264 | - const { onRemoveAfter } = props; | |
| 265 | - const removeRowKeys = getSelectRowKeys(); | |
| 266 | - selectedRowKeys.value = unref(selectedRowKeys).filter((key) => !removeRowKeys.includes(key)); | |
| 267 | - selectedRows.value = unref(selectedRows).filter((item) => { | |
| 268 | - const { primaryKey } = props; | |
| 269 | - return unref(selectedRowKeys).includes(item[primaryKey]); | |
| 270 | - }); | |
| 271 | - pendingTotal.value = unref(pendingTotal) + removeRowKeys.length; | |
| 272 | - selectedTotal.value = unref(selectedTotal) - removeRowKeys.length; | |
| 273 | - | |
| 274 | - clearSelectedRowKeys(); | |
| 275 | - selectedConfirmQueue.value = []; | |
| 276 | - setProps({ dataSource: unref(selectedRows) }); | |
| 277 | - handleTriggerEmit(unref(selectedRowKeys), unref(selectedRows)); | |
| 278 | - | |
| 279 | - if (onRemoveAfter && isFunction(onRemoveAfter)) { | |
| 280 | - await onRemoveAfter(actionType); | |
| 281 | - } | |
| 282 | - }; | |
| 283 | - | |
| 284 | - const actionType = { | |
| 285 | - setSelectedOptions, | |
| 286 | - setSelectedTotal, | |
| 287 | - reloadPending, | |
| 288 | - reloadSelected, | |
| 289 | - }; | |
| 290 | - | |
| 291 | - const getSelectedRows = (options: Recordable[]) => { | |
| 292 | - const { labelField, valueField } = props; | |
| 293 | - return options.map((item) => ({ ...item, label: item[labelField], value: item[valueField] })); | |
| 294 | - }; | |
| 295 | - | |
| 296 | - const getSelectedKeys = (options: Recordable[]) => { | |
| 297 | - const { primaryKey } = props; | |
| 298 | - return options.map((item) => item[primaryKey]); | |
| 299 | - }; | |
| 300 | - | |
| 301 | - function setSelectedOptions(options: Recordable[]) { | |
| 302 | - selectedRows.value = getSelectedRows(options); | |
| 303 | - selectedRowKeys.value = getSelectedKeys(options); | |
| 304 | - } | |
| 305 | - | |
| 306 | - function setSelectedTotal(number: number) { | |
| 307 | - selectedTotal.value = number; | |
| 308 | - } | |
| 309 | - | |
| 310 | - const handleCheckoutPanel = async (keys: Active) => { | |
| 311 | - await nextTick(); | |
| 312 | - if (keys === Active.PENDING) { | |
| 313 | - reloadPending(); | |
| 314 | - } else { | |
| 315 | - reloadSelected(); | |
| 316 | - setProps({ | |
| 317 | - dataSource: unref(selectedRows), | |
| 318 | - }); | |
| 319 | - } | |
| 320 | - }; | |
| 321 | - | |
| 322 | - watch( | |
| 323 | - () => props.value, | |
| 324 | - () => { | |
| 325 | - if (props.value && !props.value.length) { | |
| 326 | - selectedRowKeys.value = []; | |
| 327 | - selectedRows.value = []; | |
| 328 | - // pendingTotal.value = 0; | |
| 329 | - selectedTotal.value = 0; | |
| 330 | - } | |
| 331 | - } | |
| 332 | - ); | |
| 333 | - | |
| 334 | - onMounted(async () => { | |
| 335 | - const { initSelectedOptions } = props; | |
| 336 | - if (initSelectedOptions && isFunction(initSelectedOptions)) { | |
| 337 | - const options = await initSelectedOptions(actionType); | |
| 338 | - setSelectedOptions(options); | |
| 339 | - } | |
| 340 | - }); | |
| 341 | -</script> | |
| 342 | - | |
| 343 | -<template> | |
| 344 | - <section> | |
| 345 | - <BasicModal @register="registerModal" v-bind="getModalBindProps"> | |
| 346 | - <section class="bg-gray-100"> | |
| 347 | - <Tabs v-model:active-key="activeKey" type="card" @change="handleCheckoutPanel"> | |
| 348 | - <Tabs.TabPane :key="Active.PENDING"> | |
| 349 | - <template #tab> | |
| 350 | - <div class="flex items-center justify-center"> | |
| 351 | - <span>待选设备</span> | |
| 352 | - <Badge show-zero :count="pendingTotal" /> | |
| 353 | - </div> | |
| 354 | - </template> | |
| 355 | - <BasicTable @register="regsterPendingTable"> | |
| 356 | - <template #toolbar> | |
| 357 | - <section class="flex w-full justify-end items-center"> | |
| 358 | - <!-- <Button type="primary">全选</Button> --> | |
| 359 | - <div class="text-blue-400"> | |
| 360 | - <span class="mr-2">选择设备:</span> | |
| 361 | - <span>{{ pendingConfirmQueue.length }}</span> | |
| 362 | - </div> | |
| 363 | - </section> | |
| 364 | - </template> | |
| 365 | - </BasicTable> | |
| 366 | - <section class="flex justify-end px-4 pb-4"> | |
| 367 | - <Button | |
| 368 | - type="primary" | |
| 369 | - @click="handleSelected" | |
| 370 | - :disabled="!pendingConfirmQueue.length" | |
| 371 | - > | |
| 372 | - <span>确定已选</span> | |
| 373 | - </Button> | |
| 374 | - </section> | |
| 375 | - </Tabs.TabPane> | |
| 376 | - <Tabs.TabPane :key="Active.SELECTED"> | |
| 377 | - <template #tab> | |
| 378 | - <div class="flex items-center justify-center"> | |
| 379 | - <span>已选设备</span> | |
| 380 | - <Badge show-zero :count="selectedTotal" /> | |
| 381 | - </div> | |
| 382 | - </template> | |
| 383 | - <BasicTable @register="registerSelectedTable"> | |
| 384 | - <template #toolbar> | |
| 385 | - <section class="flex w-full justify-end items-center"> | |
| 386 | - <!-- <Button type="primary">全选</Button> --> | |
| 387 | - <div class="text-blue-400"> | |
| 388 | - <span class="mr-2">选择设备:</span> | |
| 389 | - <span>{{ selectedConfirmQueue.length }}</span> | |
| 390 | - </div> | |
| 391 | - </section> | |
| 392 | - </template> | |
| 393 | - </BasicTable> | |
| 394 | - <section class="flex justify-end px-4 pb-4"> | |
| 395 | - <Button | |
| 396 | - type="primary" | |
| 397 | - :disabled="!selectedConfirmQueue.length" | |
| 398 | - @click="handleRemoveSelected" | |
| 399 | - > | |
| 400 | - <span>移除已选</span> | |
| 401 | - </Button> | |
| 402 | - </section> | |
| 403 | - </Tabs.TabPane> | |
| 404 | - </Tabs> | |
| 405 | - </section> | |
| 406 | - </BasicModal> | |
| 407 | - <Button @click="handleOpenModal" v-bind="getBindButtonProps"> | |
| 408 | - <span v-if="!selectedRowKeys.length">选择设备</span> | |
| 409 | - <div v-if="selectedRowKeys.length"> | |
| 410 | - <Tag | |
| 411 | - class="!px-2 !py-1 !bg-gray-50 !border-gray-100" | |
| 412 | - v-for="item in getShowTagOptions" | |
| 413 | - :key="item.value" | |
| 414 | - > | |
| 415 | - <span> | |
| 416 | - {{ item.alias || item.name }} | |
| 417 | - </span> | |
| 418 | - </Tag> | |
| 419 | - <Tag class="!px-2 !py-1 !bg-gray-50 !border-gray-100" v-if="getSurplusOptionsLength"> | |
| 420 | - <span> +{{ getSurplusOptionsLength }}... </span> | |
| 421 | - </Tag> | |
| 422 | - </div> | |
| 423 | - </Button> | |
| 424 | - </section> | |
| 425 | -</template> | |
| 426 | - | |
| 427 | -<style lang="less"> | |
| 428 | - @prefix-cls: ~'@{namespace}-transfer-table-modal'; | |
| 429 | - | |
| 430 | - .@{prefix-cls} { | |
| 431 | - .vben-basic-table { | |
| 432 | - padding-top: 0; | |
| 433 | - } | |
| 434 | - | |
| 435 | - .vben-basic-form > .ant-row { | |
| 436 | - width: 100%; | |
| 437 | - } | |
| 438 | - | |
| 439 | - .ant-tabs-top-bar { | |
| 440 | - background-color: #fff; | |
| 441 | - } | |
| 442 | - } | |
| 443 | -</style> |
| ... | ... | @@ -5,7 +5,8 @@ |
| 5 | 5 | import { BasicModal } from '/@/components/Modal'; |
| 6 | 6 | import { PlusCircleOutlined } from '@ant-design/icons-vue'; |
| 7 | 7 | import { FormFieldsEnum, formSchemas } from './config'; |
| 8 | - import { DataTypeEnum } from '../StructForm/config'; | |
| 8 | + import { DataTypeEnum } from '/@/enums/objectModelEnum'; | |
| 9 | + | |
| 9 | 10 | const show = ref(false); |
| 10 | 11 | |
| 11 | 12 | const props = withDefaults( |
| ... | ... | @@ -50,7 +51,7 @@ |
| 50 | 51 | updateSchema([ |
| 51 | 52 | { |
| 52 | 53 | field: FormFieldsEnum.ZOOM_FACTOR, |
| 53 | - ifShow: props.dataType == DataTypeEnum.IS_BOOL ? false : true, | |
| 54 | + ifShow: props.dataType == DataTypeEnum.BOOL ? false : true, | |
| 54 | 55 | }, |
| 55 | 56 | ]); |
| 56 | 57 | } | ... | ... |
| 1 | 1 | <script lang="ts" setup> |
| 2 | 2 | import { Card } from 'ant-design-vue'; |
| 3 | 3 | import { computed, nextTick, onMounted, onUpdated, unref, watch } from 'vue'; |
| 4 | - import { DataTypeEnum } from '../StructForm/config'; | |
| 5 | 4 | import { BasicCreateFormParams } from './type'; |
| 6 | 5 | import { DynamicProps } from '/#/utils'; |
| 7 | 6 | import { Specs, StructJSON } from '/@/api/device/model/modelOfMatterModel'; |
| 8 | 7 | import { BasicForm, FormProps, FormSchema, useForm } from '/@/components/Form'; |
| 8 | + import { DataTypeEnum } from '/@/enums/objectModelEnum'; | |
| 9 | 9 | import { ReadAndWriteEnum } from '/@/enums/toolEnum'; |
| 10 | 10 | |
| 11 | 11 | const props = withDefaults( |
| ... | ... | @@ -86,7 +86,7 @@ |
| 86 | 86 | // step: step, |
| 87 | 87 | // formatter: (value: string) => value, |
| 88 | 88 | // parser: (string: string) => { |
| 89 | - // if (dataType === DataTypeEnum.IS_NUMBER_INT) { | |
| 89 | + // if (dataType === DataTypeEnum.NUMBER_INT) { | |
| 90 | 90 | // return Number(Number(string).toFixed()); |
| 91 | 91 | // } |
| 92 | 92 | // return Number(string); |
| ... | ... | @@ -188,19 +188,19 @@ |
| 188 | 188 | dataType: dataType! as unknown as DataTypeEnum, |
| 189 | 189 | specs: specs as Partial<Specs>, |
| 190 | 190 | }; |
| 191 | - if (type === DataTypeEnum.IS_NUMBER_INT || type === DataTypeEnum.IS_NUMBER_DOUBLE) { | |
| 191 | + if (type === DataTypeEnum.NUMBER_INT || type === DataTypeEnum.NUMBER_DOUBLE) { | |
| 192 | 192 | schemas.push(createInputNumber(params)); |
| 193 | 193 | } |
| 194 | 194 | |
| 195 | - if (type === DataTypeEnum.IS_BOOL) { | |
| 195 | + if (type === DataTypeEnum.BOOL) { | |
| 196 | 196 | schemas.push(createSelect(params)); |
| 197 | 197 | } |
| 198 | 198 | |
| 199 | - if (type === DataTypeEnum.IS_STRING) { | |
| 199 | + if (type === DataTypeEnum.STRING) { | |
| 200 | 200 | schemas.push(createInput(params)); |
| 201 | 201 | } |
| 202 | 202 | |
| 203 | - if (type === DataTypeEnum.IS_STRUCT) { | |
| 203 | + if (type === DataTypeEnum.STRUCT) { | |
| 204 | 204 | schemas.push(createInputJson(params)); |
| 205 | 205 | } |
| 206 | 206 | } | ... | ... |
| 1 | 1 | import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel'; |
| 2 | 2 | import { findDictItemByCode } from '/@/api/system/dict'; |
| 3 | 3 | import { FormSchema } from '/@/components/Table'; |
| 4 | +import { DataTypeEnum } from '/@/enums/objectModelEnum'; | |
| 4 | 5 | import { isNullOrUnDef } from '/@/utils/is'; |
| 5 | 6 | import { FormField } from '/@/views/device/profiles/step/cpns/physical/cpns/config'; |
| 6 | 7 | |
| 7 | -export enum DataTypeEnum { | |
| 8 | - IS_NUMBER_INT = 'INT', | |
| 9 | - IS_NUMBER_DOUBLE = 'DOUBLE', | |
| 10 | - IS_STRING = 'TEXT', | |
| 11 | - IS_STRUCT = 'STRUCT', | |
| 12 | - IS_BOOL = 'BOOL', | |
| 13 | -} | |
| 14 | - | |
| 15 | 8 | export const validateValueRange = (_rule, value: Record<'min' | 'max', number>, _callback) => { |
| 16 | 9 | value = value || {}; |
| 17 | 10 | const { min, max } = value; |
| ... | ... | @@ -77,10 +70,9 @@ export const formSchemas = ( |
| 77 | 70 | try { |
| 78 | 71 | const record = await findDictItemByCode(params); |
| 79 | 72 | return hasStructForm |
| 80 | - ? record.filter((item) => item.itemValue !== DataTypeEnum.IS_STRUCT) | |
| 73 | + ? record.filter((item) => item.itemValue !== DataTypeEnum.STRUCT) | |
| 81 | 74 | : record; |
| 82 | 75 | } catch (error) { |
| 83 | - console.log(error); | |
| 84 | 76 | return []; |
| 85 | 77 | } |
| 86 | 78 | }, |
| ... | ... | @@ -91,7 +83,7 @@ export const formSchemas = ( |
| 91 | 83 | valueField: 'itemValue', |
| 92 | 84 | getPopupContainer: () => document.body, |
| 93 | 85 | onChange: (value: string) => { |
| 94 | - if (value == DataTypeEnum.IS_STRUCT) { | |
| 86 | + if (value == DataTypeEnum.STRUCT) { | |
| 95 | 87 | updateSchema({ |
| 96 | 88 | field: FormField.SPECS_LIST, |
| 97 | 89 | componentProps: { |
| ... | ... | @@ -114,8 +106,8 @@ export const formSchemas = ( |
| 114 | 106 | span: 18, |
| 115 | 107 | }, |
| 116 | 108 | ifShow: ({ values }) => |
| 117 | - values[FormField.TYPE] === DataTypeEnum.IS_NUMBER_INT || | |
| 118 | - values[FormField.TYPE] === DataTypeEnum.IS_NUMBER_DOUBLE, | |
| 109 | + values[FormField.TYPE] === DataTypeEnum.NUMBER_INT || | |
| 110 | + values[FormField.TYPE] === DataTypeEnum.NUMBER_DOUBLE, | |
| 119 | 111 | rules: [{ validator: validateValueRange }], |
| 120 | 112 | }, |
| 121 | 113 | { |
| ... | ... | @@ -134,8 +126,8 @@ export const formSchemas = ( |
| 134 | 126 | }, |
| 135 | 127 | }, |
| 136 | 128 | ifShow: ({ values }) => |
| 137 | - values[FormField.TYPE] === DataTypeEnum.IS_NUMBER_INT || | |
| 138 | - values[FormField.TYPE] === DataTypeEnum.IS_NUMBER_DOUBLE, | |
| 129 | + values[FormField.TYPE] === DataTypeEnum.NUMBER_INT || | |
| 130 | + values[FormField.TYPE] === DataTypeEnum.NUMBER_DOUBLE, | |
| 139 | 131 | dynamicRules: ({ model }) => { |
| 140 | 132 | const valueRange = model[FormField.VALUE_RANGE] || {}; |
| 141 | 133 | const { min, max } = valueRange; |
| ... | ... | @@ -199,8 +191,8 @@ export const formSchemas = ( |
| 199 | 191 | }; |
| 200 | 192 | }, |
| 201 | 193 | ifShow: ({ values }) => |
| 202 | - values[FormField.TYPE] === DataTypeEnum.IS_NUMBER_INT || | |
| 203 | - values[FormField.TYPE] === DataTypeEnum.IS_NUMBER_DOUBLE, | |
| 194 | + values[FormField.TYPE] === DataTypeEnum.NUMBER_INT || | |
| 195 | + values[FormField.TYPE] === DataTypeEnum.NUMBER_DOUBLE, | |
| 204 | 196 | }, |
| 205 | 197 | { |
| 206 | 198 | field: FormField.BOOL_CLOSE, |
| ... | ... | @@ -214,7 +206,7 @@ export const formSchemas = ( |
| 214 | 206 | placeholder: '如:关', |
| 215 | 207 | }, |
| 216 | 208 | defaultValue: '关', |
| 217 | - ifShow: ({ values }) => values[FormField.TYPE] === DataTypeEnum.IS_BOOL, | |
| 209 | + ifShow: ({ values }) => values[FormField.TYPE] === DataTypeEnum.BOOL, | |
| 218 | 210 | dynamicRules: ({ model }) => { |
| 219 | 211 | const close = model[FormField.BOOL_CLOSE]; |
| 220 | 212 | const open = model[FormField.BOOL_OPEN]; |
| ... | ... | @@ -243,7 +235,7 @@ export const formSchemas = ( |
| 243 | 235 | placeholder: '如:开', |
| 244 | 236 | }, |
| 245 | 237 | defaultValue: '开', |
| 246 | - ifShow: ({ values }) => values[FormField.TYPE] === DataTypeEnum.IS_BOOL, | |
| 238 | + ifShow: ({ values }) => values[FormField.TYPE] === DataTypeEnum.BOOL, | |
| 247 | 239 | dynamicRules: ({ model }) => { |
| 248 | 240 | const close = model[FormField.BOOL_CLOSE]; |
| 249 | 241 | const open = model[FormField.BOOL_OPEN]; |
| ... | ... | @@ -277,7 +269,7 @@ export const formSchemas = ( |
| 277 | 269 | suffix: () => '字节', |
| 278 | 270 | }; |
| 279 | 271 | }, |
| 280 | - ifShow: ({ values }) => values[FormField.TYPE] === DataTypeEnum.IS_STRING, | |
| 272 | + ifShow: ({ values }) => values[FormField.TYPE] === DataTypeEnum.STRING, | |
| 281 | 273 | }, |
| 282 | 274 | { |
| 283 | 275 | field: FormField.EXTENSION_DESC, |
| ... | ... | @@ -322,7 +314,7 @@ export const formSchemas = ( |
| 322 | 314 | valueField: 'value', |
| 323 | 315 | changeEvent: 'update:value', |
| 324 | 316 | colProps: { span: 24 }, |
| 325 | - ifShow: ({ values }) => values[FormField.TYPE] === DataTypeEnum.IS_STRUCT, | |
| 317 | + ifShow: ({ values }) => values[FormField.TYPE] === DataTypeEnum.STRUCT, | |
| 326 | 318 | rules: [{ required: true, validator: validateJSON }], |
| 327 | 319 | }, |
| 328 | 320 | { | ... | ... |
| 1 | -import { DataTypeEnum } from './config'; | |
| 2 | 1 | import { StructJSON } from '/@/api/device/model/modelOfMatterModel'; |
| 2 | +import { DataTypeEnum } from '/@/enums/objectModelEnum'; | |
| 3 | 3 | import { FormField } from '/@/views/device/profiles/step/cpns/physical/cpns/config'; |
| 4 | 4 | |
| 5 | 5 | export enum OpenModalMode { | ... | ... |
| 1 | 1 | import { cloneDeep } from 'lodash-es'; |
| 2 | -import { DataTypeEnum } from './config'; | |
| 3 | 2 | import { StructFormValue } from './type'; |
| 4 | 3 | import { DataType, ModelOfMatterParams, StructJSON } from '/@/api/device/model/modelOfMatterModel'; |
| 5 | 4 | import { isArray } from '/@/utils/is'; |
| 5 | +import { DataTypeEnum } from '/@/enums/objectModelEnum'; | |
| 6 | 6 | |
| 7 | 7 | export function transfromToStructJSON(value: StructFormValue): StructJSON { |
| 8 | 8 | const { |
| ... | ... | @@ -24,21 +24,21 @@ export function transfromToStructJSON(value: StructFormValue): StructJSON { |
| 24 | 24 | let dataType = {} as unknown as DataType; |
| 25 | 25 | |
| 26 | 26 | switch (type) { |
| 27 | - case DataTypeEnum.IS_NUMBER_INT: | |
| 27 | + case DataTypeEnum.NUMBER_INT: | |
| 28 | 28 | dataType = { |
| 29 | 29 | type, |
| 30 | 30 | specs: { valueRange, step, unit, unitName }, |
| 31 | 31 | }; |
| 32 | 32 | break; |
| 33 | 33 | |
| 34 | - case DataTypeEnum.IS_NUMBER_DOUBLE: | |
| 34 | + case DataTypeEnum.NUMBER_DOUBLE: | |
| 35 | 35 | dataType = { |
| 36 | 36 | type, |
| 37 | 37 | specs: { valueRange, step, unit, unitName }, |
| 38 | 38 | }; |
| 39 | 39 | break; |
| 40 | 40 | |
| 41 | - case DataTypeEnum.IS_BOOL: | |
| 41 | + case DataTypeEnum.BOOL: | |
| 42 | 42 | dataType = { |
| 43 | 43 | type, |
| 44 | 44 | specs: { |
| ... | ... | @@ -48,14 +48,14 @@ export function transfromToStructJSON(value: StructFormValue): StructJSON { |
| 48 | 48 | }; |
| 49 | 49 | break; |
| 50 | 50 | |
| 51 | - case DataTypeEnum.IS_STRING: | |
| 51 | + case DataTypeEnum.STRING: | |
| 52 | 52 | dataType = { |
| 53 | 53 | type, |
| 54 | 54 | specs: { length }, |
| 55 | 55 | }; |
| 56 | 56 | break; |
| 57 | 57 | |
| 58 | - case DataTypeEnum.IS_STRUCT: | |
| 58 | + case DataTypeEnum.STRUCT: | |
| 59 | 59 | dataType = { |
| 60 | 60 | type, |
| 61 | 61 | specs: specs! as unknown as ModelOfMatterParams[], | ... | ... |
| 1 | +<script setup lang="ts"> | |
| 2 | + import { StructJSON } from '/@/api/device/model/modelOfMatterModel'; | |
| 3 | + import { JsonPreview } from '/@/components/CodeEditor'; | |
| 4 | + import { BasicModal, useModalInner } from '/@/components/Modal'; | |
| 5 | + | |
| 6 | + defineProps<{ | |
| 7 | + inputData?: StructJSON[]; | |
| 8 | + }>(); | |
| 9 | + | |
| 10 | + defineEmits(['register']); | |
| 11 | + | |
| 12 | + const data = {}; | |
| 13 | + | |
| 14 | + const [register] = useModalInner(); | |
| 15 | +</script> | |
| 16 | + | |
| 17 | +<template> | |
| 18 | + <BasicModal @register="register" title=""> | |
| 19 | + <!-- --> | |
| 20 | + <JsonPreview :data="data" /> | |
| 21 | + </BasicModal> | |
| 22 | +</template> | ... | ... |
| 1 | +import { FormSchema } from '../../../types/form'; | |
| 2 | +import { Specs, StructJSON } from '/@/api/device/model/modelOfMatterModel'; | |
| 3 | +import { DataTypeEnum } from '/@/enums/objectModelEnum'; | |
| 4 | +import { TransportTypeEnum } from '/@/views/device/profiles/components/TransportDescript/const'; | |
| 5 | + | |
| 6 | +export const getFormSchemas = ({ | |
| 7 | + structJSON: structJson, | |
| 8 | + required, | |
| 9 | + transportType, | |
| 10 | +}: { | |
| 11 | + structJSON: StructJSON[]; | |
| 12 | + required?: boolean; | |
| 13 | + transportType?: string; | |
| 14 | +}): FormSchema[] => { | |
| 15 | + const createInputNumber = ({ identifier, functionName, dataType }: StructJSON): FormSchema => { | |
| 16 | + const { specs } = dataType || {}; | |
| 17 | + const { valueRange } = specs! as Specs; | |
| 18 | + const { max = 2147483647, min = -2147483648 } = valueRange || {}; | |
| 19 | + return { | |
| 20 | + field: identifier, | |
| 21 | + label: functionName, | |
| 22 | + component: 'InputNumber', | |
| 23 | + rules: [ | |
| 24 | + { | |
| 25 | + required, | |
| 26 | + message: `${functionName}是必填项`, | |
| 27 | + }, | |
| 28 | + { | |
| 29 | + type: 'number', | |
| 30 | + trigger: 'change', | |
| 31 | + validator: (_rule, value) => { | |
| 32 | + const reg = /^[0-9]*$/; | |
| 33 | + if (!reg.test(value)) | |
| 34 | + return Promise.reject(new Error(`${functionName}不是一个有效的数字`)); | |
| 35 | + if (value < min || value > max) | |
| 36 | + return Promise.reject(new Error(`${functionName}取值范围在${min}~${max}之间`)); | |
| 37 | + | |
| 38 | + return Promise.resolve(value); | |
| 39 | + }, | |
| 40 | + }, | |
| 41 | + ], | |
| 42 | + componentProps: { | |
| 43 | + max, | |
| 44 | + min, | |
| 45 | + placeholder: `请输入${functionName}`, | |
| 46 | + }, | |
| 47 | + } as FormSchema; | |
| 48 | + }; | |
| 49 | + | |
| 50 | + const createInput = ({ identifier, functionName, dataType }: StructJSON): FormSchema => { | |
| 51 | + const { specs } = dataType || {}; | |
| 52 | + const { length = 10240 } = specs! as Partial<Specs>; | |
| 53 | + return { | |
| 54 | + field: identifier, | |
| 55 | + label: functionName, | |
| 56 | + component: 'Input', | |
| 57 | + rules: [ | |
| 58 | + { | |
| 59 | + required, | |
| 60 | + message: `${functionName}是必填项`, | |
| 61 | + }, | |
| 62 | + { | |
| 63 | + type: 'string', | |
| 64 | + trigger: 'change', | |
| 65 | + validator: (_rule, value) => { | |
| 66 | + if ((value?.length || 0) > length) | |
| 67 | + return Promise.reject(new Error(`${functionName}数据长度应该小于${length}`)); | |
| 68 | + | |
| 69 | + return Promise.resolve(value); | |
| 70 | + }, | |
| 71 | + }, | |
| 72 | + ], | |
| 73 | + componentProps: { | |
| 74 | + maxLength: length, | |
| 75 | + placeholder: `请输入${functionName}`, | |
| 76 | + }, | |
| 77 | + } as FormSchema; | |
| 78 | + }; | |
| 79 | + | |
| 80 | + const createSelect = ({ identifier, functionName, dataType }: StructJSON): FormSchema => { | |
| 81 | + const { specs } = dataType || {}; | |
| 82 | + const { boolClose, boolOpen } = specs! as Partial<Specs>; | |
| 83 | + return { | |
| 84 | + field: identifier, | |
| 85 | + label: functionName!, | |
| 86 | + component: 'Select', | |
| 87 | + rules: [ | |
| 88 | + { | |
| 89 | + required, | |
| 90 | + message: `${functionName}是必填项`, | |
| 91 | + type: 'number', | |
| 92 | + }, | |
| 93 | + ], | |
| 94 | + componentProps: { | |
| 95 | + options: [ | |
| 96 | + { label: `${boolClose}-0`, value: 0 }, | |
| 97 | + { label: `${boolOpen}-1`, value: 1 }, | |
| 98 | + ], | |
| 99 | + placeholder: `请选择${functionName}`, | |
| 100 | + }, | |
| 101 | + }; | |
| 102 | + }; | |
| 103 | + | |
| 104 | + const createStructJson = ({ identifier, functionName, dataType }: StructJSON): FormSchema => { | |
| 105 | + return { | |
| 106 | + field: identifier, | |
| 107 | + label: functionName!, | |
| 108 | + component: 'Input', | |
| 109 | + changeEvent: 'update:value', | |
| 110 | + componentProps: () => { | |
| 111 | + return { | |
| 112 | + inputData: dataType?.specs || [], | |
| 113 | + }; | |
| 114 | + }, | |
| 115 | + colSlot: identifier, | |
| 116 | + }; | |
| 117 | + }; | |
| 118 | + | |
| 119 | + const createTCPServiceCommandInput = ({ serviceCommand }: StructJSON): FormSchema => { | |
| 120 | + return { | |
| 121 | + field: 'serviceCommand', | |
| 122 | + label: '服务命令', | |
| 123 | + component: 'Input', | |
| 124 | + required, | |
| 125 | + defaultValue: serviceCommand, | |
| 126 | + componentProps: { | |
| 127 | + placeholder: `请输入服务命令`, | |
| 128 | + }, | |
| 129 | + }; | |
| 130 | + }; | |
| 131 | + | |
| 132 | + const schemas: FormSchema[] = []; | |
| 133 | + | |
| 134 | + for (const item of structJson) { | |
| 135 | + const { dataType } = item; | |
| 136 | + const { type } = dataType || {}; | |
| 137 | + if (transportType === TransportTypeEnum.TCP) { | |
| 138 | + item.serviceCommand && schemas.push(createTCPServiceCommandInput(item)); | |
| 139 | + break; | |
| 140 | + } | |
| 141 | + | |
| 142 | + if (type === DataTypeEnum.BOOL) schemas.push(createSelect(item)); | |
| 143 | + else if (type === DataTypeEnum.NUMBER_INT) schemas.push(createInputNumber(item)); | |
| 144 | + else if (type === DataTypeEnum.NUMBER_DOUBLE) schemas.push(createInputNumber(item)); | |
| 145 | + else if (type === DataTypeEnum.STRING) schemas.push(createInput(item)); | |
| 146 | + else if (type === DataTypeEnum.STRUCT) schemas.push(createStructJson(item)); | |
| 147 | + } | |
| 148 | + | |
| 149 | + return schemas; | |
| 150 | +}; | ... | ... |
| 1 | +import { ValidatorRule } from 'ant-design-vue/lib/form/interface'; | |
| 2 | +export { default as ThingsModelForm } from './index.vue'; | |
| 3 | + | |
| 4 | +export const validateTCPCustomCommand: ValidatorRule['validator'] = (_rule, value) => { | |
| 5 | + const reg = /^[\s0-9a-fA-F]+$/; | |
| 6 | + if (reg.test(value)) return Promise.resolve(); | |
| 7 | + return Promise.reject('请输入ASCII或HEX服务命令(0~9/A~F)'); | |
| 8 | +}; | |
| 9 | + | |
| 10 | +export const trimBlankSpace = (string: string) => string.replace(/(?!^)(?=(\w{2})+$)/g, ''); | |
| 11 | + | |
| 12 | +export const formatCommandString = (string = '') => string.replace(/(?!^)(?=(\w{2})+$)/g, ' '); | ... | ... |
| 1 | +<script setup lang="ts"> | |
| 2 | + import { Card } from 'ant-design-vue'; | |
| 3 | + import { ComponentPublicInstance, computed, nextTick, reactive, unref, watch } from 'vue'; | |
| 4 | + import { getFormSchemas } from './config'; | |
| 5 | + import { ThingsModelForm } from '.'; | |
| 6 | + import { DefineComponentsBasicExpose } from '/#/utils'; | |
| 7 | + import { StructJSON } from '/@/api/device/model/modelOfMatterModel'; | |
| 8 | + import { useForm } from '../../../hooks/useForm'; | |
| 9 | + import { DataTypeEnum } from '/@/enums/objectModelEnum'; | |
| 10 | + import { BasicForm } from '/@/components/Form'; | |
| 11 | + | |
| 12 | + const props = withDefaults( | |
| 13 | + defineProps<{ | |
| 14 | + value?: Recordable; | |
| 15 | + inputData?: StructJSON[]; | |
| 16 | + required?: boolean; | |
| 17 | + title?: string; | |
| 18 | + transportType?: string; | |
| 19 | + disabled?: boolean; | |
| 20 | + identifier?: string; | |
| 21 | + }>(), | |
| 22 | + { | |
| 23 | + inputData: () => [], | |
| 24 | + required: true, | |
| 25 | + } | |
| 26 | + ); | |
| 27 | + | |
| 28 | + const thingsModelFormListElMap = reactive< | |
| 29 | + Record<string, { el: InstanceType<typeof ThingsModelForm>; structJSON: StructJSON }> | |
| 30 | + >({}); | |
| 31 | + | |
| 32 | + const [register, formActionType] = useForm({ | |
| 33 | + schemas: getFormSchemas({ | |
| 34 | + structJSON: props.inputData || [], | |
| 35 | + required: props.required, | |
| 36 | + transportType: props.transportType, | |
| 37 | + }), | |
| 38 | + showActionButtonGroup: false, | |
| 39 | + layout: 'inline', | |
| 40 | + labelWidth: 100, | |
| 41 | + }); | |
| 42 | + | |
| 43 | + const getStructFormItem = computed(() => { | |
| 44 | + const { inputData } = props; | |
| 45 | + return inputData.filter((item) => item.dataType?.type === DataTypeEnum.STRUCT); | |
| 46 | + }); | |
| 47 | + | |
| 48 | + const setFormElRef = ( | |
| 49 | + el: Nullable<Element | ComponentPublicInstance>, | |
| 50 | + structJSON: StructJSON | |
| 51 | + ) => { | |
| 52 | + const _structJSON = unref(getStructFormItem).find( | |
| 53 | + (item) => item.identifier === structJSON.identifier | |
| 54 | + ); | |
| 55 | + | |
| 56 | + if (_structJSON) | |
| 57 | + thingsModelFormListElMap[structJSON.identifier!] = { | |
| 58 | + el: el as InstanceType<typeof ThingsModelForm>, | |
| 59 | + structJSON, | |
| 60 | + }; | |
| 61 | + }; | |
| 62 | + | |
| 63 | + const getFieldsValue = () => { | |
| 64 | + const basicValue = formActionType.getFieldsValue(); | |
| 65 | + | |
| 66 | + const structValue: Recordable = {}; | |
| 67 | + for (const key of Object.keys(thingsModelFormListElMap)) { | |
| 68 | + const item = thingsModelFormListElMap[key]; | |
| 69 | + const { el } = item; | |
| 70 | + structValue[key] = el.getFieldsValue() || {}; | |
| 71 | + } | |
| 72 | + | |
| 73 | + return { | |
| 74 | + ...basicValue, | |
| 75 | + ...structValue, | |
| 76 | + }; | |
| 77 | + }; | |
| 78 | + | |
| 79 | + const setFieldsValue = (value: Recordable) => { | |
| 80 | + formActionType.setFieldsValue(value); | |
| 81 | + }; | |
| 82 | + | |
| 83 | + const validate = async () => { | |
| 84 | + await formActionType.validate(); | |
| 85 | + for (const key of Object.keys(thingsModelFormListElMap)) | |
| 86 | + await thingsModelFormListElMap[key]?.el?.validate?.(); | |
| 87 | + }; | |
| 88 | + | |
| 89 | + watch( | |
| 90 | + () => props.value, | |
| 91 | + async (value) => { | |
| 92 | + await nextTick(); | |
| 93 | + formActionType.resetFields(); | |
| 94 | + formActionType.setFieldsValue(value || {}); | |
| 95 | + }, | |
| 96 | + { immediate: true } | |
| 97 | + ); | |
| 98 | + | |
| 99 | + watch( | |
| 100 | + () => [props.inputData, props.identifier], | |
| 101 | + (value) => { | |
| 102 | + if (value && value.length) { | |
| 103 | + const schemas = getFormSchemas({ | |
| 104 | + structJSON: props.inputData || [], | |
| 105 | + required: props.required, | |
| 106 | + transportType: props.transportType, | |
| 107 | + }); | |
| 108 | + formActionType.setProps({ schemas }); | |
| 109 | + } | |
| 110 | + } | |
| 111 | + ); | |
| 112 | + | |
| 113 | + watch( | |
| 114 | + () => props.disabled, | |
| 115 | + (value) => { | |
| 116 | + formActionType.setProps({ disabled: value }); | |
| 117 | + } | |
| 118 | + ); | |
| 119 | + | |
| 120 | + defineExpose<DefineComponentsBasicExpose>({ | |
| 121 | + getFieldsValue, | |
| 122 | + setFieldsValue, | |
| 123 | + validate, | |
| 124 | + }); | |
| 125 | +</script> | |
| 126 | + | |
| 127 | +<template> | |
| 128 | + <Card | |
| 129 | + class="!border-2 !border-dashed" | |
| 130 | + :title="title" | |
| 131 | + :style="{ backgroundColor: disabled ? '#f0f0f0' : '', borderColor: disabled ? '#e3e3e3' : '' }" | |
| 132 | + > | |
| 133 | + <BasicForm class="things-model-form" @register="register" :disabled="disabled"> | |
| 134 | + <template | |
| 135 | + v-for="item in getStructFormItem" | |
| 136 | + #[item.identifier!]="{ model, field }" | |
| 137 | + :key="item.identifier" | |
| 138 | + > | |
| 139 | + <ThingsModelForm | |
| 140 | + class="!ml-10" | |
| 141 | + :ref="(el) => setFormElRef(el, item)" | |
| 142 | + v-model:value="model[field]" | |
| 143 | + :input-data="(item.dataType?.specs as StructJSON[]) || []" | |
| 144 | + :title="item.functionName" | |
| 145 | + :disabled="disabled" | |
| 146 | + /> | |
| 147 | + </template> | |
| 148 | + </BasicForm> | |
| 149 | + </Card> | |
| 150 | +</template> | |
| 151 | + | |
| 152 | +<style lang="less" scoped> | |
| 153 | + .things-model-form { | |
| 154 | + > :deep(.ant-row) { | |
| 155 | + width: 100%; | |
| 156 | + } | |
| 157 | + | |
| 158 | + :deep(.ant-input-number) { | |
| 159 | + width: 100%; | |
| 160 | + } | |
| 161 | + | |
| 162 | + :deep(.ant-form-item-label) { | |
| 163 | + label { | |
| 164 | + width: 100%; | |
| 165 | + display: block; | |
| 166 | + overflow: hidden; | |
| 167 | + text-overflow: ellipsis; | |
| 168 | + } | |
| 169 | + } | |
| 170 | + } | |
| 171 | + | |
| 172 | + :deep(.ant-form-item-control) { | |
| 173 | + margin-left: 6px; | |
| 174 | + } | |
| 175 | +</style> | ... | ... |
| ... | ... | @@ -123,6 +123,7 @@ export type ComponentType = |
| 123 | 123 | | 'TransferModal' |
| 124 | 124 | | 'TransferTableModal' |
| 125 | 125 | | 'ObjectModelValidateForm' |
| 126 | + | 'ThingsModelForm' | |
| 126 | 127 | | 'DevicePicker' |
| 127 | 128 | | 'ProductPicker' |
| 128 | 129 | | 'PollCommandInput' |
| ... | ... | @@ -138,4 +139,8 @@ export type ComponentType = |
| 138 | 139 | | 'RelationsQuery' |
| 139 | 140 | | 'CredentialsCard' |
| 140 | 141 | | 'ApiComplete' |
| 141 | - | 'DeviceProfileForm'; | |
| 142 | + | 'DeviceProfileForm' | |
| 143 | + | 'ConditionFilter' | |
| 144 | + | 'TimeRangePicker' | |
| 145 | + | 'TriggerDurationInput' | |
| 146 | + | 'AlarmProfileSelect'; | ... | ... |
| ... | ... | @@ -25,19 +25,18 @@ export function usePagination(refProps: ComputedRef<BasicTableProps>) { |
| 25 | 25 | const { t } = useI18n(); |
| 26 | 26 | |
| 27 | 27 | const configRef = ref<PaginationProps>({ |
| 28 | - hideOnSinglePage:true | |
| 28 | + hideOnSinglePage: true, | |
| 29 | 29 | }); |
| 30 | 30 | const show = ref(true); |
| 31 | 31 | |
| 32 | 32 | watchEffect(() => { |
| 33 | 33 | const { pagination } = unref(refProps); |
| 34 | - | |
| 34 | + | |
| 35 | 35 | if (!isBoolean(pagination) && pagination) { |
| 36 | 36 | configRef.value = { |
| 37 | 37 | ...unref(configRef), |
| 38 | 38 | ...(pagination ?? {}), |
| 39 | - }; | |
| 40 | - | |
| 39 | + }; | |
| 41 | 40 | } |
| 42 | 41 | }); |
| 43 | 42 | ... | ... |
| ... | ... | @@ -88,7 +88,7 @@ export function useTableScroll( |
| 88 | 88 | |
| 89 | 89 | bodyEl!.style.height = 'unset'; |
| 90 | 90 | |
| 91 | - if (!unref(getCanResize) || tableData.length === 0) return; | |
| 91 | + if (!unref(getCanResize)) return; | |
| 92 | 92 | |
| 93 | 93 | await nextTick(); |
| 94 | 94 | //Add a delay to get the correct bottomIncludeBody paginationHeight footerHeight headerHeight |
| ... | ... | @@ -143,7 +143,12 @@ export function useTableScroll( |
| 143 | 143 | height = (height > maxHeight! ? (maxHeight as number) : height) ?? height; |
| 144 | 144 | setHeight(height); |
| 145 | 145 | |
| 146 | - bodyEl!.style.height = `${height}px`; | |
| 146 | + if (tableData.length) { | |
| 147 | + bodyEl!.style.height = `${height}px`; | |
| 148 | + } else { | |
| 149 | + const emptyPlaceholder: HTMLDivElement = tableEl.querySelector('.ant-table-placeholder')!; | |
| 150 | + emptyPlaceholder && (emptyPlaceholder.style.height = `${height}px`); | |
| 151 | + } | |
| 147 | 152 | } |
| 148 | 153 | useWindowSizeFn(calcTableHeight, 280); |
| 149 | 154 | onMountedOrActivated(() => { | ... | ... |
| ... | ... | @@ -11,3 +11,19 @@ export enum AlarmStatusMean { |
| 11 | 11 | CLEARED_ACK = '清除已确认', |
| 12 | 12 | ACTIVE_ACK = '激活已确认', |
| 13 | 13 | } |
| 14 | + | |
| 15 | +export enum AlarmLevelEnum { | |
| 16 | + CRITICAL = 'CRITICAL', | |
| 17 | + MAJOR = 'MAJOR', | |
| 18 | + MINOR = 'MINOR', | |
| 19 | + WARNING = 'WARNING', | |
| 20 | + INDETERMINATE = 'INDETERMINATE', | |
| 21 | +} | |
| 22 | + | |
| 23 | +export enum AlarmLevelNameEnum { | |
| 24 | + CRITICAL = '紧急', | |
| 25 | + MAJOR = '重要', | |
| 26 | + MINOR = '次要', | |
| 27 | + WARNING = '警告', | |
| 28 | + INDETERMINATE = '不确定', | |
| 29 | +} | ... | ... |
src/enums/linkedgeEnum.ts
0 → 100644
| 1 | +/** | |
| 2 | + * 运算符枚举值 | |
| 3 | + */ | |
| 4 | + | |
| 5 | +// 数字运算符或者时间运算符 | |
| 6 | +export enum NumberOperationEnum { | |
| 7 | + EQUAL = 'EQUAL', | |
| 8 | + NOT_EQUAL = 'NOT_EQUAL', | |
| 9 | + LESS = 'LESS', | |
| 10 | + LESS_OR_EQUAL = 'LESS_OR_EQUAL', | |
| 11 | + GREATER = 'GREATER', | |
| 12 | + GREATER_OR_EQUAL = 'GREATER_OR_EQUAL', | |
| 13 | +} | |
| 14 | + | |
| 15 | +export enum NumberOperationNameEnum { | |
| 16 | + EQUAL = '等于', | |
| 17 | + NOT_EQUAL = '不等于', | |
| 18 | + LESS = '小于', | |
| 19 | + LESS_OR_EQUAL = '小于等于', | |
| 20 | + GREATER = '大于', | |
| 21 | + GREATER_OR_EQUAL = '大于等于', | |
| 22 | +} | |
| 23 | + | |
| 24 | +export enum StringOperationEnum { | |
| 25 | + EQUAL = 'EQUAL', | |
| 26 | + NOT_EQUAL = 'NOT_EQUAL', | |
| 27 | + STARTS_WITH = 'STARTS_WITH', | |
| 28 | + ENDS_WITH = 'ENDS_WITH', | |
| 29 | + CONTAINS = 'CONTAINS', | |
| 30 | + NOT_CONTAINS = 'NOT_CONTAINS', | |
| 31 | +} | |
| 32 | + | |
| 33 | +export enum StringOperationNameEnum { | |
| 34 | + EQUAL = '等于', | |
| 35 | + NOT_EQUAL = '不等于', | |
| 36 | + STARTS_WITH = '开始于', | |
| 37 | + ENDS_WITH = '结束于', | |
| 38 | + CONTAINS = '包含', | |
| 39 | + NOT_CONTAINS = '不包含', | |
| 40 | +} | |
| 41 | + | |
| 42 | +export enum BooleanOperationEnum { | |
| 43 | + EQUAL = 'EQUAL', | |
| 44 | + NOT_EQUAL = 'NOT_EQUAL', | |
| 45 | +} | |
| 46 | + | |
| 47 | +export enum BooleanOperationNameEnum { | |
| 48 | + EQUAL = '等于', | |
| 49 | + NOT_EQUAL = '不等于', | |
| 50 | +} | |
| 51 | + | |
| 52 | +export enum BooleanOperationValueEnum { | |
| 53 | + TRUE = 'true', | |
| 54 | + FALSE = 'false', | |
| 55 | +} | |
| 56 | + | |
| 57 | +export enum BooleanOperationValueNameEnum { | |
| 58 | + TRUE = '真', | |
| 59 | + FALSE = '假', | |
| 60 | +} | |
| 61 | + | |
| 62 | +export enum FlipFlopTypeEnum { | |
| 63 | + SIMPLE = 'SIMPLE', | |
| 64 | + DURATION = 'DURATION', | |
| 65 | + REPEATING = 'REPEATING', | |
| 66 | +} | |
| 67 | + | |
| 68 | +export enum ScheduleTypeEnum { | |
| 69 | + ANY_TIME = 'ANY_TIME', | |
| 70 | + SPECIFIC_TIME = 'SPECIFIC_TIME', | |
| 71 | + CUSTOM = 'CUSTOM', | |
| 72 | +} | |
| 73 | + | |
| 74 | +export enum ScheduleTypeNameEnum { | |
| 75 | + ANY_TIME = '始终启用', | |
| 76 | + SPECIFIC_TIME = '定时启用', | |
| 77 | + CUSTOM = '自定义启用', | |
| 78 | +} | |
| 79 | + | |
| 80 | +export enum FlipFlopTypeNameEnum { | |
| 81 | + SIMPLE = '简单', | |
| 82 | + DURATION = '持续时长', | |
| 83 | + REPEATING = '重复次数', | |
| 84 | +} | |
| 85 | + | |
| 86 | +export enum TriggerTypeEnum { | |
| 87 | + DEVICE_TRIGGER = 'DEVICE_TRIGGER', | |
| 88 | + SCHEDULE_TRIGGER = 'SCHEDULE_TRIGGER', | |
| 89 | + SCENE_TRIGGER = 'SCENE_TRIGGER', | |
| 90 | + HAND_ACT = 'HAND_ACT', | |
| 91 | +} | |
| 92 | + | |
| 93 | +export enum TriggerTypeNameEnum { | |
| 94 | + DEVICE_TRIGGER = '设备触发', | |
| 95 | + SCHEDULE_TRIGGER = '定时触发', | |
| 96 | + SCENE_TRIGGER = '场景触发', | |
| 97 | + HAND_ACT = '手动触发', | |
| 98 | +} | |
| 99 | + | |
| 100 | +export enum DeviceTriggerTypeEum { | |
| 101 | + TIME_SERIES = 'TIME_SERIES', | |
| 102 | +} | |
| 103 | + | |
| 104 | +export enum DeviceTriggerTypeNameEum { | |
| 105 | + TIME_SERIES = '属性触发', | |
| 106 | +} | |
| 107 | + | |
| 108 | +export enum TriggerEntityTypeEnum { | |
| 109 | + ALL = 'ALL', | |
| 110 | + PART = 'PART', | |
| 111 | +} | |
| 112 | + | |
| 113 | +export enum TriggerEntityTypeNameEnum { | |
| 114 | + ALL = '全部', | |
| 115 | + PART = '部分', | |
| 116 | +} | |
| 117 | + | |
| 118 | +export enum TriggerValueTypeEnum { | |
| 119 | + NUMERIC = 'NUMERIC', | |
| 120 | + BOOLEAN = 'BOOLEAN', | |
| 121 | + STRING = 'STRING', | |
| 122 | + DATE_TIME = 'DATE_TIME', | |
| 123 | +} | |
| 124 | + | |
| 125 | +export enum TriggerValueTypeNameEnum { | |
| 126 | + NUMERIC = '数字', | |
| 127 | + BOOLEAN = '布尔值', | |
| 128 | + STRING = '字符串', | |
| 129 | + DATE_TIME = '时间', | |
| 130 | +} | |
| 131 | + | |
| 132 | +export enum TriggerUnitEnum { | |
| 133 | + SECONDS = 'SECONDS', | |
| 134 | + MINUTES = 'MINUTES', | |
| 135 | + HOURS = 'HOURS', | |
| 136 | + DAYS = 'DAYS', | |
| 137 | +} | |
| 138 | + | |
| 139 | +export enum TriggerUnitNameEnum { | |
| 140 | + SECONDS = '秒', | |
| 141 | + MINUTES = '分', | |
| 142 | + HOURS = '时', | |
| 143 | + DAYS = '天', | |
| 144 | +} | |
| 145 | + | |
| 146 | +export enum ExecutionActionEnum { | |
| 147 | + DEVICE_OUT = 'DEVICE_OUT', | |
| 148 | + MSG_NOTIFY = 'MSG_NOTIFY', | |
| 149 | +} | |
| 150 | + | |
| 151 | +export enum ExecutionActionNameEnum { | |
| 152 | + DEVICE_OUT = '设备输出', | |
| 153 | + MSG_NOTIFY = '告警输出', | |
| 154 | +} | |
| 155 | + | |
| 156 | +export enum CommandTypeEnum { | |
| 157 | + CUSTOM = 0, | |
| 158 | + SERVICE = 1, | |
| 159 | + ATTRIBUTE = 2, | |
| 160 | + API = 'api', | |
| 161 | +} | |
| 162 | + | |
| 163 | +export enum CommandTypeNameEnum { | |
| 164 | + CUSTOM = '自定义', | |
| 165 | + SERVICE = '服务', | |
| 166 | + ATTRIBUTE = '属性', | |
| 167 | +} | ... | ... |
src/enums/objectModelEnum.ts
0 → 100644
src/enums/operationEnum.ts
deleted
100644 → 0
| 1 | -/** | |
| 2 | - * 运算符枚举值 | |
| 3 | - */ | |
| 4 | - | |
| 5 | -// 数字运算符或者时间运算符 | |
| 6 | -export enum Number_Operation { | |
| 7 | - EQUAL = 'EQUAL', | |
| 8 | - NOT_EQUAL = 'NOT_EQUAL', | |
| 9 | - LESS = 'LESS', | |
| 10 | - LESS_OR_EQUAL = 'LESS_OR_EQUAL', | |
| 11 | - GREATER = 'GREATER', | |
| 12 | - GREATER_OR_EQUAL = 'GREATER_OR_EQUAL', | |
| 13 | -} | |
| 14 | - | |
| 15 | -export enum String_Operation { | |
| 16 | - EQUAL = 'EQUAL', | |
| 17 | - NOT_EQUAL = 'NOT_EQUAL', | |
| 18 | - BEGAN_IN = 'STARTS_WITH', | |
| 19 | - END_IN = 'ENDS_WITH', | |
| 20 | - INCLUDE = 'CONTAINS', | |
| 21 | - NOT_INCLUDE = 'NOT_CONTAINS', | |
| 22 | -} | |
| 23 | - | |
| 24 | -export enum Boolean_Operation { | |
| 25 | - EQUAL = 'EQUAL', | |
| 26 | - NOT_EQUAL = 'NOT_EQUAL', | |
| 27 | -} |
| ... | ... | @@ -7,7 +7,7 @@ export enum DataActionModeEnum { |
| 7 | 7 | } |
| 8 | 8 | |
| 9 | 9 | export enum DataActionModeNameEnum { |
| 10 | - CREATE = '创建', | |
| 10 | + CREATE = '新增', | |
| 11 | 11 | READ = '查看', |
| 12 | 12 | UPDATE = '编辑', |
| 13 | 13 | DELETE = '删除', |
| ... | ... | @@ -40,6 +40,11 @@ export enum ServiceCallTypeEnum { |
| 40 | 40 | SYNC = 'SYNC', |
| 41 | 41 | } |
| 42 | 42 | |
| 43 | +export enum ServiceCallTypeNameEnum { | |
| 44 | + ASYNC = '异步', | |
| 45 | + SYNC = '同步', | |
| 46 | +} | |
| 47 | + | |
| 43 | 48 | export enum CommandDeliveryWayEnum { |
| 44 | 49 | ONE_WAY = 'oneway', |
| 45 | 50 | TWO_WAY = 'twoway', | ... | ... |
| 1 | 1 | export const createPickerSearch = (searchValue = false) => { |
| 2 | 2 | return { |
| 3 | 3 | showSearch: true, |
| 4 | + getPopupContainer: (triggerNode) => triggerNode.parentNode, | |
| 4 | 5 | filterOption: (inputValue: string, option: Record<'label' | 'value', string>) => { |
| 5 | 6 | let { label, value } = option; |
| 6 | 7 | label = label.toLowerCase(); | ... | ... |
| ... | ... | @@ -120,6 +120,22 @@ export const emailRule: Rule[] = [ |
| 120 | 120 | }, |
| 121 | 121 | ]; |
| 122 | 122 | |
| 123 | +// 钉钉验证 | |
| 124 | +export const dingRule: Rule[] = [ | |
| 125 | + { | |
| 126 | + validator: (_, value: string) => { | |
| 127 | + const reg = /^[1][3,4,5,6,7,8,9][0-9]{9}$/; | |
| 128 | + if (!value) { | |
| 129 | + return Promise.resolve(); | |
| 130 | + } else if (!reg.test(value)) { | |
| 131 | + return Promise.reject('手机号格式不正确'); | |
| 132 | + } | |
| 133 | + return Promise.resolve(); | |
| 134 | + }, | |
| 135 | + validateTrigger: 'blur', | |
| 136 | + }, | |
| 137 | +]; | |
| 138 | + | |
| 123 | 139 | // 中文正则 |
| 124 | 140 | export const ChineseRegexp = /[\u4E00-\u9FA5]/; |
| 125 | 141 | ... | ... |
| 1 | 1 | import { BasicColumn, FormSchema } from '/@/components/Table'; |
| 2 | -import { emailRule, phoneRule } from '/@/utils/rules'; | |
| 2 | +import { dingRule, emailRule, phoneRule } from '/@/utils/rules'; | |
| 3 | 3 | import { useComponentRegister } from '/@/components/Form'; |
| 4 | 4 | import { OrgTreeSelect } from '../../common/OrgTreeSelect'; |
| 5 | 5 | useComponentRegister('OrgTreeSelect', OrgTreeSelect); |
| ... | ... | @@ -31,6 +31,11 @@ export const columns: BasicColumn[] = [ |
| 31 | 31 | width: 180, |
| 32 | 32 | }, |
| 33 | 33 | { |
| 34 | + title: '钉钉', | |
| 35 | + dataIndex: 'dingtalk', | |
| 36 | + width: 160, | |
| 37 | + }, | |
| 38 | + { | |
| 34 | 39 | title: '备注', |
| 35 | 40 | dataIndex: 'remark', |
| 36 | 41 | width: 120, |
| ... | ... | @@ -109,6 +114,17 @@ export const formSchema: FormSchema[] = [ |
| 109 | 114 | }, |
| 110 | 115 | }, |
| 111 | 116 | { |
| 117 | + field: 'dingtalk', | |
| 118 | + label: '钉钉', | |
| 119 | + component: 'Input', | |
| 120 | + helpMessage: '请输入与钉钉相关联的手机号', | |
| 121 | + rules: dingRule, | |
| 122 | + componentProps: { | |
| 123 | + placeholder: '不填默认为手机号码', | |
| 124 | + maxLength: 11, | |
| 125 | + }, | |
| 126 | + }, | |
| 127 | + { | |
| 112 | 128 | field: 'remark', |
| 113 | 129 | label: '备注', |
| 114 | 130 | component: 'InputTextArea', | ... | ... |
| ... | ... | @@ -127,10 +127,19 @@ export function useAlarmNotify(params: UseAlarmNotifyParams = {}) { |
| 127 | 127 | clearInterval(timeout as NodeJS.Timer); |
| 128 | 128 | timeout = null; |
| 129 | 129 | }; |
| 130 | + | |
| 130 | 131 | onMounted(() => { |
| 131 | 132 | if (getRoleHasNotifyFlag()) polling(); |
| 132 | 133 | }); |
| 133 | 134 | |
| 135 | + document.addEventListener('visibilitychange', () => { | |
| 136 | + if (document.hidden) { | |
| 137 | + clearTimeout(); | |
| 138 | + } else { | |
| 139 | + polling(); | |
| 140 | + } | |
| 141 | + }); | |
| 142 | + | |
| 134 | 143 | onUnmounted(() => { |
| 135 | 144 | clearTimeout(); |
| 136 | 145 | }); | ... | ... |
| ... | ... | @@ -16,15 +16,17 @@ |
| 16 | 16 | value?: string | string[]; |
| 17 | 17 | apiTreeSelectProps?: Recordable; |
| 18 | 18 | showCreate?: boolean; |
| 19 | + disabled?: boolean; | |
| 19 | 20 | }>(), |
| 20 | 21 | { |
| 21 | 22 | showCreate: true, |
| 23 | + disabled: false, | |
| 22 | 24 | } |
| 23 | 25 | ); |
| 24 | 26 | |
| 25 | 27 | const needReload = ref(true); |
| 26 | 28 | |
| 27 | - const emit = defineEmits(['change']); | |
| 29 | + const emit = defineEmits(['change', 'optionsChange']); | |
| 28 | 30 | |
| 29 | 31 | const handleOpenCreate = () => { |
| 30 | 32 | openDrawer(true, { isUpdate: false }); |
| ... | ... | @@ -35,13 +37,14 @@ |
| 35 | 37 | const orgList = ref<Recordable[]>([]); |
| 36 | 38 | |
| 37 | 39 | const getBindProps = computed<Recordable>(() => { |
| 38 | - const { value, apiTreeSelectProps = {} } = props; | |
| 40 | + const { value, apiTreeSelectProps = {}, disabled } = props; | |
| 39 | 41 | const { params = {} } = apiTreeSelectProps; |
| 40 | 42 | return { |
| 41 | 43 | replaceFields: { children: 'children', key: 'id', title: 'name', value: 'id' }, |
| 42 | 44 | getPopupContainer: () => document.body, |
| 43 | 45 | placeholder: '请选择所属组织', |
| 44 | 46 | maxLength: 250, |
| 47 | + disabled, | |
| 45 | 48 | ...apiTreeSelectProps, |
| 46 | 49 | value, |
| 47 | 50 | dropdownStyle: { maxHeight: '300px' }, |
| ... | ... | @@ -63,6 +66,7 @@ |
| 63 | 66 | onChange: (...args: any[]) => { |
| 64 | 67 | emit('change', ...args); |
| 65 | 68 | }, |
| 69 | + onOptionsChange: (...args: any[]) => emit('optionsChange', ...args), | |
| 66 | 70 | }; |
| 67 | 71 | }); |
| 68 | 72 | |
| ... | ... | @@ -80,7 +84,9 @@ |
| 80 | 84 | <template> |
| 81 | 85 | <section class="flex"> |
| 82 | 86 | <ApiTreeSelect v-bind="getBindProps" /> |
| 83 | - <Button v-if="getShowCreate" type="link" @click="handleOpenCreate">新增组织</Button> | |
| 87 | + <Button v-if="getShowCreate" type="link" @click="handleOpenCreate" :disabled="disabled" | |
| 88 | + >新增组织</Button | |
| 89 | + > | |
| 84 | 90 | <OrganizationDrawer v-if="getShowCreate" @register="registerDrawer" @success="handleReload" /> |
| 85 | 91 | </section> |
| 86 | 92 | </template> | ... | ... |
| ... | ... | @@ -222,6 +222,14 @@ |
| 222 | 222 | </div> |
| 223 | 223 | </template> |
| 224 | 224 | <template class="ant-card-actions" #actions> |
| 225 | + <Tooltip title="预览"> | |
| 226 | + <AuthIcon | |
| 227 | + :auth="ConfigurationTemplatePermission.PREVIEW" | |
| 228 | + class="!text-lg" | |
| 229 | + icon="ant-design:eye-outlined" | |
| 230 | + @click="handlePreview(item)" | |
| 231 | + /> | |
| 232 | + </Tooltip> | |
| 225 | 233 | <Tooltip v-if="!isCustomerUser" title="设计"> |
| 226 | 234 | <AuthIcon |
| 227 | 235 | :auth="ConfigurationTemplatePermission.DESIGN" | ... | ... |
| ... | ... | @@ -232,12 +232,6 @@ export const schemas = (): FormSchema[] => { |
| 232 | 232 | component: 'InputGroup', |
| 233 | 233 | required: true, |
| 234 | 234 | colProps: { span: 24 }, |
| 235 | - componentProps: ({ formActionType }) => { | |
| 236 | - const { getFieldsValue } = formActionType; | |
| 237 | - return { | |
| 238 | - type: getFieldsValue().requestContentType, | |
| 239 | - }; | |
| 240 | - }, | |
| 241 | 235 | }, |
| 242 | 236 | { |
| 243 | 237 | field: 'fillAddress', | ... | ... |
| ... | ... | @@ -127,6 +127,15 @@ |
| 127 | 127 | showActionButtonGroup: false, |
| 128 | 128 | }); |
| 129 | 129 | |
| 130 | + const updatePartFormScheme = (requestType: string) => { | |
| 131 | + updateSchema({ | |
| 132 | + field: 'requestHttpTypeAndUrl', | |
| 133 | + componentProps: { | |
| 134 | + type: requestType, | |
| 135 | + }, | |
| 136 | + }); | |
| 137 | + }; | |
| 138 | + | |
| 130 | 139 | const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => { |
| 131 | 140 | await resetFields(); |
| 132 | 141 | await nextTick(); |
| ... | ... | @@ -152,13 +161,12 @@ |
| 152 | 161 | requestUrl: data.record?.requestUrl, |
| 153 | 162 | }, |
| 154 | 163 | }); |
| 155 | - await nextTick(() => simpleRequestRef.value?.setValue(data.record, false, [])); | |
| 156 | - updateSchema({ | |
| 157 | - field: 'requestHttpTypeAndUrl', | |
| 158 | - componentProps: { | |
| 159 | - type: String(data.record?.requestContentType), | |
| 160 | - }, | |
| 164 | + await nextTick(() => { | |
| 165 | + simpleRequestRef.value?.setValue(data.record, false, []); | |
| 166 | + updatePartFormScheme(String(data.record?.requestContentType)); | |
| 161 | 167 | }); |
| 168 | + } else { | |
| 169 | + await updatePartFormScheme(RequestMethodTypeEnum.COMMOM); | |
| 162 | 170 | } |
| 163 | 171 | }); |
| 164 | 172 | ... | ... |
| 1 | +<script setup lang="ts"> | |
| 2 | + import { computed, unref } from 'vue'; | |
| 3 | + import { ref } from 'vue'; | |
| 4 | + import { BasicModal, useModalInner } from '/@/components/Modal'; | |
| 5 | + import { schemas } from '../index'; | |
| 6 | + import { useForm, BasicForm } from '/@/components/Form'; | |
| 7 | + | |
| 8 | + import { deviceProfileCategory } from '/@/api/device/classModal'; | |
| 9 | + import { useMessage } from '/@/hooks/web/useMessage'; | |
| 10 | + | |
| 11 | + const emit = defineEmits(['handleReload', 'register']); | |
| 12 | + | |
| 13 | + const isUpdate = ref<Boolean>(false); | |
| 14 | + const getTitle = computed(() => (!unref(isUpdate) ? '新增品类' : '编辑品类')); | |
| 15 | + const { createMessage } = useMessage(); | |
| 16 | + | |
| 17 | + const [registerForm, { getFieldsValue, setFieldsValue, validate }] = useForm({ | |
| 18 | + labelWidth: 140, | |
| 19 | + schemas, | |
| 20 | + actionColOptions: { | |
| 21 | + span: 14, | |
| 22 | + }, | |
| 23 | + showActionButtonGroup: false, | |
| 24 | + }); | |
| 25 | + const recordInfo = ref<any>({}); | |
| 26 | + | |
| 27 | + const [register, { closeModal, setModalProps }] = useModalInner(async (data) => { | |
| 28 | + console.log(123131, data); | |
| 29 | + setModalProps({ confirmLoading: false, loading: true }); | |
| 30 | + isUpdate.value = data?.isUpdate; | |
| 31 | + recordInfo.value = data?.record; | |
| 32 | + if (data?.record) { | |
| 33 | + setFieldsValue(data?.record); | |
| 34 | + } | |
| 35 | + setModalProps({ loading: false }); | |
| 36 | + }); | |
| 37 | + | |
| 38 | + const handleCancel = () => { | |
| 39 | + closeModal(); | |
| 40 | + }; | |
| 41 | + | |
| 42 | + const handleOk = async () => { | |
| 43 | + await validate(); | |
| 44 | + let values = getFieldsValue(); | |
| 45 | + if (unref(isUpdate)) { | |
| 46 | + values = { ...values, id: unref(recordInfo).id }; | |
| 47 | + } | |
| 48 | + await deviceProfileCategory(values); | |
| 49 | + createMessage.success('操作成功'); | |
| 50 | + emit('handleReload'); | |
| 51 | + handleCancel(); | |
| 52 | + }; | |
| 53 | +</script> | |
| 54 | + | |
| 55 | +<template> | |
| 56 | + <div> | |
| 57 | + <BasicModal | |
| 58 | + v-bind="$attrs" | |
| 59 | + width="30rem" | |
| 60 | + :title="getTitle" | |
| 61 | + @register="register" | |
| 62 | + @cancel="handleCancel" | |
| 63 | + @ok="handleOk" | |
| 64 | + destroyOnClose | |
| 65 | + > | |
| 66 | + <div> | |
| 67 | + <BasicForm @register="registerForm" /> | |
| 68 | + </div> | |
| 69 | + </BasicModal> | |
| 70 | + </div> | |
| 71 | +</template> | ... | ... |
src/views/device/classIfication/index.ts
0 → 100644
| 1 | +import { BasicColumn, FormSchema } from '/@/components/Table'; | |
| 2 | +import { findDictItemByCode } from '/@/api/system/dict'; | |
| 3 | + | |
| 4 | +import { DictEnum } from '/@/enums/dictEnum'; | |
| 5 | + | |
| 6 | +export const columns: BasicColumn[] = [ | |
| 7 | + { | |
| 8 | + title: '名称', | |
| 9 | + dataIndex: 'name', | |
| 10 | + }, | |
| 11 | + { | |
| 12 | + title: '领域', | |
| 13 | + dataIndex: 'dictItemName', | |
| 14 | + }, | |
| 15 | + { | |
| 16 | + title: '状态', | |
| 17 | + dataIndex: 'status', | |
| 18 | + slots: { customRender: 'status' }, | |
| 19 | + }, | |
| 20 | +]; | |
| 21 | + | |
| 22 | +export const searchFormSchema: FormSchema[] = [ | |
| 23 | + { | |
| 24 | + field: 'name', | |
| 25 | + label: '名称', | |
| 26 | + component: 'Input', | |
| 27 | + colProps: { span: 6 }, | |
| 28 | + componentProps: { | |
| 29 | + maxLength: 255, | |
| 30 | + placeholder: '请输入品类名称', | |
| 31 | + }, | |
| 32 | + }, | |
| 33 | + { | |
| 34 | + field: 'status', | |
| 35 | + label: '状态', | |
| 36 | + component: 'Select', | |
| 37 | + colProps: { span: 6 }, | |
| 38 | + componentProps: { | |
| 39 | + options: [ | |
| 40 | + { label: '启用', value: '1' }, | |
| 41 | + { label: '禁用', value: '0' }, | |
| 42 | + ], | |
| 43 | + placeholder: '请选择品类状态', | |
| 44 | + }, | |
| 45 | + }, | |
| 46 | + { | |
| 47 | + field: 'dictItemId', | |
| 48 | + label: '领域', | |
| 49 | + component: 'ApiSelect', | |
| 50 | + colProps: { span: 6 }, | |
| 51 | + componentProps() { | |
| 52 | + return { | |
| 53 | + api: findDictItemByCode, | |
| 54 | + params: { | |
| 55 | + dictCode: DictEnum.CATEGORY_FIELD, | |
| 56 | + }, | |
| 57 | + labelField: 'itemText', | |
| 58 | + valueField: 'itemValue', | |
| 59 | + placeholder: '请选择领域', | |
| 60 | + getPopupContainer: () => document.body, | |
| 61 | + }; | |
| 62 | + }, | |
| 63 | + }, | |
| 64 | +]; | |
| 65 | + | |
| 66 | +export const schemas: FormSchema[] = [ | |
| 67 | + { | |
| 68 | + field: 'name', | |
| 69 | + label: '品类名称', | |
| 70 | + component: 'Input', | |
| 71 | + colProps: { span: 21 }, | |
| 72 | + required: true, | |
| 73 | + componentProps: { | |
| 74 | + maxLength: 20, | |
| 75 | + }, | |
| 76 | + }, | |
| 77 | + { | |
| 78 | + field: 'dictItemId', | |
| 79 | + label: '领域', | |
| 80 | + component: 'ApiSelect', | |
| 81 | + colProps: { span: 21 }, | |
| 82 | + required: true, | |
| 83 | + componentProps({ formActionType }) { | |
| 84 | + return { | |
| 85 | + api: findDictItemByCode, | |
| 86 | + params: { | |
| 87 | + dictCode: DictEnum.CATEGORY_FIELD, | |
| 88 | + }, | |
| 89 | + onChange(value, options) { | |
| 90 | + formActionType.setFieldsValue({ dictItemName: value ? options.label : '' }); | |
| 91 | + }, | |
| 92 | + labelField: 'itemText', | |
| 93 | + valueField: 'itemValue', | |
| 94 | + placeholder: '请选择领域', | |
| 95 | + getPopupContainer: () => document.body, | |
| 96 | + }; | |
| 97 | + }, | |
| 98 | + }, | |
| 99 | + { | |
| 100 | + field: 'dictItemName', | |
| 101 | + label: '领域名称', | |
| 102 | + ifShow: false, | |
| 103 | + component: 'Input', | |
| 104 | + }, | |
| 105 | + { | |
| 106 | + field: 'status', | |
| 107 | + label: '状态', | |
| 108 | + component: 'RadioButtonGroup', | |
| 109 | + defaultValue: 1, | |
| 110 | + componentProps: { | |
| 111 | + options: [ | |
| 112 | + { label: '启用', value: 1 }, | |
| 113 | + { label: '禁用', value: 0 }, | |
| 114 | + ], | |
| 115 | + }, | |
| 116 | + }, | |
| 117 | +]; | ... | ... |
src/views/device/classIfication/index.vue
0 → 100644
| 1 | +<script setup lang="ts"> | |
| 2 | + import { ref } from 'vue'; | |
| 3 | + import { columns, searchFormSchema } from '.'; | |
| 4 | + import { BasicTable, useTable, TableAction } from '/@/components/Table'; | |
| 5 | + import { Button, Popconfirm, Switch } from 'ant-design-vue'; | |
| 6 | + import { useBatchOperation } from '/@/utils/useBatchOperation'; | |
| 7 | + import { useMessage } from '/@/hooks/web/useMessage'; | |
| 8 | + import { Authority } from '/@/components/Authority'; | |
| 9 | + import { useModal } from '/@/components/Modal'; | |
| 10 | + import { classModal } from './components/index'; | |
| 11 | + import { useDrawer } from '/@/components/Drawer'; | |
| 12 | + import { USER_INFO_KEY } from '/@/enums/cacheEnum'; | |
| 13 | + import { getAuthCache } from '/@/utils/auth'; | |
| 14 | + import { authBtn } from '/@/enums/roleEnum'; | |
| 15 | + import { | |
| 16 | + getDeviceClassList, | |
| 17 | + deleteDeviceClass, | |
| 18 | + deviceProfileCategory, | |
| 19 | + } from '/@/api/device/classModal'; | |
| 20 | + | |
| 21 | + import { BasicDrawer } from '/@/components/Drawer'; | |
| 22 | + import PhysicalModelManagementStep from '/@/views/device/profiles/step/PhysicalModelManagementStep.vue'; | |
| 23 | + const [ | |
| 24 | + registerTable, | |
| 25 | + { reload, setLoading, getSelectRowKeys, setSelectedRowKeys, getRowSelection }, | |
| 26 | + ] = useTable({ | |
| 27 | + title: '产品品类列表', | |
| 28 | + api: getDeviceClassList, | |
| 29 | + columns, | |
| 30 | + formConfig: { | |
| 31 | + labelWidth: 100, | |
| 32 | + schemas: searchFormSchema, | |
| 33 | + }, | |
| 34 | + immediate: true, | |
| 35 | + useSearchForm: true, | |
| 36 | + showTableSetting: true, | |
| 37 | + bordered: true, | |
| 38 | + showIndexColumn: false, | |
| 39 | + clickToRowSelect: false, | |
| 40 | + rowKey: 'id', | |
| 41 | + // searchInfo: searchInfo, | |
| 42 | + actionColumn: { | |
| 43 | + width: 230, | |
| 44 | + title: '操作', | |
| 45 | + slots: { customRender: 'action' }, | |
| 46 | + fixed: 'right', | |
| 47 | + }, | |
| 48 | + rowSelection: { | |
| 49 | + type: 'checkbox', | |
| 50 | + getCheckboxProps: (record: any) => { | |
| 51 | + return { disabled: !!record.status }; | |
| 52 | + }, | |
| 53 | + }, | |
| 54 | + }); | |
| 55 | + | |
| 56 | + const [registerModal, { openModal }] = useModal(); | |
| 57 | + const [registerDetailDrawer, { openDrawer }] = useDrawer(); | |
| 58 | + | |
| 59 | + const { createMessage } = useMessage(); | |
| 60 | + const { isExistOption } = useBatchOperation(getRowSelection, setSelectedRowKeys); | |
| 61 | + | |
| 62 | + const switchLoading = ref<boolean>(false); | |
| 63 | + | |
| 64 | + const userInfo: any = getAuthCache(USER_INFO_KEY); | |
| 65 | + const role: string = userInfo.roles[0]; | |
| 66 | + | |
| 67 | + const handleReload = () => { | |
| 68 | + setSelectedRowKeys([]); | |
| 69 | + reload(); | |
| 70 | + }; | |
| 71 | + | |
| 72 | + // 新增 | |
| 73 | + const handleCreate = () => { | |
| 74 | + openModal(true, { | |
| 75 | + isUpdate: false, | |
| 76 | + }); | |
| 77 | + }; | |
| 78 | + | |
| 79 | + // 编辑 | |
| 80 | + const handleEdit = (record?: any) => { | |
| 81 | + openModal(true, { | |
| 82 | + isUpdate: true, | |
| 83 | + record, | |
| 84 | + }); | |
| 85 | + }; | |
| 86 | + | |
| 87 | + // 详情 | |
| 88 | + const registerDetailRecord = ref<any>({}); | |
| 89 | + const handleDetail = (record?: any) => { | |
| 90 | + openDrawer(true); | |
| 91 | + registerDetailRecord.value = { | |
| 92 | + ...record, | |
| 93 | + ifShowClass: true, | |
| 94 | + }; | |
| 95 | + }; | |
| 96 | + | |
| 97 | + // 状态->编辑 | |
| 98 | + const handleSwitch = async (e: any, record: any) => { | |
| 99 | + switchLoading.value = true; | |
| 100 | + console.log(e, record); | |
| 101 | + await deviceProfileCategory({ ...record, status: e }); | |
| 102 | + switchLoading.value = false; | |
| 103 | + createMessage.success('操作成功'); | |
| 104 | + handleReload(); | |
| 105 | + }; | |
| 106 | + | |
| 107 | + // 删除 | |
| 108 | + const handleDelete = async (record?: any) => { | |
| 109 | + let ids: string[] = []; | |
| 110 | + if (record) { | |
| 111 | + ids = [record.id]; | |
| 112 | + } else { | |
| 113 | + ids = getSelectRowKeys(); | |
| 114 | + } | |
| 115 | + try { | |
| 116 | + setLoading(true); | |
| 117 | + await deleteDeviceClass({ ids }); | |
| 118 | + createMessage.success('删除成功'); | |
| 119 | + handleReload(); | |
| 120 | + } catch (error) { | |
| 121 | + throw error; | |
| 122 | + } finally { | |
| 123 | + setLoading(false); | |
| 124 | + } | |
| 125 | + }; | |
| 126 | +</script> | |
| 127 | +<template> | |
| 128 | + <div> | |
| 129 | + <BasicTable style="flex: auto" @register="registerTable"> | |
| 130 | + <template #toolbar> | |
| 131 | + <Authority value="api:yt:product:category:post"> | |
| 132 | + <Button type="primary" @click="handleCreate"> 新增品类 </Button> | |
| 133 | + </Authority> | |
| 134 | + <Authority value="api:yt:product:category:delete"> | |
| 135 | + <Popconfirm | |
| 136 | + title="您确定要批量删除数据" | |
| 137 | + ok-text="确定" | |
| 138 | + cancel-text="取消" | |
| 139 | + @confirm="handleDelete()" | |
| 140 | + > | |
| 141 | + <a-button color="error" :disabled="!isExistOption"> 批量删除 </a-button> | |
| 142 | + </Popconfirm> | |
| 143 | + </Authority> | |
| 144 | + </template> | |
| 145 | + <template #status="{ record }"> | |
| 146 | + <Switch | |
| 147 | + @click="(e) => handleSwitch(e, record)" | |
| 148 | + :loading="switchLoading" | |
| 149 | + v-model:checked="record.status" | |
| 150 | + checked-children="启用" | |
| 151 | + un-checked-children="禁用" | |
| 152 | + :checkedValue="1" | |
| 153 | + :unCheckedValue="0" | |
| 154 | + /> | |
| 155 | + </template> | |
| 156 | + <template #action="{ record }"> | |
| 157 | + <TableAction | |
| 158 | + :actions="[ | |
| 159 | + { | |
| 160 | + label: '详情', | |
| 161 | + icon: 'ant-design:eye-outlined', | |
| 162 | + auth: 'api:yt:product:category:get', | |
| 163 | + onClick: handleDetail.bind(null, record), | |
| 164 | + }, | |
| 165 | + { | |
| 166 | + label: '编辑', | |
| 167 | + auth: 'api:yt:product:category:update', | |
| 168 | + icon: 'clarity:note-edit-line', | |
| 169 | + ifShow: authBtn(role), | |
| 170 | + onClick: handleEdit.bind(null, record), | |
| 171 | + }, | |
| 172 | + { | |
| 173 | + label: '删除', | |
| 174 | + auth: 'api:yt:product:category:delete', | |
| 175 | + icon: 'ant-design:delete-outlined', | |
| 176 | + ifShow: authBtn(role) && !record.status, | |
| 177 | + color: 'error', | |
| 178 | + popConfirm: { | |
| 179 | + title: '是否确认删除', | |
| 180 | + confirm: handleDelete.bind(null, record), | |
| 181 | + }, | |
| 182 | + }, | |
| 183 | + ]" | |
| 184 | + /> | |
| 185 | + </template> | |
| 186 | + </BasicTable> | |
| 187 | + <classModal @register="registerModal" @handleReload="handleReload" /> | |
| 188 | + <!-- <physicalModel @register="registerDetailDrawer" :record /> --> | |
| 189 | + <BasicDrawer title="物模型" @register="registerDetailDrawer" width="60%" destroy-on-close> | |
| 190 | + <PhysicalModelManagementStep :record="registerDetailRecord" /> | |
| 191 | + </BasicDrawer> | |
| 192 | + </div> | |
| 193 | +</template> | ... | ... |
| ... | ... | @@ -16,6 +16,9 @@ import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue'; |
| 16 | 16 | import { createImgPreview } from '/@/components/Preview'; |
| 17 | 17 | import { uploadThumbnail } from '/@/api/configuration/center/configurationCenter'; |
| 18 | 18 | |
| 19 | +import { getOrganizationList } from '/@/api/system/system'; | |
| 20 | +import { copyTransFun } from '/@/utils/fnUtils'; | |
| 21 | + | |
| 19 | 22 | useComponentRegister('JSONEditor', JSONEditor); |
| 20 | 23 | useComponentRegister('ObjectModelValidateForm', ObjectModelValidateForm); |
| 21 | 24 | |
| ... | ... | @@ -263,22 +266,15 @@ export const step1Schemas: FormSchema[] = [ |
| 263 | 266 | ifShow: ({ values }) => isGateWay(values.deviceType), |
| 264 | 267 | }, |
| 265 | 268 | { |
| 266 | - field: 'organizationId', | |
| 267 | - label: '所属组织', | |
| 268 | - component: 'Input', | |
| 269 | - required: true, | |
| 270 | - slot: 'addOrg', | |
| 271 | - }, | |
| 272 | - { | |
| 273 | 269 | field: 'gatewayId', |
| 274 | 270 | label: '网关设备', |
| 275 | 271 | required: true, |
| 276 | 272 | component: 'ApiSelect', |
| 277 | - ifShow: ({ values }) => values.deviceType === 'SENSOR' && values.organizationId, | |
| 273 | + ifShow: ({ values }) => values.deviceType === 'SENSOR', | |
| 278 | 274 | componentProps: ({ formModel, formActionType }) => { |
| 279 | - const { organizationId, transportType } = formModel; | |
| 275 | + const { transportType } = formModel; | |
| 280 | 276 | const { validateFields } = formActionType; |
| 281 | - if (![organizationId, transportType].every(Boolean)) return {}; | |
| 277 | + if (!transportType) return {}; | |
| 282 | 278 | return { |
| 283 | 279 | api: async (params: Recordable) => { |
| 284 | 280 | try { |
| ... | ... | @@ -291,19 +287,36 @@ export const step1Schemas: FormSchema[] = [ |
| 291 | 287 | }, |
| 292 | 288 | showSearch: true, |
| 293 | 289 | params: { |
| 294 | - organizationId, | |
| 295 | 290 | transportType, |
| 296 | 291 | }, |
| 297 | 292 | valueField: 'tbDeviceId', |
| 298 | 293 | labelField: 'alias', |
| 299 | - onChange: async () => { | |
| 294 | + onChange: async (value, options) => { | |
| 300 | 295 | await nextTick(); |
| 296 | + if (value) { | |
| 297 | + const data = await getOrganizationList({ organizationId: options?.organizationId }); | |
| 298 | + copyTransFun(data as any as any[]); | |
| 299 | + formModel.organizationList = data; | |
| 300 | + } | |
| 301 | 301 | validateFields(['gatewayId']); |
| 302 | 302 | }, |
| 303 | 303 | }; |
| 304 | 304 | }, |
| 305 | 305 | }, |
| 306 | 306 | { |
| 307 | + field: 'organizationList', | |
| 308 | + label: '依据网关设备请求的组织数组', | |
| 309 | + component: 'Input', | |
| 310 | + ifShow: false, | |
| 311 | + }, | |
| 312 | + { | |
| 313 | + field: 'organizationId', | |
| 314 | + label: '所属组织', | |
| 315 | + component: 'Select', | |
| 316 | + required: true, | |
| 317 | + slot: 'addOrg', | |
| 318 | + }, | |
| 319 | + { | |
| 307 | 320 | field: 'label', |
| 308 | 321 | label: '设备标签', |
| 309 | 322 | component: 'Input', | ... | ... |
| ... | ... | @@ -14,7 +14,7 @@ |
| 14 | 14 | placeholder="请选择组织" |
| 15 | 15 | allow-clear |
| 16 | 16 | tree-default-expand-all |
| 17 | - :tree-data="treeData" | |
| 17 | + :tree-data="model?.['organizationList'] || treeData" | |
| 18 | 18 | /> |
| 19 | 19 | </div> |
| 20 | 20 | <div> |
| ... | ... | @@ -49,44 +49,46 @@ |
| 49 | 49 | centered |
| 50 | 50 | > |
| 51 | 51 | <div> |
| 52 | - <Form :label-col="labelCol" :colon="false" :rules="rules" :model="positionState"> | |
| 53 | - <Row :gutter="20" class="mt-4"> | |
| 54 | - <Col :span="20"> | |
| 55 | - <FormItem label="搜索位置"> | |
| 56 | - <AutoComplete | |
| 57 | - v-model:value="positionState.address" | |
| 58 | - :options="dataSource" | |
| 59 | - style="width: 100%" | |
| 60 | - placeholder="搜索位置" | |
| 61 | - @search="debounceSearch" | |
| 62 | - @select="handleSelect" | |
| 63 | - backfill | |
| 64 | - /> | |
| 65 | - </FormItem> | |
| 66 | - </Col> | |
| 67 | - </Row> | |
| 68 | - <Row :gutter="20" class=""> | |
| 69 | - <Col :span="10"> | |
| 70 | - <FormItem label="经度" name="longitude"> | |
| 71 | - <Input | |
| 72 | - @blur="redirectPosition" | |
| 73 | - @change="redirectPosition" | |
| 74 | - v-model:value="positionState.longitude" | |
| 75 | - /> | |
| 76 | - </FormItem> | |
| 77 | - </Col> | |
| 78 | - <Col :span="10"> | |
| 79 | - <FormItem label="纬度" name="latitude"> | |
| 80 | - <Input | |
| 81 | - @blur="redirectPosition" | |
| 82 | - @change="redirectPosition" | |
| 83 | - v-model:value="positionState.latitude" | |
| 84 | - /> | |
| 85 | - </FormItem> | |
| 86 | - </Col> | |
| 87 | - </Row> | |
| 88 | - </Form> | |
| 89 | - <div ref="wrapRef" style="height: 300px; width: 90%" class="ml-6"></div> | |
| 52 | + <Spin :spinning="spinning"> | |
| 53 | + <Form :label-col="labelCol" :colon="false" :rules="rules" :model="positionState"> | |
| 54 | + <Row :gutter="20" class="mt-4"> | |
| 55 | + <Col :span="20"> | |
| 56 | + <FormItem label="搜索位置"> | |
| 57 | + <AutoComplete | |
| 58 | + v-model:value="positionState.address" | |
| 59 | + :options="dataSource" | |
| 60 | + style="width: 100%" | |
| 61 | + placeholder="搜索位置" | |
| 62 | + @search="debounceSearch" | |
| 63 | + @select="handleSelect" | |
| 64 | + backfill | |
| 65 | + /> | |
| 66 | + </FormItem> | |
| 67 | + </Col> | |
| 68 | + </Row> | |
| 69 | + <Row :gutter="20" class=""> | |
| 70 | + <Col :span="10"> | |
| 71 | + <FormItem label="经度" name="longitude"> | |
| 72 | + <Input | |
| 73 | + @blur="redirectPosition" | |
| 74 | + @change="redirectPosition" | |
| 75 | + v-model:value="positionState.longitude" | |
| 76 | + /> | |
| 77 | + </FormItem> | |
| 78 | + </Col> | |
| 79 | + <Col :span="10"> | |
| 80 | + <FormItem label="纬度" name="latitude"> | |
| 81 | + <Input | |
| 82 | + @blur="redirectPosition" | |
| 83 | + @change="redirectPosition" | |
| 84 | + v-model:value="positionState.latitude" | |
| 85 | + /> | |
| 86 | + </FormItem> | |
| 87 | + </Col> | |
| 88 | + </Row> | |
| 89 | + </Form> | |
| 90 | + <div ref="wrapRef" style="height: 300px; width: 90%" class="ml-6"></div> | |
| 91 | + </Spin> | |
| 90 | 92 | </div> |
| 91 | 93 | </Modal> |
| 92 | 94 | <DeptDrawer @register="registerModal" @success="handleSuccess" /> |
| ... | ... | @@ -97,7 +99,7 @@ |
| 97 | 99 | import { BasicForm, useForm } from '/@/components/Form'; |
| 98 | 100 | import { step1Schemas } from '../../config/data'; |
| 99 | 101 | import { useScript } from '/@/hooks/web/useScript'; |
| 100 | - import { Input, message, Modal, Form, Row, Col, AutoComplete } from 'ant-design-vue'; | |
| 102 | + import { Input, message, Modal, Form, Row, Col, AutoComplete, Spin } from 'ant-design-vue'; | |
| 101 | 103 | import { EnvironmentTwoTone } from '@ant-design/icons-vue'; |
| 102 | 104 | import { upload } from '/@/api/oss/ossFileUploader'; |
| 103 | 105 | import { BAI_DU_MAP_URL } from '/@/utils/fnUtils'; |
| ... | ... | @@ -113,6 +115,8 @@ |
| 113 | 115 | import { toRaw } from 'vue'; |
| 114 | 116 | import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue'; |
| 115 | 117 | import { buildUUID } from '/@/utils/uuid'; |
| 118 | + import { useMessage } from '/@/hooks/web/useMessage'; | |
| 119 | + import { computed } from 'vue'; | |
| 116 | 120 | |
| 117 | 121 | export default defineComponent({ |
| 118 | 122 | components: { |
| ... | ... | @@ -126,6 +130,7 @@ |
| 126 | 130 | Row, |
| 127 | 131 | Col, |
| 128 | 132 | DeptDrawer, |
| 133 | + Spin, | |
| 129 | 134 | }, |
| 130 | 135 | props: { |
| 131 | 136 | isUpdate: { |
| ... | ... | @@ -134,9 +139,14 @@ |
| 134 | 139 | }, |
| 135 | 140 | emits: ['next'], |
| 136 | 141 | setup(props, { emit }) { |
| 142 | + const { createMessage } = useMessage(); | |
| 137 | 143 | const orgData: any = reactive({ |
| 138 | 144 | treeData: [], |
| 139 | 145 | }); |
| 146 | + const isUpdate1 = computed(() => { | |
| 147 | + const { isUpdate } = props; | |
| 148 | + return isUpdate; | |
| 149 | + }); | |
| 140 | 150 | const getOrganizationListFunc = async () => { |
| 141 | 151 | const data = await getOrganizationList(); |
| 142 | 152 | copyTransFun(data as any as any[]); |
| ... | ... | @@ -168,17 +178,27 @@ |
| 168 | 178 | const devicePic = ref(''); |
| 169 | 179 | const loading = ref(false); |
| 170 | 180 | |
| 171 | - const [register, { validate, resetFields, setFieldsValue, getFieldsValue, updateSchema }] = | |
| 172 | - useForm({ | |
| 173 | - labelWidth: 140, | |
| 174 | - schemas: step1Schemas, | |
| 175 | - actionColOptions: { | |
| 176 | - span: 14, | |
| 177 | - }, | |
| 178 | - labelAlign: 'right', | |
| 179 | - showResetButton: false, | |
| 180 | - showSubmitButton: false, | |
| 181 | - }); | |
| 181 | + const [ | |
| 182 | + register, | |
| 183 | + { | |
| 184 | + validate, | |
| 185 | + resetFields, | |
| 186 | + setFieldsValue, | |
| 187 | + getFieldsValue, | |
| 188 | + updateSchema, | |
| 189 | + clearValidate, | |
| 190 | + validateFields, | |
| 191 | + }, | |
| 192 | + ] = useForm({ | |
| 193 | + labelWidth: 140, | |
| 194 | + schemas: step1Schemas, | |
| 195 | + actionColOptions: { | |
| 196 | + span: 14, | |
| 197 | + }, | |
| 198 | + labelAlign: 'right', | |
| 199 | + showResetButton: false, | |
| 200 | + showSubmitButton: false, | |
| 201 | + }); | |
| 182 | 202 | async function nextStep() { |
| 183 | 203 | try { |
| 184 | 204 | let values = await validate(); |
| ... | ... | @@ -220,21 +240,53 @@ |
| 220 | 240 | }; |
| 221 | 241 | |
| 222 | 242 | // 地图的弹框 |
| 243 | + const spinning = ref<boolean>(false); | |
| 223 | 244 | const visible = ref(false); |
| 224 | - const selectPosition = () => { | |
| 245 | + const selectPosition = async () => { | |
| 225 | 246 | visible.value = true; |
| 226 | - if (!positionState.longitude) { | |
| 227 | - positionState.longitude = '104.05326410962411'; | |
| 228 | - positionState.latitude = '30.54855093076791'; | |
| 229 | - | |
| 230 | - // 根据经纬度获取详细位置 | |
| 231 | - if (positionState.longitude && positionState.latitude) { | |
| 232 | - var pt = new BMap.Point(positionState.longitude, positionState.latitude); | |
| 233 | - getAddrByPoint(pt); | |
| 247 | + if ( | |
| 248 | + !unref(isUpdate1) && | |
| 249 | + unref(devicePositionState).longitude && | |
| 250 | + unref(devicePositionState).latitude | |
| 251 | + ) { | |
| 252 | + positionState.longitude = unref(devicePositionState).longitude; | |
| 253 | + positionState.latitude = unref(devicePositionState).latitude; | |
| 254 | + } | |
| 255 | + if (!positionState.longitude || !positionState.latitude) { | |
| 256 | + let getLocalCity = new BMap.LocalCity(); | |
| 257 | + let getLocation = new BMap.Geolocation(); | |
| 258 | + const userAgent = navigator.userAgent; | |
| 259 | + try { | |
| 260 | + spinning.value = true; | |
| 261 | + if ( | |
| 262 | + (userAgent.indexOf('Chrome') > -1 || userAgent.indexOf('WebKit') > -1) && | |
| 263 | + userAgent.indexOf('Edg') == -1 | |
| 264 | + ) { | |
| 265 | + //判断是否是谷歌 或则是谷歌的内核 '104.05326410962411'; '30.54855093076791'; | |
| 266 | + await getLocalCity.get(function (res) { | |
| 267 | + positionState.longitude = res?.center.lng || '104.05326410962411'; | |
| 268 | + positionState.latitude = res?.center.lat || '30.54855093076791'; | |
| 269 | + var pt = new BMap.Point(positionState.longitude, positionState.latitude); | |
| 270 | + getAddrByPoint(pt); | |
| 271 | + spinning.value = false; | |
| 272 | + }); | |
| 273 | + } else { | |
| 274 | + await getLocation.getCurrentPosition(function (res) { | |
| 275 | + positionState.longitude = res?.longitude || '104.05326410962411'; | |
| 276 | + positionState.latitude = res?.latitude || '30.54855093076791'; | |
| 277 | + var pt = new BMap.Point(positionState.longitude, positionState.latitude); | |
| 278 | + getAddrByPoint(pt); | |
| 279 | + spinning.value = false; | |
| 280 | + }); | |
| 281 | + } | |
| 282 | + } catch (err) { | |
| 283 | + createMessage.error('获取定位失败'); | |
| 234 | 284 | } |
| 235 | 285 | initMap(positionState.longitude, positionState.latitude); |
| 236 | 286 | } else { |
| 237 | 287 | initMap(positionState.longitude, positionState.latitude); |
| 288 | + var pt = new BMap.Point(positionState.longitude, positionState.latitude); | |
| 289 | + getAddrByPoint(pt); | |
| 238 | 290 | } |
| 239 | 291 | }; |
| 240 | 292 | |
| ... | ... | @@ -447,11 +499,11 @@ |
| 447 | 499 | }); |
| 448 | 500 | } |
| 449 | 501 | |
| 450 | - const handleTreeOrg = () => { | |
| 451 | - const clearGatewayId = { | |
| 452 | - gatewayId: '', | |
| 453 | - }; | |
| 454 | - setFieldsValue(clearGatewayId); | |
| 502 | + const handleTreeOrg = (option: string) => { | |
| 503 | + if (option) clearValidate('organizationId'); | |
| 504 | + else { | |
| 505 | + validateFields(['organizationId']); | |
| 506 | + } | |
| 455 | 507 | }; |
| 456 | 508 | |
| 457 | 509 | return { |
| ... | ... | @@ -488,6 +540,7 @@ |
| 488 | 540 | handleSuccess, |
| 489 | 541 | handleTreeOrg, |
| 490 | 542 | devicePositionState, |
| 543 | + spinning, | |
| 491 | 544 | }; |
| 492 | 545 | }, |
| 493 | 546 | }); | ... | ... |
| ... | ... | @@ -15,13 +15,13 @@ |
| 15 | 15 | import { useHistoryData } from '../../hook/useHistoryData'; |
| 16 | 16 | import { formatToDateTime } from '/@/utils/dateUtil'; |
| 17 | 17 | import { useTable, BasicTable, BasicColumn } from '/@/components/Table'; |
| 18 | - import { DataTypeEnum } from '/@/components/Form/src/externalCompns/components/StructForm/config'; | |
| 19 | 18 | import { |
| 20 | 19 | ModeSwitchButton, |
| 21 | 20 | TABLE_CHART_MODE_LIST, |
| 22 | 21 | EnumTableChartMode, |
| 23 | 22 | } from '/@/components/Widget'; |
| 24 | 23 | import { SchemaFiled } from '/@/views/visual/palette/components/HistoryTrendModal/config'; |
| 24 | + import { DataTypeEnum } from '/@/enums/objectModelEnum'; | |
| 25 | 25 | |
| 26 | 26 | interface DeviceDetail { |
| 27 | 27 | tbDeviceId: string; |
| ... | ... | @@ -188,7 +188,7 @@ |
| 188 | 188 | method.setFieldsValue({ keys: props.attr }); |
| 189 | 189 | const attrInfo = unref(deviceAttrs).find((item) => item.identifier === props.attr); |
| 190 | 190 | if ( |
| 191 | - [DataTypeEnum.IS_STRING, DataTypeEnum.IS_STRUCT].includes( | |
| 191 | + [DataTypeEnum.STRING, DataTypeEnum.STRUCT].includes( | |
| 192 | 192 | attrInfo?.detail.dataType.type as unknown as DataTypeEnum |
| 193 | 193 | ) |
| 194 | 194 | ) { | ... | ... |
| ... | ... | @@ -16,7 +16,6 @@ |
| 16 | 16 | import { DeviceModelOfMatterAttrs, DeviceRecord } from '/@/api/device/model/deviceModel'; |
| 17 | 17 | import { Specs, StructJSON } from '/@/api/device/model/modelOfMatterModel'; |
| 18 | 18 | import { isArray, isNull, isObject } from '/@/utils/is'; |
| 19 | - import { DataTypeEnum } from '/@/components/Form/src/externalCompns/components/StructForm/config'; | |
| 20 | 19 | import { useGlobSetting } from '/@/hooks/setting'; |
| 21 | 20 | import { ModeSwitchButton, EnumTableCardMode } from '/@/components/Widget'; |
| 22 | 21 | import { toRaw } from 'vue'; |
| ... | ... | @@ -25,6 +24,7 @@ |
| 25 | 24 | import { ModalParamsType } from '/#/utils'; |
| 26 | 25 | import { AreaChartOutlined } from '@ant-design/icons-vue'; |
| 27 | 26 | import { SvgIcon } from '/@/components/Icon'; |
| 27 | + import { DataTypeEnum } from '/@/enums/objectModelEnum'; | |
| 28 | 28 | |
| 29 | 29 | interface ReceiveMessage { |
| 30 | 30 | data: { |
| ... | ... | @@ -220,7 +220,7 @@ |
| 220 | 220 | }; |
| 221 | 221 | |
| 222 | 222 | const isStructAndTextType = (type: DataTypeEnum) => { |
| 223 | - return [DataTypeEnum.IS_STRUCT, DataTypeEnum.IS_STRING].includes(type); | |
| 223 | + return [DataTypeEnum.STRUCT, DataTypeEnum.STRING].includes(type); | |
| 224 | 224 | }; |
| 225 | 225 | |
| 226 | 226 | const setDataSource = () => { |
| ... | ... | @@ -311,7 +311,7 @@ |
| 311 | 311 | }); |
| 312 | 312 | |
| 313 | 313 | const formatValue = (item: DataSource) => { |
| 314 | - return item.type === DataTypeEnum.IS_BOOL | |
| 314 | + return item.type === DataTypeEnum.BOOL | |
| 315 | 315 | ? !isNull(item.value) |
| 316 | 316 | ? !!Number(item.value) |
| 317 | 317 | ? item.boolOpen | ... | ... |
| ... | ... | @@ -6,7 +6,6 @@ |
| 6 | 6 | import { StructJSON } from '/@/api/device/model/modelOfMatterModel'; |
| 7 | 7 | import { BasicForm, useForm } from '/@/components/Form'; |
| 8 | 8 | import { BasicModal, useModalInner } from '/@/components/Modal'; |
| 9 | - import { DataTypeEnum } from '/@/views/device/profiles/step/cpns/physical/cpns/config'; | |
| 10 | 9 | import { sendCommandOneway } from '/@/api/dataBoard'; |
| 11 | 10 | import { useMessage } from '/@/hooks/web/useMessage'; |
| 12 | 11 | import { unref } from 'vue'; |
| ... | ... | @@ -14,6 +13,7 @@ |
| 14 | 13 | import { TaskTypeEnum } from '/@/views/task/center/config'; |
| 15 | 14 | import { SingleToHex, formSchemasConfig } from './config'; |
| 16 | 15 | import { TransportTypeEnum } from '/@/views/device/profiles/components/TransportDescript/const'; |
| 16 | + import { DataTypeEnum } from '/@/enums/objectModelEnum'; | |
| 17 | 17 | |
| 18 | 18 | defineEmits(['register']); |
| 19 | 19 | const props = defineProps<{ deviceId: string; deviceName: string }>(); |
| ... | ... | @@ -51,7 +51,7 @@ |
| 51 | 51 | |
| 52 | 52 | let schemas = [{ dataType: dataType, identifier, functionName: name } as StructJSON]; |
| 53 | 53 | |
| 54 | - if (type === DataTypeEnum.IS_STRUCT) { | |
| 54 | + if (type === DataTypeEnum.STRUCT) { | |
| 55 | 55 | schemas = dataType?.specs as StructJSON[]; |
| 56 | 56 | } |
| 57 | 57 | ... | ... |
| 1 | 1 | import { DataType, Specs, StructJSON } from '/@/api/device/model/modelOfMatterModel'; |
| 2 | 2 | import { JSONEditor } from '/@/components/CodeEditor'; |
| 3 | 3 | import { FormSchema, useComponentRegister } from '/@/components/Form'; |
| 4 | +import { DataTypeEnum } from '/@/enums/objectModelEnum'; | |
| 4 | 5 | import { useJsonParse } from '/@/hooks/business/useJsonParse'; |
| 5 | -import { DataTypeEnum } from '/@/views/device/profiles/step/cpns/physical/cpns/config'; | |
| 6 | 6 | |
| 7 | 7 | export interface BasicCreateFormParams { |
| 8 | 8 | identifier: string; |
| ... | ... | @@ -19,9 +19,9 @@ const validateDouble = ( |
| 19 | 19 | max?: number | string |
| 20 | 20 | ) => { |
| 21 | 21 | min = |
| 22 | - Number(min) || type === DataTypeEnum.IS_NUMBER_INT ? Number.MIN_SAFE_INTEGER : Number.MIN_VALUE; | |
| 22 | + Number(min) || type === DataTypeEnum.NUMBER_INT ? Number.MIN_SAFE_INTEGER : Number.MIN_VALUE; | |
| 23 | 23 | max = |
| 24 | - Number(max) || type === DataTypeEnum.IS_NUMBER_INT ? Number.MAX_SAFE_INTEGER : Number.MAX_VALUE; | |
| 24 | + Number(max) || type === DataTypeEnum.NUMBER_INT ? Number.MAX_SAFE_INTEGER : Number.MAX_VALUE; | |
| 25 | 25 | |
| 26 | 26 | return { |
| 27 | 27 | flag: value < min || value > max, |
| ... | ... | @@ -56,13 +56,11 @@ export const useGenDynamicForm = () => { |
| 56 | 56 | }, |
| 57 | 57 | ], |
| 58 | 58 | componentProps: { |
| 59 | - max: | |
| 60 | - max ?? type === DataTypeEnum.IS_NUMBER_INT ? Number.MAX_SAFE_INTEGER : Number.MAX_VALUE, | |
| 61 | - min: | |
| 62 | - min ?? type === DataTypeEnum.IS_NUMBER_INT ? Number.MIN_SAFE_INTEGER : Number.MIN_VALUE, | |
| 59 | + max: max ?? type === DataTypeEnum.NUMBER_INT ? Number.MAX_SAFE_INTEGER : Number.MAX_VALUE, | |
| 60 | + min: min ?? type === DataTypeEnum.NUMBER_INT ? Number.MIN_SAFE_INTEGER : Number.MIN_VALUE, | |
| 63 | 61 | step, |
| 64 | 62 | placeholder: `请输入${functionName}`, |
| 65 | - precision: type === DataTypeEnum.IS_NUMBER_INT ? 0 : 2, | |
| 63 | + precision: type === DataTypeEnum.NUMBER_INT ? 0 : 2, | |
| 66 | 64 | }, |
| 67 | 65 | } as FormSchema; |
| 68 | 66 | }; |
| ... | ... | @@ -141,11 +139,11 @@ export const useGenDynamicForm = () => { |
| 141 | 139 | }; |
| 142 | 140 | |
| 143 | 141 | const schemaMethod = { |
| 144 | - [DataTypeEnum.IS_BOOL]: createSelect, | |
| 145 | - [DataTypeEnum.IS_NUMBER_DOUBLE]: createInputNumber, | |
| 146 | - [DataTypeEnum.IS_NUMBER_INT]: createInputNumber, | |
| 147 | - [DataTypeEnum.IS_STRING]: createInput, | |
| 148 | - [DataTypeEnum.IS_STRUCT]: createInputJson, | |
| 142 | + [DataTypeEnum.BOOL]: createSelect, | |
| 143 | + [DataTypeEnum.NUMBER_DOUBLE]: createInputNumber, | |
| 144 | + [DataTypeEnum.NUMBER_INT]: createInputNumber, | |
| 145 | + [DataTypeEnum.STRING]: createInput, | |
| 146 | + [DataTypeEnum.STRUCT]: createInputJson, | |
| 149 | 147 | }; |
| 150 | 148 | |
| 151 | 149 | const fieldTypeMap = new Map<string, DataTypeEnum>(); |
| ... | ... | @@ -176,7 +174,7 @@ export const useGenDynamicForm = () => { |
| 176 | 174 | const dataType = fieldTypeMap.get(next)!; |
| 177 | 175 | |
| 178 | 176 | let itemValue = value[next]; |
| 179 | - if (dataType === DataTypeEnum.IS_STRUCT) { | |
| 177 | + if (dataType === DataTypeEnum.STRUCT) { | |
| 180 | 178 | const { value } = useJsonParse(itemValue); |
| 181 | 179 | itemValue = value; |
| 182 | 180 | } | ... | ... |
| ... | ... | @@ -4,6 +4,7 @@ |
| 4 | 4 | :maskClosable="false" |
| 5 | 5 | v-bind="$attrs" |
| 6 | 6 | :width="dynamicWidth" |
| 7 | + :destroy-on-close="true" | |
| 7 | 8 | @register="register" |
| 8 | 9 | @ok="handleSubmit" |
| 9 | 10 | @cancel="handleCancel" |
| ... | ... | @@ -125,6 +126,8 @@ |
| 125 | 126 | const title = unref(isUpdate) ? '编辑产品' : '新增产品'; |
| 126 | 127 | setModalProps({ title, showOkBtn: true, showCancelBtn: true }); |
| 127 | 128 | if (unref(isUpdate)) { |
| 129 | + const { deviceType } = res || {}; | |
| 130 | + deviceTypeStr.value = deviceType; | |
| 128 | 131 | await setDeviceConfEditFormData(res); |
| 129 | 132 | await setTransConfEditFormData(res); |
| 130 | 133 | handleStepNext(false, res); |
| ... | ... | @@ -157,7 +160,6 @@ |
| 157 | 160 | }; |
| 158 | 161 | const deviceTypeStr = ref(''); |
| 159 | 162 | const handleGetDeviceType = async (e) => { |
| 160 | - console.log(e); | |
| 161 | 163 | deviceTypeStr.value = e; |
| 162 | 164 | await nextTick(); |
| 163 | 165 | TransConStRef.value?.updateDisabled(e); | ... | ... |
| 1 | +<script lang="ts" setup> | |
| 2 | + import { columns, searchFormSchema } from './config'; | |
| 3 | + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; | |
| 4 | + import { BasicTable } from '/@/components/Table'; | |
| 5 | + import { useTable } from '/@/components/Table'; | |
| 6 | + import { Button } from 'ant-design-vue'; | |
| 7 | + import { ExclamationCircleOutlined } from '@ant-design/icons-vue'; | |
| 8 | + import { getDeviceClassList } from '/@/api/device/classModal'; | |
| 9 | + import { ref } from 'vue'; | |
| 10 | + const emits = defineEmits([ | |
| 11 | + 'handleOpenListDrawer', | |
| 12 | + 'handleSelectCategory', | |
| 13 | + 'handleClose', | |
| 14 | + 'register', | |
| 15 | + ]); | |
| 16 | + | |
| 17 | + const categoryId = ref<string | undefined | null>(); | |
| 18 | + const [registerDrawer] = useDrawerInner((data) => { | |
| 19 | + categoryId.value = data.categoryId || {}; | |
| 20 | + }); | |
| 21 | + const [registerTable] = useTable({ | |
| 22 | + title: '', | |
| 23 | + api: getDeviceClassList, | |
| 24 | + columns, | |
| 25 | + formConfig: { | |
| 26 | + schemas: searchFormSchema, | |
| 27 | + }, | |
| 28 | + searchInfo: { | |
| 29 | + status: 1, | |
| 30 | + }, | |
| 31 | + resizeHeightOffset: 50, | |
| 32 | + useSearchForm: true, | |
| 33 | + showTableSetting: false, | |
| 34 | + bordered: true, | |
| 35 | + showIndexColumn: false, | |
| 36 | + clickToRowSelect: false, | |
| 37 | + rowKey: 'id', | |
| 38 | + actionColumn: { | |
| 39 | + width: 100, | |
| 40 | + title: '操作', | |
| 41 | + slots: { customRender: 'action' }, | |
| 42 | + fixed: 'right', | |
| 43 | + }, | |
| 44 | + }); | |
| 45 | + | |
| 46 | + const closeDrawer = () => { | |
| 47 | + emits('handleClose'); | |
| 48 | + }; | |
| 49 | + | |
| 50 | + const handleChecked = (item?: any) => { | |
| 51 | + emits('handleSelectCategory', item); | |
| 52 | + }; | |
| 53 | + | |
| 54 | + const handleOpenListDrawer = (record?: any) => { | |
| 55 | + emits('handleOpenListDrawer', record); | |
| 56 | + }; | |
| 57 | +</script> | |
| 58 | + | |
| 59 | +<template> | |
| 60 | + <BasicDrawer | |
| 61 | + :zIndex="1100" | |
| 62 | + v-bind="$attrs" | |
| 63 | + @register="registerDrawer" | |
| 64 | + :showFooter="true" | |
| 65 | + destroyOnClose | |
| 66 | + @close="closeDrawer" | |
| 67 | + title="选择品类" | |
| 68 | + width="32%" | |
| 69 | + > | |
| 70 | + <BasicTable @register="registerTable"> | |
| 71 | + <template #name="{ record }"> | |
| 72 | + <span>{{ record.name }}</span> | |
| 73 | + <ExclamationCircleOutlined | |
| 74 | + style="color: #377dff" | |
| 75 | + @click.stop="handleOpenListDrawer(record)" | |
| 76 | + class="ml-1" | |
| 77 | + /> | |
| 78 | + </template> | |
| 79 | + <template #action="{ record }"> | |
| 80 | + <Button type="link" :disabled="categoryId === record.id" @click="handleChecked(record)">{{ | |
| 81 | + categoryId === record.id ? '已选择' : '选择' | |
| 82 | + }}</Button> | |
| 83 | + </template> | |
| 84 | + </BasicTable> | |
| 85 | + </BasicDrawer> | |
| 86 | +</template> | ... | ... |
| 1 | +<script lang="ts" setup> | |
| 2 | + import { columnsDrawer } from './config'; | |
| 3 | + import { unref, ref, watch, nextTick } from 'vue'; | |
| 4 | + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; | |
| 5 | + import { BasicTable } from '/@/components/Table'; | |
| 6 | + import { useTable } from '/@/components/Table'; | |
| 7 | + import { ExclamationCircleOutlined } from '@ant-design/icons-vue'; | |
| 8 | + import { getModelList } from '/@/api/device/modelOfMatter'; | |
| 9 | + | |
| 10 | + defineEmits(['register']); | |
| 11 | + | |
| 12 | + const props = defineProps<{ cateforyListInfo: any }>(); | |
| 13 | + | |
| 14 | + const recordInfo = ref<any>({}); | |
| 15 | + const secondVisible = ref<Boolean>(false); | |
| 16 | + | |
| 17 | + watch( | |
| 18 | + () => props.cateforyListInfo, | |
| 19 | + async () => { | |
| 20 | + recordInfo.value = props.cateforyListInfo.record || {}; | |
| 21 | + secondVisible.value = props.cateforyListInfo.isRight || false; | |
| 22 | + await nextTick(); | |
| 23 | + reload(); | |
| 24 | + } | |
| 25 | + ); | |
| 26 | + const [registerListDrawer, { closeDrawer }] = useDrawerInner(); | |
| 27 | + const [registerTable, { reload }] = useTable({ | |
| 28 | + title: '', | |
| 29 | + api: async (params: Record<'page' | 'pageSize', number>) => { | |
| 30 | + return await getModelList({ | |
| 31 | + ...params, | |
| 32 | + id: unref(recordInfo).id, | |
| 33 | + selectType: 'category', | |
| 34 | + }); | |
| 35 | + }, | |
| 36 | + columns: columnsDrawer, | |
| 37 | + useSearchForm: false, | |
| 38 | + showTableSetting: false, | |
| 39 | + bordered: true, | |
| 40 | + showIndexColumn: false, | |
| 41 | + clickToRowSelect: false, | |
| 42 | + rowKey: 'id', | |
| 43 | + }); | |
| 44 | + | |
| 45 | + const handleClose = () => { | |
| 46 | + closeDrawer(); | |
| 47 | + }; | |
| 48 | +</script> | |
| 49 | + | |
| 50 | +<template> | |
| 51 | + <BasicDrawer | |
| 52 | + :zIndex="1100" | |
| 53 | + @register="registerListDrawer" | |
| 54 | + wrap-class-name="secondDrawer" | |
| 55 | + :wrap-style="{ | |
| 56 | + right: secondVisible ? '32%' : 0, | |
| 57 | + transition: 'none', | |
| 58 | + }" | |
| 59 | + v-bind="$attrs" | |
| 60 | + destroyOnClose | |
| 61 | + @close="handleClose" | |
| 62 | + title="物模型" | |
| 63 | + width="36%" | |
| 64 | + > | |
| 65 | + <BasicTable @register="registerTable"> | |
| 66 | + <template #name="{ record }"> | |
| 67 | + <span>{{ record.name }}</span> | |
| 68 | + <ExclamationCircleOutlined class="ml-1" /> | |
| 69 | + </template> | |
| 70 | + </BasicTable> | |
| 71 | + </BasicDrawer> | |
| 72 | +</template> | ... | ... |
| 1 | +<template> | |
| 2 | + <BasicModal | |
| 3 | + title="导入物模型" | |
| 4 | + :maskClosable="false" | |
| 5 | + destroyOnClose | |
| 6 | + v-bind="$attrs" | |
| 7 | + width="25rem" | |
| 8 | + @register="register" | |
| 9 | + @cancel="handleCancel" | |
| 10 | + :showOkBtn="false" | |
| 11 | + > | |
| 12 | + <div class="w-full h-full" ref="loadingRef"> | |
| 13 | + <!-- <div class="flex justify-end"> | |
| 14 | + <Button @click="handleTemplateDownload" type="link">EXCEL模板下载</Button> | |
| 15 | + </div> --> | |
| 16 | + <div class="flex justify-evenly items-center h-50 !w-full"> | |
| 17 | + <Upload | |
| 18 | + accept=".json," | |
| 19 | + :show-upload-list="false" | |
| 20 | + :customRequest="handleImportModel" | |
| 21 | + class="flex justify-center items-center" | |
| 22 | + > | |
| 23 | + <div class="flex flex-col justify-center items-center"> | |
| 24 | + <img :src="JSONImage" alt="avatar" class="w-20 h-20" /> | |
| 25 | + </div> | |
| 26 | + </Upload> | |
| 27 | + <Upload | |
| 28 | + accept=".csv,.xls,.xlsx" | |
| 29 | + :show-upload-list="false" | |
| 30 | + :customRequest="handleCSVImport" | |
| 31 | + class="flex justify-center items-center" | |
| 32 | + > | |
| 33 | + <div class="flex flex-col justify-center items-center"> | |
| 34 | + <img :src="CSVImage" alt="avatar" class="w-20 h-20" /> | |
| 35 | + </div> | |
| 36 | + </Upload> | |
| 37 | + </div> | |
| 38 | + </div> | |
| 39 | + </BasicModal> | |
| 40 | +</template> | |
| 41 | +<script lang="ts" setup> | |
| 42 | + import { ref, unref } from 'vue'; | |
| 43 | + import { Upload } from 'ant-design-vue'; | |
| 44 | + import { BasicModal, useModalInner } from '/@/components/Modal'; | |
| 45 | + import { DeviceRecord } from '/@/api/device/model/deviceModel'; | |
| 46 | + import { useMessage } from '/@/hooks/web/useMessage'; | |
| 47 | + import { isObject, isString } from '/@/utils/is'; | |
| 48 | + import { | |
| 49 | + importCsvCategory, | |
| 50 | + importModelCategory, | |
| 51 | + importModelOfMatter, | |
| 52 | + importCsvDeviceProfileId, | |
| 53 | + } from '/@/api/device/modelOfMatter'; | |
| 54 | + // import XLSX, { CellObject } from 'xlsx'; | |
| 55 | + import { useLoading } from '/@/components/Loading'; | |
| 56 | + import JSONImage from '/@/assets/svg/JSON.svg'; | |
| 57 | + import CSVImage from '/@/assets/svg/excel.svg'; | |
| 58 | + | |
| 59 | + const emits = defineEmits(['register', 'handleImportCSV', 'handleReload']); | |
| 60 | + | |
| 61 | + defineProps<{ | |
| 62 | + record: DeviceRecord; | |
| 63 | + }>(); | |
| 64 | + | |
| 65 | + const { createMessage } = useMessage(); | |
| 66 | + const loadingRef = ref(); | |
| 67 | + const [openLoading, closeLoading] = useLoading({ | |
| 68 | + target: loadingRef, | |
| 69 | + props: { | |
| 70 | + tip: '加载中', | |
| 71 | + absolute: true, | |
| 72 | + }, | |
| 73 | + }); | |
| 74 | + | |
| 75 | + const isEmptyObject = (value: any) => isObject(value) && !Object.keys(value).length; | |
| 76 | + | |
| 77 | + const ImportInfo = ref<{ id?: string; isCateGory?: string | Boolean }>({}); | |
| 78 | + | |
| 79 | + const [register, { closeModal }] = useModalInner(async (data) => { | |
| 80 | + ImportInfo.value = data; | |
| 81 | + }); | |
| 82 | + // 导入loading | |
| 83 | + const importLoading = ref(false); | |
| 84 | + | |
| 85 | + const paseJSON = (string: string) => { | |
| 86 | + let data = null; | |
| 87 | + let flag = false; | |
| 88 | + try { | |
| 89 | + if (!isString(string)) return { flag: false, data }; | |
| 90 | + data = JSON.parse(string); | |
| 91 | + flag = true; | |
| 92 | + if (!isObject(data)) flag = false; | |
| 93 | + } catch (error) {} | |
| 94 | + return { flag, data }; | |
| 95 | + }; | |
| 96 | + | |
| 97 | + // JSON导入 | |
| 98 | + const handleImportModel = async (data: { file: File }) => { | |
| 99 | + const fileReader = new FileReader(); | |
| 100 | + const { isCateGory, id } = unref(ImportInfo); | |
| 101 | + | |
| 102 | + fileReader.onload = async () => { | |
| 103 | + const { flag, data } = paseJSON(fileReader.result as string); | |
| 104 | + if (!flag) { | |
| 105 | + createMessage.warning('JSON解析失败,请导入正确的JSON'); | |
| 106 | + return; | |
| 107 | + } | |
| 108 | + openLoading(); | |
| 109 | + try { | |
| 110 | + importLoading.value = true; | |
| 111 | + | |
| 112 | + Object.keys(data || {}).forEach((key) => { | |
| 113 | + const value = (data || {})[key]; | |
| 114 | + if (value && isEmptyObject(value)) { | |
| 115 | + (data || {})[key] = []; | |
| 116 | + } | |
| 117 | + }); | |
| 118 | + | |
| 119 | + const result = isCateGory | |
| 120 | + ? await importModelCategory({ | |
| 121 | + categoryId: id, | |
| 122 | + data: data!, | |
| 123 | + functionType: 'all', | |
| 124 | + }) | |
| 125 | + : await importModelOfMatter({ | |
| 126 | + tkDeviceProfileId: id, | |
| 127 | + data: data!, | |
| 128 | + functionType: 'all', | |
| 129 | + }); | |
| 130 | + | |
| 131 | + result | |
| 132 | + ? createMessage.success('导入成功~') | |
| 133 | + : createMessage.error('JSON解析失败,请导入正确的JSON'); | |
| 134 | + | |
| 135 | + result && emits('handleReload'); | |
| 136 | + } catch (error) { | |
| 137 | + throw error; | |
| 138 | + } finally { | |
| 139 | + importLoading.value = false; | |
| 140 | + closeLoading(); | |
| 141 | + closeModal(); | |
| 142 | + } | |
| 143 | + }; | |
| 144 | + | |
| 145 | + fileReader.readAsText(data.file, 'utf-8'); | |
| 146 | + }; | |
| 147 | + | |
| 148 | + // CSV导入 | |
| 149 | + const handleCSVImport = async ({ file }) => { | |
| 150 | + const { isCateGory, id } = unref(ImportInfo); | |
| 151 | + | |
| 152 | + try { | |
| 153 | + openLoading(); | |
| 154 | + const formData = new FormData(); | |
| 155 | + formData.set('file', file); | |
| 156 | + const flag = isCateGory | |
| 157 | + ? await importCsvCategory({ categoryId: id, deviceProfileId: undefined, file: formData }) | |
| 158 | + : await importCsvDeviceProfileId({ | |
| 159 | + categoryId: undefined, | |
| 160 | + deviceProfileId: id, | |
| 161 | + file: formData, | |
| 162 | + }); | |
| 163 | + flag && createMessage.info(flag?.message); | |
| 164 | + } catch (msg) { | |
| 165 | + console.log(msg, 'msg'); | |
| 166 | + } finally { | |
| 167 | + closeLoading(); | |
| 168 | + closeModal(); | |
| 169 | + emits('handleReload'); | |
| 170 | + } | |
| 171 | + }; | |
| 172 | + | |
| 173 | + // const downloadFile = (data: string, fileName: string, type: string, ext: string) => { | |
| 174 | + // const blob = new Blob([data], { type: type }); | |
| 175 | + // const objectURL = URL.createObjectURL(blob); | |
| 176 | + // const element = document.createElement('a'); | |
| 177 | + // element.href = objectURL; | |
| 178 | + // element.download = `${fileName}.${ext}`; | |
| 179 | + // element.style.display = 'none'; | |
| 180 | + // document.body.appendChild(element); | |
| 181 | + // element.click(); | |
| 182 | + // element.remove(); | |
| 183 | + // URL.revokeObjectURL(objectURL); | |
| 184 | + // }; | |
| 185 | + | |
| 186 | + // 模板下载 | |
| 187 | + // const handleTemplateDownload = () => { | |
| 188 | + | |
| 189 | + // }; | |
| 190 | + | |
| 191 | + const handleCancel = () => { | |
| 192 | + closeModal(); | |
| 193 | + }; | |
| 194 | +</script> | |
| 195 | + | |
| 196 | +<style lang="less" scope></style> | ... | ... |
| 1 | +import { BasicColumn, FormSchema } from '/@/components/Table'; | |
| 2 | +import { findDictItemByCode } from '/@/api/system/dict'; | |
| 3 | +import { h, unref } from 'vue'; | |
| 4 | +import { Tooltip } from 'ant-design-vue'; | |
| 5 | + | |
| 6 | +import { FunctionType } from '/@/views/device/profiles/step/cpns/physical/cpns/config'; | |
| 7 | +import { useMessage } from '/@/hooks/web/useMessage'; | |
| 8 | +import { useClipboard } from '@vueuse/core'; | |
| 9 | +import { DictEnum } from '/@/enums/dictEnum'; | |
| 10 | + | |
| 11 | +// import { | |
| 12 | +// EventType, | |
| 13 | +// EventTypeColor, | |
| 14 | +// EventTypeName, | |
| 15 | +// } from '/@/views/device/list/cpns/tabs/EventManage/config'; | |
| 16 | + | |
| 17 | +export const columns: BasicColumn[] = [ | |
| 18 | + { | |
| 19 | + title: '品类名称', | |
| 20 | + dataIndex: 'name', | |
| 21 | + slots: { customRender: 'name' }, | |
| 22 | + }, | |
| 23 | + { | |
| 24 | + title: '领域', | |
| 25 | + dataIndex: 'dictItemName', | |
| 26 | + }, | |
| 27 | +]; | |
| 28 | + | |
| 29 | +export const formatFunctionType: Record<FunctionType, string> = { | |
| 30 | + [FunctionType.PROPERTIES]: '属性', | |
| 31 | + [FunctionType.EVENTS]: '事件', | |
| 32 | + [FunctionType.SERVICE]: '服务', | |
| 33 | +}; | |
| 34 | + | |
| 35 | +const handleCopy = async (value: string) => { | |
| 36 | + const { createMessage } = useMessage(); | |
| 37 | + const { copied, copy } = useClipboard({ legacy: true }); | |
| 38 | + await copy(value); | |
| 39 | + if (unref(copied)) createMessage.success('复制成功~'); | |
| 40 | + else createMessage.error('复制失败~'); | |
| 41 | +}; | |
| 42 | + | |
| 43 | +export const columnsDrawer: BasicColumn[] = [ | |
| 44 | + { | |
| 45 | + title: '功能类型', | |
| 46 | + dataIndex: 'functionType', | |
| 47 | + width: 90, | |
| 48 | + format: (text: FunctionType) => { | |
| 49 | + return formatFunctionType[text]; | |
| 50 | + }, | |
| 51 | + }, | |
| 52 | + { | |
| 53 | + title: '功能名称', | |
| 54 | + dataIndex: 'functionName', | |
| 55 | + width: 90, | |
| 56 | + ellipsis: true, | |
| 57 | + }, | |
| 58 | + { | |
| 59 | + title: '标识符', | |
| 60 | + dataIndex: 'identifier', | |
| 61 | + width: 90, | |
| 62 | + ellipsis: true, | |
| 63 | + customRender: ({ text }: Record<'text', string>) => { | |
| 64 | + return h(Tooltip, { title: text }, () => | |
| 65 | + h('span', { class: 'cursor-pointer', onClick: () => handleCopy(text) }, text) | |
| 66 | + ); | |
| 67 | + }, | |
| 68 | + }, | |
| 69 | + { | |
| 70 | + title: '数据类型', | |
| 71 | + dataIndex: 'functionJson.dataType.type', | |
| 72 | + width: 100, | |
| 73 | + format: (text: string) => { | |
| 74 | + return text || '--'; | |
| 75 | + }, | |
| 76 | + ellipsis: true, | |
| 77 | + }, | |
| 78 | + // { | |
| 79 | + // title: '事件类型', | |
| 80 | + // dataIndex: 'eventType', | |
| 81 | + // customRender({ text }) { | |
| 82 | + // return h( | |
| 83 | + // Tag, | |
| 84 | + // { | |
| 85 | + // color: EventTypeColor[text as EventType], | |
| 86 | + // }, | |
| 87 | + // () => EventTypeName[text as EventType] | |
| 88 | + // ); | |
| 89 | + // }, | |
| 90 | + // ellipsis: true, | |
| 91 | + // }, | |
| 92 | + // { | |
| 93 | + // title: '状态', | |
| 94 | + // dataIndex: 'status', | |
| 95 | + // width: 100, | |
| 96 | + // customRender: (value: Record<'text', number>) => { | |
| 97 | + // const { text } = value; | |
| 98 | + // return h( | |
| 99 | + // Tag, | |
| 100 | + // { | |
| 101 | + // color: text ? 'green' : 'red', | |
| 102 | + // }, | |
| 103 | + // () => (text ? '已发布' : '待发布') | |
| 104 | + // ); | |
| 105 | + // }, | |
| 106 | + // }, | |
| 107 | +]; | |
| 108 | + | |
| 109 | +export const searchFormSchema: FormSchema[] = [ | |
| 110 | + { | |
| 111 | + field: 'dictItemId', | |
| 112 | + label: '', | |
| 113 | + component: 'ApiSelect', | |
| 114 | + colProps: { span: 7 }, | |
| 115 | + componentProps() { | |
| 116 | + return { | |
| 117 | + api: findDictItemByCode, | |
| 118 | + params: { | |
| 119 | + dictCode: DictEnum.CATEGORY_FIELD, | |
| 120 | + }, | |
| 121 | + labelField: 'itemText', | |
| 122 | + valueField: 'itemValue', | |
| 123 | + placeholder: '请选择领域', | |
| 124 | + // getPopupContainer: () => document.body, | |
| 125 | + }; | |
| 126 | + }, | |
| 127 | + }, | |
| 128 | + { | |
| 129 | + field: 'name', | |
| 130 | + label: '', | |
| 131 | + component: 'Input', | |
| 132 | + colProps: { span: 9 }, | |
| 133 | + componentProps: { | |
| 134 | + placeholder: '请输入品类名称', | |
| 135 | + }, | |
| 136 | + }, | |
| 137 | +]; | ... | ... |
| ... | ... | @@ -42,6 +42,12 @@ export enum ModelOfMatterPermission { |
| 42 | 42 | DELETE = 'api:yt:things_model:delete', |
| 43 | 43 | RELEASE = 'api:yt:things_model:release', |
| 44 | 44 | } |
| 45 | +export enum ModelCategoryPermission { | |
| 46 | + CREATE = 'api:yt:things_model:category:post', | |
| 47 | + UPDATE = 'api:yt:things_model:category:put', | |
| 48 | + DELETE = 'api:yt:things_model:category:delete', | |
| 49 | + RELEASE = 'api:yt:things_model:category:release', | |
| 50 | +} | |
| 45 | 51 | |
| 46 | 52 | const handleCopy = async (value: string) => { |
| 47 | 53 | const { createMessage } = useMessage(); |
| ... | ... | @@ -212,6 +218,41 @@ export const step1Schemas: FormSchema[] = [ |
| 212 | 218 | }, |
| 213 | 219 | }, |
| 214 | 220 | { |
| 221 | + field: 'category', | |
| 222 | + label: '产品品类', | |
| 223 | + component: 'RadioGroup', | |
| 224 | + defaultValue: 2, | |
| 225 | + required: true, | |
| 226 | + componentProps({ formModel }) { | |
| 227 | + return { | |
| 228 | + options: [ | |
| 229 | + { label: '自定义品类', value: 2 }, | |
| 230 | + { label: '标准品类', value: 1 }, | |
| 231 | + ], | |
| 232 | + onChange() { | |
| 233 | + formModel.categoryId = null; | |
| 234 | + formModel.categoryName = undefined; | |
| 235 | + }, | |
| 236 | + }; | |
| 237 | + }, | |
| 238 | + }, | |
| 239 | + { | |
| 240 | + field: 'categoryId', | |
| 241 | + label: '产品品类', | |
| 242 | + component: 'Input', | |
| 243 | + defaultValue: undefined, | |
| 244 | + ifShow: false, | |
| 245 | + }, | |
| 246 | + { | |
| 247 | + field: 'categoryName', | |
| 248 | + label: ' ', | |
| 249 | + component: 'ApiSelect', | |
| 250 | + colProps: { span: 14 }, | |
| 251 | + slot: 'categoryName', | |
| 252 | + required: true, | |
| 253 | + ifShow: ({ model }) => model.category === 1, | |
| 254 | + }, | |
| 255 | + { | |
| 215 | 256 | field: 'name', |
| 216 | 257 | label: '产品名称', |
| 217 | 258 | required: true, |
| ... | ... | @@ -325,6 +366,14 @@ export const columns: BasicColumn[] = [ |
| 325 | 366 | width: 120, |
| 326 | 367 | }, |
| 327 | 368 | { |
| 369 | + title: '产品品类', | |
| 370 | + dataIndex: 'categoryName', | |
| 371 | + width: 120, | |
| 372 | + format: (text) => { | |
| 373 | + return text ? text : '自定义品类'; | |
| 374 | + }, | |
| 375 | + }, | |
| 376 | + { | |
| 328 | 377 | title: '设备类型', |
| 329 | 378 | dataIndex: 'deviceType', |
| 330 | 379 | width: 90, | ... | ... |
| 1 | 1 | <template> |
| 2 | 2 | <div class="step1"> |
| 3 | - <BasicForm @register="register" /> | |
| 3 | + <BasicForm @register="register"> | |
| 4 | + <template #categoryName="{ model }"> | |
| 5 | + <div class="flex"> | |
| 6 | + <Input | |
| 7 | + v-model:value="model.categoryName" | |
| 8 | + placeholder="请选择所属品类" | |
| 9 | + style="width: 300px" | |
| 10 | + :disabled="cateGoryDisabled" | |
| 11 | + @focus="handleFocus" | |
| 12 | + /> | |
| 13 | + <Button type="link" :disabled="!model.categoryName" @click="handleCategoryId" | |
| 14 | + >查看功能</Button | |
| 15 | + > | |
| 16 | + </div> | |
| 17 | + </template> | |
| 18 | + </BasicForm> | |
| 19 | + <CategoryList | |
| 20 | + @register="registerDrawer" | |
| 21 | + @handleOpenListDrawer="handleOpenListDrawer" | |
| 22 | + @handleSelectCategory="handleSelectCategory" | |
| 23 | + @handleClose="handleClose" | |
| 24 | + /> | |
| 25 | + <CategoryListDrawer @register="registerListDrawer" :cateforyListInfo="cateforyListInfo" /> | |
| 4 | 26 | </div> |
| 5 | 27 | </template> |
| 6 | 28 | <script lang="ts" setup> |
| 7 | - import { nextTick } from 'vue'; | |
| 29 | + import { nextTick, ref } from 'vue'; | |
| 8 | 30 | import { BasicForm, useForm } from '/@/components/Form'; |
| 9 | 31 | import { step1Schemas } from '../device.profile.data'; |
| 10 | 32 | import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue'; |
| 11 | 33 | import { buildUUID } from '/@/utils/uuid'; |
| 34 | + import { Input, Button } from 'ant-design-vue'; | |
| 35 | + import { useDrawer } from '/@/components/Drawer'; | |
| 36 | + import CategoryList from '../components/CategoryList.vue'; | |
| 37 | + import CategoryListDrawer from '../components/CategoryListDrawer.vue'; | |
| 12 | 38 | |
| 13 | 39 | const emits = defineEmits(['next', 'emitDeviceType']); |
| 14 | 40 | const props = defineProps({ |
| 15 | 41 | ifShowBtn: { type: Boolean, default: true }, |
| 16 | 42 | }); |
| 43 | + const [registerDrawer, { openDrawer, closeDrawer }] = useDrawer(); | |
| 44 | + const [registerListDrawer, { openDrawer: openListDrawer, closeDrawer: closeListDrawer }] = | |
| 45 | + useDrawer(); | |
| 17 | 46 | |
| 18 | 47 | const [register, { validate, setFieldsValue, resetFields, updateSchema, getFieldsValue }] = |
| 19 | 48 | useForm({ |
| ... | ... | @@ -29,6 +58,9 @@ |
| 29 | 58 | }, |
| 30 | 59 | submitFunc: customSubmitFunc, |
| 31 | 60 | }); |
| 61 | + | |
| 62 | + const cateGoryDisabled = ref<boolean>(false); | |
| 63 | + | |
| 32 | 64 | const editOrAddNameStatus = (nameStatus) => |
| 33 | 65 | updateSchema({ |
| 34 | 66 | field: 'name', |
| ... | ... | @@ -48,19 +80,20 @@ |
| 48 | 80 | emits('emitDeviceType', values?.deviceType); |
| 49 | 81 | } |
| 50 | 82 | //回显数据 |
| 51 | - const setFormData = (v) => { | |
| 83 | + const setFormData = async (v) => { | |
| 52 | 84 | if (v.image) { |
| 53 | 85 | setFieldsValue({ |
| 54 | 86 | image: [{ uid: buildUUID(), name: 'name', url: v.image } as FileItem], |
| 55 | 87 | }); |
| 56 | 88 | } |
| 57 | 89 | const { image, ...params } = v; |
| 58 | - console.log(image); | |
| 59 | - setFieldsValue({ ...params }); | |
| 90 | + console.log(image, props.isUpdate); | |
| 91 | + setFieldsValue({ ...params, category: params?.categoryId ? 1 : 2 }); | |
| 60 | 92 | }; |
| 61 | 93 | //获取数据 |
| 62 | 94 | async function getFormData() { |
| 63 | - const values = await validate(); | |
| 95 | + await validate(); | |
| 96 | + const values = getFieldsValue(); | |
| 64 | 97 | if (!values) return; |
| 65 | 98 | if (Reflect.has(values, 'image')) { |
| 66 | 99 | const file = (values.image || []).at(0) || {}; |
| ... | ... | @@ -74,12 +107,65 @@ |
| 74 | 107 | }; |
| 75 | 108 | |
| 76 | 109 | const editOrAddDeviceTypeStatus = (status: boolean) => { |
| 77 | - updateSchema({ | |
| 78 | - field: 'deviceType', | |
| 79 | - componentProps: { | |
| 80 | - disabled: status, | |
| 110 | + updateSchema([ | |
| 111 | + { | |
| 112 | + field: 'deviceType', | |
| 113 | + componentProps: { | |
| 114 | + disabled: status, | |
| 115 | + }, | |
| 81 | 116 | }, |
| 82 | - }); | |
| 117 | + { | |
| 118 | + field: 'category', | |
| 119 | + componentProps({ formModel }) { | |
| 120 | + return { | |
| 121 | + options: [ | |
| 122 | + { label: '自定义品类', value: 2 }, | |
| 123 | + { label: '标准品类', value: 1 }, | |
| 124 | + ], | |
| 125 | + onChange() { | |
| 126 | + formModel.categoryId = null; | |
| 127 | + formModel.categoryName = undefined; | |
| 128 | + }, | |
| 129 | + disabled: status, | |
| 130 | + }; | |
| 131 | + }, | |
| 132 | + }, | |
| 133 | + ]); | |
| 134 | + | |
| 135 | + cateGoryDisabled.value = status; | |
| 136 | + }; | |
| 137 | + | |
| 138 | + // 查看功能 | |
| 139 | + const handleCategoryId = () => { | |
| 140 | + const { categoryId } = getFieldsValue() || {}; | |
| 141 | + if (!categoryId) return; | |
| 142 | + cateforyListInfo.value = { record: { id: categoryId }, isRight: false }; | |
| 143 | + openListDrawer(true); | |
| 144 | + }; | |
| 145 | + | |
| 146 | + // 获取焦点 | |
| 147 | + const handleFocus = () => { | |
| 148 | + const { categoryId } = getFieldsValue() || {}; | |
| 149 | + openDrawer(true, { categoryId }); | |
| 150 | + }; | |
| 151 | + | |
| 152 | + //打开品类名称 | |
| 153 | + const cateforyListInfo = ref<any>({}); | |
| 154 | + const handleOpenListDrawer = (record?: any) => { | |
| 155 | + cateforyListInfo.value = { record, isRight: true }; | |
| 156 | + openListDrawer(true); | |
| 157 | + }; | |
| 158 | + | |
| 159 | + // 选择产品品类 | |
| 160 | + const handleSelectCategory = (item) => { | |
| 161 | + closeDrawer(); | |
| 162 | + closeListDrawer(); | |
| 163 | + item.id && setFieldsValue({ categoryId: item.id, categoryName: item?.name }); | |
| 164 | + }; | |
| 165 | + | |
| 166 | + // 关闭抽屉 | |
| 167 | + const handleClose = () => { | |
| 168 | + closeListDrawer(); | |
| 83 | 169 | }; |
| 84 | 170 | |
| 85 | 171 | defineExpose({ | ... | ... |
| ... | ... | @@ -27,25 +27,33 @@ |
| 27 | 27 | </div> |
| 28 | 28 | <div class="flex justify-between items-end"> |
| 29 | 29 | <div class="flex gap-2"> |
| 30 | - <Authority :value="ModelOfMatterPermission.CREATE"> | |
| 30 | + <Authority :value="[ModelOfMatterPermission.CREATE, ModelCategoryPermission.CREATE]"> | |
| 31 | 31 | <Button v-if="isShowBtn" type="primary" @click="handleCreateOrEdit()"> |
| 32 | 32 | 新增物模型 |
| 33 | 33 | </Button> |
| 34 | 34 | </Authority> |
| 35 | - <Button type="primary" @click="handleOpenTsl"> 物模型TSL </Button> | |
| 36 | - <Authority value="api:yt:things_model:import"> | |
| 37 | - <Upload | |
| 35 | + <Button v-if="!record.ifShowClass" type="primary" @click="handleOpenTsl"> | |
| 36 | + 物模型TSL</Button | |
| 37 | + > | |
| 38 | + <Button v-else type="primary" @click="handleExport" :loading="loading" | |
| 39 | + >导出物模型</Button | |
| 40 | + > | |
| 41 | + <Authority | |
| 42 | + :value="['api:yt:things_model:import', 'api:yt:things_model:category:import']" | |
| 43 | + > | |
| 44 | + <!-- <Upload | |
| 38 | 45 | v-if="isShowBtn" |
| 39 | 46 | accept=".json," |
| 40 | 47 | :show-upload-list="false" |
| 41 | 48 | :customRequest="handleImportModel" |
| 42 | 49 | > |
| 43 | 50 | <Button type="primary" :loading="importLoading"> 导入物模型 </Button> |
| 44 | - </Upload> | |
| 51 | + </Upload> --> | |
| 52 | + <Button type="primary" @click="handleSelectImport">导入物模型</Button> | |
| 45 | 53 | </Authority> |
| 46 | 54 | </div> |
| 47 | 55 | <div class="flex gap-2"> |
| 48 | - <Authority :value="ModelOfMatterPermission.RELEASE"> | |
| 56 | + <Authority :value="[ModelOfMatterPermission.RELEASE]"> | |
| 49 | 57 | <Popconfirm |
| 50 | 58 | title="是否需要发布上线?" |
| 51 | 59 | ok-text="确定" |
| ... | ... | @@ -61,7 +69,7 @@ |
| 61 | 69 | <Button v-if="isShowBtn" class="!bg-gray-200" type="text" @click="handleReturn"> |
| 62 | 70 | 返回 |
| 63 | 71 | </Button> |
| 64 | - <Authority :value="ModelOfMatterPermission.DELETE"> | |
| 72 | + <Authority :value="[ModelOfMatterPermission.DELETE, ModelCategoryPermission.DELETE]"> | |
| 65 | 73 | <Popconfirm |
| 66 | 74 | title="您确定要批量删除数据" |
| 67 | 75 | ok-text="确定" |
| ... | ... | @@ -94,14 +102,14 @@ |
| 94 | 102 | { |
| 95 | 103 | label: '编辑', |
| 96 | 104 | icon: 'clarity:note-edit-line', |
| 97 | - auth: ModelOfMatterPermission.UPDATE, | |
| 105 | + auth: [ModelOfMatterPermission.UPDATE, ModelCategoryPermission.UPDATE], | |
| 98 | 106 | onClick: handleCreateOrEdit.bind(null, record), |
| 99 | 107 | ifShow: !isShowBtn ? false : true, |
| 100 | 108 | }, |
| 101 | 109 | { |
| 102 | 110 | label: '删除', |
| 103 | 111 | icon: 'ant-design:delete-outlined', |
| 104 | - auth: ModelOfMatterPermission.DELETE, | |
| 112 | + auth: [ModelOfMatterPermission.DELETE, ModelCategoryPermission.DELETE], | |
| 105 | 113 | color: 'error', |
| 106 | 114 | ifShow: !isShowBtn ? false : true, |
| 107 | 115 | popConfirm: { |
| ... | ... | @@ -119,6 +127,11 @@ |
| 119 | 127 | @success="handleSuccess" |
| 120 | 128 | /> |
| 121 | 129 | <PhysicalModelTsl :record="$props.record" @register="registerModalTsl" /> |
| 130 | + <SelectImport | |
| 131 | + :record="$props.record" | |
| 132 | + @register="registerModalSelect" | |
| 133 | + @handleReload="handleReload" | |
| 134 | + /> | |
| 122 | 135 | </div> |
| 123 | 136 | </template> |
| 124 | 137 | <script lang="ts" setup> |
| ... | ... | @@ -127,25 +140,32 @@ |
| 127 | 140 | import { |
| 128 | 141 | modelOfMatterForm, |
| 129 | 142 | ModelOfMatterPermission, |
| 143 | + ModelCategoryPermission, | |
| 130 | 144 | physicalColumn, |
| 131 | 145 | } from '../device.profile.data'; |
| 132 | 146 | import { useBatchDelete } from '/@/hooks/web/useBatchDelete'; |
| 133 | 147 | import { Authority } from '/@/components/Authority'; |
| 134 | 148 | import PhysicalModelModal from './cpns/physical/PhysicalModelModal.vue'; |
| 135 | 149 | import PhysicalModelTsl from './cpns/physical/PhysicalModelTsl.vue'; |
| 136 | - import { Popconfirm, Button, Alert, Upload } from 'ant-design-vue'; | |
| 150 | + import { Popconfirm, Button, Alert } from 'ant-design-vue'; | |
| 137 | 151 | import { useMessage } from '/@/hooks/web/useMessage'; |
| 138 | 152 | import { DeviceRecord } from '/@/api/device/model/deviceModel'; |
| 139 | 153 | import { |
| 140 | 154 | deleteModel, |
| 155 | + deleteModelCategory, | |
| 141 | 156 | getModelList, |
| 142 | - importModelOfMatter, | |
| 143 | 157 | releaseModel, |
| 144 | 158 | } from '/@/api/device/modelOfMatter'; |
| 145 | 159 | import { OpenModelOfMatterModelParams, OpenModelMode } from './cpns/physical/types'; |
| 146 | 160 | import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel'; |
| 147 | - import { ref } from 'vue'; | |
| 148 | - import { isObject, isString } from '/@/utils/is'; | |
| 161 | + import { ref, unref } from 'vue'; | |
| 162 | + import { isObject } from '/@/utils/is'; | |
| 163 | + import { useRole } from '/@/hooks/business/useRole'; | |
| 164 | + import { ExportModelCategory } from '/@/api/device/modelOfMatter'; | |
| 165 | + import { FunctionType } from './cpns/physical/cpns/config'; | |
| 166 | + import SelectImport from '../components/SelectImport.vue'; | |
| 167 | + | |
| 168 | + const { isPlatformAdmin, isSysadmin } = useRole(); | |
| 149 | 169 | defineEmits(['register']); |
| 150 | 170 | |
| 151 | 171 | const props = defineProps<{ |
| ... | ... | @@ -156,10 +176,15 @@ |
| 156 | 176 | const isShowBtn = ref(false); |
| 157 | 177 | const [registerModal, { openModal }] = useModal(); |
| 158 | 178 | const [registerModalTsl, { openModal: openModalTsl }] = useModal(); |
| 179 | + const [registerModalSelect, { openModal: openModalSelect }] = useModal(); | |
| 159 | 180 | |
| 160 | 181 | const [registerTable, { reload, setProps }] = useTable({ |
| 161 | 182 | api: async (params: Record<'page' | 'pageSize', number>) => { |
| 162 | - return await getModelList({ ...params, deviceProfileId: props.record.id }); | |
| 183 | + return await getModelList({ | |
| 184 | + ...params, | |
| 185 | + id: props.record.id, | |
| 186 | + selectType: props.record.ifShowClass ? 'category' : undefined, | |
| 187 | + }); | |
| 163 | 188 | }, |
| 164 | 189 | columns: physicalColumn, |
| 165 | 190 | showIndexColumn: false, |
| ... | ... | @@ -184,9 +209,10 @@ |
| 184 | 209 | const handleSuccess = () => { |
| 185 | 210 | reload(); |
| 186 | 211 | }; |
| 187 | - | |
| 188 | 212 | const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions } = useBatchDelete( |
| 189 | - deleteModel, | |
| 213 | + props.record.ifShowClass && (unref(isPlatformAdmin) || unref(isSysadmin)) | |
| 214 | + ? deleteModelCategory | |
| 215 | + : deleteModel, | |
| 190 | 216 | handleSuccess, |
| 191 | 217 | setProps |
| 192 | 218 | ); |
| ... | ... | @@ -242,59 +268,76 @@ |
| 242 | 268 | } |
| 243 | 269 | }; |
| 244 | 270 | |
| 245 | - const paseJSON = (string: string) => { | |
| 246 | - let data = null; | |
| 247 | - let flag = false; | |
| 248 | - try { | |
| 249 | - if (!isString(string)) return { flag: false, data }; | |
| 250 | - data = JSON.parse(string); | |
| 251 | - flag = true; | |
| 252 | - if (!isObject(data)) flag = false; | |
| 253 | - } catch (error) {} | |
| 254 | - return { flag, data }; | |
| 255 | - }; | |
| 256 | - | |
| 257 | 271 | const isEmptyObject = (value: any) => isObject(value) && !Object.keys(value).length; |
| 258 | 272 | |
| 259 | - const importLoading = ref(false); | |
| 260 | - const handleImportModel = async (data: { file: File }) => { | |
| 261 | - const fileReader = new FileReader(); | |
| 262 | - | |
| 263 | - fileReader.onload = async () => { | |
| 264 | - const { flag, data } = paseJSON(fileReader.result as string); | |
| 265 | - if (!flag) { | |
| 266 | - createMessage.warning('JSON解析失败,请导入正确的JSON~'); | |
| 267 | - return; | |
| 268 | - } | |
| 269 | - try { | |
| 270 | - importLoading.value = true; | |
| 273 | + // 选择导入物模型的方式 | |
| 274 | + const handleSelectImport = () => { | |
| 275 | + openModalSelect(true, { | |
| 276 | + id: props.record.id, | |
| 277 | + isCateGory: (unref(isPlatformAdmin) || unref(isSysadmin)) && props.record.ifShowClass, | |
| 278 | + }); | |
| 279 | + }; | |
| 271 | 280 | |
| 272 | - Object.keys(data || {}).forEach((key) => { | |
| 273 | - const value = (data || {})[key]; | |
| 274 | - if (value && isEmptyObject(value)) { | |
| 275 | - (data || {})[key] = []; | |
| 276 | - } | |
| 277 | - }); | |
| 281 | + const handleReload = () => { | |
| 282 | + reload(); | |
| 283 | + }; | |
| 278 | 284 | |
| 279 | - const result = await importModelOfMatter({ | |
| 280 | - tkDeviceProfileId: props.record.id, | |
| 281 | - data: data!, | |
| 282 | - functionType: 'all', | |
| 283 | - }); | |
| 285 | + // 导出物模型 | |
| 286 | + const loading = ref<boolean>(false); | |
| 284 | 287 | |
| 285 | - result | |
| 286 | - ? createMessage.success('导入成功~') | |
| 287 | - : createMessage.error('JSON解析失败,请导入正确的JSON~'); | |
| 288 | + const getAllCategory = () => { | |
| 289 | + const { id: deviceProfileId } = props.record; | |
| 290 | + return Promise.all([ | |
| 291 | + ExportModelCategory({ | |
| 292 | + deviceProfileId, | |
| 293 | + functionType: FunctionType.EVENTS, | |
| 294 | + }), | |
| 295 | + ExportModelCategory({ | |
| 296 | + deviceProfileId, | |
| 297 | + functionType: FunctionType.PROPERTIES, | |
| 298 | + }), | |
| 299 | + ExportModelCategory({ | |
| 300 | + deviceProfileId, | |
| 301 | + functionType: FunctionType.SERVICE, | |
| 302 | + }), | |
| 303 | + ]); | |
| 304 | + }; | |
| 305 | + const exportJSONFile = (value: Recordable) => { | |
| 306 | + const blob = new Blob([JSON.stringify(value, null, 2)], { type: 'text/json' }); | |
| 307 | + const objectURL = URL.createObjectURL(blob); | |
| 308 | + const element = document.createElement('a'); | |
| 309 | + element.href = objectURL; | |
| 310 | + element.download = `${props.record.name}-model.json`; | |
| 311 | + element.style.display = 'none'; | |
| 312 | + document.body.appendChild(element); | |
| 313 | + element.click(); | |
| 314 | + element.remove(); | |
| 315 | + URL.revokeObjectURL(objectURL); | |
| 316 | + }; | |
| 288 | 317 | |
| 289 | - result && reload(); | |
| 290 | - } catch (error) { | |
| 291 | - throw error; | |
| 292 | - } finally { | |
| 293 | - importLoading.value = false; | |
| 294 | - } | |
| 295 | - }; | |
| 318 | + const isEmptyStr = (s: any) => { | |
| 319 | + if (s == undefined || s == null || s == '') { | |
| 320 | + return true; | |
| 321 | + } | |
| 322 | + return false; | |
| 323 | + }; | |
| 296 | 324 | |
| 297 | - fileReader.readAsText(data.file, 'utf-8'); | |
| 325 | + //产品品类物模型导出 | |
| 326 | + const handleExport = async () => { | |
| 327 | + loading.value = true; | |
| 328 | + try { | |
| 329 | + const [events, properties, services] = await getAllCategory(); | |
| 330 | + const value = { | |
| 331 | + properties: isEmptyObject(properties) || isEmptyStr(properties) ? [] : properties, | |
| 332 | + services: isEmptyObject(services) || isEmptyStr(services) ? [] : services, | |
| 333 | + events: isEmptyObject(events) || isEmptyStr(events) ? [] : events, | |
| 334 | + }; | |
| 335 | + exportJSONFile(value); | |
| 336 | + } catch (error) { | |
| 337 | + throw error; | |
| 338 | + } finally { | |
| 339 | + loading.value = false; | |
| 340 | + } | |
| 298 | 341 | }; |
| 299 | 342 | |
| 300 | 343 | defineExpose({}); | ... | ... |
| ... | ... | @@ -60,11 +60,19 @@ |
| 60 | 60 | import Service from './cpns/Service.vue'; |
| 61 | 61 | import Events from './cpns/Events.vue'; |
| 62 | 62 | import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel'; |
| 63 | - import { createModel, updateModel } from '/@/api/device/modelOfMatter'; | |
| 63 | + import { | |
| 64 | + createModel, | |
| 65 | + updateModel, | |
| 66 | + createModelCategory, | |
| 67 | + updateModelCategory, | |
| 68 | + } from '/@/api/device/modelOfMatter'; | |
| 64 | 69 | import { DeviceRecord, DeviceTypeEnum } from '/@/api/device/model/deviceModel'; |
| 65 | 70 | import { useMessage } from '/@/hooks/web/useMessage'; |
| 66 | 71 | import { OpenModelMode, OpenModelOfMatterModelParams } from './types/index'; |
| 67 | 72 | import { FunctionType } from './cpns/config'; |
| 73 | + import { useRole } from '/@/hooks/business/useRole'; | |
| 74 | + | |
| 75 | + const { isPlatformAdmin, isSysadmin } = useRole(); | |
| 68 | 76 | |
| 69 | 77 | const emit = defineEmits(['register', 'success']); |
| 70 | 78 | |
| ... | ... | @@ -158,14 +166,28 @@ |
| 158 | 166 | params = (await EventsRef.value?.getFormData()) || {}; |
| 159 | 167 | } |
| 160 | 168 | params.deviceProfileId = props.record.id; |
| 169 | + | |
| 161 | 170 | if (unref(openModalMode) === OpenModelMode.CREATE) { |
| 162 | - await createModel(params); | |
| 171 | + (unref(isSysadmin) || unref(isPlatformAdmin)) && props.record.ifShowClass | |
| 172 | + ? await createModelCategory({ | |
| 173 | + ...params, | |
| 174 | + deviceProfileId: undefined, | |
| 175 | + categoryId: props.record.id, | |
| 176 | + }) | |
| 177 | + : await createModel(params); | |
| 163 | 178 | createMessage.success('创建成功'); |
| 164 | 179 | } else { |
| 165 | 180 | params.id = unref(openModalParams)?.record.id; |
| 166 | - await updateModel(params); | |
| 181 | + (unref(isSysadmin) || unref(isPlatformAdmin)) && props.record.ifShowClass | |
| 182 | + ? await updateModelCategory({ | |
| 183 | + ...params, | |
| 184 | + deviceProfileId: undefined, | |
| 185 | + categoryId: props.record.id, | |
| 186 | + }) | |
| 187 | + : await updateModel(params); | |
| 167 | 188 | createMessage.success('修改成功'); |
| 168 | 189 | } |
| 190 | + | |
| 169 | 191 | closeModal(); |
| 170 | 192 | emit('success'); |
| 171 | 193 | } catch (error) { | ... | ... |
| ... | ... | @@ -73,9 +73,18 @@ |
| 73 | 73 | const getAllModel = () => { |
| 74 | 74 | const { id: deviceProfileId } = props.record; |
| 75 | 75 | return Promise.all([ |
| 76 | - getModelTsl({ deviceProfileId, functionType: FunctionType.EVENTS }), | |
| 77 | - getModelTsl({ deviceProfileId, functionType: FunctionType.PROPERTIES }), | |
| 78 | - getModelTsl({ deviceProfileId, functionType: FunctionType.SERVICE }), | |
| 76 | + getModelTsl({ | |
| 77 | + deviceProfileId, | |
| 78 | + functionType: FunctionType.EVENTS, | |
| 79 | + }), | |
| 80 | + getModelTsl({ | |
| 81 | + deviceProfileId, | |
| 82 | + functionType: FunctionType.PROPERTIES, | |
| 83 | + }), | |
| 84 | + getModelTsl({ | |
| 85 | + deviceProfileId, | |
| 86 | + functionType: FunctionType.SERVICE, | |
| 87 | + }), | |
| 79 | 88 | ]); |
| 80 | 89 | }; |
| 81 | 90 | ... | ... |
| ... | ... | @@ -84,7 +84,10 @@ |
| 84 | 84 | const handleSwitchTsl = async (functionType: FunctionType) => { |
| 85 | 85 | try { |
| 86 | 86 | loading.value = true; |
| 87 | - const record = await getModelTsl({ deviceProfileId: props.record.id, functionType }); | |
| 87 | + const record = await getModelTsl({ | |
| 88 | + deviceProfileId: props.record.id, | |
| 89 | + functionType, | |
| 90 | + }); | |
| 88 | 91 | jsonValue.value = JSON.stringify( |
| 89 | 92 | { |
| 90 | 93 | [functionType]: record, | ... | ... |
| 1 | 1 | import { FormSchema } from '/@/components/Table'; |
| 2 | 2 | import { findDictItemByCode } from '/@/api/system/dict'; |
| 3 | +import { DataTypeEnum } from '/@/enums/objectModelEnum'; | |
| 3 | 4 | |
| 4 | 5 | export enum FormField { |
| 5 | 6 | FUNCTION_NAME = 'functionName', |
| ... | ... | @@ -40,30 +41,19 @@ export enum AssessMode { |
| 40 | 41 | WRITE = 'w', |
| 41 | 42 | } |
| 42 | 43 | |
| 43 | -/** | |
| 44 | - * 新增参数 动态显示表单 | |
| 45 | - */ | |
| 46 | -export enum DataTypeEnum { | |
| 47 | - IS_NUMBER_INT = 'INT', | |
| 48 | - IS_NUMBER_DOUBLE = 'DOUBLE', | |
| 49 | - IS_STRING = 'TEXT', | |
| 50 | - IS_STRUCT = 'STRUCT', | |
| 51 | - IS_BOOL = 'BOOL', | |
| 52 | -} | |
| 53 | - | |
| 54 | 44 | const isNumber = (type: string) => { |
| 55 | - return type === DataTypeEnum.IS_NUMBER_INT || type === DataTypeEnum.IS_NUMBER_DOUBLE; | |
| 45 | + return type === DataTypeEnum.NUMBER_INT || type === DataTypeEnum.NUMBER_DOUBLE; | |
| 56 | 46 | }; |
| 57 | 47 | |
| 58 | 48 | const isString = (type: string) => { |
| 59 | - return type === DataTypeEnum.IS_STRING; | |
| 49 | + return type === DataTypeEnum.STRING; | |
| 60 | 50 | }; |
| 61 | 51 | const isStruct = (type: string) => { |
| 62 | - return type === DataTypeEnum.IS_STRUCT; | |
| 52 | + return type === DataTypeEnum.STRUCT; | |
| 63 | 53 | }; |
| 64 | 54 | |
| 65 | 55 | const isBool = (type: string) => { |
| 66 | - return type === DataTypeEnum.IS_BOOL; | |
| 56 | + return type === DataTypeEnum.BOOL; | |
| 67 | 57 | }; |
| 68 | 58 | |
| 69 | 59 | export const serviceSchemas = (tcpDeviceFlag: boolean): FormSchema[] => { | ... | ... |
| ... | ... | @@ -138,13 +138,90 @@ |
| 138 | 138 | }); |
| 139 | 139 | } |
| 140 | 140 | |
| 141 | + const cipherLength = 7; | |
| 142 | + | |
| 143 | + //字符串星号替代 | |
| 144 | + function parseStringToStar(originalStr: string, startLength: number, endLength: number) { | |
| 145 | + //字符串大于7位,前3后4明文,其他以星号替代 | |
| 146 | + //字符串小于7位,前1后1明文,其他以星号替代 | |
| 147 | + return originalStr?.length > startLength | |
| 148 | + ? originalStr?.substr(0, startLength) + | |
| 149 | + new Array(originalStr?.length - endLength)?.join('*') + | |
| 150 | + originalStr?.substr(-endLength) | |
| 151 | + : originalStr; | |
| 152 | + } | |
| 153 | + | |
| 154 | + //长度 都大于或者小于7或者其中一个大于7,一个小于7个字符的处理 | |
| 155 | + //二维数组优化if else if else | |
| 156 | + const mapConditionConfig = [ | |
| 157 | + [ | |
| 158 | + (startParam, endParam) => | |
| 159 | + String(startParam)?.length > cipherLength && String(endParam)?.length > cipherLength, | |
| 160 | + (startParam) => parseStringToStar(startParam, 3, 4), | |
| 161 | + (endParam) => parseStringToStar(endParam, 3, 4), | |
| 162 | + ], | |
| 163 | + [ | |
| 164 | + (startParam, endParam) => | |
| 165 | + String(startParam)?.length < cipherLength && String(endParam)?.length < cipherLength, | |
| 166 | + (startParam) => parseStringToStar(startParam, 1, 1), | |
| 167 | + (endParam) => parseStringToStar(endParam, 1, 1), | |
| 168 | + ], | |
| 169 | + [ | |
| 170 | + (startParam, endParam) => | |
| 171 | + String(startParam)?.length > cipherLength || String(endParam)?.length < cipherLength, | |
| 172 | + (startParam) => parseStringToStar(startParam, 3, 4), | |
| 173 | + (endParam) => parseStringToStar(endParam, 1, 1), | |
| 174 | + ], | |
| 175 | + [ | |
| 176 | + (startParam, endParam) => | |
| 177 | + String(startParam)?.length < cipherLength || String(endParam)?.length > cipherLength, | |
| 178 | + (startParam) => parseStringToStar(startParam, 1, 1), | |
| 179 | + (endParam) => parseStringToStar(endParam, 3, 4), | |
| 180 | + ], | |
| 181 | + ]; | |
| 182 | + | |
| 183 | + const handleStandardLength = ( | |
| 184 | + startKey: string, | |
| 185 | + endKey: string, | |
| 186 | + startParam: string, | |
| 187 | + endParam: string | |
| 188 | + ) => { | |
| 189 | + const findDateFlow: any = mapConditionConfig.find((item: Function[]) => | |
| 190 | + item[0](startParam, endParam) | |
| 191 | + ); | |
| 192 | + if (!findDateFlow) return; | |
| 193 | + const cipherData: Recordable = {}; | |
| 194 | + cipherData[startKey] = findDateFlow[1](startParam); | |
| 195 | + cipherData[endKey] = findDateFlow[2](endParam); | |
| 196 | + return cipherData; | |
| 197 | + }; | |
| 198 | + | |
| 199 | + const handleCipherTextConfig = (e) => { | |
| 200 | + /** | |
| 201 | + * username和password 存在则是邮件配置 | |
| 202 | + * secretId和secretKey 存在则是腾讯云配置信息 | |
| 203 | + * accessKeyId和accessKeySecret 存在则是阿里云配置信息 | |
| 204 | + */ | |
| 205 | + const { username, password, secretId, secretKey, accessKeyId, accessKeySecret } = e; | |
| 206 | + return JSON.parse( | |
| 207 | + JSON.stringify({ | |
| 208 | + ...e, | |
| 209 | + ...handleStandardLength('username', 'password', username, password), | |
| 210 | + ...handleStandardLength('secretId', 'secretKey', secretId, secretKey), | |
| 211 | + ...handleStandardLength('accessKeyId', 'accessKeySecret', accessKeyId, accessKeySecret), | |
| 212 | + }) | |
| 213 | + ); | |
| 214 | + }; | |
| 215 | + | |
| 141 | 216 | function showData(record: Recordable) { |
| 142 | 217 | Modal.info({ |
| 143 | 218 | title: '当前配置', |
| 144 | 219 | width: 600, |
| 145 | 220 | centered: true, |
| 146 | 221 | maskClosable: true, |
| 147 | - content: h(JsonPreview, { data: JSON.parse(JSON.stringify(record.config)) }), | |
| 222 | + content: h(JsonPreview, { | |
| 223 | + data: handleCipherTextConfig(record.config), | |
| 224 | + }), | |
| 148 | 225 | }); |
| 149 | 226 | } |
| 150 | 227 | const statusChange = async (checked, record) => { | ... | ... |
| ... | ... | @@ -184,10 +184,12 @@ |
| 184 | 184 | businessText.value === BusinessReportConfigTextEnum.BUSINESS_ADD_TEXT |
| 185 | 185 | ? await createOrEditReportManage(data) |
| 186 | 186 | : putReportConfigManage({ ...restData.data, ...data }); |
| 187 | - emits('success'); | |
| 188 | 187 | createMessage.success(`${businessText.value}成功`); |
| 189 | 188 | closeDrawer(); |
| 190 | 189 | handleClose(); |
| 190 | + setTimeout(() => { | |
| 191 | + emits('success'); | |
| 192 | + }, 500); | |
| 191 | 193 | } finally { |
| 192 | 194 | setDrawerProps({ confirmLoading: false }); |
| 193 | 195 | } | ... | ... |
| ... | ... | @@ -471,7 +471,6 @@ export const formSchema: BFormSchema[] = [ |
| 471 | 471 | dynamicRules: () => { |
| 472 | 472 | return [ |
| 473 | 473 | { |
| 474 | - // required: model[SchemaFiled.AGG] !== AggregateDataEnum.NONE, | |
| 475 | 474 | required: true, |
| 476 | 475 | message: '间隔时间为必填项', |
| 477 | 476 | type: 'number', |
| ... | ... | @@ -479,7 +478,11 @@ export const formSchema: BFormSchema[] = [ |
| 479 | 478 | ]; |
| 480 | 479 | }, |
| 481 | 480 | ifShow({ values }) { |
| 482 | - return values[SchemaFiled.WAY] === QueryWay.TIME_PERIOD && exectueIsImmed(values.executeWay); | |
| 481 | + return ( | |
| 482 | + values[SchemaFiled.WAY] === QueryWay.TIME_PERIOD && | |
| 483 | + exectueIsImmed(values.executeWay) && | |
| 484 | + values[SchemaFiled.DATA_TYPE] !== DataTypeEnum.ORIGINAL | |
| 485 | + ); | |
| 483 | 486 | }, |
| 484 | 487 | componentProps({ formModel, formActionType }) { |
| 485 | 488 | const options = | ... | ... |
| ... | ... | @@ -166,6 +166,8 @@ export const useHooks = () => { |
| 166 | 166 | dataRange: [value?.startTs, value?.endTs], |
| 167 | 167 | dateGroupGap: value?.interval, |
| 168 | 168 | }; |
| 169 | + Reflect.deleteProperty(value, 'startTs'); | |
| 170 | + Reflect.deleteProperty(value, 'interval'); | |
| 169 | 171 | } |
| 170 | 172 | const spanDisance = executeContent?.split(' '); |
| 171 | 173 | const cronTime = | ... | ... |
| ... | ... | @@ -34,7 +34,12 @@ |
| 34 | 34 | @change="(value) => handleChangeChars(value, item.device, item)" |
| 35 | 35 | v-bind="createPickerSearch()" |
| 36 | 36 | placeholder="请选择设备属性" |
| 37 | - :options="item?.attributes?.map((item1) => ({ label: item1, value: item1 }))" | |
| 37 | + :options=" | |
| 38 | + item?.attributes?.map((attrItem: any) => ({ | |
| 39 | + label: attrItem.label, | |
| 40 | + value: attrItem.value, | |
| 41 | + })) | |
| 42 | + " | |
| 38 | 43 | /> |
| 39 | 44 | </div> |
| 40 | 45 | <div class="w-full h-full flex justify-center items-center"> |
| ... | ... | @@ -64,6 +69,8 @@ |
| 64 | 69 | import { ExecuteReportRecord } from '/@/api/export/model/exportModel'; |
| 65 | 70 | import { Select, Spin, Empty } from 'ant-design-vue'; |
| 66 | 71 | import { createPickerSearch } from '/@/utils/pickerSearch'; |
| 72 | + import { getDeviceDetail } from '/@/api/device/deviceManager'; | |
| 73 | + import { getAttribute } from '/@/api/ruleengine/ruleengineApi'; | |
| 67 | 74 | |
| 68 | 75 | interface ResponsData { |
| 69 | 76 | attr: string; |
| ... | ... | @@ -141,20 +148,66 @@ |
| 141 | 148 | return chartOption; |
| 142 | 149 | }; |
| 143 | 150 | |
| 151 | + const handleDeviceProfileAttributes = async (entityId: string) => { | |
| 152 | + const deviceDetailRes = await getDeviceDetail(entityId); | |
| 153 | + const { deviceProfileId } = deviceDetailRes; | |
| 154 | + if (!deviceProfileId) return; | |
| 155 | + const attributeRes = await getAttribute(deviceProfileId); | |
| 156 | + return handleDataFormat(deviceDetailRes, attributeRes); | |
| 157 | + }; | |
| 158 | + | |
| 159 | + const handleDataFormat = (deviceDetail: any, attributes: any) => { | |
| 160 | + const { name, tbDeviceId } = deviceDetail; | |
| 161 | + const attribute = attributes.map((item: any) => ({ | |
| 162 | + identifier: item.identifier, | |
| 163 | + name: item.name, | |
| 164 | + detail: item.detail, | |
| 165 | + })); | |
| 166 | + return { | |
| 167 | + name, | |
| 168 | + tbDeviceId, | |
| 169 | + attribute, | |
| 170 | + }; | |
| 171 | + }; | |
| 172 | + | |
| 144 | 173 | const [register, { setModalProps }] = useModalInner( |
| 145 | 174 | async (data: { record: ExecuteReportRecord }) => { |
| 146 | 175 | setModalProps({ loading: true }); |
| 147 | 176 | try { |
| 148 | 177 | currentRecord = data.record; |
| 149 | 178 | const deviceInfo = data.record.executeCondition.executeAttributes || []; |
| 150 | - chartInstance.value = deviceInfo.map((item) => ({ | |
| 151 | - ...item, | |
| 152 | - active: item.attributes.at(0), | |
| 153 | - })); | |
| 179 | + let attributesList: Recordable[] = []; | |
| 180 | + // 处理为物模型里的标识符名 | |
| 181 | + const reflectDeviceList = deviceInfo.map(async (item) => { | |
| 182 | + const { device, attributes } = item as Recordable; | |
| 183 | + if (!device) return; | |
| 184 | + const thingsModel = (await handleDeviceProfileAttributes(item.device)) as Recordable; | |
| 185 | + const { tbDeviceId, attribute } = thingsModel as Recordable; | |
| 186 | + if (!tbDeviceId) return; | |
| 187 | + if (device === tbDeviceId) { | |
| 188 | + attributesList = attributes.reduce((acc, curr) => { | |
| 189 | + attribute.forEach((item: Recordable) => { | |
| 190 | + if (item.identifier === curr) { | |
| 191 | + acc.push({ | |
| 192 | + label: item.name, | |
| 193 | + value: item.identifier, | |
| 194 | + }); | |
| 195 | + } | |
| 196 | + }); | |
| 197 | + return [...acc]; | |
| 198 | + }, []); | |
| 199 | + } | |
| 200 | + return { | |
| 201 | + ...item, | |
| 202 | + active: attributes.at(0), | |
| 203 | + attributes: attributesList, | |
| 204 | + }; | |
| 205 | + }); | |
| 206 | + chartInstance.value = (await Promise.all(reflectDeviceList)) as any as ChartInstance[]; | |
| 154 | 207 | for (const item of unref(chartInstance)) { |
| 155 | 208 | const { attributes, device } = item; |
| 156 | 209 | |
| 157 | - const keys = attributes.length ? attributes.at(0) : ''; | |
| 210 | + const keys = attributes.length ? (attributes as any[]).at(0)?.value : ''; | |
| 158 | 211 | |
| 159 | 212 | const sendParams = { |
| 160 | 213 | ...data.record.executeCondition.executeCondition, | ... | ... |
| 1 | 1 | <script lang="ts" setup> |
| 2 | - import { Button, Tabs, Tag } from 'ant-design-vue'; | |
| 2 | + import { Button, Tabs, Select } from 'ant-design-vue'; | |
| 3 | 3 | import { remove, uniqBy, cloneDeep } from 'lodash'; |
| 4 | - import { computed, nextTick, onMounted, ref, unref, toRaw } from 'vue'; | |
| 4 | + import { nextTick, onMounted, ref, unref, toRaw, watch } from 'vue'; | |
| 5 | 5 | import { |
| 6 | 6 | deviceTableColumn, |
| 7 | 7 | deviceTableFormSchema, |
| ... | ... | @@ -21,8 +21,7 @@ |
| 21 | 21 | |
| 22 | 22 | const props = withDefaults( |
| 23 | 23 | defineProps<{ |
| 24 | - getPendingTableParams: (params: Recordable) => any; | |
| 25 | - getSelectedTableParams: (params: Recordable) => any; | |
| 24 | + params?: Recordable; | |
| 26 | 25 | value?: (Recordable & DeviceModel)[]; |
| 27 | 26 | maxTagLength?: number; |
| 28 | 27 | openModalValidate?: () => boolean; |
| ... | ... | @@ -34,6 +33,7 @@ |
| 34 | 33 | value: () => [], |
| 35 | 34 | maxTagLength: 2, |
| 36 | 35 | primaryKey: 'tbDeviceId', |
| 36 | + params: () => ({}), | |
| 37 | 37 | } |
| 38 | 38 | ); |
| 39 | 39 | |
| ... | ... | @@ -56,23 +56,6 @@ |
| 56 | 56 | |
| 57 | 57 | const selectedConfirmQueue = ref<DeviceModel[]>([]); |
| 58 | 58 | |
| 59 | - const getShowTagOptions = computed(() => { | |
| 60 | - const { maxTagLength } = props; | |
| 61 | - return unref(selectedTotalList).slice(0, maxTagLength); | |
| 62 | - }); | |
| 63 | - | |
| 64 | - const getSurplusOptionsLength = computed(() => { | |
| 65 | - const { maxTagLength } = props; | |
| 66 | - const surplusValue = unref(selectedTotalList).length - maxTagLength; | |
| 67 | - return surplusValue < 0 ? 0 : surplusValue; | |
| 68 | - }); | |
| 69 | - | |
| 70 | - // const pendingListCount = computed(() => { | |
| 71 | - // const { value } = props; | |
| 72 | - // const selectedList = unref(pendingTotalList).filter((item) => value.includes(item.id)); | |
| 73 | - // return unref(pendingTotalList).length - selectedList.length; | |
| 74 | - // }); | |
| 75 | - | |
| 76 | 59 | const [registerModal, { openModal }] = useModal(); |
| 77 | 60 | |
| 78 | 61 | const [regsterPendingTable, pendingTableActionType] = useTable({ |
| ... | ... | @@ -82,9 +65,8 @@ |
| 82 | 65 | immediate: false, |
| 83 | 66 | clickToRowSelect: false, |
| 84 | 67 | beforeFetch: (params) => { |
| 85 | - const { getPendingTableParams } = props; | |
| 86 | - const data = getPendingTableParams?.(params) || {}; | |
| 87 | - Object.assign(params, { ...data, selected: false }); | |
| 68 | + const { params: otherParams } = props; | |
| 69 | + Object.assign(params, { ...otherParams, selected: false }); | |
| 88 | 70 | return params; |
| 89 | 71 | }, |
| 90 | 72 | afterFetch: (list: DeviceModel[]) => { |
| ... | ... | @@ -150,9 +132,8 @@ |
| 150 | 132 | dataSource: selectedTotalList, |
| 151 | 133 | clickToRowSelect: false, |
| 152 | 134 | beforeFetch: (params) => { |
| 153 | - const { getSelectedTableParams } = props; | |
| 154 | - const data = getSelectedTableParams?.(params) || {}; | |
| 155 | - Object.assign(params, { ...data, selected: false }); | |
| 135 | + const { params: otherParams } = props; | |
| 136 | + Object.assign(params, { ...otherParams, selected: false }); | |
| 156 | 137 | return params; |
| 157 | 138 | }, |
| 158 | 139 | rowSelection: { |
| ... | ... | @@ -219,18 +200,31 @@ |
| 219 | 200 | |
| 220 | 201 | if (openModalValidate && isFunction(openModalValidate) && !openModalValidate()) return; |
| 221 | 202 | |
| 203 | + activeKey.value = Active.PENDING; | |
| 222 | 204 | openModal(true); |
| 223 | 205 | await nextTick(); |
| 224 | 206 | pendingTableActionType.reload(); |
| 225 | 207 | }; |
| 226 | 208 | |
| 209 | + watch( | |
| 210 | + () => props.params, | |
| 211 | + () => { | |
| 212 | + selectedTotalList.value = []; | |
| 213 | + selectedConfirmQueue.value = []; | |
| 214 | + pendingConfirmQueue.value = []; | |
| 215 | + try { | |
| 216 | + pendingTableActionType.clearSelectedRowKeys(); | |
| 217 | + selectedTableActionType.clearSelectedRowKeys(); | |
| 218 | + } catch (error) {} | |
| 219 | + } | |
| 220 | + ); | |
| 221 | + | |
| 227 | 222 | onMounted(async () => { |
| 228 | - const { getSelectedTableParams } = props; | |
| 229 | - const data = getSelectedTableParams?.({}) || {}; | |
| 230 | - if (!data?.convertConfigId || !data?.deviceProfileIds) { | |
| 223 | + const { params } = props; | |
| 224 | + if (!params?.convertConfigId || !params?.deviceProfileIds) { | |
| 231 | 225 | return; |
| 232 | 226 | } |
| 233 | - const { items } = await devicePage({ page: 1, pageSize: 10, ...data, selected: true }); | |
| 227 | + const { items } = await devicePage({ page: 1, pageSize: 10, ...params, selected: true }); | |
| 234 | 228 | selectedTotalList.value = items; |
| 235 | 229 | }); |
| 236 | 230 | </script> |
| ... | ... | @@ -239,7 +233,7 @@ |
| 239 | 233 | <section> |
| 240 | 234 | <BasicModal |
| 241 | 235 | @register="registerModal" |
| 242 | - title="穿梭表格" | |
| 236 | + title="设备选择" | |
| 243 | 237 | width="60%" |
| 244 | 238 | :wrapClassName="prefixCls" |
| 245 | 239 | :showOkBtn="false" |
| ... | ... | @@ -251,13 +245,11 @@ |
| 251 | 245 | <template #tab> |
| 252 | 246 | <div class="flex items-center justify-center"> |
| 253 | 247 | <span>待选设备</span> |
| 254 | - <!-- <Badge show-zero :count="pendingListCount" /> --> | |
| 255 | 248 | </div> |
| 256 | 249 | </template> |
| 257 | 250 | <BasicTable @register="regsterPendingTable"> |
| 258 | 251 | <template #toolbar> |
| 259 | 252 | <section class="flex w-full justify-end items-center"> |
| 260 | - <!-- <Button type="primary">全选</Button> --> | |
| 261 | 253 | <div class="text-blue-400"> |
| 262 | 254 | <span class="mr-2">选择设备:</span> |
| 263 | 255 | <span>{{ pendingConfirmQueue.length }}</span> |
| ... | ... | @@ -279,7 +271,6 @@ |
| 279 | 271 | <template #tab> |
| 280 | 272 | <div class="flex items-center justify-center"> |
| 281 | 273 | <span>已选设备</span> |
| 282 | - <!-- <Badge show-zero :count="selectedTotalList.length" /> --> | |
| 283 | 274 | </div> |
| 284 | 275 | </template> |
| 285 | 276 | <BasicTable @register="registerSelectedTable"> |
| ... | ... | @@ -305,23 +296,22 @@ |
| 305 | 296 | </Tabs> |
| 306 | 297 | </section> |
| 307 | 298 | </BasicModal> |
| 308 | - <Button @click="handleOpenModal" type="link" :disabled="disabled"> | |
| 309 | - <span v-if="!selectedTotalList.length">选择设备</span> | |
| 310 | - <div v-if="selectedTotalList.length"> | |
| 311 | - <Tag | |
| 312 | - class="!px-2 !py-1 !bg-gray-50 !border-gray-100" | |
| 313 | - v-for="item in getShowTagOptions" | |
| 314 | - :key="item[primaryKey]" | |
| 315 | - > | |
| 316 | - <span> | |
| 317 | - {{ item.alias || item.name }} | |
| 318 | - </span> | |
| 319 | - </Tag> | |
| 320 | - <Tag class="!px-2 !py-1 !bg-gray-50 !border-gray-100" v-if="getSurplusOptionsLength"> | |
| 321 | - <span> +{{ getSurplusOptionsLength }}... </span> | |
| 322 | - </Tag> | |
| 323 | - </div> | |
| 324 | - </Button> | |
| 299 | + <Select | |
| 300 | + placeholder="请选择设备" | |
| 301 | + :disabled="disabled" | |
| 302 | + :value="selectedTotalList.map((item) => item[primaryKey])" | |
| 303 | + mode="multiple" | |
| 304 | + :maxTagCount="3" | |
| 305 | + :open="false" | |
| 306 | + @dropdownVisibleChange="handleOpenModal" | |
| 307 | + :options=" | |
| 308 | + selectedTotalList.map((item) => ({ | |
| 309 | + ...item, | |
| 310 | + label: item.alias || item.name, | |
| 311 | + value: item[primaryKey], | |
| 312 | + })) | |
| 313 | + " | |
| 314 | + /> | |
| 325 | 315 | </section> |
| 326 | 316 | </template> |
| 327 | 317 | ... | ... |
| ... | ... | @@ -73,6 +73,10 @@ export const modeForm = (disabled: boolean): FormSchema[] => { |
| 73 | 73 | labelField: 'name', |
| 74 | 74 | valueField: 'tbProfileId', |
| 75 | 75 | disabled, |
| 76 | + selectProps: { | |
| 77 | + disabled, | |
| 78 | + placeholder: '请选择产品', | |
| 79 | + }, | |
| 76 | 80 | transferProps: { |
| 77 | 81 | listStyle: { height: '400px' }, |
| 78 | 82 | showSearch: true, |
| ... | ... | @@ -98,26 +102,14 @@ export const modeForm = (disabled: boolean): FormSchema[] => { |
| 98 | 102 | valueField: 'value', |
| 99 | 103 | changeEvent: 'update:value', |
| 100 | 104 | rules: [{ required: true, message: '数据源设备为必选项', type: 'array' }], |
| 101 | - componentProps: ({ formActionType }) => { | |
| 102 | - const { getFieldsValue } = formActionType; | |
| 105 | + componentProps: ({ formModel }) => { | |
| 106 | + const convertConfigId = formModel[BasicInfoFormField.CONVERT_CONFIG_ID]; | |
| 107 | + const deviceProfileIds = formModel[BasicInfoFormField.DATA_SOURCE_PRODUCT]; | |
| 103 | 108 | return { |
| 104 | 109 | disabled, |
| 105 | - getPendingTableParams: () => { | |
| 106 | - const values = getFieldsValue(); | |
| 107 | - const convertConfigId = Reflect.get(values, BasicInfoFormField.CONVERT_CONFIG_ID); | |
| 108 | - const deviceProfileIds = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_PRODUCT); | |
| 109 | - return { convertConfigId, deviceProfileIds }; | |
| 110 | - }, | |
| 111 | - getSelectedTableParams: () => { | |
| 112 | - const values = getFieldsValue(); | |
| 113 | - const convertConfigId = Reflect.get(values, BasicInfoFormField.CONVERT_CONFIG_ID); | |
| 114 | - const deviceProfileIds = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_PRODUCT); | |
| 115 | - return { convertConfigId, deviceProfileIds }; | |
| 116 | - }, | |
| 110 | + params: { convertConfigId, deviceProfileIds }, | |
| 117 | 111 | transformValue: handleGroupDevice, |
| 118 | 112 | openModalValidate: () => { |
| 119 | - const values = getFieldsValue(); | |
| 120 | - const deviceProfileIds = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_PRODUCT); | |
| 121 | 113 | if (!deviceProfileIds || !deviceProfileIds?.length) { |
| 122 | 114 | createMessage.warning('请选择数据源设备'); |
| 123 | 115 | } | ... | ... |
| ... | ... | @@ -9,6 +9,7 @@ export const formSchemas: FormSchema[] = [ |
| 9 | 9 | field: CheckExistenceFieldsEnum.MESSAGE_NAMES, |
| 10 | 10 | component: 'Select', |
| 11 | 11 | label: CheckExistenceFieldsNameEnum.MESSAGE_NAMES, |
| 12 | + rules: [{ required: true, type: 'array' }], | |
| 12 | 13 | componentProps: { |
| 13 | 14 | mode: 'tags', |
| 14 | 15 | open: false, |
| ... | ... | @@ -20,6 +21,7 @@ export const formSchemas: FormSchema[] = [ |
| 20 | 21 | field: CheckExistenceFieldsEnum.METADATA_NAMES, |
| 21 | 22 | component: 'Select', |
| 22 | 23 | label: CheckExistenceFieldsNameEnum.METADATA_NAMES, |
| 24 | + rules: [{ required: true, type: 'array' }], | |
| 23 | 25 | componentProps: { |
| 24 | 26 | mode: 'tags', |
| 25 | 27 | open: false, | ... | ... |
| ... | ... | @@ -25,7 +25,7 @@ export const getFormSchemas = (route: RouteLocationNormalizedLoaded): FormSchema |
| 25 | 25 | component: 'ApiSearchSelect', |
| 26 | 26 | componentProps: () => { |
| 27 | 27 | return { |
| 28 | - placeholder: '请选择所属产品', | |
| 28 | + placeholder: '请选择规则链', | |
| 29 | 29 | showSearch: true, |
| 30 | 30 | params: { |
| 31 | 31 | pageSize: 50, | ... | ... |
| ... | ... | @@ -62,7 +62,7 @@ export const formSchemas: FormSchema[] = [ |
| 62 | 62 | { |
| 63 | 63 | field: FormFieldsEnum.STATUS, |
| 64 | 64 | label: '状态', |
| 65 | - component: 'Input', | |
| 65 | + component: 'Select', | |
| 66 | 66 | componentProps: { |
| 67 | 67 | options: Object.keys(StatusEnum).map((value) => ({ label: StatusNameEnum[value], value })), |
| 68 | 68 | allowClear: true, | ... | ... |