Commit 5945f8fe5844ec9706d0049a1ff58c27b372ed90

Authored by sqy
1 parent b042fdeb

'调整文件名称'

Showing 49 changed files with 9919 additions and 0 deletions
  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>
  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: 1px;
  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: 1px;
  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 + </BasicForm>
  61 + </div>
  62 + </div>
  63 +</template>
  64 +<script lang="ts">
  65 + import { defineComponent, ref, reactive } from 'vue';
  66 + import { BasicForm, useForm } from '/@/components/Form';
  67 + import { modeRabbitMqForm, modeKafkaInseretKeyAndValueForm } from '../config';
  68 + import { Alert, Divider, Descriptions } from 'ant-design-vue';
  69 +
  70 + interface IKeyAndValue {
  71 + key: string;
  72 + value: string;
  73 + }
  74 + export default defineComponent({
  75 + components: {
  76 + BasicForm,
  77 + [Alert.name]: Alert,
  78 + [Divider.name]: Divider,
  79 + [Descriptions.name]: Descriptions,
  80 + [Descriptions.Item.name]: Descriptions.Item,
  81 + },
  82 + emits: ['next', 'prev', 'register'],
  83 + setup(_, { emit }) {
  84 + const temp = ref({});
  85 + let tempObj = ref({});
  86 + const otherPropertiesValues = reactive({
  87 + clientProperties: {},
  88 + });
  89 +
  90 + const keyAndValueArrTemp = ref<[]>([]);
  91 + const keyAndValueObj = reactive<IKeyAndValue>({
  92 + key: '',
  93 + value: '',
  94 + });
  95 + const keyAndValueArr = ref<[]>([]);
  96 + const sonValues = reactive({
  97 + configuration: {},
  98 + });
  99 +
  100 + const [register, { validate, setFieldsValue, resetFields: defineClearFunc }] = useForm({
  101 + labelWidth: 80,
  102 + schemas: modeRabbitMqForm,
  103 + actionColOptions: {
  104 + span: 14,
  105 + },
  106 + resetButtonOptions: {
  107 + text: '上一步',
  108 + },
  109 +
  110 + resetFunc: customResetFunc,
  111 + submitFunc: customSubmitFunc,
  112 + });
  113 +
  114 + const [registerKeyAndValue, { validate: validateKeyAndValue }] = useForm({
  115 + labelWidth: 80,
  116 + schemas: modeKafkaInseretKeyAndValueForm,
  117 + actionColOptions: {
  118 + span: 14,
  119 + },
  120 + });
  121 +
  122 + const setStepTwoFieldsValueFunc = (v, v1) => {
  123 + setFieldsValue(v);
  124 + setFieldsValue({
  125 + name: v1,
  126 + });
  127 + };
  128 + const customClearStepTwoValueFunc = async () => {
  129 + defineClearFunc();
  130 + };
  131 + async function customResetFunc() {
  132 + emit('prev');
  133 + }
  134 + async function customSubmitFunc() {
  135 + try {
  136 + const values = await validate();
  137 + emit('next', values);
  138 + } catch (error) {
  139 + } finally {
  140 + }
  141 + }
  142 + const tempGetKeyAndVal = async () => {
  143 + temp.value = await validateKeyAndValue();
  144 + };
  145 + // const defaultAddKeyAndValueFunc = () => {
  146 + // if (keyAndValueArr.value.length == 0) {
  147 + // keyAndValueArr.value.push(keyAndValueObj as never);
  148 + // }
  149 + // };
  150 + // defaultAddKeyAndValueFunc();
  151 +
  152 + const getDefaultValue = async () => {
  153 + await tempGetKeyAndVal();
  154 + keyAndValueArrTemp.value.push(temp.value as never);
  155 + };
  156 +
  157 + const addKeyAndValueFunc = async () => {
  158 + keyAndValueArr.value.push(keyAndValueObj as never);
  159 + await tempGetKeyAndVal();
  160 + tempObj.value = temp.value;
  161 + keyAndValueArrTemp.value.push(tempObj.value as never);
  162 + };
  163 + const removeKeyAndValueFunc = () => {
  164 + keyAndValueArr.value.splice(0, 1);
  165 + };
  166 + const getSonValueFunc = async () => {
  167 + sonValues.configuration = await validate();
  168 + if (keyAndValueArrTemp.value.length != 0) {
  169 + await getDefaultValue();
  170 + }
  171 + const kong = {};
  172 + let kongTemp = {};
  173 + keyAndValueArrTemp.value.map((item) => {
  174 + kong[item.key] = item.value;
  175 + });
  176 + kongTemp = JSON.parse(JSON.stringify(kong));
  177 + otherPropertiesValues.clientProperties = kongTemp;
  178 + Object.assign(sonValues.configuration, otherPropertiesValues);
  179 + return sonValues;
  180 + };
  181 +
  182 + return {
  183 + getSonValueFunc,
  184 + register,
  185 + setStepTwoFieldsValueFunc,
  186 + customClearStepTwoValueFunc,
  187 + keyAndValueArr,
  188 + registerKeyAndValue,
  189 + addKeyAndValueFunc,
  190 + removeKeyAndValueFunc,
  191 + };
  192 + },
  193 + });
  194 +</script>
  195 +<style lang="less" scoped>
  196 + .root {
  197 + width: 47.55vw;
  198 + border: 1px solid #d9d9d9;
  199 + display: flex;
  200 + margin-top: 1vh;
  201 + margin-left: 1.5vw;
  202 + border-radius: 8px;
  203 +
  204 + .root-form {
  205 + width: 44vw;
  206 + margin: 1vh 1vw;
  207 + position: relative;
  208 + :deep .ant-input-number {
  209 + width: 17.85vw !important;
  210 + }
  211 + :deep .ant-btn {
  212 + position: absolute;
  213 + right: 1vw;
  214 + background-color: #0960bd;
  215 + border-radius: 2px;
  216 + span {
  217 + color: white;
  218 + }
  219 + }
  220 + }
  221 + }
  222 +</style>
  1 +<template>
  2 + <div class="root">
  3 + <div class="root-form">
  4 + <div>
  5 + <BasicForm @register="register" />
  6 + </div>
  7 + </div>
  8 + </div>
  9 +</template>
  10 +<script lang="ts">
  11 + import { defineComponent, ref } from 'vue';
  12 + import { BasicForm, useForm } from '/@/components/Form';
  13 + import { modeForm } from './config';
  14 + import { Select, Input, Divider } from 'ant-design-vue';
  15 +
  16 + export default defineComponent({
  17 + components: {
  18 + BasicForm,
  19 + [Select.name]: Select,
  20 + [Input.name]: Input,
  21 + [Input.Group.name]: Input.Group,
  22 + [Divider.name]: Divider,
  23 + },
  24 + emits: ['next', 'resetFunc', 'register'],
  25 + setup(_, { emit }) {
  26 + const sonValues = ref({});
  27 + const [register, { validateFields, setFieldsValue, resetFields }] = useForm({
  28 + labelWidth: 100,
  29 + schemas: modeForm,
  30 + actionColOptions: {
  31 + span: 14,
  32 + },
  33 + showResetButton: false,
  34 + submitButtonOptions: {
  35 + text: '下一步',
  36 + },
  37 + submitFunc: customSubmitFunc,
  38 + });
  39 + //提交数据
  40 + async function customSubmitFunc() {
  41 + try {
  42 + const values = await validateFields();
  43 + emit('next', values);
  44 + } catch (error) {}
  45 + }
  46 + //回显数据
  47 + const setStepOneFieldsValueFunc = (v) => {
  48 + setFieldsValue(v);
  49 + };
  50 +
  51 + //清空数据
  52 + const customResetStepOneFunc = () => {
  53 + resetFields();
  54 + };
  55 + const getSonValueFunc = async () => {
  56 + sonValues.value = await validateFields();
  57 + return sonValues.value;
  58 + };
  59 + return {
  60 + getSonValueFunc,
  61 + register,
  62 + setStepOneFieldsValueFunc,
  63 + customResetStepOneFunc,
  64 + };
  65 + },
  66 + });
  67 +</script>
  68 +<style lang="less" scoped>
  69 + .root {
  70 + width: 100vw;
  71 + height: 30vh;
  72 + .root-form {
  73 + width: 40vw;
  74 + position: relative;
  75 + left: 14vw;
  76 + top: 8vh;
  77 + :deep .ant-btn {
  78 + position: absolute;
  79 + right: 8.6vw;
  80 + top: 6vh;
  81 + background-color: #0960bd;
  82 + border-radius: 2px;
  83 + span {
  84 + color: white;
  85 + }
  86 + }
  87 + }
  88 + }
  89 +</style>
  1 +<template>
  2 + <div class="step2">
  3 + <div>
  4 + <div v-show="isWhereComp == 'org.thingsboard.rule.engine.kafka.TbKafkaNode'">
  5 + <TransferConfigKafka ref="refTransferConfigKafka" @prev="getSonPrev" />
  6 + </div>
  7 + <div v-show="isWhereComp == 'org.thingsboard.rule.engine.mqtt.TbMqttNode'">
  8 + <TransferConfigMqtt ref="refTransferConfigMqtt" @prev="getSonPrev" />
  9 + </div>
  10 + <div v-show="isWhereComp == 'org.thingsboard.rule.engine.rabbitmq.TbRabbitMqNode'">
  11 + <TransferConfigRabbitMq ref="refTransferConfigRabbitMq" @prev="getSonPrev" />
  12 + </div>
  13 + <div v-show="isWhereComp == 'org.thingsboard.rule.engine.rest.TbRestApiCallNode'">
  14 + <TransferConfigApi ref="refTransferConfigApi" @prev="getSonPrev" />
  15 + </div>
  16 + </div>
  17 + </div>
  18 +</template>
  19 +<script lang="ts">
  20 + import { defineComponent, watch, ref, getCurrentInstance } from 'vue';
  21 + import TransferConfigKafka from '../cpns/cpns/transferConfigKafka.vue';
  22 + import TransferConfigMqtt from '../cpns/cpns/transferConfigMqtt.vue';
  23 + import TransferConfigRabbitMq from '../cpns/cpns/transferConfigRabbitMq.vue';
  24 + import TransferConfigApi from '../cpns/cpns/transferConfigApi.vue';
  25 + import { Alert, Divider, Descriptions } from 'ant-design-vue';
  26 +
  27 + export default defineComponent({
  28 + components: {
  29 + [Alert.name]: Alert,
  30 + [Divider.name]: Divider,
  31 + [Descriptions.name]: Descriptions,
  32 + [Descriptions.Item.name]: Descriptions.Item,
  33 + TransferConfigKafka,
  34 + TransferConfigMqtt,
  35 + TransferConfigRabbitMq,
  36 + TransferConfigApi,
  37 + },
  38 + // eslint-disable-next-line vue/require-prop-types
  39 + props: ['getModeSelect', 'defineClearFuncProp'],
  40 + emits: ['prevSon'],
  41 + setup(props, { emit }) {
  42 + const { proxy } = getCurrentInstance();
  43 + const getTransferConfigKafkaValue = ref({});
  44 + const refTransferConfigKafka = ref(null);
  45 + const refTransferConfigMqtt = ref(null);
  46 + const refTransferConfigRabbitMq = ref(null);
  47 + const refTransferConfigApi = ref(null);
  48 + const isWhereComp = ref('');
  49 +
  50 + const getSonPrev = () => {
  51 + emit('prevSon');
  52 + };
  53 + watch(
  54 + () => props.getModeSelect,
  55 + (val) => {
  56 + isWhereComp.value = val.type;
  57 + }
  58 + );
  59 + const clearSonValueDataFunc = () => {
  60 + try {
  61 + proxy.$refs.refTransferConfigKafka?.customClearStepTwoValueFunc();
  62 + proxy.$refs.refTransferConfigMqtt?.customClearStepTwoValueFunc();
  63 + proxy.$refs.refTransferConfigRabbitMq?.customClearStepTwoValueFunc();
  64 + proxy.$refs.refTransferConfigApi?.customClearStepTwoValueFunc();
  65 + } catch (e) {
  66 + return e;
  67 + }
  68 + };
  69 + const clearSonValueValidateFunc = () => {
  70 + try {
  71 + proxy.$refs.refTransferConfigKafka?.clearValidateFunc();
  72 + // proxy.$refs.refTransferConfigMqtt?.customClearStepTwoValueFunc();
  73 + // proxy.$refs.refTransferConfigRabbitMq?.customClearStepTwoValueFunc();
  74 + // proxy.$refs.refTransferConfigApi?.customClearStepTwoValueFunc();
  75 + } catch (e) {
  76 + return e;
  77 + }
  78 + };
  79 + const getSonValueDataFunc = () => {
  80 + if (isWhereComp.value == 'org.thingsboard.rule.engine.kafka.TbKafkaNode') {
  81 + getTransferConfigKafkaValue.value = proxy.$refs.refTransferConfigKafka.getSonValueFunc();
  82 + } else if (isWhereComp.value == 'org.thingsboard.rule.engine.mqtt.TbMqttNode') {
  83 + getTransferConfigKafkaValue.value = proxy.$refs.refTransferConfigMqtt.getSonValueFunc();
  84 + } else if (isWhereComp.value == 'org.thingsboard.rule.engine.rabbitmq.TbRabbitMqNode') {
  85 + getTransferConfigKafkaValue.value =
  86 + proxy.$refs.refTransferConfigRabbitMq.getSonValueFunc();
  87 + } else if (isWhereComp.value == 'org.thingsboard.rule.engine.rest.TbRestApiCallNode') {
  88 + getTransferConfigKafkaValue.value = proxy.$refs.refTransferConfigApi.getSonValueFunc();
  89 + }
  90 + return getTransferConfigKafkaValue.value;
  91 + };
  92 + const editSonValueDataFunc = (v) => {
  93 + try {
  94 + if (v.type == 'org.thingsboard.rule.engine.kafka.TbKafkaNode') {
  95 + isWhereComp.value = v.type;
  96 + proxy.$refs.refTransferConfigKafka.setStepTwoFieldsValueFunc(v.configuration, v.name);
  97 + } else if (v.type == 'org.thingsboard.rule.engine.mqtt.TbMqttNode') {
  98 + isWhereComp.value = v.type;
  99 + proxy.$refs.refTransferConfigMqtt.setStepTwoFieldsValueFunc(v.configuration, v.name);
  100 + } else if (v.type == 'org.thingsboard.rule.engine.rabbitmq.TbRabbitMqNode') {
  101 + isWhereComp.value = v.type;
  102 + proxy.$refs.refTransferConfigRabbitMq.setStepTwoFieldsValueFunc(
  103 + v.configuration,
  104 + v.name
  105 + );
  106 + } else if (v.type == 'org.thingsboard.rule.engine.rest.TbRestApiCallNode') {
  107 + isWhereComp.value = v.type;
  108 + proxy.$refs.refTransferConfigApi.setStepTwoFieldsValueFunc(v.configuration, v.name);
  109 + }
  110 + } catch (e) {
  111 + return e;
  112 + }
  113 + };
  114 + return {
  115 + clearSonValueValidateFunc,
  116 + clearSonValueDataFunc,
  117 + editSonValueDataFunc,
  118 + refTransferConfigKafka,
  119 + getSonValueDataFunc,
  120 + getSonPrev,
  121 + isWhereComp,
  122 + refTransferConfigMqtt,
  123 + refTransferConfigRabbitMq,
  124 + refTransferConfigApi,
  125 + };
  126 + },
  127 + });
  128 +</script>
  129 +<style lang="less" scoped></style>
  1 +<template>
  2 + <div>
  3 + <BasicTable
  4 + @selection-change="useSelectionChange"
  5 + @register="registerTable"
  6 + :loading="loading"
  7 + :rowSelection="{ type: 'checkbox' }"
  8 + >
  9 + <template #toolbar>
  10 + <a-button type="primary" @click="handleAdd"> 添加转换 </a-button>
  11 + <a-button
  12 + :disabled="disabledStatus1"
  13 + @click="handleDelete"
  14 + :type="disabledStatus1 ? 'default' : 'primary'"
  15 + >
  16 + <span :style="{ color: disabledStatus1 ? 'grey' : 'white' }">批量删除</span>
  17 + </a-button>
  18 + <a-button
  19 + :disabled="disabledStatus2"
  20 + @click="handleMutiuteDisable"
  21 + :type="disabledStatus2 ? 'default' : 'primary'"
  22 + >
  23 + <span :style="{ color: disabledStatus2 ? 'grey' : 'white' }">批量禁用</span>
  24 + </a-button>
  25 + <a-button
  26 + :disabled="disabledStatus3"
  27 + @click="handleMutiuteEnable"
  28 + :type="disabledStatus3 ? 'default' : 'primary'"
  29 + >
  30 + <span :style="{ color: disabledStatus3 ? 'grey' : 'white' }">批量启用</span>
  31 + </a-button>
  32 + </template>
  33 + <template #action="{ record }">
  34 + <TableAction
  35 + :actions="[
  36 + {
  37 + label: '编辑',
  38 + icon: 'clarity:note-edit-line',
  39 + onClick: handleEdit.bind(null, record),
  40 + ifShow: (_action) => {
  41 + return record.status == 0;
  42 + },
  43 + },
  44 +
  45 + {
  46 + label: '删除',
  47 + icon: 'ant-design:delete-outlined',
  48 + color: 'error',
  49 + popConfirm: {
  50 + title: '是否确认删除',
  51 + confirm: handleSingleDelete.bind(null, record),
  52 + },
  53 + ifShow: (_action) => {
  54 + return record.status == 0;
  55 + },
  56 + },
  57 + {
  58 + label: '启用',
  59 + icon: 'ant-design:check-circle-outlined',
  60 + color: 'success',
  61 + popConfirm: {
  62 + title: '是否启用?',
  63 + confirm: handleEnableOrDisable.bind(null, record),
  64 + },
  65 + ifShow: (_action) => {
  66 + return record.status == 0;
  67 + },
  68 + },
  69 + {
  70 + label: '禁用',
  71 + icon: 'ant-design:close-circle-outlined',
  72 + popConfirm: {
  73 + title: '是否禁用?',
  74 + confirm: handleDisable.bind(null, record),
  75 + },
  76 + ifShow: (_action) => {
  77 + return record.status == 1;
  78 + },
  79 + },
  80 + ]"
  81 + />
  82 + </template>
  83 + </BasicTable>
  84 + <div>
  85 + <DataTransferDrawer @register="registerModal" @success="handleSuccess" />
  86 + </div>
  87 + </div>
  88 +</template>
  89 +<script lang="ts">
  90 + import { defineComponent, reactive, ref } from 'vue';
  91 + import { BasicTable, useTable, TableAction } from '/@/components/Table';
  92 + import { columns, searchFormSchema } from './config';
  93 + import { useModal } from '/@/components/Modal';
  94 + import DataTransferDrawer from './addDataTransferDrawer.vue';
  95 + import {
  96 + getConvertApi,
  97 + isEnableOrDisableApi,
  98 + deleteConvertApi,
  99 + } from '/@/api/datamanager/dataManagerApi';
  100 + import { useMessage } from '/@/hooks/web/useMessage';
  101 +
  102 + export default defineComponent({
  103 + name: 'Index',
  104 + components: { BasicTable, TableAction, DataTransferDrawer },
  105 + setup() {
  106 + const enableObj = reactive({
  107 + convertIds: [],
  108 + status: 0,
  109 + });
  110 + const disabledStatus1 = ref(true);
  111 + const disabledStatus2 = ref(true);
  112 + const disabledStatus3 = ref(true);
  113 + const loading = ref(true);
  114 + const { createMessage } = useMessage();
  115 + let selectedRowKeys: any = ref([]);
  116 + let getSelectRowsArr: any = ref([]);
  117 + let isJudgeSelectRowsArr: any = ref([]);
  118 + const [registerModal, { openModal }] = useModal();
  119 + const [
  120 + registerTable,
  121 + { reload, getSelectRowKeys, getSelectRows, setLoading, clearSelectedRowKeys },
  122 + ] = useTable({
  123 + title: '数据转换列表',
  124 + clickToRowSelect: false,
  125 + columns,
  126 + api: getConvertApi,
  127 + formConfig: {
  128 + labelWidth: 120,
  129 + schemas: searchFormSchema,
  130 + },
  131 + rowKey: 'id',
  132 + useSearchForm: true,
  133 + showTableSetting: true,
  134 + bordered: true,
  135 + showIndexColumn: false,
  136 + actionColumn: {
  137 + width: 180,
  138 + title: '操作',
  139 + dataIndex: 'action',
  140 + slots: { customRender: 'action' },
  141 + fixed: 'right',
  142 + },
  143 + });
  144 +
  145 + //新增
  146 + const handleAdd = () => {
  147 + setTimeout(() => {
  148 + openModal(true, {
  149 + isUpdate: false,
  150 + });
  151 + }, 10);
  152 + };
  153 +
  154 + const handleSuccess = () => {
  155 + reload();
  156 + };
  157 + const handleEdit = (record: Recordable) => {
  158 + setTimeout(() => {
  159 + openModal(true, {
  160 + record,
  161 + isUpdate: true,
  162 + });
  163 + }, 10);
  164 + };
  165 +
  166 + const handleEnableOrDisable = async (record: Recordable) => {
  167 + setLoading(true);
  168 + enableObj.convertIds.length = 0;
  169 + try {
  170 + enableObj.status = record.status;
  171 + enableObj.convertIds.push(record.id as never);
  172 + if (enableObj.status == 0) {
  173 + enableObj.status = 1;
  174 + }
  175 + const res = await isEnableOrDisableApi(enableObj as never);
  176 + if (res !== '') {
  177 + createMessage.success('转换配置启用成功');
  178 + setLoading(false);
  179 + reload();
  180 + } else {
  181 + createMessage.error('转换配置启用失败');
  182 + }
  183 + } catch (e) {
  184 + return e;
  185 + } finally {
  186 + setLoading(false);
  187 + }
  188 + };
  189 + const handleDisable = async (record: Recordable) => {
  190 + setLoading(true);
  191 + enableObj.convertIds.length = 0;
  192 + try {
  193 + enableObj.status = record.status;
  194 + enableObj.convertIds.push(record.id as never);
  195 + if (enableObj.status == 1) {
  196 + enableObj.status = 0;
  197 + }
  198 + const res = await isEnableOrDisableApi(enableObj as never);
  199 + if (res !== '') {
  200 + createMessage.success('转换配置禁用成功');
  201 + setLoading(false);
  202 + reload();
  203 + } else {
  204 + createMessage.error('转换配置禁用失败');
  205 + }
  206 + } catch (e) {
  207 + } finally {
  208 + setLoading(false);
  209 + }
  210 + };
  211 + const handleSingleDelete = async (record: Recordable) => {
  212 + try {
  213 + let ids = [record.id];
  214 + await deleteConvertApi(ids);
  215 + createMessage.success('删除成功');
  216 + reload();
  217 + } catch (e) {
  218 + return e;
  219 + }
  220 + };
  221 + const useSelectionChange = () => {
  222 + selectedRowKeys.value = getSelectRowKeys();
  223 + isJudgeSelectRowsArr.value = getSelectRows();
  224 + const hasDisableStatus = isJudgeSelectRowsArr.value.map((m) => {
  225 + return m.status;
  226 + });
  227 + if (hasDisableStatus.length == 0) {
  228 + disabledStatus1.value = true;
  229 + disabledStatus2.value = true;
  230 + disabledStatus3.value = true;
  231 + }
  232 + hasDisableStatus.every((e) => {
  233 + if (e == 1) {
  234 + disabledStatus3.value = true;
  235 + disabledStatus2.value = false;
  236 + } else if (e == 0) {
  237 + disabledStatus2.value = true;
  238 + disabledStatus3.value = false;
  239 + }
  240 + });
  241 + let i1 = hasDisableStatus.indexOf(0);
  242 + let i2 = hasDisableStatus.indexOf(1);
  243 + if (i1 !== -1 && i2 !== -1) {
  244 + disabledStatus2.value = true;
  245 + disabledStatus3.value = true;
  246 + }
  247 + if (isJudgeSelectRowsArr.value.length == 0) {
  248 + disabledStatus1.value = true;
  249 + } else {
  250 + disabledStatus1.value = false;
  251 + }
  252 + };
  253 +
  254 + const handleDelete = async () => {
  255 + try {
  256 + setLoading(true);
  257 + const data = await deleteConvertApi(selectedRowKeys.value);
  258 + if (data == true) {
  259 + createMessage.success('删除成功');
  260 + setLoading(false);
  261 + reload();
  262 + } else {
  263 + createMessage.error('删除失败');
  264 + }
  265 + } catch (e) {
  266 + return e;
  267 + } finally {
  268 + setLoading(false);
  269 + clearSelectedRowKeys();
  270 + }
  271 + };
  272 + const handleMutiuteDisable = async () => {
  273 + enableObj.convertIds.length = 0;
  274 + try {
  275 + setLoading(true);
  276 + getSelectRowsArr.value = getSelectRows();
  277 + getSelectRowsArr.value.forEach((f) => {
  278 + if (f.id) {
  279 + enableObj.status = 0;
  280 + enableObj.convertIds.push(f.id as never);
  281 + }
  282 + });
  283 + const res = await isEnableOrDisableApi(enableObj as never);
  284 + if (res !== '') {
  285 + createMessage.success('转换配置多项禁用成功');
  286 + setLoading(false);
  287 + reload();
  288 + } else {
  289 + createMessage.error('转换配置多项禁用失败');
  290 + }
  291 + } catch (e) {
  292 + return e;
  293 + } finally {
  294 + setLoading(false);
  295 + clearSelectedRowKeys();
  296 + }
  297 + };
  298 +
  299 + const handleMutiuteEnable = async () => {
  300 + enableObj.convertIds.length = 0;
  301 + try {
  302 + setLoading(true);
  303 + getSelectRowsArr.value = getSelectRows();
  304 + getSelectRowsArr.value.forEach((f) => {
  305 + if (f.id) {
  306 + enableObj.status = 1;
  307 + enableObj.convertIds.push(f.id as never);
  308 + }
  309 + });
  310 + const res = await isEnableOrDisableApi(enableObj as never);
  311 + if (res !== '') {
  312 + createMessage.success('转换配置多项启用成功');
  313 + setLoading(false);
  314 + reload();
  315 + } else {
  316 + createMessage.error('转换配置多项启用失败');
  317 + }
  318 + } catch (e) {
  319 + return e;
  320 + } finally {
  321 + setLoading(false);
  322 + clearSelectedRowKeys();
  323 + }
  324 + };
  325 +
  326 + return {
  327 + disabledStatus1,
  328 + disabledStatus2,
  329 + disabledStatus3,
  330 + handleMutiuteEnable,
  331 + loading,
  332 + registerTable,
  333 + handleAdd,
  334 + handleDelete,
  335 + registerModal,
  336 + handleSuccess,
  337 + handleEdit,
  338 + handleEnableOrDisable,
  339 + handleSingleDelete,
  340 + useSelectionChange,
  341 + handleMutiuteDisable,
  342 + handleDisable,
  343 + };
  344 + },
  345 + });
  346 +</script>
  347 +
  348 +<style lang="less" scoped></style>
  1 +<template>
  2 + <CollapseContainer style="background-color: #eeeeee">
  3 + <div style="position: relative">
  4 + <BasicForm
  5 + :labelWidth="100"
  6 + :emptySpan="10"
  7 + :showResetButton="false"
  8 + :showSubmitButton="false"
  9 + @register="registerCondition"
  10 + />
  11 + </div>
  12 + </CollapseContainer>
  13 +</template>
  14 +<script lang="ts">
  15 + import { defineComponent, ref } from 'vue';
  16 + import { CollapseContainer } from '/@/components/Container/index';
  17 + import { BasicForm, useForm } from '/@/components/Form/index';
  18 + import { Input } from 'ant-design-vue';
  19 + import { useConditionDrawerSchema } from '../config';
  20 + // import { screenLinkPageByDeptIdGetDevice } from '/@/api/ruleengine/ruleengineApi';
  21 +
  22 + export default defineComponent({
  23 + components: { CollapseContainer, BasicForm, [Input.name]: Input },
  24 + props: ['deviceInfo1', 'editConditionFather', 'newConditionMapFather'],
  25 +
  26 + setup(props) {
  27 + const fieldValue: any = ref({});
  28 + const [registerCondition, { setFieldsValue, getFieldsValue, updateSchema, resetFields }] =
  29 + useForm({
  30 + labelWidth: 100,
  31 + schemas: useConditionDrawerSchema,
  32 + actionColOptions: { span: 24 },
  33 + });
  34 + const getFieldsValueFunc = () => {
  35 + fieldValue.value = getFieldsValue();
  36 + return fieldValue.value;
  37 + };
  38 + const resetFieldsValueFunc = () => {
  39 + resetFields();
  40 + };
  41 + const updateFieldDeviceId = (v) => {
  42 + setTimeout(() => {
  43 + updateSchema({
  44 + field: 'entityId',
  45 + componentProps: {
  46 + options: v,
  47 + },
  48 + });
  49 + }, 10);
  50 + };
  51 +
  52 + //回显数据
  53 + const setFieldsFormValueFun = () => {
  54 + if (props.editConditionFather !== 1) {
  55 + setTimeout(() => {
  56 + setFieldsValue(props.editConditionFather);
  57 + setFieldsValue({
  58 + type:
  59 + props.editConditionFather?.triggerCondition?.condition[0]?.valueType == 'NUMERIC'
  60 + ? 'NUMERIC1'
  61 + : 'NUMERIC2',
  62 + operation1:
  63 + props.editConditionFather?.triggerCondition?.condition[0]?.predicate?.operation,
  64 + operation2:
  65 + props.editConditionFather?.triggerCondition?.condition[0]?.predicate?.operation,
  66 + value1:
  67 + props.editConditionFather?.triggerCondition?.condition[0]?.predicate?.value
  68 + ?.defaultValue,
  69 + value2:
  70 + props.editConditionFather?.triggerCondition?.condition[0]?.predicate?.value
  71 + ?.defaultValue,
  72 + });
  73 + }, 100);
  74 + }
  75 + };
  76 + setFieldsFormValueFun();
  77 + const editSelectDevice = () => {
  78 + if (props.newConditionMapFather !== 1) {
  79 + setTimeout(() => {
  80 + updateSchema({
  81 + field: 'entityId',
  82 + componentProps: {
  83 + options: props.newConditionMapFather,
  84 + },
  85 + });
  86 + }, 100);
  87 + }
  88 + };
  89 + editSelectDevice();
  90 + //新增清空设备选择
  91 + const clearSelectDevice = () => {
  92 + updateSchema({
  93 + field: 'entityId',
  94 + componentProps: {
  95 + options: [],
  96 + },
  97 + });
  98 + };
  99 + // const editSelectDevice = (v) => {
  100 + // updateSchema({
  101 + // field: 'entityId',
  102 + // componentProps: {
  103 + // options: v,
  104 + // },
  105 + // });
  106 + // };
  107 + return {
  108 + updateFieldDeviceId,
  109 + resetFieldsValueFunc,
  110 + clearSelectDevice,
  111 + editSelectDevice,
  112 + getFieldsValueFunc,
  113 + registerCondition,
  114 + };
  115 + },
  116 + });
  117 +</script>
  1 +<template>
  2 + <CollapseContainer class="prefixRedDot" style="background-color: #eeeeee">
  3 + <div style="position: relative">
  4 + <BasicForm
  5 + :labelWidth="100"
  6 + :showResetButton="false"
  7 + :showSubmitButton="false"
  8 + :emptySpan="10"
  9 + @register="registerAction"
  10 + />
  11 + </div>
  12 + </CollapseContainer>
  13 +</template>
  14 +<script lang="ts">
  15 + import { defineComponent, ref } from 'vue';
  16 + import { CollapseContainer } from '/@/components/Container/index';
  17 + import { BasicForm, useForm } from '/@/components/Form/index';
  18 + import { Input } from 'ant-design-vue';
  19 + import { useActionDrawerSchema } from '../config';
  20 +
  21 + export default defineComponent({
  22 + components: { CollapseContainer, BasicForm, [Input.name]: Input },
  23 + props: ['deviceInfo2', 'editActionFather', 'newActionMapFather'],
  24 +
  25 + setup(props) {
  26 + const fieldValue: any = ref({});
  27 + const [registerAction, { setFieldsValue, getFieldsValue, resetFields, updateSchema }] =
  28 + useForm({
  29 + labelWidth: 100,
  30 + schemas: useActionDrawerSchema,
  31 + actionColOptions: { span: 24 },
  32 + });
  33 + const getFieldsValueFunc = () => {
  34 + fieldValue.value = getFieldsValue();
  35 + return fieldValue.value;
  36 + };
  37 + const resetFieldsValueFunc = () => {
  38 + resetFields();
  39 + };
  40 + const updateFieldDeviceId = (v) => {
  41 + setTimeout(() => {
  42 + updateSchema({
  43 + field: 'deviceId',
  44 + componentProps: {
  45 + options: v,
  46 + },
  47 + });
  48 + }, 10);
  49 + };
  50 +
  51 + //回显数据
  52 + const setFieldsFormValueFun = () => {
  53 + if (props.editActionFather !== 1) {
  54 + setTimeout(() => {
  55 + setFieldsValue(props.editActionFather);
  56 + }, 100);
  57 + }
  58 + };
  59 + setFieldsFormValueFun();
  60 + const editSelectDevice = () => {
  61 + if (props.newActionMapFather !== 1) {
  62 + setTimeout(() => {
  63 + updateSchema({
  64 + field: 'deviceId',
  65 + componentProps: {
  66 + options: props.newActionMapFather,
  67 + },
  68 + });
  69 + }, 100);
  70 + }
  71 + };
  72 + editSelectDevice();
  73 + //新增清空设备选择
  74 + const clearSelectDevice = () => {
  75 + updateSchema({
  76 + field: 'deviceId',
  77 + componentProps: {
  78 + options: [],
  79 + },
  80 + });
  81 + };
  82 + return {
  83 + updateFieldDeviceId,
  84 + clearSelectDevice,
  85 + editSelectDevice,
  86 + resetFieldsValueFunc,
  87 + getFieldsValueFunc,
  88 + registerAction,
  89 + };
  90 + },
  91 + });
  92 +</script>
  93 +
  94 +<style lang="less">
  95 + .prefixRedDot:before {
  96 + content: '* ';
  97 + color: red;
  98 + vertical-align: middle;
  99 + display: inline-block;
  100 + position: relative;
  101 + top: 20px;
  102 + left: 5px;
  103 + }
  104 +</style>
  1 +<template>
  2 + <div>
  3 + <CollapseContainer style="background-color: #eeeeee">
  4 + <div>
  5 + <BasicForm
  6 + :labelWidth="100"
  7 + :showResetButton="false"
  8 + :showSubmitButton="false"
  9 + :emptySpan="10"
  10 + @register="registerTrigger"
  11 + />
  12 + </div>
  13 + </CollapseContainer>
  14 + </div>
  15 +</template>
  16 +<script lang="ts">
  17 + import { defineComponent, ref } from 'vue';
  18 + import { CollapseContainer } from '/@/components/Container/index';
  19 + import { BasicForm, useForm } from '/@/components/Form/index';
  20 + import { Input } from 'ant-design-vue';
  21 + import { useTriggerDrawerSchema } from '../config';
  22 +
  23 + export default defineComponent({
  24 + components: { CollapseContainer, BasicForm, [Input.name]: Input },
  25 + props: ['deviceInfo', 'editTriggerFather', 'newFilterMapFather'],
  26 + setup(props) {
  27 + const fieldValue: any = ref({});
  28 + const [registerTrigger, { resetFields, setFieldsValue, getFieldsValue, updateSchema }] =
  29 + useForm({
  30 + labelWidth: 100,
  31 + schemas: useTriggerDrawerSchema,
  32 + actionColOptions: { span: 24 },
  33 + });
  34 + const getFieldsValueFunc = () => {
  35 + fieldValue.value = getFieldsValue();
  36 + return fieldValue.value;
  37 + };
  38 + const updateFieldDeviceId = (v) => {
  39 + setTimeout(() => {
  40 + updateSchema({
  41 + field: 'entityId',
  42 + componentProps: {
  43 + options: v,
  44 + },
  45 + });
  46 + }, 10);
  47 + };
  48 + const resetFieldsValueFunc = () => {
  49 + resetFields();
  50 + };
  51 +
  52 + //回显数据
  53 + const setFieldsFormValueFun = () => {
  54 + if (props.editTriggerFather != 1) {
  55 + setTimeout(() => {
  56 + setFieldsValue(props.editTriggerFather);
  57 + setFieldsValue({
  58 + entityId1: props.editTriggerFather.entityId,
  59 + entityId2: props.editTriggerFather.entityId,
  60 + type1: props.editTriggerFather?.triggerCondition?.condition[0]?.key?.type,
  61 + type2: props.editTriggerFather?.triggerCondition?.condition[0]?.predicate?.type,
  62 + operation:
  63 + props.editTriggerFather?.triggerCondition?.condition[0]?.predicate?.operation,
  64 + value:
  65 + props.editTriggerFather?.triggerCondition?.condition[0]?.predicate?.value
  66 + ?.defaultValue,
  67 + });
  68 + }, 10);
  69 + }
  70 + };
  71 +
  72 + setFieldsFormValueFun();
  73 + //新增清空设备选择
  74 + const clearSelectDevice = () => {
  75 + updateSchema({
  76 + field: 'entityId',
  77 + componentProps: {
  78 + options: [],
  79 + },
  80 + });
  81 + };
  82 + const editSelectDevice = () => {
  83 + if (props.newFilterMapFather != 1) {
  84 + setTimeout(() => {
  85 + updateSchema({
  86 + field: 'entityId',
  87 + componentProps: {
  88 + options: props.newFilterMapFather,
  89 + },
  90 + });
  91 + }, 100);
  92 + }
  93 + };
  94 + editSelectDevice();
  95 + //新增清空场景触发器选择
  96 + const clearSelectScene = () => {
  97 + updateSchema({
  98 + field: 'sceneLinkageId',
  99 + componentProps: {
  100 + options: [],
  101 + },
  102 + });
  103 + };
  104 + const editSelectScene = (v) => {
  105 + updateSchema({
  106 + field: 'sceneLinkageId',
  107 + componentProps: {
  108 + options: v,
  109 + },
  110 + });
  111 + };
  112 + return {
  113 + updateFieldDeviceId,
  114 + resetFieldsValueFunc,
  115 + clearSelectScene,
  116 + editSelectScene,
  117 + clearSelectDevice,
  118 + editSelectDevice,
  119 + getFieldsValueFunc,
  120 + registerTrigger,
  121 + };
  122 + },
  123 + });
  124 +</script>
  125 +
  126 +<style>
  127 + .ant-slider-handle {
  128 + display: none !important;
  129 + }
  130 +</style>
  1 +import { BasicColumn, FormSchema } from '/@/components/Table';
  2 +import { ref } from 'vue';
  3 +import {
  4 + screenLinkOrganizationGetApi,
  5 + screenLinkPagePutApi,
  6 +} from '/@/api/ruleengine/ruleengineApi';
  7 +import { h } from 'vue';
  8 +import { Switch } from 'ant-design-vue';
  9 +import { useMessage } from '/@/hooks/web/useMessage';
  10 +import { copyTransFun } from '/@/utils/fnUtils';
  11 +
  12 +/**
  13 + * 所使用的枚举值
  14 + */
  15 +
  16 +export enum TriggerEnum {
  17 + IS_DEVICE_ACT = 'DEVICE_TRIGGER',
  18 + IS_TIME_ACT = 'SCHEDULE_TRIGGER',
  19 + IS_SCENE_ACT = 'SCENE_TRIGGER',
  20 + IS_HAND_ACT = 'HAND_ACT',
  21 + IS_MSG_NOTIFY = 'MSG_NOTIFY',
  22 + IS_DEVICE_STATUS = 'DEVICE_STATUS',
  23 + IS_TIME_ALL = 'SCHEDULE_TRIGGER',
  24 +}
  25 +
  26 +export enum AttributeActionEnum {
  27 + IS_ATTRIBUTE_ACT = 'ATTRIBUTE',
  28 + IS_UP_DOWN_ACT = 'TIME_SERIES',
  29 +}
  30 +
  31 +export enum AttrAndWenDuEnum {
  32 + IS_ALL_ATTR = 'ALL_ATTR',
  33 + IS_WENDU_ACT = 'NUMERIC',
  34 + IS_SHIDU = 'NUMERIC',
  35 + IS_CONDITION_WENDU = 'NUMERIC2',
  36 + IS_CONDITION_SHIDU = 'NUMERIC1',
  37 +}
  38 +export const isConditionShiDu = (type: string) => {
  39 + return type === AttrAndWenDuEnum.IS_CONDITION_SHIDU;
  40 +};
  41 +export const isConditionWenDu = (type: string) => {
  42 + return type === AttrAndWenDuEnum.IS_CONDITION_WENDU;
  43 +};
  44 +
  45 +export const isShiDu = (type: string) => {
  46 + return type === AttrAndWenDuEnum.IS_SHIDU;
  47 +};
  48 +
  49 +export const isWenDu = (type: string) => {
  50 + return type === AttrAndWenDuEnum.IS_WENDU_ACT;
  51 +};
  52 +
  53 +export const isTimeAll = (type: string) => {
  54 + return type === TriggerEnum.IS_TIME_ACT;
  55 +};
  56 +
  57 +export const isMsg = (type: string) => {
  58 + return type === TriggerEnum.IS_MSG_NOTIFY;
  59 +};
  60 +
  61 +export const isUpAndDown = (type: string) => {
  62 + return type === AttributeActionEnum.IS_UP_DOWN_ACT;
  63 +};
  64 +
  65 +export const isDevice = (type: string) => {
  66 + return type === TriggerEnum.IS_DEVICE_ACT;
  67 +};
  68 +
  69 +export const isTime = (type: string) => {
  70 + return type === TriggerEnum.IS_TIME_ACT;
  71 +};
  72 +
  73 +export const isScene = (type: string) => {
  74 + return type === TriggerEnum.IS_SCENE_ACT;
  75 +};
  76 +
  77 +export const isHand = (type: string) => {
  78 + return type === TriggerEnum.IS_HAND_ACT;
  79 +};
  80 +
  81 +export const columns: BasicColumn[] = [
  82 + {
  83 + title: '场景联动名称',
  84 + dataIndex: 'name',
  85 + width: 200,
  86 + },
  87 + {
  88 + title: '触发方式',
  89 + dataIndex: 'triggerType',
  90 + format: (text: string, record: Recordable) => {
  91 + return record.triggers[0]?.triggerType == 'DEVICE_TRIGGER'
  92 + ? '设备触发'
  93 + : record.triggers[0]?.triggerType == 'SCHEDULE_TRIGGER'
  94 + ? '定时触发'
  95 + : record.triggers[0]?.triggerType == 'SCENE_TRIGGER'
  96 + ? '场景触发'
  97 + : '手动触发';
  98 + },
  99 + width: 200,
  100 + },
  101 + {
  102 + title: '状态',
  103 + dataIndex: 'status',
  104 + width: 120,
  105 + customRender: ({ record }) => {
  106 + if (!Reflect.has(record, 'pendingStatus')) {
  107 + record.pendingStatus = false;
  108 + }
  109 + return h(Switch, {
  110 + checked: record.status === 1,
  111 + checkedChildren: '已启用',
  112 + unCheckedChildren: '已禁用',
  113 + loading: record.pendingStatus,
  114 + onChange(checked: boolean) {
  115 + record.pendingStatus = true;
  116 + const newStatus = checked ? 1 : 0;
  117 + const { createMessage } = useMessage();
  118 + screenLinkPagePutApi({ id: record.id, status: newStatus })
  119 + .then(() => {
  120 + record.status = newStatus;
  121 + if (record.status == 1) {
  122 + createMessage.success(`已启用`);
  123 + } else {
  124 + createMessage.error('已禁用');
  125 + }
  126 + })
  127 + .catch(() => {
  128 + createMessage.error('已禁用');
  129 + })
  130 + .finally(() => {
  131 + record.pendingStatus = false;
  132 + });
  133 + },
  134 + });
  135 + },
  136 + },
  137 + {
  138 + title: '描述',
  139 + dataIndex: 'description',
  140 + width: 200,
  141 + },
  142 + {
  143 + title: '创建时间',
  144 + dataIndex: 'createTime',
  145 + width: 180,
  146 + },
  147 +];
  148 +
  149 +export const getData = ref(null);
  150 +
  151 +export const formSchema: FormSchema[] = [
  152 + {
  153 + field: 'name',
  154 + label: '场景联动名称',
  155 + colProps: { span: 24 },
  156 + required: true,
  157 + component: 'Input',
  158 + componentProps: {
  159 + maxLength: 36,
  160 + placeholder: '请输入场景联动名称',
  161 + },
  162 + },
  163 + {
  164 + required: true,
  165 + field: 'organizationId',
  166 + label: '所属组织',
  167 + colProps: { span: 24 },
  168 + component: 'ApiTreeSelect',
  169 + componentProps: ({ formModel, formActionType }) => {
  170 + return {
  171 + api: async () => {
  172 + const data = await screenLinkOrganizationGetApi();
  173 + copyTransFun(data as any as any[]);
  174 + return data;
  175 + },
  176 + onChange: async (v) => {
  177 + if (v == undefined) {
  178 + formModel.entityId = undefined;
  179 + const { updateSchema } = formActionType;
  180 + updateSchema({
  181 + field: 'entityId',
  182 + componentProps: {
  183 + options: undefined,
  184 + },
  185 + });
  186 + } else {
  187 + getData.value = v;
  188 + }
  189 + },
  190 + };
  191 + },
  192 + },
  193 + {
  194 + field: 'description',
  195 + label: '描述',
  196 + colProps: { span: 24 },
  197 + component: 'InputTextArea',
  198 + componentProps: {
  199 + maxLength: 255,
  200 + placeholder: '请输入描述',
  201 + },
  202 + },
  203 +];
  204 +
  205 +export const searchFormSchema: FormSchema[] = [
  206 + {
  207 + field: 'organizationId',
  208 + label: '所属组织',
  209 + colProps: { span: 6 },
  210 + component: 'ApiTreeSelect',
  211 + componentProps: {
  212 + api: async () => {
  213 + const data = await screenLinkOrganizationGetApi();
  214 + copyTransFun(data as any as any[]);
  215 + return data;
  216 + },
  217 + },
  218 + },
  219 + {
  220 + field: 'name',
  221 + label: '名称',
  222 + component: 'Input',
  223 + colProps: { span: 6 },
  224 + componentProps: {
  225 + maxLength: 36,
  226 + placeholder: '请输入名称',
  227 + },
  228 + },
  229 + {
  230 + field: 'status',
  231 + label: '设备状态',
  232 + component: 'Select',
  233 + componentProps: {
  234 + placeholder: '请选择状态',
  235 + options: [
  236 + { label: '已启用', value: '1' },
  237 + { label: '未启用', value: '0' },
  238 + ],
  239 + },
  240 + colProps: { span: 6 },
  241 + },
  242 +];
  243 +
  244 +export const useTriggerDrawerSchema: FormSchema[] = [
  245 + {
  246 + field: 'triggerType',
  247 + label: '',
  248 + component: 'Select',
  249 + componentProps: {
  250 + placeholder: '设备触发',
  251 + options: [
  252 + { label: '设备触发', value: 'DEVICE_TRIGGER' },
  253 + { label: '定时触发', value: 'SCHEDULE_TRIGGER' },
  254 + { label: '场景触发', value: 'SCENE_TRIGGER' },
  255 + { label: '手动触发', value: 'HAND_ACT' },
  256 + ],
  257 + },
  258 + colProps: { span: 12 },
  259 + },
  260 + {
  261 + field: 'entityId',
  262 + label: '',
  263 + component: 'Select',
  264 + componentProps: {
  265 + placeholder: '请选择设备',
  266 + },
  267 + ifShow: ({ values }) =>
  268 + !isTime(Reflect.get(values, 'triggerType')) &&
  269 + !isScene(Reflect.get(values, 'triggerType')) &&
  270 + !isHand(Reflect.get(values, 'triggerType')),
  271 + colProps: {
  272 + span: 12,
  273 + },
  274 + },
  275 + {
  276 + field: 'entityId1',
  277 + component: 'Input',
  278 + label: '',
  279 + componentProps: {
  280 + maxLength: 255,
  281 + placeholder: '请输入Cron表达式',
  282 + },
  283 + colProps: {
  284 + span: 12,
  285 + },
  286 + ifShow: ({ values }) => isTimeAll(Reflect.get(values, 'triggerType')),
  287 + },
  288 + {
  289 + field: 'type1',
  290 + label: '',
  291 + component: 'Select',
  292 + componentProps: {
  293 + placeholder: '属性触发',
  294 + options: [
  295 + { label: '属性触发', value: 'ATTRIBUTE' },
  296 + { label: '上下线触发', value: 'TIME_SERIES' },
  297 + ],
  298 + },
  299 + ifShow: ({ values }) =>
  300 + !isTime(Reflect.get(values, 'triggerType')) &&
  301 + !isScene(Reflect.get(values, 'triggerType')) &&
  302 + !isHand(Reflect.get(values, 'triggerType')),
  303 + colProps: { span: 12 },
  304 + },
  305 + {
  306 + field: 'key1',
  307 + label: '',
  308 + component: 'Select',
  309 + componentProps: {
  310 + placeholder: '请选择上下线',
  311 + options: [
  312 + { label: '上下线', value: '1' },
  313 + { label: '上线', value: '2' },
  314 + { label: '下线', value: '3' },
  315 + ],
  316 + },
  317 + colProps: { span: 12 },
  318 + ifShow: ({ values }) =>
  319 + isUpAndDown(Reflect.get(values, 'type1')) &&
  320 + !isTime(Reflect.get(values, 'triggerType')) &&
  321 + !isScene(Reflect.get(values, 'triggerType')) &&
  322 + !isHand(Reflect.get(values, 'triggerType')),
  323 + },
  324 + {
  325 + field: 'type2',
  326 + label: '',
  327 + component: 'Select',
  328 + componentProps: {
  329 + placeholder: '全部属性',
  330 + options: [
  331 + { label: '全部属性', value: 'STRING' },
  332 + { label: 'wendu', value: 'NUMERIC' },
  333 + ],
  334 + },
  335 + ifShow: ({ values }) =>
  336 + !isTime(Reflect.get(values, 'triggerType')) &&
  337 + !isScene(Reflect.get(values, 'triggerType')) &&
  338 + !isHand(Reflect.get(values, 'triggerType')) &&
  339 + !isUpAndDown(Reflect.get(values, 'type1')),
  340 + colProps: { span: 12 },
  341 + },
  342 + {
  343 + field: 'operation',
  344 + label: '',
  345 + component: 'Select',
  346 + componentProps: {
  347 + placeholder: '',
  348 + options: [
  349 + { label: '=', value: 'EQUAL' },
  350 + { label: '<', value: 'LESS' },
  351 + { label: '>', value: 'GREATER' },
  352 + { label: '<=', value: 'LESS_OR_EQUAL' },
  353 + { label: '>=', value: 'GREATER_OR_EQUAL' },
  354 + ],
  355 + },
  356 + ifShow: ({ values }) =>
  357 + isWenDu(Reflect.get(values, 'type2')) &&
  358 + !isUpAndDown(Reflect.get(values, 'type1')) &&
  359 + !isTime(Reflect.get(values, 'triggerType')) &&
  360 + !isScene(Reflect.get(values, 'triggerType')) &&
  361 + !isHand(Reflect.get(values, 'triggerType')),
  362 + colProps: { span: 12 },
  363 + },
  364 + {
  365 + field: 'value',
  366 + component: 'Input',
  367 + label: '',
  368 + componentProps: {
  369 + maxLength: 16,
  370 + placeholder: '请输入比较值',
  371 + },
  372 +
  373 + ifShow: ({ values }) =>
  374 + isWenDu(Reflect.get(values, 'type2')) &&
  375 + !isUpAndDown(Reflect.get(values, 'type1')) &&
  376 + !isTime(Reflect.get(values, 'triggerType')) &&
  377 + !isScene(Reflect.get(values, 'triggerType')) &&
  378 + !isHand(Reflect.get(values, 'triggerType')),
  379 + colProps: {
  380 + span: 12,
  381 + },
  382 + },
  383 +
  384 + {
  385 + field: 'entityId2',
  386 + label: '',
  387 + component: 'Select',
  388 + colProps: {
  389 + span: 12,
  390 + },
  391 + componentProps: {
  392 + placeholder: '请输入场景触发器',
  393 + options: [
  394 + { label: '场景触发器1', value: '1' },
  395 + { label: '场景触发器2', value: '2' },
  396 + { label: '场景触发器3', value: '3' },
  397 + ],
  398 + },
  399 + ifShow: ({ values }) => isScene(Reflect.get(values, 'triggerType')),
  400 + },
  401 +
  402 + {
  403 + field: 'no3',
  404 + label: '',
  405 + component: 'ApiSelect',
  406 + colProps: {
  407 + span: 12,
  408 + },
  409 + componentProps: {
  410 + placeholder: '暂不实现',
  411 + },
  412 + ifShow: ({ values }) => isHand(Reflect.get(values, 'triggerType')),
  413 + },
  414 +];
  415 +
  416 +export const useConditionDrawerSchema: FormSchema[] = [
  417 + {
  418 + field: 'triggerType',
  419 + label: '',
  420 + component: 'Select',
  421 + componentProps: {
  422 + placeholder: '设备状态',
  423 + options: [
  424 + { label: '设备触发', value: 'DEVICE_TRIGGER' },
  425 + { label: '时间范围', value: 'SCHEDULE_TRIGGER' },
  426 + ],
  427 + },
  428 + colProps: { span: 12 },
  429 + },
  430 + {
  431 + field: 'entityId',
  432 + label: '',
  433 + component: 'Select',
  434 + componentProps: {
  435 + placeholder: '请选择设备',
  436 + },
  437 + ifShow: ({ values }) => !isTimeAll(Reflect.get(values, 'triggerType')),
  438 + colProps: {
  439 + span: 12,
  440 + },
  441 + },
  442 + {
  443 + field: 'createTime',
  444 + component: 'DatePicker',
  445 + label: '',
  446 + componentProps: {
  447 + placeholder: '请选择起始时间',
  448 + },
  449 + colProps: {
  450 + span: 12,
  451 + },
  452 + ifShow: ({ values }) => isTimeAll(Reflect.get(values, 'triggerType')),
  453 + },
  454 + {
  455 + field: 'updateTime',
  456 + component: 'DatePicker',
  457 + label: '',
  458 + componentProps: {
  459 + placeholder: '请选择结束时间',
  460 + },
  461 + colProps: {
  462 + span: 12,
  463 + },
  464 + ifShow: ({ values }) => isTimeAll(Reflect.get(values, 'triggerType')),
  465 + },
  466 + {
  467 + field: 'type',
  468 + label: '',
  469 + component: 'Select',
  470 + componentProps: {
  471 + placeholder: '请选择或者输入属性',
  472 + options: [
  473 + { label: 'shidu', value: 'NUMERIC1' },
  474 + { label: 'wendu', value: 'NUMERIC2' },
  475 + ],
  476 + },
  477 + ifShow: ({ values }) => !isTimeAll(Reflect.get(values, 'triggerType')),
  478 + colProps: { span: 12 },
  479 + },
  480 + {
  481 + field: 'operation1',
  482 + label: '',
  483 + component: 'Select',
  484 + componentProps: {
  485 + placeholder: '',
  486 + options: [
  487 + { label: '=', value: 'EQUAL' },
  488 + { label: '<', value: 'LESS' },
  489 + { label: '>', value: 'GREATER' },
  490 + { label: '<=', value: 'LESS_OR_EQUAL' },
  491 + { label: '>=', value: 'GREATER_OR_EQUAL' },
  492 + ],
  493 + },
  494 + ifShow: ({ values }) =>
  495 + isConditionShiDu(Reflect.get(values, 'type')) &&
  496 + !isTimeAll(Reflect.get(values, 'triggerType')),
  497 + colProps: { span: 12 },
  498 + },
  499 + {
  500 + field: 'value1',
  501 + component: 'Input',
  502 + label: '',
  503 + componentProps: {
  504 + maxLength: 16,
  505 + placeholder: '请输入比较值',
  506 + },
  507 +
  508 + ifShow: ({ values }) =>
  509 + isConditionShiDu(Reflect.get(values, 'type')) &&
  510 + !isTimeAll(Reflect.get(values, 'triggerType')),
  511 + colProps: {
  512 + span: 12,
  513 + },
  514 + },
  515 +
  516 + {
  517 + field: 'operation2',
  518 + label: '',
  519 + component: 'Select',
  520 + componentProps: {
  521 + placeholder: '',
  522 + options: [
  523 + { label: '=', value: 'EQUAL' },
  524 + { label: '<', value: 'LESS' },
  525 + { label: '>', value: 'GREATER' },
  526 + { label: '<=', value: 'LESS_OR_EQUAL' },
  527 + { label: '>=', value: 'GREATER_OR_EQUAL' },
  528 + ],
  529 + },
  530 + ifShow: ({ values }) =>
  531 + isConditionWenDu(Reflect.get(values, 'type')) &&
  532 + !isTimeAll(Reflect.get(values, 'triggerType')),
  533 + colProps: { span: 12 },
  534 + },
  535 + {
  536 + field: 'value2',
  537 + component: 'Input',
  538 + label: '',
  539 + componentProps: {
  540 + maxLength: 16,
  541 + placeholder: '请输入比较值',
  542 + },
  543 + ifShow: ({ values }) =>
  544 + isConditionWenDu(Reflect.get(values, 'type')) &&
  545 + !isTimeAll(Reflect.get(values, 'triggerType')),
  546 + colProps: {
  547 + span: 12,
  548 + },
  549 + },
  550 +];
  551 +
  552 +export const useActionDrawerSchema: FormSchema[] = [
  553 + {
  554 + field: 'outTarget',
  555 + label: '',
  556 + component: 'Select',
  557 + required: true,
  558 + componentProps: {
  559 + placeholder: '请选择设备输出',
  560 + options: [
  561 + { label: '设备输出', value: 'DEVICE_OUT' },
  562 + { label: '消息通知', value: 'MSG_NOTIFY' },
  563 + { label: '场景联动', value: 'SCENE_TRIGGER' },
  564 + ],
  565 + },
  566 + colProps: { span: 12 },
  567 + },
  568 + {
  569 + field: 'deviceId',
  570 + label: '',
  571 + component: 'Select',
  572 + componentProps: {
  573 + placeholder: '请选择设备',
  574 + },
  575 + ifShow: ({ values }) =>
  576 + !isScene(Reflect.get(values, 'outTarget')) && !isMsg(Reflect.get(values, 'outTarget')),
  577 + colProps: {
  578 + span: 12,
  579 + },
  580 + },
  581 + {
  582 + field: 'doContext',
  583 + component: 'Input',
  584 + label: '',
  585 + componentProps: {
  586 + maxLength: 255,
  587 + placeholder: '请输入下发指定',
  588 + },
  589 + ifShow: ({ values }) =>
  590 + !isScene(Reflect.get(values, 'outTarget')) && !isMsg(Reflect.get(values, 'outTarget')),
  591 + colProps: {
  592 + span: 12,
  593 + },
  594 + },
  595 + {
  596 + field: 'wu2',
  597 + component: 'Input',
  598 + label: '',
  599 + componentProps: {
  600 + placeholder: '暂不实现',
  601 + },
  602 + colProps: {
  603 + span: 12,
  604 + },
  605 + ifShow: ({ values }) => isMsg(Reflect.get(values, 'outTarget')),
  606 + },
  607 + {
  608 + field: 'wu3',
  609 + label: '',
  610 + component: 'Input',
  611 + componentProps: {
  612 + placeholder: '无',
  613 + style: {
  614 + visibility: 'hidden',
  615 + },
  616 + },
  617 + colProps: { span: 12 },
  618 + ifShow: ({ values }) => isMsg(Reflect.get(values, 'outTarget')),
  619 + },
  620 + {
  621 + field: 'entityId',
  622 + label: '',
  623 + component: 'Select',
  624 + colProps: {
  625 + span: 12,
  626 + },
  627 + componentProps: {
  628 + placeholder: '请选择场景触发器',
  629 + options: [
  630 + { label: '场景触发器1', value: '1' },
  631 + { label: '场景触发器2', value: '2' },
  632 + { label: '场景触发器3', value: '3' },
  633 + { label: '场景触发器4', value: '4' },
  634 + ],
  635 + },
  636 + ifShow: ({ values }) => isScene(Reflect.get(values, 'outTarget')),
  637 + },
  638 + {
  639 + field: 'wu4',
  640 + label: '',
  641 + component: 'Input',
  642 + componentProps: {
  643 + placeholder: '无',
  644 + style: {
  645 + visibility: 'hidden',
  646 + },
  647 + },
  648 + colProps: { span: 12 },
  649 + ifShow: ({ values }) => isScene(Reflect.get(values, 'outTarget')),
  650 + },
  651 +];
  1 +export interface IAddTrigger {
  2 + triggerType: string;
  3 + entityId: string;
  4 + touchWay: string;
  5 + attributeChoose: string;
  6 + compare: string;
  7 + value: string;
  8 +}
  9 +
  10 +export interface IAddCondition {
  11 + triggerType: string;
  12 + entityId: string;
  13 + createTime: string;
  14 + updateTime: string;
  15 + compare: string;
  16 + value: string;
  17 +}
  18 +
  19 +export interface IAddAction {
  20 + outTarget: string;
  21 + deviceId: string;
  22 + command: string;
  23 + sceneLinkageId: string;
  24 +}
  1 +<template>
  2 + <div>
  3 + <BasicTable
  4 + @register="registerTable"
  5 + @selection-change="useSelectionChange"
  6 + :rowSelection="{ type: 'checkbox' }"
  7 + >
  8 + <template #toolbar>
  9 + <a-button type="primary" @click="handleAdd"> 新增场景联动 </a-button>
  10 + <a-button color="error" @click="handleDeleteOrBatchDelete(null)" :disabled="hasBatchDelete">
  11 + 批量删除
  12 + </a-button>
  13 + </template>
  14 + <template #action="{ record }">
  15 + <TableAction
  16 + :actions="[
  17 + {
  18 + label: '编辑',
  19 + icon: 'clarity:note-edit-line',
  20 + onClick: handleEdit.bind(null, record),
  21 + },
  22 + {
  23 + label: '删除',
  24 + icon: 'ant-design:delete-outlined',
  25 + color: 'error',
  26 + popConfirm: {
  27 + title: '是否确认删除',
  28 + confirm: handleDeleteOrBatchDelete.bind(null, record),
  29 + },
  30 + },
  31 + ]"
  32 + />
  33 + </template>
  34 + </BasicTable>
  35 + <SceneLinkAgeDrawer
  36 + @register="registerDrawer"
  37 + @success="handleSuccess"
  38 + ref="sceneLinkAgeDrawerRef"
  39 + />
  40 + </div>
  41 +</template>
  42 +<script lang="ts">
  43 + import { defineComponent, getCurrentInstance, ref } from 'vue';
  44 + import { BasicTable, useTable, TableAction } from '/@/components/Table';
  45 + import { useDrawer } from '/@/components/Drawer';
  46 + import SceneLinkAgeDrawer from './useDrawer.vue';
  47 + import { columns, searchFormSchema } from './config';
  48 + import { useMessage } from '/@/hooks/web/useMessage';
  49 + import { screenLinkPageGetApi, screenLinkPageDeleteApi } from '/@/api/ruleengine/ruleengineApi';
  50 + import { useBatchDelete } from '/@/hooks/web/useBatchDelete';
  51 +
  52 + export default defineComponent({
  53 + name: 'Index',
  54 + components: { BasicTable, SceneLinkAgeDrawer, TableAction },
  55 + emits: ['default', 'registerTable', 'registerDrawer', 'register'],
  56 + setup() {
  57 + const { proxy } = getCurrentInstance();
  58 + const sceneLinkAgeDrawerRef: any = ref(null);
  59 + const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions } = useBatchDelete(
  60 + screenLinkPageDeleteApi,
  61 + handleSuccess
  62 + );
  63 + let selectedRowKeys: Array<string> = [];
  64 + const [registerDrawer, { openDrawer }] = useDrawer();
  65 + const { createMessage } = useMessage();
  66 + const [registerTable, { reload, getSelectRowKeys }] = useTable({
  67 + title: '场景联动列表',
  68 + api: screenLinkPageGetApi,
  69 + columns,
  70 + formConfig: {
  71 + labelWidth: 120,
  72 + schemas: searchFormSchema,
  73 + },
  74 + useSearchForm: true,
  75 + showTableSetting: true,
  76 + bordered: true,
  77 + showIndexColumn: false,
  78 + actionColumn: {
  79 + width: 200,
  80 + title: '操作',
  81 + dataIndex: 'action',
  82 + slots: { customRender: 'action' },
  83 + fixed: 'right',
  84 + },
  85 + ...selectionOptions,
  86 + });
  87 +
  88 + function handleAdd() {
  89 + openDrawer(true, {
  90 + isUpdate: false,
  91 + });
  92 + try {
  93 + setTimeout(() => {
  94 + // proxy.$refs.sceneLinkAgeDrawerRef.defaultAddTrigger();
  95 + // proxy.$refs.sceneLinkAgeDrawerRef.defaultAddCondition();
  96 + proxy.$refs.sceneLinkAgeDrawerRef.defaultAddAction();
  97 + }, 50);
  98 + } catch (e) {
  99 + return e;
  100 + }
  101 + }
  102 +
  103 + const useSelectionChange = () => {
  104 + selectedRowKeys = getSelectRowKeys();
  105 + };
  106 +
  107 + async function handleToolbarDel() {
  108 + await screenLinkPageDeleteApi(selectedRowKeys);
  109 + createMessage.success('删除成功');
  110 + reload();
  111 + }
  112 +
  113 + function handleEdit(record: Recordable) {
  114 + openDrawer(true, {
  115 + record,
  116 + isUpdate: true,
  117 + });
  118 + }
  119 + async function handleDelete(record: Recordable) {
  120 + try {
  121 + let ids = [record.id];
  122 + await screenLinkPageDeleteApi(ids);
  123 + createMessage.success('删除成功');
  124 + reload();
  125 + } catch (e) {
  126 + return e;
  127 + }
  128 + }
  129 + function handleSuccess() {
  130 + reload();
  131 + }
  132 + return {
  133 + sceneLinkAgeDrawerRef,
  134 + useSelectionChange,
  135 + registerTable,
  136 + registerDrawer,
  137 + handleAdd,
  138 + handleToolbarDel,
  139 + handleEdit,
  140 + handleDelete,
  141 + handleSuccess,
  142 + hasBatchDelete,
  143 + handleDeleteOrBatchDelete,
  144 + };
  145 + },
  146 + });
  147 +</script>
  148 +
  149 +<style lang="less" scoped></style>
  1 +<template>
  2 + <BasicDrawer
  3 + v-bind="$attrs"
  4 + @register="registerDrawer"
  5 + showFooter
  6 + :title="getTitle"
  7 + width="1000px"
  8 + @ok="handleSubmit"
  9 + @close="handleClose"
  10 + >
  11 + <div>
  12 + <BasicForm @register="registerForm" />
  13 + <!-- 触发器 -->
  14 + <div style="border-radius: 4px">
  15 + <template
  16 + v-for="(item, index) in isUpdate == false ? addTriggerPushData : editTriggerPushData"
  17 + :key="index"
  18 + >
  19 + <span style="display: none">{{ item + index }}</span>
  20 + <span style="position: relative; top: 3.2vh; left: 0.5vw">触发器 {{ index + 1 }}</span>
  21 + <div style="display: block">
  22 + <AddTriggerForm
  23 + ref="refTriggerChild"
  24 + :editTriggerFather="isUpdate == false ? 1 : item"
  25 + :newFilterMapFather="isUpdate == false ? 1 : newFilterMap"
  26 + :deviceInfo="getDeviceInfo"
  27 + />
  28 + </div>
  29 + <div style="height: 3vh"></div>
  30 + </template>
  31 + <div
  32 + style="
  33 + display: flex;
  34 + width: 11vw;
  35 + height: 4vh;
  36 + flex-direction: row;
  37 + justify-content: space-between;
  38 + "
  39 + >
  40 + <div style="display: flex; width: 4vw; height: 4vh">
  41 + <Button type="primary" style="border-radius: 2px" class="mt-5" @click="addTrigger"
  42 + >新增触发器</Button
  43 + >
  44 + </div>
  45 + <div style="display: flex; width: 4vw; height: 4vh">
  46 + <Button
  47 + v-if="addTriggerPushData.length != 0 || editTriggerPushData.length != 0"
  48 + type="default"
  49 + style="border-radius: 2px; background-color: rgba(237, 111, 111, 1)"
  50 + class="mt-5"
  51 + @click="removeTrigger"
  52 + >
  53 + <span style="color: white">删除</span></Button
  54 + >
  55 + </div>
  56 + </div>
  57 + </div>
  58 + <div style="height: 5vh"></div>
  59 + <!-- 执行条件 -->
  60 + <div style="border-radius: 4px" class="condition-style">
  61 + <template
  62 + v-for="(item, index) in isUpdate == false ? addConditionPushData : editConditionPushData"
  63 + :key="index"
  64 + >
  65 + <span style="display: none">{{ item + index }}</span>
  66 + <span style="position: relative; top: 3.2vh; left: 0.5vw">执行条件 {{ index + 1 }}</span>
  67 +
  68 + <div>
  69 + <AddConditiForm
  70 + :editConditionFather="isUpdate == false ? 1 : item"
  71 + :newConditionMapFather="isUpdate == false ? 1 : newConditionFilterMap"
  72 + :deviceInfo1="getDeviceInfo1"
  73 + ref="refConditionChild"
  74 + />
  75 + </div>
  76 + <div style="height: 3vh"></div>
  77 + </template>
  78 + <div
  79 + style="
  80 + display: flex;
  81 + width: 11vw;
  82 + height: 4vh;
  83 + flex-direction: row;
  84 + justify-content: space-between;
  85 + "
  86 + >
  87 + <div style="display: flex; width: 4vw; height: 4vh">
  88 + <Button type="primary" style="border-radius: 2px" class="mt-5" @click="addCondition"
  89 + >新增执行条件</Button
  90 + >
  91 + </div>
  92 + <div style="display: flex; width: 4vw; height: 4vh">
  93 + <Button
  94 + v-if="addConditionPushData.length != 0 || editConditionPushData.length != 0"
  95 + style="border-radius: 2px; background-color: rgba(237, 111, 111, 1)"
  96 + type="default"
  97 + class="mt-5"
  98 + @click="removeCondition"
  99 + >
  100 + <span style="color: white">删除</span></Button
  101 + >
  102 + </div>
  103 + </div>
  104 + </div>
  105 + <!-- 执行动作 -->
  106 + <div style="height: 5vh"></div>
  107 + <div style="border-radius: 4px">
  108 + <template
  109 + v-for="(item, index) in isUpdate == false ? addActionPushData : editActionPushData"
  110 + :key="index"
  111 + >
  112 + <span style="display: none">{{ item + index }}</span>
  113 + <span style="position: relative; top: 4.2vh; left: 0.65vw">执行动作 {{ index + 1 }}</span>
  114 +
  115 + <div>
  116 + <AddActionForm
  117 + :editActionFather="isUpdate == false ? 1 : item"
  118 + :newActionMapFather="isUpdate == false ? 1 : newActionFilterMap"
  119 + :deviceInfo2="getDeviceInfo2"
  120 + ref="refActionChild"
  121 + />
  122 + </div>
  123 + <div style="height: 3vh"></div>
  124 + </template>
  125 + <div
  126 + style="
  127 + display: flex;
  128 + width: 11vw;
  129 + height: 4vh;
  130 + flex-direction: row;
  131 + justify-content: space-between;
  132 + "
  133 + >
  134 + <div style="display: flex; width: 4vw; height: 4vh">
  135 + <Button type="primary" style="border-radius: 2px" class="mt-5" @click="addAction"
  136 + >新增执行动作</Button
  137 + >
  138 + </div>
  139 + <div style="display: flex; width: 4vw; height: 4vh">
  140 + <Button
  141 + v-if="addActionPushData.length !== 0 || editActionPushData.length !== 0"
  142 + style="border-radius: 2px; background-color: rgba(237, 111, 111, 1)"
  143 + type="default"
  144 + class="mt-5"
  145 + @click="removeAction"
  146 + >
  147 + <span style="color: white">删除</span></Button
  148 + >
  149 + </div>
  150 + </div>
  151 + <div style="height: 5vh"></div>
  152 + </div>
  153 + </div>
  154 + </BasicDrawer>
  155 +</template>
  156 +<script lang="ts">
  157 + import { defineComponent, ref, computed, unref, reactive, getCurrentInstance, watch } from 'vue';
  158 + import { BasicForm, useForm } from '/@/components/Form';
  159 + import { formSchema, getData } from './config';
  160 + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  161 + import {
  162 + screenLinkPageAddApi,
  163 + screenLinkPageUpdateApi,
  164 + screenLinkPageByDeptIdGetDevice,
  165 + } from '/@/api/ruleengine/ruleengineApi';
  166 + import { useMessage } from '/@/hooks/web/useMessage';
  167 + import AddTriggerForm from './addForm/trigger.vue';
  168 + import AddConditiForm from './addForm/condition.vue';
  169 + import AddActionForm from './addForm/doaction.vue';
  170 + import { IAddTrigger } from './index';
  171 + import { Button } from '/@/components/Button';
  172 +
  173 + export default defineComponent({
  174 + name: 'ConfigDrawer',
  175 + components: {
  176 + BasicDrawer,
  177 + BasicForm,
  178 + AddTriggerForm,
  179 + AddConditiForm,
  180 + AddActionForm,
  181 + Button,
  182 + },
  183 + emits: ['success', 'register', 'registerForm'],
  184 + setup(_, { emit }) {
  185 + const { proxy } = getCurrentInstance();
  186 + const lastEditRefTriggerChildDataArray = ref<[]>([]);
  187 + const lastRefTriggerChildDataArray = ref<[]>([]);
  188 + const lastRefConditionChildDataArray = ref<[]>([]);
  189 + const lastRefActionChildDataArray = ref<[]>([]);
  190 + let refTriggerChildData: any = reactive({});
  191 + let refConditionChildData: any = reactive({});
  192 + let refActionChildData: any = reactive({});
  193 + const addTriggerData = reactive<IAddTrigger>({
  194 + triggerType: '',
  195 + entityId: '',
  196 + touchWay: '',
  197 + attributeChoose: '',
  198 + compare: '',
  199 + value: '',
  200 + });
  201 + const addTriggerPushData = ref<[]>([]);
  202 + const addConditionPushData = ref<[]>([]);
  203 + const addActionPushData = ref<[]>([]);
  204 + //edit data
  205 + const editTriggerPushData = ref<[]>([]);
  206 + const editConditionPushData = ref<[]>([]);
  207 + const editActionPushData = ref<[]>([]);
  208 + const getChildData = ref(null);
  209 + const refTriggerChild = ref(null);
  210 + const refConditionChild = ref(null);
  211 + const refActionChild = ref(null);
  212 + const getConditionChildData = ref(null);
  213 + const { createMessage } = useMessage();
  214 + const isUpdate = ref(true);
  215 + let getAllFormData: any = reactive({});
  216 + let getValuesFormData: any = reactive({});
  217 + const getId = ref('');
  218 + const getTenantId = ref('');
  219 + const getDeviceInfo = ref(null);
  220 + const getDeviceInfo1 = ref(null);
  221 + const getDeviceInfo2 = ref(null);
  222 + const newFilterMap = ref<[]>([]);
  223 + const newConditionFilterMap = ref<[]>([]);
  224 + const newActionFilterMap = ref<[]>([]);
  225 + let filterNewConditionArr = [];
  226 + const pushEditArray = ref<any>([{}]);
  227 + const pushEditConditionArray = ref<any>([{}]);
  228 + const pushEditActionArray = ref<any>([{}]);
  229 + let filterArrayTrigger = [];
  230 + const filterArrayCondition = ref<[]>([]);
  231 + const filterArrayAction = ref<[]>([]);
  232 + let filterNewTriggerArr = [];
  233 + let triggersObj = {
  234 + triggers: [],
  235 + };
  236 + let conditionsObj = {
  237 + doConditions: [],
  238 + };
  239 + let actionsObj = {
  240 + doActions: [],
  241 + };
  242 + let optionsItemArray = ref<[]>([]);
  243 + const isNoChange = ref(false);
  244 + let kongTriggerObj = {};
  245 + let kongConditionObj = {};
  246 + let kongActionObj = {};
  247 +
  248 + const [registerForm, { resetFields, setFieldsValue, validateFields }] = useForm({
  249 + labelWidth: 120,
  250 + schemas: formSchema,
  251 + showActionButtonGroup: false,
  252 + });
  253 + const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
  254 + await resetFields();
  255 + setDrawerProps({ confirmLoading: false });
  256 + isUpdate.value = !!data?.isUpdate;
  257 + if (!unref(isUpdate)) {
  258 + try {
  259 + refTriggerChildData = {};
  260 + refConditionChildData = {};
  261 + refActionChildData = {};
  262 + getAllFormData = {};
  263 + triggersObj = {
  264 + triggers: [],
  265 + };
  266 + conditionsObj = {
  267 + doConditions: [],
  268 + };
  269 + actionsObj = {
  270 + doActions: [],
  271 + };
  272 + filterNewTriggerArr.length = 0;
  273 + filterNewConditionArr.length = 0;
  274 + lastRefTriggerChildDataArray.value.length = 0;
  275 + lastRefConditionChildDataArray.value.length = 0;
  276 + lastRefActionChildDataArray.value.length = 0;
  277 + editTriggerPushData.value.length = 0;
  278 + editConditionPushData.value.length = 0;
  279 + editActionPushData.value.length = 0;
  280 + addTriggerPushData.value.length = 0;
  281 + addConditionPushData.value.length = 0;
  282 + addActionPushData.value.length = 0;
  283 + handleClose();
  284 + optionsItemArray.value.length = 0;
  285 + try {
  286 + setTimeout(() => {
  287 + proxy.$refs.refTriggerChild.resetFieldsValueFunc();
  288 + proxy.$refs.refTriggerChild.clearSelectDevice();
  289 + proxy.$refs.refConditionChild.resetFieldsValueFunc();
  290 + proxy.$refs.refConditionChild.clearSelectDevice();
  291 + proxy.$refs.refActionChild.resetFieldsValueFunc();
  292 + proxy.$refs.refActionChild.clearSelectDevice();
  293 + clearActionsAllDevice();
  294 + resetActionsAllArrayFunc();
  295 + }, 10);
  296 + } catch (e) {
  297 + return e;
  298 + }
  299 + } catch (e) {
  300 + return e;
  301 + }
  302 + } else {
  303 + try {
  304 + emit('success');
  305 + kongTriggerObj = {};
  306 + kongConditionObj = {};
  307 + kongActionObj = {};
  308 + pushEditArray.value = [];
  309 + pushEditArray.value.length = 0;
  310 + pushEditConditionArray.value.length = 0;
  311 + pushEditConditionArray.value = [];
  312 + pushEditActionArray.value = [];
  313 + pushEditActionArray.value.length = 0;
  314 + newFilterMap.value = [];
  315 + newConditionFilterMap.value = [];
  316 + newActionFilterMap.value = [];
  317 + clearAllArrayFunc();
  318 + editTriggerPushData.value = [];
  319 + editTriggerPushData.value.length = 0;
  320 + editConditionPushData.value = [];
  321 + editConditionPushData.value.length = 0;
  322 + editActionPushData.value = [];
  323 + editActionPushData.value.length = 0;
  324 + lastEditRefTriggerChildDataArray.value = [];
  325 + getId.value = data.record.id;
  326 + getTenantId.value = data.record.tenantId;
  327 + await setFieldsValue({
  328 + ...data.record,
  329 + });
  330 + editTriggerPushData.value = data.record.triggers;
  331 + isNoChange.value = true;
  332 + editConditionPushData.value = data.record.doConditions;
  333 + editActionPushData.value = data.record.doActions;
  334 + const options = await screenLinkPageByDeptIdGetDevice({
  335 + organizationId: data.record.organizationId,
  336 + });
  337 + data.record.triggers.forEach((f1) => {
  338 + options.items?.forEach((f2) => {
  339 + if (f2.tbDeviceId == f1.entityId) {
  340 + newFilterMap.value.push({
  341 + value: f2.tbDeviceId,
  342 + label: f2.name,
  343 + });
  344 + }
  345 + });
  346 + });
  347 + data.record.doConditions.forEach((f1) => {
  348 + options.items?.forEach((f2) => {
  349 + if (f2.tbDeviceId == f1.entityId) {
  350 + newConditionFilterMap.value.push({
  351 + value: f2.tbDeviceId,
  352 + label: f2.name,
  353 + });
  354 + }
  355 + });
  356 + });
  357 + data.record.doActions.forEach((f1) => {
  358 + options.items?.forEach((f2) => {
  359 + if (f2.tbDeviceId == f1.deviceId) {
  360 + newActionFilterMap.value.push({
  361 + value: f2.tbDeviceId,
  362 + label: f2.name,
  363 + });
  364 + }
  365 + });
  366 + });
  367 + } catch (e) {
  368 + return e;
  369 + }
  370 + }
  371 + });
  372 + const getTitle = computed(() => (!unref(isUpdate) ? '新增场景联动' : '编辑场景联动'));
  373 + const handleClose = () => {
  374 + pushEditArray.value.length = 0;
  375 + pushEditConditionArray.value.length = 0;
  376 + pushEditActionArray.value.length = 0;
  377 + lastRefTriggerChildDataArray.value.length = 0;
  378 + lastRefTriggerChildDataArray.value = [];
  379 + lastRefConditionChildDataArray.value.length = 0;
  380 + lastRefActionChildDataArray.value.length = 0;
  381 + lastRefActionChildDataArray.value = [];
  382 + filterArrayTrigger.length = 0;
  383 + filterArrayCondition.value.length = 0;
  384 + filterArrayAction.value.length = 0;
  385 + };
  386 +
  387 + const clearAllArrayFunc = () => {
  388 + unref(addTriggerPushData).length = 0;
  389 + unref(addConditionPushData).length = 0;
  390 + unref(addActionPushData).length = 0;
  391 + lastRefTriggerChildDataArray.value.length = 0;
  392 + lastRefConditionChildDataArray.value.length = 0;
  393 + lastRefActionChildDataArray.value.length = 0;
  394 + lastEditRefTriggerChildDataArray.value.length = 0;
  395 + };
  396 + const resetActionsAllArrayFunc = () => {
  397 + try {
  398 + proxy.$refs.refActionChild.resetFieldsValueFunc();
  399 + } catch (e) {
  400 + return e;
  401 + }
  402 + };
  403 + const clearActionsAllDevice = () => {
  404 + try {
  405 + proxy.$refs.refActionChild.clearSelectDevice();
  406 + } catch (e) {
  407 + return e;
  408 + }
  409 + };
  410 + watch(getData, async (newV) => {
  411 + const options = await screenLinkPageByDeptIdGetDevice({ organizationId: newV });
  412 + options.items.forEach((v) => {
  413 + return (v.value = v.tbDeviceId), (v.label = v.name);
  414 + });
  415 + optionsItemArray.value = options.items;
  416 + updateDeviceIdFunc(optionsItemArray.value);
  417 + try {
  418 + proxy.$refs.refActionChild.updateFieldDeviceId(optionsItemArray.value);
  419 + } catch (e) {
  420 + return e;
  421 + }
  422 + });
  423 +
  424 + const updateDeviceIdFunc = (v) => {
  425 + try {
  426 + proxy.$refs.refTriggerChild.updateFieldDeviceId(v);
  427 + proxy.$refs.refConditionChild.updateFieldDeviceId(v);
  428 + proxy.$refs.refActionChild.updateFieldDeviceId(v);
  429 + } catch (e) {
  430 + return e;
  431 + }
  432 + };
  433 +
  434 + //获取触发器方法
  435 + const refTriggerChildDataFunc = () => {
  436 + try {
  437 + refTriggerChildData = proxy.$refs.refTriggerChild.getFieldsValueFunc();
  438 + } catch (e) {
  439 + return e;
  440 + }
  441 + };
  442 + //获取执行条件方法
  443 + const refConditionChildDataFunc = () => {
  444 + try {
  445 + refConditionChildData = proxy.$refs.refConditionChild.getFieldsValueFunc();
  446 + } catch (e) {
  447 + return e;
  448 + }
  449 + };
  450 + //获取执行动作方法
  451 + const refActionChildDataFunc = () => {
  452 + try {
  453 + refActionChildData = proxy.$refs.refActionChild.getFieldsValueFunc();
  454 + } catch (e) {
  455 + return e;
  456 + }
  457 + };
  458 +
  459 + const getDefaultValue = () => {
  460 + if (!unref(isUpdate)) {
  461 + refTriggerChildDataFunc();
  462 + refConditionChildDataFunc();
  463 + refActionChildDataFunc();
  464 + let newTriggerArray = addTriggerPushData.value.concat(refTriggerChildData);
  465 + let newConditionArray = addConditionPushData.value.concat(refConditionChildData);
  466 + let newActionArray = addActionPushData.value.concat(refActionChildData);
  467 + newTriggerArray = newTriggerArray.map((m) => {
  468 + return {
  469 + triggerType: m?.triggerType,
  470 + entityId: m?.entityId || m?.entityId1 || m?.entityId2,
  471 + triggerCondition: {
  472 + condition: [
  473 + {
  474 + key: {
  475 + key: m.key1 == null ? 'CO2' : m.key1,
  476 + type: m.type1 == null ? 'TIME_SERIES' : m.type1,
  477 + },
  478 + valueType: m.type2 == null ? 'NUMERIC' : m.type2,
  479 + value: {},
  480 + predicate: {
  481 + type: m.type2 == null ? 'NUMERIC' : m.type2,
  482 + value: {
  483 + defaultValue: Number(m.value) == null ? 0 : Number(m.value),
  484 + },
  485 + operation: m.operation == null ? 'GREATER_OR_EQUAL' : m.operation,
  486 + },
  487 + },
  488 + ],
  489 + spec: {
  490 + type: 'SIMPLE',
  491 + },
  492 + },
  493 + };
  494 + });
  495 + newConditionArray = newConditionArray.map((m) => {
  496 + return {
  497 + triggerType: m?.triggerType,
  498 + entityId: m?.entityId,
  499 + triggerCondition: {
  500 + condition: [
  501 + {
  502 + key: {
  503 + type: 'TIME_SERIES',
  504 + key: 'CO2',
  505 + },
  506 + valueType:
  507 + m.type == 'NUMERIC1'
  508 + ? 'NUMERIC'
  509 + : m.type == 'NUMERIC2'
  510 + ? 'NUMERIC'
  511 + : 'NUMERIC',
  512 + value: {},
  513 + predicate: {
  514 + type:
  515 + m.type == 'NUMERIC1'
  516 + ? 'NUMERIC'
  517 + : m.type == 'NUMERIC2'
  518 + ? 'NUMERIC'
  519 + : 'NUMERIC',
  520 + value: {
  521 + defaultValue:
  522 + Number(m.value1) == null
  523 + ? 0
  524 + : Number(m.value1) || Number(m.value2) == null
  525 + ? 0
  526 + : Number(m.value2),
  527 + },
  528 + operation: m.operation1 || m.operatio2,
  529 + },
  530 + },
  531 + ],
  532 + spec: {
  533 + type: 'SIMPLE',
  534 + },
  535 + },
  536 + };
  537 + });
  538 + newTriggerArray.shift();
  539 + newConditionArray.shift();
  540 + newActionArray.shift();
  541 + delete getAllFormData.id;
  542 + delete getAllFormData.getTenantId;
  543 + triggersObj = {
  544 + triggers: newTriggerArray,
  545 + };
  546 + conditionsObj = {
  547 + doConditions: newConditionArray,
  548 + };
  549 + actionsObj = {
  550 + doActions: newActionArray,
  551 + };
  552 + Object.assign(getAllFormData, triggersObj, conditionsObj, actionsObj);
  553 + } else {
  554 + editTriggerPushData.value.forEach((f) => {
  555 + kongTriggerObj = f;
  556 + pushEditArray.value.push(kongTriggerObj);
  557 + });
  558 + editConditionPushData.value.forEach((f) => {
  559 + kongConditionObj = f;
  560 + pushEditConditionArray.value.push(kongConditionObj);
  561 + });
  562 + editActionPushData.value.forEach((f) => {
  563 + kongActionObj = f;
  564 + pushEditActionArray.value.push(kongActionObj);
  565 + });
  566 + refTriggerChildDataFunc();
  567 + let newTriggerArray = pushEditArray.value.concat(refTriggerChildData);
  568 + newTriggerArray = newTriggerArray.filter((f) => Object.keys(f).length !== 0);
  569 + newTriggerArray.shift();
  570 + triggersObj = {
  571 + triggers: isNoChange.value ? editTriggerPushData.value : newTriggerArray,
  572 + };
  573 + refConditionChildDataFunc();
  574 + let newConditionArray = pushEditConditionArray.value.concat(refConditionChildData);
  575 + newConditionArray = newConditionArray.filter((f) => Object.keys(f).length !== 0);
  576 + newConditionArray.shift();
  577 + conditionsObj = {
  578 + doConditions: newConditionArray,
  579 + };
  580 + refActionChildDataFunc();
  581 + let newActionArray = pushEditActionArray.value.concat(refActionChildData);
  582 + newActionArray = newActionArray.filter((f) => Object.keys(f).length !== 0);
  583 + newActionArray.shift();
  584 + actionsObj = {
  585 + doActions: newActionArray,
  586 + };
  587 + Object.assign(getAllFormData, triggersObj, conditionsObj, actionsObj);
  588 + }
  589 + };
  590 +
  591 + const handleSubmit = async () => {
  592 + if (!unref(isUpdate)) {
  593 + getDefaultValue();
  594 + getValuesFormData = await validateFields();
  595 + if (!getValuesFormData) return;
  596 + let isKongNum = 0;
  597 + getAllFormData.doActions.forEach((f) => {
  598 + isKongNum = Object.keys(f).length;
  599 + });
  600 +
  601 + if (getAllFormData.doActions.length == 1 && isKongNum == 0)
  602 + return createMessage.error('请填写执行动作');
  603 + Object.assign(getAllFormData, getValuesFormData);
  604 + await screenLinkPageAddApi(getAllFormData);
  605 + createMessage.success('场景联动新增成功');
  606 + closeDrawer();
  607 + emit('success');
  608 + } else {
  609 + getDefaultValue();
  610 + getValuesFormData = await validateFields();
  611 + Object.assign(getAllFormData, getValuesFormData);
  612 + getAllFormData.id = getId.value;
  613 + getAllFormData.tenantId = getTenantId.value;
  614 + refTriggerChildData = {};
  615 + pushEditArray.value.length = 0;
  616 + pushEditConditionArray.value.length = 0;
  617 + pushEditActionArray.value.length = 0;
  618 + await screenLinkPageUpdateApi(getAllFormData);
  619 + createMessage.success('场景联动编辑成功');
  620 + closeDrawer();
  621 + emit('success');
  622 + }
  623 + };
  624 + //新增触发器
  625 + const addTrigger = () => {
  626 + if (!unref(isUpdate)) {
  627 + refTriggerChildDataFunc();
  628 + unref(addTriggerPushData).push(refTriggerChildData as never);
  629 + addTriggerPushData.value = addTriggerPushData.value.map((m) => {
  630 + return {
  631 + triggerType: m?.triggerType,
  632 + entityId: m?.entityId || m?.entityId1 || m?.entityId2,
  633 + triggerCondition: {
  634 + condition: [
  635 + {
  636 + key: {
  637 + key: m.key1 == null ? 'CO2' : m.key1,
  638 + type: m.type1 == null ? 'TIME_SERIES' : m.type1,
  639 + },
  640 + valueType: m.type2 == null ? 'NUMERIC' : m.type2,
  641 + value: {},
  642 + predicate: {
  643 + type: m.type2 == null ? 'NUMERIC' : m.type2,
  644 + value: {
  645 + defaultValue: Number(m.value) == null ? 0 : Number(m.value),
  646 + },
  647 + operation: m.operation == null ? 'GREATER_OR_EQUAL' : m.operation,
  648 + },
  649 + },
  650 + ],
  651 + spec: {
  652 + type: 'SIMPLE',
  653 + },
  654 + },
  655 + };
  656 + });
  657 + try {
  658 + setTimeout(() => {
  659 + proxy.$refs.refTriggerChild.updateFieldDeviceId(optionsItemArray.value);
  660 + }, 50);
  661 + } catch (e) {
  662 + return e;
  663 + }
  664 + } else {
  665 + isNoChange.value = false;
  666 + unref(editTriggerPushData).push(refTriggerChildData as never);
  667 + refTriggerChildDataFunc();
  668 + pushEditArray.value.push(refTriggerChildData);
  669 + pushEditArray.value = pushEditArray.value.map((m) => {
  670 + return {
  671 + triggerType: m?.triggerType,
  672 + entityId: m?.entityId || m?.entityId1 || m?.entityId2,
  673 + triggerCondition: {
  674 + condition: [
  675 + {
  676 + key: {
  677 + key: m.key1 == null ? 'CO2' : m.key1,
  678 + type: m.type1 == null ? 'TIME_SERIES' : m.type1,
  679 + },
  680 + valueType: m.type2 == null ? 'NUMERIC' : m.type2,
  681 + value: {},
  682 + predicate: {
  683 + type: m.type2 == null ? 'NUMERIC' : m.type2,
  684 + value: {
  685 + defaultValue: Number(m.value) == null ? 0 : Number(m.value),
  686 + },
  687 + operation: m.operation == null ? 'GREATER_OR_EQUAL' : m.operation,
  688 + },
  689 + },
  690 + ],
  691 + spec: {
  692 + type: 'SIMPLE',
  693 + },
  694 + },
  695 + };
  696 + });
  697 + try {
  698 + setTimeout(() => {
  699 + proxy.$refs.refTriggerChild.updateFieldDeviceId(optionsItemArray.value);
  700 + }, 50);
  701 + } catch (e) {
  702 + return e;
  703 + }
  704 + refTriggerChildData = {};
  705 + }
  706 + };
  707 + const removeTrigger = () => {
  708 + if (!unref(isUpdate)) {
  709 + try {
  710 + unref(addTriggerPushData).pop();
  711 + } catch (e) {
  712 + return e;
  713 + }
  714 + } else {
  715 + try {
  716 + unref(editTriggerPushData).pop();
  717 + } catch (e) {
  718 + return e;
  719 + }
  720 + }
  721 + };
  722 +
  723 + //新增执行条件
  724 + const addCondition = () => {
  725 + if (!unref(isUpdate)) {
  726 + refConditionChildDataFunc();
  727 + unref(addConditionPushData).push(refConditionChildData as never);
  728 + addConditionPushData.value = addConditionPushData.value.map((m) => {
  729 + return {
  730 + triggerType: m?.triggerType,
  731 + entityId: m?.entityId,
  732 + triggerCondition: {
  733 + condition: [
  734 + {
  735 + key: {
  736 + type: 'TIME_SERIES',
  737 + key: 'CO2',
  738 + },
  739 + valueType:
  740 + m.type == 'NUMERIC1'
  741 + ? 'NUMERIC'
  742 + : m.type == 'NUMERIC2'
  743 + ? 'NUMERIC'
  744 + : 'NUMERIC',
  745 + value: {},
  746 + predicate: {
  747 + type:
  748 + m.type == 'NUMERIC1'
  749 + ? 'NUMERIC'
  750 + : m.type == 'NUMERIC2'
  751 + ? 'NUMERIC'
  752 + : 'NUMERIC',
  753 + value: {
  754 + defaultValue:
  755 + Number(m.value1) == null
  756 + ? 0
  757 + : Number(m.value1) || Number(m.value2) == null
  758 + ? 0
  759 + : Number(m.value2),
  760 + },
  761 + operation: m.operation1 || m.operatio2,
  762 + },
  763 + },
  764 + ],
  765 + spec: {
  766 + type: 'SIMPLE',
  767 + },
  768 + },
  769 + };
  770 + });
  771 + try {
  772 + setTimeout(() => {
  773 + proxy.$refs.refConditionChild.updateFieldDeviceId(optionsItemArray.value);
  774 + }, 50);
  775 + } catch (e) {
  776 + return e;
  777 + }
  778 + } else {
  779 + isNoChange.value = false;
  780 + unref(editConditionPushData).push(refConditionChildData as never);
  781 + refConditionChildDataFunc();
  782 + pushEditConditionArray.value.push(refConditionChildData);
  783 + pushEditConditionArray.value = pushEditConditionArray.value.map((m) => {
  784 + return {
  785 + triggerType: m?.triggerType,
  786 + entityId: m?.entityId,
  787 + triggerCondition: {
  788 + condition: [
  789 + {
  790 + key: {
  791 + type: 'TIME_SERIES',
  792 + key: 'CO2',
  793 + },
  794 + valueType:
  795 + m.type == 'NUMERIC1'
  796 + ? 'NUMERIC'
  797 + : m.type == 'NUMERIC2'
  798 + ? 'NUMERIC'
  799 + : 'NUMERIC',
  800 + value: {},
  801 + predicate: {
  802 + type:
  803 + m.type == 'NUMERIC1'
  804 + ? 'NUMERIC'
  805 + : m.type == 'NUMERIC2'
  806 + ? 'NUMERIC'
  807 + : 'NUMERIC',
  808 + value: {
  809 + defaultValue:
  810 + Number(m.value1) == null
  811 + ? 0
  812 + : Number(m.value1) || Number(m.value2) == null
  813 + ? 0
  814 + : Number(m.value2),
  815 + },
  816 + operation: m.operation1 || m.operatio2,
  817 + },
  818 + },
  819 + ],
  820 + spec: {
  821 + type: 'SIMPLE',
  822 + },
  823 + },
  824 + };
  825 + });
  826 + try {
  827 + setTimeout(() => {
  828 + proxy.$refs.refConditionChild.updateFieldDeviceId(optionsItemArray.value);
  829 + }, 50);
  830 + } catch (e) {
  831 + return e;
  832 + }
  833 + refConditionChildData = {};
  834 + }
  835 + };
  836 + const removeCondition = () => {
  837 + if (!unref(isUpdate)) {
  838 + try {
  839 + unref(addConditionPushData).pop();
  840 + } catch (e) {
  841 + return e;
  842 + }
  843 + } else {
  844 + try {
  845 + unref(editConditionPushData).pop();
  846 + } catch (e) {
  847 + return e;
  848 + }
  849 + }
  850 + };
  851 +
  852 + //默认新增执行动作
  853 + const defaultAddAction = () => {
  854 + if (unref(addActionPushData).length == 0) {
  855 + addAction();
  856 + }
  857 + };
  858 + //新增执行动作
  859 + const addAction = () => {
  860 + if (!unref(isUpdate)) {
  861 + refActionChildDataFunc();
  862 + unref(addActionPushData).push(refActionChildData as never);
  863 + try {
  864 + setTimeout(() => {
  865 + proxy.$refs.refActionChild.updateFieldDeviceId(optionsItemArray.value);
  866 + }, 50);
  867 + } catch (e) {
  868 + return e;
  869 + }
  870 + } else {
  871 + isNoChange.value = false;
  872 + unref(editActionPushData).push(refActionChildData as never);
  873 + refActionChildDataFunc();
  874 + pushEditActionArray.value.push(refActionChildData);
  875 + try {
  876 + setTimeout(() => {
  877 + proxy.$refs.refActionChild.updateFieldDeviceId(optionsItemArray.value);
  878 + }, 50);
  879 + } catch (e) {
  880 + return e;
  881 + }
  882 + refActionChildData = {};
  883 + }
  884 + };
  885 + const removeAction = () => {
  886 + if (!unref(isUpdate)) {
  887 + try {
  888 + unref(addActionPushData).pop();
  889 + } catch (e) {
  890 + return e;
  891 + }
  892 + } else {
  893 + try {
  894 + unref(editActionPushData).pop();
  895 + } catch (e) {
  896 + return e;
  897 + }
  898 + }
  899 + };
  900 +
  901 + return {
  902 + updateDeviceIdFunc,
  903 + handleClose,
  904 + newFilterMap,
  905 + newConditionFilterMap,
  906 + newActionFilterMap,
  907 + editTriggerPushData,
  908 + editConditionPushData,
  909 + editActionPushData,
  910 + isUpdate,
  911 + clearActionsAllDevice,
  912 + getDeviceInfo,
  913 + getDeviceInfo1,
  914 + getDeviceInfo2,
  915 + resetActionsAllArrayFunc,
  916 + addActionPushData,
  917 + defaultAddAction,
  918 + refActionChild,
  919 + addAction,
  920 + removeAction,
  921 + addConditionPushData,
  922 + refConditionChild,
  923 + addCondition,
  924 + removeCondition,
  925 + clearAllArrayFunc,
  926 + removeTrigger,
  927 + addTriggerPushData,
  928 + addTriggerData,
  929 + addTrigger,
  930 + getConditionChildData,
  931 + refTriggerChild,
  932 + getChildData,
  933 + getAllFormData,
  934 + registerDrawer,
  935 + registerForm,
  936 + getTitle,
  937 + handleSubmit,
  938 + };
  939 + },
  940 + });
  941 +</script>
  942 +
  943 +<style lang="less" scoped>
  944 + .condition-style {
  945 + :deep .ant-calendar-picker {
  946 + width: 24.9vw !important;
  947 + }
  948 + }
  949 +</style>
  1 +import { BasicColumn, FormSchema } from '/@/components/Table';
  2 +import { h } from 'vue';
  3 +import { Tag, Switch } from 'ant-design-vue';
  4 +import { useMessage } from '/@/hooks/web/useMessage';
  5 +import { updateTransformScriptStatusApi } from '/@/api/device/TransformScriptApi';
  6 +export const columns: BasicColumn[] = [
  7 + {
  8 + title: '名称',
  9 + dataIndex: 'name',
  10 + width: 100,
  11 + },
  12 + {
  13 + title: '用途',
  14 + dataIndex: 'type',
  15 + width: 200,
  16 + customRender: () => h(Tag, { color: 'blue' }, () => '消息格式化'),
  17 + },
  18 + {
  19 + title: '状态',
  20 + dataIndex: 'status',
  21 + width: 120,
  22 + customRender: ({ record }) => {
  23 + if (!Reflect.has(record, 'pendingStatus')) {
  24 + record.pendingStatus = false;
  25 + }
  26 + return h(Switch, {
  27 + checked: record.status === 1,
  28 + checkedChildren: '已启用',
  29 + unCheckedChildren: '已禁用',
  30 + loading: record.pendingStatus,
  31 + onChange(checked: boolean) {
  32 + record.pendingStatus = true;
  33 + const newStatus = checked ? 1 : 0;
  34 + const { createMessage } = useMessage();
  35 + updateTransformScriptStatusApi(newStatus, record.id)
  36 + .then(() => {
  37 + record.status = newStatus;
  38 + createMessage.success(`${record.status ? '启用' : '禁用'}成功`);
  39 + })
  40 + .finally(() => {
  41 + record.pendingStatus = false;
  42 + });
  43 + },
  44 + });
  45 + },
  46 + },
  47 + {
  48 + title: '创建时间',
  49 + dataIndex: 'createTime',
  50 + width: 180,
  51 + },
  52 +];
  53 +
  54 +export const searchFormSchema: FormSchema[] = [
  55 + {
  56 + field: 'name',
  57 + label: '名称',
  58 + component: 'Input',
  59 + colProps: { span: 6 },
  60 + componentProps: {
  61 + maxLength: 36,
  62 + placeholder: '请输入名称',
  63 + },
  64 + },
  65 + {
  66 + field: 'status',
  67 + label: '状态',
  68 + component: 'Select',
  69 + componentProps: {
  70 + placeholder: '请选择状态',
  71 + options: [
  72 + { label: '已启用', value: '1' },
  73 + { label: '未启用', value: '0' },
  74 + ],
  75 + },
  76 + colProps: { span: 6 },
  77 + },
  78 +];
  79 +
  80 +export const formSchema: FormSchema[] = [
  81 + {
  82 + field: 'name',
  83 + label: '名称',
  84 + required: true,
  85 + component: 'Input',
  86 + componentProps: {
  87 + maxLength: 36,
  88 + placeholder: '请输入名称',
  89 + },
  90 + },
  91 + {
  92 + field: 'remark',
  93 + label: '说明',
  94 + component: 'InputTextArea',
  95 + componentProps: {
  96 + maxLength: 255,
  97 + autoSize: { minRows: 5, maxRows: 8 },
  98 + placeholder: '请输入说明',
  99 + },
  100 + },
  101 + {
  102 + field: 'function',
  103 + label: '',
  104 + component: 'Input',
  105 + slot: 'function',
  106 + },
  107 + {
  108 + field: 'id',
  109 + label: 'id',
  110 + component: 'Input',
  111 + ifShow: false,
  112 + },
  113 +];
  1 +<template>
  2 + <div>
  3 + <BasicDrawer
  4 + v-bind="$attrs"
  5 + :title="getTitle"
  6 + @register="register"
  7 + width="500px"
  8 + showFooter
  9 + @ok="handleSubmit"
  10 + >
  11 + <BasicForm @register="registerForm">
  12 + <template #function>
  13 + <Card title="转换函数" :bodyStyle="{ padding: 0, height: '280px' }">
  14 + <template #extra>
  15 + <Tag color="blue">Transform Function</Tag>
  16 + <a-button @click="handleFormat" size="small">格式化</a-button>
  17 + </template>
  18 + <div class="ml-8">function Transform(msg, metadata) {</div>
  19 + <div ref="aceRef" class="overflow-hidden"></div>
  20 + <div class="ml-7">}</div>
  21 + </Card>
  22 + <a-button type="primary" class="mt-4" @click="testTransformFunc">测试转换功能</a-button>
  23 + </template>
  24 + </BasicForm>
  25 + </BasicDrawer>
  26 + </div>
  27 +</template>
  28 +
  29 +<script lang="ts" setup>
  30 + import { ref, computed } from 'vue';
  31 + import { useDrawerInner, BasicDrawer } from '/@/components/Drawer/index';
  32 + import { useForm, BasicForm } from '/@/components/Form/index';
  33 + import { formSchema } from '../config/config.data.ts';
  34 + import { Card, Tag } from 'ant-design-vue';
  35 + import { createOrEditTransformScriptApi } from '/@/api/device/TransformScriptApi';
  36 + import { useMessage } from '/@/hooks/web/useMessage';
  37 + import ace from 'ace-builds';
  38 + import 'ace-builds/src-noconflict/theme-chrome'; // 默认设置的主题
  39 + import 'ace-builds/src-noconflict/mode-javascript'; // 默认设置的语言模式
  40 + import { beautify } from 'ace-builds/src-noconflict/ext-beautify.js';
  41 +
  42 + const emit = defineEmits(['register', 'isStatus', 'success']);
  43 + const isUpdate = ref(false);
  44 + const aceEditor = ref();
  45 + const aceRef = ref();
  46 + const getTitle = computed(() => (isUpdate.value ? '编辑转换脚本' : '新增转换脚本'));
  47 + const [register, { closeDrawer }] = useDrawerInner((data) => {
  48 + resetFields();
  49 + isUpdate.value = data.isUpdate;
  50 + initEditor(data.record?.configuration.jsScript);
  51 + if (isUpdate.value) {
  52 + setFieldsValue(data.record);
  53 + }
  54 + });
  55 + const [registerForm, { getFieldsValue, setFieldsValue, resetFields }] = useForm({
  56 + showActionButtonGroup: false,
  57 + colProps: { span: 24 },
  58 + schemas: formSchema,
  59 + });
  60 +
  61 + // 初始化编辑器
  62 + const initEditor = (jsScript?: string) => {
  63 + aceEditor.value = ace.edit(aceRef.value, {
  64 + maxLines: 12, // 最大行数,超过会自动出现滚动条
  65 + minLines: 12, // 最小行数,还未到最大行数时,编辑器会自动伸缩大小
  66 + fontSize: 14, // 编辑器内字体大小
  67 + theme: 'ace/theme/chrome', // 默认设置的主题
  68 + mode: 'ace/mode/javascript', // 默认设置的语言模式
  69 + tabSize: 2, // 制表符设置为 4 个空格大小
  70 + });
  71 +
  72 + aceEditor.value.setOptions({
  73 + enableBasicAutocompletion: true,
  74 + enableLiveAutocompletion: true,
  75 + });
  76 + aceEditor.value.setValue(jsScript ?? 'return {msg: msg, metadata: metadata};');
  77 + beautify(aceEditor.value.session);
  78 + };
  79 +
  80 + const testTransformFunc = () => {
  81 + closeDrawer();
  82 + const jsCode = aceEditor.value.getValue();
  83 + emit('isStatus', { status: 1, jsCode });
  84 + };
  85 + const handleSubmit = async () => {
  86 + const fieldsValue = getFieldsValue();
  87 + try {
  88 + await createOrEditTransformScriptApi({
  89 + configuration: {
  90 + jsScript: aceEditor.value.getValue(),
  91 + },
  92 + type: 'org.thingsboard.rule.engine.transform.TbTransformMsgNode',
  93 + ...fieldsValue,
  94 + });
  95 + closeDrawer();
  96 + emit('success');
  97 + const { createMessage } = useMessage();
  98 + createMessage.success('保存成功');
  99 + } catch (e) {
  100 + const { createMessage } = useMessage();
  101 + createMessage.success('保存失败');
  102 + }
  103 + };
  104 + const handleFormat = () => {
  105 + beautify(aceEditor.value.session);
  106 + };
  107 + defineExpose({ aceEditor });
  108 +</script>
  1 +<template>
  2 + <div>
  3 + <PageWrapper title="测试脚本功能" class="pl-4 pr-4 pt-4" :contentStyle="{ display: 'none' }" />
  4 + <div class="h-full flex p-4">
  5 + <div class="flex flex-col w-1/2">
  6 + <div class="flex-1 mr-4 mb-4">
  7 + <Card title="消息" :bodyStyle="cardStyle">
  8 + <template #extra>
  9 + <Tag color="blue">Message</Tag>
  10 + <a-button @click="handleFormatJson" size="small">格式化</a-button>
  11 + <a-button @click="handleMiniJson" size="small" class="ml-2">收起</a-button>
  12 + </template>
  13 + <div ref="jsoneditorRef" style="height: 100%"></div>
  14 + </Card>
  15 + </div>
  16 + <div class="flex-1 mr-4">
  17 + <Card title="转换函数" :bodyStyle="cardStyle">
  18 + <template #extra>
  19 + <Tag color="blue">Transform Function</Tag>
  20 + <a-button @click="handleFormatJScript" size="small">格式化</a-button>
  21 +
  22 + <Tooltip title="帮助文档" @click="openModal">
  23 + <QuestionCircleOutlined class="ml-2" style="font-size: 1rem" />
  24 + </Tooltip>
  25 + </template>
  26 + <div class="ml-8">function Transform(msg, metadata) {</div>
  27 + <div ref="aceRef" style="height: calc(100% - 44px)"></div>
  28 + <div class="ml-7">}</div>
  29 + </Card>
  30 + </div>
  31 + </div>
  32 + <div class="flex flex-col w-1/2">
  33 + <div class="flex-1 mb-4">
  34 + <Card title="元数据" :bodyStyle="cardStyle">
  35 + <template #extra>
  36 + <Tag color="blue">Meta Data</Tag>
  37 + </template>
  38 + <Description @register="registerDesc" />
  39 + </Card>
  40 + </div>
  41 + <div class="flex-1">
  42 + <Card title="输出" :bodyStyle="cardStyle">
  43 + <template #extra>
  44 + <Tag color="blue">Output</Tag>
  45 + <a-button @click="handleFormatOutPutJson" size="small">格式化</a-button>
  46 + <a-button @click="handleCompactJson" size="small" class="ml-2">收起</a-button>
  47 + </template>
  48 + <div class="ml-8 opacity-0">site</div>
  49 + <div ref="outputRef" style="height: calc(100% - 44px)"></div>
  50 + <div class="ml-7 opacity-0">site</div>
  51 + </Card>
  52 + </div>
  53 + </div>
  54 + </div>
  55 + <div class="flex justify-between pl-4 pr-4">
  56 + <div>
  57 + <a-button class="" type="primary" @click="handleTestFunc"> 测试</a-button>
  58 + </div>
  59 + <div>
  60 + <a-button class="ml-4" @click="handleCancel"> 取消</a-button>
  61 + <a-button class="ml-4" type="primary" @click="handleOk"> 保存</a-button>
  62 + </div>
  63 + </div>
  64 + <BasicModal
  65 + @register="registerModal"
  66 + title="转换消息功能"
  67 + :footer="null"
  68 + width="800px"
  69 + centered
  70 + v-bind="$attrs"
  71 + >
  72 + <h2> function Transform(msg,metadata): {msg: object, metadata: object} </h2>
  73 + <li> 将输入消息、元数据转换为输出消息的 JavaScript 函数 </li>
  74 + <h2>参数:</h2>
  75 + <ul>
  76 + <li>msg: {[key: string]: any} - 是消息有效负载键/值对象。</li>
  77 + <li>metadata: {[key: string]: string} - 是消息元数据键/值映射,其中键和值都是字符串。</li>
  78 + </ul>
  79 + <h2>返回值:</h2>
  80 + <ul>
  81 + <li> { msg?: {[key: string]: any}, metadata?: {[key: string]: string} } </li>
  82 + <li> 结果对象中的所有字段都是可选的,如果未指定,将从原始消息中获取。 </li>
  83 + </ul>
  84 + </BasicModal>
  85 + </div>
  86 +</template>
  87 +<script lang="ts" setup>
  88 + import { ref, onMounted, defineComponent } from 'vue';
  89 + import { Card, Tag, Tooltip } from 'ant-design-vue';
  90 + import { PageWrapper } from '/@/components/Page';
  91 + import { Description, DescItem, useDescription } from '/@/components/Description/index';
  92 + import { useMessage } from '/@/hooks/web/useMessage';
  93 + import { QuestionCircleOutlined } from '@ant-design/icons-vue';
  94 + import { BasicModal, useModal } from '/@/components/Modal/index';
  95 +
  96 + import jsoneditor from 'jsoneditor';
  97 + import 'jsoneditor/dist/jsoneditor.min.css';
  98 + import ace from 'ace-builds';
  99 + import 'ace-builds/src-noconflict/theme-chrome'; // 默认设置的主题
  100 + import 'ace-builds/src-noconflict/mode-javascript'; // 默认设置的语言模式
  101 + import 'ace-builds/src-noconflict/ext-language_tools.js'; //语言提示
  102 + import { beautify } from 'ace-builds/src-noconflict/ext-beautify.js'; //格式化
  103 + // !!!important 重要,配置ace编辑器的错误提示,基础路径。否则会加载不到相关web Worker,就没有syntax validation提示
  104 + ace.config.set('basePath', 'https://cdn.jsdelivr.net/npm/ace-builds@1.4.14/src-noconflict/');
  105 + defineComponent({
  106 + Tooltip,
  107 + });
  108 +
  109 + const jsonValue = ref({
  110 + temperature: 22.4,
  111 + humidity: 78,
  112 + });
  113 + const cardStyle = { padding: 0, height: '280px' };
  114 +
  115 + // json 以及初始化JSON
  116 + const jsoneditorRef = ref();
  117 + const JsonEditor = ref();
  118 + const outputRef = ref();
  119 + const outputEditor = ref();
  120 + const aceEditor = ref();
  121 + const aceRef = ref();
  122 + const emit = defineEmits(['isStatus']);
  123 + function initEditor() {
  124 + let options = {
  125 + mode: 'code',
  126 + mainMenuBar: false,
  127 + statusBar: false,
  128 + onError: function (err) {
  129 + alert('EF1 ->' + err.toString());
  130 + },
  131 + };
  132 + let editor = new jsoneditor(jsoneditorRef.value, options);
  133 + editor.set(jsonValue.value);
  134 + JsonEditor.value = editor;
  135 + let outEditor = new jsoneditor(outputRef.value, options);
  136 + outEditor.set(true);
  137 + outputEditor.value = outEditor;
  138 +
  139 + aceEditor.value = ace.edit(aceRef.value, {
  140 + maxLines: 12, // 最大行数,超过会自动出现滚动条
  141 + minLines: 12, // 最小行数,还未到最大行数时,编辑器会自动伸缩大小
  142 + fontSize: 14, // 编辑器内字体大小
  143 + theme: 'ace/theme/chrome', // 默认设置的主题
  144 + mode: 'ace/mode/javascript', // 默认设置的语言模式
  145 + tabSize: 2, // 制表符设置为 2 个空格大小
  146 + enableBasicAutocompletion: true, //补全
  147 + enableLiveAutocompletion: true, //
  148 + });
  149 + }
  150 + const mataData: any = {
  151 + deviceName: 'Test Device',
  152 + deviceType: 'default',
  153 + ts: Date.now(),
  154 + };
  155 + const schema: DescItem[] = [
  156 + {
  157 + field: 'deviceName',
  158 + label: 'deviceName',
  159 + },
  160 + {
  161 + field: 'deviceType',
  162 + label: 'deviceType',
  163 + },
  164 + {
  165 + field: 'ts',
  166 + label: 'ts',
  167 + },
  168 + ];
  169 + const [registerDesc] = useDescription({
  170 + column: 1,
  171 + data: mataData,
  172 + schema,
  173 + });
  174 + // 格式化json
  175 + const handleFormatJson = () => {
  176 + JsonEditor.value.repair();
  177 + JsonEditor.value.format();
  178 + };
  179 + // 迷你json
  180 + const handleMiniJson = () => {
  181 + JsonEditor.value.repair();
  182 + JsonEditor.value.compact();
  183 + };
  184 + // format json
  185 + const handleFormatOutPutJson = () => {
  186 + outputEditor.value.repair();
  187 + outputEditor.value.format();
  188 + };
  189 + // 迷你json
  190 + const handleCompactJson = () => {
  191 + outputEditor.value.repair();
  192 + outputEditor.value.compact();
  193 + };
  194 +
  195 + // 测试
  196 + const handleTestFunc = async () => {
  197 + // 收集3方数据
  198 + try {
  199 + const msg = JsonEditor.value.get();
  200 + const metadata = mataData;
  201 + const jsCode = aceEditor.value.getValue();
  202 + // 执行动态Javascript脚本
  203 + let result = Function('msg', 'metadata', jsCode)(msg, metadata);
  204 + // 设置输出值
  205 + outputEditor.value.set(result);
  206 + } catch (e) {
  207 + console.log(e);
  208 + const { createMessage } = useMessage();
  209 + createMessage.error(e.toString());
  210 + }
  211 + };
  212 + const [registerModal, { openModal }] = useModal();
  213 + const handleCancel = () => {
  214 + emit('isStatus', { status: 0, emitType: 'cancel' });
  215 + };
  216 + const handleOk = () => {
  217 + emit('isStatus', { status: 0, emitType: 'ok' });
  218 + };
  219 + const handleFormatJScript = () => {
  220 + beautify(aceEditor.value.session);
  221 + };
  222 + onMounted(() => {
  223 + initEditor();
  224 + });
  225 + defineExpose({ aceEditor });
  226 +</script>
  227 +
  228 +<style scope>
  229 + .jsoneditor {
  230 + border: none;
  231 + }
  232 +</style>
  1 +<template>
  2 + <div>
  3 + <BasicTable @register="registerTable" v-show="isStatus === 0">
  4 + <template #toolbar>
  5 + <a-button type="primary" @click="handleCreate"> 新增转换脚本 </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: 'clarity:note-edit-line',
  16 +
  17 + onClick: handleEdit.bind(null, record),
  18 + },
  19 + {
  20 + label: '删除',
  21 + icon: 'ant-design:delete-outlined',
  22 + ifShow: record.status == 0,
  23 + color: 'error',
  24 + popConfirm: {
  25 + title: '是否确认删除',
  26 + confirm: handleDeleteOrBatchDelete.bind(null, record),
  27 + },
  28 + },
  29 + ]"
  30 + />
  31 + </template>
  32 + </BasicTable>
  33 + <ScriptDrawer
  34 + @register="registerDrawer"
  35 + @isStatus="handleIsStatus"
  36 + ref="scriptDrawerRef"
  37 + @success="handleSuccess"
  38 + />
  39 + <TestScript v-show="isStatus === 1" @isStatus="handleCancelStatus" ref="testScriptRef" />
  40 + </div>
  41 +</template>
  42 +
  43 +<script lang="ts" setup>
  44 + import { ref } from 'vue';
  45 + import { BasicTable, useTable, TableAction } from '/@/components/Table';
  46 + import { columns, searchFormSchema } from './config/config.data.ts';
  47 + import { getConvertApi, deleteTransformApi } from '/@/api/device/TransformScriptApi';
  48 + import { useBatchDelete } from '/@/hooks/web/useBatchDelete';
  49 + import { useDrawer } from '/@/components/Drawer/index';
  50 + import ScriptDrawer from './cpns/ScriptDrawer.vue';
  51 + import TestScript from './cpns/TestScript.vue';
  52 + const handleSuccess = () => {
  53 + reload();
  54 + };
  55 + const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions } = useBatchDelete(
  56 + deleteTransformApi,
  57 + handleSuccess
  58 + );
  59 + const [registerTable, { reload }] = useTable({
  60 + api: getConvertApi,
  61 + title: '转换脚本列表',
  62 + columns,
  63 + useSearchForm: true,
  64 + showTableSetting: true,
  65 + bordered: true,
  66 + showIndexColumn: false,
  67 + formConfig: {
  68 + labelWidth: 100,
  69 + schemas: searchFormSchema,
  70 + },
  71 + actionColumn: {
  72 + width: 180,
  73 + title: '操作',
  74 + dataIndex: 'action',
  75 + slots: { customRender: 'action' },
  76 + fixed: 'right',
  77 + },
  78 + ...selectionOptions,
  79 + });
  80 + const [registerDrawer, { openDrawer }] = useDrawer({});
  81 +
  82 + const isStatus = ref(0);
  83 + const testScriptRef = ref();
  84 + const scriptDrawerRef = ref();
  85 + const handleIsStatus = ({ status, jsCode }) => {
  86 + isStatus.value = status;
  87 + testScriptRef.value.aceEditor.setValue(jsCode);
  88 + };
  89 + const handleCancelStatus = ({ status, emitType }) => {
  90 + openDrawer(true);
  91 + isStatus.value = status;
  92 + if (emitType === 'ok') {
  93 + const jsCode = testScriptRef.value.aceEditor.getValue();
  94 + scriptDrawerRef.value.aceEditor.setValue(jsCode);
  95 + }
  96 + };
  97 + const handleCreate = () => {
  98 + openDrawer(true, {
  99 + isUpdate: false,
  100 + });
  101 + };
  102 + const handleEdit = (record: Recordable) => {
  103 + openDrawer(true, { isUpdate: true, record });
  104 + };
  105 +</script>
  1 +<template>
  2 + <div>
  3 + <PageWrapper
  4 + title="第一次使用请修改当前用户密码,待修改完成后退出登录,才能使用本系统!"
  5 + content="修改成功后会自动退出当前登录!"
  6 + class="p-4"
  7 + >
  8 + <div class="py-8 bg-white flex flex-col justify-center items-center">
  9 + <BasicForm @register="register" />
  10 + <div class="flex justify-center">
  11 + <a-button @click="resetFields"> 重置 </a-button>
  12 + <a-button class="!ml-4" type="primary" @click="handleSubmit"> 确认 </a-button>
  13 + </div>
  14 + </div>
  15 + </PageWrapper>
  16 + </div>
  17 +</template>
  18 +<script lang="ts">
  19 + import { defineComponent } from 'vue';
  20 + import { PageWrapper } from '/@/components/Page';
  21 + import { BasicForm, useForm } from '/@/components/Form';
  22 + import { USER_INFO_KEY } from '/@/enums/cacheEnum';
  23 + import { getAuthCache } from '/@/utils/auth';
  24 + import { formSchema } from './pwd.data';
  25 + import { resetPassword } from '/@/api/system/system';
  26 + import { useMultipleTabStore } from '/@/store/modules/multipleTab';
  27 + import { useUserStore } from '/@/store/modules/user';
  28 + import { useAppStore } from '/@/store/modules/app';
  29 + import { usePermissionStore } from '/@/store/modules/permission';
  30 + import { useMessage } from '/@/hooks/web/useMessage';
  31 + export default defineComponent({
  32 + name: 'ChangePassword',
  33 + components: { BasicForm, PageWrapper },
  34 + setup() {
  35 + const [register, { validate, resetFields }] = useForm({
  36 + size: 'large',
  37 + labelWidth: 100,
  38 + showActionButtonGroup: false,
  39 + schemas: formSchema,
  40 + });
  41 + const tabStore = useMultipleTabStore();
  42 + const userStore = useUserStore();
  43 + const appStore = useAppStore();
  44 + const permissionStore = usePermissionStore();
  45 + const { createMessage } = useMessage();
  46 + const userInfo = getAuthCache(USER_INFO_KEY);
  47 + // console.log(userInfo, 'userInfo');
  48 + async function handleSubmit() {
  49 + try {
  50 + const values = await validate();
  51 + const { passwordOld, passwordNew } = values;
  52 + const params = {
  53 + userId: userInfo.userId,
  54 + password: passwordOld,
  55 + resetPassword: passwordNew,
  56 + };
  57 +
  58 + await resetPassword(params).then((result) => {
  59 + if (result.data) {
  60 + createMessage.success('修改成功');
  61 + // /dashboard/analysis
  62 + setTimeout(function () {
  63 + localStorage.clear();
  64 + appStore.resetAllState();
  65 + permissionStore.resetState();
  66 + tabStore.resetState();
  67 + userStore.resetState();
  68 + location.reload();
  69 + }, 500);
  70 + }
  71 + });
  72 + } catch (error) {}
  73 + }
  74 + return { register, resetFields, handleSubmit };
  75 + },
  76 + });
  77 +</script>
  1 +import { FormSchema } from '/@/components/Form';
  2 +import { InputRegExp } from '/@/enums/regexpEnum';
  3 +export const formSchema: FormSchema[] = [
  4 + {
  5 + field: 'passwordOld',
  6 + label: '当前密码',
  7 + component: 'InputPassword',
  8 + required: true,
  9 + },
  10 + {
  11 + field: 'passwordNew',
  12 + label: '新密码',
  13 + component: 'StrengthMeter',
  14 + componentProps: {
  15 + placeholder: '新密码',
  16 + },
  17 + rules: [
  18 + {
  19 + required: true,
  20 + message: '请输入新密码',
  21 + },
  22 + ],
  23 + },
  24 + {
  25 + field: 'confirmPassword',
  26 + label: '确认密码',
  27 + component: 'InputPassword',
  28 +
  29 + dynamicRules: ({ values }) => {
  30 + return [
  31 + {
  32 + required: true,
  33 + validator: (_, value) => {
  34 + if (!value) {
  35 + return Promise.reject('密码不能为空');
  36 + }
  37 + if (value !== values.passwordNew) {
  38 + return Promise.reject('两次输入的密码不一致!');
  39 + }
  40 +
  41 + const pwdRegex = new RegExp(InputRegExp.PASSWORD_INPUT);
  42 + if (!pwdRegex.test(value)) {
  43 + return Promise.reject(
  44 + '密码中必须包含大小写 字母、数字、特称字符,至少8个字符,最多30个字符'
  45 + );
  46 + }
  47 + return Promise.resolve();
  48 + },
  49 + },
  50 + ];
  51 + },
  52 + },
  53 +];
  1 +import type { FormSchema } from '/@/components/Form/index';
  2 +export const schemas: FormSchema[] = [
  3 + {
  4 + field: 'name',
  5 + component: 'Input',
  6 + label: '平台名称',
  7 + colProps: {
  8 + span: 24,
  9 + },
  10 + componentProps: {
  11 + maxLength: 255,
  12 + placeholder: '请输入平台名称',
  13 + },
  14 + dynamicRules: () => {
  15 + return [
  16 + {
  17 + required: false,
  18 + validator: (_, value) => {
  19 + if (String(value).length > 255) {
  20 + return Promise.reject('字数不超过255个字');
  21 + }
  22 + return Promise.resolve();
  23 + },
  24 + },
  25 + ];
  26 + },
  27 + },
  28 + {
  29 + field: 'logo',
  30 + component: 'Upload',
  31 + label: 'APP Logo',
  32 + colProps: {
  33 + span: 24,
  34 + },
  35 + slot: 'logoUpload',
  36 + },
  37 + {
  38 + field: 'background',
  39 + component: 'Input',
  40 + label: '登录页背景图片',
  41 + colProps: {
  42 + span: 24,
  43 + },
  44 + slot: 'bgUpload',
  45 + },
  46 + {
  47 + field: 'backgroundColor',
  48 + component: 'AutoComplete',
  49 + label: '登录页背景颜色',
  50 + colProps: {
  51 + span: 24,
  52 + },
  53 + slot: 'colorInput',
  54 + },
  55 + {
  56 + field: 'background',
  57 + component: 'Input',
  58 + label: '首页轮播图',
  59 + colProps: {
  60 + span: 24,
  61 + },
  62 + slot: 'homeSwiper',
  63 + },
  64 +];
  1 +import type { FormSchema } from '/@/components/Form/index';
  2 +
  3 +export const schemas: FormSchema[] = [
  4 + {
  5 + field: 'name',
  6 + component: 'Input',
  7 + label: '平台名称',
  8 + colProps: {
  9 + span: 24,
  10 + },
  11 + componentProps: {
  12 + maxLength: 255,
  13 + placeholder: '请输入平台名称',
  14 + },
  15 + dynamicRules: () => {
  16 + return [
  17 + {
  18 + required: false,
  19 + validator: (_, value) => {
  20 + if (String(value).length > 255) {
  21 + return Promise.reject('字数不超过255个字');
  22 + }
  23 + return Promise.resolve();
  24 + },
  25 + },
  26 + ];
  27 + },
  28 + },
  29 + {
  30 + field: 'logo',
  31 + component: 'Upload',
  32 + label: '平台Logo',
  33 + colProps: {
  34 + span: 24,
  35 + },
  36 + slot: 'logoUpload',
  37 + },
  38 + {
  39 + field: 'icon',
  40 + component: 'Upload',
  41 + label: '浏览器Icon图标',
  42 + colProps: {
  43 + span: 24,
  44 + },
  45 + slot: 'iconUpload',
  46 + },
  47 + {
  48 + field: 'background',
  49 + component: 'Input',
  50 + label: '登录页背景图片',
  51 + colProps: {
  52 + span: 24,
  53 + },
  54 + slot: 'bgUpload',
  55 + },
  56 + {
  57 + field: 'backgroundColor',
  58 + component: 'AutoComplete',
  59 + label: '登录页背景颜色',
  60 + colProps: {
  61 + span: 24,
  62 + },
  63 + slot: 'colorInput',
  64 + },
  65 + {
  66 + field: 'copyright',
  67 + component: 'Input',
  68 + label: '页面底部版权信息',
  69 + colProps: {
  70 + span: 24,
  71 + },
  72 + componentProps: {
  73 + maxLength: 100,
  74 + placeholder: '请输入页面底部版权信息',
  75 + },
  76 + dynamicRules: () => {
  77 + return [
  78 + {
  79 + required: false,
  80 + validator: (_, value) => {
  81 + if (String(value).length > 100) {
  82 + return Promise.reject('字数不超过100个字');
  83 + }
  84 + return Promise.resolve();
  85 + },
  86 + },
  87 + ];
  88 + },
  89 + },
  90 + {
  91 + field: 'presentedOurselves',
  92 + component: 'Input',
  93 + label: '备案信息',
  94 + colProps: {
  95 + span: 24,
  96 + },
  97 + componentProps: {
  98 + maxLength: 50,
  99 + placeholder: '请输入备案信息',
  100 + },
  101 + dynamicRules: () => {
  102 + return [
  103 + {
  104 + required: false,
  105 + validator: (_, value) => {
  106 + if (String(value).length > 50) {
  107 + return Promise.reject('字数不超过50个字');
  108 + }
  109 + return Promise.resolve();
  110 + },
  111 + },
  112 + ];
  113 + },
  114 + },
  115 + {
  116 + field: 'domain',
  117 + component: 'Input',
  118 + label: '绑定域名',
  119 + colProps: {
  120 + span: 24,
  121 + },
  122 + componentProps: {
  123 + maxLength: 100,
  124 + placeholder: '请输入绑定域名',
  125 + },
  126 + dynamicRules: () => {
  127 + return [
  128 + {
  129 + required: false,
  130 + validator: (_, value) => {
  131 + if (String(value).length > 100) {
  132 + return Promise.reject('字数不超过100个字');
  133 + }
  134 + return Promise.resolve();
  135 + },
  136 + },
  137 + ];
  138 + },
  139 + },
  140 +];
  1 +import type { FormSchema } from '/@/components/Form/index';
  2 +import { getAreaList } from '/@/api/oem/index';
  3 +import { emailRule, phoneRule } from '/@/utils/rules';
  4 +
  5 +export const schemas: FormSchema[] = [
  6 + {
  7 + field: 'name',
  8 + component: 'Input',
  9 + label: '公司名称',
  10 + colProps: {
  11 + span: 24,
  12 + },
  13 + componentProps: {
  14 + maxLength: 100,
  15 + placeholder: '请输入公司名称',
  16 + },
  17 + dynamicRules: () => {
  18 + return [
  19 + {
  20 + required: false,
  21 + validator: (_, value) => {
  22 + if (String(value).length > 100) {
  23 + return Promise.reject('字数不超过100个字');
  24 + }
  25 + return Promise.resolve();
  26 + },
  27 + },
  28 + ];
  29 + },
  30 + },
  31 + {
  32 + field: 'abbreviation',
  33 + component: 'Input',
  34 + label: '公司简称',
  35 + colProps: {
  36 + span: 24,
  37 + },
  38 + componentProps: {
  39 + maxLength: 100,
  40 + placeholder: '请输入公司简称',
  41 + },
  42 + dynamicRules: () => {
  43 + return [
  44 + {
  45 + required: false,
  46 + validator: (_, value) => {
  47 + if (String(value).length > 100) {
  48 + return Promise.reject('字数不超过100个字');
  49 + }
  50 + return Promise.resolve();
  51 + },
  52 + },
  53 + ];
  54 + },
  55 + },
  56 + {
  57 + field: 'officialWebsite',
  58 + component: 'Input',
  59 + label: '公司官网',
  60 + colProps: {
  61 + span: 24,
  62 + },
  63 + componentProps: {
  64 + maxLength: 255,
  65 + placeholder: '请输入公司官网',
  66 + },
  67 + dynamicRules: () => {
  68 + return [
  69 + {
  70 + required: false,
  71 + validator: (_, value) => {
  72 + if (String(value).length > 255) {
  73 + return Promise.reject('字数不超过255个字');
  74 + }
  75 + return Promise.resolve();
  76 + },
  77 + },
  78 + ];
  79 + },
  80 + },
  81 + {
  82 + field: 'email',
  83 + component: 'Input',
  84 + label: '公司邮箱',
  85 + colProps: {
  86 + span: 24,
  87 + },
  88 + componentProps: {
  89 + placeholder: '请输入公司邮箱',
  90 + },
  91 + rules: emailRule,
  92 + },
  93 + {
  94 + field: 'synopsis',
  95 + component: 'InputTextArea',
  96 + label: '公司简介',
  97 + colProps: {
  98 + span: 24,
  99 + },
  100 + componentProps: {
  101 + maxLength: 500,
  102 + placeholder: '请输入公司简介',
  103 + autoSize: { minRows: 8, maxRows: 12 },
  104 + },
  105 + dynamicRules: () => {
  106 + return [
  107 + {
  108 + required: false,
  109 + validator: (_, value) => {
  110 + if (String(value).length > 500) {
  111 + return Promise.reject('字数不超过500个字');
  112 + }
  113 + return Promise.resolve();
  114 + },
  115 + },
  116 + ];
  117 + },
  118 + },
  119 + {
  120 + field: 'nameCountry',
  121 + component: 'ApiSelect',
  122 + label: '国家/地区',
  123 + colProps: {
  124 + span: 24,
  125 + },
  126 + componentProps: {
  127 + api: getAreaList,
  128 + params: { parentId: 0 },
  129 + labelField: 'name',
  130 + valueField: 'code',
  131 + placeholder: '国家/地区',
  132 + },
  133 + },
  134 + {
  135 + field: 'prov',
  136 + label: '所在城市',
  137 + component: 'Input',
  138 + colProps: {
  139 + span: 24,
  140 + },
  141 +
  142 + slot: 'customProv',
  143 + },
  144 + {
  145 + field: 'address',
  146 + component: 'Input',
  147 + label: '详细地址',
  148 + colProps: {
  149 + span: 24,
  150 + },
  151 + componentProps: {
  152 + maxLength: 100,
  153 + placeholder: '请输入详细地址',
  154 + },
  155 + dynamicRules: () => {
  156 + return [
  157 + {
  158 + required: false,
  159 + validator: (_, value) => {
  160 + if (String(value).length > 100) {
  161 + return Promise.reject('字数不超过100个字');
  162 + }
  163 + return Promise.resolve();
  164 + },
  165 + },
  166 + ];
  167 + },
  168 + },
  169 +
  170 + {
  171 + field: 'contacts',
  172 + component: 'Input',
  173 + label: '联系人',
  174 + colProps: {
  175 + span: 24,
  176 + },
  177 + componentProps: {
  178 + maxLength: 25,
  179 + placeholder: '请输入联系人',
  180 + },
  181 + dynamicRules: () => {
  182 + return [
  183 + {
  184 + required: false,
  185 + validator: (_, value) => {
  186 + if (String(value).length > 25) {
  187 + return Promise.reject('字数不超过25个字');
  188 + }
  189 + return Promise.resolve();
  190 + },
  191 + },
  192 + ];
  193 + },
  194 + },
  195 + {
  196 + field: 'tel',
  197 + component: 'Input',
  198 + label: '联系电话',
  199 + colProps: {
  200 + span: 24,
  201 + },
  202 + componentProps: {
  203 + placeholder: '请输入联系电话',
  204 + },
  205 + rules: phoneRule,
  206 + },
  207 + {
  208 + field: 'qrcode',
  209 + label: '二维码',
  210 + component: 'Input',
  211 + colProps: {
  212 + span: 24,
  213 + },
  214 + slot: 'qrcode',
  215 + },
  216 + {
  217 + field: 'id',
  218 + label: '唯一id',
  219 + component: 'Input',
  220 + show: false,
  221 + componentProps: {
  222 + maxLength: 36,
  223 + placeholder: '请输入唯一id',
  224 + },
  225 + },
  226 +];
  227 +
  228 +export const provSchemas: FormSchema[] = [
  229 + {
  230 + field: 'nameProv',
  231 + component: 'ApiSelect',
  232 + label: '',
  233 + colProps: {
  234 + span: 6,
  235 + },
  236 + componentProps({ formModel, formActionType }) {
  237 + const { updateSchema } = formActionType;
  238 + return {
  239 + api: getAreaList,
  240 + labelField: 'name',
  241 + valueField: 'code',
  242 + placeholder: '省份',
  243 + params: { parentId: 1 },
  244 + async onChange(value) {
  245 + if (value === undefined) {
  246 + formModel.nameCity = undefined; // reset city value
  247 + formModel.nameCoun = undefined;
  248 + formModel.nameTown = undefined;
  249 + updateSchema([
  250 + {
  251 + field: 'nameCity',
  252 + componentProps: {
  253 + options: [],
  254 + placeholder: '城市',
  255 + },
  256 + },
  257 + {
  258 + field: 'nameCoun',
  259 + componentProps: {
  260 + options: [],
  261 + placeholder: '区/县',
  262 + },
  263 + },
  264 + {
  265 + field: 'nameTown',
  266 + componentProps: {
  267 + options: [],
  268 + placeholder: '城镇/街道',
  269 + },
  270 + },
  271 + ]);
  272 + } else {
  273 + const nameCity = await getAreaList({ parentId: value });
  274 + nameCity.forEach((item) => {
  275 + item.label = item.name;
  276 + item.value = item.code;
  277 + });
  278 + formModel.nameCity = undefined; // reset city value
  279 + formModel.nameCoun = undefined;
  280 + formModel.nameTown = undefined;
  281 + updateSchema({
  282 + field: 'nameCity',
  283 + componentProps: {
  284 + options: nameCity,
  285 + placeholder: '城市',
  286 + async onChange(value) {
  287 + if (value === undefined) {
  288 + formModel.nameCoun = undefined; // reset city value
  289 + formModel.nameTown = undefined;
  290 + updateSchema([
  291 + {
  292 + field: 'nameCoun',
  293 + componentProps: {
  294 + options: [],
  295 + },
  296 + },
  297 + {
  298 + field: 'nameTown',
  299 + componentProps: {
  300 + options: [],
  301 + },
  302 + },
  303 + ]);
  304 + } else {
  305 + // 获取区数据
  306 + const nameCoun = await getAreaList({ parentId: value });
  307 + nameCoun.forEach((item) => {
  308 + item.label = item.name;
  309 + item.value = item.code;
  310 + });
  311 + updateSchema({
  312 + field: 'nameCoun',
  313 + componentProps: {
  314 + // 请选择区
  315 + options: nameCoun,
  316 + async onChange(value) {
  317 + if (value === undefined) {
  318 + formModel.nameTown = undefined;
  319 + updateSchema({
  320 + field: 'nameTown',
  321 + componentProps: {
  322 + placeholder: '城镇/街道',
  323 + options: [],
  324 + },
  325 + });
  326 + } else {
  327 + const nameTown = await getAreaList({ parentId: value });
  328 + nameTown.forEach((item) => {
  329 + item.label = item.name;
  330 + item.value = item.code;
  331 + });
  332 + updateSchema({
  333 + field: 'nameTown',
  334 + componentProps: {
  335 + placeholder: '城镇/街道',
  336 + options: nameTown,
  337 + },
  338 + });
  339 + }
  340 + },
  341 + },
  342 + });
  343 + }
  344 + },
  345 + },
  346 + });
  347 + }
  348 + },
  349 + };
  350 + },
  351 + },
  352 + {
  353 + field: 'nameCity',
  354 + component: 'Select',
  355 + label: '',
  356 + colProps: {
  357 + span: 6,
  358 + },
  359 + },
  360 + {
  361 + field: 'nameCoun',
  362 + component: 'Select',
  363 + label: '',
  364 + colProps: {
  365 + span: 6,
  366 + },
  367 + componentProps: {
  368 + placeholder: '区/县',
  369 + },
  370 + },
  371 + {
  372 + field: 'nameTown',
  373 + component: 'Select',
  374 + label: '',
  375 + colProps: {
  376 + span: 6,
  377 + },
  378 + componentProps: {
  379 + placeholder: '城镇/街道',
  380 + },
  381 + },
  382 +];
  1 +<template>
  2 + <div class="card">
  3 + <Card :bordered="false" class="card">
  4 + <BasicForm @register="registerForm">
  5 + <template #logoUpload>
  6 + <Upload
  7 + name="avatar"
  8 + list-type="picture-card"
  9 + class="avatar-uploader"
  10 + :show-upload-list="false"
  11 + @preview="handlePreview"
  12 + :customRequest="customUploadLogoPic"
  13 + :before-upload="beforeUploadLogoPic"
  14 + >
  15 + <img v-if="logoPic" :src="logoPic" />
  16 + <div v-else>
  17 + <div style="margin-top: 1.875rem">
  18 + <PlusOutlined style="font-size: 2.5rem" />
  19 + </div>
  20 + <div
  21 + class="ant-upload-text flex"
  22 + style="width: 180px; height: 100px; align-items: center; font-size: 0.5625rem"
  23 + >
  24 + 支持.PNG、.JPG格式,建议尺寸为32*32px,大小不超过500KB</div
  25 + >
  26 + </div>
  27 + </Upload>
  28 + </template>
  29 + <template #bgUpload>
  30 + <Upload
  31 + name="avatar"
  32 + list-type="picture-card"
  33 + class="avatar-uploader"
  34 + :show-upload-list="false"
  35 + :customRequest="customUploadBgPic"
  36 + :before-upload="beforeUploadBgPic"
  37 + >
  38 + <img v-if="bgPic" :src="bgPic" alt="avatar" />
  39 + <div v-else>
  40 + <div style="margin-top: 1.875rem">
  41 + <PlusOutlined style="font-size: 2.5rem" />
  42 + </div>
  43 + <div
  44 + class="ant-upload-text flex"
  45 + style="width: 280px; height: 100px; align-items: center; font-size: 0.5625rem"
  46 + >
  47 + 支持.PNG、.JPG格式,建议尺寸为1080*1620px,大小不超过5M</div
  48 + >
  49 + </div>
  50 + </Upload>
  51 + </template>
  52 + <template #colorInput="{ model, field }"
  53 + ><Input disabled v-model:value="model[field]">
  54 + <template #prefix> <input type="color" v-model="model[field]" /> </template
  55 + ></Input>
  56 + </template>
  57 +
  58 + <template #homeSwiper>
  59 + <Upload
  60 + v-model:file-list="fileList"
  61 + list-type="picture-card"
  62 + @preview="handlePreview"
  63 + :customRequest="customUploadHomeSwiper"
  64 + :before-upload="beforeUploadHomeSwiper"
  65 + >
  66 + <div v-if="fileList.length < 5">
  67 + <div style="margin-top: 1.875rem">
  68 + <PlusOutlined style="font-size: 2.5rem" />
  69 + </div>
  70 + <div
  71 + class="ant-upload-text flex"
  72 + style="width: 150px; height: 70px; align-items: center; font-size: 0.5625rem"
  73 + >支持.PNG、.JPG格式,建议尺寸为800*600px,大小不超过3M</div
  74 + >
  75 + </div>
  76 + </Upload>
  77 + <Modal :visible="previewVisible" :footer="null" @cancel="handleCancel">
  78 + <img alt="example" style="width: 100%" :src="previewImage" />
  79 + </Modal>
  80 + </template>
  81 + </BasicForm>
  82 + </Card>
  83 + <Loading v-bind="compState" />
  84 + <a-button
  85 + @click="handleUpdateInfo"
  86 + size="large"
  87 + type="primary"
  88 + style="margin-top: 20px; border-radius: 5px"
  89 + >保存信息</a-button
  90 + >
  91 + </div>
  92 +</template>
  93 +
  94 +<script lang="ts">
  95 + import { defineComponent, ref, unref, onMounted } from 'vue';
  96 + import { BasicForm, useForm } from '/@/components/Form/index';
  97 + import { Loading } from '/@/components/Loading/index';
  98 + import { Card, Upload, Input, Modal } from 'ant-design-vue';
  99 + import { PlusOutlined } from '@ant-design/icons-vue';
  100 + import { schemas } from '../config/AppDraw.config';
  101 + import { FileItem, FileInfo } from '../types/index';
  102 + import { logoUpload, bgUpload } from '/@/api/oem/index';
  103 + import { useMessage } from '/@/hooks/web/useMessage';
  104 + import { getAppDesign, updateAppDesign } from '/@/api/oem/index';
  105 + export default defineComponent({
  106 + components: {
  107 + Card,
  108 + BasicForm,
  109 + Upload,
  110 + Loading,
  111 + PlusOutlined,
  112 + Input,
  113 + Modal,
  114 + },
  115 + setup() {
  116 + const compState = ref({
  117 + absolute: false,
  118 + loading: false,
  119 + tip: '拼命加载中...',
  120 + });
  121 + const { createMessage } = useMessage();
  122 + const [registerForm, { getFieldsValue, setFieldsValue }] = useForm({
  123 + schemas,
  124 + showSubmitButton: false,
  125 + showResetButton: false,
  126 + labelWidth: 150,
  127 + wrapperCol: {
  128 + span: 10,
  129 + },
  130 + });
  131 + const previewVisible = ref<boolean>(false);
  132 + const previewImage = ref<string | undefined>('');
  133 + function getBase64(file: File) {
  134 + return new Promise((resolve, reject) => {
  135 + const reader = new FileReader();
  136 + reader.readAsDataURL(file);
  137 + reader.onload = () => resolve(reader.result);
  138 + reader.onerror = (error) => reject(error);
  139 + });
  140 + }
  141 + const handleCancel = () => {
  142 + previewVisible.value = false;
  143 + };
  144 + const handlePreview = async (file: FileItem) => {
  145 + if (!file.url && !file.preview) {
  146 + file.preview = (await getBase64(file.originFileObj)) as string;
  147 + }
  148 + previewImage.value = file.url || file.preview;
  149 + previewVisible.value = true;
  150 + };
  151 + const handleChange = ({ fileList: newFileList }: FileInfo) => {
  152 + fileList.value = newFileList;
  153 + };
  154 +
  155 + // logo图片上传
  156 + const logoPic = ref();
  157 + async function customUploadLogoPic({ file }) {
  158 + if (beforeUploadLogoPic(file)) {
  159 + const formData = new FormData();
  160 + formData.append('file', file);
  161 + const response = await logoUpload(formData);
  162 + if (response.fileStaticUri) {
  163 + logoPic.value = response.fileStaticUri;
  164 + }
  165 + }
  166 + }
  167 + const beforeUploadLogoPic = (file) => {
  168 + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
  169 + if (!isJpgOrPng) {
  170 + createMessage.error('只能上传图片文件!');
  171 + }
  172 + const isLt2M = (file.size as number) / 1024 < 500;
  173 + if (!isLt2M) {
  174 + createMessage.error('图片大小不能超过500KB!');
  175 + }
  176 + return isJpgOrPng && isLt2M;
  177 + };
  178 +
  179 + // 登录页背景上传
  180 + const bgPic = ref();
  181 + async function customUploadBgPic({ file }) {
  182 + if (beforeUploadBgPic(file)) {
  183 + const formData = new FormData();
  184 + formData.append('file', file);
  185 + const response = await bgUpload(formData);
  186 + if (response.fileStaticUri) {
  187 + bgPic.value = response.fileStaticUri;
  188 + }
  189 + }
  190 + }
  191 + const beforeUploadBgPic = (file) => {
  192 + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
  193 + if (!isJpgOrPng) {
  194 + createMessage.error('只能上传图片文件!');
  195 + }
  196 + const isLt2M = (file.size as number) / 1024 / 1024 < 5;
  197 + if (!isLt2M) {
  198 + createMessage.error('图片大小不能超过5MB!');
  199 + }
  200 + return isJpgOrPng && isLt2M;
  201 + };
  202 + // 首页轮播图
  203 + const fileList = ref<FileItem[]>([]);
  204 + async function customUploadHomeSwiper({ file }) {
  205 + if (beforeUploadHomeSwiper(file)) {
  206 + const formData = new FormData();
  207 + formData.append('file', file);
  208 +
  209 + const response = await bgUpload(formData);
  210 + if (response.fileStaticUri) {
  211 + fileList.value.push({
  212 + uid: -Math.random() + '',
  213 + name: response.fileName,
  214 + status: 'done',
  215 + url: response.fileStaticUri,
  216 + });
  217 + const fileArr = fileList.value.filter((item) => {
  218 + return item.percent !== 0;
  219 + });
  220 + fileList.value = fileArr;
  221 + }
  222 + }
  223 + }
  224 +
  225 + const beforeUploadHomeSwiper = (file) => {
  226 + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
  227 + if (!isJpgOrPng) {
  228 + createMessage.error('只能上传图片文件!');
  229 + }
  230 + const isLt2M = (file.size as number) / 1024 / 1024 < 5;
  231 + if (!isLt2M) {
  232 + createMessage.error('图片大小不能超过5MB!');
  233 + }
  234 + return isJpgOrPng && isLt2M;
  235 + };
  236 +
  237 + const handleUpdateInfo = async () => {
  238 + try {
  239 + const fieldValue = getFieldsValue();
  240 + // 做换字段
  241 + const homeSwiper = fileList.value.map((item) => item.url);
  242 + const rotation = homeSwiper.join(',');
  243 +
  244 + compState.value.loading = true;
  245 + await updateAppDesign({
  246 + ...fieldValue,
  247 + background: unref(bgPic),
  248 + icon: unref(bgPic),
  249 + logo: unref(logoPic),
  250 + rotation,
  251 + });
  252 + compState.value.loading = false;
  253 + createMessage.success('保存信息成功');
  254 + } catch (e) {
  255 + createMessage.error('保存信息失败');
  256 + }
  257 + };
  258 +
  259 + onMounted(async () => {
  260 + const res = await getAppDesign();
  261 + const rotation = res.rotation ? res.rotation.split(',') : [];
  262 + const arr: any[] = [];
  263 + for (let item of rotation) {
  264 + arr.push({
  265 + uid: -Math.random() + '',
  266 + name: '111',
  267 + url: item,
  268 + status: 'done',
  269 + });
  270 + }
  271 + setFieldsValue(res);
  272 + logoPic.value = res.logo;
  273 + bgPic.value = res.background;
  274 + if (arr[0]?.url === '') return;
  275 + fileList.value = arr;
  276 + });
  277 + return {
  278 + compState,
  279 + fileList,
  280 + registerForm,
  281 + handleUpdateInfo,
  282 + handleCancel,
  283 + handlePreview,
  284 + customUploadLogoPic,
  285 + beforeUploadLogoPic,
  286 + customUploadBgPic,
  287 + beforeUploadBgPic,
  288 + customUploadHomeSwiper,
  289 + beforeUploadHomeSwiper,
  290 + handleChange,
  291 + logoPic,
  292 + bgPic,
  293 + previewVisible,
  294 + previewImage,
  295 + };
  296 + },
  297 + });
  298 +</script>
  299 +
  300 +<style lang="less" scoped>
  301 + .ant-upload-select-picture-card i {
  302 + font-size: 32px;
  303 + color: #999;
  304 + }
  305 +
  306 + .ant-upload-select-picture-card .ant-upload-text {
  307 + margin-top: 8px;
  308 + color: #666;
  309 + }
  310 +</style>
  1 +<template>
  2 + <div class="card">
  3 + <Card :bordered="false" class="card">
  4 + <BasicForm @register="registerForm">
  5 + <template #logoUpload>
  6 + <Upload
  7 + name="avatar"
  8 + list-type="picture-card"
  9 + class="avatar-uploader"
  10 + :show-upload-list="false"
  11 + :customRequest="customUploadLogoPic"
  12 + :before-upload="beforeUploadLogoPic"
  13 + >
  14 + <img v-if="logoPic" :src="logoPic" />
  15 + <div v-else>
  16 + <div style="margin-top: 1.875rem">
  17 + <PlusOutlined style="font-size: 2.5rem" />
  18 + </div>
  19 + <div
  20 + class="ant-upload-text flex"
  21 + style="width: 180px; height: 100px; align-items: center; font-size: 0.5625rem"
  22 + >
  23 + 支持.PNG、.JPG格式,建议尺寸为32*32px,大小不超过500KB</div
  24 + >
  25 + </div>
  26 + </Upload>
  27 + </template>
  28 + <template #iconUpload>
  29 + <Upload
  30 + name="avatar"
  31 + list-type="picture-card"
  32 + class="avatar-uploader"
  33 + :show-upload-list="false"
  34 + :customRequest="customUploadIconPic"
  35 + :before-upload="beforeUploadIconPic"
  36 + >
  37 + <div v-if="iconPic">
  38 + <img :src="iconPic" class="m-auto" />
  39 + <div style="background-color: #ccc; margin-top: 20px">重新上传</div>
  40 + </div>
  41 + <div v-else>
  42 + <div style="margin-top: 20px">
  43 + <PlusOutlined style="font-size: 30px" />
  44 + </div>
  45 + <div
  46 + class="ant-upload-text flex"
  47 + style="width: 130px; height: 70px; align-items: center; font-size: 0.5625rem"
  48 + >
  49 + 支持.ICON格式,建议尺寸为16*16px</div
  50 + >
  51 + </div>
  52 + </Upload>
  53 + </template>
  54 + <template #bgUpload>
  55 + <Upload
  56 + name="avatar"
  57 + list-type="picture-card"
  58 + class="avatar-uploader"
  59 + :show-upload-list="false"
  60 + :customRequest="customUploadBgPic"
  61 + :before-upload="beforeUploadBgPic"
  62 + >
  63 + <img v-if="bgPic" :src="bgPic" alt="avatar" />
  64 + <div v-else>
  65 + <div style="margin-top: 1.875rem">
  66 + <PlusOutlined style="font-size: 2.5rem" />
  67 + </div>
  68 + <div
  69 + class="ant-upload-text flex"
  70 + style="width: 280px; height: 130px; align-items: center; font-size: 0.5625rem"
  71 + >
  72 + 支持.PNG、.JPG格式,建议尺寸为1920*1080px以上,大小不超过5M</div
  73 + >
  74 + </div>
  75 + </Upload>
  76 + </template>
  77 +
  78 + <template #colorInput="{ model, field }"
  79 + ><Input disabled v-model:value="model[field]">
  80 + <template #prefix> <input type="color" v-model="model[field]" /> </template
  81 + ></Input>
  82 + </template>
  83 + </BasicForm>
  84 + </Card>
  85 + <Loading v-bind="compState" />
  86 + <a-button
  87 + @click="handleUpdateInfo"
  88 + size="large"
  89 + type="primary"
  90 + style="margin-top: 20px; border-radius: 5px"
  91 + >保存信息</a-button
  92 + >
  93 + </div>
  94 +</template>
  95 +
  96 +<script lang="ts">
  97 + import { defineComponent, ref, onMounted, unref } from 'vue';
  98 + import { Card, Upload, Input } from 'ant-design-vue';
  99 + import { BasicForm, useForm } from '/@/components/Form/index';
  100 + import { schemas } from '../config/CVIDraw.config';
  101 + import { Loading } from '/@/components/Loading/index';
  102 + import { useMessage } from '/@/hooks/web/useMessage';
  103 + import type { FileItem } from '/@/components/Upload/src/typing';
  104 + import { logoUpload, iconUpload, bgUpload, getPlatForm, updatePlatForm } from '/@/api/oem/index';
  105 + import { PlusOutlined } from '@ant-design/icons-vue';
  106 + import { useUserStore } from '/@/store/modules/user';
  107 + import { createLocalStorage } from '/@/utils/cache/index';
  108 + import { useTitle } from '@vueuse/core';
  109 + import { useGlobSetting } from '/@/hooks/setting';
  110 + export default defineComponent({
  111 + components: {
  112 + BasicForm,
  113 + Card,
  114 + Loading,
  115 + Upload,
  116 + Input,
  117 + PlusOutlined,
  118 + },
  119 + setup() {
  120 + const compState = ref({
  121 + absolute: false,
  122 + loading: false,
  123 + tip: '拼命加载中...',
  124 + });
  125 + const { createMessage } = useMessage();
  126 + const userStore = useUserStore();
  127 + const storage = createLocalStorage();
  128 + const [registerForm, { getFieldsValue, setFieldsValue }] = useForm({
  129 + schemas,
  130 + showSubmitButton: false,
  131 + showResetButton: false,
  132 + labelWidth: 150,
  133 + wrapperCol: {
  134 + span: 10,
  135 + },
  136 + });
  137 +
  138 + const logoPic = ref();
  139 + const iconPic = ref();
  140 + const bgPic = ref();
  141 + // logo图片上传
  142 + async function customUploadLogoPic({ file }) {
  143 + if (beforeUploadLogoPic(file)) {
  144 + const formData = new FormData();
  145 + formData.append('file', file);
  146 + const response = await logoUpload(formData);
  147 + if (response.fileStaticUri) {
  148 + logoPic.value = response.fileStaticUri;
  149 + }
  150 + }
  151 + }
  152 + const beforeUploadLogoPic = (file: FileItem) => {
  153 + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
  154 + if (!isJpgOrPng) {
  155 + createMessage.error('只能上传图片文件!');
  156 + }
  157 + const isLt2M = (file.size as number) / 1024 < 500;
  158 + if (!isLt2M) {
  159 + createMessage.error('图片大小不能超过500KB!');
  160 + }
  161 + return isJpgOrPng && isLt2M;
  162 + };
  163 + // Icon上传
  164 + async function customUploadIconPic({ file }) {
  165 + if (beforeUploadIconPic(file)) {
  166 + const formData = new FormData();
  167 + formData.append('file', file);
  168 + const response = await iconUpload(formData);
  169 + if (response.fileStaticUri) {
  170 + iconPic.value = response.fileStaticUri;
  171 + }
  172 + }
  173 + }
  174 + const beforeUploadIconPic = (file: FileItem) => {
  175 + const isJpgOrPng = file.type === 'image/x-icon';
  176 + if (!isJpgOrPng) {
  177 + createMessage.error('只能上传.icon图片文件!');
  178 + }
  179 + const isLt2M = (file.size as number) / 1024 < 500;
  180 + if (!isLt2M) {
  181 + createMessage.error('图片大小不能超过500KB!');
  182 + }
  183 + return isJpgOrPng && isLt2M;
  184 + };
  185 + // 登录页背景上传
  186 + async function customUploadBgPic({ file }) {
  187 + if (beforeUploadBgPic(file)) {
  188 + const formData = new FormData();
  189 + formData.append('file', file);
  190 + const response = await bgUpload(formData);
  191 + if (response.fileStaticUri) {
  192 + bgPic.value = response.fileStaticUri;
  193 + }
  194 + }
  195 + }
  196 + const beforeUploadBgPic = (file: FileItem) => {
  197 + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
  198 + if (!isJpgOrPng) {
  199 + createMessage.error('只能上传图片文件!');
  200 + }
  201 + const isLt2M = (file.size as number) / 1024 / 1024 < 5;
  202 + if (!isLt2M) {
  203 + createMessage.error('图片大小不能超过5MB!');
  204 + }
  205 + return isJpgOrPng && isLt2M;
  206 + };
  207 +
  208 + // 更新
  209 + const handleUpdateInfo = async () => {
  210 + try {
  211 + const fieldValue = getFieldsValue();
  212 + compState.value.loading = true;
  213 + const newFieldValue = {
  214 + ...fieldValue,
  215 + logo: unref(logoPic),
  216 + icon: unref(iconPic),
  217 + background: unref(bgPic),
  218 + };
  219 + await updatePlatForm(newFieldValue);
  220 + compState.value.loading = false;
  221 + createMessage.success('保存信息成功');
  222 +
  223 + setPlatFormInfo(newFieldValue);
  224 + } catch (e) {
  225 + createMessage.error('保存信息失败');
  226 + }
  227 + };
  228 + // 设置平台信息
  229 + function setPlatFormInfo(newFieldValue) {
  230 + // 保存store
  231 + userStore.setPlatInfo(newFieldValue);
  232 + // 保存本地缓存
  233 + storage.set('platInfo', newFieldValue);
  234 + const { title } = useGlobSetting();
  235 + useTitle(`OEM定制 - ${newFieldValue.name === '' ? title : newFieldValue.name}`);
  236 + }
  237 +
  238 + onMounted(async () => {
  239 + const res = await getPlatForm();
  240 + setFieldsValue(res);
  241 + logoPic.value = res.logo;
  242 + iconPic.value = res.icon;
  243 + bgPic.value = res.background;
  244 + });
  245 + return {
  246 + registerForm,
  247 + logoPic,
  248 + iconPic,
  249 + bgPic,
  250 + customUploadLogoPic,
  251 + beforeUploadLogoPic,
  252 + customUploadIconPic,
  253 + beforeUploadIconPic,
  254 + customUploadBgPic,
  255 + beforeUploadBgPic,
  256 + compState,
  257 + handleUpdateInfo,
  258 + };
  259 + },
  260 + });
  261 +</script>
  262 +
  263 +<style lang="less" scoped></style>
  1 +<template>
  2 + <div class="card">
  3 + <Card :bordered="false" class="card">
  4 + <BasicForm @register="registerForm">
  5 + <template #qrcode>
  6 + <Upload
  7 + name="avatar"
  8 + list-type="picture-card"
  9 + class="avatar-uploader"
  10 + :show-upload-list="false"
  11 + :customRequest="customUploadqrcodePic"
  12 + :before-upload="beforeUploadqrcodePic"
  13 + >
  14 + <img v-if="qrcodePic" :src="qrcodePic" alt="avatar" />
  15 + <div v-else>
  16 + <div style="margin-top: 1.875rem">
  17 + <PlusOutlined style="font-size: 2.5rem" />
  18 + </div>
  19 + <div
  20 + class="ant-upload-text flex"
  21 + style="width: 180px; height: 100px; align-items: center; font-size: 0.5625rem"
  22 + >
  23 + 支持.PNG、.JPG格式,建议尺寸为300*300px,大小不超过2M</div
  24 + >
  25 + </div>
  26 + </Upload>
  27 + </template>
  28 + <template #customProv>
  29 + <BasicForm @register="registerCustomForm" />
  30 + </template>
  31 + </BasicForm>
  32 + </Card>
  33 + <Loading v-bind="compState" />
  34 + <a-button
  35 + @click="handleUpdateInfo"
  36 + size="large"
  37 + type="primary"
  38 + style="margin-top: 1rem; border-radius: 0.5rem"
  39 + >更新基本信息</a-button
  40 + >
  41 + </div>
  42 +</template>
  43 +
  44 +<script lang="ts">
  45 + import { defineComponent, onMounted, ref } from 'vue';
  46 + import { Card, Upload } from 'ant-design-vue';
  47 + import { BasicForm, useForm } from '/@/components/Form/index';
  48 + import { schemas, provSchemas } from '../config/enterPriseInfo.config';
  49 + import { getAreaList, getEnterPriseDetail, updateEnterPriseDetail } from '/@/api/oem/index';
  50 + import { Loading } from '/@/components/Loading';
  51 + import { useMessage } from '/@/hooks/web/useMessage';
  52 + import { useUserStore } from '/@/store/modules/user';
  53 + import { createLocalStorage } from '/@/utils/cache';
  54 + import { PlusOutlined } from '@ant-design/icons-vue';
  55 + import { qrcodeUpload } from '/@/api/oem/index';
  56 + import type { FileItem } from '/@/components/Upload/src/typing';
  57 + import type { CityItem, Code } from '../types';
  58 + export default defineComponent({
  59 + components: {
  60 + Card,
  61 + BasicForm,
  62 + Loading,
  63 + Upload,
  64 + PlusOutlined,
  65 + },
  66 + setup() {
  67 + const compState = ref({
  68 + absolute: false,
  69 + loading: false,
  70 + tip: '拼命加载中...',
  71 + });
  72 + const [registerForm, { getFieldsValue, setFieldsValue, validate }] = useForm({
  73 + labelWidth: 80,
  74 + schemas,
  75 + showResetButton: false,
  76 + showSubmitButton: false,
  77 + wrapperCol: {
  78 + span: 12,
  79 + },
  80 + });
  81 +
  82 + const [
  83 + registerCustomForm,
  84 + { getFieldsValue: getNameTown, updateSchema, setFieldsValue: setNameTown },
  85 + ] = useForm({
  86 + labelWidth: 80,
  87 + schemas: provSchemas,
  88 + showResetButton: false,
  89 + showSubmitButton: false,
  90 + compact: true,
  91 + actionColOptions: {
  92 + span: 0,
  93 + },
  94 + });
  95 +
  96 + const { createMessage } = useMessage();
  97 +
  98 + const qrcodePic = ref();
  99 + const customUploadqrcodePic = async ({ file }) => {
  100 + if (beforeUploadqrcodePic(file)) {
  101 + const formData = new FormData();
  102 + formData.append('file', file);
  103 + const response = await qrcodeUpload(formData);
  104 + if (response.fileStaticUri) {
  105 + qrcodePic.value = response.fileStaticUri;
  106 + }
  107 + }
  108 + };
  109 + const beforeUploadqrcodePic = (file: FileItem) => {
  110 + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
  111 + if (!isJpgOrPng) {
  112 + createMessage.error('只能上传图片文件!');
  113 + }
  114 + const isLt2M = (file.size as number) / 1024 / 1024 < 2;
  115 + if (!isLt2M) {
  116 + createMessage.error('图片大小不能超过2MB!');
  117 + }
  118 + return isJpgOrPng && isLt2M;
  119 + };
  120 + // 更新
  121 + const handleUpdateInfo = async () => {
  122 + try {
  123 + const fieldsValue = getFieldsValue();
  124 + const { nameTown } = getNameTown();
  125 + const newFieldValue: any = {
  126 + ...fieldsValue,
  127 + codeTown: nameTown,
  128 + qrCode: qrcodePic.value,
  129 + };
  130 + delete newFieldValue.nameProv;
  131 + delete newFieldValue.nameCity;
  132 + delete newFieldValue.nameCoun;
  133 + delete newFieldValue.nameTown;
  134 +
  135 + // 表单校验
  136 + await validate();
  137 + compState.value.loading = true;
  138 + await updateEnterPriseDetail(newFieldValue);
  139 + createMessage.success('更新信息成功');
  140 + setEnterPriseInfo(newFieldValue);
  141 + } finally {
  142 + compState.value.loading = false;
  143 + }
  144 + };
  145 +
  146 + const userStore = useUserStore();
  147 + const storage = createLocalStorage();
  148 +
  149 + // 设置企业信息
  150 + function setEnterPriseInfo(newFieldValue) {
  151 + // 保存store
  152 + userStore.setEnterPriseInfo(newFieldValue);
  153 + // 保存本地缓存
  154 + storage.set('enterpriseInfo', newFieldValue);
  155 + }
  156 +
  157 + // 地区显示回显和数据联动
  158 + async function updateCityData(
  159 + cities: CityItem[],
  160 + couns: CityItem[],
  161 + towns: CityItem[],
  162 + code: Code
  163 + ) {
  164 + // 加工后端返回字段
  165 +
  166 + cities.forEach((item) => {
  167 + item.label = item.name;
  168 + item.value = item.code;
  169 + });
  170 +
  171 + couns.forEach((item) => {
  172 + item.label = item.name;
  173 + item.value = item.code;
  174 + });
  175 + towns.forEach((item) => {
  176 + item.label = item.name;
  177 + item.value = item.code;
  178 + });
  179 + const { codeProv, codeCity, codeCoun, codeTown } = code;
  180 + updateSchema([
  181 + {
  182 + field: 'nameCity',
  183 + componentProps: ({ formModel }) => {
  184 + return {
  185 + options: cities,
  186 + async onChange(value) {
  187 + if (value === undefined) {
  188 + formModel.nameCoun = undefined; // reset city value
  189 + formModel.nameTown = undefined;
  190 + updateSchema([
  191 + {
  192 + field: 'nameCoun',
  193 + componentProps: {
  194 + options: [],
  195 + },
  196 + },
  197 + {
  198 + field: 'nameTown',
  199 + componentProps: {
  200 + options: [],
  201 + },
  202 + },
  203 + ]);
  204 + } else {
  205 + let couns: CityItem[] = await getAreaList({ parentId: value });
  206 + couns.forEach((item) => {
  207 + item.label = item.name;
  208 + item.value = item.code;
  209 + });
  210 + formModel.nameCoun = undefined; // reset city value
  211 + formModel.nameTown = undefined;
  212 + updateSchema({
  213 + field: 'nameCoun',
  214 + componentProps: {
  215 + // 请选择区
  216 + options: couns,
  217 + async onChange(value) {
  218 + if (value === undefined) {
  219 + formModel.nameTown = undefined;
  220 + } else {
  221 + let towns: CityItem[] = await getAreaList({ parentId: value });
  222 + towns.forEach((item) => {
  223 + item.label = item.name;
  224 + item.value = item.code;
  225 + });
  226 + formModel.nameTown = undefined;
  227 + updateSchema({
  228 + field: 'nameTown',
  229 + componentProps: {
  230 + placeholder: '城镇/街道',
  231 + options: towns,
  232 + },
  233 + });
  234 + }
  235 + },
  236 + },
  237 + });
  238 + }
  239 + },
  240 + };
  241 + },
  242 + },
  243 + {
  244 + field: 'nameCoun',
  245 + componentProps: {
  246 + options: couns,
  247 + async onChange(value) {
  248 + if (value === undefined) {
  249 + setNameTown({
  250 + nameTown: undefined,
  251 + });
  252 + updateSchema({
  253 + field: 'nameTown',
  254 + componentProps: {
  255 + placeholder: '城镇/街道',
  256 + options: [],
  257 + },
  258 + });
  259 + } else {
  260 + let towns = await getAreaList({ parentId: value });
  261 + towns.forEach((item) => {
  262 + item.label = item.name;
  263 + item.value = item.code;
  264 + });
  265 + setNameTown({
  266 + nameTown: undefined,
  267 + });
  268 + updateSchema({
  269 + field: 'nameTown',
  270 + componentProps: {
  271 + placeholder: '城镇/街道',
  272 + options: towns,
  273 + },
  274 + });
  275 + }
  276 + },
  277 + },
  278 + },
  279 + {
  280 + field: 'nameTown',
  281 + componentProps: {
  282 + options: towns,
  283 + },
  284 + },
  285 + ]);
  286 + setNameTown({
  287 + nameProv: codeProv,
  288 + nameCity: codeCity,
  289 + nameCoun: codeCoun,
  290 + nameTown: codeTown,
  291 + });
  292 + }
  293 +
  294 + onMounted(async () => {
  295 + const res = await getEnterPriseDetail();
  296 + if (res.sysTown) {
  297 + const { cities, couns, towns, codeCountry, codeProv, codeCity, codeCoun, codeTown } =
  298 + res.sysTown;
  299 + const code = {
  300 + codeCountry,
  301 + codeProv,
  302 + codeCity,
  303 + codeCoun,
  304 + codeTown,
  305 + };
  306 + updateCityData(cities, couns, towns, code);
  307 + setFieldsValue({ nameCountry: codeCountry });
  308 + }
  309 + setFieldsValue(res);
  310 + console.log(res);
  311 + qrcodePic.value = res.qrCode;
  312 + });
  313 +
  314 + return {
  315 + registerForm,
  316 + compState,
  317 + qrcodePic,
  318 + handleUpdateInfo,
  319 + customUploadqrcodePic,
  320 + beforeUploadqrcodePic,
  321 + registerCustomForm,
  322 + };
  323 + },
  324 + });
  325 +</script>
  1 +<template>
  2 + <div class="platform flex">
  3 + <Card class="tab-card" :bordered="false">
  4 + <Tabs v-model:activeKey="activeKey" tab-position="left">
  5 + <Tabs.TabPane key="企业信息" tab="企业信息" />
  6 + <Tabs.TabPane key="平台定制" tab="平台定制" />
  7 + <Tabs.TabPane key="APP定制" tab="APP定制" />
  8 + </Tabs>
  9 + </Card>
  10 +
  11 + <div style="width: 100%">
  12 + <Card class="card" :title="activeKey" :bordered="false" :bodyStyle="{ display: 'none' }" />
  13 + <EnterpriseInfo v-if="activeKey === '企业信息'" />
  14 + <CVIDraw v-else-if="activeKey === '平台定制'" />
  15 + <AppDraw v-else />
  16 + </div>
  17 + </div>
  18 +</template>
  19 +
  20 +<script lang="ts" setup>
  21 + import { Tabs, Card } from 'ant-design-vue';
  22 + import { ref } from 'vue';
  23 + import EnterpriseInfo from './cpns/EnterpriseInfo.vue';
  24 + import CVIDraw from './cpns/CVIDraw.vue';
  25 + import AppDraw from './cpns/AppDraw.vue';
  26 +
  27 + const activeKey = ref('企业信息');
  28 +</script>
  29 +
  30 +<style lang="less" scoped>
  31 + .title {
  32 + width: 97.4%;
  33 + height: 50px;
  34 + margin: 1rem;
  35 + line-height: 50px;
  36 + font-size: 18px;
  37 + padding-left: 10px;
  38 + background-color: #fff;
  39 + }
  40 + .tab-card {
  41 + margin: 1rem 0 1rem 1rem;
  42 + }
  43 + .card {
  44 + margin: 1rem;
  45 + }
  46 +</style>
  1 +export interface FileItem {
  2 + uid: string;
  3 + name?: string;
  4 + status?: string;
  5 + response?: string;
  6 + percent?: number;
  7 + url?: string;
  8 + preview?: string;
  9 + originFileObj?: any;
  10 +}
  11 +
  12 +export interface FileInfo {
  13 + file: FileItem;
  14 + fileList: FileItem[];
  15 +}
  16 +
  17 +export interface CityItem {
  18 + code: number;
  19 + level: string;
  20 + name: string;
  21 + parentId: number;
  22 + label?: string;
  23 + value?: number;
  24 +}
  25 +export interface Code {
  26 + codeCountry: number;
  27 + codeProv: number;
  28 + codeCity: number;
  29 + codeCoun: number;
  30 + codeTown: number;
  31 +}