Commit 055fb44c1f650e3bbf74716eca7a908d7dcc6bd4
Merge branch 'main_dev' into feat/rule-engine-designer
Showing
142 changed files
with
2161 additions
and
471 deletions
| ... | ... | @@ -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 | ... | ... |
| ... | ... | @@ -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 | }); | ... | ... |
src/hooks/business/useMenuActiveFix.ts
0 → 100644
| 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: { | ... | ... |
| ... | ... | @@ -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"> | ... | ... |
| ... | ... | @@ -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 | ... | ... |
| ... | ... | @@ -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 | }; | ... | ... |
| ... | ... | @@ -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 | ... | ... |
| ... | ... | @@ -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 | }); | ... | ... |
| ... | ... | @@ -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, | ... | ... |
| ... | ... | @@ -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 | }; | ... | ... |
| ... | ... | @@ -33,6 +33,8 @@ |
| 33 | 33 | gradientInfo: presetGradientInfo, |
| 34 | 34 | showTime: persetShowTime, |
| 35 | 35 | maxNumber: persetMaxNumber, |
| 36 | + fontSize: persetFontSize, | |
| 37 | + valueSize: persetValueSize, | |
| 36 | 38 | } = persetOption || {}; |
| 37 | 39 | const { |
| 38 | 40 | unit, |
| ... | ... | @@ -43,6 +45,8 @@ |
| 43 | 45 | instrumentPanelColor, |
| 44 | 46 | showTime, |
| 45 | 47 | maxNumber, |
| 48 | + fontSize, | |
| 49 | + valueSize, | |
| 46 | 50 | } = componentInfo || {}; |
| 47 | 51 | return { |
| 48 | 52 | unit: unit ?? presetUnit, |
| ... | ... | @@ -54,6 +58,8 @@ |
| 54 | 58 | gradientInfo: gradientInfo ?? presetGradientInfo, |
| 55 | 59 | showTime: showTime ?? persetShowTime, |
| 56 | 60 | maxNumber: maxNumber || persetMaxNumber, |
| 61 | + fontSize: fontSize || persetFontSize || 14, | |
| 62 | + valueSize: valueSize || persetValueSize || 14, | |
| 57 | 63 | }; |
| 58 | 64 | }); |
| 59 | 65 | |
| ... | ... | @@ -71,7 +77,8 @@ |
| 71 | 77 | const titleValue = ref<number>(20); |
| 72 | 78 | |
| 73 | 79 | const options = (): EChartsOption => { |
| 74 | - const { unit, fontColor, progressBarCircle, gradientInfo, maxNumber } = unref(getDesign); | |
| 80 | + const { unit, fontColor, progressBarCircle, gradientInfo, maxNumber, valueSize } = | |
| 81 | + unref(getDesign); | |
| 75 | 82 | const instrumentPanelColor = getStageColor(gradientInfo); |
| 76 | 83 | return { |
| 77 | 84 | title: { |
| ... | ... | @@ -79,7 +86,7 @@ |
| 79 | 86 | top: 'center', |
| 80 | 87 | left: 'center', |
| 81 | 88 | textStyle: { |
| 82 | - fontSize: unref(getRatio) ? 14 * unref(getRatio) : 14, | |
| 89 | + fontSize: unref(getRatio) ? valueSize * unref(getRatio) : valueSize, | |
| 83 | 90 | color: fontColor || '#65d3ff', |
| 84 | 91 | valueAnimation: true, |
| 85 | 92 | }, |
| ... | ... | @@ -210,7 +217,7 @@ |
| 210 | 217 | ], |
| 211 | 218 | title: { |
| 212 | 219 | textStyle: { |
| 213 | - fontSize: 14 * unref(getRatio), | |
| 220 | + fontSize: unref(getDesign).valueSize * unref(getRatio), | |
| 214 | 221 | }, |
| 215 | 222 | }, |
| 216 | 223 | }); |
| ... | ... | @@ -229,9 +236,11 @@ |
| 229 | 236 | <div class="flex w-full h-full flex-col justify-center items-center flex-1"> |
| 230 | 237 | <div ref="chartRefEl" class="flex-1 w-full h-6/7 flex-col justify-center items-center flex"> |
| 231 | 238 | </div> |
| 232 | - <div class="text-gray-500 text-xs text-center truncate">{{ | |
| 233 | - getDesign.attribute || '湿度' | |
| 234 | - }}</div> | |
| 239 | + <div | |
| 240 | + class="text-gray-500 text-center truncate" | |
| 241 | + :style="{ fontSize: getDesign.fontSize + 'px' }" | |
| 242 | + >{{ getDesign.attribute || '湿度' }}</div | |
| 243 | + > | |
| 235 | 244 | </div> |
| 236 | 245 | <UpdateTime v-if="getDesign.showTime" :time="time" /> |
| 237 | 246 | </main> | ... | ... |
| ... | ... | @@ -23,6 +23,8 @@ export const option: PublicPresetOptions = { |
| 23 | 23 | [ComponentConfigFieldEnum.SHOW_TIME]: false, |
| 24 | 24 | [ComponentConfigFieldEnum.MAX_NUMBER]: 100, |
| 25 | 25 | [ComponentConfigFieldEnum.UNIT]: 'kw', |
| 26 | + [ComponentConfigFieldEnum.FONT_SIZE]: 14, | |
| 27 | + [ComponentConfigFieldEnum.VALUE_SIZE]: 14, | |
| 26 | 28 | }; |
| 27 | 29 | |
| 28 | 30 | export default class Config extends PublicConfigClass implements CreateComponentType { | ... | ... |
| ... | ... | @@ -22,18 +22,6 @@ |
| 22 | 22 | defaultValue: option.unit, |
| 23 | 23 | }, |
| 24 | 24 | { |
| 25 | - field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME, | |
| 26 | - label: '显示设备名称', | |
| 27 | - component: 'Checkbox', | |
| 28 | - defaultValue: option.showDeviceName, | |
| 29 | - }, | |
| 30 | - { | |
| 31 | - field: ComponentConfigFieldEnum.SHOW_TIME, | |
| 32 | - label: '显示时间', | |
| 33 | - component: 'Checkbox', | |
| 34 | - defaultValue: option.showTime, | |
| 35 | - }, | |
| 36 | - { | |
| 37 | 25 | field: ComponentConfigFieldEnum.MAX_NUMBER, |
| 38 | 26 | label: '最大值', |
| 39 | 27 | component: 'InputNumber', |
| ... | ... | @@ -54,6 +42,52 @@ |
| 54 | 42 | }; |
| 55 | 43 | }, |
| 56 | 44 | }, |
| 45 | + { | |
| 46 | + field: ComponentConfigFieldEnum.VALUE_SIZE, | |
| 47 | + label: '数值字体大小', | |
| 48 | + component: 'InputNumber', | |
| 49 | + defaultValue: 14, | |
| 50 | + componentProps: { | |
| 51 | + min: 0, | |
| 52 | + formatter: (e) => { | |
| 53 | + const value = e.replace(/^0/g, ''); | |
| 54 | + if (value) { | |
| 55 | + return value.replace(/^0/g, ''); | |
| 56 | + } else { | |
| 57 | + return 0; | |
| 58 | + } | |
| 59 | + }, | |
| 60 | + }, | |
| 61 | + }, | |
| 62 | + { | |
| 63 | + field: ComponentConfigFieldEnum.FONT_SIZE, | |
| 64 | + label: '文本字体大小', | |
| 65 | + component: 'InputNumber', | |
| 66 | + defaultValue: 14, | |
| 67 | + componentProps: { | |
| 68 | + min: 0, | |
| 69 | + formatter: (e) => { | |
| 70 | + const value = e.replace(/^0/g, ''); | |
| 71 | + if (value) { | |
| 72 | + return value.replace(/^0/g, ''); | |
| 73 | + } else { | |
| 74 | + return 0; | |
| 75 | + } | |
| 76 | + }, | |
| 77 | + }, | |
| 78 | + }, | |
| 79 | + { | |
| 80 | + field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME, | |
| 81 | + label: '显示设备名称', | |
| 82 | + component: 'Checkbox', | |
| 83 | + defaultValue: option.showDeviceName, | |
| 84 | + }, | |
| 85 | + { | |
| 86 | + field: ComponentConfigFieldEnum.SHOW_TIME, | |
| 87 | + label: '显示时间', | |
| 88 | + component: 'Checkbox', | |
| 89 | + defaultValue: option.showTime, | |
| 90 | + }, | |
| 57 | 91 | ], |
| 58 | 92 | showActionButtonGroup: false, |
| 59 | 93 | labelWidth: 120, |
| ... | ... | @@ -71,12 +105,14 @@ |
| 71 | 105 | showDeviceName: item[ComponentConfigFieldEnum.SHOW_DEVICE_NAME], |
| 72 | 106 | showTime: item[ComponentConfigFieldEnum.SHOW_TIME], |
| 73 | 107 | maxNumber: item[ComponentConfigFieldEnum.MAX_NUMBER], |
| 108 | + fontSize: item[ComponentConfigFieldEnum.FONT_SIZE], | |
| 109 | + valueSize: item[ComponentConfigFieldEnum.VALUE_SIZE], | |
| 74 | 110 | } as ComponentInfo; |
| 75 | 111 | }; |
| 76 | 112 | |
| 77 | 113 | const setFormValues = (data: Recordable) => { |
| 78 | 114 | // return setFieldsValue(data); |
| 79 | - const { unit, fontColor, showDeviceName, showTime, maxNumber } = data; | |
| 115 | + const { unit, fontColor, showDeviceName, showTime, maxNumber, fontSize, valueSize } = data; | |
| 80 | 116 | |
| 81 | 117 | const value = { |
| 82 | 118 | [ComponentConfigFieldEnum.UNIT]: unit, |
| ... | ... | @@ -84,6 +120,8 @@ |
| 84 | 120 | [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: showDeviceName, |
| 85 | 121 | [ComponentConfigFieldEnum.SHOW_TIME]: showTime, |
| 86 | 122 | [ComponentConfigFieldEnum.MAX_NUMBER]: maxNumber, |
| 123 | + [ComponentConfigFieldEnum.FONT_SIZE]: fontSize, | |
| 124 | + [ComponentConfigFieldEnum.VALUE_SIZE]: valueSize, | |
| 87 | 125 | }; |
| 88 | 126 | return setFieldsValue(value); |
| 89 | 127 | }; | ... | ... |
| ... | ... | @@ -31,6 +31,8 @@ |
| 31 | 31 | gradientInfo: presetGradientInfo, |
| 32 | 32 | showTime: persetShowTime, |
| 33 | 33 | maxNumber: persetMaxNumber, |
| 34 | + fontSize: persetFontSize, | |
| 35 | + valueSize: persetValueSize, | |
| 34 | 36 | } = persetOption || {}; |
| 35 | 37 | const { |
| 36 | 38 | unit, |
| ... | ... | @@ -40,6 +42,8 @@ |
| 40 | 42 | gradientInfo, |
| 41 | 43 | showTime, |
| 42 | 44 | maxNumber, |
| 45 | + fontSize, | |
| 46 | + valueSize, | |
| 43 | 47 | } = componentInfo || {}; |
| 44 | 48 | return { |
| 45 | 49 | unit: unit ?? presetUnit, |
| ... | ... | @@ -50,11 +54,13 @@ |
| 50 | 54 | gradientInfo: gradientInfo ?? presetGradientInfo, |
| 51 | 55 | showTime: showTime ?? persetShowTime, |
| 52 | 56 | maxNumber: maxNumber || persetMaxNumber, |
| 57 | + fontSize: fontSize || persetFontSize || 14, | |
| 58 | + valueSize: valueSize || persetValueSize || 14, | |
| 53 | 59 | }; |
| 54 | 60 | }); |
| 55 | 61 | |
| 56 | 62 | const options = (): EChartsOption => { |
| 57 | - const { unit, fontColor, pointerColor, maxNumber } = unref(getDesign); | |
| 63 | + const { unit, fontColor, pointerColor, maxNumber, valueSize } = unref(getDesign); | |
| 58 | 64 | |
| 59 | 65 | // getStageColor(gradientInfo); |
| 60 | 66 | return { |
| ... | ... | @@ -110,7 +116,7 @@ |
| 110 | 116 | }, |
| 111 | 117 | detail: { |
| 112 | 118 | valueAnimation: true, |
| 113 | - fontSize: unref(getRatio) ? 16 * unref(getRatio) : 16, | |
| 119 | + fontSize: unref(getRatio) ? valueSize * unref(getRatio) : valueSize, | |
| 114 | 120 | offsetCenter: [0, '70%'], |
| 115 | 121 | formatter: `{value} ${unit ?? ''}`, |
| 116 | 122 | color: fontColor || 'inherit', |
| ... | ... | @@ -191,7 +197,7 @@ |
| 191 | 197 | }, |
| 192 | 198 | }, |
| 193 | 199 | detail: { |
| 194 | - fontSize: 16 * unref(getRatio), | |
| 200 | + fontSize: unref(getDesign).valueSize * unref(getRatio), | |
| 195 | 201 | }, |
| 196 | 202 | }, |
| 197 | 203 | ], |
| ... | ... | @@ -211,7 +217,7 @@ |
| 211 | 217 | <div class="flex flex-1 flex-col justify-center items-center w-full h-full"> |
| 212 | 218 | <div ref="chartRefEl" class="flex-1 w-full h-6/7 flex flex-col justify-center items-center"> |
| 213 | 219 | </div> |
| 214 | - <div class="text-gray-500 text-xs text-center truncate">{{ | |
| 220 | + <div class="text-gray-500 text-center" :style="{ fontSize: getDesign.fontSize + 'px' }">{{ | |
| 215 | 221 | getDesign.attribute || '速度' |
| 216 | 222 | }}</div> |
| 217 | 223 | </div> | ... | ... |
| ... | ... | @@ -15,6 +15,8 @@ export const option: PublicPresetOptions = { |
| 15 | 15 | [ComponentConfigFieldEnum.SHOW_TIME]: false, |
| 16 | 16 | [ComponentConfigFieldEnum.MAX_NUMBER]: 100, |
| 17 | 17 | [ComponentConfigFieldEnum.UNIT]: '℃', |
| 18 | + [ComponentConfigFieldEnum.VALUE_SIZE]: 14, | |
| 19 | + [ComponentConfigFieldEnum.FONT_SIZE]: 14, | |
| 18 | 20 | }; |
| 19 | 21 | |
| 20 | 22 | export default class Config extends PublicConfigClass implements CreateComponentType { | ... | ... |
| ... | ... | @@ -53,6 +53,40 @@ |
| 53 | 53 | }; |
| 54 | 54 | }, |
| 55 | 55 | }, |
| 56 | + { | |
| 57 | + field: ComponentConfigFieldEnum.VALUE_SIZE, | |
| 58 | + label: '数值字体大小', | |
| 59 | + component: 'InputNumber', | |
| 60 | + defaultValue: 14, | |
| 61 | + componentProps: { | |
| 62 | + min: 0, | |
| 63 | + formatter: (e) => { | |
| 64 | + const value = e.replace(/^0/g, ''); | |
| 65 | + if (value) { | |
| 66 | + return value.replace(/^0/g, ''); | |
| 67 | + } else { | |
| 68 | + return 0; | |
| 69 | + } | |
| 70 | + }, | |
| 71 | + }, | |
| 72 | + }, | |
| 73 | + { | |
| 74 | + field: ComponentConfigFieldEnum.FONT_SIZE, | |
| 75 | + label: '文本字体大小', | |
| 76 | + component: 'InputNumber', | |
| 77 | + defaultValue: 14, | |
| 78 | + componentProps: { | |
| 79 | + min: 0, | |
| 80 | + formatter: (e) => { | |
| 81 | + const value = e.replace(/^0/g, ''); | |
| 82 | + if (value) { | |
| 83 | + return value.replace(/^0/g, ''); | |
| 84 | + } else { | |
| 85 | + return 0; | |
| 86 | + } | |
| 87 | + }, | |
| 88 | + }, | |
| 89 | + }, | |
| 56 | 90 | ], |
| 57 | 91 | showActionButtonGroup: false, |
| 58 | 92 | labelWidth: 120, | ... | ... |
| ... | ... | @@ -32,19 +32,23 @@ |
| 32 | 32 | unit: presetUnit, |
| 33 | 33 | showTime: persetShowTime, |
| 34 | 34 | maxNumber: persetMaxNumber, |
| 35 | + valueSize: persetValueSize, | |
| 36 | + fontSize: persetFontSize, | |
| 35 | 37 | } = persetOption || {}; |
| 36 | - const { unit, fontColor, showTime, maxNumber } = componentInfo || {}; | |
| 38 | + const { unit, fontColor, showTime, maxNumber, valueSize, fontSize } = componentInfo || {}; | |
| 37 | 39 | return { |
| 38 | 40 | unit: unit ?? presetUnit, |
| 39 | 41 | fontColor: fontColor ?? presetFontColor, |
| 40 | 42 | attribute: attributeRename || attributeName || attribute, |
| 41 | 43 | showTime: persetShowTime || showTime, |
| 42 | 44 | maxNumber: maxNumber || persetMaxNumber, |
| 45 | + valueSize: valueSize || persetValueSize || 14, | |
| 46 | + fontSize: fontSize || persetFontSize || 14, | |
| 43 | 47 | }; |
| 44 | 48 | }); |
| 45 | 49 | |
| 46 | 50 | const options = (): EChartsOption => { |
| 47 | - const { unit, fontColor, maxNumber } = unref(getDesign); | |
| 51 | + const { unit, fontColor, maxNumber, valueSize } = unref(getDesign); | |
| 48 | 52 | return { |
| 49 | 53 | series: [ |
| 50 | 54 | { |
| ... | ... | @@ -104,7 +108,7 @@ |
| 104 | 108 | lineHeight: 10, |
| 105 | 109 | borderRadius: 8, |
| 106 | 110 | offsetCenter: [0, '40%'], |
| 107 | - fontSize: unref(getRatio) ? 14 * unref(getRatio) : 14, | |
| 111 | + fontSize: unref(getRatio) ? valueSize * unref(getRatio) : valueSize, | |
| 108 | 112 | fontWeight: 'bolder', |
| 109 | 113 | formatter: `{value} ${unit ?? ''}`, |
| 110 | 114 | color: fontColor || 'inherit', |
| ... | ... | @@ -200,7 +204,7 @@ |
| 200 | 204 | series: [ |
| 201 | 205 | { |
| 202 | 206 | detail: { |
| 203 | - fontSize: 14 * unref(getRatio), | |
| 207 | + fontSize: unref(getDesign).valueSize * unref(getRatio), | |
| 204 | 208 | }, |
| 205 | 209 | progress: { |
| 206 | 210 | width: 24 * unref(getRatio), |
| ... | ... | @@ -238,9 +242,11 @@ |
| 238 | 242 | <div class="w-full h-full flex justify-center items-center flex-1 flex-col"> |
| 239 | 243 | <div ref="chartRefEl" class="flex-1 w-full h-6/7 flex justify-center items-center flex-col"> |
| 240 | 244 | </div> |
| 241 | - <div class="text-gray-500 text-xs text-center truncate">{{ | |
| 242 | - getDesign.attribute || '温度' | |
| 243 | - }}</div> | |
| 245 | + <div | |
| 246 | + class="text-gray-500 text-center truncate" | |
| 247 | + :style="{ fontSize: getDesign.fontSize + 'px' }" | |
| 248 | + >{{ getDesign.attribute || '温度' }}</div | |
| 249 | + > | |
| 244 | 250 | </div> |
| 245 | 251 | <UpdateTime v-show="getDesign.showTime" :time="time" /> |
| 246 | 252 | </main> | ... | ... |
| ... | ... | @@ -31,6 +31,8 @@ export const option: PublicPresetOptions = { |
| 31 | 31 | [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: false, |
| 32 | 32 | [ComponentConfigFieldEnum.SHOW_TIME]: false, |
| 33 | 33 | [ComponentConfigFieldEnum.MAX_NUMBER]: 100, |
| 34 | + [ComponentConfigFieldEnum.FONT_SIZE]: 14, | |
| 35 | + [ComponentConfigFieldEnum.VALUE_SIZE]: 14, | |
| 34 | 36 | }; |
| 35 | 37 | |
| 36 | 38 | export default class Config extends PublicConfigClass implements CreateComponentType { | ... | ... |
| ... | ... | @@ -77,16 +77,38 @@ |
| 77 | 77 | }, |
| 78 | 78 | }, |
| 79 | 79 | { |
| 80 | - field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME, | |
| 81 | - label: '显示设备名称', | |
| 82 | - component: 'Checkbox', | |
| 83 | - defaultValue: option.showDeviceName, | |
| 80 | + field: ComponentConfigFieldEnum.VALUE_SIZE, | |
| 81 | + label: '数值字体大小', | |
| 82 | + component: 'InputNumber', | |
| 83 | + defaultValue: 14, | |
| 84 | + componentProps: { | |
| 85 | + min: 0, | |
| 86 | + formatter: (e) => { | |
| 87 | + const value = e.replace(/^0/g, ''); | |
| 88 | + if (value) { | |
| 89 | + return value.replace(/^0/g, ''); | |
| 90 | + } else { | |
| 91 | + return 0; | |
| 92 | + } | |
| 93 | + }, | |
| 94 | + }, | |
| 84 | 95 | }, |
| 85 | 96 | { |
| 86 | - field: ComponentConfigFieldEnum.SHOW_TIME, | |
| 87 | - label: '显示时间', | |
| 88 | - component: 'Checkbox', | |
| 89 | - defaultValue: option.showTime, | |
| 97 | + field: ComponentConfigFieldEnum.FONT_SIZE, | |
| 98 | + label: '文本字体大小', | |
| 99 | + component: 'InputNumber', | |
| 100 | + defaultValue: 14, | |
| 101 | + componentProps: { | |
| 102 | + min: 0, | |
| 103 | + formatter: (e) => { | |
| 104 | + const value = e.replace(/^0/g, ''); | |
| 105 | + if (value) { | |
| 106 | + return value.replace(/^0/g, ''); | |
| 107 | + } else { | |
| 108 | + return 0; | |
| 109 | + } | |
| 110 | + }, | |
| 111 | + }, | |
| 90 | 112 | }, |
| 91 | 113 | { |
| 92 | 114 | field: ComponentConfigFieldEnum.MAX_NUMBER, |
| ... | ... | @@ -109,6 +131,18 @@ |
| 109 | 131 | }; |
| 110 | 132 | }, |
| 111 | 133 | }, |
| 134 | + { | |
| 135 | + field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME, | |
| 136 | + label: '显示设备名称', | |
| 137 | + component: 'Checkbox', | |
| 138 | + defaultValue: option.showDeviceName, | |
| 139 | + }, | |
| 140 | + { | |
| 141 | + field: ComponentConfigFieldEnum.SHOW_TIME, | |
| 142 | + label: '显示时间', | |
| 143 | + component: 'Checkbox', | |
| 144 | + defaultValue: option.showTime, | |
| 145 | + }, | |
| 112 | 146 | ], |
| 113 | 147 | showActionButtonGroup: false, |
| 114 | 148 | labelWidth: 120, |
| ... | ... | @@ -142,11 +176,22 @@ |
| 142 | 176 | showDeviceName: value[ComponentConfigFieldEnum.SHOW_DEVICE_NAME], |
| 143 | 177 | showTime: value[ComponentConfigFieldEnum.SHOW_TIME], |
| 144 | 178 | maxNumber: value[ComponentConfigFieldEnum.MAX_NUMBER], |
| 179 | + valueSize: value[ComponentConfigFieldEnum.VALUE_SIZE], | |
| 180 | + fontSize: value[ComponentConfigFieldEnum.FONT_SIZE], | |
| 145 | 181 | } as ComponentInfo; |
| 146 | 182 | }; |
| 147 | 183 | |
| 148 | 184 | const setFormValues = (data: ComponentInfo) => { |
| 149 | - const { gradientInfo, unit, fontColor, showDeviceName, showTime, maxNumber } = data; | |
| 185 | + const { | |
| 186 | + gradientInfo, | |
| 187 | + unit, | |
| 188 | + fontColor, | |
| 189 | + showDeviceName, | |
| 190 | + showTime, | |
| 191 | + maxNumber, | |
| 192 | + valueSize, | |
| 193 | + fontSize, | |
| 194 | + } = data; | |
| 150 | 195 | const firstRecord = gradientInfo.find((item) => item.key === Gradient.FIRST); |
| 151 | 196 | const secondRecord = gradientInfo.find((item) => item.key === Gradient.SECOND); |
| 152 | 197 | const thirdRecord = gradientInfo.find((item) => item.key === Gradient.THIRD); |
| ... | ... | @@ -156,6 +201,8 @@ |
| 156 | 201 | [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: showDeviceName, |
| 157 | 202 | [ComponentConfigFieldEnum.SHOW_TIME]: showTime, |
| 158 | 203 | [ComponentConfigFieldEnum.MAX_NUMBER]: maxNumber, |
| 204 | + [ComponentConfigFieldEnum.VALUE_SIZE]: valueSize, | |
| 205 | + [ComponentConfigFieldEnum.FONT_SIZE]: fontSize, | |
| 159 | 206 | [ComponentConfigFieldEnum.FIRST_PHASE_VALUE]: firstRecord?.value, |
| 160 | 207 | [ComponentConfigFieldEnum.FIRST_PHASE_COLOR]: firstRecord?.color, |
| 161 | 208 | [ComponentConfigFieldEnum.SECOND_PHASE_VALUE]: secondRecord?.value, | ... | ... |
| ... | ... | @@ -38,9 +38,12 @@ |
| 38 | 38 | gradientInfo: presetGradientInfo, |
| 39 | 39 | showTime: persetShowTime, |
| 40 | 40 | maxNumber: persetMaxNumber, |
| 41 | + fontSize: persetFontSize, | |
| 42 | + valueSize: persetValueSize, | |
| 41 | 43 | } = persetOption || {}; |
| 42 | 44 | |
| 43 | - const { unit, fontColor, gradientInfo, showTime, maxNumber } = componentInfo || {}; | |
| 45 | + const { unit, fontColor, gradientInfo, showTime, maxNumber, fontSize, valueSize } = | |
| 46 | + componentInfo || {}; | |
| 44 | 47 | return { |
| 45 | 48 | unit: unit ?? presetUnit, |
| 46 | 49 | fontColor: fontColor ?? presetFontColor, |
| ... | ... | @@ -48,6 +51,8 @@ |
| 48 | 51 | attribute: attributeRename || attributeName || attribute, |
| 49 | 52 | showTime: showTime || persetShowTime, |
| 50 | 53 | maxNumber: maxNumber || persetMaxNumber, |
| 54 | + fontSize: fontSize || persetFontSize || 14, | |
| 55 | + valueSize: valueSize || persetValueSize || 14, | |
| 51 | 56 | }; |
| 52 | 57 | }); |
| 53 | 58 | |
| ... | ... | @@ -57,7 +62,7 @@ |
| 57 | 62 | }; |
| 58 | 63 | |
| 59 | 64 | const options = (): EChartsOption => { |
| 60 | - const { gradientInfo, unit, fontColor, maxNumber } = unref(getDesign); | |
| 65 | + const { gradientInfo, unit, fontColor, maxNumber, valueSize } = unref(getDesign); | |
| 61 | 66 | const firstRecord = getGradient(Gradient.FIRST, gradientInfo); |
| 62 | 67 | const secondRecord = getGradient(Gradient.SECOND, gradientInfo); |
| 63 | 68 | const thirdRecord = getGradient(Gradient.THIRD, gradientInfo); |
| ... | ... | @@ -122,7 +127,7 @@ |
| 122 | 127 | formatter: `{value} ${unit ?? ''}`, |
| 123 | 128 | color: fontColor || 'inherit', |
| 124 | 129 | offsetCenter: [0, '70%'], |
| 125 | - fontSize: unref(getRatio) ? unref(getRatio) * 14 : 14, | |
| 130 | + fontSize: unref(getRatio) ? unref(getRatio) * valueSize : valueSize, | |
| 126 | 131 | }, |
| 127 | 132 | data: [ |
| 128 | 133 | { |
| ... | ... | @@ -194,7 +199,7 @@ |
| 194 | 199 | fontSize: 6 * unref(getRatio), |
| 195 | 200 | }, |
| 196 | 201 | detail: { |
| 197 | - fontSize: 14 * unref(getRatio), | |
| 202 | + fontSize: unref(getDesign).valueSize * unref(getRatio), | |
| 198 | 203 | }, |
| 199 | 204 | }, |
| 200 | 205 | ], |
| ... | ... | @@ -218,7 +223,10 @@ |
| 218 | 223 | <div class="w-full h-full flex justify-center items-center flex-col flex-1"> |
| 219 | 224 | <div ref="chartRefEl" class="flex-1 w-full h-6/7 flex flex-col justify-center items-center"> |
| 220 | 225 | </div> |
| 221 | - <div class="text-center text-gray-500 text-xs truncate"> | |
| 226 | + <div | |
| 227 | + class="text-center text-gray-500 truncate" | |
| 228 | + :style="{ fontSize: getDesign.fontSize + 'px' }" | |
| 229 | + > | |
| 222 | 230 | {{ getDesign.attribute || '速度' }} |
| 223 | 231 | </div> |
| 224 | 232 | </div> | ... | ... |
| ... | ... | @@ -42,17 +42,17 @@ |
| 42 | 42 | |
| 43 | 43 | const handleGetVideoPlayUrl = async () => { |
| 44 | 44 | try { |
| 45 | - const instance = unref(basicVideoPlayEl)?.getInstance(); | |
| 46 | 45 | const { config } = props; |
| 47 | 46 | const { option } = config; |
| 48 | 47 | const { videoConfig, uuid } = option || {}; |
| 49 | 48 | if (!uuid) return; |
| 50 | 49 | const { url, id, accessMode } = videoConfig || {}; |
| 51 | - const type = getVideoTypeByUrl(url!); | |
| 50 | + let type = getVideoTypeByUrl(url!); | |
| 52 | 51 | let playUrl = url; |
| 53 | 52 | if (accessMode === AccessMode.Streaming && id) { |
| 54 | 53 | const { data: { url } = { url: '' } } = await getStreamingPlayUrl(id!); |
| 55 | 54 | playUrl = url; |
| 55 | + playUrl && (type = getVideoTypeByUrl(playUrl!)); | |
| 56 | 56 | } |
| 57 | 57 | |
| 58 | 58 | if (isRtspProtocol(url!)) { |
| ... | ... | @@ -60,10 +60,6 @@ |
| 60 | 60 | const { visitorId } = result; |
| 61 | 61 | playUrl = getFlvPlayUrl(playUrl!, visitorId); |
| 62 | 62 | withToken.value = true; |
| 63 | - | |
| 64 | - (instance!.options_ as any).flvjs.config.headers = { | |
| 65 | - 'X-Authorization': `Bearer ${isShareMode() ? getShareJwtToken() : getJwtToken()}`, | |
| 66 | - }; | |
| 67 | 63 | } |
| 68 | 64 | |
| 69 | 65 | playSource.value = { |
| ... | ... | @@ -71,7 +67,17 @@ |
| 71 | 67 | type, |
| 72 | 68 | }; |
| 73 | 69 | |
| 74 | - instance?.src(toRaw(unref(playSource))); | |
| 70 | + const instance = unref(basicVideoPlayEl)?.customInit((options) => { | |
| 71 | + withToken.value = true; | |
| 72 | + | |
| 73 | + if (unref(withToken)) { | |
| 74 | + (options as any).flvjs.config.headers = { | |
| 75 | + 'X-Authorization': `Bearer ${isShareMode() ? getShareJwtToken() : getJwtToken()}`, | |
| 76 | + }; | |
| 77 | + } | |
| 78 | + return { ...options, sources: [toRaw(unref(playSource))] } as VideoJsPlayerOptions; | |
| 79 | + }); | |
| 80 | + | |
| 75 | 81 | instance?.play(); |
| 76 | 82 | } finally { |
| 77 | 83 | loading.value = false; |
| ... | ... | @@ -80,8 +86,19 @@ |
| 80 | 86 | |
| 81 | 87 | const handleSelectPreview = () => { |
| 82 | 88 | loading.value = false; |
| 83 | - const instance = unref(basicVideoPlayEl)?.getInstance(); | |
| 84 | - instance?.src({ type: getVideoTypeByUrl(exampleVideoPlay), src: exampleVideoPlay }); | |
| 89 | + const instance = unref(basicVideoPlayEl)?.customInit((options) => { | |
| 90 | + withToken.value = true; | |
| 91 | + | |
| 92 | + if (unref(withToken)) { | |
| 93 | + (options as any).flvjs.config.headers = { | |
| 94 | + 'X-Authorization': `Bearer ${isShareMode() ? getShareJwtToken() : getJwtToken()}`, | |
| 95 | + }; | |
| 96 | + } | |
| 97 | + return { | |
| 98 | + ...options, | |
| 99 | + sources: [{ type: getVideoTypeByUrl(exampleVideoPlay), src: exampleVideoPlay }], | |
| 100 | + } as VideoJsPlayerOptions; | |
| 101 | + }); | |
| 85 | 102 | instance?.play(); |
| 86 | 103 | }; |
| 87 | 104 | |
| ... | ... | @@ -103,7 +120,12 @@ |
| 103 | 120 | <template> |
| 104 | 121 | <main class="w-full h-full flex flex-col justify-center items-center p-2"> |
| 105 | 122 | <Spin :spinning="loading" wrapper-class-name="video-spin"> |
| 106 | - <BasicVideoPlay ref="basicVideoPlayEl" :options="getOptions" :with-token="withToken" /> | |
| 123 | + <BasicVideoPlay | |
| 124 | + ref="basicVideoPlayEl" | |
| 125 | + :options="getOptions" | |
| 126 | + :with-token="withToken" | |
| 127 | + :immediateInitOnMounted="false" | |
| 128 | + /> | |
| 107 | 129 | </Spin> |
| 108 | 130 | </main> |
| 109 | 131 | </template> | ... | ... |
| ... | ... | @@ -14,6 +14,7 @@ export const option: PublicPresetOptions = { |
| 14 | 14 | [ComponentConfigFieldEnum.CLOSE_COLOR]: '#eeeeee', |
| 15 | 15 | [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: true, |
| 16 | 16 | [ComponentConfigFieldEnum.SHOW_TIME]: false, |
| 17 | + [ComponentConfigFieldEnum.FONT_SIZE]: 14, | |
| 17 | 18 | }; |
| 18 | 19 | |
| 19 | 20 | export default class Config extends PublicConfigClass implements CreateComponentType { | ... | ... |
| ... | ... | @@ -25,6 +25,29 @@ |
| 25 | 25 | }, |
| 26 | 26 | }, |
| 27 | 27 | { |
| 28 | + field: ComponentConfigFieldEnum.FONT_SIZE, | |
| 29 | + label: '文本字体大小', | |
| 30 | + component: 'InputNumber', | |
| 31 | + defaultValue: 14, | |
| 32 | + componentProps: { | |
| 33 | + min: 0, | |
| 34 | + formatter: (e) => { | |
| 35 | + const value = e.replace(/^0/g, ''); | |
| 36 | + if (value) { | |
| 37 | + return value.replace(/^0/g, ''); | |
| 38 | + } else { | |
| 39 | + return 0; | |
| 40 | + } | |
| 41 | + }, | |
| 42 | + }, | |
| 43 | + }, | |
| 44 | + { | |
| 45 | + field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME, | |
| 46 | + label: '显示设备名称', | |
| 47 | + component: 'Checkbox', | |
| 48 | + defaultValue: option.showDeviceName, | |
| 49 | + }, | |
| 50 | + { | |
| 28 | 51 | field: ComponentConfigFieldEnum.SHOW_TIME, |
| 29 | 52 | label: '显示时间', |
| 30 | 53 | component: 'Checkbox', | ... | ... |
| ... | ... | @@ -25,16 +25,18 @@ |
| 25 | 25 | closeColor: persetCloseColor, |
| 26 | 26 | showDeviceName: persetShowDeviceName, |
| 27 | 27 | showTime: persetShowTime, |
| 28 | + fontSize: persetFontSize, | |
| 28 | 29 | } = persetOption || {}; |
| 29 | 30 | const { componentInfo, attribute, attributeName, attributeRename } = option; |
| 30 | 31 | |
| 31 | - const { openColor, closeColor, showDeviceName, showTime } = componentInfo || {}; | |
| 32 | + const { openColor, closeColor, showDeviceName, showTime, fontSize } = componentInfo || {}; | |
| 32 | 33 | return { |
| 33 | 34 | openColor: openColor ?? persetOpenColor, |
| 34 | 35 | closeColor: closeColor ?? persetCloseColor, |
| 35 | 36 | showDeviceName: showDeviceName ?? persetShowDeviceName, |
| 36 | 37 | attribute: attributeRename || attributeName || attribute, |
| 37 | 38 | showTime: showTime ?? persetShowTime, |
| 39 | + fontSize: fontSize || persetFontSize || 14, | |
| 38 | 40 | }; |
| 39 | 41 | }); |
| 40 | 42 | |
| ... | ... | @@ -78,7 +80,9 @@ |
| 78 | 80 | }" |
| 79 | 81 | :class="isOpenClose ? 'switch_open' : 'switch_close'" |
| 80 | 82 | ></div> |
| 81 | - <div class="text-gray-500 text-sm truncate">{{ getDesign.attribute }}</div> | |
| 83 | + <div class="text-gray-500 truncate" :style="{ fontSize: getDesign.fontSize + 'px' }">{{ | |
| 84 | + getDesign.attribute | |
| 85 | + }}</div> | |
| 82 | 86 | </div> |
| 83 | 87 | <UpdateTime v-if="getDesign.showTime" :time="time" /> |
| 84 | 88 | </main> | ... | ... |
| ... | ... | @@ -16,6 +16,7 @@ export const option: PublicPresetOptions = { |
| 16 | 16 | [ComponentConfigFieldEnum.ICON_COLOR_CLOSE]: '#CCCCCC', |
| 17 | 17 | [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: false, |
| 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 { | ... | ... |
| ... | ... | @@ -47,6 +47,23 @@ |
| 47 | 47 | defaultValue: option.iconColorClose, |
| 48 | 48 | }, |
| 49 | 49 | { |
| 50 | + field: ComponentConfigFieldEnum.FONT_SIZE, | |
| 51 | + label: '文本字体大小', | |
| 52 | + component: 'InputNumber', | |
| 53 | + defaultValue: 14, | |
| 54 | + componentProps: { | |
| 55 | + min: 0, | |
| 56 | + formatter: (e) => { | |
| 57 | + const value = e.replace(/^0/g, ''); | |
| 58 | + if (value) { | |
| 59 | + return value.replace(/^0/g, ''); | |
| 60 | + } else { | |
| 61 | + return 0; | |
| 62 | + } | |
| 63 | + }, | |
| 64 | + }, | |
| 65 | + }, | |
| 66 | + { | |
| 50 | 67 | field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME, |
| 51 | 68 | label: '显示设备名称', |
| 52 | 69 | component: 'Checkbox', | ... | ... |
| ... | ... | @@ -26,11 +26,12 @@ |
| 26 | 26 | iconClose: persetIconCLose, |
| 27 | 27 | iconColorClose: persetIconColorClose, |
| 28 | 28 | showTime: persetShowTime, |
| 29 | + fontSize: persetFontSize, | |
| 29 | 30 | } = persetOption; |
| 30 | 31 | |
| 31 | 32 | const { componentInfo, attributeName, attributeRename } = option; |
| 32 | 33 | |
| 33 | - const { icon, iconColor, fontColor, unit, iconClose, iconColorClose, showTime } = | |
| 34 | + const { icon, iconColor, fontColor, unit, iconClose, iconColorClose, showTime, fontSize } = | |
| 34 | 35 | componentInfo || {}; |
| 35 | 36 | return { |
| 36 | 37 | iconColor: iconColor || persetIconColor, |
| ... | ... | @@ -41,6 +42,7 @@ |
| 41 | 42 | iconClose: iconClose || persetIconCLose, |
| 42 | 43 | iconColorClose: iconColorClose || persetIconColorClose, |
| 43 | 44 | showTime: showTime ?? persetShowTime, |
| 45 | + fontSize: fontSize || persetFontSize || 14, | |
| 44 | 46 | }; |
| 45 | 47 | }); |
| 46 | 48 | |
| ... | ... | @@ -68,7 +70,9 @@ |
| 68 | 70 | :size="60" |
| 69 | 71 | :style="{ color: isOpenClose ? getDesign.iconColor : getDesign.iconColorClose }" |
| 70 | 72 | /> |
| 71 | - <div class="text-gray-500 text-sm truncate m-2">{{ getDesign.attribute || '' }}</div> | |
| 73 | + <div class="text-gray-500 truncate m-2" :style="{ fontSize: getDesign.fontSize + 'px' }">{{ | |
| 74 | + getDesign.attribute || '' | |
| 75 | + }}</div> | |
| 72 | 76 | </div> |
| 73 | 77 | <UpdateTime v-show="getDesign.showTime" :time="time" /> |
| 74 | 78 | </main> | ... | ... |
| ... | ... | @@ -12,6 +12,8 @@ import { ComponentConfigFieldEnum } from '/@/views/visual/packages/enum'; |
| 12 | 12 | export const option: PublicPresetOptions = { |
| 13 | 13 | [ComponentConfigFieldEnum.FONT_COLOR]: '#000', |
| 14 | 14 | [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: false, |
| 15 | + [ComponentConfigFieldEnum.FONT_SIZE]: 14, | |
| 16 | + [ComponentConfigFieldEnum.VALUE_SIZE]: 20, | |
| 15 | 17 | }; |
| 16 | 18 | |
| 17 | 19 | export default class Config extends PublicConfigClass implements CreateComponentType { | ... | ... |
| ... | ... | @@ -19,6 +19,40 @@ |
| 19 | 19 | label: '显示设备名称', |
| 20 | 20 | component: 'Checkbox', |
| 21 | 21 | }, |
| 22 | + { | |
| 23 | + field: ComponentConfigFieldEnum.VALUE_SIZE, | |
| 24 | + label: '数值字体大小', | |
| 25 | + component: 'InputNumber', | |
| 26 | + defaultValue: 20, | |
| 27 | + componentProps: { | |
| 28 | + min: 0, | |
| 29 | + formatter: (e) => { | |
| 30 | + const value = e.replace(/^0/g, ''); | |
| 31 | + if (value) { | |
| 32 | + return value.replace(/^0/g, ''); | |
| 33 | + } else { | |
| 34 | + return 0; | |
| 35 | + } | |
| 36 | + }, | |
| 37 | + }, | |
| 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 | + }, | |
| 22 | 56 | ], |
| 23 | 57 | showActionButtonGroup: false, |
| 24 | 58 | labelWidth: 120, | ... | ... |
| ... | ... | @@ -17,13 +17,19 @@ |
| 17 | 17 | const getDesign = computed(() => { |
| 18 | 18 | const { persetOption = {}, option } = props.config; |
| 19 | 19 | |
| 20 | - const { fontColor: persetFontColor } = persetOption; | |
| 20 | + const { | |
| 21 | + fontColor: persetFontColor, | |
| 22 | + fontSize: persetFontSize, | |
| 23 | + valueSize: persetValueSize, | |
| 24 | + } = persetOption; | |
| 21 | 25 | |
| 22 | 26 | const { componentInfo, attribute, attributeRename, attributeName } = option; |
| 23 | 27 | |
| 24 | - const { fontColor } = componentInfo || {}; | |
| 28 | + const { fontColor, fontSize, valueSize } = componentInfo || {}; | |
| 25 | 29 | return { |
| 26 | 30 | fontColor: fontColor || persetFontColor, |
| 31 | + fontSize: fontSize || persetFontSize || 14, | |
| 32 | + valueSize: valueSize || persetValueSize || 20, | |
| 27 | 33 | attribute: attributeRename || attributeName || attribute, |
| 28 | 34 | }; |
| 29 | 35 | }); |
| ... | ... | @@ -45,10 +51,15 @@ |
| 45 | 51 | <main :style="getScale" class="w-full h-full flex flex-col justify-center items-center"> |
| 46 | 52 | <DeviceName :config="config" /> |
| 47 | 53 | |
| 48 | - <h1 class="my-4 font-bold text-xl !my-2 truncate" :style="{ color: getDesign.fontColor }"> | |
| 54 | + <h1 | |
| 55 | + class="my-4 font-bold !my-2 truncate" | |
| 56 | + :style="{ color: getDesign.fontColor, fontSize: getDesign.valueSize + 'px' }" | |
| 57 | + > | |
| 49 | 58 | {{ currentValue || 0 }} |
| 50 | 59 | </h1> |
| 51 | - <div class="text-gray-500 text-sm truncate">{{ getDesign.attribute || '温度' }}</div> | |
| 60 | + <div class="text-gray-500 truncate" :style="{ fontSize: getDesign.fontSize + 'px' }">{{ | |
| 61 | + getDesign.attribute || '温度' | |
| 62 | + }}</div> | |
| 52 | 63 | <!-- <div v-if="config.option.componentInfo.showDeviceName"> |
| 53 | 64 | {{ config.option.deviceRename || config.option.deviceName }} |
| 54 | 65 | </div> --> | ... | ... |
| ... | ... | @@ -12,6 +12,8 @@ import { ComponentConfigFieldEnum } from '/@/views/visual/packages/enum'; |
| 12 | 12 | export const option: PublicPresetOptions = { |
| 13 | 13 | [ComponentConfigFieldEnum.FONT_COLOR]: '#000', |
| 14 | 14 | [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: false, |
| 15 | + [ComponentConfigFieldEnum.VALUE_SIZE]: 20, | |
| 16 | + [ComponentConfigFieldEnum.FONT_SIZE]: 14, | |
| 15 | 17 | }; |
| 16 | 18 | |
| 17 | 19 | export default class Config extends PublicConfigClass implements CreateComponentType { | ... | ... |
| ... | ... | @@ -19,6 +19,40 @@ |
| 19 | 19 | label: '显示设备名称', |
| 20 | 20 | component: 'Checkbox', |
| 21 | 21 | }, |
| 22 | + { | |
| 23 | + field: ComponentConfigFieldEnum.VALUE_SIZE, | |
| 24 | + label: '数值字体大小', | |
| 25 | + component: 'InputNumber', | |
| 26 | + defaultValue: 20, | |
| 27 | + componentProps: { | |
| 28 | + min: 0, | |
| 29 | + formatter: (e) => { | |
| 30 | + const value = e.replace(/^0/g, ''); | |
| 31 | + if (value) { | |
| 32 | + return value.replace(/^0/g, ''); | |
| 33 | + } else { | |
| 34 | + return 0; | |
| 35 | + } | |
| 36 | + }, | |
| 37 | + }, | |
| 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 | + }, | |
| 22 | 56 | ], |
| 23 | 57 | showActionButtonGroup: false, |
| 24 | 58 | labelWidth: 120, | ... | ... |
| ... | ... | @@ -19,14 +19,20 @@ |
| 19 | 19 | const getDesign = computed(() => { |
| 20 | 20 | const { persetOption = {}, option } = props.config; |
| 21 | 21 | |
| 22 | - const { fontColor: persetFontColor } = persetOption; | |
| 22 | + const { | |
| 23 | + fontColor: persetFontColor, | |
| 24 | + valueSize: persetValueSize, | |
| 25 | + fontSize: persetFontSize, | |
| 26 | + } = persetOption; | |
| 23 | 27 | |
| 24 | 28 | const { componentInfo, attribute, attributeName, attributeRename } = option; |
| 25 | 29 | |
| 26 | - const { fontColor } = componentInfo || {}; | |
| 30 | + const { fontColor, valueSize, fontSize } = componentInfo || {}; | |
| 27 | 31 | |
| 28 | 32 | return { |
| 29 | 33 | fontColor: fontColor || persetFontColor, |
| 34 | + valueSize: valueSize || persetValueSize || 20, | |
| 35 | + fontSize: fontSize || persetFontSize || 14, | |
| 30 | 36 | attribute: attributeRename || attributeName || attribute, |
| 31 | 37 | }; |
| 32 | 38 | }); |
| ... | ... | @@ -50,10 +56,15 @@ |
| 50 | 56 | <DeviceName :config="config" /> |
| 51 | 57 | |
| 52 | 58 | <div class="flex-1 flex justify-center items-center flex-col" :style="getScale"> |
| 53 | - <h1 class="my-4 font-bold text-xl !my-2 truncate" :style="{ color: getDesign.fontColor }"> | |
| 59 | + <h1 | |
| 60 | + class="my-4 font-bold !my-2 truncate" | |
| 61 | + :style="{ color: getDesign.fontColor, fontSize: getDesign.valueSize + 'px' }" | |
| 62 | + > | |
| 54 | 63 | {{ currentValue || 0 }} |
| 55 | 64 | </h1> |
| 56 | - <div class="text-gray-500 text-sm truncate">{{ getDesign.attribute || '温度' }}</div> | |
| 65 | + <div class="text-gray-500 truncate" :style="{ fontSize: getDesign.fontSize + 'px' }">{{ | |
| 66 | + getDesign.attribute || '温度' | |
| 67 | + }}</div> | |
| 57 | 68 | </div> |
| 58 | 69 | <UpdateTime :time="time" /> |
| 59 | 70 | </main> | ... | ... |
| ... | ... | @@ -15,6 +15,8 @@ export const option: PublicPresetOptions = { |
| 15 | 15 | [ComponentConfigFieldEnum.ICON_COLOR]: '#367bff', |
| 16 | 16 | [ComponentConfigFieldEnum.FONT_COLOR]: '#000', |
| 17 | 17 | [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: false, |
| 18 | + [ComponentConfigFieldEnum.VALUE_SIZE]: 20, | |
| 19 | + [ComponentConfigFieldEnum.FONT_SIZE]: 14, | |
| 18 | 20 | }; |
| 19 | 21 | |
| 20 | 22 | export default class Config extends PublicConfigClass implements CreateComponentType { | ... | ... |
| ... | ... | @@ -23,6 +23,41 @@ |
| 23 | 23 | placeholder: '请输入数值单位', |
| 24 | 24 | }, |
| 25 | 25 | }, |
| 26 | + | |
| 27 | + { | |
| 28 | + field: ComponentConfigFieldEnum.VALUE_SIZE, | |
| 29 | + label: '数值字体大小', | |
| 30 | + component: 'InputNumber', | |
| 31 | + defaultValue: 20, | |
| 32 | + componentProps: { | |
| 33 | + min: 0, | |
| 34 | + formatter: (e) => { | |
| 35 | + const value = e.replace(/^0/g, ''); | |
| 36 | + if (value) { | |
| 37 | + return value.replace(/^0/g, ''); | |
| 38 | + } else { | |
| 39 | + return 0; | |
| 40 | + } | |
| 41 | + }, | |
| 42 | + }, | |
| 43 | + }, | |
| 44 | + { | |
| 45 | + field: ComponentConfigFieldEnum.FONT_SIZE, | |
| 46 | + label: '文本字体大小', | |
| 47 | + component: 'InputNumber', | |
| 48 | + defaultValue: 14, | |
| 49 | + componentProps: { | |
| 50 | + min: 0, | |
| 51 | + formatter: (e) => { | |
| 52 | + const value = e.replace(/^0/g, ''); | |
| 53 | + if (value) { | |
| 54 | + return value.replace(/^0/g, ''); | |
| 55 | + } else { | |
| 56 | + return 0; | |
| 57 | + } | |
| 58 | + }, | |
| 59 | + }, | |
| 60 | + }, | |
| 26 | 61 | { |
| 27 | 62 | field: ComponentConfigFieldEnum.ICON_COLOR, |
| 28 | 63 | label: '图标颜色', | ... | ... |
| ... | ... | @@ -26,17 +26,21 @@ |
| 26 | 26 | unit: perseUnit, |
| 27 | 27 | icon: persetIcon, |
| 28 | 28 | fontColor: persetFontColor, |
| 29 | + valueSize: persetValueSize, | |
| 30 | + fontSize: persetFontSize, | |
| 29 | 31 | } = persetOption; |
| 30 | 32 | |
| 31 | 33 | const { componentInfo, attribute, attributeRename, attributeName } = option; |
| 32 | 34 | |
| 33 | - const { icon, iconColor, fontColor, unit } = componentInfo || {}; | |
| 35 | + const { icon, iconColor, fontColor, unit, valueSize, fontSize } = componentInfo || {}; | |
| 34 | 36 | return { |
| 35 | 37 | iconColor: iconColor || persetIconColor, |
| 36 | 38 | unit: unit ?? perseUnit, |
| 37 | 39 | icon: icon || persetIcon, |
| 38 | 40 | fontColor: fontColor || persetFontColor, |
| 39 | 41 | attribute: attributeRename || attributeName || attribute, |
| 42 | + valueSize: valueSize || persetValueSize || 20, | |
| 43 | + fontSize: fontSize || persetFontSize || 14, | |
| 40 | 44 | }; |
| 41 | 45 | }); |
| 42 | 46 | |
| ... | ... | @@ -64,11 +68,16 @@ |
| 64 | 68 | :size="60" |
| 65 | 69 | :style="{ color: getDesign.iconColor }" |
| 66 | 70 | /> |
| 67 | - <h1 class="font-bold text-xl m-2 truncate" :style="{ color: getDesign.fontColor }"> | |
| 71 | + <h1 | |
| 72 | + class="font-bold m-2 truncate" | |
| 73 | + :style="{ color: getDesign.fontColor, fontSize: getDesign.valueSize + 'px' }" | |
| 74 | + > | |
| 68 | 75 | <span> {{ currentValue || 0 }}</span> |
| 69 | 76 | <span>{{ getDesign.unit }} </span> |
| 70 | 77 | </h1> |
| 71 | - <div class="text-gray-500 text-sm truncate">{{ getDesign.attribute || '温度' }}</div> | |
| 78 | + <div class="text-gray-500 truncate" :style="{ fontSize: getDesign.fontSize + 'px' }">{{ | |
| 79 | + getDesign.attribute || '温度' | |
| 80 | + }}</div> | |
| 72 | 81 | </div> |
| 73 | 82 | <UpdateTime :time="time" /> |
| 74 | 83 | </main> | ... | ... |
| ... | ... | @@ -15,6 +15,8 @@ export const option: PublicPresetOptions = { |
| 15 | 15 | [ComponentConfigFieldEnum.ICON_COLOR]: '#367bff', |
| 16 | 16 | [ComponentConfigFieldEnum.FONT_COLOR]: '#000', |
| 17 | 17 | [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: false, |
| 18 | + [ComponentConfigFieldEnum.VALUE_SIZE]: 20, | |
| 19 | + [ComponentConfigFieldEnum.FONT_SIZE]: 14, | |
| 18 | 20 | }; |
| 19 | 21 | |
| 20 | 22 | export default class Config extends PublicConfigClass implements CreateComponentType { | ... | ... |
| ... | ... | @@ -24,6 +24,40 @@ |
| 24 | 24 | }, |
| 25 | 25 | }, |
| 26 | 26 | { |
| 27 | + field: ComponentConfigFieldEnum.VALUE_SIZE, | |
| 28 | + label: '数值字体大小', | |
| 29 | + component: 'InputNumber', | |
| 30 | + defaultValue: 20, | |
| 31 | + componentProps: { | |
| 32 | + min: 0, | |
| 33 | + formatter: (e) => { | |
| 34 | + const value = e.replace(/^0/g, ''); | |
| 35 | + if (value) { | |
| 36 | + return value.replace(/^0/g, ''); | |
| 37 | + } else { | |
| 38 | + return 0; | |
| 39 | + } | |
| 40 | + }, | |
| 41 | + }, | |
| 42 | + }, | |
| 43 | + { | |
| 44 | + field: ComponentConfigFieldEnum.FONT_SIZE, | |
| 45 | + label: '文本字体大小', | |
| 46 | + component: 'InputNumber', | |
| 47 | + defaultValue: 14, | |
| 48 | + componentProps: { | |
| 49 | + min: 0, | |
| 50 | + formatter: (e) => { | |
| 51 | + const value = e.replace(/^0/g, ''); | |
| 52 | + if (value) { | |
| 53 | + return value.replace(/^0/g, ''); | |
| 54 | + } else { | |
| 55 | + return 0; | |
| 56 | + } | |
| 57 | + }, | |
| 58 | + }, | |
| 59 | + }, | |
| 60 | + { | |
| 27 | 61 | field: ComponentConfigFieldEnum.ICON_COLOR, |
| 28 | 62 | label: '图标颜色', |
| 29 | 63 | component: 'ColorPicker', | ... | ... |
| ... | ... | @@ -23,17 +23,21 @@ |
| 23 | 23 | unit: perseUnit, |
| 24 | 24 | icon: persetIcon, |
| 25 | 25 | fontColor: persetFontColor, |
| 26 | + valueSize: persetValueSize, | |
| 27 | + fontSize: persetFontSize, | |
| 26 | 28 | } = persetOption; |
| 27 | 29 | |
| 28 | 30 | const { componentInfo, attribute, attributeRename, attributeName } = option; |
| 29 | 31 | |
| 30 | - const { icon, iconColor, fontColor, unit } = componentInfo || {}; | |
| 32 | + const { icon, iconColor, fontColor, unit, valueSize, fontSize } = componentInfo || {}; | |
| 31 | 33 | return { |
| 32 | 34 | iconColor: iconColor || persetIconColor, |
| 33 | 35 | unit: unit ?? perseUnit, |
| 34 | 36 | icon: icon || persetIcon, |
| 35 | 37 | fontColor: fontColor || persetFontColor, |
| 36 | 38 | attribute: attributeRename || attributeName || attribute, |
| 39 | + valueSize: valueSize || persetValueSize || 20, | |
| 40 | + fontSize: fontSize || persetFontSize || 14, | |
| 37 | 41 | }; |
| 38 | 42 | }); |
| 39 | 43 | |
| ... | ... | @@ -60,11 +64,16 @@ |
| 60 | 64 | :size="60" |
| 61 | 65 | :style="{ color: getDesign.iconColor }" |
| 62 | 66 | /> |
| 63 | - <h1 class="my-4 font-bold text-lg !my-2 truncate" :style="{ color: getDesign.fontColor }"> | |
| 67 | + <h1 | |
| 68 | + class="my-4 font-bold !my-2 truncate" | |
| 69 | + :style="{ color: getDesign.fontColor, fontSize: getDesign.valueSize + 'px' }" | |
| 70 | + > | |
| 64 | 71 | <span>{{ currentValue || 0 }}</span> |
| 65 | 72 | <span>{{ getDesign.unit }}</span> |
| 66 | 73 | </h1> |
| 67 | - <div class="text-gray-500 text-sm truncate">{{ getDesign.attribute || '温度' }}</div> | |
| 74 | + <div class="text-gray-500 truncate" :style="{ fontSize: getDesign.fontSize + 'px' }">{{ | |
| 75 | + getDesign.attribute || '温度' | |
| 76 | + }}</div> | |
| 68 | 77 | </div> |
| 69 | 78 | </main> |
| 70 | 79 | </template> | ... | ... |
| ... | ... | @@ -16,7 +16,8 @@ export const option: PublicPresetOptions = { |
| 16 | 16 | [ComponentConfigFieldEnum.UNIT]: '℃', |
| 17 | 17 | [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: false, |
| 18 | 18 | [ComponentConfigFieldEnum.BACKGROUND_COLOR]: '#377dff', |
| 19 | - fontSize: '18px', | |
| 19 | + [ComponentConfigFieldEnum.VALUE_SIZE]: 20, | |
| 20 | + [ComponentConfigFieldEnum.FONT_SIZE]: 14, | |
| 20 | 21 | }; |
| 21 | 22 | |
| 22 | 23 | export default class Config extends PublicConfigClass implements CreateComponentType { | ... | ... |
| ... | ... | @@ -24,6 +24,41 @@ |
| 24 | 24 | defaultValue: option.backgroundColor, |
| 25 | 25 | }, |
| 26 | 26 | }, |
| 27 | + | |
| 28 | + { | |
| 29 | + field: ComponentConfigFieldEnum.VALUE_SIZE, | |
| 30 | + label: '数值字体大小', | |
| 31 | + component: 'InputNumber', | |
| 32 | + defaultValue: 20, | |
| 33 | + componentProps: { | |
| 34 | + min: 0, | |
| 35 | + formatter: (e) => { | |
| 36 | + const value = e.replace(/^0/g, ''); | |
| 37 | + if (value) { | |
| 38 | + return value.replace(/^0/g, ''); | |
| 39 | + } else { | |
| 40 | + return 0; | |
| 41 | + } | |
| 42 | + }, | |
| 43 | + }, | |
| 44 | + }, | |
| 45 | + { | |
| 46 | + field: ComponentConfigFieldEnum.FONT_SIZE, | |
| 47 | + label: '文本字体大小', | |
| 48 | + component: 'InputNumber', | |
| 49 | + defaultValue: 14, | |
| 50 | + componentProps: { | |
| 51 | + min: 0, | |
| 52 | + formatter: (e) => { | |
| 53 | + const value = e.replace(/^0/g, ''); | |
| 54 | + if (value) { | |
| 55 | + return value.replace(/^0/g, ''); | |
| 56 | + } else { | |
| 57 | + return 0; | |
| 58 | + } | |
| 59 | + }, | |
| 60 | + }, | |
| 61 | + }, | |
| 27 | 62 | { |
| 28 | 63 | field: ComponentConfigFieldEnum.MAX_NUMBER, |
| 29 | 64 | label: '最大值', | ... | ... |
| ... | ... | @@ -29,6 +29,7 @@ |
| 29 | 29 | attributeName?: string; |
| 30 | 30 | deviceRename?: string; |
| 31 | 31 | maxNumber?: number; |
| 32 | + [key: string]: number | string | undefined; | |
| 32 | 33 | } |
| 33 | 34 | |
| 34 | 35 | const defaultValue: PercentType[] = [ |
| ... | ... | @@ -39,6 +40,8 @@ |
| 39 | 40 | unit: '℃', |
| 40 | 41 | deviceName: '温湿度', |
| 41 | 42 | attribute: '温度', |
| 43 | + fontSize: 14, | |
| 44 | + valueSize: 20, | |
| 42 | 45 | id: buildUUID(), |
| 43 | 46 | }, |
| 44 | 47 | { |
| ... | ... | @@ -60,10 +63,13 @@ |
| 60 | 63 | fontColor: presetFontColor, |
| 61 | 64 | backgroundColor: persetBackgroundColor, |
| 62 | 65 | maxNumber: persetMaxNumber, |
| 66 | + valueSize: persetValueSize, | |
| 67 | + fontSize: persetFontSize, | |
| 63 | 68 | } = persetOption || {}; |
| 64 | 69 | return { |
| 65 | 70 | dataSource: dataSource.map((item) => { |
| 66 | - const { unit, fontColor, backgroundColor, maxNumber } = item.componentInfo || {}; | |
| 71 | + const { unit, fontColor, backgroundColor, maxNumber, valueSize, fontSize } = | |
| 72 | + item.componentInfo || {}; | |
| 67 | 73 | const { attribute, attributeRename, deviceName, deviceRename, deviceId, attributeName } = |
| 68 | 74 | item; |
| 69 | 75 | return { |
| ... | ... | @@ -75,6 +81,8 @@ |
| 75 | 81 | attributeName: attributeRename || attributeName, |
| 76 | 82 | maxNumber: maxNumber || persetMaxNumber, |
| 77 | 83 | id: deviceId, |
| 84 | + valueSize: valueSize || persetValueSize || 20, | |
| 85 | + fontSize: fontSize || persetFontSize || 14, | |
| 78 | 86 | } as PercentType; |
| 79 | 87 | }), |
| 80 | 88 | }; |
| ... | ... | @@ -112,14 +120,17 @@ |
| 112 | 120 | class="mt-2 flex flex-col ml-3 mr-3 items-stretch" |
| 113 | 121 | > |
| 114 | 122 | <div class="flex justify-between"> |
| 115 | - <div class="text-gray-500 text-sm truncate" :style="{ color: item.fontColor }"> | |
| 123 | + <div | |
| 124 | + class="text-gray-500 text-sm truncate" | |
| 125 | + :style="{ color: item.fontColor, fontSize: item.fontSize + 'px' }" | |
| 126 | + > | |
| 116 | 127 | {{ |
| 117 | 128 | `${item.deviceName} |
| 118 | 129 | - |
| 119 | 130 | ${item.attributeName || item.attribute || '温度'}` |
| 120 | 131 | }} |
| 121 | 132 | </div> |
| 122 | - <span class="text-lg" :style="{ color: item.fontColor }" | |
| 133 | + <span class="text-lg" :style="{ color: item.fontColor, fontSize: item.valueSize + 'px' }" | |
| 123 | 134 | >{{ item.value }} {{ item.unit }}</span |
| 124 | 135 | > |
| 125 | 136 | </div> | ... | ... |
| ... | ... | @@ -16,6 +16,8 @@ export const option: PublicPresetOptions = { |
| 16 | 16 | [ComponentConfigFieldEnum.ICON_COLOR]: '#367bff', |
| 17 | 17 | [ComponentConfigFieldEnum.FONT_COLOR]: '#000', |
| 18 | 18 | [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: false, |
| 19 | + [ComponentConfigFieldEnum.VALUE_SIZE]: 20, | |
| 20 | + [ComponentConfigFieldEnum.FONT_SIZE]: 14, | |
| 19 | 21 | }; |
| 20 | 22 | |
| 21 | 23 | export default class Config extends PublicConfigClass implements CreateComponentType { | ... | ... |
| ... | ... | @@ -23,6 +23,41 @@ |
| 23 | 23 | placeholder: '请输入数值单位', |
| 24 | 24 | }, |
| 25 | 25 | }, |
| 26 | + | |
| 27 | + { | |
| 28 | + field: ComponentConfigFieldEnum.VALUE_SIZE, | |
| 29 | + label: '数值字体大小', | |
| 30 | + component: 'InputNumber', | |
| 31 | + defaultValue: 20, | |
| 32 | + componentProps: { | |
| 33 | + min: 0, | |
| 34 | + formatter: (e) => { | |
| 35 | + const value = e.replace(/^0/g, ''); | |
| 36 | + if (value) { | |
| 37 | + return value.replace(/^0/g, ''); | |
| 38 | + } else { | |
| 39 | + return 0; | |
| 40 | + } | |
| 41 | + }, | |
| 42 | + }, | |
| 43 | + }, | |
| 44 | + { | |
| 45 | + field: ComponentConfigFieldEnum.FONT_SIZE, | |
| 46 | + label: '文本字体大小', | |
| 47 | + component: 'InputNumber', | |
| 48 | + defaultValue: 14, | |
| 49 | + componentProps: { | |
| 50 | + min: 0, | |
| 51 | + formatter: (e) => { | |
| 52 | + const value = e.replace(/^0/g, ''); | |
| 53 | + if (value) { | |
| 54 | + return value.replace(/^0/g, ''); | |
| 55 | + } else { | |
| 56 | + return 0; | |
| 57 | + } | |
| 58 | + }, | |
| 59 | + }, | |
| 60 | + }, | |
| 26 | 61 | { |
| 27 | 62 | field: ComponentConfigFieldEnum.ICON_COLOR, |
| 28 | 63 | label: '图标颜色', | ... | ... |
| ... | ... | @@ -9,6 +9,7 @@ |
| 9 | 9 | import { useReceiveValue } from '../../../hook/useReceiveValue'; |
| 10 | 10 | import { useMultipleDataFetch } from '../../../hook/socket/useSocket'; |
| 11 | 11 | import { MultipleDataFetchUpdateFn } from '../../../hook/socket/useSocket.type'; |
| 12 | + import { useComponentScale } from '../../../hook/useComponentScale'; | |
| 12 | 13 | |
| 13 | 14 | const props = defineProps<{ |
| 14 | 15 | config: ComponentPropsConfigType<typeof option>; |
| ... | ... | @@ -24,10 +25,12 @@ |
| 24 | 25 | fontColor: persetFontColor, |
| 25 | 26 | icon: persetIcon, |
| 26 | 27 | iconColor: persetIconColor, |
| 28 | + valueSize: persetValueSize, | |
| 29 | + fontSize: persetFontSize, | |
| 27 | 30 | } = persetOption || {}; |
| 28 | 31 | return { |
| 29 | 32 | dataSource: dataSource.map((item) => { |
| 30 | - const { fontColor, icon, iconColor, unit } = item.componentInfo; | |
| 33 | + const { fontColor, icon, iconColor, unit, valueSize, fontSize } = item.componentInfo; | |
| 31 | 34 | const { attribute, attributeRename, deviceName, deviceRename, deviceId, attributeName } = |
| 32 | 35 | item; |
| 33 | 36 | |
| ... | ... | @@ -40,6 +43,8 @@ |
| 40 | 43 | deviceName: deviceRename || deviceName, |
| 41 | 44 | attributeName: attributeRename || attributeName, |
| 42 | 45 | id: deviceId, |
| 46 | + valueSize: valueSize || persetValueSize || 20, | |
| 47 | + fontSize: fontSize || persetFontSize || 14, | |
| 43 | 48 | }; |
| 44 | 49 | }), |
| 45 | 50 | }; |
| ... | ... | @@ -84,6 +89,7 @@ |
| 84 | 89 | }; |
| 85 | 90 | |
| 86 | 91 | useMultipleDataFetch(props, updateFn); |
| 92 | + const { getRatio } = useComponentScale(props); | |
| 87 | 93 | </script> |
| 88 | 94 | |
| 89 | 95 | <template> |
| ... | ... | @@ -99,19 +105,21 @@ |
| 99 | 105 | <SvgIcon |
| 100 | 106 | :name="item.icon!" |
| 101 | 107 | prefix="iconfont" |
| 102 | - :size="40" | |
| 108 | + :size="getRatio ? 25 * getRatio : 25" | |
| 103 | 109 | :style="{ color: item.iconColor }" |
| 104 | 110 | /> |
| 105 | 111 | |
| 106 | - <div class="text-gray-500 text-lg truncate ml-6">{{ | |
| 107 | - item.deviceName + '-' + item.attributeName || '温度' | |
| 108 | - }}</div> | |
| 112 | + <div | |
| 113 | + class="text-gray-500 text-sm truncate ml-6" | |
| 114 | + :style="{ fontSize: item.fontSize + 'px' }" | |
| 115 | + >{{ item.deviceName + '-' + item.attributeName || '温度' }}</div | |
| 116 | + > | |
| 109 | 117 | </div> |
| 110 | 118 | |
| 111 | - <h1 class="font-bold text-xl m-2 truncate" :style="{ color: item.fontColor }"> | |
| 119 | + <span class="text-lg" :style="{ color: item.fontColor, fontSize: item.valueSize + 'px' }"> | |
| 112 | 120 | <span> {{ item.value || 0 }}</span> |
| 113 | 121 | <span>{{ item.unit }} </span> |
| 114 | - </h1> | |
| 122 | + </span> | |
| 115 | 123 | </div> |
| 116 | 124 | <!-- <UpdateTime :time="time" /> --> |
| 117 | 125 | </main> | ... | ... |
| ... | ... | @@ -14,6 +14,7 @@ import { OrgTreeSelect } from '/@/views/common/OrgTreeSelect'; |
| 14 | 14 | import { TransportTypeEnum } from '/@/views/device/profiles/components/TransportDescript/const'; |
| 15 | 15 | import { CommandTypeEnum } from '/@/views/rule/linkedge/config/config.data'; |
| 16 | 16 | import { DataActionModeEnum } from '/@/enums/toolEnum'; |
| 17 | +import { TaskTypeEnum } from '/@/views/task/center/config'; | |
| 17 | 18 | |
| 18 | 19 | useComponentRegister('OrgTreeSelect', OrgTreeSelect); |
| 19 | 20 | |
| ... | ... | @@ -24,6 +25,7 @@ export interface CommonDataSourceBindValueType extends Record<DataSourceField, s |
| 24 | 25 | command?: string; |
| 25 | 26 | commandType?: string; |
| 26 | 27 | callType?: string; |
| 28 | + [ksy: string]: string | undefined; | |
| 27 | 29 | }; |
| 28 | 30 | } |
| 29 | 31 | |
| ... | ... | @@ -33,6 +35,7 @@ export enum DataSourceField { |
| 33 | 35 | TRANSPORT_TYPE = 'transportType', |
| 34 | 36 | ORIGINATION_ID = 'organizationId', |
| 35 | 37 | DEVICE_ID = 'deviceId', |
| 38 | + DEVICE_CODE = 'deviceCode', //设备地址码 | |
| 36 | 39 | DEVICE_PROFILE_ID = 'deviceProfileId', |
| 37 | 40 | ATTRIBUTE = 'attribute', |
| 38 | 41 | ATTRIBUTE_NAME = 'attributeName', |
| ... | ... | @@ -41,10 +44,15 @@ export enum DataSourceField { |
| 41 | 44 | DEVICE_RENAME = 'deviceRename', |
| 42 | 45 | LONGITUDE_ATTRIBUTE = 'longitudeAttribute', |
| 43 | 46 | LATITUDE_ATTRIBUTE = 'latitudeAttribute', |
| 44 | - | |
| 47 | + CODE_TYPE = 'codeType', | |
| 45 | 48 | COMMAND = 'command', |
| 49 | + OPEN_COMMAND = 'openCommand', | |
| 50 | + CLOSE_COMMAND = 'closeCommand', | |
| 46 | 51 | COMMAND_TYPE = 'commandType', |
| 47 | 52 | SERVICE = 'service', |
| 53 | + OPEN_SERVICE = 'openService', | |
| 54 | + CLOSE_SERVICE = 'closeService', | |
| 55 | + EXTENSION_DESC = 'extensionDesc', | |
| 48 | 56 | CALL_TYPE = 'callType', |
| 49 | 57 | } |
| 50 | 58 | |
| ... | ... | @@ -72,7 +80,7 @@ const getDeviceService = async (deviceProfileId: string) => { |
| 72 | 80 | const getDeviceAttribute = async (params: DeviceAttributeParams) => { |
| 73 | 81 | try { |
| 74 | 82 | const data = await getDeviceAttributes(params); |
| 75 | - if (data) return data.map((item) => ({ label: item.name, value: item.identifier })); | |
| 83 | + if (data) return data.map((item) => ({ ...item, label: item.name, value: item.identifier })); | |
| 76 | 84 | } catch (error) {} |
| 77 | 85 | return []; |
| 78 | 86 | }; |
| ... | ... | @@ -82,7 +90,6 @@ export const commonDataSourceSchemas = (): FormSchema[] => { |
| 82 | 90 | const isUpdate = unref(mode) === DataActionModeEnum.UPDATE; |
| 83 | 91 | const selectWidgetKeys = useSelectWidgetKeys(); |
| 84 | 92 | const category = unref(selectWidgetKeys).categoryKey; |
| 85 | - | |
| 86 | 93 | return [ |
| 87 | 94 | { |
| 88 | 95 | field: DataSourceField.IS_GATEWAY_DEVICE, |
| ... | ... | @@ -161,6 +168,7 @@ export const commonDataSourceSchemas = (): FormSchema[] => { |
| 161 | 168 | [DataSourceField.ATTRIBUTE]: null, |
| 162 | 169 | [DataSourceField.ATTRIBUTE_NAME]: null, |
| 163 | 170 | [DataSourceField.TRANSPORT_TYPE]: option[DataSourceField.TRANSPORT_TYPE], |
| 171 | + [DataSourceField.COMMAND_TYPE]: null, | |
| 164 | 172 | }); |
| 165 | 173 | }, |
| 166 | 174 | getPopupContainer: () => document.body, |
| ... | ... | @@ -228,6 +236,9 @@ export const commonDataSourceSchemas = (): FormSchema[] => { |
| 228 | 236 | onChange(_value, record: MasterDeviceList) { |
| 229 | 237 | setFieldsValue({ |
| 230 | 238 | [DataSourceField.DEVICE_NAME]: record?.label, |
| 239 | + [DataSourceField.CODE_TYPE]: record?.codeType, | |
| 240 | + [DataSourceField.DEVICE_CODE]: record?.code, | |
| 241 | + [DataSourceField.COMMAND_TYPE]: null, | |
| 231 | 242 | }); |
| 232 | 243 | }, |
| 233 | 244 | placeholder: '请选择设备', |
| ... | ... | @@ -236,19 +247,94 @@ export const commonDataSourceSchemas = (): FormSchema[] => { |
| 236 | 247 | }, |
| 237 | 248 | }, |
| 238 | 249 | { |
| 250 | + field: DataSourceField.CODE_TYPE, | |
| 251 | + component: 'Input', | |
| 252 | + label: '设备标识符', | |
| 253 | + show: false, | |
| 254 | + }, | |
| 255 | + | |
| 256 | + { | |
| 257 | + field: DataSourceField.DEVICE_CODE, | |
| 258 | + component: 'Input', | |
| 259 | + show: false, | |
| 260 | + label: '设备地址码', | |
| 261 | + }, | |
| 262 | + | |
| 263 | + { | |
| 239 | 264 | field: DataSourceField.ATTRIBUTE_NAME, |
| 240 | 265 | component: 'Input', |
| 241 | 266 | label: '属性名', |
| 242 | 267 | show: false, |
| 243 | 268 | }, |
| 244 | 269 | { |
| 270 | + field: DataSourceField.COMMAND_TYPE, | |
| 271 | + component: 'ApiSelect', | |
| 272 | + label: '命令类型', | |
| 273 | + defaultValue: CommandTypeEnum.CUSTOM.toString(), | |
| 274 | + rules: [{ required: true, message: '请选择命令类型' }], | |
| 275 | + colProps: { span: 8 }, | |
| 276 | + ifShow: ({ model }) => { | |
| 277 | + return isControlComponent(category!) && isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]); | |
| 278 | + }, | |
| 279 | + componentProps: ({ formActionType, formModel }) => { | |
| 280 | + const { setFieldsValue } = formActionType; | |
| 281 | + const { codeType } = formModel || {}; | |
| 282 | + return { | |
| 283 | + // api: findDictItemByCode, | |
| 284 | + api: async (params: Recordable) => { | |
| 285 | + try { | |
| 286 | + const record = await findDictItemByCode(params); | |
| 287 | + if (unref(selectWidgetKeys).componentKey == 'LateralNumericalControl') { | |
| 288 | + return record.filter( | |
| 289 | + (item) => item.itemValue == CommandTypeEnum.ATTRIBUTE.toString() | |
| 290 | + ); | |
| 291 | + } | |
| 292 | + if (codeType == TaskTypeEnum.MODBUS_RTU) { | |
| 293 | + // setFieldsValue({ [DataSourceField.COMMAND_TYPE]: undefined }); | |
| 294 | + return record.filter( | |
| 295 | + (item) => item.itemValue !== CommandTypeEnum.CUSTOM.toString() | |
| 296 | + ); | |
| 297 | + } else { | |
| 298 | + return record.filter( | |
| 299 | + (item) => item.itemValue !== CommandTypeEnum.ATTRIBUTE.toString() | |
| 300 | + ); | |
| 301 | + } | |
| 302 | + } catch (error) { | |
| 303 | + console.log(error); | |
| 304 | + return []; | |
| 305 | + } | |
| 306 | + }, | |
| 307 | + params: { | |
| 308 | + dictCode: 'custom_define', | |
| 309 | + }, | |
| 310 | + labelField: 'itemText', | |
| 311 | + valueField: 'itemValue', | |
| 312 | + placeholder: '请选择命令类型', | |
| 313 | + getPopupContainer: () => document.body, | |
| 314 | + onChange() { | |
| 315 | + setFieldsValue({ | |
| 316 | + [DataSourceField.COMMAND]: null, | |
| 317 | + [DataSourceField.SERVICE]: null, | |
| 318 | + [DataSourceField.OPEN_COMMAND]: null, | |
| 319 | + [DataSourceField.CLOSE_COMMAND]: null, | |
| 320 | + [DataSourceField.OPEN_SERVICE]: null, | |
| 321 | + [DataSourceField.CLOSE_SERVICE]: null, | |
| 322 | + [DataSourceField.CALL_TYPE]: null, | |
| 323 | + [DataSourceField.ATTRIBUTE]: null, | |
| 324 | + }); | |
| 325 | + }, | |
| 326 | + }; | |
| 327 | + }, | |
| 328 | + }, | |
| 329 | + { | |
| 245 | 330 | field: DataSourceField.ATTRIBUTE, |
| 246 | 331 | component: 'ApiSelect', |
| 247 | 332 | label: '属性', |
| 248 | 333 | colProps: { span: 8 }, |
| 249 | 334 | rules: [{ required: true, message: '请选择属性' }], |
| 250 | 335 | ifShow: ({ model }) => |
| 251 | - !(isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]) && isControlComponent(category!)), | |
| 336 | + !(isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]) && isControlComponent(category!)) || | |
| 337 | + model[DataSourceField.COMMAND_TYPE] == 2, | |
| 252 | 338 | componentProps({ formModel, formActionType }) { |
| 253 | 339 | const { setFieldsValue } = formActionType; |
| 254 | 340 | const deviceProfileId = formModel[DataSourceField.DEVICE_PROFILE_ID]; |
| ... | ... | @@ -266,16 +352,15 @@ export const commonDataSourceSchemas = (): FormSchema[] => { |
| 266 | 352 | : undefined, |
| 267 | 353 | }); |
| 268 | 354 | |
| 269 | - // 当我们通过复制组件在进行编辑的时候选择控制组件会使不是bool属性的值进行赋值 | |
| 270 | - if ( | |
| 271 | - (!option?.length && | |
| 272 | - isControlComponent(category!) && | |
| 273 | - unref(selectWidgetKeys).componentKey !== 'LateralNumericalControl') || | |
| 274 | - isBooleanComponent(unref(selectWidgetKeys)) | |
| 275 | - ) { | |
| 355 | + // 选择控制组件4的时候只能选择属性且是(int double类型) | |
| 356 | + if (unref(selectWidgetKeys).componentKey == 'LateralNumericalControl') { | |
| 276 | 357 | setFieldsValue({ |
| 277 | - [DataSourceField.ATTRIBUTE]: null, | |
| 358 | + [DataSourceField.COMMAND_TYPE]: CommandTypeEnum.ATTRIBUTE.toString(), | |
| 278 | 359 | }); |
| 360 | + return option.filter( | |
| 361 | + (item) => | |
| 362 | + item.detail.dataType.type == 'INT' || item.detail.dataType.type == 'DOUBLE' | |
| 363 | + ); | |
| 279 | 364 | } |
| 280 | 365 | return option; |
| 281 | 366 | } |
| ... | ... | @@ -284,53 +369,79 @@ export const commonDataSourceSchemas = (): FormSchema[] => { |
| 284 | 369 | }, |
| 285 | 370 | placeholder: '请选择属性', |
| 286 | 371 | getPopupContainer: () => document.body, |
| 287 | - onChange(value: string, option: Record<'label' | 'value', string>) { | |
| 288 | - setFieldsValue({ [DataSourceField.ATTRIBUTE_NAME]: value ? option.label : null }); | |
| 372 | + onChange(value: string, option: Record<'label' | 'value' | any, string>) { | |
| 373 | + setFieldsValue({ | |
| 374 | + [DataSourceField.ATTRIBUTE_NAME]: value ? option.label : null, | |
| 375 | + [DataSourceField.EXTENSION_DESC]: value ? JSON.stringify(option.extensionDesc) : '', | |
| 376 | + }); | |
| 289 | 377 | }, |
| 290 | 378 | }; |
| 291 | 379 | }, |
| 292 | 380 | }, |
| 293 | 381 | { |
| 294 | - field: DataSourceField.COMMAND_TYPE, | |
| 382 | + field: DataSourceField.EXTENSION_DESC, | |
| 383 | + component: 'Input', | |
| 384 | + show: false, | |
| 385 | + label: '扩展描述符', | |
| 386 | + }, | |
| 387 | + | |
| 388 | + { | |
| 389 | + field: DataSourceField.CALL_TYPE, | |
| 390 | + component: 'Input', | |
| 391 | + ifShow: false, | |
| 392 | + label: 'callType', | |
| 393 | + }, | |
| 394 | + { | |
| 395 | + field: DataSourceField.OPEN_SERVICE, | |
| 295 | 396 | component: 'ApiSelect', |
| 296 | - label: '命令类型', | |
| 297 | - defaultValue: CommandTypeEnum.CUSTOM.toString(), | |
| 298 | - rules: [{ required: true, message: '请选择命令类型' }], | |
| 397 | + label: '开服务', | |
| 299 | 398 | colProps: { span: 8 }, |
| 399 | + rules: [{ required: true, message: '请选择开服务' }], | |
| 300 | 400 | ifShow: ({ model }) => |
| 301 | - isControlComponent(category!) && isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]), | |
| 302 | - componentProps: ({ formActionType }) => { | |
| 401 | + isControlComponent(category!) && | |
| 402 | + model[DataSourceField.COMMAND_TYPE] === CommandTypeEnum.SERVICE.toString() && | |
| 403 | + isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]), | |
| 404 | + componentProps({ formModel, formActionType }) { | |
| 303 | 405 | const { setFieldsValue } = formActionType; |
| 406 | + const deviceProfileId = formModel[DataSourceField.DEVICE_PROFILE_ID]; | |
| 407 | + const transportType = formModel[DataSourceField.TRANSPORT_TYPE]; | |
| 408 | + if (isUpdate && ![deviceProfileId, transportType].every(Boolean)) | |
| 409 | + return { placeholder: '请选择开服务', getPopupContainer: () => document.body }; | |
| 304 | 410 | return { |
| 305 | - api: findDictItemByCode, | |
| 306 | - params: { | |
| 307 | - dictCode: 'custom_define', | |
| 411 | + api: async () => { | |
| 412 | + try { | |
| 413 | + if (deviceProfileId) { | |
| 414 | + const services = await getDeviceService(deviceProfileId); | |
| 415 | + const value = formModel[DataSourceField.SERVICE]; | |
| 416 | + if (value) { | |
| 417 | + const selected = services.find((item) => item.value === value); | |
| 418 | + selected && setFieldsValue({ [DataSourceField.CALL_TYPE]: selected.callType }); | |
| 419 | + } | |
| 420 | + return services; | |
| 421 | + } | |
| 422 | + } catch (error) {} | |
| 423 | + return []; | |
| 308 | 424 | }, |
| 309 | - labelField: 'itemText', | |
| 310 | - valueField: 'itemValue', | |
| 311 | - placeholder: '请选择命令类型', | |
| 312 | - onChange() { | |
| 425 | + placeholder: '请选择开服务', | |
| 426 | + getPopupContainer: () => document.body, | |
| 427 | + onChange(value: string, options: ModelOfMatterParams) { | |
| 428 | + const command = value | |
| 429 | + ? (options.functionJson.inputData || [])[0]?.serviceCommand | |
| 430 | + : null; | |
| 313 | 431 | setFieldsValue({ |
| 314 | - [DataSourceField.COMMAND]: null, | |
| 315 | - [DataSourceField.SERVICE]: null, | |
| 316 | - [DataSourceField.CALL_TYPE]: null, | |
| 432 | + [DataSourceField.OPEN_COMMAND]: command, | |
| 433 | + [DataSourceField.CALL_TYPE]: value ? options.callType : null, | |
| 317 | 434 | }); |
| 318 | 435 | }, |
| 319 | 436 | }; |
| 320 | 437 | }, |
| 321 | 438 | }, |
| 322 | 439 | { |
| 323 | - field: DataSourceField.CALL_TYPE, | |
| 324 | - component: 'Input', | |
| 325 | - ifShow: false, | |
| 326 | - label: 'callType', | |
| 327 | - }, | |
| 328 | - { | |
| 329 | - field: DataSourceField.SERVICE, | |
| 440 | + field: DataSourceField.CLOSE_SERVICE, | |
| 330 | 441 | component: 'ApiSelect', |
| 331 | - label: '服务', | |
| 442 | + label: '关服务', | |
| 332 | 443 | colProps: { span: 8 }, |
| 333 | - rules: [{ required: true, message: '请选择服务' }], | |
| 444 | + rules: [{ required: true, message: '请选择关服务' }], | |
| 334 | 445 | ifShow: ({ model }) => |
| 335 | 446 | isControlComponent(category!) && |
| 336 | 447 | model[DataSourceField.COMMAND_TYPE] === CommandTypeEnum.SERVICE.toString() && |
| ... | ... | @@ -340,7 +451,7 @@ export const commonDataSourceSchemas = (): FormSchema[] => { |
| 340 | 451 | const deviceProfileId = formModel[DataSourceField.DEVICE_PROFILE_ID]; |
| 341 | 452 | const transportType = formModel[DataSourceField.TRANSPORT_TYPE]; |
| 342 | 453 | if (isUpdate && ![deviceProfileId, transportType].every(Boolean)) |
| 343 | - return { placeholder: '请选择服务', getPopupContainer: () => document.body }; | |
| 454 | + return { placeholder: '请选择关服务', getPopupContainer: () => document.body }; | |
| 344 | 455 | return { |
| 345 | 456 | api: async () => { |
| 346 | 457 | try { |
| ... | ... | @@ -356,14 +467,14 @@ export const commonDataSourceSchemas = (): FormSchema[] => { |
| 356 | 467 | } catch (error) {} |
| 357 | 468 | return []; |
| 358 | 469 | }, |
| 359 | - placeholder: '请选择服务', | |
| 470 | + placeholder: '请选择关服务', | |
| 360 | 471 | getPopupContainer: () => document.body, |
| 361 | 472 | onChange(value: string, options: ModelOfMatterParams) { |
| 362 | 473 | const command = value |
| 363 | 474 | ? (options.functionJson.inputData || [])[0]?.serviceCommand |
| 364 | 475 | : null; |
| 365 | 476 | setFieldsValue({ |
| 366 | - [DataSourceField.COMMAND]: command, | |
| 477 | + [DataSourceField.CLOSE_COMMAND]: command, | |
| 367 | 478 | [DataSourceField.CALL_TYPE]: value ? options.callType : null, |
| 368 | 479 | }); |
| 369 | 480 | }, |
| ... | ... | @@ -371,11 +482,27 @@ export const commonDataSourceSchemas = (): FormSchema[] => { |
| 371 | 482 | }, |
| 372 | 483 | }, |
| 373 | 484 | { |
| 374 | - field: DataSourceField.COMMAND, | |
| 485 | + field: DataSourceField.OPEN_COMMAND, | |
| 486 | + component: 'Input', | |
| 487 | + label: '命令', | |
| 488 | + colProps: { span: 8 }, | |
| 489 | + rules: [{ required: true, message: '请输入开下发命令' }], | |
| 490 | + // 是控制组件 && 自定义命令 && 传输协议为TCP | |
| 491 | + ifShow: ({ model }) => | |
| 492 | + isControlComponent(category!) && | |
| 493 | + model[DataSourceField.COMMAND_TYPE] === CommandTypeEnum.CUSTOM.toString() && | |
| 494 | + model[DataSourceField.TRANSPORT_TYPE] && | |
| 495 | + isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]), | |
| 496 | + componentProps: { | |
| 497 | + placeholder: '请输入开下发命令', | |
| 498 | + }, | |
| 499 | + }, | |
| 500 | + { | |
| 501 | + field: DataSourceField.CLOSE_COMMAND, | |
| 375 | 502 | component: 'Input', |
| 376 | 503 | label: '命令', |
| 377 | 504 | colProps: { span: 8 }, |
| 378 | - rules: [{ required: true, message: '请输入下发命令' }], | |
| 505 | + rules: [{ required: true, message: '请输入关下发命令' }], | |
| 379 | 506 | // 是控制组件 && 自定义命令 && 传输协议为TCP |
| 380 | 507 | ifShow: ({ model }) => |
| 381 | 508 | isControlComponent(category!) && |
| ... | ... | @@ -383,7 +510,7 @@ export const commonDataSourceSchemas = (): FormSchema[] => { |
| 383 | 510 | model[DataSourceField.TRANSPORT_TYPE] && |
| 384 | 511 | isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]), |
| 385 | 512 | componentProps: { |
| 386 | - placeholder: '请输入下发命令', | |
| 513 | + placeholder: '请输入关下发命令', | |
| 387 | 514 | }, |
| 388 | 515 | }, |
| 389 | 516 | { | ... | ... |
| 1 | 1 | export enum ComponentConfigFieldEnum { |
| 2 | - FONT_COLOR = 'fontColor', | |
| 2 | + FONT_COLOR = 'fontColor', //数值字体颜色 | |
| 3 | + VALUE_SIZE = 'valueSize', //数值字体大小 | |
| 4 | + TEXT_COLOR = 'textColor', //文本字体颜色 | |
| 5 | + FONT_SIZE = 'fontSize', //文本数值颜色 | |
| 3 | 6 | UNIT = 'unit', |
| 4 | 7 | POINTER_COLOR = 'pointerColor', |
| 5 | 8 | INSTRUMENT_PANEL_COLOR = 'instrumentPanelColor', | ... | ... |
| ... | ... | @@ -102,7 +102,7 @@ class Subscriber { |
| 102 | 102 | return { |
| 103 | 103 | cmdId: subscriptionId, |
| 104 | 104 | entityId: deviceId, |
| 105 | - keys: Array.from(attributes.values()).join(','), | |
| 105 | + keys: Array.from(attributes.values()).filter(Boolean).join(','), | |
| 106 | 106 | entityType: EntityTypeEnum.DEVICE, |
| 107 | 107 | scope: ScopeTypeEnum.LATEST_TELEMERY, |
| 108 | 108 | ...(unsubscribe ? { unsubscribe } : {}), | ... | ... |
| ... | ... | @@ -14,7 +14,7 @@ export function useSendCommand() { |
| 14 | 14 | return false; |
| 15 | 15 | }; |
| 16 | 16 | |
| 17 | - const sendCommand = async (record: DataSource, value: any) => { | |
| 17 | + const sendCommand = async (record: DataSource, value: any, isModbusCommand = false) => { | |
| 18 | 18 | if (!record) return false; |
| 19 | 19 | const { customCommand, attribute } = record || {}; |
| 20 | 20 | const { deviceId } = record; |
| ... | ... | @@ -25,16 +25,18 @@ export function useSendCommand() { |
| 25 | 25 | let params: string | Recordable = { |
| 26 | 26 | [attribute!]: Number(value), |
| 27 | 27 | }; |
| 28 | + if (isModbusCommand) { | |
| 29 | + params = value; | |
| 30 | + } | |
| 28 | 31 | |
| 29 | 32 | let sendCommandFn = sendCommandOneway; |
| 30 | 33 | // 如果是TCP设备从物模型中获取下发命令(TCP网关子设备无物模型服务与事件) |
| 31 | - if (customCommand?.transportType === TransportTypeEnum.TCP) { | |
| 34 | + if (customCommand?.transportType === TransportTypeEnum.TCP && !isModbusCommand) { | |
| 32 | 35 | params = customCommand.command!; |
| 33 | 36 | if (customCommand.callType === ServiceCallTypeEnum.SYNC) { |
| 34 | 37 | sendCommandFn = sendCommandTwoway; |
| 35 | 38 | } |
| 36 | 39 | } |
| 37 | - | |
| 38 | 40 | // 控制按钮下发命令为0 或 1 |
| 39 | 41 | await sendCommandFn({ |
| 40 | 42 | deviceId, | ... | ... |
| ... | ... | @@ -54,7 +54,7 @@ |
| 54 | 54 | }, |
| 55 | 55 | labelWidth: 120, |
| 56 | 56 | fieldMapToTime: [ |
| 57 | - [SchemaFiled.DATE_RANGE, [SchemaFiled.START_TS, SchemaFiled.END_TS], 'YYYY-MM-DD HH:ss'], | |
| 57 | + [SchemaFiled.DATE_RANGE, [SchemaFiled.START_TS, SchemaFiled.END_TS], 'YYYY-MM-DD HH:mm:ss'], | |
| 58 | 58 | ], |
| 59 | 59 | submitButtonOptions: { |
| 60 | 60 | loading: loading as unknown as boolean, |
| ... | ... | @@ -260,7 +260,7 @@ |
| 260 | 260 | :show-ok-btn="false" |
| 261 | 261 | cancel-text="关闭" |
| 262 | 262 | width="70%" |
| 263 | - title="历史趋势" | |
| 263 | + title="选择时间" | |
| 264 | 264 | > |
| 265 | 265 | <section |
| 266 | 266 | class="flex flex-col p-4 h-full w-full min-w-7/10" | ... | ... |
| ... | ... | @@ -152,8 +152,10 @@ |
| 152 | 152 | <section class="p-5 flex flex-col w-full"> |
| 153 | 153 | <main class="flex w-full h-full h-7"> |
| 154 | 154 | <Tooltip :title="sourceInfo.name"> |
| 155 | - <div class="flex-1 w-full h-full flex text-lg justify-center font-semibold"> | |
| 156 | - {{ sourceInfo.name }} | |
| 155 | + <div class="flex-1 w-full h-full flex text-lg justify-center font-semibold truncate"> | |
| 156 | + <div class="w-full truncate text-center"> | |
| 157 | + {{ sourceInfo.name }} | |
| 158 | + </div> | |
| 157 | 159 | </div> |
| 158 | 160 | </Tooltip> |
| 159 | 161 | ... | ... |
| ... | ... | @@ -28,6 +28,7 @@ export interface DataSource { |
| 28 | 28 | componentInfo: ComponentInfo; |
| 29 | 29 | customCommand: CustomCommand; |
| 30 | 30 | videoConfig?: VideoConfigType; |
| 31 | + [key: string]: any; | |
| 31 | 32 | } |
| 32 | 33 | |
| 33 | 34 | export interface ExtraDataSource extends DataSource, PublicComponentOptions { |
| ... | ... | @@ -62,6 +63,8 @@ export interface ComponentInfo { |
| 62 | 63 | progressBarCircle?: Boolean; |
| 63 | 64 | lineColor?: string; |
| 64 | 65 | maxNumber?: number; |
| 66 | + fontSize?: string | number; | |
| 67 | + valueSize?: string | number; | |
| 65 | 68 | [key: string]: any; |
| 66 | 69 | } |
| 67 | 70 | |
| ... | ... | @@ -71,6 +74,7 @@ export interface CustomCommand { |
| 71 | 74 | command: string; |
| 72 | 75 | service: string; |
| 73 | 76 | callType: string; |
| 77 | + [key: string]: string | undefined; | |
| 74 | 78 | } |
| 75 | 79 | |
| 76 | 80 | export interface ComponentLayoutType { | ... | ... |