Bladeren bron

首次导入

lincl 2 jaren geleden
commit
0d8d44992c
100 gewijzigde bestanden met toevoegingen van 3070 en 0 verwijderingen
  1. 14 0
      litemall-admin/.editorconfig
  2. 8 0
      litemall-admin/.env.deployment
  3. 14 0
      litemall-admin/.env.development
  4. 8 0
      litemall-admin/.env.production
  5. 4 0
      litemall-admin/.eslintignore
  6. 198 0
      litemall-admin/.eslintrc.js
  7. 23 0
      litemall-admin/.gitignore
  8. 5 0
      litemall-admin/babel.config.js
  9. 34 0
      litemall-admin/build/index.js
  10. 24 0
      litemall-admin/jest.config.js
  11. 9 0
      litemall-admin/jsconfig.json
  12. 103 0
      litemall-admin/package.json
  13. 5 0
      litemall-admin/postcss.config.js
  14. BIN
      litemall-admin/public/favicon.ico
  15. 16 0
      litemall-admin/public/index.html
  16. 230 0
      litemall-admin/public/tinymce4.7.5/langs/zh_CN.js
  17. 138 0
      litemall-admin/public/tinymce4.7.5/plugins/codesample/css/prism.css
  18. BIN
      litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-cool.gif
  19. BIN
      litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-cry.gif
  20. BIN
      litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-embarassed.gif
  21. BIN
      litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-foot-in-mouth.gif
  22. BIN
      litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-frown.gif
  23. BIN
      litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-innocent.gif
  24. BIN
      litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-kiss.gif
  25. BIN
      litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-laughing.gif
  26. BIN
      litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-money-mouth.gif
  27. BIN
      litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-sealed.gif
  28. BIN
      litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-smile.gif
  29. BIN
      litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-surprised.gif
  30. BIN
      litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-tongue-out.gif
  31. BIN
      litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-undecided.gif
  32. BIN
      litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-wink.gif
  33. BIN
      litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-yell.gif
  34. 154 0
      litemall-admin/public/tinymce4.7.5/plugins/visualblocks/css/visualblocks.css
  35. 1 0
      litemall-admin/public/tinymce4.7.5/skins/lightgray/content.inline.min.css
  36. 1 0
      litemall-admin/public/tinymce4.7.5/skins/lightgray/content.min.css
  37. BIN
      litemall-admin/public/tinymce4.7.5/skins/lightgray/fonts/tinymce-mobile.woff
  38. BIN
      litemall-admin/public/tinymce4.7.5/skins/lightgray/fonts/tinymce-small.eot
  39. 63 0
      litemall-admin/public/tinymce4.7.5/skins/lightgray/fonts/tinymce-small.svg
  40. BIN
      litemall-admin/public/tinymce4.7.5/skins/lightgray/fonts/tinymce-small.ttf
  41. BIN
      litemall-admin/public/tinymce4.7.5/skins/lightgray/fonts/tinymce-small.woff
  42. BIN
      litemall-admin/public/tinymce4.7.5/skins/lightgray/fonts/tinymce.eot
  43. 131 0
      litemall-admin/public/tinymce4.7.5/skins/lightgray/fonts/tinymce.svg
  44. BIN
      litemall-admin/public/tinymce4.7.5/skins/lightgray/fonts/tinymce.ttf
  45. BIN
      litemall-admin/public/tinymce4.7.5/skins/lightgray/fonts/tinymce.woff
  46. BIN
      litemall-admin/public/tinymce4.7.5/skins/lightgray/img/anchor.gif
  47. BIN
      litemall-admin/public/tinymce4.7.5/skins/lightgray/img/loader.gif
  48. BIN
      litemall-admin/public/tinymce4.7.5/skins/lightgray/img/object.gif
  49. BIN
      litemall-admin/public/tinymce4.7.5/skins/lightgray/img/trans.gif
  50. 1 0
      litemall-admin/public/tinymce4.7.5/skins/lightgray/skin.min.css
  51. 1 0
      litemall-admin/public/tinymce4.7.5/skins/lightgray/skin.min.css.map
  52. 2 0
      litemall-admin/public/tinymce4.7.5/tinymce.min.js
  53. 11 0
      litemall-admin/src/App.vue
  54. 41 0
      litemall-admin/src/api/ad.js
  55. 41 0
      litemall-admin/src/api/admin.js
  56. 49 0
      litemall-admin/src/api/aftersale.js
  57. 41 0
      litemall-admin/src/api/brand.js
  58. 48 0
      litemall-admin/src/api/category.js
  59. 17 0
      litemall-admin/src/api/comment.js
  60. 61 0
      litemall-admin/src/api/config.js
  61. 49 0
      litemall-admin/src/api/coupon.js
  62. 9 0
      litemall-admin/src/api/dashboard.js
  63. 48 0
      litemall-admin/src/api/goods.js
  64. 41 0
      litemall-admin/src/api/groupon.js
  65. 41 0
      litemall-admin/src/api/issue.js
  66. 41 0
      litemall-admin/src/api/keyword.js
  67. 9 0
      litemall-admin/src/api/log.js
  68. 36 0
      litemall-admin/src/api/login.js
  69. 49 0
      litemall-admin/src/api/notice.js
  70. 68 0
      litemall-admin/src/api/order.js
  71. 57 0
      litemall-admin/src/api/profile.js
  72. 16 0
      litemall-admin/src/api/region.js
  73. 65 0
      litemall-admin/src/api/role.js
  74. 25 0
      litemall-admin/src/api/stat.js
  75. 44 0
      litemall-admin/src/api/storage.js
  76. 49 0
      litemall-admin/src/api/topic.js
  77. 65 0
      litemall-admin/src/api/user.js
  78. BIN
      litemall-admin/src/assets/401_images/401.gif
  79. BIN
      litemall-admin/src/assets/404_images/404.png
  80. BIN
      litemall-admin/src/assets/404_images/404_cloud.png
  81. 116 0
      litemall-admin/src/components/BackToTop/index.vue
  82. 84 0
      litemall-admin/src/components/Breadcrumb/index.vue
  83. 59 0
      litemall-admin/src/components/Hamburger/index.vue
  84. 54 0
      litemall-admin/src/components/Notice/index.vue
  85. 99 0
      litemall-admin/src/components/Pagination/index.vue
  86. 55 0
      litemall-admin/src/components/Screenfull/index.vue
  87. 92 0
      litemall-admin/src/components/ScrollPane/index.vue
  88. 58 0
      litemall-admin/src/components/SizeSelect/index.vue
  89. 60 0
      litemall-admin/src/components/SvgIcon/index.vue
  90. 49 0
      litemall-admin/src/directive/clipboard/clipboard.js
  91. 13 0
      litemall-admin/src/directive/clipboard/index.js
  92. 13 0
      litemall-admin/src/directive/permission/index.js
  93. 29 0
      litemall-admin/src/directive/permission/permission.js
  94. 68 0
      litemall-admin/src/filters/index.js
  95. 9 0
      litemall-admin/src/icons/index.js
  96. 1 0
      litemall-admin/src/icons/svg/404.svg
  97. 1 0
      litemall-admin/src/icons/svg/bug.svg
  98. 1 0
      litemall-admin/src/icons/svg/chart.svg
  99. 1 0
      litemall-admin/src/icons/svg/clipboard.svg
  100. 0 0
      litemall-admin/src/icons/svg/component.svg

+ 14 - 0
litemall-admin/.editorconfig

@ -0,0 +1,14 @@
# https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false

+ 8 - 0
litemall-admin/.env.deployment

@ -0,0 +1,8 @@
NODE_ENV = production
# just a flag
ENV = 'deploymenet'
# base api
VUE_APP_BASE_API = 'http://122.51.199.160:8080/admin'

+ 14 - 0
litemall-admin/.env.development

@ -0,0 +1,14 @@
# just a flag
ENV = 'development'
# base api
VUE_APP_BASE_API = '/admin'
# vue-cli uses the VUE_CLI_BABEL_TRANSPILE_MODULES environment variable,
# to control whether the babel-plugin-dynamic-import-node plugin is enabled.
# It only does one thing by converting all import() to require().
# This configuration can significantly increase the speed of hot updates,
# when you have a large number of pages.
# Detail:  https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/babel-preset-app/index.js
VUE_CLI_BABEL_TRANSPILE_MODULES = true

+ 8 - 0
litemall-admin/.env.production

@ -0,0 +1,8 @@
NODE_ENV = production
# just a flag
ENV = 'production'
# base api
VUE_APP_BASE_API = 'https://www.cityihealth.com/litemall/admin'

+ 4 - 0
litemall-admin/.eslintignore

