Commit 5945f8fe5844ec9706d0049a1ff58c27b372ed90

Authored by sqy
1 parent b042fdeb

'调整文件名称'

Too many changes to show.

To preserve performance only 24 of 49 files are displayed.

  1 +import { alarmLevel, statusType } from '/@/views/device/manage/config/detail.config';
  2 +import { FormSchema } from '/@/components/Form';
  3 +import { BasicColumn } from '/@/components/Table';
  4 +import moment from 'moment';
  5 +export const alarmSearchSchemas: FormSchema[] = [
  6 + {
  7 + field: 'status',
  8 + label: '告警状态',
  9 + component: 'Select',
  10 + colProps: { span: 6 },
  11 + componentProps: {
  12 + options: [
  13 + {
  14 + label: '清除未确认',
  15 + value: 'CLEARED_UNACK',
  16 + },
  17 + {
  18 + label: '激活未确认',
  19 + value: 'ACTIVE_UNACK',
  20 + },
  21 + {
  22 + label: '清除已确认',
  23 + value: 'CLEARED_ACK',
  24 + },
  25 + {
  26 + label: '激活已确认',
  27 + value: 'ACTIVE_ACK',
  28 + },
  29 + ],
  30 + },
  31 + },
  32 + {
  33 + field: 'alarmType',
  34 + label: '告警类型',
  35 + component: 'Input',
  36 + colProps: { span: 6 },
  37 + componentProps: {
  38 + maxLength: 255,
  39 + placeholder: '请输入告警类型',
  40 + },
  41 + dynamicRules: () => {
  42 + return [
  43 + {
  44 + required: false,
  45 + validator: (_, value) => {
  46 + if (String(value).length > 255) {
  47 + return Promise.reject('字数不超过255个字');
  48 + }
  49 + return Promise.resolve();
  50 + },
  51 + },
  52 + ];
  53 + },
  54 + },
  55 + {
  56 + field: 'endTime',
  57 + label: '告警时间',
  58 + component: 'DatePicker',
  59 + componentProps: {
  60 + valueFormat: 'x',
  61 + showTime: { defaultValue: moment('23:59:59', 'HH:mm:ss') },
  62 + },
  63 + colProps: { span: 6 },
  64 + },
  65 +];
  66 +export const alarmColumns: BasicColumn[] = [
  67 + {
  68 + title: '告警时间',
  69 + dataIndex: 'createdTime',
  70 + width: 120,
  71 + },
  72 + {
  73 + title: '告警设备',
  74 + dataIndex: 'deviceName',
  75 + width: 100,
  76 + },
  77 + {
  78 + title: '类型',
  79 + dataIndex: 'type',
  80 + width: 160,
  81 + },
  82 + {
  83 + title: '告警级别',
  84 + dataIndex: 'severity',
  85 + width: 160,
  86 + format: (text) => alarmLevel(text),
  87 + },
  88 + {
  89 + title: '状态',
  90 + dataIndex: 'status',
  91 + format: (text) => statusType(text),
  92 + width: 160,
  93 + },
  94 +];
  95 +
  96 +export const alarmSchemasForm: FormSchema[] = [
  97 + {
  98 + field: 'deviceName',
  99 + label: '告警设备',
  100 + component: 'Input',
  101 + componentProps: {
  102 + disabled: true,
  103 + },
  104 + },
  105 +
  106 + {
  107 + field: 'startTs',
  108 + label: '开始时间',
  109 + component: 'Input',
  110 + componentProps: {
  111 + disabled: true,
  112 + },
  113 + },
  114 + {
  115 + field: 'endTs',
  116 + label: '结束时间',
  117 + component: 'Input',
  118 + componentProps: {
  119 + disabled: true,
  120 + },
  121 + },
  122 + {
  123 + field: 'ackTs',
  124 + label: '处理时间',
  125 + component: 'Input',
  126 + componentProps: {
  127 + disabled: true,
  128 + },
  129 + ifShow: ({ values }) => values.status === '激活已确认' || values.status === '清除已确认',
  130 + },
  131 + {
  132 + field: 'clearTs',
  133 + label: '清除时间',
  134 + component: 'Input',
  135 + componentProps: {
  136 + disabled: true,
  137 + },
  138 + ifShow: ({ values }) => values.status === '清除已确认' || values.status === '清除未确认',
  139 + },
  140 + {
  141 + field: 'type',
  142 + label: '告警类型',
  143 + component: 'Input',
  144 + componentProps: {
  145 + disabled: true,
  146 + },
  147 + },
  148 + {
  149 + field: 'severity',
  150 + label: '严重程度',
  151 + component: 'Input',
  152 + componentProps: {
  153 + disabled: true,
  154 + },
  155 + },
  156 + {
  157 + field: 'status',
  158 + label: '状态',
  159 + component: 'Input',
  160 + componentProps: {
  161 + disabled: true,
  162 + },
  163 + },
  164 + {
  165 + field: 'details',
  166 + label: '详情',
  167 + component: 'InputTextArea',
  168 + },
  169 +];
... ...
  1 +<template>
  2 + <BasicDrawer v-bind="$attrs" title="告警详情" @register="registerDrawer" width="30%">
  3 + <BasicForm @register="registerForm" />
  4 + <div class="flex justify-end">
  5 + <a-button
  6 + type="primary"
  7 + class="mr-4"
  8 + @click="handleAlarm"
  9 + v-if="alarmStatus !== 'ACTIVE_ACK' && alarmStatus !== 'CLEARED_ACK'"
  10 + >处理</a-button
  11 + >
  12 + <a-button
  13 + danger
  14 + type="primary"
  15 + @click="clearAlarm"
  16 + v-if="alarmStatus !== 'CLEARED_UNACK' && alarmStatus !== 'CLEARED_ACK'"
  17 + >清除</a-button
  18 + >
  19 + </div>
  20 + </BasicDrawer>
  21 +</template>
  22 +
  23 +<script lang="ts">
  24 + import { defineComponent, ref, unref } from 'vue';
  25 + import { BasicForm, useForm } from '/@/components/Form';
  26 + import { alarmSchemasForm } from '../config/detail.config';
  27 + import { clearOrAckAlarm } from '/@/api/device/deviceManager';
  28 + import { alarmLevel, statusType } from '/@/views/device/manage/config/detail.config';
  29 + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  30 + export default defineComponent({
  31 + name: 'AlarmDetailDrawer',
  32 + components: {
  33 + BasicForm,
  34 + BasicDrawer,
  35 + },
  36 + emits: ['success', 'register'],
  37 + setup(_, { emit }) {
  38 + const [registerForm, { setFieldsValue, resetFields }] = useForm({
  39 + showActionButtonGroup: false,
  40 + schemas: alarmSchemasForm,
  41 + labelCol: {
  42 + span: 5,
  43 + },
  44 + });
  45 + const alarmId = ref('');
  46 + const alarmStatus = ref('');
  47 + const [registerDrawer, { closeDrawer }] = useDrawerInner(async (data) => {
  48 + await resetFields();
  49 + await setFieldsValue({
  50 + ...data,
  51 + severity: alarmLevel(data.severity),
  52 + status: statusType(data.status),
  53 + });
  54 + alarmStatus.value = data.status;
  55 + alarmId.value = data.id;
  56 + });
  57 + // 处理报警
  58 + const handleAlarm = async () => {
  59 + await clearOrAckAlarm(unref(alarmId), false);
  60 + emit('success');
  61 + closeDrawer();
  62 + };
  63 + // 清除报警
  64 + const clearAlarm = async () => {
  65 + await clearOrAckAlarm(unref(alarmId), true);
  66 + emit('success');
  67 + closeDrawer();
  68 + };
  69 + return {
  70 + registerDrawer,
  71 + registerForm,
  72 + clearAlarm,
  73 + handleAlarm,
  74 + alarmStatus,
  75 + };
  76 + },
  77 + });
  78 +</script>
  79 +
  80 +<style lang="less" scoped></style>
... ...
  1 +<template>
  2 + <div>
  3 + <BasicTable @register="registerTable">
  4 + <template #action="{ record }">
  5 + <TableAction
  6 + :actions="[
  7 + {
  8 + label: '详情',
  9 + icon: 'ant-design:eye-outlined',
  10 + onClick: handleDetail.bind(null, record),
  11 + },
  12 + ]"
  13 + />
  14 + </template>
  15 + </BasicTable>
  16 + <AlarmDetailDrawer @register="registerDetailDrawer" @success="handleSuccess" />
  17 + </div>
  18 +</template>
  19 +<script lang="ts">
  20 + import { defineComponent } from 'vue';
  21 + import { BasicTable, useTable, TableAction } from '/@/components/Table';
  22 + import { alarmColumns, alarmSearchSchemas } from './config/detail.config';
  23 + import { getDeviceAlarm } from '/@/api/device/deviceManager';
  24 + import { useDrawer } from '/@/components/Drawer';
  25 + import AlarmDetailDrawer from './cpns/AlarmDetailDrawer.vue';
  26 +
  27 + export default defineComponent({
  28 + name: 'AlarmCenter',
  29 + components: {
  30 + BasicTable,
  31 + TableAction,
  32 + AlarmDetailDrawer,
  33 + },
  34 +
  35 + setup() {
  36 + const [registerTable, { reload }] = useTable({
  37 + api: getDeviceAlarm,
  38 + columns: alarmColumns,
  39 + formConfig: {
  40 + labelWidth: 120,
  41 + schemas: alarmSearchSchemas,
  42 + },
  43 + useSearchForm: true,
  44 + bordered: true,
  45 + showIndexColumn: false,
  46 + showTableSetting: true,
  47 + actionColumn: {
  48 + width: 200,
  49 + title: '操作',
  50 + slots: { customRender: 'action' },
  51 + fixed: 'right',
  52 + },
  53 + beforeFetch: (data) => {
  54 + Reflect.set(data, 'startTime', null);
  55 + },
  56 + });
  57 + const [registerDetailDrawer, { openDrawer }] = useDrawer();
  58 + const handleDetail = (record: Recordable) => {
  59 + openDrawer(true, record);
  60 + };
  61 + const handleSuccess = () => {
  62 + reload();
  63 + };
  64 + return {
  65 + registerTable,
  66 + registerDetailDrawer,
  67 + handleDetail,
  68 + handleSuccess,
  69 + };
  70 + },
  71 + });
  72 +</script>
... ...
  1 +<template>
  2 + <BasicDrawer
  3 + v-bind="$attrs"
  4 + @register="registerDrawer"
  5 + showFooter
  6 + :title="getTitle"
  7 + width="30%"
  8 + @ok="handleSubmit"
  9 + >
  10 + <BasicForm @register="registerForm" />
  11 + </BasicDrawer>
  12 +</template>
  13 +<script lang="ts">
  14 + import { defineComponent, ref, computed, unref } from 'vue';
  15 + import { BasicForm, useForm } from '/@/components/Form';
  16 + import { formSchema } from './config.data';
  17 + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  18 + import { saveOrEditAlarmContact } from '/@/api/alarm/contact/alarmContact';
  19 + import { useMessage } from '/@/hooks/web/useMessage';
  20 +
  21 + export default defineComponent({
  22 + name: 'ContactDrawer',
  23 + components: { BasicDrawer, BasicForm },
  24 + emits: ['success', 'register'],
  25 + setup(_, { emit }) {
  26 + const isUpdate = ref(true);
  27 +
  28 + const [registerForm, { validate, setFieldsValue, resetFields }] = useForm({
  29 + labelWidth: 120,
  30 + schemas: formSchema,
  31 + showActionButtonGroup: false,
  32 + });
  33 +
  34 + const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
  35 + await resetFields();
  36 + setDrawerProps({ confirmLoading: false });
  37 + isUpdate.value = !!data?.isUpdate;
  38 + if (unref(isUpdate)) {
  39 + if (data.record.organizationDTO) {
  40 + await setFieldsValue(data.record);
  41 + } else {
  42 + Reflect.deleteProperty(data.record, 'organizationId');
  43 + await setFieldsValue(data.record);
  44 + }
  45 + }
  46 + });
  47 +
  48 + const getTitle = computed(() => (!unref(isUpdate) ? '新增联系人配置' : '编辑联系人配置'));
  49 +
  50 + async function handleSubmit() {
  51 + try {
  52 + const { createMessage } = useMessage();
  53 + const values = await validate();
  54 + setDrawerProps({ confirmLoading: true });
  55 + let saveMessage = '添加成功';
  56 + let updateMessage = '修改成功';
  57 + await saveOrEditAlarmContact(values, unref(isUpdate));
  58 + closeDrawer();
  59 + emit('success');
  60 + createMessage.success(unref(isUpdate) ? updateMessage : saveMessage);
  61 + } finally {
  62 + setDrawerProps({ confirmLoading: false });
  63 + }
  64 + }
  65 +
  66 + return {
  67 + getTitle,
  68 + registerDrawer,
  69 + registerForm,
  70 + handleSubmit,
  71 + };
  72 + },
  73 + });
  74 +</script>
... ...
  1 +import { BasicColumn, FormSchema } from '/@/components/Table';
  2 +import { getOrganizationList } from '/@/api/system/system';
  3 +import { copyTransFun } from '/@/utils/fnUtils';
  4 +import { emailRule, phoneRule } from '/@/utils/rules';
  5 +
  6 +// 表格列数据
  7 +export const columns: BasicColumn[] = [
  8 + {
  9 + title: '姓名',
  10 + dataIndex: 'username',
  11 + width: 120,
  12 + },
  13 + {
  14 + title: '所属组织',
  15 + dataIndex: 'organizationDTO.name',
  16 + width: 160,
  17 + },
  18 + {
  19 + title: '手机',
  20 + dataIndex: 'phone',
  21 + width: 160,
  22 + },
  23 + {
  24 + title: '邮箱',
  25 + dataIndex: 'email',
  26 + width: 160,
  27 + },
  28 + {
  29 + title: '微信',
  30 + dataIndex: 'wechat',
  31 + width: 180,
  32 + },
  33 + {
  34 + title: '备注',
  35 + dataIndex: 'remark',
  36 + width: 120,
  37 + },
  38 +
  39 + {
  40 + title: '添加时间',
  41 + dataIndex: 'createTime',
  42 + width: 180,
  43 + },
  44 + {
  45 + title: '更新时间',
  46 + dataIndex: 'updateTime',
  47 + width: 180,
  48 + },
  49 +];
  50 +
  51 +// 查询字段
  52 +export const searchFormSchema: FormSchema[] = [
  53 + {
  54 + field: 'username',
  55 + label: '联系人姓名',
  56 + component: 'Input',
  57 + colProps: { span: 8 },
  58 + componentProps: {
  59 + maxLength: 36,
  60 + placeholder: '请输入联系人姓名',
  61 + },
  62 + },
  63 +];
  64 +
  65 +// 弹框配置项
  66 +export const formSchema: FormSchema[] = [
  67 + {
  68 + field: 'username',
  69 + label: '联系人姓名',
  70 + required: true,
  71 + component: 'Input',
  72 + componentProps: {
  73 + placeholder: '请输入联系人姓名',
  74 + maxLength: 255,
  75 + },
  76 + },
  77 + {
  78 + field: 'organizationId',
  79 + label: '所属组织',
  80 + component: 'ApiTreeSelect',
  81 + componentProps: {
  82 + api: async () => {
  83 + const data = await getOrganizationList();
  84 + copyTransFun(data as any as any[]);
  85 + return data;
  86 + },
  87 + },
  88 + },
  89 + {
  90 + field: 'phone',
  91 + label: '手机号码',
  92 + component: 'Input',
  93 + componentProps: {
  94 + placeholder: '请输入手机号码',
  95 + },
  96 + rules: phoneRule,
  97 + },
  98 + {
  99 + field: 'email',
  100 + label: '电子邮箱',
  101 + component: 'Input',
  102 + componentProps: {
  103 + placeholder: '请输入电子邮箱',
  104 + },
  105 + rules: emailRule,
  106 + },
  107 + {
  108 + field: 'wechat',
  109 + label: '微信',
  110 + component: 'Input',
  111 + componentProps: {
  112 + placeholder: '请输入微信号',
  113 + maxLength: 255,
  114 + },
  115 + },
  116 + {
  117 + field: 'remark',
  118 + label: '备注',
  119 + component: 'InputTextArea',
  120 + componentProps: {
  121 + placeholder: '请输入备注',
  122 + maxLength: 255,
  123 + },
  124 + },
  125 + {
  126 + field: 'id',
  127 + label: '',
  128 + component: 'Input',
  129 + show: false,
  130 + componentProps: {
  131 + maxLength: 36,
  132 + placeholder: 'id',
  133 + },
  134 + },
  135 +];
