refactor(dashboard): refactor create

This commit is contained in:
qianmoQ 2024-11-25 14:03:36 +08:00
parent e5863b6762
commit f9287a0342
17 changed files with 184 additions and 37 deletions

View File

@ -0,0 +1,9 @@
USE
`datacap`;
ALTER TABLE `datacap_dashboard`
ADD COLUMN `version` VARCHAR(100) DEFAULT NULL;
UPDATE `datacap_dashboard`
SET `version` = '1.0'
WHERE `version` IS NULL;

View File

@ -12,9 +12,8 @@ import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import java.io.Serializable;
@ -42,14 +41,30 @@ public abstract class BaseController<T extends BaseEntity>
}
/**
* Save changes
* Create new resource
*/
@RequestMapping(method = {RequestMethod.POST, RequestMethod.PUT})
public CommonResponse<T> saveAndUpdate(@RequestBody T configure)
@PostMapping
@JsonView(value = {EntityView.UserView.class})
public CommonResponse<T> create(@RequestBody T configure)
{
return service.saveOrUpdate(repository, configure);
}
/**
* Update existing resource
*/
@PutMapping
@JsonView(value = {EntityView.UserView.class})
public CommonResponse<T> update(@RequestBody T configure)
{
return repository.findByCode(configure.getCode())
.map(entity -> {
configure.setId(entity.getId());
return service.saveOrUpdate(repository, configure);
})
.orElseGet(() -> CommonResponse.failure("Resource [ " + configure.getCode() + " ] not found"));
}
@Deprecated
@DeleteMapping
public CommonResponse<Long> delete(@RequestParam(value = "id") Long id)

View File

@ -52,6 +52,10 @@ public class DashboardEntity
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private AvatarEntity avatar;
@Column(name = "version")
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private String version;
@ManyToOne
@JoinTable(name = "datacap_dashboard_user_relation",
joinColumns = @JoinColumn(name = "dashboard_id"),

View File

@ -1,8 +1,10 @@
package io.edurt.datacap.service.entity;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonView;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import io.edurt.datacap.common.enums.DataSetState;
import io.edurt.datacap.common.view.EntityView;
import io.edurt.datacap.service.converter.ListConverter;
import io.edurt.datacap.service.enums.SyncMode;
import lombok.AllArgsConstructor;
@ -38,50 +40,65 @@ public class DataSetEntity
extends BaseEntity
{
@Column(name = "description")
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private String description;
@Column(name = "query")
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private String query;
@Column(name = "sync_mode")
@Enumerated(EnumType.STRING)
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private SyncMode syncMode = SyncMode.MANUAL;
@Column(name = "expression")
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private String expression; // only for TIMING
@Column(name = "state")
@Convert(converter = ListConverter.class)
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private List<DataSetState> state;
@Column(name = "message")
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private String message;
@Column(name = "table_name")
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private String tableName;
@Column(name = "code")
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private String code;
@Column(name = "scheduler")
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private String scheduler;
@Column(name = "executor")
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private String executor;
@Column(name = "total_rows")
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private String totalRows;
@Column(name = "total_size")
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private String totalSize;
@Column(name = "life_cycle")
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private String lifeCycle;
@Column(name = "life_cycle_column")
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private String lifeCycleColumn;
@Column(name = "life_cycle_type")
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private String lifeCycleType;
@ManyToOne
@ -89,6 +106,7 @@ public class DataSetEntity
joinColumns = @JoinColumn(name = "dataset_id"),
inverseJoinColumns = @JoinColumn(name = "source_id"))
@JsonIgnoreProperties(value = {"user"})
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private SourceEntity source;
@ManyToOne
@ -96,6 +114,7 @@ public class DataSetEntity
joinColumns = @JoinColumn(name = "dataset_id"),
inverseJoinColumns = @JoinColumn(name = "user_id"))
@JsonIgnoreProperties(value = {"roles", "thirdConfigure", "avatarConfigure"})
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private UserEntity user;
@Transient

View File

@ -1,7 +1,8 @@
package io.edurt.datacap.service.entity;
import com.fasterxml.jackson.annotation.JsonIncludeProperties;
import com.fasterxml.jackson.annotation.JsonView;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import io.edurt.datacap.common.view.EntityView;
import io.edurt.datacap.service.enums.ReportType;
import lombok.AllArgsConstructor;
import lombok.Data;
@ -35,39 +36,44 @@ public class ReportEntity
extends BaseEntity
{
@Column(name = "configure")
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private String configure;
@Column(name = "realtime")
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private boolean realtime;
@Column(name = "type")
@Enumerated(EnumType.STRING)
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private ReportType type;
@Column(name = "query")
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private String query;
@Column(name = "description")
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private String description;
@ManyToOne
@JoinTable(name = "datacap_report_user_relation",
joinColumns = @JoinColumn(name = "report_id"),
inverseJoinColumns = @JoinColumn(name = "user_id"))
@JsonIncludeProperties(value = {"id", "name", "username", "code"})
@JsonView(value = {EntityView.AdminView.class})
private UserEntity user;
@ManyToOne
@JoinTable(name = "datacap_report_source_relation",
joinColumns = @JoinColumn(name = "report_id"),
inverseJoinColumns = @JoinColumn(name = "source_id"))
@JsonIncludeProperties(value = {"id", "code", "name", "type"})
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private SourceEntity source;
@ManyToOne
@JoinTable(name = "datacap_report_dataset_relation",
joinColumns = @JoinColumn(name = "report_id"),
inverseJoinColumns = @JoinColumn(name = "dataset_id"))
@JsonIncludeProperties(value = {"id", "code", "name", "query", "description"})
@JsonView(value = {EntityView.UserView.class, EntityView.AdminView.class})
private DataSetEntity dataset;
}

