Commit f10a58e9ad3c0bff576abe9a49ac941981111db1

Authored by xp.Huang
2 parents 3f7d4542 fe3c949f

Merge branch 'ww' into 'main'

feat: create data flow form add dataSource dataProducts dataDevices field

See merge request huang/yun-teng-iot-front!462
... ... @@ -7,6 +7,7 @@ import type {
7 7 } from './model/alarmContactModal';
8 8 import { getPageData } from '../../base';
9 9 import { DeviceModel, DeviceQueryParam } from '../../device/model/deviceModel';
  10 +import { omit } from 'lodash-es';
10 11 enum API {
11 12 alarmContact = '/alarm_contact',
12 13 updateAlarmContact = '/alarm_contact/update',
... ... @@ -50,8 +51,10 @@ export const saveOrEditAlarmContact = (params: ContactInfo, isUpdate: boolean) =
50 51
51 52 // 查询设备分页数据
52 53 export const devicePage = (params: DeviceQueryParam) => {
53   - return defHttp.get<DeviceModel>({
54   - url: API.devicePage,
55   - params,
  54 + const { page, pageSize } = params;
  55 + const otherParams = omit(params, ['page', 'pageSize']);
  56 + return defHttp.post<DeviceModel>({
  57 + url: `${API.devicePage}?page=${page}&pageSize=${pageSize}`,
  58 + params: otherParams,
56 59 });
57 60 };
... ...
1 1 import { StructJSON } from './modelOfMatterModel';
2 2 import { BasicPageParams } from '/@/api/model/baseModel';
3 3 import { AlarmStatus } from '/@/views/alarm/log/config/detail.config';
  4 +import { DeviceStatusEnum } from '/@/views/rule/dataFlow/cpns/config';
4 5 export enum DeviceState {
5 6 INACTIVE = 'INACTIVE',
6 7 ONLINE = 'ONLINE',
... ... @@ -12,7 +13,18 @@ export enum DeviceTypeEnum {
12 13 SENSOR = 'SENSOR',
13 14 }
14 15 export type DeviceProfileQueryParam = BasicPageParams & DeviceProfileParam & DeviceId;
15   -export type DeviceQueryParam = BasicPageParams & DeviceParam;
  16 +export type DeviceQueryParam = BasicPageParams & {
  17 + deviceProfileIds?: string[];
  18 + convertConfigId?: string;
  19 + deviceType?: DeviceTypeEnum;
  20 + deviceState?: DeviceStatusEnum;
  21 + organizationId?: string;
  22 + alarmStatus?: string;
  23 + orderFiled?: string;
  24 + orderType?: string;
  25 + selected?: boolean;
  26 + name?: string;
  27 +};
16 28 export type DeviceParam = {
17 29 name?: string;
18 30 deviceProfileId?: string;
... ... @@ -163,6 +175,7 @@ export interface DeviceRecord {
163 175 type: string;
164 176 default: boolean;
165 177 defaultRuleChainId: string;
  178 + profileId: string;
166 179 }
167 180
168 181 export interface DeviceModelOfMatterAttrs {
... ...
... ... @@ -38,6 +38,8 @@ import ApiSearchSelect from './components/ApiSearchSelect.vue';
38 38 import CustomMinMaxInput from './externalCompns/components/CustomMinMaxInput.vue';
39 39 import StructForm from './externalCompns/components/StructForm/StructForm.vue';
40 40 import ApiSelectScrollLoad from './components/ApiSelectScrollLoad.vue';
  41 +import TransferModal from './components/TransferModal.vue';
  42 +import TransferTableModal from './components/TransferTableModal.vue';
41 43
42 44 const componentMap = new Map<ComponentType, Component>();
43 45
... ... @@ -83,6 +85,8 @@ componentMap.set('ApiSearchSelect', ApiSearchSelect);
83 85 componentMap.set('CustomMinMaxInput', CustomMinMaxInput);
84 86 componentMap.set('StructForm', StructForm);
85 87 componentMap.set('ApiSelectScrollLoad', ApiSelectScrollLoad);
  88 +componentMap.set('TransferModal', TransferModal);
  89 +componentMap.set('TransferTableModal', TransferTableModal);
86 90
87 91 export function add(compName: ComponentType, component: Component) {
88 92 componentMap.set(compName, component);
... ...
  1 +<script lang="ts" setup>
  2 + import { Button, Transfer, Tag } from 'ant-design-vue';
  3 + import { cloneDeep, get } from 'lodash-es';
  4 + import { computed, CSSProperties, ExtractPropTypes, onMounted, ref, unref, watch } from 'vue';
  5 + import { BasicModal, useModal } from '/@/components/Modal';
  6 + import { isFunction } from '/@/utils/is';
  7 +
  8 + type TransferType = InstanceType<typeof Transfer>;
  9 +
  10 + interface Options {
  11 + title?: string;
  12 + key?: string;
  13 + disabled?: boolean;
  14 + description?: string;
  15 + }
  16 +
  17 + const emit = defineEmits(['change', 'update:value']);
  18 +
  19 + const props = withDefaults(
  20 + defineProps<{
  21 + options?: Options[];
  22 + maxTagLength?: number;
  23 + value?: string[];
  24 + api?: Fn<Recordable, Promise<Options[]>>;
  25 + labelField?: string;
  26 + valueField?: string;
  27 + resultField?: string;
  28 + params?: Recordable;
  29 + buttonName?: string;
  30 + modalProps?: ExtractPropTypes<InstanceType<typeof BasicModal>['$props']>;
  31 + transferProps?: ExtractPropTypes<TransferType['$props']>;
  32 + buttonProps?: ExtractPropTypes<InstanceType<typeof Button>['$props']>;
  33 + }>(),
  34 + {
  35 + labelField: 'label',
  36 + valueField: 'value',
  37 + buttonName: '选择产品',
  38 + maxTagLength: 2,
  39 + }
  40 + );
  41 +
  42 + const [register, { openModal }] = useModal();
  43 +
  44 + const options = ref<Options[]>([]);
  45 +
  46 + const loading = ref(false);
  47 +
  48 + const targetOptions = computed(() => {
  49 + const { valueField } = props;
  50 + return unref(getOptions).filter((item) => unref(targetKeys).includes(item[valueField]));
  51 + });
  52 +
  53 + const getShowTagOptions = computed(() => {
  54 + const { maxTagLength } = props;
  55 + return unref(targetOptions).slice(0, maxTagLength);
  56 + });
  57 +
  58 + const getSurplusOptionsLength = computed(() => {
  59 + const { maxTagLength } = props;
  60 + const surplusValue = unref(targetKeys).length - maxTagLength;
  61 + return surplusValue < 0 ? 0 : surplusValue;
  62 + });
  63 +
  64 + const count = computed(() => {
  65 + return unref(targetKeys).length;
  66 + });
  67 +
  68 + const targetKeys = ref<string[]>(props.value || []);
  69 +
  70 + const getOptions = computed<Recordable[]>(() => {
  71 + const { labelField, valueField } = props;
  72 + return unref(options).map((item) => ({
  73 + ...item,
  74 + title: item[labelField],
  75 + key: item[valueField],
  76 + }));
  77 + });
  78 +
  79 + const getBindProps = computed(() => {
  80 + const { transferProps = {} } = props;
  81 + return {
  82 + render: (item: Options) => item.title,
  83 + listStyle: { height: '300px' } as CSSProperties,
  84 + ...transferProps,
  85 + targetKeys: unref(targetKeys),
  86 + dataSource: unref(getOptions),
  87 + onChange: handleChange,
  88 + } as ExtractPropTypes<TransferType['$props']>;
  89 + });
  90 +
  91 + const getBindModalProps = computed(() => {
  92 + const { modalProps } = props;
  93 + return {
  94 + ...modalProps,
  95 + title: '选择产品',
  96 + showOkBtn: false,
  97 + };
  98 + });
  99 +
  100 + const getBindButtonProps = computed(() => {
  101 + const { buttonProps = {} } = props;
  102 + return {
  103 + ...buttonProps,
  104 + type: 'link',
  105 + onClick: handleOpenModal,
  106 + } as ExtractPropTypes<InstanceType<typeof Button>['$props']>;
  107 + });
  108 +
  109 + const handleChange = (_targetKeys: string[], direction: 'left' | 'right', moveKeys: string[]) => {
  110 + targetKeys.value = _targetKeys;
  111 + emit('update:value', _targetKeys);
  112 + const _targetOptions = cloneDeep(unref(targetOptions));
  113 + emit('change', _targetKeys, _targetOptions, direction, moveKeys);
  114 + };
  115 +
  116 + const handleGetOptions = async () => {
  117 + try {
  118 + loading.value = true;
  119 + const { api, params, resultField, options: propsOptions } = props;
  120 + if (api && isFunction(api)) {
  121 + const res = await api(params!);
  122 + if (Array.isArray(res)) {
  123 + options.value = res;
  124 + return;
  125 + }
  126 + if (resultField) {
  127 + options.value = get(res, resultField) || [];
  128 + }
  129 + } else {
  130 + if (propsOptions && Array.isArray(propsOptions)) {
  131 + options.value = propsOptions;
  132 + }
  133 + }
  134 + } catch (error) {
  135 + throw error;
  136 + } finally {
  137 + loading.value = false;
  138 + }
  139 + };
  140 +
  141 + watch(
  142 + () => props.value,
  143 + () => {
  144 + targetKeys.value = props.value || [];
  145 + }
  146 + );
  147 +
  148 + const handleOpenModal = () => {
  149 + openModal(true);
  150 + };
  151 +
  152 + onMounted(() => {
  153 + handleGetOptions();
  154 + });
  155 +</script>
  156 +
  157 +<template>
  158 + <div>
  159 + <BasicModal v-bind="getBindModalProps" @register="register">
  160 + <section class="flex justify-center items-center">
  161 + <Transfer v-bind="getBindProps" />
  162 + </section>
  163 + </BasicModal>
  164 + <Button v-bind="getBindButtonProps" class="!flex !justify-center !items-center min-h-8">
  165 + <span v-if="!count">{{ $props.buttonName }}</span>
  166 + <div v-if="!!count">
  167 + <Tag
  168 + class="!px-2 !py-1 !bg-gray-50 !border-gray-100"
  169 + v-for="item in getShowTagOptions"
  170 + :key="item.key"
  171 + >
  172 + <span>
  173 + {{ item.title }}
  174 + </span>
  175 + </Tag>
  176 + <Tag class="!px-2 !py-1 !bg-gray-50 !border-gray-100" v-if="getSurplusOptionsLength">
  177 + <span> +{{ getSurplusOptionsLength }}... </span>
  178 + </Tag>
  179 + </div>
  180 + </Button>
  181 + </div>
  182 +</template>
... ...
  1 +<script lang="ts" setup>
  2 + import { Button, Tabs, Badge, ButtonProps, Tag } from 'ant-design-vue';
  3 + import { get, isFunction, set, uniqBy } from 'lodash-es';
  4 + import { ExtractPropTypes, computed, unref, ref, nextTick, onMounted, watch } from 'vue';
  5 + import { DynamicProps } from '/#/utils';
  6 + import { BasicModal, useModal } from '/@/components/Modal';
  7 + import { BasicTable, BasicTableProps, TableRowSelection, useTable } from '/@/components/Table';
  8 + import { FETCH_SETTING } from '/@/components/Table/src/const';
  9 + import { useDesign } from '/@/hooks/web/useDesign';
  10 +
  11 + interface Options extends Recordable {
  12 + primaryKey?: string;
  13 + disabled?: boolean;
  14 + }
  15 +
  16 + enum Active {
  17 + PENDING = 'pending',
  18 + SELECTED = 'selected',
  19 + }
  20 +
  21 + interface ActionType {
  22 + setSelectedOptions: (options: Recordable[]) => void;
  23 + }
  24 +
  25 + const emit = defineEmits(['change', 'update:value']);
  26 +
  27 + const props = withDefaults(
  28 + defineProps<{
  29 + value?: string[];
  30 + labelField?: string;
  31 + valueField?: string;
  32 + primaryKey?: string;
  33 + params?: Recordable;
  34 + buttonName?: string;
  35 + pendingTableProps?: BasicTableProps;
  36 + selectedTableProps?: BasicTableProps;
  37 + maxTagLength?: number;
  38 + modalProps?: ExtractPropTypes<InstanceType<typeof BasicModal>['$props']>;
  39 + buttonProps?: ExtractPropTypes<InstanceType<typeof Button>['$props']>;
  40 + initSelectedOptions?: (actionType: ActionType) => Promise<Recordable[]>;
  41 + transformValue?: (selectedRowKeys: string[], selectedRows: Options[]) => any[];
  42 + onValueChange?: (selectedRowkeys: string[]) => any[];
  43 + onRemoveAfter?: (actionType: ActionType) => Promise<any>;
  44 + onSelectedAfter?: (actionType: ActionType) => Promise<any>;
  45 + }>(),
  46 + {
  47 + buttonName: '选择设备',
  48 + primaryKey: 'id',
  49 + maxTagLength: 2,
  50 + labelField: 'label',
  51 + valueField: 'value',
  52 + }
  53 + );
  54 +
  55 + const { prefixCls } = useDesign('transfer-table-modal');
  56 +
  57 + const activeKey = ref<Active>(Active.PENDING);
  58 +
  59 + const selectedRows = ref<Options[]>([]);
  60 +
  61 + const selectedRowKeys = ref<string[]>(props.value || []);
  62 +
  63 + const pendingOptions = ref<Options[]>([]);
  64 +
  65 + const pendingConfirmQueue = ref<Options[]>([]);
  66 +
  67 + const selectedTotal = ref(0);
  68 +
  69 + const pendingTotal = ref(0);
  70 +
  71 + const getFetchSetting = computed(() => {
  72 + const { pendingTableProps } = props;
  73 + return pendingTableProps?.fetchSetting || FETCH_SETTING;
  74 + });
  75 +
  76 + const getPendingRowSelection = computed<TableRowSelection>(() => {
  77 + const rowKeys = unref(selectedRowKeys);
  78 + return {
  79 + type: 'checkbox',
  80 + getCheckboxProps: (record: Recordable) => {
  81 + const { primaryKey } = props;
  82 + return {
  83 + ...record,
  84 + disabled: rowKeys.includes(record[primaryKey]),
  85 + };
  86 + },
  87 + onSelect: (_record: Recordable, _selected: boolean, selectedRows: Object[]) => {
  88 + pendingConfirmQueue.value = selectedRows;
  89 + },
  90 + onSelectAll: (_selected: boolean, selectedRows: Recordable[]) => {
  91 + pendingConfirmQueue.value = selectedRows;
  92 + },
  93 + };
  94 + });
  95 +
  96 + const getPendingTableBindProps = computed<Partial<DynamicProps<BasicTableProps>>>(() => {
  97 + const { pendingTableProps, primaryKey } = props;
  98 + return {
  99 + ...pendingTableProps,
  100 + rowKey: primaryKey,
  101 + api: handlePendingApiIntercept,
  102 + clickToRowSelect: false,
  103 + rowSelection: getPendingRowSelection,
  104 + };
  105 + });
  106 +
  107 + const getSelectedTableBindProps = computed<Partial<DynamicProps<BasicTableProps>>>(() => {
  108 + const { selectedTableProps, primaryKey } = props;
  109 + return {
  110 + ...selectedTableProps,
  111 + dataSource: selectedRows,
  112 + clickToRowSelect: false,
  113 + rowKey: primaryKey,
  114 + api: selectedTableProps!.api ? handleSelectedApiIntercept : undefined,
  115 + rowSelection: {
  116 + type: 'checkbox',
  117 + onSelect: (_record: Recordable, _selected: boolean, selectedRows: Object[]) => {
  118 + pendingConfirmQueue.value = selectedRows;
  119 + },
  120 + onSelectAll: (_selected: boolean, selectedRows: Recordable[]) => {
  121 + pendingConfirmQueue.value = selectedRows;
  122 + },
  123 + },
  124 + };
  125 + });
  126 +
  127 + const getModalBindProps = computed(() => {
  128 + const { modalProps = {} } = props;
  129 + return {
  130 + width: '60%',
  131 + title: '穿梭表格',
  132 + wrapClassName: prefixCls,
  133 + ...modalProps,
  134 + showOkBtn: false,
  135 + };
  136 + });
  137 +
  138 + const getBindButtonProps = computed<ButtonProps>(() => {
  139 + const { buttonProps = {} } = props;
  140 + return {
  141 + type: 'link',
  142 + ...buttonProps,
  143 + };
  144 + });
  145 +
  146 + const getShowTagOptions = computed(() => {
  147 + const { maxTagLength } = props;
  148 + return unref(selectedRows).slice(0, maxTagLength);
  149 + });
  150 +
  151 + const getSurplusOptionsLength = computed(() => {
  152 + const { maxTagLength } = props;
  153 + const surplusValue = unref(selectedRows).length - maxTagLength;
  154 + return surplusValue < 0 ? 0 : surplusValue;
  155 + });
  156 +
  157 + const [registerModal, { openModal }] = useModal();
  158 +
  159 + const [
  160 + regsterPendingTable,
  161 + {
  162 + getSelectRows: getPendingSelectRows,
  163 + getSelectRowKeys: getPendingSelectRowKeys,
  164 + reload: reloadPending,
  165 + clearSelectedRowKeys: clearPendingSelectedRowKeys,
  166 + },
  167 + ] = useTable(unref(getPendingTableBindProps));
  168 +
  169 + const [
  170 + registerSelectedTable,
  171 + { getSelectRowKeys, setProps, clearSelectedRowKeys, reload: reloadSelected },
  172 + ] = useTable(unref(getSelectedTableBindProps));
  173 +
  174 + async function handlePendingApiIntercept(params?: Recordable) {
  175 + try {
  176 + const { api } = props.pendingTableProps || {};
  177 + if (api && isFunction(api)) {
  178 + let options = await api(params);
  179 + pendingOptions.value = options;
  180 + const { totalField, listField } = unref(getFetchSetting);
  181 + const total = get(options, totalField!);
  182 + if (unref(selectedTotal) + unref(pendingTotal) !== total) {
  183 + pendingTotal.value = total;
  184 + }
  185 + let list: Recordable[] = get(options, listField!);
  186 + list = getSelectedRows(list);
  187 + options = set(options, listField!, list);
  188 + return options;
  189 + }
  190 + } catch (error) {
  191 + console.error(error);
  192 + return [];
  193 + }
  194 + return [];
  195 + }
  196 +
  197 + async function handleSelectedApiIntercept(params?: Recordable) {
  198 + try {
  199 + const { api } = props.selectedTableProps || {};
  200 + if (api && isFunction(api)) {
  201 + let options = await api(params);
  202 + pendingOptions.value = options;
  203 + const { totalField, listField } = unref(getFetchSetting);
  204 + selectedTotal.value = get(options, totalField!);
  205 + let list: Recordable[] = get(options, listField!);
  206 + list = getSelectedRows(list);
  207 + options = set(options, listField!, list);
  208 + return options;
  209 + }
  210 + } catch (error) {
  211 + console.error(error);
  212 + return [];
  213 + }
  214 + return [];
  215 + }
  216 +
  217 + const handleOpenModal = async () => {
  218 + openModal(true);
  219 + await nextTick();
  220 + if (props.value && !props.value.length) {
  221 + activeKey.value = Active.PENDING;
  222 + reloadPending();
  223 + }
  224 + };
  225 +
  226 + const handleTriggerEmit = (selectedRowKeys: string[], selectedRows: Options[]) => {
  227 + const { transformValue } = props;
  228 + let value = selectedRowKeys;
  229 + if (transformValue && isFunction(transformValue)) {
  230 + value = transformValue(selectedRowKeys, selectedRows);
  231 + }
  232 + emit('change', unref(selectedRowKeys), unref(selectedRows));
  233 + emit('update:value', unref(value));
  234 + };
  235 +
  236 + const handleSelected = async () => {
  237 + const { onSelectedAfter } = props;
  238 + const currentPageSelectRows = getPendingSelectRows();
  239 + const currentPageSelectRowKeys = getPendingSelectRowKeys();
  240 + const { primaryKey } = props;
  241 + selectedRows.value = uniqBy([...unref(selectedRows), ...currentPageSelectRows], primaryKey);
  242 + selectedRowKeys.value = [...new Set([...unref(selectedRowKeys), ...currentPageSelectRowKeys])];
  243 + pendingConfirmQueue.value = [];
  244 + // selectedTotal.value = unref(selectedRowKeys).length;
  245 + pendingTotal.value = unref(pendingTotal) - currentPageSelectRows.length;
  246 + selectedTotal.value = unref(selectedTotal) + currentPageSelectRows.length;
  247 + console.log(unref(pendingTotal));
  248 +
  249 + clearPendingSelectedRowKeys();
  250 + handleTriggerEmit(unref(selectedRowKeys), unref(selectedRows));
  251 +
  252 + if (onSelectedAfter && isFunction(onSelectedAfter)) {
  253 + await onSelectedAfter(actionType);
  254 + }
  255 + reloadPending();
  256 + };
  257 +
  258 + const handleRemoveSelected = async () => {
  259 + const { onRemoveAfter } = props;
  260 + const removeRowKeys = getSelectRowKeys();
  261 + selectedRowKeys.value = unref(selectedRowKeys).filter((key) => !removeRowKeys.includes(key));
  262 + selectedRows.value = unref(selectedRows).filter((item) => {
  263 + const { primaryKey } = props;
  264 + return unref(selectedRowKeys).includes(item[primaryKey]);
  265 + });
  266 + pendingTotal.value = unref(pendingTotal) + removeRowKeys.length;
  267 + selectedTotal.value = unref(selectedTotal) - removeRowKeys.length;
  268 +
  269 + clearSelectedRowKeys();
  270 + pendingConfirmQueue.value = [];
  271 + setProps({ dataSource: unref(selectedRows) });
  272 + handleTriggerEmit(unref(selectedRowKeys), unref(selectedRows));
  273 +
  274 + if (onRemoveAfter && isFunction(onRemoveAfter)) {
  275 + await onRemoveAfter(actionType);
  276 + }
  277 + };
  278 +
  279 + const actionType = {
  280 + setSelectedOptions,
  281 + setSelectedTotal,
  282 + reloadPending,
  283 + reloadPending,
  284 + reloadSelected,
  285 + };
  286 +
  287 + const getSelectedRows = (options: Recordable[]) => {
  288 + const { labelField, valueField } = props;
  289 + return options.map((item) => ({ ...item, label: item[labelField], value: item[valueField] }));
  290 + };
  291 +
  292 + const getSelectedKeys = (options: Recordable[]) => {
  293 + const { primaryKey } = props;
  294 + return options.map((item) => item[primaryKey]);
  295 + };
  296 +
  297 + function setSelectedOptions(options: Recordable[]) {
  298 + selectedRows.value = getSelectedRows(options);
  299 + selectedRowKeys.value = getSelectedKeys(options);
  300 + }
  301 +
  302 + function setSelectedTotal(number: number) {
  303 + selectedTotal.value = number;
  304 + }
  305 +
  306 + const handleCheckoutPanel = async (keys: Active) => {
  307 + await nextTick();
  308 + if (keys === Active.PENDING) {
  309 + reloadPending();
  310 + } else {
  311 + setProps({
  312 + dataSource: unref(selectedRows),
  313 + });
  314 + }
  315 + };
  316 +
  317 + watch(
  318 + () => props.value,
  319 + () => {
  320 + if (props.value && !props.value.length) {
  321 + selectedRowKeys.value = [];
  322 + selectedRows.value = [];
  323 + }
  324 + }
  325 + );
  326 +
  327 + onMounted(async () => {
  328 + const { initSelectedOptions } = props;
  329 + if (initSelectedOptions && isFunction(initSelectedOptions)) {
  330 + const options = await initSelectedOptions(actionType);
  331 + setSelectedOptions(options);
  332 + }
  333 + });
  334 +</script>
  335 +
  336 +<template>
  337 + <section>
  338 + <BasicModal @register="registerModal" v-bind="getModalBindProps">
  339 + <section class="bg-gray-100">
  340 + <Tabs v-model:active-key="activeKey" type="card" @change="handleCheckoutPanel">
  341 + <Tabs.TabPane :key="Active.PENDING">
  342 + <template #tab>
  343 + <div class="flex items-center justify-center">
  344 + <span>待选设备</span>
  345 + <Badge show-zero :count="pendingTotal" />
  346 + </div>
  347 + </template>
  348 + <BasicTable @register="regsterPendingTable">
  349 + <template #toolbar>
  350 + <section class="flex w-full justify-end items-center">
  351 + <!-- <Button type="primary">全选</Button> -->
  352 + <div class="text-blue-400">
  353 + <span class="mr-2">选择设备:</span>
  354 + <span>{{ pendingConfirmQueue.length }}</span>
  355 + </div>
  356 + </section>
  357 + </template>
  358 + </BasicTable>
  359 + <section class="flex justify-end px-4 pb-4">
  360 + <Button
  361 + type="primary"
  362 + @click="handleSelected"
  363 + :disabled="!pendingConfirmQueue.length"
  364 + >
  365 + <span>确定已选</span>
  366 + </Button>
  367 + </section>
  368 + </Tabs.TabPane>
  369 + <Tabs.TabPane :key="Active.SELECTED">
  370 + <template #tab>
  371 + <div class="flex items-center justify-center">
  372 + <span>已选设备</span>
  373 + <Badge show-zero :count="selectedTotal" />
  374 + </div>
  375 + </template>
  376 + <BasicTable @register="registerSelectedTable">
  377 + <template #toolbar>
  378 + <section class="flex w-full justify-end items-center">
  379 + <!-- <Button type="primary">全选</Button> -->
  380 + <div class="text-blue-400">
  381 + <span class="mr-2">选择设备:</span>
  382 + <span>{{ pendingConfirmQueue.length }}</span>
  383 + </div>
  384 + </section>
  385 + </template>
  386 + </BasicTable>
  387 + <section class="flex justify-end px-4 pb-4">
  388 + <Button
  389 + type="primary"
  390 + :disabled="!pendingConfirmQueue.length"
  391 + @click="handleRemoveSelected"
  392 + >
  393 + <span>移除已选</span>
  394 + </Button>
  395 + </section>
  396 + </Tabs.TabPane>
  397 + </Tabs>
  398 + </section>
  399 + </BasicModal>
  400 + <Button @click="handleOpenModal" v-bind="getBindButtonProps">
  401 + <span v-if="!selectedRowKeys.length">选择设备</span>
  402 + <div v-if="selectedRowKeys.length">
  403 + <Tag
  404 + class="!px-2 !py-1 !bg-gray-50 !border-gray-100"
  405 + v-for="item in getShowTagOptions"
  406 + :key="item.value"
  407 + >
  408 + <span>
  409 + {{ item.label }}
  410 + </span>
  411 + </Tag>
  412 + <Tag class="!px-2 !py-1 !bg-gray-50 !border-gray-100" v-if="getSurplusOptionsLength">
  413 + <span> +{{ getSurplusOptionsLength }}... </span>
  414 + </Tag>
  415 + </div>
  416 + </Button>
  417 + </section>
  418 +</template>
  419 +
  420 +<style lang="less">
  421 + @prefix-cls: ~'@{namespace}-transfer-table-modal';
  422 +
  423 + .@{prefix-cls} {
  424 + .vben-basic-table {
  425 + padding-top: 0;
  426 + }
  427 +
  428 + .vben-basic-form > .ant-row {
  429 + width: 100%;
  430 + }
  431 +
  432 + .ant-tabs-top-bar {
  433 + background-color: #fff;
  434 + }
  435 + }
  436 +</style>
... ...
... ... @@ -119,4 +119,6 @@ export type ComponentType =
119 119 | 'ApiUpload'
120 120 | 'ApiSearchSelect'
121 121 | 'StructForm'
122   - | 'ApiSelectScrollLoad';
  122 + | 'ApiSelectScrollLoad'
  123 + | 'TransferModal'
  124 + | 'TransferTableModal';
... ...
... ... @@ -8,6 +8,7 @@
8 8 :title="getTitle"
9 9 width="1000px"
10 10 @cancel="handleCancel"
  11 + destroy-on-close
11 12 >
12 13 <div class="step-form-form">
13 14 <a-steps :current="current">
... ... @@ -17,14 +18,19 @@
17 18 </div>
18 19 <div>
19 20 <div v-show="current === 0">
20   - <TransferConfigMode ref="refTransferConfigMode" @next="handleNext"
21   - /></div>
  21 + <TransferConfigMode
  22 + :save-content="handleSubmit"
  23 + ref="refTransferConfigMode"
  24 + @next="handleNext"
  25 + />
  26 + </div>
22 27 <div v-show="current === 1">
23 28 <TransferConfigParams
24 29 ref="refTransferConfigParams"
25 30 :getModeSelect="getModeSelectVal"
26 31 @prevSon="handlePrev"
27   - /></div>
  32 + />
  33 + </div>
28 34 </div>
29 35 <div style="float: right" v-if="isViewStatus">
30 36 <Button type="primary" @click="handleSubmit" class="mr-2">确认</Button>
... ... @@ -34,7 +40,7 @@
34 40 </div>
35 41 </template>
36 42 <script lang="ts">
37   - import { defineComponent, reactive, ref, unref, getCurrentInstance, nextTick } from 'vue';
  43 + import { defineComponent, reactive, ref, unref, getCurrentInstance } from 'vue';
38 44 import { BasicModal, useModalInner } from '/@/components/Modal';
39 45 import { Steps } from 'ant-design-vue';
40 46 import TransferConfigMode from './cpns/transferConfigMode.vue';
... ... @@ -93,6 +99,8 @@
93 99 configuration: {},
94 100 name: '',
95 101 remark: '',
  102 + datasourceType: '',
  103 + datasourceContent: {},
96 104 });
97 105 const editTypeFunc = (d) => {
98 106 editType.type = d.type;
... ... @@ -111,6 +119,10 @@
111 119 editNextType.configuration = data.record;
112 120 editNextType.name = data.record.name;
113 121 editNextType.remark = data.record.remark;
  122 + editNextType.datasourceType = data.record.datasourceType;
  123 + editNextType.datasourceContent = data.record.datasourceContent;
  124 + editNextType.convertConfigId = data.record.id;
  125 +
114 126 proxy.$refs.refTransferConfigMode.setStepOneFieldsValueFunc(editNextType);
115 127 }
116 128 if (!unref(isUpdate)) {
... ... @@ -146,16 +158,12 @@
146 158 }
147 159 });
148 160 const handleCancel = () => {
149   - nextTick(() => {
150   - defineClearFunc();
151   - closeModal();
152   - });
  161 + defineClearFunc();
  162 + closeModal();
153 163 };
154 164 const defineClearFunc = () => {
155   - nextTick(() => {
156   - proxy.$refs.refTransferConfigMode?.customResetStepOneFunc();
157   - proxy.$refs.refTransferConfigParams?.clearSonValueDataFunc();
158   - });
  165 + proxy.$refs.refTransferConfigMode?.customResetStepOneFunc();
  166 + proxy.$refs.refTransferConfigParams?.clearSonValueDataFunc();
159 167 };
160 168 const handleNext = (args) => {
161 169 current.value++;
... ... @@ -211,33 +219,25 @@
211 219 }
212 220 getModeSonFormValue.value = await proxy.$refs.refTransferConfigMode.getSonValueFunc();
213 221 getSonFormValue.value = await proxy.$refs.refTransferConfigParams.getSonValueDataFunc();
  222 +
214 223 if (getModeSonFormValue.value?.type == 'org.thingsboard.rule.engine.kafka.TbKafkaNode') {
215 224 getTypeObj.type = 'org.thingsboard.rule.engine.kafka.TbKafkaNode';
216   - getTypeObj.remark = getModeSonFormValue.value.remark;
217   - getNameObj.name = getSonFormValue.value?.configuration?.name;
218   - commonFunc();
219 225 } else if (
220 226 getModeSonFormValue.value?.type == 'org.thingsboard.rule.engine.mqtt.TbMqttNode'
221 227 ) {
222 228 getTypeObj.type = 'org.thingsboard.rule.engine.mqtt.TbMqttNode';
223   - getTypeObj.remark = getModeSonFormValue.value.remark;
224   - getNameObj.name = getSonFormValue.value?.configuration?.name;
225   - commonFunc();
226 229 } else if (
227 230 getModeSonFormValue.value?.type == 'org.thingsboard.rule.engine.rabbitmq.TbRabbitMqNode'
228 231 ) {
229 232 getTypeObj.type = 'org.thingsboard.rule.engine.rabbitmq.TbRabbitMqNode';
230   - getTypeObj.remark = getModeSonFormValue.value.remark;
231   - getNameObj.name = getSonFormValue.value?.configuration?.name;
232   - commonFunc();
233 233 } else if (
234 234 getModeSonFormValue.value?.type == 'org.thingsboard.rule.engine.rest.TbRestApiCallNode'
235 235 ) {
236 236 getTypeObj.type = 'org.thingsboard.rule.engine.rest.TbRestApiCallNode';
237   - getTypeObj.remark = getModeSonFormValue.value.remark;
238   - getNameObj.name = getSonFormValue.value?.configuration?.name;
239   - commonFunc();
240 237 }
  238 + getTypeObj.remark = getModeSonFormValue.value.remark;
  239 + getNameObj.name = getSonFormValue.value?.configuration?.name;
  240 + commonFunc();
241 241 const id: any = {
242 242 id: unref(isUpdate) ? editPostId.value : '',
243 243 };
... ... @@ -247,15 +247,19 @@
247 247 getSonFormValue.value,
248 248 getNameObj,
249 249 id,
250   - additionalInfoV.additionalInfo.description ? additionalInfoV : {}
  250 + additionalInfoV.additionalInfo.description ? additionalInfoV : {},
  251 + {
  252 + datasourceType: getModeSonFormValue.value.datasourceType,
  253 + datasourceContent: getModeSonFormValue.value.datasourceContent,
  254 + }
251 255 );
252 256 if (!unref(isUpdate)) {
253 257 delete allPostForm.id;
254 258 }
255 259 };
256   - const handleSubmit = async () => {
  260 + const handleSubmit = async (closeModalAfterSuccess = true) => {
257 261 try {
258   - setModalProps({ confirmLoading: true });
  262 + closeModalAfterSuccess && setModalProps({ confirmLoading: true });
259 263 if (!unref(isUpdate)) {
260 264 await addOrEditFunc();
261 265 if (allPostForm.name == undefined) {
... ... @@ -274,12 +278,12 @@
274 278 }
275 279 const res = await postAddConvertApi(allPostForm);
276 280 if (res) {
277   - closeModal();
278   - createMessage.success('数据流转新增成功');
  281 + closeModalAfterSuccess && closeModal();
  282 + closeModalAfterSuccess && createMessage.success('数据流转新增成功');
279 283 setTimeout(() => {
280 284 emit('success');
281 285 }, 500);
282   - defineClearFunc();
  286 + closeModalAfterSuccess && defineClearFunc();
283 287 }
284 288 } else {
285 289 await addOrEditFunc();
... ... @@ -296,15 +300,18 @@
296 300 return createMessage.error('请填写属性');
297 301 }
298 302 }
299   - Object.assign(noEditObj, getTypeObj);
  303 + Object.assign(noEditObj, getTypeObj, {
  304 + datasourceType: allPostForm.datasourceType,
  305 + datasourceContent: allPostForm.datasourceContent,
  306 + });
300 307 const res = await postAddConvertApi(isEdit.value ? noEditObj : allPostForm);
301 308 if (res) {
302   - closeModal();
303   - createMessage.success('数据流转编辑成功');
  309 + closeModalAfterSuccess && closeModal();
  310 + closeModalAfterSuccess && createMessage.success('数据流转编辑成功');
304 311 setTimeout(() => {
305 312 emit('success');
306 313 }, 500);
307   - defineClearFunc();
  314 + closeModalAfterSuccess && defineClearFunc();
308 315 }
309 316 }
310 317 } catch {
... ...
1 1 import { FormSchema } from '/@/components/Form';
2 2 import { findDictItemByCode } from '/@/api/system/dict';
3   -import { ref } from 'vue';
  3 +import { h, ref } from 'vue';
4 4 import { isExistDataManagerNameApi } from '/@/api/datamanager/dataManagerApi';
  5 +import { getDeviceProfile } from '/@/api/alarm/position';
  6 +import { BasicColumn, BasicTableProps } from '/@/components/Table';
  7 +import { devicePage } from '/@/api/device/deviceManager';
  8 +import { Tag } from 'ant-design-vue';
  9 +import { DeviceRecord } from '/@/api/device/model/deviceModel';
  10 +import { FETCH_SETTING } from '/@/components/Table/src/const';
5 11
6 12 const typeValue = ref('');
7 13 export enum CredentialsEnum {
... ... @@ -16,41 +22,306 @@ export const isPem = (type: string) => {
16 22 return type === CredentialsEnum.IS_PEM;
17 23 };
18 24
19   -export const modeForm: FormSchema[] = [
  25 +export enum DataSourceType {
  26 + ALL = 'ALL',
  27 + PRODUCT = 'PRODUCTS',
  28 + DEVICE = 'DEVICES',
  29 +}
  30 +
  31 +export enum BasicInfoFormField {
  32 + DATA_SOURCE_TYPE = 'datasourceType',
  33 + DATA_SOURCE_PRODUCT = 'datasourceProduct',
  34 + DATA_SOURCE_DEVICE = 'datasourceDevice',
  35 + CONVERT_CONFIG_ID = 'convertConfigId',
  36 +}
  37 +
  38 +export enum DeviceStatusEnum {
  39 + OFFLINE = 'OFFLINE',
  40 + ONLINE = 'ONLINE',
  41 + INACTIVE = 'INACTIVE',
  42 +}
  43 +
  44 +export enum DeviceStatusNameEnum {
  45 + OFFLINE = '离线',
  46 + ONLINE = '在线',
  47 + INACTIVE = '待激活',
  48 +}
  49 +
  50 +export enum DeviceTypeEnum {
  51 + SENSOR = 'SENSOR',
  52 + DIRECT_CONNECTION = 'DIRECT_CONNECTION',
  53 + GATEWAY = 'GATEWAY',
  54 +}
  55 +
  56 +export enum DeviceTypeNameEnum {
  57 + SENSOR = '网关子设备',
  58 + DIRECT_CONNECTION = '直连设备',
  59 + GATEWAY = '网关设备',
  60 +}
  61 +
  62 +const handleGroupDevice = (options: DeviceRecord[]) => {
  63 + const map = new Map<string, string[]>();
  64 + options.forEach((item) => {
  65 + if (map.has(item.profileId)) {
  66 + const deviceList = map.get(item.profileId)!;
  67 + deviceList.push(item.id);
  68 + } else {
  69 + map.set(item.profileId, [item.id]);
  70 + }
  71 + });
  72 + const value = Array.from(map.entries()).map(([product, devices]) => ({ product, devices }));
  73 + console.log(value);
  74 + return Array.from(map.entries()).map(([product, devices]) => ({ product, devices }));
  75 +};
  76 +
  77 +const deviceTableFormSchema: FormSchema[] = [
20 78 {
21   - field: 'type',
22   - label: '转换方式',
  79 + field: 'name',
  80 + label: '设备名称',
  81 + component: 'Input',
  82 + colProps: { span: 9 },
  83 + componentProps: {
  84 + placeholder: '请输入设备名称',
  85 + },
  86 + },
  87 + {
  88 + field: 'deviceType',
  89 + label: '设备类型',
23 90 component: 'ApiSelect',
24   - required: true,
25   - colProps: {
26   - span: 24,
  91 + colProps: { span: 9 },
  92 + componentProps: {
  93 + placeholder: '请选择设备类型',
  94 + api: findDictItemByCode,
  95 + params: {
  96 + dictCode: 'device_type',
  97 + },
  98 + labelField: 'itemText',
  99 + valueField: 'itemValue',
27 100 },
28   - componentProps({}) {
29   - return {
30   - api: findDictItemByCode,
31   - params: {
32   - dictCode: 'convert_data_to',
33   - },
34   - labelField: 'itemText',
35   - valueField: 'itemValue',
36   - onChange(value) {
37   - typeValue.value = value;
  101 + },
  102 +];
  103 +
  104 +const deviceTableColumn: BasicColumn[] = [
  105 + {
  106 + title: '状态',
  107 + dataIndex: 'deviceState',
  108 + customRender: ({ text }) => {
  109 + return h(
  110 + Tag,
  111 + {
  112 + color:
  113 + text === DeviceStatusEnum.INACTIVE
  114 + ? 'warning'
  115 + : text === DeviceStatusEnum.OFFLINE
  116 + ? 'error'
  117 + : 'success',
38 118 },
39   - };
  119 + () => DeviceStatusNameEnum[text]
  120 + );
40 121 },
41 122 },
42 123 {
43   - field: 'remark',
44   - label: '描述',
45   - colProps: { span: 24 },
46   - component: 'Input',
47   - componentProps: {
48   - maxLength: 255,
49   - placeholder: '请输入描述',
  124 + title: '设备名称/设备SN',
  125 + dataIndex: 'name',
  126 + customRender: ({ text, record }) => {
  127 + return h('div', [
  128 + h('div', text),
  129 + h('div', { class: 'text-blue-400 truncate', title: record.sn }, record.sn),
  130 + ]);
50 131 },
51 132 },
  133 + {
  134 + title: '设备类型',
  135 + dataIndex: 'deviceType',
  136 + customRender: ({ text }) => {
  137 + return h(Tag, { color: 'success' }, () => DeviceTypeNameEnum[text]);
  138 + },
  139 + },
  140 + {
  141 + title: '所属产品',
  142 + dataIndex: 'deviceProfile.name',
  143 + },
  144 + {
  145 + title: '所属组织',
  146 + dataIndex: 'organizationDTO.name',
  147 + },
52 148 ];
53 149
  150 +const TransferTableProps: BasicTableProps = {
  151 + formConfig: {
  152 + layout: 'inline',
  153 + labelWidth: 80,
  154 + schemas: deviceTableFormSchema,
  155 + actionColOptions: { span: 6 },
  156 + },
  157 + size: 'small',
  158 + maxHeight: 240,
  159 + useSearchForm: true,
  160 + columns: deviceTableColumn,
  161 + showIndexColumn: false,
  162 + fetchSetting: FETCH_SETTING,
  163 +} as BasicTableProps;
  164 +
  165 +export const modeForm = (submitFn?: Function): FormSchema[] => {
  166 + return [
  167 + {
  168 + field: BasicInfoFormField.CONVERT_CONFIG_ID,
  169 + label: '',
  170 + component: 'Input',
  171 + show: false,
  172 + },
  173 + {
  174 + field: BasicInfoFormField.DATA_SOURCE_TYPE,
  175 + label: '数据源',
  176 + component: 'RadioGroup',
  177 + defaultValue: DataSourceType.ALL,
  178 + componentProps: {
  179 + options: [
  180 + { label: '全部', value: DataSourceType.ALL },
  181 + { label: '产品', value: DataSourceType.PRODUCT },
  182 + { label: '设备', value: DataSourceType.DEVICE },
  183 + ],
  184 + },
  185 + },
  186 + {
  187 + field: BasicInfoFormField.DATA_SOURCE_PRODUCT,
  188 + label: '数据源产品',
  189 + component: 'TransferModal',
  190 + ifShow: ({ model }) => {
  191 + return model[BasicInfoFormField.DATA_SOURCE_TYPE] !== DataSourceType.ALL;
  192 + },
  193 + valueField: 'value',
  194 + changeEvent: 'update:value',
  195 + componentProps: ({ formActionType }) => {
  196 + const { setFieldsValue } = formActionType;
  197 + return {
  198 + api: getDeviceProfile,
  199 + labelField: 'name',
  200 + valueField: 'tbProfileId',
  201 + transferProps: {
  202 + listStyle: { height: '400px' },
  203 + showSearch: true,
  204 + filterOption: (inputValue: string, option: Recordable) => {
  205 + const upperCaseInputValue = inputValue.toUpperCase();
  206 + const upperCaseOptionValue = option.name.toUpperCase();
  207 + return upperCaseOptionValue.includes(upperCaseInputValue);
  208 + },
  209 + },
  210 + onChange: () => {
  211 + setFieldsValue({ [BasicInfoFormField.DATA_SOURCE_DEVICE]: [] });
  212 + },
  213 + };
  214 + },
  215 + },
  216 + {
  217 + field: BasicInfoFormField.DATA_SOURCE_DEVICE,
  218 + label: '数据源设备',
  219 + component: 'TransferTableModal',
  220 + ifShow: ({ model }) => {
  221 + return model[BasicInfoFormField.DATA_SOURCE_TYPE] === DataSourceType.DEVICE;
  222 + },
  223 + valueField: 'value',
  224 + changeEvent: 'update:value',
  225 + componentProps: ({ formActionType }) => {
  226 + const { getFieldsValue } = formActionType;
  227 + const values = getFieldsValue();
  228 + const convertConfigId = Reflect.get(values, BasicInfoFormField.CONVERT_CONFIG_ID);
  229 + const devices = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_DEVICE);
  230 +
  231 + return {
  232 + labelField: 'name',
  233 + valueField: 'id',
  234 + pendingTableProps: {
  235 + ...TransferTableProps,
  236 + api: devicePage,
  237 + beforeFetch: (params) => {
  238 + const values = getFieldsValue();
  239 + const deviceProfileIds = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_PRODUCT);
  240 + const convertConfigId = Reflect.get(values, BasicInfoFormField.CONVERT_CONFIG_ID);
  241 + if (convertConfigId) {
  242 + Object.assign(params, { convertConfigId, selected: false });
  243 + }
  244 + return { ...params, deviceProfileIds };
  245 + },
  246 + } as BasicTableProps,
  247 + selectedTableProps: {
  248 + ...TransferTableProps,
  249 + // api
  250 + api: !!(convertConfigId && devices) ? devicePage : undefined,
  251 + beforeFetch: (params) => {
  252 + const values = getFieldsValue();
  253 + const deviceProfileIds = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_PRODUCT);
  254 + const convertConfigId = Reflect.get(values, BasicInfoFormField.CONVERT_CONFIG_ID);
  255 + if (convertConfigId) {
  256 + Object.assign(params, { convertConfigId, selected: true });
  257 + }
  258 + return { ...params, deviceProfileIds };
  259 + },
  260 + } as BasicTableProps,
  261 + initSelectedOptions: async ({ setSelectedTotal }) => {
  262 + const values = getFieldsValue();
  263 + const convertConfigId = Reflect.get(values, BasicInfoFormField.CONVERT_CONFIG_ID);
  264 + const devices = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_DEVICE);
  265 + if (convertConfigId && devices) {
  266 + const { items, total } = await devicePage({
  267 + page: 1,
  268 + pageSize: 10,
  269 + convertConfigId: values[BasicInfoFormField.CONVERT_CONFIG_ID],
  270 + selected: true,
  271 + });
  272 + setSelectedTotal(total);
  273 + return items;
  274 + }
  275 + return [];
  276 + },
  277 + onSelectedAfter: async () => {
  278 + submitFn && (await submitFn(false));
  279 + },
  280 + onRemoveAfter: async ({ reloadSelected }) => {
  281 + submitFn && (await submitFn(false));
  282 + reloadSelected();
  283 + },
  284 + transformValue: (_selectedRowKeys: string[], selectedRows: DeviceRecord[]) => {
  285 + return handleGroupDevice(selectedRows);
  286 + },
  287 + };
  288 + },
  289 + },
  290 + {
  291 + field: 'type',
  292 + label: '转换方式',
  293 + component: 'ApiSelect',
  294 + required: true,
  295 + colProps: {
  296 + span: 24,
  297 + },
  298 + componentProps({}) {
  299 + return {
  300 + api: findDictItemByCode,
  301 + params: {
  302 + dictCode: 'convert_data_to',
  303 + },
  304 + labelField: 'itemText',
  305 + valueField: 'itemValue',
  306 + onChange(value) {
  307 + typeValue.value = value;
  308 + },
  309 + };
  310 + },
  311 + },
  312 + {
  313 + field: 'remark',
  314 + label: '描述',
  315 + colProps: { span: 24 },
  316 + component: 'Input',
  317 + componentProps: {
  318 + maxLength: 255,
  319 + placeholder: '请输入描述',
  320 + },
  321 + },
  322 + ];
  323 +};
  324 +
54 325 export const modeKafkaForm: FormSchema[] = [
55 326 {
56 327 field: 'name',
... ...
... ... @@ -3,12 +3,31 @@
3 3 <BasicForm @register="register" />
4 4 </div>
5 5 </template>
  6 +
6 7 <script lang="ts">
7 8 import { defineComponent, ref, nextTick } from 'vue';
8 9 import { BasicForm, useForm } from '/@/components/Form';
9   - import { modeForm } from './config';
  10 + import { BasicInfoFormField, modeForm } from './config';
10 11 import { Select, Input, Divider } from 'ant-design-vue';
11 12
  13 + export interface ConvertDevice {
  14 + product: string;
  15 + devices: string[];
  16 + }
  17 +
  18 + export interface DatasourceContent {
  19 + convertProducts: string[];
  20 + convertDevices: ConvertDevice[];
  21 + }
  22 +
  23 + export interface BasicInfoRecord {
  24 + name?: string;
  25 + type: string;
  26 + remark: string;
  27 + datasourceType: string;
  28 + datasourceContent: DatasourceContent;
  29 + }
  30 +
12 31 export default defineComponent({
13 32 components: {
14 33 BasicForm,
... ... @@ -17,12 +36,17 @@
17 36 [Input.Group.name]: Input.Group,
18 37 [Divider.name]: Divider,
19 38 },
  39 + props: {
  40 + saveContent: {
  41 + type: Function,
  42 + },
  43 + },
20 44 emits: ['next', 'resetFunc', 'register'],
21   - setup(_, { emit }) {
22   - const sonValues = ref({});
  45 + setup(props, { emit }) {
  46 + const sonValues = ref<BasicInfoRecord>({} as unknown as BasicInfoRecord);
23 47 const [register, { validateFields, setFieldsValue, resetFields }] = useForm({
24 48 labelWidth: 100,
25   - schemas: modeForm,
  49 + schemas: modeForm(props.saveContent),
26 50 actionColOptions: {
27 51 span: 14,
28 52 },
... ... @@ -40,8 +64,17 @@
40 64 } catch (error) {}
41 65 }
42 66 //回显数据
43   - const setStepOneFieldsValueFunc = (v) => {
44   - setFieldsValue(v);
  67 + const setStepOneFieldsValueFunc = (record: Recordable) => {
  68 + const value = {
  69 + ...record,
  70 + [BasicInfoFormField.DATA_SOURCE_PRODUCT]:
  71 + record?.datasourceContent?.convertProducts || [],
  72 + [BasicInfoFormField.DATA_SOURCE_DEVICE]:
  73 + (record?.datasourceContent?.convertDevices || []).reduce((prev, next) => {
  74 + return [...prev, ...(next?.devices || [])];
  75 + }, []) || [],
  76 + };
  77 + setFieldsValue(value);
45 78 };
46 79
47 80 //清空数据
... ... @@ -51,7 +84,21 @@
51 84 });
52 85 };
53 86 const getSonValueFunc = async () => {
54   - sonValues.value = await validateFields();
  87 + const record = (await validateFields()) || {};
  88 + const { type, remark } = record;
  89 + const datasourceType = Reflect.get(record, BasicInfoFormField.DATA_SOURCE_TYPE);
  90 + const convertDevices = Reflect.get(record, BasicInfoFormField.DATA_SOURCE_DEVICE);
  91 + const convertProducts = Reflect.get(record, BasicInfoFormField.DATA_SOURCE_PRODUCT);
  92 +
  93 + sonValues.value = {
  94 + type,
  95 + remark,
  96 + datasourceType,
  97 + datasourceContent: {
  98 + convertProducts,
  99 + convertDevices,
  100 + },
  101 + };
55 102 return sonValues.value;
56 103 };
57 104 return {
... ...
... ... @@ -108,6 +108,9 @@
108 108 import { RoleEnum } from '/@/enums/roleEnum';
109 109 import { useGo } from '/@/hooks/web/usePage';
110 110 import { PageEnum } from '/@/enums/pageEnum';
  111 + import { router } from '/@/router';
  112 + import { RouteRecordRaw } from 'vue-router';
  113 + import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic';
111 114
112 115 export default defineComponent({
113 116 name: 'TenantAdminDrawer',
... ... @@ -244,7 +247,12 @@
244 247 permissionStore.setPermCodeList(permissionList);
245 248 userStore.setUserInfo(userInfo);
246 249 userStore.setRoleList(userInfo.roles as RoleEnum[]);
247   - permissionStore.buildRoutesAction();
  250 + const routes = await permissionStore.buildRoutesAction();
  251 + routes.forEach((route) => {
  252 + router.addRoute(route as unknown as RouteRecordRaw);
  253 + });
  254 + router.addRoute(PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw);
  255 + permissionStore.setDynamicAddedRoute(true);
248 256 go(PageEnum.BASE_HOME);
249 257 } catch (error) {
250 258 } finally {
... ...