... ...
  1 +<template>
  2 + <div>
  3 + <PageWrapper dense contentFullHeight contentClass="flex">
  4 + <OrganizationIdTree
  5 + class="w-1/4 xl:w-1/5"
  6 + @select="handleSelect"
  7 + ref="organizationIdTreeRef"
  8 + />
  9 + <BasicTable @register="registerTable" :searchInfo="searchInfo" class="w-3/4 xl:w-4/5">
  10 + <template #toolbar>
  11 + <a-button type="primary" @click="handleCreateOrEdit(null)"> 新增告警联系人 </a-button>
  12 + <a-button
  13 + type="primary"
  14 + color="error"
  15 + @click="handleDeleteOrBatchDelete(null)"
  16 + :disabled="hasBatchDelete"
  17 + >
  18 + 批量删除
  19 + </a-button>
  20 + </template>
  21 + <template #action="{ record }">
  22 + <TableAction
  23 + :actions="[
  24 + {
  25 + label: '编辑',
  26 + icon: 'clarity:note-edit-line',
  27 + onClick: handleCreateOrEdit.bind(null, record),
  28 + },
  29 + {
  30 + label: '删除',
  31 + icon: 'ant-design:delete-outlined',
  32 + color: 'error',
  33 + popConfirm: {
  34 + title: '是否确认删除',
  35 + confirm: handleDeleteOrBatchDelete.bind(null, record),
  36 + },
  37 + },
  38 + ]"
  39 + />
  40 + </template>
  41 + </BasicTable>
  42 + </PageWrapper>
  43 + <ContactDrawer @register="registerDrawer" @success="handleSuccess" />
  44 + </div>
  45 +</template>
  46 +
  47 +<script lang="ts">
  48 + import { defineComponent, reactive, ref, computed } from 'vue';
  49 + import { BasicTable, useTable, TableAction } from '/@/components/Table';
  50 + import { PageWrapper } from '/@/components/Page';
  51 + import { useMessage } from '/@/hooks/web/useMessage';
  52 + import { useDrawer } from '/@/components/Drawer';
  53 + import ContactDrawer from './ContactDrawer.vue';
  54 + import { useResetOrganizationTree, OrganizationIdTree } from '/@/views/common/organizationIdTree';
  55 +
  56 + import { getAlarmContact, deleteAlarmContact } from '/@/api/alarm/contact/alarmContact';
  57 + import { searchFormSchema, columns } from './config.data';
  58 + export default defineComponent({
  59 + components: {
  60 + PageWrapper,
  61 + OrganizationIdTree,
  62 + BasicTable,
  63 + TableAction,
  64 + ContactDrawer,
  65 + },
  66 + setup() {
  67 + let selectedRowIds = ref<string[]>([]);
  68 + const hasBatchDelete = computed(() => selectedRowIds.value.length <= 0);
  69 + // 复选框事件
  70 + const onSelectRowChange = (selectedRowKeys: string[]) => {
  71 + selectedRowIds.value = selectedRowKeys;
  72 + };
  73 + const searchInfo = reactive<Recordable>({});
  74 + const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo);
  75 + // 表格hooks
  76 + const [registerTable, { reload }] = useTable({
  77 + api: getAlarmContact,
  78 + columns,
  79 + clickToRowSelect: false,
  80 + formConfig: {
  81 + labelWidth: 120,
  82 + schemas: searchFormSchema,
  83 + resetFunc: resetFn,
  84 + },
  85 + useSearchForm: true,
  86 + showTableSetting: true,
  87 + bordered: true,
  88 + rowSelection: {
  89 + onChange: onSelectRowChange,
  90 + type: 'checkbox',
  91 + },
  92 + rowKey: 'id',
  93 + actionColumn: {
  94 + width: 200,
  95 + title: '操作',
  96 + dataIndex: 'action',
  97 + slots: { customRender: 'action' },
  98 + fixed: 'right',
  99 + },
  100 + });
  101 + // 弹框
  102 + const [registerDrawer, { openDrawer }] = useDrawer();
  103 + const { createMessage } = useMessage();
  104 +
  105 + // 刷新
  106 + const handleSuccess = () => {
  107 + reload();
  108 + };
  109 + // 新增或编辑
  110 + const handleCreateOrEdit = (record: Recordable | null) => {
  111 + if (record) {
  112 + openDrawer(true, {
  113 + isUpdate: true,
  114 + record,
  115 + });
  116 + } else {
  117 + openDrawer(true, {
  118 + isUpdate: false,
  119 + });
  120 + }
  121 + };
  122 + // 删除或批量删除
  123 + const handleDeleteOrBatchDelete = async (record: Recordable | null) => {
  124 + if (record) {
  125 + try {
  126 + await deleteAlarmContact([record.id]);
  127 + createMessage.success('删除联系人成功');
  128 + handleSuccess();
  129 + } catch (e) {
  130 + createMessage.error('删除失败');
  131 + }
  132 + } else {
  133 + try {
  134 + await deleteAlarmContact(selectedRowIds.value);
  135 + createMessage.success('批量删除联系人成功');
  136 + selectedRowIds.value = [];
  137 + handleSuccess();
  138 + } catch (e) {
  139 + createMessage.info('删除失败');
  140 + }
  141 + }
  142 + };
  143 +
  144 + // 树形选择器
  145 + const handleSelect = (organizationId: string) => {
  146 + searchInfo.organizationId = organizationId;
  147 + handleSuccess();
  148 + };
  149 + return {
  150 + searchInfo,
  151 + hasBatchDelete,
  152 + handleCreateOrEdit,
  153 + handleDeleteOrBatchDelete,
  154 + handleSelect,
  155 + handleSuccess,
  156 + registerTable,
  157 + registerDrawer,
  158 + organizationIdTreeRef,
  159 + };
  160 + },
  161 + });
  162 +</script>
... ...
  1 +<template>
  2 + <BasicDrawer
  3 + v-bind="$attrs"
  4 + @register="registerDrawer"
  5 + showFooter
  6 + :title="getTitle"
  7 + width="500px"
  8 + @ok="handleSubmit"
  9 + >
  10 + <BasicForm @register="registerForm" />
  11 + </BasicDrawer>
  12 +</template>
  13 +<script lang="ts">
  14 + import { defineComponent, ref, computed, unref } from 'vue';
  15 + import { BasicForm, useForm } from '/@/components/Form';
  16 + import { formSchema } from './config.data';
  17 + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  18 + import { saveOrEditMessageConfig } from '/@/api/message/config';
  19 + import { useMessage } from '/@/hooks/web/useMessage';
  20 +
  21 + export default defineComponent({
  22 + name: 'ConfigDrawer',
  23 + components: { BasicDrawer, BasicForm },
  24 + emits: ['success', 'register'],
  25 + setup(_, { emit }) {
  26 + const isUpdate = ref(true);
  27 +
  28 + const [registerForm, { validate, setFieldsValue, resetFields }] = useForm({
  29 + labelWidth: 120,
  30 + schemas: formSchema,
  31 + showActionButtonGroup: false,
  32 + });
  33 +
  34 + const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
  35 + await resetFields();
  36 + setDrawerProps({ confirmLoading: false });
  37 + isUpdate.value = !!data?.isUpdate;
  38 + if (unref(isUpdate)) {
  39 + const config = data.record.config;
  40 + for (const key in config) {
  41 + Reflect.set(data.record, key + '', config[key]);
  42 + }
  43 + await setFieldsValue({
  44 + ...data.record,
  45 + });
  46 + }
  47 + });
  48 +
  49 + const getTitle = computed(() => (!unref(isUpdate) ? '新增消息配置' : '编辑消息配置'));
  50 +
  51 + async function handleSubmit() {
  52 + try {
  53 + const values = await validate();
  54 + const { createMessage } = useMessage();
  55 + setDrawerProps({ confirmLoading: true });
  56 + let config = {};
  57 + if (values.messageType === 'PHONE_MESSAGE') {
  58 + config = {
  59 + accessKeyId: values.accessKeyId,
  60 + accessKeySecret: values.accessKeySecret,
  61 + };
  62 + } else if (values.messageType === 'EMAIL_MESSAGE') {
  63 + config = {
  64 + host: values.host,
  65 + port: values.port,
  66 + username: values.username,
  67 + password: values.password,
  68 + };
  69 + }
  70 + Reflect.set(values, 'config', config);
  71 + let saveMessage = '添加成功';
  72 + let updateMessage = '修改成功';
  73 + await saveOrEditMessageConfig(values, unref(isUpdate));
  74 + closeDrawer();
  75 + emit('success');
  76 + createMessage.success(unref(isUpdate) ? updateMessage : saveMessage);
  77 + } finally {
  78 + setDrawerProps({ confirmLoading: false });
  79 + }
  80 + }
  81 +
  82 + return {
  83 + registerDrawer,
  84 + registerForm,
  85 + getTitle,
  86 + handleSubmit,
  87 + };
  88 + },
  89 + });
  90 +</script>
... ...
  1 +import { BasicColumn } from '/@/components/Table';
  2 +import { FormSchema } from '/@/components/Table';
  3 +import { findDictItemByCode } from '/@/api/system/dict';
  4 +
  5 +export const columns: BasicColumn[] = [
  6 + {
  7 + title: '场景联动名称',
  8 + dataIndex: 'name',
  9 + },
  10 + {
  11 + title: '触发方式',
  12 + // dataIndex: 'name',
  13 + width: 200,
  14 + },
  15 + {
  16 + title: '状态',
  17 + dataIndex: 'status',
  18 + width: 200,
  19 + },
  20 + {
  21 + title: '描述',
  22 + dataIndex: 'description',
  23 + width: 180,
  24 + },
  25 +];
  26 +
  27 +export const formSchema: FormSchema[] = [
  28 + {
  29 + field: 'configName',
  30 + label: '场景联动名称',
  31 + required: true,
  32 + component: 'Input',
  33 + },
  34 + {
  35 + field: 'messageType',
  36 + label: '所属组织',
  37 + required: true,
  38 + component: 'ApiSelect',
  39 + componentProps: {
  40 + api: findDictItemByCode,
  41 + params: {
  42 + dictCode: 'message_type',
  43 + },
  44 + labelField: 'itemText',
  45 + valueField: 'itemValue',
  46 + },
  47 + },
  48 + {
  49 + field: 'no1',
  50 + label: '触发器',
  51 + required: true,
  52 + component: 'Input',
  53 + },
  54 + {
  55 + field: 'no2',
  56 + label: '执行条件',
  57 + required: true,
  58 + component: 'Input',
  59 + },
  60 + {
  61 + field: 'no3',
  62 + label: '执行动作',
  63 + required: true,
  64 + component: 'Input',
  65 + },
  66 +];
... ...
  1 +<template>
  2 + <div class="p-4">
  3 + <BasicTable @register="registerTable">
  4 + <template #toolbar>
  5 + <a-button type="primary" @click="handleCreate"> 新增设备 </a-button>
  6 + </template>
  7 + <template #config="{ record }">
  8 + <a-button type="link" class="ml-2" @click="showData(record)"> 查看配置 </a-button>
  9 + </template>
  10 + <template #deviceProfile="{ record }">
  11 + <a-button type="link" class="ml-2" @click="goDeviceProfile">
  12 + {{ record.deviceProfile.name }}
  13 + </a-button>
  14 + </template>
  15 + <template #deviceType="{ record }">
  16 + <Tag color="success" class="ml-2">
  17 + {{
  18 + record.deviceType == DeviceTypeEnum.GATEWAY
  19 + ? '网关设备'
  20 + : record.deviceType == DeviceTypeEnum.DIRECT_CONNECTION
  21 + ? '直连设备'
  22 + : '网关子设备'
  23 + }}
  24 + </Tag>
  25 + </template>
  26 + <template #deviceState="{ record }">
  27 + <Tag
  28 + :color="
  29 + record.deviceState == DeviceState.INACTIVE
  30 + ? 'warning'
  31 + : record.deviceState == DeviceState.ONLINE
  32 + ? 'success'
  33 + : 'error'
  34 + "
  35 + class="ml-2"
  36 + >
  37 + {{
  38 + record.deviceState == DeviceState.INACTIVE
  39 + ? '待激活'
  40 + : record.deviceState == DeviceState.ONLINE
  41 + ? '在线'
  42 + : '离线'
  43 + }}
  44 + </Tag>
  45 + </template>
  46 + <template #action="{ record }">
  47 + <TableAction
  48 + :actions="[
  49 + {
  50 + label: '编辑',
  51 + icon: 'clarity:note-edit-line',
  52 + onClick: handleEdit.bind(null, record),
  53 + },
  54 + {
  55 + label: '删除',
  56 + icon: 'ant-design:delete-outlined',
  57 + color: 'error',
  58 + popConfirm: {
  59 + title: '是否确认删除',
  60 + confirm: handleDelete.bind(null, record),
  61 + },
  62 + },
  63 + ]"
  64 + />
  65 + </template>
  66 + </BasicTable>
  67 + <RuleEngineDrawer @register="registerDrawer" @success="handleSuccess" />
  68 + </div>
  69 +</template>
  70 +<script lang="ts">
  71 + import { defineComponent, h } from 'vue';
  72 + import { DeviceState, DeviceTypeEnum } from '/@/api/device/model/deviceModel';
  73 + import { BasicTable, useTable, TableAction } from '/@/components/Table';
  74 + import { useDrawer } from '/@/components/Drawer';
  75 + import RuleEngineDrawer from './RuleEngineDrawer.vue';
  76 + import { columns } from './config.data';
  77 + import { Modal, Tag } from 'ant-design-vue';
  78 + import { useMessage } from '/@/hooks/web/useMessage';
  79 + import { deleteDevice, devicePage } from '/@/api/device/deviceManager';
  80 + import { PageEnum } from '/@/enums/pageEnum';
  81 + import { useGo } from '/@/hooks/web/usePage';
  82 +
  83 + export default defineComponent({
  84 + name: 'DeviceManagement',
  85 + components: { BasicTable, RuleEngineDrawer, TableAction, Tag },
  86 + setup() {
  87 + const [registerDrawer, { openDrawer }] = useDrawer();
  88 + const { createMessage } = useMessage();
  89 + const go = useGo();
  90 + const [registerTable, { reload }] = useTable({
  91 + title: '设备列表',
  92 + api: devicePage,
  93 + columns,
  94 + useSearchForm: false,
  95 + showTableSetting: true,
  96 + bordered: true,
  97 + showIndexColumn: false,
  98 + actionColumn: {
  99 + width: 200,
  100 + title: '操作',
  101 + dataIndex: 'action',
  102 + slots: { customRender: 'action' },
  103 + fixed: 'right',
  104 + },
  105 + });
  106 +
  107 + function handleCreate() {
  108 + openDrawer(true, {
  109 + isUpdate: false,
  110 + });
  111 + }
  112 +
  113 + function handleEdit(record: Recordable) {
  114 + openDrawer(true, {
  115 + record,
  116 + isUpdate: true,
  117 + });
  118 + }
  119 +
  120 + function handleDelete(record: Recordable) {
  121 + let ids = [record.id];
  122 + deleteDevice(ids).then(() => {
  123 + createMessage.success('删除设备成功');
  124 + handleSuccess();
  125 + });
  126 + }
  127 +
  128 + function handleSuccess() {
  129 + reload();
  130 + }
  131 + function showData(record: Recordable) {
  132 + Modal.info({
  133 + title: '当前配置',
  134 + width: 480,
  135 + content: h(JsonPreview, { data: JSON.parse(JSON.stringify(record.deviceInfo)) }),
  136 + });
  137 + }
  138 + function goDeviceProfile() {
  139 + go(PageEnum.DEVICE_PROFILE);
  140 + }
  141 + return {
  142 + registerTable,
  143 + registerDrawer,
  144 + showData,
  145 + handleCreate,
  146 + handleEdit,
  147 + handleDelete,
  148 + handleSuccess,
  149 + goDeviceProfile,
  150 + DeviceTypeEnum,
  151 + DeviceState,
  152 + };
  153 + },
  154 + });
  155 +</script>
... ...
  1 +import type { BasicColumn } from '/@/components/Table';
  2 +import type { FormSchema } from '/@/components/Table';
  3 +import { getOrganizationList } from '/@/api/system/system';
  4 +import { copyTransFun } from '/@/utils/fnUtils';
  5 +import { getDeviceProfile } from '/@/api/alarm/position';
  6 +
  7 +export enum AggregateDataEnum {
  8 + MIN = 'MIN',
  9 + MAX = 'MAX',
  10 + AVG = 'AVG',
  11 + SUM = 'SUM',
  12 + COUNT = 'COUNT',
  13 + NONE = 'NONE',
  14 +}
  15 +export const formSchema: FormSchema[] = [
  16 + {
  17 + field: 'organizationId',
  18 + label: '',
  19 + component: 'ApiTreeSelect',
  20 + componentProps: {
  21 + placeholder: '请选择组织',
  22 + api: async () => {
  23 + const data = await getOrganizationList();
  24 + copyTransFun(data as any as any[]);
  25 + return data;
  26 + },
  27 + },
  28 + },
  29 + {
  30 + field: 'profileId',
  31 + label: '',
  32 + component: 'ApiSelect',
  33 + componentProps: {
  34 + api: getDeviceProfile,
  35 + placeholder: '请选择设备配置',
  36 + labelField: 'name',
  37 + valueField: 'id',
  38 + },
  39 + },
  40 + {
  41 + field: 'name',
  42 + label: '',
  43 + component: 'Input',
  44 + componentProps: {
  45 + maxLength: 255,
  46 + placeholder: '请输入设备名称',
  47 + },
  48 + },
  49 + {
  50 + field: 'deviceState',
  51 + label: '',
  52 + component: 'RadioGroup',
  53 + componentProps: {
  54 + size: 'small',
  55 + options: [
  56 + { label: '全部', value: '' },
  57 + { label: '待激活', value: 'INACTIVE' },
  58 + { label: '在线', value: 'ONLINE' },
  59 + { label: '离线', value: 'OFFLINE' },
  60 + ],
  61 + },
  62 + },
  63 + {
  64 + field: 'alarmStatus',
  65 + label: '是否告警',
  66 + component: 'RadioGroup',
  67 + labelWidth: '85px',
  68 + componentProps: {
  69 + size: 'small',
  70 + options: [
  71 + { label: '是', value: '1' },
  72 + { label: '否', value: '0' },
  73 + ],
  74 + },
  75 + },
  76 +];
  77 +
  78 +export const columns: BasicColumn[] = [
  79 + {
  80 + title: '名称',
  81 + dataIndex: 'name',
  82 + width: 100,
  83 + },
  84 + {
  85 + title: '位置',
  86 + dataIndex: 'deviceInfo.address',
  87 + width: 100,
  88 + },
  89 + {
  90 + title: '状态',
  91 + dataIndex: 'deviceState',
  92 + width: 100,
  93 + slots: { customRender: 'deviceState' },
  94 + },
  95 +];
  96 +
  97 +// 动态生成options
  98 +function generateOptions(value: number) {
  99 + if (value === 3600000) {
  100 + return [
  101 + {
  102 + label: '10秒',
  103 + value: 10000,
  104 + },
  105 + {
  106 + label: '15秒',
  107 + value: 15000,
  108 + },
  109 + {
  110 + label: '30秒',
  111 + value: 30000,
  112 + },
  113 + {
  114 + label: '1分钟',
  115 + value: 60000,
  116 + },
  117 + {
  118 + label: '2分钟',
  119 + value: 120000,
  120 + },
  121 + {
  122 + label: '5分钟',
  123 + value: 300000,
  124 + },
  125 + ];
  126 + } else if (value === 7200000) {
  127 + return [
  128 + {
  129 + label: '15秒',
  130 + value: 15000,
  131 + },
  132 + {
  133 + label: '30秒',
  134 + value: 30000,
  135 + },
  136 + {
  137 + label: '1分钟',
  138 + value: 60000,
  139 + },
  140 + {
  141 + label: '2分钟',
  142 + value: 120000,
  143 + },
  144 + {
  145 + label: '5分钟',
  146 + value: 300000,
  147 + },
  148 + {
  149 + label: '10分钟',
  150 + value: 600000,
  151 + },
  152 + {
  153 + label: '15分钟',
  154 + value: 900000,
  155 + },
  156 + ];
  157 + } else if (value === 18000000) {
  158 + return [
  159 + {
  160 + label: '1分钟',
  161 + value: 60000,
  162 + },
  163 + {
  164 + label: '2分钟',
  165 + value: 120000,
  166 + },
  167 + {
  168 + label: '5分钟',
  169 + value: 300000,
  170 + },
  171 + {
  172 + label: '10分钟',
  173 + value: 600000,
  174 + },
  175 + {
  176 + label: '15分钟',
  177 + value: 900000,
  178 + },
  179 + {
  180 + label: '30分钟',
  181 + value: 1800000,
  182 + },
  183 + ];
  184 + } else if (value === 36000000) {
  185 + return [
  186 + {
  187 + label: '2分钟',
  188 + value: 120000,
  189 + },
  190 + {
  191 + label: '5分钟',
  192 + value: 300000,
  193 + },
  194 + {
  195 + label: '10分钟',
  196 + value: 600000,
  197 + },
  198 + {
  199 + label: '15分钟',
  200 + value: 900000,
  201 + },
  202 + {
  203 + label: '30分钟',
  204 + value: 1800000,
  205 + },
  206 + {
  207 + label: '1小时',
  208 + value: 3600000,
  209 + },
  210 + ];
  211 + } else if (value === 43200000) {
  212 + return [
  213 + {
  214 + label: '2分钟',
  215 + value: 120000,
  216 + },
  217 + {
  218 + label: '5分钟',
  219 + value: 300000,
  220 + },
  221 + {
  222 + label: '10分钟',
  223 + value: 600000,
  224 + },
  225 + {
  226 + label: '15分钟',
  227 + value: 900000,
  228 + },
  229 + {
  230 + label: '30分钟',
  231 + value: 1800000,
  232 + },
  233 + {
  234 + label: '1小时',
  235 + value: 3600000,
  236 + },
  237 + ];
  238 + } else if (value === 86400000) {
  239 + return [
  240 + {
  241 + label: '5分钟',
  242 + value: 300000,
  243 + },
  244 + {
  245 + label: '10分钟',
  246 + value: 600000,
  247 + },
  248 + {
  249 + label: '15分钟',
  250 + value: 900000,
  251 + },
  252 + {
  253 + label: '30分钟',
  254 + value: 1800000,
  255 + },
  256 + {
  257 + label: '1小时',
  258 + value: 3600000,
  259 + },
  260 + {
  261 + label: '2小时',
  262 + value: 7200000,
  263 + },
  264 + ];
  265 + } else if (value === 604800000) {
  266 + return [
  267 + {
  268 + label: '30分钟',
  269 + value: 1800000,
  270 + },
  271 + {
  272 + label: '1小时',
  273 + value: 3600000,
  274 + },
  275 + {
  276 + label: '2小时',
  277 + value: 7200000,
  278 + },
  279 + {
  280 + label: '5小时',
  281 + value: 18000000,
  282 + },
  283 + {
  284 + label: '10小时',
  285 + value: 36000000,
  286 + },
  287 + {
  288 + label: '12小时',
  289 + value: 43200000,
  290 + },
  291 + {
  292 + label: '1天',
  293 + value: 86400000,
  294 + },
  295 + ];
  296 + } else {
  297 + return [
  298 + {
  299 + label: '2小时',
  300 + value: 7200000,
  301 + },
  302 + {
  303 + label: '5小时',
  304 + value: 18000000,
  305 + },
  306 + {
  307 + label: '10小时',
  308 + value: 36000000,
  309 + },
  310 + {
  311 + label: '12小时',
  312 + value: 43200000,
  313 + },
  314 + {
  315 + label: '1天',
  316 + value: 86400000,
  317 + },
  318 + ];
  319 + }
  320 +}
  321 +export const schemas: FormSchema[] = [
  322 + {
  323 + field: 'endTs',
  324 + label: '最后数据',
  325 + component: 'Select',
  326 + required: true,
  327 + componentProps({ formModel, formActionType }) {
  328 + return {
  329 + onChange(value) {
  330 + const { updateSchema } = formActionType;
  331 + console.log(value);
  332 + formModel.interval = '';
  333 + updateSchema({
  334 + field: 'interval',
  335 + componentProps: {
  336 + placeholder: '请选择分组间隔',
  337 + options: generateOptions(value),
  338 + },
  339 + });
  340 + },
  341 + getPopupContainer: () => document.body,
  342 + options: [
  343 + {
  344 + label: '最近1小时',
  345 + value: 3600000,
  346 + },
  347 + {
  348 + label: '最近2小时',
  349 + value: 7200000,
  350 + },
  351 + {
  352 + label: '最近5小时',
  353 + value: 18000000,
  354 + },
  355 + {
  356 + label: '最近10小时',
  357 + value: 36000000,
  358 + },
  359 + {
  360 + label: '最近12小时',
  361 + value: 43200000,
  362 + },
  363 + {
  364 + label: '最近1天',
  365 + value: 86400000,
  366 + },
  367 + {
  368 + label: '最近7天',
  369 + value: 604800000,
  370 + },
  371 + {
  372 + label: '最近30天',
  373 + value: 2592000000,
  374 + },
  375 + ],
  376 + };
  377 + },
  378 + colProps: {
  379 + span: 6,
  380 + },
  381 + },
  382 + {
  383 + field: 'interval',
  384 + label: '分组间隔',
  385 + component: 'Select',
  386 + colProps: {
  387 + span: 6,
  388 + },
  389 + componentProps: {
  390 + placeholder: '请选择分组间隔',
  391 + getPopupContainer: () => document.body,
  392 + options: [
  393 + {
  394 + label: '5分钟',
  395 + value: 300000,
  396 + },
  397 + {
  398 + label: '10分钟',
  399 + value: 600000,
  400 + },
  401 + {
  402 + label: '15分钟',
  403 + value: 900000,
  404 + },
  405 + {
  406 + label: '30分钟',
  407 + value: 1800000,
  408 + },
  409 + {
  410 + label: '1小时',
  411 + value: 3600000,
  412 + },
  413 + {
  414 + label: '2小时',
  415 + value: 7200000,
  416 + },
  417 + ],
  418 + },
  419 + },
  420 + {
  421 + field: 'agg',
  422 + label: '数据聚合功能',
  423 + component: 'Select',
  424 + componentProps: {
  425 + getPopupContainer: () => document.body,
  426 + options: [
  427 + {
  428 + label: '最小值',
  429 + value: AggregateDataEnum.MIN,
  430 + },
  431 + {
  432 + label: '最大值',
  433 + value: AggregateDataEnum.MAX,
  434 + },
  435 + {
  436 + label: '平均值',
  437 + value: AggregateDataEnum.AVG,
  438 + },
  439 + {
  440 + label: '求和',
  441 + value: AggregateDataEnum.SUM,
  442 + },
  443 + ],
  444 + },
  445 + colProps: {
  446 + span: 6,
  447 + },
  448 + },
  449 +];
