diff --git a/.gitignore b/.gitignore index 5465356..579ea1f 100644 --- a/.gitignore +++ b/.gitignore @@ -91,14 +91,14 @@ replay_pid* # When using Gradle or Maven with auto-import, you should exclude module files, # since they will be recreated, and may cause churn. Uncomment if using # auto-import. -# .idea/artifacts -# .idea/compiler.xml -# .idea/jarRepositories.xml -# .idea/modules.xml -# .idea/*.iml -# .idea/modules -# *.iml -# *.ipr +.idea/artifacts +.idea/compiler.xml +.idea/jarRepositories.xml +.idea/modules.xml +.idea/*.iml +.idea/modules +*.iml +*.ipr # CMake cmake-build-*/ diff --git a/.idea/jpa.xml b/.idea/jpa.xml new file mode 100644 index 0000000..898e07a --- /dev/null +++ b/.idea/jpa.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index fae6c8e..c72dd77 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -7,4 +7,7 @@ + + \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..a4b76b9 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 50d231e..0a9a744 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -33,3 +33,14 @@ spring: driver-class-name: com.mysql.cj.jdbc.Driver username: bookstore password: EzSn+RZ*x2&fHFh9kC+H + +--- +spring: + config: + activate: + on-profile: mysql-remote + datasource: + url: jdbc:mysql://frp-air.top:43458/bookstore + driver-class-name: com.mysql.cj.jdbc.Driver + username: bookstore + password: EzSn+RZ*x2&fHFh9kC+H diff --git a/src/main/resources/static/components/book.js b/src/main/resources/static/components/book.js index 8ecc107..400fd4b 100644 --- a/src/main/resources/static/components/book.js +++ b/src/main/resources/static/components/book.js @@ -1,88 +1,208 @@ function bookForm() { - return { - type: 'form', - ...horizontalFormOptions(), - body: [ - { - type: 'hidden', - name: 'id', - }, - { - type: 'input-text', - name: 'name', - label: '名称', - required: true, - ...formInputClearable(), - }, - { - type: 'input-text', - name: 'author', - label: '作者', - ...formInputClearable(), - }, - { - type: 'input-text', - name: 'source', - label: '来源', - ...formInputClearable(), - validations: { - isUrl: true, - }, - }, - { - type: 'input-tag', - name: 'tags', - label: '标签', - clearable: true, - joinValues: false, - extractValue: true, - max: 10, - maxTagLength: 10, - source: '${base}/book/tags' - }, - { - type: 'textarea', - name: 'description', - label: '简介', - required: true, - ...formInputClearable(), - showCounter: true, - trimContents: true, - minRows: 2, - maxRows: 2, - maxLength: 100, - }, - ], - } + return { + type: 'form', + ...horizontalFormOptions(), + body: [ + { + type: 'hidden', + name: 'id', + }, + { + type: 'input-text', + name: 'name', + label: '名称', + required: true, + ...formInputClearable(), + }, + { + type: 'input-text', + name: 'author', + label: '作者', + ...formInputClearable(), + }, + { + type: 'input-text', + name: 'source', + label: '来源', + ...formInputClearable(), + validations: { + isUrl: true, + }, + }, + { + type: 'input-tag', + name: 'tags', + label: '标签', + clearable: true, + joinValues: false, + extractValue: true, + max: 10, + maxTagLength: 10, + source: '${base}/book/tags' + }, + { + type: 'textarea', + name: 'description', + label: '简介', + required: true, + ...formInputClearable(), + showCounter: true, + trimContents: true, + minRows: 2, + maxRows: 2, + maxLength: 100, + }, + ], + } } function bookAddDialog() { - return { - type: 'action', - actionType: 'dialog', - dialog: { - title: '新增书籍', - size: 'md', - body: { - ...bookForm(), - api: '${base}/book/save', - }, - }, - } + return { + type: 'action', + actionType: 'dialog', + dialog: { + title: '新增书籍', + size: 'md', + body: { + ...bookForm(), + api: '${base}/book/save', + }, + }, + } } function bookDetailDialog() { - return { - type: 'action', - actionType: 'dialog', - dialog: { - title: '编辑书籍', - size: 'md', - body: { - ...bookForm(), - initApi: '${base}/book/detail/${bookId}', - api: '${base}/book/save', - }, + return { + type: 'action', + actionType: 'dialog', + dialog: { + title: '编辑书籍', + size: 'lg', + actions: [], + body: [ + { + id: 'book-detail-dialog-form', + ...bookForm(), + initApi: '${base}/book/detail/${bookId}', + api: '${base}/book/save', }, - } + { + type: 'flex', + className: 'mt-5', + justify: 'flex-end', + items: [ + { + type: 'action', + label: '保存', + level: 'primary', + onEvent: { + click: { + actions: [ + { + actionType: 'submit', + componentId: 'book-detail-dialog-form', + }, + { + actionType: 'reload', + componentId: 'book-list', + } + ] + } + } + } + ] + }, + { + id: 'chapter-list', + type: 'crud', + ...crudCommonOptions(), + api: { + method: 'get', + url: '${base}/chapter/list/${bookId}', + data: { + page: '${page|default:1}', + size: '${size|default:10}' + } + }, + headerToolbar: [ + 'reload', + { + label: '', + icon: 'fa fa-add', + ...chapterAddDialog(), + }, + ], + footerToolbar: [ + paginationOption(), + ], + columns: [ + { + name: 'sequence', + label: '章节数', + width: 50, + }, + { + name: 'name', + label: '名称', + width: 150, + }, + { + name: 'description', + label: '简介', + }, + { + type: 'operation', + label: '操作', + fixed: 'right', + className: 'nowrap', + width: 200, + buttons: [ + { + type: 'action', + label: '编辑', + ...chapterDetailDialog(), + }, + { + type: 'action', + label: '阅读', + actionType: 'dialog', + dialog: { + title: '阅读', + size: 'lg', + actions: [], + body: { + type: 'service', + className: 'p-10', + api: '${base}/chapter/show/${chapterId}', + silentPolling: true, + body: { + type: 'tpl', + className: 'font-serif', + tpl: '${item|raw}' + } + } + } + }, + { + type: 'action', + label: '导出', + actionType: 'download', + api: '${base}/chapter/export/${chapterId}', + }, + { + type: 'action', + label: '删除', + level: 'danger', + confirmTitle: '确认删除', + confirmText: '确认删除名称为「${name}」的章节吗?', + actionType: 'ajax', + api: 'get:${base}/chapter/remove/${chapterId}', + }, + ], + }, + ], + }, + ], + }, + } } diff --git a/src/main/resources/static/components/chapter.js b/src/main/resources/static/components/chapter.js index 42a2c01..7aeed4b 100644 --- a/src/main/resources/static/components/chapter.js +++ b/src/main/resources/static/components/chapter.js @@ -1,68 +1,230 @@ function chapterForm() { - return { - type: 'form', - ...horizontalFormOptions(), - body: [ - { - type: 'hidden', - name: 'id', - }, - { - type: 'input-number', - name: 'sequence', - label: '章节数', - required: true, - step: 1, - precision: 0, - }, - { - type: 'input-text', - name: 'name', - label: '名称', - ...formInputClearable(), - }, - { - type: 'textarea', - name: 'description', - label: '简介', - ...formInputClearable(), - showCounter: true, - trimContents: true, - minRows: 2, - maxRows: 2, - maxLength: 100, - }, - ], - } + return { + type: 'form', + ...horizontalFormOptions(), + body: [ + { + type: 'hidden', + name: 'id', + }, + { + type: 'input-number', + name: 'sequence', + label: '章节数', + required: true, + step: 1, + precision: 0, + }, + { + type: 'input-text', + name: 'name', + label: '名称', + ...formInputClearable(), + }, + { + type: 'textarea', + name: 'description', + label: '简介', + ...formInputClearable(), + showCounter: true, + trimContents: true, + minRows: 2, + maxRows: 2, + maxLength: 100, + }, + ], + } } function chapterAddDialog() { - return { - type: 'action', - actionType: 'dialog', - dialog: { - title: '新增章节', - size: 'md', - body: { - ...chapterForm(), - api: '${base}/chapter/save/${bookId}', - }, - }, - } + return { + type: 'action', + actionType: 'dialog', + dialog: { + title: '新增章节', + size: 'md', + body: { + ...chapterForm(), + api: '${base}/chapter/save/${bookId}', + }, + }, + } } function chapterDetailDialog() { - return { - type: 'action', - actionType: 'dialog', - dialog: { - title: '编辑章节', - size: 'md', - body: { - ...chapterForm(), - initApi: '${base}/chapter/detail/${chapterId}', - api: '${base}/chapter/save/${bookId}', - }, + return { + type: 'action', + actionType: 'dialog', + dialog: { + title: '编辑章节', + size: 'lg', + actions: [], + body: [ + { + id: 'chapter-detail-dialog-form', + ...chapterForm(), + initApi: '${base}/chapter/detail/${chapterId}', + api: '${base}/chapter/save/${bookId}', }, - } + { + type: 'flex', + className: 'mt-5', + justify: 'flex-end', + items: [ + { + type: 'action', + label: '保存', + level: 'primary', + onEvent: { + click: { + actions: [ + { + actionType: 'submit', + componentId: 'chapter-detail-dialog-form', + }, + { + actionType: 'reload', + componentId: 'chapter-list', + } + ] + } + } + } + ] + }, + { + type: 'crud', + ...crudCommonOptions(), + api: { + method: 'get', + url: '${base}/line/list/${chapterId}', + data: { + page: '${page|default:1}', + size: '${size|default:10}' + } + }, + quickSaveItemApi: '${base}/line/update/${lineId}', + headerToolbar: [ + 'reload', + { + type: 'action', + label: '', + icon: 'fa fa-upload', + actionType: 'dialog', + dialog: { + title: '导入正文', + size: 'lg', + body: { + type: 'form', + api: '${base}/chapter/import/${chapterId}', + mode: 'normal', + body: [ + { + type: 'switch', + name: 'override', + label: '覆盖导入', + }, + { + type: 'textarea', + name: 'text', + label: '正文', + required: true, + ...formInputClearable(), + showCounter: true, + trimContents: true, + minRows: 10, + maxRows: 10, + }, + ], + }, + }, + }, + ], + footerToolbar: [ + paginationOption(), + ], + columns: [ + { + name: 'sequence', + label: '行号', + width: 50, + }, + { + name: 'text', + label: '内容', + quickEdit: { + saveImmediately: true, + resetOnFailed: true, + type: 'textarea', + showCounter: true, + trimContents: true, + minRows: 10, + maxRows: 10, + }, + }, + { + type: 'operation', + label: '操作', + fixed: 'right', + className: 'nowrap', + width: 100, + buttons: [ + { + type: 'action', + label: '处理', + actionType: 'dialog', + dialog: { + title: '文本处理', + size: 'lg', + body: { + debug: true, + type: 'form', + canAccessSuperData: false, + initApi: '${base}/line/detail/${lineId}', + api: '${base}/line/save/${chapterId}', + body: [ + { + type: 'hidden', + name: 'lineId', + }, + { + type: 'textarea', + name: 'text', + label: '正文', + ...formInputClearable(), + showCounter: true, + trimContents: true, + minRows: 5, + maxRows: 5, + }, + { + type: 'textarea', + name: 'newText', + label: '优化后正文', + ...formInputClearable(), + showCounter: true, + trimContents: true, + minRows: 5, + maxRows: 5, + }, + ] + } + } + }, + { + type: 'action', + label: '删除', + level: 'danger', + confirmTitle: '确认删除', + confirmText: '确认删除当前行吗?', + actionType: 'ajax', + api: 'get:${base}/line/remove/${lineId}', + }, + ] + } + ], + }, + ] + }, + } } \ No newline at end of file diff --git a/src/main/resources/static/components/helper.js b/src/main/resources/static/components/helper.js index e2861e3..eec46d9 100644 --- a/src/main/resources/static/components/helper.js +++ b/src/main/resources/static/components/helper.js @@ -1,37 +1,38 @@ function crudCommonOptions() { - return { - affixHeader: false, - stopAutoRefreshWhenModalIsOpen: true, - resizable: false, - syncLocation: false, - silentPolling: true, - } + return { + affixHeader: false, + stopAutoRefreshWhenModalIsOpen: true, + resizable: false, + syncLocation: false, + silentPolling: true, + } } -function horizontalFormOptions() { - return { - mode: 'horizontal', - canAccessSuperData: false, - horizontal: { - left: 1, - }, - } +function horizontalFormOptions(left = 1) { + return { + mode: 'horizontal', + canAccessSuperData: false, + horizontal: { + left: left, + justify: true, + }, + } } function formInputClearable() { - return { - clearable: true, - clearValueOnEmpty: true, - } + return { + clearable: true, + clearValueOnEmpty: true, + } } function paginationOption() { - return { - type: 'pagination', - mode: 'normal', - layout: 'total,perPage,pager', - maxButtons: 5, - showPageInput: false, - total: '${total}' - } + return { + type: 'pagination', + mode: 'normal', + layout: 'total,perPage,pager', + maxButtons: 5, + showPageInput: false, + total: '${total}' + } } diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html index f2a77c1..e74dde6 100644 --- a/src/main/resources/static/index.html +++ b/src/main/resources/static/index.html @@ -31,345 +31,103 @@ \ No newline at end of file