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,7 +4,7 @@
4 import { nextTick, ref } from 'vue'; 4 import { nextTick, ref } from 'vue';
5 import WidgetWrapper from '../components/WidgetWrapper/WidgetWrapper.vue'; 5 import WidgetWrapper from '../components/WidgetWrapper/WidgetWrapper.vue';
6 import BaseWidgetHeader from '../components/WidgetHeader/BaseWidgetHeader.vue'; 6 import BaseWidgetHeader from '../components/WidgetHeader/BaseWidgetHeader.vue';
7 - import InformationPanel from '../components/InformationPanel.vue'; 7 + import InformationPanel from '../components/Other/InformationPanel.vue';
8 import { DropMenu } from '/@/components/Dropdown'; 8 import { DropMenu } from '/@/components/Dropdown';
9 import DataBindModal from './components/DataBindModal.vue'; 9 import DataBindModal from './components/DataBindModal.vue';
10 import { useModal } from '/@/components/Modal'; 10 import { useModal } from '/@/components/Modal';
1 <script lang="ts" setup> 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 import { PageWrapper } from '/@/components/Page'; 4 import { PageWrapper } from '/@/components/Page';
5 import { MoreOutlined, ShareAltOutlined } from '@ant-design/icons-vue'; 5 import { MoreOutlined, ShareAltOutlined } from '@ant-design/icons-vue';
6 import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard'; 6 import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
7 import { useMessage } from '/@/hooks/web/useMessage'; 7 import { useMessage } from '/@/hooks/web/useMessage';
8 - import { useRouter } from 'vue-router';  
9 import Dropdown from '/@/components/Dropdown/src/Dropdown.vue'; 8 import Dropdown from '/@/components/Dropdown/src/Dropdown.vue';
10 import { DropMenu } from '/@/components/Dropdown'; 9 import { DropMenu } from '/@/components/Dropdown';
11 import { MoreActionEvent } from './config/config'; 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 const router = useRouter(); 19 const router = useRouter();
  20 +
15 const { createMessage } = useMessage(); 21 const { createMessage } = useMessage();
16 22
17 - const data = ref([{ title: 1 }, { title: 2 }, { title: 3 }]); 23 + const dataBoardList = ref<DataBoardRecord[]>([]);
18 //分页相关 24 //分页相关
19 const page = ref(1); 25 const page = ref(1);
20 const pageSize = ref(36); 26 const pageSize = ref(36);
@@ -39,8 +45,8 @@ @@ -39,8 +45,8 @@
39 } 45 }
40 46
41 const { clipboardRef } = useCopyToClipboard(); 47 const { clipboardRef } = useCopyToClipboard();
42 - const handleCopyShareUrl = () => {  
43 - clipboardRef.value = '123'; 48 + const handleCopyShareUrl = (record: DataBoardRecord) => {
  49 + clipboardRef.value = record.openUrl;
44 unref(clipboardRef) && createMessage.success('复制成功'); 50 unref(clipboardRef) && createMessage.success('复制成功');
45 }; 51 };
46 52
@@ -57,34 +63,75 @@ @@ -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 </script> 115 </script>
72 116
73 <template> 117 <template>
74 <PageWrapper> 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 <List 123 <List
77 :pagination="paginationProp" 124 :pagination="paginationProp"
78 - :data-source="data" 125 + :data-source="dataBoardList"
79 :grid="{ gutter: 5, column: 4, xs: 1, sm: 2, md: 2, lg: 3, xl: 3, xxl: 3 }" 126 :grid="{ gutter: 5, column: 4, xs: 1, sm: 2, md: 2, lg: 3, xl: 3, xxl: 3 }"
80 > 127 >
81 <template #renderItem="{ item }"> 128 <template #renderItem="{ item }">
82 <ListItem> 129 <ListItem>
83 - <Card class="data-card cursor-pointer"> 130 + <Card class="data-card cursor-pointer" @click="handleViewBoard(item)">
84 <template #extra> 131 <template #extra>
85 <Dropdown 132 <Dropdown
86 :trigger="['click']" 133 :trigger="['click']"
87 - @menu-event="handleMenuEvent" 134 + @menu-event="(event) => handleMenuEvent(event, item)"
88 :drop-menu-list="dropMenuList" 135 :drop-menu-list="dropMenuList"
89 > 136 >
90 <MoreOutlined class="rotate-90 transform cursor-pointer" /> 137 <MoreOutlined class="rotate-90 transform cursor-pointer" />
@@ -93,7 +140,7 @@ @@ -93,7 +140,7 @@
93 <!-- <template #cover>title</template> --> 140 <!-- <template #cover>title</template> -->
94 <section> 141 <section>
95 <div class="flex justify-between items-center"> 142 <div class="flex justify-between items-center">
96 - <div>设备看板名</div> 143 + <div>{{ item.name }}</div>
97 <div class="flex content-center"> 144 <div class="flex content-center">
98 <Statistic value="12"> 145 <Statistic value="12">
99 <template #suffix> 146 <template #suffix>
@@ -104,18 +151,23 @@ @@ -104,18 +151,23 @@
104 </div> 151 </div>
105 <div class="flex justify-between mt-4"> 152 <div class="flex justify-between mt-4">
106 <div> 153 <div>
107 - <span>看板类型</span>  
108 <span> 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 </span> 161 </span>
111 </div> 162 </div>
112 - <div>2021-02-11 12:00:00</div> 163 + <div>{{ item.updateTime || item.createTime }}</div>
113 </div> 164 </div>
114 </section> 165 </section>
115 </Card> 166 </Card>
116 </ListItem> 167 </ListItem>
117 </template> 168 </template>
118 </List> 169 </List>
  170 + <PanelDetailModal @register="registerModal" @change="getDatasource" />
119 </PageWrapper> 171 </PageWrapper>
120 </template> 172 </template>
121 173