... ...
  1 +<template>
  2 + <div class="wrapper">
  3 + <div ref="wrapRef" :style="{ height, width }"> </div>
  4 + <div class="right-wrap">
  5 + <BasicTable @register="registerTable" @rowClick="deviceRowClick">
  6 + <template #deviceState="{ record }">
  7 + <Tag
  8 + :color="
  9 + record.deviceState == DeviceState.INACTIVE
  10 + ? 'warning'
  11 + : record.deviceState == DeviceState.ONLINE
  12 + ? 'success'
  13 + : 'error'
  14 + "
  15 + class="ml-2"
  16 + >
  17 + {{
  18 + record.deviceState == DeviceState.INACTIVE
  19 + ? '待激活'
  20 + : record.deviceState == DeviceState.ONLINE
  21 + ? '在线'
  22 + : '离线'
  23 + }}
  24 + </Tag>
  25 + </template>
  26 + </BasicTable>
  27 + </div>
  28 + <BasicModal
  29 + @register="registerModal"
  30 + title="历史数据"
  31 + width="70%"
  32 + :minHeight="400"
  33 + :footer="null"
  34 + @cancel="cancelHistoryModal"
  35 + :canFullscreen="false"
  36 + >
  37 + <BasicForm @register="registerForm" />
  38 + <div v-show="isNull" ref="chartRef" :style="{ height: '600px', width }"></div>
  39 + <Empty v-show="!isNull" />
  40 + </BasicModal>
  41 + <DeviceDetailDrawer @register="registerDetailDrawer" />
  42 + </div>
  43 +</template>
  44 +<script lang="ts">
  45 + import { defineComponent, ref, nextTick, unref, onMounted, Ref } from 'vue';
  46 + import { useScript } from '/@/hooks/web/useScript';
  47 + import { formSchema, columns } from './config.data';
  48 + import { BasicTable, useTable } from '/@/components/Table';
  49 + import { devicePage } from '/@/api/alarm/contact/alarmContact';
  50 + import { Tag, Empty } from 'ant-design-vue';
  51 + import { DeviceState } from '/@/api/device/model/deviceModel';
  52 + import { BAI_DU_MAP_URL } from '/@/utils/fnUtils';
  53 + import { useModal, BasicModal } from '/@/components/Modal';
  54 + import { BasicForm, useForm } from '/@/components/Form';
  55 + import { schemas } from './config.data';
  56 + import { useECharts } from '/@/hooks/web/useECharts';
  57 + import {
  58 + getDeviceHistoryInfo,
  59 + getDeviceDataKeys,
  60 + getDeviceActiveTime,
  61 + } from '/@/api/alarm/position';
  62 + import { useDrawer } from '/@/components/Drawer';
  63 + import DeviceDetailDrawer from '/@/views/device/manage/cpns/modal/DeviceDetailDrawer.vue';
  64 + import moment from 'moment';
  65 + // 导入一些静态图片,避免打包时不能正确解析
  66 + import djx from '/@/assets/images/djx.png';
  67 + import zx from '/@/assets/images/zx.png';
  68 + import lx from '/@/assets/images/lx.png';
  69 + import djh from '/@/assets/images/djh.png';
  70 + import online from '/@/assets/images/online1.png';
  71 + import lx1 from '/@/assets/images/lx1.png';
  72 + export default defineComponent({
  73 + name: 'BaiduMap',
  74 + components: {
  75 + BasicTable,
  76 + Tag,
  77 + Empty,
  78 + BasicModal,
  79 + BasicForm,
  80 + DeviceDetailDrawer,
  81 + },
  82 + props: {
  83 + width: {
  84 + type: String,
  85 + default: '100%',
  86 + },
  87 + height: {
  88 + type: String,
  89 + default: 'calc(100vh - 78px)',
  90 + },
  91 + },
  92 + setup() {
  93 + let entityId = '';
  94 + let keys = [];
  95 + let globalRecord: any = {};
  96 + const wrapRef = ref<HTMLDivElement | null>(null);
  97 + const chartRef = ref<HTMLDivElement | null>(null);
  98 + const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
  99 + const isNull = ref(true);
  100 + const { toPromise } = useScript({ src: BAI_DU_MAP_URL });
  101 + const [registerDetailDrawer, { openDrawer }] = useDrawer();
  102 + const [registerModal, { openModal }] = useModal();
  103 + const [
  104 + registerForm,
  105 + { resetFields, getFieldsValue, setFieldsValue, validate, updateSchema },
  106 + ] = useForm({
  107 + labelWidth: 120,
  108 + schemas,
  109 + async submitFunc() {
  110 + // 表单验证
  111 + await validate();
  112 + let { endTs, interval, agg } = getFieldsValue();
  113 + if (!endTs || !keys.length) return;
  114 + // 数据收集
  115 + const dataArray: any[] = [];
  116 + const startTs = Date.now() - endTs;
  117 + endTs = Date.now();
  118 + // 发送请求
  119 + const res = await getDeviceHistoryInfo({
  120 + entityId,
  121 + keys: keys.join(),
  122 + startTs,
  123 + endTs,
  124 + interval,
  125 + agg,
  126 + });
  127 + // 判断数据对象是否为空
  128 + if (!Object.keys(res).length) {
  129 + isNull.value = false;
  130 + return;
  131 + } else {
  132 + isNull.value = true;
  133 + }
  134 + // 处理数据
  135 + for (const key in res) {
  136 + for (const item1 of res[key]) {
  137 + let { ts, value } = item1;
  138 + const time = moment(ts).format('YYYY-MM-DD HH:mm:ss');
  139 + value = Number(value).toFixed(2);
  140 + dataArray.push([time, value, key]);
  141 + }
  142 + }
  143 + const series: any = keys.map((item) => {
  144 + return {
  145 + name: item,
  146 + type: 'line',
  147 + stack: 'Total',
  148 + data: dataArray.filter((item1) => item1[2] === item),
  149 + };
  150 + });
  151 + // 设置数据
  152 + setOptions({
  153 + tooltip: {
  154 + trigger: 'axis',
  155 + },
  156 + legend: {
  157 + data: keys,
  158 + },
  159 + grid: {
  160 + left: '3%',
  161 + right: '4%',
  162 + bottom: '3%',
  163 + containLabel: true,
  164 + },
  165 + dataZoom: [
  166 + {
  167 + type: 'inside',
  168 + start: 0,
  169 + end: 50,
  170 + },
  171 + {
  172 + start: 20,
  173 + end: 40,
  174 + },
  175 + ],
  176 + xAxis: {
  177 + type: 'time',
  178 + boundaryGap: false,
  179 + },
  180 + yAxis: {
  181 + type: 'value',
  182 + boundaryGap: [0, '100%'],
  183 + },
  184 + series,
  185 + });
  186 + },
  187 + });
  188 + const [registerTable] = useTable({
  189 + api: devicePage,
  190 + columns,
  191 + formConfig: {
  192 + schemas: formSchema,
  193 + labelAlign: 'left',
  194 + },
  195 + showIndexColumn: false,
  196 + useSearchForm: true,
  197 + pagination: {
  198 + showSizeChanger: false,
  199 + },
  200 + });
  201 +
  202 + async function initMap() {
  203 + await toPromise();
  204 + await nextTick();
  205 + const wrapEl = unref(wrapRef);
  206 + const BMap = (window as any).BMap;
  207 + if (!wrapEl) return;
  208 + const map = new BMap.Map(wrapEl);
  209 + const point = new BMap.Point(104.04666605565338, 30.543516387560476);
  210 + map.centerAndZoom(point, 15);
  211 + map.enableScrollWheelZoom(true);
  212 + }
  213 + // 点击表格某一行触发
  214 + const deviceRowClick = async (record) => {
  215 + entityId = record.tbDeviceId;
  216 + globalRecord = record;
  217 + const BMap = (window as any).BMap;
  218 + const wrapEl = unref(wrapRef);
  219 + const map = new BMap.Map(wrapEl);
  220 + if (record.deviceInfo.address) {
  221 + keys = await getDeviceDataKeys(entityId);
  222 + const { name, organizationDTO, deviceState, deviceProfile } = record;
  223 + const { longitude, latitude, address } = record.deviceInfo;
  224 + const point = new BMap.Point(longitude, latitude);
  225 + let options = {
  226 + width: 300, // 信息窗口宽度
  227 + height: 230, // 信息窗口高度
  228 + };
  229 + map.centerAndZoom(point, 15);
  230 + map.enableScrollWheelZoom(true);
  231 + // 创建信息窗口对象
  232 + const res = await getDeviceActiveTime(entityId);
  233 +
  234 + let { value: activeStatus, lastUpdateTs } = res[0];
  235 + lastUpdateTs = moment(lastUpdateTs).format('YYYY-MM-DD HH:mm:ss');
  236 + let infoWindow = new BMap.InfoWindow(
  237 + `
  238 + <div style="display:flex;justify-content:space-between; margin:20px 0px;">
  239 + <div style="font-size:16px;font-weight:bold">${name}</div>
  240 + ${
  241 + deviceState === 'INACTIVE'
  242 + ? `<div style="display:flex;align-items:center"><img style="width:15px;height:15px" src="${djh}">待激活</div>`
  243 + : deviceState === 'ONLINE'
  244 + ? `<div style="display:flex;align-items:center"><img style="width:15px;height:15px" src="${online}">在线</div>`
  245 + : `<div style="display:flex;align-items:center"><img style="width:15px;height:15px" src="${lx1}">离线</div>`
  246 + }
  247 + </div>
  248 + <div>所属组织:${organizationDTO.name}</div>
  249 + <div style="margin-top:6px;">接入协议:${deviceProfile.transportType}</div>
  250 + <div style="margin-top:6px;">设备位置:${address}</div>
  251 + <div style="margin-top:6px;">${activeStatus ? '在' : '离'}线时间:${lastUpdateTs}</div>
  252 + <div style="display:flex;justify-content:end; margin-top:10px">
  253 + <button onclick="openDeviceInfoDrawer()" style="margin-right:10px;color:#fff;background-color:#409eff;padding:4px; border-radius:4px;">设备信息</button>
  254 + <button onclick="openHistoryModal()" style="color:#fff;background-color:#409eff;padding:4px; border-radius:4px;">历史数据</button>
  255 + </div>
  256 + `,
  257 + options
  258 + );
  259 +
  260 + map.openInfoWindow(infoWindow, map.getCenter());
  261 + let preMarker = null;
  262 +
  263 + const rivet = deviceState === 'INACTIVE' ? djx : deviceState === 'ONLINE' ? zx : lx;
  264 + let myIcon = new BMap.Icon(rivet, new BMap.Size(20, 30));
  265 + let marker = new BMap.Marker(point, { icon: myIcon });
  266 + if (marker) {
  267 + map.removeOverlay(preMarker);
  268 + }
  269 + map.addOverlay(marker);
  270 + } else {
  271 + const point = new BMap.Point(106.63028229687498, 36.06735821600903);
  272 + let options = {
  273 + width: 100, // 信息窗口宽度
  274 + height: 100, // 信息窗口高度
  275 + title: '提示', // 信息窗口标题
  276 + };
  277 + map.centerAndZoom(point, 5);
  278 + map.enableScrollWheelZoom(true);
  279 + let infoWindow = new BMap.InfoWindow('该设备暂无地理位置', options); // 创建信息窗口对象
  280 + map.openInfoWindow(infoWindow, map.getCenter());
  281 + }
  282 + };
  283 +
  284 + // 设备信息
  285 + const openDeviceInfoDrawer = async () => {
  286 + const { id, tbDeviceId } = globalRecord;
  287 + openDrawer(true, {
  288 + id,
  289 + tbDeviceId,
  290 + });
  291 + };
  292 + const openHistoryModal = async () => {
  293 + openModal(true);
  294 + // 收集参数
  295 + const dataArray: any[] = [];
  296 + const startTs = Date.now() - 86400000; //最近一天
  297 + const endTs = Date.now();
  298 + // 发送请求
  299 + if (!keys.length) {
  300 + isNull.value = false;
  301 + return;
  302 + } else {
  303 + isNull.value = true;
  304 + }
  305 + const res = await getDeviceHistoryInfo({
  306 + entityId,
  307 + keys: keys.join(),
  308 + startTs,
  309 + endTs,
  310 + interval: 7200000, //间隔两小时
  311 + agg: 'AVG',
  312 + });
  313 + // 判断对象是否为空
  314 + if (!Object.keys(res).length) {
  315 + isNull.value = false;
  316 + return;
  317 + } else {
  318 + isNull.value = true;
  319 + }
  320 + // 处理数据
  321 + for (const key in res) {
  322 + for (const item1 of res[key]) {
  323 + let { ts, value } = item1;
  324 + const time = moment(ts).format('YYYY-MM-DD HH:mm:ss');
  325 + value = Number(value).toFixed(2);
  326 + dataArray.push([time, value, key]);
  327 + }
  328 + }
  329 + const series: any = keys.map((item) => {
  330 + return {
  331 + name: item,
  332 + type: 'line',
  333 + stack: 'Total',
  334 + data: dataArray.filter((item1) => item1[2] === item),
  335 + };
  336 + });
  337 + console.log(dataArray);
  338 + // 设置数据;
  339 + setOptions({
  340 + tooltip: {
  341 + trigger: 'axis',
  342 + },
  343 + legend: {
  344 + data: keys,
  345 + },
  346 + grid: {
  347 + left: '3%',
  348 + right: '4%',
  349 + bottom: '3%',
  350 + containLabel: true,
  351 + },
  352 + dataZoom: [
  353 + {
  354 + type: 'inside',
  355 + start: 0,
  356 + end: 50,
  357 + },
  358 + {
  359 + start: 0,
  360 + end: 20,
  361 + },
  362 + ],
  363 + xAxis: {
  364 + type: 'time',
  365 + boundaryGap: false,
  366 + },
  367 + yAxis: {
  368 + type: 'value',
  369 + boundaryGap: [0, '100%'],
  370 + },
  371 + series,
  372 + });
  373 + setFieldsValue({
  374 + endTs: 86400000,
  375 + interval: 7200000,
  376 + agg: 'AVG',
  377 + });
  378 + };
  379 + const cancelHistoryModal = () => {
  380 + resetFields();
  381 + updateSchema({
  382 + field: 'interval',
  383 + componentProps: {
  384 + placeholder: '请选择分组间隔',
  385 + options: [
  386 + {
  387 + label: '5分钟',
  388 + value: 300000,
  389 + },
  390 + {
  391 + label: '10分钟',
  392 + value: 600000,
  393 + },
  394 + {
  395 + label: '15分钟',
  396 + value: 900000,
  397 + },
  398 + {
  399 + label: '30分钟',
  400 + value: 1800000,
  401 + },
  402 + {
  403 + label: '1小时',
  404 + value: 3600000,
  405 + },
  406 + {
  407 + label: '2小时',
  408 + value: 7200000,
  409 + },
  410 + ],
  411 + },
  412 + });
  413 + setOptions({});
  414 + };
  415 + onMounted(() => {
  416 + initMap();
  417 + (window as any).openDeviceInfoDrawer = openDeviceInfoDrawer;
  418 + (window as any).openHistoryModal = openHistoryModal;
  419 + });
  420 + return {
  421 + wrapRef,
  422 + registerTable,
  423 + deviceRowClick,
  424 + DeviceState,
  425 + registerModal,
  426 + registerForm,
  427 + chartRef,
  428 + isNull,
  429 + cancelHistoryModal,
  430 + registerDetailDrawer,
  431 + };
  432 + },
  433 + });
  434 +</script>
  435 +<style scoped>
  436 + .wrapper {
  437 + position: relative;
  438 + }
  439 + .right-wrap {
  440 + padding-top: 10px;
  441 + width: 22%;
  442 + height: 95%;
  443 + position: absolute;
  444 + right: 5%;
  445 + top: 3%;
  446 + background-color: #fff;
  447 + }
  448 +</style>
