Showing
53 changed files
with
1447 additions
and
691 deletions
... | ... | @@ -22,7 +22,6 @@ |
22 | 22 | theme = htmlRoot = null; |
23 | 23 | } |
24 | 24 | })(); |
25 | - | |
26 | 25 | </script> |
27 | 26 | <div id="app"> |
28 | 27 | <style> |
... | ... | @@ -152,17 +151,17 @@ |
152 | 151 | } |
153 | 152 | } |
154 | 153 | </style> |
155 | - <div class="app-loading"> | |
154 | + <div id="first-screen-loading" class="app-loading"> | |
156 | 155 | <div class="app-loading-wrap"> |
157 | - <img src="/resource/img/logo.png" class="app-loading-logo" alt="Logo" /> | |
156 | + <!-- <img src="/resource/img/logo.png" class="app-loading-logo" alt="Logo" /> --> | |
158 | 157 | <div class="app-loading-dots"> |
159 | 158 | <span class="dot dot-spin"><i></i><i></i><i></i><i></i></span> |
160 | 159 | </div> |
161 | - <div class="app-loading-title"><%= title %></div> | |
160 | + <!-- <div class="app-loading-title"><%= title %></div> --> | |
162 | 161 | </div> |
163 | 162 | </div> |
164 | 163 | </div> |
165 | - | |
164 | + | |
166 | 165 | <script type="module" src="/src/main.ts"></script> |
167 | 166 | </body> |
168 | 167 | </html> | ... | ... |
1 | 1 | import { defHttp } from '/@/utils/http/axios'; |
2 | -import { FileUploadResponse } from './model/index'; | |
2 | +import { FileUploadResponse, Platform } from './model/index'; | |
3 | 3 | enum API { |
4 | 4 | SELECT_DETAIL = '/enterprise/get', |
5 | 5 | UPDATE_DETAIL = '/enterprise/update', |
... | ... | @@ -67,7 +67,7 @@ export const bgUpload = (file) => { |
67 | 67 | |
68 | 68 | // 获取平台定制详情 |
69 | 69 | export const getPlatForm = () => { |
70 | - return defHttp.get({ | |
70 | + return defHttp.get<Platform>({ | |
71 | 71 | url: API.SELECT_PLATFORM, |
72 | 72 | }); |
73 | 73 | }; | ... | ... |
... | ... | @@ -5,3 +5,17 @@ export interface FileUploadResponse { |
5 | 5 | size: number; |
6 | 6 | fileStaticUri: string; |
7 | 7 | } |
8 | + | |
9 | +export interface Platform { | |
10 | + id: string; | |
11 | + creator: string; | |
12 | + createTime: string; | |
13 | + updater: string; | |
14 | + updateTime: string; | |
15 | + name: string; | |
16 | + logo: string; | |
17 | + background: string; | |
18 | + copyright: string; | |
19 | + presentedOurselves: string; | |
20 | + domain: string; | |
21 | +} | ... | ... |
... | ... | @@ -10,6 +10,7 @@ export { default as ApiSelect } from './src/components/ApiSelect.vue'; |
10 | 10 | export { default as RadioButtonGroup } from './src/components/RadioButtonGroup.vue'; |
11 | 11 | export { default as ApiTreeSelect } from './src/components/ApiTreeSelect.vue'; |
12 | 12 | export { default as ApiRadioGroup } from './src/components/ApiRadioGroup.vue'; |
13 | +export { default as ApiUpload } from './src/components/ApiUpload.vue'; | |
13 | 14 | |
14 | 15 | //注册自定义组件 |
15 | 16 | export { | ... | ... |
1 | +<script lang="ts"> | |
2 | + export default { | |
3 | + inheritAttrs: false, | |
4 | + }; | |
5 | +</script> | |
6 | +<script lang="ts" setup> | |
7 | + import { UploadDragger, Spin } from 'ant-design-vue'; | |
8 | + import { InboxOutlined } from '@ant-design/icons-vue'; | |
9 | + import { useMessage } from '/@/hooks/web/useMessage'; | |
10 | + import { isBoolean, isFunction } from '/@/utils/is'; | |
11 | + import { computed, ref, unref } from 'vue'; | |
12 | + import { cloneDeep } from 'lodash-es'; | |
13 | + interface FileItem { | |
14 | + uid: string; | |
15 | + name?: string; | |
16 | + status?: string; | |
17 | + response?: string; | |
18 | + url?: string; | |
19 | + } | |
20 | + | |
21 | + const emit = defineEmits(['update:fileList']); | |
22 | + | |
23 | + const { createMessage } = useMessage(); | |
24 | + | |
25 | + const loading = ref(false); | |
26 | + | |
27 | + const componentDisabled = ref(false); | |
28 | + | |
29 | + const setLoading = (spin: boolean) => { | |
30 | + loading.value = spin; | |
31 | + }; | |
32 | + | |
33 | + const props = withDefaults( | |
34 | + defineProps<{ | |
35 | + fileList?: FileItem[]; | |
36 | + accept?: string; | |
37 | + maxSize?: number; | |
38 | + disabled?: boolean; | |
39 | + listType?: string; | |
40 | + multiple?: boolean; | |
41 | + showUploadList?: boolean | { showPreviewIcon?: boolean; showRemoveIcon?: boolean }; | |
42 | + transformFile?: (file: File) => string | Blob | Promise<string | Blob | File>; | |
43 | + api: (file: string | Blob | Promise<string | Blob | File>) => Promise<FileItem>; | |
44 | + }>(), | |
45 | + { | |
46 | + fileList: () => [], | |
47 | + maxSize: 5 * 1024 * 1024, | |
48 | + showUploadList: () => ({ showPreviewIcon: true, showRemoveIcon: true }), | |
49 | + } | |
50 | + ); | |
51 | + | |
52 | + const handleBeforeUpload = (file: File) => { | |
53 | + if (file.size > props.maxSize) { | |
54 | + createMessage.warning(`文件大小超过${Math.floor(props.maxSize / 1024)}mb`); | |
55 | + return false; | |
56 | + } | |
57 | + handleUpload(file); | |
58 | + return false; | |
59 | + }; | |
60 | + | |
61 | + const getDisabled = computed(() => { | |
62 | + const { disabled } = props; | |
63 | + if (isBoolean(disabled)) { | |
64 | + return disabled ? componentDisabled.value : disabled; | |
65 | + } | |
66 | + return componentDisabled.value; | |
67 | + }); | |
68 | + | |
69 | + const handleUpload = async (file: File | string | Blob | Promise<string | Blob | File>) => { | |
70 | + try { | |
71 | + setLoading(true); | |
72 | + componentDisabled.value = true; | |
73 | + console.log({ componentDisabled: unref(componentDisabled), getDisabled: unref(getDisabled) }); | |
74 | + const { transformFile, api } = props; | |
75 | + if (transformFile && isFunction(transformFile)) file = await transformFile(file as File); | |
76 | + if (api && isFunction(api)) { | |
77 | + const data = await api(file); | |
78 | + emit('update:fileList', cloneDeep([...props.fileList, data])); | |
79 | + } | |
80 | + } catch (error) { | |
81 | + window.console.error(error); | |
82 | + } finally { | |
83 | + setLoading(false); | |
84 | + componentDisabled.value = false; | |
85 | + } | |
86 | + }; | |
87 | + | |
88 | + const handleRemove = (file: FileItem) => { | |
89 | + const _fileList = cloneDeep(props.fileList); | |
90 | + const index = _fileList.findIndex((item) => item.uid === file.uid); | |
91 | + ~index && _fileList.splice(index, 1); | |
92 | + emit('update:fileList', _fileList); | |
93 | + }; | |
94 | + | |
95 | + const handlePreview = (file: FileItem) => { | |
96 | + console.log('preview', file); | |
97 | + }; | |
98 | + | |
99 | + const handleDownload = (file: FileItem) => { | |
100 | + console.log('download', file); | |
101 | + }; | |
102 | +</script> | |
103 | + | |
104 | +<template> | |
105 | + <UploadDragger | |
106 | + :file-list="props.fileList" | |
107 | + :disabled="getDisabled" | |
108 | + :before-upload="handleBeforeUpload" | |
109 | + @preview="handlePreview" | |
110 | + @download="handleDownload" | |
111 | + :remove="handleRemove" | |
112 | + > | |
113 | + <Spin :spinning="loading"> | |
114 | + {{ getDisabled }} | |
115 | + <div class="w-full h-full flex flex-col justify-center content-center"> | |
116 | + <InboxOutlined class="text-[3rem] !text-blue-500" /> | |
117 | + <div class="m-2 text-gray-400">点击上传或拖拽上传</div> | |
118 | + </div> | |
119 | + </Spin> | |
120 | + </UploadDragger> | |
121 | +</template> | ... | ... |
... | ... | @@ -14,6 +14,7 @@ import { setupGlobDirectives } from '/@/directives'; |
14 | 14 | import { setupI18n } from '/@/locales/setupI18n'; |
15 | 15 | import { registerGlobComp } from '/@/components/registerGlobComp'; |
16 | 16 | import '/@/assets/iconfont/iconfont'; |
17 | +import { usePlatform } from './views/system/customize/hook/usePlatformInfo'; | |
17 | 18 | |
18 | 19 | if (import.meta.env.DEV) { |
19 | 20 | import('ant-design-vue/dist/antd.less'); |
... | ... | @@ -23,6 +24,8 @@ async function bootstrap() { |
23 | 24 | // Configure store |
24 | 25 | setupStore(app); |
25 | 26 | |
27 | + await usePlatform(); | |
28 | + | |
26 | 29 | // Initialize internal system configuration |
27 | 30 | initAppConfigStore(); |
28 | 31 | |
... | ... | @@ -47,6 +50,7 @@ async function bootstrap() { |
47 | 50 | // Mount when the route is ready |
48 | 51 | // https://next.router.vuejs.org/api/#isready |
49 | 52 | await router.isReady(); |
53 | + | |
50 | 54 | app.mount('#app', true); |
51 | 55 | } |
52 | 56 | ... | ... |
... | ... | @@ -39,7 +39,7 @@ |
39 | 39 | width: '200px', |
40 | 40 | height: '200px', |
41 | 41 | color: '#409eff', |
42 | - muted: false, //静音 | |
42 | + muted: true, //静音 | |
43 | 43 | webFullScreen: false, |
44 | 44 | autoPlay: true, //自动播放 |
45 | 45 | currentTime: 0, |
... | ... | @@ -238,7 +238,7 @@ |
238 | 238 | class="h-full flex flex-col justify-center items-center" |
239 | 239 | v-if="!cameraList.length" |
240 | 240 | /> |
241 | - <Row :gutter="16" class="h-full mx-0"> | |
241 | + <Row :gutter="16" class="h-full mx-0 content-start"> | |
242 | 242 | <Col |
243 | 243 | v-for="item in cameraList" |
244 | 244 | :key="item.id" | ... | ... |
1 | +<script lang="ts" setup> | |
2 | + import { BasicModal, useModalInner } from '/@/components/Modal'; | |
3 | + import { BasicForm, useForm } from '/@/components/Form'; | |
4 | + import { formSchema } from '../config/packageDetail.config'; | |
5 | + defineEmits(['register']); | |
6 | + | |
7 | + const [registerModal] = useModalInner((_record: Recordable) => {}); | |
8 | + | |
9 | + const [registerForm] = useForm({ | |
10 | + schemas: formSchema, | |
11 | + showActionButtonGroup: false, | |
12 | + // labelCol: { span: 8 }, | |
13 | + labelWidth: 100, | |
14 | + wrapperCol: { span: 16 }, | |
15 | + }); | |
16 | +</script> | |
17 | + | |
18 | +<template> | |
19 | + <BasicModal title="包管理" @register="registerModal"> | |
20 | + <BasicForm @register="registerForm" /> | |
21 | + </BasicModal> | |
22 | +</template> | ... | ... |
src/views/operation/ota/config/config.ts
0 → 100644
1 | +import { BasicColumn, FormSchema } from '/@/components/Table'; | |
2 | + | |
3 | +export const columns: BasicColumn[] = [ | |
4 | + { | |
5 | + title: '创建时间', | |
6 | + dataIndex: 'createTime', | |
7 | + width: 120, | |
8 | + }, | |
9 | + { | |
10 | + title: '标题', | |
11 | + dataIndex: 'title', | |
12 | + width: 120, | |
13 | + }, | |
14 | + { | |
15 | + title: '版本', | |
16 | + dataIndex: 'version', | |
17 | + width: 120, | |
18 | + }, | |
19 | + { | |
20 | + title: '版本标签', | |
21 | + dataIndex: 'versionLabel', | |
22 | + width: 120, | |
23 | + }, | |
24 | + { | |
25 | + title: '包类型', | |
26 | + dataIndex: 'pkgType', | |
27 | + width: 120, | |
28 | + }, | |
29 | + { | |
30 | + title: '直接URL', | |
31 | + dataIndex: 'url', | |
32 | + width: 120, | |
33 | + }, | |
34 | + { | |
35 | + title: '文件大小', | |
36 | + dataIndex: 'fileSize', | |
37 | + width: 120, | |
38 | + }, | |
39 | + { | |
40 | + title: '校验和', | |
41 | + dataIndex: 'vaildateTotal', | |
42 | + width: 120, | |
43 | + }, | |
44 | +]; | |
45 | + | |
46 | +export const searchFormSchema: FormSchema[] = [ | |
47 | + { | |
48 | + field: 'name', | |
49 | + label: '标题', | |
50 | + component: 'Input', | |
51 | + colProps: { span: 8 }, | |
52 | + }, | |
53 | +]; | ... | ... |
1 | +import { FormSchema } from '/@/components/Form'; | |
2 | + | |
3 | +export enum PackageField { | |
4 | + TITLE = 'title', | |
5 | + VERSION = 'version', | |
6 | + VERSION_LABEL = 'versionLabel', | |
7 | + DEVICE_CONFIGURATION = 'deviceConfiguration', | |
8 | + PACKAGE_TYPE = 'packageType', | |
9 | + PACKAGE_UPDATE_TYPE = 'PackageUpdateType', | |
10 | + PACKAGE_BINARY_FILE = 'packageBinaryFile', | |
11 | + PACKAGE_EXTERNAL_URL = 'packageEexternalUrl', | |
12 | + CHECK_SUM_WAY = 'checkSumWay', | |
13 | + ALG = 'alg', | |
14 | + CHECK_SUM = 'checkSum', | |
15 | + DESCRIPTION = 'description', | |
16 | +} | |
17 | + | |
18 | +export enum PackageUpdateType { | |
19 | + BINARY_FILE = 'binaryFile', | |
20 | + EXTERNAL_URL = 'externalUrl', | |
21 | +} | |
22 | + | |
23 | +export enum PackageType { | |
24 | + FIRMWARE = 'firmware', | |
25 | + SOFTWARE = 'software', | |
26 | +} | |
27 | + | |
28 | +export enum CheckSumWay { | |
29 | + AUTO = 'auto', | |
30 | + MANUAL = 'manual', | |
31 | +} | |
32 | + | |
33 | +export enum ALG { | |
34 | + MD5 = 'md5', | |
35 | + SHA_256 = 'sha-256', | |
36 | + SHA_384 = 'sha-384', | |
37 | + SHA_512 = 'sha-512', | |
38 | + CRC_32 = 'crc-32', | |
39 | + MURMUR3_32 = 'murmur3-32', | |
40 | + MURMUR3_128 = 'murmur3-128', | |
41 | +} | |
42 | + | |
43 | +export const formSchema: FormSchema[] = [ | |
44 | + { | |
45 | + field: PackageField.TITLE, | |
46 | + label: '标题', | |
47 | + component: 'Input', | |
48 | + rules: [{ required: true, message: '标题为必填项' }], | |
49 | + componentProps: { | |
50 | + placeholder: '请输入标题', | |
51 | + }, | |
52 | + }, | |
53 | + { | |
54 | + field: PackageField.VERSION, | |
55 | + label: '版本', | |
56 | + component: 'Input', | |
57 | + rules: [{ required: true, message: '版本为必填项' }], | |
58 | + componentProps: { | |
59 | + placeholder: '请输入版本', | |
60 | + }, | |
61 | + }, | |
62 | + { | |
63 | + field: PackageField.VERSION_LABEL, | |
64 | + label: '版本标签', | |
65 | + component: 'Input', | |
66 | + helpMessage: ['自定义标签应与您设备报告的软件包版本相匹配'], | |
67 | + componentProps: { | |
68 | + placeholder: '请输入版本标签', | |
69 | + }, | |
70 | + }, | |
71 | + { | |
72 | + field: PackageField.DEVICE_CONFIGURATION, | |
73 | + label: '设备配置', | |
74 | + component: 'Select', | |
75 | + helpMessage: ['上传的包仅适用于具有所选配置文件的设备'], | |
76 | + defaultValue: 'default', | |
77 | + rules: [{ required: true, message: '设备配置为必填项' }], | |
78 | + componentProps: () => { | |
79 | + return { | |
80 | + options: [{ label: 'default', value: 'default' }], | |
81 | + placeholder: '请选择设备配置', | |
82 | + }; | |
83 | + }, | |
84 | + }, | |
85 | + { | |
86 | + field: PackageField.PACKAGE_TYPE, | |
87 | + label: '包类型', | |
88 | + component: 'Select', | |
89 | + helpMessage: ['上传包后,您将无法修改标题、版本、设备配置文件和包类型'], | |
90 | + defaultValue: PackageType.FIRMWARE, | |
91 | + rules: [{ required: true, message: '包类型为必填项' }], | |
92 | + componentProps: () => { | |
93 | + return { | |
94 | + options: [ | |
95 | + { label: '固件', value: PackageType.FIRMWARE }, | |
96 | + { label: '软件', value: PackageType.SOFTWARE }, | |
97 | + ], | |
98 | + placeholder: '请选择设备配置', | |
99 | + }; | |
100 | + }, | |
101 | + }, | |
102 | + { | |
103 | + field: PackageField.PACKAGE_UPDATE_TYPE, | |
104 | + label: '上传方式', | |
105 | + component: 'RadioGroup', | |
106 | + defaultValue: PackageUpdateType.BINARY_FILE, | |
107 | + componentProps: () => { | |
108 | + return { | |
109 | + options: [ | |
110 | + { label: '上传二进制文件', value: PackageUpdateType.BINARY_FILE }, | |
111 | + { label: '使用外部URL', value: PackageUpdateType.EXTERNAL_URL }, | |
112 | + ], | |
113 | + }; | |
114 | + }, | |
115 | + }, | |
116 | + { | |
117 | + field: PackageField.PACKAGE_BINARY_FILE, | |
118 | + label: '二进制文件', | |
119 | + ifShow: ({ model }) => { | |
120 | + return model[PackageField.PACKAGE_UPDATE_TYPE] === PackageUpdateType.BINARY_FILE; | |
121 | + }, | |
122 | + component: 'Upload', | |
123 | + componentProps: { | |
124 | + api: () => { | |
125 | + return {}; | |
126 | + }, | |
127 | + }, | |
128 | + }, | |
129 | + { | |
130 | + field: PackageField.PACKAGE_EXTERNAL_URL, | |
131 | + label: '外部URL', | |
132 | + component: 'Input', | |
133 | + ifShow: ({ model }) => { | |
134 | + return model[PackageField.PACKAGE_UPDATE_TYPE] === PackageUpdateType.EXTERNAL_URL; | |
135 | + }, | |
136 | + rules: [{ required: true, message: '外部URL为必填项' }], | |
137 | + componentProps: { | |
138 | + placeholder: '请输入外部URL', | |
139 | + }, | |
140 | + }, | |
141 | + { | |
142 | + field: PackageField.CHECK_SUM_WAY, | |
143 | + label: '校验和方式', | |
144 | + component: 'RadioGroup', | |
145 | + defaultValue: CheckSumWay.AUTO, | |
146 | + componentProps: () => { | |
147 | + return { | |
148 | + options: [ | |
149 | + { label: '自动生成', value: CheckSumWay.AUTO }, | |
150 | + { label: '手动生成', value: CheckSumWay.MANUAL }, | |
151 | + ], | |
152 | + }; | |
153 | + }, | |
154 | + }, | |
155 | + { | |
156 | + field: PackageField.ALG, | |
157 | + label: '校验和算法', | |
158 | + component: 'Select', | |
159 | + ifShow: ({ model }) => { | |
160 | + return model[PackageField.CHECK_SUM_WAY] === CheckSumWay.MANUAL; | |
161 | + }, | |
162 | + componentProps: { | |
163 | + placeholder: '请选择校验和算法', | |
164 | + options: Object.keys(ALG).map((key) => { | |
165 | + return { | |
166 | + label: String(ALG[key]).toUpperCase(), | |
167 | + value: ALG[key], | |
168 | + }; | |
169 | + }), | |
170 | + }, | |
171 | + }, | |
172 | + { | |
173 | + field: PackageField.CHECK_SUM, | |
174 | + label: '校验和', | |
175 | + component: 'Input', | |
176 | + ifShow: ({ model }) => { | |
177 | + return model[PackageField.CHECK_SUM_WAY] === CheckSumWay.MANUAL; | |
178 | + }, | |
179 | + helpMessage: ['如果校验和为空,会自动生成'], | |
180 | + componentProps: { | |
181 | + placeholder: '请输入校验和', | |
182 | + }, | |
183 | + }, | |
184 | + { | |
185 | + field: PackageField.DESCRIPTION, | |
186 | + label: '描述', | |
187 | + component: 'InputTextArea', | |
188 | + componentProps: { | |
189 | + placeholder: '请输入描述', | |
190 | + }, | |
191 | + }, | |
192 | +]; | ... | ... |
src/views/operation/ota/index.vue
0 → 100644
1 | +<script lang="ts" setup> | |
2 | + import { Button } from 'ant-design-vue'; | |
3 | + import { columns, searchFormSchema } from './config/config'; | |
4 | + import { PageWrapper } from '/@/components/Page'; | |
5 | + import { BasicTable, useTable } from '/@/components/Table'; | |
6 | + import PackageDetailModal from './components/PackageDetailModal.vue'; | |
7 | + import { useModal } from '/@/components/Modal'; | |
8 | + // import { ApiUpload } from '/@/components/Form'; | |
9 | + // import { computed, ref, unref } from 'vue'; | |
10 | + | |
11 | + const [register] = useTable({ | |
12 | + columns, | |
13 | + title: '包仓库', | |
14 | + formConfig: { | |
15 | + labelWidth: 120, | |
16 | + schemas: searchFormSchema, | |
17 | + }, | |
18 | + useSearchForm: true, | |
19 | + showTableSetting: true, | |
20 | + }); | |
21 | + | |
22 | + const [registerModal, { openModal }] = useModal(); | |
23 | + | |
24 | + const handleCreatePackage = () => { | |
25 | + openModal(true); | |
26 | + }; | |
27 | + | |
28 | + // const fileList = ref([]); | |
29 | + // const handleUpload = async (file: File) => { | |
30 | + // console.log(file); | |
31 | + // return new Promise((resolve) => { | |
32 | + // setTimeout(() => { | |
33 | + // resolve({ | |
34 | + // uid: file.uid, | |
35 | + // type: file.type, | |
36 | + // name: file.name, | |
37 | + // linkProps: { download: 'http://www.baidu.cn' }, | |
38 | + // }); | |
39 | + // }, 3000); | |
40 | + // }); | |
41 | + // }; | |
42 | +</script> | |
43 | + | |
44 | +<template> | |
45 | + <PageWrapper dense contentFullHeight contentClass="flex flex-col"> | |
46 | + <!-- <div class="w-40 h-40"> | |
47 | + <ApiUpload v-model:file-list="fileList" :api="handleUpload" /> | |
48 | + </div> --> | |
49 | + <BasicTable @register="register"> | |
50 | + <template #toolbar> | |
51 | + <Button @click="handleCreatePackage" type="primary">新增包</Button> | |
52 | + </template> | |
53 | + </BasicTable> | |
54 | + <PackageDetailModal @register="registerModal" /> | |
55 | + </PageWrapper> | |
56 | +</template> | ... | ... |
... | ... | @@ -6,149 +6,161 @@ |
6 | 6 | <a-button type="primary" @click="handleAdd"> 新增场景联动 </a-button> |
7 | 7 | </Authority> |
8 | 8 | <Authority value="api:yt:sceneLinkage:delete"> |
9 | - <Popconfirm title="您确定要批量删除数据" ok-text="确定" cancel-text="取消" @confirm="handleDeleteOrBatchDelete(null)"> | |
9 | + <Popconfirm | |
10 | + title="您确定要批量删除数据" | |
11 | + ok-text="确定" | |
12 | + cancel-text="取消" | |
13 | + @confirm="handleDeleteOrBatchDelete(null)" | |
14 | + > | |
10 | 15 | <a-button color="error" :disabled="hasBatchDelete"> 批量删除 </a-button> |
11 | 16 | </Popconfirm> |
12 | 17 | </Authority> |
13 | 18 | </template> |
14 | 19 | <template #action="{ record }"> |
15 | - <TableAction :actions="[ | |
16 | - { | |
17 | - label: '查看', | |
18 | - auth: 'api:yt:sceneLinkage:get', | |
19 | - icon: 'ant-design:eye-outlined', | |
20 | - onClick: handleView.bind(null, record), | |
21 | - }, | |
22 | - { | |
23 | - label: '编辑', | |
24 | - auth: 'api:yt:sceneLinkage:update', | |
25 | - icon: 'clarity:note-edit-line', | |
26 | - onClick: handleEdit.bind(null, record), | |
27 | - ifShow: record.creator === userId && record.status !== 1, | |
28 | - }, | |
29 | - { | |
30 | - label: '删除', | |
31 | - auth: 'api:yt:sceneLinkage:delete', | |
32 | - icon: 'ant-design:delete-outlined', | |
33 | - color: 'error', | |
34 | - ifShow: record.creator === userId && record.status !== 1, | |
35 | - popConfirm: { | |
36 | - title: '是否确认删除', | |
37 | - confirm: handleDeleteOrBatchDelete.bind(null, record), | |
20 | + <TableAction | |
21 | + :actions="[ | |
22 | + { | |
23 | + label: '查看', | |
24 | + auth: 'api:yt:sceneLinkage:get', | |
25 | + icon: 'ant-design:eye-outlined', | |
26 | + onClick: handleView.bind(null, record), | |
38 | 27 | }, |
39 | - }, | |
40 | - ]" /> | |
28 | + { | |
29 | + label: '编辑', | |
30 | + auth: 'api:yt:sceneLinkage:update', | |
31 | + icon: 'clarity:note-edit-line', | |
32 | + onClick: handleEdit.bind(null, record), | |
33 | + ifShow: record.creator === userId && record.status !== 1, | |
34 | + }, | |
35 | + { | |
36 | + label: '删除', | |
37 | + auth: 'api:yt:sceneLinkage:delete', | |
38 | + icon: 'ant-design:delete-outlined', | |
39 | + color: 'error', | |
40 | + ifShow: record.creator === userId && record.status !== 1, | |
41 | + popConfirm: { | |
42 | + title: '是否确认删除', | |
43 | + confirm: handleDeleteOrBatchDelete.bind(null, record), | |
44 | + }, | |
45 | + }, | |
46 | + ]" | |
47 | + /> | |
41 | 48 | </template> |
42 | 49 | |
43 | 50 | <template #status="{ record }"> |
44 | - <Switch :checked="record.status === 1" :loading="record.pendingStatus" checkedChildren="启用" | |
45 | - unCheckedChildren="禁用" @change="(checked:boolean)=>statusChange(checked,record)" /> | |
51 | + <Switch | |
52 | + :checked="record.status === 1" | |
53 | + :loading="record.pendingStatus" | |
54 | + checkedChildren="启用" | |
55 | + unCheckedChildren="禁用" | |
56 | + @change="(checked:boolean)=>statusChange(checked,record)" | |
57 | + /> | |
46 | 58 | </template> |
47 | 59 | </BasicTable> |
48 | 60 | <SceneLinkAgeDrawer @register="registerDrawer" @success="handleSuccess" /> |
49 | 61 | </div> |
50 | 62 | </template> |
51 | 63 | <script lang="ts" setup> |
52 | -import { nextTick } from 'vue'; | |
53 | -import { BasicTable, useTable, TableAction } from '/@/components/Table'; | |
54 | -import { useDrawer } from '/@/components/Drawer'; | |
55 | -import { | |
56 | - screenLinkPageGetApi, | |
57 | - screenLinkPageDeleteApi, | |
58 | - screenLinkPagePutApi, | |
59 | -} from '/@/api/ruleengine/ruleengineApi'; | |
60 | -import { useBatchDelete } from '/@/hooks/web/useBatchDelete'; | |
61 | -import { Switch, Popconfirm } from 'ant-design-vue'; | |
62 | -import { columns, searchFormSchema } from './config/config.data.ts'; | |
63 | -import { USER_INFO_KEY } from '/@/enums/cacheEnum'; | |
64 | -import { getAuthCache } from '/@/utils/auth'; | |
65 | -import SceneLinkAgeDrawer from './SceneLinkAgeDrawer.vue'; | |
66 | -import { useMessage } from '/@/hooks/web/useMessage'; | |
67 | -import { Authority } from '/@/components/Authority'; | |
68 | - | |
69 | -const userInfo: any = getAuthCache(USER_INFO_KEY); | |
70 | -const userId = userInfo.userId; | |
64 | + import { nextTick } from 'vue'; | |
65 | + import { BasicTable, useTable, TableAction } from '/@/components/Table'; | |
66 | + import { useDrawer } from '/@/components/Drawer'; | |
67 | + import { | |
68 | + screenLinkPageGetApi, | |
69 | + screenLinkPageDeleteApi, | |
70 | + screenLinkPagePutApi, | |
71 | + } from '/@/api/ruleengine/ruleengineApi'; | |
72 | + import { useBatchDelete } from '/@/hooks/web/useBatchDelete'; | |
73 | + import { Switch, Popconfirm } from 'ant-design-vue'; | |
74 | + import { columns, searchFormSchema } from './config/config.data'; | |
75 | + import { USER_INFO_KEY } from '/@/enums/cacheEnum'; | |
76 | + import { getAuthCache } from '/@/utils/auth'; | |
77 | + import SceneLinkAgeDrawer from './SceneLinkAgeDrawer.vue'; | |
78 | + import { useMessage } from '/@/hooks/web/useMessage'; | |
79 | + import { Authority } from '/@/components/Authority'; | |
71 | 80 | |
72 | -const [registerDrawer, { openDrawer }] = useDrawer(); | |
73 | -const [registerTable, { reload, setProps, setSelectedRowKeys }] = useTable({ | |
74 | - title: '场景联动列表', | |
75 | - api: screenLinkPageGetApi, | |
76 | - columns, | |
77 | - formConfig: { | |
78 | - labelWidth: 120, | |
79 | - schemas: searchFormSchema, | |
80 | - }, | |
81 | - useSearchForm: true, | |
82 | - showTableSetting: true, | |
83 | - bordered: true, | |
84 | - showIndexColumn: false, | |
85 | - actionColumn: { | |
86 | - width: 200, | |
87 | - title: '操作', | |
88 | - dataIndex: 'action', | |
89 | - slots: { customRender: 'action' }, | |
90 | - fixed: 'right', | |
91 | - }, | |
92 | -}); | |
93 | -const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions, resetSelectedRowKeys } = | |
94 | - useBatchDelete(screenLinkPageDeleteApi, handleSuccess, setProps); | |
95 | -selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => { | |
96 | - // Demo:status为1的选择框禁用 | |
97 | - if (record.status === 1) { | |
98 | - return { disabled: true }; | |
99 | - } else { | |
100 | - return { disabled: false }; | |
101 | - } | |
102 | -}; | |
103 | -nextTick(() => { | |
104 | - setProps(selectionOptions); | |
105 | -}); | |
106 | - | |
107 | -function handleAdd() { | |
108 | - window.localStorage.setItem('isViewDisabledBtn', 'noView') | |
109 | - openDrawer(true, { | |
110 | - isUpdate: false, | |
111 | - }); | |
112 | -} | |
81 | + const userInfo: any = getAuthCache(USER_INFO_KEY); | |
82 | + const userId = userInfo.userId; | |
113 | 83 | |
114 | -function handleEdit(record: Recordable) { | |
115 | - window.localStorage.setItem('isViewDisabledBtn', 'noView') | |
116 | - openDrawer(true, { | |
117 | - record, | |
118 | - isUpdate: true, | |
84 | + const [registerDrawer, { openDrawer }] = useDrawer(); | |
85 | + const [registerTable, { reload, setProps, setSelectedRowKeys }] = useTable({ | |
86 | + title: '场景联动列表', | |
87 | + api: screenLinkPageGetApi, | |
88 | + columns, | |
89 | + formConfig: { | |
90 | + labelWidth: 120, | |
91 | + schemas: searchFormSchema, | |
92 | + }, | |
93 | + useSearchForm: true, | |
94 | + showTableSetting: true, | |
95 | + bordered: true, | |
96 | + showIndexColumn: false, | |
97 | + actionColumn: { | |
98 | + width: 200, | |
99 | + title: '操作', | |
100 | + dataIndex: 'action', | |
101 | + slots: { customRender: 'action' }, | |
102 | + fixed: 'right', | |
103 | + }, | |
119 | 104 | }); |
120 | -} | |
121 | -function handleView(record: Recordable) { | |
122 | - window.localStorage.setItem('isViewDisabledBtn', 'isView') | |
123 | - openDrawer(true, { | |
124 | - record, | |
125 | - isUpdate: 3, | |
126 | - }); | |
127 | -} | |
128 | -function handleSuccess() { | |
129 | - reload(); | |
130 | -} | |
131 | - | |
132 | -const statusChange = async (checked, record) => { | |
133 | - setProps({ | |
134 | - loading: true, | |
135 | - }); | |
136 | - setSelectedRowKeys([]); | |
137 | - resetSelectedRowKeys(); | |
138 | - const newStatus = checked ? 1 : 0; | |
139 | - const { createMessage } = useMessage(); | |
140 | - try { | |
141 | - await screenLinkPagePutApi({ id: record.id, status: newStatus }); | |
142 | - if (newStatus) { | |
143 | - createMessage.success(`启用成功`); | |
105 | + const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions, resetSelectedRowKeys } = | |
106 | + useBatchDelete(screenLinkPageDeleteApi, handleSuccess, setProps); | |
107 | + selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => { | |
108 | + // Demo:status为1的选择框禁用 | |
109 | + if (record.status === 1) { | |
110 | + return { disabled: true }; | |
144 | 111 | } else { |
145 | - createMessage.success('禁用成功'); | |
112 | + return { disabled: false }; | |
146 | 113 | } |
147 | - } finally { | |
148 | - setProps({ | |
149 | - loading: false, | |
114 | + }; | |
115 | + nextTick(() => { | |
116 | + setProps(selectionOptions); | |
117 | + }); | |
118 | + | |
119 | + function handleAdd() { | |
120 | + window.localStorage.setItem('isViewDisabledBtn', 'noView'); | |
121 | + openDrawer(true, { | |
122 | + isUpdate: false, | |
123 | + }); | |
124 | + } | |
125 | + | |
126 | + function handleEdit(record: Recordable) { | |
127 | + window.localStorage.setItem('isViewDisabledBtn', 'noView'); | |
128 | + openDrawer(true, { | |
129 | + record, | |
130 | + isUpdate: true, | |
131 | + }); | |
132 | + } | |
133 | + function handleView(record: Recordable) { | |
134 | + window.localStorage.setItem('isViewDisabledBtn', 'isView'); | |
135 | + openDrawer(true, { | |
136 | + record, | |
137 | + isUpdate: 3, | |
150 | 138 | }); |
139 | + } | |
140 | + function handleSuccess() { | |
151 | 141 | reload(); |
152 | 142 | } |
153 | -}; | |
143 | + | |
144 | + const statusChange = async (checked, record) => { | |
145 | + setProps({ | |
146 | + loading: true, | |
147 | + }); | |
148 | + setSelectedRowKeys([]); | |
149 | + resetSelectedRowKeys(); | |
150 | + const newStatus = checked ? 1 : 0; | |
151 | + const { createMessage } = useMessage(); | |
152 | + try { | |
153 | + await screenLinkPagePutApi({ id: record.id, status: newStatus }); | |
154 | + if (newStatus) { | |
155 | + createMessage.success(`启用成功`); | |
156 | + } else { | |
157 | + createMessage.success('禁用成功'); | |
158 | + } | |
159 | + } finally { | |
160 | + setProps({ | |
161 | + loading: false, | |
162 | + }); | |
163 | + reload(); | |
164 | + } | |
165 | + }; | |
154 | 166 | </script> | ... | ... |
1 | +import { getPlatForm } from '/@/api/oem'; | |
2 | + | |
3 | +enum DefaultPlatform { | |
4 | + LOGO = '/resource/img/logo.png', | |
5 | + // TITLE = 'ThingsKit', | |
6 | + ICO = '/favicon.ico', | |
7 | +} | |
8 | + | |
9 | +export const usePlatform = async () => { | |
10 | + const platformInfo = await getPlatForm(); | |
11 | + | |
12 | + const createLoadingEffect = () => { | |
13 | + const wrap = document.createElement('div'); | |
14 | + wrap.setAttribute('class', 'app-loading-wrap'); | |
15 | + const img = document.createElement('img'); | |
16 | + img.setAttribute('src', platformInfo.logo || DefaultPlatform.LOGO); | |
17 | + img.setAttribute('class', 'app-loading-logo'); | |
18 | + img.setAttribute('alt', 'Logo'); | |
19 | + const dots = document.createElement('div'); | |
20 | + dots.setAttribute('class', 'app-loading-dots'); | |
21 | + const dotWrap = document.createElement('span'); | |
22 | + dotWrap.setAttribute('class', 'dot dot-spin'); | |
23 | + for (let i = 0; i < 4; i++) { | |
24 | + dotWrap.appendChild(document.createElement('i')); | |
25 | + } | |
26 | + const title = document.createElement('div'); | |
27 | + title.setAttribute('class', 'app-loading-title'); | |
28 | + const textNode = document.createTextNode( | |
29 | + platformInfo.name || import.meta.env.VITE_GLOB_APP_TITLE | |
30 | + ); | |
31 | + title.appendChild(textNode); | |
32 | + wrap.appendChild(img); | |
33 | + dots.appendChild(dotWrap); | |
34 | + wrap.appendChild(dots); | |
35 | + wrap.appendChild(title); | |
36 | + return wrap; | |
37 | + }; | |
38 | + | |
39 | + const replaceSiteIco = () => { | |
40 | + const linkEl = document.querySelectorAll('link[rel*="icon"]'); | |
41 | + linkEl.forEach((item) => { | |
42 | + item.setAttribute('href', platformInfo.logo || DefaultPlatform.ICO); | |
43 | + }); | |
44 | + }; | |
45 | + | |
46 | + const replaceLoadingEffect = () => { | |
47 | + const loadingWrapper = document.getElementById('first-screen-loading'); | |
48 | + loadingWrapper!.innerHTML = ''; | |
49 | + loadingWrapper?.appendChild(createLoadingEffect()); | |
50 | + }; | |
51 | + | |
52 | + const bootstrap = () => { | |
53 | + replaceSiteIco(); | |
54 | + replaceLoadingEffect(); | |
55 | + }; | |
56 | + | |
57 | + bootstrap(); | |
58 | +}; | ... | ... |
src/views/visual/board/components/ControlComponent/SlidingSwitch.vue
renamed from
src/views/visual/board/components/Other/SlidingSwitch.vue
1 | +<script lang="ts"> | |
2 | + export default { | |
3 | + inheritAttrs: false, | |
4 | + }; | |
5 | +</script> | |
1 | 6 | <script lang="ts" setup> |
2 | - const props = defineProps<{ | |
3 | - value?: boolean; | |
4 | - }>(); | |
7 | + import { RadioRecord } from '../../detail/config/util'; | |
8 | + | |
9 | + interface VisualComponentProps<Layout = Recordable, Value = Recordable> { | |
10 | + value?: Value; | |
11 | + layout?: Layout; | |
12 | + radio?: RadioRecord; | |
13 | + random?: boolean; | |
14 | + add?: (key: string, method: Fn) => void; | |
15 | + update?: () => void; | |
16 | + remove?: (key: string) => void; | |
17 | + } | |
18 | + const props = defineProps<VisualComponentProps>(); | |
5 | 19 | |
6 | 20 | const emit = defineEmits(['update:value', 'change']); |
7 | 21 | |
... | ... | @@ -14,7 +28,12 @@ |
14 | 28 | |
15 | 29 | <template> |
16 | 30 | <label class="sliding-switch"> |
17 | - <input :value="props.value" type="checkbox" :checked="props.value" @change="handleChange" /> | |
31 | + <input | |
32 | + :value="props.value?.value" | |
33 | + type="checkbox" | |
34 | + :checked="props.value?.value" | |
35 | + @change="handleChange" | |
36 | + /> | |
18 | 37 | <span class="slider"></span> |
19 | 38 | <span class="on">ON</span> |
20 | 39 | <span class="off">OFF</span> |
... | ... | @@ -40,12 +59,9 @@ |
40 | 59 | .slider { |
41 | 60 | width: 80px; |
42 | 61 | height: 40px; |
62 | + display: flex; | |
63 | + align-items: center; | |
43 | 64 | box-sizing: border-box; |
44 | - position: absolute; | |
45 | - top: 0; | |
46 | - left: 0; | |
47 | - right: 0; | |
48 | - bottom: 0; | |
49 | 65 | border: 2px solid #ecf0f3; |
50 | 66 | border-radius: 20px; |
51 | 67 | box-shadow: -2px -2px 8px #fff, -2px -2px 12px hsl(0deg 0% 100% / 50%), |
... | ... | @@ -57,15 +73,14 @@ |
57 | 73 | } |
58 | 74 | |
59 | 75 | .slider::after { |
60 | - position: absolute; | |
61 | 76 | cursor: pointer; |
62 | 77 | display: block; |
63 | 78 | content: ''; |
64 | 79 | width: 24px; |
65 | 80 | height: 24px; |
66 | 81 | border-radius: 50%; |
67 | - top: 6px; | |
68 | - left: 6px; | |
82 | + margin-left: 6px; | |
83 | + margin-right: 6px; | |
69 | 84 | background-color: #ecf0f3; |
70 | 85 | box-shadow: -2px -2px 8px #fff, -2px -2px 12px hsl(0deg 0% 100% / 50%), |
71 | 86 | inset 2px 2px 4px hsl(0deg 0% 100% / 10%), 2px 2px 8px rgb(0 0 0 / 30%); |
... | ... | @@ -80,13 +95,16 @@ |
80 | 95 | input:checked ~ .slider::after { |
81 | 96 | transform: translateX(35px); |
82 | 97 | } |
98 | + | |
83 | 99 | input:not(:checked) ~ .on { |
84 | 100 | opacity: 0; |
85 | - transform: translateX(0px); | |
101 | + transform: translateX(0); | |
86 | 102 | } |
87 | 103 | |
88 | 104 | .on, |
89 | 105 | .off { |
106 | + position: absolute; | |
107 | + top: 0; | |
90 | 108 | display: inline-block; |
91 | 109 | margin-left: 3px; |
92 | 110 | width: 34px; |
... | ... | @@ -97,7 +115,9 @@ |
97 | 115 | .on { |
98 | 116 | color: #039be5; |
99 | 117 | } |
118 | + | |
100 | 119 | .off { |
120 | + right: 6px; | |
101 | 121 | color: #999; |
102 | 122 | } |
103 | 123 | } | ... | ... |
1 | +<script lang="ts"> | |
2 | + export default { | |
3 | + inheritAttrs: false, | |
4 | + }; | |
5 | +</script> | |
6 | +<script lang="ts" setup> | |
7 | + import { Switch } from 'ant-design-vue'; | |
8 | + import { computed } from 'vue'; | |
9 | + import { DEFAULT_RADIO_RECORD, fontSize, RadioRecord } from '../../detail/config/util'; | |
10 | + import SvgIcon from '/@/components/Icon/src/SvgIcon.vue'; | |
11 | + import { | |
12 | + ControlComponentDefaultConfig, | |
13 | + ControlComponentValue, | |
14 | + ControlComponentLayout, | |
15 | + } from './control.config'; | |
16 | + const props = withDefaults( | |
17 | + defineProps<{ | |
18 | + layout?: ControlComponentLayout; | |
19 | + value?: ControlComponentValue; | |
20 | + radio?: RadioRecord; | |
21 | + }>(), | |
22 | + { | |
23 | + value: () => ControlComponentDefaultConfig, | |
24 | + } | |
25 | + ); | |
26 | + const getRadio = computed(() => { | |
27 | + return props.radio || DEFAULT_RADIO_RECORD; | |
28 | + }); | |
29 | +</script> | |
30 | + | |
31 | +<template> | |
32 | + <div class="flex items-center w-full h-full p-4"> | |
33 | + <div class="flex-auto flex truncate"> | |
34 | + <SvgIcon | |
35 | + :name="props.value?.icon! || ControlComponentDefaultConfig.icon!" | |
36 | + prefix="iconfont" | |
37 | + :style="{ | |
38 | + color: props.value?.iconColor || ControlComponentDefaultConfig.iconColor, | |
39 | + width: fontSize({ radioRecord: getRadio, basic: 30, min: 16 }), | |
40 | + height: fontSize({ radioRecord: getRadio, basic: 30, min: 16 }), | |
41 | + }" | |
42 | + /> | |
43 | + <span class="flex-auto mx-4 flex items-center truncate inline-block">属性名</span> | |
44 | + </div> | |
45 | + <Switch /> | |
46 | + </div> | |
47 | +</template> | ... | ... |
src/views/visual/board/components/ControlComponent/ToggleSwitch.vue
renamed from
src/views/visual/board/components/Other/ToggleSwitch.vue
1 | +<script lang="ts"> | |
2 | + export default { | |
3 | + inheritAttrs: false, | |
4 | + }; | |
5 | +</script> | |
1 | 6 | <script lang="ts" setup> |
7 | + import { computed } from '@vue/reactivity'; | |
8 | + import { DEFAULT_RADIO_RECORD, fontSize, RadioRecord } from '../../detail/config/util'; | |
9 | + import { ControlComponentValue } from './control.config'; | |
10 | + | |
2 | 11 | const props = defineProps<{ |
3 | - value?: boolean; | |
12 | + value?: ControlComponentValue; | |
13 | + layout?: Recordable; | |
14 | + radio?: RadioRecord; | |
4 | 15 | }>(); |
5 | 16 | |
6 | 17 | const emit = defineEmits(['update:value', 'change']); |
... | ... | @@ -10,12 +21,27 @@ |
10 | 21 | emit('update:value', _value); |
11 | 22 | emit('change', _value); |
12 | 23 | }; |
24 | + | |
25 | + const getRadio = computed(() => { | |
26 | + return props.radio! || DEFAULT_RADIO_RECORD; | |
27 | + }); | |
13 | 28 | </script> |
14 | 29 | |
15 | 30 | <template> |
16 | - <div class="toggle-switch"> | |
31 | + <div | |
32 | + class="toggle-switch" | |
33 | + :style="{ | |
34 | + width: fontSize({ radioRecord: getRadio, basic: 75, max: 75, min: 60 }), | |
35 | + height: fontSize({ radioRecord: getRadio, basic: 97.5, max: 97.5, min: 80 }), | |
36 | + }" | |
37 | + > | |
17 | 38 | <label class="switch"> |
18 | - <input :value="props.value" type="checkbox" :checked="props.value" @change="handleChange" /> | |
39 | + <input | |
40 | + :value="props.value?.value" | |
41 | + type="checkbox" | |
42 | + :checked="props.value?.value" | |
43 | + @change="handleChange" | |
44 | + /> | |
19 | 45 | <div class="button"> |
20 | 46 | <div class="light"></div> |
21 | 47 | <div class="dots"></div> |
... | ... | @@ -29,9 +55,10 @@ |
29 | 55 | |
30 | 56 | <style scoped> |
31 | 57 | .toggle-switch { |
32 | - flex: 1 1 auto; | |
58 | + /* flex: 1 1 auto; */ | |
33 | 59 | max-width: 75px; |
34 | - height: 97.5px; | |
60 | + | |
61 | + /* height: 97.5px; */ | |
35 | 62 | display: flex; |
36 | 63 | } |
37 | 64 | |
... | ... | @@ -76,12 +103,12 @@ |
76 | 103 | transform-origin: center center -20px; |
77 | 104 | transform: translateZ(20px) rotateX(-25deg); |
78 | 105 | transform-style: preserve-3d; |
79 | - background-color: #9b0621; | |
80 | 106 | width: 100%; |
81 | 107 | height: 100%; |
82 | 108 | position: relative; |
83 | 109 | cursor: pointer; |
84 | 110 | background: linear-gradient(#980000 0%, #6f0000 30%, #6f0000 70%, #980000 100%); |
111 | + background-color: #9b0621; | |
85 | 112 | background-repeat: no-repeat; |
86 | 113 | } |
87 | 114 | |
... | ... | @@ -113,7 +140,7 @@ |
113 | 140 | transform: translateY(30px) rotateX(-90deg); |
114 | 141 | position: absolute; |
115 | 142 | bottom: 0; |
116 | - box-shadow: 0 30px 8px 0px black, 0 60px 20px 0px rgb(0 0 0 / 50%); | |
143 | + box-shadow: 0 30px 8px 0 black, 0 60px 20px 0 rgb(0 0 0 / 50%); | |
117 | 144 | } |
118 | 145 | |
119 | 146 | .switch .light { | ... | ... |
1 | +import { DataComponentRecord, DataSource } from '/@/api/dataBoard/model'; | |
2 | + | |
3 | +export interface ControlComponentLayout { | |
4 | + [key: string]: any; | |
5 | +} | |
6 | + | |
7 | +export interface ControlComponentValue { | |
8 | + value?: boolean; | |
9 | + name?: string; | |
10 | + icon?: string; | |
11 | + iconColor?: string; | |
12 | +} | |
13 | + | |
14 | +export const ControlComponentDefaultConfig: ControlComponentValue = { | |
15 | + icon: 'shuiwen', | |
16 | + iconColor: '#367BFF', | |
17 | +}; | |
18 | + | |
19 | +export const transformControlConfig = ( | |
20 | + _ComponentConfig: Recordable, | |
21 | + _record: DataComponentRecord, | |
22 | + dataSourceRecord: DataSource | |
23 | +) => { | |
24 | + return { | |
25 | + value: { | |
26 | + value: dataSourceRecord.componentInfo.value, | |
27 | + icon: dataSourceRecord.componentInfo.icon, | |
28 | + } as ControlComponentValue, | |
29 | + }; | |
30 | +}; | ... | ... |
1 | +<script lang="ts"> | |
2 | + export default { | |
3 | + inheritAttrs: false, | |
4 | + }; | |
5 | +</script> | |
1 | 6 | <script lang="ts" setup> |
2 | 7 | import type { ECharts, EChartsOption } from 'echarts'; |
3 | 8 | import { PropType, watch } from 'vue'; |
... | ... | @@ -7,21 +12,21 @@ |
7 | 12 | DashboardComponentLayout, |
8 | 13 | DashBoardValue, |
9 | 14 | instrumentComponent1, |
10 | - InstrumentComponentType, | |
11 | 15 | update_instrument_1_font, |
12 | 16 | update_instrument_2_font, |
13 | 17 | update_instrument_1_value, |
14 | 18 | update_instrument_2_value, |
15 | 19 | } from './dashBoardComponent.config'; |
16 | - import { dateUtil } from '/@/utils/dateUtil'; | |
17 | 20 | import { |
18 | 21 | DEFAULT_RADIO_RECORD, |
19 | 22 | RadioRecord, |
20 | - DEFAULT_DATE_FORMAT, | |
21 | 23 | fontSize, |
24 | + getUpdateTime, | |
22 | 25 | } from '../../detail/config/util'; |
23 | 26 | import { Tooltip } from 'ant-design-vue'; |
24 | 27 | import { useThrottleFn } from '@vueuse/shared'; |
28 | + import { buildUUID } from '/@/utils/uuid'; | |
29 | + import { FrontComponent } from '../help'; | |
25 | 30 | |
26 | 31 | const props = defineProps({ |
27 | 32 | add: { |
... | ... | @@ -33,7 +38,7 @@ |
33 | 38 | }, |
34 | 39 | value: { |
35 | 40 | type: Object as PropType<DashBoardValue>, |
36 | - default: () => ({}), | |
41 | + default: () => ({ id: buildUUID() }), | |
37 | 42 | }, |
38 | 43 | radio: { |
39 | 44 | type: Object as PropType<RadioRecord>, |
... | ... | @@ -60,7 +65,6 @@ |
60 | 65 | } |
61 | 66 | |
62 | 67 | const getRadio = computed(() => { |
63 | - // const { radio } = props.radio; | |
64 | 68 | return props.radio; |
65 | 69 | }); |
66 | 70 | |
... | ... | @@ -68,7 +72,6 @@ |
68 | 72 | const realWidth = unref(chartRef)?.getWidth(); |
69 | 73 | const realHeight = unref(chartRef)?.getHeight(); |
70 | 74 | const radioRecord = props.radio; |
71 | - // const widht | |
72 | 75 | return { |
73 | 76 | ...radioRecord, |
74 | 77 | height: realHeight || radioRecord.height, |
... | ... | @@ -76,7 +79,7 @@ |
76 | 79 | }; |
77 | 80 | }); |
78 | 81 | |
79 | - const beforeUpdateFn = (componentType: InstrumentComponentType) => { | |
82 | + const beforeUpdateFn = (componentType: FrontComponent) => { | |
80 | 83 | if (componentType === 'instrument-component-1') return update_instrument_1_font; |
81 | 84 | if (componentType === 'instrument-component-2') return update_instrument_2_font; |
82 | 85 | return (_radio: RadioRecord) => {}; |
... | ... | @@ -88,7 +91,7 @@ |
88 | 91 | unref(chartRef)?.resize(); |
89 | 92 | } |
90 | 93 | |
91 | - const getUpdateValueFn = (componentType: InstrumentComponentType) => { | |
94 | + const getUpdateValueFn = (componentType: FrontComponent) => { | |
92 | 95 | if (componentType === 'instrument-component-1') return update_instrument_1_value; |
93 | 96 | if (componentType === 'instrument-component-2') return update_instrument_2_value; |
94 | 97 | return (_radio: DashBoardValue) => {}; |
... | ... | @@ -101,11 +104,6 @@ |
101 | 104 | |
102 | 105 | watch(() => props.value, updateChartValue); |
103 | 106 | |
104 | - // watch( | |
105 | - // () => [props.value.gradientInfo, props.value.unit, props.value.valueColor, props.value.name], | |
106 | - // updateChartValue | |
107 | - // ); | |
108 | - | |
109 | 107 | const updateChartFont = useThrottleFn(() => { |
110 | 108 | const option = beforeUpdateFn(props.layout.componentType); |
111 | 109 | setTimeout(() => { |
... | ... | @@ -122,8 +120,6 @@ |
122 | 120 | |
123 | 121 | watch(() => props.layout.componentType, updateChartType); |
124 | 122 | |
125 | - // watch(() => props.value.gradientInfo, updateChartType); | |
126 | - | |
127 | 123 | let timeout: Nullable<number> = null; |
128 | 124 | |
129 | 125 | function handleRandomValue() { |
... | ... | @@ -170,22 +166,11 @@ |
170 | 166 | color: '#999', |
171 | 167 | }" |
172 | 168 | > |
173 | - <Tooltip | |
174 | - placement="top" | |
175 | - :title=" | |
176 | - props.value?.updateTime | |
177 | - ? dateUtil(props?.value?.updateTime).format(DEFAULT_DATE_FORMAT) | |
178 | - : '暂无更新时间' | |
179 | - " | |
180 | - > | |
169 | + <Tooltip placement="top" :title="getUpdateTime(props.value?.updateTime)"> | |
181 | 170 | <div class="truncate"> |
182 | 171 | <span class="mr-2">更新时间:</span> |
183 | 172 | <span> |
184 | - {{ | |
185 | - props.value?.updateTime | |
186 | - ? dateUtil(props?.value?.updateTime).format(DEFAULT_DATE_FORMAT) | |
187 | - : '暂无更新时间' | |
188 | - }} | |
173 | + {{ getUpdateTime(props.value?.updateTime) }} | |
189 | 174 | </span> |
190 | 175 | </div> |
191 | 176 | </Tooltip> | ... | ... |
1 | +<script lang="ts"> | |
2 | + export default { | |
3 | + inheritAttrs: false, | |
4 | + }; | |
5 | +</script> | |
1 | 6 | <script lang="ts" setup> |
2 | 7 | import { computed, onMounted, onUnmounted, ref, unref } from 'vue'; |
3 | 8 | import { Space, Tooltip } from 'ant-design-vue'; |
... | ... | @@ -6,22 +11,27 @@ |
6 | 11 | DigitalDashBoardLayout, |
7 | 12 | DigitalDashBoardValue, |
8 | 13 | } from './digitalDashBoard.config'; |
9 | - import { dateUtil } from '/@/utils/dateUtil'; | |
10 | 14 | import { |
11 | 15 | fontSize, |
12 | 16 | RadioRecord, |
13 | - DEFAULT_DATE_FORMAT, | |
17 | + getUpdateTime, | |
14 | 18 | DEFAULT_RADIO_RECORD, |
15 | 19 | DEFAULT_ANIMATION_INTERVAL, |
16 | 20 | } from '../../detail/config/util'; |
17 | 21 | import { isNaN } from 'lodash'; |
18 | 22 | |
19 | - const props = defineProps<{ | |
20 | - layout: DigitalDashBoardLayout; | |
21 | - value: DigitalDashBoardValue; | |
22 | - radio?: RadioRecord; | |
23 | - random?: boolean; | |
24 | - }>(); | |
23 | + const props = withDefaults( | |
24 | + defineProps<{ | |
25 | + layout?: DigitalDashBoardLayout; | |
26 | + value?: DigitalDashBoardValue; | |
27 | + radio?: RadioRecord; | |
28 | + random?: boolean; | |
29 | + }>(), | |
30 | + { | |
31 | + value: () => ({}), | |
32 | + layout: () => ({ max: 5, keepNumber: 2 }), | |
33 | + } | |
34 | + ); | |
25 | 35 | |
26 | 36 | const changeValue = ref(0); |
27 | 37 | |
... | ... | @@ -53,8 +63,6 @@ |
53 | 63 | }); |
54 | 64 | |
55 | 65 | const getRadio = computed(() => { |
56 | - // const { radio } = props.radio || DEFAULT_RADIO_RECORD; | |
57 | - // return radio; | |
58 | 66 | return props.radio || DEFAULT_RADIO_RECORD; |
59 | 67 | }); |
60 | 68 | |
... | ... | @@ -160,22 +168,11 @@ |
160 | 168 | color: '#999', |
161 | 169 | }" |
162 | 170 | > |
163 | - <Tooltip | |
164 | - placement="top" | |
165 | - :title=" | |
166 | - props.value?.updateTime | |
167 | - ? dateUtil(props?.value?.updateTime).format(DEFAULT_DATE_FORMAT) | |
168 | - : '暂无更新时间' | |
169 | - " | |
170 | - > | |
171 | + <Tooltip placement="top" :title="getUpdateTime(props.value?.updateTime)"> | |
171 | 172 | <div class="truncate"> |
172 | 173 | <span class="mr-1">更新时间:</span> |
173 | 174 | <span> |
174 | - {{ | |
175 | - props.value?.updateTime | |
176 | - ? dateUtil(props?.value?.updateTime).format(DEFAULT_DATE_FORMAT) | |
177 | - : '暂无更新时间' | |
178 | - }} | |
175 | + {{ getUpdateTime(props.value?.updateTime) }} | |
179 | 176 | </span> |
180 | 177 | </div> |
181 | 178 | </Tooltip> |
... | ... | @@ -188,11 +185,12 @@ |
188 | 185 | <style scoped lang="less"> |
189 | 186 | .digital-wrapper__int { |
190 | 187 | border-radius: 1px; |
191 | - box-shadow: inset 0px 1px 3px 0px rgba(0, 0, 0, 0.7); | |
192 | - background: url('/@/assets/images/digital-wrapper-bg-int.png') 0px -1px no-repeat; | |
188 | + box-shadow: inset 0 1px 3px 0 rgba(0, 0, 0, 0.7); | |
189 | + background: url('/@/assets/images/digital-wrapper-bg-int.png') 0 -1px no-repeat; | |
193 | 190 | padding: 5px; |
194 | 191 | background-size: 100% 100%; |
195 | 192 | } |
193 | + | |
196 | 194 | .digital-text_int { |
197 | 195 | display: inline-block; |
198 | 196 | overflow-wrap: break-word; |
... | ... | @@ -203,11 +201,12 @@ |
203 | 201 | |
204 | 202 | .digital-wrapper__float { |
205 | 203 | border-radius: 1px; |
206 | - box-shadow: inset 0px 1px 3px 0px rgba(112, 22, 15, 1); | |
207 | - background: url('/@/assets/images/digital-wrapper-bg-float.png') 0px -1px no-repeat; | |
204 | + box-shadow: inset 0 1px 3px 0 rgba(112, 22, 15, 1); | |
205 | + background: url('/@/assets/images/digital-wrapper-bg-float.png') 0 -1px no-repeat; | |
208 | 206 | padding: 5px; |
209 | 207 | background-size: 100% 100%; |
210 | 208 | } |
209 | + | |
211 | 210 | .digital-text_float { |
212 | 211 | display: inline-block; |
213 | 212 | overflow-wrap: break-word; | ... | ... |
1 | 1 | import { EChartsOption } from 'echarts'; |
2 | +import { FrontComponent, Gradient, GradientColor } from '../../const/const'; | |
2 | 3 | import { fontSize, RadioRecord } from '../../detail/config/util'; |
3 | -import { Gradient, visualOptionField } from '../../detail/config/visualOptions'; | |
4 | 4 | import { |
5 | 5 | ComponentInfo, |
6 | 6 | DataComponentRecord, |
... | ... | @@ -10,16 +10,6 @@ import { |
10 | 10 | import { isArray } from '/@/utils/is'; |
11 | 11 | import { buildUUID } from '/@/utils/uuid'; |
12 | 12 | |
13 | -export type InstrumentComponentType = 'instrument-component-1' | 'instrument-component-2'; | |
14 | - | |
15 | -export type GradientKey = | |
16 | - | visualOptionField.FIRST_PHASE_COLOR | |
17 | - | visualOptionField.FIRST_PHASE_VALUE | |
18 | - | visualOptionField.SECOND_PHASE_COLOR | |
19 | - | visualOptionField.SECOND_PHASE_VALUE | |
20 | - | visualOptionField.THIRD_PHASE_COLOR | |
21 | - | visualOptionField.THIRD_PHASE_VALUE; | |
22 | - | |
23 | 13 | export interface GradientInfoRecord { |
24 | 14 | key: Gradient; |
25 | 15 | value: number; |
... | ... | @@ -38,13 +28,7 @@ export interface DashBoardValue { |
38 | 28 | |
39 | 29 | export interface DashboardComponentLayout { |
40 | 30 | chartOption: EChartsOption; |
41 | - componentType: InstrumentComponentType; | |
42 | -} | |
43 | - | |
44 | -export enum GradientColor { | |
45 | - FIRST = '#67e0e3', | |
46 | - SECOND = '#37a2da', | |
47 | - THIRD = '#fd666d', | |
31 | + componentType: FrontComponent; | |
48 | 32 | } |
49 | 33 | |
50 | 34 | export const instrumentComponent1 = (params?: Partial<ComponentInfo>): EChartsOption => { |
... | ... | @@ -94,7 +78,6 @@ export const instrumentComponent1 = (params?: Partial<ComponentInfo>): EChartsOp |
94 | 78 | axisLabel: { |
95 | 79 | distance: 0, |
96 | 80 | color: '#999', |
97 | - // fontSize: 20, | |
98 | 81 | }, |
99 | 82 | anchor: { |
100 | 83 | show: false, |
... | ... | @@ -173,7 +156,6 @@ export const instrumentComponent2 = (params?: Partial<ComponentInfo>): EChartsOp |
173 | 156 | |
174 | 157 | const firstGradient = firstRecord?.value ? firstRecord.value / max : 0.3; |
175 | 158 | const secondGradient = secondRecord?.value ? secondRecord.value / max : 0.7; |
176 | - // const thirdGradient = thirdRecord?.value ? thirdRecord.value / max : 1; | |
177 | 159 | |
178 | 160 | return { |
179 | 161 | series: [ |
... | ... | @@ -307,12 +289,15 @@ export const update_instrument_2_value = (params: DashBoardValue) => { |
307 | 289 | |
308 | 290 | let max = thirdRecord?.value || secondRecord?.value || firstRecord?.value || 70; |
309 | 291 | max = Number(1 + Array(String(max).length).fill(0).join('')); |
292 | + max = value > 1 ? Number(1 + Array(String(value).length).fill(0).join('')) / 2 : 100 / 2; | |
293 | + max = value > max ? max * 2 : max; | |
310 | 294 | |
311 | 295 | const firstGradient = firstRecord?.value ? firstRecord.value / max : 0.3; |
312 | 296 | const secondGradient = secondRecord?.value ? secondRecord.value / max : 0.7; |
313 | 297 | return { |
314 | 298 | series: [ |
315 | 299 | { |
300 | + max: max < 100 ? 100 : max, | |
316 | 301 | data: [{ value: handleValue(value) }], |
317 | 302 | detail: { |
318 | 303 | formatter: `{value} ${unit ?? ''}`, |
... | ... | @@ -354,7 +339,7 @@ export const Instrument2DefaultConfig: Partial<ComponentInfo> = { |
354 | 339 | |
355 | 340 | export const transformDashboardComponentConfig = ( |
356 | 341 | config: DashboardComponentLayout, |
357 | - record: DataComponentRecord, | |
342 | + _record: DataComponentRecord, | |
358 | 343 | dataSourceRecord: DataSource |
359 | 344 | ) => { |
360 | 345 | let chartOption = config.chartOption; | ... | ... |
1 | 1 | import { EChartsOption } from 'echarts'; |
2 | -import { Component } from 'vue'; | |
3 | -import { WidgetComponentType } from '../../detail/config/visualOptions'; | |
4 | -import { | |
5 | - Instrument1DefaultConfig, | |
6 | - Instrument2DefaultConfig, | |
7 | - instrumentComponent1, | |
8 | - instrumentComponent2, | |
9 | - InstrumentComponentType, | |
10 | -} from './dashBoardComponent.config'; | |
11 | -import DashBoardComponent from './DashBoardComponent.vue'; | |
12 | -import DigitalDashBoard from './DigitalDashBoard.vue'; | |
13 | -import { buildUUID } from '/@/utils/uuid'; | |
2 | +import { InstrumentComponentType } from './dashBoardComponent.config'; | |
14 | 3 | |
15 | 4 | export interface DashboardComponentLayout { |
16 | 5 | chartOption: EChartsOption; |
17 | 6 | componentType: InstrumentComponentType; |
18 | 7 | } |
19 | - | |
20 | -interface InstrumentComponentConfig { | |
21 | - id: WidgetComponentType; | |
22 | - layout: DashboardComponentLayout; | |
23 | - component: Component; | |
24 | - value: Recordable; | |
25 | -} | |
26 | - | |
27 | -export const instrumentComponentConfig: InstrumentComponentConfig[] = [ | |
28 | - { | |
29 | - id: 'instrument-component-1', | |
30 | - layout: { | |
31 | - chartOption: instrumentComponent1(Instrument1DefaultConfig), | |
32 | - componentType: 'instrument-component-1', | |
33 | - }, | |
34 | - component: DashBoardComponent, | |
35 | - value: { id: buildUUID() }, | |
36 | - }, | |
37 | - { | |
38 | - id: 'instrument-component-2', | |
39 | - layout: { | |
40 | - chartOption: instrumentComponent2(Instrument2DefaultConfig), | |
41 | - componentType: 'instrument-component-2', | |
42 | - }, | |
43 | - component: DashBoardComponent, | |
44 | - value: { id: buildUUID() }, | |
45 | - }, | |
46 | - { | |
47 | - id: 'digital-dashboard-component', | |
48 | - layout: {}, | |
49 | - component: DigitalDashBoard, | |
50 | - value: {}, | |
51 | - }, | |
52 | -]; | ... | ... |
1 | +<script lang="ts"> | |
2 | + export default { | |
3 | + inheritAttrs: false, | |
4 | + }; | |
5 | +</script> | |
6 | +<script lang="ts" setup> | |
7 | + import { nextTick, onMounted, ref, unref } from 'vue'; | |
8 | + import { useScript } from '/@/hooks/web/useScript'; | |
9 | + import { BAI_DU_MAP_URL } from '/@/utils/fnUtils'; | |
10 | + | |
11 | + const wrapRef = ref<HTMLDivElement | null>(null); | |
12 | + const { toPromise } = useScript({ src: BAI_DU_MAP_URL }); | |
13 | + | |
14 | + async function initMap() { | |
15 | + await toPromise(); | |
16 | + await nextTick(); | |
17 | + const wrapEl = unref(wrapRef); | |
18 | + if (!wrapEl) return; | |
19 | + const BMap = (window as any).BMap; | |
20 | + const map = new BMap.Map(wrapEl); | |
21 | + const point = new BMap.Point(116.404, 39.915); | |
22 | + map.centerAndZoom(point, 15); | |
23 | + map.enableScrollWheelZoom(true); | |
24 | + } | |
25 | + | |
26 | + onMounted(() => { | |
27 | + initMap(); | |
28 | + }); | |
29 | +</script> | |
30 | + | |
31 | +<template> | |
32 | + <div class="w-full h-full flex justify-center items-center"> | |
33 | + <div ref="wrapRef" class="w-[95%] h-[95%]"></div> | |
34 | + </div> | |
35 | +</template> | ... | ... |
... | ... | @@ -12,6 +12,7 @@ |
12 | 12 | |
13 | 13 | const isEdit = ref(false); |
14 | 14 | const recordId = ref<Nullable<string>>(null); |
15 | + const loading = ref(false); | |
15 | 16 | |
16 | 17 | const [registerModal, { changeLoading, closeModal }] = useModalInner( |
17 | 18 | (record: DataBoardRecord & { isEdit: boolean }) => { |
... | ... | @@ -33,6 +34,7 @@ |
33 | 34 | await method.validate(); |
34 | 35 | try { |
35 | 36 | const value = method.getFieldsValue() as AddDataBoardParams; |
37 | + loading.value = true; | |
36 | 38 | changeLoading(true); |
37 | 39 | await addDataBoard(value); |
38 | 40 | createMessage.success('创建成功'); |
... | ... | @@ -42,12 +44,14 @@ |
42 | 44 | createMessage.error('创建失败'); |
43 | 45 | } finally { |
44 | 46 | changeLoading(false); |
47 | + loading.value = false; | |
45 | 48 | } |
46 | 49 | }; |
47 | 50 | |
48 | 51 | const handleEditPanel = async () => { |
49 | 52 | await method.validate(); |
50 | 53 | try { |
54 | + loading.value = true; | |
51 | 55 | const value = method.getFieldsValue() as UpdateDataBoardParams; |
52 | 56 | value.id = unref(recordId) as string; |
53 | 57 | changeLoading(true); |
... | ... | @@ -59,6 +63,7 @@ |
59 | 63 | createMessage.error('编辑失败'); |
60 | 64 | } finally { |
61 | 65 | changeLoading(false); |
66 | + loading.value = false; | |
62 | 67 | } |
63 | 68 | }; |
64 | 69 | |
... | ... | @@ -75,6 +80,7 @@ |
75 | 80 | :title="isEdit ? '编辑看板' : '创建看板'" |
76 | 81 | @register="registerModal" |
77 | 82 | @ok="handleGetValue" |
83 | + :okButtonProps="{ loading }" | |
78 | 84 | > |
79 | 85 | <BasicForm @register="registerForm" /> |
80 | 86 | </BasicModal> | ... | ... |
1 | +<script lang="ts"> | |
2 | + export default { | |
3 | + inheritAttrs: false, | |
4 | + }; | |
5 | +</script> | |
1 | 6 | <script lang="ts" setup> |
2 | 7 | import { computed, ref, watch } from 'vue'; |
3 | 8 | import { Tooltip, Image as AntImage } from 'ant-design-vue'; |
4 | 9 | import { |
5 | - DEFAULT_DATE_FORMAT, | |
10 | + getUpdateTime, | |
6 | 11 | DEFAULT_RADIO_RECORD, |
7 | 12 | fontSize, |
8 | 13 | RadioRecord, |
9 | 14 | } from '../../detail/config/util'; |
10 | - import { PictureComponentLayout, PictureComponentValue } from './pictureComponent.config'; | |
11 | - import { dateUtil } from '/@/utils/dateUtil'; | |
15 | + import { PictureComponentValue } from './pictureComponent.config'; | |
12 | 16 | |
13 | 17 | const props = defineProps<{ |
14 | - layout?: PictureComponentLayout; | |
18 | + layout?: Recordable; | |
15 | 19 | value?: PictureComponentValue; |
16 | 20 | radio?: RadioRecord; |
17 | 21 | }>(); |
... | ... | @@ -22,8 +26,6 @@ |
22 | 26 | const getImagBase64 = ref(fallback); |
23 | 27 | |
24 | 28 | const getRadio = computed(() => { |
25 | - // const { radio } = props.radio || DEFAULT_RADIO_RECORD; | |
26 | - // return radio; | |
27 | 29 | return props.radio || DEFAULT_RADIO_RECORD; |
28 | 30 | }); |
29 | 31 | |
... | ... | @@ -67,26 +69,14 @@ |
67 | 69 | class="w-full h-full flex flex-col justify-center items-center justify-between widget-picture" |
68 | 70 | > |
69 | 71 | <AntImage :width="getWidth" :src="getImagBase64" :fallback="fallback" /> |
70 | - <!-- <Image :style="{ width: `${getWidth}px` }" :src="getImagBase64" /> --> | |
71 | 72 | <div |
72 | 73 | class="w-full text-center truncate p-5" |
73 | 74 | :style="{ fontSize: fontSize({ radioRecord: getRadio, basic: 12, max: 12 }), color: '#999' }" |
74 | 75 | > |
75 | - <Tooltip | |
76 | - placement="top" | |
77 | - :title=" | |
78 | - props.value?.updateTime | |
79 | - ? dateUtil(props?.value?.updateTime).format(DEFAULT_DATE_FORMAT) | |
80 | - : '暂无更新时间' | |
81 | - " | |
82 | - > | |
76 | + <Tooltip placement="top" :title="getUpdateTime(props.value?.updateTime)"> | |
83 | 77 | <span class="mr-1">更新时间:</span> |
84 | 78 | <span class="truncate"> |
85 | - {{ | |
86 | - props.value?.updateTime | |
87 | - ? dateUtil(props?.value?.updateTime).format(DEFAULT_DATE_FORMAT) | |
88 | - : '暂无更新时间' | |
89 | - }} | |
79 | + {{ getUpdateTime(props.value?.updateTime) }} | |
90 | 80 | </span> |
91 | 81 | </Tooltip> |
92 | 82 | </div> | ... | ... |
1 | 1 | import PictureComponent from './PictureComponent.vue'; |
2 | 2 | |
3 | -import { PictureComponentType } from './pictureComponent.config'; | |
4 | -import { Component } from 'vue'; | |
5 | - | |
6 | -interface PictureComponentList { | |
7 | - id: PictureComponentType; | |
8 | - component: Component; | |
9 | -} | |
10 | -// { | |
11 | -// id: 'instrument-component-1', | |
12 | -// layout: { chartOption: instrumentComponent1() }, | |
13 | -// component: DashBoardComponent, | |
14 | -// value: { id: buildUUID() }, | |
15 | -// } | |
16 | -const pictureComponentList: PictureComponentList[] = [ | |
17 | - { | |
18 | - id: 'picture-component-1', | |
19 | - component: PictureComponent, | |
20 | - }, | |
21 | -]; | |
22 | - | |
23 | -export { PictureComponent, pictureComponentList }; | |
3 | +export { PictureComponent }; | ... | ... |
1 | 1 | import { DataComponentRecord, DataSource } from '/@/api/dataBoard/model'; |
2 | 2 | |
3 | -export type PictureComponentType = 'picture-component-1'; | |
4 | - | |
5 | -export interface PictureComponentLayout {} | |
6 | - | |
7 | 3 | export interface PictureComponentValue { |
8 | 4 | value?: string; |
9 | 5 | updateTime?: string; |
10 | 6 | } |
11 | 7 | |
12 | 8 | export const transformPictureConfig = ( |
13 | - config: PictureComponentLayout, | |
14 | - record: DataComponentRecord, | |
9 | + _config: Recordable, | |
10 | + _record: DataComponentRecord, | |
15 | 11 | dataSourceRecord: DataSource |
16 | 12 | ) => { |
17 | 13 | const componentInfo = dataSourceRecord.componentInfo; | ... | ... |
1 | +<script lang="ts"> | |
2 | + export default { | |
3 | + inheritAttrs: false, | |
4 | + }; | |
5 | +</script> | |
1 | 6 | <script lang="ts" setup> |
2 | 7 | import { computed } from 'vue'; |
3 | 8 | import { Statistic, Tooltip } from 'ant-design-vue'; |
4 | 9 | import { |
10 | + getUpdateTime, | |
5 | 11 | fontSize, |
6 | 12 | RadioRecord, |
7 | 13 | DEFAULT_RADIO_RECORD, |
8 | - DEFAULT_DATE_FORMAT, | |
9 | 14 | } from '../../detail/config/util'; |
10 | 15 | import { TextComponentDefaultConfig, TextComponentLayout, TextComponentValue } from './config'; |
11 | 16 | import { SvgIcon } from '/@/components/Icon'; |
12 | - import { dateUtil } from '/@/utils/dateUtil'; | |
13 | 17 | const props = defineProps({ |
14 | 18 | layout: { |
15 | 19 | type: Object as PropType<TextComponentLayout>, |
... | ... | @@ -47,8 +51,6 @@ |
47 | 51 | }); |
48 | 52 | |
49 | 53 | const getRadio = computed(() => { |
50 | - // const { radio } = props.radio; | |
51 | - // return radio; | |
52 | 54 | return props.radio || DEFAULT_RADIO_RECORD; |
53 | 55 | }); |
54 | 56 | </script> |
... | ... | @@ -84,37 +86,21 @@ |
84 | 86 | /> |
85 | 87 | </div> |
86 | 88 | <div :style="{ color: '#666', fontSize: fontSize({ radioRecord: getRadio, basic: 16 }) }"> |
87 | - <!-- {{ getShowUnit ? props.value.unit : '' }} --> | |
88 | 89 | {{ props.value.name }} |
89 | 90 | </div> |
90 | - <!-- <div class="truncate" :style="{ fontSize: fontSize({ radio: getRadio, basic: 16 }) }"> | |
91 | - {{ props.value.name }} | |
92 | - </div> --> | |
93 | 91 | </div> |
94 | 92 | </div> |
95 | 93 | </div> |
96 | 94 | |
97 | 95 | <div class="text-center text-xs truncate p-5" style="color: #999"> |
98 | - <Tooltip | |
99 | - v-if="getShowUpdate" | |
100 | - placement="top" | |
101 | - :title=" | |
102 | - props.value?.updateTime | |
103 | - ? dateUtil(props?.value?.updateTime).format(DEFAULT_DATE_FORMAT) | |
104 | - : '暂无更新时间' | |
105 | - " | |
106 | - > | |
96 | + <Tooltip v-if="getShowUpdate" placement="top" :title="getUpdateTime(props.value?.updateTime)"> | |
107 | 97 | <div |
108 | 98 | :style="{ fontSize: fontSize({ radioRecord: getRadio, basic: 12, max: 12 }) }" |
109 | 99 | class="truncate" |
110 | 100 | > |
111 | 101 | <span class="mr-1">更新时间:</span> |
112 | 102 | <span class="truncate"> |
113 | - {{ | |
114 | - props.value?.updateTime | |
115 | - ? dateUtil(props?.value?.updateTime).format(DEFAULT_DATE_FORMAT) | |
116 | - : '暂无更新时间' | |
117 | - }} | |
103 | + {{ getUpdateTime(props.value?.updateTime) }} | |
118 | 104 | </span> |
119 | 105 | </div> |
120 | 106 | </Tooltip> | ... | ... |
... | ... | @@ -18,13 +18,6 @@ export interface TextComponentValue { |
18 | 18 | deviceName?: string; |
19 | 19 | } |
20 | 20 | |
21 | -export type TextComponentType = | |
22 | - | 'text-component-1' | |
23 | - | 'text-component-2' | |
24 | - | 'text-component-3' | |
25 | - | 'text-component-4' | |
26 | - | 'text-component-5'; | |
27 | - | |
28 | 21 | type TextComponentDefault = TextComponentLayout; |
29 | 22 | |
30 | 23 | export const TextComponent1Config: TextComponentDefault = { |
... | ... | @@ -32,10 +25,6 @@ export const TextComponent1Config: TextComponentDefault = { |
32 | 25 | base: true, |
33 | 26 | }; |
34 | 27 | |
35 | -export const TextComponent2Config: TextComponentDefault = { | |
36 | - id: 'text-component-2', | |
37 | - base: false, | |
38 | -}; | |
39 | 28 | export const TextComponent3Config: TextComponentDefault = { |
40 | 29 | id: 'text-component-3', |
41 | 30 | base: false, |
... | ... | @@ -62,17 +51,9 @@ export const TextComponentDefaultConfig: Partial<ComponentInfo> = { |
62 | 51 | icon: 'shuiwen', |
63 | 52 | }; |
64 | 53 | |
65 | -export const textComponentConfig: TextComponentDefault[] = [ | |
66 | - TextComponent1Config, | |
67 | - // TextComponent2Config, | |
68 | - TextComponent3Config, | |
69 | - TextComponent4Config, | |
70 | - TextComponent5Config, | |
71 | -]; | |
72 | - | |
73 | 54 | export const transformTextComponentConfig = ( |
74 | 55 | config: TextComponentDefault, |
75 | - record: DataComponentRecord, | |
56 | + _record: DataComponentRecord, | |
76 | 57 | dataSourceRecord: DataSource |
77 | 58 | ) => { |
78 | 59 | return { | ... | ... |
... | ... | @@ -3,8 +3,11 @@ |
3 | 3 | import { DropMenu } from '/@/components/Dropdown'; |
4 | 4 | import Dropdown from '/@/components/Dropdown/src/Dropdown.vue'; |
5 | 5 | import { Tooltip } from 'ant-design-vue'; |
6 | - // import SvgIcon from '/@/components/Icon/src/SvgIcon.vue'; | |
7 | - import { isBataBoardSharePage, MoreActionEvent } from '../../config/config'; | |
6 | + import { | |
7 | + isBataBoardSharePage, | |
8 | + MoreActionEvent, | |
9 | + VisualComponentPermission, | |
10 | + } from '../../config/config'; | |
8 | 11 | import { computed } from '@vue/reactivity'; |
9 | 12 | import { usePermission } from '/@/hooks/web/usePermission'; |
10 | 13 | import { DataSource } from '/@/api/dataBoard/model'; |
... | ... | @@ -19,9 +22,9 @@ |
19 | 22 | const { hasPermission } = usePermission(); |
20 | 23 | const dropMenuList = computed<DropMenu[]>(() => { |
21 | 24 | const basicMenu: DropMenu[] = []; |
22 | - const hasUpdatePermission = hasPermission('api:yt:data_component:update:update'); | |
23 | - const hasDeletePermission = hasPermission('api:yt:data_component:delete'); | |
24 | - const hasCopyPermission = hasPermission('api:yt:dataBoardDetail:copy'); | |
25 | + const hasUpdatePermission = hasPermission(VisualComponentPermission.UPDATE); | |
26 | + const hasDeletePermission = hasPermission(VisualComponentPermission.DELETE); | |
27 | + const hasCopyPermission = hasPermission(VisualComponentPermission.COPY); | |
25 | 28 | if (hasUpdatePermission) |
26 | 29 | basicMenu.push({ |
27 | 30 | text: '编辑组件', |
... | ... | @@ -69,7 +72,6 @@ |
69 | 72 | > |
70 | 73 | <Tooltip :title="item.deviceName" placement="topLeft"> |
71 | 74 | <div class="flex p-1"> |
72 | - <!-- <SvgIcon name="" prefix="iconfont" class="!fill-emerald-400" /> --> | |
73 | 75 | <div class="truncate font-bold">{{ item.deviceRename || item.deviceName }}</div> |
74 | 76 | </div> |
75 | 77 | </Tooltip> | ... | ... |
1 | 1 | <script lang="ts" setup> |
2 | - import { useSlots } from 'vue'; | |
3 | 2 | import { useUpdateCenter } from '../../hook/useUpdateCenter'; |
4 | 3 | import { FrontDataSourceRecord } from '../../types/type'; |
5 | - // import type { WidgetWrapperRegister } from './type'; | |
6 | - // import { DataSource } from '/@/api/dataBoard/model'; | |
7 | 4 | |
8 | 5 | const props = defineProps<{ |
9 | 6 | dataSource: FrontDataSourceRecord[]; |
10 | 7 | }>(); |
11 | 8 | |
12 | - const slot = useSlots(); | |
13 | - | |
14 | 9 | const { update, add, remove } = useUpdateCenter(); |
15 | 10 | |
16 | 11 | defineExpose({ update }); |
... | ... | @@ -20,7 +15,7 @@ |
20 | 15 | <section class="widget"> |
21 | 16 | <slot name="header"></slot> |
22 | 17 | |
23 | - <div class="widget-content" :style="{ height: slot.header ? 'calc(100% - 22px)' : '100%' }"> | |
18 | + <div class="widget-content"> | |
24 | 19 | <div |
25 | 20 | v-for="item in props.dataSource" |
26 | 21 | :key="item.id" |
... | ... | @@ -28,10 +23,7 @@ |
28 | 23 | class="widget-item" |
29 | 24 | > |
30 | 25 | <div class="widget-box"> |
31 | - <div | |
32 | - class="widget-controls-container" | |
33 | - :style="{ height: slot.footer ? 'calc(100% - 20px)' : '100%' }" | |
34 | - > | |
26 | + <div class="widget-controls-container"> | |
35 | 27 | <slot |
36 | 28 | name="controls" |
37 | 29 | :record="item" |
... | ... | @@ -40,12 +32,6 @@ |
40 | 32 | :update="update" |
41 | 33 | ></slot> |
42 | 34 | </div> |
43 | - <div class="widget-value"> | |
44 | - <slot name="value" :record="item"></slot> | |
45 | - </div> | |
46 | - <div class="widget-label"> | |
47 | - <slot name="label" :record="item"></slot> | |
48 | - </div> | |
49 | 35 | </div> |
50 | 36 | </div> |
51 | 37 | </div> |
... | ... | @@ -61,14 +47,14 @@ |
61 | 47 | height: 100%; |
62 | 48 | background-color: #fff; |
63 | 49 | border-radius: 3px; |
64 | - box-shadow: 0px 1px 10px 0px rgba(0, 0, 0, 0.1); | |
50 | + box-shadow: 0 1px 10px 0 rgba(0, 0, 0, 0.1); | |
65 | 51 | } |
52 | + | |
66 | 53 | .widget-content { |
67 | 54 | display: flex; |
68 | 55 | flex-wrap: wrap; |
69 | 56 | justify-content: center; |
70 | 57 | align-items: center; |
71 | - | |
72 | 58 | width: 100%; |
73 | 59 | height: 100%; |
74 | 60 | } |
... | ... | @@ -94,7 +80,7 @@ |
94 | 80 | .widget-controls-container { |
95 | 81 | flex: 1 1 auto; |
96 | 82 | width: 100%; |
97 | - height: calc(100% - 20px); | |
83 | + height: 100%; | |
98 | 84 | display: flex; |
99 | 85 | align-items: center; |
100 | 86 | justify-content: center; | ... | ... |
src/views/visual/board/components/WidgetWrapper/type.ts
deleted
100644 → 0
src/views/visual/board/components/help.ts
0 → 100644
1 | +import { | |
2 | + TextComponent1Config, | |
3 | + TextComponent3Config, | |
4 | + TextComponent4Config, | |
5 | + TextComponent5Config, | |
6 | + TextComponentDefaultConfig, | |
7 | + transformTextComponentConfig, | |
8 | +} from './TextComponent/config'; | |
9 | +import { ComponentInfo } from '/@/api/dataBoard/model'; | |
10 | +import { transformPictureConfig } from './PictureComponent/pictureComponent.config'; | |
11 | +import { | |
12 | + DashboardComponentLayout, | |
13 | + Instrument1DefaultConfig, | |
14 | + Instrument2DefaultConfig, | |
15 | + instrumentComponent1, | |
16 | + instrumentComponent2, | |
17 | + transformDashboardComponentConfig, | |
18 | +} from './InstrumentComponent/dashBoardComponent.config'; | |
19 | +import { DigitalComponentDefaultConfig } from './InstrumentComponent/digitalDashBoard.config'; | |
20 | +import { transformControlConfig } from './ControlComponent/control.config'; | |
21 | + | |
22 | +import TextComponent from './TextComponent/TextComponent.vue'; | |
23 | +import DashBoardComponent from './InstrumentComponent/DashBoardComponent.vue'; | |
24 | +import PictureComponent from './PictureComponent/PictureComponent.vue'; | |
25 | +import DigitalDashBoard from './InstrumentComponent/DigitalDashBoard.vue'; | |
26 | +import ToggleSwitch from './ControlComponent/ToggleSwitch.vue'; | |
27 | +import SlidingSwitch from './ControlComponent/SlidingSwitch.vue'; | |
28 | +import SwitchWithIcon from './ControlComponent/SwitchWithIcon.vue'; | |
29 | +import MapComponent from './MapComponent/MapComponent.vue'; | |
30 | +import { transfromMapComponentConfig } from './MapComponent/map.config'; | |
31 | +import { ComponentConfig } from '../types/type'; | |
32 | +import { FrontComponent, FrontComponentCategory } from '../const/const'; | |
33 | + | |
34 | +export const frontComponentDefaultConfigMap = new Map<FrontComponent, Partial<ComponentInfo>>(); | |
35 | + | |
36 | +export const frontComponentMap = new Map<FrontComponent, ComponentConfig>(); | |
37 | + | |
38 | +frontComponentMap.set(FrontComponent.TEXT_COMPONENT_1, { | |
39 | + Component: TextComponent, | |
40 | + ComponentName: '文本组件1', | |
41 | + ComponentKey: FrontComponent.TEXT_COMPONENT_1, | |
42 | + ComponentConfig: TextComponent1Config, | |
43 | + ComponentCategory: FrontComponentCategory.TEXT, | |
44 | + transformConfig: transformTextComponentConfig, | |
45 | +}); | |
46 | + | |
47 | +frontComponentMap.set(FrontComponent.TEXT_COMPONENT_3, { | |
48 | + Component: TextComponent, | |
49 | + ComponentName: '文本组件2', | |
50 | + ComponentKey: FrontComponent.TEXT_COMPONENT_3, | |
51 | + ComponentConfig: TextComponent3Config, | |
52 | + ComponentCategory: FrontComponentCategory.TEXT, | |
53 | + transformConfig: transformTextComponentConfig, | |
54 | +}); | |
55 | + | |
56 | +frontComponentMap.set(FrontComponent.TEXT_COMPONENT_4, { | |
57 | + Component: TextComponent, | |
58 | + ComponentName: '文本组件3', | |
59 | + ComponentKey: FrontComponent.TEXT_COMPONENT_4, | |
60 | + ComponentConfig: TextComponent4Config, | |
61 | + ComponentCategory: FrontComponentCategory.TEXT, | |
62 | + transformConfig: transformTextComponentConfig, | |
63 | +}); | |
64 | + | |
65 | +frontComponentMap.set(FrontComponent.TEXT_COMPONENT_5, { | |
66 | + Component: TextComponent, | |
67 | + ComponentName: '文本组件4', | |
68 | + ComponentKey: FrontComponent.TEXT_COMPONENT_5, | |
69 | + ComponentConfig: TextComponent5Config, | |
70 | + ComponentCategory: FrontComponentCategory.TEXT, | |
71 | + transformConfig: transformTextComponentConfig, | |
72 | +}); | |
73 | + | |
74 | +frontComponentMap.set(FrontComponent.INSTRUMENT_COMPONENT_1, { | |
75 | + Component: DashBoardComponent, | |
76 | + ComponentName: '仪表盘', | |
77 | + ComponentKey: FrontComponent.INSTRUMENT_COMPONENT_1, | |
78 | + ComponentConfig: { | |
79 | + chartOption: instrumentComponent1(Instrument1DefaultConfig), | |
80 | + componentType: FrontComponent.INSTRUMENT_COMPONENT_1, | |
81 | + } as DashboardComponentLayout, | |
82 | + ComponentCategory: FrontComponentCategory.INSTRUMENT, | |
83 | + transformConfig: transformDashboardComponentConfig, | |
84 | +}); | |
85 | + | |
86 | +frontComponentMap.set(FrontComponent.INSTRUMENT_COMPONENT_2, { | |
87 | + Component: DashBoardComponent, | |
88 | + ComponentName: '阶段仪表盘', | |
89 | + ComponentKey: FrontComponent.INSTRUMENT_COMPONENT_2, | |
90 | + ComponentConfig: { | |
91 | + chartOption: instrumentComponent2(Instrument2DefaultConfig), | |
92 | + componentType: FrontComponent.INSTRUMENT_COMPONENT_2, | |
93 | + } as DashboardComponentLayout, | |
94 | + ComponentCategory: FrontComponentCategory.INSTRUMENT, | |
95 | + transformConfig: transformDashboardComponentConfig, | |
96 | +}); | |
97 | + | |
98 | +frontComponentMap.set(FrontComponent.DIGITAL_DASHBOARD_COMPONENT, { | |
99 | + Component: DigitalDashBoard, | |
100 | + ComponentName: '数字仪表盘', | |
101 | + ComponentKey: FrontComponent.DIGITAL_DASHBOARD_COMPONENT, | |
102 | + ComponentCategory: FrontComponentCategory.INSTRUMENT, | |
103 | + transformConfig: transformDashboardComponentConfig, | |
104 | +}); | |
105 | + | |
106 | +frontComponentMap.set(FrontComponent.PICTURE_COMPONENT_1, { | |
107 | + Component: PictureComponent, | |
108 | + ComponentName: '图片组件', | |
109 | + ComponentKey: FrontComponent.PICTURE_COMPONENT_1, | |
110 | + ComponentCategory: FrontComponentCategory.PICTURE, | |
111 | + transformConfig: transformPictureConfig, | |
112 | +}); | |
113 | + | |
114 | +frontComponentMap.set(FrontComponent.CONTROL_COMPONENT_SWITCH_WITH_ICON, { | |
115 | + Component: SwitchWithIcon, | |
116 | + ComponentName: '控制按钮1', | |
117 | + ComponentKey: FrontComponent.CONTROL_COMPONENT_SWITCH_WITH_ICON, | |
118 | + ComponentCategory: FrontComponentCategory.CONTROL, | |
119 | + transformConfig: transformControlConfig, | |
120 | +}); | |
121 | + | |
122 | +frontComponentMap.set(FrontComponent.CONTROL_COMPONENT_SLIDING_SWITCH, { | |
123 | + Component: SlidingSwitch, | |
124 | + ComponentName: '控制按钮2', | |
125 | + ComponentKey: FrontComponent.CONTROL_COMPONENT_SLIDING_SWITCH, | |
126 | + ComponentCategory: FrontComponentCategory.CONTROL, | |
127 | + transformConfig: transformControlConfig, | |
128 | +}); | |
129 | + | |
130 | +frontComponentMap.set(FrontComponent.CONTROL_COMPONENT_TOGGLE_SWITCH, { | |
131 | + Component: ToggleSwitch, | |
132 | + ComponentName: '控制按钮3', | |
133 | + ComponentKey: FrontComponent.CONTROL_COMPONENT_TOGGLE_SWITCH, | |
134 | + ComponentCategory: FrontComponentCategory.CONTROL, | |
135 | + transformConfig: transformControlConfig, | |
136 | +}); | |
137 | + | |
138 | +frontComponentMap.set(FrontComponent.MAP_COMPONENT_TRACK, { | |
139 | + Component: MapComponent, | |
140 | + ComponentName: '实时轨迹', | |
141 | + ComponentKey: FrontComponent.MAP_COMPONENT_TRACK, | |
142 | + ComponentCategory: FrontComponentCategory.MAP, | |
143 | + transformConfig: transfromMapComponentConfig, | |
144 | +}); | |
145 | + | |
146 | +frontComponentDefaultConfigMap.set(FrontComponent.TEXT_COMPONENT_1, TextComponentDefaultConfig); | |
147 | +frontComponentDefaultConfigMap.set(FrontComponent.TEXT_COMPONENT_3, TextComponentDefaultConfig); | |
148 | +frontComponentDefaultConfigMap.set(FrontComponent.TEXT_COMPONENT_4, TextComponentDefaultConfig); | |
149 | +frontComponentDefaultConfigMap.set(FrontComponent.TEXT_COMPONENT_5, TextComponentDefaultConfig); | |
150 | + | |
151 | +frontComponentDefaultConfigMap.set(FrontComponent.INSTRUMENT_COMPONENT_1, Instrument1DefaultConfig); | |
152 | +frontComponentDefaultConfigMap.set(FrontComponent.INSTRUMENT_COMPONENT_2, Instrument2DefaultConfig); | |
153 | + | |
154 | +frontComponentDefaultConfigMap.set( | |
155 | + FrontComponent.DIGITAL_DASHBOARD_COMPONENT, | |
156 | + DigitalComponentDefaultConfig | |
157 | +); | |
158 | + | |
159 | +export const getComponentDefaultConfig = (key: FrontComponent) => { | |
160 | + return frontComponentDefaultConfigMap.get(key) || {}; | |
161 | +}; | ... | ... |
src/views/visual/board/config/componentMap.ts
deleted
100644 → 0
... | ... | @@ -4,7 +4,19 @@ export enum MoreActionEvent { |
4 | 4 | DELETE = 'delete', |
5 | 5 | } |
6 | 6 | |
7 | -// export enum | |
7 | +export enum VisualBoardPermission { | |
8 | + UPDATE = 'api:yt:data_board:update:update', | |
9 | + DELETE = 'api:yt:data_board:delete', | |
10 | + CREATE = '', | |
11 | + DETAIL = 'api:yt:data_component:list', | |
12 | +} | |
13 | + | |
14 | +export enum VisualComponentPermission { | |
15 | + UPDATE = 'api:yt:data_component:update:update', | |
16 | + DELETE = 'api:yt:data_component:delete', | |
17 | + COPY = 'api:yt:dataBoardDetail:copy', | |
18 | + CREATE = 'api:yt:data_component:add:post', | |
19 | +} | |
8 | 20 | |
9 | 21 | export const DEFAULT_MAX_COL = 24; |
10 | 22 | export const DEFAULT_WIDGET_WIDTH = 6; | ... | ... |
src/views/visual/board/const/const.ts
0 → 100644
1 | +export enum FrontComponentCategory { | |
2 | + TEXT = 'text', | |
3 | + PICTURE = 'picture', | |
4 | + INSTRUMENT = 'instrument', | |
5 | + CONTROL = 'control', | |
6 | + MAP = 'map', | |
7 | +} | |
8 | + | |
9 | +export const FrontComponentCategoryName = { | |
10 | + [FrontComponentCategory.TEXT]: '文本组件', | |
11 | + [FrontComponentCategory.INSTRUMENT]: '仪表组件', | |
12 | + [FrontComponentCategory.CONTROL]: '控制组件', | |
13 | + [FrontComponentCategory.PICTURE]: '图片组件', | |
14 | + [FrontComponentCategory.MAP]: '地图组件', | |
15 | +}; | |
16 | + | |
17 | +export enum FrontComponent { | |
18 | + TEXT_COMPONENT_1 = 'text-component-1', | |
19 | + TEXT_COMPONENT_2 = 'text-component-2', | |
20 | + TEXT_COMPONENT_3 = 'text-component-3', | |
21 | + TEXT_COMPONENT_4 = 'text-component-4', | |
22 | + TEXT_COMPONENT_5 = 'text-component-5', | |
23 | + INSTRUMENT_COMPONENT_1 = 'instrument-component-1', | |
24 | + INSTRUMENT_COMPONENT_2 = 'instrument-component-2', | |
25 | + DIGITAL_DASHBOARD_COMPONENT = 'digital-dashboard-component', | |
26 | + PICTURE_COMPONENT_1 = 'picture-component-1', | |
27 | + CONTROL_COMPONENT_TOGGLE_SWITCH = 'control-component-toggle-switch', | |
28 | + CONTROL_COMPONENT_SWITCH_WITH_ICON = 'control-component-switch-with-icon', | |
29 | + CONTROL_COMPONENT_SLIDING_SWITCH = 'control-component-sliding-switch', | |
30 | + MAP_COMPONENT_TRACK = 'map-component-track', | |
31 | +} | |
32 | + | |
33 | +export enum Gradient { | |
34 | + FIRST = 'first', | |
35 | + SECOND = 'second', | |
36 | + THIRD = 'third', | |
37 | +} | |
38 | +export enum GradientColor { | |
39 | + FIRST = '#67e0e3', | |
40 | + SECOND = '#37a2da', | |
41 | + THIRD = '#fd666d', | |
42 | +} | |
43 | + | |
44 | +export enum visualOptionField { | |
45 | + FONT_COLOR = 'fontColor', | |
46 | + UNIT = 'unit', | |
47 | + ICON_COLOR = 'iconColor', | |
48 | + ICON = 'icon', | |
49 | + FIRST_PHASE_COLOR = 'firstPhaseColor', | |
50 | + SECOND_PHASE_COLOR = 'secondPhaseColor', | |
51 | + THIRD_PHASE_COLOR = 'thirdPhaseColor', | |
52 | + FIRST_PHASE_VALUE = 'firstPhaseValue', | |
53 | + SECOND_PHASE_VALUE = 'secondPhaseValue', | |
54 | + THIRD_PHASE_VALUE = 'thirdPhaseValue', | |
55 | +} | ... | ... |
... | ... | @@ -2,17 +2,17 @@ |
2 | 2 | import { CopyOutlined, DeleteOutlined, SettingOutlined } from '@ant-design/icons-vue'; |
3 | 3 | import { Tooltip, Button } from 'ant-design-vue'; |
4 | 4 | import { FormActionType, useForm } from '/@/components/Form'; |
5 | - import { basicSchema, dataSourceSchema } from '../config/basicConfiguration'; | |
5 | + import { basicSchema } from '../config/basicConfiguration'; | |
6 | 6 | import BasicForm from '/@/components/Form/src/BasicForm.vue'; |
7 | - import { ref, shallowReactive, unref, nextTick, watch } from 'vue'; | |
7 | + import { ref, shallowReactive, unref, nextTick, watch, computed } from 'vue'; | |
8 | 8 | import VisualOptionsModal from './VisualOptionsModal.vue'; |
9 | 9 | import { useModal } from '/@/components/Modal'; |
10 | 10 | import { buildUUID } from '/@/utils/uuid'; |
11 | 11 | import type { ComponentInfo, DataSource } from '/@/api/dataBoard/model'; |
12 | 12 | import { useMessage } from '/@/hooks/web/useMessage'; |
13 | 13 | import { DataBoardLayoutInfo } from '../../types/type'; |
14 | - import { FrontComponent } from '../config/help'; | |
15 | - import { computed } from '@vue/reactivity'; | |
14 | + import { getDataSourceComponent } from './DataSourceForm/help'; | |
15 | + import { FrontComponent } from '../../const/const'; | |
16 | 16 | |
17 | 17 | type DataSourceFormEL = { [key: string]: Nullable<FormActionType> }; |
18 | 18 | |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | |
21 | 21 | const props = defineProps<{ |
22 | 22 | record: DataBoardLayoutInfo; |
23 | - frontId?: string; | |
23 | + frontId?: FrontComponent; | |
24 | 24 | defaultConfig?: Partial<ComponentInfo>; |
25 | 25 | }>(); |
26 | 26 | |
... | ... | @@ -39,7 +39,7 @@ |
39 | 39 | const dataSourceEl = shallowReactive<DataSourceFormEL>({} as unknown as DataSourceFormEL); |
40 | 40 | |
41 | 41 | const setFormEl = (el: any, id: string) => { |
42 | - if (!dataSourceEl[id] && el) { | |
42 | + if (id && el) { | |
43 | 43 | const { formActionType } = el as unknown as { formActionType: FormActionType }; |
44 | 44 | dataSourceEl[id] = formActionType; |
45 | 45 | } |
... | ... | @@ -112,8 +112,6 @@ |
112 | 112 | return; |
113 | 113 | } |
114 | 114 | |
115 | - // const defaultConfig = getComponentDefaultConfig(props.frontId as WidgetComponentType); | |
116 | - | |
117 | 115 | const componentInfo: ComponentInfo = { |
118 | 116 | ...(props.defaultConfig || {}), |
119 | 117 | ...(item.componentInfo || {}), |
... | ... | @@ -177,6 +175,10 @@ |
177 | 175 | ~index && (unref(dataSource)[index].componentInfo = value); |
178 | 176 | }; |
179 | 177 | |
178 | + const dataSourceComponent = computed(() => { | |
179 | + return getDataSourceComponent(props.frontId as FrontComponent); | |
180 | + }); | |
181 | + | |
180 | 182 | defineExpose({ |
181 | 183 | getAllDataSourceFieldValue, |
182 | 184 | validate, |
... | ... | @@ -198,17 +200,8 @@ |
198 | 200 | 选择设备 |
199 | 201 | </div> |
200 | 202 | <div class="pl-2 flex-auto"> |
201 | - <BasicForm | |
202 | - :ref="(el) => setFormEl(el, item.id)" | |
203 | - :schemas="dataSourceSchema" | |
204 | - class="w-full flex-1 data-source-form" | |
205 | - :show-action-button-group="false" | |
206 | - :row-props="{ | |
207 | - gutter: 10, | |
208 | - }" | |
209 | - layout="inline" | |
210 | - :label-col="{ span: 0 }" | |
211 | - /> | |
203 | + <!-- <BasicDataSourceForm /> --> | |
204 | + <component :is="dataSourceComponent" :ref="(el) => setFormEl(el, item.id)" /> | |
212 | 205 | </div> |
213 | 206 | <div class="flex justify-center gap-3 w-24"> |
214 | 207 | <Tooltip title="复制"> | ... | ... |
... | ... | @@ -12,7 +12,7 @@ |
12 | 12 | import { decode } from '../../config/config'; |
13 | 13 | import { ComponentInfo } from '/@/api/dataBoard/model'; |
14 | 14 | import { useCalcGridLayout } from '../../hook/useCalcGridLayout'; |
15 | - import { FrontComponent } from '../config/help'; | |
15 | + import { FrontComponent } from '../../const/const'; | |
16 | 16 | |
17 | 17 | interface DataComponentRouteParams extends RouteParams { |
18 | 18 | id: string; |
... | ... | @@ -23,9 +23,9 @@ |
23 | 23 | }>(); |
24 | 24 | |
25 | 25 | const emit = defineEmits(['update', 'create', 'register']); |
26 | - | |
27 | 26 | const ROUTE = useRoute(); |
28 | 27 | |
28 | + const loading = ref(false); | |
29 | 29 | const { createMessage } = useMessage(); |
30 | 30 | |
31 | 31 | const boardId = computed(() => { |
... | ... | @@ -62,11 +62,15 @@ |
62 | 62 | }; |
63 | 63 | |
64 | 64 | const handleSubmit = async () => { |
65 | - const { getAllDataSourceFieldValue, validate } = unref(basicConfigurationEl)!; | |
66 | - await validate(); | |
67 | - const value = getAllDataSourceFieldValue(); | |
68 | - unref(isEdit) ? handleUpdateComponent(value) : handleAddComponent(value); | |
69 | - resetForm(); | |
65 | + try { | |
66 | + const { getAllDataSourceFieldValue, validate } = unref(basicConfigurationEl)!; | |
67 | + await validate(); | |
68 | + const value = getAllDataSourceFieldValue(); | |
69 | + unref(isEdit) ? handleUpdateComponent(value) : handleAddComponent(value); | |
70 | + resetForm(); | |
71 | + } catch (error: unknown) { | |
72 | + window.console.error(error); | |
73 | + } | |
70 | 74 | }; |
71 | 75 | |
72 | 76 | const { calcLayoutInfo } = useCalcGridLayout(); |
... | ... | @@ -78,6 +82,7 @@ |
78 | 82 | } |
79 | 83 | const layout = calcLayoutInfo(unref(props.layout)); |
80 | 84 | changeOkLoading(true); |
85 | + loading.value = true; | |
81 | 86 | await addDataComponent({ |
82 | 87 | boardId: unref(boardId), |
83 | 88 | record: { dataBoardId: unref(boardId), frontId: unref(frontId), ...value, layout }, |
... | ... | @@ -90,12 +95,14 @@ |
90 | 95 | // createMessage.error('创建失败'); |
91 | 96 | } finally { |
92 | 97 | changeOkLoading(false); |
98 | + loading.value = false; | |
93 | 99 | } |
94 | 100 | }; |
95 | 101 | |
96 | 102 | const handleUpdateComponent = async (value: Recordable) => { |
97 | 103 | try { |
98 | 104 | changeOkLoading(true); |
105 | + loading.value = true; | |
99 | 106 | const res = await updateDataComponent({ |
100 | 107 | boardId: unref(boardId), |
101 | 108 | record: { |
... | ... | @@ -113,6 +120,7 @@ |
113 | 120 | // createMessage.error('修改失败'); |
114 | 121 | } finally { |
115 | 122 | changeOkLoading(false); |
123 | + loading.value = false; | |
116 | 124 | } |
117 | 125 | }; |
118 | 126 | |
... | ... | @@ -130,10 +138,11 @@ |
130 | 138 | :destroy-on-close="true" |
131 | 139 | @ok="handleSubmit" |
132 | 140 | @cancel="resetForm" |
141 | + :ok-button-props="{ loading }" | |
133 | 142 | > |
134 | 143 | <section> |
135 | 144 | <Tabs type="card"> |
136 | - <Tabs.TabPane key="1" tab="基础配置"> | |
145 | + <Tabs.TabPane key="basicConfig" tab="基础配置"> | |
137 | 146 | <BasicConfiguration |
138 | 147 | ref="basicConfigurationEl" |
139 | 148 | :front-id="frontId" |
... | ... | @@ -141,7 +150,7 @@ |
141 | 150 | :defaultConfig="componentDefaultConfig" |
142 | 151 | /> |
143 | 152 | </Tabs.TabPane> |
144 | - <Tabs.TabPane key="2" tab="可视化配置"> | |
153 | + <Tabs.TabPane key="visualConfig" tab="可视化配置"> | |
145 | 154 | <VisualConfiguration v-model:value="frontId" @change="handleComponentCheckedChange" /> |
146 | 155 | </Tabs.TabPane> |
147 | 156 | </Tabs> | ... | ... |
1 | +<script lang="ts" setup> | |
2 | + import { ref } from 'vue'; | |
3 | + import { dataSourceSchema } from '../../config/basicConfiguration'; | |
4 | + import { FormActionType } from '/@/components/Form'; | |
5 | + import BasicForm from '/@/components/Form/src/BasicForm.vue'; | |
6 | + const formEl = ref<Nullable<FormActionType>>(null); | |
7 | + | |
8 | + defineExpose({ formActionType: formEl }); | |
9 | +</script> | |
10 | + | |
11 | +<template> | |
12 | + <BasicForm | |
13 | + ref="formEl" | |
14 | + :schemas="dataSourceSchema" | |
15 | + class="w-full flex-1 data-source-form" | |
16 | + :show-action-button-group="false" | |
17 | + :row-props="{ | |
18 | + gutter: 10, | |
19 | + }" | |
20 | + layout="inline" | |
21 | + :label-col="{ span: 0 }" | |
22 | + /> | |
23 | +</template> | ... | ... |
1 | +<script lang="ts" setup> | |
2 | + import { ref, unref } from 'vue'; | |
3 | + import { BasicForm, FormActionType } from '/@/components/Form'; | |
4 | + import { controlFormSchema } from '../../config/basicConfiguration'; | |
5 | + | |
6 | + const formEl = ref<Nullable<FormActionType>>(); | |
7 | + | |
8 | + const setFormEl = (el: any) => { | |
9 | + formEl.value = el; | |
10 | + }; | |
11 | + | |
12 | + const getFieldsValue = () => { | |
13 | + return unref(formEl)!.getFieldsValue(); | |
14 | + }; | |
15 | + | |
16 | + const validate = async () => { | |
17 | + await unref(formEl)!.validate(); | |
18 | + }; | |
19 | + | |
20 | + const setFieldsValue = async (record: Recordable) => { | |
21 | + await unref(formEl)!.setFieldsValue(record); | |
22 | + }; | |
23 | + | |
24 | + const clearValidate = async (name?: string | string[]) => { | |
25 | + await unref(formEl)!.clearValidate(name); | |
26 | + }; | |
27 | + defineExpose({ | |
28 | + formActionType: { getFieldsValue, validate, setFieldsValue, clearValidate }, | |
29 | + }); | |
30 | +</script> | |
31 | + | |
32 | +<template> | |
33 | + <div class="w-full flex-1"> | |
34 | + <BasicForm | |
35 | + :ref="(el) => setFormEl(el)" | |
36 | + :schemas="controlFormSchema" | |
37 | + class="w-full flex-1 data-source-form" | |
38 | + :show-action-button-group="false" | |
39 | + :row-props="{ | |
40 | + gutter: 10, | |
41 | + }" | |
42 | + layout="inline" | |
43 | + :label-col="{ span: 0 }" | |
44 | + /> | |
45 | + </div> | |
46 | +</template> | ... | ... |
1 | +import { Component } from 'vue'; | |
2 | +import { FrontComponent } from '../../../const/const'; | |
3 | +import BasicDataSourceForm from './BasicDataSourceForm.vue'; | |
4 | +import ControlDataSourceForm from './ControlDataSourceForm.vue'; | |
5 | + | |
6 | +const dataSourceComponentMap = new Map<FrontComponent, Component>(); | |
7 | + | |
8 | +dataSourceComponentMap.set(FrontComponent.CONTROL_COMPONENT_TOGGLE_SWITCH, ControlDataSourceForm); | |
9 | + | |
10 | +export const getDataSourceComponent = (frontId: FrontComponent) => { | |
11 | + if (dataSourceComponentMap.has(frontId)) return dataSourceComponentMap.get(frontId)!; | |
12 | + return BasicDataSourceForm; | |
13 | +}; | ... | ... |
1 | 1 | <script lang="ts" setup> |
2 | 2 | import { Tabs, List } from 'ant-design-vue'; |
3 | 3 | import VisualWidgetSelect from './VisualWidgetSelect.vue'; |
4 | - import TextComponent from '../../components/TextComponent/TextComponent.vue'; | |
5 | - import { textComponentConfig } from '../../components/TextComponent/config'; | |
6 | - import { instrumentComponentConfig } from '../../components/InstrumentComponent'; | |
7 | - import { pictureComponentList } from '../../components/PictureComponent'; | |
8 | - import { getComponentDefaultConfig } from '../config/help'; | |
9 | - import { WidgetComponentType } from '../config/visualOptions'; | |
4 | + import { getComponentDefaultConfig } from '../../components/help'; | |
5 | + import { frontComponentMap } from '../../components/help'; | |
6 | + import { computed } from 'vue'; | |
7 | + import { | |
8 | + FrontComponent, | |
9 | + FrontComponentCategory, | |
10 | + FrontComponentCategoryName, | |
11 | + } from '../../const/const'; | |
12 | + | |
13 | + interface DataSource { | |
14 | + category: string; | |
15 | + categoryName: string; | |
16 | + list: Recordable[]; | |
17 | + } | |
10 | 18 | const props = defineProps<{ |
11 | 19 | value: string; |
12 | 20 | }>(); |
... | ... | @@ -14,7 +22,25 @@ |
14 | 22 | |
15 | 23 | const grid = { gutter: 10, column: 1, xs: 1, sm: 2, md: 2, lg: 3, xl: 3, xxl: 4 }; |
16 | 24 | |
17 | - const handleCheck = (checked: WidgetComponentType) => { | |
25 | + const getDataSource = computed(() => { | |
26 | + const _dataSource = Array.from(frontComponentMap.values()); | |
27 | + const category = new Map<FrontComponentCategory, DataSource>(); | |
28 | + for (const item of _dataSource) { | |
29 | + if (category.has(item.ComponentCategory)) { | |
30 | + const value = category.get(item.ComponentCategory)!; | |
31 | + value.list.push(item); | |
32 | + continue; | |
33 | + } | |
34 | + category.set(item.ComponentCategory, { | |
35 | + category: item.ComponentCategory, | |
36 | + categoryName: FrontComponentCategoryName[item.ComponentCategory], | |
37 | + list: [item], | |
38 | + }); | |
39 | + } | |
40 | + return Array.from(category.values()); | |
41 | + }); | |
42 | + | |
43 | + const handleCheck = (checked: FrontComponent) => { | |
18 | 44 | const defaultConfig = getComponentDefaultConfig(checked); |
19 | 45 | emit('update:value', checked); |
20 | 46 | emit('change', defaultConfig); |
... | ... | @@ -24,51 +50,25 @@ |
24 | 50 | <template> |
25 | 51 | <section> |
26 | 52 | <Tabs> |
27 | - <Tabs.TabPane key="1" tab="文本组件"> | |
28 | - <List :grid="grid" :data-source="textComponentConfig"> | |
29 | - <template #renderItem="{ item }"> | |
30 | - <List.Item class="!flex !justify-center"> | |
31 | - <VisualWidgetSelect | |
32 | - :checked-id="props.value" | |
33 | - :control-id="item.id" | |
34 | - @change="handleCheck" | |
35 | - > | |
36 | - <TextComponent :layout="item" :value="item.value" /> | |
37 | - </VisualWidgetSelect> | |
38 | - </List.Item> | |
39 | - </template> | |
40 | - </List> | |
41 | - </Tabs.TabPane> | |
42 | - <Tabs.TabPane key="2" tab="图片组件"> | |
43 | - <List :grid="grid" :data-source="pictureComponentList"> | |
44 | - <template #renderItem="{ item }"> | |
45 | - <List.Item class="!flex !justify-center"> | |
46 | - <VisualWidgetSelect | |
47 | - :checked-id="props.value" | |
48 | - :control-id="item.id" | |
49 | - @change="handleCheck" | |
50 | - > | |
51 | - <component :is="item.component" /> | |
52 | - </VisualWidgetSelect> | |
53 | - </List.Item> | |
54 | - </template> | |
55 | - </List> | |
56 | - </Tabs.TabPane> | |
57 | - <Tabs.TabPane key="3" tab="仪表组件"> | |
58 | - <List :grid="grid" :data-source="instrumentComponentConfig"> | |
53 | + <Tabs.TabPane | |
54 | + v-for="category in getDataSource" | |
55 | + :key="category.category" | |
56 | + :tab="category.categoryName" | |
57 | + > | |
58 | + <List :grid="grid" :data-source="category.list"> | |
59 | 59 | <template #renderItem="{ item }"> |
60 | 60 | <List.Item class="!flex !justify-center"> |
61 | 61 | <VisualWidgetSelect |
62 | 62 | :checked-id="props.value" |
63 | - :control-id="item.id" | |
63 | + :control-id="item.ComponentKey" | |
64 | 64 | @change="handleCheck" |
65 | 65 | > |
66 | - <component | |
67 | - :is="item.component" | |
68 | - :random="true" | |
69 | - :layout="item.layout" | |
70 | - :value="item.value" | |
71 | - /> | |
66 | + <template #default> | |
67 | + <component :is="item.Component" :random="true" :layout="item.ComponentConfig" /> | |
68 | + </template> | |
69 | + <template #description> | |
70 | + {{ item.ComponentName || '选择' }} | |
71 | + </template> | |
72 | 72 | </VisualWidgetSelect> |
73 | 73 | </List.Item> |
74 | 74 | </template> | ... | ... |
1 | 1 | <script lang="ts" setup> |
2 | 2 | import { ref, unref } from 'vue'; |
3 | - import { | |
4 | - WidgetComponentType, | |
5 | - schemasMap, | |
6 | - VisualOptionParams, | |
7 | - visualOptionField, | |
8 | - Gradient, | |
9 | - } from '../config/visualOptions'; | |
3 | + import { schemasMap, VisualOptionParams } from '../config/visualOptions'; | |
10 | 4 | import { useForm, BasicForm } from '/@/components/Form'; |
11 | 5 | import { BasicModal, useModalInner } from '/@/components/Modal'; |
12 | 6 | import { ComponentInfo } from '/@/api/dataBoard/model'; |
13 | 7 | import { computed } from '@vue/reactivity'; |
8 | + import { FrontComponent, Gradient, visualOptionField } from '../../const/const'; | |
14 | 9 | |
15 | 10 | const emit = defineEmits(['close', 'register']); |
16 | 11 | |
... | ... | @@ -21,7 +16,7 @@ |
21 | 16 | const recordId = ref(''); |
22 | 17 | |
23 | 18 | const getSchemas = computed(() => { |
24 | - return schemasMap.get((props.value as WidgetComponentType) || 'text-component-1'); | |
19 | + return schemasMap.get((props.value as FrontComponent) || 'text-component-1'); | |
25 | 20 | }); |
26 | 21 | |
27 | 22 | const [registerForm, method] = useForm({ | ... | ... |
... | ... | @@ -30,16 +30,19 @@ |
30 | 30 | <slot></slot> |
31 | 31 | </div> |
32 | 32 | <Card.Meta> |
33 | - <template #description> 选择 </template> | |
33 | + <template #description> | |
34 | + <slot name="description"></slot> | |
35 | + </template> | |
34 | 36 | </Card.Meta> |
35 | 37 | </Card> |
36 | 38 | </template> |
37 | 39 | |
38 | 40 | <style scoped> |
39 | 41 | .widget-select { |
40 | - box-shadow: 0px 1px 10px 0px rgba(0, 0, 0, 0.1); | |
42 | + box-shadow: 0 1px 10px 0 rgba(0, 0, 0, 0.1); | |
41 | 43 | border-width: 2px; |
42 | 44 | } |
45 | + | |
43 | 46 | .widget-select:deep(.ant-card-body) { |
44 | 47 | /* height: 240px; */ |
45 | 48 | width: 240px; | ... | ... |
... | ... | @@ -217,3 +217,24 @@ export const dataSourceSchema: FormSchema[] = [ |
217 | 217 | }, |
218 | 218 | }, |
219 | 219 | ]; |
220 | + | |
221 | +export const controlFormSchema: FormSchema[] = [ | |
222 | + { | |
223 | + field: DataSourceField.DEVICE_RENAME, | |
224 | + component: 'Input', | |
225 | + label: '设备', | |
226 | + colProps: { span: 8 }, | |
227 | + componentProps: { | |
228 | + placeholder: '设备重命名', | |
229 | + }, | |
230 | + }, | |
231 | + { | |
232 | + field: DataSourceField.ATTRIBUTE_RENAME, | |
233 | + component: 'Input', | |
234 | + label: '属性', | |
235 | + colProps: { span: 8 }, | |
236 | + componentProps: { | |
237 | + placeholder: '属性重命名', | |
238 | + }, | |
239 | + }, | |
240 | +]; | ... | ... |
src/views/visual/board/detail/config/help.ts
deleted
100644 → 0
1 | -import { Component } from 'vue'; | |
2 | -import TextComponent from '../../components/TextComponent/TextComponent.vue'; | |
3 | -import { | |
4 | - TextComponent1Config, | |
5 | - TextComponent2Config, | |
6 | - TextComponent3Config, | |
7 | - TextComponent4Config, | |
8 | - TextComponent5Config, | |
9 | - TextComponentDefaultConfig, | |
10 | - transformTextComponentConfig, | |
11 | -} from '../../components/TextComponent/config'; | |
12 | -import { ComponentInfo, DataComponentRecord, DataSource } from '/@/api/dataBoard/model'; | |
13 | -import DashBoardComponent from '../../components/InstrumentComponent/DashBoardComponent.vue'; | |
14 | -import PictureComponent from '../../components/PictureComponent/PictureComponent.vue'; | |
15 | -import { transformPictureConfig } from '../../components/PictureComponent/pictureComponent.config'; | |
16 | -import { WidgetComponentType } from './visualOptions'; | |
17 | -import { | |
18 | - DashboardComponentLayout, | |
19 | - Instrument1DefaultConfig, | |
20 | - Instrument2DefaultConfig, | |
21 | - instrumentComponent1, | |
22 | - instrumentComponent2, | |
23 | - transformDashboardComponentConfig, | |
24 | -} from '../../components/InstrumentComponent/dashBoardComponent.config'; | |
25 | -import DigitalDashBoard from '../../components/InstrumentComponent/DigitalDashBoard.vue'; | |
26 | -import { DigitalComponentDefaultConfig } from '../../components/InstrumentComponent/digitalDashBoard.config'; | |
27 | -export enum FrontComponent { | |
28 | - TEXT_COMPONENT_1 = 'text-component-1', | |
29 | - TEXT_COMPONENT_2 = 'text-component-2', | |
30 | - TEXT_COMPONENT_3 = 'text-component-3', | |
31 | - TEXT_COMPONENT_4 = 'text-component-4', | |
32 | - TEXT_COMPONENT_5 = 'text-component-5', | |
33 | - INSTRUMENT_COMPONENT_1 = 'instrument-component-1', | |
34 | - INSTRUMENT_COMPONENT_2 = 'instrument-component-2', | |
35 | - DIGITAL_DASHBOARD_COMPONENT = 'digital-dashboard-component', | |
36 | - PICTURE_COMPONENT_1 = 'picture-component-1', | |
37 | -} | |
38 | - | |
39 | -export interface ComponentConfig { | |
40 | - Component: Component; | |
41 | - ComponentConfig: Recordable; | |
42 | - transformConfig: ( | |
43 | - ComponentConfig: Recordable, | |
44 | - record: DataComponentRecord, | |
45 | - dataSourceRecord: DataSource | |
46 | - ) => Recordable; | |
47 | -} | |
48 | - | |
49 | -export const frontComponentDefaultConfigMap = new Map< | |
50 | - WidgetComponentType, | |
51 | - Partial<ComponentInfo> | |
52 | ->(); | |
53 | - | |
54 | -export const frontComponentMap = new Map<WidgetComponentType, ComponentConfig>(); | |
55 | - | |
56 | -frontComponentMap.set(FrontComponent.TEXT_COMPONENT_1, { | |
57 | - Component: TextComponent, | |
58 | - ComponentConfig: TextComponent1Config, | |
59 | - transformConfig: transformTextComponentConfig, | |
60 | -}); | |
61 | - | |
62 | -frontComponentMap.set(FrontComponent.TEXT_COMPONENT_2, { | |
63 | - Component: TextComponent, | |
64 | - ComponentConfig: TextComponent2Config, | |
65 | - transformConfig: transformTextComponentConfig, | |
66 | -}); | |
67 | - | |
68 | -frontComponentMap.set(FrontComponent.TEXT_COMPONENT_3, { | |
69 | - Component: TextComponent, | |
70 | - ComponentConfig: TextComponent3Config, | |
71 | - transformConfig: transformTextComponentConfig, | |
72 | -}); | |
73 | - | |
74 | -frontComponentMap.set(FrontComponent.TEXT_COMPONENT_4, { | |
75 | - Component: TextComponent, | |
76 | - ComponentConfig: TextComponent4Config, | |
77 | - transformConfig: transformTextComponentConfig, | |
78 | -}); | |
79 | - | |
80 | -frontComponentMap.set(FrontComponent.TEXT_COMPONENT_5, { | |
81 | - Component: TextComponent, | |
82 | - ComponentConfig: TextComponent5Config, | |
83 | - transformConfig: transformTextComponentConfig, | |
84 | -}); | |
85 | - | |
86 | -frontComponentMap.set(FrontComponent.INSTRUMENT_COMPONENT_1, { | |
87 | - Component: DashBoardComponent, | |
88 | - ComponentConfig: { | |
89 | - chartOption: instrumentComponent1(), | |
90 | - componentType: FrontComponent.INSTRUMENT_COMPONENT_1, | |
91 | - } as DashboardComponentLayout, | |
92 | - transformConfig: transformDashboardComponentConfig, | |
93 | -}); | |
94 | - | |
95 | -frontComponentMap.set(FrontComponent.INSTRUMENT_COMPONENT_2, { | |
96 | - Component: DashBoardComponent, | |
97 | - ComponentConfig: { | |
98 | - chartOption: instrumentComponent2(), | |
99 | - componentType: FrontComponent.INSTRUMENT_COMPONENT_2, | |
100 | - } as DashboardComponentLayout, | |
101 | - transformConfig: transformDashboardComponentConfig, | |
102 | -}); | |
103 | - | |
104 | -frontComponentMap.set(FrontComponent.DIGITAL_DASHBOARD_COMPONENT, { | |
105 | - Component: DigitalDashBoard, | |
106 | - ComponentConfig: {}, | |
107 | - transformConfig: transformDashboardComponentConfig, | |
108 | -}); | |
109 | - | |
110 | -frontComponentMap.set(FrontComponent.PICTURE_COMPONENT_1, { | |
111 | - Component: PictureComponent, | |
112 | - ComponentConfig: {}, | |
113 | - transformConfig: transformPictureConfig, | |
114 | -}); | |
115 | - | |
116 | -frontComponentDefaultConfigMap.set(FrontComponent.TEXT_COMPONENT_1, TextComponentDefaultConfig); | |
117 | -frontComponentDefaultConfigMap.set(FrontComponent.TEXT_COMPONENT_2, TextComponentDefaultConfig); | |
118 | -frontComponentDefaultConfigMap.set(FrontComponent.TEXT_COMPONENT_3, TextComponentDefaultConfig); | |
119 | -frontComponentDefaultConfigMap.set(FrontComponent.TEXT_COMPONENT_4, TextComponentDefaultConfig); | |
120 | -frontComponentDefaultConfigMap.set(FrontComponent.TEXT_COMPONENT_5, TextComponentDefaultConfig); | |
121 | - | |
122 | -frontComponentDefaultConfigMap.set(FrontComponent.INSTRUMENT_COMPONENT_1, Instrument1DefaultConfig); | |
123 | -frontComponentDefaultConfigMap.set(FrontComponent.INSTRUMENT_COMPONENT_2, Instrument2DefaultConfig); | |
124 | - | |
125 | -frontComponentDefaultConfigMap.set( | |
126 | - FrontComponent.DIGITAL_DASHBOARD_COMPONENT, | |
127 | - DigitalComponentDefaultConfig | |
128 | -); | |
129 | - | |
130 | -export const getComponentDefaultConfig = (key: WidgetComponentType) => { | |
131 | - return frontComponentDefaultConfigMap.get(key) || {}; | |
132 | -}; |
1 | +import { dateUtil } from '/@/utils/dateUtil'; | |
2 | + | |
1 | 3 | export interface RadioRecord { |
2 | 4 | width: number; |
3 | 5 | height: number; |
... | ... | @@ -16,6 +18,10 @@ export const DEFAULT_RADIO_RECORD: RadioRecord = { |
16 | 18 | |
17 | 19 | export const DEFAULT_DATE_FORMAT = 'YYYY-MM-DD HH:mm:ss'; |
18 | 20 | |
21 | +export const getUpdateTime = (updateTime?: string) => { | |
22 | + return updateTime ? dateUtil(updateTime).format(DEFAULT_DATE_FORMAT) : '暂无更新时间'; | |
23 | +}; | |
24 | + | |
19 | 25 | export const calcScale = ( |
20 | 26 | width: number, |
21 | 27 | height: number, | ... | ... |
1 | -import { InstrumentComponentType } from '../../components/InstrumentComponent/dashBoardComponent.config'; | |
2 | -import { DigitalDashBoardComponentType } from '../../components/InstrumentComponent/digitalDashBoard.config'; | |
3 | -import { PictureComponentType } from '../../components/PictureComponent/pictureComponent.config'; | |
4 | -import { TextComponentType } from '../../components/TextComponent/config'; | |
1 | +import { FrontComponent, GradientColor } from '../../const/const'; | |
5 | 2 | import { FormSchema } from '/@/components/Form'; |
6 | 3 | |
7 | -export type WidgetComponentType = | |
8 | - | TextComponentType | |
9 | - | InstrumentComponentType | |
10 | - | DigitalDashBoardComponentType | |
11 | - | PictureComponentType; | |
12 | - | |
13 | 4 | export interface VisualOptionParams { |
14 | 5 | [visualOptionField.FONT_COLOR]: string; |
15 | 6 | [visualOptionField.UNIT]: string; |
... | ... | @@ -23,17 +14,6 @@ export interface VisualOptionParams { |
23 | 14 | [visualOptionField.THIRD_PHASE_VALUE]: string; |
24 | 15 | } |
25 | 16 | |
26 | -export enum Gradient { | |
27 | - FIRST = 'first', | |
28 | - SECOND = 'second', | |
29 | - THIRD = 'third', | |
30 | -} | |
31 | -export enum GradientColor { | |
32 | - FIRST = '#67e0e3', | |
33 | - SECOND = '#37a2da', | |
34 | - THIRD = '#fd666d', | |
35 | -} | |
36 | - | |
37 | 17 | export enum visualOptionField { |
38 | 18 | FONT_COLOR = 'fontColor', |
39 | 19 | UNIT = 'unit', |
... | ... | @@ -198,13 +178,13 @@ export const modeFour: FormSchema[] = [ |
198 | 178 | }, |
199 | 179 | ]; |
200 | 180 | |
201 | -export const schemasMap = new Map<WidgetComponentType, FormSchema[]>(); | |
181 | +export const schemasMap = new Map<FrontComponent, FormSchema[]>(); | |
202 | 182 | |
203 | -schemasMap.set('text-component-1', modeOne); | |
204 | -schemasMap.set('text-component-2', modeOne); | |
205 | -schemasMap.set('text-component-3', modeOne); | |
206 | -schemasMap.set('text-component-4', modeTwo); | |
207 | -schemasMap.set('text-component-5', modeTwo); | |
208 | -schemasMap.set('instrument-component-1', modeOne); | |
209 | -schemasMap.set('instrument-component-2', modeThree); | |
210 | -schemasMap.set('digital-dashboard-component', modeFour); | |
183 | +schemasMap.set(FrontComponent.TEXT_COMPONENT_1, modeOne); | |
184 | +schemasMap.set(FrontComponent.TEXT_COMPONENT_2, modeOne); | |
185 | +schemasMap.set(FrontComponent.TEXT_COMPONENT_3, modeOne); | |
186 | +schemasMap.set(FrontComponent.TEXT_COMPONENT_4, modeTwo); | |
187 | +schemasMap.set(FrontComponent.TEXT_COMPONENT_5, modeTwo); | |
188 | +schemasMap.set(FrontComponent.INSTRUMENT_COMPONENT_1, modeOne); | |
189 | +schemasMap.set(FrontComponent.INSTRUMENT_COMPONENT_2, modeThree); | |
190 | +schemasMap.set(FrontComponent.DIGITAL_DASHBOARD_COMPONENT, modeFour); | ... | ... |
... | ... | @@ -16,6 +16,7 @@ |
16 | 16 | DEFAULT_WIDGET_WIDTH, |
17 | 17 | isBataBoardSharePage, |
18 | 18 | MoreActionEvent, |
19 | + VisualComponentPermission, | |
19 | 20 | } from '../config/config'; |
20 | 21 | import { |
21 | 22 | addDataComponent, |
... | ... | @@ -32,11 +33,10 @@ |
32 | 33 | DataSource, |
33 | 34 | Layout, |
34 | 35 | } from '/@/api/dataBoard/model'; |
35 | - import { frontComponentMap } from './config/help'; | |
36 | + import { frontComponentMap } from '../components/help'; | |
36 | 37 | import { calcScale } from './config/util'; |
37 | 38 | import { useMessage } from '/@/hooks/web/useMessage'; |
38 | 39 | import { DataBoardLayoutInfo } from '../types/type'; |
39 | - import { WidgetComponentType } from './config/visualOptions'; | |
40 | 40 | import Authority from '/@/components/Authority/src/Authority.vue'; |
41 | 41 | import { useSocketConnect } from '../hook/useSocketConnect'; |
42 | 42 | import { buildUUID } from '/@/utils/uuid'; |
... | ... | @@ -44,6 +44,7 @@ |
44 | 44 | import trendIcon from '/@/assets/svg/trend.svg'; |
45 | 45 | import backIcon from '/@/assets/images/back.png'; |
46 | 46 | import { useCalcGridLayout } from '../hook/useCalcGridLayout'; |
47 | + import { FrontComponent } from '../const/const'; | |
47 | 48 | |
48 | 49 | const ROUTE = useRoute(); |
49 | 50 | |
... | ... | @@ -298,7 +299,7 @@ |
298 | 299 | |
299 | 300 | const getComponent = (record: DataComponentRecord) => { |
300 | 301 | const frontComponent = record.frontId; |
301 | - const component = frontComponentMap.get(frontComponent as WidgetComponentType); | |
302 | + const component = frontComponentMap.get(frontComponent as FrontComponent); | |
302 | 303 | return component?.Component; |
303 | 304 | }; |
304 | 305 | |
... | ... | @@ -307,8 +308,8 @@ |
307 | 308 | dataSourceRecord: DataSource |
308 | 309 | ) => { |
309 | 310 | const frontComponent = record.frontId; |
310 | - const component = frontComponentMap.get(frontComponent as WidgetComponentType); | |
311 | - return component?.transformConfig(component.ComponentConfig, record, dataSourceRecord); | |
311 | + const component = frontComponentMap.get(frontComponent as FrontComponent); | |
312 | + return component?.transformConfig(component.ComponentConfig || {}, record, dataSourceRecord); | |
312 | 313 | }; |
313 | 314 | |
314 | 315 | const handleUpdate = async (id: string) => { |
... | ... | @@ -360,9 +361,7 @@ |
360 | 361 | await deleteDataComponent({ dataBoardId, ids: [id] }); |
361 | 362 | createMessage.success('删除成功'); |
362 | 363 | await getDataBoardComponent(); |
363 | - } catch (error) { | |
364 | - // createMessage.error('删除失败'); | |
365 | - } | |
364 | + } catch (error) {} | |
366 | 365 | }; |
367 | 366 | |
368 | 367 | const [registerHistoryDataModal, historyDataModalMethod] = useModal(); |
... | ... | @@ -391,7 +390,7 @@ |
391 | 390 | </div> |
392 | 391 | </template> |
393 | 392 | <template #extra> |
394 | - <Authority value="api:yt:data_component:add:post"> | |
393 | + <Authority :value="VisualComponentPermission.CREATE"> | |
395 | 394 | <Button v-if="!getIsSharePage" type="primary" @click="handleOpenCreatePanel"> |
396 | 395 | 创建组件 |
397 | 396 | </Button> |
... | ... | @@ -439,7 +438,6 @@ |
439 | 438 | :data-source="item.record.dataSource" |
440 | 439 | > |
441 | 440 | <template #header> |
442 | - <!-- <div>header</div> --> | |
443 | 441 | <BaseWidgetHeader |
444 | 442 | :record="item.record.dataSource" |
445 | 443 | :id="item.record.id" |
... | ... | @@ -448,11 +446,6 @@ |
448 | 446 | > |
449 | 447 | <template #moreAction> |
450 | 448 | <Tooltip title="趋势"> |
451 | - <!-- <LineChartOutlined | |
452 | - v-if="!getIsSharePage" | |
453 | - class="cursor-pointer mx-1" | |
454 | - @click="handleOpenHistroyDataModal(item.record.dataSource)" | |
455 | - /> --> | |
456 | 449 | <img |
457 | 450 | :src="trendIcon" |
458 | 451 | v-if="!getIsSharePage" |
... | ... | @@ -494,14 +487,18 @@ |
494 | 487 | .vue-grid-item:not(.vue-grid-placeholder) { |
495 | 488 | background: #fff; |
496 | 489 | border: none !important; |
490 | + | |
497 | 491 | /* border: 1px solid black; */ |
498 | 492 | } |
493 | + | |
499 | 494 | .vue-grid-item .resizing { |
500 | 495 | opacity: 0.9; |
501 | 496 | } |
497 | + | |
502 | 498 | .vue-grid-item .static { |
503 | 499 | background: #cce; |
504 | 500 | } |
501 | + | |
505 | 502 | .vue-grid-item .text { |
506 | 503 | font-size: 24px; |
507 | 504 | text-align: center; |
... | ... | @@ -514,16 +511,20 @@ |
514 | 511 | height: 100%; |
515 | 512 | width: 100%; |
516 | 513 | } |
514 | + | |
517 | 515 | .vue-grid-item .no-drag { |
518 | 516 | height: 100%; |
519 | 517 | width: 100%; |
520 | 518 | } |
519 | + | |
521 | 520 | .vue-grid-item .minMax { |
522 | 521 | font-size: 12px; |
523 | 522 | } |
523 | + | |
524 | 524 | .vue-grid-item .add { |
525 | 525 | cursor: pointer; |
526 | 526 | } |
527 | + | |
527 | 528 | .vue-draggable-handle { |
528 | 529 | position: absolute; |
529 | 530 | width: 20px; |
... | ... | @@ -540,12 +541,6 @@ |
540 | 541 | cursor: pointer; |
541 | 542 | } |
542 | 543 | |
543 | - // .container { | |
544 | - // display: grid; | |
545 | - // grid-template-columns: 3; | |
546 | - // grid-row: 3; | |
547 | - // } | |
548 | - | |
549 | 544 | .grid-item-layout { |
550 | 545 | overflow: hidden; |
551 | 546 | border: 1px solid #eee !important; | ... | ... |
... | ... | @@ -7,7 +7,7 @@ |
7 | 7 | import { useMessage } from '/@/hooks/web/useMessage'; |
8 | 8 | import Dropdown from '/@/components/Dropdown/src/Dropdown.vue'; |
9 | 9 | import { DropMenu } from '/@/components/Dropdown'; |
10 | - import { DATA_BOARD_SHARE_URL, MoreActionEvent } from './config/config'; | |
10 | + import { DATA_BOARD_SHARE_URL, MoreActionEvent, VisualBoardPermission } from './config/config'; | |
11 | 11 | import { useModal } from '/@/components/Modal'; |
12 | 12 | import PanelDetailModal from './components/PanelDetailModal.vue'; |
13 | 13 | import { getDataBoardList, deleteDataBoard } from '/@/api/dataBoard'; |
... | ... | @@ -36,7 +36,7 @@ |
36 | 36 | labelWidth: 80, |
37 | 37 | layout: 'inline', |
38 | 38 | submitButtonOptions: { |
39 | - loading: loading, | |
39 | + loading: loading as unknown as boolean, | |
40 | 40 | }, |
41 | 41 | submitFunc: async () => { |
42 | 42 | try { |
... | ... | @@ -51,7 +51,7 @@ |
51 | 51 | }, |
52 | 52 | }); |
53 | 53 | |
54 | - //分页相关 | |
54 | + // about pagination | |
55 | 55 | const page = ref(1); |
56 | 56 | const pageSize = ref(10); |
57 | 57 | const total = ref(0); |
... | ... | @@ -90,8 +90,8 @@ |
90 | 90 | |
91 | 91 | const { hasPermission } = usePermission(); |
92 | 92 | const dropMenuList = computed<DropMenu[]>(() => { |
93 | - const hasUpdatePermission = hasPermission('api:yt:data_board:update:update'); | |
94 | - const hasDeletePermission = hasPermission('api:yt:data_board:delete'); | |
93 | + const hasUpdatePermission = hasPermission(VisualBoardPermission.UPDATE); | |
94 | + const hasDeletePermission = hasPermission(VisualBoardPermission.DELETE); | |
95 | 95 | const basicMenu: DropMenu[] = []; |
96 | 96 | if (hasUpdatePermission) |
97 | 97 | basicMenu.push({ |
... | ... | @@ -147,31 +147,21 @@ |
147 | 147 | }; |
148 | 148 | |
149 | 149 | const handleRemove = async (record: DataBoardRecord) => { |
150 | - // TODO 删除确认 | |
151 | 150 | try { |
152 | 151 | await deleteDataBoard([record.id]); |
153 | 152 | createMessage.success('删除成功'); |
154 | 153 | await getDatasource(); |
155 | - } catch (error) { | |
156 | - // createMessage.error('删除失败'); | |
157 | - } | |
154 | + } catch (error) {} | |
158 | 155 | }; |
159 | 156 | |
160 | 157 | const [registerModal, { openModal }] = useModal(); |
161 | 158 | |
162 | 159 | const handleViewBoard = (record: DataBoardRecord) => { |
163 | - const hasDetailPermission = hasPermission('api:yt:data_component:list'); | |
160 | + const hasDetailPermission = hasPermission(VisualBoardPermission.DETAIL); | |
164 | 161 | if (hasDetailPermission) { |
165 | 162 | const boardId = encode(record.id); |
166 | 163 | const boardName = encode(record.name); |
167 | 164 | router.push(`/visual/board/detail/${boardId}/${boardName}`); |
168 | - // router.push({ | |
169 | - // name: 'visualBoardDetail' | |
170 | - // params: { | |
171 | - // boardId: encode(record.id), | |
172 | - // boardName: encode(record.name), | |
173 | - // }, | |
174 | - // }); | |
175 | 165 | } else createMessage.warning('没有权限'); |
176 | 166 | }; |
177 | 167 | |
... | ... | @@ -186,8 +176,6 @@ |
186 | 176 | '.ant-spin-container' |
187 | 177 | ) as HTMLElement; |
188 | 178 | listContainerEl && |
189 | - // (listContainerEl.style.minHeight = listContainerHeight + 'px') && | |
190 | - // (listContainerEl.style.maxHeight = listContainerHeight + 'px') && | |
191 | 179 | (listContainerEl.style.height = listContainerHeight + 'px') && |
192 | 180 | (listContainerEl.style.overflowY = 'auto') && |
193 | 181 | (listContainerEl.style.overflowX = 'hidden'); |
... | ... | @@ -210,7 +198,6 @@ |
210 | 198 | <div class="bg-light-100 mb-6 w-full p-3 search-form"> |
211 | 199 | <BasicForm class="flex-auto w-full" @register="searchFormRegister" /> |
212 | 200 | </div> |
213 | - <!-- <div> </div> --> | |
214 | 201 | <Spin :spinning="loading"> |
215 | 202 | <List |
216 | 203 | ref="listEL" |
... | ... | @@ -235,7 +222,6 @@ |
235 | 222 | <MoreOutlined class="rotate-90 transform cursor-pointer" /> |
236 | 223 | </Dropdown> |
237 | 224 | </template> |
238 | - <!-- <template #cover>title</template> --> | |
239 | 225 | <section @click="handleViewBoard(item)"> |
240 | 226 | <div class="flex data-card__info"> |
241 | 227 | <div> |
... | ... | @@ -247,16 +233,19 @@ |
247 | 233 | </Statistic> |
248 | 234 | </div> |
249 | 235 | </div> |
250 | - <div class="flex justify-between mt-4 text-sm" style="color: #999999"> | |
236 | + <div class="flex justify-between mt-4 text-sm" style="color: #999"> | |
251 | 237 | <div> |
252 | 238 | <span> |
253 | 239 | {{ item.viewType === ViewType.PRIVATE_VIEW ? '私有看板' : '公共看板' }} |
254 | 240 | </span> |
255 | - <!-- <span v-if="item.viewType === ViewType.PUBLIC_VIEW"> | |
241 | + <span | |
242 | + style="display: none" | |
243 | + v-if="item.viewType === ViewType.PUBLIC_VIEW && false" | |
244 | + > | |
256 | 245 | <Tooltip title="点击复制分享链接"> |
257 | 246 | <ShareAltOutlined class="ml-2" @click.stop="handleCopyShareUrl(item)" /> |
258 | 247 | </Tooltip> |
259 | - </span> --> | |
248 | + </span> | |
260 | 249 | </div> |
261 | 250 | <div>{{ item.createTime }}</div> |
262 | 251 | </div> |
... | ... | @@ -278,15 +267,17 @@ |
278 | 267 | .data-card:deep(.ant-card-head-title) { |
279 | 268 | padding: 0; |
280 | 269 | } |
270 | + | |
281 | 271 | .data-card:deep(.ant-card-extra) { |
282 | 272 | padding: 0; |
283 | 273 | } |
274 | + | |
284 | 275 | .data-card:deep(.ant-card-body) { |
285 | 276 | padding: 20px; |
286 | 277 | } |
287 | 278 | |
288 | 279 | .data-card__info { |
289 | - color: #666666; | |
280 | + color: #666; | |
290 | 281 | |
291 | 282 | &::before { |
292 | 283 | content: ''; |
... | ... | @@ -299,8 +290,10 @@ |
299 | 290 | |
300 | 291 | .search-form { |
301 | 292 | width: 100%; |
293 | + | |
302 | 294 | form { |
303 | 295 | width: 100%; |
296 | + | |
304 | 297 | :deep(.ant-row) { |
305 | 298 | width: 100%; |
306 | 299 | } | ... | ... |
1 | +import { Component } from 'vue'; | |
1 | 2 | import { Layout } from 'vue3-grid-layout'; |
3 | +import { FrontComponent, FrontComponentCategory, visualOptionField } from '../const/const'; | |
4 | +import { RadioRecord } from '../detail/config/util'; | |
2 | 5 | import { DataComponentRecord, DataSource } from '/@/api/dataBoard/model'; |
3 | 6 | |
4 | 7 | export type FrontDataSourceRecord = DataSource; |
... | ... | @@ -8,3 +11,39 @@ export type DataBoardLayoutInfo = Layout & { |
8 | 11 | width?: number; |
9 | 12 | height?: number; |
10 | 13 | }; |
14 | + | |
15 | +export interface ComponentConfig { | |
16 | + Component: Component; | |
17 | + ComponentName?: string; | |
18 | + ComponentKey: FrontComponent; | |
19 | + ComponentConfig?: Recordable; | |
20 | + ComponentCategory: FrontComponentCategory; | |
21 | + transformConfig: ( | |
22 | + componentConfig: Recordable, | |
23 | + record: DataComponentRecord, | |
24 | + dataSourceRecord: DataSource | |
25 | + ) => Recordable; | |
26 | +} | |
27 | + | |
28 | +export interface VisualOptionParams { | |
29 | + [visualOptionField.FONT_COLOR]: string; | |
30 | + [visualOptionField.UNIT]: string; | |
31 | + [visualOptionField.ICON_COLOR]: string; | |
32 | + [visualOptionField.ICON]: string; | |
33 | + [visualOptionField.FIRST_PHASE_COLOR]: string; | |
34 | + [visualOptionField.SECOND_PHASE_COLOR]: string; | |
35 | + [visualOptionField.THIRD_PHASE_COLOR]: string; | |
36 | + [visualOptionField.FIRST_PHASE_VALUE]: string; | |
37 | + [visualOptionField.SECOND_PHASE_VALUE]: string; | |
38 | + [visualOptionField.THIRD_PHASE_VALUE]: string; | |
39 | +} | |
40 | + | |
41 | +export interface VisualComponentProps<Layout = Recordable, Value = Recordable> { | |
42 | + value?: Value; | |
43 | + layout?: Layout; | |
44 | + radio?: RadioRecord; | |
45 | + random?: boolean; | |
46 | + add?: (key: string, method: Fn) => void; | |
47 | + update?: () => void; | |
48 | + remove?: (key: string) => void; | |
49 | +} | ... | ... |