feat: 增加优化器模板的编辑
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
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',
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user