... ...
  1 +<template>
  2 + <div>
  3 + <BasicModal
  4 + v-bind="$attrs"
  5 + @register="registerModal"
  6 + :showFooter="false"
  7 + :title="dataSource?.sysNotice?.title"
  8 + width="50%"
  9 + centered
  10 + :showCancelBtn="false"
  11 + :showOkBtn="false"
  12 + @cancel="handleClose"
  13 + >
  14 + <PageWrapper dense contentFullHeight contentBackground>
  15 + <div class="detail-notice-info">
  16 + <span class="mr-6"
  17 + ><UserOutlined class="mr-2" />发送者:{{ dataSource?.user?.realName }}</span
  18 + >
  19 + <span class="mr-6"
  20 + ><SolutionOutlined class="mr-2" />通知类型:{{
  21 + dataSource?.sysNotice?.type === 'NOTICE'
  22 + ? '公告'
  23 + : dataSource?.sysNotice?.type === 'MEETING'
  24 + ? '会议'
  25 + : dataSource?.sysNotice?.type === 'OTHER'
  26 + ? '其他'
  27 + : ''
  28 + }}</span
  29 + >
  30 + <span class="mr-6"
  31 + ><FieldTimeOutlined class="mr-2" />发送时间{{ dataSource?.sysNotice.senderDate }}</span
  32 + >
  33 + </div>
  34 + <!--eslint-disable-next-line vue/no-v-html-->
  35 + <p v-html="dataSource?.sysNotice?.content"></p>
  36 + </PageWrapper>
  37 + </BasicModal>
  38 + </div>
  39 +</template>
  40 +<script lang="ts">
  41 + import { defineComponent, ref, unref } from 'vue';
  42 + import { BasicModal, useModalInner } from '/@/components/Modal';
  43 + import { UserOutlined, SolutionOutlined, FieldTimeOutlined } from '@ant-design/icons-vue';
  44 + import { PageWrapper } from '/@/components/Page';
  45 + import { notifyMyGetDetailApi } from '/@/api/stationnotification/stationnotifyApi';
  46 + export default defineComponent({
  47 + name: 'MyNoticeDrawer',
  48 + components: { BasicModal, PageWrapper, UserOutlined, SolutionOutlined, FieldTimeOutlined },
  49 + emits: ['success', 'register'],
  50 + setup(_, { emit }) {
  51 + const dataSource = ref();
  52 + const [registerModal] = useModalInner(async (data) => {
  53 + dataSource.value = data.record;
  54 + });
  55 + const handleClose = async () => {
  56 + // 如果已读,就不刷新表格了
  57 + if (unref(dataSource).readStatus === '1') return;
  58 + await notifyMyGetDetailApi(unref(dataSource).id);
  59 + emit('success');
  60 + };
  61 + return {
  62 + registerModal,
  63 + handleClose,
  64 + dataSource,
  65 + };
  66 + },
  67 + });
  68 +</script>
  69 +
  70 +<style lang="less" scoped>
  71 + .detail-notice-info {
  72 + color: #999;
  73 + border-top: 1px solid #ccc;
  74 + border-bottom: 1px solid #ccc;
  75 + padding-top: 5px;
  76 + padding-bottom: 5px;
  77 + }
  78 +</style>
... ...
  1 +import { BasicColumn, FormSchema } from '/@/components/Table';
  2 +import { Tag } from 'ant-design-vue';
  3 +import { DescItem } from '/@/components/Description/index';
  4 +
  5 +import { h } from 'vue';
  6 +
  7 +export const columns: BasicColumn[] = [
  8 + {
  9 + title: '标题',
  10 + dataIndex: 'sysNotice.title',
  11 + width: 200,
  12 + },
  13 + {
  14 + title: '类型',
  15 + dataIndex: 'type',
  16 + width: 200,
  17 + format: (text: string, record: Recordable) => {
  18 + return record.sysNotice.type === 'NOTICE'
  19 + ? '公告'
  20 + : record.sysNotice.type === 'MEETING'
  21 + ? '会议'
  22 + : record.sysNotice.type === 'OTHER'
  23 + ? '其他'
  24 + : '无';
  25 + },
  26 + },
  27 + {
  28 + title: '发送者',
  29 + dataIndex: 'sysNotice.senderName',
  30 + width: 200,
  31 + },
  32 + {
  33 + title: '发送时间',
  34 + dataIndex: 'sysNotice.senderDate',
  35 + width: 200,
  36 + },
  37 + {
  38 + title: '阅读状态',
  39 + dataIndex: 'readStatus',
  40 + width: 200,
  41 + customRender: ({ record }) => {
  42 + const status = record.readStatus;
  43 + const enable = status == 0 ? '未读' : status == 1 ? '已读' : '其他';
  44 + const color = enable == '未读' ? 'yellow' : enable == '已读' ? 'green' : 'red';
  45 + const text = enable == '未读' ? '未读' : enable == '已读' ? '已读' : '其他';
  46 + return h(Tag, { color }, () => text);
  47 + },
  48 + },
  49 +];
  50 +
  51 +export const searchFormSchema: FormSchema[] = [
  52 + {
  53 + field: 'type',
  54 + label: '通知类型',
  55 + colProps: { span: 6 },
  56 + component: 'Select',
  57 + componentProps: {
  58 + placeholder: '请选择类型',
  59 + options: [
  60 + {
  61 + label: '公告',
  62 + value: 'NOTICE',
  63 + },
  64 + {
  65 + label: '会议',
  66 + value: 'MEETING',
  67 + },
  68 + {
  69 + label: '其他',
  70 + value: 'OTHER',
  71 + },
  72 + ],
  73 + },
  74 + },
  75 +];
  76 +
  77 +export const DescDetailSchema: DescItem[] = [
  78 + {
  79 + field: 'sysNotice.senderName',
  80 + label: '发送者',
  81 + },
  82 + {
  83 + field: 'sysNotice.senderDate',
  84 + label: '发送时间',
  85 + },
  86 + {
  87 + field: 'sysNotice.type',
  88 + label: '类型',
  89 + render: (text) => {
  90 + return text === 'NOTICE'
  91 + ? '公告'
  92 + : text === 'MEETING'
  93 + ? '会议'
  94 + : text === 'OTHER'
  95 + ? '其他'
  96 + : '';
  97 + },
  98 + },
  99 +];
... ...
  1 +<template>
  2 + <div>
  3 + <BasicTable @register="registerTable">
  4 + <template #action="{ record }">
  5 + <TableAction
  6 + :actions="[
  7 + {
  8 + label: '查看',
  9 + tooltip: '查看',
  10 + icon: 'ant-design:eye-outlined',
  11 + onClick: handleView.bind(null, record),
  12 + },
  13 + ]"
  14 + />
  15 + </template>
  16 + </BasicTable>
  17 + <CatNoticeModal @register="registerModal" @success="handleSuccess" />
  18 + </div>
  19 +</template>
  20 +<script lang="ts">
  21 + import { defineComponent } from 'vue';
  22 + import { BasicTable, useTable, TableAction } from '/@/components/Table';
  23 + import { useModal } from '/@/components/Modal';
  24 + import CatNoticeModal from './CatNoticeModal.vue';
  25 + import { columns, searchFormSchema } from './config.d';
  26 + import { notifyMyGetrPageApi } from '/@/api/stationnotification/stationnotifyApi';
  27 + export default defineComponent({
  28 + name: 'LoginForm',
  29 + components: { BasicTable, CatNoticeModal, TableAction },
  30 + setup() {
  31 + const [registerModal, { openModal }] = useModal();
  32 + const [registerTable, { reload }] = useTable({
  33 + api: notifyMyGetrPageApi,
  34 + columns,
  35 + formConfig: {
  36 + labelWidth: 120,
  37 + schemas: searchFormSchema,
  38 + },
  39 + useSearchForm: true,
  40 + showTableSetting: true,
  41 + bordered: true,
  42 + showIndexColumn: false,
  43 + actionColumn: {
  44 + width: 200,
  45 + title: '操作',
  46 + dataIndex: 'action',
  47 + slots: { customRender: 'action' },
  48 + fixed: 'right',
  49 + },
  50 + });
  51 +
  52 + function handleView(record: Recordable) {
  53 + openModal(true, {
  54 + record,
  55 + });
  56 + }
  57 +
  58 + function handleSuccess() {
  59 + reload();
  60 + }
  61 + return {
  62 + registerTable,
  63 + registerModal,
  64 + handleView,
  65 + handleSuccess,
  66 + };
  67 + },
  68 + });
  69 +</script>
... ...
  1 +import { h } from 'vue';
  2 +import { BasicColumn, FormSchema } from '/@/components/Table';
  3 +import { Tinymce } from '/@/components/Tinymce/index';
  4 +import { getOrganizationList } from '/@/api/system/system';
  5 +import { copyTransFun } from '/@/utils/fnUtils';
  6 +import { Tag } from 'ant-design-vue';
  7 +
  8 +export enum IsOrgEnum {
  9 + IS_ORG_ENUM = '1',
  10 +}
  11 +export const isOrg = (type: string) => {
  12 + return type === IsOrgEnum.IS_ORG_ENUM;
  13 +};
  14 +
  15 +export const columns: BasicColumn[] = [
  16 + {
  17 + title: '类型',
  18 + dataIndex: 'type',
  19 + width: 200,
  20 + format: (_text: string, record: Recordable) => {
  21 + return record.type === 'NOTICE'
  22 + ? '公告'
  23 + : record.type === 'MEETING'
  24 + ? '会议'
  25 + : record.type === 'OTHER'
  26 + ? '其他'
  27 + : '';
  28 + },
  29 + },
  30 + {
  31 + title: '标题',
  32 + dataIndex: 'title',
  33 + width: 200,
  34 + },
  35 + {
  36 + title: '内容',
  37 + dataIndex: 'content',
  38 + width: 120,
  39 + format: (text: string, record: Recordable) => {
  40 + return !record.content ? '' : record.content.slice(3, record.content.length - 4);
  41 + },
  42 + },
  43 + {
  44 + title: '发送者',
  45 + dataIndex: 'senderName',
  46 + width: 200,
  47 + format: (text: string, record: Recordable) => {
  48 + return record.senderName ? record.senderName : '无';
  49 + },
  50 + },
  51 + {
  52 + title: '状态',
  53 + dataIndex: 'status',
  54 + width: 200,
  55 + customRender: ({ record }) => {
  56 + const status = record.status;
  57 + const enable = status === '已发布' ? '已发布' : status === '草稿' ? '草稿' : '其他';
  58 + const color = enable === '已发布' ? 'green' : enable === '草稿' ? 'yellow' : 'red';
  59 + const text = enable === '已发布' ? '已发布' : enable === '草稿' ? '草稿' : '其他';
  60 + return h(Tag, { color: color }, () => text);
  61 + },
  62 + },
  63 +];
  64 +
  65 +export const formSchema: FormSchema[] = [
  66 + {
  67 + field: 'type',
  68 + label: '类型',
  69 + colProps: { span: 24 },
  70 + required: true,
  71 + component: 'RadioGroup',
  72 + componentProps: {
  73 + options: [
  74 + {
  75 + label: '公告',
  76 + value: 'NOTICE',
  77 + },
  78 + {
  79 + label: '会议',
  80 + value: 'MEETING',
  81 + },
  82 + {
  83 + label: '其他',
  84 + value: 'OTHER',
  85 + },
  86 + ],
  87 + },
  88 + },
  89 + {
  90 + field: 'title',
  91 + label: '标题',
  92 + required: true,
  93 + colProps: { span: 24 },
  94 + component: 'Input',
  95 + componentProps: {
  96 + placeholder: '请输入标题',
  97 + maxLength: 200,
  98 + },
  99 + },
  100 + {
  101 + field: 'content',
  102 + component: 'Input',
  103 + colProps: { span: 24 },
  104 + label: '通知内容',
  105 + required: true,
  106 + render: ({ model, field }) => {
  107 + return h(Tinymce, {
  108 + value: model[field],
  109 + onChange: (value: string) => {
  110 + model[field] = value;
  111 + },
  112 + });
  113 + },
  114 + },
  115 + {
  116 + field: 'receiverType',
  117 + required: true,
  118 + label: '接收者',
  119 + colProps: { span: 13 },
  120 + component: 'Select',
  121 + componentProps: {
  122 + placeholder: '接收者',
  123 + options: [
  124 + { label: '全部', value: '0' },
  125 + { label: '组织', value: '1' },
  126 + ],
  127 + },
  128 + },
  129 + {
  130 + field: 'organizationId',
  131 + label: '所属组织',
  132 + colProps: { span: 13 },
  133 + component: 'ApiTreeSelect',
  134 + required: true,
  135 + componentProps: {
  136 + multiple: true,
  137 + api: async () => {
  138 + const data = await getOrganizationList();
  139 + copyTransFun(data as any as any[]);
  140 + return data;
  141 + },
  142 + },
  143 + ifShow: ({ values }) => isOrg(Reflect.get(values, 'receiverType')),
  144 + },
  145 +];
  146 +
  147 +export const searchFormSchema: FormSchema[] = [
  148 + {
  149 + field: 'type',
  150 + label: '通知类型',
  151 + colProps: { span: 6 },
  152 + component: 'Select',
  153 + componentProps: {
  154 + placeholder: '请选择类型',
  155 + options: [
  156 + {
  157 + label: '公告',
  158 + value: 'NOTICE',
  159 + },
  160 + {
  161 + label: '会议',
  162 + value: 'MEETING',
  163 + },
  164 + {
  165 + label: '其他',
  166 + value: 'OTHER',
  167 + },
  168 + ],
  169 + },
  170 + },
  171 +];
  172 +export const detailColumns: BasicColumn[] = [
  173 + {
  174 + title: '接收者',
  175 + dataIndex: 'user.realName',
  176 + width: 200,
  177 + },
  178 + {
  179 + title: '阅读状态',
  180 + dataIndex: 'readStatus',
  181 + width: 200,
  182 + slots: { customRender: 'readStatus' },
  183 + },
  184 + {
  185 + title: '阅读时间',
  186 + dataIndex: 'readDate',
  187 + width: 200,
  188 + },
  189 +];
... ...
  1 +<template>
  2 + <div>
  3 + <BasicTable @register="registerTable">
  4 + <template #toolbar>
  5 + <a-button type="primary" @click="handleAdd">新增通知</a-button>
  6 + <a-button color="error" @click="handleDeleteOrBatchDelete(null)" :disabled="hasBatchDelete">
  7 + 批量删除
  8 + </a-button>
  9 + </template>
  10 + <template #action="{ record }">
  11 + <TableAction
  12 + :actions="[
  13 + {
  14 + label: '查看',
  15 + icon: 'ant-design:eye-outlined',
  16 + onClick: handleView.bind(null, record),
  17 + ifShow: (_action) => {
  18 + return record.status === '已发布';
  19 + },
  20 + },
  21 + {
  22 + label: '编辑',
  23 + icon: 'clarity:note-edit-line',
  24 + onClick: handleEdit.bind(null, record),
  25 + ifShow: (_action) => {
  26 + return record.status === '草稿';
  27 + },
  28 + },
  29 + {
  30 + label: '删除',
  31 + icon: 'ant-design:delete-outlined',
  32 + color: 'error',
  33 + popConfirm: {
  34 + title: '是否确认删除',
  35 + confirm: handleDeleteOrBatchDelete.bind(null, record),
  36 + },
  37 + },
  38 + ]"
  39 + />
  40 + </template>
  41 + </BasicTable>
  42 + <NotifyManagerDrawer
  43 + @register="registerAdd"
  44 + @success="handleSuccess"
  45 + ref="NotifyManagerDrawerRef"
  46 + />
  47 + <tableViewChild @register="registerDrawer" />
  48 + </div>
  49 +</template>
  50 +<script lang="ts">
  51 + import { defineComponent, ref } from 'vue';
  52 + import { BasicTable, useTable, TableAction } from '/@/components/Table';
  53 + import { useDrawer } from '/@/components/Drawer';
  54 + import NotifyManagerDrawer from './useDrawer.vue';
  55 + import tableViewChild from './viewDetailDrawer.vue';
  56 + import { columns, searchFormSchema } from './config.d';
  57 + import { notifyGetTableApi, notifyDeleteApi } from '/@/api/stationnotification/stationnotifyApi';
  58 + import { useBatchDelete } from '/@/hooks/web/useBatchDelete';
  59 + export default defineComponent({
  60 + name: 'Notificationmannager',
  61 + components: { BasicTable, NotifyManagerDrawer, TableAction, tableViewChild },
  62 + setup() {
  63 + const [registerDrawer, { openDrawer }] = useDrawer();
  64 + const [registerAdd, { openDrawer: openDrawerAdd }] = useDrawer();
  65 +
  66 + // 批量删除
  67 + const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions } = useBatchDelete(
  68 + notifyDeleteApi,
  69 + handleSuccess
  70 + );
  71 + const NotifyManagerDrawerRef = ref();
  72 + const [registerTable, { reload }] = useTable({
  73 + api: notifyGetTableApi,
  74 + columns,
  75 + formConfig: {
  76 + labelWidth: 120,
  77 + schemas: searchFormSchema,
  78 + },
  79 + useSearchForm: true,
  80 + showTableSetting: true,
  81 + bordered: true,
  82 + showIndexColumn: false,
  83 + actionColumn: {
  84 + width: 200,
  85 + title: '操作',
  86 + dataIndex: 'action',
  87 + slots: { customRender: 'action' },
  88 + fixed: 'right',
  89 + },
  90 + ...selectionOptions,
  91 + });
  92 +
  93 + function handleAdd() {
  94 + openDrawerAdd(true, {
  95 + isUpdate: false,
  96 + });
  97 + NotifyManagerDrawerRef.value.setFieldsValue({ content: '' });
  98 + }
  99 +
  100 + const handleView = (record: Recordable) => {
  101 + openDrawer(true, {
  102 + record,
  103 + });
  104 + };
  105 + function handleEdit(record: Recordable) {
  106 + openDrawerAdd(true, {
  107 + record,
  108 + isUpdate: true,
  109 + });
  110 + }
  111 + function handleSuccess() {
  112 + reload();
  113 + }
  114 + return {
  115 + hasBatchDelete,
  116 + handleView,
  117 + registerAdd,
  118 + registerTable,
  119 + registerDrawer,
  120 + handleAdd,
  121 + handleEdit,
  122 + handleSuccess,
  123 + handleDeleteOrBatchDelete,
  124 + NotifyManagerDrawerRef,
  125 + };
  126 + },
  127 + });
  128 +</script>