@ -0,0 +1,4 @@
build/*.js
src/assets
public
dist

+ 198 - 0
litemall-admin/.eslintrc.js

@ -0,0 +1,198 @@
module.exports = {
  root: true,
  parserOptions: {
    parser: 'babel-eslint',
    sourceType: 'module'
  },
  env: {
    browser: true,
    node: true,
    es6: true,
  },
  extends: ['plugin:vue/recommended', 'eslint:recommended'],
  // add your custom rules here
  //it is base on https://github.com/vuejs/eslint-config-vue
  rules: {
    "vue/max-attributes-per-line": [2, {
      "singleline": 10,
      "multiline": {
        "max": 1,
        "allowFirstLine": false
      }
    }],
    "vue/singleline-html-element-content-newline": "off",
    "vue/multiline-html-element-content-newline":"off",
    "vue/name-property-casing": ["error", "PascalCase"],
    "vue/no-v-html": "off",
    'accessor-pairs': 2,
    'arrow-spacing': [2, {
      'before': true,
      'after': true
    }],
    'block-spacing': [2, 'always'],
    'brace-style': [2, '1tbs', {
      'allowSingleLine': true
    }],
    'camelcase': [0, {
      'properties': 'always'
    }],
    'comma-dangle': [2, 'never'],
    'comma-spacing': [2, {
      'before': false,
      'after': true
    }],
    'comma-style': [2, 'last'],
    'constructor-super': 2,
    'curly': [2, 'multi-line'],
    'dot-location': [2, 'property'],
    'eol-last': 2,
    'eqeqeq': ["error", "always", {"null": "ignore"}],
    'generator-star-spacing': [2, {
      'before': true,
      'after': true
    }],
    'handle-callback-err': [2, '^(err|error)$'],
    'indent': [2, 2, {
      'SwitchCase': 1
    }],
    'jsx-quotes': [2, 'prefer-single'],
    'key-spacing': [2, {
      'beforeColon': false,
      'afterColon': true
    }],
    'keyword-spacing': [2, {
      'before': true,
      'after': true
    }],
    'new-cap': [2, {
      'newIsCap': true,
      'capIsNew': false
    }],
    'new-parens': 2,
    'no-array-constructor': 2,
    'no-caller': 2,
    'no-console': 'off',
    'no-class-assign': 2,
    'no-cond-assign': 2,
    'no-const-assign': 2,
    'no-control-regex': 0,
    'no-delete-var': 2,
    'no-dupe-args': 2,
    'no-dupe-class-members': 2,
    'no-dupe-keys': 2,
    'no-duplicate-case': 2,
    'no-empty-character-class': 2,
    'no-empty-pattern': 2,
    'no-eval': 2,
    'no-ex-assign': 2,
    'no-extend-native': 2,
    'no-extra-bind': 2,
    'no-extra-boolean-cast': 2,
    'no-extra-parens': [2, 'functions'],
    'no-fallthrough': 2,
    'no-floating-decimal': 2,
    'no-func-assign': 2,
    'no-implied-eval': 2,
    'no-inner-declarations': [2, 'functions'],
    'no-invalid-regexp': 2,
    'no-irregular-whitespace': 2,
    'no-iterator': 2,
    'no-label-var': 2,
    'no-labels': [2, {
      'allowLoop': false,
      'allowSwitch': false
    }],
    'no-lone-blocks': 2,
    'no-mixed-spaces-and-tabs': 2,
    'no-multi-spaces': 2,
    'no-multi-str': 2,
    'no-multiple-empty-lines': [2, {
      'max': 1
    }],
    'no-native-reassign': 2,
    'no-negated-in-lhs': 2,
    'no-new-object': 2,
    'no-new-require': 2,
    'no-new-symbol': 2,
    'no-new-wrappers': 2,
    'no-obj-calls': 2,
    'no-octal': 2,
    'no-octal-escape': 2,
    'no-path-concat': 2,
    'no-proto': 2,
    'no-redeclare': 2,
    'no-regex-spaces': 2,
    'no-return-assign': [2, 'except-parens'],
    'no-self-assign': 2,
    'no-self-compare': 2,
    'no-sequences': 2,
    'no-shadow-restricted-names': 2,
    'no-spaced-func': 2,
    'no-sparse-arrays': 2,
    'no-this-before-super': 2,
    'no-throw-literal': 2,
    'no-trailing-spaces': 2,
    'no-undef': 2,
    'no-undef-init': 2,
    'no-unexpected-multiline': 2,
    'no-unmodified-loop-condition': 2,
    'no-unneeded-ternary': [2, {
      'defaultAssignment': false
    }],
    'no-unreachable': 2,
    'no-unsafe-finally': 2,
    'no-unused-vars': [2, {
      'vars': 'all',
      'args': 'none'
    }],
    'no-useless-call': 2,
    'no-useless-computed-key': 2,
    'no-useless-constructor': 2,
    'no-useless-escape': 0,
    'no-whitespace-before-property': 2,
    'no-with': 2,
    'one-var': [2, {
      'initialized': 'never'
    }],
    'operator-linebreak': [2, 'after', {
      'overrides': {
        '?': 'before',
        ':': 'before'
      }
    }],
    'padded-blocks': [2, 'never'],
    'quotes': [2, 'single', {
      'avoidEscape': true,
      'allowTemplateLiterals': true
    }],
    'semi': [2, 'never'],
    'semi-spacing': [2, {
      'before': false,
      'after': true
    }],
    'space-before-blocks': [2, 'always'],
    'space-before-function-paren': [2, 'never'],
    'space-in-parens': [2, 'never'],
    'space-infix-ops': 2,
    'space-unary-ops': [2, {
      'words': true,
      'nonwords': false
    }],
    'spaced-comment': [2, 'always', {
      'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
    }],
    'template-curly-spacing': [2, 'never'],
    'use-isnan': 2,
    'valid-typeof': 2,
    'wrap-iife': [2, 'any'],
    'yield-star-spacing': [2, 'both'],
    'yoda': [2, 'never'],
    'prefer-const': 2,
    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
    'object-curly-spacing': [2, 'always', {
      objectsInObjects: false
    }],
    'array-bracket-spacing': [2, 'never']
  }
}

+ 23 - 0
litemall-admin/.gitignore

@ -0,0 +1,23 @@
.DS_Store
node_modules/
dist/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
**/*.log
tests/**/coverage/
tests/e2e/reports
selenium-debug.log
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.local
package-lock.json
yarn.lock

+ 5 - 0
litemall-admin/babel.config.js

@ -0,0 +1,5 @@
module.exports = {
  presets: [
    '@vue/app'
  ]
}

+ 34 - 0
litemall-admin/build/index.js

@ -0,0 +1,34 @@
const { run } = require('runjs')
const chalk = require('chalk')
const rawArgv = process.argv.slice(2)
const args = rawArgv.join(' ')
if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
  const report = rawArgv.includes('--report')
  run(`vue-cli-service build ${args}`)
  const port = 9526
  const publicPath = '/'
  var connect = require('connect')
  var serveStatic = require('serve-static')
  const app = connect()
  app.use(
    publicPath,
    serveStatic('./dist', {
      index: ['index.html', '/']
    })
  )
  app.listen(port, function () {
    console.log(chalk.green(`> Preview at  http://localhost:${port}${publicPath}`))
    if (report) {
      console.log(chalk.green(`> Report at  http://localhost:${port}${publicPath}report.html`))
    }
  })
} else {
  run(`vue-cli-service build ${args}`)
}

+ 24 - 0
litemall-admin/jest.config.js

@ -0,0 +1,24 @@
module.exports = {
  moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
  transform: {
    '^.+\\.vue$': 'vue-jest',
    '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
      'jest-transform-stub',
    '^.+\\.jsx?$': 'babel-jest'
  },
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1'
  },
  snapshotSerializers: ['jest-serializer-vue'],
  testMatch: [
    '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
  ],
  collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'],
  coverageDirectory: '<rootDir>/tests/unit/coverage',
  // 'collectCoverage': true,
  'coverageReporters': [
    'lcov',
    'text-summary'
  ],
  testURL: 'http://localhost/'
}

+ 9 - 0
litemall-admin/jsconfig.json

@ -0,0 +1,9 @@
{ 
  "compilerOptions": {
    "baseUrl": "./",
    "paths": {
        "@/*": ["src/*"]
    }
  },
  "exclude": ["node_modules", "dist"]
}

+ 103 - 0
litemall-admin/package.json

@ -0,0 +1,103 @@
{
  "name": "litemall-admin",
  "version": "1.0.0",
  "description": "litemall-admin basing on vue-element-admin 4.3.0",
  "author": "linlinjava <linlinjava@163.com>",
  "license": "MIT",
  "scripts": {
    "dev": "vue-cli-service serve",
    "build": "vue-cli-service build --mode production",
    "build:prod": "vue-cli-service build --mode production",
    "build:dep": "vue-cli-service build --mode deployment",
    "preview": "node build/index.js --preview",
    "lint": "eslint --ext .js,.vue src",
    "test:unit": "jest --clearCache && vue-cli-service test:unit",
    "test:ci": "npm run lint && npm run test:unit",
    "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml"
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "src/**/*.{js,vue}": [
      "eslint --fix",
      "git add"
    ]
  },
  "keywords": [
    "vue",
    "admin",
    "dashboard",
    "element-ui",
    "boilerplate",
    "admin-template",
    "management-system"
  ],
  "repository": {
    "type": "git",
    "url": "git+https://github.com/linlinjava/litemall.git"
  },
  "bugs": {
    "url": "https://github.com/linlinjava/litemall/issues"
  },
  "dependencies": {
    "@tinymce/tinymce-vue": "3.0.1",
    "lodash": "^4.17.11",
    "v-charts": "1.19.0",
    "axios": ">=0.21.2",
    "clipboard": "2.0.4",
    "connect": "3.6.6",
    "echarts": "4.2.1",
    "element-ui": "2.15.6",
    "file-saver": "1.3.8",
    "js-cookie": "2.2.0",
    "normalize.css": "7.0.0",
    "nprogress": "0.2.0",
    "path-to-regexp": "2.4.0",
    "screenfull": "4.2.0",
    "script-loader": "0.7.2",
    "vue": "2.6.10",
    "vue-count-to": "1.0.13",
    "vue-router": "3.0.2",
    "vuex": "3.1.0",
    "xlsx": ">=0.17.0"
  },
  "devDependencies": {
    "@babel/core": "7.0.0",
    "@babel/register": "7.0.0",
    "@vue/cli-plugin-babel": "4.4.4",
    "@vue/cli-plugin-eslint": "4.4.4",
    "@vue/cli-plugin-unit-jest": "4.4.4",
    "@vue/cli-service": "4.4.4",
    "autoprefixer": "9.5.1",
    "babel-eslint": "10.1.0",
    "babel-jest": "23.6.0",
    "babel-plugin-dynamic-import-node": "2.3.3",
    "chalk": "2.4.2",
    "chokidar": "2.1.5",
    "connect": "3.6.6",
    "eslint": "6.7.2",
    "eslint-plugin-vue": "6.2.2",
    "html-webpack-plugin": "3.2.0",
    "husky": "1.3.1",
    "lint-staged": "8.1.5",
    "sass": "1.26.2",
    "runjs": "4.3.2",
    "sass-loader": "8.0.2",
    "script-ext-html-webpack-plugin": "2.1.3",
    "serve-static": "1.13.2",
    "svg-sprite-loader": "4.1.3",
    "svgo": "1.2.0",
    "vue-template-compiler": "2.6.10"
  },
  "engines": {
    "node": ">=8.9",
    "npm": ">= 3.0.0"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions"
  ]
}

+ 5 - 0
litemall-admin/postcss.config.js

@ -0,0 +1,5 @@
module.exports = {
  plugins: {
    autoprefixer: {}
  }
}

BIN
litemall-admin/public/favicon.ico


+ 16 - 0
litemall-admin/public/index.html

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="renderer" content="webkit">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title><%= webpackConfig.name %></title>
  </head>
  <body>
    <script src=<%= BASE_URL %>/tinymce4.7.5/tinymce.min.js></script>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

+ 230 - 0
litemall-admin/public/tinymce4.7.5/langs/zh_CN.js

