浏览代码

2023.10.21
- 初始化项目

zweiqin 1 年之前
当前提交
0ff2894c65
共有 100 个文件被更改,包括 12766 次插入0 次删除
  1. 14 0
      .editorconfig
  2. 11 0
      .env.development
  3. 7 0
      .env.production
  4. 9 0
      .env.staging
  5. 6 0
      .eslintignore
  6. 1432 0
      .eslintrc.js
  7. 15 0
      .gitignore
  8. 5 0
      .travis.yml
  9. 2 0
      Dockerfile
  10. 21 0
      LICENSE
  11. 21 0
      README.md
  12. 14 0
      babel.config.js
  13. 35 0
      build/index.js
  14. 11 0
      canvas-container/App.vue
  15. 二进制
      canvas-container/assets/font/DIN-Bold.eot
  16. 二进制
      canvas-container/assets/font/DIN-Bold.otf
  17. 二进制
      canvas-container/assets/font/DIN-Bold.ttf
  18. 二进制
      canvas-container/assets/font/DIN-Bold.woff
  19. 二进制
      canvas-container/assets/font/DIN-Bold.woff2
  20. 539 0
      canvas-container/assets/font_icon/demo.css
  21. 2242 0
      canvas-container/assets/font_icon/demo_index.html
  22. 371 0
      canvas-container/assets/font_icon/iconfont.css
  23. 二进制
      canvas-container/assets/font_icon/iconfont.eot
  24. 0 0
      canvas-container/assets/font_icon/iconfont.js
  25. 632 0
      canvas-container/assets/font_icon/iconfont.json
  26. 28 0
      canvas-container/assets/font_icon/iconfont.svg
  27. 二进制
      canvas-container/assets/font_icon/iconfont.ttf
  28. 二进制
      canvas-container/assets/font_icon/iconfont.woff
  29. 二进制
      canvas-container/assets/font_icon/iconfont.woff2
  30. 365 0
      canvas-container/components/Upload/index.vue
  31. 366 0
      canvas-container/components/canvasEditPage.vue
  32. 24 0
      canvas-container/components/canvasShow/basics/assistDiv.vue
  33. 103 0
      canvas-container/components/canvasShow/basics/banner.vue
  34. 128 0
      canvas-container/components/canvasShow/basics/brandList.vue
  35. 116 0
      canvas-container/components/canvasShow/basics/categoryList.vue
  36. 88 0
      canvas-container/components/canvasShow/basics/coupon/app/index.vue
  37. 82 0
      canvas-container/components/canvasShow/basics/coupon/mixin.js
  38. 374 0
      canvas-container/components/canvasShow/basics/coupon/pc/index.vue
  39. 230 0
      canvas-container/components/canvasShow/basics/custom.vue
  40. 238 0
      canvas-container/components/canvasShow/basics/discount/app/index.vue
  41. 118 0
      canvas-container/components/canvasShow/basics/discount/mixin.js
  42. 247 0
      canvas-container/components/canvasShow/basics/discount/pc/index.vue
  43. 149 0
      canvas-container/components/canvasShow/basics/group/app/index.vue
  44. 94 0
      canvas-container/components/canvasShow/basics/group/mixin.js
  45. 250 0
      canvas-container/components/canvasShow/basics/group/pc/index.vue
  46. 104 0
      canvas-container/components/canvasShow/basics/header/app/index.vue
  47. 48 0
      canvas-container/components/canvasShow/basics/header/mixin.js
  48. 108 0
      canvas-container/components/canvasShow/basics/header/pc/index.vue
  49. 112 0
      canvas-container/components/canvasShow/basics/imageText.vue
  50. 134 0
      canvas-container/components/canvasShow/basics/imageTextList.vue
  51. 96 0
      canvas-container/components/canvasShow/basics/imageTextNav.vue
  52. 63 0
      canvas-container/components/canvasShow/basics/live/app/index.vue
  53. 280 0
      canvas-container/components/canvasShow/basics/live/app/item.vue
  54. 113 0
      canvas-container/components/canvasShow/basics/live/mixin.js
  55. 163 0
      canvas-container/components/canvasShow/basics/newProduct/app/index.vue
  56. 107 0
      canvas-container/components/canvasShow/basics/newProduct/mixin.js
  57. 112 0
      canvas-container/components/canvasShow/basics/notice.vue
  58. 178 0
      canvas-container/components/canvasShow/basics/price/app/index.vue
  59. 85 0
      canvas-container/components/canvasShow/basics/price/mixin.js
  60. 254 0
      canvas-container/components/canvasShow/basics/price/pc/index.vue
  61. 240 0
      canvas-container/components/canvasShow/basics/product/app/index.vue
  62. 105 0
      canvas-container/components/canvasShow/basics/product/mixin.js
  63. 226 0
      canvas-container/components/canvasShow/basics/product/pc/index.vue
  64. 113 0
      canvas-container/components/canvasShow/basics/shop.vue
  65. 155 0
      canvas-container/components/canvasShow/basics/spike/app/index.vue
  66. 152 0
      canvas-container/components/canvasShow/basics/spike/mixin.js
  67. 217 0
      canvas-container/components/canvasShow/basics/spike/pc/index.vue
  68. 79 0
      canvas-container/components/canvasShow/basics/text.vue
  69. 76 0
      canvas-container/components/canvasShow/basics/video.vue
  70. 211 0
      canvas-container/components/canvasShow/basics/vip/app/index.vue
  71. 56 0
      canvas-container/components/canvasShow/basics/vip/mixin.js
  72. 241 0
      canvas-container/components/canvasShow/basics/vip/pc/index.vue
  73. 109 0
      canvas-container/components/canvasShow/canvasShowPage.vue
  74. 102 0
      canvas-container/components/canvasShow/componentMap.js
  75. 31 0
      canvas-container/components/canvasShow/config/api.js
  76. 12 0
      canvas-container/components/canvasShow/config/config.js
  77. 144 0
      canvas-container/components/canvasShow/config/mixin/funMixin.js
  78. 9 0
      canvas-container/components/canvasShow/config/mixin/index.js
  79. 39 0
      canvas-container/components/canvasShow/config/mixin/sendReqMixin.js
  80. 105 0
      canvas-container/components/canvasShow/config/mixin/server.js
  81. 二进制
      canvas-container/components/canvasShow/static/images/btn-next.png
  82. 二进制
      canvas-container/components/canvasShow/static/images/btn-next2.png
  83. 二进制
      canvas-container/components/canvasShow/static/images/btn-prev.png
  84. 二进制
      canvas-container/components/canvasShow/static/images/btn-prev2.png
  85. 二进制
      canvas-container/components/canvasShow/static/images/coupon/bg-coupon.png
  86. 二进制
      canvas-container/components/canvasShow/static/images/coupon/bg-coupon2.png
  87. 二进制
      canvas-container/components/canvasShow/static/images/coupon/border_L1.png
  88. 0 0
      canvas-container/components/canvasShow/static/images/coupon/border_L2.png
  89. 0 0
      canvas-container/components/canvasShow/static/images/coupon/border_L3.png
  90. 0 0
      canvas-container/components/canvasShow/static/images/coupon/border_L4.png
  91. 0 0
      canvas-container/components/canvasShow/static/images/coupon/border_R1.png
  92. 0 0
      canvas-container/components/canvasShow/static/images/coupon/border_R2.png
  93. 0 0
      canvas-container/components/canvasShow/static/images/coupon/border_R3.png
  94. 0 0
      canvas-container/components/canvasShow/static/images/coupon/border_R4.png
  95. 二进制
      canvas-container/components/canvasShow/static/images/coupon/flag-coupon-r.png
  96. 二进制
      canvas-container/components/canvasShow/static/images/coupon/flag-coupon.png
  97. 二进制
      canvas-container/components/canvasShow/static/images/coupon/flag-coupon2-r.png
  98. 二进制
      canvas-container/components/canvasShow/static/images/coupon/flag-coupon2.png
  99. 二进制
      canvas-container/components/canvasShow/static/images/discount/bg-discount-more.png
  100. 二进制
      canvas-container/components/canvasShow/static/images/discount/bg-discount-top-text.png

+ 14 - 0
.editorconfig

@@ -0,0 +1,14 @@
+# http://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

+ 11 - 0
.env.development

@@ -0,0 +1,11 @@
+# just a flag
+ENV = 'development'
+
+# base api
+VUE_APP_BASE_API = '/dev-api'
+
+# 开发环境
+# VUE_APP_DOMAIN_PREFIX = 'http://192.168.0.91:9003'
+# 演示环境
+# VUE_APP_DOMAIN_PREFIX = 'http://192.168.0.91:9003'
+VUE_APP_DOMAIN_PREFIX = '/api'

+ 7 - 0
.env.production

@@ -0,0 +1,7 @@
+# just a flag
+ENV = 'production'
+
+# base api
+VUE_APP_BASE_API = '/prod-api'
+
+VUE_APP_DOMAIN_PREFIX = 'https://nsadminapi.tuanfengkeji.cn'

+ 9 - 0
.env.staging

@@ -0,0 +1,9 @@
+NODE_ENV = production
+
+# just a flag
+ENV = 'staging'
+
+# base api
+VUE_APP_BASE_API = '/stage-api'
+
+VUE_APP_DOMAIN_PREFIX = 'https://nsadminapi.tuanfengkeji.cn'

+ 6 - 0
.eslintignore

@@ -0,0 +1,6 @@
+build/*.js
+src/assets
+src/canvas-container
+canvas-container
+public
+dist

+ 1432 - 0
.eslintrc.js

@@ -0,0 +1,1432 @@
+module.exports = {
+  root: true, // 停止在父级目录中寻找(配置文件)
+  parserOptions: {
+    ecmaVersion: 10, // 可以使用 6、7、8、9 或 10 来指定你想要使用的 ECMAScript 版本
+    sourceType: 'module', // "script" (默认) 或 "module"(如果你的代码是 ECMAScript 模块)
+    // 表示你想使用的额外的语言特性
+    ecmaFeatures: {
+      globalReturn: false, // 允许在全局作用域下使用 return 语句
+      impliedStrict: false, // 启用全局 strict mode (如果 ecmaVersion 是 5 或更高)
+      jsx: true, // 启用 JSX
+      experimentalObjectRestSpread: false // 启用实验性的 object rest/spread properties 支持
+    },
+    // parser: 'esprima' // 建议在项目为uniapp项目时使用
+    parser: 'babel-eslint' // ESLint 默认使用"espree"(Espree)作为其解析器,你也可以在配置文件中指定一个不同的解析器,"esprima",Babel-ESLint('babel-eslint'是一款用于 ESLint 的语法分析器,它支持使用 ESLint 分析所有 babel 兼容的代码)或@typescript-eslint/parser。
+  },
+  // 在配置文件里配置插件时,可以使用 plugins 关键字来存放插件名字的列表。插件名称可以省略 eslint-plugin- 前缀。插件是相对于 ESLint 进程的当前工作目录解析的
+  // plugins: ['a-plugin'],
+  // processor: 'a-plugin/a-processor', // 插件可以提供处理器,指定处理器使用由插件名和处理器名组成的串接字符串加上斜杠
+  // 可以为特定类型的文件指定处理器
+  // overrides: [
+  // 	{
+  // 		files: ['*.md'],
+  // 		processor: 'a-plugin/markdown'
+  // 	}
+  // ],
+  // 可以禁用一组文件的配置文件中的规则
+  // overrides: [
+  // 	{
+  // 		files: ['*-test.js', '*.spec.js'],
+  // 		rules: {
+  // 			'no-unused-expressions': 'off'
+  // 		}
+  // 	}
+  // ],
+  // ESLint 支持在配置文件添加共享设置。可以添加 settings 对象到配置文件,它将提供给每一个将被执行的规则。
+  // settings: {
+  // 	sharedData: 'Hello'
+  // },
+  env: {
+    browser: true, // 浏览器环境中的全局变量
+    node: true, // Node.js 全局变量和 Node.js 作用域
+    es6: true // 启用除了 modules 以外的所有 ECMAScript 6 特性(该选项会自动设置 ecmaVersion 解析器选项为 6)
+    // commonjs: true, // CommonJS 全局变量和 CommonJS 作用域 (用于 Browserify/WebPack 打包的只在浏览器中运行的代码)
+    // 'shared-node-browser': true, // Node.js 和 Browser 通用全局变量
+    // worker: true, // Web Workers 全局变量
+    // amd: true, // 将 require() 和 define() 定义为像 amd 一样的全局变量
+    // mocha: true, // 添加所有的 Mocha 测试全局变量
+    // jasmine: true, // 添加所有的 Jasmine 版本 1.3 和 2.0 的测试全局变量
+    // jest: true, // Jest 全局变量
+    // phantomjs: true, // PhantomJS 全局变量
+    // protractor: true, // Protractor 全局变量
+    // qunit: true, // QUnit 全局变量
+    // jquery: true, // jQuery 全局变量
+    // prototypejs: true, // Prototype.js 全局变量
+    // shelljs: true, // ShellJS 全局变量
+    // meteor: true, // Meteor 全局变量
+    // mongo: true, // MongoDB 全局变量
+    // applescript: true, // AppleScript 全局变量
+    // nashorn: true, // Java 8 Nashorn 全局变量
+    // serviceworker: true, // Service Worker 全局变量
+    // atomtest: true, // Atom 测试全局变量
+    // embertest: true, // Ember 测试全局变量
+    // webextensions: true, // WebExtensions 全局变量
+    // greasemonkey: true // GreaseMonkey 全局变量
+  },
+  // 要在配置文件中配置全局变量,请将 globals 配置属性设置为一个对象,该对象包含以你希望使用的每个全局变量
+  globals: {
+    // var1: 'writable', // "writable" 允许重写变量,等价于旧值:布尔值 true 和字符串值 "writeable"
+    // var2: 'readonly', // "readonly" 不允许重写变量,等价于旧值:布尔值 false 和字符串值 "readable"
+    // Promise: 'off', // "off" 禁用全局变量
+    uni: 'writable',
+    UniApp: 'writable'
+  },
+  // extends 属性值可以是:指定配置的字符串(配置文件的路径、可共享配置的名称、eslint:recommended 或 eslint:all);字符串数组:每个配置继承它前面的配置。extends 属性值可以省略包名的前缀 eslint-config-。
+  // extends 属性值可以由以下组成:①plugin:②包名 (省略了前缀,比如,react)③/④配置名称 (比如 recommended)。"plugin:react/recommended"
+  extends: [
+    'plugin:vue/recommended', // 如果是特殊情况(被检验的文件的目录下没有eslint-plugin-vue包),则又由于node加载不到该配置文件目录下的eslint-plugin-vue包的原因,故这里应该去掉
+    'eslint:recommended'
+  ],
+  // add your custom rules here
+  // it is base on https://github.com/vuejs/eslint-config-vue;http://eslint.cn/docs/rules/;https://eslint.vuejs.org/rules/。
+  rules: {
+    // 配置定义在插件中的一个规则的时候,你必须使用 插件名/规则ID 的形式
+    // 关于'plugin:vue/recommended'的扩展:
+    // Base Rules
+    'vue/comment-directive': 'off',
+    'vue/jsx-uses-var': 'off',
+
+    // Priority A: Essential
+    'vue/multi-word-component-names': 'off', // 这个规则要求组件名总是由多个单词组成,除了根App组件,以及Vue提供的内置组件
+    'vue/no-arrow-functions-in-watch': 'error', // 该规则不允许在定义观察器时使用箭头函数。箭头函数绑定到它们的父上下文,这意味着它们不能通过this
+    'vue/no-async-in-computed-properties': 'error', // 在computed properties中禁用异步actions
+    'vue/no-child-content': 'error', // 不允许元素的子内容被指令覆盖,如v-html或者v-text.(对象)选项有"additionalDirectives"要检查的附加指令的数组,没有v-前缀。默认为空;v-html和v-text总是被检查。
+    'vue/no-computed-properties-in-data': 'error', // This rule disallow accessing computed properties in data(). The computed property cannot be accessed in data() because is before initialization.
+    'vue/no-dupe-keys': 'error', // 不允许重复的keys,该规则旨在防止重复的属性名称。(对象)选项有"groups" (string[]) Array of additional groups to search for duplicates. Default is empty.
+    'vue/no-dupe-v-else-if': 'error', // This rule disallows duplicate conditions in the same v-if / v-else-if chain.
+    'vue/no-duplicate-attributes': ['error', {
+      'allowCoexistClass': true,
+      'allowCoexistStyle': true
+    }], // allowCoexistClass (boolean),allowCoexistStyle (boolean) ... Enables v-bind:class/v-bind:style (opens new window)directive can coexist with the plain class/style attribute. Default is true.
+    'vue/no-export-in-script-setup': 'error', // Disallow export in <script setup>
+    'vue/no-mutating-props': 'error', // Disallow mutation of component props
+    'vue/no-parsing-error': ['error', {
+      'abrupt-closing-of-empty-comment': true,
+      'absence-of-digits-in-numeric-character-reference': true,
+      'cdata-in-html-content': true,
+      'character-reference-outside-unicode-range': true,
+      'control-character-in-input-stream': true,
+      'control-character-reference': true,
+      'eof-before-tag-name': true,
+      'eof-in-cdata': true,
+      'eof-in-comment': true,
+      'eof-in-tag': true,
+      'incorrectly-closed-comment': true,
+      'incorrectly-opened-comment': true,
+      'invalid-first-character-of-tag-name': true,
+      'missing-attribute-value': true,
+      'missing-end-tag-name': true,
+      'missing-semicolon-after-character-reference': true,
+      'missing-whitespace-between-attributes': true,
+      'nested-comment': true,
+      'noncharacter-character-reference': true,
+      'noncharacter-in-input-stream': true,
+      'null-character-reference': true,
+      'surrogate-character-reference': true,
+      'surrogate-in-input-stream': true,
+      'unexpected-character-in-attribute-name': true,
+      'unexpected-character-in-unquoted-attribute-value': true,
+      'unexpected-equals-sign-before-attribute-name': true,
+      'unexpected-null-character': true,
+      'unexpected-question-mark-instead-of-tag-name': true,
+      'unexpected-solidus-in-tag': true,
+      'unknown-named-character-reference': true,
+      'end-tag-with-attributes': true,
+      'duplicate-attribute': true,
+      'end-tag-with-trailing-solidus': true,
+      'non-void-html-element-start-tag-with-trailing-solidus': false, // 默认情况下是禁用的,因为Vue.js支持自结束标记。
+      'x-invalid-end-tag': true, // 启用关于尚未打开的元素的结束标记的错误。
+      'x-invalid-namespace': true// 启用关于无效的错误xmlns属性。
+    }], // 在 <template> 标签下不允许解析错误
+    'vue/no-ref-as-operand': 'error', // This rule reports cases where a ref is used incorrectly as an operand. You must use .value to access the Ref value.
+    'vue/no-reserved-component-names': 'error', // disallowVueBuiltInComponents/disallowVue3BuiltInComponents (boolean)...如果true,不允许Vue.js 2/3.x内置组件名。默认值为false.
+    'vue/no-reserved-keys': 'error', // 这条规则禁止使用保留名称 (打开新窗口)以避免冲突和意外行为,不允许覆盖保留关键字。(对象)选项有reserved (string[])内部附加受限属性的数组groups。默认值为空。groups (string[])要在其中搜索重复项的附加组名数组。默认值为空。
+    'vue/no-reserved-props': ['error', {
+      'vueVersion': 3
+    }], // vueVersion (2 | 3)...指定您正在使用的Vue版本。默认值为3
+    'vue/no-setup-props-destructure': 'error', // This rule reports the destructuring of props passed to setup causing the value to lose reactivity.析构props传递给setup会导致数值失去反应性。此外,在根范围内析构setup()应该出错,但在嵌套回调或返回的呈现函数中正常:
+    'vue/no-shared-component-data': 'error', // 将组件的data数据属性强制为函数(除了new Vue),即强制data必须是一个带返回值的函数。因为如果当data的值是一个对象,那它由组件的所有实例共享。
+    'vue/no-side-effects-in-computed-properties': 'warn', // 该规则旨在防止代码在计算属性和函数中产生副作用。不允许在computed properties中出现副作用。
+    'vue/no-template-key': 'error', // <template>不允许key属性。Vue.js disallows key attribute on <template> elements.This rule does not report keys placed on <template v-for>. It's valid for Vue.js 3.x(即在vue3中是合法的).
+    'vue/no-textarea-mustache': 'error', // Interpolation on textareas (<textarea>{{text}}</textarea>) won't work. Use v-model instead.
+    'vue/no-unused-components': 'warn', // 不允许注册模板中未使用的组件
+    'vue/no-unused-vars': 'warn', // 不允许在v-for或者范围内的属性出现未使用的变量定义。Disallow unused variable definitions of v-for directives or scope attributes。(对象)选项有ignorePattern当v-for指令或范围属性的定义与ignorePattern正则表达式匹配时,禁用报告。系统默认值null
+    'vue/no-use-computed-property-like-method': 'off', // Disallow use computed property like method
+    'vue/no-use-v-if-with-v-for': ['warn', {
+      'allowUsingIterationVar': false
+    }], // 该规则旨在防止使用v-for指令连同v-if指令。(对象)选项有allowUsingIterationVar (boolean) Enables The v-if directive use the reference which is to the variables which are defined by the v-for directives. Default is false.
+    'vue/no-v-text-v-html-on-component': 'off', // 不允许组件上的v-text / v-html
+    'vue/require-component-is': 'error', // <component>标签需要v-bind:is属性。Require v-bind:is of <component> elements。可以使用同一个挂载点,并使用保留的<component>元素并动态绑定到其is属性。
+    'vue/require-prop-type-constructor': 'error', // Require prop type to be a constructor。它将捕捉最常犯的错误,即使用字符串而不是构造函数。
+    'vue/require-render-return': 'error', // render 函数必须有一个返回值。Enforce render function to always return value
+    'vue/require-v-for-key': 'error', // 保证 v-bind:key 和 v-for 指令成对出现。Require v-bind:key with v-for directives
+    'vue/require-valid-default-prop': 'error', // 检查默认的prop值是否有效。Enforce props default values to be valid。 It should report an error when default value for type Array or Object is not returned using function.
+    'vue/return-in-computed-property': ['error', {
+      'treatUndefinedAsUnspecified': true
+    }], // 保证computed属性中有return语句。This rule enforces that a return statement is present in computed properties and functions.(对象)选项有"treatUndefinedAsUnspecified": true(默认值)不允许使用隐式返回未定义的return声明。
+    'vue/return-in-emits-validator': 'error', // 该规则强制要求return语句存在于emits验证器。
+    'vue/use-v-on-exact': 'error', // 当有另一个v-on时,此规则强制要求使用exact修饰语。
+    'vue/valid-attribute-name': 'error', // Require valid attribute names。This rule detects invalid HTML attributes.
+    'vue/valid-define-emits': 'error', // This rule checks whether defineEmits compiler macro is valid.
+    'vue/valid-define-props': 'error', // This rule checks whether defineProps compiler macro is valid.
+    'vue/valid-next-tick': 'error', // Enforce valid nextTick function calls。Calling Vue.nextTick or vm.$nextTick without passing a callback and without awaiting the returned Promise is likely a mistake (probably a missing await).
+    'vue/valid-template-root': 'error', // 强制校验 template 根节点。Enforce valid template root。This rule checks whether every template root is valid.
+    'vue/valid-v-bind': 'error', // 强制校验 v-bind 指令。Enforce valid v-bind directives
+    'vue/valid-v-cloak': 'error', // 强制校验 v-cloak 指令。强制校验 v-bind 指令。Enforce valid v-bind directives
+    'vue/valid-v-else-if': 'error', // 强制校验 v-else-if 指令。Enforce valid v-else-if directives
+    'vue/valid-v-else': 'error', // 强制校验 v-else 指令。Enforce valid v-else directives
+    'vue/valid-v-for': 'error', // 强制校验 v-for 指令。Enforce valid v-for directives
+    'vue/valid-v-html': 'error', // 强制校验 v-html 指令。Enforce valid v-html directives
+    'vue/valid-v-if': 'error', // 强制校验 v-if 指令。Enforce valid v-if directives
+    'vue/valid-v-model': 'error', // 强制校验 v-model 指令。Enforce valid v-model directives
+    'vue/valid-v-on': 'error', // 强制校验 v-on 指令。Enforce valid v-on directives
+    'vue/valid-v-once': 'error', // 强制校验 v-once 指令。Enforce valid v-once directives
+    'vue/valid-v-pre': 'error', // 强制校验 v-pre 指令。Enforce valid v-pre directives
+    'vue/valid-v-show': 'error', // 强制校验 v-show 指令。Enforce valid v-show directives
+    'vue/valid-v-slot': 'error', // 强制校验 v-slot 指令。Enforce valid v-slot directives。allowModifiers (boolean)允许在的参数中使用修饰符v-slot指令。紧随其后的修饰符v-slot仍然不被允许,默认值false.
+    'vue/valid-v-text': 'error', // 强制校验 v-text 指令。Enforce valid v-text directives
+
+    // Priority A: Essential for Vue.js 3.x
+    'vue/no-deprecated-data-object-declaration': 'error', // 不允许对data使用不推荐使用的对象声明,例如不推荐对象的形式
+    'vue/no-deprecated-destroyed-lifecycle': 'off', // Disallow using deprecated destroyed and beforeDestroy lifecycle hooks。而是使用beforeUnmount,unmounted
+    'vue/no-deprecated-dollar-listeners-api': 'error', // 不允许使用已弃用$listeners
+    'vue/no-deprecated-dollar-scopedslots-api': 'error', // 不允许使用已弃用$scopedSlots
+    'vue/no-deprecated-events-api': 'error', // Disallow using deprecated events api。This rule reports use of deprecated $on, $off $once api.(in Vue.js 3.0.0+).
+    'vue/no-deprecated-filter': 'error', // 不允许使用不推荐使用的过滤器语法
+    'vue/no-deprecated-functional-template': 'error', // 不允许使用已弃用的functional模板
+    'vue/no-deprecated-html-element-is': 'error', // Disallow using deprecated the is attribute on HTML elements
+    'vue/no-deprecated-inline-template': 'error', // 不允许使用已弃用inline-template属性
+    'vue/no-deprecated-props-default-this': 'error', // Disallow deprecated this access in props default function
+    'vue/no-deprecated-router-link-tag-prop': 'error', // Disallow using deprecated tag property on RouterLink
+    'vue/no-deprecated-scope-attribute': 'error', // Disallow deprecated scope attribute(in Vue.js 2.5.0+)
+    'vue/no-deprecated-slot-attribute': 'error', // Disallow deprecated slot attribute
+    'vue/no-deprecated-slot-scope-attribute': 'off', // Disallow deprecated slot-scope attribute
+    'vue/no-deprecated-v-bind-sync': 'off', // Disallow use of deprecated .sync modifier on v-bind directive。考虑到elementui的vue2.x版本的组件上使用.sync的情况
+    'vue/no-deprecated-v-is': 'off', // Disallow deprecated v-is directive
+    'vue/no-deprecated-v-on-native-modifier': 'off', // Disallow using deprecated .native modifiers
+    'vue/no-deprecated-v-on-number-modifiers': 'off', // Disallow using deprecated number (keycode) modifiers
+    'vue/no-deprecated-vue-config-keycodes': 'error', // Disallow using deprecated Vue.config.keyCodes
+    'vue/no-expose-after-await': 'error', // Disallow asynchronously registered expose。This rule reports usages of expose() and defineExpose() after an await expression.In the 'setup() function'/'<script setup>', expose()/defineExpose() should be registered synchronously.
+    'vue/no-lifecycle-after-await': 'error', // 不允许异步注册的生命周期挂钩。In setup() function, onXXX lifecycle hooks should be registered synchronously.
+    'vue/no-v-for-template-key-on-child': 'off', // Disallow key of <template v-for> placed on child elements。此规则针对Vue.js 3.x。如果您使用的是Vue.js 2.x,请启用vue/no-v-for-template-key。不要同时启用两个规则;它们是相互冲突的。
+    'vue/no-watch-after-await': 'error', // 不允许异步注册watch。In setup() function, watch() should be registered synchronously.但是,This rule is not reported when using the stop handle.
+    'vue/prefer-import-from-vue': 'error', // Enforce import from 'vue' instead of import from '@vue/*'
+    'vue/require-slots-as-functions': 'error', // Enforce properties of $slots to be used as a function。this.$slots.default在Vue.js 2.x中是一个VNode数组,但在Vue.js 3.x中更改为一个返回VNode数组的函数。
+    'vue/require-toggle-inside-transition': 'error', // Require control the display of the content inside <transition>。The element inside `<transition>` is expected to have a `v-if` or `v-show` directive.
+    'vue/valid-v-is': 'error', // Enforce valid v-is directives。
+    'vue/valid-v-memo': 'error', // Enforce valid v-memo directives。
+
+    // Priority A: Essential for Vue.js 2.x
+    'vue/no-custom-modifiers-on-v-model': 'error', // 不允许在组件上使用v-model上的自定义的修饰符,如<MyComponent v-model.aaa="foo" />
+    'vue/no-multiple-template-root': 'error', // 不允许向模板添加多个根节点
+    'vue/no-v-for-template-key': 'error', // Disallow key attribute on <template v-for>。在Vue.js 2.x中,不允许key属性在<template>元素上。此规则针对Vue.js 2.x。如果您使用的是Vue.js 3.x,请启用vue/no-v-for-template-key-on-child。不要同时启用两个规则;它们是相互冲突的。
+    'vue/no-v-model-argument': 'off', // 不允许向自定义组件的v-model上添加参数
+    'vue/valid-model-definition': 'error', // Require valid keys in model option
+    'vue/valid-v-bind-sync': 'error', // Enforce valid .sync modifier on v-bind directives
+
+    // Priority B: Strongly Recommended
+    'vue/attribute-hyphenation': ['error', 'always', {
+      'ignore': []
+    }], // 该规则强制在Vue模板中的自定义组件上使用带连字符的属性名称(短横线命名)。(字符串)选项"always"(默认)使用连字符名称,"never"除了被忽略的名字外,不要使用连字符的名字。(对象)选项"ignore"被忽略名称的数组
+    'vue/component-definition-name-casing': ['error', 'PascalCase'], // 对组件定义名称(name)强制使用特定的大小写。(字符串)选项有"PascalCase" (default)enforce component definition names to pascal case,"kebab-case" enforce component definition names to kebab case。旧版的是'vue/name-property-casing': 'off'。
+    'vue/first-attribute-linebreak': ['error', {
+      'singleline': 'ignore',
+      'multiline': 'below'
+    }], // 该规则旨在为第一个属性强制执行一致的位置。(对象)选项有singleline当属性在单行上时,第一个属性的位置,默认值为"ignore",其它"below"在第一个属性前需要换行符,"beside"不允许在第一个属性前换行;multiline当属性跨多行时,第一个属性的位置,默认值为"below".
+    'vue/html-closing-bracket-newline': ['error', {
+      'singleline': 'never',
+      'multiline': 'always'
+    }], // 此规则在标签的右括号前强制换行(或不换行)。(对象)选项有singleline,"never"(默认)/"always",单行元素的配置,如果元素没有属性或者最后一个属性与左括号在同一行,那么它就是一个单行元素。multiline多行元素的配置,"never"/"always"(默认),如果最后一个属性不在左括号的同一行,它就是一个多行元素。
+    'vue/html-closing-bracket-spacing': ['error', {
+      'startTag': 'never',
+      'endTag': 'never',
+      'selfClosingTag': 'always'
+    }], // 这条规则的目的是在标签结束括号之前强制执行一致的间距样式>。(对象)选项有startTag ("always" | "never")的设置>开始标签(例如<div>).默认值为"never",endTag ("always" | "never")的设置>结束标签(例如</div>).默认值为"never",selfClosingTag ("always" | "never")的设置/>自关闭标签(例如<div/>).默认值为"always".
+    'vue/html-end-tags': 'error', // Enforce end tag style
+    'vue/html-indent': ['error', 2, {
+      // 2对象attribute (integer)属性缩进的乘数,默认值为1;baseIndent (integer)顶级语句的缩进倍数,默认值为1,"const";closeBracket (integer | object)右括号缩进的倍数,默认值为0;alignAttributesVertically (boolean)多行情况下,属性是否应与第一个属性垂直对齐的条件,默认值为true;ignores (string[])忽略节点的选择器。
+      'attribute': 1,
+      'baseIndent': 1,
+      'closeBracket': 0,
+      'alignAttributesVertically': true,
+      'ignores': []
+    }], // 此规则强制在标签中使用一致的缩进样式,默认样式是两个空格。选项:1数字或字符串type (number | "tab")缩进的类型,默认值为2,如果这是一个数字,那就是一次缩进的空格数,如果这是"tab",它使用一个制表符对应一个缩进。
+    'vue/html-quotes': ['error', 'double', {
+      'avoidEscape': false
+    }], // 强制HTML属性的引号样式。1字符串选项:"double"(默认)...需要双引号。"single"...需要单引号。 2对象选项:avoidEscape如果true,允许字符串使用单引号或双引号,只要字符串包含否则必须转义的引号。
+    'vue/html-self-closing': ['error', {
+      'html': {
+        'void': 'any',
+        'normal': 'any',
+        'component': 'any'
+      },
+      'svg': 'always',
+      'math': 'always'
+    }], // 为没有内容的标签Enforce self-closing style。(对象)选项html.void ("never" by default)如<img>,html.normal ("always" by default)如<div />,html.component ("always" by default),svg("always" by default),math("always" by default)。每个选项都可以设置为下列值之一:"always","never","any"。
+    'vue/max-attributes-per-line': [
+      'error',
+      {
+        singleline: {
+          max: 8
+        },
+        multiline: {
+          max: 4
+        }
+      }
+    ], // 限制每行的最大属性数以提高可读性。(对象)选项singleline.max (number)当开始标记在单行中时,每行的最大属性数。默认值为1.这可以是{ singleline: 1 }代替{ singleline: { max: 1 }};multiline.max (number)当开始标记在多行中时,每行的最大属性数。默认值为1.这可以是{ multiline: 1 }代替{ multiline: { max: 1 }}。
+    'vue/multiline-html-element-content-newline': ['error', {
+      'ignoreWhenEmpty': true,
+      'ignores': ['pre', 'textarea'],
+      'allowEmptyLines': true
+    }], // 在多行元素的内容前后需要换行符。(对象)选项ignoreWhenEmpty当元素没有内容时禁用报告,系统默认值true;ignores元素名称忽略换行符样式的配置。系统默认值["pre", "textarea", ...INLINE_ELEMENTS];allowEmptyLines如果true,它允许内容周围有空行。系统默认值false。
+    'vue/mustache-interpolation-spacing': ['error', 'always'], // Enforce unified spacing in mustache interpolations。字符串选项"always"(默认)表达式和花括号之间应该有一个空格。"never"...表达式和花括号之间不要有空格。
+    'vue/no-multi-spaces': ['error', {
+      'ignoreProperties': false
+    }], // Disallow multiple spaces。(对象)选项有ignoreProperties,whether or not objects' properties should be ignored,default false。
+    'vue/no-spaces-around-equal-signs-in-attribute': 'error', // Disallow spaces around equal signs in attribute。HTML5 allows spaces around equal signs. But space-less is easier to read, and groups entities better together.
+    'vue/no-template-shadow': 'warn', // Disallow variable declarations from shadowing variables declared in the outer scope。no-template-shadow should report variable definitions of v-for directives or scope attributes if they shadow the variables in parent scopes.
+    'vue/one-component-per-file': 'off', // Enforce that each component should be in its own file。This rule checks if there is only one component per file。
+    'vue/prop-name-casing': ['error', 'camelCase'], // 对Vue组件中的props的属性名称强制使用特定的大小写。字符串选项有"camelCase" (default),"snake_case"。
+    'vue/require-default-prop': 'off', // Require default value for props。This rule requires default value to be set for each props that are not marked as required (except Boolean props).
+    'vue/require-prop-types': 'error', // Require type definitions in props。该规则强制要求props语句包含类型定义。
+    'vue/singleline-html-element-content-newline': 'off', // Require a line break before and after the contents of a singleline element。(对象)选项有ignoreWhenNoAttributes当给定元素没有属性时,允许在一行中包含内容,系统默认值true。ignoreWhenEmpty当元素没有内容时禁用报告,系统默认值true。ignores元素名称忽略换行符样式的配置,系统默认值["pre", "textarea", ...INLINE_ELEMENTS]。
+    'vue/v-bind-style': ['error', 'shorthand'], // This rule enforces v-bind directive style which you should use shorthand or long form。字符串选项有"shorthand" (default),"longform"。
+    'vue/v-on-style': ['error', 'shorthand'], // This rule enforces v-on directive style which you should use shorthand or long form。字符串选项有"shorthand" (default),"longform"。
+    'vue/v-slot-style': ['error', {
+      'atComponent': 'v-slot',
+      'default': 'shorthand',
+      'named': 'shorthand'
+    }], // This rule enforces v-slot directive style which you should use shorthand or long form。1字符串选项:"longform","shorthand"。 2对象选项:atComponent,default,named。可选值有"shorthand" use # shorthand,"longform" use v-slot: directive notation,"v-slot" use v-slot without that argument。
+
+    // Priority B: Strongly Recommended for Vue.js 3.x
+    'vue/require-explicit-emits': ['error', {
+      'allowProps': false
+    }], // This rule reports event triggers not declared with the emits option。(对象)选项有"allowProps"If true, allow event names defined in props,default false。
+    'vue/v-on-event-hyphenation': ['warn', 'always', {
+      'autofix': false,
+      'ignore': []
+    }], // This rule enforces using hyphenated v-on event names on custom components in Vue templates。1字符串选项:"always"(default),"never"。 2对象选项:autofix,If true, enable autofix。ignore,Array of ignored names。
+
+    // Priority C: Recommended
+    'vue/attributes-order': ['error', {
+      'order': [
+        'DEFINITION',
+        'LIST_RENDERING',
+        'CONDITIONALS',
+        'RENDER_MODIFIERS',
+        'GLOBAL',
+        ['UNIQUE', 'SLOT'],
+        'TWO_WAY_BINDING',
+        'OTHER_DIRECTIVES',
+        'OTHER_ATTR',
+        'EVENTS',
+        'CONTENT'
+      ],
+      'alphabetical': false
+    }], // 该规则旨在强制组件属性的排序。1对象选项。2字符串选项。标签里的各类属性的排序顺序,不符合规则则报错(原先默认的为警告)
+    'vue/component-tags-order': ['error', {
+      'order': [['script', 'template'], 'style']
+    }], // order ((string|string[])[])顶级元素名称的顺序。系统默认值[ [ "script", "template" ], "style" ]。也可以是CSS选择器,比如script[setup]和i18n:not([locale=en])。
+    'vue/no-lone-template': ['error', {
+      'ignoreAccessible': false
+    }], // 这条规则旨在消除不必要的和潜在的混乱<template>。在Vue.js 2.x中,没有特定指令的<template>元素会没有效果。在Vue.js 3.x中,没有特定指令的<template>元素虽能呈现<template>元素,但在大多数情况下,这可能不是您想要的。(对象)选项ignoreAccessibleIf true, ignore accessible <template> elements,default false,this option is useless if you are using Vue.js 2.x.
+    'vue/no-multiple-slot-args': 'error', // This rule disallows to pass multiple arguments to scoped slots。
+    'vue/no-v-html': 'off', // 禁止使用v-html,以防止XSS攻击,即降低将潜在的不安全/非转义html注入浏览器导致跨站点脚本(XSS)攻击的风险。
+    'vue/order-in-components': ['error', {
+      'order': [
+        'el',
+        'name',
+        'key',
+        'parent',
+        'functional',
+        ['delimiters', 'comments'],
+        ['components', 'directives', 'filters'],
+        'extends',
+        'mixins',
+        ['provide', 'inject'],
+        'ROUTER_GUARDS',
+        'layout',
+        'middleware',
+        'validate',
+        'scrollToTop',
+        'transition',
+        'loading',
+        'inheritAttrs',
+        'model',
+        ['props', 'propsData'],
+        'emits',
+        'setup',
+        'asyncData',
+        'data',
+        'fetch',
+        'head',
+        'computed',
+        'watch',
+        'watchQuery',
+        'LIFECYCLE_HOOKS',
+        'methods',
+        ['template', 'render'],
+        'renderError'
+      ]
+    }], // Enforce order of properties in components。(对象)选项有order ((string | string[])[])属性的顺序。元素是属性名或下列组之一:LIFECYCLE_HOOKS,Vue生命周期事件,按照它们被调用的顺序。ROUTER_GUARDS: Vue路由器导航防护装置,按照它们被调用的顺序。
+    'vue/this-in-template': ['error', 'never'], // Disallow usage of this in template。字符串选项"always","never" (default)
+
+    // Uncategorized
+    'vue/block-lang': ['error', {
+      script: {
+        lang: ['ts', 'js'],
+        allowNoLang: true
+      },
+      style: {
+        lang: ['less', 'sass', 'scss', 'css'],
+        allowNoLang: true
+      }
+    }], // This rule disallows the use of languages other than those available in the your application for the lang attribute of block elements。(对象)选项。值有lang指定的可用值lang块的属性,如果有多种语言可用,请将它们指定为一个数组,如果不指定,将不允许任何语言、allowNoLang如果true,允许lang未指定属性(允许使用块的默认语言)。
+    'vue/block-tag-newline': ['error', {
+      'singleline': 'consistent',
+      'multiline': 'consistent',
+      'maxEmptyLines': 1
+    }], // 在'打开块级标记'之后和'关闭块级标记'之前强制换行。(对象)选项有singleline单线块的配置;multiline多线块的配置;maxEmptyLines指定允许的最大空行数,默认为0;blocks为每个块名指定。可选值有"always" | "never" | "consistent" | "ignore"。
+    'vue/component-api-style': ['error',
+      ['script-setup', 'composition', 'composition-vue2', 'options']], // 强制组件API样式。(数组)选项有"script-setup", "composition", "composition-vue2","options"
+    'vue/component-name-in-template-casing': ['error', 'PascalCase', {
+      'registeredComponentsOnly': true,
+      'ignores': []
+    }], // 出于一致性目的,在模板中定义所使用的组件名的样式。1字符串选项"PascalCase"(默认)强制标签名使用pascal大小写,"kebab-case"。2对象选项registeredComponentsOnly如果true,只检查注册的组件(在PascalCase中)。ignores (string[])要忽略的元素名称。globals (string[]) ...要检查的全局注册的组件名。
+    'vue/component-options-name-casing': ['error', 'PascalCase'], // 此规则旨在在components选项里强制组件名称(左边的)。字符串选项有"PascalCase" (default),"kebab-case"(can only use kebab case in template),"camelCase"(can't use pascal case in template)。
+    'vue/custom-event-name-casing': ['error', 'kebab-case', {
+      'ignores': []
+    }], // Enforce specific casing for custom event name。1字符串选项。Vue 2推荐使用kebab-case作为自定义事件名称,如this.$emit('myEvent')。在Vue 3中,使用camelCase或kebab-case作为您的自定义事件名称不会限制它在v-on中的使用,然而,遵循JavaScript约定,camelCase(默认)更加自然。2对象选项
+    'vue/define-emits-declaration': ['error', 'type-based'], // 字符串选项,type-based(默认)强制基于类型的声明,runtime强制运行时声明。此规则仅适用于setup script和lang="ts"。
+    'vue/define-macros-order': ['error', {
+      'order': ['defineProps', 'defineEmits']
+    }], // This rule reports the defineProps and defineEmits compiler macros when they are not the first statements in <script setup> (after any potential import statements or type definitions) or when they are not in the correct order。(对象)选项有order (string[])The order of defineEmits and defineProps macros。
+    'vue/define-props-declaration': ['error', 'type-based'], // 字符串选项,type-based(默认)强制基于类型的声明,runtime强制运行时声明。此规则仅适用于setup script和lang="ts"。
+    'vue/html-button-has-type': ['error', {
+      'button': true,
+      'submit': true,
+      'reset': true
+    }], // Disallow usage of button without an explicit type attribute。This rule aims to warn if no type or an invalid type is used on a button type attribute。(对象)选项有button,submit,reset。
+    'vue/html-comment-content-newline': ['error', {
+      'singleline': 'never',
+      'multiline': 'never'
+    }, {
+      'exceptions': []
+    }], // This rule will enforce consistency of line break after the <!-- and before the --> of comment. It also provides several exceptions for various documentation styles。1对象选项singleline("never" (default),"always"),multiline ("never","always" (default))。2对象选项"exceptions" exceptions to the rule。
+    'vue/html-comment-content-spacing': ['error', 'always', {
+      'exceptions': []
+    }], // This rule will enforce consistency of spacing after the <!-- and before the --> of comment. It also provides several exceptions for various documentation styles。1字符串选项"always" (default),"never"。2对象选项"exceptions" exceptions to the rule。
+    'vue/html-comment-indent': ['error', 2], // 在HTML注释中强制一致的缩进。选项有type (number | "tab")缩进的类型,默认值为2。如果这是一个数字,那就是一次缩进的空格数,如果这是"tab",它使用一个制表符对应一个缩进。
+    'vue/match-component-file-name': ['error', {
+      'extensions': ['jsx', 'vue'],
+      'shouldMatchCase': false
+    }], // 您可以定义一组文件扩展名,该规则应该验证组件名称。(对象)选项有,"extensions": []要验证的文件扩展名数组(可以使用以下任意组合:".js", ".jsx", ".ts", ".tsx",以及".vue"扩展),默认值设置为["jsx"]。"shouldMatchCase": false布尔值,指示组件名是否也应与其文件名大小写匹配,默认值设置为false。
+    'vue/match-component-import-name': 'warn', // 要求注册的组件名与导入的组件名匹配(右边的和导入的)。“匹配”意味着导入的名称与组件对象属性标识符的PascalCase或kebab-case版本相匹配。
+    'vue/new-line-between-multi-line-property': 'off', // 这条规则的目的是在Vue组件的多行属性之间强制换行,以提高可读性。(对象)选项有minLineOfMultilineProperty,定义多行属性的最小行数,默认值2。
+    'vue/next-tick-style': ['warn', 'callback'], // This rule enforces whether the callback version or Promise version (which was introduced in Vue v2.1.0) should be used in Vue.nextTick and this.$nextTick。字符串选项,"promise"(默认)需要使用promise版本,"callback"需要使用回调版本(如果您使用低于v2.1.0的Vue版本,请使用此选项。)
+    'vue/no-bare-strings-in-template': 'off', // 为了能够国际化您的应用程序,您需要避免在模板中使用普通字符串(bare strings)。(对象)选项有allowlist允许的字符串数组。attributes一个对象的关键字是标记名或模式和值,它是一个属性数组,用于检查标记名。directives用于检查文字值的指令名数组。
+    'vue/no-boolean-default': 'off', // Boolean时,不传的情况下,不写'default: true'就是默认为false,写了就强制是true。与强制执行总是将布尔属性默认为false的HTML标准有关。此规则有争议。字符串选项有'no-default' (default),'default-false'。
+    'vue/no-duplicate-attr-inheritance': 'error', // Enforce inheritAttrs to be set to false when using v-bind="$attrs"。该规则旨在防止重复的属性继承。
+    'vue/no-empty-component-block': 'off', // This rule disallows the <template> <script> <style> block to be empty。除非有src值。valid-template-root验了template就够了。
+    'vue/no-multiple-objects-in-class': 'error', // Disallow to pass multiple objects into array to class。
+    'vue/no-potential-component-option-typo': ['error', {
+      'presets': [ 'all' ],
+      'custom': [],
+      'threshold': 1
+    }], // 不允许组件属性中出现潜在的输入错误。(对象)选项有presets,enum type,包含几个常见的vue组件选项集,["all"]与["vue", "vue-router", "nuxt"]相同,系统默认值 ["vue"]。custom,array type,一个存储您自定义组件选项要检测的列表,系统默认值 []。threshold,number type,一个用于控制报告编辑距离上限的数字,系统默认值。
+    'vue/no-ref-object-destructure': 'warn', // Disallow destructuring of ref objects that can lead to loss of reactivity。
+    'vue/no-required-prop-with-default': ['error', {
+      'autofix': true
+    }], // Enforce props with default values to be optional。
+    'vue/no-restricted-block': 'off', // 不允许指定的块(根标签)。字符串列表选项。对象列表选项,element指定块元素名称或模式,message指定可选的自定义消息。
+    'vue/no-restricted-call-after-await': 'off', // 不允许异步调用受限方法。对象列表选项,module指定模块名称,path指定导入的名称或指向该方法的路径,message指定可选的自定义消息。
+    'vue/no-restricted-class': 'off', // 不允许使用在标签中使用的指定类。字符串列表选项。This rule will only detect classes that are used as strings in your templates。
+    'vue/no-restricted-component-options': 'off', // 不允许指定的组件的选项。字符串列表选项。数组。对象列表选项,name通过字符串指定组件选项名称或模式,或者通过数组指定路径,message指定可选的自定义消息。
+    'vue/no-restricted-custom-event': 'off', // 不允许使用指定的自定义事件。字符串列表选项。对象列表选项,event指定事件名称或模式,message指定可选的自定义消息,suggest指定一个可选名称来建议更改。
+    'vue/no-restricted-html-elements': 'off', // 不允许使用指定的HTML elements。字符串列表选项。对象列表选项,element指定html元素,message指定可选的自定义消息。
+    'vue/no-restricted-props': 'off', // 不允许使用指定的props。字符串列表选项。对象列表选项,name指定属性的名称或模式,message指定可选的自定义消息,suggest指定一个可选名称来建议更改。
+    'vue/no-restricted-static-attribute': 'off', // 不允许使用指定的attribute。字符串列表选项。对象列表选项,key指定属性的名称或模式,value指定值文本或模式或true(如果指定,则只有在使用指定值时才会报告,如果true,只有在没有值或者值和键相同的情况下才会报告),element指定元素名称或模式(如果指定,则只有在指定元素上使用时才会报告),message指定可选的自定义消息。
+    'vue/no-restricted-v-bind': 'off', // 不允许使用指定的argument in v-bind(:的属性)。字符串列表选项。对象列表选项,argument指定参数名称或模式或者null(如果null则它匹配v-bind=),modifiers指定修饰符名称的数组(如果指定,则只有在使用指定的修饰符时才会报告),element指定元素名称或模式(如果指定,则只有在指定元素上使用时才会报告),message指定可选的自定义消息。
+    'vue/no-static-inline-styles': 'off', // Disallow static inline style attributes(但允许动态:绑定数据变量值的情况),建议将它们分为<style>标签。对象选项有allowBinding,如果true,允许所有的:动态绑定数据的情况,但依然不允许静态绑定(字符串)的情况,默认值false。
+    'vue/no-template-target-blank': ['error', {
+      'allowReferrer': true,
+      'enforceDynamicLinks': 'always'
+    }], // Disallow target="_blank" attribute without rel="noopener noreferrer"(为了避免安全漏洞)。(对象)选项有allowReferrer,如果true,则不需要noreferrer,默认false。enforceDynamicLinks ("always" | "never")如果always,则对于href是动态链接,也实施该规则,默认值always.
+    'vue/no-this-in-before-route-enter': 'error', // 不允许在beforeRouteEnter方法使用this。Because lack of this in the beforeRouteEnter。
+    'vue/no-undef-components': 'off', // 禁止在<template>里使用未定义的组件。该规则不能检查全局注册的组件和mixins中注册的组件,除非您将它们添加为被忽略模式的一部分。(对象)选项有ignorePatterns,如果组件名与一个或多个模式匹配则不报错。
+    'vue/no-undef-properties': ['warn', {
+      'ignores': [ '/^\\$/' ]
+    }], // 不允许出现未在data中定义的属性。此规则无法检测在其他文件或组件中定义的属性,且如果使用mixins,会有许多误报。(对象)选项有ignores (string[])已经定义的属性名称或模式的数组,或者要从检查中忽略的属性,默认值为["/^\\$/"]。
+    'vue/no-unsupported-features': 'off', // 此规则不能使用指定版本上不支持的Vue.js语法。(对象)选项有version接受的有效版本范围,ignores可以用这个ignores忽略给定特征的选项。原先的是{'version': '^2.6.10','ignores': []}。
+    'vue/no-unused-properties': 'off', // 不允许出现未使用的属性。此规则不能在其他组件中使用(例如mixins,或通过$refs属性访问而无法确定的地方)。(对象)选项有groups (string[])用于搜索属性的组数组,默认值为["props"],数组的值是下列字符串中的一些:"props""data""computed""methods""setup"。deepData (boolean)如果true,则data中定义的属性的对象将被深入搜索,默认值为false。ignorePublicMembers (boolean)默认值为false。
+    'vue/no-unused-refs': 'off', // 不允许出现未使用的ref。此规则不能在其他组件中使用(例如mixins,或通过$refs.x.$refs方式访问的情况)。
+    'vue/no-useless-mustaches': ['error', {
+      'ignoreIncludesComment': true,
+      'ignoreStringEscape': true
+    }], // 不允许不必要的插值表达式。此规则报告带有字符串文字值的插值。(对象)选项有ignoreIncludesComment如果true,则不要报告包含注释的表达式,系统默认值false。ignoreStringEscape如果true,则不要报告带有有用转义的字符串文字,系统默认值false。
+    'vue/no-useless-v-bind': ['error', {
+      'ignoreIncludesComment': true,
+      'ignoreStringEscape': true
+    }], // 不允许不必要的v-bind指令。此规则报告v-bind带有一个字符串值。(对象)选项有ignoreIncludesComment如果true,则不要报告包含注释的表达式,系统默认值false。ignoreStringEscape如果true,则不要报告带有有用转义的字符串文字,系统默认值false。
+    'vue/no-v-text': 'off', // Disallow use of v-text。
+    'vue/padding-line-between-blocks': ['error', 'always'], // 要求或不允许在块之间填充空行。字符串选项有"always" (default) Requires one or more blank lines。"never" Disallows blank lines。
+    'vue/padding-line-between-tags': 'off', // Require or disallow newlines between sibling tags in template。数组选项,值是对象:blankLine,always never consistent;prev任何不带括号的标记名;next任何不带括号的标记名。
+    'vue/prefer-prop-type-boolean-first': 'error', // Enforce Boolean comes first in component prop types。因为考虑到(在父组件)用简写形式使用它时,想为true,也考虑到想为''(但考虑到默认人一般会认为是true)。也考虑到当不使用时,需求为字符串的default(设置default就行)。反正用简写方式传了就需要是true。
+    'vue/prefer-separate-static-class': 'error', // Require static class names in template to be in a separate class attribute。
+    'vue/prefer-true-attribute-shorthand': ['error', 'always'], // Require shorthand form attribute when v-bind value is true。(对象)选项有"always" (default),"never"。反正用简写方式传了就需要是true。
+    'vue/require-direct-export': 'error', // 该规则旨在要求直接导出组件对象。(对象)选项有"disallowFunctionalComponentFunction" If true, disallow functional component functions, available in Vue 3.x,default false。
+    'vue/require-emit-validator': 'off', // Require type definitions in emits。
+    'vue/require-expose': 'off', // Require declare public properties using expose。此规则强制要组件使用显式声明组件的公开属性,即expose。
+    'vue/require-name-property': 'error', // 此规则需要在组件上设置一个name的属性。
+    'vue/require-prop-comment': 'off', // This rule enforces that every prop has a comment that documents it。(对象)选项有type,可选值"JSDoc" "line" "block" "any"。
+    'vue/script-indent': ['error', 2, {
+      'baseIndent': 0,
+      'switchCase': 1,
+      'ignores': []
+    }], // 在<script>中强制一致的缩进。字符串选项,TYPE (number | "tab")缩进的类型,默认值为2。对象选项baseIndent (integer)顶级语句的缩进倍数,默认值为0;switchCase (integer)缩进的倍数为case/default条款,默认值为0;ignores (string[])忽略节点的选择器。
+    'vue/sort-keys': 'off', // Enforce sort-keys in a manner that is compatible with order-in-components。字符串选项,"asc" "desc"。对象选项,caseSensitive,ignoreChildrenOf,ignoreGrandchildrenOf,minKeys,natural。
+    'vue/static-class-names-order': 'off', // Enforce static class names order。
+    'vue/v-for-delimiter-style': ['error', 'in'], // 此规则强制在v-for指令应该使用哪个分隔符(in或of)。
+    'vue/v-on-handler-style': ['warn', 'inline', {
+      'ignoreIncludesComment': false
+    }], // 在强制处理v-on指令程序的写作风格。字符串/数组选项有["method", "inline-function"] | ["method", "inline"] | "inline-function" | "inline"。对象选项有ignoreIncludesComment,如果true,则不报告包含注释的inline(inline handlers)或inline-functions(即使首选样式是"method"),但如果仅仅是method的方式则依然会报错,默认值为false。
+
+    // Extension Rules
+    'vue/array-bracket-newline': [2, 'consistent'], // Enforce linebreaks after opening and before closing array brackets in <template>
+    'vue/array-bracket-spacing': [
+      2,
+      'never',
+      {
+        singleValue: true,
+        objectsInArrays: false,
+        arraysInArrays: false
+      }
+    ], // Enforce linebreaks after opening and before closing array brackets in <template>
+    'vue/arrow-spacing': [
+      2,
+      {
+        before: true,
+        after: true
+      }
+    ], // Enforce consistent spacing before and after the arrow in arrow functions in <template>
+    'vue/block-spacing': [2, 'always'], // Disallow or enforce spaces inside of blocks after opening block and before closing block in <template>
+    'vue/brace-style': [
+      2,
+      '1tbs',
+      {
+        allowSingleLine: true
+      }
+    ], // Enforce consistent brace style for blocks in <template>
+    'vue/camelcase': 0, // Enforce camelcase naming convention in <template>
+    'vue/comma-dangle': [2, 'never'], // Enforce consistent spacing before and after commas in <template>
+    'vue/comma-spacing': [
+      2,
+      {
+        before: false,
+        after: true
+      }
+    ], // Enforce consistent spacing before and after commas in <template>
+    'vue/comma-style': [2, 'last'], // Enforce consistent newlines before and after dots in <template>
+    'vue/dot-location': [2, 'property'], // Enforce consistent newlines before and after dots in <template>
+    'vue/dot-notation': [
+      2,
+      {
+        allowKeywords: true
+      }
+    ], // Enforce dot notation whenever possible in <template>
+    'vue/eqeqeq': [2, 'always'], // Require the use of === and !== in <template>
+    'vue/func-call-spacing': 2, // Require or disallow spacing between function identifiers and their invocations in <template>
+    'vue/key-spacing': [
+      2,
+      {
+        beforeColon: false,
+        afterColon: true
+      }
+    ], // Enforce consistent spacing between keys and values in object literal properties in <template>
+    'vue/keyword-spacing': [
+      // -强制在关键字前后使用一致的空格。(对象)选项:"before": true (默认) "after": true (默认) "overrides"(允许覆盖指定的关键字的空格风格)
+      2,
+      {
+        before: true,
+        after: true
+      }
+    ], // Enforce consistent spacing before and after keywords in <template>
+    'vue/max-len': [
+      2,
+      {
+        code: 180,
+        tabWidth: 2,
+        comments: 180,
+        ignoreComments: true,
+        ignoreTrailingComments: false,
+        ignoreUrls: false,
+        ignoreStrings: false,
+        ignoreTemplateLiterals: false,
+        ignoreRegExpLiterals: false,
+        ignoreHTMLAttributeValues: false, // 额外的
+        ignoreHTMLTextContents: false // 额外的
+      }
+    ], // Enforce a maximum line length in .vue files
+    'vue/multiline-ternary': [2, 'always-multiline'], // Enforce newlines between operands of ternary expressions in <template>
+    'vue/no-constant-condition': 2, // Disallow constant expressions in conditions in <template>
+    'vue/no-empty-pattern': 2, // Disallow empty destructuring patterns in <template>
+    'vue/no-extra-parens': [
+      2,
+      'all',
+      {
+        conditionalAssign: false,
+        returnAssign: false,
+        nestedBinaryExpressions: false,
+        ignoreJSX: 'all',
+        enforceForArrowConditionals: false
+      }
+    ], // Disallow unnecessary parentheses in <template>
+    'vue/no-irregular-whitespace': 2, // Disallow irregular whitespace in .vue files
+    // 'vue/no-loss-of-precision': 1, // Disallow literal numbers that lose precision in <template> // 额外的
+    'vue/no-restricted-syntax': 0, // Disallow specified syntax in <template>
+    'vue/no-sparse-arrays': 2, // Disallow sparse arrays in <template>
+    'vue/no-useless-concat': 2, // Disallow unnecessary concatenation of literals or template literals in <template>
+    'vue/object-curly-newline': [
+      2,
+      {
+        consistent: true
+      }
+    ], // Enforce consistent line breaks after opening and before closing braces in <template>
+    'vue/object-curly-spacing': [
+      2,
+      'always',
+      {
+        arraysInObjects: true,
+        objectsInObjects: true
+      }
+    ], // Enforce consistent spacing inside braces in <template>
+    'vue/object-property-newline': [
+      2,
+      {
+        'allowAllPropertiesOnSameLine': true
+      }
+    ], // Enforce placing object properties on separate lines in <template>
+    'vue/object-shorthand': [2, 'always'], // Require or disallow method and property shorthand syntax for object literals in <template>
+    'vue/operator-linebreak': [
+      2,
+      'after',
+      {
+        overrides: {
+          '?': 'before',
+          ':': 'before'
+        }
+      }
+    ], // Enforce consistent linebreak style for operators in <template>
+    'vue/prefer-template': 0, // Require template literals instead of string concatenation in <template>
+    'vue/quote-props': [2, 'consistent'], // Require quotes around object literal property names in <template>
+    'vue/space-in-parens': [2, 'never'], // Enforce consistent spacing inside parentheses in <template>
+    'vue/space-infix-ops': 2, // Require spacing around infix operators in <template>
+    'vue/space-unary-ops': 2, // Enforce consistent spacing before or after unary operators in <template>
+    'vue/template-curly-spacing': [2, 'never'], // Require or disallow spacing around embedded expressions of template strings in <template>
+
+    // Deprecated
+    /*
+      vue/no-invalid-model-keys
+      vue/script-setup-uses-vars
+      vue/v-on-function-call
+    */
+
+    // 官网:http://eslint.cn/docs/rules/
+    // 注释的第一句的前面的“-”表示fixable,第一句为权威注释
+    // 选项:1字符串:"aaa"解,"bbb"解 2对象:"ccc": CCC,"ddd": DDD;对象:"eee": EEE,"fff": FFF
+    // Possible Errors:这些规则与 JavaScript 代码中可能的错误或逻辑错误有关:
+    'for-direction': 2, // 强制 “for” 循环中更新子句的计数器朝着正确的方向移动
+    'getter-return': 2, // 强制 getter 函数中出现 return 语句
+    'no-async-promise-executor': 0, // 禁止使用异步函数作为 Promise executor。Promise的函数参数不能有async
+    'no-await-in-loop': 0, // 禁止在循环中出现 await
+    'no-compare-neg-zero': 2, // 禁止与 -0 进行比较
+    'no-cond-assign': 2, // 禁止条件表达式中出现赋值操作符
+    'no-console': 1, // 禁用 console
+    'no-constant-condition': 2, // 禁止在条件中使用常量表达式 if(true) if(1)
+    'no-control-regex': 2, // 禁止在正则表达式中使用控制字符
+    'no-debugger': 1, // 禁止使用debugger
+    'no-dupe-args': 2, // 禁止 function 定义中出现重名参数。函数参数不能重复
+    'no-dupe-keys': 2, // 禁止对象字面量中出现重复的 key。在创建对象字面量时不允许键重复 {a:1,a:1}
+    'no-duplicate-case': 2, // 禁止出现重复的 case 标签。switch中的case标签不能重复
+    'no-empty': 1, // 禁止出现空语句块。块语句中的内容不能为空
+    'no-empty-character-class': 2, // 禁止在正则表达式中使用空字符集。正则表达式中的[]内容不能为空
+    'no-ex-assign': 2, // 禁止对 catch 子句的参数重新赋值。禁止给catch语句中的异常参数赋值
+    'no-extra-boolean-cast': 2, // -禁止不必要的布尔转换
+    'no-extra-parens': [
+      // -禁止非必要的括号
+      2,
+      'all',
+      {
+        conditionalAssign: false, // 允许在条件语句的测试表达式中的赋值语句周围出现额外的圆括号
+        returnAssign: false, // 允许在 return 语句中的赋值语句周围出现额外的圆括号
+        nestedBinaryExpressions: false, // 允许在嵌套的二元表达式中出现额外的圆括号
+        ignoreJSX: 'all', // 允许在 none/所有/多行/单行的JSX 组件周围出现额外的圆括号,默认为none
+        enforceForArrowConditionals: false // 允许在箭头函数体中的三元表达式周围出现额外的圆括号
+      }
+    ],
+    'no-extra-semi': 2, // -禁止不必要的分号
+    'no-func-assign': 2, // 禁止对 function 声明重新赋值。禁止重复的函数声明
+    'no-inner-declarations': 1, // 禁止在嵌套的块中出现变量声明或 function 声明。禁止在块语句中使用声明(变量或函数)。"functions" (默认) 禁止 function 声明出现在嵌套的语句块中;"both" 禁止 function 和 var 声明出现在嵌套的语句块中
+    'no-invalid-regexp': 2, // 禁止 RegExp 构造函数中存在无效的正则表达式字符串。禁止无效的正则表达式
+    'no-irregular-whitespace': 2, // 禁止不规则的空白。不能有不规则的空格
+    'no-misleading-character-class': 2, // 不允许在字符类语法中出现由多个代码点组成的字符
+    'no-obj-calls': 1, // 禁止把全局对象作为函数调用。不能调用内置的全局对象,比如Math() JSON()
+    'no-prototype-builtins': 1, // 禁止直接调用 Object.prototypes 的内置属性
+    'no-regex-spaces': 2, // -禁止正则表达式字面量中出现多个空格。禁止在正则表达式字面量中使用多个空格 /foo bar/
+    'no-sparse-arrays': 2, // 禁用稀疏数组, [1,,2]
+    'no-template-curly-in-string': 0, // 禁止在常规字符串中出现模板字面量占位符语法
+    'no-unexpected-multiline': 2, // 禁止出现令人困惑的多行表达式
+    'no-unreachable': 2, // 禁止在 return、throw、continue 和 break 语句之后出现不可达代码。不能有无法执行的代码
+    'no-unsafe-finally': 2, // 禁止在 finally 语句块中出现控制流语句
+    'no-unsafe-negation': 2, // -禁止对关系运算符的左操作数使用否定操作符
+    'require-atomic-updates': 2, // 禁止由于 await 或 yield的使用而可能导致出现竞态条件的赋值
+    'use-isnan': 2, // 要求使用 isNaN() 检查 NaN。禁止比较时使用NaN,只能用isNaN()
+    'valid-typeof': 2, // 强制 typeof 表达式与有效的字符串进行比较。必须使用合法的typeof的值
+
+    // Best Practices:这些规则是关于最佳实践的,帮助你避免一些问题
+    'accessor-pairs': 0, // 强制 getter 和 setter 在对象中成对出现。在对象中使用getter/setter
+    'array-callback-return': 2, // 强制数组(的特定)方法的回调函数中有 return 语句。from,every,filter,find,findIndex,map,reduce,reduceRight,some,sort。
+    'block-scoped-var': 0, // 强制把变量的使用限制在其定义的作用域范围内。块语句中使用var
+    'class-methods-use-this': 0, // 强制类(里面的)方法使用 this
+    'complexity': [2,
+      11], // 指定程序中允许的最大环路复杂度。此规则目的在于通过在项目中设置一个圈复杂度阈值来控制代码的复杂度,因此,它将会在圈复杂度超过配置的阈值时发出警告 (默认是 20)。循环复杂度
+    'consistent-return': 0, // 要求 return 语句要么总是指定返回的值,要么不指定。return 后面是否允许省略
+    'curly': [2,
+      'multi-line'], // -强制所有控制语句使用一致的括号风格。必须使用 if(){} 中的{}。默认选项 "all",其它multi,multi-line,multi-or-nest,consistent。
+    'default-case': 0, // 要求 switch 语句中有 default 分支。switch语句最后必须有default
+    'dot-location': [2, 'property'], // -强制在点号之前和之后一致的换行。"object" (默认),"property"。对象访问符的位置,换行的时候在行首还是行尾
+    'dot-notation': [
+      2,
+      {
+        allowKeywords: true
+      }
+    ], // -强制尽可能地使用点号(而不是xx["xxx"])。设置 allowKeywords 为 false(默认为true),避免对是保留字的属性使用点号,也可以设置为一个正则表达式
+    'eqeqeq': [2,
+      'always'], // -要求使用 === 和 !==。always(可以有第二个参数,是个对象"null":always (默认),never,ignore),smart(除了比较两个字面量的值,比较 typeof 的值,与 null 进行比较 这些情况外)。
+    'guard-for-in': 0, // 要求 for-in 循环中有一个 if 语句。for in循环要用if语句过滤
+    'max-classes-per-file': [2, 11], // 强制每个文件中包含的的类的最大数量。默认为1
+    'no-alert': 1, // 禁止使用alert confirm prompt
+    'no-caller': 2, // 禁止使用arguments.caller或arguments.callee
+    'no-case-declarations': 2, // 不允许在 case 子句中使用词法声明。该规则禁止词法声明 (let、const、function 和 class) 出现在 case或default 子句中(但var可以),为了保证词法声明语句只在当前 case 语句中有效,要将有词法声明子句包裹在块中。
+    'eslint no-div-regex': 0, // -禁止除法操作符显式的出现在正则表达式开始的位置。禁止使用看起来像除法的正则表达式
+    'no-else-return': 2, // -禁止 if 语句中 return 语句之后有 else 块。禁止在 else 前有 return。如果if语句里面有return,后面不能跟else语句。allowElseIf: true (默认) ,false
+    'no-empty-function': 1, // 禁止出现空函数
+    'no-empty-pattern': 2, // 禁止使用空解构模式。如禁止var {} = foo;var {a: []} = foo;function foo({a: {}}) {}等等
+    'no-eq-null': 2, // 禁止在没有类型检查操作符的情况下与 null 进行比较。禁止对null使用==或!=运算符。关联eqeqeq这个规则。该规则旨在通过确保与 null 比较时只等于 null,而不同时等于 undefined
+    'no-eval': 2, // 禁用 eval()
+    'no-extend-native': 2, // 禁止扩展原生类型。禁止扩展native对象。如禁止Object.prototype.extra = 55;
+    'no-extra-bind': 2, // -禁止不必要的 .bind() 调用。禁止不必要的函数绑定
+    'no-extra-label': 2, // -禁用不必要的标签。如果一个循环中不包含嵌套循环或 switch 语句,对这样的循环使用标签是不必要的。
+    'no-fallthrough': 2, // 禁止 case 语句落空。禁止switch穿透
+    'no-floating-decimal': 2, // -禁止数字字面量中使用前导和末尾小数点。禁止省略浮点数中的0。如禁止.5,3.
+    'no-global-assign': 2, // 禁止对原生对象或只读的全局对象进行赋值
+    'no-implicit-coercion': 0, // -禁止使用短符号进行类型转换。禁止隐式转换。有三个主要选项和一个覆盖选项:"boolean"(默认是 true),"number"(默认是 true),"string"(默认是 true),"allow" (默认是 empty)如{ "allow": ["!!", "~"] } 。
+    'no-implicit-globals': 1, // 禁止在全局范围内使用变量声明和 function 声明
+    'no-implied-eval': 2, // 禁止使用类似 eval() 的方法。禁止使用隐式eval
+    'no-invalid-this': 2, // 禁止 this 关键字出现在类和类对象之外。禁止无效的this,只能用在构造器,类,对象字面量。该规则 只 在严格模式下生效。如果在 ESLint 配置中设置了 "parserOptions": { "sourceType": "module" },你的代码即使没有使用 "use strict"指令,也是处于严格模式下的。
+    'no-iterator': 0, // 禁止使用__iterator__ 属性
+    'no-labels': [
+      // 禁用标签语句。禁止标签声明
+      2,
+      {
+        allowLoop: false, // 默认是 false)如果这个选项被设置为 true,该规则忽略循环语句中的标签。
+        allowSwitch: true // 默认是 false)如果这个选项被设置为 true,该规则忽略 switch 语句中的标签。
+      }
+    ],
+    'no-lone-blocks': 2, // 禁止不必要的嵌套块
+    'no-loop-func': 0, // 禁止在循环语句中出现包含不安全引用的函数声明。禁止循环中存在函数。禁止在循环中使用函数(如果没有引用外部变量不形成闭包就可以)
+    'no-magic-numbers': 0, // 禁用魔术数字。该规则旨在确保将具体的数字声明为意义明确的常量,从而使代码更加可读并且易于重构。(对象)选项有"ignore","ignoreArrayIndexes","enforceConst","detectObjects"。
+    'no-multi-spaces': [
+      2,
+      {
+        ignoreEOLComments: true
+      }
+    ], // -禁止使用多个空格。选项:"ignoreEOLComments": true (默认 false) 忽略行尾注释前的多个空格;"exceptions": { "Property": true } ("Property" 是为一个默认指定的节点) 指定要忽略的节点
+    'no-multi-str': 2, // 禁止使用多行字符串。字符串不能用\换行
+    'no-new': 0, // 禁止使用 new 以避免产生副作用。禁止在使用new构造一个实例后不赋值
+    'no-new-func': 2, // 禁止对 Function 对象使用 new 操作符。禁止使用new Function
+    'no-new-wrappers': 2, // 禁止对 String,Number 和 Boolean 使用 new 操作符。禁止使用new创建包装实例,new String new Boolean new Number
+    'no-octal': 2, // 禁用八进制字面量。禁止使用八进制数字
+    'no-octal-escape': 0, // 禁止在字符串中使用八进制转义序列。禁止使用八进制转义序列
+    'no-param-reassign': 1, // 禁止对 function 的参数进行重新赋值。(对象)选项:"props"(布尔值),"ignorePropertyModificationsFor"(数组)
+    'no-proto': 2, // 禁用 __proto__ 属性。
+    'no-redeclare': 2, // 禁止重复声明变量。此规则目旨在消除同一作用域中多次声明同一变量。
+    'no-restricted-properties': 0, // 禁止使用对象的某些属性。该规则接受一个对象列表,用来指定对象名和属性名。
+    'no-return-assign': [2,
+      'except-parens'], // 禁止在 return 语句中使用赋值语句。return 语句中不能有赋值表达式。(字符串)选项:except-parens(默认),always
+    'no-return-await': 0, // 禁用不必要的 return await。唯一有效是,如果 try/catch 语句中使用 return await 捕获到另一个基于 Promise 的函数的错误,则会出现异常。
+    'no-script-url': 0, // 禁止使用 javascript: url。禁止使用javascript:void(0)
+    'no-self-assign': 2, // 禁止自我赋值
+    'no-self-compare': 2, // 禁止自身比较。唯一肯能会对变量自身做比较时候是当你在测试变量是否是 NaN。
+    'no-sequences': 2, // 禁止使用逗号运算符。以下情况除外:在初始化或者更新部分 for 语句时,如果表达式序列被明确包裹在括号中。
+    'no-throw-literal': 2, // 禁止抛出异常字面量。禁止抛出字面量错误 throw "error";throw 0;throw undefined;等等
+    'no-unmodified-loop-condition': 0, // 禁用一成不变的循环条件
+    'no-unused-expressions': 0, // 禁止出现未使用过的表达式。禁止无用的表达式。(对象)选项:allowShortCircuit,allowTernary,allowTaggedTemplates。
+    'no-unused-labels': 2, // -禁用出现未使用过的标
+    'no-useless-call': 0, // 禁止不必要的 .call() 和 .apply()。
+    'no-useless-catch': 2, // 禁止不必要的 catch 子句。只重新抛出原始错误的 catch 子句是冗余的,所以最好不要使用这些不必要的 catch 子句。
+    'no-useless-concat': 2, // 禁止不必要的字符串字面量或模板字面量的连接
+    'no-useless-escape': 2, // 禁用不必要的转义字符
+    'no-useless-return': 2, // -禁止多余的 return 语句
+
+    'no-void': 2, // 禁用 void 操作符
+    'no-warning-comments': 0, // 禁止在注释中使用特定的警告术语。不能有警告备注。(对象)选项:"terms"数组,"location"字符串。
+    'no-with': 2, // 禁用 with 语句
+    'prefer-named-capture-group': 0, // 建议在正则表达式中使用命名捕获组
+    'prefer-promise-reject-errors': 0, // 要求使用 Error 对象作为 Promise 拒绝的原因
+    'radix': 1, // 强制在 parseInt() 使用基数参数。parseInt必须指定第二个参数。(字符串)选项:"always"强制提供一个基数(默认的),"as-needed"禁止提供基数10
+    'require-await': 2, // 禁止使用不带 await 表达式的 async 函数
+    'require-unicode-regexp': 0, // 强制在 RegExp 上使用 u 标志
+    'vars-on-top': 0, // 要求所有的 var 声明出现在它们所在的作用域顶部。var必须放在作用域顶部
+    'wrap-iife': [2,
+      'any'], // -立即执行函数表达式的小括号风格。选项:字符串("outside" "inside" "any"),对象{"functionPrototypeMethods": true}默认为false
+    'yoda': [2, 'never'], // -要求或禁止 “Yoda” 条件。(字符串)选项:"never","always"
+
+    // Strict Mode:该规则与使用严格模式和严格模式指令有关
+    'strict': [2, 'never'], // -要求或禁止使用严格模式指令。(字符串)选项:默认"safe","global","function","never"
+
+    // Variables:这些规则与变量声明有关
+    'init-declarations': 0, // 要求或禁止 var 声明中的初始化。声明时必须赋初值。选项:字符串(默认"always","never"),对象如"never", { "ignoreForLoopInit": true }用来表明在设置了 "never" 之后,是否允许在 for 循环中变量声明时进行初始化
+    'no-delete-var': 1, // 禁止删除变量。不能对var声明的变量使用delete操作符
+    'no-label-var': 1, // 不允许标签与变量同名。label名不能与var声明的变量名相同
+    'no-restricted-globals': 0, // 禁用特定的全局变量。选项:包含一个字符串列表,每个字符串都是全局受限的。
+    'no-shadow': 0, // 禁止变量声明与外层作用域的变量同名。外部作用域中的变量不能与它所包含的作用域中的变量或参数同名。(对象)选项:"builtinGlobals" "hoist" "allow"
+    'no-shadow-restricted-names': 2, // 禁止将标识符定义为受限的名字。关键字不能被遮蔽。严格模式中规定的限制标识符不能作为声明时的变量名使用
+    'no-undef': 2, // 禁用未声明的变量,除非它们在 /*global */ 注释中被提到。不能有未定义的变量。(对象)选项:{ "typeof": false }默认false
+    'no-undef-init': 2, // -禁止将变量初始化为 undefined。变量初始化时不能直接给它赋值为undefined
+    'no-undefined': 2, // 禁止将 undefined 作为标识符。不允许使用undefined变量
+    'no-unused-vars': [
+      // 禁止出现未使用过的变量。不能有声明后未被使用的变量或参数
+      1,
+      // 其它选项:varsIgnorePattern,ignoreRestSiblings,argsIgnorePattern,caughtErrors,caughtErrorsIgnorePattern
+      {
+        vars: 'all', // all 检测所有变量,包括全局环境中的变量,这是默认值。local 仅仅检测本作用域中声明的变量是否使用,允许不使用全局环境中的变量。
+        args: 'none' // after-used - 不检查最后一个使用的参数之前出现的未使用的位置参数,但是检查最后一个使用的参数之后的所有命名参数和所有位置参数。all - 所有命名参数必须使用。none - 不检查参数。
+      }
+    ],
+    'no-use-before-define': 2, // 禁止在变量定义之前使用它们。未定义前不能使用。(对象)选项:functions (boolean),classes (boolean),variables (boolean)默认都是true
+
+    // Node.js and CommonJS:这些规则是关于Node.js 或 在浏览器中使用CommonJS 的
+    'callback-return': 0, // 强制数组方法的回调函数中有 return 语句。强制返回callback函数。允许多次调用回调什么的。选项:数组,包含可能的回调函数名称,默认["callback", "cb", "next"]
+    'global-require': 0, // 要求 require() 出现在顶层模块作用域中。强制在模块顶部调用 require()。因为 require() 是同步加载的,在其它地方使用时,会导致性能问题。
+    'handle-callback-err': [1,
+      '^.*(e|E)rr'], // 要求回调函数中有容错处理。nodejs 处理错误。这个模式期望一个 Error 对象或 null 作为回调的第一个参数。(字符串)选项:默认'err'
+    'no-buffer-constructor': 2, // 禁用 Buffer() 构造函数
+    'no-mixed-requires': 0, // 声明时不能混用声明类型。(对象)选项:默认{ "grouping": false, "allowCall": false }
+    'no-new-require': 2, // 禁止调用 require 时使用 new 操作符。禁止使用new require
+    'no-path-concat': 0, // 禁止对 __dirname 和 __filename 进行字符串连接。node中不能使用__dirname或__filename做路径拼接
+    'no-process-env': 0, // 禁止使用process.env
+    'no-process-exit': 0, // 禁止使用process.exit()
+    'no-restricted-modules': 0, // 禁用通过 require 加载的指定模块。如果使用了禁用的指定模块就会报错。选项:该规则有一个或多个字符串作为选项,受限制的模块名称。
+    'no-sync': 0, // nodejs 禁止同步方法。选项:该规则有一个对象选项 { allowAtRootLevel: <boolean> },用来决定同步方法是否允许放置在文件顶层,在任何函数之外,默认为 false。
+
+    // Stylistic Issues:这些规则是关于风格指南的,而且是非常主观的
+    'array-bracket-newline': [2,
+      'consistent'], // -在数组开括号后和闭括号前强制换行。选项:"always","never","consistent" 对每个括号要求使用一致的换行符,"multiline": true (默认) 如果数组元素内或元素间有换行则要求换行,"minItems": null (默认) 如果数组元素的个数大于等于给定的整数则要求换行。
+    'array-bracket-spacing': [
+      // -强制数组方括号中使用一致的空格。是否允许非空数组里面有多余的空格。选项:"never" (默认),"always",有例外情况,用一个对象表示,如{ "singleValue": true, "objectsInArrays": true, "arraysInArrays": true }
+      2,
+      'never',
+      {
+        singleValue: true,
+        objectsInArrays: false,
+        arraysInArrays: false
+      }
+    ],
+    'array-element-newline': [2,
+      'consistent'], // -强制数组元素间出现换行。选项:"always" (默认) ,"never" ,"consistent","multiline": <boolean>,"minItems": <number>
+    'block-spacing': [2, 'always'], // -禁止或强制在代码块中的同一行的开括号前和闭括号后有空格。选项:"always","never"
+    'brace-style': [
+      // -强制在代码块中使用一致的大括号风格。选项:"1tbs" (默认) "stroustrup" "allman"
+      2,
+      '1tbs',
+      {
+        allowSingleLine: true // 有例外情况,用对象表示,"allowSingleLine"(默认 false) 是否允许块的开括号和闭括号在同一行
+      }
+    ],
+    'camelcase': 0, // 强制使用骆驼拼写法命名约定。(对象)选项:"properties": "always" (默认),"properties": "never","ignoreDestructuring": false (默认) ,"ignoreDestructuring": true,allow (string[])
+    'capitalized-comments': 0, // -强制或禁止对注释的第一个字母大写。选项:"always"(默认,小写),"never"。其它(对象)选项:ignorePattern,ignoreInlineComments,ignoreConsecutiveComments。
+    'comma-dangle': [2,
+      'never'], // -要求或禁止末尾逗号。对象字面量项尾不能有逗号。选项:"never" (默认),"always","always-multiline","only-multiline",或对象{ arrays: 'never', objects: 'never', imports: 'never', exports: 'never', functions: 'never' }
+    'comma-spacing': [
+      // -强制在逗号前后使用一致的空格。(对象)选项:默认{ "before": false, "after": true }
+      2,
+      {
+        before: false,
+        after: true
+      }
+    ],
+    'comma-style': [2,
+      'last'], // -强制使用一致的逗号风格。换行时在行首还是行尾。选项:"last"(默认,要求逗号放在数组元素、对象属性或变量声明之后,且在同一行),"first",(对象)选项"exceptions"
+    'computed-property-spacing': [2, 'never'], // -强制在计算的属性的方括号中使用一致的空格。选项:"never" (默认) "always"
+    'consistent-this': 0, // 当获取当前执行环境的上下文时,强制使用一致的命名。this别名。选项:默认 "that"
+    'eol-last': 2, // -要求或禁止文件末尾存在空行。文件以单一的换行符结束。选项:"always" (默认) 强制使用换行 (LF) "never"
+    'func-call-spacing': 2, // -要求或禁止在函数标识符和其调用之间有空格。选项:"never" (默认) 禁止在函数名和开括号之间有空格,"always"
+    'func-name-matching': 0, // 选项:"always"(默认)或 "never"和一个对象选项,其只有一个 includeCommonJSModuleExports 属性,值为布尔类型,默认为 false,表示该规则会忽略 module.exports 和 module["exports"]
+    'func-names': 0, // 要求或禁止使用命名的 function 表达式。函数表达式必须有名字。选项"always" (默认) "as-needed" "never",和对象选项"generators"
+    'func-style': 0, // 强制一致地使用 function 声明或表达式。函数风格,规定只能使用函数声明/函数表达式。选项:"expression" (默认) 要求使用函数表达式而不是函数声明,"declaration",其它(对象)选项"allowArrowFunctions": true (默认为 false) 允许使用箭头函数 (仅在使用 declaration 时启用)
+    'function-paren-newline': [2,
+      'multiline'], // -强制在函数括号内使用一致的换行。选项:"always" "never" "multiline" "multiline-arguments" "consistent" { "minItems": value }
+    'id-blacklist': 0, // 禁用指定的标识符。选项:该规则有一个或多个字符串选项,受限制的标识符的名称。
+    'id-length': [
+      2,
+      {
+        min: 1,
+        max: 36
+      }
+    ], // 强制标识符的最小和最大长度。变量名长度。(对象)选项:"min" (默认为 2) "max" (默认无穷大) "properties": always (默认) "properties": never "exceptions"(所允许的特定的标识符名称数组)
+    'id-match': 0, // 要求标识符匹配一个指定的正则表达式。命名检测。字符串选项:特定的正则表达式,其它对象选项:"properties": true "onlyDeclarations": true "onlyDeclarations": false "ignoreDestructuring": false (默认) "ignoreDestructuring": true
+    'implicit-arrow-linebreak': [2,
+      'beside'], // -强制隐式返回的箭头函数体的位置。选项:"beside" (默认) 禁止在箭头函数体之前出现换行,"below" 要求在箭头函数体之前出现换行。
+    'indent': [
+      // -强制使用一致的缩进(风格)。选项:空格缩进默认4,tab 缩进"tab",其它对象选项"SwitchCase"(默认:0)等等
+      2,
+      2,
+      {
+        SwitchCase: 1
+      }
+    ],
+    'jsx-quotes': [2, 'prefer-double'], // -强制在 JSX 属性中一致地使用双引号或单引号。选项:"prefer-double" (默认),"prefer-single"
+    'key-spacing': [
+      // -强制在对象字面量的属性中键和值之间使用一致的间距。(对象)选项:"beforeColon": false (默认) | true,"afterColon": true (默认) | false,"mode": "strict" (默认) | "minimum","align": "value" | "colon","align","singleLine","multiLine"
+      2,
+      {
+        // 对象字面量中冒号的前后空格
+        beforeColon: false,
+        afterColon: true
+      }
+    ],
+    'keyword-spacing': [
+      // -强制在关键字前后使用一致的空格。(对象)选项:"before": true (默认) "after": true (默认) "overrides"(允许覆盖指定的关键字的空格风格)
+      2,
+      {
+        before: true,
+        after: true
+      }
+    ],
+    'line-comment-position': 0, // 强制行注释的位置。(字符串或对象)选项:"position":above (默认) 强制行注释只在代码上方单独成行,beside 强制行注释只在代码行后面。
+    'linebreak-style': [0, 'windows'], // -强制使用一致的换行风格。选项:"unix" (默认),"windows"
+    'lines-around-comment': [
+      // -要求在注释周围有空行。行前和行后备注
+      2,
+      {
+        beforeBlockComment: true,
+        afterBlockComment: true,
+        beforeLineComment: false,
+        afterLineComment: false,
+        allowBlockStart: true,
+        allowBlockEnd: true,
+        allowObjectStart: true,
+        allowObjectEnd: true,
+        allowArrayStart: true,
+        allowArrayEnd: true,
+        allowClassStart: true,
+        allowClassEnd: true
+      }
+    ],
+    'lines-between-class-members': [
+      2,
+      'always',
+      {
+        exceptAfterSingleLine: false
+      }
+    ], // -要求或禁止类成员之间出现空行。选项:"always"(默认) "never",其它(对象)选项"exceptAfterSingleLine": false(默认)不要跳过对单行类成员之后的空行的检查
+    'max-depth': [2, 5], // 强制可嵌套的块的最大深度。嵌套块深度。选项:数字或对象,"max" (默认 4) 强制块语句的最大可嵌套深度
+    'max-len': [
+      // 强制一行的最大长度。选项:数字或对象
+      2,
+      {
+        code: 180,
+        tabWidth: 2,
+        comments: 180,
+        ignoreComments: true,
+        ignoreTrailingComments: false,
+        ignoreUrls: false,
+        ignoreStrings: false,
+        ignoreTemplateLiterals: false,
+        ignoreRegExpLiterals: false
+      }
+    ],
+    'max-lines': [
+      2,
+      {
+        max: 999,
+        skipBlankLines: true,
+        skipComments: true
+      }
+    ], // 强制最大行数。选项:"max" (默认 300) 强制一个文件的最大行数,"skipBlankLines": true 忽略空白行,"skipComments": true 忽略只包含注释的行
+    'max-lines-per-function': [
+      2,
+      {
+        max: 280,
+        skipBlankLines: true,
+        skipComments: true,
+        IIFEs: true
+      }
+    ], // 强制函数最大代码行数。选项:"max" (默认 50) 强制在函数中的最大行数,"skipBlankLines" (默认 false) 忽略纯粹由空格组成的行,"skipComments" (默认 false) 忽略只包含注释的行,"IIFEs" (默认 false) 包括 IIFE 中包含的任何代码。
+    'max-nested-callbacks': [2, 5], // 强制回调函数最大嵌套深度。选项:数字或对象,"max" (默认 10) 强制回调函数最大可嵌套深度
+    'max-params': [2, 6], // 强制函数定义中最多允许的参数数量。函数最多只能有5个参数。选项:数字或对象,"max" (默认 3) 强制函数定义中最大参数个数
+    'max-statements': [2,
+      250], // 强制函数块最多允许的的语句数量。函数内最多有几个声明。选项:数字或对象,max 属性,"ignoreTopLevelFunctions": true 忽略顶级函数
+    'max-statements-per-line': [
+      2,
+      {
+        max: 3
+      }
+    ], // 强制每一行中所允许的最大语句数量。选项:"max" 属性是可选的(默认为 1)
+    'multiline-comment-style': 0, // -强制对多行注释使用特定风格。(字符串)选项:"starred-block" (默认): 禁止使用连续的行注释来表示块注释,另外要求块注释的每行之前有一个 *,"bare-block": 禁止使用连续的行注释来表示块注释,并且禁止块注释每行前有一个"*","separate-lines": 禁用块注释,使用连续的行注释。
+    'multiline-ternary': [2,
+      'always-multiline'], // 要求或禁止在三元操作数中间换行。选项:"always" (默认) 强制三元操作数之间有换行,"always-multiline" 如果表达式跨越多个行,则在三元表达式的操作数之间强制换行,"never" 禁止三元操作数之间有换行 (强制整个三元表达式在同一行)
+    'new-cap': [
+      // 要求构造函数首字母大写。函数名首行大写必须使用new方式调用,首行小写必须用不带new方式调用。(对象)选项:"newIsCap": true (默认) "newIsCap": false "capIsNew": true(默认)  "newIsCapExceptions" "newIsCapExceptionPattern" "capIsNewExceptions" "capIsNewExceptionPattern" "properties": true (默认) 。
+      2,
+      {
+        newIsCap: true,
+        capIsNew: false
+      }
+    ],
+    'new-parens': [2,
+      'always'], // -强制或禁止调用无参构造函数时有圆括号。new时必须加小括号。选项:"always" 强制括号后的新构造函数没有参数(默认),"never" 强制在没有参数的新构造函数后不出现任何圆括号。
+    'newline-per-chained-call': [
+      2,
+      {
+        ignoreChainWithDepth: 2
+      }
+    ], // -要求方法链中每个调用都有一个换行符。选项:"ignoreChainWithDepth" (默认为 2) 允许在同一行成链的深度
+    'no-array-constructor': 0, // 禁用 Array 构造函数。禁止使用数组构造器
+    'no-bitwise': 2, // 禁止使用按位运算符
+    'no-continue': 0, // 禁止使用continue
+    'no-inline-comments': 0, // 禁止使用内联注释。禁止行内备注
+    'no-lonely-if': 2, // -禁止 if 作为唯一的语句出现在 else 语句中。禁止else语句内只有if语句
+    'no-mixed-operators': 0, // 禁止混合使用不同的操作符。选项:groups (string[][]) - 指定要检查的操作符分组,allowSamePrecedence (boolean) - 指定是否允许混合运算符具有相同的优先级,默认为 true
+    'no-mixed-spaces-and-tabs': 2, // 禁止空格和 tab 的混合缩进。禁止混用tab和空格
+    'no-multi-assign': 0, // 禁止连续赋值
+    'no-multiple-empty-lines': [
+      2,
+      {
+        max: 1,
+        maxEOF: 1,
+        maxBOF: 0
+      }
+    ], // -禁止出现多行空行。空行最多不能超过2行。(对象)选项:"max" (默认为 2) 强制最大连续空行数,"maxEOF" 强制文件末尾的最大连续空行数,"maxBOF" 强制文件开始的最大连续空行数
+    'no-negated-condition': 0, // 禁用否定的表达式。在含有 else 分支的 if 语句和三元表达式的情况使用
+    'no-nested-ternary': 0, // 禁用嵌套的三元表达式。禁止使用嵌套的三目运算
+    'no-new-object': 0, // 禁用 Object 的构造函数。禁止使用new Object()
+    'no-plusplus': 0, // 	禁用一元操作符 ++ 和 --。(对象)选项:"allowForLoopAfterthoughts": true
+    'no-restricted-syntax': 0, // 禁用特定的语法。选项:是个字符串列表,列表中的每个字符串都是一个 AST 选择器
+    'no-tabs': 0, // 禁用 tab。选项:allowIndentationTabs (默认: false)
+    'no-ternary': 0, // 禁用三元操作符。禁止使用三目运算符
+    'no-trailing-spaces': 2, // -禁用行尾空格。一行结束后面不要有空格。(对象)选项:"skipBlankLines": false (默认)禁止在空行使用空白符,"ignoreComments": false (默认) 禁止在注释块中使用空白符
+    'no-underscore-dangle': 0, // 禁止标识符中有悬空下划线。标识符不能以_开头或结尾。(对象)选项:"allow" 允许指定标识符使用悬空下划线,"allowAfterThis": false (默认),"allowAfterSuper": false (默认),"enforceInMethodNames": false (默认)
+    'no-unneeded-ternary': [
+      2,
+      {
+        defaultAssignment: false
+      }
+    ], // -禁止可以在有更简单的可替代的表达式(更简单结构)时使用三元操作符。(对象)选项:"defaultAssignment": true (默认) 允许条件表达式作为默认的赋值模式
+    'no-whitespace-before-property': 2, // -禁止属性前有空白
+    'nonblock-statement-body-position': [2,
+      'beside'], // -强制单个语句的位置。(字符串)选项:"beside" (默认) 禁止单行语句之前有换行,"below" 要求单行语句之前有换行,"any" 不强制单行语句的位置,其它(对象)选项:"overrides"(对象)。联接curly
+    'object-curly-newline': [
+      2,
+      {
+        consistent: true
+      }
+    ], // -强制大括号内换行符的一致性。选项:1字符串"always","never" 2对象"multiline": true,"minProperties","consistent": true,"ObjectExpression","ObjectPattern","ImportDeclaration","ExportDeclaration"
+    'object-curly-spacing': [
+      // -强制在大括号中使用一致的空格。大括号内是否允许不必要的空格。选项:字符串"never" (默认),"always";对象:"arraysInObjects": false,"objectsInObjects": false(当第一个选项为 always 时生效)
+      2,
+      'always',
+      {
+        arraysInObjects: true,
+        objectsInObjects: true
+      }
+    ],
+    'object-property-newline': [
+      2,
+      {
+        'allowAllPropertiesOnSameLine': true
+      }
+    ], // -强制将对象的属性放在不同的行上。选项:对象allowAllPropertiesOnSameLine:true所有属性都在同一行上将被允许
+    'one-var': [
+      2,
+      {
+        initialized: 'never'
+      }
+    ], // -强制函数中的变量要么一起声明要么分开声明。连续声明。选项:1字符串"always" (默认),"never","consecutive" 2对象"var","let","const","separateRequires" 3对象"initialized","uninitialized"
+    'one-var-declaration-per-line': 2, // -要求或禁止在变量声明周围换行。选项:字符串"initializations" (默认) 强制每个变量初始化语句换行,"always" 强制每个变量声明都换行
+    'operator-assignment': [0,
+      'always'], // -要求或禁止在可能的情况下使用简化的赋值操作符。赋值运算符 += -=什么的。选项:字符串"always" (默认) 要求尽可能地简化赋值操作,"never" 禁止简化赋值操作
+    'operator-linebreak': [
+      2,
+      'after',
+      {
+        overrides: {
+          '?': 'before',
+          ':': 'before'
+        }
+      }
+    ], // -强制操作符使用一致的换行符。换行时运算符在行尾还是行首。选项:字符串"after","before","none";对象默认"after", { "overrides": { "?": "before", ":": "before" } }
+    'padded-blocks': [2,
+      'never'], // -要求或禁止块内填充。块语句内行首行尾是否要空行。选项:1字符串"always" (默认),"never" 2对象"blocks","classes","switches";对象"allowSingleLineBlocks": true 允许单行块
+    'padding-line-between-statements': 0, // -要求或禁止在语句间填充空行。选项:对象blankLine,prev,next
+    'prefer-object-spread': 0, // -禁止使用以对象字面量作为第一个参数的 Object.assign,优先使用对象扩展。
+    'quote-props': [2,
+      'consistent'], // -要求对象字面量属性名称用引号括起来。对象字面量中的属性名是否强制引号。选项:字符串"always" (默认),"as-needed","consistent","consistent-as-needed";对象"keywords": true,"unnecessary": true (默认),"unnecessary": false,"numbers": true
+    'quotes': [
+      2,
+      'single',
+      {
+        avoidEscape: true,
+        allowTemplateLiterals: true
+      }
+    ], // -强制使用一致的反勾号、双引号或单引号。引号类型 `` "" ''。选项:字符串"double" (默认),"single","backtick";对象"avoidEscape": true,"allowTemplateLiterals": true。
+    'semi': [
+      2,
+      'never',
+      {
+        beforeStatementContinuationChars: 'always'
+      }
+    ], // -要求或禁止使用分号代替 ASI。语句强制分号结尾。选项:字符串"always" (默认),"never";对象"omitLastInOneLineBlock": true,"beforeStatementContinuationChars": "any" (默认) "always" "never"
+    'semi-spacing': [
+      2,
+      {
+        before: false,
+        after: true
+      }
+    ], // -强制分号之前和之后使用一致的空格。分号前后空格。选项:对象默认{"before": false, "after": true}
+    'semi-style': [2, 'last'], //	-强制分号的位置。选项:字符串"last" (默认),"first"
+    'sort-keys': 0, // 要求对象属性按序排列。选项:字符串"asc" (默认),"desc";对象caseSensitive默认为 true,minKeys默认值为 2,natural默认为 false
+    'sort-vars': 0, // -要求同一个声明块中的变量按顺序排列。变量声明时排序。
+    'space-before-blocks': [2, 'always'], // -强制在块之前使用一致的空格。不以新行开始的块{前面要不要有空格。选项:字符串"always"默认,"never";对象
+    'space-before-function-paren': [
+      // -强制在 function的左括号之前使用一致的空格。函数定义时括号前面要不要有空格。选项:1字符串always (默认),never 2对象anonymous,named,asyncArrow
+      2,
+      {
+        anonymous: 'always',
+        named: 'never',
+        asyncArrow: 'always'
+      }
+    ],
+    'space-in-parens': [2, 'never'], // -强制在圆括号内使用一致的空格。小括号里面要不要有空格。选项:字符串"never" (默认),"always";对象"exceptions"
+    'space-infix-ops': 2, // -要求操作符周围有空格。中缀操作符周围要不要有空格。选项:对象默认{"words": true, "nonwords": false}
+    'space-unary-ops': 2, // -强制在一元操作符前后使用一致的空格。一元运算符的前或后要不要加空格。选项:对象默认{"words": true, "nonwords": false}
+    'spaced-comment': [
+      // -强制在注释中 // 或 /* 使用一致的空格。注释风格要要有空格什么的。选项:字符串:"always","never";对象"exceptions","markers"
+      2,
+      'always',
+      {
+        markers: [
+          'global',
+          'globals',
+          'eslint',
+          'eslint-disable',
+          '*package',
+          '!',
+          ',',
+          '/',
+          '*'
+        ]
+      }
+    ],
+    'switch-colon-spacing': [
+      2,
+      {
+        after: true,
+        before: false
+      }
+    ], // -强制在 switch 的冒号左右有空格。选项:对象默认{"after": true, "before": false}
+    'template-tag-spacing': [2, 'never'], // -要求或禁止在模板标记和它们的字面量之间有空格。选项:字符串"never" (默认),"always"
+    'unicode-bom': [2, 'never'], // -要求或禁止 Unicode 字节顺序标记 (BOM)。选项:字符串"never" (默认),"always"
+    'wrap-regex': 0, // 正则表达式字面量用小括号包起来
+
+    // ECMAScript 6:这些规则只与 ES6 有关, 即通常所说的 ES2015
+    'arrow-body-style': [2,
+      'as-needed'], // -要求箭头函数体使用大括号。选项:字符串"always","as-needed"(默认),"never";对象requireReturnForObjectLiteral默认为false
+    'arrow-parens': [2, 'always'], // -箭头函数用小括号括起来。选项:字符串"always" (默认),"as-needed";对象"requireForBlockBody": true
+    'arrow-spacing': [
+      2,
+      {
+        before: true,
+        after: true
+      }
+    ], // -强制箭头函数的箭头前后使用一致的空格。=>的前后括号。选项:对象默认{ "before": true, "after": true }
+    'constructor-super': 2, // 要求在构造函数中有 super() 的调用。非派生类不能调用super,派生类必须调用super。
+    'generator-star-spacing': [
+      2,
+      {
+        before: true,
+        after: true
+      }
+    ], // -强制 generator 函数中 * 号周围使用一致的空格。生成器函数*的前后空格。选项:1字符串 2对象默认{"before": true, "after": false}
+    'no-class-assign': 2, // 禁止修改类声明的变量。禁止给类赋值。
+    'no-confusing-arrow': 0, // -禁止在可能与比较操作符相混淆的地方使用箭头函数。
+    'no-const-assign': 2, // 禁止修改const声明的变量。
+    'no-dupe-class-members': 2, // 禁止类成员中出现重复的名称。
+    'no-duplicate-imports': 2, // 禁止重复模块导入。
+    'no-new-symbol': 2, // 禁止 Symbolnew 操作符和 new 一起使用。
+    'no-restricted-imports': 0, // 禁止使用指定的 import 加载的模块。选项:字符串;对象。
+    'no-this-before-super': 2, // 在调用super()之前不能使用this或super。
+    'no-useless-computed-key': 2, // -禁止在对象中使用不必要的计算属性。
+    'no-useless-constructor': 2, // 禁用不必要的构造函数。
+    'no-useless-rename': 2, // -禁止在 import 和 export 和解构赋值时将引用重命名为相同的名字。选项:对象ignoreImport,ignoreExport,ignoreDestructuring默认都为false
+    'no-var': 0, // -要求使用 let 或 const 而不是 var。禁用var,用let和const代替
+    'object-shorthand': [2,
+      'always'], // -要求或禁止对象字面量中方法和属性使用简写语法。强制对象字面量缩写语法。选项:字符串"always" (默认),"methods","properties","never","consistent","consistent-as-needed";对象"avoidQuotes","ignoreConstructors","avoidExplicitReturnArrows"
+    'prefer-arrow-callback': 0, // -要求回调函数使用箭头函数。选项:对象默认{ allowNamedFunctions: false, allowUnboundThis: true }
+    'prefer-const': 2, // -要求使用 const 声明那些声明后不再被修改的变量。首选const。
+    'prefer-destructuring': 0, // -优先使用数组和对象解构。选项:对象
+    'prefer-numeric-literals': 1, // -禁用 parseInt() 和 Number.parseInt(),使用二进制,八进制和十六进制字面量。
+    'prefer-rest-params': 0, // 要求使用剩余参数而不是 arguments。因为arguments 没有 Array.prototype 方法,有点不方便。
+    'prefer-spread': 0, // 要求使用扩展运算符而非 .apply()。首选展开运算。
+    'prefer-template': 0, // -要求使用模板字面量而非字符串连接。
+    'require-yield': 2, // 要求 generator 函数内有 yield。生成器函数必须有yield
+    'rest-spread-spacing': [2, 'never'], // -强制剩余和扩展运算符及其表达式之间有空格。选项:字符串"never"(默认),"always"
+    'sort-imports': 0, // -强制模块内的 import 排序。选项:对象ignoreCase (默认:false),ignoreDeclarationSort (默认: false),ignoreMemberSort (默认:false),memberSyntaxSortOrder (默认:["none", "all", "multiple", "single"])
+    'symbol-description': 0, // 要求 symbol 描述。
+    'template-curly-spacing': [2, 'never'], // -要求或禁止模板字符串中的嵌入表达式周围空格的使用。选项:字符串"never" (默认),"always"。
+    'yield-star-spacing': [
+      2,
+      {
+        before: true,
+        after: true
+      }
+    ] // -强制在 yield* 表达式中 * 周围使用空格。选项:1字符串 2对象默认{"before": false, "after": true}
+
+    // Deprecated:
+    /*
+		  Deprecated rule,Replaced by
+		  indent-legacy,indent
+		  lines-around-directive,padding-line-between-statements
+		  newline-after-var,adding-line-between-statements
+		  newline-before-return,padding-line-between-statements
+		  no-catch-shadow,no-shadow
+		  no-native-reassign,no-global-assign
+		  no-negated-in-lhs,no-unsafe-negation
+		  no-spaced-func,func-call-spacing
+		  prefer-reflect,(no replacement)
+		  require-jsdoc,(no replacement)
+		  valid-jsdoc,(no replacement)
+		*/
+
+    // Removed:These rules from older versions of ESLint (before the deprecation policy existed) have been replaced by newer rules
+    /*
+		  Removed rule,Replaced by
+		  generator-star,generator-star-spacing
+		  global-strict,strict
+		  no-arrow-condition,no-confusing-arrowno-constant-condition
+		  no-comma-dangle,comma-dangle
+		  no-empty-class,no-empty-character-class
+		  no-empty-label,no-labels
+		  no-extra-strict,strict
+		  no-reserved-keys,quote-props
+		  no-space-before-semi,semi-spacing
+		  no-wrap-func,no-extra-parens
+		  space-after-function-name,space-before-function-paren
+		  space-after-keywords,keyword-spacing
+		  space-before-function-parentheses,space-before-function-paren
+		  space-before-keywords,keyword-spacing
+		  space-in-brackets,object-curly-spacingarray-bracket-spacing
+		  space-return-throw-case,keyword-spacing
+		  space-unary-word-ops,space-unary-ops
+		  spaced-line-comment,spaced-comment
+		*/
+  }
+}
+
+/*
+在VSCode中使用ESLint:
+安装VSCode插件:Prettier ESLint(prettier-eslint),ESLint,Prettier,Vetur(这个没用)。
+保存时,(ide)编辑器(如VSCode)执行顺序:(注意在HBuilderX中②③的顺序相反)
+①ide的ESLint插件对不符合配置规则的地方进行实时标红(保存之前)
+②读取配置文件.eslintrc.js,ide的ESLint插件进行修改。(相当于编辑器帮你执行了eslint --fix)
+③编辑器用选择好的(默认的)格式化程序(如Prettier或Prettier ESLint来)进行格式化(不用Vetur,主要是因为其只针对vue文件且有缺陷):
+如果是Prettier,则对js文件和vue文件都是不能细化到ESLint里面的规则进行修正(例如数组应该换行的却不换行,该有空格的却没有空格,且可能对vue的html模板有其它影响)。
+如果是prettier-eslint,则对js文件和vue文件能够细化到ESLint里面的规则进行修正,因为Prettier ESLint首先会检查根路径有没有eslint的配置文件,有则根据里面的规则进行格式化,再根据自己本身的默认规则(包)进行格式化且会去掉和eslint冲突的部分。
+(如果是Prettier ESLint,则会读取项目目录下的eslint包和prettier包进行修复,如果只是ESLint,则会读取项目目录下的eslint包或全局的eslint包)
+Prettier ESLint完全没用
+如果是Vetur,则不能对js文件进行格式化,对vue文件即使对里面的js模板使用prettier-eslint也依然不能细化到ESLint里面的规则进行修正,因为Vetur使用的prettier-eslint(完全没用,还是会变回prettier),是根据Prettier ESLint插件本身的默认规则(包)来进行格式化的,不会读取到eslint的配置文件。
+④(重新运行项目)对于vue项目,脚手架内部会使用eslint进行代码规范检查(不符合规范则在终端里报错)(相当于vue项目帮执行了eslint的检查文件命令)
+VSCode的settings.json文件配置:
+{
+	"editor.tabSize": 2,
+	"editor.detectIndentation": false,
+	"security.workspace.trust.untrustedFiles": "open",
+	"workbench.editorAssociations": {
+		"*.backup": "default"
+	},
+	"files.associations": {
+		"*.cjson": "jsonc",
+		"*.wxss": "css",
+		"*.wxs": "javascript"
+	},
+	"emmet.includeLanguages": {
+		"wxml": "html"
+	},
+	"minapp-vscode.disableAutoConfig": true,
+	"diffEditor.ignoreTrimWhitespace": false,
+	"editor.minimap.maxColumn": 50,
+	"explorer.confirmDelete": false,
+	"[html]": {
+		"editor.defaultFormatter": "vscode.html-language-features"
+	},
+	"[vue]": {
+		// "editor.defaultFormatter": "octref.vetur"
+		"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
+	},
+	"[javascript]": {
+		// "editor.defaultFormatter": "esbenp.prettier-vscode"
+		"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
+	},
+	"[json]": {
+		"editor.defaultFormatter": "vscode.json-language-features"
+	},
+	//编辑器配置: //或者在UI界面里面设置
+	"files.eol": "\n",
+	"editor.tabCompletion": "on",
+	"editor.insertSpaces": false,
+	"editor.formatOnSave": true,
+	"editor.formatOnPaste": true,
+	"editor.defaultFormatter": "rvest.vs-code-prettier-eslint",
+	"editor.codeActionsOnSave": {
+		"source.fixAll.eslint": true
+	},
+	//Vetur
+	"vetur.format.defaultFormatter.js": "prettier-eslint",
+	"vetur.format.options.useTabs": true,
+	//ESLint:
+	"eslint.alwaysShowStatus": true,
+	"eslint.format.enable": true,
+	"eslint.run": "onType",
+	"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact", "html", "vue"],
+	// "eslint.nodePath": "d:\\node_modules",
+	// "eslint.nodePath": "d:\\wang\\nvm\\nvm\\v14.19.0\\node_modules\\eslint-plugin-vue\\node_modules",
+	// "eslint.options": {
+	// 	"plugins": ["html"],
+	// 	"extensions": [".js", ".vue", ".jsx", ".tsx"]
+	// },
+	//Prettier 用来替代lint中的一些场景,如分号、tab缩进、空格、引号等(这些问题lint工具不能自动修复)
+	"prettier.printWidth": 180,
+	"prettier.quoteProps": "consistent",
+	"prettier.semi": false,
+	"prettier.singleQuote": true,
+	"prettier.trailingComma": "none",
+	"prettier.useTabs": true,
+	"prettier.bracketSpacing": true,
+	"prettier.proseWrap": "preserve"
+}
+.prettierrc文件配置:
+{
+	"printWidth": 180,
+	"semi": false,
+	"tabWidth": 2,
+	"useTabs": true,
+	"singleQuote": true,
+	"trailingComma": "none",
+	"bracketSpacing": true,
+	"htmlWhitespaceSensitivity": "css",
+	"arrowParens": "always",
+	"quoteProps": "consistent",
+	"jsxSingleQuote": false,
+	"bracketSameLine": true,
+	"proseWrap": "preserve",
+	"vueIndentScriptAndStyle": false,
+	"endOfLine": "lf",
+	"embeddedLanguageFormatting": "auto",
+	"singleAttributePerLine": false
+}
+在HBuilderX中的Prettier插件的prettier.config文件配置:
+module.exports = {
+	printWidth: 180,
+	semi: false,
+	tabWidth: 2,
+	useTabs: true,
+	singleQuote: true,
+	trailingComma: "none",
+	bracketSpacing: true,
+	htmlWhitespaceSensitivity: "css",
+	arrowParens: "always",
+	quoteProps: "consistent",
+	jsxSingleQuote: false,
+	bracketSameLine: true,
+	proseWrap: "preserve",
+	vueIndentScriptAndStyle: false,
+	endOfLine: "lf",
+	embeddedLanguageFormatting: "auto",
+	singleAttributePerLine: false,
+	parsers: {
+		".jsx": "flow",
+		".scss": "scss",
+		".ts": "typescript",
+		".less": "css",
+		".vue": "vue",
+		".nvue": "vue",
+		".ux": "vue",
+		".yml": "yaml",
+	}
+}
+注意:
+①在项目里面:
+1如果项目里面有eslint配置文件:
+则会调用配置文件所在目录下的eslint包。所以需要用到eslint(npm包),需要安装对应的npm包npm i eslint@6.8.0 -D,注意这里安装的是6.8.0或以下的版本
+在该配置文件里,parser使用了'babel-eslint'(即Babel-ESLint解析器),则需要安装对应的npm包npm i babel-eslint -D。(若不是在项目里面,则不需要安装)
+在该配置文件里,extends里含有'plugin:vue/recommended',则需要安装对应的npm包npm i eslint-plugin-vue -D。(若就算不是在项目里面,也需要安装,安装在配置文件的目录下)
+2如果项目里面没有eslint配置文件:
+则编辑器的ESLint插件,会从该文件同层级目录中寻找,依次到父目录,直到盘符根目录,直到读取到eslint配置文件。
+然后调用项目里的node_modules目录下的eslint包和babel-eslint包和eslint-plugin-vue包来执行,如果项目里面没有node_modules目录(没有这些包),则
+调用全局的eslint包和babel-eslint包进行解析,再调用项目目录下的node_modules目录下的eslint-plugin-vue包(如果没有则调用配置文件所在目录下的eslint-plugin-vue包,但可能会报错,报错则建议去掉配置文件里写上的引用的插件,因为node的原因找不到对应的包)。然后对文件进行实时标红和修复(用ESLint插件进行修复--fix,而不是Prettier ESLint)。
+②如果不在项目(目录)里面:(如单独的一个文件在盘符下的任意地方,而配置文件在盘符根目录):
+则需要在该目录下或父级目录下有配置文件,且需要安装全局的eslint,npm i eslint -g,不限版本。
+然后调用全局的eslint包和babel-eslint包进行解析,再调用文件目录下的node_modules目录下的eslint-plugin-vue包(如果没有则调用配置文件所在目录下的eslint-plugin-vue包)。然后对文件进行实时标红和修复(用ESLint插件进行修复--fix,而不是Prettier ESLint)。
+其它插件介绍:
+eslint-plugin-prettier 将 Prettier 的规则设置到 ESLint 的规则中。eslint-config-prettier 关闭 ESLint 中与 Prettier 中会发生冲突的规则。
+然后可以npm i eslint-plugin-prettier eslint-config-prettier -D
+配置:
+{
+  "extends": ["plugin:prettier/recommended"]
+}
+相当于:
+{
+  "extends": ["prettier"],
+  "plugins": ["prettier"],
+  "rules": {
+    "prettier/prettier": "error",
+    "arrow-body-style": "off",
+    "prefer-arrow-callback": "off"
+  }
+}
+另外:
+关于报错:
+报错1
+TypeScript intellisense is disabled on template. To enable, configure `"jsx": "preserve"` in the `"compilerOptions"` property of tsconfig or jsconfig. To disable this prompt instead, configure `"experimentalDisableTemplateSupport": true` in `"vueCompilerOptions"` property.
+解决方法:
+要在jsconfig.json文件里重新写入:
+{
+  "compilerOptions": {
+    "target": "es5",
+    "module": "esnext",
+    "baseUrl": "./",
+    "jsx": "preserve",	//在这里添加"jsx": "preserve",
+    "moduleResolution": "node",
+    "paths": {
+      "@/*": [
+        "src/*"
+      ]
+    },
+    "lib": [
+      "esnext",
+      "dom",
+      "dom.iterable",
+      "scripthost"
+    ]
+  },
+  "exclude": ["node_modules", "dist"]
+}
+报错2
+Parsing error: require() of ES Module D:\。。。\node_modules\eslint-scope\lib\definition.js from D:\。。。\node_modules\babel-eslint\lib\require-from-eslint.js not supported.
+Instead change the require of definition.js in D:\。。。\node_modules\babel-eslint\lib\require-from-eslint.js to a dynamic import() which is available in all CommonJS modules.
+是因为当前的eslint版本(例如,如果下载的是最新版8.22.0等等)过高,这些版本不支持在CommonJS模块中使用。
+解决方法:
+方法1,将node版本升级到xx以上,根据官网(https://eslint.org/docs/user-guide/getting-started)介绍,node版本需要^12.22.0, ^14.17.0, or >=16.0.0才行。
+方法2,将 eslint 降级到版本6.8.0(7.0.0 之前的最后一个版本)。此版本仍包含createRequire(可以读取CommonJS模块)这里用的是"devDependencies": {"babel-eslint": "^10.1.0","eslint": "^6.8.0","eslint-plugin-vue": "^9.3.0"}。(但是如果用的是最新的全局的eslint包,也不会报此错误)
+*/

+ 15 - 0
.gitignore

@@ -0,0 +1,15 @@
+.DS_Store
+node_modules/
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+tests/**/coverage/
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+dist/

+ 5 - 0
.travis.yml

@@ -0,0 +1,5 @@
+language: node_js
+node_js: 10
+script: npm run test
+notifications:
+  email: false

+ 2 - 0
Dockerfile

@@ -0,0 +1,2 @@
+FROM registry.cn-guangdong.aliyuncs.com/shop/nginx
+COPY dist/ /home/ui-admin/

+ 21 - 0
LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023-present zweiqin
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 21 - 0
README.md

@@ -0,0 +1,21 @@
+
+shop 前端源码
+
+#### 项目源码
+
+
+
+#### 项目基础要求
+node:10.0.0及以上
+npm:最新的即可
+
+
+#### Build Setup
+``` bash
+
+# 安装依赖
+npm install
+
+# 启动服务 localhost:8013
+npm run dev
+

+ 14 - 0
babel.config.js

@@ -0,0 +1,14 @@
+module.exports = {
+  presets: [
+    // https://github.com/vuejs/vue-cli/tree/master/packages/@vue/babel-preset-app
+    '@vue/cli-plugin-babel/preset'
+  ],
+  'env': {
+    'development': {
+      // babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require().
+      // This plugin can significantly increase the speed of hot updates, when you have a large number of pages.
+      // https://panjiachen.github.io/vue-element-admin-site/guide/advanced/lazy-loading.html
+      'plugins': ['dynamic-import-node']
+    }
+  }
+}

+ 35 - 0
build/index.js

@@ -0,0 +1,35 @@
+const { run } = require('runjs')
+const chalk = require('chalk')
+const config = require('../vue.config.js')
+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 = config.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}`)
+}

+ 11 - 0
canvas-container/App.vue

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

二进制
canvas-container/assets/font/DIN-Bold.eot


二进制
canvas-container/assets/font/DIN-Bold.otf


二进制
canvas-container/assets/font/DIN-Bold.ttf


二进制
canvas-container/assets/font/DIN-Bold.woff


二进制
canvas-container/assets/font/DIN-Bold.woff2


+ 539 - 0
canvas-container/assets/font_icon/demo.css

@@ -0,0 +1,539 @@
+/* Logo 字体 */
+@font-face {
+  font-family: "iconfont logo";
+  src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
+  src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
+}
+
+.logo {
+  font-family: "iconfont logo";
+  font-size: 160px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+/* tabs */
+.nav-tabs {
+  position: relative;
+}
+
+.nav-tabs .nav-more {
+  position: absolute;
+  right: 0;
+  bottom: 0;
+  height: 42px;
+  line-height: 42px;
+  color: #666;
+}
+
+#tabs {
+  border-bottom: 1px solid #eee;
+}
+
+#tabs li {
+  cursor: pointer;
+  width: 100px;
+  height: 40px;
+  line-height: 40px;
+  text-align: center;
+  font-size: 16px;
+  border-bottom: 2px solid transparent;
+  position: relative;
+  z-index: 1;
+  margin-bottom: -1px;
+  color: #666;
+}
+
+
+#tabs .active {
+  border-bottom-color: #f00;
+  color: #222;
+}
+
+.tab-container .content {
+  display: none;
+}
+
+/* 页面布局 */
+.main {
+  padding: 30px 100px;
+  width: 960px;
+  margin: 0 auto;
+}
+
+.main .logo {
+  color: #333;
+  text-align: left;
+  margin-bottom: 30px;
+  line-height: 1;
+  height: 110px;
+  margin-top: -50px;
+  overflow: hidden;
+  *zoom: 1;
+}
+
+.main .logo a {
+  font-size: 160px;
+  color: #333;
+}
+
+.helps {
+  margin-top: 40px;
+}
+
+.helps pre {
+  padding: 20px;
+  margin: 10px 0;
+  border: solid 1px #e7e1cd;
+  background-color: #fffdef;
+  overflow: auto;
+}
+
+.icon_lists {
+  width: 100% !important;
+  overflow: hidden;
+  *zoom: 1;
+}
+
+.icon_lists li {
+  width: 100px;
+  margin-bottom: 10px;
+  margin-right: 20px;
+  text-align: center;
+  list-style: none !important;
+  cursor: default;
+}
+
+.icon_lists li .code-name {
+  line-height: 1.2;
+}
+
+.icon_lists .icon {
+  display: block;
+  height: 100px;
+  line-height: 100px;
+  font-size: 42px;
+  margin: 10px auto;
+  color: #333;
+  -webkit-transition: font-size 0.25s linear, width 0.25s linear;
+  -moz-transition: font-size 0.25s linear, width 0.25s linear;
+  transition: font-size 0.25s linear, width 0.25s linear;
+}
+
+.icon_lists .icon:hover {
+  font-size: 100px;
+}
+
+.icon_lists .svg-icon {
+  /* 通过设置 font-size 来改变图标大小 */
+  width: 1em;
+  /* 图标和文字相邻时,垂直对齐 */
+  vertical-align: -0.15em;
+  /* 通过设置 color 来改变 SVG 的颜色/fill */
+  fill: currentColor;
+  /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
+      normalize.css 中也包含这行 */
+  overflow: hidden;
+}
+
+.icon_lists li .name,
+.icon_lists li .code-name {
+  color: #666;
+}
+
+/* markdown 样式 */
+.markdown {
+  color: #666;
+  font-size: 14px;
+  line-height: 1.8;
+}
+
+.highlight {
+  line-height: 1.5;
+}
+
+.markdown img {
+  vertical-align: middle;
+  max-width: 100%;
+}
+
+.markdown h1 {
+  color: #404040;
+  font-weight: 500;
+  line-height: 40px;
+  margin-bottom: 24px;
+}
+
+.markdown h2,
+.markdown h3,
+.markdown h4,
+.markdown h5,
+.markdown h6 {
+  color: #404040;
+  margin: 1.6em 0 0.6em 0;
+  font-weight: 500;
+  clear: both;
+}
+
+.markdown h1 {
+  font-size: 28px;
+}
+
+.markdown h2 {
+  font-size: 22px;
+}
+
+.markdown h3 {
+  font-size: 16px;
+}
+
+.markdown h4 {
+  font-size: 14px;
+}
+
+.markdown h5 {
+  font-size: 12px;
+}
+
+.markdown h6 {
+  font-size: 12px;
+}
+
+.markdown hr {
+  height: 1px;
+  border: 0;
+  background: #e9e9e9;
+  margin: 16px 0;
+  clear: both;
+}
+
+.markdown p {
+  margin: 1em 0;
+}
+
+.markdown>p,
+.markdown>blockquote,
+.markdown>.highlight,
+.markdown>ol,
+.markdown>ul {
+  width: 80%;
+}
+
+.markdown ul>li {
+  list-style: circle;
+}
+
+.markdown>ul li,
+.markdown blockquote ul>li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown>ul li p,
+.markdown>ol li p {
+  margin: 0.6em 0;
+}
+
+.markdown ol>li {
+  list-style: decimal;
+}
+
+.markdown>ol li,
+.markdown blockquote ol>li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown code {
+  margin: 0 3px;
+  padding: 0 5px;
+  background: #eee;
+  border-radius: 3px;
+}
+
+.markdown strong,
+.markdown b {
+  font-weight: 600;
+}
+
+.markdown>table {
+  border-collapse: collapse;
+  border-spacing: 0px;
+  empty-cells: show;
+  border: 1px solid #e9e9e9;
+  width: 95%;
+  margin-bottom: 24px;
+}
+
+.markdown>table th {
+  white-space: nowrap;
+  color: #333;
+  font-weight: 600;
+}
+
+.markdown>table th,
+.markdown>table td {
+  border: 1px solid #e9e9e9;
+  padding: 8px 16px;
+  text-align: left;
+}
+
+.markdown>table th {
+  background: #F7F7F7;
+}
+
+.markdown blockquote {
+  font-size: 90%;
+  color: #999;
+  border-left: 4px solid #e9e9e9;
+  padding-left: 0.8em;
+  margin: 1em 0;
+}
+
+.markdown blockquote p {
+  margin: 0;
+}
+
+.markdown .anchor {
+  opacity: 0;
+  transition: opacity 0.3s ease;
+  margin-left: 8px;
+}
+
+.markdown .waiting {
+  color: #ccc;
+}
+
+.markdown h1:hover .anchor,
+.markdown h2:hover .anchor,
+.markdown h3:hover .anchor,
+.markdown h4:hover .anchor,
+.markdown h5:hover .anchor,
+.markdown h6:hover .anchor {
+  opacity: 1;
+  display: inline-block;
+}
+
+.markdown>br,
+.markdown>p>br {
+  clear: both;
+}
+
+
+.hljs {
+  display: block;
+  background: white;
+  padding: 0.5em;
+  color: #333333;
+  overflow-x: auto;
+}
+
+.hljs-comment,
+.hljs-meta {
+  color: #969896;
+}
+
+.hljs-string,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-strong,
+.hljs-emphasis,
+.hljs-quote {
+  color: #df5000;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-type {
+  color: #a71d5d;
+}
+
+.hljs-literal,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-attribute {
+  color: #0086b3;
+}
+
+.hljs-section,
+.hljs-name {
+  color: #63a35c;
+}
+
+.hljs-tag {
+  color: #333333;
+}
+
+.hljs-title,
+.hljs-attr,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-selector-attr,
+.hljs-selector-pseudo {
+  color: #795da3;
+}
+
+.hljs-addition {
+  color: #55a532;
+  background-color: #eaffea;
+}
+
+.hljs-deletion {
+  color: #bd2c00;
+  background-color: #ffecec;
+}
+
+.hljs-link {
+  text-decoration: underline;
+}
+
+/* 代码高亮 */
+/* PrismJS 1.15.0
+https://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;
+  background: none;
+  text-shadow: 0 1px white;
+  font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
+  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;
+  white-space: normal;
+}
+
+.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: #9a6e3a;
+  background: hsla(0, 0%, 100%, .5);
+}
+
+.token.atrule,
+.token.attr-value,
+.token.keyword {
+  color: #07a;
+}
+
+.token.function,
+.token.class-name {
+  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;
+}

+ 2242 - 0
canvas-container/assets/font_icon/demo_index.html

@@ -0,0 +1,2242 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+	<meta charset="utf-8" />
+	<title>iconfont Demo</title>
+	<link rel="shortcut icon" href="//img.alicdn.com/imgextra/i2/O1CN01ZyAlrn1MwaMhqz36G_!!6000000001499-73-tps-64-64.ico"
+		type="image/x-icon" />
+	<link rel="icon" type="image/svg+xml"
+		href="//img.alicdn.com/imgextra/i4/O1CN01EYTRnJ297D6vehehJ_!!6000000008020-55-tps-64-64.svg" />
+	<link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
+	<link rel="stylesheet" href="demo.css">
+	<link rel="stylesheet" href="iconfont.css">
+	<script src="iconfont.js"></script>
+	<!-- jQuery -->
+	<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
+	<!-- 代码高亮 -->
+	<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
+	<style>
+		.main .logo {
+			margin-top: 0;
+			height: auto;
+		}
+
+		.main .logo a {
+			display: flex;
+			align-items: center;
+		}
+
+		.main .logo .sub-title {
+			margin-left: 0.5em;
+			font-size: 22px;
+			color: #fff;
+			background: linear-gradient(-45deg, #3967FF, #B500FE);
+			-webkit-background-clip: text;
+			-webkit-text-fill-color: transparent;
+		}
+	</style>
+</head>
+
+<body>
+	<div class="main">
+		<h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">
+				<img width="200"
+					src="https://img.alicdn.com/imgextra/i3/O1CN01Mn65HV1FfSEzR6DKv_!!6000000000514-55-tps-228-59.svg">
+
+			</a></h1>
+		<div class="nav-tabs">
+			<ul id="tabs" class="dib-box">
+				<li class="dib active"><span>Unicode</span></li>
+				<li class="dib"><span>Font class</span></li>
+				<li class="dib"><span>Symbol</span></li>
+			</ul>
+
+			<a href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=8888888" target="_blank"
+				class="nav-more">查看项目</a>
+
+		</div>
+		<div class="tab-container">
+			<div class="content unicode" style="display: block;">
+				<ul class="icon_lists dib-box">
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe7d5;</span>
+						<div class="name">直播</div>
+						<div class="code-name">&amp;#xe7d5;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe683;</span>
+						<div class="name">轮播</div>
+						<div class="code-name">&amp;#xe683;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe6db;</span>
+						<div class="name">new</div>
+						<div class="code-name">&amp;#xe6db;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe61f;</span>
+						<div class="name">会员</div>
+						<div class="code-name">&amp;#xe61f;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe676;</span>
+						<div class="name">商品</div>
+						<div class="code-name">&amp;#xe676;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe6f0;</span>
+						<div class="name">公告</div>
+						<div class="code-name">&amp;#xe6f0;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe66f;</span>
+						<div class="name">魔方</div>
+						<div class="code-name">&amp;#xe66f;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe601;</span>
+						<div class="name">arrange1</div>
+						<div class="code-name">&amp;#xe601;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe604;</span>
+						<div class="name">price</div>
+						<div class="code-name">&amp;#xe604;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe605;</span>
+						<div class="name">arrange2</div>
+						<div class="code-name">&amp;#xe605;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xea7a;</span>
+						<div class="name">公告</div>
+						<div class="code-name">&amp;#xea7a;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe650;</span>
+						<div class="name">秒杀</div>
+						<div class="code-name">&amp;#xe650;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe652;</span>
+						<div class="name">折扣</div>
+						<div class="code-name">&amp;#xe652;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe653;</span>
+						<div class="name">拼团</div>
+						<div class="code-name">&amp;#xe653;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe64b;</span>
+						<div class="name">秒杀1</div>
+						<div class="code-name">&amp;#xe64b;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe64c;</span>
+						<div class="name">新品</div>
+						<div class="code-name">&amp;#xe64c;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe64d;</span>
+						<div class="name">折扣1</div>
+						<div class="code-name">&amp;#xe64d;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe64e;</span>
+						<div class="name">头部</div>
+						<div class="code-name">&amp;#xe64e;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe64f;</span>
+						<div class="name">拼团1</div>
+						<div class="code-name">&amp;#xe64f;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe607;</span>
+						<div class="name">长方形</div>
+						<div class="code-name">&amp;#xe607;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe674;</span>
+						<div class="name">空</div>
+						<div class="code-name">&amp;#xe674;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe621;</span>
+						<div class="name">优惠券3</div>
+						<div class="code-name">&amp;#xe621;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe624;</span>
+						<div class="name">优惠券4</div>
+						<div class="code-name">&amp;#xe624;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe625;</span>
+						<div class="name">优惠券2</div>
+						<div class="code-name">&amp;#xe625;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe626;</span>
+						<div class="name">优惠券1</div>
+						<div class="code-name">&amp;#xe626;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe628;</span>
+						<div class="name">卡片8</div>
+						<div class="code-name">&amp;#xe628;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe62a;</span>
+						<div class="name">卡片6</div>
+						<div class="code-name">&amp;#xe62a;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe62e;</span>
+						<div class="name">卡片7</div>
+						<div class="code-name">&amp;#xe62e;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe627;</span>
+						<div class="name">卡片1</div>
+						<div class="code-name">&amp;#xe627;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe629;</span>
+						<div class="name">卡片3</div>
+						<div class="code-name">&amp;#xe629;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe62b;</span>
+						<div class="name">卡片2</div>
+						<div class="code-name">&amp;#xe62b;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe62c;</span>
+						<div class="name">卡片5</div>
+						<div class="code-name">&amp;#xe62c;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe62f;</span>
+						<div class="name">卡片4</div>
+						<div class="code-name">&amp;#xe62f;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe630;</span>
+						<div class="name">app</div>
+						<div class="code-name">&amp;#xe630;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe631;</span>
+						<div class="name">辅助分割</div>
+						<div class="code-name">&amp;#xe631;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe632;</span>
+						<div class="name">pc</div>
+						<div class="code-name">&amp;#xe632;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe634;</span>
+						<div class="name">h5</div>
+						<div class="code-name">&amp;#xe634;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe635;</span>
+						<div class="name">图文</div>
+						<div class="code-name">&amp;#xe635;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe636;</span>
+						<div class="name">商品列表</div>
+						<div class="code-name">&amp;#xe636;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe637;</span>
+						<div class="name">类别列表</div>
+						<div class="code-name">&amp;#xe637;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe638;</span>
+						<div class="name">视频</div>
+						<div class="code-name">&amp;#xe638;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe639;</span>
+						<div class="name">图文导航</div>
+						<div class="code-name">&amp;#xe639;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe63a;</span>
+						<div class="name">自定义</div>
+						<div class="code-name">&amp;#xe63a;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe63b;</span>
+						<div class="name">小程序</div>
+						<div class="code-name">&amp;#xe63b;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe63c;</span>
+						<div class="name">图文列表</div>
+						<div class="code-name">&amp;#xe63c;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe63d;</span>
+						<div class="name">优惠券</div>
+						<div class="code-name">&amp;#xe63d;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe63e;</span>
+						<div class="name">文本</div>
+						<div class="code-name">&amp;#xe63e;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe640;</span>
+						<div class="name">品牌列表</div>
+						<div class="code-name">&amp;#xe640;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe641;</span>
+						<div class="name">店铺头部</div>
+						<div class="code-name">&amp;#xe641;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe642;</span>
+						<div class="name">魔方</div>
+						<div class="code-name">&amp;#xe642;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe643;</span>
+						<div class="name">一行两个</div>
+						<div class="code-name">&amp;#xe643;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe644;</span>
+						<div class="name">一行三个</div>
+						<div class="code-name">&amp;#xe644;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe645;</span>
+						<div class="name">一行四个</div>
+						<div class="code-name">&amp;#xe645;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe646;</span>
+						<div class="name">一左两右</div>
+						<div class="code-name">&amp;#xe646;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe647;</span>
+						<div class="name">两行两个</div>
+						<div class="code-name">&amp;#xe647;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe648;</span>
+						<div class="name">一上两下</div>
+						<div class="code-name">&amp;#xe648;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe602;</span>
+						<div class="name">close</div>
+						<div class="code-name">&amp;#xe602;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe66c;</span>
+						<div class="name">替换图片</div>
+						<div class="code-name">&amp;#xe66c;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe62d;</span>
+						<div class="name">选择</div>
+						<div class="code-name">&amp;#xe62d;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe661;</span>
+						<div class="name">选择</div>
+						<div class="code-name">&amp;#xe661;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe618;</span>
+						<div class="name">选择</div>
+						<div class="code-name">&amp;#xe618;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe608;</span>
+						<div class="name">警告</div>
+						<div class="code-name">&amp;#xe608;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe651;</span>
+						<div class="name">删 除</div>
+						<div class="code-name">&amp;#xe651;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe622;</span>
+						<div class="name">查看</div>
+						<div class="code-name">&amp;#xe622;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe60a;</span>
+						<div class="name">问号</div>
+						<div class="code-name">&amp;#xe60a;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe73f;</span>
+						<div class="name">方块</div>
+						<div class="code-name">&amp;#xe73f;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe633;</span>
+						<div class="name">删除</div>
+						<div class="code-name">&amp;#xe633;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe64a;</span>
+						<div class="name">图片</div>
+						<div class="code-name">&amp;#xe64a;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe61e;</span>
+						<div class="name">图片</div>
+						<div class="code-name">&amp;#xe61e;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe703;</span>
+						<div class="name">拖动位置</div>
+						<div class="code-name">&amp;#xe703;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe603;</span>
+						<div class="name">add</div>
+						<div class="code-name">&amp;#xe603;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe649;</span>
+						<div class="name">文本</div>
+						<div class="code-name">&amp;#xe649;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe600;</span>
+						<div class="name">A</div>
+						<div class="code-name">&amp;#xe600;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe8c2;</span>
+						<div class="name">文本</div>
+						<div class="code-name">&amp;#xe8c2;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xec82;</span>
+						<div class="name">右对齐</div>
+						<div class="code-name">&amp;#xec82;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xec86;</span>
+						<div class="name">左对齐</div>
+						<div class="code-name">&amp;#xec86;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe619;</span>
+						<div class="name">居中</div>
+						<div class="code-name">&amp;#xe619;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe664;</span>
+						<div class="name">add</div>
+						<div class="code-name">&amp;#xe664;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe63f;</span>
+						<div class="name">搜索</div>
+						<div class="code-name">&amp;#xe63f;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe660;</span>
+						<div class="name">导航</div>
+						<div class="code-name">&amp;#xe660;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe685;</span>
+						<div class="name">加上</div>
+						<div class="code-name">&amp;#xe685;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe687;</span>
+						<div class="name">检查</div>
+						<div class="code-name">&amp;#xe687;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe68a;</span>
+						<div class="name">减去</div>
+						<div class="code-name">&amp;#xe68a;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe695;</span>
+						<div class="name">箭头</div>
+						<div class="code-name">&amp;#xe695;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe6ab;</span>
+						<div class="name">箭头</div>
+						<div class="code-name">&amp;#xe6ab;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe6bc;</span>
+						<div class="name">箭头</div>
+						<div class="code-name">&amp;#xe6bc;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe771;</span>
+						<div class="name">列表</div>
+						<div class="code-name">&amp;#xe771;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe67d;</span>
+						<div class="name">user</div>
+						<div class="code-name">&amp;#xe67d;</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont">&#xe623;</span>
+						<div class="name">Shopping cart, finance, business</div>
+						<div class="code-name">&amp;#xe623;</div>
+					</li>
+
+				</ul>
+				<div class="article markdown">
+					<h2 id="unicode-">Unicode 引用</h2>
+					<hr>
+
+					<p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
+					<ul>
+						<li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
+						<li>默认情况下不支持多色,直接添加多色图标会自动去色。</li>
+					</ul>
+					<blockquote>
+						<p>注意:新版 iconfont 支持两种方式引用多色图标:SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)</p>
+					</blockquote>
+					<p>Unicode 使用步骤如下:</p>
+					<h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
+					<pre><code class="language-css"
+>@font-face {
+  font-family: 'iconfont';
+  src: url('iconfont.woff2?t=1638330949259') format('woff2'),
+       url('iconfont.woff?t=1638330949259') format('woff'),
+       url('iconfont.ttf?t=1638330949259') format('truetype');
+}
+</code></pre>
+					<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
+					<pre><code class="language-css"
+>.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+</code></pre>
+					<h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
+					<pre>
+<code class="language-html"
+>&lt;span class="iconfont"&gt;&amp;#x33;&lt;/span&gt;
+</code></pre>
+					<blockquote>
+						<p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
+					</blockquote>
+				</div>
+			</div>
+			<div class="content font-class">
+				<ul class="icon_lists dib-box">
+
+					<li class="dib">
+						<span class="icon iconfont icon-zhibo"></span>
+						<div class="name">
+							直播
+						</div>
+						<div class="code-name">.icon-zhibo
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-lunbo"></span>
+						<div class="name">
+							轮播
+						</div>
+						<div class="code-name">.icon-lunbo
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-new"></span>
+						<div class="name">
+							new
+						</div>
+						<div class="code-name">.icon-new
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-huiyuan"></span>
+						<div class="name">
+							会员
+						</div>
+						<div class="code-name">.icon-huiyuan
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-shangpin"></span>
+						<div class="name">
+							商品
+						</div>
+						<div class="code-name">.icon-shangpin
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-gonggao1"></span>
+						<div class="name">
+							公告
+						</div>
+						<div class="code-name">.icon-gonggao1
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-mofang1"></span>
+						<div class="name">
+							魔方
+						</div>
+						<div class="code-name">.icon-mofang1
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-arrange1"></span>
+						<div class="name">
+							arrange1
+						</div>
+						<div class="code-name">.icon-arrange1
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-price"></span>
+						<div class="name">
+							price
+						</div>
+						<div class="code-name">.icon-price
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-arrange2"></span>
+						<div class="name">
+							arrange2
+						</div>
+						<div class="code-name">.icon-arrange2
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-gonggao"></span>
+						<div class="name">
+							公告
+						</div>
+						<div class="code-name">.icon-gonggao
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-miaosha"></span>
+						<div class="name">
+							秒杀
+						</div>
+						<div class="code-name">.icon-miaosha
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-zhekou"></span>
+						<div class="name">
+							折扣
+						</div>
+						<div class="code-name">.icon-zhekou
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-pintuan"></span>
+						<div class="name">
+							拼团
+						</div>
+						<div class="code-name">.icon-pintuan
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-miaosha1"></span>
+						<div class="name">
+							秒杀1
+						</div>
+						<div class="code-name">.icon-miaosha1
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-xinpin"></span>
+						<div class="name">
+							新品
+						</div>
+						<div class="code-name">.icon-xinpin
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-zhekou1"></span>
+						<div class="name">
+							折扣1
+						</div>
+						<div class="code-name">.icon-zhekou1
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-toubu"></span>
+						<div class="name">
+							头部
+						</div>
+						<div class="code-name">.icon-toubu
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-pintuan1"></span>
+						<div class="name">
+							拼团1
+						</div>
+						<div class="code-name">.icon-pintuan1
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-weibiaoti-zhuanhuan-"></span>
+						<div class="name">
+							长方形
+						</div>
+						<div class="code-name">.icon-weibiaoti-zhuanhuan-
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-kong"></span>
+						<div class="name">
+							空
+						</div>
+						<div class="code-name">.icon-kong
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-youhuiquan3"></span>
+						<div class="name">
+							优惠券3
+						</div>
+						<div class="code-name">.icon-youhuiquan3
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-youhuiquan4"></span>
+						<div class="name">
+							优惠券4
+						</div>
+						<div class="code-name">.icon-youhuiquan4
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-youhuiquan2"></span>
+						<div class="name">
+							优惠券2
+						</div>
+						<div class="code-name">.icon-youhuiquan2
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-youhuiquan1"></span>
+						<div class="name">
+							优惠券1
+						</div>
+						<div class="code-name">.icon-youhuiquan1
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-kapian8"></span>
+						<div class="name">
+							卡片8
+						</div>
+						<div class="code-name">.icon-kapian8
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-kapian6"></span>
+						<div class="name">
+							卡片6
+						</div>
+						<div class="code-name">.icon-kapian6
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-kapian7"></span>
+						<div class="name">
+							卡片7
+						</div>
+						<div class="code-name">.icon-kapian7
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-kapian1"></span>
+						<div class="name">
+							卡片1
+						</div>
+						<div class="code-name">.icon-kapian1
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-kapian3"></span>
+						<div class="name">
+							卡片3
+						</div>
+						<div class="code-name">.icon-kapian3
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-kapian2"></span>
+						<div class="name">
+							卡片2
+						</div>
+						<div class="code-name">.icon-kapian2
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-kapian5"></span>
+						<div class="name">
+							卡片5
+						</div>
+						<div class="code-name">.icon-kapian5
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-kapian4"></span>
+						<div class="name">
+							卡片4
+						</div>
+						<div class="code-name">.icon-kapian4
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-app"></span>
+						<div class="name">
+							app
+						</div>
+						<div class="code-name">.icon-app
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-fuzhufenge"></span>
+						<div class="name">
+							辅助分割
+						</div>
+						<div class="code-name">.icon-fuzhufenge
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-pc"></span>
+						<div class="name">
+							pc
+						</div>
+						<div class="code-name">.icon-pc
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-h5"></span>
+						<div class="name">
+							h5
+						</div>
+						<div class="code-name">.icon-h5
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-tuwen"></span>
+						<div class="name">
+							图文
+						</div>
+						<div class="code-name">.icon-tuwen
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-shangpinliebiao"></span>
+						<div class="name">
+							商品列表
+						</div>
+						<div class="code-name">.icon-shangpinliebiao
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-leibieliebiao"></span>
+						<div class="name">
+							类别列表
+						</div>
+						<div class="code-name">.icon-leibieliebiao
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-shipin"></span>
+						<div class="name">
+							视频
+						</div>
+						<div class="code-name">.icon-shipin
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-tuwendaohang"></span>
+						<div class="name">
+							图文导航
+						</div>
+						<div class="code-name">.icon-tuwendaohang
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-zidingyi"></span>
+						<div class="name">
+							自定义
+						</div>
+						<div class="code-name">.icon-zidingyi
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-xiaochengxu"></span>
+						<div class="name">
+							小程序
+						</div>
+						<div class="code-name">.icon-xiaochengxu
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-tuwenliebiao"></span>
+						<div class="name">
+							图文列表
+						</div>
+						<div class="code-name">.icon-tuwenliebiao
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-youhuiquan"></span>
+						<div class="name">
+							优惠券
+						</div>
+						<div class="code-name">.icon-youhuiquan
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-wenben2"></span>
+						<div class="name">
+							文本
+						</div>
+						<div class="code-name">.icon-wenben2
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-pinpailiebiao"></span>
+						<div class="name">
+							品牌列表
+						</div>
+						<div class="code-name">.icon-pinpailiebiao
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-dianputoubu"></span>
+						<div class="name">
+							店铺头部
+						</div>
+						<div class="code-name">.icon-dianputoubu
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-mofang"></span>
+						<div class="name">
+							魔方
+						</div>
+						<div class="code-name">.icon-mofang
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-yihangliangge"></span>
+						<div class="name">
+							一行两个
+						</div>
+						<div class="code-name">.icon-yihangliangge
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-yihangsange"></span>
+						<div class="name">
+							一行三个
+						</div>
+						<div class="code-name">.icon-yihangsange
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-yihangsige"></span>
+						<div class="name">
+							一行四个
+						</div>
+						<div class="code-name">.icon-yihangsige
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-yizuoliangyou"></span>
+						<div class="name">
+							一左两右
+						</div>
+						<div class="code-name">.icon-yizuoliangyou
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-lianghangliangge"></span>
+						<div class="name">
+							两行两个
+						</div>
+						<div class="code-name">.icon-lianghangliangge
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-yishangliangxia"></span>
+						<div class="name">
+							一上两下
+						</div>
+						<div class="code-name">.icon-yishangliangxia
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-close"></span>
+						<div class="name">
+							close
+						</div>
+						<div class="code-name">.icon-close
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-tihuantupian"></span>
+						<div class="name">
+							替换图片
+						</div>
+						<div class="code-name">.icon-tihuantupian
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-xuanze"></span>
+						<div class="name">
+							选择
+						</div>
+						<div class="code-name">.icon-xuanze
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-xuanze-danxuan"></span>
+						<div class="name">
+							选择
+						</div>
+						<div class="code-name">.icon-xuanze-danxuan
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-xuanze1"></span>
+						<div class="name">
+							选择
+						</div>
+						<div class="code-name">.icon-xuanze1
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-jinggao"></span>
+						<div class="name">
+							警告
+						</div>
+						<div class="code-name">.icon-jinggao
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-shanchu1"></span>
+						<div class="name">
+							删 除
+						</div>
+						<div class="code-name">.icon-shanchu1
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-chakan"></span>
+						<div class="name">
+							查看
+						</div>
+						<div class="code-name">.icon-chakan
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-iconfontquestion"></span>
+						<div class="name">
+							问号
+						</div>
+						<div class="code-name">.icon-iconfontquestion
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-fangkuai"></span>
+						<div class="name">
+							方块
+						</div>
+						<div class="code-name">.icon-fangkuai
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-shanchu"></span>
+						<div class="name">
+							删除
+						</div>
+						<div class="code-name">.icon-shanchu
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-tupian"></span>
+						<div class="name">
+							图片
+						</div>
+						<div class="code-name">.icon-tupian
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-tupian1"></span>
+						<div class="name">
+							图片
+						</div>
+						<div class="code-name">.icon-tupian1
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-tuodongweizhi"></span>
+						<div class="name">
+							拖动位置
+						</div>
+						<div class="code-name">.icon-tuodongweizhi
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-add2"></span>
+						<div class="name">
+							add
+						</div>
+						<div class="code-name">.icon-add2
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-wenben"></span>
+						<div class="name">
+							文本
+						</div>
+						<div class="code-name">.icon-wenben
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-A"></span>
+						<div class="name">
+							A
+						</div>
+						<div class="code-name">.icon-A
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-wenben1"></span>
+						<div class="name">
+							文本
+						</div>
+						<div class="code-name">.icon-wenben1
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-youduiqi"></span>
+						<div class="name">
+							右对齐
+						</div>
+						<div class="code-name">.icon-youduiqi
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-zuoduiqi"></span>
+						<div class="name">
+							左对齐
+						</div>
+						<div class="code-name">.icon-zuoduiqi
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-juzhong"></span>
+						<div class="name">
+							居中
+						</div>
+						<div class="code-name">.icon-juzhong
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-add1"></span>
+						<div class="name">
+							add
+						</div>
+						<div class="code-name">.icon-add1
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-sousuo"></span>
+						<div class="name">
+							搜索
+						</div>
+						<div class="code-name">.icon-sousuo
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-arrow-up"></span>
+						<div class="name">
+							导航
+						</div>
+						<div class="code-name">.icon-arrow-up
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-add"></span>
+						<div class="name">
+							加上
+						</div>
+						<div class="code-name">.icon-add
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-success"></span>
+						<div class="name">
+							检查
+						</div>
+						<div class="code-name">.icon-success
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-subtract"></span>
+						<div class="name">
+							减去
+						</div>
+						<div class="code-name">.icon-subtract
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-arrow-down"></span>
+						<div class="name">
+							箭头
+						</div>
+						<div class="code-name">.icon-arrow-down
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-arrow-right"></span>
+						<div class="name">
+							箭头
+						</div>
+						<div class="code-name">.icon-arrow-right
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-arrow-left"></span>
+						<div class="name">
+							箭头
+						</div>
+						<div class="code-name">.icon-arrow-left
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-phone-menu"></span>
+						<div class="name">
+							列表
+						</div>
+						<div class="code-name">.icon-phone-menu
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-user"></span>
+						<div class="name">
+							user
+						</div>
+						<div class="code-name">.icon-user
+						</div>
+					</li>
+
+					<li class="dib">
+						<span class="icon iconfont icon-shoppingCart"></span>
+						<div class="name">
+							Shopping cart, finance, business
+						</div>
+						<div class="code-name">.icon-shoppingCart
+						</div>
+					</li>
+
+				</ul>
+				<div class="article markdown">
+					<h2 id="font-class-">font-class 引用</h2>
+					<hr>
+
+					<p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
+					<p>与 Unicode 使用方式相比,具有如下特点:</p>
+					<ul>
+						<li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
+						<li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
+					</ul>
+					<p>使用步骤如下:</p>
+					<h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
+					<pre><code class="language-html">&lt;link rel="stylesheet" href="./iconfont.css"&gt;
+</code></pre>
+					<h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
+					<pre><code class="language-html">&lt;span class="iconfont icon-xxx"&gt;&lt;/span&gt;
+</code></pre>
+					<blockquote>
+						<p>"
+							iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
+					</blockquote>
+				</div>
+			</div>
+			<div class="content symbol">
+				<ul class="icon_lists dib-box">
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-zhibo"></use>
+						</svg>
+						<div class="name">直播</div>
+						<div class="code-name">#icon-zhibo</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-lunbo"></use>
+						</svg>
+						<div class="name">轮播</div>
+						<div class="code-name">#icon-lunbo</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-new"></use>
+						</svg>
+						<div class="name">new</div>
+						<div class="code-name">#icon-new</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-huiyuan"></use>
+						</svg>
+						<div class="name">会员</div>
+						<div class="code-name">#icon-huiyuan</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-shangpin"></use>
+						</svg>
+						<div class="name">商品</div>
+						<div class="code-name">#icon-shangpin</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-gonggao1"></use>
+						</svg>
+						<div class="name">公告</div>
+						<div class="code-name">#icon-gonggao1</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-mofang1"></use>
+						</svg>
+						<div class="name">魔方</div>
+						<div class="code-name">#icon-mofang1</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-arrange1"></use>
+						</svg>
+						<div class="name">arrange1</div>
+						<div class="code-name">#icon-arrange1</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-price"></use>
+						</svg>
+						<div class="name">price</div>
+						<div class="code-name">#icon-price</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-arrange2"></use>
+						</svg>
+						<div class="name">arrange2</div>
+						<div class="code-name">#icon-arrange2</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-gonggao"></use>
+						</svg>
+						<div class="name">公告</div>
+						<div class="code-name">#icon-gonggao</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-miaosha"></use>
+						</svg>
+						<div class="name">秒杀</div>
+						<div class="code-name">#icon-miaosha</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-zhekou"></use>
+						</svg>
+						<div class="name">折扣</div>
+						<div class="code-name">#icon-zhekou</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-pintuan"></use>
+						</svg>
+						<div class="name">拼团</div>
+						<div class="code-name">#icon-pintuan</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-miaosha1"></use>
+						</svg>
+						<div class="name">秒杀1</div>
+						<div class="code-name">#icon-miaosha1</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-xinpin"></use>
+						</svg>
+						<div class="name">新品</div>
+						<div class="code-name">#icon-xinpin</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-zhekou1"></use>
+						</svg>
+						<div class="name">折扣1</div>
+						<div class="code-name">#icon-zhekou1</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-toubu"></use>
+						</svg>
+						<div class="name">头部</div>
+						<div class="code-name">#icon-toubu</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-pintuan1"></use>
+						</svg>
+						<div class="name">拼团1</div>
+						<div class="code-name">#icon-pintuan1</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-weibiaoti-zhuanhuan-"></use>
+						</svg>
+						<div class="name">长方形</div>
+						<div class="code-name">#icon-weibiaoti-zhuanhuan-</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-kong"></use>
+						</svg>
+						<div class="name">空</div>
+						<div class="code-name">#icon-kong</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-youhuiquan3"></use>
+						</svg>
+						<div class="name">优惠券3</div>
+						<div class="code-name">#icon-youhuiquan3</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-youhuiquan4"></use>
+						</svg>
+						<div class="name">优惠券4</div>
+						<div class="code-name">#icon-youhuiquan4</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-youhuiquan2"></use>
+						</svg>
+						<div class="name">优惠券2</div>
+						<div class="code-name">#icon-youhuiquan2</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-youhuiquan1"></use>
+						</svg>
+						<div class="name">优惠券1</div>
+						<div class="code-name">#icon-youhuiquan1</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-kapian8"></use>
+						</svg>
+						<div class="name">卡片8</div>
+						<div class="code-name">#icon-kapian8</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-kapian6"></use>
+						</svg>
+						<div class="name">卡片6</div>
+						<div class="code-name">#icon-kapian6</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-kapian7"></use>
+						</svg>
+						<div class="name">卡片7</div>
+						<div class="code-name">#icon-kapian7</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-kapian1"></use>
+						</svg>
+						<div class="name">卡片1</div>
+						<div class="code-name">#icon-kapian1</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-kapian3"></use>
+						</svg>
+						<div class="name">卡片3</div>
+						<div class="code-name">#icon-kapian3</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-kapian2"></use>
+						</svg>
+						<div class="name">卡片2</div>
+						<div class="code-name">#icon-kapian2</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-kapian5"></use>
+						</svg>
+						<div class="name">卡片5</div>
+						<div class="code-name">#icon-kapian5</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-kapian4"></use>
+						</svg>
+						<div class="name">卡片4</div>
+						<div class="code-name">#icon-kapian4</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-app"></use>
+						</svg>
+						<div class="name">app</div>
+						<div class="code-name">#icon-app</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-fuzhufenge"></use>
+						</svg>
+						<div class="name">辅助分割</div>
+						<div class="code-name">#icon-fuzhufenge</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-pc"></use>
+						</svg>
+						<div class="name">pc</div>
+						<div class="code-name">#icon-pc</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-h5"></use>
+						</svg>
+						<div class="name">h5</div>
+						<div class="code-name">#icon-h5</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-tuwen"></use>
+						</svg>
+						<div class="name">图文</div>
+						<div class="code-name">#icon-tuwen</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-shangpinliebiao"></use>
+						</svg>
+						<div class="name">商品列表</div>
+						<div class="code-name">#icon-shangpinliebiao</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-leibieliebiao"></use>
+						</svg>
+						<div class="name">类别列表</div>
+						<div class="code-name">#icon-leibieliebiao</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-shipin"></use>
+						</svg>
+						<div class="name">视频</div>
+						<div class="code-name">#icon-shipin</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-tuwendaohang"></use>
+						</svg>
+						<div class="name">图文导航</div>
+						<div class="code-name">#icon-tuwendaohang</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-zidingyi"></use>
+						</svg>
+						<div class="name">自定义</div>
+						<div class="code-name">#icon-zidingyi</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-xiaochengxu"></use>
+						</svg>
+						<div class="name">小程序</div>
+						<div class="code-name">#icon-xiaochengxu</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-tuwenliebiao"></use>
+						</svg>
+						<div class="name">图文列表</div>
+						<div class="code-name">#icon-tuwenliebiao</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-youhuiquan"></use>
+						</svg>
+						<div class="name">优惠券</div>
+						<div class="code-name">#icon-youhuiquan</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-wenben2"></use>
+						</svg>
+						<div class="name">文本</div>
+						<div class="code-name">#icon-wenben2</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-pinpailiebiao"></use>
+						</svg>
+						<div class="name">品牌列表</div>
+						<div class="code-name">#icon-pinpailiebiao</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-dianputoubu"></use>
+						</svg>
+						<div class="name">店铺头部</div>
+						<div class="code-name">#icon-dianputoubu</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-mofang"></use>
+						</svg>
+						<div class="name">魔方</div>
+						<div class="code-name">#icon-mofang</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-yihangliangge"></use>
+						</svg>
+						<div class="name">一行两个</div>
+						<div class="code-name">#icon-yihangliangge</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-yihangsange"></use>
+						</svg>
+						<div class="name">一行三个</div>
+						<div class="code-name">#icon-yihangsange</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-yihangsige"></use>
+						</svg>
+						<div class="name">一行四个</div>
+						<div class="code-name">#icon-yihangsige</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-yizuoliangyou"></use>
+						</svg>
+						<div class="name">一左两右</div>
+						<div class="code-name">#icon-yizuoliangyou</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-lianghangliangge"></use>
+						</svg>
+						<div class="name">两行两个</div>
+						<div class="code-name">#icon-lianghangliangge</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-yishangliangxia"></use>
+						</svg>
+						<div class="name">一上两下</div>
+						<div class="code-name">#icon-yishangliangxia</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-close"></use>
+						</svg>
+						<div class="name">close</div>
+						<div class="code-name">#icon-close</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-tihuantupian"></use>
+						</svg>
+						<div class="name">替换图片</div>
+						<div class="code-name">#icon-tihuantupian</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-xuanze"></use>
+						</svg>
+						<div class="name">选择</div>
+						<div class="code-name">#icon-xuanze</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-xuanze-danxuan"></use>
+						</svg>
+						<div class="name">选择</div>
+						<div class="code-name">#icon-xuanze-danxuan</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-xuanze1"></use>
+						</svg>
+						<div class="name">选择</div>
+						<div class="code-name">#icon-xuanze1</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-jinggao"></use>
+						</svg>
+						<div class="name">警告</div>
+						<div class="code-name">#icon-jinggao</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-shanchu1"></use>
+						</svg>
+						<div class="name">删 除</div>
+						<div class="code-name">#icon-shanchu1</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-chakan"></use>
+						</svg>
+						<div class="name">查看</div>
+						<div class="code-name">#icon-chakan</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-iconfontquestion"></use>
+						</svg>
+						<div class="name">问号</div>
+						<div class="code-name">#icon-iconfontquestion</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-fangkuai"></use>
+						</svg>
+						<div class="name">方块</div>
+						<div class="code-name">#icon-fangkuai</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-shanchu"></use>
+						</svg>
+						<div class="name">删除</div>
+						<div class="code-name">#icon-shanchu</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-tupian"></use>
+						</svg>
+						<div class="name">图片</div>
+						<div class="code-name">#icon-tupian</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-tupian1"></use>
+						</svg>
+						<div class="name">图片</div>
+						<div class="code-name">#icon-tupian1</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-tuodongweizhi"></use>
+						</svg>
+						<div class="name">拖动位置</div>
+						<div class="code-name">#icon-tuodongweizhi</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-add2"></use>
+						</svg>
+						<div class="name">add</div>
+						<div class="code-name">#icon-add2</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-wenben"></use>
+						</svg>
+						<div class="name">文本</div>
+						<div class="code-name">#icon-wenben</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-A"></use>
+						</svg>
+						<div class="name">A</div>
+						<div class="code-name">#icon-A</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-wenben1"></use>
+						</svg>
+						<div class="name">文本</div>
+						<div class="code-name">#icon-wenben1</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-youduiqi"></use>
+						</svg>
+						<div class="name">右对齐</div>
+						<div class="code-name">#icon-youduiqi</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-zuoduiqi"></use>
+						</svg>
+						<div class="name">左对齐</div>
+						<div class="code-name">#icon-zuoduiqi</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-juzhong"></use>
+						</svg>
+						<div class="name">居中</div>
+						<div class="code-name">#icon-juzhong</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-add1"></use>
+						</svg>
+						<div class="name">add</div>
+						<div class="code-name">#icon-add1</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-sousuo"></use>
+						</svg>
+						<div class="name">搜索</div>
+						<div class="code-name">#icon-sousuo</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-arrow-up"></use>
+						</svg>
+						<div class="name">导航</div>
+						<div class="code-name">#icon-arrow-up</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-add"></use>
+						</svg>
+						<div class="name">加上</div>
+						<div class="code-name">#icon-add</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-success"></use>
+						</svg>
+						<div class="name">检查</div>
+						<div class="code-name">#icon-success</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-subtract"></use>
+						</svg>
+						<div class="name">减去</div>
+						<div class="code-name">#icon-subtract</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-arrow-down"></use>
+						</svg>
+						<div class="name">箭头</div>
+						<div class="code-name">#icon-arrow-down</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-arrow-right"></use>
+						</svg>
+						<div class="name">箭头</div>
+						<div class="code-name">#icon-arrow-right</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-arrow-left"></use>
+						</svg>
+						<div class="name">箭头</div>
+						<div class="code-name">#icon-arrow-left</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-phone-menu"></use>
+						</svg>
+						<div class="name">列表</div>
+						<div class="code-name">#icon-phone-menu</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-user"></use>
+						</svg>
+						<div class="name">user</div>
+						<div class="code-name">#icon-user</div>
+					</li>
+
+					<li class="dib">
+						<svg class="icon svg-icon" aria-hidden="true">
+							<use xlink:href="#icon-shoppingCart"></use>
+						</svg>
+						<div class="name">Shopping cart, finance, business</div>
+						<div class="code-name">#icon-shoppingCart</div>
+					</li>
+
+				</ul>
+				<div class="article markdown">
+					<h2 id="symbol-">Symbol 引用</h2>
+					<hr>
+
+					<p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
+						这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p>
+					<ul>
+						<li>支持多色图标了,不再受单色限制。</li>
+						<li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li>
+						<li>兼容性较差,支持 IE9+,及现代浏览器。</li>
+						<li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
+					</ul>
+					<p>使用步骤如下:</p>
+					<h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3>
+					<pre><code class="language-html">&lt;script src="./iconfont.js"&gt;&lt;/script&gt;
+</code></pre>
+					<h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
+					<pre><code class="language-html">&lt;style&gt;
+.icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+&lt;/style&gt;
+</code></pre>
+					<h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
+					<pre><code class="language-html">&lt;svg class="icon" aria-hidden="true"&gt;
+  &lt;use xlink:href="#icon-xxx"&gt;&lt;/use&gt;
+&lt;/svg&gt;
+</code></pre>
+				</div>
+			</div>
+
+		</div>
+	</div>
+	<script>
+		$(document).ready(function () {
+			$('.tab-container .content:first').show()
+
+			$('#tabs li').click(function (e) {
+				var tabContent = $('.tab-container .content')
+				var index = $(this).index()
+
+				if ($(this).hasClass('active')) {
+					return
+				} else {
+					$('#tabs li').removeClass('active')
+					$(this).addClass('active')
+
+					tabContent.hide().eq(index).fadeIn()
+				}
+			})
+		})
+	</script>
+</body>
+
+</html>

+ 371 - 0
canvas-container/assets/font_icon/iconfont.css

@@ -0,0 +1,371 @@
+@font-face {
+  font-family: "iconfont"; /* Project id 8888888 */
+  src: url('iconfont.woff2?t=1638330949259') format('woff2'),
+       url('iconfont.woff?t=1638330949259') format('woff'),
+       url('iconfont.ttf?t=1638330949259') format('truetype');
+}
+
+.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+.icon-zhibo:before {
+  content: "\e7d5";
+}
+
+.icon-lunbo:before {
+  content: "\e683";
+}
+
+.icon-new:before {
+  content: "\e6db";
+}
+
+.icon-huiyuan:before {
+  content: "\e61f";
+}
+
+.icon-shangpin:before {
+  content: "\e676";
+}
+
+.icon-gonggao1:before {
+  content: "\e6f0";
+}
+
+.icon-mofang1:before {
+  content: "\e66f";
+}
+
+.icon-arrange1:before {
+  content: "\e601";
+}
+
+.icon-price:before {
+  content: "\e604";
+}
+
+.icon-arrange2:before {
+  content: "\e605";
+}
+
+.icon-gonggao:before {
+  content: "\ea7a";
+}
+
+.icon-miaosha:before {
+  content: "\e650";
+}
+
+.icon-zhekou:before {
+  content: "\e652";
+}
+
+.icon-pintuan:before {
+  content: "\e653";
+}
+
+.icon-miaosha1:before {
+  content: "\e64b";
+}
+
+.icon-xinpin:before {
+  content: "\e64c";
+}
+
+.icon-zhekou1:before {
+  content: "\e64d";
+}
+
+.icon-toubu:before {
+  content: "\e64e";
+}
+
+.icon-pintuan1:before {
+  content: "\e64f";
+}
+
+.icon-weibiaoti-zhuanhuan-:before {
+  content: "\e607";
+}
+
+.icon-kong:before {
+  content: "\e674";
+}
+
+.icon-youhuiquan3:before {
+  content: "\e621";
+}
+
+.icon-youhuiquan4:before {
+  content: "\e624";
+}
+
+.icon-youhuiquan2:before {
+  content: "\e625";
+}
+
+.icon-youhuiquan1:before {
+  content: "\e626";
+}
+
+.icon-kapian8:before {
+  content: "\e628";
+}
+
+.icon-kapian6:before {
+  content: "\e62a";
+}
+
+.icon-kapian7:before {
+  content: "\e62e";
+}
+
+.icon-kapian1:before {
+  content: "\e627";
+}
+
+.icon-kapian3:before {
+  content: "\e629";
+}
+
+.icon-kapian2:before {
+  content: "\e62b";
+}
+
+.icon-kapian5:before {
+  content: "\e62c";
+}
+
+.icon-kapian4:before {
+  content: "\e62f";
+}
+
+.icon-app:before {
+  content: "\e630";
+}
+
+.icon-fuzhufenge:before {
+  content: "\e631";
+}
+
+.icon-pc:before {
+  content: "\e632";
+}
+
+.icon-h5:before {
+  content: "\e634";
+}
+
+.icon-tuwen:before {
+  content: "\e635";
+}
+
+.icon-shangpinliebiao:before {
+  content: "\e636";
+}
+
+.icon-leibieliebiao:before {
+  content: "\e637";
+}
+
+.icon-shipin:before {
+  content: "\e638";
+}
+
+.icon-tuwendaohang:before {
+  content: "\e639";
+}
+
+.icon-zidingyi:before {
+  content: "\e63a";
+}
+
+.icon-xiaochengxu:before {
+  content: "\e63b";
+}
+
+.icon-tuwenliebiao:before {
+  content: "\e63c";
+}
+
+.icon-youhuiquan:before {
+  content: "\e63d";
+}
+
+.icon-wenben2:before {
+  content: "\e63e";
+}
+
+.icon-pinpailiebiao:before {
+  content: "\e640";
+}
+
+.icon-dianputoubu:before {
+  content: "\e641";
+}
+
+.icon-mofang:before {
+  content: "\e642";
+}
+
+.icon-yihangliangge:before {
+  content: "\e643";
+}
+
+.icon-yihangsange:before {
+  content: "\e644";
+}
+
+.icon-yihangsige:before {
+  content: "\e645";
+}
+
+.icon-yizuoliangyou:before {
+  content: "\e646";
+}
+
+.icon-lianghangliangge:before {
+  content: "\e647";
+}
+
+.icon-yishangliangxia:before {
+  content: "\e648";
+}
+
+.icon-close:before {
+  content: "\e602";
+}
+
+.icon-tihuantupian:before {
+  content: "\e66c";
+}
+
+.icon-xuanze:before {
+  content: "\e62d";
+}
+
+.icon-xuanze-danxuan:before {
+  content: "\e661";
+}
+
+.icon-xuanze1:before {
+  content: "\e618";
+}
+
+.icon-jinggao:before {
+  content: "\e608";
+}
+
+.icon-shanchu1:before {
+  content: "\e651";
+}
+
+.icon-chakan:before {
+  content: "\e622";
+}
+
+.icon-iconfontquestion:before {
+  content: "\e60a";
+}
+
+.icon-fangkuai:before {
+  content: "\e73f";
+}
+
+.icon-shanchu:before {
+  content: "\e633";
+}
+
+.icon-tupian:before {
+  content: "\e64a";
+}
+
+.icon-tupian1:before {
+  content: "\e61e";
+}
+
+.icon-tuodongweizhi:before {
+  content: "\e703";
+}
+
+.icon-add2:before {
+  content: "\e603";
+}
+
+.icon-wenben:before {
+  content: "\e649";
+}
+
+.icon-A:before {
+  content: "\e600";
+}
+
+.icon-wenben1:before {
+  content: "\e8c2";
+}
+
+.icon-youduiqi:before {
+  content: "\ec82";
+}
+
+.icon-zuoduiqi:before {
+  content: "\ec86";
+}
+
+.icon-juzhong:before {
+  content: "\e619";
+}
+
+.icon-add1:before {
+  content: "\e664";
+}
+
+.icon-sousuo:before {
+  content: "\e63f";
+}
+
+.icon-arrow-up:before {
+  content: "\e660";
+}
+
+.icon-add:before {
+  content: "\e685";
+}
+
+.icon-success:before {
+  content: "\e687";
+}
+
+.icon-subtract:before {
+  content: "\e68a";
+}
+
+.icon-arrow-down:before {
+  content: "\e695";
+}
+
+.icon-arrow-right:before {
+  content: "\e6ab";
+}
+
+.icon-arrow-left:before {
+  content: "\e6bc";
+}
+
+.icon-phone-menu:before {
+  content: "\e771";
+}
+
+.icon-user:before {
+  content: "\e67d";
+}
+
+.icon-shoppingCart:before {
+  content: "\e623";
+}
+

二进制
canvas-container/assets/font_icon/iconfont.eot


文件差异内容过多而无法显示
+ 0 - 0
canvas-container/assets/font_icon/iconfont.js


+ 632 - 0
canvas-container/assets/font_icon/iconfont.json

@@ -0,0 +1,632 @@
+{
+	"id": "8888888",
+	"name": "shop",
+	"font_family": "iconfont",
+	"css_prefix_text": "icon-",
+	"description": "",
+	"glyphs": [
+		{
+			"icon_id": "8798014",
+			"name": "直播",
+			"font_class": "zhibo",
+			"unicode": "e7d5",
+			"unicode_decimal": 59349
+		},
+		{
+			"icon_id": "9468467",
+			"name": "轮播",
+			"font_class": "lunbo",
+			"unicode": "e683",
+			"unicode_decimal": 59011
+		},
+		{
+			"icon_id": "12598705",
+			"name": "new",
+			"font_class": "new",
+			"unicode": "e6db",
+			"unicode_decimal": 59099
+		},
+		{
+			"icon_id": "11219616",
+			"name": "会员",
+			"font_class": "huiyuan",
+			"unicode": "e61f",
+			"unicode_decimal": 58911
+		},
+		{
+			"icon_id": "8262494",
+			"name": "商品",
+			"font_class": "shangpin",
+			"unicode": "e676",
+			"unicode_decimal": 58998
+		},
+		{
+			"icon_id": "17004151",
+			"name": "公告",
+			"font_class": "gonggao1",
+			"unicode": "e6f0",
+			"unicode_decimal": 59120
+		},
+		{
+			"icon_id": "22142857",
+			"name": "魔方",
+			"font_class": "mofang1",
+			"unicode": "e66f",
+			"unicode_decimal": 58991
+		},
+		{
+			"icon_id": "23733851",
+			"name": "arrange1",
+			"font_class": "arrange1",
+			"unicode": "e601",
+			"unicode_decimal": 58881
+		},
+		{
+			"icon_id": "23733852",
+			"name": "price",
+			"font_class": "price",
+			"unicode": "e604",
+			"unicode_decimal": 58884
+		},
+		{
+			"icon_id": "23733853",
+			"name": "arrange2",
+			"font_class": "arrange2",
+			"unicode": "e605",
+			"unicode_decimal": 58885
+		},
+		{
+			"icon_id": "4609686",
+			"name": "公告",
+			"font_class": "gonggao",
+			"unicode": "ea7a",
+			"unicode_decimal": 60026
+		},
+		{
+			"icon_id": "19849914",
+			"name": "秒杀",
+			"font_class": "miaosha",
+			"unicode": "e650",
+			"unicode_decimal": 58960
+		},
+		{
+			"icon_id": "19849915",
+			"name": "折扣",
+			"font_class": "zhekou",
+			"unicode": "e652",
+			"unicode_decimal": 58962
+		},
+		{
+			"icon_id": "19849916",
+			"name": "拼团",
+			"font_class": "pintuan",
+			"unicode": "e653",
+			"unicode_decimal": 58963
+		},
+		{
+			"icon_id": "19827115",
+			"name": "秒杀1",
+			"font_class": "miaosha1",
+			"unicode": "e64b",
+			"unicode_decimal": 58955
+		},
+		{
+			"icon_id": "19827116",
+			"name": "新品",
+			"font_class": "xinpin",
+			"unicode": "e64c",
+			"unicode_decimal": 58956
+		},
+		{
+			"icon_id": "19827117",
+			"name": "折扣1",
+			"font_class": "zhekou1",
+			"unicode": "e64d",
+			"unicode_decimal": 58957
+		},
+		{
+			"icon_id": "19827118",
+			"name": "头部",
+			"font_class": "toubu",
+			"unicode": "e64e",
+			"unicode_decimal": 58958
+		},
+		{
+			"icon_id": "19827119",
+			"name": "拼团1",
+			"font_class": "pintuan1",
+			"unicode": "e64f",
+			"unicode_decimal": 58959
+		},
+		{
+			"icon_id": "11640000",
+			"name": "长方形",
+			"font_class": "weibiaoti-zhuanhuan-",
+			"unicode": "e607",
+			"unicode_decimal": 58887
+		},
+		{
+			"icon_id": "10541266",
+			"name": "空",
+			"font_class": "kong",
+			"unicode": "e674",
+			"unicode_decimal": 58996
+		},
+		{
+			"icon_id": "18863998",
+			"name": "优惠券3",
+			"font_class": "youhuiquan3",
+			"unicode": "e621",
+			"unicode_decimal": 58913
+		},
+		{
+			"icon_id": "18863999",
+			"name": "优惠券4",
+			"font_class": "youhuiquan4",
+			"unicode": "e624",
+			"unicode_decimal": 58916
+		},
+		{
+			"icon_id": "18864000",
+			"name": "优惠券2",
+			"font_class": "youhuiquan2",
+			"unicode": "e625",
+			"unicode_decimal": 58917
+		},
+		{
+			"icon_id": "18864001",
+			"name": "优惠券1",
+			"font_class": "youhuiquan1",
+			"unicode": "e626",
+			"unicode_decimal": 58918
+		},
+		{
+			"icon_id": "18870310",
+			"name": "卡片8",
+			"font_class": "kapian8",
+			"unicode": "e628",
+			"unicode_decimal": 58920
+		},
+		{
+			"icon_id": "18870312",
+			"name": "卡片6",
+			"font_class": "kapian6",
+			"unicode": "e62a",
+			"unicode_decimal": 58922
+		},
+		{
+			"icon_id": "18870314",
+			"name": "卡片7",
+			"font_class": "kapian7",
+			"unicode": "e62e",
+			"unicode_decimal": 58926
+		},
+		{
+			"icon_id": "18870683",
+			"name": "卡片1",
+			"font_class": "kapian1",
+			"unicode": "e627",
+			"unicode_decimal": 58919
+		},
+		{
+			"icon_id": "18870798",
+			"name": "卡片3",
+			"font_class": "kapian3",
+			"unicode": "e629",
+			"unicode_decimal": 58921
+		},
+		{
+			"icon_id": "18870799",
+			"name": "卡片2",
+			"font_class": "kapian2",
+			"unicode": "e62b",
+			"unicode_decimal": 58923
+		},
+		{
+			"icon_id": "18870800",
+			"name": "卡片5",
+			"font_class": "kapian5",
+			"unicode": "e62c",
+			"unicode_decimal": 58924
+		},
+		{
+			"icon_id": "18870801",
+			"name": "卡片4",
+			"font_class": "kapian4",
+			"unicode": "e62f",
+			"unicode_decimal": 58927
+		},
+		{
+			"icon_id": "18907727",
+			"name": "app",
+			"font_class": "app",
+			"unicode": "e630",
+			"unicode_decimal": 58928
+		},
+		{
+			"icon_id": "18907728",
+			"name": "辅助分割",
+			"font_class": "fuzhufenge",
+			"unicode": "e631",
+			"unicode_decimal": 58929
+		},
+		{
+			"icon_id": "18907729",
+			"name": "pc",
+			"font_class": "pc",
+			"unicode": "e632",
+			"unicode_decimal": 58930
+		},
+		{
+			"icon_id": "18907730",
+			"name": "h5",
+			"font_class": "h5",
+			"unicode": "e634",
+			"unicode_decimal": 58932
+		},
+		{
+			"icon_id": "18907732",
+			"name": "图文",
+			"font_class": "tuwen",
+			"unicode": "e635",
+			"unicode_decimal": 58933
+		},
+		{
+			"icon_id": "18907733",
+			"name": "商品列表",
+			"font_class": "shangpinliebiao",
+			"unicode": "e636",
+			"unicode_decimal": 58934
+		},
+		{
+			"icon_id": "18907734",
+			"name": "类别列表",
+			"font_class": "leibieliebiao",
+			"unicode": "e637",
+			"unicode_decimal": 58935
+		},
+		{
+			"icon_id": "18907735",
+			"name": "视频",
+			"font_class": "shipin",
+			"unicode": "e638",
+			"unicode_decimal": 58936
+		},
+		{
+			"icon_id": "18907736",
+			"name": "图文导航",
+			"font_class": "tuwendaohang",
+			"unicode": "e639",
+			"unicode_decimal": 58937
+		},
+		{
+			"icon_id": "18907737",
+			"name": "自定义",
+			"font_class": "zidingyi",
+			"unicode": "e63a",
+			"unicode_decimal": 58938
+		},
+		{
+			"icon_id": "18907738",
+			"name": "小程序",
+			"font_class": "xiaochengxu",
+			"unicode": "e63b",
+			"unicode_decimal": 58939
+		},
+		{
+			"icon_id": "18907739",
+			"name": "图文列表",
+			"font_class": "tuwenliebiao",
+			"unicode": "e63c",
+			"unicode_decimal": 58940
+		},
+		{
+			"icon_id": "18907741",
+			"name": "优惠券",
+			"font_class": "youhuiquan",
+			"unicode": "e63d",
+			"unicode_decimal": 58941
+		},
+		{
+			"icon_id": "18907742",
+			"name": "文本",
+			"font_class": "wenben2",
+			"unicode": "e63e",
+			"unicode_decimal": 58942
+		},
+		{
+			"icon_id": "18907743",
+			"name": "品牌列表",
+			"font_class": "pinpailiebiao",
+			"unicode": "e640",
+			"unicode_decimal": 58944
+		},
+		{
+			"icon_id": "18907805",
+			"name": "店铺头部",
+			"font_class": "dianputoubu",
+			"unicode": "e641",
+			"unicode_decimal": 58945
+		},
+		{
+			"icon_id": "18908808",
+			"name": "魔方",
+			"font_class": "mofang",
+			"unicode": "e642",
+			"unicode_decimal": 58946
+		},
+		{
+			"icon_id": "18908809",
+			"name": "一行两个",
+			"font_class": "yihangliangge",
+			"unicode": "e643",
+			"unicode_decimal": 58947
+		},
+		{
+			"icon_id": "18908810",
+			"name": "一行三个",
+			"font_class": "yihangsange",
+			"unicode": "e644",
+			"unicode_decimal": 58948
+		},
+		{
+			"icon_id": "18908811",
+			"name": "一行四个",
+			"font_class": "yihangsige",
+			"unicode": "e645",
+			"unicode_decimal": 58949
+		},
+		{
+			"icon_id": "18908812",
+			"name": "一左两右",
+			"font_class": "yizuoliangyou",
+			"unicode": "e646",
+			"unicode_decimal": 58950
+		},
+		{
+			"icon_id": "18908813",
+			"name": "两行两个",
+			"font_class": "lianghangliangge",
+			"unicode": "e647",
+			"unicode_decimal": 58951
+		},
+		{
+			"icon_id": "18908814",
+			"name": "一上两下",
+			"font_class": "yishangliangxia",
+			"unicode": "e648",
+			"unicode_decimal": 58952
+		},
+		{
+			"icon_id": "16963297",
+			"name": "close",
+			"font_class": "close",
+			"unicode": "e602",
+			"unicode_decimal": 58882
+		},
+		{
+			"icon_id": "1630982",
+			"name": "替换图片",
+			"font_class": "tihuantupian",
+			"unicode": "e66c",
+			"unicode_decimal": 58988
+		},
+		{
+			"icon_id": "1472518",
+			"name": "选择",
+			"font_class": "xuanze",
+			"unicode": "e62d",
+			"unicode_decimal": 58925
+		},
+		{
+			"icon_id": "2570139",
+			"name": "选择",
+			"font_class": "xuanze-danxuan",
+			"unicode": "e661",
+			"unicode_decimal": 58977
+		},
+		{
+			"icon_id": "16391281",
+			"name": "选择",
+			"font_class": "xuanze1",
+			"unicode": "e618",
+			"unicode_decimal": 58904
+		},
+		{
+			"icon_id": "15076931",
+			"name": "警告",
+			"font_class": "jinggao",
+			"unicode": "e608",
+			"unicode_decimal": 58888
+		},
+		{
+			"icon_id": "14404139",
+			"name": "删 除",
+			"font_class": "shanchu1",
+			"unicode": "e651",
+			"unicode_decimal": 58961
+		},
+		{
+			"icon_id": "8649511",
+			"name": "查看",
+			"font_class": "chakan",
+			"unicode": "e622",
+			"unicode_decimal": 58914
+		},
+		{
+			"icon_id": "584016",
+			"name": "问号",
+			"font_class": "iconfontquestion",
+			"unicode": "e60a",
+			"unicode_decimal": 58890
+		},
+		{
+			"icon_id": "14384498",
+			"name": "方块",
+			"font_class": "fangkuai",
+			"unicode": "e73f",
+			"unicode_decimal": 59199
+		},
+		{
+			"icon_id": "690725",
+			"name": "删除",
+			"font_class": "shanchu",
+			"unicode": "e633",
+			"unicode_decimal": 58931
+		},
+		{
+			"icon_id": "1172721",
+			"name": "图片",
+			"font_class": "tupian",
+			"unicode": "e64a",
+			"unicode_decimal": 58954
+		},
+		{
+			"icon_id": "6049692",
+			"name": "图片",
+			"font_class": "tupian1",
+			"unicode": "e61e",
+			"unicode_decimal": 58910
+		},
+		{
+			"icon_id": "15994506",
+			"name": "拖动位置",
+			"font_class": "tuodongweizhi",
+			"unicode": "e703",
+			"unicode_decimal": 59139
+		},
+		{
+			"icon_id": "12609224",
+			"name": "add",
+			"font_class": "add2",
+			"unicode": "e603",
+			"unicode_decimal": 58883
+		},
+		{
+			"icon_id": "2404491",
+			"name": "文本",
+			"font_class": "wenben",
+			"unicode": "e649",
+			"unicode_decimal": 58953
+		},
+		{
+			"icon_id": "9567573",
+			"name": "A",
+			"font_class": "A",
+			"unicode": "e600",
+			"unicode_decimal": 58880
+		},
+		{
+			"icon_id": "10885439",
+			"name": "文本",
+			"font_class": "wenben1",
+			"unicode": "e8c2",
+			"unicode_decimal": 59586
+		},
+		{
+			"icon_id": "6337463",
+			"name": "右对齐",
+			"font_class": "youduiqi",
+			"unicode": "ec82",
+			"unicode_decimal": 60546
+		},
+		{
+			"icon_id": "6337473",
+			"name": "左对齐",
+			"font_class": "zuoduiqi",
+			"unicode": "ec86",
+			"unicode_decimal": 60550
+		},
+		{
+			"icon_id": "11976280",
+			"name": "居中",
+			"font_class": "juzhong",
+			"unicode": "e619",
+			"unicode_decimal": 58905
+		},
+		{
+			"icon_id": "15838424",
+			"name": "add",
+			"font_class": "add1",
+			"unicode": "e664",
+			"unicode_decimal": 58980
+		},
+		{
+			"icon_id": "695192",
+			"name": "搜索",
+			"font_class": "sousuo",
+			"unicode": "e63f",
+			"unicode_decimal": 58943
+		},
+		{
+			"icon_id": "608218",
+			"name": "导航",
+			"font_class": "arrow-up",
+			"unicode": "e660",
+			"unicode_decimal": 58976
+		},
+		{
+			"icon_id": "608288",
+			"name": "加上",
+			"font_class": "add",
+			"unicode": "e685",
+			"unicode_decimal": 59013
+		},
+		{
+			"icon_id": "608290",
+			"name": "检查",
+			"font_class": "success",
+			"unicode": "e687",
+			"unicode_decimal": 59015
+		},
+		{
+			"icon_id": "608293",
+			"name": "减去",
+			"font_class": "subtract",
+			"unicode": "e68a",
+			"unicode_decimal": 59018
+		},
+		{
+			"icon_id": "608317",
+			"name": "箭头",
+			"font_class": "arrow-down",
+			"unicode": "e695",
+			"unicode_decimal": 59029
+		},
+		{
+			"icon_id": "608352",
+			"name": "箭头",
+			"font_class": "arrow-right",
+			"unicode": "e6ab",
+			"unicode_decimal": 59051
+		},
+		{
+			"icon_id": "609192",
+			"name": "箭头",
+			"font_class": "arrow-left",
+			"unicode": "e6bc",
+			"unicode_decimal": 59068
+		},
+		{
+			"icon_id": "609891",
+			"name": "列表",
+			"font_class": "phone-menu",
+			"unicode": "e771",
+			"unicode_decimal": 59249
+		},
+		{
+			"icon_id": "380396",
+			"name": "user",
+			"font_class": "user",
+			"unicode": "e67d",
+			"unicode_decimal": 59005
+		},
+		{
+			"icon_id": "10554762",
+			"name": "Shopping cart, finance, business",
+			"font_class": "shoppingCart",
+			"unicode": "e623",
+			"unicode_decimal": 58915
+		}
+	]
+}

文件差异内容过多而无法显示
+ 28 - 0
canvas-container/assets/font_icon/iconfont.svg


二进制
canvas-container/assets/font_icon/iconfont.ttf


二进制
canvas-container/assets/font_icon/iconfont.woff


二进制
canvas-container/assets/font_icon/iconfont.woff2


+ 365 - 0
canvas-container/components/Upload/index.vue

@@ -0,0 +1,365 @@
+<template>
+  <div class="content">
+    <el-upload
+      v-loading="isUploading"
+      :disabled="componentError"
+      class="upload-demo"
+      drag
+      :headers="headers"
+      :file-list="viewFileList"
+      :name="name"
+      :show-file-list="showFileList"
+      :list-type="showFileListType"
+      :multiple="multiple"
+      :action="uploadUrl"
+      :limit="limit"
+      :on-success="handleUploadSuccess"
+      :before-upload="handleBeforeUpload"
+      :on-error="handleUploadError"
+      :on-exceed="handleExceed"
+      :before-remove="handleBeforeRemove"
+      :on-remove="handleRemove"
+      :on-preview="handlePreviewOpen"
+    >
+      <i class="el-icon-upload"></i>
+      <div
+        class="el-upload__text"
+        v-if="!componentError"
+      >将文件拖到此处,或<em>点击上传</em></div>
+      <div
+        class="error-text"
+        v-else
+      > 组件配置错误,请查看控制台
+      </div>
+      <div
+        class="el-upload__tip"
+        slot="tip"
+      >
+        文件大小不超过{{ limitSize }}m,文件类型为{{ types.toString() }}
+      </div>
+    </el-upload>
+
+    <!-- 预览 -->
+    <el-dialog
+      title="预览"
+      :visible.sync="previewObj.show"
+      width="60%"
+      :before-close="handlePreviewClose"
+    >
+      <div class="preview-content">
+        <template v-if="previewObj.file && previewObj.file.type.includes('image')">
+          <el-image class="preview-item" :src="previewObj.file.url" />
+        </template>
+        <template v-if="previewObj.file && previewObj.file.type.includes('video')">
+          <video class="preview-item" controls :src="previewObj.file.url" />
+        </template>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import mime from 'mime'
+let fullLoading = null
+const baseURL = process.env.VUE_APP_DOMAIN_PREFIX
+export default {
+  name: "Upload",
+  props: {
+    headers:{
+      type:Object,
+      default:()=>({})
+    },
+    /** 上传时候表单的KEY */
+    name: {
+      type: String,
+      default: () => "file"
+    },
+    /** 限制上传数量 */
+    limit: {
+      type: Number,
+      default: () => 5
+    },
+    /** 限制的那张大小 单位M */
+    limitSize: {
+      type: Number,
+      default: () => 5
+    },
+    /** 是否多选 */
+    multiple: {
+      type: Boolean,
+      default: () => true
+    },
+    /** 是否展示文件列表 */
+    showFileList: {
+      type: Boolean,
+      default: () => true
+    },
+    /** 文件展示方式 text/picture/picture-card */
+    showFileListType:{
+      type:String,
+      default:()=>'text'
+    },
+    /** 允许上传的文件尾缀 string[] */
+    types: {
+      type: Array,
+      default: () => (['jpg', 'png', 'gif'])
+    },
+    /** 默认的文件列表 string[] */
+    defaultFileList: {
+      type: Array,
+      default: () => ([])
+    },
+    /** 上传成功后端返回的字段名称 */
+    responseFileName: {
+      type: String,
+      default: () => 'url'
+    },
+    /** 是否需要全屏loading */
+    needFullScreenLoading:{
+      type:Boolean,
+      default:()=>true
+    }
+  },
+  data() {
+    return {
+      uploadUrl: `${ baseURL }/file/upload`,
+      // 真实文件列表
+      fileList: [],
+      // 默认展示的list,解决多上传只回调success一次的问题
+      viewFileList:[],
+      // 组件是否部署错误
+      componentError: false,
+      // 是否正在上传
+      isUploading:false,
+      // 预览对象
+      previewObj:{
+        show:false,
+        file:null
+      }
+    }
+  },
+  watch: {
+    defaultFileList: {
+      handler() {
+        // 判断类型
+        const flag = Object.prototype.toString.call(this.defaultFileList) === '[object Array]'
+          && this.defaultFileList.length > 0 &&
+          Object.prototype.toString.call(this.defaultFileList[0]) !== '[object String]'
+        if (flag) {
+          this.componentError = true
+          throw new Error('defaultFileList格式错误,应为string[]格式')
+        }else{
+          this.componentError = false
+        }
+        this.viewFileList = this.defaultFileList.map(defaultFilePath => ({name: defaultFilePath, url: defaultFilePath}))
+        this.viewFileList.forEach(item=>{
+          this.fileList.push(item)
+        })
+      },
+      deep: true,
+      immediate: true
+    },
+    fileList:{
+      handler(){
+        this.handleNotifyFather()
+      },
+      deep:true,
+      immediate:false
+    }
+  },
+  methods: {
+    /**
+     * 检查type是否符合types的mime
+     * @param type 文件后缀
+     * @param types 可用文件后缀集合
+     */
+    handleCheckFileMime(type, types) {
+      const typeMimes = types.map(item => mime.getType(item))
+      return typeMimes.includes(type)
+    },
+
+    handleCheckFileSize(fileSize, limitSize) {
+      const limitByteSize = limitSize * 1024 * 1024
+      return limitByteSize > fileSize
+    },
+
+    /**
+     * 上传之前的钩子
+     * @param file
+     * @return {undefined}
+     */
+    handleBeforeUpload(file) {
+      // 检查mime
+      const fileType = file.type || mime.getType(file.name.slice(file.name.lastIndexOf('.') + 1))
+      const checkFileMime = this.handleCheckFileMime(fileType, this.types)
+      const checkFileSize = this.handleCheckFileSize(file.size, this.limitSize);
+      !checkFileSize ? file.isJumpRemove = true : undefined
+      !checkFileSize ? this.$notify.warning(`文件大小不得超出${ this.limitSize }m`) : undefined
+      !checkFileMime ? file.isJumpRemove = true : undefined
+      !checkFileMime ? this.$notify.warning(`文件类型不在合法列表 ${ this.types }`) : undefined
+      if(checkFileSize && checkFileMime){
+        // 开启loading
+        this.isUploading = true
+        if(this.needFullScreenLoading){
+          fullLoading = this.$loading({
+            background:`rgba(255,255,255,0.5)`,
+            text:'上传中',
+            fullscreen:true
+          })
+        }
+      }
+      return checkFileSize && checkFileMime
+    },
+
+    /**
+     * 上传成功钩子
+     * @param response
+     * @param file
+     * @param fileList
+     */
+    handleUploadSuccess(response, file, fileList) {
+      this.isUploading = false
+      if(this.needFullScreenLoading){
+        fullLoading?.close()
+      }
+      const successObj = {
+        url: response.data[this.responseFileName],
+        name: file.name
+      }
+      file.url =  response.data[this.responseFileName]
+      this.fileList.push(successObj)
+    },
+
+    /**
+     * 上传失败的钩子
+     * @param err
+     * @param file
+     * @param fileList
+     */
+    handleUploadError(err, file, fileList) {
+    },
+
+    /**
+     * 超出数量的钩子
+     * @param files
+     * @param fileList
+     */
+    handleExceed(files, fileList) {
+      this.$notify.warning(`文件总数大于可上传数量 ${ this.limit }`)
+    },
+
+    /**
+     * 文件即将移除的钩子
+     * @param file
+     * @param fileList
+     */
+    async handleBeforeRemove(file, fileList) {
+      // 如果是超出文件大小调用,放行
+      if (file?.raw?.isJumpRemove) {
+        return true
+      }
+      return await this.$confirm('此操作将会删除已上传的文件, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+    },
+
+    /**
+     * 移除文件的钩子
+     */
+    handleRemove(file, fileList) {
+      if (file?.raw?.isJumpRemove) {
+        return
+      }
+      this.fileList.splice(this.fileList.findIndex(fileItem => file?.response?.data[this.responseFileName] === fileItem.url || file.url === fileItem.url), 1)
+    },
+
+    /**
+     * 通知父组件
+     */
+    handleNotifyFather(){
+      this.$emit('change',this.fileList)
+    },
+
+    /**
+     * 预览
+     * 图片视频直接预览,其他下载
+     * @param file
+     */
+    handlePreviewOpen(file){
+      if(!file.type){
+        file.type = mime.getType(file?.url?.slice(file?.url?.lastIndexOf('.')+1)) || mime.getType(file?.name?.slice(file?.name.lastIndexOf('.')+1)) || undefined
+      }
+      if(file.type.includes('image') || file.type.includes('video')){
+        this.previewObj.file = file
+        this.previewObj.show = true
+      }else{
+        this.$confirm('需要下载才能预览此文件, 是否继续?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        }).then(() => {
+          let htmlAnchorElement = document.createElement('a');
+          htmlAnchorElement.download = file?.url.slice(file?.url.lastIndexOf('/')+1)
+          htmlAnchorElement.target='_bank'
+          htmlAnchorElement.href = file?.url
+          htmlAnchorElement.click()
+          htmlAnchorElement = null
+        }).catch(() => {
+        });
+      }
+    },
+
+    handlePreviewClose(){
+      this.previewObj.file = null
+      this.previewObj.show = false
+    }
+  }
+}
+</script>
+
+<style
+  lang="scss"
+  scoped
+>
+::v-deep .el-upload {
+  width: 100% !important;
+
+  .el-upload-dragger {
+    width: 100% !important;
+  }
+}
+
+.error-text {
+  font-size: 18px;
+  font-weight: bolder;
+  color: red;
+  animation: error-animation 2.5s ease-in-out infinite;
+}
+
+@keyframes error-animation {
+  0%, 100% {
+    font-size: 18px;
+    color: red;
+  }
+  25%, 75% {
+    font-size: 16px;
+    color: #b9b1b1;
+  }
+  50% {
+    font-size: 18px;
+    color: #500000;
+  }
+}
+
+.preview-content{
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  .preview-item{
+    min-width: 800px;
+  }
+}
+
+</style>

+ 366 - 0
canvas-container/components/canvasEditPage.vue

@@ -0,0 +1,366 @@
+<template>
+   <div class="layout hom-layout" v-loading.fullscreen.lock="loading">
+     <draggable
+       class="dragArea list-group"
+       :list="componentsData"
+       group="pageEdit"
+       :move="checkMove"
+       @end="pageAdd"
+       @change="pageChange"
+       filter=".undraggable"
+     >
+     <div class="list-group-item" v-for="(item,index) in componentsData" :key="index" :class="[{'on':activeComponent == index,'undraggable':item.undraggable},'item-'+item.type]" @click="selectComponent(item,index)">
+       <component v-show="!item.isEmpty" :isNoData.sync='item.isEmpty' :is="componentMap[terminal-1].get(item.type)" :componentContent="item.componentContent" :terminal="terminal" :typeId="typeId" :shopId="shopId" @cleckLoading="cleckLoading"></component>
+       <div class="no-data" v-show="item.isEmpty">
+         <i class="iconfont icon-kong"></i>
+         <p>暂无数据<br>请在右边窗口编辑内容</p>
+       </div>
+       <div class="btns">
+         <span @click="delComponent(item,index)"><i class="iconfont icon-shanchu"></i></span>
+       </div>
+     </div>
+     </draggable>
+   </div>
+</template>
+
+<script>
+  import draggable from 'vuedraggable'
+  import componentMap from './canvasShow/componentMap'
+  import { mapGetters, mapMutations } from 'vuex'
+  export default {
+  // import testData from '@@/config/testData3'
+    name: 'canvasEditPage',
+    components: {
+      draggable
+    },
+    props: {
+      terminal: {
+        type: Number,
+        default: 4
+      },
+      typeId: {
+        type: Number,
+        default: 1
+      },
+      shopId: {
+        type: Number,
+        default: 0
+      }
+    },
+    data () {
+      return {
+        activeComponent: -1,
+        componentMap: componentMap,
+        loading: false
+      }
+    },
+    mounted () {
+      // this.setComponentsData(testData)
+    },
+    computed: {
+      ...mapGetters([
+        'componentsData'
+      ])
+    },
+    methods: {
+      ...mapMutations({
+        setActiveComponent: 'SET_ACTIVECOMPONENT',
+        setComponentsData: 'SET_COMPONENTSDATA'
+      }),
+      // 画布添加或者移动了组件
+      pageChange (e) {
+        if (e.added) {
+          if(e.added.element.type == 'header'){
+            var headerArr = this.componentsData.filter(v=>{
+              return v.type === 'header'
+            })
+            if(headerArr.length >= 2){
+              this.componentsData.splice(e.added.newIndex, 1)
+              this.$message.warning('头部组件最多只能存在一个。')
+            } else if(headerArr.length === 1 && this.componentsData[0].type !== 'header'){
+              this.componentsData.splice(e.added.newIndex, 1)
+              this.componentsData.unshift(e.added.element)
+            }
+            this.activeComponent = 0
+            e.added.element.index = 0
+            this.setActiveComponent(e.added.element)
+          } else {
+            if(e.added.element.type==='productList'&&[1,2,3].includes(this.terminal)){
+              // 添加的是商品列表 且是小程序、H5、App
+              this.$alert('当前选中了商品组件,若需要开启触底加载,需要将该组件置于组件列表的尾部,否则触底加载将会失效;若不开启触底加载,可能会导致性能问题!','警告')
+            }
+            this.activeComponent = e.added.newIndex
+            e.added.element.index = e.added.newIndex
+            this.setActiveComponent(e.added.element)
+          }
+        }
+        if (e.moved) {
+          this.activeComponent = e.moved.newIndex
+          e.moved.element.index = e.moved.newIndex
+          this.setActiveComponent(e.moved.element)
+        }
+        this.$emit('showRightBox', true)
+      },
+      // 拖动检查
+      checkMove(e){
+        console.log(e,'checkMove')
+        //不允许停靠
+        if (e.relatedContext.element.type == 'header') return false;
+        //不允许拖拽
+        if (e.draggedContext.element.type == 'header') return false;
+      },
+      pageAdd(e){
+        console.log(e,'pageAdd')
+        return false
+      },
+      // 选中组件
+      selectComponent (item, index) {
+        this.activeComponent = index
+        item.index = index
+        this.setActiveComponent(item)
+        this.$emit('showRightBox', true)
+    },
+      // 删除组件
+      delComponent (item, index) {
+        this.$confirm('确定删除吗?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        }).then(() => {
+          this.activeComponent = -1
+          this.componentsData.splice(index, 1)
+          this.$emit('showRightBox', false)
+        }).catch(() => {
+        })
+      },
+      cleckLoading(){
+        if(typeof(uni) !== 'undefined'){
+          uni.getStorage({
+            key: 'sendNum',
+            success: function (res) {
+              let sendNum = res.data;
+              this.loading = parseInt(sendNum) !== 0
+            }
+          })
+        } else {
+          let sendNum = localStorage.getItem('sendNum')
+          this.loading = parseInt(sendNum) !== 0
+        }
+      },
+      // 检查组件是否为空
+      checkIsNoData(dataList) {
+        for(let i=0;i<dataList.length;i++){
+          const newVal = dataList[i].componentContent
+          let isEmpty = true
+          let _data = ''
+          switch (dataList[i].type){
+            case 'banner':
+              _data=newVal.bannerData
+              _data.forEach(function(value ){
+                if(value.bannerUrl){
+                  isEmpty = false
+                }
+              })
+              break
+            case 'header':
+            case 'notice':
+            case 'text':
+            case 'imageTextNav':
+            case 'imageText':
+            case 'imageTextList':
+            case 'brandList':
+            case 'categoryList':
+            case 'assistDiv':
+            case 'vip':
+            case 'live':
+            case 'videoBox':
+              isEmpty = false
+              break
+            case 'productList':
+              _data = newVal.productData
+              if((_data.sourceType=='1' && _data.productIdList.length > 0) || (_data.sourceType=='2' && _data.categoryId != 0)){
+                isEmpty = false
+              }
+              break
+            case 'custom':
+              _data=newVal.imgData
+              _data.forEach(function(value ){
+                if(value.src){
+                  isEmpty = false
+                }
+              })
+              break
+            case 'groupList':
+              if(this.typeId === 1){
+                isEmpty = false
+              }
+              else {
+                if(newVal.shopGroupWorkId){
+                  isEmpty = false
+                }
+              }
+              break
+            case 'spikeList':
+              if(newVal.shopSeckillId){
+                isEmpty = false
+              }
+              break
+            case 'discountList':
+              if(newVal.discountId){
+                isEmpty = false
+              }
+              break
+            case 'priceList':
+              if(newVal.priceId){
+                isEmpty = false
+              }
+              break
+            case 'coupon':
+              if(newVal.selectedCoupon.length > 0){
+                isEmpty = false
+              }
+              break
+            case 'newProduct':
+              _data = newVal.productData
+              if((_data.sourceType=='1' && _data.productIdList.length > 0) || (_data.sourceType=='2' && _data.categoryId != 0)){
+                isEmpty = false
+              }
+              break
+            case 'shop':
+              _data=newVal.imgTextData
+              _data.forEach(function(value ){
+                if(value.img){
+                  isEmpty = false
+                }
+              })
+              break
+          }
+          dataList[i].isEmpty = isEmpty
+          this.$forceUpdate()
+        }
+        console.log(dataList)
+      },
+    },
+    // 监控组件是否为空
+    watch: {
+      'componentsData': {
+        handler(newVal, oldVal) {
+          this.checkIsNoData(newVal)
+        },
+        deep: true
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+.hom-layout {
+  background-color: #fff;
+  ::v-deep .sortable-chosen {
+    .contentBox {
+      display: none;
+    }
+    .cloneText {
+      display: block;
+      width: 100%;
+      height: 50px;
+      line-height: 50px;
+      font-size: 18px;
+      text-align: center;
+      background-color: $mainColor;
+      color: #fff;
+    }
+  }
+  .list-group {
+    min-height: calc(100vh - 50px);
+  }
+  .list-group-item {
+    position: relative;
+    cursor: move;
+    background-color: #fff;
+    min-height: 100px;
+    &.item-assistDiv,&.item-notice,&.item-text{
+      min-height: 0px;
+    }
+    .btns {
+      display: none;
+    }
+    &:hover {
+      &:after {
+        content: '';
+        position: absolute;
+        width: 100%;
+        height: 100%;
+        left: 0;
+        top: 0;
+        border: 1px $mainColor dashed;
+        z-index: 2;
+      }
+    }
+    &.on {
+      &:after {
+        content: '';
+        position: absolute;
+        width: 100%;
+        height: 100%;
+        left: 0;
+        top: 0;
+        border: 1px $mainColor solid;
+        z-index: 2;
+      }
+      .btns {
+        display: block;
+        position: absolute;
+        right: -13px;
+        top: 50%;
+        margin-top: -13px;
+        z-index: 3;
+        span {
+          display: block;
+          width: 26px;
+          height: 26px;
+          line-height: 26px;
+          text-align: center;
+          color: #666;
+          background-color: #fff;
+          box-shadow: 0 0 2px rgba(51, 51, 51, 0.2);
+          cursor: pointer;
+        }
+      }
+    }
+  }
+}
+.no-data {
+  width: 100%;
+  display: flex;
+  height: 300px;
+  -webkit-box-align: center;
+  align-items: center;
+  -webkit-box-pack: center;
+  justify-content: center;
+  color: #999;
+  text-align: center;
+  font-size: 16px;
+  line-height: 1.8;
+  .iconfont {
+    font-size: 100px;
+    color: $mainColor;
+    margin-right: 50px;
+  }
+}
+</style>
+
+<style lang="scss">
+.warp {
+  width: 710px;
+  margin: 0 auto;
+  max-width: 100%;
+  &.terminal4 {
+    width: 1200px;
+    max-width: 100%;
+  }
+}
+.flex-box {
+  display: flex;
+}
+</style>

+ 24 - 0
canvas-container/components/canvasShow/basics/assistDiv.vue

@@ -0,0 +1,24 @@
+<template>
+  <div class="div" :style="{backgroundColor:componentContent.bgColor,height:componentContent.height + 'px'}"></div>
+</template>
+
+<script>
+  export default {
+    name: 'assistDiv',
+    props: {
+      terminal: {
+        type: Number,
+        default: 4
+      },
+      componentContent: {
+        type: Object
+      }
+    }
+  }
+</script>
+
+<style scoped>
+  .div{
+    width: 100%;
+  }
+</style>

+ 103 - 0
canvas-container/components/canvasShow/basics/banner.vue

@@ -0,0 +1,103 @@
+<template>
+  <div class="banner"  :class="'terminal' + terminal">
+    <swiper :options="swiperOption">
+      <swiper-slide class="banner-item" v-for="(item,index) in bannerList" :key="index" :style="{backgroundImage: 'url('+ item.bannerUrl +')','height':componentContent.height + 'px'}" @click="jumpLink(item.linkObj)">
+<!--        <div class="a-link" @click="jumpLink(item.linkObj)"><img class="img" :src="item.bannerUrl" v-show="item.bannerUrl"></div>-->
+      </swiper-slide>
+    </swiper>
+    <div class="swiper-pagination" slot="pagination"></div>
+  </div>
+</template>
+
+<script>
+import { directive, Swiper, SwiperSlide } from 'vue-awesome-swiper'
+import 'swiper/css/swiper.css'
+  import {funMixin} from '../config/mixin'
+  export default {
+    name: 'Banner',
+    mixins: [funMixin],
+    data () {
+      return {
+        swiperOption: {
+          autoplay: false, // 可选选项,自动滑动
+          loop: true,
+          pagination: {
+            el: '.swiper-pagination'
+          }
+        }
+      }
+    },
+    props: {
+      terminal: {
+        type: Number,
+        default: 4
+      },
+      componentContent: {
+        type: Object
+      }
+    },
+    components: {
+      Swiper,
+      SwiperSlide
+    },
+    directives: {
+      swiper: directive
+    },
+    mounted() {
+      this.$forceUpdate() // 刷新轮播图
+    },
+    computed: {
+      bannerList: function () {
+        console.log(this.componentContent)
+        return this.componentContent.bannerData.filter(function (item) {
+          return item.bannerUrl
+        })
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+.banner{
+  .banner-item {
+    width: 100%;
+    background-repeat: no-repeat;
+    background-position: center;
+    background-size: auto 100%;
+    img {
+      width: 100%;
+    }
+  }
+  &.terminal4{
+    ::v-deep .el-carousel{
+      height: 100%;
+      .el-carousel__container{
+        height: 100%;
+      }
+    }
+    .banner-item{
+      img{
+        display: none;
+      }
+    }
+  }
+  .swiper-pagination{
+    display: flex;
+    justify-content: center;
+    bottom: 20px;
+    width: 100%;
+    ::v-deep .swiper-pagination-bullet{
+      width: 30px;
+      height: 4px;
+      background: #fff;
+      opacity: 0.5;
+      border-radius: 2px;
+      margin: 0 7.5px;
+    }
+    ::v-deep .swiper-pagination-bullet-active{
+      opacity: 1;
+      width: 58px;
+    }
+  }
+}
+</style>

+ 128 - 0
canvas-container/components/canvasShow/basics/brandList.vue

@@ -0,0 +1,128 @@
+<template>
+  <div class="brand-list warp" :class="'terminal' + terminal">
+    <h2 class="hom-title" :style="{textAlign:componentContent.textAlign}">{{componentContent.title}}</h2>
+    <div class="content-warp">
+      <ul class="clearfix">
+        <li v-for="(item, index) in componentContent.imgList" :key="index">
+          <a class="item a-link" @click="jumpLink(item.linkObj)">
+            <div class="imgBox">
+              <img :src="item.imgData" v-show="item.imgData" :alt="item.title">
+            </div>
+            <h4 class="h4">{{item.title}}</h4>
+          </a>
+        </li>
+      </ul>
+    </div>
+  </div>
+</template>
+
+<script>
+  import {funMixin} from '../config/mixin'
+  export default {
+    name: 'brandList',
+    mixins: [funMixin],
+    props: {
+      terminal: {
+        type: Number,
+        default: 4
+      },
+      componentContent: {
+        type: Object
+      }
+    }
+  }
+</script>
+<style lang="scss" scoped>
+  .brand-list{
+    color: #fff;
+    padding: 20px 0;
+    .hom-title{
+      font-size: 22px;
+      color: #333;
+      line-height: 1em;
+      margin-bottom: 23px;
+      font-weight: bold;
+    }
+    .content-warp{
+      display: flex;
+    }
+    .first{
+      width: 24%;
+      padding-top: 10px;
+      .item{
+        background-color: #7A8594;
+        height: 336px;
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+        .h3{
+          font-size: 30px;
+          line-height: 46px;
+          margin-bottom: 10px;
+        }
+      }
+    }
+    ul{
+      width: 100%;
+      li{
+        width: 25%;
+        float: left;
+        padding: 10px 0 0 10px;
+        .item{
+          height: auto;
+          display: flex;
+          flex-direction: column;
+          justify-content: center;
+          .imgBox {
+            padding-bottom: 80%;
+            background-color: #cacaca;
+            position: relative;
+          }
+          .h4{
+            font-size: 18px;
+            color: #333333;
+            text-align: center;
+            height: 40px;
+            line-height: 40px;
+          }
+          .p{
+            font-size: 12px;
+            margin: 7px 0 12px;
+          }
+          img {
+            max-width: 100%;
+            height: 100%;
+            max-height: 100%;
+            position: absolute;
+            margin: auto;
+            top: 0;
+            right: 0;
+            bottom: 0;
+            left: 0;
+          }
+        }
+      }
+    }
+  }
+  .terminal1,.terminal2,.terminal3{
+    &.brand-list{
+      .content-warp{
+        display: block;
+      }
+      .first{
+        width: 100%;
+      }
+      ul{
+        width: auto;
+        margin-left: -15px;
+        li{
+          padding: 15px 0 0 15px;
+          width: 50%;
+          .item {
+            padding-left: 0;
+          }
+        }
+      }
+    }
+  }
+</style>

+ 116 - 0
canvas-container/components/canvasShow/basics/categoryList.vue

@@ -0,0 +1,116 @@
+<template>
+  <div class="category-list warp" :class="'terminal' + terminal">
+    <h2 class="hom-title" :style="{textAlign:componentContent.textAlign}">{{componentContent.title}}</h2>
+    <div class="content-warp">
+      <ul class="clearfix" :class="{number5: componentContent.categoryData.length === 5}">
+        <li v-for="(item) of componentContent.categoryData" :key="item.id">
+            <a class="item a-link" @click="jumpCategory(item)">
+            <div class="imgBox">
+               <img ref="getHeight" :src="item.img" v-show="item.img" :alt="item.name">
+            </div>
+            </a>
+        </li>
+      </ul>
+    </div>
+  </div>
+</template>
+
+<script>
+import {funMixin} from '../config/mixin'
+  export default {
+    name: 'categoryList',
+    mixins: [funMixin],
+    props: {
+      terminal: {
+        type: Number,
+        default: 4
+      },
+      componentContent: {
+        type: Object
+      }
+    }
+  }
+</script>
+<style lang="scss" scoped>
+  .category-list{
+    padding: 20px 0;
+    .hom-title{
+      font-size: 22px;
+      color: #333;
+      line-height: 1em;
+      margin-bottom: 23px;
+      font-weight: bold;
+      text-align: center;
+    }
+    .content-warp{
+      display: flex;
+      ul{
+        width: 100%;
+        display: flex;
+        flex-wrap: wrap;
+        li{
+          flex: 1;
+          padding: 10px 0 0 10px;
+          .item{
+            height: auto;
+            display: flex;
+            flex-direction: column;
+            justify-content: center;
+            .imgBox {
+              padding-bottom: 80%;
+              background-color: #cacaca;
+              position: relative;
+            }
+            img {
+              max-width: 100%;
+              height: 100%;
+              max-height: 100%;
+              position: absolute;
+              margin: auto;
+              top: 0;
+              right: 0;
+              bottom: 0;
+              left: 0;
+            }
+          }
+        }
+      }
+      .number5 {
+        display: block;
+        li {
+          width: 25%;
+          float: left;
+        }
+        li:nth-child(1) {
+          width: 50%;
+        }
+      }
+    }
+  }
+  @media screen and (max-width: 768px) {
+    .category-list .content-warp{
+      display: block;
+      ul{
+        margin: -15px 0 0 -15px;
+        width: auto;
+        li{
+          flex: 0 0 50%;
+          padding: 15px 0 0 15px;
+        }
+      }
+    }
+  }
+  .terminal1,.terminal2,.terminal3{
+    &.category-list .content-warp{
+      display: block;
+      ul{
+        margin: -15px 0 0 -15px;
+        width: auto;
+        li{
+          flex: 0 0 50%;
+          padding: 15px 0 0 15px;
+        }
+      }
+    }
+  }
+</style>

+ 88 - 0
canvas-container/components/canvasShow/basics/coupon/app/index.vue

@@ -0,0 +1,88 @@
+<template>
+  <div class="coupon">
+    <div class="coupon-list">
+      <div class="coupon-item" v-for="(item,index) in couponsData" :key="index" :class="item.state && item.state !== 3 && 'isReceive'">
+        <div class="coupon-item-content">
+          <div class="coupon-item-price">
+            <span v-if="item.couponType !== 2">¥</span>
+            <b v-if="typeId !== 1">{{item.couponContent}}</b>
+            <b v-else>{{item.reduceMoney}}</b>
+            <b v-if="item.couponType == 2">折券</b>
+          </div>
+          <div class="coupon-item-date">{{item.effectiveStart.split(' ')[0]}} - {{item.effectiveEnd.split(' ')[0]}}</div>
+          <div class="coupon-item-text">{{item.content}}</div>
+        </div>
+        <button v-if="item.state === 0" class="coupon-item-btn" @click="jumpStore(item)">立即使用</button>
+        <button v-else-if="item.state === 1" class="coupon-item-btn">已使用</button>
+        <button v-else-if="item.state === 2" class="coupon-item-btn">已过期</button>
+        <button v-else @click="receiveCoupon(item)" class="coupon-item-btn">立即领取</button>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import {commonMixin} from '../mixin'
+export default {
+  mixins: [commonMixin]
+}
+</script>
+
+<style lang="scss" scoped>
+.coupon {
+  padding: 25px;
+  &-list{
+    display: flex;
+    flex-wrap: wrap;
+  }
+  &-item{
+    width: 335px;
+    height: 292px;
+    background: url("../../../static/images/coupon/bg-coupon.png") no-repeat;
+    margin-left: 28px;
+    &:nth-child(2n+1){
+      margin-left: 0;
+    }
+    &-content{
+      text-align: center;
+    }
+    &-price{
+      color: #C5AA7B;
+      margin: 26px 0 10px;
+      span{
+        font-size: 36px;
+        line-height: 68px;
+      }
+      b{
+        font-size: 50px;
+        line-height: 68px;
+      }
+    }
+    &-date,&-text{
+      font-size: 20px;
+      line-height: 28px;
+      color: #999999;
+    }
+    &-date{
+      margin-bottom: 8px;
+    }
+    &-btn{
+      display: block;
+      margin: 60px auto 0;
+      width: 112px;
+      height: 48px;
+      background-color: #C5AA7B;
+      color: #fff;
+    }
+    &.isReceive{
+      background-image: url("../../../static/images/coupon/bg-coupon2.png");
+      &-price{
+        color: #999;
+      }
+      &-btn{
+        background-color: #ccc;
+      }
+    }
+  }
+}
+</style>

+ 82 - 0
canvas-container/components/canvasShow/basics/coupon/mixin.js

@@ -0,0 +1,82 @@
+import api from '../../config/api'
+import { funMixin } from '../../config/mixin'
+import { mapGetters } from 'vuex'
+
+export const commonMixin = {
+  name: 'textComponent',
+  mixins: [funMixin],
+  data () {
+    return {
+      couponsData: []
+    }
+  },
+  props: {
+    terminal: {
+      type: Number,
+      default: 4
+    },
+    typeId: {
+      type: Number,
+      default: 1
+    },
+    shopId: {
+      type: Number,
+      default: 0
+    },
+    componentContent: {
+      type: Object
+    }
+  },
+  computed: {
+    ...mapGetters([
+      'couponNum'
+    ]),
+  },
+  watch: {
+    'couponNum': {
+      handler(newVal, oldVal) {
+        this.getData()
+      },
+      deep: true
+    }
+  },
+  mounted() {
+      this.getData()
+  },
+  methods: {
+    getData() {
+      const _ = this
+      if(_.componentContent.selectedCoupon && _.componentContent.selectedCoupon.length > 0){
+        this.beforeGetData()
+        let _url = ''
+        if(_.typeId === 1){
+          _url =`${api.getCoupons}?page=1&pageSize=99&ids=${_.componentContent.selectedCoupon}`
+        } else if(_.typeId === 3) {
+          _url =`${api.getShopCoupons}?page=1&pageSize=99&shopId=${_.shopId}&ids=${_.componentContent.selectedCoupon}`
+        }
+        const params = {
+          method: 'GET',
+          url: _url,
+        }
+        this.sendReq(params, (res) => {
+          _.afterGetData()
+          _.couponsData = res.data.list
+          if(_.typeId === 1){
+            _.couponsData.forEach(item=>{
+              item.couponName = item.activityName
+              item.effectiveStart = item.activityStartTime
+              item.effectiveEnd = item.activityEndTime
+            })
+          }
+          if(JSON.stringify(_.componentContent.couponList) !== JSON.stringify(_.couponsData)){
+            _.componentContent.couponList = _.couponsData
+          }
+        },(err)=>{
+          _.afterGetData()
+        })
+      } else {
+        _.couponsData = []
+      }
+    }
+  }
+}

+ 374 - 0
canvas-container/components/canvasShow/basics/coupon/pc/index.vue

@@ -0,0 +1,374 @@
+<template>
+  <div class="couponBox warp" :class="['terminal' + terminal,'arrange'+(componentContent.arrangeActiveIndex+1),'color'+(componentContent.colorActiveIndex+1)]">
+    <div class="couponListBox" v-if="componentContent.selectedCoupon">
+      <div class="listItemBox" v-for="(item,index) in couponsData" :key="index" :class="item.state && item.state !== 3 && 'isReceive'">
+        <div class="listItemBoxInner">
+          <div class="itemInfo">
+            <i class="flag" :class="'flag'+item.couponType"></i>
+            <div class="amount">
+              <b v-if="item.couponType !== 2">¥</b>
+              <span v-if="typeId !== 1">
+                {{item.couponContent}}
+                </span>
+              <span v-else>
+                {{item.reduceMoney}}
+                </span>
+              <b v-if="item.couponType == 2">折</b>
+            </div>
+            <div class="couponInfo">
+              <p>{{item.content}}</p>
+            </div>
+          </div>
+          <!--            <div class="itemInfo" v-else>-->
+          <!--              <div class="amount">-->
+          <!--                <b>¥</b><span>{{item.reduceMoney}}<i>满减券</i></span>-->
+          <!--              </div>-->
+          <!--              <div class="couponInfo">-->
+          <!--                <p>{{item.content}}</p>-->
+          <!--              </div>-->
+          <!--            </div>-->
+          <div v-if="item.state === 0" class="receiveBtn">
+            <span>己领取</span>
+          </div>
+          <div v-else-if="item.state === 1" class="receiveBtn">
+            <span>已使用</span>
+          </div>
+          <div v-else-if="item.state === 2" class="receiveBtn">
+            <span>已过期</span>
+          </div>
+          <div v-else class="receiveBtn" @click="receiveCoupon(item)">
+            <span>立即领取</span>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import {commonMixin} from '../mixin'
+export default {
+  mixins: [commonMixin]
+}
+</script>
+
+<style lang="scss" scoped>
+.couponBox {
+  min-height: 177px;
+  margin: 0 auto;
+  padding: 20px 0;
+  .couponListBox {
+    flex-wrap: wrap;
+    /**默认**/
+    .listItemBox {
+      //background-image:url('../../../static/images/coupon/border_L1.png'), url('../../../static/images/coupon/border_R1.png');
+      //background-repeat: no-repeat, no-repeat;
+      //background-position: left top, right top;
+      box-sizing: border-box;
+      .listItemBoxInner {
+        width: 100%;
+        height: 150px;
+        display: flex;
+        background-color: #FAFAFA;
+        align-items: center;
+        justify-content: space-between;
+        position: relative;
+        .flag{
+          display: block;
+          width: 71px;
+          height: 71px;
+          background-repeat: no-repeat;
+          position: absolute;
+          top: 0;
+          left: 0;
+          &.flag1{
+            background-image: url("../../../static/images/coupon/flag-coupon.png");
+          }
+          &.flag2{
+            background-image: url("../../../static/images/coupon/flag-coupon2.png");
+          }
+        }
+        .itemInfo {
+          flex: 1;
+        }
+        .amount {
+          max-width: 90%;
+          margin: 0 auto;
+          display: flex;
+          align-items: baseline;
+          justify-content: center;
+          line-height: 60px;
+          b {
+            font-size: 30px;
+          }
+          span {
+            font-size: 60px;
+            font-weight: bold;
+          }
+          i {
+            font-style: normal;
+            font-size: 18px;
+            margin-left: 5px;
+          }
+        }
+        .couponInfo {
+          text-align: center;
+          p {
+            display: inline-block;
+            padding: 0 42px;
+            text-align: center;
+            font-size: 18px;
+            line-height: 40px;
+            color: #C83732;
+            background: #F5E5E5;
+          }
+        }
+      }
+      .receiveBtn {
+        width: 72px;
+        margin-right: 5px;
+        background: #C5AA7B;
+        height: 100%;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        cursor: pointer;
+        position: relative;
+        &:before,&:after{
+          content: '';
+          display: block;
+          width: 25px;
+          height: 25px;
+          background-color: #fff;
+          position: absolute;
+          left: -12.5px;
+          border-radius: 50%;
+        }
+        &:before{
+          top: -12.5px;
+        }
+        &:after{
+          bottom: -12.5px;
+        }
+        span {
+          color: #FFFFFF !important;
+          writing-mode: vertical-lr;
+          font-size: 19px;
+        }
+      }
+      &.isReceive {
+        //background-image:url('../../../static/images/coupon/border_L4.png'), url('../../../static/images/coupon/border_R4.png');
+        .listItemBoxInner {
+          .flag{
+            &.flag1{
+              background-image: url("../../../static/images/coupon/flag-coupon-r.png");
+            }
+            &.flag2{
+              background-image: url("../../../static/images/coupon/flag-coupon2-r.png");
+            }
+          }
+          .itemInfo {
+            color: #999;
+            .couponInfo {
+              p {
+                color: #999;
+                background: #F1F1F1;
+              }
+            }
+          }
+          .receiveBtn {
+            cursor: auto;
+            background: #999;
+          }
+        }
+      }
+    }
+  }
+
+  @mixin cardColor($bgColor: #FF3737,$fontColor: #fff) {
+    .couponListBox {
+      .listItemBox {
+        .listItemBoxInner{
+          background: $bgColor;
+        }
+        .itemInfo {
+          .amount {
+            b {
+              color: #EC4B42;
+            }
+            span {
+              color: #EC4B42;
+              i {
+                color: #EC4B42;
+              }
+            }
+          }
+          .couponInfo {
+            color:#EC4B42;
+          }
+        }
+        .receiveBtn {
+          span {
+            color: #EC4B42;
+          }
+        }
+        &.cardStyle3{
+          .itemInfo {
+            .amount {
+              span {
+                color: $bgColor;
+                i {
+                  color: $bgColor;
+                }
+              }
+            }
+            .couponInfo {
+              color:$bgColor;
+            }
+          }
+        }
+        &.cardStyle4{
+          border: 2px solid $bgColor;
+          padding: 5px;
+          .listItemBoxInner{
+            padding: 20px 15px;
+            height: 85px;
+            border: 1px solid $bgColor;
+          }
+          .itemInfo {
+            .amount {
+              span {
+                color: $bgColor;
+                i {
+                  color: $bgColor;
+                }
+              }
+            }
+            .couponInfo {
+              color:$bgColor;
+            }
+          }
+          .receiveBtn {
+            border-left: 1px $bgColor dashed;
+            span {
+              color: $bgColor;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  &.arrange1{
+
+  }
+  &.arrange2{
+    max-width: 100%;
+    .couponListBox{
+      display: flex;
+      flex-wrap: wrap;
+      justify-content: space-between;
+      .listItemBox{
+        width: 48%;
+      }
+    }
+  }
+  &.arrange3{
+    max-width: 100%;
+    .couponListBox{
+      display: flex;
+      flex-wrap: wrap;
+      justify-content: space-between;
+      .listItemBox{
+        width: 32%;
+      }
+    }
+  }
+  &.arrange4{
+    max-width: 100%;
+    .couponListBox{
+      display: flex;
+      overflow: hidden;
+      .listItemBox{
+        width: 268px;
+        flex: 0 0 268px;
+        margin:0 25px 25px 0;
+        &:nth-child(4n){
+          margin-right: 0;
+        }
+      }
+    }
+  }
+  //&.color1{
+  //  .listItemBox {
+  //    background-image:url('../../../static/images/coupon/border_L1.png'), url('../../../static/images/coupon/border_R1.png');
+  //    .listItemBoxInner {
+  //      border-top: 1px solid #EC4B42;
+  //      border-bottom: 1px solid #EC4B42;
+  //      .itemInfo {
+  //        color: #EC4B42;
+  //        .amount {
+  //          border-bottom: 1px solid #EC4B42;
+  //        }
+  //        .couponInfo {
+  //          p {
+  //            color: #EC4B42;
+  //          }
+  //        }
+  //      }
+  //      .receiveBtn {
+  //        background: #EC4B42;
+  //      }
+  //    }
+  //  }
+  //}
+
+  &.color2{
+    .listItemBox {
+      background-image:url('../../../static/images/coupon/border_L2.png'), url('../../../static/images/coupon/border_R2.png');
+      .listItemBoxInner {
+        border-top: 1px solid #FF7800;
+        border-bottom: 1px solid #FF7800;
+        .itemInfo {
+          color: #FF7800;
+          .amount {
+            border-bottom: 1px solid #FF7800;
+          }
+          .couponInfo {
+            p {
+              color: #FF7800;
+            }
+          }
+        }
+        .receiveBtn {
+          background: #FF7800;
+        }
+      }
+    }
+  }
+
+  &.color3{
+    .listItemBox {
+      background-image:url('../../../static/images/coupon/border_L3.png'), url('../../../static/images/coupon/border_R3.png');
+      .listItemBoxInner {
+        border-top: 1px solid #86A7FF;
+        border-bottom: 1px solid #86A7FF;
+        .itemInfo {
+          color: #86A7FF;
+          .amount {
+            border-bottom: 1px solid #86A7FF;
+          }
+          .couponInfo {
+            p {
+              color: #86A7FF;
+            }
+          }
+        }
+        .receiveBtn {
+          background: #86A7FF;
+        }
+      }
+    }
+  }
+}
+</style>

+ 230 - 0
canvas-container/components/canvasShow/basics/custom.vue

@@ -0,0 +1,230 @@
+<template>
+  <div class="custom" :class="'terminal' + terminal">
+    <div class="rowLayout" v-if="componentContent.layoutType ==='L1' || componentContent.layoutType ==='L2' || componentContent.layoutType ==='L3' || componentContent.layoutType ==='L4'">
+      <div class="customLayout" :style="{'padding':'0 ' + componentContent.pageSpacing + 'px','marginLeft':(-componentContent.imgClearance) +'px'}">
+        <ul class="clearfix" :class="'layout'+componentContent.layoutType">
+          <li v-for="(item,index) of componentContent.imgData" :key="index" :style="{'width':getItemValue(item.width) + '%','height':getItemValue(item.height) + '%','left':getItemValue(item.left) + '%','top':getItemValue(item.top) + '%','paddingLeft':componentContent.imgClearance +'px'}">
+            <a class="a-link" @click="jumpLink(item.linkObj)"><img class="img" :src="item.src" v-if="item.src"></a>
+          </li>
+        </ul>
+      </div>
+    </div>
+    <div v-else :style="{'padding':'0 ' + componentContent.pageSpacing + 'px'}">
+      <div class="boxLayout" :style="{'paddingBottom':componentContent.maxH !== 0?getItemValue(componentContent.maxH) + '%': '100%'}">
+        <div class="boxLayoutInner">
+          <div class="boxWarp">
+            <div class="customLayout" :style="{'marginLeft':(-componentContent.imgClearance) +'px','top':(-componentContent.imgClearance) +'px'}">
+              <ul class="clearfix" :class="'layout'+componentContent.layoutType">
+                <li v-for="(item,index) of componentContent.imgData" :key="index" :style="{'width':getItemValue(item.width) + '%','height':getItemValue(item.height) + '%','left':getItemValue(item.left) + '%','top':getItemValue(item.top) + '%','padding':componentContent.imgClearance +'px 0 0 ' + componentContent.imgClearance +'px'}">
+                  <a class="a-link" @click="jumpLink(item.linkObj)"><img class="img" :src="item.src" v-if="item.src"></a>
+                </li>
+              </ul>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+  import {funMixin} from '../config/mixin'
+  export default {
+    name: 'customComponent',
+    mixins: [funMixin],
+    data () {
+      return {
+      }
+    },
+    props: {
+      terminal: {
+        type: Number,
+        default: 4
+      },
+      componentContent: {
+        type: Object
+      }
+    },
+    methods: {
+      // 计算生成格子百分比
+      getItemValue (val) {
+        const density = parseInt(this.componentContent.density)
+        if (val === 0 || density === 0) {
+          return 0
+        }
+        return (val / density * 10000 / 100.00)// 小数点后两位百分比
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+  .custom{
+    .boxLayout{
+      position: relative;
+      .boxLayoutInner{
+        padding-bottom: 100%;
+        position: absolute;
+        width: 100%;
+        left: 0;
+        top: 0;
+      }
+      .boxWarp{
+        position: absolute;
+        width: 100%;
+        height: 100%;
+        left: 0;
+        top: 0;
+        overflow: hidden;
+      }
+    }
+    .customLayout{
+      position: relative;
+      ul{
+        display: flex;
+        flex-wrap: wrap;
+        position: relative;
+      }
+      li{
+        .img{
+          width: 100%;
+          display: block;
+        }
+      }
+      .layoutL1 li{
+        flex: 0 0 100%;
+      }
+      .layoutL2 li{
+        flex: 0 0 50%;
+      }
+      .layoutL3 li{
+        flex: 0 0 33.3%;
+      }
+      .layoutL4 li{
+        flex: 0 0 25%;
+      }
+      .layoutT2B2{
+        padding-bottom: 100%;
+        li{
+          width: 50%;
+          height: 50%;
+          position: absolute;
+          .img{
+            width: 100%;
+            height: 100%;
+          }
+          &:nth-child(1){
+            left: 0;
+            top: 0;
+          }
+          &:nth-child(2){
+            right: 0;
+            top: 0;
+          }
+          &:nth-child(3){
+            left: 0;
+            bottom: 0;
+          }
+          &:nth-child(4){
+            right: 0;
+            bottom: 0;
+          }
+        }
+      }
+      .layoutL1R2{
+        padding-bottom: 100%;
+        li{
+          width: 50%;
+          height: 50%;
+          position: absolute;
+          .img{
+            width: 100%;
+            height: 100%;
+          }
+          &:nth-child(1){
+            height: 100%;
+            left: 0;
+            top: 0;
+          }
+          &:nth-child(2){
+            right: 0;
+            top: 0;
+          }
+          &:nth-child(3){
+            right: 0;
+            bottom: 0;
+          }
+        }
+      }
+      .layoutT1B2{
+        padding-bottom: 100%;
+        li{
+          width: 50%;
+          height: 50%;
+          position: absolute;
+          .img{
+            width: 100%;
+            height: 100%;
+          }
+          &:nth-child(1){
+            width: 100%;
+            left: 0;
+            top: 0;
+          }
+          &:nth-child(2){
+            left: 0;
+            bottom: 0;
+          }
+          &:nth-child(3){
+            right: 0;
+            bottom: 0;
+          }
+        }
+      }
+      .layoutL1T1B2{
+        padding-bottom: 50%;
+        li{
+          position: absolute;
+          .img{
+            width: 100%;
+            height: 100%;
+          }
+          &:nth-child(1){
+            width: 50%;
+            height: 100%;
+            left: 0;
+            top: 0;
+          }
+          &:nth-child(2){
+            right: 0;
+            top: 0;
+            width: 50%;
+            height: 50%;
+          }
+          &:nth-child(3){
+            left: 50%;
+            bottom: 0;
+            width: 25%;
+            height: 50%;
+          }
+          &:nth-child(4){
+            right: 0;
+            bottom: 0;
+            width: 25%;
+            height: 50%;
+          }
+        }
+      }
+      .layoutaverage{
+        padding-bottom: 100%;
+        li{
+          position: absolute;
+          .img{
+            width: 100%;
+            height: 100%;
+          }
+        }
+      }
+    }
+  }
+</style>

+ 238 - 0
canvas-container/components/canvasShow/basics/discount/app/index.vue

@@ -0,0 +1,238 @@
+<template>
+  <div class="hom-pro-list">
+    <div class="title">
+      <img src="../../../static/images/discount/img-title.png" alt="限时折扣"/>
+    </div>
+    <div v-if="componentContent.arrangeType == '横向滑动'" class="product-list product-swiper">
+      <swiper ref="mySwiper" class="product-list-box" :options="swiperOption">
+        <swiper-slide class="product-list-item" v-for="(item,index) in productData.products" :key="index" @click="jumpProductDetail(item)">
+          <div class="product-list-img">
+            <img v-show="item.image" class="img" :src="item.image">
+          </div>
+          <div class="product-list-info">
+            <label class="product-name">{{item.productName}}</label>
+            <div>
+              <div class="flag">
+                <img src="../../../static/images/discount/flag-discount2.png" alt="限时折扣"/>
+              </div>
+              <label class="buy-count">剩余{{item.stockNumber}}件</label>
+            </div>
+            <div class="price-warp">
+              <div class="price">
+                ¥ {{item.price}}
+              </div>
+              <div class="original-price">
+                ¥ {{item.originalPrice}}
+              </div>
+            </div>
+          </div>
+        </swiper-slide>
+      </swiper>
+      <div class="pagination discount-pagination" slot="pagination"></div>
+    </div>
+    <div v-if="componentContent.arrangeType == '多行多列'" class="product-list">
+      <div class="product-list-box" >
+        <div class="product-list-item" v-for="(item,index) in productData.products" :key="index" @click="jumpProductDetail(item)">
+          <div class="product-list-img">
+            <img v-show="item.image" class="img" :src="item.image">
+          </div>
+          <div class="product-list-info">
+            <label class="product-name">{{item.productName}}</label>
+            <div>
+              <div class="flag">
+                <img src="../../../static/images/discount/flag-discount2.png" alt="限时折扣"/>
+              </div>
+              <label class="buy-count">剩余{{item.stockNumber}}件</label>
+            </div>
+            <div class="price-warp">
+              <div class="price">
+                ¥ {{item.price}}
+              </div>
+              <div class="original-price">
+                ¥ {{item.originalPrice}}
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <button v-show="componentContent.showMore" class="btn-more" @click="jumpGroupWorks(productData)">查看全部 <span class="icon iconfont icon-arrow-right"></span></button>
+  </div>
+</template>
+
+<script>
+import {commonMixin} from '../mixin'
+export default {
+  mixins: [commonMixin],
+  data () {
+    return {
+      swiperOption: {
+        slidesPerView: 2,
+        spaceBetween: 14,
+        autoplay: false, // 可选选项,自动滑动
+        loop: true,
+        pagination: {
+          el: '.discount-pagination',
+          clickable: true
+        },
+        navigation: {
+          nextEl: '.swiper-button-next',
+          prevEl: '.swiper-button-prev'
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.hom-pro-list{
+  padding: 20px 0;
+  .title{
+    text-align: center;
+    margin-bottom: 20px;
+    label{
+      background: url("../../../static/images/icon-title.png") no-repeat left center;
+      font-size: 30px;
+      font-weight: bold;
+      padding-left: 48px;
+    }
+  }
+  /**多行多列**/
+  .product-list {
+    position: relative;
+    &-box {
+      display: flex;
+      flex-wrap: wrap;
+      flex-direction: row;
+      padding-left: 20px;
+    }
+    &.product-swiper .product-list-box{
+      margin: 0 20px;
+      padding-left: 0;
+    }
+    &-item {
+      margin: 0 14px 20px 0;
+      width: 348px;
+    }
+    &-img {
+      width: 348px;
+      height: 348px;
+      background-color: #f5f5f5;
+      border-radius: 10px 10px 0 0;
+      .img {
+        width: 100%;
+        height: 100%;
+        object-fit: contain;
+      }
+    }
+    &-info {
+      background-color: #FFFFFF;
+      //box-shadow: 0px 0px 15px 0px rgba(52, 52, 52, 0.15);
+      border-radius: 0 0 10px 10px;
+      padding: 20px;
+      label{
+        font-weight: normal;
+      }
+      .product-name{
+        font-size: 28px;
+        color: #333;
+        display: block;
+        overflow: hidden;
+        text-overflow:ellipsis;
+        white-space: nowrap;
+        margin-bottom: 18px;
+        line-height: 40px;
+      }
+      .shop-box{
+        background-color: #333333;
+        border-radius: 0px 20px 20px 0px;
+        line-height: 40px;
+        display: inline-block;
+        height: 40px;
+        margin-right: 10px;
+        .shop-name{
+          font-size: 20px;
+          color: #FFEBC4;
+          padding: 0 8px 0 12px;
+        }
+        .shop-logo{
+          border: 2px solid #707070;
+          border-radius: 50%;
+          overflow: hidden;
+          float: right;
+          img{
+            width: 34px;
+            height: 34px;
+            display: block;
+          }
+        }
+      }
+      .flag{
+        float: left;
+        margin-right: 20px;
+        img{
+          height: 44px;
+        }
+      }
+      .buy-count{
+        color: #C5AA7B;
+        font-size: 20px;
+        border: 2px solid #E4E5E6;
+        line-height: 40px;
+        padding: 0 5px;
+        display: inline-block;
+      }
+      .price-warp{
+        display: flex;
+        align-items: baseline;
+        line-height: 56px;
+        margin-top: 16px;
+        .price{
+          color: #C83732;
+          font-size: 40px;
+          margin-right: 20px;
+        }
+        .original-price{
+          font-size: 24px;
+          color: #ccc;
+          text-decoration: line-through;
+        }
+      }
+    }
+    //::v-deep .swiper-pagination-bullet{
+    //  display: none;
+    //}
+  }
+}
+
+.pagination{
+  display: flex;
+  justify-content: center;
+  padding: 20px 0;
+  ::v-deep .swiper-pagination-bullet{
+    width: 10px;
+    height: 10px;
+    background: #333333;
+    opacity: 0.3;
+    border-radius: 5px;
+    margin: 0 5px;
+  }
+  ::v-deep .swiper-pagination-bullet-active{
+    width: 20px;
+    height: 10px;
+    opacity: 1;
+  }
+}
+.btn-more {
+  width: 170px;
+  height: 54px;
+  border: 2px solid #C5AA7B;
+  color: #C5AA7B;
+  font-size: 24px;
+  background-color: transparent;
+  margin: 20px auto 0;
+  display: block;
+}
+
+</style>

+ 118 - 0
canvas-container/components/canvasShow/basics/discount/mixin.js

@@ -0,0 +1,118 @@
+import { directive, Swiper, SwiperSlide } from 'vue-awesome-swiper'
+import 'swiper/css/swiper.css'
+import api from '../../config/api'
+import {funMixin} from '../../config/mixin'
+import { mapGetters } from 'vuex'
+
+export const commonMixin = {
+  name: 'discountList',
+  mixins: [funMixin],
+  data () {
+    return {
+      value: 100,
+      productData: {},
+      count: [],
+      timer: null
+    }
+  },
+  props: {
+    terminal: {
+      type: Number,
+      default: 4
+    },
+    typeId: {
+      type: Number,
+      default: 1
+    },
+    shopId: {
+      type: Number,
+      default: 0
+    },
+    componentContent: {
+      type: Object
+    }
+  },
+  components: {
+    Swiper,
+    SwiperSlide
+  },
+  directives: {
+    swiper: directive
+  },
+  computed: {
+    ...mapGetters([
+      'discountNum'
+    ]),
+  },
+  watch: {
+    'discountNum': {
+      handler(newVal, oldVal) {
+        this.getData()
+      },
+      deep: true
+    }
+  },
+  mounted() {
+      this.getData()
+  },
+  methods: {
+    getData() {
+      const _ = this
+      if(_.componentContent.discountId){
+        this.beforeGetData()
+        var _url= ''
+        if(this.typeId === 1){
+          _url= `${api.getMinDiscount}?ids=${_.componentContent.discountId}`
+        }
+        if(this.typeId === 3){
+          _url= `${api.getDiscounts}?shopId=${_.shopId}&ids=${_.componentContent.discountId}`
+        }
+        const params = {
+          method: 'GET',
+          url: _url,
+        }
+        this.sendReq(params, (res) => {
+          _.afterGetData()
+          if(res.data.length> 0){
+            _.productData = res.data[0]
+            // 只有进行中和未开始活动, 用倒计时
+            if(_.productData.state !==2) {
+              this.timer = setInterval(()=>{
+                _.getTime(_.productData)
+              }, 1000)
+            }
+          }
+        },(err)=>{
+          _.afterGetData()
+        })
+      } else {
+        _.productData = {
+          products:[]
+        }
+      }
+    },
+    getTime(info) {
+      const date = new Date().getTime()
+      const startTime = new Date(info.startTime.replace(/-/g,'/')).getTime()
+      const endTime = new Date(info.endTime.replace(/-/g,'/')).getTime()
+      if(startTime > date) {
+        this.countDown(startTime-date,true) // 未开始
+      } else {
+        this.countDown(endTime-date) // 进行中
+      }
+
+    },
+    countDown(time, isStart) {
+      const fn = (v) =>  v < 10 ? `0${v}` : v
+      const t = parseInt(time / 1000)
+      const text = isStart ? '开始' : '结束'
+      const hour = parseInt(t / 3600)
+      const min = parseInt((t % 3600) / 60)
+      const s = t % 60
+      this.count = [text, fn(hour), fn(min), fn(s)]
+    }
+  },
+  beforeDestroy() {
+    clearInterval(this.timer)
+  }
+}

+ 247 - 0
canvas-container/components/canvasShow/basics/discount/pc/index.vue

@@ -0,0 +1,247 @@
+<template>
+  <div class="discount">
+    <div class="discount-top">
+      <div class="discount-top-text">全场5折起</div>
+      <div class="discount-top-time">
+<!--        距{{count[0]}}-->
+        距离本场结束还有
+        <div class="time"><span>{{count[1]}}</span>:<span>{{count[2]}}</span>:<span>{{count[3]}}</span></div></div>
+    </div>
+    <div class="discount-more" :style="{backgroundImage: 'url('+ componentContent.moreBg +')'}">
+      <div class="discount-more-overlay">
+        <button class="btn-more" @click="jumpGroupWorks(productData)">查看全部</button>
+      </div>
+    </div>
+    <div class="discount-list">
+      <div class="swiper-button-prev"></div>
+      <div class="swiper-button-next"></div>
+      <swiper class="products-swiper" :options="swiperOption">
+        <swiper-slide class="products-swiper-slide item" v-for="(item,index) in productData.products" :key="index">
+          <div class="a-link" @click="jumpProductDetail(item)">
+            <div class="itemImgBox">
+              <div class="imgBox">
+                <el-image
+                  :src="item.image"
+                  fit="contain"></el-image>
+              </div>
+            </div>
+            <div class="text">
+              <h4 class="h4">{{item.productName}}</h4>
+              <div class="priceBox">
+                <span class="discount" v-if="item.originalPrice">¥{{item.originalPrice}}</span>
+                <dl>
+                  <dt><img src="../../../static/images/discount/flag-discount.png" alt="折扣价"></dt>
+                  <dd>
+                    ¥{{item.price}}
+                  </dd>
+                </dl>
+              </div>
+            </div>
+          </div>
+        </swiper-slide>
+      </swiper>
+    </div>
+  </div>
+</template>
+
+<script>
+import {commonMixin} from '../mixin'
+export default {
+  mixins: [commonMixin],
+  data () {
+    return {
+      swiperOption: {
+        slidesPerView: 3, // 显示数量
+        spaceBetween: 13, // 间隔
+        autoplay: false, // 可选选项,自动滑动
+        loop: true,
+        pagination: {
+          el: '.discount-pagination'
+        },
+        navigation: {
+          nextEl: '.swiper-button-next',
+          prevEl: '.swiper-button-prev'
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.discount{
+  width: 1200px;
+  max-width: 100%;
+  margin: 0 auto;
+  overflow: hidden;
+  &-top{
+    height: 250px;
+    padding-top: 96px;
+    margin-bottom: 15px;
+    background: url("../../../static/images/discount/bg-discount-top.png") no-repeat;
+    &-text{
+      background: url("../../../static/images/discount/bg-discount-top-text.png") no-repeat;
+      width: 176px;
+      height: 83px;
+      padding-top: 13px;
+      line-height: 50px;
+      font-size: 25px;
+      color: #fff;
+      margin: 0px auto 18px;
+      text-align: center;
+    }
+    &-time{
+      margin: 0 auto;
+      text-align: center;
+      font-size: 16px;
+      color: #FFEBC4;
+      .time{
+        font-size: 20px;
+        color: #999;
+        display: inline-block;
+        span{
+          display: inline-block;
+          line-height: 40px;
+          padding: 0 9px;
+          margin: 0 5px;
+          background-color: #343434;
+          color: #fff;
+        }
+      }
+    }
+  }
+  &-list{
+    margin-right: 303px;
+    position: relative;
+    .swiper-button-prev,.swiper-button-next{
+      width: 95px;
+      height: 95px;
+      position: absolute;
+      cursor:pointer;
+      top: 115px;
+      background-repeat: no-repeat;
+      &:after{
+        content: '';
+      }
+    }
+    .swiper-button-prev{
+      left: -22px;
+      background: url('../../../static/images/btn-prev2.png');
+    }
+    .swiper-button-next{
+      right: -22px;
+      background: url('../../../static/images/btn-next2.png');
+    }
+    .a-link{
+      cursor: pointer;
+      &:hover{
+        box-shadow: 3px 4px 20px 0px rgba(186, 186, 186, 0.5);
+      }
+      .itemImgBox {
+        height: auto;
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+        .imgBox {
+          padding-bottom: 100%;
+          background-color: #cacaca;
+          position: relative;
+          .el-image {
+            width: 100%;
+            height: 100%;
+            position: absolute;
+            top: 0;
+            left: 0;
+          }
+        }
+      }
+      .text{
+        padding:25px 20px 17px;
+        text-align: center;
+        //height: 180px;
+        .h4{
+          font-size: 18px;
+          line-height: 24px;
+          overflow: hidden;
+          text-overflow:ellipsis;
+          white-space: nowrap;
+          color: #333333;
+          //max-height: 48px;
+        }
+        .p{
+          color: #999;
+          font-size: 16px;
+          overflow: hidden;
+          text-overflow:ellipsis;
+          white-space: nowrap;
+          padding-top: 18px;
+          position: relative;
+          margin-top: 8px;
+          &:after{
+            position: absolute;
+            top: 0;
+            left: 50%;
+            margin-left: -80px;
+            width: 160px;
+            height: 2px;
+            background: #F0F0F0;
+            content: '';
+          }
+        }
+        .priceBox {
+          dl {
+            display: inline-block;
+            min-width: 130px;
+            dt{
+              float: left;
+              img{
+                display: block;
+              }
+            }
+            dd{
+              border: 1px solid #F3F4F5;
+              font-size: 25px;
+              line-height: 34px;
+              color: #C83732;
+              margin-left: 57px;
+              padding: 0 10px;
+            }
+          }
+          span.discount {
+            display: block;
+            font-size: 18px;
+            line-height: 24px;
+            padding: 15px 0 11px;
+            color: #ccc;
+            text-decoration: line-through;
+          }
+        }
+      }
+    }
+  }
+  &-more{
+    width: 290px;
+    height: 466px;
+    float: right;
+    position: relative;
+    &-overlay{
+      position: absolute;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+      background-color: rgba(0,0,0,0.6);
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      .btn-more{
+        width: 130px;
+        height: 41px;
+        background-color: #fff;
+        font-size: 18px;
+        color: #C5AA7B;
+      }
+    }
+  }
+}
+</style>

+ 149 - 0
canvas-container/components/canvasShow/basics/group/app/index.vue

@@ -0,0 +1,149 @@
+<template>
+  <div class="group-list">
+    <div class="group-warp">
+      <div class="title">
+        <label>
+          <img src="../../../static/images/group/img-title.png" alt="拼团专区"/>
+        </label>
+        <a v-show="componentContent.showMore" class="btn-all a-link" @click="jumpDiscount(productData)">更多<i class="iconfont icon-arrow-right"></i></a>
+      </div>
+      <swiper class="pro-box" :options="swiperOption">
+        <swiper-slide class="pro-item" v-for="(item,index) in productData.products" :key="index" @click="jumpProductDetail(item)">
+          <div class="pro-item-img">
+            <img v-show="item.image" class="img" :src="item.image">
+          </div>
+          <div class="pro-item-info">
+            <label class="name">{{item.productName}}</label>
+            <div class="price">
+              <label class="unit">¥ </label>
+              <label class="val"> {{item.price}}</label>
+            </div>
+            <label class="buyCount">{{item.workUsers?item.workUsers:0}}人已拼</label>
+          </div>
+        </swiper-slide>
+      </swiper>
+      <div class="pagination group-pagination"></div>
+    </div>
+  </div>
+
+</template>
+
+<script>
+import {commonMixin} from '../mixin'
+export default {
+  mixins: [commonMixin],
+  data () {
+    return {
+      swiperOption: {
+        slidesPerView: 3, // 显示数量
+        spaceBetween: 16, // 间隔
+        autoplay: false, // 可选选项,自动滑动
+        loop: true,
+        pagination: {
+          el: '.group-pagination'
+        },
+        navigation: {
+          nextEl: '.swiper-button-next',
+          prevEl: '.swiper-button-prev'
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  .group-list{
+    padding: 30px 20px 60px;
+    .group-warp{
+      width: 710px;
+      height: 528px;
+      padding: 0 10px;
+      background: #333333;
+      box-shadow: 0px 20px 30px rgba(0, 0, 0, 0.3);
+      opacity: 1;
+      border-radius: 20px;
+    }
+    .title{
+      display: flex;
+      align-items:center;
+      position: relative;
+      padding: 40px 0 30px 20px;
+      .btn-all{
+        position: absolute;
+        right: 8px;
+        top: 40px;
+        line-height: 33px;
+        padding-right: 25px;
+        font-size: 24px;
+        color: #FFEBC4;
+        .iconfont{
+          content: '';
+          font-size: 26px;
+          position: absolute;
+          right: 0;
+          top: 0;
+        }
+      }
+    }
+    .pro-box{
+      padding-bottom: 20px;
+      .pro-item{
+        width: 220px;
+        height: 382px;
+        background: #FFFFFF;
+        .pro-item-img{
+          .img{
+            width: 100%;
+            height: 220px;
+          }
+        }
+        .pro-item-info{
+          text-align: center;
+          padding: 0px 10px 20px;
+          .name{
+            font-size: 24px;
+            font-weight: normal;
+            color: #FFEBC4;
+            line-height: 50px;
+            background-color: #333333;
+            text-align: center;
+            margin-bottom: 18px;
+            padding: 0 5px;
+            display: block;
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+          }
+          .price{
+            color: #C83732;
+            font-size: 28px;
+            font-weight: bold;
+            line-height: 40px;
+          }
+          .buyCount{
+            font-size: 24px;
+            color: #ccc;
+            line-height: 34px;
+            font-weight: normal;
+          }
+        }
+      }
+    }
+    .pagination{
+      display: flex;
+      justify-content: center;
+      ::v-deep .swiper-pagination-bullet{
+        width: 24px;
+        height: 4px;
+        background: #fff;
+        opacity: 0.5;
+        border-radius: 2px;
+        margin: 0 5px;
+      }
+      ::v-deep .swiper-pagination-bullet-active{
+        opacity: 1;
+      }
+    }
+  }
+</style>

+ 94 - 0
canvas-container/components/canvasShow/basics/group/mixin.js

@@ -0,0 +1,94 @@
+import { directive, Swiper, SwiperSlide } from 'vue-awesome-swiper'
+import 'swiper/css/swiper.css'
+import api from '../../config/api'
+import {funMixin} from '../../config/mixin'
+import { mapGetters } from 'vuex'
+
+export const commonMixin = {
+  name: 'productList',
+  mixins: [funMixin],
+  props: {
+    terminal: {
+      type: Number,
+      default: 4
+    },
+    typeId: {
+      type: Number,
+      default: 1
+    },
+    shopId: {
+      type: Number,
+      default: 0
+    },
+    componentContent: {
+      type: Object
+    }
+  },
+  components: {
+    Swiper,
+    SwiperSlide
+  },
+  directives: {
+    swiper: directive
+  },
+  data () {
+    return {
+      productData: []
+    }
+  },
+  computed: {
+    ...mapGetters([
+      'groupNum'
+    ]),
+  },
+  watch: {
+    'groupNum': {
+      handler(newVal, oldVal) {
+        this.getData()
+      },
+      deep: true
+    }
+  },
+  mounted() {
+      this.getData()
+  },
+  methods: {
+      getData() {
+        const _ = this
+        let _url = ''
+        if(_.typeId === 1){
+          this.beforeGetData()
+          const params = {
+            method: 'GET',
+            url: `${api.getAdminGroupWorks}`,
+          }
+          this.sendReq(params, (res) => {
+            _.afterGetData()
+            _.productData.products = res.data
+            _.$forceUpdate()
+          },(err)=>{
+            _.afterGetData()
+          })
+        } else if(_.typeId === 3) {
+          if(_.componentContent.shopGroupWorkId){
+            this.beforeGetData()
+            const params = {
+              method: 'GET',
+              url: `${api.getGroupWorks}?shopId=${_.shopId}&ids=${_.componentContent.shopGroupWorkId}`,
+            }
+            this.sendReq(params, (res) => {
+              _.afterGetData()
+              _.productData = res.data[0]
+            },(err)=>{
+              _.afterGetData()
+            })
+          } else {
+            _.productData = {
+              products:[]
+            }
+          }
+        }
+
+      },
+  }
+}

+ 250 - 0
canvas-container/components/canvasShow/basics/group/pc/index.vue

@@ -0,0 +1,250 @@
+<template>
+  <div class="product-list" :class="'terminal'+terminal">
+    <div class="picListWarp" v-if="componentContent.arrangeType == '横向滑动'">
+      <div class="picList" v-if="productData.products && productData.products.length>0">
+        <div class="swiper-button-prev"></div>
+        <div class="swiper-button-next"></div>
+        <swiper class="products-swiper" :options="swiperOption">
+          <swiper-slide class="products-swiper-slide item" v-for="(item,index) in productData.products" :key="index">
+            <div class="a-link" @click="jumpProductDetail(item)">
+              <div class="itemImgBox">
+                <div class="imgBox">
+                  <el-image
+                    :src="item.image"
+                    fit="contain"></el-image>
+                </div>
+              </div>
+              <div class="text">
+                <h4 class="h4">{{item.productName}}</h4>
+                <div class="priceBox">
+                  <span class="discount" v-if="item.originalPrice">¥{{item.originalPrice}}</span>
+                  <dl>
+                    <dt><img src="../../../static/images/group/flag-group.png" alt="拼团价"></dt>
+                    <dd>
+                      ¥{{item.price}}
+                    </dd>
+                  </dl>
+                </div>
+              </div>
+            </div>
+          </swiper-slide>
+        </swiper>
+      </div>
+    </div>
+    <div v-else class="picList" >
+      <ul class="clearfix" :class="'imgTextNum' +  componentContent.productNum"  v-if="productData.products && productData.products.length>0">
+        <li class="item" v-for="(item,index) in productData.products.slice(0, componentContent.productRowNum * componentContent.productNum)" :key="index">
+          <div class="a-link" @click="jumpProductDetail(item)">
+            <div class="itemImgBox">
+              <div class="imgBox">
+                <el-image
+                  :src="item.image"
+                  fit="contain"></el-image>
+              </div>
+            </div>
+            <div class="text">
+              <h4 class="h4">{{item.productName}}</h4>
+              <div class="priceBox">
+                <span class="discount" v-if="item.originalPrice">¥{{item.originalPrice}}</span>
+                <dl>
+                  <dt><img src="../../../static/images/group/flag-group.png" alt="拼团价"></dt>
+                  <dd>
+                    ¥{{item.price}}
+                  </dd>
+                </dl>
+              </div>
+            </div>
+          </div>
+        </li>
+      </ul>
+    </div>
+    <button v-show="componentContent.showMore" class="btn-more" @click="jumpGroupWorks(productData)">查看全部 <span class="icon iconfont icon-arrow-right"></span></button>
+  </div>
+</template>
+
+<script>
+  import {commonMixin} from '../mixin'
+  export default {
+    mixins: [commonMixin],
+    data () {
+      return {
+        swiperOption: {
+          slidesPerView: 4, // 显示数量
+          spaceBetween: 13, // 间隔
+          autoplay: false, // 可选选项,自动滑动
+          loop: true,
+          pagination: {
+            el: '.group-pagination'
+          },
+          navigation: {
+            nextEl: '.swiper-button-next',
+            prevEl: '.swiper-button-prev'
+          }
+        }
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+.product-list{
+  padding: 20px 0;
+  background-color: #fff;
+  .picListWarp{
+    width: 1380px;
+    max-width: 100%;
+    margin: 0 auto;
+    position: relative;
+  }
+  .picList{
+    width: 1200px;
+    max-width: 100%;
+    margin: 0 auto;
+    .swiper-button-prev,.swiper-button-next{
+      width: 50px;
+      height: 50px;
+      position: absolute;
+      cursor:pointer;
+      top: 140px;
+      background-repeat: no-repeat;
+      &:after{
+        content: '';
+      }
+    }
+    .swiper-button-prev{
+      left: 0;
+      background: url('../../../static/images/btn-prev.png');
+    }
+    .swiper-button-next{
+      right: 0;
+      background: url('../../../static/images/btn-next.png');
+    }
+    .a-link{
+      cursor: pointer;
+      &:hover{
+        box-shadow: 3px 4px 20px 0px rgba(186, 186, 186, 0.5);
+      }
+      .itemImgBox {
+        height: auto;
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+        .imgBox {
+          padding-bottom: 100%;
+          background-color: #cacaca;
+          position: relative;
+          .el-image {
+            width: 100%;
+            height: 100%;
+            position: absolute;
+            top: 0;
+            left: 0;
+          }
+        }
+      }
+      .text{
+        padding:25px 20px 17px;
+        text-align: center;
+        //height: 180px;
+        .h4{
+          font-size: 18px;
+          line-height: 24px;
+          overflow: hidden;
+          text-overflow:ellipsis;
+          white-space: nowrap;
+          color: #333333;
+          //max-height: 48px;
+        }
+        .p{
+          color: #999;
+          font-size: 16px;
+          overflow: hidden;
+          text-overflow:ellipsis;
+          white-space: nowrap;
+          padding-top: 18px;
+          position: relative;
+          margin-top: 8px;
+          &:after{
+            position: absolute;
+            top: 0;
+            left: 50%;
+            margin-left: -80px;
+            width: 160px;
+            height: 2px;
+            background: #F0F0F0;
+            content: '';
+          }
+        }
+        .priceBox {
+          dl {
+            display: inline-block;
+            min-width: 130px;
+            dt{
+              float: left;
+              img{
+                display: block;
+              }
+            }
+            dd{
+              border: 1px solid #F3F4F5;
+              font-size: 25px;
+              line-height: 34px;
+              color: #C83732;
+              margin-left: 57px;
+              padding: 0 10px;
+            }
+          }
+          span.discount {
+            display: block;
+            font-size: 18px;
+            line-height: 24px;
+            padding: 15px 0 11px;
+            color: #ccc;
+            text-decoration: line-through;
+          }
+        }
+      }
+    }
+    ul{
+      margin: -15px 0 0 -15px;
+      display: flex;
+      flex-wrap: wrap;
+      li{
+        flex: 0 0 50%;
+        padding: 15px 0 0 15px;
+        width: 0;
+      }
+    }
+    .imgTextNum2 {
+      li {
+        flex: 0 0 50%;
+      }
+    }
+    .imgTextNum3 {
+      li {
+        flex: 0 0 33.33%;
+      }
+    }
+    .imgTextNum4 {
+      li {
+        flex: 0 0 25%;
+      }
+    }
+    .imgTextNum5 {
+      li {
+        flex: 0 0 20%;
+      }
+    }
+  }
+}
+.btn-more {
+  width: 130px;
+  height: 41px;
+  border: 2px solid #C5AA7B;
+  color: #C5AA7B;
+  font-size: 18px;
+  background-color: transparent;
+  margin: 20px auto 0;
+  display: block;
+}
+</style>

+ 104 - 0
canvas-container/components/canvasShow/basics/header/app/index.vue

@@ -0,0 +1,104 @@
+<template>
+  <div class="header">
+    <div class="top-box">
+      <img v-if="componentContent.logoType === 1" class="logo"
+             :src="componentContent.imageUrl"
+           mode="heightFix">
+      <h3 v-else class="h3" :style="{fontSize:componentContent.fontSizeNum+'px',fontWeight:componentContent.textFontW,color:componentContent.titColor}">{{componentContent.title}}</h3>
+      <div class="search-btn">
+        <img class="search-icon"
+               src="../../../static/images/search.png"
+               mode="widthFix">
+      </div>
+    </div>
+    <div class="tabs-nav-warp">
+      <div class="tabs-nav" scroll-x="true">
+        <div class="ul">
+          <div class="li" :class="{'on':activeTab===0}" @click="tabChange(0)">首页</div>
+          <div class="li" :class="{'on':activeTab===index+1}" v-for="(item,index) in classifyData" :key="index">
+            {{item.categoryName}}
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import {commonMixin} from '../mixin'
+export default {
+  mixins: [commonMixin],
+  data () {
+    return {
+      activeTab: 0
+    }
+  },
+  computed: {
+
+  },
+}
+</script>
+
+<style lang="scss" scoped>
+  .header {
+    .top-box {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      padding-left: 30px;
+      width: 100%;
+      .logo {
+        // width: 280px;
+        height: 70px;
+        margin-top: 0px;
+      }
+
+      .search-btn {
+        height: 66px;
+        background: rgba(255, 255, 255, 1);
+        border-radius: 33px;
+        display: flex;
+        flex-direction: row;
+        align-items: center;
+        margin-right: 30px;
+        .search-icon {
+          width: 60px;
+          height: 60px;
+        }
+      }
+    }
+  }
+  .tabs-nav-warp{
+    margin-top: 20px;
+    padding:0 30px;
+    overflow: hidden;
+    .tabs-nav{
+      .ul{
+        display: flex;
+        .li{
+          flex: 1 0 auto;
+          margin-left: 36px;
+          font-size: 30px;
+          color: #999999;
+          position: relative;
+          padding-bottom: 18px;
+          &:first-child{
+            margin-left: 0;
+          }
+          &.on{
+            &:after{
+              content: '';
+              width: 100%;
+              height: 4px;
+              background: #C5AA7B;
+              position: absolute;
+              left: 0;
+              bottom: 0;
+            }
+            font-weight:bold;
+          }
+        }
+      }
+    }
+  }
+</style>

+ 48 - 0
canvas-container/components/canvasShow/basics/header/mixin.js

@@ -0,0 +1,48 @@
+import api from '../../config/api'
+import {funMixin} from '../../config/mixin'
+
+export const commonMixin = {
+  name: 'headerComponent',
+  mixins: [funMixin],
+  props: {
+    terminal: {
+      type: Number,
+      default: 4
+    },
+    typeId: {
+      type: Number,
+      default: 1
+    },
+    shopId: {
+      type: Number,
+      default: 0
+    },
+    componentContent: {
+      type: Object
+    }
+  },
+  data () {
+    return {
+      classifyData: []
+    }
+  },
+  mounted() {
+      this.getData()
+  },
+  methods: {
+    getData() {
+      this.beforeGetData()
+      const _ = this
+      _.sendReq({
+        url: `${api.getClassify}?page=1&pageSize=20`,
+        method: 'GET'
+      }, (res) => {
+        _.afterGetData()
+        _.classifyData = res.data
+        console.log(_.classifyData)
+      },(err)=>{
+        _.afterGetData()
+      })
+    }
+  }
+}

+ 108 - 0
canvas-container/components/canvasShow/basics/header/pc/index.vue

@@ -0,0 +1,108 @@
+<template>
+  <div class="header">
+    <nav class="nav">
+      <ul>
+        <li class="on">
+          <router-link to="/">
+            首页
+          </router-link>
+        </li>
+        <li v-for="(item,index) in classifyData.slice(0, 6)" :key="index" @click="jumpCategory(item)">
+          {{item.categoryName}}
+        </li>
+      </ul>
+    </nav>
+    <div class="search">
+      <div class="searchSelect">
+        <el-dropdown trigger="click">
+              <span class="el-dropdown-link">宝贝
+                <i class="el-icon-arrow-down cur-poi el-icon--right"></i>
+              </span>
+          <el-dropdown-menu slot="dropdown">
+            <el-dropdown-item command="宝贝">宝贝</el-dropdown-item>
+            <el-dropdown-item command="店铺">店铺</el-dropdown-item>
+          </el-dropdown-menu>
+        </el-dropdown>
+      </div>
+      <div class="searchRight">
+        <input type="text" maxlength="20" placeholder="请输入搜索商品">
+      </div>
+      <span class="btn cur-poi">
+        <i class="icon el-icon-search"></i>
+      </span>
+    </div>
+  </div>
+</template>
+
+<script>
+  import {commonMixin} from '../mixin'
+  export default {
+    mixins: [commonMixin],
+  }
+</script>
+
+<style lang="scss" scoped>
+  .header{
+    height: 80px;
+    width: 1200px;
+    margin: 0 auto;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    flex-wrap: nowrap;
+    .nav{
+      float: left;
+      padding-top: 30px;
+      ul{
+        width: 760px;
+        display: flex;
+        justify-content: space-between;
+      }
+      li{
+        font-size: 16px;
+        line-height: 21px;
+        padding-bottom: 24px;
+        color: #333;
+        cursor: pointer;
+        border-bottom: 3px solid #fff;
+        &.on,&:hover{
+          color: #C5AA7B;
+          border-color: #C5AA7B;
+        }
+      }
+    }
+    .search{
+      width: 394px;
+      height: 39px;
+      border: 2px solid #F3F4F5;
+      float: right;
+      // margin-top: 21px;
+      display: flex;
+      .searchSelect{
+        width: 82px;
+        height: 30px;
+        margin-top: 2px;
+        border-right: 1px solid #CCCCCC;
+        text-align: center;
+        line-height: 30px;
+        .el-dropdown{
+          color: #C5AA7B;
+        }
+      }
+      .searchRight{
+        flex: 1;
+        input{
+          padding-left: 15px;
+          font-size: 14px;
+          color: #333;
+          line-height: 35px;
+        }
+      }
+      .btn{
+        font-size: 20px;
+        line-height: 35px;
+        padding-right: 15px;
+      }
+    }
+  }
+</style>

+ 112 - 0
canvas-container/components/canvasShow/basics/imageText.vue

@@ -0,0 +1,112 @@
+<template>
+  <div class="imageText warp" :class="['terminal'+terminal,'pos-' + componentContent.positionValue]">
+    <div class="img img-left">
+      <a class="a-link" @click="jumpLink(componentContent.linkObj)"><img :src="componentContent.imageUrl" alt=""></a>
+    </div>
+    <div class="text">
+      <h3 class="h3">{{componentContent.title}}</h3>
+      <div v-html="componentContent.content"></div>
+    </div>
+    <div class="img img-right">
+      <a class="item a-link" @click="jumpLink(componentContent.linkObj)"><img :src="componentContent.imageUrl" alt=""></a>
+    </div>
+  </div>
+</template>
+
+<script>
+  import {funMixin} from '../config/mixin'
+  export default {
+    name: 'imageTextComponent',
+    mixins: [funMixin],
+    data () {
+      return {
+      }
+    },
+    props: {
+      terminal: {
+        type: Number,
+        default: 4
+      },
+      componentContent: {
+        type: Object
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+  .imageText{
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 20px 0;
+    .img{
+      width: 50%;
+      padding-bottom: 30%;
+      background-color: #cacaca;
+      position: relative;
+      img{
+        max-width: 100%;
+        height: 100%;
+        max-height: 100%;
+        position: absolute;
+        margin: auto;
+        top: 0;
+        right: 0;
+        bottom: 0;
+        left: 0;
+      }
+    }
+    .text{
+      width: 40%;
+      .h3{
+        font-size: 30px;
+        margin-bottom: 24px;
+      }
+      .p{
+        font-size: 16px;
+      }
+    }
+    &.pos-top{
+      display: block;
+      text-align: center;
+      .img{
+        width: 100%;
+      }
+      .text{
+        width: 100%;
+        margin-top: 30px;
+      }
+      .img-right{
+        display: none;
+      }
+    }
+    &.pos-bottom{
+      display: block;
+      text-align: center;
+      .img{
+        width: 100%;
+      }
+      .text{
+        width: 100%;
+        margin-bottom: 30px;
+      }
+      .img-left{
+        display: none;
+      }
+    }
+    &.pos-left{
+      .img-right{
+        display: none;
+      }
+    }
+    &.pos-right{
+      .text{
+        padding-left: 20px;
+      }
+      .img-left{
+        display: none;
+      }
+    }
+  }
+</style>

+ 134 - 0
canvas-container/components/canvasShow/basics/imageTextList.vue

@@ -0,0 +1,134 @@
+<template>
+  <div class="hom-pro-list warp" :class="'terminal'+terminal">
+    <div class="title">
+      <h2 class="h2" :style="{textAlign:componentContent.textAlign}">{{componentContent.title}}</h2>
+    </div>
+    <ul class="clearfix" :class="{imgTextNum4: componentContent.imgTextData.length === 4, imgTextNum5: componentContent.imgTextData.length === 5, imgTextStyle: componentContent.imgTextData.length >= 6 || componentContent.imgTextData.length === 3}">
+      <li v-for="(item,index) in componentContent.imgTextData" :key="index">
+        <a class="item a-link" @click="jumpLink(componentContent.linkObj)">
+          <div class="itemImgBox" v-show="item.isShow">
+            <div class="imgBox">
+              <img ref="getHeight" :src="item.imgData" v-show="item.imgData" :alt="item.title">
+            </div>
+          </div>
+          <div class="text">
+            <h4 class="h4">{{item.title}}</h4>
+            <p class="p">{{item.describe}}</p>
+          </div>
+        </a>
+      </li>
+    </ul>
+  </div>
+</template>
+
+<script>
+  import {funMixin} from '../config/mixin'
+  export default {
+    name: 'imageTextList',
+    mixins: [funMixin],
+    props: {
+      terminal: {
+        type: Number,
+        default: 4
+      },
+      componentContent: {
+        type: Object
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+  .hom-pro-list{
+    min-height: 450px;
+    padding: 20px 0;
+    .title{
+      margin-bottom: 23px;
+      position: relative;
+      .h2{
+        font-size: 22px;
+        color: #333;
+        line-height: 1em;
+        font-weight: bold;
+      }
+    }
+    ul{
+      margin: -15px 0 0 -15px;
+      display: flex;
+      flex-wrap: wrap;
+      li{
+        flex: 0 0 50%;
+        padding: 15px 0 0 15px;
+        box-sizing: border-box;
+        .item{
+          .itemImgBox {
+            height: auto;
+            display: flex;
+            flex-direction: column;
+            justify-content: center;
+            .imgBox {
+              padding-bottom: 80%;
+              background-color: #cacaca;
+              position: relative;
+              img {
+                max-width: 100%;
+                height: 100%;
+                max-height: 100%;
+                position: absolute;
+                margin: auto;
+                top: 0;
+                right: 0;
+                bottom: 0;
+                left: 0;
+              }
+            }
+          }
+          .text{
+            padding:16px 20px;
+            text-align: center;
+            .h4{
+              line-height: 25px;
+              overflow: hidden;
+              color: #333333;
+            }
+            .p{
+              color: #666666;
+              padding: 5px 0 10px;
+            }
+          }
+        }
+      }
+    }
+    .imgTextNum4 {
+      li {
+        flex: 0 0 50%;
+      }
+    }
+    .imgTextNum5 {
+      li {
+        flex: 0 0 33.33%;
+      }
+      li:nth-child(1) {
+        flex: 0 0 50%;
+      }
+      li:nth-child(2) {
+        flex: 0 0 50%;
+      }
+    }
+    .imgTextStyle {
+      li {
+        flex: 0 0 33.33%;
+      }
+    }
+  }
+  @media screen and (max-width: 768px) {
+    .hom-pro-list ul li{
+      flex: 0 0 50%;
+    }
+  }
+  .terminal1,.terminal2,.terminal3{
+    &.hom-pro-list ul li{
+      flex: 0 0 50%;
+    }
+  }
+</style>

+ 96 - 0
canvas-container/components/canvasShow/basics/imageTextNav.vue

@@ -0,0 +1,96 @@
+<template>
+  <ul class="ul image-text-nav" :class="'terminal' + terminal">
+    <li class="li" v-for="(item,index) in componentContent.imgTextData" :key="index" :style="{'flex':'0 0 '+ getItemValue() + '%'}">
+      <!--<router-link class="item" :to="jumpLink(item.linkObj)">-->
+        <div class="img-box">
+          <div class="img-box-inner">
+            <el-image
+              :src="item.img"
+              fit="cover"></el-image>
+          </div>
+        </div>
+        <h4 class="h4">{{item.title}}</h4>
+      <!--</router-link>-->
+    </li>
+  </ul>
+</template>
+
+<script>
+  import {funMixin} from '../config/mixin'
+  export default {
+    name: 'imageTextNav',
+    mixins: [funMixin],
+    props: {
+      terminal: {
+        type: Number,
+        default: 4
+      },
+      componentContent: {
+        type: Object
+      }
+    },
+    methods: {
+      // 计算生成格子百分比
+      getItemValue (val) {
+        const len = parseInt(this.componentContent.imgTextData.length)
+        if (len === 0) {
+          return 0
+        } else {
+          return (1 / len * 10000 / 100.00)
+        }
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+  .image-text-nav{
+    min-height: 100px;
+    width: 690px;
+    margin: 0 auto;
+    display: flex;
+    padding: 20px 0;
+    .li{
+      text-align: center;
+      .img-box{
+        .el-image{
+          width: 100px;
+          height: 100px;
+        }
+      }
+      .h4{
+        font-size: 26px;
+        color: #333;
+        line-height: 33px;
+      }
+    }
+    &.terminal4{
+      width: 1000px;
+      .li{
+        .img-box{
+          display: inline-block;
+          width: 100px;
+          height: 100px;
+          border: 2px solid #F3F4F5;
+          border-radius: 10px;
+          &-inner{
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            height: 100%;
+          }
+          .el-image{
+            width: 60px;
+            height: 60px;
+          }
+        }
+        .h4{
+          font-size: 18px;
+          color: #ccc;
+          line-height: 1em;
+          padding-top: 20px;
+        }
+      }
+    }
+  }
+</style>

+ 63 - 0
canvas-container/components/canvasShow/basics/live/app/index.vue

@@ -0,0 +1,63 @@
+<template>
+  <div class="live-list-page">
+    <div class="title">
+      <img src="../../../static/images/live/img-title.png" alt="商品推荐"/>
+    </div>
+    <div class="live-list">
+      <LiveBox class="live-item"
+               v-for="item in roomList"
+               :key="item.roomid"
+               :liveData.sync="item"
+               @click="toLiveRoom(item)"
+      />
+    </div>
+    <button v-show="componentContent.showMore" class="btn-more" @click="jumpGroupWorks(productData)">查看全部 <span class="icon iconfont icon-arrow-right"></span></button>
+  </div>
+</template>
+
+<script>
+import {commonMixin} from '../mixin'
+import LiveBox from './item'
+export default {
+  mixins: [commonMixin],
+  components: {
+    LiveBox
+  },
+  data () {
+    return {
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.live-list-page{
+  .title{
+    text-align: center;
+    margin-bottom: 20px;
+  }
+  .live-list{
+    padding-left: 20px;
+    width: 100%;
+    display: flex;
+    flex-wrap: wrap;
+    .live-item{
+      margin:0 14px 14px 0;
+      width: 348px;
+      height: 464px;
+      border-radius: 8px;
+      overflow: hidden;
+    }
+  }
+  .btn-more {
+    width: 170px;
+    height: 54px;
+    border: 2px solid #C5AA7B;
+    color: #C5AA7B;
+    font-size: 24px;
+    background-color: transparent;
+    margin: 20px auto 0;
+    display: block;
+  }
+}
+</style>

+ 280 - 0
canvas-container/components/canvasShow/basics/live/app/item.vue

@@ -0,0 +1,280 @@
+<template>
+  <div class="live-box">
+    <div class="live-ongoing" v-if="liveData.live_status === 101 || isOn">
+      <img class="cover-img" :src="liveData.cover_img" />
+      <div class="status">
+        <div class="status-state">
+          <img class="img" src="../../../static/images/live/icon-live-num.png" />直播中</div>
+        <div class="status-num">1000人</div>
+      </div>
+      <div class="user">
+        <div class="user-pic">
+          <img class="img" src="../../../static/images/live/huabei.png" />
+        </div>
+        <view class="user-name">{{ liveData.anchor_name }}</view>
+      </div>
+      <div class="products">
+        <div class="uni-padding-wrap">
+          <div class="page-section swiper">
+            <div class="page-section-spacing">
+              <el-carousel height="34px" direction="vertical" indicator-position="none">
+                <el-carousel-item v-for="item in liveData.goods" :key="item.goods_id">
+                  <h3 class="medium">{{ item.name }}</h3>
+                </el-carousel-item>
+              </el-carousel>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="live-other" v-else>
+      <img class="cover-img" :src="liveData.cover_img" />
+      <div class="user">
+        <div class="user-pic"><img class="img" src="../../../static/images/live/huabei.png" /></div>
+        <div class="user-name">{{ liveData.anchor_name }}</div>
+      </div>
+      <div class="count-down">
+        <div class="text">开播倒计时</div>
+        <div class="time">
+          <div class="time-item dots">{{times[0]}}</div>
+          <div class="time-item dots">{{times[1]}}</div>
+          <div class="time-item">{{times[2]}}</div>
+        </div>
+      </div>
+      <div class="btn-subscribe">立即预约</div>
+      <!--      <view class="btn-subscribe subscribed">已预约</view>-->
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  props: {
+    liveData: {
+      type: Object,
+      default: () => ({
+        name: '',
+        cover_img: ''
+      })
+    }
+  },
+  data () {
+    return {
+      background: ['color1', 'color2', 'color3'],
+      indicatorDots: false,
+      autoplay: true,
+      interval: 2000, // 自动播放间隔时长
+      duration: 500, // 幻灯片切换时长(ms)
+      times: [],
+      isOn: false
+    }
+  },
+  created() {
+    this.countTime()
+  },
+  methods: {
+    changeIndicatorDots(e) {
+      this.indicatorDots = !this.indicatorDots
+    },
+    changeAutoplay(e) {
+      this.autoplay = !this.autoplay
+    },
+    intervalChange(e) {
+      this.interval = e.target.value
+    },
+    durationChange(e) {
+      this.duration = e.target.value
+    },
+    countTime(){
+      var nowtime = new Date().getTime()  //获取当前时间
+      var starttime = this.liveData.start_time * 1000
+      if(this.liveData.live_status === 102){
+        if(starttime > nowtime){
+          var lefttime = starttime - nowtime  //距离结束时间的毫秒数
+          var leftd = Math.floor(lefttime/(1000*60*60)),  //计算小时数
+            leftm = Math.floor(lefttime/(1000*60)%60),  //计算分钟数
+            lefts = Math.floor(lefttime/1000%60);  //计算秒数
+          this.times = [leftd < 10?'0'+ leftd:leftd,leftm < 10?'0'+ leftm:leftm,lefts < 10?'0'+ lefts:lefts]
+          setTimeout(() => {
+            this.countTime()
+          },1000)
+        } else {
+          this.isOn = true
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.live-box{
+  position: relative;
+  color: #fff;
+  .cover-img{
+    width: 100%;
+    height: 100%;
+    position: absolute;
+    z-index: 0;
+  }
+  .user{
+    display: flex;
+    line-height: 60px;
+    height: 64px;
+    &-pic{
+      .img{
+        width: 60px;
+        height: 60px;
+        border: 2px solid rgba(255, 255, 255, 0.5019607843137255);
+        border-radius: 50%;
+        overflow: hidden;
+      }
+    }
+    &-name{
+      font-size: 28px;
+      margin-left: 16px;
+    }
+  }
+  .live-ongoing{
+    width: 100%;
+    height: 100%;
+    position: relative;
+    .status{
+      position: absolute;
+      top: 22px;
+      left: 22px;
+      //width: 212upx;
+      height: 48px;
+      background: rgba(0,0,0,0.3);
+      border: 2px solid rgba(255,255,255,0.3);
+      border-radius: 24px;
+      font-size: 20px;
+      line-height: 44px;
+      display: flex;
+      padding-right: 8px;
+      &-state{
+        width: 118px;
+        height: 44px;
+        background: linear-gradient(90deg, #C83732 0%, #E25C44 100%);
+        opacity: 1;
+        border-radius: 26px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        .img{
+          width: 20px;
+          height: 20px;
+          margin-right: 6px;
+        }
+      }
+      &-num{
+        min-width: 80px;
+        padding: 0 8px;
+      }
+    }
+    .user{
+      position: absolute;
+      bottom: 62px;
+      left: 20px;
+    }
+    .products{
+      position: absolute;
+      left: 0px;
+      bottom: 20px;
+      width: 100%;
+      padding:0 20px;
+      .swiper{
+        height: 34px;
+        line-height: 34px;
+        font-size: 24px;
+        overflow: hidden;
+        text-overflow:ellipsis;
+        white-space: nowrap;
+      }
+    }
+  }
+  .live-other{
+    position: relative;
+    height: 100%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    .cover-img{
+      filter:blur(20px);
+      -webkit-filter:blur(20px);
+      -moz-filter:blur(20px);
+      -ms-filter:blur(20px);
+      -o-filter:blur(20px);
+    }
+    .user{
+      position: absolute;
+      top: 20px;
+      left: 20px;
+    }
+    .count-down{
+      position: relative;
+      .text{
+        font-size: 26px;
+        line-height: 36px;
+        margin-bottom: 16px;
+        opacity: 0.5;
+        text-align: center;
+      }
+      .time{
+        display: flex;
+        &-item{
+          min-width: 52px;
+          padding: 0 5px;
+          height: 52px;
+          line-height: 52px;
+          background: #FFFFFF;
+          opacity: 1;
+          border-radius: 4px;
+          font-size: 26px;
+          color: #C83732;
+          text-align: center;
+          &.dots{
+            margin-right: 22px;
+            position: relative;
+            &:before,&:after{
+              content:'';
+              width: 6px;
+              height: 6px;
+              background: #FFFFFF;
+              position: absolute;
+              right: -14px;
+            }
+            &:before{
+              top: 14px;
+            }
+            &:after{
+              bottom: 14px;
+            }
+          }
+        }
+      }
+    }
+    .btn-subscribe{
+      width: 200px;
+      height: 64px;
+      line-height: 64px;
+      background: linear-gradient(90deg, #C83732 0%, #E25C44 100%);
+      box-shadow: 0rpx 6px 12px rgba(233, 0, 0, 0.3);
+      opacity: 1;
+      border-radius: 8px;
+      color: #fff;
+      font-size: 24px;
+      text-align: center;
+      position: absolute;
+      bottom: 60px;
+      left: 50%;
+      margin-left: -100px;
+      &.subscribed{
+        background: #FFFFFF;
+        color: #999999;
+        box-shadow: none;
+      }
+    }
+  }
+}
+</style>

+ 113 - 0
canvas-container/components/canvasShow/basics/live/mixin.js

@@ -0,0 +1,113 @@
+export const commonMixin = {
+  data() {
+    return {
+      appid: 'wx123456789abcdefg',
+      roomId: [], // 填写具体的房间号
+      roomList: []
+    }
+  },
+  props: {
+    terminal: {
+      type: Number,
+      default: 4
+    },
+    typeId: {
+      type: Number,
+      default: 1
+    },
+    shopId: {
+      type: Number,
+      default: 0
+    },
+    componentContent: {
+      type: Object
+    }
+  },
+  created() {
+    this.getLiveRooms()
+  },
+  methods: {
+    // 获取直播间列表
+    getLiveRooms () {
+      // Net.request('https://api.weixin.qq.com/wxa/business/getliveinfo?access_token=').then(res => {})
+      const response = {
+        "errcode": 0,    // 错误码,0代表成功,1代表未创建直播间
+        "errmsg": "ok",   // 错误信息
+        "total":1,
+        "room_info":[{
+          "name":"直播房间名",
+          "roomid": 1,
+          "cover_img":"https://www.baidu.com/img/flexible/logo/pc/result@2.png",
+          "share_img":"https://www.tencent.com/img/banners/brief-1-1.jpg",
+          "live_status": 101,
+          // "live_status": 101, // 直播间状态。101:直播中,102:未开始,103已结束,104禁播,105:暂停,106:异常,107:已过期
+          "start_time": 1568128900, // 直播间开始时间,列表按照start_time降序排列
+          "end_time": 1568131200, // 直播计划结束时间
+          "anchor_name":"里斯",
+          "goods":[{
+            "cover_img":"https://static.www.tencent.com/img/banner/wxpay-banner.jpg",
+            "url":"pages/index/index.html",
+            "name":"茶杯",
+            "price": 1889,          // 价格(分)
+            "price2": 0,
+            "price_type": 1,        // 价格类型,1:一口价(只需要传入price,price2不传) 2:价格区间(price字段为左边界,price2字段为右边界,price和price2必传) 3:显示折扣价(price字段为原价,price2字段为现价, price和price2必传)
+            "goods_id": 256,        // 商品id
+            "third_party_appid": "wx123456789aaaaaaa" //第三方商品appid ,当前小程序商品则为空
+          }],
+          "live_type": 0,				// 直播类型,1 推流 0 手机直播
+          "close_like": 0,			// 是否关闭点赞 【0:开启,1:关闭】(若关闭,观众端将隐藏点赞按钮,直播开始后不允许开启)
+          "close_goods": 0,			// 是否关闭货架 【0:开启,1:关闭】(若关闭,观众端将隐藏商品货架,直播开始后不允许开启)
+          "close_comment": 0,			// 是否关闭评论 【0:开启,1:关闭】(若关闭,观众端将隐藏评论入口,直播开始后不允许开启)
+          "close_kf": 1,				// 是否关闭客服 【0:开启,1:关闭】 默认关闭客服(直播开始后允许开启)
+          "close_replay": 1,			// 是否关闭回放 【0:开启,1:关闭】默认关闭回放(直播开始后允许开启)
+          "is_feeds_public": 0,		// 是否开启官方收录,1 开启,0 关闭
+          "creater_openid": "aaaaAbbbbB0ccccC0ddddDeeeeE0", // 创建者openid
+          "feeds_img": "XXX"			// 官方收录封面
+        },{
+          "name":"直播房间名",
+          "roomid": 2,
+          "cover_img":"https://www.baidu.com/img/flexible/logo/pc/result@2.png",
+          "share_img":"https://www.tencent.com/img/banners/brief-1-1.jpg",
+          "live_status": 102,
+          // "live_status": 101, // 直播间状态。101:直播中,102:未开始,103已结束,104禁播,105:暂停,106:异常,107:已过期
+          "start_time": 1639223017, // 直播间开始时间,列表按照start_time降序排列
+          "end_time": 1639200008, // 直播计划结束时间
+          "anchor_name":"里斯",
+          "goods":[{
+            "cover_img":"https://static.www.tencent.com/img/banner/wxpay-banner.jpg",
+            "url":"pages/index/index.html",
+            "name":"茶杯",
+            "price": 1889,          // 价格(分)
+            "price2": 0,
+            "price_type": 1,        // 价格类型,1:一口价(只需要传入price,price2不传) 2:价格区间(price字段为左边界,price2字段为右边界,price和price2必传) 3:显示折扣价(price字段为原价,price2字段为现价, price和price2必传)
+            "goods_id": 256,        // 商品id
+            "third_party_appid": "wx123456789aaaaaaa" //第三方商品appid ,当前小程序商品则为空
+          }],
+          "live_type": 0,				// 直播类型,1 推流 0 手机直播
+          "close_like": 0,			// 是否关闭点赞 【0:开启,1:关闭】(若关闭,观众端将隐藏点赞按钮,直播开始后不允许开启)
+          "close_goods": 0,			// 是否关闭货架 【0:开启,1:关闭】(若关闭,观众端将隐藏商品货架,直播开始后不允许开启)
+          "close_comment": 0,			// 是否关闭评论 【0:开启,1:关闭】(若关闭,观众端将隐藏评论入口,直播开始后不允许开启)
+          "close_kf": 1,				// 是否关闭客服 【0:开启,1:关闭】 默认关闭客服(直播开始后允许开启)
+          "close_replay": 1,			// 是否关闭回放 【0:开启,1:关闭】默认关闭回放(直播开始后允许开启)
+          "is_feeds_public": 0,		// 是否开启官方收录,1 开启,0 关闭
+          "creater_openid": "aaaaAbbbbB0ccccC0ddddDeeeeE0", // 创建者openid
+          "feeds_img": "XXX"			// 官方收录封面
+        }]
+      }
+      this.roomList = response.room_info
+    },
+    toLiveRoom (item) {
+      this.roomId.push(item.roomid)
+      if (!this.appid || !this.roomId.length) { return }
+      // 路由参数
+      let customParams = encodeURIComponent(JSON.stringify({ path: 'livePage/index', pid: 1 }))
+      // let customParams
+      // 开发者在直播间页面路径上携带自定义参数(如示例中的path和pid参数),后续可以在分享卡片链接和跳转至商详页时获取,详见【获取自定义参数】、【直播间到商详页面携带参数】章节(上限600个字符,超过部分会被截断)
+      // #ifdef MP-WEIXIN
+      wx.navigateTo({
+        url: `plugin-private://${this.appid}/pages/live-player-plugin?room_id=${this.roomId}&custom_params=${customParams}`
+      })
+      // #endif
+    }
+  }
+}

+ 163 - 0
canvas-container/components/canvasShow/basics/newProduct/app/index.vue

@@ -0,0 +1,163 @@
+<template>
+  <div class="hom-pro-list">
+    <div class="product-swiper">
+      <swiper class="product-swiper-box" :options="swiperOption">
+        <swiper-slide class="product-swiper-item" v-for="(item,index) in productData.slice(0, 3)" :key="index" @click="jumpProductDetail(item)">
+          <div class="product-swiper-img">
+            <img class="img" :src="item.image">
+          </div>
+          <div class="product-swiper-info">
+            <label class="product-name">{{item.productName}}</label>
+            <div class="price-warp">
+              <div class="price">
+                ¥ {{item.price}}
+              </div>
+              <div class="original-price">
+                ¥ {{item.originalPrice}}
+              </div>
+            </div>
+          </div>
+        </swiper-slide>
+      </swiper>
+      <div class="pagination new-pagination"></div>
+    </div>
+    <button v-show="componentContent.showMore" class="btn-more" @click="jumpLink(componentContent.linkObj)">查看全部 <span class="icon iconfont icon-arrow-right"></span></button>
+  </div>
+</template>
+
+<script>
+import {commonMixin} from '../mixin'
+export default {
+  mixins: [commonMixin],
+  data () {
+    return {
+      index: 1,
+      swiperOption: {
+        slidesPerView: 3,
+        spaceBetween: 12,
+        autoplay: false, // 可选选项,自动滑动
+        loop: true,
+        pagination: {
+          el: '.new-pagination'
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.hom-pro-list{
+  ::v-deep .swiper-wrapper{
+    position: static;
+  }
+  /**横向滑动**/
+  .product-swiper{
+    width: 100%;
+    height: 454px;
+    padding: 90px 34px 0;
+    background: url("../../../static/images/newProduct/bg-product-card.png") no-repeat center;
+    position: relative;
+    &+.btn-more{
+      margin-top: 20px;
+    }
+    .title{
+      padding: 22px 0px 0 0;
+      label{
+        background-image: none;
+        color: #A56C4C;
+        font-style: italic;
+        padding: 0;
+      }
+    }
+    &-box {
+      padding-bottom: 20px;
+    }
+    &-item {
+      width: 220px;
+      position: relative;
+      background-color: #FFFFFF;
+    }
+    &-img {
+      width: 220px;
+      height: 220px;
+      position: relative;
+      &:after{
+        content: '';
+        display: block;
+        width: 54px;
+        height: 54px;
+        background: url("../../../static/images/newProduct/flag-new.png") no-repeat;
+        position: absolute;
+        top: 0;
+        left: 0;
+      }
+      .img {
+        width: 100%;
+        height: 100%;
+        object-fit: contain;
+      }
+    }
+    &-info {
+      background-color: #FFFFFF;
+      padding: 10px;
+      text-align: center;
+      .product-name{
+        font-size: 20px;
+        color: #333;
+        display: block;
+        overflow: hidden;
+        text-overflow:ellipsis;
+        white-space: nowrap;
+        margin-bottom: 6px;
+        line-height: 28px;
+      }
+      .price-warp{
+        display: flex;
+        justify-content: center;
+        align-items: baseline;
+        line-height: 28px;
+        .price{
+          color: #C83732;
+          font-size: 20px;
+          margin-right: 10px;
+        }
+        .original-price{
+          font-size: 16px;
+          color: #ccc;
+          text-decoration: line-through;
+        }
+      }
+    }
+  }
+}
+
+.pagination{
+  display: flex;
+  justify-content: center;
+  width: 100%;
+  bottom: 0;
+  ::v-deep .swiper-pagination-bullet{
+    width: 24px;
+    height: 4px;
+    background: #FFFFFF;
+    opacity: 0.5;
+    border-radius: 2px;
+    margin: 0 10px;
+  }
+  ::v-deep .swiper-pagination-bullet-active{
+    opacity: 1;
+  }
+}
+.btn-more {
+  width: 170px;
+  height: 54px;
+  border: 2px solid #C5AA7B;
+  color: #C5AA7B;
+  font-size: 24px;
+  background-color: transparent;
+  margin: 20px auto 0;
+  display: block;
+}
+
+</style>

+ 107 - 0
canvas-container/components/canvasShow/basics/newProduct/mixin.js

@@ -0,0 +1,107 @@
+import { directive, Swiper, SwiperSlide } from 'vue-awesome-swiper'
+import {funMixin} from '../../config/mixin'
+import 'swiper/css/swiper.css'
+import api from '../../config/api'
+import { mapGetters } from 'vuex'
+
+export const commonMixin = {
+  name: 'productList',
+  mixins: [funMixin],
+  props: {
+    terminal: {
+      type: Number,
+      default: 4
+    },
+    typeId: {
+      type: Number,
+      default: 1
+    },
+    shopId: {
+      type: Number,
+      default: 0
+    },
+    componentContent: {
+      type: Object
+    }
+  },
+  components: {
+    Swiper,
+    SwiperSlide
+  },
+  directives: {
+    swiper: directive
+  },
+  data () {
+    return {
+      productData: []
+    }
+  },
+  mounted() {
+    this.getData(true)
+  },
+  watch: {
+    'newProductNum': {
+      handler(newVal, oldVal) {
+        this.getData()
+      },
+      deep: true
+    }
+  },
+  computed: {
+    ...mapGetters([
+      'newProductNum'
+    ]),
+    swiper() {
+      if(this.$refs.mySwiper){
+        return this.$refs.mySwiper.$swiper
+      }
+    }
+  },
+  methods: {
+    getData(isFirst) {
+      const _ = this
+      if (_.componentContent.productData.sourceType === '1') {
+        if(_.componentContent.productData.productIdList && _.componentContent.productData.productIdList.length>0){
+          this.beforeGetData()
+          _.sendReq({
+            url: `${api.getProducts}?page=1&pageSize=99&ids=${_.componentContent.productData.productIdList}`,
+            method: 'GET'
+          }, (proRes) => {
+            _.afterGetData()
+            _.productData = proRes.data.list
+            if(isFirst){
+              _.componentContent.productData.imgTextData = _.productData
+            }
+            _.$forceUpdate() // 刷新轮播图
+          },(err)=>{
+            _.afterGetData()
+          })
+        } else {
+          _.productData = []
+        }
+      } else if(_.componentContent.productData.sourceType === '2'){
+        if(_.componentContent.productData.categoryId) {
+          this.beforeGetData()
+          _.sendReq({
+            url: `${api.getProducts}?page=1&pageSize=99&classifyId=${_.componentContent.productData.categoryId}`,
+            method: 'GET'
+          }, (proRes) => {
+            _.afterGetData()
+            _.productData = proRes.data.list
+            if(isFirst){
+              _.componentContent.productData.imgTextData = _.productData
+            }
+            _.$forceUpdate() // 刷新轮播图
+            // _.swiper.update()
+          },(err)=>{
+            _.afterGetData()
+          })
+        } else {
+          _.productData = {
+            products:[]
+          }
+        }
+      }
+    },
+  }
+}

+ 112 - 0
canvas-container/components/canvasShow/basics/notice.vue

@@ -0,0 +1,112 @@
+<template>
+  <div class="notice-list" :class="'terminal'+terminal" :style="{backgroundColor:componentContent.bgColor}">
+    <swiper :options="swiperOption">
+      <swiper-slide v-for="(item,index) in noticesList" :key="index">
+        <div class="a-link" @click="jumpNoticeDetail(item)" :style="{color:componentContent.titColor}"><span>{{item.noticeTitle}}</span></div>
+      </swiper-slide>
+    </swiper>
+  </div>
+</template>
+
+<script>
+import api from '../config/api'
+import { funMixin } from '../config/mixin'
+import { directive, Swiper, SwiperSlide } from 'vue-awesome-swiper'
+import 'swiper/css/swiper.css'
+export default {
+  name: "noticeComponent",
+  mixins: [funMixin],
+  data () {
+    return {
+      noticesList: [],
+      swiperOption: {
+        autoplay: false, // 可选选项,自动滑动
+        loop: true,
+        pagination: {
+          el: '.swiper-pagination'
+        }
+      }
+    }
+  },
+  props: {
+    terminal: {
+      type: Number,
+      default: 4
+    },
+    componentContent: {
+      type: Object
+    }
+  },
+  components: {
+    Swiper,
+    SwiperSlide
+  },
+  directives: {
+    swiper: directive
+  },
+  mounted() {
+      this.getData()
+  },
+  methods: {
+    getData() {
+      this.beforeGetData()
+      const _ = this
+      let _url = `${api.getNotices}`
+      const params = {
+        method: 'GET',
+        url: _url,
+      }
+      this.sendReq(params, (res) => {
+        this.afterGetData()
+        _.noticesList = res.data
+      },(err)=>{
+        this.afterGetData()
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.notice-list{
+  height: 60px;
+  line-height: 60px;
+  padding: 0 20px;
+  .a-link{
+    display: block;
+    cursor: pointer;
+    overflow: hidden;
+    text-overflow:ellipsis;
+    white-space: nowrap;
+    text-align: center;
+    span{
+      display: inline-block;
+      padding-left: 50px;
+      font-size: 24px;
+      background: url("../static/images/notice/ico_notice2.png") no-repeat left center;
+    }
+  }
+  &.terminal4{
+    height: 50px;
+    line-height: 50px;
+    padding: 0;
+    .swiper-container{
+      height: 100%;
+      width: 1200px;
+      max-width: 100%;
+      margin: 0 auto;
+    }
+    .a-link{
+      display: block;
+      cursor: pointer;
+      text-align: left;
+      span{
+        display: block;
+        padding-left: 25px;
+        font-size: 14px;
+        background: url("../static/images/notice/ico_notice.png") no-repeat left center;
+      }
+    }
+  }
+}
+</style>

+ 178 - 0
canvas-container/components/canvasShow/basics/price/app/index.vue

@@ -0,0 +1,178 @@
+<template>
+  <div class="group-list">
+    <div class="group-warp">
+      <div class="title">
+        <label>
+          <img src="../../../static/images/price/img-title.png" alt="组合优惠"/>
+        </label>
+        <div class="price-text" v-if="productData.rules">
+          {{productData.rules[0].price}}元任选{{productData.rules[0].number}}件
+        </div>
+        <a v-show="componentContent.showMore" class="btn-all a-link" @click="jumpDiscount(productData)">更多<i class="iconfont icon-arrow-right"></i></a>
+      </div>
+      <swiper class="pro-box" :options="swiperOption">
+        <swiper-slide class="pro-item" v-for="(item,index) in productData.composeProducts" :key="index" @click="jumpProductDetail(item)">
+          <div class="pro-item-img">
+            <img v-show="item.image" class="img" :src="item.image">
+          </div>
+          <div class="pro-item-info">
+            <h3 class="name">
+              {{item.productName}}
+            </h3>
+            <div class="stock">
+              还剩{{item.stockNumber}}件
+            </div>
+            <div class="price-warp">
+              <div class="price">
+                ¥ {{item.price}}
+              </div>
+              <div class="original-price">
+                ¥ {{item.originalPrice}}
+              </div>
+            </div>
+          </div>
+        </swiper-slide>
+      </swiper>
+      <div class="pagination price-pagination"></div>
+    </div>
+  </div>
+
+</template>
+
+<script>
+import {commonMixin} from '../mixin'
+export default {
+  mixins: [commonMixin],
+  data () {
+    return {
+      swiperOption: {
+        slidesPerView: 2, // 显示数量
+        spaceBetween: 20, // 间隔
+        autoplay: false, // 可选选项,自动滑动
+        loop: true,
+        pagination: {
+          el: '.price-pagination'
+        },
+        navigation: {
+          nextEl: '.swiper-button-next',
+          prevEl: '.swiper-button-prev'
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.group-list{
+  padding: 30px 20px 60px;
+  min-height: 80px;
+  .group-warp{
+    width: 710px;
+    height: 544px;
+    padding: 0 10px;
+    background: #333333;
+    box-shadow: 0px 20px 30px rgba(0, 0, 0, 0.3);
+    opacity: 1;
+    border-radius: 20px;
+  }
+  .title{
+    display: flex;
+    align-items:center;
+    position: relative;
+    padding: 32px 0 20px 20px;
+    .price-text{
+      width: 300px;
+      height: 50px;
+      background: linear-gradient(90deg, #C83732 0%, #E25C44 100%);
+      box-shadow: 0px 6px 12px rgba(233, 0, 0, 0.3);
+      border-radius: 26px;
+      font-size: 24px;
+      color: #fff;
+      text-align: center;
+      line-height: 50px;
+      margin-left: 20px;
+    }
+    .btn-all{
+      position: absolute;
+      right: 8px;
+      top: 40px;
+      line-height: 33px;
+      padding-right: 25px;
+      font-size: 24px;
+      color: #FFEBC4;
+      .iconfont{
+        content: '';
+        font-size: 26px;
+        position: absolute;
+        right: 0;
+        top: 0;
+      }
+    }
+  }
+  .pro-box{
+    padding-bottom: 20px;
+    .pro-item{
+      width: 220px;
+      height: 398px;
+      background: #FFFFFF;
+      .pro-item-img{
+        .img{
+          width: 100%;
+          height: 236px;
+        }
+      }
+      .pro-item-info{
+        padding: 0 20px;
+        .name{
+          font-size: 24px;
+          line-height: 40px;
+          color: #333333;
+          overflow: hidden;
+          text-overflow:ellipsis;
+          white-space: nowrap;
+        }
+        .stock{
+          padding: 0 8px;
+          height: 40px;
+          border: 2px solid #E4E5E6;
+          line-height: 40px;
+          margin: 10px 0;
+          display: inline-block;
+          font-size: 20px;
+          color: #C5AA7B;
+        }
+        .price{
+          font-size: 32px;
+          font-weight: bold;
+          line-height: 44px;
+          color: #C83732;
+          padding-right: 10px;
+          display: inline-block;
+        }
+        .original-price{
+          font-size: 20px;
+          line-height: 28px;
+          color: #CCCCCC;
+          display: inline-block;
+        }
+      }
+    }
+  }
+  .pagination{
+    display: flex;
+    justify-content: center;
+    ::v-deep .swiper-pagination-bullet{
+      width: 24px;
+      height: 4px;
+      background: #fff;
+      opacity: 0.5;
+      border-radius: 2px;
+      margin: 0 5px;
+    }
+    ::v-deep .swiper-pagination-bullet-active{
+      opacity: 1;
+    }
+  }
+}
+</style>

+ 85 - 0
canvas-container/components/canvasShow/basics/price/mixin.js

@@ -0,0 +1,85 @@
+import { directive, Swiper, SwiperSlide } from 'vue-awesome-swiper'
+import 'swiper/css/swiper.css'
+import api from '../../config/api'
+import {funMixin} from '../../config/mixin'
+import { mapGetters } from 'vuex'
+
+export const commonMixin = {
+  name: 'price',
+  mixins: [funMixin],
+  props: {
+    terminal: {
+      type: Number,
+      default: 4
+    },
+    typeId: {
+      type: Number,
+      default: 1
+    },
+    shopId: {
+      type: Number,
+      default: 0
+    },
+    componentContent: {
+      type: Object
+    }
+  },
+  components: {
+    Swiper,
+    SwiperSlide
+  },
+  directives: {
+    swiper: directive
+  },
+  data () {
+    return {
+      productData: {
+        composeProducts:[],
+        rules: [{
+          price: null,
+          number: null
+        }]
+      }
+    }
+  },
+  computed: {
+    ...mapGetters([
+      'priceNum'
+    ]),
+  },
+  watch: {
+    'priceNum': {
+      handler(newVal, oldVal) {
+        this.getData()
+      },
+      deep: true
+    }
+  },
+  created() {
+    this.getData()
+  },
+  methods: {
+      getData() {
+        const _ = this
+        if(_.componentContent.priceId){
+          this.beforeGetData()
+          const params = {
+            method: 'GET',
+            url: `${api.getPrices}?shopId=${_.shopId}&ids=${_.componentContent.priceId}`,
+          }
+          this.sendReq(params, (res) => {
+            _.afterGetData()
+            if( res.data.length > 0){
+              _.productData = res.data[0]
+            }
+          },(err)=>{
+            _.afterGetData()
+          })
+        } else {
+          _.productData = {
+            products:[]
+          }
+        }
+      },
+  }
+}

+ 254 - 0
canvas-container/components/canvasShow/basics/price/pc/index.vue

@@ -0,0 +1,254 @@
+<template>
+  <div class="product-list" :class="'terminal'+terminal">
+    <div class="picListWarp" v-if="componentContent.arrangeType == '横向滑动'">
+      <div class="picList" v-if="productData.composeProducts && productData.composeProducts.length>0">
+        <div class="swiper-button-prev"></div>
+        <div class="swiper-button-next"></div>
+        <swiper class="products-swiper" :options="swiperOption">
+          <swiper-slide class="products-swiper-slide item" v-for="(item,index) in productData.composeProducts" :key="index">
+            <div class="a-link" @click="jumpProductDetail(item)">
+              <div class="itemImgBox">
+                <div class="imgBox">
+                  <el-image
+                    :src="item.image"
+                    fit="contain"></el-image>
+                </div>
+              </div>
+              <div class="text">
+                <div class="discount-text">
+                  <span>任选{{productData.rules[0].number}}件{{productData.rules[0].price}}元</span>
+                </div>
+                <h4 class="h4">{{item.productName}}</h4>
+                <div class="priceBox">
+                  <span>¥{{item.price}}</span>
+                </div>
+                <button class="btn-cart" @click="addCart(item.id)">加入购物车</button>
+              </div>
+            </div>
+          </swiper-slide>
+        </swiper>
+      </div>
+    </div>
+    <div v-else class="picList" >
+      <ul class="clearfix" :class="'imgTextNum' +  componentContent.productNum">
+        <li class="item" v-for="(item,index) in productData.composeProducts.slice(0, componentContent.productRowNum * componentContent.productNum)" :key="index">
+          <div class="a-link" @click="jumpProductDetail(item)">
+            <div class="itemImgBox">
+              <div class="imgBox">
+                <el-image
+                  :src="item.image"
+                  fit="contain"></el-image>
+              </div>
+            </div>
+            <div class="text">
+              <div class="discount-text">
+                <span>任选{{productData.rules[0].number}}件{{productData.rules[0].price}}元</span>
+              </div>
+              <h4 class="h4">{{item.productName}}</h4>
+              <div class="priceBox">
+                <span>¥{{item.price}}</span>
+              </div>
+              <button class="btn-cart" @click="addCart(item.id)">加入购物车</button>
+            </div>
+          </div>
+        </li>
+      </ul>
+    </div>
+    <button v-show="componentContent.showMore" class="btn-more" @click="jumpPice(productData)">查看全部 <span class="icon iconfont icon-arrow-right"></span></button>
+  </div>
+</template>
+
+<script>
+  import {commonMixin} from '../mixin'
+  export default {
+    mixins: [commonMixin],
+    data () {
+      return {
+        swiperOption: {
+          slidesPerView: 4, // 显示数量
+          spaceBetween: 13, // 间隔
+          autoplay: false, // 可选选项,自动滑动
+          loop: true,
+          pagination: {
+            el: '.price-pagination'
+          },
+          navigation: {
+            nextEl: '.swiper-button-next',
+            prevEl: '.swiper-button-prev'
+          }
+        }
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+.product-list{
+  padding: 20px 0;
+  background-color: #fff;
+  min-height: 100px;
+  .picListWarp{
+    width: 1380px;
+    max-width: 100%;
+    margin: 0 auto;
+    position: relative;
+  }
+  .picList{
+    width: 1200px;
+    max-width: 100%;
+    margin: 0 auto;
+    .swiper-button-prev,.swiper-button-next{
+      width: 50px;
+      height: 50px;
+      position: absolute;
+      cursor:pointer;
+      top: 140px;
+      background-repeat: no-repeat;
+      &:after{
+        content: '';
+      }
+    }
+    .swiper-button-prev{
+      left: 0;
+      background: url('../../../static/images/btn-prev.png');
+    }
+    .swiper-button-next{
+      right: 0;
+      background: url('../../../static/images/btn-next.png');
+    }
+    .a-link{
+      cursor: pointer;
+      &:hover{
+        box-shadow: 3px 4px 20px 0px rgba(186, 186, 186, 0.5);
+      }
+      .itemImgBox {
+        height: auto;
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+        .imgBox {
+          padding-bottom: 100%;
+          background-color: #cacaca;
+          position: relative;
+          .el-image {
+            width: 100%;
+            height: 100%;
+            position: absolute;
+            top: 0;
+            left: 0;
+          }
+        }
+      }
+      .text{
+        padding:25px 10px 17px;
+        text-align: center;
+        position: relative;
+        //height: 180px;
+        .discount-text{
+          background: url("../../../static/images/price/bg-discount.png") no-repeat;
+          width: 100%;
+          height: 47px;
+          font-size: 14px;
+          color: #fff;
+          line-height: 60px;
+          text-align: center;
+          position: absolute;
+          top: -47px;
+          left: 0;
+        }
+        .h4{
+          font-size: 18px;
+          line-height: 24px;
+          overflow: hidden;
+          text-overflow:ellipsis;
+          white-space: nowrap;
+          color: #333333;
+          //max-height: 48px;
+        }
+        .p{
+          color: #999;
+          font-size: 16px;
+          overflow: hidden;
+          text-overflow:ellipsis;
+          white-space: nowrap;
+          padding-top: 18px;
+          position: relative;
+          margin-top: 8px;
+          &:after{
+            position: absolute;
+            top: 0;
+            left: 50%;
+            margin-left: -80px;
+            width: 160px;
+            height: 2px;
+            background: #F0F0F0;
+            content: '';
+          }
+        }
+        .priceBox {
+          padding-top: 11px;
+          line-height: 33px;
+          span {
+            font-size: 25px;
+            color: #C83732;
+            padding-right: 12px;
+          }
+          span.discount {
+            font-size: 18px;
+            color: #ccc;
+            text-decoration: line-through;
+          }
+        }
+        .btn-cart{
+          margin-top: 5px;
+          width: 100%;
+          height: 40px;
+          background-color: #333;
+          font-size: 18px;
+          color: #FFEBC4;
+        }
+      }
+    }
+    ul{
+      margin: -15px 0 0 -15px;
+      display: flex;
+      flex-wrap: wrap;
+      li{
+        flex: 0 0 50%;
+        padding: 15px 0 0 15px;
+        width: 0;
+      }
+    }
+    .imgTextNum2 {
+      li {
+        flex: 0 0 50%;
+      }
+    }
+    .imgTextNum3 {
+      li {
+        flex: 0 0 33.33%;
+      }
+    }
+    .imgTextNum4 {
+      li {
+        flex: 0 0 25%;
+      }
+    }
+    .imgTextNum5 {
+      li {
+        flex: 0 0 20%;
+      }
+    }
+  }
+}
+.btn-more {
+  width: 130px;
+  height: 41px;
+  border: 2px solid #C5AA7B;
+  color: #C5AA7B;
+  font-size: 18px;
+  background-color: transparent;
+  margin: 20px auto 0;
+  display: block;
+}
+</style>

+ 240 - 0
canvas-container/components/canvasShow/basics/product/app/index.vue

@@ -0,0 +1,240 @@
+<template>
+  <div class="hom-pro-list">
+    <div class="title">
+      <img src="../../../static/images/product/img-title.png" alt="商品推荐"/>
+    </div>
+    <div v-if="componentContent.arrangeType == '横向滑动'" class="product-list product-swiper">
+      <swiper ref="mySwiper" class="product-list-box" :options="swiperOption">
+        <swiper-slide class="product-list-item" v-for="(item,index) in productData.slice(0, 10)" :key="index" @click="jumpProductDetail(item)">
+          <div class="product-list-img">
+            <img v-show="item.image" class="img" :src="item.image">
+          </div>
+          <div class="product-list-info">
+            <label class="product-name">{{item.productName}}</label>
+            <div>
+              <div class="shop-box" v-if="typeId == 1" @click.stop="jumpStore(item)">
+                <label class="shop-name">{{item.shopName}}</label>
+                <div class="shop-logo">
+                  <img :src="item.shopLogo">
+                </div>
+              </div>
+              <label class="buy-count">{{item.users?item.users: 0}}人付款</label>
+            </div>
+            <div class="price-warp">
+              <div class="price">
+                ¥ {{item.price}}
+              </div>
+              <div class="original-price">
+                ¥ {{item.originalPrice}}
+              </div>
+            </div>
+          </div>
+        </swiper-slide>
+      </swiper>
+      <div class="pagination product-pagination" slot="pagination"></div>
+    </div>
+    <div v-if="componentContent.arrangeType == '多行多列'" class="product-list">
+      <div class="product-list-box" >
+        <div class="product-list-item" v-for="(item,index) in productData" :key="index" @click="jumpProductDetail(item)">
+          <div class="product-list-img">
+            <img v-show="item.image" class="img" :src="item.image">
+          </div>
+          <div class="product-list-info">
+            <label class="product-name">{{item.productName}}</label>
+            <div>
+              <div class="shop-box" v-if="typeId == 1" @click.stop="jumpStore(item)">
+                <label class="shop-name">{{item.shopName}}</label>
+                <div class="shop-logo">
+                  <img :src="item.shopLogo">
+                </div>
+              </div>
+              <label class="buy-count">{{item.users?item.users: 0}}人付款</label>
+            </div>
+            <div class="price-warp">
+              <div class="price">
+                ¥ {{item.price}}
+              </div>
+              <div class="original-price">
+                ¥ {{item.originalPrice}}
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <button v-show="componentContent.showMore" class="btn-more" @click="jumpLink(componentContent.linkObj)">查看全部 <span class="icon iconfont icon-arrow-right"></span></button>
+  </div>
+</template>
+
+<script>
+import {commonMixin} from '../mixin'
+export default {
+  mixins: [commonMixin],
+  data () {
+    return {
+      swiperOption: {
+        slidesPerView: 2,
+        spaceBetween: 14,
+        autoplay: false, // 可选选项,自动滑动
+        loop: true,
+        pagination: {
+          el: '.product-pagination',
+          clickable: true
+        },
+        navigation: {
+          nextEl: '.swiper-button-next',
+          prevEl: '.swiper-button-prev'
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.hom-pro-list{
+  padding: 20px 0;
+  .title{
+    text-align: center;
+    margin-bottom: 20px;
+    label{
+      background: url("../../../static/images/icon-title.png") no-repeat left center;
+      font-size: 30px;
+      font-weight: bold;
+      padding-left: 48px;
+    }
+  }
+  /**多行多列**/
+  .product-list {
+    position: relative;
+    &-box {
+      display: flex;
+      flex-wrap: wrap;
+      flex-direction: row;
+      padding-left: 20px;
+      ::v-deep .swiper-pagination-bullet{
+        display: none;
+      }
+    }
+    &.product-swiper .product-list-box{
+      margin: 0 20px;
+      padding-left: 0;
+    }
+    &-item {
+      margin: 0 14px 20px 0;
+      width: 348px;
+    }
+    &-img {
+      width: 348px;
+      height: 348px;
+      background-color: #f5f5f5;
+      border-radius: 10px 10px 0 0;
+      .img {
+        width: 100%;
+        height: 100%;
+        object-fit: contain;
+      }
+    }
+    &-info {
+      background-color: #FFFFFF;
+      //box-shadow: 0px 0px 15px 0px rgba(52, 52, 52, 0.15);
+      border-radius: 0 0 10px 10px;
+      padding: 20px;
+      label{
+        font-weight: normal;
+      }
+      .product-name{
+        font-size: 28px;
+        color: #333;
+        display: block;
+        overflow: hidden;
+        text-overflow:ellipsis;
+        white-space: nowrap;
+        margin-bottom: 18px;
+        line-height: 40px;
+      }
+      .shop-box{
+        background-color: #333333;
+        border-radius: 0px 20px 20px 0px;
+        line-height: 40px;
+        display: inline-block;
+        height: 40px;
+        margin-right: 10px;
+        .shop-name{
+          font-size: 20px;
+          color: #FFEBC4;
+          padding: 0 8px 0 12px;
+        }
+        .shop-logo{
+          border: 2px solid #707070;
+          border-radius: 50%;
+          overflow: hidden;
+          float: right;
+          img{
+            width: 34px;
+            height: 34px;
+            display: block;
+          }
+        }
+      }
+      .buy-count{
+        color: #C5AA7B;
+        font-size: 20px;
+        margin-bottom: 16px;
+        border: 2px solid #E4E5E6;
+        line-height: 40px;
+        padding: 0 5px;
+        display: inline-block;
+      }
+      .price-warp{
+        display: flex;
+        align-items: baseline;
+        line-height: 56px;
+        .price{
+          color: #C83732;
+          font-size: 40px;
+          margin-right: 20px;
+        }
+        .original-price{
+          font-size: 24px;
+          color: #ccc;
+          text-decoration: line-through;
+        }
+      }
+    }
+    //::v-deep .swiper-pagination-bullet{
+    //  display: none;
+    //}
+  }
+}
+
+.pagination{
+  display: flex;
+  justify-content: center;
+  padding: 20px 0;
+  ::v-deep .swiper-pagination-bullet{
+    width: 10px;
+    height: 10px;
+    background: #333333;
+    opacity: 0.3;
+    border-radius: 5px;
+    margin: 0 5px;
+  }
+  ::v-deep .swiper-pagination-bullet-active{
+    width: 20px;
+    height: 10px;
+    opacity: 1;
+  }
+}
+.btn-more {
+  width: 170px;
+  height: 54px;
+  border: 2px solid #C5AA7B;
+  color: #C5AA7B;
+  font-size: 24px;
+  background-color: transparent;
+  margin: 20px auto 0;
+  display: block;
+}
+
+</style>

+ 105 - 0
canvas-container/components/canvasShow/basics/product/mixin.js

@@ -0,0 +1,105 @@
+import { directive, Swiper, SwiperSlide } from 'vue-awesome-swiper'
+import {funMixin} from '../../config/mixin'
+import 'swiper/css/swiper.css'
+import api from '../../config/api'
+import { mapGetters } from 'vuex'
+
+export const commonMixin = {
+  name: 'productList',
+  mixins: [funMixin],
+  props: {
+    terminal: {
+      type: Number,
+      default: 4
+    },
+    typeId: {
+      type: Number,
+      default: 1
+    },
+    shopId: {
+      type: Number,
+      default: 0
+    },
+    componentContent: {
+      type: Object
+    }
+  },
+  components: {
+    Swiper,
+    SwiperSlide
+  },
+  directives: {
+    swiper: directive
+  },
+  data () {
+    return {
+      productData: []
+    }
+  },
+  watch: {
+    'productNum': {
+      handler(newVal, oldVal) {
+        this.getData()
+      },
+      deep: true
+    }
+  },
+  mounted() {
+    this.getData(true)
+  },
+  computed: {
+    ...mapGetters([
+      'productNum'
+    ]),
+    swiper() {
+      if(this.$refs.mySwiper){
+        return this.$refs.mySwiper.$swiper
+      }
+    }
+  },
+  methods: {
+    getData(isFirst) {
+      const _ = this
+      if (_.componentContent.productData.sourceType === '1') {
+        if(_.componentContent.productData.productIdList && _.componentContent.productData.productIdList.length>0){
+          this.beforeGetData()
+          _.sendReq({
+            url: `${api.getProducts}?page=1&pageSize=99&ids=${_.componentContent.productData.productIdList}`,
+            method: 'GET'
+          }, (proRes) => {
+            _.afterGetData()
+            _.productData = proRes.data.list
+            if(isFirst){
+              _.componentContent.productData.imgTextData = _.productData
+            }
+          },(err)=>{
+            _.afterGetData()
+          })
+        } else {
+          _.productData = []
+        }
+      } else if(_.componentContent.productData.sourceType === '2'){
+        if(_.componentContent.productData.categoryId) {
+          this.beforeGetData()
+          _.sendReq({
+            url: `${api.getProducts}?page=1&pageSize=99&classifyId=${_.componentContent.productData.categoryId}`,
+            method: 'GET'
+          }, (proRes) => {
+            _.afterGetData()
+            _.productData = proRes.data.list
+            if(isFirst){
+              _.componentContent.productData.imgTextData = _.productData
+            }
+            // _.swiper.update()
+          },(err)=>{
+            _.afterGetData()
+          })
+        } else {
+          _.productData = {
+            products:[]
+          }
+        }
+      }
+    },
+  }
+}

+ 226 - 0
canvas-container/components/canvasShow/basics/product/pc/index.vue

@@ -0,0 +1,226 @@
+<template>
+  <div class="product-list" :class="'terminal'+terminal">
+    <div class="picListWarp" v-if="componentContent.arrangeType == '横向滑动'">
+      <div class="picList" v-if="productData && productData.length>0">
+        <div class="swiper-button-prev"></div>
+        <div class="swiper-button-next"></div>
+        <swiper ref="swiper" class="products-swiper" :options="swiperOption">
+          <swiper-slide class="products-swiper-slide item" v-for="(item,index) in productData" :key="index">
+            <div class="a-link" @click="jumpProductDetail(item)">
+              <div class="itemImgBox">
+                <div class="imgBox">
+                  <el-image
+                    :src="item.image"
+                    fit="contain"></el-image>
+                </div>
+              </div>
+              <div class="text">
+                <h4 class="h4">{{item.productName}}</h4>
+                <div class="priceBox">
+                  <span>¥{{item.price}}</span>
+                  <span class="discount" v-if="item.originalPrice">¥{{item.originalPrice}}</span>
+                </div>
+              </div>
+            </div>
+          </swiper-slide>
+        </swiper>
+      </div>
+    </div>
+    <div v-else class="picList" >
+      <ul class="clearfix" :class="'imgTextNum' +  componentContent.productNum">
+        <li class="item" v-for="(item,index) in productData.slice(0, componentContent.productRowNum * componentContent.productNum)" :key="index">
+          <div class="a-link" @click="jumpProductDetail(item)">
+            <div class="itemImgBox">
+              <div class="imgBox">
+                <el-image
+                  :src="item.image"
+                  fit="contain"></el-image>
+              </div>
+            </div>
+            <div class="text">
+              <h4 class="h4">{{item.productName}}</h4>
+              <div class="priceBox">
+                <span>¥{{item.price}}</span>
+                <span class="discount" v-if="item.originalPrice">¥{{item.originalPrice}}</span>
+              </div>
+            </div>
+          </div>
+        </li>
+      </ul>
+    </div>
+    <button v-show="componentContent.showMore" class="btn-more" @click="jumpLink(componentContent.linkObj)">查看全部 <span class="icon iconfont icon-arrow-right"></span></button>
+  </div>
+</template>
+
+<script>
+import {commonMixin} from '../mixin'
+  export default {
+    mixins: [commonMixin],
+    data () {
+      return {
+        swiperOption: {
+          slidesPerView: 4, // 显示数量
+          spaceBetween: 13, // 间隔
+          autoplay: false, // 可选选项,自动滑动
+          loop: true,
+          pagination: {
+            el: '.product-pagination'
+          },
+          navigation: {
+            nextEl: '.swiper-button-next',
+            prevEl: '.swiper-button-prev'
+          }
+        }
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+  .product-list{
+    padding: 20px 0;
+    background-color: #fff;
+    .picListWarp{
+      width: 1380px;
+      max-width: 100%;
+      margin: 0 auto;
+      position: relative;
+    }
+    .picList{
+      width: 1200px;
+      max-width: 100%;
+      margin: 0 auto;
+      .swiper-button-prev,.swiper-button-next{
+        width: 50px;
+        height: 50px;
+        position: absolute;
+        cursor:pointer;
+        top: 140px;
+        background-repeat: no-repeat;
+        &:after{
+          content: '';
+        }
+      }
+      .swiper-button-prev{
+        left: 0;
+        background: url('../../../static/images/btn-prev.png');
+      }
+      .swiper-button-next{
+        right: 0;
+        background: url('../../../static/images/btn-next.png');
+      }
+      .a-link{
+        cursor: pointer;
+        &:hover{
+          box-shadow: 3px 4px 20px 0px rgba(186, 186, 186, 0.5);
+        }
+        .itemImgBox {
+          height: auto;
+          display: flex;
+          flex-direction: column;
+          justify-content: center;
+          .imgBox {
+            padding-bottom: 100%;
+            background-color: #cacaca;
+            position: relative;
+            .el-image {
+              width: 100%;
+              height: 100%;
+              position: absolute;
+              top: 0;
+              left: 0;
+            }
+          }
+        }
+        .text{
+          padding:25px 20px 17px;
+          text-align: center;
+          //height: 180px;
+          .h4{
+            font-size: 18px;
+            line-height: 24px;
+            overflow: hidden;
+            text-overflow:ellipsis;
+            white-space: nowrap;
+            color: #333333;
+            //max-height: 48px;
+          }
+          .p{
+            color: #999;
+            font-size: 16px;
+            overflow: hidden;
+            text-overflow:ellipsis;
+            white-space: nowrap;
+            padding-top: 18px;
+            position: relative;
+            margin-top: 8px;
+            &:after{
+              position: absolute;
+              top: 0;
+              left: 50%;
+              margin-left: -80px;
+              width: 160px;
+              height: 2px;
+              background: #F0F0F0;
+              content: '';
+            }
+          }
+          .priceBox {
+            padding-top: 11px;
+            line-height: 33px;
+            span {
+              font-size: 25px;
+              color: #C83732;
+              padding-right: 12px;
+            }
+            span.discount {
+              font-size: 18px;
+              color: #ccc;
+              text-decoration: line-through;
+            }
+          }
+        }
+      }
+      ul{
+        margin: -15px 0 0 -15px;
+        display: flex;
+        flex-wrap: wrap;
+        li{
+          flex: 0 0 50%;
+          padding: 15px 0 0 15px;
+          width: 0;
+        }
+      }
+      .imgTextNum2 {
+        li {
+          flex: 0 0 50%;
+        }
+      }
+      .imgTextNum3 {
+        li {
+          flex: 0 0 33.33%;
+        }
+      }
+      .imgTextNum4 {
+        li {
+          flex: 0 0 25%;
+        }
+      }
+      .imgTextNum5 {
+        li {
+          flex: 0 0 20%;
+        }
+      }
+    }
+  }
+  .btn-more {
+    width: 130px;
+    height: 41px;
+    border: 2px solid #C5AA7B;
+    color: #C5AA7B;
+    font-size: 18px;
+    background-color: transparent;
+    margin: 20px auto 0;
+    display: block;
+  }
+</style>

+ 113 - 0
canvas-container/components/canvasShow/basics/shop.vue

@@ -0,0 +1,113 @@
+<template>
+  <div class="shop"  :class="'terminal' + terminal">
+    <swiper :options="swiperOption">
+      <swiper-slide class="shop-item" v-for="(item,index) in imgList" :key="index">
+        <div class="shop-item-warp">
+          <img class="img" :src="item.img">
+          <div class="a-link" @click="jumpLink(item.linkObj)">
+            进店逛逛<i class="iconfont icon-arrow-right"></i>
+          </div>
+        </div>
+      </swiper-slide>
+    </swiper>
+    <div class="pagination shop-pagination"></div>
+  </div>
+</template>
+
+<script>
+import { directive, Swiper, SwiperSlide } from 'vue-awesome-swiper'
+import 'swiper/css/swiper.css'
+import {funMixin} from '../config/mixin'
+export default {
+  name: 'shop',
+  mixins: [funMixin],
+  data () {
+    return {
+      swiperOption: {
+        autoplay: false, // 可选选项,自动滑动
+        loop: true,
+        pagination: {
+          el: '.shop-pagination'
+        }
+      }
+    }
+  },
+  props: {
+    terminal: {
+      type: Number,
+      default: 4
+    },
+    componentContent: {
+      type: Object
+    }
+  },
+  components: {
+    Swiper,
+    SwiperSlide
+  },
+  directives: {
+    swiper: directive
+  },
+  computed: {
+    imgList: function () {
+      console.log(this.componentContent)
+      return this.componentContent.imgTextData.filter(function (item) {
+        return item.img
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.shop{
+  position: relative;
+  &-item{
+    &-warp{
+      position: relative;
+      padding: 0 20px;
+      .img{
+        width: 100%;
+        height: 420px;
+      }
+      .a-link{
+        width: 220px;
+        height: 80px;
+        line-height: 80px;
+        background: linear-gradient(225deg, #585858 0%, #333333 100%);
+        box-shadow: 0px 20px 40px rgba(0, 0, 0, 0.3);
+        display: block;
+        color: #fff;
+        font-size: 28px;
+        text-align: center;
+        position: absolute;
+        right: 0;
+        bottom: 30px;
+        .icon{
+          margin-left: 20px;
+        }
+      }
+    }
+  }
+  .pagination{
+    display: flex;
+    justify-content: center;
+    padding:20px 0;
+    ::v-deep .swiper-pagination-bullet{
+      width: 12px;
+      height: 12px;
+      background: #333333;
+      border-radius: 50%;
+      opacity: 0.2;
+      margin: 0 10px;
+    }
+    ::v-deep .swiper-pagination-bullet-active{
+      width: 24px;
+      height: 12px;
+      background: #333333;
+      opacity: 1;
+      border-radius: 8px;
+    }
+  }
+}
+</style>

+ 155 - 0
canvas-container/components/canvasShow/basics/spike/app/index.vue

@@ -0,0 +1,155 @@
+<template>
+  <div class="spike">
+    <div class="spike-card" v-if="productData.products && productData.products.length>0">
+      <div class="spike-card-top">
+        <h2 class="spike-card-top-title">
+          <img src="../../../static/images/spike/img-title.png" alt="秒杀专区"/>
+        </h2>
+        <div class="spike-card-top-time" v-if="state===2">
+          活动已结束
+        </div>
+        <div class="spike-card-top-time" v-else>
+          距离{{count[0]}}还有 <span>{{count[1]}}</span><i>:</i><span>{{count[2]}}</span><i>:</i><span>{{count[3]}}</span>
+        </div>
+        <a class="btn-more" @click="jumpSeckills(productData)">更多<i class="iconfont icon-arrow-right"></i></a>
+      </div>
+      <ul class="spike-card-list">
+        <li class="spike-card-item"  v-for='item in productData.products.slice(0,4)' :key='item.productId' @click="jumpProductDetail(it)">
+          <div class="spike-card-item-img">
+            <img :src="item.image" alt="">
+          </div>
+          <div class="spike-card-item-info">
+            <h3 class="name">
+              {{item.productName}}
+            </h3>
+            <div class="stock">
+              还剩{{item.stockNumber}}件
+            </div>
+            <div class="price-warp">
+              <div class="price">
+                ¥ {{item.price}}
+              </div>
+              <div class="original-price">
+                ¥ {{item.originalPrice}}
+              </div>
+            </div>
+          </div>
+        </li>
+      </ul>
+    </div>
+  </div>
+</template>
+
+<script>
+import {commonMixin} from '../mixin'
+export default {
+  mixins: [commonMixin]
+}
+</script>
+
+<style lang="scss" scoped>
+.spike{
+  background: #F8F8F8;
+  padding: 20px;
+  &-card{
+    height: 498px;
+    background: #FFFFFF;
+    border-radius: 20px;
+    &-top{
+      position: relative;
+      padding: 32px 0 22px;
+      display: flex;
+      &-title{
+        padding: 10px 20px 0 30px;
+      }
+      &-time{
+        padding: 0 18px;
+        height: 50px;
+        background: linear-gradient(90deg, #C83732 0%, #E25C44 100%);
+        box-shadow: 0px 6px 12px rgba(233, 0, 0, 0.3);
+        opacity: 1;
+        border-radius: 26px;
+        font-size: 24px;
+        line-height: 50px;
+        color: #fff;
+        text-align: center;
+      }
+      .btn-more{
+        position: absolute;
+        right: 8px;
+        top: 40px;
+        line-height: 33px;
+        padding-right: 25px;
+        font-size: 24px;
+        color: #333;
+        .iconfont{
+          content: '';
+          font-size: 26px;
+          position: absolute;
+          right: 0;
+          top: 0;
+        }
+      }
+    }
+    &-list{}
+    &-item{
+      width: 50%;
+      border-top: 1px solid  #F3F4F5;
+      border-left: 1px solid  #F3F4F5;
+      float: left;
+      align-items: center;
+      &:nth-child(2n+1){
+        border-left: 0px;
+      }
+      &-img{
+        width: 162px;
+        height: 196px;
+        margin-right: 10px;
+        float: left;
+        img {
+          width: 100%;
+          height: 100%;
+          object-fit: contain;
+        }
+      }
+      &-info{
+        height: 100%;
+        margin-left: 172px;
+        width: 168px;
+        .name{
+          font-size: 24px;
+          line-height: 40px;
+          color: #333333;
+          overflow: hidden;
+          text-overflow:ellipsis;
+          white-space: nowrap;
+        }
+        .stock{
+          padding: 0 8px;
+          height: 40px;
+          border: 2px solid #E4E5E6;
+          line-height: 40px;
+          margin: 10px 0;
+          display: inline-block;
+          font-size: 20px;
+          color: #C5AA7B;
+        }
+        .price{
+          font-size: 32px;
+          font-weight: bold;
+          line-height: 44px;
+          color: #C83732;
+          padding-right: 10px;
+          display: inline-block;
+        }
+        .original-price{
+          font-size: 20px;
+          line-height: 28px;
+          color: #CCCCCC;
+          display: inline-block;
+        }
+      }
+    }
+  }
+}
+</style>

+ 152 - 0
canvas-container/components/canvasShow/basics/spike/mixin.js

@@ -0,0 +1,152 @@
+import api from '../../config/api'
+import {funMixin} from '../../config/mixin'
+import { mapGetters } from 'vuex'
+
+export const commonMixin = {
+  name: 'spikeList',
+  mixins: [funMixin],
+  data () {
+    return {
+      productData: {
+        products: []
+      },
+      count: [],
+      state: 0,
+      timer: null
+    }
+  },
+  props: {
+    terminal: {
+      type: Number,
+      default: 4
+    },
+    typeId: {
+      type: Number,
+      default: 1
+    },
+    shopId: {
+      type: Number,
+      default: 0
+    },
+    componentContent: {
+      type: Object
+    }
+  },
+  computed: {
+    ...mapGetters([
+      'spikeNum'
+    ]),
+  },
+  watch: {
+    'spikeNum': {
+      handler(newVal, oldVal) {
+        this.getData()
+      },
+      deep: true
+    }
+  },
+  created() {
+    this.getData()
+  },
+  methods: {
+    getData() {
+
+      const _ = this
+      if(_.componentContent.shopSeckillId){
+        if(this.typeId === 1){
+          this.beforeGetData()
+          const params = {
+            method: 'GET',
+            url: `${api.getPlatformSeckills}?ids=${_.componentContent.shopSeckillId}`,
+          }
+          this.sendReq(params, (res) => {
+            _.afterGetData()
+            if(res.data.length> 0){
+              _.productData = res.data[0]
+              _.productData.products.map(function(value){
+                value.sliderVal = (value.stockNumber/value.total*100).toFixed(2)
+                return value;
+              });
+              // 只有进行中和未开始活动, 用倒计时
+              this.timer = setInterval(()=>{
+                _.getTime(_.productData)
+              }, 1000)
+            }
+          },(err)=>{
+            _.afterGetData()
+          })
+        }
+        if(this.typeId === 3){
+          this.beforeGetData()
+          const params = {
+            method: 'GET',
+            url: `${api.getSeckills}?shopId=${_.shopId}&ids=${_.componentContent.shopSeckillId}`,
+          }
+          this.sendReq(params, (res) => {
+            this.afterGetData()
+            if(res.data.length> 0){
+              _.productData = res.data[0]
+              _.productData.products.map(function(value){
+                value.sliderVal = (value.stockNumber/value.total*100).toFixed(2)
+                return value;
+              });
+              // 只有进行中和未开始活动, 用倒计时
+              if(_.productData.state !==2) {
+                this.timer = setInterval(()=>{
+                  _.getTime(_.productData)
+                }, 1000)
+              }
+            } else {
+              _.productData = {
+                products:[]
+              }
+            }
+          },(err)=>{
+            _.afterGetData()
+          })
+        }
+      } else {
+        _.productData = {
+          products:[]
+        }
+      }
+    },
+    getTime(info) {
+      const date = new Date().getTime()
+      let startTime = ''
+      let endTime = ''
+      if(this.typeId === 1){
+        startTime = new Date(info.startTime.replace(/-/g,'/')).getTime()
+        endTime = new Date(info.endTime.replace(/-/g,'/')).getTime()
+      } else {
+        startTime = new Date(info.effectiveStart.replace(/-/g,'/')).getTime()
+        endTime = new Date(info.effectiveEnd.replace(/-/g,'/')).getTime()
+      }
+      if(date > endTime){
+        this.state = 2
+      } else if(startTime > date) {
+        this.state = 0
+        this.countDown(startTime-date) // 未开始
+      } else {
+        this.state = 1
+        this.countDown(endTime-date) // 进行中
+      }
+
+    },
+
+    countDown(time) {
+      const fn = (v) =>  v < 10 ? `0${v}` : v
+      const t = parseInt(time / 1000)
+      const text = this.state == 0 ? '开始' : '结束'
+      const hour = parseInt(t / 3600)
+      const min = parseInt((t % 3600) / 60)
+      const s = t % 60
+      // console.log(min, '分',t)
+      this.count = [text, fn(hour), fn(min), fn(s)]
+      // console.log(text, fn(hour), fn(min), fn(s))
+    }
+  },
+  beforeDestroy() {
+    clearInterval(this.timer)
+  }
+}

+ 217 - 0
canvas-container/components/canvasShow/basics/spike/pc/index.vue

@@ -0,0 +1,217 @@
+<template>
+  <div class="spikeList" :class="'terminal'+terminal" v-if="componentContent.shopSeckillId && productData.products && productData.products.length > 0">
+    <div class="warp">
+      <div>
+        <div class="spikeCard">
+          <div class="listLeft">
+            <img src="../../../static/images/spike/bg-spike.png">
+            <div class="bgBox">
+              <div class="title"><img src="../../../static/images/spike/tit-spike.png" alt="秒杀专区"></div>
+              <div class="text">整点秒杀,数量有限</div>
+              <div class="sessions">{{productData.seckillName}} {{state===0?'倒计时':''}}</div>
+              <div class="time-text time-text-end" v-if="state===2">活动已结束</div>
+              <div v-else>
+                <div class="time-text">距离{{count[0]}}还有</div>
+                <div class="timeBox">
+                  <span>{{count[1]}}</span><i>:</i><span>{{count[2]}}</span><i>:</i><span>{{count[3]}}</span>
+                </div>
+              </div>
+              <button class="btn-more" @click="jumpSeckills(productData)">查看全部 <span class="icon iconfont icon-arrow-right"></span></button>
+            </div>
+          </div>
+          <div class="listRight">
+            <div class="listItem" v-for='it in productData.products.slice(0, 6)' :key='it.productId' @click="jumpProductDetail(it)">
+              <div class="imgBox">
+                <img :src="it.image" alt="">
+              </div>
+              <div class="itemInfo">
+                <h3>{{it.productName}}</h3>
+                <div class="begrenzt">
+                  <span class="people">还剩{{it.stockNumber}}件</span>
+                  <div class="progress" :style="{'width':it.sliderVal + '%'}"></div>
+                </div>
+                <div class="originalPrice">¥{{it.originalPrice}}</div>
+                <dl class="discountPrice">
+                  <dt>
+                    <img src="../../../static/images/spike/flag-spike.png" alt="秒杀价">
+                  </dt>
+                  <dd>
+                    <span>¥</span><b>{{it.price}}</b>
+                  </dd>
+                </dl>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import {commonMixin} from '../mixin'
+export default {
+  mixins: [commonMixin]
+}
+</script>
+
+<style lang="scss" scoped>
+.spikeList{
+  min-height: 100px;
+  &.terminal4{
+    background-color: #F3F4F5;
+    .warp{
+      width: 1200px;
+    }
+    .spikeCard {
+      display: flex;
+      width: 100%;
+      .listLeft {
+        width: 487px;
+        height: 758px;
+        text-align: center;
+        position: relative;
+        .bgBox {
+          position: absolute;
+          top: 0;
+          left: 0;
+          width: 100%;
+          .title{
+            padding-top: 140px;
+          }
+          .text{
+            color: #8E8D8C;
+            font-size: 30px;
+            line-height: 40px;
+            margin: 15px 0 100px 0;
+          }
+          .sessions{
+            color: #FFEBC4;
+            font-size: 30px;
+            line-height: 40px;
+          }
+          .time-text{
+            padding-top: 60px;
+            color: #FFEBC4;
+            font-size: 18px;
+            &-end{
+              margin-bottom: 20px;
+            }
+          }
+          .timeBox {
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            margin:10px 0 50px;
+            span {
+              display: block;
+              width: 60px;
+              height: 60px;
+              background: rgba(51,51,51,0.8);
+              color: #FFFFFF;
+              font-size: 30px;
+              line-height: 60px;
+            }
+            i {
+              font-size: 30px;
+              color: #fff;
+              font-style: normal;
+              font-weight: bold;
+              padding: 0 13px;
+            }
+          }
+          .btn-more {
+            width: 130px;
+            height: 41px;
+            border: 2px solid #FFEBC4;
+            color: #FFEBC4;
+            font-size: 18px;
+            background-color: transparent;
+          }
+        }
+      }
+      .listRight {
+        padding: 40px 0 0 8px;
+        .listItem {
+          float:left;
+          width: 220px;
+          height: 335px;
+          margin:0 0 15px 15px;
+          background-color: #fff;
+          .imgBox {
+            width: 220px;
+            height: 220px;
+            img {
+              width: 100%;
+              height: 100%;
+            }
+          }
+          .itemInfo {
+            position: relative;
+            padding: 10px;
+            text-align: center;
+            h3{
+              font-size: 14px;
+              color: #333;
+              line-height: 18px;
+              overflow: hidden;
+              text-overflow:ellipsis;
+              white-space: nowrap;
+            }
+            .begrenzt{
+              position: absolute;
+              left: 5px;
+              top: -35px;
+              width: 210px;
+              height: 30px;
+              border: 1px solid #C83732;
+              background-color: #C83732;
+              text-align: center;
+              .people{
+                position: relative;
+                z-index: 2;
+                font-size: 12px;
+                color: #FFBAB8;
+                line-height: 30px;
+              }
+              .progress{
+                position: absolute;
+                right: 0;
+                top: 0;
+                background-color: #fff;
+                height: 28px;
+              }
+            }
+            .discountPrice {
+              display: inline-block;
+              width: 130px;
+              dt{
+                float: left;
+              }
+              dd{
+                border: 1px solid #F3F4F5;
+                color: #C83732;
+                line-height: 30px;
+                font-weight: bold;
+                span {
+                  font-size: 18px;
+                }
+                b {
+                  font-size: 18px;
+                }
+              }
+            }
+            .originalPrice {
+              font-size: 14px;
+              line-height: 19px;
+              padding: 10px 0 6px;
+              color: #ccc;
+              text-decoration: line-through;
+            }
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 79 - 0
canvas-container/components/canvasShow/basics/text.vue

@@ -0,0 +1,79 @@
+<template>
+  <div class="text warp" :class="['text-'+componentContent.textPos,{'show-more':componentContent.showMore},'terminal' + terminal]" :style="{backgroundColor:componentContent.bgColor}">
+    <div class="line-warp" :class="{'borderBot':componentContent.showLine}">
+      <h3 class="h3" :style="{fontSize:componentContent.fontSizeNum+'px',fontWeight:componentContent.textFontW,color:componentContent.titColor}">{{componentContent.title}}</h3>
+      <p class="p" :style="{fontSize:componentContent.describeSizeNum+'px',fontWeight:componentContent.describeFontW,color:componentContent.describeColor}">{{componentContent.describe}}</p>
+      <div class="btn-more" v-show="componentContent.showMore" :class="'style'+componentContent.styleValue" @click="jumpLink(item.linkObj)"><span>查看更多</span><i class="iconfont icon-arrow-right"></i></div>
+    </div>
+  </div>
+</template>
+
+<script>
+  export default {
+    name: 'textComponent',
+    data () {
+      return {
+      }
+    },
+    props: {
+      terminal: {
+        type: Number,
+        default: 4
+      },
+      componentContent: {
+        type: Object
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+  .text{
+    padding: 0px 20px;
+    position: relative;
+    .line-warp{
+      padding: 10px 0;
+    }
+    .borderBot{
+      border-bottom: 1px solid #cccc;
+    }
+    .h3{
+      line-height: 1.5;
+    }
+    .p{
+      line-height: 1.5;
+      margin-top: 5px;
+    }
+    .style1{
+
+    }
+    .style2{
+      .iconfont{
+        display: none;
+      }
+    }
+    .style3{
+      span{
+        display: none;
+      }
+    }
+    &.text-left{
+      text-align: left;
+      &.show-more{
+        position: relative;
+        padding-right: 20px;
+        .btn-more{
+          position: absolute;
+          right: 0;
+          top: 10px;
+        }
+      }
+    }
+    &.text-center{
+      text-align: center;
+    }
+    &.text-right{
+      text-align: right;
+    }
+  }
+</style>

+ 76 - 0
canvas-container/components/canvasShow/basics/video.vue

@@ -0,0 +1,76 @@
+<template>
+  <div class="videoBox warp" :class="'terminal' + terminal">
+    <div class="videoLeftBox">
+      <h3>{{componentContent.title}}</h3>
+      <div v-html="componentContent.mainBody"></div>
+    </div>
+    <div class="videoRightBox">
+      <video class="myVideo" id="myVideo" :src="componentContent.videoUrl" enable-danmu danmu-btn controls></video>
+    </div>
+    <div class="clear"></div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'videoBox',
+  props: {
+    terminal: {
+      type: Number,
+      default: 4
+    },
+    componentContent: {
+      type: Object
+    }
+  },
+  data () {
+    return {
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+ .videoBox {
+   padding: 20px 0;
+   display: flex;
+   justify-content: flex-start;
+   align-items: center;
+   .videoLeftBox {
+     width: 50%;
+     padding-right: 10%;
+     h3 {
+       font-size: 28px;
+       color: #333333;
+       margin-bottom: 30px;
+     }
+     p {
+       color: #333333;
+       font-size: 14px;
+       line-height: 30px;
+     }
+   }
+   .videoRightBox {
+     width: 50%;
+     video {
+       width: 100%;
+     }
+   }
+   .clear {
+     clear: both;
+   }
+ }
+ .terminal1,.terminal2,.terminal3{
+   &.videoBox{
+     display: block;
+     .videoLeftBox{
+       width: 100%;
+       text-align: center;
+       margin-bottom: 20px;
+     }
+     .videoRightBox {
+       width: 100%;
+     }
+   }
+ }
+</style>

+ 211 - 0
canvas-container/components/canvasShow/basics/vip/app/index.vue

@@ -0,0 +1,211 @@
+<template>
+  <div class="vip">
+    <div class="vip-card">
+      <div class="vip-title">
+        <h2>
+          <img src="../../../static/images/vip/img-title.png" alt="会员专区"/>
+        </h2>
+        <a v-show="componentContent.showMore" class="btn-more a-link" @click="jumpVip">更多<i class="iconfont icon-arrow-right"></i></a>
+      </div>
+      <swiper class="vip-list" :options="swiperOption">
+        <swiper-slide class="vip-item-warp" v-for="(itemJ,indexJ) in listTemp" :key="indexJ" @click="jumpProductDetail(item)">
+          <div class="vip-item"  v-for="(item,index) in itemJ" :key="index">
+            <div class="vip-item-img">
+              <img v-show="item.image" class="img" :src="item.image">
+            </div>
+            <div class="vip-item-info">
+              <h3 class="name">
+                {{item.productName}}
+              </h3>
+              <div class="stock">
+                还剩{{item.stockNumber}}件
+              </div>
+              <div class="original-price">
+                ¥ {{item.originalPrice}}
+              </div>
+              <div class="price-warp">
+                <div class="flag">
+                  <img src="../../../static/images/vip/flag-vip2.png" alt="会员价"/>
+                </div>
+                <div class="price">
+                  ¥ {{item.price}}
+                </div>
+              </div>
+              <div class="btn-buy">
+                <span>去购买</span>
+                <div class="progress">
+                  <i></i>
+                </div>
+              </div>
+            </div>
+          </div>
+        </swiper-slide>
+      </swiper>
+      <div class="pagination vip-pagination"></div>
+    </div>
+  </div>
+</template>
+
+<script>
+import {commonMixin} from '../mixin'
+export default {
+  mixins: [commonMixin],
+  data () {
+    return {
+      swiperOption: {
+        autoplay: false, // 可选选项,自动滑动
+        loop: true,
+        pagination: {
+          el: '.vip-pagination'
+        }
+      }
+    }
+  },
+  computed: {
+    listTemp: function () {
+      var list = this.productData;
+      var arrTemp = [];
+      var index = -1;
+      var count = 2; // 每组多少条
+      for (var i = 0; i < list.length; i++) {
+        if (i % count==0) {
+          arrTemp.push([]);
+          index ++
+        }
+        arrTemp[index].push(list[i]);
+      }
+      return arrTemp;
+    }
+  },
+}
+</script>
+
+<style lang="scss" scoped>
+.vip{
+  &-card{
+    background: #333333;
+    padding: 0 20px 20px;
+  }
+  &-title{
+    padding: 42px 0 28px 30px;
+    position: relative;
+    .btn-more{
+      position: absolute;
+      right: 8px;
+      top: 40px;
+      line-height: 33px;
+      padding-right: 25px;
+      font-size: 24px;
+      color: #FFEBC4;
+      .iconfont{
+        content: '';
+        font-size: 26px;
+        position: absolute;
+        right: 0;
+        top: 0;
+      }
+    }
+  }
+  &-item{
+    display: flex;
+    background-color: #fff;
+    margin-top: 20px;
+    &:first-child{
+      margin-top: 0px;
+    }
+    &-img{
+      width: 260px;
+      height: 260px;
+      margin-right: 20px;
+      background-color: #ececec;
+      .img {
+        width: 100%;
+        height: 100%;
+        object-fit: contain;
+      }
+    }
+    &-info{
+      flex: 1;
+      position: relative;
+      .name{
+        font-size: 28px;
+        line-height: 40px;
+        color: #333333;
+        padding: 30px 0 10px;
+      }
+      .stock{
+        color: #C5AA7B;
+        font-size: 20px;
+        border: 2px solid #E4E5E6;
+        line-height: 40px;
+        padding: 0 5px;
+        display: inline-block;
+        margin-bottom: 30px;
+      }
+      .original-price{
+        font-size: 24px;
+        line-height: 34px;
+        color: #CCCCCC;
+      }
+      .flag{
+        float: left;
+        padding: 12px 10px 0 0;
+      }
+      .price{
+        font-size: 40px;
+        font-weight: bold;
+        line-height: 56px;
+        color: #C83732;
+      }
+      .btn-buy{
+        position: absolute;
+        right: 20px;
+        bottom: 20px;
+        width: 160px;
+        height: 84px;
+        background: linear-gradient(90deg, #C83732 0%, #E25C44 100%);
+        box-shadow: 0px 6px 12px rgba(233, 0, 0, 0.3);
+        border-radius: 10px;
+        text-align: center;
+        padding: 16px 20px 0;
+        span{
+          font-size: 24px;
+          line-height: 34px;
+          color: #FFFFFF;
+          margin-bottom: 10px;
+        }
+        .progress{
+          height: 8px;
+          background: rgba(255,255,255,0.5);
+          border-radius: 4px;
+          position: relative;
+          i{
+            position: absolute;
+            left: 0;
+            top: 0;
+            width: 50%;
+            height: 8px;
+            background-color: #fff;
+            border-radius: 4px;
+          }
+        }
+      }
+    }
+  }
+  .pagination{
+    display: flex;
+    justify-content: center;
+    ::v-deep .swiper-pagination-bullet{
+      width: 24px;
+      height: 4px;
+      background: #fff;
+      opacity: 0.5;
+      border-radius: 2px;
+      margin: 0 5px;
+    }
+    ::v-deep .swiper-pagination-bullet-active{
+      opacity: 1;
+    }
+  }
+}
+</style>

+ 56 - 0
canvas-container/components/canvasShow/basics/vip/mixin.js

@@ -0,0 +1,56 @@
+import { directive, Swiper, SwiperSlide } from 'vue-awesome-swiper'
+import 'swiper/css/swiper.css'
+import api from '../../config/api'
+import {funMixin} from '../../config/mixin'
+
+export const commonMixin = {
+  name: 'productList',
+  mixins: [funMixin],
+  props: {
+    terminal: {
+      type: Number,
+      default: 4
+    },
+    typeId: {
+      type: Number,
+      default: 1
+    },
+    shopId: {
+      type: Number,
+      default: 0
+    },
+    componentContent: {
+      type: Object
+    }
+  },
+  components: {
+    Swiper,
+    SwiperSlide
+  },
+  directives: {
+    swiper: directive
+  },
+  data () {
+    return {
+      productData: []
+    }
+  },
+  mounted() {
+      this.getData()
+  },
+  methods: {
+    getData() {
+      this.beforeGetData()
+      const _ = this
+      _.sendReq({
+        url: `${api.getMemberProducts}?page=1&pageSize=20`,
+        method: 'GET'
+      }, (proRes) => {
+        _.afterGetData()
+        _.productData = proRes.data.list
+      },(err)=>{
+        _.afterGetData()
+      })
+    }
+  }
+}

+ 241 - 0
canvas-container/components/canvasShow/basics/vip/pc/index.vue

@@ -0,0 +1,241 @@
+<template>
+  <div class="product-list" :class="'terminal'+terminal">
+    <div class="picListWarp" v-if="componentContent.arrangeType == '横向滑动'">
+      <div class="picList" v-if="productData && productData.length>0">
+        <div class="swiper-button-prev"></div>
+        <div class="swiper-button-next"></div>
+        <swiper class="products-swiper" :options="swiperOption">
+          <swiper-slide class="products-swiper-slide item" v-for="(item,index) in productData" :key="index">
+            <div class="a-link" @click="jumpProductDetail(item)">
+              <div class="itemImgBox">
+                <div class="imgBox">
+                  <el-image
+                    :src="item.image"
+                    fit="contain"></el-image>
+                </div>
+              </div>
+              <div class="text">
+                <h4 class="h4">{{item.productName}}</h4>
+                <div class="priceBox">
+                  <dl>
+                    <dt><img src="../../../static/images/vip/flag-vip.png" alt="会员价"></dt>
+                    <dd>
+                      ¥{{item.price}}
+                    </dd>
+                  </dl>
+                </div>
+              </div>
+            </div>
+          </swiper-slide>
+        </swiper>
+      </div>
+    </div>
+    <div v-else class="picList" >
+      <ul class="clearfix" :class="'imgTextNum' +  componentContent.productNum">
+        <li class="item" v-for="(item,index) in productData.slice(0, componentContent.productRowNum * componentContent.productNum)" :key="index">
+          <div class="a-link" @click="jumpProductDetail(item)">
+            <div class="itemImgBox">
+              <div class="imgBox">
+                <el-image
+                  :src="item.image"
+                  fit="contain"></el-image>
+              </div>
+            </div>
+            <div class="text">
+              <h4 class="h4">{{item.productName}}</h4>
+              <div class="priceBox">
+                <dl>
+                  <dt><img src="../../../static/images/vip/flag-vip.png" alt="会员价"></dt>
+                  <dd>
+                    ¥{{item.price}}
+                  </dd>
+                </dl>
+              </div>
+            </div>
+          </div>
+        </li>
+      </ul>
+    </div>
+    <button v-show="componentContent.showMore" class="btn-more" @click="jumpVip">查看全部 <span class="icon iconfont icon-arrow-right"></span></button>
+  </div>
+</template>
+
+<script>
+import {commonMixin} from '../mixin'
+  export default {
+    mixins: [commonMixin],
+    data () {
+      return {
+        swiperOption: {
+          slidesPerView: 4, // 显示数量
+          spaceBetween: 13, // 间隔
+          autoplay: false, // 可选选项,自动滑动
+          loop: true,
+          pagination: {
+            el: '.vip-pagination'
+          },
+          navigation: {
+            nextEl: '.swiper-button-next',
+            prevEl: '.swiper-button-prev'
+          }
+        }
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+  .product-list{
+    padding: 20px 0;
+    background-color: #fff;
+    .picListWarp{
+      width: 1380px;
+      max-width: 100%;
+      margin: 0 auto;
+      position: relative;
+    }
+    .picList{
+      width: 1200px;
+      max-width: 100%;
+      margin: 0 auto;
+      .swiper-button-prev,.swiper-button-next{
+        width: 50px;
+        height: 50px;
+        position: absolute;
+        cursor:pointer;
+        top: 140px;
+        background-repeat: no-repeat;
+        &:after{
+          content: '';
+        }
+      }
+      .swiper-button-prev{
+        left: 0;
+        background: url('../../../static/images/btn-prev.png');
+      }
+      .swiper-button-next{
+        right: 0;
+        background: url('../../../static/images/btn-next.png');
+      }
+      .a-link{
+        cursor: pointer;
+        &:hover{
+          box-shadow: 3px 4px 20px 0px rgba(186, 186, 186, 0.5);
+        }
+        .itemImgBox {
+          height: auto;
+          display: flex;
+          flex-direction: column;
+          justify-content: center;
+          .imgBox {
+            padding-bottom: 100%;
+            background-color: #cacaca;
+            position: relative;
+            .el-image {
+              width: 100%;
+              height: 100%;
+              position: absolute;
+              top: 0;
+              left: 0;
+            }
+          }
+        }
+        .text{
+          padding:25px 20px 17px;
+          text-align: center;
+          //height: 180px;
+          .h4{
+            font-size: 18px;
+            line-height: 24px;
+            overflow: hidden;
+            text-overflow:ellipsis;
+            white-space: nowrap;
+            color: #333333;
+            margin-bottom: 15px;
+            //max-height: 48px;
+          }
+          .p{
+            color: #999;
+            font-size: 16px;
+            overflow: hidden;
+            text-overflow:ellipsis;
+            white-space: nowrap;
+            padding-top: 18px;
+            position: relative;
+            margin-top: 8px;
+            &:after{
+              position: absolute;
+              top: 0;
+              left: 50%;
+              margin-left: -80px;
+              width: 160px;
+              height: 2px;
+              background: #F0F0F0;
+              content: '';
+            }
+          }
+          .priceBox {
+            dl {
+              display: inline-block;
+              min-width: 130px;
+              dt{
+                float: left;
+                img{
+                  display: block;
+                }
+              }
+              dd{
+                border: 1px solid #F3F4F5;
+                font-size: 25px;
+                line-height: 34px;
+                color: #C83732;
+                margin-left: 57px;
+                padding: 0 10px;
+              }
+            }
+          }
+        }
+      }
+      ul{
+        margin: -15px 0 0 -15px;
+        display: flex;
+        flex-wrap: wrap;
+        li{
+          flex: 0 0 50%;
+          padding: 15px 0 0 15px;
+          width: 0;
+        }
+      }
+      .imgTextNum2 {
+        li {
+          flex: 0 0 50%;
+        }
+      }
+      .imgTextNum3 {
+        li {
+          flex: 0 0 33.33%;
+        }
+      }
+      .imgTextNum4 {
+        li {
+          flex: 0 0 25%;
+        }
+      }
+      .imgTextNum5 {
+        li {
+          flex: 0 0 20%;
+        }
+      }
+    }
+  }
+  .btn-more {
+    width: 130px;
+    height: 41px;
+    border: 2px solid #C5AA7B;
+    color: #C5AA7B;
+    font-size: 18px;
+    background-color: transparent;
+    margin: 20px auto 0;
+    display: block;
+  }
+</style>

+ 109 - 0
canvas-container/components/canvasShow/canvasShowPage.vue

@@ -0,0 +1,109 @@
+<template>
+  <div class="layout hom-layout">
+      <div class="list-group-item" v-for="(item,index) in componentsData" :key="index">
+        <component :is="componentMap[terminal-1].get(item.type)" :componentContent="item.componentContent" :terminal="terminal" :typeId="typeId" :shopId="shopId"></component>
+      </div>
+  </div>
+</template>
+
+<script>
+  import componentMap from './componentMap'
+  import api from './config/api'
+  import {sendReqMixin} from './config/mixin'
+  export default {
+    name: 'canvasPage',
+    mixins: [sendReqMixin],
+    data () {
+      return {
+        // terminal: 4, // 画布设备 1 小程序,2 H5,3 App 4 电脑
+        // typeId: 3, // 画布类型 1 平台画布,2 自定义页面,3 商家店铺装修
+        // shopId: 0, // 店铺id
+        componentsData: [],
+        activeComponent: -1,
+        componentMap: componentMap
+      }
+    },
+    props: {
+      terminal: {
+        type: Number,
+        default: 4
+      },
+      typeId: {
+        type: Number,
+        default: 1
+      },
+      shopId: {
+        type: Number,
+        default: 0
+      }
+    },
+    mounted () {
+      // this.shopId = Cookies.get('shopID')
+      this.canvasGet()
+    },
+    methods: {
+      // 读取画布
+      canvasGet () {
+        var _this = this
+        var apiUrl = api.getCanvas + '?terminal=' + this.terminal + '&type=' + this.typeId
+        if (this.shopId) {
+          apiUrl += '&shopId=' + this.shopId
+        }
+        let params = {
+          url: apiUrl,
+          method: 'GET'
+        }
+        this.sendReq(params, (res) => {
+          if (JSON.stringify(res.data) !== '{}') {
+            _this.canvasId = res.data.canvasId
+            var componentsData = JSON.parse(res.data.json)
+            for (let i = 0; i < componentsData.length; i++) {
+              if (componentsData[i].type === 'shopHeader' && this.terminal === 4) {
+                if (componentsData[i].componentContent.category && componentsData[i].componentContent.category.length !== 0) {
+                  var categoryArr = componentsData[i].componentContent.category
+                  _this.sendReq({
+                    url: `${api.getClassify}`,
+                    method: 'GET'
+                  }, (proRes) => {
+                    componentsData[i].componentContent.category = proRes.data.filter((item) => {
+                      for (let i = 0; i < categoryArr.length; i++) {
+                        if (categoryArr[i].id === item.id) {
+                          return true
+                        }
+                      }
+                    })
+                  })
+                }
+              }
+            }
+            _this.componentsData = componentsData
+          } else {
+            _this.canvasId = ''
+          }
+          // console.log(JSON.parse(res.data.json))
+        })
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+  .hom-layout{
+    background-color: #f5f5f5;
+  }
+</style>
+
+<style lang="scss">
+  .warp{
+    width: 690px;
+    margin: 0 auto;
+    max-width: 100%;
+    &.terminal4{
+      width: 1200px;
+      max-width: 100%;
+    }
+  }
+  .flex-box{
+    display: flex;
+  }
+</style>

+ 102 - 0
canvas-container/components/canvasShow/componentMap.js

@@ -0,0 +1,102 @@
+export const componentMap = [
+  // 小程序
+  new Map([
+    ['header', () => import('./basics/header/app')], // 首页头部
+    ['banner', () => import('./basics/banner')], // 轮播图
+    ['text', () => import('./basics/text')], // 文本
+    ['imageText', () => import('./basics/imageText')], // 图文
+    ['brandList', () => import('./basics/brandList')], // 品牌列表
+    ['categoryList', () => import('./basics/categoryList')], // 品牌列表
+    ['imageTextList', () => import('./basics/imageTextList')], // 图文列表
+    ['assistDiv', () => import('./basics/assistDiv')], // 铺助分割
+    ['imageTextNav', () => import('./basics/imageTextNav')], // 图文导航
+    ['productList', () => import('./basics/product/app')], // 商品列表
+    ['videoBox', () => import('./basics/video')], // 视频
+    ['coupon', () => import('./basics/coupon/app')], // 优惠券
+    ['custom', () => import('./basics/custom')], // 自定义
+    ['notice', () => import('./basics/notice')], // 公告
+    ['vip', () => import('./basics/vip/app')], // 会员专区
+    ['groupList', () => import('./basics/group/app')], // 拼团专区
+    ['spikeList', () => import('./basics/spike/app')], // 秒杀专区
+    ['priceList', () => import('./basics/price/app')], // 定价捆绑
+    ['discountList', () => import('./basics/discount/app')], // 限时折扣
+    ['newProduct', () => import('./basics/newProduct/app')], // 每日上新
+    ['live', () => import('./basics/live/app')], // 直播
+    ['shop', () => import('./basics/shop')] // 每日好店
+  ]),
+  // H5
+  new Map([
+    ['header', () => import('./basics/header/app')], // 首页头部
+    ['banner', () => import('./basics/banner')], // 轮播图
+    ['text', () => import('./basics/text')], // 文本
+    ['imageText', () => import('./basics/imageText')], // 图文
+    ['brandList', () => import('./basics/brandList')], // 品牌列表
+    ['categoryList', () => import('./basics/categoryList')], // 品牌列表
+    ['imageTextList', () => import('./basics/imageTextList')], // 图文列表
+    ['assistDiv', () => import('./basics/assistDiv')], // 铺助分割
+    ['imageTextNav', () => import('./basics/imageTextNav')], // 图文导航
+    ['productList', () => import('./basics/product/app')], // 商品列表
+    ['videoBox', () => import('./basics/video')], // 视频
+    ['coupon', () => import('./basics/coupon/app')], // 优惠券
+    ['custom', () => import('./basics/custom')], // 自定义
+    ['notice', () => import('./basics/notice')], // 公告
+    ['vip', () => import('./basics/vip/app')], // 会员专区
+    ['groupList', () => import('./basics/group/app')], // 拼团专区
+    ['spikeList', () => import('./basics/spike/app')], // 秒杀专区
+    ['priceList', () => import('./basics/price/app')], // 定价捆绑
+    ['discountList', () => import('./basics/discount/app')], // 限时折扣
+    ['newProduct', () => import('./basics/newProduct/app')], // 每日上新
+    ['live', () => import('./basics/live/app')], // 直播
+    ['shop', () => import('./basics/shop')] // 每日好店
+  ]),
+  // APP
+  new Map([
+    ['header', () => import('./basics/header/app')], // 首页头部
+    ['banner', () => import('./basics/banner')], // 轮播图
+    ['text', () => import('./basics/text')], // 文本
+    ['imageText', () => import('./basics/imageText')], // 图文
+    ['brandList', () => import('./basics/brandList')], // 品牌列表
+    ['categoryList', () => import('./basics/categoryList')], // 品牌列表
+    ['imageTextList', () => import('./basics/imageTextList')], // 图文列表
+    ['assistDiv', () => import('./basics/assistDiv')], // 铺助分割
+    ['imageTextNav', () => import('./basics/imageTextNav')], // 图文导航
+    ['productList', () => import('./basics/product/app')], // 商品列表
+    ['videoBox', () => import('./basics/video')], // 视频
+    ['coupon', () => import('./basics/coupon/app')], // 优惠券
+    ['custom', () => import('./basics/custom')], // 自定义
+    ['notice', () => import('./basics/notice')], // 公告
+    ['vip', () => import('./basics/vip/app')], // 会员专区
+    ['groupList', () => import('./basics/group/app')], // 拼团专区
+    ['spikeList', () => import('./basics/spike/app')], // 秒杀专区
+    ['priceList', () => import('./basics/price/app')], // 定价捆绑
+    ['discountList', () => import('./basics/discount/app')], // 限时折扣
+    ['newProduct', () => import('./basics/newProduct/app')], // 每日上新
+    ['live', () => import('./basics/live/app')], // 直播
+    ['shop', () => import('./basics/shop')] // 每日好店
+  ]),
+  // PC
+  new Map([
+    ['header', () => import('./basics/header/pc')], // 首页头部
+    ['banner', () => import('./basics/banner')], // 轮播图
+    ['text', () => import('./basics/text')], // 文本
+    ['imageText', () => import('./basics/imageText')], // 图文
+    ['brandList', () => import('./basics/brandList')], // 品牌列表
+    ['categoryList', () => import('./basics/categoryList')], // 品牌列表
+    ['imageTextList', () => import('./basics/imageTextList')], // 图文列表
+    ['assistDiv', () => import('./basics/assistDiv')], // 铺助分割
+    ['imageTextNav', () => import('./basics/imageTextNav')], // 图文导航
+    ['productList', () => import('./basics/product/pc')], // 商品列表
+    ['videoBox', () => import('./basics/video')], // 视频
+    ['coupon', () => import('./basics/coupon/pc')], // 优惠券
+    ['custom', () => import('./basics/custom')], // 自定义
+    ['notice', () => import('./basics/notice')], // 公告
+    ['vip', () => import('./basics/vip/pc')], // 会员专区
+    ['groupList', () => import('./basics/group/pc')], // 拼团专区
+    ['spikeList', () => import('./basics/spike/pc')], // 秒杀专区
+    ['priceList', () => import('./basics/price/pc')], // 定价捆绑
+    ['discountList', () => import('./basics/discount/pc')], // 限时折扣
+    ['newProduct', () => import('./basics/newProduct/app')], // 每日上新
+    ['shop', () => import('./basics/shop')] // 每日好店
+  ])
+]
+export default componentMap

+ 31 - 0
canvas-container/components/canvasShow/config/api.js

@@ -0,0 +1,31 @@
+// 导入api接口模块
+
+// 获取当前环境变量 true => 生产环境 false => 开发环境
+const BASEURL = process.env.VUE_APP_DOMAIN_PREFIX
+// const BASEURL = (process.env.NODE_ENV === 'production') ? '/api' : '/api'
+
+export const api = {
+  // 画布模块
+  fileUpload: BASEURL + '/file/upload', // 文件上传
+  getClassify: BASEURL + '/canvas/getClassify', // 查询分类层级
+  getProducts: BASEURL + '/canvas/getProducts', // 选择商品查询
+  saveCanvas: BASEURL + '/canvas/saveCanvas', // 保存画布
+  getCanvas: BASEURL + '/canvas/getCanvas', // 读取画布
+  getShops: BASEURL + '/canvas/getShops', // 选择店铺查询
+  getCoupons: BASEURL + '/canvas/getCoupons', // 优惠券查询
+  getShopCoupons: BASEURL + '/canvas/getShopCoupons', // 优惠券查询
+  takeCoupon: BASEURL + '/coupon/takeCoupon', // 领取优惠券
+  selectCanvasCustomList: BASEURL + '/canvas/selectCanvasCustomList', // 自定义页面查询
+  getPlatformSeckills: `${BASEURL}/canvas/getPlatformSeckills`, // 平台秒杀活动
+  getSeckills: `${BASEURL}/renovation/getSeckills`, // 商家秒杀活动
+  getMinDiscount: `${BASEURL}/canvas/getMinDiscount`, // 平台限时折扣
+  getDiscounts: `${BASEURL}/renovation/getDiscounts`, // 商家限时折扣
+  getAdminGroupWorks: `${BASEURL}/canvas/getGroupWorks`, // 平台拼团专区
+  getGroupWorks: `${BASEURL}/renovation/getGroupWorks`, // 商家拼团专区
+  getPriceProducts: `${BASEURL}/canvas/getPriceProducts`, // 商家定价捆绑
+  getPrices: `${BASEURL}/canvas/getPrices`, // 商家定价捆绑
+  getMemberProducts: `${BASEURL}/canvas/getMemberProducts`, // 查询会员商品数据
+  getNotices: `${BASEURL}/canvas/getNotices`, // 平台获取公告数据
+  getNoticesAll: `${BASEURL}/notice/getAll`, // 平台获取公告数据
+}
+export default api

+ 12 - 0
canvas-container/components/canvasShow/config/config.js

@@ -0,0 +1,12 @@
+// 画布配置
+import Cookies from 'js-cookie'
+
+const config = {
+  terminal: 4, // 画布设备 1 小程序,2 H5,3 App 4 电脑
+  typeId: 1, // 页面类型 0 C端 1 平台画布,2 自定义页面,3 商家店铺装修
+  getToken: function(){
+    return Cookies.get('shopAdminToken')
+  }
+}
+
+export default config

+ 144 - 0
canvas-container/components/canvasShow/config/mixin/funMixin.js

@@ -0,0 +1,144 @@
+// import router from '@/router'
+import api from '../api'
+import {sendReq} from './sendReqMixin'
+import canvasConfig from '../config'
+
+/*
+ * 公共方法的 mixin
+ */
+export const tool = {
+  mixins: [sendReq],
+  props: {
+    isNoData: {
+      type: Boolean,
+      default: false
+    }
+  },
+  methods: {
+    //  请求数据前 请求完再显示所有组件
+    beforeGetData(){
+      if(typeof(uni) !== 'undefined'){
+        uni.getStorage({
+          key: 'sendNum',
+          success: function (res) {
+            let sendNum = res.data;
+            console.log('sendNum',parseInt(sendNum) + 1);
+            uni.setStorage({key: 'sendNum',data: parseInt(sendNum) + 1});
+            this.$emit('cleckLoading')
+          }
+        })
+      } else {
+        let sendNum = localStorage.getItem('sendNum')
+        console.log('sendNum',parseInt(sendNum) + 1);
+        localStorage.setItem('sendNum',parseInt(sendNum) + 1)
+        this.$emit('cleckLoading')
+      }
+    },
+    //  请求数据后
+    afterGetData(){
+      if(typeof(uni) !== 'undefined'){
+        uni.getStorage({
+          key: 'sendNum',
+          success: function (res) {
+            let sendNum = res.data;
+            console.log('sendNum',parseInt(sendNum) - 1);
+            uni.setStorage({key: 'sendNum',data: parseInt(sendNum) - 1});
+            this.$emit('cleckLoading')
+          }
+        })
+      } else {
+        let sendNum = localStorage.getItem('sendNum')
+        console.log('sendNum',parseInt(sendNum) - 1);
+        localStorage.setItem('sendNum',parseInt(sendNum) - 1)
+        this.$emit('cleckLoading')
+      }
+
+    },
+    // 判断url
+    jumpLink (linkObj) {
+      var link = ''
+      if(linkObj && linkObj.typeText && linkObj.data){
+        switch (linkObj.typeText) {
+          case '类别':
+            router.push({name:'category',query:{classifyData:JSON.stringify(linkObj.data)}})
+            break
+          case '店辅':
+            router.push({
+              path: '/store',
+              query: {shopId: linkObj.data.shopId}
+            });
+            break
+          case '商品':
+            this.setCurrentPro(linkObj.data)
+            router.push("/productDetail");
+            break
+          case '自定义':
+            // router.push("/category");
+            break
+        }
+      } else if(linkObj.selsectValue==='/index'){
+        router.push("/index");
+      }
+      return link
+    },
+    // 跳转到类别主页
+    jumpCategory(item){
+    },
+    // 跳转到店铺主页
+    jumpStore(item){
+
+    },
+    // 跳转到商品详情
+    jumpProductDetail(item){
+    },
+    // 跳转到秒杀专区
+    jumpSeckills(item){
+    },
+    // 跳转到拼团专区
+    jumpGroupWorks(item){
+    },
+    // 跳转到折扣专区
+    jumpDiscount(item){
+    },
+    // 跳转到会员专区
+    jumpVip(){
+    },
+    // 跳转到公告详情
+    jumpNoticeDetail(item){
+    },
+    // 领取优惠券
+    receiveCoupon(item) {
+      var key = canvasConfig.getToken()
+      if (key) {
+        var paramsData = {}
+        if(this.typeId === 1){
+          paramsData.couponId = item.couponId
+        } else if(this.typeId === 3) {
+          paramsData.shopCouponId = item.shopCouponId
+          paramsData.shopId = this.shopId
+        }
+        let params = {
+          url: api.takeCoupon,
+          method: 'POST',
+          data: paramsData
+        }
+        this.sendReq(params, (res) => {
+          this.$message({
+            message: '领取成功!',
+            type: 'success'
+          })
+          this.getData()
+        })
+      } else {
+        this.$message({
+          message: '请先登录'
+        })
+        this.$router.push({path: '/login'})
+      }
+    },
+    // 加入购物车
+    addCart(id){
+      console.log(id)
+    }
+  }
+}

+ 9 - 0
canvas-container/components/canvasShow/config/mixin/index.js

@@ -0,0 +1,9 @@
+/*
+ * 用于组件复用
+ * 参考链接 https://cn.vuejs.org/v2/guide/mixins.html#全局混合
+ * 混合 (mixins) 是一种分发 Vue 组件中可复用功能的非常灵活的方式。混合对象可以包含任意组件选项。以组件使用混合对象时,所有混合对象的选项将被混入该组件本身的选项。
+ */
+import { tool } from './funMixin.js'
+import { sendReq } from './sendReqMixin.js'
+export const funMixin = { ...tool }
+export const sendReqMixin = { ...sendReq }

+ 39 - 0
canvas-container/components/canvasShow/config/mixin/sendReqMixin.js

@@ -0,0 +1,39 @@
+/*
+ * 发送请求 mixin
+ */
+import request from './server'
+
+/* eslint-disable */
+export const sendReq = {
+  data () {
+    return {
+      // 加载中
+      loading: false,
+    }
+  },
+  methods: {
+    /*
+     * 发送请求
+     */
+    sendReq (params, callback, errorCallback) {
+      let self = this
+      request({
+        method: params.method || 'POST',
+        url: params.url,
+        data: params.data || {},
+        withCredentials : true,
+        headers: {
+          'Content-type': params.contentType || 'application/json;charset=utf-8'
+        }
+      }).then((res) => {
+        if (res && res.data) {
+          callback && callback(res.data)
+        }
+      }).catch(err => {
+        if (err) {
+          errorCallback && errorCallback(err)
+        }
+      })
+    }
+  }
+}

+ 105 - 0
canvas-container/components/canvasShow/config/mixin/server.js

@@ -0,0 +1,105 @@
+// 引入axios
+// import router from './../../router'
+import Vue from 'vue'
+// import promise from 'es6-promise'
+import axios from 'axios'
+import canvasConfig from '../config'
+// import Cookies from 'js-cookie'
+// import localStorage from '../storage/localStorage'
+// promise.polyfill()
+
+const service = axios.create({
+  headers: {
+    'X-Requested-With': 'XMLHttpRequest'
+  },
+  withCredentials: true,
+  timeout: 20000 // 请求超时 20s
+})
+
+// 请求拦截器
+service.interceptors.request.use(config => {
+  // 是否为当前的请求加上请求头 token
+  const token = canvasConfig.getToken()
+  if (token) {
+    if(canvasConfig.typeId === 1){
+      config.headers['Authorization-admin'] = token
+    } else if(canvasConfig.typeId === 3){
+      config.headers['Authorization-business'] = token
+    } else {
+      config.headers['Authorization'] = token
+    }
+  }
+  return config
+}, error => {
+  return Promise.reject(error)
+})
+
+// 响应拦截器
+service.interceptors.response.use(
+  (response) => {
+    if (response.data.code && response.data.code !=='200' && response.data.message) {
+      Vue.prototype.$message.error(response.data.message)
+    }
+    return response
+  },
+  err => {
+    // 失败响应
+    if (err && err.response) {
+      switch (err.response.status) {
+        case 400:
+          err.message = '请求无效,请检查参数是否正确!'
+          break
+
+        case 401:
+          err.message = '未经授权,访问被拒!'
+          break
+
+        case 403:
+          err.message = '拒绝访问!'
+          break
+
+        case 404:
+          err.message = `地址不存在!`
+          break
+
+        case 408:
+          err.message = '请求超时!'
+          break
+
+        case 500:
+          err.message = '系统错误!'
+          break
+
+        case 501:
+          err.message = '该方法未实现!'
+          break
+
+        case 502:
+          err.message = '网关出错!'
+          break
+
+        case 503:
+          err.message = '服务不可用!'
+          break
+
+        case 504:
+          err.message = '网关请求超时'
+          break
+
+        case 505:
+          err.message = 'HTTP版本不受支持'
+          break
+
+        default:
+      }
+      if (err.response.data.error) {
+        err.message = err.response.data.error
+      }
+      Vue.prototype.$message.closeAll()
+      Vue.prototype.$message.error(err.message)
+      // router.push({name: 'error', params: {message: err.message, status: err.response.status}})
+    }
+    return Promise.reject(err)
+  }
+)
+export default service

二进制
canvas-container/components/canvasShow/static/images/btn-next.png


二进制
canvas-container/components/canvasShow/static/images/btn-next2.png


二进制
canvas-container/components/canvasShow/static/images/btn-prev.png


二进制
canvas-container/components/canvasShow/static/images/btn-prev2.png


二进制
canvas-container/components/canvasShow/static/images/coupon/bg-coupon.png


二进制
canvas-container/components/canvasShow/static/images/coupon/bg-coupon2.png


二进制
canvas-container/components/canvasShow/static/images/coupon/border_L1.png


+ 0 - 0
canvas-container/components/canvasShow/static/images/coupon/border_L2.png


+ 0 - 0
canvas-container/components/canvasShow/static/images/coupon/border_L3.png


+ 0 - 0
canvas-container/components/canvasShow/static/images/coupon/border_L4.png


+ 0 - 0
canvas-container/components/canvasShow/static/images/coupon/border_R1.png


+ 0 - 0
canvas-container/components/canvasShow/static/images/coupon/border_R2.png


+ 0 - 0
canvas-container/components/canvasShow/static/images/coupon/border_R3.png


+ 0 - 0
canvas-container/components/canvasShow/static/images/coupon/border_R4.png


二进制
canvas-container/components/canvasShow/static/images/coupon/flag-coupon-r.png


二进制
canvas-container/components/canvasShow/static/images/coupon/flag-coupon.png


二进制
canvas-container/components/canvasShow/static/images/coupon/flag-coupon2-r.png


二进制
canvas-container/components/canvasShow/static/images/coupon/flag-coupon2.png


二进制
canvas-container/components/canvasShow/static/images/discount/bg-discount-more.png


二进制
canvas-container/components/canvasShow/static/images/discount/bg-discount-top-text.png


部分文件因为文件数量过多而无法显示