... ...
  1 +<template>
  2 + <div>
  3 + <BasicDrawer
  4 + v-bind="$attrs"
  5 + @register="registerDrawer"
  6 + :title="getTitle"
  7 + width="800px"
  8 + showFooter
  9 + >
  10 + <BasicForm @register="registerForm" />
  11 + <template #footer>
  12 + <a-button @click="handleCancel">取消</a-button>
  13 + <a-button @click="handleSaveDraft">保存草稿</a-button>
  14 + <a-button type="primary" @click="handleSend">发布通知</a-button>
  15 + </template>
  16 + </BasicDrawer>
  17 + </div>
  18 +</template>
  19 +<script lang="ts">
  20 + import { defineComponent, computed, unref, ref } from 'vue';
  21 + import { BasicForm, useForm } from '/@/components/Form';
  22 + import { formSchema } from './config.d';
  23 + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  24 + import {
  25 + notifyAddDraftApi,
  26 + notifyAddLeaseApi,
  27 + } from '/@/api/stationnotification/stationnotifyApi';
  28 + import { useMessage } from '/@/hooks/web/useMessage';
  29 + export default defineComponent({
  30 + name: 'ConfigDrawer',
  31 + components: { BasicDrawer, BasicForm },
  32 + emits: ['success', 'register'],
  33 + setup(_, { emit }) {
  34 + const { createMessage } = useMessage();
  35 + const isUpdate = ref<Boolean>();
  36 + const getTitle = computed(() => (!unref(isUpdate) ? '新增通知' : '编辑通知'));
  37 + const noticeId = ref('');
  38 + const [registerForm, { setFieldsValue, resetFields, validate, getFieldsValue }] = useForm({
  39 + labelWidth: 120,
  40 + schemas: formSchema,
  41 + showActionButtonGroup: false,
  42 + });
  43 + const [registerDrawer, { closeDrawer }] = useDrawerInner(async (data) => {
  44 + await resetFields();
  45 + isUpdate.value = data.isUpdate;
  46 + //编辑
  47 + if (data.isUpdate) {
  48 + noticeId.value = data.record.id;
  49 + Reflect.set(data.record, 'receiverType', data.record.receiverType === '全部' ? '0' : '1');
  50 + if (data.record.receiverType === '1') {
  51 + if (!data.record.pointId.length) return;
  52 + const organizationId = data.record.pointId.split(',');
  53 + Reflect.set(data.record, 'organizationId', organizationId);
  54 + }
  55 + setFieldsValue(data.record);
  56 + }
  57 + });
  58 + // 发布通知
  59 + const handleSend = async () => {
  60 + await validate();
  61 + const field = getFieldsValue();
  62 + const pointId = field.receiverType === '1' ? field.organizationId + '' : null;
  63 + // 新增情况
  64 + if (!unref(isUpdate)) {
  65 + const addNotice = {
  66 + ...field,
  67 + pointId,
  68 + };
  69 + await notifyAddLeaseApi(addNotice);
  70 + } else {
  71 + const editNotice = {
  72 + ...field,
  73 + pointId,
  74 + id: unref(noticeId),
  75 + };
  76 + await notifyAddLeaseApi(editNotice);
  77 + }
  78 + emit('success');
  79 + closeDrawer();
  80 + createMessage.success('发布成功');
  81 + };
  82 + // 保存草稿
  83 + const handleSaveDraft = async () => {
  84 + await validate();
  85 + const field = getFieldsValue();
  86 + const pointId = field.receiverType === '1' ? field.organizationId + '' : null;
  87 + if (!unref(isUpdate)) {
  88 + const saveDraft = {
  89 + ...field,
  90 + pointId,
  91 + };
  92 + await notifyAddDraftApi(saveDraft);
  93 + } else {
  94 + const editDraft = {
  95 + ...field,
  96 + pointId,
  97 + id: unref(noticeId),
  98 + };
  99 + await notifyAddDraftApi(editDraft);
  100 + }
  101 + emit('success');
  102 + closeDrawer();
  103 + createMessage.success('保存草稿成功');
  104 + };
  105 + const handleCancel = () => {
  106 + // resetFields();
  107 + closeDrawer();
  108 + };
  109 + return {
  110 + getTitle,
  111 + handleSend,
  112 + handleCancel,
  113 + handleSaveDraft,
  114 + registerForm,
  115 + registerDrawer,
  116 + setFieldsValue,
  117 + };
  118 + },
  119 + });
  120 +</script>
... ...
  1 +<template>
  2 + <div>
  3 + <BasicDrawer
  4 + v-bind="$attrs"
  5 + @register="registerDrawer"
  6 + :showFooter="false"
  7 + :title="descInfo?.title"
  8 + destroyOnClose
  9 + width="70%"
  10 + >
  11 + <div v-html="descInfo?.content"></div>
  12 + <Description @register="registerDesc" class="mt-4" />
  13 + <BasicTable @register="registerTable" class="mt-4">
  14 + <template #readStatus="{ record }">
  15 + <Tag :color="record.readStatus === '0' ? 'orange' : 'green'">
  16 + {{ record.readStatus === '0' ? '未读' : '已读' }}
  17 + </Tag>
  18 + </template>
  19 + </BasicTable>
  20 + </BasicDrawer>
  21 + </div>
  22 +</template>
  23 +<script lang="ts">
  24 + import { defineComponent, ref } from 'vue';
  25 + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  26 + import { Description, DescItem, useDescription } from '/@/components/Description/index';
  27 + import {
  28 + getNotifyDetailPage,
  29 + noticeByIdGetInfo,
  30 + } from '/@/api/stationnotification/stationnotifyApi';
  31 + import { useTable, BasicTable } from '/@/components/Table';
  32 + import { detailColumns } from './config.d';
  33 + import { Tag } from 'ant-design-vue';
  34 + const schema: DescItem[] = [
  35 + {
  36 + field: 'senderName',
  37 + label: '发送者',
  38 + },
  39 + {
  40 + field: 'type',
  41 + label: '类型',
  42 + render: (_, { type }) => {
  43 + return type === 'NOTICE'
  44 + ? '公告'
  45 + : type === 'MEETING'
  46 + ? '会议'
  47 + : type === 'OTHER'
  48 + ? '其他'
  49 + : '';
  50 + },
  51 + },
  52 + {
  53 + field: 'senderDate',
  54 + label: '发送时间',
  55 + },
  56 + ];
  57 + export default defineComponent({
  58 + name: 'ConfigDrawer',
  59 + components: { BasicDrawer, Description, BasicTable, Tag },
  60 + emits: ['success', 'register'],
  61 + setup() {
  62 + let descInfo = ref();
  63 + let noticeId;
  64 + const [registerDrawer] = useDrawerInner(async (data) => {
  65 + let getDescInfo = await noticeByIdGetInfo(data.record.id);
  66 + noticeId = data.record.id;
  67 + descInfo.value = getDescInfo;
  68 + reload();
  69 + });
  70 + const [registerTable, { reload }] = useTable({
  71 + api: getNotifyDetailPage,
  72 + columns: detailColumns,
  73 + bordered: true,
  74 + showTableSetting: true,
  75 + showIndexColumn: false,
  76 + immediate: false,
  77 + beforeFetch: getNoticeId,
  78 + });
  79 + function getNoticeId(data) {
  80 + Reflect.set(data, 'noticeId', noticeId);
  81 + }
  82 +
  83 + const [registerDesc] = useDescription({
  84 + bordered: true,
  85 + data: descInfo,
  86 + schema,
  87 + });
  88 + return {
  89 + descInfo,
  90 + registerDesc,
  91 + registerTable,
  92 + registerDrawer,
  93 + };
  94 + },
  95 + });
  96 +</script>
... ...
  1 +<template>
  2 + <div>
  3 + <BasicModal
  4 + v-bind="$attrs"
  5 + @register="registerDrawer"
  6 + showFooter
  7 + :title="getTitle"
  8 + width="1000px"
  9 + @ok="handleSubmit"
  10 + @cancel="handleCancel"
  11 + >
  12 + <div class="step-form-form">
  13 + <a-steps :current="current">
  14 + <a-step title="选择转换方式" />
  15 + <a-step title="完善配置参数" />
  16 + </a-steps>
  17 + </div>
  18 + <div>
  19 + <div v-show="current === 0">
  20 + <TransferConfigMode ref="refTransferConfigMode" @next="handleNext"
  21 + /></div>
  22 + <div v-show="current === 1">
  23 + <TransferConfigParams
  24 + ref="refTransferConfigParams"
  25 + :getModeSelect="getModeSelectVal"
  26 + @prevSon="handlePrev"
  27 + /></div>
  28 + </div>
  29 + </BasicModal>
  30 + </div>
  31 +</template>
  32 +<script lang="ts">
  33 + import { defineComponent, reactive, ref, computed, unref, getCurrentInstance } from 'vue';
  34 + import { BasicModal, useModalInner } from '/@/components/Modal';
  35 + import { Steps } from 'ant-design-vue';
  36 + import TransferConfigMode from './cpns/transferConfigMode.vue';
  37 + import TransferConfigParams from './cpns/transferConfigParams.vue';
  38 + import { postAddConvertApi } from '/@/api/datamanager/dataManagerApi';
  39 + import { useMessage } from '/@/hooks/web/useMessage';
  40 +
  41 + export default defineComponent({
  42 + name: 'ConfigDrawer',
  43 + components: {
  44 + BasicModal,
  45 + [Steps.name]: Steps,
  46 + [Steps.Step.name]: Steps.Step,
  47 + TransferConfigMode,
  48 + TransferConfigParams,
  49 + },
  50 + emits: ['success', 'register'],
  51 + setup(_, { emit }) {
  52 + const { createMessage } = useMessage();
  53 + const { proxy } = getCurrentInstance();
  54 + const allPostForm = reactive({});
  55 + const getNameObj = reactive({
  56 + name: '',
  57 + });
  58 + const getTypeObj = reactive({
  59 + type: '',
  60 + remark: '',
  61 + });
  62 + const additionalInfoV = {
  63 + additionalInfo: {
  64 + description: '',
  65 + },
  66 + };
  67 + const getSonFormValue = ref({});
  68 + const getModeSonFormValue = ref({});
  69 + const refTransferConfigParams = ref(null);
  70 + const refTransferConfigMode = ref(null);
  71 + const getModeSelectVal = ref({});
  72 + const isUpdate = ref(true);
  73 + const getTitle = computed(() => (!unref(isUpdate) ? '新增转换配置' : '编辑数据转换'));
  74 + const current = ref(0);
  75 + const editPostId = ref('');
  76 + const editType = reactive({
  77 + type: '',
  78 + configuration: {},
  79 + name: '',
  80 + });
  81 + const editNextType = reactive({
  82 + type: '',
  83 + configuration: {},
  84 + name: '',
  85 + remark: '',
  86 + });
  87 + const editTypeFunc = (d) => {
  88 + editType.type = d.type;
  89 + editType.configuration = d.configuration;
  90 + editType.name = d.name;
  91 + };
  92 +
  93 + const [registerDrawer, { closeModal }] = useModalInner(async (data) => {
  94 + isUpdate.value = !!data?.isUpdate;
  95 + current.value = 0;
  96 + if (unref(isUpdate)) {
  97 + editPostId.value = data.record.id;
  98 + editNextType.type = data.record.type;
  99 + editNextType.configuration = data.record;
  100 + editNextType.name = data.record.name;
  101 + editNextType.remark = data.record.remark;
  102 + proxy.$refs.refTransferConfigMode.setStepOneFieldsValueFunc(editNextType);
  103 + }
  104 + });
  105 + const handleCancel = () => {
  106 + defineClearFunc();
  107 + };
  108 + const defineClearFunc = () => {
  109 + try {
  110 + proxy.$refs.refTransferConfigMode.customResetStepOneFunc();
  111 + proxy.$refs.refTransferConfigParams?.clearSonValueDataFunc();
  112 + } catch (e) {
  113 + return e;
  114 + }
  115 + };
  116 + const handleNext = (args) => {
  117 + current.value++;
  118 + getModeSelectVal.value = args;
  119 + if (unref(isUpdate)) {
  120 + try {
  121 + if (editNextType.type == 'org.thingsboard.rule.engine.kafka.TbKafkaNode') {
  122 + editTypeFunc(editNextType.configuration);
  123 + } else if (editNextType.type == 'org.thingsboard.rule.engine.mqtt.TbMqttNode') {
  124 + editTypeFunc(editNextType.configuration);
  125 + } else if (editNextType.type == 'org.thingsboard.rule.engine.rabbitmq.TbRabbitMqNode') {
  126 + editTypeFunc(editNextType.configuration);
  127 + } else if (editNextType.type == 'org.thingsboard.rule.engine.rest.TbRestApiCallNode') {
  128 + editTypeFunc(editNextType.configuration);
  129 + }
  130 + proxy.$refs.refTransferConfigParams.editSonValueDataFunc(editType);
  131 + } catch (e) {
  132 + return e;
  133 + }
  134 + }
  135 + };
  136 + const handlePrev = () => {
  137 + current.value--;
  138 + };
  139 +
  140 + const commonFunc = () => {
  141 + try {
  142 + additionalInfoV.additionalInfo.description =
  143 + getSonFormValue.value.configuration.description;
  144 + delete getSonFormValue.value.configuration.description;
  145 + delete getSonFormValue.value.configuration.type;
  146 + delete getSonFormValue.value?.configuration?.name;
  147 + } catch (e) {
  148 + return e;
  149 + }
  150 + };
  151 + const addOrEditFunc = async () => {
  152 + if (!unref(isUpdate)) {
  153 + proxy.$refs.refTransferConfigParams.clearSonValueValidateFunc();
  154 + }
  155 + getModeSonFormValue.value = await proxy.$refs.refTransferConfigMode.getSonValueFunc();
  156 + getSonFormValue.value = await proxy.$refs.refTransferConfigParams.getSonValueDataFunc();
  157 + if (getModeSonFormValue.value?.type == 'org.thingsboard.rule.engine.kafka.TbKafkaNode') {
  158 + getTypeObj.type = 'org.thingsboard.rule.engine.kafka.TbKafkaNode';
  159 + getTypeObj.remark = getModeSonFormValue.value.remark;
  160 + getNameObj.name = getSonFormValue.value?.configuration?.name;
  161 + commonFunc();
  162 + } else if (
  163 + getModeSonFormValue.value?.type == 'org.thingsboard.rule.engine.mqtt.TbMqttNode'
  164 + ) {
  165 + getTypeObj.type = 'org.thingsboard.rule.engine.mqtt.TbMqttNode';
  166 + getTypeObj.remark = getModeSonFormValue.value.remark;
  167 + getNameObj.name = getSonFormValue.value?.configuration?.name;
  168 + commonFunc();
  169 + } else if (
  170 + getModeSonFormValue.value?.type == 'org.thingsboard.rule.engine.rabbitmq.TbRabbitMqNode'
  171 + ) {
  172 + getTypeObj.type = 'org.thingsboard.rule.engine.rabbitmq.TbRabbitMqNode';
  173 + getTypeObj.remark = getModeSonFormValue.value.remark;
  174 + getNameObj.name = getSonFormValue.value?.configuration?.name;
  175 + commonFunc();
  176 + } else if (
  177 + getModeSonFormValue.value?.type == 'org.thingsboard.rule.engine.rest.TbRestApiCallNode'
  178 + ) {
  179 + getTypeObj.type = 'org.thingsboard.rule.engine.rest.TbRestApiCallNode';
  180 + getTypeObj.remark = getModeSonFormValue.value.remark;
  181 + getNameObj.name = getSonFormValue.value?.configuration?.name;
  182 + commonFunc();
  183 + }
  184 + const id: any = {
  185 + id: unref(isUpdate) ? editPostId.value : '',
  186 + };
  187 + Object.assign(
  188 + allPostForm,
  189 + getTypeObj,
  190 + getSonFormValue.value,
  191 + getNameObj,
  192 + id,
  193 + additionalInfoV
  194 + );
  195 + if (!unref(isUpdate)) {
  196 + delete allPostForm.id;
  197 + }
  198 + };
  199 + const handleSubmit = async () => {
  200 + if (!unref(isUpdate)) {
  201 + await addOrEditFunc();
  202 + await postAddConvertApi(allPostForm);
  203 + createMessage.success('数据转换新增成功');
  204 + emit('success');
  205 + defineClearFunc();
  206 + closeModal();
  207 + } else {
  208 + await addOrEditFunc();
  209 + await postAddConvertApi(allPostForm);
  210 + createMessage.success('数据转换编辑成功');
  211 + emit('success');
  212 + defineClearFunc();
  213 + closeModal();
  214 + }
  215 + };
  216 + return {
  217 + handleCancel,
  218 + registerDrawer,
  219 + handleSubmit,
  220 + getTitle,
  221 + current,
  222 + handleNext,
  223 + handlePrev,
  224 + getModeSelectVal,
  225 + refTransferConfigParams,
  226 + refTransferConfigMode,
  227 + };
  228 + },
  229 + });
  230 +</script>