View File

@ -9,7 +9,4 @@ import org.springframework.data.repository.PagingAndSortingRepository;
public interface DashboardService
extends BaseService<DashboardEntity>
{
CommonResponse<PageEntity<DashboardEntity>> getAll(FilterBody filter);
CommonResponse<DashboardEntity> saveOrUpdate(PagingAndSortingRepository<DashboardEntity, Long> repository, DashboardEntity configure);
}

View File

@ -5,11 +5,12 @@ import io.edurt.datacap.service.adapter.PageRequestAdapter;
import io.edurt.datacap.service.body.FilterBody;
import io.edurt.datacap.service.entity.DashboardEntity;
import io.edurt.datacap.service.entity.PageEntity;
import io.edurt.datacap.service.repository.BaseRepository;
import io.edurt.datacap.service.repository.DashboardRepository;
import io.edurt.datacap.service.repository.ReportRepository;
import io.edurt.datacap.service.security.UserDetailsService;
import io.edurt.datacap.service.service.DashboardService;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Service;
@Service
@ -17,23 +18,31 @@ public class DashboardServiceImpl
implements DashboardService
{
private final DashboardRepository repository;
private final ReportRepository reportRepository;
public DashboardServiceImpl(DashboardRepository repository)
public DashboardServiceImpl(DashboardRepository repository, ReportRepository reportRepository)
{
this.repository = repository;
this.reportRepository = reportRepository;
}
@Override
public CommonResponse<PageEntity<DashboardEntity>> getAll(FilterBody filter)
public CommonResponse<PageEntity<DashboardEntity>> getAll(BaseRepository<DashboardEntity, Long> baseRepository, FilterBody filter)
{
Pageable pageable = PageRequestAdapter.of(filter);
return CommonResponse.success(PageEntity.build(repository.findAllByUser(UserDetailsService.getUser(), pageable)));
}
@Override
public CommonResponse<DashboardEntity> saveOrUpdate(PagingAndSortingRepository<DashboardEntity, Long> repository, DashboardEntity configure)
public CommonResponse<DashboardEntity> saveOrUpdate(BaseRepository<DashboardEntity, Long> baseRepository, DashboardEntity configure)
{
configure.setUser(UserDetailsService.getUser());
configure.getReports()
.forEach(entity -> reportRepository.findByCode(entity.getCode())
.ifPresentOrElse(
report -> entity.setId(report.getId()),
() -> {throw new RuntimeException("Report [ " + entity.getCode() + " ] not found");}
));
return CommonResponse.success(repository.save(configure));
}
}

View File