@ -0,0 +1,230 @@
tinymce.addI18n('zh_CN',{
"Cut": "\u526a\u5207",
"Heading 5": "\u6807\u98985",
"Header 2": "\u6807\u98982",
"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u4f60\u7684\u6d4f\u89c8\u5668\u4e0d\u652f\u6301\u5bf9\u526a\u8d34\u677f\u7684\u8bbf\u95ee\uff0c\u8bf7\u4f7f\u7528Ctrl+X\/C\/V\u952e\u8fdb\u884c\u590d\u5236\u7c98\u8d34\u3002",
"Heading 4": "\u6807\u98984",
"Div": "Div\u533a\u5757",
"Heading 2": "\u6807\u98982",
"Paste": "\u7c98\u8d34",
"Close": "\u5173\u95ed",
"Font Family": "\u5b57\u4f53",
"Pre": "\u9884\u683c\u5f0f\u6587\u672c",
"Align right": "\u53f3\u5bf9\u9f50",
"New document": "\u65b0\u6587\u6863",
"Blockquote": "\u5f15\u7528",
"Numbered list": "\u7f16\u53f7\u5217\u8868",
"Heading 1": "\u6807\u98981",
"Headings": "\u6807\u9898",
"Increase indent": "\u589e\u52a0\u7f29\u8fdb",
"Formats": "\u683c\u5f0f",
"Headers": "\u6807\u9898",
"Select all": "\u5168\u9009",
"Header 3": "\u6807\u98983",
"Blocks": "\u533a\u5757",
"Undo": "\u64a4\u6d88",
"Strikethrough": "\u5220\u9664\u7ebf",
"Bullet list": "\u9879\u76ee\u7b26\u53f7",
"Header 1": "\u6807\u98981",
"Superscript": "\u4e0a\u6807",
"Clear formatting": "\u6e05\u9664\u683c\u5f0f",
"Font Sizes": "\u5b57\u53f7",
"Subscript": "\u4e0b\u6807",
"Header 6": "\u6807\u98986",
"Redo": "\u91cd\u590d",
"Paragraph": "\u6bb5\u843d",
"Ok": "\u786e\u5b9a",
"Bold": "\u7c97\u4f53",
"Code": "\u4ee3\u7801",
"Italic": "\u659c\u4f53",
"Align center": "\u5c45\u4e2d",
"Header 5": "\u6807\u98985",
"Heading 6": "\u6807\u98986",
"Heading 3": "\u6807\u98983",
"Decrease indent": "\u51cf\u5c11\u7f29\u8fdb",
"Header 4": "\u6807\u98984",
"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\u5f53\u524d\u4e3a\u7eaf\u6587\u672c\u7c98\u8d34\u6a21\u5f0f\uff0c\u518d\u6b21\u70b9\u51fb\u53ef\u4ee5\u56de\u5230\u666e\u901a\u7c98\u8d34\u6a21\u5f0f\u3002",
"Underline": "\u4e0b\u5212\u7ebf",
"Cancel": "\u53d6\u6d88",
"Justify": "\u4e24\u7aef\u5bf9\u9f50",
"Inline": "\u6587\u672c",
"Copy": "\u590d\u5236",
"Align left": "\u5de6\u5bf9\u9f50",
"Visual aids": "\u7f51\u683c\u7ebf",
"Lower Greek": "\u5c0f\u5199\u5e0c\u814a\u5b57\u6bcd",
"Square": "\u65b9\u5757",
"Default": "\u9ed8\u8ba4",
"Lower Alpha": "\u5c0f\u5199\u82f1\u6587\u5b57\u6bcd",
"Circle": "\u7a7a\u5fc3\u5706",
"Disc": "\u5b9e\u5fc3\u5706",
"Upper Alpha": "\u5927\u5199\u82f1\u6587\u5b57\u6bcd",
"Upper Roman": "\u5927\u5199\u7f57\u9a6c\u5b57\u6bcd",
"Lower Roman": "\u5c0f\u5199\u7f57\u9a6c\u5b57\u6bcd",
"Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.": "\u6807\u8bc6\u7b26\u5e94\u8be5\u4ee5\u5b57\u6bcd\u5f00\u5934\uff0c\u540e\u8ddf\u5b57\u6bcd\u3001\u6570\u5b57\u3001\u7834\u6298\u53f7\u3001\u70b9\u3001\u5192\u53f7\u6216\u4e0b\u5212\u7ebf\u3002",
"Name": "\u540d\u79f0",
"Anchor": "\u951a\u70b9",
"Id": "\u6807\u8bc6\u7b26",
"You have unsaved changes are you sure you want to navigate away?": "\u4f60\u8fd8\u6709\u6587\u6863\u5c1a\u672a\u4fdd\u5b58\uff0c\u786e\u5b9a\u8981\u79bb\u5f00\uff1f",
"Restore last draft": "\u6062\u590d\u4e0a\u6b21\u7684\u8349\u7a3f",
"Special character": "\u7279\u6b8a\u7b26\u53f7",
"Source code": "\u6e90\u4ee3\u7801",
"Language": "\u8bed\u8a00",
"Insert\/Edit code sample": "\u63d2\u5165\/\u7f16\u8f91\u4ee3\u7801\u793a\u4f8b",
"B": "B",
"R": "R",
"G": "G",
"Color": "\u989c\u8272",
"Right to left": "\u4ece\u53f3\u5230\u5de6",
"Left to right": "\u4ece\u5de6\u5230\u53f3",
"Emoticons": "\u8868\u60c5",
"Robots": "\u673a\u5668\u4eba",
"Document properties": "\u6587\u6863\u5c5e\u6027",
"Title": "\u6807\u9898",
"Keywords": "\u5173\u952e\u8bcd",
"Encoding": "\u7f16\u7801",
"Description": "\u63cf\u8ff0",
"Author": "\u4f5c\u8005",
"Fullscreen": "\u5168\u5c4f",
"Horizontal line": "\u6c34\u5e73\u5206\u5272\u7ebf",
"Horizontal space": "\u6c34\u5e73\u8fb9\u8ddd",
"Insert\/edit image": "\u63d2\u5165\/\u7f16\u8f91\u56fe\u7247",
"General": "\u666e\u901a",
"Advanced": "\u9ad8\u7ea7",
"Source": "\u5730\u5740",
"Border": "\u8fb9\u6846",
"Constrain proportions": "\u4fdd\u6301\u7eb5\u6a2a\u6bd4",
"Vertical space": "\u5782\u76f4\u8fb9\u8ddd",
"Image description": "\u56fe\u7247\u63cf\u8ff0",
"Style": "\u6837\u5f0f",
"Dimensions": "\u5927\u5c0f",
"Insert image": "\u63d2\u5165\u56fe\u7247",
"Image": "\u56fe\u7247",
"Zoom in": "\u653e\u5927",
"Contrast": "\u5bf9\u6bd4\u5ea6",
"Back": "\u540e\u9000",
"Gamma": "\u4f3d\u9a6c\u503c",
"Flip horizontally": "\u6c34\u5e73\u7ffb\u8f6c",
"Resize": "\u8c03\u6574\u5927\u5c0f",
"Sharpen": "\u9510\u5316",
"Zoom out": "\u7f29\u5c0f",
"Image options": "\u56fe\u7247\u9009\u9879",
"Apply": "\u5e94\u7528",
"Brightness": "\u4eae\u5ea6",
"Rotate clockwise": "\u987a\u65f6\u9488\u65cb\u8f6c",
"Rotate counterclockwise": "\u9006\u65f6\u9488\u65cb\u8f6c",
"Edit image": "\u7f16\u8f91\u56fe\u7247",
"Color levels": "\u989c\u8272\u5c42\u6b21",
"Crop": "\u88c1\u526a",
"Orientation": "\u65b9\u5411",
"Flip vertically": "\u5782\u76f4\u7ffb\u8f6c",
"Invert": "\u53cd\u8f6c",
"Date\/time": "\u65e5\u671f\/\u65f6\u95f4",
"Insert date\/time": "\u63d2\u5165\u65e5\u671f\/\u65f6\u95f4",
"Remove link": "\u5220\u9664\u94fe\u63a5",
"Url": "\u5730\u5740",
"Text to display": "\u663e\u793a\u6587\u5b57",
"Anchors": "\u951a\u70b9",
"Insert link": "\u63d2\u5165\u94fe\u63a5",
"Link": "\u94fe\u63a5",
"New window": "\u5728\u65b0\u7a97\u53e3\u6253\u5f00",
"None": "\u65e0",
"The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u5c5e\u4e8e\u5916\u90e8\u94fe\u63a5\uff0c\u9700\u8981\u52a0\u4e0ahttp:\/\/:\u524d\u7f00\u5417\uff1f",
"Paste or type a link": "\u7c98\u8d34\u6216\u8f93\u5165\u94fe\u63a5",
"Target": "\u6253\u5f00\u65b9\u5f0f",
"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u4e3a\u90ae\u4ef6\u5730\u5740\uff0c\u9700\u8981\u52a0\u4e0amailto:\u524d\u7f00\u5417\uff1f",
"Insert\/edit link": "\u63d2\u5165\/\u7f16\u8f91\u94fe\u63a5",
"Insert\/edit video": "\u63d2\u5165\/\u7f16\u8f91\u89c6\u9891",
"Media": "\u5a92\u4f53",
"Alternative source": "\u955c\u50cf",
"Paste your embed code below:": "\u5c06\u5185\u5d4c\u4ee3\u7801\u7c98\u8d34\u5728\u4e0b\u9762:",
"Insert video": "\u63d2\u5165\u89c6\u9891",
"Poster": "\u5c01\u9762",
"Insert\/edit media": "\u63d2\u5165\/\u7f16\u8f91\u5a92\u4f53",
"Embed": "\u5185\u5d4c",
"Nonbreaking space": "\u4e0d\u95f4\u65ad\u7a7a\u683c",
"Page break": "\u5206\u9875\u7b26",
"Paste as text": "\u7c98\u8d34\u4e3a\u6587\u672c",
"Preview": "\u9884\u89c8",
"Print": "\u6253\u5370",
"Save": "\u4fdd\u5b58",
"Could not find the specified string.": "\u672a\u627e\u5230\u641c\u7d22\u5185\u5bb9.",
"Replace": "\u66ff\u6362",
"Next": "\u4e0b\u4e00\u4e2a",
"Whole words": "\u5168\u5b57\u5339\u914d",
"Find and replace": "\u67e5\u627e\u548c\u66ff\u6362",
"Replace with": "\u66ff\u6362\u4e3a",
"Find": "\u67e5\u627e",
"Replace all": "\u5168\u90e8\u66ff\u6362",
"Match case": "\u533a\u5206\u5927\u5c0f\u5199",
"Prev": "\u4e0a\u4e00\u4e2a",
"Spellcheck": "\u62fc\u5199\u68c0\u67e5",
"Finish": "\u5b8c\u6210",
"Ignore all": "\u5168\u90e8\u5ffd\u7565",
"Ignore": "\u5ffd\u7565",
"Add to Dictionary": "\u6dfb\u52a0\u5230\u5b57\u5178",
"Insert row before": "\u5728\u4e0a\u65b9\u63d2\u5165",
"Rows": "\u884c",
"Height": "\u9ad8",
"Paste row after": "\u7c98\u8d34\u5230\u4e0b\u65b9",
"Alignment": "\u5bf9\u9f50\u65b9\u5f0f",
"Border color": "\u8fb9\u6846\u989c\u8272",
"Column group": "\u5217\u7ec4",
"Row": "\u884c",
"Insert column before": "\u5728\u5de6\u4fa7\u63d2\u5165",
"Split cell": "\u62c6\u5206\u5355\u5143\u683c",
"Cell padding": "\u5355\u5143\u683c\u5185\u8fb9\u8ddd",
"Cell spacing": "\u5355\u5143\u683c\u5916\u95f4\u8ddd",
"Row type": "\u884c\u7c7b\u578b",
"Insert table": "\u63d2\u5165\u8868\u683c",
"Body": "\u8868\u4f53",
"Caption": "\u6807\u9898",
"Footer": "\u8868\u5c3e",
"Delete row": "\u5220\u9664\u884c",
"Paste row before": "\u7c98\u8d34\u5230\u4e0a\u65b9",
"Scope": "\u8303\u56f4",
"Delete table": "\u5220\u9664\u8868\u683c",
"H Align": "\u6c34\u5e73\u5bf9\u9f50",
"Top": "\u9876\u90e8\u5bf9\u9f50",
"Header cell": "\u8868\u5934\u5355\u5143\u683c",
"Column": "\u5217",
"Row group": "\u884c\u7ec4",
"Cell": "\u5355\u5143\u683c",
"Middle": "\u5782\u76f4\u5c45\u4e2d",
"Cell type": "\u5355\u5143\u683c\u7c7b\u578b",
"Copy row": "\u590d\u5236\u884c",
"Row properties": "\u884c\u5c5e\u6027",
"Table properties": "\u8868\u683c\u5c5e\u6027",
"Bottom": "\u5e95\u90e8\u5bf9\u9f50",
"V Align": "\u5782\u76f4\u5bf9\u9f50",
"Header": "\u8868\u5934",
"Right": "\u53f3\u5bf9\u9f50",
"Insert column after": "\u5728\u53f3\u4fa7\u63d2\u5165",
"Cols": "\u5217",
"Insert row after": "\u5728\u4e0b\u65b9\u63d2\u5165",
"Width": "\u5bbd",
"Cell properties": "\u5355\u5143\u683c\u5c5e\u6027",
"Left": "\u5de6\u5bf9\u9f50",
"Cut row": "\u526a\u5207\u884c",
"Delete column": "\u5220\u9664\u5217",
"Center": "\u5c45\u4e2d",
"Merge cells": "\u5408\u5e76\u5355\u5143\u683c",
"Insert template": "\u63d2\u5165\u6a21\u677f",
"Templates": "\u6a21\u677f",
"Background color": "\u80cc\u666f\u8272",
"Custom...": "\u81ea\u5b9a\u4e49...",
"Custom color": "\u81ea\u5b9a\u4e49\u989c\u8272",
"No color": "\u65e0",
"Text color": "\u6587\u5b57\u989c\u8272",
"Table of Contents": "\u5185\u5bb9\u5217\u8868",
"Show blocks": "\u663e\u793a\u533a\u5757\u8fb9\u6846",
"Show invisible characters": "\u663e\u793a\u4e0d\u53ef\u89c1\u5b57\u7b26",
"Words: {0}": "\u5b57\u6570\uff1a{0}",
"Insert": "\u63d2\u5165",
"File": "\u6587\u4ef6",
"Edit": "\u7f16\u8f91",
"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u5728\u7f16\u8f91\u533a\u6309ALT-F9\u6253\u5f00\u83dc\u5355\uff0c\u6309ALT-F10\u6253\u5f00\u5de5\u5177\u680f\uff0c\u6309ALT-0\u67e5\u770b\u5e2e\u52a9",
"Tools": "\u5de5\u5177",
"View": "\u89c6\u56fe",
"Table": "\u8868\u683c",
"Format": "\u683c\u5f0f"
});

