Commit 055fb44c1f650e3bbf74716eca7a908d7dcc6bd4

Authored by ww
2 parents c75b2494 36bebfb5

Merge branch 'main_dev' into feat/rule-engine-designer

Showing 100 changed files with 1383 additions and 334 deletions

Too many changes to show.

To preserve performance only 100 of 142 files are displayed.

... ... @@ -127,6 +127,9 @@ export interface MasterDeviceList {
127 127 label?: string;
128 128 value?: string;
129 129 alias?: string;
  130 + codeType?: string;
  131 + code?: string;
  132 + [key: string]: string | undefined;
130 133 }
131 134
132 135 export interface ComponentInfoDetail {
... ...
... ... @@ -167,6 +167,7 @@ export interface DeviceRecord {
167 167 creator: string;
168 168 createTime: string;
169 169 codeType?: string;
  170 + code?: string;
170 171 name: string;
171 172 tenantId: string;
172 173 transportType: string;
... ...
... ... @@ -16,6 +16,7 @@
16 16 :formProps="getProps"
17 17 :allDefaultValues="defaultValueRef"
18 18 :formModel="formModel"
  19 + :validateFields="validateFields"
19 20 :setFormModel="setFormModel"
20 21 >
21 22 <template #[item]="data" v-for="item in Object.keys($slots)">
... ... @@ -229,10 +230,10 @@
229 230
230 231 function setFormModel(key: string, value: any) {
231 232 formModel[key] = value;
232   - const { validateTrigger } = unref(getBindValue);
233   - if (!validateTrigger || validateTrigger === 'change') {
234   - validateFields([key]).catch((_) => {});
235   - }
  233 + // const { validateTrigger } = unref(getBindValue);
  234 + // if (!validateTrigger || validateTrigger === 'change') {
  235 + // validateFields([key]).catch((_) => {});
  236 + // }
236 237 }
237 238
238 239 function handleEnterPress(e: KeyboardEvent) {
... ...
... ... @@ -14,6 +14,7 @@
14 14 import { upperFirst, cloneDeep } from 'lodash-es';
15 15 import { useItemLabelWidth } from '../hooks/useLabelWidth';
16 16 import { useI18n } from '/@/hooks/web/useI18n';
  17 + import { NamePath, ValidateOptions } from 'ant-design-vue/lib/form/interface';
17 18
18 19 export default defineComponent({
19 20 name: 'BasicFormItem',
... ... @@ -39,6 +40,12 @@
39 40 type: Function as PropType<(key: string, value: any) => void>,
40 41 default: null,
41 42 },
  43 + validateFields: {
  44 + type: Function as PropType<
  45 + (nameList?: NamePath[], options?: ValidateOptions) => Promise<any>
  46 + >,
  47 + default: null,
  48 + },
42 49 tableAction: {
43 50 type: Object as PropType<TableActionType>,
44 51 },
... ... @@ -208,6 +215,7 @@
208 215 rules[characterInx].message ||
209 216 t('component.form.maxTip', [rules[characterInx].max] as Recordable);
210 217 }
  218 + rules.forEach((item) => !item.trigger && (item.trigger = 'change'));
211 219 return rules;
212 220 }
213 221
... ... @@ -234,6 +242,10 @@
234 242 const value = target ? (isCheck ? target.checked : target.value) : e;
235 243 props.setFormModel(field, value);
236 244 },
  245 + onBlur: (...args) => {
  246 + unref(getComponentsProps)?.onBlur?.(...args);
  247 + props.validateFields([field], { triggerName: 'blur' }).catch((_) => {});
  248 + },
237 249 };
238 250 const Comp = componentMap.get(component) as ReturnType<typeof defineComponent>;
239 251
... ...
1 1 <script lang="ts" setup>
2 2 import { Button } from 'ant-design-vue';
3   - import { nextTick, ref, unref, watch } from 'vue';
  3 + import { nextTick, ref, watch } from 'vue';
4 4 import { BasicForm, useForm } from '/@/components/Form';
5 5 import { BasicModal } from '/@/components/Modal';
6 6 import { PlusCircleOutlined } from '@ant-design/icons-vue';
... ... @@ -19,8 +19,6 @@
19 19 }
20 20 );
21 21
22   - const dataType = ref(props.dataType); //获取数据类型
23   -
24 22 const emit = defineEmits(['update:value']);
25 23
26 24 const [
... ... @@ -46,15 +44,17 @@
46 44 show.value = false;
47 45 };
48 46
49   - watch(
50   - () => props.dataType,
51   - (value) => {
52   - dataType.value = value;
  47 + watch(show, async (value) => {
  48 + if (value) {
  49 + await nextTick();
53 50 updateSchema([
54   - { field: FormFieldsEnum.ZOOM_FACTOR, ifShow: unref(dataType) == 'BOOL' ? false : true },
  51 + {
  52 + field: FormFieldsEnum.ZOOM_FACTOR,
  53 + ifShow: props.dataType == DataTypeEnum.IS_BOOL ? false : true,
  54 + },
55 55 ]);
56 56 }
57   - );
  57 + });
58 58
59 59 watch(
60 60 () => props.value,
... ...
1 1 import type { FormProps, FormActionType, UseFormReturnType, FormSchema } from '../types/form';
2   -import type { NamePath } from 'ant-design-vue/lib/form/interface';
  2 +import type { NamePath, ValidateOptions } from 'ant-design-vue/lib/form/interface';
3 3 import type { DynamicProps } from '/#/utils';
4 4 import { ref, onUnmounted, unref, nextTick, watch } from 'vue';
5 5 import { isProdMode } from '/@/utils/env';
... ... @@ -112,9 +112,12 @@ export function useForm(props?: Props): UseFormReturnType {
112 112 return form.validate(nameList);
113 113 },
114 114
115   - validateFields: async (nameList?: NamePath[]): Promise<Recordable> => {
  115 + validateFields: async (
  116 + nameList?: NamePath[],
  117 + options?: ValidateOptions
  118 + ): Promise<Recordable> => {
116 119 const form = await getForm();
117   - return form.validateFields(nameList);
  120 + return form.validateFields(nameList, options);
118 121 },
119 122 };
120 123
... ...
1 1 import type { ComputedRef, Ref } from 'vue';
2 2 import type { FormProps, FormSchema, FormActionType } from '../types/form';
3   -import type { NamePath } from 'ant-design-vue/lib/form/interface';
  3 +import type { NamePath, ValidateOptions } from 'ant-design-vue/lib/form/interface';
4 4 import { unref, toRaw } from 'vue';
5 5 import { isArray, isFunction, isObject, isString } from '/@/utils/is';
6 6 import { deepMerge } from '/@/utils';
... ... @@ -206,8 +206,8 @@ export function useFormEvents({
206 206 });
207 207 }
208 208
209   - async function validateFields(nameList?: NamePath[] | undefined) {
210   - return unref(formElRef)?.validateFields(nameList);
  209 + async function validateFields(nameList?: NamePath[] | undefined, options?: ValidateOptions) {
  210 + return unref(formElRef)?.validateFields(nameList, options);
211 211 }
212 212
213 213 async function validate(nameList?: NamePath[] | undefined) {
... ...
1   -import type { NamePath, RuleObject } from 'ant-design-vue/lib/form/interface';
  1 +import type { NamePath, RuleObject, ValidateOptions } from 'ant-design-vue/lib/form/interface';
2 2 import type { VNode } from 'vue';
3 3 import type { ButtonProps as AntdButtonProps } from '/@/components/Button';
4 4 import type { FormItem } from './formItem';
... ... @@ -39,7 +39,7 @@ export interface FormActionType {
39 39 prefixField: string | undefined,
40 40 first?: boolean | undefined
41 41 ) => Promise<void>;
42   - validateFields: (nameList?: NamePath[]) => Promise<any>;
  42 + validateFields: (nameList?: NamePath[], options?: ValidateOptions) => Promise<any>;
43 43 validate: (nameList?: NamePath[]) => Promise<any>;
44 44 scrollToField: (name: NamePath, options?: ScrollOptions) => Promise<void>;
45 45 }
... ...
... ... @@ -33,6 +33,7 @@
33 33 import { openWindow } from '/@/utils';
34 34
35 35 import { useOpenKeys } from './useOpenKeys';
  36 + import { useMenuActiveFix } from '/@/hooks/business/useMenuActiveFix';
36 37 export default defineComponent({
37 38 name: 'SimpleMenu',
38 39 components: {
... ... @@ -120,7 +121,9 @@
120 121 isClickGo.value = false;
121 122 return;
122 123 }
123   - const path = (route || unref(currentRoute)).path;
  124 +
  125 + let { flag, path } = useMenuActiveFix(route || unref(currentRoute));
  126 + path = flag ? path : (route || unref(currentRoute)).path;
124 127
125 128 menuState.activeName = path;
126 129
... ...
... ... @@ -29,7 +29,6 @@ export function useOpenKeys(
29 29 return;
30 30 }
31 31 const keys = getAllParentPath(menuList, path);
32   -
33 32 if (!unref(accordion)) {
34 33 menuState.openNames = uniq([...menuState.openNames, ...keys]);
35 34 } else {
... ...
... ... @@ -48,6 +48,7 @@
48 48 'update:value',
49 49 'change',
50 50 'check',
  51 + 'unSelectAll',
51 52 'update:searchValue',
52 53 ],
53 54 setup(props, { attrs, slots, emit, expose }) {
... ... @@ -188,6 +189,7 @@
188 189 }
189 190
190 191 function checkAll(checkAll: boolean) {
  192 + if (!checkAll) emit('unSelectAll');
191 193 state.checkedKeys = checkAll ? getEnabledKeys() : ([] as Keys);
192 194 }
193 195
... ...
... ... @@ -2,17 +2,23 @@
2 2 import { isNumber } from 'lodash';
3 3 import videoJs, { VideoJsPlayer, VideoJsPlayerOptions } from 'video.js';
4 4 import 'video.js/dist/video-js.css';
5   - import { computed, CSSProperties, onMounted, onUnmounted, ref, unref } from 'vue';
  5 + import { computed, CSSProperties, onMounted, onUnmounted, ref, toRaw, unref } from 'vue';
6 6 import { useDesign } from '/@/hooks/web/useDesign';
7 7 import { getJwtToken, getShareJwtToken } from '/@/utils/auth';
8 8 import { isShareMode } from '/@/views/sys/share/hook';
9 9 import 'videojs-flvjs-es6';
10 10 const { prefixCls } = useDesign('basic-video-play');
11 11
12   - const props = defineProps<{
13   - options?: VideoJsPlayerOptions;
14   - withToken?: boolean;
15   - }>();
  12 + const props = withDefaults(
  13 + defineProps<{
  14 + options?: VideoJsPlayerOptions;
  15 + withToken?: boolean;
  16 + immediateInitOnMounted?: boolean;
  17 + }>(),
  18 + {
  19 + immediateInitOnMounted: true,
  20 + }
  21 + );
16 22
17 23 const emit = defineEmits<{
18 24 (event: 'ready', instance?: Nullable<VideoJsPlayer>): void;
... ... @@ -68,8 +74,18 @@
68 74 });
69 75 };
70 76
  77 + const customInit = (getOptionsFn: (optios: VideoJsPlayerOptions) => VideoJsPlayerOptions) => {
  78 + return (videoPlayInstance.value = videoJs(
  79 + unref(videoPlayEl)!,
  80 + getOptionsFn(toRaw(unref(getOptions))),
  81 + () => {
  82 + emit('ready', unref(videoPlayInstance));
  83 + }
  84 + ));
  85 + };
  86 +
71 87 onMounted(() => {
72   - init();
  88 + props.immediateInitOnMounted && init();
73 89 });
74 90
75 91 onUnmounted(() => {
... ... @@ -79,6 +95,7 @@
79 95 });
80 96
81 97 defineExpose({
  98 + customInit,
82 99 reloadPlayer: init,
83 100 getInstance: () => unref(videoPlayInstance),
84 101 });
... ...
  1 +import { RouteLocationNormalizedLoaded } from 'vue-router';
  2 +
  3 +const menuMap = new Map();
  4 +
  5 +menuMap.set('/visual/board/detail/:boardId/:boardName?', '/visual/board');
  6 +
  7 +export const useMenuActiveFix = (route: RouteLocationNormalizedLoaded) => {
  8 + let flag = false;
  9 + let path;
  10 +
  11 + const matchPath = route.matched.map((item) => item.path);
  12 + const needFixMenus: string[] = Array.from(menuMap.keys());
  13 +
  14 + for (const item of matchPath) {
  15 + for (const menu of needFixMenus) {
  16 + if (menu === item) {
  17 + flag = true;
  18 + path = menuMap.get(menu);
  19 + break;
  20 + }
  21 + }
  22 + }
  23 +
  24 + return {
  25 + flag,
  26 + path,
  27 + };
  28 +};
... ...
... ... @@ -54,10 +54,11 @@
54 54 field: FiledKey.WEBSITE,
55 55 label: handleDecode(t('routes.aboutSoftware.websiteLabel')),
56 56 render: (val: string) => {
  57 + let joinWww = val.substring(0, 8) + 'www.' + val.substring(8);
57 58 return h(
58 59 'span',
59   - { class: 'text-blue-500 cursor-pointer', onClick: () => open(val) },
60   - val
  60 + { class: 'text-blue-500 cursor-pointer', onClick: () => open(joinWww) },
  61 + joinWww
61 62 );
62 63 },
63 64 },
... ...
... ... @@ -19,6 +19,7 @@
19 19 import { useRootSetting } from '/@/hooks/setting/useRootSetting';
20 20 import { useAppInject } from '/@/hooks/web/useAppInject';
21 21 import { useDesign } from '/@/hooks/web/useDesign';
  22 + import { OUTSIDE_LINK_PREFIX } from '/@/router/helper/routeHelper';
22 23
23 24 export default defineComponent({
24 25 name: 'LayoutMenu',
... ... @@ -113,6 +114,11 @@
113 114 */
114 115
115 116 function handleMenuClick(path: string) {
  117 + if (path.startsWith(OUTSIDE_LINK_PREFIX)) {
  118 + path = path.replace(OUTSIDE_LINK_PREFIX, '');
  119 + window.open(path);
  120 + return;
  121 + }
116 122 go(path);
117 123 }
118 124
... ... @@ -183,7 +189,6 @@
183 189 padding: 10px 4px 10px 10px;
184 190
185 191 img {
186   - width: @logo-width;
187 192 height: @logo-width;
188 193 }
189 194 }
... ...
... ... @@ -6,6 +6,7 @@ import { cloneDeep, omit } from 'lodash-es';
6 6 import { warn } from '/@/utils/log';
7 7 import { createRouter, createWebHashHistory } from 'vue-router';
8 8
  9 +export const OUTSIDE_LINK_PREFIX = '/outside/link';
9 10 export type LayoutMapKey = 'LAYOUT';
10 11 const IFRAME = () => import('/@/views/sys/iframe/FrameBlank.vue');
11 12
... ... @@ -81,6 +82,9 @@ export function transformObjToRoute<T = AppRouteModule>(routeList: AppRouteModul
81 82 route.meta = meta;
82 83 }
83 84 }
  85 + if (!route.path.startsWith('/') && route.meta.isLink) {
  86 + route.path = `${OUTSIDE_LINK_PREFIX}${route.path}`;
  87 + }
84 88 route.children && asyncImportRoute(route.children);
85 89 });
86 90 return routeList as unknown as T[];
... ...
... ... @@ -16,6 +16,7 @@
16 16 mode="multiple"
17 17 v-model:value="model[field]"
18 18 :options="alarmContactOptions.map((item) => ({ value: item.value, label: item.label }))"
  19 + @change="handleChange"
