Переглянути джерело

【模版目录】更新管理段模版

吴昊天 2 роки тому
батько
коміт
5d8d903065
30 змінених файлів з 480 додано та 186 видалено
  1. 5 5
      template/admin/README.md
  2. 82 18
      template/admin/package-lock.json
  3. 2 1
      template/admin/package.json
  4. 87 0
      template/admin/src/api/export.js
  5. 8 4
      template/admin/src/components/customerInfo/index.vue
  6. 1 1
      template/admin/src/components/from/from.vue
  7. 1 1
      template/admin/src/components/sendCoupons/index.vue
  8. 2 0
      template/admin/src/main.js
  9. 2 3
      template/admin/src/pages/account/login/index.vue
  10. 30 14
      template/admin/src/pages/marketing/storeBargain/index.vue
  11. 29 12
      template/admin/src/pages/marketing/storeCombination/index.vue
  12. 9 8
      template/admin/src/pages/marketing/storeCouponIssue/create.vue
  13. 1 1
      template/admin/src/pages/marketing/storeCouponIssue/index.vue
  14. 29 12
      template/admin/src/pages/marketing/storeSeckill/index.vue
  15. 45 28
      template/admin/src/pages/order/orderList/components/tableFrom.vue
  16. 1 1
      template/admin/src/pages/order/orderList/components/tableList.vue
  17. 3 2
      template/admin/src/pages/product/productAdd/index.vue
  18. 32 18
      template/admin/src/pages/product/productList/index.vue
  19. 1 1
      template/admin/src/pages/setting/setApp/index.vue
  20. 2 1
      template/admin/src/pages/setting/setSystem/index.vue
  21. 3 15
      template/admin/src/pages/system/configTab/list.vue
  22. 20 13
      template/admin/src/pages/user/grade/card/index.vue
  23. 1 1
      template/admin/src/pages/user/grade/type/index.vue
  24. 1 0
      template/admin/src/pages/user/level/index.vue
  25. 0 5
      template/admin/src/pages/user/list/handle/userDetails.vue
  26. 2 2
      template/admin/src/pages/user/list/handle/userEdit.vue
  27. 69 16
      template/admin/src/pages/user/list/index.vue
  28. 0 2
      template/admin/src/router/modules/setting.js
  29. 7 0
      template/admin/src/styles/style.css
  30. 5 1
      template/admin/src/utils/modalForm.js

+ 5 - 5
template/admin/README.md

@@ -22,7 +22,7 @@ product 商品
 ├─ product 商品管理
 ├─ productList 商品管理目录
 ├─ index.vue  首页
-├─ components  组
+├─ components  组
 ├─ tableFrom.vue
 ├─ tableList.vue
 ├─ handle 操作功能页面目录
@@ -30,7 +30,7 @@ product 商品
 ├─ productCategory 商品分类目录
 ├─ index.vue 商品分类首页
 
-页面命名、组、文件夹 命名格式小驼峰命名法,例如:用户列表 userList
+页面命名、组、文件夹 命名格式小驼峰命名法,例如:用户列表 userList
 
 类名函数命名 大驼峰式 例如:addUser
 变量命名 小驼峰式 例如:user 或者 userInfo _userinfo user-info
@@ -39,13 +39,13 @@ product 商品
 ### 文件管理规范
 pages 页面模块必须件文件夹区分
 api 接口一个模块一个文件
-组件 一个组件一个文件夹
+组建 一个组建一个文件夹
 plugins 插件一个插件一个文件夹
 vuex 路由状态管理,一个模块在modules 中建一个文件夹
 router 一个模块一个模块在modules 中建一个文件夹
-style 样式尽量采用iView自带组,common.less 系统通用样式不要轻易动
+style 样式尽量采用iView自带组,common.less 系统通用样式不要轻易动
 自定义通用样式 style.less,每次添加必须加注释,页面独立样式在在页面内写,后缀less 格式
-组样式 styles 中添加文件夹 composents 对应components 目录新建样式文件
+组样式 styles 中添加文件夹 composents 对应components 目录新建样式文件
 utils 自定义工具js 独立命名,一般不用新建文件夹
 
 ## 模块命名

+ 82 - 18
template/admin/package-lock.json

@@ -2454,33 +2454,97 @@
         }
       }
     },