+ 138 - 0
litemall-admin/public/tinymce4.7.5/plugins/codesample/css/prism.css

@ -0,0 +1,138 @@
/* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript */
/**
 * prism.js default theme for JavaScript, CSS and HTML
 * Based on dabblet (http://dabblet.com)
 * @author Lea Verou
 */
code[class*="language-"],
pre[class*="language-"] {
  color: black;
  text-shadow: 0 1px white;
  font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
  direction: ltr;
  text-align: left;
  white-space: pre;
  word-spacing: normal;
  word-break: normal;
  word-wrap: normal;
  line-height: 1.5;
  -moz-tab-size: 4;
  -o-tab-size: 4;
  tab-size: 4;
  -webkit-hyphens: none;
  -moz-hyphens: none;
  -ms-hyphens: none;
  hyphens: none;
}
pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
  text-shadow: none;
  background: #b3d4fc;
}
pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
code[class*="language-"]::selection, code[class*="language-"] ::selection {
  text-shadow: none;
  background: #b3d4fc;
}
@media print {
  code[class*="language-"],
  pre[class*="language-"] {
    text-shadow: none;
  }
}
/* Code blocks */
pre[class*="language-"] {
  padding: 1em;
  margin: .5em 0;
  overflow: auto;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
  background: #f5f2f0;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
  padding: .1em;
  border-radius: .3em;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
  color: slategray;
}
.token.punctuation {
  color: #999;
}
.namespace {
  opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
  color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
  color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
  color: #a67f59;
  background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
  color: #07a;
}
.token.function {
  color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
  color: #e90;
}
.token.important,
.token.bold {
  font-weight: bold;
}
.token.italic {
  font-style: italic;
}
.token.entity {
  cursor: help;
}

BIN
litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-cool.gif


BIN
litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-cry.gif


BIN
litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-embarassed.gif


BIN
litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-foot-in-mouth.gif


BIN
litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-frown.gif


BIN
litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-innocent.gif


BIN
litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-kiss.gif


BIN
litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-laughing.gif


BIN
litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-money-mouth.gif


BIN
litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-sealed.gif


BIN
litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-smile.gif


BIN
litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-surprised.gif


BIN
litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-tongue-out.gif


BIN
litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-undecided.gif


BIN
litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-wink.gif


BIN
litemall-admin/public/tinymce4.7.5/plugins/emoticons/img/smiley-yell.gif


+ 154 - 0
litemall-admin/public/tinymce4.7.5/plugins/visualblocks/css/visualblocks.css

@ -0,0 +1,154 @@
.mce-visualblocks p {
  padding-top: 10px;
  border: 1px dashed #BBB;
  margin-left: 3px;
  background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7);
  background-repeat: no-repeat;
}
.mce-visualblocks h1 {
  padding-top: 10px;
  border: 1px dashed #BBB;
  margin-left: 3px;
  background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==);
  background-repeat: no-repeat;
}
.mce-visualblocks h2 {
  padding-top: 10px;
  border: 1px dashed #BBB;
  margin-left: 3px;
  background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==);
  background-repeat: no-repeat;
}
.mce-visualblocks h3 {
  padding-top: 10px;
  border: 1px dashed #BBB;
  margin-left: 3px;
  background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7);
  background-repeat: no-repeat;
}
.mce-visualblocks h4 {
  padding-top: 10px;
  border: 1px dashed #BBB;
  margin-left: 3px;
  background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==);
  background-repeat: no-repeat;
}
.mce-visualblocks h5 {
  padding-top: 10px;
  border: 1px dashed #BBB;
  margin-left: 3px;
  background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==);
  background-repeat: no-repeat;
}
.mce-visualblocks h6 {
  padding-top: 10px;
  border: 1px dashed #BBB;
  margin-left: 3px;
  background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==);
  background-repeat: no-repeat;
}
.mce-visualblocks div:not([data-mce-bogus]) {
  padding-top: 10px;
  border: 1px dashed #BBB;
  margin-left: 3px;
  background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7);
  background-repeat: no-repeat;
}
.mce-visualblocks section {
  padding-top: 10px;
  border: 1px dashed #BBB;
  margin: 0 0 1em 3px;
  background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=);
  background-repeat: no-repeat;
}
.mce-visualblocks article {
  padding-top: 10px;
  border: 1px dashed #BBB;
  margin: 0 0 1em 3px;
  background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7);
  background-repeat: no-repeat;
}
.mce-visualblocks blockquote {
  padding-top: 10px;
  border: 1px dashed #BBB;
  background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7);
  background-repeat: no-repeat;
}
.mce-visualblocks address {
  padding-top: 10px;
  border: 1px dashed #BBB;
  margin: 0 0 1em 3px;
  background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=);
  background-repeat: no-repeat;
}
.mce-visualblocks pre {
  padding-top: 10px;
  border: 1px dashed #BBB;
  margin-left: 3px;
  background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==);
  background-repeat: no-repeat;
}
.mce-visualblocks figure {
  padding-top: 10px;
  border: 1px dashed #BBB;
  margin: 0 0 1em 3px;
  background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7);
  background-repeat: no-repeat;
}
.mce-visualblocks hgroup {
  padding-top: 10px;
  border: 1px dashed #BBB;
  margin: 0 0 1em 3px;
  background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7);
  background-repeat: no-repeat;
}
.mce-visualblocks aside {
  padding-top: 10px;
  border: 1px dashed #BBB;
  margin: 0 0 1em 3px;
  background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=);
  background-repeat: no-repeat;
}
.mce-visualblocks figcaption {
  border: 1px dashed #BBB;
}
.mce-visualblocks ul {
  padding-top: 10px;
  border: 1px dashed #BBB;
  margin: 0 0 1em 3px;
  background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==);
  background-repeat: no-repeat;
}
.mce-visualblocks ol {
  padding-top: 10px;
  border: 1px dashed #BBB;
  margin: 0 0 1em 3px;
  background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==);
  background-repeat: no-repeat;
}
.mce-visualblocks dl {
  padding-top: 10px;
  border: 1px dashed #BBB;
  margin: 0 0 1em 3px;
  background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==);
  background-repeat: no-repeat;
}

