lilei 1 napja
szülő
commit
70e49ff816

+ 30 - 47
src/config/router.config.js

@@ -95,56 +95,39 @@ export const asyncMobileRouterMap = [
     meta: {
       title: '首页'
     },
-    redirect: '/inventoryManagement',
+    redirect: '/home',
     children: [
        {
-         path: '/inventoryManagement',
-         redirect: '/inventoryManagement/inventoryQuery',
-         component: PageView,
+         path: '/home',
+         name: 'home',
+         component: () => import(/* webpackChunkName: "home" */ '@/mobile/Home'),
+         meta: {
+           title: '首页',
+           icon: 'home',
+           hidden: true
+         }
+       },
+       {
+         path: '/inventoryQuery',
+         name: 'inventoryQuery',
+         component: () => import(/* webpackChunkName: "inventoryManagement" */ '@/mobile/inventoryManagement/inventoryQuery/list.vue'),
+         meta: {
+           title: '库存查询',
+           icon: 'monitor',
+           hidden: true,
+           permission: 'M_inventoryQueryList'
+         }
+       },
+       {
+         path: 'productPricing',
+         name: 'productPricing',
+         component: () => import(/* webpackChunkName: "productManagement" */ '@/mobile/productManagement/productPricing/list.vue'),
          meta: {
-           title: '库存管理',
-           icon: 'shop',
-           permission: 'M_inventoryManagement'
-         },
-         children: [
-           {
-             path: '/inventoryManagement/inventoryQuery',
-             redirect: '/inventoryManagement/inventoryQuery/list',
-             name: 'inventoryQuery',
-             component: BlankLayout,
-             meta: {
-               title: '库存查询',
-               icon: 'monitor',
-               permission: 'M_inventoryQueryList'
-             },
-             hideChildrenInMenu: true,
-             children: [
-               {
-                 path: 'list',
-                 name: 'inventoryQueryList',
-                 component: () => import(/* webpackChunkName: "inventoryManagement" */ '@/views/inventoryManagement/inventoryQuery/list.vue'),
-                 meta: {
-                   title: '库存列表',
-                   icon: 'monitor',
-                   hidden: true,
-                   permission: 'M_inventoryQueryList'
-                 }
-               },
-               {
-                 path: 'warehouseDetail/:sn/:warehouseSn',
-                 name: 'inventoryQueryWarehouseDetail',
-                 component: () => import(/* webpackChunkName: "inventoryManagement" */ '@/views/inventoryManagement/inventoryQuery/warehouseDetail.vue'),
-                 meta: {
-                   title: '出入库明细',
-                   icon: 'monitor',
-                   replaceTab: true,
-                   hidden: true,
-                   permission: 'B_inventoryQuery_rkDetail'
-                 }
-               }
-             ]
-           },
-           ]
+           title: '产品定价',
+           icon: 'transaction',
+           hidden: true,
+           permission: 'M_productPricingList'
+         }
        }
     ]
   },

+ 71 - 31
src/layouts/MobileLayout.vue

@@ -1,53 +1,93 @@
 <script>
+import { mixin } from '@/utils/mixin'
+import { mapActions, mapGetters } from 'vuex'
 export default {
-  name: 'MobileLayout'
+  name: 'MobileLayout',
+  components: {
+  },
+  mixins: [mixin],
+  computed: {
+    ...mapGetters(['nickname', 'avatar'])
+  },
+  methods: {
+    ...mapActions(['Logout']),
+    handleLogout () {
+      this.$confirm({
+        title: '提示',
+        content: '确定要退出登录吗 ?',
+        centered: true,
+        onOk: () => {
+          return this.Logout({}).then(() => {
+            setTimeout(() => {
+              this.$router.push({ path: '/user/login' })
+            }, 16)
+          }).catch(err => {
+            this.$message.error({
+              title: '错误',
+              description: err.message
+            })
+          })
+        },
+        onCancel () {
+        }
+      })
+    },
+    handleToHome () {
+      this.$router.push({ name: 'home' })
+    }
+  }
 }
 </script>
 
 <template>
   <a-layout id="components-layout-mobile-fixed">
     <a-layout-header :style="{ position: 'fixed', zIndex: 1, width: '100%',padding:'0 10px' }">
-      <div class="logo" />
-      <a-menu
-        theme="dark"
-        mode="horizontal"
-        :default-selected-keys="['2']"
-        :style="{ lineHeight: '64px' }"
-      >
-        <a-menu-item key="1">
-          nav 1
-        </a-menu-item>
-        <a-menu-item key="2">
-          nav 2
-        </a-menu-item>
-        <a-menu-item key="3">
-          nav 3
-        </a-menu-item>
-      </a-menu>
+      <div class="logo">
+        运营中心系统
+      </div>
+      <div class="user-wrapper">
+        <a href="javascript:;" style="margin:0 10px;color: #fff;" @click="handleToHome">
+          <a-icon type="home"/>
+          <span style="margin: 0 5px;">返回首页</span>
+        </a>
+        <a-icon type="user" />
+        <span style="margin: 0 5px;">{{ nickname }}</span>
+        <a href="javascript:;" style="margin-left: 10px;color: #ff5500;" @click="handleLogout">
+          <a-icon type="logout"/>
+          <span style="margin: 0 5px;">退出</span>
+        </a>
+      </div>
     </a-layout-header>
-    <a-layout-content :style="{ padding: '0 50px', marginTop: '64px' }">
-      <a-breadcrumb :style="{ margin: '16px 0' }">
-        <a-breadcrumb-item>Home</a-breadcrumb-item>
-        <a-breadcrumb-item>List</a-breadcrumb-item>
-        <a-breadcrumb-item>App</a-breadcrumb-item>
-      </a-breadcrumb>
-      <div :style="{ background: '#fff', padding: '24px', minHeight: '380px' }">
+    <a-layout-content :style="{ padding: '0', marginTop: '64px' }">
+      <div style="padding:10px;">
         <keep-alive>
           <router-view :key="$route.name"></router-view>
         </keep-alive>
       </div>
     </a-layout-content>
-    <a-layout-footer :style="{ textAlign: 'center' }">
-      Ant Design ©2018 Created by Ant UED
-    </a-layout-footer>
   </a-layout>
 </template>
 <style>
+.envtipsBox{
+  display:none;
+}
+#components-layout-mobile-fixed{
+  height: 100%;
+  overflow: auto;
+}
 #components-layout-mobile-fixed .logo {
-  width: 120px;
+  width: 100px;
   height: 31px;
-  background: rgba(255, 255, 255, 0.2);
-  margin: 16px 24px 16px 0;
+  line-height:31px;
+  color: #fff;
+  margin: 16px 15px 16px 0;
   float: left;
+  text-align: center;
+  font-weight: 900;
+}
+#components-layout-mobile-fixed .user-wrapper{
+  float: right;
+  z-index: 10000;
+  color: #fff;
 }
 </style>

+ 54 - 0
src/mobile/Home.vue

