├── pkg
├── ui
│ ├── src
│ │ ├── views
│ │ │ ├── setting
│ │ │ │ └── wechatMenu.vue
│ │ │ ├── category
│ │ │ │ └── emun
│ │ │ │ │ └── index.js
│ │ │ ├── comicCategory
│ │ │ │ └── emun
│ │ │ │ │ └── index.js
│ │ │ ├── redirect
│ │ │ │ └── index.vue
│ │ │ ├── users
│ │ │ │ └── emun
│ │ │ │ │ └── index.js
│ │ │ ├── login
│ │ │ │ └── auth-redirect.vue
│ │ │ ├── permission
│ │ │ │ ├── page.vue
│ │ │ │ └── components
│ │ │ │ │ └── SwitchRoles.vue
│ │ │ ├── dashboard
│ │ │ │ └── index.vue
│ │ │ ├── comics
│ │ │ │ └── emun
│ │ │ │ │ └── index.js
│ │ │ ├── books
│ │ │ │ └── emun
│ │ │ │ │ └── index.js
│ │ │ └── guide
│ │ │ │ ├── index.vue
│ │ │ │ └── steps.js
│ │ ├── assets
│ │ │ ├── logo-min.png
│ │ │ ├── 401_images
│ │ │ │ └── 401.gif
│ │ │ ├── 404_images
│ │ │ │ ├── 404.png
│ │ │ │ └── 404_cloud.png
│ │ │ └── custom-theme
│ │ │ │ └── fonts
│ │ │ │ ├── element-icons.ttf
│ │ │ │ └── element-icons.woff
│ │ ├── App.vue
│ │ ├── icons
│ │ │ ├── svg
│ │ │ │ ├── chart.svg
│ │ │ │ ├── size.svg
│ │ │ │ ├── link.svg
│ │ │ │ ├── component.svg
│ │ │ │ ├── guide.svg
│ │ │ │ ├── money.svg
│ │ │ │ ├── email.svg
│ │ │ │ ├── drag.svg
│ │ │ │ ├── documentation.svg
│ │ │ │ ├── fullscreen.svg
│ │ │ │ ├── lock.svg
│ │ │ │ ├── user.svg
│ │ │ │ ├── excel.svg
│ │ │ │ ├── example.svg
│ │ │ │ ├── star.svg
│ │ │ │ ├── table.svg
│ │ │ │ ├── search.svg
│ │ │ │ ├── password.svg
│ │ │ │ ├── education.svg
│ │ │ │ ├── tab.svg
│ │ │ │ ├── message.svg
│ │ │ │ ├── theme.svg
│ │ │ │ ├── peoples.svg
│ │ │ │ ├── edit.svg
│ │ │ │ ├── nested.svg
│ │ │ │ ├── tree-table.svg
│ │ │ │ ├── eye.svg
│ │ │ │ ├── clipboard.svg
│ │ │ │ ├── list.svg
│ │ │ │ ├── icon.svg
│ │ │ │ ├── international.svg
│ │ │ │ ├── wechat.svg
│ │ │ │ ├── skill.svg
│ │ │ │ ├── people.svg
│ │ │ │ ├── language.svg
│ │ │ │ ├── eye-open.svg
│ │ │ │ ├── 404.svg
│ │ │ │ └── zip.svg
│ │ │ ├── index.js
│ │ │ └── svgo.yml
│ │ ├── api
│ │ │ ├── lime-admin
│ │ │ │ ├── upload.js
│ │ │ │ ├── enum
│ │ │ │ │ └── index.js
│ │ │ │ ├── comment.js
│ │ │ │ ├── comicComment.js
│ │ │ │ ├── setting.js
│ │ │ │ ├── category.js
│ │ │ │ ├── comicCategory.js
│ │ │ │ ├── chapter.js
│ │ │ │ ├── comicChapter.js
│ │ │ │ ├── users.js
│ │ │ │ ├── distributorLevel.js
│ │ │ │ └── distributor.js
│ │ │ ├── auth-admin
│ │ │ │ ├── enum
│ │ │ │ │ └── index.js
│ │ │ │ ├── auth.js
│ │ │ │ └── user.js
│ │ │ └── user.js
│ │ ├── components
│ │ │ ├── ImageCropper
│ │ │ │ └── utils
│ │ │ │ │ ├── mimes.js
│ │ │ │ │ ├── data2blob.js
│ │ │ │ │ └── effectRipple.js
│ │ │ ├── Tinymce
│ │ │ │ ├── toolbar.js
│ │ │ │ └── plugins.js
│ │ │ ├── MarkdownEditor
│ │ │ │ └── default-options.js
│ │ │ ├── Screenfull
│ │ │ │ └── index.vue
│ │ │ └── Hamburger
│ │ │ │ └── index.vue
│ │ ├── utils
│ │ │ ├── get-page-title.js
│ │ │ ├── auth.js
│ │ │ ├── permission.js
│ │ │ ├── clipboard.js
│ │ │ ├── error-log.js
│ │ │ └── open-window.js
│ │ ├── layout
│ │ │ ├── components
│ │ │ │ ├── index.js
│ │ │ │ ├── Sidebar
│ │ │ │ │ ├── Item.vue
│ │ │ │ │ ├── FixiOSBug.js
│ │ │ │ │ └── Link.vue
│ │ │ │ └── AppMain.vue
│ │ │ └── mixin
│ │ │ │ └── ResizeHandler.js
│ │ ├── directive
│ │ │ ├── waves
│ │ │ │ ├── index.js
│ │ │ │ └── waves.css
│ │ │ ├── el-drag-dialog
│ │ │ │ └── index.js
│ │ │ ├── clipboard
│ │ │ │ └── index.js
│ │ │ ├── permission
│ │ │ │ ├── index.js
│ │ │ │ └── permission.js
│ │ │ └── el-table
│ │ │ │ ├── index.js
│ │ │ │ └── adaptive.js
│ │ ├── store
│ │ │ ├── modules
│ │ │ │ ├── errorLog.js
│ │ │ │ └── settings.js
│ │ │ ├── getters.js
│ │ │ └── index.js
│ │ ├── vendor
│ │ │ └── Export2Zip.js
│ │ ├── styles
│ │ │ ├── variables.scss
│ │ │ ├── element-variables.scss
│ │ │ ├── transition.scss
│ │ │ └── element-ui.scss
│ │ └── settings.js
│ ├── .eslintignore
│ ├── babel.config.js
│ ├── postcss.config.js
│ ├── public
│ │ ├── favicon.ico
│ │ └── index.html
│ ├── tests
│ │ └── unit
│ │ │ ├── .eslintrc.js
│ │ │ ├── components
│ │ │ ├── Hamburger.spec.js
│ │ │ └── SvgIcon.spec.js
│ │ │ └── utils
│ │ │ ├── formatTime.spec.js
│ │ │ ├── validate.spec.js
│ │ │ └── parseTime.spec.js
│ ├── .travis.yml
│ ├── .env.staging
│ ├── .env.production
│ ├── jsconfig.json
│ ├── plop-templates
│ │ ├── utils.js
│ │ ├── store
│ │ │ └── index.hbs
│ │ ├── view
│ │ │ ├── index.hbs
│ │ │ └── prompt.js
│ │ └── component
│ │ │ ├── index.hbs
│ │ │ └── prompt.js
│ ├── .env.development
│ ├── .editorconfig
│ ├── .gitignore
│ ├── plopfile.js
│ ├── jest.config.js
│ ├── build
│ │ └── index.js
│ ├── LICENSE
│ └── mock
│ │ └── index.js
├── h5
│ ├── .eslintignore
│ ├── static
│ │ └── images
│ │ │ ├── 1.jpg
│ │ │ ├── 2.jpg
│ │ │ ├── 3.jpg
│ │ │ ├── 4.jpg
│ │ │ ├── 5.jpg
│ │ │ ├── sprite.0.50.png
│ │ │ └── sprite@2x.0.50.png
│ ├── src
│ │ ├── components
│ │ │ ├── rate
│ │ │ │ ├── star_off.png
│ │ │ │ ├── star_on.png
│ │ │ │ └── star_half.png
│ │ │ └── common
│ │ │ │ ├── HorizontalList.vue
│ │ │ │ ├── Similar.vue
│ │ │ │ ├── TopMenu.vue
│ │ │ │ └── VerticalList.vue
│ │ ├── store
│ │ │ ├── index.js
│ │ │ └── modules
│ │ │ │ ├── types.js
│ │ │ │ └── state.js
│ │ ├── assets
│ │ │ ├── logo.svg
│ │ │ ├── lock.svg
│ │ │ └── user.svg
│ │ ├── utils
│ │ │ └── auth.js
│ │ ├── App.vue
│ │ ├── main.js
│ │ └── permission.js
│ ├── README.md
│ ├── config
│ │ ├── prod.env.js
│ │ ├── test.env.js
│ │ └── dev.env.js
│ ├── .editorconfig
│ ├── .gitignore
│ ├── .postcssrc.js
│ ├── index.html
│ ├── .babelrc
│ ├── build
│ │ ├── vue-loader.conf.js
│ │ ├── webpack.test.conf.js
│ │ ├── build.js
│ │ └── check-versions.js
│ └── .eslintrc.js
├── api
│ ├── admin
│ │ ├── model
│ │ │ ├── base.go
│ │ │ ├── spider.go
│ │ │ ├── chapter.go
│ │ │ ├── book.go
│ │ │ ├── comicCategory.go
│ │ │ ├── category.go
│ │ │ ├── comicComments.go
│ │ │ ├── comments.go
│ │ │ ├── config.go
│ │ │ ├── distributor.go
│ │ │ ├── comicChapters.go
│ │ │ ├── chapters.go
│ │ │ └── distributorLevel.go
│ │ ├── dto
│ │ │ ├── upload.go
│ │ │ ├── chapter.go
│ │ │ ├── general.go
│ │ │ ├── init.go
│ │ │ ├── comicComment.go
│ │ │ ├── comment.go
│ │ │ └── comicCategory.go
│ │ ├── controllers
│ │ │ ├── rule.go
│ │ │ ├── upload.go
│ │ │ ├── setting.go
│ │ │ ├── base.go
│ │ │ ├── comments.go
│ │ │ └── comicComments.go
│ │ ├── service
│ │ │ ├── upload.go
│ │ │ ├── comments.go
│ │ │ └── comicComments.go
│ │ ├── domain
│ │ │ └── task
│ │ │ │ └── task_lock.go
│ │ └── dao
│ │ │ ├── spider.go
│ │ │ ├── book.go
│ │ │ ├── chapter.go
│ │ │ ├── comment.go
│ │ │ ├── comicComment.go
│ │ │ ├── category.go
│ │ │ └── comicCategory.go
│ ├── front
│ │ ├── domain
│ │ │ ├── wechat
│ │ │ │ └── subscribe.go
│ │ │ └── auth
│ │ │ │ ├── login
│ │ │ │ └── general.go
│ │ │ │ └── account.go
│ │ ├── dao
│ │ │ ├── category.go
│ │ │ ├── config.go
│ │ │ ├── chapters.go
│ │ │ └── books.go
│ │ ├── controllers
│ │ │ ├── wechat.go
│ │ │ ├── chapters.go
│ │ │ └── books.go
│ │ └── dto
│ │ │ ├── general.go
│ │ │ ├── user.go
│ │ │ └── init.go
│ ├── middleware
│ │ ├── auth.go
│ │ ├── cors.go
│ │ └── file.go
│ ├── router
│ │ ├── router.go
│ │ └── front.go
│ └── utils
│ │ └── e
│ │ └── code.go
├── crawler
│ ├── novels
│ │ ├── biquge
│ │ │ ├── list.go
│ │ │ ├── book.go
│ │ │ └── chapter.go
│ │ ├── store.go
│ │ └── aoyuge
│ │ │ └── file.go
│ └── core
│ │ └── task.go
├── down
│ ├── site
│ │ ├── jjxs.go
│ │ └── site_chromedp.go
│ ├── convert.go
│ ├── job.go
│ ├── util.go
│ ├── store
│ │ └── store.go
│ ├── output
│ │ ├── txt.go
│ │ └── output.go
│ ├── search.go
│ └── syncstore.go
└── common
│ ├── types.go
│ ├── db
│ ├── mongo_test.go
│ └── db_test.go
│ └── cache
│ └── init.go
├── .gitignore
├── docs
└── image
│ ├── 1.png
│ ├── 2.png
│ ├── 3.png
│ ├── 4.png
│ ├── wx.jpg
│ ├── logo.png
│ ├── books.png
│ ├── upload.png
│ ├── category.png
│ └── chapters.png
├── CHANGELOG.md
├── scripts
├── build.sh
├── apppkg.sh
├── run.sh
├── tag.sh
└── version.sh
├── main.go
├── cmd
└── cobra.go
├── config
└── in-cluster.yaml
└── Makefile
/pkg/ui/src/views/setting/wechatMenu.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/ui/.eslintignore:
--------------------------------------------------------------------------------
1 | build/*.js
2 | src/assets
3 | public
4 | dist
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | lime
2 | .idea/
3 | data/
4 | go.sum
5 | config/in-local.yaml
6 |
--------------------------------------------------------------------------------
/docs/image/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/docs/image/1.png
--------------------------------------------------------------------------------
/docs/image/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/docs/image/2.png
--------------------------------------------------------------------------------
/docs/image/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/docs/image/3.png
--------------------------------------------------------------------------------
/docs/image/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/docs/image/4.png
--------------------------------------------------------------------------------
/docs/image/wx.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/docs/image/wx.jpg
--------------------------------------------------------------------------------
/docs/image/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/docs/image/logo.png
--------------------------------------------------------------------------------
/docs/image/books.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/docs/image/books.png
--------------------------------------------------------------------------------
/docs/image/upload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/docs/image/upload.png
--------------------------------------------------------------------------------
/pkg/h5/.eslintignore:
--------------------------------------------------------------------------------
1 | /build/
2 | /config/
3 | /dist/
4 | /*.js
5 | /test/unit/coverage/
6 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | v0.0.1 init 初始化
4 | V0.1 小说内容管理: 分类管理、小说列表、上传小说、热词列表、评论列表
5 |
--------------------------------------------------------------------------------
/docs/image/category.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/docs/image/category.png
--------------------------------------------------------------------------------
/docs/image/chapters.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/docs/image/chapters.png
--------------------------------------------------------------------------------
/pkg/ui/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/app'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/h5/static/images/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/pkg/h5/static/images/1.jpg
--------------------------------------------------------------------------------
/pkg/h5/static/images/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/pkg/h5/static/images/2.jpg
--------------------------------------------------------------------------------
/pkg/h5/static/images/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/pkg/h5/static/images/3.jpg
--------------------------------------------------------------------------------
/pkg/h5/static/images/4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/pkg/h5/static/images/4.jpg
--------------------------------------------------------------------------------
/pkg/h5/static/images/5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/pkg/h5/static/images/5.jpg
--------------------------------------------------------------------------------
/pkg/ui/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {}
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/ui/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/pkg/ui/public/favicon.ico
--------------------------------------------------------------------------------
/pkg/ui/tests/unit/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | jest: true
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/ui/src/assets/logo-min.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/pkg/ui/src/assets/logo-min.png
--------------------------------------------------------------------------------
/pkg/api/admin/model/base.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | type Pagination struct {
4 | Start int
5 | Limit int
6 | }
7 |
--------------------------------------------------------------------------------
/scripts/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | export GO111MODULE=on
4 | export GOPROXY=https://goproxy.io
5 | go build -o lime
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "lime/cmd"
5 | )
6 |
7 | func main() {
8 | cmd.Execute()
9 | }
10 |
--------------------------------------------------------------------------------
/pkg/h5/static/images/sprite.0.50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/pkg/h5/static/images/sprite.0.50.png
--------------------------------------------------------------------------------
/pkg/ui/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js: 10
3 | script: npm run test
4 | notifications:
5 | email: false
6 |
--------------------------------------------------------------------------------
/pkg/ui/src/assets/401_images/401.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/pkg/ui/src/assets/401_images/401.gif
--------------------------------------------------------------------------------
/pkg/ui/src/assets/404_images/404.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/pkg/ui/src/assets/404_images/404.png
--------------------------------------------------------------------------------
/pkg/h5/src/components/rate/star_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/pkg/h5/src/components/rate/star_off.png
--------------------------------------------------------------------------------
/pkg/h5/src/components/rate/star_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/pkg/h5/src/components/rate/star_on.png
--------------------------------------------------------------------------------
/pkg/h5/static/images/sprite@2x.0.50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/pkg/h5/static/images/sprite@2x.0.50.png
--------------------------------------------------------------------------------
/pkg/h5/README.md:
--------------------------------------------------------------------------------
1 | H5 阅读
2 |
3 |
4 | 特别鸣谢:
5 |
6 | 本H5项目查考: [https://github.com/YepFury/reader](https://github.com/YepFury/reader)
--------------------------------------------------------------------------------
/pkg/h5/src/components/rate/star_half.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/pkg/h5/src/components/rate/star_half.png
--------------------------------------------------------------------------------
/pkg/ui/src/assets/404_images/404_cloud.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/pkg/ui/src/assets/404_images/404_cloud.png
--------------------------------------------------------------------------------
/pkg/api/admin/dto/upload.go:
--------------------------------------------------------------------------------
1 | package dto
2 |
3 | type UploadTokenDto struct {
4 | key string `json:"key"`
5 | hash string `json:"hash"`
6 | }
7 |
--------------------------------------------------------------------------------
/pkg/h5/config/prod.env.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | module.exports = {
3 | NODE_ENV: '"production"',
4 | BASE_URL: '"//lime.bullteam.cn/"'
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/ui/.env.staging:
--------------------------------------------------------------------------------
1 | NODE_ENV = production
2 |
3 | # just a flag
4 | ENV = 'staging'
5 |
6 | # base api
7 | VUE_APP_BASE_API = '/stage-api'
8 |
9 |
--------------------------------------------------------------------------------
/pkg/ui/src/assets/custom-theme/fonts/element-icons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/pkg/ui/src/assets/custom-theme/fonts/element-icons.ttf
--------------------------------------------------------------------------------
/pkg/ui/src/assets/custom-theme/fonts/element-icons.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limeteam/lime/HEAD/pkg/ui/src/assets/custom-theme/fonts/element-icons.woff
--------------------------------------------------------------------------------
/scripts/apppkg.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | # get import path of current go project.
4 | ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5 | echo ${ROOT//$GOPATH\/src\//}
6 |
--------------------------------------------------------------------------------
/pkg/ui/.env.production:
--------------------------------------------------------------------------------
1 | # just a flag
2 | ENV = 'production'
3 |
4 | # base api
5 | VUE_APP_BASE_API = '//api.auth.bullteam.cn'
6 |
7 | VUE_APP_CONFIG_API = '//lime.bullteam.cn/'
8 |
--------------------------------------------------------------------------------
/pkg/ui/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "./",
4 | "paths": {
5 | "@/*": ["src/*"]
6 | }
7 | },
8 | "exclude": ["node_modules", "dist"]
9 | }
--------------------------------------------------------------------------------
/pkg/ui/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
--------------------------------------------------------------------------------
/pkg/h5/config/test.env.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const merge = require('webpack-merge')
3 | const devEnv = require('./dev.env')
4 |
5 | module.exports = merge(devEnv, {
6 | NODE_ENV: '"testing"'
7 | })
8 |
--------------------------------------------------------------------------------
/pkg/ui/src/views/category/emun/index.js:
--------------------------------------------------------------------------------
1 | export const CATEGORY_CHANNEL = [
2 | { key: 0, display_name: '全部' },
3 | { key: 1, display_name: '男生' },
4 | { key: 2, display_name: '女生' }
5 | ]
--------------------------------------------------------------------------------
/pkg/ui/src/views/comicCategory/emun/index.js:
--------------------------------------------------------------------------------
1 | export const CATEGORY_CHANNEL = [
2 | { key: 0, display_name: '全部' },
3 | { key: 1, display_name: '男生' },
4 | { key: 2, display_name: '女生' }
5 | ]
--------------------------------------------------------------------------------
/pkg/h5/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 4
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/chart.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/ui/src/api/lime-admin/upload.js:
--------------------------------------------------------------------------------
1 | import request from './request'
2 |
3 | export function getQiniuToken() {
4 | return request({
5 | url: '/admin/upload/qiniuToken',
6 | method: 'GET'
7 | })
8 | }
9 |
--------------------------------------------------------------------------------
/pkg/ui/src/components/ImageCropper/utils/mimes.js:
--------------------------------------------------------------------------------
1 | export default {
2 | 'jpg': 'image/jpeg',
3 | 'png': 'image/png',
4 | 'gif': 'image/gif',
5 | 'svg': 'image/svg+xml',
6 | 'psd': 'image/photoshop'
7 | }
8 |
--------------------------------------------------------------------------------
/pkg/ui/plop-templates/utils.js:
--------------------------------------------------------------------------------
1 | exports.notEmpty = name => {
2 | return v => {
3 | if (!v || v.trim === '') {
4 | return `${name} is required`
5 | } else {
6 | return true
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/scripts/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | export MYSQL_PASSWORD=123456
4 | export MYSQL_HOST=127.0.0.1
5 | export MYSQL_DB=lime
6 | export MYSQL_PORT=3306
7 | export MYSQL_USERNAME=root
8 |
9 | ./lime server ./config/in-local.yaml -p 808
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/size.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/h5/config/dev.env.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const merge = require('webpack-merge')
3 | const prodEnv = require('./prod.env')
4 |
5 | module.exports = merge(prodEnv, {
6 | NODE_ENV: '"development"',
7 | BASE_URL: '"//127.0.0.1:8080/"'
8 | })
9 |
--------------------------------------------------------------------------------
/pkg/ui/src/api/auth-admin/enum/index.js:
--------------------------------------------------------------------------------
1 | export const TOKEN_EXPIRATION = [
2 | // 需要登录
3 | 111001002,
4 | // token 无效
5 | 111001003,
6 | // token 过期
7 | 111001004,
8 | // token 无法解密
9 | 109001010
10 | ]
11 | export const NOT_SHOW_MSG = []
12 |
--------------------------------------------------------------------------------
/pkg/ui/src/api/lime-admin/enum/index.js:
--------------------------------------------------------------------------------
1 | export const TOKEN_EXPIRATION = [
2 | // 需要登录
3 | 111001002,
4 | // token 无效
5 | 111001003,
6 | // token 过期
7 | 111001004,
8 | // token 无法解密
9 | 109001010
10 | ]
11 | export const NOT_SHOW_MSG = []
12 |
--------------------------------------------------------------------------------
/pkg/crawler/novels/biquge/list.go:
--------------------------------------------------------------------------------
1 | package biquge
2 |
3 | import (
4 | "fmt"
5 | "lime/pkg/crawler/novels"
6 | )
7 |
8 | //采集列表页面
9 |
10 | func Test() {
11 | rules := novels.GetRules()
12 | fmt.Println(rules.RuleConfigInfo.GetSiteUrl.Pattern)
13 | }
14 |
--------------------------------------------------------------------------------
/pkg/down/site/jjxs.go:
--------------------------------------------------------------------------------
1 | package site
2 |
3 | var jyxs = SiteA{
4 | Name: "精英小说",
5 | HomePage: "http://www.jyyxs.com/",
6 | Match: []string{
7 | `https://www\.jyyxs\.com/\d+_\d+/*`,
8 | `https://www\.jyyxs\.com/\d+_\d+/\d+\.html/*`,
9 | },
10 | }
11 |
--------------------------------------------------------------------------------
/pkg/h5/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | /dist/
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | /test/
8 | selenium-debug.log
9 |
10 | # Editor directories and files
11 | .idea
12 | .vscode
13 | *.suo
14 | *.ntvs*
15 | *.njsproj
16 | *.sln
17 |
--------------------------------------------------------------------------------
/pkg/api/front/domain/wechat/subscribe.go:
--------------------------------------------------------------------------------
1 | package wechat
2 |
3 | import "github.com/silenceper/wechat/v2/officialaccount/message"
4 |
5 | func Subscribe() *message.Reply {
6 | text := message.NewText("欢迎关注lime soft!")
7 | return &message.Reply{MsgType: message.MsgTypeText, MsgData: text}
8 | }
9 |
--------------------------------------------------------------------------------
/pkg/common/types.go:
--------------------------------------------------------------------------------
1 | package common
2 |
3 | const (
4 | OutputTypeMySQL = "mysql"
5 | OutputTypeCSV = "csv"
6 | OutputDbBook = "book"
7 | OutputMongodb = "mongodb"
8 | OutputYaml = "yaml"
9 | )
10 |
11 | type MTS struct {
12 | ID int
13 | Status TaskStatus
14 | }
15 |
--------------------------------------------------------------------------------
/pkg/ui/plop-templates/store/index.hbs:
--------------------------------------------------------------------------------
1 | {{#if state}}
2 | const state = {}
3 | {{/if}}
4 |
5 | {{#if mutations}}
6 | const mutations = {}
7 | {{/if}}
8 |
9 | {{#if actions}}
10 | const actions = {}
11 | {{/if}}
12 |
13 | export default {
14 | namespaced: true,
15 | {{options}}
16 | }
17 |
--------------------------------------------------------------------------------
/pkg/ui/src/utils/get-page-title.js:
--------------------------------------------------------------------------------
1 | import defaultSettings from '@/settings'
2 |
3 | const title = defaultSettings.title || 'Zeus Admin'
4 |
5 | export default function getPageTitle(pageTitle) {
6 | if (pageTitle) {
7 | return `${pageTitle} - ${title}`
8 | }
9 | return `${title}`
10 | }
11 |
--------------------------------------------------------------------------------
/pkg/h5/.postcssrc.js:
--------------------------------------------------------------------------------
1 | // https://github.com/michael-ciniawsky/postcss-load-config
2 |
3 | module.exports = {
4 | "plugins": {
5 | "postcss-import": {},
6 | "postcss-url": {},
7 | // to edit target browsers: use "browserslist" field in package.json
8 | "autoprefixer": {}
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/pkg/ui/.env.development:
--------------------------------------------------------------------------------
1 | # just a flag
2 | ENV = 'development'
3 |
4 | # base api
5 | #VUE_APP_BASE_API = '/dev-api'
6 | VUE_CLI_BABEL_TRANSPILE_MODULES = true
7 |
8 | VUE_APP_BASE_API = '//api.auth.bullteam.cn'
9 | #VUE_APP_BASE_API = '//127.0.0.1:8082'
10 | VUE_APP_CONFIG_API = '//127.0.0.1:8080'
11 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/link.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/ui/src/layout/components/index.js:
--------------------------------------------------------------------------------
1 | export { default as AppMain } from './AppMain'
2 | export { default as Navbar } from './Navbar'
3 | export { default as Settings } from './Settings'
4 | export { default as Sidebar } from './Sidebar/index.vue'
5 | export { default as TagsView } from './TagsView/index.vue'
6 |
--------------------------------------------------------------------------------
/pkg/ui/src/directive/waves/index.js:
--------------------------------------------------------------------------------
1 | import waves from './waves'
2 |
3 | const install = function(Vue) {
4 | Vue.directive('waves', waves)
5 | }
6 |
7 | if (window.Vue) {
8 | window.waves = waves
9 | Vue.use(install); // eslint-disable-line
10 | }
11 |
12 | waves.install = install
13 | export default waves
14 |
--------------------------------------------------------------------------------
/scripts/tag.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # TODO modify TAG of released Naftis during CI
4 | # export TAG=$(if [ `git branch | grep \* | cut -d ' ' -f2` != "master" ]; then git checkout master --quiet; fi && git describe --tags --abbrev=0)
5 | if [[ -z $TAG ]]; then
6 | TAG=`git describe --tags --abbrev=0`
7 | fi
8 |
9 | echo $TAG
--------------------------------------------------------------------------------
/pkg/ui/.editorconfig:
--------------------------------------------------------------------------------
1 | # https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | end_of_line = lf
9 | insert_final_newline = true
10 | trim_trailing_whitespace = true
11 |
12 | [*.md]
13 | insert_final_newline = false
14 | trim_trailing_whitespace = false
15 |
--------------------------------------------------------------------------------
/pkg/ui/src/views/redirect/index.vue:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/pkg/h5/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 |
4 | import state from './modules/state'
5 | import actions from './modules/actions'
6 | import mutations from './modules/mutations'
7 |
8 | Vue.use(Vuex);
9 |
10 | export default new Vuex.Store({
11 | state,
12 | actions,
13 | mutations
14 | })
15 |
--------------------------------------------------------------------------------
/pkg/ui/src/directive/el-drag-dialog/index.js:
--------------------------------------------------------------------------------
1 | import drag from './drag'
2 |
3 | const install = function(Vue) {
4 | Vue.directive('el-drag-dialog', drag)
5 | }
6 |
7 | if (window.Vue) {
8 | window['el-drag-dialog'] = drag
9 | Vue.use(install); // eslint-disable-line
10 | }
11 |
12 | drag.install = install
13 | export default drag
14 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/component.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/guide.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import SvgIcon from '@/components/SvgIcon'// svg component
3 |
4 | // register globally
5 | Vue.component('svg-icon', SvgIcon)
6 |
7 | const req = require.context('./svg', false, /\.svg$/)
8 | const requireAll = requireContext => requireContext.keys().map(requireContext)
9 | requireAll(req)
10 |
--------------------------------------------------------------------------------
/pkg/h5/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Lime
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/pkg/h5/src/assets/logo.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/pkg/ui/src/directive/clipboard/index.js:
--------------------------------------------------------------------------------
1 | import Clipboard from './clipboard'
2 |
3 | const install = function(Vue) {
4 | Vue.directive('Clipboard', Clipboard)
5 | }
6 |
7 | if (window.Vue) {
8 | window.clipboard = Clipboard
9 | Vue.use(install); // eslint-disable-line
10 | }
11 |
12 | Clipboard.install = install
13 | export default Clipboard
14 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/money.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/h5/src/utils/auth.js:
--------------------------------------------------------------------------------
1 | import Cookies from 'js-cookie'
2 |
3 | const TokenKey = 'Lime-Token'
4 |
5 | export function getToken() {
6 | return Cookies.get(TokenKey)
7 | }
8 |
9 | export function setToken(token) {
10 | return Cookies.set(TokenKey, token)
11 | }
12 |
13 | export function removeToken() {
14 | return Cookies.remove(TokenKey)
15 | }
16 |
--------------------------------------------------------------------------------
/pkg/ui/src/utils/auth.js:
--------------------------------------------------------------------------------
1 | import Cookies from 'js-cookie'
2 |
3 | const TokenKey = 'Admin-Token'
4 |
5 | export function getToken() {
6 | return Cookies.get(TokenKey)
7 | }
8 |
9 | export function setToken(token) {
10 | return Cookies.set(TokenKey, token)
11 | }
12 |
13 | export function removeToken() {
14 | return Cookies.remove(TokenKey)
15 | }
16 |
--------------------------------------------------------------------------------
/pkg/ui/src/directive/permission/index.js:
--------------------------------------------------------------------------------
1 | import permission from './permission'
2 |
3 | const install = function(Vue) {
4 | Vue.directive('permission', permission)
5 | }
6 |
7 | if (window.Vue) {
8 | window['permission'] = permission
9 | Vue.use(install); // eslint-disable-line
10 | }
11 |
12 | permission.install = install
13 | export default permission
14 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/email.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/api/front/dao/category.go:
--------------------------------------------------------------------------------
1 | package dao
2 |
3 | import (
4 | "lime/pkg/api/admin/model"
5 | "lime/pkg/common/db"
6 | )
7 |
8 | type CategoryDao struct {}
9 |
10 |
11 | func (c CategoryDao) GetAll() []model.Category {
12 | var Category []model.Category
13 | db := db.GetGormDB()
14 | db.Model(&model.Category{}).Find(&Category)
15 | return Category
16 | }
17 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/drag.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svgo.yml:
--------------------------------------------------------------------------------
1 | # replace default config
2 |
3 | # multipass: true
4 | # full: true
5 |
6 | plugins:
7 |
8 | # - name
9 | #
10 | # or:
11 | # - name: false
12 | # - name: true
13 | #
14 | # or:
15 | # - name:
16 | # param1: 1
17 | # param2: 2
18 |
19 | - removeAttrs:
20 | attrs:
21 | - 'fill'
22 | - 'fill-rule'
23 |
--------------------------------------------------------------------------------
/pkg/ui/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | dist/
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | **/*.log
8 |
9 | tests/**/coverage/
10 | tests/e2e/reports
11 | selenium-debug.log
12 |
13 | # Editor directories and files
14 | .idea
15 | .vscode
16 | *.suo
17 | *.ntvs*
18 | *.njsproj
19 | *.sln
20 | *.local
21 |
22 | package-lock.json
23 | yarn.lock
24 |
--------------------------------------------------------------------------------
/pkg/ui/src/directive/el-table/index.js:
--------------------------------------------------------------------------------
1 | import adaptive from './adaptive'
2 |
3 | const install = function(Vue) {
4 | Vue.directive('el-height-adaptive-table', adaptive)
5 | }
6 |
7 | if (window.Vue) {
8 | window['el-height-adaptive-table'] = adaptive
9 | Vue.use(install); // eslint-disable-line
10 | }
11 |
12 | adaptive.install = install
13 | export default adaptive
14 |
--------------------------------------------------------------------------------
/pkg/ui/src/api/lime-admin/comment.js:
--------------------------------------------------------------------------------
1 | import request from './request'
2 |
3 | export function CommentList() {
4 | return request({
5 | url: '/admin/novels/comments',
6 | method: 'GET'
7 | })
8 | }
9 |
10 | export function deleteComment(id,data) {
11 | return request({
12 | url: '/admin/novels/comments/' + id,
13 | method: 'delete',
14 | data: data
15 | })
16 | }
17 |
--------------------------------------------------------------------------------
/pkg/ui/src/api/lime-admin/comicComment.js:
--------------------------------------------------------------------------------
1 | import request from './request'
2 |
3 | export function CommentList() {
4 | return request({
5 | url: '/admin/comics/comments',
6 | method: 'GET'
7 | })
8 | }
9 |
10 | export function deleteComment(id,data) {
11 | return request({
12 | url: '/admin/comics/comments/' + id,
13 | method: 'delete',
14 | data: data
15 | })
16 | }
17 |
--------------------------------------------------------------------------------
/pkg/api/admin/model/spider.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "github.com/globalsign/mgo/bson"
5 | "time"
6 | )
7 |
8 | type Spider struct {
9 | Id bson.ObjectId `json:"_id" bson:"_id"`
10 | AppName string `json:"app_name" bson:"app_name"`
11 | CreatedAt time.Time `json:"create_at" bson:"create_at"`
12 | UpdatedAt time.Time `json:"update_at" bson:"update_at"`
13 | }
14 |
--------------------------------------------------------------------------------
/pkg/ui/src/views/users/emun/index.js:
--------------------------------------------------------------------------------
1 | export const USERS_GENDER = [ //性别
2 | { key: 1, display_name: '男' },
3 | { key: 2, display_name: '女' }
4 | ]
5 |
6 | export const USERS_STATUS = [ //用户状态
7 | { key: 0, display_name: '正常' },
8 | { key: 1, display_name: '封禁' }
9 | ]
10 |
11 | export const USERS_ROBOTS = [ //是否免登
12 | { key: 0, display_name: '是' },
13 | { key: 1, display_name: '否' }
14 | ]
15 |
--------------------------------------------------------------------------------
/pkg/api/front/controllers/wechat.go:
--------------------------------------------------------------------------------
1 | package controllers
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "lime/pkg/api/admin/controllers"
6 | "lime/pkg/api/front/service"
7 | )
8 |
9 | type WechatController struct {
10 | controllers.BaseController
11 | }
12 |
13 | var WechatService = service.WechatService{}
14 |
15 | func (C *WechatController) Callback(c *gin.Context) {
16 | WechatService.Callback(c)
17 | }
--------------------------------------------------------------------------------
/pkg/h5/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
21 |
--------------------------------------------------------------------------------
/pkg/ui/src/views/login/auth-redirect.vue:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/pkg/ui/plopfile.js:
--------------------------------------------------------------------------------
1 | const viewGenerator = require('./plop-templates/view/prompt')
2 | const componentGenerator = require('./plop-templates/component/prompt')
3 | const storeGenerator = require('./plop-templates/store/prompt.js')
4 |
5 | module.exports = function(plop) {
6 | plop.setGenerator('view', viewGenerator)
7 | plop.setGenerator('component', componentGenerator)
8 | plop.setGenerator('store', storeGenerator)
9 | }
10 |
--------------------------------------------------------------------------------
/pkg/api/front/domain/auth/login/general.go:
--------------------------------------------------------------------------------
1 | package login
2 |
3 | import (
4 | "lime/pkg/api/front/domain/auth"
5 | "lime/pkg/api/admin/model"
6 | )
7 |
8 | // VerifyPassword : verify password by salt
9 | func VerifyPassword(password string, userModel model.Users) bool {
10 | if pwd, err := auth.HashPassword(password, userModel.Salt); err == nil && pwd == userModel.Password {
11 | return true
12 | }
13 | return false
14 | }
15 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/documentation.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/fullscreen.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/h5/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["env", {
4 | "modules": false,
5 | "targets": {
6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
7 | }
8 | }],
9 | "stage-2"
10 | ],
11 | "plugins": ["transform-vue-jsx", "transform-runtime"],
12 | "env": {
13 | "test": {
14 | "presets": ["env", "stage-2"],
15 | "plugins": ["transform-vue-jsx", "istanbul"]
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/pkg/ui/plop-templates/view/index.hbs:
--------------------------------------------------------------------------------
1 | {{#if template}}
2 |
3 |
4 |
5 | {{/if}}
6 |
7 | {{#if script}}
8 |
20 | {{/if}}
21 |
22 | {{#if style}}
23 |
26 | {{/if}}
27 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/lock.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/user.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/ui/plop-templates/component/index.hbs:
--------------------------------------------------------------------------------
1 | {{#if template}}
2 |
3 |
4 |
5 | {{/if}}
6 |
7 | {{#if script}}
8 |
20 | {{/if}}
21 |
22 | {{#if style}}
23 |
26 | {{/if}}
27 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/excel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/ui/src/views/permission/page.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
20 |
--------------------------------------------------------------------------------
/pkg/api/middleware/auth.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "lime/pkg/api/front/domain/auth"
6 | "net/http"
7 | )
8 |
9 | func AuthMiddleware() gin.HandlerFunc {
10 | return func(c *gin.Context) {
11 | err := auth.TokenValid(c.Request)
12 | if err != nil {
13 | c.JSON(http.StatusUnauthorized, gin.H{
14 | "code": http.StatusUnauthorized,
15 | "msg": err.Error(),
16 | })
17 | c.Abort()
18 | return
19 | }
20 | c.Next()
21 | }
22 | }
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/example.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/api/admin/controllers/rule.go:
--------------------------------------------------------------------------------
1 | package controllers
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | log "github.com/sirupsen/logrus"
6 | "lime/pkg/crawler/core"
7 | )
8 |
9 | type RuleController struct {
10 | BaseController
11 | }
12 |
13 | func (C *RuleController) GetRuleList(c *gin.Context) {
14 | keys := core.GetTaskRuleKeys()
15 | if len(keys) == 0 {
16 | log.Warnf("task rule is empty")
17 | }
18 | C.Resp(c, map[string]interface{}{
19 | "list": keys,
20 | "total": len(keys),
21 | })
22 | }
23 |
--------------------------------------------------------------------------------
/pkg/ui/src/api/auth-admin/auth.js:
--------------------------------------------------------------------------------
1 | import request from './request'
2 |
3 | /**
4 | * 获取授权的菜单接口
5 | */
6 | export function getMenu() {
7 | return request({
8 | url: 'v1/user/menu',
9 | method: 'GET',
10 | params: {
11 | domain: 'lime'
12 | }
13 | })
14 | }
15 |
16 | /**
17 | * 获取用户权限列表接口
18 | */
19 | export function permList() {
20 | return request({
21 | url: 'v1/users/perm/list',
22 | method: 'GET',
23 | params: {
24 | code: 'lime'
25 | }
26 | })
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/pkg/common/db/mongo_test.go:
--------------------------------------------------------------------------------
1 | package db
2 |
3 | import (
4 | . "github.com/smartystreets/goconvey/convey"
5 | "github.com/spf13/viper"
6 | "testing"
7 | )
8 |
9 | func TestGetDb(t *testing.T) {
10 | Convey("Test GetDb", t, func() {
11 | s, db := GetDb()
12 | Convey("The value should be Session.Copy", func() {
13 | So(s, ShouldEqual, Session.Copy())
14 | })
15 | Convey("The value should be reference of database", func() {
16 | So(db, ShouldEqual, s.DB(viper.GetString("mongo.db")))
17 | })
18 | })
19 | }
20 |
--------------------------------------------------------------------------------
/pkg/api/admin/controllers/upload.go:
--------------------------------------------------------------------------------
1 | package controllers
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/spf13/viper"
6 | "lime/pkg/api/admin/service"
7 | )
8 |
9 | var UploadService = service.UploadService{}
10 |
11 | type UploadController struct {
12 | BaseController
13 | }
14 |
15 | func (C *UploadController) QiniuToken(c *gin.Context) {
16 | token := UploadService.GetToken()
17 | C.Resp(c, map[string]interface{}{
18 | "token": token,
19 | "domain": viper.GetString("qiniu.domain"),
20 | })
21 | }
22 |
--------------------------------------------------------------------------------
/pkg/ui/src/components/Tinymce/toolbar.js:
--------------------------------------------------------------------------------
1 | // Here is a list of the toolbar
2 | // Detail list see https://www.tinymce.com/docs/advanced/editor-control-identifiers/#toolbarcontrols
3 |
4 | const toolbar = ['searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo removeformat subscript superscript code codesample', 'hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen']
5 |
6 | export default toolbar
7 |
--------------------------------------------------------------------------------
/pkg/ui/src/api/user.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | export function login(data) {
4 | return request({
5 | url: '/vue-element-admin/user/login',
6 | method: 'post',
7 | data
8 | })
9 | }
10 |
11 | export function getInfo(token) {
12 | return request({
13 | url: '/vue-element-admin/user/info',
14 | method: 'get',
15 | params: { token }
16 | })
17 | }
18 |
19 | export function logout() {
20 | return request({
21 | url: '/vue-element-admin/user/logout',
22 | method: 'post'
23 | })
24 | }
25 |
--------------------------------------------------------------------------------
/pkg/ui/src/store/modules/errorLog.js:
--------------------------------------------------------------------------------
1 | const state = {
2 | logs: []
3 | }
4 |
5 | const mutations = {
6 | ADD_ERROR_LOG: (state, log) => {
7 | state.logs.push(log)
8 | },
9 | CLEAR_ERROR_LOG: (state) => {
10 | state.logs.splice(0)
11 | }
12 | }
13 |
14 | const actions = {
15 | addErrorLog({ commit }, log) {
16 | commit('ADD_ERROR_LOG', log)
17 | },
18 | clearErrorLog({ commit }) {
19 | commit('CLEAR_ERROR_LOG')
20 | }
21 | }
22 |
23 | export default {
24 | namespaced: true,
25 | state,
26 | mutations,
27 | actions
28 | }
29 |
--------------------------------------------------------------------------------
/pkg/ui/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | <%= webpackConfig.name %>
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/star.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/api/admin/controllers/setting.go:
--------------------------------------------------------------------------------
1 | package controllers
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/spf13/viper"
6 | "lime/pkg/api/utils"
7 | "strings"
8 | )
9 |
10 | type SettingController struct {
11 | BaseController
12 | }
13 |
14 | func (C *SettingController) GetTokenAndEncodingAESKey(c *gin.Context) {
15 | C.Resp(c, map[string]interface{}{
16 | "receiveUrl": viper.GetString("wechat.receiveUrl") + "/v1/wechat/callback",
17 | "token": strings.ToLower(utils.CreateRandomString(32)),
18 | "EncodingAESKey": utils.CreateRandomString(43),
19 | })
20 | }
--------------------------------------------------------------------------------
/pkg/ui/src/api/lime-admin/setting.js:
--------------------------------------------------------------------------------
1 | import request from './request'
2 |
3 | export function wechatSetting(code, data) {
4 | return request({
5 | url: '/admin/configs/' + code + '/distributor',
6 | method: 'post',
7 | data: data
8 | })
9 | }
10 |
11 | export function getWetchatSetting(code, data) {
12 | return request({
13 | url: '/admin/distributor/' + code,
14 | method: 'GET'
15 | })
16 | }
17 |
18 | export function getTokenAndKey() {
19 | return request({
20 | url: '/admin/setting/getTokenAndEncodingAESKey',
21 | method: 'GET'
22 | })
23 | }
--------------------------------------------------------------------------------
/pkg/api/admin/service/upload.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "github.com/spf13/viper"
5 | "github.com/qiniu/api.v7/v7/auth/qbox"
6 | "github.com/qiniu/api.v7/v7/storage"
7 | )
8 |
9 | // Service
10 | type UploadService struct {
11 | }
12 |
13 | func (us UploadService) GetToken() (token string) {
14 | accessKey := viper.GetString("qiniu.ak")
15 | secretKey := viper.GetString("qiniu.sk")
16 | bucket:= viper.GetString("qiniu.bucket")
17 | putPolicy := storage.PutPolicy{
18 | Scope: bucket,
19 | }
20 | mac := qbox.NewMac(accessKey, secretKey)
21 | return putPolicy.UploadToken(mac)
22 | }
23 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/table.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/search.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/ui/src/components/Tinymce/plugins.js:
--------------------------------------------------------------------------------
1 | // Any plugins you want to use has to be imported
2 | // Detail plugins list see https://www.tinymce.com/docs/plugins/
3 | // Custom builds see https://www.tinymce.com/download/custom-builds/
4 |
5 | const plugins = ['advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount']
6 |
7 | export default plugins
8 |
--------------------------------------------------------------------------------
/pkg/api/middleware/cors.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/gin-contrib/cors"
5 | "github.com/gin-gonic/gin"
6 | "github.com/spf13/viper"
7 | "time"
8 | )
9 |
10 | func Cors() gin.HandlerFunc {
11 | return cors.New(cors.Config{
12 | AllowOrigins: viper.GetStringSlice("cors.allow_origins"),
13 | AllowMethods: viper.GetStringSlice("cors.allow_methods"),
14 | AllowHeaders: viper.GetStringSlice("cors.allow_headers"),
15 | AllowCredentials: viper.GetBool("cors.allow_credentials"),
16 | MaxAge: time.Second * time.Duration(viper.GetInt("cors.max_age")),
17 | })
18 | }
19 |
--------------------------------------------------------------------------------
/pkg/ui/src/store/getters.js:
--------------------------------------------------------------------------------
1 | const getters = {
2 | sidebar: state => state.app.sidebar,
3 | size: state => state.app.size,
4 | device: state => state.app.device,
5 | visitedViews: state => state.tagsView.visitedViews,
6 | cachedViews: state => state.tagsView.cachedViews,
7 | token: state => state.user.token,
8 | avatar: state => state.user.avatar,
9 | name: state => state.user.name,
10 | introduction: state => state.user.introduction,
11 | roles: state => state.user.roles,
12 | permission_routes: state => state.permission.routes,
13 | errorLogs: state => state.errorLog.logs
14 | }
15 | export default getters
16 |
--------------------------------------------------------------------------------
/pkg/api/admin/model/chapter.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "time"
5 | )
6 |
7 | type Chapter struct {
8 | Id int `json:"id"`
9 | Book_id int `json:"book_id"`
10 | Title string `json:"title"`
11 | Content string `json:"content"`
12 | Status int `json:"status"`
13 | Url string `json:"url"`
14 | CreateTime time.Time `json:"created_time"`
15 | LastUpdateTime time.Time `json:"updated_time"`
16 | }
17 |
18 | func (d *Chapter) TableName() string {
19 | return "chapter"
20 | }
21 |
22 | func init() {
23 | //db.Register(&Chapter{})
24 | }
25 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/password.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/ui/src/components/ImageCropper/utils/data2blob.js:
--------------------------------------------------------------------------------
1 | /**
2 | * database64文件格式转换为2进制
3 | *
4 | * @param {[String]} data dataURL 的格式为 “data:image/png;base64,****”,逗号之前都是一些说明性的文字,我们只需要逗号之后的就行了
5 | * @param {[String]} mime [description]
6 | * @return {[blob]} [description]
7 | */
8 | export default function(data, mime) {
9 | data = data.split(',')[1]
10 | data = window.atob(data)
11 | var ia = new Uint8Array(data.length)
12 | for (var i = 0; i < data.length; i++) {
13 | ia[i] = data.charCodeAt(i)
14 | }
15 | // canvas.toDataURL 返回的默认格式就是 image/png
16 | return new Blob([ia], {
17 | type: mime
18 | })
19 | }
20 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/education.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/ui/src/layout/components/Sidebar/Item.vue:
--------------------------------------------------------------------------------
1 |
30 |
--------------------------------------------------------------------------------
/pkg/ui/src/views/dashboard/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 |
12 |
13 |
26 |
35 |
--------------------------------------------------------------------------------
/pkg/api/admin/domain/task/task_lock.go:
--------------------------------------------------------------------------------
1 | package task
2 |
3 | import (
4 | "sync"
5 | )
6 |
7 | var taskLock *TaskLock
8 |
9 | type TaskLock struct {
10 | taskLock map[int]bool
11 | sync.Mutex
12 | }
13 |
14 | func init() {
15 | taskLock = &TaskLock{
16 | taskLock: make(map[int]bool),
17 | }
18 | }
19 |
20 | func (tl *TaskLock) IsRunning(taskid int) bool {
21 | tl.Lock()
22 | defer tl.Unlock()
23 | if tl.taskLock[taskid] {
24 | return true
25 | }
26 | tl.taskLock[taskid] = true
27 | return false
28 | }
29 |
30 | func (tl *TaskLock) Complete(taskid int) {
31 | tl.Lock()
32 | defer tl.Unlock()
33 | delete(tl.taskLock, taskid)
34 | }
35 |
--------------------------------------------------------------------------------
/pkg/api/admin/model/book.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "time"
5 | )
6 |
7 | type Book struct {
8 | Id int `json:"id"`
9 | Name string `json:"name"`
10 | Author string `json:"author"`
11 | Image string `json:"image"`
12 | Status int `son:"status"`
13 | Url string `json:"url"`
14 | Desc string `json:"desc"`
15 | CreateTime time.Time `json:"created_time"`
16 | LastUpdateTime time.Time `json:"updated_time"`
17 | }
18 |
19 | func (d *Book) TableName() string {
20 | return "book"
21 | }
22 |
23 | func init() {
24 | //db.Register(&Book{})
25 | }
26 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/tab.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/h5/src/store/modules/types.js:
--------------------------------------------------------------------------------
1 | // 类型名称
2 | export const TYPE = 'TYPE';
3 | // 显示章节目录
4 | export const TITLE_COVER = 'TITLE_COVER';
5 | // 显示上下导航
6 | export const MENU = 'MENU';
7 | // 当前章节
8 | export const CURRENT_CPT = 'CURRENT_CPT';
9 | // 上一章
10 | export const PRE_CPT = 'PRE_CPT';
11 | // 下一章
12 | export const NEXT_CPT = 'NEXT_CPT';
13 | // 日夜模式
14 | export const SWITCH_STYLE = 'SWITCH_STYLE';
15 | // 字体显示
16 | export const FONT = 'FONT';
17 | // 字体变大
18 | export const BIG_SIZE = 'BIG_SIZE';
19 | // 字体变小
20 | export const SMALL_SIZE = 'SMALL_SIZE';
21 | // 日间模式
22 | export const DAY_STYLE = 'DAY_STYLE';
23 | // 个人信息
24 | export const PERSON_INFO = 'PERSON_INFO';
25 |
--------------------------------------------------------------------------------
/pkg/ui/src/api/auth-admin/user.js:
--------------------------------------------------------------------------------
1 | import request from './request'
2 | // import qs from 'qs'
3 |
4 | /**
5 | * 获取用户信息接口
6 | */
7 | export function getInfo() {
8 | return request({
9 | url: 'v1/users/info',
10 | method: 'GET',
11 | params: {
12 | domain: 'zeus-config'
13 | }
14 | })
15 | }
16 |
17 | export function login(data) {
18 | return request({
19 | url: 'v1/users/login',
20 | method: 'POST',
21 | data
22 | })
23 | }
24 |
25 | export function logout() {
26 | return request({
27 | url: 'v1/users/logout',
28 | method: 'GET',
29 | params: {
30 | domain: 'zeus-config'
31 | }
32 | })
33 | }
34 |
35 |
--------------------------------------------------------------------------------
/pkg/h5/build/vue-loader.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const utils = require('./utils')
3 | const config = require('../config')
4 | const isProduction = process.env.NODE_ENV === 'production'
5 | const sourceMapEnabled = isProduction
6 | ? config.build.productionSourceMap
7 | : config.dev.cssSourceMap
8 |
9 | module.exports = {
10 | loaders: utils.cssLoaders({
11 | sourceMap: sourceMapEnabled,
12 | extract: isProduction
13 | }),
14 | cssSourceMap: sourceMapEnabled,
15 | cacheBusting: config.dev.cacheBusting,
16 | transformToRequire: {
17 | video: ['src', 'poster'],
18 | source: 'src',
19 | img: 'src',
20 | image: 'xlink:href'
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/message.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/down/convert.go:
--------------------------------------------------------------------------------
1 | package down
2 |
3 | import (
4 | "fmt"
5 | log "github.com/sirupsen/logrus"
6 | "lime/pkg/down/output"
7 | )
8 |
9 | var outputOpt output.Option
10 |
11 | func Covert(filename string, format string, outputpath string) error {
12 | if err := LoadLocalStore(filename); err != nil {
13 | return err
14 | }
15 | if format == "" {
16 | return nil
17 | }
18 | var ConversionFileName string
19 | if outputpath == "" {
20 | ConversionFileName = fmt.Sprintf("%s.%s", chapter.BookName, format)
21 | }
22 | log.Printf("Start Conversion: Format:%#v OutPath:%#v", format, ConversionFileName)
23 | return output.Output(*chapter, format, ConversionFileName, outputOpt)
24 | }
25 |
--------------------------------------------------------------------------------
/pkg/ui/src/directive/permission/permission.js:
--------------------------------------------------------------------------------
1 | import store from '@/store'
2 |
3 | export default {
4 | inserted(el, binding, vnode) {
5 | const { value } = binding
6 | const roles = store.getters && store.getters.roles
7 |
8 | if (value && value instanceof Array && value.length > 0) {
9 | const permissionRoles = value
10 |
11 | const hasPermission = roles.some(role => {
12 | return permissionRoles.includes(role)
13 | })
14 |
15 | if (!hasPermission) {
16 | el.parentNode && el.parentNode.removeChild(el)
17 | }
18 | } else {
19 | throw new Error(`need roles! Like v-permission="['admin','editor']"`)
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/theme.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/h5/src/main.js:
--------------------------------------------------------------------------------
1 | // The Vue build version to load with the `import` command
2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
3 | import Vue from 'vue'
4 | import Mint from 'mint-ui';
5 | import 'mint-ui/lib/style.css'
6 | import router from './router'
7 | import store from './store'
8 | import './permission' // permission control
9 | import App from './App'
10 |
11 |
12 | Vue.use(Mint);
13 |
14 | import 'animate.css';
15 | import '@/assets/less/reset.css';
16 |
17 | Vue.config.productionTip = false
18 |
19 | /* eslint-disable no-new */
20 | new Vue({
21 | el: '#app',
22 | router,
23 | store,
24 | components: {App},
25 | template: ''
26 | })
27 |
--------------------------------------------------------------------------------
/pkg/ui/src/vendor/Export2Zip.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | import { saveAs } from 'file-saver'
3 | import JSZip from 'jszip'
4 |
5 | export function export_txt_to_zip(th, jsonData, txtName, zipName) {
6 | const zip = new JSZip()
7 | const txt_name = txtName || 'file'
8 | const zip_name = zipName || 'file'
9 | const data = jsonData
10 | let txtData = `${th}\r\n`
11 | data.forEach((row) => {
12 | let tempStr = ''
13 | tempStr = row.toString()
14 | txtData += `${tempStr}\r\n`
15 | })
16 | zip.file(`${txt_name}.txt`, txtData)
17 | zip.generateAsync({
18 | type: "blob"
19 | }).then((blob) => {
20 | saveAs(blob, `${zip_name}.zip`)
21 | }, (err) => {
22 | alert('导出失败')
23 | })
24 | }
25 |
--------------------------------------------------------------------------------
/pkg/api/admin/model/comicCategory.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "lime/pkg/common/db"
5 | "time"
6 | )
7 |
8 | type ComicCategory struct {
9 | Id int `json:"id"`
10 | Name string `json:"name"`
11 | Comic_num int `json:"comic_num"`
12 | Sort int `json:"sort"`
13 | CreatedAt time.Time `json:"created_at" gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP"`
14 | UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP"`
15 | DeletedAt *time.Time `json:"deleted_at"`
16 | }
17 |
18 | func (C *ComicCategory) TableName() string {
19 | return "comic_category"
20 | }
21 |
22 | func init() {
23 | db.Register(&ComicCategory{})
24 | }
25 |
--------------------------------------------------------------------------------
/pkg/api/router/router.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "lime/pkg/api/middleware"
6 | "lime/pkg/api/utils/upload"
7 | "net/http"
8 | )
9 |
10 | func Init(e *gin.Engine, cors bool) {
11 | e.Use(
12 | gin.Recovery(),
13 | )
14 | if cors {
15 | e.Use(middleware.Cors())
16 | }
17 |
18 | e.LoadHTMLGlob("./pkg/ui/dist/*.html") // 添加入口index.html
19 | e.LoadHTMLFiles("./pkg/ui/dist/static/*/*") // 添加资源路径
20 | e.Static("/static", "./pkg/ui/dist/static") // 添加资源路径
21 | e.StaticFile("/admin/", "./pkg/ui/dist/index.html") //前端接口
22 | e.StaticFS("/upload/images", http.Dir(upload.GetImageFullPath()))
23 | e.StaticFS("/upload/books", http.Dir("data/books/"))
24 | }
25 |
--------------------------------------------------------------------------------
/pkg/crawler/novels/biquge/book.go:
--------------------------------------------------------------------------------
1 | package biquge
2 |
3 | import (
4 | "fmt"
5 | "github.com/gocolly/colly"
6 | "lime/pkg/crawler/novels"
7 | //"regexp"
8 | )
9 |
10 | var rules = novels.GetRules().RuleConfigInfo
11 |
12 | func Book() {
13 | c := novels.Init()
14 | c.DetectCharset = true
15 | c.MaxDepth = 1
16 | c.OnHTML("html", func(e *colly.HTMLElement) {
17 | //intro,_ := e.DOM.Find("#maininfo").Html()
18 | //re, _ := regexp.Compile(rules.NovelIntro.Pattern)
19 | //NovelIntro := re.FindString(intro)
20 | //fmt.Println(NovelIntro)
21 | })
22 | c.OnRequest(func(r *colly.Request) {
23 | fmt.Println("Visiting", r.URL.String())
24 | })
25 | c.Visit("https://www.xbaquge.com/files/article/html/40/40670/")
26 | }
27 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/peoples.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/ui/src/utils/permission.js:
--------------------------------------------------------------------------------
1 | import store from '@/store'
2 |
3 | /**
4 | * @param {Array} value
5 | * @returns {Boolean}
6 | * @example see @/views/permission/directive.vue
7 | */
8 | export default function checkPermission(value) {
9 | if (value && value instanceof Array && value.length > 0) {
10 | const roles = store.getters && store.getters.roles
11 | const permissionRoles = value
12 |
13 | const hasPermission = roles.some(role => {
14 | return permissionRoles.includes(role)
15 | })
16 |
17 | if (!hasPermission) {
18 | return false
19 | }
20 | return true
21 | } else {
22 | console.error(`need roles! Like v-permission="['admin','editor']"`)
23 | return false
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/pkg/ui/src/components/MarkdownEditor/default-options.js:
--------------------------------------------------------------------------------
1 | // doc: https://nhnent.github.io/tui.editor/api/latest/ToastUIEditor.html#ToastUIEditor
2 | export default {
3 | minHeight: '200px',
4 | previewStyle: 'vertical',
5 | useCommandShortcut: true,
6 | useDefaultHTMLSanitizer: true,
7 | usageStatistics: false,
8 | hideModeSwitch: false,
9 | toolbarItems: [
10 | 'heading',
11 | 'bold',
12 | 'italic',
13 | 'strike',
14 | 'divider',
15 | 'hr',
16 | 'quote',
17 | 'divider',
18 | 'ul',
19 | 'ol',
20 | 'task',
21 | 'indent',
22 | 'outdent',
23 | 'divider',
24 | 'table',
25 | 'image',
26 | 'link',
27 | 'divider',
28 | 'code',
29 | 'codeblock'
30 | ]
31 | }
32 |
--------------------------------------------------------------------------------
/pkg/ui/src/api/lime-admin/category.js:
--------------------------------------------------------------------------------
1 | import request from './request'
2 |
3 | export function categoryList() {
4 | return request({
5 | url: '/admin/novels/categories',
6 | method: 'GET'
7 | })
8 | }
9 |
10 | export function updateCategory(id, data) {
11 | return request({
12 | url: '/admin/novels/categories/' + id,
13 | method: 'put',
14 | data: data
15 | })
16 | }
17 |
18 | export function createCategory(data) {
19 | return request({
20 | url: '/admin/novels/categories',
21 | method: 'post',
22 | data: data
23 | })
24 | }
25 |
26 | export function deleteCategory(id,data) {
27 | return request({
28 | url: '/novels/categories/' + id,
29 | method: 'delete',
30 | data: data
31 | })
32 | }
33 |
--------------------------------------------------------------------------------
/pkg/ui/tests/unit/components/Hamburger.spec.js:
--------------------------------------------------------------------------------
1 | import { shallowMount } from '@vue/test-utils'
2 | import Hamburger from '@/components/Hamburger/index.vue'
3 | describe('Hamburger.vue', () => {
4 | it('toggle click', () => {
5 | const wrapper = shallowMount(Hamburger)
6 | const mockFn = jest.fn()
7 | wrapper.vm.$on('toggleClick', mockFn)
8 | wrapper.find('.hamburger').trigger('click')
9 | expect(mockFn).toBeCalled()
10 | })
11 | it('prop isActive', () => {
12 | const wrapper = shallowMount(Hamburger)
13 | wrapper.setProps({ isActive: true })
14 | expect(wrapper.contains('.is-active')).toBe(true)
15 | wrapper.setProps({ isActive: false })
16 | expect(wrapper.contains('.is-active')).toBe(false)
17 | })
18 | })
19 |
--------------------------------------------------------------------------------
/pkg/ui/tests/unit/components/SvgIcon.spec.js:
--------------------------------------------------------------------------------
1 | import { shallowMount } from '@vue/test-utils'
2 | import SvgIcon from '@/components/SvgIcon/index.vue'
3 | describe('SvgIcon.vue', () => {
4 | it('iconClass', () => {
5 | const wrapper = shallowMount(SvgIcon, {
6 | propsData: {
7 | iconClass: 'test'
8 | }
9 | })
10 | expect(wrapper.find('use').attributes().href).toBe('#icon-test')
11 | })
12 | it('className', () => {
13 | const wrapper = shallowMount(SvgIcon, {
14 | propsData: {
15 | iconClass: 'test'
16 | }
17 | })
18 | expect(wrapper.classes().length).toBe(1)
19 | wrapper.setProps({ className: 'test' })
20 | expect(wrapper.classes().includes('test')).toBe(true)
21 | })
22 | })
23 |
--------------------------------------------------------------------------------
/pkg/crawler/novels/store.go:
--------------------------------------------------------------------------------
1 | package novels
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "lime/pkg/api/admin/model"
7 | "lime/pkg/common/db"
8 | "time"
9 | )
10 |
11 | const FileExt = "crawnovel"
12 |
13 | func SaveBook(row map[int]interface{}) error {
14 | dto := model.Book{}
15 | dto.Name = fmt.Sprintf("%v", row[0])
16 | dto.Author = fmt.Sprintf("%v", row[1])
17 | dto.Image = fmt.Sprintf("%v", row[2])
18 | dto.Url = fmt.Sprintf("%v", row[3])
19 | dto.Desc = fmt.Sprintf("%v", row[4])
20 | dto.Status = 0
21 | dto.CreateTime = time.Now()
22 | dto.LastUpdateTime = time.Now()
23 | db := db.GetGormDB()
24 | created := db.Save(&dto)
25 | if created.RowsAffected > 0 {
26 | return nil
27 | }
28 | return errors.New("add book error")
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/pkg/api/admin/model/category.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "lime/pkg/common/db"
5 | "time"
6 | )
7 |
8 | type Category struct {
9 | Id int `json:"id"`
10 | Name string `json:"name"`
11 | ChannelId int `json:"channel_id"`
12 | NovelNum int `json:"novel_num"`
13 | Sort int `json:"sort"`
14 | CreatedAt time.Time `json:"created_at" gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP"`
15 | UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP"`
16 | DeletedAt *time.Time `json:"deleted_at"`
17 | }
18 |
19 | func (C *Category) TableName() string {
20 | return "novel_category"
21 | }
22 |
23 | func init() {
24 | db.Register(&Category{})
25 | }
26 |
--------------------------------------------------------------------------------
/pkg/api/front/domain/auth/account.go:
--------------------------------------------------------------------------------
1 | package auth
2 |
3 | import (
4 | "crypto/rand"
5 | "fmt"
6 | "golang.org/x/crypto/scrypt"
7 | "io"
8 | )
9 |
10 | const pwHashBytes = 64
11 |
12 | // HashPassword : password hashing
13 | func HashPassword(password string, salt string) (hash string, err error) {
14 | h, err := scrypt.Key([]byte(password), []byte(salt), 16384, 8, 1, pwHashBytes)
15 | if err != nil {
16 | return "", err
17 | }
18 | return fmt.Sprintf("%x", h), nil
19 | }
20 |
21 | // MakeSalt : make password more complicated
22 | func MakeSalt() (salt string, err error) {
23 | buf := make([]byte, pwHashBytes)
24 | if _, err := io.ReadFull(rand.Reader, buf); err != nil {
25 | return "", err
26 | }
27 | return fmt.Sprintf("%x", buf), nil
28 | }
29 |
--------------------------------------------------------------------------------
/pkg/ui/src/api/lime-admin/comicCategory.js:
--------------------------------------------------------------------------------
1 | import request from './request'
2 |
3 | export function categoryList() {
4 | return request({
5 | url: '/admin/comics/categories',
6 | method: 'GET'
7 | })
8 | }
9 |
10 | export function updateCategory(id, data) {
11 | return request({
12 | url: '/admin/comics/categories/' + id,
13 | method: 'put',
14 | data: data
15 | })
16 | }
17 |
18 | export function createCategory(data) {
19 | return request({
20 | url: '/admin/comics/categories',
21 | method: 'post',
22 | data: data
23 | })
24 | }
25 |
26 | export function deleteCategory(id,data) {
27 | return request({
28 | url: '/admin/comics/categories/' + id,
29 | method: 'delete',
30 | data: data
31 | })
32 | }
33 |
--------------------------------------------------------------------------------
/pkg/api/front/dao/config.go:
--------------------------------------------------------------------------------
1 | package dao
2 |
3 | import (
4 | "gorm.io/datatypes"
5 | "lime/pkg/api/admin/model"
6 | "lime/pkg/common/cache"
7 | "lime/pkg/common/db"
8 | )
9 |
10 | type ConfigDao struct {
11 | }
12 |
13 | func (c ConfigDao) Get(id int) model.Config {
14 | var Config model.Config
15 | db := db.GetGormDB()
16 | db.Where("id = ?", id).First(&Config)
17 | return Config
18 | }
19 |
20 | func (c ConfigDao) GetByCode(code string) datatypes.JSON {
21 | var Config model.Config
22 | configCache, err := cache.Get(code)
23 | if err == nil {
24 | return datatypes.JSON(configCache)
25 | }
26 | db := db.GetGormDB()
27 | db.Where("config_code = ?", code).First(&Config)
28 | cache.Set(code, string(Config.Config_value), 3600)
29 | return Config.Config_value
30 | }
31 |
--------------------------------------------------------------------------------
/pkg/ui/src/layout/components/Sidebar/FixiOSBug.js:
--------------------------------------------------------------------------------
1 | export default {
2 | computed: {
3 | device() {
4 | return this.$store.state.app.device
5 | }
6 | },
7 | mounted() {
8 | // In order to fix the click on menu on the ios device will trigger the mouseleave bug
9 | // https://github.com/PanJiaChen/vue-element-admin/issues/1135
10 | this.fixBugIniOS()
11 | },
12 | methods: {
13 | fixBugIniOS() {
14 | const $subMenu = this.$refs.subMenu
15 | if ($subMenu) {
16 | const handleMouseleave = $subMenu.handleMouseleave
17 | $subMenu.handleMouseleave = (e) => {
18 | if (this.device === 'mobile') {
19 | return
20 | }
21 | handleMouseleave(e)
22 | }
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/pkg/ui/src/utils/clipboard.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Clipboard from 'clipboard'
3 |
4 | function clipboardSuccess() {
5 | Vue.prototype.$message({
6 | message: 'Copy successfully',
7 | type: 'success',
8 | duration: 1500
9 | })
10 | }
11 |
12 | function clipboardError() {
13 | Vue.prototype.$message({
14 | message: 'Copy failed',
15 | type: 'error'
16 | })
17 | }
18 |
19 | export default function handleClipboard(text, event) {
20 | const clipboard = new Clipboard(event.target, {
21 | text: () => text
22 | })
23 | clipboard.on('success', () => {
24 | clipboardSuccess()
25 | clipboard.destroy()
26 | })
27 | clipboard.on('error', () => {
28 | clipboardError()
29 | clipboard.destroy()
30 | })
31 | clipboard.onClick(event)
32 | }
33 |
--------------------------------------------------------------------------------
/pkg/ui/src/views/comics/emun/index.js:
--------------------------------------------------------------------------------
1 | export const CATEGORY_CHANNEL = [
2 | { key: 1, display_name: '男频' },
3 | { key: 2, display_name: '女频' }
4 | ]
5 |
6 | export const COMIC_ATTRS = [ //属性
7 | { key: 0, display_name: '免费' },
8 | { key: 1, display_name: '热门' },
9 | { key: 2, display_name: '会员' },
10 | { key: 3, display_name: '推荐' }
11 | ]
12 |
13 | export const COMIC_ONLINE_STATUS = [ //上架状态
14 | { key: 0, display_name: '已经上架' },
15 | { key: 1, display_name: '已经下架' }
16 | ]
17 |
18 | export const COMIC_STATUS = [ //小说状态
19 | { key: 0, display_name: '连载中' },
20 | { key: 1, display_name: '已完结' },
21 | { key: 2, display_name: '太监' }
22 | ]
23 |
24 | export const COMIC_IS_SENSITIVITYS = [ //是否敏感
25 | { key: 0, display_name: '不敏感' },
26 | { key: 1, display_name: '敏感' }
27 | ]
28 |
--------------------------------------------------------------------------------
/pkg/ui/src/views/permission/components/SwitchRoles.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Your roles: {{ roles }}
5 |
6 | Switch roles:
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
33 |
--------------------------------------------------------------------------------
/pkg/h5/src/assets/lock.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/ui/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 | import getters from './getters'
4 |
5 | Vue.use(Vuex)
6 |
7 | // https://webpack.js.org/guides/dependency-management/#requirecontext
8 | const modulesFiles = require.context('./modules', true, /\.js$/)
9 |
10 | // you do not need `import app from './modules/app'`
11 | // it will auto require all vuex module from modules file
12 | const modules = modulesFiles.keys().reduce((modules, modulePath) => {
13 | // set './app.js' => 'app'
14 | const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
15 | const value = modulesFiles(modulePath)
16 | modules[moduleName] = value.default
17 | return modules
18 | }, {})
19 |
20 | const store = new Vuex.Store({
21 | modules,
22 | getters
23 | })
24 |
25 | export default store
26 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/edit.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/ui/src/store/modules/settings.js:
--------------------------------------------------------------------------------
1 | import variables from '@/styles/element-variables.scss'
2 | import defaultSettings from '@/settings'
3 |
4 | const { showSettings, tagsView, fixedHeader, sidebarLogo } = defaultSettings
5 |
6 | const state = {
7 | theme: variables.theme,
8 | showSettings: showSettings,
9 | tagsView: tagsView,
10 | fixedHeader: fixedHeader,
11 | sidebarLogo: sidebarLogo
12 | }
13 |
14 | const mutations = {
15 | CHANGE_SETTING: (state, { key, value }) => {
16 | if (state.hasOwnProperty(key)) {
17 | state[key] = value
18 | }
19 | }
20 | }
21 |
22 | const actions = {
23 | changeSetting({ commit }, data) {
24 | commit('CHANGE_SETTING', data)
25 | }
26 | }
27 |
28 | export default {
29 | namespaced: true,
30 | state,
31 | mutations,
32 | actions
33 | }
34 |
35 |
--------------------------------------------------------------------------------
/pkg/api/admin/dao/spider.go:
--------------------------------------------------------------------------------
1 | package dao
2 |
3 | import (
4 | "fmt"
5 | "github.com/globalsign/mgo/bson"
6 | "lime/pkg/api/admin/model"
7 | "lime/pkg/common/db"
8 | "time"
9 | )
10 |
11 | type SpiderDao struct{}
12 |
13 | func (sd SpiderDao) Add(row map[int]interface{}) error {
14 | var spider model.Spider
15 | s, c := db.GetCol("spiders")
16 | defer s.Close()
17 | spider.Id = bson.NewObjectId()
18 | spider.AppName = fmt.Sprintf("%v", row[0])
19 |
20 | spider.CreatedAt = time.Now()
21 | spider.UpdatedAt = time.Now()
22 | if err := c.Insert(&spider); err != nil {
23 | return err
24 | }
25 | return nil
26 | }
27 |
28 | func (sd SpiderDao) InitYaml(row map[int]interface{}) error {
29 |
30 | return nil
31 | }
32 |
33 | func (sd SpiderDao) AddYaml(row map[int]interface{}) error {
34 |
35 | return nil
36 | }
37 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/nested.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/api/middleware/file.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "bytes"
5 | "github.com/gin-gonic/gin"
6 | "io/ioutil"
7 | "net/http"
8 | )
9 |
10 | //Avoid a large file from loading into memory
11 | //If the file size is greater than 8MB dont allow it to even load into memory and waste our time.
12 | func MaxSizeAllowed(n int64) gin.HandlerFunc {
13 | return func(c *gin.Context) {
14 | c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, n)
15 | buff, errRead := c.GetRawData()
16 | if errRead != nil {
17 | c.JSON(http.StatusRequestEntityTooLarge, gin.H{
18 | "status": http.StatusRequestEntityTooLarge,
19 | "upload_err": "too large: upload an image less than 8MB",
20 | })
21 | c.Abort()
22 | return
23 | }
24 | buf := bytes.NewBuffer(buff)
25 | c.Request.Body = ioutil.NopCloser(buf)
26 | }
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/pkg/h5/src/components/common/HorizontalList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
{{title}}
5 |
6 |
7 |
8 | -
9 |
10 |
11 | {{item.name}}
12 | {{item.author}}
13 |
14 |
15 |
16 |
17 |
18 |
19 |
25 |
26 |
29 |
--------------------------------------------------------------------------------
/pkg/api/front/dao/chapters.go:
--------------------------------------------------------------------------------
1 | package dao
2 |
3 | import (
4 | "lime/pkg/api/admin/model"
5 | "lime/pkg/common/db"
6 | )
7 |
8 | type ChaptersDao struct {
9 | }
10 |
11 | func (c ChaptersDao) Get(bookId int,chapterId int) model.Chapters {
12 | var Chapters model.Chapters
13 | db := db.GetGormDB()
14 | db.Where("novel_id = ? and chapter_no = ?", bookId,chapterId).First(&Chapters)
15 | return Chapters
16 | }
17 |
18 | func (c ChaptersDao) GetListByBookId(bookId int) []model.Chapters {
19 | var Chapters []model.Chapters
20 | db := db.GetGormDB()
21 | db.Model(&model.Chapters{}).Where("novel_id = ?",bookId).Find(&Chapters)
22 | return Chapters
23 | }
24 |
25 | func (c ChaptersDao) GetAll() []model.Chapters {
26 | var Chapters []model.Chapters
27 | db := db.GetGormDB()
28 | db.Model(&model.Chapters{}).Find(&Chapters)
29 | return Chapters
30 | }
31 |
--------------------------------------------------------------------------------
/pkg/down/job.go:
--------------------------------------------------------------------------------
1 | package down
2 |
3 | import (
4 | log "github.com/sirupsen/logrus"
5 | "io"
6 | "lime/pkg/down/site"
7 | "time"
8 | )
9 |
10 | var (
11 | tSleep time.Duration
12 | errSleep time.Duration
13 | )
14 |
15 | func Job(syncStore *SyncStore, jobch chan error) {
16 | defer func(jobch chan error) {
17 | jobch <- io.EOF
18 | }(jobch)
19 | for {
20 | vi, ci, BookURL, err := syncStore.GetJob()
21 | if err != nil {
22 | if err != io.EOF {
23 | jobch <- err
24 | }
25 | return
26 | }
27 |
28 | LoopStep:
29 | for {
30 | content, err := site.Chapter(BookURL)
31 | if err != nil {
32 | log.Printf("Error: %s", err)
33 | time.Sleep(errSleep)
34 | continue LoopStep
35 | }
36 | syncStore.SaveJob(vi, ci, content)
37 | jobch <- nil
38 | time.Sleep(tSleep)
39 | break LoopStep
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/pkg/ui/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
3 | transform: {
4 | '^.+\\.vue$': 'vue-jest',
5 | '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
6 | 'jest-transform-stub',
7 | '^.+\\.jsx?$': 'babel-jest'
8 | },
9 | moduleNameMapper: {
10 | '^@/(.*)$': '/src/$1'
11 | },
12 | snapshotSerializers: ['jest-serializer-vue'],
13 | testMatch: [
14 | '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
15 | ],
16 | collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'],
17 | coverageDirectory: '/tests/unit/coverage',
18 | // 'collectCoverage': true,
19 | 'coverageReporters': [
20 | 'lcov',
21 | 'text-summary'
22 | ],
23 | testURL: 'http://localhost/'
24 | }
25 |
--------------------------------------------------------------------------------
/pkg/api/admin/dto/chapter.go:
--------------------------------------------------------------------------------
1 | package dto
2 |
3 | import "time"
4 |
5 | type ChapterCreateDto struct {
6 | Id int `json:"id"`
7 | Book_id int `form:"book_id" json:"book_id"`
8 | Title string `form:"title" json:"title"`
9 | Content string `form:"content" json:"content"`
10 | Status int `form:"status" json:"status"`
11 | Url string `form:"url" json:"url"`
12 | CreateTime time.Time `type(datetime)" json:"create_time"`
13 | LastLoginTime time.Time `type(datetime)" json:"-"`
14 | }
15 |
16 | type ChapterEditDto struct {
17 | Id int `json:"id"`
18 | Book_id int `form:"book_id" json:"book_id"`
19 | Title string `form:"title" json:"title"`
20 | Content string `form:"content" json:"content"`
21 | Status int `form:"status" json:"status"`
22 | Url string `form:"url" json:"url"`
23 | }
24 |
--------------------------------------------------------------------------------
/pkg/api/admin/model/comicComments.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "lime/pkg/common/db"
5 | "time"
6 | )
7 |
8 | type ComicComments struct {
9 | Id int `gorm:"primary_key" json:"id"` //分类ID
10 | Comic_id int `json:"comic_id"` //漫画ID
11 | Username string `json:"username"` //章节标题
12 | Content string `json:"content"` //内容
13 | Source string `json:"source"` //来源
14 | CreatedAt time.Time `json:"created_at" gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP"`
15 | UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP"`
16 | DeletedAt *time.Time `json:"deleted_at"`
17 | }
18 |
19 | func (C *ComicComments) TableName() string {
20 | return "comic_comment"
21 | }
22 |
23 | func init() {
24 | db.Register(&ComicComments{})
25 | }
26 |
--------------------------------------------------------------------------------
/pkg/ui/src/layout/components/Sidebar/Link.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
44 |
--------------------------------------------------------------------------------
/cmd/cobra.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "github.com/spf13/cobra"
5 | "lime/cmd/api"
6 | "lime/cmd/convert"
7 | "lime/cmd/download"
8 | "lime/cmd/search"
9 | "lime/cmd/task"
10 | "os"
11 | )
12 |
13 | var rootCmd = &cobra.Command{
14 | Use: "download",
15 | Short: "download API server",
16 | SilenceUsage: true,
17 | DisableAutoGenTag: true,
18 | Long: `Start download API server`,
19 | PersistentPreRunE: func(*cobra.Command, []string) error { return nil },
20 | }
21 |
22 | func init() {
23 | rootCmd.AddCommand(api.StartCmd)
24 | rootCmd.AddCommand(download.StartCmd)
25 | rootCmd.AddCommand(convert.StartCmd)
26 | rootCmd.AddCommand(search.StartCmd)
27 | rootCmd.AddCommand(task.StartCmd)
28 | }
29 |
30 | //Execute : run commands
31 | func Execute() {
32 | if err := rootCmd.Execute(); err != nil {
33 | os.Exit(-1)
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/pkg/down/util.go:
--------------------------------------------------------------------------------
1 | package down
2 |
3 | import (
4 | "regexp"
5 | )
6 |
7 | func TitleAlias(s string) (alias []string) {
8 | var res = []string{
9 | `^([第]?([零一二三四五六七八就十百千万0-9]+)[章\,,、]?)[ ]*([^ ()\(\))]+).*$`,
10 | `([^ ()\(\)]+)`, // 没有章节号的章节
11 | `[(\(](.+?)[)\)]`, //括号内的
12 | }
13 | for _, v := range res {
14 | re, err := regexp.Compile(v)
15 | if err != nil {
16 | panic(err)
17 | }
18 | find := re.FindAllStringSubmatch(s, -1)
19 | if find == nil {
20 | continue
21 | }
22 | for _, v1 := range find {
23 | for _, v := range v1[1:] {
24 | if v == "" || v == s || StringInSlice(v, alias) {
25 | continue
26 | }
27 | alias = append(alias, v)
28 | }
29 | }
30 | }
31 | return
32 | }
33 |
34 | func StringInSlice(str string, slice []string) bool {
35 | for _, v := range slice {
36 | if str == v {
37 | return true
38 | }
39 | }
40 | return false
41 | }
42 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/tree-table.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/ui/src/views/books/emun/index.js:
--------------------------------------------------------------------------------
1 | export const CATEGORY_CHANNEL = [
2 | { key: 0, display_name: '全部' },
3 | { key: 1, display_name: '男生' },
4 | { key: 2, display_name: '女生' }
5 | ]
6 |
7 | export const BOOK_ATTRS = [ //属性
8 | { key: 0, display_name: '新书' },
9 | { key: 1, display_name: '热门' },
10 | { key: 2, display_name: '会员' },
11 | { key: 3, display_name: '爽文' },
12 | { key: 4, display_name: '精选' },
13 | { key: 5, display_name: '大神' }
14 | ]
15 |
16 | export const BOOK_ONLINE_STATUS = [ //上架状态
17 | { key: 0, display_name: '已经上架' },
18 | { key: 1, display_name: '已经下架' }
19 | ]
20 |
21 | export const BOOK_STATUS = [ //小说状态
22 | { key: 0, display_name: '连载中' },
23 | { key: 1, display_name: '已完结' },
24 | { key: 2, display_name: '太监' }
25 | ]
26 |
27 | export const BOOK_IS_SENSITIVITYS = [ //是否敏感
28 | { key: 0, display_name: '不敏感' },
29 | { key: 1, display_name: '敏感' }
30 | ]
31 |
--------------------------------------------------------------------------------
/pkg/api/admin/model/comments.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "lime/pkg/common/db"
5 | "time"
6 | )
7 |
8 | type Comments struct {
9 | Id int `gorm:"primary_key" json:"id"` //分类ID
10 | Novel_id int `json:"novel_id"` //小说ID
11 | Username string `json:"username"` //章节标题
12 | Content string `json:"content"` //内容
13 | Likes int `json:"likes"` //点赞数
14 | Source string `json:"source"` //来源
15 | CreatedAt time.Time `json:"created_at" gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP"`
16 | UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP"`
17 | DeletedAt *time.Time `json:"deleted_at"`
18 | }
19 |
20 | func (C *Comments) TableName() string {
21 | return "novel_comment"
22 | }
23 |
24 | func init() {
25 | db.Register(&Comments{})
26 | }
27 |
--------------------------------------------------------------------------------
/pkg/h5/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // https://eslint.org/docs/user-guide/configuring
2 |
3 | module.exports = {
4 | root: true,
5 | parserOptions: {
6 | parser: 'babel-eslint'
7 | },
8 | env: {
9 | browser: true,
10 | },
11 | extends: [
12 | // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
13 | // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
14 | 'plugin:vue/essential',
15 | // https://github.com/standard/standard/blob/master/docs/RULES-en.md
16 | 'standard'
17 | ],
18 | // required to lint *.vue files
19 | plugins: [
20 | 'vue'
21 | ],
22 | // add your custom rules here
23 | rules: {
24 | // allow async-await
25 | 'generator-star-spacing': 'off',
26 | // allow debugger during development
27 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/pkg/h5/src/store/modules/state.js:
--------------------------------------------------------------------------------
1 | import { getToken} from '@/utils/auth'
2 | const state = {
3 | userInfo: null,
4 | types: [
5 | {
6 | type: 1,
7 | title: '玄幻'
8 | },
9 | {
10 | type: 2,
11 | title: '修真'
12 | },
13 | {
14 | type: 3,
15 | title: '都市'
16 | },
17 | {
18 | type: 4,
19 | title: '历史'
20 | },
21 | {
22 | type: 5,
23 | title: '游戏'
24 | }
25 | ],
26 | cover: false,
27 | menu: false,
28 | currentCpt: 1,
29 | night: false,
30 | nightText: '夜间',
31 | font: false,
32 | fontSize: 16,
33 | currentStyle: 'style1',
34 | styles: ['style1', 'style2', 'style3', 'style4', 'style5'],
35 | token: getToken(),
36 | username: '',
37 | faceicon: ''
38 | }
39 | export default state;
40 |
--------------------------------------------------------------------------------
/pkg/down/store/store.go:
--------------------------------------------------------------------------------
1 | package store
2 |
3 | import "sync"
4 |
5 | const FileExt = "lime"
6 |
7 | // Volume 卷
8 | type Volume struct {
9 | Name string
10 | IsVIP bool
11 | Chapters []Chapter
12 | }
13 |
14 | // Chapter 章节
15 | type Chapter struct {
16 | Name string //名称
17 | URL string //章节链接
18 | Text []string
19 | Alias []string `yaml:"-"`
20 | MuxLock sync.Mutex `yaml:"-"`
21 | }
22 |
23 | // Store is store yaml data file format
24 | type Store struct {
25 | BookURL string
26 | BookName string
27 | Author string // 作者
28 | CoverURL string // 封面链接
29 | Description string // 介绍
30 | Volumes []Volume
31 | }
32 |
33 | func (store Store) Total() (Done, AllChaper int) {
34 | for _, v := range store.Volumes {
35 | AllChaper += len(v.Chapters)
36 | for _, v2 := range v.Chapters {
37 | if len(v2.Text) != 0 {
38 | Done++
39 | }
40 | }
41 | }
42 | return
43 | }
44 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/eye.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/down/output/txt.go:
--------------------------------------------------------------------------------
1 | package output
2 |
3 | import (
4 | "html/template"
5 | "lime/pkg/down/store"
6 | "os"
7 | "strings"
8 | )
9 |
10 | type TXT struct {
11 | }
12 |
13 | func (t *TXT) Conv(src store.Store, outpath string, opts Option) (err error) {
14 | f, err := os.Create(outpath)
15 | if err != nil {
16 | return err
17 | }
18 | defer f.Close()
19 |
20 | temp := template.New("txt_lime")
21 | temp = temp.Funcs(template.FuncMap{
22 | "split": strings.Split,
23 | })
24 | temp, err = temp.Parse(TxtTemplate)
25 | if err != nil {
26 | return err
27 | }
28 |
29 | return temp.Execute(
30 | f, src)
31 | }
32 |
33 | var TxtTemplate = `书名:{{.BookName}}
34 | 作者:{{.Author}}
35 | 链接:{{.BookURL}}
36 | 简介:
37 | {{range split .Description "\n"}} {{.}}
38 | {{end}}
39 | {{- range .Volumes }}
40 | {{if .IsVIP}}付费{{else}}免费{{end}}卷 {{.Name}}
41 | {{range .Chapters}}
42 | {{.Name}}
43 | {{range .Text}} {{.}}
44 | {{end}}{{end}}{{end}}`
45 |
--------------------------------------------------------------------------------
/pkg/ui/src/styles/variables.scss:
--------------------------------------------------------------------------------
1 | // base color
2 | $blue:#324157;
3 | $light-blue:#3A71A8;
4 | $red:#C03639;
5 | $pink: #E65D6E;
6 | $green: #30B08F;
7 | $tiffany: #4AB7BD;
8 | $yellow:#FEC171;
9 | $panGreen: #30B08F;
10 |
11 | // sidebar
12 | $menuText:#bfcbd9;
13 | $menuActiveText:#409EFF;
14 | $subMenuActiveText:#f4f4f5; // https://github.com/ElemeFE/element/issues/12951
15 |
16 | $menuBg:#304156;
17 | $menuHover:#263445;
18 |
19 | $subMenuBg:#1f2d3d;
20 | $subMenuHover:#001528;
21 |
22 | $sideBarWidth: 210px;
23 |
24 | // the :export directive is the magic sauce for webpack
25 | // https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
26 | :export {
27 | menuText: $menuText;
28 | menuActiveText: $menuActiveText;
29 | subMenuActiveText: $subMenuActiveText;
30 | menuBg: $menuBg;
31 | menuHover: $menuHover;
32 | subMenuBg: $subMenuBg;
33 | subMenuHover: $subMenuHover;
34 | sideBarWidth: $sideBarWidth;
35 | }
36 |
--------------------------------------------------------------------------------
/pkg/ui/src/directive/waves/waves.css:
--------------------------------------------------------------------------------
1 | .waves-ripple {
2 | position: absolute;
3 | border-radius: 100%;
4 | background-color: rgba(0, 0, 0, 0.15);
5 | background-clip: padding-box;
6 | pointer-events: none;
7 | -webkit-user-select: none;
8 | -moz-user-select: none;
9 | -ms-user-select: none;
10 | user-select: none;
11 | -webkit-transform: scale(0);
12 | -ms-transform: scale(0);
13 | transform: scale(0);
14 | opacity: 1;
15 | }
16 |
17 | .waves-ripple.z-active {
18 | opacity: 0;
19 | -webkit-transform: scale(2);
20 | -ms-transform: scale(2);
21 | transform: scale(2);
22 | -webkit-transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
23 | transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
24 | transition: opacity 1.2s ease-out, transform 0.6s ease-out;
25 | transition: opacity 1.2s ease-out, transform 0.6s ease-out, -webkit-transform 0.6s ease-out;
26 | }
--------------------------------------------------------------------------------
/pkg/ui/src/styles/element-variables.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * I think element-ui's default theme color is too light for long-term use.
3 | * So I modified the default color and you can modify it to your liking.
4 | **/
5 |
6 | /* theme color */
7 | $--color-primary: #1890ff;
8 | $--color-success: #13ce66;
9 | $--color-warning: #ffba00;
10 | $--color-danger: #ff4949;
11 | // $--color-info: #1E1E1E;
12 |
13 | $--button-font-weight: 400;
14 |
15 | // $--color-text-regular: #1f2d3d;
16 |
17 | $--border-color-light: #dfe4ed;
18 | $--border-color-lighter: #e6ebf5;
19 |
20 | $--table-border: 1px solid #dfe6ec;
21 |
22 | /* icon font path, required */
23 | $--font-path: "~element-ui/lib/theme-chalk/fonts";
24 |
25 | @import "~element-ui/packages/theme-chalk/src/index";
26 |
27 | // the :export directive is the magic sauce for webpack
28 | // https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
29 | :export {
30 | theme: $--color-primary;
31 | }
32 |
--------------------------------------------------------------------------------
/pkg/ui/src/styles/transition.scss:
--------------------------------------------------------------------------------
1 | // global transition css
2 |
3 | /* fade */
4 | .fade-enter-active,
5 | .fade-leave-active {
6 | transition: opacity 0.28s;
7 | }
8 |
9 | .fade-enter,
10 | .fade-leave-active {
11 | opacity: 0;
12 | }
13 |
14 | /* fade-transform */
15 | .fade-transform-leave-active,
16 | .fade-transform-enter-active {
17 | transition: all .5s;
18 | }
19 |
20 | .fade-transform-enter {
21 | opacity: 0;
22 | transform: translateX(-30px);
23 | }
24 |
25 | .fade-transform-leave-to {
26 | opacity: 0;
27 | transform: translateX(30px);
28 | }
29 |
30 | /* breadcrumb transition */
31 | .breadcrumb-enter-active,
32 | .breadcrumb-leave-active {
33 | transition: all .5s;
34 | }
35 |
36 | .breadcrumb-enter,
37 | .breadcrumb-leave-active {
38 | opacity: 0;
39 | transform: translateX(20px);
40 | }
41 |
42 | .breadcrumb-move {
43 | transition: all .5s;
44 | }
45 |
46 | .breadcrumb-leave-active {
47 | position: absolute;
48 | }
49 |
--------------------------------------------------------------------------------
/pkg/ui/src/settings.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | title: 'Lime Admin',
3 |
4 | /**
5 | * @type {boolean} true | false
6 | * @description Whether show the settings right-panel
7 | */
8 | showSettings: false,
9 |
10 | /**
11 | * @type {boolean} true | false
12 | * @description Whether need tagsView
13 | */
14 | tagsView: false,
15 |
16 | /**
17 | * @type {boolean} true | false
18 | * @description Whether fix the header
19 | */
20 | fixedHeader: false,
21 |
22 | /**
23 | * @type {boolean} true | false
24 | * @description Whether show the logo in sidebar
25 | */
26 | sidebarLogo: true,
27 |
28 | /**
29 | * @type {string | array} 'production' | ['production', 'development']
30 | * @description Need show err logs component.
31 | * The default is only used in the production env
32 | * If you want to also use it in dev, you can pass ['production', 'development']
33 | */
34 | errorLog: 'production'
35 | }
36 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/clipboard.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/api/front/controllers/chapters.go:
--------------------------------------------------------------------------------
1 | package controllers
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "lime/pkg/api/admin/controllers"
6 | "lime/pkg/api/front/dto"
7 | "lime/pkg/api/front/service"
8 | "lime/pkg/api/utils/e"
9 | )
10 |
11 | type ChaptersController struct {
12 | controllers.BaseController
13 | }
14 | var ChaptersService = service.ChaptersService{}
15 |
16 | func (C *ChaptersController) List(c *gin.Context) {
17 | var Dto dto.ChapterListDto
18 | if C.BindAndValidate(c, &Dto) {
19 | data := ChaptersService.List(Dto)
20 | C.Resp(c, map[string]interface{}{
21 | "result": data,
22 | })
23 | }
24 | }
25 |
26 | func (C *ChaptersController) Get(c *gin.Context) {
27 | var Dto dto.ChaptersGetDto
28 | if C.BindAndValidate(c, &Dto) {
29 | data,err := ChaptersService.GetChapterInfoById(Dto)
30 | if err != nil {
31 | C.Fail(c, e.ErrIdData)
32 | return
33 | }
34 | C.Resp(c, map[string]interface{}{
35 | "result": data,
36 | })
37 | }
38 | }
--------------------------------------------------------------------------------
/pkg/api/front/controllers/books.go:
--------------------------------------------------------------------------------
1 | package controllers
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "lime/pkg/api/admin/controllers"
6 | "lime/pkg/api/front/dto"
7 | "lime/pkg/api/front/service"
8 | "lime/pkg/api/utils/e"
9 | )
10 |
11 | type BooksController struct {
12 | controllers.BaseController
13 | }
14 | var BooksService = service.BooksService{}
15 |
16 | func (C *BooksController) Get(c *gin.Context) {
17 | var Dto dto.GeneralGetDto
18 | if C.BindAndValidate(c, &Dto) {
19 | data, err := BooksService.GetBookInfoById(Dto)
20 | if err != nil {
21 | C.Fail(c, e.ErrIdData)
22 | return
23 | }
24 | C.Resp(c, map[string]interface{}{
25 | "result": data,
26 | })
27 | }
28 | }
29 |
30 | func (C *BooksController) List(c *gin.Context) {
31 | var Dto dto.GeneralListDto
32 | if C.BindAndValidate(c, &Dto) {
33 | data, total := BooksService.List(Dto)
34 | C.Resp(c, map[string]interface{}{
35 | "result": data,
36 | "total": total,
37 | })
38 | }
39 | }
--------------------------------------------------------------------------------
/pkg/crawler/novels/biquge/chapter.go:
--------------------------------------------------------------------------------
1 | package biquge
2 |
3 | import (
4 | "fmt"
5 | "github.com/gocolly/colly"
6 | "lime/pkg/api/admin/dto"
7 | "lime/pkg/api/admin/service"
8 | "lime/pkg/crawler/novels"
9 | )
10 |
11 | var ChapterService = service.ChapterService{}
12 |
13 | func Chapter() {
14 | c := novels.Init()
15 | c.DetectCharset = true
16 | c.MaxDepth = 1
17 | c.OnHTML("a[href]", func(e *colly.HTMLElement) {
18 | url_prefix := e.Request.URL.Scheme + "://" + e.Request.URL.Host
19 | link := e.Attr("href")
20 | title := e.Text
21 | var chapterDto dto.ChapterCreateDto
22 | chapterDto.Url = url_prefix + link
23 | chapterDto.Book_id = 3
24 | chapterDto.Title = title
25 | created := ChapterService.Create(chapterDto)
26 | if created.Id <= 0 {
27 | fmt.Println("error add")
28 | }
29 | })
30 | c.OnRequest(func(r *colly.Request) {
31 | fmt.Println("Visiting", r.URL.String())
32 | })
33 | c.Visit("https://www.xbaquge.com/files/article/html/40/40670/")
34 | }
35 |
--------------------------------------------------------------------------------
/pkg/api/admin/dto/general.go:
--------------------------------------------------------------------------------
1 | package dto
2 |
3 | import "strings"
4 |
5 | // GeneralListDto - General list request params
6 | type GeneralListDto struct {
7 | Skip int `form:"skip,default=0" json:"skip"`
8 | Limit int `form:"limit,default=20" json:"limit" binding:"max=100"`
9 | Order string `form:"order" json:"order"`
10 | Q string `form:"q" json:"q"`
11 | }
12 |
13 | type GeneralTreeDto struct {
14 | Q string `form:"q" json:"q"`
15 | }
16 | type GeneralDelDto struct {
17 | Id int `uri:"id" json:"id" binding:"required"`
18 | }
19 | type GeneralGetDto struct {
20 | Id int `uri:"id" json:"id" binding:"required"`
21 | }
22 |
23 | // TransformSearch - transform search query
24 | func TransformSearch(qs string, mapping map[string]string) (ss map[string]string) {
25 | ss = make(map[string]string)
26 | for _, v := range strings.Split(qs, ",") {
27 | vs := strings.Split(v, "=")
28 | if _, ok := mapping[vs[0]]; ok {
29 | ss[mapping[vs[0]]] = vs[1]
30 | }
31 | }
32 | return
33 | }
34 |
--------------------------------------------------------------------------------
/pkg/api/front/dto/general.go:
--------------------------------------------------------------------------------
1 | package dto
2 |
3 | import "strings"
4 |
5 | // GeneralListDto - General list request params
6 | type GeneralListDto struct {
7 | Skip int `form:"skip,default=0" json:"skip"`
8 | Limit int `form:"limit,default=20" json:"limit" binding:"max=100"`
9 | Order string `form:"order" json:"order"`
10 | Q string `form:"q" json:"q"`
11 | }
12 |
13 | type GeneralTreeDto struct {
14 | Q string `form:"q" json:"q"`
15 | }
16 | type GeneralDelDto struct {
17 | Id int `uri:"id" json:"id" binding:"required"`
18 | }
19 | type GeneralGetDto struct {
20 | Id int `uri:"id" json:"id" binding:"required"`
21 | }
22 |
23 | // TransformSearch - transform search query
24 | func TransformSearch(qs string, mapping map[string]string) (ss map[string]string) {
25 | ss = make(map[string]string)
26 | for _, v := range strings.Split(qs, ",") {
27 | vs := strings.Split(v, "=")
28 | if _, ok := mapping[vs[0]]; ok {
29 | ss[mapping[vs[0]]] = vs[1]
30 | }
31 | }
32 | return
33 | }
34 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/list.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/h5/build/webpack.test.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // This is the webpack config used for unit tests.
3 |
4 | const utils = require('./utils')
5 | const webpack = require('webpack')
6 | const merge = require('webpack-merge')
7 | const baseWebpackConfig = require('./webpack.base.conf')
8 |
9 | const webpackConfig = merge(baseWebpackConfig, {
10 | // use inline sourcemap for karma-sourcemap-loader
11 | module: {
12 | rules: utils.styleLoaders()
13 | },
14 | devtool: '#inline-source-map',
15 | resolveLoader: {
16 | alias: {
17 | // necessary to to make lang="scss" work in test when using vue-loader's ?inject option
18 | // see discussion at https://github.com/vuejs/vue-loader/issues/724
19 | 'scss-loader': 'sass-loader'
20 | }
21 | },
22 | plugins: [
23 | new webpack.DefinePlugin({
24 | 'process.env': require('../config/test.env')
25 | })
26 | ]
27 | })
28 |
29 | // no need for app entry during tests
30 | delete webpackConfig.entry
31 |
32 | module.exports = webpackConfig
33 |
--------------------------------------------------------------------------------
/pkg/h5/src/components/common/Similar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{book.name}}
6 | {{book.author}}
7 |
8 |
9 |
10 |
11 |
36 |
37 |
40 |
--------------------------------------------------------------------------------
/pkg/ui/src/views/guide/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 | Show Guide
10 |
11 |
12 |
13 |
14 |
37 |
--------------------------------------------------------------------------------
/pkg/api/front/dao/books.go:
--------------------------------------------------------------------------------
1 | package dao
2 |
3 | import (
4 | "fmt"
5 | "lime/pkg/api/front/dto"
6 | "lime/pkg/api/admin/model"
7 | "lime/pkg/common/db"
8 | )
9 |
10 | type BooksDao struct {}
11 |
12 | func (c BooksDao) Get(id int) model.Books {
13 | var Books model.Books
14 | db := db.GetGormDB()
15 | db.Where("id = ?", id).First(&Books)
16 | return Books
17 | }
18 |
19 | func (c BooksDao) List(listDto dto.GeneralListDto) ([]model.Books, int64) {
20 | var Books []model.Books
21 | var total int64
22 | db := db.GetGormDB()
23 | for sk, sv := range dto.TransformSearch(listDto.Q, dto.BookListSearchMapping) {
24 | db = db.Where(fmt.Sprintf("%s = ?", sk), sv)
25 | }
26 | db.Offset(listDto.Skip).Limit(listDto.Limit).Find(&Books)
27 | db.Model(&model.Books{}).Count(&total)
28 | return Books, total
29 | }
30 |
31 | func (c BooksDao) GetRandBooks(extraId int) []model.Books {
32 | var Books []model.Books
33 | db := db.GetGormDB()
34 | db.Model(&model.Books{}).Where("id !=?",extraId).Order("created_at desc").Limit(2).Find(&Books)
35 | return Books
36 | }
--------------------------------------------------------------------------------
/pkg/ui/build/index.js:
--------------------------------------------------------------------------------
1 | const { run } = require('runjs')
2 | const chalk = require('chalk')
3 | const config = require('../vue.config.js')
4 | const rawArgv = process.argv.slice(2)
5 | const args = rawArgv.join(' ')
6 |
7 | if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
8 | const report = rawArgv.includes('--report')
9 |
10 | run(`vue-cli-service build ${args}`)
11 |
12 | const port = 9526
13 | const publicPath = config.publicPath
14 |
15 | var connect = require('connect')
16 | var serveStatic = require('serve-static')
17 | const app = connect()
18 |
19 | app.use(
20 | publicPath,
21 | serveStatic('./dist', {
22 | index: ['index.html', '/']
23 | })
24 | )
25 |
26 | app.listen(port, function () {
27 | console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`))
28 | if (report) {
29 | console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`))
30 | }
31 |
32 | })
33 | } else {
34 | run(`vue-cli-service build ${args}`)
35 | }
36 |
--------------------------------------------------------------------------------
/pkg/api/admin/dao/book.go:
--------------------------------------------------------------------------------
1 | package dao
2 |
3 | import (
4 | "github.com/jinzhu/gorm"
5 | "lime/pkg/api/admin/dto"
6 | "lime/pkg/api/admin/model"
7 | "lime/pkg/common/db"
8 | )
9 |
10 | type BookDao struct {
11 | }
12 |
13 | func (u BookDao) Get(id int) model.Book {
14 | var Book model.Book
15 | db := db.GetGormDB()
16 | db.Where("id = ?", id).First(&Book)
17 | return Book
18 | }
19 |
20 | func (u BookDao) List(listDto dto.BookListDto) ([]model.Book, int64) {
21 | var Book []model.Book
22 | var total int64
23 | db := db.GetGormDB()
24 | db.Preload("Book").Offset(listDto.Skip).Limit(listDto.Limit).Find(&Book)
25 | db.Model(&model.Book{}).Count(&total)
26 | return Book, total
27 | }
28 |
29 | func (u BookDao) Create(Book *model.Book) *gorm.DB {
30 | db := db.GetGormDB()
31 | return db.Save(Book)
32 | }
33 |
34 | func (u BookDao) Update(Book *model.Book) *gorm.DB {
35 | db := db.GetGormDB()
36 | return db.Save(Book)
37 | }
38 |
39 | func (u BookDao) Delete(Book *model.Book) *gorm.DB {
40 | db := db.GetGormDB()
41 | return db.Delete(Book)
42 | }
43 |
--------------------------------------------------------------------------------
/pkg/api/router/front.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | controllersFront "lime/pkg/api/front/controllers"
6 | "lime/pkg/api/middleware"
7 | )
8 |
9 | func Front(e *gin.Engine) {
10 | //前台接口
11 | v1 := e.Group("/v1")
12 | UsersController := &controllersFront.UsersController{}
13 | v1.GET("/user/info",middleware.AuthMiddleware(),UsersController.Info)
14 | v1.POST("/user/login",UsersController.Login)
15 | v1.POST("/user/register",UsersController.Register)
16 | v1.POST("/user/resetPwd",middleware.AuthMiddleware(),UsersController.ResetPassword)
17 |
18 |
19 | V1BooksController := &controllersFront.BooksController{}
20 | v1.GET("/books", V1BooksController.List)
21 | v1.GET("/books/:id", V1BooksController.Get)
22 |
23 | V1ChaptersController := &controllersFront.ChaptersController{}
24 | v1.GET("/chapters", V1ChaptersController.List)
25 | v1.GET("/chapters/:id", V1ChaptersController.Get)
26 |
27 | V1WechatController := &controllersFront.WechatController{}
28 | v1.GET("/wechat/callback", V1WechatController.Callback)
29 | }
30 |
--------------------------------------------------------------------------------
/pkg/api/admin/model/config.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "gorm.io/datatypes"
5 | "time"
6 | )
7 |
8 | type Config struct {
9 | Id int `gorm:"primary_key" json:"id"` //分类ID
10 | Name string `json:"name"` //名称
11 | Config_code string `json:"config_code"` //配置code
12 | Config_value datatypes.JSON `json:"config_value"` //配置值
13 | Config_group string `json:"config_group"` //组
14 | Desc string `json:"desc"` //描述
15 | Status int `json:"status"` //状态 -1 已经删除 0 禁用 1 启用
16 | CreatedAt time.Time `json:"created_at" gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP"`
17 | UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP"`
18 | DeletedAt *time.Time `json:"deleted_at"`
19 | }
20 |
21 | func (C *Config) TableName() string {
22 | return "config"
23 | }
24 |
25 | func init() {
26 | //db.Register(&Config{})
27 | }
28 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/icon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/api/utils/e/code.go:
--------------------------------------------------------------------------------
1 | package e
2 |
3 | type ControllerError struct {
4 | Code int `json:"code"`
5 | Message string `json:"msg"`
6 | Moreinfo string `json:"moreinfo"`
7 | }
8 |
9 | var (
10 | Err404 = &ControllerError{404, "页面没有找到", ""}
11 | ErrInputData = &ControllerError{10001, "数据输入错误", ""}
12 | ErrDatabase = &ControllerError{10002, "服务器错误", ""}
13 | ErrValidation = &ControllerError{13011, "请求参数验证失败", ""}
14 | ErrAddFail = &ControllerError{11000, "创建失败", ""}
15 | ErrEditFail = &ControllerError{11001, "更新失败", ""}
16 | ErrDelFail = &ControllerError{11002, "删除失败", ""}
17 | ErrInvalidParams = &ControllerError{11003, "验证失败", ""}
18 | ErrIdData = &ControllerError{10016, "此ID无数据记录", ""}
19 | OtherTaskRunning = &ControllerError{12000, "有其他任务在执行", ""}
20 | ErrUploadCover = &ControllerError{12001, "上传封面失败", ""}
21 | ErrLogin = &ControllerError{12002, "登陆失败,请输入正确的用户名和密码", ""}
22 | ErrReg = &ControllerError{12003, "注册失败", ""}
23 | ErrUnauthorized = &ControllerError{12004, "校验身份失败,请重新登陆", ""}
24 | )
25 |
--------------------------------------------------------------------------------
/pkg/down/output/output.go:
--------------------------------------------------------------------------------
1 | package output
2 |
3 | import (
4 | "fmt"
5 | "lime/pkg/down/store"
6 | "reflect"
7 | )
8 |
9 | func init() {
10 | RegOutputFormat("epub", &EPUB{})
11 | RegOutputFormat("md", &Markdown{})
12 | RegOutputFormat("txt", &TXT{})
13 | }
14 |
15 | // Option is Convert output options
16 | type Option struct {
17 | IgnoreCover bool // 忽略封面
18 | NoEPUBMetadata bool // 不添加EPUB元数据
19 | }
20 |
21 | type Conversion interface {
22 | Conv(src store.Store, outpath string, opts Option) error
23 | }
24 |
25 | var formatMap = map[string]Conversion{}
26 |
27 | var (
28 | ErrUnsupportFormat = fmt.Errorf("Unsupport Conversion Format")
29 | )
30 |
31 | func RegOutputFormat(s string, conv Conversion) {
32 | formatMap[s] = conv
33 | }
34 |
35 | func Output(src store.Store, format string, outpath string, opts Option) (err error) {
36 | var c Conversion
37 | conver, ok := formatMap[format]
38 | if !ok {
39 | err = ErrUnsupportFormat
40 | }
41 | c = reflect.New(reflect.TypeOf(conver).Elem()).Interface().(Conversion)
42 | return c.Conv(src, outpath, opts)
43 | }
44 |
--------------------------------------------------------------------------------
/pkg/ui/src/utils/error-log.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import store from '@/store'
3 | import { isString, isArray } from '@/utils/validate'
4 | import settings from '@/settings'
5 |
6 | // you can set in settings.js
7 | // errorLog:'production' | ['production', 'development']
8 | const { errorLog: needErrorLog } = settings
9 |
10 | function checkNeed() {
11 | const env = process.env.NODE_ENV
12 | if (isString(needErrorLog)) {
13 | return env === needErrorLog
14 | }
15 | if (isArray(needErrorLog)) {
16 | return needErrorLog.includes(env)
17 | }
18 | return false
19 | }
20 |
21 | if (checkNeed()) {
22 | Vue.config.errorHandler = function(err, vm, info, a) {
23 | // Don't ask me why I use Vue.nextTick, it just a hack.
24 | // detail see https://forum.vuejs.org/t/dispatch-in-vue-config-errorhandler-has-some-problem/23500
25 | Vue.nextTick(() => {
26 | store.dispatch('errorLog/addErrorLog', {
27 | err,
28 | vm,
29 | info,
30 | url: window.location.href
31 | })
32 | console.error(err, info)
33 | })
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/pkg/api/admin/dto/init.go:
--------------------------------------------------------------------------------
1 | package dto
2 |
3 | import (
4 | "fmt"
5 | "github.com/gin-gonic/gin"
6 | "github.com/pkg/errors"
7 | "gopkg.in/go-playground/validator.v8"
8 | "strings"
9 | )
10 |
11 | func init() {
12 |
13 | // Register custom validate methods
14 | }
15 |
16 | // Bind : bind request dto and auto verify parameters
17 | func Bind(c *gin.Context, obj interface{}) error {
18 | _ = c.ShouldBindUri(obj)
19 | if err := c.ShouldBind(obj); err != nil {
20 | if fieldErr, ok := err.(validator.ValidationErrors); ok {
21 | var tagErrorMsg []string
22 | for _, v := range fieldErr {
23 | if _, has := ValidateErrorMessage[v.Tag]; has {
24 | tagErrorMsg = append(tagErrorMsg, fmt.Sprintf(ValidateErrorMessage[v.Tag], v.Field, v.Value))
25 | } else {
26 | tagErrorMsg = append(tagErrorMsg, err.Error())
27 | }
28 | }
29 | return errors.New(strings.Join(tagErrorMsg, ","))
30 | }
31 | }
32 | return nil
33 | }
34 |
35 | //ValidateErrorMessage : customize error messages
36 | var ValidateErrorMessage = map[string]string{
37 | "required": "%s is required,got empty %#v",
38 | }
39 |
--------------------------------------------------------------------------------
/pkg/ui/src/api/lime-admin/chapter.js:
--------------------------------------------------------------------------------
1 | import request from './request'
2 |
3 | export function getChapter(id) {
4 | return request({
5 | url: '/admin/novels/chapters/' + id,
6 | method: 'GET'
7 | })
8 | }
9 |
10 | export function ChapterList(query) {
11 | return request({
12 | url: '/admin/novels/chapters',
13 | method: 'GET',
14 | params: query
15 | })
16 | }
17 |
18 | export function updateChapter(id, data) {
19 | return request({
20 | url: '/admin/novels/chapters/' + id,
21 | method: 'put',
22 | data: data
23 | })
24 | }
25 |
26 | export function updatestatus(id, data) {
27 | return request({
28 | url: '/admin/novels//chapters/' + id + '/status',
29 | method: 'post',
30 | data: data
31 | })
32 | }
33 |
34 | export function createChapter(data) {
35 | return request({
36 | url: '/admin/novels/chapters',
37 | method: 'post',
38 | data: data
39 | })
40 | }
41 |
42 | export function deleteChapter(id,data) {
43 | return request({
44 | url: '/admin/novels/chapters/' + id,
45 | method: 'delete',
46 | data: data
47 | })
48 | }
49 |
--------------------------------------------------------------------------------
/pkg/ui/src/api/lime-admin/comicChapter.js:
--------------------------------------------------------------------------------
1 | import request from './request'
2 |
3 | export function getChapter(id) {
4 | return request({
5 | url: '/admin/comics/chapters/' + id,
6 | method: 'GET'
7 | })
8 | }
9 |
10 | export function ChapterList(query) {
11 | return request({
12 | url: '/admin/comics/chapters',
13 | method: 'GET',
14 | params: query
15 | })
16 | }
17 |
18 | export function updateChapter(id, data) {
19 | return request({
20 | url: '/admin/comics/chapters/' + id,
21 | method: 'put',
22 | data: data
23 | })
24 | }
25 |
26 | export function updatestatus(id, data) {
27 | return request({
28 | url: '/admin/comics//chapters/' + id + '/status',
29 | method: 'post',
30 | data: data
31 | })
32 | }
33 |
34 | export function createChapter(data) {
35 | return request({
36 | url: '/admin/comics/chapters',
37 | method: 'post',
38 | data: data
39 | })
40 | }
41 |
42 | export function deleteChapter(id,data) {
43 | return request({
44 | url: '/admin/comics/chapters/' + id,
45 | method: 'delete',
46 | data: data
47 | })
48 | }
49 |
--------------------------------------------------------------------------------
/pkg/ui/src/api/lime-admin/users.js:
--------------------------------------------------------------------------------
1 | import request from './request'
2 |
3 | export function getUser(id) {
4 | return request({
5 | url: '/admin/users/' + id,
6 | method: 'GET'
7 | })
8 | }
9 |
10 | export function userList(query) {
11 | return request({
12 | url: '/admin/users',
13 | method: 'GET',
14 | params: query
15 | })
16 | }
17 |
18 | export function updateUser(id, data) {
19 | return request({
20 | url: '/admin/users/' + id,
21 | method: 'put',
22 | data: data
23 | })
24 | }
25 |
26 | export function updatestatus(id, data) {
27 | return request({
28 | url: '/admin/users/' + id + '/status',
29 | method: 'post',
30 | data: data
31 | })
32 | }
33 |
34 | export function createUser(data) {
35 | return request({
36 | url: '/admin/users',
37 | method: 'post',
38 | data: data
39 | })
40 | }
41 |
42 | export function uploadAvatar(formData) {
43 | return request({
44 | url: '/admin/upload/face',
45 | method: 'post',
46 | data: formData,
47 | headers: {
48 | 'Content-Type': 'multipart/form-data'
49 | }
50 | })
51 | }
52 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/international.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/api/admin/dao/chapter.go:
--------------------------------------------------------------------------------
1 | package dao
2 |
3 | import (
4 | "github.com/jinzhu/gorm"
5 | "lime/pkg/api/admin/dto"
6 | "lime/pkg/api/admin/model"
7 | "lime/pkg/common/db"
8 | )
9 |
10 | type ChapterDao struct {
11 | }
12 |
13 | func (u ChapterDao) Get(id int) model.Chapter {
14 | var Chapter model.Chapter
15 | db := db.GetGormDB()
16 | db.Where("id = ?", id).First(&Chapter)
17 | return Chapter
18 | }
19 |
20 | func (u ChapterDao) List(listDto dto.GeneralListDto) ([]model.Chapter, int64) {
21 | var Chapter []model.Chapter
22 | var total int64
23 | db := db.GetGormDB()
24 | db.Preload("Chapter").Offset(listDto.Skip).Limit(listDto.Limit).Find(&Chapter)
25 | db.Model(&model.Chapter{}).Count(&total)
26 | return Chapter, total
27 | }
28 |
29 | func (u ChapterDao) Create(Chapter *model.Chapter) *gorm.DB {
30 | db := db.GetGormDB()
31 | return db.Save(Chapter)
32 | }
33 |
34 | func (u ChapterDao) Update(Chapter *model.Chapter) *gorm.DB {
35 | db := db.GetGormDB()
36 | return db.Save(Chapter)
37 | }
38 |
39 | func (u ChapterDao) Delete(Chapter *model.Chapter) *gorm.DB {
40 | db := db.GetGormDB()
41 | return db.Delete(Chapter)
42 | }
43 |
--------------------------------------------------------------------------------
/pkg/crawler/core/task.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "github.com/pkg/errors"
7 | "sync"
8 | )
9 |
10 | // Task is a task define
11 | type Task struct {
12 | ID int
13 | TaskRule
14 | TaskConfig
15 | }
16 |
17 | // NewTask return a new task object
18 | func NewTask(id int, rule TaskRule, config TaskConfig) *Task {
19 | return &Task{
20 | ID: id,
21 | TaskRule: rule,
22 | TaskConfig: config,
23 | }
24 | }
25 |
26 | var (
27 | ctlMu = &sync.RWMutex{}
28 | ctlMap = make(map[int]context.CancelFunc)
29 | )
30 |
31 | func addTaskCtrl(taskID int, cancelFunc context.CancelFunc) error {
32 | ctlMu.Lock()
33 | defer ctlMu.Unlock()
34 |
35 | if _, ok := ctlMap[taskID]; ok {
36 | return errors.WithStack(fmt.Errorf("duplicate taskID:%d", taskID))
37 | }
38 | ctlMap[taskID] = cancelFunc
39 |
40 | return nil
41 | }
42 |
43 | // CancelTask cancel a task by taskID
44 | func CancelTask(taskID int) bool {
45 | ctlMu.Lock()
46 | defer ctlMu.Unlock()
47 |
48 | cancel, ok := ctlMap[taskID]
49 | if !ok {
50 | return false
51 | }
52 | cancel()
53 | delete(ctlMap, taskID)
54 |
55 | return true
56 | }
57 |
--------------------------------------------------------------------------------
/pkg/ui/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017-present PanJiaChen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/wechat.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/ui/src/api/lime-admin/distributorLevel.js:
--------------------------------------------------------------------------------
1 | import request from './request'
2 |
3 | export function getDistributorLevel(id) {
4 | return request({
5 | url: '/admin/distributorlevels/' + id,
6 | method: 'GET'
7 | })
8 | }
9 |
10 | export function DistributorLevelList(query) {
11 | return request({
12 | url: '/admin/distributorlevels',
13 | method: 'GET',
14 | params: query
15 | })
16 | }
17 |
18 | export function updateDistributorLevel(id, data) {
19 | return request({
20 | url: '/admin/distributorlevels/' + id,
21 | method: 'put',
22 | data: data
23 | })
24 | }
25 |
26 | export function updatestatus(id, data) {
27 | return request({
28 | url: '/admin/distributorlevels/' + id + '/status',
29 | method: 'post',
30 | data: data
31 | })
32 | }
33 |
34 | export function createDistributorLevel(data) {
35 | return request({
36 | url: '/admin/distributorlevels',
37 | method: 'post',
38 | data: data
39 | })
40 | }
41 |
42 | export function deleteDistributorLevel(id,data) {
43 | return request({
44 | url: '/admin/distributorlevels/' + id,
45 | method: 'delete',
46 | data: data
47 | })
48 | }
49 |
--------------------------------------------------------------------------------
/config/in-cluster.yaml:
--------------------------------------------------------------------------------
1 | mode: debug
2 | mysql:
3 | dsn: >-
4 | ${lime_MYSQL_USERNAME}:${lime_MYSQL_PASSWORD}@tcp(${lime_MYSQL_HOST}:${lime_MYSQL_PORT})/${lime_MYSQL_DB}?charset=utf8&parseTime=True&loc=Local
5 | pool:
6 | min: 5
7 | max: 20
8 | redis:
9 | host: ${lime_REDIS_HOST}:${lime_REDIS_PORT}
10 | auth: ${lime_REDIS_PASSWORD}
11 | pool:
12 | min: 3
13 | max: 20
14 | mongo:
15 | host: ${lime_MONGO_HOST}
16 | port: ${lime_MONGO_PORT}
17 | db: ${lime_MONGO_DB}
18 | username: ${lime_MONGO_USERNAME}
19 | password: ${lime_MONGO_PASSWORD}
20 | authSource: ${lime_MONGO_AUTHSOURCE}
21 | cors:
22 | allow_credentials: false
23 | allow_headers:
24 | - '*'
25 | allow_methods:
26 | - GET
27 | - POST
28 | - OPTIONS
29 | - PUT
30 | - DELETE
31 | allow_origins:
32 | - '*'
33 | enable: false
34 | max_age: 7200
35 | upload:
36 | image_prefix_url: "http://127.0.0.1:8000"
37 | image_save_path: "data/images/"
38 | image_max_size: 5
39 | image_allow_exts:
40 | - .jpg
41 | - .jpeg
42 | - .png"
43 | auth:
44 | access_secret: ""
45 | refresh_secret: ""
46 | qiniu:
47 | ak: ""
48 | sk: ""
49 | bucket: ""
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/skill.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/down/search.go:
--------------------------------------------------------------------------------
1 | package down
2 |
3 | import (
4 | "fmt"
5 | "github.com/go-yaml/yaml"
6 | log "github.com/sirupsen/logrus"
7 | "io/ioutil"
8 | "lime/pkg/down/site"
9 | )
10 |
11 | func Search(keyword string, put bool, filename string, driver string) error {
12 | var bookurl = ""
13 | r, err := site.Search(keyword)
14 | if err != nil {
15 | return err
16 | }
17 | if !put {
18 | fmt.Printf("搜索到%d个内容:\n", len(r))
19 | for _, v := range r {
20 | fmt.Printf("%s %s %s\n", v.BookURL, v.BookName, v.Author)
21 | }
22 | return nil
23 | }
24 | if filename == "" {
25 | err := InitLoadStore(driver, bookurl)
26 | if err != nil {
27 | return err
28 | }
29 | } else {
30 | err := LoadLocalStore(filename)
31 | if err != nil {
32 | return err
33 | }
34 | }
35 | rrr := []site.ChaperSearchResult{}
36 | for _, v := range r {
37 | if (v.Author == chapter.Author) && (v.BookName == chapter.BookName) {
38 | log.Printf("%s %s %s", v.BookURL, v.BookName, v.Author)
39 | rrr = append(rrr, v)
40 | }
41 | }
42 | b, err := yaml.Marshal(chapter)
43 | if err != nil {
44 | return err
45 | }
46 | ioutil.WriteFile(filename, b, 0775)
47 | return nil
48 | }
49 |
--------------------------------------------------------------------------------
/pkg/ui/tests/unit/utils/formatTime.spec.js:
--------------------------------------------------------------------------------
1 | import { formatTime } from '@/utils/index.js'
2 | describe('Utils:formatTime', () => {
3 | const d = new Date('2018-07-13 17:54:01') // "2018-07-13 17:54:01"
4 | const retrofit = 5 * 1000
5 |
6 | it('ten digits timestamp', () => {
7 | expect(formatTime((d / 1000).toFixed(0))).toBe('7月13日17时54分')
8 | })
9 | it('test now', () => {
10 | expect(formatTime(+new Date() - 1)).toBe('刚刚')
11 | })
12 | it('less two minute', () => {
13 | expect(formatTime(+new Date() - 60 * 2 * 1000 + retrofit)).toBe('2分钟前')
14 | })
15 | it('less two hour', () => {
16 | expect(formatTime(+new Date() - 60 * 60 * 2 * 1000 + retrofit)).toBe('2小时前')
17 | })
18 | it('less one day', () => {
19 | expect(formatTime(+new Date() - 60 * 60 * 24 * 1 * 1000)).toBe('1天前')
20 | })
21 | it('more than one day', () => {
22 | expect(formatTime(d)).toBe('7月13日17时54分')
23 | })
24 | it('format', () => {
25 | expect(formatTime(d, '{y}-{m}-{d} {h}:{i}')).toBe('2018-07-13 17:54')
26 | expect(formatTime(d, '{y}-{m}-{d}')).toBe('2018-07-13')
27 | expect(formatTime(d, '{y}/{m}/{d} {h}-{i}')).toBe('2018/07/13 17-54')
28 | })
29 | })
30 |
--------------------------------------------------------------------------------
/pkg/api/admin/dao/comment.go:
--------------------------------------------------------------------------------
1 | package dao
2 |
3 | import (
4 | "github.com/jinzhu/gorm"
5 | "lime/pkg/api/admin/dto"
6 | "lime/pkg/api/admin/model"
7 | "lime/pkg/common/db"
8 | )
9 |
10 | type CommentDao struct {
11 | }
12 |
13 | func (c CommentDao) Get(id int) model.Comments {
14 | var Comment model.Comments
15 | db := db.GetGormDB()
16 | db.Where("id = ?", id).First(&Comment)
17 | return Comment
18 | }
19 |
20 | func (c CommentDao) GetAll() []model.Comments {
21 | var Comment []model.Comments
22 | db := db.GetGormDB()
23 | db.Model(&model.Comments{}).Find(&Comment)
24 | return Comment
25 | }
26 |
27 | func (c CommentDao) List(listDto dto.CommentListDto) ([]model.Comments, int64) {
28 | var Comment []model.Comments
29 | var total int64
30 | db := db.GetGormDB()
31 | db.Offset(listDto.Skip).Limit(listDto.Limit).Find(&Comment)
32 | db.Model(&model.Comments{}).Count(&total)
33 | return Comment, total
34 | }
35 |
36 | func (c CommentDao) Create(Comment *model.Comments) *gorm.DB {
37 | db := db.GetGormDB()
38 | return db.Save(Comment)
39 | }
40 |
41 | func (c CommentDao) Delete(Comment *model.Comments) *gorm.DB {
42 | db := db.GetGormDB()
43 | return db.Delete(Comment)
44 | }
45 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/people.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | SHELL := /bin/bash
2 | BASE_PATH := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
3 |
4 | TITLE := $(shell basename $(BASE_PATH))
5 | SHORT_REV := $(shell git rev-parse HEAD | cut -c1-8)
6 | BUILD_TIME := $(shell date +%Y-%m-%d--%T)
7 | APP_PKG := $(shell $(BASE_PATH)/scripts/apppkg.sh)
8 | UI := $(BASE_PATH)/pkg/ui
9 | TAG := $(shell $(BASE_PATH)/scripts/tag.sh)
10 | export BIN_OUT := $(BASE_PATH)/bin
11 |
12 | all: print
13 |
14 | print:
15 | @echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>making print<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
16 | @echo SHELL:$(SHELL)
17 | @echo BASE_PATH:$(BASE_PATH)
18 | @echo TITLE:$(TITLE)
19 | @echo SHORT_REV:$(SHORT_REV)
20 | @echo APP_PKG:$(APP_PKG)
21 | @echo BIN_OUT:$(BIN_OUT)
22 | @echo USER:$(USER)
23 | @echo HUB:$(HUB)
24 | @echo UI:$(UI)
25 | @echo TAG:$(TAG)
26 | @echo -e "\n"
27 | build:
28 | @echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>make build<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
29 | $(shell $(BASE_PATH)/scripts/build.sh)
30 | @echo -e "\n"
31 | run:
32 | @echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>run lime<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
33 | $(shell $(BASE_PATH)/scripts/run.sh)
34 | @echo -e "\n"
35 |
--------------------------------------------------------------------------------
/pkg/api/admin/dto/comicComment.go:
--------------------------------------------------------------------------------
1 | package dto
2 |
3 | import "time"
4 |
5 | type ComicCommentListDto struct {
6 | Id int `form:"id" json:"id" `
7 | Comic_id int `form:"comic_id" json:"comic_id" `
8 | Username string `form:"username" json:"username" `
9 | Content string `form:"content,default=0" json:"content" `
10 | Source string `form:"source" json:"source" `
11 | CreatedAt time.Time `form:"created_at" json:"created_at"`
12 | UpdatedAt time.Time `form:"updated_at" json:"updated_at"`
13 | DeletedAt *time.Time `form:"deleted_at" json:"deleted_at"`
14 | Page string `form:"page" json:"page" `
15 | Skip int `form:"skip,default=0" json:"skip"`
16 | Limit int `form:"limit,default=20" json:"limit" binding:"max=100"`
17 | }
18 |
19 | type ComicCommentCreateDto struct {
20 | Comic_id int `form:"comic_id" json:"comic_id" `
21 | Username string `form:"username" json:"username" `
22 | Content string `form:"content,default=0" json:"content" `
23 | Source string `form:"source" json:"source" `
24 | CreatedAt time.Time `form:"created_at" json:"created_at"`
25 | UpdatedAt time.Time `form:"updated_at" json:"updated_at"`
26 | }
27 |
--------------------------------------------------------------------------------
/pkg/api/admin/controllers/base.go:
--------------------------------------------------------------------------------
1 | package controllers
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "lime/pkg/api/admin/dto"
6 | "lime/pkg/api/utils/e"
7 | "net/http"
8 | )
9 |
10 | type BaseController struct {
11 | }
12 |
13 | func (bc *BaseController) BindAndValidate(c *gin.Context, obj interface{}) bool {
14 | if err := dto.Bind(c, obj); err != nil {
15 | failValidate(c, err.Error())
16 | return false
17 | }
18 | return true
19 | }
20 |
21 | func (bc *BaseController) Resp(c *gin.Context, data map[string]interface{}) {
22 | c.JSON(http.StatusOK, gin.H{
23 | "code": 200,
24 | "data": data,
25 | })
26 | }
27 |
28 | func (bc *BaseController) Ok(c *gin.Context, msg string) {
29 | c.JSON(http.StatusOK, gin.H{
30 | "code": 200,
31 | "msg": msg,
32 | })
33 | }
34 |
35 | func (bc *BaseController) Fail(c *gin.Context, errs *e.ControllerError) {
36 | c.JSON(http.StatusOK, gin.H{
37 | "code": errs.Code,
38 | "msg": errs.Message,
39 | "moreinfo": errs.Moreinfo,
40 | })
41 | }
42 |
43 | func failValidate(c *gin.Context, msg string) {
44 | errs := e.ErrValidation
45 | c.AbortWithStatusJSON(http.StatusOK, gin.H{
46 | "code": errs.Code,
47 | "msg": errs.Message,
48 | "detail": msg,
49 | })
50 | }
51 |
--------------------------------------------------------------------------------
/pkg/h5/src/permission.js:
--------------------------------------------------------------------------------
1 | import router from './router'
2 | import store from './store'
3 | import { Toast } from 'mint-ui'
4 | import NProgress from 'nprogress' // progress bar
5 | import 'nprogress/nprogress.css' // progress bar style
6 | import { getToken } from '@/utils/auth' // get token from cookie
7 |
8 | NProgress.configure({ showSpinner: false }) // NProgress Configuration
9 |
10 | const whiteList = ['/login', '/register', '/home'] // no redirect whitelist
11 |
12 | router.beforeEach(async (to, from, next) => {
13 | // start progress bar
14 | NProgress.start()
15 | const hasToken = getToken()
16 |
17 | if (hasToken) {
18 | if (to.path === '/login') {
19 | next({ path: '/' })
20 | NProgress.done()
21 | } else {
22 | next()
23 | NProgress.done()
24 | }
25 | } else {
26 | if (whiteList.indexOf(to.path) !== -1) {
27 | next()
28 | } else {
29 | await store.dispatch('resetToken')
30 | Toast({
31 | message: '重新登陆',
32 | position: 'bottom',
33 | duration: 5000
34 | });
35 | next(`/login`)
36 | NProgress.done()
37 | }
38 | }
39 | })
40 |
41 | router.afterEach(() => {
42 | // finish progress bar
43 | NProgress.done()
44 | })
45 |
--------------------------------------------------------------------------------
/pkg/api/admin/model/distributor.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "time"
5 | )
6 |
7 | type Distributor struct {
8 | Id int `gorm:"primary_key" json:"id"` //分类ID
9 | Recommender_id int `json:"recommender_id"` //推荐人ID
10 | Distributor_id int `json:"distributor_id"` //分销商ID
11 | Name string `json:"name"` //姓名
12 | Mobile string `json:"mobile"` //手机
13 | Distribution_level int `json:"distribution_level"` //分销等级
14 | Commission_withdrawn int `json:"commission_withdrawn"` //已经提现佣金
15 | Commission_available int `json:"commission_available"` //可提现佣金
16 | Status int `json:"status"` //状态:1 已审核 2 待审核 3 已拒绝
17 | CreatedAt time.Time `json:"created_at" gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP"`
18 | UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP"`
19 | DeletedAt *time.Time `json:"deleted_at"`
20 | }
21 |
22 | func (C *Distributor) TableName() string {
23 | return "distributor"
24 | }
25 |
26 | func init() {
27 | //db.Register(&Distributor{})
28 | }
29 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/language.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/ui/src/layout/components/AppMain.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
24 |
25 |
49 |
50 |
58 |
--------------------------------------------------------------------------------
/pkg/ui/tests/unit/utils/validate.spec.js:
--------------------------------------------------------------------------------
1 | import { validUsername, validURL, validLowerCase, validUpperCase, validAlphabets } from '@/utils/validate.js'
2 | describe('Utils:validate', () => {
3 | it('validUsername', () => {
4 | expect(validUsername('admin')).toBe(true)
5 | expect(validUsername('editor')).toBe(true)
6 | expect(validUsername('xxxx')).toBe(false)
7 | })
8 | it('validURL', () => {
9 | expect(validURL('https://github.com/PanJiaChen/vue-element-admin')).toBe(true)
10 | expect(validURL('http://github.com/PanJiaChen/vue-element-admin')).toBe(true)
11 | expect(validURL('github.com/PanJiaChen/vue-element-admin')).toBe(false)
12 | })
13 | it('validLowerCase', () => {
14 | expect(validLowerCase('abc')).toBe(true)
15 | expect(validLowerCase('Abc')).toBe(false)
16 | expect(validLowerCase('123abc')).toBe(false)
17 | })
18 | it('validUpperCase', () => {
19 | expect(validUpperCase('ABC')).toBe(true)
20 | expect(validUpperCase('Abc')).toBe(false)
21 | expect(validUpperCase('123ABC')).toBe(false)
22 | })
23 | it('validAlphabets', () => {
24 | expect(validAlphabets('ABC')).toBe(true)
25 | expect(validAlphabets('Abc')).toBe(true)
26 | expect(validAlphabets('123aBC')).toBe(false)
27 | })
28 | })
29 |
--------------------------------------------------------------------------------
/pkg/api/admin/model/comicChapters.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "gorm.io/datatypes"
5 | "time"
6 | )
7 |
8 | type ComicChapters struct {
9 | Id int `gorm:"primary_key" json:"id"` //分类ID
10 | Comic_id int `json:"comic_id"` //漫画ID
11 | Chapter_no int `json:"chapter_no"` //章节编号
12 | Title string `json:"title"` //章节标题
13 | Desc datatypes.JSON `json:"desc" gorm:"type:json;" ` //章节图
14 | Cover string `json:"cover"` //封面
15 | Upload_type int `json:"upload_type"` //上传类型 1多图上传 2链接上传
16 | Is_vip int `json:"is_vip"` //是否收费
17 | CreatedAt time.Time `json:"created_at" gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP"`
18 | UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP"`
19 | DeletedAt *time.Time `json:"deleted_at"`
20 | }
21 |
22 | type ChapterImage struct {
23 | Name string `json:"name"`
24 | Url string `json:"url"`
25 | }
26 |
27 | func (C *ComicChapters) TableName() string {
28 | return "comic_chapter"
29 | }
30 |
31 | func init() {
32 | //db.Register(&ComicChapters{})
33 | }
34 |
--------------------------------------------------------------------------------
/pkg/api/admin/dao/comicComment.go:
--------------------------------------------------------------------------------
1 | package dao
2 |
3 | import (
4 | "github.com/jinzhu/gorm"
5 | "lime/pkg/api/admin/dto"
6 | "lime/pkg/api/admin/model"
7 | "lime/pkg/common/db"
8 | )
9 |
10 | type ComicCommentDao struct {
11 | }
12 |
13 | func (c ComicCommentDao) Get(id int) model.ComicComments {
14 | var Comment model.ComicComments
15 | db := db.GetGormDB()
16 | db.Where("id = ?", id).First(&Comment)
17 | return Comment
18 | }
19 |
20 | func (c ComicCommentDao) GetAll() []model.ComicComments {
21 | var Comment []model.ComicComments
22 | db := db.GetGormDB()
23 | db.Model(&model.ComicComments{}).Find(&Comment)
24 | return Comment
25 | }
26 |
27 | func (c ComicCommentDao) List(listDto dto.ComicCommentListDto) ([]model.ComicComments, int64) {
28 | var Comment []model.ComicComments
29 | var total int64
30 | db := db.GetGormDB()
31 | db.Offset(listDto.Skip).Limit(listDto.Limit).Find(&Comment)
32 | db.Model(&model.ComicComments{}).Count(&total)
33 | return Comment, total
34 | }
35 |
36 | func (c ComicCommentDao) Create(Comment *model.ComicComments) *gorm.DB {
37 | db := db.GetGormDB()
38 | return db.Save(Comment)
39 | }
40 |
41 | func (c ComicCommentDao) Delete(Comment *model.ComicComments) *gorm.DB {
42 | db := db.GetGormDB()
43 | return db.Delete(Comment)
44 | }
45 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/eye-open.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/ui/src/utils/open-window.js:
--------------------------------------------------------------------------------
1 | /**
2 | *Created by PanJiaChen on 16/11/29.
3 | * @param {Sting} url
4 | * @param {Sting} title
5 | * @param {Number} w
6 | * @param {Number} h
7 | */
8 | export default function openWindow(url, title, w, h) {
9 | // Fixes dual-screen position Most browsers Firefox
10 | const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left
11 | const dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top
12 |
13 | const width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width
14 | const height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height
15 |
16 | const left = ((width / 2) - (w / 2)) + dualScreenLeft
17 | const top = ((height / 2) - (h / 2)) + dualScreenTop
18 | const newWindow = window.open(url, title, 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=yes, copyhistory=no, width=' + w + ', height=' + h + ', top=' + top + ', left=' + left)
19 |
20 | // Puts focus on the newWindow
21 | if (window.focus) {
22 | newWindow.focus()
23 | }
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/pkg/ui/src/views/guide/steps.js:
--------------------------------------------------------------------------------
1 | const steps = [
2 | {
3 | element: '#hamburger-container',
4 | popover: {
5 | title: 'Hamburger',
6 | description: 'Open && Close sidebar',
7 | position: 'bottom'
8 | }
9 | },
10 | {
11 | element: '#breadcrumb-container',
12 | popover: {
13 | title: 'Breadcrumb',
14 | description: 'Indicate the current page location',
15 | position: 'bottom'
16 | }
17 | },
18 | {
19 | element: '#header-search',
20 | popover: {
21 | title: 'Page Search',
22 | description: 'Page search, quick navigation',
23 | position: 'left'
24 | }
25 | },
26 | {
27 | element: '#screenfull',
28 | popover: {
29 | title: 'Screenfull',
30 | description: 'Set the page into fullscreen',
31 | position: 'left'
32 | }
33 | },
34 | {
35 | element: '#size-select',
36 | popover: {
37 | title: 'Switch Size',
38 | description: 'Switch the system size',
39 | position: 'left'
40 | }
41 | },
42 | {
43 | element: '#tags-view-container',
44 | popover: {
45 | title: 'Tags view',
46 | description: 'The history of the page you visited',
47 | position: 'bottom'
48 | },
49 | padding: 0
50 | }
51 | ]
52 |
53 | export default steps
54 |
--------------------------------------------------------------------------------
/scripts/version.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
4 |
5 | BUILD_GIT_REVISION=$(git rev-parse HEAD 2> /dev/null)
6 | if [[ $? == 0 ]]; then
7 | git diff-index --quiet HEAD
8 | if [[ $? != 0 ]]; then
9 | BUILD_GIT_REVISION=${BUILD_GIT_REVISION}"-dirty"
10 | fi
11 | else
12 | BUILD_GIT_REVISION=unknown
13 | fi
14 |
15 | # Check for local changes
16 | git diff-index --quiet HEAD --
17 | if [[ $? == 0 ]];
18 | then
19 | tree_status="Clean"
20 | else
21 | tree_status="Modified"
22 | fi
23 |
24 | # XXX This needs to be updated to accomodate tags added after building, rather than prior to builds
25 | RELEASE_TAG=$(git describe --match '[0-9]*\.[0-9]*\.[0-9]*' --exact-match 2> /dev/null || echo "")
26 |
27 | # security wanted VERSION='unknown'
28 | VERSION="${BUILD_GIT_REVISION}"
29 | if [[ -n "${RELEASE_TAG}" ]]; then
30 | VERSION="${RELEASE_TAG}"
31 | elif [[ -n ${ISTIO_VERSION} ]]; then
32 | VERSION="${ISTIO_VERSION}"
33 | fi
34 |
35 | # used by pkg/version
36 | echo buildVersion "${VERSION}"
37 | echo buildGitRevision "${BUILD_GIT_REVISION}"
38 | echo buildUser "$(whoami)"
39 | echo buildHost "$(hostname -f)"
40 | echo buildStatus "${tree_status}"
41 | echo buildTime "$(date +%Y-%m-%d--%T)"
42 |
--------------------------------------------------------------------------------
/pkg/ui/tests/unit/utils/parseTime.spec.js:
--------------------------------------------------------------------------------
1 | import { parseTime } from '@/utils/index.js'
2 |
3 | describe('Utils:parseTime', () => {
4 | const d = new Date('2018-07-13 17:54:01') // "2018-07-13 17:54:01"
5 | it('timestamp', () => {
6 | expect(parseTime(d)).toBe('2018-07-13 17:54:01')
7 | })
8 |
9 | it('timestamp string', () => {
10 | expect(parseTime((d + ''))).toBe('2018-07-13 17:54:01')
11 | })
12 |
13 | it('ten digits timestamp', () => {
14 | expect(parseTime((d / 1000).toFixed(0))).toBe('2018-07-13 17:54:01')
15 | })
16 | it('new Date', () => {
17 | expect(parseTime(new Date(d))).toBe('2018-07-13 17:54:01')
18 | })
19 | it('format', () => {
20 | expect(parseTime(d, '{y}-{m}-{d} {h}:{i}')).toBe('2018-07-13 17:54')
21 | expect(parseTime(d, '{y}-{m}-{d}')).toBe('2018-07-13')
22 | expect(parseTime(d, '{y}/{m}/{d} {h}-{i}')).toBe('2018/07/13 17-54')
23 | })
24 | it('get the day of the week', () => {
25 | expect(parseTime(d, '{a}')).toBe('五') // 星期五
26 | })
27 | it('get the day of the week', () => {
28 | expect(parseTime(+d + 1000 * 60 * 60 * 24 * 2, '{a}')).toBe('日') // 星期日
29 | })
30 | it('empty argument', () => {
31 | expect(parseTime()).toBeNull()
32 | })
33 |
34 | it('null', () => {
35 | expect(parseTime(null)).toBeNull()
36 | })
37 | })
38 |
--------------------------------------------------------------------------------
/pkg/api/admin/controllers/comments.go:
--------------------------------------------------------------------------------
1 | package controllers
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "lime/pkg/api/admin/dto"
6 | "lime/pkg/api/admin/service"
7 | "lime/pkg/api/utils/e"
8 | )
9 |
10 | var CommentsService = service.CommentService{}
11 |
12 | type CommentsController struct {
13 | BaseController
14 | }
15 |
16 | func (C *CommentsController) List(c *gin.Context) {
17 | var Dto dto.CommentListDto
18 | if C.BindAndValidate(c, &Dto) {
19 | data, total := CommentsService.List(Dto)
20 | C.Resp(c, map[string]interface{}{
21 | "list": data,
22 | "total": total,
23 | "page": Dto.Page,
24 | "page_size": Dto.Limit,
25 | })
26 | }
27 | }
28 |
29 | func (C *CommentsController) Get(c *gin.Context) {
30 | var Dto dto.GeneralGetDto
31 | if C.BindAndValidate(c, &Dto) {
32 | data := CommentsService.InfoOfId(Dto)
33 | if data.Id < 1 {
34 | C.Fail(c, e.ErrIdData)
35 | return
36 | }
37 | C.Resp(c, map[string]interface{}{
38 | "result": data,
39 | })
40 | }
41 | }
42 |
43 | func (C *CommentsController) Delete(c *gin.Context) {
44 | var Dto dto.GeneralDelDto
45 | if C.BindAndValidate(c, &Dto) {
46 | affected := CommentsService.Delete(Dto)
47 | if affected <= 0 {
48 | C.Fail(c, e.ErrDelFail)
49 | return
50 | }
51 | C.Ok(c, "删除成功")
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/pkg/api/admin/model/chapters.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "lime/pkg/common/db"
5 | "time"
6 | )
7 |
8 | type Chapters struct {
9 | Id int `gorm:"primary_key" json:"id"` //分类ID
10 | Novel_id int `json:"novel_id"` //小说ID
11 | Chapter_no int `json:"chapter_no"` //章节编号
12 | Title string `json:"title"` //章节标题
13 | Desc string `json:"desc"` //章节内容
14 | Link string `json:"link"` //章节采集链接
15 | Is_vip int `json:"is_vip"` //是否收费
16 | Source string `json:"source"` //章节采集站点源
17 | Views int `json:"views"` //浏览次数
18 | Text_num int `json:"text_num"` //章节字数
19 | Status int `json:"status"` //章节采集状态0正常,1失败
20 | Try_views int `json:"try_views"` //采集重试次数
21 | CreatedAt time.Time `json:"created_at" gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP"`
22 | UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP"`
23 | DeletedAt *time.Time `json:"deleted_at"`
24 | }
25 |
26 | func (C *Chapters) TableName() string {
27 | return "novel_chapter_0000"
28 | }
29 |
30 | func init() {
31 | db.Register(&Chapters{})
32 | }
33 |
--------------------------------------------------------------------------------
/pkg/ui/src/components/Screenfull/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
50 |
51 |
61 |
--------------------------------------------------------------------------------
/pkg/common/cache/init.go:
--------------------------------------------------------------------------------
1 | package cache
2 |
3 | import "time"
4 |
5 | var adapter Adapter
6 |
7 | type Adapter interface {
8 | Connect()
9 | Get(key string) (string, error)
10 | Set(key string, val string, expire int) error
11 | Del(key string) error
12 | HashGet(hk, key string) (string, error)
13 | HashDel(hk, key string) error
14 | Increase(key string) error
15 | Expire(key string, dur time.Duration) error
16 | }
17 |
18 | func SetUp() {
19 | adapter = &Redis{}
20 | adapter.Connect()
21 | }
22 |
23 | // Set val in cache
24 | func Set(key, val string, expire int) error {
25 | return adapter.Set(key, val, expire)
26 | }
27 |
28 | // Get val in cache
29 | func Get(key string) (string, error) {
30 | return adapter.Get(key)
31 | }
32 |
33 | // Del delete key in cache
34 | func Del(key string) error {
35 | return adapter.Del(key)
36 | }
37 |
38 | // HashGet get val in hashtable cache
39 | func HashGet(hk, key string) (string, error) {
40 | return adapter.HashGet(hk, key)
41 | }
42 |
43 | // HashDel delete one key:value pair in hashtable cache
44 | func HashDel(hk, key string) error {
45 | return adapter.HashDel(hk, key)
46 | }
47 |
48 | // Increase value
49 | func Increase(key string) error {
50 | return adapter.Increase(key)
51 | }
52 |
53 | func Expire(key string, dur time.Duration) error {
54 | return adapter.Expire(key, dur)
55 | }
56 |
--------------------------------------------------------------------------------
/pkg/api/admin/dto/comment.go:
--------------------------------------------------------------------------------
1 | package dto
2 |
3 | import "time"
4 |
5 | type CommentListDto struct {
6 | Id int `form:"id" json:"id" `
7 | Name string `form:"name" json:"name" `
8 | Novel_id int `form:"novel_id" json:"novel_id" `
9 | Username string `form:"username" json:"username" `
10 | Content string `form:"content,default=0" json:"content" `
11 | Likes int `form:"likes" json:"likes" `
12 | Source string `form:"source" json:"source" `
13 | CreatedAt time.Time `form:"created_at" json:"created_at"`
14 | UpdatedAt time.Time `form:"updated_at" json:"updated_at"`
15 | DeletedAt *time.Time `form:"deleted_at" json:"deleted_at"`
16 | Page string `form:"page" json:"page" `
17 | Skip int `form:"skip,default=0" json:"skip"`
18 | Limit int `form:"limit,default=20" json:"limit" binding:"max=100"`
19 | }
20 |
21 | type CommentCreateDto struct {
22 | Novel_id int `form:"novel_id" json:"novel_id" `
23 | Username string `form:"username" json:"username" `
24 | Content string `form:"content,default=0" json:"content" `
25 | Likes int `form:"likes" json:"likes" `
26 | Source string `form:"source" json:"source" `
27 | CreatedAt time.Time `form:"created_at" json:"created_at"`
28 | UpdatedAt time.Time `form:"updated_at" json:"updated_at"`
29 | }
30 |
--------------------------------------------------------------------------------
/pkg/down/syncstore.go:
--------------------------------------------------------------------------------
1 | package down
2 |
3 | import (
4 | "fmt"
5 | "github.com/go-yaml/yaml"
6 | "io"
7 | "io/ioutil"
8 | "lime/pkg/down/store"
9 | "sync"
10 | )
11 |
12 | type SyncStore struct {
13 | lock *sync.Mutex
14 | IsTWork bool
15 | jobs [][]bool
16 | Store *store.Store
17 | }
18 |
19 | func (s *SyncStore) Init() {
20 | s.jobs = make([][]bool, len(s.Store.Volumes))
21 | s.lock = &sync.Mutex{}
22 | for k := range s.jobs {
23 | s.jobs[k] = make([]bool, len(s.Store.Volumes[k].Chapters))
24 | }
25 | }
26 |
27 | func (s *SyncStore) GetJob() (vi, ci int, url string, err error) {
28 | s.lock.Lock()
29 | defer s.lock.Unlock()
30 | for vi, vol := range s.Store.Volumes {
31 | for ci, ch := range vol.Chapters {
32 | if !s.jobs[vi][ci] {
33 | if len(ch.Text) == 0 {
34 | s.jobs[vi][ci] = true
35 | return vi, ci, ch.URL, nil
36 | }
37 | }
38 | }
39 | }
40 | return 0, 0, "", io.EOF
41 | }
42 |
43 | func (s *SyncStore) SaveJob(vi, ci int, text []string) {
44 | s.lock.Lock()
45 | defer s.lock.Unlock()
46 | s.Store.Volumes[vi].Chapters[ci].Text = text
47 | bbb, err := yaml.Marshal(*(s.Store))
48 | if err != nil {
49 | panic(err)
50 | }
51 | var filename = fmt.Sprintf("%s.%s", s.Store.BookName, store.FileExt)
52 | err = ioutil.WriteFile(filename, bbb, 0775)
53 | if err != nil {
54 | panic(err)
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/pkg/h5/src/components/common/TopMenu.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
19 |
20 |
50 |
--------------------------------------------------------------------------------
/pkg/ui/src/directive/el-table/adaptive.js:
--------------------------------------------------------------------------------
1 | import { addResizeListener, removeResizeListener } from 'element-ui/src/utils/resize-event'
2 |
3 | /**
4 | * How to use
5 | * ...
6 | * el-table height is must be set
7 | * bottomOffset: 30(default) // The height of the table from the bottom of the page.
8 | */
9 |
10 | const doResize = (el, binding, vnode) => {
11 | const { componentInstance: $table } = vnode
12 |
13 | const { value } = binding
14 |
15 | if (!$table.height) {
16 | throw new Error(`el-$table must set the height. Such as height='100px'`)
17 | }
18 | const bottomOffset = (value && value.bottomOffset) || 30
19 |
20 | if (!$table) return
21 |
22 | const height = window.innerHeight - el.getBoundingClientRect().top - bottomOffset
23 | $table.layout.setHeight(height)
24 | $table.doLayout()
25 | }
26 |
27 | export default {
28 | bind(el, binding, vnode) {
29 | el.resizeListener = () => {
30 | doResize(el, binding, vnode)
31 | }
32 | // parameter 1 is must be "Element" type
33 | addResizeListener(window.document.body, el.resizeListener)
34 | },
35 | inserted(el, binding, vnode) {
36 | doResize(el, binding, vnode)
37 | },
38 | unbind(el) {
39 | removeResizeListener(window.document.body, el.resizeListener)
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/pkg/api/admin/controllers/comicComments.go:
--------------------------------------------------------------------------------
1 | package controllers
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "lime/pkg/api/admin/dto"
6 | "lime/pkg/api/admin/service"
7 | "lime/pkg/api/utils/e"
8 | )
9 |
10 | var ComicCommentsService = service.ComicCommentervice{}
11 |
12 | type ComicCommentsController struct {
13 | BaseController
14 | }
15 |
16 | func (C *ComicCommentsController) List(c *gin.Context) {
17 | var Dto dto.ComicCommentListDto
18 | if C.BindAndValidate(c, &Dto) {
19 | data, total := ComicCommentsService.List(Dto)
20 | C.Resp(c, map[string]interface{}{
21 | "list": data,
22 | "total": total,
23 | "page": Dto.Page,
24 | "page_size": Dto.Limit,
25 | })
26 | }
27 | }
28 |
29 | func (C *ComicCommentsController) Get(c *gin.Context) {
30 | var Dto dto.GeneralGetDto
31 | if C.BindAndValidate(c, &Dto) {
32 | data := ComicCommentsService.InfoOfId(Dto)
33 | if data.Id < 1 {
34 | C.Fail(c, e.ErrIdData)
35 | return
36 | }
37 | C.Resp(c, map[string]interface{}{
38 | "result": data,
39 | })
40 | }
41 | }
42 |
43 | func (C *ComicCommentsController) Delete(c *gin.Context) {
44 | var Dto dto.GeneralDelDto
45 | if C.BindAndValidate(c, &Dto) {
46 | affected := ComicCommentsService.Delete(Dto)
47 | if affected <= 0 {
48 | C.Fail(c, e.ErrDelFail)
49 | return
50 | }
51 | C.Ok(c, "删除成功")
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/pkg/ui/src/components/Hamburger/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
32 |
33 |
45 |
--------------------------------------------------------------------------------
/pkg/crawler/novels/aoyuge/file.go:
--------------------------------------------------------------------------------
1 | package aoyuge
2 |
3 | import (
4 | "fmt"
5 | "github.com/go-yaml/yaml"
6 | "io/ioutil"
7 | "net/url"
8 | "os"
9 | "sync"
10 | )
11 |
12 | // Chapter 章节
13 | type Chapter struct {
14 | Name string //名称
15 | URL string //章节链接
16 | Text []string
17 | Alias []string `yaml:"-"`
18 | MuxLock sync.Mutex `yaml:"-"`
19 | }
20 |
21 | const FileExt = "lime"
22 |
23 | // Volume 卷
24 | type Volume struct {
25 | Name string
26 | IsVIP bool
27 | Chapters []Chapter
28 | }
29 |
30 | // Store is store yaml data file format
31 | type Store struct {
32 | BookURL string
33 | BookName string
34 | Author string // 作者
35 | CoverURL string // 封面链接
36 | Description string // 介绍
37 | Volumes []Volume
38 | }
39 |
40 | func WriteBook(bookurl string, chapter Store) error {
41 | bookURL, err := url.Parse(bookurl)
42 | if err != nil {
43 | return err
44 | }
45 | chapter.BookURL = bookURL.String()
46 | filename := fmt.Sprintf("%s.%s", chapter.BookName, FileExt)
47 | filemode, err := os.Stat(filename)
48 | if err != nil && os.IsNotExist(err) {
49 | bookContent, err := yaml.Marshal(chapter)
50 | if err != nil {
51 | return err
52 | }
53 | ioutil.WriteFile(filename, bookContent, 0775)
54 | return nil
55 | }
56 | if filemode.IsDir() {
57 | return fmt.Errorf("is Dir")
58 | }
59 | return nil
60 | }
61 |
--------------------------------------------------------------------------------
/pkg/api/admin/model/distributorLevel.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "gorm.io/datatypes"
5 | "time"
6 | )
7 |
8 | type DistributorLevel struct {
9 | Id int `gorm:"primary_key" json:"id"` //分类ID
10 | Name string `json:"name"` //等级名称
11 | Recommendtype int `json:"recommendtype"` //返佣类型 1按比例返佣 2 按固定返佣
12 | Buyagain_switch int `json:"buyagain_switch"` //复购返佣
13 | Auto_upgrade int `json:"auto_upgrade"` //自动升级 0 否 1是
14 | Upgrade_conditions datatypes.JSON `json:"upgrade_conditions"` //升级条件
15 | Adaptive_degradation int `json:"adaptive_degradation"` //自动降级
16 | Degradation_conditions datatypes.JSON `json:"degradation_conditions"` //降级条件
17 | Weight int `json:"weight"` //权重
18 | CreatedAt time.Time `json:"created_at" gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP"`
19 | UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP"`
20 | DeletedAt *time.Time `json:"deleted_at"`
21 | }
22 |
23 | func (C *DistributorLevel) TableName() string {
24 | return "distributor_level"
25 | }
26 |
27 | func init() {
28 | //db.Register(&DistributorLevel{})
29 | }
30 |
--------------------------------------------------------------------------------
/pkg/h5/build/build.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | require('./check-versions')()
3 |
4 | process.env.NODE_ENV = 'production'
5 |
6 | const ora = require('ora')
7 | const rm = require('rimraf')
8 | const path = require('path')
9 | const chalk = require('chalk')
10 | const webpack = require('webpack')
11 | const config = require('../config')
12 | const webpackConfig = require('./webpack.prod.conf')
13 |
14 | const spinner = ora('building for production...')
15 | spinner.start()
16 |
17 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
18 | if (err) throw err
19 | webpack(webpackConfig, (err, stats) => {
20 | spinner.stop()
21 | if (err) throw err
22 | process.stdout.write(stats.toString({
23 | colors: true,
24 | modules: false,
25 | children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
26 | chunks: false,
27 | chunkModules: false
28 | }) + '\n\n')
29 |
30 | if (stats.hasErrors()) {
31 | console.log(chalk.red(' Build failed with errors.\n'))
32 | process.exit(1)
33 | }
34 |
35 | console.log(chalk.cyan(' Build complete.\n'))
36 | console.log(chalk.yellow(
37 | ' Tip: built files are meant to be served over an HTTP server.\n' +
38 | ' Opening index.html over file:// won\'t work.\n'
39 | ))
40 | })
41 | })
42 |
--------------------------------------------------------------------------------
/pkg/h5/src/assets/user.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/api/admin/dao/category.go:
--------------------------------------------------------------------------------
1 | package dao
2 |
3 | import (
4 | "github.com/jinzhu/gorm"
5 | "lime/pkg/api/admin/dto"
6 | "lime/pkg/api/admin/model"
7 | "lime/pkg/common/db"
8 | )
9 |
10 | type CategoryDao struct {
11 | }
12 |
13 | func (c CategoryDao) Get(id int) model.Category {
14 | var Category model.Category
15 | db := db.GetGormDB()
16 | db.Where("id = ?", id).First(&Category)
17 | return Category
18 | }
19 |
20 | func (c CategoryDao) GetAll() []model.Category {
21 | var Category []model.Category
22 | db := db.GetGormDB()
23 | db.Model(&model.Category{}).Find(&Category)
24 | return Category
25 | }
26 |
27 | func (c CategoryDao) List(listDto dto.CategoryListDto) ([]model.Category, int64) {
28 | var Category []model.Category
29 | var total int64
30 | db := db.GetGormDB()
31 | db.Offset(listDto.Skip).Limit(listDto.Limit).Find(&Category)
32 | db.Model(&model.Category{}).Count(&total)
33 | return Category, total
34 | }
35 |
36 | func (c CategoryDao) Create(Category *model.Category) *gorm.DB {
37 | db := db.GetGormDB()
38 | return db.Save(Category)
39 | }
40 |
41 | // Update
42 | func (c CategoryDao) Update(Category *model.Category, ups map[string]interface{}) *gorm.DB {
43 | db := db.GetGormDB()
44 | return db.Model(Category).Update(ups)
45 | }
46 |
47 | func (c CategoryDao) Delete(Category *model.Category) *gorm.DB {
48 | db := db.GetGormDB()
49 | return db.Delete(Category)
50 | }
51 |
--------------------------------------------------------------------------------
/pkg/api/admin/dto/comicCategory.go:
--------------------------------------------------------------------------------
1 | package dto
2 |
3 | import "time"
4 |
5 | type ComicCategoryListDto struct {
6 | Name string `form:"name" json:"name" `
7 | Comic_num int `form:"comic_num,default=0" json:"comic_num" `
8 | Sort int `form:"sort" json:"sort" `
9 | CreatedAt time.Time `form:"created_at" json:"created_at"`
10 | UpdatedAt time.Time `form:"updated_at" json:"updated_at"`
11 | DeletedAt *time.Time `form:"deleted_at" json:"deleted_at"`
12 | Page string `form:"page" json:"page" `
13 | Skip int `form:"skip,default=0" json:"skip"`
14 | Limit int `form:"limit,default=20" json:"limit" binding:"max=100"`
15 | }
16 |
17 | type ComicCategoryCreateDto struct {
18 | Name string `form:"name" json:"name" `
19 | Comic_num int `form:"comic_num,default=0" json:"comic_num" `
20 | Sort int `form:"sort" json:"sort" `
21 | CreatedAt time.Time `form:"created_at" json:"created_at"`
22 | UpdatedAt time.Time `form:"updated_at" json:"updated_at"`
23 | }
24 |
25 | type ComicCategoryEditDto struct {
26 | Id int `uri:"id" json:"id" binding:"required"`
27 | Name string `form:"name" json:"name" binding:"required"`
28 | Comic_num int `form:"comic_num,default=0" json:"comic_num" `
29 | Sort int `form:"sort" json:"sort" `
30 | UpdatedAt time.Time `form:"updated_at" json:"updated_at" sql:"-"`
31 | }
32 |
--------------------------------------------------------------------------------
/pkg/ui/src/icons/svg/404.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pkg/ui/plop-templates/view/prompt.js:
--------------------------------------------------------------------------------
1 | const { notEmpty } = require('../utils.js')
2 |
3 | module.exports = {
4 | description: 'generate a view',
5 | prompts: [{
6 | type: 'input',
7 | name: 'name',
8 | message: 'view name please',
9 | validate: notEmpty('name')
10 | },
11 | {
12 | type: 'checkbox',
13 | name: 'blocks',
14 | message: 'Blocks:',
15 | choices: [{
16 | name: '',
17 | value: 'template',
18 | checked: true
19 | },
20 | {
21 | name: '
38 |
39 |
42 |
--------------------------------------------------------------------------------
/pkg/ui/mock/index.js:
--------------------------------------------------------------------------------
1 | import Mock from 'mockjs'
2 | import { param2Obj } from '../src/utils'
3 |
4 |
5 | const mocks = [
6 | ]
7 |
8 | // for v1 mock
9 | // please use it cautiously, it will redefine XMLHttpRequest,
10 | // which will cause many of your third-party libraries to be invalidated(like progress event).
11 | export function mockXHR() {
12 | // mock patch
13 | // https://github.com/nuysoft/Mock/issues/300
14 | Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
15 | Mock.XHR.prototype.send = function() {
16 | if (this.custom.xhr) {
17 | this.custom.xhr.withCredentials = this.withCredentials || false
18 |
19 | if (this.responseType) {
20 | this.custom.xhr.responseType = this.responseType
21 | }
22 | }
23 | this.proxy_send(...arguments)
24 | }
25 |
26 | function XHR2ExpressReqWrap(respond) {
27 | return function(options) {
28 | let result = null
29 | if (respond instanceof Function) {
30 | const { body, type, url } = options
31 | // https://expressjs.com/en/4x/api.html#req
32 | result = respond({
33 | method: type,
34 | body: JSON.parse(body),
35 | query: param2Obj(url)
36 | })
37 | } else {
38 | result = respond
39 | }
40 | return Mock.mock(result)
41 | }
42 | }
43 |
44 | for (const i of mocks) {
45 | Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response))
46 | }
47 | }
48 |
49 | export default mocks
50 |
--------------------------------------------------------------------------------
/pkg/api/admin/dao/comicCategory.go:
--------------------------------------------------------------------------------
1 | package dao
2 |
3 | import (
4 | "github.com/jinzhu/gorm"
5 | "lime/pkg/api/admin/dto"
6 | "lime/pkg/api/admin/model"
7 | "lime/pkg/common/db"
8 | )
9 |
10 | type ComicCategoryDao struct {
11 | }
12 |
13 | func (c ComicCategoryDao) Get(id int) model.ComicCategory {
14 | var Category model.ComicCategory
15 | db := db.GetGormDB()
16 | db.Where("id = ?", id).First(&Category)
17 | return Category
18 | }
19 |
20 | func (c ComicCategoryDao) GetAll() []model.ComicCategory {
21 | var Category []model.ComicCategory
22 | db := db.GetGormDB()
23 | db.Model(&model.ComicCategory{}).Find(&Category)
24 | return Category
25 | }
26 |
27 | func (c ComicCategoryDao) List(listDto dto.ComicCategoryListDto) ([]model.ComicCategory, int64) {
28 | var Category []model.ComicCategory
29 | var total int64
30 | db := db.GetGormDB()
31 | db.Offset(listDto.Skip).Limit(listDto.Limit).Find(&Category)
32 | db.Model(&model.ComicCategory{}).Count(&total)
33 | return Category, total
34 | }
35 |
36 | func (c ComicCategoryDao) Create(Category *model.ComicCategory) *gorm.DB {
37 | db := db.GetGormDB()
38 | return db.Save(Category)
39 | }
40 |
41 | // Update
42 | func (c ComicCategoryDao) Update(Category *model.ComicCategory, ups map[string]interface{}) *gorm.DB {
43 | db := db.GetGormDB()
44 | return db.Model(Category).Update(ups)
45 | }
46 |
47 | func (c ComicCategoryDao) Delete(Category *model.ComicCategory) *gorm.DB {
48 | db := db.GetGormDB()
49 | return db.Delete(Category)
50 | }
51 |
--------------------------------------------------------------------------------
/pkg/down/site/site_chromedp.go:
--------------------------------------------------------------------------------
1 | package site
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "github.com/chromedp/chromedp"
7 | "lime/pkg/down/store"
8 | "log"
9 | "net/url"
10 | "strings"
11 | )
12 |
13 | func ChromedpBookInfo(BookURL string, logfile string) (s *store.Store, err error) {
14 |
15 | ms, err := MatchOne(Sitepool, BookURL)
16 | if err != nil {
17 | return nil, err
18 | }
19 |
20 | var (
21 | // BookName string
22 | // Author string
23 | html string
24 | u *url.URL
25 | )
26 |
27 | u, _ = url.Parse(BookURL)
28 |
29 | tasks := chromedp.Tasks{
30 | chromedp.Navigate(BookURL),
31 | // chromedp.Text(`html`, &html, chromedp.ByQuery),
32 | chromedp.OuterHTML(`html`, &html, chromedp.ByQuery),
33 | // chromedp.WaitVisible(`html`, chromedp.ByQuery),
34 | }
35 |
36 | // create chrome instance
37 | ctx, cancel := chromedp.NewContext(context.Background())
38 | defer cancel()
39 |
40 | if err := chromedp.Run(ctx, tasks...); err != nil {
41 | log.Fatal(err)
42 | }
43 |
44 | chapter, err := ms.BookInfo(strings.NewReader(html))
45 | if err != nil {
46 | return nil, err
47 | }
48 |
49 | for v1, k1 := range chapter.Volumes {
50 | for v2, k2 := range k1.Chapters {
51 | u1, _ := url.Parse(k2.URL)
52 | chapter.Volumes[v1].Chapters[v2].URL = u.ResolveReference(u1).String()
53 | }
54 | }
55 |
56 | if len(chapter.Volumes) == 0 {
57 | // fmt.Printf(content)
58 | return nil, fmt.Errorf("not match volumes")
59 | }
60 |
61 | return chapter, nil
62 | }
63 |
--------------------------------------------------------------------------------
/pkg/api/front/dto/init.go:
--------------------------------------------------------------------------------
1 | package dto
2 |
3 | import (
4 | "fmt"
5 | "github.com/gin-gonic/gin"
6 | "github.com/gin-gonic/gin/binding"
7 | "github.com/go-playground/validator/v10"
8 | "github.com/pkg/errors"
9 | log "github.com/sirupsen/logrus"
10 | "strings"
11 | )
12 |
13 | func init() {
14 | // Register custom validate methods
15 | if v, ok := binding.Validator.Engine().(*validator.Validate);ok {
16 | _ = v.RegisterValidation("pwdValidate", pwdValidate)
17 | } else {
18 | log.Fatal("Gin fail to registered custom validator(v10)")
19 | }
20 | }
21 |
22 | // Bind : bind request dto and auto verify parameters
23 | func Bind(c *gin.Context, obj interface{}) error {
24 | _ = c.ShouldBindUri(obj)
25 | if err := c.ShouldBind(obj); err != nil {
26 | if fieldErr, ok := err.(validator.ValidationErrors); ok {
27 | var tagErrorMsg []string
28 | for _, v := range fieldErr {
29 | if _, has := ValidateErrorMessage[v.Tag()]; has {
30 | tagErrorMsg = append(tagErrorMsg, fmt.Sprintf(ValidateErrorMessage[v.Tag()], v.Field(), v.Value()))
31 | } else {
32 | tagErrorMsg = append(tagErrorMsg, err.Error())
33 | }
34 | }
35 | return errors.New(strings.Join(tagErrorMsg, ","))
36 | }
37 | }
38 | return nil
39 | }
40 |
41 | //ValidateErrorMessage : customize error messages
42 | var ValidateErrorMessage = map[string]string{
43 | "customValidate": "%s can not be %s",
44 | "required": "%s is required,got empty %#v",
45 | "pwdValidate": "%s is not a valid password",
46 | }
47 |
--------------------------------------------------------------------------------
/pkg/ui/src/components/ImageCropper/utils/effectRipple.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 点击波纹效果
3 | *
4 | * @param {[event]} e [description]
5 | * @param {[Object]} arg_opts [description]
6 | * @return {[bollean]} [description]
7 | */
8 | export default function(e, arg_opts) {
9 | var opts = Object.assign({
10 | ele: e.target, // 波纹作用元素
11 | type: 'hit', // hit点击位置扩散center中心点扩展
12 | bgc: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
13 | }, arg_opts)
14 | var target = opts.ele
15 | if (target) {
16 | var rect = target.getBoundingClientRect()
17 | var ripple = target.querySelector('.e-ripple')
18 | if (!ripple) {
19 | ripple = document.createElement('span')
20 | ripple.className = 'e-ripple'
21 | ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px'
22 | target.appendChild(ripple)
23 | } else {
24 | ripple.className = 'e-ripple'
25 | }
26 | switch (opts.type) {
27 | case 'center':
28 | ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px'
29 | ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px'
30 | break
31 | default:
32 | ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.body.scrollTop) + 'px'
33 | ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.body.scrollLeft) + 'px'
34 | }
35 | ripple.style.backgroundColor = opts.bgc
36 | ripple.className = 'e-ripple z-active'
37 | return false
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/pkg/api/admin/service/comicComments.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | log "github.com/sirupsen/logrus"
5 | "lime/pkg/api/admin/dao"
6 | "lime/pkg/api/admin/dto"
7 | "lime/pkg/api/admin/model"
8 | "time"
9 | )
10 |
11 | var ComicCommentDao = dao.ComicCommentDao{}
12 |
13 | // Service
14 | type ComicCommentervice struct {
15 | }
16 |
17 | // InfoOfId
18 | func (cs ComicCommentervice) InfoOfId(dto dto.GeneralGetDto) model.ComicComments {
19 | return ComicCommentDao.Get(dto.Id)
20 | }
21 |
22 | func (cs ComicCommentervice) GetAll() []model.ComicComments {
23 | return ComicCommentDao.GetAll()
24 | }
25 |
26 | // List
27 | func (cs ComicCommentervice) List(dto dto.ComicCommentListDto) ([]model.ComicComments, int64) {
28 | return ComicCommentDao.List(dto)
29 | }
30 |
31 | // Create
32 | func (cs ComicCommentervice) Create(dto dto.ComicCommentCreateDto) (model.ComicComments, error) {
33 | ComicCommentModel := model.ComicComments{
34 | Comic_id: dto.Comic_id,
35 | Username: dto.Username,
36 | Content: dto.Content,
37 | Source: dto.Source,
38 | CreatedAt: time.Now(),
39 | UpdatedAt: time.Now(),
40 | }
41 | c := ComicCommentDao.Create(&ComicCommentModel)
42 | if c.Error != nil {
43 | log.Error(c.Error.Error())
44 | }
45 | return ComicCommentModel, nil
46 | }
47 |
48 | //Delete
49 | func (cs ComicCommentervice) Delete(dto dto.GeneralDelDto) int64 {
50 | ComicCommentModel := model.ComicComments{
51 | Id: dto.Id,
52 | }
53 | c := ComicCommentDao.Delete(&ComicCommentModel)
54 | return c.RowsAffected
55 | }
56 |
--------------------------------------------------------------------------------
/pkg/h5/build/check-versions.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const chalk = require('chalk')
3 | const semver = require('semver')
4 | const packageConfig = require('../package.json')
5 | const shell = require('shelljs')
6 |
7 | function exec (cmd) {
8 | return require('child_process').execSync(cmd).toString().trim()
9 | }
10 |
11 | const versionRequirements = [
12 | {
13 | name: 'node',
14 | currentVersion: semver.clean(process.version),
15 | versionRequirement: packageConfig.engines.node
16 | }
17 | ]
18 |
19 | if (shell.which('npm')) {
20 | versionRequirements.push({
21 | name: 'npm',
22 | currentVersion: exec('npm --version'),
23 | versionRequirement: packageConfig.engines.npm
24 | })
25 | }
26 |
27 | module.exports = function () {
28 | const warnings = []
29 |
30 | for (let i = 0; i < versionRequirements.length; i++) {
31 | const mod = versionRequirements[i]
32 |
33 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
34 | warnings.push(mod.name + ': ' +
35 | chalk.red(mod.currentVersion) + ' should be ' +
36 | chalk.green(mod.versionRequirement)
37 | )
38 | }
39 | }
40 |
41 | if (warnings.length) {
42 | console.log('')
43 | console.log(chalk.yellow('To use this template, you must update following to modules:'))
44 | console.log()
45 |
46 | for (let i = 0; i < warnings.length; i++) {
47 | const warning = warnings[i]
48 | console.log(' ' + warning)
49 | }
50 |
51 | console.log()
52 | process.exit(1)
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/pkg/ui/src/styles/element-ui.scss:
--------------------------------------------------------------------------------
1 | // cover some element-ui styles
2 |
3 | .el-breadcrumb__inner,
4 | .el-breadcrumb__inner a {
5 | font-weight: 400 !important;
6 | }
7 |
8 | .el-upload {
9 | input[type="file"] {
10 | display: none !important;
11 | }
12 | }
13 |
14 | .el-upload__input {
15 | display: none;
16 | }
17 |
18 | .cell {
19 | .el-tag {
20 | margin-right: 0px;
21 | }
22 | }
23 |
24 | .small-padding {
25 | .cell {
26 | padding-left: 5px;
27 | padding-right: 5px;
28 | }
29 | }
30 |
31 | .fixed-width {
32 | .el-button--mini {
33 | padding: 7px 10px;
34 | min-width: 60px;
35 | }
36 | }
37 |
38 | .status-col {
39 | .cell {
40 | padding: 0 10px;
41 | text-align: center;
42 |
43 | .el-tag {
44 | margin-right: 0px;
45 | }
46 | }
47 | }
48 |
49 | // to fixed https://github.com/ElemeFE/element/issues/2461
50 | .el-dialog {
51 | transform: none;
52 | left: 0;
53 | position: relative;
54 | margin: 0 auto;
55 | }
56 |
57 | // refine element ui upload
58 | .upload-container {
59 | .el-upload {
60 | width: 100%;
61 |
62 | .el-upload-dragger {
63 | width: 100%;
64 | height: 200px;
65 | }
66 | }
67 | }
68 |
69 | // dropdown
70 | .el-dropdown-menu {
71 | a {
72 | display: block
73 | }
74 | }
75 |
76 | // fix date-picker ui bug in filter-item
77 | .el-range-editor.el-input__inner {
78 | display: inline-flex !important;
79 | }
80 |
81 | // to fix el-date-picker css style
82 | .el-range-separator {
83 | box-sizing: content-box;
84 | }
85 |
--------------------------------------------------------------------------------