19 20 >
20 21 <template #dropdownRender="{ menuNode: menu }">
21 22 <v-nodes :vnodes="menu" />
... ... @@ -82,6 +83,7 @@
82 83 const [registerAlarmContactDrawer, { openDrawer }] = useDrawer();
83 84 async function handleSuccess() {
84 85 //获取告警联系人
  86 + if (!unref(orgId)) return;
85 87 const res = await byOrgIdGetAlarmContact(orgId.value);
86 88 if (res) {
87 89 alarmContactOptions.value = res.map((m) => {
... ... @@ -91,6 +93,10 @@
91 93 alarmContactOptions.value = [];
92 94 }
93 95 }
  96 +
  97 + const handleChange = () => {
  98 + validateFields(['alarmContactId']);
  99 + };
94 100 // 新增或编辑
95 101 const handleOpenAlarmContact = () => {
96 102 openDrawer(true, {
... ... @@ -100,7 +106,10 @@
100 106 const isUpdate = ref(true);
101 107 let allData: any = reactive({});
102 108 const editId = ref('');
103   - const [registerForm, { validate, setFieldsValue, resetFields, updateSchema }] = useForm({
  109 + const [
  110 + registerForm,
  111 + { validate, setFieldsValue, resetFields, updateSchema, validateFields },
  112 + ] = useForm({
104 113 labelWidth: 120,
105 114 schemas: formSchema,
106 115 showActionButtonGroup: false,
... ... @@ -191,6 +200,7 @@
191 200 handleOpenAlarmContact,
192 201 registerAlarmContactDrawer,
193 202 handleSuccess,
  203 + handleChange,
194 204 };
195 205 },
196 206 });
... ...
... ... @@ -37,13 +37,21 @@
37 37 </a-button>
38 38 </template>
39 39 <template #status="{ record }">
40   - <Switch
41   - :checked="record.status === 1"
42   - :loading="record.pendingStatus"
43   - checkedChildren="启用"
44   - unCheckedChildren="禁用"
45   - @change="(checked:boolean)=>statusChange(checked,record)"
46   - />
  40 + <Authority value="api:yt:alarm:profile:status">
  41 + <Switch
  42 + :checked="record.status === 1"
  43 + :loading="record.pendingStatus"
  44 + checkedChildren="启用"
  45 + unCheckedChildren="禁用"
  46 + @change="(checked:boolean)=>statusChange(checked,record)"
  47 + />
  48 + </Authority>
  49 + <Tag
  50 + v-if="!hasPermission('api:yt:alarm:profile:status')"
  51 + :color="record.status ? 'green' : 'red'"
  52 + >
  53 + {{ record.status ? '启用' : '禁用' }}
  54 + </Tag>
47 55 </template>
48 56 <template #action="{ record }">
49 57 <TableAction
... ... @@ -88,7 +96,7 @@
88 96 import { useResetOrganizationTree, OrganizationIdTree } from '/@/views/common/organizationIdTree';
89 97 import { deleteAlarmConfig, queryAlarmConfig } from '/@/api/alarm/config/alarmConfig';
90 98 import { searchFormSchema, columns } from './config.data';
91   - import { Modal, Popconfirm } from 'ant-design-vue';
  99 + import { Modal, Popconfirm, Tag } from 'ant-design-vue';
92 100 import { JsonPreview } from '/@/components/CodeEditor';
93 101 import { findDictItemByCode } from '/@/api/system/dict';
94 102 import { alarmContactGetPage } from '/@/api/device/deviceConfigApi';
... ... @@ -97,6 +105,7 @@
97 105 import { putAlarmConfigStatus } from '/@/api/alarm/config/alarmConfig';
98 106 import { useMessage } from '/@/hooks/web/useMessage';
99 107 import { Authority } from '/@/components/Authority';
  108 + import { usePermission } from '/@/hooks/web/usePermission';
100 109
101 110 export default defineComponent({
102 111 components: {
... ... @@ -108,8 +117,10 @@
108 117 Switch,
109 118 Authority,
110 119 Popconfirm,
  120 + Tag,
111 121 },
112 122 setup() {
  123 + const { hasPermission } = usePermission();
113 124 const searchInfo = reactive<Recordable>({});
114 125 const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo);
115 126 // 刷新
... ... @@ -250,6 +261,7 @@
250 261 showAlarmContact,
251 262 showMessageMode,
252 263 statusChange,
  264 + hasPermission,
253 265 };
254 266 },
255 267 });
... ...
... ... @@ -17,10 +17,21 @@ export enum ConfigurationPermission {
17 17 UPDATE = 'api:yt:dataview:center:update',
18 18 DELETE = 'api:yt:dataview:center:delete',
19 19 SHARE = 'api:yt:dataview:center:share',
20   - DESIGN = 'api:yt:dataview:center:get_configuration_info:design',
  20 + // DESIGN = 'api:yt:dataview:center:get_configuration_info:design',
  21 + DESIGN = 'api:yt:dataview:center:get_dataview_info:design',
21 22 PREVIEW = 'api:yt:dataview:center:get_configuration_info:preview',
22 23 PUBLISH = 'api:yt:dataview:center:publish',
23 24 // CANCEL_PUBLISH = 'api:yt:dataview:center:cancel_publish',
  25 + PUBLISH_INTERFACE = 'api:yt:dataview:center:public_interface',
  26 +}
  27 +
  28 +export enum PublicInterface {
  29 + CREATE = 'api:yt:dataview:center:public_interface:post',
  30 + LIST = 'api:yt:dataview:center:public_interface:list',
  31 + UPDATE = 'api:yt:dataview:center:public_interface:update',
  32 + DELETE = 'api:yt:dataview:center:public_interface:delete',
  33 + PUBLISH = 'api:yt:dataview:center:public_interface:publish',
  34 + CANCEL_PUBLISH = 'api:yt:dataview:center:public_interface:cancel',
24 35 }
25 36
26 37 // 查询字段
... ...
... ... @@ -218,7 +218,10 @@
218 218 <Authority v-if="!isCustomerUser" :value="ConfigurationPermission.CREATE">
219 219 <Button type="primary" @click="handleCreateOrUpdate()"> 新增大屏 </Button>
220 220 </Authority>
221   - <Authority v-if="hasPublicInterfacePermission" :value="ConfigurationPermission.CREATE">
  221 + <Authority
  222 + v-if="hasPublicInterfacePermission"
  223 + :value="ConfigurationPermission.PUBLISH_INTERFACE"
  224 + >
222 225 <Button type="primary" @click="handleCreateOrUpdatePublicApi()">公共接口管理</Button>
223 226 </Authority>
224 227 <CardLayoutButton v-model:value="listColumn" @change="handleCardLayoutChange" />
... ... @@ -280,6 +283,7 @@
280 283 </Tooltip>
281 284 <Tooltip v-if="!isCustomerUser" title="设计">
282 285 <AuthIcon
  286 + :auth="ConfigurationPermission.DESIGN"
283 287 :disabled="item.state === 1"
284 288 icon="ant-design:edit-outlined"
285 289 @click="handleDesign(item)"
... ...
... ... @@ -9,23 +9,30 @@
9 9 <a-button type="link" class="ml-2" @click="handleRecordContent(record)"> 查看 </a-button>
10 10 </template>
11 11 <template #toolbar>
12   - <a-button type="primary" @click="handleCreateOrEdit(null)"> 新增公共接口 </a-button>
13   - <Popconfirm
14   - title="您确定要批量删除数据"
15   - ok-text="确定"
16   - cancel-text="取消"
17   - @confirm="handleDeleteOrBatchDelete(null)"
18   - >
19   - <a-button color="error" :disabled="hasBatchDelete"> 批量删除 </a-button>
20   - </Popconfirm>
21   - <Popconfirm
22   - title="您确定要批量发布"
23   - ok-text="确定"
24   - cancel-text="取消"
25   - @confirm="handleBatchPublish('batchPublish')"
26   - >
27   - <a-button color="error" :disabled="hasBatchPublish"> 批量发布 </a-button>
28   - </Popconfirm>
  12 + <Authority :value="PublicInterface.CREATE">
  13 + <a-button type="primary" @click="handleCreateOrEdit(null)"> 新增公共接口 </a-button>
  14 + </Authority>
  15 +
  16 + <Authority :value="PublicInterface.DELETE">
  17 + <Popconfirm
  18 + title="您确定要批量删除数据"
  19 + ok-text="确定"
  20 + cancel-text="取消"
  21 + @confirm="handleDeleteOrBatchDelete(null)"
  22 + >
  23 + <a-button color="error" :disabled="hasBatchDelete"> 批量删除 </a-button>
  24 + </Popconfirm>
  25 + </Authority>
  26 + <Authority :value="PublicInterface.PUBLISH">
  27 + <Popconfirm
  28 + title="您确定要批量发布"
  29 + ok-text="确定"
  30 + cancel-text="取消"
  31 + @confirm="handleBatchPublish('batchPublish')"
  32 + >
  33 + <a-button color="error" :disabled="hasBatchPublish"> 批量发布 </a-button>
  34 + </Popconfirm>
  35 + </Authority>
29 36 <!-- <Popconfirm
30 37 title="您确定要批量取消发布"
31 38 ok-text="确定"
... ... @@ -41,6 +48,7 @@
41 48 {
42 49 label: '发布',
43 50 icon: 'ant-design:node-expand-outlined',
  51 + auth: PublicInterface.PUBLISH,
44 52 onClick: handlePublish.bind(null, 'publish', record),
45 53 ifShow: () => {
46 54 return record.state === 0 && record.creator === userId;
... ... @@ -49,6 +57,7 @@
49 57 {
50 58 label: '取消发布',
51 59 icon: 'ant-design:node-collapse-outlined',
  60 + auth: PublicInterface.CANCEL_PUBLISH,
52 61 onClick: handlePublish.bind(null, 'canelPublish', record),
53 62 ifShow: () => {
54 63 return record.state === 1 && record.creator === userId;
... ... @@ -57,6 +66,7 @@
57 66 {
58 67 label: '修改',
59 68 icon: 'clarity:note-edit-line',
  69 + auth: PublicInterface.UPDATE,
60 70 onClick: handleCreateOrEdit.bind(null, record),
61 71 ifShow: () => {
62 72 return record.state === 0 && record.creator === userId;
... ... @@ -65,6 +75,7 @@
65 75 {
66 76 label: '删除',
67 77 icon: 'ant-design:delete-outlined',
  78 + auth: PublicInterface.DELETE,
68 79 color: 'error',
69 80 ifShow: () => {
70 81 return record.state === 0 && record.creator === userId;
... ... @@ -99,6 +110,8 @@
99 110 import { useMessage } from '/@/hooks/web/useMessage';
100 111 import { USER_INFO_KEY } from '/@/enums/cacheEnum';
101 112 import { getAuthCache } from '/@/utils/auth';
  113 + import { PublicInterface } from '../config';
  114 + import { Authority } from '/@/components/Authority';
102 115
103 116 const userInfo = getAuthCache(USER_INFO_KEY) as any;
104 117
... ... @@ -119,7 +132,7 @@
119 132 },
120 133 useSearchForm: true,
121 134 actionColumn: {
122   - width: 150,
  135 + width: 180,
123 136 title: '操作',
124 137 dataIndex: 'action',
125 138 slots: { customRender: 'action' },
... ...
... ... @@ -125,23 +125,25 @@ export const step1Schemas: FormSchema[] = [
125 125 dynamicRules({ values }) {
126 126 return [
127 127 {
128   - required:
129   - (values?.transportType === TransportTypeEnum.TCP &&
130   - values?.deviceType === DeviceTypeEnum.SENSOR) ||
131   - values?.deviceType === DeviceTypeEnum.GATEWAY,
  128 + required: values?.transportType === TransportTypeEnum.TCP,
132 129 message: '请输入设备标识符',
133 130 },
134 131 ];
135 132 },
136   - ifShow: ({ values }) =>
137   - values?.transportType === TransportTypeEnum.TCP &&
138   - (values.deviceType === DeviceTypeEnum.SENSOR || values.deviceType === DeviceTypeEnum.GATEWAY),
139   - componentProps: ({}) => {
  133 + // ifShow: ({ values }) =>
  134 + // values?.transportType === TransportTypeEnum.TCP &&
  135 + // (values.deviceType === DeviceTypeEnum.SENSOR || values.deviceType === DeviceTypeEnum.GATEWAY),
  136 + ifShow: ({ values }) => values?.transportType === TransportTypeEnum.TCP,
  137 + componentProps: ({ formActionType }) => {
  138 + const { setFieldsValue } = formActionType;
140 139 return {
141 140 options: [
142 141 { label: '自定义', value: TaskTypeEnum.CUSTOM },
143 142 { label: 'ModBus', value: TaskTypeEnum.MODBUS_RTU },
144 143 ],
  144 + onChange() {
  145 + setFieldsValue({ addressCode: null });
  146 + },
145 147 };
146 148 },
147 149 },
... ... @@ -167,11 +169,17 @@ export const step1Schemas: FormSchema[] = [
167 169 minValue: 0,
168 170 disabledSwitch: true,
169 171 },
  172 + // ifShow: ({ values }) => {
  173 + // return (
  174 + // values?.transportType === TransportTypeEnum.TCP &&
  175 + // (values.deviceType === DeviceTypeEnum.SENSOR ||
  176 + // values.deviceType === DeviceTypeEnum.GATEWAY) &&
  177 + // values?.codeType === TaskTypeEnum.MODBUS_RTU
  178 + // );
  179 + // },
170 180 ifShow: ({ values }) => {
171 181 return (
172 182 values?.transportType === TransportTypeEnum.TCP &&
173   - (values.deviceType === DeviceTypeEnum.SENSOR ||
174   - values.deviceType === DeviceTypeEnum.GATEWAY) &&
175 183 values?.codeType === TaskTypeEnum.MODBUS_RTU
176 184 );
177 185 },
... ...
... ... @@ -43,7 +43,9 @@ export const descSchema = (emit: EmitType): DescItem[] => {
43 43 type: 'link',
44 44 style: { padding: 0 },
45 45 onClick: () =>
46   - !isCustomer ? go(PageEnum.DEVICE_PROFILE + '?name=' + String(val)) : '',
  46 + !isCustomer
  47 + ? go(PageEnum.DEVICE_PROFILE + '?name=' + encodeURIComponent(String(val)))
  48 + : '',
47 49 },
48 50 { default: () => val }
49 51 );
... ... @@ -167,12 +169,12 @@ export const alarmColumns: BasicColumn[] = [
167 169 {
168 170 title: '告警时间',
169 171 dataIndex: 'createdTime',
170   - width: 120,
  172 + width: 180,
171 173 },
172 174 {
173 175 title: '告警设备',
174 176 dataIndex: 'deviceName',
175   - width: 100,
  177 + width: 120,
176 178 },
177 179 {
178 180 title: '告警场景',
... ... @@ -182,14 +184,20 @@ export const alarmColumns: BasicColumn[] = [
182 184 {
183 185 title: '告警级别',
184 186 dataIndex: 'severity',
185   - width: 160,
  187 + width: 90,
186 188 format: (text) => alarmLevel(text),
187 189 },
188 190 {
  191 + title: '告警详情',
  192 + dataIndex: 'details',
  193 + slots: { customRender: 'details' },
  194 + width: 160,
  195 + },
  196 + {
189 197 title: '状态',
190 198 dataIndex: 'status',
191 199 format: (text) => statusType(text),
192   - width: 160,
  200 + width: 100,
193 201 },
194 202 ];
195 203
... ... @@ -261,14 +269,6 @@ export const alarmSchemasForm: FormSchema[] = [
261 269 disabled: true,
262 270 },
263 271 },
264   - {
265   - field: 'details',
266   - label: '详情',
267   - component: 'InputTextArea',
268   - componentProps: {
269   - maxLength: 255,
270   - },
271   - },
272 272 ];
273 273 // 子设备
274 274 export const childDeviceSchemas: FormSchema[] = [
... ...
... ... @@ -54,10 +54,6 @@
54 54 await resetFields();
55 55 await setFieldsValue({
56 56 ...data,
57   - details: JSON.stringify(data?.details?.data).slice(
58   - 1,
59   - JSON.stringify(data?.details?.data).length - 1
60   - ),
61 57 severity: alarmLevel(data.severity),
62 58 status: statusType(data.status),
63 59 });
... ...
... ... @@ -145,6 +145,8 @@
145 145 // !!!此处需要删除地图的属性,否则会报堆栈溢出的错误 Uncaught RangeError: Maximum call stack size exceeded
146 146 Reflect.deleteProperty(DeviceStep1Ref.value.positionState, 'map');
147 147 Reflect.deleteProperty(DeviceStep1Ref.value.positionState, 'marker');
  148 + Reflect.deleteProperty(DeviceStep1Ref.value.devicePositionState, 'map');
  149 + Reflect.deleteProperty(DeviceStep1Ref.value.devicePositionState, 'marker');
148 150 setModalProps({
149 151 confirmLoading: true,
150 152 });
... ... @@ -156,7 +158,7 @@
156 158 customerId: currentDeviceData.customerId,
157 159 deviceInfo: {
158 160 avatar: DeviceStep1Ref.value?.devicePic,
159   - ...DeviceStep1Ref.value?.positionState,
  161 + ...DeviceStep1Ref.value?.devicePositionState,
160 162 },
161 163 };
162 164 validateNameLength(stepRecord.name);
... ... @@ -168,7 +170,7 @@
168 170 sn: stepRecord.name,
169 171 deviceInfo: {
170 172 avatar: DeviceStep1Ref.value?.devicePic,
171   - ...DeviceStep1Ref.value?.positionState,
  173 + ...DeviceStep1Ref.value?.devicePositionState,
172 174 },
173 175 deviceToken:
174 176 unref(current) === 0 || !unref(stepState).addAgree
... ...
... ... @@ -46,7 +46,7 @@
46 46 </div>
47 47 </template>
48 48 <template #deviceAddress>
49   - <Input disabled v-model:value="positionState.address">
  49 + <Input disabled v-model:value="devicePositionState.address">
50 50 <template #addonAfter>
51 51 <EnvironmentTwoTone @click="selectPosition" />
52 52 </template>
... ... @@ -128,6 +128,7 @@
128 128 import { useDrawer } from '/@/components/Drawer';
129 129 import DeptDrawer from '/@/views/system/organization/OrganizationDrawer.vue';
130 130 import { TaskTypeEnum } from '/@/views/task/center/config';
  131 + import { toRaw } from 'vue';
131 132
132 133 export default defineComponent({
133 134 components: {
... ... @@ -239,8 +240,14 @@
239 240 const selectPosition = () => {
240 241 visible.value = true;
241 242 if (!positionState.longitude) {
242   - positionState.longitude = '104.04666605565338';
243   - positionState.latitude = '30.543516387560476';
  243 + positionState.longitude = '104.05326410962411';
  244 + positionState.latitude = '30.54855093076791';
  245 +
  246 + // 根据经纬度获取详细位置
  247 + if (positionState.longitude && positionState.latitude) {
  248 + var pt = new BMap.Point(positionState.longitude, positionState.latitude);
  249 + getAddrByPoint(pt);
  250 + }
244 251 initMap(positionState.longitude, positionState.latitude);
245 252 } else {
246 253 initMap(positionState.longitude, positionState.latitude);
... ... @@ -261,6 +268,15 @@
261 268 map: null,
262 269 marker: null,
263 270 });
  271 +
  272 + const devicePositionState = ref({
  273 + longitude: '',
  274 + latitude: '',
  275 + address: '',
  276 + map: null,
  277 + marker: null,
  278 + });
  279 +
264 280 /**
265 281 * 逆地址解析函数(根据坐标点获取详细地址)
266 282 * @param {Object} point 百度地图坐标点,必传
... ... @@ -371,6 +387,7 @@
371 387 // 确定选择的位置
372 388 const handleOk = () => {
373 389 visible.value = false;
  390 + devicePositionState.value = { ...toRaw(positionState) };
374 391 };
375 392 // 取消选择位置
376 393 const handleCancel = () => {
... ... @@ -385,6 +402,7 @@
385 402 positionState.longitude = deviceInfo.longitude;
386 403 positionState.latitude = deviceInfo.latitude;
387 404 positionState.address = deviceInfo.address;
  405 + devicePositionState.value = { ...toRaw(positionState) };
388 406 devicePic.value = deviceInfo.avatar;
389 407 setFieldsValue({
390 408 ...data,
... ... @@ -418,11 +436,13 @@
418 436 function parentResetDevicePic(deviceInfo) {
419 437 devicePic.value = deviceInfo.avatar;
420 438 }
  439 +
421 440 // 父组件重置位置
422 441 function parentResetPositionState() {
423 442 for (let key in positionState) {
424 443 positionState[key] = '';
425 444 }
  445 + devicePositionState.value = { ...toRaw(positionState) };
426 446 }
427 447 // 禁用设备类型
428 448 function disabledDeviceType(disabled: boolean) {
... ... @@ -474,6 +494,7 @@
474 494 handleOpenOrgDrawer,
475 495 handleSuccess,
476 496 handleTreeOrg,
  497 + devicePositionState,
477 498 };
478 499 },
479 500 });
... ...
... ... @@ -12,17 +12,31 @@
12 12 ]"
13 13 />
14 14 </template>
  15 + <template #details="{ record }">
  16 + <a-button type="link" class="ml-2" @click="handleViewAlarmDetails(record)">
  17 + 查看告警详情
  18 + </a-button>
  19 + </template>
15 20 </BasicTable>
16 21 <AlarmDetailModal @register="registerDetailModal" @success="handleSuccess" />
17 22 </div>
18 23 </template>
19 24 <script lang="ts">
20   - import { defineComponent } from 'vue';
  25 + import { defineComponent, h, nextTick } from 'vue';
21 26 import { BasicTable, useTable, TableAction } from '/@/components/Table';
22 27 import { alarmColumns, alarmSearchSchemas } from '../../config/detail.config';
23 28 import { getDeviceAlarm } from '/@/api/device/deviceManager';
24 29 import AlarmDetailModal from '../modal/AlarmDetailModal.vue';
25 30 import { useModal } from '/@/components/Modal';
  31 + import { Modal } from 'ant-design-vue';
  32 + import { JsonPreview } from '/@/components/CodeEditor';
  33 + import { getDeviceDetail } from '/@/api/device/deviceManager';
  34 + import { getAttribute } from '/@/api/ruleengine/ruleengineApi';
  35 + import {
  36 + operationNumber_OR_TIME,
  37 + operationString,
  38 + operationBoolean,
  39 + } from '/@/views/rule/linkedge/config/formatData';
26 40 export default defineComponent({
27 41 name: 'DeviceManagement',
28 42 components: {
... ... @@ -66,11 +80,86 @@
66 80 const handleSuccess = () => {
67 81 reload();
68 82 };
  83 + const handleViewAlarmDetails = async (record: Recordable) => {
  84 + await nextTick();
  85 + const { details } = record;
  86 + const deviceIdKeys = Object.keys(details);
  87 + const detailObject = deviceIdKeys.map((key) => ({ label: key, value: details[key] }));
  88 + const dataFormat = await handleAlarmDetailFormat(deviceIdKeys);
  89 + console.log(detailObject, dataFormat, 'dataFormat');
  90 + const dataFormats = detailObject.reduce((acc: any, curr: any) => {
  91 + dataFormat.forEach((item) => {
  92 + if (item.tbDeviceId === curr.label) {
  93 + const findName = item.attribute.find(
  94 + (item) => item.identifier === curr.value.key
  95 + )?.name;
  96 + const findLogin = [
  97 + ...operationNumber_OR_TIME,
  98 + ...operationString,
  99 + ...operationBoolean,
  100 + ].find((item) => item.value === curr.value.logic)?.symbol;
  101 + const findAttribute = item.attribute.find(
  102 + (findItem) => findItem.identifier === curr.value.key
  103 + );
  104 + const value = {
  105 + ['触发属性']: findName,
  106 + ['触发条件']: `${findLogin}${curr.value.logicValue}`,
  107 + ['触发值']: `${curr.value.realValue}${findAttribute.detail?.dataType?.specs?.unit?.key}`,
  108 + };
  109 + const data = {
  110 + [item.name]: value,
  111 + };
  112 + acc.push(data);
  113 + }
  114 + });
  115 + return [...acc];
  116 + }, []);
  117 + const objectFormat = dataFormats.reduce((acc: any, curr: any) => {
  118 + return {
  119 + ...acc,
  120 + ...curr,
  121 + };
  122 + }, {});
  123 + Modal.info({
  124 + title: '告警详情',
  125 + width: 600,
  126 + centered: true,
  127 + maskClosable: true,
  128 + content: h(JsonPreview, { data: JSON.parse(JSON.stringify(objectFormat)) }),
  129 + });
  130 + };
  131 + const handleAlarmDetailFormat = async (keys: string[]) => {
  132 + const temp: any = [];
  133 + for (let item of keys) {
  134 + if (item === 'key' || item === 'data') return []; //旧数据则终止
  135 + const deviceDetailRes = await getDeviceDetail(item);
  136 + const { deviceProfileId } = deviceDetailRes;
  137 + if (!deviceProfileId) return [];
  138 + const attributeRes = await getAttribute(deviceProfileId);
  139 + const dataFormat: any = handleDataFormat(deviceDetailRes, attributeRes);
  140 + temp.push(dataFormat);
  141 + }
  142 + return temp;
  143 + };
  144 + const handleDataFormat = (deviceDetail: any, attributes: any) => {
  145 + const { name, tbDeviceId } = deviceDetail;
  146 + const attribute = attributes.map((item) => ({
  147 + identifier: item.identifier,
  148 + name: item.name,
  149 + detail: item.detail,
  150 + }));
  151 + return {
  152 + name,
  153 + tbDeviceId,
  154 + attribute,
  155 + };
  156 + };
69 157 return {
70 158 registerTable,
71 159 registerDetailModal,
72 160 handleDetail,
73 161 handleSuccess,
  162 + handleViewAlarmDetails,
74 163 };
75 164 },
76 165 });
... ...
... ... @@ -52,7 +52,9 @@
52 52 <div class="mt-4" v-if="!isCustomer">
53 53 <a-button type="primary" class="mr-4" @click="copyTbDeviceId">复制设备ID</a-button>
54 54 <a-button type="primary" class="mr-4" @click="copyDeviceToken">复制访问令牌</a-button>
55   - <a-button type="primary" class="mr-4" @click="manageDeviceToken">管理设备凭证</a-button>
  55 + <Authority value="api:yt:device:equipment">
  56 + <a-button type="primary" class="mr-4" @click="manageDeviceToken">管理设备凭证</a-button>
  57 + </Authority>
56 58 <ManageDeviceTokenModal @register="registerModal" />
57 59 </div>
58 60 <div class="mt-4">
... ... @@ -84,10 +86,10 @@
84 86 import { DeviceTypeEnum } from '/@/api/device/model/deviceModel';
85 87 import { useAuthDeviceDetail } from '../../hook/useAuthDeviceDetail';
86 88 import { useClipboard } from '@vueuse/core';
87   -
88 89 import wz from '/@/assets/images/wz.png';
89 90 import { useAsyncQueue } from '../../../localtion/useAsyncQueue';
90 91 import locationImage from '/@/assets/icons/location.svg';
  92 + import { Authority } from '/@/components/Authority';
91 93
92 94 export default defineComponent({
93 95 components: {
... ... @@ -98,6 +100,7 @@
98 100 BasicModal,
99 101 Tooltip,
100 102 Empty,
  103 + Authority,
101 104 },
102 105 props: {
103 106 deviceDetail: {
... ...
... ... @@ -72,7 +72,7 @@ export const formSchemas: FormSchema[] = [
72 72 },
73 73 {
74 74 field: 'eventType',
75   - label: '告警类型',
  75 + label: '事件类型',
76 76 component: 'ApiSelect',
77 77 componentProps: {
78 78 placeholder: '请选择事件类型',
... ...
... ... @@ -167,6 +167,7 @@
167 167 mode.value = value;
168 168 await nextTick();
169 169 setTableData(socketInfo.originData);
  170 + socketInfo.dataSource = socketInfo.originData;
170 171 };
171 172
172 173 const { createMessage } = useMessage();
... ... @@ -315,10 +316,10 @@
315 316 <ModeSwitchButton v-model:value="mode" @change="switchMode" />
316 317 </div>
317 318 <List
318   - v-if="mode === EnumTableCardMode.CARD"
  319 + v-show="mode === EnumTableCardMode.CARD"
319 320 ref="listElRef"
320 321 class="list-mode !px-2"
321   - :data-source="socketInfo.originData"
  322 + :data-source="socketInfo.dataSource"
322 323 :grid="grid"
323 324 :pagination="pagination"
324 325 >
... ...
... ... @@ -129,17 +129,20 @@ const SingleToHexBatch = (t) => {
129 129
130 130 const formSchemasConfig = (schemas, actionType): FormSchema[] => {
131 131 const { identifier, functionName } = schemas;
132   - console.log(identifier, 'identifier', actionType, 'actionType');
133 132 if (actionType == '06') {
134 133 return [
135 134 {
136 135 field: identifier,
137 136 label: functionName,
138 137 component: 'InputNumber',
139   - rules: [{ required: true, message: '请输入' }],
  138 + rules: [{ required: true, message: '请输入正数' }],
140 139 componentProps: {
141   - precision: 0,
142   - placeholder: `请输入整数`,
  140 + min: 0,
  141 + formatter: (e) => {
  142 + const value = `${e}`.replace('-', '').replace(/^(-)*(\d+)\.(\d\d).*$/, '$1$2.$3');
  143 + return value;
  144 + },
  145 + placeholder: `请输入正数`,
143 146 },
144 147 },
145 148 ];
... ... @@ -166,7 +169,7 @@ const formSchemasConfig = (schemas, actionType): FormSchema[] => {
166 169 component: 'InputNumber',
167 170 rules: [{ required: true, message: '请输入值' }],
168 171 componentProps: {
169   - placeholder: `请输入`,
  172 + placeholder: `请输入数字`,
170 173 formatter: (e) =>
171 174 `${e}`.replace(/\B(?=(\d{3})+(?!\d))/g, '').replace(/^(-)*(\d+)\.(\d\d).*$/, '$1$2.$3'),
172 175 },
... ...
... ... @@ -39,10 +39,9 @@
39 39 const { name, detail, identifier, deviceDetail, extensionDesc } = record;
40 40 const { dataType } = detail;
41 41 const { type } = dataType || {};
42   - const { codeType, deviceProfile } = deviceDetail || {};
  42 + const { codeType, deviceProfile, code } = deviceDetail || {};
43 43 const { transportType } = deviceProfile || {};
44 44 const { registerAddress, actionType, zoomFactor } = extensionDesc || {}; //获取扩展描述内容
45   -
46 45 formField.value = identifier;
47 46 zoomFactorValue.value = zoomFactor ? Number(zoomFactor) : 1;
48 47 isShowMultiply.value = type == 'INT' || type == 'DOUBLE' ? true : false;
... ... @@ -64,7 +63,7 @@
64 63 isShowModBUS.value = true;
65 64 modBUSForm.value = {
66 65 crc: 'CRC_16_LOWER',
67   - deviceCode: '01',
  66 + deviceCode: code,
68 67 method: actionType == '16' ? '10' : actionType,
69 68 registerAddress,
70 69 registerNumber: 1,
... ... @@ -91,6 +90,17 @@
91 90 return array;
92 91 };
93 92
  93 + // 获取小数
  94 + const getFloatPart = (number: string | number) => {
  95 + const isLessZero = Number(number) < 0;
  96 + number = number.toString();
  97 + const floatPartStartIndex = number.indexOf('.');
  98 + const value = ~floatPartStartIndex
  99 + ? `${isLessZero ? '-' : ''}0.${number.substring(floatPartStartIndex + 1)}`
  100 + : '0';
  101 + return Number(value);
  102 + };
  103 +
94 104 const { createMessage } = useMessage();
95 105 const loading = ref(false);
96 106 const handleSend = async () => {
... ... @@ -111,15 +121,37 @@
111 121 const oldValue = getFieldsValue()[unref(formField)];
112 122 modBUSForm.value.registerNumber = 1;
113 123 modBUSForm.value.registerValues = [oldValue];
  124 +
114 125 if (unref(isShowMultiply) && unref(modBUSForm).method == '06') {
  126 + const newValue =
  127 + Math.trunc(oldValue) * unref(zoomFactorValue) +
  128 + getFloatPart(oldValue) * unref(zoomFactorValue);
  129 + if (newValue % 1 != 0) {
  130 + createMessage.warning(`属性下发类型必须是整数,缩放因子为${unref(zoomFactorValue)}`);
  131 + return;
  132 + }
  133 +
  134 + if (oldValue * unref(zoomFactorValue) > 65535) {
  135 + createMessage.warning(`属性下发值不能超过65535,缩放因子是${unref(zoomFactorValue)}`);
  136 + return;
  137 + }
115 138 //bool类型的就不用去乘缩放因子了
116   - modBUSForm.value.registerValues = [oldValue * unref(zoomFactorValue)];
  139 + modBUSForm.value.registerValues = [newValue];
117 140 }
118 141
119 142 if (unref(modBUSForm).method == '16' || unref(modBUSForm).method == '10') {
120   - const newValue = getArray(
121   - SingleToHex(unref(isShowMultiply) ? oldValue * unref(zoomFactorValue) : oldValue)
122   - );
  143 + const regex = /^-?\d+(\.\d{0,2})?$/;
  144 + const values =
  145 + Math.trunc(oldValue) * unref(zoomFactorValue) +
  146 + getFloatPart(oldValue) * unref(zoomFactorValue);
  147 +
  148 + if (!regex.test(values as any)) {
  149 + createMessage.warning(`属性下发值精确到两位小数,缩放因子是${unref(zoomFactorValue)}`);
  150 + return;
  151 + }
  152 +
  153 + const newValue =
  154 + values == 0 ? [0, 0] : getArray(SingleToHex(unref(isShowMultiply) ? values : oldValue));
123 155 modBUSForm.value.registerValues = newValue;
124 156 modBUSForm.value.registerNumber = 2;
125 157 modBUSForm.value.method = '10';
... ...
... ... @@ -5,7 +5,9 @@
5 5 >
6 6 <template #toolbar>
7 7 <Space>
8   - <Button type="primary" @click="openModal(true)">命令下发</Button>
  8 + <Authority value="api:yt:device:rpc">
  9 + <Button type="primary" @click="openModal(true)">命令下发</Button>
  10 + </Authority>
9 11 </Space>
10 12 </template>
11 13 <template #recordContent="{ record }">
... ... @@ -43,6 +45,7 @@
43 45 import { DeviceRecord } from '/@/api/device/model/deviceModel';
44 46 import { BasicModal, useModal } from '/@/components/Modal';
45 47 import CommandIssuance from '../CommandIssuance.vue';
  48 + import { Authority } from '/@/components/Authority';
46 49
47 50 const props = defineProps({
48 51 fromId: {
... ... @@ -85,7 +88,8 @@
85 88 };
86 89 const handleRecordContent = (record) => {
87 90 if (!record?.request?.body) return;
88   - const jsonParams = record?.request?.body;
  91 + if (Object.prototype.toString.call(record?.request?.body) !== '[object Object]') return;
  92 + const jsonParams = record?.request?.body?.params;
89 93 commonModalInfo('命令下发内容', jsonParams);
90 94 };
91 95 const handleRecordResponseContent = (record) => {
... ...
... ... @@ -24,14 +24,16 @@
24 24 <Authority value="api:yt:device:import">
25 25 <Button type="primary" @click="handleBatchImport">导入</Button>
26 26 </Authority>
27   - <a-button
28   - v-if="authBtn(role)"
29   - type="primary"
30   - @click="handleBatchAssign"
31   - :disabled="!isExistOption"
32   - >
33   - 批量分配
34   - </a-button>
  27 + <Authority value="api:yt:device:assign">
  28 + <a-button
  29 + v-if="authBtn(role)"
  30 + type="primary"
  31 + @click="handleBatchAssign"
  32 + :disabled="!isExistOption"
  33 + >
  34 + 批量分配
  35 + </a-button>
  36 + </Authority>
35 37 </template>
36 38 <template #img="{ record }">
37 39 <TableImg
... ... @@ -134,6 +136,7 @@
134 136 label: '分配客户',
135 137 icon: 'mdi:account-arrow-right',
136 138 ifShow: authBtn(role),
  139 + auth: 'api:yt:device:assign',
137 140 onClick: handleDispatchCustomer.bind(null, record),
138 141 },
139 142 {
... ...
... ... @@ -33,9 +33,15 @@
33 33 </Button>
34 34 </Authority>
35 35 <Button type="primary" @click="handleOpenTsl"> 物模型TSL </Button>
36   - <Upload v-if="isShowBtn" :show-upload-list="false" :customRequest="handleImportModel">
37   - <Button type="primary" :loading="importLoading"> 导入物模型 </Button>
38   - </Upload>
  36 + <Authority value="api:yt:things_model:import">
  37 + <Upload
  38 + v-if="isShowBtn"
  39 + :show-upload-list="false"
  40 + :customRequest="handleImportModel"
  41 + >
  42 + <Button type="primary" :loading="importLoading"> 导入物模型 </Button>
  43 + </Upload>
  44 + </Authority>
39 45 </div>
40 46 <div class="flex gap-2">
41 47 <Authority :value="ModelOfMatterPermission.RELEASE">
... ...
... ... @@ -19,6 +19,6 @@
19 19 </template>
20 20 <style scoped>
21 21 :deep(.ant-table-body) {
22   - overflow: hidden !important;
  22 + overflow: scroll !important;
23 23 }
24 24 </style>
... ...
... ... @@ -78,8 +78,7 @@
78 78 return deviceType === DeviceTypeEnum.SENSOR && transportType === 'TCP';
79 79 });
80 80
81   - const blockContent = `属性一般是设备的运行状态,如当前温度等;服务是设备可被调用的方法,支持定义参数,如执行某项任务;事件则是设备上报的
82   -通知,如告警,需要被及时处理。`;
  81 + const blockContent = `属性一般是指设备的运行状态,如当前温度等;服务是指设备可被调用的方法,支持定义参数,如执行某项任务;事件则是指设备上报的通知,如告警,需要被及时处理。`;
83 82 const activeKey = ref<FunctionType>(FunctionType.PROPERTIES);
84 83 const size = ref('small');
85 84
... ...
... ... @@ -89,7 +89,9 @@
89 89 functionJson: {
90 90 inputData,
91 91 outputData,
92   - ...(serviceCommand ? { inputData: [{ serviceCommand }] } : {}),
  92 + ...(serviceCommand
  93 + ? { inputData: [{ serviceCommand: serviceCommand.replaceAll(/\s/g, '').toUpperCase() }] }
  94 + : {}),
93 95 },
94 96 } as ModelOfMatterParams;
95 97
... ...
... ... @@ -117,7 +117,18 @@ export const serviceSchemas = (tcpDeviceFlag: boolean): FormSchema[] => {
117 117 field: FormField.SERVICE_COMMAND,
118 118 label: '输入参数',
119 119 component: 'Input',
120   - rules: [{ message: '输入参数为必填项', required: true }],
  120 + rules: [
  121 + { message: '输入参数为必填项', required: true },
  122 + {
  123 + message: '请输入ASCII或HEX服务命令(0~9/A~F)',
  124 + validator(_rule, value, _callback) {
  125 + const reg = /^[\s0-9a-fA-F]+$/;
  126 +
  127 + if (reg.test(value)) return Promise.resolve();
  128 + return Promise.reject('请输入ASCII或HEX服务命令(0~9/A~F)');
  129 + },
  130 + },
  131 + ],
121 132 ifShow: tcpDeviceFlag,
122 133 componentProps: {
123 134 placeholder: '请输入ASCII或HEX服务命令',
... ...
... ... @@ -17,16 +17,26 @@
17 17 </Authority>
18 18 </template>
19 19 <template #config="{ record }">
20   - <a-button type="link" class="ml-2" @click="showData(record)"> 查看配置 </a-button>
  20 + <Authority value="api:yt:message:get:config">
  21 + <a-button type="link" class="ml-2" @click="showData(record)"> 查看配置 </a-button>
  22 + </Authority>
21 23 </template>
22 24 <template #status="{ record }">
23   - <Switch
24   - :checked="record.status === 1"
25   - :loading="record.pendingStatus"
26   - checkedChildren="启用"
27   - unCheckedChildren="禁用"
28   - @change="(checked:boolean)=>statusChange(checked,record)"
29   - />
  25 + <Authority value="api:yt:message:status">
  26 + <Switch
  27 + :checked="record.status === 1"
  28 + :loading="record.pendingStatus"
  29 + checkedChildren="启用"
  30 + unCheckedChildren="禁用"
  31 + @change="(checked:boolean)=>statusChange(checked,record)"
  32 + />
  33 + </Authority>
  34 + <Tag
  35 + v-if="!hasPermission('api:yt:message:status')"
  36 + :color="record.status ? 'green' : 'red'"
  37 + >
  38 + {{ record.status ? '启用' : '禁用' }}
  39 + </Tag>
30 40 </template>
31 41 <template #action="{ record }">
32 42 <TableAction
... ... @@ -62,18 +72,20 @@
62 72 import { useDrawer } from '/@/components/Drawer';
63 73 import ConfigDrawer from './ConfigDrawer.vue';
64 74 import { columns, searchFormSchema } from './config.data';
65   - import { Modal, Popconfirm } from 'ant-design-vue';
  75 + import { Modal, Popconfirm, Tag } from 'ant-design-vue';
66 76 import { JsonPreview } from '/@/components/CodeEditor';
67 77 import { useMessage } from '/@/hooks/web/useMessage';
68 78 import { useBatchDelete } from '/@/hooks/web/useBatchDelete';
69 79 import { Switch } from 'ant-design-vue';
70 80 import { setMessageConfigStatus } from '/@/api/message/config';
71 81 import { Authority } from '/@/components/Authority';
  82 + import { usePermission } from '/@/hooks/web/usePermission';
72 83
73 84 export default defineComponent({
74 85 name: 'MessageConfigManagement',
75   - components: { BasicTable, ConfigDrawer, TableAction, Switch, Authority, Popconfirm },
  86 + components: { BasicTable, ConfigDrawer, TableAction, Switch, Authority, Popconfirm, Tag },
76 87 setup() {
  88 + const { hasPermission } = usePermission();
77 89 const [registerDrawer, { openDrawer }] = useDrawer();
78 90 function handleSuccess() {
79 91 reload();
... ... @@ -168,6 +180,7 @@
168 180 handleDeleteOrBatchDelete,
169 181 hasBatchDelete,
170 182 statusChange,
  183 + hasPermission,
171 184 };
172 185 },
173 186 });
... ...
... ... @@ -22,13 +22,21 @@
22 22 </a-button>
23 23 </template>
24 24 <template #status="{ record }">
25   - <Switch
26   - :checked="record.status === 1"
27   - :loading="record.pendingStatus"
28   - checkedChildren="启用"
29   - unCheckedChildren="禁用"
30   - @change="(checked:boolean)=>statusChange(checked,record)"
31   - />
  25 + <Authority value="api:yt:template:status">
  26 + <Switch
  27 + :checked="record.status === 1"
  28 + :loading="record.pendingStatus"
  29 + checkedChildren="启用"
  30 + unCheckedChildren="禁用"
  31 + @change="(checked:boolean)=>statusChange(checked,record)"
  32 + />
  33 + </Authority>
  34 + <Tag
  35 + v-if="!hasPermission('api:yt:template:status')"
  36 + :color="record.status ? 'green' : 'red'"
  37 + >
  38 + {{ record.status ? '启用' : '禁用' }}
  39 + </Tag>
32 40 </template>
33 41 <template #action="{ record }">
34 42 <TableAction
... ... @@ -80,9 +88,10 @@
80 88 import SendEmail from '/@/views/message/template/SendEmail.vue';
81 89 import { useMessage } from '/@/hooks/web/useMessage';
82 90 import { useBatchDelete } from '/@/hooks/web/useBatchDelete';
83   - import { Switch, Popconfirm } from 'ant-design-vue';
  91 + import { Switch, Popconfirm, Tag } from 'ant-design-vue';
84 92 import { setMessageTemplateStatus } from '/@/api/message/template';
85 93 import { Authority } from '/@/components/Authority';
  94 + import { usePermission } from '/@/hooks/web/usePermission';
86 95
87 96 export default defineComponent({
88 97 name: 'MessageTemplateManagement',
... ... @@ -95,8 +104,10 @@
95 104 Switch,
96 105 Authority,
97 106 Popconfirm,
  107 + Tag,
98 108 },
99 109 setup() {
  110 + const { hasPermission } = usePermission();
100 111 const [registerModal, { openModal: openModal }] = useModal();
101 112 const [registerMailModal, { openModal: openMailModal }] = useModal();
102 113 const go = useGo();
... ... @@ -218,6 +229,7 @@
218 229 handleDeleteOrBatchDelete,
219 230 statusChange,
220 231 hasBatchDelete,
  232 + hasPermission,
221 233 };
222 234 },
223 235 });
... ...
... ... @@ -135,10 +135,14 @@
135 135 <Tabs.TabPane tab="详情" key="detail">
136 136 <Space>
137 137 <!-- <Button type="primary" @click="openDetailPage">打开详情页</Button> -->
138   - <Button type="primary" @click="downloadPackage" :disabled="!!otaRecord.url">
139   - 下载包
140   - </Button>
141   - <Button type="primary" @click="deletePackage" danger>删除包</Button>
  138 + <Authority :value="OtaPermissionKey.DOWNLOAD">
  139 + <Button type="primary" @click="downloadPackage" :disabled="!!otaRecord.url">
  140 + 下载包
  141 + </Button>
  142 + </Authority>
  143 + <Authority :value="OtaPermissionKey.DELETE">
  144 + <Button type="primary" @click="deletePackage" danger>删除包</Button>
  145 + </Authority>
142 146 </Space>
143 147 <div class="mt-3">
144 148 <Space>
... ...
... ... @@ -9,6 +9,7 @@ export enum PermissionReportConfigEnum {
9 9 PERMISSION_GET = 'api:yt:report:get',
10 10 PERMISSION_DELETE = 'api:yt:report_form:config:delete',
11 11 PERMISSION_UPDATE = 'api:yt:report_form:config:update',
  12 + PERMISSION_STATUS = 'api:yt:report_form:config:status',
12 13 }
13 14
14 15 //业务文字描述配置枚举
... ...
... ... @@ -74,14 +74,22 @@
74 74 />
75 75 </template>
76 76 <template #configStatus="{ record }">
77   - <Switch
78   - :disabled="disabledSwitch"
79   - :checked="record.status === 1"
80   - :loading="record.pendingStatus"
81   - :checkedChildren="BusinessReportConfigTextEnum.BUSINESS_ENABLE_TEXT"
82   - :unCheckedChildren="BusinessReportConfigTextEnum.BUSINESS_DISABLE_TEXT"
83   - @change="(checked: boolean) => statusChange(checked, record)"
84   - />
  77 + <Authority :value="PermissionReportConfigEnum.PERMISSION_STATUS">
  78 + <Switch
  79 + :disabled="disabledSwitch"
  80 + :checked="record.status === 1"
  81 + :loading="record.pendingStatus"
  82 + :checkedChildren="BusinessReportConfigTextEnum.BUSINESS_ENABLE_TEXT"
  83 + :unCheckedChildren="BusinessReportConfigTextEnum.BUSINESS_DISABLE_TEXT"
  84 + @change="(checked: boolean) => statusChange(checked, record)"
  85 + />
  86 + </Authority>
  87 + <Tag
  88 + v-if="!hasPermission(PermissionReportConfigEnum.PERMISSION_STATUS)"
  89 + :color="record.status ? 'green' : 'red'"
  90 + >
  91 + {{ record.status ? '启用' : '禁用' }}
  92 + </Tag>
85 93 </template>
86 94 </BasicTable>
87 95 <ReportConfigDrawer @register="registerDrawer" @success="handleSuccess" />
... ... @@ -101,7 +109,7 @@
101 109 import { defaultTableAttribtes } from './config';
102 110 import { Authority } from '/@/components/Authority';
103 111 import { useBatchDelete } from '/@/hooks/web/useBatchDelete';
104   - import { Popconfirm, Switch } from 'ant-design-vue';
  112 + import { Popconfirm, Switch, Tag } from 'ant-design-vue';
105 113 import { useModal } from '/@/components/Modal';
106 114 import { useGo } from '/@/hooks/web/usePage';
107 115 import { useMessage } from '/@/hooks/web/useMessage';
... ... @@ -111,6 +119,9 @@
111 119 BusinessReportConfigTextEnum,
112 120 BusinessReportConfigStatusEnum,
113 121 } from './enum';
  122 + import { usePermission } from '/@/hooks/web/usePermission';
  123 +
  124 + const { hasPermission } = usePermission();
114 125
115 126 const disabledSwitch = ref(false);
116 127
... ...
... ... @@ -192,8 +192,8 @@
192 192 },
193 193 toolbox: {},
194 194 grid: {
195   - left: '8%',
196   - right: '8%',
  195 + left: '14%',
  196 + right: '20%',
197 197 bottom: 80,
198 198 containLabel: true,
199 199 },
... ...
... ... @@ -8,6 +8,7 @@ export enum PermissionDataFlowEnum {
8 8 PERMISSION_GET = 'api:yt:convert:config:get',
9 9 PERMISSION_DELETE = 'api:yt:convert:config:delete',
10 10 PERMISSION_UPDATE = 'api:yt:convert:config:update',
  11 + PERMISSION_STATUS = 'api:yt:convert:config:status',
11 12 }
12 13
13 14 //业务文字描述配置枚举
... ...
... ... @@ -79,13 +79,21 @@
79 79 />
80 80 </template>
81 81 <template #status="{ record }">
82   - <Switch
83   - :checked="record.status === 1"
84   - :loading="record.pendingStatus"
85   - checkedChildren="启用"
86   - unCheckedChildren="禁用"
87   - @change="(checked:boolean)=>hanldeSwitch(checked,record)"
88   - />
  82 + <Authority :value="PermissionDataFlowEnum.PERMISSION_STATUS">
  83 + <Switch
  84 + :checked="record.status === 1"
  85 + :loading="record.pendingStatus"
  86 + checkedChildren="启用"
  87 + unCheckedChildren="禁用"
  88 + @change="(checked:boolean)=>hanldeSwitch(checked,record)"
  89 + />
  90 + </Authority>
  91 + <Tag
  92 + v-if="!hasPermission(PermissionDataFlowEnum.PERMISSION_STATUS)"
  93 + :color="record.status ? 'green' : 'red'"
  94 + >
  95 + {{ record.status ? '启用' : '禁用' }}
  96 + </Tag>
89 97 </template>
90 98 </BasicTable>
91 99 <DataFlowModal @register="registerModal" @success="handleSuccess" />
... ... @@ -103,15 +111,18 @@
103 111 import { useMessage } from '/@/hooks/web/useMessage';
104 112 import { Authority } from '/@/components/Authority';
105 113 import { useBatchDelete } from '/@/hooks/web/useBatchDelete';
106   - import { Switch, Popconfirm } from 'ant-design-vue';
  114 + import { Switch, Popconfirm, Tag } from 'ant-design-vue';
107 115 import { PermissionDataFlowEnum, BusinessDataFlowTextEnum } from './enum';
108 116 import { DataFlowModal } from './components/dataflowmodal';
109 117 import { defaultTableAttribute } from './config';
  118 + import { usePermission } from '/@/hooks/web/usePermission';
110 119
111 120 const { createMessage } = useMessage();
112 121
113 122 const loading = ref(true);
114 123
  124 + const { hasPermission } = usePermission();
  125 +
115 126 const handleSuccess = () => {
116 127 reload();
117 128 };
... ...
... ... @@ -31,6 +31,7 @@ export type TOption = {
31 31 export enum CommandTypeEnum {
32 32 CUSTOM = 0,
33 33 SERVICE = 1,
  34 + ATTRIBUTE = 2,
34 35 }
35 36
36 37 /**
... ...
... ... @@ -164,26 +164,26 @@ export const genActionData = (actionData) => {
164 164 };
165 165
166 166 export const operationNumber_OR_TIME = [
167   - { label: '等于', value: Number_Operation.EQUAL },
168   - { label: '不等于', value: Number_Operation.NOT_EQUAL },
169   - { label: '小于', value: Number_Operation.LESS },
170   - { label: '小于等于', value: Number_Operation.LESS_OR_EQUAL },
171   - { label: '大于', value: Number_Operation.GREATER },
172   - { label: '大于等于', value: Number_Operation.GREATER_OR_EQUAL },
  167 + { label: '等于', value: Number_Operation.EQUAL, symbol: '=' },
  168 + { label: '不等于', value: Number_Operation.NOT_EQUAL, symbol: '!=' },
  169 + { label: '小于', value: Number_Operation.LESS, symbol: '<' },
  170 + { label: '小于等于', value: Number_Operation.LESS_OR_EQUAL, symbol: '<=' },
  171 + { label: '大于', value: Number_Operation.GREATER, symbol: '>' },
  172 + { label: '大于等于', value: Number_Operation.GREATER_OR_EQUAL, symbol: '>=' },
173 173 ];
174 174
175 175 export const operationString = [
176   - { label: '等于', value: String_Operation.EQUAL },
177   - { label: '不等于', value: String_Operation.NOT_EQUAL },
178   - { label: '开始于', value: String_Operation.BEGAN_IN },
179   - { label: '结束于', value: String_Operation.END_IN },
180   - { label: '包含', value: String_Operation.INCLUDE },
181   - { label: '不包含', value: String_Operation.NOT_INCLUDE },
  176 + { label: '等于', value: String_Operation.EQUAL, symbol: '=' },
  177 + { label: '不等于', value: String_Operation.NOT_EQUAL, symbol: '!=' },
  178 + { label: '开始于', value: String_Operation.BEGAN_IN, symbol: '开始于' },
  179 + { label: '结束于', value: String_Operation.END_IN, symbol: '结束于' },
  180 + { label: '包含', value: String_Operation.INCLUDE, symbol: '包含' },
  181 + { label: '不包含', value: String_Operation.NOT_INCLUDE, symbol: '不包含' },
182 182 ];
183 183
184 184 export const operationBoolean = [
185   - { label: '等于', value: Boolean_Operation.EQUAL },
186   - { label: '不等于', value: Boolean_Operation.NOT_EQUAL },
  185 + { label: '等于', value: Boolean_Operation.EQUAL, symbol: '=' },
  186 + { label: '不等于', value: Boolean_Operation.NOT_EQUAL, symbol: '!=' },
187 187 ];
188 188
189 189 export const scheduleOptions = [
... ...
... ... @@ -50,13 +50,21 @@
50 50 </template>
51 51
52 52 <template #status="{ record }">
53   - <Switch
54   - :checked="record.status === 1"
55   - :loading="record.pendingStatus"
56   - checkedChildren="启用"
57   - unCheckedChildren="禁用"
58   - @change="(checked:boolean)=>statusChange(checked,record)"
59   - />
  53 + <Authority value="api:yt:sceneLinkage:status">
  54 + <Switch
  55 + :checked="record.status === 1"
  56 + :loading="record.pendingStatus"
  57 + checkedChildren="启用"
  58 + unCheckedChildren="禁用"
  59 + @change="(checked:boolean)=>statusChange(checked,record)"
  60 + />
  61 + </Authority>
  62 + <Tag
  63 + v-if="!hasPermission('api:yt:sceneLinkage:status')"
  64 + :color="record.status ? 'green' : 'red'"
  65 + >
  66 + {{ record.status ? '启用' : '禁用' }}
  67 + </Tag>
60 68 </template>
61 69 </BasicTable>
62 70 <SceneLinkAgeDrawer @register="registerDrawer" @success="handleSuccess" />
... ... @@ -72,16 +80,18 @@
72 80 screenLinkPagePutApi,
73 81 } from '/@/api/ruleengine/ruleengineApi';
74 82 import { useBatchDelete } from '/@/hooks/web/useBatchDelete';
75   - import { Switch, Popconfirm } from 'ant-design-vue';
  83 + import { Switch, Popconfirm, Tag } from 'ant-design-vue';
76 84 import { columns, searchFormSchema } from './config/config.data';
77 85 import { USER_INFO_KEY } from '/@/enums/cacheEnum';
78 86 import { getAuthCache } from '/@/utils/auth';
79 87 import SceneLinkAgeDrawer from './SceneLinkAgeDrawer.vue';
80 88 import { useMessage } from '/@/hooks/web/useMessage';
81 89 import { Authority } from '/@/components/Authority';
  90 + import { usePermission } from '/@/hooks/web/usePermission';
82 91
83 92 const userInfo: any = getAuthCache(USER_INFO_KEY);
84 93 const userId = userInfo.userId;
  94 + const { hasPermission } = usePermission();
85 95
86 96 const [registerDrawer, { openDrawer }] = useDrawer();
87 97 const [registerTable, { reload, setProps, setSelectedRowKeys }] = useTable({
... ...
... ... @@ -17,13 +17,21 @@
17 17 </Authority>
18 18 </template>
19 19 <template #status="{ record }">
20   - <Switch
21   - :checked="record.status === 1"
22   - :loading="record.pendingStatus"
23   - checkedChildren="启用"
24   - unCheckedChildren="禁用"
25   - @change="(checked:boolean)=>statusChange(checked,record)"
26   - />
  20 + <Authority value="api:yt:convert:js:status">
  21 + <Switch
  22 + :checked="record.status === 1"
  23 + :loading="record.pendingStatus"
  24 + checkedChildren="启用"
  25 + unCheckedChildren="禁用"
  26 + @change="(checked:boolean)=>statusChange(checked,record)"
  27 + />
  28 + </Authority>
  29 + <Tag
  30 + v-if="!hasPermission('api:yt:convert:js:status')"
  31 + :color="record.status ? 'green' : 'red'"
  32 + >
  33 + {{ record.status ? '启用' : '禁用' }}
  34 + </Tag>
27 35 </template>
28 36 <template #action="{ record }">
29 37 <TableAction
... ... @@ -69,7 +77,7 @@
69 77
70 78 <script lang="ts" setup>
71 79 import { ref, nextTick } from 'vue';
72   - import { Switch, Popconfirm } from 'ant-design-vue';
  80 + import { Switch, Popconfirm, Tag } from 'ant-design-vue';
73 81 import { BasicTable, useTable, TableAction } from '/@/components/Table';
74 82 import { columns } from '../config/config.data';
75 83 import { getConvertApi, deleteTransformApi } from '/@/api/device/TransformScriptApi';
... ... @@ -81,11 +89,14 @@
81 89 import { useBatchDelete } from '/@/hooks/web/useBatchDelete';
82 90 import { Authority } from '/@/components/Authority';
83 91 import { computed, unref } from 'vue';
  92 + import { usePermission } from '/@/hooks/web/usePermission';
84 93
85 94 const props = defineProps<{ searchInfo: Recordable }>();
86 95
87 96 const getSearchInfo = computed(() => props.searchInfo);
88 97
  98 + const { hasPermission } = usePermission();
  99 +
89 100 const handleSuccess = () => {
90 101 reload();
91 102 };
... ...
... ... @@ -16,8 +16,8 @@
16 16 <div class="hidden min-h-full pl-4 mr-4 xl:flex xl:flex-col xl:w-6/12">
17 17 <!-- <AppLogo class="-enter-x" /> -->
18 18 <div style="display: flex; margin-top: 10px">
19   - <img v-if="defaultLogo" :src="defaultLogo" style="width: 48px; height: 48px" />
20   - <img style="width: 48px; height: 48px" v-else src="/src/assets/images/logo.png" />
  19 + <img v-if="defaultLogo" :src="defaultLogo" class="h-12" />
  20 + <img class="h-12" v-else src="/src/assets/images/logo.png" />
21 21 <div
22 22 class="ml-2 truncate md:opacity-100"
23 23 style="
... ...
... ... @@ -24,8 +24,9 @@
24 24 :customRequest="customUploadIconPic"
25 25 :before-upload="beforeUploadIconPic"
26 26 >
27   - <div v-if="iconPic">
  27 + <div v-if="iconPic" class="relative">
28 28 <img :src="iconPic" class="m-auto fill-img" />
  29 + <CloseCircleOutlined class="absolute icon-delete" @click.stop="handleDelete" />
29 30 <div style="background-color: #ccc; margin-top: 20px">重新上传</div>
30 31 </div>
31 32 <div v-else>
... ... @@ -81,7 +82,7 @@
81 82 import { useMessage } from '/@/hooks/web/useMessage';
82 83 import type { FileItem } from '/@/components/Upload/src/typing';
83 84 import { iconUpload, getPlatForm, updatePlatForm, resetPlateInfo } from '/@/api/oem/index';
84   - import { PlusOutlined } from '@ant-design/icons-vue';
  85 + import { PlusOutlined, CloseCircleOutlined } from '@ant-design/icons-vue';
85 86 import { useUserStore } from '/@/store/modules/user';
86 87 import { createLocalStorage } from '/@/utils/cache/index';
87 88 import { Authority } from '/@/components/Authority';
... ... @@ -100,6 +101,7 @@
100 101 ContentUploadText,
101 102 Spin,
102 103 CustomUploadComp,
  104 + CloseCircleOutlined,
103 105 },
104 106 setup() {
105 107 const loading = ref(false);
... ... @@ -188,6 +190,11 @@
188 190 storage.set('platformInfo', newFieldValue);
189 191 }
190 192
  193 + // 删除浏览器ico图标
  194 + const handleDelete = () => {
  195 + iconPic.value = '';
  196 + };
  197 +
191 198 onMounted(async () => {
192 199 const res = await getPlatForm();
193 200 setFieldsValue(res);
... ... @@ -227,6 +234,7 @@
227 234 handleResetInfo,
228 235 handleSetBgImgUrl,
229 236 handleSetLogoImgUrl,
  237 + handleDelete,
230 238 };
231 239 },
232 240 });
... ... @@ -251,4 +259,12 @@
251 259 width: 100%;
252 260 height: 100%;
253 261 }
  262 +
  263 + .icon-delete {
  264 + top: -13px;
  265 + right: -13px;
  266 + color: rgb(146, 145, 145);
  267 + font-size: 1rem;
  268 + z-index: 9999;
  269 + }
254 270 </style>
... ...
1 1 <script setup name="CustomUploadComp" lang="ts">
2   - import { PlusOutlined } from '@ant-design/icons-vue';
  2 + import { PlusOutlined, CloseCircleOutlined } from '@ant-design/icons-vue';
3 3 import { Upload, Spin } from 'ant-design-vue';
4 4 import { ref, watchEffect } from 'vue';
5 5 import { useUpload } from './hooks/useUploadFile.hook';
... ... @@ -40,6 +40,12 @@
40 40 }
41 41 };
42 42
  43 + // 删除图片
  44 + const handleDelete = () => {
  45 + uploadImgUrl.value = '';
  46 + emit('setImg', uploadImgUrl.value);
  47 + };
  48 +
43 49 watchEffect(() => {
44 50 init();
45 51 });
... ... @@ -59,7 +65,10 @@
59 65 :customRequest="customUpload"
60 66 :before-upload="beforeUploadVerify"
61 67 >
62   - <img v-if="uploadImgUrl" class="fill-img" :src="uploadImgUrl" alt="avatar" />
  68 + <div v-if="uploadImgUrl" class="w-full h-full modal-div relative">
  69 + <img class="fill-img" :src="uploadImgUrl" alt="avatar" />
  70 + <CloseCircleOutlined class="absolute icon-delete" @click.stop="handleDelete" />
  71 + </div>
63 72 <div v-else>
64 73 <Spin v-if="uploadLoading" tip="正在上传中..." />
65 74 <PlusOutlined v-else />
... ... @@ -74,4 +83,12 @@
74 83 width: 100%;
75 84 height: 100%;
76 85 }
  86 +
  87 + .icon-delete {
  88 + top: -13px;
  89 + right: -13px;
  90 + color: rgb(146, 145, 145);
  91 + font-size: 1rem;
  92 + z-index: 9999;
  93 + }
77 94 </style>
... ...
... ... @@ -21,13 +21,18 @@
21 21 </Authority>
22 22 </template>
23 23 <template #status="{ record }">
24   - <Switch
25   - :checked="record.status === 1"
26   - :loading="record.pendingStatus"
27   - checkedChildren="启用"
28   - unCheckedChildren="禁用"
29   - @change="(checked:boolean)=>statusChange(checked,record)"
30   - />
  24 + <Authority value="api:yt:role:status">
  25 + <Switch
  26 + :checked="record.status === 1"
  27 + :loading="record.pendingStatus"
  28 + checkedChildren="启用"
  29 + unCheckedChildren="禁用"
  30 + @change="(checked:boolean)=>statusChange(checked,record)"
  31 + />
  32 + </Authority>
  33 + <Tag v-if="!hasPermission('api:yt:role:status')" :color="record.status ? 'green' : 'red'">
  34 + {{ record.status ? '启用' : '禁用' }}
  35 + </Tag>
31 36 </template>
32 37 <template #action="{ record }">
33 38 <TableAction
... ... @@ -67,12 +72,14 @@
67 72 import { Authority } from '/@/components/Authority';
68 73 import { useBatchDelete } from '/@/hooks/web/useBatchDelete';
69 74 import { useMessage } from '/@/hooks/web/useMessage';
70   - import { Switch, Popconfirm } from 'ant-design-vue';
  75 + import { Switch, Popconfirm, Tag } from 'ant-design-vue';
  76 + import { usePermission } from '/@/hooks/web/usePermission';
71 77
72 78 export default defineComponent({
73 79 name: 'RoleManagement',
74   - components: { BasicTable, RoleDrawer, TableAction, Authority, Switch, Popconfirm },
  80 + components: { BasicTable, RoleDrawer, TableAction, Authority, Switch, Popconfirm, Tag },
75 81 setup() {
  82 + const { hasPermission } = usePermission();
76 83 const [registerDrawer, { openDrawer }] = useDrawer();
77 84 function handleSuccess() {
78 85 reload();
... ... @@ -157,6 +164,7 @@
157 164 hasBatchDelete,
158 165 handleDeleteOrBatchDelete,
159 166 statusChange,
  167 + hasPermission,
160 168 };
161 169 },
162 170 });
... ...
... ... @@ -7,7 +7,7 @@ export const validateDevicePicker = () => {
7 7 validateTrigger: 'blur',
8 8 validator(_rule: Recordable, value: Recordable, _callback: Fn) {
9 9 const device = Reflect.get(value || {}, FormFieldsEnum.DEVICE);
10   - if (!device) return Promise.reject('请选择设备');
  10 + if (!device || !device.length) return Promise.reject('请选择设备');
11 11 return Promise.resolve();
12 12 },
13 13 } as Rule;
... ...
... ... @@ -41,7 +41,9 @@
41 41 const inputType = ref(props.type);
42 42
43 43 const getInputValue = computed(() => {
44   - const { type, value, toUpperCase } = props;
  44 + const { type, toUpperCase } = props;
  45 + let { value } = props;
  46 + if (isNaN(value as number)) value = undefined;
45 47
46 48 if (isNullOrUnDef(value)) return value;
47 49
... ...
... ... @@ -133,6 +133,7 @@
133 133 text: '详情',
134 134 event: DropMenuEvent.DETAIL,
135 135 icon: 'ant-design:eye-outlined',
  136 + auth: PermissionEnum.DETAIL,
136 137 onClick: emit.bind(null, 'detail', getRecord),
137 138 },
138 139 {
... ...
... ... @@ -7,6 +7,7 @@ export enum PermissionEnum {
7 7 DELETE = 'api:yt:task_center:delete',
8 8 ALLOW = 'api:yt:task_center:cancel:allow',
9 9 EXECUTE = 'api:yt:task_center:immediate:execute',
  10 + DETAIL = 'api:yt:task_center:get',
10 11 }
11 12
12 13 export enum FormFieldsEnum {
... ...
... ... @@ -16,6 +16,7 @@
16 16 :replaceFields="{ title: 'name', key: 'id' }"
17 17 :checkedKeys="roleMenus"
18 18 @check="handleCheckClick"
  19 + @unSelectAll="handleUnSelectAll"
19 20 checkable
20 21 toolbar
21 22 ref="treeRef"
... ... @@ -128,6 +129,11 @@
128 129 });
129 130 const getTitle = computed(() => (!unref(isUpdate) ? '新增角色' : '编辑角色'));
130 131
  132 + // 取消全部的时候清除回显时获取的
  133 + const handleUnSelectAll = () => {
  134 + checkedKeysWithHalfChecked.value = [];
  135 + };
  136 +
131 137 async function handleSubmit() {
132 138 setDrawerProps({ loading: true, confirmLoading: true });
133 139 const { createMessage } = useMessage();
... ... @@ -143,7 +149,8 @@
143 149 roleType: RoleEnum.TENANT_ADMIN,
144 150 menu,
145 151 };
146   - if (req.menu == undefined) return createMessage.error('请勾选权限菜单');
  152 + if (req.menu == undefined || !req.menu.length)
  153 + return createMessage.error('请勾选权限菜单');
147 154 const res = await saveOrUpdateRoleInfoWithMenu(req);
148 155 if (res) {
149 156 closeDrawer();
... ... @@ -247,6 +254,7 @@
247 254 roleMenus,
248 255 treeRef,
249 256 handleCheckClick,
  257 + handleUnSelectAll,
250 258 };
251 259 },
252 260 });
... ...
... ... @@ -9,6 +9,7 @@ export enum VisualBoardPermission {
9 9 UPDATE = 'api:yt:data_board:update:update',
10 10 DELETE = 'api:yt:data_board:delete',
11 11 CREATE = '',
  12 + SHARE = 'api:yt:data_board:share',
12 13 DETAIL = 'api:yt:data_component:list',
13 14 }
14 15
... ...
... ... @@ -99,19 +99,22 @@
99 99 const dropMenuList = computed<DropMenu[]>(() => {
100 100 const hasUpdatePermission = hasPermission(VisualBoardPermission.UPDATE);
101 101 const hasDeletePermission = hasPermission(VisualBoardPermission.DELETE);
102   - const basicMenu: DropMenu[] = [
103   - {
104   - text: '分享',
105   - event: MoreActionEvent.SHARE,
106   - icon: 'ant-design:share-alt-outlined',
107   - },
108   - ];
  102 + const hasSharePermission = hasPermission(VisualBoardPermission.SHARE);
  103 + let basicMenu: DropMenu[] = [];
109 104 if (hasUpdatePermission)
110 105 basicMenu.push({
111 106 text: '编辑',
112 107 event: MoreActionEvent.EDIT,
113 108 icon: 'ant-design:edit-outlined',
114 109 });
  110 + if (hasSharePermission) {
  111 + basicMenu.push({
  112 + text: '分享',
  113 + event: MoreActionEvent.SHARE,
  114 + icon: 'ant-design:share-alt-outlined',
  115 + });
  116 + }
  117 +
115 118 if (hasDeletePermission)
116 119 basicMenu.push({
117 120 text: '删除',
... ...
... ... @@ -122,7 +122,7 @@
122 122 });
123 123 };
124 124
125   - const handleCopy = (record: DataSourceType) => {
  125 + const handleCopy = async (record: DataSourceType) => {
126 126 const { key } = props.componentConfig || {};
127 127 if (key == 'HumidityComponent2' && props.dataSource.length >= 6) {
128 128 createMessage.warning('绑定的数据源不能超过6条~');
... ... @@ -134,7 +134,7 @@
134 134 return;
135 135 }
136 136
137   - const allValues = getFormValues();
  137 + const allValues = await getFormValues();
138 138 const currentRecord = getFormValueByUUID(record.uuid);
139 139 const uuid = trackUpdate();
140 140 const raw = toRaw(record);
... ... @@ -173,7 +173,7 @@
173 173
174 174 const handleSettingOk = (data: DataSourceType) => {
175 175 const { uuid } = data;
176   - const _dataSource = cloneDeep(props.dataSource);
  176 + const _dataSource = cloneDeep(getFormValues());
177 177
178 178 const index = _dataSource.findIndex((item) => item.uuid === uuid);
179 179
... ...
... ... @@ -95,6 +95,11 @@
95 95 };
96 96 setFormValues(record);
97 97 } else {
  98 + selectWidgetKeys.value = {
  99 + componentKey: TextComponent1Config.key,
  100 + categoryKey: PackagesCategoryEnum.TEXT,
  101 + };
  102 + activeKey.value = TabKeyEnum.BASIC;
98 103 dataSource.value = [genNewDataSourceItem()];
99 104 }
100 105 }
... ...
... ... @@ -16,6 +16,7 @@ export const option: PublicPresetOptions = {
16 16 [ComponentConfigFieldEnum.CLOSE_COLOR]: '#FF0000',
17 17 [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: true,
18 18 [ComponentConfigFieldEnum.SHOW_TIME]: false,
  19 + [ComponentConfigFieldEnum.FONT_SIZE]: 14,
19 20 };
20 21
21 22 export default class Config extends PublicConfigClass implements CreateComponentType {
... ...
... ... @@ -36,6 +36,23 @@
36 36 component: 'Checkbox',
37 37 defaultValue: option.showTime,
38 38 },
  39 + {
  40 + field: ComponentConfigFieldEnum.FONT_SIZE,
  41 + label: '文本字体大小',
  42 + component: 'InputNumber',
  43 + defaultValue: 14,
  44 + componentProps: {
  45 + min: 0,
  46 + formatter: (e) => {
  47 + const value = e.replace(/^0/g, '');
  48 + if (value) {
  49 + return value.replace(/^0/g, '');
  50 + } else {
  51 + return 0;
  52 + }
  53 + },
  54 + },
  55 + },
39 56 ],
40 57 showActionButtonGroup: false,
41 58 labelWidth: 120,
... ...
... ... @@ -24,6 +24,7 @@
24 24 showTime: boolean;
25 25 status: IStatus;
26 26 time: number;
  27 + fontSize?: number;
27 28 }
28 29
29 30 const props = defineProps<{
... ... @@ -53,7 +54,11 @@
53 54 const getDesign = computed(() => {
54 55 const { persetOption = {}, option } = props.config;
55 56 const { dataSource } = option;
56   - const { showDeviceName: presetShowDeviceName, showTime: persetShowTime } = persetOption;
  57 + const {
  58 + showDeviceName: presetShowDeviceName,
  59 + showTime: persetShowTime,
  60 + fontSize: persetFontSize,
  61 + } = persetOption;
57 62
58 63 return {
59 64 dataSource: dataSource?.map((item) => {
... ... @@ -63,6 +68,7 @@
63 68 deviceName: deviceRename || deviceName,
64 69 showDeviceName: componentInfo.showDeviceName ?? presetShowDeviceName,
65 70 showTime: componentInfo.showTime ?? persetShowTime,
  71 + fontSize: componentInfo.fontSize || persetFontSize,
66 72 };
67 73 }),
68 74 };
... ... @@ -82,6 +88,7 @@
82 88 time: 1689574726,
83 89 showDeviceName: true,
84 90 showTime: true,
  91 + fontSize: 14,
85 92 },
86 93 ]);
87 94
... ... @@ -133,6 +140,7 @@
133 140 showTime: item.showTime,
134 141 status: { text: '', color: '' },
135 142 time: 0,
  143 + fontSize: item.fontSize,
136 144 };
137 145 }) as any;
138 146 const { data, update } = message;
... ... @@ -163,7 +171,7 @@
163 171 <main :style="getScale" class="w-full h-full flex justify-center items-center">
164 172 <div v-for="item in alarmStatusList" :key="item.id" class="flex flex-col items-center">
165 173 <div class="flex justify-center items-center flex-col">
166   - <div class="text-gray-500 text-sm truncate"
  174 + <div class="text-gray-500 truncate" :style="{ fontSize: item.fontSize + 'px' }"
167 175 >{{
168 176 item.status.text
169 177 ? item.showDeviceName
... ...
... ... @@ -11,6 +11,7 @@ import { ComponentConfigFieldEnum } from '../../../enum';
11 11
12 12 export const option: PublicPresetOptions = {
13 13 [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: false,
  14 + [ComponentConfigFieldEnum.FONT_SIZE]: 14,
14 15 // [ComponentConfigFieldEnum.FONT_COLOR]: '#000',
15 16 };
16 17
... ...
... ... @@ -19,6 +19,12 @@
19 19 component: 'Checkbox',
20 20 defaultValue: option.showDeviceName,
21 21 },
  22 + {
  23 + field: ComponentConfigFieldEnum.FONT_SIZE,
  24 + label: '文本字体大小',
  25 + component: 'InputNumber',
  26 + defaultValue: 14,
  27 + },
22 28 ],
23 29 showActionButtonGroup: false,
24 30 labelWidth: 120,
... ...
... ... @@ -32,6 +32,10 @@
32 32 transportType: value.transportType,
33 33 service: value.service,
34 34 command: value.command,
  35 + openService: value.openService,
  36 + closeService: value.closeService,
  37 + openCommand: value.openCommand,
  38 + closeCommand: value.closeCommand,
35 39 commandType: value.commandType,
36 40 callType: value.callType,
37 41 },
... ... @@ -45,6 +49,10 @@
45 49 ...record,
46 50 transportType: customCommand?.transportType || (record as Recordable).transportType,
47 51 service: customCommand?.service || (record as Recordable).service,
  52 + openService: customCommand?.openService || (record as Recordable).openService,
  53 + closeService: customCommand?.closeService || (record as Recordable).closeService,
  54 + openCommand: customCommand?.openCommand || (record as Recordable).openCommand,
  55 + closeCommand: customCommand?.closeCommand || (record as Recordable).closeCommand,
48 56 command: customCommand?.command || (record as Recordable).command,
49 57 commandType: customCommand?.commandType || (record as Recordable).commandType,
50 58 callType: customCommand?.callType || (record as Recordable).callType,
... ...
... ... @@ -2,12 +2,13 @@
2 2 import { ComponentPropsConfigType } from '/@/views/visual/packages/index.type';
3 3 import { option } from './config';
4 4 import { Spin } from 'ant-design-vue';
5   - import { computed, ref } from 'vue';
  5 + import { computed, ref, unref } from 'vue';
6 6 import { useComponentScale } from '../../../hook/useComponentScale';
7 7 import { useSendCommand } from '../../../hook/useSendCommand';
8 8 import { DeviceName } from '/@/views/visual/commonComponents/DeviceName';
9 9 import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type';
10 10 import { useDataFetch } from '../../../hook/socket/useSocket';
  11 + import { getSendValues } from '../config';
11 12
12 13 const props = defineProps<{
13 14 config: ComponentPropsConfigType<typeof option>;
... ... @@ -18,10 +19,28 @@
18 19 const currentValue = ref(false);
19 20
20 21 const getDesign = computed(() => {
21   - const { option } = props.config;
22   - const { attribute, attributeRename, attributeName } = option;
  22 + const { option, persetOption } = props.config;
  23 + const {
  24 + attribute,
  25 + attributeRename,
  26 + attributeName,
  27 + componentInfo,
  28 + commandType,
  29 + extensionDesc,
  30 + codeType,
  31 + deviceCode,
  32 + customCommand,
  33 + } = option;
  34 + const { fontSize: persetFontSize } = persetOption || {};
  35 + const { fontSize } = componentInfo || {};
23 36 return {
24 37 attribute: attributeRename || attributeName || attribute,
  38 + fontSize: fontSize || persetFontSize || 14,
  39 + extensionDesc: extensionDesc ? JSON.parse(extensionDesc) : {},
  40 + commandType,
  41 + codeType,
  42 + deviceCode,
  43 + customCommand,
25 44 };
26 45 });
27 46
... ... @@ -29,8 +48,12 @@
29 48 const handleChange = async (event: Event) => {
30 49 const target = event.target as HTMLInputElement;
31 50 const value = target.checked;
  51 + const { option } = props.config || {};
32 52
33   - const flag = await sendCommand(props.config.option, value);
  53 + const { values, isModbusCommand, sendValue } =
  54 + (await getSendValues(option, unref(getDesign), value)) || {};
  55 +
  56 + const flag = await sendCommand(values, isModbusCommand ? sendValue : value, isModbusCommand);
34 57 if (flag) currentValue.value = value;
35 58 flag ? (currentValue.value = value) : (target.checked = !value);
36 59 };
... ... @@ -61,7 +84,10 @@
61 84 <span class="on">ON</span>
62 85 <span class="off">OFF</span>
63 86 </label>
64   - <div class="text-center mt-2 text-gray-700" :style="getScale">
  87 + <div
  88 + class="text-center mt-2 text-gray-700"
  89 + :style="{ ...getScale, fontSize: getDesign.fontSize + 'px' }"
  90 + >
65 91 {{ getDesign.attribute || '属性' }}
66 92 </div>
67 93 </Spin>
... ...
... ... @@ -13,6 +13,7 @@ export const option: PublicPresetOptions = {
13 13 [ComponentConfigFieldEnum.ICON]: 'shuiwen',
14 14 [ComponentConfigFieldEnum.ICON_COLOR]: '#377DFF',
15 15 [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: false,
  16 + [ComponentConfigFieldEnum.FONT_SIZE]: 14,
16 17 };
17 18
18 19 export default class Config extends PublicConfigClass implements CreateComponentType {
... ...
... ... @@ -32,6 +32,12 @@
32 32 component: 'Checkbox',
33 33 defaultValue: option.showDeviceName,
34 34 },
  35 + {
  36 + field: ComponentConfigFieldEnum.FONT_SIZE,
  37 + label: '文本字体大小',
  38 + component: 'InputNumber',
  39 + defaultValue: option.fontSize,
  40 + },
35 41 ],
36 42 showActionButtonGroup: false,
37 43 labelWidth: 120,
... ...
... ... @@ -32,6 +32,10 @@
32 32 transportType: value.transportType,
33 33 service: value.service,
34 34 command: value.command,
  35 + openService: value.openService,
  36 + closeService: value.closeService,
  37 + openCommand: value.openCommand,
  38 + closeCommand: value.closeCommand,
35 39 commandType: value.commandType,
36 40 callType: value.callType,
37 41 },
... ... @@ -41,14 +45,20 @@
41 45
42 46 const setFormValues = (record: DataSource) => {
43 47 const { customCommand } = record;
44   - return setFieldsValue({
  48 + const values = {
45 49 ...record,
46 50 transportType: customCommand?.transportType || (record as Recordable).transportType,
47 51 service: customCommand?.service || (record as Recordable).service,
48 52 command: customCommand?.command || (record as Recordable).command,
  53 + openService: customCommand?.openService || (record as Recordable).openService,
  54 + closeService: customCommand?.closeService || (record as Recordable).closeService,
  55 + openCommand: customCommand?.openCommand || (record as Recordable).openCommand,
  56 + closeCommand: customCommand?.closeCommand || (record as Recordable).closeCommand,
49 57 commandType: customCommand?.commandType || (record as Recordable).commandType,
50 58 callType: customCommand?.callType || (record as Recordable).callType,
51   - } as unknown as Partial<CommonDataSourceBindValueType>);
  59 + } as unknown as Partial<CommonDataSourceBindValueType>;
  60 +
  61 + return setFieldsValue(values);
52 62 };
53 63
54 64 defineExpose({
... ...
... ... @@ -10,6 +10,7 @@
10 10 import { DeviceName } from '/@/views/visual/commonComponents/DeviceName';
11 11 import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type';
12 12 import { useDataFetch } from '../../../hook/socket/useSocket';
  13 + import { getSendValues } from '../config';
13 14
14 15 const props = defineProps<{
15 16 config: ComponentPropsConfigType<typeof option>;
... ... @@ -19,19 +20,50 @@
19 20
20 21 const getDesign = computed(() => {
21 22 const { option, persetOption } = props.config;
22   - const { componentInfo, attribute, attributeRename, attributeName } = option;
23   - const { icon: presetIcon, iconColor: presetIconColor } = persetOption || {};
24   - const { icon, iconColor } = componentInfo || {};
  23 + const {
  24 + componentInfo,
  25 + attribute,
  26 + attributeRename,
  27 + attributeName,
  28 + commandType,
  29 + extensionDesc,
  30 + codeType,
  31 + deviceCode,
  32 + customCommand,
  33 + } = option;
  34 + const {
  35 + icon: presetIcon,
  36 + iconColor: presetIconColor,
  37 + fontSize: persetFontSize,
  38 + } = persetOption || {};
  39 + const { icon, iconColor, fontSize } = componentInfo || {};
  40 +
25 41 return {
26 42 icon: icon ?? presetIcon,
27 43 iconColor: iconColor || presetIconColor,
28 44 attribute: attributeRename || attributeName || attribute,
  45 + extensionDesc: extensionDesc ? JSON.parse(extensionDesc) : {},
  46 + fontSize: fontSize || persetFontSize || 14,
  47 + commandType,
  48 + codeType,
  49 + deviceCode,
  50 + customCommand,
29 51 };
30 52 });
31 53
32 54 const { sendCommand, loading } = useSendCommand();
  55 +
33 56 const handleChange = async () => {
34   - const flag = await sendCommand(props.config.option, unref(checked));
  57 + const { option } = props.config || {};
  58 +
  59 + const { values, isModbusCommand, sendValue } =
  60 + (await getSendValues(option, unref(getDesign), unref(checked))) || {};
  61 +
  62 + const flag = await sendCommand(
  63 + values,
  64 + isModbusCommand ? sendValue : unref(checked),
  65 + isModbusCommand
  66 + );
35 67 if (!flag) checked.value = !unref(checked);
36 68 };
37 69
... ... @@ -57,7 +89,10 @@
57 89 :style="{ color: getDesign.iconColor }"
58 90 :size="50"
59 91 />
60   - <span class="mt-3 truncate text-gray-500 text-xs text-center">
  92 + <span
  93 + class="mt-3 truncate text-gray-500 text-center"
  94 + :style="{ fontSize: getDesign.fontSize + 'px' }"
  95 + >
61 96 {{ getDesign.attribute || '属性' }}
62 97 </span>
63 98 </div>
... ...
... ... @@ -11,6 +11,7 @@ import { ComponentConfigFieldEnum } from '../../../enum';
11 11
12 12 export const option: PublicPresetOptions = {
13 13 [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: false,
  14 + [ComponentConfigFieldEnum.FONT_SIZE]: 14,
14 15 // [ComponentConfigFieldEnum.FONT_COLOR]: '#000',
15 16 };
16 17
... ...
... ... @@ -18,6 +18,12 @@
18 18 component: 'Checkbox',
19 19 defaultValue: option.showDeviceName,
20 20 },
  21 + {
  22 + field: ComponentConfigFieldEnum.FONT_SIZE,
  23 + label: '文本字体大小',
  24 + component: 'InputNumber',
  25 + defaultValue: option.fontSize,
  26 + },
21 27 ],
22 28 showActionButtonGroup: false,
23 29 labelWidth: 120,
... ...
... ... @@ -32,6 +32,10 @@
32 32 transportType: value.transportType,
33 33 service: value.service,
34 34 command: value.command,
  35 + openService: value.openService,
  36 + closeService: value.closeService,
  37 + openCommand: value.openCommand,
  38 + closeCommand: value.closeCommand,
35 39 commandType: value.commandType,
36 40 callType: value.callType,
37 41 },
... ... @@ -45,6 +49,10 @@
45 49 ...record,
46 50 transportType: customCommand?.transportType || (record as Recordable).transportType,
47 51 service: customCommand?.service || (record as Recordable).service,
  52 + openService: customCommand?.openService || (record as Recordable).openService,
  53 + closeService: customCommand?.closeService || (record as Recordable).closeService,
  54 + openCommand: customCommand?.openCommand || (record as Recordable).openCommand,
  55 + closeCommand: customCommand?.closeCommand || (record as Recordable).closeCommand,
48 56 command: customCommand?.command || (record as Recordable).command,
49 57 commandType: customCommand?.commandType || (record as Recordable).commandType,
50 58 callType: customCommand?.callType || (record as Recordable).callType,
... ...
... ... @@ -2,12 +2,13 @@
2 2 import { ComponentPropsConfigType } from '/@/views/visual/packages/index.type';
3 3 import { option } from './config';
4 4 import { Spin } from 'ant-design-vue';
5   - import { computed, ref } from 'vue';
  5 + import { computed, ref, unref } from 'vue';
6 6 import { useComponentScale } from '../../../hook/useComponentScale';
7 7 import { useSendCommand } from '../../../hook/useSendCommand';
8 8 import { DeviceName } from '/@/views/visual/commonComponents/DeviceName';
9 9 import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type';
10 10 import { useDataFetch } from '../../../hook/socket/useSocket';
  11 + import { getSendValues } from '../config';
11 12
12 13 const props = defineProps<{
13 14 config: ComponentPropsConfigType<typeof option>;
... ... @@ -18,10 +19,28 @@
18 19 const currentValue = ref(false);
19 20
20 21 const getDesign = computed(() => {
21   - const { option } = props.config;
22   - const { attribute, attributeRename, attributeName } = option;
  22 + const { option, persetOption } = props.config;
  23 + const {
  24 + attribute,
  25 + attributeRename,
  26 + attributeName,
  27 + commandType,
  28 + extensionDesc,
  29 + codeType,
  30 + deviceCode,
  31 + customCommand,
  32 + componentInfo,
  33 + } = option;
  34 + const { fontSize: persetFontSize } = persetOption || {};
  35 + const { fontSize } = componentInfo || {};
23 36 return {
24 37 attribute: attributeRename || attributeName || attribute,
  38 + extensionDesc: extensionDesc ? JSON.parse(extensionDesc) : {},
  39 + commandType,
  40 + codeType,
  41 + deviceCode,
  42 + customCommand,
  43 + fontSize: fontSize || persetFontSize || 14,
25 44 };
26 45 });
27 46
... ... @@ -29,7 +48,12 @@
29 48 const handleChange = async (event: Event) => {
30 49 const target = event.target as HTMLInputElement;
31 50 const value = target.checked;
32   - const flag = await sendCommand(props.config.option, value);
  51 + const { option } = props.config || {};
  52 +
  53 + const { values, isModbusCommand, sendValue } =
  54 + (await getSendValues(option, unref(getDesign), value)) || {};
  55 +
  56 + const flag = await sendCommand(values, isModbusCommand ? sendValue : value, isModbusCommand);
33 57 flag ? (currentValue.value = value) : (target.checked = !value);
34 58 };
35 59
... ... @@ -60,9 +84,11 @@
60 84 </div>
61 85 </label>
62 86 </div>
63   - <div class="text-center mt-2 text-gray-500" :style="getScale">{{
64   - getDesign.attribute || '属性'
65   - }}</div>
  87 + <div
  88 + class="text-center mt-2 text-gray-500"
  89 + :style="{ ...getScale, fontSize: getDesign.fontSize + 'px' }"
  90 + >{{ getDesign.attribute || '属性' }}</div
  91 + >
66 92 </Spin>
67 93 </main>
68 94 </main>
... ...
... ... @@ -13,8 +13,11 @@ export const option: PublicPresetOptions = {
13 13 [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: false,
14 14 [ComponentConfigFieldEnum.CONTROL_BAR_COLOR]: '#0072ff',
15 15 [ComponentConfigFieldEnum.FONT_COLOR]: '#000000',
  16 + [ComponentConfigFieldEnum.TEXT_COLOR]: '#000000',
16 17 [ComponentConfigFieldEnum.MIN_NUMBER]: 0,
17 18 [ComponentConfigFieldEnum.MAX_NUMBER]: 100,
  19 + [ComponentConfigFieldEnum.FONT_SIZE]: 14,
  20 + [ComponentConfigFieldEnum.VALUE_SIZE]: 20,
18 21 };
19 22
20 23 export default class Config extends PublicConfigClass implements CreateComponentType {
... ...
... ... @@ -8,20 +8,39 @@
8 8 const [register, { getFieldsValue, setFieldsValue, resetFields }] = useForm({
9 9 schemas: [
10 10 {
11   - field: ComponentConfigFieldEnum.CONTROL_BAR_COLOR,
12   - label: '控制栏背景色',
  11 + field: ComponentConfigFieldEnum.FONT_COLOR,
  12 + label: '数值字体颜色',
13 13 component: 'ColorPicker',
14 14 changeEvent: 'update:value',
15   - defaultValue: option.controlBarColor,
  15 + defaultValue: option.fontColor,
16 16 },
17 17 {
18   - field: ComponentConfigFieldEnum.FONT_COLOR,
19   - label: '数值字体颜色',
  18 + field: ComponentConfigFieldEnum.VALUE_SIZE,
  19 + label: '数值字体大小',
  20 + component: 'InputNumber',
  21 + defaultValue: option.fontSize,
  22 + },
  23 + {
  24 + field: ComponentConfigFieldEnum.TEXT_COLOR,
  25 + label: '文本字体颜色',
20 26 component: 'ColorPicker',
21 27 changeEvent: 'update:value',
22 28 defaultValue: option.fontColor,
23 29 },
24 30 {
  31 + field: ComponentConfigFieldEnum.FONT_SIZE,
  32 + label: '文本字体大小',
  33 + component: 'InputNumber',
  34 + defaultValue: option.fontSize,
  35 + },
  36 + {
  37 + field: ComponentConfigFieldEnum.CONTROL_BAR_COLOR,
  38 + label: '控制栏背景色',
  39 + component: 'ColorPicker',
  40 + changeEvent: 'update:value',
  41 + defaultValue: option.controlBarColor,
  42 + },
  43 + {
25 44 field: ComponentConfigFieldEnum.MIN_NUMBER,
26 45 label: '最小值',
27 46 component: 'InputNumber',
... ... @@ -61,6 +80,7 @@
61 80 };
62 81 },
63 82 },
  83 +
64 84 {
65 85 field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME,
66 86 label: '显示设备名称',
... ...
... ... @@ -32,6 +32,10 @@
32 32 transportType: value.transportType,
33 33 service: value.service,
34 34 command: value.command,
  35 + openService: value.openService,
  36 + closeService: value.closeService,
  37 + openCommand: value.openCommand,
  38 + closeCommand: value.closeCommand,
35 39 commandType: value.commandType,
36 40 },
37 41 };
... ... @@ -42,10 +46,14 @@
42 46 const { customCommand } = record;
43 47 return setFieldsValue({
44 48 ...record,
45   - transportType: customCommand?.transportType,
46   - service: customCommand?.service,
47   - command: customCommand?.command,
48   - commandType: customCommand?.commandType,
  49 + transportType: customCommand?.transportType || (record as Recordable).transportType,
  50 + service: customCommand?.service || (record as Recordable).service,
  51 + openService: customCommand?.openService || (record as Recordable).openService,
  52 + closeService: customCommand?.closeService || (record as Recordable).closeService,
  53 + openCommand: customCommand?.openCommand || (record as Recordable).openCommand,
  54 + closeCommand: customCommand?.closeCommand || (record as Recordable).closeCommand,
  55 + command: customCommand?.command || (record as Recordable).command,
  56 + commandType: customCommand?.commandType || (record as Recordable).command,
49 57 } as unknown as Partial<CommonDataSourceBindValueType>);
50 58 };
51 59
... ...
... ... @@ -9,6 +9,10 @@
9 9 import { useReceiveValue } from '../../../hook/useReceiveValue';
10 10 import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type';
11 11 import { useDataFetch } from '../../../hook/socket/useSocket';
  12 + import { TaskTypeEnum } from '/@/views/task/center/config';
  13 + import { useMessage } from '/@/hooks/web/useMessage';
  14 + import { SingleToHex } from '/@/views/device/list/cpns/tabs/ObjectModelCommandDeliveryModal/config';
  15 + import { genModbusCommand } from '/@/api/task';
12 16
13 17 const props = defineProps<{
14 18 config: ComponentPropsConfigType<typeof option>;
... ... @@ -23,20 +27,42 @@
23 27
24 28 const getDesign = computed(() => {
25 29 const { option, persetOption } = props.config;
26   - const { componentInfo, attribute, attributeRename, attributeName } = option;
  30 + const {
  31 + componentInfo,
  32 + attribute,
  33 + attributeRename,
  34 + attributeName,
  35 + commandType,
  36 + extensionDesc,
  37 + codeType,
  38 + deviceCode,
  39 + customCommand,
  40 + } = option;
27 41 const {
28 42 controlBarColor: persetControlBarColor,
29 43 fonColor: persetFontColor,
30 44 minNumber: persetMinNumber,
31 45 maxNumber: persetMaxNumber,
  46 + textColor: persetTextColor,
  47 + valueSize: persetValueSize,
  48 + fontSize: persetFontSize,
32 49 } = persetOption || {};
33   - const { controlBarColor, fontColor, minNumber, maxNumber } = componentInfo || {};
  50 + const { controlBarColor, fontColor, minNumber, maxNumber, textColor, valueSize, fontSize } =
  51 + componentInfo || {};
34 52 return {
35 53 attribute: attributeRename || attributeName || attribute,
36 54 controlBarColor: controlBarColor ?? persetControlBarColor,
37 55 fontColor: fontColor ?? persetFontColor,
38 56 minNumber: minNumber ?? persetMinNumber,
39 57 maxNumber: maxNumber ?? persetMaxNumber,
  58 + extensionDesc: extensionDesc ? JSON.parse(extensionDesc) : {},
  59 + commandType,
  60 + codeType,
  61 + deviceCode,
  62 + customCommand,
  63 + textColor: textColor || persetTextColor,
  64 + valueSize: valueSize || persetValueSize || 20,
  65 + fontSize: fontSize || persetFontSize || 14,
40 66 };
41 67 });
42 68
... ... @@ -59,9 +85,98 @@
59 85 sliderValue.value = afterValue.value; //这一步是因为当我们是点击不是拖动时候,会让值更新不了,所以需要赋值一次
60 86 };
61 87
  88 + const { createMessage } = useMessage();
  89 +
  90 + // 获取小数
  91 + const getFloatPart = (number: string | number) => {
  92 + const isLessZero = Number(number) < 0;
  93 + number = number.toString();
  94 + const floatPartStartIndex = number.indexOf('.');
  95 + const value = ~floatPartStartIndex
  96 + ? `${isLessZero ? '-' : ''}0.${number.substring(floatPartStartIndex + 1)}`
  97 + : '0';
  98 + return Number(value);
  99 + };
  100 +
  101 + const getArray = (values) => {
  102 + const str = values.replace(/\s+/g, '');
  103 + const array: any = [];
  104 +
  105 + for (let i = 0; i < str.length; i += 4) {
  106 + const chunk = parseInt(str.substring(i, i + 4), 16);
  107 + array.push(chunk);
  108 + }
  109 + return array;
  110 + };
  111 +
  112 + const getSendValue = async (value: number) => {
  113 + const { extensionDesc, codeType, deviceCode, customCommand } = unref(getDesign) || {};
  114 + const { transportType } = customCommand || {};
  115 + const { registerAddress, actionType, zoomFactor } = extensionDesc || {};
  116 + const newZoomValue = zoomFactor ? Number(zoomFactor) : 1;
  117 + if (transportType == 'TCP' && codeType == TaskTypeEnum.MODBUS_RTU) {
  118 + if (!deviceCode) {
  119 + createMessage.warning('当前设备没有设置地址码');
  120 + return;
  121 + }
  122 + const modbusForm = ref({
  123 + crc: 'CRC_16_LOWER',
  124 + deviceCode: deviceCode,
  125 + method: actionType == '16' ? '10' : actionType,
  126 + registerAddress,
  127 + registerNumber: 1,
  128 + registerValues: [value],
  129 + }) as any;
  130 + if (!actionType) {
  131 + createMessage.warning('当前物模型扩展描述没有填写');
  132 + return;
  133 + }
  134 + if (actionType == '06') {
  135 + const newValue = Math.trunc(value) * newZoomValue + getFloatPart(value) * newZoomValue;
  136 + if (newValue % 1 != 0) {
  137 + createMessage.warning(`值必须是整数,缩放因子为${unref(newZoomValue)}`);
  138 + return;
  139 + }
  140 +
  141 + if (newValue > 65535) {
  142 + createMessage.warning(`值不能超过65535,缩放因子是${unref(newZoomValue)}`);
  143 + return;
  144 + }
  145 + modbusForm.value.registerValues = [newValue];
  146 + }
  147 + if (actionType == '05') {
  148 + if (Number(value) != 0 || Number(value) != 1) {
  149 + createMessage.warning(`当前物模型仅支持值为0和1`);
  150 + return;
  151 + }
  152 + }
  153 + if (actionType == '16' || actionType == '10') {
  154 + const regex = /^-?\d+(\.\d{0,2})?$/;
  155 + const values =
  156 + Math.trunc(value) * unref(newZoomValue) + getFloatPart(value) * unref(newZoomValue);
  157 + if (!regex.test(values as any)) {
  158 + createMessage.warning(`值精确到两位小数,缩放因子是${unref(newZoomValue)}`);
  159 + return;
  160 + }
  161 + const newValue = values == 0 ? [0, 0] : getArray(SingleToHex(values));
  162 + modbusForm.value.registerValues = newValue;
  163 + modbusForm.value.registerNumber = 2;
  164 + modbusForm.value.method = '10';
  165 + }
  166 + const sendValue = await genModbusCommand(unref(modbusForm));
  167 + return sendValue;
  168 + }
  169 + };
  170 +
62 171 const handleBlur = async () => {
63 172 if (unref(oldSliderValue) !== unref(sliderValue)) {
64   - const flag = await sendCommand(props.config.option, unref(sliderValue));
  173 + const { codeType, customCommand } = unref(getDesign) || {};
  174 + const { transportType } = customCommand || {};
  175 + const sendValue = ref<any>(unref(sliderValue));
  176 + if (transportType == 'TCP' && codeType == TaskTypeEnum.MODBUS_RTU) {
  177 + sendValue.value = await getSendValue(unref(sliderValue));
  178 + }
  179 + const flag = await sendCommand(props.config.option, unref(sendValue), true);
65 180 flag
66 181 ? ((sliderValue.value = unref(sliderValue)),
67 182 (oldSliderValue.value = sliderValue.value),
... ... @@ -90,7 +205,7 @@
90 205 <Spin :spinning="loading" class="w-full h-full">
91 206 <div class="flex flex-col" style="width: 80%">
92 207 <span
93   - :style="{ color: getDesign.fontColor }"
  208 + :style="{ color: getDesign.fontColor, fontSize: getDesign.valueSize + 'px' }"
94 209 class="font-bold text-xl mt-3 truncate text-center"
95 210 >{{ sliderValue }}</span
96 211 >
... ... @@ -107,7 +222,7 @@
107 222 />
108 223
109 224 <span
110   - :style="{ color: getDesign.fontColor }"
  225 + :style="{ color: getDesign.textColor, fontSize: getDesign.fontSize + 'px' }"
111 226 class="mt-3 truncate font-bold text-xs text-center"
112 227 >
113 228 {{ getDesign.attribute || '属性' }}
... ...
... ... @@ -14,6 +14,7 @@ export const option: PublicPresetOptions = {
14 14 [ComponentConfigFieldEnum.ICON]: 'shuiwen',
15 15 [ComponentConfigFieldEnum.ICON_COLOR]: '#377DFF',
16 16 [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: false,
  17 + [ComponentConfigFieldEnum.FONT_SIZE]: 14,
17 18 };
18 19
19 20 export default class Config extends PublicConfigClass implements CreateComponentType {
... ...
... ... @@ -27,6 +27,12 @@
27 27 },
28 28 },
29 29 {
  30 + field: ComponentConfigFieldEnum.FONT_SIZE,
  31 + label: '文本字体大小',
  32 + component: 'InputNumber',
  33 + defaultValue: option.fontSize,
  34 + },
  35 + {
30 36 field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME,
31 37 label: '显示设备名称',
32 38 component: 'Checkbox',
... ...
... ... @@ -32,6 +32,10 @@
32 32 transportType: value.transportType,
33 33 service: value.service,
34 34 command: value.command,
  35 + openService: value.openService,
  36 + closeService: value.closeService,
  37 + openCommand: value.openCommand,
  38 + closeCommand: value.closeCommand,
35 39 commandType: value.commandType,
36 40 callType: value.callType,
37 41 },
... ... @@ -45,6 +49,10 @@
45 49 ...record,
46 50 transportType: customCommand?.transportType || (record as Recordable).transportType,
47 51 service: customCommand?.service || (record as Recordable).service,
  52 + openService: customCommand?.openService || (record as Recordable).openService,
  53 + closeService: customCommand?.closeService || (record as Recordable).closeService,
  54 + openCommand: customCommand?.openCommand || (record as Recordable).openCommand,
  55 + closeCommand: customCommand?.closeCommand || (record as Recordable).closeCommand,
48 56 command: customCommand?.command || (record as Recordable).command,
49 57 commandType: customCommand?.commandType || (record as Recordable).commandType,
50 58 callType: customCommand?.callType || (record as Recordable).callType,
... ...
... ... @@ -5,6 +5,6 @@ const componentKeys = useComponentKeys('SwitchList');
5 5
6 6 export const SwitchListConfig: ConfigType = {
7 7 ...componentKeys,
8   - title: '开关控制列表',
  8 + title: '开关控制列表',
9 9 package: PackagesCategoryEnum.CONTROL,
10 10 };
... ...
... ... @@ -13,6 +13,7 @@
13 13 import { useReceiveMessage } from '../../../hook/useReceiveMessage';
14 14 import { useReceiveValue } from '../../../hook/useReceiveValue';
15 15 import { DataSource } from '/@/views/visual/palette/types';
  16 + import { getSendValues, CommandTypeEnumLIst } from '../config';
16 17
17 18 const props = defineProps<{
18 19 config: ComponentPropsConfigType<typeof option>;
... ... @@ -51,12 +52,24 @@
51 52 fontColor: persetFontColor,
52 53 icon: persetIcon,
53 54 iconColor: persetIconColor,
  55 + fontSize: persetFontSize,
54 56 } = persetOption || {};
55 57 return {
56 58 dataSource: dataSource.map((item) => {
57   - const { fontColor, icon, iconColor, unit, showDeviceName } = item.componentInfo;
58   - const { attribute, attributeRename, attributeName, deviceId, deviceName, deviceRename } =
59   - item;
  59 + const { fontColor, icon, iconColor, unit, showDeviceName, fontSize } = item.componentInfo;
  60 + const {
  61 + attribute,
  62 + attributeRename,
  63 + attributeName,
  64 + deviceId,
  65 + deviceName,
  66 + deviceRename,
  67 + commandType,
  68 + extensionDesc,
  69 + codeType,
  70 + deviceCode,
  71 + customCommand,
  72 + } = item;
60 73 return {
61 74 unit: unit ?? persetUnit,
62 75 fontColor: fontColor ?? persetFontColor,
... ... @@ -67,6 +80,12 @@
67 80 showDeviceName,
68 81 deviceName: deviceRename || deviceName,
69 82 id: deviceId,
  83 + extensionDesc: extensionDesc ? JSON.parse(extensionDesc) : {},
  84 + commandType,
  85 + codeType,
  86 + deviceCode,
  87 + customCommand,
  88 + fontSize: fontSize || persetFontSize || 14,
70 89 };
71 90 }),
72 91 };
... ... @@ -76,7 +95,6 @@
76 95 const handleChange = async (index: number, checked: Boolean) => {
77 96 const { heightPx, itemHeightRatio, itemWidthRatio, mode, widthPx, dataSource } =
78 97 props.config.option;
79   -
80 98 const data = {
81 99 ...dataSource?.[index],
82 100 heightPx,
... ... @@ -85,8 +103,10 @@
85 103 mode,
86 104 widthPx,
87 105 } as DataSource;
  106 + const { values, isModbusCommand, sendValue } =
  107 + (await getSendValues(data, unref(getDesign).dataSource[index], checked)) || {};
88 108
89   - const flag = await sendCommand(data, checked);
  109 + const flag = await sendCommand(values, isModbusCommand ? sendValue : checked, isModbusCommand);
90 110 if (!flag) controlList.value[index].checked = !checked;
91 111 };
92 112
... ... @@ -128,15 +148,15 @@
128 148 <SvgIcon
129 149 :name="item.icon!"
130 150 prefix="iconfont"
131   - :size="getRatio ? 30 * getRatio : 30"
  151 + :size="getRatio ? 25 * getRatio : 25"
132 152 :style="{ color: item.iconColor }"
133 153 />
134 154
135   - <div
136   - class="text-gray-500 truncate ml-6"
137   - :style="{ fontSize: getRatio ? '18px' : getRatio * 18 + 'px' }"
138   - >{{ `${item.deviceName} - ${item.attributeName}` }}</div
139   - >
  155 + <div class="text-gray-500 truncate ml-6" :style="{ fontSize: item.fontSize + 'px' }">{{
  156 + `${item.deviceName} - ${
  157 + item.commandType ? CommandTypeEnumLIst[item.commandType].name : item.attributeName
  158 + }`
  159 + }}</div>
140 160 </div>
141 161
142 162 <Switch
... ...
  1 +import { ref, unref } from 'vue';
  2 +import { TransportTypeEnum } from '/@/views/device/profiles/components/TransportDescript/const';
  3 +import { CommandTypeEnum } from '/@/views/rule/linkedge/config/config.data';
  4 +import { TaskTypeEnum } from '/@/views/task/center/config';
  5 +import { genModbusCommand } from '/@/api/task';
  6 +import { useMessage } from '/@/hooks/web/useMessage';
  7 +import { SingleToHex } from '/@/views/device/list/cpns/tabs/ObjectModelCommandDeliveryModal/config';
  8 +
  9 +const getArray = (values) => {
  10 + const str = values.replace(/\s+/g, '');
  11 + const array: any = [];
  12 +
  13 + for (let i = 0; i < str.length; i += 4) {
  14 + const chunk = parseInt(str.substring(i, i + 4), 16);
  15 + array.push(chunk);
  16 + }
  17 + return array;
  18 +};
  19 +
  20 +export const getSendValues = async (option, getDesign, checked) => {
  21 + const values: any = option;
  22 + const isModbusCommand = ref<boolean>(false); //判断是否是TCP设备-> 且设备标识符是modeBUs,切选择是下发命令类型是属性
  23 + const { extensionDesc, commandType, codeType, deviceCode, customCommand } = getDesign || {};
  24 + const { registerAddress, actionType } = extensionDesc || {};
  25 + const { openCommand, closeCommand, transportType } = customCommand || {};
  26 + const modBUS = ref<any>({});
  27 + const sendValue = ref();
  28 +
  29 + const { createMessage } = useMessage();
  30 + //判断是不是TCP类型设备
  31 + if (transportType === TransportTypeEnum.TCP) {
  32 + if (
  33 + //判断TCP下发类型是否是自定义还是服务
  34 + commandType === CommandTypeEnum.CUSTOM.toString() ||
  35 + commandType == CommandTypeEnum.SERVICE.toString()
  36 + ) {
  37 + values.customCommand.command = checked ? openCommand : closeCommand;
  38 + values.customCommand.command = values.customCommand.command
  39 + .replaceAll(/\s/g, '')
  40 + .toUpperCase();
  41 + }
  42 + if (
  43 + //判断命令下发类型是不是属性 且是modbus
  44 + commandType === CommandTypeEnum.ATTRIBUTE.toString() &&
  45 + codeType === TaskTypeEnum.MODBUS_RTU
  46 + ) {
  47 + if (!deviceCode) {
  48 + createMessage.warning('当前设备没有设置地址码');
  49 + return;
  50 + }
  51 + if (!actionType) {
  52 + createMessage.warning('当前物模型扩展描述没有填写');
  53 + return;
  54 + }
  55 + isModbusCommand.value = true;
  56 + modBUS.value = {
  57 + crc: 'CRC_16_LOWER',
  58 + deviceCode: deviceCode,
  59 + method: actionType == '16' ? '10' : actionType,
  60 + registerAddress,
  61 + registerNumber: 1,
  62 + registerValues: [Number(checked)],
  63 + };
  64 +
  65 + if (actionType == '16' || actionType == '10') {
  66 + const newValue = Number(checked) == 0 ? [0, 0] : getArray(SingleToHex(Number(checked)));
  67 + modBUS.value.registerValues = newValue;
  68 + modBUS.value.registerNumber = 2;
  69 + modBUS.value.method = '10';
  70 + }
  71 +
  72 + sendValue.value = await genModbusCommand(unref(modBUS));
  73 + }
  74 + }
  75 +
  76 + return { values, sendValue: unref(sendValue), isModbusCommand: unref(isModbusCommand) };
  77 +};
  78 +
  79 +export const CommandTypeEnumLIst = {
  80 + '0': { CUSTOM: 0, name: '自定义' },
  81 + '1': { CUSTOM: 0, name: '服务' },
  82 + '2': { CUSTOM: 0, name: '属性' },
  83 +};
... ...
... ... @@ -13,6 +13,8 @@ export const option: PublicPresetOptions = {
13 13 [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: false,
14 14 [ComponentConfigFieldEnum.UNIT]: 'm',
15 15 [ComponentConfigFieldEnum.MAX_NUMBER]: 100,
  16 + [ComponentConfigFieldEnum.VALUE_SIZE]: 20,
  17 + [ComponentConfigFieldEnum.FONT_SIZE]: 14,
16 18 [ComponentConfigFieldEnum.FONT_COLOR]: '#fff',
17 19 [ComponentConfigFieldEnum.SHOW_TIME]: false,
18 20 [ComponentConfigFieldEnum.FLOWMETER_CONFIG]: {
... ...
... ... @@ -10,7 +10,7 @@
10 10 schemas: [
11 11 {
12 12 field: ComponentConfigFieldEnum.FONT_COLOR,
13   - label: '字体颜色',
  13 + label: '数值字体颜色',
14 14 component: 'ColorPicker',
15 15 changeEvent: 'update:value',
16 16 defaultValue: option.fontColor,
... ... @@ -50,6 +50,40 @@
50 50 defaultValue: option.unit,
51 51 },
52 52 {
  53 + field: ComponentConfigFieldEnum.VALUE_SIZE,
  54 + label: '数值字体大小',
  55 + component: 'InputNumber',
  56 + defaultValue: 14,
  57 + componentProps: {
  58 + min: 0,
  59 + formatter: (e) => {
  60 + const value = e.replace(/^0/g, '');
  61 + if (value) {
  62 + return value.replace(/^0/g, '');
  63 + } else {
  64 + return 0;
  65 + }
  66 + },
  67 + },
  68 + },
  69 + {
  70 + field: ComponentConfigFieldEnum.FONT_SIZE,
  71 + label: '文本字体大小',
  72 + component: 'InputNumber',
  73 + defaultValue: 14,
  74 + componentProps: {
  75 + min: 0,
  76 + formatter: (e) => {
  77 + const value = e.replace(/^0/g, '');
  78 + if (value) {
  79 + return value.replace(/^0/g, '');
  80 + } else {
  81 + return 0;
  82 + }
  83 + },
  84 + },
  85 + },
  86 + {
53 87 field: ComponentConfigFieldEnum.MAX_NUMBER,
54 88 label: '最大值',
55 89 component: 'InputNumber',
... ...
... ... @@ -20,7 +20,8 @@
20 20 const getDesign = computed(() => {
21 21 const { option, persetOption } = props.config;
22 22 const { componentInfo, attribute, attributeName, attributeRename } = option;
23   - const { flowmeterConfig, unit, fontColor, showTime, maxNumber } = componentInfo || {};
  23 + const { flowmeterConfig, unit, fontColor, showTime, maxNumber, valueSize, fontSize } =
  24 + componentInfo || {};
24 25 const { backgroundColor, waveFirst, waveSecond, waveThird } = flowmeterConfig || {};
25 26 const {
26 27 flowmeterConfig: presetFlowmeterConfig,
... ... @@ -28,6 +29,8 @@
28 29 fontColor: presetFontColor,
29 30 showTime: persetShowTime,
30 31 maxNumber: persetMaxNumber,
  32 + valueSize: persetValueSize,
  33 + fontSize: persetFontSize,
31 34 } = persetOption || {};
32 35 const {
33 36 backgroundColor: presetBackgroundColor,
... ... @@ -45,6 +48,8 @@
45 48 attribute: attributeRename || attributeName || attribute,
46 49 showTime: showTime ?? persetShowTime,
47 50 maxNumber: maxNumber ?? persetMaxNumber,
  51 + valueSize: valueSize || persetValueSize || 20,
  52 + fontSize: fontSize || persetFontSize || 14,
48 53 };
49 54 });
50 55
... ... @@ -129,14 +134,17 @@
129 134
130 135 <div
131 136 class="absolute w-full h-full top-0 left-0 text-center text-lg flex items-center justify-center"
132   - :style="{ color: getDesign.fontColor }"
  137 + :style="{ color: getDesign.fontColor, fontSize: getDesign.valueSize + 'px' }"
133 138 >
134 139 <div>{{ currentValue }}</div>
135 140 <div class="ml-1">{{ getDesign.unit }}</div>
136 141 </div>
137   - <div class="text-gray-500 text-sm truncate" style="flex: 0 0 20px">{{
138   - getDesign.attribute || '属性'
139   - }}</div>
  142 + <div
  143 + class="text-gray-500 text-sm truncate"
  144 + style="flex: 0 0 20px"
  145 + :style="{ fontSize: getDesign.fontSize + 'px' }"
  146 + >{{ getDesign.attribute || '属性' }}</div
  147 + >
140 148 <UpdateTime v-show="getDesign.showTime" :time="time" />
141 149 </main>
142 150 </template>
... ...
... ... @@ -14,6 +14,8 @@ export const option: PublicPresetOptions = {
14 14 [ComponentConfigFieldEnum.SHOW_TIME]: false,
15 15 [ComponentConfigFieldEnum.UNIT]: 'm',
16 16 [ComponentConfigFieldEnum.MAX_NUMBER]: 100,
  17 + [ComponentConfigFieldEnum.FONT_SIZE]: 14,
  18 + [ComponentConfigFieldEnum.VALUE_SIZE]: 20,
17 19 [ComponentConfigFieldEnum.FLOWMETER_CONFIG]: {
18 20 [ComponentConfigFieldEnum.BACKGROUND_COLOR]: '#8badcb',
19 21 [ComponentConfigFieldEnum.WAVE_FIRST]: '#4579e2',
... ...
... ... @@ -10,7 +10,7 @@
10 10 schemas: [
11 11 {
12 12 field: ComponentConfigFieldEnum.FONT_COLOR,
13   - label: '字体颜色',
  13 + label: '数值字体颜色',
14 14 component: 'ColorPicker',
15 15 changeEvent: 'update:value',
16 16 defaultValue: option.fontColor,
... ... @@ -56,6 +56,40 @@
56 56 // defaultValue: 0,
57 57 // },
58 58 {
  59 + field: ComponentConfigFieldEnum.VALUE_SIZE,
  60 + label: '数值字体大小',
  61 + component: 'InputNumber',
  62 + defaultValue: 14,
  63 + componentProps: {
  64 + min: 0,
  65 + formatter: (e) => {
  66 + const value = e.replace(/^0/g, '');
  67 + if (value) {
  68 + return value.replace(/^0/g, '');
  69 + } else {
  70 + return 0;
  71 + }
  72 + },
  73 + },
  74 + },
  75 + {
  76 + field: ComponentConfigFieldEnum.FONT_SIZE,
  77 + label: '文本字体大小',
  78 + component: 'InputNumber',
  79 + defaultValue: 14,
  80 + componentProps: {
  81 + min: 0,
  82 + formatter: (e) => {
  83 + const value = e.replace(/^0/g, '');
  84 + if (value) {
  85 + return value.replace(/^0/g, '');
  86 + } else {
  87 + return 0;
  88 + }
  89 + },
  90 + },
  91 + },
  92 + {
59 93 field: ComponentConfigFieldEnum.MAX_NUMBER,
60 94 label: '最大值',
61 95 component: 'InputNumber',
... ...
... ... @@ -20,7 +20,8 @@
20 20 const getDesign = computed(() => {
21 21 const { option, persetOption } = props.config;
22 22 const { componentInfo, attribute, attributeName, attributeRename } = option;
23   - const { flowmeterConfig, unit, fontColor, showTime, maxNumber } = componentInfo || {};
  23 + const { flowmeterConfig, unit, fontColor, showTime, maxNumber, fontSize, valueSize } =
  24 + componentInfo || {};
24 25 const { backgroundColor, waveFirst, waveSecond, waveThird } = flowmeterConfig || {};
25 26 const {
26 27 flowmeterConfig: presetFlowmeterConfig,
... ... @@ -28,6 +29,8 @@
28 29 fontColor: presetFontColor,
29 30 showTime: persetShowTime,
30 31 maxNumber: persetMaxNumber,
  32 + fontSize: persetFontSize,
  33 + valueSize: persetValueSize,
31 34 } = persetOption || {};
32 35 const {
33 36 backgroundColor: presetBackgroundColor,
... ... @@ -45,6 +48,8 @@
45 48 attribute: attributeRename || attributeName || attribute,
46 49 showTime: showTime ?? persetShowTime,
47 50 maxNumber: maxNumber ?? persetMaxNumber,
  51 + fontSize: fontSize || persetFontSize || 14,
  52 + valueSize: valueSize || persetValueSize || 20,
48 53 };
49 54 });
50 55
... ... @@ -122,14 +127,17 @@
122 127 </svg>
123 128 <div
124 129 class="absolute w-full h-full top-0 left-0 text-center text-lg flex items-center justify-center"
125   - :style="{ color: getDesign.fontColor }"
  130 + :style="{ color: getDesign.fontColor, fontSize: getDesign.valueSize + 'px' }"
126 131 >
127 132 <div>{{ currentValue }}</div>
128 133 <div class="ml-1">{{ getDesign.unit }}</div>
129 134 </div>
130   - <div class="text-gray-500 text-sm truncate" style="flex: 0 0 20px">{{
131   - getDesign.attribute || '属性'
132   - }}</div>
  135 + <div
  136 + class="text-gray-500"
  137 + style="flex: 0 0 20px"
  138 + :style="{ fontSize: getDesign.fontSize + 'px', height: getDesign.fontSize + 'px' }"
  139 + >{{ getDesign.attribute || '属性' }}</div
  140 + >
133 141 <UpdateTime v-show="getDesign.showTime" :time="time" />
134 142 </main>
135 143 </template>
... ...
... ... @@ -27,6 +27,8 @@ export const option: PublicPresetOptions = {
27 27 [ComponentConfigFieldEnum.UNIT]: '℃',
28 28 [ComponentConfigFieldEnum.POINTER_COLOR]: '#15E2C6',
29 29 [ComponentConfigFieldEnum.INSTRUMENT_PANEL_COLOR]: '#61D4C5',
  30 + [ComponentConfigFieldEnum.FONT_SIZE]: 14,
  31 + [ComponentConfigFieldEnum.VALUE_SIZE]: 14,
30 32 [ComponentConfigFieldEnum.GRADIENT_INFO]: [
31 33 { key: Gradient.FIRST, value: 0, color: GradientColor.FIRST },
32 34 { key: Gradient.SECOND, value: 1, color: GradientColor.SECOND },
... ...
... ... @@ -43,26 +43,6 @@
43 43 changeEvent: 'update:value',
44 44 defaultValue: GradientColor.SECOND,
45 45 },
46   - // {
47   - // field: ComponentConfigFieldEnum.INSTRUMENT_PANEL_WIDTH,
48   - // label: '仪表盘宽度',
49   - // component: 'Slider',
50   - // changeEvent: 'update:value',
51   - // defaultValue: option.pointerColor,
52   - // },
53   - {
54   - field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME,
55   - label: '显示设备名称',
56   - component: 'Checkbox',
57   - defaultValue: option.showDeviceName,
58   - },
59   - {
60   - field: ComponentConfigFieldEnum.SHOW_TIME,
61   - label: '显示时间',
62   - component: 'Checkbox',
63   - defaultValue: option.showTime,
64   - },
65   -
66 46 {
67 47 field: ComponentConfigFieldEnum.UNIT,
68 48 label: '数值单位',
... ... @@ -70,6 +50,40 @@
70 50 defaultValue: option.unit,
71 51 },
72 52 {
  53 + field: ComponentConfigFieldEnum.VALUE_SIZE,
  54 + label: '数值字体大小',
  55 + component: 'InputNumber',
  56 + defaultValue: 14,
  57 + componentProps: {
  58 + min: 0,
  59 + formatter: (e) => {
  60 + const value = e.replace(/^0/g, '');
  61 + if (value) {
  62 + return value.replace(/^0/g, '');
  63 + } else {
  64 + return 0;
  65 + }
  66 + },
  67 + },
  68 + },
  69 + {
  70 + field: ComponentConfigFieldEnum.FONT_SIZE,
  71 + label: '文本字体大小',
  72 + component: 'InputNumber',
  73 + defaultValue: 14,
  74 + componentProps: {
  75 + min: 0,
  76 + formatter: (e) => {
  77 + const value = e.replace(/^0/g, '');
  78 + if (value) {
  79 + return value.replace(/^0/g, '');
  80 + } else {
  81 + return 0;
  82 + }
  83 + },
  84 + },
  85 + },
  86 + {
73 87 field: ComponentConfigFieldEnum.MAX_NUMBER,
74 88 label: '最大值',
75 89 component: 'InputNumber',
... ... @@ -90,6 +104,18 @@
90 104 };
91 105 },
92 106 },
  107 + {
  108 + field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME,
  109 + label: '显示设备名称',
  110 + component: 'Checkbox',
  111 + defaultValue: option.showDeviceName,
  112 + },
  113 + {
  114 + field: ComponentConfigFieldEnum.SHOW_TIME,
  115 + label: '显示时间',
  116 + component: 'Checkbox',
  117 + defaultValue: option.showTime,
  118 + },
93 119 ],
94 120 showActionButtonGroup: false,
95 121 labelWidth: 120,
... ... @@ -120,13 +146,24 @@
120 146 showTime: item[ComponentConfigFieldEnum.SHOW_TIME],
121 147 pointerColor: item[ComponentConfigFieldEnum.POINTER_COLOR],
122 148 maxNumber: item[ComponentConfigFieldEnum.MAX_NUMBER],
  149 + fontSize: item[ComponentConfigFieldEnum.FONT_SIZE],
  150 + valueSize: item[ComponentConfigFieldEnum.VALUE_SIZE],
123 151 } as ComponentInfo;
124 152 };
125 153
126 154 const setFormValues = (data: Recordable) => {
127 155 // return setFieldsValue(data);
128   - const { gradientInfo, unit, fontColor, showDeviceName, pointerColor, showTime, maxNumber } =
129   - data;
  156 + const {
  157 + gradientInfo,
  158 + unit,
  159 + fontColor,
  160 + showDeviceName,
  161 + pointerColor,
  162 + showTime,
  163 + maxNumber,
  164 + fontSize,
  165 + valueSize,
  166 + } = data;
130 167 const firstRecord = gradientInfo.find((item) => item.key === Gradient.FIRST);
131 168 const secondRecord = gradientInfo.find((item) => item.key === Gradient.SECOND);
132 169
... ... @@ -141,6 +178,8 @@
141 178 [ComponentConfigFieldEnum.SECOND_PHASE_COLOR]: secondRecord?.color,
142 179 [ComponentConfigFieldEnum.POINTER_COLOR]: pointerColor,
143 180 [ComponentConfigFieldEnum.MAX_NUMBER]: maxNumber,
  181 + [ComponentConfigFieldEnum.FONT_SIZE]: fontSize,
  182 + [ComponentConfigFieldEnum.VALUE_SIZE]: valueSize,
144 183 };
145 184 return setFieldsValue(value);
146 185 };
... ...
... ... @@ -32,6 +32,8 @@
32 32 gradientInfo: presetGradientInfo,
33 33 showTime: persetShowTime,
34 34 maxNumber: persetMaxNumber,
  35 + fontSize: persetFontSize,
  36 + valueSize: persetValueSize,
35 37 } = persetOption || {};
36 38 const {
37 39 unit,
... ... @@ -41,6 +43,8 @@
41 43 gradientInfo,
42 44 showTime,
43 45 maxNumber,
  46 + fontSize,
  47 + valueSize,
44 48 } = componentInfo || {};
45 49 return {
46 50 unit: unit ?? presetUnit,
... ... @@ -51,6 +55,8 @@
51 55 gradientInfo: gradientInfo ?? presetGradientInfo,
52 56 showTime: showTime ?? persetShowTime,
53 57 maxNumber: maxNumber || persetMaxNumber,
  58 + fontSize: fontSize || persetFontSize || 14,
  59 + valueSize: valueSize || persetValueSize || 14,
54 60 };
55 61 });
56 62
... ... @@ -66,7 +72,7 @@
66 72 };
67 73
68 74 const options = (): EChartsOption => {
69   - const { unit, fontColor, pointerColor, gradientInfo, maxNumber } = unref(getDesign);
  75 + const { unit, fontColor, pointerColor, gradientInfo, maxNumber, valueSize } = unref(getDesign);
70 76
71 77 const instrumentPanelColor = getStageColor(gradientInfo);
72 78 // getStageColor(gradientInfo);
... ... @@ -108,7 +114,7 @@
108 114 //指针
109 115 show: true,
110 116 icon: 'path://M2090.36389,615.30999 L2090.36389,615.30999 C2091.48372,615.30999 2092.40383,616.194028 2092.44859,617.312956 L2096.90698,728.755929 C2097.05155,732.369577 2094.2393,735.416212 2090.62566,735.56078 C2090.53845,735.564269 2090.45117,735.566014 2090.36389,735.566014 L2090.36389,735.566014 C2086.74736,735.566014 2083.81557,732.63423 2083.81557,729.017692 C2083.81557,728.930412 2083.81732,728.84314 2083.82081,728.755929 L2088.2792,617.312956 C2088.32396,616.194028 2089.24407,615.30999 2090.36389,615.30999 Z',
111   - width: 4 * unref(getRatio) ? 4 * unref(getRatio) : 4,
  117 + width: unref(getRatio) ? 4 * unref(getRatio) : 4,
112 118 length: '100%',
113 119 itemStyle: {
114 120 color: pointerColor,
... ... @@ -128,7 +134,7 @@
128 134 },
129 135 detail: {
130 136 valueAnimation: true,
131   - fontSize: 14 * unref(getRatio),
  137 + fontSize: unref(getRatio) ? valueSize * unref(getRatio) : valueSize,
132 138 fontWeight: 'bolder',
133 139 formatter: `{value} ${unit ?? ''}`,
134 140 color: fontColor || 'inherit',
... ... @@ -199,7 +205,7 @@
199 205 width: 4 * unref(getRatio),
200 206 },
201 207 detail: {
202   - fontSize: 14 * unref(getRatio),
  208 + fontSize: unref(getDesign).valueSize * unref(getRatio),
203 209 },
204 210 },
205 211 ],
... ... @@ -219,9 +225,11 @@
219 225 <div class="w-full h-full flex flex-1 flex-col justify-center items-center">
220 226 <div ref="chartRefEl" class="flex-1 w-full h-6/7 flex flex-col justify-center items-center">
221 227 </div>
222   - <div class="text-gray-500 text-xs text-center truncate">{{
223   - getDesign.attribute || '湿度'
224   - }}</div>
  228 + <div
  229 + class="text-gray-500 text-center truncate"
  230 + :style="{ fontSize: getDesign.fontSize + 'px' }"
  231 + >{{ getDesign.attribute || '湿度' }}</div
  232 + >
225 233 </div>
226 234 <UpdateTime v-if="getDesign.showTime" :time="time" />
227 235 </main>
... ...
... ... @@ -26,6 +26,8 @@ export const option: PublicPresetOptions = {
26 26 [ComponentConfigFieldEnum.POINTER_COLOR]: '#15E2C6',
27 27 [ComponentConfigFieldEnum.INSTRUMENT_PANEL_COLOR]: '#61D4C5',
28 28 [ComponentConfigFieldEnum.MAX_NUMBER]: 100,
  29 + [ComponentConfigFieldEnum.FONT_SIZE]: 14,
  30 + [ComponentConfigFieldEnum.VALUE_SIZE]: 14,
29 31 [ComponentConfigFieldEnum.GRADIENT_INFO]: [
30 32 { key: Gradient.FIRST, value: 0, color: GradientColor.FIRST },
31 33 { key: Gradient.SECOND, value: 1, color: GradientColor.SECOND },
... ...
... ... @@ -43,24 +43,6 @@
43 43 defaultValue: GradientColor.SECOND,
44 44 },
45 45 {
46   - field: ComponentConfigFieldEnum.PROGRESS_BAR_CIRCLE,
47   - label: '显示进度条圆形',
48   - component: 'Checkbox',
49   - defaultValue: option.progressBarCircle,
50   - },
51   - {
52   - field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME,
53   - label: '显示设备名称',
54   - component: 'Checkbox',
55   - defaultValue: option.showDeviceName,
56   - },
57   - {
58   - field: ComponentConfigFieldEnum.SHOW_TIME,
59   - label: '显示时间',
60   - component: 'Checkbox',
61   - defaultValue: option.showTime,
62   - },
63   - {
64 46 field: ComponentConfigFieldEnum.MAX_NUMBER,
65 47 label: '最大值',
66 48 component: 'InputNumber',
... ... @@ -81,6 +63,58 @@
81 63 };
82 64 },
83 65 },
  66 + {
  67 + field: ComponentConfigFieldEnum.VALUE_SIZE,
  68 + label: '数值字体大小',
  69 + component: 'InputNumber',
  70 + defaultValue: 14,
  71 + componentProps: {
  72 + min: 0,
  73 + formatter: (e) => {
  74 + const value = e.replace(/^0/g, '');
  75 + if (value) {
  76 + return value.replace(/^0/g, '');
  77 + } else {
  78 + return 0;
  79 + }
  80 + },
  81 + },
  82 + },
  83 + {
  84 + field: ComponentConfigFieldEnum.FONT_SIZE,
  85 + label: '文本字体大小',
  86 + component: 'InputNumber',
  87 + defaultValue: 14,
  88 + componentProps: {
  89 + min: 0,
  90 + formatter: (e) => {
  91 + const value = e.replace(/^0/g, '');
  92 + if (value) {
  93 + return value.replace(/^0/g, '');
  94 + } else {
  95 + return 0;
  96 + }
  97 + },
  98 + },
  99 + },
  100 + {
  101 + field: ComponentConfigFieldEnum.PROGRESS_BAR_CIRCLE,
  102 + label: '显示进度条圆形',
  103 + component: 'Checkbox',
  104 + defaultValue: option.progressBarCircle,
  105 + },
  106 + {
  107 + field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME,
  108 + label: '显示设备名称',
  109 + component: 'Checkbox',
  110 + defaultValue: option.showDeviceName,
  111 + },
  112 + {
  113 + field: ComponentConfigFieldEnum.SHOW_TIME,
  114 + label: '显示时间',
  115 + component: 'Checkbox',
  116 + defaultValue: option.showTime,
  117 + },
84 118 ],
85 119 showActionButtonGroup: false,
86 120 labelWidth: 120,
... ... @@ -111,6 +145,8 @@
111 145 showTime: item[ComponentConfigFieldEnum.SHOW_TIME],
112 146 progressBarCircle: item[ComponentConfigFieldEnum.PROGRESS_BAR_CIRCLE],
113 147 maxNumber: item[ComponentConfigFieldEnum.MAX_NUMBER],
  148 + valueSize: item[ComponentConfigFieldEnum.VALUE_SIZE],
  149 + fontSize: item[ComponentConfigFieldEnum.FONT_SIZE],
114 150 } as ComponentInfo;
115 151 };
116 152
... ... @@ -124,6 +160,8 @@
124 160 progressBarCircle,
125 161 showTime,
126 162 maxNumber,
  163 + valueSize,
  164 + fontSize,
127 165 } = data;
128 166 const firstRecord = gradientInfo.find((item) => item.key === Gradient.FIRST);
129 167 const secondRecord = gradientInfo.find((item) => item.key === Gradient.SECOND);
... ... @@ -139,6 +177,8 @@
139 177 [ComponentConfigFieldEnum.SECOND_PHASE_COLOR]: secondRecord?.color,
140 178 [ComponentConfigFieldEnum.PROGRESS_BAR_CIRCLE]: progressBarCircle,
141 179 [ComponentConfigFieldEnum.MAX_NUMBER]: maxNumber,
  180 + [ComponentConfigFieldEnum.VALUE_SIZE]: valueSize,
  181 + [ComponentConfigFieldEnum.FONT_SIZE]: fontSize,
142 182 };
143 183 return setFieldsValue(value);
144 184 };
... ...