Commit 5292e73e4b4a6944d69a86221a8fca9128cb4617

Authored by xp.Huang
2 parents 18c614c0 d88bbd49

Merge branch 'ft' into 'main_dev'

refactor: 替换之前重构好的脚本管理和报表配置代码

See merge request yunteng/thingskit-front!619
Showing 36 changed files with 1806 additions and 1975 deletions
@@ -33,7 +33,7 @@ @@ -33,7 +33,7 @@
33 import { getAuthCache } from '/@/utils/auth'; 33 import { getAuthCache } from '/@/utils/auth';
34 import { isAdmin } from '/@/enums/roleEnum'; 34 import { isAdmin } from '/@/enums/roleEnum';
35 import { TableDefaultTypeEnum } from '../../../config/enum'; 35 import { TableDefaultTypeEnum } from '../../../config/enum';
36 - import { AggregateDataEnum } from '/@/views/report/config/timeConfig'; 36 + import { AggregateDataEnum } from '/@/views/device/localtion/config.data';
37 import SelectTenant from '../components/selectTenant.vue'; 37 import SelectTenant from '../components/selectTenant.vue';
38 38
39 const userInfo: any = getAuthCache(USER_INFO_KEY); 39 const userInfo: any = getAuthCache(USER_INFO_KEY);
@@ -153,7 +153,7 @@ @@ -153,7 +153,7 @@
153 import { editTestCellTableTHeadConfig } from '../../../config/config'; 153 import { editTestCellTableTHeadConfig } from '../../../config/config';
154 import { QuestionCircleOutlined } from '@ant-design/icons-vue'; 154 import { QuestionCircleOutlined } from '@ant-design/icons-vue';
155 import moment from 'moment'; 155 import moment from 'moment';
156 - import { AggregateDataEnum } from '/@/views/report/config/timeConfig'; 156 + import { AggregateDataEnum } from '/@/views/device/localtion/config.data';
157 import { getPacketIntervalByRange } from '/@/views/device/localtion/cpns/TimePeriodForm/helper'; 157 import { getPacketIntervalByRange } from '/@/views/device/localtion/cpns/TimePeriodForm/helper';
158 import { uniqBy } from 'lodash'; 158 import { uniqBy } from 'lodash';
159 import { TableDefaultTypeEnum } from '../../../config/enum'; 159 import { TableDefaultTypeEnum } from '../../../config/enum';
@@ -2,18 +2,17 @@ @@ -2,18 +2,17 @@
2 import { Button, Tag } from 'ant-design-vue'; 2 import { Button, Tag } from 'ant-design-vue';
3 import { h, onMounted, ref, unref, Ref } from 'vue'; 3 import { h, onMounted, ref, unref, Ref } from 'vue';
4 import { DeviceRecord } from '/@/api/device/model/deviceModel'; 4 import { DeviceRecord } from '/@/api/device/model/deviceModel';
5 - // import { ScriptRecord } from '/@/api/scriptmanage/model/scriptModel';  
6 import { getScriptManageMeList } from '/@/api/scriptmanage/scriptManager'; 5 import { getScriptManageMeList } from '/@/api/scriptmanage/scriptManager';
7 import { Description, useDescription } from '/@/components/Description'; 6 import { Description, useDescription } from '/@/components/Description';
8 import { useModal } from '/@/components/Modal'; 7 import { useModal } from '/@/components/Modal';
9 - import CoverScriptModal from '/@/views/rule/script/TcpConversionScript/ConverScriptModal.vue'; 8 + import { ConverScriptModal } from '/@/views/rule/script/TcpConversionScript/components';
10 import { SelectTypes } from 'ant-design-vue/es/select'; 9 import { SelectTypes } from 'ant-design-vue/es/select';
  10 + import { BusinessConvertScriptTextEnum } from '/@/views/rule/script/TcpConversionScript/config';
11 11
12 const props = defineProps<{ 12 const props = defineProps<{
13 record: DeviceRecord['profileData']['transportConfiguration']; 13 record: DeviceRecord['profileData']['transportConfiguration'];
14 }>(); 14 }>();
15 15
16 - // const scriptInfo = ref<ScriptRecord>({} as unknown as ScriptRecord);  
17 const authScriptIdStr = ref(''); 16 const authScriptIdStr = ref('');
18 17
19 const upScriptIdStr = ref(''); 18 const upScriptIdStr = ref('');
@@ -87,29 +86,25 @@ @@ -87,29 +86,25 @@
87 const [registerModal, { openModal }] = useModal(); 86 const [registerModal, { openModal }] = useModal();
88 87
89 const handleTestAuthScript = () => { 88 const handleTestAuthScript = () => {
90 - openModal(true, {  
91 - isUpdate: false,  
92 - isTest: true,  
93 - record: unref(authScriptIdStr),  
94 - isText: 'test',  
95 - isTitle: 'test',  
96 - }); 89 + const modalParams = {
  90 + text: BusinessConvertScriptTextEnum.BUSINESS_TEST_TEXT,
  91 + record: { id: unref(authScriptIdStr) },
  92 + };
  93 + openModal(true, modalParams);
97 }; 94 };
98 95
99 const handleTestUpScript = () => { 96 const handleTestUpScript = () => {
100 - openModal(true, {  
101 - isUpdate: false,  
102 - isTest: true,  
103 - record: unref(upScriptIdStr),  
104 - isText: 'test',  
105 - isTitle: 'test',  
106 - }); 97 + const modalParams = {
  98 + text: BusinessConvertScriptTextEnum.BUSINESS_TEST_TEXT,
  99 + record: { id: unref(upScriptIdStr) },
  100 + };
  101 + openModal(true, modalParams);
107 }; 102 };
108 </script> 103 </script>
109 104
110 <template> 105 <template>
111 <section> 106 <section>
112 <Description @register="register" /> 107 <Description @register="register" />
113 - <CoverScriptModal @register="registerModal" /> 108 + <ConverScriptModal @register="registerModal" />
114 </section> 109 </section>
115 </template> 110 </template>
  1 +<template>
  2 + <div class="flex">
  3 + <div>
  4 + <Select
  5 + v-bind="$attrs"
  6 + placeholder="请选择脚本"
  7 + @change="handleChange"
  8 + v-model:value="scriptId"
  9 + style="width: 305px"
  10 + show-search
  11 + :options="selectOptions"
  12 + :filter-option="handleSearch"
  13 + allowClear
  14 + />
  15 + </div>
  16 + <div>
  17 + <span
  18 + @click="handleBusinessModal(BusinessConvertScriptTextEnum.BUSINESS_ADD_TEXT)"
  19 + class="ml-2"
  20 + style="color: #409eff; cursor: pointer"
  21 + size="small"
  22 + >新建转换脚本</span
  23 + >
  24 + </div>
  25 + </div>
  26 + <a-button
  27 + @click="handleBusinessModal(BusinessConvertScriptTextEnum.BUSINESS_TEST_TEXT)"
  28 + class="mt-4"
  29 + type="primary"
  30 + >测试脚本</a-button
  31 + >
  32 + <ConverScriptModal @register="registerModal" @success="handleSuccess" />
  33 +</template>
  34 +<script lang="ts" setup name="ScriptSelectItem">
  35 + import { ref, Ref, onMounted } from 'vue';
  36 + import { SelectTypes } from 'ant-design-vue/es/select';
  37 + import { Select } from 'ant-design-vue';
  38 + import {
  39 + BusinessConvertScriptTextEnum,
  40 + ScriptTypeEnum,
  41 + } from '/@/views/rule/script/TcpConversionScript/config';
  42 + import { getScriptManageMeList } from '/@/api/scriptmanage/scriptManager';
  43 + import { useModal } from '/@/components/Modal';
  44 + import { useMessage } from '/@/hooks/web/useMessage';
  45 + import { ConverScriptModal } from '/@/views/rule/script/TcpConversionScript/components';
  46 +
  47 + const props = defineProps({
  48 + scriptType: {
  49 + type: String,
  50 + default: ScriptTypeEnum.TRANSPORT_TCP_AUTH,
  51 + },
  52 + modelValue: {
  53 + type: String,
  54 + default: '',
  55 + },
  56 + });
  57 +
  58 + const emits = defineEmits(['update:modelValue', 'change']);
  59 +
  60 + const { createMessage } = useMessage();
  61 +
  62 + const selectOptions: Ref<SelectTypes['options']> = ref([]);
  63 +
  64 + //如果是空字符串,placeholder没提示文字
  65 + const scriptId = ref<any>(null);
  66 +
  67 + onMounted(() => {
  68 + getSelectOptions();
  69 + });
  70 +
  71 + const getSelectOptions = async () => {
  72 + selectOptions.value = await getAllScriptType(props.scriptType);
  73 + };
  74 +
  75 + const getAllScriptType = async (type) => {
  76 + const rest = await getScriptManageMeList({ scriptType: type });
  77 + return rest.map((m) => ({ label: m.name, value: m.id }));
  78 + };
  79 +
  80 + const handleSearch = (inputValue: string, option: Record<'label' | 'value', string>) => {
  81 + return option.label.includes(inputValue);
  82 + };
  83 +
  84 + const [registerModal, { openModal }] = useModal();
  85 +
  86 + // 业务弹窗
  87 + const handleBusinessModal = (text) => {
  88 + const modalParams = {
  89 + text,
  90 + record:
  91 + text !== BusinessConvertScriptTextEnum.BUSINESS_ADD_TEXT ? { id: scriptId.value } : null,
  92 + scriptType: props.scriptType,
  93 + };
  94 + if (!scriptId.value) return createMessage.error('请先选择对应脚本');
  95 + openModal(true, modalParams);
  96 + };
  97 +
  98 + const handleSuccess = ({ rest }) => {
  99 + getSelectOptions();
  100 + const { id } = rest;
  101 + scriptId.value = id;
  102 + };
  103 +
  104 + const handleChange = (value) => {
  105 + emits('update:modelValue', value);
  106 + emits('change', value);
  107 + };
  108 +
  109 + const setValue = (value) => {
  110 + scriptId.value = value;
  111 + };
  112 + defineExpose({
  113 + setValue,
  114 + });
  115 +</script>
  1 +import ScriptSelectItem from './ScriptSelectItem.vue';
  2 +
  3 +export { ScriptSelectItem };
1 -import { FormSchema } from '/@/components/Form';  
2 -  
3 -export const tcpSchemas: FormSchema[] = [  
4 - {  
5 - field: 'authScriptId',  
6 - label: '鉴权脚本',  
7 - component: 'Input',  
8 - slot: 'authScriptId',  
9 - colProps: { span: 24 },  
10 - required: true,  
11 - },  
12 - {  
13 - field: 'upScriptId',  
14 - label: '上行脚本',  
15 - component: 'Input',  
16 - slot: 'upScriptId',  
17 - colProps: { span: 24 },  
18 - required: true,  
19 - },  
20 -];  
21 -  
22 -// 新增编辑配置  
23 -export const formSchema: FormSchema[] = [  
24 - {  
25 - field: 'name',  
26 - label: '输入参数',  
27 - colProps: { span: 24 },  
28 - required: true,  
29 - component: 'Input',  
30 - componentProps: {  
31 - maxLength: 255,  
32 - placeholder: '请输入输入参数',  
33 - },  
34 - },  
35 - {  
36 - field: 'scriptContent',  
37 - label: '脚本内容',  
38 - required: true,  
39 - component: 'Input',  
40 - slot: 'scriptContent',  
41 - colProps: { span: 24 },  
42 - },  
43 - {  
44 - field: 'remark',  
45 - label: '输出参数',  
46 - colProps: { span: 24 },  
47 - component: 'InputTextArea',  
48 - componentProps: {  
49 - rows: 6,  
50 - maxLength: 255,  
51 - placeholder: '请输入输出参数',  
52 - },  
53 - },  
54 -];  
1 -<template>  
2 - <div>  
3 - <a-form  
4 - ref="formRef"  
5 - :model="scriptForm"  
6 - name="basic"  
7 - :label-col="{ span: 4 }"  
8 - :wrapper-col="{ span: 16 }"  
9 - style="margin-left: 2.4rem"  
10 - autocomplete="off"  
11 - >  
12 - <a-form-item  
13 - v-if="deviceTypeStr !== 'SENSOR'"  
14 - label="鉴权脚本"  
15 - name="'params'"  
16 - :rules="[{ required: true, message: '请选择鉴权脚本' }]"  
17 - >  
18 - <div style="display: flex; align-items: center">  
19 - <div>  
20 - <Select  
21 - @change="handleAuthChange"  
22 - placeholder="请选择"  
23 - v-model:value="scriptForm.authScriptId"  
24 - style="width: 305px"  
25 - show-search  
26 - :options="selectAuthOptions"  
27 - :filter-option="handleAuthSearch"  
28 - allowClear  
29 - />  
30 - </div>  
31 - <div>  
32 - <span  
33 - @click="handleCreateOrEditAuth('add')"  
34 - class="ml-2"  
35 - style="color: #409eff; cursor: pointer"  
36 - size="small"  
37 - >新建转换脚本</span  
38 - >  
39 - </div>  
40 - </div>  
41 - <a-button @click="handleCreateOrEditAuth('test')" class="mt-4" type="primary"  
42 - >测试脚本</a-button  
43 - >  
44 - </a-form-item>  
45 - <a-form-item  
46 - label="上行脚本"  
47 - name="'params'"  
48 - :rules="[{ required: true, message: '请选择上行脚本' }]"  
49 - >  
50 - <div style="display: flex; align-items: center">  
51 - <div>  
52 - <Select  
53 - @change="handleUpChange"  
54 - placeholder="请选择"  
55 - v-model:value="scriptForm.upScriptId"  
56 - style="width: 305px"  
57 - show-search  
58 - :options="selectUpOptions"  
59 - :filter-option="handleSearch"  
60 - allowClear  
61 - />  
62 - </div>  
63 - <div>  
64 - <span  
65 - @click="handleCreateOrEdit('add')"  
66 - class="ml-2"  
67 - style="color: #409eff; cursor: pointer"  
68 - size="small"  
69 - >新建转换脚本</span  
70 - >  
71 - </div>  
72 - </div>  
73 - <a-button @click="handleCreateOrEdit('test')" class="mt-4" type="primary"  
74 - >测试脚本</a-button  
75 - >  
76 - </a-form-item>  
77 - </a-form>  
78 - <ConverScriptModal @register="registerModal" @success="handleSuccess" />  
79 - <ConverScriptModal @register="registerAuthModal" @success="handleAuthSuccess" />  
80 - </div>  
81 -</template>  
82 -<script lang="ts" setup name="index">  
83 - import { ref, Ref, onMounted, reactive } from 'vue';  
84 - import { SelectTypes } from 'ant-design-vue/es/select';  
85 - import { Select } from 'ant-design-vue';  
86 - import { useModal } from '/@/components/Modal';  
87 - import { getScriptManageMeList } from '/@/api/scriptmanage/scriptManager';  
88 - import ConverScriptModal from '/@/views/rule/script/TcpConversionScript/ConverScriptModal.vue';  
89 - import { useMessage } from '/@/hooks/web/useMessage';  
90 -  
91 - const props = defineProps({  
92 - deviceTypeStr: { type: String, default: '' },  
93 - });  
94 -  
95 - const scriptForm = reactive({  
96 - authScriptId: '',  
97 - upScriptId: '',  
98 - });  
99 - const selectUpOptions: Ref<SelectTypes['options']> = ref([]);  
100 -  
101 - const selectAuthOptions: Ref<SelectTypes['options']> = ref([]);  
102 -  
103 - const { createMessage } = useMessage();  
104 -  
105 - const upScriptIdStr = ref('');  
106 -  
107 - const authScriptIdStr = ref('');  
108 -  
109 - onMounted(async () => {  
110 - selectUpOptions.value = await getAllScriptType('TRANSPORT_TCP_UP');  
111 - selectAuthOptions.value = await getAllScriptType('TRANSPORT_TCP_AUTH');  
112 - });  
113 -  
114 - const getAllScriptType = async (type) => {  
115 - const rest = await getScriptManageMeList({ scriptType: type });  
116 - return rest.map((m) => ({ label: m.name, value: m.id }));  
117 - };  
118 -  
119 - const handleSuccess = async ({ res, text }) => {  
120 - if (text !== 'test') {  
121 - const rest = await getAllScriptType('TRANSPORT_TCP_UP');  
122 - selectUpOptions.value = rest;  
123 - scriptForm.upScriptId = res?.id;  
124 - upScriptIdStr.value = res?.id;  
125 - }  
126 - };  
127 -  
128 - const handleAuthSuccess = async ({ res, text }) => {  
129 - if (text !== 'test') {  
130 - const rest = await getAllScriptType('TRANSPORT_TCP_AUTH');  
131 - selectAuthOptions.value = rest;  
132 - scriptForm.authScriptId = res?.id;  
133 - authScriptIdStr.value = res?.id;  
134 - }  
135 - };  
136 -  
137 - const handleUpChange = (v) => {  
138 - upScriptIdStr.value = v;  
139 - scriptForm.upScriptId = v;  
140 - };  
141 -  
142 - const handleAuthChange = (v) => {  
143 - authScriptIdStr.value = v;  
144 - scriptForm.authScriptId = v;  
145 - };  
146 -  
147 - const [registerModal, { openModal }] = useModal();  
148 -  
149 - const [registerAuthModal, { openModal: openAuthModel }] = useModal();  
150 -  
151 - //TODO: 待优化  
152 -  
153 - const handleCreateOrEditAuth = (c) => {  
154 - if (c === 'add') {  
155 - openAuthModel(true, {  
156 - isUpdate: true,  
157 - isView: false,  
158 - isTest: false,  
159 - isText: 'confirm',  
160 - isTitle: 'add',  
161 - });  
162 - } else {  
163 - if (!authScriptIdStr.value) return createMessage.error('请先选择对应脚本');  
164 - openAuthModel(true, {  
165 - isUpdate: false,  
166 - isTest: true,  
167 - record: authScriptIdStr.value,  
168 - isText: 'test',  
169 - isTitle: 'test',  
170 - });  
171 - }  
172 - };  
173 -  
174 - const handleCreateOrEdit = (c) => {  
175 - if (c === 'add') {  
176 - openModal(true, {  
177 - isUpdate: true,  
178 - isView: false,  
179 - isTest: false,  
180 - isText: 'confirm',  
181 - isTitle: 'add',  
182 - });  
183 - } else {  
184 - if (!upScriptIdStr.value) return createMessage.error('请先选择对应脚本');  
185 - openModal(true, {  
186 - isUpdate: false,  
187 - isTest: true,  
188 - record: upScriptIdStr.value,  
189 - isText: 'test',  
190 - isTitle: 'test',  
191 - });  
192 - }  
193 - };  
194 -  
195 - const getFormData = async () => {  
196 - if (props.deviceTypeStr === 'SENSOR') {  
197 - if (!scriptForm.upScriptId) {  
198 - createMessage.error('请先选择对应脚本');  
199 - throw new Error('请先选择对应脚本');  
200 - }  
201 - } else {  
202 - if (!scriptForm.authScriptId) {  
203 - createMessage.error('请先选择对应脚本');  
204 - throw new Error('请先选择对应脚本');  
205 - }  
206 - if (!scriptForm.upScriptId) {  
207 - createMessage.error('请先选择对应脚本');  
208 - throw new Error('请先选择对应脚本');  
209 - }  
210 - }  
211 - return {  
212 - ...scriptForm,  
213 - type: 'TCP',  
214 - };  
215 - };  
216 -  
217 - const resetFormData = () => {  
218 - // resetFields();  
219 - };  
220 -  
221 - const setFormData = (v) => {  
222 - scriptForm.authScriptId = v?.authScriptId;  
223 - scriptForm.upScriptId = v?.upScriptId;  
224 - // setFieldsValue(v);  
225 - upScriptIdStr.value = v?.upScriptId;  
226 - authScriptIdStr.value = v?.authScriptId;  
227 - };  
228 -  
229 - const handleSearch = (inputValue: string, option: Record<'label' | 'value', string>) => {  
230 - return option.label.includes(inputValue);  
231 - };  
232 -  
233 - const handleAuthSearch = (inputValue: string, option: Record<'label' | 'value', string>) => {  
234 - return option.label.includes(inputValue);  
235 - };  
236 -  
237 - defineExpose({  
238 - getFormData,  
239 - resetFormData,  
240 - setFormData,  
241 - });  
242 -</script>  
243 -<style lang="less" scoped></style> 1 +<template>
  2 + <div>
  3 + <a-form
  4 + ref="formRef"
  5 + :model="scriptForm"
  6 + name="basic"
  7 + :label-col="{ span: 4 }"
  8 + :wrapper-col="{ span: 16 }"
  9 + autocomplete="off"
  10 + style="margin-left: 2.4rem"
  11 + >
  12 + <a-form-item
  13 + v-if="deviceTypeStr !== TypeEnum.SENSOR"
  14 + label="鉴权脚本"
  15 + name="authScriptId"
  16 + :rules="[{ required: true, message: '请选择鉴权脚本' }]"
  17 + >
  18 + <ScriptSelectItem
  19 + ref="scriptSelectItemAuthRef"
  20 + v-model:value="scriptForm.authScriptId"
  21 + :scriptType="ScriptTypeEnum.TRANSPORT_TCP_AUTH"
  22 + />
  23 + </a-form-item>
  24 + <a-form-item
  25 + label="上行脚本"
  26 + name="upScriptId"
  27 + :rules="[{ required: true, message: '请选择上行脚本' }]"
  28 + >
  29 + <ScriptSelectItem
  30 + ref="scriptSelectItemUpRef"
  31 + v-model:value="scriptForm.upScriptId"
  32 + :scriptType="ScriptTypeEnum.TRANSPORT_TCP_UP"
  33 + />
  34 + </a-form-item>
  35 + </a-form>
  36 + </div>
  37 +</template>
  38 +<script lang="ts" setup name="index">
  39 + import { reactive, ref } from 'vue';
  40 + import { useMessage } from '/@/hooks/web/useMessage';
  41 + import { ScriptSelectItem } from './components';
  42 + import { ScriptTypeEnum } from '/@/views/rule/script/TcpConversionScript/config';
  43 + import { TypeEnum } from '/@/views/device/list/config/data';
  44 +
  45 + const props = defineProps({
  46 + deviceTypeStr: { type: String, default: '' },
  47 + });
  48 +
  49 + const scriptForm = reactive({
  50 + authScriptId: '',
  51 + upScriptId: '',
  52 + });
  53 +
  54 + const { createMessage } = useMessage();
  55 +
  56 + const scriptSelectItemAuthRef = ref<InstanceType<typeof ScriptSelectItem>>();
  57 +
  58 + const scriptSelectItemUpRef = ref<InstanceType<typeof ScriptSelectItem>>();
  59 +
  60 + const getFormData = async () => {
  61 + //业务 网关子设备没有鉴权脚本
  62 + if (props.deviceTypeStr === TypeEnum.SENSOR) Reflect.deleteProperty(scriptForm, 'authScriptId');
  63 + if (Object.values(scriptForm).some((item) => !item)) {
  64 + createMessage.error('请先选择对应脚本');
  65 + throw new Error('请先选择对应脚本');
  66 + }
  67 + return {
  68 + ...scriptForm,
  69 + type: 'TCP',
  70 + };
  71 + };
  72 +
  73 + const resetFormData = () => {};
  74 +
  75 + const setFormData = (data) => {
  76 + scriptForm.authScriptId = data?.authScriptId;
  77 + scriptForm.upScriptId = data?.upScriptId;
  78 + scriptSelectItemAuthRef.value?.setValue(data?.authScriptId);
  79 + scriptSelectItemUpRef.value?.setValue(data?.upScriptId);
  80 + };
  81 + defineExpose({
  82 + getFormData,
  83 + resetFormData,
  84 + setFormData,
  85 + });
  86 +</script>
  87 +<style lang="less" scoped></style>
