Commit cf4ef9c76b556ad4872e878abd61b8c05806152f

Authored by ww
1 parent 154ef642

feat: add operation ota page && dynamic set loading effect

... ... @@ -22,7 +22,6 @@
22 22 theme = htmlRoot = null;
23 23 }
24 24 })();
25   -
26 25 </script>
27 26 <div id="app">
28 27 <style>
... ... @@ -152,17 +151,17 @@
152 151 }
153 152 }
154 153 </style>
155   - <div class="app-loading">
  154 + <div id="first-screen-loading" class="app-loading">
156 155 <div class="app-loading-wrap">
157   - <img src="/resource/img/logo.png" class="app-loading-logo" alt="Logo" />
  156 + <!-- <img src="/resource/img/logo.png" class="app-loading-logo" alt="Logo" /> -->
158 157 <div class="app-loading-dots">
159 158 <span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
160 159 </div>
161   - <div class="app-loading-title"><%= title %></div>
  160 + <!-- <div class="app-loading-title"><%= title %></div> -->
162 161 </div>
163 162 </div>
164 163 </div>
165   -
  164 +
166 165 <script type="module" src="/src/main.ts"></script>
167 166 </body>
168 167 </html>
... ...
1 1 import { defHttp } from '/@/utils/http/axios';
2   -import { FileUploadResponse } from './model/index';
  2 +import { FileUploadResponse, Platform } from './model/index';
