1
0

feat: 增加优化器模板的编辑

This commit is contained in:
2024-12-23 23:35:21 +08:00
parent 4204a3e282
commit 1c868815de
4 changed files with 287 additions and 92 deletions

View File

@@ -108,3 +108,21 @@ class Line(
interface LineRepository : JpaRepository<Line, String>, JpaSpecificationExecutor<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>

View File

@@ -1,27 +1,35 @@
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.lanyuanxiaoyao.bookstore.CharWidthOptimization
import com.lanyuanxiaoyao.bookstore.ListResponse
import com.lanyuanxiaoyao.bookstore.Optimization
import com.lanyuanxiaoyao.bookstore.Optimization.ArgumentType.LIST
import com.lanyuanxiaoyao.bookstore.Optimization.ArgumentType.MAP
import com.lanyuanxiaoyao.bookstore.Optimization.ArgumentType.NONE
import com.lanyuanxiaoyao.bookstore.OptimizationTemplate
import com.lanyuanxiaoyao.bookstore.OptimizationTemplateRepository
import com.lanyuanxiaoyao.bookstore.PageResponse
import com.lanyuanxiaoyao.bookstore.SingleResponse
import com.lanyuanxiaoyao.bookstore.SliceOptimization
import com.lanyuanxiaoyao.bookstore.TrimOptimization
import java.awt.SystemColor.text
import jakarta.transaction.Transactional
import org.slf4j.LoggerFactory
import org.springframework.data.domain.PageRequest
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.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
@RestController
@RequestMapping("optimization")
class OptimizationController(builder: Jackson2ObjectMapperBuilder) {
class OptimizationController(
private val optimizationTemplateRepository: OptimizationTemplateRepository,
builder: Jackson2ObjectMapperBuilder,
) {
private val log = LoggerFactory.getLogger(javaClass)
private val mapper: ObjectMapper = builder.build()
@@ -43,4 +51,60 @@ class OptimizationController(builder: Jackson2ObjectMapperBuilder) {
val lines = Optimization.process(root, optimizationMap)
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,
)
}

View 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',
},
],
},
}
}

View File

@@ -28,16 +28,17 @@
</body>
<script src="sdk/sdk.js"></script>
<script>
const information = {
debug: false,
name: '书籍中心',
description: '网络书籍精排版工具',
base: 'http://127.0.0.1:23890',
}
const information = {
debug: false,
name: '书籍中心',
description: '网络书籍精排版工具',
base: 'http://127.0.0.1:23890',
}
</script>
<script src="components/helper.js"></script>
<script src="components/book.js"></script>
<script src="components/chapter.js"></script>
<script src="components/optimization.js"></script>
<script>
(function () {
let amis = amisRequire('amis/embed')
@@ -59,8 +60,8 @@
url: '${base}/book/list',
data: {
page: '${page|default:1}',
size: '${size|default:10}'
}
size: '${size|default:10}',
},
},
...crudCommonOptions(),
headerToolbar: [
@@ -122,99 +123,68 @@
},
],
},
]
],
},
{
title: '优化',
body: [
{
type: 'form',
name: 'optimization-form',
body: [
type: 'crud',
api: {
method: 'get',
url: '${base}/optimization/list',
data: {
page: '${page|default:1}',
size: '${size|default:10}',
},
},
...crudCommonOptions(),
headerToolbar: [
'reload',
{
type: 'textarea',
name: 'text',
label: '正文',
required: true,
...formInputClearable(),
showCounter: true,
trimContents: true,
minRows: 5,
maxRows: 5,
label: '',
icon: 'fa fa-add',
...optimizationTemplateAddDialog(),
},
],
columns: [
{
name: 'name',
label: '名称',
width: 150,
},
{
type: 'combo',
name: 'optimizations',
label: '优化器',
required: true,
multiLine: true,
multiple: true,
draggable: true,
items: [
name: 'description',
label: '描述',
},
{
type: 'operation',
label: '操作',
fixed: 'right',
className: 'nowrap',
width: 100,
buttons: [
{
name: 'type',
label: '类型',
type: 'select',
required: true,
selectFirst: true,
source: '${base}/optimization/optimizations',
type: 'action',
label: '编辑',
...optimizationTemplateDetailDialog(),
},
{
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: 'action',
label: '删除',
level: 'danger',
confirmTitle: '确认删除',
confirmText: '确认删除名称为「${name}」的优化器模板吗?',
actionType: 'ajax',
api: 'get:${base}/optimization/remove/${templateId}',
},
]
},
{
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: '${optimizations|default:undefined}'
}
},
reload: 'optimization-form?newText=${item}'
},
{
disabled: true,
type: 'diff-editor',
name: 'newText',
label: '正文优化',
diffValue: '${text}',
language: 'plain-text'
},
]
],
},
]
}
]
],
},
],
},
}
amis.embed(
@@ -222,7 +192,7 @@
amisJSON,
{
data: {
...information
...information,
},
},
{