File diff suppressed because it is too large
+ 1 - 0
litemall-admin/public/tinymce4.7.5/skins/lightgray/content.inline.min.css


File diff suppressed because it is too large
+ 1 - 0
litemall-admin/public/tinymce4.7.5/skins/lightgray/content.min.css


BIN
litemall-admin/public/tinymce4.7.5/skins/lightgray/fonts/tinymce-mobile.woff


BIN
litemall-admin/public/tinymce4.7.5/skins/lightgray/fonts/tinymce-small.eot


File diff suppressed because it is too large
+ 63 - 0
litemall-admin/public/tinymce4.7.5/skins/lightgray/fonts/tinymce-small.svg


BIN
litemall-admin/public/tinymce4.7.5/skins/lightgray/fonts/tinymce-small.ttf


BIN
litemall-admin/public/tinymce4.7.5/skins/lightgray/fonts/tinymce-small.woff


BIN
litemall-admin/public/tinymce4.7.5/skins/lightgray/fonts/tinymce.eot


File diff suppressed because it is too large
+ 131 - 0
litemall-admin/public/tinymce4.7.5/skins/lightgray/fonts/tinymce.svg


BIN
litemall-admin/public/tinymce4.7.5/skins/lightgray/fonts/tinymce.ttf


BIN
litemall-admin/public/tinymce4.7.5/skins/lightgray/fonts/tinymce.woff


BIN
litemall-admin/public/tinymce4.7.5/skins/lightgray/img/anchor.gif


BIN
litemall-admin/public/tinymce4.7.5/skins/lightgray/img/loader.gif


BIN
litemall-admin/public/tinymce4.7.5/skins/lightgray/img/object.gif


BIN
litemall-admin/public/tinymce4.7.5/skins/lightgray/img/trans.gif


File diff suppressed because it is too large
+ 1 - 0
litemall-admin/public/tinymce4.7.5/skins/lightgray/skin.min.css


File diff suppressed because it is too large
+ 1 - 0
litemall-admin/public/tinymce4.7.5/skins/lightgray/skin.min.css.map


File diff suppressed because it is too large
+ 2 - 0
litemall-admin/public/tinymce4.7.5/tinymce.min.js


+ 11 - 0
litemall-admin/src/App.vue

@ -0,0 +1,11 @@
<template>
  <div id="app">
    <router-view/>
  </div>
</template>
<script>
export default{
  name: 'App'
}
</script>

+ 41 - 0
litemall-admin/src/api/ad.js

@ -0,0 +1,41 @@
import request from '@/utils/request'
export function listAd(query) {
  return request({
    url: '/ad/list',
    method: 'get',
    params: query
  })
}
export function createAd(data) {
  return request({
    url: '/ad/create',
    method: 'post',
    data
  })
}
export function readAd(data) {
  return request({
    url: '/ad/read',
    method: 'get',
    data
  })
}
export function updateAd(data) {
  return request({
    url: '/ad/update',
    method: 'post',
    data
  })
}
export function deleteAd(data) {
  return request({
    url: '/ad/delete',
    method: 'post',
    data
  })
}

+ 41 - 0
litemall-admin/src/api/admin.js

@ -0,0 +1,41 @@
import request from '@/utils/request'
export function listAdmin(query) {
  return request({
    url: '/admin/list',
    method: 'get',
    params: query
  })
}
export function createAdmin(data) {
  return request({
    url: '/admin/create',
    method: 'post',
    data
  })
}
export function readminAdmin(data) {
  return request({
    url: '/admin/readmin',
    method: 'get',
    data
  })
}
export function updateAdmin(data) {
  return request({
    url: '/admin/update',
    method: 'post',
    data
  })
}
export function deleteAdmin(data) {
  return request({
    url: '/admin/delete',
    method: 'post',
    data
  })
}

+ 49 - 0
litemall-admin/src/api/aftersale.js

@ -0,0 +1,49 @@
import request from '@/utils/request'
export function listAftersale(query) {
  return request({
    url: '/aftersale/list',
    method: 'get',
    params: query
  })
}
export function receptAftersale(data) {
  return request({
    url: '/aftersale/recept',
    method: 'post',
    data
  })
}
export function batchReceptAftersale(data) {
  return request({
    url: '/aftersale/batch-recept',
    method: 'post',
    data
  })
}
export function rejectAftersale(data) {
  return request({
    url: '/aftersale/reject',
    method: 'post',
    data
  })
}
export function batchRejectAftersale(data) {
  return request({
    url: '/aftersale/batch-reject',
    method: 'post',
    data
  })
}
export function refundAftersale(data) {
  return request({
    url: '/aftersale/refund',
    method: 'post',
    data
  })
}

+ 41 - 0
litemall-admin/src/api/brand.js

@ -0,0 +1,41 @@
import request from '@/utils/request'
export function listBrand(query) {
  return request({
    url: '/brand/list',
    method: 'get',
    params: query
  })
}
export function createBrand(data) {
  return request({
    url: '/brand/create',
    method: 'post',
    data
  })
}
export function readBrand(data) {
  return request({
    url: '/brand/read',
    method: 'get',
    data
  })
}
export function updateBrand(data) {
  return request({
    url: '/brand/update',
    method: 'post',
    data
  })
}
export function deleteBrand(data) {
  return request({
    url: '/brand/delete',
    method: 'post',
    data
  })
}

+ 48 - 0
litemall-admin/src/api/category.js

@ -0,0 +1,48 @@
import request from '@/utils/request'
export function listCategory(query) {
  return request({
    url: '/category/list',
    method: 'get',
    params: query
  })
}
export function listCatL1() {
  return request({
    url: '/category/l1',
    method: 'get'
  })
}
export function createCategory(data) {
  return request({
    url: '/category/create',
    method: 'post',
    data
  })
}
export function readCategory(data) {
  return request({
    url: '/category/read',
    method: 'get',
    data
  })
}
export function updateCategory(data) {
  return request({
    url: '/category/update',
    method: 'post',
    data
  })
}
export function deleteCategory(data) {
  return request({
    url: '/category/delete',
    method: 'post',
    data
  })
}

+ 17 - 0
litemall-admin/src/api/comment.js

@ -0,0 +1,17 @@
import request from '@/utils/request'
export function listComment(query) {
  return request({
    url: '/comment/list',
    method: 'get',
    params: query
  })
}
export function deleteComment(data) {
  return request({
    url: '/comment/delete',
    method: 'post',
    data
  })
}

+ 61 - 0
litemall-admin/src/api/config.js

@ -0,0 +1,61 @@
import request from '@/utils/request'
export function listMall() {
  return request({
    url: '/config/mall',
    method: 'get'
  })
}
export function updateMall(data) {
  return request({
    url: '/config/mall',
    method: 'post',
    data
  })
}
export function listExpress() {
  return request({
    url: '/config/express',
    method: 'get'
  })
}
export function updateExpress(data) {
  return request({
    url: '/config/express',
    method: 'post',
    data
  })
}
export function listOrder() {
  return request({
    url: '/config/order',
    method: 'get'
  })
}
export function updateOrder(data) {
  return request({
    url: '/config/order',
    method: 'post',
    data
  })
}
export function listWx() {
  return request({
    url: '/config/wx',
    method: 'get'
  })
}
export function updateWx(data) {
  return request({
    url: '/config/wx',
    method: 'post',
    data
  })
}

+ 49 - 0
litemall-admin/src/api/coupon.js

@ -0,0 +1,49 @@
import request from '@/utils/request'
export function listCoupon(query) {
  return request({
    url: '/coupon/list',
    method: 'get',
    params: query
  })
}
export function createCoupon(data) {
  return request({
    url: '/coupon/create',
    method: 'post',
    data
  })
}
export function readCoupon(id) {
  return request({
    url: '/coupon/read',
    method: 'get',
    params: { id }
  })
}
export function updateCoupon(data) {
  return request({
    url: '/coupon/update',
    method: 'post',
    data
  })
}
export function deleteCoupon(data) {
  return request({
    url: '/coupon/delete',
    method: 'post',
    data
  })
}
export function listCouponUser(query) {
  return request({
    url: '/coupon/listuser',
    method: 'get',
    params: query
  })
}

+ 9 - 0
litemall-admin/src/api/dashboard.js

@ -0,0 +1,9 @@
import request from '@/utils/request'
export function info(query) {
  return request({
    url: '/dashboard',
    method: 'get',
    params: query
  })
}

+ 48 - 0
litemall-admin/src/api/goods.js

@ -0,0 +1,48 @@
import request from '@/utils/request'
export function listGoods(query) {
  return request({
    url: '/goods/list',
    method: 'get',
    params: query
  })
}
export function deleteGoods(data) {
  return request({
    url: '/goods/delete',
    method: 'post',
    data
  })
}
export function publishGoods(data) {
  return request({
    url: '/goods/create',
    method: 'post',
    data
  })
}
export function detailGoods(id) {
  return request({
    url: '/goods/detail',
    method: 'get',
    params: { id }
  })
}
export function editGoods(data) {
  return request({
    url: '/goods/update',
    method: 'post',
    data
  })
}
export function listCatAndBrand() {
  return request({
    url: '/goods/catAndBrand',
    method: 'get'
  })
}

+ 41 - 0
litemall-admin/src/api/groupon.js

@ -0,0 +1,41 @@
import request from '@/utils/request'
export function listRecord(query) {
  return request({
    url: '/groupon/listRecord',
    method: 'get',
    params: query
  })
}
export function listGroupon(query) {
  return request({
    url: '/groupon/list',
    method: 'get',
    params: query
  })
}
export function deleteGroupon(data) {
  return request({
    url: '/groupon/delete',
    method: 'post',
    data
  })
}
export function publishGroupon(data) {
  return request({
    url: '/groupon/create',
    method: 'post',
    data
  })
}
export function editGroupon(data) {
  return request({
    url: '/groupon/update',
    method: 'post',
    data
  })
}

+ 41 - 0
litemall-admin/src/api/issue.js

