Commit c158d755d19c4ba9dbb1d9aea35d94b9454bd4d9

Authored by ww
1 parent 67a97b78

wip: implement data board list page

  1 +import {
  2 + AddDataBoardParams,
  3 + DataBoardList,
  4 + GetDataBoardParams,
  5 + UpdateDataBoardParams,
  6 +} from './model';
  7 +import { defHttp } from '/@/utils/http/axios';
  8 +
  9 +enum DataBoardUrl {
  10 + GET_DATA_BOARD = '/data_board',
  11 + ADD_DATA_BOARD = '/data_board/add',
  12 + DELETE_DATA_BOARD = '/data_board',
  13 + UPDATE_DATA_BOARD = '/data_board/update',
  14 +}
  15 +
  16 +/**
  17 + * @description 获取数据看板
  18 + * @param params
  19 + * @returns
  20 + */
  21 +export const getDataBoardList = (params: GetDataBoardParams) => {
  22 + return defHttp.get<DataBoardList>({
  23 + url: DataBoardUrl.GET_DATA_BOARD,
  24 + params,
  25 + });
  26 +};
  27 +
  28 +/**
  29 + * @description 新增数据看板
  30 + * @param params
  31 + * @returns
  32 + */
  33 +export const addDataBoard = (params: AddDataBoardParams) => {
  34 + return defHttp.post({
  35 + url: DataBoardUrl.ADD_DATA_BOARD,
  36 + params,
  37 + });
  38 +};
  39 +
  40 +/**
  41 + * @description 编辑数据看吧
  42 + * @param params
  43 + * @returns
  44 + */
  45 +export const updateDataBoard = (params: UpdateDataBoardParams) => {
  46 + return defHttp.post({
  47 + url: DataBoardUrl.UPDATE_DATA_BOARD,
  48 + params,
  49 + });
  50 +};
  51 +
  52 +/**
  53 + * @description 删除数据看板
  54 + * @param params
  55 + * @returns
  56 + */
  57 +export const deleteDataBoard = (params: string[]) => {
  58 + return defHttp.delete({
  59 + url: DataBoardUrl.DELETE_DATA_BOARD,
  60 + params: { ids: params },
  61 + });
  62 +};
... ...
  1 +export interface AddDataBoardParams {
  2 + name: string;
  3 + viewType: string;
  4 + remark?: string;
  5 +}
  6 +
  7 +export interface UpdateDataBoardParams extends AddDataBoardParams {
  8 + id: string;
  9 +}
  10 +
  11 +export interface GetDataBoardParams {
  12 + page?: number;
  13 + pageSize?: number;
  14 + orderFiled?: string;
  15 + orderType?: string;
  16 +}
  17 +
  18 +export interface Layout {
  19 + h: number;
  20 + id: string;
  21 + w: number;
  22 + x: number;
  23 + y: number;
  24 +}
  25 +
  26 +export interface Layout {
  27 + h: number;
  28 + id: string;
  29 + w: number;
  30 + x: number;
  31 + y: number;
  32 +}
  33 +
  34 +export interface DataBoardRecord {
  35 + name: string;
  36 + roleIds: string[];
  37 + updater: string;
  38 + description: string;
  39 + remark: string;
  40 + viewType: string;
  41 + enabled: boolean;
  42 + updateTime: string;
  43 + createTime: string;
  44 + tenantProfileId: string;
  45 + id: string;
  46 + tenantExpireTime: string;
  47 + icon: string;
  48 + openUrl: string;
  49 + tenantId: string;
  50 + creator: string;
  51 + layout: Layout[];
  52 + defaultConfig: string;
  53 + tenantStatus: string;
  54 +}
  55 +
  56 +export interface DataBoardList {
  57 + items: DataBoardRecord[];
  58 + total: number;
  59 +}
