Commit 3a077970aa3aeafcb6846a6a5c487a86691506a5

Authored by fengtao
1 parent db7d22cf

style:修改设备配置样式,fix:修改报警详细信息为输入框,fix:清除设备配置部分控制台警告,fix:完全清除场景联动控制台警告,fix:修复角色管理菜单…

…回显问题,feat:新增消息发送里的手机号验证规则
... ... @@ -244,7 +244,7 @@
244 244 </script>
245 245 <style scoped lang="less">
246 246 .change-avatar {
247   - /deep/ .ant-upload-select-picture-card {
  247 + :deep .ant-upload-select-picture-card {
248 248 display: inherit;
249 249 float: none;
250 250 width: 8.6vw;
... ...
... ... @@ -4,8 +4,6 @@ import { mainOutRoutes } from './mainOut';
4 4 import { PageEnum } from '/@/enums/pageEnum';
5 5 import { t } from '/@/hooks/web/useI18n';
6 6 import { LAYOUT } from '../constant';
7   -import { getMenuList } from '/@/api/sys/menu';
8   -import { router } from '/@/router';
9 7
10 8 const modules = import.meta.globEager('./modules/**/*.ts');
11 9 const routeModuleList: AppRouteModule[] = [];
... ... @@ -14,40 +12,6 @@ Object.keys(modules).forEach((key) => {
14 12 const modList = Array.isArray(mod) ? [...mod] : [mod];
15 13 routeModuleList.push(...modList);
16 14 });
17   -let pushPath = '';
18   -let pushSubPath = '';
19   -
20   -async function hashChangeFunc() {
21   - const getMenuListData1 = window.localStorage.getItem('menuListStorage') || (await getMenuList());
22   - const getMenuListData = JSON.parse(getMenuListData1);
23   - const getHomePage = getMenuListData.find((f) => {
24   - return f.path == '/dashboard/workbench';
25   - });
26   - if (getHomePage?.path == '/dashboard/workbench') {
27   - setTimeout(() => {
28   - router.push('/dashboard/workbench');
29   - }, 200);
30   - } else {
31   - const routeF = getMenuListData[0]?.children[0]?.path || getMenuListData[0].path;
32   - pushPath = routeF;
33   - pushSubPath = pushPath.substring(1);
34   - }
35   -}
36   -hashChangeFunc();
37   -
38   -window.onhashchange = (e) => {
39   - console.log(e);
40   - setTimeout(() => {
41   - if (
42   - e.newURL == 'http://localhost:8083/#/' ||
43   - e.newURL == 'http://localhost:8083/#' ||
44   - e.newURL == 'http://localhost:8083/' ||
45   - e.newURL == 'http://localhost:8083'
46   - ) {
47   - window.location.href = e.newURL + pushSubPath;
48   - }
49   - }, 1000);
50   -};
51 15
52 16 export const asyncRoutes = [PAGE_NOT_FOUND_ROUTE, ...routeModuleList];
53 17 export const RootRoute: AppRouteRecordRaw = {
... ...
... ... @@ -122,7 +122,6 @@ const transform: AxiosTransform = {
122 122 const err: string = error?.toString?.() ?? '';
123 123 let errMessage = '';
124 124 try {
125   - console.log(response.data);
126 125 if (response.data.status == '401' || response.data.message == '"Authentication failed"') {
127 126 window.localStorage.clear();
128 127 window.sessionStorage.clear();
... ...
... ... @@ -18,11 +18,11 @@
18 18 <DatePicker @change="onDateChange" v-model:value="dateValue" />
19 19 </div>
20 20 </template>
21   - <div v-show="activeKey === '1'">
  21 + <div v-if="activeKey === '1'">
22 22 <!-- 折线图 -->
23 23 <VisitAnalysis :alarmList="state.alarmList" />
24 24 </div>
25   - <div v-show="activeKey === '2'">
  25 + <div v-if="activeKey === '2'">
26 26 <!-- 柱形图 -->
27 27 <VisitAnalysisBar :dataPointList="state.dataPointList" :messageList="state.messageList" />
28 28 </div>
... ...
1 1 <template>
2   - <div>
  2 + <div style="min-width: 100%">
3 3 <p class="center">告警数</p>
4 4 <div ref="chartRef" :style="{ height, width }" v-show="alarmList.length"></div>
5 5 <div v-show="!alarmList.length"><Empty /></div>
... ... @@ -58,6 +58,9 @@
58 58 setOptions({
59 59 tooltip: {
60 60 trigger: 'axis',
  61 + axisPointer: {
  62 + type: 'cross',
  63 + },
61 64 },
62 65 grid: {
63 66 left: '3%',
... ...
1 1 <template>
2   - <div>
  2 + <div style="min-width: 100%">
3 3 <p class="center">消息量</p>
4 4 <div ref="chartRef" :style="{ height, width }" v-show="dataPointList.length"></div>
5 5 <div v-show="!dataPointList.length"><Empty /></div>
... ...
... ... @@ -153,7 +153,6 @@
153 153 }
154 154 function handleStep2Next(v) {
155 155 current.value++;
156   -
157 156 getStepTwoData.value = v;
158 157 if (unref(isUpdate)) {
159 158 proxy.$refs.DeviceProfileStep3Ref.retryRegisterFormFunc({
... ... @@ -162,7 +161,7 @@
162 161 proxy.$refs.DeviceProfileStep3Ref.retryRegisterFormHighSettingmFunc({
163 162 propagate: editEchoData.value.profileData.alarms[0].propagate,
164 163 propagateRelationTypes:
165   - editEchoData.value.profileData?.alarms[0].propagateRelationTypes,
  164 + editEchoData.value.profileData?.alarms[0].propagateRelationTypes[0],
166 165 });
167 166 const getKey = Object.keys(editEchoData.value.profileData?.alarms[0].createRules);
168 167 proxy.$refs.DeviceProfileStep3Ref.retryRegisterFormCreateAlarmFunc({
... ... @@ -212,13 +211,11 @@
212 211 `
213 212 );
214 213 proxy.$refs.DeviceProfileStep3Ref.retryEnableFormDataFunc(`始终启用`);
215   - proxy.$refs.DeviceProfileStep3Ref.retryTemplateFormDataFunc(
216   - `
217   - 报警详细信息:${
218   - editEchoData.value.profileData?.alarms[0].createRules[getKey[0]].alarmDetails
219   - }
220   - `
221   - );
  214 + proxy.$refs.DeviceProfileStep3Ref.setRegisterFormChangeDetailFunc({
  215 + alarmDetails:
  216 + editEchoData.value.profileData?.alarms[0].createRules[getKey[0]].alarmDetails,
  217 + });
  218 +
222 219 //清除报警
223 220 proxy.$refs.DeviceProfileStep3Ref.retryRulesClearFormDataFunc(
224 221 `
... ... @@ -226,21 +223,23 @@
226 223 `
227 224 );
228 225 proxy.$refs.DeviceProfileStep3Ref.retryEnableClearFormDataFunc(`始终启用`);
229   - proxy.$refs.DeviceProfileStep3Ref.retryTemplateClearFormDataFunc(
230   - `
231   - 报警详细信息:${editEchoData.value.profileData?.alarms[0].clearRule.alarmDetails}
232   - `
233   - );
  226 + proxy.$refs.DeviceProfileStep3Ref.setRegisterFormClearChangeDetailFunc({
  227 + alarmDetails: editEchoData.value.profileData?.alarms[0].clearRule.alarmDetails,
  228 + });
234 229 } else {
235   - proxy.$refs.DeviceProfileStep3Ref.resetRegisterFormFunc();
236   - proxy.$refs.DeviceProfileStep3Ref.resetRegisterFormHighSettingmFunc();
237   - proxy.$refs.DeviceProfileStep3Ref.resetRegisterFormCreateAlarmFunc();
238   - proxy.$refs.DeviceProfileStep3Ref.resetRulesFormDataFunc();
239   - proxy.$refs.DeviceProfileStep3Ref.resetEnableFormDataFunc();
240   - proxy.$refs.DeviceProfileStep3Ref.resetTemplateFormDataFunc();
241   - proxy.$refs.DeviceProfileStep3Ref.resetRulesClearFormDataFunc();
242   - proxy.$refs.DeviceProfileStep3Ref.resetEnableClearFormDataFunc();
243   - proxy.$refs.DeviceProfileStep3Ref.resetTemplateClearFormDataFunc();
  230 + try {
  231 + proxy.$refs.DeviceProfileStep3Ref.resetRegisterFormFunc();
  232 + proxy.$refs.DeviceProfileStep3Ref.resetRegisterFormHighSettingmFunc();
  233 + proxy.$refs.DeviceProfileStep3Ref.resetRegisterFormCreateAlarmFunc();
  234 + proxy.$refs.DeviceProfileStep3Ref.resetRulesFormDataFunc();
  235 + proxy.$refs.DeviceProfileStep3Ref.resetEnableFormDataFunc();
  236 + proxy.$refs.DeviceProfileStep3Ref.resetTemplateFormDataFunc();
  237 + proxy.$refs.DeviceProfileStep3Ref.resetRulesClearFormDataFunc();
  238 + proxy.$refs.DeviceProfileStep3Ref.resetEnableClearFormDataFunc();
  239 + proxy.$refs.DeviceProfileStep3Ref.resetTemplateClearFormDataFunc();
  240 + proxy.$refs.DeviceProfileStep3Ref.resetRegisterFormChangeDetailFunc();
  241 + proxy.$refs.DeviceProfileStep3Ref.resetRegisterFormClearChangeDetailFunc();
  242 + } catch (e) {}
244 243 }
245 244 }
246 245 function handleStep3Next(v) {
... ... @@ -248,16 +247,23 @@
248 247 getStepThreeData.value = v;
249 248 try {
250 249 if (unref(isUpdate)) {
251   - setTimeout(() => {
252   - try {
253   - proxy.$refs.DeviceProfileStep4Ref.resetFieldsFunc({
254   - alarmContactId: editEchoData.value.alarmProfile.alarmContactId,
255   - messageMode: editEchoData.value.alarmProfile.messageMode,
256   - });
257   - } catch (e) {
258   - return e;
259   - }
260   - }, 1000);
  250 + try {
  251 + proxy.$refs.DeviceProfileStep4Ref.resetFieldsFunc({
  252 + alarmContactId: editEchoData.value.alarmProfile.alarmContactId,
  253 + messageMode: editEchoData.value.alarmProfile.messageMode,
  254 + });
  255 + } catch (e) {
  256 + return e;
  257 + }
  258 + } else {
  259 + try {
  260 + proxy.$refs.DeviceProfileStep4Ref.resetFieldsFunc({
  261 + alarmContactId: '',
  262 + messageMode: '',
  263 + });
  264 + } catch (e) {
  265 + return e;
  266 + }
261 267 }
262 268 } catch (e) {
263 269 return e;
... ... @@ -302,7 +308,7 @@
302 308 }
303 309 };
304 310 const handleCancel = () => {
305   - return;
  311 + closeModal();
306 312 };
307 313 return {
308 314 handleChange,
... ...
... ... @@ -10,7 +10,7 @@
10 10 components: { BasicForm },
11 11 setup() {
12 12 const getValueData: any = ref({});
13   - const [register, { setProps, getFieldsValue }] = useForm({
  13 + const [register, { getFieldsValue, resetFields }] = useForm({
14 14 schemas: alertContactsSchemas,
15 15 actionColOptions: {
16 16 span: 24,
... ... @@ -22,10 +22,13 @@
22 22 getV = getValueData.value;
23 23 return getV;
24 24 }
  25 + const customResetStep4AndFunc = () => {
  26 + resetFields();
  27 + };
25 28 return {
  29 + customResetStep4AndFunc,
26 30 getAllFields,
27 31 register,
28   - setProps,
29 32 };
30 33 },
31 34 });
... ...
1 1 <template>
2 2 <div>
3 3 <BasicModal
4   - :showCancelBtn="true"
  4 + :showCancelBtn="false"
5 5 :showOkBtn="false"
6 6 v-bind="$attrs"
7 7 width="55rem"
... ... @@ -315,7 +315,7 @@
315 315 setRegisterStep3HighSetting({
316 316 propagate: descInfo.value.profileData?.alarms[0]?.propagate,
317 317 propagateRelationTypes:
318   - descInfo.value.profileData?.alarms[0]?.propagateRelationTypes,
  318 + descInfo.value.profileData?.alarms[0]?.propagateRelationTypes[0],
319 319 });
320 320 const getKey = Object.keys(descInfo.value.profileData?.alarms[0]?.createRules);
321 321 setRegisterStep3CreateAlarm({
... ... @@ -486,13 +486,13 @@
486 486
487 487 <style scoped lang="less">
488 488 .input-style {
489   - /deep/ .ant-form-item-control-input {
  489 + :deep .ant-form-item-control-input {
490 490 position: relative;
491 491 display: flex;
492 492 align-items: center;
493 493 min-height: 02px;
494 494 }
495   - /deep/.ant-col-24 {
  495 + :deep.ant-col-24 {
496 496 display: block;
497 497 flex: 0 0 100%;
498 498 max-width: 100%;
... ... @@ -501,13 +501,13 @@
501 501 }
502 502
503 503 .clear-input-style {
504   - /deep/ .ant-form-item-control-input {
  504 + :deep .ant-form-item-control-input {
505 505 position: relative;
506 506 display: flex;
507 507 align-items: center;
508 508 min-height: 02px;
509 509 }
510   - /deep/.ant-col-24 {
  510 + :deep.ant-col-24 {
511 511 display: block;
512 512 flex: 0 0 100%;
513 513 max-width: 100%;
... ...
... ... @@ -19,7 +19,7 @@
19 19 :actions="[
20 20 {
21 21 label: '详情',
22   - icon: 'clarity:note-edit-line',
  22 + icon: 'ant-design:eye-outlined',
23 23 onClick: handleDetailView.bind(null, record),
24 24 },
25 25 {
... ... @@ -29,7 +29,7 @@
29 29 },
30 30 {
31 31 label: '导出',
32   - icon: 'clarity:note-edit-line',
  32 + icon: 'ant-design:login-outlined',
33 33 onClick: handleExport.bind(null, record),
34 34 },
35 35 {
... ...
... ... @@ -42,7 +42,9 @@
42 42 </Upload>
43 43 </div>
44 44 </div>
45   - <BasicForm @register="register" />
  45 + <div style="margin-top: -50px">
  46 + <BasicForm @register="register" />
  47 + </div>
46 48 </div>
47 49 </div>
48 50 </template>
... ... @@ -167,7 +169,7 @@
167 169 color: @text-color;
168 170 }
169 171 .device-icon-style {
170   - /deep/ .ant-upload-select-picture-card {
  172 + :deep .ant-upload-select-picture-card {
171 173 display: inherit;
172 174 float: none;
173 175 width: 8.6vw;
... ...
... ... @@ -47,7 +47,9 @@
47 47 try {
48 48 const values = await validate();
49 49 emit('next', values);
50   - } catch (error) {}
  50 + } catch (error) {
  51 + } finally {
  52 + }
51 53 }
52 54 return { register, resetFieldsFunc, customResetAndFunc };
53 55 },
... ...
1 1 <template>
2   - <div class="step3">
  2 + <div class="step3" style="background-color: #f6f8f9">
3 3 <template v-for="(item, index) in profileData" :key="item.id">
4 4 <CollapseContainer class="border mb-1" :canExpan="false">
5 5 <template #action>
... ... @@ -8,110 +8,125 @@
8 8 style="cursor: pointer"
9 9 @click="deleteAlarmRule(index)"
10 10 alt="移除"
11   - src="../../../../assets/images/close.png"
  11 + src="../../../../assets/images/shanchu.png"
12 12 />
13 13 </div>
14 14 </template>
15   - <div class="alert-type" style="margin-left: -26px; margin-top: -10px">
16   - <BasicForm @register="registerForm"
17   - /></div>
18   - <div style="margin-top: -20px">
19   - <div style="margin-left: 20px; margin-top: -10px">
20   - <BasicForm
21   - @register="registerFormHighSetting"
22   - style="margin-left: 12px; margin-top: -10px"
23   - >
24   - <template #checkBox="{ model, field }">
25   - <Checkbox v-model:checked="model[field]">传递报警</Checkbox>
26   - </template>
27   - </BasicForm>
  15 + <div style="margin-top: -15px; margin-left: 10px">
  16 + <div class="alert-type" style="margin-left: -50px; margin-top: -10px">
  17 + <BasicForm @register="registerForm"
  18 + /></div>
  19 + <div style="margin-top: -15px">
  20 + <div style="margin-left: -8px; margin-top: -10px">
  21 + <BasicForm
  22 + @register="registerFormHighSetting"
  23 + style="margin-left: 12px; margin-top: -10px"
  24 + >
  25 + <template #checkBox="{ model, field }">
  26 + <Checkbox v-model:checked="model[field]">传递报警</Checkbox>
  27 + </template>
  28 + </BasicForm>
  29 + </div>
28 30 </div>
29 31 </div>
30   - <p>创建报警规则</p>
31   - <template v-for="(childItem, createIndex) in item.alarms" :key="childItem.id">
32   - <div class="aic" style="border: 1px solid #bfbfbf">
33   - <div class="w-3/4">
34   - <div style="margin-left: -33px; margin-top: 20px"
35   - ><BasicForm @register="registerFormCreateAlarm" />
36   - </div>
37   - <div style="margin-left: 5px; margin-top: -50px">
38   - <div style="color: #f5594e" class="ml-4"
39   - >报警规则条件:
40   - <Button size="small" type="primary" @click="handleOpenAlaramRuleConditions"
41   - >添加</Button
42   - >
43   - <p>{{ ruleTemplateData }}</p>
  32 + <div style="margin-top: -57px">
  33 + <p style="margin-left: 10px">创建报警规则</p>
  34 + <template v-for="(childItem, createIndex) in item.alarms" :key="childItem.id">
  35 + <div class="aic" style="border: 1px solid #bfbfbf">
  36 + <div class="w-3/4" style="margin-left: 40px">
  37 + <div style="margin-left: -33px; margin-top: 20px"
  38 + ><BasicForm @register="registerFormCreateAlarm" />
44 39 </div>
45   - <div style="white-space: wrap" class="mt-4 ml-4"
46   - >启用规则:
47   - <Button size="small" type="primary" @click="handleOpenEnableRule">添加</Button>
48   - <p>{{ enableTemplateData }}</p>
49   - <div class="mt-4 ml-4" style="margin-left: 0px"
50   - >详情模板:
51   - <Button size="small" type="primary" @click="handleOpenDetailTemplate"
  40 + <div style="margin-left: 5px; margin-top: -50px">
  41 + <div style="color: #f5594e" class="ml-4"
  42 + >报警规则条件:
  43 + <Button size="small" type="primary" @click="handleOpenAlaramRuleConditions"
52 44 >添加</Button
53 45 >
54   - <p>{{ detailTemplateData }}</p>
  46 + <p>{{ ruleTemplateData }}</p>
55 47 </div>
56   - <div style="margin-left: 0px; position: relative">
57   - <BasicForm @register="dashboardForm" />
  48 + <div style="white-space: wrap; margin-top: 25px" class="mt-4 ml-4"
  49 + >启用规则:
  50 + <Button size="small" type="primary" @click="handleOpenEnableRule">添加</Button>
  51 + <p>{{ enableTemplateData }}</p>
  52 + <div
  53 + class="mt-4 ml-4"
  54 + style="margin-left: 0px; position: relative; margin-top: 25px"
  55 + >详情模板:
  56 + <div style="position: absolute; top: -5px; left: 80px; width: 571px">
  57 + <BasicForm @register="registerFormChangeDetail" />
  58 + </div>
  59 + <!-- <Button size="small" type="primary" @click="handleOpenDetailTemplate"
  60 + >添加</Button
  61 + > -->
  62 + </div>
  63 + <div style="margin-left: 0px; margin-top: 25px; position: relative">
  64 + <BasicForm @register="dashboardForm" />
  65 + </div>
58 66 </div>
59 67 </div>
60   - </div>
61   - <div
62   - class="remove-type"
63   - style="display: inline-block; position: relative; top: -237px; left: 800px"
64   - >
65   - <img
66   - style="cursor: pointer"
67   - @click="deleteCondition(index, createIndex)"
68   - alt="移除"
69   - src="../../../../assets/images/close.png"
70   - />
  68 + <div
  69 + class="remove-type"
  70 + style="display: inline-block; position: relative; top: -257px; left: 757px"
  71 + >
  72 + <img
  73 + style="cursor: pointer"
  74 + @click="deleteCondition(index, createIndex)"
  75 + alt="移除"
  76 + src="../../../../assets/images/close.png"
  77 + />
  78 + </div>
71 79 </div>
72 80 </div>
73   - </div>
74   - </template>
75   - <a-button style="border-radius: 10px" class="mt-5" @click="addCreateRole(index)"
76   - ><PlusCircleOutlined />添加创建条件</a-button
77   - >
  81 + </template>
  82 + <a-button style="border-radius: 10px" class="mt-5" @click="addCreateRole(index)"
  83 + ><PlusCircleOutlined />添加创建条件</a-button
  84 + >
  85 + </div>
78 86 <div style="height: 20px"></div>
79   - <p>清除报警规则</p>
80   - <template
81   - v-for="(childClearItem, clearIndexItem) in item.clearRule"
82   - :key="childClearItem.id"
83   - >
84   - <div class="aic mb-1" style="border: 1px solid #bfbfbf">
85   - <div class="w-3/4">
86   - <div style="margin-left: 5px">
87   - <div style="color: #f5594e" class="mt-4 ml-4"
88   - >报警规则条件:
89   - <Button size="small" type="primary" @click="handleOpenClearAlaramRuleConditions"
90   - >添加</Button
91   - >
92   - <p>{{ ruleClearTemplateData }}</p>
93   - </div>
94   - <div style="white-space: wrap" class="mt-4 ml-4"
95   - >启用规则:
96   - <Button size="small" type="primary" @click="handleOpenClearEnableRule"
97   - >添加</Button
98   - >
99   - <p>{{ enableClearTemplateData }}</p>
100   - <div class="mt-4 ml-4" style="margin-left: 0px"
101   - >详情模板:
102   - <Button size="small" type="primary" @click="handleOpenClearDetailTemplate"
  87 + <div>
  88 + <p style="margin-left: 10px">清除报警规则</p>
  89 + <template
  90 + v-for="(childClearItem, clearIndexItem) in item.clearRule"
  91 + :key="childClearItem.id"
  92 + >
  93 + <div class="aic mb-1" style="border: 1px solid #bfbfbf">
  94 + <div class="w-3/4" style="margin-left: 40px">
  95 + <div style="margin-left: 5px">
  96 + <div style="color: #f5594e" class="mt-4 ml-4"
  97 + >报警规则条件:
  98 + <Button size="small" type="primary" @click="handleOpenClearAlaramRuleConditions"
103 99 >添加</Button
104 100 >
105   - <p>{{ detailClearTemplateData }}</p>
  101 + <p>{{ ruleClearTemplateData }}</p>
106 102 </div>
107   - <div style="margin-left: 0px">
108   - <BasicForm @register="dashboardForm" />
  103 + <div style="white-space: wrap; margin-top: 25px" class="mt-4 ml-4"
  104 + >启用规则:
  105 + <Button size="small" type="primary" @click="handleOpenClearEnableRule"
  106 + >添加</Button
  107 + >
  108 + <p>{{ enableClearTemplateData }}</p>
  109 + <div
  110 + class="mt-4 ml-4"
  111 + style="margin-left: 0px; position: relative; margin-top: 25px"
  112 + >详情模板:
  113 + <div style="position: absolute; top: -5px; left: 80px; width: 571px">
  114 + <BasicForm @register="registerFormChangeClearDetail" />
  115 + </div>
  116 + <!-- <Button size="small" type="primary" @click="handleOpenClearDetailTemplate"
  117 + >添加</Button
  118 + >
  119 + <p>{{ detailClearTemplateData }}</p> -->
  120 + </div>
  121 + <div style="margin-left: 0px; margin-top: 25px">
  122 + <BasicForm @register="dashboardForm" />
  123 + </div>
109 124 </div>
110 125 </div>
111 126 </div>
112 127 </div>
113   - </div>
114   - </template>
  128 + </template>
  129 + </div>
115 130 </CollapseContainer>
116 131 </template>
117 132 </div>
... ... @@ -179,6 +194,7 @@
179 194 step3CreateAlarm,
180 195 dashboardFormScheme,
181 196 isWhereType,
  197 + formChangeDetailSchema,
182 198 } from './data';
183 199 import { PlusCircleOutlined } from '@ant-design/icons-vue';
184 200 import { Checkbox } from 'ant-design-vue';
... ... @@ -202,6 +218,9 @@
202 218 },
203 219 emits: ['prev', 'next', 'redo', 'handleFormStep3toStep4Next'],
204 220 setup(_, { emit }) {
  221 + const changeGetDetailValue: any = ref(null);
  222 + const changeGetClearDetailValue: any = ref(null);
  223 + const ruleNumber = ref(0);
205 224 const { proxy } = getCurrentInstance();
206 225 const getChildData1 = ref(null);
207 226 const getChildData2 = ref(null);
... ... @@ -241,6 +260,7 @@
241 260 };
242 261 //删除告警配置
243 262 const deleteAlarmRule = (index: number) => {
  263 + ruleNumber.value--;
244 264 unref(profileData).splice(index, 1);
245 265 };
246 266 // 上一步
... ... @@ -249,6 +269,7 @@
249 269 };
250 270 //添加报警规则
251 271 const addAlarmRule = () => {
  272 + ruleNumber.value++;
252 273 clearIndex.value++;
253 274 unref(profileData).push({
254 275 configuration: {
... ... @@ -326,6 +347,40 @@
326 347 span: 24,
327 348 },
328 349 });
  350 + //详情模板
  351 + const [
  352 + registerFormChangeDetail,
  353 + {
  354 + getFieldsValue: getRegisterFormChangeDetail,
  355 + setFieldsValue: setRegisterFormChangeDetail,
  356 + resetFields: resetRegisterFormChangeDetail,
  357 + },
  358 + ] = useForm({
  359 + labelWidth: 120,
  360 + schemas: formChangeDetailSchema,
  361 + showResetButton: false,
  362 + showSubmitButton: false,
  363 + actionColOptions: {
  364 + span: 24,
  365 + },
  366 + });
  367 + //清除详情模板
  368 + const [
  369 + registerFormChangeClearDetail,
  370 + {
  371 + getFieldsValue: getRegisterFormClearChangeDetail,
  372 + setFieldsValue: setRegisterFormClearChangeDetail,
  373 + resetFields: resetRegisterFormClearChangeDetail,
  374 + },
  375 + ] = useForm({
  376 + labelWidth: 120,
  377 + schemas: formChangeDetailSchema,
  378 + showResetButton: false,
  379 + showSubmitButton: false,
  380 + actionColOptions: {
  381 + span: 24,
  382 + },
  383 + });
329 384 // 添加创建条件表单
330 385 const [
331 386 registerFormCreateAlarm,
... ... @@ -372,6 +427,14 @@
372 427 const resetTemplateClearFormDataFunc = () => {
373 428 detailClearTemplateData.value = ``;
374 429 };
  430 + //修改详情模板
  431 + const resetRegisterFormChangeDetailFunc = () => {
  432 + resetRegisterFormChangeDetail();
  433 + };
  434 + //清除修改详情模板
  435 + const resetRegisterFormClearChangeDetailFunc = () => {
  436 + resetRegisterFormClearChangeDetail();
  437 + };
375 438
376 439 //回显表单数据
377 440 const retryRegisterFormFunc = (v) => {
... ... @@ -401,6 +464,14 @@
401 464 const retryTemplateClearFormDataFunc = (v) => {
402 465 detailClearTemplateData.value = v;
403 466 };
  467 + //修改详情模板
  468 + const setRegisterFormChangeDetailFunc = (v) => {
  469 + setRegisterFormChangeDetail(v);
  470 + };
  471 + //清除修改详情模板
  472 + const setRegisterFormClearChangeDetailFunc = (v) => {
  473 + setRegisterFormClearChangeDetail(v);
  474 + };
404 475
405 476 const tempValue1: string = ref<string>('');
406 477 // 添加‘创建条件’
... ... @@ -486,6 +557,7 @@
486 557 // isWhereTypeValueDisabled.value = false;
487 558 }
488 559 });
  560 +
489 561 //详情模板
490 562 const getAllFieldsFunc = (v) => {
491 563 detailObj.value = v;
... ... @@ -764,17 +836,17 @@
764 836 }
765 837 const handleFormStep3toStep4Next = async () => {
766 838 try {
  839 + changeGetDetailValue.value = getRegisterFormChangeDetail();
  840 + changeGetClearDetailValue.value = getRegisterFormClearChangeDetail();
767 841 if (enableObj.value.schedule == 'CUSTOM') {
768   - for (let i in enableObj.value) {
769   - console.log(enableObj.value[i]);
770   - console.log(i);
771   - // let o = {};
772   - // if(enableObj.value[i]=='1')
773   - // o[i] = enableObj.value[i];
774   - // getSchduleCustomValue.value.push(o);
775   - // getSchduleCustomValue.value.push(enableObj.value[i]);
776   - }
777   - console.log(getSchduleCustomValue.value);
  842 + // for (let i in enableObj.value) {
  843 + // console.log(i);
  844 + // // let o = {};
  845 + // // if(enableObj.value[i]=='1')
  846 + // // o[i] = enableObj.value[i];
  847 + // // getSchduleCustomValue.value.push(o);
  848 + // // getSchduleCustomValue.value.push(enableObj.value[i]);
  849 + // }
778 850 // switch (enableObj.value.daysOfWeek1[0]) {
779 851 // case '1':
780 852 // getSchduleCustomValue.value.push({
... ... @@ -854,7 +926,11 @@
854 926 ? scheduleCustomClearValue.value
855 927 : scheduleClearValue,
856 928 };
857   - const getClearAdditionalProp = Object.assign({}, detailClearObj.value, getClearSchedule);
  929 + const getClearAdditionalProp = Object.assign(
  930 + {},
  931 + changeGetClearDetailValue.value,
  932 + getClearSchedule
  933 + );
858 934 const scheduleValue = {
859 935 type: enableObj.value.schedule,
860 936 daysOfWeek: enableObj.value.daysOfWeek,
... ... @@ -867,7 +943,7 @@
867 943 enableObj.value.schedule == 'CUSTOM' ? scheduleCustomValue.value : scheduleValue,
868 944 };
869 945
870   - const getAdditionalProp = Object.assign({}, detailObj.value, getSchedule);
  946 + const getAdditionalProp = Object.assign({}, changeGetDetailValue.value, getSchedule);
871 947 const getScheduleAndAlarmDetails = Object.assign(
872 948 {},
873 949 getAdditionalProp,
... ... @@ -930,14 +1006,18 @@
930 1006 isRuleAlarmRuleConditions.value = 1;
931 1007 setTimeout(() => {
932 1008 openModal1(true);
933   - proxy.$refs.getChildData1.resetDataFunc();
  1009 + setTimeout(() => {
  1010 + proxy.$refs.getChildData1.resetDataFunc();
  1011 + }, 1000);
934 1012 }, 50);
935 1013 };
936 1014 const handleOpenEnableRule = () => {
937 1015 isRuleAlarmRuleConditions.value = 2;
938 1016 setTimeout(() => {
939 1017 openModal2(true);
940   - proxy.$refs.getChildData2.resetDataFunc();
  1018 + setTimeout(() => {
  1019 + proxy.$refs.getChildData2.resetDataFunc();
  1020 + }, 1000);
941 1021 }, 50);
942 1022 };
943 1023 const handleOpenAlaramRuleConditions = () => {
... ... @@ -945,39 +1025,54 @@
945 1025 setTimeout(() => {
946 1026 openModal3(true);
947 1027 try {
948   - proxy.$refs.getChildData3.resetDataFunc();
  1028 + setTimeout(() => {
  1029 + proxy.$refs.getChildData3.resetDataFunc();
  1030 + }, 1000);
949 1031 } catch (e) {
950 1032 return e;
951 1033 }
952   - }, 100);
  1034 + }, 500);
953 1035 };
954 1036 const handleOpenClearDetailTemplate = () => {
955 1037 isRuleAlarmRuleConditions.value = 4;
956 1038 setTimeout(() => {
957 1039 openModal4(true);
958 1040 try {
959   - proxy.$refs.getChildData1.resetDataFunc();
  1041 + setTimeout(() => {
  1042 + proxy.$refs.getChildData1.resetDataFunc();
  1043 + }, 1000);
960 1044 } catch (e) {
961 1045 return e;
962 1046 }
963   - }, 50);
  1047 + }, 500);
964 1048 };
965 1049 const handleOpenClearEnableRule = () => {
966 1050 isRuleAlarmRuleConditions.value = 5;
967 1051 setTimeout(() => {
968 1052 openModal5(true);
969   - proxy.$refs.getChildData2.resetDataFunc();
  1053 + setTimeout(() => {
  1054 + proxy.$refs.getChildData2.resetDataFunc();
  1055 + }, 1000);
970 1056 }, 50);
971 1057 };
972 1058 const handleOpenClearAlaramRuleConditions = () => {
973 1059 isRuleAlarmRuleConditions.value = 6;
974 1060 setTimeout(() => {
975 1061 openModal6(true);
976   - proxy.$refs.getChildData3.resetDataFunc();
  1062 + setTimeout(() => {
  1063 + proxy.$refs.getChildData3.resetDataFunc();
  1064 + }, 1000);
977 1065 }, 50);
978 1066 };
979 1067
980 1068 return {
  1069 + resetRegisterFormChangeDetailFunc,
  1070 + resetRegisterFormClearChangeDetailFunc,
  1071 + setRegisterFormClearChangeDetailFunc,
  1072 + setRegisterFormChangeDetailFunc,
  1073 + registerFormChangeClearDetail,
  1074 + registerFormChangeDetail,
  1075 + ruleNumber,
981 1076 resetEnableClearFormDataFunc,
982 1077 resetTemplateClearFormDataFunc,
983 1078 resetRulesClearFormDataFunc,
... ... @@ -1046,6 +1141,8 @@
1046 1141 <style lang="less" scoped>
1047 1142 .step3 {
1048 1143 width: 100%;
  1144 + background-color: #f6f8f9;
  1145 + z-index: 1;
1049 1146 }
1050 1147 .border {
1051 1148 border: 1px solid #bfbfbf;
... ...
... ... @@ -31,8 +31,8 @@
31 31 const resetFieldsFunc = (v) => {
32 32 setFieldsValue(v);
33 33 };
34   - const customResetAndFunc = async () => {
35   - await resetFields();
  34 + const customResetAndFunc = () => {
  35 + resetFields();
36 36 };
37 37 async function customResetFunc() {
38 38 emit('prev');
... ... @@ -56,7 +56,7 @@
56 56 </script>
57 57 <style lang="less" scoped>
58 58 .step-4 {
59   - /deep/ .ant-btn {
  59 + :deep .ant-btn {
60 60 position: relative;
61 61 right: 375px;
62 62 top: 18px;
... ...
... ... @@ -221,7 +221,7 @@
221 221 });
222 222 </script>
223 223 <style lang="less" scoped>
224   - /deep/ .ant-table-body {
  224 + :deep.ant-table-body {
225 225 overflow-y: auto !important;
226 226 min-height: 173px !important;
227 227 height: 100px !important;
... ...
... ... @@ -98,6 +98,7 @@ export const step3Schemas: FormSchema[] = [
98 98 {
99 99 field: 'alarmType',
100 100 component: 'Input',
  101 + required: true,
101 102 label: '报警类型',
102 103 colProps: {
103 104 span: 12,
... ... @@ -106,19 +107,6 @@ export const step3Schemas: FormSchema[] = [
106 107 maxLength: 255,
107 108 placeholder: '请输入报警类型',
108 109 },
109   - dynamicRules: () => {
110   - return [
111   - {
112   - required: false,
113   - validator: (_, value) => {
114   - if (String(value).length > 255) {
115   - return Promise.reject('字数不超过255个字');
116   - }
117   - return Promise.resolve();
118   - },
119   - },
120   - ];
121   - },
122 110 },
123 111 ];
124 112
... ... @@ -127,7 +115,6 @@ export const step3ViewHighSetting: FormSchema[] = [
127 115 field: 'propagate',
128 116 component: 'Checkbox',
129 117 label: '传递报警',
130   - // renderComponentContent: '忽略大小写',
131 118 },
132 119 {
133 120 field: 'propagateRelationTypes',
... ... @@ -161,19 +148,6 @@ export const step3HighSetting: FormSchema[] = [
161 148 maxLength: 255,
162 149 placeholder: '请输入关联类型',
163 150 },
164   - dynamicRules: () => {
165   - return [
166   - {
167   - required: false,
168   - validator: (_, value) => {
169   - if (String(value).length > 255) {
170   - return Promise.reject('字数不超过255个字');
171   - }
172   - return Promise.resolve();
173   - },
174   - },
175   - ];
176   - },
177 151 ifShow: ({ values }) => !!values.propagate,
178 152 },
179 153 ];
... ... @@ -275,3 +249,17 @@ export const alertContactsSchemas: FormSchema[] = [
275 249 },
276 250 },
277 251 ];
  252 +
  253 +export const formChangeDetailSchema: FormSchema[] = [
  254 + {
  255 + field: 'alarmDetails',
  256 + label: '',
  257 + colProps: { span: 13 },
  258 + required: true,
  259 + component: 'Input',
  260 + componentProps: {
  261 + maxLength: 255,
  262 + placeholder: '请输入报警详细信息',
  263 + },
  264 + },
  265 +];
... ...
... ... @@ -227,19 +227,6 @@ export const formSchema: FormSchema[] = [
227 227 maxLength: 255,
228 228 placeholder: '请输入消息配置',
229 229 },
230   - dynamicRules: () => {
231   - return [
232   - {
233   - required: false,
234   - validator: (_, value) => {
235   - if (String(value).length > 255) {
236   - return Promise.reject('字数不超过255个字');
237   - }
238   - return Promise.resolve();
239   - },
240   - },
241   - ];
242   - },
243 230 },
244 231 {
245 232 field: 'id',
... ... @@ -270,19 +257,6 @@ export const formSchema: FormSchema[] = [
270 257 maxLength: 255,
271 258 placeholder: '请输入备注',
272 259 },
273   - dynamicRules: () => {
274   - return [
275   - {
276   - required: false,
277   - validator: (_, value) => {
278   - if (String(value).length > 255) {
279   - return Promise.reject('字数不超过255个字');
280   - }
281   - return Promise.resolve();
282   - },
283   - },
284   - ];
285   - },
286 260
287 261 component: 'InputTextArea',
288 262 },
... ...
... ... @@ -3,6 +3,8 @@ import { FormSchema } from '/@/components/Table';
3 3 import { h } from 'vue';
4 4 import { Tag } from 'ant-design-vue';
5 5 import { useI18n } from '/@/hooks/web/useI18n';
  6 +import { phoneRule } from '/@/utils/rules';
  7 +
6 8 const { t } = useI18n();
7 9 export const columns: BasicColumn[] = [
8 10 {
... ... @@ -52,6 +54,7 @@ export const searchFormSchema: FormSchema[] = [
52 54 label: '发送手机',
53 55 component: 'Input',
54 56 colProps: { span: 6 },
  57 + rules: phoneRule,
55 58 componentProps: {
56 59 maxLength: 36,
57 60 },
... ...
... ... @@ -44,6 +44,7 @@
44 44
45 45 export default defineComponent({
46 46 components: { CollapseContainer, BasicForm, [Input.name]: Input, Button },
  47 + // eslint-disable-next-line vue/require-prop-types
47 48 props: ['deviceInfo1'],
48 49 setup(props) {
49 50 const getValueData: any = ref({});
... ... @@ -66,7 +67,9 @@
66 67 });
67 68 let isJudge = ref(1);
68 69 if (isJudge.value == 1) {
69   - resetFields();
  70 + setTimeout(() => {
  71 + resetFields();
  72 + }, 1000);
70 73 }
71 74 watch(
72 75 () => props.deviceInfo1,
... ...
... ... @@ -44,6 +44,7 @@
44 44
45 45 export default defineComponent({
46 46 components: { CollapseContainer, BasicForm, [Input.name]: Input, Button },
  47 + // eslint-disable-next-line vue/require-prop-types
47 48 props: ['deviceInfo2'],
48 49 setup(props) {
49 50 const addHideButton = ref(1);
... ... @@ -66,7 +67,9 @@
66 67 });
67 68 let isJudge = ref(1);
68 69 if (isJudge.value == 1) {
69   - resetFields();
  70 + setTimeout(() => {
  71 + resetFields();
  72 + }, 1000);
70 73 }
71 74 watch(
72 75 () => props.deviceInfo2,
... ... @@ -432,5 +435,6 @@
432 435 display: inline-block;
433 436 position: relative;
434 437 top: 33px;
  438 + left: 5px;
435 439 }
436 440 </style>
... ...
  1 +/* eslint-disable vue/require-prop-types */
1 2 <template>
2 3 <div>
3 4 <CollapseContainer title="触发器" style="background-color: #eeeeee">
... ... @@ -56,6 +57,7 @@
56 57
57 58 export default defineComponent({
58 59 components: { CollapseContainer, BasicForm, [Input.name]: Input, Button },
  60 + // eslint-disable-next-line vue/require-prop-types
59 61 props: ['deviceInfo'],
60 62 setup(props) {
61 63 const getValueData: any = ref({});
... ... @@ -79,7 +81,9 @@
79 81 });
80 82 let isJudge = ref(1);
81 83 if (isJudge.value == 1) {
82   - resetFields();
  84 + setTimeout(() => {
  85 + resetFields();
  86 + }, 1000);
83 87 }
84 88 watch(
85 89 () => props.deviceInfo,
... ...
1 1 <template>
2 2 <div>
3 3 <BasicTable
4   - :rowSelection="{ type: 'checkbox' }"
5   - @selection-change="useSelectionChange"
6 4 @register="registerTable"
  5 + @selection-change="useSelectionChange"
  6 + :rowSelection="{ type: 'checkbox' }"
7 7 >
8 8 <template #toolbar>
9 9 <a-button type="primary" @click="handleAdd"> 新增场景联动 </a-button>
10   - <a-button type="error" @click="handleToolbarDel"> 删除 </a-button>
  10 + <a-button
  11 + style="background-color: rgba(237, 111, 111, 1)"
  12 + type="default"
  13 + @click="handleToolbarDel"
  14 + >
  15 + <span style="color: white">删除</span>
  16 + </a-button>
11 17 </template>
12 18 <template #action="{ record }">
13 19 <TableAction
... ... @@ -49,13 +55,14 @@
49 55 export default defineComponent({
50 56 name: 'Index',
51 57 components: { BasicTable, SceneLinkAgeDrawer, TableAction },
  58 + emits: ['default', 'registerTable', 'registerDrawer', 'register'],
52 59 setup() {
53 60 let selectedRowKeys: Array<string> = [];
54 61 let echoEditData = reactive({});
55 62 const [registerDrawer, { openDrawer }] = useDrawer();
56 63 const { createMessage } = useMessage();
57 64 const [registerTable, { reload, getSelectRowKeys }] = useTable({
58   - title: '',
  65 + title: '场景联动列表',
59 66 clickToRowSelect: false,
60 67 api: screenLinkPageGetApi,
61 68 columns,
... ... @@ -63,9 +70,6 @@
63 70 labelWidth: 120,
64 71 schemas: searchFormSchema,
65 72 },
66   - filterFn: (registerTable) => {
67   - return registerTable;
68   - },
69 73 rowKey: 'id',
70 74 useSearchForm: true,
71 75 showTableSetting: true,
... ... @@ -126,3 +130,5 @@
126 130 },
127 131 });
128 132 </script>
  133 +
  134 +<style lang="less" scoped></style>
... ...
... ... @@ -8,9 +8,15 @@
8 8 @ok="handleSubmit"
9 9 >
10 10 <BasicForm @register="registerForm" />
11   - <AddTriggerForm ref="getTriggerChildData" :deviceInfo="getDeviceInfo" />
12   - <AddConditiForm ref="getConditionChildData" :deviceInfo1="getDeviceInfo1" />
13   - <AddActionForm ref="getChildData" :deviceInfo2="getDeviceInfo2" />
  11 + <div>
  12 + <AddTriggerForm ref="getTriggerChildData" :deviceInfo="getDeviceInfo" />
  13 + </div>
  14 + <div>
  15 + <AddConditiForm ref="getConditionChildData" :deviceInfo1="getDeviceInfo1" />
  16 + </div>
  17 + <div>
  18 + <AddActionForm ref="getChildData" :deviceInfo2="getDeviceInfo2" />
  19 + </div>
14 20 </BasicDrawer>
15 21 </template>
16 22 <script lang="ts">
... ... @@ -31,7 +37,7 @@
31 37 export default defineComponent({
32 38 name: 'ConfigDrawer',
33 39 components: { BasicDrawer, BasicForm, AddTriggerForm, AddActionForm, AddConditiForm },
34   - emits: ['success', 'register'],
  40 + emits: ['success', 'register', 'registerForm'],
35 41 setup(_, { emit }) {
36 42 const { proxy } = getCurrentInstance();
37 43 const getChildData = ref(null);
... ... @@ -49,14 +55,12 @@
49 55 let getDeviceInfo1 = ref(null);
50 56 let getDeviceInfo2 = ref(null);
51 57
52   - const [
53   - registerForm,
54   - { resetFields, setFieldsValue, validateFields, getFieldsValue, updateSchema },
55   - ] = useForm({
56   - labelWidth: 120,
57   - schemas: formSchema,
58   - showActionButtonGroup: false,
59   - });
  58 + const [registerForm, { resetFields, setFieldsValue, validateFields, getFieldsValue }] =
  59 + useForm({
  60 + labelWidth: 120,
  61 + schemas: formSchema,
  62 + showActionButtonGroup: false,
  63 + });
60 64
61 65 watch(getData, (newV) => {
62 66 getDeviceInfo.value = newV;
... ... @@ -65,7 +69,6 @@
65 69 });
66 70
67 71 const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
68   - console.log(data);
69 72 await resetFields();
70 73 setDrawerProps({ confirmLoading: false });
71 74 isUpdate.value = !!data?.isUpdate;
... ...
... ... @@ -107,7 +107,7 @@
107 107 roleMenus.value = await getMenusIdsByRoleId(data.record.id);
108 108 treeData.value.map((m) => {
109 109 roleMenus.value.map((m1) => {
110   - if (m.key === m1) {
  110 + if (m.key === m1 && m.children.length !== 0) {
111 111 proxy.useChildrenIdsRemoveParentId(m1, roleMenus.value);
112 112 }
113 113 });
... ...
... ... @@ -4,6 +4,7 @@ import { h } from 'vue';
4 4 import { Switch } from 'ant-design-vue';
5 5 import { setRoleStatus } from '/@/api/system/system';
6 6 import { useMessage } from '/@/hooks/web/useMessage';
  7 +import { getAllRoleList } from '/@/api/system/system';
7 8
8 9 export const columns: BasicColumn[] = [
9 10 {
... ... @@ -29,10 +30,14 @@ export const columns: BasicColumn[] = [
29 30 checkedChildren: '已启用',
30 31 unCheckedChildren: '已禁用',
31 32 loading: record.pendingStatus,
32   - onChange(checked: boolean) {
  33 + async onChange(checked: boolean) {
33 34 record.pendingStatus = true;
34 35 const newStatus = checked ? 1 : 0;
35 36 const { createMessage } = useMessage();
  37 + const data = await getAllRoleList();
  38 + const findById = data.find((f) => f.id == record.id);
  39 + if (findById?.id) return createMessage.error(`该租户下面有此用户,无法禁用`);
  40 + record.pendingStatus = true;
36 41 setRoleStatus(record.id, newStatus)
37 42 .then(() => {
38 43 record.status = newStatus;
... ...
... ... @@ -50,31 +50,33 @@
50 50 placeholder: '请输入账号',
51 51 },
52 52 dynamicRules: ({ values }) => {
53   - const findUserName = isJudgeUserNameExist.value.find((f) => {
54   - if (f) {
55   - return f.username == values.username;
56   - }
57   - });
58   - return [
59   - {
60   - validator(_, value) {
61   - return new Promise((resolve, reject) => {
62   - if (value == '') {
63   - reject('请输入账号');
64   - } else if (ChineseRegexp.test(value)) {
65   - reject('账号不能含有中文');
66   - } else if (EmailRegexp.test(value)) {
67   - reject('账号不能为电子邮箱格式');
68   - } else if (value == findUserName?.username) {
69   - reject('账号已存在');
70   - return;
71   - } else {
72   - resolve();
73   - }
74   - });
  53 + try {
  54 + const findUserName = isJudgeUserNameExist.value.find((f) => {
  55 + if (f) {
  56 + return f.username == values.username;
  57 + }
  58 + });
  59 + return [
  60 + {
  61 + validator(_, value) {
  62 + return new Promise((resolve, reject) => {
  63 + if (value == '') {
  64 + reject('请输入账号');
  65 + } else if (ChineseRegexp.test(value)) {
  66 + reject('账号不能含有中文');
  67 + } else if (EmailRegexp.test(value)) {
  68 + reject('账号不能为电子邮箱格式');
  69 + } else if (value == findUserName?.username) {
  70 + reject('账号已存在');
  71 + return;
  72 + } else {
  73 + resolve();
  74 + }
  75 + });
  76 + },
75 77 },
76   - },
77   - ];
  78 + ];
  79 + } catch (e) {}
78 80 },
79 81 },
80 82 {
... ...