1 -<template>  
2 - <BasicDrawer  
3 - :maskClosable="true"  
4 - @close="handleClose"  
5 - destroyOnClose  
6 - v-bind="$attrs"  
7 - @register="registerDrawer"  
8 - showFooter  
9 - :title="getTitle"  
10 - width="30%"  
11 - @ok="handleSubmit"  
12 - >  
13 - <BasicForm @register="registerForm">  
14 - <template #devices="{ model, field }">  
15 - <p style="display: none">{{ field }}</p>  
16 - <p>{{ queryModeFunc(model['queryMode']) }}</p>  
17 - <p>{{ orgFunc(model['organizationId']) }}</p>  
18 - <p>{{ dataTypeFunc(model['dataType']) }}</p>  
19 - <Select  
20 - placeholder="请选择设备"  
21 - v-model:value="selectDevice"  
22 - style="width: 100%"  
23 - :options="selectOptions"  
24 - @change="handleDeviceChange"  
25 - @deselect="handleDeselect"  
26 - mode="multiple"  
27 - labelInValue  
28 - notFoundContent="请选择设备"  
29 - />  
30 - <div style="margin-top: 1.5vh"></div>  
31 - <template v-for="(item, index) in deviceList" :key="item.value">  
32 - <p style="display: none">{{ index }}</p>  
33 - <DeviceAttrCpns  
34 - :ref="bindDeviceRefObj.deviceAttrRef"  
35 - :value="item"  
36 - :orgId="organizationId || orgId"  
37 - />  
38 - </template>  
39 - </template>  
40 - </BasicForm>  
41 - </BasicDrawer>  
42 -</template>  
43 -<script lang="ts" setup>  
44 - import { ref, computed, unref, reactive, watch, Ref, nextTick } from 'vue';  
45 - import { BasicForm, useForm } from '/@/components/Form';  
46 - import { DataTypeEnum, formSchema, organizationId } from './config.data';  
47 - import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';  
48 - import {  
49 - createOrEditReportManage,  
50 - putReportConfigManage,  
51 - reportEditDetailPage,  
52 - } from '/@/api/report/reportManager';  
53 - import { useMessage } from '/@/hooks/web/useMessage';  
54 - import moment from 'moment';  
55 - import { screenLinkPageByDeptIdGetDevice } from '/@/api/ruleengine/ruleengineApi';  
56 - import { Select } from 'ant-design-vue';  
57 - import DeviceAttrCpns from './cpns/DeviceAttrCpns.vue';  
58 - import { SchemaFiled } from './config.data';  
59 - import { QueryWay } from '../../device/localtion/cpns/TimePeriodForm/config';  
60 - import { AggregateDataEnum } from '../../device/localtion/cpns/TimePeriodForm/config';  
61 -  
62 - type TDeviceList = {  
63 - key?: string;  
64 - value?: string;  
65 - label?: string;  
66 - attribute?: string;  
67 - device?: string;  
68 - name?: string;  
69 - attributes?: string | undefined;  
70 - deviceProfileId?: string;  
71 - id?: string;  
72 - };  
73 - type TSelectOption = {  
74 - value?: string;  
75 - label?: string;  
76 - deviceProfileId?: string;  
77 - id?: string;  
78 - };  
79 - const emit = defineEmits(['success', 'register']);  
80 - const bindDeviceRefObj = {  
81 - deviceAttrRef: ref([]),  
82 - };  
83 - const isUpdate = ref(true);  
84 - const editId = ref('');  
85 - const orgId = ref('');  
86 - const selectOptions: Ref<TSelectOption[]> = ref([]);  
87 - const selectDevice = ref([]);  
88 - const deviceList: Ref<TDeviceList[]> = ref([]);  
89 - const editDeviceList: Ref<TDeviceList[]> = ref([]);  
90 - let editResData: any = reactive({});  
91 - const editDeviceAttr: any = ref([]);  
92 - const orgFuncId = ref('');  
93 - const queryModeStr = ref('');  
94 - const dataTypeStr = ref(0);  
95 - const orgFunc = (e) => {  
96 - orgFuncId.value = e;  
97 - };  
98 - const queryModeFunc = (e) => {  
99 - queryModeStr.value = e;  
100 - };  
101 - const dataTypeFunc = (e) => {  
102 - dataTypeStr.value = e;  
103 - };  
104 - watch(  
105 - () => dataTypeStr.value,  
106 - (newValue) => {  
107 - if (newValue == 0) {  
108 - setFieldsValue({ limit: 100 });  
109 - } else {  
110 - }  
111 - }  
112 - );  
113 - watch(  
114 - () => queryModeStr.value,  
115 - (newValue: string) => {  
116 - if (newValue == 'latest') {  
117 - setFieldsValue({ startTs: 1000 });  
118 - setFieldsValue({ interval: 1000 });  
119 - } else {  
120 - }  
121 - }  
122 - );  
123 - watch(  
124 - () => orgFuncId.value,  
125 - async (newValue: string) => {  
126 - if (newValue) {  
127 - //获取设备  
128 - const { items } = await screenLinkPageByDeptIdGetDevice({  
129 - organizationId: newValue,  
130 - });  
131 - selectOptions.value = items.map((item) => {  
132 - if (item.deviceType !== 'GATEWAY')  
133 - return {  
134 - label: item.alias ? item.alias : item.name,  
135 - value: item.tbDeviceId,  
136 - id: item.id,  
137 - deviceProfileId: item.deviceProfileId,  
138 - };  
139 - });  
140 - }  
141 - }  
142 - );  
143 - //设备Select选中  
144 - const handleDeviceChange = (_, o) => {  
145 - if (unref(isUpdate)) {  
146 - //编辑  
147 - let temp: any = [];  
148 - editDeviceAttr.value.forEach((f) => {  
149 - temp = [f, ...o];  
150 - });  
151 - let deWeightThree = () => {  
152 - let map = new Map();  
153 - for (let item of deviceList.value) {  
154 - if (!map.has(item.value)) {  
155 - map.set(item.value, item);  
156 - }  
157 - }  
158 - return [...map.values()];  
159 - };  
160 - temp = deWeightThree();  
161 - deviceList.value = temp;  
162 - if (o.length !== 0) {  
163 - deviceList.value = o;  
164 - }  
165 - } else {  
166 - deviceList.value = o;  
167 - }  
168 - };  
169 - //设备取消删除  
170 - const handleDeselect = (e) => {  
171 - if (unref(isUpdate)) {  
172 - //编辑  
173 - let deWeightThree = () => {  
174 - let map = new Map();  
175 - for (let item of deviceList.value) {  
176 - if (!map.has(item.value)) {  
177 - map.set(item.value, item);  
178 - }  
179 - }  
180 - return [...map.values()];  
181 - };  
182 - deviceList.value = deWeightThree();  
183 - const findEditValue = deviceList.value.findIndex((f) => f.value == e.value);  
184 - if (findEditValue !== -1) deviceList.value.splice(findEditValue, 1);  
185 - } else {  
186 - const eDevice = e.key || e.value;  
187 - const findValue = deviceList.value.findIndex((f) => f.value == eDevice);  
188 - if (findValue !== -1) deviceList.value.splice(findValue, 1);  
189 - }  
190 - };  
191 - const [registerForm, { validate, setFieldsValue, resetFields, updateSchema, getFieldsValue }] =  
192 - useForm({  
193 - labelWidth: 120,  
194 - schemas: formSchema,  
195 - showActionButtonGroup: false,  
196 - fieldMapToTime: [[SchemaFiled.DATE_RANGE, [SchemaFiled.START_TS, SchemaFiled.END_TS]]],  
197 - });  
198 - const isViewDetail = ref(false);  
199 -  
200 - const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {  
201 - await nextTick();  
202 - await resetFields();  
203 - setDrawerProps({ confirmLoading: false });  
204 - isUpdate.value = !!data?.isUpdate;  
205 - isViewDetail.value = !!data?.isView;  
206 - if (unref(isViewDetail)) {  
207 - setDrawerProps({ showFooter: true });  
208 - if (unref(isUpdate)) {  
209 - setDrawerProps({ title: '编辑报表配置' });  
210 - } else {  
211 - setDrawerProps({ title: '新增报表配置' });  
212 - }  
213 - } else {  
214 - setDrawerProps({ showFooter: false });  
215 - setDrawerProps({ title: '查看报表配置' });  
216 - }  
217 - if (unref(isUpdate)) {  
218 - //编辑回显数据  
219 - editResData = await reportEditDetailPage(data.record.id);  
220 - //回显基础数据  
221 - editId.value = editResData.data.id;  
222 - const spanDisance = editResData.data.executeContent?.split(' ');  
223 - await setFieldsValue(editResData.data);  
224 - //回显嵌套数据  
225 - await setFieldsValue({  
226 - dateGroupGap:  
227 - editResData.data.queryCondition?.queryMode === 1  
228 - ? editResData.data.queryCondition?.interval  
229 - : null,  
230 - agg: editResData.data.queryCondition?.agg,  
231 - interval: editResData.data.queryCondition?.interval,  
232 - limit: editResData.data.queryCondition?.limit,  
233 - orderBy: editResData.data.queryCondition?.orderBy,  
234 - useStrictDataTypes: editResData.data.queryCondition?.useStrictDataTypes,  
235 - startTs: editResData.data.queryCondition?.startTs,  
236 - endTs: editResData.data.queryCondition?.endTs,  
237 - way: editResData.data?.way,  
238 - queryMode: editResData.data.queryCondition?.queryMode === 0 ? 'latest' : 'timePeriod',  
239 - cronTime:  
240 - editResData.data?.cycle?.cycleType === 2  
241 - ? spanDisance[2] < 10  
242 - ? editResData.data.executeContent.slice(0, 7) + '* * ?'  
243 - : editResData.data.executeContent.slice(0, 7) + ' ' + '* * ?'  
244 - : editResData.data?.cycle?.cycleType === 1  
245 - ? spanDisance[2] < 10  
246 - ? editResData.data.executeContent.slice(0, 5) + ' ' + ' * * ?'  
247 - : editResData.data.executeContent.slice(0, 6) + ' ' + ' * * ?'  
248 - : editResData.data.executeContent,  
249 - currentCycle: editResData.data?.cycle?.currentCycle,  
250 - cycleTime: editResData.data?.cycle?.cycleTime,  
251 - cycleType: editResData.data?.cycle?.cycleType,  
252 - });  
253 - const endTsTime = editResData.data.queryCondition?.endTs;  
254 - const startTsTime = editResData.data.queryCondition?.startTs;  
255 - const mathFloor = (endTsTime - startTsTime) / 10;  
256 - const multTen = Math.floor(mathFloor) * 10;  
257 - await setFieldsValue({  
258 - startTs: multTen,  
259 - });  
260 - if (editResData.data.queryCondition?.queryMode == 1) {  
261 - await setFieldsValue({  
262 - dataRange: [  
263 - editResData.data.queryCondition?.startTs,  
264 - editResData.data.queryCondition?.endTs,  
265 - ],  
266 - });  
267 - }  
268 - //回显聚合条件  
269 - const dataCompareOpions = [  
270 - { label: '最小值', value: AggregateDataEnum.MIN },  
271 - { label: '最大值', value: AggregateDataEnum.MAX },  
272 - { label: '平均值', value: AggregateDataEnum.AVG },  
273 - { label: '求和', value: AggregateDataEnum.SUM },  
274 - { label: '计数', value: AggregateDataEnum.COUNT },  
275 - { label: '空', value: AggregateDataEnum.NONE },  
276 - ];  
277 - const updateSchemaAgg = (options: {}) => {  
278 - updateSchema({  
279 - field: SchemaFiled.AGG,  
280 - componentProps: {  
281 - options,  
282 - },  
283 - });  
284 - };  
285 - if (editResData.data.dataType == 1) updateSchemaAgg(dataCompareOpions.slice(0, 5));  
286 - else updateSchemaAgg(dataCompareOpions.slice(5, 6));  
287 - //回显执行方式和查询周期  
288 - const dataQueryOpions = [  
289 - { label: '固定周期', value: QueryWay.LATEST },  
290 - { label: '自定义周期', value: QueryWay.TIME_PERIOD },  
291 - ];  
292 - const updateSchemaQuery = (options: {}) => {  
293 - updateSchema({  
294 - field: SchemaFiled.WAY,  
295 - componentProps: {  
296 - options,  
297 - },  
298 - });  
299 - };  
300 - if (editResData.data.executeWay == 0) updateSchemaQuery(dataQueryOpions);  
301 - else updateSchemaQuery(dataQueryOpions.slice(0, 1));  
302 - //回显设备  
303 - orgId.value = editResData.data.organizationId;  
304 - const { items } = await screenLinkPageByDeptIdGetDevice({  
305 - organizationId: editResData.data.organizationId,  
306 - });  
307 - selectOptions.value = items.map((item) => {  
308 - if (item.deviceType !== 'GATEWAY')  
309 - return {  
310 - label: item.alias ? item.alias : item.name,  
311 - value: item.tbDeviceId,  
312 - id: item.id,  
313 - deviceProfileId: item.deviceProfileId,  
314 - };  
315 - });  
316 - const deviceIds = editResData.data.executeAttributes.map((m) => {  
317 - return {  
318 - label: m.name,  
319 - key: m.device,  
320 - };  
321 - });  
322 - selectDevice.value = deviceIds;  
323 - //回显设备属性  
324 - editDeviceAttr.value = editResData.data.executeAttributes?.map((item) => {  
325 - const T = selectOptions.value.find((o) => {  
326 - if (item.device === o.value) {  
327 - return {  
328 - id: o.id,  
329 - deviceProfileId: o.deviceProfileId,  
330 - };  
331 - }  
332 - });  
333 - return {  
334 - ...T,  
335 - label: item.alias ? item.alias : item.name,  
336 - value: item.device,  
337 - attributes: item.attributes,  
338 - };  
339 - });  
340 - deviceList.value = editDeviceAttr.value;  
341 - editDeviceList.value = editResData.data.executeAttributes;  
342 - } else {  
343 - setFieldsValue({  
344 - startTs: 1000,  
345 - interval: 1000,  
346 - });  
347 - editId.value = '';  
348 - orgId.value = '';  
349 - selectDevice.value = [];  
350 - selectOptions.value = [];  
351 - deviceList.value = [];  
352 - getAttrDevice.value = [];  
353 - editDeviceList.value = [];  
354 - editDeviceAttr.value = [];  
355 - updateSchema({  
356 - field: SchemaFiled.AGG,  
357 - componentProps: {  
358 - options: [],  
359 - },  
360 - });  
361 - //新增显示执行方式和查询周期  
362 - const dataQueryOpions = [  
363 - { label: '固定周期', value: QueryWay.LATEST },  
364 - { label: '自定义周期', value: QueryWay.TIME_PERIOD },  
365 - ];  
366 - const updateSchemaQuery = (options: {}) => {  
367 - updateSchema({  
368 - field: SchemaFiled.WAY,  
369 - componentProps: {  
370 - options,  
371 - },  
372 - });  
373 - };  
374 - if (getFieldsValue().executeWay == 0) updateSchemaQuery(dataQueryOpions);  
375 - }  
376 - });  
377 - const handleClose = () => {  
378 - deviceList.value = [];  
379 - editId.value = '';  
380 - orgId.value = '';  
381 - selectDevice.value = [];  
382 - selectOptions.value = [];  
383 - getAttrDevice.value = [];  
384 - editDeviceList.value = [];  
385 - editDeviceAttr.value = [];  
386 - };  
387 - const getAttrDevice: Ref<TDeviceList[]> = ref([]);  
388 - const getTitle = computed(() => (!unref(isUpdate) ? '新增报表配置' : '编辑报表配置'));  
389 - let postObj: any = reactive({});  
390 - let queryCondition: any = reactive({});  
391 - let executeContent: any = reactive({});  
392 - const startTs = ref(0);  
393 - const endTs = ref(0);  
394 -  
395 - const getFormValueFunc = () => {  
396 - const item: any = unref(bindDeviceRefObj.deviceAttrRef)?.map((item: any) => item.emitChange());  
397 - getAttrDevice.value = item;  
398 - };  
399 -  
400 - async function handleSubmit() {  
401 - setDrawerProps({ confirmLoading: true });  
402 - try {  
403 - const { createMessage } = useMessage();  
404 - const values = await validate();  
405 - if (!values) return;  
406 - getFormValueFunc();  
407 - let hasAttr = false;  
408 - if (!unref(isUpdate)) {  
409 - if (getAttrDevice.value.length === 0) {  
410 - return createMessage.error('请选择设备及其属性');  
411 - } else {  
412 - getAttrDevice.value.forEach((f: any) => {  
413 - if (f.attributes == undefined || f.attributes.length == 0) hasAttr = true;  
414 - });  
415 - }  
416 - } else {  
417 - if (getAttrDevice.value.length === 0) {  
418 - return createMessage.error('请选择设备及其属性');  
419 - } else {  
420 - getAttrDevice.value.forEach((f: any) => {  
421 - if (f.attributes == undefined || f.attributes.length == 0) hasAttr = true;  
422 - });  
423 - }  
424 - }  
425 - if (hasAttr) return createMessage.error('请选择设备属性');  
426 - if (values.executeWay == 0) {  
427 - executeContent = null;  
428 - } else {  
429 - //拼接corn  
430 - let joinCorn = '';  
431 - if (values.cycleType === 1) {  
432 - joinCorn = values.cronTime.slice(0, 6) + values.currentCycle.slice(5);  
433 - executeContent = joinCorn;  
434 - } else if (values.cycleType === 0) {  
435 - executeContent = values.cronTime;  
436 - } else if (values.cycleType === 2) {  
437 - joinCorn = values.cronTime.slice(0, 6) + values.cycleTime.slice(5);  
438 - executeContent = joinCorn;  
439 - }  
440 - }  
441 - if (values.queryMode === QueryWay.LATEST) {  
442 - startTs.value = moment().subtract(values.startTs, 'ms').valueOf();  
443 - endTs.value = Date.now();  
444 - } else {  
445 - const fT = JSON.parse(JSON.stringify(values.dataRange));  
446 - startTs.value = moment(fT[0]).valueOf();  
447 - endTs.value = moment(fT[1]).valueOf();  
448 - }  
449 - queryCondition = {  
450 - agg: values.agg,  
451 - ...(values?.queryMode === QueryWay.LATEST && values?.dataType != DataTypeEnum.ORIGINAL  
452 - ? { interval: values?.queryMode === 'latest' ? values.interval : values.dateGroupGap }  
453 - : {}),  
454 - limit: values.limit,  
455 - ...{  
456 - startTs: startTs.value,  
457 - },  
458 - ...{  
459 - endTs: endTs.value,  
460 - },  
461 - queryMode: values?.queryMode === 'latest' ? 0 : 1,  
462 - };  
463 - const cycle: any = {};  
464 - if (values.cycleType === 0) {  
465 - cycle.cycleType = values.cycleType;  
466 - cycle.cronTime = values.cronTime;  
467 - }  
468 - if (values.cycleType === 1) {  
469 - cycle.cycleType = values.cycleType;  
470 - cycle.currentCycle = values.currentCycle;  
471 - cycle.cronTime = values.cronTime;  
472 - }  
473 - if (values.cycleType === 2) {  
474 - cycle.cycleType = values.cycleType;  
475 - cycle.cycleTime = values.cycleTime;  
476 - cycle.cronTime = values.cronTime;  
477 - }  
478 - // const cycle = {  
479 - // currentCycle: values.currentCycle,  
480 - // cycleTime: values.cycleTime,  
481 - // cronTime: values.cronTime,  
482 - // cycleType: values.cycleType,  
483 - // };  
484 - delete values.devices;  
485 - delete values.agg;  
486 - delete values.interval;  
487 - delete values.timeZone;  
488 - delete values.cronTime;  
489 - delete values.currentCycle;  
490 - delete values.cycleTime;  
491 - delete values.limit1;  
492 - delete values.startTs;  
493 - delete values.queryMode;  
494 - delete values.cycleType;  
495 - postObj = {  
496 - ...values,  
497 - ...{  
498 - executeAttributes:  
499 - getAttrDevice.value.length == 0 ? editDeviceList.value : getAttrDevice.value,  
500 - },  
501 - ...{ queryCondition },  
502 - ...{ cycle },  
503 - ...{ executeContent },  
504 - ...{ id: editId.value !== '' ? editId.value : '' },  
505 - };  
506 - let saveMessage = '添加成功';  
507 - let updateMessage = '修改成功';  
508 - editId.value !== ''  
509 - ? await putReportConfigManage(postObj)  
510 - : await createOrEditReportManage(postObj);  
511 -  
512 - closeDrawer();  
513 - emit('success');  
514 - createMessage.success(unref(isUpdate) ? updateMessage : saveMessage);  
515 - handleClose();  
516 - } finally {  
517 - setTimeout(() => {  
518 - setDrawerProps({ confirmLoading: false });  
519 - }, 300);  
520 - }  
521 - }  
522 -</script>  
src/views/report/config/components/DevicePreviewModal.vue renamed from src/views/report/config/DevicePreviewModal.vue
@@ -6,7 +6,6 @@ @@ -6,7 +6,6 @@
6 width="55rem" 6 width="55rem"
7 @register="register" 7 @register="register"
8 title="执行设备及属性" 8 title="执行设备及属性"
9 - @cancel="handleCancel"  
10 :showOkBtn="false" 9 :showOkBtn="false"
11 > 10 >
12 <div> 11 <div>
@@ -19,10 +18,11 @@ @@ -19,10 +18,11 @@
19 import { ref, nextTick } from 'vue'; 18 import { ref, nextTick } from 'vue';
20 import { BasicModal, useModalInner } from '/@/components/Modal'; 19 import { BasicModal, useModalInner } from '/@/components/Modal';
21 import { BasicTable, useTable } from '/@/components/Table'; 20 import { BasicTable, useTable } from '/@/components/Table';
22 - import { viewDeviceColumn } from './config.data'; 21 + import { viewDeviceColumn } from '../config';
23 import { reportEditDetailPage } from '/@/api/report/reportManager'; 22 import { reportEditDetailPage } from '/@/api/report/reportManager';
24 23
25 - const tableData: any = ref([]); 24 + const tableData = ref([]);
  25 +
26 const [registerTable] = useTable({ 26 const [registerTable] = useTable({
27 columns: viewDeviceColumn, 27 columns: viewDeviceColumn,
28 showIndexColumn: false, 28 showIndexColumn: false,
@@ -30,22 +30,20 @@ @@ -30,22 +30,20 @@
30 showTableSetting: false, 30 showTableSetting: false,
31 bordered: true, 31 bordered: true,
32 }); 32 });
  33 +