... ...
  1 +import { BasicColumn, FormSchema } from '/@/components/Table';
  2 +import { h } from 'vue';
  3 +import { Tag } from 'ant-design-vue';
  4 +
  5 +export const columns: BasicColumn[] = [
  6 + {
  7 + title: '数据转换名称',
  8 + dataIndex: 'name',
  9 + width: 200,
  10 + },
  11 + {
  12 + title: '途径',
  13 + dataIndex: 'type',
  14 + width: 200,
  15 + customRender: ({ record }) => {
  16 + const status = record.type;
  17 + const enable =
  18 + status === 'org.thingsboard.rule.engine.kafka.TbKafkaNode'
  19 + ? 'KafKa'
  20 + : record.type === 'org.thingsboard.rule.engine.mqtt.TbMqttNode'
  21 + ? 'MQTT'
  22 + : record.type === 'org.thingsboard.rule.engine.rabbitmq.TbRabbitMqNode'
  23 + ? 'RabbitMQ'
  24 + : 'REST_API';
  25 + const color =
  26 + enable == 'KafKa'
  27 + ? '#0099FF'
  28 + : enable == 'MQTT'
  29 + ? '#7C7CC9'
  30 + : enable == 'RabbitMQ'
  31 + ? '#E8A15E'
  32 + : '#81B1AB';
  33 + const text =
  34 + enable == 'KafKa'
  35 + ? 'KafKa'
  36 + : enable == 'MQTT'
  37 + ? 'MQTT'
  38 + : enable == 'RabbitMQ'
  39 + ? 'RabbitMQ'
  40 + : 'REST_API';
  41 + return h(Tag, { color: color }, () => text);
  42 + },
  43 +
  44 + format: (_text: string, record: Recordable) => {
  45 + return record.type === 'org.thingsboard.rule.engine.kafka.TbKafkaNode'
  46 + ? 'KafKa'
  47 + : record.type === 'org.thingsboard.rule.engine.mqtt.TbMqttNode'
  48 + ? 'MQTT'
  49 + : record.type === 'org.thingsboard.rule.engine.rabbitmq.TbRabbitMqNode'
  50 + ? 'RabbitMQ'
  51 + : 'REST_API';
  52 + },
  53 + },
  54 + {
  55 + title: '状态',
  56 + dataIndex: 'status',
  57 + width: 120,
  58 + customRender: ({ record }) => {
  59 + const status = record.status;
  60 + const enable = ~~status === 1;
  61 + const color = enable ? '#2aae67' : '#eb846f';
  62 + const text = enable ? '启用' : '禁用';
  63 + return h(Tag, { color: color }, () => text);
  64 + },
  65 + },
  66 + {
  67 + title: '描述',
  68 + dataIndex: 'remark',
  69 + width: 200,
  70 + },
  71 + {
  72 + title: '创建时间',
  73 + dataIndex: 'createTime',
  74 + width: 180,
  75 + },
  76 +];
  77 +
  78 +export const searchFormSchema: FormSchema[] = [
  79 + {
  80 + field: 'name',
  81 + label: '名称',
  82 + component: 'Input',
  83 + colProps: { span: 6 },
  84 + componentProps: {
  85 + maxLength: 36,
  86 + placeholder: '请输入名称',
  87 + },
  88 + },
  89 + {
  90 + field: 'status',
  91 + label: '状态',
  92 + component: 'Select',
  93 + componentProps: {
  94 + placeholder: '请选择状态',
  95 + options: [
  96 + { label: '已启用', value: '1' },
  97 + { label: '未启用', value: '0' },
  98 + ],
  99 + },
  100 + colProps: { span: 6 },
  101 + },
  102 +];
... ...
  1 +import { FormSchema } from '/@/components/Form';
  2 +import { findDictItemByCode } from '/@/api/system/dict';
  3 +import { isExistDataManagerNameApi } from '/@/api/datamanager/dataManagerApi';
  4 +import { ref } from 'vue';
  5 +import { useMessage } from '/@/hooks/web/useMessage';
  6 +const { createMessage } = useMessage();
  7 +
  8 +const typeValue = ref('');
  9 +
  10 +export enum CredentialsEnum {
  11 + IS_ANONYMOUS = 'anonymous',
  12 + IS_BASIC = 'basic',
  13 + IS_PEM = 'pem',
  14 +}
  15 +
  16 +export const isBasic = (type: string) => {
  17 + return type === CredentialsEnum.IS_BASIC;
  18 +};
  19 +export const isPem = (type: string) => {
  20 + return type === CredentialsEnum.IS_PEM;
  21 +};
  22 +
  23 +export const modeForm: FormSchema[] = [
  24 + {
  25 + field: 'type',
  26 + label: '转换方式',
  27 + component: 'ApiSelect',
  28 + required: true,
  29 + colProps: {
  30 + span: 13,
  31 + },
  32 + componentProps({}) {
  33 + return {
  34 + api: findDictItemByCode,
  35 + params: {
  36 + dictCode: 'convert_data_to',
  37 + },
  38 + labelField: 'itemText',
  39 + valueField: 'itemValue',
  40 + onChange(value) {
  41 + typeValue.value = value;
  42 + },
  43 + };
  44 + },
  45 + },
  46 + {
  47 + field: 'remark',
  48 + label: '描述',
  49 + colProps: { span: 13 },
  50 + component: 'Input',
  51 + componentProps: {
  52 + maxLength: 255,
  53 + placeholder: '请输入描述',
  54 + },
  55 + },
  56 +];
  57 +
  58 +export const modeKafkaInseretKeyAndValueForm: FormSchema[] = [
  59 + {
  60 + field: 'key',
  61 + label: 'Key',
  62 + colProps: { span: 12 },
  63 + required: true,
  64 + component: 'Input',
  65 + componentProps: {
  66 + maxLength: 255,
  67 + placeholder: '请输入Key',
  68 + },
  69 + },
  70 + {
  71 + field: 'value',
  72 + label: 'Value',
  73 + colProps: { span: 12 },
  74 + required: true,
  75 + component: 'Input',
  76 + componentProps: {
  77 + maxLength: 255,
  78 + placeholder: '请输入Value',
  79 + },
  80 + },
  81 +];
  82 +
  83 +export const modeApiInseretKeyAndValueForm: FormSchema[] = [
  84 + {
  85 + field: 'key',
  86 + label: 'Header',
  87 + colProps: { span: 12 },
  88 + required: true,
  89 + component: 'Input',
  90 + componentProps: {
  91 + maxLength: 255,
  92 + placeholder: '请输入Header',
  93 + },
  94 + },
  95 + {
  96 + field: 'value',
  97 + label: 'Value',
  98 + colProps: { span: 12 },
  99 + required: true,
  100 + component: 'Input',
  101 + componentProps: {
  102 + maxLength: 255,
  103 + placeholder: '请输入Value',
  104 + },
  105 + },
  106 +];
  107 +
  108 +export const modeKafkaForm: FormSchema[] = [
  109 + {
  110 + field: 'name',
  111 + label: '名称',
  112 + colProps: { span: 12 },
  113 + required: true,
  114 + component: 'Input',
  115 + componentProps: {
  116 + maxLength: 255,
  117 + placeholder: '请输入名称',
  118 + },
  119 + dynamicRules: ({ values }) => {
  120 + return [
  121 + {
  122 + required: true,
  123 + validator(_, value) {
  124 + return new Promise((resolve, reject) => {
  125 + if (value == '') {
  126 + reject('请输入名称');
  127 + } else {
  128 + if (values.name != undefined) {
  129 + isExistDataManagerNameApi({
  130 + name: value,
  131 + type:
  132 + typeValue.value == ''
  133 + ? 'org.thingsboard.rule.engine.kafka.TbKafkaNode'
  134 + : typeValue.value,
  135 + }).then((data) => {
  136 + if (data == true) {
  137 + createMessage.error('名称已存在');
  138 + resolve();
  139 + } else {
  140 + resolve();
  141 + }
  142 + });
  143 + } else {
  144 + resolve();
  145 + }
  146 + }
  147 + });
  148 + },
  149 + },
  150 + ];
  151 + },
  152 + },
  153 + {
  154 + field: 'topicPattern',
  155 + label: 'Topic',
  156 + colProps: { span: 12 },
  157 + required: true,
  158 + component: 'Input',
  159 + defaultValue: 'my-topic',
  160 + componentProps: {
  161 + maxLength: 255,
  162 + placeholder: '请输入Topic pattern',
  163 + },
  164 + },
  165 + {
  166 + field: 'bootstrapServers',
  167 + label: 'Bootstrap',
  168 + colProps: { span: 12 },
  169 + component: 'Input',
  170 + defaultValue: 'localhost:9092',
  171 + required: true,
  172 + componentProps: {
  173 + maxLength: 255,
  174 + placeholder: 'localhost:9092',
  175 + },
  176 + },
  177 + {
  178 + field: 'retries',
  179 + label: 'Retries',
  180 + colProps: { span: 12 },
  181 + component: 'InputNumber',
  182 + defaultValue: 0,
  183 + componentProps: {
  184 + maxLength: 255,
  185 + placeholder: '请输入Automatically retry times if fails',
  186 + },
  187 + },
  188 + {
  189 + field: 'batchSize',
  190 + label: 'BatchSize',
  191 + colProps: { span: 12 },
  192 + component: 'InputNumber',
  193 + defaultValue: 16384,
  194 + componentProps: {
  195 + maxLength: 255,
  196 + placeholder: '请输入Produces batch size in bytes',
  197 + },
  198 + },
  199 + {
  200 + field: 'linger',
  201 + label: 'Linger',
  202 + colProps: { span: 12 },
  203 + component: 'InputNumber',
  204 + defaultValue: 0,
  205 + componentProps: {
  206 + maxLength: 255,
  207 + placeholder: '请输入Time to buffer locally(ms)',
  208 + },
  209 + },
  210 + {
  211 + field: 'bufferMemory',
  212 + label: 'BufferMemory',
  213 + colProps: { span: 12 },
  214 + component: 'InputNumber',
  215 + defaultValue: 33554432,
  216 + componentProps: {
  217 + maxLength: 255,
  218 + placeholder: '请输入Client buffer max size in bytes',
  219 + },
  220 + },
  221 + {
  222 + field: 'acks',
  223 + component: 'Select',
  224 + label: 'Acks',
  225 + colProps: { span: 12 },
  226 + defaultValue: '-1',
  227 + componentProps: {
  228 + placeholder: '请选择Number of acknowledgments',
  229 + options: [
  230 + { label: 'all', value: 'all' },
  231 + { label: '-1', value: '-1' },
  232 + { label: '0', value: '0' },
  233 + { label: '1', value: '1' },
  234 + ],
  235 + },
  236 + },
  237 + {
  238 + field: 'keySerializer',
  239 + label: 'Key',
  240 + colProps: { span: 12 },
  241 + required: true,
  242 + component: 'Input',
  243 + defaultValue: 'org.apache.kafka.common.serialization.StringSerializer',
  244 + componentProps: {
  245 + maxLength: 255,
  246 + placeholder: 'org.apache.kafka.common.serialization.StringSerializer',
  247 + },
  248 + },
  249 + {
  250 + field: 'valueSerializer',
  251 + label: 'Value',
  252 + colProps: { span: 12 },
  253 + required: true,
  254 + component: 'Input',
  255 + defaultValue: 'org.apache.kafka.common.serialization.StringSerializer',
  256 + componentProps: {
  257 + maxLength: 255,
  258 + placeholder: 'org.apache.kafka.common.serialization.StringSerializer',
  259 + },
  260 + },
  261 + {
  262 + field: '1',
  263 + label: '',
  264 + colProps: { span: 24 },
  265 + slot: 'addValue',
  266 + component: 'Input',
  267 + },
  268 + {
  269 + field: 'addMetadataKeyValuesAsKafkaHeaders',
  270 + label: '选择',
  271 + colProps: { span: 12 },
  272 + component: 'Checkbox',
  273 + renderComponentContent: 'Add Message metadata key-value pairs to Kafka record headers',
  274 + },
  275 + {
  276 + field: 'kafkaHeadersCharset',
  277 + component: 'Select',
  278 + label: 'Charset',
  279 + required: true,
  280 + colProps: { span: 12 },
  281 + defaultValue: 'UTF-8',
  282 + componentProps: {
  283 + placeholder: '请选择Charset encoding',
  284 + options: [
  285 + { label: 'US-ASCII', value: 'US' },
  286 + { label: 'ISO-8859-1', value: 'ISO-8859-1' },
  287 + { label: 'UTF-8', value: 'UTF-8' },
  288 + { label: 'UTF-16BE', value: 'UTF-16BE' },
  289 + { label: 'UTF-16LE', value: 'UTF-16LE' },
  290 + { label: 'UTF-16', value: 'UTF-16' },
  291 + ],
  292 + },
  293 + ifShow: ({ values }) => {
  294 + return !!values.addMetadataKeyValuesAsKafkaHeaders;
  295 + },
  296 + },
  297 +
  298 + {
  299 + field: 'description',
  300 + label: '说明',
  301 + colProps: { span: 12 },
  302 + component: 'Input',
  303 + componentProps: {
  304 + maxLength: 255,
  305 + placeholder: '请输入说明',
  306 + },
  307 + },
  308 +];
  309 +
  310 +export const modeMqttForm: FormSchema[] = [
  311 + {
  312 + field: 'name',
  313 + label: '名称',
  314 + colProps: { span: 12 },
  315 + required: true,
  316 + component: 'Input',
  317 + componentProps: {
  318 + maxLength: 255,
  319 + placeholder: '请输入名称',
  320 + },
  321 + dynamicRules: ({ values }) => {
  322 + return [
  323 + {
  324 + required: true,
  325 + validator(_, value) {
  326 + return new Promise((resolve, reject) => {
  327 + if (value == '') {
  328 + reject('请输入名称');
  329 + } else {
  330 + if (values.name != undefined) {
  331 + isExistDataManagerNameApi({
  332 + name: value,
  333 + type:
  334 + typeValue.value == ''
  335 + ? 'org.thingsboard.rule.engine.mqtt.TbMqttNode'
  336 + : typeValue.value,
  337 + }).then((data) => {
  338 + if (data == true) {
  339 + createMessage.error('名称已存在');
  340 + resolve();
  341 + } else {
  342 + resolve();
  343 + }
  344 + });
  345 + } else {
  346 + resolve();
  347 + }
  348 + }
  349 + });
  350 + },
  351 + },
  352 + ];
  353 + },
  354 + },
  355 + {
  356 + field: 'topicPattern',
  357 + label: 'Topic',
  358 + colProps: { span: 12 },
  359 + required: true,
  360 + component: 'Input',
  361 + componentProps: {
  362 + maxLength: 255,
  363 + placeholder: '请输入Topic pattern',
  364 + },
  365 + },
  366 + {
  367 + field: 'host',
  368 + label: 'Host',
  369 + colProps: { span: 12 },
  370 + component: 'Input',
  371 + required: true,
  372 + defaultValue: 'localhost',
  373 + componentProps: {
  374 + maxLength: 255,
  375 + placeholder: '请输入Host',
  376 + },
  377 + },
  378 + {
  379 + field: 'port',
  380 + label: 'Port',
  381 + colProps: { span: 12 },
  382 + component: 'InputNumber',
  383 + defaultValue: 1883,
  384 + required: true,
  385 + componentProps: {
  386 + maxLength: 255,
  387 + placeholder: '请输入Port',
  388 + },
  389 + },
  390 + {
  391 + field: 'connectTimeoutSec',
  392 + label: 'Connection',
  393 + colProps: { span: 12 },
  394 + component: 'InputNumber',
  395 + defaultValue: 10,
  396 + required: true,
  397 + componentProps: {
  398 + maxLength: 255,
  399 + placeholder: '请输入Connection timeout (sec)',
  400 + },
  401 + },
  402 + {
  403 + field: 'clientId',
  404 + label: 'Client ID',
  405 + colProps: { span: 12 },
  406 + component: 'Input',
  407 + componentProps: {
  408 + maxLength: 255,
  409 + placeholder: '请输入Client ID',
  410 + },
  411 + },
  412 + {
  413 + field: 'cleanSession',
  414 + label: 'Clean',
  415 + colProps: { span: 12 },
  416 + component: 'Checkbox',
  417 + renderComponentContent: 'Clean session',
  418 + },
  419 + {
  420 + field: 'ssl',
  421 + label: 'Enable',
  422 + colProps: { span: 12 },
  423 + component: 'Checkbox',
  424 + renderComponentContent: 'Enable SSL',
  425 + },
  426 + {
  427 + field: 'type',
  428 + component: 'Select',
  429 + label: 'type',
  430 + colProps: { span: 12 },
  431 + componentProps: {
  432 + placeholder: '请选择Credentials',
  433 + options: [
  434 + { label: 'Anonymous', value: 'anonymous' },
  435 + { label: 'Basic', value: 'basic' },
  436 + { label: 'PEM', value: 'pem' },
  437 + ],
  438 + },
  439 + },
  440 + {
  441 + field: 'username',
  442 + label: 'Username',
  443 + colProps: { span: 12 },
  444 + component: 'Input',
  445 + required: true,
  446 + componentProps: {
  447 + maxLength: 255,
  448 + placeholder: '请输入Username',
  449 + },
  450 + ifShow: ({ values }) => isBasic(Reflect.get(values, 'type')),
  451 + },
  452 + {
  453 + field: 'password',
  454 + label: 'Password',
  455 + colProps: { span: 12 },
  456 + component: 'Input',
  457 + componentProps: {
  458 + maxLength: 255,
  459 + placeholder: '请输入Password',
  460 + },
  461 + ifShow: ({ values }) => isBasic(Reflect.get(values, 'type')),
  462 + },
  463 + {
  464 + field: '4',
  465 + label: '',
  466 + colProps: { span: 24 },
  467 + component: 'Input',
  468 + slot: 'uploadAdd1',
  469 + ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),
  470 + },
  471 + {
  472 + field: '5',
  473 + label: '',
  474 + colProps: { span: 24 },
  475 + component: 'Input',
  476 + slot: 'uploadAdd2',
  477 + ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),
  478 + },
  479 + {
  480 + field: '6',
  481 + label: '',
  482 + colProps: { span: 24 },
  483 + component: 'Input',
  484 + slot: 'uploadAdd3',
  485 + ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),
  486 + },
  487 + {
  488 + field: 'password',
  489 + label: 'Password',
  490 + colProps: { span: 12 },
  491 + component: 'Input',
  492 + componentProps: {
  493 + maxLength: 255,
  494 + placeholder: '请输入Password',
  495 + },
  496 + ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),
  497 + },
  498 + {
  499 + field: 'description',
  500 + label: '说明',
  501 + colProps: { span: 12 },
  502 + component: 'Input',
  503 + componentProps: {
  504 + maxLength: 255,
  505 + placeholder: '请输入说明',
  506 + },
  507 + },
  508 +];
  509 +
  510 +export const modeRabbitMqForm: FormSchema[] = [
  511 + {
  512 + field: 'name',
  513 + label: '名称',
  514 + colProps: { span: 12 },
  515 + required: true,
  516 + component: 'Input',
  517 + componentProps: {
  518 + maxLength: 255,
  519 + placeholder: '请输入名称',
  520 + },
  521 + dynamicRules: ({ values }) => {
  522 + return [
  523 + {
  524 + required: true,
  525 + validator(_, value) {
  526 + return new Promise((resolve, reject) => {
  527 + if (value == '') {
  528 + reject('请输入名称');
  529 + } else {
  530 + if (values.name != undefined) {
  531 + isExistDataManagerNameApi({
  532 + name: value,
  533 + type:
  534 + typeValue.value == ''
  535 + ? 'org.thingsboard.rule.engine.rabbitmq.TbRabbitMqNode'
  536 + : typeValue.value,
  537 + }).then((data) => {
  538 + if (data == true) {
  539 + createMessage.error('名称已存在');
  540 + resolve();
  541 + } else {
  542 + resolve();
  543 + }
  544 + });
  545 + } else {
  546 + resolve();
  547 + }
  548 + }
  549 + });
  550 + },
  551 + },
  552 + ];
  553 + },
  554 + },
  555 + {
  556 + field: 'exchangeNamePattern',
  557 + label: 'Exchange',
  558 + colProps: { span: 12 },
  559 + component: 'Input',
  560 + componentProps: {
  561 + maxLength: 255,
  562 + placeholder: '请输入Exchange name pattern',
  563 + },
  564 + },
  565 + {
  566 + field: 'routingKeyPattern',
  567 + label: 'Routing',
  568 + colProps: { span: 12 },
  569 + component: 'Input',
  570 + componentProps: {
  571 + maxLength: 255,
  572 + placeholder: '请输入Routing key pattern',
  573 + },
  574 + },
  575 + {
  576 + field: 'messageProperties',
  577 + component: 'Select',
  578 + label: 'Message',
  579 + colProps: { span: 12 },
  580 + componentProps: {
  581 + placeholder: '请选择Message properties',
  582 + options: [
  583 + { label: 'BASIC', value: 'BASIC' },
  584 + { label: 'TEXT_PLAIN', value: 'TEXT_PLAIN' },
  585 + { label: 'MINIMAL_BASIC', value: 'MINIMAL_BASIC' },
  586 + { label: 'MINIMAL_PERSISTENT_BASIC', value: 'MINIMAL_PERSISTENT_BASIC' },
  587 + { label: 'PERSISTENT_BASIC', value: 'PERSISTENT_BASIC' },
  588 + { label: 'PERSISTENT_TEXT_PLAIN', value: 'PERSISTENT_TEXT_PLAIN' },
  589 + ],
  590 + },
  591 + },
  592 + {
  593 + field: 'host',
  594 + label: 'Host',
  595 + colProps: { span: 12 },
  596 + component: 'Input',
  597 + required: true,
  598 + defaultValue: 'localhost',
  599 + componentProps: {
  600 + maxLength: 255,
  601 + placeholder: 'localhost',
  602 + },
  603 + },
  604 + {
  605 + field: 'port',
  606 + label: 'Port',
  607 + colProps: { span: 12 },
  608 + component: 'InputNumber',
  609 + defaultValue: 5672,
  610 + required: true,
  611 + componentProps: {
  612 + maxLength: 255,
  613 + placeholder: '请输入Port',
  614 + },
  615 + },
  616 + {
  617 + field: 'virtualHost',
  618 + label: 'Virtual',
  619 + colProps: { span: 12 },
  620 + component: 'Input',
  621 + defaultValue: '/',
  622 + componentProps: {
  623 + maxLength: 255,
  624 + placeholder: '/',
  625 + },
  626 + },
  627 + {
  628 + field: 'username',
  629 + label: 'Username',
  630 + colProps: { span: 12 },
  631 + component: 'Input',
  632 + defaultValue: 'guest',
  633 + componentProps: {
  634 + maxLength: 255,
  635 + placeholder: '请输入Username',
  636 + },
  637 + },
  638 + {
  639 + field: 'password',
  640 + label: 'Password',
  641 + colProps: { span: 12 },
  642 + component: 'Input',
  643 + defaultValue: 'guest',
  644 + componentProps: {
  645 + maxLength: 255,
  646 + placeholder: '请输入Password',
  647 + },
  648 + },
  649 + {
  650 + field: 'automaticRecoveryEnabled',
  651 + label: ' Automatic',
  652 + colProps: { span: 12 },
  653 + component: 'Checkbox',
  654 + renderComponentContent: 'Automatic recovery',
  655 + },
  656 + {
  657 + field: 'connectionTimeout',
  658 + label: 'Connect',
  659 + colProps: { span: 12 },
  660 + component: 'InputNumber',
  661 + defaultValue: 60000,
  662 + componentProps: {
  663 + maxLength: 255,
  664 + placeholder: '请输入Connection timeout (ms)',
  665 + },
  666 + },
  667 + {
  668 + field: 'handshakeTimeout',
  669 + label: 'Handshake',
  670 + colProps: { span: 12 },
  671 + component: 'InputNumber',
  672 + defaultValue: 10000,
  673 + componentProps: {
  674 + maxLength: 255,
  675 + placeholder: '请输入Handshake timeout (ms)',
  676 + },
  677 + },
  678 + {
  679 + field: '1',
  680 + label: '',
  681 + colProps: { span: 24 },
  682 + component: 'Input',
  683 + slot: 'addKeyAndValue',
  684 + },
  685 +
  686 + {
  687 + field: 'description',
  688 + label: '说明',
  689 + colProps: { span: 12 },
  690 + component: 'Input',
  691 + componentProps: {
  692 + maxLength: 255,
  693 + placeholder: '请输入说明',
  694 + },
  695 + },
  696 +];
  697 +
  698 +export const modeApiForm: FormSchema[] = [
  699 + {
  700 + field: 'name',
  701 + label: '名称',
  702 + colProps: { span: 12 },
  703 + required: true,
  704 + component: 'Input',
  705 + componentProps: {
  706 + maxLength: 255,
  707 + placeholder: '请输入名称',
  708 + },
  709 + dynamicRules: ({ values }) => {
  710 + return [
  711 + {
  712 + required: true,
  713 + validator(_, value) {
  714 + return new Promise((resolve, reject) => {
  715 + if (value == '') {
  716 + reject('请输入名称');
  717 + } else {
  718 + if (values.name != undefined) {
  719 + isExistDataManagerNameApi({
  720 + name: value,
  721 + type:
  722 + typeValue.value == ''
  723 + ? 'org.thingsboard.rule.engine.rest.TbRestApiCallNode'
  724 + : typeValue.value,
  725 + }).then((data) => {
  726 + if (data == true) {
  727 + createMessage.error('名称已存在');
  728 + resolve();
  729 + } else {
  730 + resolve();
  731 + }
  732 + });
  733 + } else {
  734 + resolve();
  735 + }
  736 + }
  737 + });
  738 + },
  739 + },
  740 + ];
  741 + },
  742 + },
  743 + {
  744 + field: 'restEndpointUrlPattern',
  745 + label: 'Endpoint',
  746 + colProps: { span: 12 },
  747 + required: true,
  748 + defaultValue: 'http://localhost/api',
  749 + component: 'Input',
  750 + componentProps: {
  751 + maxLength: 255,
  752 + placeholder: '请输入Endpoint URL pattern',
  753 + },
  754 + },
  755 + {
  756 + field: 'requestMethod',
  757 + component: 'Select',
  758 + label: 'Request',
  759 + colProps: { span: 12 },
  760 + defaultValue: 'POST',
  761 + componentProps: {
  762 + placeholder: '请选择Request method',
  763 + options: [
  764 + { label: 'GET', value: 'GET' },
  765 + { label: 'POST', value: 'POST' },
  766 + { label: 'PUT', value: 'PUT' },
  767 + { label: 'DELETE', value: 'DELETE' },
  768 + ],
  769 + },
  770 + },
  771 + {
  772 + field: 'enableProxy',
  773 + label: '选择',
  774 + colProps: { span: 12 },
  775 + component: 'Checkbox',
  776 + renderComponentContent: 'Enable proxy',
  777 + },
  778 +
  779 + {
  780 + field: 'proxyHost',
  781 + label: 'Host',
  782 + colProps: { span: 12 },
  783 + required: true,
  784 + component: 'Input',
  785 + componentProps: {
  786 + maxLength: 255,
  787 + placeholder: 'http或者https开头',
  788 + },
  789 + ifShow: ({ values }) => {
  790 + return !!values.enableProxy;
  791 + },
  792 + },
  793 + {
  794 + field: 'proxyPort',
  795 + label: 'Port',
  796 + colProps: { span: 12 },
  797 + required: true,
  798 + component: 'InputNumber',
  799 + defaultValue: 0,
  800 + componentProps: {
  801 + maxLength: 255,
  802 + placeholder: 'http或者https开头',
  803 + },
  804 + ifShow: ({ values }) => {
  805 + return !!values.enableProxy;
  806 + },
  807 + },
  808 + {
  809 + field: 'proxyUser',
  810 + label: 'User',
  811 + colProps: { span: 12 },
  812 + required: true,
  813 + component: 'Input',
  814 + componentProps: {
  815 + maxLength: 255,
  816 + placeholder: '请输入Proxy user',
  817 + },
  818 + ifShow: ({ values }) => {
  819 + return !!values.enableProxy;
  820 + },
  821 + },
  822 + {
  823 + field: 'proxyPassword',
  824 + label: 'Password',
  825 + colProps: { span: 12 },
  826 + required: true,
  827 + component: 'Input',
  828 + componentProps: {
  829 + maxLength: 255,
  830 + placeholder: '请输入Proxy password',
  831 + },
  832 + ifShow: ({ values }) => {
  833 + return !!values.enableProxy;
  834 + },
  835 + },
  836 +
  837 + {
  838 + field: 'useSystemProxyProperties',
  839 + label: '选择',
  840 + colProps: { span: 12 },
  841 + component: 'Checkbox',
  842 + renderComponentContent: 'Use system proxy properties',
  843 + },
  844 + {
  845 + field: 'maxParallelRequestsCount',
  846 + label: 'Max',
  847 + colProps: { span: 12 },
  848 + required: true,
  849 + component: 'InputNumber',
  850 + defaultValue: 0,
  851 + componentProps: {
  852 + maxLength: 255,
  853 + placeholder: '请输入Max number of paraller requests',
  854 + },
  855 + ifShow: ({ values }) => {
  856 + return !!values.useSystemProxyProperties;
  857 + },
  858 + },
  859 + {
  860 + field: 'ignoreRequestBody',
  861 + label: '选择',
  862 + colProps: { span: 12 },
  863 + component: 'Checkbox',
  864 + renderComponentContent: 'Without request body',
  865 + },
  866 + {
  867 + field: 'readTimeoutMs',
  868 + label: 'Read',
  869 + colProps: { span: 12 },
  870 + required: true,
  871 + component: 'InputNumber',
  872 + defaultValue: 0,
  873 + componentProps: {
  874 + maxLength: 255,
  875 + placeholder: '请输入Read timeout in times',
  876 + },
  877 + ifShow: ({ values }) => {
  878 + return !values.useSystemProxyProperties;
  879 + },
  880 + },
  881 + {
  882 + field: 'maxParallelRequestsCount',
  883 + label: 'Max',
  884 + colProps: { span: 12 },
  885 + required: true,
  886 + component: 'InputNumber',
  887 + defaultValue: 0,
  888 + componentProps: {
  889 + maxLength: 255,
  890 + placeholder: '请输入Max number of paraller requests',
  891 + },
  892 + ifShow: ({ values }) => {
  893 + return !values.useSystemProxyProperties;
  894 + },
  895 + },
  896 + {
  897 + field: 'Header',
  898 + label: 'Header',
  899 + colProps: { span: 12 },
  900 + required: true,
  901 + component: 'Input',
  902 + defaultValue: 'Content-Type',
  903 + componentProps: {
  904 + maxLength: 255,
  905 + placeholder: 'Content-Type',
  906 + },
  907 + },
  908 + {
  909 + field: 'Value',
  910 + label: 'Value',
  911 + colProps: { span: 12 },
  912 + required: true,
  913 + component: 'Input',
  914 + defaultValue: 'application/json',
  915 + componentProps: {
  916 + maxLength: 255,
  917 + placeholder: 'application/json',
  918 + },
  919 + },
  920 + {
  921 + field: '1',
  922 + label: '',
  923 + colProps: { span: 24 },
  924 + component: 'Input',
  925 + slot: 'addKeyAndValue',
  926 + },
  927 +
  928 + {
  929 + field: 'useRedisQueueForMsgPersistence',
  930 + label: '选择',
  931 + colProps: { span: 12 },
  932 + component: 'Checkbox',
  933 + renderComponentContent: 'Use redis queue for message persistence',
  934 + },
  935 + {
  936 + field: 'trimQueue',
  937 + label: '选择',
  938 + colProps: { span: 12 },
  939 + component: 'Checkbox',
  940 + renderComponentContent: 'Trim redis queue',
  941 + ifShow: ({ values }) => {
  942 + return !!values.useRedisQueueForMsgPersistence;
  943 + },
  944 + },
  945 + {
  946 + field: 'maxQueueSize',
  947 + label: 'Redis',
  948 + colProps: { span: 12 },
  949 + required: true,
  950 + component: 'InputNumber',
  951 + defaultValue: 0,
  952 + componentProps: {
  953 + maxLength: 255,
  954 + placeholder: '请输入Redis queue max size',
  955 + },
  956 + ifShow: ({ values }) => {
  957 + return !!values.useRedisQueueForMsgPersistence;
  958 + },
  959 + },
  960 +
  961 + {
  962 + field: 'type',
  963 + component: 'Select',
  964 + label: 'type',
  965 + colProps: { span: 12 },
  966 + componentProps: {
  967 + placeholder: '请选择Number of acknowledgments',
  968 + options: [
  969 + { label: 'Anonymous', value: 'anonymous' },
  970 + { label: 'Basic', value: 'basic' },
  971 + { label: 'PEM', value: 'pem' },
  972 + ],
  973 + },
  974 + },
  975 + {
  976 + field: 'username',
  977 + label: 'Username',
  978 + colProps: { span: 12 },
  979 + component: 'Input',
  980 + required: true,
  981 + componentProps: {
  982 + maxLength: 255,
  983 + placeholder: '请输入Username',
  984 + },
  985 + ifShow: ({ values }) => isBasic(Reflect.get(values, 'type')),
  986 + },
  987 + {
  988 + field: 'password',
  989 + label: 'Password',
  990 + colProps: { span: 12 },
  991 + component: 'Input',
  992 + required: true,
  993 + componentProps: {
  994 + maxLength: 255,
  995 + placeholder: '请输入Password',
  996 + },
  997 + ifShow: ({ values }) => isBasic(Reflect.get(values, 'type')),
  998 + },
  999 + {
  1000 + field: '1',
  1001 + label: '',
  1002 + colProps: { span: 24 },
  1003 + component: 'Input',
  1004 + slot: 'uploadAdd1',
  1005 + ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),
  1006 + },
  1007 + {
  1008 + field: '1',
  1009 + label: '',
  1010 + colProps: { span: 24 },
  1011 + component: 'Input',
  1012 + slot: 'uploadAdd2',
  1013 + ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),
  1014 + },
  1015 + {
  1016 + field: '1',
  1017 + label: '',
  1018 + colProps: { span: 24 },
  1019 + component: 'Input',
  1020 + slot: 'uploadAdd3',
  1021 + ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),
  1022 + },
  1023 + {
  1024 + field: 'password',
  1025 + label: 'Password',
  1026 + colProps: { span: 12 },
  1027 + component: 'Input',
  1028 + componentProps: {
  1029 + maxLength: 255,
  1030 + placeholder: '请输入Password',
  1031 + },
  1032 + ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),
  1033 + },
  1034 +
  1035 + {
  1036 + field: 'description',
  1037 + label: '说明',
  1038 + colProps: { span: 12 },
  1039 + component: 'Input',
  1040 + componentProps: {
  1041 + maxLength: 255,
  1042 + placeholder: '请输入说明',
  1043 + },
  1044 + },
  1045 +];
