Commit 07ef1fd239b7a52bfa0cf2b970f57885729fa032

Authored by fengwotao
2 parents 038d1b5f c5077dc9

Merge branch 'main_dev' into ft

@@ -5,6 +5,13 @@ export enum DataActionModeEnum { @@ -5,6 +5,13 @@ export enum DataActionModeEnum {
5 DELETE = 'DELETE', 5 DELETE = 'DELETE',
6 } 6 }
7 7
  8 +export enum DataActionModeNameEnum {
  9 + CREATE = '创建',
  10 + READ = '查看',
  11 + UPDATE = '编辑',
  12 + DELETE = '删除',
  13 +}
  14 +
8 export enum TimeUnitEnum { 15 export enum TimeUnitEnum {
9 SECOND = 'SECOND', 16 SECOND = 'SECOND',
10 MINUTE = 'MINUTE', 17 MINUTE = 'MINUTE',
@@ -3,9 +3,13 @@ @@ -3,9 +3,13 @@
3 import { BasicModal, useModalInner } from '/@/components/Modal'; 3 import { BasicModal, useModalInner } from '/@/components/Modal';
4 import { FieldsEnum, schemas, ViewTypeEnum } from './config'; 4 import { FieldsEnum, schemas, ViewTypeEnum } from './config';
5 import { DataBoardRecord } from '/@/api/dataBoard/model'; 5 import { DataBoardRecord } from '/@/api/dataBoard/model';
6 - import { Alert } from 'ant-design-vue'; 6 + import { Alert, Button, Tooltip } from 'ant-design-vue';
7 import { ref, unref } from 'vue'; 7 import { ref, unref } from 'vue';
8 import { nextTick } from 'vue'; 8 import { nextTick } from 'vue';
  9 + import { ModalParamsType } from '/#/utils';
  10 + import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
  11 + import { useMessage } from '/@/hooks/web/useMessage';
  12 + import { computed } from 'vue';
9 13
10 const props = defineProps<{ 14 const props = defineProps<{
11 shareApi?: (...args: any[]) => Promise<any>; 15 shareApi?: (...args: any[]) => Promise<any>;
@@ -13,15 +17,20 @@ @@ -13,15 +17,20 @@
13 17
14 const loading = ref(false); 18 const loading = ref(false);
15 const record = ref<DataBoardRecord>({} as unknown as DataBoardRecord); 19 const record = ref<DataBoardRecord>({} as unknown as DataBoardRecord);
  20 + const link = ref('');
16 21
17 - const [register, { closeModal }] = useModalInner(async (data: DataBoardRecord) => {  
18 - record.value = data;  
19 - await nextTick();  
20 - setFieldsValue({  
21 - [FieldsEnum.IS_SHARE]: data.viewType === ViewTypeEnum.PUBLIC_VIEW,  
22 - [FieldsEnum.ACCESS_CREDENTIALS]: data.accessCredentials,  
23 - });  
24 - }); 22 + const [register, { closeModal }] = useModalInner(
  23 + async (data: ModalParamsType<DataBoardRecord>) => {
  24 + const { record: value, href } = data;
  25 + record.value = value;
  26 + link.value = href;
  27 + await nextTick();
  28 + setFieldsValue({
  29 + [FieldsEnum.IS_SHARE]: value.viewType === ViewTypeEnum.PUBLIC_VIEW,
  30 + [FieldsEnum.ACCESS_CREDENTIALS]: value.accessCredentials,
  31 + });
  32 + }
  33 + );
25 34
26 const [registerForm, { getFieldsValue, setFieldsValue }] = useForm({ 35 const [registerForm, { getFieldsValue, setFieldsValue }] = useForm({
27 schemas, 36 schemas,
@@ -32,6 +41,10 @@ @@ -32,6 +41,10 @@
32 41
33 const emit = defineEmits(['register', 'success']); 42 const emit = defineEmits(['register', 'success']);
34 43
  44 + const handleOpenLink = () => {
  45 + window.open(unref(link));
  46 + };
  47 +
35 const handleSubmit = async () => { 48 const handleSubmit = async () => {
36 try { 49 try {
37 loading.value = true; 50 loading.value = true;
@@ -44,6 +57,19 @@ @@ -44,6 +57,19 @@
44 loading.value = false; 57 loading.value = false;
45 } 58 }
46 }; 59 };
  60 +
  61 + const isPublicState = computed(() => {
  62 + return unref(record).viewType === ViewTypeEnum.PUBLIC_VIEW;
  63 + });
  64 +
  65 + const { clipboardRef, isSuccessRef } = useCopyToClipboard();
  66 + const { createMessage } = useMessage();
  67 + const handleCopy = () => {
  68 + clipboardRef.value = unref(link);
  69 + if (unref(isSuccessRef)) {
  70 + createMessage.success('复制成功~');
  71 + }
  72 + };
47 </script> 73 </script>
48 74
49 <template> 75 <template>
@@ -54,5 +80,27 @@ @@ -54,5 +80,27 @@
54 message="私有视图只有项目成员可以浏览,公开视图拥有一个公开的 URL,任何人无需登录即可浏览." 80 message="私有视图只有项目成员可以浏览,公开视图拥有一个公开的 URL,任何人无需登录即可浏览."
55 /> 81 />
56 <BasicForm @register="registerForm" /> 82 <BasicForm @register="registerForm" />
  83 + <section>
  84 + <div v-if="isPublicState" class="mt-4">
  85 + <span> 设置分享后, 可通过如下 </span>
  86 + <Button type="link" class="!px-1" @click="handleOpenLink"> 链接 </Button>
  87 + <span>访问:</span>
  88 + </div>
  89 + <Tooltip v-if="isPublicState" title="点击复制链接">
  90 + <div
  91 + class="px-4 py-2 my-2 bg-gray-50 font-semibold tracking-wider text-base cursor-pointer truncate"
  92 + @click="handleCopy"
  93 + >
  94 + <span>{{ link }}</span>
  95 + </div>
  96 + </Tooltip>
  97 +
  98 + <Alert type="warning">
  99 + <template #message>
  100 + <span class="font-bold mr-1">提示:</span>
  101 + <span>不要忘记将相关设备 <span class="mx-1 font-bold">公开</span> 以访问其数据</span>
  102 + </template>
  103 + </Alert>
  104 + </section>
57 </BasicModal> 105 </BasicModal>
58 </template> 106 </template>
@@ -28,6 +28,7 @@ @@ -28,6 +28,7 @@
28 import { ViewTypeNameEnum } from '../../common/ShareModal/config'; 28 import { ViewTypeNameEnum } from '../../common/ShareModal/config';
29 import { useModal } from '/@/components/Modal'; 29 import { useModal } from '/@/components/Modal';
30 import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard'; 30 import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
  31 + import { ViewType } from '../../visual/board/config/panelDetail';
31 32
32 const listColumn = ref(5); 33 const listColumn = ref(5);
33 34
@@ -153,17 +154,20 @@ @@ -153,17 +154,20 @@
153 getListData(); 154 getListData();
154 }; 155 };
155 156
156 - const { clipboardRef, isSuccessRef } = useCopyToClipboard();  
157 - const handleCreateShareUrl = (record: ConfigurationCenterItemsModal) => {  
158 - if (!unref(getShareFlag)) return;  
159 - const { origin } = location; 157 + const createShareUrl = (record: ConfigurationCenterItemsModal) => {
160 const searchParams = new URLSearchParams(); 158 const searchParams = new URLSearchParams();
161 isDev && searchParams.set('dev', '1'); 159 isDev && searchParams.set('dev', '1');
162 searchParams.set('share', 'SCADA'); 160 searchParams.set('share', 'SCADA');
163 searchParams.set('configurationId', record.id); 161 searchParams.set('configurationId', record.id);
164 searchParams.set('publicId', record.publicId || ''); 162 searchParams.set('publicId', record.publicId || '');
165 searchParams.set('lightbox', '1'); 163 searchParams.set('lightbox', '1');
166 - const url = `${origin}${configurationPrefix}/?${searchParams.toString()}`; 164 + return `${origin}${configurationPrefix}/?${searchParams.toString()}`;
  165 + };
  166 +
  167 + const { clipboardRef, isSuccessRef } = useCopyToClipboard();
  168 + const handleCreateShareUrl = (record: ConfigurationCenterItemsModal) => {
  169 + if (!unref(getShareFlag)) return;
  170 + const url = createShareUrl(record);
167 clipboardRef.value = url; 171 clipboardRef.value = url;
168 if (unref(isSuccessRef)) { 172 if (unref(isSuccessRef)) {
169 createMessage.success('复制成功~'); 173 createMessage.success('复制成功~');
@@ -173,7 +177,7 @@ @@ -173,7 +177,7 @@
173 const [registerShareModal, { openModal }] = useModal(); 177 const [registerShareModal, { openModal }] = useModal();
174 178
175 const handleOpenShareModal = (record: ConfigurationCenterItemsModal) => { 179 const handleOpenShareModal = (record: ConfigurationCenterItemsModal) => {
176 - openModal(true, record); 180 + openModal(true, { record, href: createShareUrl(record) });
177 }; 181 };
178 182
179 const listEl = ref<Nullable<ComponentElRef>>(null); 183 const listEl = ref<Nullable<ComponentElRef>>(null);
@@ -228,7 +232,13 @@ @@ -228,7 +232,13 @@
228 </template> 232 </template>
229 <template #renderItem="{ item }"> 233 <template #renderItem="{ item }">
230 <List.Item> 234 <List.Item>
231 - <Card hoverable class="card-container"> 235 + <Card
  236 + :style="{
  237 + '--viewType': item.viewType === ViewType.PUBLIC_VIEW ? '#1890ff' : '#faad14',
  238 + }"
  239 + hoverable
  240 + class="card-container"
  241 + >
232 <template #cover> 242 <template #cover>
233 <div 243 <div
234 class="img-container h-full w-full !flex justify-center items-center text-center p-1 relative" 244 class="img-container h-full w-full !flex justify-center items-center text-center p-1 relative"
@@ -357,6 +367,6 @@ @@ -357,6 +367,6 @@
357 } 367 }
358 368
359 .card-container:deep(.ant-card-cover) { 369 .card-container:deep(.ant-card-cover) {
360 - background-color: #2db7f5; 370 + background-color: var(--viewType);
361 } 371 }
362 </style> 372 </style>
@@ -29,6 +29,7 @@ @@ -29,6 +29,7 @@
29 import { ShareModal } from '/@/views/common/ShareModal'; 29 import { ShareModal } from '/@/views/common/ShareModal';
30 import { ViewTypeNameEnum } from '../common/ShareModal/config'; 30 import { ViewTypeNameEnum } from '../common/ShareModal/config';
31 import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard'; 31 import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
  32 + import { ViewType } from '../visual/board/config/panelDetail';
32 33
33 const listColumn = ref(5); 34 const listColumn = ref(5);
34 35
@@ -163,15 +164,18 @@ @@ -163,15 +164,18 @@
163 const getPublicApiListData = () => {}; 164 const getPublicApiListData = () => {};
164 165
165 const [registerShareModal, { openModal }] = useModal(); 166 const [registerShareModal, { openModal }] = useModal();
166 - const handleOpenShareModal = (item: BigScreenCenterItemsModel) => {  
167 - openModal(true, item); 167 + const handleOpenShareModal = (record: BigScreenCenterItemsModel) => {
  168 + openModal(true, { record, href: createShareUrl(record) });
  169 + };
  170 +
  171 + const createShareUrl = (record: BigScreenCenterItemsModel) => {
  172 + const { origin } = location;
  173 + return `${origin}${largeDesignerPrefix}/#/share/preview/${record.id}/${record.publicId}`;
168 }; 174 };
169 175
170 const { clipboardRef, isSuccessRef } = useCopyToClipboard(); 176 const { clipboardRef, isSuccessRef } = useCopyToClipboard();
171 const handleCreateShareUrl = (record: BigScreenCenterItemsModel) => { 177 const handleCreateShareUrl = (record: BigScreenCenterItemsModel) => {
172 - const { origin } = location;  
173 - const { largeDesignerPrefix } = useGlobSetting();  
174 - clipboardRef.value = `${origin}${largeDesignerPrefix}/#/share/preview/${record.id}/${record.publicId}`; 178 + clipboardRef.value = createShareUrl(record);
175 if (unref(isSuccessRef)) { 179 if (unref(isSuccessRef)) {
176 createMessage.success('复制成功~'); 180 createMessage.success('复制成功~');
177 } 181 }
@@ -223,7 +227,12 @@ @@ -223,7 +227,12 @@
223 </template> 227 </template>
224 <template #renderItem="{ item }"> 228 <template #renderItem="{ item }">
225 <List.Item> 229 <List.Item>
226 - <Card class="card-container"> 230 + <Card
  231 + :style="{
  232 + '--viewType': item.viewType === ViewType.PUBLIC_VIEW ? '#1890ff' : '#faad14',
  233 + }"
  234 + class="card-container"
  235 + >
227 <template #cover> 236 <template #cover>
228 <div class="h-full w-full relative hover-show-modal-content img-container"> 237 <div class="h-full w-full relative hover-show-modal-content img-container">
229 <img 238 <img
@@ -421,6 +430,6 @@ @@ -421,6 +430,6 @@
421 } 430 }
422 431
423 .card-container:deep(.ant-card-cover) { 432 .card-container:deep(.ant-card-cover) {
424 - background-color: #2db7f5; 433 + background-color: var(--viewType);
425 } 434 }
426 </style> 435 </style>
  1 +import { DescItem } from '/@/components/Description';
  2 +import {
  3 + ExecuteTimeTypeEnum,
  4 + ExecuteTimeTypeNameEnum,
  5 + FormFieldsEnum,
  6 + PeriodTypeNameEnum,
  7 +} from '../DetailModal/config';
  8 +import { TaskStatusEnum, TaskTargetEnum, TaskTargetNameEnum } from '../../config';
  9 +import { h } from 'vue';
  10 +import { Tag } from 'ant-design-vue';
  11 +import { TaskStatusNameEnum } from '../../config';
  12 +import { TaskRecordType } from '/@/api/task/model';
  13 +import { TaskTypeNameEnum } from '../../config';
  14 +import { TimeUnitNameEnum } from '/@/enums/toolEnum';
  15 +import { PeriodTypeEnum } from '../DetailModal/config';
  16 +
  17 +enum WeekEnum {
  18 + MON = 'MON',
  19 + TUES = 'TUES',
  20 + WED = 'WED',
  21 + THUR = 'THUR',
  22 + FRI = 'FRI',
  23 + SAT = 'SAT',
  24 + SUN = 'SUN',
  25 +}
  26 +
  27 +enum WeekNameEnum {
  28 + MON = '星期一',
  29 + TUES = '星期二',
  30 + WED = '星期三',
  31 + THUR = '星期四',
  32 + FRI = '星期五',
  33 + SAT = '星期六',
  34 + SUN = '星期天',
  35 +}
  36 +
  37 +const isWeek = (string: string) => {
  38 + return Object.keys(WeekEnum).some((item) => string.includes(item));
  39 +};
  40 +
  41 +const extractCronExpression = (expression: string) => {
  42 + const flag = isWeek(expression);
  43 + const list = expression.split(' ');
  44 + const unit = flag ? list[list.length - 1] : list[3];
  45 + return flag ? WeekNameEnum[unit] : unit;
  46 +};
  47 +
  48 +export const schemas: DescItem[] = [
  49 + {
  50 + field: FormFieldsEnum.NAME,
  51 + label: '任务名',
  52 + },
  53 + {
  54 + field: FormFieldsEnum.TARGET_TYPE,
  55 + label: '目标类型',
  56 + render(val: TaskTargetEnum) {
  57 + return h(
  58 + Tag,
  59 + { color: val === TaskTargetEnum.DEVICES ? 'blue' : 'cyan' },
  60 + () => TaskTargetNameEnum[val]
  61 + );
  62 + },
  63 + },
  64 + {
  65 + field: 'state',
  66 + label: '任务状态',
  67 + render(val: TaskStatusEnum) {
  68 + return h(
  69 + Tag,
  70 + { color: val === TaskStatusEnum.NORMAL ? 'success' : 'error' },
  71 + () => TaskStatusNameEnum[TaskStatusEnum[val]]
  72 + );
  73 + },
  74 + },
  75 + {
  76 + field: FormFieldsEnum.EXECUTE_CONTENT_TYPE,
  77 + label: '任务类型',
  78 + render(_val: any, data: TaskRecordType) {
  79 + return TaskTypeNameEnum[data.executeContent.type];
  80 + },
  81 + },
  82 + {
  83 + field: FormFieldsEnum.EXECUTE_TIME_TYPE,
  84 + label: '定时方式',
  85 + render(_val: any, data: TaskRecordType) {
  86 + return ExecuteTimeTypeNameEnum[data.executeTime.type];
  87 + },
  88 + },
  89 + {
  90 + field: FormFieldsEnum.EXECUTE_TIME_INTERVAL,
  91 + label: '间隔时间',
  92 + render(_val: any, data: TaskRecordType) {
  93 + const { executeTime } = data;
  94 + const { time, type, periodType, pollUnit, period } = executeTime;
  95 + console.log({ time, type, periodType, pollUnit });
  96 + return type === ExecuteTimeTypeEnum.POLL
  97 + ? `${time}${TimeUnitNameEnum[pollUnit]}`
  98 + : `${PeriodTypeNameEnum[periodType]} ${
  99 + periodType === PeriodTypeEnum.DAY
  100 + ? ''
  101 + : `/ ${extractCronExpression(period)}${isWeek(period) ? '' : '号'}`
  102 + } / ${time}`;
  103 + },
  104 + },
  105 + {
  106 + field: 'createTime',
  107 + label: '创建时间',
  108 + },
  109 + {
  110 + field: 'updateTime',
  111 + label: '修改时间',
  112 + },
  113 +];
  1 +export { default as DetailDrawer } from './index.vue';
  1 +<script lang="ts" setup>
  2 + import { useDescription, Description } from '/@/components/Description';
  3 + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  4 + import { schemas } from './config';
  5 + import { ModalParamsType } from '/#/utils';
  6 + import { TaskRecordType } from '/@/api/task/model';
  7 + defineEmits(['register']);
  8 +
  9 + const [registerDrawer] = useDrawerInner((data: ModalParamsType<TaskRecordType>) => {
  10 + const { record } = data;
  11 + setDescProps({ data: record });
  12 + });
  13 +
  14 + const [registerDescription, { setDescProps }] = useDescription({
  15 + schema: schemas,
  16 + labelStyle: { width: '120px' },
  17 + column: 1,
  18 + });
  19 +</script>
  20 +
  21 +<template>
  22 + <BasicDrawer title="任务详情" @register="registerDrawer" width="30%">
  23 + <Description @register="registerDescription" />
  24 + </BasicDrawer>
  25 +</template>
@@ -263,14 +263,20 @@ export const formSchemas: FormSchema[] = [ @@ -263,14 +263,20 @@ export const formSchemas: FormSchema[] = [
263 label: '周期', 263 label: '周期',
264 required: true, 264 required: true,
265 defaultValue: PeriodTypeEnum.MONTH, 265 defaultValue: PeriodTypeEnum.MONTH,
266 - componentProps: {  
267 - placeholder: '请选择周期',  
268 - options: [  
269 - { label: PeriodTypeNameEnum.DAY, value: PeriodTypeEnum.DAY },  
270 - { label: PeriodTypeNameEnum.WEEK, value: PeriodTypeEnum.WEEK },  
271 - { label: PeriodTypeNameEnum.MONTH, value: PeriodTypeEnum.MONTH },  
272 - ],  
273 - getPopupContainer: () => document.body, 266 + componentProps: ({ formActionType }) => {
  267 + const { setFieldsValue } = formActionType;
  268 + return {
  269 + placeholder: '请选择周期',
  270 + options: [
  271 + { label: PeriodTypeNameEnum.DAY, value: PeriodTypeEnum.DAY },
  272 + { label: PeriodTypeNameEnum.WEEK, value: PeriodTypeEnum.WEEK },
  273 + { label: PeriodTypeNameEnum.MONTH, value: PeriodTypeEnum.MONTH },
  274 + ],
  275 + getPopupContainer: () => document.body,
  276 + onChange() {
  277 + setFieldsValue({ [FormFieldsEnum.EXECUTE_TIME_PERIOD]: null });
  278 + },
  279 + };
274 }, 280 },
275 ifShow: ({ model }) => model[FormFieldsEnum.EXECUTE_TIME_TYPE] === ExecuteTimeTypeEnum.CUSTOM, 281 ifShow: ({ model }) => model[FormFieldsEnum.EXECUTE_TIME_TYPE] === ExecuteTimeTypeEnum.CUSTOM,
276 }, 282 },
@@ -6,10 +6,11 @@ @@ -6,10 +6,11 @@
6 import { composeData, parseData } from './util'; 6 import { composeData, parseData } from './util';
7 import { createTask, updateTask } from '/@/api/task'; 7 import { createTask, updateTask } from '/@/api/task';
8 import { ModalParamsType } from '/#/utils'; 8 import { ModalParamsType } from '/#/utils';
9 - import { DataActionModeEnum } from '/@/enums/toolEnum'; 9 + import { DataActionModeEnum, DataActionModeNameEnum } from '/@/enums/toolEnum';
10 import { TaskRecordType } from '/@/api/task/model'; 10 import { TaskRecordType } from '/@/api/task/model';
11 import { FormValueType } from './util'; 11 import { FormValueType } from './util';
12 import { unref } from 'vue'; 12 import { unref } from 'vue';
  13 + import { computed } from 'vue';
13 14
14 const props = defineProps<{ 15 const props = defineProps<{
15 reload: Fn; 16 reload: Fn;
@@ -18,6 +19,8 @@ @@ -18,6 +19,8 @@
18 19
19 const formMode = ref(DataActionModeEnum.CREATE); 20 const formMode = ref(DataActionModeEnum.CREATE);
20 21
  22 + const modalMode = ref<DataActionModeEnum>(DataActionModeEnum.CREATE);
  23 +
21 const dataSource = ref<TaskRecordType>(); 24 const dataSource = ref<TaskRecordType>();
22 const [registerModal, { closeModal }] = useModalInner( 25 const [registerModal, { closeModal }] = useModalInner(
23 ( 26 (
@@ -26,6 +29,7 @@ @@ -26,6 +29,7 @@
26 mode: DataActionModeEnum.CREATE, 29 mode: DataActionModeEnum.CREATE,
27 } 30 }
28 ) => { 31 ) => {
  32 + modalMode.value = mode;
29 dataSource.value = record; 33 dataSource.value = record;
30 formMode.value = mode; 34 formMode.value = mode;
31 resetFields(); 35 resetFields();
@@ -62,12 +66,16 @@ @@ -62,12 +66,16 @@
62 loading.value = false; 66 loading.value = false;
63 } 67 }
64 }; 68 };
  69 +
  70 + const getTitle = computed(() => {
  71 + return `${DataActionModeNameEnum[unref(modalMode)]}任务`;
  72 + });
65 </script> 73 </script>
66 74
67 <template> 75 <template>
68 <BasicModal 76 <BasicModal
69 @register="registerModal" 77 @register="registerModal"
70 - title="创建任务" 78 + :title="getTitle"
71 width="700px" 79 width="700px"
72 :okButtonProps="{ loading }" 80 :okButtonProps="{ loading }"
73 @ok="handleOk" 81 @ok="handleOk"
1 -import CronParser, { CronFields, HourRange, SixtyRange } from 'cron-parser'; 1 +import { HourRange, SixtyRange } from 'cron-parser';
2 import { dateUtil } from '/@/utils/dateUtil'; 2 import { dateUtil } from '/@/utils/dateUtil';
3 -import { ExecuteTimeTypeEnum, FormFieldsEnum, PushWayEnum } from './config'; 3 +import { ExecuteTimeTypeEnum, FormFieldsEnum, PeriodTypeEnum, PushWayEnum } from './config';
4 import { CreateTaskRecordType, TaskRecordType } from '/@/api/task/model'; 4 import { CreateTaskRecordType, TaskRecordType } from '/@/api/task/model';
5 import { DeviceCascadePickerValueType } from '../DevicePicker'; 5 import { DeviceCascadePickerValueType } from '../DevicePicker';
6 import { TaskTargetEnum } from '../../config'; 6 import { TaskTargetEnum } from '../../config';
@@ -12,52 +12,31 @@ export interface FormValueType extends Partial<Record<FormFieldsEnum, any>> { @@ -12,52 +12,31 @@ export interface FormValueType extends Partial<Record<FormFieldsEnum, any>> {
12 [FormFieldsEnum.DEVICE_PROFILE]: ProductCascadePickerValueType; 12 [FormFieldsEnum.DEVICE_PROFILE]: ProductCascadePickerValueType;
13 } 13 }
14 14
15 -type CanWrite<T> = {  
16 - -readonly [K in keyof T]: T[K];  
17 -};  
18 -  
19 interface GenCronExpressionResultType { 15 interface GenCronExpressionResultType {
20 effective: boolean; 16 effective: boolean;
21 expression?: string; 17 expression?: string;
22 } 18 }
23 19
24 -export const usePluginGenCronExpression = (  
25 - time: string,  
26 - expression = '* * * * * * *',  
27 - includesYear = true  
28 -): GenCronExpressionResultType => {  
29 - try {  
30 - const separator = ' ';  
31 - const removeYear = expression.split(separator).slice(0, 6).join(separator);  
32 -  
33 - const date = dateUtil(time, 'HH:mm:ss');  
34 -  
35 - const second = date.get('second') as SixtyRange;  
36 - const minute = date.get('minute') as SixtyRange;  
37 - const hour = date.get('hour') as HourRange;  
38 -  
39 - const result = CronParser.parseExpression(removeYear, { utc: true, nthDayOfWeek: 4 });  
40 - const fields = JSON.parse(JSON.stringify(result.fields)) as CanWrite<CronFields>;  
41 - fields.second = [second];  
42 - fields.minute = [minute];  
43 - fields.hour = [hour];  
44 -  
45 - // console.log(CronParser.fieldsToExpression(CronParser.parseExpression('').fields).stringify());  
46 -  
47 - let newExpression = CronParser.fieldsToExpression(fields).stringify(true);  
48 - newExpression = includesYear ? `${newExpression} *` : newExpression;  
49 - return { effective: true, expression: newExpression };  
50 - } catch (error) {  
51 - // throw error;  
52 - return { effective: false };  
53 - } 20 +export const genPollCronExpression = (value: number, type: TimeUnitEnum) => {
  21 + const placeholder = 'placeholder';
  22 + const expression = {
  23 + [TimeUnitEnum.SECOND]: `${placeholder} * * * * ? *`,
  24 + [TimeUnitEnum.MINUTE]: `* ${placeholder} * * * ? *`,
  25 + [TimeUnitEnum.HOUR]: `* * ${placeholder} * * ? *`,
  26 + };
  27 + const newExpression = expression[type];
  28 + return newExpression.replace(placeholder, `0/${value}`);
54 }; 29 };
55 30
56 export const genCronExpression = ( 31 export const genCronExpression = (
57 time: string, 32 time: string,
58 - expression = '* * * * * * *' 33 + expression = '* * * * * * *',
  34 + periodType: PeriodTypeEnum
59 ): GenCronExpressionResultType => { 35 ): GenCronExpressionResultType => {
60 try { 36 try {
  37 + if (periodType === PeriodTypeEnum.DAY) {
  38 + expression = '* * * * * ? *';
  39 + }
61 const separator = ' '; 40 const separator = ' ';
62 const list: (string | number)[] = expression.split(separator); 41 const list: (string | number)[] = expression.split(separator);
63 42
@@ -103,10 +82,12 @@ export const composeData = (result: Required<FormValueType>): CreateTaskRecordTy @@ -103,10 +82,12 @@ export const composeData = (result: Required<FormValueType>): CreateTaskRecordTy
103 deviceType: productDeviceType, 82 deviceType: productDeviceType,
104 } = deviceProfile || {}; 83 } = deviceProfile || {};
105 84
106 - const { expression } = genCronExpression(time, period); 85 + const { expression } = genCronExpression(time, period, periodType);
107 86
108 const cron = 87 const cron =
109 - executeTimeType === ExecuteTimeTypeEnum.POLL ? `0/${interval} * * * * ? *` : expression!; 88 + executeTimeType === ExecuteTimeTypeEnum.POLL
  89 + ? genPollCronExpression(interval, pollUnit)
  90 + : expression!;
110 91
111 return { 92 return {
112 name, 93 name,
@@ -63,8 +63,9 @@ export const formSchemas: FormSchema[] = [ @@ -63,8 +63,9 @@ export const formSchemas: FormSchema[] = [
63 { 63 {
64 field: FormFieldsEnum.TARGET_IDS, 64 field: FormFieldsEnum.TARGET_IDS,
65 component: 'ApiSelect', 65 component: 'ApiSelect',
66 - label: '定目标设备', 66 + label: '定目标设备',
67 ifShow: ({ model }) => model[FormFieldsEnum.EXECUTE_TARGET_TYPE] === TargetType.ASSIGN, 67 ifShow: ({ model }) => model[FormFieldsEnum.EXECUTE_TARGET_TYPE] === TargetType.ASSIGN,
  68 + rules: [{ required: true, message: '请选择指定目标设备' }],
68 componentProps: ({ formModel }) => { 69 componentProps: ({ formModel }) => {
69 const record = JSON.parse(formModel[FormFieldsEnum.TASK_RECORD]) as TaskRecordType; 70 const record = JSON.parse(formModel[FormFieldsEnum.TASK_RECORD]) as TaskRecordType;
70 const isDevices = record.targetType === TaskTargetEnum.DEVICES; 71 const isDevices = record.targetType === TaskTargetEnum.DEVICES;
@@ -24,7 +24,7 @@ @@ -24,7 +24,7 @@
24 } 24 }
25 }); 25 });
26 26
27 - const [registerForm, { setFieldsValue, getFieldsValue, resetFields }] = useForm({ 27 + const [registerForm, { setFieldsValue, getFieldsValue, resetFields, validate }] = useForm({
28 schemas: formSchemas, 28 schemas: formSchemas,
29 showActionButtonGroup: false, 29 showActionButtonGroup: false,
30 }); 30 });
@@ -37,7 +37,8 @@ @@ -37,7 +37,8 @@
37 ? TaskTargetEnum.DEVICES 37 ? TaskTargetEnum.DEVICES
38 : unref(dataSource)!.targetType, 38 : unref(dataSource)!.targetType,
39 id: unref(dataSource)!.id, 39 id: unref(dataSource)!.id,
40 - targetIds, 40 + targetIds:
  41 + executeTarget === TargetType.ASSIGN ? targetIds : unref(dataSource)?.executeTarget.data,
41 cronExpression: unref(dataSource)!.executeTime.cron, 42 cronExpression: unref(dataSource)!.executeTime.cron,
42 name: unref(dataSource)!.name, 43 name: unref(dataSource)!.name,
43 }; 44 };
@@ -46,6 +47,7 @@ @@ -46,6 +47,7 @@
46 const loading = ref(false); 47 const loading = ref(false);
47 const { createMessage } = useMessage(); 48 const { createMessage } = useMessage();
48 const handleOk = async () => { 49 const handleOk = async () => {
  50 + await validate();
49 const record = getFieldsValue() as FormValue; 51 const record = getFieldsValue() as FormValue;
50 const value = composeData(record); 52 const value = composeData(record);
51 try { 53 try {
@@ -21,6 +21,7 @@ @@ -21,6 +21,7 @@
21 enum DropMenuEvent { 21 enum DropMenuEvent {
22 DELETE = 'DELETE', 22 DELETE = 'DELETE',
23 EDIT = 'EDIT', 23 EDIT = 'EDIT',
  24 + DETAIL = 'DETAIL',
24 } 25 }
25 26
26 const props = withDefaults( 27 const props = withDefaults(
@@ -35,7 +36,7 @@ @@ -35,7 +36,7 @@
35 } 36 }
36 ); 37 );
37 38
38 - const emit = defineEmits(['edit', 'runTask']); 39 + const emit = defineEmits(['edit', 'runTask', 'detail']);
39 40
40 const loading = ref(false); 41 const loading = ref(false);
41 42
@@ -131,6 +132,12 @@ @@ -131,6 +132,12 @@
131 :trigger="['hover']" 132 :trigger="['hover']"
132 :drop-menu-list="[ 133 :drop-menu-list="[
133 { 134 {
  135 + text: '详情',
  136 + event: DropMenuEvent.DETAIL,
  137 + icon: 'ant-design:eye-outlined',
  138 + onClick: emit.bind(null, 'detail', getRecord),
  139 + },
  140 + {
134 text: '编辑', 141 text: '编辑',
135 event: DropMenuEvent.DELETE, 142 event: DropMenuEvent.DELETE,
136 disabled: !!getRecord.state, 143 disabled: !!getRecord.state,
@@ -190,12 +197,14 @@ @@ -190,12 +197,14 @@
190 </div> 197 </div>
191 </div> 198 </div>
192 <div class="mt-4 flex justify-between items-center gap-3"> 199 <div class="mt-4 flex justify-between items-center gap-3">
193 - <Button size="small" @click="handleRunTask">  
194 - <div class="text-xs px-1">  
195 - <PlayCircleOutlined class="mr-1" />  
196 - <span>运行任务</span>  
197 - </div>  
198 - </Button> 200 + <Authority :value="PermissionEnum.EXECUTE">
  201 + <Button size="small" @click="handleRunTask">
  202 + <div class="text-xs px-1">
  203 + <PlayCircleOutlined class="mr-1" />
  204 + <span>运行任务</span>
  205 + </div>
  206 + </Button>
  207 + </Authority>
199 <Tooltip 208 <Tooltip
200 v-if="getLastExecuteTime" 209 v-if="getLastExecuteTime"
201 overlay-class-name="task-last-execute-time-tooltip" 210 overlay-class-name="task-last-execute-time-tooltip"
@@ -6,6 +6,7 @@ export enum PermissionEnum { @@ -6,6 +6,7 @@ export enum PermissionEnum {
6 START_TASK = 'api:yt:task_center:update:state', 6 START_TASK = 'api:yt:task_center:update:state',
7 DELETE = 'api:yt:task_center:delete', 7 DELETE = 'api:yt:task_center:delete',
8 ALLOW = 'api:yt:task_center:cancel:allow', 8 ALLOW = 'api:yt:task_center:cancel:allow',
  9 + EXECUTE = 'api:yt:task_center:immediate:execute',
9 } 10 }
10 11
11 export enum FormFieldsEnum { 12 export enum FormFieldsEnum {
@@ -17,13 +18,11 @@ export enum FormFieldsEnum { @@ -17,13 +18,11 @@ export enum FormFieldsEnum {
17 export enum TaskTargetEnum { 18 export enum TaskTargetEnum {
18 DEVICES = 'DEVICES', 19 DEVICES = 'DEVICES',
19 PRODUCTS = 'PRODUCTS', 20 PRODUCTS = 'PRODUCTS',
20 - ALL = 'all',  
21 } 21 }
22 22
23 export enum TaskTargetNameEnum { 23 export enum TaskTargetNameEnum {
24 DEVICES = '设备', 24 DEVICES = '设备',
25 PRODUCTS = '产品', 25 PRODUCTS = '产品',
26 - ALL = '不限任务目标类型',  
27 } 26 }
28 27
29 export enum TaskTypeEnum { 28 export enum TaskTypeEnum {
@@ -43,7 +42,7 @@ export enum TaskStatusEnum { @@ -43,7 +42,7 @@ export enum TaskStatusEnum {
43 42
44 export enum TaskStatusNameEnum { 43 export enum TaskStatusNameEnum {
45 DEACTIVATE = '已停用', 44 DEACTIVATE = '已停用',
46 - NORMAL = '正常', 45 + NORMAL = '已启用',
47 } 46 }
48 47
49 export const formSchemas: FormSchema[] = [ 48 export const formSchemas: FormSchema[] = [
@@ -17,8 +17,11 @@ @@ -17,8 +17,11 @@
17 import { Authority } from '/@/components/Authority'; 17 import { Authority } from '/@/components/Authority';
18 import { getBoundingClientRect } from '/@/utils/domUtils'; 18 import { getBoundingClientRect } from '/@/utils/domUtils';
19 import { RunTaskModal } from './components/RunTaskModal'; 19 import { RunTaskModal } from './components/RunTaskModal';
  20 + import { DetailDrawer } from './components/DetailDrawer';
  21 + import { useDrawer } from '/@/components/Drawer';
20 22
21 const [registerModal, { openModal }] = useModal(); 23 const [registerModal, { openModal }] = useModal();
  24 + const [registerDrawer, { openDrawer }] = useDrawer();
22 const [registerRunTaskModal, { openModal: openRunTaskModal }] = useModal(); 25 const [registerRunTaskModal, { openModal: openRunTaskModal }] = useModal();
23 26
24 const [registerForm, { getFieldsValue }] = useForm({ 27 const [registerForm, { getFieldsValue }] = useForm({
@@ -28,7 +31,6 @@ @@ -28,7 +31,6 @@
28 showAdvancedButton: true, 31 showAdvancedButton: true,
29 labelWidth: 100, 32 labelWidth: 100,
30 submitFunc: async () => { 33 submitFunc: async () => {
31 - pagination.params = getFieldsValue();  
32 getDataSource(); 34 getDataSource();
33 }, 35 },
34 }); 36 });
@@ -39,7 +41,6 @@ @@ -39,7 +41,6 @@
39 showQuickJumper: true, 41 showQuickJumper: true,
40 size: 'small', 42 size: 'small',
41 showTotal: (total: number) => `共 ${total} 条数据`, 43 showTotal: (total: number) => `共 ${total} 条数据`,
42 - params: {} as Recordable,  
43 }); 44 });
44 45
45 const dataSource = ref<TaskRecordType[]>([]); 46 const dataSource = ref<TaskRecordType[]>([]);
@@ -47,7 +48,8 @@ @@ -47,7 +48,8 @@
47 const getDataSource = async () => { 48 const getDataSource = async () => {
48 try { 49 try {
49 loading.value = true; 50 loading.value = true;
50 - const { items } = await getTaskCenterList({ page: 1, pageSize: 10, ...pagination.params }); 51 + const params = getFieldsValue();
  52 + const { items } = await getTaskCenterList({ page: 1, pageSize: 10, ...params });
51 dataSource.value = items; 53 dataSource.value = items;
52 } catch (error) { 54 } catch (error) {
53 throw error; 55 throw error;
@@ -67,6 +69,10 @@ @@ -67,6 +69,10 @@
67 openRunTaskModal(true, record); 69 openRunTaskModal(true, record);
68 }; 70 };
69 71
  72 + const handleDetail = (record: TaskRecordType) => {
  73 + openDrawer(true, { mode: DataActionModeEnum.READ, record } as ModalParamsType);
  74 + };
  75 +
70 const reload = () => getDataSource(); 76 const reload = () => getDataSource();
71 77
72 const listElRef = ref<Nullable<ComponentElRef>>(null); 78 const listElRef = ref<Nullable<ComponentElRef>>(null);
@@ -137,11 +143,18 @@ @@ -137,11 +143,18 @@
137 </template> 143 </template>
138 <template #renderItem="{ item }"> 144 <template #renderItem="{ item }">
139 <List.Item :key="item.id"> 145 <List.Item :key="item.id">
140 - <TaskCard :record="item" :reload="reload" @runTask="handleRunTask" @edit="handleEdit" /> 146 + <TaskCard
  147 + :record="item"
  148 + :reload="reload"
  149 + @runTask="handleRunTask"
  150 + @detail="handleDetail"
  151 + @edit="handleEdit"
  152 + />
141 </List.Item> 153 </List.Item>
142 </template> 154 </template>
143 </List> 155 </List>
144 </section> 156 </section>
  157 + <DetailDrawer @register="registerDrawer" />
145 <DetailModal @register="registerModal" :reload="reload" /> 158 <DetailModal @register="registerModal" :reload="reload" />
146 <RunTaskModal :reload="reload" @register="registerRunTaskModal" /> 159 <RunTaskModal :reload="reload" @register="registerRunTaskModal" />
147 </PageWrapper> 160 </PageWrapper>
@@ -55,10 +55,10 @@ export function useSendCommand() { @@ -55,10 +55,10 @@ export function useSendCommand() {
55 }, 55 },
56 }); 56 });
57 createMessage.success('命令下发成功'); 57 createMessage.success('命令下发成功');
  58 + return true;
58 } catch (msg) { 59 } catch (msg) {
  60 + console.log('enter');
59 return error(); 61 return error();
60 - } finally {  
61 - return true;  
62 } 62 }
63 }; 63 };
64 return { 64 return {
@@ -60,7 +60,8 @@ @@ -60,7 +60,8 @@
60 const resetFormFields = async () => { 60 const resetFormFields = async () => {
61 const hasExistEl = Object.keys(dataSourceEl).filter((key) => dataSourceEl[key]); 61 const hasExistEl = Object.keys(dataSourceEl).filter((key) => dataSourceEl[key]);
62 for (const id of hasExistEl) { 62 for (const id of hasExistEl) {
63 - await dataSourceEl[id]?.resetFields(); 63 + const oldValues = dataSourceEl[id]?.getFieldsValue();
  64 + dataSourceEl[id]?.setFieldsValue({ ...oldValues, [DataSourceField.ATTRIBUTE]: null });
64 } 65 }
65 }; 66 };
66 67
@@ -268,10 +269,8 @@ @@ -268,10 +269,8 @@
268 watch( 269 watch(
269 () => props.frontId, 270 () => props.frontId,
270 async (target, oldTarget) => { 271 async (target, oldTarget) => {
271 - if (isControlComponent(oldTarget!)) return;  
272 - if (isControlComponent(target!)) {  
273 - await resetFormFields();  
274 - } 272 + if (isControlComponent(oldTarget!) && isControlComponent(target!)) return;
  273 + await resetFormFields();
275 } 274 }
276 ); 275 );
277 276
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 list: Recordable[]; 16 list: Recordable[];
17 } 17 }
18 const props = defineProps<{ 18 const props = defineProps<{
19 - value: string; 19 + value?: string;
20 }>(); 20 }>();
21 const emit = defineEmits(['update:value', 'change']); 21 const emit = defineEmits(['update:value', 'change']);
22 22
@@ -10,7 +10,6 @@ import { findDictItemByCode } from '/@/api/system/dict'; @@ -10,7 +10,6 @@ import { findDictItemByCode } from '/@/api/system/dict';
10 import { DeviceTypeEnum } from '/@/api/device/model/deviceModel'; 10 import { DeviceTypeEnum } from '/@/api/device/model/deviceModel';
11 import { DataTypeEnum } from '/@/components/Form/src/externalCompns/components/StructForm/config'; 11 import { DataTypeEnum } from '/@/components/Form/src/externalCompns/components/StructForm/config';
12 import { TransportTypeEnum } from '/@/views/device/profiles/components/TransportDescript/const'; 12 import { TransportTypeEnum } from '/@/views/device/profiles/components/TransportDescript/const';
13 -import { nextTick } from 'vue';  
14 13
15 export enum BasicConfigField { 14 export enum BasicConfigField {
16 NAME = 'name', 15 NAME = 'name',
@@ -183,7 +182,7 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For @@ -183,7 +182,7 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For
183 colProps: { span: 8 }, 182 colProps: { span: 8 },
184 rules: [{ required: true, message: '组织为必填项' }], 183 rules: [{ required: true, message: '组织为必填项' }],
185 componentProps({ formActionType }) { 184 componentProps({ formActionType }) {
186 - const { setFieldsValue, getFieldsValue } = formActionType; 185 + const { setFieldsValue } = formActionType;
187 return { 186 return {
188 placeholder: '请选择组织', 187 placeholder: '请选择组织',
189 api: async () => { 188 api: async () => {
@@ -195,9 +194,6 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For @@ -195,9 +194,6 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For
195 setFieldsValue({ 194 setFieldsValue({
196 [DataSourceField.DEVICE_ID]: null, 195 [DataSourceField.DEVICE_ID]: null,
197 }); 196 });
198 - nextTick(() => {  
199 - console.log('org change', getFieldsValue());  
200 - });  
201 }, 197 },
202 getPopupContainer: () => document.body, 198 getPopupContainer: () => document.body,
203 }; 199 };
@@ -76,7 +76,7 @@ @@ -76,7 +76,7 @@
76 }); 76 });
77 77
78 const getSharePageData = computed(() => { 78 const getSharePageData = computed(() => {
79 - return props.value; 79 + return props.value!;
80 }); 80 });
81 81
82 const getIsSharePage = computed(() => { 82 const getIsSharePage = computed(() => {
@@ -230,8 +230,9 @@ @@ -230,8 +230,9 @@
230 const getDataBoradDetail = async () => { 230 const getDataBoradDetail = async () => {
231 try { 231 try {
232 return unref(getIsSharePage) ? unref(getSharePageData) : await getBasePageComponentData(); 232 return unref(getIsSharePage) ? unref(getSharePageData) : await getBasePageComponentData();
233 - } catch (error) {}  
234 - return {} as ComponentInfoDetail; 233 + } catch (error) {
  234 + return {} as ComponentInfoDetail;
  235 + }
235 }; 236 };
236 237
237 const loading = ref(false); 238 const loading = ref(false);
@@ -22,6 +22,8 @@ @@ -22,6 +22,8 @@
22 import { useForm, BasicForm } from '/@/components/Form'; 22 import { useForm, BasicForm } from '/@/components/Form';
23 import { formSchema } from './config/searchForm'; 23 import { formSchema } from './config/searchForm';
24 import { ShareModal } from '/@/views/common/ShareModal'; 24 import { ShareModal } from '/@/views/common/ShareModal';
  25 + import { ModalParamsType } from '/#/utils';
  26 + import { DataActionModeEnum } from '/@/enums/toolEnum';
25 27
26 const ListItem = List.Item; 28 const ListItem = List.Item;
27 const router = useRouter(); 29 const router = useRouter();
@@ -133,7 +135,11 @@ @@ -133,7 +135,11 @@
133 }; 135 };
134 136
135 const handleOpenShareModal = (record: DataBoardRecord) => { 137 const handleOpenShareModal = (record: DataBoardRecord) => {
136 - openShareModal(true, record); 138 + openShareModal(true, {
  139 + record,
  140 + mode: DataActionModeEnum.READ,
  141 + href: createShareUrl(record),
  142 + } as ModalParamsType<DataBoardRecord>);
137 }; 143 };
138 144
139 const handleMenuEvent = (event: DropMenu, record: DataBoardRecord) => { 145 const handleMenuEvent = (event: DropMenu, record: DataBoardRecord) => {
@@ -8,4 +8,5 @@ export type DynamicProps<T> = { @@ -8,4 +8,5 @@ export type DynamicProps<T> = {
8 export interface ModalParamsType<T = Recordable> { 8 export interface ModalParamsType<T = Recordable> {
9 mode: DataActionModeEnum; 9 mode: DataActionModeEnum;
10 record: T; 10 record: T;
  11 + [key: string]: any;
11 } 12 }