Commit 607e8c7249a0d04a01bee8be38073a152e97b32d

Authored by fengtao
2 parents c06c58dc 23345cac

Merge branch 'main' into ft_local_dev

Showing 53 changed files with 1447 additions and 691 deletions
@@ -22,7 +22,6 @@ @@ -22,7 +22,6 @@
22 theme = htmlRoot = null; 22 theme = htmlRoot = null;
23 } 23 }
24 })(); 24 })();
25 -  
26 </script> 25 </script>
27 <div id="app"> 26 <div id="app">
28 <style> 27 <style>
@@ -152,17 +151,17 @@ @@ -152,17 +151,17 @@
152 } 151 }
153 } 152 }
154 </style> 153 </style>
155 - <div class="app-loading"> 154 + <div id="first-screen-loading" class="app-loading">
156 <div class="app-loading-wrap"> 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 <div class="app-loading-dots"> 157 <div class="app-loading-dots">
159 <span class="dot dot-spin"><i></i><i></i><i></i><i></i></span> 158 <span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
160 </div> 159 </div>
161 - <div class="app-loading-title"><%= title %></div> 160 + <!-- <div class="app-loading-title"><%= title %></div> -->
162 </div> 161 </div>
163 </div> 162 </div>
164 </div> 163 </div>
165 - 164 +
166 <script type="module" src="/src/main.ts"></script> 165 <script type="module" src="/src/main.ts"></script>
167 </body> 166 </body>
168 </html> 167 </html>
1 import { defHttp } from '/@/utils/http/axios'; 1 import { defHttp } from '/@/utils/http/axios';
2 -import { FileUploadResponse } from './model/index'; 2 +import { FileUploadResponse, Platform } from './model/index';
3 enum API { 3 enum API {
4 SELECT_DETAIL = '/enterprise/get', 4 SELECT_DETAIL = '/enterprise/get',
5 UPDATE_DETAIL = '/enterprise/update', 5 UPDATE_DETAIL = '/enterprise/update',
@@ -67,7 +67,7 @@ export const bgUpload = (file) => { @@ -67,7 +67,7 @@ export const bgUpload = (file) => {
67 67
68 // 获取平台定制详情 68 // 获取平台定制详情
69 export const getPlatForm = () => { 69 export const getPlatForm = () => {
70 - return defHttp.get({ 70 + return defHttp.get<Platform>({
71 url: API.SELECT_PLATFORM, 71 url: API.SELECT_PLATFORM,
72 }); 72 });
73 }; 73 };
@@ -5,3 +5,17 @@ export interface FileUploadResponse { @@ -5,3 +5,17 @@ export interface FileUploadResponse {
5 size: number; 5 size: number;
6 fileStaticUri: string; 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,6 +10,7 @@ export { default as ApiSelect } from './src/components/ApiSelect.vue';
10 export { default as RadioButtonGroup } from './src/components/RadioButtonGroup.vue'; 10 export { default as RadioButtonGroup } from './src/components/RadioButtonGroup.vue';
11 export { default as ApiTreeSelect } from './src/components/ApiTreeSelect.vue'; 11 export { default as ApiTreeSelect } from './src/components/ApiTreeSelect.vue';
12 export { default as ApiRadioGroup } from './src/components/ApiRadioGroup.vue'; 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 export { 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,6 +14,7 @@ import { setupGlobDirectives } from '/@/directives';
14 import { setupI18n } from '/@/locales/setupI18n'; 14 import { setupI18n } from '/@/locales/setupI18n';
15 import { registerGlobComp } from '/@/components/registerGlobComp'; 15 import { registerGlobComp } from '/@/components/registerGlobComp';
16 import '/@/assets/iconfont/iconfont'; 16 import '/@/assets/iconfont/iconfont';
  17 +import { usePlatform } from './views/system/customize/hook/usePlatformInfo';
17 18
18 if (import.meta.env.DEV) { 19 if (import.meta.env.DEV) {
19 import('ant-design-vue/dist/antd.less'); 20 import('ant-design-vue/dist/antd.less');
@@ -23,6 +24,8 @@ async function bootstrap() { @@ -23,6 +24,8 @@ async function bootstrap() {
23 // Configure store 24 // Configure store
24 setupStore(app); 25 setupStore(app);
25 26
  27 + await usePlatform();
  28 +
26 // Initialize internal system configuration 29 // Initialize internal system configuration
27 initAppConfigStore(); 30 initAppConfigStore();
28 31
@@ -47,6 +50,7 @@ async function bootstrap() { @@ -47,6 +50,7 @@ async function bootstrap() {
47 // Mount when the route is ready 50 // Mount when the route is ready
48 // https://next.router.vuejs.org/api/#isready 51 // https://next.router.vuejs.org/api/#isready
49 await router.isReady(); 52 await router.isReady();
  53 +
50 app.mount('#app', true); 54 app.mount('#app', true);
51 } 55 }
52 56
@@ -39,7 +39,7 @@ @@ -39,7 +39,7 @@
39 width: '200px', 39 width: '200px',
40 height: '200px', 40 height: '200px',
41 color: '#409eff', 41 color: '#409eff',
42 - muted: false, //静音 42 + muted: true, //静音
43 webFullScreen: false, 43 webFullScreen: false,
44 autoPlay: true, //自动播放 44 autoPlay: true, //自动播放
45 currentTime: 0, 45 currentTime: 0,
@@ -238,7 +238,7 @@ @@ -238,7 +238,7 @@
238 class="h-full flex flex-col justify-center items-center" 238 class="h-full flex flex-col justify-center items-center"
239 v-if="!cameraList.length" 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 <Col 242 <Col
243 v-for="item in cameraList" 243 v-for="item in cameraList"
244 :key="item.id" 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>
  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 +];
  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,149 +6,161 @@
6 <a-button type="primary" @click="handleAdd"> 新增场景联动 </a-button> 6 <a-button type="primary" @click="handleAdd"> 新增场景联动 </a-button>
7 </Authority> 7 </Authority>
8 <Authority value="api:yt:sceneLinkage:delete"> 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 <a-button color="error" :disabled="hasBatchDelete"> 批量删除 </a-button> 15 <a-button color="error" :disabled="hasBatchDelete"> 批量删除 </a-button>
11 </Popconfirm> 16 </Popconfirm>
12 </Authority> 17 </Authority>
13 </template> 18 </template>
14 <template #action="{ record }"> 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 </template> 48 </template>
42 49
43 <template #status="{ record }"> 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 </template> 58 </template>
47 </BasicTable> 59 </BasicTable>
48 <SceneLinkAgeDrawer @register="registerDrawer" @success="handleSuccess" /> 60 <SceneLinkAgeDrawer @register="registerDrawer" @success="handleSuccess" />
49 </div> 61 </div>
50 </template> 62 </template>
51 <script lang="ts" setup> 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 } else { 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 reload(); 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 </script> 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 <script lang="ts" setup> 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 const emit = defineEmits(['update:value', 'change']); 20 const emit = defineEmits(['update:value', 'change']);
7 21
@@ -14,7 +28,12 @@ @@ -14,7 +28,12 @@
14 28
15 <template> 29 <template>
16 <label class="sliding-switch"> 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 <span class="slider"></span> 37 <span class="slider"></span>
19 <span class="on">ON</span> 38 <span class="on">ON</span>
20 <span class="off">OFF</span> 39 <span class="off">OFF</span>
@@ -40,12 +59,9 @@ @@ -40,12 +59,9 @@
40 .slider { 59 .slider {
41 width: 80px; 60 width: 80px;
42 height: 40px; 61 height: 40px;
  62 + display: flex;
  63 + align-items: center;
43 box-sizing: border-box; 64 box-sizing: border-box;
44 - position: absolute;  
45 - top: 0;  
46 - left: 0;  
47 - right: 0;  
48 - bottom: 0;  
49 border: 2px solid #ecf0f3; 65 border: 2px solid #ecf0f3;
50 border-radius: 20px; 66 border-radius: 20px;
51 box-shadow: -2px -2px 8px #fff, -2px -2px 12px hsl(0deg 0% 100% / 50%), 67 box-shadow: -2px -2px 8px #fff, -2px -2px 12px hsl(0deg 0% 100% / 50%),
@@ -57,15 +73,14 @@ @@ -57,15 +73,14 @@
57 } 73 }
58 74
59 .slider::after { 75 .slider::after {
60 - position: absolute;  
61 cursor: pointer; 76 cursor: pointer;
62 display: block; 77 display: block;
63 content: ''; 78 content: '';
64 width: 24px; 79 width: 24px;
65 height: 24px; 80 height: 24px;
66 border-radius: 50%; 81 border-radius: 50%;
67 - top: 6px;  
68 - left: 6px; 82 + margin-left: 6px;
  83 + margin-right: 6px;
69 background-color: #ecf0f3; 84 background-color: #ecf0f3;
70 box-shadow: -2px -2px 8px #fff, -2px -2px 12px hsl(0deg 0% 100% / 50%), 85 box-shadow: -2px -2px 8px #fff, -2px -2px 12px hsl(0deg 0% 100% / 50%),
71 inset 2px 2px 4px hsl(0deg 0% 100% / 10%), 2px 2px 8px rgb(0 0 0 / 30%); 86 inset 2px 2px 4px hsl(0deg 0% 100% / 10%), 2px 2px 8px rgb(0 0 0 / 30%);
@@ -80,13 +95,16 @@ @@ -80,13 +95,16 @@
80 input:checked ~ .slider::after { 95 input:checked ~ .slider::after {
81 transform: translateX(35px); 96 transform: translateX(35px);
82 } 97 }
  98 +
83 input:not(:checked) ~ .on { 99 input:not(:checked) ~ .on {
84 opacity: 0; 100 opacity: 0;
85 - transform: translateX(0px); 101 + transform: translateX(0);
86 } 102 }
87 103
88 .on, 104 .on,
89 .off { 105 .off {
  106 + position: absolute;
  107 + top: 0;
90 display: inline-block; 108 display: inline-block;
91 margin-left: 3px; 109 margin-left: 3px;
92 width: 34px; 110 width: 34px;
@@ -97,7 +115,9 @@ @@ -97,7 +115,9 @@
97 .on { 115 .on {
98 color: #039be5; 116 color: #039be5;
99 } 117 }
  118 +
100 .off { 119 .off {
  120 + right: 6px;
101 color: #999; 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 <script lang="ts" setup> 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 const props = defineProps<{ 11 const props = defineProps<{
3 - value?: boolean; 12 + value?: ControlComponentValue;
  13 + layout?: Recordable;
  14 + radio?: RadioRecord;
4 }>(); 15 }>();
5 16
6 const emit = defineEmits(['update:value', 'change']); 17 const emit = defineEmits(['update:value', 'change']);
@@ -10,12 +21,27 @@ @@ -10,12 +21,27 @@
10 emit('update:value', _value); 21 emit('update:value', _value);
11 emit('change', _value); 22 emit('change', _value);
12 }; 23 };
  24 +
  25 + const getRadio = computed(() => {
  26 + return props.radio! || DEFAULT_RADIO_RECORD;
  27 + });
13 </script> 28 </script>
14 29
15 <template> 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 <label class="switch"> 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 <div class="button"> 45 <div class="button">
20 <div class="light"></div> 46 <div class="light"></div>
21 <div class="dots"></div> 47 <div class="dots"></div>
@@ -29,9 +55,10 @@ @@ -29,9 +55,10 @@
29 55
30 <style scoped> 56 <style scoped>
31 .toggle-switch { 57 .toggle-switch {
32 - flex: 1 1 auto; 58 + /* flex: 1 1 auto; */
33 max-width: 75px; 59 max-width: 75px;
34 - height: 97.5px; 60 +
  61 + /* height: 97.5px; */
35 display: flex; 62 display: flex;
36 } 63 }
37 64
@@ -76,12 +103,12 @@ @@ -76,12 +103,12 @@
76 transform-origin: center center -20px; 103 transform-origin: center center -20px;
77 transform: translateZ(20px) rotateX(-25deg); 104 transform: translateZ(20px) rotateX(-25deg);
78 transform-style: preserve-3d; 105 transform-style: preserve-3d;
79 - background-color: #9b0621;  
80 width: 100%; 106 width: 100%;
81 height: 100%; 107 height: 100%;
82 position: relative; 108 position: relative;
83 cursor: pointer; 109 cursor: pointer;
84 background: linear-gradient(#980000 0%, #6f0000 30%, #6f0000 70%, #980000 100%); 110 background: linear-gradient(#980000 0%, #6f0000 30%, #6f0000 70%, #980000 100%);
  111 + background-color: #9b0621;
85 background-repeat: no-repeat; 112 background-repeat: no-repeat;
86 } 113 }
87 114
@@ -113,7 +140,7 @@ @@ -113,7 +140,7 @@
113 transform: translateY(30px) rotateX(-90deg); 140 transform: translateY(30px) rotateX(-90deg);
114 position: absolute; 141 position: absolute;
115 bottom: 0; 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 .switch .light { 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 <script lang="ts" setup> 6 <script lang="ts" setup>
2 import type { ECharts, EChartsOption } from 'echarts'; 7 import type { ECharts, EChartsOption } from 'echarts';
3 import { PropType, watch } from 'vue'; 8 import { PropType, watch } from 'vue';
@@ -7,21 +12,21 @@ @@ -7,21 +12,21 @@
7 DashboardComponentLayout, 12 DashboardComponentLayout,
8 DashBoardValue, 13 DashBoardValue,
9 instrumentComponent1, 14 instrumentComponent1,
10 - InstrumentComponentType,  
11 update_instrument_1_font, 15 update_instrument_1_font,
12 update_instrument_2_font, 16 update_instrument_2_font,
13 update_instrument_1_value, 17 update_instrument_1_value,
14 update_instrument_2_value, 18 update_instrument_2_value,
15 } from './dashBoardComponent.config'; 19 } from './dashBoardComponent.config';
16 - import { dateUtil } from '/@/utils/dateUtil';  
17 import { 20 import {
18 DEFAULT_RADIO_RECORD, 21 DEFAULT_RADIO_RECORD,
19 RadioRecord, 22 RadioRecord,
20 - DEFAULT_DATE_FORMAT,  
21 fontSize, 23 fontSize,
  24 + getUpdateTime,
22 } from '../../detail/config/util'; 25 } from '../../detail/config/util';
23 import { Tooltip } from 'ant-design-vue'; 26 import { Tooltip } from 'ant-design-vue';
24 import { useThrottleFn } from '@vueuse/shared'; 27 import { useThrottleFn } from '@vueuse/shared';
  28 + import { buildUUID } from '/@/utils/uuid';
  29 + import { FrontComponent } from '../help';
25 30
26 const props = defineProps({ 31 const props = defineProps({
27 add: { 32 add: {
@@ -33,7 +38,7 @@ @@ -33,7 +38,7 @@
33 }, 38 },
34 value: { 39 value: {
35 type: Object as PropType<DashBoardValue>, 40 type: Object as PropType<DashBoardValue>,
36 - default: () => ({}), 41 + default: () => ({ id: buildUUID() }),
37 }, 42 },
38 radio: { 43 radio: {
39 type: Object as PropType<RadioRecord>, 44 type: Object as PropType<RadioRecord>,
@@ -60,7 +65,6 @@ @@ -60,7 +65,6 @@
60 } 65 }
61 66
62 const getRadio = computed(() => { 67 const getRadio = computed(() => {
63 - // const { radio } = props.radio;  
64 return props.radio; 68 return props.radio;
65 }); 69 });
66 70
@@ -68,7 +72,6 @@ @@ -68,7 +72,6 @@
68 const realWidth = unref(chartRef)?.getWidth(); 72 const realWidth = unref(chartRef)?.getWidth();
69 const realHeight = unref(chartRef)?.getHeight(); 73 const realHeight = unref(chartRef)?.getHeight();
70 const radioRecord = props.radio; 74 const radioRecord = props.radio;
71 - // const widht  
72 return { 75 return {
73 ...radioRecord, 76 ...radioRecord,
74 height: realHeight || radioRecord.height, 77 height: realHeight || radioRecord.height,
@@ -76,7 +79,7 @@ @@ -76,7 +79,7 @@
76 }; 79 };
77 }); 80 });
78 81
79 - const beforeUpdateFn = (componentType: InstrumentComponentType) => { 82 + const beforeUpdateFn = (componentType: FrontComponent) => {
80 if (componentType === 'instrument-component-1') return update_instrument_1_font; 83 if (componentType === 'instrument-component-1') return update_instrument_1_font;
81 if (componentType === 'instrument-component-2') return update_instrument_2_font; 84 if (componentType === 'instrument-component-2') return update_instrument_2_font;
82 return (_radio: RadioRecord) => {}; 85 return (_radio: RadioRecord) => {};
@@ -88,7 +91,7 @@ @@ -88,7 +91,7 @@
88 unref(chartRef)?.resize(); 91 unref(chartRef)?.resize();
89 } 92 }
90 93
91 - const getUpdateValueFn = (componentType: InstrumentComponentType) => { 94 + const getUpdateValueFn = (componentType: FrontComponent) => {
92 if (componentType === 'instrument-component-1') return update_instrument_1_value; 95 if (componentType === 'instrument-component-1') return update_instrument_1_value;
93 if (componentType === 'instrument-component-2') return update_instrument_2_value; 96 if (componentType === 'instrument-component-2') return update_instrument_2_value;
94 return (_radio: DashBoardValue) => {}; 97 return (_radio: DashBoardValue) => {};
@@ -101,11 +104,6 @@ @@ -101,11 +104,6 @@
101 104
102 watch(() => props.value, updateChartValue); 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 const updateChartFont = useThrottleFn(() => { 107 const updateChartFont = useThrottleFn(() => {
110 const option = beforeUpdateFn(props.layout.componentType); 108 const option = beforeUpdateFn(props.layout.componentType);
111 setTimeout(() => { 109 setTimeout(() => {
@@ -122,8 +120,6 @@ @@ -122,8 +120,6 @@
122 120
123 watch(() => props.layout.componentType, updateChartType); 121 watch(() => props.layout.componentType, updateChartType);
124 122
125 - // watch(() => props.value.gradientInfo, updateChartType);  
126 -  
127 let timeout: Nullable<number> = null; 123 let timeout: Nullable<number> = null;
128 124
129 function handleRandomValue() { 125 function handleRandomValue() {
@@ -170,22 +166,11 @@ @@ -170,22 +166,11 @@
170 color: '#999', 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 <div class="truncate"> 170 <div class="truncate">
182 <span class="mr-2">更新时间:</span> 171 <span class="mr-2">更新时间:</span>
183 <span> 172 <span>
184 - {{  
185 - props.value?.updateTime  
186 - ? dateUtil(props?.value?.updateTime).format(DEFAULT_DATE_FORMAT)  
187 - : '暂无更新时间'  
188 - }} 173 + {{ getUpdateTime(props.value?.updateTime) }}
189 </span> 174 </span>
190 </div> 175 </div>
191 </Tooltip> 176 </Tooltip>
  1 +<script lang="ts">
  2 + export default {
  3 + inheritAttrs: false,
  4 + };
  5 +</script>
1 <script lang="ts" setup> 6 <script lang="ts" setup>
2 import { computed, onMounted, onUnmounted, ref, unref } from 'vue'; 7 import { computed, onMounted, onUnmounted, ref, unref } from 'vue';
3 import { Space, Tooltip } from 'ant-design-vue'; 8 import { Space, Tooltip } from 'ant-design-vue';
@@ -6,22 +11,27 @@ @@ -6,22 +11,27 @@
6 DigitalDashBoardLayout, 11 DigitalDashBoardLayout,
7 DigitalDashBoardValue, 12 DigitalDashBoardValue,
8 } from './digitalDashBoard.config'; 13 } from './digitalDashBoard.config';
9 - import { dateUtil } from '/@/utils/dateUtil';  
10 import { 14 import {
11 fontSize, 15 fontSize,
12 RadioRecord, 16 RadioRecord,
13 - DEFAULT_DATE_FORMAT, 17 + getUpdateTime,
14 DEFAULT_RADIO_RECORD, 18 DEFAULT_RADIO_RECORD,
15 DEFAULT_ANIMATION_INTERVAL, 19 DEFAULT_ANIMATION_INTERVAL,
16 } from '../../detail/config/util'; 20 } from '../../detail/config/util';
17 import { isNaN } from 'lodash'; 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 const changeValue = ref(0); 36 const changeValue = ref(0);
27 37
@@ -53,8 +63,6 @@ @@ -53,8 +63,6 @@
53 }); 63 });
54 64
55 const getRadio = computed(() => { 65 const getRadio = computed(() => {
56 - // const { radio } = props.radio || DEFAULT_RADIO_RECORD;  
57 - // return radio;  
58 return props.radio || DEFAULT_RADIO_RECORD; 66 return props.radio || DEFAULT_RADIO_RECORD;
59 }); 67 });
60 68
@@ -160,22 +168,11 @@ @@ -160,22 +168,11 @@
160 color: '#999', 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 <div class="truncate"> 172 <div class="truncate">
172 <span class="mr-1">更新时间:</span> 173 <span class="mr-1">更新时间:</span>
173 <span> 174 <span>
174 - {{  
175 - props.value?.updateTime  
176 - ? dateUtil(props?.value?.updateTime).format(DEFAULT_DATE_FORMAT)  
177 - : '暂无更新时间'  
178 - }} 175 + {{ getUpdateTime(props.value?.updateTime) }}
179 </span> 176 </span>
180 </div> 177 </div>
181 </Tooltip> 178 </Tooltip>
@@ -188,11 +185,12 @@ @@ -188,11 +185,12 @@
188 <style scoped lang="less"> 185 <style scoped lang="less">
189 .digital-wrapper__int { 186 .digital-wrapper__int {
190 border-radius: 1px; 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 padding: 5px; 190 padding: 5px;
194 background-size: 100% 100%; 191 background-size: 100% 100%;
195 } 192 }
  193 +
196 .digital-text_int { 194 .digital-text_int {
197 display: inline-block; 195 display: inline-block;
198 overflow-wrap: break-word; 196 overflow-wrap: break-word;
@@ -203,11 +201,12 @@ @@ -203,11 +201,12 @@
203 201
204 .digital-wrapper__float { 202 .digital-wrapper__float {
205 border-radius: 1px; 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 padding: 5px; 206 padding: 5px;
209 background-size: 100% 100%; 207 background-size: 100% 100%;
210 } 208 }
  209 +
211 .digital-text_float { 210 .digital-text_float {
212 display: inline-block; 211 display: inline-block;
213 overflow-wrap: break-word; 212 overflow-wrap: break-word;
1 import { EChartsOption } from 'echarts'; 1 import { EChartsOption } from 'echarts';
  2 +import { FrontComponent, Gradient, GradientColor } from '../../const/const';
2 import { fontSize, RadioRecord } from '../../detail/config/util'; 3 import { fontSize, RadioRecord } from '../../detail/config/util';
3 -import { Gradient, visualOptionField } from '../../detail/config/visualOptions';  
4 import { 4 import {
5 ComponentInfo, 5 ComponentInfo,
6 DataComponentRecord, 6 DataComponentRecord,
@@ -10,16 +10,6 @@ import { @@ -10,16 +10,6 @@ import {
10 import { isArray } from '/@/utils/is'; 10 import { isArray } from '/@/utils/is';
11 import { buildUUID } from '/@/utils/uuid'; 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 export interface GradientInfoRecord { 13 export interface GradientInfoRecord {
24 key: Gradient; 14 key: Gradient;
25 value: number; 15 value: number;
@@ -38,13 +28,7 @@ export interface DashBoardValue { @@ -38,13 +28,7 @@ export interface DashBoardValue {
38 28
39 export interface DashboardComponentLayout { 29 export interface DashboardComponentLayout {
40 chartOption: EChartsOption; 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 export const instrumentComponent1 = (params?: Partial<ComponentInfo>): EChartsOption => { 34 export const instrumentComponent1 = (params?: Partial<ComponentInfo>): EChartsOption => {
@@ -94,7 +78,6 @@ export const instrumentComponent1 = (params?: Partial<ComponentInfo>): EChartsOp @@ -94,7 +78,6 @@ export const instrumentComponent1 = (params?: Partial<ComponentInfo>): EChartsOp
94 axisLabel: { 78 axisLabel: {
95 distance: 0, 79 distance: 0,
96 color: '#999', 80 color: '#999',
97 - // fontSize: 20,  
98 }, 81 },
99 anchor: { 82 anchor: {
100 show: false, 83 show: false,
@@ -173,7 +156,6 @@ export const instrumentComponent2 = (params?: Partial<ComponentInfo>): EChartsOp @@ -173,7 +156,6 @@ export const instrumentComponent2 = (params?: Partial<ComponentInfo>): EChartsOp
173 156
174 const firstGradient = firstRecord?.value ? firstRecord.value / max : 0.3; 157 const firstGradient = firstRecord?.value ? firstRecord.value / max : 0.3;
175 const secondGradient = secondRecord?.value ? secondRecord.value / max : 0.7; 158 const secondGradient = secondRecord?.value ? secondRecord.value / max : 0.7;
176 - // const thirdGradient = thirdRecord?.value ? thirdRecord.value / max : 1;  
177 159
178 return { 160 return {
179 series: [ 161 series: [
@@ -307,12 +289,15 @@ export const update_instrument_2_value = (params: DashBoardValue) => { @@ -307,12 +289,15 @@ export const update_instrument_2_value = (params: DashBoardValue) => {
307 289
308 let max = thirdRecord?.value || secondRecord?.value || firstRecord?.value || 70; 290 let max = thirdRecord?.value || secondRecord?.value || firstRecord?.value || 70;
309 max = Number(1 + Array(String(max).length).fill(0).join('')); 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 const firstGradient = firstRecord?.value ? firstRecord.value / max : 0.3; 295 const firstGradient = firstRecord?.value ? firstRecord.value / max : 0.3;
312 const secondGradient = secondRecord?.value ? secondRecord.value / max : 0.7; 296 const secondGradient = secondRecord?.value ? secondRecord.value / max : 0.7;
313 return { 297 return {
314 series: [ 298 series: [
315 { 299 {
  300 + max: max < 100 ? 100 : max,
316 data: [{ value: handleValue(value) }], 301 data: [{ value: handleValue(value) }],
317 detail: { 302 detail: {
318 formatter: `{value} ${unit ?? ''}`, 303 formatter: `{value} ${unit ?? ''}`,
@@ -354,7 +339,7 @@ export const Instrument2DefaultConfig: Partial<ComponentInfo> = { @@ -354,7 +339,7 @@ export const Instrument2DefaultConfig: Partial<ComponentInfo> = {
354 339
355 export const transformDashboardComponentConfig = ( 340 export const transformDashboardComponentConfig = (
356 config: DashboardComponentLayout, 341 config: DashboardComponentLayout,
357 - record: DataComponentRecord, 342 + _record: DataComponentRecord,
358 dataSourceRecord: DataSource 343 dataSourceRecord: DataSource
359 ) => { 344 ) => {
360 let chartOption = config.chartOption; 345 let chartOption = config.chartOption;
1 import { ComponentInfo } from '/@/api/dataBoard/model'; 1 import { ComponentInfo } from '/@/api/dataBoard/model';
2 2
3 -export type DigitalDashBoardComponentType = 'digital-dashboard-component';  
4 -  
5 export interface DigitalDashBoardLayout { 3 export interface DigitalDashBoardLayout {
6 max: number; 4 max: number;
7 keepNumber: number; 5 keepNumber: number;
1 import { EChartsOption } from 'echarts'; 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 export interface DashboardComponentLayout { 4 export interface DashboardComponentLayout {
16 chartOption: EChartsOption; 5 chartOption: EChartsOption;
17 componentType: InstrumentComponentType; 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>
  1 +import { ComponentConfig } from '../help';
  2 +
  3 +export const transfromMapComponentConfig: ComponentConfig['transformConfig'] = (
  4 + _componentConfig,
  5 + _record,
  6 + _dataSourceRecord
  7 +) => {
  8 + return {};
  9 +};
@@ -12,6 +12,7 @@ @@ -12,6 +12,7 @@
12 12
13 const isEdit = ref(false); 13 const isEdit = ref(false);
14 const recordId = ref<Nullable<string>>(null); 14 const recordId = ref<Nullable<string>>(null);
  15 + const loading = ref(false);
15 16
16 const [registerModal, { changeLoading, closeModal }] = useModalInner( 17 const [registerModal, { changeLoading, closeModal }] = useModalInner(
17 (record: DataBoardRecord & { isEdit: boolean }) => { 18 (record: DataBoardRecord & { isEdit: boolean }) => {
@@ -33,6 +34,7 @@ @@ -33,6 +34,7 @@
33 await method.validate(); 34 await method.validate();
34 try { 35 try {
35 const value = method.getFieldsValue() as AddDataBoardParams; 36 const value = method.getFieldsValue() as AddDataBoardParams;
  37 + loading.value = true;
36 changeLoading(true); 38 changeLoading(true);
37 await addDataBoard(value); 39 await addDataBoard(value);
38 createMessage.success('创建成功'); 40 createMessage.success('创建成功');
@@ -42,12 +44,14 @@ @@ -42,12 +44,14 @@
42 createMessage.error('创建失败'); 44 createMessage.error('创建失败');
43 } finally { 45 } finally {
44 changeLoading(false); 46 changeLoading(false);
  47 + loading.value = false;
45 } 48 }
46 }; 49 };
47 50
48 const handleEditPanel = async () => { 51 const handleEditPanel = async () => {
49 await method.validate(); 52 await method.validate();
50 try { 53 try {
  54 + loading.value = true;
51 const value = method.getFieldsValue() as UpdateDataBoardParams; 55 const value = method.getFieldsValue() as UpdateDataBoardParams;
52 value.id = unref(recordId) as string; 56 value.id = unref(recordId) as string;
53 changeLoading(true); 57 changeLoading(true);
@@ -59,6 +63,7 @@ @@ -59,6 +63,7 @@
59 createMessage.error('编辑失败'); 63 createMessage.error('编辑失败');
60 } finally { 64 } finally {
61 changeLoading(false); 65 changeLoading(false);
  66 + loading.value = false;
62 } 67 }
63 }; 68 };
64 69
@@ -75,6 +80,7 @@ @@ -75,6 +80,7 @@
75 :title="isEdit ? '编辑看板' : '创建看板'" 80 :title="isEdit ? '编辑看板' : '创建看板'"
76 @register="registerModal" 81 @register="registerModal"
77 @ok="handleGetValue" 82 @ok="handleGetValue"
  83 + :okButtonProps="{ loading }"
78 > 84 >
79 <BasicForm @register="registerForm" /> 85 <BasicForm @register="registerForm" />
80 </BasicModal> 86 </BasicModal>
  1 +<script lang="ts">
  2 + export default {
  3 + inheritAttrs: false,
  4 + };
  5 +</script>
1 <script lang="ts" setup> 6 <script lang="ts" setup>
2 import { computed, ref, watch } from 'vue'; 7 import { computed, ref, watch } from 'vue';
3 import { Tooltip, Image as AntImage } from 'ant-design-vue'; 8 import { Tooltip, Image as AntImage } from 'ant-design-vue';
4 import { 9 import {
5 - DEFAULT_DATE_FORMAT, 10 + getUpdateTime,
6 DEFAULT_RADIO_RECORD, 11 DEFAULT_RADIO_RECORD,
7 fontSize, 12 fontSize,
8 RadioRecord, 13 RadioRecord,
9 } from '../../detail/config/util'; 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 const props = defineProps<{ 17 const props = defineProps<{
14 - layout?: PictureComponentLayout; 18 + layout?: Recordable;
15 value?: PictureComponentValue; 19 value?: PictureComponentValue;
16 radio?: RadioRecord; 20 radio?: RadioRecord;
17 }>(); 21 }>();
@@ -22,8 +26,6 @@ @@ -22,8 +26,6 @@
22 const getImagBase64 = ref(fallback); 26 const getImagBase64 = ref(fallback);
23 27
24 const getRadio = computed(() => { 28 const getRadio = computed(() => {
25 - // const { radio } = props.radio || DEFAULT_RADIO_RECORD;  
26 - // return radio;  
27 return props.radio || DEFAULT_RADIO_RECORD; 29 return props.radio || DEFAULT_RADIO_RECORD;
28 }); 30 });
29 31
@@ -67,26 +69,14 @@ @@ -67,26 +69,14 @@
67 class="w-full h-full flex flex-col justify-center items-center justify-between widget-picture" 69 class="w-full h-full flex flex-col justify-center items-center justify-between widget-picture"
68 > 70 >
69 <AntImage :width="getWidth" :src="getImagBase64" :fallback="fallback" /> 71 <AntImage :width="getWidth" :src="getImagBase64" :fallback="fallback" />
70 - <!-- <Image :style="{ width: `${getWidth}px` }" :src="getImagBase64" /> -->  
71 <div 72 <div
72 class="w-full text-center truncate p-5" 73 class="w-full text-center truncate p-5"
73 :style="{ fontSize: fontSize({ radioRecord: getRadio, basic: 12, max: 12 }), color: '#999' }" 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 <span class="mr-1">更新时间:</span> 77 <span class="mr-1">更新时间:</span>
84 <span class="truncate"> 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 </span> 80 </span>
91 </Tooltip> 81 </Tooltip>
92 </div> 82 </div>
1 import PictureComponent from './PictureComponent.vue'; 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 import { DataComponentRecord, DataSource } from '/@/api/dataBoard/model'; 1 import { DataComponentRecord, DataSource } from '/@/api/dataBoard/model';
2 2
3 -export type PictureComponentType = 'picture-component-1';  
4 -  
5 -export interface PictureComponentLayout {}  
6 -  
7 export interface PictureComponentValue { 3 export interface PictureComponentValue {
8 value?: string; 4 value?: string;
9 updateTime?: string; 5 updateTime?: string;
10 } 6 }
11 7
12 export const transformPictureConfig = ( 8 export const transformPictureConfig = (
13 - config: PictureComponentLayout,  
14 - record: DataComponentRecord, 9 + _config: Recordable,
  10 + _record: DataComponentRecord,
15 dataSourceRecord: DataSource 11 dataSourceRecord: DataSource
16 ) => { 12 ) => {
17 const componentInfo = dataSourceRecord.componentInfo; 13 const componentInfo = dataSourceRecord.componentInfo;
  1 +<script lang="ts">
  2 + export default {
  3 + inheritAttrs: false,
  4 + };
  5 +</script>
1 <script lang="ts" setup> 6 <script lang="ts" setup>
2 import { computed } from 'vue'; 7 import { computed } from 'vue';
3 import { Statistic, Tooltip } from 'ant-design-vue'; 8 import { Statistic, Tooltip } from 'ant-design-vue';
4 import { 9 import {
  10 + getUpdateTime,
5 fontSize, 11 fontSize,
6 RadioRecord, 12 RadioRecord,
7 DEFAULT_RADIO_RECORD, 13 DEFAULT_RADIO_RECORD,
8 - DEFAULT_DATE_FORMAT,  
9 } from '../../detail/config/util'; 14 } from '../../detail/config/util';
10 import { TextComponentDefaultConfig, TextComponentLayout, TextComponentValue } from './config'; 15 import { TextComponentDefaultConfig, TextComponentLayout, TextComponentValue } from './config';
11 import { SvgIcon } from '/@/components/Icon'; 16 import { SvgIcon } from '/@/components/Icon';
12 - import { dateUtil } from '/@/utils/dateUtil';  
13 const props = defineProps({ 17 const props = defineProps({
14 layout: { 18 layout: {
15 type: Object as PropType<TextComponentLayout>, 19 type: Object as PropType<TextComponentLayout>,
@@ -47,8 +51,6 @@ @@ -47,8 +51,6 @@
47 }); 51 });
48 52
49 const getRadio = computed(() => { 53 const getRadio = computed(() => {
50 - // const { radio } = props.radio;  
51 - // return radio;  
52 return props.radio || DEFAULT_RADIO_RECORD; 54 return props.radio || DEFAULT_RADIO_RECORD;
53 }); 55 });
54 </script> 56 </script>
@@ -84,37 +86,21 @@ @@ -84,37 +86,21 @@
84 /> 86 />
85 </div> 87 </div>
86 <div :style="{ color: '#666', fontSize: fontSize({ radioRecord: getRadio, basic: 16 }) }"> 88 <div :style="{ color: '#666', fontSize: fontSize({ radioRecord: getRadio, basic: 16 }) }">
87 - <!-- {{ getShowUnit ? props.value.unit : '' }} -->  
88 {{ props.value.name }} 89 {{ props.value.name }}
89 </div> 90 </div>
90 - <!-- <div class="truncate" :style="{ fontSize: fontSize({ radio: getRadio, basic: 16 }) }">  
91 - {{ props.value.name }}  
92 - </div> -->  
93 </div> 91 </div>
94 </div> 92 </div>
95 </div> 93 </div>
96 94
97 <div class="text-center text-xs truncate p-5" style="color: #999"> 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 <div 97 <div
108 :style="{ fontSize: fontSize({ radioRecord: getRadio, basic: 12, max: 12 }) }" 98 :style="{ fontSize: fontSize({ radioRecord: getRadio, basic: 12, max: 12 }) }"
109 class="truncate" 99 class="truncate"
110 > 100 >
111 <span class="mr-1">更新时间:</span> 101 <span class="mr-1">更新时间:</span>
112 <span class="truncate"> 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 </span> 104 </span>
119 </div> 105 </div>
120 </Tooltip> 106 </Tooltip>
@@ -18,13 +18,6 @@ export interface TextComponentValue { @@ -18,13 +18,6 @@ export interface TextComponentValue {
18 deviceName?: string; 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 type TextComponentDefault = TextComponentLayout; 21 type TextComponentDefault = TextComponentLayout;
29 22
30 export const TextComponent1Config: TextComponentDefault = { 23 export const TextComponent1Config: TextComponentDefault = {
@@ -32,10 +25,6 @@ export const TextComponent1Config: TextComponentDefault = { @@ -32,10 +25,6 @@ export const TextComponent1Config: TextComponentDefault = {
32 base: true, 25 base: true,
33 }; 26 };
34 27
35 -export const TextComponent2Config: TextComponentDefault = {  
36 - id: 'text-component-2',  
37 - base: false,  
38 -};  
39 export const TextComponent3Config: TextComponentDefault = { 28 export const TextComponent3Config: TextComponentDefault = {
40 id: 'text-component-3', 29 id: 'text-component-3',
41 base: false, 30 base: false,
@@ -62,17 +51,9 @@ export const TextComponentDefaultConfig: Partial<ComponentInfo> = { @@ -62,17 +51,9 @@ export const TextComponentDefaultConfig: Partial<ComponentInfo> = {
62 icon: 'shuiwen', 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 export const transformTextComponentConfig = ( 54 export const transformTextComponentConfig = (
74 config: TextComponentDefault, 55 config: TextComponentDefault,
75 - record: DataComponentRecord, 56 + _record: DataComponentRecord,
76 dataSourceRecord: DataSource 57 dataSourceRecord: DataSource
77 ) => { 58 ) => {
78 return { 59 return {
@@ -3,8 +3,11 @@ @@ -3,8 +3,11 @@
3 import { DropMenu } from '/@/components/Dropdown'; 3 import { DropMenu } from '/@/components/Dropdown';
4 import Dropdown from '/@/components/Dropdown/src/Dropdown.vue'; 4 import Dropdown from '/@/components/Dropdown/src/Dropdown.vue';
5 import { Tooltip } from 'ant-design-vue'; 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 import { computed } from '@vue/reactivity'; 11 import { computed } from '@vue/reactivity';
9 import { usePermission } from '/@/hooks/web/usePermission'; 12 import { usePermission } from '/@/hooks/web/usePermission';
10 import { DataSource } from '/@/api/dataBoard/model'; 13 import { DataSource } from '/@/api/dataBoard/model';
@@ -19,9 +22,9 @@ @@ -19,9 +22,9 @@
19 const { hasPermission } = usePermission(); 22 const { hasPermission } = usePermission();
20 const dropMenuList = computed<DropMenu[]>(() => { 23 const dropMenuList = computed<DropMenu[]>(() => {
21 const basicMenu: DropMenu[] = []; 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 if (hasUpdatePermission) 28 if (hasUpdatePermission)
26 basicMenu.push({ 29 basicMenu.push({
27 text: '编辑组件', 30 text: '编辑组件',
@@ -69,7 +72,6 @@ @@ -69,7 +72,6 @@
69 > 72 >
70 <Tooltip :title="item.deviceName" placement="topLeft"> 73 <Tooltip :title="item.deviceName" placement="topLeft">
71 <div class="flex p-1"> 74 <div class="flex p-1">
72 - <!-- <SvgIcon name="" prefix="iconfont" class="!fill-emerald-400" /> -->  
73 <div class="truncate font-bold">{{ item.deviceRename || item.deviceName }}</div> 75 <div class="truncate font-bold">{{ item.deviceRename || item.deviceName }}</div>
74 </div> 76 </div>
75 </Tooltip> 77 </Tooltip>
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 - import { useSlots } from 'vue';  
3 import { useUpdateCenter } from '../../hook/useUpdateCenter'; 2 import { useUpdateCenter } from '../../hook/useUpdateCenter';
4 import { FrontDataSourceRecord } from '../../types/type'; 3 import { FrontDataSourceRecord } from '../../types/type';
5 - // import type { WidgetWrapperRegister } from './type';  
6 - // import { DataSource } from '/@/api/dataBoard/model';  
7 4
8 const props = defineProps<{ 5 const props = defineProps<{
9 dataSource: FrontDataSourceRecord[]; 6 dataSource: FrontDataSourceRecord[];
10 }>(); 7 }>();
11 8
12 - const slot = useSlots();  
13 -  
14 const { update, add, remove } = useUpdateCenter(); 9 const { update, add, remove } = useUpdateCenter();
15 10
16 defineExpose({ update }); 11 defineExpose({ update });
@@ -20,7 +15,7 @@ @@ -20,7 +15,7 @@
20 <section class="widget"> 15 <section class="widget">
21 <slot name="header"></slot> 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 <div 19 <div
25 v-for="item in props.dataSource" 20 v-for="item in props.dataSource"
26 :key="item.id" 21 :key="item.id"
@@ -28,10 +23,7 @@ @@ -28,10 +23,7 @@
28 class="widget-item" 23 class="widget-item"
29 > 24 >
30 <div class="widget-box"> 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 <slot 27 <slot
36 name="controls" 28 name="controls"
37 :record="item" 29 :record="item"
@@ -40,12 +32,6 @@ @@ -40,12 +32,6 @@
40 :update="update" 32 :update="update"
41 ></slot> 33 ></slot>
42 </div> 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 </div> 35 </div>
50 </div> 36 </div>
51 </div> 37 </div>
@@ -61,14 +47,14 @@ @@ -61,14 +47,14 @@
61 height: 100%; 47 height: 100%;
62 background-color: #fff; 48 background-color: #fff;
63 border-radius: 3px; 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 .widget-content { 53 .widget-content {
67 display: flex; 54 display: flex;
68 flex-wrap: wrap; 55 flex-wrap: wrap;
69 justify-content: center; 56 justify-content: center;
70 align-items: center; 57 align-items: center;
71 -  
72 width: 100%; 58 width: 100%;
73 height: 100%; 59 height: 100%;
74 } 60 }
@@ -94,7 +80,7 @@ @@ -94,7 +80,7 @@
94 .widget-controls-container { 80 .widget-controls-container {
95 flex: 1 1 auto; 81 flex: 1 1 auto;
96 width: 100%; 82 width: 100%;
97 - height: calc(100% - 20px); 83 + height: 100%;
98 display: flex; 84 display: flex;
99 align-items: center; 85 align-items: center;
100 justify-content: center; 86 justify-content: center;
1 -// import { DataBoardLayoutInfo } from '../../types/type';  
2 -  
3 -// export type WidgetWrapperRegister = (dataSource: DataBoardLayoutInfo['record'][]) => any;  
  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 +};
1 -import { Component } from 'vue';  
2 -import IndicatorLight from '../cpns/IndicatorLight.vue';  
3 -  
4 -export const dashboardComponentMap = new Map<string, Component>();  
5 -  
6 -dashboardComponentMap.set('IndicatorLight', IndicatorLight);  
@@ -4,7 +4,19 @@ export enum MoreActionEvent { @@ -4,7 +4,19 @@ export enum MoreActionEvent {
4 DELETE = 'delete', 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 export const DEFAULT_MAX_COL = 24; 21 export const DEFAULT_MAX_COL = 24;
10 export const DEFAULT_WIDGET_WIDTH = 6; 22 export const DEFAULT_WIDGET_WIDTH = 6;
  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,17 +2,17 @@
2 import { CopyOutlined, DeleteOutlined, SettingOutlined } from '@ant-design/icons-vue'; 2 import { CopyOutlined, DeleteOutlined, SettingOutlined } from '@ant-design/icons-vue';
3 import { Tooltip, Button } from 'ant-design-vue'; 3 import { Tooltip, Button } from 'ant-design-vue';
4 import { FormActionType, useForm } from '/@/components/Form'; 4 import { FormActionType, useForm } from '/@/components/Form';
5 - import { basicSchema, dataSourceSchema } from '../config/basicConfiguration'; 5 + import { basicSchema } from '../config/basicConfiguration';
6 import BasicForm from '/@/components/Form/src/BasicForm.vue'; 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 import VisualOptionsModal from './VisualOptionsModal.vue'; 8 import VisualOptionsModal from './VisualOptionsModal.vue';
9 import { useModal } from '/@/components/Modal'; 9 import { useModal } from '/@/components/Modal';
10 import { buildUUID } from '/@/utils/uuid'; 10 import { buildUUID } from '/@/utils/uuid';
11 import type { ComponentInfo, DataSource } from '/@/api/dataBoard/model'; 11 import type { ComponentInfo, DataSource } from '/@/api/dataBoard/model';
12 import { useMessage } from '/@/hooks/web/useMessage'; 12 import { useMessage } from '/@/hooks/web/useMessage';
13 import { DataBoardLayoutInfo } from '../../types/type'; 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 type DataSourceFormEL = { [key: string]: Nullable<FormActionType> }; 17 type DataSourceFormEL = { [key: string]: Nullable<FormActionType> };
18 18
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 20
21 const props = defineProps<{ 21 const props = defineProps<{
22 record: DataBoardLayoutInfo; 22 record: DataBoardLayoutInfo;
23 - frontId?: string; 23 + frontId?: FrontComponent;
24 defaultConfig?: Partial<ComponentInfo>; 24 defaultConfig?: Partial<ComponentInfo>;
25 }>(); 25 }>();
26 26
@@ -39,7 +39,7 @@ @@ -39,7 +39,7 @@
39 const dataSourceEl = shallowReactive<DataSourceFormEL>({} as unknown as DataSourceFormEL); 39 const dataSourceEl = shallowReactive<DataSourceFormEL>({} as unknown as DataSourceFormEL);
40 40
41 const setFormEl = (el: any, id: string) => { 41 const setFormEl = (el: any, id: string) => {
42 - if (!dataSourceEl[id] && el) { 42 + if (id && el) {
43 const { formActionType } = el as unknown as { formActionType: FormActionType }; 43 const { formActionType } = el as unknown as { formActionType: FormActionType };
44 dataSourceEl[id] = formActionType; 44 dataSourceEl[id] = formActionType;
45 } 45 }
@@ -112,8 +112,6 @@ @@ -112,8 +112,6 @@
112 return; 112 return;
113 } 113 }
114 114
115 - // const defaultConfig = getComponentDefaultConfig(props.frontId as WidgetComponentType);  
116 -  
117 const componentInfo: ComponentInfo = { 115 const componentInfo: ComponentInfo = {
118 ...(props.defaultConfig || {}), 116 ...(props.defaultConfig || {}),
119 ...(item.componentInfo || {}), 117 ...(item.componentInfo || {}),
@@ -177,6 +175,10 @@ @@ -177,6 +175,10 @@
177 ~index && (unref(dataSource)[index].componentInfo = value); 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 defineExpose({ 182 defineExpose({
181 getAllDataSourceFieldValue, 183 getAllDataSourceFieldValue,
182 validate, 184 validate,
@@ -198,17 +200,8 @@ @@ -198,17 +200,8 @@
198 选择设备 200 选择设备
199 </div> 201 </div>
200 <div class="pl-2 flex-auto"> 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 </div> 205 </div>
213 <div class="flex justify-center gap-3 w-24"> 206 <div class="flex justify-center gap-3 w-24">
214 <Tooltip title="复制"> 207 <Tooltip title="复制">
@@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@
12 import { decode } from '../../config/config'; 12 import { decode } from '../../config/config';
13 import { ComponentInfo } from '/@/api/dataBoard/model'; 13 import { ComponentInfo } from '/@/api/dataBoard/model';
14 import { useCalcGridLayout } from '../../hook/useCalcGridLayout'; 14 import { useCalcGridLayout } from '../../hook/useCalcGridLayout';
15 - import { FrontComponent } from '../config/help'; 15 + import { FrontComponent } from '../../const/const';
16 16
17 interface DataComponentRouteParams extends RouteParams { 17 interface DataComponentRouteParams extends RouteParams {
18 id: string; 18 id: string;
@@ -23,9 +23,9 @@ @@ -23,9 +23,9 @@
23 }>(); 23 }>();
24 24
25 const emit = defineEmits(['update', 'create', 'register']); 25 const emit = defineEmits(['update', 'create', 'register']);
26 -  
27 const ROUTE = useRoute(); 26 const ROUTE = useRoute();
28 27
  28 + const loading = ref(false);
29 const { createMessage } = useMessage(); 29 const { createMessage } = useMessage();
30 30
31 const boardId = computed(() => { 31 const boardId = computed(() => {
@@ -62,11 +62,15 @@ @@ -62,11 +62,15 @@
62 }; 62 };
63 63
64 const handleSubmit = async () => { 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 const { calcLayoutInfo } = useCalcGridLayout(); 76 const { calcLayoutInfo } = useCalcGridLayout();
@@ -78,6 +82,7 @@ @@ -78,6 +82,7 @@
78 } 82 }
79 const layout = calcLayoutInfo(unref(props.layout)); 83 const layout = calcLayoutInfo(unref(props.layout));
80 changeOkLoading(true); 84 changeOkLoading(true);
  85 + loading.value = true;
81 await addDataComponent({ 86 await addDataComponent({
82 boardId: unref(boardId), 87 boardId: unref(boardId),
83 record: { dataBoardId: unref(boardId), frontId: unref(frontId), ...value, layout }, 88 record: { dataBoardId: unref(boardId), frontId: unref(frontId), ...value, layout },
@@ -90,12 +95,14 @@ @@ -90,12 +95,14 @@
90 // createMessage.error('创建失败'); 95 // createMessage.error('创建失败');
91 } finally { 96 } finally {
92 changeOkLoading(false); 97 changeOkLoading(false);
  98 + loading.value = false;
93 } 99 }
94 }; 100 };
95 101
96 const handleUpdateComponent = async (value: Recordable) => { 102 const handleUpdateComponent = async (value: Recordable) => {
97 try { 103 try {
98 changeOkLoading(true); 104 changeOkLoading(true);
  105 + loading.value = true;
99 const res = await updateDataComponent({ 106 const res = await updateDataComponent({
100 boardId: unref(boardId), 107 boardId: unref(boardId),
101 record: { 108 record: {
@@ -113,6 +120,7 @@ @@ -113,6 +120,7 @@
113 // createMessage.error('修改失败'); 120 // createMessage.error('修改失败');
114 } finally { 121 } finally {
115 changeOkLoading(false); 122 changeOkLoading(false);
  123 + loading.value = false;
116 } 124 }
117 }; 125 };
118 126
@@ -130,10 +138,11 @@ @@ -130,10 +138,11 @@
130 :destroy-on-close="true" 138 :destroy-on-close="true"
131 @ok="handleSubmit" 139 @ok="handleSubmit"
132 @cancel="resetForm" 140 @cancel="resetForm"
  141 + :ok-button-props="{ loading }"
133 > 142 >
134 <section> 143 <section>
135 <Tabs type="card"> 144 <Tabs type="card">
136 - <Tabs.TabPane key="1" tab="基础配置"> 145 + <Tabs.TabPane key="basicConfig" tab="基础配置">
137 <BasicConfiguration 146 <BasicConfiguration
138 ref="basicConfigurationEl" 147 ref="basicConfigurationEl"
139 :front-id="frontId" 148 :front-id="frontId"
@@ -141,7 +150,7 @@ @@ -141,7 +150,7 @@
141 :defaultConfig="componentDefaultConfig" 150 :defaultConfig="componentDefaultConfig"
142 /> 151 />
143 </Tabs.TabPane> 152 </Tabs.TabPane>
144 - <Tabs.TabPane key="2" tab="可视化配置"> 153 + <Tabs.TabPane key="visualConfig" tab="可视化配置">
145 <VisualConfiguration v-model:value="frontId" @change="handleComponentCheckedChange" /> 154 <VisualConfiguration v-model:value="frontId" @change="handleComponentCheckedChange" />
146 </Tabs.TabPane> 155 </Tabs.TabPane>
147 </Tabs> 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 <script lang="ts" setup> 1 <script lang="ts" setup>
2 import { Tabs, List } from 'ant-design-vue'; 2 import { Tabs, List } from 'ant-design-vue';
3 import VisualWidgetSelect from './VisualWidgetSelect.vue'; 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 const props = defineProps<{ 18 const props = defineProps<{
11 value: string; 19 value: string;
12 }>(); 20 }>();
@@ -14,7 +22,25 @@ @@ -14,7 +22,25 @@
14 22
15 const grid = { gutter: 10, column: 1, xs: 1, sm: 2, md: 2, lg: 3, xl: 3, xxl: 4 }; 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 const defaultConfig = getComponentDefaultConfig(checked); 44 const defaultConfig = getComponentDefaultConfig(checked);
19 emit('update:value', checked); 45 emit('update:value', checked);
20 emit('change', defaultConfig); 46 emit('change', defaultConfig);
@@ -24,51 +50,25 @@ @@ -24,51 +50,25 @@
24 <template> 50 <template>
25 <section> 51 <section>
26 <Tabs> 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 <template #renderItem="{ item }"> 59 <template #renderItem="{ item }">
60 <List.Item class="!flex !justify-center"> 60 <List.Item class="!flex !justify-center">
61 <VisualWidgetSelect 61 <VisualWidgetSelect
62 :checked-id="props.value" 62 :checked-id="props.value"
63 - :control-id="item.id" 63 + :control-id="item.ComponentKey"
64 @change="handleCheck" 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 </VisualWidgetSelect> 72 </VisualWidgetSelect>
73 </List.Item> 73 </List.Item>
74 </template> 74 </template>
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 import { ref, unref } from 'vue'; 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 import { useForm, BasicForm } from '/@/components/Form'; 4 import { useForm, BasicForm } from '/@/components/Form';
11 import { BasicModal, useModalInner } from '/@/components/Modal'; 5 import { BasicModal, useModalInner } from '/@/components/Modal';
12 import { ComponentInfo } from '/@/api/dataBoard/model'; 6 import { ComponentInfo } from '/@/api/dataBoard/model';
13 import { computed } from '@vue/reactivity'; 7 import { computed } from '@vue/reactivity';
  8 + import { FrontComponent, Gradient, visualOptionField } from '../../const/const';
14 9
15 const emit = defineEmits(['close', 'register']); 10 const emit = defineEmits(['close', 'register']);
16 11
@@ -21,7 +16,7 @@ @@ -21,7 +16,7 @@
21 const recordId = ref(''); 16 const recordId = ref('');
22 17
23 const getSchemas = computed(() => { 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 const [registerForm, method] = useForm({ 22 const [registerForm, method] = useForm({
@@ -30,16 +30,19 @@ @@ -30,16 +30,19 @@
30 <slot></slot> 30 <slot></slot>
31 </div> 31 </div>
32 <Card.Meta> 32 <Card.Meta>
33 - <template #description> 选择 </template> 33 + <template #description>
  34 + <slot name="description"></slot>
  35 + </template>
34 </Card.Meta> 36 </Card.Meta>
35 </Card> 37 </Card>
36 </template> 38 </template>
37 39
38 <style scoped> 40 <style scoped>
39 .widget-select { 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 border-width: 2px; 43 border-width: 2px;
42 } 44 }
  45 +
43 .widget-select:deep(.ant-card-body) { 46 .widget-select:deep(.ant-card-body) {
44 /* height: 240px; */ 47 /* height: 240px; */
45 width: 240px; 48 width: 240px;
@@ -217,3 +217,24 @@ export const dataSourceSchema: FormSchema[] = [ @@ -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 +];
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 export interface RadioRecord { 3 export interface RadioRecord {
2 width: number; 4 width: number;
3 height: number; 5 height: number;
@@ -16,6 +18,10 @@ export const DEFAULT_RADIO_RECORD: RadioRecord = { @@ -16,6 +18,10 @@ export const DEFAULT_RADIO_RECORD: RadioRecord = {
16 18
17 export const DEFAULT_DATE_FORMAT = 'YYYY-MM-DD HH:mm:ss'; 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 export const calcScale = ( 25 export const calcScale = (
20 width: number, 26 width: number,
21 height: number, 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 import { FormSchema } from '/@/components/Form'; 2 import { FormSchema } from '/@/components/Form';
6 3
7 -export type WidgetComponentType =  
8 - | TextComponentType  
9 - | InstrumentComponentType  
10 - | DigitalDashBoardComponentType  
11 - | PictureComponentType;  
12 -  
13 export interface VisualOptionParams { 4 export interface VisualOptionParams {
14 [visualOptionField.FONT_COLOR]: string; 5 [visualOptionField.FONT_COLOR]: string;
15 [visualOptionField.UNIT]: string; 6 [visualOptionField.UNIT]: string;
@@ -23,17 +14,6 @@ export interface VisualOptionParams { @@ -23,17 +14,6 @@ export interface VisualOptionParams {
23 [visualOptionField.THIRD_PHASE_VALUE]: string; 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 export enum visualOptionField { 17 export enum visualOptionField {
38 FONT_COLOR = 'fontColor', 18 FONT_COLOR = 'fontColor',
39 UNIT = 'unit', 19 UNIT = 'unit',
@@ -198,13 +178,13 @@ export const modeFour: FormSchema[] = [ @@ -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,6 +16,7 @@
16 DEFAULT_WIDGET_WIDTH, 16 DEFAULT_WIDGET_WIDTH,
17 isBataBoardSharePage, 17 isBataBoardSharePage,
18 MoreActionEvent, 18 MoreActionEvent,
  19 + VisualComponentPermission,
19 } from '../config/config'; 20 } from '../config/config';
20 import { 21 import {
21 addDataComponent, 22 addDataComponent,
@@ -32,11 +33,10 @@ @@ -32,11 +33,10 @@
32 DataSource, 33 DataSource,
33 Layout, 34 Layout,
34 } from '/@/api/dataBoard/model'; 35 } from '/@/api/dataBoard/model';
35 - import { frontComponentMap } from './config/help'; 36 + import { frontComponentMap } from '../components/help';
36 import { calcScale } from './config/util'; 37 import { calcScale } from './config/util';
37 import { useMessage } from '/@/hooks/web/useMessage'; 38 import { useMessage } from '/@/hooks/web/useMessage';
38 import { DataBoardLayoutInfo } from '../types/type'; 39 import { DataBoardLayoutInfo } from '../types/type';
39 - import { WidgetComponentType } from './config/visualOptions';  
40 import Authority from '/@/components/Authority/src/Authority.vue'; 40 import Authority from '/@/components/Authority/src/Authority.vue';
41 import { useSocketConnect } from '../hook/useSocketConnect'; 41 import { useSocketConnect } from '../hook/useSocketConnect';
42 import { buildUUID } from '/@/utils/uuid'; 42 import { buildUUID } from '/@/utils/uuid';
@@ -44,6 +44,7 @@ @@ -44,6 +44,7 @@
44 import trendIcon from '/@/assets/svg/trend.svg'; 44 import trendIcon from '/@/assets/svg/trend.svg';
45 import backIcon from '/@/assets/images/back.png'; 45 import backIcon from '/@/assets/images/back.png';
46 import { useCalcGridLayout } from '../hook/useCalcGridLayout'; 46 import { useCalcGridLayout } from '../hook/useCalcGridLayout';
  47 + import { FrontComponent } from '../const/const';
47 48
48 const ROUTE = useRoute(); 49 const ROUTE = useRoute();
49 50
@@ -298,7 +299,7 @@ @@ -298,7 +299,7 @@
298 299
299 const getComponent = (record: DataComponentRecord) => { 300 const getComponent = (record: DataComponentRecord) => {
300 const frontComponent = record.frontId; 301 const frontComponent = record.frontId;
301 - const component = frontComponentMap.get(frontComponent as WidgetComponentType); 302 + const component = frontComponentMap.get(frontComponent as FrontComponent);
302 return component?.Component; 303 return component?.Component;
303 }; 304 };
304 305
@@ -307,8 +308,8 @@ @@ -307,8 +308,8 @@
307 dataSourceRecord: DataSource 308 dataSourceRecord: DataSource
308 ) => { 309 ) => {
309 const frontComponent = record.frontId; 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 const handleUpdate = async (id: string) => { 315 const handleUpdate = async (id: string) => {
@@ -360,9 +361,7 @@ @@ -360,9 +361,7 @@
360 await deleteDataComponent({ dataBoardId, ids: [id] }); 361 await deleteDataComponent({ dataBoardId, ids: [id] });
361 createMessage.success('删除成功'); 362 createMessage.success('删除成功');
362 await getDataBoardComponent(); 363 await getDataBoardComponent();
363 - } catch (error) {  
364 - // createMessage.error('删除失败');  
365 - } 364 + } catch (error) {}
366 }; 365 };
367 366
368 const [registerHistoryDataModal, historyDataModalMethod] = useModal(); 367 const [registerHistoryDataModal, historyDataModalMethod] = useModal();
@@ -391,7 +390,7 @@ @@ -391,7 +390,7 @@
391 </div> 390 </div>
392 </template> 391 </template>
393 <template #extra> 392 <template #extra>
394 - <Authority value="api:yt:data_component:add:post"> 393 + <Authority :value="VisualComponentPermission.CREATE">
395 <Button v-if="!getIsSharePage" type="primary" @click="handleOpenCreatePanel"> 394 <Button v-if="!getIsSharePage" type="primary" @click="handleOpenCreatePanel">
396 创建组件 395 创建组件
397 </Button> 396 </Button>
@@ -439,7 +438,6 @@ @@ -439,7 +438,6 @@
439 :data-source="item.record.dataSource" 438 :data-source="item.record.dataSource"
440 > 439 >
441 <template #header> 440 <template #header>
442 - <!-- <div>header</div> -->  
443 <BaseWidgetHeader 441 <BaseWidgetHeader
444 :record="item.record.dataSource" 442 :record="item.record.dataSource"
445 :id="item.record.id" 443 :id="item.record.id"
@@ -448,11 +446,6 @@ @@ -448,11 +446,6 @@
448 > 446 >
449 <template #moreAction> 447 <template #moreAction>
450 <Tooltip title="趋势"> 448 <Tooltip title="趋势">
451 - <!-- <LineChartOutlined  
452 - v-if="!getIsSharePage"  
453 - class="cursor-pointer mx-1"  
454 - @click="handleOpenHistroyDataModal(item.record.dataSource)"  
455 - /> -->  
456 <img 449 <img
457 :src="trendIcon" 450 :src="trendIcon"
458 v-if="!getIsSharePage" 451 v-if="!getIsSharePage"
@@ -494,14 +487,18 @@ @@ -494,14 +487,18 @@
494 .vue-grid-item:not(.vue-grid-placeholder) { 487 .vue-grid-item:not(.vue-grid-placeholder) {
495 background: #fff; 488 background: #fff;
496 border: none !important; 489 border: none !important;
  490 +
497 /* border: 1px solid black; */ 491 /* border: 1px solid black; */
498 } 492 }
  493 +
499 .vue-grid-item .resizing { 494 .vue-grid-item .resizing {
500 opacity: 0.9; 495 opacity: 0.9;
501 } 496 }
  497 +
502 .vue-grid-item .static { 498 .vue-grid-item .static {
503 background: #cce; 499 background: #cce;
504 } 500 }
  501 +
505 .vue-grid-item .text { 502 .vue-grid-item .text {
506 font-size: 24px; 503 font-size: 24px;
507 text-align: center; 504 text-align: center;
@@ -514,16 +511,20 @@ @@ -514,16 +511,20 @@
514 height: 100%; 511 height: 100%;
515 width: 100%; 512 width: 100%;
516 } 513 }
  514 +
517 .vue-grid-item .no-drag { 515 .vue-grid-item .no-drag {
518 height: 100%; 516 height: 100%;
519 width: 100%; 517 width: 100%;
520 } 518 }
  519 +
521 .vue-grid-item .minMax { 520 .vue-grid-item .minMax {
522 font-size: 12px; 521 font-size: 12px;
523 } 522 }
  523 +
524 .vue-grid-item .add { 524 .vue-grid-item .add {
525 cursor: pointer; 525 cursor: pointer;
526 } 526 }
  527 +
527 .vue-draggable-handle { 528 .vue-draggable-handle {
528 position: absolute; 529 position: absolute;
529 width: 20px; 530 width: 20px;
@@ -540,12 +541,6 @@ @@ -540,12 +541,6 @@
540 cursor: pointer; 541 cursor: pointer;
541 } 542 }
542 543
543 - // .container {  
544 - // display: grid;  
545 - // grid-template-columns: 3;  
546 - // grid-row: 3;  
547 - // }  
548 -  
549 .grid-item-layout { 544 .grid-item-layout {
550 overflow: hidden; 545 overflow: hidden;
551 border: 1px solid #eee !important; 546 border: 1px solid #eee !important;
@@ -8,6 +8,10 @@ interface GapRecord { @@ -8,6 +8,10 @@ interface GapRecord {
8 endIndex: Nullable<number>; 8 endIndex: Nullable<number>;
9 } 9 }
10 10
  11 +/**
  12 + * @description calculate where to place the component
  13 + * @returns
  14 + */
11 export function useCalcGridLayout() { 15 export function useCalcGridLayout() {
12 const calcLayoutInfo = ( 16 const calcLayoutInfo = (
13 layoutInfo: Layout[], 17 layoutInfo: Layout[],
@@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
7 import { useMessage } from '/@/hooks/web/useMessage'; 7 import { useMessage } from '/@/hooks/web/useMessage';
8 import Dropdown from '/@/components/Dropdown/src/Dropdown.vue'; 8 import Dropdown from '/@/components/Dropdown/src/Dropdown.vue';
9 import { DropMenu } from '/@/components/Dropdown'; 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 import { useModal } from '/@/components/Modal'; 11 import { useModal } from '/@/components/Modal';
12 import PanelDetailModal from './components/PanelDetailModal.vue'; 12 import PanelDetailModal from './components/PanelDetailModal.vue';
13 import { getDataBoardList, deleteDataBoard } from '/@/api/dataBoard'; 13 import { getDataBoardList, deleteDataBoard } from '/@/api/dataBoard';
@@ -36,7 +36,7 @@ @@ -36,7 +36,7 @@
36 labelWidth: 80, 36 labelWidth: 80,
37 layout: 'inline', 37 layout: 'inline',
38 submitButtonOptions: { 38 submitButtonOptions: {
39 - loading: loading, 39 + loading: loading as unknown as boolean,
40 }, 40 },
41 submitFunc: async () => { 41 submitFunc: async () => {
42 try { 42 try {
@@ -51,7 +51,7 @@ @@ -51,7 +51,7 @@
51 }, 51 },
52 }); 52 });
53 53
54 - //分页相关 54 + // about pagination
55 const page = ref(1); 55 const page = ref(1);
56 const pageSize = ref(10); 56 const pageSize = ref(10);
57 const total = ref(0); 57 const total = ref(0);
@@ -90,8 +90,8 @@ @@ -90,8 +90,8 @@
90 90
91 const { hasPermission } = usePermission(); 91 const { hasPermission } = usePermission();
92 const dropMenuList = computed<DropMenu[]>(() => { 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 const basicMenu: DropMenu[] = []; 95 const basicMenu: DropMenu[] = [];
96 if (hasUpdatePermission) 96 if (hasUpdatePermission)
97 basicMenu.push({ 97 basicMenu.push({
@@ -147,31 +147,21 @@ @@ -147,31 +147,21 @@
147 }; 147 };
148 148
149 const handleRemove = async (record: DataBoardRecord) => { 149 const handleRemove = async (record: DataBoardRecord) => {
150 - // TODO 删除确认  
151 try { 150 try {
152 await deleteDataBoard([record.id]); 151 await deleteDataBoard([record.id]);
153 createMessage.success('删除成功'); 152 createMessage.success('删除成功');
154 await getDatasource(); 153 await getDatasource();
155 - } catch (error) {  
156 - // createMessage.error('删除失败');  
157 - } 154 + } catch (error) {}
158 }; 155 };
159 156
160 const [registerModal, { openModal }] = useModal(); 157 const [registerModal, { openModal }] = useModal();
161 158
162 const handleViewBoard = (record: DataBoardRecord) => { 159 const handleViewBoard = (record: DataBoardRecord) => {
163 - const hasDetailPermission = hasPermission('api:yt:data_component:list'); 160 + const hasDetailPermission = hasPermission(VisualBoardPermission.DETAIL);
164 if (hasDetailPermission) { 161 if (hasDetailPermission) {
165 const boardId = encode(record.id); 162 const boardId = encode(record.id);
166 const boardName = encode(record.name); 163 const boardName = encode(record.name);
167 router.push(`/visual/board/detail/${boardId}/${boardName}`); 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 } else createMessage.warning('没有权限'); 165 } else createMessage.warning('没有权限');
176 }; 166 };
177 167
@@ -186,8 +176,6 @@ @@ -186,8 +176,6 @@
186 '.ant-spin-container' 176 '.ant-spin-container'
187 ) as HTMLElement; 177 ) as HTMLElement;
188 listContainerEl && 178 listContainerEl &&
189 - // (listContainerEl.style.minHeight = listContainerHeight + 'px') &&  
190 - // (listContainerEl.style.maxHeight = listContainerHeight + 'px') &&  
191 (listContainerEl.style.height = listContainerHeight + 'px') && 179 (listContainerEl.style.height = listContainerHeight + 'px') &&
192 (listContainerEl.style.overflowY = 'auto') && 180 (listContainerEl.style.overflowY = 'auto') &&
193 (listContainerEl.style.overflowX = 'hidden'); 181 (listContainerEl.style.overflowX = 'hidden');
@@ -210,7 +198,6 @@ @@ -210,7 +198,6 @@
210 <div class="bg-light-100 mb-6 w-full p-3 search-form"> 198 <div class="bg-light-100 mb-6 w-full p-3 search-form">
211 <BasicForm class="flex-auto w-full" @register="searchFormRegister" /> 199 <BasicForm class="flex-auto w-full" @register="searchFormRegister" />
212 </div> 200 </div>
213 - <!-- <div> </div> -->  
214 <Spin :spinning="loading"> 201 <Spin :spinning="loading">
215 <List 202 <List
216 ref="listEL" 203 ref="listEL"
@@ -235,7 +222,6 @@ @@ -235,7 +222,6 @@
235 <MoreOutlined class="rotate-90 transform cursor-pointer" /> 222 <MoreOutlined class="rotate-90 transform cursor-pointer" />
236 </Dropdown> 223 </Dropdown>
237 </template> 224 </template>
238 - <!-- <template #cover>title</template> -->  
239 <section @click="handleViewBoard(item)"> 225 <section @click="handleViewBoard(item)">
240 <div class="flex data-card__info"> 226 <div class="flex data-card__info">
241 <div> 227 <div>
@@ -247,16 +233,19 @@ @@ -247,16 +233,19 @@
247 </Statistic> 233 </Statistic>
248 </div> 234 </div>
249 </div> 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 <div> 237 <div>
252 <span> 238 <span>
253 {{ item.viewType === ViewType.PRIVATE_VIEW ? '私有看板' : '公共看板' }} 239 {{ item.viewType === ViewType.PRIVATE_VIEW ? '私有看板' : '公共看板' }}
254 </span> 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 <Tooltip title="点击复制分享链接"> 245 <Tooltip title="点击复制分享链接">
257 <ShareAltOutlined class="ml-2" @click.stop="handleCopyShareUrl(item)" /> 246 <ShareAltOutlined class="ml-2" @click.stop="handleCopyShareUrl(item)" />
258 </Tooltip> 247 </Tooltip>
259 - </span> --> 248 + </span>
260 </div> 249 </div>
261 <div>{{ item.createTime }}</div> 250 <div>{{ item.createTime }}</div>
262 </div> 251 </div>
@@ -278,15 +267,17 @@ @@ -278,15 +267,17 @@
278 .data-card:deep(.ant-card-head-title) { 267 .data-card:deep(.ant-card-head-title) {
279 padding: 0; 268 padding: 0;
280 } 269 }
  270 +
281 .data-card:deep(.ant-card-extra) { 271 .data-card:deep(.ant-card-extra) {
282 padding: 0; 272 padding: 0;
283 } 273 }
  274 +
284 .data-card:deep(.ant-card-body) { 275 .data-card:deep(.ant-card-body) {
285 padding: 20px; 276 padding: 20px;
286 } 277 }
287 278
288 .data-card__info { 279 .data-card__info {
289 - color: #666666; 280 + color: #666;
290 281
291 &::before { 282 &::before {
292 content: ''; 283 content: '';
@@ -299,8 +290,10 @@ @@ -299,8 +290,10 @@
299 290
300 .search-form { 291 .search-form {
301 width: 100%; 292 width: 100%;
  293 +
302 form { 294 form {
303 width: 100%; 295 width: 100%;
  296 +
304 :deep(.ant-row) { 297 :deep(.ant-row) {
305 width: 100%; 298 width: 100%;
306 } 299 }
  1 +import { Component } from 'vue';
1 import { Layout } from 'vue3-grid-layout'; 2 import { Layout } from 'vue3-grid-layout';
  3 +import { FrontComponent, FrontComponentCategory, visualOptionField } from '../const/const';
  4 +import { RadioRecord } from '../detail/config/util';
2 import { DataComponentRecord, DataSource } from '/@/api/dataBoard/model'; 5 import { DataComponentRecord, DataSource } from '/@/api/dataBoard/model';
3 6
4 export type FrontDataSourceRecord = DataSource; 7 export type FrontDataSourceRecord = DataSource;
@@ -8,3 +11,39 @@ export type DataBoardLayoutInfo = Layout & { @@ -8,3 +11,39 @@ export type DataBoardLayoutInfo = Layout & {
8 width?: number; 11 width?: number;
9 height?: number; 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 +}