@ -0,0 +1,41 @@
import request from '@/utils/request'
export function listIssue(query) {
  return request({
    url: '/issue/list',
    method: 'get',
    params: query
  })
}
export function createIssue(data) {
  return request({
    url: '/issue/create',
    method: 'post',
    data
  })
}
export function readIssue(data) {
  return request({
    url: '/issue/read',
    method: 'get',
    data
  })
}
export function updateIssue(data) {
  return request({
    url: '/issue/update',
    method: 'post',
    data
  })
}
export function deleteIssue(data) {
  return request({
    url: '/issue/delete',
    method: 'post',
    data
  })
}

+ 41 - 0
litemall-admin/src/api/keyword.js

@ -0,0 +1,41 @@
import request from '@/utils/request'
export function listKeyword(query) {
  return request({
    url: '/keyword/list',
    method: 'get',
    params: query
  })
}
export function createKeyword(data) {
  return request({
    url: '/keyword/create',
    method: 'post',
    data
  })
}
export function readKeyword(data) {
  return request({
    url: '/keyword/read',
    method: 'get',
    data
  })
}
export function updateKeyword(data) {
  return request({
    url: '/keyword/update',
    method: 'post',
    data
  })
}
export function deleteKeyword(data) {
  return request({
    url: '/keyword/delete',
    method: 'post',
    data
  })
}

+ 9 - 0
litemall-admin/src/api/log.js

@ -0,0 +1,9 @@
import request from '@/utils/request'
export function listLog(query) {
  return request({
    url: '/log/list',
    method: 'get',
    params: query
  })
}

+ 36 - 0
litemall-admin/src/api/login.js

@ -0,0 +1,36 @@
import request from '@/utils/request'
export function loginByUsername(username, password, code) {
  const data = {
    username,
    password,
    code
  }
  return request({
    url: '/auth/login',
    method: 'post',
    data
  })
}
export function logout() {
  return request({
    url: '/auth/logout',
    method: 'post'
  })
}
export function getUserInfo(token) {
  return request({
    url: '/auth/info',
    method: 'get',
    params: { token }
  })
}
export function getKaptcha() {
  return request({
    url: '/auth/kaptcha',
    method: 'get'
  })
}

+ 49 - 0
litemall-admin/src/api/notice.js

@ -0,0 +1,49 @@
import request from '@/utils/request'
export function listNotice(query) {
  return request({
    url: '/notice/list',
    method: 'get',
    params: query
  })
}
export function createNotice(data) {
  return request({
    url: '/notice/create',
    method: 'post',
    data
  })
}
export function readNotice(query) {
  return request({
    url: '/notice/read',
    method: 'get',
    params: query
  })
}
export function updateNotice(data) {
  return request({
    url: '/notice/update',
    method: 'post',
    data
  })
}
export function deleteNotice(data) {
  return request({
    url: '/notice/delete',
    method: 'post',
    data
  })
}
export function batchDeleteNotice(data) {
  return request({
    url: '/notice/batch-delete',
    method: 'post',
    data
  })
}

+ 68 - 0
litemall-admin/src/api/order.js

@ -0,0 +1,68 @@
import request from '@/utils/request'
import Qs from 'qs'
export function listOrder(query) {
  return request({
    url: '/order/list',
    method: 'get',
    params: query,
    paramsSerializer: function(params) {
      return Qs.stringify(params, { arrayFormat: 'repeat' })
    }
  })
}
export function detailOrder(id) {
  return request({
    url: '/order/detail',
    method: 'get',
    params: { id }
  })
}
export function shipOrder(data) {
  return request({
    url: '/order/ship',
    method: 'post',
    data
  })
}
export function refundOrder(data) {
  return request({
    url: '/order/refund',
    method: 'post',
    data
  })
}
export function payOrder(data) {
  return request({
    url: '/order/pay',
    method: 'post',
    data
  })
}
export function deleteOrder(data) {
  return request({
    url: '/order/delete',
    method: 'post',
    data
  })
}
export function replyComment(data) {
  return request({
    url: '/order/reply',
    method: 'post',
    data
  })
}
export function listChannel(id) {
  return request({
    url: '/order/channel',
    method: 'get'
  })
}

+ 57 - 0
litemall-admin/src/api/profile.js

@ -0,0 +1,57 @@
import request from '@/utils/request'
export function changePassword(data) {
  return request({
    url: '/profile/password',
    method: 'post',
    data
  })
}
export function nNotice() {
  return request({
    url: '/profile/nnotice',
    method: 'get'
  })
}
export function listNotice(query) {
  return request({
    url: '/profile/lsnotice',
    method: 'get',
    params: query
  })
}
export function catNotice(data) {
  return request({
    url: '/profile/catnotice',
    method: 'post',
    data
  })
}
export function bcatNotice(data) {
  return request({
    url: '/profile/bcatnotice',
    method: 'post',
    data
  })
}
export function rmotice(data) {
  return request({
    url: '/profile/rmnotice',
    method: 'post',
    data
  })
}
export function brmNotice(data) {
  return request({
    url: '/profile/brmnotice',
    method: 'post',
    data
  })
}

+ 16 - 0
litemall-admin/src/api/region.js

@ -0,0 +1,16 @@
import request from '@/utils/request'
export function listRegion() {
  return request({
    url: '/region/list',
    method: 'get'
  })
}
export function listSubRegion(query) {
  return request({
    url: '/region/clist',
    method: 'get',
    params: query
  })
}

+ 65 - 0
litemall-admin/src/api/role.js

@ -0,0 +1,65 @@
import request from '@/utils/request'
export function listRole(query) {
  return request({
    url: '/role/list',
    method: 'get',
    params: query
  })
}
export function createRole(data) {
  return request({
    url: '/role/create',
    method: 'post',
    data
  })
}
export function readRole(data) {
  return request({
    url: '/role/read',
    method: 'get',
    data
  })
}
export function updateRole(data) {
  return request({
    url: '/role/update',
    method: 'post',
    data
  })
}
export function deleteRole(data) {
  return request({
    url: '/role/delete',
    method: 'post',
    data
  })
}
export function getPermission(query) {
  return request({
    url: '/role/permissions',
    method: 'get',
    params: query
  })
}
export function updatePermission(data) {
  return request({
    url: '/role/permissions',
    method: 'post',
    data
  })
}
export function roleOptions(query) {
  return request({
    url: '/role/options',
    method: 'get',
    params: query
  })
}

+ 25 - 0
litemall-admin/src/api/stat.js

@ -0,0 +1,25 @@
import request from '@/utils/request'
export function statUser(query) {
  return request({
    url: '/stat/user',
    method: 'get',
    params: query
  })
}
export function statOrder(query) {
  return request({
    url: '/stat/order',
    method: 'get',
    params: query
  })
}
export function statGoods(query) {
  return request({
    url: '/stat/goods',
    method: 'get',
    params: query
  })
}

+ 44 - 0
litemall-admin/src/api/storage.js

@ -0,0 +1,44 @@
import request from '@/utils/request'
export function listStorage(query) {
  return request({
    url: '/storage/list',
    method: 'get',
    params: query
  })
}
export function createStorage(data) {
  return request({
    url: '/storage/create',
    method: 'post',
    data
  })
}
export function readStorage(data) {
  return request({
    url: '/storage/read',
    method: 'get',
    data
  })
}
export function updateStorage(data) {
  return request({
    url: '/storage/update',
    method: 'post',
    data
  })
}
export function deleteStorage(data) {
  return request({
    url: '/storage/delete',
    method: 'post',
    data
  })
}
const uploadPath = process.env.VUE_APP_BASE_API + '/storage/create'
export { uploadPath }

+ 49 - 0
litemall-admin/src/api/topic.js

@ -0,0 +1,49 @@
import request from '@/utils/request'
export function listTopic(query) {
  return request({
    url: '/topic/list',
    method: 'get',
    params: query
  })
}
export function createTopic(data) {
  return request({
    url: '/topic/create',
    method: 'post',
    data
  })
}
export function readTopic(query) {
  return request({
    url: '/topic/read',
    method: 'get',
    params: query
  })
}
export function updateTopic(data) {
  return request({
    url: '/topic/update',
    method: 'post',
    data
  })
}
export function deleteTopic(data) {
  return request({
    url: '/topic/delete',
    method: 'post',
    data
  })
}
export function batchDeleteTopic(data) {
  return request({
    url: '/topic/batch-delete',
    method: 'post',
    data
  })
}

+ 65 - 0
litemall-admin/src/api/user.js

@ -0,0 +1,65 @@
import request from '@/utils/request'
export function fetchList(query) {
  return request({
    url: '/user/list',
    method: 'get',
    params: query
  })
}
export function userDetail(id) {
  return request({
    url: '/user/detail',
    method: 'get',
    params: {id}
  })
}
export function updateUser(data) {
  return request({
    url: '/user/update',
    method: 'post',
    data
  })
}
export function listAddress(query) {
  return request({
    url: '/address/list',
    method: 'get',
    params: query
  })
}
export function listCollect(query) {
  return request({
    url: '/collect/list',
    method: 'get',
    params: query
  })
}
export function listFeedback(query) {
  return request({
    url: '/feedback/list',
    method: 'get',
    params: query
  })
}
export function listFootprint(query) {
  return request({
    url: '/footprint/list',
    method: 'get',
    params: query
  })
}
export function listHistory(query) {
  return request({
    url: '/history/list',
    method: 'get',
    params: query
  })
}

BIN
litemall-admin/src/assets/401_images/401.gif


BIN
litemall-admin/src/assets/404_images/404.png


BIN
litemall-admin/src/assets/404_images/404_cloud.png


+ 116 - 0
litemall-admin/src/components/BackToTop/index.vue

@ -0,0 +1,116 @@
<template>
  <transition :name="transitionName">
    <div v-show="visible" :style="customStyle" class="back-to-ceiling" @click="backToTop">
      <svg width="16" height="16" viewBox="0 0 17 17" xmlns="http://www.w3.org/2000/svg" class="Icon Icon--backToTopArrow" aria-hidden="true" style="height: 16px; width: 16px;">
        <title>回到顶部</title>
        <g>
          <path d="M12.036 15.59c0 .55-.453.995-.997.995H5.032c-.55 0-.997-.445-.997-.996V8.584H1.03c-1.1 0-1.36-.633-.578-1.416L7.33.29c.39-.39 1.026-.385 1.412 0l6.878 6.88c.782.78.523 1.415-.58 1.415h-3.004v7.004z" fill-rule="evenodd"/>
        </g>
      </svg>
    </div>
  </transition>
