Commit 9ecf92838e500e6fbf6b931933ab483076c01365
Merge branch 'feat/device-list-collect' of http://git.yunteng.com/yunteng/things…
…kit-front into feat/device-new-protocol
Showing
30 changed files
with
394 additions
and
30 deletions
| @@ -45,6 +45,7 @@ enum DeviceManagerApi { | @@ -45,6 +45,7 @@ enum DeviceManagerApi { | ||
| 45 | DEVICE_PUBLIC = '/customer/public/device', | 45 | DEVICE_PUBLIC = '/customer/public/device', |
| 46 | 46 | ||
| 47 | DEVICE_PRIVATE = '/customer/device', | 47 | DEVICE_PRIVATE = '/customer/device', |
| 48 | + DEVICE_COLLECT = '/device/collect ', //收藏 | ||
| 48 | 49 | ||
| 49 | /** | 50 | /** |
| 50 | * @description 通过设备列表获取设备信息 | 51 | * @description 通过设备列表获取设备信息 |
| @@ -61,6 +62,13 @@ export const devicePage = (params: DeviceQueryParam) => { | @@ -61,6 +62,13 @@ export const devicePage = (params: DeviceQueryParam) => { | ||
| 61 | }); | 62 | }); |
| 62 | }; | 63 | }; |
| 63 | 64 | ||
| 65 | +export const deviceCollect = (params: Array<any>) => { | ||
| 66 | + return defHttp.post({ | ||
| 67 | + url: `${DeviceManagerApi.DEVICE_COLLECT}`, | ||
| 68 | + params, | ||
| 69 | + }); | ||
| 70 | +}; | ||
| 71 | + | ||
| 64 | /** | 72 | /** |
| 65 | * 分页查询设备配置页面 | 73 | * 分页查询设备配置页面 |
| 66 | * @param params pageSize page name | 74 | * @param params pageSize page name |
| @@ -187,6 +187,7 @@ export interface AlarmLogItem { | @@ -187,6 +187,7 @@ export interface AlarmLogItem { | ||
| 187 | originatorType: number; | 187 | originatorType: number; |
| 188 | deviceId: string; | 188 | deviceId: string; |
| 189 | deviceName: string; | 189 | deviceName: string; |
| 190 | + deviceAlias: string; | ||
| 190 | type: string; | 191 | type: string; |
| 191 | severity: string; | 192 | severity: string; |
| 192 | status: string; | 193 | status: string; |
| @@ -67,7 +67,7 @@ export function useAlarmNotify(params: UseAlarmNotifyParams = {}) { | @@ -67,7 +67,7 @@ export function useAlarmNotify(params: UseAlarmNotifyParams = {}) { | ||
| 67 | 67 | ||
| 68 | if (items.length) { | 68 | if (items.length) { |
| 69 | const first = items.at(0)!; | 69 | const first = items.at(0)!; |
| 70 | - const { deviceName, id, severity, type } = first; | 70 | + const { deviceAlias, deviceName, id, severity, type } = first; |
| 71 | 71 | ||
| 72 | let key: Nullable<string> = `open-notify-${id}`; | 72 | let key: Nullable<string> = `open-notify-${id}`; |
| 73 | 73 | ||
| @@ -80,7 +80,7 @@ export function useAlarmNotify(params: UseAlarmNotifyParams = {}) { | @@ -80,7 +80,7 @@ export function useAlarmNotify(params: UseAlarmNotifyParams = {}) { | ||
| 80 | description: h('div', {}, [ | 80 | description: h('div', {}, [ |
| 81 | h('div', { style: { marginRight: '5px' } }, [ | 81 | h('div', { style: { marginRight: '5px' } }, [ |
| 82 | h('span', { style: { marginRight: '5px' } }, '设备:'), | 82 | h('span', { style: { marginRight: '5px' } }, '设备:'), |
| 83 | - h('span', {}, `[${deviceName}]`), | 83 | + h('span', {}, `[${deviceAlias ?? deviceName}]`), |
| 84 | ]), | 84 | ]), |
| 85 | h('div', { style: { marginRight: '5px' } }, [ | 85 | h('div', { style: { marginRight: '5px' } }, [ |
| 86 | h('span', { style: { marginRight: '5px' } }, '告警场景:'), | 86 | h('span', { style: { marginRight: '5px' } }, '告警场景:'), |
| @@ -41,6 +41,7 @@ | @@ -41,6 +41,7 @@ | ||
| 41 | " | 41 | " |
| 42 | v-else-if="item.key === TableDefaultTypeEnum.ENTITYID" | 42 | v-else-if="item.key === TableDefaultTypeEnum.ENTITYID" |
| 43 | v-model:value="item.value" | 43 | v-model:value="item.value" |
| 44 | + v-bind="createPickerSearch()" | ||
| 44 | placeholder="请选择" | 45 | placeholder="请选择" |
| 45 | :options="entityOptions" | 46 | :options="entityOptions" |
| 46 | allowClear | 47 | allowClear |
| @@ -53,6 +54,7 @@ | @@ -53,6 +54,7 @@ | ||
| 53 | " | 54 | " |
| 54 | v-else-if="item.key === TableDefaultTypeEnum.KEYS" | 55 | v-else-if="item.key === TableDefaultTypeEnum.KEYS" |
| 55 | v-model:value="item.value" | 56 | v-model:value="item.value" |
| 57 | + v-bind="createPickerSearch()" | ||
| 56 | placeholder="请选择" | 58 | placeholder="请选择" |
| 57 | :options="attributeOptions" | 59 | :options="attributeOptions" |
| 58 | mode="multiple" | 60 | mode="multiple" |
| @@ -102,6 +104,7 @@ | @@ -102,6 +104,7 @@ | ||
| 102 | " | 104 | " |
| 103 | v-else | 105 | v-else |
| 104 | v-model:value="item.value" | 106 | v-model:value="item.value" |
| 107 | + v-bind="createPickerSearch()" | ||
| 105 | placeholder="请选择" | 108 | placeholder="请选择" |
| 106 | :options="valueOptions" | 109 | :options="valueOptions" |
| 107 | allowClear | 110 | allowClear |
| @@ -157,6 +160,7 @@ | @@ -157,6 +160,7 @@ | ||
| 157 | import { getPacketIntervalByRange } from '/@/views/device/localtion/cpns/TimePeriodForm/helper'; | 160 | import { getPacketIntervalByRange } from '/@/views/device/localtion/cpns/TimePeriodForm/helper'; |
| 158 | import { uniqBy } from 'lodash'; | 161 | import { uniqBy } from 'lodash'; |
| 159 | import { TableDefaultTypeEnum } from '../../../config/enum'; | 162 | import { TableDefaultTypeEnum } from '../../../config/enum'; |
| 163 | + import { createPickerSearch } from '/@/utils/pickerSearch'; | ||
| 160 | 164 | ||
| 161 | const props = defineProps({ | 165 | const props = defineProps({ |
| 162 | method: { | 166 | method: { |
| @@ -12,7 +12,7 @@ export const columns: BasicColumn[] = [ | @@ -12,7 +12,7 @@ export const columns: BasicColumn[] = [ | ||
| 12 | { | 12 | { |
| 13 | title: '状态', | 13 | title: '状态', |
| 14 | dataIndex: 'deviceState', | 14 | dataIndex: 'deviceState', |
| 15 | - width: 80, | 15 | + width: 110, |
| 16 | slots: { customRender: 'deviceState' }, | 16 | slots: { customRender: 'deviceState' }, |
| 17 | }, | 17 | }, |
| 18 | { | 18 | { |
| @@ -167,4 +167,17 @@ export const searchFormSchema: FormSchema[] = [ | @@ -167,4 +167,17 @@ export const searchFormSchema: FormSchema[] = [ | ||
| 167 | }; | 167 | }; |
| 168 | }, | 168 | }, |
| 169 | }, | 169 | }, |
| 170 | + { | ||
| 171 | + field: 'isCollect', | ||
| 172 | + label: '是否收藏', | ||
| 173 | + component: 'Select', | ||
| 174 | + colProps: { span: 6 }, | ||
| 175 | + componentProps: { | ||
| 176 | + options: [ | ||
| 177 | + { label: '是', value: 1 }, | ||
| 178 | + { label: '否', value: 0 }, | ||
| 179 | + ], | ||
| 180 | + placeholder: '请选择', | ||
| 181 | + }, | ||
| 182 | + }, | ||
| 170 | ]; | 183 | ]; |
| @@ -212,6 +212,10 @@ export const basicInfoForm: FormSchema[] = [ | @@ -212,6 +212,10 @@ export const basicInfoForm: FormSchema[] = [ | ||
| 212 | labelField: 'name', | 212 | labelField: 'name', |
| 213 | valueField: 'tbDeviceId', | 213 | valueField: 'tbDeviceId', |
| 214 | getPopupContainer: () => document.body, | 214 | getPopupContainer: () => document.body, |
| 215 | + showSearch: true, | ||
| 216 | + filterOption: (inputValue: string, options: Record<'label', string>) => { | ||
| 217 | + return options.label.includes(inputValue); | ||
| 218 | + }, | ||
| 215 | }; | 219 | }; |
| 216 | }, | 220 | }, |
| 217 | }, | 221 | }, |
| @@ -34,6 +34,11 @@ | @@ -34,6 +34,11 @@ | ||
| 34 | 批量分配 | 34 | 批量分配 |
| 35 | </a-button> | 35 | </a-button> |
| 36 | </Authority> | 36 | </Authority> |
| 37 | + <!-- <Authority> | ||
| 38 | + <a-button type="primary" @click="handelCollect()" :disabled="!isExistOption"> | ||
| 39 | + 批量收藏 | ||
| 40 | + </a-button> | ||
| 41 | + </Authority> --> | ||
| 37 | </template> | 42 | </template> |
| 38 | <template #img="{ record }"> | 43 | <template #img="{ record }"> |
| 39 | <TableImg | 44 | <TableImg |
| @@ -85,7 +90,13 @@ | @@ -85,7 +90,13 @@ | ||
| 85 | </Tag> | 90 | </Tag> |
| 86 | </template> | 91 | </template> |
| 87 | <template #deviceState="{ record }"> | 92 | <template #deviceState="{ record }"> |
| 93 | + <!-- <HeartOutlined v-if="!record.isCollect" class="mr-1" style="color: red" /> --> | ||
| 94 | + <Tooltip> | ||
| 95 | + <template #title> 我的收藏</template> | ||
| 96 | + <HeartTwoTone v-if="record.isCollect" class="mr-1" twoToneColor="#3B82F6" /> | ||
| 97 | + </Tooltip> | ||
| 88 | <Tag | 98 | <Tag |
| 99 | + :style="{ marginLeft: !record.isCollect ? '17px' : '' }" | ||
| 89 | :color=" | 100 | :color=" |
| 90 | record.deviceState == DeviceState.INACTIVE | 101 | record.deviceState == DeviceState.INACTIVE |
| 91 | ? 'warning' | 102 | ? 'warning' |
| @@ -154,6 +165,18 @@ | @@ -154,6 +165,18 @@ | ||
| 154 | icon: 'ant-design:rise-outlined', | 165 | icon: 'ant-design:rise-outlined', |
| 155 | onClick: handleUpAndDownRecord.bind(null, record), | 166 | onClick: handleUpAndDownRecord.bind(null, record), |
| 156 | }, | 167 | }, |
| 168 | + !record.isCollect | ||
| 169 | + ? { | ||
| 170 | + label: '收藏', | ||
| 171 | + icon: 'ant-design:heart-outlined', | ||
| 172 | + onClick: handelCollect.bind(null, record), | ||
| 173 | + } | ||
| 174 | + : { | ||
| 175 | + label: '取消收藏', | ||
| 176 | + auth: 'api:yt:device:online:record', | ||
| 177 | + icon: 'ant-design:heart-outlined', | ||
| 178 | + onClick: handelCollect.bind(null, record), | ||
| 179 | + }, | ||
| 157 | { | 180 | { |
| 158 | label: '删除', | 181 | label: '删除', |
| 159 | auth: 'api:yt:device:delete', | 182 | auth: 'api:yt:device:delete', |
| @@ -195,10 +218,12 @@ | @@ -195,10 +218,12 @@ | ||
| 195 | } from '/@/api/device/model/deviceModel'; | 218 | } from '/@/api/device/model/deviceModel'; |
| 196 | import { BasicTable, useTable, TableAction, TableImg } from '/@/components/Table'; | 219 | import { BasicTable, useTable, TableAction, TableImg } from '/@/components/Table'; |
| 197 | import { columns, searchFormSchema } from './config/device.data'; | 220 | import { columns, searchFormSchema } from './config/device.data'; |
| 198 | - import { Tag, Popover, Popconfirm, Button } from 'ant-design-vue'; | 221 | + import { Tag, Popover, Popconfirm, Button, Tooltip } from 'ant-design-vue'; |
| 222 | + import { HeartTwoTone } from '@ant-design/icons-vue'; | ||
| 199 | import { | 223 | import { |
| 200 | deleteDevice, | 224 | deleteDevice, |
| 201 | devicePage, | 225 | devicePage, |
| 226 | + deviceCollect, | ||
| 202 | cancelDispatchCustomer, | 227 | cancelDispatchCustomer, |
| 203 | getGATEWAY, | 228 | getGATEWAY, |
| 204 | privateDevice, | 229 | privateDevice, |
| @@ -244,6 +269,9 @@ | @@ -244,6 +269,9 @@ | ||
| 244 | Popconfirm, | 269 | Popconfirm, |
| 245 | BatchImportModal, | 270 | BatchImportModal, |
| 246 | Button, | 271 | Button, |
| 272 | + // HeartOutlined, | ||
| 273 | + HeartTwoTone, | ||
| 274 | + Tooltip, | ||
| 247 | }, | 275 | }, |
| 248 | setup(_) { | 276 | setup(_) { |
| 249 | const { isCustomer } = useAuthDeviceDetail(); | 277 | const { isCustomer } = useAuthDeviceDetail(); |
| @@ -465,6 +493,26 @@ | @@ -465,6 +493,26 @@ | ||
| 465 | } catch (error) {} | 493 | } catch (error) {} |
| 466 | }; | 494 | }; |
| 467 | 495 | ||
| 496 | + // 收藏 && 批量收藏 | ||
| 497 | + const handelCollect = async (record?: Recordable) => { | ||
| 498 | + let ids: string[] = []; | ||
| 499 | + if (record) { | ||
| 500 | + ids.push(record.id); | ||
| 501 | + } else { | ||
| 502 | + ids = await getSelectRowKeys(); | ||
| 503 | + } | ||
| 504 | + try { | ||
| 505 | + setLoading(true); | ||
| 506 | + await deviceCollect(ids); | ||
| 507 | + createMessage.success('操作成功'); | ||
| 508 | + handleReload(); | ||
| 509 | + } catch (error) { | ||
| 510 | + throw error; | ||
| 511 | + } finally { | ||
| 512 | + setLoading(false); | ||
| 513 | + } | ||
| 514 | + }; | ||
| 515 | + | ||
| 468 | onMounted(() => { | 516 | onMounted(() => { |
| 469 | const queryParams = ROUTE.query as Record<'deviceProfileId', undefined | string>; | 517 | const queryParams = ROUTE.query as Record<'deviceProfileId', undefined | string>; |
| 470 | const { setFieldsValue } = getForm(); | 518 | const { setFieldsValue } = getForm(); |
| @@ -492,6 +540,7 @@ | @@ -492,6 +540,7 @@ | ||
| 492 | copySN, | 540 | copySN, |
| 493 | isExistOption, | 541 | isExistOption, |
| 494 | handleDelete, | 542 | handleDelete, |
| 543 | + handelCollect, | ||
| 495 | // hasBatchDelete, | 544 | // hasBatchDelete, |
| 496 | // handleDeleteOrBatchDelete, | 545 | // handleDeleteOrBatchDelete, |
| 497 | handleReload, | 546 | handleReload, |
| @@ -2,7 +2,8 @@ import type { BasicColumn } from '/@/components/Table'; | @@ -2,7 +2,8 @@ import type { BasicColumn } from '/@/components/Table'; | ||
| 2 | import type { FormSchema } from '/@/components/Table'; | 2 | import type { FormSchema } from '/@/components/Table'; |
| 3 | import { getOrganizationList } from '/@/api/system/system'; | 3 | import { getOrganizationList } from '/@/api/system/system'; |
| 4 | import { copyTransFun } from '/@/utils/fnUtils'; | 4 | import { copyTransFun } from '/@/utils/fnUtils'; |
| 5 | -import { getDeviceDataKeys, getDeviceProfile } from '/@/api/alarm/position'; | 5 | +import { getDeviceDataKeys } from '/@/api/alarm/position'; |
| 6 | +import { deviceProfile } from '/@/api/device/deviceManager'; | ||
| 6 | import { EChartsOption } from 'echarts'; | 7 | import { EChartsOption } from 'echarts'; |
| 7 | 8 | ||
| 8 | export enum AggregateDataEnum { | 9 | export enum AggregateDataEnum { |
| @@ -31,11 +32,17 @@ export const formSchema: FormSchema[] = [ | @@ -31,11 +32,17 @@ export const formSchema: FormSchema[] = [ | ||
| 31 | field: 'deviceProfileId', | 32 | field: 'deviceProfileId', |
| 32 | label: '', | 33 | label: '', |
| 33 | component: 'ApiSelect', | 34 | component: 'ApiSelect', |
| 34 | - componentProps: { | ||
| 35 | - api: getDeviceProfile, | ||
| 36 | - placeholder: '请选择产品', | ||
| 37 | - labelField: 'name', | ||
| 38 | - valueField: 'tbProfileId', | 35 | + componentProps: () => { |
| 36 | + return { | ||
| 37 | + showSearch: true, | ||
| 38 | + labelField: 'name', | ||
| 39 | + valueField: 'tbProfileId', | ||
| 40 | + resultField: 'data', | ||
| 41 | + placeholder: '请选择产品', | ||
| 42 | + api: deviceProfile, | ||
| 43 | + filterOption: (inputValue: string, option: Record<'label' | 'value', string>) => | ||
| 44 | + option.label.includes(inputValue), | ||
| 45 | + }; | ||
| 39 | }, | 46 | }, |
| 40 | }, | 47 | }, |
| 41 | { | 48 | { |
| @@ -6,6 +6,7 @@ | @@ -6,6 +6,7 @@ | ||
| 6 | v-model:value="param.attributes" | 6 | v-model:value="param.attributes" |
| 7 | class="!w-1/2" | 7 | class="!w-1/2" |
| 8 | :options="selectOptions" | 8 | :options="selectOptions" |
| 9 | + v-bind="createPickerSearch()" | ||
| 9 | :disabled="disabled" | 10 | :disabled="disabled" |
| 10 | @change="emitChange" | 11 | @change="emitChange" |
| 11 | mode="multiple" | 12 | mode="multiple" |
| @@ -24,6 +25,7 @@ | @@ -24,6 +25,7 @@ | ||
| 24 | import { Select } from 'ant-design-vue'; | 25 | import { Select } from 'ant-design-vue'; |
| 25 | import { Params } from '../type/'; | 26 | import { Params } from '../type/'; |
| 26 | import { useHooks } from '../hooks/index.hooks'; | 27 | import { useHooks } from '../hooks/index.hooks'; |
| 28 | + import { createPickerSearch } from '/@/utils/pickerSearch'; | ||
| 27 | 29 | ||
| 28 | const props = defineProps({ | 30 | const props = defineProps({ |
| 29 | value: propTypes.object.def({}), | 31 | value: propTypes.object.def({}), |
| @@ -32,12 +32,10 @@ | @@ -32,12 +32,10 @@ | ||
| 32 | class="min-w-25" | 32 | class="min-w-25" |
| 33 | v-model:value="item.active" | 33 | v-model:value="item.active" |
| 34 | @change="(value) => handleChangeChars(value, item.device, item)" | 34 | @change="(value) => handleChangeChars(value, item.device, item)" |
| 35 | + v-bind="createPickerSearch()" | ||
| 35 | placeholder="请选择设备属性" | 36 | placeholder="请选择设备属性" |
| 36 | - > | ||
| 37 | - <Select.Option v-for="attr in item.attributes" :key="attr" :value="attr"> | ||
| 38 | - {{ attr }} | ||
| 39 | - </Select.Option> | ||
| 40 | - </Select> | 37 | + :options="item?.attributes?.map((item1) => ({ label: item1, value: item1 }))" |
| 38 | + /> | ||
| 41 | </div> | 39 | </div> |
| 42 | <div class="w-full h-full flex justify-center items-center"> | 40 | <div class="w-full h-full flex justify-center items-center"> |
| 43 | <Empty v-show="item.notFoundData" description="暂无数据" class="text-dark-50" /> | 41 | <Empty v-show="item.notFoundData" description="暂无数据" class="text-dark-50" /> |
| @@ -65,6 +63,7 @@ | @@ -65,6 +63,7 @@ | ||
| 65 | import moment from 'moment'; | 63 | import moment from 'moment'; |
| 66 | import { ExecuteReportRecord } from '/@/api/export/model/exportModel'; | 64 | import { ExecuteReportRecord } from '/@/api/export/model/exportModel'; |
| 67 | import { Select, Spin, Empty } from 'ant-design-vue'; | 65 | import { Select, Spin, Empty } from 'ant-design-vue'; |
| 66 | + import { createPickerSearch } from '/@/utils/pickerSearch'; | ||
| 68 | 67 | ||
| 69 | interface ResponsData { | 68 | interface ResponsData { |
| 70 | attr: string; | 69 | attr: string; |
| @@ -8,6 +8,7 @@ import { findDictItemByCode } from '/@/api/system/dict'; | @@ -8,6 +8,7 @@ import { findDictItemByCode } from '/@/api/system/dict'; | ||
| 8 | // import { unref } from 'vue'; | 8 | // import { unref } from 'vue'; |
| 9 | import { getMeetTheConditionsDevice } from '/@/api/dataBoard'; | 9 | import { getMeetTheConditionsDevice } from '/@/api/dataBoard'; |
| 10 | import { MasterDeviceList } from '/@/api/dataBoard/model'; | 10 | import { MasterDeviceList } from '/@/api/dataBoard/model'; |
| 11 | +import { createPickerSearch } from '/@/utils/pickerSearch'; | ||
| 11 | 12 | ||
| 12 | export const formSchemas = (): FormSchema[] => { | 13 | export const formSchemas = (): FormSchema[] => { |
| 13 | // const mode = useSelectWidgetMode(); | 14 | // const mode = useSelectWidgetMode(); |
| @@ -150,7 +151,6 @@ export const formSchemas = (): FormSchema[] => { | @@ -150,7 +151,6 @@ export const formSchemas = (): FormSchema[] => { | ||
| 150 | return []; | 151 | return []; |
| 151 | }, | 152 | }, |
| 152 | onChange(_value, record: MasterDeviceList) { | 153 | onChange(_value, record: MasterDeviceList) { |
| 153 | - console.log(record, 'record'); | ||
| 154 | setFieldsValue({ | 154 | setFieldsValue({ |
| 155 | [DataSourceField.DEVICE_NAME]: record?.label, | 155 | [DataSourceField.DEVICE_NAME]: record?.label, |
| 156 | deviceIds: record?.id, | 156 | deviceIds: record?.id, |
| @@ -158,6 +158,7 @@ export const formSchemas = (): FormSchema[] => { | @@ -158,6 +158,7 @@ export const formSchemas = (): FormSchema[] => { | ||
| 158 | }, | 158 | }, |
| 159 | placeholder: '请选择设备', | 159 | placeholder: '请选择设备', |
| 160 | getPopupContainer: () => document.body, | 160 | getPopupContainer: () => document.body, |
| 161 | + ...createPickerSearch(), | ||
| 161 | }; | 162 | }; |
| 162 | }, | 163 | }, |
| 163 | }, | 164 | }, |
| @@ -12,6 +12,7 @@ import { ComponentConfigFieldEnum } from '../../../enum'; | @@ -12,6 +12,7 @@ import { ComponentConfigFieldEnum } from '../../../enum'; | ||
| 12 | export const option: PublicPresetOptions = { | 12 | export const option: PublicPresetOptions = { |
| 13 | [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: false, | 13 | [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: false, |
| 14 | [ComponentConfigFieldEnum.FONT_SIZE]: 14, | 14 | [ComponentConfigFieldEnum.FONT_SIZE]: 14, |
| 15 | + [ComponentConfigFieldEnum.PASS_WORD]: '', | ||
| 15 | // [ComponentConfigFieldEnum.FONT_COLOR]: '#000', | 16 | // [ComponentConfigFieldEnum.FONT_COLOR]: '#000', |
| 16 | }; | 17 | }; |
| 17 | 18 |
| @@ -14,10 +14,10 @@ | @@ -14,10 +14,10 @@ | ||
| 14 | // defaultValue: option.fontColor, | 14 | // defaultValue: option.fontColor, |
| 15 | // }, | 15 | // }, |
| 16 | { | 16 | { |
| 17 | - field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME, | ||
| 18 | - label: '显示设备名称', | ||
| 19 | - component: 'Checkbox', | ||
| 20 | - defaultValue: option.showDeviceName, | 17 | + field: ComponentConfigFieldEnum.PASS_WORD, |
| 18 | + label: '操作密码', | ||
| 19 | + component: 'InputPassword', | ||
| 20 | + defaultValue: '', | ||
| 21 | }, | 21 | }, |
| 22 | { | 22 | { |
| 23 | field: ComponentConfigFieldEnum.FONT_SIZE, | 23 | field: ComponentConfigFieldEnum.FONT_SIZE, |
| @@ -25,6 +25,12 @@ | @@ -25,6 +25,12 @@ | ||
| 25 | component: 'InputNumber', | 25 | component: 'InputNumber', |
| 26 | defaultValue: 14, | 26 | defaultValue: 14, |
| 27 | }, | 27 | }, |
| 28 | + { | ||
| 29 | + field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME, | ||
| 30 | + label: '显示设备名称', | ||
| 31 | + component: 'Checkbox', | ||
| 32 | + defaultValue: option.showDeviceName, | ||
| 33 | + }, | ||
| 28 | ], | 34 | ], |
| 29 | showActionButtonGroup: false, | 35 | showActionButtonGroup: false, |
| 30 | labelWidth: 120, | 36 | labelWidth: 120, |
| @@ -9,6 +9,8 @@ | @@ -9,6 +9,8 @@ | ||
| 9 | import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type'; | 9 | import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type'; |
| 10 | import { useDataFetch } from '../../../hook/socket/useSocket'; | 10 | import { useDataFetch } from '../../../hook/socket/useSocket'; |
| 11 | import { getSendValues } from '../config'; | 11 | import { getSendValues } from '../config'; |
| 12 | + import { useModal } from '/@/components/Modal'; | ||
| 13 | + import PasswordModal from '../component/PasswordModal.vue'; | ||
| 12 | 14 | ||
| 13 | const props = defineProps<{ | 15 | const props = defineProps<{ |
| 14 | config: ComponentPropsConfigType<typeof option>; | 16 | config: ComponentPropsConfigType<typeof option>; |
| @@ -31,11 +33,13 @@ | @@ -31,11 +33,13 @@ | ||
| 31 | deviceCode, | 33 | deviceCode, |
| 32 | customCommand, | 34 | customCommand, |
| 33 | } = option; | 35 | } = option; |
| 34 | - const { fontSize: persetFontSize } = persetOption || {}; | ||
| 35 | - const { fontSize } = componentInfo || {}; | 36 | + |
| 37 | + const { fontSize: persetFontSize, password: persetPassword } = persetOption || {}; | ||
| 38 | + const { fontSize, password } = componentInfo || {}; | ||
| 36 | return { | 39 | return { |
| 37 | attribute: attributeRename || attributeName || attribute, | 40 | attribute: attributeRename || attributeName || attribute, |
| 38 | fontSize: fontSize || persetFontSize || 14, | 41 | fontSize: fontSize || persetFontSize || 14, |
| 42 | + password: password || persetPassword, | ||
| 39 | extensionDesc: extensionDesc ? JSON.parse(extensionDesc) : {}, | 43 | extensionDesc: extensionDesc ? JSON.parse(extensionDesc) : {}, |
| 40 | commandType, | 44 | commandType, |
| 41 | codeType, | 45 | codeType, |
| @@ -45,7 +49,31 @@ | @@ -45,7 +49,31 @@ | ||
| 45 | }); | 49 | }); |
| 46 | 50 | ||
| 47 | const { sendCommand, loading } = useSendCommand(); | 51 | const { sendCommand, loading } = useSendCommand(); |
| 52 | + | ||
| 53 | + const handleSendCommand = async (data) => { | ||
| 54 | + const { control: event } = data || {}; | ||
| 55 | + const target = event.target as HTMLInputElement; | ||
| 56 | + const value = !target.checked; | ||
| 57 | + const { option } = props.config || {}; | ||
| 58 | + | ||
| 59 | + const { values, isModbusCommand, sendValue } = | ||
| 60 | + (await getSendValues(option, unref(getDesign), value)) || {}; | ||
| 61 | + | ||
| 62 | + const flag = await sendCommand(values, isModbusCommand ? sendValue : value, isModbusCommand); | ||
| 63 | + if (flag) currentValue.value = value; | ||
| 64 | + flag ? (currentValue.value = value) : (target.checked = !value); | ||
| 65 | + }; | ||
| 66 | + | ||
| 48 | const handleChange = async (event: Event) => { | 67 | const handleChange = async (event: Event) => { |
| 68 | + if (unref(getDesign).password) { | ||
| 69 | + const target = event.target as HTMLInputElement; | ||
| 70 | + const value = target.checked; | ||
| 71 | + target.checked = !value; | ||
| 72 | + currentValue.value = !value; | ||
| 73 | + openModal(true, { password: unref(getDesign).password, control: event }); | ||
| 74 | + return; | ||
| 75 | + } | ||
| 76 | + | ||
| 49 | const target = event.target as HTMLInputElement; | 77 | const target = event.target as HTMLInputElement; |
| 50 | const value = target.checked; | 78 | const value = target.checked; |
| 51 | const { option } = props.config || {}; | 79 | const { option } = props.config || {}; |
| @@ -66,6 +94,8 @@ | @@ -66,6 +94,8 @@ | ||
| 66 | }; | 94 | }; |
| 67 | 95 | ||
| 68 | useDataFetch(props, updateFn); | 96 | useDataFetch(props, updateFn); |
| 97 | + | ||
| 98 | + const [registerModal, { openModal }] = useModal(); | ||
| 69 | </script> | 99 | </script> |
| 70 | 100 | ||
| 71 | <template> | 101 | <template> |
| @@ -95,6 +125,8 @@ | @@ -95,6 +125,8 @@ | ||
| 95 | </div> | 125 | </div> |
| 96 | </Spin> | 126 | </Spin> |
| 97 | </main> | 127 | </main> |
| 128 | + | ||
| 129 | + <PasswordModal @register="registerModal" @success="handleSendCommand" /> | ||
| 98 | </main> | 130 | </main> |
| 99 | </template> | 131 | </template> |
| 100 | 132 |
| @@ -14,6 +14,7 @@ export const option: PublicPresetOptions = { | @@ -14,6 +14,7 @@ export const option: PublicPresetOptions = { | ||
| 14 | [ComponentConfigFieldEnum.ICON_COLOR]: '#377DFF', | 14 | [ComponentConfigFieldEnum.ICON_COLOR]: '#377DFF', |
| 15 | [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: false, | 15 | [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: false, |
| 16 | [ComponentConfigFieldEnum.FONT_SIZE]: 14, | 16 | [ComponentConfigFieldEnum.FONT_SIZE]: 14, |
| 17 | + [ComponentConfigFieldEnum.PASS_WORD]: '', | ||
| 17 | }; | 18 | }; |
| 18 | 19 | ||
| 19 | export default class Config extends PublicConfigClass implements CreateComponentType { | 20 | export default class Config extends PublicConfigClass implements CreateComponentType { |
| @@ -38,6 +38,12 @@ | @@ -38,6 +38,12 @@ | ||
| 38 | component: 'InputNumber', | 38 | component: 'InputNumber', |
| 39 | defaultValue: option.fontSize, | 39 | defaultValue: option.fontSize, |
| 40 | }, | 40 | }, |
| 41 | + { | ||
| 42 | + field: ComponentConfigFieldEnum.PASS_WORD, | ||
| 43 | + label: '操作密码', | ||
| 44 | + component: 'InputPassword', | ||
| 45 | + defaultValue: '', | ||
| 46 | + }, | ||
| 41 | ], | 47 | ], |
| 42 | showActionButtonGroup: false, | 48 | showActionButtonGroup: false, |
| 43 | labelWidth: 120, | 49 | labelWidth: 120, |
| @@ -11,6 +11,8 @@ | @@ -11,6 +11,8 @@ | ||
| 11 | import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type'; | 11 | import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type'; |
| 12 | import { useDataFetch } from '../../../hook/socket/useSocket'; | 12 | import { useDataFetch } from '../../../hook/socket/useSocket'; |
| 13 | import { getSendValues } from '../config'; | 13 | import { getSendValues } from '../config'; |
| 14 | + import { useModal } from '/@/components/Modal'; | ||
| 15 | + import PasswordModal from '../component/PasswordModal.vue'; | ||
| 14 | 16 | ||
| 15 | const props = defineProps<{ | 17 | const props = defineProps<{ |
| 16 | config: ComponentPropsConfigType<typeof option>; | 18 | config: ComponentPropsConfigType<typeof option>; |
| @@ -35,8 +37,9 @@ | @@ -35,8 +37,9 @@ | ||
| 35 | icon: presetIcon, | 37 | icon: presetIcon, |
| 36 | iconColor: presetIconColor, | 38 | iconColor: presetIconColor, |
| 37 | fontSize: persetFontSize, | 39 | fontSize: persetFontSize, |
| 40 | + password: persetPassword, | ||
| 38 | } = persetOption || {}; | 41 | } = persetOption || {}; |
| 39 | - const { icon, iconColor, fontSize } = componentInfo || {}; | 42 | + const { icon, iconColor, fontSize, password } = componentInfo || {}; |
| 40 | 43 | ||
| 41 | return { | 44 | return { |
| 42 | icon: icon ?? presetIcon, | 45 | icon: icon ?? presetIcon, |
| @@ -44,6 +47,7 @@ | @@ -44,6 +47,7 @@ | ||
| 44 | attribute: attributeRename || attributeName || attribute, | 47 | attribute: attributeRename || attributeName || attribute, |
| 45 | extensionDesc: extensionDesc ? JSON.parse(extensionDesc) : {}, | 48 | extensionDesc: extensionDesc ? JSON.parse(extensionDesc) : {}, |
| 46 | fontSize: fontSize || persetFontSize || 14, | 49 | fontSize: fontSize || persetFontSize || 14, |
| 50 | + password: password || persetPassword, | ||
| 47 | commandType, | 51 | commandType, |
| 48 | codeType, | 52 | codeType, |
| 49 | deviceCode, | 53 | deviceCode, |
| @@ -54,6 +58,11 @@ | @@ -54,6 +58,11 @@ | ||
| 54 | const { sendCommand, loading } = useSendCommand(); | 58 | const { sendCommand, loading } = useSendCommand(); |
| 55 | 59 | ||
| 56 | const handleChange = async () => { | 60 | const handleChange = async () => { |
| 61 | + if (unref(getDesign).password) { | ||
| 62 | + openModal(true, { password: unref(getDesign).password }); | ||
| 63 | + checked.value = !unref(checked); | ||
| 64 | + return; | ||
| 65 | + } | ||
| 57 | const { option } = props.config || {}; | 66 | const { option } = props.config || {}; |
| 58 | 67 | ||
| 59 | const { values, isModbusCommand, sendValue } = | 68 | const { values, isModbusCommand, sendValue } = |
| @@ -67,6 +76,21 @@ | @@ -67,6 +76,21 @@ | ||
| 67 | if (!flag) checked.value = !unref(checked); | 76 | if (!flag) checked.value = !unref(checked); |
| 68 | }; | 77 | }; |
| 69 | 78 | ||
| 79 | + const handleSendCommand = async () => { | ||
| 80 | + const { option } = props.config || {}; | ||
| 81 | + checked.value = !unref(checked); | ||
| 82 | + | ||
| 83 | + const { values, isModbusCommand, sendValue } = | ||
| 84 | + (await getSendValues(option, unref(getDesign), unref(checked))) || {}; | ||
| 85 | + | ||
| 86 | + const flag = await sendCommand( | ||
| 87 | + values, | ||
| 88 | + isModbusCommand ? sendValue : unref(checked), | ||
| 89 | + isModbusCommand | ||
| 90 | + ); | ||
| 91 | + if (!flag) checked.value = !unref(checked); | ||
| 92 | + }; | ||
| 93 | + | ||
| 70 | const updateFn: DataFetchUpdateFn = (message, attribute) => { | 94 | const updateFn: DataFetchUpdateFn = (message, attribute) => { |
| 71 | const { data = {} } = message; | 95 | const { data = {} } = message; |
| 72 | const [latest] = data[attribute] || []; | 96 | const [latest] = data[attribute] || []; |
| @@ -76,6 +100,8 @@ | @@ -76,6 +100,8 @@ | ||
| 76 | 100 | ||
| 77 | useDataFetch(props, updateFn); | 101 | useDataFetch(props, updateFn); |
| 78 | const { getScale, getRatio } = useComponentScale(props); | 102 | const { getScale, getRatio } = useComponentScale(props); |
| 103 | + | ||
| 104 | + const [registerModal, { openModal }] = useModal(); | ||
| 79 | </script> | 105 | </script> |
| 80 | 106 | ||
| 81 | <template> | 107 | <template> |
| @@ -105,5 +131,6 @@ | @@ -105,5 +131,6 @@ | ||
| 105 | @change="handleChange" | 131 | @change="handleChange" |
| 106 | /> | 132 | /> |
| 107 | </main> | 133 | </main> |
| 134 | + <PasswordModal @register="registerModal" @success="handleSendCommand" /> | ||
| 108 | </main> | 135 | </main> |
| 109 | </template> | 136 | </template> |
| @@ -12,6 +12,7 @@ import { ComponentConfigFieldEnum } from '../../../enum'; | @@ -12,6 +12,7 @@ import { ComponentConfigFieldEnum } from '../../../enum'; | ||
| 12 | export const option: PublicPresetOptions = { | 12 | export const option: PublicPresetOptions = { |
| 13 | [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: false, | 13 | [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: false, |
| 14 | [ComponentConfigFieldEnum.FONT_SIZE]: 14, | 14 | [ComponentConfigFieldEnum.FONT_SIZE]: 14, |
| 15 | + [ComponentConfigFieldEnum.PASS_WORD]: '', | ||
| 15 | // [ComponentConfigFieldEnum.FONT_COLOR]: '#000', | 16 | // [ComponentConfigFieldEnum.FONT_COLOR]: '#000', |
| 16 | }; | 17 | }; |
| 17 | 18 |
| @@ -24,6 +24,12 @@ | @@ -24,6 +24,12 @@ | ||
| 24 | component: 'InputNumber', | 24 | component: 'InputNumber', |
| 25 | defaultValue: option.fontSize, | 25 | defaultValue: option.fontSize, |
| 26 | }, | 26 | }, |
| 27 | + { | ||
| 28 | + field: ComponentConfigFieldEnum.PASS_WORD, | ||
| 29 | + label: '操作密码', | ||
| 30 | + component: 'InputPassword', | ||
| 31 | + defaultValue: '', | ||
| 32 | + }, | ||
| 27 | ], | 33 | ], |
| 28 | showActionButtonGroup: false, | 34 | showActionButtonGroup: false, |
| 29 | labelWidth: 120, | 35 | labelWidth: 120, |
| @@ -9,6 +9,8 @@ | @@ -9,6 +9,8 @@ | ||
| 9 | import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type'; | 9 | import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type'; |
| 10 | import { useDataFetch } from '../../../hook/socket/useSocket'; | 10 | import { useDataFetch } from '../../../hook/socket/useSocket'; |
| 11 | import { getSendValues } from '../config'; | 11 | import { getSendValues } from '../config'; |
| 12 | + import PasswordModal from '../component/PasswordModal.vue'; | ||
| 13 | + import { useModal } from '/@/components/Modal'; | ||
| 12 | 14 | ||
| 13 | const props = defineProps<{ | 15 | const props = defineProps<{ |
| 14 | config: ComponentPropsConfigType<typeof option>; | 16 | config: ComponentPropsConfigType<typeof option>; |
| @@ -31,11 +33,12 @@ | @@ -31,11 +33,12 @@ | ||
| 31 | customCommand, | 33 | customCommand, |
| 32 | componentInfo, | 34 | componentInfo, |
| 33 | } = option; | 35 | } = option; |
| 34 | - const { fontSize: persetFontSize } = persetOption || {}; | ||
| 35 | - const { fontSize } = componentInfo || {}; | 36 | + const { fontSize: persetFontSize, password: persetPassword } = persetOption || {}; |
| 37 | + const { fontSize, password } = componentInfo || {}; | ||
| 36 | return { | 38 | return { |
| 37 | attribute: attributeRename || attributeName || attribute, | 39 | attribute: attributeRename || attributeName || attribute, |
| 38 | extensionDesc: extensionDesc ? JSON.parse(extensionDesc) : {}, | 40 | extensionDesc: extensionDesc ? JSON.parse(extensionDesc) : {}, |
| 41 | + password: password || persetPassword, | ||
| 39 | commandType, | 42 | commandType, |
| 40 | codeType, | 43 | codeType, |
| 41 | deviceCode, | 44 | deviceCode, |
| @@ -46,6 +49,15 @@ | @@ -46,6 +49,15 @@ | ||
| 46 | 49 | ||
| 47 | const { loading, sendCommand } = useSendCommand(); | 50 | const { loading, sendCommand } = useSendCommand(); |
| 48 | const handleChange = async (event: Event) => { | 51 | const handleChange = async (event: Event) => { |
| 52 | + if (unref(getDesign).password) { | ||
| 53 | + const target = event.target as HTMLInputElement; | ||
| 54 | + const value = target.checked; | ||
| 55 | + target.checked = !value; | ||
| 56 | + currentValue.value = !value; | ||
| 57 | + openModal(true, { password: unref(getDesign).password, control: event }); | ||
| 58 | + return; | ||
| 59 | + } | ||
| 60 | + | ||
| 49 | const target = event.target as HTMLInputElement; | 61 | const target = event.target as HTMLInputElement; |
| 50 | const value = target.checked; | 62 | const value = target.checked; |
| 51 | const { option } = props.config || {}; | 63 | const { option } = props.config || {}; |
| @@ -57,6 +69,19 @@ | @@ -57,6 +69,19 @@ | ||
| 57 | flag ? (currentValue.value = value) : (target.checked = !value); | 69 | flag ? (currentValue.value = value) : (target.checked = !value); |
| 58 | }; | 70 | }; |
| 59 | 71 | ||
| 72 | + const handleSendCommand = async (data) => { | ||
| 73 | + const { control: event } = data || {}; | ||
| 74 | + const target = event.target as HTMLInputElement; | ||
| 75 | + const value = !target.checked; | ||
| 76 | + const { option } = props.config || {}; | ||
| 77 | + | ||
| 78 | + const { values, isModbusCommand, sendValue } = | ||
| 79 | + (await getSendValues(option, unref(getDesign), value)) || {}; | ||
| 80 | + | ||
| 81 | + const flag = await sendCommand(values, isModbusCommand ? sendValue : value, isModbusCommand); | ||
| 82 | + flag ? (currentValue.value = value) : (target.checked = !value); | ||
| 83 | + }; | ||
| 84 | + | ||
| 60 | const updateFn: DataFetchUpdateFn = (message, attribute) => { | 85 | const updateFn: DataFetchUpdateFn = (message, attribute) => { |
| 61 | const { data = {} } = message; | 86 | const { data = {} } = message; |
| 62 | const [latest] = data[attribute] || []; | 87 | const [latest] = data[attribute] || []; |
| @@ -65,6 +90,7 @@ | @@ -65,6 +90,7 @@ | ||
| 65 | }; | 90 | }; |
| 66 | 91 | ||
| 67 | useDataFetch(props, updateFn); | 92 | useDataFetch(props, updateFn); |
| 93 | + const [registerModal, { openModal }] = useModal(); | ||
| 68 | </script> | 94 | </script> |
| 69 | 95 | ||
| 70 | <template> | 96 | <template> |
| @@ -94,6 +120,8 @@ | @@ -94,6 +120,8 @@ | ||
| 94 | > | 120 | > |
| 95 | </Spin> | 121 | </Spin> |
| 96 | </main> | 122 | </main> |
| 123 | + | ||
| 124 | + <PasswordModal @register="registerModal" @success="handleSendCommand" /> | ||
| 97 | </main> | 125 | </main> |
| 98 | </template> | 126 | </template> |
| 99 | 127 |
| @@ -18,6 +18,7 @@ export const option: PublicPresetOptions = { | @@ -18,6 +18,7 @@ export const option: PublicPresetOptions = { | ||
| 18 | [ComponentConfigFieldEnum.MAX_NUMBER]: 100, | 18 | [ComponentConfigFieldEnum.MAX_NUMBER]: 100, |
| 19 | [ComponentConfigFieldEnum.FONT_SIZE]: 14, | 19 | [ComponentConfigFieldEnum.FONT_SIZE]: 14, |
| 20 | [ComponentConfigFieldEnum.VALUE_SIZE]: 20, | 20 | [ComponentConfigFieldEnum.VALUE_SIZE]: 20, |
| 21 | + [ComponentConfigFieldEnum.PASS_WORD]: '', | ||
| 21 | }; | 22 | }; |
| 22 | 23 | ||
| 23 | export default class Config extends PublicConfigClass implements CreateComponentType { | 24 | export default class Config extends PublicConfigClass implements CreateComponentType { |
| @@ -87,6 +87,13 @@ | @@ -87,6 +87,13 @@ | ||
| 87 | component: 'Checkbox', | 87 | component: 'Checkbox', |
| 88 | defaultValue: option.showDeviceName, | 88 | defaultValue: option.showDeviceName, |
| 89 | }, | 89 | }, |
| 90 | + | ||
| 91 | + { | ||
| 92 | + field: ComponentConfigFieldEnum.PASS_WORD, | ||
| 93 | + label: '操作密码', | ||
| 94 | + component: 'InputPassword', | ||
| 95 | + defaultValue: '', | ||
| 96 | + }, | ||
| 90 | ], | 97 | ], |
| 91 | showActionButtonGroup: false, | 98 | showActionButtonGroup: false, |
| 92 | labelWidth: 120, | 99 | labelWidth: 120, |
| @@ -13,6 +13,8 @@ | @@ -13,6 +13,8 @@ | ||
| 13 | import { useMessage } from '/@/hooks/web/useMessage'; | 13 | import { useMessage } from '/@/hooks/web/useMessage'; |
| 14 | import { SingleToHex } from '/@/views/device/list/cpns/tabs/ObjectModelCommandDeliveryModal/config'; | 14 | import { SingleToHex } from '/@/views/device/list/cpns/tabs/ObjectModelCommandDeliveryModal/config'; |
| 15 | import { genModbusCommand } from '/@/api/task'; | 15 | import { genModbusCommand } from '/@/api/task'; |
| 16 | + import PasswordModal from '../component/PasswordModal.vue'; | ||
| 17 | + import { useModal } from '/@/components/Modal'; | ||
| 16 | 18 | ||
| 17 | const props = defineProps<{ | 19 | const props = defineProps<{ |
| 18 | config: ComponentPropsConfigType<typeof option>; | 20 | config: ComponentPropsConfigType<typeof option>; |
| @@ -46,9 +48,18 @@ | @@ -46,9 +48,18 @@ | ||
| 46 | textColor: persetTextColor, | 48 | textColor: persetTextColor, |
| 47 | valueSize: persetValueSize, | 49 | valueSize: persetValueSize, |
| 48 | fontSize: persetFontSize, | 50 | fontSize: persetFontSize, |
| 51 | + password: persetPassword, | ||
| 49 | } = persetOption || {}; | 52 | } = persetOption || {}; |
| 50 | - const { controlBarColor, fontColor, minNumber, maxNumber, textColor, valueSize, fontSize } = | ||
| 51 | - componentInfo || {}; | 53 | + const { |
| 54 | + controlBarColor, | ||
| 55 | + password, | ||
| 56 | + fontColor, | ||
| 57 | + minNumber, | ||
| 58 | + maxNumber, | ||
| 59 | + textColor, | ||
| 60 | + valueSize, | ||
| 61 | + fontSize, | ||
| 62 | + } = componentInfo || {}; | ||
| 52 | return { | 63 | return { |
| 53 | attribute: attributeRename || attributeName || attribute, | 64 | attribute: attributeRename || attributeName || attribute, |
| 54 | controlBarColor: controlBarColor ?? persetControlBarColor, | 65 | controlBarColor: controlBarColor ?? persetControlBarColor, |
| @@ -63,6 +74,7 @@ | @@ -63,6 +74,7 @@ | ||
| 63 | textColor: textColor || persetTextColor, | 74 | textColor: textColor || persetTextColor, |
| 64 | valueSize: valueSize || persetValueSize || 20, | 75 | valueSize: valueSize || persetValueSize || 20, |
| 65 | fontSize: fontSize || persetFontSize || 14, | 76 | fontSize: fontSize || persetFontSize || 14, |
| 77 | + password: password || persetPassword, | ||
| 66 | }; | 78 | }; |
| 67 | }); | 79 | }); |
| 68 | 80 | ||
| @@ -82,6 +94,7 @@ | @@ -82,6 +94,7 @@ | ||
| 82 | const handleAfterChange = async () => { | 94 | const handleAfterChange = async () => { |
| 83 | unref(sliderEl)?.blur(); | 95 | unref(sliderEl)?.blur(); |
| 84 | if (unref(sliderValue) == unref(afterValue)) return; | 96 | if (unref(sliderValue) == unref(afterValue)) return; |
| 97 | + if (unref(getDesign).password) return; | ||
| 85 | sliderValue.value = afterValue.value; //这一步是因为当我们是点击不是拖动时候,会让值更新不了,所以需要赋值一次 | 98 | sliderValue.value = afterValue.value; //这一步是因为当我们是点击不是拖动时候,会让值更新不了,所以需要赋值一次 |
| 86 | }; | 99 | }; |
| 87 | 100 | ||
| @@ -169,6 +182,33 @@ | @@ -169,6 +182,33 @@ | ||
| 169 | }; | 182 | }; |
| 170 | 183 | ||
| 171 | const handleBlur = async () => { | 184 | const handleBlur = async () => { |
| 185 | + if (unref(getDesign).password) { | ||
| 186 | + sliderValue.value = oldSliderValue.value; | ||
| 187 | + openModal(true, { password: unref(getDesign).password, value: afterValue.value }); | ||
| 188 | + return; | ||
| 189 | + } | ||
| 190 | + | ||
| 191 | + if (unref(oldSliderValue) !== unref(sliderValue)) { | ||
| 192 | + const { codeType, customCommand } = unref(getDesign) || {}; | ||
| 193 | + const { transportType } = customCommand || {}; | ||
| 194 | + const sendValue = ref<any>(unref(sliderValue)); | ||
| 195 | + const isModbusCommand = ref<boolean>(false); | ||
| 196 | + if (transportType == 'TCP' && codeType == TaskTypeEnum.MODBUS_RTU) { | ||
| 197 | + sendValue.value = await getSendValue(unref(sliderValue)); | ||
| 198 | + isModbusCommand.value = true; | ||
| 199 | + } | ||
| 200 | + const flag = await sendCommand(props.config.option, unref(sendValue), unref(isModbusCommand)); | ||
| 201 | + flag | ||
| 202 | + ? ((sliderValue.value = unref(sliderValue)), | ||
| 203 | + (oldSliderValue.value = sliderValue.value), | ||
| 204 | + (index.value = 0)) | ||
| 205 | + : (sliderValue.value = unref(oldSliderValue)); | ||
| 206 | + } | ||
| 207 | + }; | ||
| 208 | + | ||
| 209 | + const handleSendCommand = async (data) => { | ||
| 210 | + const { value } = data || {}; | ||
| 211 | + sliderValue.value = value; | ||
| 172 | if (unref(oldSliderValue) !== unref(sliderValue)) { | 212 | if (unref(oldSliderValue) !== unref(sliderValue)) { |
| 173 | const { codeType, customCommand } = unref(getDesign) || {}; | 213 | const { codeType, customCommand } = unref(getDesign) || {}; |
| 174 | const { transportType } = customCommand || {}; | 214 | const { transportType } = customCommand || {}; |
| @@ -199,6 +239,7 @@ | @@ -199,6 +239,7 @@ | ||
| 199 | 239 | ||
| 200 | useDataFetch(props, updateFn); | 240 | useDataFetch(props, updateFn); |
| 201 | const { getScale, getRatio } = useComponentScale(props); | 241 | const { getScale, getRatio } = useComponentScale(props); |
| 242 | + const [registerModal, { openModal }] = useModal(); | ||
| 202 | </script> | 243 | </script> |
| 203 | 244 | ||
| 204 | <template> | 245 | <template> |
| @@ -244,6 +285,7 @@ | @@ -244,6 +285,7 @@ | ||
| 244 | </div> | 285 | </div> |
| 245 | </Spin> | 286 | </Spin> |
| 246 | </main> | 287 | </main> |
| 288 | + <PasswordModal @register="registerModal" @success="handleSendCommand" /> | ||
| 247 | </main> | 289 | </main> |
| 248 | </template> | 290 | </template> |
| 249 | <style lang="less" scoped> | 291 | <style lang="less" scoped> |
| @@ -15,6 +15,7 @@ export const option: PublicPresetOptions = { | @@ -15,6 +15,7 @@ export const option: PublicPresetOptions = { | ||
| 15 | [ComponentConfigFieldEnum.ICON_COLOR]: '#377DFF', | 15 | [ComponentConfigFieldEnum.ICON_COLOR]: '#377DFF', |
| 16 | [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: false, | 16 | [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: false, |
| 17 | [ComponentConfigFieldEnum.FONT_SIZE]: 14, | 17 | [ComponentConfigFieldEnum.FONT_SIZE]: 14, |
| 18 | + [ComponentConfigFieldEnum.PASS_WORD]: '', | ||
| 18 | }; | 19 | }; |
| 19 | 20 | ||
| 20 | export default class Config extends PublicConfigClass implements CreateComponentType { | 21 | export default class Config extends PublicConfigClass implements CreateComponentType { |
| @@ -38,6 +38,12 @@ | @@ -38,6 +38,12 @@ | ||
| 38 | component: 'Checkbox', | 38 | component: 'Checkbox', |
| 39 | defaultValue: option.showDeviceName, | 39 | defaultValue: option.showDeviceName, |
| 40 | }, | 40 | }, |
| 41 | + { | ||
| 42 | + field: ComponentConfigFieldEnum.PASS_WORD, | ||
| 43 | + label: '操作密码', | ||
| 44 | + component: 'InputPassword', | ||
| 45 | + defaultValue: '', | ||
| 46 | + }, | ||
| 41 | ], | 47 | ], |
| 42 | showActionButtonGroup: false, | 48 | showActionButtonGroup: false, |
| 43 | labelWidth: 120, | 49 | labelWidth: 120, |
| @@ -14,6 +14,8 @@ | @@ -14,6 +14,8 @@ | ||
| 14 | import { useReceiveValue } from '../../../hook/useReceiveValue'; | 14 | import { useReceiveValue } from '../../../hook/useReceiveValue'; |
| 15 | import { DataSource } from '/@/views/visual/palette/types'; | 15 | import { DataSource } from '/@/views/visual/palette/types'; |
| 16 | import { getSendValues, CommandTypeEnumLIst } from '../config'; | 16 | import { getSendValues, CommandTypeEnumLIst } from '../config'; |
| 17 | + import { useModal } from '/@/components/Modal'; | ||
| 18 | + import PasswordModal from '../component/PasswordModal.vue'; | ||
| 17 | 19 | ||
| 18 | const props = defineProps<{ | 20 | const props = defineProps<{ |
| 19 | config: ComponentPropsConfigType<typeof option>; | 21 | config: ComponentPropsConfigType<typeof option>; |
| @@ -53,10 +55,12 @@ | @@ -53,10 +55,12 @@ | ||
| 53 | icon: persetIcon, | 55 | icon: persetIcon, |
| 54 | iconColor: persetIconColor, | 56 | iconColor: persetIconColor, |
| 55 | fontSize: persetFontSize, | 57 | fontSize: persetFontSize, |
| 58 | + password: persetPassword, | ||
| 56 | } = persetOption || {}; | 59 | } = persetOption || {}; |
| 57 | return { | 60 | return { |
| 58 | dataSource: dataSource.map((item) => { | 61 | dataSource: dataSource.map((item) => { |
| 59 | - const { fontColor, icon, iconColor, unit, showDeviceName, fontSize } = item.componentInfo; | 62 | + const { fontColor, icon, iconColor, unit, showDeviceName, password, fontSize } = |
| 63 | + item.componentInfo; | ||
| 60 | const { | 64 | const { |
| 61 | attribute, | 65 | attribute, |
| 62 | attributeRename, | 66 | attributeRename, |
| @@ -86,13 +90,19 @@ | @@ -86,13 +90,19 @@ | ||
| 86 | deviceCode, | 90 | deviceCode, |
| 87 | customCommand, | 91 | customCommand, |
| 88 | fontSize: fontSize || persetFontSize || 14, | 92 | fontSize: fontSize || persetFontSize || 14, |
| 93 | + password: password || persetPassword, | ||
| 89 | }; | 94 | }; |
| 90 | }), | 95 | }), |
| 91 | }; | 96 | }; |
| 92 | }); | 97 | }); |
| 93 | 98 | ||
| 94 | const { loading, sendCommand } = useSendCommand(); | 99 | const { loading, sendCommand } = useSendCommand(); |
| 95 | - const handleChange = async (index: number, checked: Boolean) => { | 100 | + const handleChange = async (index: number, checked: Boolean, item: any) => { |
| 101 | + if (item.password) { | ||
| 102 | + openModal(true, { password: item.password, index, checked }); | ||
| 103 | + controlList.value[index].checked = !checked; | ||
| 104 | + return; | ||
| 105 | + } | ||
| 96 | const { heightPx, itemHeightRatio, itemWidthRatio, mode, widthPx, dataSource } = | 106 | const { heightPx, itemHeightRatio, itemWidthRatio, mode, widthPx, dataSource } = |
| 97 | props.config.option; | 107 | props.config.option; |
| 98 | const data = { | 108 | const data = { |
| @@ -120,6 +130,25 @@ | @@ -120,6 +130,25 @@ | ||
| 120 | }) | 130 | }) |
| 121 | : svgList | 131 | : svgList |
| 122 | ); | 132 | ); |
| 133 | + const handleSendCommand = async (modalData) => { | ||
| 134 | + const { index, checked } = modalData || {}; | ||
| 135 | + const { heightPx, itemHeightRatio, itemWidthRatio, mode, widthPx, dataSource } = | ||
| 136 | + props.config.option; | ||
| 137 | + const data = { | ||
| 138 | + ...dataSource?.[index], | ||
| 139 | + heightPx, | ||
| 140 | + itemHeightRatio, | ||
| 141 | + itemWidthRatio, | ||
| 142 | + mode, | ||
| 143 | + widthPx, | ||
| 144 | + } as DataSource; | ||
| 145 | + controlList.value[index].checked = checked; | ||
| 146 | + const { values, isModbusCommand, sendValue } = | ||
| 147 | + (await getSendValues(data, unref(getDesign).dataSource[index], checked)) || {}; | ||
| 148 | + | ||
| 149 | + const flag = await sendCommand(values, isModbusCommand ? sendValue : checked, isModbusCommand); | ||
| 150 | + if (!flag) controlList.value[index].checked = !checked; | ||
| 151 | + }; | ||
| 123 | 152 | ||
| 124 | const updateFn: MultipleDataFetchUpdateFn = async (message, deviceId, attribute) => { | 153 | const updateFn: MultipleDataFetchUpdateFn = async (message, deviceId, attribute) => { |
| 125 | forEachGroupMessage(message, deviceId, attribute, (attribute, value) => { | 154 | forEachGroupMessage(message, deviceId, attribute, (attribute, value) => { |
| @@ -133,6 +162,7 @@ | @@ -133,6 +162,7 @@ | ||
| 133 | 162 | ||
| 134 | useMultipleDataFetch(props, updateFn); | 163 | useMultipleDataFetch(props, updateFn); |
| 135 | const { getRatio } = useComponentScale(props); | 164 | const { getRatio } = useComponentScale(props); |
| 165 | + const [registerModal, { openModal }] = useModal(); | ||
| 136 | </script> | 166 | </script> |
| 137 | 167 | ||
| 138 | <template> | 168 | <template> |
| @@ -166,9 +196,10 @@ | @@ -166,9 +196,10 @@ | ||
| 166 | <Switch | 196 | <Switch |
| 167 | v-model:checked="item.checked" | 197 | v-model:checked="item.checked" |
| 168 | :loading="loading" | 198 | :loading="loading" |
| 169 | - @change="handleChange(index, item.checked)" | 199 | + @change="handleChange(index, item.checked, item)" |
| 170 | :style="{ transform: `scale(${getRatio || 1})` }" | 200 | :style="{ transform: `scale(${getRatio || 1})` }" |
| 171 | /> | 201 | /> |
| 172 | </div> | 202 | </div> |
| 203 | + <PasswordModal @register="registerModal" @success="handleSendCommand" /> | ||
| 173 | </main> | 204 | </main> |
| 174 | </template> | 205 | </template> |
| 1 | +<template> | ||
| 2 | + <div> | ||
| 3 | + <BasicModal | ||
| 4 | + destroyOnClose | ||
| 5 | + v-bind="$attrs" | ||
| 6 | + width="30rem" | ||
| 7 | + :height="50" | ||
| 8 | + :minHeight="50" | ||
| 9 | + @register="register" | ||
| 10 | + title="操作密码" | ||
| 11 | + @ok="handleSuccess" | ||
| 12 | + @cancel="handleClose" | ||
| 13 | + > | ||
| 14 | + <div> | ||
| 15 | + <BasicForm @register="registerForm" /> | ||
| 16 | + </div> | ||
| 17 | + </BasicModal> | ||
| 18 | + </div> | ||
| 19 | +</template> | ||
| 20 | +<script setup lang="ts"> | ||
| 21 | + import { BasicModal, useModalInner } from '/@/components/Modal'; | ||
| 22 | + import { useForm, BasicForm } from '/@/components/Form'; | ||
| 23 | + import { formSchema } from './config'; | ||
| 24 | + import { useMessage } from '/@/hooks/web/useMessage'; | ||
| 25 | + import { ref, unref } from 'vue'; | ||
| 26 | + | ||
| 27 | + const emit = defineEmits(['register', 'success', 'cancel']); | ||
| 28 | + | ||
| 29 | + const persetData = ref<{ [key: string]: string | number }>({}); | ||
| 30 | + | ||
| 31 | + const { createMessage } = useMessage(); | ||
| 32 | + | ||
| 33 | + const [registerForm, { getFieldsValue, validate }] = useForm({ | ||
| 34 | + labelWidth: 70, | ||
| 35 | + schemas: formSchema, | ||
| 36 | + showActionButtonGroup: false, | ||
| 37 | + }); | ||
| 38 | + | ||
| 39 | + const [register, { setModalProps, closeModal }] = useModalInner(async (data) => { | ||
| 40 | + setModalProps({ loading: true }); | ||
| 41 | + persetData.value = data; | ||
| 42 | + setModalProps({ loading: false }); | ||
| 43 | + }); | ||
| 44 | + | ||
| 45 | + const handleClose = () => { | ||
| 46 | + emit('cancel'); | ||
| 47 | + closeModal(); | ||
| 48 | + }; | ||
| 49 | + | ||
| 50 | + const handleSuccess = async () => { | ||
| 51 | + await validate(); | ||
| 52 | + const { password: passwordField } = getFieldsValue(); | ||
| 53 | + if (unref(persetData).password != passwordField) { | ||
| 54 | + createMessage.warning('操作密码不正确'); | ||
| 55 | + return; | ||
| 56 | + } | ||
| 57 | + emit('success', unref(persetData)); | ||
| 58 | + closeModal(); | ||
| 59 | + }; | ||
| 60 | +</script> | ||
| 61 | +<style lang="less" scoped></style> |
| 1 | +import { FormSchema } from '/@/components/Form'; | ||
| 2 | + | ||
| 3 | +export const formSchema: FormSchema[] = [ | ||
| 4 | + { | ||
| 5 | + field: 'password', | ||
| 6 | + label: '操作密码', | ||
| 7 | + colProps: { span: 16 }, | ||
| 8 | + component: 'InputPassword', | ||
| 9 | + required: true, | ||
| 10 | + componentProps: { | ||
| 11 | + placeholder: '请输入操作密码', | ||
| 12 | + max: 120, | ||
| 13 | + }, | ||
| 14 | + }, | ||
| 15 | +]; |
| @@ -15,6 +15,7 @@ import { TransportTypeEnum } from '/@/views/device/profiles/components/Transport | @@ -15,6 +15,7 @@ import { TransportTypeEnum } from '/@/views/device/profiles/components/Transport | ||
| 15 | import { CommandTypeEnum } from '/@/views/rule/linkedge/config/config.data'; | 15 | import { CommandTypeEnum } from '/@/views/rule/linkedge/config/config.data'; |
| 16 | import { DataActionModeEnum } from '/@/enums/toolEnum'; | 16 | import { DataActionModeEnum } from '/@/enums/toolEnum'; |
| 17 | import { TaskTypeEnum } from '/@/views/task/center/config'; | 17 | import { TaskTypeEnum } from '/@/views/task/center/config'; |
| 18 | +import { createPickerSearch } from '/@/utils/pickerSearch'; | ||
| 18 | 19 | ||
| 19 | useComponentRegister('OrgTreeSelect', OrgTreeSelect); | 20 | useComponentRegister('OrgTreeSelect', OrgTreeSelect); |
| 20 | 21 | ||
| @@ -247,6 +248,7 @@ export const commonDataSourceSchemas = (): FormSchema[] => { | @@ -247,6 +248,7 @@ export const commonDataSourceSchemas = (): FormSchema[] => { | ||
| 247 | }, | 248 | }, |
| 248 | placeholder: '请选择设备', | 249 | placeholder: '请选择设备', |
| 249 | getPopupContainer: () => document.body, | 250 | getPopupContainer: () => document.body, |
| 251 | + ...createPickerSearch(), | ||
| 250 | }; | 252 | }; |
| 251 | }, | 253 | }, |
| 252 | }, | 254 | }, |
| @@ -387,6 +389,7 @@ export const commonDataSourceSchemas = (): FormSchema[] => { | @@ -387,6 +389,7 @@ export const commonDataSourceSchemas = (): FormSchema[] => { | ||
| 387 | [DataSourceField.EXTENSION_DESC]: value ? JSON.stringify(option.extensionDesc) : '', | 389 | [DataSourceField.EXTENSION_DESC]: value ? JSON.stringify(option.extensionDesc) : '', |
| 388 | }); | 390 | }); |
| 389 | }, | 391 | }, |
| 392 | + ...createPickerSearch(), | ||
| 390 | }; | 393 | }; |
| 391 | }, | 394 | }, |
| 392 | }, | 395 | }, |
| @@ -35,4 +35,5 @@ export enum ComponentConfigFieldEnum { | @@ -35,4 +35,5 @@ export enum ComponentConfigFieldEnum { | ||
| 35 | CLOSE_COLOR = 'closeColor', | 35 | CLOSE_COLOR = 'closeColor', |
| 36 | MIN_NUMBER = 'minNumber', | 36 | MIN_NUMBER = 'minNumber', |
| 37 | MAX_NUMBER = 'maxNumber', | 37 | MAX_NUMBER = 'maxNumber', |
| 38 | + PASS_WORD = 'password', //操作密码 | ||
| 38 | } | 39 | } |