... ...
src/views/data/board/components/Other/CommandSendButton.vue renamed from src/views/data/board/components/CommandSendButton.vue
src/views/data/board/components/Other/IndicatorLight.vue renamed from src/views/data/board/components/IndicatorLight.vue
src/views/data/board/components/Other/InformationPanel.vue renamed from src/views/data/board/components/InformationPanel.vue
src/views/data/board/components/Other/LightBulbSwitch.vue renamed from src/views/data/board/components/LightBulbSwitch.vue
src/views/data/board/components/Other/RockerSwitch.vue renamed from src/views/data/board/components/RockerSwitch.vue
src/views/data/board/components/Other/SlidingSwitch.vue renamed from src/views/data/board/components/SlidingSwitch.vue
src/views/data/board/components/Other/ToggleSwitch.vue renamed from src/views/data/board/components/ToggleSwitch.vue
  1 +<script lang="ts" setup>
  2 + import { BasicModal, useModalInner } from '/@/components/Modal';
  3 + import { BasicForm, useForm } from '/@/components/Form';
  4 + import { formSchema } from '../config/panelDetail';
  5 + import { addDataBoard, updateDataBoard } from '/@/api/dataBoard';
  6 + import { AddDataBoardParams } from '/@/api/dataBoard/model';
  7 + import { useMessage } from '/@/hooks/web/useMessage';
  8 + import type { DataBoardRecord, UpdateDataBoardParams } from '/@/api/dataBoard/model';
  9 + import { ref, unref } from 'vue';
  10 +
  11 + const emit = defineEmits(['change']);
  12 +
  13 + const isEdit = ref(false);
  14 + const recordId = ref<Nullable<string>>(null);
  15 +
  16 + const [registerModal, { changeLoading, closeModal }] = useModalInner(
  17 + (record: DataBoardRecord & { isEdit: boolean }) => {
  18 + method.setFieldsValue(record);
  19 + recordId.value = record.id;
  20 + isEdit.value = record.isEdit;
  21 + }
  22 + );
  23 +
  24 + const [registerForm, method] = useForm({
  25 + showActionButtonGroup: false,
  26 + schemas: formSchema,
  27 + labelWidth: 80,
  28 + });
  29 +
  30 + const { createMessage } = useMessage();
  31 +
  32 + const handleCreatePanel = async () => {
  33 + try {
  34 + const value = method.getFieldsValue() as AddDataBoardParams;
  35 + changeLoading(true);
  36 + await addDataBoard(value);
  37 + createMessage.success('创建成功');
  38 + closeModal();
  39 + emit('change');
  40 + } catch (error) {
  41 + createMessage.error('创建失败');
  42 + } finally {
  43 + changeLoading(false);
  44 + }
  45 + };
  46 +
  47 + const handleEditPanel = async () => {
  48 + try {
  49 + const value = method.getFieldsValue() as UpdateDataBoardParams;
  50 + value.id = unref(recordId) as string;
  51 + changeLoading(true);
  52 + await updateDataBoard(value);
  53 + createMessage.success('编辑成功');
  54 + closeModal();
  55 + emit('change');
  56 + } catch (error) {
  57 + createMessage.error('编辑失败');
  58 + } finally {
  59 + changeLoading(false);
  60 + }
  61 + };
  62 +
  63 + const handleGetValue = () => {
  64 + unref(isEdit) ? handleEditPanel() : handleCreatePanel();
  65 + };
  66 +</script>
  67 +
  68 +<template>
  69 + <BasicModal
  70 + v-bind="$attrs"
  71 + :destroyOnClose="true"
  72 + :title="isEdit ? '编辑看板' : '创建看板'"
  73 + @register="registerModal"
  74 + @ok="handleGetValue"
  75 + >
  76 + <BasicForm @register="registerForm" />
  77 + </BasicModal>
  78 +</template>
  79 +
  80 +<style scoped></style>
