1
0

fix: 优化器执行预览后会刷新页面导致草稿丢失

This commit is contained in:
2024-12-24 09:59:52 +08:00
parent 1c868815de
commit 3fd42162ad
4 changed files with 248 additions and 156 deletions

View File

@@ -8,16 +8,39 @@ import com.lanyuanxiaoyao.bookstore.Optimization.ArgumentType.NONE
interface Optimization { interface Optimization {
companion object { companion object {
fun listArgument(argument: Any): List<String> {
if (argument !is List<*>) throw IllegalArgumentException("Argument must be a list")
return argument
.map { it as String }
.filter { it.isNotBlank() }
}
fun mapArgument(argument: Any): Map<String, Any> {
if (argument !is Map<*, *>) throw IllegalArgumentException("Argument must be a map")
return argument
.map { (k, v) -> (k as String) to (v as String) }
.toMap()
}
fun process(root: JsonNode, optimizationMap: Map<String, Optimization>): List<String> { fun process(root: JsonNode, optimizationMap: Map<String, Optimization>): List<String> {
val text = root.get("text").asText() val text = root
.get("text")
.asText()
val nodes = root.get("optimizations") ?: emptyList() val nodes = root.get("optimizations") ?: emptyList()
var lines = listOf(text) var lines = listOf(text)
for (node in nodes) { for (node in nodes) {
val type = node.get("type").asText() val type = node
.get("type")
.asText()
val optimization = optimizationMap[type] ?: throw IllegalArgumentException("Unknown optimization type: $type") val optimization = optimizationMap[type] ?: throw IllegalArgumentException("Unknown optimization type: $type")
lines = when (optimization.argumentType()) { lines = when (optimization.argumentType()) {
NONE -> optimization.handle(lines, Unit) NONE -> optimization.handle(lines, Unit)
LIST -> optimization.handle(lines, node.get("argument").map { it.asText() }) LIST -> optimization.handle(
lines,
node
.get("argument")
.map { it.asText() })
MAP -> optimization.handle(lines, MAP -> optimization.handle(lines,
node node
.get("argument") .get("argument")
@@ -45,13 +68,13 @@ interface Optimization {
class SliceOptimization() : Optimization { class SliceOptimization() : Optimization {
override fun key(): String = "slice-${argumentType()}" override fun key(): String = "slice-${argumentType()}"
override fun name(): String = "切分" override fun name(): String = "正则切分"
override fun handle(line: List<String>, argument: Any): List<String> { override fun handle(line: List<String>, argument: Any): List<String> {
val keys = argument as List<String> val keys = Optimization.listArgument(argument)
var result = line var result = line
for (key in keys) { for (key in keys) {
result = result.flatMap { it.split(key) } result = result.flatMap { it.split(Regex(key)) }
} }
return result return result
} }
@@ -59,6 +82,19 @@ class SliceOptimization() : Optimization {
override fun argumentType(): Optimization.ArgumentType = Optimization.ArgumentType.LIST override fun argumentType(): Optimization.ArgumentType = Optimization.ArgumentType.LIST
} }
class RemoveBlankLineOptimization : Optimization {
override fun key(): String = "remove-blank-${argumentType()}"
override fun name(): String = "移除空白行"
override fun handle(line: List<String>, argument: Any): List<String> {
return line.filter { it.isNotBlank() }
}
override fun argumentType(): Optimization.ArgumentType = Optimization.ArgumentType.NONE
}
abstract class AbstractOptimization(private val key: String, private val name: String) : Optimization { abstract class AbstractOptimization(private val key: String, private val name: String) : Optimization {
override fun key(): String = "${key}-${argumentType()}" override fun key(): String = "${key}-${argumentType()}"
override fun name(): String = name override fun name(): String = name
@@ -72,6 +108,24 @@ abstract class AbstractOptimization(private val key: String, private val name: S
abstract fun handle(line: String, argument: Any): String abstract fun handle(line: String, argument: Any): String
} }
class RemoveOptimization : AbstractOptimization("remove", "移除") {
override fun handle(line: String, argument: Any): String {
val words = Optimization.listArgument(argument)
return words.fold(line) { result, word -> result.replace(word, "") }
}
override fun argumentType(): Optimization.ArgumentType = LIST
}
class RegexRemoveOptimization : AbstractOptimization("regex-remove", "正则移除") {
override fun handle(line: String, argument: Any): String {
val words = Optimization.listArgument(argument)
return words.fold(line) { result, word -> result.replace(Regex(word), "") }
}
override fun argumentType(): Optimization.ArgumentType = LIST
}
class TrimOptimization : AbstractOptimization("trim", "移除前后空白") { class TrimOptimization : AbstractOptimization("trim", "移除前后空白") {
override fun handle(line: String, argument: Any): String { override fun handle(line: String, argument: Any): String {
if (line.isBlank()) return line if (line.isBlank()) return line

View File

@@ -5,11 +5,14 @@ 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.MapResponse
import com.lanyuanxiaoyao.bookstore.Optimization import com.lanyuanxiaoyao.bookstore.Optimization
import com.lanyuanxiaoyao.bookstore.OptimizationTemplate import com.lanyuanxiaoyao.bookstore.OptimizationTemplate
import com.lanyuanxiaoyao.bookstore.OptimizationTemplateRepository import com.lanyuanxiaoyao.bookstore.OptimizationTemplateRepository
import com.lanyuanxiaoyao.bookstore.PageResponse import com.lanyuanxiaoyao.bookstore.PageResponse
import com.lanyuanxiaoyao.bookstore.SingleResponse import com.lanyuanxiaoyao.bookstore.RegexRemoveOptimization
import com.lanyuanxiaoyao.bookstore.RemoveBlankLineOptimization
import com.lanyuanxiaoyao.bookstore.RemoveOptimization
import com.lanyuanxiaoyao.bookstore.SliceOptimization import com.lanyuanxiaoyao.bookstore.SliceOptimization
import com.lanyuanxiaoyao.bookstore.TrimOptimization import com.lanyuanxiaoyao.bookstore.TrimOptimization
import jakarta.transaction.Transactional import jakarta.transaction.Transactional
@@ -35,7 +38,10 @@ class OptimizationController(
private val mapper: ObjectMapper = builder.build() private val mapper: ObjectMapper = builder.build()
private val optimizations: List<Optimization> = listOf( private val optimizations: List<Optimization> = listOf(
SliceOptimization(), SliceOptimization(),
RemoveBlankLineOptimization(),
TrimOptimization(), TrimOptimization(),
RemoveOptimization(),
RegexRemoveOptimization(),
CharWidthOptimization(), CharWidthOptimization(),
) )
private val optimizationMap: Map<String, Optimization> = optimizations.associateBy { it.key() } private val optimizationMap: Map<String, Optimization> = optimizations.associateBy { it.key() }
@@ -46,10 +52,16 @@ class OptimizationController(
} }
@PostMapping("execute") @PostMapping("execute")
fun execute(@RequestBody json: String): SingleResponse<String> { fun execute(@RequestBody json: String): MapResponse {
val root = mapper.readTree(json) val root = mapper.readTree(json)
val lines = Optimization.process(root, optimizationMap) val lines = Optimization.process(root, optimizationMap)
return SingleResponse(lines.joinToString("\n")) log.info("处理后行数:{}", lines.size)
return MapResponse(
mapOf(
"item" to lines.joinToString("\n"),
"count" to lines.size,
)
)
} }
@GetMapping("list") @GetMapping("list")
@@ -86,7 +98,9 @@ class OptimizationController(
@GetMapping("detail/{templateId}") @GetMapping("detail/{templateId}")
fun detail(@PathVariable("templateId") templateId: String): ViewItem { fun detail(@PathVariable("templateId") templateId: String): ViewItem {
val template = optimizationTemplateRepository.findById(templateId).orElseThrow() val template = optimizationTemplateRepository
.findById(templateId)
.orElseThrow()
return ViewItem( return ViewItem(
templateId = template.templateId, templateId = template.templateId,
name = template.name, name = template.name,

View File

@@ -1,8 +1,7 @@
function optimizationTemplateForm() { function optimizationTemplateForm() {
return { return {
debug: true, id: 'optimization-template-form',
type: 'form', type: 'form',
name: 'optimization-template-form',
...horizontalFormOptions(), ...horizontalFormOptions(),
body: [ body: [
{ {
@@ -86,16 +85,33 @@ function optimizationTemplateForm() {
label: '优化预览', label: '优化预览',
className: 'w-full mb-5', className: 'w-full mb-5',
level: 'primary', level: 'primary',
actionType: 'ajax', onEvent: {
api: { click: {
method: 'post', actions: [
url: '${base}/optimization/execute', {
data: { actionType: 'ajax',
text: '${text|default:undefined}', api: {
optimizations: '${config|default:undefined}' method: 'post',
url: '${base}/optimization/execute',
data: {
text: '${text|default:undefined}',
optimizations: '${config|default:undefined}',
},
silent: true,
},
},
{
actionType: 'setValue',
componentId: 'optimization-template-form',
args: {
value: {
newText: '${event.data.responseResult.responseData.item}'
}
}
}
]
} }
}, }
reload: 'optimization-template-form?newText=${item}'
}, },
{ {
disabled: true, disabled: true,

View File

@@ -40,6 +40,147 @@
<script src="components/chapter.js"></script> <script src="components/chapter.js"></script>
<script src="components/optimization.js"></script> <script src="components/optimization.js"></script>
<script> <script>
function bookTab() {
return {
title: '书架',
body: [
{
id: 'book-list',
type: 'crud',
api: {
method: 'get',
url: '${base}/book/list',
data: {
page: '${page|default:1}',
size: '${size|default:10}',
},
},
...crudCommonOptions(),
headerToolbar: [
'reload',
{
label: '',
icon: 'fa fa-add',
...bookAddDialog(),
},
],
footerToolbar: [
paginationOption(),
],
columns: [
{
name: 'name',
label: '名称',
width: 150,
},
{
name: 'description',
label: '描述',
},
{
type: 'operation',
label: '操作',
fixed: 'right',
className: 'nowrap',
width: 100,
buttons: [
{
type: 'action',
label: '跳转',
actionType: 'url',
url: '${source}',
blank: true,
},
{
type: 'action',
label: '导出',
actionType: 'download',
api: '${base}/book/export/${bookId}',
},
{
type: 'action',
label: '编辑',
...bookDetailDialog(),
},
{
type: 'action',
label: '删除',
level: 'danger',
confirmTitle: '确认删除',
confirmText: '确认删除名称为「${name}」的书籍吗?',
actionType: 'ajax',
api: 'get:${base}/book/remove/${bookId}',
},
],
},
],
},
],
}
}
function optimizationTab() {
return {
title: '优化',
body: [
{
type: 'crud',
api: {
method: 'get',
url: '${base}/optimization/list',
data: {
page: '${page|default:1}',
size: '${size|default:10}',
},
},
...crudCommonOptions(),
headerToolbar: [
'reload',
{
label: '',
icon: 'fa fa-add',
...optimizationTemplateAddDialog(),
},
],
columns: [
{
name: 'name',
label: '名称',
width: 150,
},
{
name: 'description',
label: '描述',
},
{
type: 'operation',
label: '操作',
fixed: 'right',
className: 'nowrap',
width: 100,
buttons: [
{
type: 'action',
label: '编辑',
...optimizationTemplateDetailDialog(),
},
{
type: 'action',
label: '删除',
level: 'danger',
confirmTitle: '确认删除',
confirmText: '确认删除名称为「${name}」的优化器模板吗?',
actionType: 'ajax',
api: 'get:${base}/optimization/remove/${templateId}',
},
]
},
],
},
],
}
}
(function () { (function () {
let amis = amisRequire('amis/embed') let amis = amisRequire('amis/embed')
let amisJSON = { let amisJSON = {
@@ -49,141 +190,8 @@
body: { body: {
type: 'tabs', type: 'tabs',
tabs: [ tabs: [
{ optimizationTab(),
title: '书架', bookTab(),
body: [
{
id: 'book-list',
type: 'crud',
api: {
method: 'get',
url: '${base}/book/list',
data: {
page: '${page|default:1}',
size: '${size|default:10}',
},
},
...crudCommonOptions(),
headerToolbar: [
'reload',
{
label: '',
icon: 'fa fa-add',
...bookAddDialog(),
},
],
footerToolbar: [
paginationOption(),
],
columns: [
{
name: 'name',
label: '名称',
width: 150,
},
{
name: 'description',
label: '描述',
},
{
type: 'operation',
label: '操作',
fixed: 'right',
className: 'nowrap',
width: 100,
buttons: [
{
type: 'action',
label: '跳转',
actionType: 'url',
url: '${source}',
blank: true,
},
{
type: 'action',
label: '导出',
actionType: 'download',
api: '${base}/book/export/${bookId}',
},
{
type: 'action',
label: '编辑',
...bookDetailDialog(),
},
{
type: 'action',
label: '删除',
level: 'danger',
confirmTitle: '确认删除',
confirmText: '确认删除名称为「${name}」的书籍吗?',
actionType: 'ajax',
api: 'get:${base}/book/remove/${bookId}',
},
],
},
],
},
],
},
{
title: '优化',
body: [
{
type: 'crud',
api: {
method: 'get',
url: '${base}/optimization/list',
data: {
page: '${page|default:1}',
size: '${size|default:10}',
},
},
...crudCommonOptions(),
headerToolbar: [
'reload',
{
label: '',
icon: 'fa fa-add',
...optimizationTemplateAddDialog(),
},
],
columns: [
{
name: 'name',
label: '名称',
width: 150,
},
{
name: 'description',
label: '描述',
},
{
type: 'operation',
label: '操作',
fixed: 'right',
className: 'nowrap',
width: 100,
buttons: [
{
type: 'action',
label: '编辑',
...optimizationTemplateDetailDialog(),
},
{
type: 'action',
label: '删除',
level: 'danger',
confirmTitle: '确认删除',
confirmText: '确认删除名称为「${name}」的优化器模板吗?',
actionType: 'ajax',
api: 'get:${base}/optimization/remove/${templateId}',
},
]
},
],
},
],
},
], ],
}, },
} }