</template>
<script>
export default {
  name: 'BackToTop',
  props: {
    visibilityHeight: {
      type: Number,
      default: 400
    },
    backPosition: {
      type: Number,
      default: 0
    },
    customStyle: {
      type: Object,
      default: function() {
        return {
          right: '50px',
          bottom: '50px',
          width: '40px',
          height: '40px',
          'border-radius': '4px',
          'line-height': '45px',
          background: '#e7eaf1'
        }
      }
    },
    transitionName: {
      type: String,
      default: 'fade'
    }
  },
  data() {
    return {
      visible: false,
      interval: null,
      isMoving: false
    }
  },
  mounted() {
    window.addEventListener('scroll', this.handleScroll)
  },
  beforeDestroy() {
    window.removeEventListener('scroll', this.handleScroll)
    if (this.interval) {
      clearInterval(this.interval)
    }
  },
  methods: {
    handleScroll() {
      this.visible = window.pageYOffset > this.visibilityHeight
    },
    backToTop() {
      if (this.isMoving) return
      const start = window.pageYOffset
      let i = 0
      this.isMoving = true
      this.interval = setInterval(() => {
        const next = Math.floor(this.easeInOutQuad(10 * i, start, -start, 500))
        if (next <= this.backPosition) {
          window.scrollTo(0, this.backPosition)
          clearInterval(this.interval)
          this.isMoving = false
        } else {
          window.scrollTo(0, next)
        }
        i++
      }, 16.7)
    },
    easeInOutQuad(t, b, c, d) {
      if ((t /= d / 2) < 1) return c / 2 * t * t + b
      return -c / 2 * (--t * (t - 2) - 1) + b
    }
  }
}
</script>
<style scoped>
  .back-to-ceiling {
    position: fixed;
    display: inline-block;
    text-align: center;
    cursor: pointer;
  }
  .back-to-ceiling:hover {
    background: #d5dbe7;
  }
  .fade-enter-active,
  .fade-leave-active {
    transition: opacity .5s;
  }
  .fade-enter,
  .fade-leave-to {
    opacity: 0
  }
  .back-to-ceiling .Icon {
    fill: #9aaabf;
    background: none;
  }
</style>

+ 84 - 0
litemall-admin/src/components/Breadcrumb/index.vue

@ -0,0 +1,84 @@
<template>
  <el-breadcrumb class="app-breadcrumb" separator="/">
    <transition-group name="breadcrumb">
      <el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path">
        <span v-if="item.redirect === 'noredirect' || index == levelList.length - 1" class="no-redirect">{{ item.meta.title }}</span>
        <a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
      </el-breadcrumb-item>
    </transition-group>
  </el-breadcrumb>
</template>
<script>
import pathToRegexp from 'path-to-regexp'
export default {
  data() {
    return {
      levelList: null
    }
  },
  watch: {
    $route(route) {
      // if you go to the redirect page, do not update the breadcrumbs
      if (route.path.startsWith('/redirect/')) {
        return
      }
      this.getBreadcrumb()
    }
  },
  created() {
    this.getBreadcrumb()
  },
  methods: {
    getBreadcrumb() {
      // only show routes with meta.title
      let matched = this.$route.matched.filter(
        item => item.meta && item.meta.title
      )
      const first = matched[0]
      if (!this.isDashboard(first)) {
        matched = [{ path: '/dashboard', meta: { title: '首页' }}].concat(matched)
      }
      this.levelList = matched.filter(
        item => item.meta && item.meta.title && item.meta.breadcrumb !== false
      )
    },
    isDashboard(route) {
      const name = route && route.name
      if (!name) {
        return false
      }
      return (
        name.trim().toLocaleLowerCase() === 'Dashboard'.toLocaleLowerCase())
    },
    pathCompile(path) {
      // To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
      const { params } = this.$route
      var toPath = pathToRegexp.compile(path)
      return toPath(params)
    },
    handleLink(item) {
      const { redirect, path } = item
      if (redirect) {
        this.$router.push(redirect)
        return
      }
      this.$router.push(this.pathCompile(path))
    }
  }
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.app-breadcrumb.el-breadcrumb {
  display: inline-block;
  font-size: 14px;
  line-height: 50px;
  margin-left: 10px;
  .no-redirect {
    color: #97a8be;
    cursor: text;
  }
}
</style>

+ 59 - 0
litemall-admin/src/components/Hamburger/index.vue

@ -0,0 +1,59 @@
<template>
  <div>
    <svg
      :class="{'is-active':isActive}"
      t="1492500959545"
      class="hamburger"
      style=""
      viewBox="0 0 1024 1024"
      version="1.1"
      xmlns="http://www.w3.org/2000/svg"
      p-id="1691"
      xmlns:xlink="http://www.w3.org/1999/xlink"
      width="64"
      height="64"
      @click="toggleClick">
      <path
        d="M966.8023 568.849776 57.196677 568.849776c-31.397081 0-56.850799-25.452695-56.850799-56.850799l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 543.397081 998.200404 568.849776 966.8023 568.849776z"
        p-id="1692"/>
      <path
        d="M966.8023 881.527125 57.196677 881.527125c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 856.07443 998.200404 881.527125 966.8023 881.527125z"
        p-id="1693"/>
      <path
        d="M966.8023 256.17345 57.196677 256.17345c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 0c0-31.397081 25.452695-56.850799 56.850799-56.850799l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.850799l0 0C1023.653099 230.720755 998.200404 256.17345 966.8023 256.17345z"
        p-id="1694"/>
    </svg>
  </div>
</template>
<script>
export default {
  name: 'Hamburger',
  props: {
    isActive: {
      type: Boolean,
      default: false
    },
    toggleClick: {
      type: Function,
      default: null
    }
  }
}
</script>
<style scoped>
.hamburger {
  display: inline-block;
  cursor: pointer;
  width: 20px;
  height: 20px;
  transform: rotate(90deg);
  transition: .38s;
  transform-origin: 50% 50%;
}
.hamburger.is-active {
  transform: rotate(0deg);
}
</style>

+ 54 - 0
litemall-admin/src/components/Notice/index.vue

@ -0,0 +1,54 @@
<template>
  <div>
    <el-badge :is-dot="hasNotice">
      <i class="el-icon-bell" @click="click" />
    </el-badge>
  </div>
</template>
<script>
import { nNotice } from '@/api/profile'
export default {
  data() {
    return {
      hasNotice: false,
      timer: ''
    }
  },
  mounted() {
    this.timer = setInterval(this.checkNotice, 30 * 1000)
  },
  beforeDestroy() {
    clearInterval(this.timer)
  },
  created() {
    this.checkNotice()
  },
  methods: {
    click() {
      this.$router.push({ path: '/profile/notice' })
    },
    checkNotice() {
      if (this.hasNotice) {
        return
      }
      nNotice().then(response => {
        this.hasNotice = response.data.data > 0
      })
    }
  }
}
</script>
<style lang="scss" scoped>
::v-deep .el-badge__content.is-fixed.is-dot {
  right: 5px;
  top: 10px;
}
.el-icon-bell {
  font-size: 20px;
  cursor: pointer;
}
</style>

+ 99 - 0
litemall-admin/src/components/Pagination/index.vue

@ -0,0 +1,99 @@
<template>
  <div :class="{'hidden':hidden}" class="pagination-container">
    <el-pagination
      :background="background"
      :current-page.sync="currentPage"
      :page-size.sync="pageSize"
      :layout="layout"
      :total="total"
      v-bind="$attrs"
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"/>
  </div>
</template>
<script>
import { scrollTo } from '@/utils/scrollTo'
export default {
  name: 'Pagination',
  props: {
    total: {
      required: true,
      type: Number
    },
    page: {
      type: Number,
      default: 1
    },
    limit: {
      type: Number,
      default: 20
    },
    pageSizes: {
      type: Array,
      default() {
        return [10, 20, 30, 50]
      }
    },
    layout: {
      type: String,
      default: 'total, sizes, prev, pager, next, jumper'
    },
    background: {
      type: Boolean,
      default: true
    },
    autoScroll: {
      type: Boolean,
      default: true
    },
    hidden: {
      type: Boolean,
      default: false
    }
  },
  computed: {
    currentPage: {
      get() {
        return this.page
      },
      set(val) {
        this.$emit('update:page', val)
      }
    },
    pageSize: {
      get() {
        return this.limit
      },
      set(val) {
        this.$emit('update:limit', val)
      }
    }
  },
  methods: {
    handleSizeChange(val) {
      this.$emit('pagination', { page: this.currentPage, limit: val })
      if (this.autoScroll) {
        scrollTo(0, 800)
      }
    },
    handleCurrentChange(val) {
      this.$emit('pagination', { page: val, limit: this.pageSize })
      if (this.autoScroll) {
        scrollTo(0, 800)
      }
    }
  }
}
</script>
<style scoped>
.pagination-container {
  background: #fff;
  padding: 32px 16px;
}
.pagination-container.hidden {
  display: none;
}
</style>

+ 55 - 0
litemall-admin/src/components/Screenfull/index.vue

@ -0,0 +1,55 @@
<template>
  <div>
    <i class="el-icon-full-screen" @click="click" />
  </div>
</template>
<script>
import screenfull from 'screenfull'
export default {
  name: 'Screenfull',
  props: {
    width: {
      type: Number,
      default: 22
    },
    height: {
      type: Number,
      default: 22
    },
    fill: {
      type: String,
      default: '#48576a'
    }
  },
  data() {
    return {
      isFullscreen: false
    }
  },
  methods: {
    click() {
      if (!screenfull.enabled) {
        this.$message({
          message: '浏览器不支持全屏',
          type: 'warning'
        })
        return false
      }
      screenfull.toggle()
    }
  }
}
</script>
<style scoped>
.el-icon-full-screen {
  display: inline-block;
  cursor: pointer;
  fill: #5a5e66;;
  width: 20px;
  height: 20px;
  font-size: 20px;
}
</style>

+ 92 - 0
litemall-admin/src/components/ScrollPane/index.vue

@ -0,0 +1,92 @@
<template>
  <el-scrollbar ref="scrollContainer" :vertical="false" class="scroll-container" @wheel.native.prevent="handleScroll">
    <slot />
  </el-scrollbar>
</template>
<script>
const tagAndTagSpacing = 4 // tagAndTagSpacing
export default {
  name: 'ScrollPane',
  data() {
    return {
      left: 0
    }
  },
  methods: {
    handleScroll(e) {
      const eventDelta = e.wheelDelta || -e.deltaY * 40
      const $scrollWrapper = this.$refs.scrollContainer.$refs.wrap
      $scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
    },
    moveToTarget(currentTag) {
      const $container = this.$refs.scrollContainer.$el
      const $containerWidth = $container.offsetWidth
      const $scrollWrapper = this.$refs.scrollContainer.$refs.wrap
      const tagList = this.$parent.$refs.tag
      let firstTag = null
      let lastTag = null
      let prevTag = null
      let nextTag = null
      // find first tag and last tag
      if (tagList.length > 0) {
        firstTag = tagList[0]
        lastTag = tagList[tagList.length - 1]
      }
      // find preTag and nextTag
      for (let i = 0; i < tagList.length; i++) {
        if (tagList[i] === currentTag) {
          if (i === 0) {
            nextTag = tagList[i].length > 1 && tagList[i + 1]
          } else if (i === tagList.length - 1) {
            prevTag = tagList[i].length > 1 && tagList[i - 1]
          } else {
            prevTag = tagList[i - 1]
            nextTag = tagList[i + 1]
          }
          break
        }
      }
      if (firstTag === currentTag) {
        $scrollWrapper.scrollLeft = 0
      } else if (lastTag === currentTag) {
        $scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth
      } else {
        // the tag's offsetLeft after of nextTag
        const afterNextTagOffsetLeft = nextTag.$el.offsetLeft + nextTag.$el.offsetWidth + tagAndTagSpacing
        // the tag's offsetLeft before of prevTag
        const beforePrevTagOffsetLeft = prevTag.$el.offsetLeft - tagAndTagSpacing
        if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) {
          $scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth
        } else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) {
          $scrollWrapper.scrollLeft = beforePrevTagOffsetLeft
        }
      }
    }
  }
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.scroll-container {
  white-space: nowrap;
  position: relative;
  overflow: hidden;
  width: 100%;
  ::v-deep {
    .el-scrollbar__bar {
      bottom: 0px;
    }
    .el-scrollbar__wrap {
      height: 49px;
    }
  }
}
</style>