3 3 enum API {
4 4 SELECT_DETAIL = '/enterprise/get',
5 5 UPDATE_DETAIL = '/enterprise/update',
... ... @@ -67,7 +67,7 @@ export const bgUpload = (file) => {
67 67
68 68 // 获取平台定制详情
69 69 export const getPlatForm = () => {
70   - return defHttp.get({
  70 + return defHttp.get<Platform>({
71 71 url: API.SELECT_PLATFORM,
72 72 });
73 73 };
... ...
... ... @@ -5,3 +5,17 @@ export interface FileUploadResponse {
5 5 size: number;
6 6 fileStaticUri: string;
7 7 }
  8 +
  9 +export interface Platform {
  10 + id: string;
  11 + creator: string;
  12 + createTime: string;
  13 + updater: string;
  14 + updateTime: string;
  15 + name: string;
  16 + logo: string;
  17 + background: string;
  18 + copyright: string;
  19 + presentedOurselves: string;
  20 + domain: string;
  21 +}
... ...
... ... @@ -10,6 +10,7 @@ export { default as ApiSelect } from './src/components/ApiSelect.vue';
10 10 export { default as RadioButtonGroup } from './src/components/RadioButtonGroup.vue';
11 11 export { default as ApiTreeSelect } from './src/components/ApiTreeSelect.vue';
12 12 export { default as ApiRadioGroup } from './src/components/ApiRadioGroup.vue';
  13 +export { default as ApiUpload } from './src/components/ApiUpload.vue';
13 14
14 15 //注册自定义组件
15 16 export {
... ...
  1 +<script lang="ts">
  2 + export default {
  3 + inheritAttrs: false,
  4 + };
  5 +</script>
  6 +<script lang="ts" setup>
  7 + import { UploadDragger, Spin } from 'ant-design-vue';
  8 + import { InboxOutlined } from '@ant-design/icons-vue';
  9 + import { useMessage } from '/@/hooks/web/useMessage';
  10 + import { isBoolean, isFunction } from '/@/utils/is';
  11 + import { computed, ref, unref } from 'vue';
  12 + import { cloneDeep } from 'lodash-es';
  13 + interface FileItem {
  14 + uid: string;
  15 + name?: string;
  16 + status?: string;
  17 + response?: string;
  18 + url?: string;
  19 + }
  20 +
  21 + const emit = defineEmits(['update:fileList']);
  22 +
  23 + const { createMessage } = useMessage();
  24 +
  25 + const loading = ref(false);
  26 +
  27 + const componentDisabled = ref(false);
  28 +
  29 + const setLoading = (spin: boolean) => {
  30 + loading.value = spin;
  31 + };
  32 +
  33 + const props = withDefaults(
  34 + defineProps<{
  35 + fileList?: FileItem[];
  36 + accept?: string;
  37 + maxSize?: number;
  38 + disabled?: boolean;
  39 + listType?: string;
  40 + multiple?: boolean;
  41 + showUploadList?: boolean | { showPreviewIcon?: boolean; showRemoveIcon?: boolean };
  42 + transformFile?: (file: File) => string | Blob | Promise<string | Blob | File>;
  43 + api: (file: string | Blob | Promise<string | Blob | File>) => Promise<FileItem>;
  44 + }>(),
  45 + {
  46 + fileList: () => [],
  47 + maxSize: 5 * 1024 * 1024,
  48 + showUploadList: () => ({ showPreviewIcon: true, showRemoveIcon: true }),
  49 + }
  50 + );
  51 +
  52 + const handleBeforeUpload = (file: File) => {
  53 + if (file.size > props.maxSize) {
  54 + createMessage.warning(`文件大小超过${Math.floor(props.maxSize / 1024)}mb`);
  55 + return false;
  56 + }
  57 + handleUpload(file);
  58 + return false;
  59 + };
  60 +
  61 + const getDisabled = computed(() => {
  62 + const { disabled } = props;
  63 + if (isBoolean(disabled)) {
  64 + return disabled ? componentDisabled.value : disabled;
  65 + }
  66 + return componentDisabled.value;
  67 + });
  68 +
  69 + const handleUpload = async (file: File | string | Blob | Promise<string | Blob | File>) => {
  70 + try {
  71 + setLoading(true);
  72 + componentDisabled.value = true;
  73 + console.log({ componentDisabled: unref(componentDisabled), getDisabled: unref(getDisabled) });
  74 + const { transformFile, api } = props;
  75 + if (transformFile && isFunction(transformFile)) file = await transformFile(file as File);
  76 + if (api && isFunction(api)) {
  77 + const data = await api(file);
  78 + emit('update:fileList', cloneDeep([...props.fileList, data]));
  79 + }
  80 + } catch (error) {
  81 + window.console.error(error);
  82 + } finally {
  83 + setLoading(false);
  84 + componentDisabled.value = false;
  85 + }
  86 + };
  87 +
  88 + const handleRemove = (file: FileItem) => {
  89 + const _fileList = cloneDeep(props.fileList);
  90 + const index = _fileList.findIndex((item) => item.uid === file.uid);
  91 + ~index && _fileList.splice(index, 1);
  92 + emit('update:fileList', _fileList);
  93 + };
  94 +
  95 + const handlePreview = (file: FileItem) => {
  96 + console.log('preview', file);
  97 + };
  98 +
  99 + const handleDownload = (file: FileItem) => {
  100 + console.log('download', file);
  101 + };
  102 +</script>
  103 +
  104 +<template>
  105 + <UploadDragger
  106 + :file-list="props.fileList"
  107 + :disabled="getDisabled"
  108 + :before-upload="handleBeforeUpload"
  109 + @preview="handlePreview"
  110 + @download="handleDownload"
  111 + :remove="handleRemove"
  112 + >
  113 + <Spin :spinning="loading">
  114 + {{ getDisabled }}
  115 + <div class="w-full h-full flex flex-col justify-center content-center">
  116 + <InboxOutlined class="text-[3rem] !text-blue-500" />
  117 + <div class="m-2 text-gray-400">点击上传或拖拽上传</div>
  118 + </div>
  119 + </Spin>
  120 + </UploadDragger>
  121 +</template>
... ...
... ... @@ -14,6 +14,7 @@ import { setupGlobDirectives } from '/@/directives';
14 14 import { setupI18n } from '/@/locales/setupI18n';
15 15 import { registerGlobComp } from '/@/components/registerGlobComp';
16 16 import '/@/assets/iconfont/iconfont';
  17 +import { usePlatform } from './views/system/customize/hook/usePlatformInfo';
17 18
18 19 if (import.meta.env.DEV) {
19 20 import('ant-design-vue/dist/antd.less');
... ... @@ -23,6 +24,8 @@ async function bootstrap() {
23 24 // Configure store
24 25 setupStore(app);
25 26
  27 + await usePlatform();
  28 +
26 29 // Initialize internal system configuration
27 30 initAppConfigStore();
28 31
... ... @@ -47,6 +50,7 @@ async function bootstrap() {
47 50 // Mount when the route is ready
48 51 // https://next.router.vuejs.org/api/#isready
49 52 await router.isReady();
  53 +
50 54 app.mount('#app', true);
51 55 }
52 56
... ...
... ... @@ -39,7 +39,7 @@
39 39 width: '200px',
40 40 height: '200px',
41 41 color: '#409eff',
42   - muted: false, //静音
  42 + muted: true, //静音
43 43 webFullScreen: false,
44 44 autoPlay: true, //自动播放
45 45 currentTime: 0,
... ...
  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 6 <a-button type="primary" @click="handleAdd"> 新增场景联动 </a-button>
7 7 </Authority>
8 8 <Authority value="api:yt:sceneLinkage:delete">
9   - <Popconfirm title="您确定要批量删除数据" ok-text="确定" cancel-text="取消" @confirm="handleDeleteOrBatchDelete(null)">
  9 + <Popconfirm
  10 + title="您确定要批量删除数据"
  11 + ok-text="确定"
  12 + cancel-text="取消"
  13 + @confirm="handleDeleteOrBatchDelete(null)"
  14 + >
10 15 <a-button color="error" :disabled="hasBatchDelete"> 批量删除 </a-button>
11 16 </Popconfirm>
12 17 </Authority>
13 18 </template>
14 19 <template #action="{ record }">
15   - <TableAction :actions="[
16   - {
17   - label: '查看',
18   - auth: 'api:yt:sceneLinkage:get',
19   - icon: 'ant-design:eye-outlined',
20   - onClick: handleView.bind(null, record),
21   - },
22   - {
23   - label: '编辑',
24   - auth: 'api:yt:sceneLinkage:update',
25   - icon: 'clarity:note-edit-line',
26   - onClick: handleEdit.bind(null, record),
27   - ifShow: record.creator === userId && record.status !== 1,
28   - },
29   - {
30   - label: '删除',
31   - auth: 'api:yt:sceneLinkage:delete',
32   - icon: 'ant-design:delete-outlined',
33   - color: 'error',
34   - ifShow: record.creator === userId && record.status !== 1,
35   - popConfirm: {
36   - title: '是否确认删除',
37   - confirm: handleDeleteOrBatchDelete.bind(null, record),
  20 + <TableAction
  21 + :actions="[
  22 + {
  23 + label: '查看',
  24 + auth: 'api:yt:sceneLinkage:get',
  25 + icon: 'ant-design:eye-outlined',
  26 + onClick: handleView.bind(null, record),
38 27 },
39   - },
40   - ]" />
  28 + {
  29 + label: '编辑',
  30 + auth: 'api:yt:sceneLinkage:update',
  31 + icon: 'clarity:note-edit-line',
  32 + onClick: handleEdit.bind(null, record),
  33 + ifShow: record.creator === userId && record.status !== 1,
  34 + },
  35 + {
  36 + label: '删除',
  37 + auth: 'api:yt:sceneLinkage:delete',
  38 + icon: 'ant-design:delete-outlined',
  39 + color: 'error',
  40 + ifShow: record.creator === userId && record.status !== 1,
  41 + popConfirm: {
  42 + title: '是否确认删除',
  43 + confirm: handleDeleteOrBatchDelete.bind(null, record),
  44 + },
  45 + },
  46 + ]"
  47 + />
41 48 </template>
42 49
43 50 <template #status="{ record }">
44   - <Switch :checked="record.status === 1" :loading="record.pendingStatus" checkedChildren="启用"
45   - unCheckedChildren="禁用" @change="(checked:boolean)=>statusChange(checked,record)" />
  51 + <Switch
  52 + :checked="record.status === 1"
  53 + :loading="record.pendingStatus"
  54 + checkedChildren="启用"
  55 + unCheckedChildren="禁用"
  56 + @change="(checked:boolean)=>statusChange(checked,record)"
  57 + />
46 58 </template>
47 59 </BasicTable>
48 60 <SceneLinkAgeDrawer @register="registerDrawer" @success="handleSuccess" />
49 61 </div>
50 62 </template>
51 63 <script lang="ts" setup>
52   -import { nextTick } from 'vue';
53   -import { BasicTable, useTable, TableAction } from '/@/components/Table';
54   -import { useDrawer } from '/@/components/Drawer';
55   -import {
56   - screenLinkPageGetApi,
57   - screenLinkPageDeleteApi,
58   - screenLinkPagePutApi,
59   -} from '/@/api/ruleengine/ruleengineApi';
60   -import { useBatchDelete } from '/@/hooks/web/useBatchDelete';
61   -import { Switch, Popconfirm } from 'ant-design-vue';
62   -import { columns, searchFormSchema } from './config/config.data.ts';
63   -import { USER_INFO_KEY } from '/@/enums/cacheEnum';
64   -import { getAuthCache } from '/@/utils/auth';
65   -import SceneLinkAgeDrawer from './SceneLinkAgeDrawer.vue';
66   -import { useMessage } from '/@/hooks/web/useMessage';
67   -import { Authority } from '/@/components/Authority';
68   -
69   -const userInfo: any = getAuthCache(USER_INFO_KEY);
70   -const userId = userInfo.userId;
  64 + import { nextTick } from 'vue';
  65 + import { BasicTable, useTable, TableAction } from '/@/components/Table';
  66 + import { useDrawer } from '/@/components/Drawer';
  67 + import {
  68 + screenLinkPageGetApi,
  69 + screenLinkPageDeleteApi,
  70 + screenLinkPagePutApi,
  71 + } from '/@/api/ruleengine/ruleengineApi';
  72 + import { useBatchDelete } from '/@/hooks/web/useBatchDelete';
  73 + import { Switch, Popconfirm } from 'ant-design-vue';
  74 + import { columns, searchFormSchema } from './config/config.data';
  75 + import { USER_INFO_KEY } from '/@/enums/cacheEnum';
  76 + import { getAuthCache } from '/@/utils/auth';
  77 + import SceneLinkAgeDrawer from './SceneLinkAgeDrawer.vue';
  78 + import { useMessage } from '/@/hooks/web/useMessage';
  79 + import { Authority } from '/@/components/Authority';
71 80
72   -const [registerDrawer, { openDrawer }] = useDrawer();
73   -const [registerTable, { reload, setProps, setSelectedRowKeys }] = useTable({
74   - title: '场景联动列表',
75   - api: screenLinkPageGetApi,
76   - columns,
77   - formConfig: {
78   - labelWidth: 120,
79   - schemas: searchFormSchema,
80   - },
81   - useSearchForm: true,
82   - showTableSetting: true,
83   - bordered: true,
84   - showIndexColumn: false,
85   - actionColumn: {
86   - width: 200,
87   - title: '操作',
88   - dataIndex: 'action',
89   - slots: { customRender: 'action' },
90   - fixed: 'right',
91   - },
92   -});
93   -const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions, resetSelectedRowKeys } =
94   - useBatchDelete(screenLinkPageDeleteApi, handleSuccess, setProps);
95   -selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => {
96   - // Demo:status为1的选择框禁用
97   - if (record.status === 1) {
98   - return { disabled: true };
99   - } else {
100   - return { disabled: false };
101   - }
102   -};
103   -nextTick(() => {
104   - setProps(selectionOptions);
105   -});
106   -
107   -function handleAdd() {
108   - window.localStorage.setItem('isViewDisabledBtn', 'noView')
109   - openDrawer(true, {
110   - isUpdate: false,
111   - });
112   -}
  81 + const userInfo: any = getAuthCache(USER_INFO_KEY);
  82 + const userId = userInfo.userId;
113 83
114   -function handleEdit(record: Recordable) {
115   - window.localStorage.setItem('isViewDisabledBtn', 'noView')
116   - openDrawer(true, {
117   - record,
118   - isUpdate: true,
  84 + const [registerDrawer, { openDrawer }] = useDrawer();
  85 + const [registerTable, { reload, setProps, setSelectedRowKeys }] = useTable({
  86 + title: '场景联动列表',
  87 + api: screenLinkPageGetApi,
  88 + columns,
  89 + formConfig: {
  90 + labelWidth: 120,
  91 + schemas: searchFormSchema,
  92 + },
  93 + useSearchForm: true,
  94 + showTableSetting: true,
  95 + bordered: true,
  96 + showIndexColumn: false,
  97 + actionColumn: {
  98 + width: 200,
  99 + title: '操作',
  100 + dataIndex: 'action',
  101 + slots: { customRender: 'action' },
  102 + fixed: 'right',
  103 + },
119 104 });
120   -}
121   -function handleView(record: Recordable) {
122   - window.localStorage.setItem('isViewDisabledBtn', 'isView')
123   - openDrawer(true, {
124   - record,
125   - isUpdate: 3,
126   - });
127   -}
128   -function handleSuccess() {
129   - reload();
130   -}
131   -
132   -const statusChange = async (checked, record) => {
133   - setProps({
134   - loading: true,
135   - });
136   - setSelectedRowKeys([]);
137   - resetSelectedRowKeys();
138   - const newStatus = checked ? 1 : 0;
139   - const { createMessage } = useMessage();
140   - try {
141   - await screenLinkPagePutApi({ id: record.id, status: newStatus });
142   - if (newStatus) {
143   - createMessage.success(`启用成功`);
  105 + const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions, resetSelectedRowKeys } =
  106 + useBatchDelete(screenLinkPageDeleteApi, handleSuccess, setProps);
  107 + selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => {
  108 + // Demo:status为1的选择框禁用
  109 + if (record.status === 1) {
  110 + return { disabled: true };
144 111 } else {
145   - createMessage.success('禁用成功');
  112 + return { disabled: false };
146 113 }
147   - } finally {
148   - setProps({
149   - loading: false,
  114 + };
  115 + nextTick(() => {
  116 + setProps(selectionOptions);
  117 + });
  118 +
  119 + function handleAdd() {
  120 + window.localStorage.setItem('isViewDisabledBtn', 'noView');
  121 + openDrawer(true, {
  122 + isUpdate: false,
  123 + });
  124 + }
  125 +
  126 + function handleEdit(record: Recordable) {
  127 + window.localStorage.setItem('isViewDisabledBtn', 'noView');
  128 + openDrawer(true, {
  129 + record,
  130 + isUpdate: true,
  131 + });
  132 + }
  133 + function handleView(record: Recordable) {
  134 + window.localStorage.setItem('isViewDisabledBtn', 'isView');
  135 + openDrawer(true, {
  136 + record,
  137 + isUpdate: 3,
150 138 });
  139 + }
  140 + function handleSuccess() {
151 141 reload();
152 142 }
153   -};
  143 +
  144 + const statusChange = async (checked, record) => {
  145 + setProps({
  146 + loading: true,
  147 + });
  148 + setSelectedRowKeys([]);
  149 + resetSelectedRowKeys();
  150 + const newStatus = checked ? 1 : 0;
  151 + const { createMessage } = useMessage();
  152 + try {
  153 + await screenLinkPagePutApi({ id: record.id, status: newStatus });
  154 + if (newStatus) {
  155 + createMessage.success(`启用成功`);
  156 + } else {
  157 + createMessage.success('禁用成功');
  158 + }
  159 + } finally {
  160 + setProps({
  161 + loading: false,
  162 + });
  163 + reload();
  164 + }
  165 + };
154 166 </script>
... ...
  1 +import { getPlatForm } from '/@/api/oem';
  2 +
  3 +enum DefaultPlatform {
  4 + LOGO = '/resource/img/logo.png',
  5 + // TITLE = 'ThingsKit',
  6 + ICO = '/favicon.ico',
  7 +}
  8 +
  9 +export const usePlatform = async () => {
  10 + const platformInfo = await getPlatForm();
  11 +
  12 + const createLoadingEffect = () => {
  13 + const wrap = document.createElement('div');
  14 + wrap.setAttribute('class', 'app-loading-wrap');
  15 + const img = document.createElement('img');
  16 + img.setAttribute('src', platformInfo.logo || DefaultPlatform.LOGO);
  17 + img.setAttribute('class', 'app-loading-logo');
  18 + img.setAttribute('alt', 'Logo');
  19 + const dots = document.createElement('div');
  20 + dots.setAttribute('class', 'app-loading-dots');
  21 + const dotWrap = document.createElement('span');
  22 + dotWrap.setAttribute('class', 'dot dot-spin');
  23 + for (let i = 0; i < 4; i++) {
  24 + dotWrap.appendChild(document.createElement('i'));
  25 + }
  26 + const title = document.createElement('div');
  27 + title.setAttribute('class', 'app-loading-title');
  28 + const textNode = document.createTextNode(
  29 + platformInfo.name || import.meta.env.VITE_GLOB_APP_TITLE
  30 + );
  31 + title.appendChild(textNode);
  32 + wrap.appendChild(img);
  33 + dots.appendChild(dotWrap);
  34 + wrap.appendChild(dots);
  35 + wrap.appendChild(title);
  36 + return wrap;
  37 + };
  38 +
  39 + const replaceSiteIco = () => {
  40 + const linkEl = document.querySelectorAll('link[rel*="icon"]');
  41 + linkEl.forEach((item) => {
  42 + item.setAttribute('href', platformInfo.logo || DefaultPlatform.ICO);
  43 + });
  44 + };
  45 +
  46 + const replaceLoadingEffect = () => {
  47 + const loadingWrapper = document.getElementById('first-screen-loading');
  48 + loadingWrapper!.innerHTML = '';
  49 + loadingWrapper?.appendChild(createLoadingEffect());
  50 + };
  51 +
  52 + const bootstrap = () => {
  53 + replaceSiteIco();
  54 + replaceLoadingEffect();
  55 + };
  56 +
  57 + bootstrap();
  58 +};
... ...