github.com/e154/smart-home@v0.17.2-0.20240311175135-e530a6e5cd45/static_source/admin/src/views/Dashboard/index.vue (about)

     1  <script setup lang="ts">
     2  import {useI18n} from '@/hooks/web/useI18n'
     3  import {Table} from '@/components/Table'
     4  import {h, reactive, ref, watch} from 'vue'
     5  import {Pagination, TableColumn} from '@/types/table'
     6  import api from "@/api/api";
     7  import {ElButton, ElMessage} from 'element-plus'
     8  import {ApiDashboard} from "@/api/stub";
     9  import {useRouter} from "vue-router";
    10  import {parseTime} from "@/utils";
    11  import {ContentWrap} from "@/components/ContentWrap";
    12  import {Dialog} from '@/components/Dialog'
    13  import {Core} from "@/views/Dashboard/core";
    14  import {useCache} from "@/hooks/web/useCache";
    15  import {JsonEditor} from "@/components/JsonEditor";
    16  import {prepareUrl} from "@/utils/serverId";
    17  import {Infotip} from "@/components/Infotip";
    18  
    19  const {push} = useRouter()
    20  const counter = ref(0);
    21  const {t} = useI18n()
    22  const {wsCache} = useCache()
    23  
    24  interface TableObject {
    25    tableList: ApiDashboard[]
    26    params?: any
    27    loading: boolean
    28    sort?: string
    29  }
    30  
    31  interface Params {
    32    page?: number;
    33    limit?: number;
    34    sort?: string;
    35  }
    36  
    37  const cachePref = 'dashboard'
    38  const tableObject = reactive<TableObject>(
    39      {
    40        tableList: [],
    41        loading: false,
    42        sort: wsCache.get(cachePref + 'Sort') || '-createdAt'
    43      },
    44  );
    45  
    46  const columns: TableColumn[] = [
    47    {
    48      field: 'id',
    49      label: t('dashboard.id'),
    50      sortable: true,
    51      width: "60px"
    52    },
    53    {
    54      field: 'name',
    55      label: t('dashboard.name'),
    56      sortable: true,
    57      width: "170px"
    58    },
    59    {
    60      field: 'areaId',
    61      label: t('dashboard.area'),
    62      width: "100px",
    63      sortable: true,
    64      formatter: (row: ApiDashboard) => {
    65        return h(
    66            'span',
    67            row.area?.name
    68        )
    69      }
    70    },
    71    {
    72      field: 'description',
    73      sortable: true,
    74      label: t('dashboard.description')
    75    },
    76    {
    77      field: 'link',
    78      label: t('dashboard.landing'),
    79      width: "120px",
    80    },
    81    {
    82      field: 'operations',
    83      label: t('dashboard.operations'),
    84      width: "120px",
    85    },
    86    {
    87      field: 'createdAt',
    88      label: t('main.createdAt'),
    89      type: 'time',
    90      sortable: true,
    91      width: "170px",
    92      formatter: (row: ApiDashboard) => {
    93        return h(
    94            'span',
    95            parseTime(row.createdAt)
    96        )
    97      }
    98    },
    99    {
   100      field: 'updatedAt',
   101      label: t('main.updatedAt'),
   102      type: 'time',
   103      sortable: true,
   104      width: "170px",
   105      formatter: (row: ApiDashboard) => {
   106        return h(
   107            'span',
   108            parseTime(row.updatedAt)
   109        )
   110      }
   111    }
   112  ]
   113  const paginationObj = ref<Pagination>({
   114    currentPage: wsCache.get(cachePref + 'CurrentPage') || 1,
   115    pageSize: wsCache.get(cachePref + 'PageSize') || 50,
   116    total: 0,
   117  })
   118  
   119  const getList = async () => {
   120    tableObject.loading = true
   121  
   122    wsCache.set(cachePref + 'CurrentPage', paginationObj.value.currentPage)
   123    wsCache.set(cachePref + 'PageSize', paginationObj.value.pageSize)
   124    wsCache.set(cachePref + 'Sort', tableObject.sort)
   125  
   126    let params: Params = {
   127      page: paginationObj.value.currentPage,
   128      limit: paginationObj.value.pageSize,
   129      sort: tableObject.sort,
   130    }
   131  
   132    const res = await api.v1.dashboardServiceGetDashboardList(params)
   133        .catch(() => {
   134        })
   135        .finally(() => {
   136          tableObject.loading = false
   137        })
   138    if (res) {
   139      const {items, meta} = res.data;
   140      tableObject.tableList = items;
   141      paginationObj.value.currentPage = meta.pagination.page;
   142      paginationObj.value.total = meta.pagination.total;
   143      counter.value = meta.pagination.total + 1
   144    } else {
   145      tableObject.tableList = [];
   146    }
   147  }
   148  
   149  watch(
   150      () => paginationObj.value.currentPage,
   151      () => {
   152        getList()
   153      }
   154  )
   155  
   156  watch(
   157      () => paginationObj.value.pageSize,
   158      () => {
   159        getList()
   160      }
   161  )
   162  
   163  const sortChange = (data) => {
   164    const {column, prop, order} = data;
   165    const pref: string = order === 'ascending' ? '+' : '-'
   166    tableObject.sort = pref + prop
   167    getList()
   168  }
   169  
   170  getList()
   171  
   172  const addNew = () => {
   173    Core.createNew('new' + counter.value)
   174        .then((dashboard: ApiDashboard) => {
   175          ElMessage({
   176            title: t('Success'),
   177            message: t('message.createdSuccessfully'),
   178            type: 'success',
   179            duration: 2000
   180          });
   181          push({path: `/dashboards/edit/${dashboard.id}`});
   182        })
   183        .catch((e) => {
   184          counter.value++
   185        })
   186  }
   187  
   188  const editDashboard = (row: ApiDashboard) => {
   189    push(`/dashboards/edit/${row.id}`)
   190  }
   191  
   192  const showDashboard = (row: ApiDashboard) => {
   193    push(`/dashboards/view/${row.id}`)
   194  }
   195  
   196  //todo: experimental function
   197  const openLanding = (item: ApiDashboard): string => {
   198    const uri = window.location.origin || import.meta.env.VITE_API_BASEPATH as string;
   199    const accessToken = wsCache.get("accessToken")
   200    const url = prepareUrl(uri + '/#/landing/' + item.id + '?access_token=' + accessToken);
   201    window.open(url, '_blank', 'noreferrer');
   202  }
   203  
   204  const dialogVisible = ref(false)
   205  const importValue = ref(null)
   206  
   207  const importHandler = (val: any) => {
   208    if (importValue.value == val) {
   209      return
   210    }
   211    importValue.value = val
   212  }
   213  
   214  const importDashboard = async () => {
   215    let dashboard: ApiDashboard
   216    try {
   217      if (importValue.value?.json) {
   218        dashboard = importValue.value.json as ApiDashboard;
   219      } else if (importValue.value.text) {
   220        dashboard = JSON.parse(importValue.value.text) as ApiDashboard;
   221      }
   222    } catch {
   223      ElMessage({
   224        title: t('Error'),
   225        message: t('message.corruptedJsonFormat'),
   226        type: 'error',
   227        duration: 2000
   228      });
   229      return
   230    }
   231    const data = await Core._import(dashboard);
   232    if (data) {
   233      await getList();
   234      ElMessage({
   235        title: t('Success'),
   236        message: t('message.importedSuccessful'),
   237        type: 'success',
   238        duration: 2000
   239      });
   240    }
   241  }
   242  
   243  </script>
   244  
   245  <template>
   246    <ContentWrap>
   247      <ElButton class="flex mb-20px items-left" type="primary" @click="addNew()" plain>
   248        <Icon icon="ep:plus" class="mr-5px"/>
   249        {{ t('dashboard.addNewDashboard') }}
   250      </ElButton>
   251      <ElButton class="flex mb-20px items-left" type="primary" @click="dialogVisible = true" plain>
   252        {{ t('main.import') }}
   253      </ElButton>
   254  
   255      <Infotip
   256          type="warning"
   257          :show-index="false"
   258          title="WARNING"
   259          :schema="[
   260        {
   261          label: 'The functionality is experimental and may change in the future.',
   262        },
   263        {
   264          label: 'Added a landing page link that provides direct access to the dashboard. The direct link allows you to embed the dashboard into your solution.',
   265        },
   266        {
   267          label: ' &nbsp;',
   268        },
   269        {
   270          label: 'Be careful, the link contains your access token. Generate a link on behalf of a non-privileged user.',
   271        },
   272      ]"
   273      />
   274  
   275      <Table
   276          :selection="false"
   277          v-model:pageSize="paginationObj.pageSize"
   278          v-model:currentPage="paginationObj.currentPage"
   279          :showUpPagination="20"
   280          :columns="columns"
   281          :data="tableObject.tableList"
   282          :loading="tableObject.loading"
   283          :pagination="paginationObj"
   284          @sort-change="sortChange"
   285          style="width: 100%"
   286          @current-change="showDashboard"
   287      >
   288  
   289        <template #status="{ row }">
   290  
   291          <div class="w-[100%] text-center">
   292            <Icon icon="noto:green-circle" class="mr-5px" v-if="row?.isLoaded"/>
   293            <Icon icon="noto:red-circle" class="mr-5px" v-if="!row?.isLoaded"/>
   294          </div>
   295  
   296        </template>
   297  
   298        <template #link="{ row }">
   299          <div class="w-[100%] text-center landing-link">
   300            <ElButton link @click.prevent.stop="openLanding(row)">
   301              {{ $t('main.open') }}&nbsp;<Icon icon="gg:external"/>
   302            </ElButton>
   303          </div>
   304        </template>
   305  
   306        <template #operations="{ row }">
   307          <div class="w-[100%] text-center edit-link">
   308            <ElButton link @click.prevent.stop="editDashboard(row)">
   309              {{ $t('main.edit') }}
   310            </ElButton>
   311          </div>
   312        </template>
   313      </Table>
   314    </ContentWrap>
   315  
   316    <!-- import dialog -->
   317    <Dialog v-model="dialogVisible" :title="t('dashboard.dialogImportTitle')" :maxHeight="400" width="80%" custom-class>
   318      <JsonEditor @change="importHandler"/>
   319      <template #footer>
   320        <ElButton type="primary" @click="importDashboard()" plain>{{ t('main.import') }}</ElButton>
   321        <ElButton @click="dialogVisible = false">{{ t('main.closeDialog') }}</ElButton>
   322      </template>
   323    </Dialog>
   324    <!-- /import dialog -->
   325  
   326  </template>
   327  
   328  <style lang="less">
   329  
   330  .landing-link, .edit-link {
   331    .el-button {
   332      font-size: calc(100% - 1px);
   333    }
   334  
   335    .el-icon {
   336      font-size: calc(100% - 6px) !important;
   337    }
   338  }
   339  
   340  .landing-link {
   341    display: none;
   342  }
   343  
   344  .el-table__row {
   345    cursor: pointer;
   346  
   347    &:hover {
   348      .landing-link {
   349        display: inherit;
   350  
   351      }
   352    }
   353  }
   354  
   355  </style>