Commit 1b471b784586e802a1a8f662567e6544699f0cdf
Merge branch 'main_dev' of http://git.yunteng.com/yunteng/thingskit-front into f…
…ix/board-style-issues
Showing
39 changed files
with
263 additions
and
106 deletions
... | ... | @@ -85,7 +85,7 @@ interface TrendParamsType { |
85 | 85 | } |
86 | 86 | // 获取租户趋势或者客户趋势数据 |
87 | 87 | export const getTrendData = (params: TrendParamsType) => { |
88 | - return defHttp.get({ | |
88 | + return defHttp.get<Record<'date' | 'value', string>[]>({ | |
89 | 89 | url: HomeEnum.TrendAPI, |
90 | 90 | params, |
91 | 91 | }); | ... | ... |
... | ... | @@ -30,6 +30,8 @@ enum DeviceManagerApi { |
30 | 30 | |
31 | 31 | ALARM_BATCH_ACK = '/alarm/batch/ack', |
32 | 32 | |
33 | + ALARM_BATCH_CLEAR = '/alarm/batch/clear', | |
34 | + | |
33 | 35 | DEVICE_CREDENTIALS = '/device/credentials', |
34 | 36 | |
35 | 37 | COMMAND_ISSUANCE = '/rpc', |
... | ... | @@ -358,3 +360,13 @@ export const doBatchAckAlarm = (ids: string[]) => { |
358 | 360 | { joinPrefix: false } |
359 | 361 | ); |
360 | 362 | }; |
363 | + | |
364 | +export const doBatchClearAlarm = (ids: string[]) => { | |
365 | + return defHttp.post( | |
366 | + { | |
367 | + url: DeviceManagerApi.ALARM_BATCH_CLEAR, | |
368 | + data: { alarmIds: ids }, | |
369 | + }, | |
370 | + { joinPrefix: false } | |
371 | + ); | |
372 | +}; | ... | ... |
... | ... | @@ -9,7 +9,7 @@ |
9 | 9 | import { useMessage } from '/@/hooks/web/useMessage'; |
10 | 10 | import { computed, ref, unref } from 'vue'; |
11 | 11 | import { cloneDeep } from 'lodash-es'; |
12 | - import { isFunction, isNumber, isObject } from '/@/utils/is'; | |
12 | + import { isFunction, isNumber, isObject, isString } from '/@/utils/is'; | |
13 | 13 | import { useDesign } from '/@/hooks/web/useDesign'; |
14 | 14 | |
15 | 15 | export interface FileItem { |
... | ... | @@ -59,10 +59,19 @@ |
59 | 59 | ); |
60 | 60 | |
61 | 61 | const handleBeforeUpload = (file: File, fileList: File[]) => { |
62 | - const { beforeUpload } = props; | |
62 | + const { beforeUpload, accept } = props; | |
63 | 63 | |
64 | 64 | if (beforeUpload && isFunction(beforeUpload)) return beforeUpload?.(file, fileList); |
65 | 65 | |
66 | + if (accept && isString(accept)) { | |
67 | + const limitFileSuffix = accept.split(','); | |
68 | + | |
69 | + if (limitFileSuffix.length && !limitFileSuffix.some((suffix) => file.name.includes(suffix))) { | |
70 | + createMessage.warning(`允许上传的文件类型包括${accept}`); | |
71 | + return false; | |
72 | + } | |
73 | + } | |
74 | + | |
66 | 75 | if (file.size > props.maxSize) { |
67 | 76 | createMessage.warning(`文件大小超过${Math.floor(props.maxSize / 1024 / 1024)}mb`); |
68 | 77 | return false; | ... | ... |
... | ... | @@ -2,7 +2,7 @@ import { RouteLocationNormalizedLoaded } from 'vue-router'; |
2 | 2 | |
3 | 3 | const menuMap = new Map(); |
4 | 4 | |
5 | -menuMap.set('/visual/board/detail/:boardId/:boardName?', '/visual/board'); | |
5 | +menuMap.set('/visual/board/detail/:boardId/:boardName/:organizationId?', '/visual/board'); | |
6 | 6 | menuMap.set('/rule/chain/:id', '/rule/chain'); |
7 | 7 | |
8 | 8 | export const useMenuActiveFix = (route: RouteLocationNormalizedLoaded) => { | ... | ... |
... | ... | @@ -37,7 +37,7 @@ |
37 | 37 | </a-button> |
38 | 38 | </template> |
39 | 39 | <template #status="{ record }"> |
40 | - <Authority value="api:yt:alarm:profile:status"> | |
40 | + <Authority value="api:yt:alarm:profile:update"> | |
41 | 41 | <Switch |
42 | 42 | :checked="record.status === 1" |
43 | 43 | :loading="record.pendingStatus" |
... | ... | @@ -47,7 +47,7 @@ |
47 | 47 | /> |
48 | 48 | </Authority> |
49 | 49 | <Tag |
50 | - v-if="!hasPermission('api:yt:alarm:profile:status')" | |
50 | + v-if="!hasPermission('api:yt:alarm:profile:update')" | |
51 | 51 | :color="record.status ? 'green' : 'red'" |
52 | 52 | > |
53 | 53 | {{ record.status ? '启用' : '禁用' }} | ... | ... |
... | ... | @@ -19,7 +19,30 @@ |
19 | 19 | </a-button> |
20 | 20 | </template> |
21 | 21 | <template #toolbar> |
22 | - <Button @click="handleBatchAck" type="primary" :disabled="getCanBatchAck">批量处理</Button> | |
22 | + <Tooltip> | |
23 | + <template #title> | |
24 | + <div>激活未确认: 可以处理,清除</div> | |
25 | + <div>激活已确认: 只可清除,已经处理</div> | |
26 | + <div>清除未确认: 只可处理,已经清除</div> | |
27 | + <div>清除已确认: 不需要做处理和清除</div> | |
28 | + </template> | |
29 | + <Button @click="handleBatchClear" type="primary" :disabled="getCanBatchClear"> | |
30 | + <QuestionCircleOutlined class="cursor-pointer" /> | |
31 | + <span>批量清除</span> | |
32 | + </Button> | |
33 | + </Tooltip> | |
34 | + <Tooltip> | |
35 | + <template #title> | |
36 | + <div>激活未确认: 可以处理,清除</div> | |
37 | + <div>激活已确认: 只可清除,已经处理</div> | |
38 | + <div>清除未确认: 只可处理,已经清除</div> | |
39 | + <div>清除已确认: 不需要做处理和清除</div> | |
40 | + </template> | |
41 | + <Button @click="handleBatchAck" type="primary" :disabled="getCanBatchAck"> | |
42 | + <QuestionCircleOutlined class="cursor-pointer" /> | |
43 | + <span>批量处理</span> | |
44 | + </Button> | |
45 | + </Tooltip> | |
23 | 46 | </template> |
24 | 47 | </BasicTable> |
25 | 48 | <AlarmDetailDrawer @register="registerDetailDrawer" @success="handleSuccess" /> |
... | ... | @@ -29,10 +52,10 @@ |
29 | 52 | import { defineComponent, nextTick, h, computed } from 'vue'; |
30 | 53 | import { BasicTable, useTable, TableAction } from '/@/components/Table'; |
31 | 54 | import { alarmColumns, alarmSearchSchemas } from './config/detail.config'; |
32 | - import { doBatchAckAlarm, getDeviceAlarm } from '/@/api/device/deviceManager'; | |
55 | + import { doBatchAckAlarm, doBatchClearAlarm, getDeviceAlarm } from '/@/api/device/deviceManager'; | |
33 | 56 | import { useDrawer } from '/@/components/Drawer'; |
34 | 57 | import AlarmDetailDrawer from './cpns/AlarmDetailDrawer.vue'; |
35 | - import { Modal, Button } from 'ant-design-vue'; | |
58 | + import { Modal, Button, Tooltip } from 'ant-design-vue'; | |
36 | 59 | import { JsonPreview } from '/@/components/CodeEditor'; |
37 | 60 | import { getDeviceDetail } from '/@/api/device/deviceManager'; |
38 | 61 | import { getAttribute } from '/@/api/ruleengine/ruleengineApi'; |
... | ... | @@ -44,6 +67,7 @@ |
44 | 67 | import { AlarmLogItem } from '/@/api/device/model/deviceConfigModel'; |
45 | 68 | import { AlarmStatus } from '/@/enums/alarmEnum'; |
46 | 69 | import { useMessage } from '/@/hooks/web/useMessage'; |
70 | + import { QuestionCircleOutlined } from '@ant-design/icons-vue'; | |
47 | 71 | |
48 | 72 | export default defineComponent({ |
49 | 73 | name: 'AlarmCenter', |
... | ... | @@ -52,6 +76,8 @@ |
52 | 76 | BasicTable, |
53 | 77 | TableAction, |
54 | 78 | AlarmDetailDrawer, |
79 | + QuestionCircleOutlined, | |
80 | + Tooltip, | |
55 | 81 | }, |
56 | 82 | |
57 | 83 | setup() { |
... | ... | @@ -60,6 +86,7 @@ |
60 | 86 | title: '告警记录列表', |
61 | 87 | api: getDeviceAlarm, |
62 | 88 | columns: alarmColumns, |
89 | + rowKey: 'id', | |
63 | 90 | useSearchForm: true, |
64 | 91 | formConfig: { |
65 | 92 | labelWidth: 120, |
... | ... | @@ -168,9 +195,30 @@ |
168 | 195 | }; |
169 | 196 | }; |
170 | 197 | |
198 | + const getCanBatchClear = computed(() => { | |
199 | + const rowSelection = getRowSelection(); | |
200 | + const getRows: AlarmLogItem[] = getSelectRows(); | |
201 | + | |
202 | + return ( | |
203 | + !rowSelection.selectedRowKeys?.length || | |
204 | + getRows.some( | |
205 | + (item) => | |
206 | + item.status === AlarmStatus.CLEARED_ACK || item.status === AlarmStatus.CLEARED_UN_ACK | |
207 | + ) | |
208 | + ); | |
209 | + }); | |
210 | + | |
171 | 211 | const getCanBatchAck = computed(() => { |
172 | 212 | const rowSelection = getRowSelection(); |
173 | - return !rowSelection.selectedRowKeys?.length; | |
213 | + const getRows: AlarmLogItem[] = getSelectRows(); | |
214 | + | |
215 | + return ( | |
216 | + !rowSelection.selectedRowKeys?.length || | |
217 | + getRows.some( | |
218 | + (item) => | |
219 | + item.status === AlarmStatus.CLEARED_ACK || item.status === AlarmStatus.ACTIVE_ACK | |
220 | + ) | |
221 | + ); | |
174 | 222 | }); |
175 | 223 | |
176 | 224 | const { createMessage } = useMessage(); |
... | ... | @@ -183,6 +231,15 @@ |
183 | 231 | reload(); |
184 | 232 | }; |
185 | 233 | |
234 | + const handleBatchClear = async () => { | |
235 | + const ids = getSelectRows<AlarmLogItem>().map((item) => item.id); | |
236 | + if (!ids.length) return; | |
237 | + await doBatchClearAlarm(ids); | |
238 | + createMessage.success('操作成功'); | |
239 | + clearSelectedRowKeys(); | |
240 | + reload(); | |
241 | + }; | |
242 | + | |
186 | 243 | return { |
187 | 244 | registerTable, |
188 | 245 | registerDetailDrawer, |
... | ... | @@ -190,7 +247,9 @@ |
190 | 247 | handleSuccess, |
191 | 248 | handleViewAlarmDetails, |
192 | 249 | handleBatchAck, |
250 | + handleBatchClear, | |
193 | 251 | getCanBatchAck, |
252 | + getCanBatchClear, | |
194 | 253 | }; |
195 | 254 | }, |
196 | 255 | }); | ... | ... |
... | ... | @@ -136,13 +136,19 @@ |
136 | 136 | const handlePreview = (record: ConfigurationCenterItemsModal) => { |
137 | 137 | if (!unref(getPreviewFlag)) return; |
138 | 138 | window.open( |
139 | - `${configurationPrefix}/${isDev ? '?dev=1&' : '?'}configurationId=${record!.id}&lightbox=1` | |
139 | + `${configurationPrefix}/${isDev ? '?dev=1&' : '?'}configurationId=${ | |
140 | + record!.id | |
141 | + }&lightbox=1&organizationId=${record.organizationId}` | |
140 | 142 | ); |
141 | 143 | }; |
142 | 144 | |
143 | 145 | const handleDesign = (record: ConfigurationCenterItemsModal) => { |
144 | 146 | if (!unref(getDesignFlag)) return; |
145 | - window.open(`${configurationPrefix}/${isDev ? '?dev=1&' : '?'}configurationId=${record!.id}`); | |
147 | + window.open( | |
148 | + `${configurationPrefix}/${isDev ? '?dev=1&' : '?'}configurationId=${ | |
149 | + record!.id | |
150 | + }&organizationId=${record.organizationId}` | |
151 | + ); | |
146 | 152 | }; |
147 | 153 | |
148 | 154 | const handleDelete = async (record: ConfigurationCenterItemsModal) => { |
... | ... | @@ -165,6 +171,7 @@ |
165 | 171 | searchParams.set('configurationId', record.id); |
166 | 172 | searchParams.set('publicId', record.publicId || ''); |
167 | 173 | searchParams.set('lightbox', '1'); |
174 | + searchParams.set('organizationId', record!.organizationId || ''); | |
168 | 175 | return `${origin}${configurationPrefix}/?${searchParams.toString()}`; |
169 | 176 | }; |
170 | 177 | ... | ... |
... | ... | @@ -132,6 +132,9 @@ |
132 | 132 | @calendarChange="handleCalendarChange" |
133 | 133 | size="small" |
134 | 134 | v-model:value="customerDateValue" |
135 | + :showTime="{ | |
136 | + defaultValue: [dateUtil('00:00:00', 'HH:mm:ss'), dateUtil('23:59:59', 'HH:mm:ss')], | |
137 | + }" | |
135 | 138 | > |
136 | 139 | <Button |
137 | 140 | type="link" |
... | ... | @@ -165,7 +168,7 @@ |
165 | 168 | import { useWebSocket } from '@vueuse/core'; |
166 | 169 | import { getAuthCache } from '/@/utils/auth'; |
167 | 170 | import { JWT_TOKEN_KEY } from '/@/enums/cacheEnum'; |
168 | - import { formatToDateTime } from '/@/utils/dateUtil'; | |
171 | + import { dateUtil, formatToDateTime } from '/@/utils/dateUtil'; | |
169 | 172 | import CustomerTrend from './CustomerTrend.vue'; |
170 | 173 | // import TenantTrend from './TenantTrend.vue'; |
171 | 174 | import CustomerAlarmMessage from './CustomerAlarmMessage.vue'; |
... | ... | @@ -530,6 +533,7 @@ |
530 | 533 | }; |
531 | 534 | |
532 | 535 | const handleDisableDate = (current: moment.Moment) => { |
536 | + if (!current) return true; | |
533 | 537 | if (!unref(customerDateValue) || unref(customerDateValue).length === 0) { |
534 | 538 | return false; |
535 | 539 | } | ... | ... |
... | ... | @@ -117,6 +117,9 @@ |
117 | 117 | @calendarChange="handleCalendarChange" |
118 | 118 | :disabledDate="handleDisableDate" |
119 | 119 | v-model:value="tenantDateValue" |
120 | + :showTime="{ | |
121 | + defaultValue: [dateUtil('00:00:00', 'HH:mm:ss'), dateUtil('23:59:59', 'HH:mm:ss')], | |
122 | + }" | |
120 | 123 | > |
121 | 124 | <Button |
122 | 125 | type="link" |
... | ... | @@ -175,7 +178,7 @@ |
175 | 178 | import { useWebSocket } from '@vueuse/core'; |
176 | 179 | import { getAuthCache } from '/@/utils/auth'; |
177 | 180 | import { JWT_TOKEN_KEY } from '/@/enums/cacheEnum'; |
178 | - import { formatToDateTime } from '/@/utils/dateUtil'; | |
181 | + import { dateUtil, formatToDateTime } from '/@/utils/dateUtil'; | |
179 | 182 | // import CustomerTrend from './CustomerTrend.vue'; |
180 | 183 | import TenantTrend from './TenantTrend.vue'; |
181 | 184 | import CustomerAlarmMessage from './CustomerAlarmMessage.vue'; |
... | ... | @@ -548,6 +551,7 @@ |
548 | 551 | }; |
549 | 552 | |
550 | 553 | const handleDisableDate = (current: moment.Moment) => { |
554 | + if (!current) return true; | |
551 | 555 | if (!unref(tenantDateValue) || unref(tenantDateValue).length === 0) { |
552 | 556 | return false; |
553 | 557 | } | ... | ... |
1 | -import { dateUtil, formatToDateTime } from '/@/utils/dateUtil'; | |
2 | -import { ref } from 'vue'; | |
1 | +import { dateUtil } from '/@/utils/dateUtil'; | |
2 | +import { Ref, ref } from 'vue'; | |
3 | 3 | import { getTrendData } from '/@/api/dashboard'; |
4 | 4 | import { RangePickerValue } from 'ant-design-vue/lib/date-picker/interface'; |
5 | +import moment from 'moment'; | |
5 | 6 | |
6 | 7 | export enum ShortcutQueryKeyEnum { |
7 | 8 | LATEST_1_MONTH = 'LATEST_1_MONTH', |
... | ... | @@ -42,8 +43,8 @@ export function getDateByShortcutQueryKey(value: ShortcutQueryKeyEnum) { |
42 | 43 | export function useDate() { |
43 | 44 | const tenantDateValue = ref([]); |
44 | 45 | const customerDateValue = ref<RangePickerValue>([]); |
45 | - const tenantTrendList = ref([]); | |
46 | - const customerTrendList = ref([]); | |
46 | + const tenantTrendList = ref<[string, string][]>([]); | |
47 | + const customerTrendList = ref<[string, string][]>([]); | |
47 | 48 | const activeTenantIndex = ref(0); |
48 | 49 | const activeCustomerIndex = ref(0); |
49 | 50 | const TenantOrCustomerDateList = ref([ |
... | ... | @@ -80,52 +81,39 @@ export function useDate() { |
80 | 81 | } |
81 | 82 | |
82 | 83 | // 获取选中的时间范围内的数据 |
83 | - async function getDateData(startTs, endTs, trend: 'CUSTOMER_TREND' | 'TENANT_TREND', list) { | |
84 | - // 计算时间间隔 | |
85 | - function computedInterval(startTs: number, endTs: number) { | |
86 | - /** | |
87 | - * 选择的时间间隔 | |
88 | - * <=1 2h | |
89 | - * <=30 1day | |
90 | - * >30<90 2day | |
91 | - * >90 1month | |
92 | - */ | |
93 | - let interval = 86400000; | |
94 | - if (endTs - startTs <= 86400000) { | |
95 | - interval = 7200000; | |
96 | - } else if (endTs - startTs <= 2592000000) { | |
97 | - interval = 86400000; | |
98 | - } else if (endTs - startTs > 2592000000 && endTs - startTs < 7776000000) { | |
99 | - interval = 172800000; | |
100 | - } else if (endTs - startTs > 7776000000) { | |
101 | - interval = 2592000000; | |
102 | - } | |
103 | - return interval; | |
104 | - } | |
105 | - startTs = parseInt(formatToDateTime(startTs, 'x')) - 86400000; | |
106 | - endTs = parseInt(formatToDateTime(endTs, 'x')); | |
84 | + async function getDateData( | |
85 | + startTs: moment.Moment, | |
86 | + endTs: moment.Moment, | |
87 | + trend: 'CUSTOMER_TREND' | 'TENANT_TREND', | |
88 | + list: Ref<[string, string][]> | |
89 | + ) { | |
107 | 90 | const res = await getTrendData({ |
108 | - startTs, | |
109 | - endTs, | |
110 | - interval: computedInterval(startTs, endTs), | |
91 | + startTs: startTs.valueOf(), | |
92 | + endTs: endTs.valueOf(), | |
93 | + interval: 24 * 60 * 60 * 1000, | |
111 | 94 | trend, |
112 | 95 | }); |
113 | - list.value = res.map((item) => [item.ts, item.value]); | |
96 | + list.value = res.map((item) => [item.date, item.value]); | |
114 | 97 | } |
115 | 98 | |
116 | 99 | // 租户选择日期 |
117 | - function onDateTenantChange(_, dateString) { | |
118 | - if (!_.length) return; | |
119 | - const [startTs, endTs] = dateString; | |
100 | + function onDateTenantChange(range: RangePickerValue) { | |
101 | + if (!range.length) return; | |
102 | + const [startTs, endTs] = range; | |
120 | 103 | activeTenantIndex.value = -1; |
121 | - getDateData(startTs, endTs, 'TENANT_TREND', tenantTrendList); | |
104 | + getDateData(startTs as moment.Moment, endTs as moment.Moment, 'TENANT_TREND', tenantTrendList); | |
122 | 105 | } |
123 | 106 | // 客户趋势选择日期 |
124 | - function onDateCustomerChange(_, dateString) { | |
125 | - if (!_.length) return; | |
126 | - const [startTs, endTs] = dateString; | |
107 | + function onDateCustomerChange(range: RangePickerValue) { | |
108 | + if (!range.length) return; | |
109 | + const [startTs, endTs] = range; | |
127 | 110 | activeCustomerIndex.value = -1; |
128 | - getDateData(startTs, endTs, 'CUSTOMER_TREND', customerTrendList); | |
111 | + getDateData( | |
112 | + startTs as moment.Moment, | |
113 | + endTs as moment.Moment, | |
114 | + 'CUSTOMER_TREND', | |
115 | + customerTrendList | |
116 | + ); | |
129 | 117 | } |
130 | 118 | return { |
131 | 119 | tenantDateValue, | ... | ... |
... | ... | @@ -124,12 +124,16 @@ |
124 | 124 | const { largeDesignerPrefix } = useGlobSetting(); |
125 | 125 | |
126 | 126 | const handlePreview = (record: BigScreenCenterItemsModel) => { |
127 | - window.open(`${largeDesignerPrefix}/#/chart/preview/${record.id}`); | |
127 | + window.open( | |
128 | + `${largeDesignerPrefix}/#/chart/preview/${record.id}?organizationId=${record.organizationId}` | |
129 | + ); | |
128 | 130 | }; |
129 | 131 | |
130 | 132 | const handleDesign = (record: BigScreenCenterItemsModel) => { |
131 | 133 | if (record.state === 1) return; |
132 | - window.open(`${largeDesignerPrefix}/#/chart/home/${record.id}`); | |
134 | + window.open( | |
135 | + `${largeDesignerPrefix}/#/chart/home/${record.id}?organizationId=${record.organizationId}` | |
136 | + ); | |
133 | 137 | }; |
134 | 138 | |
135 | 139 | const handleDelete = async (record: BigScreenCenterItemsModel) => { | ... | ... |
... | ... | @@ -10,7 +10,7 @@ |
10 | 10 | </div> |
11 | 11 | </template> |
12 | 12 | <script lang="ts"> |
13 | - import { defineComponent, ref } from 'vue'; | |
13 | + import { defineComponent, nextTick, ref } from 'vue'; | |
14 | 14 | import { BasicForm, useForm } from '/@/components/Form'; |
15 | 15 | import { CommandFieldsEnum, CommandSchemas, CommandType, ValueType } from '../../config/data'; |
16 | 16 | import { commandIssuanceApi } from '/@/api/device/deviceManager'; |
... | ... | @@ -35,7 +35,7 @@ |
35 | 35 | const { createMessage } = useMessage(); |
36 | 36 | const loading = ref(false); |
37 | 37 | |
38 | - const [registerForm, { getFieldsValue, validate, resetFields }] = useForm({ | |
38 | + const [registerForm, { getFieldsValue, validate, resetFields, clearValidate }] = useForm({ | |
39 | 39 | labelWidth: 120, |
40 | 40 | schemas: CommandSchemas( |
41 | 41 | props.deviceDetail.deviceProfile.transportType as TransportTypeEnum, |
... | ... | @@ -47,8 +47,10 @@ |
47 | 47 | showResetButton: false, |
48 | 48 | }); |
49 | 49 | |
50 | - const handleCancel = () => { | |
51 | - resetFields(); | |
50 | + const handleCancel = async () => { | |
51 | + await resetFields(); | |
52 | + await nextTick(); | |
53 | + await clearValidate(); | |
52 | 54 | }; |
53 | 55 | |
54 | 56 | const handleOk = async () => { | ... | ... |
... | ... | @@ -22,7 +22,7 @@ |
22 | 22 | </Authority> |
23 | 23 | </template> |
24 | 24 | <template #status="{ record }"> |
25 | - <Authority value="api:yt:message:status"> | |
25 | + <Authority value="api:yt:message:update"> | |
26 | 26 | <Switch |
27 | 27 | :checked="record.status === 1" |
28 | 28 | :loading="record.pendingStatus" |
... | ... | @@ -32,7 +32,7 @@ |
32 | 32 | /> |
33 | 33 | </Authority> |
34 | 34 | <Tag |
35 | - v-if="!hasPermission('api:yt:message:status')" | |
35 | + v-if="!hasPermission('api:yt:message:update')" | |
36 | 36 | :color="record.status ? 'green' : 'red'" |
37 | 37 | > |
38 | 38 | {{ record.status ? '启用' : '禁用' }} | ... | ... |
... | ... | @@ -22,7 +22,7 @@ |
22 | 22 | </a-button> |
23 | 23 | </template> |
24 | 24 | <template #status="{ record }"> |
25 | - <Authority value="api:yt:template:status"> | |
25 | + <Authority value="api:yt:template:update"> | |
26 | 26 | <Switch |
27 | 27 | :checked="record.status === 1" |
28 | 28 | :loading="record.pendingStatus" |
... | ... | @@ -32,7 +32,7 @@ |
32 | 32 | /> |
33 | 33 | </Authority> |
34 | 34 | <Tag |
35 | - v-if="!hasPermission('api:yt:template:status')" | |
35 | + v-if="!hasPermission('api:yt:template:update')" | |
36 | 36 | :color="record.status ? 'green' : 'red'" |
37 | 37 | > |
38 | 38 | {{ record.status ? '启用' : '禁用' }} | ... | ... |
... | ... | @@ -4,12 +4,12 @@ |
4 | 4 | <div style="height: 30px"></div> |
5 | 5 | <BasicForm @register="registerForm" /> |
6 | 6 | <div class="flex flex-end" style="float: right"> |
7 | - <a-button type="primary" @click="handleDeviceState">处理</a-button> | |
7 | + <a-button v-if="!isHandler" type="primary" @click="handleDeviceState">处理</a-button> | |
8 | 8 | </div> |
9 | 9 | </BasicDrawer> |
10 | 10 | </template> |
11 | 11 | <script lang="ts" setup> |
12 | - import { reactive } from 'vue'; | |
12 | + import { reactive, ref } from 'vue'; | |
13 | 13 | import { BasicForm, useForm } from '/@/components/Form'; |
14 | 14 | import { formHandleSchema, formDetailSchema } from './config.data'; |
15 | 15 | import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; |
... | ... | @@ -26,7 +26,7 @@ |
26 | 26 | obj: {}, |
27 | 27 | }); |
28 | 28 | |
29 | - const [registerForm, { resetFields, getFieldsValue }] = useForm({ | |
29 | + const [registerForm, { resetFields, getFieldsValue, setFieldsValue }] = useForm({ | |
30 | 30 | schemas: formHandleSchema, |
31 | 31 | showActionButtonGroup: false, |
32 | 32 | }); |
... | ... | @@ -37,11 +37,15 @@ |
37 | 37 | layout: 'vertical', |
38 | 38 | }); |
39 | 39 | |
40 | + const isHandler = ref(false); | |
41 | + | |
40 | 42 | const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => { |
41 | 43 | await resetFields(); |
42 | 44 | setDrawerProps({ confirmLoading: false }); |
43 | 45 | record.obj = data.record; |
44 | 46 | setDescProps({ data: data.record }); |
47 | + isHandler.value = data?.record?.remark; | |
48 | + setFieldsValue(data.record); | |
45 | 49 | }); |
46 | 50 | |
47 | 51 | const handleDeviceState = async () => { | ... | ... |
... | ... | @@ -194,6 +194,10 @@ export const formSchema: DescItem[] = [ |
194 | 194 | field: 'createTime', |
195 | 195 | label: '时间', |
196 | 196 | }, |
197 | + { | |
198 | + field: 'remark', | |
199 | + label: '备注', | |
200 | + }, | |
197 | 201 | ]; |
198 | 202 | |
199 | 203 | export const formDetailSchema: DescItem[] = [ |
... | ... | @@ -221,7 +225,7 @@ export const formDetailSchema: DescItem[] = [ |
221 | 225 | //处理表单 |
222 | 226 | export const formHandleSchema: FormSchema[] = [ |
223 | 227 | { |
224 | - field: 'description', | |
228 | + field: 'remark', | |
225 | 229 | label: '备注', |
226 | 230 | colProps: { span: 24 }, |
227 | 231 | component: 'InputTextArea', | ... | ... |
... | ... | @@ -74,7 +74,7 @@ |
74 | 74 | /> |
75 | 75 | </template> |
76 | 76 | <template #configStatus="{ record }"> |
77 | - <Authority :value="PermissionReportConfigEnum.PERMISSION_STATUS"> | |
77 | + <Authority :value="PermissionReportConfigEnum.PERMISSION_UPDATE"> | |
78 | 78 | <Switch |
79 | 79 | :disabled="disabledSwitch" |
80 | 80 | :checked="record.status === 1" |
... | ... | @@ -85,7 +85,7 @@ |
85 | 85 | /> |
86 | 86 | </Authority> |
87 | 87 | <Tag |
88 | - v-if="!hasPermission(PermissionReportConfigEnum.PERMISSION_STATUS)" | |
88 | + v-if="!hasPermission(PermissionReportConfigEnum.PERMISSION_UPDATE)" | |
89 | 89 | :color="record.status ? 'green' : 'red'" |
90 | 90 | > |
91 | 91 | {{ record.status ? '启用' : '禁用' }} | ... | ... |
... | ... | @@ -31,9 +31,9 @@ |
31 | 31 | import { CredentialsEnum } from '../mqtt/enum'; |
32 | 32 | |
33 | 33 | const credentialsFile = reactive({ |
34 | - caCertFileName: '', | |
35 | - certFileName: '', | |
36 | - privateKeyFileName: '', | |
34 | + caCertFileName: undefined, | |
35 | + certFileName: undefined, | |
36 | + privateKeyFileName: undefined, | |
37 | 37 | }); |
38 | 38 | |
39 | 39 | const [register, { validateFields, setFieldsValue, resetFields }] = useForm({ |
... | ... | @@ -50,6 +50,11 @@ |
50 | 50 | const getValue = async () => { |
51 | 51 | const values = await validateFields(); |
52 | 52 | if (!values) return; |
53 | + // if (values.type == 'anonymous' || values.type == 'basic') { | |
54 | + // credentialsFile.caCertFileName = undefined; | |
55 | + // credentialsFile.certFileName = undefined; | |
56 | + // credentialsFile.privateKeyFileName = undefined; | |
57 | + // } | |
53 | 58 | const credentials = { |
54 | 59 | type: values['type'], |
55 | 60 | ...credentialsFile, | ... | ... |
... | ... | @@ -51,10 +51,16 @@ |
51 | 51 | const getValue = async () => { |
52 | 52 | const values = await validateFields(); |
53 | 53 | if (!values) return; |
54 | + if (values.type == 'anonymous' || values.type == 'basic') { | |
55 | + credentialsFile.caCertFileName = undefined; | |
56 | + credentialsFile.certFileName = undefined; | |
57 | + credentialsFile.privateKeyFileName = undefined; | |
58 | + } | |
54 | 59 | const credentials = { |
55 | 60 | type: values['type'], |
56 | 61 | ...credentialsFile, |
57 | 62 | }; |
63 | + | |
58 | 64 | const mergeValues = { |
59 | 65 | ...values, |
60 | 66 | ...{ credentials }, |
... | ... | @@ -67,7 +73,12 @@ |
67 | 73 | if (credentials) { |
68 | 74 | for (let i in credentials) Reflect.set(credentialsFile, i, credentials[i]); |
69 | 75 | } |
70 | - setFieldsValue({ ...value, type: credentials.type }); | |
76 | + setFieldsValue({ | |
77 | + ...value, | |
78 | + type: credentials.type, | |
79 | + username: credentials.username, | |
80 | + password: credentials.password, | |
81 | + }); | |
71 | 82 | }; |
72 | 83 | |
73 | 84 | const resetValue = () => resetFields(); | ... | ... |
... | ... | @@ -18,7 +18,7 @@ class MqttFormPartialConfig { |
18 | 18 | return [ |
19 | 19 | { label: 'Anonymous', value: 'anonymous' }, |
20 | 20 | { label: 'Basic', value: 'basic' }, |
21 | - { label: 'PEM', value: 'pem' }, | |
21 | + { label: 'PEM', value: 'cert.PEM' }, | |
22 | 22 | ]; |
23 | 23 | } |
24 | 24 | } |
... | ... | @@ -138,9 +138,21 @@ export const modeMqttForm: FormSchema[] = [ |
138 | 138 | label: '凭据类型', |
139 | 139 | colProps: { span: 12 }, |
140 | 140 | defaultValue: MqttFormPartialConfig.type, |
141 | - componentProps: { | |
142 | - placeholder: '请选择Credentials', | |
143 | - options: MqttFormPartialConfig.getType(), | |
141 | + componentProps: ({ formActionType }) => { | |
142 | + const { setFieldsValue } = formActionType; | |
143 | + return { | |
144 | + placeholder: '请选择Credentials', | |
145 | + options: MqttFormPartialConfig.getType(), | |
146 | + onChange(e) { | |
147 | + if (e) { | |
148 | + console.log('执行'); | |
149 | + setFieldsValue({ | |
150 | + password: undefined, | |
151 | + username: undefined, | |
152 | + }); | |
153 | + } | |
154 | + }, | |
155 | + }; | |
144 | 156 | }, |
145 | 157 | }, |
146 | 158 | { | ... | ... |
... | ... | @@ -128,8 +128,9 @@ |
128 | 128 | : undefined, |
129 | 129 | appendClientIdSuffix: getDataFlowParams.appendClientIdSuffix || undefined, |
130 | 130 | type: undefined, |
131 | + username: undefined, | |
132 | + password: undefined, | |
131 | 133 | }; |
132 | - | |
133 | 134 | const rest = isRabbitmq(getDataFlowMethod?.type) |
134 | 135 | ? await postAddConvertApi({ ...restData.data, ...data }) |
135 | 136 | : await postAddConvertApi({ ...restData.data, ...data, configuration }); | ... | ... |
... | ... | @@ -79,7 +79,7 @@ |
79 | 79 | /> |
80 | 80 | </template> |
81 | 81 | <template #status="{ record }"> |
82 | - <Authority :value="PermissionDataFlowEnum.PERMISSION_STATUS"> | |
82 | + <Authority :value="PermissionDataFlowEnum.PERMISSION_UPDATE"> | |
83 | 83 | <Switch |
84 | 84 | :checked="record.status === 1" |
85 | 85 | :loading="record.pendingStatus" |
... | ... | @@ -89,7 +89,7 @@ |
89 | 89 | /> |
90 | 90 | </Authority> |
91 | 91 | <Tag |
92 | - v-if="!hasPermission(PermissionDataFlowEnum.PERMISSION_STATUS)" | |
92 | + v-if="!hasPermission(PermissionDataFlowEnum.PERMISSION_UPDATE)" | |
93 | 93 | :color="record.status ? 'green' : 'red'" |
94 | 94 | > |
95 | 95 | {{ record.status ? '启用' : '禁用' }} | ... | ... |
... | ... | @@ -755,6 +755,18 @@ export const actionSchema: FormSchema[] = [ |
755 | 755 | component: 'Select', |
756 | 756 | label: '', |
757 | 757 | show: ({ values }) => isAlarmOut(values.outTarget), |
758 | + // dynamicRules: (params) => { | |
759 | + // const { outTarget } = params.values; | |
760 | + // return [ | |
761 | + // { | |
762 | + // required: outTarget == 'MSG_NOTIFY' ? true : false, | |
763 | + // validator: (_, value) => { | |
764 | + // if (!value) return Promise.reject('请选择告警配置'); | |
765 | + // Promise.resolve(); | |
766 | + // }, | |
767 | + // }, | |
768 | + // ]; | |
769 | + // }, | |
758 | 770 | componentProps: { |
759 | 771 | placeholder: '请选择告警等级', |
760 | 772 | options: [ | ... | ... |
... | ... | @@ -273,6 +273,10 @@ |
273 | 273 | if (validate.device == 'PART' && validate.deviceId == undefined) |
274 | 274 | return createMessage.error('请选择设备'); |
275 | 275 | } |
276 | + if (type === 'MSG_NOTIFY') { | |
277 | + if (!validate.alarm_config) return createMessage.error('请选择告警配置'); | |
278 | + if (!validate.alarm_level) return createMessage.error('请选择告警等级'); | |
279 | + } | |
276 | 280 | //ft-add-2022-11-22 |
277 | 281 | //TODO-fengtao-设备验证 |
278 | 282 | const value = getFieldsValue(); | ... | ... |
... | ... | @@ -50,7 +50,7 @@ |
50 | 50 | </template> |
51 | 51 | |
52 | 52 | <template #status="{ record }"> |
53 | - <Authority value="api:yt:sceneLinkage:status"> | |
53 | + <Authority value="api:yt:sceneLinkage:update"> | |
54 | 54 | <Switch |
55 | 55 | :checked="record.status === 1" |
56 | 56 | :loading="record.pendingStatus" |
... | ... | @@ -60,7 +60,7 @@ |
60 | 60 | /> |
61 | 61 | </Authority> |
62 | 62 | <Tag |
63 | - v-if="!hasPermission('api:yt:sceneLinkage:status')" | |
63 | + v-if="!hasPermission('api:yt:sceneLinkage:update')" | |
64 | 64 | :color="record.status ? 'green' : 'red'" |
65 | 65 | > |
66 | 66 | {{ record.status ? '启用' : '禁用' }} | ... | ... |
... | ... | @@ -17,7 +17,7 @@ |
17 | 17 | </Authority> |
18 | 18 | </template> |
19 | 19 | <template #status="{ record }"> |
20 | - <Authority value="api:yt:convert:js:status"> | |
20 | + <Authority value="api:yt:convert:js:update"> | |
21 | 21 | <Switch |
22 | 22 | :checked="record.status === 1" |
23 | 23 | :loading="record.pendingStatus" |
... | ... | @@ -27,7 +27,7 @@ |
27 | 27 | /> |
28 | 28 | </Authority> |
29 | 29 | <Tag |
30 | - v-if="!hasPermission('api:yt:convert:js:status')" | |
30 | + v-if="!hasPermission('api:yt:convert:js:update')" | |
31 | 31 | :color="record.status ? 'green' : 'red'" |
32 | 32 | > |
33 | 33 | {{ record.status ? '启用' : '禁用' }} | ... | ... |
... | ... | @@ -71,7 +71,7 @@ |
71 | 71 | /> |
72 | 72 | </template> |
73 | 73 | <template #status="{ record }"> |
74 | - <Authority :value="PermissionConvertScriptEnum.PERMISSION_UPDATE_STATUS"> | |
74 | + <Authority :value="PermissionConvertScriptEnum.PERMISSION_UPDATE"> | |
75 | 75 | <Switch |
76 | 76 | :checked="record.status === 1" |
77 | 77 | :loading="record.pendingStatus" |
... | ... | @@ -81,7 +81,7 @@ |
81 | 81 | /> |
82 | 82 | </Authority> |
83 | 83 | <Tag |
84 | - v-if="!hasPermission(PermissionConvertScriptEnum.PERMISSION_UPDATE_STATUS)" | |
84 | + v-if="!hasPermission(PermissionConvertScriptEnum.PERMISSION_UPDATE)" | |
85 | 85 | :color="record.status ? 'green' : 'red'" |
86 | 86 | > |
87 | 87 | {{ record.status ? '启用' : '禁用' }} | ... | ... |
... | ... | @@ -21,7 +21,7 @@ |
21 | 21 | </Authority> |
22 | 22 | </template> |
23 | 23 | <template #status="{ record }"> |
24 | - <Authority value="api:yt:role:status"> | |
24 | + <Authority value="api:yt:role:saveOrUpdateRoleInfoWithMenu:update"> | |
25 | 25 | <Switch |
26 | 26 | :checked="record.status === 1" |
27 | 27 | :loading="record.pendingStatus" |
... | ... | @@ -30,7 +30,10 @@ |
30 | 30 | @change="(checked:boolean)=>statusChange(checked,record)" |
31 | 31 | /> |
32 | 32 | </Authority> |
33 | - <Tag v-if="!hasPermission('api:yt:role:status')" :color="record.status ? 'green' : 'red'"> | |
33 | + <Tag | |
34 | + v-if="!hasPermission('api:yt:role:saveOrUpdateRoleInfoWithMenu:update')" | |
35 | + :color="record.status ? 'green' : 'red'" | |
36 | + > | |
34 | 37 | {{ record.status ? '启用' : '禁用' }} |
35 | 38 | </Tag> |
36 | 39 | </template> | ... | ... |
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | import { BasicForm, useForm } from '/@/components/Form'; |
3 | 3 | import { BasicModal, useModalInner } from '/@/components/Modal'; |
4 | 4 | import { formSchemas } from './config'; |
5 | - import { ref } from 'vue'; | |
5 | + import { nextTick, ref } from 'vue'; | |
6 | 6 | import { composeData, parseData } from './util'; |
7 | 7 | import { createTask, updateTask } from '/@/api/task'; |
8 | 8 | import { ModalParamsType } from '/#/utils'; |
... | ... | @@ -33,7 +33,10 @@ |
33 | 33 | modalMode.value = mode; |
34 | 34 | dataSource.value = record; |
35 | 35 | formMode.value = mode; |
36 | - resetFields(); | |
36 | + resetFields().then(async () => { | |
37 | + await nextTick(); | |
38 | + clearValidate(); | |
39 | + }); | |
37 | 40 | if (record && mode === DataActionModeEnum.UPDATE) { |
38 | 41 | const res = parseData(record); |
39 | 42 | setFieldsValue({ ...res }); |
... | ... | @@ -41,13 +44,14 @@ |
41 | 44 | } |
42 | 45 | ); |
43 | 46 | |
44 | - const [registerForm, { getFieldsValue, validate, setFieldsValue, resetFields }] = useForm({ | |
45 | - schemas: formSchemas, | |
46 | - showActionButtonGroup: false, | |
47 | - layout: 'inline', | |
48 | - baseColProps: { span: 24 }, | |
49 | - labelWidth: 140, | |
50 | - }); | |
47 | + const [registerForm, { getFieldsValue, validate, setFieldsValue, resetFields, clearValidate }] = | |
48 | + useForm({ | |
49 | + schemas: formSchemas, | |
50 | + showActionButtonGroup: false, | |
51 | + layout: 'inline', | |
52 | + baseColProps: { span: 24 }, | |
53 | + labelWidth: 140, | |
54 | + }); | |
51 | 55 | |
52 | 56 | const loading = ref(false); |
53 | 57 | const { createMessage } = useMessage(); | ... | ... |
... | ... | @@ -124,7 +124,6 @@ export const parseData = (result: TaskRecordType): Required<FormValueType> => { |
124 | 124 | TaskRecordType['executeTarget'] |
125 | 125 | >; |
126 | 126 | const { type: executeTimeType, period, periodType, time, pollUnit } = executeTime; |
127 | - console.log(pushWay === PushWayEnum.MQTT ? JSON.stringify(rpcCommand, null, 2) : rpcCommand); | |
128 | 127 | return { |
129 | 128 | name, |
130 | 129 | targetType, | ... | ... |
... | ... | @@ -188,7 +188,9 @@ |
188 | 188 | if (hasDetailPermission) { |
189 | 189 | const boardId = encode(record.id); |
190 | 190 | const boardName = encode(record.name); |
191 | - router.push(`/visual/board/detail/${boardId}/${boardName}`); | |
191 | + const organizationId = encode(record?.organizationId); | |
192 | + | |
193 | + router.push(`/visual/board/detail/${boardId}/${boardName}/${organizationId}`); | |
192 | 194 | } else createMessage.warning('没有权限'); |
193 | 195 | }; |
194 | 196 | ... | ... |
... | ... | @@ -12,10 +12,6 @@ |
12 | 12 | [PackagesCategoryEnum.MAP]: [ |
13 | 13 | '地图组件,需绑定两个数据源,且数据源为同一设备。第一数据源为经度,第二数据源为纬度,否则地图组件不能正常显示。', |
14 | 14 | ], |
15 | - [PackagesCategoryEnum.CONTROL]: [ | |
16 | - '控制组件数据源为TCP产品,则其控制命令下发为TCP产品 物模型=>服务,且不具备状态显示功能.', | |
17 | - '控制组件数据源为非TCP产品,则其控制命令下发为产品 物模型=>属性,且具备状态显示功能.', | |
18 | - ], | |
19 | 15 | }; |
20 | 16 | |
21 | 17 | const getMessage = computed(() => { | ... | ... |
... | ... | @@ -90,6 +90,7 @@ export const commonDataSourceSchemas = (): FormSchema[] => { |
90 | 90 | const isUpdate = unref(mode) === DataActionModeEnum.UPDATE; |
91 | 91 | const selectWidgetKeys = useSelectWidgetKeys(); |
92 | 92 | const category = unref(selectWidgetKeys).categoryKey; |
93 | + | |
93 | 94 | return [ |
94 | 95 | { |
95 | 96 | field: DataSourceField.IS_GATEWAY_DEVICE, |
... | ... | @@ -191,6 +192,9 @@ export const commonDataSourceSchemas = (): FormSchema[] => { |
191 | 192 | }); |
192 | 193 | }, |
193 | 194 | showCreate: false, |
195 | + apiTreeSelectProps: { | |
196 | + params: { organizationId: location?.pathname?.split('/')?.pop() || '' }, | |
197 | + }, | |
194 | 198 | getPopupContainer: () => document.body, |
195 | 199 | }; |
196 | 200 | }, | ... | ... |