@ -44,15 +44,9 @@ public class ExecuteServiceImpl
@Override
public CommonResponse<Object> execute(ExecuteEntity configure)
{
try {
return sourceRepository.findById(Long.valueOf(configure.getName()))
.map(entity -> handleSourceEntity(entity, configure.getContent()))
.orElse(CommonResponse.failure(ServiceState.SOURCE_NOT_FOUND));
}
catch (NumberFormatException e) {
log.error("Invalid source id: {}", configure.getName(), e);
return CommonResponse.failure(ServiceState.INVALID_PARAMETER, "Invalid source id");
}
return sourceRepository.findByCode(configure.getName())
.map(entity -> handleSourceEntity(entity, configure.getContent()))
.orElse(CommonResponse.failure(ServiceState.SOURCE_NOT_FOUND));
}
/**

View File

@ -3,6 +3,7 @@ export interface BaseModel
id?: number
name?: string
active?: boolean
code?: string
createTime?: string
updateTime?: string
}

View File

@ -143,7 +143,7 @@ export default defineComponent({
default: () => '400px'
},
original: {
type: Number
type: String
}
},
data()

View File

@ -2,7 +2,7 @@
<div class="relative">
<ShadcnSpin v-model="loading" fixed/>
<DashboardEditor v-if="dataInfo" :info="dataInfo"/>
<DashboardEditor :info="dataInfo"/>
</div>
</template>
@ -21,7 +21,8 @@ export default defineComponent({
return {
loading: false,
saving: false,
dataInfo: null as DashboardModel | null
dataInfo: null as DashboardModel | null,
version: '2'
}
},
created()
@ -40,6 +41,7 @@ export default defineComponent({
.then(response => {
if (response.status) {
this.dataInfo = response.data
this.version = response.data.version
}
else {
this.$Message.error({

View File

@ -12,7 +12,7 @@
<ShadcnToggleGroup v-model="report" multiple>
<ShadcnRow gutter="8">
<ShadcnCol v-for="item of data" span="4">
<ShadcnToggle :key="item.id" class="px-1 py-1" :value="item.id">
<ShadcnToggle :key="item.code" class="px-1 py-1" :value="item.code">
<ShadcnCard :title="item.name">
<template #extra>
<ShadcnTooltip v-if="item.description" :content="item.description">
@ -25,7 +25,7 @@
:configuration="JSON.parse(item.configure as string)"
:type="item.type"
:query="item.type === 'DATASET' ? JSON.parse(item.query as string) : item.query"
:original="item?.source?.id"/>
:original="item?.source?.code"/>
</ShadcnCard>
</ShadcnToggle>
</ShadcnCol>
@ -71,7 +71,6 @@ import ReportService from '@/services/report.ts'
import { FilterModel } from '@/model/filter.ts'
import { ReportModel } from '@/model/report.ts'
import VisualView from '@/views/components/visual/VisualView.vue'
import { toNumber } from 'lodash'
export default defineComponent({
name: 'ChartContainer',
@ -158,7 +157,7 @@ export default defineComponent({
onSubmit()
{
const nodes = this.data.filter(item =>
this.report.some((reportId: number) => toNumber(item.id) === toNumber(reportId))
this.report.some((reportId: string) => item.code === reportId)
)
this.$emit('change', nodes)

View File

@ -49,7 +49,7 @@
:configuration="JSON.parse(item.node.configure)"
:type="item.original?.type"
:query="item.original.type === 'DATASET' ? JSON.parse(item.original.query as string) : item.original.query"
:original="item?.original?.source?.id"/>
:original="item?.original?.source?.code"/>
<VisualView v-else
:width="calculateWidth(item)"
@ -219,7 +219,7 @@ export default defineComponent({
i: 'new-' + Date.now(),
title: node.name,
node: {
id: node.id,
id: node.code,
configure: node.configure,
code: node.dataset?.code,
query: node?.query
@ -233,9 +233,10 @@ export default defineComponent({
{
if (this.formState) {
this.formState.configure = JSON.stringify(this.layouts)
this.layouts.forEach((item: { node: { id: any; }; }) => {
this.formState?.reports?.push({ id: item.node.id })
this.layouts.forEach((item: { original: { code: any; }; }) => {
this.formState?.reports?.push({ code: item.original.code })
})
this.formState.version = '1.0'
this.loading = true
DashboardService.saveOrUpdate(this.formState)
.then(response => {

View File

@ -0,0 +1,6 @@
<template>
</template>
<script setup lang="ts">
</script>

View File

@ -37,7 +37,7 @@
:configuration="JSON.parse(item.node.configure)"
:type="item.original?.type"
:query="item.original.type === 'DATASET' ? JSON.parse(item.original.query as string) : item.original.query"
:original="item?.original?.source?.id"/>
:original="item?.original?.source?.code"/>
<VisualView v-else
:width="calculateWidth(item)"

View File

@ -0,0 +1,84 @@
---
title: 保存仪表盘
---
请求地址:`/api/v1/dashboard`
请求方式:`POST`
## Body
=== "示例"
```json
{
"name": "M 1.0",
"configure": "[...]",
"version": "1.0",
"description": "随意修改的仪表盘",
"reports": [
{
"code": "24f38722eb6d432a9ee574e675bd0509"
}
]
}
```
=== "参数"
|参数|类型| 描述 |
|---|---|---------------------|
|`name`|String| 仪表盘名称 |
|`configure`|String| 仪表盘配置 |
|`version`|String| 仪表盘版本 |
|`description`|String| 仪表盘描述 |
|`reports`|Array| 报表列表,结构 `[{"code": "24f38722eb6d432a9ee574e675bd0509"}]` |
## Response
=== "示例"
```json
{
"name": "M 1.0",
"code": "9e78e83f55864da7a4802e0989ae1f33",
"active": true,
"createTime": "2024-11-25 13:48:27",
"updateTime": "2024-11-25 13:48:27",
"configure": "[...]",
"description": "随意修改的仪表盘",
"avatar": {},
"version": "1.0",
"reports": [
{
"name": null,
"code": "24f38722eb6d432a9ee574e675bd0509",
"active": true,
"createTime": null,
"updateTime": null,
"configure": null,
"realtime": false,
"type": null,
"query": null,
"description": null,
"source": null,
"dataset": null
}
]
}
```
=== "参数"
|参数|类型| 描述 |
|---|---|---------------------|
|`name`|String| 仪表盘名称 |
|`code`|String| 仪表盘编码 |
|`active`|Boolean| 是否激活 |
|`createTime`|String| 创建时间 |
|`updateTime`|String| 更新时间 |
|`configure`|String| 仪表盘配置 |
|`description`|String| 仪表盘描述 |
|`avatar`|Object| 仪表盘头像 |
|`version`|String| 仪表盘版本 |
|`reports`|Array| 报表列表详见[报表](../report/list.md) |

View File

@ -295,5 +295,6 @@ nav:
- api/plugin/uninstall.md
- ApiDashboard:
- api/dashboard/list.md
- api/dashboard/save.md
- useCases.md
- partners.md