Commit 226aff840e1ae30fd8ffc56607022103c1e96d08
Merge branch 'ww' into 'main'
feat: add AuthIcon component replace ant-design icon See merge request huang/yun-teng-iot-front!451
Showing
14 changed files
with
314 additions
and
87 deletions
src/assets/icons/location.svg
0 → 100644
1 | +<svg t="1671693733059" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="25398" width="200" height="200"><path d="M585.290213 343.524914c0-37.136805-33.106002-67.357084-73.789587-67.357084-40.684608 0-73.78754 30.220279-73.78754 67.357084 0 37.120432 33.102932 67.329455 73.78754 67.329455C552.184211 410.854369 585.290213 380.645346 585.290213 343.524914zM467.227284 343.524914c0-22.289656 19.860327-40.417525 44.273343-40.417525 24.415063 0 44.273343 18.127869 44.273343 40.417525 0 22.271236-19.85828 40.389896-44.273343 40.389896C487.087611 383.91481 467.227284 365.79615 467.227284 343.524914zM511.141446 741.92667l11.455913-12.768815c8.013511-8.92937 204.344015-220.213447 203.697285-358.458021-0.506537-111.529119-101.375875-208.420867-214.795041-208.420867-113.923656 0-215.816301 96.907097-215.816301 208.483288 0 138.182153 196.101283 349.432461 204.055442 358.356714L511.141446 741.92667zM511.500627 189.219549c97.206926 0 184.830589 84.850503 185.278797 181.601034 0.517793 109.87034-144.55121 279.638885-185.553043 328.016709-40.799218-48.428989-186.026834-218.179115-186.026834-328.072991C325.199547 274.042423 413.845493 189.219549 511.500627 189.219549zM946.101839 789.395798 832.104505 600.221274c-10.316973-17.114796-30.019711-27.752064-51.421136-27.752064L673.835875 572.46921c-8.156774 0-14.759145 6.03239-14.759145 13.472849 0 7.436366 6.601348 13.46671 14.759145 13.46671l106.848517 0c10.636245 0 20.437471 5.287423 25.566282 13.795191L920.250054 802.37746c5.013177 8.337899 4.856611 18.201547-0.448208 26.380834-5.303796 8.190543-14.699794 13.077853-25.120121 13.077853L128.318504 841.836147c-10.41828 0-19.814278-4.88731-25.119097-13.077853-5.302773-8.179286-5.462408-18.042935-0.446162-26.380834l113.997334-189.174524c5.130857-8.507768 14.930037-13.795191 25.566282-13.795191L349.166401 599.407746c8.15575 0 14.757099-6.030343 14.757099-13.46671 0-7.440459-6.601348-13.472849-14.757099-13.472849L242.317884 572.468187c-21.401426 0-41.10314 10.638291-51.42216 27.752064L76.898391 789.395798c-10.102079 16.758686-9.769504 36.600593 0.89437 53.073776 10.665921 16.476253 29.5582 26.307156 50.526767 26.307156L894.680702 868.776729c20.968567 0 39.862893-9.830903 50.528813-26.307156C955.87339 825.99639 956.204941 806.154483 946.101839 789.395798z" fill="#bfbfbf" p-id="25399"></path></svg> | ... | ... |
1 | -<script lang="ts" setup></script> | |
1 | +<script lang="ts" setup> | |
2 | + import { Dropdown, Menu, Popconfirm } from 'ant-design-vue'; | |
3 | + import { computed, useSlots } from 'vue'; | |
4 | + import Icon from '../Icon'; | |
5 | + import { usePermission } from '/@/hooks/web/usePermission'; | |
2 | 6 | |
3 | -<template> <div></div></template> | |
7 | + export interface AuthDropDownProps { | |
8 | + dropMenuList: AuthDropMenuList[]; | |
9 | + trigger?: ('contextmenu' | 'click' | 'hover')[]; | |
10 | + } | |
11 | + | |
12 | + export interface AuthDropMenuList { | |
13 | + icon?: string; | |
14 | + event: string | number; | |
15 | + text: string; | |
16 | + disabled?: boolean; | |
17 | + divider?: boolean; | |
18 | + auth?: string; | |
19 | + onClick?: Fn; | |
20 | + popconfirm?: { | |
21 | + cancelText?: string; | |
22 | + okText?: string; | |
23 | + okType?: string; | |
24 | + title?: string; | |
25 | + icon?: string; | |
26 | + disabled?: boolean; | |
27 | + onCancel?: Fn; | |
28 | + onConfirm?: Fn; | |
29 | + onVisibleChange?: Fn; | |
30 | + }; | |
31 | + } | |
32 | + | |
33 | + const props = defineProps<AuthDropDownProps>(); | |
34 | + | |
35 | + const slot = useSlots(); | |
36 | + | |
37 | + const { hasPermission } = usePermission(); | |
38 | + | |
39 | + const getMenuList = computed(() => { | |
40 | + const { dropMenuList } = props; | |
41 | + return dropMenuList.filter((menu) => (menu.auth ? hasPermission(menu.auth) : true)); | |
42 | + }); | |
43 | + | |
44 | + const hasDefaultSlot = computed(() => { | |
45 | + return !!slot.default; | |
46 | + }); | |
47 | +</script> | |
48 | + | |
49 | +<template> | |
50 | + <Dropdown :trigger="$props.trigger"> | |
51 | + <template #overlay> | |
52 | + <Menu v-if="getMenuList.length"> | |
53 | + <template v-for="item in getMenuList" :key="item.event"> | |
54 | + <Menu.Divider v-if="item.divider" /> | |
55 | + <Menu.Item v-if="!item.popconfirm" @click="item.onClick"> | |
56 | + <span class="flex justify-center items-center"> | |
57 | + <Icon :icon="item.icon" /> | |
58 | + <span class="ml-2">{{ item.text }}</span> | |
59 | + </span> | |
60 | + </Menu.Item> | |
61 | + <Menu.Item v-if="item.popconfirm"> | |
62 | + <Popconfirm v-bind="item.popconfirm"> | |
63 | + <template v-if="item.popconfirm.icon" #icon> | |
64 | + <Icon :icon="item.popconfirm.icon" /> | |
65 | + </template> | |
66 | + <span class="flex justify-center items-center"> | |
67 | + <Icon :icon="item.icon" /> | |
68 | + <span class="ml-2">{{ item.text }}</span> | |
69 | + </span> | |
70 | + </Popconfirm> | |
71 | + </Menu.Item> | |
72 | + </template> | |
73 | + </Menu> | |
74 | + </template> | |
75 | + <Icon | |
76 | + v-if="!hasDefaultSlot" | |
77 | + class="items-center justify-center" | |
78 | + icon="ant-design:ellipsis-outlined" | |
79 | + :class="!getMenuList.length ? '!text-gray-200 !cursor-not-allowed' : ''" | |
80 | + /> | |
81 | + <slot name="default"></slot> | |
82 | + </Dropdown> | |
83 | +</template> | ... | ... |
1 | +<script lang="ts" setup> | |
2 | + import { Icon } from '/@/components/Icon'; | |
3 | + import { computed, ExtractPropTypes, unref } from 'vue'; | |
4 | + import { usePermission } from '/@/hooks/web/usePermission'; | |
5 | + | |
6 | + interface AuthIconProps extends ExtractPropTypes<typeof Icon> { | |
7 | + auth?: string; | |
8 | + } | |
9 | + | |
10 | + const props = defineProps<AuthIconProps>(); | |
11 | + | |
12 | + const emit = defineEmits(['click']); | |
13 | + | |
14 | + const { hasPermission } = usePermission(); | |
15 | + | |
16 | + const getHasPermission = computed(() => { | |
17 | + const { auth } = props; | |
18 | + return auth ? hasPermission(auth) : true; | |
19 | + }); | |
20 | + | |
21 | + const getBindProps = computed(() => { | |
22 | + return { | |
23 | + ...props, | |
24 | + ...(unref(getHasPermission) ? { onClick: (event: Event) => emit('click', event) } : {}), | |
25 | + }; | |
26 | + }); | |
27 | +</script> | |
28 | + | |
29 | +<template> | |
30 | + <Icon | |
31 | + v-bind="getBindProps" | |
32 | + class="justify-center items-center" | |
33 | + :class="getHasPermission ? '' : '!cursor-not-allowed !text-gray-200'" | |
34 | + /> | |
35 | +</template> | ... | ... |
... | ... | @@ -26,3 +26,26 @@ export function buildShortUUID(prefix = ''): string { |
26 | 26 | unique++; |
27 | 27 | return prefix + '_' + random + unique + String(time); |
28 | 28 | } |
29 | + | |
30 | +export function getlowerCaseChars() { | |
31 | + return Array.from({ length: 26 }).map((_, index) => String.fromCharCode(index + 97)); | |
32 | +} | |
33 | + | |
34 | +export function getUpperCaseChars() { | |
35 | + return Array.from({ length: 26 }).map((_, index) => String.fromCharCode(index + 65)); | |
36 | +} | |
37 | + | |
38 | +export function randomString(length = 20) { | |
39 | + const upperCaseChars = getUpperCaseChars(); | |
40 | + const lowerCaseChars = getlowerCaseChars(); | |
41 | + const numberChars = Array.from({ length: 10 }).map((_, index) => index); | |
42 | + const allChars = [...numberChars, ...upperCaseChars, ...lowerCaseChars].sort( | |
43 | + () => 0.5 - Math.random() | |
44 | + ); | |
45 | + | |
46 | + const rangeFn = () => (Math.random() * 63) | 0; | |
47 | + | |
48 | + return Array.from({ length }) | |
49 | + .map(() => allChars[rangeFn()]) | |
50 | + .join(''); | |
51 | +} | ... | ... |
1 | 1 | <script setup lang="ts"> |
2 | 2 | import { List, Card, Button, PaginationProps, Popover, Slider, Tooltip } from 'ant-design-vue'; |
3 | - import { | |
4 | - ReloadOutlined, | |
5 | - AppstoreOutlined, | |
6 | - EyeOutlined, | |
7 | - EditOutlined, | |
8 | - EllipsisOutlined, | |
9 | - } from '@ant-design/icons-vue'; | |
3 | + import { ReloadOutlined, AppstoreOutlined } from '@ant-design/icons-vue'; | |
10 | 4 | import { computed, onMounted, reactive, ref, unref } from 'vue'; |
11 | 5 | import { OrganizationIdTree, useResetOrganizationTree } from '../../common/organizationIdTree'; |
12 | 6 | import { |
... | ... | @@ -15,7 +9,6 @@ |
15 | 9 | } from '/@/api/configuration/center/configurationCenter'; |
16 | 10 | import { ConfigurationCenterItemsModal } from '/@/api/configuration/center/model/configurationCenterModal'; |
17 | 11 | import { PageWrapper } from '/@/components/Page'; |
18 | - import { Dropdown } from '/@/components/Dropdown'; | |
19 | 12 | import { BasicForm, useForm } from '/@/components/Form'; |
20 | 13 | import { ConfigurationPermission, searchFormSchema } from './center.data'; |
21 | 14 | import { useMessage } from '/@/hooks/web/useMessage'; |
... | ... | @@ -23,12 +16,13 @@ |
23 | 16 | import { isDevMode } from '/@/utils/env'; |
24 | 17 | import ConfigurationCenterDrawer from './ConfigurationCenterDrawer.vue'; |
25 | 18 | import { useDrawer } from '/@/components/Drawer'; |
26 | - import { useSyncConfirm } from '/@/hooks/component/useSyncConfirm'; | |
27 | 19 | import { getBoundingClientRect } from '/@/utils/domUtils'; |
28 | 20 | import configurationSrc from '/@/assets/icons/configuration.svg'; |
29 | 21 | import { cloneDeep } from 'lodash'; |
30 | 22 | import { usePermission } from '/@/hooks/web/usePermission'; |
31 | 23 | import { useGlobSetting } from '/@/hooks/setting'; |
24 | + import { AuthIcon } from '/@/components/Widget'; | |
25 | + import AuthDropDown from '/@/components/Widget/AuthDropDown.vue'; | |
32 | 26 | |
33 | 27 | const listColumn = ref(5); |
34 | 28 | |
... | ... | @@ -136,10 +130,8 @@ |
136 | 130 | window.open(`${configurationPrefix}/${isDev ? '?dev=1&' : '?'}configurationId=${record!.id}`); |
137 | 131 | }; |
138 | 132 | |
139 | - const { createSyncConfirm } = useSyncConfirm(); | |
140 | 133 | const handleDelete = async (record: ConfigurationCenterItemsModal) => { |
141 | 134 | try { |
142 | - await createSyncConfirm({ iconType: 'warning', content: '是否确认删除操作?' }); | |
143 | 135 | await deleteConfigurationCenter([record.id]); |
144 | 136 | createMessage.success('删除成功'); |
145 | 137 | await getListData(); |
... | ... | @@ -227,20 +219,44 @@ |
227 | 219 | </template> |
228 | 220 | <template class="ant-card-actions" #actions> |
229 | 221 | <Tooltip title="预览"> |
230 | - <EyeOutlined | |
231 | - :class="getPreviewFlag ? '' : '!cursor-not-allowed !text-gray-200'" | |
232 | - key="setting" | |
222 | + <AuthIcon | |
223 | + :auth="ConfigurationPermission.PREVIEW" | |
224 | + class="!text-lg" | |
225 | + icon="ant-design:eye-outlined" | |
233 | 226 | @click="handlePreview(item)" |
234 | 227 | /> |
235 | 228 | </Tooltip> |
236 | 229 | <Tooltip title="设计"> |
237 | - <EditOutlined | |
238 | - :class="getDesignFlag ? '' : '!cursor-not-allowed !text-gray-200'" | |
239 | - key="edit" | |
230 | + <AuthIcon | |
231 | + :auth="ConfigurationPermission.DESIGN" | |
232 | + class="!text-lg" | |
233 | + icon="ant-design:edit-outlined" | |
240 | 234 | @click="handleDesign(item)" |
241 | 235 | /> |
242 | 236 | </Tooltip> |
243 | - <Dropdown | |
237 | + <AuthDropDown | |
238 | + :dropMenuList="[ | |
239 | + { | |
240 | + text: '编辑', | |
241 | + auth: ConfigurationPermission.UPDATE, | |
242 | + icon: 'clarity:note-edit-line', | |
243 | + event: '', | |
244 | + onClick: handleCreateOrUpdate.bind(null, item), | |
245 | + }, | |
246 | + { | |
247 | + text: '删除', | |
248 | + auth: ConfigurationPermission.DELETE, | |
249 | + icon: 'ant-design:delete-outlined', | |
250 | + event: '', | |
251 | + popconfirm: { | |
252 | + title: '是否确认删除操作?', | |
253 | + onConfirm: handleDelete.bind(null, item), | |
254 | + }, | |
255 | + }, | |
256 | + ]" | |
257 | + :trigger="['hover']" | |
258 | + /> | |
259 | + <!-- <Dropdown | |
244 | 260 | :dropMenuList="[ |
245 | 261 | { |
246 | 262 | text: '编辑', |
... | ... | @@ -261,7 +277,7 @@ |
261 | 277 | :trigger="['hover']" |
262 | 278 | > |
263 | 279 | <EllipsisOutlined key="ellipsis" /> |
264 | - </Dropdown> | |
280 | + </Dropdown> --> | |
265 | 281 | </template> |
266 | 282 | <Card.Meta> |
267 | 283 | <template #title> | ... | ... |
... | ... | @@ -399,6 +399,7 @@ export const step2Schemas: FormSchema[] = [ |
399 | 399 | field: 'credentialsId', |
400 | 400 | required: true, |
401 | 401 | ifShow: false, |
402 | + slot: 'credentialsId', | |
402 | 403 | componentProps: { |
403 | 404 | maxLength: 36, |
404 | 405 | placeholder: '请输入访问令牌', |
... | ... | @@ -421,6 +422,7 @@ export const step2Schemas: FormSchema[] = [ |
421 | 422 | field: 'clientId', |
422 | 423 | required: true, |
423 | 424 | ifShow: false, |
425 | + slot: 'clientId', | |
424 | 426 | componentProps: { |
425 | 427 | maxLength: 36, |
426 | 428 | placeholder: '请输入客户端ID', |
... | ... | @@ -597,6 +599,7 @@ export const TokenSchemas: FormSchema[] = [ |
597 | 599 | field: 'credentialsId', |
598 | 600 | required: true, |
599 | 601 | ifShow: false, |
602 | + slot: 'credentialsId', | |
600 | 603 | componentProps: { |
601 | 604 | maxLength: 36, |
602 | 605 | placeholder: '请输入访问令牌', | ... | ... |
... | ... | @@ -12,7 +12,17 @@ |
12 | 12 | <template #clientId="{ field, model }"> |
13 | 13 | <div class="flex items-center"> |
14 | 14 | <Input v-model:value="model[field]" placeholder="请输入客户端ID" /> |
15 | - <ReloadOutlined class="ml-3 !text-blue-600" @click="handleCreateUUID" /> | |
15 | + <Tooltip title="刷新客户端ID"> | |
16 | + <ReloadOutlined class="ml-3 !text-blue-600" @click="handleCreateUUID" /> | |
17 | + </Tooltip> | |
18 | + </div> | |
19 | + </template> | |
20 | + <template #credentialsId="{ field, model }"> | |
21 | + <div class="flex items-center"> | |
22 | + <Input v-model:value="model[field]" placeholder="请输入访问令牌" /> | |
23 | + <Tooltip title="刷新访问令牌"> | |
24 | + <ReloadOutlined class="ml-3 !text-blue-600" @click="handleCreateCredentialsId" /> | |
25 | + </Tooltip> | |
16 | 26 | </div> |
17 | 27 | </template> |
18 | 28 | </BasicForm> |
... | ... | @@ -26,8 +36,8 @@ |
26 | 36 | import { TokenSchemas, credentialTypeEnum } from '../../config/data'; |
27 | 37 | import { saveDeviceToken } from '/@/api/device/deviceManager'; |
28 | 38 | import { useMessage } from '/@/hooks/web/useMessage'; |
29 | - import { Input } from 'ant-design-vue'; | |
30 | - import { buildUUID } from '/@/utils/uuid'; | |
39 | + import { Input, Tooltip } from 'ant-design-vue'; | |
40 | + import { buildUUID, randomString } from '/@/utils/uuid'; | |
31 | 41 | import { ReloadOutlined } from '@ant-design/icons-vue'; |
32 | 42 | export default defineComponent({ |
33 | 43 | components: { |
... | ... | @@ -35,6 +45,7 @@ |
35 | 45 | BasicForm, |
36 | 46 | Input, |
37 | 47 | ReloadOutlined, |
48 | + Tooltip, | |
38 | 49 | }, |
39 | 50 | emits: ['register'], |
40 | 51 | setup() { |
... | ... | @@ -224,6 +235,10 @@ |
224 | 235 | const handleCreateUUID = () => { |
225 | 236 | setFieldsValue({ clientId: buildUUID() }); |
226 | 237 | }; |
238 | + | |
239 | + const handleCreateCredentialsId = () => { | |
240 | + setFieldsValue({ credentialsId: randomString() }); | |
241 | + }; | |
227 | 242 | return { |
228 | 243 | registerModal, |
229 | 244 | registerForm, |
... | ... | @@ -231,6 +246,7 @@ |
231 | 246 | handleCancel, |
232 | 247 | handleOk, |
233 | 248 | handleCreateUUID, |
249 | + handleCreateCredentialsId, | |
234 | 250 | }; |
235 | 251 | }, |
236 | 252 | }); | ... | ... |
... | ... | @@ -4,6 +4,30 @@ |
4 | 4 | <template #addAgree="{ model, field }"> |
5 | 5 | <Checkbox v-model:checked="model[field]" @change="checkedChange">添加协议</Checkbox> |
6 | 6 | </template> |
7 | + <template #clientId="{ model, field }"> | |
8 | + <div class="flex justify-center items-center"> | |
9 | + <Input v-model:value="model[field]" placeholder="请输入客户端ID" /> | |
10 | + <Tooltip title="刷新客户端ID"> | |
11 | + <Icon | |
12 | + class="ml-3 cursor-pointer !text-blue-600" | |
13 | + icon="ant-design:reload-outlined" | |
14 | + @click="handleGenerateClientId" | |
15 | + /> | |
16 | + </Tooltip> | |
17 | + </div> | |
18 | + </template> | |
19 | + <template #credentialsId="{ model, field }"> | |
20 | + <div class="flex justify-center items-center"> | |
21 | + <Input v-model:value="model[field]" placeholder="请输入访问令牌" /> | |
22 | + <Tooltip title="刷新访问令牌"> | |
23 | + <Icon | |
24 | + class="ml-3 cursor-pointer !text-blue-600" | |
25 | + icon="ant-design:reload-outlined" | |
26 | + @click="handleGenerateCredentialsId" | |
27 | + /> | |
28 | + </Tooltip> | |
29 | + </div> | |
30 | + </template> | |
7 | 31 | </BasicForm> |
8 | 32 | <div> |
9 | 33 | <a-button @click="prevStep">上一步</a-button> |
... | ... | @@ -13,13 +37,18 @@ |
13 | 37 | <script lang="ts"> |
14 | 38 | import { defineComponent } from 'vue'; |
15 | 39 | |
16 | - import { Checkbox } from 'ant-design-vue'; | |
40 | + import { Checkbox, Input, Tooltip } from 'ant-design-vue'; | |
17 | 41 | import { BasicForm, useForm } from '/@/components/Form'; |
18 | 42 | import { step2Schemas } from '../../config/data'; |
43 | + import { Icon } from '/@/components/Icon'; | |
44 | + import { buildUUID, randomString } from '/@/utils/uuid'; | |
19 | 45 | export default defineComponent({ |
20 | 46 | components: { |
21 | 47 | BasicForm, |
22 | 48 | Checkbox, |
49 | + Input, | |
50 | + Icon, | |
51 | + Tooltip, | |
23 | 52 | }, |
24 | 53 | |
25 | 54 | emits: ['prev', 'next'], |
... | ... | @@ -105,6 +134,14 @@ |
105 | 134 | validate(); |
106 | 135 | } |
107 | 136 | |
137 | + const handleGenerateClientId = () => { | |
138 | + setFieldsValue({ clientId: buildUUID() }); | |
139 | + }; | |
140 | + | |
141 | + const handleGenerateCredentialsId = () => { | |
142 | + setFieldsValue({ credentialsId: randomString() }); | |
143 | + }; | |
144 | + | |
108 | 145 | return { |
109 | 146 | prevStep, |
110 | 147 | registerForm, |
... | ... | @@ -113,6 +150,8 @@ |
113 | 150 | validate, |
114 | 151 | resetFieldsValueAndStatus, |
115 | 152 | validateStep2Method, |
153 | + handleGenerateClientId, | |
154 | + handleGenerateCredentialsId, | |
116 | 155 | }; |
117 | 156 | }, |
118 | 157 | }); | ... | ... |
... | ... | @@ -55,15 +55,23 @@ |
55 | 55 | <a-button type="primary" class="mr-4" @click="manageDeviceToken">管理设备凭证</a-button> |
56 | 56 | <ManageDeviceTokenModal @register="registerModal" /> |
57 | 57 | </div> |
58 | - <div v-if="deviceDetail?.deviceInfo?.address" class="mt-4"> | |
58 | + <div class="mt-4"> | |
59 | 59 | <p>设备位置</p> |
60 | - <div ref="mapWrapRef" style="height: 550px; width: 100%"></div> | |
60 | + <div v-if="deviceDetail?.deviceInfo?.address"> | |
61 | + <div ref="mapWrapRef" style="height: 550px; width: 100%"></div> | |
62 | + </div> | |
63 | + <Empty | |
64 | + v-if="!deviceDetail?.deviceInfo?.address" | |
65 | + :image="locationImage" | |
66 | + :imageStyle="{ display: 'flex', 'justify-content': 'center', height: '150px' }" | |
67 | + description="请添加设备地理位置" | |
68 | + /> | |
61 | 69 | </div> |
62 | 70 | </div> |
63 | 71 | </template> |
64 | 72 | <script lang="ts"> |
65 | 73 | import { defineComponent, ref, unref, nextTick } from 'vue'; |
66 | - import { Image, Tooltip } from 'ant-design-vue'; | |
74 | + import { Empty, Image, Tooltip } from 'ant-design-vue'; | |
67 | 75 | import { descSchema } from '../../config/detail.config'; |
68 | 76 | import { useAsyncScript } from '/@/hooks/web/useAsyncScript'; |
69 | 77 | import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard'; |
... | ... | @@ -78,6 +86,8 @@ |
78 | 86 | |
79 | 87 | import wz from '/@/assets/images/wz.png'; |
80 | 88 | import { useAsyncQueue } from '../../../localtion/useAsyncQueue'; |
89 | + import locationImage from '/@/assets/icons/location.svg'; | |
90 | + | |
81 | 91 | export default defineComponent({ |
82 | 92 | components: { |
83 | 93 | Image, |
... | ... | @@ -86,6 +96,7 @@ |
86 | 96 | QuestionCircleOutlined, |
87 | 97 | BasicModal, |
88 | 98 | Tooltip, |
99 | + Empty, | |
89 | 100 | }, |
90 | 101 | props: { |
91 | 102 | deviceDetail: { |
... | ... | @@ -197,6 +208,7 @@ |
197 | 208 | DeviceTypeEnum, |
198 | 209 | copyTopic, |
199 | 210 | remoteConnectiondGateway, |
211 | + locationImage, | |
200 | 212 | }; |
201 | 213 | }, |
202 | 214 | }); | ... | ... |
... | ... | @@ -2,9 +2,14 @@ |
2 | 2 | import { PageWrapper } from '/@/components/Page'; |
3 | 3 | import { BasicForm, useForm } from '/@/components/Form'; |
4 | 4 | import { List, Button, Tooltip, Card, PaginationProps, Image } from 'ant-design-vue'; |
5 | - import { ReloadOutlined, EyeOutlined, FormOutlined, MoreOutlined } from '@ant-design/icons-vue'; | |
5 | + import { ReloadOutlined } from '@ant-design/icons-vue'; | |
6 | 6 | import { computed, onMounted, reactive, ref, unref } from 'vue'; |
7 | - import { CardLayoutButton, EnumTableCardMode, ModeSwitchButton } from '/@/components/Widget'; | |
7 | + import { | |
8 | + AuthIcon, | |
9 | + CardLayoutButton, | |
10 | + EnumTableCardMode, | |
11 | + ModeSwitchButton, | |
12 | + } from '/@/components/Widget'; | |
8 | 13 | import { Authority } from '/@/components/Authority'; |
9 | 14 | import { |
10 | 15 | deviceConfigDelete, |
... | ... | @@ -12,7 +17,6 @@ |
12 | 17 | setDeviceProfileIsDefaultApi, |
13 | 18 | } from '/@/api/device/deviceConfigApi'; |
14 | 19 | import { ProfileRecord } from '/@/api/device/model/deviceConfigModel'; |
15 | - import { Dropdown } from '/@/components/Dropdown'; | |
16 | 20 | import { |
17 | 21 | defaultObj, |
18 | 22 | searchFormSchema, |
... | ... | @@ -20,14 +24,13 @@ |
20 | 24 | ProductPermission, |
21 | 25 | } from './device.profile.data'; |
22 | 26 | import { useMessage } from '/@/hooks/web/useMessage'; |
23 | - import { useSyncConfirm } from '/@/hooks/component/useSyncConfirm'; | |
24 | 27 | import DeviceProfileModal from './DeviceProfileModal.vue'; |
25 | 28 | import DeviceProfileDrawer from './DeviceProfileDrawer.vue'; |
26 | 29 | import { useModal } from '/@/components/Modal'; |
27 | 30 | import { useDrawer } from '/@/components/Drawer'; |
28 | 31 | import productDefault from '/@/assets/icons/product-default.svg'; |
29 | - import { usePermission } from '/@/hooks/web/usePermission'; | |
30 | 32 | import { useRoute } from 'vue-router'; |
33 | + import AuthDropDown from '/@/components/Widget/AuthDropDown.vue'; | |
31 | 34 | |
32 | 35 | defineProps<{ |
33 | 36 | mode: EnumTableCardMode; |
... | ... | @@ -42,7 +45,6 @@ |
42 | 45 | const IMAGE_FALLBACK = productDefault; |
43 | 46 | |
44 | 47 | const { createMessage } = useMessage(); |
45 | - const { createSyncConfirm } = useSyncConfirm(); | |
46 | 48 | |
47 | 49 | const [register, { getFieldsValue, setFieldsValue }] = useForm({ |
48 | 50 | showAdvancedButton: true, |
... | ... | @@ -105,40 +107,6 @@ |
105 | 107 | } |
106 | 108 | }; |
107 | 109 | |
108 | - const { hasPermission } = usePermission(); | |
109 | - | |
110 | - const getHasDeleteFlag = computed(() => { | |
111 | - return hasPermission(ProductPermission.DELETE); | |
112 | - }); | |
113 | - | |
114 | - const getHasDetailFlag = computed(() => { | |
115 | - return hasPermission(ProductPermission.DETAIL); | |
116 | - }); | |
117 | - | |
118 | - const getHasUpdateFlag = computed(() => { | |
119 | - return hasPermission(ProductPermission.UPDATE); | |
120 | - }); | |
121 | - | |
122 | - const getDropDownList = (record: ProfileRecord) => { | |
123 | - const list = [ | |
124 | - { | |
125 | - text: '默认', | |
126 | - event: DropMenuEvent.SET_DEFAULT, | |
127 | - icon: 'ant-design:unordered-list-outlined', | |
128 | - onClick: handleSetDefault.bind(null, record), | |
129 | - }, | |
130 | - ]; | |
131 | - if (unref(getHasDeleteFlag)) { | |
132 | - list.push({ | |
133 | - text: '删除', | |
134 | - event: DropMenuEvent.DELETE, | |
135 | - icon: 'ant-design:delete-outlined', | |
136 | - onClick: handleDelete.bind(null, [record.id]), | |
137 | - }); | |
138 | - } | |
139 | - return list; | |
140 | - }; | |
141 | - | |
142 | 110 | const handleModeChange = (mode: EnumTableCardMode) => { |
143 | 111 | emit('changeMode', mode); |
144 | 112 | }; |
... | ... | @@ -163,12 +131,10 @@ |
163 | 131 | }; |
164 | 132 | |
165 | 133 | const handleShowDetail = (record: ProfileRecord) => { |
166 | - if (!unref(getHasDetailFlag)) return; | |
167 | 134 | openDrawer(true, { record }); |
168 | 135 | }; |
169 | 136 | |
170 | 137 | const handleUpdate = (record: ProfileRecord) => { |
171 | - if (!unref(getHasUpdateFlag)) return; | |
172 | 138 | openModal(true, { |
173 | 139 | record, |
174 | 140 | isUpdate: true, |
... | ... | @@ -177,7 +143,6 @@ |
177 | 143 | |
178 | 144 | const handleDelete = async (id: string[]) => { |
179 | 145 | try { |
180 | - await createSyncConfirm({ iconType: 'warning', content: '是否确认删除操作?' }); | |
181 | 146 | await deviceConfigDelete(id); |
182 | 147 | createMessage.success('删除成功'); |
183 | 148 | await getDataSource(); |
... | ... | @@ -268,22 +233,43 @@ |
268 | 233 | </template> |
269 | 234 | <template class="ant-card-actions" #actions> |
270 | 235 | <Tooltip title="详情"> |
271 | - <EyeOutlined | |
272 | - :class="getHasDetailFlag ? '' : '!cursor-not-allowed !text-gray-200'" | |
273 | - key="setting" | |
236 | + <AuthIcon | |
237 | + :auth="ProductPermission.DETAIL" | |
238 | + class="!text-lg" | |
239 | + icon="ant-design:eye-outlined" | |
274 | 240 | @click.stop="handleShowDetail(item)" |
275 | 241 | /> |
276 | 242 | </Tooltip> |
277 | 243 | <Tooltip title="编辑"> |
278 | - <FormOutlined | |
279 | - :class="getHasUpdateFlag ? '' : '!cursor-not-allowed !text-gray-200'" | |
280 | - key="edit" | |
244 | + <AuthIcon | |
245 | + :auth="ProductPermission.UPDATE" | |
246 | + class="!text-lg" | |
247 | + icon="ant-design:form-outlined" | |
281 | 248 | @click.stop="handleUpdate(item)" |
282 | 249 | /> |
283 | 250 | </Tooltip> |
284 | - <Dropdown :trigger="['hover']" :drop-menu-list="getDropDownList(item)"> | |
285 | - <MoreOutlined @click.stop class="transform rotate-90" /> | |
286 | - </Dropdown> | |
251 | + <AuthDropDown | |
252 | + @click.stop | |
253 | + :trigger="['hover']" | |
254 | + :drop-menu-list="[ | |
255 | + { | |
256 | + text: '默认', | |
257 | + event: DropMenuEvent.SET_DEFAULT, | |
258 | + icon: 'ant-design:unordered-list-outlined', | |
259 | + onClick: handleSetDefault.bind(null, item), | |
260 | + }, | |
261 | + { | |
262 | + text: '删除', | |
263 | + event: DropMenuEvent.DELETE, | |
264 | + auth: ProductPermission.DELETE, | |
265 | + icon: 'ant-design:delete-outlined', | |
266 | + popconfirm: { | |
267 | + title: '是否确认删除操作?', | |
268 | + onConfirm: handleDelete.bind(null, [item.id]), | |
269 | + }, | |
270 | + }, | |
271 | + ]" | |
272 | + /> | |
287 | 273 | </template> |
288 | 274 | <Card.Meta> |
289 | 275 | <template #title> |
... | ... | @@ -308,7 +294,10 @@ |
308 | 294 | |
309 | 295 | <style lang="less" scoped> |
310 | 296 | .profile-list:deep(.ant-image-img) { |
311 | - width: 100% !important; | |
312 | - height: 100% !important; | |
297 | + @apply !w-full !h-full; | |
298 | + } | |
299 | + | |
300 | + .profile-list:deep(.ant-card-body) { | |
301 | + @apply !p-4; | |
313 | 302 | } |
314 | 303 | </style> | ... | ... |
... | ... | @@ -28,10 +28,13 @@ |
28 | 28 | field: 'scriptName', |
29 | 29 | label: '转换脚本', |
30 | 30 | render: (value: string) => { |
31 | - return h('div', [ | |
32 | - h(Tag, { color: 'blue' }, () => value), | |
33 | - h(Button, { type: 'link', onClick: handleTestScript }, () => '测试脚本'), | |
34 | - ]); | |
31 | + return ( | |
32 | + value && | |
33 | + h('div', [ | |
34 | + h(Tag, { color: 'blue' }, () => value), | |
35 | + h(Button, { type: 'link', onClick: handleTestScript }, () => '测试脚本'), | |
36 | + ]) | |
37 | + ); | |
35 | 38 | }, |
36 | 39 | }, |
37 | 40 | ], | ... | ... |
... | ... | @@ -261,12 +261,14 @@ export const columns: BasicColumn[] = [ |
261 | 261 | title: '默认配置', |
262 | 262 | dataIndex: 'default', |
263 | 263 | width: 80, |
264 | - format: (text) => (text ? '是' : '否'), | |
264 | + customRender: ({ text }) => | |
265 | + text ? h(Tag, { color: 'blue' }, () => '是') : h(Tag, { color: 'red' }, () => '否'), | |
265 | 266 | }, |
266 | 267 | { |
267 | 268 | title: '描述', |
268 | 269 | dataIndex: 'description', |
269 | 270 | width: 90, |
271 | + ellipsis: true, | |
270 | 272 | }, |
271 | 273 | { |
272 | 274 | title: '创建时间', | ... | ... |
... | ... | @@ -8,7 +8,9 @@ |
8 | 8 | placeholder="请选择转换脚本" |
9 | 9 | v-model:value="selectScript.script" |
10 | 10 | style="width: 305px" |
11 | + show-search | |
11 | 12 | :options="selectOptions" |
13 | + :filter-option="handleSearch" | |
12 | 14 | allowClear |
13 | 15 | /> |
14 | 16 | </div> |
... | ... | @@ -113,6 +115,11 @@ |
113 | 115 | const setFormData = (v) => { |
114 | 116 | selectScript.script = v?.scriptId; |
115 | 117 | }; |
118 | + | |
119 | + const handleSearch = (inputValue: string, option: Record<'label' | 'value', string>) => { | |
120 | + return option.label.includes(inputValue); | |
121 | + }; | |
122 | + | |
116 | 123 | defineExpose({ |
117 | 124 | getFormData, |
118 | 125 | resetFormData, | ... | ... |