Procházet zdrojové kódy

Merge commit '87574c8cdaa6e400a919c6364fce6552432e698e' into HEAD

gitadmin před 9 měsíci
rodič
revize
5ee8eabe30
26 změnil soubory, kde provedl 2416 přidání a 62 odebrání
  1. binární
      public/templ/商城产品导入模板.xlsx
  2. 70 0
      src/api/shopCategory.js
  3. 143 0
      src/api/shopProduct.js
  4. 4 1
      src/components/UploadFile/index.vue
  5. 119 44
      src/config/router.config.js
  6. 1 1
      src/views/allocationManagement/transferOut/edit.vue
  7. 1 1
      src/views/bnSetting/menu/adminMenus.vue
  8. 1 1
      src/views/bnSetting/menu/childModal.vue
  9. 1 1
      src/views/bnSetting/menu/storeMenus.vue
  10. 203 0
      src/views/easyPassManagement/shoppingManagement/addCategoryModal.vue
  11. 85 0
      src/views/easyPassManagement/shoppingManagement/chooseProduct.vue
  12. 274 0
      src/views/easyPassManagement/shoppingManagement/chooseProductsModal.vue
  13. 78 0
      src/views/easyPassManagement/shoppingManagement/imgShowModal.vue
  14. 311 0
      src/views/easyPassManagement/shoppingManagement/list.vue
  15. 194 0
      src/views/easyPassManagement/shoppingProducts/chooseImportModal.vue
  16. 208 0
      src/views/easyPassManagement/shoppingProducts/editProductModal.vue
  17. 208 0
      src/views/easyPassManagement/shoppingProducts/importGuideModal.vue
  18. 502 0
      src/views/easyPassManagement/shoppingProducts/list.vue
  19. 1 1
      src/views/power/dataDictionary/codeItemModal.vue
  20. 1 1
      src/views/power/dataDictionary/codeModal.vue
  21. 1 1
      src/views/power/menu/childModal.vue
  22. 1 1
      src/views/power/menu/menu.vue
  23. 1 1
      src/views/power/register/register.vue
  24. 4 4
      src/views/promotionRulesManagement/dealerPromotions/sendAmountModal.vue
  25. 1 1
      src/views/promotionRulesManagement/promotionManagement/edit.vue
  26. 3 3
      src/views/promotionRulesManagement/promotionRules/choosePriceProductsModal.vue

binární
public/templ/商城产品导入模板.xlsx


+ 70 - 0
src/api/shopCategory.js

@@ -0,0 +1,70 @@
+import { axios } from '@/utils/request'
+
+//  易码通商城列表  无分页
+export const shopCategoryList = (params) => {
+  const url = '/shopCategory/queryList'
+  return axios({
+    url: url,
+    data: params,
+    method: 'post',
+    headers: {
+      'module': encodeURIComponent('列表查询')
+    }
+  })
+}
+// 易码通商城新增类目
+export const saveShopCategory = (params) => {
+  return axios({
+    url: '/shopCategory/saveShopCategory',
+    data: params,
+    method: 'post',
+    headers: {
+      'module': encodeURIComponent('新增类目')
+    }
+  })
+}
+
+// 易码通商城目录 删除 sn=categorySn
+export const shopCategoryDel = params => {
+  return axios({
+    url: `/shopCategory/delete/${params.categorySn}`,
+    data: params,
+    method: 'post',
+    headers: {
+      'module': encodeURIComponent('删除')
+    }
+  })
+}
+
+// 易码通商城目录 获取子级目录列表  无分页
+export const getChildList = params => {
+  return axios({
+    url: `/shopCategory/queryExtBySn/${params.categorySn}`,
+    data: params,
+    method: 'post',
+    headers: {
+      'module': encodeURIComponent('获取子级目录列表')
+    }
+  })
+}
+
+// 易码通商城目录 详情
+export const shopCategoryDetail = params => {
+  return axios({
+    url: `/shopCategory/queryBySn/${params.categorySn}`,
+    data: params,
+    method: 'post',
+    headers: {
+      'module': encodeURIComponent('详情')
+    }
+  })
+}
+
+// 易码通商城目录 修改状态
+export const shopCategoryUpdateStatus = (params) => {
+  return axios({
+    url: 'shopCategory/updateStatus',
+    data: params,
+    method: 'post'
+  })
+}

+ 143 - 0
src/api/shopProduct.js

