Commit 14468e22febab59d123c9154332e06ea59d546b3
Merge branch 'ft_local_dev' into 'main'
feat:新增脚本管理-转换脚本静态页面 See merge request huang/yun-teng-iot-front!347
Showing
11 changed files
with
558 additions
and
106 deletions
| @@ -4,6 +4,27 @@ import { Rule } from 'ant-design-vue/lib/form/interface'; | @@ -4,6 +4,27 @@ import { Rule } from 'ant-design-vue/lib/form/interface'; | ||
| 4 | * | 4 | * |
| 5 | */ | 5 | */ |
| 6 | 6 | ||
| 7 | +export const validatorLongitude = (_rule: Rule, value: string) => { | ||
| 8 | + const reg = | ||
| 9 | + /^(\-|\+)?(((\d|[1-9]\d|1[0-7]\d|0{1,3})\.\d{0,20})|(\d|[1-9]\d|1[0-7]\d|0{1,3})|180\.0{0,20}|180)$/; | ||
| 10 | + if (!value) { | ||
| 11 | + return Promise.reject('请输入经度'); | ||
| 12 | + } else if (!reg.test(value)) { | ||
| 13 | + return Promise.reject('经度整数部分为0-180,小数部分为0到6位!'); | ||
| 14 | + } | ||
| 15 | + return Promise.resolve(); | ||
| 16 | +}; | ||
| 17 | +export const validatorLatitude = (_rule: Rule, value: string) => { | ||
| 18 | + const reg = /^(\-|\+)?([0-8]?\d{1}\.\d{0,20}|90\.0{0,20}|[0-8]?\d{1}|90)$/; | ||
| 19 | + if (value === '') { | ||
| 20 | + return Promise.reject('请输入维度'); | ||
| 21 | + } else if (!reg.test(value)) { | ||
| 22 | + return Promise.reject('纬度整数部分为0-90,小数部分为0到6位!'); | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + return Promise.resolve(); | ||
| 26 | +}; | ||
| 27 | + | ||
| 7 | //正整数并且可以是英文 | 28 | //正整数并且可以是英文 |
| 8 | export const numberAndEngLishRule: Rule[] = [ | 29 | export const numberAndEngLishRule: Rule[] = [ |
| 9 | { | 30 | { |
| @@ -46,7 +46,7 @@ | @@ -46,7 +46,7 @@ | ||
| 46 | centered | 46 | centered |
| 47 | > | 47 | > |
| 48 | <div> | 48 | <div> |
| 49 | - <Form :label-col="labelCol" :colon="false"> | 49 | + <Form :label-col="labelCol" :colon="false" :rules="rules" :model="positionState"> |
| 50 | <Row :gutter="20" class="mt-4"> | 50 | <Row :gutter="20" class="mt-4"> |
| 51 | <Col :span="20"> | 51 | <Col :span="20"> |
| 52 | <FormItem label="搜索位置"> | 52 | <FormItem label="搜索位置"> |
| @@ -64,13 +64,21 @@ | @@ -64,13 +64,21 @@ | ||
| 64 | </Row> | 64 | </Row> |
| 65 | <Row :gutter="20" class=""> | 65 | <Row :gutter="20" class=""> |
| 66 | <Col :span="10"> | 66 | <Col :span="10"> |
| 67 | - <FormItem label="经度"> | ||
| 68 | - <Input v-model:value="positionState.longitude" disabled /> | 67 | + <FormItem label="经度" name="longitude"> |
| 68 | + <Input | ||
| 69 | + @blur="redirectPosition" | ||
| 70 | + @change="redirectPosition" | ||
| 71 | + v-model:value="positionState.longitude" | ||
| 72 | + /> | ||
| 69 | </FormItem> | 73 | </FormItem> |
| 70 | </Col> | 74 | </Col> |
| 71 | <Col :span="10"> | 75 | <Col :span="10"> |
| 72 | - <FormItem label="纬度"> | ||
| 73 | - <Input v-model:value="positionState.latitude" disabled /> | 76 | + <FormItem label="纬度" name="latitude"> |
| 77 | + <Input | ||
| 78 | + @blur="redirectPosition" | ||
| 79 | + @change="redirectPosition" | ||
| 80 | + v-model:value="positionState.latitude" | ||
| 81 | + /> | ||
| 74 | </FormItem> | 82 | </FormItem> |
| 75 | </Col> | 83 | </Col> |
| 76 | </Row> | 84 | </Row> |
| @@ -90,9 +98,11 @@ | @@ -90,9 +98,11 @@ | ||
| 90 | import { upload } from '/@/api/oss/ossFileUploader'; | 98 | import { upload } from '/@/api/oss/ossFileUploader'; |
| 91 | import { FileItem } from '/@/components/Upload/src/typing'; | 99 | import { FileItem } from '/@/components/Upload/src/typing'; |
| 92 | import { BAI_DU_MAP_URL } from '/@/utils/fnUtils'; | 100 | import { BAI_DU_MAP_URL } from '/@/utils/fnUtils'; |
| 93 | - import { generateSNCode } from '/@/api/device/deviceManager.ts'; | 101 | + import { generateSNCode } from '/@/api/device/deviceManager'; |
| 94 | import icon from '/@/assets/images/wz.png'; | 102 | import icon from '/@/assets/images/wz.png'; |
| 95 | import { useDebounceFn } from '@vueuse/core'; | 103 | import { useDebounceFn } from '@vueuse/core'; |
| 104 | + import { validatorLongitude, validatorLatitude } from '/@/utils/rules'; | ||
| 105 | + | ||
| 96 | export default defineComponent({ | 106 | export default defineComponent({ |
| 97 | components: { | 107 | components: { |
| 98 | BasicForm, | 108 | BasicForm, |
| @@ -115,6 +125,16 @@ | @@ -115,6 +125,16 @@ | ||
| 115 | }, | 125 | }, |
| 116 | emits: ['next'], | 126 | emits: ['next'], |
| 117 | setup(props, { emit }) { | 127 | setup(props, { emit }) { |
| 128 | + const redirectPosition = () => { | ||
| 129 | + if (positionState.longitude && positionState.latitude) { | ||
| 130 | + var pt = new BMap.Point(positionState.longitude, positionState.latitude); | ||
| 131 | + getAddrByPoint(pt); | ||
| 132 | + } | ||
| 133 | + }; | ||
| 134 | + const rules: any = { | ||
| 135 | + longitude: [{ required: true, validator: validatorLongitude, trigger: 'blur' }], | ||
| 136 | + latitude: [{ required: true, validator: validatorLatitude, trigger: 'blur' }], | ||
| 137 | + }; | ||
| 118 | const devicePic = ref(''); | 138 | const devicePic = ref(''); |
| 119 | const loading = ref(false); | 139 | const loading = ref(false); |
| 120 | 140 | ||
| @@ -202,9 +222,9 @@ | @@ -202,9 +222,9 @@ | ||
| 202 | geco.getLocation(point, function (res) { | 222 | geco.getLocation(point, function (res) { |
| 203 | positionState.marker.setPosition(point); //重新设置标注的地理坐标 | 223 | positionState.marker.setPosition(point); //重新设置标注的地理坐标 |
| 204 | positionState.map.panTo(point); //将地图的中心点更改为给定的点 | 224 | positionState.map.panTo(point); //将地图的中心点更改为给定的点 |
| 205 | - positionState.address = res.address; //记录该点的详细地址信息 | ||
| 206 | - positionState.longitude = point.lng; //记录当前坐标点 | ||
| 207 | - positionState.latitude = point.lat; | 225 | + positionState.address = res?.address; //记录该点的详细地址信息 |
| 226 | + positionState.longitude = point?.lng; //记录当前坐标点 | ||
| 227 | + positionState.latitude = point?.lat; | ||
| 208 | }); | 228 | }); |
| 209 | } | 229 | } |
| 210 | 230 | ||
| @@ -378,6 +398,8 @@ | @@ -378,6 +398,8 @@ | ||
| 378 | debounceSearch, | 398 | debounceSearch, |
| 379 | generateSN, | 399 | generateSN, |
| 380 | loading, | 400 | loading, |
| 401 | + rules, | ||
| 402 | + redirectPosition, | ||
| 381 | }; | 403 | }; |
| 382 | }, | 404 | }, |
| 383 | }); | 405 | }); |
| @@ -387,6 +409,7 @@ | @@ -387,6 +409,7 @@ | ||
| 387 | width: 450px; | 409 | width: 450px; |
| 388 | margin: 0 auto; | 410 | margin: 0 auto; |
| 389 | } | 411 | } |
| 412 | + | ||
| 390 | :deep(.ant-radio-group) { | 413 | :deep(.ant-radio-group) { |
| 391 | width: 15vw; | 414 | width: 15vw; |
| 392 | } | 415 | } |
| @@ -4,6 +4,95 @@ import { findDictItemByCode } from '/@/api/system/dict'; | @@ -4,6 +4,95 @@ import { findDictItemByCode } from '/@/api/system/dict'; | ||
| 4 | import { MessageEnum } from '/@/enums/messageEnum'; | 4 | import { MessageEnum } from '/@/enums/messageEnum'; |
| 5 | import { numberRule } from '/@/utils/rules'; | 5 | import { numberRule } from '/@/utils/rules'; |
| 6 | 6 | ||
| 7 | +import { deviceConfigGetRuleChain } from '/@/api/device/deviceConfigApi'; | ||
| 8 | + | ||
| 9 | +export const step1Schemas: FormSchema[] = [ | ||
| 10 | + { | ||
| 11 | + field: 'image', | ||
| 12 | + label: '上传图片', | ||
| 13 | + component: 'Input', | ||
| 14 | + slot: 'imageSelect', | ||
| 15 | + }, | ||
| 16 | + { | ||
| 17 | + field: 'name', | ||
| 18 | + label: '配置名称', | ||
| 19 | + required: true, | ||
| 20 | + component: 'Input', | ||
| 21 | + componentProps() { | ||
| 22 | + return { | ||
| 23 | + disabled: false, | ||
| 24 | + ength: 255, | ||
| 25 | + placeholder: '请输入配置名称', | ||
| 26 | + }; | ||
| 27 | + }, | ||
| 28 | + }, | ||
| 29 | + { | ||
| 30 | + field: 'defaultRuleChainId', | ||
| 31 | + label: '规则链', | ||
| 32 | + component: 'ApiSelect', | ||
| 33 | + componentProps: { | ||
| 34 | + api: async () => { | ||
| 35 | + const data = await deviceConfigGetRuleChain(); | ||
| 36 | + const returnData = data.map((m) => { | ||
| 37 | + return { | ||
| 38 | + getValueField: m.name, | ||
| 39 | + getKeyField: m.id.id, | ||
| 40 | + }; | ||
| 41 | + }); | ||
| 42 | + return returnData; | ||
| 43 | + }, | ||
| 44 | + labelField: 'getValueField', | ||
| 45 | + valueField: 'getKeyField', | ||
| 46 | + immediate: true, | ||
| 47 | + }, | ||
| 48 | + }, | ||
| 49 | + { | ||
| 50 | + field: 'defaultQueueName', | ||
| 51 | + label: '处理队列', | ||
| 52 | + component: 'ApiSelect', | ||
| 53 | + componentProps: { | ||
| 54 | + api: findDictItemByCode, | ||
| 55 | + params: { | ||
| 56 | + dictCode: 'queen_execute_sequence', | ||
| 57 | + }, | ||
| 58 | + labelField: 'itemText', | ||
| 59 | + valueField: 'itemValue', | ||
| 60 | + resultField: 'items', | ||
| 61 | + }, | ||
| 62 | + }, | ||
| 63 | + | ||
| 64 | + { | ||
| 65 | + label: '描述', | ||
| 66 | + field: 'description', | ||
| 67 | + component: 'InputTextArea', | ||
| 68 | + componentProps: { | ||
| 69 | + maxLength: 255, | ||
| 70 | + placeholder: '请输入描述', | ||
| 71 | + }, | ||
| 72 | + }, | ||
| 73 | +]; | ||
| 74 | + | ||
| 75 | +export const step2Schemas: FormSchema[] = [ | ||
| 76 | + { | ||
| 77 | + field: 'transportType', | ||
| 78 | + component: 'Select', | ||
| 79 | + label: '接入协议', | ||
| 80 | + defaultValue: 'DEFAULT', | ||
| 81 | + componentProps() { | ||
| 82 | + return { | ||
| 83 | + options: [ | ||
| 84 | + { label: '默认', value: 'DEFAULT' }, | ||
| 85 | + { label: 'MQTT', value: 'MQTT' }, | ||
| 86 | + { label: 'CoAP', value: 'COAP' }, | ||
| 87 | + { label: 'LWM2M', value: 'LWM2M' }, | ||
| 88 | + { label: 'SNMP', value: 'SNMP' }, | ||
| 89 | + ], | ||
| 90 | + }; | ||
| 91 | + }, | ||
| 92 | + colProps: { span: 10 }, | ||
| 93 | + }, | ||
| 94 | +]; | ||
| 95 | + | ||
| 7 | export const columns: BasicColumn[] = [ | 96 | export const columns: BasicColumn[] = [ |
| 8 | { | 97 | { |
| 9 | title: '配置图片', //图标 | 98 | title: '配置图片', //图标 |
| @@ -34,7 +34,7 @@ | @@ -34,7 +34,7 @@ | ||
| 34 | <script lang="ts" setup> | 34 | <script lang="ts" setup> |
| 35 | import { ref } from 'vue'; | 35 | import { ref } from 'vue'; |
| 36 | import { BasicForm, useForm } from '/@/components/Form'; | 36 | import { BasicForm, useForm } from '/@/components/Form'; |
| 37 | - import { step1Schemas } from './data'; | 37 | + import { step1Schemas } from '../device.profile.data'; |
| 38 | import { uploadApi } from '/@/api/personal/index'; | 38 | import { uploadApi } from '/@/api/personal/index'; |
| 39 | import { Upload } from 'ant-design-vue'; | 39 | import { Upload } from 'ant-design-vue'; |
| 40 | import { PlusOutlined, LoadingOutlined } from '@ant-design/icons-vue'; | 40 | import { PlusOutlined, LoadingOutlined } from '@ant-design/icons-vue'; |
| 1 | <template> | 1 | <template> |
| 2 | - <div class="step2-style"> | 2 | + <div |
| 3 | + class="step2-style" | ||
| 4 | + :style="[isMqttType == 'DEFAULT' ? { minHeight: 0 + 'px' } : { minHeight: 800 + 'px' }]" | ||
| 5 | + > | ||
| 3 | <div | 6 | <div |
| 4 | - style="margin-top: 0.1vh; height: 15vh" | ||
| 5 | :style="[ | 7 | :style="[ |
| 6 | isMqttType == 'MQTT' | 8 | isMqttType == 'MQTT' |
| 7 | ? { minHeight: 45 + 'vh' } | 9 | ? { minHeight: 45 + 'vh' } |
| @@ -40,7 +42,7 @@ | @@ -40,7 +42,7 @@ | ||
| 40 | <script lang="ts" setup> | 42 | <script lang="ts" setup> |
| 41 | import { reactive, ref, onUnmounted, nextTick } from 'vue'; | 43 | import { reactive, ref, onUnmounted, nextTick } from 'vue'; |
| 42 | import { BasicForm, useForm } from '/@/components/Form'; | 44 | import { BasicForm, useForm } from '/@/components/Form'; |
| 43 | - import { step2Schemas } from './data'; | 45 | + import { step2Schemas } from '../device.profile.data'; |
| 44 | import { Button } from '/@/components/Button'; | 46 | import { Button } from '/@/components/Button'; |
| 45 | import MqttCpns from './cpns/mqtt/Mqtt.vue'; | 47 | import MqttCpns from './cpns/mqtt/Mqtt.vue'; |
| 46 | import CoapCpns from './cpns/coap/Coap.vue'; | 48 | import CoapCpns from './cpns/coap/Coap.vue'; |
| @@ -52,7 +54,7 @@ | @@ -52,7 +54,7 @@ | ||
| 52 | const coapRef = ref<InstanceType<typeof CoapCpns>>(); | 54 | const coapRef = ref<InstanceType<typeof CoapCpns>>(); |
| 53 | const lwm2mRef = ref<InstanceType<typeof Lwm2mCpns>>(); | 55 | const lwm2mRef = ref<InstanceType<typeof Lwm2mCpns>>(); |
| 54 | const snmpRef = ref<InstanceType<typeof SnmpCpns>>(); | 56 | const snmpRef = ref<InstanceType<typeof SnmpCpns>>(); |
| 55 | - const isMqttType = ref(''); | 57 | + const isMqttType = ref('DEFAULT'); |
| 56 | let step2Data = reactive({ | 58 | let step2Data = reactive({ |
| 57 | transportConfiguration: {}, | 59 | transportConfiguration: {}, |
| 58 | }); | 60 | }); |
| @@ -75,7 +77,7 @@ | @@ -75,7 +77,7 @@ | ||
| 75 | }; | 77 | }; |
| 76 | 78 | ||
| 77 | const resetFormData = () => { | 79 | const resetFormData = () => { |
| 78 | - isMqttType.value = ''; | 80 | + isMqttType.value = 'DEFAULT'; |
| 79 | resetFields(); | 81 | resetFields(); |
| 80 | nextTick(() => { | 82 | nextTick(() => { |
| 81 | mqttRef.value?.resetFormData(); | 83 | mqttRef.value?.resetFormData(); |
| @@ -107,7 +109,7 @@ | @@ -107,7 +109,7 @@ | ||
| 107 | }); | 109 | }); |
| 108 | }); | 110 | }); |
| 109 | onUnmounted(() => { | 111 | onUnmounted(() => { |
| 110 | - isMqttType.value = ''; | 112 | + isMqttType.value = 'DEFAULT'; |
| 111 | }); | 113 | }); |
| 112 | const getFormData = async () => { | 114 | const getFormData = async () => { |
| 113 | const val = await validate(); | 115 | const val = await validate(); |
src/views/device/profiles/step/data.ts
deleted
100644 → 0
| 1 | -import { FormSchema } from '/@/components/Form'; | ||
| 2 | -import { deviceConfigGetRuleChain } from '/@/api/device/deviceConfigApi'; | ||
| 3 | -import { findDictItemByCode } from '/@/api/system/dict'; | ||
| 4 | - | ||
| 5 | -export const step1Schemas: FormSchema[] = [ | ||
| 6 | - { | ||
| 7 | - field: 'image', | ||
| 8 | - label: '上传图片', | ||
| 9 | - component: 'Input', | ||
| 10 | - slot: 'imageSelect', | ||
| 11 | - }, | ||
| 12 | - { | ||
| 13 | - field: 'name', | ||
| 14 | - label: '配置名称', | ||
| 15 | - required: true, | ||
| 16 | - component: 'Input', | ||
| 17 | - componentProps() { | ||
| 18 | - return { | ||
| 19 | - disabled: false, | ||
| 20 | - ength: 255, | ||
| 21 | - placeholder: '请输入配置名称', | ||
| 22 | - }; | ||
| 23 | - }, | ||
| 24 | - }, | ||
| 25 | - { | ||
| 26 | - field: 'defaultRuleChainId', | ||
| 27 | - label: '规则链', | ||
| 28 | - component: 'ApiSelect', | ||
| 29 | - componentProps: { | ||
| 30 | - api: async () => { | ||
| 31 | - const data = await deviceConfigGetRuleChain(); | ||
| 32 | - const returnData = data.map((m) => { | ||
| 33 | - return { | ||
| 34 | - getValueField: m.name, | ||
| 35 | - getKeyField: m.id.id, | ||
| 36 | - }; | ||
| 37 | - }); | ||
| 38 | - return returnData; | ||
| 39 | - }, | ||
| 40 | - labelField: 'getValueField', | ||
| 41 | - valueField: 'getKeyField', | ||
| 42 | - immediate: true, | ||
| 43 | - }, | ||
| 44 | - }, | ||
| 45 | - { | ||
| 46 | - field: 'defaultQueueName', | ||
| 47 | - label: '处理队列', | ||
| 48 | - component: 'ApiSelect', | ||
| 49 | - componentProps: { | ||
| 50 | - api: findDictItemByCode, | ||
| 51 | - params: { | ||
| 52 | - dictCode: 'queen_execute_sequence', | ||
| 53 | - }, | ||
| 54 | - labelField: 'itemText', | ||
| 55 | - valueField: 'itemValue', | ||
| 56 | - resultField: 'items', | ||
| 57 | - }, | ||
| 58 | - }, | ||
| 59 | - | ||
| 60 | - { | ||
| 61 | - label: '描述', | ||
| 62 | - field: 'description', | ||
| 63 | - component: 'InputTextArea', | ||
| 64 | - componentProps: { | ||
| 65 | - maxLength: 255, | ||
| 66 | - placeholder: '请输入描述', | ||
| 67 | - }, | ||
| 68 | - }, | ||
| 69 | -]; | ||
| 70 | - | ||
| 71 | -export const step2Schemas: FormSchema[] = [ | ||
| 72 | - { | ||
| 73 | - field: 'transportType', | ||
| 74 | - component: 'Select', | ||
| 75 | - label: '接入协议', | ||
| 76 | - defaultValue: 'DEFAULT', | ||
| 77 | - componentProps() { | ||
| 78 | - return { | ||
| 79 | - options: [ | ||
| 80 | - { label: '默认', value: 'DEFAULT' }, | ||
| 81 | - { label: 'MQTT', value: 'MQTT' }, | ||
| 82 | - { label: 'CoAP', value: 'COAP' }, | ||
| 83 | - { label: 'LWM2M', value: 'LWM2M' }, | ||
| 84 | - { label: 'SNMP', value: 'SNMP' }, | ||
| 85 | - ], | ||
| 86 | - }; | ||
| 87 | - }, | ||
| 88 | - colProps: { span: 10 }, | ||
| 89 | - }, | ||
| 90 | -]; |
| 1 | +<template> | ||
| 2 | + <div> | ||
| 3 | + <BasicForm @register="registerForm"> | ||
| 4 | + <template #scriptContent> | ||
| 5 | + <Card title="脚本内容" :bodyStyle="{ padding: 0, height: '280px' }"> | ||
| 6 | + <div ref="aceRef" class="overflow-hidden"></div> | ||
| 7 | + </Card> | ||
| 8 | + <Button @click="handleCopy" class="mt-4"> | ||
| 9 | + <template #icon> | ||
| 10 | + <CopyOutlined /> | ||
| 11 | + </template> | ||
| 12 | + copy | ||
| 13 | + </Button> | ||
| 14 | + </template> | ||
| 15 | + </BasicForm> | ||
| 16 | + </div> | ||
| 17 | +</template> | ||
| 18 | +<script setup lang="ts"> | ||
| 19 | + import { ref, unref } from 'vue'; | ||
| 20 | + import { formSchema } from './config.data'; | ||
| 21 | + import { BasicForm, useForm } from '/@/components/Form'; | ||
| 22 | + import ace from 'ace-builds'; | ||
| 23 | + import { Card, Button } from 'ant-design-vue'; | ||
| 24 | + import 'ace-builds/src-noconflict/theme-chrome'; // 默认设置的主题 | ||
| 25 | + import 'ace-builds/src-noconflict/mode-javascript'; // 默认设置的语言模式 | ||
| 26 | + import { beautify } from 'ace-builds/src-noconflict/ext-beautify.js'; | ||
| 27 | + import { CopyOutlined } from '@ant-design/icons-vue'; | ||
| 28 | + import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard'; | ||
| 29 | + import { useMessage } from '/@/hooks/web/useMessage'; | ||
| 30 | + | ||
| 31 | + defineEmits(['register']); | ||
| 32 | + const { createMessage } = useMessage(); | ||
| 33 | + const { clipboardRef, copiedRef } = useCopyToClipboard(); | ||
| 34 | + const aceEditor = ref(); | ||
| 35 | + const aceRef = ref(); | ||
| 36 | + const [registerForm, { validate, resetFields }] = useForm({ | ||
| 37 | + labelWidth: 120, | ||
| 38 | + schemas: formSchema, | ||
| 39 | + showActionButtonGroup: false, | ||
| 40 | + }); | ||
| 41 | + // 初始化编辑器 | ||
| 42 | + const initEditor = (jsScript?: string) => { | ||
| 43 | + aceEditor.value = ace.edit(aceRef.value, { | ||
| 44 | + maxLines: 12, // 最大行数,超过会自动出现滚动条 | ||
| 45 | + minLines: 12, // 最小行数,还未到最大行数时,编辑器会自动伸缩大小 | ||
| 46 | + fontSize: 14, // 编辑器内字体大小 | ||
| 47 | + theme: 'ace/theme/chrome', // 默认设置的主题 | ||
| 48 | + mode: 'ace/mode/javascript', // 默认设置的语言模式 | ||
| 49 | + tabSize: 2, // 制表符设置为 4 个空格大小 | ||
| 50 | + }); | ||
| 51 | + | ||
| 52 | + aceEditor.value.setOptions({ | ||
| 53 | + enableBasicAutocompletion: true, | ||
| 54 | + enableLiveAutocompletion: true, | ||
| 55 | + }); | ||
| 56 | + aceEditor.value.setValue( | ||
| 57 | + jsScript ?? | ||
| 58 | + ` | ||
| 59 | + var trimSource =source.replaceAll(" ",""); | ||
| 60 | + if(trimSource.length==26 && trimSource.startsWith("020308")){ | ||
| 61 | + var str = ""; | ||
| 62 | + for(var i = 6;i<20;i+=2){ | ||
| 63 | + str += String.fromCharCode(parseInt(trimSource[i]+trimSource[i+1],16)); | ||
| 64 | + }` | ||
| 65 | + ); | ||
| 66 | + beautify(aceEditor.value.session); | ||
| 67 | + }; | ||
| 68 | + const handleCopy = () => { | ||
| 69 | + const valueRef = aceEditor.value.getValue(); | ||
| 70 | + const value = unref(valueRef); | ||
| 71 | + if (!value) { | ||
| 72 | + createMessage.warning('请输入要拷贝的内容!'); | ||
| 73 | + return; | ||
| 74 | + } | ||
| 75 | + clipboardRef.value = value; | ||
| 76 | + if (unref(copiedRef)) { | ||
| 77 | + createMessage.success('复制成功!'); | ||
| 78 | + } | ||
| 79 | + }; | ||
| 80 | + const getFormData = async () => { | ||
| 81 | + const value = await validate(); | ||
| 82 | + if (!value) return; | ||
| 83 | + return value; | ||
| 84 | + }; | ||
| 85 | + const resetFormData = () => { | ||
| 86 | + resetFields(); | ||
| 87 | + }; | ||
| 88 | + | ||
| 89 | + defineExpose({ | ||
| 90 | + initEditor, | ||
| 91 | + getFormData, | ||
| 92 | + resetFormData, | ||
| 93 | + }); | ||
| 94 | +</script> | ||
| 95 | +<style lang="less" scoped> | ||
| 96 | + @import url('./ConverScriptModal.less'); | ||
| 97 | +</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 ref="converScriptRef" /> | ||
| 14 | + </BasicModal> | ||
| 15 | + </div> | ||
| 16 | +</template> | ||
| 17 | +<script setup lang="ts"> | ||
| 18 | + import { ref, computed, unref } from 'vue'; | ||
| 19 | + import { BasicModal, useModalInner } from '/@/components/Modal'; | ||
| 20 | + import ConverScript from './ConverScript.vue'; | ||
| 21 | + | ||
| 22 | + const converScriptRef = ref<InstanceType<typeof ConverScript>>(); | ||
| 23 | + const getTitle = computed(() => (isUpdate.value ? '编辑转换脚本' : '新增转换脚本')); | ||
| 24 | + const isUpdate = ref(false); | ||
| 25 | + const isViewDetail = ref(''); | ||
| 26 | + const [register, { setModalProps, closeModal }] = useModalInner(async (data) => { | ||
| 27 | + setModalProps({ loading: true }); | ||
| 28 | + isUpdate.value = data.isUpdate; | ||
| 29 | + isViewDetail.value = data.isView; | ||
| 30 | + converScriptRef.value?.initEditor(data.record?.configuration?.jsScript); | ||
| 31 | + setModalProps({ loading: false }); | ||
| 32 | + if (!unref(isViewDetail)) { | ||
| 33 | + const title = !unref(isUpdate) ? '编辑转换脚本' : '新增转换脚本'; | ||
| 34 | + setModalProps({ title, showOkBtn: true, showCancelBtn: true }); | ||
| 35 | + if (!unref(isUpdate)) { | ||
| 36 | + } | ||
| 37 | + } else { | ||
| 38 | + setModalProps({ showOkBtn: false, showCancelBtn: false, title: '查看转换脚本' }); | ||
| 39 | + } | ||
| 40 | + }); | ||
| 41 | + const handleSubmit = async () => { | ||
| 42 | + const val = await converScriptRef.value?.getFormData(); | ||
| 43 | + console.log(val); | ||
| 44 | + }; | ||
| 45 | + const handleCancel = () => { | ||
| 46 | + closeModal(); | ||
| 47 | + converScriptRef.value?.resetFormData(); | ||
| 48 | + }; | ||
| 49 | +</script> | ||
| 50 | +<style lang="less" scoped> | ||
| 51 | + @import url('./ConverScriptModal.less'); | ||
| 52 | +</style> |
| 1 | +import { BasicColumn, FormSchema } from '/@/components/Table'; | ||
| 2 | +import moment from 'moment'; | ||
| 3 | +import { h } from 'vue'; | ||
| 4 | +import { Tag } from 'ant-design-vue'; | ||
| 5 | + | ||
| 6 | +// 表格配置 | ||
| 7 | +export const columns: BasicColumn[] = [ | ||
| 8 | + { | ||
| 9 | + title: '脚本名称', | ||
| 10 | + dataIndex: 'reportConfigName', | ||
| 11 | + width: 80, | ||
| 12 | + }, | ||
| 13 | + { | ||
| 14 | + title: '脚本状态', | ||
| 15 | + dataIndex: 'organizationName', | ||
| 16 | + width: 120, | ||
| 17 | + customRender: ({ record }) => { | ||
| 18 | + const status = record.organizationName; | ||
| 19 | + const color = status == 1 ? 'green' : 'red'; | ||
| 20 | + const text = status == 1 ? '启用' : '禁用'; | ||
| 21 | + return h(Tag, { color: color }, () => text); | ||
| 22 | + }, | ||
| 23 | + }, | ||
| 24 | + { | ||
| 25 | + title: '脚本内容', | ||
| 26 | + dataIndex: 'dataType', | ||
| 27 | + width: 120, | ||
| 28 | + slots: { customRender: 'dataType' }, | ||
| 29 | + }, | ||
| 30 | + { | ||
| 31 | + title: '描述', | ||
| 32 | + dataIndex: 'executeWay', | ||
| 33 | + width: 120, | ||
| 34 | + }, | ||
| 35 | + { | ||
| 36 | + title: '创建日期', | ||
| 37 | + dataIndex: 'executeTime', | ||
| 38 | + width: 180, | ||
| 39 | + }, | ||
| 40 | +]; | ||
| 41 | + | ||
| 42 | +// 查询配置 | ||
| 43 | +export const searchFormSchema: FormSchema[] = [ | ||
| 44 | + { | ||
| 45 | + field: 'reportConfigName', | ||
| 46 | + label: '脚本名称', | ||
| 47 | + component: 'Input', | ||
| 48 | + colProps: { span: 6 }, | ||
| 49 | + componentProps: { | ||
| 50 | + maxLength: 36, | ||
| 51 | + placeholder: '请输入配置名称', | ||
| 52 | + }, | ||
| 53 | + }, | ||
| 54 | + { | ||
| 55 | + field: 'sendTime', | ||
| 56 | + label: '创建时间', | ||
| 57 | + component: 'RangePicker', | ||
| 58 | + componentProps: { | ||
| 59 | + showTime: { | ||
| 60 | + defaultValue: [moment('00:00:00', 'HH:mm:ss'), moment('23:59:59', 'HH:mm:ss')], | ||
| 61 | + }, | ||
| 62 | + }, | ||
| 63 | + colProps: { span: 6 }, | ||
| 64 | + }, | ||
| 65 | +]; | ||
| 66 | + | ||
| 67 | +// 新增编辑配置 | ||
| 68 | +export const formSchema: FormSchema[] = [ | ||
| 69 | + { | ||
| 70 | + field: 'name', | ||
| 71 | + label: '名称', | ||
| 72 | + colProps: { span: 24 }, | ||
| 73 | + required: true, | ||
| 74 | + component: 'Input', | ||
| 75 | + componentProps: { | ||
| 76 | + maxLength: 255, | ||
| 77 | + placeholder: '请输入脚本名称', | ||
| 78 | + }, | ||
| 79 | + }, | ||
| 80 | + { | ||
| 81 | + field: 'scriptContent', | ||
| 82 | + label: '脚本内容', | ||
| 83 | + required: true, | ||
| 84 | + component: 'Input', | ||
| 85 | + slot: 'scriptContent', | ||
| 86 | + colProps: { span: 24 }, | ||
| 87 | + }, | ||
| 88 | + { | ||
| 89 | + field: 'remark', | ||
| 90 | + label: '备注', | ||
| 91 | + colProps: { span: 24 }, | ||
| 92 | + component: 'InputTextArea', | ||
| 93 | + componentProps: { | ||
| 94 | + rows: 6, | ||
| 95 | + maxLength: 255, | ||
| 96 | + placeholder: '请输入备注', | ||
| 97 | + }, | ||
| 98 | + }, | ||
| 99 | +]; |
| 1 | +<template> | ||
| 2 | + <div> | ||
| 3 | + <BasicTable :clickToRowSelect="false" @register="registerTable" :searchInfo="searchInfo"> | ||
| 4 | + <template #toolbar> | ||
| 5 | + <Authority value=""> | ||
| 6 | + <a-button type="primary" @click="handleCreateOrEdit(null)"> 新增转换脚本 </a-button> | ||
| 7 | + </Authority> | ||
| 8 | + <Authority value=""> | ||
| 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 #dataType="{ 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: 'clarity:note-edit-line', | ||
| 30 | + auth: '', | ||
| 31 | + onClick: handleCreateOrEdit.bind(null, record), | ||
| 32 | + }, | ||
| 33 | + { | ||
| 34 | + label: '删除', | ||
| 35 | + icon: 'ant-design:delete-outlined', | ||
| 36 | + auth: '', | ||
| 37 | + color: 'error', | ||
| 38 | + popConfirm: { | ||
| 39 | + title: '是否确认删除', | ||
| 40 | + confirm: handleDeleteOrBatchDelete.bind(null, record), | ||
| 41 | + }, | ||
| 42 | + }, | ||
| 43 | + ]" | ||
| 44 | + /> | ||
| 45 | + </template> | ||
| 46 | + </BasicTable> | ||
| 47 | + <ConverScriptModal @register="registerModal" /> | ||
| 48 | + </div> | ||
| 49 | +</template> | ||
| 50 | + | ||
| 51 | +<script lang="ts" setup> | ||
| 52 | + import { reactive, nextTick } from 'vue'; | ||
| 53 | + import { BasicTable, useTable, TableAction } from '/@/components/Table'; | ||
| 54 | + import { searchFormSchema, columns } from './config.data'; | ||
| 55 | + import { Authority } from '/@/components/Authority'; | ||
| 56 | + import { useBatchDelete } from '/@/hooks/web/useBatchDelete'; | ||
| 57 | + import { Popconfirm } from 'ant-design-vue'; | ||
| 58 | + import { useModal } from '/@/components/Modal'; | ||
| 59 | + import ConverScriptModal from './ConverScriptModal.vue'; | ||
| 60 | + import { exportPage, deleteExportManage } from '/@/api/export/exportManager'; | ||
| 61 | + | ||
| 62 | + const searchInfo = reactive<Recordable>({}); | ||
| 63 | + const [registerTable, { reload, setProps, setTableData }] = useTable({ | ||
| 64 | + title: '转换脚本列表', | ||
| 65 | + api: exportPage, | ||
| 66 | + columns, | ||
| 67 | + showIndexColumn: false, | ||
| 68 | + clickToRowSelect: false, | ||
| 69 | + formConfig: { | ||
| 70 | + labelWidth: 120, | ||
| 71 | + schemas: searchFormSchema, | ||
| 72 | + fieldMapToTime: [['sendTime', ['startTime', 'endTime'], 'x']], | ||
| 73 | + }, | ||
| 74 | + useSearchForm: true, | ||
| 75 | + showTableSetting: true, | ||
| 76 | + bordered: true, | ||
| 77 | + rowKey: 'id', | ||
| 78 | + actionColumn: { | ||
| 79 | + width: 200, | ||
| 80 | + title: '操作', | ||
| 81 | + dataIndex: 'action', | ||
| 82 | + slots: { customRender: 'action' }, | ||
| 83 | + fixed: 'right', | ||
| 84 | + }, | ||
| 85 | + }); | ||
| 86 | + | ||
| 87 | + const handleSuccess = () => { | ||
| 88 | + reload(); | ||
| 89 | + }; | ||
| 90 | + | ||
| 91 | + const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions } = useBatchDelete( | ||
| 92 | + deleteExportManage, | ||
| 93 | + handleSuccess, | ||
| 94 | + setProps | ||
| 95 | + ); | ||
| 96 | + | ||
| 97 | + nextTick(() => { | ||
| 98 | + setProps(selectionOptions); | ||
| 99 | + }); | ||
| 100 | + | ||
| 101 | + const [registerModal, { openModal }] = useModal(); | ||
| 102 | + | ||
| 103 | + // 新增或编辑 | ||
| 104 | + const handleCreateOrEdit = (record: Recordable | null) => { | ||
| 105 | + setTableData([ | ||
| 106 | + { | ||
| 107 | + id: 1, | ||
| 108 | + reportConfigName: '11', | ||
| 109 | + organizationName: 0, | ||
| 110 | + dataType: '11', | ||
| 111 | + executeWay: '11', | ||
| 112 | + executeTime: '2022-05-21', | ||
| 113 | + }, | ||
| 114 | + { | ||
| 115 | + id: 2, | ||
| 116 | + reportConfigName: '11', | ||
| 117 | + organizationName: 0, | ||
| 118 | + dataType: '11', | ||
| 119 | + executeWay: '11', | ||
| 120 | + executeTime: '2022-05-21', | ||
| 121 | + }, | ||
| 122 | + ]); | ||
| 123 | + if (record) { | ||
| 124 | + openModal(true, { | ||
| 125 | + isUpdate: false, | ||
| 126 | + record, | ||
| 127 | + isView: false, | ||
| 128 | + }); | ||
| 129 | + } else { | ||
| 130 | + openModal(true, { | ||
| 131 | + isUpdate: true, | ||
| 132 | + isView: false, | ||
| 133 | + }); | ||
| 134 | + } | ||
| 135 | + }; | ||
| 136 | + const handleScriptView = (record: Recordable | null) => { | ||
| 137 | + if (record) { | ||
| 138 | + openModal(true, { | ||
| 139 | + isUpdate: true, | ||
| 140 | + record, | ||
| 141 | + isView: true, | ||
| 142 | + }); | ||
| 143 | + } | ||
| 144 | + }; | ||
| 145 | +</script> |