33 const [register] = useModalInner((data) => { 34 const [register] = useModalInner((data) => {
34 const getTableData = async () => { 35 const getTableData = async () => {
35 - const res: any = await reportEditDetailPage(data.record.id);  
36 - const resMap = res.data.executeAttributes.map((d) => {  
37 - return {  
38 - device: d.name,  
39 - attribute: d.attributes.join(','),  
40 - };  
41 - }); 36 + const res = (await reportEditDetailPage(data.record?.id)) as any;
  37 + const resMap = res?.data?.executeAttributes?.map((item) => ({
  38 + device: item.name,
  39 + attribute: item.attributes.join(','),
  40 + }));
42 tableData.value = resMap; 41 tableData.value = resMap;
43 }; 42 };
44 nextTick(() => { 43 nextTick(() => {
45 getTableData(); 44 getTableData();
46 }); 45 });
47 }); 46 });
48 - const handleCancel = () => {};  
49 </script> 47 </script>
50 <style lang="less" scoped> 48 <style lang="less" scoped>
51 :deep(.ant-table-body) { 49 :deep(.ant-table-body) {
  1 +<template>
  2 + <BasicDrawer
  3 + destroyOnClose
  4 + v-bind="$attrs"
  5 + showFooter
  6 + width="35%"
  7 + :maskClosable="true"
  8 + :title="businessText"
  9 + @register="registerDrawer"
  10 + @ok="handleSubmit"
  11 + @close="handleClose"
  12 + >
  13 + <BasicForm @register="registerForm">
  14 + <!-- 设备选择 -->
  15 + <template #devices="{ model }">
  16 + <span class="hidden">{{ handleChangeOrg(model['organizationId']) }}</span>
  17 + <SelectDevice ref="selectDeviceRef" :selectOptions="selectOptions" />
  18 + </template>
  19 + </BasicForm>
  20 + </BasicDrawer>
  21 +</template>
  22 +<script lang="ts" setup>
  23 + import { ref, reactive, Ref, nextTick, watch } from 'vue';
  24 + import { BasicForm, useForm } from '/@/components/Form';
  25 + import { formSchema } from '../config';
  26 + import { SchemaFiled, BusinessReportConfigTextEnum, BusinessExecutewayEnum } from '../enum';
  27 + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  28 + import {
  29 + createOrEditReportManage,
  30 + putReportConfigManage,
  31 + reportEditDetailPage,
  32 + } from '/@/api/report/reportManager';
  33 + import { useMessage } from '/@/hooks/web/useMessage';
  34 + import { TSelectOption } from '../type';
  35 + import { SelectDevice } from './index';
  36 + import { useHooks } from '../hooks/index.hooks';
  37 + import { useThrottleFn } from '@vueuse/shared';
  38 +
  39 + const emits = defineEmits(['success', 'register']);
  40 +
  41 + const selectDeviceRef = ref<InstanceType<typeof SelectDevice>>();
  42 +
  43 + const { createMessage } = useMessage();
  44 +
  45 + const {
  46 + getDeviceList,
  47 + getQueryCondition,
  48 + removeFields,
  49 + setDefaultTime,
  50 + setQueryCondition,
  51 + setAggByDateType,
  52 + disableCustomWeekly,
  53 + setPropsForModal,
  54 + validateSelectDevice,
  55 + } = useHooks();
  56 +
  57 + const selectOptions: Ref<TSelectOption[]> = ref([]);
  58 +
  59 + const orgId = ref('');
  60 +
  61 + const handleChangeOrg = (e) => {
  62 + orgId.value = e;
  63 + //放在这里的话,会造成发出很多请求,原因不是很清楚
  64 + // getDeviceListByOrg(orgId.value);
  65 + };
  66 +
  67 + const getDeviceListByOrg = async (organizationId) => {
  68 + selectOptions.value = await getDeviceList(organizationId);
  69 + };
  70 +
  71 + watch(
  72 + () => orgId.value,
  73 + (newValue: string) => {
  74 + if (newValue) {
  75 + //获取设备
  76 + selectDeviceRef.value?.resetValue();
  77 + getDeviceListByOrg(newValue);
  78 + }
  79 + },
  80 + {
  81 + immediate: true,
  82 + }
  83 + );
  84 +
  85 + const [registerForm, { validate, resetFields, setFieldsValue, updateSchema }] = useForm({
  86 + labelWidth: 120,
  87 + schemas: formSchema,
  88 + showActionButtonGroup: false,
  89 + fieldMapToTime: [[SchemaFiled.DATE_RANGE, [SchemaFiled.START_TS, SchemaFiled.END_TS]]],
  90 + });
  91 +
  92 + const businessText = ref('');
  93 +
  94 + const restData = reactive({
  95 + data: {},
  96 + });
  97 +
  98 + const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
  99 + try {
  100 + await nextTick();
  101 + handleClose();
  102 + businessText.value = data.text;
  103 + setFieldsValue(setDefaultTime());
  104 + updateSchema(disableCustomWeekly(BusinessExecutewayEnum.BUSINESS_EXECUTEWAY_IMMEDIATE));
  105 + setDrawerProps(setPropsForModal(businessText.value));
  106 + if (businessText.value === BusinessReportConfigTextEnum.BUSINESS_ADD_TEXT) return;
  107 + const rest = await reportEditDetailPage(data.record?.id);
  108 + restData.data = rest['data'] ?? {};
  109 + const {
  110 + organizationId,
  111 + executeAttributes,
  112 + queryCondition,
  113 + dataType,
  114 + executeWay,
  115 + cycle,
  116 + executeContent,
  117 + } = restData.data as any;
  118 + await setFieldsValue({
  119 + ...restData.data,
  120 + ...setQueryCondition(queryCondition, cycle, executeContent),
  121 + });
  122 + if (organizationId) {
  123 + await getDeviceListByOrg(organizationId);
  124 + selectDeviceRef.value?.setValue(executeAttributes);
  125 + }
  126 + await updateSchema(setAggByDateType(dataType));
  127 + await updateSchema(disableCustomWeekly(executeWay));
  128 + } finally {
  129 + setDrawerProps({ loading: false });
  130 + }
  131 + });
  132 +
  133 + const handleClose = () => resetValue();
  134 +
  135 + const useThrottle = useThrottleFn(() => {
  136 + getValue();
  137 + }, 2000);
  138 +
  139 + const handleSubmit = () => {
  140 + useThrottle();
  141 + };
  142 +
  143 + const getValue = async () => {
  144 + try {
  145 + setDrawerProps({ confirmLoading: true });
  146 + const values = await validate();
  147 + if (!values) return;
  148 + const [queryCondition, cycle, executeContent] = getQueryCondition(values);
  149 + const executeAttributes = selectDeviceRef.value?.getSelectAttributes();
  150 + validateSelectDevice(executeAttributes);
  151 + const data = {
  152 + ...values,
  153 + executeAttributes,
  154 + queryCondition,
  155 + cycle,
  156 + executeContent,
  157 + };
  158 + removeFields.forEach((item) => {
  159 + Reflect.deleteProperty(data, item);
  160 + });
  161 + businessText.value === BusinessReportConfigTextEnum.BUSINESS_ADD_TEXT
  162 + ? await createOrEditReportManage(data)
  163 + : putReportConfigManage({ ...restData.data, ...data });
  164 + emits('success');
  165 + createMessage.success(`${businessText.value}成功`);
  166 + closeDrawer();
  167 + handleClose();
  168 + } finally {
  169 + setDrawerProps({ confirmLoading: false });
  170 + }
  171 + };
  172 +
  173 + //重置表单
  174 + const resetValue = () => {
  175 + resetFields();
  176 + selectOptions.value = [];
  177 + selectDeviceRef.value?.resetValue();
  178 + };
  179 +</script>
src/views/report/config/components/SelectAttributes.vue renamed from src/views/report/config/cpns/DeviceAttrCpns.vue
1 <template> 1 <template>
2 <div 2 <div
  3 + class="flex"
3 v-for="param in dynamicInput.params" 4 v-for="param in dynamicInput.params"
4 :key="param.key" 5 :key="param.key"
5 - style="display: flex; margin-top: 0.25vh" 6 + style="margin-top: 1.25vh"
6 > 7 >
7 - <a-input  
8 - :disabled="true"  
9 - v-model:value="param.name"  
10 - style="width: 38%; margin-bottom: 5px; margin-left: 1vh"  
11 - @change="emitChange"  
12 - /> 8 + <a-input :disabled="true" v-model:value="param.name" style="width: 38%; margin-bottom: 5px" />
13 <Select 9 <Select
14 placeholder="请选择设备属性" 10 placeholder="请选择设备属性"
15 v-model:value="param.attributes" 11 v-model:value="param.attributes"
16 - style="width: 160px; margin-left: 1.8vw" 12 + style="width: 38%; margin-left: 1.8vw"
17 :options="selectOptions" 13 :options="selectOptions"
18 @change="emitChange" 14 @change="emitChange"
19 mode="multiple" 15 mode="multiple"
@@ -26,72 +22,66 @@ @@ -26,72 +22,66 @@
26 inheritAttrs: false, 22 inheritAttrs: false,
27 }; 23 };
28 </script> 24 </script>
29 -<script lang="ts" setup> 25 +<script lang="ts" setup name="SelectAttributes">
30 import { reactive, UnwrapRef, watchEffect, ref } from 'vue'; 26 import { reactive, UnwrapRef, watchEffect, ref } from 'vue';
31 import { propTypes } from '/@/utils/propTypes'; 27 import { propTypes } from '/@/utils/propTypes';
32 import { Select } from 'ant-design-vue'; 28 import { Select } from 'ant-design-vue';
33 - import { getAttribute } from '/@/api/ruleengine/ruleengineApi'; 29 + import { Params } from '../type/';
  30 + import { useHooks } from '../hooks/index.hooks';
34 31
35 - interface Params {  
36 - [x: string]: string;  
37 - attributes: any;  
38 - device: string;  
39 - }  
40 const props = defineProps({ 32 const props = defineProps({
41 value: propTypes.object.def({}), 33 value: propTypes.object.def({}),
42 - orgId: propTypes.string.def(''),  
43 }); 34 });
  35 +
44 const selectOptions: any = ref([]); 36 const selectOptions: any = ref([]);
45 - //获取对应设备属性  
46 - const getAttr = async (orgId, _) => {  
47 - if (orgId) {  
48 - const res = await getAttribute(orgId);  
49 - if (Array.isArray(res)) {  
50 - selectOptions.value = res.map((o) => {  
51 - let obj: any = {};  
52 - if (o?.identifier !== null) {  
53 - obj = {  
54 - label: o?.identifier,  
55 - value: o?.identifier,  
56 - };  
57 - return obj;  
58 - }  
59 - });  
60 - //如果服务端返回的数组里含有null 过滤null值  
61 - const excludeNull = selectOptions.value.filter(Boolean);  
62 - selectOptions.value = excludeNull;  
63 - }  
64 - }  
65 - }; 37 +
  38 + const { getDeviceAttr } = useHooks();
  39 +
66 //动态数据 40 //动态数据
67 const dynamicInput: UnwrapRef<{ params: Params[] }> = reactive({ params: [] }); 41 const dynamicInput: UnwrapRef<{ params: Params[] }> = reactive({ params: [] });
68 - const rEffect = watchEffect(() => {  
69 - initVal();  
70 - });  
71 - rEffect();  
72 - /**  
73 - * 初始化数值  
74 - */  
75 - async function initVal() { 42 +
  43 + const initVal = async () => {
76 if (props.value) { 44 if (props.value) {
77 - await getAttr(props.value?.deviceProfileId, props.value?.id); 45 + selectOptions.value = await getDeviceAttr(props.value?.deviceProfileId);
78 dynamicInput.params.push({ 46 dynamicInput.params.push({
79 name: props.value.label, 47 name: props.value.label,
80 device: props.value.value, 48 device: props.value.value,
81 - attributes: props.value?.attributes == [] ? [] : props.value.attributes, 49 + attributes: props.value.attributes,
82 }); 50 });
83 } 51 }
84 - }  
85 - /**  
86 - * 数值改变  
87 - */  
88 - function emitChange() { 52 + };
  53 +
  54 + //数值改变
  55 + const valEffect = watchEffect(() => {
  56 + initVal();
  57 + });
  58 +
  59 + valEffect();
  60 +
  61 + //chang改变
  62 + const emitChange = () => {
89 return dynamicInput.params[0]; 63 return dynamicInput.params[0];
90 - } 64 + };
91 defineExpose({ 65 defineExpose({
92 emitChange, 66 emitChange,
93 }); 67 });
94 </script> 68 </script>
95 <style scoped lang="css"> 69 <style scoped lang="css">
96 - @import './deviceAttrCpns.css'; 70 + .dynamic-delete-button {
  71 + cursor: pointer;
  72 + position: relative;
  73 + top: 4px;
  74 + font-size: 24px;
  75 + color: #999;
  76 + transition: all 0.3s;
  77 + }
  78 +
  79 + .dynamic-delete-button:hover {
  80 + color: #777;
  81 + }
  82 +
  83 + .dynamic-delete-button[disabled] {
  84 + cursor: not-allowed;
  85 + opacity: 0.5;
  86 + }
97 </style> 87 </style>
  1 +<template>
  2 + <Select
  3 + placeholder="请选择设备"
  4 + v-model:value="selectValue"
  5 + style="width: 100%"
  6 + :options="selectOptions"
  7 + @change="handleDeviceChange"
  8 + mode="multiple"
  9 + labelInValue
  10 + />
  11 + <template v-for="(item, index) in deviceList" :key="item.value">
  12 + <SelectAttributes :ref="bindDeviceRef.deviceAttrRef" :value="item" :index="index" />
  13 + </template>
  14 +</template>
  15 +<script lang="ts" setup name="SelectDevice">
  16 + import { ref, Ref, PropType, unref } from 'vue';
  17 + import { Select } from 'ant-design-vue';
  18 + import SelectAttributes from './SelectAttributes.vue';
  19 + import { TDeviceList, TSelectOption } from '../type';
  20 +
  21 + const props = defineProps({
  22 + selectOptions: {
  23 + type: Array as PropType<TSelectOption[]>,
  24 + required: true,
  25 + },
  26 + });
  27 +
  28 + const selectValue = ref([]);
  29 +
  30 + const bindDeviceRef = {
  31 + deviceAttrRef: ref([]),
  32 + };
  33 +
  34 + const deviceList: Ref<TDeviceList[]> = ref([]);
  35 +
  36 + const getSelectAttributes = () => {
  37 + return unref(bindDeviceRef.deviceAttrRef)?.map((item: any) => item.emitChange());
  38 + };
  39 +
  40 + const handleDeviceChange = (_, options) => {
  41 + deviceList.value = options;
  42 + };
  43 +
  44 + const setValue = (value) => {
  45 + selectValue.value = value.map((item) => ({
  46 + label: item.name,
  47 + key: item.device,
  48 + }));
  49 + deviceList.value = value?.map((item) => {
  50 + const T = props.selectOptions.find((o) => {
  51 + if (item.device === o.value) {
  52 + return {
  53 + id: o.id,
  54 + deviceProfileId: o.deviceProfileId,
  55 + };
  56 + }
  57 + });
  58 + return {
  59 + ...T,
  60 + label: item.alias ? item.alias : item.name,
  61 + value: item.device,
  62 + attributes: item.attributes,
  63 + };
  64 + });
  65 + };
  66 +
  67 + const resetValue = () => {
  68 + selectValue.value = [];
  69 + deviceList.value = [];
  70 + };
  71 + defineExpose({
  72 + getSelectAttributes,
  73 + setValue,
  74 + resetValue,
  75 + });
  76 +</script>
  77 +<style scoped lang="css"></style>
  1 +import SelectDevice from './SelectDevice.vue';
  2 +import SelectAttributes from './SelectAttributes.vue';
  3 +import DevicePreviewModal from './DevicePreviewModal.vue';
  4 +import ReportConfigDrawer from './ReportConfigDrawer.vue';
  5 +
  6 +export { SelectDevice, SelectAttributes, DevicePreviewModal, ReportConfigDrawer };
src/views/report/config/config.ts renamed from src/views/report/config/config.data.ts
1 -import { ref } from 'vue';  
2 -import { BasicColumn, FormSchema } from '/@/components/Table';  
3 -import { FormSchema as QFormSchema, useComponentRegister } from '/@/components/Form/index'; 1 +import { BasicColumn, BasicTableProps, FormSchema } from '/@/components/Table';
  2 +import { FormSchema as BFormSchema, useComponentRegister } from '/@/components/Form/index';
4 import { findDictItemByCode } from '/@/api/system/dict'; 3 import { findDictItemByCode } from '/@/api/system/dict';
5 -import { isTiming, isWeek, isMonth, isFixedTime } from './timeConfig';  
6 -import { AggregateDataEnum } from '../../device/localtion/cpns/TimePeriodForm/config'; 4 +import { AggregateDataEnum } from '/@/views/device/localtion/cpns/TimePeriodForm/config';
7 import { 5 import {
8 getPacketIntervalByRange, 6 getPacketIntervalByRange,
9 getPacketIntervalByValue, 7 getPacketIntervalByValue,
10 intervalOption, 8 intervalOption,
11 -} from '../../device/localtion/cpns/TimePeriodForm/helper'; 9 +} from '/@/views/device/localtion/cpns/TimePeriodForm/helper';
12 import moment, { Moment } from 'moment'; 10 import moment, { Moment } from 'moment';
13 import { OrgTreeSelect } from '../../common/OrgTreeSelect'; 11 import { OrgTreeSelect } from '../../common/OrgTreeSelect';
  12 +import {
  13 + BusinessExecutewayEnum,
  14 + BusinessReportConfigTextEnum,
  15 + CycleTypeEnum,
  16 + DataTypeEnum,
  17 + DataTypeNameEnum,
  18 + ExecuteWayNameEnum,
  19 + QueryWay,
  20 + SchemaFiled,
  21 + businesAggOptions,
  22 + businesCycleTypeOptions,
  23 + businesDataTypeOptions,
  24 + businesLimitValue,
  25 + businesQueryCycleOptions,
  26 + businesWayOptions,
  27 + businessExecuteWayOptions,
  28 + cycleTypeIsMonthly,
  29 + cycleTypeIsWeekly,
  30 + cycleTypeSetDefault,
  31 + exectueIsImmed,
  32 + exectueIsSchedule,
  33 +} from './enum';