... ...
  1 +import { FormSchema } from '/@/components/Form';
  2 +export enum ViewType {
  3 + PRIVATE_VIEW = 'PRIVATE_VIEW',
  4 + PUBLIC_VIEW = 'PUBLIC_VIEW',
  5 +}
  6 +
  7 +export const formSchema: FormSchema[] = [
  8 + {
  9 + field: 'name',
  10 + label: '名称',
  11 + component: 'Input',
  12 + required: true,
  13 + componentProps: {
  14 + placeholder: '请输入看板名称',
  15 + },
  16 + },
  17 + {
  18 + field: 'viewType',
  19 + label: '名称',
  20 + component: 'RadioGroup',
  21 + defaultValue: ViewType.PRIVATE_VIEW,
  22 + helpMessage: [
  23 + '私有视图只有项目成员可以浏览。公开视图拥有一个公开的 URL,任何人无需登录即可浏览。 ',
  24 + ],
  25 + componentProps: {
  26 + placeholder: '请选择公开性',
  27 + options: [
  28 + { label: '私有看板', value: ViewType.PRIVATE_VIEW },
  29 + { label: '公开看板', value: ViewType.PUBLIC_VIEW },
  30 + ],
  31 + },
  32 + },
  33 + {
  34 + field: 'remark',
  35 + label: '备注',
  36 + component: 'InputTextArea',
  37 + componentProps: {
  38 + placeholder: '请输入看板备注',
  39 + },
  40 + },
  41 +];
... ...
... ... @@ -4,7 +4,7 @@
4 4 import { nextTick, ref } from 'vue';
5 5 import WidgetWrapper from '../components/WidgetWrapper/WidgetWrapper.vue';
6 6 import BaseWidgetHeader from '../components/WidgetHeader/BaseWidgetHeader.vue';
7   - import InformationPanel from '../components/InformationPanel.vue';
  7 + import InformationPanel from '../components/Other/InformationPanel.vue';
8 8 import { DropMenu } from '/@/components/Dropdown';
9 9 import DataBindModal from './components/DataBindModal.vue';
10 10 import { useModal } from '/@/components/Modal';
... ...
1 1 <script lang="ts" setup>
2   - import { List, Card, Statistic } from 'ant-design-vue';
3   - import { ref, unref } from 'vue';
  2 + import { List, Card, Statistic, Button, Tooltip } from 'ant-design-vue';
  3 + import { onMounted, ref, unref } from 'vue';
4 4 import { PageWrapper } from '/@/components/Page';
5 5 import { MoreOutlined, ShareAltOutlined } from '@ant-design/icons-vue';
6 6 import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
7 7 import { useMessage } from '/@/hooks/web/useMessage';
8   - import { useRouter } from 'vue-router';
9 8 import Dropdown from '/@/components/Dropdown/src/Dropdown.vue';
10 9 import { DropMenu } from '/@/components/Dropdown';
11 10 import { MoreActionEvent } from './config/config';
12   - const ListItem = List.Item;
  11 + import { useModal } from '/@/components/Modal';
  12 + import PanelDetailModal from './components/PanelDetailModal.vue';
  13 + import { getDataBoardList, deleteDataBoard } from '/@/api/dataBoard';
  14 + import { DataBoardRecord } from '/@/api/dataBoard/model';
  15 + import { ViewType } from './config/panelDetail';
  16 + import { useRouter } from 'vue-router';
13 17
  18 + const ListItem = List.Item;
14 19 const router = useRouter();
  20 +
15 21 const { createMessage } = useMessage();
16 22
17   - const data = ref([{ title: 1 }, { title: 2 }, { title: 3 }]);
  23 + const dataBoardList = ref<DataBoardRecord[]>([]);
