Parcourir la source

数据权限控制

chenrui il y a 1 mois
Parent
commit
137e5fae6b

+ 2 - 5
src/api/reportDailyConf.js

@@ -1,12 +1,9 @@
 import { axios } from '@/utils/request'
 
-//  每日报表配置  分页
+//  每日报表配置  分页
 export const reportDailyConfList = (params) => {
-  const url = `/dailyReportConf/queryPage/${params.pageNo}/${params.pageSize}`
-  delete params.pageNo
-  delete params.pageSize
   return axios({
-    url: url,
+    url: '/dailyReportConf/queryList',
     data: params,
     method: 'post',
     headers: {

+ 3 - 17
src/views/dealerManagement/businessOwnerSettings/categorySet.vue

@@ -25,7 +25,6 @@
                 <a-col :span="20">
                   <a-tag
                     :id="'categorySet-chooseType'+record.bizUserScopeSn"
-                    style="margin-bottom:10px;"
                     closable
                     @close.prevent="delLabel(record.bizUserScopeSn,con,'typeList')"
                     v-for="(con,i) in record.productTypeList"
@@ -54,7 +53,6 @@
               <a-row v-if="record.productBrandList && record.productBrandList.length>0">
                 <a-col :span="20">
                   <a-tag
-                    style="margin-bottom:10px;"
                     :id="'categorySet-chooseBrand'+record.bizUserScopeSn"
                     closable
                     @close.prevent="delLabel(record.bizUserScopeSn,item,'brandList')"
@@ -103,8 +101,8 @@
 import { commonMixin } from '@/utils/mixin'
 // 组件
 import { STable } from '@/components'
-import ChooseBrandModal from '@/views/common/chooseBrandModal.vue'
-import ChooseTypeModal from '@/views/common/chooseTypeModal.vue'
+import ChooseBrandModal from './chooseBrandModal.vue'
+import ChooseTypeModal from './chooseTypeModal.vue'
 // 接口
 import { getNewScopeSn, queryProductScopePage, saveProductBrandList, saveProductTypeList, bizuserScopeDelete, deleteProductBrand, deleteProductType } from '@/api/bizuser'
 export default {
@@ -234,13 +232,7 @@ export default {
     },
     // 添加品牌标签
     addBrandTag (pos, row) {
-      const newData = []
-      row.productBrandList.forEach(item => {
-        const obj = {}
-        obj.goodsSn = item.dataSn
-        newData.push(obj)
-      })
-      this.chooseBrand = newData
+      this.chooseBrand = row.productBrandList
       this.chooseObj = row
       this.openBrandModal = true
     },
@@ -336,9 +328,3 @@ export default {
   }
 }
 </script>
-
-<style lang="less">
-  .categorySet-wrap{
-
-  }
-</style>

+ 127 - 0
src/views/dealerManagement/businessOwnerSettings/chooseBrandModal.vue

@@ -0,0 +1,127 @@
+<template>
+  <a-modal
+    centered
+    class="chooseBrand-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="选择产品品牌"
+    v-model="isShow"
+    @cancel="isShow=false"
+    :width="800">
+    <div class="chooseBrand-con">
+      <a-row style="height: 400px;overflow-y: scroll;">
+        <a-col :span="6" v-for="(item,index) in brandList" :key="item.brandSn">
+          <a-checkbox :checked="item.checked" :disabled="item.isDisabled" @change="e=>onChange(e,index)">
+            {{ item.brandName }}
+          </a-checkbox>
+        </a-col>
+      </a-row>
+      <!-- 按钮 -->
+      <div class="btn-con">
+        <a-button
+          id="chooseBrand-cancel"
+          class="button-cancel"
+          @click="isShow=false"
+          style="padding: 0 30px;">取消</a-button>
+        <a-button
+          type="primary"
+          id="chooseBrand-submit"
+          @click="handleSave"
+          style="padding: 0 30px;margin-left: 15px;">保存</a-button>
+      </div>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import { productBrandQuery } from '@/api/productBrand'
+export default {
+  name: 'ChooseBrandModal',
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    chooseData: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      brandList: [] //  品牌数据
+    }
+  },
+  methods: {
+    // 保存
+    handleSave () {
+      const _this = this
+      const checkedRowList = _this.brandList.filter(item => item.checked)
+      if (checkedRowList.length < 1) {
+        _this.$message.warning('请在列表勾选后再进行操作!')
+        return
+      }
+      _this.$emit('ok', checkedRowList)
+      _this.isShow = false
+    },
+    // change
+    onChange (e, pos) {
+      this.brandList.map(item => {
+        item.checked = false
+        return item
+      })
+      this.brandList[pos].checked = e.target.checked
+      this.$forceUpdate()
+    },
+    // 获取品牌数据
+    getBrandList () {
+      const _this = this
+      productBrandQuery({}).then(res => {
+        if (res.status == 200) {
+          if (_this.chooseData && _this.chooseData.length > 0) {
+            const checkedList = _this.chooseData.map(item => item.dataSn)
+            res.data.map(item => {
+              item.checked = checkedList.includes(item.brandSn)
+            })
+          }
+          _this.brandList = res.data
+        } else {
+          _this.brandList = []
+        }
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+      } else {
+        const _this = this
+        _this.getBrandList()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .chooseBrand-modal{
+    .chooseBrand-con{
+      .btn-con{
+        text-align: center;
+        margin: 30px 0 20px;
+        .button-cancel{
+          font-size: 12px;
+        }
+      }
+    }
+  }
+</style>

+ 165 - 0
src/views/dealerManagement/businessOwnerSettings/chooseTypeModal.vue

@@ -0,0 +1,165 @@
+<template>
+  <a-modal
+    centered
+    class="chooseType-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="选择产品分类"
+    v-model="isShow"
+    @cancel="isShow=false"
+    width="50%">
+    <div class="chooseType-con">
+      <a-tree
+        style="height: 400px;overflow-y: scroll;"
+        checkable
+        @check="onCheck"
+        :checkStrictly="linkageStatus"
+        :checkedKeys="selectedKey"
+        :treeData="productTypeList"
+        :replaceFields="replaceFields"
+        :expandedKeys.sync="expandedKeys"
+      />
+      <!-- 按钮 -->
+      <div class="btn-con">
+        <a-button
+          id="chooseType-cancel"
+          class="button-cancel"
+          @click="isShow=false"
+          style="padding: 0 30px;">取消</a-button>
+        <a-button
+          type="primary"
+          id="chooseType-submit"
+          @click="handleSave"
+          style="padding: 0 30px;margin-left: 15px;">保存</a-button>
+      </div>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import { productTypeQuery } from '@/api/productType'
+export default {
+  name: 'ChooseTypeModal',
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    chooseData: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    linkageStatus: { // 父子是否联动
+      type: Boolean,
+      default: true
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      selectedKey: [], //  选中项
+      checkedRows: [], //  选中项  整条数据
+      replaceFields: {// tree 渲染配置
+        children: 'children',
+        title: 'productTypeName',
+        key: 'productTypeSn'
+      },
+      productTypeList: [], // tree列表数据
+      expandedKeys: []// 第一级  展开sn
+    }
+  },
+  methods: {
+    //  产品分类  列表
+    getProductType () {
+      productTypeQuery({}).then(res => {
+        if (res.status == 200) {
+          this.recursionFun(res.data)
+          this.productTypeList = res.data
+          this.expandedKeys = this.getLevel1Keys(res.data) // 仅展开二级
+        } else {
+          this.productTypeList = []
+        }
+      })
+    },
+    // 遍历树数据,提取所有一级节点的 Key
+    getLevel1Keys (treeData) {
+      const keys = []
+      treeData.forEach(level1Node => {
+        keys.push(level1Node.productTypeSn)
+      })
+      return keys
+    },
+    // 保存
+    handleSave () {
+      if (this.selectedKey.checked && this.selectedKey.checked.length < 1) {
+        this.$message.warning('请在列表勾选后再进行操作!')
+        return
+      }
+      this.$emit('ok', this.checkedRows)
+      this.isShow = false
+    },
+    //  递归函数
+    recursionFun (data) {
+      if (data) {
+        data.map((item, index) => {
+          item.disabled = (item.productTypeLevel == 1 || item.productTypeLevel == 3)
+          if (item.children && item.children.length > 0) {
+            this.recursionFun(item.children)
+          }
+        })
+      }
+    },
+    onCheck (checkedKeys, { checkedNodes, node }) {
+      this.checkedRows = []
+      // 强制单选:仅保留最后一次选中的节点
+      this.selectedKey = [node.eventKey]
+      if (checkedNodes && checkedNodes.length == 1) {
+        this.checkedRows.push(checkedNodes[0].data.props)
+      } else {
+        this.checkedRows.push(checkedNodes[1].data.props)
+      }
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+      } else {
+        this.getProductType()
+        // 清空已选项
+        this.selectedKey = []
+        // 回显已选数据
+        const _this = this
+        this.$nextTick(() => {
+          _this.checkedRows = _this.chooseData
+          _this.chooseData.forEach(item => {
+            _this.selectedKey.push(item.goodsSn)
+          })
+        })
+      }
+    }
+
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .chooseType-modal{
+    .chooseType-con{
+      .btn-con{
+        text-align: center;
+        margin: 30px 0 20px;
+        .button-cancel{
+          font-size: 12px;
+        }
+      }
+    }
+  }
+</style>

+ 318 - 2
src/views/setting/dailyReportSettings/categoryTargetList.vue

@@ -1,8 +1,324 @@
 <template>
+  <div>
+    <a-card size="small" :bordered="false" class="estimatedOrderList-wrap searchBoxNormal">
+      <!-- 搜索条件 -->
+      <div class="table-page-search-wrapper" ref="tableSearch">
+        <a-form-model
+          id="estimatedOrderList-form"
+          ref="ruleForm"
+          class="form-model-con"
+          layout="inline"
+          :model="queryParam"
+          :rules="rules">
+          <a-row :gutter="15">
+            <a-col :md="5" :sm="24">
+              <a-form-model-item label="年份" prop="confYear">
+                <a-select
+                  id="estimatedOrderList-confYear"
+                  style="width: 100%"
+                  placeholder="请选择年份"
+                  :value="queryParam.confYear"
+                  @change="changeYear"
+                  s>
+                  <a-select-option :id="'estimatedOrderList-'+item" v-for="item in years" :value="item" :key="item">
+                    {{ item }}
+                  </a-select-option>
+                </a-select>
+              </a-form-model-item>
+            </a-col>
+            <a-col :md="4" :sm="24">
+              <a-button
+                type="primary"
+                @click="handleSearch"
+                :disabled="disabled"
+                id="estimatedOrderList-refresh">查询</a-button>
+              <a-button
+                style="margin-left: 8px"
+                @click="resetSearchForm"
+                :disabled="disabled"
+                id="estimatedOrderList-reset">重置</a-button>
+            </a-col>
+          </a-row>
+        </a-form-model>
+      </div>
+    </a-card>
+    <a-card size="small" :bordered="false">
+      <a-spin :spinning="spinning" tip="Loading...">
+        <!-- 列表 -->
+        <s-table
+          class="sTable fixPagination"
+          ref="table"
+          size="small"
+          :rowKey="(record) => record.no"
+          rowKeyName="no"
+          :style="{ height: tableHeight+70+'px' }"
+          :columns="columns"
+          :data="loadData"
+          :scroll="{ y: tableHeight}"
+          :defaultLoadData="false"
+          :showPagination="false"
+          bordered>
+          <!-- $hasPermissions('B_tireSubsidySetting_edit')&& -->
+          <!-- 1月~12月 -->
+          <template
+            v-for="col in 12"
+            :slot="'month'+col"
+            slot-scope="text, record"
+          >
+            <div :key="col">
+              <a-input-number
+                style="width:100%;"
+                v-if="record.editable"
+                size="small"
+                :min="0"
+                :max="999999999"
+                placeholder="请输入"
+                :value="text"
+                :precision="2"
+                :id="'estimatedOrderList-input-'+record.id"
+                @change="e => handleChange(e,record, col)" />
+              <template v-else>
+                {{ text?toThousands(text):'0.00' }}
+              </template>
+            </div>
+          </template>
+          <!-- 操作 -->
+          <template slot="action" slot-scope="text, record">
+            <span v-if="record.editable">
+              <a-button
+                size="small"
+                type="link"
+                class="button-info"
+                @click="handleSave(record)"
+                :id="'estimatedOrderList-save-btn'+record.id"
+              >
+                保存
+              </a-button>
+              <a-popconfirm title="确定取消吗?" :id="'estimatedOrderList-cancel-btn'+record.id" @confirm="() => handleCancel(record)">
+                <a>取消</a>
+              </a-popconfirm>
+            </span>
+            <a-button
+              size="small"
+              type="link"
+              v-else
+              class="button-info"
+              :disabled="editingKey !== ''"
+              @click="handleEdit(record)"
+              :id="'estimatedOrderList-edit-btn'+record.id"
+            >
+              编辑
+            </a-button>
+          </template>
+        </s-table>
+      </a-spin>
+    </a-card>
+  </div>
 </template>
 
 <script>
+import { commonMixin } from '@/utils/mixin'
+import debounce from 'lodash/debounce'
+// 组件
+import { STable } from '@/components'
+// 接口
+import { reportDailyConfList, dailyReportConfSave } from '@/api/reportDailyConf'
+export default {
+  name: 'EstimatedOrderList',
+  mixins: [commonMixin],
+  components: { STable },
+  props: {
+    pageType: { //  弹框显示状态
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    const _this = this
+    _this.handleChange = debounce(_this.handleChange, 800)
+    return {
+      spinning: false,
+      disabled: false, //  查询、重置按钮是否可操作
+      tableHeight: 0, // 表格高度
+      toYears: new Date().getFullYear(), // 今年
+      editingKey: '', // 按钮是否禁用
+      //  查询条件
+      queryParam: {
+        confType: undefined, // 页面类型
+        confYear: new Date().getFullYear() // 年份
+      },
+      rules: {
+        confYear: [{ required: true, message: '请选择年份', trigger: 'change' }]
+      },
+      dataSources: null, // 表格数据
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        this.spinning = true
+        // 获取列表数据  wu分页
+        this.queryParam.confType = this.pageType
+        const params = Object.assign(parameter, this.queryParam)
+        return reportDailyConfList(params).then(res => {
+          let data
+          if (res.status == 200) {
+            data = res.data
+            // 计算表格序号
+            for (var i = 0; i < data.length; i++) {
+              data[i].no = i + 1
+              data[i].editable = false
+            }
+          }
+          this.disabled = false
+          this.spinning = false
+          this.dataSources = data
+          return data
+        })
+      }
+    }
+  },
+  computed: {
+    // 获取年份数据
+    years () {
+      const years = []
+      const lens = (this.toYears - 2023) + 1
+      for (let i = 0; i < lens; i++) {
+        years.push(this.toYears - i)
+      }
+      return years
+    },
+    columns () {
+      const _this = this
+      const arr = [
+        { title: (_this.pageType === 'CATEGORY_MONTHLY_TARGET' ? '类别' : '项目'), dataIndex: 'productTypeName', width: '12%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '1月', dataIndex: 'value01', width: '8%', align: 'right', scopedSlots: { customRender: 'month1' } },
+        { title: '2月', dataIndex: 'value02', width: '8%', align: 'right', scopedSlots: { customRender: 'month2' } },
+        { title: '3月', dataIndex: 'value03', width: '8%', align: 'right', scopedSlots: { customRender: 'month3' } },
+        { title: '4月', dataIndex: 'value04', width: '8%', align: 'right', scopedSlots: { customRender: 'month4' } },
+        { title: '5月', dataIndex: 'value05', width: '8%', align: 'right', scopedSlots: { customRender: 'month5' } },
+        { title: '6月', dataIndex: 'value06', width: '8%', align: 'right', scopedSlots: { customRender: 'month6' } },
+        { title: '7月', dataIndex: 'value07', width: '8%', align: 'right', scopedSlots: { customRender: 'month7' } },
+        { title: '8月', dataIndex: 'value08', width: '8%', align: 'right', scopedSlots: { customRender: 'month8' } },
+        { title: '9月', dataIndex: 'value09', width: '8%', align: 'right', scopedSlots: { customRender: 'month9' } },
+        { title: '10月', dataIndex: 'value10', width: '8%', align: 'right', scopedSlots: { customRender: 'month10' } },
+        { title: '11月', dataIndex: 'value11', width: '8%', align: 'right', scopedSlots: { customRender: 'month11' } },
+        { title: '12月', dataIndex: 'value12', width: '8%', align: 'right', scopedSlots: { customRender: 'month12' } },
+        { title: '合计', dataIndex: 'summation', width: '11%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: '11%', align: 'center' }
+      ]
+      if (_this.pageType === 'CATEGORY_MANAGER_MONTHLY_TARGET') {
+        arr.splice(1, 0, { title: '品类经理', dataIndex: 'userName', width: '12%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true })
+      }
+      return arr
+    }
+  },
+  methods: {
+    // 添加数据处理方法
+    processData (data, field) {
+      let count = 0
+      data.forEach((item, index) => {
+        if (index === 0 || item[field] !== data[index - 1][field]) {
+          count = 1
+          // 向后查找相同项
+          for (let i = index + 1; i < data.length; i++) {
+            if (item[field] === data[i][field]) count++
+            else break
+          }
+          item.rowSpan = count // 设置合并行数
+        } else {
+          item.rowSpan = 0 // 后续相同项设置为0(不渲染)
+        }
+      })
+      return data
+    },
+    // 查询
+    handleSearch () {
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          this.$refs.table.refresh(true)
+        } else {
+          this.$message.error('请选择年份')
+          return false
+        }
+      })
+    },
+    // 选择查询年份  change
+    changeYear (val) {
+      this.editingKey = ''
+      if (!val) {
+        this.queryParam.confYear = void 0
+      } else {
+        this.queryParam.confYear = val
+      }
+    },
+    // 编辑
+    handleEdit (row) {
+      this.editingKey = row.no
+      row.editable = true
+    },
+    // 保存
+    handleSave (row) {
+      row.confYear = this.queryParam.confYear
+      dailyReportConfSave(row).then(res => {
+        if (res.status == 200) {
+          this.$message.success(res.message)
+          row.editable = false
+          this.editingKey = ''
+          this.$refs.table.refresh(true)
+        }
+      })
+    },
+    // 取消
+    handleCancel (row) {
+      row.editable = false
+      this.editingKey = ''
+      this.$refs.table.refresh(true)
+    },
+    // input   change事件
+    handleChange (val, row, column) {
+      const _this = this
+      const newColumn = _this.padZero(column)
+      row['value' + newColumn] = val
+      row.summation = _this.calculateTotal(row)
+      // _this.dataSources[column * 1 - 1] = row
+    },
+    // 补零方法
+    padZero (num) {
+      return String(num).padStart(2, '0')
+    },
+    // 计算合计
+    calculateTotal (rowData) {
+      const keys = Array.from({ length: 12 }, (_, i) => 'value' + this.padZero(i + 1))
+      const totalNum = keys.reduce((sum, key) => sum + (Number(rowData[key]) || 0), 0)
+      console.log('sdsdsd:', totalNum)
+      return totalNum
+    },
+    //  重置
+    resetSearchForm () {
+      this.queryParam.confType = undefined
+      this.queryParam.confYear = new Date().getFullYear()
+      this.$refs.ruleForm.resetFields()
+      this.$refs.table.refresh(true)
+    },
+    // 初始化
+    pageInit () {
+      this.$nextTick(() => { // 页面渲染完成后的回调
+        this.setTableH()
+      })
+      this.resetSearchForm()
+    },
+    // 计算表格高度
+    setTableH () {
+      const tableSearchH = this.$refs.tableSearch.offsetHeight
+      this.tableHeight = window.innerHeight - tableSearchH - 280
+    }
+  },
+  mounted () {
+    this.pageInit()
+  }
+}
 </script>
-
-<style>
+<style lang="less" scoped>
+::v-deep.button-info[disabled] {
+  color: gray;
+}
 </style>

+ 91 - 34
src/views/setting/dailyReportSettings/estimatedOrderList.vue

@@ -1,10 +1,10 @@
 <template>
   <div>
-    <a-card size="small" :bordered="false" class="rebateAmountList-wrap searchBoxNormal">
+    <a-card size="small" :bordered="false" class="estimatedOrderList-wrap searchBoxNormal">
       <!-- 搜索条件 -->
       <div class="table-page-search-wrapper" ref="tableSearch">
         <a-form-model
-          id="rebateAmountList-form"
+          id="estimatedOrderList-form"
           ref="ruleForm"
           class="form-model-con"
           layout="inline"
@@ -14,13 +14,12 @@
             <a-col :md="5" :sm="24">
               <a-form-model-item label="年份" prop="confYear">
                 <a-select
-                  id="yearQueryList-time"
+                  id="estimatedOrderList-confYear"
                   style="width: 100%"
                   placeholder="请选择年份"
                   :value="queryParam.confYear"
-                  @change="changeYear"
-                  allowClear>
-                  <a-select-option v-for="item in years" :value="item" :key="item">
+                  @change="changeYear">
+                  <a-select-option :id="'estimatedOrderList-'+item" v-for="item in years" :value="item" :key="item">
                     {{ item }}
                   </a-select-option>
                 </a-select>
@@ -29,14 +28,14 @@
             <a-col :md="4" :sm="24">
               <a-button
                 type="primary"
-                @click="$refs.table.refresh(true)"
+                @click="handleSearch"
                 :disabled="disabled"
-                id="rebateAmountList-refresh">查询</a-button>
+                id="estimatedOrderList-refresh">查询</a-button>
               <a-button
                 style="margin-left: 8px"
                 @click="resetSearchForm"
                 :disabled="disabled"
-                id="rebateAmountList-reset">重置</a-button>
+                id="estimatedOrderList-reset">重置</a-button>
             </a-col>
           </a-row>
         </a-form-model>
@@ -56,8 +55,8 @@
           :data="loadData"
           :scroll="{ y: tableHeight}"
           :defaultLoadData="false"
+          :showPagination="false"
           bordered>
-          <!-- $hasPermissions('B_tireSubsidySetting_edit')&& -->
           <!-- 1月~12月 -->
           <template
             v-for="col in 12"
@@ -70,9 +69,11 @@
                 v-if="record.editable"
                 size="small"
                 :min="0"
-                :max="99999999"
+                :max="999999999"
                 placeholder="请输入"
+                :precision="0"
                 :value="text"
+                :id="'estimatedOrderList-input-'+record.id"
                 @change="e => handleChange(e,record, col)" />
               <template v-else>
                 {{ text }}
@@ -87,27 +88,22 @@
                 type="link"
                 class="button-info"
                 @click="handleSave(record)"
-                :id="'rebateAmountList-edit-btn'+record.id"
+                :id="'estimatedOrderList-save-btn'+record.id"
               >
                 保存
               </a-button>
-              <a-button
-                size="small"
-                type="link"
-                class="button-info"
-                @click="handleCancel(record)"
-                :id="'rebateAmountList-edit-btn'+record.id"
-              >
-                取消
-              </a-button>
+              <a-popconfirm title="确定取消吗?" :id="'estimatedOrderList-cancel-btn'+record.id" @confirm="() => handleCancel(record)">
+                <a>取消</a>
+              </a-popconfirm>
             </span>
             <a-button
               size="small"
               type="link"
               v-else
               class="button-info"
+              :disabled="editingKey !== ''"
               @click="handleEdit(record)"
-              :id="'rebateAmountList-edit-btn'+record.id"
+              :id="'estimatedOrderList-edit-btn'+record.id"
             >
               编辑
             </a-button>
@@ -120,12 +116,13 @@
 
 <script>
 import { commonMixin } from '@/utils/mixin'
+import debounce from 'lodash/debounce'
 // 组件
 import { STable } from '@/components'
 // 接口
 import { reportDailyConfList, dailyReportConfSave } from '@/api/reportDailyConf'
 export default {
-  name: 'RebateAmountList',
+  name: 'EstimatedOrderList',
   mixins: [commonMixin],
   components: { STable },
   props: {
@@ -136,12 +133,13 @@ export default {
   },
   data () {
     const _this = this
+    _this.handleChange = debounce(_this.handleChange, 800)
     return {
       spinning: false,
       disabled: false, //  查询、重置按钮是否可操作
       tableHeight: 0, // 表格高度
-      openRebateAddModal: false, // 新增弹窗
       toYears: new Date().getFullYear(), // 今年
+      editingKey: '', // 按钮是否禁用
       //  查询条件
       queryParam: {
         confType: undefined, // 页面类型
@@ -155,7 +153,7 @@ export default {
       loadData: parameter => {
         this.disabled = true
         this.spinning = true
-        // 获取列表数据  分页
+        // 获取列表数据  分页
         this.queryParam.confType = this.pageType
         const params = Object.assign(parameter, this.queryParam)
         return reportDailyConfList(params).then(res => {
@@ -163,15 +161,18 @@ export default {
           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].editable = false
+            for (var i = 0; i < data.length; i++) {
+              data[i].no = i + 1
+              data[i].editable = false
             }
           }
-          this.dataSources = data
           this.disabled = false
           this.spinning = false
+          if (this.pageType === 'REGIONAL_ESTIMATED_ORDER') {
+            this.dataSources = this.processData(data, 'productTypeKey')
+          } else {
+            this.dataSources = data
+          }
           return data
         })
       }
@@ -203,18 +204,57 @@ export default {
         { title: '10月', dataIndex: 'value10', width: '8%', align: 'right', scopedSlots: { customRender: 'month10' } },
         { title: '11月', dataIndex: 'value11', width: '8%', align: 'right', scopedSlots: { customRender: 'month11' } },
         { title: '12月', dataIndex: 'value12', width: '8%', align: 'right', scopedSlots: { customRender: 'month12' } },
-        { title: '合计', dataIndex: 'summation', width: '11%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
+        { title: '合计', dataIndex: 'summation', width: '11%', align: 'right', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
         { title: '操作', scopedSlots: { customRender: 'action' }, width: '11%', align: 'center' }
       ]
       if (_this.pageType === 'REGIONAL_ESTIMATED_ORDER') {
-        arr.splice(0, 0, { title: '品类', dataIndex: 'productTypeName', width: '12%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true })
+        arr.splice(0, 0, { title: '品类',
+          dataIndex: 'productTypeName',
+          width: '12%',
+          align: 'center',
+          ellipsis: true,
+          customRender: (value, row, index) => ({
+            children: value,
+            attrs: { rowSpan: row.rowSpan }
+          })
+        })
       }
       return arr
     }
   },
   methods: {
+    // 添加数据处理方法
+    processData (data, field) {
+      let count = 0
+      data.forEach((item, index) => {
+        if (index === 0 || item[field] !== data[index - 1][field]) {
+          count = 1
+          // 向后查找相同项
+          for (let i = index + 1; i < data.length; i++) {
+            if (item[field] === data[i][field]) count++
+            else break
+          }
+          item.rowSpan = count // 设置合并行数
+        } else {
+          item.rowSpan = 0 // 后续相同项设置为0(不渲染)
+        }
+      })
+      return data
+    },
+    // 查询
+    handleSearch () {
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          this.$refs.table.refresh(true)
+        } else {
+          this.$message.error('请选择年份')
+          return false
+        }
+      })
+    },
     // 选择查询年份  change
     changeYear (val) {
+      this.editingKey = ''
       if (!val) {
         this.queryParam.confYear = void 0
       } else {
@@ -223,15 +263,26 @@ export default {
     },
     // 编辑
     handleEdit (row) {
+      this.editingKey = row.no
       row.editable = true
     },
     // 保存
     handleSave (row) {
-      row.editable = false
+      row.confYear = this.queryParam.confYear
+      dailyReportConfSave(row).then(res => {
+        if (res.status == 200) {
+          this.$message.success(res.message)
+          row.editable = false
+          this.editingKey = ''
+          this.$refs.table.refresh(true)
+        }
+      })
     },
     // 取消
     handleCancel (row) {
       row.editable = false
+      this.editingKey = ''
+      this.$refs.table.refresh(true)
     },
     // input   change事件
     handleChange (val, row, column) {
@@ -239,7 +290,7 @@ export default {
       const newColumn = _this.padZero(column)
       row['value' + newColumn] = val
       row.summation = _this.calculateTotal(row)
-      _this.dataSources[column * 1 - 1] = row
+      // _this.dataSources[column * 1 - 1] = row
     },
     // 补零方法
     padZero (num) {
@@ -256,6 +307,7 @@ export default {
     resetSearchForm () {
       this.queryParam.confType = undefined
       this.queryParam.confYear = new Date().getFullYear()
+      this.$refs.ruleForm.resetFields()
       this.$refs.table.refresh(true)
     },
     // 初始化
@@ -276,3 +328,8 @@ export default {
   }
 }
 </script>
+<style lang="less" scoped>
+::v-deep.button-info[disabled] {
+  color: gray;
+}
+</style>

+ 1 - 1
src/views/setting/dailyReportSettings/index.vue

@@ -2,7 +2,7 @@
   <div>
     <a-card size="small" :bordered="false">
       <a-tabs default-active-key="1" v-model="tabVal">
-        <a-tab-pane key="1" tab="区域预估订单">
+        <a-tab-pane key="1" tab="区域预估订单" force-render>
           <estimatedOrderList pageType="REGIONAL_ESTIMATED_ORDER"></estimatedOrderList>
         </a-tab-pane>
         <a-tab-pane key="2" tab="轮胎月目标" force-render>

+ 352 - 3
src/views/setting/dailyReportSettings/partitionTargetList.vue

@@ -1,8 +1,357 @@
 <template>
+  <div>
+    <a-card size="small" :bordered="false" class="estimatedOrderList-wrap searchBoxNormal">
+      <!-- 搜索条件 -->
+      <div class="table-page-search-wrapper" ref="tableSearch">
+        <a-form-model
+          id="estimatedOrderList-form"
+          ref="ruleForm"
+          class="form-model-con"
+          layout="inline"
+          :model="queryParam"
+          :rules="rules">
+          <a-row :gutter="15">
+            <a-col :md="5" :sm="24">
+              <a-form-model-item label="年份" prop="confYear">
+                <a-select
+                  id="estimatedOrderList-confYear"
+                  style="width: 100%"
+                  placeholder="请选择年份"
+                  :value="queryParam.confYear"
+                  @change="changeYear">
+                  <a-select-option :id="'estimatedOrderList-'+item" v-for="item in years" :value="item" :key="item">
+                    {{ item }}
+                  </a-select-option>
+                </a-select>
+              </a-form-model-item>
+            </a-col>
+            <a-col :md="4" :sm="24">
+              <a-button
+                type="primary"
+                @click="handleSearch"
+                :disabled="disabled"
+                id="estimatedOrderList-refresh">查询</a-button>
+              <a-button
+                style="margin-left: 8px"
+                @click="resetSearchForm"
+                :disabled="disabled"
+                id="estimatedOrderList-reset">重置</a-button>
+            </a-col>
+          </a-row>
+        </a-form-model>
+      </div>
+    </a-card>
+    <a-card size="small" :bordered="false">
+      <a-spin :spinning="spinning" tip="Loading...">
+        <!-- 列表 -->
+        <s-table
+          class="sTable fixPagination"
+          ref="table"
+          size="small"
+          :rowKey="(record) => record.no"
+          rowKeyName="no"
+          :style="{ height: tableHeight+70+'px' }"
+          :columns="columns"
+          :data="loadData"
+          :rowClassName="(record, index) => record.subareaAreaName ==='合计' ? 'last-row':''"
+          :scroll="{ y: tableHeight}"
+          :showPagination="false"
+          :defaultLoadData="false"
+          bordered>
+          <!-- $hasPermissions('B_tireSubsidySetting_edit')&& -->
+          <!-- 1月~12月 -->
+          <template
+            v-for="col in 12"
+            :slot="'month'+col"
+            slot-scope="text, record"
+          >
+            <div :key="col">
+              <a-input-number
+                style="width:100%;"
+                v-if="record.editable"
+                size="small"
+                :min="0"
+                :max="999999999"
+                placeholder="请输入"
+                :precision="2"
+                :value="text"
+                :id="'estimatedOrderList-input-'+record.id"
+                @change="e => handleChange(e,record, col)" />
+              <template v-else>
+                {{ text?toThousands(text):'0.00' }}
+              </template>
+            </div>
+          </template>
+          <!-- 操作 -->
+          <template slot="action" slot-scope="text, record">
+            <span v-if="record.editable">
+              <a-button
+                size="small"
+                type="link"
+                class="button-info"
+                @click="handleSave(record)"
+                :id="'estimatedOrderList-save-btn'+record.id"
+              >
+                保存
+              </a-button>
+              <a-popconfirm title="确定取消吗?" :id="'estimatedOrderList-cancel-btn'+record.id" @confirm="() => handleCancel(record)">
+                <a>取消</a>
+              </a-popconfirm>
+            </span>
+            <a-button
+              size="small"
+              type="link"
+              v-else-if="!record.editable &&record.subareaAreaName!='合计' "
+              class="button-info"
+              :disabled="editingKey !== ''"
+              @click="handleEdit(record)"
+              :id="'estimatedOrderList-edit-btn'+record.id"
+            >
+              编辑
+            </a-button>
+            <span v-else>--</span>
+          </template>
+        </s-table>
+      </a-spin>
+    </a-card>
+  </div>
 </template>
 
 <script>
+import { commonMixin } from '@/utils/mixin'
+import debounce from 'lodash/debounce'
+// 组件
+import { STable } from '@/components'
+// 接口
+import { reportDailyConfList, dailyReportConfSave } from '@/api/reportDailyConf'
+export default {
+  name: 'EstimatedOrderList',
+  mixins: [commonMixin],
+  components: { STable },
+  props: {
+    pageType: { //  弹框显示状态
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    const _this = this
+    _this.handleChange = debounce(_this.handleChange, 800)
+    return {
+      spinning: false,
+      disabled: false, //  查询、重置按钮是否可操作
+      tableHeight: 0, // 表格高度
+      toYears: new Date().getFullYear(), // 今年
+      editingKey: '', // 按钮是否禁用
+      //  查询条件
+      queryParam: {
+        confType: undefined, // 页面类型
+        confYear: new Date().getFullYear() // 年份
+      },
+      rules: {
+        confYear: [{ required: true, message: '请选择年份', trigger: 'change' }]
+      },
+      dataSources: null, // 表格数据
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        this.spinning = true
+        // 获取列表数据  wu分页
+        this.queryParam.confType = this.pageType
+        const params = Object.assign(parameter, this.queryParam)
+        return reportDailyConfList(params).then(res => {
+          let data
+          if (res.status == 200) {
+            data = res.data
+            // 计算表格序号
+            for (var i = 0; i < data.length; i++) {
+              data[i].no = i + 1
+              data[i].editable = false
+            }
+          }
+          this.disabled = false
+          this.spinning = false
+          this.dataSources = data
+          return data
+        })
+      }
+    }
+  },
+  computed: {
+    // 获取年份数据
+    years () {
+      const years = []
+      const lens = (this.toYears - 2023) + 1
+      for (let i = 0; i < lens; i++) {
+        years.push(this.toYears - i)
+      }
+      return years
+    },
+    columns () {
+      const _this = this
+      const arr = [
+        { title: '分区',
+          dataIndex: 'subareaAreaName',
+          width: '12%',
+          align: 'center',
+          ellipsis: true,
+          customRender: (text, record, index) => {
+            const isLastRow = record.no == this.dataSources.length
+            return {
+              children: text,
+              attrs: {
+                colSpan: isLastRow ? 2 : 1// 合并前两列
+              }
+            }
+          } },
+        { title: '区域负责人',
+          dataIndex: 'userName',
+          width: '12%',
+          align: 'center',
+          customRender: (text, record, index) => {
+            const isLastRow = record.no == this.dataSources.length
+            return {
+              children: text || '--',
+              attrs: {
+                colSpan: isLastRow ? 0 : 1// 合并前两列
+              }
+            }
+          },
+          ellipsis: true },
+        { title: '1月', dataIndex: 'value01', width: '8%', align: 'right', scopedSlots: { customRender: 'month1' } },
+        { title: '2月', dataIndex: 'value02', width: '8%', align: 'right', scopedSlots: { customRender: 'month2' } },
+        { title: '3月', dataIndex: 'value03', width: '8%', align: 'right', scopedSlots: { customRender: 'month3' } },
+        { title: '4月', dataIndex: 'value04', width: '8%', align: 'right', scopedSlots: { customRender: 'month4' } },
+        { title: '5月', dataIndex: 'value05', width: '8%', align: 'right', scopedSlots: { customRender: 'month5' } },
+        { title: '6月', dataIndex: 'value06', width: '8%', align: 'right', scopedSlots: { customRender: 'month6' } },
+        { title: '7月', dataIndex: 'value07', width: '8%', align: 'right', scopedSlots: { customRender: 'month7' } },
+        { title: '8月', dataIndex: 'value08', width: '8%', align: 'right', scopedSlots: { customRender: 'month8' } },
+        { title: '9月', dataIndex: 'value09', width: '8%', align: 'right', scopedSlots: { customRender: 'month9' } },
+        { title: '10月', dataIndex: 'value10', width: '8%', align: 'right', scopedSlots: { customRender: 'month10' } },
+        { title: '11月', dataIndex: 'value11', width: '8%', align: 'right', scopedSlots: { customRender: 'month11' } },
+        { title: '12月', dataIndex: 'value12', width: '8%', align: 'right', scopedSlots: { customRender: 'month12' } },
+        { title: '合计', dataIndex: 'summation', width: '11%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: '11%', align: 'center' }
+      ]
+      return arr
+    }
+  },
+  methods: {
+    // 添加数据处理方法
+    processData (data, field) {
+      let count = 0
+      data.forEach((item, index) => {
+        if (index === 0 || item[field] !== data[index - 1][field]) {
+          count = 1
+          // 向后查找相同项
+          for (let i = index + 1; i < data.length; i++) {
+            if (item[field] === data[i][field]) count++
+            else break
+          }
+          item.rowSpan = count // 设置合并行数
+        } else {
+          item.rowSpan = 0 // 后续相同项设置为0(不渲染)
+        }
+      })
+      return data
+    },
+    // 查询
+    handleSearch () {
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          this.$refs.table.refresh(true)
+        } else {
+          this.$message.error('请选择年份')
+          return false
+        }
+      })
+    },
+    // 选择查询年份  change
+    changeYear (val) {
+      this.editingKey = ''
+      if (!val) {
+        this.queryParam.confYear = void 0
+      } else {
+        this.queryParam.confYear = val
+      }
+    },
+    // 编辑
+    handleEdit (row) {
+      this.editingKey = row.no
+      row.editable = true
+    },
+    // 保存
+    handleSave (row) {
+      row.confYear = this.queryParam.confYear
+      dailyReportConfSave(row).then(res => {
+        if (res.status == 200) {
+          this.$message.success(res.message)
+          row.editable = false
+          this.editingKey = ''
+          this.$refs.table.refresh(true)
+        }
+      })
+    },
+    // 取消
+    handleCancel (row) {
+      row.editable = false
+      this.editingKey = ''
+      this.$refs.table.refresh(true)
+    },
+    // input   change事件
+    handleChange (val, row, column) {
+      const _this = this
+      const newColumn = _this.padZero(column)
+      row['value' + newColumn] = val
+      row.summation = _this.calculateTotal(row)
+      // _this.dataSources[column * 1 - 1] = row
+    },
+    // 补零方法
+    padZero (num) {
+      return String(num).padStart(2, '0')
+    },
+    // 计算合计
+    calculateTotal (rowData) {
+      const keys = Array.from({ length: 12 }, (_, i) => 'value' + this.padZero(i + 1))
+      const totalNum = keys.reduce((sum, key) => sum + (Number(rowData[key]) || 0), 0)
+      console.log('sdsdsd:', totalNum)
+      return totalNum
+    },
+    //  重置
+    resetSearchForm () {
+      this.queryParam.confType = undefined
+      this.queryParam.confYear = new Date().getFullYear()
+      this.$refs.ruleForm.resetFields()
+      this.$refs.table.refresh(true)
+    },
+    // 初始化
+    pageInit () {
+      this.$nextTick(() => { // 页面渲染完成后的回调
+        this.setTableH()
+      })
+      this.resetSearchForm()
+    },
+    // 计算表格高度
+    setTableH () {
+      const tableSearchH = this.$refs.tableSearch.offsetHeight
+      this.tableHeight = window.innerHeight - tableSearchH - 280
+    }
+  },
+  mounted () {
+    this.pageInit()
+  }
+}
 </script>
-
-<style>
-</style>
+<style lang="less" scoped>
+.button-info[disabled] {
+  color: gray;
+}
+/* 最后一行样式 */
+/deep/.last-row {
+    background: #fafafa !important; /* 橙色背景 */
+    /* 固定定位 */
+    position: sticky;
+    bottom: 0;
+    z-index: 2;
+  }
+</style>