+ 58 - 0
litemall-admin/src/components/SizeSelect/index.vue

@ -0,0 +1,58 @@
<template>
  <el-dropdown trigger="click" @command="handleSetSize">
    <div>
      <i class="el-icon-rank" />
    </div>
    <el-dropdown-menu slot="dropdown">
      <el-dropdown-item :disabled="size==='medium'" command="medium">Medium</el-dropdown-item>
      <el-dropdown-item :disabled="size==='small'" command="small">Small</el-dropdown-item>
      <el-dropdown-item :disabled="size==='mini'" command="mini">Mini</el-dropdown-item>
    </el-dropdown-menu>
  </el-dropdown>
</template>
<script>
export default {
  computed: {
    size() {
      return this.$store.getters.size
    }
  },
  methods: {
    handleSetSize(size) {
      this.$ELEMENT.size = size
      this.$store.dispatch('setSize', size)
      this.refreshView()
      this.$message({
        message: '布局尺寸切换成功',
        type: 'success'
      })
    },
    refreshView() {
      // In order to make the cached page re-rendered
      this.$store.dispatch('delAllCachedViews', this.$route)
      const { fullPath } = this.$route
      this.$nextTick(() => {
        this.$router.replace({
          path: '/redirect' + fullPath
        })
      })
    }
  }
}
</script>
<style scoped>
.el-icon-rank {
  display: inline-block;
  cursor: pointer;
  fill: #5a5e66;;
  width: 20px;
  height: 20px;
  font-size: 20px;
}
</style>

+ 60 - 0
litemall-admin/src/components/SvgIcon/index.vue

@ -0,0 +1,60 @@
<template>
  <div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
  <svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
    <use :xlink:href="iconName" />
  </svg>
</template>
<script>
// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage
import { isExternal } from '@/utils/validate'
export default {
  name: 'SvgIcon',
  props: {
    iconClass: {
      type: String,
      required: true
    },
    className: {
      type: String,
      default: ''
    }
  },
  computed: {
    isExternal() {
      return isExternal(this.iconClass)
    },
    iconName() {
      return `#icon-${this.iconClass}`
    },
    svgClass() {
      if (this.className) {
        return 'svg-icon ' + this.className
      } else {
        return 'svg-icon'
      }
    },
    styleExternalIcon() {
      return {
        mask: `url(${this.iconClass}) no-repeat 50% 50%`,
        '-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
      }
    }
  }
}
</script>
<style scoped>
.svg-icon {
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
  fill: currentColor;
  overflow: hidden;
}
.svg-external-icon {
  background-color: currentColor;
  mask-size: cover!important;
  display: inline-block;
}
</style>

+ 49 - 0
litemall-admin/src/directive/clipboard/clipboard.js

@ -0,0 +1,49 @@
// Inspired by https://github.com/Inndy/vue-clipboard2
const Clipboard = require('clipboard')
if (!Clipboard) {
  throw new Error('you should npm install `clipboard` --save at first ')
}
export default {
  bind(el, binding) {
    if (binding.arg === 'success') {
      el._v_clipboard_success = binding.value
    } else if (binding.arg === 'error') {
      el._v_clipboard_error = binding.value
    } else {
      const clipboard = new Clipboard(el, {
        text() { return binding.value },
        action() { return binding.arg === 'cut' ? 'cut' : 'copy' }
      })
      clipboard.on('success', e => {
        const callback = el._v_clipboard_success
        callback && callback(e) // eslint-disable-line
      })
      clipboard.on('error', e => {
        const callback = el._v_clipboard_error
        callback && callback(e) // eslint-disable-line
      })
      el._v_clipboard = clipboard
    }
  },
  update(el, binding) {
    if (binding.arg === 'success') {
      el._v_clipboard_success = binding.value
    } else if (binding.arg === 'error') {
      el._v_clipboard_error = binding.value
    } else {
      el._v_clipboard.text = function() { return binding.value }
      el._v_clipboard.action = function() { return binding.arg === 'cut' ? 'cut' : 'copy' }
    }
  },
  unbind(el, binding) {
    if (binding.arg === 'success') {
      delete el._v_clipboard_success
    } else if (binding.arg === 'error') {
      delete el._v_clipboard_error
    } else {
      el._v_clipboard.destroy()
      delete el._v_clipboard
    }
  }
}

+ 13 - 0
litemall-admin/src/directive/clipboard/index.js

@ -0,0 +1,13 @@
import Clipboard from './clipboard'
const install = function(Vue) {
  Vue.directive('Clipboard', Clipboard)
}
if (window.Vue) {
  window.clipboard = Clipboard
  Vue.use(install); // eslint-disable-line
}
Clipboard.install = install
export default Clipboard

+ 13 - 0
litemall-admin/src/directive/permission/index.js

@ -0,0 +1,13 @@
import permission from './permission'
const install = function(Vue) {
  Vue.directive('permission', permission)
}
if (window.Vue) {
  window['permission'] = permission
  Vue.use(install); // eslint-disable-line
}
permission.install = install
export default permission

+ 29 - 0
litemall-admin/src/directive/permission/permission.js

@ -0,0 +1,29 @@
import store from '@/store'
export default{
  inserted(el, binding, vnode) {
    const { value } = binding
    const perms = store.getters && store.getters.perms
    if (value && value instanceof Array && value.length > 0) {
      const permissions = value
      var hasPermission = false
      if (perms.indexOf('*') >= 0) {
        hasPermission = true
      } else {
        hasPermission = perms.some(perm => {
          return permissions.includes(perm)
        })
      }
      if (!hasPermission) {
        el.parentNode && el.parentNode.removeChild(el)
      }
    } else {
      throw new Error(`need perms! Like v-permission="['GET /aaa','POST /bbb']"`)
    }
  }
}

+ 68 - 0
litemall-admin/src/filters/index.js

@ -0,0 +1,68 @@
// import parseTime, formatTime and set to filter
export { parseTime, formatTime } from '@/utils'
/**
 * Show plural label if time is plural number
 * @param {number} time
 * @param {string} label
 * @return {string}
 */
function pluralize(time, label) {
  if (time === 1) {
    return time + label
  }
  return time + label + 's'
}
/**
 * @param {number} time
 */
export function timeAgo(time) {
  const between = Date.now() / 1000 - Number(time)
  if (between < 3600) {
    return pluralize(~~(between / 60), ' minute')
  } else if (between < 86400) {
    return pluralize(~~(between / 3600), ' hour')
  } else {
    return pluralize(~~(between / 86400), ' day')
  }
}
/**
 * Number formatting
 * like 10000 => 10k
 * @param {number} num
 * @param {number} digits
 */
export function numberFormatter(num, digits) {
  const si = [
    { value: 1E18, symbol: 'E' },
    { value: 1E15, symbol: 'P' },
    { value: 1E12, symbol: 'T' },
    { value: 1E9, symbol: 'G' },
    { value: 1E6, symbol: 'M' },
    { value: 1E3, symbol: 'k' }
  ]
  for (let i = 0; i < si.length; i++) {
    if (num >= si[i].value) {
      return (num / si[i].value).toFixed(digits).replace(/\.0+$|(\.[0-9]*[1-9])0+$/, '$1') + si[i].symbol
    }
  }
  return num.toString()
}
/**
 * 10000 => "10,000"
 * @param {number} num
 */
export function toThousandFilter(num) {
  return (+num || 0).toString().replace(/^-?\d+/g, m => m.replace(/(?=(?!\b)(\d{3})+$)/g, ','))
}
/**
 * Upper case first char
 * @param {String} string
 */
export function uppercaseFirst(string) {
  return string.charAt(0).toUpperCase() + string.slice(1)
}

+ 9 - 0
litemall-admin/src/icons/index.js

@ -0,0 +1,9 @@
import Vue from 'vue'
import SvgIcon from '@/components/SvgIcon'// svg组件
// register globally
Vue.component('svg-icon', SvgIcon)
const req = require.context('./svg', false, /\.svg$/)
const requireAll = requireContext => requireContext.keys().map(requireContext)
requireAll(req)

File diff suppressed because it is too large
+ 1 - 0
litemall-admin/src/icons/svg/404.svg


File diff suppressed because it is too large
+ 1 - 0
litemall-admin/src/icons/svg/bug.svg


+ 1 - 0
litemall-admin/src/icons/svg/chart.svg

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M0 54.857h36.571V128H0V54.857zM91.429 27.43H128V128H91.429V27.429zM45.714 0h36.572v128H45.714V0z"/></svg>

File diff suppressed because it is too large
+ 1 - 0
litemall-admin/src/icons/svg/clipboard.svg


+ 0 - 0
litemall-admin/src/icons/svg/component.svg


Some files were not shown because too many files changed in this diff