@@ -0,0 +1,143 @@
+import { axios } from '@/utils/request'
+
+//  商城产品列表  有分页
+export const shopProductList = (params) => {
+  const url = `/shopProduct/queryProductPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post',
+    headers: {
+      'module': encodeURIComponent('列表查询')
+    }
+  })
+}
+
+// 商城产品列表 删除
+export const shopProductDel = params => {
+  return axios({
+    url: '/shopProduct/delete',
+    data: params,
+    method: 'post',
+    headers: {
+      'module': encodeURIComponent('删除')
+    }
+  })
+}
+// 商城产品 导出模板
+export const shopProductDownloadExcel = params => {
+  return axios.request({
+    url: '/shopProduct/downloadExcel',
+    method: 'post',
+    data: params,
+    responseType: 'blob',
+    headers: {
+      'module': encodeURIComponent('下载导入模板')
+    }
+  })
+}
+
+// 商城产品 导入解析
+export const shopProductParseExcel = (params) => {
+  return axios({
+    url: '/shopProduct/parseExcel',
+    data: params,
+    method: 'post'
+  })
+}
+
+// 商城产品  导出错误项
+export const shopProductExport = params => {
+  return axios.request({
+    url: '/shopProduct/exportError',
+    method: 'post',
+    data: params,
+    responseType: 'blob',
+    headers: {
+      'module': encodeURIComponent('导出错误项')
+    }
+  })
+}
+
+// 商城产品 详情
+export const shopProductDetail = params => {
+  return axios({
+    url: `/shopProduct/queryBySn/${params.shopProductSn}`,
+    data: params,
+    method: 'post',
+    headers: {
+      'module': encodeURIComponent('详情')
+    }
+  })
+}
+
+// 商城产品 批量保存
+export const saveBatchProduct = params => {
+  return axios({
+    url: '/shopProduct/saveBatchProduct',
+    data: params,
+    method: 'post',
+    headers: {
+      'module': encodeURIComponent('批量保存')
+    }
+  })
+}
+
+// 商城产品 导入产品批量保存
+export const saveBatchProductExcel = params => {
+  return axios({
+    url: '/shopProduct/saveBatchProductExcel',
+    data: params,
+    method: 'post',
+    headers: {
+      'module': encodeURIComponent('批量保存')
+    }
+  })
+}
+
+// 商城产品  产品保存
+export const shopProductSaveProduct = params => {
+  return axios({
+    url: '/shopProduct/saveProduct',
+    data: params,
+    method: 'post',
+    headers: {
+      'module': encodeURIComponent('保存')
+    }
+  })
+}
+
+// 商城产品  更新上架、下架状态
+export const shopProductUpdateStatus = params => {
+  return axios({
+    url: '/shopProduct/updateStatus',
+    data: params,
+    method: 'post',
+    headers: {
+      'module': encodeURIComponent('更新状态')
+    }
+  })
+}
+
+// 获取类目中已选择的产品  列表
+export const queryProductSnList = (params) => {
+  return axios({
+    url: '/shopProduct/queryProductSnList',
+    data: params,
+    method: 'post'
+  })
+}
+
+// 商城目录 列表  无分页
+export const queryExtList = (params) => {
+  return axios({
+    url: '/shopCategory/queryExtList',
+    data: params,
+    method: 'post',
+    headers: {
+      'module': encodeURIComponent('商城目录列表')
+    }
+  })
+}

+ 4 - 1
src/components/UploadFile/index.vue

@@ -178,7 +178,7 @@ export default {
           this.previewImage = file.url || file.thumbUrl
         }
         this.previewVisible = true
-      } else {
+      } else if (file.type) {
         if (file.response && file.response.status && file.response.status == 200) {
           var src = file.response.data
           if (Array.isArray(src)) {
@@ -186,6 +186,9 @@ export default {
           }
           window.location.href = src.replace('http:', 'https:')
         }
+      } else {
+        this.previewImage = file.url
+        this.previewVisible = true
       }
     },
     handleRemove (file) {

+ 119 - 44
src/config/router.config.js

@@ -3469,94 +3469,169 @@ export const asyncRouterMap = [
         },
         children: [
           {
-            path: '/promotionRulesManagement/promotionManagement',
-            redirect: '/promotionRulesManagement/promotionManagement/list',
-            name: 'promotionManagement',
+            path: '/promotionRulesManagement/dealerPromotions',
+            redirect: '/promotionRulesManagement/dealerPromotions/list',
+            name: 'dealerPromotionManagement',
             component: BlankLayout,
             meta: {
-              title: '修理厂促销',
+              title: '经销商促销',
+              icon: 'setting',
+              permission: 'M_dealerPromotionManagementList'
+            },
+            hideChildrenInMenu: true,
+            children: [
+              {
+                path: 'list',
+                name: 'dealerPromotionManagementList',
+                component: () => import(/* webpackChunkName: "dealerManagement" */ '@/views/promotionRulesManagement/dealerPromotions/list.vue'),
+                meta: {
+                  title: '经销商促销',
+                  icon: 'setting',
+                  hidden: true,
+                  permission: 'M_dealerPromotionManagementList'
+                }
+              },
+              {
+                path: 'detail',
+                name: 'dealerPromotionManagementDetail',
+                component: () => import(/* webpackChunkName: "promotionRulesManagement" */ '@/views/promotionRulesManagement/dealerPromotions/detail.vue'),
+                meta: {
+                  title: '促销活动详情',
+                  icon: 'thunderbolt',
+                  hidden: true
+                }
+              },
+              {
+                path: 'ruleSet',
+                name: 'dealerPromotionManagementRule',
+                component: () => import(/* webpackChunkName: "promotionRulesManagement" */ '@/views/promotionRulesManagement/dealerPromotions/detail.vue'),
+                meta: {
+                  title: '促销规则设置',
+                  icon: 'thunderbolt',
+                  replaceTab: true,
+                  hidden: true
+                }
+              }
+            ]
+          }
+        ]
+      },
+      // 易码通
+      {
+        path: '/easyPassManagement',
+        redirect: '/easyPassManagement/shoppingManagement',
+        component: PageView,
+        meta: {
+          title: '易码通',
+          icon: 'shop',
+          permission: 'M_shoppingManagement'
+        },
+        children: [
+          {
+            path: '/easyPassManagement/shoppingManagement',
+            redirect: '/easyPassManagement/shoppingManagement/list',
+            name: 'shoppingManagement',
+            component: BlankLayout,
+            meta: {
+              title: '商城类目',
               icon: 'file-ppt',
-              permission: 'M_promotionManagementList'
+              permission: 'M_shoppingManagementList'
             },
             hideChildrenInMenu: true,
             children: [
               {
                 path: 'list',
-                name: 'promotionManagementList',
-                component: () => import(/* webpackChunkName: "promotionRulesManagement" */ '@/views/promotionRulesManagement/promotionManagement/list.vue'),
+                name: 'shoppingManagementList',
+                component: () => import(/* webpackChunkName: "easyPassManagement" */ '@/views/easyPassManagement/shoppingManagement/list.vue'),
                 meta: {
-                  title: '修理厂促销列表',
+                  title: '商城类目列表',
                   icon: 'file-ppt',
                   hidden: true,
-                  permission: 'M_promotionManagementList'
+                  permission: 'M_shoppingManagementList'
                 }
               },
               {
-                path: 'add/:sn/:pageType',
-                name: 'promotionManagementAdd',
-                component: () => import(/* webpackChunkName: "promotionRulesManagement" */ '@/views/promotionRulesManagement/promotionManagement/edit.vue'),
+                path: 'chooseProduct/:sn',
+                name: 'chooseProductList',
+                component: () => import(/* webpackChunkName: "easyPassManagement" */ '@/views/easyPassManagement/shoppingManagement/chooseProduct.vue'),
                 meta: {
-                  title: '新增修理厂促销',
+                  title: '商城类目产品列表',
                   icon: 'file-ppt',
                   hidden: true,
-                  permission: 'B_promotionManagementAdd'
+                  replaceTab: true,
+                  permission: 'B_category_chooseProduct'
                 }
-              },
+              }
+            ]
+          },
+          {
+            path: '/easyPassManagement/shoppingProducts',
+            redirect: '/easyPassManagement/shoppingProducts/list',
+            name: 'shoppingProducts',
+            component: BlankLayout,
+            meta: {
+              title: '商城产品',
+              icon: 'file-ppt',
+              permission: 'M_shoppingProducts'
+            },
+            hideChildrenInMenu: true,
+            children: [
               {
-                path: 'edit/:sn/:pageType',
-                name: 'promotionManagementEdit',
-                component: () => import(/* webpackChunkName: "promotionRulesManagement" */ '@/views/promotionRulesManagement/promotionManagement/edit.vue'),
+                path: 'list',
+                name: 'shoppingProductsList',
+                component: () => import(/* webpackChunkName: "easyPassManagement" */ '@/views/easyPassManagement/shoppingProducts/list.vue'),
                 meta: {
-                  title: '编辑修理厂促销',
+                  title: '商城产品列表',
                   icon: 'file-ppt',
                   hidden: true,
-                  permission: 'B_promotionManagementEdit'
+                  permission: 'M_shoppingProductsList'
                 }
               }
             ]
           },
           {
-            path: '/promotionRulesManagement/dealerPromotions',
-            redirect: '/promotionRulesManagement/dealerPromotions/list',
-            name: 'dealerPromotionManagement',
+            path: '/promotionRulesManagement/promotionManagement',
+            redirect: '/promotionRulesManagement/promotionManagement/list',
+            name: 'promotionManagement',
             component: BlankLayout,
             meta: {
-              title: '经销商促销',
-              icon: 'setting',
-              permission: 'M_dealerPromotionManagementList'
+              title: '修理厂促销',
+              icon: 'file-ppt',
+              permission: 'M_promotionManagementList'
             },
             hideChildrenInMenu: true,
             children: [
               {
                 path: 'list',
-                name: 'dealerPromotionManagementList',
-                component: () => import(/* webpackChunkName: "dealerManagement" */ '@/views/promotionRulesManagement/dealerPromotions/list.vue'),
+                name: 'promotionManagementList',
+                component: () => import(/* webpackChunkName: "promotionRulesManagement" */ '@/views/promotionRulesManagement/promotionManagement/list.vue'),
                 meta: {
-                  title: '经销商促销',
-                  icon: 'setting',
+                  title: '修理厂促销列表',
+                  icon: 'file-ppt',
                   hidden: true,
-                  permission: 'M_dealerPromotionManagementList'
+                  permission: 'M_promotionManagementList'
                 }
               },
               {
-                path: 'detail',
-                name: 'dealerPromotionManagementDetail',
-                component: () => import(/* webpackChunkName: "promotionRulesManagement" */ '@/views/promotionRulesManagement/dealerPromotions/detail.vue'),
+                path: 'add/:sn/:pageType',
+                name: 'promotionManagementAdd',
+                component: () => import(/* webpackChunkName: "promotionRulesManagement" */ '@/views/promotionRulesManagement/promotionManagement/edit.vue'),
                 meta: {
-                  title: '促销活动详情',
-                  icon: 'thunderbolt',
-                  hidden: true
+                  title: '新增修理厂促销',
+                  icon: 'file-ppt',
+                  hidden: true,
+                  permission: 'B_promotionManagementAdd'
                 }
               },
               {
-                path: 'ruleSet',
-                name: 'dealerPromotionManagementRule',
-                component: () => import(/* webpackChunkName: "promotionRulesManagement" */ '@/views/promotionRulesManagement/dealerPromotions/detail.vue'),
+                path: 'edit/:sn/:pageType',
+                name: 'promotionManagementEdit',
+                component: () => import(/* webpackChunkName: "promotionRulesManagement" */ '@/views/promotionRulesManagement/promotionManagement/edit.vue'),
                 meta: {
-                  title: '促销规则设置',
-                  icon: 'thunderbolt',
-                  replaceTab: true,
-                  hidden: true
+                  title: '编辑修理厂促销',
+                  icon: 'file-ppt',
+                  hidden: true,
+                  permission: 'B_promotionManagementEdit'
                 }
               }
             ]

+ 1 - 1
src/views/allocationManagement/transferOut/edit.vue

@@ -285,7 +285,7 @@
               v-model="record.qty"
               :precision="0"
               :min="1"
-              :max="999999"
+              :max="99999999"
               placeholder="请输入"
               @blur="e => qtyBlur(e.target.value, record)"
               style="width: 100%;" />

+ 1 - 1
src/views/bnSetting/menu/adminMenus.vue

@@ -111,7 +111,7 @@
               v-decorator="['formData.sort', {
                 initialValue: formData.sort,
                 rules: [] }]"
-              :max="999999"
+              :max="99999999"
               :min="0"
             />
           </a-form-item>

+ 1 - 1
src/views/bnSetting/menu/childModal.vue

@@ -128,7 +128,7 @@
             v-decorator="['formData.sort', {
               initialValue: formData.sort,
               rules: [] }]"
-            :max="999999"
+            :max="99999999"
             :min="0"
           />
         </a-form-item>

+ 1 - 1
src/views/bnSetting/menu/storeMenus.vue

@@ -149,7 +149,7 @@
               v-decorator="['formData.sort', {
                 initialValue: formData.sort,
                 rules: [] }]"
-              :max="999999"
+              :max="99999999"
               :min="0"
             />
           </a-form-item>

+ 203 - 0
src/views/easyPassManagement/shoppingManagement/addCategoryModal.vue

@@ -0,0 +1,203 @@
+<template>
+  <a-modal
+    centered
+    class="add-category-modal"
+    :footer="null"
+    :maskClosable="false"
+    :title="pageType==='add'?'新增类目':pageType==='addChild'?'新增子类目':'编辑'"
+    v-model="isShow"
+    @cancel="isShow = false"
+    :width="700">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-form-model
+        id="add-category-form"
+        ref="ruleForm"
+        :model="form"
+        :rules="rules"
+        :label-col="formItemLayout.labelCol"
+        :wrapper-col="formItemLayout.wrapperCol"
+      >
+        <a-form-model-item label="父类名称" v-if="pageType==='addChild'&&parentData&&parentData.categorySn">
+          {{ parentData&&parentData.categoryName ||'--' }}
+        </a-form-model-item>
+        <a-form-model-item label="上传图标" prop="iconUrl">
+          <Upload
+            class="upload"
+            id="add-category-iconUrl"
+            v-model.trim="form.iconUrl"
+            ref="imageSet"
+            :fileSize="10"
+            :maxNums="1"
+            @change="changeImage"
+            listType="picture-card"></Upload>
+        </a-form-model-item>
+        <a-form-model-item label="类目名称" prop="categoryName">
+          <a-input
+            id="add-category-name"
+            :maxLength="5"
+            v-model.trim="form.categoryName"
+            placeholder="请输入类目名称(最多5个字符)"
+            allowClear/>
+        </a-form-model-item>
+        <a-form-model-item label="易码通优先级" prop="sort">
+          <a-input-number
+            style="width:100%;"
+            id="add-category-sort"
+            v-model.trim="form.sort"
+            :min="0"
+            :precision="0"
+            :max="99999999"
+            placeholder="请输入正整数,数字越大优先级越低"
+            allowClear />
+        </a-form-model-item>
+      </a-form-model>
+      <div class="btn-cont">
+        <a-button id="add-category-modal-back" @click="isShow = false" style="margin-right: 15px;">取消</a-button>
+        <a-button type="primary" id="add-category-modal-save" @click="handleSave">保存</a-button>
+      </div>
+    </a-spin>
+  </a-modal>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+// 组件
+import { Upload } from '@/components'
+// 接口
+import { saveShopCategory, shopCategoryDetail } from '@/api/shopCategory'
+export default {
+  name: 'AddCategoryModal',
+  mixins: [commonMixin],
+  components: { Upload },
+  props: {
+    openModal: {//  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    parentData: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    pageType: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      spinning: false,
+      isShow: this.openModal, //  是否打开弹框
+      // 设置表单label布局
+      formItemLayout: {
+        labelCol: { span: 4 },
+        wrapperCol: { span: 18 }
+      },
+      // 添加参数
+      form: {
+        parentSn: undefined,
+        categoryName: '', //  类目名称
+        sort: undefined, //  优先级
+        iconUrl: '' //  上传图标
+      },
+      // 必填项验证
+      rules: {
+        iconUrl: [{ required: true, message: '请选择上传图标', trigger: 'change' }],
+        categoryName: [{ required: true, message: '请输入类目名称', trigger: 'blur' }],
+        sort: [{ required: true, message: '请输入优先级', trigger: 'blur' }]
+      }
+    }
+  },
+  methods: {
+    //  图片上传
+    changeImage (file) {
+      this.form.iconUrl = file
+      if (file) {
+        this.$nextTick(() => {
+          this.$refs.ruleForm.clearValidate('iconUrl')
+        })
+      }
+    },
+    //  保存
+    handleSave () {
+      const _this = this
+      //  处理表单校验
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          _this.spinning = true
+          if (_this.parentData && _this.parentData.categorySn && _this.pageType === 'addChild') {
+            _this.form.parentSn = _this.parentData.categorySn
+          }
+          saveShopCategory(_this.form).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              setTimeout(() => {
+                _this.$emit('ok')
+                _this.isShow = false
+                _this.spinning = false
+              }, 1000)
+            } else {
+              _this.spinning = false
+            }
+          })
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    },
+    // 重置
+    resetAddForm () {
+      this.form.categorySn = undefined
+      this.form.parentSn = undefined
+      this.form.categoryName = ''
+      this.form.sort = undefined
+      this.form.iconUrl = ''
+      this.$refs.imageSet.setFileList('')
+      this.$refs.ruleForm.resetFields()
+    },
+    // 获取详情数据
+    getDetailData (ajaxData) {
+      this.spinning = true
+      shopCategoryDetail(ajaxData).then(res => {
+        if (res.status == 200) {
+          this.form = res.data
+          this.$refs.imageSet.setFileList(res.data.iconUrl)
+        }
+        this.spinning = false
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.resetAddForm()
+      } else {
+        this.form = {}
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+.add-category-modal {
+	.ant-modal-body {
+		padding: 40px 40px 24px;
+	}
+	.btn-cont {
+		text-align: center;
+		margin: 35px 0 10px;
+	}
+  .ant-radio + span{
+    line-height: 40px;
+  }
+}
+</style>

+ 85 - 0
src/views/easyPassManagement/shoppingManagement/chooseProduct.vue

@@ -0,0 +1,85 @@
+<template>
+  <div class="chooseProductEdit-wrap">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-page-header :ghost="false" :backIcon="false" class="chooseProductEdit-back">
+        <!-- 自定义的二级文字标题 -->
+        <template slot="subTitle">
+          <a id="chooseProductEdit-back-btn" href="javascript:;" @click="handleBack">
+            <a-icon type="left" />
+            返回列表
+          </a>
+          <span style="margin: 0 15px;color: #666;font-weight: bold;">类目名称:{{ detailsData&&detailsData.categoryName }}</span>
+        </template>
+      </a-page-header>
+      <a-card size="small" :bordered="false" class="chooseProductEdit-cont table-page-search-wrapper">
+        <!-- 主要内容 -->
+        <main-content ref="mainCon" :itemCategorySn="$route.params.sn"></main-content>
+      </a-card>
+    </a-spin>
+  </div>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+// 组件
+import mainContent from '@/views/easyPassManagement/shoppingProducts/list'
+// 接口
+import { shopCategoryDetail } from '@/api/shopCategory'
+export default {
+  name: 'ChooseProductEdit',
+  mixins: [commonMixin],
+  components: { mainContent },
+  data () {
+    return {
+      spinning: false,
+      detailsData: null, // 类目详情
+      tableHeight: 0 // 表格高度
+    }
+  },
+  methods: {
+    //  返回列表并刷新
+    handleBack () {
+      this.$router.push({ name: 'shoppingManagementList', query: { closeLastOldTab: true } })
+    },
+    // 获取目录详情
+    getCategoryDetail () {
+      this.spinning = true
+      shopCategoryDetail({ categorySn: this.$route.params.sn }).then(res => {
+        if (res.status == 200) {
+          this.detailsData = res.data || {}
+        }
+        this.spinning = false
+      })
+    }
+  },
+  mounted () {
+    if (!this.$store.state.app.isNewTab) {
+      // 页签刷新时调用
+      this.getCategoryDetail()
+    }
+  },
+  activated () {
+    // 如果是新页签打开或者进入新的子页(例:存在列表第2条数据编辑页页签时再打开第4条数据的编辑页),则重置当前页面
+    if (this.$store.state.app.isNewTab || !this.$store.state.app.isNewSubTab) {
+      this.getCategoryDetail()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {})
+  }
+}
+</script>
+
+<style lang="less">
+.chooseProductEdit-wrap {
+  position: relative;
+  height: 100%;
+  box-sizing: border-box;
+  > .ant-spin-nested-loading {
+    height: 100%;
+  }
+  .chooseProductEdit-cont {
+    margin-top: 6px;
+  }
+}
+</style>

+ 274 - 0
src/views/easyPassManagement/shoppingManagement/chooseProductsModal.vue

@@ -0,0 +1,274 @@
+<template>
+  <a-drawer
+    :zIndex="zIndex"
+    title="选择产品"
+    placement="right"
+    :visible="isShow"
+    width="80%"
+    :get-container="false"
+    :wrap-style="{ position: 'absolute' }"
+    :headerStyle="{ padding: '10px' }"
+    @close="onClose"
+    wrapClassName="chooseProducts-modal">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <div class="products-con">
+        <!-- 搜索条件 -->
+        <div class="table-page-search-wrapper">
+          <a-form-model
+            ref="ruleForm"
+            class="form-model-con"
+            layout="inline"
+            :model="queryParam"
+            id="chooseProducts-form"
+            :label-col="formItemLayout.labelCol"
+            :wrapper-col="formItemLayout.wrapperCol">
+            <a-row :gutter="15">
+              <a-col :md="8" :sm="24">
+                <a-form-model-item label="产品编码">
+                  <a-input id="chooseProducts-productCode" v-model.trim="queryParam.code" allowClear placeholder="请输入产品编码"/>
+                </a-form-model-item>
+              </a-col>
+              <a-col :md="8" :sm="24">
+                <a-form-model-item label="原厂编码">
+                  <a-input id="chooseProducts-origCode" v-model.trim="queryParam.origCode" allowClear placeholder="请输入原厂编码"/>
+                </a-form-model-item>
+              </a-col>
+              <a-col :md="8" :sm="24">
+                <a-form-model-item label="产品名称">
+                  <a-input id="chooseProducts-productName" v-model.trim="queryParam.name" allowClear placeholder="请输入产品名称"/>
+                </a-form-model-item>
+              </a-col>
+              <a-col :md="8" :sm="24">
+                <a-form-model-item label="产品分类">
+                  <productTypeAll placeholder="请选择产品分类" @change="changeProductType" v-model="queryParam.productType" id="chooseProducts-productType"></productTypeAll>
+                </a-form-model-item>
+              </a-col>
+              <a-col :md="8" :sm="24">
+                <a-form-model-item label="产品品牌">
+                  <ProductBrand id="chooseProducts-productBrandSn" v-model="queryParam.productBrandSn"></ProductBrand>
+                </a-form-model-item>
+              </a-col>
+              <a-col :md="8" :sm="24" style="margin-bottom: 10px;">
+                <a-button type="primary" @click="$refs.table.refresh()" :disabled="disabled" id="chooseProducts-refresh">查询</a-button>
+                <a-button style="margin-left: 5px" @click="resetData" :disabled="disabled" id="chooseProducts-reset">重置</a-button>
+              </a-col>
+            </a-row>
+          </a-form-model>
+        </div>
+        <div style="margin-bottom: 10px">
+          <a-button type="primary" ghost id="chooseProducts-add-btn" :loading="loading" @click="handleSave">批量添加</a-button>
+          <span style="margin-left: 5px">
+            <template v-if="selectCount"> {{ `已选 ${selectCount} 项` }} </template>
+          </span>
+        </div>
+        <!-- 列表 -->
+        <s-table
+          class="sTable"
+          ref="table"
+          size="small"
+          :rowKey="(record) => record.productSn"
+          rowKeyName="productSn"
+          :row-selection="{ columnWidth: 40, getCheckboxProps: record => ({ props: { disabled: !record.terminalPrice || record.disabledFlag } })}"
+          @rowSelection="rowSelectionFun"
+          :columns="columns"
+          :pagination="{pageSizeOptions: ['20','50','100','200','500']}"
+          :data="loadData"
+          :defaultLoadData="false"
+          style="max-height:700px;"
+          :scroll="{ y: 550 }"
+          bordered>
+          <!-- 产品分类 -->
+          <template slot="productType" slot-scope="text, record">
+            <span v-if="record.productTypeName2 || record.productTypeName3">{{ record.productTypeName2 }} {{ record.productTypeName3 ? '>' : '' }} {{ record.productTypeName3 }}</span>
+            <span v-else>--</span>
+          </template>
+          <!-- 包装数 -->
+          <template slot="productQty" slot-scope="text, record">
+            <span v-if="record.packQty">
+              {{ record.packQty }}{{ record.unit }}/{{ record.packQtyUnit?record.packQtyUnit:'--' }}
+            </span>
+            <span v-else>--</span>
+          </template>
+        </s-table>
+      </div>
+    </a-spin>
+  </a-drawer>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+// 组件
+import { STable } from '@/components'
+import ProductBrand from '@/views/common/productBrand.js'
+import productTypeAll from '@/views/common/productTypeAll.js'
+// 接口
+import { productList } from '@/api/product'
+export default {
+  name: 'ChooseProductsModal',
+  components: { STable, ProductBrand, productTypeAll },
+  mixins: [commonMixin],
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    chooseData: {// 选中的产品
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    zIndex: { // 层级
+      type: [String, Number],
+      default: 1000
+    }
+  },
+  data () {
+    const _this = this
+    return {
+      spinning: false,
+      isShow: this.openModal, //  是否打开弹框
+      // form 表单中label布局
+      formItemLayout: {
+        labelCol: { span: 4 },
+        wrapperCol: { span: 20 }
+      },
+      //  查询条件
+      queryParam: {
+        code: undefined, // 产品名称
+        origCode: undefined, // 产品编码
+        name: undefined, // 原厂编码
+        productBrandSn: undefined, //  产品品牌
+        productType: [], // 产品分类
+        productTypeSn1: '', //  产品一级分类
+        productTypeSn2: '', //  产品二级分类
+        productTypeSn3: '', //  产品三级分类
+        onlineFalg: 1// 查询上架产品
+      },
+      disabled: false, //  查询、重置按钮是否可操作
+      loading: false, //  表格加载中
+      columns: [// 表头
+        { title: '序号', dataIndex: 'no', width: 60, align: 'center' },
+        { title: '产品编码', dataIndex: 'code', align: 'center', width: '12%' },
+        { title: '产品名称', dataIndex: 'name', align: 'left', width: '18%', ellipsis: true, customRender: function (text) { return text || '--' } },
+        { title: '原厂编码', dataIndex: 'origCode', align: 'center', ellipsis: true, customRender: function (text) { return text || '--' } },
+        { title: '终端价', dataIndex: 'terminalPrice', width: '6%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
+        // { title: '市级价', dataIndex: 'cityPrice', width: '6%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
+        // { title: '特约价', dataIndex: 'specialPrice', width: '6%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
+        { title: '品牌', dataIndex: 'productBrandName', align: 'center', width: '8%', ellipsis: true, customRender: function (text) { return text || '--' } },
+        { title: '产品分类', scopedSlots: { customRender: 'productType' }, align: 'center' },
+        { title: '包装数', scopedSlots: { customRender: 'productQty' }, width: '6%', align: 'center' },
+        { title: '单位', dataIndex: 'unit', align: 'center', width: '6%', ellipsis: true, customRender: function (text) { return text || '--' } }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        this.spinning = true
+        const params = Object.assign(parameter, this.queryParam)
+        params.queryWord = _this.productCode && this.productCode
+        return productList(params).then(res => {
+          let data
+          if (res.status == 200) {
+            data = res.data
+            const no = (data.pageNo - 1) * data.pageSize
+            for (var i = 0; i < data.list.length; i++) {
+              data.list[i].no = no + i + 1
+              // 回显禁用
+              if (this.chooseData && this.chooseData.length > 0) {
+                data.list[i].disabledFlag = this.chooseData.includes(data.list[i].productSn)
+              }
+            }
+            this.disabled = false
+          }
+          _this.spinning = false
+          return data
+        })
+      },
+      rowSelectionInfo: null// 选中数据
+    }
+  },
+  computed: {
+    // 计算选中产品条数
+    selectCount () {
+      return this.rowSelectionInfo && this.rowSelectionInfo.selectedRowKeys.length
+    }
+  },
+  methods: {
+    // 表格选中项
+    rowSelectionFun (obj) {
+      this.rowSelectionInfo = obj || null
+    },
+    // 重置数据
+    resetData () {
+      this.queryParam.code = undefined
+      this.queryParam.origCode = undefined
+      this.queryParam.name = undefined
+      this.queryParam.productBrandSn = undefined
+      this.queryParam.productTypeSn1 = ''
+      this.queryParam.productTypeSn2 = ''
+      this.queryParam.productTypeSn3 = ''
+      this.queryParam.productType = []
+      this.$nextTick(() => {
+        this.$refs.table.refresh(true)
+      })
+    },
+    //  清空选项
+    resetSearchForm () {
+      this.$refs.table.clearSelected()
+    },
+    // 批量添加
+    handleSave () {
+      if (!this.rowSelectionInfo || (this.rowSelectionInfo && this.rowSelectionInfo.selectedRowKeys.length < 1)) {
+        this.$message.warning('请在列表勾选后再进行操作!')
+        return
+      }
+      const resultList = JSON.parse(JSON.stringify(this.rowSelectionInfo && this.rowSelectionInfo.selectedRows))
+      this.$emit('ok', resultList)
+      // this.isShow = false
+    },
+    // 关闭弹框
+    onClose () {
+      this.isShow = false
+      this.$emit('close')
+    },
+    //  产品分类  change
+    changeProductType (val, opt) {
+      this.queryParam.productTypeSn1 = val[0] ? val[0] : ''
+      this.queryParam.productTypeSn2 = val[1] ? val[1] : ''
+      this.queryParam.productTypeSn3 = val[2] ? val[2] : ''
+    }
+
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.resetSearchForm()
+        this.rowSelectionInfo = null
+        this.$emit('close')
+      } else {
+        const _this = this
+        _this.resetData()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .chooseProducts-modal{
+    .products-con{
+      .btn-con{
+        text-align: center;
+        margin: 30px 0 20px;
+        .button-cancel{
+          font-size: 12px;
+        }
+      }
+    }
+  }
+</style>

+ 78 - 0
src/views/easyPassManagement/shoppingManagement/imgShowModal.vue

@@ -0,0 +1,78 @@
+<template>
+  <a-modal
+    centered
+    class="imgShow-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="预览"
+    v-model="isShow"
+    @cancel="isShow=false"
+    :width="500">
+    <div class="imgShow-con">
+      <img :src="mainContent" alt="图片走丢了" />
+    </div>
+    <div class="btn-cont">
+      <a-button id="imgShow-modal-back" @click="isShow = false">关闭</a-button>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+export default {
+  name: 'ImgShowModal',
+  mixins: [commonMixin],
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      mainContent: '' // 主要显示内容
+    }
+  },
+  methods: {
+    // 初始化
+    pageInit (url) {
+      this.mainContent = url
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .imgShow-modal{
+    .imgShow-con{
+      width:90%;
+      margin:0 auto;
+      max-height:700px;
+      overflow-y:scroll;
+      scrollbar-width: none;
+      img{
+         width:100%;
+         height:auto;
+         object-fit:cover;
+       }
+    }
+
+    .btn-cont {
+      text-align: center;
+      margin: 30px 0 0px;
+    }
+  }
+</style>

+ 311 - 0
src/views/easyPassManagement/shoppingManagement/list.vue

@@ -0,0 +1,311 @@
+<template>
+  <a-card size="small" :bordered="false" class="shoppingManagementList-wrap">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <!-- 操作按钮 -->
+      <div ref="tableSearch" class="table-operator" style="border: 0;">
+        <a-button id="shoppingManagementList-addType" v-if="$hasPermissions('B_addCategory')" type="primary" @click="addCategory('add')">新增类目</a-button>
+      </div>
+      <!-- 列表 -->
+      <a-table
+        class="sTable fixPagination"
+        ref="table"
+        :style="{ height: tableHeight+70+'px'}"
+        size="small"
+        :rowKey="(record) => record.categorySn"
+        rowKeyName="categorySn"
+        :columns="columns"
+        :pagination="false"
+        :dataSource="loadDataList"
+        :scroll="{ y: tableHeight+70 }"
+        @expand="expandChild"
+        :expanded-row-keys.sync="expandedRowKeys"
+        bordered>
+        <!-- 图片 -->
+        <template slot="imgs" slot-scope="text, record">
+          <div class="addType-img" v-if="record.iconUrl">
+            <img
+              :src="record.iconUrl"
+              alt="图片走丢啦"
+              width="40"
+              height="40"
+              @click="handleImg(record)"
+              :id="'shoppingManagementList-img-'+record.id"/>
+          </div>
+          <span v-else>--</span>
+        </template>
+        <!-- 状态 -->
+        <template slot="enabledFlag" slot-scope="text, record">
+          <a-switch
+            :id="'shoppingManagementList-enableFlag-'+record.id"
+            v-if="$hasPermissions('B_shoppingManagement_enabled')"
+            checkedChildren="启用"
+            unCheckedChildren="禁用"
+            v-model="record.enableFlag"
+            @change="e=>changeFlagHandle(e,record)"/>
+          <span v-else :style="{color:(record.status==1?'#00aa00':'#999')}"> {{ record.status==1? '已启用': '已禁用' }} </span>
+        </template>
+        <!-- 操作 -->
+        <template slot="action" slot-scope="text, record">
+          <a-button
+            size="small"
+            type="link"
+            class="button-info"
+            @click="handleEdit(record,'edit')"
+            v-if="$hasPermissions('B_addCategory_edit')"
+            :id="'shoppingManagementList-edit-btn'+record.id">编辑</a-button>
+          <a-button
+            size="small"
+            type="link"
+            class="button-info"
+            @click="handleEdit(record,'addChild')"
+            v-if="$hasPermissions('B_addChildCategory')&&(record.type && record.type=='root')&&(record.shopCategoryCount>=0&&record.shopProductCount==0)"
+            :id="'shoppingManagementList-addChild-btn'+record.id">添加子类目</a-button>
+          <a-button
+            size="small"
+            type="link"
+            v-if="$hasPermissions('B_addProduct')&&(record.shopProductCount>=0&&record.shopCategoryCount==0)||record.type!='root'"
+            class="button-success"
+            @click="handleAddProduct(record)"
+            :id="'shoppingManagementList-addProduct-btn'+record.id">添加产品</a-button>
+          <a-button
+            size="small"
+            type="link"
+            class="button-error"
+            @click="handleDel(record)"
+            v-if="$hasPermissions('B_delCategory')"
+            :id="'shoppingManagementList-del-btn'+record.id">删除</a-button>
+        </template>
+      </a-table>
+    </a-spin>
+    <!-- 新增类目 -->
+    <addCategoryModal
+      v-drag
+      ref="categoryModal"
+      :pageType="pageType"
+      :openModal="openCategoryModal"
+      :parentData="parentData"
+      @ok="handleCategoryOk"
+      @close="closeCategory"></addCategoryModal>
+    <!-- 查看图片 -->
+    <imgShowModal v-drag ref="checkedImg" :openModal="openCheckedImgModal" @close="openCheckedImgModal=false"></imgShowModal>
+  </a-card>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+// 组件
+import { VSelect } from '@/components'
+import addCategoryModal from './addCategoryModal.vue'
+import imgShowModal from './imgShowModal.vue'
+// 接口
+import { shopCategoryList, getChildList, shopCategoryUpdateStatus, shopCategoryDel } from '@/api/shopCategory'
+export default {
+  name: 'ShoppingManagementList',
+  mixins: [commonMixin],
+  components: { VSelect, addCategoryModal, imgShowModal },
+  data () {
+    return {
+      spinning: false,
+      tableHeight: 0, // 表格高度
+      openCategoryModal: false, // 打开新增类目弹窗
+      // 表头
+      columns: [
+        { title: '类目名称', dataIndex: 'categoryName', width: '23%', align: 'left', customRender: function (text) { return text || '--' } },
+        { title: '图片', scopedSlots: { customRender: 'imgs' }, width: '10%', align: 'center' },
+        { title: '易码通优先级', dataIndex: 'sort', width: '10%', align: 'center', customRender: function (text) { return (text || text == 0) ? text : '--' }, ellipsis: true },
+        { title: '创建时间', dataIndex: 'createDate', width: '20%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        // { title: '状态', scopedSlots: { customRender: 'enabledFlag' }, width: '15%', align: 'center' },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: '23%', align: 'center' }
+      ],
+      parentData: null, // 父级类目一行数据
+      loadDataList: [], // 表格数据
+      pageType: null, // 按钮类型
+      expandedRowKeys: [], // 展开的类目sn合集
+      openCheckedImgModal: false// 查看图片弹窗
+    }
+  },
+  methods: {
+    // 展开子级 获取子级数据
+    expandChild (expanded, record) {
+      if (expanded) {
+        const _this = this
+        _this.spinning = true
+        getChildList({ categorySn: record.categorySn }).then(res => {
+          if (res.status == 200) {
+            const pos = this.loadDataList.findIndex(item => item.categorySn === record.categorySn)
+            _this.loadDataList[pos].children = pos != -1 ? (res.data.shopCategoryList && res.data.shopCategoryList.length > 0) ? res.data.shopCategoryList : [] : []
+            // 处理显示状态
+            if (_this.loadDataList[pos].children && _this.loadDataList[pos].children.length > 0) {
+              _this.loadDataList[pos].children.map(con => con.enableFlag = con.status == 1)
+            }
+          }
+          _this.spinning = false
+        })
+      }
+    },
+    // 新增类目
+    addCategory (typeVal) {
+      this.pageType = typeVal
+      this.openCategoryModal = true
+    },
+    // 新增类目成功
+    handleCategoryOk () {
+      this.getTabData()
+    },
+    // 关闭新增类目弹窗
+    closeCategory () {
+      this.pageType = null
+      this.parentData = null
+      this.openCategoryModal = false
+    },
+    // 编辑  添加子类目
+    handleEdit (row, typeVal) {
+      this.pageType = typeVal
+      this.openCategoryModal = true
+      this.parentData = row
+      if (typeVal === 'edit') {
+        this.$refs.categoryModal.getDetailData({ categorySn: row.categorySn })
+      }
+    },
+    // 更新状态
+    changeFlagHandle (e, row) {
+      const _this = this
+      _this.spinning = true
+      const params = { categorySn: row.categorySn }
+      params.status = row.status == 1 ? '0' : '1'
+      shopCategoryUpdateStatus(params).then(res => {
+        if (res.status == 200) {
+          _this.$message.success(res.message)
+          row.enableFlag = e
+          _this.spinning = false
+        } else {
+          _this.spinning = false
+        }
+      })
+    },
+    // 添加产品
+    handleAddProduct (row) {
+      this.$router.push({ name: 'chooseProductList', params: { sn: row.categorySn } })
+    },
+    // 查看图片
+    handleImg (row) {
+      this.openCheckedImgModal = true
+      const _this = this
+      _this.$nextTick(() => {
+        _this.$refs.checkedImg.pageInit(row.iconUrl)
+      })
+    },
+    // 删除
+    handleDel (row) {
+      const _this = this
+      if (row.shopCategoryCount > 0) {
+        _this.$message.warning('请先删除子类目!')
+        return
+      }
+      if (row.shopProductCount > 0) {
+        _this.$message.warning('请先删除关联产品!')
+        return
+      }
+      this.$confirm({
+        title: '提示',
+        content: '删除后数据不可恢复,确认删除吗?',
+        centered: true,
+        onOk () {
+          _this.spinning = true
+          shopCategoryDel({ categorySn: row.categorySn }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              if (row.type === 'root') {
+                const pos = _this.loadDataList.findIndex(item => item.categorySn === row.categorySn)
+                _this.loadDataList.splice(pos, 1)
+              } else {
+                const posNum = _this.loadDataList.findIndex(item => item.categorySn === row.parentSn)
+                const indexNum = _this.loadDataList[posNum].children.findIndex(con => con.categorySn === row.categorySn)
+                _this.loadDataList[posNum].children.splice(indexNum, 1)
+                // 清空子级时,显示选择产品列表
+                if (_this.loadDataList[posNum].children && _this.loadDataList[posNum].children.length === 0) {
+                  _this.loadDataList[posNum].shopCategoryCount = 0
+
+                  const i = _this.expandedRowKeys.findIndex(item => item === row.parentSn)
+                  _this.expandedRowKeys.splice(i, 1)
+                }
+              }
+              _this.spinning = false
+            } else {
+              _this.spinning = false
+            }
+          })
+        }
+      })
+    },
+    // 获取表格数据
+    getTabData () {
+      this.spinning = true
+      shopCategoryList({}).then(res => {
+        let data
+        if (res.status == 200) {
+          data = res.data
+          for (var i = 0; i < data.length; i++) {
+            data[i].enableFlag = data[i].status == 1
+            data[i].children = []
+            data[i].type = 'root'
+          }
+        }
+        this.loadDataList = res.data
+        if (this.expandedRowKeys && this.expandedRowKeys.length > 0) {
+          this.expandedRowKeys.forEach(item => {
+            this.expandChild(true, { categorySn: item })
+          })
+        }
+        this.spinning = false
+      })
+    },
+    // 初始化
+    pageInit () {
+      const _this = this
+      _this.getTabData()
+      this.$nextTick(() => { // 页面渲染完成后的回调
+        _this.setTableH()
+      })
+    },
+    // 计算表格高度
+    setTableH () {
+      const tableSearchH = this.$refs.tableSearch.offsetHeight
+      this.tableHeight = window.innerHeight - tableSearchH - 230
+    }
+  },
+  watch: {
+    '$store.state.app.winHeight' (newValue, oldValue) { //  窗口变更时,需同时更改表格高度
+      this.setTableH()
+    }
+  },
+  mounted () {
+    if (!this.$store.state.app.isNewTab) { // 页签刷新时调用
+      this.pageInit()
+    }
+  },
+  activated () {
+    // 如果是新页签打开,则重置当前页面
+    if (this.$store.state.app.isNewTab) {
+      this.pageInit()
+    }
+    // 仅刷新列表,不重置页面
+    if (this.$store.state.app.updateList) {
+      this.pageInit()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {})
+  }
+}
+</script>
+<style lang="less">
+  .shoppingManagementList-wrap{
+    height: 99%;
+    .addType-img{
+      img{
+        object-fit: cover;
+      }
+    }
+  }
+</style>

+ 194 - 0
src/views/easyPassManagement/shoppingProducts/chooseImportModal.vue

@@ -0,0 +1,194 @@
+<template>
+  <a-modal
+    centered
+    class="chooseImport-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="导入"
+    v-model="isShow"
+    @cancel="isShow=false"
+    :width="900">
+    <div class="chooseImport-con">
+      <!-- 可导入数据 -->
+      <p class="">可导入数据{{ loadData.length }}条</p>
+      <a-table
+        class="sTable"
+        ref="table"
+        size="small"
+        :rowKey="(record) => record.allocateSn"
+        :columns="nowColumns"
+        :dataSource="loadData"
+        :loading="loading"
+        :scroll="{ y: 200 }"
+        :pagination="false"
+        bordered>
+      </a-table>
+      <a-divider />
+      <!-- 不可导入数据 -->
+      <p class="red">不可导入数据{{ unLoadData.length }}条</p>
+      <a-table
+        class="unTable"
+        ref="unTable"
+        size="small"
+        :rowKey="(record) => record.errorDesc"
+        :columns="nowUnColumns"
+        :dataSource="unLoadData"
+        :loading="loading"
+        :scroll="{ y: 200 }"
+        :pagination="false"
+        bordered>
+      </a-table>
+      <!-- 按钮 -->
+      <div class="btn-con">
+        <a-button
+          type="primary"
+          id="chooseImport-submit"
+          size="large"
+          :class="loadData.length==0?'button-grey':'button-primary'"
+          @click="handleSubmit"
+          style="padding: 0 40px;">确认导入</a-button>
+        <a-button
+          id="chooseImport-cancel"
+          size="large"
+          class="button-cancel"
+          @click="isShow=false"
+          style="padding: 0 40px;margin-left: 15px;">取消</a-button>
+        <a-button
+          type="primary"
+          id="chooseImport-error"
+          size="large"
+          class="button-error"
+          @click="handleError"
+          style="padding: 0 40px;margin-left: 15px;">导出错误项</a-button>
+      </div>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+import { hdExportExcel } from '@/libs/exportExcel'
+// 接口
+import { shopProductParseExcel, shopProductExport } from '@/api/shopProduct'
+export default {
+  name: 'ChooseImportModal',
+  mixins: [commonMixin],
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    paramsData: {// 导入数据
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  data () {
+    const _this = this
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      nowColumns: [
+        { title: '序号', dataIndex: 'no', width: '10%', align: 'center' },
+        { title: '产品编码', dataIndex: 'productCode', width: '25%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '一级商城类目', dataIndex: 'shopCategoryName1', width: '20%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '二级商城类目', dataIndex: 'shopCategoryName2', width: '20%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '售价', dataIndex: 'price', width: '6%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } }
+      ],
+      loadData: [], // 可导入数据
+      nowUnColumns: [
+        { title: '序号', dataIndex: 'no', width: '9%', align: 'center' },
+        { title: '产品编码', dataIndex: 'productCode', width: '21%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '一级商城类目', dataIndex: 'shopCategoryName1', width: '16%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '二级商城类目', dataIndex: 'shopCategoryName2', width: '16%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '售价', dataIndex: 'price', width: '6%', align: 'right', customRender: function (text) { return (text != 'null' ? (text || text == 0) ? _this.toThousands(text) : '--':'--') } },
+        { title: '备注', dataIndex: 'remark', width: '14%', align: 'center', customRender: function (text) { return text || '--' } }
+      ],
+      unLoadData: [], // 导入错误数据
+      loading: false// 列表加载状态
+    }
+  },
+  methods: {
+    // 获取导入列表数据
+    getData () {
+      const _this = this
+      this.loading = true
+      const params = {
+        path: this.paramsData.path
+      }
+      shopProductParseExcel(params).then(res => {
+        this.loading = false
+        if (res.status == 200) {
+          if (res.data.rightList && res.data.rightList.length > 0) {
+            res.data.rightList.map((item, index) => {
+              item.no = index + 1
+            })
+          }
+          if (res.data.errorList && res.data.errorList.length > 0) {
+            res.data.errorList.map((item, index) => {
+              item.no = index + 1
+            })
+          }
+          _this.loadData = res.data.rightList || []
+          _this.unLoadData = res.data.errorList || []
+        }
+      })
+    },
+    // 确认导入
+    handleSubmit () {
+      if (this.loadData.length == 0) {
+        this.$message.warning('无可导入产品!')
+      } else {
+        this.$emit('ok', this.loadData)
+        this.isShow = false
+      }
+    },
+    // 导出错误项
+    handleError () {
+      const _this = this
+      if (_this.unLoadData.length < 1) {
+        _this.$message.info('暂无可导出的错误项~')
+        return
+      }
+      _this.spinning = true
+      hdExportExcel(shopProductExport, _this.unLoadData, '商城产品导出错误项', function () {
+        _this.spinning = false
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.loadData = []
+        this.unLoadData = []
+      } else {
+        this.getData()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .chooseImport-modal{
+    .chooseImport-con{
+      .red{
+        color: #f30;
+      }
+      .btn-con{
+        text-align: center;
+        margin: 30px 0 20px;
+        .button-cancel,.button-error{
+          font-size: 12px;
+        }
+      }
+    }
+  }
+</style>

+ 208 - 0
src/views/easyPassManagement/shoppingProducts/editProductModal.vue

@@ -0,0 +1,208 @@
+<template>
+  <a-modal
+    centered
+    class="edit-product-modal"
+    id="edit-product-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="编辑"
+    v-model="isShow"
+    @cancel="isShow = false"
+    :width="700">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-form-model
+        id="edit-product-form"
+        ref="ruleForm"
+        :model="form"
+        :rules="rules"
+        :label-col="formItemLayout.labelCol"
+        :wrapper-col="formItemLayout.wrapperCol"
+      >
+        <a-form-model-item label="产品编码">
+          {{ form.productCode }}
+        </a-form-model-item>
+        <a-form-model-item label="售价类型" prop="priceType">
+          <a-select v-model="form.priceType" id="edit-product-priceType" placeholder="请选择售价类型" allowClear @change="handlePriceType">
+            <a-select-option value="TERMINAL_PRICE">
+              终端价
+            </a-select-option>
+            <a-select-option value="CUSTOM_PRICE">
+              自定义
+            </a-select-option>
+          </a-select>
+        </a-form-model-item>
+        <a-form-model-item label="售价" prop="price">
+          <a-input-number
+            style="width:100%;"
+            id="edit-product-price"
+            :min="0.01"
+            :max="99999999"
+            :precision="2"
+            :step="0.1"
+            v-model="form.price"
+            :disabled="form.priceType==='TERMINAL_PRICE'"
+            placeholder="请输入产品售价"/>
+        </a-form-model-item>
+        <a-form-model-item label="热销产品" prop="hotFlag">
+          <v-select
+            v-model="form.hotFlag"
+            code="FlAG"
+            id="edit-product-hotFlag"
+            placeholder="请选择是否是热销产品"
+            allowClear
+            @change="handleHotProduct"
+          ></v-select>
+        </a-form-model-item>
+        <a-form-model-item label="热销产品优先级" prop="hotSort" v-if="form.hotFlag==='1'">
+          <a-input-number
+            style="width:100%;"
+            id="edit-product-money"
+            :min="0"
+            :max="99999999"
+            :precision="0"
+            :step="1"
+            v-model="form.hotSort"
+            placeholder="请输入正整数,数字越大优先级越低"/>
+        </a-form-model-item>
+      </a-form-model>
+      <div class="btn-cont">
+        <a-button id="edit-product-modal-back" @click="isShow = false" style="margin-right: 15px;">取消</a-button>
+        <a-button type="primary" id="edit-product-modal-save" @click="handleSave">保存</a-button>
+      </div>
+    </a-spin>
+  </a-modal>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+// 组件
+import { VSelect } from '@/components'
+// 接口
+import { shopProductDetail, shopProductSaveProduct } from '@/api/shopProduct'
+export default {
+  name: 'EditProductModal',
+  mixins: [commonMixin],
+  components: { VSelect },
+  props: {
+    openModal: {//  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    itemSn: {
+      type: String || Number,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      spinning: false,
+      isShow: this.openModal, //  是否打开弹框
+      formItemLayout: {
+        labelCol: { span: 4 },
+        wrapperCol: { span: 18 }
+      },
+      form: {
+        priceType: 'TERMINAL_PRICE', // 售价类型
+        price: '', // 售价
+        hotFlag: undefined, // 是否是热销产品
+        hotSort: undefined// 热销产品优先级
+      },
+      // 必填项校验
+      rules: {
+        priceType: [{ required: true, message: '请选择售价类型', trigger: 'change' }],
+        price: [{ required: true, message: '请输入产品售价', trigger: 'blur' }],
+        hotFlag: [{ required: true, message: '请选择是否是热销产品', trigger: 'change' }],
+        hotSort: [{ required: true, message: '请输入热销产品优先级', trigger: 'blur' }]
+      }
+    }
+  },
+  methods: {
+    // 售价类型  change
+    handlePriceType (val) {
+      if (val === 'TERMINAL_PRICE') {
+        this.form.price = this.form && (this.form.terminalPrice || this.form.terminalPrice == 0) ? this.form.terminalPrice : ''
+      }
+    },
+    // 获取编辑详情
+    getDetail () {
+      this.spinning = true
+      shopProductDetail({ shopProductSn: this.itemSn }).then(res => {
+        if (res.status == 200 && res.data) {
+          res.data.hotSort = res.data.hotFlag == '0' ? undefined : res.data.hotSort
+          this.form = res.data
+          this.spinning = false
+        } else {
+          this.form = {}
+        }
+      })
+    },
+    // 热销产品切换时清空数据
+    handleHotProduct (e) {
+      if (e == 0) {
+        this.form.hotSort = undefined
+      }
+    },
+    //  保存
+    handleSave () {
+      const _this = this
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          _this.spinning = true
+          _this.form.shopProductSn = _this.itemSn
+          shopProductSaveProduct(_this.form).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              setTimeout(() => {
+                _this.$emit('ok')
+                _this.isShow = false
+                _this.spinning = false
+              }, 1000)
+            } else {
+              _this.spinning = false
+            }
+          })
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    },
+    // 重置
+    reSetForm () {
+      this.form.priceType = 'TERMINAL_PRICE'
+      this.form.price = ''
+      this.form.hotFlag = undefined
+      this.form.hotSort = undefined
+      this.$refs.ruleForm.resetFields()
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.reSetForm()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+.edit-product-modal {
+	.ant-modal-body {
+		padding: 40px 40px 24px;
+	}
+	.btn-cont {
+		text-align: center;
+		margin: 35px 0 10px;
+	}
+  .ant-radio + span{
+    line-height: 40px;
+  }
+}
+</style>

+ 208 - 0
src/views/easyPassManagement/shoppingProducts/importGuideModal.vue

@@ -0,0 +1,208 @@
+<template>
+  <a-modal
+    centered
+    class="importGuide-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="导入"
+    v-model="isShow"
+    @cancel="isShow=false"
+    :width="750">
+    <div class="importGuide-con">
+      <div class="explain-con">
+        <div class="explain-item">
+          <div class="explain-tit">
+            <span>1</span>准备导入
+          </div>
+          <ul>
+            <li>1) “产品编码”必须是系统中已上线的产品</li>
+            <li>2) 商城类目必须是系统中已存在的商城类目</li>
+            <li>3) 售价非必填,若填写,产品售价为导入的售价,售价类型为自定义,若不填写,产品售价为终端价</li>
+          </ul>
+          <a-button
+            id="importGuide-download"
+            type="link"
+            icon="download"
+            style="padding: 0 0 0 23px;"
+            :loading="exportLoading"
+            @click="handleExport">下载导入模板</a-button>
+        </div>
+        <div class="explain-item">
+          <div class="explain-tit">
+            <span>2</span>上传数据文件
+          </div>
+          <p>目前支持的文件类型*.xls,*.xlsx.</p>
+          <div style="overflow: hidden;padding-left: 23px;">
+            <Upload
+              id="importGuide-attachList"
+              ref="importUpload"
+              :maxNums="1"
+              fileType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel"
+              uploadType="import"
+              :action="attachAction"
+              :uploadParams="uploadParams"
+              upText="添加文件"
+              @change="changeImport"></Upload>
+          </div>
+        </div>
+      </div>
+      <!-- 按钮 -->
+      <div class="btn-con">
+        <a-button
+          type="primary"
+          id="importGuide-nextStep"
+          size="large"
+          class="button-primary"
+          @click="handlerNextStep"
+          style="padding: 0 60px;">下一步</a-button>
+        <a-button
+          id="importGuide-cancel"
+          size="large"
+          class="button-cancel"
+          @click="isShow=false"
+          style="padding: 0 60px;margin-left: 15px;">取消</a-button>
+      </div>
+    </div>
+    <!-- 导入 -->
+    <chooseImportModal :openModal="openImportModal" :paramsData="paramsData" @close="handleClose" @ok="hanldeOk" />
+  </a-modal>
+</template>
+
+<script>
+import { hdExportExcel } from '@/libs/exportExcel'
+// 组件
+import ChooseImportModal from './chooseImportModal.vue'
+import { Upload } from '@/components'
+// 接口
+import { shopProductDownloadExcel } from '@/api/shopProduct'
+export default {
+  name: 'ImportGuideModal',
+  components: { ChooseImportModal, Upload },
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    params: {
+      type: Object,
+      default: null
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      exportLoading: false, // 导出按钮加载状态
+      openImportModal: false, //  打开导入详情弹窗
+      attachAction: process.env.VUE_APP_API_BASE_URL + '/upload', // 上传文件地址
+      paramsData: null, // 导入数据
+      uploadParams: {// 上传文件参数
+        savePathType: 'local'
+      }
+    }
+  },
+  methods: {
+    // 下一步
+    handlerNextStep () {
+      if (this.paramsData) {
+        this.openImportModal = true
+      } else {
+        this.$message.warning('添加文件后再进行下一步操作!')
+      }
+    },
+    // 上传文件  change
+    changeImport (file) {
+      if (file) {
+        this.paramsData = {
+          path: file
+        }
+      }
+    },
+    // 导入
+    hanldeOk (arr) {
+      if (arr && arr.length > 0) {
+        this.$emit('ok', arr)
+        this.isShow = false
+      }
+    },
+    // 关闭
+    handleClose () {
+      this.openImportModal = false
+      this.isShow = false
+    },
+    //  导出
+    handleExport () {
+      const _this = this
+      _this.spinning = true
+      _this.exportLoading = true
+      setTimeout(() => {
+        _this.exportLoading = false
+      }, 1000)
+      hdExportExcel(shopProductDownloadExcel, {}, '商城产品导入模板', function () {
+        _this.spinning = false
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.paramsData = null
+        this.$refs.importUpload.setFileList('')
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .importGuide-modal{
+    .importGuide-con{
+      .explain-con{
+        .explain-item{
+          margin-bottom: 10px;
+          .explain-tit{
+            font-weight: bold;
+            span{
+              display: inline-block;
+              width: 18px;
+              height: 18px;
+              line-height: 16px;
+              text-align: center;
+              margin-right: 5px;
+              border-radius: 50%;
+              border: 1px solid rgba(0, 0, 0, 0.3);
+            }
+          }
+          p{
+            margin: 8px 0;
+            padding-left: 23px;
+          }
+          ul{
+            list-style: none;
+            padding: 0;
+            padding-left: 23px;
+            margin: 0;
+            li{
+              line-height: 26px;
+            }
+          }
+        }
+        #importGuide-attachList{
+          width: 100%;
+        }
+      }
+      .btn-con{
+        margin: 10px 0 20px;
+        text-align: center;
+        .button-cancel{
+          font-size: 12px;
+        }
+      }
+    }
+  }
+</style>

+ 502 - 0
src/views/easyPassManagement/shoppingProducts/list.vue

@@ -0,0 +1,502 @@
+<template>
+  <div>
+    <a-card size="small" :bordered="false" class="shoppingProductsList-wrap searchBoxNormal">
+      <!-- 搜索条件 -->
+      <div ref="tableSearch" class="table-page-search-wrapper">
+        <a-form layout="inline" id="shoppingProductsList-form" @keyup.enter.native="$refs.table.refresh(true)">
+          <a-row :gutter="15">
+            <a-col :md="6" :sm="24">
+              <a-form-item label="产品名称">
+                <a-input id="shoppingProductsList-name" v-model.trim="queryParam.productName" allowClear placeholder="请输入产品名称"/>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-item label="产品编码/原厂编码">
+                <a-input id="shoppingProductsList-productCode" v-model.trim="queryParam.productCode" allowClear placeholder="请输入产品编码/原厂编码"/>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-item label="品牌">
+                <productBrand id="shoppingProductsList-productBrandSn" v-model="queryParam.productBrandSn"></productBrand>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-item label="产品分类">
+                <productType id="shoppingProductsList-productType" placeholder="请选择产品分类" @change="changeProductType" v-model="productType"></productType>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24" v-if="!itemCategorySn">
+              <a-form-item label="商城类目">
+                <a-cascader
+                  id="shoppingProductsList-category"
+                  expandTrigger="hover"
+                  :changeOnSelect="true"
+                  :fieldNames="fieldNames"
+                  :options="categoryOptions"
+                  placeholder="请选择商城类目"
+                  @change="changeProductsCategory"
+                  allowClear
+                  v-model="category"/>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-item label="热销产品">
+                <v-select code="FLAG" id="shoppingProductsList-hotFlag" v-model="queryParam.hotFlag" allowClear placeholder="请选择是否是热销产品"></v-select>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-item label="产品商城状态">
+                <v-select code="SHOP_PRODUCT_STATUS" id="shoppingProductsList-status" v-model="queryParam.status" allowClear placeholder="请选择产品商城状态"></v-select>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24" style="margin-bottom: 10px;">
+              <a-button type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="shoppingProductsList-refresh">查询</a-button>
+              <a-button style="margin-left: 5px" @click="resetSearchForm" :disabled="disabled" id="shoppingProductsList-reset">重置</a-button>
+            </a-col>
+          </a-row>
+        </a-form>
+      </div>
+    </a-card>
+    <a-card size="small" :bordered="false">
+      <!-- 操作按钮 -->
+      <div class="table-operator">
+        <a-button type="primary" id="shoppingProductsList-addProduct-btn" v-if="$hasPermissions('B_category_chooseProduct')&&itemCategorySn" @click="handleChooseProduct">选择产品</a-button>
+        <a-button type="primary" v-if="$hasPermissions('B_shoppingProducts_import')&&!itemCategorySn" id="shoppingProductsList-import-btn" @click="handleAddProduct">产品导入</a-button>
+        <span v-if="productNum&&productNum*1>0">
+          <a-button type="primary" v-if="$hasPermissions('B_groundingProducts_btn')" id="shoppingProductsList-grounding-btn" class="button-info" @click="changeStatus('1')">批量上架</a-button>
+          <a-button v-if="$hasPermissions('B_offProducts_btn')" @click="changeStatus('0')" id="shoppingProductsList-off-btn">批量下架</a-button>
+          <a-button
+            v-if="$hasPermissions('B_delProducts_btn')"
+            type="primary"
+            class="button-error"
+            id="shoppingProductsList-delProduct-btn"
+            ghost
+            @click="handleDel()">批量删除</a-button>
+          <span v-if="rowSelectionInfo&&rowSelectionInfo.selectedRowKeys.length>0">已选{{ rowSelectionInfo&&rowSelectionInfo.selectedRowKeys.length }}项</span>
+        </span>
+      </div>
+      <a-spin :spinning="spinning" tip="Loading...">
+        <!-- 列表 -->
+        <s-table
+          class="sTable fixPagination"
+          ref="table"
+          :style="{ height:itemCategorySn?(tableHeight-10+'px'):(tableHeight+70+'px')}"
+          size="small"
+          :rowKey="(record) => record.shopProductSn"
+          rowKeyName="shopProductSn"
+          :columns="columns"
+          :data="loadData"
+          :pageSize="20"
+          :row-selection="{ columnWidth: 40}"
+          @rowSelection="rowSelectionFun"
+          :scroll="{ y: itemCategorySn?tableHeight-100:tableHeight-20 }"
+          :defaultLoadData="false"
+          bordered>
+          <!-- 产品编码 -->
+          <template slot="productCode" slot-scope="text, record">
+            <span style="padding-right: 6px;">{{ record.productCode }}</span>
+            <a-badge v-if="record.hotFlag=='1'" count="热" :number-style="{ zoom:'80%' }"></a-badge>
+          </template>
+          <!-- 产品分类 -->
+          <template slot="productType" slot-scope="text, record">
+            <span v-if="record.productTypeName2 || record.productTypeName3">{{ record.productTypeName2 }} {{ record.productTypeName3 ? '>' : '' }} {{ record.productTypeName3 }}</span>
+            <span v-else>--</span>
+          </template>
+          <!-- 商城类目 -->
+          <template slot="categoryName" slot-scope="text, record">
+            <span v-if="record.categoryName1 || record.categoryName2">{{ record.categoryName1 }} {{ (record.categoryName1&&record.categoryName2) ? '>' : '' }} {{ record.categoryName2 }}</span>
+            <span v-else>--</span>
+          </template>
+          <!-- 售价类型 -->
+          <template slot="priceType" slot-scope="text, record">
+            <span v-if="record.priceType">{{ record.priceType=='TERMINAL_PRICE'?'终端价':'自定义' }}</span>
+            <span v-else>--</span>
+          </template>
+          <!-- 是否是热销产品 -->
+          <template slot="hotFlag" slot-scope="text, record">
+            <span v-if="record.hotFlag">{{ record.hotFlag=='1'?'是':'否' }}</span>
+            <span v-else>--</span>
+          </template>
+          <!-- 操作 -->
+          <template slot="action" slot-scope="text, record">
+            <a-button
+              size="small"
+              type="link"
+              v-if="$hasPermissions('B_editProducts_btn')"
+              @click="handleEdit(record)"
+              class="button-info"
+              :id="'chooseProductEdit-edit-btn'+record.id">编辑</a-button>
+            <a-button
+              size="small"
+              type="link"
+              @click="changeStatus('1',record)"
+              class="button-info"
+              v-if="$hasPermissions('B_groundingProducts_btn')&&record.status=='0'"
+              :id="'chooseProductEdit-top-btn'+record.id">上架</a-button>
+            <a-button
+              size="small"
+              type="link"
+              @click="changeStatus('0',record)"
+              class="button-info"
+              v-if="$hasPermissions('B_offProducts_btn')&&record.status!='0'"
+              :id="'chooseProductEdit-bottom-btn'+record.id">下架</a-button>
+            <a-button
+              size="small"
+              type="link"
+              class="button-error"
+              v-if="$hasPermissions('B_delProducts_btn')"
+              @click="handleDel(record)"
+              :id="'chooseProductEdit-del-btn'+record.id">删除</a-button>
+          </template>
+        </s-table>
+      </a-spin>
+    </a-card>
+    <!-- 添加产品 -->
+    <chooseProduct
+      ref="chooseProduct"
+      :chooseData="chooseDataList"
+      :openModal="showProModal"
+      @ok="addProductSuccess"
+      @close="closeProductModal"></chooseProduct>
+    <!-- 导入产品 -->
+    <importGuideModal :openModal="openGuideModal" @close="openGuideModal=false" @ok="hanldeOk" />
+    <!-- 编辑 -->
+    <editProductModal ref="editProduct" :itemSn="itemProductSn" :openModal="openEditModal" @close="openEditModal=false" @ok="hanldeEditOk" ></editProductModal>
+  </div>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+// 组件
+import { STable, VSelect } from '@/components'
+import importGuideModal from './importGuideModal.vue'
+import editProductModal from './editProductModal.vue'
+import productType from '@/views/common/productType.js'
+import productBrand from '@/views/common/productBrand.js'
+import chooseProduct from '@/views/easyPassManagement/shoppingManagement/chooseProductsModal'
+// 接口
+import { shopProductList, saveBatchProductExcel, shopProductDel, shopProductUpdateStatus, queryProductSnList, saveBatchProduct, queryExtList } from '@/api/shopProduct'
+export default {
+  name: 'ShoppingProductsList',
+  mixins: [commonMixin],
+  props: {
+    itemCategorySn: {// 当前行类目sn
+      type: String,
+      default: ''
+    }
+  },
+  components: { STable, VSelect, importGuideModal, editProductModal, productType, productBrand, chooseProduct },
+  data () {
+    return {
+      spinning: false,
+      disabled: false, //  查询、重置按钮是否可操作
+      tableHeight: 0, // 表格高度
+      // form表单label布局
+      formItemLayout: {
+        labelCol: { span: 6 },
+        wrapperCol: { span: 16 }
+      },
+      showProModal: false, // 打开添加产品弹窗
+      productType: [], // 产品分类
+      chooseDataList: [], // 已选产品sn集合
+      // 查询条件
+      queryParam: {
+        productName: '', // 产品名称
+        productCode: '', // 产品编码/原厂编码
+        productBrandSn: undefined, //  产品品牌
+        productTypeSn1: '', //  产品一级分类
+        productTypeSn2: '', //  产品二级分类
+        productTypeSn3: '', //  产品三级分类
+        hotFlag: undefined, // 是否是热销产品
+        status: undefined, // 状态
+        categorySn1: undefined, // 商城一级类目
+        categorySn2: undefined// 商城二级类目
+      },
+      productNum: null, // 列表数据总条数
+      categoryOptions: [], // 产品类目列表
+      fieldNames: { label: 'categoryName', value: 'categorySn', children: 'shopCategoryList' },
+      category: [], // 类目val
+      rowSelectionInfo: null, // 已选数据
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        this.spinning = true
+        if (this.itemCategorySn) {
+          this.queryParam.categorySn = this.itemCategorySn
+        }
+        return shopProductList(Object.assign(parameter, this.queryParam)).then(res => {
+          let data
+          if (res.status == 200) {
+            data = res.data
+            const no = (data.pageNo - 1) * data.pageSize
+            for (var i = 0; i < data.list.length; i++) {
+              data.list[i].no = no + i + 1
+            }
+            this.disabled = false
+            this.productNum = data.count
+          }
+          this.spinning = false
+          return data
+        })
+      },
+      openGuideModal: false, // 打开导入弹窗
+      openEditModal: false, // 打开编辑弹窗
+      itemProductSn: null// 当前行商城产品sn
+    }
+  },
+  computed: {
+    columns () {
+      const _this = this
+      const arr = [
+        { title: '序号', dataIndex: 'no', align: 'center', width: '50px' },
+        { title: '产品编码', dataIndex: 'productCode', width: '12%', align: 'center', scopedSlots: { customRender: 'productCode' } },
+        { title: '产品名称', dataIndex: 'productName', width: '22%', align: 'left', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '原厂编码', dataIndex: 'productOrigCode', align: 'center', width: '10%', customRender: function (text) { return text || '--' } },
+        { title: '品牌', dataIndex: 'productBrandName', align: 'center', width: '10%', customRender: function (text) { return text || '--' } },
+        { title: '产品分类', align: 'center', width: '15%', scopedSlots: { customRender: 'productType' } },
+        // { title: '售价', dataIndex: 'price', width: '7%', align: 'right', customRender: function (text) { return text || text == 0 ? _this.toThousands(text, 2) : '--' } },
+        { title: '售价类型', dataIndex: 'priceType', scopedSlots: { customRender: 'priceType' }, align: 'center', width: '10%' },
+        // { title: '终端价', dataIndex: 'terminalPrice', width: '7%', align: 'right', customRender: function (text) { return text || text == 0 ? _this.toThousands(text, 2) : '--' } },
+        // { title: '车主价', dataIndex: 'carOwnersPrice', width: '7%', align: 'right', customRender: function (text) { return text || text == 0 ? _this.toThousands(text, 2) : '--' } },
+        { title: '热销产品', dataIndex: 'hotFlag', scopedSlots: { customRender: 'hotFlag' }, align: 'center', width: '8%' },
+        { title: '易码通优先级', dataIndex: 'hotSort', align: 'center', width: '7%', customRender: function (text) { return (text || text == 0) ? text : '--' } },
+        { title: '添加时间', dataIndex: 'createDate', align: 'center', width: '10%', customRender: function (text) { return text || '--' } },
+        { title: '产品商城状态', dataIndex: 'statusDictValue', align: 'center', width: '6%', customRender: function (text) { return text || '--' } },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: '14%', align: 'center' }
+      ]
+      // 售价
+      if (_this.$hasPermissions('M_shoppingProductsList_salesPrice')) {
+        arr.splice(6, 0, { title: '售价', dataIndex: 'price', width: '7%', align: 'right', customRender: function (text) { return text || text == 0 ? _this.toThousands(text, 2) : '--' } })
+      }
+      // 终端价
+      const pos = _this.$hasPermissions('M_shoppingProductsList_salesPrice') ? 8 : 7
+      if (_this.$hasPermissions('M_shoppingProductsList_terminalPrice')) {
+        arr.splice(pos, 0, { title: '终端价', dataIndex: 'terminalPrice', width: '7%', align: 'right', customRender: function (text) { return text || text == 0 ? _this.toThousands(text, 2) : '--' } })
+      }
+      // 车主价
+      if (_this.$hasPermissions('M_shoppingProductsList_carOwnersPrice')) {
+        arr.splice((pos * 1 + 1), 0, { title: '车主价', dataIndex: 'carOwnersPrice', width: '7%', align: 'right', customRender: function (text) { return text || text == 0 ? _this.toThousands(text, 2) : '--' } })
+      }
+      if (!_this.itemCategorySn) {
+        arr.splice(6, 0, { title: '商城类目', scopedSlots: { customRender: 'categoryName' }, width: '15%', align: 'center' })
+      }
+      return arr
+    }
+  },
+  methods: {
+    // 表格选中项
+    rowSelectionFun (obj) {
+      this.rowSelectionInfo = obj || null
+    },
+    // 选择产品
+    async handleChooseProduct () {
+      // 回显已选择产品并禁用
+      const res = await queryProductSnList({})
+      if (res.status == 200) {
+        this.chooseDataList = res.data || []
+      }
+      this.showProModal = true
+    },
+    // 选择产品 成功
+    addProductSuccess (list) {
+      const _this = this
+      _this.spinning = true
+      const newList = list.map(item => {
+        return {
+          categorySn: _this.$route.params.sn,
+          productSn: item.productSn,
+          productCode: item.code,
+          priceType: 'TERMINAL_PRICE',
+          price: item.terminalPrice
+        }
+      })
+      _this.hanldeOk(newList, 'chooseProduct')
+    },
+    // 获取产品类目列表
+    getCategoryList () {
+      const _this = this
+      _this.spinning = true
+      queryExtList({}).then(res => {
+        if (res.status == 200) {
+          this.categoryOptions = res.data || []
+        }
+        _this.spinning = false
+      })
+    },
+    // 关闭选择弹窗
+    closeProductModal () {
+      this.showProModal = false
+      this.chooseDataList = []
+    },
+    // 导入产品
+    handleAddProduct () {
+      this.openGuideModal = true
+    },
+    // 导入产品成功
+    hanldeOk (list, typeVal) {
+      const _this = this
+      _this.spinning = true
+      const ajaxName = (typeVal && typeVal === 'chooseProduct') ? saveBatchProduct : saveBatchProductExcel
+      ajaxName(list).then(res => {
+        if (res.status == 200) {
+          _this.$message.success(res.message)
+          _this.$nextTick(() => {
+            _this.showProModal = false
+            _this.$refs.table.refresh(true)
+          })
+        }
+        _this.spinning = false
+      })
+    },
+    //  重置
+    resetSearchForm () {
+      this.queryParam.productName = ''
+      this.queryParam.productCode = ''
+      this.queryParam.productBrandSn = undefined
+      this.queryParam.productTypeSn1 = ''
+      this.queryParam.productTypeSn2 = ''
+      this.queryParam.productTypeSn3 = ''
+      this.queryParam.hotFlag = undefined
+      this.queryParam.status = undefined
+      this.queryParam.categorySn1 = undefined
+      this.queryParam.categorySn2 = undefined
+      this.productType = []
+      this.category = []
+      this.$refs.table.refresh(true)
+    },
+    // 编辑
+    handleEdit (row) {
+      this.itemProductSn = row.shopProductSn
+      this.openEditModal = true
+      const _this = this
+      this.$nextTick(() => {
+        _this.$refs.editProduct.getDetail()
+      })
+    },
+    // 编辑成功
+    hanldeEditOk () {
+      this.itemProductSn = null
+      this.$refs.table.refresh()
+    },
+    //  产品分类  change
+    changeProductType (val, opt) {
+      this.queryParam.productTypeSn1 = val[0] ? val[0] : ''
+      this.queryParam.productTypeSn2 = val[1] ? val[1] : ''
+      this.queryParam.productTypeSn3 = val[2] ? val[2] : ''
+    },
+    // 商城类目
+    changeProductsCategory (val) {
+      this.queryParam.categorySn1 = val[0] ? val[0] : undefined
+      this.queryParam.categorySn2 = val[1] ? val[1] : undefined
+    },
+    // 删除
+    handleDel (row) {
+      const _this = this
+      let shopProductSnList = []
+      if (row && Object.keys(row).length > 0) {
+        shopProductSnList.push(row.shopProductSn)
+      } else {
+        shopProductSnList = _this.rowSelectionInfo && _this.rowSelectionInfo.selectedRowKeys ? _this.rowSelectionInfo.selectedRowKeys : []
+      }
+      if (shopProductSnList && shopProductSnList.length == 0) {
+        this.$message.warning('请在列表中勾选产品!')
+        return
+      }
+      this.confirmDel(shopProductSnList)
+    },
+    // 确认删除
+    confirmDel (shopProductSnList) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确认删除产品吗?',
+        centered: true,
+        onOk () {
+          _this.spinning = true
+          shopProductDel({ shopProductSnList }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$refs.table.clearSelected()
+              _this.$refs.table.refresh()
+            }
+            _this.spinning = false
+          })
+        }
+      })
+    },
+    // 批量上、下架
+    changeStatus (type, row) {
+      let newRow = []
+      if (!row) {
+        newRow = this.rowSelectionInfo && this.rowSelectionInfo.selectedRowKeys
+        if (!this.rowSelectionInfo || (newRow.length < 1)) {
+          this.$message.warning('请在列表中进行勾选!')
+          return false
+        }
+      } else {
+        newRow.push(row.shopProductSn)
+      }
+      this.handleChangeStatus(type, newRow)
+    },
+    // 确定上、下架
+    handleChangeStatus (typeVal, ajaxData) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确认' + (typeVal === '0' ? '下架' : '上架') + '产品吗?',
+        centered: true,
+        onOk () {
+          _this.spinning = true
+          shopProductUpdateStatus({ shopProductSnList: ajaxData, status: typeVal }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$refs.table.clearSelected()
+              _this.$refs.table.refresh()
+            }
+            _this.spinning = false
+          })
+        }
+      })
+    },
+    // 初始化
+    pageInit () {
+      const _this = this
+      if (!_this.itemCategorySn) {
+        _this.getCategoryList()
+      }
+      _this.closeProductModal()
+      _this.$nextTick(() => { // 页面渲染完成后的回调
+        _this.setTableH()
+      })
+    },
+    // 计算表格高度
+    setTableH () {
+      const tableSearchH = this.$refs.tableSearch.offsetHeight
+      this.tableHeight = window.innerHeight - tableSearchH - 240
+    }
+  },
+  watch: {
+    '$store.state.app.winHeight' (newValue, oldValue) { //  窗口变更时,需同时更改表格高度
+      this.setTableH()
+    }
+  },
+  mounted () {
+    if (!this.$store.state.app.isNewTab) { // 页签刷新时调用
+      this.pageInit()
+      this.resetSearchForm()
+    }
+  },
+  activated () {
+    // 如果是新页签打开,则重置当前页面
+    if (this.$store.state.app.isNewTab) {
+      this.pageInit()
+      this.resetSearchForm()
+    }
+    // 仅刷新列表,不重置页面
+    if (this.$store.state.app.updateList) {
+      this.pageInit()
+      this.$refs.table.refresh(true)
+    }
+  }
+}
+</script>

+ 1 - 1
src/views/power/dataDictionary/codeItemModal.vue

@@ -72,7 +72,7 @@
                 v-decorator="['formData.sort', {
                   initialValue: formData.sort,
                   rules: [{ required: true, message: '请输入排序值!' }] }]"
-                :max="999999"
+                :max="99999999"
                 :min="0"
               />
             </a-form-item>

+ 1 - 1
src/views/power/dataDictionary/codeModal.vue

@@ -35,7 +35,7 @@
             v-decorator="['formData.sort', {
               initialValue: formData.sort,
               rules: [{ required: true, message: '请输入排序值!' }] }]"
-            :max="999999"
+            :max="99999999"
             :min="0"
           />
         </a-form-item>

+ 1 - 1
src/views/power/menu/childModal.vue

@@ -126,7 +126,7 @@
             v-decorator="['formData.sort', {
               initialValue: formData.sort,
               rules: [] }]"
-            :max="999999"
+            :max="99999999"
             :min="0"
           />
         </a-form-item>

+ 1 - 1
src/views/power/menu/menu.vue

@@ -150,7 +150,7 @@
               v-decorator="['formData.sort', {
                 initialValue: formData.sort,
                 rules: [] }]"
-              :max="999999"
+              :max="99999999"
               :min="0"
             />
           </a-form-item>

+ 1 - 1
src/views/power/register/register.vue

@@ -89,7 +89,7 @@
               v-decorator="['formData.index', {
                 initialValue: formData.index,
                 rules: [{ required: true, message: '请输入排序值!' }] }]"
-              :max="999999"
+              :max="99999999"
               :min="0"
             />
           </a-form-item>

+ 4 - 4
src/views/promotionRulesManagement/dealerPromotions/sendAmountModal.vue

@@ -51,7 +51,7 @@
                 id="promotionList-gateValue"
                 v-model="form.gateValue"
                 :min="0"
-                :max="999999"
+                :max="99999999"
                 :precision="2"
                 size="small"/> %作为配额
               <a-tooltip title="如:填写100%,则购买10000元门槛产品,可享受10000配额购买正价产品,根据门槛金额动态调整配额">
@@ -62,7 +62,7 @@
               购买门槛产品满最低金额 <a-input-number
                 id="promotionList-gateValue"
                 v-model="form.gateValue"
-                :max="999999"
+                :max="99999999"
                 :min="0"
                 :precision="2"
                 size="small"/>元,不限制配额。
@@ -73,7 +73,7 @@
                 id="promotionList-gateValue"
                 v-model="form.gateValue"
                 :min="0"
-                :max="999999"
+                :max="99999999"
                 :precision="2"
                 size="small"/>
               元门槛产品,可使用
@@ -81,7 +81,7 @@
                 v-model="form.quotaAmount"
                 id="promotionList-quotaAmount"
                 :min="0"
-                :max="999999"
+                :max="99999999"
                 :precision="2"
                 size="small"/>
               元配额,采购规则中的正价商品(配额算销售额)

+ 1 - 1
src/views/promotionRulesManagement/promotionManagement/edit.vue

@@ -40,7 +40,7 @@
                   placeholder="请输入排序数字(数字越大越靠后)"
                   v-model="form.sort"
                   :min="0"
-                  :max="999999"/>
+                  :max="99999999"/>
               </a-form-model-item>
             </a-col>
             <a-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">

+ 3 - 3
src/views/promotionRulesManagement/promotionRules/choosePriceProductsModal.vue

@@ -35,7 +35,7 @@
                   id="choosePosPriceProducts-orderGoodsQty"
                   v-model="orderGoodsQty"
                   :min="1"
-                  :max="999999"
+                  :max="99999999"
                   :precision="0"
                   style="width: 85%;margin-right: 5px;"
                   placeholder="请输入限制数量(1~999999)"
@@ -76,7 +76,7 @@
             v-model="record.orderGoodsQty"
             :precision="0"
             :min="1"
-            :max="999999"
+            :max="99999999"
             placeholder="请输入限制数量(1~999999)"
             style="width: 50%;margin-left: 5px;" />
         </template>
@@ -88,7 +88,7 @@
             v-model="record.goodsPrice"
             :precision="2"
             :min="0.1"
-            :max="999999"
+            :max="99999999"
             placeholder="请输入限制数量(0.1~999999)"
             style="width: 100%;" />
         </template>