... ...
  1 +<template>
  2 + <div class="root">
  3 + <div class="root-form">
  4 + <BasicForm :showSubmitButton="false" @register="register">
  5 + <template #addKeyAndValue="{ field }">
  6 + <span style="display: none">{{ field }}</span>
  7 + <div>
  8 + <div>
  9 + <template v-for="(item, index) in keyAndValueArr" :key="index">
  10 + <span style="display: none">{{ item + index }}</span>
  11 + <BasicForm
  12 + :showResetButton="false"
  13 + :showSubmitButton="false"
  14 + @register="registerKeyAndValue"
  15 + />
  16 + </template>
  17 + <div
  18 + style="
  19 + width: 7vw;
  20 + height: 3.3vh;
  21 + display: flex;
  22 + flex-direction: row;
  23 + justify-content: center;
  24 + align-items: center;
  25 + margin-left: 1.8vw;
  26 + "
  27 + >
  28 + <div
  29 + style="
  30 + width: 2.9vw;
  31 + height: 3.3vh;
  32 + background-color: #0960bd;
  33 + border-radius: 2px;
  34 + cursor: pointer;
  35 + text-align: center;
  36 + line-height: 3.1vh;
  37 + "
  38 + >
  39 + <span @click="addKeyAndValueFunc" style="color: white">添加</span>
  40 + </div>
  41 + <div
  42 + style="
  43 + width: 2.9vw;
  44 + height: 3.3vh;
  45 + margin-left: 1vw;
  46 + background-color: #ed6f6f;
  47 + border-radius: 2px;
  48 + cursor: pointer;
  49 + text-align: center;
  50 + line-height: 3.1vh;
  51 + "
  52 + >
  53 + <span @click="removeKeyAndValueFunc" style="color: white">删除</span>
  54 + </div>
  55 + </div>
  56 + <div> </div>
  57 + </div>
  58 + </div>
  59 + </template>
  60 + <template #uploadAdd1="{ field }">
  61 + <span style="display: none">{{ field }}</span>
  62 + <a-upload-dragger
  63 + v-model:fileList="fileList"
  64 + name="file"
  65 + :multiple="true"
  66 + action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
  67 + @change="handleChange"
  68 + >
  69 + <p class="ant-upload-drag-icon">
  70 + <InboxOutlined />
  71 + </p>
  72 + <p class="ant-upload-text">Click or drag file to this area to upload</p>
  73 + <p class="ant-upload-hint">
  74 + Support for a single or bulk upload. Strictly prohibit from uploading company data or
  75 + other band files
  76 + </p>
  77 + </a-upload-dragger>
  78 + </template>
  79 + <template #uploadAdd2="{ field }">
  80 + <span style="display: none">{{ field }}</span>
  81 + <a-upload-dragger
  82 + v-model:fileList="fileList"
  83 + name="file"
  84 + :multiple="true"
  85 + action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
  86 + @change="handleChange"
  87 + >
  88 + <p class="ant-upload-drag-icon">
  89 + <InboxOutlined />
  90 + </p>
  91 + <p class="ant-upload-text">Click or drag file to this area to upload</p>
  92 + <p class="ant-upload-hint">
  93 + Support for a single or bulk upload. Strictly prohibit from uploading company data or
  94 + other band files
  95 + </p>
  96 + </a-upload-dragger>
  97 + </template>
  98 + <template #uploadAdd3="{ field }">
  99 + <span style="display: none">{{ field }}</span>
  100 + <a-upload-dragger
  101 + v-model:fileList="fileList"
  102 + name="file"
  103 + :multiple="true"
  104 + action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
  105 + @change="handleChange"
  106 + >
  107 + <p class="ant-upload-drag-icon">
  108 + <InboxOutlined />
  109 + </p>
  110 + <p class="ant-upload-text">Click or drag file to this area to upload</p>
  111 + <p class="ant-upload-hint">
  112 + Support for a single or bulk upload. Strictly prohibit from uploading company data or
  113 + other band files
  114 + </p>
  115 + </a-upload-dragger>
  116 + </template>
  117 + </BasicForm>
  118 + </div>
  119 + </div>
  120 +</template>
  121 +<script lang="ts">
  122 + import { defineComponent, ref, reactive } from 'vue';
  123 + import { BasicForm, useForm } from '/@/components/Form';
  124 + import { modeApiForm, modeApiInseretKeyAndValueForm } from '../config';
  125 + import { InboxOutlined } from '@ant-design/icons-vue';
  126 + import { Alert, Divider, Descriptions, Upload } from 'ant-design-vue';
  127 + interface IKeyAndValue {
  128 + key: string;
  129 + value: string;
  130 + }
  131 + export default defineComponent({
  132 + components: {
  133 + BasicForm,
  134 + [Alert.name]: Alert,
  135 + [Divider.name]: Divider,
  136 + [Descriptions.name]: Descriptions,
  137 + [Descriptions.Item.name]: Descriptions.Item,
  138 + InboxOutlined,
  139 + [Upload.Dragger.name]: Upload.Dragger,
  140 + },
  141 + emits: ['next', 'prev', 'register'],
  142 + setup(_, { emit }) {
  143 + const fileList = ref<[]>([]);
  144 + const keyAndValueArr = ref<[]>([]);
  145 + const temp = ref({});
  146 + let tempObj = ref({});
  147 + const otherPropertiesValues = reactive({
  148 + headers: {},
  149 + });
  150 + const credentialsV = reactive({
  151 + credentials: {
  152 + type: '',
  153 + },
  154 + });
  155 + const keyAndValueArrTemp = ref<[]>([]);
  156 + const keyAndValueObj = reactive<IKeyAndValue>({
  157 + key: '',
  158 + value: '',
  159 + });
  160 + const sonValues = reactive({
  161 + configuration: {},
  162 + });
  163 + const [register, { validate, setFieldsValue, resetFields: defineClearFunc }] = useForm({
  164 + labelWidth: 80,
  165 + schemas: modeApiForm,
  166 + actionColOptions: {
  167 + span: 14,
  168 + },
  169 + resetButtonOptions: {
  170 + text: '上一步',
  171 + },
  172 +
  173 + resetFunc: customResetFunc,
  174 + submitFunc: customSubmitFunc,
  175 + });
  176 +
  177 + const [
  178 + registerKeyAndValue,
  179 + { validate: validateKeyAndValue, resetFields: defineClearKeyAndValueFunc },
  180 + ] = useForm({
  181 + labelWidth: 80,
  182 + schemas: modeApiInseretKeyAndValueForm,
  183 + actionColOptions: {
  184 + span: 14,
  185 + },
  186 + });
  187 + const setStepTwoFieldsValueFunc = (v, v1) => {
  188 + setFieldsValue(v);
  189 + setFieldsValue({
  190 + name: v1,
  191 + });
  192 + };
  193 + const customClearStepTwoValueFunc = async () => {
  194 + defineClearFunc();
  195 + defineClearKeyAndValueFunc();
  196 + };
  197 + async function customResetFunc() {
  198 + emit('prev');
  199 + }
  200 + async function customSubmitFunc() {
  201 + try {
  202 + const values = await validate();
  203 + emit('next', values);
  204 + } catch (error) {
  205 + } finally {
  206 + }
  207 + }
  208 + const tempGetKeyAndVal = async () => {
  209 + temp.value = await validateKeyAndValue();
  210 + };
  211 + // const defaultAddKeyAndValueFunc = () => {
  212 + // if (keyAndValueArr.value.length == 0) {
  213 + // keyAndValueArr.value.push(keyAndValueObj as never);
  214 + // }
  215 + // };
  216 + // defaultAddKeyAndValueFunc();
  217 +
  218 + const getDefaultValue = async () => {
  219 + await tempGetKeyAndVal();
  220 + keyAndValueArrTemp.value.push(temp.value as never);
  221 + };
  222 +
  223 + const addKeyAndValueFunc = async () => {
  224 + keyAndValueArr.value.push(keyAndValueObj as never);
  225 + await tempGetKeyAndVal();
  226 + tempObj.value = temp.value;
  227 + keyAndValueArrTemp.value.push(tempObj.value as never);
  228 + };
  229 + const removeKeyAndValueFunc = () => {
  230 + keyAndValueArr.value.splice(0, 1);
  231 + };
  232 + const handleChange = () => {};
  233 +
  234 + const getSonValueFunc = async () => {
  235 + sonValues.configuration = await validate();
  236 + if (keyAndValueArrTemp.value.length != 0) {
  237 + await getDefaultValue();
  238 + }
  239 + credentialsV.credentials.type = sonValues.configuration.type;
  240 + const kong = {};
  241 + let kongTemp = {};
  242 + keyAndValueArrTemp.value.map((item) => {
  243 + kong[item.key] = item.value;
  244 + });
  245 + kongTemp = JSON.parse(JSON.stringify(kong));
  246 + otherPropertiesValues.headers = kongTemp;
  247 + Object.assign(sonValues.configuration, otherPropertiesValues, credentialsV);
  248 + return sonValues;
  249 + };
  250 + return {
  251 + register,
  252 + setStepTwoFieldsValueFunc,
  253 + customClearStepTwoValueFunc,
  254 + addKeyAndValueFunc,
  255 + removeKeyAndValueFunc,
  256 + getSonValueFunc,
  257 + keyAndValueArr,
  258 + registerKeyAndValue,
  259 + fileList,
  260 + handleChange,
  261 + };
  262 + },
  263 + });
  264 +</script>
  265 +<style lang="less" scoped>
  266 + .root {
  267 + width: 47.55vw;
  268 + border: 1px solid #bfbfbf;
  269 + display: flex;
  270 + margin-top: 1vh;
  271 + margin-left: 1.5vw;
  272 + border-radius: 8px;
  273 +
  274 + .root-form {
  275 + width: 45vw;
  276 + margin: 1vh 1vw;
  277 + position: relative;
  278 + :deep .ant-input-number {
  279 + width: 18.35vw !important;
  280 + }
  281 + :deep .ant-btn {
  282 + position: absolute;
  283 + right: 1vw;
  284 + background-color: #0960bd;
  285 + border-radius: 2px;
  286 + span {
  287 + color: white;
  288 + }
  289 + }
  290 + }
  291 + }
  292 +</style>