-    "@form-create/core": {
-      "version": "1.0.18",
-      "resolved": "https://registry.npmjs.org/@form-create/core/-/core-1.0.18.tgz",
-      "integrity": "sha512-DOHn9izm39M2B9BW1F7g/8wbOYlfLwpdHfoEHNl0qG2P78m7F8uO//TvbX9qO9byFuGTAST30LrAA1G8qPjQ5w==",
+    "@form-create/component-ivu-checkbox": {
+      "version": "2.5.27",
+      "resolved": "https://registry.npmmirror.com/@form-create/component-ivu-checkbox/-/component-ivu-checkbox-2.5.27.tgz",
+      "integrity": "sha512-E29BvKCR1Ozu8AHAozFI2i2psKwuAx6BPPdoRP8nzgzLEgJbBTumReJttJeU8PMid/G+thi6Tn6Iz7uk2nnztw==",
       "requires": {
-        "@form-create/utils": "^1.0.15",
-        "vue": "^2.6.10"
+        "@form-create/utils": "^2.5.27"
       }
     },
-    "@form-create/iview": {
-      "version": "1.0.18",
-      "resolved": "https://registry.npmjs.org/@form-create/iview/-/iview-1.0.18.tgz",
-      "integrity": "sha512-F+w7kziOIMh9nXrWP7sggxGYeD4hgcWYjnowRsDCkiMs29E1t4jZ18EdEknl07Iea6FVK3zhD2OuBbykchiK3g==",
+    "@form-create/component-ivu-frame": {
+      "version": "2.5.27",
+      "resolved": "https://registry.npmmirror.com/@form-create/component-ivu-frame/-/component-ivu-frame-2.5.27.tgz",
+      "integrity": "sha512-GBDHSGuiJhp0Oq278Y9Q9Z2xwdTMxiaSWgWhhUB/VEVqLBOSr8UVhBsRKydbhg2CGhlgDaWjpHwO6gQYiNHLdw==",
       "requires": {
-        "@form-create/core": "^1.0.18",
-        "@form-create/utils": "^1.0.15",
-        "iview": "^3.3.3"
+        "@form-create/utils": "^2.5.27"
       }
     },
-    "@form-create/utils": {
-      "version": "1.0.15",
-      "resolved": "https://registry.npmjs.org/@form-create/utils/-/utils-1.0.15.tgz",
-      "integrity": "sha512-IK1U3RcYEucgvt0bt51/xXdzdj1ShRfZJhXywjcUtIXVyZlD/jbRdXaGOn7q9Mvq+9MuqEKwtmtCvP8cb3Qlyw==",
+    "@form-create/component-ivu-group": {
+      "version": "2.5.27",
+      "resolved": "https://registry.npmmirror.com/@form-create/component-ivu-group/-/component-ivu-group-2.5.27.tgz",
+      "integrity": "sha512-UEo64Mqp6ahWht+4TLpbQMwD1THofDLcWZyzCEU1e/ANQFLA9YlI3hoydQ+Iyh4Wb4dgOSwLiRJmeNpcKKn4EA==",
       "requires": {
-        "vue": "^2.5.2"
+        "@form-create/utils": "^2.5.27"
       }
     },
+    "@form-create/component-ivu-radio": {
+      "version": "2.5.27",
+      "resolved": "https://registry.npmmirror.com/@form-create/component-ivu-radio/-/component-ivu-radio-2.5.27.tgz",
+      "integrity": "sha512-JWo8sbw4htg5aN6UxlCF3+abLclHjV5ar4N6qYDBmvFjI3gjKQxv7VN+g7S0TWvoS6ruI5/kUv1Xo3nt/Gx7Tg==",
+      "requires": {
+        "@form-create/utils": "^2.5.27"
+      }
+    },
+    "@form-create/component-ivu-select": {
+      "version": "2.5.27",
+      "resolved": "https://registry.npmmirror.com/@form-create/component-ivu-select/-/component-ivu-select-2.5.27.tgz",
+      "integrity": "sha512-bZjwUmVUnCjzeZPYRBdWROY2ldcVntbYlHgK3hnA1e2whTbtVPSbhLtFheqCFKCoxZKLidNRQMJfyzWvgaoS4w==",
+      "requires": {
+        "@form-create/utils": "^2.5.27"
+      }
+    },
+    "@form-create/component-ivu-tree": {
+      "version": "2.5.27",
+      "resolved": "https://registry.npmmirror.com/@form-create/component-ivu-tree/-/component-ivu-tree-2.5.27.tgz",
+      "integrity": "sha512-zraldTfO4QoJmxolovvSKqd0WQEYa7ZOU2+C8t93e4tN2rIHLnIFVJe4jz3ymgobOXLgyl17oHqZiW3C74k1Dw==",
+      "requires": {
+        "@form-create/utils": "^2.5.27"
+      }
+    },
+    "@form-create/component-ivu-upload": {
+      "version": "2.5.27",
+      "resolved": "https://registry.npmmirror.com/@form-create/component-ivu-upload/-/component-ivu-upload-2.5.27.tgz",
+      "integrity": "sha512-yiRXvanqSkIklUVbcsBcct2rBb6FgUZ0frCRIOxMHeuSz4/OVVz/OK3S+d0x+EBcRfAwJYxbsIwaC3ybl9b28A==",
+      "requires": {
+        "@form-create/utils": "^2.5.27"
+      }
+    },
+    "@form-create/component-subform": {
+      "version": "2.5.25",
+      "resolved": "https://registry.npmmirror.com/@form-create/component-subform/-/component-subform-2.5.25.tgz",
+      "integrity": "sha512-puGWWxSOeII4y4mCNxrKF/eH4nY1AQAx87VchzErLmemwF6TtNBLBsJLCCmFAVLYn1koYU5nNu5Y2yG9s2CKlQ=="
+    },
+    "@form-create/core": {
+      "version": "2.5.27",
+      "resolved": "https://registry.npmmirror.com/@form-create/core/-/core-2.5.27.tgz",
+      "integrity": "sha512-f2Lp1lW2YobviQbZzFspozQ5+7r2swx7l8ZiBjTj1X4OblGJBvRyg5tuFI2r/OlXr9+r9giDWXoKViPPdf1dIQ==",
+      "requires": {
+        "@form-create/utils": "^2.5.27"
+      }
+    },
+    "@form-create/iview": {
+      "version": "2.5.27",
+      "resolved": "https://registry.npmmirror.com/@form-create/iview/-/iview-2.5.27.tgz",
+      "integrity": "sha512-Yi3l84jPYIcYlZW5MGGQDJhDTdiEJW/ErYwrfoL1owr++cWEQlCpJmbh2toTowYR/gnGcdvA+TrYBEa4KTVLDA==",
+      "requires": {
+        "@form-create/component-ivu-checkbox": "^2.5.27",
+        "@form-create/component-ivu-frame": "^2.5.27",
+        "@form-create/component-ivu-group": "^2.5.27",
+        "@form-create/component-ivu-radio": "^2.5.27",
+        "@form-create/component-ivu-select": "^2.5.27",
+        "@form-create/component-ivu-tree": "^2.5.27",
+        "@form-create/component-ivu-upload": "^2.5.27",
+        "@form-create/component-subform": "^2.5.25",
+        "@form-create/core": "^2.5.27",
+        "@form-create/utils": "^2.5.27"
+      }
+    },
+    "@form-create/utils": {
+      "version": "2.5.27",
+      "resolved": "https://registry.npmmirror.com/@form-create/utils/-/utils-2.5.27.tgz",
+      "integrity": "sha512-QLzenitKzakxQ8bK8yFYd/9n4eT4E9jKkEneU0yhbjr0ter5uqguGGNJP7gI8waysRAS49VSjQOAY0b4l7mWvg=="
+    },
     "@gar/promisify": {
       "version": "1.1.3",
       "resolved": "https://registry.npmmirror.com/@gar/promisify/-/promisify-1.1.3.tgz",

+ 2 - 1
template/admin/package.json

@@ -5,6 +5,7 @@
   "private": false,
   "scripts": {
     "serve": "vue-cli-service serve --open --mode=dev",
+    "dev": "vue-cli-service serve --open --mode=dev",
     "build": "vue-cli-service build --mode=production",
     "eslint:comment": "使用 ESLint 检查并自动修复 src 目录下所有扩展名为 .js 和 .vue 的文件",
     "eslint": "eslint --ext .js,.vue,.ts --ignore-path .gitignore --fix src",
@@ -15,7 +16,7 @@
     "@babel/polyfill": "^7.8.7",
     "@babel/runtime": "^7.2.0",
     "@better-scroll/core": "^2.0.5",
-    "@form-create/iview": "^1.0.18",
+    "@form-create/iview": "^2.5.27",
     "async-validator": "^3.4.0",
     "awe-dnd": "^0.3.4",
     "better-scroll": "^1.15.2",

+ 87 - 0
template/admin/src/api/export.js

@@ -0,0 +1,87 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import request from '@/libs/request';
+
+/**
+ * 用户列表导出
+ */
+export function exportUserList(data) {
+  return request({
+    url: '/export/user_list',
+    method: 'get',
+    params: data,
+  });
+}
+
+/**
+ * 订单列表导出
+ */
+export function exportOrderList(data) {
+  return request({
+    url: '/export/order_list',
+    method: 'get',
+    params: data,
+  });
+}
+
+/**
+ * 商品列表导出
+ */
+export function exportProductList(data) {
+  return request({
+    url: '/export/product_list',
+    method: 'get',
+    params: data,
+  });
+}
+
+/**
+ * 砍价列表导出
+ */
+export function exportBargainList(data) {
+  return request({
+    url: '/export/bargain_list',
+    method: 'get',
+    params: data,
+  });
+}
+
+/**
+ * 拼团列表导出
+ */
+export function exportCombinationList(data) {
+  return request({
+    url: '/export/combination_list',
+    method: 'get',
+    params: data,
+  });
+}
+
+/**
+ * 秒杀列表导出
+ */
+export function exportSeckillList(data) {
+  return request({
+    url: '/export/seckill_list',
+    method: 'get',
+    params: data,
+  });
+}
+
+/**
+ * 会员卡导出
+ */
+export function exportmberCardList(id) {
+  return request({
+    url: `/export/member_card/${id}`,
+    method: 'get',
+  });
+}

+ 8 - 4
template/admin/src/components/customerInfo/index.vue

@@ -58,17 +58,21 @@
       </template>
       <template slot-scope="{ row, index }" slot="user_type">
         <span v-if="row.user_type === 'wechat'">公众号</span>
-        <span v-if="row.user_type === 'routine'">小程序</span>
-        <span v-if="row.user_type === 'h5'">H5</span>
-        <span v-if="row.user_type === 'pc'">PC</span>
+        <span v-else-if="row.user_type === 'routine'">小程序</span>
+        <span v-else-if="row.user_type === 'h5'">H5</span>
+        <span v-else-if="row.user_type === 'pc'">PC</span>
+        <span v-else>--</span>
+
       </template>
       <template slot-scope="{ row, index }" slot="sex">
         <span v-show="row.sex === 1">男</span>
         <span v-show="row.sex === 2">女</span>
         <span v-show="row.sex === 0">保密</span>
+        <span v-show="row.sex === null">--</span>
       </template>
       <template slot-scope="{ row, index }" slot="country">
-        <span>{{ row.country + row.province + row.city }}</span>
+        <span v-if="row.country || row.province || row.city">{{ row.country + row.province + row.city }}</span>
+        <span v-else>--</span>
       </template>
       <template slot-scope="{ row, index }" slot="subscribe">
         <span v-text="row.subscribe === 1 ? '关注' : '未关注'"></span>

+ 1 - 1
template/admin/src/components/from/from.vue

@@ -23,7 +23,7 @@
       <form-create
         :option="config"
         :rule="Array.from(FromData.rules)"
-        @on-submit="onSubmit"
+        @submit="onSubmit"
         class="formBox"
         ref="fc"
         handleIcon="false"

+ 1 - 1
template/admin/src/components/sendCoupons/index.vue

@@ -13,7 +13,7 @@
       <div class="acea-row">
         <span class="sp">优惠券名称:</span
         ><Input
-          v-model="page.title"
+          v-model="page.coupon_title"
           search
           enter-button
           placeholder="请输入优惠券名称"

+ 2 - 0
template/admin/src/main.js

@@ -55,6 +55,7 @@ import Viewer from 'v-viewer';
 import VueDND from 'awe-dnd';
 import formCreate from '@form-create/iview';
 import modalForm from '@/utils/modalForm';
+import exportExcel from '@/utils/newToExcel.js'
 import videoCloud from '@/utils/videoCloud';
 import { modalSure } from '@/utils/public';
 import { authLapse } from '@/utils/authLapse';
@@ -93,6 +94,7 @@ if (process.env.NODE_ENV !== 'production') require('@/mock');
 window.Promise = Promise;
 Vue.prototype.$modalForm = modalForm;
 Vue.prototype.$modalSure = modalSure;
+Vue.prototype.$exportExcel = exportExcel;
 Vue.prototype.$videoCloud = videoCloud;
 Vue.prototype.$authLapse = authLapse;
 Vue.prototype.$wechat = Auth;

+ 2 - 3
template/admin/src/pages/account/login/index.vue

@@ -73,7 +73,6 @@ import { getWorkermanUrl } from '@/api/kefu';
 import { setCookies } from '@/libs/util';
 import '@/assets/js/canvas-nest.min';
 import Verify from '@/components/verifition/Verify';
-
 export default {
   components: {
     Verify,
@@ -243,10 +242,10 @@ export default {
           return this.$router.replace({ path: '/admin/home/' || '/admin/' });
         })
         .catch((res) => {
-          msg();
+          msg()
           let data = res === undefined ? {} : res;
-          this.login_captcha = res.data.login_captcha;
           this.$Message.error(data.msg || '登录失败');
+          this.login_captcha = res.data.login_captcha;
         });
       setTimeout((e) => {
         this.loading = false;

+ 30 - 14
template/admin/src/pages/marketing/storeBargain/index.vue

@@ -34,7 +34,7 @@
             <Button v-auth="['marketing-store_bargain-create']" type="primary" icon="md-add" @click="add" class="mr10"
               >添加砍价商品</Button
             >
-            <Button v-auth="['export-storeBargain']" class="export" icon="ios-share-outline" @click="exports"
+            <Button v-auth="['export-storeBargain']" class="export" icon="ios-share-outline" @click="exportList"
               >导出</Button
             >
           </Col>
@@ -110,6 +110,7 @@
 import { mapState } from 'vuex';
 import { bargainListApi, bargainSetStatusApi, stroeBargainApi } from '@/api/marketing';
 import { formatDate } from '@/utils/validate';
+import { exportBargainList } from '@/api/export';
 export default {
   name: 'storeBargain',
   filters: {
@@ -207,7 +208,6 @@ export default {
       tableFrom: {
         status: '',
         store_name: '',
-        export: 0,
         page: 1,
         limit: 15,
       },
@@ -237,19 +237,35 @@ export default {
       this.$router.push({ path: '/admin/marketing/store_bargain/create/0' });
     },
     // 导出
-    exports() {
-      let formValidate = this.tableFrom;
-      let data = {
-        status: formValidate.status,
-        store_name: formValidate.store_name,
-      };
-      stroeBargainApi(data)
-        .then((res) => {
-          location.href = res.data[0];
-        })
-        .catch((res) => {
-          this.$Message.error(res.msg);
+    // 用户导出
+    async exportList() {
+      this.tableFrom.status = this.tableFrom.status || '';
+      let [th, filekey, data, fileName] = [[], [], [], ''];
+      let excelData = JSON.parse(JSON.stringify(this.tableFrom));
+      excelData.page = 1;
+      excelData.limit = 50;
+      for (let i = 0; i < excelData.page + 1; i++) {
+        let lebData = await this.getExcelData(excelData);
+        if (!fileName) fileName = lebData.filename;
+        if (!filekey.length) {
+          filekey = lebData.fileKey;
+        }
+        if (!th.length) th = lebData.header;
+        if (lebData.export.length) {
+          data = data.concat(lebData.export);
+          excelData.page++;
+        } else {
+          this.$exportExcel(th, filekey, fileName, data);
+          return;
+        }
+      }
+    },
+    getExcelData(excelData) {
+      return new Promise((resolve, reject) => {
+        exportBargainList(excelData).then((res) => {
+          resolve(res.data);
         });
+      });
     },
     // 编辑
     edit(row) {

+ 29 - 12
template/admin/src/pages/marketing/storeCombination/index.vue

@@ -116,6 +116,8 @@
 import { combinationListApi, combinationSetStatusApi, storeCombinationApi } from '@/api/marketing';
 import { mapState } from 'vuex';
 import { formatDate } from '@/utils/validate';
+import { exportCombinationList } from '@/api/export.js';
+
 export default {
   name: 'index',
   filters: {
@@ -256,20 +258,35 @@ export default {
   },
   methods: {
     // 导出
-    exports() {
-      let formValidate = this.formValidate;
-      let data = {
-        is_show: formValidate.is_show,
-        store_name: formValidate.store_name,
-      };
-      storeCombinationApi(data)
-        .then((res) => {
-          location.href = res.data[0];
-        })
-        .catch((res) => {
-          this.$Message.error(res.msg);
+    async exports() {
+      let [th, filekey, data, fileName] = [[], [], [], ''];
+      let excelData = JSON.parse(JSON.stringify(this.formValidate));
+      excelData.page = 1;
+      excelData.limit = 200;
+      for (let i = 0; i < excelData.page + 1; i++) {
+        let lebData = await this.getExcelData(excelData);
+        if (!fileName) fileName = lebData.filename;
+        if (!filekey.length) {
+          filekey = lebData.fileKey;
+        }
+        if (!th.length) th = lebData.header;
+        if (lebData.export.length) {
+          data = data.concat(lebData.export);
+          excelData.page++;
+        } else {
+          this.$exportExcel(th, filekey, fileName, data);
+          return;
+        }
+      }
+    },
+    getExcelData(excelData) {
+      return new Promise((resolve, reject) => {
+        exportCombinationList(excelData).then((res) => {
+          resolve(res.data);
         });
+      });
     },
+
     // 添加
     add() {
       this.$router.push({ path: '/admin/marketing/store_combination/create' });

+ 9 - 8
template/admin/src/pages/marketing/storeCouponIssue/create.vue

@@ -16,7 +16,7 @@
     <Card :bordered="false" dis-hover class="ivu-mt">
       <Form :model="formData" :label-width="150">
         <FormItem label="优惠券名称">
-          <Input v-model="formData.coupon_title" placeholder="请输入优惠券名称"></Input>
+          <Input v-model="formData.coupon_title" :maxlength="18" placeholder="请输入优惠券名称"></Input>
         </FormItem>
         <FormItem label="发送方式">
           <RadioGroup v-model="formData.receive_type">
@@ -51,7 +51,7 @@
           <div class="info">选择商品的品类</div>
         </FormItem>
         <FormItem label="优惠券面值">
-          <InputNumber :min="1" :max="100000000" v-model="formData.coupon_price"></InputNumber>
+          <InputNumber :min="1" :max="99999" v-model="formData.coupon_price"></InputNumber>
         </FormItem>
         <FormItem label="使用门槛">
           <RadioGroup v-model="isMinPrice">
@@ -60,7 +60,7 @@
           </RadioGroup>
         </FormItem>
         <FormItem v-if="isMinPrice">
-          <InputNumber :min="1" :max="100000000" v-model="formData.use_min_price"></InputNumber>
+          <InputNumber :min="1" :max="99999" v-model="formData.use_min_price"></InputNumber>
           <div class="info">填写优惠券的最低消费金额</div>
         </FormItem>
         <FormItem label="使用时间">
@@ -107,11 +107,11 @@
           label=""
           v-if="formData.receive_type != 2 && formData.receive_type != 3"
         >
-          <InputNumber :min="1" :max="100000000" v-model="formData.total_count" :precision="0"></InputNumber>
+          <InputNumber :min="1" :max="99999" v-model="formData.total_count" :precision="0"></InputNumber>
           <div class="info">填写优惠券的发布数量</div>
         </FormItem>
         <FormItem label="用户领取数量" v-if="formData.receive_type != 2 && formData.receive_type != 3">
-          <InputNumber :min="1" :max="100000000" v-model="formData.receive_limit" :precision="0"></InputNumber>
+          <InputNumber :min="1" :max="99999" v-model="formData.receive_limit" :precision="0"></InputNumber>
           <div class="info">填写每个用户可以领取多少张</div>
         </FormItem>
         <!--                <FormItem label="排序">-->
@@ -328,19 +328,20 @@ export default {
       } else if (this.formData.type == 2) {
         this.formData.category_id = '';
       }
-
-      this.disabled = false;
+      if (this.disabled) return;
+      this.disabled = true;
       couponSaveApi(this.formData)
         .then((res) => {
-          this.disabled = true;
           this.$Message.success(res.msg);
           setTimeout(() => {
+            this.disabled = false;
             this.$router.push({
               path: '/admin/marketing/store_coupon_issue/index',
             });
           }, 1000);
         })
         .catch((err) => {
+          this.disabled = false;
           this.$Message.error(err.msg);
         });
     },

+ 1 - 1
template/admin/src/pages/marketing/storeCouponIssue/index.vue

@@ -252,7 +252,7 @@ export default {
         coupon_title: '',
         receive_type: '',
         page: 1,
-        limit: 15,
+        limit: 10,
       },
       receive_type: '',
       tableList: [],

+ 29 - 12
template/admin/src/pages/marketing/storeSeckill/index.vue

@@ -97,6 +97,8 @@
 import { mapState } from 'vuex';
 import { seckillListApi, seckillStatusApi, storeSeckillApi } from '@/api/marketing';
 import { formatDate } from '@/utils/validate';
+import { exportSeckillList } from '@/api/export.js';
+
 export default {
   name: 'storeSeckill',
   filters: {
@@ -208,20 +210,35 @@ export default {
       this.$router.push({ path: '/admin/marketing/store_seckill/create' });
     },
     // 导出
-    exports() {
-      let formValidate = this.tableFrom;
-      let data = {
-        status: formValidate.status,
-        store_name: formValidate.store_name,
-      };
-      storeSeckillApi(data)
-        .then((res) => {
-          location.href = res.data[0];
-        })
-        .catch((res) => {
-          this.$Message.error(res.msg);
+    async exports() {
+      let [th, filekey, data, fileName] = [[], [], [], ''];
+      let excelData = JSON.parse(JSON.stringify(this.tableFrom));
+      excelData.page = 1;
+      excelData.limit = 200;
+      for (let i = 0; i < excelData.page + 1; i++) {
+        let lebData = await this.getExcelData(excelData);
+        if (!fileName) fileName = lebData.filename;
+        if (!filekey.length) {
+          filekey = lebData.fileKey;
+        }
+        if (!th.length) th = lebData.header;
+        if (lebData.export.length) {
+          data = data.concat(lebData.export);
+          excelData.page++;
+        } else {
+          this.$exportExcel(th, filekey, fileName, data);
+          return;
+        }
+      }
+    },
+    getExcelData(excelData) {
+      return new Promise((resolve, reject) => {
+        exportSeckillList(excelData).then((res) => {
+          resolve(res.data);
         });
+      });
     },
+
     // 编辑
     edit(row) {
       this.$router.push({

+ 45 - 28
template/admin/src/pages/order/orderList/components/tableFrom.vue

@@ -84,7 +84,7 @@
               <Icon type="md-list"></Icon>
               订单核销
             </Button>
-            <Button v-auth="['export-storeOrder']" class="export" icon="ios-share-outline" @click="exports"
+            <Button v-auth="['export-storeOrder']" class="export" icon="ios-share-outline" @click="exportList"
               >导出</Button
             >
           </div>
@@ -92,7 +92,14 @@
       </Row>
     </Form>
     <!--订单核销模态框-->
-    <Modal v-model="modals2" title="订单核销" class="paymentFooter" scrollable width="400">
+    <Modal
+      v-model="modals2"
+      title="订单核销"
+      class="paymentFooter"
+      :closable="false"
+      width="400"
+      @on-visible-change="changeModal"
+    >
       <Form
         ref="writeOffFrom"
         :model="writeOffFrom"
@@ -102,16 +109,7 @@
         @submit.native.prevent
       >
         <FormItem prop="code" label-for="code">
-          <Input
-            search
-            enter-button="验证"
-            style="width: 100%"
-            type="text"
-            placeholder="请输入12位核销码"
-            @on-search="search('writeOffFrom')"
-            v-model.number="writeOffFrom.code"
-            number
-          />
+          <Input style="width: 100%" type="text" placeholder="请输入12位核销码" v-model.number="writeOffFrom.code" />
         </FormItem>
       </Form>
       <div slot="footer">
@@ -125,6 +123,7 @@
 <script>
 import { mapState, mapMutations } from 'vuex';
 import { putWrite, storeOrderApi } from '@/api/order';
+import { exportOrderList } from '@/api/export';
 export default {
   name: 'table_from',
   data() {
@@ -173,6 +172,7 @@ export default {
         real_name: '',
         field_key: 'all',
         pay_type: '',
+        type: '',
       },
       modalTitleSs: '',
       statusType: '',
@@ -264,7 +264,8 @@ export default {
     };
   },
   computed: {
-    ...mapState('order', ['orderChartType', 'isDels', 'delIdList']),
+    ...mapState('order', ['orderChartType', 'isDels', 'delIdList', 'orderType']),
+
     today() {
       const end = new Date();
       const start = new Date();
@@ -294,23 +295,38 @@ export default {
       this.getOrderStatus(this.orderData.status);
       this.$emit('getList', 1);
     },
+    changeModal(status) {
+      if (!status) this.writeOffFrom.code = '';
+    },
     // 导出
-    exports() {
-      let formValidate = this.orderData;
-      let id = this.delIdList;
-      let data = {
-        status: formValidate.status,
-        data: formValidate.data,
-        real_name: formValidate.real_name,
-        ids: id.join(),
-      };
-      storeOrderApi(data)
-        .then((res) => {
-          location.href = res.data[0];
-        })
-        .catch((res) => {
-          this.$Message.error(res.msg);
+    async exportList() {
+      this.orderData.type = this.orderType === 0 ? '' : this.orderType;
+      let [th, filekey, data, fileName] = [[], [], [], ''];
+      let excelData = JSON.parse(JSON.stringify(this.orderData));
+      excelData.page = 1;
+      excelData.limit = 200;
+      for (let i = 0; i < excelData.page + 1; i++) {
+        let lebData = await this.getExcelData(excelData);
+        if (!fileName) fileName = lebData.filename;
+        if (!filekey.length) {
+          filekey = lebData.fileKey;
+        }
+        if (!th.length) th = lebData.header;
+        if (lebData.export.length) {
+          data = data.concat(lebData.export);
+          excelData.page++;
+        } else {
+          this.$exportExcel(th, filekey, fileName, data);
+          return;
+        }
+      }
+    },
+    getExcelData(excelData) {
+      return new Promise((resolve, reject) => {
+        exportOrderList(excelData).then((res) => {
+          resolve(res.data);
         });
+      });
     },
     // 具体日期
     onchangeTime(e) {
@@ -437,6 +453,7 @@ export default {
     },
     del(name) {
       this.modals2 = false;
+      this.writeOffFrom.code = '';
       this.$refs[name].resetFields();
     },
     handleSubmit() {

+ 1 - 1
template/admin/src/pages/order/orderList/components/tableList.vue

@@ -262,7 +262,7 @@ export default {
           width: 100,
         },
         {
-          title: '支付状态',
+          title: '支付方式',
           key: 'pay_type_name',
           width: 80,
         },

+ 3 - 2
template/admin/src/pages/product/productAdd/index.vue

@@ -1135,7 +1135,8 @@
                   <Input
                     v-model.trim="item.title"
                     :placeholder="'留言标题' + (index + 1)"
-                    style="width: 100px; margin-right: 10px"
+                    style="width: 150px; margin-right: 10px"
+                    :maxlength="10"
                   />
                   <Select v-model="item.label" style="width: 200px; margin-left: 6px; margin-right: 10px">
                     <Option v-for="items in CustomList" :value="items.value" :key="items.value">{{
@@ -1374,7 +1375,7 @@ export default {
       virtual: [
         { tit: '普通商品', id: 0, tit2: '物流发货' },
         { tit: '卡密/网盘', id: 1, tit2: '自动发货' },
-        { tit: '优惠', id: 2, tit2: '自动发货' },
+        { tit: '优惠', id: 2, tit2: '自动发货' },
         { tit: '虚拟商品', id: 3, tit2: '虚拟发货' },
       ],
       seletVideo: 0, //选择视频类型

+ 32 - 18
template/admin/src/pages/product/productList/index.vue

@@ -270,6 +270,7 @@ import { mapState } from 'vuex';
 import taoBao from './taoBao';
 import goodsDetail from './components/goodsDetail.vue';
 import couponList from '@/components/couponList';
+import { exportProductList } from '@/api/export';
 
 import {
   getGoodHeade,
@@ -324,8 +325,7 @@ export default {
         limit: 15,
         cate_id: '',
         type: '1',
-        store_name: '',
-        excel: 0,
+        store_name: ''
       },
       list: [],
       tableList: [],
@@ -556,20 +556,33 @@ export default {
       this.getDataList();
     },
     // 导出
-    exports() {
-      let formValidate = this.artFrom;
-      let data = {
-        cate_id: formValidate.cate_id,
-        type: formValidate.type,
-        store_name: formValidate.store_name,
-      };
-      storeProductApi(data)
-        .then((res) => {
-          location.href = res.data[0];
-        })
-        .catch((res) => {
-          this.$Message.error(res.msg);
+    async exports() {
+      let [th, filekey, data, fileName] = [[], [], [], ''];
+      let excelData = JSON.parse(JSON.stringify(this.artFrom));
+      excelData.page = 1;
+      excelData.limit = 50;
+      for (let i = 0; i < excelData.page + 1; i++) {
+        let lebData = await this.getExcelData(excelData);
+        if (!fileName) fileName = lebData.filename;
+        if (!filekey.length) {
+          filekey = lebData.fileKey;
+        }
+        if (!th.length) th = lebData.header;
+        if (lebData.export.length) {
+          data = data.concat(lebData.export);
+          excelData.page++;
+        } else {
+          this.$exportExcel(th, filekey, fileName, data);
+          return;
+        }
+      }
+    },
+    getExcelData(excelData) {
+      return new Promise((resolve, reject) => {
+        exportProductList(excelData).then((res) => {
+          resolve(res.data);
         });
+      });
     },
     changeTemplate(e) {
       // this.template = e;
@@ -849,13 +862,14 @@ export default {
     overflow: auto;
   }
 }
-.batch-box{
-   >>> .ivu-modal-body {
+
+.batch-box {
+  >>> .ivu-modal-body {
     overflow: auto;
     min-height: 350px;
-
   }
 }
+
 .tabBox_img {
   width: 36px;
   height: 36px;

+ 1 - 1
template/admin/src/pages/setting/setApp/index.vue

@@ -12,7 +12,7 @@
       </div>
     </div>
     <Card :bordered="false" dis-hover class="ivu-mt" v-if="currentTab === 'onsale'">
-      <!--<form-create  :rule="Array.from(FromData.rules)" @on-submit="onSubmit" ></form-create>-->
+      <!--<form-create  :rule="Array.from(FromData.rules)" @submit="onSubmit" ></form-create>-->
     </Card>
   </div>
 </template>

+ 2 - 1
template/admin/src/pages/setting/setSystem/index.vue

@@ -18,7 +18,7 @@
           :key="index"
         ></TabPane>
       </Tabs>
-      <form-create :option="option" :rule="rules" @on-submit="onSubmit" v-if="rules.length !== 0"></form-create>
+      <form-create :option="option" :rule="rules" @submit="onSubmit" v-if="rules.length !== 0"></form-create>
       <Spin size="large" fix v-if="spinShow"></Spin>
     </Card>
   </div>
@@ -177,6 +177,7 @@ export default {
       if (this.$route.query.from === 'download') {
         await this.getHeader(2);
       } else if (this.$route.params.type !== '3') {
+        this.childrenId = '';
         await this.getHeader();
       } else {
         this.headerList = [];

+ 3 - 15
template/admin/src/pages/system/configTab/list.vue

@@ -31,32 +31,20 @@
             >{{ row.value }}</span
           >
           <div class="valBox acea-row" v-if="row.type === 'upload' && row.upload_type === 3">
-            <div v-if="row.value instanceof Array">
+            <div v-if="row.value.length">
               <div class="valPicbox acea-row row-column-around" v-for="(item, index) in row.value" :key="index">
                 <div class="valPicbox_pic"><Icon type="md-document" /></div>
                 <span class="valPicbox_sp">{{ item.filename }}</span>
               </div>
             </div>
-            <!--                        <div v-else>-->
-            <!--                            <div class="valPicbox acea-row row-column-around">-->
-            <!--                                <div class="valPicbox_pic"><Icon type="md-document" /></div>-->
-            <!--                                <span class="valPicbox_sp">{{row.filename}}</span>-->
-            <!--                            </div>-->
-            <!--                        </div>-->
           </div>
           <div class="valBox acea-row" v-if="row.type === 'upload' && row.upload_type !== 3">
-            <div v-if="row.value instanceof Array">
+            <div v-if="row.value.length">
               <div class="valPicbox acea-row row-column-around" v-for="(item, index) in row.value" :key="index">
                 <div class="valPicbox_pic"><img v-lazy="item.filepath" /></div>
                 <span class="valPicbox_sp">{{ item.filename }}</span>
               </div>
             </div>
-            <!--                        <div v-else>-->
-            <!--                            <div class="valPicbox acea-row row-column-around">-->
-            <!--                                <div class="valPicbox_pic"><img :src="row.filepath ? row.filepath : require('../../../assets/images/moren.jpg')"></div>-->
-            <!--                                <span class="valPicbox_sp">{{row.filename}}</span>-->
-            <!--                            </div>-->
-            <!--                        </div>-->
           </div>
         </template>
         <template slot-scope="{ row, index }" slot="statuss">
@@ -106,7 +94,7 @@
       <form-create
         v-if="rules.length != 0"
         :rule="rules"
-        @on-submit="onSubmit"
+        @submit="onSubmit"
         class="formBox"
         ref="fc"
         handleIcon="false"

+ 20 - 13
template/admin/src/pages/user/grade/card/index.vue

@@ -72,7 +72,7 @@
       </div>
     </Card>
     <Modal v-model="modal" title="添加批次" footer-hide>
-      <form-create v-model="fapi" :rule="rule" @on-submit="onSubmit"></form-create>
+      <form-create v-model="fapi" :rule="rule" @submit="onSubmit"></form-create>
     </Modal>
     <Modal v-model="cardModal" title="卡列表" footer-hide width="1000">
       <cardList v-if="cardModal" :id="id"></cardList>
@@ -104,6 +104,7 @@
 import { mapState } from 'vuex';
 import cardList from './list.vue';
 import { userMemberBatch, memberBatchSave, memberBatchSetValue, exportMemberCard, userMemberScan } from '@/api/user';
+import { exportmberCardList } from '@/api/export.js';
 
 export default {
   name: 'index',
@@ -316,18 +317,24 @@ export default {
           this.$Message.error(err.msg);
         });
     },
-    // 查看
-    exportExcel(row) {
-      this.$Spin.show();
-      exportMemberCard(row.id)
-        .then((res) => {
-          this.$Spin.hide();
-          location.href = res.data[0];
-        })
-        .catch((err) => {
-          this.$Spin.hide();
-          this.$Message.error(err.msg);
+    // 导出
+    async export(row) {
+      let [th, filekey, data, fileName] = [[], [], [], ''];
+      let lebData = await this.getExcelData(row.id);
+      if (!fileName) fileName = lebData.filename;
+      if (!filekey.length) {
+        filekey = lebData.fileKey;
+      }
+      if (!th.length) th = lebData.header;
+      data = data.concat(lebData.export);
+      this.$exportExcel(th, filekey, fileName, data);
+    },
+    getExcelData(excelData) {
+      return new Promise((resolve, reject) => {
+        exportmberCardList(excelData).then((res) => {
+          resolve(res.data);
         });
+      });
     },
     // 更多
     changeMenu(row, name) {
@@ -342,7 +349,7 @@ export default {
           this.cardModal = true;
           break;
         case '3':
-          this.exportExcel(row);
+          this.export(row);
           break;
       }
     },

+ 1 - 1
template/admin/src/pages/user/grade/type/index.vue

@@ -34,7 +34,7 @@
       </Table>
     </Card>
     <Modal v-model="modal" :title="`${rowModelType}${rowEdit && rowEdit.title}会员`" footer-hide @on-cancel="cancel">
-      <form-create v-model="fapi" :rule="rule" @on-submit="onSubmit"></form-create>
+      <form-create v-model="fapi" :rule="rule" @submit="onSubmit"></form-create>
     </Modal>
   </div>
 </template>

+ 1 - 0
template/admin/src/pages/user/level/index.vue

@@ -271,6 +271,7 @@ export default {
         .then((res) => {
           this.$Message.success(res.msg);
           this.levelLists.splice(num, 1);
+          this.total--
         })
         .catch((res) => {
           this.$Message.error(res.msg);

+ 0 - 5
template/admin/src/pages/user/list/handle/userDetails.vue

@@ -158,11 +158,6 @@ export default {
                     key: 'total_num',
                     minWidth: 90,
                   },
-                  {
-                    title: '商品总价',
-                    key: 'total_price',
-                    minWidth: 110,
-                  },
                   {
                     title: '实付金额',
                     key: 'pay_price',

+ 2 - 2
template/admin/src/pages/user/list/handle/userEdit.vue

@@ -55,12 +55,12 @@
       </FormItem>
 
       <FormItem label="用户等级:">
-        <Select v-model="formItem.level" class="form-sty">
+        <Select v-model="formItem.level" class="form-sty" clearable>
           <Option v-for="(item, index) in infoData.levelInfo" :key="index" :value="item.id">{{ item.name }}</Option>
         </Select>
       </FormItem>
       <FormItem label="用户分组:">
-        <Select v-model="formItem.group_id" class="form-sty">
+        <Select v-model="formItem.group_id"  class="form-sty" clearable>
           <Option v-for="(item, index) in infoData.groupInfo" :key="index" :value="item.id">{{
             item.group_name
           }}</Option>

+ 69 - 16
template/admin/src/pages/user/list/index.vue

@@ -133,19 +133,21 @@
                   </RadioGroup>
                 </FormItem>
               </Col>
-              <FormItem label="身份:" label-for="is_promoter">
-                <RadioGroup v-model="userFrom.is_promoter" type="button">
-                  <Radio label="">
-                    <span>全部</span>
-                  </Radio>
-                  <Radio label="1">
-                    <span>推广员</span>
-                  </Radio>
-                  <Radio label="0">
-                    <span>普通用户</span>
-                  </Radio>
-                </RadioGroup>
-              </FormItem>
+              <Col v-bind="grid">
+                <FormItem label="身份:" label-for="is_promoter">
+                  <RadioGroup v-model="userFrom.is_promoter" type="button">
+                    <Radio label="">
+                      <span>全部</span>
+                    </Radio>
+                    <Radio label="1">
+                      <span>推广员</span>
+                    </Radio>
+                    <Radio label="0">
+                      <span>普通用户</span>
+                    </Radio>
+                  </RadioGroup>
+                </FormItem>
+              </Col>
             </Col>
             <Col span="18">
               <Col v-bind="grid">
@@ -221,6 +223,7 @@
           </Button>
           <Button v-auth="['admin-user-group_set']" class="mr20" @click="setGroup">批量设置分组</Button>
           <Button v-auth="['admin-user-set_label']" class="mr20" @click="setLabel">批量设置标签</Button>
+          <Button class="mr20" icon="ios-share-outline" @click="exportList">导出</Button>
 
           <!-- <Button v-auth="['admin-user-synchro']" class="mr20" @click="synchro">同步公众号用户</Button> -->
         </Col>
@@ -269,9 +272,9 @@
         <!--                    </i-switch>-->
         <!--                </template>-->
         <template slot-scope="{ row, index }" slot="action">
-          <a @click="edit(row)">编辑</a>
-          <Divider type="vertical" />
-          <template>
+          <template v-if="row.is_del != 1">
+            <a @click="edit(row)">编辑</a>
+            <Divider type="vertical" />
             <Dropdown @on-click="changeMenu(row, $event, index)" :transfer="true">
               <a href="javascript:void(0)">
                 更多
@@ -289,6 +292,9 @@
               </DropdownMenu>
             </Dropdown>
           </template>
+          <template v-else>
+            <div v-if="row.is_del == 1" style="color: red">已注销</div>
+          </template>
         </template>
       </Table>
 
@@ -407,6 +413,7 @@ import {
   saveSetLabel,
 } from '@/api/user';
 import { agentSpreadApi } from '@/api/agent';
+import { exportUserList } from '@/api/export';
 import editFrom from '../../../components/from/from';
 import sendFrom from '@/components/sendCoupons/index';
 import userDetails from './handle/userDetails';
@@ -1015,6 +1022,52 @@ export default {
           this.$Message.error(res.msg);
         });
     },
+    // 用户导出
+    async exportList() {
+      if (this.selectDataLabel.length) {
+        let activeIds = [];
+        this.selectDataLabel.forEach((item) => {
+          activeIds.push(item.id);
+        });
+        this.userFrom.label_id = activeIds.join(',');
+      }
+      this.userFrom.user_type = this.userFrom.user_type || '';
+      this.userFrom.status = this.userFrom.status || '';
+      this.userFrom.sex = this.userFrom.sex || '';
+      this.userFrom.is_promoter = this.userFrom.is_promoter || '';
+      this.userFrom.country = this.userFrom.country || '';
+      this.userFrom.pay_count = this.pay_count === 'all' ? '' : this.pay_count;
+      this.userFrom.user_time_type = this.user_time_type === 'all' ? '' : this.user_time_type;
+      this.userFrom.field_key = this.field_key === 'all' ? '' : this.field_key;
+      this.userFrom.level = this.level === 'all' ? '' : this.level;
+      this.userFrom.group_id = this.group_id === 'all' ? '' : this.group_id;
+      let [th, filekey, data, fileName] = [[], [], [], ''];
+      //   let fileName = "";
+      let excelData = JSON.parse(JSON.stringify(this.userFrom));
+      excelData.page = 1;
+      for (let i = 0; i < excelData.page + 1; i++) {
+        let lebData = await this.getExcelData(excelData);
+        if (!fileName) fileName = lebData.filename;
+        if (!filekey.length) {
+          filekey = lebData.fileKey;
+        }
+        if (!th.length) th = lebData.header;
+        if (lebData.export.length) {
+          data = data.concat(lebData.export);
+          excelData.page++;
+        } else {
+          this.$exportExcel(th, filekey, fileName, data);
+          return;
+        }
+      }
+    },
+    getExcelData(excelData) {
+      return new Promise((resolve, reject) => {
+        exportUserList(excelData).then((res) => {
+          resolve(res.data);
+        });
+      });
+    },
     pageChange(index) {
       this.selectionList = [];
       this.userFrom.page = index;

+ 0 - 2
template/admin/src/router/modules/setting.js

@@ -65,7 +65,6 @@ export default {
       path: 'system_config/:type?/:tab_id?',
       name: `${pre}setApp`,
       meta: {
-        ...meta,
         title: '应用设置',
       },
       component: () => import('@/pages/setting/setSystem/index'),
@@ -74,7 +73,6 @@ export default {
       path: 'system_config/payment/:type?/:tab_id?',
       name: `${pre}payment`,
       meta: {
-        ...meta,
         title: '支付配置',
       },
       component: () => import('@/pages/setting/setSystem/index'),

+ 7 - 0
template/admin/src/styles/style.css

@@ -678,3 +678,10 @@ body {
 .paddingBox {
   padding: 0 10px 10px;
 }
+
+/* form-create tips 样式 */
+.tips-info {
+  line-height: 18px;
+  margin-top: 8px;
+  color: rgb(153, 153, 153);
+}

+ 5 - 1
template/admin/src/utils/modalForm.js

@@ -88,9 +88,12 @@ export default function (formRequestPromise, { width = '700' } = { width: '700'
             },
           },
         };
-        data.config.onSubmit = function (formData, $f) {
+        let btnStop = false;
+        data.config.onSubmit = (formData, $f) => {
           $f.btn.loading(true);
           $f.btn.disabled(true);
+          if (btnStop) return;
+          btnStop = true;
           request[data.method.toLowerCase()](data.action, formData)
             .then((res) => {
               modalInstance.remove();
@@ -101,6 +104,7 @@ export default function (formRequestPromise, { width = '700' } = { width: '700'
               Message.error(err.msg || '提交失败');
             })
             .finally(() => {
+              btnStop = false;
               $f.btn.loading(false);
               $f.btn.disabled(false);
             });