@@ -0,0 +1,54 @@
+<template>
+  <div class="home">
+    <div class="nav-items col-1" @click="toPage('inventoryQuery')" v-if="$hasPermissions('M_inventoryQueryList')">
+      <a-icon type="search" />
+      <div>库存查询</div>
+    </div>
+    <div class="nav-items col-2" @click="toPage('productPricing')" v-if="$hasPermissions('M_productPricingList')">
+      <a-icon type="euro" />
+      <div>产品定价</div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  methods: {
+    toPage (page) {
+      this.$router.push({ name: page })
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .home {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    height: calc(100vh - 84px);
+    padding: 0 50px;
+    .nav-items {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      margin-top: 20px;
+      color: #fff;
+      width: 100%;
+      border-radius: 10px;
+      padding: 20px;
+      div {
+        margin-left: 15px;
+        font-size: 20px;
+      }
+      font-size: 30px;
+    }
+    .col-1{
+      background-color: #55aa00;
+    }
+    .col-2{
+      background-color: #0055aa;
+    }
+  }
+</style>

+ 188 - 0
src/mobile/inventoryManagement/inventoryQuery/detailModal.vue

@@ -0,0 +1,188 @@
+<template>
+  <a-modal
+    centered
+    class="inventoryQueryDetail-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="库存详情"
+    v-model="isShow"
+    @cancel="isShow=false"
+    width="100%">
+    <!-- 合计 -->
+    <a-alert type="info" style="margin-bottom:10px">
+      <div class="ftext" slot="message">
+        可用库存总数量:<strong>{{ (currentStock&&(currentStock.currentStockQty || currentStock.currentStockQty==0)) ? currentStock.currentStockQty : '--' }}个</strong>;
+        <span v-if="$hasPermissions('B_inventoryQuery_detail_costPrice')">可用库存总成本:<strong>{{ (currentStock&&(currentStock.currentStockCost || currentStock.currentStockCost==0)) ? toThousands(currentStock.currentStockCost) : '--' }}</strong>。</span>
+      </div>
+    </a-alert>
+    <!-- 库存详情 -->
+    <s-table
+      v-if="openModal"
+      class="sTable"
+      ref="table"
+      size="small"
+      :rowKey="(record) => record.id"
+      :columns="columns"
+      :data="loadData"
+      :scroll="{ y: 500 }"
+    >
+      <template slot="productInfo" slot-scope="text, record">
+        <div class="tr-row">
+          <div class="tr-title">{{ record.productName }}</div>
+          <div>产品编码:<span class="code">{{ record.productCode }}</span></div>
+          <div>原厂编码:<span>{{ record.productOrigCode ||'--' }}</span></div>
+          <div>仓库仓位:<span>{{ record.warehouseName }}</span>><span>{{ record.warehouseLocationName }}</span></div>
+          <div>
+            库存数量:
+            <span style="vertical-align: middle;margin-right:5px;color:red"> {{ (record.currentQty ||record.currentQty==0)?record.currentQty:'--' }}</span>
+            <a-tooltip placement="bottom" v-if="record.lockFlag==1" >
+              <template slot="title">
+                采购入库的库存为锁定库存
+              </template>
+              <a-badge count="锁" v-if="record.lockFlag==1" :number-style="{ zoom:'80%' }"></a-badge>
+            </a-tooltip>
+          </div>
+          <div v-if="$hasPermissions('B_inventoryQuery_detail_costPrice')">成本单价:<span>{{ toThousands(record.putCost) }}</span></div>
+          <div>入库类型:<span>{{ record.putBizTypeDictValue }}</span></div>
+          <div>入库时间:<span>{{ record.putTime }}</span></div>
+        </div>
+      </template>
+    </s-table>
+    <div class="btn-cont">
+      <a-button id="inventoryQueryDetail-detail-modal-back" @click="isShow = false">返回列表</a-button>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+import { STable } from '@/components'
+import { stockDetailList, stockDetailCount } from '@/api/stock'
+export default {
+  name: 'InventoryQueryDetailModal',
+  mixins: [commonMixin],
+  components: { STable },
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    itemId: {
+      type: [Number, String],
+      default: ''
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        return stockDetailList(Object.assign(parameter, { stockSn: this.itemId })).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
+              data.list[i].productOrigCode = data.list[i].productOrigCode.trim()
+            }
+            this.disabled = false
+            // 总计
+            this.getTotal(Object.assign(parameter, { stockSn: this.itemId }))
+          }
+          return data
+        })
+      },
+      currentStock: { // 合计信息
+        currentQty: '',
+        putCost: ''
+      }
+    }
+  },
+  computed: {
+    stockQty () { //  库存总数量 合计
+      const currentStockQty = Number(this.currentStock.currentStockQty) || 0
+      const freezeStockQty = Number(this.currentStock.freezeStockQty) || 0
+      return currentStockQty + freezeStockQty
+    },
+    stockCost () { //  库存总成本 合计
+      const currentStockCost = Number(this.currentStock.currentStockCost) || 0
+      const freezeStockCost = Number(this.currentStock.freezeStockCost) || 0
+      return ((currentStockCost * 1000 + freezeStockCost * 1000) / 1000).toFixed(2)
+    },
+    columns () {
+      const arr = [
+        { title: '序号', dataIndex: 'no', width: '40px', align: 'center' },
+        { title: '产品信息', scopedSlots: { customRender: 'productInfo' }, width: '90%', align: 'center' }
+      ]
+      return arr
+    }
+  },
+  methods: {
+    // 合计
+    getTotal (param) {
+      stockDetailCount(param).then(res => {
+        if (res.status == 200 && res.data) {
+          this.currentStock = res.data
+        } else {
+          this.currentStock = { // 合计信息
+            currentQty: '',
+            putCost: ''
+          }
+        }
+      })
+    },
+    // 重置
+    resetPage () {
+      this.currentStock = { // 合计信息
+        currentQty: '',
+        putCost: ''
+      }
+      this.$refs.table.clearTable()
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.resetPage()
+        this.$emit('close')
+        this.$store.state.app.curActionPermission = ''
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .inventoryQueryDetail-modal{
+    .btn-cont {
+      text-align: center;
+      margin: 5px 0 10px;
+    }
+    .tr-row{
+      text-align: left;
+      .tr-title{
+        font-weight: bold;
+      }
+      > div{
+        padding: 2px 0;
+        color: #666;
+        span{
+          color: #222;
+        }
+        .code{
+          color: #00aaff;
+        }
+        .nums{
+          color: #ff0000;
+        }
+      }
+    }
+  }
+</style>

+ 107 - 0
src/mobile/inventoryManagement/inventoryQuery/exportExcelModal.vue

@@ -0,0 +1,107 @@
+<template>
+  <a-modal
+    centered
+    :footer="null"
+    :maskClosable="false"
+    class="export-excel-modal"
+    title="选择导出方式"
+    v-model="isShow"
+    @cancel="isShow=false"
+    :width="600">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-form-model
+        id="export-excel-form"
+        ref="ruleForm"
+        :model="form"
+        :rules="rules"
+        :label-col="formItemLayout.labelCol"
+        :wrapper-col="formItemLayout.wrapperCol"
+      >
+        <a-form-model-item label="导出库存" prop="exportType">
+          <a-radio-group v-model="form.exportType" id="export-excel-radio">
+            <a-radio value="all" id="export-excel-radio-all">所有</a-radio>
+            <a-radio value="type" id="export-excel-radio-type">分类汇总导出</a-radio>
+          </a-radio-group>
+        </a-form-model-item>
+      </a-form-model>
+      <div class="btn-cont">
+        <a-button type="primary" id="export-excel-save" @click="handleSave()">导出</a-button>
+        <a-button id="export-excel-back" @click="handleCancel" style="margin-left: 15px;">取消</a-button>
+      </div>
+    </a-spin>
+  </a-modal>
+</template>
+
+<script>
+export default {
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    itemData: {
+      type: Object,
+      default: () => {
+        return null
+      }
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      form: {
+        exportType: 'all' // 导出方式
+      },
+      rules: {
+        exportType: [{ required: true, message: '请选择导出方式', trigger: 'change' }]
+      },
+      formItemLayout: {
+        labelCol: { span: 6 },
+        wrapperCol: { span: 18 }
+      },
+      spinning: false
+    }
+  },
+  methods: {
+    // 确认
+    handleSave (isPrint) {
+      const _this = this
+      this.$store.state.app.curActionPermission = 'B_inventoryQuery_export'
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          _this.$emit('ok', _this.form.exportType)
+          _this.isShow = false
+        } else {
+          return false
+        }
+      })
+    },
+    // 取消选择分类
+    handleCancel () {
+      this.isShow = false
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.$refs.ruleForm.resetFields()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .export-excel-modal{
+    .btn-cont {
+      text-align: center;
+      margin: 35px 0 10px;
+    }
+  }
+</style>

+ 334 - 0
src/mobile/inventoryManagement/inventoryQuery/list.vue

@@ -0,0 +1,334 @@
+<template>
+  <div>
+    <a-card size="small" :bordered="false" class="searchBoxNormal">
+      <!-- 搜索条件 -->
+      <div ref="tableSearch" class="table-page-search-wrapper">
+        <a-form layout="inline" id="inventoryQueryList-form" labelAlign="right" @keyup.enter.native="$refs.table.refresh(true)">
+          <a-row :gutter="15">
+            <a-col :md="6" :sm="24">
+              <a-form-item label="产品编码">
+                <a-input id="inventoryQueryList-productCode" v-model.trim="queryParam.productCode" allowClear placeholder="请输入产品编码"/>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-item label="原厂编码">
+                <a-input id="inventoryQueryList-productOrigCode" v-model.trim="queryParam.productOrigCode" allowClear placeholder="请输入原厂编码"/>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-item label="产品品牌">
+                <ProductBrand id="inventoryQueryList-productBrandSn" v-model="queryParam.productBrandSn"></ProductBrand>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-item label="产品分类">
+                <ProductType id="inventoryQueryList-productType" placeholder="请选择产品分类" @change="changeProductType" v-model="productType"></ProductType>
+              </a-form-item>
+            </a-col>
+            <template v-if="advanced">
+              <a-col :md="6" :sm="24">
+                <a-form-item label="产品名称">
+                  <a-input id="inventoryQueryList-productName" v-model.trim="queryParam.productName" allowClear placeholder="请输入产品名称"/>
+                </a-form-item>
+              </a-col>
+              <a-col :md="6" :sm="24">
+                <a-form-item label="仓库">
+                  <warehouse isPermission v-model="queryParam.warehouseSn" id="inventoryQueryList-warehouseSn" placeholder="请选择仓库" />
+                </a-form-item>
+              </a-col>
+              <a-col :md="4" :sm="24">
+                <a-form-item label="库存情况">
+                  <a-checkbox style="float:right" v-model="queryParam.zeroQtyFlag" id="inventoryQueryList-zeroQtyFlag">只查看有库存</a-checkbox>
+                </a-form-item>
+              </a-col>
+            </template>
+            <a-col :md="6" :sm="24" style="text-align: center;">
+              <a-button type="primary" @click="$refs.table.refresh()" :disabled="disabled" id="inventoryQueryList-refresh">查询</a-button>
+              <a-button style="margin-left: 5px" @click="resetSearchForm" :disabled="disabled" id="inventoryQueryList-reset">重置</a-button>
+              <a @click="advanced=!advanced" style="margin-left: 5px" id="inventoryQueryList-advanced">
+                {{ advanced ? '收起' : '展开' }}
+                <a-icon :type="advanced ? 'up' : 'down'"/>
+              </a>
+            </a-col>
+          </a-row>
+        </a-form>
+      </div>
+    </a-card>
+
+    <a-card size="small" :bordered="false" class="inventoryQueryList-wrap">
+      <a-spin :spinning="spinning" tip="Loading...">
+        <!-- 合计 -->
+        <div class="ftext tongji-bar">
+          <div>
+            可用库存总数量:<strong>{{ (currentStock&&(currentStock.currentStockQty || currentStock.currentStockQty==0)) ? currentStock.currentStockQty : '--' }}个</strong>;
+          </div>
+          <div v-if="$hasPermissions('M_inventoryQueryList_costPrice')">可用库存总成本:<strong>{{ (currentStock&&(currentStock.currentStockCost || currentStock.currentStockCost==0)) ? toThousands(currentStock.currentStockCost) : '--' }}</strong>。</div>
+        </div>
+        <!-- 列表 -->
+        <s-table
+          class="sTable"
+          ref="table"
+          size="small"
+          :rowKey="(record) => record.id"
+          :columns="columns"
+          :pageSize="20"
+          :data="loadData"
+          :defaultLoadData="false"
+        >
+          <template slot="productInfo" slot-scope="text, record">
+            <div class="tr-row">
+              <div class="tr-title">{{ record.productName }}</div>
+              <div>产品编码:<span class="code">{{ record.productCode }}</span></div>
+              <div>仓库:<span>{{ record.warehouseName }}</span></div>
+              <div>产品品牌:<span>{{ record.productBrandName }}</span></div>
+              <div>可用库存数量:<span class="nums">{{ record.currentStockQty }}</span> {{ record.productUnit }}</div>
+              <div v-if="$hasPermissions('M_inventoryQueryList_costPrice')">可用库存成本:<span>{{ toThousands(record.currentStockCost) }}</span></div>
+              <div>货位编号:<span>{{ record.stackPlaceEntity && record.stackPlaceEntity.stackPlaceCode||'--' }}</span></div>
+              <div>最后入库时间:<span>{{ record.lastStockTime }}</span></div>
+            </div>
+          </template>
+          <!-- 操作 -->
+          <template slot="action" slot-scope="text, record">
+            <a-button
+              v-if="$hasPermissions('B_inventoryQuery_detail')"
+              size="small"
+              type="link"
+              class="button-success"
+              style="margin:10px 0;"
+              @click="goDetail(record)"
+              :id="'inventoryQueryList-detail-'+record.id">库存详情</a-button>
+            <a-button
+              v-if="$hasPermissions('B_inventoryQuery_rkDetail')"
+              size="small"
+              type="link"
+              class="button-warning"
+              @click="goWarehouseDetail(record)"
+              :id="'inventoryQueryList-whousedetail-'+record.id">出入库明细</a-button>
+            <span v-if="!$hasPermissions('B_inventoryQuery_detail')&&!$hasPermissions('B_inventoryQuery_rkDetail')">--</span>
+          </template>
+        </s-table>
+      </a-spin>
+      <!-- 库存详情 -->
+      <inventory-query-detail-modal v-drag :openModal="openModal" :itemId="itemId" @close="closeModal" />
+    </a-card>
+  </div>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+// 组件
+import { STable, VSelect } from '@/components'
+import inventoryQueryDetailModal from './detailModal.vue'
+import ProductType from '@/views/common/productType.js'
+import ProductBrand from '@/views/common/productBrand.js'
+import warehouse from '@/views/common/chooseWarehouse.js'
+// 接口
+import { stockList, stockCount } from '@/api/stock'
+export default {
+  name: 'InventoryQueryList',
+  mixins: [commonMixin],
+  components: { STable, VSelect, inventoryQueryDetailModal, ProductType, ProductBrand, warehouse },
+  data () {
+    return {
+      spinning: false,
+      advanced: false, // 高级搜索 展开/关闭
+      tableHeight: 0, // 表格高度
+      queryParam: { //  查询条件
+        productCode: '', //  产品编码
+        productName: '', //  产品名称
+        productOrigCode: '', //  原厂编码
+        productBrandSn: undefined, //  产品品牌
+        warehouseSn: undefined, // 仓库
+        productTypeSn1: '', //  产品分类1
+        productTypeSn2: '', //  产品分类2
+        productTypeSn3: '', //  产品分类3
+        zeroQtyFlag: false //  库存情况
+      },
+      productType: [], // 产品分类
+      exportLoading: false, // 导出loading
+      disabled: false, //  查询、重置按钮是否可操作
+      zeroQtyData: [ //  库存情况
+        { name: '库存数量为0', id: '1' },
+        { name: '库存数量不为0', id: '0' }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        this.spinning = true
+        // 排序
+        if (parameter.sortOrder && parameter.sortField == 'currentStockQty') {
+          parameter.sortField = 'qty'
+          parameter.sortAlias = ''
+        }
+        if (parameter.sortOrder && parameter.sortField == 'currentStockCost') {
+          parameter.sortField = 'currentStockCost'
+          parameter.sortAlias = 'stock'
+        }
+        // 没有排序
+        if (!parameter.sortOrder) {
+          parameter.sortField = ''
+          parameter.sortAlias = ''
+        }
+
+        const params = Object.assign(parameter, this.queryParam)
+        if (params.zeroQtyFlag) {
+          params.zeroQtyFlag = '0'
+        } else {
+          params.zeroQtyFlag = ''
+        }
+        // 获取列表数据  有分页
+        return stockList(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
+            }
+            this.disabled = false
+            this.spinning = false
+            // 总计
+            this.getTotal(params)
+          }
+          return data
+        })
+      },
+      openModal: false, //  查看库存详情  弹框
+      itemId: '', //  当前库存记录id
+      currentStock: null // 可用库存合计
+    }
+  },
+  computed: {
+    // 表头
+    columns () {
+      const arr = [
+        { title: '序号', dataIndex: 'no', width: '40px', align: 'center' },
+        { title: '产品信息', scopedSlots: { customRender: 'productInfo' }, width: '82%', align: 'center' },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: '10%', align: 'center' }
+      ]
+      return arr
+    }
+  },
+  methods: {
+    //  重置
+    resetSearchForm () {
+      this.queryParam.productBrandSn = undefined
+      this.queryParam.productTypeSn1 = ''
+      this.queryParam.productTypeSn2 = ''
+      this.queryParam.productTypeSn3 = ''
+      this.queryParam.productCode = ''
+      this.queryParam.productOrigCode = ''
+      this.queryParam.productName = ''
+      this.queryParam.warehouseSn = undefined
+      this.queryParam.zeroQtyFlag = false
+      this.productType = []
+      this.$refs.table.refresh(true)
+    },
+    // 获取表格数据
+    getTableData () {
+
+    },
+    // 合计
+    getTotal (param) {
+      stockCount(param).then(res => {
+        if (res.status == 200 && res.data) {
+          this.currentStock = res.data
+        } else {
+          this.currentStock = null
+        }
+      })
+    },
+    //  库存详情
+    goDetail (row) {
+      this.$store.state.app.curActionPermission = 'B_inventoryQuery_detail'
+      this.itemId = row.stockSn
+      this.openModal = true
+    },
+    //  关闭弹框
+    closeModal () {
+      this.itemId = ''
+      this.openModal = false
+    },
+    //  出入库明细
+    goWarehouseDetail (row) {
+      this.$router.push({ name: 'inventoryQueryWarehouseDetail', params: { sn: row.productSn, warehouseSn: row.warehouseSn } })
+    },
+    //  产品分类  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] : ''
+    },
+    // 初始化页面
+    pageInit () {
+      const _this = this
+      this.$nextTick(() => { // 页面渲染完成后的回调
+        _this.setTableH()
+      })
+    },
+    // 计算表格高度
+    setTableH () {
+      const tableSearchH = this.$refs.tableSearch.offsetHeight
+      this.tableHeight = window.innerHeight - tableSearchH - 226
+    }
+  },
+  watch: {
+    advanced (newValue, oldValue) {
+      const _this = this
+      this.$nextTick(() => { // 页面渲染完成后的回调
+        _this.setTableH()
+      })
+    },
+    '$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()
+      this.$refs.table.refresh()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {})
+  }
+}
+</script>
+<style lang="less">
+  .inventoryQueryList-wrap{
+    margin-top: 10px;
+    .sTable{
+      margin-top: 10px;
+    }
+    .tr-row{
+      text-align: left;
+      .tr-title{
+        font-weight: bold;
+      }
+      > div{
+        padding: 2px 0;
+        color: #666;
+        span{
+          color: #222;
+        }
+        .code{
+          color: #00aaff;
+        }
+        .nums{
+          color: #ff0000;
+        }
+      }
+    }
+  }
+</style>

