Showing
7 changed files
with
481 additions
and
791 deletions
src/components/Form/src/components/TransferTableModal.vue
deleted
100644 → 0
| 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 selectedConfirmQueue = ref<Options[]>([]); | |
| 66 | - | |
| 67 | - const pendingConfirmQueue = ref<Options[]>([]); | |
| 68 | - | |
| 69 | - const selectedTotal = ref(0); | |
| 70 | - | |
| 71 | - const pendingTotal = ref(0); | |
| 72 | - | |
| 73 | - const getFetchSetting = computed(() => { | |
| 74 | - const { pendingTableProps } = props; | |
| 75 | - return pendingTableProps?.fetchSetting || FETCH_SETTING; | |
| 76 | - }); | |
| 77 | - | |
| 78 | - const getPendingRowSelection = computed<TableRowSelection>(() => { | |
| 79 | - const rowKeys = unref(selectedRowKeys); | |
| 80 | - return { | |
| 81 | - type: 'checkbox', | |
| 82 | - getCheckboxProps: (record: Recordable) => { | |
| 83 | - const { primaryKey } = props; | |
| 84 | - return { | |
| 85 | - ...record, | |
| 86 | - disabled: rowKeys.includes(record[primaryKey]), | |
| 87 | - }; | |
| 88 | - }, | |
| 89 | - onSelect: (_record: Recordable, _selected: boolean, selectedRows: Object[]) => { | |
| 90 | - pendingConfirmQueue.value = selectedRows; | |
| 91 | - }, | |
| 92 | - onSelectAll: (_selected: boolean, selectedRows: Recordable[]) => { | |
| 93 | - pendingConfirmQueue.value = selectedRows; | |
| 94 | - }, | |
| 95 | - }; | |
| 96 | - }); | |
| 97 | - | |
| 98 | - const getPendingTableBindProps = computed<Partial<DynamicProps<BasicTableProps>>>(() => { | |
| 99 | - const { pendingTableProps, primaryKey } = props; | |
| 100 | - return { | |
| 101 | - ...pendingTableProps, | |
| 102 | - rowKey: primaryKey, | |
| 103 | - api: handlePendingApiIntercept, | |
| 104 | - clickToRowSelect: false, | |
| 105 | - rowSelection: getPendingRowSelection, | |
| 106 | - }; | |
| 107 | - }); | |
| 108 | - | |
| 109 | - const getSelectedTableBindProps = computed<Partial<DynamicProps<BasicTableProps>>>(() => { | |
| 110 | - const { selectedTableProps, primaryKey } = props; | |
| 111 | - return { | |
| 112 | - ...selectedTableProps, | |
| 113 | - dataSource: selectedRows, | |
| 114 | - clickToRowSelect: false, | |
| 115 | - rowKey: primaryKey, | |
| 116 | - api: selectedTableProps!.api ? handleSelectedApiIntercept : undefined, | |
| 117 | - rowSelection: { | |
| 118 | - type: 'checkbox', | |
| 119 | - onSelect: (_record: Recordable, _selected: boolean, selectedRows: Object[]) => { | |
| 120 | - selectedConfirmQueue.value = selectedRows; | |
| 121 | - }, | |
| 122 | - onSelectAll: (_selected: boolean, selectedRows: Recordable[]) => { | |
| 123 | - selectedConfirmQueue.value = selectedRows; | |
| 124 | - }, | |
| 125 | - }, | |
| 126 | - }; | |
| 127 | - }); | |
| 128 | - | |
| 129 | - const getModalBindProps = computed(() => { | |
| 130 | - const { modalProps = {} } = props; | |
| 131 | - return { | |
| 132 | - width: '60%', | |
| 133 | - title: '穿梭表格', | |
| 134 | - wrapClassName: prefixCls, | |
| 135 | - ...modalProps, | |
| 136 | - showOkBtn: false, | |
| 137 | - }; | |
| 138 | - }); | |
| 139 | - | |
| 140 | - const getBindButtonProps = computed<ButtonProps>(() => { | |
| 141 | - const { buttonProps = {} } = props; | |
| 142 | - return { | |
| 143 | - type: 'link', | |
| 144 | - ...buttonProps, | |
| 145 | - }; | |
| 146 | - }); | |
| 147 | - | |
| 148 | - const getShowTagOptions = computed(() => { | |
| 149 | - const { maxTagLength } = props; | |
| 150 | - return unref(selectedRows).slice(0, maxTagLength); | |
| 151 | - }); | |
| 152 | - | |
| 153 | - const getSurplusOptionsLength = computed(() => { | |
| 154 | - const { maxTagLength } = props; | |
| 155 | - const surplusValue = unref(selectedRows).length - maxTagLength; | |
| 156 | - return surplusValue < 0 ? 0 : surplusValue; | |
| 157 | - }); | |
| 158 | - | |
| 159 | - const [registerModal, { openModal }] = useModal(); | |
| 160 | - | |
| 161 | - const [ | |
| 162 | - regsterPendingTable, | |
| 163 | - { | |
| 164 | - getSelectRows: getPendingSelectRows, | |
| 165 | - getSelectRowKeys: getPendingSelectRowKeys, | |
| 166 | - reload: reloadPending, | |
| 167 | - clearSelectedRowKeys: clearPendingSelectedRowKeys, | |
| 168 | - }, | |
| 169 | - ] = useTable(unref(getPendingTableBindProps)); | |
| 170 | - | |
| 171 | - const [ | |
| 172 | - registerSelectedTable, | |
| 173 | - { getSelectRowKeys, setProps, clearSelectedRowKeys, reload: reloadSelected }, | |
| 174 | - ] = useTable(unref(getSelectedTableBindProps)); | |
| 175 | - | |
| 176 | - async function handlePendingApiIntercept(params?: Recordable) { | |
| 177 | - try { | |
| 178 | - const { api } = props.pendingTableProps || {}; | |
| 179 | - if (api && isFunction(api)) { | |
| 180 | - let options = await api(params); | |
| 181 | - pendingOptions.value = options; | |
| 182 | - const { totalField, listField } = unref(getFetchSetting); | |
| 183 | - const total = get(options, totalField!); | |
| 184 | - if (unref(selectedTotal) + unref(pendingTotal) !== total) { | |
| 185 | - pendingTotal.value = total; | |
| 186 | - } | |
| 187 | - let list: Recordable[] = get(options, listField!); | |
| 188 | - list = getSelectedRows(list); | |
| 189 | - options = set(options, listField!, list); | |
| 190 | - return options; | |
| 191 | - } | |
| 192 | - } catch (error) { | |
| 193 | - console.error(error); | |
| 194 | - return []; | |
| 195 | - } | |
| 196 | - return []; | |
| 197 | - } | |
| 198 | - | |
| 199 | - async function handleSelectedApiIntercept(params?: Recordable) { | |
| 200 | - try { | |
| 201 | - const { api } = props.selectedTableProps || {}; | |
| 202 | - if (api && isFunction(api)) { | |
| 203 | - let options = await api(params); | |
| 204 | - pendingOptions.value = options; | |
| 205 | - const { totalField, listField } = unref(getFetchSetting); | |
| 206 | - selectedTotal.value = get(options, totalField!); | |
| 207 | - let list: Recordable[] = get(options, listField!); | |
| 208 | - list = getSelectedRows(list); | |
| 209 | - options = set(options, listField!, list); | |
| 210 | - return options; | |
| 211 | - } | |
| 212 | - } catch (error) { | |
| 213 | - console.error(error); | |
| 214 | - return []; | |
| 215 | - } | |
| 216 | - return []; | |
| 217 | - } | |
| 218 | - | |
| 219 | - const handleOpenModal = async () => { | |
| 220 | - openModal(true); | |
| 221 | - await nextTick(); | |
| 222 | - if (props.value && !props.value.length) { | |
| 223 | - activeKey.value = Active.PENDING; | |
| 224 | - reloadPending(); | |
| 225 | - } | |
| 226 | - }; | |
| 227 | - | |
| 228 | - const handleTriggerEmit = (selectedRowKeys: string[], selectedRows: Options[]) => { | |
| 229 | - const { transformValue } = props; | |
| 230 | - let value = selectedRowKeys; | |
| 231 | - if (transformValue && isFunction(transformValue)) { | |
| 232 | - value = transformValue(selectedRowKeys, selectedRows); | |
| 233 | - } | |
| 234 | - emit('change', unref(selectedRowKeys), unref(selectedRows)); | |
| 235 | - emit('update:value', unref(value)); | |
| 236 | - }; | |
| 237 | - | |
| 238 | - const handleSelected = async () => { | |
| 239 | - const { onSelectedAfter } = props; | |
| 240 | - const currentPageSelectRows = getPendingSelectRows(); | |
| 241 | - const currentPageSelectRowKeys = getPendingSelectRowKeys(); | |
| 242 | - const { primaryKey } = props; | |
| 243 | - selectedRows.value = uniqBy([...unref(selectedRows), ...currentPageSelectRows], primaryKey); | |
| 244 | - selectedRowKeys.value = [...new Set([...unref(selectedRowKeys), ...currentPageSelectRowKeys])]; | |
| 245 | - pendingConfirmQueue.value = []; | |
| 246 | - // selectedTotal.value = unref(selectedRowKeys).length; | |
| 247 | - pendingTotal.value = unref(pendingTotal) - currentPageSelectRows.length; | |
| 248 | - selectedTotal.value = unref(selectedTotal) + currentPageSelectRows.length; | |
| 249 | - | |
| 250 | - clearPendingSelectedRowKeys(); | |
| 251 | - handleTriggerEmit(unref(selectedRowKeys), unref(selectedRows)); | |
| 252 | - | |
| 253 | - if (onSelectedAfter && isFunction(onSelectedAfter)) { | |
| 254 | - await onSelectedAfter(actionType); | |
| 255 | - } | |
| 256 | - reloadPending(); | |
| 257 | - }; | |
| 258 | - | |
| 259 | - const handleRemoveSelected = async () => { | |
| 260 | - const { onRemoveAfter } = props; | |
| 261 | - const removeRowKeys = getSelectRowKeys(); | |
| 262 | - selectedRowKeys.value = unref(selectedRowKeys).filter((key) => !removeRowKeys.includes(key)); | |
| 263 | - selectedRows.value = unref(selectedRows).filter((item) => { | |
| 264 | - const { primaryKey } = props; | |
| 265 | - return unref(selectedRowKeys).includes(item[primaryKey]); | |
| 266 | - }); | |
| 267 | - pendingTotal.value = unref(pendingTotal) + removeRowKeys.length; | |
| 268 | - selectedTotal.value = unref(selectedTotal) - removeRowKeys.length; | |
| 269 | - | |
| 270 | - clearSelectedRowKeys(); | |
| 271 | - selectedConfirmQueue.value = []; | |
| 272 | - setProps({ dataSource: unref(selectedRows) }); | |
| 273 | - handleTriggerEmit(unref(selectedRowKeys), unref(selectedRows)); | |
| 274 | - | |
| 275 | - if (onRemoveAfter && isFunction(onRemoveAfter)) { | |
| 276 | - await onRemoveAfter(actionType); | |
| 277 | - } | |
| 278 | - }; | |
| 279 | - | |
| 280 | - const actionType = { | |
| 281 | - setSelectedOptions, | |
| 282 | - setSelectedTotal, | |
| 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 | - reloadSelected(); | |
| 312 | - setProps({ | |
| 313 | - dataSource: unref(selectedRows), | |
| 314 | - }); | |
| 315 | - } | |
| 316 | - }; | |
| 317 | - | |
| 318 | - watch( | |
| 319 | - () => props.value, | |
| 320 | - () => { | |
| 321 | - if (props.value && !props.value.length) { | |
| 322 | - selectedRowKeys.value = []; | |
| 323 | - selectedRows.value = []; | |
| 324 | - // pendingTotal.value = 0; | |
| 325 | - selectedTotal.value = 0; | |
| 326 | - } | |
| 327 | - } | |
| 328 | - ); | |
| 329 | - | |
| 330 | - onMounted(async () => { | |
| 331 | - const { initSelectedOptions } = props; | |
| 332 | - if (initSelectedOptions && isFunction(initSelectedOptions)) { | |
| 333 | - const options = await initSelectedOptions(actionType); | |
| 334 | - setSelectedOptions(options); | |
| 335 | - } | |
| 336 | - }); | |
| 337 | -</script> | |
| 338 | - | |
| 339 | -<template> | |
| 340 | - <section> | |
| 341 | - <BasicModal @register="registerModal" v-bind="getModalBindProps"> | |
| 342 | - <section class="bg-gray-100"> | |
| 343 | - <Tabs v-model:active-key="activeKey" type="card" @change="handleCheckoutPanel"> | |
| 344 | - <Tabs.TabPane :key="Active.PENDING"> | |
| 345 | - <template #tab> | |
| 346 | - <div class="flex items-center justify-center"> | |
| 347 | - <span>待选设备</span> | |
| 348 | - <Badge show-zero :count="pendingTotal" /> | |
| 349 | - </div> | |
| 350 | - </template> | |
| 351 | - <BasicTable @register="regsterPendingTable"> | |
| 352 | - <template #toolbar> | |
| 353 | - <section class="flex w-full justify-end items-center"> | |
| 354 | - <!-- <Button type="primary">全选</Button> --> | |
| 355 | - <div class="text-blue-400"> | |
| 356 | - <span class="mr-2">选择设备:</span> | |
| 357 | - <span>{{ pendingConfirmQueue.length }}</span> | |
| 358 | - </div> | |
| 359 | - </section> | |
| 360 | - </template> | |
| 361 | - </BasicTable> | |
| 362 | - <section class="flex justify-end px-4 pb-4"> | |
| 363 | - <Button | |
| 364 | - type="primary" | |
| 365 | - @click="handleSelected" | |
| 366 | - :disabled="!pendingConfirmQueue.length" | |
| 367 | - > | |
| 368 | - <span>确定已选</span> | |
| 369 | - </Button> | |
| 370 | - </section> | |
| 371 | - </Tabs.TabPane> | |
| 372 | - <Tabs.TabPane :key="Active.SELECTED"> | |
| 373 | - <template #tab> | |
| 374 | - <div class="flex items-center justify-center"> | |
| 375 | - <span>已选设备</span> | |
| 376 | - <Badge show-zero :count="selectedTotal" /> | |
| 377 | - </div> | |
| 378 | - </template> | |
| 379 | - <BasicTable @register="registerSelectedTable"> | |
| 380 | - <template #toolbar> | |
| 381 | - <section class="flex w-full justify-end items-center"> | |
| 382 | - <!-- <Button type="primary">全选</Button> --> | |
| 383 | - <div class="text-blue-400"> | |
| 384 | - <span class="mr-2">选择设备:</span> | |
| 385 | - <span>{{ selectedConfirmQueue.length }}</span> | |
| 386 | - </div> | |
| 387 | - </section> | |
| 388 | - </template> | |
| 389 | - </BasicTable> | |
| 390 | - <section class="flex justify-end px-4 pb-4"> | |
| 391 | - <Button | |
| 392 | - type="primary" | |
| 393 | - :disabled="!selectedConfirmQueue.length" | |
| 394 | - @click="handleRemoveSelected" | |
| 395 | - > | |
| 396 | - <span>移除已选</span> | |
| 397 | - </Button> | |
| 398 | - </section> | |
| 399 | - </Tabs.TabPane> | |
| 400 | - </Tabs> | |
| 401 | - </section> | |
| 402 | - </BasicModal> | |
| 403 | - <Button @click="handleOpenModal" v-bind="getBindButtonProps"> | |
| 404 | - <span v-if="!selectedRowKeys.length">选择设备</span> | |
| 405 | - <div v-if="selectedRowKeys.length"> | |
| 406 | - <Tag | |
| 407 | - class="!px-2 !py-1 !bg-gray-50 !border-gray-100" | |
| 408 | - v-for="item in getShowTagOptions" | |
| 409 | - :key="item.value" | |
| 410 | - > | |
| 411 | - <span> | |
| 412 | - {{ item.alias || item.name }} | |
| 413 | - </span> | |
| 414 | - </Tag> | |
| 415 | - <Tag class="!px-2 !py-1 !bg-gray-50 !border-gray-100" v-if="getSurplusOptionsLength"> | |
| 416 | - <span> +{{ getSurplusOptionsLength }}... </span> | |
| 417 | - </Tag> | |
| 418 | - </div> | |
| 419 | - </Button> | |
| 420 | - </section> | |
| 421 | -</template> | |
| 422 | - | |
| 423 | -<style lang="less"> | |
| 424 | - @prefix-cls: ~'@{namespace}-transfer-table-modal'; | |
| 425 | - | |
| 426 | - .@{prefix-cls} { | |
| 427 | - .vben-basic-table { | |
| 428 | - padding-top: 0; | |
| 429 | - } | |
| 430 | - | |
| 431 | - .vben-basic-form > .ant-row { | |
| 432 | - width: 100%; | |
| 433 | - } | |
| 434 | - | |
| 435 | - .ant-tabs-top-bar { | |
| 436 | - background-color: #fff; | |
| 437 | - } | |
| 438 | - } | |
| 439 | -</style> |
| ... | ... | @@ -61,7 +61,6 @@ |
| 61 | 61 | //input动态数据 |
| 62 | 62 | const dynamicInput: UnwrapRef<{ params: Params[] }> = reactive({ params: [] }); |
| 63 | 63 | |
| 64 | - console.log(dynamicInput, 'dynamicInput'); | |
| 65 | 64 | //删除Input |
| 66 | 65 | const remove = (item: Params) => { |
| 67 | 66 | let index = dynamicInput.params.indexOf(item); | ... | ... |
| ... | ... | @@ -37,7 +37,7 @@ |
| 37 | 37 | import { BasicModal, useModalInner } from '/@/components/Modal'; |
| 38 | 38 | import { add } from '/@/components/Form/src/componentMap'; |
| 39 | 39 | import TransferModal from '/@/components/Form/src/components/TransferModal.vue'; |
| 40 | - import TransferTableModal from '/@/components/Form/src/components/TransferTableModal.vue'; | |
| 40 | + import TransferTableModal from './TransferTableModal.vue'; | |
| 41 | 41 | import { DataFlowMethod, DataFlowParams } from './index'; |
| 42 | 42 | import { stepConfig, removeFieldByModeForm } from './config'; |
| 43 | 43 | import { postAddConvertApi } from '/@/api/datamanager/dataManagerApi'; | ... | ... |
| 1 | +import { h, unref } from 'vue'; | |
| 2 | +import { findDictItemByCode } from '/@/api/system/dict'; | |
| 3 | +import { FETCH_SETTING } from '/@/components/Table/src/const'; | |
| 4 | +import { DeviceStatusEnum, DeviceStatusNameEnum, DeviceTypeNameEnum } from './enum'; | |
| 5 | +import { Tag } from 'ant-design-vue'; | |
| 6 | +import { BasicColumn, BasicTableProps, FormSchema } from '/@/components/Table'; | |
| 7 | +import { useClipboard } from '@vueuse/core'; | |
| 8 | +import { useMessage } from '/@/hooks/web/useMessage'; | |
| 9 | + | |
| 10 | +export const deviceTableFormSchema: FormSchema[] = [ | |
| 11 | + { | |
| 12 | + field: 'name', | |
| 13 | + label: '设备名称', | |
| 14 | + component: 'Input', | |
| 15 | + colProps: { span: 9 }, | |
| 16 | + componentProps: { | |
| 17 | + placeholder: '请输入设备名称', | |
| 18 | + }, | |
| 19 | + }, | |
| 20 | + { | |
| 21 | + field: 'deviceType', | |
| 22 | + label: '设备类型', | |
| 23 | + component: 'ApiSelect', | |
| 24 | + colProps: { span: 9 }, | |
| 25 | + componentProps: { | |
| 26 | + placeholder: '请选择设备类型', | |
| 27 | + api: findDictItemByCode, | |
| 28 | + params: { | |
| 29 | + dictCode: 'device_type', | |
| 30 | + }, | |
| 31 | + labelField: 'itemText', | |
| 32 | + valueField: 'itemValue', | |
| 33 | + }, | |
| 34 | + }, | |
| 35 | +]; | |
| 36 | + | |
| 37 | +const { copied, copy } = useClipboard({ legacy: true }); | |
| 38 | + | |
| 39 | +const { createMessage } = useMessage(); | |
| 40 | + | |
| 41 | +export const deviceTableColumn: BasicColumn[] = [ | |
| 42 | + { | |
| 43 | + title: '状态', | |
| 44 | + dataIndex: 'deviceState', | |
| 45 | + customRender: ({ text }) => { | |
| 46 | + return h( | |
| 47 | + Tag, | |
| 48 | + { | |
| 49 | + color: | |
| 50 | + text === DeviceStatusEnum.INACTIVE | |
| 51 | + ? 'warning' | |
| 52 | + : text === DeviceStatusEnum.OFFLINE | |
| 53 | + ? 'error' | |
| 54 | + : 'success', | |
| 55 | + }, | |
| 56 | + () => DeviceStatusNameEnum[text] | |
| 57 | + ); | |
| 58 | + }, | |
| 59 | + }, | |
| 60 | + { | |
| 61 | + title: '别名/设备名称', | |
| 62 | + dataIndex: 'name', | |
| 63 | + customRender: ({ record }) => { | |
| 64 | + return h('div', [ | |
| 65 | + h( | |
| 66 | + 'div', | |
| 67 | + { | |
| 68 | + class: 'cursor-pointer', | |
| 69 | + onClick: async () => { | |
| 70 | + await copy(record.name); | |
| 71 | + if (unref(copied)) createMessage.success('复制成功~'); | |
| 72 | + }, | |
| 73 | + }, | |
| 74 | + [ | |
| 75 | + record.alias && h('div', { class: 'truncate' }, record.alias), | |
| 76 | + h('div', { class: 'text-blue-400 truncate' }, record.name), | |
| 77 | + ] | |
| 78 | + ), | |
| 79 | + ]); | |
| 80 | + }, | |
| 81 | + }, | |
| 82 | + { | |
| 83 | + title: '设备类型', | |
| 84 | + dataIndex: 'deviceType', | |
| 85 | + customRender: ({ text }) => { | |
| 86 | + return h(Tag, { color: 'success' }, () => DeviceTypeNameEnum[text]); | |
| 87 | + }, | |
| 88 | + }, | |
| 89 | + { | |
| 90 | + title: '所属产品', | |
| 91 | + dataIndex: 'deviceProfile.name', | |
| 92 | + }, | |
| 93 | + { | |
| 94 | + title: '所属组织', | |
| 95 | + dataIndex: 'organizationDTO.name', | |
| 96 | + }, | |
| 97 | +]; | |
| 98 | + | |
| 99 | +export const TransferTableProps: BasicTableProps = { | |
| 100 | + formConfig: { | |
| 101 | + layout: 'inline', | |
| 102 | + labelWidth: 80, | |
| 103 | + schemas: deviceTableFormSchema, | |
| 104 | + actionColOptions: { span: 6 }, | |
| 105 | + }, | |
| 106 | + size: 'small', | |
| 107 | + maxHeight: 240, | |
| 108 | + useSearchForm: true, | |
| 109 | + columns: deviceTableColumn, | |
| 110 | + showIndexColumn: false, | |
| 111 | + fetchSetting: FETCH_SETTING, | |
| 112 | +} as BasicTableProps; | ... | ... |
| 1 | +<script lang="ts" setup> | |
| 2 | + import { Button, Tabs, Tag } from 'ant-design-vue'; | |
| 3 | + import { remove, uniqBy, cloneDeep } from 'lodash'; | |
| 4 | + import { computed, nextTick, onMounted, ref, unref, toRaw } from 'vue'; | |
| 5 | + import { | |
| 6 | + deviceTableColumn, | |
| 7 | + deviceTableFormSchema, | |
| 8 | + TransferTableProps, | |
| 9 | + } from './TransferTableModal.config'; | |
| 10 | + import { devicePage } from '/@/api/device/deviceManager'; | |
| 11 | + import { DeviceModel as RawDeviceModal } from '/@/api/device/model/deviceModel'; | |
| 12 | + import { BasicModal, useModal } from '/@/components/Modal'; | |
| 13 | + import { BasicTable, useTable } from '/@/components/Table'; | |
| 14 | + import { FETCH_SETTING } from '/@/components/Table/src/const'; | |
| 15 | + import { useDesign } from '/@/hooks/web/useDesign'; | |
| 16 | + import { isFunction } from '/@/utils/is'; | |
| 17 | + | |
| 18 | + interface DeviceModel extends RawDeviceModal { | |
| 19 | + disabled?: boolean; | |
| 20 | + } | |
| 21 | + | |
| 22 | + const props = withDefaults( | |
| 23 | + defineProps<{ | |
| 24 | + getPendingTableParams: (params: Recordable) => any; | |
| 25 | + getSelectedTableParams: (params: Recordable) => any; | |
| 26 | + value?: (Recordable & DeviceModel)[]; | |
| 27 | + maxTagLength?: number; | |
| 28 | + openModalValidate?: () => boolean; | |
| 29 | + primaryKey?: string; | |
| 30 | + transformValue?: (list: Recordable[]) => any; | |
| 31 | + }>(), | |
| 32 | + { | |
| 33 | + value: () => [], | |
| 34 | + maxTagLength: 2, | |
| 35 | + primaryKey: 'tbDeviceId', | |
| 36 | + } | |
| 37 | + ); | |
| 38 | + | |
| 39 | + const emit = defineEmits(['update:value']); | |
| 40 | + | |
| 41 | + enum Active { | |
| 42 | + PENDING = 'pending', | |
| 43 | + SELECTED = 'selected', | |
| 44 | + } | |
| 45 | + | |
| 46 | + const activeKey = ref(Active.PENDING); | |
| 47 | + | |
| 48 | + const { prefixCls } = useDesign('transfer-table-modal'); | |
| 49 | + | |
| 50 | + const pendingTotalList = ref<DeviceModel[]>([]); | |
| 51 | + | |
| 52 | + const pendingConfirmQueue = ref<DeviceModel[]>([]); | |
| 53 | + | |
| 54 | + const selectedTotalList = ref<DeviceModel[]>([]); | |
| 55 | + | |
| 56 | + const selectedConfirmQueue = ref<DeviceModel[]>([]); | |
| 57 | + | |
| 58 | + const getShowTagOptions = computed(() => { | |
| 59 | + const { maxTagLength } = props; | |
| 60 | + return unref(selectedTotalList).slice(0, maxTagLength); | |
| 61 | + }); | |
| 62 | + | |
| 63 | + const getSurplusOptionsLength = computed(() => { | |
| 64 | + const { maxTagLength } = props; | |
| 65 | + const surplusValue = unref(selectedTotalList).length - maxTagLength; | |
| 66 | + return surplusValue < 0 ? 0 : surplusValue; | |
| 67 | + }); | |
| 68 | + | |
| 69 | + // const pendingListCount = computed(() => { | |
| 70 | + // const { value } = props; | |
| 71 | + // const selectedList = unref(pendingTotalList).filter((item) => value.includes(item.id)); | |
| 72 | + // return unref(pendingTotalList).length - selectedList.length; | |
| 73 | + // }); | |
| 74 | + | |
| 75 | + const [registerModal, { openModal }] = useModal(); | |
| 76 | + | |
| 77 | + const [regsterPendingTable, pendingTableActionType] = useTable({ | |
| 78 | + ...TransferTableProps, | |
| 79 | + rowKey: props.primaryKey, | |
| 80 | + api: devicePage, | |
| 81 | + immediate: false, | |
| 82 | + clickToRowSelect: false, | |
| 83 | + beforeFetch: (params) => { | |
| 84 | + const { getPendingTableParams } = props; | |
| 85 | + const data = getPendingTableParams?.(params) || {}; | |
| 86 | + Object.assign(params, { ...data, selected: false }); | |
| 87 | + return params; | |
| 88 | + }, | |
| 89 | + afterFetch: (list: DeviceModel[]) => { | |
| 90 | + pendingTotalList.value = list; | |
| 91 | + return unref(pendingTotalList); | |
| 92 | + }, | |
| 93 | + rowSelection: { | |
| 94 | + type: 'checkbox', | |
| 95 | + getCheckboxProps: (record: DeviceModel) => { | |
| 96 | + const { primaryKey } = props; | |
| 97 | + const checked = unref(selectedTotalList).map((item) => item[primaryKey]); | |
| 98 | + return { | |
| 99 | + disabled: checked.includes(record[props.primaryKey]!), | |
| 100 | + }; | |
| 101 | + }, | |
| 102 | + onSelect: (_record: Recordable, _selected: boolean, selectedRows: DeviceModel[]) => { | |
| 103 | + const { primaryKey } = props; | |
| 104 | + const checked = unref(selectedTotalList).map((item) => item[primaryKey]); | |
| 105 | + pendingConfirmQueue.value = selectedRows.filter( | |
| 106 | + (item) => !checked.includes(item[primaryKey]!) | |
| 107 | + ); | |
| 108 | + }, | |
| 109 | + onSelectAll: (_selected: boolean, selectedRows: DeviceModel[]) => { | |
| 110 | + const { primaryKey } = props; | |
| 111 | + const checked = unref(selectedTotalList).map((item) => item[primaryKey]); | |
| 112 | + pendingConfirmQueue.value = selectedRows.filter( | |
| 113 | + (item) => !checked.includes(item[primaryKey]!) | |
| 114 | + ); | |
| 115 | + }, | |
| 116 | + }, | |
| 117 | + }); | |
| 118 | + | |
| 119 | + const [registerSelectedTable, selectedTableActionType] = useTable({ | |
| 120 | + formConfig: { | |
| 121 | + layout: 'inline', | |
| 122 | + labelWidth: 80, | |
| 123 | + schemas: deviceTableFormSchema, | |
| 124 | + actionColOptions: { span: 6 }, | |
| 125 | + }, | |
| 126 | + size: 'small', | |
| 127 | + maxHeight: 240, | |
| 128 | + useSearchForm: true, | |
| 129 | + columns: deviceTableColumn, | |
| 130 | + api: async (params) => { | |
| 131 | + const { name = '', deviceType = '' } = params || {}; | |
| 132 | + const items = unref(selectedTotalList).filter((item) => { | |
| 133 | + return ( | |
| 134 | + item.name.toUpperCase().includes(name.toUpperCase()) && | |
| 135 | + item.deviceType.toUpperCase().includes(deviceType.toUpperCase()) | |
| 136 | + ); | |
| 137 | + }); | |
| 138 | + return { | |
| 139 | + items, | |
| 140 | + total: items.length, | |
| 141 | + }; | |
| 142 | + }, | |
| 143 | + showIndexColumn: false, | |
| 144 | + pagination: { hideOnSinglePage: false }, | |
| 145 | + fetchSetting: FETCH_SETTING, | |
| 146 | + rowKey: props.primaryKey, | |
| 147 | + dataSource: selectedTotalList, | |
| 148 | + clickToRowSelect: false, | |
| 149 | + beforeFetch: (params) => { | |
| 150 | + const { getSelectedTableParams } = props; | |
| 151 | + const data = getSelectedTableParams?.(params) || {}; | |
| 152 | + Object.assign(params, { ...data, selected: false }); | |
| 153 | + return params; | |
| 154 | + }, | |
| 155 | + rowSelection: { | |
| 156 | + type: 'checkbox', | |
| 157 | + onSelect: (_record: Recordable, _selected: boolean, selectedRows: DeviceModel[]) => { | |
| 158 | + selectedConfirmQueue.value = selectedRows; | |
| 159 | + }, | |
| 160 | + onSelectAll: (_selected: boolean, selectedRows: DeviceModel[]) => { | |
| 161 | + selectedConfirmQueue.value = selectedRows; | |
| 162 | + }, | |
| 163 | + }, | |
| 164 | + }); | |
| 165 | + | |
| 166 | + const handleTriggerUpdateValue = () => { | |
| 167 | + let list: Recordable[] = cloneDeep(toRaw(unref(selectedTotalList))); | |
| 168 | + const { transformValue } = props; | |
| 169 | + if (transformValue && isFunction(transformValue)) list = transformValue(list); | |
| 170 | + | |
| 171 | + emit('update:value', list); | |
| 172 | + }; | |
| 173 | + | |
| 174 | + const handleSelected = () => { | |
| 175 | + const { primaryKey } = props; | |
| 176 | + const _list = [...unref(selectedTotalList), ...unref(pendingConfirmQueue)]; | |
| 177 | + selectedTotalList.value = uniqBy(_list, primaryKey); | |
| 178 | + pendingConfirmQueue.value = []; | |
| 179 | + | |
| 180 | + handleTriggerUpdateValue(); | |
| 181 | + pendingTableActionType.setTableData([]); | |
| 182 | + nextTick(() => pendingTableActionType.setTableData(unref(pendingTotalList))); | |
| 183 | + }; | |
| 184 | + | |
| 185 | + const handleRemoveSelected = () => { | |
| 186 | + const { primaryKey } = props; | |
| 187 | + const selectedIds = unref(selectedConfirmQueue).map((selected) => selected[primaryKey]); | |
| 188 | + remove(unref(selectedTotalList), (item) => selectedIds.includes(item[primaryKey])); | |
| 189 | + | |
| 190 | + handleTriggerUpdateValue(); | |
| 191 | + | |
| 192 | + selectedTableActionType.clearSelectedRowKeys(); | |
| 193 | + selectedConfirmQueue.value = []; | |
| 194 | + selectedTableActionType.reload(); | |
| 195 | + }; | |
| 196 | + | |
| 197 | + const handleCheckoutPanel = async () => { | |
| 198 | + await nextTick(); | |
| 199 | + selectedTableActionType.reload(); | |
| 200 | + }; | |
| 201 | + | |
| 202 | + const handleOpenModal = async () => { | |
| 203 | + const { openModalValidate } = props; | |
| 204 | + | |
| 205 | + if (openModalValidate && isFunction(openModalValidate) && !openModalValidate()) return; | |
| 206 | + | |
| 207 | + openModal(true); | |
| 208 | + await nextTick(); | |
| 209 | + pendingTableActionType.reload(); | |
| 210 | + }; | |
| 211 | + | |
| 212 | + onMounted(async () => { | |
| 213 | + const { getSelectedTableParams } = props; | |
| 214 | + const data = getSelectedTableParams?.({}) || {}; | |
| 215 | + if (!data?.convertConfigId || !data?.deviceProfileIds) { | |
| 216 | + return; | |
| 217 | + } | |
| 218 | + const { items } = await devicePage({ page: 1, pageSize: 10, ...data, selected: true }); | |
| 219 | + selectedTotalList.value = items; | |
| 220 | + }); | |
| 221 | +</script> | |
| 222 | + | |
| 223 | +<template> | |
| 224 | + <section> | |
| 225 | + <BasicModal | |
| 226 | + @register="registerModal" | |
| 227 | + title="穿梭表格" | |
| 228 | + width="60%" | |
| 229 | + :wrapClassName="prefixCls" | |
| 230 | + :showOkBtn="false" | |
| 231 | + cancelText="关闭" | |
| 232 | + > | |
| 233 | + <section class="bg-gray-100"> | |
| 234 | + <Tabs v-model:active-key="activeKey" type="card" @change="handleCheckoutPanel"> | |
| 235 | + <Tabs.TabPane :key="Active.PENDING"> | |
| 236 | + <template #tab> | |
| 237 | + <div class="flex items-center justify-center"> | |
| 238 | + <span>待选设备</span> | |
| 239 | + <!-- <Badge show-zero :count="pendingListCount" /> --> | |
| 240 | + </div> | |
| 241 | + </template> | |
| 242 | + <BasicTable @register="regsterPendingTable"> | |
| 243 | + <template #toolbar> | |
| 244 | + <section class="flex w-full justify-end items-center"> | |
| 245 | + <!-- <Button type="primary">全选</Button> --> | |
| 246 | + <div class="text-blue-400"> | |
| 247 | + <span class="mr-2">选择设备:</span> | |
| 248 | + <span>{{ pendingConfirmQueue.length }}</span> | |
| 249 | + </div> | |
| 250 | + </section> | |
| 251 | + </template> | |
| 252 | + </BasicTable> | |
| 253 | + <section class="flex justify-end px-4 pb-4"> | |
| 254 | + <Button | |
| 255 | + type="primary" | |
| 256 | + @click="handleSelected" | |
| 257 | + :disabled="!pendingConfirmQueue.length" | |
| 258 | + > | |
| 259 | + <span>确定已选</span> | |
| 260 | + </Button> | |
| 261 | + </section> | |
| 262 | + </Tabs.TabPane> | |
| 263 | + <Tabs.TabPane :key="Active.SELECTED"> | |
| 264 | + <template #tab> | |
| 265 | + <div class="flex items-center justify-center"> | |
| 266 | + <span>已选设备</span> | |
| 267 | + <!-- <Badge show-zero :count="selectedTotalList.length" /> --> | |
| 268 | + </div> | |
| 269 | + </template> | |
| 270 | + <BasicTable @register="registerSelectedTable"> | |
| 271 | + <template #toolbar> | |
| 272 | + <section class="flex w-full justify-end items-center"> | |
| 273 | + <div class="text-blue-400"> | |
| 274 | + <span class="mr-2">选择设备:</span> | |
| 275 | + <span>{{ selectedConfirmQueue.length }}</span> | |
| 276 | + </div> | |
| 277 | + </section> | |
| 278 | + </template> | |
| 279 | + </BasicTable> | |
| 280 | + <section class="flex justify-end px-4 pb-4"> | |
| 281 | + <Button | |
| 282 | + type="primary" | |
| 283 | + :disabled="!selectedConfirmQueue.length" | |
| 284 | + @click="handleRemoveSelected" | |
| 285 | + > | |
| 286 | + <span>移除已选</span> | |
| 287 | + </Button> | |
| 288 | + </section> | |
| 289 | + </Tabs.TabPane> | |
| 290 | + </Tabs> | |
| 291 | + </section> | |
| 292 | + </BasicModal> | |
| 293 | + <Button @click="handleOpenModal" type="link"> | |
| 294 | + <span v-if="!selectedTotalList.length">选择设备</span> | |
| 295 | + <div v-if="selectedTotalList.length"> | |
| 296 | + <Tag | |
| 297 | + class="!px-2 !py-1 !bg-gray-50 !border-gray-100" | |
| 298 | + v-for="item in getShowTagOptions" | |
| 299 | + :key="item[primaryKey]" | |
| 300 | + > | |
| 301 | + <span> | |
| 302 | + {{ item.alias || item.name }} | |
| 303 | + </span> | |
| 304 | + </Tag> | |
| 305 | + <Tag class="!px-2 !py-1 !bg-gray-50 !border-gray-100" v-if="getSurplusOptionsLength"> | |
| 306 | + <span> +{{ getSurplusOptionsLength }}... </span> | |
| 307 | + </Tag> | |
| 308 | + </div> | |
| 309 | + </Button> | |
| 310 | + </section> | |
| 311 | +</template> | |
| 312 | + | |
| 313 | +<style lang="less"> | |
| 314 | + @prefix-cls: ~'@{namespace}-transfer-table-modal'; | |
| 315 | + | |
| 316 | + .@{prefix-cls} { | |
| 317 | + .vben-basic-table { | |
| 318 | + padding-top: 0; | |
| 319 | + } | |
| 320 | + | |
| 321 | + .vben-basic-form > .ant-row { | |
| 322 | + width: 100%; | |
| 323 | + } | |
| 324 | + | |
| 325 | + .ant-tabs-top-bar { | |
| 326 | + background-color: #fff; | |
| 327 | + } | |
| 328 | + | |
| 329 | + .transfer-table-disabled-row { | |
| 330 | + :deep(.ant-checkbox) { | |
| 331 | + cursor: not-allowed; | |
| 332 | + | |
| 333 | + .ant-checkbox-inner { | |
| 334 | + background-color: #f5f5f5; | |
| 335 | + border-color: #d9d9d9 !important; | |
| 336 | + } | |
| 337 | + } | |
| 338 | + } | |
| 339 | + } | |
| 340 | +</style> | ... | ... |
| 1 | 1 | import { FormSchema } from '/@/components/Form'; |
| 2 | 2 | import { findDictItemByCode } from '/@/api/system/dict'; |
| 3 | -import { h, unref } from 'vue'; | |
| 4 | 3 | import { getDeviceProfile } from '/@/api/alarm/position'; |
| 5 | -import { BasicColumn, BasicTableProps } from '/@/components/Table'; | |
| 6 | -import { devicePage } from '/@/api/device/deviceManager'; | |
| 7 | -import { Tag } from 'ant-design-vue'; | |
| 4 | +import { BasicInfoFormField, DataSourceType } from '../enum'; | |
| 8 | 5 | import { DeviceRecord } from '/@/api/device/model/deviceModel'; |
| 9 | -import { FETCH_SETTING } from '/@/components/Table/src/const'; | |
| 10 | -import { useMessage } from '/@/hooks/web/useMessage'; | |
| 11 | -import { | |
| 12 | - BasicInfoFormField, | |
| 13 | - DataSourceType, | |
| 14 | - DeviceStatusEnum, | |
| 15 | - DeviceStatusNameEnum, | |
| 16 | - DeviceTypeNameEnum, | |
| 17 | -} from '../enum'; | |
| 18 | -import { useClipboard } from '@vueuse/core'; | |
| 19 | 6 | |
| 20 | 7 | export const stepConfig = ['选择流转方式', '完善配置参数']; |
| 21 | 8 | |
| 22 | 9 | export const removeFieldByModeForm = ['name', 'description']; |
| 23 | 10 | |
| 24 | -//表单通用配置 | |
| 25 | -export const modelFormPublicConfig = { | |
| 26 | - labelWidth: 120, | |
| 27 | - actionColOptions: { | |
| 28 | - span: 14, | |
| 29 | - }, | |
| 30 | - showResetButton: false, | |
| 31 | - showSubmitButton: false, | |
| 32 | -}; | |
| 33 | - | |
| 34 | 11 | const handleGroupDevice = (options: DeviceRecord[]) => { |
| 35 | 12 | const map = new Map<string, string[]>(); |
| 36 | 13 | options.forEach((item) => { |
| ... | ... | @@ -46,111 +23,17 @@ const handleGroupDevice = (options: DeviceRecord[]) => { |
| 46 | 23 | return value; |
| 47 | 24 | }; |
| 48 | 25 | |
| 49 | -const deviceTableFormSchema: FormSchema[] = [ | |
| 50 | - { | |
| 51 | - field: 'name', | |
| 52 | - label: '设备名称', | |
| 53 | - component: 'Input', | |
| 54 | - colProps: { span: 9 }, | |
| 55 | - componentProps: { | |
| 56 | - placeholder: '请输入设备名称', | |
| 57 | - }, | |
| 58 | - }, | |
| 59 | - { | |
| 60 | - field: 'deviceType', | |
| 61 | - label: '设备类型', | |
| 62 | - component: 'ApiSelect', | |
| 63 | - colProps: { span: 9 }, | |
| 64 | - componentProps: { | |
| 65 | - placeholder: '请选择设备类型', | |
| 66 | - api: findDictItemByCode, | |
| 67 | - params: { | |
| 68 | - dictCode: 'device_type', | |
| 69 | - }, | |
| 70 | - labelField: 'itemText', | |
| 71 | - valueField: 'itemValue', | |
| 72 | - }, | |
| 73 | - }, | |
| 74 | -]; | |
| 75 | - | |
| 76 | -const { copied, copy } = useClipboard({ legacy: true }); | |
| 77 | - | |
| 78 | -const { createMessage } = useMessage(); | |
| 79 | - | |
| 80 | -const deviceTableColumn: BasicColumn[] = [ | |
| 81 | - { | |
| 82 | - title: '状态', | |
| 83 | - dataIndex: 'deviceState', | |
| 84 | - customRender: ({ text }) => { | |
| 85 | - return h( | |
| 86 | - Tag, | |
| 87 | - { | |
| 88 | - color: | |
| 89 | - text === DeviceStatusEnum.INACTIVE | |
| 90 | - ? 'warning' | |
| 91 | - : text === DeviceStatusEnum.OFFLINE | |
| 92 | - ? 'error' | |
| 93 | - : 'success', | |
| 94 | - }, | |
| 95 | - () => DeviceStatusNameEnum[text] | |
| 96 | - ); | |
| 97 | - }, | |
| 98 | - }, | |
| 99 | - { | |
| 100 | - title: '别名/设备名称', | |
| 101 | - dataIndex: 'name', | |
| 102 | - customRender: ({ record }) => { | |
| 103 | - return h('div', [ | |
| 104 | - h( | |
| 105 | - 'div', | |
| 106 | - { | |
| 107 | - class: 'cursor-pointer', | |
| 108 | - onClick: async () => { | |
| 109 | - await copy(record.name); | |
| 110 | - if (unref(copied)) createMessage.success('复制成功~'); | |
| 111 | - }, | |
| 112 | - }, | |
| 113 | - [ | |
| 114 | - record.alias && h('div', { class: 'truncate' }, record.alias), | |
| 115 | - h('div', { class: 'text-blue-400 truncate' }, record.name), | |
| 116 | - ] | |
| 117 | - ), | |
| 118 | - ]); | |
| 119 | - }, | |
| 120 | - }, | |
| 121 | - { | |
| 122 | - title: '设备类型', | |
| 123 | - dataIndex: 'deviceType', | |
| 124 | - customRender: ({ text }) => { | |
| 125 | - return h(Tag, { color: 'success' }, () => DeviceTypeNameEnum[text]); | |
| 126 | - }, | |
| 127 | - }, | |
| 128 | - { | |
| 129 | - title: '所属产品', | |
| 130 | - dataIndex: 'deviceProfile.name', | |
| 131 | - }, | |
| 132 | - { | |
| 133 | - title: '所属组织', | |
| 134 | - dataIndex: 'organizationDTO.name', | |
| 135 | - }, | |
| 136 | -]; | |
| 137 | - | |
| 138 | -const TransferTableProps: BasicTableProps = { | |
| 139 | - formConfig: { | |
| 140 | - layout: 'inline', | |
| 141 | - labelWidth: 80, | |
| 142 | - schemas: deviceTableFormSchema, | |
| 143 | - actionColOptions: { span: 6 }, | |
| 26 | +//表单通用配置 | |
| 27 | +export const modelFormPublicConfig = { | |
| 28 | + labelWidth: 120, | |
| 29 | + actionColOptions: { | |
| 30 | + span: 14, | |
| 144 | 31 | }, |
| 145 | - size: 'small', | |
| 146 | - maxHeight: 240, | |
| 147 | - useSearchForm: true, | |
| 148 | - columns: deviceTableColumn, | |
| 149 | - showIndexColumn: false, | |
| 150 | - fetchSetting: FETCH_SETTING, | |
| 151 | -} as BasicTableProps; | |
| 32 | + showResetButton: false, | |
| 33 | + showSubmitButton: false, | |
| 34 | +}; | |
| 152 | 35 | |
| 153 | -export const modeForm = (submitFn?: Function): FormSchema[] => { | |
| 36 | +export const modeForm = (): FormSchema[] => { | |
| 154 | 37 | return [ |
| 155 | 38 | { |
| 156 | 39 | field: BasicInfoFormField.CONVERT_CONFIG_ID, |
| ... | ... | @@ -214,69 +97,20 @@ export const modeForm = (submitFn?: Function): FormSchema[] => { |
| 214 | 97 | rules: [{ required: true, message: '数据源设备为必选项', type: 'array' }], |
| 215 | 98 | componentProps: ({ formActionType }) => { |
| 216 | 99 | const { getFieldsValue } = formActionType; |
| 217 | - const values = getFieldsValue(); | |
| 218 | - const convertConfigId = Reflect.get(values, BasicInfoFormField.CONVERT_CONFIG_ID); | |
| 219 | - const devices = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_DEVICE); | |
| 220 | - | |
| 221 | 100 | return { |
| 222 | - labelField: 'name', | |
| 223 | - valueField: 'tbDeviceId', | |
| 224 | - primaryKey: 'tbDeviceId', | |
| 225 | - pendingTableProps: { | |
| 226 | - ...TransferTableProps, | |
| 227 | - api: devicePage, | |
| 228 | - beforeFetch: (params) => { | |
| 229 | - const values = getFieldsValue(); | |
| 230 | - const deviceProfileIds = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_PRODUCT); | |
| 231 | - const convertConfigId = Reflect.get(values, BasicInfoFormField.CONVERT_CONFIG_ID); | |
| 232 | - if (convertConfigId) { | |
| 233 | - Object.assign(params, { convertConfigId, selected: false }); | |
| 234 | - } | |
| 235 | - return { ...params, deviceProfileIds }; | |
| 236 | - }, | |
| 237 | - } as BasicTableProps, | |
| 238 | - selectedTableProps: { | |
| 239 | - ...TransferTableProps, | |
| 240 | - // api | |
| 241 | - api: !!(convertConfigId && devices) ? devicePage : undefined, | |
| 242 | - beforeFetch: (params) => { | |
| 243 | - const values = getFieldsValue(); | |
| 244 | - const deviceProfileIds = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_PRODUCT); | |
| 245 | - const convertConfigId = Reflect.get(values, BasicInfoFormField.CONVERT_CONFIG_ID); | |
| 246 | - if (convertConfigId) { | |
| 247 | - Object.assign(params, { convertConfigId, selected: true }); | |
| 248 | - } | |
| 249 | - return { ...params, deviceProfileIds }; | |
| 250 | - }, | |
| 251 | - } as BasicTableProps, | |
| 252 | - initSelectedOptions: async ({ setSelectedTotal }) => { | |
| 101 | + getPendingTableParams: () => { | |
| 253 | 102 | const values = getFieldsValue(); |
| 254 | 103 | const convertConfigId = Reflect.get(values, BasicInfoFormField.CONVERT_CONFIG_ID); |
| 255 | 104 | const deviceProfileIds = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_PRODUCT); |
| 256 | - const devices = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_DEVICE); | |
| 257 | - if (convertConfigId && devices) { | |
| 258 | - const { items, total } = await devicePage({ | |
| 259 | - page: 1, | |
| 260 | - pageSize: 10, | |
| 261 | - convertConfigId: values[BasicInfoFormField.CONVERT_CONFIG_ID], | |
| 262 | - deviceProfileIds, | |
| 263 | - selected: true, | |
| 264 | - }); | |
| 265 | - setSelectedTotal(total); | |
| 266 | - return items; | |
| 267 | - } | |
| 268 | - return []; | |
| 105 | + return { convertConfigId, deviceProfileIds }; | |
| 269 | 106 | }, |
| 270 | - onSelectedAfter: async () => { | |
| 271 | - submitFn && (await submitFn(false)); | |
| 272 | - }, | |
| 273 | - onRemoveAfter: async ({ reloadSelected }) => { | |
| 274 | - submitFn && (await submitFn(false)); | |
| 275 | - reloadSelected(); | |
| 276 | - }, | |
| 277 | - transformValue: (_selectedRowKeys: string[], selectedRows: DeviceRecord[]) => { | |
| 278 | - return handleGroupDevice(selectedRows); | |
| 107 | + getSelectedTableParams: () => { | |
| 108 | + const values = getFieldsValue(); | |
| 109 | + const convertConfigId = Reflect.get(values, BasicInfoFormField.CONVERT_CONFIG_ID); | |
| 110 | + const deviceProfileIds = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_PRODUCT); | |
| 111 | + return { convertConfigId, deviceProfileIds }; | |
| 279 | 112 | }, |
| 113 | + transformValue: handleGroupDevice, | |
| 280 | 114 | }; |
| 281 | 115 | }, |
| 282 | 116 | }, | ... | ... |
| 1 | 1 | import { FormSchema } from '/@/components/Form'; |
| 2 | 2 | import { findDictItemByCode } from '/@/api/system/dict'; |
| 3 | -import { h, ref, unref } from 'vue'; | |
| 3 | +import { ref } from 'vue'; | |
| 4 | 4 | import { isExistDataManagerNameApi } from '/@/api/datamanager/dataManagerApi'; |
| 5 | 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 | 6 | import { DeviceRecord } from '/@/api/device/model/deviceModel'; |
| 10 | -import { FETCH_SETTING } from '/@/components/Table/src/const'; | |
| 11 | -import { useClipboard } from '@vueuse/core'; | |
| 12 | -import { useMessage } from '/@/hooks/web/useMessage'; | |
| 13 | 7 | |
| 14 | 8 | const typeValue = ref(''); |
| 15 | 9 | export enum CredentialsEnum { |
| ... | ... | @@ -76,108 +70,7 @@ const handleGroupDevice = (options: DeviceRecord[]) => { |
| 76 | 70 | return value; |
| 77 | 71 | }; |
| 78 | 72 | |
| 79 | -const deviceTableFormSchema: FormSchema[] = [ | |
| 80 | - { | |
| 81 | - field: 'name', | |
| 82 | - label: '设备名称', | |
| 83 | - component: 'Input', | |
| 84 | - colProps: { span: 9 }, | |
| 85 | - componentProps: { | |
| 86 | - placeholder: '请输入设备名称', | |
| 87 | - }, | |
| 88 | - }, | |
| 89 | - { | |
| 90 | - field: 'deviceType', | |
| 91 | - label: '设备类型', | |
| 92 | - component: 'ApiSelect', | |
| 93 | - colProps: { span: 9 }, | |
| 94 | - componentProps: { | |
| 95 | - placeholder: '请选择设备类型', | |
| 96 | - api: findDictItemByCode, | |
| 97 | - params: { | |
| 98 | - dictCode: 'device_type', | |
| 99 | - }, | |
| 100 | - labelField: 'itemText', | |
| 101 | - valueField: 'itemValue', | |
| 102 | - }, | |
| 103 | - }, | |
| 104 | -]; | |
| 105 | -const { copied, copy } = useClipboard({ legacy: true }); | |
| 106 | -const { createMessage } = useMessage(); | |
| 107 | -const deviceTableColumn: BasicColumn[] = [ | |
| 108 | - { | |
| 109 | - title: '状态', | |
| 110 | - dataIndex: 'deviceState', | |
| 111 | - customRender: ({ text }) => { | |
| 112 | - return h( | |
| 113 | - Tag, | |
| 114 | - { | |
| 115 | - color: | |
| 116 | - text === DeviceStatusEnum.INACTIVE | |
| 117 | - ? 'warning' | |
| 118 | - : text === DeviceStatusEnum.OFFLINE | |
| 119 | - ? 'error' | |
| 120 | - : 'success', | |
| 121 | - }, | |
| 122 | - () => DeviceStatusNameEnum[text] | |
| 123 | - ); | |
| 124 | - }, | |
| 125 | - }, | |
| 126 | - { | |
| 127 | - title: '别名/设备名称', | |
| 128 | - dataIndex: 'name', | |
| 129 | - customRender: ({ record }) => { | |
| 130 | - return h('div', [ | |
| 131 | - h( | |
| 132 | - 'div', | |
| 133 | - { | |
| 134 | - class: 'cursor-pointer', | |
| 135 | - onClick: async () => { | |
| 136 | - await copy(record.name); | |
| 137 | - if (unref(copied)) createMessage.success('复制成功~'); | |
| 138 | - }, | |
| 139 | - }, | |
| 140 | - [ | |
| 141 | - record.alias && h('div', { class: 'truncate' }, record.alias), | |
| 142 | - h('div', { class: 'text-blue-400 truncate' }, record.name), | |
| 143 | - ] | |
| 144 | - ), | |
| 145 | - ]); | |
| 146 | - }, | |
| 147 | - }, | |
| 148 | - { | |
| 149 | - title: '设备类型', | |
| 150 | - dataIndex: 'deviceType', | |
| 151 | - customRender: ({ text }) => { | |
| 152 | - return h(Tag, { color: 'success' }, () => DeviceTypeNameEnum[text]); | |
| 153 | - }, | |
| 154 | - }, | |
| 155 | - { | |
| 156 | - title: '所属产品', | |
| 157 | - dataIndex: 'deviceProfile.name', | |
| 158 | - }, | |
| 159 | - { | |
| 160 | - title: '所属组织', | |
| 161 | - dataIndex: 'organizationDTO.name', | |
| 162 | - }, | |
| 163 | -]; | |
| 164 | - | |
| 165 | -const TransferTableProps: BasicTableProps = { | |
| 166 | - formConfig: { | |
| 167 | - layout: 'inline', | |
| 168 | - labelWidth: 80, | |
| 169 | - schemas: deviceTableFormSchema, | |
| 170 | - actionColOptions: { span: 6 }, | |
| 171 | - }, | |
| 172 | - size: 'small', | |
| 173 | - maxHeight: 240, | |
| 174 | - useSearchForm: true, | |
| 175 | - columns: deviceTableColumn, | |
| 176 | - showIndexColumn: false, | |
| 177 | - fetchSetting: FETCH_SETTING, | |
| 178 | -} as BasicTableProps; | |
| 179 | - | |
| 180 | -export const modeForm = (submitFn?: Function): FormSchema[] => { | |
| 73 | +export const modeForm = (): FormSchema[] => { | |
| 181 | 74 | return [ |
| 182 | 75 | { |
| 183 | 76 | field: BasicInfoFormField.CONVERT_CONFIG_ID, |
| ... | ... | @@ -239,69 +132,20 @@ export const modeForm = (submitFn?: Function): FormSchema[] => { |
| 239 | 132 | changeEvent: 'update:value', |
| 240 | 133 | componentProps: ({ formActionType }) => { |
| 241 | 134 | const { getFieldsValue } = formActionType; |
| 242 | - const values = getFieldsValue(); | |
| 243 | - const convertConfigId = Reflect.get(values, BasicInfoFormField.CONVERT_CONFIG_ID); | |
| 244 | - const devices = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_DEVICE); | |
| 245 | - | |
| 246 | 135 | return { |
| 247 | - labelField: 'name', | |
| 248 | - valueField: 'tbDeviceId', | |
| 249 | - primaryKey: 'tbDeviceId', | |
| 250 | - pendingTableProps: { | |
| 251 | - ...TransferTableProps, | |
| 252 | - api: devicePage, | |
| 253 | - beforeFetch: (params) => { | |
| 254 | - const values = getFieldsValue(); | |
| 255 | - const deviceProfileIds = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_PRODUCT); | |
| 256 | - const convertConfigId = Reflect.get(values, BasicInfoFormField.CONVERT_CONFIG_ID); | |
| 257 | - if (convertConfigId) { | |
| 258 | - Object.assign(params, { convertConfigId, selected: false }); | |
| 259 | - } | |
| 260 | - return { ...params, deviceProfileIds }; | |
| 261 | - }, | |
| 262 | - } as BasicTableProps, | |
| 263 | - selectedTableProps: { | |
| 264 | - ...TransferTableProps, | |
| 265 | - // api | |
| 266 | - api: !!(convertConfigId && devices) ? devicePage : undefined, | |
| 267 | - beforeFetch: (params) => { | |
| 268 | - const values = getFieldsValue(); | |
| 269 | - const deviceProfileIds = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_PRODUCT); | |
| 270 | - const convertConfigId = Reflect.get(values, BasicInfoFormField.CONVERT_CONFIG_ID); | |
| 271 | - if (convertConfigId) { | |
| 272 | - Object.assign(params, { convertConfigId, selected: true }); | |
| 273 | - } | |
| 274 | - return { ...params, deviceProfileIds }; | |
| 275 | - }, | |
| 276 | - } as BasicTableProps, | |
| 277 | - initSelectedOptions: async ({ setSelectedTotal }) => { | |
| 136 | + getPendingTableParams: () => { | |
| 278 | 137 | const values = getFieldsValue(); |
| 279 | 138 | const convertConfigId = Reflect.get(values, BasicInfoFormField.CONVERT_CONFIG_ID); |
| 280 | 139 | const deviceProfileIds = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_PRODUCT); |
| 281 | - const devices = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_DEVICE); | |
| 282 | - if (convertConfigId && devices) { | |
| 283 | - const { items, total } = await devicePage({ | |
| 284 | - page: 1, | |
| 285 | - pageSize: 10, | |
| 286 | - convertConfigId: values[BasicInfoFormField.CONVERT_CONFIG_ID], | |
| 287 | - deviceProfileIds, | |
| 288 | - selected: true, | |
| 289 | - }); | |
| 290 | - setSelectedTotal(total); | |
| 291 | - return items; | |
| 292 | - } | |
| 293 | - return []; | |
| 294 | - }, | |
| 295 | - onSelectedAfter: async () => { | |
| 296 | - submitFn && (await submitFn(false)); | |
| 140 | + return { convertConfigId, deviceProfileIds }; | |
| 297 | 141 | }, |
| 298 | - onRemoveAfter: async ({ reloadSelected }) => { | |
| 299 | - submitFn && (await submitFn(false)); | |
| 300 | - reloadSelected(); | |
| 301 | - }, | |
| 302 | - transformValue: (_selectedRowKeys: string[], selectedRows: DeviceRecord[]) => { | |
| 303 | - return handleGroupDevice(selectedRows); | |
| 142 | + getSelectedTableParams: () => { | |
| 143 | + const values = getFieldsValue(); | |
| 144 | + const convertConfigId = Reflect.get(values, BasicInfoFormField.CONVERT_CONFIG_ID); | |
| 145 | + const deviceProfileIds = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_PRODUCT); | |
| 146 | + return { convertConfigId, deviceProfileIds }; | |
| 304 | 147 | }, |
| 148 | + transformValue: handleGroupDevice, | |
| 305 | 149 | }; |
| 306 | 150 | }, |
| 307 | 151 | }, | ... | ... |