18 24 //分页相关
19 25 const page = ref(1);
20 26 const pageSize = ref(36);
... ... @@ -39,8 +45,8 @@
39 45 }
40 46
41 47 const { clipboardRef } = useCopyToClipboard();
42   - const handleCopyShareUrl = () => {
43   - clipboardRef.value = '123';
  48 + const handleCopyShareUrl = (record: DataBoardRecord) => {
  49 + clipboardRef.value = record.openUrl;
44 50 unref(clipboardRef) && createMessage.success('复制成功');
45 51 };
46 52
... ... @@ -57,34 +63,75 @@
57 63 },
58 64 ];
59 65
60   - const handleMenuEvent = (event: DropMenu) => {
61   - if (event.event === MoreActionEvent.EDIT) {
62   - handleEdit();
  66 + const getDatasource = async () => {
  67 + try {
  68 + const { total, items } = await getDataBoardList({
  69 + page: unref(paginationProp).current,
  70 + pageSize: unref(paginationProp).pageSize,
  71 + });
  72 + dataBoardList.value = items;
  73 + paginationProp.value.total = total;
  74 + } catch (error) {
  75 + } finally {
63 76 }
64 77 };
65 78
66   - const handleEdit = () => {
67   - router.push('/data/board/detail/1234');
  79 + const handleMenuEvent = (event: DropMenu, record: DataBoardRecord) => {
  80 + if (event.event === MoreActionEvent.EDIT) handleEdit(record);
  81 + if (event.event === MoreActionEvent.DELETE) handleRemove(record);
  82 + };
  83 +
  84 + const handleEdit = (record: DataBoardRecord) => {
  85 + openModal(true, {
  86 + isEdit: true,
  87 + ...record,
  88 + });
  89 + };
  90 +
  91 + const handleOpenDetailModal = () => {
  92 + openModal();
68 93 };
69 94
70   - const handleRemove = () => {};
  95 + const handleRemove = async (record: DataBoardRecord) => {
  96 + // TODO 删除确认
  97 + try {
  98 + await deleteDataBoard([record.id]);
  99 + createMessage.success('删除成功');
  100 + await getDatasource();
  101 + } catch (error) {
  102 + createMessage.error('删除失败');
  103 + }
  104 + };
  105 +
  106 + const [registerModal, { openModal }] = useModal();
  107 +
  108 + const handleViewBoard = (record: DataBoardRecord) => {
  109 + router.push(`/data/board/detail/${record.id}`);
  110 + };
  111 +
  112 + onMounted(() => {
  113 + getDatasource();
  114 + });
71 115 </script>
72 116
73 117 <template>
74 118 <PageWrapper>
75   - <template #header> 自定义看板 </template>
  119 + <div class="flex mb-6 items-center">
  120 + <div class="text-lg mr-6 font-bold">自定义看板</div>
  121 + <Button type="primary" @click="handleOpenDetailModal">创建看板</Button>
  122 + </div>
76 123 <List
77 124 :pagination="paginationProp"
78   - :data-source="data"
  125 + :data-source="dataBoardList"
79 126 :grid="{ gutter: 5, column: 4, xs: 1, sm: 2, md: 2, lg: 3, xl: 3, xxl: 3 }"
80 127 >
81 128 <template #renderItem="{ item }">
82 129 <ListItem>
83   - <Card class="data-card cursor-pointer">
  130 + <Card class="data-card cursor-pointer" @click="handleViewBoard(item)">
84 131 <template #extra>
85 132 <Dropdown
86 133 :trigger="['click']"
87   - @menu-event="handleMenuEvent"
  134 + @menu-event="(event) => handleMenuEvent(event, item)"
88 135 :drop-menu-list="dropMenuList"
89 136 >
90 137 <MoreOutlined class="rotate-90 transform cursor-pointer" />
... ... @@ -93,7 +140,7 @@
93 140 <!-- <template #cover>title</template> -->
94 141 <section>
95 142 <div class="flex justify-between items-center">
96   - <div>设备看板名</div>
  143 + <div>{{ item.name }}</div>
97 144 <div class="flex content-center">
98 145 <Statistic value="12">
99 146 <template #suffix>
... ... @@ -104,18 +151,23 @@
104 151 </div>
105 152 <div class="flex justify-between mt-4">
106 153 <div>
107   - <span>看板类型</span>
108 154 <span>
109   - <ShareAltOutlined @click="handleCopyShareUrl" />
  155 + {{ item.viewType === ViewType.PRIVATE_VIEW ? '私有看板' : '公共看板' }}
  156 + </span>
  157 + <span v-if="item.viewType === ViewType.PUBLIC_VIEW">
  158 + <Tooltip title="分享链接">
  159 + <ShareAltOutlined class="ml-2" @click="handleCopyShareUrl(item)" />
  160 + </Tooltip>
110 161 </span>
111 162 </div>
112   - <div>2021-02-11 12:00:00</div>
  163 + <div>{{ item.updateTime || item.createTime }}</div>
113 164 </div>
114 165 </section>
115 166 </Card>
116 167 </ListItem>
117 168 </template>
118 169 </List>
  170 + <PanelDetailModal @register="registerModal" @change="getDatasource" />
119 171 </PageWrapper>
120 172 </template>
121 173
... ...