Commit 41168f200bbb3a94f81fb2da52c829381b9a1f5c

Authored by fengtao
2 parents 134ced98 b16b7e2b

Merge branch 'main' into ft

... ... @@ -52,9 +52,6 @@
52 52 slots: { customRender: 'action' },
53 53 fixed: 'right',
54 54 },
55   - // beforeFetch: (data) => {
56   - // Reflect.set(data, 'startTime', null);
57   - // },
58 55 });
59 56 const [registerDetailDrawer, { openDrawer }] = useDrawer();
60 57 const handleDetail = (record: Recordable) => {
... ...
... ... @@ -98,7 +98,7 @@
98 98 </div>
99 99 </template>
100 100 <script lang="ts" setup>
101   - import { ref, reactive, onMounted } from 'vue';
  101 + import { ref, reactive } from 'vue';
102 102 import { Card, DatePicker } from 'ant-design-vue';
103 103 import VisitAnalysis from './VisitAnalysis.vue';
104 104 import VisitAnalysisBar from './VisitAnalysisBar.vue';
... ... @@ -451,10 +451,6 @@
451 451 send(sendValue);
452 452 }
453 453 }
454   - onMounted(() => {
455   - console.log(props.role);
456   - });
457   -
458 454 const {
459 455 tenantDateValue,
460 456 customerDateValue,
... ...
... ... @@ -2,8 +2,7 @@
2 2 <div class="step2">
3 3 <BasicForm @register="registerForm">
4 4 <template #addAgree="{ model, field }">
5   - <Checkbox v-model:checked="model[field]" @change="checkedChange" />
6   - <span class="ml-2">添加协议</span>
  5 + <Checkbox v-model:checked="model[field]" @change="checkedChange">添加协议</Checkbox>
7 6 </template>
8 7 </BasicForm>
9 8 <div>
... ...
... ... @@ -102,6 +102,8 @@
102 102 Modal.info({
103 103 title: '当前配置',
104 104 width: 600,
  105 + centered: true,
  106 + maskClosable: true,
105 107 content: h(JsonPreview, { data: JSON.parse(JSON.stringify(record.config)) }),
106 108 });
107 109 }
... ...
... ... @@ -3,9 +3,10 @@
3 3 v-bind="$attrs"
4 4 @register="register"
5 5 title="邮件发送参数"
  6 + centered
6 7 :okButtonProps="{ disabled: true }"
7 8 @ok="handleOK"
8   - width="700px"
  9 + :width="700"
9 10 >
10 11 <div class="pt-6px pr-6px">
11 12 <BasicForm @register="registerForm" />
... ...
... ... @@ -79,6 +79,8 @@
79 79 Modal.info({
80 80 title: '当前配置',
81 81 width: 480,
  82 + centered: true,
  83 + maskClosable: true,
82 84 content: h(JsonPreview, { data: JSON.parse(JSON.stringify(record.templateParam)) }),
83 85 });
84 86 }
... ...
... ... @@ -14,12 +14,12 @@ export const columns: BasicColumn[] = [
14 14 {
15 15 title: '短信平台',
16 16 dataIndex: 'typeDictText',
17   - width: 180,
  17 + width: 160,
18 18 },
19 19 {
20 20 title: '用途',
21 21 dataIndex: 'templatePurposeDictText',
22   - width: 180,
  22 + width: 160,
23 23 },
24 24 {
25 25 title: '状态',
... ... @@ -38,12 +38,12 @@ export const columns: BasicColumn[] = [
38 38 {
39 39 title: '备注',
40 40 dataIndex: 'remark',
41   - width: 180,
  41 + width: 160,
42 42 },
43 43 {
44 44 title: '发送时间',
45 45 dataIndex: 'sendTime',
46   - width: 180,
  46 + width: 160,
47 47 },
48 48 ];
49 49
... ...
... ... @@ -181,9 +181,21 @@
181 181 setEditAlarmConfig(skipUnwrap.actionItemRefs, editAlarmConfigData);
182 182 });
183 183
  184 + const map = {
  185 + ANY_TIME: 0,
  186 + SPECIFIC_TIME: 1,
  187 + CUSTOM: 2,
  188 + };
