Commit d19cd89570bae7cba3a851023e16b7bd0c4b8843

Authored by xp.Huang
2 parents 32f1277c e267ec9a

Merge branch 'feat/basic-table' into 'main_dev'

feat(src/packages): 重写基础分页表格,支持告警列表或设备列表搜索

See merge request yunteng/thingskit-view!249
@@ -21,6 +21,7 @@ enum Api { @@ -21,6 +21,7 @@ enum Api {
21 GET_ATTRBUTELIST = '/device/attributes/', 21 GET_ATTRBUTELIST = '/device/attributes/',
22 GET_DEVICE_LATEST = '/plugins/telemetry/DEVICE/', 22 GET_DEVICE_LATEST = '/plugins/telemetry/DEVICE/',
23 DEVICE_ATTR = '/device/attributes', 23 DEVICE_ATTR = '/device/attributes',
  24 + ALARM_LIST = '/alarm',
24 } 25 }
25 26
26 export const getDictItemByCode = (value: string) => { 27 export const getDictItemByCode = (value: string) => {
@@ -152,3 +153,10 @@ export const getProfileAttrs = (params: { deviceProfileId: string; dataType?: st @@ -152,3 +153,10 @@ export const getProfileAttrs = (params: { deviceProfileId: string; dataType?: st
152 params: { dataType }, 153 params: { dataType },
153 }); 154 });
154 }; 155 };
  156 +
  157 +//获取告警列表
  158 +export const getAlarmList = (params?: object) =>
  159 + defHttp.get({
  160 + url: Api.ALARM_LIST,
  161 + params
  162 + })
  1 +import cloneDeep from 'lodash/cloneDeep'
  2 +import { PublicConfigClass } from '@/packages/public'
  3 +import { CreateComponentType } from '@/packages/index.d'
  4 +import { chartInitConfig } from '@/settings/designSetting'
  5 +import { OverrideTablesBasicConfig } from './index'
  6 +import dataJson from './data.json'
  7 +
  8 +const { dimensions, source } = dataJson
  9 +export const option = {
  10 + dynamicForm: {
  11 + keys: [
  12 + {
  13 + key: '测试,test',
  14 + }
  15 + ]
  16 + },
  17 + dataset: { dimensions, source },
  18 + pagination: {
  19 + page: 1,
  20 + pageSize: 10
  21 + },
  22 + align: 'center',
  23 + style: {
  24 + border: 'on',
  25 + singleColumn: 'off',
  26 + singleLine: 'off',
  27 + bottomBordered: 'on',
  28 + striped: 'on',
  29 + fontSize: 16,
  30 + borderWidth: 0,
  31 + borderColor: 'black',
  32 + borderStyle: 'solid'
  33 + },
  34 + inputShow: false
  35 +}
  36 +
  37 +export default class Config extends PublicConfigClass implements CreateComponentType {
  38 + public key = OverrideTablesBasicConfig.key
  39 + public attr = { ...chartInitConfig, w: 600, h: 300, zIndex: -1 }
  40 + public chartConfig = cloneDeep(OverrideTablesBasicConfig)
  41 + public option = cloneDeep(option)
  42 +}
  1 +<template>
  2 + <collapse-item name="表格设置" :expanded="true">
  3 + <n-tag type="primary">配置分页接口查询参数键,以逗号分隔键名和键值</n-tag>
  4 + <n-tag type="primary">例如:设备名称,deviceName</n-tag>
  5 + <setting-item-box :alone="true" name="搜索字段">
  6 + <SettingItem name="表格搜索" :alone="true">
  7 + <n-switch v-model:value="optionData.inputShow"></n-switch>
  8 + </SettingItem>
  9 + <setting-item v-if="optionData.inputShow" :alone="true">
  10 + <n-form ref="formRef" :model="dynamicForm" :style="{ maxWidth: '640px' }">
  11 + <n-form-item
  12 + v-for="(item, index) in dynamicForm.keys"
  13 + :key="index"
  14 + :label="`字段${index + 1}`"
  15 + :path="`keys[${index}].key`"
  16 + >
  17 + <n-input v-model:value="item.key" clearable />
  18 + <n-button style="margin-left: 12px" @click="removeItem(index)" v-if="dynamicForm.keys.length > 1">
  19 + 删除
  20 + </n-button>
  21 + </n-form-item>
  22 + <n-form-item>
  23 + <n-space>
  24 + <n-button attr-type="button" @click="addItem" v-if="dynamicForm.keys.length < 2"> 增加 </n-button>
  25 + </n-space>
  26 + </n-form-item>
  27 + </n-form>
  28 + </setting-item>
  29 + </setting-item-box>
  30 + <n-tag type="primary">若配置无响应,请在预览页面查看效果</n-tag>
  31 + <setting-item-box :alone="true" name="对齐方式">
  32 + <setting-item :alone="true">
  33 + <n-select
  34 + v-model:value="optionData.align"
  35 + size="small"
  36 + :options="[
  37 + { label: '靠左', value: 'left' },
  38 + { label: '居中', value: 'center' },
  39 + { label: '靠右', value: 'right' }
  40 + ]"
  41 + />
  42 + </setting-item>
  43 + </setting-item-box>
  44 + <setting-item-box :alone="false" name="分页设置">
  45 + <setting-item name="默认页码" :alone="true">
  46 + <n-input-number v-model:value="optionData.pagination.page" size="small" placeholder="字体大小"></n-input-number>
  47 + </setting-item>
  48 + <setting-item name="分页" :alone="true">
  49 + <n-select v-model:value="optionData.pagination.pageSize" size="small" :options="page" />
  50 + </setting-item>
  51 + </setting-item-box>
  52 + <setting-item-box :alone="false" name="表格样式">
  53 + <SettingItem name="显示边框" :alone="true">
  54 + <n-select v-model:value="(optionData as any).style.border" size="small" :options="borderFlag" />
  55 + </SettingItem>
  56 + <SettingItem name="底部边框" :alone="true">
  57 + <n-select
  58 + v-model:value="(optionData as any).style.bottomBordered"
  59 + size="small"
  60 + :options="bottom_borderedFlag"
  61 + />
  62 + </SettingItem>
  63 + <SettingItem name="列分割线" :alone="true">
  64 + <n-select v-model:value="(optionData as any).style.singleLine" size="small" :options="columnFlag" />
  65 + </SettingItem>
  66 + <SettingItem name="行分割线" :alone="true">
  67 + <n-select v-model:value="(optionData as any).style.singleColumn" size="small" :options="lineFlag" />
  68 + </SettingItem>
  69 + <SettingItem name="斑马条纹" :alone="true">
  70 + <n-select v-model:value="(optionData as any).style.striped" size="small" :options="stripedFlag" />
  71 + </SettingItem>
  72 + <setting-item name="字体大小" :alone="true">
  73 + <n-input-number
  74 + v-model:value="optionData.style.fontSize"
  75 + :min="12"
  76 + size="small"
  77 + placeholder="字体大小"
  78 + ></n-input-number>
  79 + </setting-item>
  80 + <setting-item name="边框宽度" :alone="true">
  81 + <n-input-number
  82 + v-model:value="optionData.style.borderWidth"
  83 + :min="0"
  84 + size="small"
  85 + placeholder="字体大小"
  86 + ></n-input-number>
  87 + </setting-item>
  88 + <setting-item name="边框颜色" :alone="true">
  89 + <n-color-picker size="small" :modes="['rgb']" v-model:value="optionData.style.borderColor"></n-color-picker>
  90 + </setting-item>
  91 + <setting-item name="边框样式" :alone="true">
  92 + <n-select v-model:value="optionData.style.borderStyle" size="small" :options="borderStyleFlag" />
  93 + </setting-item>
  94 + </setting-item-box>
  95 + </collapse-item>
  96 +</template>
  97 +
  98 +<script setup lang="ts">
  99 +import { PropType, watch, ref, toRefs } from 'vue'
  100 +import { option } from './config'
  101 +import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
  102 +import { FormInst } from 'naive-ui'
  103 +
  104 +const page = [
  105 + { label: '2', value: 2 },
  106 + { label: '5', value: 5 },
  107 + { label: '10', value: 10 },
  108 + { label: '15', value: 15 },
  109 + { label: '30', value: 30 }
  110 +]
  111 +const borderFlag = [
  112 + { label: '显示', value: 'on' },
  113 + { label: '不显示', value: 'off' }
  114 +]
  115 +const columnFlag = [
  116 + { label: '显示', value: 'off' },
  117 + { label: '不显示', value: 'on' }
  118 +]
  119 +const lineFlag = [
  120 + { label: '显示', value: 'off' },
  121 + { label: '不显示', value: 'on' }
  122 +]
  123 +const bottom_borderedFlag = [
  124 + { label: '显示', value: 'on' },
  125 + { label: '不显示', value: 'off' }
  126 +]
  127 +const stripedFlag = [
  128 + { label: '显示', value: 'on' },
  129 + { label: '不显示', value: 'off' }
  130 +]
  131 +const borderStyleFlag = [
  132 + { label: '实线边框', value: 'solid' },
  133 + { label: '虚线边框', value: 'dashed' },
  134 + { label: '点状边框', value: 'dotted' },
  135 + { label: '双线边框', value: 'double' }
  136 +]
  137 +const props = defineProps({
  138 + optionData: {
  139 + type: Object as PropType<typeof option>,
  140 + required: true
  141 + }
  142 +})
  143 +
  144 +const header = ref()
  145 +const median = ref<string[]>([])
  146 +props.optionData.dataset.dimensions.forEach(item => {
  147 + median.value.push(item.title)
  148 +})
  149 +
  150 +const { dynamicForm } = toRefs(props.optionData)
  151 +
  152 +const formRef = ref<FormInst | null>(null)
  153 +
  154 +const removeItem = (index: number) => {
  155 + dynamicForm.value.keys.splice(index, 1)
  156 +}
  157 +
  158 +const addItem = () => {
  159 + dynamicForm.value.keys.push({ key: '' })
  160 +}
  161 +
  162 +//转string
  163 +watch(
  164 + () => props.optionData,
  165 + () => {
  166 + median.value = []
  167 + props.optionData.dataset.dimensions.forEach(item => {
  168 + median.value.push(item.title)
  169 + })
  170 + header.value = median.value.toString()
  171 + },
  172 + {
  173 + deep: false,
  174 + immediate: true
  175 + }
  176 +)
  177 +
  178 +//更新columns
  179 +watch([header], ([headerNew], [headerOld]) => {
  180 + if (headerNew !== headerOld) {
  181 + headerNew.split(',').forEach((item: string, index: number) => {
  182 + if (index + 1 <= props.optionData.dataset.dimensions.length) {
  183 + props.optionData.dataset.dimensions[index].title = headerNew.split(',')[index]
  184 + }
  185 + })
  186 + }
  187 +})
  188 +</script>
  1 +{
  2 + "dimensions": [
  3 + {
  4 + "title": "产品名称",
  5 + "key": "productName"
  6 + },
  7 + {
  8 + "title": "产品销量(万)",
  9 + "key": "totalSum"
  10 + },
  11 + {
  12 + "title": "销售额(万)",
  13 + "key": "totalAmount"
  14 + }
  15 + ],
  16 + "source": [
  17 + {
  18 + "key": 0,
  19 + "productName": "产品A1",
  20 + "totalSum": 10,
  21 + "totalAmount": 10
  22 + },
  23 + {
  24 + "key": 1,
  25 + "productName": "产品B1",
  26 + "totalSum": 10,
  27 + "totalAmount": 10
  28 + },
  29 + {
  30 + "key": 2,
  31 + "productName": "产品C1",
  32 + "totalSum": 10,
  33 + "totalAmount": 10
  34 + },
  35 + {
  36 + "key": 3,
  37 + "productName": "产品D1",
  38 + "totalSum": 10,
  39 + "totalAmount": 10
  40 + },
  41 + {
  42 + "key": 4,
  43 + "productName": "产品A2",
  44 + "totalSum": 10,
  45 + "totalAmount": 10
  46 + },
  47 + {
  48 + "key": 5,
  49 + "productName": "产品D2",
  50 + "totalSum": 10,
  51 + "totalAmount": 10
  52 + },
  53 + {
  54 + "key": 6,
  55 + "productName": "产品A3",
  56 + "totalSum": 10,
  57 + "totalAmount": 10
  58 + }
  59 + ]
  60 +}
  1 +import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
  2 +import { ChatCategoryEnum, ChatCategoryEnumName } from '@/packages/components/Tables/index.d'
  3 +import { useWidgetKey } from '@/packages/external/useWidgetKey'
  4 +
  5 +const { key, conKey, chartKey } = useWidgetKey('OverrideTablesBasic', true)
  6 +
  7 +export const OverrideTablesBasicConfig: ConfigType = {
  8 + key,
  9 + chartKey,
  10 + conKey,
  11 + title: '分页表格(适合告警或者设备列表)',
  12 + category: ChatCategoryEnum.TABLE,
  13 + categoryName: ChatCategoryEnumName.TABLE,
  14 + package: PackagesCategoryEnum.TABLES,
  15 + chartFrame: ChartFrameEnum.COMMON,
  16 + image: 'tables_basic.png'
  17 +}
  1 +<template>
  2 + <div class="go-tables-basic">
  3 + <n-space>
  4 + <n-form v-if="inputShow" :model="dynamicForm" :style="{ maxWidth: '640px' }" inline>
  5 + <n-form-item v-for="(item, index) in dynamicForm.keys" :key="index" :label="`${item.key.split(',').at(-2)}`">
  6 + <n-input v-model:value="item.value" clearable>
  7 + <template #prefix>
  8 + <n-icon :component="SearchIcon" />
  9 + </template>
  10 + </n-input>
  11 + </n-form-item>
  12 + </n-form>
  13 + </n-space>
  14 + <n-data-table
  15 + remote
  16 + :style="`
  17 + width: ${w}px;
  18 + height: ${h}px;
  19 + font-size: ${option.style.fontSize}px;
  20 + border-width: ${option.style.border === 'on' ? option.style.borderWidth : 0}px;
  21 + border-color: ${option.style.borderColor};
  22 + border-style: ${option.style.borderStyle}`"
  23 + :bordered="option.style.border === 'on'"
  24 + :single-column="option.style.singleColumn === 'on'"
  25 + :single-line="option.style.singleLine === 'on'"
  26 + :bottom-bordered="option.style.bottomBordered === 'on'"
  27 + :striped="option.style.striped === 'on'"
  28 + :max-height="h"
  29 + size="small"
  30 + :columns="option.dataset.dimensions"
  31 + :data="option.dataset.source"
  32 + :pagination="pagination"
  33 + />
  34 + </div>
  35 +</template>
  36 +
  37 +<script setup lang="ts">
  38 +import { PropType, toRefs, watch, reactive, ref, onMounted } from 'vue'
  39 +import { CreateComponentType } from '@/packages/index.d'
  40 +import { icon } from '@/plugins'
  41 +import { getAlarmList, getDeviceList } from '@/api/external/common'
  42 +import { useFilterFn } from '@/hooks/external/useFilterFn'
  43 +import dataJson from './data.json'
  44 +
  45 +const props = defineProps({
  46 + chartConfig: {
  47 + type: Object as PropType<CreateComponentType>,
  48 + required: true
  49 + }
  50 +})
  51 +
  52 +const { SearchIcon } = icon.ionicons5
  53 +
  54 +const { align, pagination, inputShow, dynamicForm } = toRefs(props.chartConfig.option)
  55 +
  56 +pagination.value.onChange = (page: number) => {
  57 + pagination.value.page = page
  58 +}
  59 +
  60 +const { w, h } = toRefs(props.chartConfig.attr)
  61 +
  62 +const option = reactive({
  63 + dataset: props.chartConfig.option.dataset,
  64 + style: props.chartConfig.option.style
  65 +})
  66 +
  67 +watch(
  68 + () => props.chartConfig.option.dataset,
  69 + (newData: Recordable) => {
  70 + option.dataset = newData
  71 + option?.dataset?.dimensions?.forEach((header: Recordable) => {
  72 + header.align = align.value
  73 + })
  74 + },
  75 + {
  76 + immediate: true,
  77 + deep: true
  78 + }
  79 +)
  80 +
  81 +const alarmParams = ref({})
  82 +
  83 +watch(
  84 + () => props.chartConfig.option,
  85 + newData => {
  86 + const { dynamicForm } = newData
  87 + const { keys } = dynamicForm
  88 + alarmParams.value = keys.reduce((acc: Recordable, curr: Recordable) => {
  89 + const param = {
  90 + [curr.key.split(',').at(-1)]: curr.value
  91 + }
  92 + Object.assign(acc, param)
  93 + return acc
  94 + }, {})
  95 + fetchAlarmList(props.chartConfig.filter!, props.chartConfig.request!, {
  96 + ...alarmParams.value,
  97 + page: pagination.value.page,
  98 + pageSize: pagination.value.pageSize
  99 + })
  100 + },
  101 + {
  102 + deep: true
  103 + }
  104 +)
  105 +
  106 +const fetchAlarmList = async (filterStr: string, request: Recordable, params: Recordable) => {
  107 + const { requestUrl } = request
  108 + let res = null
  109 + if (requestUrl === '/api/yt/alarm') {
  110 + res = await getAlarmList(params)
  111 + } else if (requestUrl === '/api/yt/device') {
  112 + const { page, pageSize, ...rest } = params
  113 + res = await getDeviceList(
  114 + {
  115 + page: params.page,
  116 + pageSize: params.pageSize
  117 + },
  118 + Object.keys(rest).length === 0 ? {"name": ""} : rest
  119 + )
  120 + }
  121 + if (filterStr) {
  122 + const filterRes = useFilterFn(filterStr, res)
  123 + const { value } = filterRes
  124 + option.dataset = value
  125 + pagination.value.itemCount = res.total
  126 + } else {
  127 + option.dataset = dataJson
  128 + }
  129 +}
  130 +
  131 +onMounted(() => {
  132 + fetchAlarmList(props.chartConfig.filter!, props.chartConfig.request!, {
  133 + page: pagination.value.page,
  134 + pageSize: pagination.value.pageSize
  135 + })
  136 +})
  137 +</script>
  138 +
  139 +<style lang="scss" scoped>
  140 +@include go('tables-basic') {
  141 + display: flex;
  142 + flex-direction: column;
  143 + gap: 15px;
  144 + align-items: flex-end;
  145 +}
  146 +</style>
@@ -69,6 +69,7 @@ import { Decorates24Config } from '@/packages/components/external/Decorates/Deco @@ -69,6 +69,7 @@ import { Decorates24Config } from '@/packages/components/external/Decorates/Deco
69 import { Decorates25Config } from '@/packages/components/external/Decorates/Decorates/Decorates25' 69 import { Decorates25Config } from '@/packages/components/external/Decorates/Decorates/Decorates25'
70 import { Decorates26Config } from '@/packages/components/external/Decorates/Decorates/Decorates26' 70 import { Decorates26Config } from '@/packages/components/external/Decorates/Decorates/Decorates26'
71 import { OverrideTableScrollBoardConfig } from '@/packages/components/external/Tables/Tables/OverrideTableScrollBoard' 71 import { OverrideTableScrollBoardConfig } from '@/packages/components/external/Tables/Tables/OverrideTableScrollBoard'
  72 +import { OverrideTablesBasicConfig } from '@/packages/components/external/Tables/Tables/OverrideTablesBasic'
72 73
73 74
74 /** 75 /**
@@ -156,6 +157,7 @@ export function useInjectLib(packagesList: EPackagesType) { @@ -156,6 +157,7 @@ export function useInjectLib(packagesList: EPackagesType) {
156 157
157 //列表 158 //列表
158 addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.TABLES, OverrideTableScrollBoardConfig)//重写列表下的轮播列表 159 addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.TABLES, OverrideTableScrollBoardConfig)//重写列表下的轮播列表
  160 + addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.TABLES, OverrideTablesBasicConfig)//重写列表下的轮播列表
159 // 161 //
160 } 162 }
161 163