ソースを参照

[Wip 0000] 可配置首页及配置表格开发

houzekong 8 ヶ月 前
コミット
9f760615b0

+ 0 - 1
src/components/chart/LineMulti.vue

@@ -103,7 +103,6 @@
         if (props.option) {
           Object.assign(option, props.option);
         }
-        console.log(props.chartData);
 
         //图例类型
         // let typeArr = Array.from(new Set(props.chartData.map((item) => item.type)));

+ 0 - 1
src/layouts/default/sider/bottomSideder.vue

@@ -88,7 +88,6 @@
       }
 
       async function handleMenuClick(path: Menu) {
-        debugger;
         if (path.path == currentRoute.value.fullPath) {
           return;
         }

+ 0 - 1
src/router/guard/permissionGuard.ts

@@ -41,7 +41,6 @@ export function createPermissionGuard(router: Router) {
   const permissionStore = usePermissionStoreWithOut();
 
   router.beforeEach(async (to, from, next) => {
-    debugger;
     RootRoute.redirect = glob.homePath || PageEnum.BASE_HOME;
 
     if (_.isEmpty(history.state.current)) {

+ 50 - 28
src/views/vent/deviceManager/configurationTable/adapters.ts

@@ -1,7 +1,12 @@
 import _ from 'lodash-es';
 
-/** 将 formData 格式化为 api 需要的格式 */
-export function parseFormDataToParams(formData: Record<string, number | string | undefined>) {
+export interface ModuleData {
+  list?: Record<string, string>;
+  chart?: Record<string, string>;
+}
+
+/** 将原本的 formData 格式化为 api.saveOrUpdate 需要的格式 */
+export function parseFormDataToParams(formData: Record<string, number | string | undefined>): ModuleData {
   const params = {};
   _.forEach(formData, (v: string | undefined, k) => {
     // 如果是以 moduleData 打头的数据要特殊处理,因为这是配置的主要项目,表单配置见 ./configuration.data
@@ -15,31 +20,48 @@ export function parseFormDataToParams(formData: Record<string, number | string |
   return params;
 }
 
-/** 将 api 返回的 moduleData 格式化为可用的对象,如果传入了 data,那么会返回带数据的配置,否则返回默认配置 */
-export function parseModuleDataToObject(moduleData: string): { chart: { label: string; prop: string }[]; list: { label: string; prop: string }[] };
-export function parseModuleDataToObject(
-  moduleData: string,
-  data: any
-): { chart: { label: string; value: string }[]; list: { label: string; value: string }[] };
+/** 将 api.list 返回的 moduleData 格式化,格式化之后可以支持对应的表单以用,该方法会修改源数据 */
+export function parseModuleData(listData: { moduleData: ModuleData }) {
+  _.forEach(listData.moduleData, (v, k) => {
+    listData[`moduleData.${k}`] = JSON.stringify(v);
+  });
 
-export function parseModuleDataToObject(moduleData: string, data?: any) {
-  const raw = JSON.parse(moduleData);
-  if (data) {
-    return {
-      chart: _.map(_.get(raw, 'chart', []), (label, prop) => {
-        return { label, value: _.get(data, prop, '/') };
-      }),
-      list: _.map(_.get(raw, 'list', []), (label, prop) => {
-        return { label, value: _.get(data, prop, '/') };
-      }),
-    };
-  }
-  return {
-    chart: _.map(_.get(raw, 'chart', []), (label, prop) => {
-      return { label, prop };
-    }),
-    list: _.map(_.get(raw, 'list', []), (label, prop) => {
-      return { label, prop };
-    }),
-  };
+  return listData;
 }
+
+// export function parseModuleDataToConfig(moduleData: ModuleData): {
+//   chart: { label: string; prop: string }[];
+//   list: { label: string; prop: string }[];
+// };
+// export function parseModuleDataToConfig(
+//   moduleData: ModuleData,
+//   data: any
+// ): {
+//   chart: { label: string; value: string }[];
+//   list: { label: string; value: string }[];
+// };
+
+/** 将 api.list 返回的 moduleData 格式化为配置对象,如果传入了 data,那么会返回带数据的配置,否则返回默认配置,这些配置通常可用于页面展示 */
+// export function parseModuleDataToConfig(moduleData: ModuleData): {
+//   chart: { label: string; prop: string }[];
+//   list: { label: string; prop: string }[];
+// } {
+//   // if (data) {
+//   //   return {
+//   //     chart: _.map(_.get(moduleData, 'chart', []), (label, prop) => {
+//   //       return { label, value: _.get(data, prop, '/') };
+//   //     }),
+//   //     list: _.map(_.get(moduleData, 'list', []), (label, prop) => {
+//   //       return { label, value: _.get(data, prop, '/') };
+//   //     }),
+//   //   };
+//   // }
+//   return {
+//     chart: _.map(_.get(moduleData, 'chart', []), (label, prop) => {
+//       return { label, prop };
+//     }),
+//     list: _.map(_.get(moduleData, 'list', []), (label, prop) => {
+//       return { label, prop };
+//     }),
+//   };
+// }

+ 9 - 2
src/views/vent/deviceManager/configurationTable/configuration.api.ts

@@ -1,4 +1,4 @@
-import { parseFormDataToParams } from './adapters';
+import { parseFormDataToParams, parseModuleData } from './adapters';
 import { defHttp } from '/@/utils/http/axios';
 
 enum Api {
@@ -12,7 +12,14 @@ enum Api {
  * 列表接口
  * @param params
  */
-export const list = (params) => defHttp.post({ url: Api.list, params });
+export const list = (params) =>
+  defHttp.post({ url: Api.list, params }).then((result) => {
+    result.records.forEach((item) => {
+      parseModuleData(item);
+    });
+
+    return result;
+  });
 
 /**
  * 删除配置项

+ 32 - 19
src/views/vent/deviceManager/configurationTable/configuration.data.ts

@@ -1,9 +1,10 @@
 import { BasicColumn } from '/@/components/Table';
 import { FormSchema } from '/@/components/Table';
+import _ from 'lodash-es';
 
 export const columns: BasicColumn[] = [
   {
-    title: '所属模块',
+    title: '所属页面',
     dataIndex: 'pageType',
   },
   {
@@ -11,20 +12,32 @@ export const columns: BasicColumn[] = [
     dataIndex: 'deviceType',
   },
   {
-    title: '所展示点位及名称',
-    dataIndex: 'moduleData',
-    format: (ctx: string) => {
-      try {
-        const json = JSON.parse(ctx);
-        return Object.keys(json)
-          .map((k) => {
-            return `点位:${k};名称:${json[k]}`;
-          })
-          .join('\n');
-      } catch (e) {
-        return '渲染错误';
-      }
-    },
+    title: '主要内容配置',
+    dataIndex: 'moduleData_list',
+    // format: (ctx: any) => {
+    //   try {
+    //     if (!ctx) return '/';
+    //     return _.map(ctx.list, (v, k) => {
+    //       return `点位:${k};名称:${v}`;
+    //     }).join('\n');
+    //   } catch (e) {
+    //     return '渲染错误';
+    //   }
+    // },
+  },
+  {
+    title: '图表内容配置',
+    dataIndex: 'moduleData_chart',
+    //   format: (ctx: any) => {
+    //     try {
+    //       if (!ctx) return '/';
+    //       return _.map(ctx.chart, (v, k) => {
+    //         return `点位:${k};名称:${v}`;
+    //       }).join('<br>');
+    //     } catch (e) {
+    //       return '渲染错误';
+    //     }
+    //   },
   },
 ];
 
@@ -40,12 +53,12 @@ export const searchFormSchema: FormSchema[] = [
     colProps: { span: 6 },
   },
   {
-    label: '页面类型',
+    label: '所属页面',
     field: 'pageType',
     component: 'JDictSelectTag',
     componentProps: {
       dictCode: 'configurable_homepage',
-      placeholder: '请选择页面类型',
+      placeholder: '请选择所属页面',
     },
     colProps: { span: 6 },
   },
@@ -69,13 +82,13 @@ export const formSchema: FormSchema[] = [
     },
   },
   {
-    label: '页面类型',
+    label: '所属页面',
     field: 'pageType',
     component: 'JDictSelectTag',
     required: true,
     componentProps: {
       dictCode: 'configurable_homepage',
-      placeholder: '请选择页面类型',
+      placeholder: '请选择所属页面',
     },
   },
   {

+ 16 - 1
src/views/vent/deviceManager/configurationTable/index.vue

@@ -11,7 +11,22 @@
       title="配置列表"
       :showTab="true"
       :deviceType="deviceType"
-    />
+    >
+      <template #filterCell="{ column, record }">
+        <template v-if="column.key === 'moduleData_list'">
+          <div v-for="(val, key) in record.moduleData.list" :key="key">
+            <span>点位:{{ key }};</span>
+            <span>名称:{{ val }};</span>
+          </div>
+        </template>
+        <template v-if="column.key === 'moduleData_chart'">
+          <div v-for="(val, key) in record.moduleData.chart" :key="key">
+            <span>点位:{{ key }};</span>
+            <span>名称:{{ val }};</span>
+          </div>
+        </template>
+      </template>
+    </NormalTable>
   </div>
 </template>
 

+ 34 - 62
src/views/vent/home/configurable/components/AirVolumeMonitor.vue

@@ -8,78 +8,54 @@
       </div>
     </div>
   </CostumeHeader> -->
-  <PictorialBar
-    :option="chartOption"
-    series-prop-type="valueA"
-    x-axis-prop-type="x"
-    :chart-data="[
-      { valueA: 1, valueB: 1, x: 2 },
-      { valueA: 1, valueB: 1, x: 3 },
-      { valueA: 1, valueB: 1, x: 4 },
-      { valueA: 1, valueB: 1, x: 5 },
-      { valueA: 2, valueB: 2, x: 6 },
-      { valueA: 3, valueB: 1, x: 7 },
-      { valueA: 1, valueB: 1, x: 8 },
-    ]"
-    height="100%"
-  />
+  <PictorialBar :option="chartOption" :series-prop-type="seriesPropType" x-axis-prop-type="x" :chart-data="chartData" height="100%" />
   <!-- <div class="flex justify-around mt-10px">
     <MiniBoard v-for="item in configs" :key="item.prop" :label="item.label" :value="selectedDevice[item.prop]" />
   </div> -->
 </template>
 <script lang="ts" setup>
-  import { onMounted, ref } from 'vue';
-  import { list as cfgList } from '@/views/vent/deviceManager/configurationTable/configuration.api';
-  import { list } from '@/views/vent/deviceManager/deviceTable/device.api';
-  import CostumeHeader from './CostumeHeader.vue';
-  import { RightCircleOutlined } from '@ant-design/icons-vue';
+  import { computed, onMounted, ref } from 'vue';
   import PictorialBar from '/@/components/chart/PictorialBar.vue';
   import { EChartsOption, graphic } from 'echarts';
-  // import MiniBoard from './MiniBoard.vue';
+  import { useInitConfig } from '../hooks/useInit';
+  import _ from 'lodash-es';
   // import mapComponent from './components/3Dmap/index.vue';
 
   // 设备类别,是个枚举 TODO: 将手动换为自动获取类别
   const devicekind = 'fanlocal';
 
-  const configs = ref<{ prop: string; label: string }[]>([]);
-  function fetchConfig() {
-    cfgList({
-      deviceType: 'devicekind',
-    }).then(({ records }) => {
-      const moduleData = JSON.parse(records[0]?.moduleData);
-      configs.value = Object.keys(moduleData).map((k) => {
-        return {
-          prop: k,
-          label: moduleData[k],
-        };
-      });
-    });
-  }
+  const { configs, fetchConfig } = useInitConfig(devicekind);
 
-  const devices = ref<any[]>([]);
-  const selectedDevice = ref<any>({});
-  function selectDeviceByID(id: string) {
-    selectedDevice.value = devices.value.find((e) => {
-      return e.id === id;
-    });
-  }
-  // 获取全部局扇的数据,并以选项格式返回给 Header 消费
-  function fetchOptions() {
-    return list({
-      devicekind,
-    }).then(({ records }) => {
-      devices.value = records;
-      selectDeviceByID(records[0]?.id);
-      return records.map((e) => {
-        return {
-          label: e.strinstallpos,
-          key: e.id,
-        };
-      });
-    });
-  }
+  onMounted(() => {
+    fetchConfig();
+  });
+
+  // 适用于 PictorialBar 的 prop,即从配置中选取第一项作取值依赖
+  const seriesPropType = computed(() => {
+    if (configs.value.chart) {
+      return Object.keys(configs.value.chart)[0];
+    } else {
+      return 'y';
+    }
+  });
+
+  const chartData = ref<any[]>([
+    { valueA: 1, y: 1, x: 2 },
+    { valueA: 1, y: 1, x: 3 },
+    { valueA: 1, y: 1, x: 4 },
+    { valueA: 1, y: 1, x: 5 },
+    { valueA: 2, y: 2, x: 6 },
+    { valueA: 3, y: 1, x: 7 },
+    { valueA: 1, y: 1, x: 8 },
+  ]);
+
+  function fetchChartData() {}
 
-  // 图表相关
+  onMounted(() => {
+    fetchChartData();
+  });
+
+  // 图表的配置项
   const chartOption: EChartsOption = {
     grid: {
       top: 50,
@@ -129,9 +105,5 @@
       color: '#fff',
     },
   };
-
-  onMounted(() => {
-    fetchConfig();
-  });
 </script>
 <style scoped></style>

+ 23 - 24
src/views/vent/home/configurable/components/CostumeHeader.vue

@@ -12,8 +12,8 @@
           <CaretDownOutlined class="w-30px" v-else />
         </div>
         <template #overlay>
-          <Menu :selected-keys="[selectedKey]" @click="selectHandler">
-            <MenuItem v-for="item in options" :key="item.key" :title="item.label">
+          <Menu :selected-keys="[value]" @click="selectHandler">
+            <MenuItem v-for="item in options" :key="item.value" :title="item.label">
               {{ item.label }}
             </MenuItem>
           </Menu>
@@ -24,39 +24,38 @@
   </div>
 </template>
 <script lang="ts" setup>
-  import { onMounted, ref } from 'vue';
+  import { computed, ref } from 'vue';
   import { Dropdown, Menu, MenuItem } from 'ant-design-vue';
   import { SwapOutlined, CaretDownOutlined, CaretUpOutlined } from '@ant-design/icons-vue';
 
-  const props = defineProps<{
-    api?: () => Promise<{ label: any; key: any }[]>;
-  }>();
-  const emit = defineEmits(['change']);
+  const props = withDefaults(
+    defineProps<{
+      options: { label: any; value: any }[];
+      value: string;
+    }>(),
+    {
+      options: () => [],
+      value: '',
+    }
+  );
+  const emit = defineEmits(['change', 'update:value']);
 
   // 下拉框是否可见
   const visible = ref(false);
   // 选中的选项
-  const selectedKey = ref('');
-  const selectedLabel = ref('');
-  const options = ref<{ label: any; key: any }[]>([]);
+  const selectedLabel = computed(() => {
+    const res = props.options.find((opt) => {
+      return opt.value === props.value;
+    });
+
+    return res ? res.label : '/';
+  });
 
   // 选择了某一项
-  function selectHandler({ key, item }) {
-    selectedKey.value = key;
-    selectedLabel.value = item.title;
+  function selectHandler({ key }) {
+    emit('update:value', key);
     emit('change', key);
   }
-
-  onMounted(() => {
-    // 获取数据
-    if (!props.api) return;
-    props.api().then((opts) => {
-      options.value = opts;
-      selectHandler({ key: opts[0]?.key, item: { title: opts[0]?.label } });
-      // selectedKey.value = opts[0]?.key;
-      // selectedLabel.value = opts[0]?.label;
-    });
-  });
 </script>
 <style scoped>
   .costume-header__header {

+ 0 - 15
src/views/vent/home/configurable/components/DeviceWarning.vue

@@ -77,21 +77,6 @@
       color: 'blue',
     },
   ]);
-  // 获取全部局扇的数据,并以选项格式返回给 Header 消费
-  // function fetchOptions() {
-  //   return list({
-  //     devicekind,
-  //   }).then(({ records }) => {
-  //     devices.value = records;
-  //     selectDeviceByID(records[0]?.id);
-  //     return records.map((e) => {
-  //       return {
-  //         label: e.strinstallpos,
-  //         key: e.id,
-  //       };
-  //     });
-  //   });
-  // }
 
   onMounted(() => {
     // fetchConfig();

+ 38 - 64
src/views/vent/home/configurable/components/MonitorCenter.vue

@@ -3,43 +3,31 @@
   <div class="monitor-center pt-10px pl-2px pr-2px pb-10px">
     <div class="flex">
       <div class="monitor-center__item_A">
-        <span>吨煤通风费用(元)</span>
-        <span class="color-green">32</span>
+        <span>巷道总长度(m)</span>
+        <span class="color-green">{{ data.flength }}</span>
       </div>
       <div class="monitor-center__item_B flex flex-items-center">
         <span>吨煤通风费用(元)</span>
-        <span class="color-yellow">32</span>
+        <span class="color-yellow">{{ data.cost }}</span>
       </div>
     </div>
     <div class="flex">
       <div class="ml-7px text-center">
-        <span>总风量</span>
+        <span>总风量(m³/min)</span>
         <div class="number_grid">
-          <span>1</span>
-          <span>2</span>
-          <span>.</span>
-          <span>3</span>
-          <span>4</span>
+          <span v-for="(c, i) in data.m3Str" :key="`vhccmcc-${i}`">{{ c }}</span>
         </div>
       </div>
       <div class="ml-7px text-center">
-        <span>吨煤通风</span>
+        <span>总阻力(pa)</span>
         <div class="number_grid">
-          <span>1</span>
-          <span>2</span>
-          <span>.</span>
-          <span>3</span>
-          <span>4</span>
+          <span v-for="(c, i) in data.paStr" :key="`vhccmcc-${i}`">{{ c }}</span>
         </div>
       </div>
       <div class="ml-7px text-center">
-        <span>吨煤通风</span>
+        <span>等积孔(m³)</span>
         <div class="number_grid">
-          <span>1</span>
-          <span>2</span>
-          <span>.</span>
-          <span>3</span>
-          <span>4</span>
+          <span v-for="(c, i) in data.eStr" :key="`vhccmcc-${i}`">{{ c }}</span>
         </div>
       </div>
     </div>
@@ -53,60 +41,23 @@
 </template>
 <script lang="ts" setup>
   import { onMounted, ref } from 'vue';
-  import { list as cfgList } from '@/views/vent/deviceManager/configurationTable/configuration.api';
-  import { list } from '@/views/vent/deviceManager/deviceTable/device.api';
   import Chart from '/@/components/chart/Chart.vue';
   import { EChartsOption } from 'echarts';
+  import _ from 'lodash-es';
   // import mapComponent from './components/3Dmap/index.vue';
 
   // 设备类别,是个枚举 TODO: 将手动换为自动获取类别
-  const devicekind = 'fanlocal';
+  // const devicekind = 'fanlocal';
 
-  const configs = ref<{ prop: string; label: string }[]>([]);
-  function fetchConfig() {
-    cfgList({
-      deviceType: 'devicekind',
-    }).then(({ records }) => {
-      const moduleData = JSON.parse(records[0]?.moduleData);
-      configs.value = Object.keys(moduleData).map((k) => {
-        return {
-          prop: k,
-          label: moduleData[k],
-        };
-      });
-    });
-  }
-
-  const devices = ref<any[]>([]);
-  const selectedDevice = ref<any>({});
-  function selectDeviceByID(id: string) {
-    selectedDevice.value = devices.value.find((e) => {
-      return e.id === id;
-    });
-  }
-  // 获取全部局扇的数据,并以选项格式返回给 Header 消费
-  function fetchOptions() {
-    return list({
-      devicekind,
-    }).then(({ records }) => {
-      devices.value = records;
-      selectDeviceByID(records[0]?.id);
-      return records.map((e) => {
-        return {
-          label: e.strinstallpos,
-          key: e.id,
-        };
-      });
-    });
-  }
+  const data = ref<Record<string, any>>({});
 
   // 图表相关
-  const chartOptions = [
+  const chartOptions = ref([
     { title: '外部漏风率', option: getChartOption(40) },
     { title: '有效风量率', option: getChartOption(30) },
     { title: '灵敏度A', option: getChartOption(20) },
     { title: '灵敏度B', option: getChartOption(50) },
-  ];
+  ]);
 
   function getChartOption(percent: number): EChartsOption {
     const data = [
@@ -226,8 +177,31 @@
     };
   }
 
+  function fetchData() {
+    Promise.resolve({
+      flength: 222,
+      m3: 33333,
+      pa: 44444,
+      e: 55555,
+      cost: 111,
+      p1: 40,
+      p2: 20,
+      p3: 30,
+      p4: 10,
+    }).then((r: any) => {
+      data.value = r;
+      const reference = [r.p1, r.p2, r.p3, r.p4];
+      r.eStr = _.pad(r.e.toString(), 5, '0');
+      r.m3Str = _.pad(r.m3.toString(), 5, '0');
+      r.paStr = _.pad(r.pa.toString(), 5, '0');
+      chartOptions.value.forEach((item, i) => {
+        item.option = getChartOption(reference[i]);
+      });
+    });
+  }
+
   onMounted(() => {
-    fetchConfig();
+    fetchData();
   });
 </script>
 <style lang="less" scoped>

+ 8 - 42
src/views/vent/home/configurable/components/SubVentilate.vue

@@ -1,5 +1,5 @@
 <template>
-  <CostumeHeader :api="fetchOptions" @change="selectDeviceByID">
+  <CostumeHeader v-model:value="selectedDeviceID" :options="options">
     <div class="w-200px flex flex-items-center">
       <RightCircleOutlined class="w-30px" />
       <div class="flex-grow-1">
@@ -8,61 +8,27 @@
     </div>
   </CostumeHeader>
   <div class="flex justify-around mt-10px">
-    <MiniBoard v-for="item in configs" :key="item.prop" :label="item.label" :value="selectedDevice[item.prop]" type="A" />
+    <MiniBoard v-for="(label, prop) in configs.list" :key="`vhccsv-${prop}`" :label="label" :value="get(selectedDevice, prop)" type="A" />
   </div>
 </template>
 <script lang="ts" setup>
-  import { onMounted, ref } from 'vue';
-  import { list as cfgList } from '@/views/vent/deviceManager/configurationTable/configuration.api';
-  import { list } from '@/views/vent/deviceManager/deviceTable/device.api';
+  import { onMounted } from 'vue';
   import CostumeHeader from './CostumeHeader.vue';
   import { RightCircleOutlined } from '@ant-design/icons-vue';
   import MiniBoard from './MiniBoard.vue';
+  import { useInitConfig, useInitDevices } from '../hooks/useInit';
+  import { get } from '../../billboard/utils';
   // import mapComponent from './components/3Dmap/index.vue';
 
   // 设备类别,是个枚举 TODO: 将手动换为自动获取类别
   const devicekind = 'fanlocal';
 
-  const configs = ref<{ prop: string; label: string }[]>([]);
-  function fetchConfig() {
-    cfgList({
-      deviceType: 'devicekind',
-    }).then(({ records }) => {
-      const moduleData = JSON.parse(records[0]?.moduleData);
-      configs.value = Object.keys(moduleData).map((k) => {
-        return {
-          prop: k,
-          label: moduleData[k],
-        };
-      });
-    });
-  }
-
-  const devices = ref<any[]>([]);
-  const selectedDevice = ref<any>({});
-  function selectDeviceByID(id: string) {
-    selectedDevice.value = devices.value.find((e) => {
-      return e.id === id;
-    });
-  }
-  // 获取全部局扇的数据,并以选项格式返回给 Header 消费
-  function fetchOptions() {
-    return list({
-      devicekind,
-    }).then(({ records }) => {
-      devices.value = records;
-      selectDeviceByID(records[0]?.id);
-      return records.map((e) => {
-        return {
-          label: e.strinstallpos,
-          key: e.id,
-        };
-      });
-    });
-  }
+  const { configs, fetchConfig } = useInitConfig(devicekind);
+  const { options, selectedDevice, selectedDeviceID, fetchDevices } = useInitDevices(devicekind);
 
   onMounted(() => {
     fetchConfig();
+    fetchDevices();
   });
 </script>
 <style scoped></style>

+ 8 - 42
src/views/vent/home/configurable/components/Ventilate.vue

@@ -1,6 +1,6 @@
 <!-- eslint-disable vue/multi-word-component-names -->
 <template>
-  <CostumeHeader :api="fetchOptions" @change="selectDeviceByID">
+  <CostumeHeader v-model:value="selectedDeviceID" :options="options">
     <div class="w-200px flex flex-items-center">
       <RightCircleOutlined class="w-30px" />
       <div class="flex-grow-1">
@@ -9,61 +9,27 @@
     </div>
   </CostumeHeader>
   <div class="flex justify-around mt-10px">
-    <MiniBoard v-for="item in configs" :key="item.prop" :label="item.label" :value="selectedDevice[item.prop]" type="C" />
+    <MiniBoard v-for="(label, prop) in configs.list" :key="`vhccv-${prop}`" :label="label" :value="get(selectedDevice, prop)" type="C" />
   </div>
 </template>
 <script lang="ts" setup>
-  import { onMounted, ref } from 'vue';
-  import { list as cfgList } from '@/views/vent/deviceManager/configurationTable/configuration.api';
-  import { list } from '@/views/vent/deviceManager/deviceTable/device.api';
+  import { onMounted } from 'vue';
   import CostumeHeader from './CostumeHeader.vue';
   import { RightCircleOutlined } from '@ant-design/icons-vue';
   import MiniBoard from './MiniBoard.vue';
+  import { useInitConfig, useInitDevices } from '../hooks/useInit';
+  import { get } from '../../billboard/utils';
   // import mapComponent from './components/3Dmap/index.vue';
 
   // 设备类别,是个枚举 TODO: 将手动换为自动获取类别
   const devicekind = 'fanmain';
 
-  const configs = ref<{ prop: string; label: string }[]>([]);
-  function fetchConfig() {
-    cfgList({
-      deviceType: 'devicekind',
-    }).then(({ records }) => {
-      const moduleData = JSON.parse(records[0]?.moduleData);
-      configs.value = Object.keys(moduleData).map((k) => {
-        return {
-          prop: k,
-          label: moduleData[k],
-        };
-      });
-    });
-  }
-
-  const devices = ref<any[]>([]);
-  const selectedDevice = ref<any>({});
-  function selectDeviceByID(id: string) {
-    selectedDevice.value = devices.value.find((e) => {
-      return e.id === id;
-    });
-  }
-  // 获取全部局扇的数据,并以选项格式返回给 Header 消费
-  function fetchOptions() {
-    return list({
-      devicekind,
-    }).then(({ records }) => {
-      devices.value = records;
-      selectDeviceByID(records[0]?.id);
-      return records.map((e) => {
-        return {
-          label: e.strinstallpos,
-          key: e.id,
-        };
-      });
-    });
-  }
+  const { configs, fetchConfig } = useInitConfig(devicekind);
+  const { options, selectedDevice, selectedDeviceID, fetchDevices } = useInitDevices(devicekind);
 
   onMounted(() => {
     fetchConfig();
+    fetchDevices();
   });
 </script>
 <style scoped></style>

+ 45 - 58
src/views/vent/home/configurable/components/VentilateAnalysis.vue

@@ -1,6 +1,6 @@
 <!-- eslint-disable vue/multi-word-component-names -->
 <template>
-  <CostumeHeader :api="fetchOptions" @change="selectDeviceByID">
+  <CostumeHeader v-model:value="selectedDeviceID" :options="options">
     <!-- <div class="w-200px flex flex-items-center">
       <RightCircleOutlined class="w-30px" />
       <div class="flex-grow-1">
@@ -8,77 +8,68 @@
       </div>
     </div> -->
   </CostumeHeader>
-  <Pie
-    :option="chartOption"
-    :chart-data="[
-      {
-        value: 70,
-        name: 'A',
-      },
-      {
-        value: 30,
-        name: 'B',
-      },
-    ]"
-    height="140px"
-  />
+  <Pie :option="chartOption" :chart-data="chartData" height="140px" />
   <div class="flex justify-around mt-10px">
-    <MiniBoard v-for="item in configs" :key="item.prop" :label="item.label" :value="selectedDevice[item.prop]" layout="label-top" type="D" />
+    <MiniBoard
+      v-for="(label, prop) in configs.list"
+      :key="`vhccva-${prop}`"
+      :label="label"
+      :value="get(selectedDevice, prop)"
+      layout="label-top"
+      type="D"
+    />
   </div>
 </template>
 <script lang="ts" setup>
-  import { onMounted, ref } from 'vue';
-  import { list as cfgList } from '@/views/vent/deviceManager/configurationTable/configuration.api';
-  import { list } from '@/views/vent/deviceManager/deviceTable/device.api';
   import CostumeHeader from './CostumeHeader.vue';
-  import { RightCircleOutlined } from '@ant-design/icons-vue';
-  import MiniBoard from './MiniBoard.vue';
+  import { onMounted, ref } from 'vue';
   import Pie from '/@/components/chart/Pie.vue';
   import { EChartsOption } from 'echarts';
+  import { useInitConfig, useInitDevices } from '../hooks/useInit';
+  import { get } from '../../billboard/utils';
+  import _ from 'lodash-es';
+  import MiniBoard from './MiniBoard.vue';
   // import mapComponent from './components/3Dmap/index.vue';
 
   // 设备类别,是个枚举 TODO: 将手动换为自动获取类别
-  const devicekind = 'windrect';
+  const devicekind = 'fanlocal';
 
-  const configs = ref<{ prop: string; label: string }[]>([]);
-  function fetchConfig() {
-    cfgList({
-      deviceType: 'devicekind',
-    }).then(({ records }) => {
-      const moduleData = JSON.parse(records[0]?.moduleData);
-      configs.value = Object.keys(moduleData).map((k) => {
-        return {
-          prop: k,
-          label: moduleData[k],
-        };
-      });
-    });
-  }
+  const { configs, fetchConfig } = useInitConfig(devicekind);
+  const { options, selectedDevice, selectedDeviceID, fetchDevices } = useInitDevices(devicekind);
 
-  const devices = ref<any[]>([]);
-  const selectedDevice = ref<any>({});
-  function selectDeviceByID(id: string) {
-    selectedDevice.value = devices.value.find((e) => {
-      return e.id === id;
-    });
-  }
-  // 获取全部局扇的数据,并以选项格式返回给 Header 消费
-  function fetchOptions() {
-    return list({
-      devicekind,
-    }).then(({ records }) => {
-      devices.value = records;
-      selectDeviceByID(records[0]?.id);
-      return records.map((e) => {
+  onMounted(() => {
+    fetchConfig();
+    fetchDevices();
+  });
+
+  const chartData = ref<any[]>([
+    {
+      value: 70,
+      name: 'A',
+    },
+    {
+      value: 30,
+      name: 'B',
+    },
+  ]);
+
+  function fetchChartData() {
+    return;
+    Promise.resolve({ a: 3, b: 7 }).then((res) => {
+      chartData.value = _.map(configs.value.chart || [], (label, prop) => {
         return {
-          label: e.strinstallpos,
-          key: e.id,
+          value: _.get(res, prop),
+          name: label,
         };
       });
     });
   }
 
-  // 图标相关
+  onMounted(() => {
+    fetchChartData();
+  });
+
+  // 图表配置项
   const chartOption: EChartsOption = {
     series: [
       {
@@ -100,9 +91,5 @@
     ],
     color: ['#d9a1ff', '#00d1ff', '#82fe78'],
   };
-
-  onMounted(() => {
-    fetchConfig();
-  });
 </script>
 <style scoped></style>

+ 8 - 42
src/views/vent/home/configurable/components/VentilateControl.vue

@@ -1,6 +1,6 @@
 <!-- eslint-disable vue/multi-word-component-names -->
 <template>
-  <CostumeHeader :api="fetchOptions" @change="selectDeviceByID">
+  <CostumeHeader v-model:value="selectedDeviceID" :options="options">
     <div class="w-200px flex flex-items-center">
       <RightCircleOutlined class="w-30px" />
       <div class="flex-grow-1">
@@ -13,57 +13,23 @@
   </div> -->
 </template>
 <script lang="ts" setup>
-  import { onMounted, ref } from 'vue';
-  import { list as cfgList } from '@/views/vent/deviceManager/configurationTable/configuration.api';
-  import { list } from '@/views/vent/deviceManager/deviceTable/device.api';
+  import { onMounted } from 'vue';
   import CostumeHeader from './CostumeHeader.vue';
   import { RightCircleOutlined } from '@ant-design/icons-vue';
   // import MiniBoard from './MiniBoard.vue';
+  import { useInitDevices } from '../hooks/useInit';
+  // import { get } from '../../billboard/utils';
   // import mapComponent from './components/3Dmap/index.vue';
 
   // 设备类别,是个枚举 TODO: 将手动换为自动获取类别
   const devicekind = 'fanlocal';
 
-  const configs = ref<{ prop: string; label: string }[]>([]);
-  function fetchConfig() {
-    cfgList({
-      deviceType: 'devicekind',
-    }).then(({ records }) => {
-      const moduleData = JSON.parse(records[0]?.moduleData);
-      configs.value = Object.keys(moduleData).map((k) => {
-        return {
-          prop: k,
-          label: moduleData[k],
-        };
-      });
-    });
-  }
-
-  const devices = ref<any[]>([]);
-  const selectedDevice = ref<any>({});
-  function selectDeviceByID(id: string) {
-    selectedDevice.value = devices.value.find((e) => {
-      return e.id === id;
-    });
-  }
-  // 获取全部局扇的数据,并以选项格式返回给 Header 消费
-  function fetchOptions() {
-    return list({
-      devicekind,
-    }).then(({ records }) => {
-      devices.value = records;
-      selectDeviceByID(records[0]?.id);
-      return records.map((e) => {
-        return {
-          label: e.strinstallpos,
-          key: e.id,
-        };
-      });
-    });
-  }
+  // const { configs, fetchConfig } = useInitConfig(devicekind);
+  const { options, selectedDevice, selectedDeviceID, fetchDevices } = useInitDevices(devicekind);
 
   onMounted(() => {
-    fetchConfig();
+    // fetchConfig();
+    fetchDevices();
   });
 </script>
 <style scoped></style>

+ 53 - 61
src/views/vent/home/configurable/components/WorkSurface.vue

@@ -1,6 +1,6 @@
 <!-- eslint-disable vue/multi-word-component-names -->
 <template>
-  <CostumeHeader :api="fetchOptions" @change="selectDeviceByID">
+  <CostumeHeader v-model:value="selectedDeviceID" :options="options">
     <!-- <div class="w-200px flex flex-items-center">
       <RightCircleOutlined class="w-30px" />
       <div class="flex-grow-1">
@@ -10,79 +10,75 @@
   </CostumeHeader>
   <LineMulti
     :option="chartOption"
-    :prop-type-arr="
-      new Map([
-        ['valueA', '值A'],
-        ['valueB', '值B'],
-      ])
-    "
+    :prop-type-arr="propTypeArr"
     x-axis-prop-type="x"
-    :chart-data="[
-      { valueA: 1, valueB: 3, x: 2 },
-      { valueA: 2, valueB: 1, x: 3 },
-      { valueA: 1, valueB: 1, x: 4 },
-      { valueA: 3, valueB: 2, x: 5 },
-      { valueA: 2, valueB: 1, x: 6 },
-      { valueA: 1, valueB: 2, x: 7 },
-    ]"
+    :chart-data="chartData"
     height="140px"
     class="worksurface-chart"
   />
   <div class="flex justify-around">
-    <MiniBoard v-for="item in configs" :key="item.prop" :label="item.label" :value="selectedDevice[item.prop]" layout="label-top" type="B" />
+    <MiniBoard
+      v-for="(label, prop) in configs.list"
+      :key="`vhccws-${prop}`"
+      :label="label"
+      :value="get(selectedDevice, prop)"
+      layout="label-top"
+      type="B"
+    />
   </div>
 </template>
 <script lang="ts" setup>
-  import { onMounted, ref } from 'vue';
-  import { list as cfgList } from '@/views/vent/deviceManager/configurationTable/configuration.api';
-  import { list } from '@/views/vent/deviceManager/deviceTable/device.api';
-  import CostumeHeader from './CostumeHeader.vue';
-  import { RightCircleOutlined } from '@ant-design/icons-vue';
-  import MiniBoard from './MiniBoard.vue';
   import LineMulti from '/@/components/chart/LineMulti.vue';
+  import CostumeHeader from './CostumeHeader.vue';
+  import { computed, onMounted, ref } from 'vue';
   import { EChartsOption } from 'echarts';
+  import { useInitConfig, useInitDevices } from '../hooks/useInit';
+  import { get } from '../../billboard/utils';
+  import _ from 'lodash-es';
+  import MiniBoard from './MiniBoard.vue';
   // import mapComponent from './components/3Dmap/index.vue';
 
   // 设备类别,是个枚举 TODO: 将手动换为自动获取类别
   const devicekind = 'fanlocal';
 
-  const configs = ref<{ prop: string; label: string }[]>([]);
-  function fetchConfig() {
-    cfgList({
-      deviceType: 'devicekind',
-    }).then(({ records }) => {
-      const moduleData = JSON.parse(records[0]?.moduleData);
-      configs.value = Object.keys(moduleData).map((k) => {
-        return {
-          prop: k,
-          label: moduleData[k],
-        };
-      });
-    });
-  }
+  const { configs, fetchConfig } = useInitConfig(devicekind);
+  const { options, selectedDevice, selectedDeviceID, fetchDevices } = useInitDevices(devicekind);
 
-  const devices = ref<any[]>([]);
-  const selectedDevice = ref<any>({});
-  function selectDeviceByID(id: string) {
-    selectedDevice.value = devices.value.find((e) => {
-      return e.id === id;
-    });
-  }
-  // 获取全部局扇的数据,并以选项格式返回给 Header 消费
-  function fetchOptions() {
-    return list({
-      devicekind,
-    }).then(({ records }) => {
-      devices.value = records;
-      selectDeviceByID(records[0]?.id);
-      return records.map((e) => {
-        return {
-          label: e.strinstallpos,
-          key: e.id,
-        };
+  onMounted(() => {
+    fetchConfig();
+    fetchDevices();
+  });
+
+  const chartData = ref<any[]>([
+    { valueA: 1, valueB: 3, x: 2 },
+    { valueA: 2, valueB: 1, x: 3 },
+    { valueA: 1, valueB: 1, x: 4 },
+    { valueA: 3, valueB: 2, x: 5 },
+    { valueA: 2, valueB: 1, x: 6 },
+    { valueA: 1, valueB: 2, x: 7 },
+  ]);
+
+  const propTypeArr = computed(() => {
+    if (configs.value.chart) {
+      const map = new Map();
+      _.forEach(configs.value.chart || [], (label, prop) => {
+        map.set(prop, label);
       });
-    });
-  }
+
+      return map;
+    } else {
+      return new Map([
+        ['valueA', '值A'],
+        ['valueB', '值B'],
+      ]);
+    }
+  });
+
+  function fetchChartData() {}
+
+  onMounted(() => {
+    fetchChartData();
+  });
 
   // 图表相关
   const chartOption: EChartsOption = {
@@ -112,10 +108,6 @@
     backgroundColor: '#081f33',
     // backgroundColor: '#0091ff12',
   };
-
-  onMounted(() => {
-    fetchConfig();
-  });
 </script>
 <style scoped lang="less">
   @import '@/design/vent/color.less';

+ 58 - 0
src/views/vent/home/configurable/hooks/useInit.ts

@@ -0,0 +1,58 @@
+import { computed, ref } from 'vue';
+import { list as cfgList } from '@/views/vent/deviceManager/configurationTable/configuration.api';
+import { list } from '@/views/vent/deviceManager/deviceTable/device.api';
+import { ModuleData } from '@/views/vent/deviceManager/configurationTable/adapters';
+// import mapComponent from './components/3Dmap/index.vue';
+
+export function useInitConfig(deviceType: string) {
+  function fetchConfig() {
+    cfgList({
+      deviceType,
+    }).then(({ records }) => {
+      configs.value = records[0]?.moduleData;
+    });
+  }
+  const configs = ref<ModuleData>({});
+
+  return {
+    fetchConfig,
+    configs,
+  };
+}
+
+export function useInitDevices(devicekind: string) {
+  const devices = ref<Record<string, any>[]>([]);
+  const options = ref<{ label: string; value: string }[]>([]);
+  const selectedDeviceID = ref<string>('');
+
+  const selectedDevice = computed(() => {
+    return (
+      devices.value.find((e) => {
+        return e.id === selectedDeviceID.value;
+      }) || {}
+    );
+  });
+
+  // 获取设备数据,赋值并以选项格式返回给 Header 消费
+  function fetchDevices() {
+    return list({
+      devicekind,
+    }).then(({ records }) => {
+      devices.value = records;
+      selectedDeviceID.value = records[0]?.id;
+      options.value = records.map((e) => {
+        return {
+          label: e.strinstallpos,
+          value: e.id,
+        };
+      });
+    });
+  }
+
+  return {
+    fetchDevices,
+    selectedDevice,
+    selectedDeviceID,
+    options,
+  };
+}

+ 2 - 1
src/views/vent/home/configurable/index.vue

@@ -1,3 +1,4 @@
+<!-- eslint-disable vue/multi-word-component-names -->
 <template>
   <div class="company-home">
     <div class="top-bg">
@@ -37,7 +38,7 @@
   </div>
 </template>
 <script lang="ts" setup>
-  import { computed, ref } from 'vue';
+  import { ref } from 'vue';
   import ModuleLeft from './components/moduleLeft.vue';
   import ModuleRight from './components/moduleRight.vue';
   import ModuleBottom from './components/moduleBottom.vue';