14 useComponentRegister('OrgTreeSelect', OrgTreeSelect); 34 useComponentRegister('OrgTreeSelect', OrgTreeSelect);
15 -export enum QueryWay {  
16 - LATEST = 'latest',  
17 - TIME_PERIOD = 'timePeriod',  
18 -}  
19 -export enum SchemaFiled {  
20 - WAY = 'queryMode',  
21 - TIME_PERIOD = 'timePeriod',  
22 - KEYS = 'keys',  
23 - DATE_RANGE = 'dataRange',  
24 - START_TS = 'startTs',  
25 - END_TS = 'endTs',  
26 - INTERVAL = 'interval',  
27 - LIMIT = 'limit',  
28 - AGG = 'agg',  
29 - ORDER_BY = 'orderBy',  
30 - DATA_TYPE = 'dataType',  
31 -}  
32 -  
33 -export enum DataTypeEnum {  
34 - ORIGINAL = 0,  
35 - AGG = 1,  
36 -}  
37 -  
38 -export enum DataTypeNameEnum {  
39 - ORIGINAL = '原始数据',  
40 - AGG = '聚合数据',  
41 -}  
42 -  
43 -export const organizationId = ref('');  
44 35
45 -// 表格配置 36 +// 表格配置
46 export const columns: BasicColumn[] = [ 37 export const columns: BasicColumn[] = [
47 { 38 {
48 title: '配置名称', 39 title: '配置名称',
@@ -75,7 +66,9 @@ export const columns: BasicColumn[] = [ @@ -75,7 +66,9 @@ export const columns: BasicColumn[] = [
75 dataIndex: 'executeWay', 66 dataIndex: 'executeWay',
76 width: 160, 67 width: 160,
77 format: (_text: string, record: Recordable) => { 68 format: (_text: string, record: Recordable) => {
78 - return record.executeWay === 0 ? '立即执行' : '定时执行'; 69 + return record.executeWay === BusinessExecutewayEnum.BUSINESS_EXECUTEWAY_IMMEDIATE
  70 + ? ExecuteWayNameEnum.EXECUTEWAY_IMMEDIATE
  71 + : ExecuteWayNameEnum.EXECUTEWAY_SCHEDULED;
79 }, 72 },
80 }, 73 },
81 { 74 {
@@ -95,20 +88,8 @@ export const columns: BasicColumn[] = [ @@ -95,20 +88,8 @@ export const columns: BasicColumn[] = [
95 width: 180, 88 width: 180,
96 }, 89 },
97 ]; 90 ];
98 -export const viewDeviceColumn: BasicColumn[] = [  
99 - {  
100 - title: '设备',  
101 - dataIndex: 'device',  
102 - width: 80,  
103 - },  
104 - {  
105 - title: '属性',  
106 - dataIndex: 'attribute',  
107 - width: 120,  
108 - },  
109 -];  
110 91
111 -// 查询配置 92 +// 表格查询配置
112 export const searchFormSchema: FormSchema[] = [ 93 export const searchFormSchema: FormSchema[] = [
113 { 94 {
114 field: 'name', 95 field: 'name',
@@ -152,8 +133,45 @@ export const searchFormSchema: FormSchema[] = [ @@ -152,8 +133,45 @@ export const searchFormSchema: FormSchema[] = [
152 }, 133 },
153 ]; 134 ];
154 135
155 -// 新增编辑配置  
156 -export const formSchema: QFormSchema[] = [ 136 +//表格通用属性配置
  137 +export const defaultTableAttribtes: BasicTableProps = {
  138 + title: '报表列表',
  139 + columns,
  140 + showIndexColumn: false,
  141 + clickToRowSelect: false,
  142 + formConfig: {
  143 + labelWidth: 120,
  144 + schemas: searchFormSchema,
  145 + fieldMapToTime: [['sendTime', ['startTime', 'endTime'], 'x']],
  146 + },
  147 + useSearchForm: true,
  148 + showTableSetting: true,
  149 + bordered: true,
  150 + rowKey: 'id',
  151 + actionColumn: {
  152 + width: 200,
  153 + title: '操作',
  154 + dataIndex: 'action',
  155 + slots: { customRender: 'action' },
  156 + fixed: 'right',
  157 + },
  158 +};
  159 +
  160 +export const viewDeviceColumn: BasicColumn[] = [
  161 + {
  162 + title: '设备',
  163 + dataIndex: 'device',
  164 + width: 80,
  165 + },
  166 + {
  167 + title: '属性',
  168 + dataIndex: 'attribute',
  169 + width: 120,
  170 + },
  171 +];
  172 +
  173 +// 表单配置
  174 +export const formSchema: BFormSchema[] = [
157 { 175 {
158 field: 'name', 176 field: 'name',
159 label: '报表名称', 177 label: '报表名称',
@@ -171,13 +189,6 @@ export const formSchema: QFormSchema[] = [ @@ -171,13 +189,6 @@ export const formSchema: QFormSchema[] = [
171 colProps: { span: 24 }, 189 colProps: { span: 24 },
172 component: 'OrgTreeSelect', 190 component: 'OrgTreeSelect',
173 required: true, 191 required: true,
174 - componentProps: () => {  
175 - return {  
176 - async onChange(e) {  
177 - organizationId.value = e;  
178 - },  
179 - };  
180 - },  
181 }, 192 },
182 { 193 {
183 field: 'remark', 194 field: 'remark',
@@ -192,64 +203,48 @@ export const formSchema: QFormSchema[] = [ @@ -192,64 +203,48 @@ export const formSchema: QFormSchema[] = [
192 { 203 {
193 field: 'executeWay', 204 field: 'executeWay',
194 component: 'RadioGroup', 205 component: 'RadioGroup',
195 - helpMessage: [  
196 - `立即执行,在创建完报表配置后,启用配置即执行。  
197 - 定时执行,用户定义执行时间,启用后,  
198 - 在满足执行时间条件后,自动执行。`,  
199 - ], 206 + helpMessage: [BusinessReportConfigTextEnum.BUSINESS_EXECUTEWAY_HELPMESSAGE_TEXT],
200 label: '执行方式', 207 label: '执行方式',
201 colProps: { 208 colProps: {
202 span: 24, 209 span: 24,
203 }, 210 },
204 - defaultValue: 0, 211 + defaultValue: BusinessExecutewayEnum.BUSINESS_EXECUTEWAY_IMMEDIATE,
205 componentProps: ({ formActionType }) => { 212 componentProps: ({ formActionType }) => {
206 const { updateSchema, setFieldsValue } = formActionType; 213 const { updateSchema, setFieldsValue } = formActionType;
207 - const options = [  
208 - {  
209 - label: '立即执行',  
210 - value: 0,  
211 - },  
212 - {  
213 - label: '定时执行',  
214 - value: 1,  
215 - },  
216 - ];  
217 return { 214 return {
218 - options, 215 + options: businessExecuteWayOptions,
219 placeholder: '请选择执行方式', 216 placeholder: '请选择执行方式',
220 onChange(e) { 217 onChange(e) {
221 - let dataCompareOpions: any = [];  
222 - setFieldsValue({  
223 - startTs: 1000,  
224 - interval: 1000,  
225 - });  
226 - if (e.target.value == 0) {  
227 - setFieldsValue({ queryMode: QueryWay.LATEST });  
228 - dataCompareOpions = [  
229 - { label: '固定周期', value: QueryWay.LATEST },  
230 - { label: '自定义周期', value: QueryWay.TIME_PERIOD },  
231 - ]; 218 + //动态切换 最近时间 间隔时间变化
  219 + const setDefaultTime = (startTs, interval, queryMode) => {
  220 + setFieldsValue({
  221 + startTs,
  222 + interval,
  223 + queryMode,
  224 + });
  225 + };
  226 + //动态切换 查询周期变化
  227 + const setQueryMode = (defaultValue, field = SchemaFiled.WAY, comObJ) => {
232 updateSchema({ 228 updateSchema({
233 - field: SchemaFiled.WAY,  
234 - componentProps: {  
235 - options: dataCompareOpions,  
236 - }, 229 + defaultValue,
  230 + field,
  231 + componentProps: comObJ,
  232 + });
  233 + };
  234 + if (e.target.value == BusinessExecutewayEnum.BUSINESS_EXECUTEWAY_IMMEDIATE) {
  235 + //业务 选择立即执行
  236 + setDefaultTime(1000, 1000, QueryWay.LATEST);
  237 + setQueryMode(null, SchemaFiled.WAY, {
  238 + options: businesQueryCycleOptions,
237 }); 239 });
238 } else { 240 } else {
239 - setFieldsValue({ queryMode: QueryWay.LATEST });  
240 - setFieldsValue({ startTs: 5000 });  
241 - setFieldsValue({ interval: 1000 });  
242 - dataCompareOpions = [{ label: '固定周期', value: QueryWay.LATEST }];  
243 - updateSchema({  
244 - defaultValue: QueryWay.LATEST,  
245 - field: SchemaFiled.WAY,  
246 - componentProps: {  
247 - options: dataCompareOpions,  
248 - }, 241 + //业务 选择定时执行
  242 + setDefaultTime(5000, 1000, QueryWay.LATEST);
  243 + setQueryMode(QueryWay.LATEST, SchemaFiled.WAY, {
  244 + options: businesQueryCycleOptions.filter((item) => item.value === QueryWay.LATEST),
249 }); 245 });
250 } 246 }
251 }, 247 },
252 - maxLength: 250,  
253 }; 248 };
254 }, 249 },
255 }, 250 },
@@ -259,16 +254,12 @@ export const formSchema: QFormSchema[] = [ @@ -259,16 +254,12 @@ export const formSchema: QFormSchema[] = [
259 label: '周期', 254 label: '周期',
260 required: true, 255 required: true,
261 colProps: { span: 24 }, 256 colProps: { span: 24 },
262 - defaultValue: 0, 257 + defaultValue: CycleTypeEnum.DAILY,
263 componentProps: { 258 componentProps: {
264 placeholder: '请选择周期', 259 placeholder: '请选择周期',
265 - options: [  
266 - { label: '每日', value: 0 },  
267 - { label: '每周', value: 1 },  
268 - { label: '每月', value: 2 },  
269 - ], 260 + options: businesCycleTypeOptions,
270 }, 261 },
271 - ifShow: ({ values }) => isTiming(values.executeWay), 262 + ifShow: ({ values }) => exectueIsSchedule(values.executeWay),
272 }, 263 },
273 { 264 {
274 field: 'currentCycle', 265 field: 'currentCycle',
@@ -276,7 +267,7 @@ export const formSchema: QFormSchema[] = [ @@ -276,7 +267,7 @@ export const formSchema: QFormSchema[] = [
276 label: '每周', 267 label: '每周',
277 required: true, 268 required: true,
278 colProps: { span: 24 }, 269 colProps: { span: 24 },
279 - defaultValue: '0 0 0 ? * MON', 270 + defaultValue: cycleTypeSetDefault.WEEKLY,
280 componentProps: { 271 componentProps: {
281 placeholder: '请选择周期', 272 placeholder: '请选择周期',
282 api: findDictItemByCode, 273 api: findDictItemByCode,
@@ -286,7 +277,8 @@ export const formSchema: QFormSchema[] = [ @@ -286,7 +277,8 @@ export const formSchema: QFormSchema[] = [
286 labelField: 'itemText', 277 labelField: 'itemText',
287 valueField: 'itemValue', 278 valueField: 'itemValue',
288 }, 279 },
289 - ifShow: ({ values }) => isWeek(values.cycleType), 280 + ifShow: ({ values }) =>
  281 + exectueIsSchedule(values.executeWay) && cycleTypeIsWeekly(values.cycleType),
290 }, 282 },
291 { 283 {
292 field: 'cycleTime', 284 field: 'cycleTime',
@@ -294,7 +286,7 @@ export const formSchema: QFormSchema[] = [ @@ -294,7 +286,7 @@ export const formSchema: QFormSchema[] = [
294 label: '每月', 286 label: '每月',
295 required: true, 287 required: true,
296 colProps: { span: 24 }, 288 colProps: { span: 24 },
297 - defaultValue: '0 0 0 1 * ? *', 289 + defaultValue: cycleTypeSetDefault.MONTHLY,
298 componentProps: { 290 componentProps: {
299 placeholder: '请选择月份', 291 placeholder: '请选择月份',
300 api: findDictItemByCode, 292 api: findDictItemByCode,
@@ -304,7 +296,8 @@ export const formSchema: QFormSchema[] = [ @@ -304,7 +296,8 @@ export const formSchema: QFormSchema[] = [
304 labelField: 'itemText', 296 labelField: 'itemText',
305 valueField: 'itemValue', 297 valueField: 'itemValue',
306 }, 298 },
307 - ifShow: ({ values }) => isMonth(values.cycleType), 299 + ifShow: ({ values }) =>
  300 + exectueIsSchedule(values.executeWay) && cycleTypeIsMonthly(values.cycleType),
308 }, 301 },
309 { 302 {
310 field: 'cronTime', 303 field: 'cronTime',
@@ -312,7 +305,7 @@ export const formSchema: QFormSchema[] = [ @@ -312,7 +305,7 @@ export const formSchema: QFormSchema[] = [
312 label: '时间', 305 label: '时间',
313 required: true, 306 required: true,
314 colProps: { span: 24 }, 307 colProps: { span: 24 },
315 - defaultValue: '0 0 0 * * ?', 308 + defaultValue: cycleTypeSetDefault.DAILY,
316 componentProps: { 309 componentProps: {
317 placeholder: '请选择时间', 310 placeholder: '请选择时间',
318 api: findDictItemByCode, 311 api: findDictItemByCode,
@@ -322,12 +315,13 @@ export const formSchema: QFormSchema[] = [ @@ -322,12 +315,13 @@ export const formSchema: QFormSchema[] = [
322 labelField: 'itemText', 315 labelField: 'itemText',
323 valueField: 'itemValue', 316 valueField: 'itemValue',
324 }, 317 },
325 - ifShow: ({ values }) => isTiming(values.executeWay), 318 + ifShow: ({ values }) =>
  319 + exectueIsSchedule(values.executeWay) && exectueIsSchedule(values.executeWay),
326 }, 320 },
327 { 321 {
328 field: 'devices', 322 field: 'devices',
329 label: '设备', 323 label: '设备',
330 - component: 'Select', 324 + component: 'Input',
331 slot: 'devices', 325 slot: 'devices',
332 colProps: { span: 24 }, 326 colProps: { span: 24 },
333 }, 327 },
@@ -338,42 +332,37 @@ export const formSchema: QFormSchema[] = [ @@ -338,42 +332,37 @@ export const formSchema: QFormSchema[] = [
338 component: 'Select', 332 component: 'Select',
339 componentProps: ({ formActionType }) => { 333 componentProps: ({ formActionType }) => {
340 const { updateSchema, setFieldsValue } = formActionType; 334 const { updateSchema, setFieldsValue } = formActionType;
341 - const options = [  
342 - { label: DataTypeNameEnum.ORIGINAL, value: DataTypeEnum.ORIGINAL },  
343 - { label: DataTypeNameEnum.AGG, value: DataTypeEnum.AGG },  
344 - ];  
345 return { 335 return {
346 - options, 336 + options: businesDataTypeOptions,
347 onSelect(e) { 337 onSelect(e) {
348 - let dataCompareOpions: any = [];  
349 - if (e == 0) {  
350 - setFieldsValue({ agg: 'NONE' });  
351 - dataCompareOpions = [{ label: '空', value: AggregateDataEnum.NONE }]; 338 + setFieldsValue({
  339 + [SchemaFiled.DATE_RANGE]: [],
  340 + [SchemaFiled.START_TS]: null,
  341 + [SchemaFiled.END_TS]: null,
  342 + [SchemaFiled.INTERVAL]: null,
  343 + dateGroupGap: null,
  344 + });
  345 + const setAgg = (agg, field = SchemaFiled.AGG, comObj) => {
  346 + setFieldsValue({ agg });
352 updateSchema({ 347 updateSchema({
353 - field: SchemaFiled.AGG,  
354 - componentProps: {  
355 - options: dataCompareOpions,  
356 - }, 348 + field,
  349 + componentProps: comObj,
  350 + });
  351 + };
  352 + if (e == DataTypeEnum.ORIGINAL) {
  353 + //业务 选择原始数据
  354 + setAgg('NONE', SchemaFiled.AGG, {
  355 + options: businesAggOptions.filter((item) => item.value === AggregateDataEnum.NONE),
357 }); 356 });
  357 + setFieldsValue({ limit: businesLimitValue.default });
358 } else { 358 } else {
359 - setFieldsValue({ agg: '' });  
360 - dataCompareOpions = [  
361 - { label: '最小值', value: AggregateDataEnum.MIN },  
362 - { label: '最大值', value: AggregateDataEnum.MAX },  
363 - { label: '平均值', value: AggregateDataEnum.AVG },  
364 - { label: '求和', value: AggregateDataEnum.SUM },  
365 - { label: '计数', value: AggregateDataEnum.COUNT },  
366 - ];  
367 - updateSchema({  
368 - field: SchemaFiled.AGG,  
369 - componentProps: {  
370 - options: dataCompareOpions,  
371 - }, 359 + //业务 选择聚合数据
  360 + setAgg('', SchemaFiled.AGG, {
  361 + options: businesAggOptions.filter((item) => item.value !== AggregateDataEnum.NONE),
372 }); 362 });
373 } 363 }
374 }, 364 },
375 - maxLength: 250,  
376 - placeholder: '请选择属性性质', 365 + placeholder: '请选择数据类型',
377 }; 366 };
378 }, 367 },
379 colProps: { span: 24 }, 368 colProps: { span: 24 },
@@ -393,15 +382,15 @@ export const formSchema: QFormSchema[] = [ @@ -393,15 +382,15 @@ export const formSchema: QFormSchema[] = [
393 required: true, 382 required: true,
394 label: '最大条数', 383 label: '最大条数',
395 component: 'InputNumber', 384 component: 'InputNumber',
396 - defaultValue: 100, 385 + defaultValue: businesLimitValue.default,
397 ifShow({ values }) { 386 ifShow({ values }) {
398 return values[SchemaFiled.AGG] === AggregateDataEnum.NONE; 387 return values[SchemaFiled.AGG] === AggregateDataEnum.NONE;
399 }, 388 },
400 - colProps: { span: 12 },  
401 componentProps: { 389 componentProps: {
  390 + style: { width: '10vw' },
402 placeholder: '请输入最大条数', 391 placeholder: '请输入最大条数',
403 - min: 7,  
404 - max: 50000, 392 + min: businesLimitValue.min,
  393 + max: businesLimitValue.max,
405 }, 394 },
406 }, 395 },
407 { 396 {
@@ -414,18 +403,20 @@ export const formSchema: QFormSchema[] = [ @@ -414,18 +403,20 @@ export const formSchema: QFormSchema[] = [
414 const { setFieldsValue } = formActionType; 403 const { setFieldsValue } = formActionType;
415 return { 404 return {
416 placeholder: '请选择查询周期', 405 placeholder: '请选择查询周期',
417 - options: [  
418 - { label: '固定周期', value: QueryWay.LATEST },  
419 - { label: '自定义周期', value: QueryWay.TIME_PERIOD },  
420 - ], 406 + options: businesWayOptions,
421 onChange(value) { 407 onChange(value) {
422 value === QueryWay.LATEST 408 value === QueryWay.LATEST
423 ? setFieldsValue({ 409 ? setFieldsValue({
424 [SchemaFiled.DATE_RANGE]: [], 410 [SchemaFiled.DATE_RANGE]: [],
425 [SchemaFiled.START_TS]: null, 411 [SchemaFiled.START_TS]: null,
426 [SchemaFiled.END_TS]: null, 412 [SchemaFiled.END_TS]: null,
  413 + [SchemaFiled.INTERVAL]: null,
  414 + dateGroupGap: null,
427 }) 415 })
428 - : setFieldsValue({ [SchemaFiled.START_TS]: null }); 416 + : setFieldsValue({
  417 + [SchemaFiled.START_TS]: null,
  418 + [SchemaFiled.INTERVAL]: null,
  419 + });
429 }, 420 },
430 }; 421 };
431 }, 422 },
@@ -436,7 +427,7 @@ export const formSchema: QFormSchema[] = [ @@ -436,7 +427,7 @@ export const formSchema: QFormSchema[] = [
436 component: 'RangePicker', 427 component: 'RangePicker',
437 required: true, 428 required: true,
438 ifShow({ values }) { 429 ifShow({ values }) {
439 - return values[SchemaFiled.WAY] === QueryWay.TIME_PERIOD && !isFixedTime(values.executeWay); 430 + return values[SchemaFiled.WAY] === QueryWay.TIME_PERIOD && exectueIsImmed(values.executeWay);
440 }, 431 },
441 componentProps({ formActionType }) { 432 componentProps({ formActionType }) {
442 const { setFieldsValue } = formActionType; 433 const { setFieldsValue } = formActionType;
@@ -462,14 +453,12 @@ export const formSchema: QFormSchema[] = [ @@ -462,14 +453,12 @@ export const formSchema: QFormSchema[] = [
462 getPopupContainer: () => document.body, 453 getPopupContainer: () => document.body,
463 }; 454 };
464 }, 455 },
465 - colProps: {  
466 - span: 10,  
467 - },  
468 }, 456 },
469 { 457 {
470 field: 'dateGroupGap', 458 field: 'dateGroupGap',
471 label: '分组间隔', 459 label: '分组间隔',
472 component: 'Select', 460 component: 'Select',
  461 + colProps: { span: 24 },
473 dynamicRules: ({ model }) => { 462 dynamicRules: ({ model }) => {
474 return [ 463 return [
475 { 464 {
@@ -480,7 +469,7 @@ export const formSchema: QFormSchema[] = [ @@ -480,7 +469,7 @@ export const formSchema: QFormSchema[] = [
480 ]; 469 ];
481 }, 470 },
482 ifShow({ values }) { 471 ifShow({ values }) {
483 - return values[SchemaFiled.WAY] === QueryWay.TIME_PERIOD && !isFixedTime(values.executeWay); 472 + return values[SchemaFiled.WAY] === QueryWay.TIME_PERIOD && exectueIsImmed(values.executeWay);
484 }, 473 },
485 componentProps({ formModel, formActionType }) { 474 componentProps({ formModel, formActionType }) {
486 const options = 475 const options =
@@ -542,3 +531,5 @@ export const formSchema: QFormSchema[] = [ @@ -542,3 +531,5 @@ export const formSchema: QFormSchema[] = [
542 }, 531 },
543 }, 532 },
544 ]; 533 ];
  534 +
  535 +export { SchemaFiled };
1 -.dynamic-delete-button {  
2 - cursor: pointer;  
3 - position: relative;  
4 - top: 4px;  
5 - font-size: 24px;  
6 - color: #999;  
7 - transition: all 0.3s;  
8 -}  
9 -  
10 -.dynamic-delete-button:hover {  
11 - color: #777;  
12 -}  
13 -  
14 -.dynamic-delete-button[disabled] {  
15 - cursor: not-allowed;  
16 - opacity: 0.5;  
17 -}  
  1 +/**
  2 + * 报表配置相关枚举值定义
  3 + */
  4 +import { AggregateDataEnum } from '/@/views/device/localtion/cpns/TimePeriodForm/config';
  5 +
  6 +//业务权限配置枚举
  7 +export enum PermissionReportConfigEnum {
  8 + PERMISSION_POST = 'api:yt:report_form:config:post',
  9 + PERMISSION_GET = 'api:yt:report:get',
  10 + PERMISSION_DELETE = 'api:yt:report_form:config:delete',
  11 + PERMISSION_UPDATE = 'api:yt:report_form:config:update',
  12 +}
  13 +
  14 +//业务文字描述配置枚举
  15 +export enum BusinessReportConfigTextEnum {
  16 + BUSINESS_ADD_TEXT = '新增报表',
  17 + BUSINESS_EXPORT_TEXT = '下载报表',
  18 + BUSINESS_DELETE_TEXT = '批量删除',
  19 + BUSINESS_VIEW_DEVICE_TEXT = '查看设备',
  20 + BUSINESS_UPDATE_TEXT = '编辑报表',
  21 + BUSINESS_ENABLE_TEXT = '启用',
  22 + BUSINESS_DISABLE_TEXT = '禁用',
  23 + BUSINESS_VIEW_TEXT = '查看报表',
  24 + BUSINESS_EXECUTEWAY_HELPMESSAGE_TEXT = `立即执行,在创建完报表配置后,启用配置即执行;
  25 + 定时执行,用户定义执行时间,启用后,
  26 + 在满足执行时间条件后,自动执行。
  27 + `,
  28 +}
  29 +
  30 +//业务表格状态配置枚举
  31 +export enum BusinessReportConfigStatusEnum {
  32 + BUSINESS_ENABLE = 0,
  33 + BUSINESS_DISABLE = 1,
  34 +}
  35 +
  36 +//业务表单执行方式配置枚举
  37 +export enum BusinessExecutewayEnum {
  38 + BUSINESS_EXECUTEWAY_IMMEDIATE = 0,
  39 + BUSINESS_EXECUTEWAY_SCHEDULED = 1,
  40 +}
  41 +
  42 +//业务表单查询周期配置枚举
  43 +export enum QueryWay {
  44 + LATEST = 'latest',
  45 + TIME_PERIOD = 'timePeriod',
  46 +}
  47 +
  48 +//业务表单周期配置枚举
  49 +export enum CycleTypeEnum {
  50 + DAILY = 0,
  51 + WEEKLY = 1,
  52 + MONTHLY = 2,
  53 +}
  54 +
  55 +export enum SchemaFiled {
  56 + WAY = 'queryMode',
  57 + TIME_PERIOD = 'timePeriod',
  58 + KEYS = 'keys',
  59 + DATE_RANGE = 'dataRange',
  60 + START_TS = 'startTs',
  61 + END_TS = 'endTs',
  62 + INTERVAL = 'interval',
  63 + LIMIT = 'limit',
  64 + AGG = 'agg',
  65 + ORDER_BY = 'orderBy',
  66 + DATA_TYPE = 'dataType',
  67 +}
  68 +
  69 +export enum DataTypeEnum {
  70 + ORIGINAL = 0,
  71 + AGG = 1,
  72 +}
  73 +
  74 +export enum DataTypeNameEnum {
  75 + ORIGINAL = '原始数据',
  76 + AGG = '聚合数据',
  77 +}
  78 +
  79 +//映射执行方式文本值
  80 +export enum ExecuteWayNameEnum {
  81 + EXECUTEWAY_IMMEDIATE = '立即执行',
  82 + EXECUTEWAY_SCHEDULED = '定时执行',
  83 +}
  84 +
  85 +//业务表单执行方式配置项
  86 +export const businessExecuteWayOptions = [
  87 + {
  88 + label: '立即执行',
  89 + value: BusinessExecutewayEnum.BUSINESS_EXECUTEWAY_IMMEDIATE,
  90 + },
  91 + {
  92 + label: '定时执行',
  93 + value: BusinessExecutewayEnum.BUSINESS_EXECUTEWAY_SCHEDULED,
  94 + },
  95 +];
  96 +
  97 +//业务表单查询周期配置项
  98 +export const businesQueryCycleOptions = [
  99 + {
  100 + label: '固定周期',
  101 + value: QueryWay.LATEST,
  102 + },
  103 + {
  104 + label: '自定义周期',
  105 + value: QueryWay.TIME_PERIOD,
  106 + },
  107 +];
  108 +
  109 +//业务表单周期配置项
  110 +export const businesCycleTypeOptions = [
  111 + { label: '每日', value: CycleTypeEnum.DAILY },
  112 + { label: '每周', value: CycleTypeEnum.WEEKLY },
  113 + { label: '每月', value: CycleTypeEnum.MONTHLY },
  114 +];
  115 +
  116 +//业务表单动态判断是否为定时执行配置项
  117 +export const exectueIsSchedule = (type: number) => {
  118 + return type === BusinessExecutewayEnum.BUSINESS_EXECUTEWAY_SCHEDULED;
  119 +};
  120 +
  121 +//业务表单动态判断是否为立即执行配置项
  122 +export const exectueIsImmed = (type: number) => {
  123 + return type === BusinessExecutewayEnum.BUSINESS_EXECUTEWAY_IMMEDIATE;
  124 +};
  125 +
  126 +//业务表单动态判断是否为每周配置项
  127 +export const cycleTypeIsWeekly = (type: number) => {
  128 + return type === CycleTypeEnum.WEEKLY;
  129 +};
  130 +
  131 +//业务表单动态判断是否为每月配置项
  132 +export const cycleTypeIsMonthly = (type: number) => {
  133 + return type === CycleTypeEnum.MONTHLY;
  134 +};
  135 +
  136 +//业务表单每周每日每月默认值配置
  137 +export const cycleTypeSetDefault = {
  138 + DAILY: '0 0 0 * * ?',
  139 + WEEKLY: '0 0 0 ? * MON',
  140 + MONTHLY: '0 0 0 1 * ? *',
  141 +};
  142 +
  143 +//业务表单数据类型配置项
  144 +export const businesDataTypeOptions = [
  145 + { label: DataTypeNameEnum.ORIGINAL, value: DataTypeEnum.ORIGINAL },
  146 + { label: DataTypeNameEnum.AGG, value: DataTypeEnum.AGG },
  147 +];
  148 +
  149 +//业务表单聚合条件配置项
  150 +export const businesAggOptions = [
  151 + { label: '最小值', value: AggregateDataEnum.MIN },
  152 + { label: '最大值', value: AggregateDataEnum.MAX },
  153 + { label: '平均值', value: AggregateDataEnum.AVG },
  154 + { label: '求和', value: AggregateDataEnum.SUM },
  155 + { label: '计数', value: AggregateDataEnum.COUNT },
  156 + { label: '空', value: AggregateDataEnum.NONE },
  157 +];
  158 +
  159 +//业务表单最大条数配置项
  160 +export const businesLimitValue = {
  161 + default: 100,
  162 + min: 7,
  163 + max: 50000,
  164 +};
  165 +
  166 +//业务查询周期配置项
  167 +export const businesWayOptions = [
  168 + { label: '固定周期', value: QueryWay.LATEST },
  169 + { label: '自定义周期', value: QueryWay.TIME_PERIOD },
  170 +];
  1 +/**
  2 + * 报表配置所需hooks
  3 + */
  4 +
  5 +import { ref } from 'vue';
  6 +import {
  7 + DataTypeEnum,
  8 + QueryWay,
  9 + SchemaFiled,
  10 + businesAggOptions,
  11 + BusinessExecutewayEnum,
  12 + businesWayOptions,
  13 + CycleTypeEnum,
  14 + BusinessReportConfigTextEnum,
  15 +} from '../enum';
  16 +import moment from 'moment';
  17 +import { DeviceTypeEnum } from '/@/api/device/model/deviceModel';
  18 +import { getAttribute, screenLinkPageByDeptIdGetDevice } from '/@/api/ruleengine/ruleengineApi';
  19 +import { TSelectOption } from '../type';
  20 +import { AggregateDataEnum } from '/@/views/device/localtion/config.data';
  21 +import { useMessage } from '/@/hooks/web/useMessage';
  22 +
  23 +export const useHooks = () => {
  24 + const { createMessage } = useMessage();
  25 +
  26 + //获取设备
  27 + const getDeviceList = async (organizationId) => {
  28 + const { items } = await screenLinkPageByDeptIdGetDevice({
  29 + organizationId,
  30 + });
  31 + return items?.map((item) => {
  32 + if (item.deviceType !== DeviceTypeEnum.GATEWAY)
  33 + return {
  34 + label: item.alias ? item.alias : item.name,
  35 + value: item.tbDeviceId,
  36 + id: item.id,
  37 + deviceProfileId: item.deviceProfileId,
  38 + };
  39 + });
  40 + };
  41 +
  42 + //获取对应设备属性
  43 + const getDeviceAttr = async (deviceProfileId) => {
  44 + //业务 根据产品id
  45 + if (!deviceProfileId) return;
  46 + const res = await getAttribute(deviceProfileId);
  47 + if (!Array.isArray(res)) return;
  48 + return res.map((items) => {
  49 + const item = ref<TSelectOption>();
  50 + if (items?.identifier !== null) {
  51 + item.value = {
  52 + label: items?.identifier,
  53 + value: items?.identifier,
  54 + };
  55 + return item.value;
  56 + }
  57 + });
  58 + };
  59 +
  60 + //映射查询周期值
  61 + const mapQueryMode = (queryMode) => {
  62 + return queryMode === QueryWay.LATEST ? 0 : 1;
  63 + };
  64 +
  65 + //映射查询周期文本
  66 + const mapQueryModeText = (queryMode) => {
  67 + return queryMode === 0 ? QueryWay.LATEST : QueryWay.TIME_PERIOD;
  68 + };
  69 +
  70 + //要删除的字段,不需要传给服务端
  71 + const removeFields = [
  72 + 'agg',
  73 + 'interval',
  74 + 'queryMode',
  75 + 'startTs',
  76 + 'devices',
  77 + 'dataRange',
  78 + 'cycleType',
  79 + 'currentCycle',
  80 + 'cycleTime',
  81 + 'cronTime',
  82 + 'limit',
  83 + 'dateGroupGap',
  84 + ];
  85 +
  86 + //获取表单部分字段组合成queryCondition和cycle对象和根据cron表达式生成executeContent
  87 + const getQueryCondition = (values) => {
  88 + const {
  89 + agg,
  90 + queryMode,
  91 + startTs,
  92 + interval,
  93 + dateGroupGap,
  94 + cycleType,
  95 + currentCycle,
  96 + cycleTime,
  97 + cronTime,
  98 + limit,
  99 + } = values;
  100 + const startTsValue = ref();
  101 + const endTsValue = ref();
  102 + const intervalValue = ref();
  103 + if (queryMode === QueryWay.LATEST) {
  104 + //业务 查询周期为固定周期
  105 + startTsValue.value = moment().subtract(startTs, 'ms').valueOf();
  106 + endTsValue.value = Date.now();
  107 + intervalValue.value = interval;
  108 + } else {
  109 + //业务 查询周期为自定义周期
  110 + const defineDate = JSON.parse(JSON.stringify(values.dataRange));
  111 + startTsValue.value = moment(defineDate[0]).valueOf();
  112 + endTsValue.value = moment(defineDate[1]).valueOf();
  113 + intervalValue.value = dateGroupGap;
  114 + }
  115 + const executeContent = ref('');
  116 + if (cycleType === CycleTypeEnum.WEEKLY) {
  117 + executeContent.value = cronTime.slice(0, 6) + currentCycle.slice(5);
  118 + } else if (cycleType === CycleTypeEnum.DAILY) {
  119 + executeContent.value = cronTime;
  120 + } else if (cycleType === CycleTypeEnum.MONTHLY) {
  121 + executeContent.value = cronTime.slice(0, 6) + cycleTime.slice(5);
  122 + }
  123 + return [
  124 + {
  125 + limit,
  126 + agg,
  127 + interval: intervalValue.value,
  128 + queryMode: mapQueryMode(queryMode),
  129 + startTs: startTsValue.value,
  130 + endTs: endTsValue.value,
  131 + },
  132 + {
  133 + cycleType,
  134 + currentCycle,
  135 + cycleTime,
  136 + cronTime,
  137 + },
  138 + executeContent.value,
  139 + ];
  140 + };
  141 +
  142 + //新增默认设置部分字段(执行方式,查询周期,最近时间,间隔时间)
  143 + const setDefaultTime = () => {
  144 + return {
  145 + executeWay: BusinessExecutewayEnum.BUSINESS_EXECUTEWAY_IMMEDIATE,
  146 + [SchemaFiled.WAY]: QueryWay.LATEST,
  147 + [SchemaFiled.START_TS]: 1000,
  148 + [SchemaFiled.INTERVAL]: 1000,
  149 + };
  150 + };
  151 +
  152 + //编辑回显queryCondition和cycle对象
  153 + const setQueryCondition = (value, cycle, executeContent) => {
  154 + const conditionObj = ref({});
  155 + //业务 查询周期是固定周期
  156 + if (value?.queryMode === 0) {
  157 + const formatNumber = (value?.endTs - value?.startTs) / 10;
  158 + const transNumber = Math.floor(formatNumber) * 10;
  159 + conditionObj.value = {
  160 + interval: value?.interval,
  161 + startTs: transNumber,
  162 + endTs: value?.endTs,
  163 + };
  164 + } else {
  165 + conditionObj.value = {
  166 + dataRange: [value?.startTs, value?.endTs],
  167 + dateGroupGap: value?.interval,
  168 + };
  169 + }
  170 + const spanDisance = executeContent?.split(' ');
  171 + const cronTime =
  172 + cycle?.cycleType === 2
  173 + ? spanDisance[2] < 10
  174 + ? executeContent.slice(0, 7) + '* * ?'
  175 + : executeContent.slice(0, 7) + ' ' + '* * ?'
  176 + : cycle?.cycleType === 1
  177 + ? spanDisance[2] < 10
  178 + ? executeContent.slice(0, 5) + ' ' + ' * * ?'
  179 + : executeContent.slice(0, 6) + ' ' + ' * * ?'
  180 + : executeContent;
  181 + return {
  182 + ...value,
  183 + ...conditionObj.value,
  184 + ...cycle,
  185 + cronTime,
  186 + queryMode: mapQueryModeText(value?.queryMode),
  187 + };
  188 + };
  189 +
  190 + //业务 回显聚合条件如果数据类型是原始数据则只有空
  191 + const setAggByDateType = (dataType) => {
  192 + const options = ref([]);
  193 + if (dataType === DataTypeEnum.ORIGINAL) {
  194 + options.value = businesAggOptions.filter(
  195 + (item) => item.value === AggregateDataEnum.NONE
  196 + ) as any;
  197 + } else
  198 + options.value = businesAggOptions.filter(
  199 + (item) => item.value !== AggregateDataEnum.NONE
  200 + ) as any;
  201 + return {
  202 + field: SchemaFiled.AGG,
  203 + componentProps: {
  204 + options: options.value,
  205 + },
  206 + };
  207 + };
  208 +
  209 + //业务 执行方式为定时执行 查询周期只有固定周期
  210 + const disableCustomWeekly = (type) => {
  211 + const options = ref([]);
  212 + if (type === BusinessExecutewayEnum.BUSINESS_EXECUTEWAY_SCHEDULED) {
  213 + options.value = businesWayOptions.filter((item) => item.value === QueryWay.LATEST) as any;
  214 + } else {
  215 + options.value = businesWayOptions as any;
  216 + }
  217 + return {
  218 + field: SchemaFiled.WAY,
  219 + componentProps: {
  220 + options: options.value,
  221 + },
  222 + };
  223 + };
  224 +
  225 + //Modal弹窗属性
  226 + const setPropsForModal = (text) => {
  227 + return {
  228 + loading: true,
  229 + title: text,
  230 + showOkBtn: text !== BusinessReportConfigTextEnum.BUSINESS_VIEW_TEXT,
  231 + showCancelBtn: text !== BusinessReportConfigTextEnum.BUSINESS_VIEW_TEXT,
  232 + };
  233 + };
  234 +
  235 + //验证设备以及所选属性
  236 + const validateSelectDevice = (values) => {
  237 + const throwErrorMsg = () => {
  238 + createMessage.error('请选择设备及其属性');
  239 + throw new Error('请选择设备及其属性');
  240 + };
  241 + if (Array.isArray(values) && values.length === 0) throwErrorMsg();
  242 + else {
  243 + values.forEach((f) => {
  244 + if (!f.attributes || f.attributes.length == 0) throwErrorMsg();
  245 + });
  246 + }
  247 + };
  248 +
  249 + return {
  250 + getDeviceList,
  251 + getQueryCondition,
  252 + removeFields,
  253 + setDefaultTime,
  254 + getDeviceAttr,
  255 + setQueryCondition,
  256 + setAggByDateType,
  257 + disableCustomWeekly,
  258 + setPropsForModal,
  259 + validateSelectDevice,
  260 + };
  261 +};
1 <template> 1 <template>
2 <div> 2 <div>
3 - <BasicTable :clickToRowSelect="false" @register="registerTable" :searchInfo="searchInfo"> 3 + <BasicTable :clickToRowSelect="false" @register="registerTable">
4 <template #toolbar> 4 <template #toolbar>
5 - <Authority value="api:yt:report_form:config:post">  
6 - <a-button type="primary" @click="handleCreateOrEdit(null)"> 新增报表 </a-button> 5 + <Authority :value="PermissionReportConfigEnum.PERMISSION_POST">
  6 + <a-button
  7 + type="primary"
  8 + @click="handleBussinessDrawer(BusinessReportConfigTextEnum.BUSINESS_ADD_TEXT, null)"
  9 + >
  10 + {{ BusinessReportConfigTextEnum.BUSINESS_ADD_TEXT }}
  11 + </a-button>
7 </Authority> 12 </Authority>
8 - <Authority value="api:yt:report:get">  
9 - <a-button type="primary" @click="go('/report/export')"> 下载报表 </a-button> 13 + <Authority :value="PermissionReportConfigEnum.PERMISSION_GET">
  14 + <a-button type="primary" @click="go('/report/export')">
  15 + {{ BusinessReportConfigTextEnum.BUSINESS_EXPORT_TEXT }}
  16 + </a-button>
10 </Authority> 17 </Authority>
11 - <Authority value="api:yt:report_form:config:delete"> 18 + <Authority :value="PermissionReportConfigEnum.PERMISSION_DELETE">
12 <Popconfirm 19 <Popconfirm
13 title="您确定要批量删除数据" 20 title="您确定要批量删除数据"
14 ok-text="确定" 21 ok-text="确定"
15 cancel-text="取消" 22 cancel-text="取消"
16 @confirm="handleDeleteOrBatchDelete(null)" 23 @confirm="handleDeleteOrBatchDelete(null)"
17 > 24 >
18 - <a-button type="primary" color="error" :disabled="hasBatchDelete"> 批量删除 </a-button> 25 + <a-button type="primary" color="error" :disabled="hasBatchDelete">
  26 + {{ BusinessReportConfigTextEnum.BUSINESS_DELETE_TEXT }}
  27 + </a-button>
19 </Popconfirm> 28 </Popconfirm>
20 </Authority> 29 </Authority>
21 </template> 30 </template>
22 <template #doDeviceSlot="{ record }"> 31 <template #doDeviceSlot="{ record }">
23 <a-button type="text" @click="handleDeviceView(record)"> 32 <a-button type="text" @click="handleDeviceView(record)">
24 - <span style="color: #377dff">查看设备</span> 33 + <span style="color: #377dff">{{
  34 + BusinessReportConfigTextEnum.BUSINESS_VIEW_DEVICE_TEXT
  35 + }}</span>
25 </a-button> 36 </a-button>
26 </template> 37 </template>
27 <template #action="{ record }"> 38 <template #action="{ record }">
28 <TableAction 39 <TableAction
29 :actions="[ 40 :actions="[
30 { 41 {
31 - label: '查看', 42 + label: BusinessReportConfigTextEnum.BUSINESS_VIEW_TEXT.slice(0, 2),
32 icon: 'ant-design:eye-outlined', 43 icon: 'ant-design:eye-outlined',
33 - onClick: handleViewDetail.bind(null, record), 44 + onClick: handleBussinessDrawer.bind(
  45 + null,
  46 + BusinessReportConfigTextEnum.BUSINESS_VIEW_TEXT,
  47 + record
  48 + ),
34 ifShow: record.status === 1, 49 ifShow: record.status === 1,
35 }, 50 },
36 { 51 {
37 - label: '编辑', 52 + label: BusinessReportConfigTextEnum.BUSINESS_UPDATE_TEXT.slice(0, 2),
38 icon: 'clarity:note-edit-line', 53 icon: 'clarity:note-edit-line',
39 - auth: 'api:yt:report_form:config:update',  
40 - onClick: handleCreateOrEdit.bind(null, record), 54 + auth: PermissionReportConfigEnum.PERMISSION_UPDATE,
  55 + onClick: handleBussinessDrawer.bind(
  56 + null,
  57 + BusinessReportConfigTextEnum.BUSINESS_UPDATE_TEXT,
  58 + record
  59 + ),
41 ifShow: record.status === 0, 60 ifShow: record.status === 0,
42 }, 61 },
43 { 62 {
44 - label: '删除', 63 + label: BusinessReportConfigTextEnum.BUSINESS_DELETE_TEXT.slice(2),
45 icon: 'ant-design:delete-outlined', 64 icon: 'ant-design:delete-outlined',
46 - auth: 'api:yt:report_form:config:delete', 65 + auth: PermissionReportConfigEnum.PERMISSION_DELETE,
47 color: 'error', 66 color: 'error',
48 ifShow: record.status === 0, 67 ifShow: record.status === 0,
49 popConfirm: { 68 popConfirm: {
@@ -59,8 +78,8 @@ @@ -59,8 +78,8 @@
59 :disabled="disabledSwitch" 78 :disabled="disabledSwitch"
60 :checked="record.status === 1" 79 :checked="record.status === 1"
61 :loading="record.pendingStatus" 80 :loading="record.pendingStatus"
62 - checkedChildren="启用"  
63 - unCheckedChildren="禁用" 81 + :checkedChildren="BusinessReportConfigTextEnum.BUSINESS_ENABLE_TEXT"
  82 + :unCheckedChildren="BusinessReportConfigTextEnum.BUSINESS_DISABLE_TEXT"
64 @change="(checked: boolean) => statusChange(checked, record)" 83 @change="(checked: boolean) => statusChange(checked, record)"
65 /> 84 />
66 </template> 85 </template>
@@ -71,130 +90,96 @@ @@ -71,130 +90,96 @@
71 </template> 90 </template>
72 91
73 <script lang="ts" setup> 92 <script lang="ts" setup>
74 - import { reactive, nextTick, ref } from 'vue'; 93 + import { nextTick, ref } from 'vue';
75 import { BasicTable, useTable, TableAction } from '/@/components/Table'; 94 import { BasicTable, useTable, TableAction } from '/@/components/Table';
76 import { useDrawer } from '/@/components/Drawer'; 95 import { useDrawer } from '/@/components/Drawer';
77 - import ReportConfigDrawer from './ReportConfigDrawer.vue';  
78 - import DevicePreviewModal from './DevicePreviewModal.vue';  
79 import { 96 import {
80 reportPage, 97 reportPage,
81 deleteReportManage, 98 deleteReportManage,
82 putReportByidAndStatusManage, 99 putReportByidAndStatusManage,
83 } from '/@/api/report/reportManager'; 100 } from '/@/api/report/reportManager';
84 - import { searchFormSchema, columns } from './config.data'; 101 + import { defaultTableAttribtes } from './config';
85 import { Authority } from '/@/components/Authority'; 102 import { Authority } from '/@/components/Authority';
86 import { useBatchDelete } from '/@/hooks/web/useBatchDelete'; 103 import { useBatchDelete } from '/@/hooks/web/useBatchDelete';
87 import { Popconfirm, Switch } from 'ant-design-vue'; 104 import { Popconfirm, Switch } from 'ant-design-vue';
88 import { useModal } from '/@/components/Modal'; 105 import { useModal } from '/@/components/Modal';
89 import { useGo } from '/@/hooks/web/usePage'; 106 import { useGo } from '/@/hooks/web/usePage';
90 import { useMessage } from '/@/hooks/web/useMessage'; 107 import { useMessage } from '/@/hooks/web/useMessage';
  108 + import { ReportConfigDrawer, DevicePreviewModal } from './components';
  109 + import {
  110 + PermissionReportConfigEnum,
  111 + BusinessReportConfigTextEnum,
  112 + BusinessReportConfigStatusEnum,
  113 + } from './enum';
91 114
92 - const searchInfo = reactive<Recordable>({});  
93 const disabledSwitch = ref(false); 115 const disabledSwitch = ref(false);
94 116
95 const [registerTable, { reload, setProps, setSelectedRowKeys }] = useTable({ 117 const [registerTable, { reload, setProps, setSelectedRowKeys }] = useTable({
96 - title: '报表列表',  
97 api: reportPage, 118 api: reportPage,
98 - columns,  
99 - showIndexColumn: false,  
100 - clickToRowSelect: false,  
101 - formConfig: {  
102 - labelWidth: 120,  
103 - schemas: searchFormSchema,  
104 - fieldMapToTime: [['sendTime', ['startTime', 'endTime'], 'x']],  
105 - },  
106 - useSearchForm: true,  
107 - showTableSetting: true,  
108 - bordered: true,  
109 - rowKey: 'id',  
110 - actionColumn: {  
111 - width: 200,  
112 - title: '操作',  
113 - dataIndex: 'action',  
114 - slots: { customRender: 'action' },  
115 - fixed: 'right',  
116 - }, 119 + ...defaultTableAttribtes,
117 }); 120 });
118 121
119 - // 弹框 122 + // 业务弹窗
120 const [registerDrawer, { openDrawer }] = useDrawer(); 123 const [registerDrawer, { openDrawer }] = useDrawer();
  124 +
121 const { createMessage } = useMessage(); 125 const { createMessage } = useMessage();
122 126
123 - // 刷新  
124 const handleSuccess = () => { 127 const handleSuccess = () => {
125 reload(); 128 reload();
126 }; 129 };
127 130
128 const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions, resetSelectedRowKeys } = 131 const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions, resetSelectedRowKeys } =
129 - useBatchDelete(deleteReportManage, handleSuccess, setProps); 132 + useBatchDelete(deleteReportManage, handleSuccess, setProps) as any;
130 selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => { 133 selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => {
131 - // Demo:status为1的选择框禁用  
132 - if (record.status === 1) { 134 + //业务 status为1 选择框则禁用
  135 + if (record.status === BusinessReportConfigStatusEnum.BUSINESS_DISABLE)
133 return { disabled: true }; 136 return { disabled: true };
134 - } else {  
135 - return { disabled: false };  
136 - } 137 + else return { disabled: false };
137 }; 138 };
138 139
139 nextTick(() => { 140 nextTick(() => {
140 setProps(selectionOptions); 141 setProps(selectionOptions);
141 }); 142 });
142 143
143 - // 新增或编辑  
144 - const handleCreateOrEdit = (record: Recordable | null) => {  
145 - if (record) {  
146 - openDrawer(true, {  
147 - isUpdate: true,  
148 - record,  
149 - isView: true,  
150 - });  
151 - } else {  
152 - openDrawer(true, {  
153 - isUpdate: false,  
154 - isView: true,  
155 - });  
156 - }  
157 - };  
158 - const handleViewDetail = (record: Recordable) => {  
159 - if (record) {  
160 - openDrawer(true, {  
161 - isUpdate: true,  
162 - record,  
163 - isView: false,  
164 - });  
165 - } 144 + // 业务弹窗
  145 + const handleBussinessDrawer = (text, record) => {
  146 + const modalParams = {
  147 + text,
  148 + record,
  149 + };
  150 + openDrawer(true, modalParams);
166 }; 151 };
167 152
168 //查看设备 153 //查看设备
169 const [registerModal, { openModal }] = useModal(); 154 const [registerModal, { openModal }] = useModal();
  155 +
170 const handleDeviceView = (record) => { 156 const handleDeviceView = (record) => {
171 openModal(true, { 157 openModal(true, {
172 isUpdate: true, 158 isUpdate: true,
173 record, 159 record,
174 }); 160 });
175 }; 161 };
  162 +
  163 + const setPropsLoading = (loading) => {
  164 + setProps({
  165 + loading,
  166 + });
  167 + setSelectedRowKeys([]);
  168 + resetSelectedRowKeys();
  169 + };
  170 +
176 const statusChange = async (checked, record) => { 171 const statusChange = async (checked, record) => {
177 try { 172 try {
178 - setProps({  
179 - loading: true,  
180 - });  
181 - setSelectedRowKeys([]);  
182 - resetSelectedRowKeys(); 173 + setPropsLoading(true);
183 disabledSwitch.value = true; 174 disabledSwitch.value = true;
184 const newStatus = checked ? 1 : 0; 175 const newStatus = checked ? 1 : 0;
185 const res = await putReportByidAndStatusManage(record.id, newStatus); 176 const res = await putReportByidAndStatusManage(record.id, newStatus);
186 - if (res && newStatus) {  
187 - createMessage.success(`启用成功`);  
188 - } else {  
189 - createMessage.success('禁用成功');  
190 - } 177 + if (res && newStatus)
  178 + createMessage.success(`${BusinessReportConfigTextEnum.BUSINESS_ENABLE_TEXT}成功`);
  179 + else createMessage.success(`${BusinessReportConfigTextEnum.BUSINESS_DISABLE_TEXT}成功`);
191 } finally { 180 } finally {
192 - setTimeout(() => {  
193 - setProps({  
194 - loading: false,  
195 - });  
196 - disabledSwitch.value = false;  
197 - }, 500); 181 + setPropsLoading(false);
  182 + disabledSwitch.value = false;
198 reload(); 183 reload();
199 } 184 }
200 }; 185 };
1 -interface IOptionConfig {  
2 - label: string;  
3 - value: number;  
4 -}  
5 -  
6 -export const optionsConfig: IOptionConfig[] = [  
7 - {  
8 - label: '1秒',  
9 - value: 1000,  
10 - },  
11 - {  
12 - label: '5秒',  
13 - value: 5000,  
14 - },  
15 - {  
16 - label: '10秒',  
17 - value: 10000,  
18 - },  
19 - {  
20 - label: '15秒',  
21 - value: 15000,  
22 - },  
23 - {  
24 - label: '30秒',  
25 - value: 30000,  
26 - },  
27 - {  
28 - label: '1分钟',  
29 - value: 60000,  
30 - },  
31 - {  
32 - label: '2分钟',  
33 - value: 120000,  
34 - },  
35 - {  
36 - label: '5分钟',  
37 - value: 300000,  
38 - },  
39 - {  
40 - label: '10分钟',  
41 - value: 600000,  
42 - },  
43 - {  
44 - label: '15分钟',  
45 - value: 900000,  
46 - },  
47 - {  
48 - label: '30分钟',  
49 - value: 1800000,  
50 - },  
51 - {  
52 - label: '1小时',  
53 - value: 3600000,  
54 - },  
55 - {  
56 - label: '2小时',  
57 - value: 7200000,  
58 - },  
59 - {  
60 - label: '5小时',  
61 - value: 18000000,  
62 - },  
63 - {  
64 - label: '10小时',  
65 - value: 36000000,  
66 - },  
67 - {  
68 - label: '12小时',  
69 - value: 43200000,  
70 - },  
71 - {  
72 - label: '1天',  
73 - value: 86400000,  
74 - },  
75 -];  
76 -  
77 -export enum TypeEnum {  
78 - IS_TIMING = 1,  
79 - IS_WEEK = 1,  
80 - IS_MONTH = 2,  
81 - IS_EMPTY = 'NONE',  
82 - IS_DEFAULT_WEEK = 'defaultIsWeek',  
83 - IS_FIXED_WEEK = '2',  
84 - IS_MIN = 'MIN',  
85 - IS_MAX = 'MAX',  
86 - IS_AVG = 'AVG',  
87 - IS_SUM = 'SUM',  
88 - COUNT = 'COUNT',  
89 - IS_FIXED_TIME = 1,  
90 -}  
91 -  
92 -export enum AggregateDataEnum {  
93 - MIN = 'MIN',  
94 - MAX = 'MAX',  
95 - AVG = 'AVG',  
96 - SUM = 'SUM',  
97 - COUNT = 'COUNT',  
98 - NONE = 'NONE',  
99 -}  
100 -export const isFixedTime = (type: string) => {  
101 - return type === TypeEnum.IS_FIXED_TIME;  
102 -};  
103 -  
104 -export const isTiming = (type: string) => {  
105 - return type === TypeEnum.IS_TIMING;  
106 -};  
107 -  
108 -export const isWeek = (type: string) => {  
109 - return type === TypeEnum.IS_WEEK;  
110 -};  
111 -  
112 -export const isMonth = (type: string) => {  
113 - return type === TypeEnum.IS_MONTH;  
114 -};  
115 -  
116 -export const isEmpty = (type: string) => {  
117 - return type === TypeEnum.IS_EMPTY;  
118 -};  
119 -  
120 -export const isDefultWeek = (type: string) => {  
121 - return type === TypeEnum.IS_DEFAULT_WEEK;  
122 -};  
123 -export const isFixedWeek = (type: string) => {  
124 - return type === TypeEnum.IS_FIXED_WEEK;  
125 -};  
126 -  
127 -export const isMin = (type: string) => {  
128 - return type === TypeEnum.IS_MIN;  
129 -};  
130 -  
131 -export const isMax = (type: string) => {  
132 - return type === TypeEnum.IS_MAX;  
133 -};  
134 -  
135 -export const isAvg = (type: string) => {  
136 - return type === TypeEnum.IS_AVG;  
137 -};  
138 -export const isSum = (type: string) => {  
139 - return type === TypeEnum.IS_SUM;  
140 -};  
141 -  
142 -export const isCountAll = (type: string) => {  
143 - return type === TypeEnum.COUNT;  
144 -};  
  1 +/**
  2 + * 报表配置相关类型定义
  3 + */
  4 +
  5 +//设备列表类型定义
  6 +export type TDeviceList = {
  7 + key?: string;
  8 + value?: string;
  9 + label?: string;
  10 + attribute?: string;
  11 + device?: string;
  12 + name?: string;
  13 + attributes?: string | undefined;
  14 + deviceProfileId?: string;
  15 + id?: string;
  16 +};
  17 +
  18 +//设备下拉框类型定义
  19 +export type TSelectOption = {
  20 + label: string;
  21 + value: string;
  22 + deviceProfileId?: string;
  23 + id?: string;
  24 +};
  25 +
  26 +//设备属性
  27 +export interface Params {
  28 + [x: string]: string;
  29 + attributes: any;
  30 + device: string;
  31 +}
1 -.wrapper {  
2 - margin: 10px 60px 60px 60px;  
3 -}  
4 -  
5 -.inner {  
6 - width: 400px;  
7 - height: 400px;  
8 -}  
9 -  
10 -.item {  
11 - text-align: center;  
12 - font-size: 200%;  
13 - color: #fff;  
14 -}  
src/views/report/export/components/ReportPreviewModal.vue renamed from src/views/report/export/ReportPreviewModal.vue
@@ -306,7 +306,20 @@ @@ -306,7 +306,20 @@
306 }); 306 });
307 </script> 307 </script>
308 <style lang="less" scoped> 308 <style lang="less" scoped>
309 - @import url('./ReportPreviewModal.less'); 309 + .wrapper {
  310 + margin: 10px 60px 60px 60px;
  311 + }
  312 +
  313 + .inner {
  314 + width: 400px;
  315 + height: 400px;
  316 + }
  317 +
  318 + .item {
  319 + text-align: center;
  320 + font-size: 200%;
  321 + color: #fff;
  322 + }
310 323
311 .chart-style { 324 .chart-style {
312 display: flex; 325 display: flex;
  1 +import ReportPreviewModal from './ReportPreviewModal.vue';
  2 +
  3 +export { ReportPreviewModal };
src/views/report/export/config.ts renamed from src/views/report/export/config.data.ts
1 -import { BasicColumn, FormSchema } from '/@/components/Table'; 1 +import { BasicColumn, BasicTableProps, FormSchema } from '/@/components/Table';
2 import moment from 'moment'; 2 import moment from 'moment';
3 import { h } from 'vue'; 3 import { h } from 'vue';
4 import { Tag } from 'ant-design-vue'; 4 import { Tag } from 'ant-design-vue';
  5 +import { DataTypeNameEnum, ExecuteWayNameEnum } from '../config/enum';
5 6
6 // 表格配置 7 // 表格配置
7 export const columns: BasicColumn[] = [ 8 export const columns: BasicColumn[] = [
@@ -20,7 +21,7 @@ export const columns: BasicColumn[] = [ @@ -20,7 +21,7 @@ export const columns: BasicColumn[] = [
20 dataIndex: 'dataType', 21 dataIndex: 'dataType',
21 width: 120, 22 width: 120,
22 format: (_text: string, record: Recordable) => { 23 format: (_text: string, record: Recordable) => {
23 - return record.dataCompare === 0 ? '原始数据' : '聚合数据'; 24 + return record.dataCompare === 0 ? DataTypeNameEnum.ORIGINAL : DataTypeNameEnum.AGG;
24 }, 25 },
25 }, 26 },
26 { 27 {
@@ -28,7 +29,9 @@ export const columns: BasicColumn[] = [ @@ -28,7 +29,9 @@ export const columns: BasicColumn[] = [
28 dataIndex: 'executeWay', 29 dataIndex: 'executeWay',
29 width: 120, 30 width: 120,
30 format: (_text: string, record: Recordable) => { 31 format: (_text: string, record: Recordable) => {
31 - return record.executeWay === 0 ? '立即执行' : '定时执行'; 32 + return record.executeWay === 0
  33 + ? ExecuteWayNameEnum.EXECUTEWAY_IMMEDIATE
  34 + : ExecuteWayNameEnum.EXECUTEWAY_SCHEDULED;
32 }, 35 },
33 }, 36 },
34 { 37 {
@@ -49,7 +52,7 @@ export const columns: BasicColumn[] = [ @@ -49,7 +52,7 @@ export const columns: BasicColumn[] = [
49 }, 52 },
50 ]; 53 ];
51 54
52 -// 查询配置 55 +// 表格查询配置
53 export const searchFormSchema: FormSchema[] = [ 56 export const searchFormSchema: FormSchema[] = [
54 { 57 {
55 field: 'reportConfigName', 58 field: 'reportConfigName',
@@ -96,3 +99,27 @@ export const searchFormSchema: FormSchema[] = [ @@ -96,3 +99,27 @@ export const searchFormSchema: FormSchema[] = [
96 colProps: { span: 6 }, 99 colProps: { span: 6 },
97 }, 100 },
98 ]; 101 ];
  102 +
  103 +//表格通用属性配置
  104 +export const defaultTableAttribtes: BasicTableProps = {
  105 + title: '报表导出列表',
  106 + columns,
  107 + showIndexColumn: false,
  108 + clickToRowSelect: false,
  109 + formConfig: {
  110 + labelWidth: 120,
  111 + schemas: searchFormSchema,
  112 + fieldMapToTime: [['sendTime', ['startTime', 'endTime'], 'x']],
  113 + },
  114 + useSearchForm: true,
  115 + showTableSetting: true,
  116 + bordered: true,
  117 + rowKey: 'id',
  118 + actionColumn: {
  119 + width: 200,
  120 + title: '操作',
  121 + dataIndex: 'action',
  122 + slots: { customRender: 'action' },
  123 + fixed: 'right',
  124 + },
  125 +};
  1 +/**
  2 + * 报表导出相关枚举值定义
  3 + */
  4 +
  5 +//业务权限配置枚举
  6 +export enum PermissionReportExportEnum {
  7 + PERMISSION_GET = 'api:yt:reportExport:get',
  8 + PERMISSION_EXPORT = 'api:yt:reportExport:export',
  9 + PERMISSION_DELETE = 'api:yt:report:generate:record:delete',
  10 +}
  11 +
  12 +//业务文字描述配置枚举
  13 +export enum BusinessReportExportTextEnum {
  14 + BUSINESS_EXPORT_TEXT = '报表导出',
  15 + BUSINESS_DELETE_TEXT = '批量删除',
  16 + BUSINESS_VIEW_TEXT = '报表查看',
  17 +}
1 <template> 1 <template>
2 <div> 2 <div>
3 - <BasicTable :clickToRowSelect="false" @register="registerTable" :searchInfo="searchInfo"> 3 + <BasicTable :clickToRowSelect="false" @register="registerTable">
4 <template #toolbar> 4 <template #toolbar>
5 - <Authority value="api:yt:report:generate:record:delete"> 5 + <Authority :value="PermissionReportExportEnum.PERMISSION_DELETE">
6 <Popconfirm 6 <Popconfirm
7 title="您确定要批量删除数据" 7 title="您确定要批量删除数据"
8 ok-text="确定" 8 ok-text="确定"
9 cancel-text="取消" 9 cancel-text="取消"
10 @confirm="handleDeleteOrBatchDelete(null)" 10 @confirm="handleDeleteOrBatchDelete(null)"
11 > 11 >
12 - <a-button type="primary" color="error" :disabled="hasBatchDelete"> 批量删除 </a-button> 12 + <a-button type="primary" color="error" :disabled="hasBatchDelete">
  13 + {{ BusinessReportExportTextEnum.BUSINESS_DELETE_TEXT }}
  14 + </a-button>
13 </Popconfirm> 15 </Popconfirm>
14 </Authority> 16 </Authority>
15 </template> 17 </template>
@@ -17,9 +19,9 @@ @@ -17,9 +19,9 @@
17 <TableAction 19 <TableAction
18 :actions="[ 20 :actions="[
19 { 21 {
20 - label: '报表导出', 22 + label: BusinessReportExportTextEnum.BUSINESS_EXPORT_TEXT,
21 icon: 'ant-design:dot-chart-outlined', 23 icon: 'ant-design:dot-chart-outlined',
22 - auth: 'api:yt:reportExport:export', 24 + auth: PermissionReportExportEnum.PERMISSION_EXPORT,
23 ifShow: record.executeStatus === 1, 25 ifShow: record.executeStatus === 1,
24 popConfirm: { 26 popConfirm: {
25 title: '是否需要导出', 27 title: '是否需要导出',
@@ -27,15 +29,15 @@ @@ -27,15 +29,15 @@
27 }, 29 },
28 }, 30 },
29 { 31 {
30 - label: '报表查看', 32 + label: BusinessReportExportTextEnum.BUSINESS_VIEW_TEXT,
31 icon: 'clarity:note-edit-line', 33 icon: 'clarity:note-edit-line',
32 - auth: 'api:yt:reportExport:get', 34 + auth: PermissionReportExportEnum.PERMISSION_GET,
33 onClick: handleView.bind(null, record), 35 onClick: handleView.bind(null, record),
34 }, 36 },
35 { 37 {
36 - label: '删除', 38 + label: BusinessReportExportTextEnum.BUSINESS_DELETE_TEXT.slice(2),
37 icon: 'ant-design:delete-outlined', 39 icon: 'ant-design:delete-outlined',
38 - auth: 'api:yt:report:generate:record:delete', 40 + auth: PermissionReportExportEnum.PERMISSION_DELETE,
39 color: 'error', 41 color: 'error',
40 popConfirm: { 42 popConfirm: {
41 title: '是否确认删除', 43 title: '是否确认删除',
@@ -51,40 +53,21 @@ @@ -51,40 +53,21 @@
51 </template> 53 </template>
52 54
53 <script lang="ts" setup> 55 <script lang="ts" setup>
54 - import { reactive, nextTick } from 'vue'; 56 + import { nextTick } from 'vue';
55 import { BasicTable, useTable, TableAction } from '/@/components/Table'; 57 import { BasicTable, useTable, TableAction } from '/@/components/Table';
56 - import { searchFormSchema, columns } from './config.data'; 58 + import { defaultTableAttribtes } from './config';
57 import { Authority } from '/@/components/Authority'; 59 import { Authority } from '/@/components/Authority';
58 import { useBatchDelete } from '/@/hooks/web/useBatchDelete'; 60 import { useBatchDelete } from '/@/hooks/web/useBatchDelete';
59 import { Popconfirm } from 'ant-design-vue'; 61 import { Popconfirm } from 'ant-design-vue';
60 import { useModal } from '/@/components/Modal'; 62 import { useModal } from '/@/components/Modal';
61 - import ReportPreviewModal from './ReportPreviewModal.vue'; 63 + import { ReportPreviewModal } from './components';
62 import { exportPage, deleteExportManage } from '/@/api/export/exportManager'; 64 import { exportPage, deleteExportManage } from '/@/api/export/exportManager';
63 import { downloadByUrl } from '/@/utils/file/download'; 65 import { downloadByUrl } from '/@/utils/file/download';
  66 + import { PermissionReportExportEnum, BusinessReportExportTextEnum } from './enum';
64 67
65 - const searchInfo = reactive<Recordable>({});  
66 const [registerTable, { reload, setProps }] = useTable({ 68 const [registerTable, { reload, setProps }] = useTable({
67 - title: '报表导出列表',  
68 api: exportPage, 69 api: exportPage,
69 - columns,  
70 - showIndexColumn: false,  
71 - clickToRowSelect: false,  
72 - formConfig: {  
73 - labelWidth: 120,  
74 - schemas: searchFormSchema,  
75 - fieldMapToTime: [['sendTime', ['startTime', 'endTime'], 'x']],  
76 - },  
77 - useSearchForm: true,  
78 - showTableSetting: true,  
79 - bordered: true,  
80 - rowKey: 'id',  
81 - actionColumn: {  
82 - width: 200,  
83 - title: '操作',  
84 - dataIndex: 'action',  
85 - slots: { customRender: 'action' },  
86 - fixed: 'right',  
87 - }, 70 + ...defaultTableAttribtes,
88 }); 71 });
89 72
90 const handleSuccess = () => { 73 const handleSuccess = () => {
@@ -101,19 +84,23 @@ @@ -101,19 +84,23 @@
101 setProps(selectionOptions); 84 setProps(selectionOptions);
102 }); 85 });
103 86
  87 + //业务弹窗
104 const [registerModal, { openModal }] = useModal(); 88 const [registerModal, { openModal }] = useModal();
  89 +
105 const handleView = (record) => { 90 const handleView = (record) => {
106 openModal(true, { 91 openModal(true, {
107 isUpdate: true, 92 isUpdate: true,
108 record, 93 record,
109 }); 94 });
110 }; 95 };
  96 +
111 const exportUrlsFunc = (fUrl) => { 97 const exportUrlsFunc = (fUrl) => {
112 const options: any = { 98 const options: any = {
113 url: fUrl, 99 url: fUrl,
114 }; 100 };
115 downloadByUrl(options); 101 downloadByUrl(options);
116 }; 102 };
  103 +
117 const handleExport = (record) => { 104 const handleExport = (record) => {
118 if (record.reportPath) { 105 if (record.reportPath) {
119 const urls = record.reportPath.split(','); 106 const urls = record.reportPath.split(',');
1 -.wrapper {  
2 - margin: 10px 60px 60px 60px;  
3 -}  
4 -  
5 -.inner {  
6 - width: 400px;  
7 - height: 400px;  
8 -}  
9 -  
10 -.item {  
11 - text-align: center;  
12 - font-size: 200%;  
13 - color: #fff;  
14 -}  
1 -<template>  
2 - <div>  
3 - <BasicModal  
4 - destroyOnClose  
5 - v-bind="$attrs"  
6 - width="60rem"  
7 - @register="register"  
8 - :title="getTitle"  
9 - :minHeight="500"  
10 - @cancel="handleCancel"  
11 - @ok="handleSubmit"  
12 - >  
13 - <ConverScript  
14 - :view="isViewDetail"  
15 - :text="isTitle"  
16 - :ifAdd="isTest ? false : true"  
17 - ref="converScriptRef"  
18 - />  
19 - </BasicModal>  
20 - </div>  
21 -</template>  
22 -<script setup lang="ts">  
23 - import { ref, computed, unref, reactive } from 'vue';  
24 - import { BasicModal, useModalInner } from '/@/components/Modal';  
25 - import ConverScript from './ConverScript.vue';  
26 - import {  
27 - createOrEditScriptManage,  
28 - getScriptManageDetail,  
29 - testScriptManage,  
30 - } from '/@/api/scriptmanage/scriptManager';  
31 - import { useMessage } from '/@/hooks/web/useMessage';  
32 -  
33 - const emits = defineEmits(['success', 'register']);  
34 - const { createMessage } = useMessage();  
35 - const converScriptRef = ref<InstanceType<typeof ConverScript>>();  
36 - const getTitle = computed(() => (isUpdate.value ? '编辑转换脚本' : '新增转换脚本'));  
37 - const isUpdate = ref(false);  
38 - const isViewDetail = ref('');  
39 - const isTest = ref(false);  
40 - const isText = ref('');  
41 - const isTitle = ref('');  
42 - const editData = reactive({  
43 - data: {},  
44 - });  
45 - const [register, { setModalProps, closeModal }] = useModalInner(async (data) => {  
46 - setModalProps({ loading: true });  
47 - handleCancel(false);  
48 - isUpdate.value = data.isUpdate;  
49 - isViewDetail.value = data.isView;  
50 - isTest.value = data.isTest;  
51 - isText.value = data.isText;  
52 - isTitle.value = data.isTitle;  
53 - editData.data = data.record;  
54 - setModalProps({ loading: false });  
55 - converScriptRef.value?.initEditor();  
56 - if (!unref(isViewDetail)) {  
57 - const title =  
58 - unref(isTitle) == 'edit'  
59 - ? '编辑转换脚本'  
60 - : unref(isTitle) == 'add'  
61 - ? '新增转换脚本'  
62 - : '测试转换脚本';  
63 - const okText = isText.value == 'test' ? '测试' : '确定';  
64 - if (unref(isTitle) == 'add') {  
65 - converScriptRef.value?.setDefaultRadio('TRANSPORT_TCP_UP');  
66 - }  
67 - if (unref(isTitle) == 'edit') {  
68 - converScriptRef.value?.setFormData(data.record);  
69 - }  
70 - if (unref(isTitle) == 'test') {  
71 - if (data.record) {  
72 - const res = await getScriptManageDetail(data.record);  
73 - converScriptRef.value?.setFormData(res);  
74 - } else {  
75 - converScriptRef.value?.setDefaultRadio('TRANSPORT_TCP_UP');  
76 - }  
77 - }  
78 - setModalProps({ title, showOkBtn: true, showCancelBtn: true, okText });  
79 - if (!unref(isUpdate)) {  
80 - }  
81 - } else {  
82 - setModalProps({ showOkBtn: false, showCancelBtn: false, title: '查看转换脚本' });  
83 - const res = await getScriptManageDetail(data.record.id);  
84 - converScriptRef.value?.setFormData(res || {});  
85 - }  
86 - });  
87 -  
88 - const handleSubmit = async () => {  
89 - setModalProps({ confirmLoading: true });  
90 - try {  
91 - const val = await converScriptRef.value?.getFormData();  
92 - const tempObj = {  
93 - ...editData.data,  
94 - ...val,  
95 - };  
96 - const res: any =  
97 - isText.value == 'test'  
98 - ? await testScriptManage(val)  
99 - : await createOrEditScriptManage(tempObj);  
100 - createMessage.success(  
101 - unref(isTitle) == 'edit'  
102 - ? '编辑转换脚本成功'  
103 - : unref(isTitle) == 'add'  
104 - ? '新增转换脚本成功'  
105 - : '测试转换脚本成功'  
106 - );  
107 - if (unref(isTitle) == 'add' || unref(isTitle) == 'edit') {  
108 - setTimeout(() => {  
109 - closeModal();  
110 - }, 10);  
111 - emits('success', {  
112 - res,  
113 - text: isText.value,  
114 - });  
115 - } else {  
116 - if (res) {  
117 - converScriptRef.value?.setScriptOutputData(res?.output || res?.error);  
118 - }  
119 - }  
120 - } finally {  
121 - setModalProps({ confirmLoading: false });  
122 - }  
123 - };  
124 - const handleCancel = (flag) => {  
125 - if (flag) {  
126 - closeModal();  
127 - }  
128 - converScriptRef.value?.resetFormData();  
129 - };  
130 -</script>  
131 -<style lang="less" scoped>  
132 - @import url('./ConverScriptModal.less');  
133 -</style>  
1 -<template>  
2 - <div>  
3 - <BasicModal  
4 - destroyOnClose  
5 - v-bind="$attrs"  
6 - width="60rem"  
7 - @register="register"  
8 - :title="getTitle"  
9 - :minHeight="500"  
10 - @cancel="handleCancel"  
11 - @ok="handleSubmit"  
12 - >  
13 - <ConverScript  
14 - :view="isViewDetail"  
15 - :text="isTitle"  
16 - :ifAdd="isTest ? false : true"  
17 - ref="converScriptRef"  
18 - />  
19 - </BasicModal>  
20 - </div>  
21 -</template>  
22 -<script setup lang="ts">  
23 - import { ref, computed, unref, reactive } from 'vue';  
24 - import { BasicModal, useModalInner } from '/@/components/Modal';  
25 - import ConverScript from './ConverScript.vue';  
26 - import {  
27 - createOrEditScriptManage,  
28 - getScriptManageDetail,  
29 - testScriptManage,  
30 - } from '/@/api/scriptmanage/scriptManager';  
31 - import { useMessage } from '/@/hooks/web/useMessage';  
32 -  
33 - const emits = defineEmits(['success', 'register']);  
34 - const { createMessage } = useMessage();  
35 - const converScriptRef = ref<InstanceType<typeof ConverScript>>();  
36 - const getTitle = computed(() => (isUpdate.value ? '编辑转换脚本' : '新增转换脚本'));  
37 - const isUpdate = ref(false);  
38 - const isViewDetail = ref('');  
39 - const isTest = ref(false);  
40 - const isText = ref('');  
41 - const isTitle = ref('');  
42 - const editData = reactive({  
43 - data: {},  
44 - });  
45 - const [register, { setModalProps, closeModal }] = useModalInner(async (data) => {  
46 - setModalProps({ loading: true });  
47 - handleCancel(false);  
48 - isUpdate.value = data.isUpdate;  
49 - isViewDetail.value = data.isView;  
50 - isTest.value = data.isTest;  
51 - isText.value = data.isText;  
52 - isTitle.value = data.isTitle;  
53 - editData.data = data.record;  
54 - setModalProps({ loading: false });  
55 - converScriptRef.value?.initEditor();  
56 - if (!unref(isViewDetail)) {  
57 - const title =  
58 - unref(isTitle) == 'edit'  
59 - ? '编辑转换脚本'  
60 - : unref(isTitle) == 'add'  
61 - ? '新增转换脚本'  
62 - : '测试转换脚本';  
63 - const okText = isText.value == 'test' ? '测试' : '确定';  
64 - if (unref(isTitle) == 'add') {  
65 - converScriptRef.value?.setDefaultRadio('TRANSPORT_TCP_UP');  
66 - }  
67 - if (unref(isTitle) == 'edit') {  
68 - converScriptRef.value?.setFormData(data.record);  
69 - }  
70 - if (unref(isTitle) == 'test') {  
71 - if (data.record) {  
72 - const res = await getScriptManageDetail(data.record);  
73 - converScriptRef.value?.setFormData({ ...res, convertJs: data?.testContent });  
74 - } else {  
75 - converScriptRef.value?.setFormData({ convertJs: data?.testContent });  
76 - converScriptRef.value?.setDefaultRadio('TRANSPORT_TCP_UP');  
77 - }  
78 - }  
79 - setModalProps({ title, showOkBtn: true, showCancelBtn: true, okText });  
80 - if (!unref(isUpdate)) {  
81 - }  
82 - } else {  
83 - setModalProps({ showOkBtn: false, showCancelBtn: false, title: '查看转换脚本' });  
84 - const res = await getScriptManageDetail(data.record.id);  
85 - converScriptRef.value?.setFormData(res || {});  
86 - }  
87 - });  
88 -  
89 - const handleSubmit = async () => {  
90 - setModalProps({ confirmLoading: true });  
91 - try {  
92 - const val = await converScriptRef.value?.getFormData();  
93 - const tempObj = {  
94 - ...editData.data,  
95 - ...val,  
96 - };  
97 - const res: any =  
98 - isText.value == 'test'  
99 - ? await testScriptManage(val)  
100 - : await createOrEditScriptManage(tempObj);  
101 - createMessage.success(  
102 - unref(isTitle) == 'edit'  
103 - ? '编辑转换脚本成功'  
104 - : unref(isTitle) == 'add'  
105 - ? '新增转换脚本成功'  
106 - : '测试转换脚本成功'  
107 - );  
108 - if (unref(isTitle) == 'add' || unref(isTitle) == 'edit') {  
109 - setTimeout(() => {  
110 - closeModal();  
111 - }, 10);  
112 - emits('success', {  
113 - res,  
114 - text: isText.value,  
115 - });  
116 - } else {  
117 - if (res) {  
118 - converScriptRef.value?.setScriptOutputData(res?.output || res?.error);  
119 - }  
120 - }  
121 - } finally {  
122 - setModalProps({ confirmLoading: false });  
123 - }  
124 - };  
125 - const handleCancel = (flag) => {  
126 - if (flag) {  
127 - closeModal();  
128 - }  
129 - converScriptRef.value?.resetFormData();  
130 - };  
131 -</script>  
132 -<style lang="less" scoped>  
133 - @import url('./ConverScriptModal.less');  
134 -</style>  
src/views/rule/script/TcpConversionScript/components/ConverScriptForm.vue renamed from src/views/rule/script/TcpConversionScript/ConverScript.vue
@@ -6,17 +6,16 @@ @@ -6,17 +6,16 @@
6 name="basic" 6 name="basic"
7 :label-col="{ span: 4 }" 7 :label-col="{ span: 4 }"
8 :wrapper-col="{ span: 16 }" 8 :wrapper-col="{ span: 16 }"
9 - autocomplete="off"  
10 > 9 >
11 <a-form-item 10 <a-form-item
12 - :label="ifAdd ? '名称' : '输入参数(params)'"  
13 - :name="ifAdd ? 'name' : 'params'"  
14 - :rules="[{ required: true, message: ifAdd ? '请输入脚本名称' : '请输入参数' }]" 11 + :label="isNotTest ? '名称' : '输入参数(params)'"
  12 + :name="isNotTest ? 'name' : 'params'"
  13 + :rules="[{ required: true, message: isNotTest ? '请输入脚本名称' : '请输入参数' }]"
15 > 14 >
16 <a-input-group compact> 15 <a-input-group compact>
17 <a-input 16 <a-input
18 style="width: calc(100% - 200px)" 17 style="width: calc(100% - 200px)"
19 - v-if="ifAdd" 18 + v-if="isNotTest"
20 :maxlength="36" 19 :maxlength="36"
21 @change="handleInputChange" 20 @change="handleInputChange"
22 v-model:value="scriptForm.name" 21 v-model:value="scriptForm.name"
@@ -28,7 +27,13 @@ @@ -28,7 +27,13 @@
28 v-model:value="scriptForm.params" 27 v-model:value="scriptForm.params"
29 placeholder="请输入参数" 28 placeholder="请输入参数"
30 /> 29 />
31 - <a-button @click="onHandleClick(text)" v-show="ifAdd && !view" type="primary"> 30 + <a-button
  31 + @click="
  32 + handleInnerTestClick(BusinessConvertScriptTextEnum.BUSINESS_TEST_TEXT, 'innerTest')
  33 + "
  34 + v-show="isNotTest && !isView"
  35 + type="primary"
  36 + >
32 测试 37 测试
33 </a-button> 38 </a-button>
34 </a-input-group> 39 </a-input-group>
@@ -46,36 +51,35 @@ @@ -46,36 +51,35 @@
46 /> 51 />
47 </a-space> 52 </a-space>
48 </a-form-item> 53 </a-form-item>
49 - <a-form-item label="脚本内容" :name="ifAdd ? 'convertJs' : 'script'">  
50 - <Card title="脚本内容" :bodyStyle="{ padding: 0 }"> 54 + <a-form-item label="脚本内容" :name="isNotTest ? 'convertJs' : 'script'">
  55 + <Card title="编写脚本内容" :bodyStyle="{ padding: 0 }">
51 <template #extra> 56 <template #extra>
52 <Button 57 <Button
53 - v-show="ifAdd && !view"  
54 - @click="onHandleTestExampleGateway(scriptForm.scriptType)"  
55 - style="position: relative; top: -4rem; right: -6.6rem" 58 + v-show="isNotTest && !isView"
  59 + @click="onHandleTestExample(true, scriptForm.scriptType)"
  60 + class="button-text"
56 type="primary" 61 type="primary"
57 > 62 >
58 直连/子设备用例</Button 63 直连/子设备用例</Button
59 > 64 >
60 <Button 65 <Button
61 - class="ml-2"  
62 - v-show="ifAdd && !view"  
63 - @click="onHandleTestExample(scriptForm.scriptType)"  
64 - style="position: relative; top: -4rem; right: -6.6rem" 66 + class="ml-2 button-text"
  67 + v-show="isNotTest && !isView"
  68 + @click="onHandleTestExample(false, scriptForm.scriptType)"
65 type="primary" 69 type="primary"
66 > 70 >
67 网关用例</Button 71 网关用例</Button
68 > 72 >
69 <a-button @click="handleFormat" size="small">格式化</a-button> 73 <a-button @click="handleFormat" size="small">格式化</a-button>
70 <Tooltip 74 <Tooltip
71 - v-if="scriptForm.scriptType !== 'TRANSPORT_TCP_UP'" 75 + v-if="scriptForm.scriptType !== ScriptTypeEnum.TRANSPORT_TCP_UP"
72 :title="defaultAuthTitle" 76 :title="defaultAuthTitle"
73 class="ml-2" 77 class="ml-2"
74 > 78 >
75 - <QuestionCircleOutlined style="font-size: 1rem" /> 79 + <QuestionCircleOutlined />
76 </Tooltip> 80 </Tooltip>
77 <Tooltip v-else :title="defaultUpTitle" class="ml-2"> 81 <Tooltip v-else :title="defaultUpTitle" class="ml-2">
78 - <QuestionCircleOutlined style="font-size: 1rem" /> 82 + <QuestionCircleOutlined />
79 </Tooltip> 83 </Tooltip>
80 </template> 84 </template>
81 <div ref="aceRef"></div> 85 <div ref="aceRef"></div>
@@ -88,12 +92,12 @@ @@ -88,12 +92,12 @@
88 </Button> 92 </Button>
89 </a-form-item> 93 </a-form-item>
90 <a-form-item 94 <a-form-item
91 - :label="ifAdd ? '备注' : '输出参数(output)'"  
92 - :name="ifAdd ? 'description' : 'output'" 95 + :label="isNotTest ? '备注' : '输出参数(output)'"
  96 + :name="isNotTest ? 'description' : 'output'"
93 > 97 >
94 <a-textarea 98 <a-textarea
95 :rows="3" 99 :rows="3"
96 - v-if="ifAdd" 100 + v-if="isNotTest"
97 v-model:value="scriptForm.description" 101 v-model:value="scriptForm.description"
98 placeholder="请输入备注" 102 placeholder="请输入备注"
99 :maxlength="255" 103 :maxlength="255"
@@ -107,7 +111,7 @@ @@ -107,7 +111,7 @@
107 /> 111 />
108 </a-form-item> 112 </a-form-item>
109 </a-form> 113 </a-form>
110 - <TestScriptModal @register="registerModal" /> 114 + <ConverScriptModal @register="registerModal" />
111 </div> 115 </div>
112 </template> 116 </template>
113 <script setup lang="ts"> 117 <script setup lang="ts">
@@ -130,18 +134,25 @@ @@ -130,18 +134,25 @@
130 defaultTestUpExample, 134 defaultTestUpExample,
131 defaultTestAuthExample, 135 defaultTestAuthExample,
132 defaultTestSubGatewayUpExample, 136 defaultTestSubGatewayUpExample,
133 - } from './config.data'; 137 + ScriptTypeEnum,
  138 + aceEditorAttribtes,
  139 + aceEditorOptions,
  140 + } from '../config';
134 import { useAppStore } from '/@/store/modules/app'; 141 import { useAppStore } from '/@/store/modules/app';
135 - import TestScriptModal from './TestScriptModal.vue'; 142 + import { ConverScriptModal } from './index';
136 import { useModal } from '/@/components/Modal'; 143 import { useModal } from '/@/components/Modal';
  144 + import { useHooks } from '../hooks/index.hooks';
  145 + import { BusinessConvertScriptTextEnum } from '../config';
137 146
138 defineEmits(['register']); 147 defineEmits(['register']);
  148 +
139 const props = defineProps({ 149 const props = defineProps({
140 - ifAdd: { type: Boolean, default: true },  
141 - text: { type: String, default: '' },  
142 - view: { type: Boolean, default: false }, 150 + isNotTest: { type: Boolean, default: true },
  151 + isView: { type: Boolean, default: false },
143 }); 152 });
144 153
  154 + const { validateContentError } = useHooks();
  155 +
145 const scriptForm = reactive({ 156 const scriptForm = reactive({
146 name: '', 157 name: '',
147 description: '', 158 description: '',
@@ -170,49 +181,42 @@ @@ -170,49 +181,42 @@
170 181
171 const getAceClass = computed((): string => userStore.getDarkMode); 182 const getAceClass = computed((): string => userStore.getDarkMode);
172 183
173 - const setDefaultRadio = (p3) => {  
174 - scriptForm.scriptType = p3; 184 + const setDefaultRadio = (defaultRadio) => {
  185 + scriptForm.scriptType = defaultRadio;
175 }; 186 };
176 187
177 const getDictValue = async (dict_type) => { 188 const getDictValue = async (dict_type) => {
178 const res = await findDictItemByCode({ 189 const res = await findDictItemByCode({
179 dictCode: dict_type, 190 dictCode: dict_type,
180 }); 191 });
181 - return res.map((m) => {  
182 - return { label: m.itemText, value: m.itemValue };  
183 - }); 192 + return res.map((m) => ({ label: m.itemText, value: m.itemValue }));
  193 + };
  194 +
  195 + const getScriptType = async () => {
  196 + reportTypeOptions.scriptTypeOptions = (await getDictValue('script_type')) as any;
184 }; 197 };
185 198
186 - onMounted(async () => {  
187 - reportTypeOptions.scriptTypeOptions = (await getDictValue('script_type')) as never as any; 199 + onMounted(() => {
  200 + getScriptType();
  201 + initEditor();
188 }); 202 });
189 203
190 - // 初始化编辑器 204 + // 初始化Ace编辑器
191 const initEditor = () => { 205 const initEditor = () => {
192 - aceEditor.value = ace.edit(aceRef.value, {  
193 - maxLines: 16, // 最大行数,超过会自动出现滚动条  
194 - minLines: 12, // 最小行数,还未到最大行数时,编辑器会自动伸缩大小  
195 - fontSize: 14, // 编辑器内字体大小  
196 - theme: 'ace/theme/chrome', // 默认设置的主题  
197 - mode: 'ace/mode/javascript', // 默认设置的语言模式  
198 - tabSize: 2, // 制表符设置为 4 个空格大小  
199 - });  
200 - 206 + aceEditor.value = ace.edit(aceRef.value, aceEditorAttribtes);
201 aceEditor.value.setOptions({ 207 aceEditor.value.setOptions({
202 - enableBasicAutocompletion: true,  
203 - enableLiveAutocompletion: true,  
204 - enableSnippets: true,  
205 - enableEmmet: true, 208 + ...aceEditorOptions,
206 theme: getAceClass.value === 'dark' ? 'ace/theme/terminal' : 'ace/theme/chrome', 209 theme: getAceClass.value === 'dark' ? 'ace/theme/terminal' : 'ace/theme/chrome',
207 }); 210 });
208 aceEditor.value.setValue(''); 211 aceEditor.value.setValue('');
209 beautify(aceEditor.value.session); 212 beautify(aceEditor.value.session);
210 - switchScriptTypeGetContent('TRANSPORT_TCP_UP'); 213 + switchScriptTypeGetContent(ScriptTypeEnum.TRANSPORT_TCP_UP);
211 }; 214 };
212 215
213 const handleScriptType = ({ target }) => { 216 const handleScriptType = ({ target }) => {
214 const { value } = target; 217 const { value } = target;
215 scriptForm.scriptType = value; 218 scriptForm.scriptType = value;
  219 + //业务 编辑不允许切换
216 if (convertJsContent.value) return; 220 if (convertJsContent.value) return;
217 switchScriptTypeGetContent(value); 221 switchScriptTypeGetContent(value);
218 }; 222 };
@@ -221,23 +225,17 @@ @@ -221,23 +225,17 @@
221 aceEditor.value.setValue(defaultScriptTypeContent[type]); 225 aceEditor.value.setValue(defaultScriptTypeContent[type]);
222 }; 226 };
223 227
224 - const onHandleTestExample = (example) => {  
225 - if (example === 'TRANSPORT_TCP_UP') {  
226 - aceEditor.value?.setValue(defaultTestUpExample);  
227 - } else {  
228 - aceEditor.value?.setValue(defaultTestAuthExample);  
229 - }  
230 - handleFormat();  
231 - };  
232 -  
233 - const onHandleTestExampleGateway = (example) => {  
234 - if (example === 'TRANSPORT_TCP_UP') { 228 + const onHandleTestExample = (status, example) => {
  229 + if (status && example === ScriptTypeEnum.TRANSPORT_TCP_UP) {
235 aceEditor.value?.setValue(defaultTestSubGatewayUpExample); 230 aceEditor.value?.setValue(defaultTestSubGatewayUpExample);
236 } else { 231 } else {
237 - aceEditor.value?.setValue(defaultTestAuthExample); 232 + example === ScriptTypeEnum.TRANSPORT_TCP_UP
  233 + ? aceEditor.value?.setValue(defaultTestUpExample)
  234 + : aceEditor.value?.setValue(defaultTestAuthExample);
238 } 235 }
239 handleFormat(); 236 handleFormat();
240 }; 237 };
  238 +
241 const handleCopy = () => { 239 const handleCopy = () => {
242 const valueRef = aceEditor.value.getValue(); 240 const valueRef = aceEditor.value.getValue();
243 const value = unref(valueRef); 241 const value = unref(valueRef);
@@ -255,61 +253,40 @@ @@ -255,61 +253,40 @@
255 253
256 const getFormData = async () => { 254 const getFormData = async () => {
257 const value = await formRef.value.validateFields(); 255 const value = await formRef.value.validateFields();
258 - if (props.ifAdd) { 256 + if (props.isNotTest) {
259 scriptForm.convertJs = aceEditor.value.getValue(); 257 scriptForm.convertJs = aceEditor.value.getValue();
260 - if (scriptForm.convertJs == '') {  
261 - createMessage.error('请编写脚本内容');  
262 - throw '请编写脚本内容';  
263 - } 258 + if (scriptForm.convertJs == '') return validateContentError();
264 } else { 259 } else {
265 scriptForm.script = aceEditor.value.getValue(); 260 scriptForm.script = aceEditor.value.getValue();
266 - if (scriptForm.script == '') {  
267 - createMessage.error('请编写脚本内容');  
268 - throw '请编写脚本内容';  
269 - } 261 + if (scriptForm.script == '') return validateContentError();
270 } 262 }
271 if (!value) return; 263 if (!value) return;
272 - if (scriptForm.params) {  
273 - const trimParams = scriptForm.params.replace(/\s*/g, '');  
274 - Reflect.set(value, 'params', trimParams);  
275 - }  
276 - if (scriptForm.convertJs.length > 1000) {  
277 - createMessage.error('脚本内容长度不能大于1000');  
278 - throw '脚本内容长度不能大于1000';  
279 - } 264 + if (scriptForm.params) removeTrim(true, scriptForm.params);
280 return { 265 return {
281 ...value, 266 ...value,
282 - ...{ convertJs: props.ifAdd ? scriptForm.convertJs : null },  
283 - ...{ script: !props.ifAdd ? scriptForm.script : null }, 267 + ...{ convertJs: props.isNotTest ? scriptForm.convertJs : null },
  268 + ...{ script: !props.isNotTest ? scriptForm.script : null },
284 }; 269 };
285 }; 270 };
286 271
287 - const handleInputChange = (e) => {  
288 - const trimParams = e.target.value.replace(/\s*/g, ''); 272 + const removeTrim = (status, e) => {
  273 + //去除空格
  274 + const value = status ? e : e.target.value;
  275 + const trimParams = value.replace(/\s*/g, '');
289 Reflect.set(scriptForm, 'params', trimParams); 276 Reflect.set(scriptForm, 'params', trimParams);
290 - if (scriptForm.scriptType === 'TRANSPORT_TCP_DOWN') {  
291 - aceEditor.value.setValue(`out.datas = "${scriptForm.params}";out.deviceName = "sensor";`);  
292 - }  
293 }; 277 };
294 278
295 - const getRecordId = ref(''); 279 + const handleInputChange = (e) => removeTrim(false, e);
296 280
297 const convertJsContent = ref(''); 281 const convertJsContent = ref('');
298 282
299 const setFormData = (v) => { 283 const setFormData = (v) => {
300 - if (v) {  
301 - getRecordId.value = v?.id;  
302 - for (let i in scriptForm) {  
303 - Reflect.set(scriptForm, i, v[i]);  
304 - }  
305 - aceEditor.value.setValue(v.convertJs);  
306 - convertJsContent.value = v.convertJs;  
307 - handleFormat(); 284 + if (!v) return;
  285 + for (let i in scriptForm) {
  286 + Reflect.set(scriptForm, i, v[i]);
308 } 287 }
309 - };  
310 -  
311 - const setScriptContentData = (v) => {  
312 - aceEditor.value.setValue(v); 288 + aceEditor.value.setValue(v.convertJs);
  289 + convertJsContent.value = v.convertJs;
313 handleFormat(); 290 handleFormat();
314 }; 291 };
315 292
@@ -317,6 +294,7 @@ @@ -317,6 +294,7 @@
317 for (let i in scriptForm) { 294 for (let i in scriptForm) {
318 Reflect.set(scriptForm, i, ''); 295 Reflect.set(scriptForm, i, '');
319 } 296 }
  297 + setDefaultRadio(ScriptTypeEnum.TRANSPORT_TCP_UP);
320 }; 298 };
321 299
322 const setScriptOutputData = (v) => { 300 const setScriptOutputData = (v) => {
@@ -332,29 +310,39 @@ @@ -332,29 +310,39 @@
332 310
333 const [registerModal, { openModal }] = useModal(); 311 const [registerModal, { openModal }] = useModal();
334 312
335 - const onHandleClick = (o) => { 313 + const handleInnerTestClick = (text, innerTest) => {
336 const getTestContent = aceEditor.value?.getValue(); 314 const getTestContent = aceEditor.value?.getValue();
337 - openModal(true, {  
338 - isAuth: '',  
339 - isUpdate: o,  
340 - record: o === 'add' ? null : getRecordId.value,  
341 - testContent: getTestContent,  
342 - isTest: true,  
343 - isText: 'test',  
344 - isTitle: 'test', 315 + const modalParams = {
  316 + innerTest,
  317 + text,
  318 + record: {
  319 + convertJs: getTestContent,
  320 + scriptType: scriptForm.scriptType,
  321 + },
  322 + };
  323 + openModal(true, modalParams);
  324 + };
  325 +
  326 + const setDisableRadio = (value) => {
  327 + reportTypeOptions.scriptTypeOptions.forEach((item: any) => {
  328 + if (item.value === value) item.disabled = false;
  329 + else item.disabled = true;
345 }); 330 });
346 }; 331 };
347 332
348 defineExpose({ 333 defineExpose({
349 - initEditor,  
350 getFormData, 334 getFormData,
351 resetFormData, 335 resetFormData,
352 setFormData, 336 setFormData,
353 - setScriptContentData,  
354 setScriptOutputData, 337 setScriptOutputData,
355 setDefaultRadio, 338 setDefaultRadio,
  339 + setDisableRadio,
356 }); 340 });
357 </script> 341 </script>
358 <style lang="less" scoped> 342 <style lang="less" scoped>
359 - @import url('./ConverScriptModal.less'); 343 + .button-text {
  344 + position: relative;
  345 + top: -4rem;
  346 + right: -6.6rem;
  347 + }
360 </style> 348 </style>
  1 +<template>
  2 + <div>
  3 + <BasicModal
  4 + destroyOnClose
  5 + v-bind="$attrs"
  6 + width="60rem"
  7 + @register="register"
  8 + :minHeight="500"
  9 + @cancel="handleCancel"
  10 + @ok="handleSubmit"
  11 + >
  12 + <ConverScriptForm
  13 + ref="converScriptFormRef"
  14 + :isNotTest="businessText !== BusinessConvertScriptTextEnum.BUSINESS_TEST_TEXT"
  15 + :isView="businessText === BusinessConvertScriptTextEnum.BUSINESS_VIEW_TEXT"
  16 + />
  17 + </BasicModal>
  18 + </div>
  19 +</template>
  20 +<script setup lang="ts">
  21 + import { ref, nextTick, reactive } from 'vue';
  22 + import { BasicModal, useModalInner } from '/@/components/Modal';
  23 + import { ConverScriptForm } from './index';
  24 + import {
  25 + createOrEditScriptManage,
  26 + getScriptManageDetail,
  27 + testScriptManage,
  28 + } from '/@/api/scriptmanage/scriptManager';
  29 + import { useMessage } from '/@/hooks/web/useMessage';
  30 + import { BusinessConvertScriptTextEnum } from '../config';
  31 + import { useHooks } from '../hooks/index.hooks';
  32 + import { useThrottleFn } from '@vueuse/shared';
  33 +
  34 + const emits = defineEmits(['success', 'register']);
  35 +
  36 + const { createMessage } = useMessage();
  37 +
  38 + const { setPropsForModal, businessTextIsTest } = useHooks();
  39 +
  40 + const converScriptFormRef = ref<InstanceType<typeof ConverScriptForm>>();
  41 +
  42 + const businessText = ref('');
  43 +
  44 + const restData = reactive({
  45 + data: {},
  46 + });
  47 +
  48 + const [register, { setModalProps, closeModal }] = useModalInner(async (data) => {
  49 + try {
  50 + await nextTick();
  51 + businessText.value = data.text;
  52 + restData.data = data.record;
  53 + setModalProps(setPropsForModal(data.text));
  54 + handleCancel(false);
  55 + if (!data.record) return;
  56 + if (!data.innerTest) {
  57 + const rest = await getScriptManageDetail(data.record?.id);
  58 + converScriptFormRef.value?.setFormData(rest);
  59 + } else converScriptFormRef.value?.setFormData(data.record);
  60 + if (data.scriptType) {
  61 + converScriptFormRef.value?.setDisableRadio(data.scriptType);
  62 + }
  63 + } finally {
  64 + setModalProps({
  65 + loading: false,
  66 + });
  67 + }
  68 + });
  69 +
  70 + const handleSubmit = () => useThrottle();
  71 +
  72 + const useThrottle = useThrottleFn(() => {
  73 + getValue();
  74 + }, 2000);
  75 +
  76 + const getValue = async () => {
  77 + try {
  78 + setModalProps({ confirmLoading: true });
  79 + const formData = await converScriptFormRef.value?.getFormData();
  80 + const rest = businessTextIsTest(businessText.value)
  81 + ? ((await testScriptManage(formData)) as any)
  82 + : ((await createOrEditScriptManage({ ...restData.data, ...formData })) as any);
  83 + if (businessTextIsTest(businessText.value)) {
  84 + createMessage.success(`${businessText.value}成功`);
  85 + converScriptFormRef.value?.setScriptOutputData(rest?.output || rest?.error);
  86 + } else {
  87 + createMessage.success(`${businessText.value}成功`);
  88 + closeModal();
  89 + emits('success', {
  90 + rest,
  91 + text: businessText.value,
  92 + });
  93 + }
  94 + } finally {
  95 + setModalProps({ confirmLoading: false });
  96 + }
  97 + };
  98 +
  99 + const handleCancel = (flag) => {
  100 + if (flag) {
  101 + closeModal();
  102 + }
  103 + converScriptFormRef.value?.resetFormData();
  104 + };
  105 +</script>
  106 +<style lang="less" scoped></style>
  1 +import ConverScriptModal from './ConverScriptModal.vue';
  2 +import ConverScriptForm from './ConverScriptForm.vue';
  3 +
  4 +export { ConverScriptModal, ConverScriptForm };
src/views/rule/script/TcpConversionScript/config/index.ts renamed from src/views/rule/script/TcpConversionScript/config.data.ts
1 -import { BasicColumn, FormSchema } from '/@/components/Table'; 1 +import { BasicColumn, BasicTableProps, FormSchema } from '/@/components/Table';
2 import moment from 'moment'; 2 import moment from 'moment';
3 import { h } from 'vue'; 3 import { h } from 'vue';
4 4
  5 +//业务权限配置
  6 +export enum PermissionConvertScriptEnum {
  7 + PERMISSION_POST = 'api:yt:js:post',
  8 + PERMISSION_DELETE = 'api:yt:js:delete',
  9 + PERMISSION_TEST = 'api:yt:js:test',
  10 + PERMISSION_UPDATE = 'api:yt:js:update',
  11 + PERMISSION_UPDATE_STATUS = 'api:yt:js:update:status',
  12 +}
  13 +
  14 +//业务文字描述配置
  15 +export enum BusinessConvertScriptTextEnum {
  16 + BUSINESS_ENABLE_SUCCESS = '启用成功',
  17 + BUSINESS_DISABLE_SUCCESS = '禁用成功',
  18 + BUSINESS_ADD_TEXT = '新增转换脚本',
  19 + BUSINESS_DELETE_TEXT = '批量删除',
  20 + BUSINESS_VIEW_TEXT = '查看转换脚本',
  21 + BUSINESS_TEST_TEXT = '测试转换脚本',
  22 + BUSINESS_EDIT_TEXT = '编辑转换脚本',
  23 + BUSINESS_SUBMIT_TEXT = '确定',
  24 +}
  25 +
  26 +//业务脚本类型枚举
  27 +export enum ScriptTypeEnum {
  28 + //上行脚本
  29 + TRANSPORT_TCP_UP = 'TRANSPORT_TCP_UP',
  30 + //设备鉴权
  31 + TRANSPORT_TCP_AUTH = 'TRANSPORT_TCP_AUTH',
  32 +}
  33 +
  34 +//Ace编辑器通用配置
  35 +export const aceEditorAttribtes = {
  36 + maxLines: 16, // 最大行数,超过会自动出现滚动条
  37 + minLines: 12, // 最小行数,还未到最大行数时,编辑器会自动伸缩大小
  38 + fontSize: 14, // 编辑器内字体大小
  39 + theme: 'ace/theme/chrome', // 默认设置的主题
  40 + mode: 'ace/mode/javascript', // 默认设置的语言模式
  41 + tabSize: 2, // 制表符设置为 4 个空格大小
  42 +};
  43 +
  44 +export const aceEditorOptions = {
  45 + enableBasicAutocompletion: true,
  46 + enableLiveAutocompletion: true,
  47 + enableSnippets: true,
  48 + enableEmmet: true,
  49 +};
  50 +
5 // 表格配置 51 // 表格配置
6 export const columns: BasicColumn[] = [ 52 export const columns: BasicColumn[] = [
7 { 53 {
@@ -33,7 +79,26 @@ export const columns: BasicColumn[] = [ @@ -33,7 +79,26 @@ export const columns: BasicColumn[] = [
33 }, 79 },
34 ]; 80 ];
35 81
36 -// 查询配置 82 +//表格通用属性配置
  83 +export const defaultTableAttribtes: BasicTableProps = {
  84 + columns,
  85 + title: '转换脚本列表',
  86 + showIndexColumn: false,
  87 + clickToRowSelect: false,
  88 + useSearchForm: true,
  89 + showTableSetting: true,
  90 + bordered: true,
  91 + rowKey: 'id',
  92 + actionColumn: {
  93 + width: 200,
  94 + title: '操作',
  95 + dataIndex: 'action',
  96 + slots: { customRender: 'action' },
  97 + fixed: 'right',
  98 + },
  99 +};
  100 +
  101 +// 表格查询配置
37 export const searchFormSchema: FormSchema[] = [ 102 export const searchFormSchema: FormSchema[] = [
38 { 103 {
39 field: 'name', 104 field: 'name',
@@ -58,6 +123,7 @@ export const searchFormSchema: FormSchema[] = [ @@ -58,6 +123,7 @@ export const searchFormSchema: FormSchema[] = [
58 }, 123 },
59 ]; 124 ];
60 125
  126 +//示例配置
61 export const defaultAuthTitle = h('div', { style: 'background:#404040' }, [ 127 export const defaultAuthTitle = h('div', { style: 'background:#404040' }, [
62 h('h3', { style: 'color:white' }, '设备鉴权示例'), 128 h('h3', { style: 'color:white' }, '设备鉴权示例'),
63 h('h3', { style: 'color:white' }, '输入参数:为16进制字符串'), 129 h('h3', { style: 'color:white' }, '输入参数:为16进制字符串'),
@@ -84,7 +150,7 @@ export const defaultUpTitle = h('div', { style: 'background:#404040' }, [ @@ -84,7 +150,7 @@ export const defaultUpTitle = h('div', { style: 'background:#404040' }, [
84 ), 150 ),
85 ]); 151 ]);
86 152
87 -// TRANSPORT_TCP_DOWN: 'out.datas = "";out.deviceName = "sensor";', 153 +//用例配置
88 export const defaultScriptTypeContent = { 154 export const defaultScriptTypeContent = {
89 TRANSPORT_TCP_UP: `/*网关上行脚本*/ 155 TRANSPORT_TCP_UP: `/*网关上行脚本*/
90 var teleData = {}; 156 var teleData = {};
@@ -104,21 +170,9 @@ out.success = params; @@ -104,21 +170,9 @@ out.success = params;
104 `, 170 `,
105 }; 171 };
106 172
107 -export const defaultTestUpExample = `/*网关上行脚本*/  
108 -var teleData = {};  
109 -/*物模型数据(可选):原始数据*/  
110 -teleData.source= params;  
111 -/*网关设备:slaveDevice是网关子设备的“设备标识”*/  
112 -slaveDevice = params.substr(0,2);  
113 -teleData[slaveDevice]= params;  
114 -out.datas = teleData;  
115 -out.telemetry = true;/*必填:true表示设备上报的遥测数据,false表示命令下发的响应数据*/`; 173 +export const defaultTestUpExample = defaultScriptTypeContent['TRANSPORT_TCP_UP'];
116 174
117 -export const defaultTestAuthExample = `/*必填:设备的访问令牌*/  
118 -out.password = params;  
119 -/*选填:设备鉴权成功后响应给设备的信息*/  
120 -out.success = params;  
121 -`; 175 +export const defaultTestAuthExample = defaultScriptTypeContent['TRANSPORT_TCP_AUTH'];
122 176
123 export const defaultTestSubGatewayUpExample = `/*params为TCP上报的标准ModBus数据,实际使用或测试时请删除*/ 177 export const defaultTestSubGatewayUpExample = `/*params为TCP上报的标准ModBus数据,实际使用或测试时请删除*/
124 var params = "010304026C00883BF0" 178 var params = "010304026C00883BF0"
  1 +import { BusinessConvertScriptTextEnum } from '../config';
  2 +import { useMessage } from '/@/hooks/web/useMessage';
  3 +
  4 +export const useHooks = () => {
  5 + const { createMessage } = useMessage();
  6 +
  7 + //映射弹窗底部按钮文字
  8 + const getModalButtonText = (text) => {
  9 + return text === BusinessConvertScriptTextEnum.BUSINESS_TEST_TEXT
  10 + ? BusinessConvertScriptTextEnum.BUSINESS_TEST_TEXT.slice(0, 2)
  11 + : BusinessConvertScriptTextEnum.BUSINESS_SUBMIT_TEXT;
  12 + };
  13 +
  14 + //判断业务文字是否为测试
  15 + const businessTextIsTest = (text) => text === BusinessConvertScriptTextEnum.BUSINESS_TEST_TEXT;
  16 +
  17 + //验证脚本内容
  18 + const validateContentError = () => {
  19 + createMessage.error('请编写脚本内容');
  20 + throw '请编写脚本内容';
  21 + };
  22 +
  23 + //Modal弹窗属性
  24 + const setPropsForModal = (text) => {
  25 + return {
  26 + loading: true,
  27 + title: text,
  28 + okText: getModalButtonText(text),
  29 + showOkBtn: text !== BusinessConvertScriptTextEnum.BUSINESS_VIEW_TEXT,
  30 + showCancelBtn: text !== BusinessConvertScriptTextEnum.BUSINESS_VIEW_TEXT,
  31 + };
  32 + };
  33 + return {
  34 + getModalButtonText,
  35 + businessTextIsTest,
  36 + validateContentError,
  37 + setPropsForModal,
  38 + };
  39 +};
1 -export { default as TcpConversionScript } from './index.vue'; 1 +export { default as TcpConversionScript } from './index.vue';
1 -<template>  
2 - <div>  
3 - <BasicTable :clickToRowSelect="false" @register="registerTable" :searchInfo="searchInfo">  
4 - <template #toolbar>  
5 - <Authority value="api:yt:js:post">  
6 - <a-button type="primary" @click="handleCreateOrEdit(null)"> 新增转换脚本 </a-button>  
7 - </Authority>  
8 - <Authority value="api:yt:js:delete">  
9 - <Popconfirm  
10 - title="您确定要批量删除数据"  
11 - ok-text="确定"  
12 - cancel-text="取消"  
13 - @confirm="handleDeleteOrBatchDelete(null)"  
14 - >  
15 - <a-button type="primary" color="error" :disabled="hasBatchDelete"> 批量删除 </a-button>  
16 - </Popconfirm>  
17 - </Authority>  
18 - </template>  
19 - <template #convertJs="{ record }">  
20 - <a-button type="text" @click="handleScriptView(record)">  
21 - <span style="color: #377dff">查看脚本</span>  
22 - </a-button>  
23 - </template>  
24 - <template #action="{ record }">  
25 - <TableAction  
26 - :actions="[  
27 - {  
28 - label: '测试',  
29 - icon: 'ant-design:font-size-outlined',  
30 - auth: 'api:yt:js:test',  
31 - onClick: handleBindTest.bind(null, record),  
32 - },  
33 - {  
34 - label: '编辑',  
35 - icon: 'clarity:note-edit-line',  
36 - auth: 'api:yt:js:update',  
37 - onClick: handleCreateOrEdit.bind(null, record),  
38 - ifShow: record.status == 0,  
39 - },  
40 - {  
41 - label: '删除',  
42 - icon: 'ant-design:delete-outlined',  
43 - auth: 'api:yt:js:delete',  
44 - color: 'error',  
45 - ifShow: record.status == 0,  
46 - popConfirm: {  
47 - title: '是否确认删除',  
48 - confirm: handleDeleteOrBatchDelete.bind(null, record),  
49 - },  
50 - },  
51 - ]"  
52 - />  
53 - </template>  
54 - <template #status="{ record }">  
55 - <Authority value="api:yt:js:update:status">  
56 - <Switch  
57 - :checked="record.status === 1"  
58 - :loading="record.pendingStatus"  
59 - checkedChildren="启用"  
60 - unCheckedChildren="禁用"  
61 - @change="(checked:boolean)=>statusChange(checked,record)"  
62 - />  
63 - </Authority>  
64 - </template>  
65 - </BasicTable>  
66 - <ConverScriptModal @register="registerModal" @success="handleSuccess" />  
67 - </div>  
68 -</template>  
69 -  
70 -<script lang="ts" setup>  
71 - import { reactive, nextTick, unref } from 'vue';  
72 - import { BasicTable, useTable, TableAction } from '/@/components/Table';  
73 - import { columns } from './config.data';  
74 - import { Authority } from '/@/components/Authority';  
75 - import { useBatchDelete } from '/@/hooks/web/useBatchDelete';  
76 - import { Switch, Popconfirm } from 'ant-design-vue';  
77 - import { useModal } from '/@/components/Modal';  
78 - import ConverScriptModal from './ConverScriptModal.vue';  
79 - import {  
80 - ScriptPage,  
81 - deleteScriptManage,  
82 - scriptPagePutApi,  
83 - } from '/@/api/scriptmanage/scriptManager';  
84 - import { useMessage } from '/@/hooks/web/useMessage';  
85 -  
86 - const props = defineProps<{ searchInfo: Recordable }>();  
87 - const searchInfo = reactive<Recordable>({});  
88 - const [registerTable, { reload, setProps, setSelectedRowKeys }] = useTable({  
89 - title: '转换脚本列表',  
90 - api: ScriptPage,  
91 - columns,  
92 - showIndexColumn: false,  
93 - clickToRowSelect: false,  
94 - showTableSetting: true,  
95 - bordered: true,  
96 - rowKey: 'id',  
97 - beforeFetch: (params: Recordable) => {  
98 - return { ...unref(props.searchInfo), ...params };  
99 - },  
100 - actionColumn: {  
101 - width: 200,  
102 - title: '操作',  
103 - dataIndex: 'action',  
104 - slots: { customRender: 'action' },  
105 - fixed: 'right',  
106 - },  
107 - });  
108 -  
109 - const handleSuccess = () => {  
110 - reload();  
111 - };  
112 -  
113 - const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions, resetSelectedRowKeys } =  
114 - useBatchDelete(deleteScriptManage, handleSuccess, setProps);  
115 - selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => {  
116 - // Demo:status为1的选择框禁用  
117 - if (record.status === 1) {  
118 - return { disabled: true };  
119 - } else {  
120 - return { disabled: false };  
121 - }  
122 - };  
123 -  
124 - nextTick(() => {  
125 - setProps(selectionOptions);  
126 - });  
127 -  
128 - const [registerModal, { openModal }] = useModal();  
129 -  
130 - // 新增或编辑  
131 - const handleCreateOrEdit = (record: Recordable | null) => {  
132 - if (record) {  
133 - openModal(true, {  
134 - isUpdate: false,  
135 - record,  
136 - isAuth: '',  
137 - isView: false,  
138 - isTest: false,  
139 - isText: 'confirm',  
140 - isTitle: 'edit',  
141 - });  
142 - } else {  
143 - openModal(true, {  
144 - isAuth: '',  
145 - isUpdate: true,  
146 - isView: false,  
147 - isTest: false,  
148 - isText: 'confirm',  
149 - isTitle: 'add',  
150 - });  
151 - }  
152 - };  
153 - const handleBindTest = (record: Recordable | null) => {  
154 - if (record) {  
155 - openModal(true, {  
156 - isAuth: '',  
157 - isUpdate: false,  
158 - record: record.id,  
159 - isTest: true,  
160 - isText: 'test',  
161 - isTitle: 'test',  
162 - });  
163 - }  
164 - };  
165 - const handleScriptView = (record: Recordable | null) => {  
166 - if (record) {  
167 - openModal(true, {  
168 - isUpdate: true,  
169 - record,  
170 - isView: true,  
171 - });  
172 - }  
173 - };  
174 - const statusChange = async (checked, record) => {  
175 - setProps({  
176 - loading: true,  
177 - });  
178 - setSelectedRowKeys([]);  
179 - resetSelectedRowKeys();  
180 - const newStatus = checked ? 1 : 0;  
181 - const { createMessage } = useMessage();  
182 - try {  
183 - await scriptPagePutApi(record.id, newStatus);  
184 - if (newStatus) {  
185 - createMessage.success(`启用成功`);  
186 - } else {  
187 - createMessage.success('禁用成功');  
188 - }  
189 - } finally {  
190 - setProps({  
191 - loading: false,  
192 - });  
193 - reload();  
194 - }  
195 - };  
196 -  
197 - defineExpose({  
198 - reload: () => {  
199 - reload();  
200 - },  
201 - });  
202 -</script> 1 +<template>
  2 + <div>
  3 + <BasicTable :clickToRowSelect="false" @register="registerTable" :searchInfo="searchInfo">
  4 + <template #toolbar>
  5 + <Authority :value="PermissionConvertScriptEnum.PERMISSION_POST">
  6 + <a-button
  7 + type="primary"
  8 + @click="handleBusinessModal(BusinessConvertScriptTextEnum.BUSINESS_ADD_TEXT, null)"
  9 + >
  10 + {{ BusinessConvertScriptTextEnum.BUSINESS_ADD_TEXT }}
  11 + </a-button>
  12 + </Authority>
  13 + <Authority :value="PermissionConvertScriptEnum.PERMISSION_DELETE">
  14 + <Popconfirm
  15 + title="您确定要批量删除数据"
  16 + ok-text="确定"
  17 + cancel-text="取消"
  18 + @confirm="handleDeleteOrBatchDelete(null)"
  19 + >
  20 + <a-button type="primary" color="error" :disabled="hasBatchDelete">
  21 + {{ BusinessConvertScriptTextEnum.BUSINESS_DELETE_TEXT }}
  22 + </a-button>
  23 + </Popconfirm>
  24 + </Authority>
  25 + </template>
  26 + <template #convertJs="{ record }">
  27 + <a-button
  28 + type="text"
  29 + @click="handleBusinessModal(BusinessConvertScriptTextEnum.BUSINESS_VIEW_TEXT, record)"
  30 + >
  31 + <span style="color: #377dff">{{
  32 + BusinessConvertScriptTextEnum.BUSINESS_VIEW_TEXT.slice(0, 2)
  33 + }}</span>
  34 + </a-button>
  35 + </template>
  36 + <template #action="{ record }">
  37 + <TableAction
  38 + :actions="[
  39 + {
  40 + label: BusinessConvertScriptTextEnum.BUSINESS_TEST_TEXT.slice(0, 2),
  41 + icon: 'ant-design:font-size-outlined',
  42 + auth: PermissionConvertScriptEnum.PERMISSION_TEST,
  43 + onClick: handleBusinessModal.bind(
  44 + null,
  45 + BusinessConvertScriptTextEnum.BUSINESS_TEST_TEXT,
  46 + record
  47 + ),
  48 + },
  49 + {
  50 + label: BusinessConvertScriptTextEnum.BUSINESS_EDIT_TEXT.slice(0, 2),
  51 + icon: 'clarity:note-edit-line',
  52 + auth: PermissionConvertScriptEnum.PERMISSION_UPDATE,
  53 + onClick: handleBusinessModal.bind(
  54 + null,
  55 + BusinessConvertScriptTextEnum.BUSINESS_EDIT_TEXT,
  56 + record
  57 + ),
  58 + ifShow: record.status == 0,
  59 + },
  60 + {
  61 + label: BusinessConvertScriptTextEnum.BUSINESS_DELETE_TEXT.slice(-2),
  62 + icon: 'ant-design:delete-outlined',
  63 + auth: PermissionConvertScriptEnum.PERMISSION_DELETE,
  64 + color: 'error',
  65 + ifShow: record.status == 0,
  66 + popConfirm: {
  67 + title: '是否确认删除',
  68 + confirm: handleDeleteOrBatchDelete.bind(null, record),
  69 + },
  70 + },
  71 + ]"
  72 + />
  73 + </template>
  74 + <template #status="{ record }">
  75 + <Authority :value="PermissionConvertScriptEnum.PERMISSION_UPDATE_STATUS">
  76 + <Switch
  77 + :checked="record.status === 1"
  78 + :loading="record.pendingStatus"
  79 + checkedChildren="启用"
  80 + unCheckedChildren="禁用"
  81 + @change="(checked:boolean)=>statusChange(checked,record)"
  82 + />
  83 + </Authority>
  84 + </template>
  85 + </BasicTable>
  86 + <ConverScriptModal @register="registerModal" @success="handleSuccess" />
  87 + </div>
  88 +</template>
  89 +
  90 +<script lang="ts" setup name="index">
  91 + import { reactive, nextTick, unref } from 'vue';
  92 + import { BasicTable, useTable, TableAction } from '/@/components/Table';
  93 + import { Authority } from '/@/components/Authority';
  94 + import { useModal } from '/@/components/Modal';
  95 + import { useBatchDelete } from '/@/hooks/web/useBatchDelete';
  96 + import { Switch, Popconfirm } from 'ant-design-vue';
  97 + import { useMessage } from '/@/hooks/web/useMessage';
  98 + import {
  99 + ScriptPage,
  100 + deleteScriptManage,
  101 + scriptPagePutApi,
  102 + } from '/@/api/scriptmanage/scriptManager';
  103 + import {
  104 + PermissionConvertScriptEnum,
  105 + searchFormSchema,
  106 + defaultTableAttribtes,
  107 + BusinessConvertScriptTextEnum,
  108 + } from './config';
  109 + import { ConverScriptModal } from './components';
  110 +
  111 + const props = defineProps<{ searchInfo: Recordable }>();
  112 +
  113 + const searchInfo = reactive<Recordable>({});
  114 +
  115 + const [registerTable, { reload, setProps, setSelectedRowKeys }] = useTable({
  116 + api: ScriptPage,
  117 + ...defaultTableAttribtes,
  118 + beforeFetch: (params: Recordable) => {
  119 + return { ...unref(props.searchInfo), ...params };
  120 + },
  121 + formConfig: {
  122 + labelWidth: 120,
  123 + schemas: searchFormSchema,
  124 + fieldMapToTime: [['sendTime', ['startTime', 'endTime'], 'x']],
  125 + },
  126 + });
  127 +
  128 + const handleSuccess = () => {
  129 + reload();
  130 + };
  131 +
  132 + const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions, resetSelectedRowKeys } =
  133 + useBatchDelete(deleteScriptManage, handleSuccess, setProps) as any;
  134 + selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => {
  135 + if (record.status === 1) return { disabled: true };
  136 + else return { disabled: false };
  137 + };
  138 +
  139 + nextTick(() => {
  140 + setProps(selectionOptions);
  141 + });
  142 +
  143 + const [registerModal, { openModal }] = useModal();
  144 +
  145 + // 业务弹窗
  146 + const handleBusinessModal = (text, record: Recordable | null) => {
  147 + const modalParams = {
  148 + text,
  149 + record,
  150 + };
  151 + openModal(true, modalParams);
  152 + };
  153 +
  154 + const setPropsLoading = (loading) => {
  155 + setProps({
  156 + loading,
  157 + });
  158 + setSelectedRowKeys([]);
  159 + resetSelectedRowKeys();
  160 + };
  161 +
  162 + const statusChange = async (checked, record) => {
  163 + setPropsLoading(true);
  164 + const newStatus = checked ? 1 : 0;
  165 + const { createMessage } = useMessage();
  166 + try {
  167 + await scriptPagePutApi(record.id, newStatus);
  168 + if (newStatus)
  169 + return createMessage.success(BusinessConvertScriptTextEnum.BUSINESS_ENABLE_SUCCESS);
  170 + else return createMessage.success(BusinessConvertScriptTextEnum.BUSINESS_DISABLE_SUCCESS);
  171 + } finally {
  172 + setPropsLoading(false);
  173 + reload();
  174 + }
  175 + };
  176 +
  177 + defineExpose({
  178 + reload: () => {
  179 + reload();
  180 + },
  181 + });
  182 +</script>