2 Commits

Author SHA1 Message Date
v-zhangjc9
64ef5514b4 feat(ai-web): 完成执行任务的创建 2025-07-04 19:31:24 +08:00
v-zhangjc9
4f1dc84405 feat(web): 调整侧边栏实现 2025-07-04 10:54:45 +08:00
6 changed files with 105 additions and 24 deletions

View File

@@ -2,19 +2,22 @@ package com.lanyuanxiaoyao.service.ai.web.controller.task;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.lanyuanxiaoyao.service.ai.core.entity.amis.AmisResponse;
import com.lanyuanxiaoyao.service.ai.web.base.controller.SimpleControllerSupport; import com.lanyuanxiaoyao.service.ai.web.base.controller.SimpleControllerSupport;
import com.lanyuanxiaoyao.service.ai.web.base.entity.SimpleItem; import com.lanyuanxiaoyao.service.ai.web.base.entity.SimpleItem;
import com.lanyuanxiaoyao.service.ai.web.entity.FlowTask; import com.lanyuanxiaoyao.service.ai.web.entity.FlowTask;
import com.lanyuanxiaoyao.service.ai.web.entity.FlowTaskTemplate; import com.lanyuanxiaoyao.service.ai.web.entity.FlowTaskTemplate;
import com.lanyuanxiaoyao.service.ai.web.service.task.FlowTaskService; import com.lanyuanxiaoyao.service.ai.web.service.task.FlowTaskService;
import com.lanyuanxiaoyao.service.ai.web.service.task.FlowTaskTemplateService; import com.lanyuanxiaoyao.service.ai.web.service.task.FlowTaskTemplateService;
import java.util.Map;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.mapstruct.Context;
import org.mapstruct.Mapping; import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@@ -22,15 +25,23 @@ import org.springframework.web.bind.annotation.RestController;
@RestController @RestController
@RequestMapping("flow_task") @RequestMapping("flow_task")
public class TaskController extends SimpleControllerSupport<FlowTask, TaskController.SaveItem, TaskController.ListItem, TaskController.DetailItem> { public class TaskController extends SimpleControllerSupport<FlowTask, TaskController.SaveItem, TaskController.ListItem, TaskController.DetailItem> {
private final FlowTaskService flowTaskService;
private final FlowTaskTemplateService flowTaskTemplateService; private final FlowTaskTemplateService flowTaskTemplateService;
private final ObjectMapper mapper; private final ObjectMapper mapper;
public TaskController(FlowTaskService flowTaskService, FlowTaskTemplateService flowTaskTemplateService, Jackson2ObjectMapperBuilder builder) { public TaskController(FlowTaskService flowTaskService, FlowTaskTemplateService flowTaskTemplateService, Jackson2ObjectMapperBuilder builder) {
super(flowTaskService); super(flowTaskService);
this.flowTaskService = flowTaskService;
this.flowTaskTemplateService = flowTaskTemplateService; this.flowTaskTemplateService = flowTaskTemplateService;
this.mapper = builder.build(); this.mapper = builder.build();
} }
@GetMapping("input_data/{id}")
public AmisResponse<?> getInputSchema(@PathVariable("id") Long id) throws JsonProcessingException {
var task = flowTaskService.detailOrThrow(id);
return AmisResponse.responseSuccess(mapper.readValue(task.getInput(), Map.class));
}
@Override @Override
protected SaveItemMapper<FlowTask, SaveItem> saveItemMapper() { protected SaveItemMapper<FlowTask, SaveItem> saveItemMapper() {
return item -> { return item -> {
@@ -45,13 +56,13 @@ public class TaskController extends SimpleControllerSupport<FlowTask, TaskContro
@Override @Override
protected ListItemMapper<FlowTask, ListItem> listItemMapper() { protected ListItemMapper<FlowTask, ListItem> listItemMapper() {
ListItem.Mapper map = Mappers.getMapper(ListItem.Mapper.class); ListItem.Mapper map = Mappers.getMapper(ListItem.Mapper.class);
return task -> map.from(task, mapper); return map::from;
} }
@Override @Override
protected DetailItemMapper<FlowTask, DetailItem> detailItemMapper() { protected DetailItemMapper<FlowTask, DetailItem> detailItemMapper() {
DetailItem.Mapper map = Mappers.getMapper(DetailItem.Mapper.class); DetailItem.Mapper map = Mappers.getMapper(DetailItem.Mapper.class);
return task -> map.from(task, mapper); return map::from;
} }
@Data @Data
@@ -64,17 +75,14 @@ public class TaskController extends SimpleControllerSupport<FlowTask, TaskContro
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public static class ListItem extends SimpleItem { public static class ListItem extends SimpleItem {
private Long templateId; private Long templateId;
private Object input; private String templateName;
private FlowTask.Status status; private FlowTask.Status status;
@org.mapstruct.Mapper @org.mapstruct.Mapper
public static abstract class Mapper { public static abstract class Mapper {
@Mapping(target = "templateId", source = "task.template.id") @Mapping(target = "templateId", source = "task.template.id")
public abstract ListItem from(FlowTask task, @Context ObjectMapper mapper) throws JsonProcessingException; @Mapping(target = "templateName", source = "task.template.name")
public abstract ListItem from(FlowTask task);
protected Object mapInput(String input, @Context ObjectMapper mapper) throws JsonProcessingException {
return mapper.readValue(input, Object.class);
}
} }
} }
@@ -87,7 +95,8 @@ public class TaskController extends SimpleControllerSupport<FlowTask, TaskContro
@org.mapstruct.Mapper @org.mapstruct.Mapper
public static abstract class Mapper extends ListItem.Mapper { public static abstract class Mapper extends ListItem.Mapper {
@Mapping(target = "templateId", source = "task.template.id") @Mapping(target = "templateId", source = "task.template.id")
public abstract DetailItem from(FlowTask task, @Context ObjectMapper mapper) throws JsonProcessingException; @Mapping(target = "templateName", source = "task.template.name")
public abstract DetailItem from(FlowTask task);
} }
} }
} }

View File

@@ -15,6 +15,8 @@ import lombok.extern.slf4j.Slf4j;
import org.mapstruct.Context; import org.mapstruct.Context;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
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.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@@ -33,6 +35,12 @@ public class TaskTemplateController extends SimpleControllerSupport<FlowTaskTemp
this.mapper = builder.build(); this.mapper = builder.build();
} }
@GetMapping("input_schema/{id}")
public AmisResponse<?> getInputSchema(@PathVariable("id") Long id) throws JsonProcessingException {
var template = flowTaskTemplateService.detailOrThrow(id);
return AmisResponse.responseSuccess(mapper.readValue(template.getInputSchema(), Map.class));
}
@PostMapping("update_flow_graph") @PostMapping("update_flow_graph")
public AmisResponse<?> updateFlowGraph(@RequestBody UpdateGraphItem item) throws JsonProcessingException { public AmisResponse<?> updateFlowGraph(@RequestBody UpdateGraphItem item) throws JsonProcessingException {
flowTaskTemplateService.updateFlowGraph(item.getId(), mapper.writeValueAsString(item.getGraph())); flowTaskTemplateService.updateFlowGraph(item.getId(), mapper.writeValueAsString(item.getGraph()));
@@ -41,7 +49,7 @@ public class TaskTemplateController extends SimpleControllerSupport<FlowTaskTemp
@Override @Override
protected SaveItemMapper<FlowTaskTemplate, SaveItem> saveItemMapper() { protected SaveItemMapper<FlowTaskTemplate, SaveItem> saveItemMapper() {
SaveItem.Mapper map = Mappers.getMapper(SaveItem.Mapper.class); var map = Mappers.getMapper(SaveItem.Mapper.class);
return item -> map.from(item, mapper); return item -> map.from(item, mapper);
} }
@@ -52,7 +60,7 @@ public class TaskTemplateController extends SimpleControllerSupport<FlowTaskTemp
@Override @Override
protected DetailItemMapper<FlowTaskTemplate, DetailItem> detailItemMapper() { protected DetailItemMapper<FlowTaskTemplate, DetailItem> detailItemMapper() {
DetailItem.Mapper map = Mappers.getMapper(DetailItem.Mapper.class); var map = Mappers.getMapper(DetailItem.Mapper.class);
return template -> map.from(template, mapper); return template -> map.from(template, mapper);
} }

View File

@@ -16,7 +16,7 @@ public class FlowTaskTemplateService extends SimpleServiceSupport<FlowTaskTempla
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void updateFlowGraph(Long id, String flowGraph) { public void updateFlowGraph(Long id, String flowGraph) {
FlowTaskTemplate template = detailOrThrow(id); var template = detailOrThrow(id);
template.setFlowGraph(flowGraph); template.setFlowGraph(flowGraph);
save(template); save(template);
} }

View File

@@ -1,7 +1,7 @@
import {type AppItemProps, ProLayout} from '@ant-design/pro-components' import {type AppItemProps, ProLayout} from '@ant-design/pro-components'
import {ConfigProvider} from 'antd' import {ConfigProvider} from 'antd'
import {dateFormat} from 'licia' import {dateFormat} from 'licia'
import React, {useMemo} from 'react' import React, {useMemo, useState} from 'react'
import {Outlet, useLocation, useNavigate} from 'react-router' import {Outlet, useLocation, useNavigate} from 'react-router'
import styled from 'styled-components' import styled from 'styled-components'
import {menus} from '../route.tsx' import {menus} from '../route.tsx'
@@ -14,7 +14,7 @@ const ProLayoutDiv = styled.div`
margin: 0; margin: 0;
.ant-menu-sub > .ant-menu-item { .ant-menu-sub > .ant-menu-item {
padding-left: 16px !important; //padding-left: 28px !important;
} }
` `
@@ -52,10 +52,13 @@ const apps: AppItemProps[] = [
const App: React.FC = () => { const App: React.FC = () => {
const navigate = useNavigate() const navigate = useNavigate()
const location = useLocation() const location = useLocation()
const [collapsed, setCollapsed] = useState<boolean>(false)
const currentYear = useMemo(() => dateFormat(new Date(), 'yyyy'), []) const currentYear = useMemo(() => dateFormat(new Date(), 'yyyy'), [])
return ( return (
<ProLayoutDiv> <ProLayoutDiv>
<ProLayout <ProLayout
collapsed={collapsed}
onCollapse={setCollapsed}
siderWidth={180} siderWidth={180}
token={{ token={{
colorTextAppListIcon: '#dfdfdf', colorTextAppListIcon: '#dfdfdf',
@@ -78,7 +81,6 @@ const App: React.FC = () => {
}, },
}} }}
appList={apps} appList={apps}
defaultCollapsed={false}
breakpoint={false} breakpoint={false}
disableMobile={true} disableMobile={true}
logo={<img src="icon.png" alt="logo"/>} logo={<img src="icon.png" alt="logo"/>}
@@ -86,11 +88,12 @@ const App: React.FC = () => {
route={menus} route={menus}
location={{pathname: location.pathname}} location={{pathname: location.pathname}}
menu={{type: 'sub'}} menu={{type: 'sub'}}
menuItemRender={(item) => { menuItemRender={(item, defaultDom) => {
return ( return (
<div onClick={() => navigate(item.path || '/')}> <div onClick={() => navigate(item.path || '/')}>
{item.icon} {/*<span className="align-center">{item.icon}</span>*/}
<span className="ml-2">{item.name}</span> {/*<span className="ml-2">{item.name}</span>*/}
{defaultDom}
</div> </div>
) )
}} }}

View File

@@ -1,9 +1,9 @@
import {isEmpty, isEqual} from 'licia' import {isEmpty, isEqual} from 'licia'
import React from 'react' import React from 'react'
import {useParams} from 'react-router'
import styled from 'styled-components' import styled from 'styled-components'
import {amisRender, commonInfo, horizontalFormOptions} from '../../../../util/amis.tsx' import {amisRender, commonInfo, horizontalFormOptions} from '../../../../util/amis.tsx'
import {generateInputForm, typeMap} from '../InputSchema.tsx' import {generateInputForm, typeMap} from '../InputSchema.tsx'
import { useParams } from 'react-router'
const TemplateEditDiv = styled.div` const TemplateEditDiv = styled.div`
.antd-EditorControl { .antd-EditorControl {
@@ -54,7 +54,7 @@ const FlowTaskTemplateEdit: React.FC = () => {
actionType: 'setValue', actionType: 'setValue',
args: { args: {
value: { value: {
inputPreview: generateInputForm(inputSchema), inputPreview: generateInputForm(inputSchema, '入参表单预览'),
}, },
}, },
}) })
@@ -75,6 +75,8 @@ const FlowTaskTemplateEdit: React.FC = () => {
label: '名称', label: '名称',
required: true, required: true,
clearable: true, clearable: true,
maxLength: 10,
showCounter: true,
}, },
{ {
type: 'textarea', type: 'textarea',
@@ -82,6 +84,8 @@ const FlowTaskTemplateEdit: React.FC = () => {
label: '描述', label: '描述',
required: true, required: true,
clearable: true, clearable: true,
maxLength: 500,
showCounter: true,
}, },
{ {
type: 'group', type: 'group',

View File

@@ -10,8 +10,8 @@ import {isEqual} from 'licia'
export const commonInfo = { export const commonInfo = {
debug: isEqual(import.meta.env.MODE, 'development'), debug: isEqual(import.meta.env.MODE, 'development'),
baseUrl: 'http://132.126.207.130:35690/hudi_services/service_web', baseUrl: 'http://132.126.207.130:35690/hudi_services/service_web',
// baseAiUrl: 'http://132.126.207.130:35690/hudi_services/service_ai_web', baseAiUrl: 'http://132.126.207.130:35690/hudi_services/service_ai_web',
baseAiUrl: 'http://localhost:8080', // baseAiUrl: 'http://localhost:8080',
authorizationHeaders: { authorizationHeaders: {
'Authorization': 'Basic QXhoRWJzY3dzSkRiWU1IMjpjWXhnM2I0UHRXb1ZENVNqRmF5V3h0blNWc2p6UnNnNA==', 'Authorization': 'Basic QXhoRWJzY3dzSkRiWU1IMjpjWXhnM2I0UHRXb1ZENVNqRmF5V3h0blNWc2p6UnNnNA==',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -278,7 +278,7 @@ export function horizontalFormOptions() {
return { return {
mode: 'horizontal', mode: 'horizontal',
horizontal: { horizontal: {
leftFixed: 'sm' leftFixed: 'sm',
}, },
} }
} }
@@ -2517,4 +2517,61 @@ export function time(field: string) {
export function pictureFromIds(field: string) { export function pictureFromIds(field: string) {
return `\${ARRAYMAP(${field},id => '${commonInfo.baseAiUrl}/upload/download/' + id)}` return `\${ARRAYMAP(${field},id => '${commonInfo.baseAiUrl}/upload/download/' + id)}`
}
const formInputFileStaticColumns = [
{
name: 'filename',
label: '文件名',
},
{
type: 'operation',
label: '操作',
width: 140,
buttons: [
{
type: 'action',
label: '预览',
level: 'link',
icon: 'fas fa-eye'
},
{
type: 'action',
label: '下载',
level: 'link',
icon: 'fa fa-download',
actionType: 'ajax',
// api: {
// ...apiGet('${base}/upload/download/${id}'),
// responseType: 'blob',
// }
}
]
}
]
export function formInputSingleFileStatic(field: string, label: string) {
return {
visibleOn: '${static}',
type: 'control',
label: label,
required: true,
body: {
type: 'table',
source: `\${${field}|asArray}`,
columns: formInputFileStaticColumns,
},
}
}
export function formInputMultiFileStatic(field: string, label: string) {
return {
visibleOn: '${static}',
type: 'input-table',
label: label,
name: field,
required: true,
resizable: false,
columns: formInputFileStaticColumns,
}
} }