... ...
  1 +<template>
  2 + <div class="root">
  3 + <div class="root-form">
  4 + <BasicForm :showResetButton="false" :showSubmitButton="false" @register="register">
  5 + <template #addValue="{ field }">
  6 + <span style="display: none">{{ field }}</span>
  7 + <div>
  8 + <div>
  9 + <div v-if="keyAndValueArr.length > 0">
  10 + <template v-for="(item, index) in keyAndValueArr" :key="index">
  11 + <span style="display: none">{{ item + index }}</span>
  12 + <BasicForm
  13 + :showResetButton="false"
  14 + :showSubmitButton="false"
  15 + @register="registerKeyAndValue"
  16 + />
  17 + </template>
  18 + </div>
  19 + <div
  20 + style="
  21 + width: 7vw;
  22 + height: 3.3vh;
  23 + display: flex;
  24 + flex-direction: row;
  25 + justify-content: center;
  26 + align-items: center;
  27 + margin-left: 1.8vw;
  28 + "
  29 + >
  30 + <div
  31 + style="
  32 + width: 2.9vw;
  33 + height: 3.3vh;
  34 + background-color: #0960bd;
  35 + border-radius: 2px;
  36 + cursor: pointer;
  37 + text-align: center;
  38 + line-height: 3.1vh;
  39 + "
  40 + >
  41 + <span @click="addKeyAndValueFunc" style="color: white">添加</span>
  42 + </div>
  43 + <div
  44 + style="
  45 + width: 2.9vw;
  46 + height: 3.3vh;
  47 + margin-left: 1vw;
  48 + background-color: #ed6f6f;
  49 + border-radius: 2px;
  50 + cursor: pointer;
  51 + text-align: center;
  52 + line-height: 3.1vh;
  53 + "
  54 + >
  55 + <span @click="removeKeyAndValueFunc" style="color: white">删除</span>
  56 + </div>
  57 + </div>
  58 + <div> </div>
  59 + </div>
  60 + </div>
  61 + </template>
  62 + </BasicForm>
  63 + <div
  64 + style="
  65 + width: 3.3vw;
  66 + height: 3.3vh;
  67 + margin-left: 22vw;
  68 + margin-top: 2vh;
  69 + background-color: #0960bd;
  70 + border-radius: 2px;
  71 + cursor: pointer;
  72 + text-align: center;
  73 + line-height: 3.1vh;
  74 + "
  75 + >
  76 + <span @click="customResetFunc" style="color: white">上一步</span>
  77 + </div>
  78 + </div>
  79 + </div>
  80 +</template>
  81 +<script lang="ts">
  82 + import { defineComponent, ref, reactive } from 'vue';
  83 + import { BasicForm, useForm } from '/@/components/Form';
  84 + import { modeKafkaForm, modeKafkaInseretKeyAndValueForm } from '../config';
  85 + import { Alert, Divider, Descriptions } from 'ant-design-vue';
  86 +
  87 + interface IKeyAndValue {
  88 + key: string;
  89 + value: string;
  90 + }
  91 +
  92 + export default defineComponent({
  93 + components: {
  94 + BasicForm,
  95 + [Alert.name]: Alert,
  96 + [Divider.name]: Divider,
  97 + [Descriptions.name]: Descriptions,
  98 + [Descriptions.Item.name]: Descriptions.Item,
  99 + },
  100 + emits: ['next', 'prev', 'register'],
  101 + setup(_, { emit }) {
  102 + const temp = ref({});
  103 + let tempObj = ref({});
  104 + const keyAndValueArr = ref<[]>([]);
  105 + const keyAndValueArrTemp = ref<[]>([]);
  106 + const vType = ref('');
  107 + const keyAndValueObj = reactive<IKeyAndValue>({
  108 + key: '',
  109 + value: '',
  110 + });
  111 + const sonValues = reactive({
  112 + configuration: {},
  113 + });
  114 + const otherPropertiesValues = reactive({
  115 + otherProperties: {},
  116 + });
  117 +
  118 + const [register, { validate, setFieldsValue, resetFields: defineClearFunc, clearValidate }] =
  119 + useForm({
  120 + labelWidth: 80,
  121 + schemas: modeKafkaForm,
  122 + actionColOptions: {
  123 + span: 14,
  124 + },
  125 + resetButtonOptions: {
  126 + text: '上一步',
  127 + },
  128 + resetFunc: customResetFunc,
  129 + });
  130 +
  131 + const [
  132 + registerKeyAndValue,
  133 + { validate: validateKeyAndValue, resetFields: defineClearKeyAndValueFunc },
  134 + ] = useForm({
  135 + labelWidth: 80,
  136 + schemas: modeKafkaInseretKeyAndValueForm,
  137 + actionColOptions: {
  138 + span: 14,
  139 + },
  140 + });
  141 +
  142 + const clearValidateFunc = async () => {
  143 + await clearValidate(['name']);
  144 + };
  145 +
  146 + const setStepTwoFieldsValueFunc = async (v, v1) => {
  147 + setFieldsValue(v);
  148 + vType.value = v1;
  149 + setFieldsValue({
  150 + name: v1,
  151 + });
  152 + };
  153 +
  154 + const customClearStepTwoValueFunc = async () => {
  155 + defineClearFunc();
  156 + defineClearKeyAndValueFunc();
  157 + };
  158 + async function customResetFunc() {
  159 + emit('prev');
  160 + }
  161 +
  162 + const tempGetKeyAndVal = async () => {
  163 + temp.value = await validateKeyAndValue();
  164 + };
  165 + // const defaultAddKeyAndValueFunc = () => {
  166 + // if (keyAndValueArr.value.length == 0) {
  167 + // keyAndValueArr.value.push(keyAndValueObj as never);
  168 + // }
  169 + // };
  170 + // defaultAddKeyAndValueFunc();
  171 +
  172 + const getDefaultValue = async () => {
  173 + await tempGetKeyAndVal();
  174 + keyAndValueArrTemp.value.push(temp.value as never);
  175 + };
  176 +
  177 + const addKeyAndValueFunc = async () => {
  178 + keyAndValueArr.value.push(keyAndValueObj as never);
  179 + await tempGetKeyAndVal();
  180 + tempObj.value = temp.value;
  181 + keyAndValueArrTemp.value.push(tempObj.value as never);
  182 + };
  183 + const removeKeyAndValueFunc = () => {
  184 + keyAndValueArr.value.splice(0, 1);
  185 + };
  186 +
  187 + const getSonValueFunc = async () => {
  188 + try {
  189 + sonValues.configuration = await validate();
  190 + if (keyAndValueArrTemp.value.length != 0) {
  191 + await getDefaultValue();
  192 + }
  193 + const kong = {};
  194 + let kongTemp = {};
  195 + keyAndValueArrTemp.value.map((item) => {
  196 + kong[item.key] = item.value;
  197 + });
  198 + kongTemp = JSON.parse(JSON.stringify(kong));
  199 + otherPropertiesValues.otherProperties = kongTemp;
  200 + Object.assign(sonValues.configuration, otherPropertiesValues);
  201 + return sonValues;
  202 + } catch (e) {
  203 + return e;
  204 + }
  205 + };
  206 + return {
  207 + clearValidateFunc,
  208 + getSonValueFunc,
  209 + keyAndValueArr,
  210 + register,
  211 + setStepTwoFieldsValueFunc,
  212 + customClearStepTwoValueFunc,
  213 + addKeyAndValueFunc,
  214 + registerKeyAndValue,
  215 + removeKeyAndValueFunc,
  216 + customResetFunc,
  217 + };
  218 + },
  219 + });
  220 +</script>
  221 +<style lang="less" scoped>
  222 + .root {
  223 + width: 47.55vw;
  224 + border: 1px solid #d9d9d9;
  225 + display: flex;
  226 + margin-top: 1vh;
  227 + margin-left: 1.5vw;
  228 + border-radius: 8px;
  229 + .root-form {
  230 + width: 45vw;
  231 + margin: 1vh 1vw;
  232 + position: relative;
  233 + :deep .ant-input-number {
  234 + width: 18.35vw !important;
  235 + }
  236 + }
  237 + }
  238 +</style>
... ...
  1 +<template>
  2 + <div class="root">
  3 + <div class="root-form">
  4 + <BasicForm :showSubmitButton="false" @register="register">
  5 + <template #uploadAdd1="{ field }">
  6 + <span style="display: none">{{ field }}</span>
  7 + <a-upload-dragger
  8 + v-model:fileList="fileList"
  9 + name="file"
  10 + :multiple="true"
  11 + action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
  12 + @change="handleChange"
  13 + >
  14 + <p class="ant-upload-drag-icon">
  15 + <InboxOutlined />
  16 + </p>
  17 + <p class="ant-upload-text">Click or drag file to this area to upload</p>
  18 + <p class="ant-upload-hint">
  19 + Support for a single or bulk upload. Strictly prohibit from uploading company data or
  20 + other band files
  21 + </p>
  22 + </a-upload-dragger>
  23 + </template>
  24 + <template #uploadAdd2="{ field }">
  25 + <span style="display: none">{{ field }}</span>
  26 + <a-upload-dragger
  27 + v-model:fileList="fileList"
  28 + name="file"
  29 + :multiple="true"
  30 + action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
  31 + @change="handleChange"
  32 + >
  33 + <p class="ant-upload-drag-icon">
  34 + <InboxOutlined />
  35 + </p>
  36 + <p class="ant-upload-text">Click or drag file to this area to upload</p>
  37 + <p class="ant-upload-hint">
  38 + Support for a single or bulk upload. Strictly prohibit from uploading company data or
  39 + other band files
  40 + </p>
  41 + </a-upload-dragger>
  42 + </template>
  43 + <template #uploadAdd3="{ field }">
  44 + <span style="display: none">{{ field }}</span>
  45 + <a-upload-dragger
  46 + v-model:fileList="fileList"
  47 + name="file"
  48 + :multiple="true"
  49 + action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
  50 + @change="handleChange"
  51 + >
  52 + <p class="ant-upload-drag-icon">
  53 + <InboxOutlined />
  54 + </p>
  55 + <p class="ant-upload-text">Click or drag file to this area to upload</p>
  56 + <p class="ant-upload-hint">
  57 + Support for a single or bulk upload. Strictly prohibit from uploading company data or
  58 + other band files
  59 + </p>
  60 + </a-upload-dragger>
  61 + </template>
  62 + </BasicForm>
  63 + </div>
  64 + </div>
  65 +</template>
  66 +<script lang="ts">
  67 + import { defineComponent, ref, reactive } from 'vue';
  68 + import { BasicForm, useForm } from '/@/components/Form';
  69 + import { modeMqttForm } from '../config';
  70 + import { InboxOutlined } from '@ant-design/icons-vue';
  71 + import { Alert, Divider, Descriptions, Upload } from 'ant-design-vue';
  72 +
  73 + export default defineComponent({
  74 + components: {
  75 + BasicForm,
  76 + [Alert.name]: Alert,
  77 + [Divider.name]: Divider,
  78 + [Descriptions.name]: Descriptions,
  79 + [Descriptions.Item.name]: Descriptions.Item,
  80 + InboxOutlined,
  81 + [Upload.Dragger.name]: Upload.Dragger,
  82 + },
  83 + emits: ['next', 'prev', 'register'],
  84 + setup(_, { emit }) {
  85 + const fileList = ref<[]>([]);
  86 + const credentialsV = reactive({
  87 + credentials: {
  88 + type: '',
  89 + },
  90 + });
  91 + const sonValues = reactive({
  92 + configuration: {},
  93 + });
  94 + const [register, { validate, setFieldsValue, resetFields: defineClearFunc }] = useForm({
  95 + labelWidth: 80,
  96 + schemas: modeMqttForm,
  97 + actionColOptions: {
  98 + span: 14,
  99 + },
  100 + resetButtonOptions: {
  101 + text: '上一步',
  102 + },
  103 +
  104 + resetFunc: customResetFunc,
  105 + submitFunc: customSubmitFunc,
  106 + });
  107 + const setStepTwoFieldsValueFunc = (v, v1) => {
  108 + setFieldsValue(v);
  109 + setFieldsValue({
  110 + name: v1,
  111 + });
  112 + };
  113 + const customClearStepTwoValueFunc = async () => {
  114 + defineClearFunc();
  115 + };
  116 + async function customResetFunc() {
  117 + emit('prev');
  118 + }
  119 + async function customSubmitFunc() {
  120 + try {
  121 + const values = await validate();
  122 + emit('next', values);
  123 + } catch (error) {
  124 + } finally {
  125 + }
  126 + }
  127 + const handleChange = () => {};
  128 + const getSonValueFunc = async () => {
  129 + sonValues.configuration = await validate();
  130 + credentialsV.credentials.type = sonValues.configuration.type;
  131 + Object.assign(sonValues.configuration, credentialsV);
  132 + return sonValues;
  133 + };
  134 + return {
  135 + getSonValueFunc,
  136 + register,
  137 + setStepTwoFieldsValueFunc,
  138 + customClearStepTwoValueFunc,
  139 + fileList,
  140 + handleChange,
  141 + };
  142 + },
  143 + });
  144 +</script>
  145 +<style lang="less" scoped>
  146 + .root {
  147 + width: 47.55vw;
  148 + min-height: 50vh;
  149 + border: 1px solid #bfbfbf;
  150 + display: flex;
  151 + margin-top: 1vh;
  152 + margin-left: 1.5vw;
  153 + border-radius: 8px;
  154 + .root-form {
  155 + width: 45vw;
  156 + margin: 1vh 1vw;
  157 + position: relative;
  158 + :deep .ant-input-number {
  159 + width: 18.35vw !important;
  160 + }
  161 + :deep .ant-btn {
  162 + position: absolute;
  163 + right: 1vw;
  164 + background-color: #0960bd;
  165 + border-radius: 2px;
  166 + span {
  167 + color: white;
  168 + }
  169 + }
  170 + }
  171 + }
  172 +</style>
... ...