feat: 增加优化器模板的编辑
This commit is contained in:
@@ -108,3 +108,21 @@ class Line(
|
|||||||
interface LineRepository : JpaRepository<Line, String>, JpaSpecificationExecutor<Line> {
|
interface LineRepository : JpaRepository<Line, String>, JpaSpecificationExecutor<Line> {
|
||||||
fun findAllByChapter_ChapterId(chapterId: String, sort: Sort): List<Line>
|
fun findAllByChapter_ChapterId(chapterId: String, sort: Sort): List<Line>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@DynamicUpdate
|
||||||
|
class OptimizationTemplate(
|
||||||
|
@Id
|
||||||
|
var templateId: String,
|
||||||
|
@Column(nullable = false)
|
||||||
|
var name: String,
|
||||||
|
var description: String?,
|
||||||
|
@Lob
|
||||||
|
@Basic(fetch = FetchType.LAZY)
|
||||||
|
@Column(nullable = false, length = Int.MAX_VALUE)
|
||||||
|
var config: String,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
interface OptimizationTemplateRepository : JpaRepository<OptimizationTemplate, String>,
|
||||||
|
JpaSpecificationExecutor<OptimizationTemplate>
|
||||||
|
|||||||
@@ -1,27 +1,35 @@
|
|||||||
package com.lanyuanxiaoyao.bookstore.controller
|
package com.lanyuanxiaoyao.bookstore.controller
|
||||||
|
|
||||||
|
import cn.hutool.core.util.IdUtil
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import com.lanyuanxiaoyao.bookstore.CharWidthOptimization
|
import com.lanyuanxiaoyao.bookstore.CharWidthOptimization
|
||||||
import com.lanyuanxiaoyao.bookstore.ListResponse
|
import com.lanyuanxiaoyao.bookstore.ListResponse
|
||||||
import com.lanyuanxiaoyao.bookstore.Optimization
|
import com.lanyuanxiaoyao.bookstore.Optimization
|
||||||
import com.lanyuanxiaoyao.bookstore.Optimization.ArgumentType.LIST
|
import com.lanyuanxiaoyao.bookstore.OptimizationTemplate
|
||||||
import com.lanyuanxiaoyao.bookstore.Optimization.ArgumentType.MAP
|
import com.lanyuanxiaoyao.bookstore.OptimizationTemplateRepository
|
||||||
import com.lanyuanxiaoyao.bookstore.Optimization.ArgumentType.NONE
|
import com.lanyuanxiaoyao.bookstore.PageResponse
|
||||||
import com.lanyuanxiaoyao.bookstore.SingleResponse
|
import com.lanyuanxiaoyao.bookstore.SingleResponse
|
||||||
import com.lanyuanxiaoyao.bookstore.SliceOptimization
|
import com.lanyuanxiaoyao.bookstore.SliceOptimization
|
||||||
import com.lanyuanxiaoyao.bookstore.TrimOptimization
|
import com.lanyuanxiaoyao.bookstore.TrimOptimization
|
||||||
import java.awt.SystemColor.text
|
import jakarta.transaction.Transactional
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
import org.springframework.data.domain.PageRequest
|
||||||
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.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
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam
|
||||||
import org.springframework.web.bind.annotation.RestController
|
import org.springframework.web.bind.annotation.RestController
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("optimization")
|
@RequestMapping("optimization")
|
||||||
class OptimizationController(builder: Jackson2ObjectMapperBuilder) {
|
class OptimizationController(
|
||||||
|
private val optimizationTemplateRepository: OptimizationTemplateRepository,
|
||||||
|
builder: Jackson2ObjectMapperBuilder,
|
||||||
|
) {
|
||||||
private val log = LoggerFactory.getLogger(javaClass)
|
private val log = LoggerFactory.getLogger(javaClass)
|
||||||
|
|
||||||
private val mapper: ObjectMapper = builder.build()
|
private val mapper: ObjectMapper = builder.build()
|
||||||
@@ -43,4 +51,60 @@ class OptimizationController(builder: Jackson2ObjectMapperBuilder) {
|
|||||||
val lines = Optimization.process(root, optimizationMap)
|
val lines = Optimization.process(root, optimizationMap)
|
||||||
return SingleResponse(lines.joinToString("\n"))
|
return SingleResponse(lines.joinToString("\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("list")
|
||||||
|
fun list(
|
||||||
|
@RequestParam("page", defaultValue = "1") page: Int,
|
||||||
|
@RequestParam("size", defaultValue = "10") size: Int,
|
||||||
|
): PageResponse<ViewItem> {
|
||||||
|
val pageable = optimizationTemplateRepository.findAll(PageRequest.of(0.coerceAtLeast(page - 1), size))
|
||||||
|
return PageResponse(
|
||||||
|
pageable.content.map { template ->
|
||||||
|
ViewItem(
|
||||||
|
templateId = template.templateId,
|
||||||
|
name = template.name,
|
||||||
|
description = template.description,
|
||||||
|
config = mapper.readTree(template.config),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
pageable.totalElements,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@PostMapping("save")
|
||||||
|
fun save(@RequestBody item: ViewItem) {
|
||||||
|
optimizationTemplateRepository.save(
|
||||||
|
OptimizationTemplate(
|
||||||
|
templateId = item.templateId ?: IdUtil.simpleUUID(),
|
||||||
|
name = item.name,
|
||||||
|
description = item.description,
|
||||||
|
config = mapper.writeValueAsString(item.config),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("detail/{templateId}")
|
||||||
|
fun detail(@PathVariable("templateId") templateId: String): ViewItem {
|
||||||
|
val template = optimizationTemplateRepository.findById(templateId).orElseThrow()
|
||||||
|
return ViewItem(
|
||||||
|
templateId = template.templateId,
|
||||||
|
name = template.name,
|
||||||
|
description = template.description,
|
||||||
|
config = mapper.readTree(template.config),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@GetMapping("remove/{templateId}")
|
||||||
|
fun remove(@PathVariable("templateId") templateId: String) {
|
||||||
|
optimizationTemplateRepository.deleteById(templateId)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class ViewItem(
|
||||||
|
val templateId: String?,
|
||||||
|
val name: String,
|
||||||
|
val description: String?,
|
||||||
|
val config: JsonNode,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
143
src/main/resources/static/components/optimization.js
Normal file
143
src/main/resources/static/components/optimization.js
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
function optimizationTemplateForm() {
|
||||||
|
return {
|
||||||
|
debug: true,
|
||||||
|
type: 'form',
|
||||||
|
name: 'optimization-template-form',
|
||||||
|
...horizontalFormOptions(),
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'hidden',
|
||||||
|
name: 'templateId',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'name',
|
||||||
|
label: '名称',
|
||||||
|
required: true,
|
||||||
|
...formInputClearable(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'textarea',
|
||||||
|
name: 'description',
|
||||||
|
label: '简介',
|
||||||
|
...formInputClearable(),
|
||||||
|
showCounter: true,
|
||||||
|
trimContents: true,
|
||||||
|
minRows: 2,
|
||||||
|
maxRows: 2,
|
||||||
|
maxLength: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'combo',
|
||||||
|
name: 'config',
|
||||||
|
label: '优化器',
|
||||||
|
required: true,
|
||||||
|
multiLine: true,
|
||||||
|
multiple: true,
|
||||||
|
draggable: true,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: 'type',
|
||||||
|
label: '类型',
|
||||||
|
type: 'select',
|
||||||
|
required: true,
|
||||||
|
selectFirst: true,
|
||||||
|
source: '${base}/optimization/optimizations',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
visibleOn: "${ENDSWITH(type, 'MAP')}",
|
||||||
|
type: 'input-kv',
|
||||||
|
name: 'argument',
|
||||||
|
label: '参数',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
visibleOn: "${ENDSWITH(type, 'LIST')}",
|
||||||
|
type: 'combo',
|
||||||
|
name: 'argument',
|
||||||
|
label: '参数',
|
||||||
|
required: true,
|
||||||
|
multiple: true,
|
||||||
|
multiLine: true,
|
||||||
|
flat: true,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'argument',
|
||||||
|
label: '目标值',
|
||||||
|
required: true,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'textarea',
|
||||||
|
name: 'text',
|
||||||
|
label: '测试正文',
|
||||||
|
...formInputClearable(),
|
||||||
|
showCounter: true,
|
||||||
|
trimContents: true,
|
||||||
|
minRows: 5,
|
||||||
|
maxRows: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'action',
|
||||||
|
label: '优化预览',
|
||||||
|
className: 'w-full mb-5',
|
||||||
|
level: 'primary',
|
||||||
|
actionType: 'ajax',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: '${base}/optimization/execute',
|
||||||
|
data: {
|
||||||
|
text: '${text|default:undefined}',
|
||||||
|
optimizations: '${config|default:undefined}'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
reload: 'optimization-template-form?newText=${item}'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
disabled: true,
|
||||||
|
type: 'diff-editor',
|
||||||
|
name: 'newText',
|
||||||
|
label: '正文优化',
|
||||||
|
diffValue: '${text}',
|
||||||
|
language: 'plain-text'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function optimizationTemplateAddDialog() {
|
||||||
|
return {
|
||||||
|
type: 'action',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
title: '新增优化器模板',
|
||||||
|
size: 'lg',
|
||||||
|
body: {
|
||||||
|
...optimizationTemplateForm(),
|
||||||
|
api: '${base}/optimization/save',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function optimizationTemplateDetailDialog() {
|
||||||
|
return {
|
||||||
|
type: 'action',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
title: '编辑优化器模板',
|
||||||
|
size: 'lg',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
...optimizationTemplateForm(),
|
||||||
|
initApi: '${base}/optimization/detail/${templateId}',
|
||||||
|
api: '${base}/optimization/save',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,6 +38,7 @@
|
|||||||
<script src="components/helper.js"></script>
|
<script src="components/helper.js"></script>
|
||||||
<script src="components/book.js"></script>
|
<script src="components/book.js"></script>
|
||||||
<script src="components/chapter.js"></script>
|
<script src="components/chapter.js"></script>
|
||||||
|
<script src="components/optimization.js"></script>
|
||||||
<script>
|
<script>
|
||||||
(function () {
|
(function () {
|
||||||
let amis = amisRequire('amis/embed')
|
let amis = amisRequire('amis/embed')
|
||||||
@@ -59,8 +60,8 @@
|
|||||||
url: '${base}/book/list',
|
url: '${base}/book/list',
|
||||||
data: {
|
data: {
|
||||||
page: '${page|default:1}',
|
page: '${page|default:1}',
|
||||||
size: '${size|default:10}'
|
size: '${size|default:10}',
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
...crudCommonOptions(),
|
...crudCommonOptions(),
|
||||||
headerToolbar: [
|
headerToolbar: [
|
||||||
@@ -122,99 +123,68 @@
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '优化',
|
title: '优化',
|
||||||
body: [
|
body: [
|
||||||
{
|
{
|
||||||
type: 'form',
|
type: 'crud',
|
||||||
name: 'optimization-form',
|
api: {
|
||||||
body: [
|
method: 'get',
|
||||||
|
url: '${base}/optimization/list',
|
||||||
|
data: {
|
||||||
|
page: '${page|default:1}',
|
||||||
|
size: '${size|default:10}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
...crudCommonOptions(),
|
||||||
|
headerToolbar: [
|
||||||
|
'reload',
|
||||||
{
|
{
|
||||||
type: 'textarea',
|
label: '',
|
||||||
name: 'text',
|
icon: 'fa fa-add',
|
||||||
label: '正文',
|
...optimizationTemplateAddDialog(),
|
||||||
required: true,
|
},
|
||||||
...formInputClearable(),
|
],
|
||||||
showCounter: true,
|
columns: [
|
||||||
trimContents: true,
|
{
|
||||||
minRows: 5,
|
name: 'name',
|
||||||
maxRows: 5,
|
label: '名称',
|
||||||
|
width: 150,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'combo',
|
name: 'description',
|
||||||
name: 'optimizations',
|
label: '描述',
|
||||||
label: '优化器',
|
|
||||||
required: true,
|
|
||||||
multiLine: true,
|
|
||||||
multiple: true,
|
|
||||||
draggable: true,
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
name: 'type',
|
|
||||||
label: '类型',
|
|
||||||
type: 'select',
|
|
||||||
required: true,
|
|
||||||
selectFirst: true,
|
|
||||||
source: '${base}/optimization/optimizations',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
visibleOn: "${ENDSWITH(type, 'MAP')}",
|
type: 'operation',
|
||||||
type: 'input-kv',
|
label: '操作',
|
||||||
name: 'argument',
|
fixed: 'right',
|
||||||
label: '参数',
|
className: 'nowrap',
|
||||||
required: true,
|
width: 100,
|
||||||
},
|
buttons: [
|
||||||
{
|
{
|
||||||
visibleOn: "${ENDSWITH(type, 'LIST')}",
|
type: 'action',
|
||||||
type: 'combo',
|
label: '编辑',
|
||||||
name: 'argument',
|
...optimizationTemplateDetailDialog(),
|
||||||
label: '参数',
|
|
||||||
required: true,
|
|
||||||
multiple: true,
|
|
||||||
multiLine: true,
|
|
||||||
flat: true,
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
type: 'input-text',
|
|
||||||
name: 'argument',
|
|
||||||
label: '目标值',
|
|
||||||
required: true,
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'action',
|
type: 'action',
|
||||||
label: '执行优化',
|
label: '删除',
|
||||||
className: 'w-full mb-5',
|
level: 'danger',
|
||||||
level: 'primary',
|
confirmTitle: '确认删除',
|
||||||
|
confirmText: '确认删除名称为「${name}」的优化器模板吗?',
|
||||||
actionType: 'ajax',
|
actionType: 'ajax',
|
||||||
api: {
|
api: 'get:${base}/optimization/remove/${templateId}',
|
||||||
method: 'post',
|
|
||||||
url: '${base}/optimization/execute',
|
|
||||||
data: {
|
|
||||||
text: '${text|default:undefined}',
|
|
||||||
optimizations: '${optimizations|default:undefined}'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
reload: 'optimization-form?newText=${item}'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
disabled: true,
|
|
||||||
type: 'diff-editor',
|
|
||||||
name: 'newText',
|
|
||||||
label: '正文优化',
|
|
||||||
diffValue: '${text}',
|
|
||||||
language: 'plain-text'
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
amis.embed(
|
amis.embed(
|
||||||
@@ -222,7 +192,7 @@
|
|||||||
amisJSON,
|
amisJSON,
|
||||||
{
|
{
|
||||||
data: {
|
data: {
|
||||||
...information
|
...information,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user