Commit 226aff840e1ae30fd8ffc56607022103c1e96d08

Authored by xp.Huang
2 parents 8e597b2e 1ea0731f

Merge branch 'ww' into 'main'

feat: add AuthIcon component replace ant-design icon

See merge request huang/yun-teng-iot-front!451
  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>
1 export { default as ModeSwitchButton } from './ModeSwitchButton.vue'; 1 export { default as ModeSwitchButton } from './ModeSwitchButton.vue';
2 export { default as CardLayoutButton } from './CardLayoutButton.vue'; 2 export { default as CardLayoutButton } from './CardLayoutButton.vue';
  3 +export { default as AuthIcon } from './AuthIcon.vue';
3 export { 4 export {
4 EnumTableCardMode, 5 EnumTableCardMode,
5 EnumTableChartMode, 6 EnumTableChartMode,
@@ -26,3 +26,26 @@ export function buildShortUUID(prefix = ''): string { @@ -26,3 +26,26 @@ export function buildShortUUID(prefix = ''): string {
26 unique++; 26 unique++;
27 return prefix + '_' + random + unique + String(time); 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 <script setup lang="ts"> 1 <script setup lang="ts">
2 import { List, Card, Button, PaginationProps, Popover, Slider, Tooltip } from 'ant-design-vue'; 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 import { computed, onMounted, reactive, ref, unref } from 'vue'; 4 import { computed, onMounted, reactive, ref, unref } from 'vue';
11 import { OrganizationIdTree, useResetOrganizationTree } from '../../common/organizationIdTree'; 5 import { OrganizationIdTree, useResetOrganizationTree } from '../../common/organizationIdTree';
12 import { 6 import {
@@ -15,7 +9,6 @@ @@ -15,7 +9,6 @@
15 } from '/@/api/configuration/center/configurationCenter'; 9 } from '/@/api/configuration/center/configurationCenter';
16 import { ConfigurationCenterItemsModal } from '/@/api/configuration/center/model/configurationCenterModal'; 10 import { ConfigurationCenterItemsModal } from '/@/api/configuration/center/model/configurationCenterModal';
17 import { PageWrapper } from '/@/components/Page'; 11 import { PageWrapper } from '/@/components/Page';
18 - import { Dropdown } from '/@/components/Dropdown';  
19 import { BasicForm, useForm } from '/@/components/Form'; 12 import { BasicForm, useForm } from '/@/components/Form';
20 import { ConfigurationPermission, searchFormSchema } from './center.data'; 13 import { ConfigurationPermission, searchFormSchema } from './center.data';
21 import { useMessage } from '/@/hooks/web/useMessage'; 14 import { useMessage } from '/@/hooks/web/useMessage';
@@ -23,12 +16,13 @@ @@ -23,12 +16,13 @@
23 import { isDevMode } from '/@/utils/env'; 16 import { isDevMode } from '/@/utils/env';
24 import ConfigurationCenterDrawer from './ConfigurationCenterDrawer.vue'; 17 import ConfigurationCenterDrawer from './ConfigurationCenterDrawer.vue';
25 import { useDrawer } from '/@/components/Drawer'; 18 import { useDrawer } from '/@/components/Drawer';
26 - import { useSyncConfirm } from '/@/hooks/component/useSyncConfirm';  
27 import { getBoundingClientRect } from '/@/utils/domUtils'; 19 import { getBoundingClientRect } from '/@/utils/domUtils';
28 import configurationSrc from '/@/assets/icons/configuration.svg'; 20 import configurationSrc from '/@/assets/icons/configuration.svg';
29 import { cloneDeep } from 'lodash'; 21 import { cloneDeep } from 'lodash';
30 import { usePermission } from '/@/hooks/web/usePermission'; 22 import { usePermission } from '/@/hooks/web/usePermission';
31 import { useGlobSetting } from '/@/hooks/setting'; 23 import { useGlobSetting } from '/@/hooks/setting';
  24 + import { AuthIcon } from '/@/components/Widget';
  25 + import AuthDropDown from '/@/components/Widget/AuthDropDown.vue';
32 26
33 const listColumn = ref(5); 27 const listColumn = ref(5);
34 28
@@ -136,10 +130,8 @@ @@ -136,10 +130,8 @@
136 window.open(`${configurationPrefix}/${isDev ? '?dev=1&' : '?'}configurationId=${record!.id}`); 130 window.open(`${configurationPrefix}/${isDev ? '?dev=1&' : '?'}configurationId=${record!.id}`);
137 }; 131 };
138 132
139 - const { createSyncConfirm } = useSyncConfirm();  
140 const handleDelete = async (record: ConfigurationCenterItemsModal) => { 133 const handleDelete = async (record: ConfigurationCenterItemsModal) => {
141 try { 134 try {
142 - await createSyncConfirm({ iconType: 'warning', content: '是否确认删除操作?' });  
143 await deleteConfigurationCenter([record.id]); 135 await deleteConfigurationCenter([record.id]);
144 createMessage.success('删除成功'); 136 createMessage.success('删除成功');
145 await getListData(); 137 await getListData();
@@ -227,20 +219,44 @@ @@ -227,20 +219,44 @@
227 </template> 219 </template>
228 <template class="ant-card-actions" #actions> 220 <template class="ant-card-actions" #actions>
229 <Tooltip title="预览"> 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 @click="handlePreview(item)" 226 @click="handlePreview(item)"
234 /> 227 />
235 </Tooltip> 228 </Tooltip>
236 <Tooltip title="设计"> 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 @click="handleDesign(item)" 234 @click="handleDesign(item)"
241 /> 235 />
242 </Tooltip> 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 :dropMenuList="[ 260 :dropMenuList="[
245 { 261 {
246 text: '编辑', 262 text: '编辑',
@@ -261,7 +277,7 @@ @@ -261,7 +277,7 @@
261 :trigger="['hover']" 277 :trigger="['hover']"
262 > 278 >
263 <EllipsisOutlined key="ellipsis" /> 279 <EllipsisOutlined key="ellipsis" />
264 - </Dropdown> 280 + </Dropdown> -->
265 </template> 281 </template>
266 <Card.Meta> 282 <Card.Meta>
267 <template #title> 283 <template #title>
@@ -399,6 +399,7 @@ export const step2Schemas: FormSchema[] = [ @@ -399,6 +399,7 @@ export const step2Schemas: FormSchema[] = [
399 field: 'credentialsId', 399 field: 'credentialsId',
400 required: true, 400 required: true,
401 ifShow: false, 401 ifShow: false,
  402 + slot: 'credentialsId',
402 componentProps: { 403 componentProps: {
403 maxLength: 36, 404 maxLength: 36,
404 placeholder: '请输入访问令牌', 405 placeholder: '请输入访问令牌',
@@ -421,6 +422,7 @@ export const step2Schemas: FormSchema[] = [ @@ -421,6 +422,7 @@ export const step2Schemas: FormSchema[] = [
421 field: 'clientId', 422 field: 'clientId',
422 required: true, 423 required: true,
423 ifShow: false, 424 ifShow: false,
  425 + slot: 'clientId',
424 componentProps: { 426 componentProps: {
425 maxLength: 36, 427 maxLength: 36,
426 placeholder: '请输入客户端ID', 428 placeholder: '请输入客户端ID',
@@ -597,6 +599,7 @@ export const TokenSchemas: FormSchema[] = [ @@ -597,6 +599,7 @@ export const TokenSchemas: FormSchema[] = [
597 field: 'credentialsId', 599 field: 'credentialsId',
598 required: true, 600 required: true,
599 ifShow: false, 601 ifShow: false,
  602 + slot: 'credentialsId',
600 componentProps: { 603 componentProps: {
601 maxLength: 36, 604 maxLength: 36,
602 placeholder: '请输入访问令牌', 605 placeholder: '请输入访问令牌',
@@ -12,7 +12,17 @@ @@ -12,7 +12,17 @@
12 <template #clientId="{ field, model }"> 12 <template #clientId="{ field, model }">
13 <div class="flex items-center"> 13 <div class="flex items-center">
14 <Input v-model:value="model[field]" placeholder="请输入客户端ID" /> 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 </div> 26 </div>
17 </template> 27 </template>
18 </BasicForm> 28 </BasicForm>
@@ -26,8 +36,8 @@ @@ -26,8 +36,8 @@
26 import { TokenSchemas, credentialTypeEnum } from '../../config/data'; 36 import { TokenSchemas, credentialTypeEnum } from '../../config/data';
27 import { saveDeviceToken } from '/@/api/device/deviceManager'; 37 import { saveDeviceToken } from '/@/api/device/deviceManager';
28 import { useMessage } from '/@/hooks/web/useMessage'; 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 import { ReloadOutlined } from '@ant-design/icons-vue'; 41 import { ReloadOutlined } from '@ant-design/icons-vue';
32 export default defineComponent({ 42 export default defineComponent({
33 components: { 43 components: {
@@ -35,6 +45,7 @@ @@ -35,6 +45,7 @@
35 BasicForm, 45 BasicForm,
36 Input, 46 Input,
37 ReloadOutlined, 47 ReloadOutlined,
  48 + Tooltip,
38 }, 49 },
39 emits: ['register'], 50 emits: ['register'],
40 setup() { 51 setup() {
@@ -224,6 +235,10 @@ @@ -224,6 +235,10 @@
224 const handleCreateUUID = () => { 235 const handleCreateUUID = () => {
225 setFieldsValue({ clientId: buildUUID() }); 236 setFieldsValue({ clientId: buildUUID() });
226 }; 237 };
  238 +
  239 + const handleCreateCredentialsId = () => {
  240 + setFieldsValue({ credentialsId: randomString() });
  241 + };
227 return { 242 return {
228 registerModal, 243 registerModal,
229 registerForm, 244 registerForm,
@@ -231,6 +246,7 @@ @@ -231,6 +246,7 @@
231 handleCancel, 246 handleCancel,
232 handleOk, 247 handleOk,
233 handleCreateUUID, 248 handleCreateUUID,
  249 + handleCreateCredentialsId,
234 }; 250 };
235 }, 251 },
236 }); 252 });
@@ -4,6 +4,30 @@ @@ -4,6 +4,30 @@
4 <template #addAgree="{ model, field }"> 4 <template #addAgree="{ model, field }">
5 <Checkbox v-model:checked="model[field]" @change="checkedChange">添加协议</Checkbox> 5 <Checkbox v-model:checked="model[field]" @change="checkedChange">添加协议</Checkbox>
6 </template> 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 </BasicForm> 31 </BasicForm>
8 <div> 32 <div>
9 <a-button @click="prevStep">上一步</a-button> 33 <a-button @click="prevStep">上一步</a-button>
@@ -13,13 +37,18 @@ @@ -13,13 +37,18 @@
13 <script lang="ts"> 37 <script lang="ts">
14 import { defineComponent } from 'vue'; 38 import { defineComponent } from 'vue';
15 39
16 - import { Checkbox } from 'ant-design-vue'; 40 + import { Checkbox, Input, Tooltip } from 'ant-design-vue';
17 import { BasicForm, useForm } from '/@/components/Form'; 41 import { BasicForm, useForm } from '/@/components/Form';
18 import { step2Schemas } from '../../config/data'; 42 import { step2Schemas } from '../../config/data';
  43 + import { Icon } from '/@/components/Icon';
  44 + import { buildUUID, randomString } from '/@/utils/uuid';
19 export default defineComponent({ 45 export default defineComponent({
20 components: { 46 components: {
21 BasicForm, 47 BasicForm,
22 Checkbox, 48 Checkbox,
  49 + Input,
  50 + Icon,
  51 + Tooltip,
23 }, 52 },
24 53
25 emits: ['prev', 'next'], 54 emits: ['prev', 'next'],
@@ -105,6 +134,14 @@ @@ -105,6 +134,14 @@
105 validate(); 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 return { 145 return {
109 prevStep, 146 prevStep,
110 registerForm, 147 registerForm,
@@ -113,6 +150,8 @@ @@ -113,6 +150,8 @@
113 validate, 150 validate,
114 resetFieldsValueAndStatus, 151 resetFieldsValueAndStatus,
115 validateStep2Method, 152 validateStep2Method,
  153 + handleGenerateClientId,
  154 + handleGenerateCredentialsId,
116 }; 155 };
117 }, 156 },
118 }); 157 });
@@ -55,15 +55,23 @@ @@ -55,15 +55,23 @@
55 <a-button type="primary" class="mr-4" @click="manageDeviceToken">管理设备凭证</a-button> 55 <a-button type="primary" class="mr-4" @click="manageDeviceToken">管理设备凭证</a-button>
56 <ManageDeviceTokenModal @register="registerModal" /> 56 <ManageDeviceTokenModal @register="registerModal" />
57 </div> 57 </div>
58 - <div v-if="deviceDetail?.deviceInfo?.address" class="mt-4"> 58 + <div class="mt-4">
59 <p>设备位置</p> 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 </div> 69 </div>
62 </div> 70 </div>
63 </template> 71 </template>
64 <script lang="ts"> 72 <script lang="ts">
65 import { defineComponent, ref, unref, nextTick } from 'vue'; 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 import { descSchema } from '../../config/detail.config'; 75 import { descSchema } from '../../config/detail.config';
68 import { useAsyncScript } from '/@/hooks/web/useAsyncScript'; 76 import { useAsyncScript } from '/@/hooks/web/useAsyncScript';
69 import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard'; 77 import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
@@ -78,6 +86,8 @@ @@ -78,6 +86,8 @@
78 86
79 import wz from '/@/assets/images/wz.png'; 87 import wz from '/@/assets/images/wz.png';
80 import { useAsyncQueue } from '../../../localtion/useAsyncQueue'; 88 import { useAsyncQueue } from '../../../localtion/useAsyncQueue';
  89 + import locationImage from '/@/assets/icons/location.svg';
  90 +
81 export default defineComponent({ 91 export default defineComponent({
82 components: { 92 components: {
83 Image, 93 Image,
@@ -86,6 +96,7 @@ @@ -86,6 +96,7 @@
86 QuestionCircleOutlined, 96 QuestionCircleOutlined,
87 BasicModal, 97 BasicModal,
88 Tooltip, 98 Tooltip,
  99 + Empty,
89 }, 100 },
90 props: { 101 props: {
91 deviceDetail: { 102 deviceDetail: {
@@ -197,6 +208,7 @@ @@ -197,6 +208,7 @@
197 DeviceTypeEnum, 208 DeviceTypeEnum,
198 copyTopic, 209 copyTopic,
199 remoteConnectiondGateway, 210 remoteConnectiondGateway,
  211 + locationImage,
200 }; 212 };
201 }, 213 },
202 }); 214 });
@@ -2,9 +2,14 @@ @@ -2,9 +2,14 @@
2 import { PageWrapper } from '/@/components/Page'; 2 import { PageWrapper } from '/@/components/Page';
3 import { BasicForm, useForm } from '/@/components/Form'; 3 import { BasicForm, useForm } from '/@/components/Form';
4 import { List, Button, Tooltip, Card, PaginationProps, Image } from 'ant-design-vue'; 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 import { computed, onMounted, reactive, ref, unref } from 'vue'; 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 import { Authority } from '/@/components/Authority'; 13 import { Authority } from '/@/components/Authority';
9 import { 14 import {
10 deviceConfigDelete, 15 deviceConfigDelete,
@@ -12,7 +17,6 @@ @@ -12,7 +17,6 @@
12 setDeviceProfileIsDefaultApi, 17 setDeviceProfileIsDefaultApi,
13 } from '/@/api/device/deviceConfigApi'; 18 } from '/@/api/device/deviceConfigApi';
14 import { ProfileRecord } from '/@/api/device/model/deviceConfigModel'; 19 import { ProfileRecord } from '/@/api/device/model/deviceConfigModel';
15 - import { Dropdown } from '/@/components/Dropdown';  
16 import { 20 import {
17 defaultObj, 21 defaultObj,
18 searchFormSchema, 22 searchFormSchema,
@@ -20,14 +24,13 @@ @@ -20,14 +24,13 @@
20 ProductPermission, 24 ProductPermission,
21 } from './device.profile.data'; 25 } from './device.profile.data';
22 import { useMessage } from '/@/hooks/web/useMessage'; 26 import { useMessage } from '/@/hooks/web/useMessage';
23 - import { useSyncConfirm } from '/@/hooks/component/useSyncConfirm';  
24 import DeviceProfileModal from './DeviceProfileModal.vue'; 27 import DeviceProfileModal from './DeviceProfileModal.vue';
25 import DeviceProfileDrawer from './DeviceProfileDrawer.vue'; 28 import DeviceProfileDrawer from './DeviceProfileDrawer.vue';
26 import { useModal } from '/@/components/Modal'; 29 import { useModal } from '/@/components/Modal';
27 import { useDrawer } from '/@/components/Drawer'; 30 import { useDrawer } from '/@/components/Drawer';
28 import productDefault from '/@/assets/icons/product-default.svg'; 31 import productDefault from '/@/assets/icons/product-default.svg';
29 - import { usePermission } from '/@/hooks/web/usePermission';  
30 import { useRoute } from 'vue-router'; 32 import { useRoute } from 'vue-router';
  33 + import AuthDropDown from '/@/components/Widget/AuthDropDown.vue';
31 34
32 defineProps<{ 35 defineProps<{
33 mode: EnumTableCardMode; 36 mode: EnumTableCardMode;
@@ -42,7 +45,6 @@ @@ -42,7 +45,6 @@
42 const IMAGE_FALLBACK = productDefault; 45 const IMAGE_FALLBACK = productDefault;
43 46
44 const { createMessage } = useMessage(); 47 const { createMessage } = useMessage();
45 - const { createSyncConfirm } = useSyncConfirm();  
46 48
47 const [register, { getFieldsValue, setFieldsValue }] = useForm({ 49 const [register, { getFieldsValue, setFieldsValue }] = useForm({
48 showAdvancedButton: true, 50 showAdvancedButton: true,
@@ -105,40 +107,6 @@ @@ -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 const handleModeChange = (mode: EnumTableCardMode) => { 110 const handleModeChange = (mode: EnumTableCardMode) => {
143 emit('changeMode', mode); 111 emit('changeMode', mode);
144 }; 112 };
@@ -163,12 +131,10 @@ @@ -163,12 +131,10 @@
163 }; 131 };
164 132
165 const handleShowDetail = (record: ProfileRecord) => { 133 const handleShowDetail = (record: ProfileRecord) => {
166 - if (!unref(getHasDetailFlag)) return;  
167 openDrawer(true, { record }); 134 openDrawer(true, { record });
168 }; 135 };
169 136
170 const handleUpdate = (record: ProfileRecord) => { 137 const handleUpdate = (record: ProfileRecord) => {
171 - if (!unref(getHasUpdateFlag)) return;  
172 openModal(true, { 138 openModal(true, {
173 record, 139 record,
174 isUpdate: true, 140 isUpdate: true,
@@ -177,7 +143,6 @@ @@ -177,7 +143,6 @@
177 143
178 const handleDelete = async (id: string[]) => { 144 const handleDelete = async (id: string[]) => {
179 try { 145 try {
180 - await createSyncConfirm({ iconType: 'warning', content: '是否确认删除操作?' });  
181 await deviceConfigDelete(id); 146 await deviceConfigDelete(id);
182 createMessage.success('删除成功'); 147 createMessage.success('删除成功');
183 await getDataSource(); 148 await getDataSource();
@@ -268,22 +233,43 @@ @@ -268,22 +233,43 @@
268 </template> 233 </template>
269 <template class="ant-card-actions" #actions> 234 <template class="ant-card-actions" #actions>
270 <Tooltip title="详情"> 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 @click.stop="handleShowDetail(item)" 240 @click.stop="handleShowDetail(item)"
275 /> 241 />
276 </Tooltip> 242 </Tooltip>
277 <Tooltip title="编辑"> 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 @click.stop="handleUpdate(item)" 248 @click.stop="handleUpdate(item)"
282 /> 249 />
283 </Tooltip> 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 </template> 273 </template>
288 <Card.Meta> 274 <Card.Meta>
289 <template #title> 275 <template #title>
@@ -308,7 +294,10 @@ @@ -308,7 +294,10 @@
308 294
309 <style lang="less" scoped> 295 <style lang="less" scoped>
310 .profile-list:deep(.ant-image-img) { 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 </style> 303 </style>
@@ -28,10 +28,13 @@ @@ -28,10 +28,13 @@
28 field: 'scriptName', 28 field: 'scriptName',
29 label: '转换脚本', 29 label: '转换脚本',
30 render: (value: string) => { 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,12 +261,14 @@ export const columns: BasicColumn[] = [
261 title: '默认配置', 261 title: '默认配置',
262 dataIndex: 'default', 262 dataIndex: 'default',
263 width: 80, 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 title: '描述', 268 title: '描述',
268 dataIndex: 'description', 269 dataIndex: 'description',
269 width: 90, 270 width: 90,
  271 + ellipsis: true,
270 }, 272 },
271 { 273 {
272 title: '创建时间', 274 title: '创建时间',
@@ -8,7 +8,9 @@ @@ -8,7 +8,9 @@
8 placeholder="请选择转换脚本" 8 placeholder="请选择转换脚本"
9 v-model:value="selectScript.script" 9 v-model:value="selectScript.script"
10 style="width: 305px" 10 style="width: 305px"
  11 + show-search
11 :options="selectOptions" 12 :options="selectOptions"
  13 + :filter-option="handleSearch"
12 allowClear 14 allowClear
13 /> 15 />
14 </div> 16 </div>
@@ -113,6 +115,11 @@ @@ -113,6 +115,11 @@
113 const setFormData = (v) => { 115 const setFormData = (v) => {
114 selectScript.script = v?.scriptId; 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 defineExpose({ 123 defineExpose({
117 getFormData, 124 getFormData,
118 resetFormData, 125 resetFormData,