184 189 // 回显触发器数据---此处是个闭包!
185 190 triggers.forEach((trigger, index) => {
186 191 nextTick(async () => {
  192 + // 回显启用规则
  193 + unref(skipUnwrap.triggerItemRefs)[index].currentIndex =
  194 + map[trigger.triggerCondition.schedule.type];
  195 + unref(skipUnwrap.triggerItemRefs)[index].scheduleData = trigger.triggerCondition.schedule;
  196 + unref(skipUnwrap.triggerItemRefs)[index].isUpdate = true;
  197 + unref(skipUnwrap.triggerItemRefs)[index].alarmScheduleRef.scheduleData =
  198 + trigger.triggerCondition.schedule;
187 199 unref(skipUnwrap.triggerItemRefs)[index].setFieldsFormValueFun({
188 200 triggered: trigger?.triggerCondition?.condition?.spec?.type,
189 201 device: trigger?.entityType,
... ... @@ -235,6 +247,14 @@
235 247
236 248 doConditions.forEach((condition, index) => {
237 249 nextTick(async () => {
  250 + // 回显启用规则
  251 + unref(skipUnwrap.conditionItemRefs)[index].currentIndex =
  252 + map[condition.triggerCondition.schedule.type];
  253 + unref(skipUnwrap.conditionItemRefs)[index].scheduleData =
  254 + condition.triggerCondition.schedule;
  255 + unref(skipUnwrap.conditionItemRefs)[index].isUpdate = true;
  256 + unref(skipUnwrap.conditionItemRefs)[index].alarmScheduleRef.scheduleData =
  257 + condition.triggerCondition.schedule;
238 258 unref(skipUnwrap.conditionItemRefs)[index].setFieldsFormValueFun({
239 259 triggered: condition?.triggerCondition?.condition?.spec?.type,
240 260 device: condition?.entityType,
... ... @@ -311,6 +331,13 @@
311 331 nextTick(async () => {
312 332 unref(skipUnwrap.actionItemRefs)[index].refItem.clearRuleRefs.value.map(
313 333 (item, index) => {
  334 + // 回显启用规则
  335 + item.currentIndex =
  336 + map[action.doContext.clearRule[index].triggerCondition.schedule.type];
  337 + item.scheduleData = action.doContext.clearRule[index].triggerCondition.schedule;
  338 + item.isUpdate = true;
  339 + item.alarmScheduleRef.scheduleData =
  340 + action.doContext.clearRule[index].triggerCondition.schedule;
314 341 item.setFieldsFormValueFun({
315 342 triggered:
316 343 action.doContext.clearRule[index].triggerCondition.condition.spec.type,
... ... @@ -459,15 +486,15 @@
459 486 * 获取触发器、执行条件、执行动作表单值--多个
460 487 */
461 488 const getFormValueFunc = () => {
462   - getTriggerFormValue.value = unref(skipUnwrap.triggerItemRefs)?.map((item) => {
463   - return genTriggerOrConditionData(item.getFieldsValueFunc());
464   - });
465   - getConditionFormValue.value = unref(skipUnwrap.conditionItemRefs).map((item) => {
466   - return genTriggerOrConditionData(item.getFieldsValueFunc());
467   - });
468   - getActionFormValue.value = unref(skipUnwrap.actionItemRefs).map((item) => {
469   - return genActionData(item.getFieldsValueFunc());
470   - });
  489 + getTriggerFormValue.value = unref(skipUnwrap.triggerItemRefs)?.map((item) =>
  490 + genTriggerOrConditionData(item.getFieldsValueFunc())
  491 + );
  492 + getConditionFormValue.value = unref(skipUnwrap.conditionItemRefs).map((item) =>
  493 + genTriggerOrConditionData(item.getFieldsValueFunc())
  494 + );
  495 + getActionFormValue.value = unref(skipUnwrap.actionItemRefs).map((item) =>
  496 + genActionData(item.getFieldsValueFunc())
  497 + );
471 498 };
472 499 const handleSubmit = async () => {
473 500 let basicFormValue = await validate();
... ...
1 1 import { ref } from 'vue';
2 2 import { BasicColumn, FormSchema } from '/@/components/Table';
3 3 import { screenLinkOrganizationGetApi } from '/@/api/ruleengine/ruleengineApi';
  4 +import { scheduleOptions } from './formatData';
4 5
5 6 import { copyTransFun } from '/@/utils/fnUtils';
6 7
... ... @@ -392,3 +393,79 @@ export const actionSchema: FormSchema[] = [
392 393 slot: 'clearAlarm',
393 394 },
394 395 ];
  396 +
  397 +export const alarmScheduleSchemas: FormSchema[] = [
  398 + {
  399 + field: 'schedule',
  400 + label: '',
  401 + component: 'Select',
  402 + componentProps({ formActionType }) {
  403 + const { resetFields } = formActionType;
  404 + return {
  405 + options: scheduleOptions,
  406 + allowClear: false,
  407 + onChange(value) {
  408 + console.log(value);
  409 + resetFields();
  410 + },
  411 + };
  412 + },
  413 + },
  414 + {
  415 + field: 'timezone',
  416 + label: '时区',
  417 + component: 'Select',
  418 + defaultValue: 'Asia/Shanghai',
  419 + componentProps: {
  420 + options: [
  421 + {
  422 + label: 'Asia/Shanghai',
  423 + value: 'Asia/Shanghai',
  424 + },
  425 + ],
  426 + allowClear: false,
  427 + },
  428 + ifShow: ({ values }) => values.schedule !== 'ANY_TIME',
  429 + },
  430 + {
  431 + field: 'daysOfWeek',
  432 + label: '天',
  433 + component: 'CheckboxGroup',
  434 + rules: [
  435 + {
  436 + message: '请至少选择一天',
  437 + required: true,
  438 + },
  439 + ],
  440 + componentProps: {
  441 + options: [
  442 + { label: '星期一', value: 1 },
  443 + { label: '星期二', value: 2 },
  444 + { label: '星期三', value: 3 },
  445 + { label: '星期四', value: 4 },
  446 + { label: '星期五', value: 5 },
  447 + { label: '星期六', value: 6 },
  448 + { label: '星期日', value: 7 },
  449 + ],
  450 + },
  451 + colProps: {
  452 + span: 24,
  453 + },
  454 + ifShow: ({ values }) => values.schedule === 'SPECIFIC_TIME',
  455 + },
  456 + {
  457 + field: 'time',
  458 + label: '时间',
  459 + labelWidth: 40,
  460 + component: 'RangePicker',
  461 + ifShow: ({ values }) => values.schedule === 'SPECIFIC_TIME',
  462 + slot: 'timing',
  463 + },
  464 + {
  465 + field: 'day',
  466 + label: '天',
  467 + component: 'CheckboxGroup',
  468 + slot: 'customEnable',
  469 + ifShow: ({ values }) => values.schedule === 'CUSTOM',
  470 + },
  471 +];
... ...
... ... @@ -60,13 +60,7 @@ export const genTriggerOrConditionData = (triggerData) => {
60 60 },
61 61 },
62 62 },
63   - schedule: {
64   - type: schedule,
65   - // timezone: 'Asia/Shanghai',
66   - // daysOfWeek: [2, 3],
67   - // startsOn: 8700000,
68   - // endsOn: 30300000,
69   - },
  63 + schedule,
70 64 },
71 65 };
72 66 };
... ... @@ -81,6 +75,7 @@ export const genActionData = (actionData) => {
81 75 device,
82 76 deviceId,
83 77 } = actionData;
  78 + console.log(actionData);
84 79 const clearRule = clearRules.map((item) => {
85 80 const mapPredicate = item.predicate.map((pred) => {
86 81 return {
... ... @@ -117,13 +112,7 @@ export const genActionData = (actionData) => {
117 112 },
118 113 },
119 114 },
120   - schedule: {
121   - type: item.schedule,
122   - // timezone: 'Asia/Shanghai',
123   - // daysOfWeek: [2, 3],
124   - // startsOn: 8700000,
125   - // endsOn: 30300000,
126   - },
  115 + schedule: item.schedule,
127 116 },
128 117 };
129 118 });
... ...
  1 +<template>
  2 + <BasicModal
  3 + v-bind="$attrs"
  4 + :width="600"
  5 + title="编辑报警日程"
  6 + centered
  7 + @register="registerModal"
  8 + @ok="handleOk"
  9 + @cancel="handleCancel"
  10 + >
  11 + <BasicForm @register="registerForm" ref="basicFormRef">
  12 + <template #customEnable>
  13 + <template v-for="(item, optionIndex) in options" :key="item.flag">
  14 + <div :class="optionIndex >= 1 ? 'mt-4' : ''">
  15 + <Checkbox v-model:checked="item.enabled">星期{{ item.flag }}</Checkbox>
  16 + <TimePicker
  17 + size="small"
  18 + placeholder="开始时间"
  19 + v-model:value="item.startsOn"
  20 + value-format="x"
  21 + format="HH:mm"
  22 + :disabled="!item.enabled"
  23 + />
  24 + ~
  25 + <TimePicker
  26 + size="small"
  27 + placeholder="结束时间"
  28 + v-model:value="item.endsOn"
  29 + value-format="x"
  30 + format="HH:mm"
  31 + :disabled="!item.enabled"
  32 + /> </div
  33 + ></template>
  34 + </template>
  35 + <template #timing>
  36 + <TimePicker
  37 + size="small"
  38 + placeholder="开始时间"
  39 + v-model:value="timeState.startsOn"
  40 + value-format="x"
  41 + format="HH:mm"
  42 + />
  43 + ~
  44 + <TimePicker
  45 + size="small"
  46 + placeholder="结束时间"
  47 + v-model:value="timeState.endsOn"
  48 + value-format="x"
  49 + format="HH:mm"
  50 + />
  51 + </template>
  52 + </BasicForm>
  53 + </BasicModal>
  54 +</template>
  55 +
  56 +<script lang="ts" setup>
  57 + import { reactive, ref, watch, nextTick } from 'vue';
  58 + import { useModalInner, BasicModal } from '/@/components/Modal';
  59 + import { BasicForm, useForm } from '/@/components/Form';
  60 + import { alarmScheduleSchemas } from '../config/config.data.ts';
  61 + import { Checkbox, TimePicker } from 'ant-design-vue';
  62 + const emit = defineEmits(['register', 'cancel']);
  63 + const [registerForm, { setFieldsValue, getFieldsValue }] = useForm({
  64 + showActionButtonGroup: false,
  65 + schemas: alarmScheduleSchemas,
  66 + });
  67 + const timeState = reactive({
  68 + startsOn: null,
  69 + endsOn: null,
  70 + });
  71 +
  72 + const options = ref([
  73 + {
  74 + enabled: false,
  75 + dayOfWeek: 1,
  76 + flag: '一',
  77 + endsOn: null,
  78 + startsOn: null,
  79 + },
  80 + {
  81 + enabled: false,
  82 + dayOfWeek: 2,
  83 + flag: '二',
  84 + endsOn: null,
  85 + startsOn: null,
  86 + },
  87 + {
  88 + enabled: false,
  89 + dayOfWeek: 3,
  90 + flag: '三',
  91 + endsOn: null,
  92 + startsOn: null,
  93 + },
  94 + {
  95 + enabled: false,
  96 + dayOfWeek: 4,
  97 + flag: '四',
  98 + endsOn: null,
  99 + startsOn: null,
  100 + },
  101 + {
  102 + enabled: false,
  103 + dayOfWeek: 5,
  104 + flag: '五',
  105 + endsOn: null,
  106 + startsOn: null,
  107 + },
  108 + {
  109 + enabled: false,
  110 + dayOfWeek: 6,
  111 + flag: '六',
  112 + endsOn: null,
  113 + startsOn: null,
  114 + },
  115 + {
  116 + enabled: false,
  117 + dayOfWeek: 7,
  118 + flag: '日',
  119 + endsOn: null,
  120 + startsOn: null,
  121 + },
  122 + ]);
  123 + const basicFormRef = ref<InstanceType<typeof BasicForm>>();
  124 + let index = ref(null);
  125 + watch(
  126 + options,
  127 + (newValue) => {
  128 + const arr = [];
  129 + for (let item of newValue) {
  130 + if (item.enabled && item.startsOn && item.endsOn) {
  131 + arr.push(true);
  132 + } else if ((!item.enabled && item.startsOn && item.endsOn) || item.enabled) {
  133 + arr.push(false);
  134 + }
  135 + }
  136 + console.log(arr);
  137 + const flag = arr.length ? !arr.every((item) => item) : true;
  138 + console.log(flag);
  139 + nextTick(() => {
  140 + setModalProps({
  141 + okButtonProps: {
  142 + disabled: flag,
  143 + },
  144 + });
  145 + });
  146 + },
  147 + {
  148 + deep: true,
  149 + }
  150 + );
  151 +
  152 + const [registerModal, { closeModal, setModalProps }] = useModalInner((data) => {
  153 + watch([timeState, basicFormRef.value.formModel], ([timeState, formModel]) => {
  154 + setModalProps({
  155 + okButtonProps: {
  156 + disabled:
  157 + timeState.startsOn === null ||
  158 + timeState.endsOn === null ||
  159 + !formModel.daysOfWeek?.length,
  160 + },
  161 + });
  162 + watch(
  163 + () => formModel.schedule,
  164 + () => {
  165 + timeState.startsOn = null;
  166 + timeState.endsOn = null;
  167 + }
  168 + );
  169 + });
  170 + const { value, currentIndex, isUpdate, scheduleData } = data;
  171 + index.value = currentIndex;
  172 + const dayZenoTime = Math.round(new Date(new Date().toLocaleDateString()).getTime());
  173 + // 编辑
  174 + setFieldsValue({
  175 + schedule: value,
  176 + });
  177 + if (isUpdate) {
  178 + nextTick(() => {
  179 + // 回显定时启用
  180 + if (scheduleData.type === 'SPECIFIC_TIME') {
  181 + setFieldsValue({
  182 + daysOfWeek: scheduleData.daysOfWeek,
  183 + });
  184 + timeState.startsOn = scheduleData.startsOn + dayZenoTime + '';
  185 + timeState.endsOn = scheduleData.endsOn + dayZenoTime + '';
  186 + }
  187 + // 回显自定义启用
  188 + if (scheduleData.type === 'CUSTOM') {
  189 + for (let [index, item] of scheduleData?.items.entries()) {
  190 + if (item.enabled) {
  191 + options.value[index].enabled = item.enabled;
  192 + options.value[index].startsOn = item.startsOn + dayZenoTime + '';
  193 + options.value[index].endsOn = item.endsOn + dayZenoTime + '';
  194 + }
  195 + }
  196 + }
  197 + });
  198 + }
  199 + });
  200 + const scheduleData = ref({
  201 + type: 'ANY_TIME',
  202 + });
  203 + const handleOk = () => {
  204 + const { schedule: type, timezone, daysOfWeek } = getFieldsValue();
  205 + // 获取当天0时时间戳
  206 + const dayZenoTime = Math.round(new Date(new Date().toLocaleDateString()).getTime());
  207 + if (type === 'CUSTOM') {
  208 + const items = options.value.map((item) => {
  209 + return {
  210 + startsOn: item.startsOn ? item.startsOn - dayZenoTime : 0,
  211 + endsOn: item.endsOn ? item.endsOn - dayZenoTime : 0,
  212 + dayOfWeek: item.dayOfWeek,
  213 + enabled: item.enabled,
  214 + };
  215 + });
  216 + scheduleData.value = {
  217 + type,
  218 + timezone,
  219 + items,
  220 + };
  221 + } else if (type === 'SPECIFIC_TIME') {
  222 + scheduleData.value = {
  223 + type,
  224 + timezone,
  225 + daysOfWeek,
  226 + startsOn: timeState.startsOn - dayZenoTime,
  227 + endsOn: timeState.endsOn - dayZenoTime,
  228 + };
  229 + }
  230 + closeModal();
  231 + };
  232 + const handleCancel = () => {
  233 + emit('cancel', index.value);
  234 + };
  235 +
  236 + defineExpose({
  237 + scheduleData,
  238 + });
  239 +</script>
  240 +
  241 +<style lang="less" scoped></style>
... ...
... ... @@ -2,9 +2,18 @@
2 2 <div>
3 3 <CollapseContainer style="background-color: #f2f2f2" title="清除告警" :canExpan="false">
4 4 <template #action>
5   - <div>
6   - <span class="mr-2">启用规则</span>
7   - <RadioGroup v-model:value="schedule" :options="scheduleOptions" />
  5 + <div class="flex">
  6 + <div class="flex">
  7 + <span class="mr-2">启用规则:</span>
  8 + <template v-for="(item, scheduleIndex) in scheduleOptions" :key="item.label">
  9 + <div
  10 + :class="{ 'ml-4': scheduleIndex >= 1, active: scheduleIndex === currentIndex }"
  11 + class="cursor-pointer"
  12 + @click="handleScheduleChange(item.value)"
  13 + >{{ item.label }}</div
  14 + >
  15 + </template>
  16 + </div>
8 17 <Tooltip title="移除" class="ml-4">
9 18 <Icon
10 19 icon="fluent:delete-off-20-regular"
... ... @@ -45,19 +54,22 @@
45 54 />
46 55 </Card>
47 56 </CollapseContainer>
  57 + <AlarmSchedule ref="alarmScheduleRef" @register="registerModal" @cancel="handleCancel" />
48 58 </div>
49 59 </template>
50 60 <script lang="ts" setup>
51   - import { ref, provide } from 'vue';
  61 + import { ref, provide, nextTick } from 'vue';
52 62 import { CollapseContainer } from '/@/components/Container/index';
53 63 import { BasicForm, useForm } from '/@/components/Form/index';
54   - import { Radio, Card, Select, Input, Tooltip } from 'ant-design-vue';
  64 + import { Card, Select, Input, Tooltip } from 'ant-design-vue';
55 65 import { trigger_condition_schema } from '../config/config.data.ts';
56 66 import { getAttribute } from '/@/api/ruleengine/ruleengineApi';
57 67 import ConditionScreening from './ConditionScreening.vue';
58 68 import { scheduleOptions, timeUnitOptions, options } from '../config/formatData.ts';
59   -
60 69 import { Icon } from '/@/components/Icon';
  70 + import AlarmSchedule from './AlarmSchedule.vue';
  71 + import { useModal } from '/@/components/Modal';
  72 +
61 73 defineProps({
62 74 index: {
63 75 type: Number,
... ... @@ -69,13 +81,21 @@
69 81 },
70 82 });
71 83 const emit = defineEmits(['delete']);
72   - const RadioGroup = Radio.Group;
73   -
  84 + const isUpdate = ref(false);
  85 + const conditionScreeningRef = ref();
74 86 const [registerForm, { resetFields, getFieldsValue, updateSchema, setFieldsValue }] = useForm({
75 87 schemas: trigger_condition_schema,
76 88 showActionButtonGroup: false,
77 89 });
78 90
  91 + const alarmScheduleRef = ref<InstanceType<typeof AlarmSchedule>>();
  92 + const getFieldsValueFunc = () => {
  93 + const predicate = conditionScreeningRef?.value?.refItem?.conditionScreeningRefs?.value?.map(
  94 + (item) => item.getFieldsValue()
  95 + );
  96 + return { ...getFieldsValue(), predicate, schedule: alarmScheduleRef.value.scheduleData };
  97 + };
  98 +
79 99 const updateFieldDeviceId = (deviceList: any[]) => {
80 100 updateSchema({
81 101 field: 'entityId',
... ... @@ -89,7 +109,7 @@
89 109 },
90 110 });
91 111 };
92   - const conditionScreeningRef = ref();
  112 +
93 113 const resetFieldsValueFunc = () => resetFields();
94 114 // 回显数据函数
95 115 const setFieldsFormValueFun = (fieldsValue) => {
... ... @@ -115,10 +135,50 @@
115 135 const operationType = ref<string>('');
116 136 provide('operationType', operationType);
117 137
118   - const childGetFieldsValue = () => getFieldsValue();
119 138 const handleDelete = (index: number) => {
120 139 emit('delete', index);
121 140 };
  141 +
  142 + // 子组件获取父组件的值
  143 + const childGetFieldsValue = () => getFieldsValue();
  144 +
  145 + // 获取conditionScreeningForm的组件
  146 + const getRefItemConditionScreeningRefs = async () => {
  147 + await nextTick();
  148 + return conditionScreeningRef.value.refItem.conditionScreeningRefs;
  149 + };
  150 +
  151 + const setConditionScreeningList = (list) => {
  152 + conditionScreeningRef.value.conditionScreeningList = list;
  153 + };
  154 + const setRichText = (list) => {
  155 + conditionScreeningRef.value.otherAttribute = list;
  156 + };
  157 +
  158 + const currentIndex = ref(0);
  159 + const [registerModal, { openModal }] = useModal();
  160 + const handleScheduleChange = (value) => {
  161 + const index = scheduleOptions.findIndex((item) => item.value === value);
  162 + // 报警日程弹窗
  163 + if (index !== 0) {
  164 + openModal(true, {
  165 + isUpdate: isUpdate.value,
  166 + value,
  167 + currentIndex: currentIndex.value,
  168 + scheduleData,
  169 + });
  170 + } else {
  171 + alarmScheduleRef.value.scheduleData = {
  172 + type: value,
  173 + };
  174 + console.log(value);
  175 + }
  176 + currentIndex.value = index;
  177 + };
  178 + const handleCancel = (index) => {
  179 + currentIndex.value = index;
  180 + };
  181 + const scheduleData = ref(null);
122 182 defineExpose({
123 183 getFieldsValue,
124 184 updateFieldDeviceId,
... ... @@ -128,5 +188,18 @@
128 188 conditionScreeningRef,
129 189 schedule,
130 190 operationType,
  191 + getFieldsValueFunc,
  192 + getRefItemConditionScreeningRefs,
  193 + setConditionScreeningList,
  194 + setRichText,
  195 + currentIndex,
  196 + scheduleData,
  197 + isUpdate,
  198 + alarmScheduleRef,
131 199 });
132 200 </script>
  201 +<style>
  202 + .active {
  203 + color: #377dff;
  204 + }
  205 +</style>
... ...
... ... @@ -54,6 +54,7 @@
54 54 label: '和',
55 55 component: 'Input',
56 56 slot: 'and',
  57 + labelWidth: 50,
57 58 colProps: { span: 3 },
58 59 },
59 60 'value'
... ...
... ... @@ -74,7 +74,4 @@
74 74 padding: 1rem 0 0.5rem;
75 75 border-radius: 0.25rem;
76 76 }
77   - .ant-input-number {
78   - width: 200px;
79   - }
80 77 </style>
... ...
... ... @@ -3,13 +3,16 @@
3 3 <CollapseContainer style="background-color: #f2f2f2" :title="`${title} ${index + 1}`">
4 4 <template #action>
5 5 <div class="flex">
6   - <div>
7   - <span class="mr-2">启用规则</span>
8   - <RadioGroup
9   - v-model:value="schedule"
10   - :options="scheduleOptions"
11   - @change="handleRadioGroupChange"
12   - />
  6 + <div class="flex">
  7 + <span class="mr-2">启用规则:</span>
  8 + <template v-for="(item, scheduleIndex) in scheduleOptions" :key="item.label">
  9 + <div
  10 + :class="{ 'ml-4': scheduleIndex >= 1, active: scheduleIndex === currentIndex }"
  11 + class="cursor-pointer"
  12 + @click="handleScheduleChange(item.value)"
  13 + >{{ item.label }}</div
  14 + >
  15 + </template>
13 16 </div>
14 17 <Tooltip title="移除" class="ml-4">
15 18 <Icon
... ... @@ -50,6 +53,7 @@
50 53 />
51 54 </Card>
52 55 </CollapseContainer>
  56 + <AlarmSchedule ref="alarmScheduleRef" @register="registerModal" @cancel="handleCancel" />
53 57 </div>
54 58 </template>
55 59 <script lang="ts" setup>
... ... @@ -57,12 +61,13 @@
57 61 import { CollapseContainer } from '/@/components/Container/index';
58 62 import { BasicForm, useForm } from '/@/components/Form/index';
59 63 import { Icon } from '/@/components/Icon';
60   - import { Tooltip, Radio, Card, Select, Input } from 'ant-design-vue';
  64 + import { Tooltip, Card, Select, Input } from 'ant-design-vue';
61 65 import { trigger_condition_schema } from '../config/config.data.ts';
62 66 import { getAttribute } from '/@/api/ruleengine/ruleengineApi';
63 67 import ConditionScreening from './ConditionScreening.vue';
64 68 import { scheduleOptions, timeUnitOptions, options } from '../config/formatData.ts';
65   - const RadioGroup = Radio.Group;
  69 + import AlarmSchedule from './AlarmSchedule.vue';
  70 + import { useModal } from '/@/components/Modal';
66 71
67 72 defineProps({
68 73 title: {
... ... @@ -75,19 +80,20 @@
75 80 },
76 81 });
77 82 const emit = defineEmits(['delete']);
  83 + const isUpdate = ref(false);
78 84 const conditionScreeningRef = ref();
79 85 const [registerForm, { resetFields, getFieldsValue, updateSchema, setFieldsValue }] = useForm({
80 86 schemas: trigger_condition_schema,
81 87 showActionButtonGroup: false,
82 88 });
83 89
  90 + const alarmScheduleRef = ref<InstanceType<typeof AlarmSchedule>>();
84 91 const getFieldsValueFunc = () => {
85 92 const predicate = conditionScreeningRef?.value?.refItem?.conditionScreeningRefs?.value?.map(
86   - (item) => {
87   - return item.getFieldsValue();
88   - }
  93 + (item) => item.getFieldsValue()
89 94 );
90   - return { ...getFieldsValue(), predicate, schedule: schedule.value };
  95 +
  96 + return { ...getFieldsValue(), predicate, schedule: alarmScheduleRef.value.scheduleData };
91 97 };
92 98 const updateFieldDeviceId = (deviceList: any[]) => {
93 99 updateSchema({
... ... @@ -108,8 +114,8 @@
108 114 setFieldsValue(fieldsValue);
109 115 };
110 116 const updateFieldAttributeFunc = async () => {
111   - const data1 = await getAttribute();
112   - const options = data1.map((m) => {
  117 + const data = await getAttribute();
  118 + const options = data.map((m) => {
113 119 return {
114 120 label: m,
115 121 value: m,
... ... @@ -127,8 +133,6 @@
127 133 const handleDelete = (params: { index: number; title: string }) => {
128 134 emit('delete', params);
129 135 };
130   -
131   - const schedule = ref('ANY_TIME');
132 136 const operationType = ref<string>('');
133 137 provide('operationType', operationType);
134 138
... ... @@ -148,16 +152,30 @@
148 152 conditionScreeningRef.value.otherAttribute = list;
149 153 };
150 154
151   - const handleRadioGroupChange = (e) => {
152   - const { value } = e.target;
153   - if (value === 'SPECIFIC_TIME') {
154   - console.log('定时启用');
155   - // 定时启用
156   - } else if (value === 'CUSTOM') {
157   - console.log('自定义启用');
158   - // 自定义启用
  155 + const [registerModal, { openModal }] = useModal();
  156 + const currentIndex = ref(0);
  157 + const handleScheduleChange = (value) => {
  158 + const index = scheduleOptions.findIndex((item) => item.value === value);
  159 + // 报警日程弹窗
  160 + if (index !== 0) {
  161 + openModal(true, {
  162 + isUpdate: isUpdate.value,
  163 + value,
  164 + currentIndex: currentIndex.value,
  165 + scheduleData,
  166 + });
  167 + } else {
  168 + alarmScheduleRef.value.scheduleData = {
  169 + type: value,
  170 + };
  171 + console.log(value);
159 172 }
  173 + currentIndex.value = index;
  174 + };
  175 + const handleCancel = (index) => {
  176 + currentIndex.value = index;
160 177 };
  178 + const scheduleData = ref(null);
161 179 defineExpose({
162 180 getFieldsValueFunc,
163 181 updateFieldDeviceId,
... ... @@ -168,6 +186,15 @@
168 186 getRefItemConditionScreeningRefs,
169 187 setConditionScreeningList,
170 188 setRichText,
171   - setFormList,
  189 + currentIndex,
  190 + scheduleData,
  191 + isUpdate,
  192 + alarmScheduleRef,
172 193 });
173 194 </script>
  195 +
  196 +<style>
  197 + .active {
  198 + color: #377dff;
  199 + }
  200 +</style>
... ...
... ... @@ -123,19 +123,19 @@
123 123 const predicate = item.conditionScreeningRef?.refItem?.conditionScreeningRefs?.value?.map(
124 124 (item) => item.getFieldsValue()
125 125 );
126   -
127 126 return {
128 127 ...item.getFieldsValue(),
129 128 predicate,
130   - schedule: item?.schedule,
  129 + schedule: item.alarmScheduleRef.scheduleData,
131 130 };
132 131 });
133 132 return {
134 133 ...getFieldsValue(),
135   - doContext: unref(jsonInstance.value).get(),
  134 + doContext: unref(jsonInstance.value)?.get(),
136 135 clearRule,
137 136 };
138 137 };
  138 +
139 139 const setFieldsFormValueFun = (fieldsValue) => {
140 140 setFieldsValue(fieldsValue);
141 141 };
... ... @@ -163,7 +163,6 @@
163 163 options: alarmConfigList,
164 164 },
165 165 });
166   - hasDisabled.value = false;
167 166 userStore.setOutTarget('DEVICE_OUT');
168 167 };
169 168
... ...
... ... @@ -48,8 +48,7 @@
48 48 <SceneLinkAgeDrawer @register="registerDrawer" @success="handleSuccess" />
49 49 </div>
50 50 </template>
51   -<script lang="ts">
52   - import { defineComponent } from 'vue';
  51 +<script lang="ts" setup>
53 52 import { BasicTable, useTable, TableAction } from '/@/components/Table';
54 53 import { useDrawer } from '/@/components/Drawer';
55 54 import {
... ... @@ -62,110 +61,88 @@
62 61 import { columns, searchFormSchema } from './config/config.data.ts';
63 62 import { USER_INFO_KEY } from '/@/enums/cacheEnum';
64 63 import { getAuthCache } from '/@/utils/auth';
65   - import { authBtn } from '/@/enums/roleEnum';
66 64 import SceneLinkAgeDrawer from './SceneLinkAgeDrawer.vue';
67 65 import { useMessage } from '/@/hooks/web/useMessage';
68 66
69   - export default defineComponent({
70   - name: 'LinkEdge',
71   - components: { BasicTable, SceneLinkAgeDrawer, TableAction, Switch },
72   - setup() {
73   - const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions, resetSelectedRowKeys } =
74   - useBatchDelete(screenLinkPageDeleteApi, handleSuccess);
75   - selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => {
76   - // Demo:status为1的选择框禁用
77   - if (record.status === 1) {
78   - return { disabled: true };
79   - } else {
80   - return { disabled: false };
81   - }
82   - };
  67 + const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions, resetSelectedRowKeys } =
  68 + useBatchDelete(screenLinkPageDeleteApi, handleSuccess);
  69 + selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => {
  70 + // Demo:status为1的选择框禁用
  71 + if (record.status === 1) {
  72 + return { disabled: true };
  73 + } else {
  74 + return { disabled: false };
  75 + }
  76 + };
83 77
84   - const userInfo: any = getAuthCache(USER_INFO_KEY);
85   - const userId = userInfo.userId;
86   - const role: string = userInfo.roles[0];
87   - const [registerDrawer, { openDrawer }] = useDrawer();
88   - const [registerTable, { reload, setProps, setSelectedRowKeys }] = useTable({
89   - title: '场景联动列表',
90   - api: screenLinkPageGetApi,
91   - columns,
92   - formConfig: {
93   - labelWidth: 120,
94   - schemas: searchFormSchema,
95   - },
96   - useSearchForm: true,
97   - showTableSetting: true,
98   - bordered: true,
99   - showIndexColumn: false,
100   - actionColumn: {
101   - width: 200,
102   - title: '操作',
103   - dataIndex: 'action',
104   - slots: { customRender: 'action' },
105   - fixed: 'right',
106   - },
107   - ...selectionOptions,
108   - });
109   -
110   - function handleAdd() {
111   - openDrawer(true, {
112   - isUpdate: false,
113   - });
114   - }
115   -
116   - function handleEdit(record: Recordable) {
117   - openDrawer(true, {
118   - record,
119   - isUpdate: true,
120   - });
121   - }
122   - function handleView(record: Recordable) {
123   - openDrawer(true, {
124   - record,
125   - isUpdate: 3,
126   - });
127   - }
128   - function handleSuccess() {
129   - reload();
130   - }
  78 + const userInfo: any = getAuthCache(USER_INFO_KEY);
  79 + const userId = userInfo.userId;
131 80
132   - const statusChange = async (checked, record) => {
133   - // record.pendingStatus = true;
134   - setProps({
135   - loading: true,
136   - });
137   - setSelectedRowKeys([]);
138   - resetSelectedRowKeys();
139   - const newStatus = checked ? 1 : 0;
140   - const { createMessage } = useMessage();
141   - try {
142   - await screenLinkPagePutApi({ id: record.id, status: newStatus });
143   - if (newStatus) {
144   - createMessage.success(`启用成功`);
145   - } else {
146   - createMessage.success('禁用成功');
147   - }
148   - } finally {
149   - setProps({
150   - loading: false,
151   - });
152   - reload();
153   - }
154   - };
155   - return {
156   - registerTable,
157   - registerDrawer,
158   - handleAdd,
159   - handleEdit,
160   - handleSuccess,
161   - hasBatchDelete,
162   - handleDeleteOrBatchDelete,
163   - handleView,
164   - authBtn,
165   - role,
166   - userId,
167   - statusChange,
168   - };
  81 + const [registerDrawer, { openDrawer }] = useDrawer();
  82 + const [registerTable, { reload, setProps, setSelectedRowKeys }] = useTable({
  83 + title: '场景联动列表',
  84 + api: screenLinkPageGetApi,
  85 + columns,
  86 + formConfig: {
  87 + labelWidth: 120,
  88 + schemas: searchFormSchema,
169 89 },
  90 + useSearchForm: true,
  91 + showTableSetting: true,
  92 + bordered: true,
  93 + showIndexColumn: false,
  94 + actionColumn: {
  95 + width: 200,
  96 + title: '操作',
  97 + dataIndex: 'action',
  98 + slots: { customRender: 'action' },
  99 + fixed: 'right',
  100 + },
  101 + ...selectionOptions,
170 102 });
  103 +
  104 + function handleAdd() {
  105 + openDrawer(true, {
  106 + isUpdate: false,
  107 + });
  108 + }
  109 +
  110 + function handleEdit(record: Recordable) {
  111 + openDrawer(true, {
  112 + record,
  113 + isUpdate: true,
  114 + });
  115 + }
  116 + function handleView(record: Recordable) {
  117 + openDrawer(true, {
  118 + record,
  119 + isUpdate: 3,
  120 + });
  121 + }
  122 + function handleSuccess() {
  123 + reload();
  124 + }
  125 +
  126 + const statusChange = async (checked, record) => {
  127 + setProps({
  128 + loading: true,
  129 + });
  130 + setSelectedRowKeys([]);
  131 + resetSelectedRowKeys();
  132 + const newStatus = checked ? 1 : 0;
  133 + const { createMessage } = useMessage();
  134 + try {
  135 + await screenLinkPagePutApi({ id: record.id, status: newStatus });
  136 + if (newStatus) {
  137 + createMessage.success(`启用成功`);
  138 + } else {
  139 + createMessage.success('禁用成功');
  140 + }
  141 + } finally {
  142 + setProps({
  143 + loading: false,
  144 + });
  145 + reload();
  146 + }
  147 + };
171 148 </script>
... ...
1 1 import { BasicColumn, FormSchema } from '/@/components/Table';
2 2 import { h } from 'vue';
3   -import { Tag, Switch } from 'ant-design-vue';
4   -import { useMessage } from '/@/hooks/web/useMessage';
5   -import { updateTransformScriptStatusApi } from '/@/api/device/TransformScriptApi';
  3 +import { Tag } from 'ant-design-vue';
6 4 export const columns: BasicColumn[] = [
7 5 {
8 6 title: '名称',
... ... @@ -19,30 +17,7 @@ export const columns: BasicColumn[] = [
19 17 title: '状态',
20 18 dataIndex: 'status',
21 19 width: 120,
22   - customRender: ({ record }) => {
23   - if (!Reflect.has(record, 'pendingStatus')) {
24   - record.pendingStatus = false;
25   - }
26   - return h(Switch, {
27   - checked: record.status === 1,
28   - checkedChildren: '已启用',
29   - unCheckedChildren: '已禁用',
30   - loading: record.pendingStatus,
31   - onChange(checked: boolean) {
32   - record.pendingStatus = true;
33   - const newStatus = checked ? 1 : 0;
34   - const { createMessage } = useMessage();
35   - updateTransformScriptStatusApi(newStatus, record.id)
36   - .then(() => {
37   - record.status = newStatus;
38   - createMessage.success(`${record.status ? '启用' : '禁用'}成功`);
39   - })
40   - .finally(() => {
41   - record.pendingStatus = false;
42   - });
43   - },
44   - });
45   - },
  20 + slots: { customRender: 'status' },
46 21 },
47 22 {
48 23 title: '创建时间',
... ...
1 1 <template>
2 2 <div>
3   - <BasicTable
4   - @selection-change="useSelectionChange"
5   - :rowSelection="{ type: 'checkbox' }"
6   - @register="registerTable"
7   - v-show="isStatus === 0"
8   - :clickToRowSelect="false"
9   - >
  3 + <BasicTable @register="registerTable" v-show="isStatus === 0">
10 4 <template #toolbar>
11 5 <a-button type="primary" @click="handleCreate"> 新增转换脚本 </a-button>
12   - <a-button color="error" @click="handleDeleteOrBatchDelete(null)" :disabled="disabled">
  6 + <a-button color="error" @click="handleDeleteOrBatchDelete(null)" :disabled="hasBatchDelete">
13 7 批量删除
14 8 </a-button>
15 9 </template>
  10 + <template #status="{ record }">
  11 + <Switch
  12 + :checked="record.status === 1"
  13 + :loading="record.pendingStatus"
  14 + checkedChildren="启用"
  15 + unCheckedChildren="禁用"
  16 + @change="(checked:boolean)=>statusChange(checked,record)"
  17 + />
  18 + </template>
16 19 <template #action="{ record }">
17 20 <TableAction
18 21 :actions="[
... ... @@ -48,6 +51,7 @@
48 51
49 52 <script lang="ts" setup>
50 53 import { ref } from 'vue';
  54 + import { Switch } from 'ant-design-vue';
51 55 import { BasicTable, useTable, TableAction } from '/@/components/Table';
52 56 import { columns, searchFormSchema } from './config/config.data';
53 57 import { getConvertApi, deleteTransformApi } from '/@/api/device/TransformScriptApi';
... ... @@ -55,14 +59,24 @@
55 59 import ScriptDrawer from './cpns/ScriptDrawer.vue';
56 60 import TestScript from './cpns/TestScript.vue';
57 61 import { useMessage } from '/@/hooks/web/useMessage';
  62 + import { updateTransformScriptStatusApi } from '/@/api/device/TransformScriptApi';
  63 + import { useBatchDelete } from '/@/hooks/web/useBatchDelete';
58 64
59 65 const handleSuccess = () => {
60 66 reload();
61 67 };
62   - const { createMessage } = useMessage();
63   - let selectedRowKeys: any = [];
64   - const disabled = ref(true);
65   - const [registerTable, { reload, getSelectRowKeys, getSelectRows }] = useTable({
  68 +
  69 + const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions, resetSelectedRowKeys } =
  70 + useBatchDelete(deleteTransformApi, handleSuccess);
  71 + selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => {
  72 + // Demo:status为1的选择框禁用
  73 + if (record.status === 1) {
  74 + return { disabled: true };
  75 + } else {
  76 + return { disabled: false };
  77 + }
  78 + };
  79 + const [registerTable, { reload, setProps, setSelectedRowKeys }] = useTable({
66 80 api: getConvertApi,
67 81 title: '转换脚本列表',
68 82 columns,
... ... @@ -74,6 +88,7 @@
74 88 labelWidth: 100,
75 89 schemas: searchFormSchema,
76 90 },
  91 + clickToRowSelect: 'false',
77 92 rowKey: 'id',
78 93 actionColumn: {
79 94 width: 180,
... ... @@ -82,6 +97,7 @@
82 97 slots: { customRender: 'action' },
83 98 fixed: 'right',
84 99 },
  100 + ...selectionOptions,
85 101 });
86 102 const [registerDrawer, { openDrawer }] = useDrawer();
87 103
... ... @@ -108,39 +124,26 @@
108 124 const handleEdit = (record: Recordable) => {
109 125 openDrawer(true, { isUpdate: true, record });
110 126 };
111   - const useSelectionChange = () => {
112   - selectedRowKeys = getSelectRowKeys();
113   - if (selectedRowKeys.length > 0) {
114   - disabled.value = false;
115   - }
116   - let getRows = getSelectRows();
117   - const isJudge = getRows.map((m) => m.status);
118   - if (isJudge.length === 0) {
119   - disabled.value = true;
120   - }
121   - if (isJudge.includes(1)) {
122   - disabled.value = true;
123   - }
124   - };
125   - // 删除或批量删除
126   - const handleDeleteOrBatchDelete = async (record: Recordable | null) => {
127   - if (record) {
128   - try {
129   - await deleteTransformApi([record.id]);
130   - createMessage.success('删除成功');
131   - handleSuccess();
132   - } catch (e: any) {}
133   - } else {
134   - try {
135   - await deleteTransformApi(selectedRowKeys);
136   - createMessage.success('批量删除成功');
137   - handleSuccess();
138   - selectedRowKeys.length = 0;
139   - } catch (e: any) {
140   - selectedRowKeys.length = 0;
141   - } finally {
142   - selectedRowKeys.length = 0;
  127 + const statusChange = async (checked, record) => {
  128 + setProps({
  129 + loading: true,
  130 + });
  131 + setSelectedRowKeys([]);
  132 + resetSelectedRowKeys();
  133 + const newStatus = checked ? 1 : 0;
  134 + const { createMessage } = useMessage();
  135 + try {
  136 + await updateTransformScriptStatusApi(newStatus, record.id);
  137 + if (newStatus) {
  138 + createMessage.success(`启用成功`);
  139 + } else {
  140 + createMessage.success('禁用成功');
143 141 }
  142 + } finally {
  143 + setProps({
  144 + loading: false,
  145 + });
  146 + reload();
144 147 }
145 148 };
146 149 </script>
... ...
... ... @@ -112,7 +112,7 @@
112 112 showTableSetting: true,
113 113 bordered: true,
114 114 actionColumn: {
115   - width: 200,
  115 + width: 240,
116 116 title: '操作',
117 117 dataIndex: 'action',
118 118 slots: { customRender: 'action' },
... ...
... ... @@ -44,7 +44,7 @@
44 44 class="ant-upload-text flex"
45 45 style="width: 280px; height: 100px; align-items: center; font-size: 0.5625rem"
46 46 >
47   - 支持.PNG、.JPG格式,建议尺寸为1080*1620px,大小不超过5M</div
  47 + 支持.PNG、.JPG格式,建议尺寸为1920*1080px,大小不超过2M</div
48 48 >
49 49 </div>
50 50 </Upload>
... ... @@ -187,9 +187,9 @@
187 187 if (!isJpgOrPng) {
188 188 createMessage.error('只能上传图片文件!');
189 189 }
190   - const isLt2M = (file.size as number) / 1024 / 1024 < 5;
  190 + const isLt2M = (file.size as number) / 1024 / 1024 < 2;
191 191 if (!isLt2M) {
192   - createMessage.error('图片大小不能超过5MB!');
  192 + createMessage.error('图片大小不能超过2MB!');
193 193 }
194 194 return isJpgOrPng && isLt2M;
195 195 };
... ...
... ... @@ -69,7 +69,7 @@
69 69 class="ant-upload-text flex"
70 70 style="width: 280px; height: 130px; align-items: center; font-size: 0.5625rem"
71 71 >
72   - 支持.PNG、.JPG格式,建议尺寸为1920*1080px以上,大小不超过5M</div
  72 + 支持.PNG、.JPG格式,建议尺寸为1920*1080px以上,大小不超过2M</div
73 73 >
74 74 </div>
75 75 </Upload>
... ... @@ -99,8 +99,6 @@
99 99 import { PlusOutlined } from '@ant-design/icons-vue';
100 100 import { useUserStore } from '/@/store/modules/user';
101 101 import { createLocalStorage } from '/@/utils/cache/index';
102   - import { useTitle } from '@vueuse/core';
103   - import { useGlobSetting } from '/@/hooks/setting';
104 102 export default defineComponent({
105 103 components: {
106 104 BasicForm,
... ... @@ -192,9 +190,9 @@
192 190 if (!isJpgOrPng) {
193 191 createMessage.error('只能上传图片文件!');
194 192 }
195   - const isLt2M = (file.size as number) / 1024 / 1024 < 5;
  193 + const isLt2M = (file.size as number) / 1024 / 1024 < 2;
196 194 if (!isLt2M) {
197   - createMessage.error('图片大小不能超过5MB!');
  195 + createMessage.error('图片大小不能超过2MB!');
198 196 }
199 197 return isJpgOrPng && isLt2M;
200 198 };
... ...