+ 318 - 0
src/mobile/inventoryManagement/inventoryQuery/warehouseDetail.vue

@@ -0,0 +1,318 @@
+<template>
+  <div class="inventoryQueryWarehouseDetail-wrap">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-page-header :ghost="false" :backIcon="false" class="inventoryQueryWarehouseDetail-back">
+        <!-- 自定义的二级文字标题 -->
+        <template slot="subTitle">
+          <a id="inventoryQueryWarehouseDetail-back-btn" href="javascript:;" @click="handleBack"><a-icon type="left" /> 返回列表</a>
+        </template>
+      </a-page-header>
+      <a-card size="small" :bordered="false" class="inventoryQueryWarehouseDetail-cont">
+        <!-- 搜索条件 -->
+        <div ref="tableSearch" class="table-page-search-wrapper">
+          <a-form layout="inline" @keyup.enter.native="$refs.table.refresh(true)">
+            <a-row :gutter="15">
+              <a-col :md="6" :sm="24">
+                <a-form-item label="单据审核时间">
+                  <rangeDate ref="rangeDate" @change="dateChange" />
+                </a-form-item>
+              </a-col>
+              <a-col :md="6" :sm="24">
+                <a-form-item label="关联单号">
+                  <a-input id="inventoryQueryWarehouseDetail-bizNo" v-model.trim="queryParam.bizNo" allowClear placeholder="请输入关联单号"/>
+                </a-form-item>
+              </a-col>
+              <a-col :md="6" :sm="24">
+                <a-form-item label="下推单号">
+                  <a-input id="inventoryQueryWarehouseDetail-bizSubNo" v-model.trim="queryParam.bizSubNo" allowClear placeholder="请输入下推单号"/>
+                </a-form-item>
+              </a-col>
+              <template v-if="advanced">
+                <a-col :md="6" :sm="24">
+                  <a-form-item label="变动类型">
+                    <v-select
+                      v-model="queryParam.flowType"
+                      ref="flowType"
+                      id="inventoryQueryWarehouseDetail-flowType"
+                      code="STOCK_FLOW_TYPE"
+                      placeholder="请选择变动类型"
+                      allowClear></v-select>
+                  </a-form-item>
+                </a-col>
+                <a-col :md="6" :sm="24">
+                  <a-form-item label="单据类型">
+                    <v-select
+                      v-model="queryParam.bizType"
+                      ref="bizType"
+                      id="inventoryQueryWarehouseDetail-bizType"
+                      code="STOCK_FLOW_BIZ_TYPE"
+                      placeholder="请选择单据类型"
+                      allowClear></v-select>
+                  </a-form-item>
+                </a-col>
+                <a-col :md="6" :sm="24">
+                  <a-form-item label="单位名称">
+                    <a-input id="inventoryQueryWarehouseDetail-unitName" v-model.trim="queryParam.unitName" allowClear placeholder="请输入单位名称"/>
+                  </a-form-item>
+                </a-col>
+                <a-col :md="6" :sm="24">
+                  <a-form-item label="出入库状态">
+                    <v-select
+                      v-model="queryParam.state"
+                      ref="state"
+                      id="inventoryQueryWarehouseDetail-state"
+                      code="STOCK_FLOW_STATE"
+                      placeholder="请选择出入库状态"
+                      allowClear></v-select>
+                  </a-form-item>
+                </a-col>
+              </template>
+              <a-col :md="6" :sm="24">
+                <a-button type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="inventoryQueryWarehouseDetail-refresh">查询</a-button>
+                <a-button style="margin-left: 5px" @click="resetSearchForm" :disabled="disabled" id="inventoryQueryWarehouseDetail-reset">重置</a-button>
+                <a-button
+                  type="primary"
+                  style="margin-left: 5px"
+                  class="button-warning"
+                  v-if="$hasPermissions('B_inventoryQuery_rkDetail_export')"
+                  @click="handleExcel"
+                  :disabled="disabled"
+                  :loading="exportLoading"
+                  id="inventoryQueryList-export">导出</a-button>
+                <a @click="advanced=!advanced" style="margin-left: 5px" id="inventoryQueryList-advanced">
+                  {{ advanced ? '收起' : '展开' }}
+                  <a-icon :type="advanced ? 'up' : 'down'"/>
+                </a>
+              </a-col>
+            </a-row>
+          </a-form>
+        </div>
+        <!-- 合计 -->
+        <a-alert type="info" style="margin-bottom:10px">
+          <div class="ftext" slot="message">
+            当前库存总数量:<strong>{{ (productTotal&&(productTotal.totalQty || productTotal.totalQty==0)) ? productTotal.totalQty : '--' }}个</strong>;
+            入库总数量:<strong>{{ (productTotal&&(productTotal.totalPutQty || productTotal.totalPutQty==0)) ? productTotal.totalPutQty : '--' }}个</strong>;
+            出库总数量:<strong>{{ (productTotal&&(productTotal.totalOutQty || productTotal.totalOutQty==0)) ? productTotal.totalOutQty : '--' }}个</strong>;
+            <span v-if="$hasPermissions('B_inventoryQuery_rkDetail_costPrice')">当前库存总成本:<strong>{{ (productTotal&&(productTotal.totalCost || productTotal.totalCost==0)) ? toThousands(productTotal.totalCost) : '--' }}</strong>。</span>
+          </div>
+        </a-alert>
+        <!-- 列表 -->
+        <s-table
+          class="sTable fixPagination"
+          ref="table"
+          :style="{ height: tableHeight+70+'px' }"
+          size="small"
+          :rowKey="(record) => record.id"
+          :columns="columns"
+          :data="loadData"
+          :scroll="{ y: tableHeight }"
+          :defaultLoadData="false"
+          bordered>
+          <!-- 数量 -->
+          <template slot="qty" slot-scope="text, record">
+            <p :class="record.flowType=='PUT' ? 'green':'red'" style="margin: 0;">
+              <span v-if="record.qty!=0">{{ record.flowType=='PUT' ? '+':'-' }}</span>
+              {{ record.qty }}
+            </p>
+          </template>
+          <!-- 总售价 -->
+          <template slot="totalAmount" slot-scope="text, record">
+            <span v-if="record.bizType!='SPARE_PARTS_RETURN'"> {{ toThousands(record.totalPrice) }}</span>
+            <span v-else>--</span>
+          </template>
+        </s-table>
+      </a-card>
+    </a-spin>
+  </div>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+import { STable, VSelect } from '@/components'
+import rangeDate from '@/views/common/rangeDate.vue'
+import { hdExportExcel } from '@/libs/exportExcel'
+import { stockFlowCount, stockFlowList, stockFlowExport } from '@/api/stock'
+export default {
+  name: 'InventoryQueryWarehouseDetail',
+  mixins: [commonMixin],
+  components: { STable, VSelect, rangeDate },
+  data () {
+    return {
+      spinning: false,
+      advanced: false, // 高级搜索 展开/关闭
+      tableHeight: 0,
+      queryParam: { //  查询条件
+        beginDate: '', // 开始时间
+        endDate: '', // 结束时间
+        bizType: undefined, // 单据类型
+        flowType: undefined, // 变动类型
+        unitName: '', // 单位
+        bizNo: '', // 关联单号
+        bizSubNo: '', // 下推单号
+        warehouseSn: undefined, // 仓库sn
+        state: undefined // 单据状态
+      },
+      disabled: false, //  查询、重置按钮是否可操作
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        this.spinning = true
+        const params = Object.assign(parameter, this.queryParam, { productSn: this.$route.params.sn, warehouseSn: this.$route.params.warehouseSn })
+        return stockFlowList(params).then(res => {
+          let data
+          if (res.status == 200) {
+            data = res.data
+            this.getTotal(params)
+            const no = (data.pageNo - 1) * data.pageSize
+            for (var i = 0; i < data.list.length; i++) {
+              data.list[i].no = no + i + 1
+              if (data.list[i].flowType == 'PUT') {
+                data.list[i].qty = data.list[i].putQty
+              } else if (data.list[i].flowType == 'OUT') {
+                data.list[i].qty = data.list[i].outQty
+              }
+            }
+            this.disabled = false
+          }
+          this.spinning = false
+          return data
+        })
+      },
+      exportLoading: false, // 导出按钮loading
+      productTotal: null //  合计
+    }
+  },
+  computed: {
+    columns () {
+      const _this = this
+      const arr = [
+        { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
+        { title: '产品编码', dataIndex: 'productCode', width: '6%', align: 'left', customRender: function (text) { return text || '--' } },
+        { title: '产品名称', dataIndex: 'productName', width: '10%', align: 'left', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '原厂编码', dataIndex: 'productOrigCode', width: '6%', align: 'left', customRender: function (text) { return text || '--' } },
+        { title: '批次号', dataIndex: 'stockBatchNo', width: '9%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '单据类型', dataIndex: 'bizTypeDictValue', width: '9%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '关联单号', dataIndex: 'bizNo', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '下推单号', dataIndex: 'bizSubNo', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '单据审核时间', dataIndex: 'auditTime', width: '7%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '单位名称', dataIndex: 'unitName', width: '10%', align: 'left', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '仓库', dataIndex: 'warehouseName', width: '8%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '仓位', dataIndex: 'warehouseLocationName', width: '8%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '数量', scopedSlots: { customRender: 'qty' }, width: '5%', align: 'center' },
+        // { title: '总成本', dataIndex: 'totalCost', width: '4%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        // { title: '总售价', dataIndex: 'totalPrice', width: '4%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '出入库状态', dataIndex: 'stateDictValue', width: '6%', align: 'center', customRender: function (text) { return text || '--' } }
+      ]
+      if (this.$hasPermissions('B_inventoryQuery_rkDetail_costPrice')) { // 成本价权限
+        arr.splice(13, 0, { title: '总成本', dataIndex: 'totalCost', width: '5%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } })
+      }
+      if (this.$hasPermissions('B_inventoryQuery_rkDetail_salesPrice')) { // 售价权限
+        arr.splice(14, 0, { title: '总售价', width: '5%', align: 'right', scopedSlots: { customRender: 'totalAmount' } })
+      }
+      return arr
+    }
+  },
+  methods: {
+    //  创建时间  change
+    dateChange (date) {
+      this.queryParam.beginDate = date[0]
+      this.queryParam.endDate = date[1]
+    },
+    // 合计
+    getTotal (param) {
+      stockFlowCount(param).then(res => {
+        if (res.status == 200 && res.data) {
+          this.productTotal = res.data
+        } else {
+          this.productTotal = null
+        }
+      })
+    },
+    //  重置
+    resetSearchForm () {
+      this.$refs.rangeDate.resetDate()
+      this.queryParam.beginDate = ''
+      this.queryParam.endDate = ''
+      this.queryParam.bizType = undefined
+      this.queryParam.flowType = undefined
+      this.queryParam.unitName = ''
+      this.queryParam.bizSubNo = ''
+      this.queryParam.bizNo = ''
+      this.queryParam.warehouseSn = undefined
+      this.queryParam.state = undefined
+      this.$refs.table.refresh(true)
+    },
+    // 导出
+    handleExcel () {
+      const _this = this
+      this.$store.state.app.curActionPermission = 'B_inventoryQuery_rkDetail_export'
+      const params = Object.assign(this.queryParam, { productSn: this.$route.params.sn, warehouseSn: this.$route.params.warehouseSn })
+      this.exportLoading = true
+      this.spinning = true
+      hdExportExcel(stockFlowExport, params, '出入库明细', function () {
+        _this.exportLoading = false
+        _this.spinning = false
+        _this.$store.state.app.curActionPermission = ''
+      })
+    },
+    //  返回列表
+    handleBack () {
+      this.$router.push({ name: 'inventoryQueryList', query: { closeLastOldTab: true } })
+    },
+    pageInit () {
+      const _this = this
+      this.$nextTick(() => { // 页面渲染完成后的回调
+        _this.setTableH()
+      })
+    },
+    setTableH () {
+      const tableSearchH = this.$refs.tableSearch.offsetHeight
+      this.tableHeight = window.innerHeight - tableSearchH - 268
+    }
+  },
+  watch: {
+    advanced (newValue, oldValue) {
+      const _this = this
+      this.$nextTick(() => { // 页面渲染完成后的回调
+        _this.setTableH()
+      })
+    },
+    '$store.state.app.winHeight' (newValue, oldValue) { //  窗口变更时,需同时更改表格高度
+      this.setTableH()
+    }
+  },
+  mounted () {
+    if (!this.$store.state.app.isNewTab) { // 页签刷新时调用
+      this.resetSearchForm()
+      this.pageInit()
+    }
+  },
+  activated () {
+    // 如果是新页签打开或者进入新的子页(例:存在列表第2条数据编辑页页签时再打开第4条数据的编辑页),则重置当前页面
+    if (this.$store.state.app.isNewTab || !this.$store.state.app.isNewSubTab) {
+      this.resetSearchForm()
+      this.pageInit()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {})
+  }
+}
+</script>
+
+<style lang="less">
+  .inventoryQueryWarehouseDetail-wrap{
+    .inventoryQueryWarehouseDetail-back{
+      margin-bottom: 6px;
+    }
+    .inventoryQueryWarehouseDetail-cont{
+      margin-bottom: 6px;
+    }
+    .green{
+      color: #19be6b;
+    }
+    .red{
+      color: #ed1c24;
+    }
+  }
+</style>

+ 146 - 0
src/mobile/productManagement/productPricing/auditModal.vue

@@ -0,0 +1,146 @@
+<template>
+  <a-modal
+    centered
+    class="productPricingAudit-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="定价审核"
+    v-model="isShow"
+    @cancel="isShow=false"
+    :width="800">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <!-- 定价审核 -->
+      <div>
+        <a-descriptions bordered :column="1">
+          <a-descriptions-item label="成本价">
+            <div v-if="detailsData && detailsData.supplierProductList" style="margin-top: 8px;">
+              <p v-for="(item, index) in detailsData.supplierProductList" :key="index" style="margin: 0;">{{ ((item.cost || item.cost==0) ? toThousands(item.cost) : '--') + ' -- ' + (item.supplierName||'') + ';' }}</p>
+            </div>
+            <span v-else>--</span>
+          </a-descriptions-item>
+          <a-descriptions-item label="省级价">
+            {{ detailsData && (detailsData.afterProvincePrice || detailsData.afterProvincePrice==0) ? toThousands(detailsData.afterProvincePrice) : '--' }}
+            <span v-if="detailsData && (detailsData.afterProvincePrice != detailsData.beforeProvincePrice)">
+              (原{{ (detailsData.beforeProvincePrice || detailsData.beforeProvincePrice==0) ? toThousands(detailsData.beforeProvincePrice) : '--' }})
+            </span>
+          </a-descriptions-item>
+          <a-descriptions-item label="市级价">
+            {{ detailsData && (detailsData.afterCityPrice || detailsData.afterCityPrice==0) ? toThousands(detailsData.afterCityPrice) : '--' }}
+            <span v-if="detailsData && (detailsData.afterCityPrice != detailsData.beforeCityPrice)">
+              (原{{ (detailsData.beforeCityPrice || detailsData.beforeCityPrice==0) ? toThousands(detailsData.beforeCityPrice) : '--' }})
+            </span>
+          </a-descriptions-item>
+          <a-descriptions-item label="特约价">
+            {{ detailsData && (detailsData.afterSpecialPrice || detailsData.afterSpecialPrice==0) ? toThousands(detailsData.afterSpecialPrice) : '--' }}
+            <span v-if="detailsData && (detailsData.afterSpecialPrice != detailsData.beforeSpecialPrice)">
+              (原{{ (detailsData.beforeSpecialPrice || detailsData.beforeSpecialPrice==0) ? toThousands(detailsData.beforeSpecialPrice) : '--' }})
+            </span>
+          </a-descriptions-item>
+          <a-descriptions-item label="终端价">
+            {{ detailsData && (detailsData.afterTerminalPrice || detailsData.afterTerminalPrice==0) ? toThousands(detailsData.afterTerminalPrice) : '--' }}
+            <span v-if="detailsData && (detailsData.afterTerminalPrice != detailsData.beforeTerminalPrice)">
+              (原{{ (detailsData.beforeTerminalPrice || detailsData.beforeTerminalPrice==0) ? toThousands(detailsData.beforeTerminalPrice) : '--' }})
+            </span>
+          </a-descriptions-item>
+          <a-descriptions-item label="车主价">
+            {{ detailsData && (detailsData.afterCarOwnersPrice || detailsData.afterCarOwnersPrice==0) ? toThousands(detailsData.afterCarOwnersPrice) : '--' }}
+            <span v-if="detailsData && (detailsData.afterCarOwnersPrice != detailsData.beforeCarOwnersPrice)">
+              (原{{ (detailsData.beforeCarOwnersPrice || detailsData.beforeCarOwnersPrice==0) ? toThousands(detailsData.beforeCarOwnersPrice) : '--' }})
+            </span>
+          </a-descriptions-item>
+          <a-descriptions-item label="变更原因">{{ detailsData && detailsData.changeReason || '--' }}</a-descriptions-item>
+        </a-descriptions>
+        <div class="btn-cont">
+          <a-button type="primary" id="productPricingAudit-back" @click="handleAudit('AUDIT_REJECT')" style="margin-right: 15px;">审核不通过</a-button>
+          <a-button type="primary" class="button-info" id="productPricingAudit-save" @click="handleAudit('PRICED')">审核通过</a-button>
+        </div>
+      </div>
+    </a-spin>
+  </a-modal>
+</template>
+
+<script>
+import { toThousands } from '@/libs/tools.js'
+// 接口
+import { productPricingSnDetail, productPricingAudit } from '@/api/product'
+export default {
+  name: 'ProductPricingAuditModal',
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    itemSn: {// 审核sn
+      type: [Number, String],
+      default: ''
+    }
+  },
+  data () {
+    return {
+      spinning: false,
+      toThousands, // 金额 截取到两位函数 3位添加‘,’
+      isShow: this.openModal, //  是否打开弹框
+      detailsData: null //  详情数据
+    }
+  },
+  methods: {
+    //  获取详情数据
+    getDetail () {
+      productPricingSnDetail({ sn: this.itemSn }).then(res => {
+        if (res.status == 200) {
+          this.detailsData = res.data
+        } else {
+          this.detailsData = null
+        }
+      })
+    },
+    // 审核  type =='AUDIT_REJECT'?'不通过':'通过(PRICED)'
+    handleAudit (type) {
+      const ajaxData = {
+        id: this.detailsData.id,
+        productSn: this.detailsData.productSn,
+        auditState: type
+      }
+      this.spinning = true
+      productPricingAudit(ajaxData).then(res => {
+        if (res.status == 200) {
+          this.isShow = false
+          this.$emit('ok')
+          this.spinning = false
+        } else {
+          this.spinning = false
+        }
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+      }
+    },
+    itemSn (newValue, oldValue) {
+      if (this.isShow && newValue) {
+        this.getDetail()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .productPricingAudit-modal{
+    .ant-modal-body {
+      padding: 40px 40px 24px;
+    }
+    .btn-cont {
+      text-align: center;
+      margin: 35px 0 30px;
+    }
+  }
+</style>

+ 202 - 0
src/mobile/productManagement/productPricing/chooseImportModal.vue

@@ -0,0 +1,202 @@
+<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 { productPriceImport, productPriceFailExcel } from '@/api/product'
+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: 'name', width: '25%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品编码', dataIndex: 'code', width: '25%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '省级价', dataIndex: 'provincePrice', 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: 'terminalPrice', width: '6%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
+        { title: '车主价', dataIndex: 'carOwnersPrice', width: '6%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
+        { title: '变更原因', dataIndex: 'changeReason', width: '10%', align: 'center', customRender: function (text) { return text || '--' } }
+      ],
+      loadData: [], // 可导入数据
+      nowUnColumns: [
+        { title: '序号', dataIndex: 'no', width: '9%', align: 'center' },
+        { title: '产品名称', dataIndex: 'name', width: '21%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品编码', dataIndex: 'code', width: '18%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '省级价', dataIndex: 'provincePrice', 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: 'terminalPrice', width: '6%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
+        { title: '车主价', dataIndex: 'carOwnersPrice', width: '6%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
+        { title: '变更原因', dataIndex: 'changeReason', width: '8%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '备注', dataIndex: 'errorMsg', 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
+      }
+      productPriceImport(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(productPriceFailExcel, _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>

+ 272 - 0
src/mobile/productManagement/productPricing/editModal.vue

@@ -0,0 +1,272 @@
+<template>
+  <a-modal
+    centered
+    class="productPricingEdit-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="编辑价格"
+    v-model="isShow"
+    @cancel="isShow=false"
+    :width="800">
+    <!-- 编辑价格 -->
+    <div>
+      <a-spin :spinning="spinning" tip="Loading...">
+        <a-form-model
+          id="productPricingEdit-form"
+          ref="ruleForm"
+          :model="form"
+          :rules="rules"
+          :label-col="formItemLayout.labelCol"
+          :wrapper-col="formItemLayout.wrapperCol"
+        >
+          <a-form-model-item label="成本价">
+            <div v-if="detailData && detailData.supplierProductList" style="margin-top: 8px;">
+              <p v-for="(item, index) in detailData.supplierProductList" :key="index" style="margin: 0;line-height: 1.5em;">{{ ((item.cost || item.cost==0) ? item.cost.toFixed(2) : '--') + ' 元 -- ' + (item.supplierName||'') + ';' }}</p>
+            </div>
+            <span v-else>--</span>
+          </a-form-model-item>
+          <a-form-model-item label="省级价" prop="afterProvincePrice">
+            <a-input-number
+              id="productPricingEdit-afterProvincePrice"
+              v-model="form.afterProvincePrice"
+              :precision="2"
+              :min="0.01"
+              :max="99999999"
+              placeholder="请输入省级价"
+              ref="afterProvincePrice"
+              @keydown.enter.native="nextFocus('afterProvincePrice', 'afterCityPrice', $event)"
+              style="width: 100%;" />
+          </a-form-model-item>
+          <a-form-model-item label="市级价" prop="afterCityPrice">
+            <a-input-number
+              id="productPricingEdit-afterCityPrice"
+              v-model="form.afterCityPrice"
+              :precision="2"
+              :min="0.01"
+              :max="99999999"
+              placeholder="请输入市级价"
+              ref="afterCityPrice"
+              @keydown.enter.native="nextFocus('afterCityPrice', 'afterSpecialPrice', $event)"
+              style="width: 100%;" />
+          </a-form-model-item>
+          <a-form-model-item label="特约价" prop="afterSpecialPrice">
+            <a-input-number
+              id="productPricingEdit-afterSpecialPrice"
+              v-model="form.afterSpecialPrice"
+              :precision="2"
+              :min="0.01"
+              :max="99999999"
+              placeholder="请输入特约价"
+              ref="afterSpecialPrice"
+              @keydown.enter.native="nextFocus('afterSpecialPrice', 'afterTerminalPrice', $event)"
+              style="width: 100%;" />
+          </a-form-model-item>
+          <a-form-model-item label="终端价" prop="afterTerminalPrice">
+            <a-input-number
+              id="productPricingEdit-afterTerminalPrice"
+              v-model="form.afterTerminalPrice"
+              :precision="2"
+              :min="0.01"
+              :max="99999999"
+              placeholder="请输入终端价"
+              ref="afterTerminalPrice"
+              @keydown.enter.native="nextFocus('afterTerminalPrice', 'afterCarOwnersPrice', $event)"
+              style="width: 100%;" />
+          </a-form-model-item>
+          <a-form-model-item label="车主价" prop="afterCarOwnersPrice">
+            <a-input-number
+              id="productPricingEdit-afterCarOwnersPrice"
+              v-model="form.afterCarOwnersPrice"
+              :precision="2"
+              :min="0.01"
+              :max="99999999"
+              placeholder="请输入车主价"
+              ref="afterCarOwnersPrice"
+              @keydown.enter.native="nextFocus('afterCarOwnersPrice', 'changeReason', $event, 'vSelect')"
+              style="width: 100%;" />
+          </a-form-model-item>
+          <a-form-model-item label="变更原因" prop="changeReason">
+            <v-select
+              code="PRODUCT_PRICE_CHANGE_REASON"
+              id="productPricingEdit-changeReason"
+              v-model="form.changeReason"
+              allowClear
+              placeholder="请选择变更原因"
+              ref="changeReason"
+              @keydown.enter.native="nextFocus('changeReason', '', $event)"
+            ></v-select>
+          </a-form-model-item>
+        </a-form-model>
+        <div class="btn-cont">
+          <a-button id="productPricingEdit-cancel" @click="isShow = false" style="margin-right: 15px;">取消</a-button>
+          <a-button type="primary" id="productPricingEdit-save" @click="handleSave">保存</a-button>
+        </div>
+      </a-spin>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import { VSelect } from '@/components'
+// 接口
+import { productPricingSnDetail, productPricingSave } from '@/api/product'
+export default {
+  name: 'ProductPricingEditModal',
+  components: { VSelect },
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    itemSn: {// 定价产品sn
+      type: [Number, String],
+      default: ''
+    }
+  },
+  data () {
+    return {
+      spinning: false,
+      isShow: this.openModal, //  是否打开弹框
+      formItemLayout: {// 表单布局设置
+        labelCol: { span: 4 },
+        wrapperCol: { span: 17 }
+      },
+      form: {
+        afterProvincePrice: '', // 省级价
+        afterCityPrice: '', // 市级价
+        afterSpecialPrice: '', // 特约价
+        afterTerminalPrice: '', // 终端价
+        afterCarOwnersPrice: '', // 车主价
+        changeReason: undefined// 变更原因
+      },
+      rules: {
+        changeReason: [
+          { required: true, message: '请选择变更原因', trigger: 'change' }
+        ],
+        afterProvincePrice: [
+          { required: true, message: '请输入省级价', trigger: 'blur' }
+        ],
+        afterCityPrice: [
+          { required: true, message: '请输入市级价', trigger: 'blur' }
+        ],
+        afterSpecialPrice: [
+          { required: true, message: '请输入特约价', trigger: 'blur' }
+        ],
+        afterTerminalPrice: [
+          { required: true, message: '请输入终端价', trigger: 'blur' }
+        ],
+        afterCarOwnersPrice: [
+          { required: true, message: '请输入车主价', trigger: 'blur' }
+        ]
+      },
+      detailData: null //  数据详情
+    }
+  },
+  methods: {
+    //  获取详情
+    getDetail () {
+      productPricingSnDetail({ sn: this.itemSn }).then(res => {
+        if (res.status == 200) {
+          this.detailData = res.data
+          this.form.afterProvincePrice = res.data.afterProvincePrice || ''
+          this.form.afterCityPrice = res.data.afterCityPrice || ''
+          this.form.afterSpecialPrice = res.data.afterSpecialPrice || ''
+          this.form.afterTerminalPrice = res.data.afterTerminalPrice || ''
+          this.form.afterCarOwnersPrice = res.data.afterCarOwnersPrice || ''
+          this.form.changeReason = res.data.id && res.data.changeReason ? '价格修改' : '首次定价'
+        } else {
+          this.detailData = null
+          this.$refs.ruleForm.resetFields()
+        }
+      })
+    },
+    // 保存    定价规则==>省级价<市级价<特约价<终端价<车主价
+    handleSave () {
+      const _this = this
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          const newFormData = _this.form
+          if (newFormData.afterCityPrice * 1 < newFormData.afterProvincePrice * 1 || newFormData.afterCityPrice * 1 > newFormData.afterSpecialPrice * 1) {
+            _this.$message.error({ content: '价格设置规则:省级价≤市级价≤特约价', duration: 5 })
+            return
+          }
+          const form = JSON.parse(JSON.stringify(_this.form))
+          form.id = this.detailData.id || undefined
+          form.productSn = _this.itemSn
+          _this.spinning = true
+          productPricingSave(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
+        }
+      })
+    },
+    // 回车键快捷定位表单下一项
+    nextFocus (nowRef, nextRef, event, isComponent) {
+      const _this = this
+      if (_this.$refs[nowRef]) {
+        _this.$nextTick(() => {
+          if (_this.$refs[nextRef]) {
+            event.target.blur()
+            if (isComponent == 'vSelect') {
+              _this.$refs[nextRef].$children[0].focus()
+            } else {
+              _this.$refs[nextRef].focus()
+            }
+          }
+        })
+      }
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.costPrice = ''
+        this.$refs.ruleForm.resetFields()
+      } else {
+        // 默认首项获取焦点
+        const _this = this
+        setTimeout(() => {
+          if (_this.$refs['afterProvincePrice']) {
+            _this.$refs['afterProvincePrice'].focus()
+          }
+        }, 300)
+      }
+    },
+    itemSn (newValue, oldValue) {
+      if (this.isShow && newValue) {
+        this.getDetail()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .productPricingEdit-modal{
+    .ant-modal-body {
+      padding: 40px 40px 24px;
+    }
+    .btn-cont {
+      text-align: center;
+      margin: 35px 0 30px;
+    }
+  }
+</style>

+ 208 - 0
src/mobile/productManagement/productPricing/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) 导入的Excel文件中必须包含名为“产品编码”的列,且名称必须相同</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 { productPriceTplDownload } from '@/api/product'
+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 (obj) {
+      if (obj && obj.length > 0) {
+        this.$emit('ok', obj)
+        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(productPriceTplDownload, {}, '产品定价导入模板', 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>

+ 426 - 0
src/mobile/productManagement/productPricing/list.vue

@@ -0,0 +1,426 @@
+<template>
+  <div>
+    <a-card size="small" :bordered="false" class="productPricingList-wrap searchBoxNormal">
+      <!-- 搜索条件 -->
+      <div ref="tableSearch" class="table-page-search-wrapper">
+        <a-form layout="inline" @keyup.enter.native="searchForm">
+          <a-row :gutter="15">
+            <a-col :md="6" :sm="24">
+              <a-form-item label="定价时间">
+                <rangeDate id="productPricingList-rangeDate" ref="rangeDate" :value="time" @change="dateChange" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-item label="产品编码/原厂编码">
+                <a-input id="productPricingList-queryWord" v-model.trim="queryParam.queryWord" allowClear placeholder="请输入产品编码/原厂编码"/>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-item label="产品名称">
+                <a-input id="productPricingList-name" v-model.trim="queryParam.name" allowClear placeholder="请输入产品名称"/>
+              </a-form-item>
+            </a-col>
+            <template v-if="advanced">
+              <a-col :md="6" :sm="24">
+                <a-form-item label="定价状态">
+                  <v-select code="PRICING_STATUS" id="productPricingList-pricingState" v-model="queryParam.pricingState" allowClear placeholder="请选择定价状态"></v-select>
+                </a-form-item>
+              </a-col>
+              <a-col :md="6" :sm="24">
+                <a-form-item label="品牌">
+                  <ProductBrand id="productPricingList-productBrandSn" v-model="queryParam.productBrandSn"></ProductBrand>
+                </a-form-item>
+              </a-col>
+              <a-col :md="6" :sm="24">
+                <a-form-item label="产品分类">
+                  <ProductType id="productPricingList-productType" placeholder="请选择产品分类" @change="changeProductType" v-model="productType"></ProductType>
+                </a-form-item>
+              </a-col>
+            </template>
+            <a-col :md="6" :sm="24" style="margin-bottom: 10px;">
+              <a-button type="primary" @click="searchForm" :disabled="disabled" id="productPricingList-refresh">查询</a-button>
+              <a-button style="margin-left: 5px" @click="resetSearchForm" :disabled="disabled" id="productPricingList-reset">重置</a-button>
+              <a-button
+                style="margin-left: 5px"
+                type="primary"
+                class="button-warning"
+                @click="handleExport"
+                :disabled="disabled"
+                v-if="$hasPermissions('B_ProductPriceExoprt')"
+                id="productPricingList-export">导出</a-button>
+              <a @click="advanced=!advanced" style="margin-left: 5px">
+                {{ advanced ? '收起' : '展开' }}
+                <a-icon :type="advanced ? 'up' : 'down'"/>
+              </a>
+            </a-col>
+          </a-row>
+        </a-form>
+      </div>
+    </a-card>
+    <a-card size="small" :bordered="false">
+      <a-spin :spinning="spinning" tip="Loading...">
+        <!-- 操作按钮 -->
+        <div class="table-operator">
+          <a-button
+            style="margin: 0 10px 0 0;"
+            v-if="$hasPermissions('B_productPriceImport')"
+            id="productPricingList-add"
+            @click="openGuideModal=true"
+            type="primary"
+          >定价导入</a-button>
+          <a-button
+            id="productPricingList-batchAudit"
+            type="primary"
+            ghost
+            :loading="spinning"
+            @click="handleBatchAudit"
+            v-if="$hasPermissions('B_productPricing_audit')"
+            style="margin: 0 10px 0 0;">批量审核</a-button>
+          <span v-if="$hasPermissions('B_productPricing_audit')&&selTotal">已选{{ selTotal }}项</span>
+        </div>
+        <!-- 列表 -->
+        <s-table
+          class="sTable fixPagination"
+          ref="table"
+          :style="{ height: tableHeight+70+'px' }"
+          size="small"
+          :row-selection="$hasPermissions('B_productPricing_audit') ? { columnWidth: '4%', getCheckboxProps: record => ({ props: { disabled: record.pricingState!='WAIT_PRICING_AUDIT' } })}: null"
+          @rowSelection="rowSelectionFun"
+          :rowKey="(record) => record.id"
+          :columns="columns"
+          :data="loadData"
+          :scroll="{y: tableHeight }"
+          :defaultLoadData="false"
+          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="sterminaldsdPrice" slot-scope="text, record">
+            <div v-if="record.supplierProductList">
+              <p v-for="(item, index) in record.supplierProductList" :key="index" style="margin: 0;">
+                <span>{{ (item.cost || item.cost==0) ? item.cost.toFixed(2):'--' }}</span>元 -
+                <span>{{ (item.supplierName||'') }}</span>;
+              </p>
+            </div>
+            <span v-else>--</span>
+          </template>
+          <!-- 操作 -->
+          <template slot="action" slot-scope="text, record">
+            <a-button
+              size="small"
+              type="link"
+              v-if="record.pricingState=='WAIT_PRICING_AUDIT' && $hasPermissions('B_productPricing_audit')"
+              class="button-warning"
+              @click="handleAudit(record)"
+              :id="'productPricingList-audit-btn'+record.id">审核</a-button>
+            <a-button
+              size="small"
+              type="link"
+              v-if="$hasPermissions('B_productPricing_edit')"
+              class="button-info"
+              @click="handleEdit(record)"
+              :id="'productPricingList-edit-btn'+record.id">编辑</a-button>
+            <span v-if="!(record.pricingState=='WAIT_PRICING_AUDIT' && $hasPermissions('B_productPricing_audit')) && !$hasPermissions('B_productPricing_edit')">--</span>
+          </template>
+        </s-table>
+      </a-spin>
+      <!-- 编辑价格 -->
+      <product-pricing-edit-modal v-drag :openModal="openModal" :itemSn="itemSn" @close="closeModal" @ok="$refs.table.refresh()" />
+      <!-- 审核价格 -->
+      <product-pricing-audit-modal v-drag :openModal="openPriceAuditModal" :itemSn="itemSn" @close="closeAuditModal" @ok="auditSuccess" />
+      <!-- 导入产品 -->
+      <importGuideModal :openModal="openGuideModal" @close="openGuideModal=false" @ok="hanldeOk" />
+      <!-- 审核弹窗 -->
+      <a-modal
+        closable
+        v-model="openAuditModal"
+        :footer="null"
+        width="416px"
+        centered>
+        <div style="display:flex;margin:30px 0 20px 20px;">
+          <a-icon type="question-circle" :style="{fontSize:'23px',color:'#faad14'}"/>
+          <div style="margin-left:10px;">
+            <p style="font-size:16px;font-wight:bold;">提示</p>
+            <p>确认要审核吗?</p>
+          </div>
+        </div>
+        <!-- 按钮 -->
+        <div style="text-align: right;">
+          <a-button
+            id="auditModal-cancel"
+            type="primary"
+            @click="handleAuditModal('AUDIT_REJECT')"
+            style="margin-right: 15px;">审核不通过</a-button>
+          <a-button
+            type="primary"
+            id="auditModal-save"
+            class="button-info"
+            @click="handleAuditModal('PRICED')"
+          >审核通过</a-button>
+        </div>
+      </a-modal>
+    </a-card>
+  </div>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+import { exportExcel } from '@/libs/JGPrint.js'
+// 组件
+import rangeDate from '@/views/common/rangeDate.vue'
+import { STable, VSelect } from '@/components'
+import productPricingEditModal from './editModal.vue'
+import productPricingAuditModal from './auditModal.vue'
+import ProductType from '@/views/common/productType.js'
+import ProductBrand from '@/views/common/productBrand.js'
+import ImportGuideModal from './importGuideModal.vue'
+// 接口
+import { productPricingList, productExportPricing, batchAuditPrice, productPriceInsertImport } from '@/api/product'
+export default {
+  name: 'ProductPricingList',
+  mixins: [commonMixin],
+  components: { STable, VSelect, rangeDate, productPricingEditModal, productPricingAuditModal, ProductBrand, ProductType, ImportGuideModal },
+  data () {
+    return {
+      spinning: false,
+      advanced: true, // 高级搜索 展开/关闭
+      disabled: false, //  查询、重置按钮是否可操作
+      openGuideModal: false, // 打开定价导入弹窗
+      tableHeight: 0, // 表格高度
+      time: [], // 定价时间
+      //  查询条件
+      queryParam: {
+        name: '', //  产品名称
+        queryWord: '', // 产品编码/原厂编码
+        productBrandSn: undefined, //  产品品牌
+        productTypeSn1: '', //  产品一级分类
+        productTypeSn2: '', //  产品二级分类
+        productTypeSn3: '', //  产品三级分类
+        pricingState: undefined, //  定价状态
+        beginDate: undefined, // 定价开始时间
+        endDate: undefined// 定价结束时间
+      },
+      productType: [], // 产品分类
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        this.spinning = true
+        // 获取列表数据 有分页
+        return productPricingList(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.total = data.count || 0
+            this.disabled = false
+          }
+          this.spinning = false
+          return data
+        })
+      },
+      total: 0, // 合计
+      openModal: false, //  编辑  弹框
+      openAuditModal: false, //  审核  弹框
+      openPriceAuditModal: false, // 价格审核 弹框
+      itemSn: '', //  当前产品sn
+      rowSelectionInfo: null// 选中的表格数据
+    }
+  },
+  computed: {
+    // 计算选中列表条数
+    selTotal () {
+      return this.rowSelectionInfo && this.rowSelectionInfo.selectedRowKeys ? this.rowSelectionInfo.selectedRowKeys.length : 0
+    },
+    columns () {
+      const _this = this
+      const arr = [
+        { title: '序号', dataIndex: 'no', width: '3%', align: 'center' },
+        { title: '创建时间', dataIndex: 'createDate', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品名称', dataIndex: 'name', align: 'left', width: '13%', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '产品编码', dataIndex: 'code', width: '6%', align: 'left', customRender: function (text) { return text || '--' } },
+        { title: '原厂编码', dataIndex: 'origCode', width: '6%', align: 'left', customRender: function (text) { return text || '--' } },
+        { title: '品牌', dataIndex: 'productBrandName', width: '5%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品分类', scopedSlots: { customRender: 'productType' }, width: '11%', align: 'left' },
+        { title: '产品状态', dataIndex: 'stateDictValue', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '定价状态', dataIndex: 'pricingStateDictValue', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '定价时间', dataIndex: 'pricingTime', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '成本价', scopedSlots: { customRender: 'sterminaldsdPrice' }, width: '7%', align: 'center' },
+        { title: '省级价', dataIndex: 'provincePrice', width: '5%', align: 'center', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
+        { title: '市级价', dataIndex: 'cityPrice', width: '5%', align: 'center', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
+        { title: '特约价', dataIndex: 'specialPrice', width: '5%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
+        { title: '终端价', dataIndex: 'terminalPrice', width: '5%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
+        { title: '车主价', dataIndex: 'carOwnersPrice', width: '5%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: '8%', align: 'center' }
+      ]
+      return arr
+    }
+  },
+  methods: {
+    //  定价时间  change
+    dateChange (date) {
+      this.queryParam.beginDate = date[0]
+      this.queryParam.endDate = date[1]
+    },
+    // 表格选中项
+    rowSelectionFun (obj) {
+      this.rowSelectionInfo = obj || null
+    },
+    //  重置
+    resetSearchForm () {
+      this.queryParam.name = ''
+      this.queryParam.queryWord = ''
+      this.queryParam.productBrandSn = undefined
+      this.queryParam.productTypeSn1 = ''
+      this.queryParam.productTypeSn2 = ''
+      this.queryParam.productTypeSn3 = ''
+      this.queryParam.pricingState = undefined
+
+      this.queryParam.beginDate = undefined
+      this.queryParam.endDate = undefined
+      this.time = []
+      this.$refs.rangeDate.resetDate(this.time)
+      this.productType = []
+      this.$refs.table.clearSelected() // 清空表格选中项
+      this.$refs.table.refresh(true)
+    },
+    // 查询
+    searchForm () {
+      this.$refs.table.clearSelected() // 清空表格选中项
+      this.$refs.table.refresh(true)
+    },
+    // 审核
+    handleAudit (row) {
+      this.itemSn = row.productSn
+      this.openPriceAuditModal = true
+    },
+    // 价格审核成功
+    auditSuccess () {
+      this.$refs.table.clearSelected() // 清空表格选中项
+      this.$refs.table.refresh()
+    },
+    // 批量审核
+    handleBatchAudit () {
+      const _this = this
+      if (!_this.rowSelectionInfo || (_this.rowSelectionInfo && _this.rowSelectionInfo.selectedRowKeys.length < 1)) {
+        _this.$message.warning('请先选择产品!')
+        return
+      }
+      _this.openAuditModal = true
+    },
+    // 导入产品
+    hanldeOk (obj) {
+      productPriceInsertImport(obj).then(res => {
+        if (res.status == 200) {
+          this.resetSearchForm()
+        }
+      })
+    },
+    //  导出
+    handleExport () {
+      const _this = this
+      const params = this.queryParam
+      this.spinning = true
+      exportExcel(productExportPricing, params, '产品价格导出', function () {
+        _this.spinning = false
+      })
+    },
+    //  编辑
+    handleEdit (row) {
+      this.itemSn = row.productSn
+      this.openModal = true
+    },
+    //  关闭弹框
+    closeModal () {
+      this.itemSn = ''
+      this.openModal = false
+    },
+    //  关闭审核弹框
+    closeAuditModal () {
+      this.itemSn = ''
+      this.openPriceAuditModal = false
+    },
+    //  产品分类  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] : ''
+    },
+    // 初始化数据
+    pageInit () {
+      const _this = this
+      this.$nextTick(() => { // 页面渲染完成后的回调
+        _this.setTableH()
+      })
+    },
+    // 计算表格高度
+    setTableH () {
+      const tableSearchH = this.$refs.tableSearch.offsetHeight
+      this.tableHeight = window.innerHeight - tableSearchH - 240
+    },
+    // 批量审核
+    handleAuditModal (type) {
+      const _this = this
+      const productSnList = []
+      _this.rowSelectionInfo && _this.rowSelectionInfo.selectedRows.map(item => {
+        productSnList.push(item.productSn)
+      })
+      const ajaxData = {
+        productSnList: productSnList,
+        auditState: type
+      }
+      _this.spinning = true
+      batchAuditPrice(ajaxData).then(res => {
+        if (res.status == 200) {
+          _this.$refs.table.clearSelected() // 清空表格选中项
+          _this.$message.success(res.message)
+          _this.$refs.table.refresh()
+          _this.spinning = false
+          _this.openAuditModal = false
+        } else {
+          _this.spinning = false
+        }
+      })
+    }
+  },
+  watch: {
+    // 展开关闭 监听表格高度变化
+    advanced (newValue, oldValue) {
+      const _this = this
+      this.$nextTick(() => { // 页面渲染完成后的回调
+        _this.setTableH()
+      })
+    },
+    '$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()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {})
+  }
+}
+</script>